@astryxdesign/core 0.7.3-canary.b74cf21 → 0.7.3-canary.ca48bb7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheet.js +8 -4
- package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetSwitcher.js +7 -0
- package/dist/Calendar/Calendar.js +3 -2
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +19 -24
- package/dist/ClickableCard/ClickableCard.d.ts +2 -2
- package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
- package/dist/ClickableCard/ClickableCard.js +11 -9
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +11 -1
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +23 -5
- package/dist/DateInput/DateInput.d.ts +4 -4
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +27 -20
- package/dist/DateInput/NativeDateField.d.ts.map +1 -1
- package/dist/DateInput/NativeDateField.js +14 -8
- package/dist/DateInput/TouchDateField.d.ts.map +1 -1
- package/dist/DateInput/TouchDateField.js +14 -10
- package/dist/DateRangeInput/DateRangeInput.d.ts +5 -5
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +27 -18
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +9 -4
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +52 -10
- package/dist/DropdownMenu/DropdownMenuContext.d.ts +34 -1
- package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuContext.js +15 -0
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +21 -2
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +375 -42
- package/dist/DropdownMenu/menuRegionStops.d.ts +2 -2
- package/dist/DropdownMenu/menuRegionStops.js +2 -2
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +14 -12
- package/dist/Link/Link.d.ts +2 -3
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +11 -19
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +48 -15
- package/dist/MultiSelector/MultiSelector.d.ts +4 -4
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.disabledFocus.a11y.chromium.spec.d.ts +2 -0
- package/dist/MultiSelector/MultiSelector.disabledFocus.a11y.chromium.spec.d.ts.map +1 -0
- package/dist/MultiSelector/MultiSelector.disabledFocus.a11y.chromium.spec.js +48 -0
- package/dist/MultiSelector/MultiSelector.js +25 -18
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +5 -2
- package/dist/Popover/Popover.d.ts.map +1 -1
- package/dist/Popover/Popover.js +8 -4
- package/dist/Selector/Selector.d.ts +4 -4
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +23 -14
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +7 -14
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +25 -17
- package/dist/Switch/switch.markers.stylex.d.ts +2 -0
- package/dist/Switch/switch.markers.stylex.d.ts.map +1 -1
- package/dist/Switch/switch.markers.stylex.js +6 -0
- package/dist/TimeInput/TimeInput.d.ts +2 -1
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +41 -8
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +8 -3
- package/dist/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/Tooltip/Tooltip.js +36 -14
- package/dist/TopNav/TopNav.d.ts.map +1 -1
- package/dist/TopNav/TopNav.js +2 -2
- package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
- package/dist/TopNav/TopNavHeading.js +1 -0
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +8 -3
- package/dist/astryx.css +7 -2
- package/dist/hooks/useGridFocus.d.ts.map +1 -1
- package/dist/hooks/useGridFocus.js +10 -1
- package/dist/hooks/useMenuPress.d.ts +11 -1
- package/dist/hooks/useMenuPress.d.ts.map +1 -1
- package/dist/hooks/useMenuPress.js +43 -5
- package/dist/utils/disabledInteraction.d.ts +21 -0
- package/dist/utils/disabledInteraction.d.ts.map +1 -0
- package/dist/utils/disabledInteraction.js +33 -0
- package/dist/utils/timeParser.d.ts +4 -0
- package/dist/utils/timeParser.d.ts.map +1 -1
- package/dist/utils/timeParser.js +9 -2
- package/package.json +3 -3
- package/src/Banner/Banner.spec.md +37 -32
- package/src/BottomSheet/BottomSheet.spec.md +26 -53
- package/src/BottomSheet/BottomSheet.test.tsx +29 -0
- package/src/BottomSheet/BottomSheet.tsx +8 -4
- package/src/BottomSheet/BottomSheetSwitcher.spec.md +45 -48
- package/src/BottomSheet/BottomSheetSwitcher.test.tsx +26 -0
- package/src/BottomSheet/BottomSheetSwitcher.tsx +6 -0
- package/src/Calendar/Calendar.test.tsx +68 -24
- package/src/Calendar/Calendar.tsx +2 -1
- package/src/CheckboxInput/CheckboxInput.test.tsx +44 -5
- package/src/CheckboxInput/CheckboxInput.tsx +16 -26
- package/src/CheckboxInput/__tests__/Checkbox.a11y.states.ts +3 -3
- package/src/CheckboxList/CheckboxList.test.tsx +9 -6
- package/src/ClickableCard/ClickableCard.doc.mjs +2 -2
- package/src/ClickableCard/ClickableCard.test.tsx +5 -4
- package/src/ClickableCard/ClickableCard.tsx +9 -9
- package/src/CodeBlock/CodeBlock.highlightStyles.test.tsx +87 -0
- package/src/CodeBlock/CodeBlock.tsx +11 -1
- package/src/ComplexSelector/ComplexSelector.focusableDisabled.test.tsx +76 -0
- package/src/ComplexSelector/ComplexSelector.tsx +21 -4
- package/src/ContextMenu/ContextMenu.test.tsx +41 -0
- package/src/DateInput/DateInput.doc.mjs +9 -8
- package/src/DateInput/DateInput.test.tsx +88 -13
- package/src/DateInput/DateInput.tsx +49 -21
- package/src/DateInput/DateInputTouch.test.tsx +22 -1
- package/src/DateInput/NativeDateField.test.tsx +29 -3
- package/src/DateInput/NativeDateField.tsx +20 -7
- package/src/DateInput/TouchDateField.tsx +24 -9
- package/src/DateRangeInput/DateRangeInput.doc.mjs +6 -5
- package/src/DateRangeInput/DateRangeInput.test.tsx +82 -16
- package/src/DateRangeInput/DateRangeInput.tsx +40 -20
- package/src/Dialog/Dialog.test.tsx +39 -0
- package/src/Dialog/Dialog.tsx +9 -4
- package/src/DropdownMenu/DropdownMenu.spec.md +33 -2
- package/src/DropdownMenu/DropdownMenu.tsx +79 -8
- package/src/DropdownMenu/DropdownMenuContext.public.test.ts +22 -0
- package/src/DropdownMenu/DropdownMenuContext.tsx +39 -1
- package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +16 -1
- package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +623 -1
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +556 -99
- package/src/DropdownMenu/__tests__/SubMenuHeaderFooter.a11y.chromium.spec.ts +267 -0
- package/src/DropdownMenu/menuRegionStops.ts +2 -2
- package/src/DropdownMenu/modules/useMenuPress.spec.md +9 -0
- package/src/FieldStatus/FieldStatus.spec.md +3 -2
- package/src/FileInput/FileInput.test.tsx +30 -7
- package/src/FileInput/FileInput.tsx +21 -11
- package/src/Link/Link.test.tsx +21 -7
- package/src/Link/Link.tsx +16 -24
- package/src/Link/__tests__/Link.a11y.states.ts +1 -1
- package/src/Markdown/Markdown.rerender.test.tsx +143 -0
- package/src/Markdown/Markdown.tsx +89 -35
- package/src/MultiSelector/MultiSelector.disabledFocus.a11y.chromium.spec.ts +71 -0
- package/src/MultiSelector/MultiSelector.doc.mjs +5 -5
- package/src/MultiSelector/MultiSelector.focusableDisabled.test.tsx +121 -0
- package/src/MultiSelector/MultiSelector.test.tsx +49 -7
- package/src/MultiSelector/MultiSelector.tsx +53 -29
- package/src/Pagination/Pagination.test.tsx +5 -1
- package/src/Pagination/Pagination.tsx +3 -1
- package/src/Popover/Popover.test.tsx +15 -0
- package/src/Popover/Popover.tsx +19 -8
- package/src/PowerSearch/PowerSearchFilterEditor.test.tsx +3 -2
- package/src/PowerSearch/PowerSearchToken.test.tsx +7 -5
- package/src/Selector/Selector.doc.mjs +4 -4
- package/src/Selector/Selector.focusableDisabled.test.tsx +127 -0
- package/src/Selector/Selector.test.tsx +48 -6
- package/src/Selector/Selector.tsx +51 -21
- package/src/SideNav/SideNav.test.tsx +35 -0
- package/src/Slider/Slider.test.tsx +3 -3
- package/src/Slider/Slider.tsx +8 -15
- package/src/Switch/Switch.test.tsx +85 -8
- package/src/Switch/Switch.tsx +26 -16
- package/src/Switch/__tests__/Switch.a11y.states.ts +2 -2
- package/src/Switch/switch.markers.stylex.ts +4 -0
- package/src/Table/plugins/selection/useTableSelection.test.tsx +5 -3
- package/src/TimeInput/TimeInput.doc.mjs +5 -3
- package/src/TimeInput/TimeInput.test.tsx +20 -0
- package/src/TimeInput/TimeInput.tsx +2 -1
- package/src/Timestamp/Timestamp.doc.mjs +1 -1
- package/src/Timestamp/Timestamp.test.tsx +168 -0
- package/src/Timestamp/Timestamp.tsx +62 -11
- package/src/Token/Token.test.tsx +26 -4
- package/src/Token/Token.tsx +6 -2
- package/src/Tooltip/Tooltip.test.tsx +51 -6
- package/src/Tooltip/Tooltip.tsx +41 -18
- package/src/Tooltip/__tests__/Tooltip.a11y.chromium.spec.ts +129 -0
- package/src/Tooltip/__tests__/Tooltip.a11y.renders.tsx +86 -0
- package/src/Tooltip/__tests__/Tooltip.a11y.states.ts +132 -0
- package/src/Tooltip/__tests__/Tooltip.a11y.test.tsx +126 -0
- package/src/TopNav/TopNav.tsx +11 -1
- package/src/TopNav/TopNavHeading.tsx +1 -0
- package/src/TopNav/__tests__/TopNavMobileLongHeading.a11y.chromium.spec.ts +74 -0
- package/src/TreeList/TreeList.test.tsx +28 -0
- package/src/TreeList/TreeListItem.tsx +6 -2
- package/src/__tests__/DisabledTriggerFocus.a11y.chromium.spec.ts +86 -0
- package/src/hooks/useGridFocus.ts +16 -1
- package/src/hooks/useMenuPress.ts +45 -7
- package/src/utils/disabledInteraction.ts +40 -0
- package/src/utils/timeParser.test.ts +11 -0
- package/src/utils/timeParser.ts +9 -2
package/dist/astryx.css
CHANGED
|
@@ -644,8 +644,10 @@
|
|
|
644
644
|
.xk2sxw7:focus-within:not(#\#):not(#\#){border-color:var(--color-error)}
|
|
645
645
|
.xyq33ac:focus-within:not(#\#):not(#\#){border-color:var(--color-success)}
|
|
646
646
|
.xa1yw2k:focus-within:not(#\#):not(#\#){border-color:var(--color-warning)}
|
|
647
|
-
.
|
|
647
|
+
.x1bax923.x1bax923:where(.xgy66g5:has(:focus-visible) *):not(#\#):not(#\#){outline:var(--focus-outline-width) var(--focus-outline-style) var(--focus-outline-color)}
|
|
648
648
|
.x1dordxg:focus-within:not(#\#):not(#\#){overflow:visible}
|
|
649
|
+
.x16it14f:has(> [aria-disabled="true"]:focus-visible):not(#\#):not(#\#){border-color:var(--color-accent)}
|
|
650
|
+
.x2uiyk:has(input:focus):not(#\#):not(#\#){border-color:var(--color-accent)}
|
|
649
651
|
.xb0m1lw:has(> div > .astryx-layout-content):not(#\#):not(#\#){margin-inline:0}
|
|
650
652
|
.x16s19ga:has(:focus-visible):not(#\#):not(#\#){outline:var(--focus-outline-width) var(--focus-outline-style) var(--focus-outline-color)}
|
|
651
653
|
.xf0xpto:placeholder-shown:not(#\#):not(#\#){flex:0 0 auto}
|
|
@@ -1505,8 +1507,8 @@
|
|
|
1505
1507
|
.x1nw7mhf:focus-visible:not(#\#):not(#\#):not(#\#){outline-offset:calc(-1 * var(--focus-outline-width))}
|
|
1506
1508
|
.x1l5jwag:focus-visible:not(#\#):not(#\#):not(#\#){outline-offset:calc(0px - var(--focus-outline-width))}
|
|
1507
1509
|
.x13aywxo:focus-visible:not(#\#):not(#\#):not(#\#){outline-offset:var(--button-focus-offset)}
|
|
1510
|
+
.x1s7sthk.x1s7sthk:where(.xgy66g5:has(:focus-visible) *):not(#\#):not(#\#):not(#\#){outline-offset:var(--focus-outline-offset)}
|
|
1508
1511
|
.x1vwwbsn:focus-visible:not(#\#):not(#\#):not(#\#){outline-offset:var(--focus-outline-offset)}
|
|
1509
|
-
.xwz5zln.xwz5zln:where(.x1iwu4tg:has(:focus-visible) *):not(#\#):not(#\#):not(#\#){outline-offset:var(--focus-outline-offset)}
|
|
1510
1512
|
.x1jhp3zv:focus-visible:not(#\#):not(#\#):not(#\#){outline-style:var(--focus-outline-style)}
|
|
1511
1513
|
.x1vidyx5:focus-visible:not(#\#):not(#\#):not(#\#){outline-width:var(--focus-outline-width)}
|
|
1512
1514
|
.x1n6uwha:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){padding-inline-end:max(var(--spacing-4),env(safe-area-inset-left,0px))}
|
|
@@ -1535,8 +1537,11 @@
|
|
|
1535
1537
|
.x1qf1n5z.x1qf1n5z:where(.astryx-input-group > *):focus-visible:not(#\#):not(#\#):not(#\#){z-index:2}
|
|
1536
1538
|
.x1s2lk0z.x1s2lk0z:where(:not(:disabled,[aria-disabled="true"]))[data-astryx-press="fading"]:not(#\#):not(#\#):not(#\#){--_press-overlay:var(--_press-paint)}
|
|
1537
1539
|
.x1sad4of.x1sad4of:where(:not(:disabled,[aria-disabled="true"]))[data-astryx-press="on"]:not(#\#):not(#\#):not(#\#){--_press-overlay:var(--_press-paint)}
|
|
1540
|
+
.xwmge8v:has(> [aria-disabled="true"]:focus-visible):not(#\#):not(#\#):not(#\#){box-shadow:inset 0 0 0 2px var(--color-accent-muted)}
|
|
1541
|
+
.xxsos93:has(input:focus):not(#\#):not(#\#):not(#\#){box-shadow:inset 0 0 0 2px var(--color-accent-muted)}
|
|
1538
1542
|
.x1btxeh5:has(input:focus-visible):not(#\#):not(#\#):not(#\#){box-shadow:inset 0 0 0 2px var(--color-accent)}
|
|
1539
1543
|
.xsw3flo:has(> div > .astryx-layout-content):not(#\#):not(#\#):not(#\#){container-type:inline-size}
|
|
1544
|
+
.x1ab7gxt:has(~ * > [data-astryx-submenu-regions="view"]:not([hidden])):not(#\#):not(#\#):not(#\#){display:none}
|
|
1540
1545
|
.x92e2el:has(> [data-astryx-edge-comp]:last-child):not(#\#):not(#\#):not(#\#){margin-inline-end:var(--x-4drmnv)}
|
|
1541
1546
|
.x1kftj4p:has(> [data-astryx-edge-comp]:first-child):not(#\#):not(#\#):not(#\#){margin-inline-start:var(--x-126w13d)}
|
|
1542
1547
|
.x1uy843r:has(:focus-visible):not(#\#):not(#\#):not(#\#){outline-color:var(--focus-outline-color)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useGridFocus.d.ts","sourceRoot":"","sources":["../../src/hooks/useGridFocus.ts"],"names":[],"mappings":"AAsBA;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;;;;;;;;;;OAYG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC;IAEjD;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,WAAW,GAAG,IAAI,CAAC;IAE3D;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAE5D;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAE3D;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IAEtB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IAExB;;;;;;;;;;;;;;;;;;OAkBG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW;IACrE;;OAEG;IACH,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAEnC;;OAEG;IACH,aAAa,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC;IAEhD;;;;OAIG;IACH,WAAW,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IAE3C;;OAEG;IACH,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAEnC;;OAEG;IACH,UAAU,EAAE,MAAM,IAAI,CAAC;IAEvB;;OAEG;IACH,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAC9D,OAAO,EAAE,mBAAmB,GAC3B,kBAAkB,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"useGridFocus.d.ts","sourceRoot":"","sources":["../../src/hooks/useGridFocus.ts"],"names":[],"mappings":"AAsBA;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;;;;;;;;;;OAYG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC;IAEjD;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,WAAW,GAAG,IAAI,CAAC;IAE3D;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAE5D;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAE3D;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IAEtB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IAExB;;;;;;;;;;;;;;;;;;OAkBG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW;IACrE;;OAEG;IACH,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAEnC;;OAEG;IACH,aAAa,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC;IAEhD;;;;OAIG;IACH,WAAW,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IAE3C;;OAEG;IACH,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAEnC;;OAEG;IACH,UAAU,EAAE,MAAM,IAAI,CAAC;IAEvB;;OAEG;IACH,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAC9D,OAAO,EAAE,mBAAmB,GAC3B,kBAAkB,CAAC,CAAC,CAAC,CAsZvB"}
|
|
@@ -163,7 +163,16 @@ export function useGridFocus(options) {
|
|
|
163
163
|
for (const el of targets) {
|
|
164
164
|
setTabIndex(el, el === tabbable ? 0 : -1);
|
|
165
165
|
}
|
|
166
|
-
|
|
166
|
+
// A cell that stopped being focusable (an aria-disabled day, for example,
|
|
167
|
+
// which stays reachable by focus) can still hold the stop from earlier
|
|
168
|
+
// navigation; it never stays tabbable, so the grid keeps one Tab stop.
|
|
169
|
+
for (const cell of getCells()) {
|
|
170
|
+
const el = cellFocusable(cell) ? null : resolveFocusTarget(cell);
|
|
171
|
+
if (el != null) {
|
|
172
|
+
setTabIndex(el, -1);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}, [getFocusTargets, getCells, cellFocusable, resolveFocusTarget, setTabIndex]);
|
|
167
176
|
|
|
168
177
|
// Keep the tab stop valid across renders (cells added/removed, focusability
|
|
169
178
|
// toggled). Runs after every commit but only when roving tabindex is on.
|
|
@@ -32,7 +32,9 @@
|
|
|
32
32
|
*
|
|
33
33
|
* The menu root is marked `data-astryx-menu-press` so a nested flyout (a DOM
|
|
34
34
|
* descendant of its parent menu) can tell which level owns a press, and so a
|
|
35
|
-
* surface can be recognised as carrying this model.
|
|
35
|
+
* surface can be recognised as carrying this model. A menu the root renders
|
|
36
|
+
* beside itself names the root with `data-astryx-menu-press-surface` and counts
|
|
37
|
+
* as nested in it.
|
|
36
38
|
*
|
|
37
39
|
* SYNC: When modified, update:
|
|
38
40
|
* - /packages/core/src/hooks/index.ts
|
|
@@ -44,6 +46,14 @@ import { type RefObject } from 'react';
|
|
|
44
46
|
import { type MenuPressPointerType } from './menuPressGesture';
|
|
45
47
|
/** Marks a menu root that carries this press model. */
|
|
46
48
|
export declare const MENU_PRESS_MARKER = "data-astryx-menu-press";
|
|
49
|
+
/**
|
|
50
|
+
* Carried by a menu root that another root renders beside itself rather than
|
|
51
|
+
* inside it, naming that root's `id`: the menu of a sub-menu with a header or
|
|
52
|
+
* footer, in a dialog beside the root's menu, is nested in that root for the
|
|
53
|
+
* press model, as a flyout inside the root's DOM is. Nothing else beside the
|
|
54
|
+
* root carries it, so a picker placed in a header or footer stays its own root.
|
|
55
|
+
*/
|
|
56
|
+
export declare const MENU_PRESS_SURFACE_ATTR = "data-astryx-menu-press-surface";
|
|
47
57
|
/** How long after a tracked release the browser's click is still swallowed. */
|
|
48
58
|
export declare const MENU_PRESS_STRAY_CLICK_MS = 400;
|
|
49
59
|
/** How long a finger must rest on the trigger before the menu opens under it. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMenuPress.d.ts","sourceRoot":"","sources":["../../src/hooks/useMenuPress.ts"],"names":[],"mappings":"AAIA
|
|
1
|
+
{"version":3,"file":"useMenuPress.d.ts","sourceRoot":"","sources":["../../src/hooks/useMenuPress.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,EAA0C,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAE9E,OAAO,EAML,KAAK,oBAAoB,EAC1B,MAAM,oBAAoB,CAAC;AAG5B,uDAAuD;AACvD,eAAO,MAAM,iBAAiB,2BAA2B,CAAC;AAE1D;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,mCAAmC,CAAC;AAExE,+EAA+E;AAC/E,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAC7C,iFAAiF;AACjF,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAC5C,oFAAoF;AACpF,eAAO,MAAM,6BAA6B,KAAK,CAAC;AAchD;;;;;GAKG;AACH,wBAAgB,qBAAqB,IAAI,OAAO,CAE/C;AA6DD,0DAA0D;AAC1D,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAMD,MAAM,WAAW,mBAAmB;IAClC,+EAA+E;IAC/E,OAAO,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACvC,uEAAuE;IACvE,UAAU,CAAC,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC3C;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,oBAAoB,KAAK,OAAO,CAAC;IAChE;;;;;OAKG;IACH,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;IAC/D,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,WAAW,GAAG,IAAI,CAAC;IACvC;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,CAAC;IACnD,mBAAmB;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,+CAA+C;IAC/C,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,SAAS,EAAE;QACT,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;QAChE,CAAC,iBAAiB,CAAC,EAAE,EAAE,CAAC;KACzB,CAAC;IACF,yEAAyE;IACzE,YAAY,EAAE;QACZ,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;QAChE,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;KAC/D,CAAC;IACF;;;;OAIG;IACH,uBAAuB,EAAE,MAAM,OAAO,CAAC;IACvC,uEAAuE;IACvE,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAkED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,kBAAkB,CA2iB7E"}
|
|
@@ -36,7 +36,9 @@
|
|
|
36
36
|
*
|
|
37
37
|
* The menu root is marked `data-astryx-menu-press` so a nested flyout (a DOM
|
|
38
38
|
* descendant of its parent menu) can tell which level owns a press, and so a
|
|
39
|
-
* surface can be recognised as carrying this model.
|
|
39
|
+
* surface can be recognised as carrying this model. A menu the root renders
|
|
40
|
+
* beside itself names the root with `data-astryx-menu-press-surface` and counts
|
|
41
|
+
* as nested in it.
|
|
40
42
|
*
|
|
41
43
|
* SYNC: When modified, update:
|
|
42
44
|
* - /packages/core/src/hooks/index.ts
|
|
@@ -52,6 +54,14 @@ import { useLongPress } from "./useLongPress.js";
|
|
|
52
54
|
/** Marks a menu root that carries this press model. */
|
|
53
55
|
export const MENU_PRESS_MARKER = 'data-astryx-menu-press';
|
|
54
56
|
const MENU_PRESS_ROOT_SELECTOR = `[${MENU_PRESS_MARKER}]`;
|
|
57
|
+
/**
|
|
58
|
+
* Carried by a menu root that another root renders beside itself rather than
|
|
59
|
+
* inside it, naming that root's `id`: the menu of a sub-menu with a header or
|
|
60
|
+
* footer, in a dialog beside the root's menu, is nested in that root for the
|
|
61
|
+
* press model, as a flyout inside the root's DOM is. Nothing else beside the
|
|
62
|
+
* root carries it, so a picker placed in a header or footer stays its own root.
|
|
63
|
+
*/
|
|
64
|
+
export const MENU_PRESS_SURFACE_ATTR = 'data-astryx-menu-press-surface';
|
|
55
65
|
|
|
56
66
|
/** How long after a tracked release the browser's click is still swallowed. */
|
|
57
67
|
export const MENU_PRESS_STRAY_CLICK_MS = 400;
|
|
@@ -153,13 +163,41 @@ function isRowFocusable(row) {
|
|
|
153
163
|
function getOutermostRoot(menu) {
|
|
154
164
|
let root = menu;
|
|
155
165
|
for (;;) {
|
|
156
|
-
const parent = root.parentElement?.closest(MENU_PRESS_ROOT_SELECTOR);
|
|
157
|
-
if (parent == null) {
|
|
166
|
+
const parent = root.parentElement?.closest(MENU_PRESS_ROOT_SELECTOR) ?? getSurfaceOwner(root);
|
|
167
|
+
if (parent == null || parent === root) {
|
|
158
168
|
return root;
|
|
159
169
|
}
|
|
160
170
|
root = parent;
|
|
161
171
|
}
|
|
162
172
|
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* The menu root that renders `menu` beside itself, if any (see
|
|
176
|
+
* `MENU_PRESS_SURFACE_ATTR`). Read off the menu itself, never an ancestor, so
|
|
177
|
+
* a root placed in a region of that surface is not adopted.
|
|
178
|
+
*/
|
|
179
|
+
function getSurfaceOwner(menu) {
|
|
180
|
+
const ownerId = menu.getAttribute(MENU_PRESS_SURFACE_ATTR);
|
|
181
|
+
if (!ownerId) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
const owner = menu.ownerDocument.getElementById(ownerId);
|
|
185
|
+
return owner?.matches(MENU_PRESS_ROOT_SELECTOR) === true ? owner : null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Whether `element` is inside the menu tree whose outermost root is `root`:
|
|
190
|
+
* inside the root itself, or inside a menu nested in it through a surface
|
|
191
|
+
* the root renders beside itself. Anything else in such a surface (a header
|
|
192
|
+
* field, say) is outside the menu, as the root's own regions are.
|
|
193
|
+
*/
|
|
194
|
+
function isInMenuTree(element, root) {
|
|
195
|
+
if (root.contains(element)) {
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
const owner = element.closest(MENU_PRESS_ROOT_SELECTOR);
|
|
199
|
+
return owner != null && getOutermostRoot(owner) === root;
|
|
200
|
+
}
|
|
163
201
|
// =============================================================================
|
|
164
202
|
// Hook
|
|
165
203
|
// =============================================================================
|
|
@@ -223,13 +261,13 @@ export function useMenuPress(options) {
|
|
|
223
261
|
element = event.target instanceof Element ? event.target : null;
|
|
224
262
|
}
|
|
225
263
|
const root = menu == null ? null : getOutermostRoot(menu);
|
|
226
|
-
const isInMenu = root != null && element != null &&
|
|
264
|
+
const isInMenu = root != null && element != null && isInMenuTree(element, root);
|
|
227
265
|
const trigger = triggerRef?.current ?? null;
|
|
228
266
|
const isOnTrigger = trigger != null && element != null && trigger.contains(element);
|
|
229
267
|
let row = null;
|
|
230
268
|
if (isInMenu && element != null) {
|
|
231
269
|
row = element.closest(itemSelector);
|
|
232
|
-
if (row != null && !
|
|
270
|
+
if (row != null && !isInMenuTree(row, root)) {
|
|
233
271
|
row = null;
|
|
234
272
|
}
|
|
235
273
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file disabledInteraction.ts
|
|
3
|
+
* @input An optional caller keydown handler
|
|
4
|
+
* @output Event props that keep a focusable, aria-disabled control inert
|
|
5
|
+
* @position Shared by controls that replace native `disabled` with
|
|
6
|
+
* `aria-disabled` under spec:AST-085 (FR1, FR2)
|
|
7
|
+
*/
|
|
8
|
+
import type { KeyboardEvent, KeyboardEventHandler, MouseEvent } from 'react';
|
|
9
|
+
/**
|
|
10
|
+
* Event props for a disabled control that stays focusable. Native `disabled`
|
|
11
|
+
* dispatched no click at all; without it, Enter and Space still synthesize a
|
|
12
|
+
* click that native listeners on the element (a wrapping Popover's trigger)
|
|
13
|
+
* receive. Cancelling those keys keeps the click from existing, and the click
|
|
14
|
+
* handler cancels pointer clicks and keeps them from reaching ancestors. Other
|
|
15
|
+
* keys still reach the caller's handler.
|
|
16
|
+
*/
|
|
17
|
+
export declare function disabledInteractionProps<T extends HTMLElement>(onKeyDown?: KeyboardEventHandler<T>): {
|
|
18
|
+
onClick: (event: MouseEvent<T>) => void;
|
|
19
|
+
onKeyDown: (event: KeyboardEvent<T>) => void;
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=disabledInteraction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disabledInteraction.d.ts","sourceRoot":"","sources":["../../src/utils/disabledInteraction.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAC,aAAa,EAAE,oBAAoB,EAAE,UAAU,EAAC,MAAM,OAAO,CAAC;AAE3E;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,WAAW,EAC5D,SAAS,CAAC,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAClC;IACD,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IACxC,SAAS,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;CAC9C,CAcA"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file disabledInteraction.ts
|
|
5
|
+
* @input An optional caller keydown handler
|
|
6
|
+
* @output Event props that keep a focusable, aria-disabled control inert
|
|
7
|
+
* @position Shared by controls that replace native `disabled` with
|
|
8
|
+
* `aria-disabled` under spec:AST-085 (FR1, FR2)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Event props for a disabled control that stays focusable. Native `disabled`
|
|
13
|
+
* dispatched no click at all; without it, Enter and Space still synthesize a
|
|
14
|
+
* click that native listeners on the element (a wrapping Popover's trigger)
|
|
15
|
+
* receive. Cancelling those keys keeps the click from existing, and the click
|
|
16
|
+
* handler cancels pointer clicks and keeps them from reaching ancestors. Other
|
|
17
|
+
* keys still reach the caller's handler.
|
|
18
|
+
*/
|
|
19
|
+
export function disabledInteractionProps(onKeyDown) {
|
|
20
|
+
return {
|
|
21
|
+
onClick: event => {
|
|
22
|
+
event.preventDefault();
|
|
23
|
+
event.stopPropagation();
|
|
24
|
+
},
|
|
25
|
+
onKeyDown: event => {
|
|
26
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
27
|
+
event.preventDefault();
|
|
28
|
+
} else {
|
|
29
|
+
onKeyDown?.(event);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -70,6 +70,10 @@ export declare function isTimeInRange(time: ISOTimeString, min?: ISOTimeString,
|
|
|
70
70
|
export declare function clampTime(time: ISOTimeString, min?: ISOTimeString, max?: ISOTimeString, includeSeconds?: boolean): ISOTimeString;
|
|
71
71
|
/**
|
|
72
72
|
* Adjusts a time by adding/subtracting minutes.
|
|
73
|
+
*
|
|
74
|
+
* `deltaMinutes` is a whole number of minutes. A fractional delta leaves the
|
|
75
|
+
* time unchanged rather than returning a value that is no longer a time —
|
|
76
|
+
* `HH:MM` has no place for a fraction of a minute.
|
|
73
77
|
*/
|
|
74
78
|
export declare function adjustTime(time: ISOTimeString, deltaMinutes: number, includeSeconds?: boolean): ISOTimeString;
|
|
75
79
|
//# sourceMappingURL=timeParser.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeParser.d.ts","sourceRoot":"","sources":["../../src/utils/timeParser.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG;IAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;CAAC,CAAC;AAEzE;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAMvE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CA6B5D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,UAAU,EAChB,cAAc,GAAE,OAAe,GAC9B,aAAa,CAUf;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,aAAa,GAAG,SAAS,EAC/B,cAAc,GAAE,OAAe,GAC9B,MAAM,CAqBR;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,aAAa,GAAG,SAAS,EAC/B,cAAc,GAAE,OAAe,GAC9B,MAAM,CAmBR;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,cAAc,GAAE,OAAe,GAC9B,aAAa,GAAG,IAAI,CA6HtB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,CAAC,EAAE,aAAa,GAAG,SAAS,EAC5B,CAAC,EAAE,aAAa,GAAG,SAAS,GAC3B,MAAM,CA4BR;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,aAAa,EACnB,GAAG,CAAC,EAAE,aAAa,EACnB,GAAG,CAAC,EAAE,aAAa,GAClB,OAAO,CAQT;AAED;;GAEG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,aAAa,EACnB,GAAG,CAAC,EAAE,aAAa,EACnB,GAAG,CAAC,EAAE,aAAa,EACnB,cAAc,GAAE,OAAe,GAC9B,aAAa,CAoBf;AAED
|
|
1
|
+
{"version":3,"file":"timeParser.d.ts","sourceRoot":"","sources":["../../src/utils/timeParser.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG;IAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;CAAC,CAAC;AAEzE;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAMvE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CA6B5D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,UAAU,EAChB,cAAc,GAAE,OAAe,GAC9B,aAAa,CAUf;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,aAAa,GAAG,SAAS,EAC/B,cAAc,GAAE,OAAe,GAC9B,MAAM,CAqBR;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,aAAa,GAAG,SAAS,EAC/B,cAAc,GAAE,OAAe,GAC9B,MAAM,CAmBR;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,cAAc,GAAE,OAAe,GAC9B,aAAa,GAAG,IAAI,CA6HtB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,CAAC,EAAE,aAAa,GAAG,SAAS,EAC5B,CAAC,EAAE,aAAa,GAAG,SAAS,GAC3B,MAAM,CA4BR;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,aAAa,EACnB,GAAG,CAAC,EAAE,aAAa,EACnB,GAAG,CAAC,EAAE,aAAa,GAClB,OAAO,CAQT;AAED;;GAEG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,aAAa,EACnB,GAAG,CAAC,EAAE,aAAa,EACnB,GAAG,CAAC,EAAE,aAAa,EACnB,cAAc,GAAE,OAAe,GAC9B,aAAa,CAoBf;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,aAAa,EACnB,YAAY,EAAE,MAAM,EACpB,cAAc,GAAE,OAAe,GAC9B,aAAa,CA2Bf"}
|
package/dist/utils/timeParser.js
CHANGED
|
@@ -313,6 +313,10 @@ export function clampTime(time, min, max, includeSeconds = false) {
|
|
|
313
313
|
|
|
314
314
|
/**
|
|
315
315
|
* Adjusts a time by adding/subtracting minutes.
|
|
316
|
+
*
|
|
317
|
+
* `deltaMinutes` is a whole number of minutes. A fractional delta leaves the
|
|
318
|
+
* time unchanged rather than returning a value that is no longer a time —
|
|
319
|
+
* `HH:MM` has no place for a fraction of a minute.
|
|
316
320
|
*/
|
|
317
321
|
export function adjustTime(time, deltaMinutes, includeSeconds = false) {
|
|
318
322
|
const parsed = parseISOTime(time);
|
|
@@ -321,8 +325,11 @@ export function adjustTime(time, deltaMinutes, includeSeconds = false) {
|
|
|
321
325
|
}
|
|
322
326
|
|
|
323
327
|
// A non-finite delta would spin the wrap-around forever (-Infinity) or
|
|
324
|
-
// produce "NaN:NaN" (NaN)
|
|
325
|
-
|
|
328
|
+
// produce "NaN:NaN" (NaN), and a fractional one is never rounded on the way
|
|
329
|
+
// out — formatISOTime pads "30.5" to two characters and leaves it, so the
|
|
330
|
+
// caller gets back a value that is no longer a time. Steps are whole
|
|
331
|
+
// minutes: return the input unchanged instead.
|
|
332
|
+
if (!Number.isInteger(deltaMinutes)) {
|
|
326
333
|
return time;
|
|
327
334
|
}
|
|
328
335
|
let totalMinutes = parsed.hour * 60 + parsed.minute + deltaMinutes;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/core",
|
|
3
|
-
"version": "0.7.3-canary.
|
|
3
|
+
"version": "0.7.3-canary.ca48bb7",
|
|
4
4
|
"displayName": "Astryx Core",
|
|
5
5
|
"description": "The component library. Accessible, themeable React components with built-in spacing, dark mode, and StyleX styling.",
|
|
6
6
|
"author": "Meta Open Source",
|
|
@@ -792,8 +792,8 @@
|
|
|
792
792
|
"react-dom": ">=19.0.0"
|
|
793
793
|
},
|
|
794
794
|
"devDependencies": {
|
|
795
|
-
"@astryxdesign/a11y-spec": "0.7.3-canary.
|
|
796
|
-
"@astryxdesign/cli": "0.7.3-canary.
|
|
795
|
+
"@astryxdesign/a11y-spec": "0.7.3-canary.ca48bb7",
|
|
796
|
+
"@astryxdesign/cli": "0.7.3-canary.ca48bb7",
|
|
797
797
|
"@babel/cli": "^7.29.7",
|
|
798
798
|
"@babel/core": "^7.29.7",
|
|
799
799
|
"@babel/preset-react": "^7.29.7",
|
|
@@ -42,29 +42,29 @@ separately targetable surface. The status and content targets remain unchanged.
|
|
|
42
42
|
- Released default preserved: `no` — Banner no longer derives a live-region role from visual status
|
|
43
43
|
- Compatibility class: breaking accessibility-semantic correction; visual output, DOM structure, props, theming targets, and interaction behavior are unchanged
|
|
44
44
|
- Controlled/uncontrolled behavior: unchanged
|
|
45
|
-
- Migration decision: announce async outcomes in their transition handler with `useAnnounce`; add an explicit `role="status"` only for a persistent semantic mirror, and reserve `role="alert"` for genuinely urgent interruption
|
|
45
|
+
- Migration decision: announce async outcomes in their transition handler with `useAnnounce`; add an explicit `role="status"` only for a persistent semantic mirror, and reserve `role="alert"` for genuinely urgent interruption. Inside a mounted live container, `spec:AST-086` FR4 applies instead.
|
|
46
46
|
|
|
47
47
|
Consumer migration instructions belong in consumer docs and release notes.
|
|
48
48
|
|
|
49
49
|
### DEP-0007 — Deprecate live-region roles derived from `status`
|
|
50
50
|
|
|
51
|
-
| Field | Value
|
|
52
|
-
| ---------------- |
|
|
53
|
-
| id | `DEP-0007`
|
|
54
|
-
| cleanup | `CLN-0015`
|
|
55
|
-
| package | `@astryxdesign/core`
|
|
56
|
-
| surface | Default ARIA role of `Banner`: `role="alert"` for `warning` and `error`, `role="status"` for `info` and `success`, derived from `status` when the caller passes no `role`
|
|
57
|
-
| old contract | Visual `status` selects the live-region role of the Banner root
|
|
58
|
-
| replacement | A caller that announces an async outcome calls `useAnnounce` from the transition that produced it. A caller whose Banner is a persistent semantic mirror passes `role="status"`; genuinely urgent content passes `role="alert"`. Both explicit roles already reach the Banner root |
|
|
59
|
-
| direct authority | `component:Banner`. Owners: `cixzhang`, `imdreamrunner`
|
|
60
|
-
| warning | Consumer docs and the release notes name `DEP-0007` and the explicit `role` that keeps the released semantics. No runtime warning (`spec:AST-017` FR29)
|
|
61
|
-
| migration | Non-mechanical: a caller that announces an async outcome calls `useAnnounce` from the transition that produced it; a caller whose Banner is a persistent mirror or urgent content passes `role="status"` or `role="alert"` |
|
|
62
|
-
| codemod | None: whether a Banner needs an announcement, and when, depends on the transition that renders it, which only the caller knows; adding the released role everywhere would restore the coupling this cleanup removes
|
|
63
|
-
| downstream | Maintained docs teach `useAnnounce` for async outcomes and explicit `role` for persistent mirrors |
|
|
64
|
-
| transition | no prior transition
|
|
65
|
-
| state | `proposed`
|
|
66
|
-
| open decision | Banner FR and DEC entries that make `status` visual-only
|
|
67
|
-
| target plan | `CLN-0015` in the next minor release
|
|
51
|
+
| Field | Value |
|
|
52
|
+
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
53
|
+
| id | `DEP-0007` |
|
|
54
|
+
| cleanup | `CLN-0015` |
|
|
55
|
+
| package | `@astryxdesign/core` |
|
|
56
|
+
| surface | Default ARIA role of `Banner`: `role="alert"` for `warning` and `error`, `role="status"` for `info` and `success`, derived from `status` when the caller passes no `role` |
|
|
57
|
+
| old contract | Visual `status` selects the live-region role of the Banner root |
|
|
58
|
+
| replacement | A caller that announces an async outcome calls `useAnnounce` from the transition that produced it. A caller whose Banner is a persistent semantic mirror passes `role="status"`; genuinely urgent content passes `role="alert"`. Both explicit roles already reach the Banner root. Inside a mounted live container, `spec:AST-086` FR4 applies instead. |
|
|
59
|
+
| direct authority | `component:Banner`. Owners: `cixzhang`, `imdreamrunner` |
|
|
60
|
+
| warning | Consumer docs and the release notes name `DEP-0007` and the explicit `role` that keeps the released semantics. No runtime warning (`spec:AST-017` FR29) |
|
|
61
|
+
| migration | Non-mechanical: a caller that announces an async outcome calls `useAnnounce` from the transition that produced it; a caller whose Banner is a persistent mirror or urgent content passes `role="status"` or `role="alert"`. Inside a mounted live container, `spec:AST-086` FR4 applies instead. |
|
|
62
|
+
| codemod | None: whether a Banner needs an announcement, and when, depends on the transition that renders it, which only the caller knows; adding the released role everywhere would restore the coupling this cleanup removes |
|
|
63
|
+
| downstream | Maintained docs teach `useAnnounce` for async outcomes and explicit `role` for persistent mirrors. Inside a mounted live container, `spec:AST-086` FR4 applies instead. |
|
|
64
|
+
| transition | no prior transition |
|
|
65
|
+
| state | `proposed` |
|
|
66
|
+
| open decision | Banner FR and DEC entries that make `status` visual-only |
|
|
67
|
+
| target plan | `CLN-0015` in the next minor release |
|
|
68
68
|
|
|
69
69
|
### CLN-0015 — Banner renders no live-region role by default
|
|
70
70
|
|
|
@@ -105,16 +105,16 @@ prop vocabulary or extensibility rule changes.
|
|
|
105
105
|
The requirements below describe the current implementation and its additive
|
|
106
106
|
frame target contract.
|
|
107
107
|
|
|
108
|
-
| ID | Invariant
|
|
109
|
-
| --- |
|
|
110
|
-
| FR1 | The current render places `banner` on the colored status surface, which is Banner's primary painted surface and reflects `container` and `status`.
|
|
111
|
-
| FR2 | The Banner frame receives the public ref, role, supported DOM props, `xstyle`, `className`, and `style`; it also paints the selected `boxShadow`.
|
|
112
|
-
| FR3 | An elevated `card` frame also paints the whole-banner radius. A `section` frame remains square. A non-elevated frame does not receive the frame-radius style.
|
|
113
|
-
| FR4 | Card shape is split across surface owners: the status surface owns all corners without visible content or the top corners with visible content; the content surface owns the bottom corners.
|
|
114
|
-
| FR5 | Theme-authored `borderRadius` on `banner` currently writes the private `--_banner-radius` variable on the Status surface only. CSS inheritance does not carry that value upward to the frame or sideways to the Content surface, so both keep their fallback radius.
|
|
115
|
-
| FR6 | The Banner frame exposes `banner-frame` and reflects `container` and `elevation`. The existing `banner` target remains on the Status surface rather than moving to the outermost DOM element.
|
|
116
|
-
| FR7 | `banner-frame` is additive. The existing `banner`, `banner-icon`, `banner-description`, and `banner-content` targets and their current axes remain unchanged.
|
|
117
|
-
| FR8 | `status` controls visual meaning only and MUST NOT derive `role`, `aria-live`, or an announcement. Standard DOM props MAY provide an explicit persistent role. Async outcomes MUST announce from the transition handler through `useAnnounce
|
|
108
|
+
| ID | Invariant | Basis | Contract state |
|
|
109
|
+
| --- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | ------------------------ |
|
|
110
|
+
| FR1 | The current render places `banner` on the colored status surface, which is Banner's primary painted surface and reflects `container` and `status`. | Current source, public docs, and tests | Current behavior |
|
|
111
|
+
| FR2 | The Banner frame receives the public ref, role, supported DOM props, `xstyle`, `className`, and `style`; it also paints the selected `boxShadow`. | Current source and tests | Current behavior |
|
|
112
|
+
| FR3 | An elevated `card` frame also paints the whole-banner radius. A `section` frame remains square. A non-elevated frame does not receive the frame-radius style. | Current source and elevation tests | Current behavior |
|
|
113
|
+
| FR4 | Card shape is split across surface owners: the status surface owns all corners without visible content or the top corners with visible content; the content surface owns the bottom corners. | Current source | Current behavior |
|
|
114
|
+
| FR5 | Theme-authored `borderRadius` on `banner` currently writes the private `--_banner-radius` variable on the Status surface only. CSS inheritance does not carry that value upward to the frame or sideways to the Content surface, so both keep their fallback radius. | Current compiler output and CSS inheritance | Current reachability gap |
|
|
115
|
+
| FR6 | The Banner frame exposes `banner-frame` and reflects `container` and `elevation`. The existing `banner` target remains on the Status surface rather than moving to the outermost DOM element. | Owner decision; current source and tests | Current behavior |
|
|
116
|
+
| FR7 | `banner-frame` is additive. The existing `banner`, `banner-icon`, `banner-description`, and `banner-content` targets and their current axes remain unchanged. | Current target inventory; compatibility policy | Current behavior |
|
|
117
|
+
| FR8 | `status` controls visual meaning only and MUST NOT derive `role`, `aria-live`, or an announcement. Standard DOM props MAY provide an explicit persistent role, except on a Banner added inside a mounted live container (`spec:AST-086` FR4). Async outcomes MUST announce from the transition handler through `useAnnounce`, except inside a mounted live container, where `spec:AST-086` FR4 applies; `role="alert"` is reserved for genuinely urgent interruptive content. | Accessibility Checklist §Announcements; owner decision | Current behavior |
|
|
118
118
|
|
|
119
119
|
### Allowed variation
|
|
120
120
|
|
|
@@ -154,11 +154,15 @@ runtime work.
|
|
|
154
154
|
`status` communicates visual category through color and icon; it does not choose
|
|
155
155
|
announcement urgency. Banner renders no live-region role by default. A caller may
|
|
156
156
|
provide `role="status"` through the standard DOM surface when the visible banner
|
|
157
|
-
is intentionally a persistent semantic mirror
|
|
157
|
+
is intentionally a persistent semantic mirror, except on a Banner added inside a
|
|
158
|
+
mounted live container. Async outcomes use `useAnnounce`
|
|
158
159
|
from the transition handler, which writes into a previously mounted live region;
|
|
160
|
+
inside a mounted live container, that container delivers them
|
|
161
|
+
(`spec:AST-086` FR4);
|
|
159
162
|
a Banner mounted together with its message is not a reliable announcement.
|
|
160
163
|
`role="alert"` remains available as an explicit native role, but is reserved for
|
|
161
|
-
genuinely urgent content that should interrupt current speech
|
|
164
|
+
genuinely urgent content that should interrupt current speech; it is not used on
|
|
165
|
+
a Banner added inside a mounted live container.
|
|
162
166
|
|
|
163
167
|
Dismissal focus handoff, disclosure controls, and accessible control names remain
|
|
164
168
|
unchanged.
|
|
@@ -247,8 +251,9 @@ placement and would imply that the target must remain on the outermost element.
|
|
|
247
251
|
Banner status selects color and icon only. It does not assign `role="status"` or
|
|
248
252
|
`role="alert"`. Async outcomes announce through `useAnnounce` from the transition
|
|
249
253
|
handler so the message reaches a persistent live region rather than one mounted
|
|
250
|
-
with its content. An explicit native role remains available through BaseProps for
|
|
251
|
-
a persistent semantic mirror or the rare genuinely urgent alert
|
|
254
|
+
with its content; inside a mounted live container, `spec:AST-086` FR4 applies. An explicit native role remains available through BaseProps for
|
|
255
|
+
a persistent semantic mirror or the rare genuinely urgent alert, except on a
|
|
256
|
+
Banner added inside a mounted live container.
|
|
252
257
|
|
|
253
258
|
Rejected: deriving alert urgency from `warning` or `error`. Severity and urgency
|
|
254
259
|
are independent, and a static error present on first paint is not an event that
|
|
@@ -3,11 +3,11 @@ schema_version: 3
|
|
|
3
3
|
template_version: 3
|
|
4
4
|
kind: component
|
|
5
5
|
id: component:BottomSheet
|
|
6
|
-
authority:
|
|
6
|
+
authority: current
|
|
7
7
|
archive_reason: null
|
|
8
8
|
superseded_by: null
|
|
9
|
-
approved_by:
|
|
10
|
-
approved_at:
|
|
9
|
+
approved_by: imdreamrunner
|
|
10
|
+
approved_at: 2026-10-21
|
|
11
11
|
owners: [cixzhang]
|
|
12
12
|
review_triggers: [theming, layout, public-api]
|
|
13
13
|
verified_by:
|
|
@@ -15,7 +15,6 @@ verified_by:
|
|
|
15
15
|
packages/core/src/BottomSheet/BottomSheet.test.tsx,
|
|
16
16
|
packages/core/src/BottomSheet/BottomSheetPanel.test.tsx,
|
|
17
17
|
packages/core/src/BottomSheet/BottomSheetKeyboard.test.tsx,
|
|
18
|
-
packages/core/src/BottomSheet/__tests__/BottomSheetNativeModal.a11y.browser.spec.ts,
|
|
19
18
|
packages/core/src/BottomSheet/__tests__/BottomSheetKeyboard.a11y.browser.spec.ts,
|
|
20
19
|
apps/storybook/stories/BottomSheet.stories.tsx,
|
|
21
20
|
scripts/check-knowledge.mjs,
|
|
@@ -38,52 +37,24 @@ system_specs: [spec:AST-025]
|
|
|
38
37
|
## Intent
|
|
39
38
|
|
|
40
39
|
BottomSheet presents caller-provided content in a panel that rises from the
|
|
41
|
-
bottom edge. This
|
|
42
|
-
scrolling, theming reachability, and the Content
|
|
40
|
+
bottom edge. This record covers consumer anatomy, the native dialog every sheet
|
|
41
|
+
renders, keyboard-reachable scrolling, theming reachability, and the Content
|
|
42
|
+
area's container padding. Where the shipped sheet does not yet meet a
|
|
43
|
+
requirement, the row carries a present-tense implementation gap note.
|
|
43
44
|
|
|
44
45
|
## Compatibility and migration
|
|
45
46
|
|
|
46
|
-
- Released default preserved: `
|
|
47
|
-
padding, the Content area insets by `--spacing-4` on every logical edge
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
it drops that inset or sets `padding={0}`
|
|
47
|
+
- Released default preserved: `yes`; with no `padding` prop and no theme
|
|
48
|
+
padding, the Content area insets by `--spacing-4` on every logical edge, and
|
|
49
|
+
`padding={0}` keeps an unpadded Content area
|
|
50
|
+
- Compatibility class: records the shipped anatomy, padded Content area, and
|
|
51
|
+
native dialog; no public prop, default, or export changes
|
|
52
52
|
- Controlled/uncontrolled behavior: unchanged
|
|
53
|
-
- Migration decision:
|
|
53
|
+
- Migration decision: none; the precedence rule under Transformation and
|
|
54
|
+
precedence order is the whole contract
|
|
54
55
|
|
|
55
56
|
Consumer migration instructions belong in consumer docs and release notes.
|
|
56
57
|
|
|
57
|
-
### DEP-0009 — Deprecate the unpadded default Content area of `BottomSheet`
|
|
58
|
-
|
|
59
|
-
| Field | Value |
|
|
60
|
-
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
61
|
-
| id | `DEP-0009` |
|
|
62
|
-
| cleanup | `CLN-0018` |
|
|
63
|
-
| package | `@astryxdesign/core` |
|
|
64
|
-
| surface | Default inset of the `BottomSheet` Content area when no `padding` prop and no theme padding are set |
|
|
65
|
-
| old contract | The Content area has no padding |
|
|
66
|
-
| replacement | `padding={0}` keeps the unpadded Content area; `padding` and theme padding already resolve before the default |
|
|
67
|
-
| direct authority | `component:BottomSheet` Compatibility and migration. Owners: `cixzhang` |
|
|
68
|
-
| warning | Consumer docs and the release notes name `DEP-0009` and `padding={0}`. No runtime warning (`spec:AST-017` FR29) |
|
|
69
|
-
| migration | Mechanical: add `padding={0}` to a BottomSheet that sets no padding, unless its only child is a padded Section or a Layout |
|
|
70
|
-
| codemod | `astryx upgrade` adds `padding={0}` before any spread, skips sheets whose only child is a core Section or Layout, and marks a nested padding-less Layout for review |
|
|
71
|
-
| downstream | In-repo sheets that supply their own inset pass `padding={0}`; consumer examples rely on the default inset |
|
|
72
|
-
| transition | no prior transition |
|
|
73
|
-
| state | `proposed` |
|
|
74
|
-
| open decision | This record is draft and needs approval |
|
|
75
|
-
| target plan | `CLN-0018` in the next minor release |
|
|
76
|
-
|
|
77
|
-
### CLN-0018 — BottomSheet pads its Content area by default
|
|
78
|
-
|
|
79
|
-
| Field | Value |
|
|
80
|
-
| --------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
81
|
-
| id | `CLN-0018` |
|
|
82
|
-
| lifecycle | `DEP-0009` |
|
|
83
|
-
| delta | With no `padding` prop and no theme padding, the Content area insets by `--spacing-4` on every logical edge and publishes that inset |
|
|
84
|
-
| rollback | Restore the unpadded default from the final-patch baseline |
|
|
85
|
-
| state | `pending` — lands in a declared minor with its `[breaking]` Changeset |
|
|
86
|
-
|
|
87
58
|
## Ownership boundary
|
|
88
59
|
|
|
89
60
|
**Owns**
|
|
@@ -95,7 +66,9 @@ Consumer migration instructions belong in consumer docs and release notes.
|
|
|
95
66
|
`architecture:container-padding`.
|
|
96
67
|
- Standalone sheet presentation, including its optional native-dialog Scrim.
|
|
97
68
|
- The native dialog every sheet renders, standalone or switcher-managed
|
|
98
|
-
(`component:BottomSheetSwitcher` DEC-1
|
|
69
|
+
(`component:BottomSheetSwitcher` DEC-1). Implementation gap: a
|
|
70
|
+
switcher-managed sheet renders a panel inside the switcher's one shared
|
|
71
|
+
dialog and owns no dialog of its own.
|
|
99
72
|
|
|
100
73
|
**Does not own / non-goals**
|
|
101
74
|
|
|
@@ -104,7 +77,7 @@ Consumer migration instructions belong in consumer docs and release notes.
|
|
|
104
77
|
`main`.
|
|
105
78
|
- The presentation lifecycle of its dialog and the flow's scrim ownership when
|
|
106
79
|
the sheet participates in a BottomSheetSwitcher — owned by BottomSheetSwitcher
|
|
107
|
-
(`component:BottomSheetSwitcher` DEC-1
|
|
80
|
+
(`component:BottomSheetSwitcher` DEC-1).
|
|
108
81
|
- Shared layer hosting or dismissal policy.
|
|
109
82
|
|
|
110
83
|
## Public concepts
|
|
@@ -114,12 +87,12 @@ in `BottomSheet.doc.mjs`.
|
|
|
114
87
|
|
|
115
88
|
## Behavioral and layout contract
|
|
116
89
|
|
|
117
|
-
| ID |
|
|
118
|
-
| --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
119
|
-
| FR1 | The current presented sheet contains one Sheet panel, one scrolling Content area, and one decorative Handle; a Scrim is present only in scrim-backed presentation. | Current source, docs, and tests
|
|
120
|
-
| FR2 | The Sheet panel carries `bottom-sheet`; Content area, Handle, and Scrim carry no BottomSheet public target. | Current source, docs, and tests
|
|
121
|
-
| FR3 | Content renders in one real observed content box. Effective overflow, containment, and keyboard access come from `useScrollableArea`; the named overflowing body delegates forward Tab entry to a safe first sequential native link/button. | `spec:AST-025`;
|
|
122
|
-
| FR4 | The Content area pads caller content by the sheet's container inset and publishes the applied inset to descendants as a container publisher. | `architecture:container-padding`
|
|
90
|
+
| ID | Invariant | Basis |
|
|
91
|
+
| --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
|
|
92
|
+
| FR1 | The current presented sheet contains one Sheet panel, one scrolling Content area, and one decorative Handle; a Scrim is present only in scrim-backed presentation. | Current source, docs, and tests |
|
|
93
|
+
| FR2 | The Sheet panel carries `bottom-sheet`; Content area, Handle, and Scrim carry no BottomSheet public target. | Current source, docs, and tests |
|
|
94
|
+
| FR3 | Content renders in one real observed content box. Effective overflow, containment, and keyboard access come from `useScrollableArea`; the named overflowing body delegates forward Tab entry to a safe first sequential native link/button. | `spec:AST-025`; tests |
|
|
95
|
+
| FR4 | The Content area pads caller content by the sheet's container inset and publishes the applied inset to descendants as a container publisher. | `architecture:container-padding` |
|
|
123
96
|
|
|
124
97
|
### Allowed variation
|
|
125
98
|
|
|
@@ -134,8 +107,8 @@ in `BottomSheet.doc.mjs`.
|
|
|
134
107
|
without a Scrim.
|
|
135
108
|
- A switcher-managed sheet renders the same panel anatomy in its own dialog while
|
|
136
109
|
BottomSheetSwitcher coordinates that dialog's lifecycle and the flow's one Scrim
|
|
137
|
-
(`component:BottomSheetSwitcher` DEC-1
|
|
138
|
-
|
|
110
|
+
(`component:BottomSheetSwitcher` DEC-1). Implementation gap: the panel
|
|
111
|
+
renders inside the switcher's one shared dialog.
|
|
139
112
|
|
|
140
113
|
### Transformation and precedence order
|
|
141
114
|
|