4pragma ComponentBehavior: Bound
7import QtQuick.Templates as T
10import "../internal/MotionAnimation.js" as MotionAnimation
54 default property alias destinations: rail.contentData
61 property bool expanded:
false
69 property bool hideOnCollapse:
false
72 property alias currentIndex: rail.currentIndex
75 property alias arrangement: rail.arrangement
78 property alias header: rail.header
81 property color containerColor: control.MD.Style.surfaceContainerColor
84 property color scrimColor: control.MD.Style.scrimColor
87 readonly
property alias count: rail.count
90 property Item _restoreFocusItem: null
93 property real _dragOffset: 0
96 property real _dragStartOffset: 0
102 function itemAt(index) {
103 return rail.itemAt(index);
108 control.expanded =
true;
112 function collapse() {
113 control.expanded =
false;
118 control.expanded = !control.expanded;
127 function _focusRail() {
128 let index = control.currentIndex;
130 const selectedItem = rail.itemAt(index);
131 if (selectedItem && selectedItem.enabled) {
132 selectedItem.forceActiveFocus(Qt.PopupFocusReason);
136 for (index = 0; index < rail.count; ++index) {
137 const item = rail.itemAt(index);
138 if (item && item.enabled) {
139 item.forceActiveFocus(Qt.PopupFocusReason);
143 rail.forceActiveFocus(Qt.PopupFocusReason);
147 function _focusDestination() {
148 const selected = rail.itemAt(rail._tabStopIndex);
150 selected.forceActiveFocus(Qt.TabFocusReason);
161 function _moveModalTab(backward) {
162 const headerItem = rail._headerFocusItem();
163 const headerFocusable = headerItem !== null;
164 if (headerFocusable && !headerItem.activeFocus) {
165 headerItem.forceActiveFocus(backward ? Qt.BacktabFocusReason : Qt.TabFocusReason);
168 if (!control._focusDestination() && headerFocusable)
169 headerItem.forceActiveFocus(backward ? Qt.BacktabFocusReason : Qt.TabFocusReason);
172 implicitWidth: rail.implicitWidth
173 implicitHeight: rail.implicitHeight
175 focusPolicy: Qt.StrongFocus
176 LayoutMirroring.childrenInherit:
true
180 Accessible.ignored:
true
185 _restoreFocusItem = Window.window ? Window.window.activeFocusItem : null;
186 Qt.callLater(control._focusRail);
191 if (_restoreFocusItem)
192 _restoreFocusItem.forceActiveFocus(Qt.PopupFocusReason);
193 _restoreFocusItem = null;
199 Keys.onEscapePressed:
event => {
200 if (control.expanded)
203 event.accepted =
false;
205 Keys.onTabPressed:
event => {
206 if (control.expanded) {
207 control._moveModalTab(
false);
208 event.accepted =
true;
210 event.accepted =
false;
213 Keys.onBacktabPressed:
event => {
214 if (control.expanded) {
215 control._moveModalTab(
true);
216 event.accepted =
true;
218 event.accepted =
false;
227 objectName:
"modalNavigationRailScrim"
231 color: control.scrimColor
232 opacity: control.expanded ? MD.Tokens.navigationRail.modalScrimOpacity : 0
235 Behavior on opacity {
237 duration: MotionAnimation.expressiveFastEffectsDuration
238 easing.type: Easing.BezierSpline
239 easing.bezierCurve: MotionAnimation.expressiveFastEffectsCurve
244 onTapped: control.collapse()
250 objectName:
"modalNavigationRailSurface"
254 const shownX = control.mirrored ? control.width - rail.width : 0;
255 const hiddenX = control.mirrored ? control.width : -rail.width;
256 return (control.expanded || !control.hideOnCollapse ? shownX : hiddenX)
257 + control._dragOffset;
260 width: Math.min(rail.implicitWidth, control.width)
261 height: control.height
262 expanded: control.hideOnCollapse || control.expanded
263 containerColor: control.containerColor
268 Accessible.name: control.Accessible.name
269 LayoutMirroring.enabled: control.mirrored
270 LayoutMirroring.childrenInherit:
true
273 enabled: !dragHandler.active && !dragSettleAnimation.running
276 duration: MotionAnimation.expressiveFastSpatialDuration
277 easing.type: Easing.BezierSpline
278 easing.bezierCurve: MotionAnimation.expressiveFastSpatialCurve
284 objectName:
"modalNavigationRailDragHandler"
286 enabled: control.expanded
289 acceptedDevices: PointerDevice.TouchScreen | PointerDevice.TouchPad | PointerDevice.Mouse
293 dragSettleAnimation.stop();
294 control._dragStartOffset = control._dragOffset;
296 const dismissalDistance = control.mirrored
297 ? control._dragOffset
298 : -control._dragOffset;
299 if (dismissalDistance >= rail.width * 0.5) {
300 control._dragOffset = 0;
303 dragSettleAnimation.restart();
308 onTranslationChanged: {
311 const logicalDistance = control.mirrored ? translation.x : -translation.x;
312 const clampedDistance = Math.max(0, Math.min(rail.width, logicalDistance));
313 control._dragOffset = control._dragStartOffset
314 + (control.mirrored ? clampedDistance : -clampedDistance);
321 id: dragSettleAnimation
323 property:
"_dragOffset"
325 duration: MotionAnimation.expressiveFastSpatialDuration
326 easing.type: Easing.BezierSpline
327 easing.bezierCurve: MotionAnimation.expressiveFastSpatialCurve
Material Design 3 Expressive navigation rail tokens.