@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
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ComponentPropsWithoutRef, ReactNode } from 'react';
|
|
2
|
+
export interface EmptyStateProps extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {
|
|
3
|
+
/** One sentence: what is not here, and why when it is not obvious. */
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
/** The one thing to do about it — create the first record, clear a filter. */
|
|
6
|
+
action?: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* What a region shows when it holds nothing: one sentence, and at most one way
|
|
10
|
+
* forward. Not a failure — a region that could not load says so with an
|
|
11
|
+
* `Alert` instead, because an empty result and a dead backend must never look
|
|
12
|
+
* alike. Server-safe.
|
|
13
|
+
*/
|
|
14
|
+
export declare function EmptyState({ action, className, children, ...props }: EmptyStateProps): import("react").JSX.Element;
|
|
15
|
+
//# sourceMappingURL=empty-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"empty-state.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/empty-state/empty-state.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIjE,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAC3C,wBAAwB,CAAC,KAAK,CAAC,EAC/B,UAAU,CACX;IACC,sEAAsE;IACtE,QAAQ,EAAE,SAAS,CAAC;IACpB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,eAAe,+BAejB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
|
|
3
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { cn } from '../../utils/cn.js';
|
|
5
|
+
/**
|
|
6
|
+
* What a region shows when it holds nothing: one sentence, and at most one way
|
|
7
|
+
* forward. Not a failure — a region that could not load says so with an
|
|
8
|
+
* `Alert` instead, because an empty result and a dead backend must never look
|
|
9
|
+
* alike. Server-safe.
|
|
10
|
+
*/ export function EmptyState(_0) {
|
|
11
|
+
let { action, className, children } = _0, props = _object_without_properties_loose(_0, [
|
|
12
|
+
"action",
|
|
13
|
+
"className",
|
|
14
|
+
"children"
|
|
15
|
+
]);
|
|
16
|
+
return /*#__PURE__*/ _jsxs("div", _extends({
|
|
17
|
+
className: cn('flex flex-col items-center gap-s rounded-lg border border-dashed border-border px-m py-l text-center', className)
|
|
18
|
+
}, props, {
|
|
19
|
+
children: [
|
|
20
|
+
/*#__PURE__*/ _jsx("p", {
|
|
21
|
+
className: "m-0 max-w-(--measure) text-step-sm text-content-muted",
|
|
22
|
+
children: children
|
|
23
|
+
}),
|
|
24
|
+
action
|
|
25
|
+
]
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=empty-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/ui/molecules/empty-state/empty-state.tsx"],"sourcesContent":["import type { ComponentPropsWithoutRef, ReactNode } from 'react';\n\nimport { cn } from '../../utils/cn.js';\n\nexport interface EmptyStateProps extends Omit<\n ComponentPropsWithoutRef<'div'>,\n 'children'\n> {\n /** One sentence: what is not here, and why when it is not obvious. */\n children: ReactNode;\n /** The one thing to do about it — create the first record, clear a filter. */\n action?: ReactNode;\n}\n\n/**\n * What a region shows when it holds nothing: one sentence, and at most one way\n * forward. Not a failure — a region that could not load says so with an\n * `Alert` instead, because an empty result and a dead backend must never look\n * alike. Server-safe.\n */\nexport function EmptyState({\n action,\n className,\n children,\n ...props\n}: EmptyStateProps) {\n return (\n <div\n className={cn(\n 'flex flex-col items-center gap-s rounded-lg border border-dashed border-border px-m py-l text-center',\n className,\n )}\n {...props}\n >\n <p className=\"m-0 max-w-(--measure) text-step-sm text-content-muted\">\n {children}\n </p>\n {action}\n </div>\n );\n}\n"],"names":["cn","EmptyState","action","className","children","props","div","p"],"mappings":";;;AAEA,SAASA,EAAE,QAAQ,oBAAoB;AAYvC;;;;;CAKC,GACD,OAAO,SAASC,WAAW,EAKT;QALS,EACzBC,MAAM,EACNC,SAAS,EACTC,QAAQ,EAEQ,OADbC;;;;;IAEH,qBACE,MAACC;QACCH,WAAWH,GACT,wGACAG;OAEEE;;0BAEJ,KAACE;gBAAEJ,WAAU;0BACVC;;YAEFF;;;AAGP"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/empty-state/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/ui/molecules/empty-state/index.ts"],"sourcesContent":["export * from './empty-state.js';\n"],"names":[],"mappings":"AAAA,cAAc,mBAAmB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity-link-input.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/entity-link-input/entity-link-input.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,MAAM,EACN,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,eAAe,CAAC;AAcvB,MAAM,WAAW,oBAAoB,CAAC,OAAO,SAAS,MAAM;IAC1D,+DAA+D;IAC/D,UAAU,EAAE,qBAAqB,CAAC;IAClC,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAClC,4CAA4C;IAC5C,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACpC,gCAAgC;IAChC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,0CAA0C;IAC1C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAsBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAAC,OAAO,SAAS,MAAM,EAAE,EACtD,UAAU,EACV,KAAK,EACL,MAAM,EACN,QAAQ,EACR,OAAO,EACP,EAAE,EACF,QAAgB,GACjB,EAAE,oBAAoB,CAAC,OAAO,CAAC,+
|
|
1
|
+
{"version":3,"file":"entity-link-input.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/entity-link-input/entity-link-input.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,MAAM,EACN,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,eAAe,CAAC;AAcvB,MAAM,WAAW,oBAAoB,CAAC,OAAO,SAAS,MAAM;IAC1D,+DAA+D;IAC/D,UAAU,EAAE,qBAAqB,CAAC;IAClC,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAClC,4CAA4C;IAC5C,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACpC,gCAAgC;IAChC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,0CAA0C;IAC1C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAsBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAAC,OAAO,SAAS,MAAM,EAAE,EACtD,UAAU,EACV,KAAK,EACL,MAAM,EACN,QAAQ,EACR,OAAO,EACP,EAAE,EACF,QAAgB,GACjB,EAAE,oBAAoB,CAAC,OAAO,CAAC,+BAoJ/B"}
|
|
@@ -97,7 +97,7 @@ import { LoadingBoundary } from '../loading-boundary/index.js';
|
|
|
97
97
|
disabled: disabled,
|
|
98
98
|
onChange: (event)=>source.quick.setTerm(event.currentTarget.value),
|
|
99
99
|
className: [
|
|
100
|
-
'w-full rounded-lg border border-border bg-surface-elevated px-2xs py-3xs',
|
|
100
|
+
'min-h-(--target-min) w-full rounded-lg border border-border-control bg-surface-elevated px-2xs py-3xs',
|
|
101
101
|
'text-step-sm text-content',
|
|
102
102
|
'focus-ring',
|
|
103
103
|
'disabled:cursor-not-allowed disabled:opacity-50'
|
|
@@ -112,7 +112,7 @@ import { LoadingBoundary } from '../loading-boundary/index.js';
|
|
|
112
112
|
}),
|
|
113
113
|
/*#__PURE__*/ _jsxs(ComboboxOptions, {
|
|
114
114
|
className: [
|
|
115
|
-
'max-h-64 absolute z-
|
|
115
|
+
'max-h-64 absolute z-(--z-dropdown) mt-3xs w-full overflow-auto',
|
|
116
116
|
'rounded-lg border border-border bg-surface-elevated p-3xs shadow-overlay',
|
|
117
117
|
// The panel itself is a focus-managed CONTAINER, not a target: the ring
|
|
118
118
|
// belongs on the item inside it. Stripping the outline here is
|
|
@@ -134,8 +134,11 @@ import { LoadingBoundary } from '../loading-boundary/index.js';
|
|
|
134
134
|
source.quick.options.map((option)=>/*#__PURE__*/ _jsx(ComboboxOption, {
|
|
135
135
|
value: option,
|
|
136
136
|
className: [
|
|
137
|
-
'cursor-pointer rounded-md px-2xs py-3xs text-step-sm text-content',
|
|
138
|
-
|
|
137
|
+
'flex min-h-(--target-min) cursor-pointer items-center rounded-md border-l-2 border-transparent px-2xs py-3xs text-step-sm text-content',
|
|
138
|
+
// Active: the focus ring. Chosen but not under the
|
|
139
|
+
// keyboard: a `selected` edge, 3:1 on the panel.
|
|
140
|
+
'focus-ring data-focus:bg-surface data-focus:-outline-offset-2',
|
|
141
|
+
'data-selected:border-selected'
|
|
139
142
|
].join(' '),
|
|
140
143
|
children: source.labelOf(option)
|
|
141
144
|
}, String(option.id)))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/ui/molecules/entity-link-input/entity-link-input.tsx"],"sourcesContent":["'use client';\n\nimport type {\n Entity,\n EntityFieldDescriptor,\n EntityLinkSource,\n} from '@entifix/core';\nimport {\n Combobox,\n ComboboxButton,\n ComboboxInput,\n ComboboxOption,\n ComboboxOptions,\n} from '@headlessui/react';\n\nimport { useErrorMessage, useT } from '../../../i18n/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { EntityLinkPicker } from '../entity-link-picker/index.js';\nimport { LoadingBoundary } from '../loading-boundary/index.js';\n\nexport interface EntityLinkInputProps<TTarget extends Entity> {\n /** The relation being edited. Its label names the controls. */\n descriptor: EntityFieldDescriptor;\n /** The held foreign key, as the draft carries it. `''` means unassigned. */\n value: string;\n source: EntityLinkSource<TTarget>;\n /** A target was chosen — in either mode. */\n onSelect: (entity: TTarget) => void;\n /** The relation was emptied. */\n onClear: () => void;\n /** The id the field's label points at. */\n id?: string;\n disabled?: boolean;\n}\n\n/** Chevron — the quick search. Inline so the package ships no icon dependency. */\nfunction ChevronIcon() {\n return (\n <svg aria-hidden viewBox=\"0 0 20 20\" className=\"size-4 fill-current\">\n <path d=\"M5.5 7.5 10 12l4.5-4.5z\" />\n </svg>\n );\n}\n\n/** Ellipsis — the browse dialog, the same affordance a desktop app uses. */\nfunction EllipsisIcon() {\n return (\n <svg aria-hidden viewBox=\"0 0 20 20\" className=\"size-4 fill-current\">\n <circle cx=\"4\" cy=\"10\" r=\"1.5\" />\n <circle cx=\"10\" cy=\"10\" r=\"1.5\" />\n <circle cx=\"16\" cy=\"10\" r=\"1.5\" />\n </svg>\n );\n}\n\n/**\n * The editor for a to-one relation: what the value *is*, plus the two ways to\n * change it.\n *\n * - the chevron opens a type-ahead over the target entity — \"I know roughly what\n * it is called\";\n * - the ellipsis opens the target's full table in a dialog — \"I need to filter\n * the catalog to find it\".\n *\n * It is presentational. Every option, loading flag and error arrives through\n * {@link EntityLinkSource}, which the integration layer produces; this component\n * cannot fetch, and never decides how the relation is written back — it reports\n * the chosen instance and the form's reconstruction step applies the entity's own\n * `linkSerialization` policy.\n *\n * The displayed text is the target's label when one is known and the bare foreign\n * key when it is not, so a draft restored before its label resolves still shows\n * *something* true rather than an empty box.\n */\nexport function EntityLinkInput<TTarget extends Entity>({\n descriptor,\n value,\n source,\n onSelect,\n onClear,\n id,\n disabled = false,\n}: EntityLinkInputProps<TTarget>) {\n const t = useT();\n const errorMessage = useErrorMessage();\n\n const assigned = value !== '';\n const label = source.selected.label ?? (assigned ? value : '');\n const display = source.selected.isLoading\n ? t('link.loading')\n : label === ''\n ? t('link.empty')\n : label;\n\n /**\n * Headless UI reports `null` when the search is abandoned (escape, blur). That\n * is not a request to empty the relation — clearing is the explicit action\n * beside the input — so it leaves the held value alone.\n */\n const handleSelect = (entity: TTarget | null) => {\n if (entity === null) return;\n onSelect(entity);\n source.quick.setTerm('');\n };\n\n return (\n <div className=\"flex flex-col gap-3xs\">\n <div className=\"flex items-stretch gap-3xs\">\n <div className=\"relative flex-1\">\n <Combobox<TTarget | null>\n value={null}\n onChange={handleSelect}\n disabled={disabled}\n immediate\n >\n {/*\n The input edits the *search term*, never the value: the value is a\n foreign key, which is not something a user types. So it displays the\n resolved label while idle and the term while searching.\n */}\n <ComboboxInput\n id={id}\n aria-label={t('link.search', { field: descriptor.label })}\n placeholder={display}\n value={source.quick.term}\n disabled={disabled}\n onChange={event =>\n source.quick.setTerm(event.currentTarget.value)\n }\n className={[\n 'w-full rounded-lg border border-border bg-surface-elevated px-2xs py-3xs',\n 'text-step-sm text-content',\n 'focus-ring',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n ].join(' ')}\n />\n <ComboboxButton\n aria-label={t('link.suggestAria', { field: descriptor.label })}\n className=\"inset-y-0 right-0 absolute flex items-center px-2xs text-content-muted\"\n >\n <ChevronIcon />\n </ComboboxButton>\n <ComboboxOptions\n className={[\n 'max-h-64 absolute z-50 mt-3xs w-full overflow-auto',\n 'rounded-lg border border-border bg-surface-elevated p-3xs shadow-overlay',\n // The panel itself is a focus-managed CONTAINER, not a target: the ring\n // belongs on the item inside it. Stripping the outline here is\n // correct, and is not a missing `focus-ring`.\n 'focus:outline-none',\n ].join(' ')}\n >\n {source.quick.isLoading && (\n <LoadingBoundary\n isLoading\n lines={2}\n label={t('link.loading')}\n className=\"px-2xs py-3xs\"\n >\n {null}\n </LoadingBoundary>\n )}\n {!source.quick.isLoading && source.quick.options.length === 0 && (\n <div className=\"px-2xs py-3xs text-step-sm text-content-muted\">\n {t('link.noResults')}\n </div>\n )}\n {source.quick.options.map(option => (\n <ComboboxOption\n key={String(option.id)}\n value={option}\n className={[\n 'cursor-pointer rounded-md px-2xs py-3xs text-step-sm text-content',\n 'data-focus:bg-surface',\n ].join(' ')}\n >\n {source.labelOf(option)}\n </ComboboxOption>\n ))}\n </ComboboxOptions>\n </Combobox>\n </div>\n\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n disabled={disabled}\n aria-label={t('link.browseAria', { field: descriptor.label })}\n onClick={source.browse.open}\n >\n <EllipsisIcon />\n </Button>\n {/* Clearing is only offered when there is something to clear — and a\n required relation still offers it, because `required` is the form's\n rule to report, not the input's to enforce. */}\n {assigned && !disabled && (\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={onClear}>\n {t('link.clear', { field: descriptor.label })}\n </Button>\n )}\n </div>\n\n {/* The held value, always readable — the combobox input shows the term. */}\n <span\n data-testid={`entity-link-value-${descriptor.name}`}\n className=\"text-step-sm text-content\"\n >\n {display}\n </span>\n\n {source.quick.error && (\n <span role=\"alert\" className=\"text-step-sm text-danger\">\n {errorMessage(source.quick.error)}\n </span>\n )}\n\n <EntityLinkPicker<TTarget>\n descriptor={descriptor}\n source={source}\n onSelect={entity => {\n onSelect(entity);\n source.browse.close();\n }}\n />\n </div>\n );\n}\n"],"names":["Combobox","ComboboxButton","ComboboxInput","ComboboxOption","ComboboxOptions","useErrorMessage","useT","Button","EntityLinkPicker","LoadingBoundary","ChevronIcon","svg","aria-hidden","viewBox","className","path","d","EllipsisIcon","circle","cx","cy","r","EntityLinkInput","descriptor","value","source","onSelect","onClear","id","disabled","t","errorMessage","assigned","label","selected","display","isLoading","handleSelect","entity","quick","setTerm","div","onChange","immediate","aria-label","field","placeholder","term","event","currentTarget","join","lines","options","length","map","option","labelOf","String","type","variant","size","onClick","browse","open","span","data-testid","name","error","role","close"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/ui/molecules/entity-link-input/entity-link-input.tsx"],"sourcesContent":["'use client';\n\nimport type {\n Entity,\n EntityFieldDescriptor,\n EntityLinkSource,\n} from '@entifix/core';\nimport {\n Combobox,\n ComboboxButton,\n ComboboxInput,\n ComboboxOption,\n ComboboxOptions,\n} from '@headlessui/react';\n\nimport { useErrorMessage, useT } from '../../../i18n/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { EntityLinkPicker } from '../entity-link-picker/index.js';\nimport { LoadingBoundary } from '../loading-boundary/index.js';\n\nexport interface EntityLinkInputProps<TTarget extends Entity> {\n /** The relation being edited. Its label names the controls. */\n descriptor: EntityFieldDescriptor;\n /** The held foreign key, as the draft carries it. `''` means unassigned. */\n value: string;\n source: EntityLinkSource<TTarget>;\n /** A target was chosen — in either mode. */\n onSelect: (entity: TTarget) => void;\n /** The relation was emptied. */\n onClear: () => void;\n /** The id the field's label points at. */\n id?: string;\n disabled?: boolean;\n}\n\n/** Chevron — the quick search. Inline so the package ships no icon dependency. */\nfunction ChevronIcon() {\n return (\n <svg aria-hidden viewBox=\"0 0 20 20\" className=\"size-4 fill-current\">\n <path d=\"M5.5 7.5 10 12l4.5-4.5z\" />\n </svg>\n );\n}\n\n/** Ellipsis — the browse dialog, the same affordance a desktop app uses. */\nfunction EllipsisIcon() {\n return (\n <svg aria-hidden viewBox=\"0 0 20 20\" className=\"size-4 fill-current\">\n <circle cx=\"4\" cy=\"10\" r=\"1.5\" />\n <circle cx=\"10\" cy=\"10\" r=\"1.5\" />\n <circle cx=\"16\" cy=\"10\" r=\"1.5\" />\n </svg>\n );\n}\n\n/**\n * The editor for a to-one relation: what the value *is*, plus the two ways to\n * change it.\n *\n * - the chevron opens a type-ahead over the target entity — \"I know roughly what\n * it is called\";\n * - the ellipsis opens the target's full table in a dialog — \"I need to filter\n * the catalog to find it\".\n *\n * It is presentational. Every option, loading flag and error arrives through\n * {@link EntityLinkSource}, which the integration layer produces; this component\n * cannot fetch, and never decides how the relation is written back — it reports\n * the chosen instance and the form's reconstruction step applies the entity's own\n * `linkSerialization` policy.\n *\n * The displayed text is the target's label when one is known and the bare foreign\n * key when it is not, so a draft restored before its label resolves still shows\n * *something* true rather than an empty box.\n */\nexport function EntityLinkInput<TTarget extends Entity>({\n descriptor,\n value,\n source,\n onSelect,\n onClear,\n id,\n disabled = false,\n}: EntityLinkInputProps<TTarget>) {\n const t = useT();\n const errorMessage = useErrorMessage();\n\n const assigned = value !== '';\n const label = source.selected.label ?? (assigned ? value : '');\n const display = source.selected.isLoading\n ? t('link.loading')\n : label === ''\n ? t('link.empty')\n : label;\n\n /**\n * Headless UI reports `null` when the search is abandoned (escape, blur). That\n * is not a request to empty the relation — clearing is the explicit action\n * beside the input — so it leaves the held value alone.\n */\n const handleSelect = (entity: TTarget | null) => {\n if (entity === null) return;\n onSelect(entity);\n source.quick.setTerm('');\n };\n\n return (\n <div className=\"flex flex-col gap-3xs\">\n <div className=\"flex items-stretch gap-3xs\">\n <div className=\"relative flex-1\">\n <Combobox<TTarget | null>\n value={null}\n onChange={handleSelect}\n disabled={disabled}\n immediate\n >\n {/*\n The input edits the *search term*, never the value: the value is a\n foreign key, which is not something a user types. So it displays the\n resolved label while idle and the term while searching.\n */}\n <ComboboxInput\n id={id}\n aria-label={t('link.search', { field: descriptor.label })}\n placeholder={display}\n value={source.quick.term}\n disabled={disabled}\n onChange={event =>\n source.quick.setTerm(event.currentTarget.value)\n }\n className={[\n 'min-h-(--target-min) w-full rounded-lg border border-border-control bg-surface-elevated px-2xs py-3xs',\n 'text-step-sm text-content',\n 'focus-ring',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n ].join(' ')}\n />\n <ComboboxButton\n aria-label={t('link.suggestAria', { field: descriptor.label })}\n className=\"inset-y-0 right-0 absolute flex items-center px-2xs text-content-muted\"\n >\n <ChevronIcon />\n </ComboboxButton>\n <ComboboxOptions\n className={[\n 'max-h-64 absolute z-(--z-dropdown) mt-3xs w-full overflow-auto',\n 'rounded-lg border border-border bg-surface-elevated p-3xs shadow-overlay',\n // The panel itself is a focus-managed CONTAINER, not a target: the ring\n // belongs on the item inside it. Stripping the outline here is\n // correct, and is not a missing `focus-ring`.\n 'focus:outline-none',\n ].join(' ')}\n >\n {source.quick.isLoading && (\n <LoadingBoundary\n isLoading\n lines={2}\n label={t('link.loading')}\n className=\"px-2xs py-3xs\"\n >\n {null}\n </LoadingBoundary>\n )}\n {!source.quick.isLoading && source.quick.options.length === 0 && (\n <div className=\"px-2xs py-3xs text-step-sm text-content-muted\">\n {t('link.noResults')}\n </div>\n )}\n {source.quick.options.map(option => (\n <ComboboxOption\n key={String(option.id)}\n value={option}\n className={[\n 'flex min-h-(--target-min) cursor-pointer items-center rounded-md border-l-2 border-transparent px-2xs py-3xs text-step-sm text-content',\n // Active: the focus ring. Chosen but not under the\n // keyboard: a `selected` edge, 3:1 on the panel.\n 'focus-ring data-focus:bg-surface data-focus:-outline-offset-2',\n 'data-selected:border-selected',\n ].join(' ')}\n >\n {source.labelOf(option)}\n </ComboboxOption>\n ))}\n </ComboboxOptions>\n </Combobox>\n </div>\n\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n disabled={disabled}\n aria-label={t('link.browseAria', { field: descriptor.label })}\n onClick={source.browse.open}\n >\n <EllipsisIcon />\n </Button>\n {/* Clearing is only offered when there is something to clear — and a\n required relation still offers it, because `required` is the form's\n rule to report, not the input's to enforce. */}\n {assigned && !disabled && (\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={onClear}>\n {t('link.clear', { field: descriptor.label })}\n </Button>\n )}\n </div>\n\n {/* The held value, always readable — the combobox input shows the term. */}\n <span\n data-testid={`entity-link-value-${descriptor.name}`}\n className=\"text-step-sm text-content\"\n >\n {display}\n </span>\n\n {source.quick.error && (\n <span role=\"alert\" className=\"text-step-sm text-danger\">\n {errorMessage(source.quick.error)}\n </span>\n )}\n\n <EntityLinkPicker<TTarget>\n descriptor={descriptor}\n source={source}\n onSelect={entity => {\n onSelect(entity);\n source.browse.close();\n }}\n />\n </div>\n );\n}\n"],"names":["Combobox","ComboboxButton","ComboboxInput","ComboboxOption","ComboboxOptions","useErrorMessage","useT","Button","EntityLinkPicker","LoadingBoundary","ChevronIcon","svg","aria-hidden","viewBox","className","path","d","EllipsisIcon","circle","cx","cy","r","EntityLinkInput","descriptor","value","source","onSelect","onClear","id","disabled","t","errorMessage","assigned","label","selected","display","isLoading","handleSelect","entity","quick","setTerm","div","onChange","immediate","aria-label","field","placeholder","term","event","currentTarget","join","lines","options","length","map","option","labelOf","String","type","variant","size","onClick","browse","open","span","data-testid","name","error","role","close"],"mappings":"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"}
|
|
@@ -23,11 +23,11 @@ import { EntityTable } from '../../organisms/entity-table/index.js';
|
|
|
23
23
|
/*#__PURE__*/ _jsxs(Dialog, {
|
|
24
24
|
open: browse.isOpen,
|
|
25
25
|
onClose: browse.close,
|
|
26
|
-
className: "inset-0 fixed z-
|
|
26
|
+
className: "inset-0 fixed z-(--z-overlay) flex items-start justify-center overflow-y-auto p-s",
|
|
27
27
|
children: [
|
|
28
28
|
/*#__PURE__*/ _jsx("div", {
|
|
29
29
|
"aria-hidden": true,
|
|
30
|
-
className: "inset-0 bg-
|
|
30
|
+
className: "inset-0 fixed bg-scrim"
|
|
31
31
|
}),
|
|
32
32
|
/*#__PURE__*/ _jsxs(DialogPanel, {
|
|
33
33
|
className: "max-w-4xl relative w-full rounded-lg border border-border bg-surface p-s shadow-overlay",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/ui/molecules/entity-link-picker/entity-link-picker.tsx"],"sourcesContent":["'use client';\n\nimport type {\n Entity,\n EntityFieldDescriptor,\n EntityLinkSource,\n} from '@entifix/core';\nimport { Dialog, DialogPanel, DialogTitle } from '@headlessui/react';\n\nimport { useT } from '../../../i18n/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { EntityTable } from '../../organisms/entity-table/index.js';\n\nexport interface EntityLinkPickerProps<TTarget extends Entity> {\n /** The relation being set — its label names the dialog. */\n descriptor: EntityFieldDescriptor;\n source: EntityLinkSource<TTarget>;\n onSelect: (entity: TTarget) => void;\n}\n\n/**\n * The thorough half of setting a relation: the target entity's own table, with\n * its filters, sorting and paging, inside a dialog.\n *\n * It adds nothing to the table — that is the point. A picker that re-implemented\n * filtering would drift from the listing the user already knows, so this mounts\n * the same `EntityTable` and swaps navigation for selection through `onSelect`.\n * Everything it renders comes from `source.browse`, so it holds no fetch of its\n * own.\n */\nexport function EntityLinkPicker<TTarget extends Entity>({\n descriptor,\n source,\n onSelect,\n}: EntityLinkPickerProps<TTarget>) {\n const t = useT();\n const { browse } = source;\n\n return (\n // The dialog element itself fills the viewport rather than wrapping a\n // `fixed` child in a `relative` box: a zero-sized dialog is invisible to\n // anything measuring it — assistive tech and Playwright alike — even with a\n // painted panel inside it.\n <Dialog\n open={browse.isOpen}\n onClose={browse.close}\n className=\"inset-0 fixed z-
|
|
1
|
+
{"version":3,"sources":["../../../../src/ui/molecules/entity-link-picker/entity-link-picker.tsx"],"sourcesContent":["'use client';\n\nimport type {\n Entity,\n EntityFieldDescriptor,\n EntityLinkSource,\n} from '@entifix/core';\nimport { Dialog, DialogPanel, DialogTitle } from '@headlessui/react';\n\nimport { useT } from '../../../i18n/index.js';\nimport { Button } from '../../atoms/button/index.js';\nimport { EntityTable } from '../../organisms/entity-table/index.js';\n\nexport interface EntityLinkPickerProps<TTarget extends Entity> {\n /** The relation being set — its label names the dialog. */\n descriptor: EntityFieldDescriptor;\n source: EntityLinkSource<TTarget>;\n onSelect: (entity: TTarget) => void;\n}\n\n/**\n * The thorough half of setting a relation: the target entity's own table, with\n * its filters, sorting and paging, inside a dialog.\n *\n * It adds nothing to the table — that is the point. A picker that re-implemented\n * filtering would drift from the listing the user already knows, so this mounts\n * the same `EntityTable` and swaps navigation for selection through `onSelect`.\n * Everything it renders comes from `source.browse`, so it holds no fetch of its\n * own.\n */\nexport function EntityLinkPicker<TTarget extends Entity>({\n descriptor,\n source,\n onSelect,\n}: EntityLinkPickerProps<TTarget>) {\n const t = useT();\n const { browse } = source;\n\n return (\n // The dialog element itself fills the viewport rather than wrapping a\n // `fixed` child in a `relative` box: a zero-sized dialog is invisible to\n // anything measuring it — assistive tech and Playwright alike — even with a\n // painted panel inside it.\n <Dialog\n open={browse.isOpen}\n onClose={browse.close}\n className=\"inset-0 fixed z-(--z-overlay) flex items-start justify-center overflow-y-auto p-s\"\n >\n {/* Backdrop and panel are separate so a click outside closes the dialog\n without the table's own clicks bubbling into it. */}\n <div aria-hidden className=\"inset-0 fixed bg-scrim\" />\n <DialogPanel className=\"max-w-4xl relative w-full rounded-lg border border-border bg-surface p-s shadow-overlay\">\n <div className=\"flex items-center justify-between gap-s\">\n <DialogTitle className=\"text-step-1 font-semibold text-content\">\n {t('link.browseTitle', { field: descriptor.label })}\n </DialogTitle>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={browse.close}\n >\n {t('link.close')}\n </Button>\n </div>\n\n <EntityTable<TTarget>\n entityConstructor={source.entityConstructor}\n isLoading={browse.isLoading}\n error={browse.error}\n items={browse.items}\n totalItems={browse.totalItems}\n currentPage={browse.currentPage}\n pageSize={browse.pageSize}\n onPageChange={browse.onPageChange}\n onPageSizeChange={browse.onPageSizeChange}\n filtering={browse.filtering}\n sorting={browse.sorting}\n onFilteringChange={browse.onFilteringChange}\n onSortingChange={browse.onSortingChange}\n onSelect={onSelect}\n // Scoped so a picker's column personalization does not overwrite the\n // one the user set on the full listing of the same entity.\n preferencesKey={`link-picker:${descriptor.name}`}\n />\n </DialogPanel>\n </Dialog>\n );\n}\n"],"names":["Dialog","DialogPanel","DialogTitle","useT","Button","EntityTable","EntityLinkPicker","descriptor","source","onSelect","t","browse","open","isOpen","onClose","close","className","div","aria-hidden","field","label","type","variant","size","onClick","entityConstructor","isLoading","error","items","totalItems","currentPage","pageSize","onPageChange","onPageSizeChange","filtering","sorting","onFilteringChange","onSortingChange","preferencesKey","name"],"mappings":"AAAA;;AAOA,SAASA,MAAM,EAAEC,WAAW,EAAEC,WAAW,QAAQ,oBAAoB;AAErE,SAASC,IAAI,QAAQ,yBAAyB;AAC9C,SAASC,MAAM,QAAQ,8BAA8B;AACrD,SAASC,WAAW,QAAQ,wCAAwC;AASpE;;;;;;;;;CASC,GACD,OAAO,SAASC,iBAAyC,EACvDC,UAAU,EACVC,MAAM,EACNC,QAAQ,EACuB;IAC/B,MAAMC,IAAIP;IACV,MAAM,EAAEQ,MAAM,EAAE,GAAGH;IAEnB,OACE,sEAAsE;IACtE,yEAAyE;IACzE,4EAA4E;IAC5E,2BAA2B;kBAC3B,MAACR;QACCY,MAAMD,OAAOE,MAAM;QACnBC,SAASH,OAAOI,KAAK;QACrBC,WAAU;;0BAIV,KAACC;gBAAIC,aAAW;gBAACF,WAAU;;0BAC3B,MAACf;gBAAYe,WAAU;;kCACrB,MAACC;wBAAID,WAAU;;0CACb,KAACd;gCAAYc,WAAU;0CACpBN,EAAE,oBAAoB;oCAAES,OAAOZ,WAAWa,KAAK;gCAAC;;0CAEnD,KAAChB;gCACCiB,MAAK;gCACLC,SAAQ;gCACRC,MAAK;gCACLC,SAASb,OAAOI,KAAK;0CAEpBL,EAAE;;;;kCAIP,KAACL;wBACCoB,mBAAmBjB,OAAOiB,iBAAiB;wBAC3CC,WAAWf,OAAOe,SAAS;wBAC3BC,OAAOhB,OAAOgB,KAAK;wBACnBC,OAAOjB,OAAOiB,KAAK;wBACnBC,YAAYlB,OAAOkB,UAAU;wBAC7BC,aAAanB,OAAOmB,WAAW;wBAC/BC,UAAUpB,OAAOoB,QAAQ;wBACzBC,cAAcrB,OAAOqB,YAAY;wBACjCC,kBAAkBtB,OAAOsB,gBAAgB;wBACzCC,WAAWvB,OAAOuB,SAAS;wBAC3BC,SAASxB,OAAOwB,OAAO;wBACvBC,mBAAmBzB,OAAOyB,iBAAiB;wBAC3CC,iBAAiB1B,OAAO0B,eAAe;wBACvC5B,UAAUA;wBACV,qEAAqE;wBACrE,2DAA2D;wBAC3D6B,gBAAgB,CAAC,YAAY,EAAE/B,WAAWgC,IAAI,EAAE;;;;;;AAK1D"}
|
|
@@ -1,30 +1,43 @@
|
|
|
1
|
-
import type
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/** One line of a card: a member's label and its value. */
|
|
3
|
+
export interface EntityRecordCardMeta {
|
|
4
|
+
key: string;
|
|
5
|
+
label: ReactNode;
|
|
6
|
+
value: ReactNode;
|
|
5
7
|
}
|
|
6
8
|
export interface EntityRecordCardProps {
|
|
7
|
-
columns: readonly EntityRecordCardColumn[];
|
|
8
|
-
/** Renders one column's cell. Supplied by the caller so a card and a table
|
|
9
|
-
* row stay in agreement about custom renderers. */
|
|
10
|
-
renderCell: (column: EntityRecordCardColumn) => ReactNode;
|
|
11
|
-
/** Optional trailing actions (a link to the record, …). */
|
|
12
|
-
actions?: ReactNode;
|
|
13
9
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
* The record's heading — what it is read as, usually a link to it. A link
|
|
11
|
+
* here is stretched over the whole card, so the card is one target.
|
|
12
|
+
*/
|
|
13
|
+
title: ReactNode;
|
|
14
|
+
/** A line under the heading. */
|
|
15
|
+
subtitle?: ReactNode;
|
|
16
|
+
/** Short values beside the heading — a status. */
|
|
17
|
+
badges?: readonly {
|
|
18
|
+
key: string;
|
|
19
|
+
value: ReactNode;
|
|
20
|
+
}[];
|
|
21
|
+
/** The record's other members, as a description list. */
|
|
22
|
+
meta: readonly EntityRecordCardMeta[];
|
|
23
|
+
/**
|
|
24
|
+
* Above the heading: a selection box. It is not an action on the record —
|
|
25
|
+
* it decides whether the record is *in the set* the actions run over — so it
|
|
26
|
+
* does not sit with them.
|
|
20
27
|
*/
|
|
21
28
|
leading?: ReactNode;
|
|
29
|
+
/** Above the heading, at the end: the record's menu. */
|
|
30
|
+
actions?: ReactNode;
|
|
22
31
|
className?: string;
|
|
23
32
|
}
|
|
24
33
|
/**
|
|
25
|
-
* A record pivoted from a row into a
|
|
26
|
-
*
|
|
27
|
-
*
|
|
34
|
+
* A record pivoted from a row into a card: the narrow form of a table row,
|
|
35
|
+
* where a horizontal scroll would hide most columns.
|
|
36
|
+
*
|
|
37
|
+
* An `article` named by its `h3`, so a reader can move card by card with the
|
|
38
|
+
* heading keys and hears what each record is. The title's link is stretched
|
|
39
|
+
* over the card; the selection box and the menu sit above it, so they stay
|
|
40
|
+
* their own targets.
|
|
28
41
|
*/
|
|
29
|
-
export declare function EntityRecordCard({
|
|
42
|
+
export declare function EntityRecordCard({ title, subtitle, badges, meta, leading, actions, className, }: EntityRecordCardProps): import("react").JSX.Element;
|
|
30
43
|
//# sourceMappingURL=entity-record-card.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity-record-card.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/entity-record-card/entity-record-card.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"entity-record-card.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/entity-record-card/entity-record-card.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAS,MAAM,OAAO,CAAC;AAI9C,0DAA0D;AAC1D,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,SAAS,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,KAAK,EAAE,SAAS,CAAC;IACjB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,kDAAkD;IAClD,MAAM,CAAC,EAAE,SAAS;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,EAAE,CAAC;IACtD,yDAAyD;IACzD,IAAI,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACtC;;;;OAIG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,wDAAwD;IACxD,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,QAAQ,EACR,MAAW,EACX,IAAI,EACJ,OAAO,EACP,OAAO,EACP,SAAS,GACV,EAAE,qBAAqB,+BAyDvB"}
|
|
@@ -1,36 +1,69 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useId } from 'react';
|
|
2
3
|
import { cn } from '../../utils/cn.js';
|
|
3
4
|
/**
|
|
4
|
-
* A record pivoted from a row into a
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
* A record pivoted from a row into a card: the narrow form of a table row,
|
|
6
|
+
* where a horizontal scroll would hide most columns.
|
|
7
|
+
*
|
|
8
|
+
* An `article` named by its `h3`, so a reader can move card by card with the
|
|
9
|
+
* heading keys and hears what each record is. The title's link is stretched
|
|
10
|
+
* over the card; the selection box and the menu sit above it, so they stay
|
|
11
|
+
* their own targets.
|
|
12
|
+
*/ export function EntityRecordCard({ title, subtitle, badges = [], meta, leading, actions, className }) {
|
|
13
|
+
const titleId = useId();
|
|
14
|
+
return /*#__PURE__*/ _jsxs("article", {
|
|
15
|
+
"aria-labelledby": titleId,
|
|
16
|
+
className: cn('relative rounded-xl border border-border bg-surface-elevated p-s text-content shadow-edge focus-within:border-primary', className),
|
|
10
17
|
children: [
|
|
11
|
-
leading && /*#__PURE__*/
|
|
12
|
-
className: "mb-2xs flex",
|
|
13
|
-
children:
|
|
18
|
+
(leading !== undefined || actions !== undefined) && /*#__PURE__*/ _jsxs("div", {
|
|
19
|
+
className: "relative z-1 mb-2xs flex items-center justify-between gap-2xs",
|
|
20
|
+
children: [
|
|
21
|
+
/*#__PURE__*/ _jsx("div", {
|
|
22
|
+
className: "flex",
|
|
23
|
+
children: leading
|
|
24
|
+
}),
|
|
25
|
+
/*#__PURE__*/ _jsx("div", {
|
|
26
|
+
className: "flex",
|
|
27
|
+
children: actions
|
|
28
|
+
})
|
|
29
|
+
]
|
|
14
30
|
}),
|
|
15
|
-
/*#__PURE__*/
|
|
16
|
-
className: "flex flex-
|
|
17
|
-
children:
|
|
31
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
32
|
+
className: "flex flex-wrap items-baseline justify-between gap-2xs",
|
|
33
|
+
children: [
|
|
34
|
+
/*#__PURE__*/ _jsx("h3", {
|
|
35
|
+
id: titleId,
|
|
36
|
+
className: "m-0 [&_a]:after:inset-0 text-step-0 font-semibold [&_a]:after:absolute [&_a]:after:content-['']",
|
|
37
|
+
children: title
|
|
38
|
+
}),
|
|
39
|
+
badges.length > 0 && /*#__PURE__*/ _jsx("div", {
|
|
40
|
+
className: "flex flex-wrap gap-3xs",
|
|
41
|
+
children: badges.map((badge)=>/*#__PURE__*/ _jsx("span", {
|
|
42
|
+
className: "rounded-full border border-border px-2xs text-step-sm",
|
|
43
|
+
children: badge.value
|
|
44
|
+
}, badge.key))
|
|
45
|
+
})
|
|
46
|
+
]
|
|
47
|
+
}),
|
|
48
|
+
subtitle !== undefined && /*#__PURE__*/ _jsx("p", {
|
|
49
|
+
className: "m-0 text-step-sm text-content-muted",
|
|
50
|
+
children: subtitle
|
|
51
|
+
}),
|
|
52
|
+
meta.length > 0 && /*#__PURE__*/ _jsx("dl", {
|
|
53
|
+
className: "mt-2xs flex flex-col gap-2xs",
|
|
54
|
+
children: meta.map((line)=>/*#__PURE__*/ _jsxs("div", {
|
|
18
55
|
className: "flex items-baseline justify-between gap-2xs",
|
|
19
56
|
children: [
|
|
20
57
|
/*#__PURE__*/ _jsx("dt", {
|
|
21
58
|
className: "tracking-wide text-step-xs text-content-muted uppercase",
|
|
22
|
-
children:
|
|
59
|
+
children: line.label
|
|
23
60
|
}),
|
|
24
61
|
/*#__PURE__*/ _jsx("dd", {
|
|
25
|
-
className: "text-right text-step-sm",
|
|
26
|
-
children:
|
|
62
|
+
className: "m-0 text-right text-step-sm",
|
|
63
|
+
children: line.value
|
|
27
64
|
})
|
|
28
65
|
]
|
|
29
|
-
},
|
|
30
|
-
}),
|
|
31
|
-
actions && /*#__PURE__*/ _jsx("div", {
|
|
32
|
-
className: "mt-2xs flex justify-end",
|
|
33
|
-
children: actions
|
|
66
|
+
}, line.key))
|
|
34
67
|
})
|
|
35
68
|
]
|
|
36
69
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/ui/molecules/entity-record-card/entity-record-card.tsx"],"sourcesContent":["import type
|
|
1
|
+
{"version":3,"sources":["../../../../src/ui/molecules/entity-record-card/entity-record-card.tsx"],"sourcesContent":["import { type ReactNode, useId } from 'react';\n\nimport { cn } from '../../utils/cn.js';\n\n/** One line of a card: a member's label and its value. */\nexport interface EntityRecordCardMeta {\n key: string;\n label: ReactNode;\n value: ReactNode;\n}\n\nexport interface EntityRecordCardProps {\n /**\n * The record's heading — what it is read as, usually a link to it. A link\n * here is stretched over the whole card, so the card is one target.\n */\n title: ReactNode;\n /** A line under the heading. */\n subtitle?: ReactNode;\n /** Short values beside the heading — a status. */\n badges?: readonly { key: string; value: ReactNode }[];\n /** The record's other members, as a description list. */\n meta: readonly EntityRecordCardMeta[];\n /**\n * Above the heading: a selection box. It is not an action on the record —\n * it decides whether the record is *in the set* the actions run over — so it\n * does not sit with them.\n */\n leading?: ReactNode;\n /** Above the heading, at the end: the record's menu. */\n actions?: ReactNode;\n className?: string;\n}\n\n/**\n * A record pivoted from a row into a card: the narrow form of a table row,\n * where a horizontal scroll would hide most columns.\n *\n * An `article` named by its `h3`, so a reader can move card by card with the\n * heading keys and hears what each record is. The title's link is stretched\n * over the card; the selection box and the menu sit above it, so they stay\n * their own targets.\n */\nexport function EntityRecordCard({\n title,\n subtitle,\n badges = [],\n meta,\n leading,\n actions,\n className,\n}: EntityRecordCardProps) {\n const titleId = useId();\n\n return (\n <article\n aria-labelledby={titleId}\n className={cn(\n 'relative rounded-xl border border-border bg-surface-elevated p-s text-content shadow-edge focus-within:border-primary',\n className,\n )}\n >\n {(leading !== undefined || actions !== undefined) && (\n <div className=\"relative z-1 mb-2xs flex items-center justify-between gap-2xs\">\n <div className=\"flex\">{leading}</div>\n <div className=\"flex\">{actions}</div>\n </div>\n )}\n <div className=\"flex flex-wrap items-baseline justify-between gap-2xs\">\n <h3\n id={titleId}\n className=\"m-0 [&_a]:after:inset-0 text-step-0 font-semibold [&_a]:after:absolute [&_a]:after:content-['']\"\n >\n {title}\n </h3>\n {badges.length > 0 && (\n <div className=\"flex flex-wrap gap-3xs\">\n {badges.map(badge => (\n <span\n key={badge.key}\n className=\"rounded-full border border-border px-2xs text-step-sm\"\n >\n {badge.value}\n </span>\n ))}\n </div>\n )}\n </div>\n {subtitle !== undefined && (\n <p className=\"m-0 text-step-sm text-content-muted\">{subtitle}</p>\n )}\n {meta.length > 0 && (\n <dl className=\"mt-2xs flex flex-col gap-2xs\">\n {meta.map(line => (\n <div\n key={line.key}\n className=\"flex items-baseline justify-between gap-2xs\"\n >\n <dt className=\"tracking-wide text-step-xs text-content-muted uppercase\">\n {line.label}\n </dt>\n <dd className=\"m-0 text-right text-step-sm\">{line.value}</dd>\n </div>\n ))}\n </dl>\n )}\n </article>\n );\n}\n"],"names":["useId","cn","EntityRecordCard","title","subtitle","badges","meta","leading","actions","className","titleId","article","aria-labelledby","undefined","div","h3","id","length","map","badge","span","value","key","p","dl","line","dt","label","dd"],"mappings":";AAAA,SAAyBA,KAAK,QAAQ,QAAQ;AAE9C,SAASC,EAAE,QAAQ,oBAAoB;AAgCvC;;;;;;;;CAQC,GACD,OAAO,SAASC,iBAAiB,EAC/BC,KAAK,EACLC,QAAQ,EACRC,SAAS,EAAE,EACXC,IAAI,EACJC,OAAO,EACPC,OAAO,EACPC,SAAS,EACa;IACtB,MAAMC,UAAUV;IAEhB,qBACE,MAACW;QACCC,mBAAiBF;QACjBD,WAAWR,GACT,yHACAQ;;YAGAF,CAAAA,YAAYM,aAAaL,YAAYK,SAAQ,mBAC7C,MAACC;gBAAIL,WAAU;;kCACb,KAACK;wBAAIL,WAAU;kCAAQF;;kCACvB,KAACO;wBAAIL,WAAU;kCAAQD;;;;0BAG3B,MAACM;gBAAIL,WAAU;;kCACb,KAACM;wBACCC,IAAIN;wBACJD,WAAU;kCAETN;;oBAEFE,OAAOY,MAAM,GAAG,mBACf,KAACH;wBAAIL,WAAU;kCACZJ,OAAOa,GAAG,CAACC,CAAAA,sBACV,KAACC;gCAECX,WAAU;0CAETU,MAAME,KAAK;+BAHPF,MAAMG,GAAG;;;;YASvBlB,aAAaS,2BACZ,KAACU;gBAAEd,WAAU;0BAAuCL;;YAErDE,KAAKW,MAAM,GAAG,mBACb,KAACO;gBAAGf,WAAU;0BACXH,KAAKY,GAAG,CAACO,CAAAA,qBACR,MAACX;wBAECL,WAAU;;0CAEV,KAACiB;gCAAGjB,WAAU;0CACXgB,KAAKE,KAAK;;0CAEb,KAACC;gCAAGnB,WAAU;0CAA+BgB,KAAKJ,KAAK;;;uBANlDI,KAAKH,GAAG;;;;AAa3B"}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import { type Entity, type EntityFieldDescriptor, type FilterGroup } from '@entifix/core';
|
|
1
|
+
import { type Entity, type EntityFacetCounts, type EntityFieldDescriptor, type FilterGroup } from '@entifix/core';
|
|
2
2
|
export interface FilterBuilderProps<TEntity extends Entity> {
|
|
3
3
|
/** Filterable members, already resolved from the entity metadata. */
|
|
4
4
|
descriptors: readonly EntityFieldDescriptor[];
|
|
5
5
|
/** The filtering currently applied, used to seed the rows. */
|
|
6
6
|
value?: FilterGroup<TEntity>;
|
|
7
7
|
onChange: (filtering: FilterGroup<TEntity>) => void;
|
|
8
|
+
/**
|
|
9
|
+
* How many records hold each value, by member — shown beside an enum's or a
|
|
10
|
+
* boolean's choices, so a reader sees what a choice would keep before
|
|
11
|
+
* applying it ([ADR 0012](../../../../../../../docs/adr/0012-facet-counts-are-a-port-of-their-own.md)).
|
|
12
|
+
*/
|
|
13
|
+
facets?: EntityFacetCounts;
|
|
8
14
|
}
|
|
9
15
|
/**
|
|
10
16
|
* Builds an `EntityFiltering` value from entity metadata: the member list, the
|
|
@@ -15,5 +21,5 @@ export interface FilterBuilderProps<TEntity extends Entity> {
|
|
|
15
21
|
* feeds a load request: emitting per keystroke would put one HTTP request on
|
|
16
22
|
* the wire per character typed.
|
|
17
23
|
*/
|
|
18
|
-
export declare function FilterBuilder<TEntity extends Entity>({ descriptors, value: applied, onChange, }: FilterBuilderProps<TEntity>): import("react").JSX.Element;
|
|
24
|
+
export declare function FilterBuilder<TEntity extends Entity>({ descriptors, value: applied, onChange, facets, }: FilterBuilderProps<TEntity>): import("react").JSX.Element;
|
|
19
25
|
//# sourceMappingURL=filter-builder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter-builder.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/filter-builder/filter-builder.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,MAAM,EACX,KAAK,qBAAqB,EAE1B,KAAK,WAAW,EAMjB,MAAM,eAAe,CAAC;AA+IvB,MAAM,WAAW,kBAAkB,CAAC,OAAO,SAAS,MAAM;IACxD,qEAAqE;IACrE,WAAW,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAC9C,8DAA8D;IAC9D,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7B,QAAQ,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"filter-builder.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/filter-builder/filter-builder.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,MAAM,EACX,KAAK,iBAAiB,EAEtB,KAAK,qBAAqB,EAE1B,KAAK,WAAW,EAMjB,MAAM,eAAe,CAAC;AA+IvB,MAAM,WAAW,kBAAkB,CAAC,OAAO,SAAS,MAAM;IACxD,qEAAqE;IACrE,WAAW,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAC9C,8DAA8D;IAC9D,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7B,QAAQ,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IACpD;;;;OAIG;IACH,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,OAAO,SAAS,MAAM,EAAE,EACpD,WAAW,EACX,KAAK,EAAE,OAAO,EACd,QAAQ,EACR,MAAM,GACP,EAAE,kBAAkB,CAAC,OAAO,CAAC,+BAgM7B"}
|
|
@@ -98,7 +98,7 @@ function coerce(raw, type) {
|
|
|
98
98
|
* Editing is a draft. `onChange` fires only on **Apply**, because the value
|
|
99
99
|
* feeds a load request: emitting per keystroke would put one HTTP request on
|
|
100
100
|
* the wire per character typed.
|
|
101
|
-
*/ export function FilterBuilder({ descriptors, value: applied, onChange }) {
|
|
101
|
+
*/ export function FilterBuilder({ descriptors, value: applied, onChange, facets }) {
|
|
102
102
|
var _ref;
|
|
103
103
|
const t = useT();
|
|
104
104
|
const idPrefix = useId();
|
|
@@ -218,6 +218,7 @@ function coerce(raw, type) {
|
|
|
218
218
|
}),
|
|
219
219
|
arity !== 'none' && /*#__PURE__*/ _jsx(FilterValueInput, {
|
|
220
220
|
descriptor: descriptor,
|
|
221
|
+
counts: facets == null ? void 0 : facets[descriptor.name],
|
|
221
222
|
arity: arity,
|
|
222
223
|
value: draft.value,
|
|
223
224
|
end: draft.end,
|
|
@@ -276,9 +277,17 @@ function coerce(raw, type) {
|
|
|
276
277
|
]
|
|
277
278
|
});
|
|
278
279
|
}
|
|
279
|
-
/** The value control the member's type calls for. */ function FilterValueInput({ descriptor, arity, value, end, onValueChange, onEndChange }) {
|
|
280
|
+
/** The value control the member's type calls for. */ function FilterValueInput({ descriptor, counts, arity, value, end, onValueChange, onEndChange }) {
|
|
280
281
|
const t = useT();
|
|
281
282
|
const enumLabel = useEnumLabel();
|
|
283
|
+
/** A choice's label, with how many records hold it when that is known. */ const counted = (label, option)=>{
|
|
284
|
+
var _counts_find;
|
|
285
|
+
const count = counts == null ? void 0 : (_counts_find = counts.find((entry)=>String(entry.value) === option)) == null ? void 0 : _counts_find.count;
|
|
286
|
+
return count === undefined ? label : t('filter.withCount', {
|
|
287
|
+
label,
|
|
288
|
+
count
|
|
289
|
+
});
|
|
290
|
+
};
|
|
282
291
|
if (descriptor.type === 'boolean') {
|
|
283
292
|
return /*#__PURE__*/ _jsxs(Select, {
|
|
284
293
|
"aria-label": t('filter.value'),
|
|
@@ -291,11 +300,11 @@ function coerce(raw, type) {
|
|
|
291
300
|
}),
|
|
292
301
|
/*#__PURE__*/ _jsx("option", {
|
|
293
302
|
value: "true",
|
|
294
|
-
children: t('value.yes')
|
|
303
|
+
children: counted(t('value.yes'), 'true')
|
|
295
304
|
}),
|
|
296
305
|
/*#__PURE__*/ _jsx("option", {
|
|
297
306
|
value: "false",
|
|
298
|
-
children: t('value.no')
|
|
307
|
+
children: counted(t('value.no'), 'false')
|
|
299
308
|
})
|
|
300
309
|
]
|
|
301
310
|
});
|
|
@@ -312,7 +321,7 @@ function coerce(raw, type) {
|
|
|
312
321
|
}),
|
|
313
322
|
descriptor.enumValues.map((option)=>/*#__PURE__*/ _jsx("option", {
|
|
314
323
|
value: option,
|
|
315
|
-
children: enumLabel(descriptor, option)
|
|
324
|
+
children: counted(enumLabel(descriptor, option), option)
|
|
316
325
|
}, option))
|
|
317
326
|
]
|
|
318
327
|
});
|