@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 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/ui/molecules/nav-menu/nav-menu.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport { cn } from '../../utils/cn.js';\n\n/** A bar's trigger: quiet until hovered or open. */\nconst TRIGGER =\n 'focus-ring flex h-
|
|
1
|
+
{"version":3,"sources":["../../../../src/ui/molecules/nav-menu/nav-menu.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport { cn } from '../../utils/cn.js';\n\n/** A bar's trigger: quiet until hovered or open. */\nconst TRIGGER =\n 'focus-ring flex h-8 cursor-pointer list-none items-center gap-3xs rounded-md border border-transparent px-2xs text-step-sm font-medium text-content select-none transition-[background-color,border-color] duration-(--duration-fast,150ms) hover:border-border hover:bg-[color-mix(in_srgb,var(--color-content)_6%,transparent)] [&::-webkit-details-marker]:hidden [[open]>&]:border-border [[open]>&]:bg-[color-mix(in_srgb,var(--color-content)_6%,transparent)]';\n\n/**\n * A dropdown in a navigation bar: a native `<details>` disclosure, so it opens\n * and its links work with scripting off. What a dropdown is expected to do on\n * top — one open at a time, closed by a click elsewhere or Escape — is the\n * page's to add.\n *\n * No hooks, so a client component can render it too. Its parts carry\n * `data-slot` (`nav-menu`, `nav-menu-trigger`, `nav-menu-chevron`,\n * `nav-menu-panel`), so a page can restyle them — a panel as wide as the bar\n * on a phone, say — without knowing the classes underneath.\n */\nexport function NavMenu({\n label,\n icon,\n summary,\n chevron = true,\n className,\n triggerClassName = TRIGGER,\n children,\n}: {\n /** The accessible name of the trigger. */\n label: string;\n icon: ReactNode;\n /** What the trigger shows beside the icon, if anything. */\n summary?: ReactNode;\n /** A chevron after the trigger's content: a menu of choices has one. */\n chevron?: boolean;\n className?: string;\n /** Replaces the trigger's look: a split button draws it as its own segment. */\n triggerClassName?: string;\n children: ReactNode;\n}) {\n return (\n <details data-slot=\"nav-menu\" className={cn('relative', className)}>\n {/* The name is the label followed by the summary, so what a sighted\n user reads on the trigger (\"EN\") is part of what is announced and\n what a voice user says (WCAG 2.5.3), rather than replaced by it. */}\n <summary\n title={label}\n data-slot=\"nav-menu-trigger\"\n className={triggerClassName}\n >\n <span className=\"sr-only\">{label}</span>\n {icon}\n {summary}\n {chevron && (\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 24 24\"\n data-slot=\"nav-menu-chevron\"\n className=\"size-3.5 flex-none fill-none stroke-current stroke-2 text-content-muted transition-[rotate] duration-(--duration-fast,150ms) [stroke-linecap:round] [stroke-linejoin:round] [[open]>summary>&]:rotate-180\"\n >\n <path d=\"m7 10 5 5 5-5\" />\n </svg>\n )}\n </summary>\n <div\n data-slot=\"nav-menu-panel\"\n className=\"right-0 ease-out starting:-translate-y-1 [&_ul]:m-0 [&_ul]:p-0 min-w-40 absolute top-[calc(100%+var(--spacing-3xs))] z-(--z-dropdown) rounded-lg border border-border bg-surface-elevated p-3xs shadow-overlay transition-[opacity,translate] duration-(--duration-fast) motion-reduce:transition-none starting:opacity-0 [&_ul]:list-none\"\n >\n {children}\n </div>\n </details>\n );\n}\n\n/** A check beside the chosen entry; an equal space beside the others. */\nexport function NavMenuCheck({ checked }: { checked: boolean }) {\n return (\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 24 24\"\n data-slot=\"nav-menu-check\"\n className=\"size-4 flex-none fill-none stroke-current stroke-2 [stroke-linecap:round] [stroke-linejoin:round]\"\n >\n {checked && <path d=\"m5 12.5 4.5 4.5L19 7.5\" />}\n </svg>\n );\n}\n"],"names":["cn","TRIGGER","NavMenu","label","icon","summary","chevron","className","triggerClassName","children","details","data-slot","title","span","svg","aria-hidden","viewBox","path","d","div","NavMenuCheck","checked"],"mappings":";AAEA,SAASA,EAAE,QAAQ,oBAAoB;AAEvC,kDAAkD,GAClD,MAAMC,UACJ;AAEF;;;;;;;;;;CAUC,GACD,OAAO,SAASC,QAAQ,EACtBC,KAAK,EACLC,IAAI,EACJC,OAAO,EACPC,UAAU,IAAI,EACdC,SAAS,EACTC,mBAAmBP,OAAO,EAC1BQ,QAAQ,EAaT;IACC,qBACE,MAACC;QAAQC,aAAU;QAAWJ,WAAWP,GAAG,YAAYO;;0BAItD,MAACF;gBACCO,OAAOT;gBACPQ,aAAU;gBACVJ,WAAWC;;kCAEX,KAACK;wBAAKN,WAAU;kCAAWJ;;oBAC1BC;oBACAC;oBACAC,yBACC,KAACQ;wBACCC,eAAY;wBACZC,SAAQ;wBACRL,aAAU;wBACVJ,WAAU;kCAEV,cAAA,KAACU;4BAAKC,GAAE;;;;;0BAId,KAACC;gBACCR,aAAU;gBACVJ,WAAU;0BAETE;;;;AAIT;AAEA,uEAAuE,GACvE,OAAO,SAASW,aAAa,EAAEC,OAAO,EAAwB;IAC5D,qBACE,KAACP;QACCC,eAAY;QACZC,SAAQ;QACRL,aAAU;QACVJ,WAAU;kBAETc,yBAAW,KAACJ;YAAKC,GAAE;;;AAG1B"}
|
|
@@ -11,6 +11,11 @@ export interface PaginationProps {
|
|
|
11
11
|
/**
|
|
12
12
|
* Page stepper plus an optional page-size selector, driven by callbacks.
|
|
13
13
|
*
|
|
14
|
+
* A `nav` with First, Previous, Next and Last. An end that goes nowhere stays
|
|
15
|
+
* focusable and says so with `aria-disabled`, rather than dropping out of the
|
|
16
|
+
* tab order under the reader's hand. A page change is announced — "Page 2 of
|
|
17
|
+
* 5" — and the first render is not.
|
|
18
|
+
*
|
|
14
19
|
* For a listing whose pages are addresses (server-rendered, crawlable, working
|
|
15
20
|
* without JavaScript) use {@link PaginationLinks} instead.
|
|
16
21
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/pagination/pagination.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/pagination/pagination.tsx"],"names":[],"mappings":"AAWA,eAAO,MAAM,yBAAyB,4BAA6B,CAAC;AAEpE,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,EACzB,WAAW,EACX,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,eAA2C,EAC3C,SAAS,GACV,EAAE,eAAe,+BAkEjB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from 'react';
|
|
3
4
|
import { useT } from '../../../i18n/index.js';
|
|
4
5
|
import { Button } from '../../atoms/button/index.js';
|
|
5
6
|
import { Select } from '../../atoms/field/index.js';
|
|
@@ -15,12 +16,32 @@ export const DEFAULT_PAGE_SIZE_OPTIONS = [
|
|
|
15
16
|
/**
|
|
16
17
|
* Page stepper plus an optional page-size selector, driven by callbacks.
|
|
17
18
|
*
|
|
19
|
+
* A `nav` with First, Previous, Next and Last. An end that goes nowhere stays
|
|
20
|
+
* focusable and says so with `aria-disabled`, rather than dropping out of the
|
|
21
|
+
* tab order under the reader's hand. A page change is announced — "Page 2 of
|
|
22
|
+
* 5" — and the first render is not.
|
|
23
|
+
*
|
|
18
24
|
* For a listing whose pages are addresses (server-rendered, crawlable, working
|
|
19
25
|
* without JavaScript) use {@link PaginationLinks} instead.
|
|
20
26
|
*/ export function Pagination({ currentPage, pageSize, totalItems, onPageChange, onPageSizeChange, pageSizeOptions = DEFAULT_PAGE_SIZE_OPTIONS, className }) {
|
|
21
27
|
const t = useT();
|
|
22
28
|
const totalPages = pageCount(totalItems, pageSize);
|
|
23
|
-
|
|
29
|
+
const [announced, setAnnounced] = useState(false);
|
|
30
|
+
const step = (label, page, enabled)=>/*#__PURE__*/ _jsx(Button, {
|
|
31
|
+
type: "button",
|
|
32
|
+
variant: "secondary",
|
|
33
|
+
size: "sm",
|
|
34
|
+
// Headless UI runs no handler on an `aria-disabled` button, so an end
|
|
35
|
+
// that goes nowhere is inert while it keeps its place in the tab order.
|
|
36
|
+
"aria-disabled": enabled ? undefined : true,
|
|
37
|
+
onClick: ()=>{
|
|
38
|
+
setAnnounced(true);
|
|
39
|
+
onPageChange(page);
|
|
40
|
+
},
|
|
41
|
+
children: label
|
|
42
|
+
});
|
|
43
|
+
return /*#__PURE__*/ _jsxs("nav", {
|
|
44
|
+
"aria-label": t('pagination.label'),
|
|
24
45
|
className: cn('flex flex-wrap items-center justify-between gap-2xs', className),
|
|
25
46
|
children: [
|
|
26
47
|
/*#__PURE__*/ _jsx(Text, {
|
|
@@ -32,8 +53,16 @@ export const DEFAULT_PAGE_SIZE_OPTIONS = [
|
|
|
32
53
|
items: totalItems
|
|
33
54
|
})
|
|
34
55
|
}),
|
|
56
|
+
/*#__PURE__*/ _jsx("span", {
|
|
57
|
+
role: "status",
|
|
58
|
+
className: "sr-only",
|
|
59
|
+
children: announced ? t('pagination.page', {
|
|
60
|
+
current: currentPage,
|
|
61
|
+
total: totalPages
|
|
62
|
+
}) : ''
|
|
63
|
+
}),
|
|
35
64
|
/*#__PURE__*/ _jsxs("div", {
|
|
36
|
-
className: "flex items-center gap-2xs",
|
|
65
|
+
className: "flex flex-wrap items-center gap-2xs",
|
|
37
66
|
children: [
|
|
38
67
|
onPageSizeChange && /*#__PURE__*/ _jsxs("label", {
|
|
39
68
|
className: "flex items-center gap-3xs text-step-sm text-content-muted",
|
|
@@ -49,22 +78,10 @@ export const DEFAULT_PAGE_SIZE_OPTIONS = [
|
|
|
49
78
|
})
|
|
50
79
|
]
|
|
51
80
|
}),
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
disabled: currentPage <= 1,
|
|
57
|
-
onClick: ()=>onPageChange(currentPage - 1),
|
|
58
|
-
children: t('pagination.previous')
|
|
59
|
-
}),
|
|
60
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
61
|
-
type: "button",
|
|
62
|
-
variant: "secondary",
|
|
63
|
-
size: "sm",
|
|
64
|
-
disabled: currentPage >= totalPages,
|
|
65
|
-
onClick: ()=>onPageChange(currentPage + 1),
|
|
66
|
-
children: t('pagination.next')
|
|
67
|
-
})
|
|
81
|
+
step(t('pagination.first'), 1, currentPage > 1),
|
|
82
|
+
step(t('pagination.previous'), currentPage - 1, currentPage > 1),
|
|
83
|
+
step(t('pagination.next'), currentPage + 1, currentPage < totalPages),
|
|
84
|
+
step(t('pagination.last'), totalPages, currentPage < totalPages)
|
|
68
85
|
]
|
|
69
86
|
})
|
|
70
87
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/ui/molecules/pagination/pagination.tsx"],"sourcesContent":["'use client';\n\nimport { useT } from '../../../i18n/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { Select } from '../../atoms/field/index.js';\nimport { Text } from '../../atoms/text/index.js';\nimport { cn } from '../../utils/cn.js';\nimport { pageCount } from './page-math.js';\n\nexport const DEFAULT_PAGE_SIZE_OPTIONS = [10, 25, 50, 100] as const;\n\nexport interface PaginationProps {\n currentPage: number;\n pageSize: number;\n totalItems: number;\n onPageChange: (page: number) => void;\n onPageSizeChange?: (pageSize: number) => void;\n pageSizeOptions?: readonly number[];\n className?: string;\n}\n\n/**\n * Page stepper plus an optional page-size selector, driven by callbacks.\n *\n * For a listing whose pages are addresses (server-rendered, crawlable, working\n * without JavaScript) use {@link PaginationLinks} instead.\n */\nexport function Pagination({\n currentPage,\n pageSize,\n totalItems,\n onPageChange,\n onPageSizeChange,\n pageSizeOptions = DEFAULT_PAGE_SIZE_OPTIONS,\n className,\n}: PaginationProps) {\n const t = useT();\n const totalPages = pageCount(totalItems, pageSize);\n\n return (\n <
|
|
1
|
+
{"version":3,"sources":["../../../../src/ui/molecules/pagination/pagination.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\n\nimport { useT } from '../../../i18n/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { Select } from '../../atoms/field/index.js';\nimport { Text } from '../../atoms/text/index.js';\nimport { cn } from '../../utils/cn.js';\nimport { pageCount } from './page-math.js';\n\nexport const DEFAULT_PAGE_SIZE_OPTIONS = [10, 25, 50, 100] as const;\n\nexport interface PaginationProps {\n currentPage: number;\n pageSize: number;\n totalItems: number;\n onPageChange: (page: number) => void;\n onPageSizeChange?: (pageSize: number) => void;\n pageSizeOptions?: readonly number[];\n className?: string;\n}\n\n/**\n * Page stepper plus an optional page-size selector, driven by callbacks.\n *\n * A `nav` with First, Previous, Next and Last. An end that goes nowhere stays\n * focusable and says so with `aria-disabled`, rather than dropping out of the\n * tab order under the reader's hand. A page change is announced — \"Page 2 of\n * 5\" — and the first render is not.\n *\n * For a listing whose pages are addresses (server-rendered, crawlable, working\n * without JavaScript) use {@link PaginationLinks} instead.\n */\nexport function Pagination({\n currentPage,\n pageSize,\n totalItems,\n onPageChange,\n onPageSizeChange,\n pageSizeOptions = DEFAULT_PAGE_SIZE_OPTIONS,\n className,\n}: PaginationProps) {\n const t = useT();\n const totalPages = pageCount(totalItems, pageSize);\n const [announced, setAnnounced] = useState(false);\n\n const step = (label: string, page: number, enabled: boolean) => (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n // Headless UI runs no handler on an `aria-disabled` button, so an end\n // that goes nowhere is inert while it keeps its place in the tab order.\n aria-disabled={enabled ? undefined : true}\n onClick={() => {\n setAnnounced(true);\n onPageChange(page);\n }}\n >\n {label}\n </Button>\n );\n\n return (\n <nav\n aria-label={t('pagination.label')}\n className={cn(\n 'flex flex-wrap items-center justify-between gap-2xs',\n className,\n )}\n >\n <Text step={-1} tone=\"muted\">\n {t('pagination.summary', {\n current: currentPage,\n total: totalPages,\n items: totalItems,\n })}\n </Text>\n <span role=\"status\" className=\"sr-only\">\n {announced\n ? t('pagination.page', { current: currentPage, total: totalPages })\n : ''}\n </span>\n\n <div className=\"flex flex-wrap items-center gap-2xs\">\n {onPageSizeChange && (\n <label className=\"flex items-center gap-3xs text-step-sm text-content-muted\">\n {t('pagination.rows')}\n <Select\n value={pageSize}\n onChange={event => onPageSizeChange(Number(event.target.value))}\n >\n {pageSizeOptions.map(option => (\n <option key={option} value={option}>\n {option}\n </option>\n ))}\n </Select>\n </label>\n )}\n {step(t('pagination.first'), 1, currentPage > 1)}\n {step(t('pagination.previous'), currentPage - 1, currentPage > 1)}\n {step(t('pagination.next'), currentPage + 1, currentPage < totalPages)}\n {step(t('pagination.last'), totalPages, currentPage < totalPages)}\n </div>\n </nav>\n );\n}\n"],"names":["useState","useT","Button","Select","Text","cn","pageCount","DEFAULT_PAGE_SIZE_OPTIONS","Pagination","currentPage","pageSize","totalItems","onPageChange","onPageSizeChange","pageSizeOptions","className","t","totalPages","announced","setAnnounced","step","label","page","enabled","type","variant","size","aria-disabled","undefined","onClick","nav","aria-label","tone","current","total","items","span","role","div","value","onChange","event","Number","target","map","option"],"mappings":"AAAA;;AAEA,SAASA,QAAQ,QAAQ,QAAQ;AAEjC,SAASC,IAAI,QAAQ,yBAAyB;AAC9C,SAASC,MAAM,QAAQ,8BAA8B;AACrD,SAASC,MAAM,QAAQ,6BAA6B;AACpD,SAASC,IAAI,QAAQ,4BAA4B;AACjD,SAASC,EAAE,QAAQ,oBAAoB;AACvC,SAASC,SAAS,QAAQ,iBAAiB;AAE3C,OAAO,MAAMC,4BAA4B;IAAC;IAAI;IAAI;IAAI;CAAI,CAAU;AAYpE;;;;;;;;;;CAUC,GACD,OAAO,SAASC,WAAW,EACzBC,WAAW,EACXC,QAAQ,EACRC,UAAU,EACVC,YAAY,EACZC,gBAAgB,EAChBC,kBAAkBP,yBAAyB,EAC3CQ,SAAS,EACO;IAChB,MAAMC,IAAIf;IACV,MAAMgB,aAAaX,UAAUK,YAAYD;IACzC,MAAM,CAACQ,WAAWC,aAAa,GAAGnB,SAAS;IAE3C,MAAMoB,OAAO,CAACC,OAAeC,MAAcC,wBACzC,KAACrB;YACCsB,MAAK;YACLC,SAAQ;YACRC,MAAK;YACL,sEAAsE;YACtE,wEAAwE;YACxEC,iBAAeJ,UAAUK,YAAY;YACrCC,SAAS;gBACPV,aAAa;gBACbP,aAAaU;YACf;sBAECD;;IAIL,qBACE,MAACS;QACCC,cAAYf,EAAE;QACdD,WAAWV,GACT,uDACAU;;0BAGF,KAACX;gBAAKgB,MAAM,CAAC;gBAAGY,MAAK;0BAClBhB,EAAE,sBAAsB;oBACvBiB,SAASxB;oBACTyB,OAAOjB;oBACPkB,OAAOxB;gBACT;;0BAEF,KAACyB;gBAAKC,MAAK;gBAAStB,WAAU;0BAC3BG,YACGF,EAAE,mBAAmB;oBAAEiB,SAASxB;oBAAayB,OAAOjB;gBAAW,KAC/D;;0BAGN,MAACqB;gBAAIvB,WAAU;;oBACZF,kCACC,MAACQ;wBAAMN,WAAU;;4BACdC,EAAE;0CACH,KAACb;gCACCoC,OAAO7B;gCACP8B,UAAUC,CAAAA,QAAS5B,iBAAiB6B,OAAOD,MAAME,MAAM,CAACJ,KAAK;0CAE5DzB,gBAAgB8B,GAAG,CAACC,CAAAA,uBACnB,KAACA;wCAAoBN,OAAOM;kDACzBA;uCADUA;;;;oBAOpBzB,KAAKJ,EAAE,qBAAqB,GAAGP,cAAc;oBAC7CW,KAAKJ,EAAE,wBAAwBP,cAAc,GAAGA,cAAc;oBAC9DW,KAAKJ,EAAE,oBAAoBP,cAAc,GAAGA,cAAcQ;oBAC1DG,KAAKJ,EAAE,oBAAoBC,YAAYR,cAAcQ;;;;;AAI9D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/region-state/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/ui/molecules/region-state/index.ts"],"sourcesContent":["export * from './region-state.js';\n"],"names":[],"mappings":"AAAA,cAAc,oBAAoB"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/** A failure as the organisms hold it: a typed failure, or anything thrown. */
|
|
3
|
+
export interface RegionStateError {
|
|
4
|
+
message: string;
|
|
5
|
+
code?: unknown;
|
|
6
|
+
details?: Record<string, unknown>;
|
|
7
|
+
}
|
|
8
|
+
export interface RegionStateProps {
|
|
9
|
+
/** What the region holds, plural — "invoices" — for the state's sentence. */
|
|
10
|
+
plural: string;
|
|
11
|
+
/** The first load: the organism's skeleton speaks for it, so nothing here. */
|
|
12
|
+
isLoading?: boolean;
|
|
13
|
+
/** A load that failed. */
|
|
14
|
+
error?: RegionStateError;
|
|
15
|
+
/** Loads the region again. Without it, an error offers no Retry. */
|
|
16
|
+
onRetry?: () => void;
|
|
17
|
+
/** The load answered, with nothing in it. */
|
|
18
|
+
isEmpty?: boolean;
|
|
19
|
+
/** A filter is in effect, so an empty answer is the filter's, not the data's. */
|
|
20
|
+
isFiltered?: boolean;
|
|
21
|
+
/** Clears every filter — what an empty filtered region offers. */
|
|
22
|
+
onClearFilters?: () => void;
|
|
23
|
+
/** What an empty, unfiltered region offers: creating the first record. */
|
|
24
|
+
emptyAction?: ReactNode;
|
|
25
|
+
/** Data from before the failure is still on screen. */
|
|
26
|
+
hasStaleData?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* What a region says when it is not simply showing its content
|
|
30
|
+
* ([ADR 0028](../../../../../../../docs/adr/0028-states-an-organism-must-render.md)):
|
|
31
|
+
*
|
|
32
|
+
* - a **load error** is an `Alert` with Retry — `forbidden` says so in its own
|
|
33
|
+
* words — and data kept from before it is marked possibly out of date;
|
|
34
|
+
* - an **empty result under a filter** says so and offers Clear filters;
|
|
35
|
+
* - an **empty region** says what appears here, and offers its first record.
|
|
36
|
+
*
|
|
37
|
+
* It renders nothing while loading, and nothing when there is content: the
|
|
38
|
+
* organism's own skeleton and rows speak then. An empty result and a dead
|
|
39
|
+
* backend never look alike.
|
|
40
|
+
*/
|
|
41
|
+
export declare function RegionState({ plural, isLoading, error, onRetry, isEmpty, isFiltered, onClearFilters, emptyAction, hasStaleData, }: RegionStateProps): import("react").JSX.Element | null;
|
|
42
|
+
//# sourceMappingURL=region-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"region-state.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/region-state/region-state.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAQvC,+EAA+E;AAC/E,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,gBAAgB;IAC/B,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,0BAA0B;IAC1B,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,6CAA6C;IAC7C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iFAAiF;IACjF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,kEAAkE;IAClE,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,0EAA0E;IAC1E,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,uDAAuD;IACvD,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,SAAiB,EACjB,KAAK,EACL,OAAO,EACP,OAAe,EACf,UAAkB,EAClB,cAAc,EACd,WAAW,EACX,YAAoB,GACrB,EAAE,gBAAgB,sCA8ElB"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useErrorMessage, useT } from '../../../i18n/index.js';
|
|
4
|
+
import { useErrorAction } from '../../actions/error-actions.js';
|
|
5
|
+
import { Alert } from '../../atoms/alert/index.js';
|
|
6
|
+
import { Button } from '../../atoms/button/index.js';
|
|
7
|
+
import { EmptyState } from '../empty-state/index.js';
|
|
8
|
+
/**
|
|
9
|
+
* What a region says when it is not simply showing its content
|
|
10
|
+
* ([ADR 0028](../../../../../../../docs/adr/0028-states-an-organism-must-render.md)):
|
|
11
|
+
*
|
|
12
|
+
* - a **load error** is an `Alert` with Retry — `forbidden` says so in its own
|
|
13
|
+
* words — and data kept from before it is marked possibly out of date;
|
|
14
|
+
* - an **empty result under a filter** says so and offers Clear filters;
|
|
15
|
+
* - an **empty region** says what appears here, and offers its first record.
|
|
16
|
+
*
|
|
17
|
+
* It renders nothing while loading, and nothing when there is content: the
|
|
18
|
+
* organism's own skeleton and rows speak then. An empty result and a dead
|
|
19
|
+
* backend never look alike.
|
|
20
|
+
*/ export function RegionState({ plural, isLoading = false, error, onRetry, isEmpty = false, isFiltered = false, onClearFilters, emptyAction, hasStaleData = false }) {
|
|
21
|
+
const t = useT();
|
|
22
|
+
const errorMessage = useErrorMessage();
|
|
23
|
+
const errorAction = useErrorAction();
|
|
24
|
+
// Read inside a sentence, so as a common noun: "sus facturas".
|
|
25
|
+
const noun = plural.toLocaleLowerCase();
|
|
26
|
+
if (error !== undefined) {
|
|
27
|
+
// The host's next step for this code — "Choose organization" — when it
|
|
28
|
+
// registered one and its catalog names it.
|
|
29
|
+
const next = errorAction(error);
|
|
30
|
+
return /*#__PURE__*/ _jsxs(Alert, {
|
|
31
|
+
tone: "danger",
|
|
32
|
+
"data-testid": "region-state-error",
|
|
33
|
+
action: next === undefined && onRetry === undefined ? undefined : /*#__PURE__*/ _jsxs("span", {
|
|
34
|
+
className: "flex flex-wrap gap-3xs",
|
|
35
|
+
children: [
|
|
36
|
+
next !== undefined && /*#__PURE__*/ _jsx(Button, {
|
|
37
|
+
type: "button",
|
|
38
|
+
variant: "primary",
|
|
39
|
+
size: "sm",
|
|
40
|
+
onClick: next.onAction,
|
|
41
|
+
children: next.label
|
|
42
|
+
}),
|
|
43
|
+
onRetry !== undefined && /*#__PURE__*/ _jsx(Button, {
|
|
44
|
+
type: "button",
|
|
45
|
+
variant: "secondary",
|
|
46
|
+
size: "sm",
|
|
47
|
+
onClick: onRetry,
|
|
48
|
+
children: t('state.retry')
|
|
49
|
+
})
|
|
50
|
+
]
|
|
51
|
+
}),
|
|
52
|
+
children: [
|
|
53
|
+
error.code === 'forbidden' ? t('state.forbidden', {
|
|
54
|
+
plural: noun
|
|
55
|
+
}) : errorMessage(error),
|
|
56
|
+
hasStaleData && ` ${t('state.stale')}`
|
|
57
|
+
]
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
if (isLoading || !isEmpty) return null;
|
|
61
|
+
if (isFiltered) {
|
|
62
|
+
return /*#__PURE__*/ _jsx(EmptyState, {
|
|
63
|
+
action: onClearFilters === undefined ? undefined : /*#__PURE__*/ _jsx(Button, {
|
|
64
|
+
type: "button",
|
|
65
|
+
variant: "secondary",
|
|
66
|
+
size: "sm",
|
|
67
|
+
onClick: onClearFilters,
|
|
68
|
+
children: t('state.clearFilters')
|
|
69
|
+
}),
|
|
70
|
+
children: t('state.noResults', {
|
|
71
|
+
plural: noun
|
|
72
|
+
})
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return /*#__PURE__*/ _jsx(EmptyState, {
|
|
76
|
+
action: emptyAction,
|
|
77
|
+
children: t('state.empty', {
|
|
78
|
+
plural: noun
|
|
79
|
+
})
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
//# sourceMappingURL=region-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/ui/molecules/region-state/region-state.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactNode } from 'react';\n\nimport { useErrorMessage, useT } from '../../../i18n/index.js';\nimport { useErrorAction } from '../../actions/error-actions.js';\nimport { Alert } from '../../atoms/alert/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { EmptyState } from '../empty-state/index.js';\n\n/** A failure as the organisms hold it: a typed failure, or anything thrown. */\nexport interface RegionStateError {\n message: string;\n code?: unknown;\n details?: Record<string, unknown>;\n}\n\nexport interface RegionStateProps {\n /** What the region holds, plural — \"invoices\" — for the state's sentence. */\n plural: string;\n /** The first load: the organism's skeleton speaks for it, so nothing here. */\n isLoading?: boolean;\n /** A load that failed. */\n error?: RegionStateError;\n /** Loads the region again. Without it, an error offers no Retry. */\n onRetry?: () => void;\n /** The load answered, with nothing in it. */\n isEmpty?: boolean;\n /** A filter is in effect, so an empty answer is the filter's, not the data's. */\n isFiltered?: boolean;\n /** Clears every filter — what an empty filtered region offers. */\n onClearFilters?: () => void;\n /** What an empty, unfiltered region offers: creating the first record. */\n emptyAction?: ReactNode;\n /** Data from before the failure is still on screen. */\n hasStaleData?: boolean;\n}\n\n/**\n * What a region says when it is not simply showing its content\n * ([ADR 0028](../../../../../../../docs/adr/0028-states-an-organism-must-render.md)):\n *\n * - a **load error** is an `Alert` with Retry — `forbidden` says so in its own\n * words — and data kept from before it is marked possibly out of date;\n * - an **empty result under a filter** says so and offers Clear filters;\n * - an **empty region** says what appears here, and offers its first record.\n *\n * It renders nothing while loading, and nothing when there is content: the\n * organism's own skeleton and rows speak then. An empty result and a dead\n * backend never look alike.\n */\nexport function RegionState({\n plural,\n isLoading = false,\n error,\n onRetry,\n isEmpty = false,\n isFiltered = false,\n onClearFilters,\n emptyAction,\n hasStaleData = false,\n}: RegionStateProps) {\n const t = useT();\n const errorMessage = useErrorMessage();\n const errorAction = useErrorAction();\n // Read inside a sentence, so as a common noun: \"sus facturas\".\n const noun = plural.toLocaleLowerCase();\n\n if (error !== undefined) {\n // The host's next step for this code — \"Choose organization\" — when it\n // registered one and its catalog names it.\n const next = errorAction(error);\n return (\n <Alert\n tone=\"danger\"\n data-testid=\"region-state-error\"\n action={\n next === undefined && onRetry === undefined ? undefined : (\n <span className=\"flex flex-wrap gap-3xs\">\n {next !== undefined && (\n <Button\n type=\"button\"\n variant=\"primary\"\n size=\"sm\"\n onClick={next.onAction}\n >\n {next.label}\n </Button>\n )}\n {onRetry !== undefined && (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n onClick={onRetry}\n >\n {t('state.retry')}\n </Button>\n )}\n </span>\n )\n }\n >\n {error.code === 'forbidden'\n ? t('state.forbidden', { plural: noun })\n : errorMessage(error)}\n {hasStaleData && ` ${t('state.stale')}`}\n </Alert>\n );\n }\n\n if (isLoading || !isEmpty) return null;\n\n if (isFiltered) {\n return (\n <EmptyState\n action={\n onClearFilters === undefined ? undefined : (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n onClick={onClearFilters}\n >\n {t('state.clearFilters')}\n </Button>\n )\n }\n >\n {t('state.noResults', { plural: noun })}\n </EmptyState>\n );\n }\n\n return (\n <EmptyState action={emptyAction}>\n {t('state.empty', { plural: noun })}\n </EmptyState>\n );\n}\n"],"names":["useErrorMessage","useT","useErrorAction","Alert","Button","EmptyState","RegionState","plural","isLoading","error","onRetry","isEmpty","isFiltered","onClearFilters","emptyAction","hasStaleData","t","errorMessage","errorAction","noun","toLocaleLowerCase","undefined","next","tone","data-testid","action","span","className","type","variant","size","onClick","onAction","label","code"],"mappings":"AAAA;;AAIA,SAASA,eAAe,EAAEC,IAAI,QAAQ,yBAAyB;AAC/D,SAASC,cAAc,QAAQ,iCAAiC;AAChE,SAASC,KAAK,QAAQ,6BAA6B;AACnD,SAASC,MAAM,QAAQ,8BAA8B;AACrD,SAASC,UAAU,QAAQ,0BAA0B;AA8BrD;;;;;;;;;;;;CAYC,GACD,OAAO,SAASC,YAAY,EAC1BC,MAAM,EACNC,YAAY,KAAK,EACjBC,KAAK,EACLC,OAAO,EACPC,UAAU,KAAK,EACfC,aAAa,KAAK,EAClBC,cAAc,EACdC,WAAW,EACXC,eAAe,KAAK,EACH;IACjB,MAAMC,IAAIf;IACV,MAAMgB,eAAejB;IACrB,MAAMkB,cAAchB;IACpB,+DAA+D;IAC/D,MAAMiB,OAAOZ,OAAOa,iBAAiB;IAErC,IAAIX,UAAUY,WAAW;QACvB,uEAAuE;QACvE,2CAA2C;QAC3C,MAAMC,OAAOJ,YAAYT;QACzB,qBACE,MAACN;YACCoB,MAAK;YACLC,eAAY;YACZC,QACEH,SAASD,aAAaX,YAAYW,YAAYA,0BAC5C,MAACK;gBAAKC,WAAU;;oBACbL,SAASD,2BACR,KAACjB;wBACCwB,MAAK;wBACLC,SAAQ;wBACRC,MAAK;wBACLC,SAAST,KAAKU,QAAQ;kCAErBV,KAAKW,KAAK;;oBAGdvB,YAAYW,2BACX,KAACjB;wBACCwB,MAAK;wBACLC,SAAQ;wBACRC,MAAK;wBACLC,SAASrB;kCAERM,EAAE;;;;;gBAOZP,MAAMyB,IAAI,KAAK,cACZlB,EAAE,mBAAmB;oBAAET,QAAQY;gBAAK,KACpCF,aAAaR;gBAChBM,gBAAgB,CAAC,CAAC,EAAEC,EAAE,gBAAgB;;;IAG7C;IAEA,IAAIR,aAAa,CAACG,SAAS,OAAO;IAElC,IAAIC,YAAY;QACd,qBACE,KAACP;YACCoB,QACEZ,mBAAmBQ,YAAYA,0BAC7B,KAACjB;gBACCwB,MAAK;gBACLC,SAAQ;gBACRC,MAAK;gBACLC,SAASlB;0BAERG,EAAE;;sBAKRA,EAAE,mBAAmB;gBAAET,QAAQY;YAAK;;IAG3C;IAEA,qBACE,KAACd;QAAWoB,QAAQX;kBACjBE,EAAE,eAAe;YAAET,QAAQY;QAAK;;AAGvC"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* (a choice in the page): one bordered track, the chosen segment filled.
|
|
4
4
|
*/
|
|
5
5
|
/** The joined segments; scrolls sideways rather than wrapping. */
|
|
6
|
-
export declare const LIST = "m-0 flex w-max max-w-full list-none overflow-x-auto rounded-md border border-border p-
|
|
7
|
-
export declare const OTHER = "block rounded-[calc(var(--radius-md,0.375rem)-0.125rem)] px-xs py-
|
|
8
|
-
export declare const CURRENT = "block rounded-[calc(var(--radius-md,0.375rem)-0.125rem)] px-xs py-
|
|
6
|
+
export declare const LIST = "m-0 flex w-max max-w-full list-none overflow-x-auto rounded-md border border-border p-0.75 [scrollbar-width:none]";
|
|
7
|
+
export declare const OTHER = "block rounded-[calc(var(--radius-md,0.375rem)-0.125rem)] px-xs py-1.25 text-step-sm whitespace-nowrap no-underline transition-colors duration-(--duration-fast,150ms) motion-reduce:transition-none focus-ring text-content hover:bg-[color-mix(in_srgb,var(--color-content)_6%,transparent)] hover:text-primary";
|
|
8
|
+
export declare const CURRENT = "block rounded-[calc(var(--radius-md,0.375rem)-0.125rem)] px-xs py-1.25 text-step-sm whitespace-nowrap no-underline transition-colors duration-(--duration-fast,150ms) motion-reduce:transition-none bg-primary font-medium text-primary-content";
|
|
9
9
|
//# sourceMappingURL=segment-classes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"segment-classes.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/segmented-nav/segment-classes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,kEAAkE;AAClE,eAAO,MAAM,IAAI,
|
|
1
|
+
{"version":3,"file":"segment-classes.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/segmented-nav/segment-classes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,kEAAkE;AAClE,eAAO,MAAM,IAAI,sHACoG,CAAC;AAKtH,eAAO,MAAM,KAAK,qTAA4H,CAAC;AAE/I,eAAO,MAAM,OAAO,oPAA2D,CAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The segmented look, shared by `SegmentedNav` (links) and `SegmentedControl`
|
|
3
3
|
* (a choice in the page): one bordered track, the chosen segment filled.
|
|
4
|
-
*/ /** The joined segments; scrolls sideways rather than wrapping. */ export const LIST = 'm-0 flex w-max max-w-full list-none overflow-x-auto rounded-md border border-border p-
|
|
5
|
-
const SEGMENT = 'block rounded-[calc(var(--radius-md,0.375rem)-0.125rem)] px-xs py-
|
|
4
|
+
*/ /** The joined segments; scrolls sideways rather than wrapping. */ export const LIST = 'm-0 flex w-max max-w-full list-none overflow-x-auto rounded-md border border-border p-0.75 [scrollbar-width:none]';
|
|
5
|
+
const SEGMENT = 'block rounded-[calc(var(--radius-md,0.375rem)-0.125rem)] px-xs py-1.25 text-step-sm whitespace-nowrap no-underline transition-colors duration-(--duration-fast,150ms) motion-reduce:transition-none';
|
|
6
6
|
export const OTHER = `${SEGMENT} focus-ring text-content hover:bg-[color-mix(in_srgb,var(--color-content)_6%,transparent)] hover:text-primary`;
|
|
7
7
|
export const CURRENT = `${SEGMENT} bg-primary font-medium text-primary-content`;
|
|
8
8
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/ui/molecules/segmented-nav/segment-classes.ts"],"sourcesContent":["/**\n * The segmented look, shared by `SegmentedNav` (links) and `SegmentedControl`\n * (a choice in the page): one bordered track, the chosen segment filled.\n */\n/** The joined segments; scrolls sideways rather than wrapping. */\nexport const LIST =\n 'm-0 flex w-max max-w-full list-none overflow-x-auto rounded-md border border-border p-
|
|
1
|
+
{"version":3,"sources":["../../../../src/ui/molecules/segmented-nav/segment-classes.ts"],"sourcesContent":["/**\n * The segmented look, shared by `SegmentedNav` (links) and `SegmentedControl`\n * (a choice in the page): one bordered track, the chosen segment filled.\n */\n/** The joined segments; scrolls sideways rather than wrapping. */\nexport const LIST =\n 'm-0 flex w-max max-w-full list-none overflow-x-auto rounded-md border border-border p-0.75 [scrollbar-width:none]';\n\nconst SEGMENT =\n 'block rounded-[calc(var(--radius-md,0.375rem)-0.125rem)] px-xs py-1.25 text-step-sm whitespace-nowrap no-underline transition-colors duration-(--duration-fast,150ms) motion-reduce:transition-none';\n\nexport const OTHER = `${SEGMENT} focus-ring text-content hover:bg-[color-mix(in_srgb,var(--color-content)_6%,transparent)] hover:text-primary`;\n\nexport const CURRENT = `${SEGMENT} bg-primary font-medium text-primary-content`;\n"],"names":["LIST","SEGMENT","OTHER","CURRENT"],"mappings":"AAAA;;;CAGC,GACD,gEAAgE,GAChE,OAAO,MAAMA,OACX,oHAAoH;AAEtH,MAAMC,UACJ;AAEF,OAAO,MAAMC,QAAQ,GAAGD,QAAQ,6GAA6G,CAAC,CAAC;AAE/I,OAAO,MAAME,UAAU,GAAGF,QAAQ,4CAA4C,CAAC,CAAC"}
|
|
@@ -13,18 +13,28 @@ export type SegmentedNavLink = ComponentType<{
|
|
|
13
13
|
children: ReactNode;
|
|
14
14
|
}>;
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
16
|
+
* What the segments choose between. `pages` are separate pages, and the
|
|
17
|
+
* current one is `aria-current="page"`; `sort` orders one page's results, so
|
|
18
|
+
* every segment is the same page and the current one is only the current
|
|
19
|
+
* choice (`aria-current="true"`) — calling it the page would tell a screen
|
|
20
|
+
* reader the visitor is somewhere they are not.
|
|
21
|
+
*/
|
|
22
|
+
export type SegmentedNavKind = 'pages' | 'sort';
|
|
23
|
+
/**
|
|
24
|
+
* A choice between pages, or between orderings of one page, drawn as one
|
|
25
|
+
* segmented control: each segment is a link, the current one a marked span.
|
|
26
|
+
* A visible label names the choice; the `<nav>` carries it for assistive
|
|
27
|
+
* technology.
|
|
19
28
|
*
|
|
20
29
|
* No hooks, so a server component renders it, and every segment works with
|
|
21
30
|
* scripting off. Its parts carry `data-slot` (`segmented-nav`,
|
|
22
31
|
* `segmented-nav-label`, `segmented-nav-list`, `segmented-nav-item`).
|
|
23
32
|
*/
|
|
24
|
-
export declare function SegmentedNav({ label, items, link: Link, className, }: {
|
|
33
|
+
export declare function SegmentedNav({ label, items, link: Link, kind, className, }: {
|
|
25
34
|
label: string;
|
|
26
35
|
items: readonly SegmentedNavItem[];
|
|
27
36
|
link?: SegmentedNavLink;
|
|
37
|
+
kind?: SegmentedNavKind;
|
|
28
38
|
className?: string;
|
|
29
39
|
}): import("react").JSX.Element;
|
|
30
40
|
//# sourceMappingURL=segmented-nav.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"segmented-nav.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/segmented-nav/segmented-nav.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAItD,8DAA8D;AAC9D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,iFAAiF;AACjF,MAAM,MAAM,gBAAgB,GAAG,aAAa,CAAC;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC,CAAC;AAMH
|
|
1
|
+
{"version":3,"file":"segmented-nav.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/segmented-nav/segmented-nav.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAItD,8DAA8D;AAC9D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,iFAAiF;AACjF,MAAM,MAAM,gBAAgB,GAAG,aAAa,CAAC;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC,CAAC;AAMH;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,MAAM,CAAC;AAEhD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,KAAK,EACL,IAAI,EAAE,IAAa,EACnB,IAAc,EACd,SAAS,GACV,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACnC,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,+BAkCA"}
|
|
@@ -11,14 +11,15 @@ const ANCHOR = (_0)=>{
|
|
|
11
11
|
}));
|
|
12
12
|
};
|
|
13
13
|
/**
|
|
14
|
-
* A choice between pages,
|
|
15
|
-
* link, the current
|
|
16
|
-
* choice; the `<nav>` carries it for assistive
|
|
14
|
+
* A choice between pages, or between orderings of one page, drawn as one
|
|
15
|
+
* segmented control: each segment is a link, the current one a marked span.
|
|
16
|
+
* A visible label names the choice; the `<nav>` carries it for assistive
|
|
17
|
+
* technology.
|
|
17
18
|
*
|
|
18
19
|
* No hooks, so a server component renders it, and every segment works with
|
|
19
20
|
* scripting off. Its parts carry `data-slot` (`segmented-nav`,
|
|
20
21
|
* `segmented-nav-label`, `segmented-nav-list`, `segmented-nav-item`).
|
|
21
|
-
*/ export function SegmentedNav({ label, items, link: Link = ANCHOR, className }) {
|
|
22
|
+
*/ export function SegmentedNav({ label, items, link: Link = ANCHOR, kind = 'pages', className }) {
|
|
22
23
|
return /*#__PURE__*/ _jsxs("nav", {
|
|
23
24
|
"data-slot": "segmented-nav",
|
|
24
25
|
"aria-label": label,
|
|
@@ -37,7 +38,7 @@ const ANCHOR = (_0)=>{
|
|
|
37
38
|
"data-slot": "segmented-nav-item",
|
|
38
39
|
className: "flex-none",
|
|
39
40
|
children: item.current ? /*#__PURE__*/ _jsx("span", {
|
|
40
|
-
"aria-current":
|
|
41
|
+
"aria-current": kind === 'sort' ? 'true' : 'page',
|
|
41
42
|
className: CURRENT,
|
|
42
43
|
children: item.label
|
|
43
44
|
}) : /*#__PURE__*/ _jsx(Link, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/ui/molecules/segmented-nav/segmented-nav.tsx"],"sourcesContent":["import type { ComponentType, ReactNode } from 'react';\n\nimport { CURRENT, LIST, OTHER } from './segment-classes.js';\n\n/** One segment: a page of its own, the current one marked. */\nexport interface SegmentedNavItem {\n readonly key: string;\n readonly label: ReactNode;\n readonly href: string;\n readonly current: boolean;\n}\n\n/** What renders a segment that leads elsewhere: an `<a>`, or a router's link. */\nexport type SegmentedNavLink = ComponentType<{\n href: string;\n className?: string;\n children: ReactNode;\n}>;\n\nconst ANCHOR: SegmentedNavLink = ({ children, ...props }) => (\n <a {...props}>{children}</a>\n);\n\n/**\n * A choice between pages, drawn as one segmented control: each segment is a
|
|
1
|
+
{"version":3,"sources":["../../../../src/ui/molecules/segmented-nav/segmented-nav.tsx"],"sourcesContent":["import type { ComponentType, ReactNode } from 'react';\n\nimport { CURRENT, LIST, OTHER } from './segment-classes.js';\n\n/** One segment: a page of its own, the current one marked. */\nexport interface SegmentedNavItem {\n readonly key: string;\n readonly label: ReactNode;\n readonly href: string;\n readonly current: boolean;\n}\n\n/** What renders a segment that leads elsewhere: an `<a>`, or a router's link. */\nexport type SegmentedNavLink = ComponentType<{\n href: string;\n className?: string;\n children: ReactNode;\n}>;\n\nconst ANCHOR: SegmentedNavLink = ({ children, ...props }) => (\n <a {...props}>{children}</a>\n);\n\n/**\n * What the segments choose between. `pages` are separate pages, and the\n * current one is `aria-current=\"page\"`; `sort` orders one page's results, so\n * every segment is the same page and the current one is only the current\n * choice (`aria-current=\"true\"`) — calling it the page would tell a screen\n * reader the visitor is somewhere they are not.\n */\nexport type SegmentedNavKind = 'pages' | 'sort';\n\n/**\n * A choice between pages, or between orderings of one page, drawn as one\n * segmented control: each segment is a link, the current one a marked span.\n * A visible label names the choice; the `<nav>` carries it for assistive\n * technology.\n *\n * No hooks, so a server component renders it, and every segment works with\n * scripting off. Its parts carry `data-slot` (`segmented-nav`,\n * `segmented-nav-label`, `segmented-nav-list`, `segmented-nav-item`).\n */\nexport function SegmentedNav({\n label,\n items,\n link: Link = ANCHOR,\n kind = 'pages',\n className,\n}: {\n label: string;\n items: readonly SegmentedNavItem[];\n link?: SegmentedNavLink;\n kind?: SegmentedNavKind;\n className?: string;\n}) {\n return (\n <nav data-slot=\"segmented-nav\" aria-label={label} className={className}>\n <span\n data-slot=\"segmented-nav-label\"\n aria-hidden=\"true\"\n className=\"text-step-sm text-content-muted\"\n >\n {label}\n </span>\n <ul data-slot=\"segmented-nav-list\" className={LIST}>\n {items.map(item => (\n <li\n key={item.key}\n data-slot=\"segmented-nav-item\"\n className=\"flex-none\"\n >\n {item.current ? (\n <span\n aria-current={kind === 'sort' ? 'true' : 'page'}\n className={CURRENT}\n >\n {item.label}\n </span>\n ) : (\n <Link href={item.href} className={OTHER}>\n {item.label}\n </Link>\n )}\n </li>\n ))}\n </ul>\n </nav>\n );\n}\n"],"names":["CURRENT","LIST","OTHER","ANCHOR","children","props","a","SegmentedNav","label","items","link","Link","kind","className","nav","data-slot","aria-label","span","aria-hidden","ul","map","item","li","current","aria-current","href","key"],"mappings":";;;AAEA,SAASA,OAAO,EAAEC,IAAI,EAAEC,KAAK,QAAQ,uBAAuB;AAiB5D,MAAMC,SAA2B;QAAC,EAAEC,QAAQ,EAAY,OAAPC;;;yBAC/C,KAACC,kBAAMD;kBAAQD;;;AAYjB;;;;;;;;;CASC,GACD,OAAO,SAASG,aAAa,EAC3BC,KAAK,EACLC,KAAK,EACLC,MAAMC,OAAOR,MAAM,EACnBS,OAAO,OAAO,EACdC,SAAS,EAOV;IACC,qBACE,MAACC;QAAIC,aAAU;QAAgBC,cAAYR;QAAOK,WAAWA;;0BAC3D,KAACI;gBACCF,aAAU;gBACVG,eAAY;gBACZL,WAAU;0BAETL;;0BAEH,KAACW;gBAAGJ,aAAU;gBAAqBF,WAAWZ;0BAC3CQ,MAAMW,GAAG,CAACC,CAAAA,qBACT,KAACC;wBAECP,aAAU;wBACVF,WAAU;kCAETQ,KAAKE,OAAO,iBACX,KAACN;4BACCO,gBAAcZ,SAAS,SAAS,SAAS;4BACzCC,WAAWb;sCAEVqB,KAAKb,KAAK;2CAGb,KAACG;4BAAKc,MAAMJ,KAAKI,IAAI;4BAAEZ,WAAWX;sCAC/BmB,KAAKb,KAAK;;uBAbVa,KAAKK,GAAG;;;;AAqBzB"}
|
|
@@ -44,11 +44,11 @@ import { cn } from '../../utils/cn.js';
|
|
|
44
44
|
};
|
|
45
45
|
return /*#__PURE__*/ _jsx("div", {
|
|
46
46
|
"data-slot": "split-view",
|
|
47
|
-
className: cn('lg:min-h-
|
|
47
|
+
className: cn('lg:min-h-112 relative', className),
|
|
48
48
|
children: /*#__PURE__*/ _jsx("ol", {
|
|
49
49
|
"data-slot": "split-list",
|
|
50
50
|
"aria-label": label,
|
|
51
|
-
className: "m-0 p-0 lg:max-h-
|
|
51
|
+
className: "m-0 p-0 lg:max-h-112 lg:w-2/5 lg:overflow-y-auto list-none",
|
|
52
52
|
children: items.map((item, at)=>{
|
|
53
53
|
const chosen = at === index;
|
|
54
54
|
return /*#__PURE__*/ _jsxs("li", {
|
|
@@ -66,7 +66,7 @@ import { cn } from '../../utils/cn.js';
|
|
|
66
66
|
}),
|
|
67
67
|
chosen && /*#__PURE__*/ _jsx("div", {
|
|
68
68
|
"data-slot": "split-detail",
|
|
69
|
-
className: "lg:absolute lg:top-0 lg:right-0 lg:max-h-
|
|
69
|
+
className: "lg:absolute lg:top-0 lg:right-0 lg:max-h-112 lg:w-7/12 lg:overflow-y-auto lg:p-0 px-xs py-s",
|
|
70
70
|
children: item.detail
|
|
71
71
|
})
|
|
72
72
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/ui/molecules/split-view/split-view.tsx"],"sourcesContent":["'use client';\n\nimport type { KeyboardEvent, MouseEvent, ReactNode } from 'react';\n\nimport { cn } from '../../utils/cn.js';\n\nexport interface SplitViewItem {\n readonly id: string;\n /** What the list shows of the item: its number and title, say. */\n readonly head: ReactNode;\n /** What the pane shows once the item is chosen. */\n readonly detail: ReactNode;\n /** Where the item lives on its own: followed without scripting. */\n readonly href: string;\n}\n\n/** The keys that move the choice, and where each moves it. */\nconst MOVES: Readonly<\n Record<string, (index: number, count: number) => number>\n> = {\n ArrowDown: (index, count) => Math.min(index + 1, count - 1),\n ArrowUp: index => Math.max(index - 1, 0),\n Home: () => 0,\n End: (_, count) => count - 1,\n};\n\n/**\n * A list beside a reading pane: the chosen item's detail shows next to the\n * list on a wide screen, and under its own row on a narrow one, where the\n * list reads as an accordion.\n *\n * One markup for both: the chosen row carries its detail. On a wide screen\n * the list is a column of fixed height that scrolls, and the detail is placed\n * against the whole view, so the list's overflow neither clips nor scrolls it.\n *\n * Each row is a link to the item's own page, which is what a visitor without\n * scripting follows. With it, a plain click chooses instead, and ↑, ↓, Home\n * and End move the choice, focus following it (one row in the tab order).\n * Parts carry `data-slot` (`split-view`, `split-list`, `split-row`,\n * `split-trigger`, `split-detail`) for a page to restyle.\n */\nexport function SplitView({\n label,\n items,\n selected,\n onSelect,\n className,\n}: {\n /** The list's accessible name. */\n label: string;\n items: readonly SplitViewItem[];\n /** The chosen item's id; an unknown one chooses nothing. */\n selected: string | undefined;\n onSelect: (id: string) => void;\n className?: string;\n}) {\n const index = items.findIndex(item => item.id === selected);\n const focusable = index === -1 ? 0 : index;\n\n const choose = (event: MouseEvent, id: string) => {\n // A new tab or window is the link's own business.\n if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey)\n return;\n event.preventDefault();\n onSelect(id);\n };\n\n // On each trigger rather than the list: a list is not interactive, so the\n // keys belong to the row that has focus.\n const move = (event: KeyboardEvent<HTMLAnchorElement>) => {\n const to = MOVES[event.key];\n if (to === undefined) return;\n event.preventDefault();\n const next = to(focusable, items.length);\n const triggers = event.currentTarget\n .closest('[data-slot=\"split-list\"]')\n ?.querySelectorAll<HTMLElement>('[data-slot=\"split-trigger\"]');\n triggers?.[next]?.focus();\n onSelect((items[next] as SplitViewItem).id);\n };\n\n return (\n <div\n data-slot=\"split-view\"\n className={cn('lg:min-h-
|
|
1
|
+
{"version":3,"sources":["../../../../src/ui/molecules/split-view/split-view.tsx"],"sourcesContent":["'use client';\n\nimport type { KeyboardEvent, MouseEvent, ReactNode } from 'react';\n\nimport { cn } from '../../utils/cn.js';\n\nexport interface SplitViewItem {\n readonly id: string;\n /** What the list shows of the item: its number and title, say. */\n readonly head: ReactNode;\n /** What the pane shows once the item is chosen. */\n readonly detail: ReactNode;\n /** Where the item lives on its own: followed without scripting. */\n readonly href: string;\n}\n\n/** The keys that move the choice, and where each moves it. */\nconst MOVES: Readonly<\n Record<string, (index: number, count: number) => number>\n> = {\n ArrowDown: (index, count) => Math.min(index + 1, count - 1),\n ArrowUp: index => Math.max(index - 1, 0),\n Home: () => 0,\n End: (_, count) => count - 1,\n};\n\n/**\n * A list beside a reading pane: the chosen item's detail shows next to the\n * list on a wide screen, and under its own row on a narrow one, where the\n * list reads as an accordion.\n *\n * One markup for both: the chosen row carries its detail. On a wide screen\n * the list is a column of fixed height that scrolls, and the detail is placed\n * against the whole view, so the list's overflow neither clips nor scrolls it.\n *\n * Each row is a link to the item's own page, which is what a visitor without\n * scripting follows. With it, a plain click chooses instead, and ↑, ↓, Home\n * and End move the choice, focus following it (one row in the tab order).\n * Parts carry `data-slot` (`split-view`, `split-list`, `split-row`,\n * `split-trigger`, `split-detail`) for a page to restyle.\n */\nexport function SplitView({\n label,\n items,\n selected,\n onSelect,\n className,\n}: {\n /** The list's accessible name. */\n label: string;\n items: readonly SplitViewItem[];\n /** The chosen item's id; an unknown one chooses nothing. */\n selected: string | undefined;\n onSelect: (id: string) => void;\n className?: string;\n}) {\n const index = items.findIndex(item => item.id === selected);\n const focusable = index === -1 ? 0 : index;\n\n const choose = (event: MouseEvent, id: string) => {\n // A new tab or window is the link's own business.\n if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey)\n return;\n event.preventDefault();\n onSelect(id);\n };\n\n // On each trigger rather than the list: a list is not interactive, so the\n // keys belong to the row that has focus.\n const move = (event: KeyboardEvent<HTMLAnchorElement>) => {\n const to = MOVES[event.key];\n if (to === undefined) return;\n event.preventDefault();\n const next = to(focusable, items.length);\n const triggers = event.currentTarget\n .closest('[data-slot=\"split-list\"]')\n ?.querySelectorAll<HTMLElement>('[data-slot=\"split-trigger\"]');\n triggers?.[next]?.focus();\n onSelect((items[next] as SplitViewItem).id);\n };\n\n return (\n <div\n data-slot=\"split-view\"\n className={cn('lg:min-h-112 relative', className)}\n >\n <ol\n data-slot=\"split-list\"\n aria-label={label}\n className=\"m-0 p-0 lg:max-h-112 lg:w-2/5 lg:overflow-y-auto list-none\"\n >\n {items.map((item, at) => {\n const chosen = at === index;\n return (\n <li key={item.id} data-slot=\"split-row\">\n <a\n href={item.href}\n data-slot=\"split-trigger\"\n aria-current={chosen ? 'true' : undefined}\n tabIndex={at === focusable ? 0 : -1}\n onClick={event => choose(event, item.id)}\n onKeyDown={move}\n className=\"block rounded-md px-xs py-2xs text-inherit no-underline focus-ring hover:bg-[color-mix(in_srgb,var(--color-content)_6%,transparent)] aria-[current]:bg-[color-mix(in_srgb,var(--color-primary)_14%,transparent)]\"\n >\n {item.head}\n </a>\n {chosen && (\n <div\n data-slot=\"split-detail\"\n className=\"lg:absolute lg:top-0 lg:right-0 lg:max-h-112 lg:w-7/12 lg:overflow-y-auto lg:p-0 px-xs py-s\"\n >\n {item.detail}\n </div>\n )}\n </li>\n );\n })}\n </ol>\n </div>\n );\n}\n"],"names":["cn","MOVES","ArrowDown","index","count","Math","min","ArrowUp","max","Home","End","_","SplitView","label","items","selected","onSelect","className","findIndex","item","id","focusable","choose","event","button","metaKey","ctrlKey","shiftKey","preventDefault","move","triggers","to","key","undefined","next","length","currentTarget","closest","querySelectorAll","focus","div","data-slot","ol","aria-label","map","at","chosen","li","a","href","aria-current","tabIndex","onClick","onKeyDown","head","detail"],"mappings":"AAAA;;AAIA,SAASA,EAAE,QAAQ,oBAAoB;AAYvC,4DAA4D,GAC5D,MAAMC,QAEF;IACFC,WAAW,CAACC,OAAOC,QAAUC,KAAKC,GAAG,CAACH,QAAQ,GAAGC,QAAQ;IACzDG,SAASJ,CAAAA,QAASE,KAAKG,GAAG,CAACL,QAAQ,GAAG;IACtCM,MAAM,IAAM;IACZC,KAAK,CAACC,GAAGP,QAAUA,QAAQ;AAC7B;AAEA;;;;;;;;;;;;;;CAcC,GACD,OAAO,SAASQ,UAAU,EACxBC,KAAK,EACLC,KAAK,EACLC,QAAQ,EACRC,QAAQ,EACRC,SAAS,EASV;IACC,MAAMd,QAAQW,MAAMI,SAAS,CAACC,CAAAA,OAAQA,KAAKC,EAAE,KAAKL;IAClD,MAAMM,YAAYlB,UAAU,CAAC,IAAI,IAAIA;IAErC,MAAMmB,SAAS,CAACC,OAAmBH;QACjC,kDAAkD;QAClD,IAAIG,MAAMC,MAAM,KAAK,KAAKD,MAAME,OAAO,IAAIF,MAAMG,OAAO,IAAIH,MAAMI,QAAQ,EACxE;QACFJ,MAAMK,cAAc;QACpBZ,SAASI;IACX;IAEA,0EAA0E;IAC1E,yCAAyC;IACzC,MAAMS,OAAO,CAACN;YAKKA,8BAGjBO;QAPA,MAAMC,KAAK9B,KAAK,CAACsB,MAAMS,GAAG,CAAC;QAC3B,IAAID,OAAOE,WAAW;QACtBV,MAAMK,cAAc;QACpB,MAAMM,OAAOH,GAAGV,WAAWP,MAAMqB,MAAM;QACvC,MAAML,YAAWP,+BAAAA,MAAMa,aAAa,CACjCC,OAAO,CAAC,gDADMd,6BAEbe,gBAAgB,CAAc;QAClCR,6BAAAA,iBAAAA,QAAU,CAACI,KAAK,qBAAhBJ,eAAkBS,KAAK;QACvBvB,SAAS,AAACF,KAAK,CAACoB,KAAK,CAAmBd,EAAE;IAC5C;IAEA,qBACE,KAACoB;QACCC,aAAU;QACVxB,WAAWjB,GAAG,yBAAyBiB;kBAEvC,cAAA,KAACyB;YACCD,aAAU;YACVE,cAAY9B;YACZI,WAAU;sBAETH,MAAM8B,GAAG,CAAC,CAACzB,MAAM0B;gBAChB,MAAMC,SAASD,OAAO1C;gBACtB,qBACE,MAAC4C;oBAAiBN,aAAU;;sCAC1B,KAACO;4BACCC,MAAM9B,KAAK8B,IAAI;4BACfR,aAAU;4BACVS,gBAAcJ,SAAS,SAASb;4BAChCkB,UAAUN,OAAOxB,YAAY,IAAI,CAAC;4BAClC+B,SAAS7B,CAAAA,QAASD,OAAOC,OAAOJ,KAAKC,EAAE;4BACvCiC,WAAWxB;4BACXZ,WAAU;sCAETE,KAAKmC,IAAI;;wBAEXR,wBACC,KAACN;4BACCC,aAAU;4BACVxB,WAAU;sCAETE,KAAKoC,MAAM;;;mBAjBTpC,KAAKC,EAAE;YAsBpB;;;AAIR"}
|