@entifix/react-controls 0.18.2 → 0.20.0
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/README.md +13 -5
- package/dist/i18n/catalog/en.d.ts.map +1 -1
- package/dist/i18n/catalog/en.js +68 -10
- package/dist/i18n/catalog/en.js.map +1 -1
- package/dist/i18n/catalog/es.d.ts +76 -5
- package/dist/i18n/catalog/es.d.ts.map +1 -1
- package/dist/i18n/catalog/es.js +74 -10
- package/dist/i18n/catalog/es.js.map +1 -1
- package/dist/i18n/catalog/index.d.ts +126 -10
- package/dist/i18n/catalog/index.d.ts.map +1 -1
- package/dist/i18n/entity-labels.d.ts +14 -0
- package/dist/i18n/entity-labels.d.ts.map +1 -1
- package/dist/i18n/entity-labels.js +15 -0
- package/dist/i18n/entity-labels.js.map +1 -1
- package/dist/i18n/i18n-context.js +2 -2
- package/dist/i18n/i18n-context.js.map +1 -1
- package/dist/index.d.ts +13 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -2
- package/dist/index.js.map +1 -1
- package/dist/primitives.d.ts +7 -1
- package/dist/primitives.d.ts.map +1 -1
- package/dist/primitives.js +7 -1
- package/dist/primitives.js.map +1 -1
- package/dist/theme/index.d.ts +1 -0
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +1 -0
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/theme-context.d.ts +35 -7
- package/dist/theme/theme-context.d.ts.map +1 -1
- package/dist/theme/theme-context.js +109 -21
- package/dist/theme/theme-context.js.map +1 -1
- package/dist/theme/theme-cookie.d.ts +9 -0
- package/dist/theme/theme-cookie.d.ts.map +1 -0
- package/dist/theme/theme-cookie.js +8 -0
- package/dist/theme/theme-cookie.js.map +1 -0
- package/dist/theme/theme-script.d.ts +8 -5
- package/dist/theme/theme-script.d.ts.map +1 -1
- package/dist/theme/theme-script.js +24 -10
- package/dist/theme/theme-script.js.map +1 -1
- package/dist/theme/types.d.ts +19 -3
- package/dist/theme/types.d.ts.map +1 -1
- package/dist/theme/types.js.map +1 -1
- package/dist/ui/actions/action-surfaces.d.ts +1 -1
- package/dist/ui/actions/action-surfaces.js +1 -1
- package/dist/ui/actions/action-surfaces.js.map +1 -1
- package/dist/ui/actions/error-actions.d.ts +32 -0
- package/dist/ui/actions/error-actions.d.ts.map +1 -0
- package/dist/ui/actions/error-actions.js +40 -0
- package/dist/ui/actions/error-actions.js.map +1 -0
- package/dist/ui/actions/index.d.ts +2 -0
- package/dist/ui/actions/index.d.ts.map +1 -1
- package/dist/ui/actions/index.js +2 -0
- package/dist/ui/actions/index.js.map +1 -1
- package/dist/ui/actions/shortcut.d.ts +13 -0
- package/dist/ui/actions/shortcut.d.ts.map +1 -0
- package/dist/ui/actions/shortcut.js +18 -0
- package/dist/ui/actions/shortcut.js.map +1 -0
- package/dist/ui/actions/use-verb-invoker.d.ts +50 -0
- package/dist/ui/actions/use-verb-invoker.d.ts.map +1 -0
- package/dist/ui/actions/use-verb-invoker.js +93 -0
- package/dist/ui/actions/use-verb-invoker.js.map +1 -0
- package/dist/ui/atoms/alert/alert-dismiss.d.ts +9 -0
- package/dist/ui/atoms/alert/alert-dismiss.d.ts.map +1 -0
- package/dist/ui/atoms/alert/alert-dismiss.js +28 -0
- package/dist/ui/atoms/alert/alert-dismiss.js.map +1 -0
- package/dist/ui/atoms/alert/alert.d.ts +24 -0
- package/dist/ui/atoms/alert/alert.d.ts.map +1 -0
- package/dist/ui/atoms/alert/alert.js +50 -0
- package/dist/ui/atoms/alert/alert.js.map +1 -0
- package/dist/ui/atoms/alert/index.d.ts +3 -0
- package/dist/ui/atoms/alert/index.d.ts.map +1 -0
- package/dist/ui/atoms/alert/index.js +4 -0
- package/dist/ui/atoms/alert/index.js.map +1 -0
- package/dist/ui/atoms/alert/tone.d.ts +8 -0
- package/dist/ui/atoms/alert/tone.d.ts.map +1 -0
- package/dist/ui/atoms/alert/tone.js +11 -0
- package/dist/ui/atoms/alert/tone.js.map +1 -0
- package/dist/ui/atoms/button/button-recipe.js +1 -1
- package/dist/ui/atoms/button/button-recipe.js.map +1 -1
- package/dist/ui/atoms/button/index.d.ts +1 -0
- package/dist/ui/atoms/button/index.d.ts.map +1 -1
- package/dist/ui/atoms/button/index.js +1 -0
- package/dist/ui/atoms/button/index.js.map +1 -1
- package/dist/ui/atoms/button/submit-button.d.ts +13 -0
- package/dist/ui/atoms/button/submit-button.d.ts.map +1 -0
- package/dist/ui/atoms/button/submit-button.js +29 -0
- package/dist/ui/atoms/button/submit-button.js.map +1 -0
- package/dist/ui/atoms/cell-value/cell-value.d.ts +6 -1
- package/dist/ui/atoms/cell-value/cell-value.d.ts.map +1 -1
- package/dist/ui/atoms/cell-value/cell-value.js +48 -16
- package/dist/ui/atoms/cell-value/cell-value.js.map +1 -1
- package/dist/ui/atoms/field/checkbox.d.ts.map +1 -1
- package/dist/ui/atoms/field/checkbox.js +21 -1
- package/dist/ui/atoms/field/checkbox.js.map +1 -1
- package/dist/ui/atoms/field/field.js +1 -1
- package/dist/ui/atoms/field/field.js.map +1 -1
- package/dist/ui/atoms/field-control/field-control.d.ts +7 -1
- package/dist/ui/atoms/field-control/field-control.d.ts.map +1 -1
- package/dist/ui/atoms/field-control/field-control.js +25 -3
- package/dist/ui/atoms/field-control/field-control.js.map +1 -1
- package/dist/ui/atoms/money/index.d.ts +4 -0
- package/dist/ui/atoms/money/index.d.ts.map +1 -0
- package/dist/ui/atoms/money/index.js +5 -0
- package/dist/ui/atoms/money/index.js.map +1 -0
- package/dist/ui/atoms/money/money-input.d.ts +19 -0
- package/dist/ui/atoms/money/money-input.d.ts.map +1 -0
- package/dist/ui/atoms/money/money-input.js +75 -0
- package/dist/ui/atoms/money/money-input.js.map +1 -0
- package/dist/ui/atoms/money/money-math.d.ts +21 -0
- package/dist/ui/atoms/money/money-math.d.ts.map +1 -0
- package/dist/ui/atoms/money/money-math.js +36 -0
- package/dist/ui/atoms/money/money-math.js.map +1 -0
- package/dist/ui/atoms/money/money.d.ts +19 -0
- package/dist/ui/atoms/money/money.d.ts.map +1 -0
- package/dist/ui/atoms/money/money.js +26 -0
- package/dist/ui/atoms/money/money.js.map +1 -0
- package/dist/ui/atoms/number-input/index.d.ts +3 -0
- package/dist/ui/atoms/number-input/index.d.ts.map +1 -0
- package/dist/ui/atoms/number-input/index.js +4 -0
- package/dist/ui/atoms/number-input/index.js.map +1 -0
- package/dist/ui/atoms/number-input/number-input.d.ts +10 -0
- package/dist/ui/atoms/number-input/number-input.d.ts.map +1 -0
- package/dist/ui/atoms/number-input/number-input.js +23 -0
- package/dist/ui/atoms/number-input/number-input.js.map +1 -0
- package/dist/ui/atoms/number-input/quantity-input.d.ts +29 -0
- package/dist/ui/atoms/number-input/quantity-input.d.ts.map +1 -0
- package/dist/ui/atoms/number-input/quantity-input.js +100 -0
- package/dist/ui/atoms/number-input/quantity-input.js.map +1 -0
- package/dist/ui/atoms/skeleton/skeleton.js +1 -1
- package/dist/ui/atoms/skeleton/skeleton.js.map +1 -1
- package/dist/ui/atoms/status-tag/index.d.ts +2 -0
- package/dist/ui/atoms/status-tag/index.d.ts.map +1 -0
- package/dist/ui/atoms/status-tag/index.js +3 -0
- package/dist/ui/atoms/status-tag/index.js.map +1 -0
- package/dist/ui/atoms/status-tag/status-tag.d.ts +17 -0
- package/dist/ui/atoms/status-tag/status-tag.d.ts.map +1 -0
- package/dist/ui/atoms/status-tag/status-tag.js +37 -0
- package/dist/ui/atoms/status-tag/status-tag.js.map +1 -0
- package/dist/ui/atoms/switch/switch.d.ts.map +1 -1
- package/dist/ui/atoms/switch/switch.js +6 -3
- package/dist/ui/atoms/switch/switch.js.map +1 -1
- package/dist/ui/atoms/table/table.d.ts +12 -3
- package/dist/ui/atoms/table/table.d.ts.map +1 -1
- package/dist/ui/atoms/table/table.js +59 -10
- package/dist/ui/atoms/table/table.js.map +1 -1
- package/dist/ui/atoms/text/text.d.ts +2 -2
- package/dist/ui/atoms/text/text.d.ts.map +1 -1
- package/dist/ui/atoms/text/text.js.map +1 -1
- package/dist/ui/molecules/action-bar/action-bar.d.ts +76 -0
- package/dist/ui/molecules/action-bar/action-bar.d.ts.map +1 -0
- package/dist/ui/molecules/action-bar/action-bar.js +218 -0
- package/dist/ui/molecules/action-bar/action-bar.js.map +1 -0
- package/dist/ui/molecules/action-bar/index.d.ts +2 -0
- package/dist/ui/molecules/action-bar/index.d.ts.map +1 -0
- package/dist/ui/molecules/action-bar/index.js +3 -0
- package/dist/ui/molecules/action-bar/index.js.map +1 -0
- package/dist/ui/molecules/breadcrumbs/breadcrumbs.d.ts +11 -2
- package/dist/ui/molecules/breadcrumbs/breadcrumbs.d.ts.map +1 -1
- package/dist/ui/molecules/breadcrumbs/breadcrumbs.js +9 -7
- package/dist/ui/molecules/breadcrumbs/breadcrumbs.js.map +1 -1
- package/dist/ui/molecules/bulk-action-bar/bulk-action-bar.d.ts.map +1 -1
- package/dist/ui/molecules/bulk-action-bar/bulk-action-bar.js +8 -10
- package/dist/ui/molecules/bulk-action-bar/bulk-action-bar.js.map +1 -1
- package/dist/ui/molecules/bulk-result/bulk-result.d.ts +3 -3
- package/dist/ui/molecules/bulk-result/bulk-result.js +4 -4
- package/dist/ui/molecules/bulk-result/bulk-result.js.map +1 -1
- package/dist/ui/molecules/column-settings/column-settings.js +1 -1
- package/dist/ui/molecules/column-settings/column-settings.js.map +1 -1
- package/dist/ui/molecules/confirm-dialog/confirm-dialog.d.ts +24 -9
- package/dist/ui/molecules/confirm-dialog/confirm-dialog.d.ts.map +1 -1
- package/dist/ui/molecules/confirm-dialog/confirm-dialog.js +38 -13
- package/dist/ui/molecules/confirm-dialog/confirm-dialog.js.map +1 -1
- package/dist/ui/molecules/description-list/description-list.d.ts +17 -0
- package/dist/ui/molecules/description-list/description-list.d.ts.map +1 -0
- package/dist/ui/molecules/description-list/description-list.js +36 -0
- package/dist/ui/molecules/description-list/description-list.js.map +1 -0
- package/dist/ui/molecules/description-list/index.d.ts +2 -0
- package/dist/ui/molecules/description-list/index.d.ts.map +1 -0
- package/dist/ui/molecules/description-list/index.js +3 -0
- package/dist/ui/molecules/description-list/index.js.map +1 -0
- package/dist/ui/molecules/drawer/drawer.js +3 -3
- package/dist/ui/molecules/drawer/drawer.js.map +1 -1
- package/dist/ui/molecules/empty-state/empty-state.d.ts +15 -0
- package/dist/ui/molecules/empty-state/empty-state.d.ts.map +1 -0
- package/dist/ui/molecules/empty-state/empty-state.js +29 -0
- package/dist/ui/molecules/empty-state/empty-state.js.map +1 -0
- package/dist/ui/molecules/empty-state/index.d.ts +2 -0
- package/dist/ui/molecules/empty-state/index.d.ts.map +1 -0
- package/dist/ui/molecules/empty-state/index.js +3 -0
- package/dist/ui/molecules/empty-state/index.js.map +1 -0
- package/dist/ui/molecules/entity-link-input/entity-link-input.d.ts.map +1 -1
- package/dist/ui/molecules/entity-link-input/entity-link-input.js +7 -4
- package/dist/ui/molecules/entity-link-input/entity-link-input.js.map +1 -1
- package/dist/ui/molecules/entity-link-picker/entity-link-picker.js +2 -2
- package/dist/ui/molecules/entity-link-picker/entity-link-picker.js.map +1 -1
- package/dist/ui/molecules/entity-record-card/entity-record-card.d.ts +33 -20
- package/dist/ui/molecules/entity-record-card/entity-record-card.d.ts.map +1 -1
- package/dist/ui/molecules/entity-record-card/entity-record-card.js +53 -20
- package/dist/ui/molecules/entity-record-card/entity-record-card.js.map +1 -1
- package/dist/ui/molecules/filter-builder/filter-builder.d.ts +8 -2
- package/dist/ui/molecules/filter-builder/filter-builder.d.ts.map +1 -1
- package/dist/ui/molecules/filter-builder/filter-builder.js +14 -5
- package/dist/ui/molecules/filter-builder/filter-builder.js.map +1 -1
- package/dist/ui/molecules/filter-chips/filter-chips.d.ts +16 -0
- package/dist/ui/molecules/filter-chips/filter-chips.d.ts.map +1 -0
- package/dist/ui/molecules/filter-chips/filter-chips.js +73 -0
- package/dist/ui/molecules/filter-chips/filter-chips.js.map +1 -0
- package/dist/ui/molecules/filter-chips/index.d.ts +2 -0
- package/dist/ui/molecules/filter-chips/index.d.ts.map +1 -0
- package/dist/ui/molecules/filter-chips/index.js +3 -0
- package/dist/ui/molecules/filter-chips/index.js.map +1 -0
- package/dist/ui/molecules/media-gallery/index.d.ts +2 -0
- package/dist/ui/molecules/media-gallery/index.d.ts.map +1 -0
- package/dist/ui/molecules/media-gallery/index.js +3 -0
- package/dist/ui/molecules/media-gallery/index.js.map +1 -0
- package/dist/ui/molecules/media-gallery/media-gallery.d.ts +31 -0
- package/dist/ui/molecules/media-gallery/media-gallery.d.ts.map +1 -0
- package/dist/ui/molecules/media-gallery/media-gallery.js +64 -0
- package/dist/ui/molecules/media-gallery/media-gallery.js.map +1 -0
- package/dist/ui/molecules/menu/menu.d.ts +11 -1
- package/dist/ui/molecules/menu/menu.d.ts.map +1 -1
- package/dist/ui/molecules/menu/menu.js +68 -6
- package/dist/ui/molecules/menu/menu.js.map +1 -1
- package/dist/ui/molecules/nav-menu/nav-menu.js +4 -4
- package/dist/ui/molecules/nav-menu/nav-menu.js.map +1 -1
- package/dist/ui/molecules/pagination/pagination.d.ts +5 -0
- package/dist/ui/molecules/pagination/pagination.d.ts.map +1 -1
- package/dist/ui/molecules/pagination/pagination.js +35 -18
- package/dist/ui/molecules/pagination/pagination.js.map +1 -1
- package/dist/ui/molecules/region-state/index.d.ts +2 -0
- package/dist/ui/molecules/region-state/index.d.ts.map +1 -0
- package/dist/ui/molecules/region-state/index.js +3 -0
- package/dist/ui/molecules/region-state/index.js.map +1 -0
- package/dist/ui/molecules/region-state/region-state.d.ts +42 -0
- package/dist/ui/molecules/region-state/region-state.d.ts.map +1 -0
- package/dist/ui/molecules/region-state/region-state.js +83 -0
- package/dist/ui/molecules/region-state/region-state.js.map +1 -0
- package/dist/ui/molecules/segmented-nav/segment-classes.d.ts +3 -3
- package/dist/ui/molecules/segmented-nav/segment-classes.d.ts.map +1 -1
- package/dist/ui/molecules/segmented-nav/segment-classes.js +2 -2
- package/dist/ui/molecules/segmented-nav/segment-classes.js.map +1 -1
- package/dist/ui/molecules/segmented-nav/segmented-nav.d.ts +14 -4
- package/dist/ui/molecules/segmented-nav/segmented-nav.d.ts.map +1 -1
- package/dist/ui/molecules/segmented-nav/segmented-nav.js +6 -5
- package/dist/ui/molecules/segmented-nav/segmented-nav.js.map +1 -1
- package/dist/ui/molecules/split-view/split-view.js +3 -3
- package/dist/ui/molecules/split-view/split-view.js.map +1 -1
- package/dist/ui/molecules/tab-strip/tab-strip.d.ts +51 -12
- package/dist/ui/molecules/tab-strip/tab-strip.d.ts.map +1 -1
- package/dist/ui/molecules/tab-strip/tab-strip.js +125 -34
- package/dist/ui/molecules/tab-strip/tab-strip.js.map +1 -1
- package/dist/ui/molecules/table-toolbar/table-toolbar.d.ts +3 -1
- package/dist/ui/molecules/table-toolbar/table-toolbar.d.ts.map +1 -1
- package/dist/ui/molecules/table-toolbar/table-toolbar.js +3 -2
- package/dist/ui/molecules/table-toolbar/table-toolbar.js.map +1 -1
- package/dist/ui/molecules/toast-region/toast-region.d.ts +63 -19
- package/dist/ui/molecules/toast-region/toast-region.d.ts.map +1 -1
- package/dist/ui/molecules/toast-region/toast-region.js +129 -42
- package/dist/ui/molecules/toast-region/toast-region.js.map +1 -1
- package/dist/ui/organisms/command-palette/command-palette.d.ts.map +1 -1
- package/dist/ui/organisms/command-palette/command-palette.js +25 -18
- package/dist/ui/organisms/command-palette/command-palette.js.map +1 -1
- package/dist/ui/organisms/entity-detail-grid/entity-detail-grid.d.ts.map +1 -1
- package/dist/ui/organisms/entity-detail-grid/entity-detail-grid.js +8 -3
- package/dist/ui/organisms/entity-detail-grid/entity-detail-grid.js.map +1 -1
- package/dist/ui/organisms/entity-form/entity-form.d.ts +1 -1
- package/dist/ui/organisms/entity-form/entity-form.d.ts.map +1 -1
- package/dist/ui/organisms/entity-form/entity-form.js +325 -215
- package/dist/ui/organisms/entity-form/entity-form.js.map +1 -1
- package/dist/ui/organisms/entity-form/entity-form.types.d.ts +8 -0
- package/dist/ui/organisms/entity-form/entity-form.types.d.ts.map +1 -1
- package/dist/ui/organisms/entity-form/entity-form.types.js.map +1 -1
- package/dist/ui/organisms/entity-table/entity-table.d.ts +1 -1
- package/dist/ui/organisms/entity-table/entity-table.d.ts.map +1 -1
- package/dist/ui/organisms/entity-table/entity-table.js +334 -198
- package/dist/ui/organisms/entity-table/entity-table.js.map +1 -1
- package/dist/ui/organisms/entity-table/entity-table.types.d.ts +19 -4
- package/dist/ui/organisms/entity-table/entity-table.types.d.ts.map +1 -1
- package/dist/ui/organisms/entity-table/entity-table.types.js.map +1 -1
- package/dist/ui/organisms/entity-table/header-sort.d.ts +18 -0
- package/dist/ui/organisms/entity-table/header-sort.d.ts.map +1 -0
- package/dist/ui/organisms/entity-table/header-sort.js +54 -0
- package/dist/ui/organisms/entity-table/header-sort.js.map +1 -0
- package/dist/ui/organisms/entity-table/pivot.d.ts +25 -0
- package/dist/ui/organisms/entity-table/pivot.d.ts.map +1 -0
- package/dist/ui/organisms/entity-table/pivot.js +106 -0
- package/dist/ui/organisms/entity-table/pivot.js.map +1 -0
- package/dist/ui/organisms/entity-table/use-result-announcement.d.ts +13 -0
- package/dist/ui/organisms/entity-table/use-result-announcement.d.ts.map +1 -0
- package/dist/ui/organisms/entity-table/use-result-announcement.js +31 -0
- package/dist/ui/organisms/entity-table/use-result-announcement.js.map +1 -0
- package/dist/ui/organisms/top-bar/live-indicator.d.ts +11 -0
- package/dist/ui/organisms/top-bar/live-indicator.d.ts.map +1 -0
- package/dist/ui/organisms/top-bar/live-indicator.js +46 -0
- package/dist/ui/organisms/top-bar/live-indicator.js.map +1 -0
- package/dist/ui/organisms/top-bar/top-bar.d.ts +11 -2
- package/dist/ui/organisms/top-bar/top-bar.d.ts.map +1 -1
- package/dist/ui/organisms/top-bar/top-bar.js +14 -5
- package/dist/ui/organisms/top-bar/top-bar.js.map +1 -1
- package/dist/ui/organisms/wizard/wizard.d.ts +1 -1
- package/dist/ui/organisms/wizard/wizard.d.ts.map +1 -1
- package/dist/ui/organisms/wizard/wizard.js +7 -1
- package/dist/ui/organisms/wizard/wizard.js.map +1 -1
- package/dist/ui/organisms/wizard/wizard.types.d.ts +8 -0
- package/dist/ui/organisms/wizard/wizard.types.d.ts.map +1 -1
- package/dist/ui/organisms/wizard/wizard.types.js.map +1 -1
- package/dist/ui/utils/live-updates.d.ts +24 -0
- package/dist/ui/utils/live-updates.d.ts.map +1 -0
- package/dist/ui/utils/live-updates.js +20 -0
- package/dist/ui/utils/live-updates.js.map +1 -0
- package/dist/ui/utils/use-focus-on-arrival.d.ts +14 -0
- package/dist/ui/utils/use-focus-on-arrival.d.ts.map +1 -0
- package/dist/ui/utils/use-focus-on-arrival.js +42 -0
- package/dist/ui/utils/use-focus-on-arrival.js.map +1 -0
- package/dist/ui/utils/use-hotkey.d.ts +44 -25
- package/dist/ui/utils/use-hotkey.d.ts.map +1 -1
- package/dist/ui/utils/use-hotkey.js +80 -48
- package/dist/ui/utils/use-hotkey.js.map +1 -1
- package/package.json +5 -5
- package/dist/ui/molecules/split-button/index.d.ts +0 -2
- package/dist/ui/molecules/split-button/index.d.ts.map +0 -1
- package/dist/ui/molecules/split-button/index.js +0 -3
- package/dist/ui/molecules/split-button/index.js.map +0 -1
- package/dist/ui/molecules/split-button/split-button.d.ts +0 -21
- package/dist/ui/molecules/split-button/split-button.d.ts.map +0 -1
- package/dist/ui/molecules/split-button/split-button.js +0 -35
- package/dist/ui/molecules/split-button/split-button.js.map +0 -1
|
@@ -1,29 +1,68 @@
|
|
|
1
|
-
import type
|
|
2
|
-
export
|
|
1
|
+
import { type ComponentPropsWithoutRef, type ReactNode } from 'react';
|
|
2
|
+
export interface TabStripProps extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {
|
|
3
|
+
/** The {@link Tab}s, in order. */
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
/** The tablist's accessible name; the controls catalog's `tabs.list` when omitted. */
|
|
6
|
+
label?: string;
|
|
7
|
+
/**
|
|
8
|
+
* What sits after the tabs — a {@link TabAddButton}. It is outside the
|
|
9
|
+
* tablist, because a tablist may own nothing but tabs.
|
|
10
|
+
*/
|
|
11
|
+
actions?: ReactNode;
|
|
12
|
+
}
|
|
3
13
|
/**
|
|
4
|
-
* The workspace tab strip
|
|
5
|
-
*
|
|
6
|
-
*
|
|
14
|
+
* The workspace tab strip, on the WAI-ARIA tabs pattern: one Tab stop for the
|
|
15
|
+
* whole list, Arrow Left/Right (wrapping), Home and End move between tabs, and
|
|
16
|
+
* Enter or Space activates the focused one — activation is manual, because a
|
|
17
|
+
* tab's body is a whole screen and rendering every one an arrow passes over is
|
|
18
|
+
* work nobody asked for. Delete closes a closable tab (see {@link Tab}).
|
|
19
|
+
*
|
|
20
|
+
* Presentational: the open set, the order and the active tab come from the
|
|
21
|
+
* caller. Each tab controls one {@link TabPanel}, which the caller renders.
|
|
22
|
+
* Below the width of its tabs the list scrolls on its own, so the strip
|
|
23
|
+
* reflows at 320px rather than widening the page.
|
|
7
24
|
*/
|
|
8
|
-
export declare function TabStrip({ className, children, ...props }: TabStripProps): import("react").JSX.Element;
|
|
25
|
+
export declare function TabStrip({ className, children, label, actions, ...props }: TabStripProps): import("react").JSX.Element;
|
|
9
26
|
/** `dirty` = unsaved draft; `saving` = autosave in flight; `error` = save failed. */
|
|
10
27
|
export type TabState = 'idle' | 'dirty' | 'saving' | 'error';
|
|
11
28
|
export interface TabProps {
|
|
29
|
+
/** The tab's element id, which its {@link TabPanel} is labelled by. */
|
|
30
|
+
id: string;
|
|
12
31
|
label: string;
|
|
32
|
+
/** The id of the {@link TabPanel} this tab shows, when it is the active one. */
|
|
33
|
+
controls?: string;
|
|
13
34
|
active?: boolean;
|
|
14
35
|
state?: TabState;
|
|
15
36
|
onSelect?: () => void;
|
|
37
|
+
/** Makes the tab closable: by the × beside it, or Delete while it has focus. */
|
|
16
38
|
onClose?: () => void;
|
|
17
39
|
className?: string;
|
|
40
|
+
/** Set by {@link TabStrip} on the first tab when none is active. */
|
|
41
|
+
tabStop?: boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* One tab. `role="tab"` sits on the button itself, so the tab is a single
|
|
45
|
+
* interactive element; the close × beside it is a pointer convenience only —
|
|
46
|
+
* hidden from assistive technology and out of the Tab order — and Delete on the
|
|
47
|
+
* focused tab is its keyboard equivalent, announced through `aria-keyshortcuts`.
|
|
48
|
+
*
|
|
49
|
+
* The active tab lifts onto the surface (`bg-surface-elevated` + `-mb-px`, so
|
|
50
|
+
* its base dissolves into the content plane below), and a non-idle tab shows
|
|
51
|
+
* the autosave dot and its name says the same thing in words, since a dot alone is
|
|
52
|
+
* colour carrying meaning (WCAG 1.4.1).
|
|
53
|
+
*/
|
|
54
|
+
export declare function Tab({ id, label, controls, active, state, onSelect, onClose, className, tabStop, }: TabProps): import("react").JSX.Element;
|
|
55
|
+
export interface TabPanelProps extends ComponentPropsWithoutRef<'div'> {
|
|
56
|
+
id: string;
|
|
57
|
+
/** The id of the {@link Tab} that shows this panel. */
|
|
58
|
+
labelledBy?: string;
|
|
18
59
|
}
|
|
19
60
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* a non-idle tab shows the autosave dot: it breathes while `saving`, turns
|
|
23
|
-
* `danger` on `error`. The one place the chrome gets loud, on purpose.
|
|
61
|
+
* The region a tab shows. Focusable, as the pattern asks, so a keyboard user
|
|
62
|
+
* can reach a panel whose content has nothing focusable of its own.
|
|
24
63
|
*/
|
|
25
|
-
export declare function
|
|
64
|
+
export declare function TabPanel({ labelledBy, className, ...props }: TabPanelProps): import("react").JSX.Element;
|
|
26
65
|
export type TabAddButtonProps = ComponentPropsWithoutRef<'button'>;
|
|
27
|
-
/** The "+" that opens a new tab. */
|
|
66
|
+
/** The "+" that opens a new tab. Pass it as {@link TabStrip}'s `actions`. */
|
|
28
67
|
export declare function TabAddButton({ className, ...props }: TabAddButtonProps): import("react").JSX.Element;
|
|
29
68
|
//# sourceMappingURL=tab-strip.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tab-strip.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/tab-strip/tab-strip.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"tab-strip.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/tab-strip/tab-strip.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,wBAAwB,EAI7B,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAKf,MAAM,WAAW,aAAc,SAAQ,IAAI,CACzC,wBAAwB,CAAC,KAAK,CAAC,EAC/B,UAAU,CACX;IACC,kCAAkC;IAClC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,sFAAsF;IACtF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAuBD;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,EACvB,SAAS,EACT,QAAQ,EACR,KAAK,EACL,OAAO,EACP,GAAG,KAAK,EACT,EAAE,aAAa,+BAmCf;AAED,qFAAqF;AACrF,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE7D,MAAM,WAAW,QAAQ;IACvB,uEAAuE;IACvE,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oEAAoE;IACpE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,GAAG,CAAC,EAClB,EAAE,EACF,KAAK,EACL,QAAQ,EACR,MAAc,EACd,KAAc,EACd,QAAQ,EACR,OAAO,EACP,SAAS,EACT,OAAgB,GACjB,EAAE,QAAQ,+BAgFV;AAED,MAAM,WAAW,aAAc,SAAQ,wBAAwB,CAAC,KAAK,CAAC;IACpE,EAAE,EAAE,MAAM,CAAC;IACX,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,aAAa,+BAY1E;AAED,MAAM,MAAM,iBAAiB,GAAG,wBAAwB,CAAC,QAAQ,CAAC,CAAC;AAEnE,6EAA6E;AAC7E,wBAAgB,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,iBAAiB,+BAkBtE"}
|
|
@@ -2,67 +2,158 @@
|
|
|
2
2
|
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
3
3
|
import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
|
|
4
4
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { Children, cloneElement, isValidElement } from 'react';
|
|
5
6
|
import { useT } from '../../../i18n/index.js';
|
|
6
7
|
import { cn } from '../../utils/cn.js';
|
|
7
8
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* Arrow Left/Right (wrapping), Home and End move focus to a sibling tab in the
|
|
10
|
+
* same tablist. Each tab handles its own keys, so the tablist stays a plain
|
|
11
|
+
* container and the keyboard model holds for a Tab rendered anywhere.
|
|
12
|
+
*/ function moveFocus(event) {
|
|
13
|
+
var _all_to;
|
|
14
|
+
const list = event.currentTarget.closest('[role="tablist"]');
|
|
15
|
+
if (!list) return false;
|
|
16
|
+
const all = [
|
|
17
|
+
...list.querySelectorAll('[role="tab"]')
|
|
18
|
+
];
|
|
19
|
+
const from = all.indexOf(event.currentTarget);
|
|
20
|
+
const to = {
|
|
21
|
+
ArrowRight: (from + 1) % all.length,
|
|
22
|
+
ArrowLeft: (from - 1 + all.length) % all.length,
|
|
23
|
+
Home: 0,
|
|
24
|
+
End: all.length - 1
|
|
25
|
+
}[event.key];
|
|
26
|
+
if (to === undefined) return false;
|
|
27
|
+
(_all_to = all[to]) == null ? void 0 : _all_to.focus();
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The workspace tab strip, on the WAI-ARIA tabs pattern: one Tab stop for the
|
|
32
|
+
* whole list, Arrow Left/Right (wrapping), Home and End move between tabs, and
|
|
33
|
+
* Enter or Space activates the focused one — activation is manual, because a
|
|
34
|
+
* tab's body is a whole screen and rendering every one an arrow passes over is
|
|
35
|
+
* work nobody asked for. Delete closes a closable tab (see {@link Tab}).
|
|
36
|
+
*
|
|
37
|
+
* Presentational: the open set, the order and the active tab come from the
|
|
38
|
+
* caller. Each tab controls one {@link TabPanel}, which the caller renders.
|
|
39
|
+
* Below the width of its tabs the list scrolls on its own, so the strip
|
|
40
|
+
* reflows at 320px rather than widening the page.
|
|
11
41
|
*/ export function TabStrip(_0) {
|
|
12
|
-
let { className, children } = _0, props = _object_without_properties_loose(_0, [
|
|
42
|
+
let { className, children, label, actions } = _0, props = _object_without_properties_loose(_0, [
|
|
13
43
|
"className",
|
|
14
|
-
"children"
|
|
44
|
+
"children",
|
|
45
|
+
"label",
|
|
46
|
+
"actions"
|
|
15
47
|
]);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
48
|
+
const t = useT();
|
|
49
|
+
const tabs = Children.toArray(children);
|
|
50
|
+
// Roving tabindex: the active tab is the list's Tab stop, or the first tab
|
|
51
|
+
// when none is active (a dead link shows no tab as its own).
|
|
52
|
+
const anyActive = tabs.some((tab)=>/*#__PURE__*/ isValidElement(tab) && tab.props.active === true);
|
|
53
|
+
const items = anyActive ? tabs : tabs.map((tab, index)=>index === 0 && /*#__PURE__*/ isValidElement(tab) ? /*#__PURE__*/ cloneElement(tab, {
|
|
54
|
+
tabStop: true
|
|
55
|
+
}) : tab);
|
|
56
|
+
return /*#__PURE__*/ _jsxs("div", _extends({
|
|
57
|
+
className: cn('min-w-0 flex w-full items-end gap-3xs border-b border-border bg-surface px-2xs', className)
|
|
19
58
|
}, props, {
|
|
20
|
-
children:
|
|
59
|
+
children: [
|
|
60
|
+
/*#__PURE__*/ _jsx("div", {
|
|
61
|
+
role: "tablist",
|
|
62
|
+
"aria-label": label != null ? label : t('tabs.list'),
|
|
63
|
+
"aria-orientation": "horizontal",
|
|
64
|
+
className: "min-w-0 flex flex-1 items-end gap-3xs overflow-x-auto",
|
|
65
|
+
children: items
|
|
66
|
+
}),
|
|
67
|
+
actions
|
|
68
|
+
]
|
|
21
69
|
}));
|
|
22
70
|
}
|
|
23
71
|
/**
|
|
24
|
-
* One tab.
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
|
|
72
|
+
* One tab. `role="tab"` sits on the button itself, so the tab is a single
|
|
73
|
+
* interactive element; the close × beside it is a pointer convenience only —
|
|
74
|
+
* hidden from assistive technology and out of the Tab order — and Delete on the
|
|
75
|
+
* focused tab is its keyboard equivalent, announced through `aria-keyshortcuts`.
|
|
76
|
+
*
|
|
77
|
+
* The active tab lifts onto the surface (`bg-surface-elevated` + `-mb-px`, so
|
|
78
|
+
* its base dissolves into the content plane below), and a non-idle tab shows
|
|
79
|
+
* the autosave dot and its name says the same thing in words, since a dot alone is
|
|
80
|
+
* colour carrying meaning (WCAG 1.4.1).
|
|
81
|
+
*/ export function Tab({ id, label, controls, active = false, state = 'idle', onSelect, onClose, className, tabStop = active }) {
|
|
29
82
|
const t = useT();
|
|
30
83
|
return /*#__PURE__*/ _jsxs("div", {
|
|
31
|
-
role: "
|
|
32
|
-
|
|
33
|
-
className: cn('group relative flex items-center gap-2xs rounded-t-md px-s py-2xs text-step-sm', 'transition duration-200 ease-smooth', active ? '-mb-px bg-surface-elevated font-medium text-content shadow-edge' : 'text-content-muted hover:bg-surface-elevated/60', state === 'error' && 'bg-danger-subtle text-danger', className),
|
|
84
|
+
role: "none",
|
|
85
|
+
className: cn('group relative flex shrink-0 items-center rounded-t-md text-step-sm', 'transition duration-200 ease-smooth', active ? '-mb-px bg-surface-elevated font-medium text-content shadow-edge' : 'text-content-muted hover:bg-surface-elevated/60', state === 'error' && 'bg-danger-subtle text-danger', className),
|
|
34
86
|
children: [
|
|
35
87
|
active && /*#__PURE__*/ _jsx("span", {
|
|
36
88
|
"aria-hidden": "true",
|
|
37
|
-
className: "inset-x-0 top-0
|
|
89
|
+
className: "inset-x-0 top-0 h-0.5 pointer-events-none absolute rounded-full bg-accent"
|
|
38
90
|
}),
|
|
39
|
-
/*#__PURE__*/
|
|
91
|
+
/*#__PURE__*/ _jsxs("button", {
|
|
40
92
|
type: "button",
|
|
93
|
+
role: "tab",
|
|
94
|
+
id: id,
|
|
95
|
+
"aria-selected": active,
|
|
96
|
+
"aria-controls": active ? controls : undefined,
|
|
97
|
+
"aria-keyshortcuts": onClose ? 'Delete' : undefined,
|
|
98
|
+
tabIndex: tabStop ? 0 : -1,
|
|
41
99
|
onClick: onSelect,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
100
|
+
"aria-label": state === 'idle' ? undefined : t('tabs.withState', {
|
|
101
|
+
label,
|
|
102
|
+
state: t(`tabs.${state}`)
|
|
103
|
+
}),
|
|
104
|
+
onKeyDown: (event)=>{
|
|
105
|
+
if (event.key === 'Delete' && onClose) {
|
|
106
|
+
event.preventDefault();
|
|
107
|
+
onClose();
|
|
108
|
+
} else if (moveFocus(event)) {
|
|
109
|
+
event.preventDefault();
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
className: cn('max-w-48 flex min-h-(--target-min) items-center gap-2xs rounded-t-md py-2xs pl-s focus-ring', onClose ? 'pr-3xs' : 'pr-s'),
|
|
113
|
+
children: [
|
|
114
|
+
/*#__PURE__*/ _jsx("span", {
|
|
115
|
+
className: "truncate",
|
|
116
|
+
children: label
|
|
117
|
+
}),
|
|
118
|
+
state !== 'idle' && /*#__PURE__*/ _jsx("span", {
|
|
119
|
+
"data-testid": "tab-indicator",
|
|
120
|
+
"aria-hidden": "true",
|
|
121
|
+
className: cn('size-1.5 shrink-0 rounded-full', state === 'error' ? 'bg-danger' : 'bg-accent', state === 'saving' && 'animate-pulse motion-reduce:animate-none')
|
|
122
|
+
})
|
|
123
|
+
]
|
|
49
124
|
}),
|
|
50
125
|
onClose && /*#__PURE__*/ _jsx("button", {
|
|
51
126
|
type: "button",
|
|
52
|
-
"aria-
|
|
127
|
+
"aria-hidden": "true",
|
|
128
|
+
tabIndex: -1,
|
|
129
|
+
title: t('tabs.close', {
|
|
53
130
|
label
|
|
54
131
|
}),
|
|
55
132
|
onClick: onClose,
|
|
56
|
-
className: cn('rounded
|
|
57
|
-
children:
|
|
58
|
-
"aria-hidden": "true",
|
|
59
|
-
children: "×"
|
|
60
|
-
})
|
|
133
|
+
className: cn('rounded mr-3xs flex min-h-(--target-min) min-w-(--target-min) items-center justify-center text-content-muted opacity-0 transition', 'group-focus-within:opacity-100 group-hover:opacity-100 hover:bg-surface hover:text-content', active && 'opacity-100'),
|
|
134
|
+
children: "×"
|
|
61
135
|
})
|
|
62
136
|
]
|
|
63
137
|
});
|
|
64
138
|
}
|
|
65
|
-
/**
|
|
139
|
+
/**
|
|
140
|
+
* The region a tab shows. Focusable, as the pattern asks, so a keyboard user
|
|
141
|
+
* can reach a panel whose content has nothing focusable of its own.
|
|
142
|
+
*/ export function TabPanel(_0) {
|
|
143
|
+
let { labelledBy, className } = _0, props = _object_without_properties_loose(_0, [
|
|
144
|
+
"labelledBy",
|
|
145
|
+
"className"
|
|
146
|
+
]);
|
|
147
|
+
return /*#__PURE__*/ _jsx("div", _extends({
|
|
148
|
+
role: "tabpanel",
|
|
149
|
+
// The tabs pattern makes the panel itself a Tab stop.
|
|
150
|
+
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
|
|
151
|
+
tabIndex: 0,
|
|
152
|
+
"aria-labelledby": labelledBy,
|
|
153
|
+
className: cn('focus-ring', className)
|
|
154
|
+
}, props));
|
|
155
|
+
}
|
|
156
|
+
/** The "+" that opens a new tab. Pass it as {@link TabStrip}'s `actions`. */ export function TabAddButton(_0) {
|
|
66
157
|
let { className } = _0, props = _object_without_properties_loose(_0, [
|
|
67
158
|
"className"
|
|
68
159
|
]);
|
|
@@ -70,7 +161,7 @@ import { cn } from '../../utils/cn.js';
|
|
|
70
161
|
return /*#__PURE__*/ _jsx("button", _extends({
|
|
71
162
|
type: "button",
|
|
72
163
|
"aria-label": t('tabs.new'),
|
|
73
|
-
className: cn('mb-3xs shrink-0 rounded-md px-2xs
|
|
164
|
+
className: cn('mb-3xs flex min-h-(--target-min) min-w-(--target-min) shrink-0 items-center justify-center rounded-md px-2xs text-step-sm text-content-muted', 'transition hover:bg-surface-elevated hover:text-content', 'focus-ring', className)
|
|
74
165
|
}, props, {
|
|
75
166
|
children: /*#__PURE__*/ _jsx("span", {
|
|
76
167
|
"aria-hidden": "true",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/ui/molecules/tab-strip/tab-strip.tsx"],"sourcesContent":["'use client';\n\nimport type { ComponentPropsWithoutRef } from 'react';\n\nimport { useT } from '../../../i18n/index.js';\nimport { cn } from '../../utils/cn.js';\n\nexport type TabStripProps = ComponentPropsWithoutRef<'div'>;\n\n/**\n * The workspace tab strip: a horizontally scrolling row of {@link Tab}s sitting\n * on the workspace surface. Presentational only — the open set, order, and\n * active tab come from the caller (the tabs store lives in the shell).\n */\nexport function TabStrip({ className, children, ...props }: TabStripProps) {\n return (\n <div\n role=\"tablist\"\n className={cn(\n 'flex items-end gap-3xs overflow-x-auto border-b border-border bg-surface px-2xs',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n );\n}\n\n/** `dirty` = unsaved draft; `saving` = autosave in flight; `error` = save failed. */\nexport type TabState = 'idle' | 'dirty' | 'saving' | 'error';\n\nexport interface TabProps {\n label: string;\n active?: boolean;\n state?: TabState;\n onSelect?: () => void;\n onClose?: () => void;\n className?: string;\n}\n\n/**\n * One tab. The active tab lifts onto the surface (`bg-surface-elevated` +\n * `-mb-px` so its base dissolves into the content plane below — the seam), and\n * a non-idle tab shows the autosave dot: it breathes while `saving`, turns\n * `danger` on `error`. The one place the chrome gets loud, on purpose.\n */\nexport function Tab({\n label,\n active = false,\n state = 'idle',\n onSelect,\n onClose,\n className,\n}: TabProps) {\n const t = useT();\n\n return (\n <div\n role=\"tab\"\n aria-selected={active}\n className={cn(\n 'group relative flex items-center gap-2xs rounded-t-md px-s py-2xs text-step-sm',\n 'transition duration-200 ease-smooth',\n active\n ? '-mb-px bg-surface-elevated font-medium text-content shadow-edge'\n : 'text-content-muted hover:bg-surface-elevated/60',\n state === 'error' && 'bg-danger-subtle text-danger',\n className,\n )}\n >\n {active && (\n <span\n aria-hidden=\"true\"\n className=\"inset-x-0 top-0 absolute h-[2px] rounded-full bg-accent\"\n />\n )}\n <button\n type=\"button\"\n onClick={onSelect}\n className=\"max-w-[12rem] truncate focus-ring\"\n >\n {label}\n </button>\n {state !== 'idle' && (\n <span\n data-testid=\"tab-indicator\"\n aria-hidden=\"true\"\n className={cn(\n 'size-[6px] shrink-0 rounded-full',\n state === 'error' ? 'bg-danger' : 'bg-accent',\n state === 'saving' && 'animate-pulse motion-reduce:animate-none',\n )}\n />\n )}\n {onClose && (\n <button\n type=\"button\"\n aria-label={t('tabs.close', { label })}\n onClick={onClose}\n className={cn(\n 'rounded ml-2xs p-3xs text-content-muted opacity-0 focus-ring transition',\n 'group-hover:opacity-100 hover:bg-surface hover:text-content focus:opacity-100',\n active && 'opacity-100',\n )}\n >\n <span aria-hidden=\"true\">×</span>\n </button>\n )}\n </div>\n );\n}\n\nexport type TabAddButtonProps = ComponentPropsWithoutRef<'button'>;\n\n/** The \"+\" that opens a new tab. */\nexport function TabAddButton({ className, ...props }: TabAddButtonProps) {\n const t = useT();\n\n return (\n <button\n type=\"button\"\n aria-label={t('tabs.new')}\n className={cn(\n 'mb-3xs shrink-0 rounded-md px-2xs py-3xs text-step-sm text-content-muted',\n 'transition hover:bg-surface-elevated hover:text-content',\n 'focus-ring',\n className,\n )}\n {...props}\n >\n <span aria-hidden=\"true\">+</span>\n </button>\n );\n}\n"],"names":["useT","cn","TabStrip","className","children","props","div","role","Tab","label","active","state","onSelect","onClose","t","aria-selected","span","aria-hidden","button","type","onClick","data-testid","aria-label","TabAddButton"],"mappings":"AAAA;;;;AAIA,SAASA,IAAI,QAAQ,yBAAyB;AAC9C,SAASC,EAAE,QAAQ,oBAAoB;AAIvC;;;;CAIC,GACD,OAAO,SAASC,SAAS,EAAgD;QAAhD,EAAEC,SAAS,EAAEC,QAAQ,EAA2B,OAAtBC;;;;IACjD,qBACE,KAACC;QACCC,MAAK;QACLJ,WAAWF,GACT,mFACAE;OAEEE;kBAEHD;;AAGP;AAcA;;;;;CAKC,GACD,OAAO,SAASI,IAAI,EAClBC,KAAK,EACLC,SAAS,KAAK,EACdC,QAAQ,MAAM,EACdC,QAAQ,EACRC,OAAO,EACPV,SAAS,EACA;IACT,MAAMW,IAAId;IAEV,qBACE,MAACM;QACCC,MAAK;QACLQ,iBAAeL;QACfP,WAAWF,GACT,kFACA,uCACAS,SACI,oEACA,mDACJC,UAAU,WAAW,gCACrBR;;YAGDO,wBACC,KAACM;gBACCC,eAAY;gBACZd,WAAU;;0BAGd,KAACe;gBACCC,MAAK;gBACLC,SAASR;gBACTT,WAAU;0BAETM;;YAEFE,UAAU,wBACT,KAACK;gBACCK,eAAY;gBACZJ,eAAY;gBACZd,WAAWF,GACT,oCACAU,UAAU,UAAU,cAAc,aAClCA,UAAU,YAAY;;YAI3BE,yBACC,KAACK;gBACCC,MAAK;gBACLG,cAAYR,EAAE,cAAc;oBAAEL;gBAAM;gBACpCW,SAASP;gBACTV,WAAWF,GACT,2EACA,iFACAS,UAAU;0BAGZ,cAAA,KAACM;oBAAKC,eAAY;8BAAO;;;;;AAKnC;AAIA,kCAAkC,GAClC,OAAO,SAASM,aAAa,EAA0C;QAA1C,EAAEpB,SAAS,EAA+B,OAA1BE;;;IAC3C,MAAMS,IAAId;IAEV,qBACE,KAACkB;QACCC,MAAK;QACLG,cAAYR,EAAE;QACdX,WAAWF,GACT,4EACA,2DACA,cACAE;OAEEE;kBAEJ,cAAA,KAACW;YAAKC,eAAY;sBAAO;;;AAG/B"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/ui/molecules/tab-strip/tab-strip.tsx"],"sourcesContent":["'use client';\n\nimport {\n Children,\n cloneElement,\n type ComponentPropsWithoutRef,\n isValidElement,\n type KeyboardEvent,\n type ReactElement,\n type ReactNode,\n} from 'react';\n\nimport { useT } from '../../../i18n/index.js';\nimport { cn } from '../../utils/cn.js';\n\nexport interface TabStripProps extends Omit<\n ComponentPropsWithoutRef<'div'>,\n 'children'\n> {\n /** The {@link Tab}s, in order. */\n children?: ReactNode;\n /** The tablist's accessible name; the controls catalog's `tabs.list` when omitted. */\n label?: string;\n /**\n * What sits after the tabs — a {@link TabAddButton}. It is outside the\n * tablist, because a tablist may own nothing but tabs.\n */\n actions?: ReactNode;\n}\n\n/**\n * Arrow Left/Right (wrapping), Home and End move focus to a sibling tab in the\n * same tablist. Each tab handles its own keys, so the tablist stays a plain\n * container and the keyboard model holds for a Tab rendered anywhere.\n */\nfunction moveFocus(event: KeyboardEvent<HTMLButtonElement>): boolean {\n const list = event.currentTarget.closest('[role=\"tablist\"]');\n if (!list) return false;\n const all = [...list.querySelectorAll<HTMLElement>('[role=\"tab\"]')];\n const from = all.indexOf(event.currentTarget);\n const to = {\n ArrowRight: (from + 1) % all.length,\n ArrowLeft: (from - 1 + all.length) % all.length,\n Home: 0,\n End: all.length - 1,\n }[event.key];\n if (to === undefined) return false;\n all[to]?.focus();\n return true;\n}\n\n/**\n * The workspace tab strip, on the WAI-ARIA tabs pattern: one Tab stop for the\n * whole list, Arrow Left/Right (wrapping), Home and End move between tabs, and\n * Enter or Space activates the focused one — activation is manual, because a\n * tab's body is a whole screen and rendering every one an arrow passes over is\n * work nobody asked for. Delete closes a closable tab (see {@link Tab}).\n *\n * Presentational: the open set, the order and the active tab come from the\n * caller. Each tab controls one {@link TabPanel}, which the caller renders.\n * Below the width of its tabs the list scrolls on its own, so the strip\n * reflows at 320px rather than widening the page.\n */\nexport function TabStrip({\n className,\n children,\n label,\n actions,\n ...props\n}: TabStripProps) {\n const t = useT();\n const tabs = Children.toArray(children);\n // Roving tabindex: the active tab is the list's Tab stop, or the first tab\n // when none is active (a dead link shows no tab as its own).\n const anyActive = tabs.some(\n tab => isValidElement<TabProps>(tab) && tab.props.active === true,\n );\n const items = anyActive\n ? tabs\n : tabs.map((tab, index) =>\n index === 0 && isValidElement<TabProps>(tab)\n ? cloneElement(tab as ReactElement<TabProps>, { tabStop: true })\n : tab,\n );\n\n return (\n <div\n className={cn(\n 'min-w-0 flex w-full items-end gap-3xs border-b border-border bg-surface px-2xs',\n className,\n )}\n {...props}\n >\n <div\n role=\"tablist\"\n aria-label={label ?? t('tabs.list')}\n aria-orientation=\"horizontal\"\n className=\"min-w-0 flex flex-1 items-end gap-3xs overflow-x-auto\"\n >\n {items}\n </div>\n {actions}\n </div>\n );\n}\n\n/** `dirty` = unsaved draft; `saving` = autosave in flight; `error` = save failed. */\nexport type TabState = 'idle' | 'dirty' | 'saving' | 'error';\n\nexport interface TabProps {\n /** The tab's element id, which its {@link TabPanel} is labelled by. */\n id: string;\n label: string;\n /** The id of the {@link TabPanel} this tab shows, when it is the active one. */\n controls?: string;\n active?: boolean;\n state?: TabState;\n onSelect?: () => void;\n /** Makes the tab closable: by the × beside it, or Delete while it has focus. */\n onClose?: () => void;\n className?: string;\n /** Set by {@link TabStrip} on the first tab when none is active. */\n tabStop?: boolean;\n}\n\n/**\n * One tab. `role=\"tab\"` sits on the button itself, so the tab is a single\n * interactive element; the close × beside it is a pointer convenience only —\n * hidden from assistive technology and out of the Tab order — and Delete on the\n * focused tab is its keyboard equivalent, announced through `aria-keyshortcuts`.\n *\n * The active tab lifts onto the surface (`bg-surface-elevated` + `-mb-px`, so\n * its base dissolves into the content plane below), and a non-idle tab shows\n * the autosave dot and its name says the same thing in words, since a dot alone is\n * colour carrying meaning (WCAG 1.4.1).\n */\nexport function Tab({\n id,\n label,\n controls,\n active = false,\n state = 'idle',\n onSelect,\n onClose,\n className,\n tabStop = active,\n}: TabProps) {\n const t = useT();\n\n return (\n <div\n role=\"none\"\n className={cn(\n 'group relative flex shrink-0 items-center rounded-t-md text-step-sm',\n 'transition duration-200 ease-smooth',\n active\n ? '-mb-px bg-surface-elevated font-medium text-content shadow-edge'\n : 'text-content-muted hover:bg-surface-elevated/60',\n state === 'error' && 'bg-danger-subtle text-danger',\n className,\n )}\n >\n {active && (\n <span\n aria-hidden=\"true\"\n className=\"inset-x-0 top-0 h-0.5 pointer-events-none absolute rounded-full bg-accent\"\n />\n )}\n <button\n type=\"button\"\n role=\"tab\"\n id={id}\n aria-selected={active}\n aria-controls={active ? controls : undefined}\n aria-keyshortcuts={onClose ? 'Delete' : undefined}\n tabIndex={tabStop ? 0 : -1}\n onClick={onSelect}\n aria-label={\n state === 'idle'\n ? undefined\n : t('tabs.withState', { label, state: t(`tabs.${state}`) })\n }\n onKeyDown={event => {\n if (event.key === 'Delete' && onClose) {\n event.preventDefault();\n onClose();\n } else if (moveFocus(event)) {\n event.preventDefault();\n }\n }}\n className={cn(\n 'max-w-48 flex min-h-(--target-min) items-center gap-2xs rounded-t-md py-2xs pl-s focus-ring',\n onClose ? 'pr-3xs' : 'pr-s',\n )}\n >\n <span className=\"truncate\">{label}</span>\n {state !== 'idle' && (\n <span\n data-testid=\"tab-indicator\"\n aria-hidden=\"true\"\n className={cn(\n 'size-1.5 shrink-0 rounded-full',\n state === 'error' ? 'bg-danger' : 'bg-accent',\n state === 'saving' && 'animate-pulse motion-reduce:animate-none',\n )}\n />\n )}\n </button>\n {onClose && (\n <button\n type=\"button\"\n aria-hidden=\"true\"\n tabIndex={-1}\n title={t('tabs.close', { label })}\n onClick={onClose}\n className={cn(\n 'rounded mr-3xs flex min-h-(--target-min) min-w-(--target-min) items-center justify-center text-content-muted opacity-0 transition',\n 'group-focus-within:opacity-100 group-hover:opacity-100 hover:bg-surface hover:text-content',\n active && 'opacity-100',\n )}\n >\n ×\n </button>\n )}\n </div>\n );\n}\n\nexport interface TabPanelProps extends ComponentPropsWithoutRef<'div'> {\n id: string;\n /** The id of the {@link Tab} that shows this panel. */\n labelledBy?: string;\n}\n\n/**\n * The region a tab shows. Focusable, as the pattern asks, so a keyboard user\n * can reach a panel whose content has nothing focusable of its own.\n */\nexport function TabPanel({ labelledBy, className, ...props }: TabPanelProps) {\n return (\n <div\n role=\"tabpanel\"\n // The tabs pattern makes the panel itself a Tab stop.\n // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex\n tabIndex={0}\n aria-labelledby={labelledBy}\n className={cn('focus-ring', className)}\n {...props}\n />\n );\n}\n\nexport type TabAddButtonProps = ComponentPropsWithoutRef<'button'>;\n\n/** The \"+\" that opens a new tab. Pass it as {@link TabStrip}'s `actions`. */\nexport function TabAddButton({ className, ...props }: TabAddButtonProps) {\n const t = useT();\n\n return (\n <button\n type=\"button\"\n aria-label={t('tabs.new')}\n className={cn(\n 'mb-3xs flex min-h-(--target-min) min-w-(--target-min) shrink-0 items-center justify-center rounded-md px-2xs text-step-sm text-content-muted',\n 'transition hover:bg-surface-elevated hover:text-content',\n 'focus-ring',\n className,\n )}\n {...props}\n >\n <span aria-hidden=\"true\">+</span>\n </button>\n );\n}\n"],"names":["Children","cloneElement","isValidElement","useT","cn","moveFocus","event","all","list","currentTarget","closest","querySelectorAll","from","indexOf","to","ArrowRight","length","ArrowLeft","Home","End","key","undefined","focus","TabStrip","className","children","label","actions","props","t","tabs","toArray","anyActive","some","tab","active","items","map","index","tabStop","div","role","aria-label","aria-orientation","Tab","id","controls","state","onSelect","onClose","span","aria-hidden","button","type","aria-selected","aria-controls","aria-keyshortcuts","tabIndex","onClick","onKeyDown","preventDefault","data-testid","title","TabPanel","labelledBy","aria-labelledby","TabAddButton"],"mappings":"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"}
|
|
@@ -6,8 +6,10 @@ export interface TableToolbarProps {
|
|
|
6
6
|
end?: ReactNode;
|
|
7
7
|
/** Expanded panel rendered below the bar (filters, sorting). */
|
|
8
8
|
panel?: ReactNode;
|
|
9
|
+
/** The panel's id, for the toggle that opens it to name in `aria-controls`. */
|
|
10
|
+
panelId?: string;
|
|
9
11
|
className?: string;
|
|
10
12
|
}
|
|
11
13
|
/** Bar above a table: actions on one line, an optional expanded panel below. */
|
|
12
|
-
export declare function TableToolbar({ start, end, panel, className, }: TableToolbarProps): import("react").JSX.Element;
|
|
14
|
+
export declare function TableToolbar({ start, end, panel, panelId, className, }: TableToolbarProps): import("react").JSX.Element;
|
|
13
15
|
//# sourceMappingURL=table-toolbar.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-toolbar.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/table-toolbar/table-toolbar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC,MAAM,WAAW,iBAAiB;IAChC,8DAA8D;IAC9D,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,mEAAmE;IACnE,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,gEAAgE;IAChE,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,GAAG,EACH,KAAK,EACL,SAAS,GACV,EAAE,iBAAiB,+
|
|
1
|
+
{"version":3,"file":"table-toolbar.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/table-toolbar/table-toolbar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC,MAAM,WAAW,iBAAiB;IAChC,8DAA8D;IAC9D,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,mEAAmE;IACnE,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,gEAAgE;IAChE,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,GAAG,EACH,KAAK,EACL,OAAO,EACP,SAAS,GACV,EAAE,iBAAiB,+BAmBnB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from '../../utils/cn.js';
|
|
3
|
-
/** Bar above a table: actions on one line, an optional expanded panel below. */ export function TableToolbar({ start, end, panel, className }) {
|
|
3
|
+
/** Bar above a table: actions on one line, an optional expanded panel below. */ export function TableToolbar({ start, end, panel, panelId, className }) {
|
|
4
4
|
return /*#__PURE__*/ _jsxs("div", {
|
|
5
5
|
className: cn('flex flex-col gap-2xs', className),
|
|
6
6
|
children: [
|
|
@@ -8,7 +8,7 @@ import { cn } from '../../utils/cn.js';
|
|
|
8
8
|
className: "flex flex-wrap items-center justify-between gap-2xs",
|
|
9
9
|
children: [
|
|
10
10
|
/*#__PURE__*/ _jsx("div", {
|
|
11
|
-
className: "flex flex-wrap items-center gap-2xs",
|
|
11
|
+
className: "min-w-0 flex flex-1 flex-wrap items-center gap-2xs",
|
|
12
12
|
children: start
|
|
13
13
|
}),
|
|
14
14
|
/*#__PURE__*/ _jsx("div", {
|
|
@@ -18,6 +18,7 @@ import { cn } from '../../utils/cn.js';
|
|
|
18
18
|
]
|
|
19
19
|
}),
|
|
20
20
|
panel && /*#__PURE__*/ _jsx("div", {
|
|
21
|
+
id: panelId,
|
|
21
22
|
className: "rounded-xl border border-border bg-surface p-s",
|
|
22
23
|
children: panel
|
|
23
24
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/ui/molecules/table-toolbar/table-toolbar.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport { cn } from '../../utils/cn.js';\n\nexport interface TableToolbarProps {\n /** Actions aligned to the start — titles, primary actions. */\n start?: ReactNode;\n /** Actions aligned to the end — column settings, panel toggles. */\n end?: ReactNode;\n /** Expanded panel rendered below the bar (filters, sorting). */\n panel?: ReactNode;\n className?: string;\n}\n\n/** Bar above a table: actions on one line, an optional expanded panel below. */\nexport function TableToolbar({\n start,\n end,\n panel,\n className,\n}: TableToolbarProps) {\n return (\n <div className={cn('flex flex-col gap-2xs', className)}>\n <div className=\"flex flex-wrap items-center justify-between gap-2xs\">\n <div className=\"flex flex-wrap items-center gap-2xs\"
|
|
1
|
+
{"version":3,"sources":["../../../../src/ui/molecules/table-toolbar/table-toolbar.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport { cn } from '../../utils/cn.js';\n\nexport interface TableToolbarProps {\n /** Actions aligned to the start — titles, primary actions. */\n start?: ReactNode;\n /** Actions aligned to the end — column settings, panel toggles. */\n end?: ReactNode;\n /** Expanded panel rendered below the bar (filters, sorting). */\n panel?: ReactNode;\n /** The panel's id, for the toggle that opens it to name in `aria-controls`. */\n panelId?: string;\n className?: string;\n}\n\n/** Bar above a table: actions on one line, an optional expanded panel below. */\nexport function TableToolbar({\n start,\n end,\n panel,\n panelId,\n className,\n}: TableToolbarProps) {\n return (\n <div className={cn('flex flex-col gap-2xs', className)}>\n <div className=\"flex flex-wrap items-center justify-between gap-2xs\">\n <div className=\"min-w-0 flex flex-1 flex-wrap items-center gap-2xs\">\n {start}\n </div>\n <div className=\"flex flex-wrap items-center gap-2xs\">{end}</div>\n </div>\n {panel && (\n <div\n id={panelId}\n className=\"rounded-xl border border-border bg-surface p-s\"\n >\n {panel}\n </div>\n )}\n </div>\n );\n}\n"],"names":["cn","TableToolbar","start","end","panel","panelId","className","div","id"],"mappings":";AAEA,SAASA,EAAE,QAAQ,oBAAoB;AAcvC,8EAA8E,GAC9E,OAAO,SAASC,aAAa,EAC3BC,KAAK,EACLC,GAAG,EACHC,KAAK,EACLC,OAAO,EACPC,SAAS,EACS;IAClB,qBACE,MAACC;QAAID,WAAWN,GAAG,yBAAyBM;;0BAC1C,MAACC;gBAAID,WAAU;;kCACb,KAACC;wBAAID,WAAU;kCACZJ;;kCAEH,KAACK;wBAAID,WAAU;kCAAuCH;;;;YAEvDC,uBACC,KAACG;gBACCC,IAAIH;gBACJC,WAAU;0BAETF;;;;AAKX"}
|
|
@@ -5,39 +5,83 @@ import { useErrorMessage } from '../../../i18n/index.js';
|
|
|
5
5
|
* `code`, and anything else that reached the user keeps its `message`.
|
|
6
6
|
*/
|
|
7
7
|
export type ToastFailure = Parameters<ReturnType<typeof useErrorMessage>>[0];
|
|
8
|
-
/**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
/**
|
|
9
|
+
* What a toast reports
|
|
10
|
+
* ([ADR 0028](../../../../../../../docs/adr/0028-states-an-organism-must-render.md)):
|
|
11
|
+
* a write that worked, one that can still be taken back, something worth
|
|
12
|
+
* knowing, or a failure. Only a failure interrupts.
|
|
13
|
+
*/
|
|
14
|
+
export type ToastTone = 'success' | 'undo' | 'info' | 'failure';
|
|
15
|
+
/** The one thing a toast offers to do about what it reports. */
|
|
16
|
+
export interface ToastAction {
|
|
17
|
+
/** The button's text, already in the reader's language. */
|
|
18
|
+
readonly label: string;
|
|
19
|
+
readonly onAction: () => void;
|
|
12
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* A toast to show. A failure carries the failure itself, rendered through the
|
|
23
|
+
* same {@link useErrorMessage} a form's error slot uses; every other tone
|
|
24
|
+
* carries a sentence already in the reader's language. An `undo` toast without
|
|
25
|
+
* its Undo would be a success toast, so the type asks for the action.
|
|
26
|
+
*/
|
|
27
|
+
export type ToastInput = {
|
|
28
|
+
readonly tone: 'success' | 'info';
|
|
29
|
+
readonly message: string;
|
|
30
|
+
readonly action?: ToastAction;
|
|
31
|
+
} | {
|
|
32
|
+
readonly tone: 'undo';
|
|
33
|
+
readonly message: string;
|
|
34
|
+
readonly action: ToastAction;
|
|
35
|
+
} | {
|
|
36
|
+
readonly tone: 'failure';
|
|
37
|
+
readonly failure: ToastFailure;
|
|
38
|
+
readonly action?: ToastAction;
|
|
39
|
+
};
|
|
40
|
+
/** One toast waiting in the region, under the id it was shown with. */
|
|
41
|
+
export type Toast = ToastInput & {
|
|
42
|
+
readonly id: number;
|
|
43
|
+
};
|
|
13
44
|
export interface Toasts {
|
|
14
|
-
/** The
|
|
15
|
-
readonly
|
|
16
|
-
/** Shows a
|
|
17
|
-
readonly
|
|
45
|
+
/** The toasts shown, oldest first. */
|
|
46
|
+
readonly toasts: readonly Toast[];
|
|
47
|
+
/** Shows a toast, and answers its id. */
|
|
48
|
+
readonly show: (toast: ToastInput) => number;
|
|
18
49
|
readonly dismiss: (id: number) => void;
|
|
19
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* How long a toast that is neither a failure nor offers an action stays, in
|
|
53
|
+
* milliseconds. A failure stays until it is dismissed: it reports something
|
|
54
|
+
* that already happened, often after the screen that started it was left, and
|
|
55
|
+
* a message that times out is one a slow reader never gets. A toast with an
|
|
56
|
+
* action stays too, for the same reader.
|
|
57
|
+
*/
|
|
58
|
+
export declare const TOAST_TIMEOUT_MS = 8000;
|
|
59
|
+
export interface ToastProviderProps {
|
|
60
|
+
readonly children: ReactNode;
|
|
61
|
+
/** How long a success, undo or info toast stays. */
|
|
62
|
+
readonly timeoutMs?: number;
|
|
63
|
+
}
|
|
20
64
|
/**
|
|
21
65
|
* Holds the toasts one host shows. Mounted once, above everything that can
|
|
22
66
|
* fail asynchronously, with a {@link ToastRegion} somewhere inside it.
|
|
23
67
|
*/
|
|
24
|
-
export declare function ToastProvider({ children }:
|
|
25
|
-
readonly children: ReactNode;
|
|
26
|
-
}): import("react").JSX.Element;
|
|
68
|
+
export declare function ToastProvider({ children, timeoutMs, }: ToastProviderProps): import("react").JSX.Element;
|
|
27
69
|
/**
|
|
28
70
|
* The {@link ToastProvider} above, or `undefined` outside one: a caller with
|
|
29
|
-
* no region to show a
|
|
30
|
-
* vanish.
|
|
71
|
+
* no region to show a toast in keeps what it has to say where it can, rather
|
|
72
|
+
* than having it vanish.
|
|
31
73
|
*/
|
|
32
74
|
export declare const useToasts: () => Toasts | undefined;
|
|
33
75
|
/**
|
|
34
|
-
* Where a host's toasts render
|
|
35
|
-
*
|
|
36
|
-
* asynchronous failure reads exactly as a synchronous one would.
|
|
76
|
+
* Where a host's toasts render, each through {@link Alert}: a failure is
|
|
77
|
+
* `role="alert"` and every other tone `role="status"`.
|
|
37
78
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
79
|
+
* ⚠️ **An empty region takes no room and no clicks.** It stays mounted, so a
|
|
80
|
+
* toast lands in a region that already exists, but at zero size and with
|
|
81
|
+
* `pointer-events: none` — a fixed box that kept its padding once covered two
|
|
82
|
+
* focused links and swallowed clicks (WCAG 2.4.11). While toasts show, the
|
|
83
|
+
* document's bottom scroll padding is the region's height, so a control
|
|
84
|
+
* focused by keyboard scrolls clear of it. F6 moves focus into the region.
|
|
41
85
|
*/
|
|
42
86
|
export declare function ToastRegion(): import("react").JSX.Element | null;
|
|
43
87
|
//# sourceMappingURL=toast-region.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toast-region.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/toast-region/toast-region.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"toast-region.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/toast-region/toast-region.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,SAAS,EAOf,MAAM,OAAO,CAAC;AAEf,OAAO,EAAE,eAAe,EAAQ,MAAM,wBAAwB,CAAC;AAM/D;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE7E;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAEhE,gEAAgE;AAChE,MAAM,WAAW,WAAW;IAC1B,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAClB;IACE,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;CAC9B,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B,CAAC;AAEN,uEAAuE;AACvE,MAAM,MAAM,KAAK,GAAG,UAAU,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzD,MAAM,WAAW,MAAM;IACrB,sCAAsC;IACtC,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IAClC,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,MAAM,CAAC;IAC7C,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,OAAO,CAAC;AAIrC,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,oDAAoD;IACpD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,SAA4B,GAC7B,EAAE,kBAAkB,+BA4CpB;AAED;;;;GAIG;AACH,eAAO,MAAM,SAAS,QAAO,MAAM,GAAG,SAAqC,CAAC;AA0D5E;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,uCA8C1B"}
|