@eifi1/ui-kit 0.14.1 → 0.15.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 +4 -3
- package/dist/components/alert-banner.js +5 -2
- package/dist/components/alert-banner.js.map +1 -1
- package/dist/components/amount-input.d.ts +9 -1
- package/dist/components/amount-input.js +10 -4
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/autocomplete.js +9 -2
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/bulk-action-bar.js +6 -3
- package/dist/components/bulk-action-bar.js.map +1 -1
- package/dist/components/button-group.d.ts +1 -1
- package/dist/components/calculator.d.ts +1 -1
- package/dist/components/calendar-heatmap.js +5 -5
- package/dist/components/calendar-heatmap.js.map +1 -1
- package/dist/components/copy-button.d.ts +1 -1
- package/dist/components/data-table-cells.d.ts +1 -1
- package/dist/components/data-table-filter-popover.d.ts +1 -1
- package/dist/components/data-table-filter-popover.js +3 -3
- package/dist/components/data-table-filter-popover.js.map +1 -1
- package/dist/components/data-table-filters.d.ts +1 -1
- package/dist/components/data-table.d.ts +1 -1
- package/dist/components/data-table.js +12 -4
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/error-boundary.js +2 -1
- package/dist/components/error-boundary.js.map +1 -1
- package/dist/components/field.js +4 -1
- package/dist/components/field.js.map +1 -1
- package/dist/components/file-button.d.ts +1 -1
- package/dist/components/file-dropzone.d.ts +1 -1
- package/dist/components/form-actions.d.ts +1 -1
- package/dist/components/image-grid.d.ts +8 -1
- package/dist/components/image-grid.js +16 -3
- package/dist/components/image-grid.js.map +1 -1
- package/dist/components/measured-grid.js +2 -2
- package/dist/components/measured-grid.js.map +1 -1
- package/dist/components/money-field.d.ts +92 -0
- package/dist/components/money-field.js +40 -0
- package/dist/components/money-field.js.map +1 -0
- package/dist/components/multi-select.js +3 -0
- package/dist/components/multi-select.js.map +1 -1
- package/dist/components/number-field.d.ts +13 -2
- package/dist/components/number-field.js +4 -0
- package/dist/components/number-field.js.map +1 -1
- package/dist/components/number-input.d.ts +5 -2
- package/dist/components/number-input.js +11 -3
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numpad-sheet.d.ts +1 -1
- package/dist/components/page-header.js +29 -3
- package/dist/components/page-header.js.map +1 -1
- package/dist/components/series-chart.js +37 -8
- package/dist/components/series-chart.js.map +1 -1
- package/dist/components/settings-fields.d.ts +1 -1
- package/dist/components/stat-tile.js +3 -3
- package/dist/components/stat-tile.js.map +1 -1
- package/dist/components/text-link.d.ts +1 -1
- package/dist/components/text-link.js +2 -1
- package/dist/components/text-link.js.map +1 -1
- package/dist/components/time-input.d.ts +1 -1
- package/dist/components/treemap.d.ts +3 -2
- package/dist/components/treemap.js +14 -3
- package/dist/components/treemap.js.map +1 -1
- package/dist/components/ui.d.ts +1 -1
- package/dist/components/ui.js +44 -10
- package/dist/components/ui.js.map +1 -1
- package/dist/components/use-table-state.d.ts +1 -1
- package/dist/{data-table-Drun8Fk9.d.ts → data-table-CfVXtCeG.d.ts} +4 -3
- package/dist/data-table.d.ts +1 -1
- package/dist/feedback/feedback-dialog.d.ts +10 -1
- package/dist/feedback/feedback-dialog.js +13 -3
- package/dist/feedback/feedback-dialog.js.map +1 -1
- package/dist/feedback/feedback-thread.js +31 -12
- package/dist/feedback/feedback-thread.js.map +1 -1
- package/dist/hooks/use-file-drop.d.ts +1 -1
- package/dist/i18n/defaults.d.ts +1 -1
- package/dist/i18n/kit-labels.d.ts +1 -1
- package/dist/i18n/locales/de-CH-informal.d.ts +1 -1
- package/dist/i18n/locales/de-CH.d.ts +1 -1
- package/dist/i18n/locales/de-informal.d.ts +1 -1
- package/dist/i18n/locales/de.d.ts +1 -1
- package/dist/i18n/locales/de.js +1 -0
- package/dist/i18n/locales/de.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +1 -1
- package/dist/i18n/locales/es.js +1 -0
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +1 -1
- package/dist/i18n/locales/fr.js +1 -0
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.d.ts +1 -1
- package/dist/i18n/locales/hu.js +1 -0
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +1 -1
- package/dist/i18n/locales/it.js +1 -0
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +1 -1
- package/dist/i18n/locales/zh.js +1 -0
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/{kit-labels-Mz8zZHIF.d.ts → kit-labels-BHfRBbHs.d.ts} +5 -1
- package/dist/lib/document-navigation.d.ts +15 -0
- package/dist/lib/document-navigation.js +13 -0
- package/dist/lib/document-navigation.js.map +1 -0
- package/dist/lib/strip-fade.d.ts +31 -0
- package/dist/lib/strip-fade.js +54 -0
- package/dist/lib/strip-fade.js.map +1 -0
- package/dist/rhf/fields.d.ts +1 -1
- package/dist/rhf/form.d.ts +1 -1
- package/dist/rhf/form.js +1 -1
- package/dist/rhf/form.js.map +1 -1
- package/dist/rhf.d.ts +1 -1
- package/dist/shell/app-shell.d.ts +11 -2
- package/dist/shell/app-shell.js +20 -4
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/top-bar-brand.d.ts +1 -1
- package/dist/shell.d.ts +1 -1
- package/dist/wizard/stepper-nav.d.ts +1 -1
- package/dist/wizard/stepper-nav.js +14 -2
- package/dist/wizard/stepper-nav.js.map +1 -1
- package/dist/wizard.d.ts +1 -1
- package/package.json +7 -4
- package/src/components/alert-banner.tsx +10 -2
- package/src/components/amount-input.tsx +18 -4
- package/src/components/autocomplete.tsx +10 -1
- package/src/components/bulk-action-bar.tsx +12 -3
- package/src/components/calendar-heatmap.tsx +10 -5
- package/src/components/data-table-filter-popover.tsx +6 -3
- package/src/components/data-table.tsx +21 -7
- package/src/components/error-boundary.tsx +2 -1
- package/src/components/field.tsx +4 -1
- package/src/components/image-grid.tsx +30 -2
- package/src/components/measured-grid.tsx +3 -2
- package/src/components/money-field.tsx +75 -0
- package/src/components/multi-select.tsx +3 -0
- package/src/components/number-field.tsx +14 -0
- package/src/components/number-input.tsx +23 -4
- package/src/components/page-header.tsx +38 -3
- package/src/components/series-chart.tsx +56 -8
- package/src/components/stat-tile.tsx +8 -3
- package/src/components/text-link.tsx +2 -1
- package/src/components/treemap.tsx +30 -5
- package/src/components/ui.tsx +91 -11
- package/src/feedback/feedback-dialog.tsx +20 -2
- package/src/feedback/feedback-thread.tsx +36 -13
- package/src/i18n/locales/de.ts +1 -0
- package/src/i18n/locales/es.ts +1 -0
- package/src/i18n/locales/fr.ts +1 -0
- package/src/i18n/locales/hu.ts +1 -0
- package/src/i18n/locales/it.ts +1 -0
- package/src/i18n/locales/zh.ts +1 -0
- package/src/index.ts +1 -0
- package/src/lib/document-navigation.ts +17 -0
- package/src/lib/strip-fade.ts +82 -0
- package/src/rhf/form.tsx +3 -1
- package/src/shell/app-shell.tsx +34 -7
- package/src/wizard/stepper-nav.tsx +23 -2
package/dist/index.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export { AnchorRole, ChartRampReport, ContrastCheck, ContrastReport, DeriveOptio
|
|
|
25
25
|
export { ALTERNATIVE_PRESETS, DEFAULT_PRESET, DERIVED_PRESETS, IMPRINT_PRESET, PALETTES, PalettePreset, TokenSet, applyTokenSet, presetById } from './theme/palette-presets.js';
|
|
26
26
|
export { ThemeMode, ThemePreference, ThemeState, ThemeStore, applyPersistedTheme, createThemeStore } from './theme/theme-store.js';
|
|
27
27
|
export { PaletteStore, applyPersistedPalette, createPaletteStore } from './theme/palette-store.js';
|
|
28
|
-
export { A as AppShellLabels, B as Button, a as ButtonClassesOptions, b as ButtonLinkProps, c as ButtonProps, d as ButtonSize, e as ButtonTone, f as ButtonVariant, C as CalculatorLabels, g as Card, h as CardAction, i as CardActionProps, j as CardContent, k as CardContentProps, l as CardDescription, m as CardDescriptionProps, n as CardFooter, o as CardFooterProps, p as CardHeader, q as CardHeaderProps, r as CardProps, s as CardTitle, t as CardTitleProps, u as CardTone, v as ComboboxLabels, w as CommonLabels, x as CopyButton, y as CopyButtonLabels, z as CopyButtonProps, D as CurrencyLabels, E as DEFAULT_APP_SHELL_LABELS, F as DEFAULT_CALCULATOR_LABELS, G as DEFAULT_COMBOBOX_LABELS, H as DEFAULT_COMMON_LABELS, I as DEFAULT_COPY_BUTTON_LABELS, J as DEFAULT_CURRENCY_LABELS, K as DEFAULT_DATE_PICKER_LABELS, L as DEFAULT_FILE_LABELS, M as DEFAULT_FILE_PICKER_LABELS, N as DEFAULT_FORM_ACTIONS_LABELS, O as DEFAULT_MULTI_SELECT_LABELS, P as DEFAULT_PASSWORD_REVEAL_LABELS, Q as DEFAULT_PICKER_SHEET_LABELS, R as DEFAULT_SWIPEABLE_ROW_LABELS, S as DEFAULT_TABS_LABELS, T as DEFAULT_TOP_BAR_LABELS, U as DatePickerLabels, V as EmptyState, W as EmptyStateProps, X as FIELD_BASE, Y as FIELD_DISPLAY, Z as FIELD_FLOATING_PAD, _ as FIELD_INVALID, $ as FIELD_TRIGGER, a0 as FIELD_WRITABLE_LOOK, a1 as FLOATING_INPUT_CLASS, a2 as FLOATING_LABEL_CLASS, a3 as FLOATING_LABEL_STATIC, a4 as FieldChevron, a5 as FieldChevronProps, a6 as FieldHint, a7 as FieldHintProps, a8 as FieldLabel, a9 as FieldLabelProps, aa as FileButton, ab as FileButtonProps, ac as FileLabels, ad as FilePickerLabels, ae as FileRejection, af as FileRejectionReason, ag as FileScreenOptions, ah as FloatingField, ai as FloatingFieldProps, aj as FormActions, ak as FormActionsAlign, al as FormActionsDestructive, am as FormActionsLabels, an as FormActionsPlacement, ao as FormActionsProps, ap as IconButton, aq as IconButtonGlyphSize, ar as IconButtonLinkProps, as as IconButtonProps, at as IconButtonSize, au as IconButtonTone, av as IconButtonToneColor, aw as IconButtonVariant, ax as Input, ay as InputProps, az as KitLinkComponent, aA as KitLinkProps, aB as Label, aC as LabelOverride, aD as LabelProps, aE as MultiSelectLabels, aF as PHONE_QUERY, aG as PasswordRevealLabels, aH as PickerSheetLabels, aI as Select, aJ as SelectProps, aK as Spinner, aL as SpinnerProps, aM as SwipeableRowLabels, aN as TabItem, aO as Tabs, aP as TabsLabels, aQ as TabsProps, aR as Textarea, aS as TextareaProps, aT as TopBarLabels, aU as UiKitLabelOverrides, aV as UiKitLabels, aW as UiKitProvider, aX as UiKitProviderProps, aY as UseFilePickerOptions, aZ as UseFilePickerReturn, a_ as buttonClasses, a$ as formatFileSize, b0 as matchesAccept, b1 as missingKitLabels, b2 as resolvePasswordRevealLabels, b3 as useFilePicker, b4 as useKitFileLabels, b5 as useKitLabelOverrides, b6 as useKitLabels, b7 as useKitLink, b8 as useKitLocale, b9 as useKitWeekStart } from './kit-labels-
|
|
28
|
+
export { A as AppShellLabels, B as Button, a as ButtonClassesOptions, b as ButtonLinkProps, c as ButtonProps, d as ButtonSize, e as ButtonTone, f as ButtonVariant, C as CalculatorLabels, g as Card, h as CardAction, i as CardActionProps, j as CardContent, k as CardContentProps, l as CardDescription, m as CardDescriptionProps, n as CardFooter, o as CardFooterProps, p as CardHeader, q as CardHeaderProps, r as CardProps, s as CardTitle, t as CardTitleProps, u as CardTone, v as ComboboxLabels, w as CommonLabels, x as CopyButton, y as CopyButtonLabels, z as CopyButtonProps, D as CurrencyLabels, E as DEFAULT_APP_SHELL_LABELS, F as DEFAULT_CALCULATOR_LABELS, G as DEFAULT_COMBOBOX_LABELS, H as DEFAULT_COMMON_LABELS, I as DEFAULT_COPY_BUTTON_LABELS, J as DEFAULT_CURRENCY_LABELS, K as DEFAULT_DATE_PICKER_LABELS, L as DEFAULT_FILE_LABELS, M as DEFAULT_FILE_PICKER_LABELS, N as DEFAULT_FORM_ACTIONS_LABELS, O as DEFAULT_MULTI_SELECT_LABELS, P as DEFAULT_PASSWORD_REVEAL_LABELS, Q as DEFAULT_PICKER_SHEET_LABELS, R as DEFAULT_SWIPEABLE_ROW_LABELS, S as DEFAULT_TABS_LABELS, T as DEFAULT_TOP_BAR_LABELS, U as DatePickerLabels, V as EmptyState, W as EmptyStateProps, X as FIELD_BASE, Y as FIELD_DISPLAY, Z as FIELD_FLOATING_PAD, _ as FIELD_INVALID, $ as FIELD_TRIGGER, a0 as FIELD_WRITABLE_LOOK, a1 as FLOATING_INPUT_CLASS, a2 as FLOATING_LABEL_CLASS, a3 as FLOATING_LABEL_STATIC, a4 as FieldChevron, a5 as FieldChevronProps, a6 as FieldHint, a7 as FieldHintProps, a8 as FieldLabel, a9 as FieldLabelProps, aa as FileButton, ab as FileButtonProps, ac as FileLabels, ad as FilePickerLabels, ae as FileRejection, af as FileRejectionReason, ag as FileScreenOptions, ah as FloatingField, ai as FloatingFieldProps, aj as FormActions, ak as FormActionsAlign, al as FormActionsDestructive, am as FormActionsLabels, an as FormActionsPlacement, ao as FormActionsProps, ap as IconButton, aq as IconButtonGlyphSize, ar as IconButtonLinkProps, as as IconButtonProps, at as IconButtonSize, au as IconButtonTone, av as IconButtonToneColor, aw as IconButtonVariant, ax as Input, ay as InputProps, az as KitLinkComponent, aA as KitLinkProps, aB as Label, aC as LabelOverride, aD as LabelProps, aE as MultiSelectLabels, aF as PHONE_QUERY, aG as PasswordRevealLabels, aH as PickerSheetLabels, aI as Select, aJ as SelectProps, aK as Spinner, aL as SpinnerProps, aM as SwipeableRowLabels, aN as TabItem, aO as Tabs, aP as TabsLabels, aQ as TabsProps, aR as Textarea, aS as TextareaProps, aT as TopBarLabels, aU as UiKitLabelOverrides, aV as UiKitLabels, aW as UiKitProvider, aX as UiKitProviderProps, aY as UseFilePickerOptions, aZ as UseFilePickerReturn, a_ as buttonClasses, a$ as formatFileSize, b0 as matchesAccept, b1 as missingKitLabels, b2 as resolvePasswordRevealLabels, b3 as useFilePicker, b4 as useKitFileLabels, b5 as useKitLabelOverrides, b6 as useKitLabels, b7 as useKitLink, b8 as useKitLocale, b9 as useKitWeekStart } from './kit-labels-BHfRBbHs.js';
|
|
29
29
|
export { Field, FieldControlProps, FieldLabelVisibility, FieldProps, FieldRenderMeta } from './components/field.js';
|
|
30
30
|
export { SearchField, SearchFieldProps } from './components/search-field.js';
|
|
31
31
|
export { DropdownPanel, DropdownPanelProps, DropdownSearchHeader, DropdownSearchHeaderProps, useDropdown, useDropdownSearch } from './components/dropdown.js';
|
|
@@ -36,6 +36,7 @@ export { NumberPadSheet, NumberPadSheetLabels } from './components/numpad-sheet.
|
|
|
36
36
|
export { NumberInput, stepNumber } from './components/number-input.js';
|
|
37
37
|
export { CURRENCIES, CurrencyFlag, CurrencyFlagProps, CurrencyOption, CurrencySelect, CurrencySelectProps, currencyName, getCurrency } from './components/currency-select.js';
|
|
38
38
|
export { AmountInput } from './components/amount-input.js';
|
|
39
|
+
export { MoneyField, MoneyFieldProps } from './components/money-field.js';
|
|
39
40
|
export { Combobox, ComboboxProps, InlineEntityCombobox, InlineEntityComboboxProps } from './components/combobox.js';
|
|
40
41
|
export { PickerSheet, PickerSheetProps, SHEET_ROW_CLASS } from './components/picker-sheet.js';
|
|
41
42
|
export { EntityCombobox, EntityComboboxProps } from './components/entity-combobox.js';
|
|
@@ -50,7 +51,7 @@ export { Checkbox, CheckboxProps } from './components/checkbox.js';
|
|
|
50
51
|
export { Switch, SwitchProps, SwitchSize } from './components/switch.js';
|
|
51
52
|
export { Slider, SliderMark, SliderProps, fromLogPosition, toLogPosition } from './components/slider.js';
|
|
52
53
|
export { TimeInput, TimeInputProps, isTimeInRange, normalizeTime } from './components/time-input.js';
|
|
53
|
-
export { NumberField, NumberFieldProps } from './components/number-field.js';
|
|
54
|
+
export { IntegerField, NumberField, NumberFieldProps } from './components/number-field.js';
|
|
54
55
|
export { DEFAULT_SPARKLINE_LABELS, Sparkline, SparklineLabels, SparklineProps, SparklineTone, sparklineSummary } from './components/sparkline.js';
|
|
55
56
|
export { DEFAULT_STAT_TILE_LABELS, StatTile, StatTileDelta, StatTileGrid, StatTileGridProps, StatTileLabels, StatTileLinkProps, StatTileProps, StatTileSubValue, StatTileTone } from './components/stat-tile.js';
|
|
56
57
|
export { DEFAULT_SIGNATURE_PAD_LABELS, SignatureDetail, SignaturePad, SignaturePadHandle, SignaturePadLabels, SignaturePadProps, SignatureView, SignatureViewProps } from './components/signature-pad.js';
|
|
@@ -103,7 +104,7 @@ export { LoadingState, LoadingStateProps, LoadingStateSize } from './components/
|
|
|
103
104
|
export { DEFAULT_SIGNED_AMOUNT_LABELS, Delta, DeltaProps, GoodDirection, SignedAmount, SignedAmountLabels, SignedAmountProps, SignedAmountTone, TextTone, Tone, ToneProps, toneTextClass } from './components/signed-amount.js';
|
|
104
105
|
export { CrashReport, CrashReportResult, DEFAULT_ERROR_BOUNDARY_LABELS, ErrorBoundary, ErrorBoundaryDetails, ErrorBoundaryFallbackProps, ErrorBoundaryLabels, ErrorBoundaryProps, crashFingerprint, describeThrown, formatCrashReport, isChunkLoadError } from './components/error-boundary.js';
|
|
105
106
|
export { AuthedImage, AuthedImageLabels, AuthedImageProps, DEFAULT_AUTHED_IMAGE_LABELS } from './components/authed-image.js';
|
|
106
|
-
export { DEFAULT_IMAGE_GRID_LABELS, ImageGrid, ImageGridLabels, ImageGridProps } from './components/image-grid.js';
|
|
107
|
+
export { DEFAULT_IMAGE_GRID_LABELS, ImageGrid, ImageGridLabels, ImageGridProps, splitFileName } from './components/image-grid.js';
|
|
107
108
|
export { DEFAULT_LIGHTBOX_LABELS, ImageItem, ImageItemKind, Lightbox, LightboxLabels, LightboxProps, imageItemKind } from './components/lightbox.js';
|
|
108
109
|
export { ButtonGroup, ButtonGroupLink, ButtonGroupLinkProps, ButtonGroupLinkRenderProps, ButtonGroupProps } from './components/button-group.js';
|
|
109
110
|
export { NUMERIC_CELL_CLASS, Table, TableAlign, TableBody, TableBodyProps, TableCaption, TableCaptionProps, TableCell, TableCellProps, TableDensity, TableEmpty, TableEmptyProps, TableFoot, TableFootProps, TableHead, TableHeadProps, TableHeaderCell, TableHeaderCellProps, TableHeaderCellSize, TableHeaderCellWeight, TableLayout, TableProps, TableRow, TableRowProps, TableRowVariant, TableVAlign } from './components/table.js';
|
|
@@ -119,7 +120,7 @@ export { TextLink, TextLinkCurrent, TextLinkProps, TextLinkRenderProps, TextLink
|
|
|
119
120
|
export { DEFAULT_TOAST_LABELS, TOAST_ACTION_DURATION, ToastAction, ToastId, ToastLabels, ToastOptions, ToastPosition, ToastPromiseOptions, ToastRedoOptions, ToastSwipeDirection, ToastUndoOptions, Toaster, ToasterOffset, ToasterProps, toast } from './components/toast.js';
|
|
120
121
|
export { DEFAULT_DATA_TABLE_LABELS, DataTableLabels, missingDataTableLabels, resolveDataTableLabels } from './components/data-table-labels.js';
|
|
121
122
|
export { SortCycle, SortDir, SortState, SortStepOptions, decodeSorts, encodeSorts, nextSorts, normalizeSorts } from './components/data-table-sort.js';
|
|
122
|
-
export { C as ColumnFilter, D as DataTable, x as DataTableCellProps, a as DataTableChrome, b as DataTableColumn, c as DataTableDensity, y as DataTableHeadProps, d as DataTableProps, e as DataTableRowAction, F as FilterState, f as FilterValue, M as MobileSwipeActions, S as ServerPagination, T as TableUrlState, g as TableUrlStateProps, h as TableUrlSync, U as UseTableUrlStateOptions, i as UseTableUrlStateReturn, j as dateFilter, k as decodeFilterValue, l as decodeFilterValueOfType, m as defaultFilterState, n as encodeFilterValue, o as filterHref, p as isFilterActive, q as numberFilter, r as readTableUrlState, s as resolveFilter, t as rowMatches, u as selectFilter, v as textFilter, w as useTableUrlState } from './data-table-
|
|
123
|
+
export { C as ColumnFilter, D as DataTable, x as DataTableCellProps, a as DataTableChrome, b as DataTableColumn, c as DataTableDensity, y as DataTableHeadProps, d as DataTableProps, e as DataTableRowAction, F as FilterState, f as FilterValue, M as MobileSwipeActions, S as ServerPagination, T as TableUrlState, g as TableUrlStateProps, h as TableUrlSync, U as UseTableUrlStateOptions, i as UseTableUrlStateReturn, j as dateFilter, k as decodeFilterValue, l as decodeFilterValueOfType, m as defaultFilterState, n as encodeFilterValue, o as filterHref, p as isFilterActive, q as numberFilter, r as readTableUrlState, s as resolveFilter, t as rowMatches, u as selectFilter, v as textFilter, w as useTableUrlState } from './data-table-CfVXtCeG.js';
|
|
123
124
|
export { PAGE_SIZE_OPTIONS, Pagination } from './components/data-table-pagination.js';
|
|
124
125
|
export { FilterPopover } from './components/data-table-filter-popover.js';
|
|
125
126
|
export { BooleanColumnOptions, BooleanMark, BooleanMarkProps, booleanColumn } from './components/data-table-cells.js';
|
package/dist/index.js
CHANGED
|
@@ -37,6 +37,7 @@ export * from "./components/numpad-sheet.js";
|
|
|
37
37
|
export * from "./components/number-input.js";
|
|
38
38
|
export * from "./components/currency-select.js";
|
|
39
39
|
export * from "./components/amount-input.js";
|
|
40
|
+
export * from "./components/money-field.js";
|
|
40
41
|
export * from "./components/combobox.js";
|
|
41
42
|
export * from "./components/picker-sheet.js";
|
|
42
43
|
export * from "./components/entity-combobox.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// @eifi1/ui-kit — shared design-system barrel.\n//\n// Domain-free UI + theme surface shared across apps (lead app: Keksdose). Consumers import\n// components/theme from \"@eifi1/ui-kit\" and the token stylesheet from \"@eifi1/ui-kit/tokens.css\".\n\n// ── lib ────────────────────────────────────────────────────────────────────\nexport * from \"./lib/calc\";\nexport { cn } from \"./lib/cn\";\nexport { logger, setStoreLog } from \"./lib/logger\";\n// Intl number / money / percent / date / relative-time formatting, and `useKitFormat()`\n// for the same bound to the provider's locale (kastlan's formatters.ts, English \"5m ago\").\nexport * from \"./lib/format\";\n// localStorage that never throws (Safari private mode, blocked site data).\nexport { readStored, writeStored } from \"./lib/safe-storage\";\n// Date helpers are also available via the \"@eifi1/ui-kit/dates\" subpath.\n\n// ── hooks ────────────────────────────────────────────────────────────────────\nexport { useMediaQuery } from \"./hooks/use-media-query\";\nexport { useBodyScrollLock } from \"./hooks/use-body-scroll-lock\";\nexport { useAnchoredRect } from \"./hooks/use-anchored-rect\";\nexport type { AnchorRect } from \"./hooks/use-anchored-rect\";\nexport { useAnchoredPanel, anchoredPanelPlacement, useVisualViewport } from \"./hooks/use-anchored-panel\";\nexport type {\n AnchoredPanel,\n AnchoredPanelOptions,\n ViewportBox,\n} from \"./hooks/use-anchored-panel\";\nexport { useEscapeKey, useOutsideClick } from \"./hooks/use-dismiss\";\n// Focus containment for an overlay, and a live region for a change that moves no focus.\n// Both were extracted from the two components that already did them correctly (Modal and\n// CommandPalette) so the rest of the kit stops being the exception.\nexport { useFocusTrap } from \"./hooks/use-focus-trap\";\nexport type { FocusTrapOptions } from \"./hooks/use-focus-trap\";\nexport { useAnnounce } from \"./hooks/use-announce\";\nexport type { UseAnnounceReturn, UseAnnounceOptions, AnnounceRegionProps } from \"./hooks/use-announce\";\nexport { useOverlayHistory } from \"./hooks/use-overlay-history\";\nexport { useCloseTransition, OVERLAY_EXIT_MS } from \"./hooks/use-close-transition\";\nexport { useRowSwipe } from \"./hooks/use-row-swipe\";\nexport type { SwipeStage, RowSwipeOptions, RowSwipeReturn } from \"./hooks/use-row-swipe\";\n// Any element as a file drop target, screened like FileButton (kastlan).\nexport { useFileDrop, dragHasFiles } from \"./hooks/use-file-drop\";\nexport type { UseFileDropOptions, UseFileDropReturn, FileDropProps } from \"./hooks/use-file-drop\";\n// kastlan's search boxes each carried a hand-rolled copy, two without the cleanup.\nexport { useDebounce, useDebouncedCallback } from \"./hooks/use-debounce\";\nexport type { DebouncedCallbackOptions, DebouncedFunction } from \"./hooks/use-debounce\";\n// One search param as state, the active tab in `?tab=`, and a dialog's open state in the\n// URL (Modal's `urlParam`) — kastlan's and keksdose's use-search-param-state, in the kit.\nexport { useSearchParamState, useTabParam, useDialogParam } from \"./hooks/use-search-param-state\";\nexport type { SearchParamStateOptions, DialogParam } from \"./hooks/use-search-param-state\";\n// Copy that reports whether it worked — keksdose's copy buttons said \"Copied\" when it had not.\nexport { useCopyToClipboard, copyToClipboard } from \"./hooks/use-copy-to-clipboard\";\nexport type { CopyState, UseCopyToClipboardOptions, UseCopyToClipboardReturn } from \"./hooks/use-copy-to-clipboard\";\n// Keyboard shortcuts (\"Mod+K\", \"Ctrl+Shift+F\") that leave typing in fields alone.\nexport { useHotkey, parseHotkey, matchesHotkey } from \"./hooks/use-hotkey\";\nexport type { Hotkey, ParsedHotkey, UseHotkeyOptions } from \"./hooks/use-hotkey\";\n// A protected file as an object URL, fetched with the app's own auth (kastlan's AuthedImage).\nexport { useAuthedSrc } from \"./hooks/use-authed-src\";\nexport type { AuthedFetcher, AuthedSrcStatus, UseAuthedSrcOptions, UseAuthedSrcResult } from \"./hooks/use-authed-src\";\n\n// ── theme / palettes ─────────────────────────────────────────────────────────\nexport * from \"./theme/chart-palette\";\n// Colour maths (sRGB ↔ OKLCH, WCAG contrast, CVD simulation) and the palette deriver\n// that builds a whole, contrast-solved palette from one brand colour plus any colours\n// pinned by hand. `auditPalette` / `auditChartRamp` measure a palette rather than\n// trusting a comment about it.\nexport * from \"./theme/color\";\nexport * from \"./theme/palette-derive\";\nexport * from \"./theme/palette-presets\";\nexport * from \"./theme/theme-store\";\nexport * from \"./theme/palette-store\";\n\n// ── components ───────────────────────────────────────────────────────────────\nexport * from \"./components/ui\";\n// The label-ABOVE field group (label, hint, error, required), inside wizards or out.\nexport * from \"./components/field\";\nexport * from \"./components/search-field\";\nexport * from \"./components/dropdown\";\nexport * from \"./components/popover\";\nexport { SwipeableRow } from \"./components/swipeable-row\";\nexport type { SwipeAction, SwipeableRowProps } from \"./components/swipeable-row\";\nexport * from \"./components/calculator\";\nexport * from \"./components/numpad-sheet\";\nexport * from \"./components/number-input\";\nexport * from \"./components/currency-select\";\nexport * from \"./components/amount-input\";\nexport * from \"./components/combobox\";\nexport * from \"./components/picker-sheet\";\nexport * from \"./components/entity-combobox\";\nexport * from \"./components/multi-entity-combobox\";\nexport * from \"./components/multi-select\";\nexport * from \"./components/tooltip\";\nexport * from \"./components/user-avatar\";\nexport * from \"./components/settings-fields\";\n// Sync state for a database-backed field: the engine (`useFieldSync`) and the\n// affordance (`FieldSyncIndicator`), kept separate because the state is useful\n// without the dot — a form can gate its submit on any field being `pending`.\nexport * from \"./components/field-sync\";\nexport * from \"./components/month-picker\";\nexport * from \"./components/checkbox\";\nexport * from \"./components/switch\";\nexport * from \"./components/slider\";\nexport * from \"./components/time-input\";\nexport * from \"./components/number-field\";\nexport * from \"./components/sparkline\";\nexport * from \"./components/stat-tile\";\nexport * from \"./components/signature-pad\";\nexport * from \"./components/password-strength\";\nexport * from \"./components/page-contents\";\nexport * from \"./components/disclosure\";\nexport * from \"./components/dialog-frame\";\nexport * from \"./components/danger-confirm\";\n// `useConfirm()` — the promise-based replacement for `window.confirm`, one host per app.\nexport * from \"./components/confirm-dialog\";\n// A non-modal corner panel and its round trigger (keksdose's assistant launcher).\nexport * from \"./components/floating-panel\";\n// The count / clear / actions bar a selection brings up (keksdose's three copies).\nexport * from \"./components/bulk-action-bar\";\nexport * from \"./components/swatch-picker\";\nexport * from \"./components/icon-picker\";\nexport * from \"./components/choice-card\";\nexport * from \"./components/autocomplete\";\nexport * from \"./components/measured-grid\";\nexport { useWindowedRows } from \"./hooks/use-windowed-rows\";\nexport type { WindowedRows } from \"./hooks/use-windowed-rows\";\n// Named, not `export *`: file-button.tsx also holds the screening helpers the\n// dropzone shares, which are internal.\nexport { FileButton, useFilePicker, matchesAccept, DEFAULT_FILE_PICKER_LABELS } from \"./components/file-button\";\nexport type {\n FileButtonProps,\n UseFilePickerOptions,\n UseFilePickerReturn,\n FilePickerLabels,\n FileRejection,\n FileRejectionReason,\n FileScreenOptions,\n} from \"./components/file-button\";\nexport * from \"./components/treemap\";\nexport * from \"./components/series-chart\";\nexport * from \"./components/chart-zoom\";\nexport * from \"./components/toggle-legend\";\nexport * from \"./components/facing-pair\";\nexport * from \"./components/series-chart-labels\";\nexport * from \"./components/pie-chart\";\nexport * from \"./components/pie-chart-labels\";\nexport * from \"./components/account-settings\";\n// 0.12.0: the fourth account section, and the QR code TwoFactorSetting draws its\n// otpauth URI with (encoder in lib/qr-encode.ts — no dependency, see there).\nexport * from \"./components/passkeys-setting\";\nexport * from \"./components/qr-code\";\nexport { encodeQr } from \"./lib/qr-encode\";\nexport type { QrEncodeOptions, QrErrorCorrection, QrMatrix } from \"./lib/qr-encode\";\nexport * from \"./components/alert-banner\";\nexport * from \"./components/toggle-group\";\n// A wrapping set of links/buttons marked `aria-current` — Tabs-like looks, not tabs.\nexport * from \"./components/nav-pills\";\n// A pill carrying one VALUE — inert, a link, or a toggle, depending on which prop it is\n// given — and the list field built from it. Distinct from Button on purpose: a row of\n// buttons reads as \"choose an action\", a row of chips as \"here are the things\".\nexport * from \"./components/chip\";\nexport * from \"./components/wizard-stepper\";\nexport * from \"./components/hover-menu\";\nexport * from \"./components/modal\";\nexport * from \"./components/full-bleed-dialog\";\nexport * from \"./components/grouped-picker\";\nexport * from \"./components/file-dropzone\";\nexport * from \"./components/mini-calendar\";\nexport * from \"./components/calendar-heatmap\";\nexport * from \"./components/date-picker\";\nexport * from \"./components/tree-view\";\nexport * from \"./components/chart\";\n// 0.8.0 layout and feedback primitives the apps hand-rolled or took from shadcn/Radix.\nexport * from \"./components/description-list\";\n// The Save / Cancel row forms and dialogs end in, and the editable line-item repeater\n// (journal lines, lease components, invoice positions). 0.12.0.\nexport * from \"./components/form-actions\";\nexport * from \"./components/line-items\";\nexport * from \"./components/progress-bar\";\n// Named: skeleton.tsx also holds SKELETON_CLASS, the look StatTile shares — internal.\nexport { Skeleton } from \"./components/skeleton\";\nexport type { SkeletonProps, SkeletonShape } from \"./components/skeleton\";\n// 0.12.0: a centred spinner with words, signed figures and deltas, a render-error fallback.\nexport * from \"./components/loading-state\";\nexport * from \"./components/signed-amount\";\nexport * from \"./components/error-boundary\";\nexport * from \"./components/copy-button\";\nexport { AuthedImage, DEFAULT_AUTHED_IMAGE_LABELS } from \"./components/authed-image\";\nexport type { AuthedImageProps, AuthedImageLabels } from \"./components/authed-image\";\nexport * from \"./components/image-grid\";\nexport * from \"./components/lightbox\";\nexport * from \"./components/button-group\";\nexport * from \"./components/table\";\nexport * from \"./components/separator\";\n// Named: scroll-area.tsx also holds the overflow hook and scrollbar class Table shares.\nexport { ScrollArea } from \"./components/scroll-area\";\nexport type { ScrollAreaProps } from \"./components/scroll-area\";\n// 0.10.0 rows, menu rows, text primitives and page chrome the apps drew by hand.\nexport * from \"./components/list\";\nexport * from \"./components/menu-item\";\nexport * from \"./components/text\";\nexport * from \"./components/status-dot\";\nexport * from \"./components/page-header\";\nexport * from \"./components/breadcrumbs\";\n// The one inline link (kastlan's EntityLink / CellLink / legal and source links), through\n// `<UiKitProvider linkComponent>`. Named: the file also holds the kit's internal link picker.\nexport { TextLink } from \"./components/text-link\";\nexport type {\n TextLinkProps,\n TextLinkRenderProps,\n TextLinkTone,\n TextLinkUnderline,\n TextLinkCurrent,\n} from \"./components/text-link\";\n// The toast layer over sonner (an OPTIONAL peer, loaded lazily): `toast` mirrors sonner's\n// API so apps migrate by swapping the import; `<Toaster>` carries the placement, theme,\n// tones and z-index both apps had wired by hand.\nexport { toast, Toaster, DEFAULT_TOAST_LABELS, TOAST_ACTION_DURATION } from \"./components/toast\";\nexport type {\n ToastId,\n ToastAction,\n ToastOptions,\n ToastPromiseOptions,\n ToastUndoOptions,\n ToastRedoOptions,\n ToastLabels,\n ToastPosition,\n ToastSwipeDirection,\n ToasterOffset,\n ToasterProps,\n} from \"./components/toast\";\n\n// ── data-table suite ─────────────────────────────────────────────────────────\nexport * from \"./components/data-table-labels\";\nexport * from \"./components/data-table-sort\";\nexport * from \"./components/data-table-filters\";\nexport * from \"./components/data-table-pagination\";\nexport { FilterPopover } from \"./components/data-table-filter-popover\";\n// data-table re-exports SortState internally; export the rest explicitly to\n// avoid a duplicate SortState star-export (it comes from data-table-sort).\nexport { DataTable } from \"./components/data-table\";\nexport type {\n DataTableColumn,\n DataTableCellProps,\n DataTableHeadProps,\n DataTableProps,\n ServerPagination,\n FilterState,\n MobileSwipeActions,\n DataTableDensity,\n DataTableChrome,\n DataTableRowAction,\n} from \"./components/data-table\";\n// 0.12.0: the yes/no cell, and a server table's state held by its owner, URL-synced.\nexport * from \"./components/data-table-cells\";\nexport { useTableUrlState, readTableUrlState } from \"./components/use-table-state\";\nexport type {\n TableUrlState,\n TableUrlSync,\n TableUrlStateProps,\n UseTableUrlStateOptions,\n UseTableUrlStateReturn,\n} from \"./components/use-table-state\";\n\n// ── shell (composable app chrome) ────────────────────────────────────────────\nexport * from \"./shell/topbar-controls\";\nexport * from \"./shell/top-bar\";\nexport * from \"./shell/app-shell\";\nexport * from \"./shell/option-switcher-menu\";\nexport * from \"./shell/role-switcher\";\nexport * from \"./shell/topbar-action-menu\";\nexport * from \"./shell/top-bar-brand\";\nexport * from \"./shell/auth-layout\";\n\n// ── feedback ─────────────────────────────────────────────────────────────────\n// The form somebody files a report with, and the parts an inbox is built from:\n// the status vocabulary both apps share value for value, the policy about what a\n// row may move to from where it stands, and the look of a status control, a\n// category badge and an opened report. The app still wires its own API, columns\n// and strings — see the note at the top of `feedback-inbox.tsx` for what is\n// deliberately left to it.\nexport * from \"./feedback/feedback-attachment\";\nexport * from \"./feedback/feedback-dialog\";\nexport * from \"./feedback/feedback-inbox\";\nexport * from \"./feedback/feedback-thread\";\n\n// ── multi-step wizard ────────────────────────────────────────────────────────\n// The engine (step machine, validators, collected data), the chrome around it\n// (indicator + nav bar + cancel confirm) and the review step it ends on.\n// `components/wizard-stepper` next door is a different, much smaller thing: a bare\n// step indicator for a two-step import flow, with no engine.\n//\n// Two modules were removed here rather than kept as stock. `wizard-field` held a\n// `WizardField`/`WizardSelectField` pair that had never been rendered in any app —\n// a field group nothing was built from, which this comment used to advertise. And\n// `use-rhf-wizard-step` was the only thing in the package that touched\n// react-hook-form, for a hook neither consumer called: keeping it meant an optional\n// peer, a dev dependency and a type import in every consumer's typecheck, bought\n// for nobody. A design system may carry stock; untested stock nothing has ever\n// rendered is not stock, it is a liability with an export.\nexport * from \"./wizard/types\";\nexport * from \"./wizard/use-wizard\";\nexport * from \"./wizard/wizard-context\";\nexport * from \"./wizard/validation\";\nexport * from \"./wizard/wizard-step\";\nexport * from \"./wizard/wizard-summary\";\nexport * from \"./wizard/stepper-nav\";\n\n// ── guided tours ─────────────────────────────────────────────────────────────\nexport * from \"./tour/tour\";\n\n// ── command palette / global search ──────────────────────────────────────────\nexport * from \"./search/command-palette\";\nexport * from \"./search/search-index\";\nexport * from \"./search/global-search\";\n\n// ── i18n: one label tree, one optional provider ──────────────────────────────\n// `UiKitLabels` names every string the kit renders; `<UiKitProvider labels locale>`\n// hands a translation to every component below it. Precedence: a component's own\n// prop > the provider > the English default. See src/i18n/kit-labels.tsx.\nexport * from \"./i18n/kit-labels\";\nexport * from \"./i18n/defaults\";\n"],"mappings":";AAMA,cAAc;AACd,SAAS,UAAU;AACnB,SAAS,QAAQ,mBAAmB;AAGpC,cAAc;AAEd,SAAS,YAAY,mBAAmB;AAIxC,SAAS,qBAAqB;AAC9B,SAAS,yBAAyB;AAClC,SAAS,uBAAuB;AAEhC,SAAS,kBAAkB,wBAAwB,yBAAyB;AAM5E,SAAS,cAAc,uBAAuB;AAI9C,SAAS,oBAAoB;AAE7B,SAAS,mBAAmB;AAE5B,SAAS,yBAAyB;AAClC,SAAS,oBAAoB,uBAAuB;AACpD,SAAS,mBAAmB;AAG5B,SAAS,aAAa,oBAAoB;AAG1C,SAAS,aAAa,4BAA4B;AAIlD,SAAS,qBAAqB,aAAa,sBAAsB;AAGjE,SAAS,oBAAoB,uBAAuB;AAGpD,SAAS,WAAW,aAAa,qBAAqB;AAGtD,SAAS,oBAAoB;AAI7B,cAAc;AAKd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AAEd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,oBAAoB;AAE7B,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAId,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAEd,cAAc;AAEd,cAAc;AAEd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,uBAAuB;AAIhC,SAAS,YAAY,eAAe,eAAe,kCAAkC;AAUrF,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,SAAS,gBAAgB;AAEzB,cAAc;AACd,cAAc;AAEd,cAAc;AAId,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAEd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AAEd,SAAS,gBAAgB;AAGzB,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,aAAa,mCAAmC;AAEzD,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAEd,SAAS,kBAAkB;AAG3B,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,SAAS,gBAAgB;AAWzB,SAAS,OAAO,SAAS,sBAAsB,6BAA6B;AAgB5E,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,qBAAqB;AAG9B,SAAS,iBAAiB;AAc1B,cAAc;AACd,SAAS,kBAAkB,yBAAyB;AAUpD,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AASd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAgBd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AAMd,cAAc;AACd,cAAc;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// @eifi1/ui-kit — shared design-system barrel.\n//\n// Domain-free UI + theme surface shared across apps (lead app: Keksdose). Consumers import\n// components/theme from \"@eifi1/ui-kit\" and the token stylesheet from \"@eifi1/ui-kit/tokens.css\".\n\n// ── lib ────────────────────────────────────────────────────────────────────\nexport * from \"./lib/calc\";\nexport { cn } from \"./lib/cn\";\nexport { logger, setStoreLog } from \"./lib/logger\";\n// Intl number / money / percent / date / relative-time formatting, and `useKitFormat()`\n// for the same bound to the provider's locale (kastlan's formatters.ts, English \"5m ago\").\nexport * from \"./lib/format\";\n// localStorage that never throws (Safari private mode, blocked site data).\nexport { readStored, writeStored } from \"./lib/safe-storage\";\n// Date helpers are also available via the \"@eifi1/ui-kit/dates\" subpath.\n\n// ── hooks ────────────────────────────────────────────────────────────────────\nexport { useMediaQuery } from \"./hooks/use-media-query\";\nexport { useBodyScrollLock } from \"./hooks/use-body-scroll-lock\";\nexport { useAnchoredRect } from \"./hooks/use-anchored-rect\";\nexport type { AnchorRect } from \"./hooks/use-anchored-rect\";\nexport { useAnchoredPanel, anchoredPanelPlacement, useVisualViewport } from \"./hooks/use-anchored-panel\";\nexport type {\n AnchoredPanel,\n AnchoredPanelOptions,\n ViewportBox,\n} from \"./hooks/use-anchored-panel\";\nexport { useEscapeKey, useOutsideClick } from \"./hooks/use-dismiss\";\n// Focus containment for an overlay, and a live region for a change that moves no focus.\n// Both were extracted from the two components that already did them correctly (Modal and\n// CommandPalette) so the rest of the kit stops being the exception.\nexport { useFocusTrap } from \"./hooks/use-focus-trap\";\nexport type { FocusTrapOptions } from \"./hooks/use-focus-trap\";\nexport { useAnnounce } from \"./hooks/use-announce\";\nexport type { UseAnnounceReturn, UseAnnounceOptions, AnnounceRegionProps } from \"./hooks/use-announce\";\nexport { useOverlayHistory } from \"./hooks/use-overlay-history\";\nexport { useCloseTransition, OVERLAY_EXIT_MS } from \"./hooks/use-close-transition\";\nexport { useRowSwipe } from \"./hooks/use-row-swipe\";\nexport type { SwipeStage, RowSwipeOptions, RowSwipeReturn } from \"./hooks/use-row-swipe\";\n// Any element as a file drop target, screened like FileButton (kastlan).\nexport { useFileDrop, dragHasFiles } from \"./hooks/use-file-drop\";\nexport type { UseFileDropOptions, UseFileDropReturn, FileDropProps } from \"./hooks/use-file-drop\";\n// kastlan's search boxes each carried a hand-rolled copy, two without the cleanup.\nexport { useDebounce, useDebouncedCallback } from \"./hooks/use-debounce\";\nexport type { DebouncedCallbackOptions, DebouncedFunction } from \"./hooks/use-debounce\";\n// One search param as state, the active tab in `?tab=`, and a dialog's open state in the\n// URL (Modal's `urlParam`) — kastlan's and keksdose's use-search-param-state, in the kit.\nexport { useSearchParamState, useTabParam, useDialogParam } from \"./hooks/use-search-param-state\";\nexport type { SearchParamStateOptions, DialogParam } from \"./hooks/use-search-param-state\";\n// Copy that reports whether it worked — keksdose's copy buttons said \"Copied\" when it had not.\nexport { useCopyToClipboard, copyToClipboard } from \"./hooks/use-copy-to-clipboard\";\nexport type { CopyState, UseCopyToClipboardOptions, UseCopyToClipboardReturn } from \"./hooks/use-copy-to-clipboard\";\n// Keyboard shortcuts (\"Mod+K\", \"Ctrl+Shift+F\") that leave typing in fields alone.\nexport { useHotkey, parseHotkey, matchesHotkey } from \"./hooks/use-hotkey\";\nexport type { Hotkey, ParsedHotkey, UseHotkeyOptions } from \"./hooks/use-hotkey\";\n// A protected file as an object URL, fetched with the app's own auth (kastlan's AuthedImage).\nexport { useAuthedSrc } from \"./hooks/use-authed-src\";\nexport type { AuthedFetcher, AuthedSrcStatus, UseAuthedSrcOptions, UseAuthedSrcResult } from \"./hooks/use-authed-src\";\n\n// ── theme / palettes ─────────────────────────────────────────────────────────\nexport * from \"./theme/chart-palette\";\n// Colour maths (sRGB ↔ OKLCH, WCAG contrast, CVD simulation) and the palette deriver\n// that builds a whole, contrast-solved palette from one brand colour plus any colours\n// pinned by hand. `auditPalette` / `auditChartRamp` measure a palette rather than\n// trusting a comment about it.\nexport * from \"./theme/color\";\nexport * from \"./theme/palette-derive\";\nexport * from \"./theme/palette-presets\";\nexport * from \"./theme/theme-store\";\nexport * from \"./theme/palette-store\";\n\n// ── components ───────────────────────────────────────────────────────────────\nexport * from \"./components/ui\";\n// The label-ABOVE field group (label, hint, error, required), inside wizards or out.\nexport * from \"./components/field\";\nexport * from \"./components/search-field\";\nexport * from \"./components/dropdown\";\nexport * from \"./components/popover\";\nexport { SwipeableRow } from \"./components/swipeable-row\";\nexport type { SwipeAction, SwipeableRowProps } from \"./components/swipeable-row\";\nexport * from \"./components/calculator\";\nexport * from \"./components/numpad-sheet\";\nexport * from \"./components/number-input\";\nexport * from \"./components/currency-select\";\nexport * from \"./components/amount-input\";\nexport * from \"./components/money-field\";\nexport * from \"./components/combobox\";\nexport * from \"./components/picker-sheet\";\nexport * from \"./components/entity-combobox\";\nexport * from \"./components/multi-entity-combobox\";\nexport * from \"./components/multi-select\";\nexport * from \"./components/tooltip\";\nexport * from \"./components/user-avatar\";\nexport * from \"./components/settings-fields\";\n// Sync state for a database-backed field: the engine (`useFieldSync`) and the\n// affordance (`FieldSyncIndicator`), kept separate because the state is useful\n// without the dot — a form can gate its submit on any field being `pending`.\nexport * from \"./components/field-sync\";\nexport * from \"./components/month-picker\";\nexport * from \"./components/checkbox\";\nexport * from \"./components/switch\";\nexport * from \"./components/slider\";\nexport * from \"./components/time-input\";\nexport * from \"./components/number-field\";\nexport * from \"./components/sparkline\";\nexport * from \"./components/stat-tile\";\nexport * from \"./components/signature-pad\";\nexport * from \"./components/password-strength\";\nexport * from \"./components/page-contents\";\nexport * from \"./components/disclosure\";\nexport * from \"./components/dialog-frame\";\nexport * from \"./components/danger-confirm\";\n// `useConfirm()` — the promise-based replacement for `window.confirm`, one host per app.\nexport * from \"./components/confirm-dialog\";\n// A non-modal corner panel and its round trigger (keksdose's assistant launcher).\nexport * from \"./components/floating-panel\";\n// The count / clear / actions bar a selection brings up (keksdose's three copies).\nexport * from \"./components/bulk-action-bar\";\nexport * from \"./components/swatch-picker\";\nexport * from \"./components/icon-picker\";\nexport * from \"./components/choice-card\";\nexport * from \"./components/autocomplete\";\nexport * from \"./components/measured-grid\";\nexport { useWindowedRows } from \"./hooks/use-windowed-rows\";\nexport type { WindowedRows } from \"./hooks/use-windowed-rows\";\n// Named, not `export *`: file-button.tsx also holds the screening helpers the\n// dropzone shares, which are internal.\nexport { FileButton, useFilePicker, matchesAccept, DEFAULT_FILE_PICKER_LABELS } from \"./components/file-button\";\nexport type {\n FileButtonProps,\n UseFilePickerOptions,\n UseFilePickerReturn,\n FilePickerLabels,\n FileRejection,\n FileRejectionReason,\n FileScreenOptions,\n} from \"./components/file-button\";\nexport * from \"./components/treemap\";\nexport * from \"./components/series-chart\";\nexport * from \"./components/chart-zoom\";\nexport * from \"./components/toggle-legend\";\nexport * from \"./components/facing-pair\";\nexport * from \"./components/series-chart-labels\";\nexport * from \"./components/pie-chart\";\nexport * from \"./components/pie-chart-labels\";\nexport * from \"./components/account-settings\";\n// 0.12.0: the fourth account section, and the QR code TwoFactorSetting draws its\n// otpauth URI with (encoder in lib/qr-encode.ts — no dependency, see there).\nexport * from \"./components/passkeys-setting\";\nexport * from \"./components/qr-code\";\nexport { encodeQr } from \"./lib/qr-encode\";\nexport type { QrEncodeOptions, QrErrorCorrection, QrMatrix } from \"./lib/qr-encode\";\nexport * from \"./components/alert-banner\";\nexport * from \"./components/toggle-group\";\n// A wrapping set of links/buttons marked `aria-current` — Tabs-like looks, not tabs.\nexport * from \"./components/nav-pills\";\n// A pill carrying one VALUE — inert, a link, or a toggle, depending on which prop it is\n// given — and the list field built from it. Distinct from Button on purpose: a row of\n// buttons reads as \"choose an action\", a row of chips as \"here are the things\".\nexport * from \"./components/chip\";\nexport * from \"./components/wizard-stepper\";\nexport * from \"./components/hover-menu\";\nexport * from \"./components/modal\";\nexport * from \"./components/full-bleed-dialog\";\nexport * from \"./components/grouped-picker\";\nexport * from \"./components/file-dropzone\";\nexport * from \"./components/mini-calendar\";\nexport * from \"./components/calendar-heatmap\";\nexport * from \"./components/date-picker\";\nexport * from \"./components/tree-view\";\nexport * from \"./components/chart\";\n// 0.8.0 layout and feedback primitives the apps hand-rolled or took from shadcn/Radix.\nexport * from \"./components/description-list\";\n// The Save / Cancel row forms and dialogs end in, and the editable line-item repeater\n// (journal lines, lease components, invoice positions). 0.12.0.\nexport * from \"./components/form-actions\";\nexport * from \"./components/line-items\";\nexport * from \"./components/progress-bar\";\n// Named: skeleton.tsx also holds SKELETON_CLASS, the look StatTile shares — internal.\nexport { Skeleton } from \"./components/skeleton\";\nexport type { SkeletonProps, SkeletonShape } from \"./components/skeleton\";\n// 0.12.0: a centred spinner with words, signed figures and deltas, a render-error fallback.\nexport * from \"./components/loading-state\";\nexport * from \"./components/signed-amount\";\nexport * from \"./components/error-boundary\";\nexport * from \"./components/copy-button\";\nexport { AuthedImage, DEFAULT_AUTHED_IMAGE_LABELS } from \"./components/authed-image\";\nexport type { AuthedImageProps, AuthedImageLabels } from \"./components/authed-image\";\nexport * from \"./components/image-grid\";\nexport * from \"./components/lightbox\";\nexport * from \"./components/button-group\";\nexport * from \"./components/table\";\nexport * from \"./components/separator\";\n// Named: scroll-area.tsx also holds the overflow hook and scrollbar class Table shares.\nexport { ScrollArea } from \"./components/scroll-area\";\nexport type { ScrollAreaProps } from \"./components/scroll-area\";\n// 0.10.0 rows, menu rows, text primitives and page chrome the apps drew by hand.\nexport * from \"./components/list\";\nexport * from \"./components/menu-item\";\nexport * from \"./components/text\";\nexport * from \"./components/status-dot\";\nexport * from \"./components/page-header\";\nexport * from \"./components/breadcrumbs\";\n// The one inline link (kastlan's EntityLink / CellLink / legal and source links), through\n// `<UiKitProvider linkComponent>`. Named: the file also holds the kit's internal link picker.\nexport { TextLink } from \"./components/text-link\";\nexport type {\n TextLinkProps,\n TextLinkRenderProps,\n TextLinkTone,\n TextLinkUnderline,\n TextLinkCurrent,\n} from \"./components/text-link\";\n// The toast layer over sonner (an OPTIONAL peer, loaded lazily): `toast` mirrors sonner's\n// API so apps migrate by swapping the import; `<Toaster>` carries the placement, theme,\n// tones and z-index both apps had wired by hand.\nexport { toast, Toaster, DEFAULT_TOAST_LABELS, TOAST_ACTION_DURATION } from \"./components/toast\";\nexport type {\n ToastId,\n ToastAction,\n ToastOptions,\n ToastPromiseOptions,\n ToastUndoOptions,\n ToastRedoOptions,\n ToastLabels,\n ToastPosition,\n ToastSwipeDirection,\n ToasterOffset,\n ToasterProps,\n} from \"./components/toast\";\n\n// ── data-table suite ─────────────────────────────────────────────────────────\nexport * from \"./components/data-table-labels\";\nexport * from \"./components/data-table-sort\";\nexport * from \"./components/data-table-filters\";\nexport * from \"./components/data-table-pagination\";\nexport { FilterPopover } from \"./components/data-table-filter-popover\";\n// data-table re-exports SortState internally; export the rest explicitly to\n// avoid a duplicate SortState star-export (it comes from data-table-sort).\nexport { DataTable } from \"./components/data-table\";\nexport type {\n DataTableColumn,\n DataTableCellProps,\n DataTableHeadProps,\n DataTableProps,\n ServerPagination,\n FilterState,\n MobileSwipeActions,\n DataTableDensity,\n DataTableChrome,\n DataTableRowAction,\n} from \"./components/data-table\";\n// 0.12.0: the yes/no cell, and a server table's state held by its owner, URL-synced.\nexport * from \"./components/data-table-cells\";\nexport { useTableUrlState, readTableUrlState } from \"./components/use-table-state\";\nexport type {\n TableUrlState,\n TableUrlSync,\n TableUrlStateProps,\n UseTableUrlStateOptions,\n UseTableUrlStateReturn,\n} from \"./components/use-table-state\";\n\n// ── shell (composable app chrome) ────────────────────────────────────────────\nexport * from \"./shell/topbar-controls\";\nexport * from \"./shell/top-bar\";\nexport * from \"./shell/app-shell\";\nexport * from \"./shell/option-switcher-menu\";\nexport * from \"./shell/role-switcher\";\nexport * from \"./shell/topbar-action-menu\";\nexport * from \"./shell/top-bar-brand\";\nexport * from \"./shell/auth-layout\";\n\n// ── feedback ─────────────────────────────────────────────────────────────────\n// The form somebody files a report with, and the parts an inbox is built from:\n// the status vocabulary both apps share value for value, the policy about what a\n// row may move to from where it stands, and the look of a status control, a\n// category badge and an opened report. The app still wires its own API, columns\n// and strings — see the note at the top of `feedback-inbox.tsx` for what is\n// deliberately left to it.\nexport * from \"./feedback/feedback-attachment\";\nexport * from \"./feedback/feedback-dialog\";\nexport * from \"./feedback/feedback-inbox\";\nexport * from \"./feedback/feedback-thread\";\n\n// ── multi-step wizard ────────────────────────────────────────────────────────\n// The engine (step machine, validators, collected data), the chrome around it\n// (indicator + nav bar + cancel confirm) and the review step it ends on.\n// `components/wizard-stepper` next door is a different, much smaller thing: a bare\n// step indicator for a two-step import flow, with no engine.\n//\n// Two modules were removed here rather than kept as stock. `wizard-field` held a\n// `WizardField`/`WizardSelectField` pair that had never been rendered in any app —\n// a field group nothing was built from, which this comment used to advertise. And\n// `use-rhf-wizard-step` was the only thing in the package that touched\n// react-hook-form, for a hook neither consumer called: keeping it meant an optional\n// peer, a dev dependency and a type import in every consumer's typecheck, bought\n// for nobody. A design system may carry stock; untested stock nothing has ever\n// rendered is not stock, it is a liability with an export.\nexport * from \"./wizard/types\";\nexport * from \"./wizard/use-wizard\";\nexport * from \"./wizard/wizard-context\";\nexport * from \"./wizard/validation\";\nexport * from \"./wizard/wizard-step\";\nexport * from \"./wizard/wizard-summary\";\nexport * from \"./wizard/stepper-nav\";\n\n// ── guided tours ─────────────────────────────────────────────────────────────\nexport * from \"./tour/tour\";\n\n// ── command palette / global search ──────────────────────────────────────────\nexport * from \"./search/command-palette\";\nexport * from \"./search/search-index\";\nexport * from \"./search/global-search\";\n\n// ── i18n: one label tree, one optional provider ──────────────────────────────\n// `UiKitLabels` names every string the kit renders; `<UiKitProvider labels locale>`\n// hands a translation to every component below it. Precedence: a component's own\n// prop > the provider > the English default. See src/i18n/kit-labels.tsx.\nexport * from \"./i18n/kit-labels\";\nexport * from \"./i18n/defaults\";\n"],"mappings":";AAMA,cAAc;AACd,SAAS,UAAU;AACnB,SAAS,QAAQ,mBAAmB;AAGpC,cAAc;AAEd,SAAS,YAAY,mBAAmB;AAIxC,SAAS,qBAAqB;AAC9B,SAAS,yBAAyB;AAClC,SAAS,uBAAuB;AAEhC,SAAS,kBAAkB,wBAAwB,yBAAyB;AAM5E,SAAS,cAAc,uBAAuB;AAI9C,SAAS,oBAAoB;AAE7B,SAAS,mBAAmB;AAE5B,SAAS,yBAAyB;AAClC,SAAS,oBAAoB,uBAAuB;AACpD,SAAS,mBAAmB;AAG5B,SAAS,aAAa,oBAAoB;AAG1C,SAAS,aAAa,4BAA4B;AAIlD,SAAS,qBAAqB,aAAa,sBAAsB;AAGjE,SAAS,oBAAoB,uBAAuB;AAGpD,SAAS,WAAW,aAAa,qBAAqB;AAGtD,SAAS,oBAAoB;AAI7B,cAAc;AAKd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AAEd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,oBAAoB;AAE7B,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAId,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAEd,cAAc;AAEd,cAAc;AAEd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,uBAAuB;AAIhC,SAAS,YAAY,eAAe,eAAe,kCAAkC;AAUrF,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,SAAS,gBAAgB;AAEzB,cAAc;AACd,cAAc;AAEd,cAAc;AAId,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAEd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AAEd,SAAS,gBAAgB;AAGzB,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,aAAa,mCAAmC;AAEzD,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAEd,SAAS,kBAAkB;AAG3B,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,SAAS,gBAAgB;AAWzB,SAAS,OAAO,SAAS,sBAAsB,6BAA6B;AAgB5E,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,qBAAqB;AAG9B,SAAS,iBAAiB;AAc1B,cAAc;AACd,SAAS,kBAAkB,yBAAyB;AAUpD,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AASd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAgBd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AAMd,cAAc;AACd,cAAc;","names":[]}
|
|
@@ -661,7 +661,11 @@ interface SelectProps extends Omit<SelectHTMLAttributes<HTMLSelectElement>, "siz
|
|
|
661
661
|
invalid?: boolean;
|
|
662
662
|
/** See {@link Input}'s `error`. */
|
|
663
663
|
error?: ReactNode;
|
|
664
|
-
/** A {@link FieldHint} for the label line — see {@link FloatingField}.
|
|
664
|
+
/** A {@link FieldHint} for the label line — see {@link FloatingField}. Plain
|
|
665
|
+
* TEXT (a string or a number) is a caption instead, and goes UNDER the field
|
|
666
|
+
* like every other field's hint, attached through `aria-describedby`: the label
|
|
667
|
+
* line is 11px of strip shared with the label, and a sentence placed there was
|
|
668
|
+
* set in the value's type on top of both the label and the value. */
|
|
665
669
|
hint?: ReactNode;
|
|
666
670
|
/**
|
|
667
671
|
* `"sm"`: a 28px, 12px-type select for a toolbar or a table header, where the
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The full-document navigations the kit makes, behind one object the tests can spy on.
|
|
3
|
+
*
|
|
4
|
+
* jsdom implements neither `location.reload` nor `location.replace`, and its
|
|
5
|
+
* `window.location` is unforgeable: a test cannot stub it by redefining the property
|
|
6
|
+
* once the suite runs each file in its own VM context (`pool: "vmThreads"`, which took
|
|
7
|
+
* the suite from ~3 minutes to ~1). `vi.spyOn(documentNavigation, "reload")` works in
|
|
8
|
+
* every pool. Internal, not part of the package's surface.
|
|
9
|
+
*/
|
|
10
|
+
declare const documentNavigation: {
|
|
11
|
+
reload(): void;
|
|
12
|
+
replace(href: string): void;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export { documentNavigation };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/document-navigation.ts"],"sourcesContent":["/**\n * The full-document navigations the kit makes, behind one object the tests can spy on.\n *\n * jsdom implements neither `location.reload` nor `location.replace`, and its\n * `window.location` is unforgeable: a test cannot stub it by redefining the property\n * once the suite runs each file in its own VM context (`pool: \"vmThreads\"`, which took\n * the suite from ~3 minutes to ~1). `vi.spyOn(documentNavigation, \"reload\")` works in\n * every pool. Internal, not part of the package's surface.\n */\nexport const documentNavigation = {\n reload(): void {\n window.location.reload();\n },\n replace(href: string): void {\n window.location.replace(href);\n },\n};\n"],"mappings":";AASO,MAAM,qBAAqB;AAAA,EAChC,SAAe;AACb,WAAO,SAAS,OAAO;AAAA,EACzB;AAAA,EACA,QAAQ,MAAoB;AAC1B,WAAO,SAAS,QAAQ,IAAI;AAAA,EAC9B;AACF;","names":[]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
|
|
3
|
+
declare const TAB_FADE_PX = 24;
|
|
4
|
+
/**
|
|
5
|
+
* Shared by Tabs' strip and AppShell's scrolling phone sub-nav; internal, not part of
|
|
6
|
+
* the package's surface.
|
|
7
|
+
*
|
|
8
|
+
* Which ends of a sideways-scrolling strip have tabs cut off behind them, as the
|
|
9
|
+
* `mask-image` that fades those ends out — or `undefined` while everything fits.
|
|
10
|
+
*
|
|
11
|
+
* A strip that overflowed used to stop dead at its edge: the last tab sliced through
|
|
12
|
+
* mid-word, and nothing on a phone (whose scrollbars are overlays that only show
|
|
13
|
+
* while you drag) said there was more to reach. A fade is the cue — the letters
|
|
14
|
+
* thin out rather than end — and it is measured, not assumed, so a strip that fits
|
|
15
|
+
* is painted exactly as before. Physical `left`/`right` in the gradient, because
|
|
16
|
+
* `mask-image` has no logical directions; the reading direction is read from the
|
|
17
|
+
* element, and `scrollLeft` is a magnitude here because an RTL strip counts it
|
|
18
|
+
* negative from the start edge.
|
|
19
|
+
*/
|
|
20
|
+
declare function useStripFade(ref: RefObject<HTMLElement | null>): {
|
|
21
|
+
mask: string | undefined;
|
|
22
|
+
overflow: "start" | "end" | "both" | undefined;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Scroll `item` into view inside `strip` — the strip only (`scrollBy` on it, never
|
|
26
|
+
* `scrollIntoView`, which would scroll the page too) — far enough to clear the fade.
|
|
27
|
+
* A no-op when the strip fits or the item is already clear of both edges.
|
|
28
|
+
*/
|
|
29
|
+
declare function scrollIntoStrip(strip: HTMLElement, item: HTMLElement): void;
|
|
30
|
+
|
|
31
|
+
export { TAB_FADE_PX, scrollIntoStrip, useStripFade };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useLayoutEffect, useState } from "react";
|
|
3
|
+
const TAB_FADE_PX = 24;
|
|
4
|
+
function useStripFade(ref) {
|
|
5
|
+
const [edges, setEdges] = useState({ left: false, right: false, rtl: false });
|
|
6
|
+
useLayoutEffect(() => {
|
|
7
|
+
const el = ref.current;
|
|
8
|
+
if (!el) return;
|
|
9
|
+
const measure = () => {
|
|
10
|
+
const hidden = el.scrollWidth - el.clientWidth;
|
|
11
|
+
const scrolled = Math.abs(el.scrollLeft);
|
|
12
|
+
const rtl2 = getComputedStyle(el).direction === "rtl";
|
|
13
|
+
const atStart = scrolled > 1;
|
|
14
|
+
const atEnd = hidden - scrolled > 1;
|
|
15
|
+
const left = rtl2 ? atEnd : atStart;
|
|
16
|
+
const right = rtl2 ? atStart : atEnd;
|
|
17
|
+
setEdges(
|
|
18
|
+
(prev) => prev.left === left && prev.right === right && prev.rtl === rtl2 ? prev : { left, right, rtl: rtl2 }
|
|
19
|
+
);
|
|
20
|
+
};
|
|
21
|
+
measure();
|
|
22
|
+
el.addEventListener("scroll", measure, { passive: true });
|
|
23
|
+
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(measure);
|
|
24
|
+
observer?.observe(el);
|
|
25
|
+
for (const child of Array.from(el.children)) observer?.observe(child);
|
|
26
|
+
return () => {
|
|
27
|
+
el.removeEventListener("scroll", measure);
|
|
28
|
+
observer?.disconnect();
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
if (!edges.left && !edges.right) return { mask: void 0, overflow: void 0 };
|
|
32
|
+
const l = edges.left ? `transparent, #000 ${TAB_FADE_PX}px` : "#000";
|
|
33
|
+
const r = edges.right ? `#000 calc(100% - ${TAB_FADE_PX}px), transparent` : "#000";
|
|
34
|
+
const rtl = edges.rtl;
|
|
35
|
+
const start = rtl ? edges.right : edges.left;
|
|
36
|
+
const end = rtl ? edges.left : edges.right;
|
|
37
|
+
return {
|
|
38
|
+
mask: `linear-gradient(to right, ${l}, ${r})`,
|
|
39
|
+
overflow: start && end ? "both" : start ? "start" : "end"
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function scrollIntoStrip(strip, item) {
|
|
43
|
+
if (strip.scrollWidth <= strip.clientWidth) return;
|
|
44
|
+
const s = strip.getBoundingClientRect();
|
|
45
|
+
const t = item.getBoundingClientRect();
|
|
46
|
+
const delta = t.left < s.left + TAB_FADE_PX ? t.left - s.left - TAB_FADE_PX : t.right > s.right - TAB_FADE_PX ? t.right - s.right + TAB_FADE_PX : 0;
|
|
47
|
+
if (delta !== 0) strip.scrollBy({ left: delta });
|
|
48
|
+
}
|
|
49
|
+
export {
|
|
50
|
+
TAB_FADE_PX,
|
|
51
|
+
scrollIntoStrip,
|
|
52
|
+
useStripFade
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=strip-fade.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/strip-fade.ts"],"sourcesContent":["import { useLayoutEffect, useState, type RefObject } from \"react\";\n\n// How far the fade at a scrolled strip's cut edge reaches, and how much room a tab\n// brought into view keeps from that edge so the fade never lies on top of it.\nexport const TAB_FADE_PX = 24;\n\n/**\n * Shared by Tabs' strip and AppShell's scrolling phone sub-nav; internal, not part of\n * the package's surface.\n *\n * Which ends of a sideways-scrolling strip have tabs cut off behind them, as the\n * `mask-image` that fades those ends out — or `undefined` while everything fits.\n *\n * A strip that overflowed used to stop dead at its edge: the last tab sliced through\n * mid-word, and nothing on a phone (whose scrollbars are overlays that only show\n * while you drag) said there was more to reach. A fade is the cue — the letters\n * thin out rather than end — and it is measured, not assumed, so a strip that fits\n * is painted exactly as before. Physical `left`/`right` in the gradient, because\n * `mask-image` has no logical directions; the reading direction is read from the\n * element, and `scrollLeft` is a magnitude here because an RTL strip counts it\n * negative from the start edge.\n */\nexport function useStripFade(\n ref: RefObject<HTMLElement | null>,\n): { mask: string | undefined; overflow: \"start\" | \"end\" | \"both\" | undefined } {\n const [edges, setEdges] = useState({ left: false, right: false, rtl: false });\n useLayoutEffect(() => {\n const el = ref.current;\n if (!el) return;\n const measure = () => {\n const hidden = el.scrollWidth - el.clientWidth;\n const scrolled = Math.abs(el.scrollLeft);\n const rtl = getComputedStyle(el).direction === \"rtl\";\n const atStart = scrolled > 1;\n const atEnd = hidden - scrolled > 1;\n const left = rtl ? atEnd : atStart;\n const right = rtl ? atStart : atEnd;\n setEdges((prev) =>\n prev.left === left && prev.right === right && prev.rtl === rtl ? prev : { left, right, rtl },\n );\n };\n measure();\n el.addEventListener(\"scroll\", measure, { passive: true });\n const observer = typeof ResizeObserver === \"undefined\" ? null : new ResizeObserver(measure);\n observer?.observe(el);\n // The tabs, too: a label or a badge that grows changes the overflow without\n // resizing the strip's own box.\n for (const child of Array.from(el.children)) observer?.observe(child);\n return () => {\n el.removeEventListener(\"scroll\", measure);\n observer?.disconnect();\n };\n });\n if (!edges.left && !edges.right) return { mask: undefined, overflow: undefined };\n const l = edges.left ? `transparent, #000 ${TAB_FADE_PX}px` : \"#000\";\n const r = edges.right ? `#000 calc(100% - ${TAB_FADE_PX}px), transparent` : \"#000\";\n const rtl = edges.rtl;\n const start = rtl ? edges.right : edges.left;\n const end = rtl ? edges.left : edges.right;\n return {\n mask: `linear-gradient(to right, ${l}, ${r})`,\n overflow: start && end ? \"both\" : start ? \"start\" : \"end\",\n };\n}\n\n/**\n * Scroll `item` into view inside `strip` — the strip only (`scrollBy` on it, never\n * `scrollIntoView`, which would scroll the page too) — far enough to clear the fade.\n * A no-op when the strip fits or the item is already clear of both edges.\n */\nexport function scrollIntoStrip(strip: HTMLElement, item: HTMLElement): void {\n if (strip.scrollWidth <= strip.clientWidth) return;\n const s = strip.getBoundingClientRect();\n const t = item.getBoundingClientRect();\n const delta =\n t.left < s.left + TAB_FADE_PX\n ? t.left - s.left - TAB_FADE_PX\n : t.right > s.right - TAB_FADE_PX\n ? t.right - s.right + TAB_FADE_PX\n : 0;\n if (delta !== 0) strip.scrollBy({ left: delta });\n}\n"],"mappings":";AAAA,SAAS,iBAAiB,gBAAgC;AAInD,MAAM,cAAc;AAkBpB,SAAS,aACd,KAC8E;AAC9E,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE,MAAM,OAAO,OAAO,OAAO,KAAK,MAAM,CAAC;AAC5E,kBAAgB,MAAM;AACpB,UAAM,KAAK,IAAI;AACf,QAAI,CAAC,GAAI;AACT,UAAM,UAAU,MAAM;AACpB,YAAM,SAAS,GAAG,cAAc,GAAG;AACnC,YAAM,WAAW,KAAK,IAAI,GAAG,UAAU;AACvC,YAAMA,OAAM,iBAAiB,EAAE,EAAE,cAAc;AAC/C,YAAM,UAAU,WAAW;AAC3B,YAAM,QAAQ,SAAS,WAAW;AAClC,YAAM,OAAOA,OAAM,QAAQ;AAC3B,YAAM,QAAQA,OAAM,UAAU;AAC9B;AAAA,QAAS,CAAC,SACR,KAAK,SAAS,QAAQ,KAAK,UAAU,SAAS,KAAK,QAAQA,OAAM,OAAO,EAAE,MAAM,OAAO,KAAAA,KAAI;AAAA,MAC7F;AAAA,IACF;AACA,YAAQ;AACR,OAAG,iBAAiB,UAAU,SAAS,EAAE,SAAS,KAAK,CAAC;AACxD,UAAM,WAAW,OAAO,mBAAmB,cAAc,OAAO,IAAI,eAAe,OAAO;AAC1F,cAAU,QAAQ,EAAE;AAGpB,eAAW,SAAS,MAAM,KAAK,GAAG,QAAQ,EAAG,WAAU,QAAQ,KAAK;AACpE,WAAO,MAAM;AACX,SAAG,oBAAoB,UAAU,OAAO;AACxC,gBAAU,WAAW;AAAA,IACvB;AAAA,EACF,CAAC;AACD,MAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,MAAO,QAAO,EAAE,MAAM,QAAW,UAAU,OAAU;AAC/E,QAAM,IAAI,MAAM,OAAO,qBAAqB,WAAW,OAAO;AAC9D,QAAM,IAAI,MAAM,QAAQ,oBAAoB,WAAW,qBAAqB;AAC5E,QAAM,MAAM,MAAM;AAClB,QAAM,QAAQ,MAAM,MAAM,QAAQ,MAAM;AACxC,QAAM,MAAM,MAAM,MAAM,OAAO,MAAM;AACrC,SAAO;AAAA,IACL,MAAM,6BAA6B,CAAC,KAAK,CAAC;AAAA,IAC1C,UAAU,SAAS,MAAM,SAAS,QAAQ,UAAU;AAAA,EACtD;AACF;AAOO,SAAS,gBAAgB,OAAoB,MAAyB;AAC3E,MAAI,MAAM,eAAe,MAAM,YAAa;AAC5C,QAAM,IAAI,MAAM,sBAAsB;AACtC,QAAM,IAAI,KAAK,sBAAsB;AACrC,QAAM,QACJ,EAAE,OAAO,EAAE,OAAO,cACd,EAAE,OAAO,EAAE,OAAO,cAClB,EAAE,QAAQ,EAAE,QAAQ,cAClB,EAAE,QAAQ,EAAE,QAAQ,cACpB;AACR,MAAI,UAAU,EAAG,OAAM,SAAS,EAAE,MAAM,MAAM,CAAC;AACjD;","names":["rtl"]}
|
package/dist/rhf/fields.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, ReactElement } from 'react';
|
|
3
3
|
import { FieldValues, FieldPath, ControllerProps, ControllerRenderProps, ControllerFieldState } from 'react-hook-form';
|
|
4
|
-
import { aJ as SelectProps, ay as InputProps, aS as TextareaProps } from '../kit-labels-
|
|
4
|
+
import { aJ as SelectProps, ay as InputProps, aS as TextareaProps } from '../kit-labels-BHfRBbHs.js';
|
|
5
5
|
import { NumberFieldProps } from '../components/number-field.js';
|
|
6
6
|
import { DatePickerProps } from '../components/date-picker.js';
|
|
7
7
|
import { CheckboxProps } from '../components/checkbox.js';
|
package/dist/rhf/form.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as react from 'react';
|
|
|
2
2
|
import { ReactElement, ComponentProps } from 'react';
|
|
3
3
|
import * as react_hook_form from 'react-hook-form';
|
|
4
4
|
import { FieldValues, FieldPath, ControllerProps } from 'react-hook-form';
|
|
5
|
-
import { aD as LabelProps } from '../kit-labels-
|
|
5
|
+
import { aD as LabelProps } from '../kit-labels-BHfRBbHs.js';
|
|
6
6
|
import '../components/data-table-labels.js';
|
|
7
7
|
import '../components/mini-calendar.js';
|
|
8
8
|
import '../components/calendar-heatmap.js';
|
package/dist/rhf/form.js
CHANGED
|
@@ -64,7 +64,7 @@ function FormItem({ className, ...rest }) {
|
|
|
64
64
|
[]
|
|
65
65
|
);
|
|
66
66
|
const value = useMemo(() => ({ id, mounted, mark }), [id, mounted, mark]);
|
|
67
|
-
return /* @__PURE__ */ jsx(FormItemContext.Provider, { value, children: /* @__PURE__ */ jsx("div", { "data-slot": "form-item", ...rest, className: cn("grid gap-1", className) }) });
|
|
67
|
+
return /* @__PURE__ */ jsx(FormItemContext.Provider, { value, children: /* @__PURE__ */ jsx("div", { "data-slot": "form-item", ...rest, className: cn("grid content-start gap-1", className) }) });
|
|
68
68
|
}
|
|
69
69
|
function useDescribes(slot, on) {
|
|
70
70
|
const item = useContext(FormItemContext);
|
package/dist/rhf/form.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/rhf/form.tsx"],"sourcesContent":["/**\n * The react-hook-form adapter: the five parts every form is built from, and the hook\n * they share. `@eifi1/ui-kit/rhf`.\n *\n * ```tsx\n * <Form {...form}>\n * <FormField control={form.control} name=\"amount\" render={({ field }) => (\n * <FormItem>\n * <FormLabel required>Amount</FormLabel>\n * <FormControl>\n * <NumberField value={field.value} onCommit={field.onChange} />\n * </FormControl>\n * <FormMessage />\n * </FormItem>\n * )} />\n * </Form>\n * ```\n *\n * The shape is shadcn's `form.tsx`, on purpose: Kastlan builds every form from that\n * file, so moving onto this one is an import line rather than a rewrite. What differs\n * is what the shadcn file gets wrong:\n *\n * - **`aria-describedby` names only what is on screen.** shadcn always points the\n * control at a description id, rendered or not, and at the message id whenever the\n * field has an error, whether a message was rendered for it or not. A reference to\n * a node that does not exist describes the field as nothing. Here the description\n * and the message say when they are mounted, and the control points at exactly\n * those.\n * - **Merged, never replaced.** A control that already carries its own\n * `aria-describedby` keeps it, first — the same rule as the kit's `error` prop\n * (see `useFieldError` in components/ui.tsx).\n * - **No Radix.** `FormControl` is a one-child `cloneElement`, not `Slot`, and the\n * label is the kit's own `Label` — the kit carries no Radix dependency and this\n * entry is not the place to start.\n *\n * ## Why this is its own entry\n *\n * The main barrel once shipped a react-hook-form hook (`use-rhf-wizard-step`) and\n * removed it: it made react-hook-form an install every consumer's typecheck paid for,\n * for a hook nobody called (see the wizard section of src/index.ts). This is the\n * answer to that, not a reversal of it. Nothing outside `src/rhf*` imports\n * react-hook-form — `__tests__/packaging-contract.test.ts` holds that — and the peer is\n * optional, so an app that does not use it installs nothing and imports nothing.\n *\n * ## Painting the field\n *\n * `FormControl` sets `aria-invalid` on its child. `NumberField` and the pickers paint\n * from that attribute; `Input`, `Select` and `Textarea` paint only from their\n * `invalid` prop (see its note in components/ui.tsx: a bare attribute announces but\n * does not paint), so pass it from the render prop —\n * `<Input {...field} invalid={fieldState.invalid} />`. `FormControl` does not inject\n * `invalid` itself because its child may be a native element, which would print it\n * into the DOM as an unknown attribute.\n *\n * ## Clearing a picker: `null`, unless the picker is told otherwise\n *\n * Nothing here touches a value. `FormField` is `Controller`, so what a control hands\n * `field.onChange` is exactly what lands in the form — and what the entity pickers\n * hand it on a clear is `null`: `EntityCombobox`'s \"×\", `InlineEntityCombobox`'s \"×\"\n * and its emptied text. (`MultiEntityCombobox` and `MultiSelect` clear to `[]`.)\n *\n * A zod schema that spells \"no choice\" as `\"\"` (`z.string()`, or `z.literal(\"\")` in a\n * union) then fails on the `null`. Say so on the PICKER, not here:\n *\n * ```tsx\n * <EntityCombobox clearValue=\"\" value={field.value} onChange={field.onChange} … />\n * ```\n *\n * `clearValue` also types `onChange` (`(v: V | \"\") => void` rather than\n * `V | null`) and reads `\"\"` back as \"nothing selected\", so an initial `defaultValues`\n * of `\"\"` shows the placeholder rather than an unresolvable id. The adapter does not\n * coerce because it cannot see the schema: mapping `null` to `\"\"` for every field\n * would break every schema that wants `null` (`z.string().nullable()`), which is the\n * pickers' default for a reason — it is the one value no option can have.\n */\nimport {\n Children,\n cloneElement,\n createContext,\n isValidElement,\n useCallback,\n useContext,\n useId,\n useLayoutEffect,\n useMemo,\n useState,\n type ComponentProps,\n type ReactElement,\n} from \"react\";\nimport {\n Controller,\n FormProvider,\n useFormContext,\n useFormState,\n type ControllerProps,\n type FieldPath,\n type FieldValues,\n} from \"react-hook-form\";\nimport { Label, type LabelProps } from \"../components/ui\";\nimport { cn } from \"../lib/cn\";\n\n/** The form's `useForm()` return, spread in: `<Form {...form}>`. react-hook-form's own\n * `FormProvider`, under the name the shadcn file gave it. */\nexport const Form = FormProvider;\n\n// ── contexts ─────────────────────────────────────────────────────────────────\n\nconst FormFieldContext = createContext<{ name: string } | null>(null);\n\n/** The two optional nodes a control can be described by. */\ntype Described = \"description\" | \"message\";\n\ninterface FormItemContextValue {\n id: string;\n mounted: Record<Described, boolean>;\n mark: (slot: Described, on: boolean) => void;\n}\n\nconst FormItemContext = createContext<FormItemContextValue | null>(null);\n\n// ── FormField ────────────────────────────────────────────────────────────────\n\n/**\n * react-hook-form's `Controller`, with the field's name put in context for the parts\n * below it. Takes exactly `Controller`'s props.\n */\nexport function FormField<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformedValues = TFieldValues,\n>(props: ControllerProps<TFieldValues, TName, TTransformedValues>) {\n const value = useMemo(() => ({ name: props.name as string }), [props.name]);\n return (\n <FormFieldContext.Provider value={value}>\n <Controller {...props} />\n </FormFieldContext.Provider>\n );\n}\n\n// ── useFormField ─────────────────────────────────────────────────────────────\n\n/**\n * The ids and the state of the field around the caller: for a part of your own that\n * sits beside the kit's (a character counter that belongs in `aria-describedby`, a\n * label with a different look).\n *\n * Throws outside a `FormField` + `FormItem` pair. shadcn's version answered there with\n * ids like `undefined-form-item`, which label nothing and fail nowhere.\n */\nexport function useFormField() {\n const field = useContext(FormFieldContext);\n const item = useContext(FormItemContext);\n if (!field) throw new Error(\"useFormField must be used inside <FormField>.\");\n if (!item) throw new Error(\"useFormField must be used inside <FormItem>.\");\n const { getFieldState } = useFormContext();\n // Subscribes this part to the field's state, so a label or message re-renders when\n // the field's error changes without the whole form doing so.\n const formState = useFormState({ name: field.name });\n const state = getFieldState(field.name, formState);\n const formDescriptionId = `${item.id}-description`;\n const formMessageId = `${item.id}-message`;\n const describedBy = [\n item.mounted.description && formDescriptionId,\n item.mounted.message && formMessageId,\n ]\n .filter(Boolean)\n .join(\" \");\n return {\n id: item.id,\n name: field.name,\n formItemId: `${item.id}-control`,\n formDescriptionId,\n formMessageId,\n /** The ids of the description and message that are actually rendered, or\n * `undefined` when neither is. */\n describedBy: describedBy || undefined,\n ...state,\n };\n}\n\n// ── FormItem ─────────────────────────────────────────────────────────────────\n\nexport type FormItemProps = ComponentProps<\"div\">;\n\n/** One field's box: mints the id its label, control, description and message share. */\nexport function FormItem({ className, ...rest }: FormItemProps) {\n const id = useId();\n const [mounted, setMounted] = useState<Record<Described, boolean>>({\n description: false,\n message: false,\n });\n const mark = useCallback(\n (slot: Described, on: boolean) =>\n setMounted((prev) => (prev[slot] === on ? prev : { ...prev, [slot]: on })),\n [],\n );\n const value = useMemo(() => ({ id, mounted, mark }), [id, mounted, mark]);\n return (\n <FormItemContext.Provider value={value}>\n <div data-slot=\"form-item\" {...rest} className={cn(\"grid gap-1\", className)} />\n </FormItemContext.Provider>\n );\n}\n\n/** Report a describing node's presence to the item, so the control points at it only\n * while it is on screen. A layout effect, so the reference lands before paint. */\nfunction useDescribes(slot: Described, on: boolean) {\n const item = useContext(FormItemContext);\n const mark = item?.mark;\n useLayoutEffect(() => {\n if (!on || !mark) return;\n mark(slot, true);\n return () => mark(slot, false);\n }, [slot, on, mark]);\n}\n\n// ── FormLabel ────────────────────────────────────────────────────────────────\n\nexport type FormLabelProps = LabelProps;\n\n/**\n * The kit's {@link Label}, bound to the control by `htmlFor` and turned to the danger\n * colour while the field is invalid. `required` draws the kit's `aria-hidden` mark:\n * whether the field is required is the control's to announce.\n */\nexport function FormLabel({ className, ...rest }: FormLabelProps) {\n const { error, formItemId } = useFormField();\n return (\n <Label\n data-slot=\"form-label\"\n data-error={error ? true : undefined}\n htmlFor={formItemId}\n {...rest}\n className={cn(\"data-[error=true]:text-[var(--danger)]\", className)}\n />\n );\n}\n\n// ── FormControl ──────────────────────────────────────────────────────────────\n\nexport interface FormControlProps {\n /** Exactly one element: the kit field, or a native one. It receives `id`,\n * `aria-describedby` and `aria-invalid`. */\n children: ReactElement;\n}\n\ntype AriaProps = {\n id?: string;\n \"aria-describedby\"?: string;\n \"aria-invalid\"?: ComponentProps<\"input\">[\"aria-invalid\"];\n};\n\n/**\n * Wires its one child to the item: the `id` the label points at, `aria-describedby`\n * naming the rendered description and message, and `aria-invalid` while the field has\n * an error.\n *\n * The child's own values win where it has them (an explicit `id`, a set\n * `aria-invalid`), as they did under Radix `Slot`; its own `aria-describedby` is\n * merged in front of the item's rather than replaced.\n */\nexport function FormControl({ children }: FormControlProps) {\n const { invalid, formItemId, describedBy } = useFormField();\n const child = Children.only(children);\n if (!isValidElement<AriaProps>(child)) return child;\n const own = child.props;\n const merged = [own[\"aria-describedby\"], describedBy].filter(Boolean).join(\" \");\n return cloneElement(child, {\n id: own.id ?? formItemId,\n \"aria-describedby\": merged || undefined,\n \"aria-invalid\": own[\"aria-invalid\"] ?? (invalid || undefined),\n });\n}\n\n// ── FormDescription / FormMessage ────────────────────────────────────────────\n\nexport type FormDescriptionProps = ComponentProps<\"p\">;\n\n/** Standing advice under the field (\"at least twelve characters\"). */\nexport function FormDescription({ className, ...rest }: FormDescriptionProps) {\n const { formDescriptionId } = useFormField();\n useDescribes(\"description\", true);\n return (\n <p\n data-slot=\"form-description\"\n {...rest}\n id={formDescriptionId}\n className={cn(\"text-[11px] leading-tight text-[var(--text-muted)]\", className)}\n />\n );\n}\n\nexport type FormMessageProps = ComponentProps<\"p\">;\n\n/**\n * The field's error message, from the form — the kit renders no string of its own\n * here; the schema or the `rules` carry the words. Without an error it renders its\n * `children`, if any, and otherwise nothing.\n *\n * Deliberately NOT `role=\"alert\"`, for the reason the kit's `error` prop gives: the\n * message is read when focus reaches the control, which is where a field's own error\n * is wanted, and an alert would interrupt on every keystroke of a form that\n * re-validates as you type.\n */\nexport function FormMessage({ className, children, ...rest }: FormMessageProps) {\n const { error, formMessageId } = useFormField();\n const body = error ? String(error.message ?? \"\") : children;\n const shown = body !== undefined && body !== null && body !== false && body !== \"\";\n useDescribes(\"message\", shown);\n if (!shown) return null;\n return (\n <p\n data-slot=\"form-message\"\n {...rest}\n id={formMessageId}\n className={cn(\"text-[11px] leading-tight text-[var(--danger)]\", className)}\n >\n {body}\n </p>\n );\n}\n"],"mappings":";AAsIM;AA3DN;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AACP,SAAS,aAA8B;AACvC,SAAS,UAAU;AAIZ,MAAM,OAAO;AAIpB,MAAM,mBAAmB,cAAuC,IAAI;AAWpE,MAAM,kBAAkB,cAA2C,IAAI;AAQhE,SAAS,UAId,OAAiE;AACjE,QAAM,QAAQ,QAAQ,OAAO,EAAE,MAAM,MAAM,KAAe,IAAI,CAAC,MAAM,IAAI,CAAC;AAC1E,SACE,oBAAC,iBAAiB,UAAjB,EAA0B,OACzB,8BAAC,cAAY,GAAG,OAAO,GACzB;AAEJ;AAYO,SAAS,eAAe;AAC7B,QAAM,QAAQ,WAAW,gBAAgB;AACzC,QAAM,OAAO,WAAW,eAAe;AACvC,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,+CAA+C;AAC3E,MAAI,CAAC,KAAM,OAAM,IAAI,MAAM,8CAA8C;AACzE,QAAM,EAAE,cAAc,IAAI,eAAe;AAGzC,QAAM,YAAY,aAAa,EAAE,MAAM,MAAM,KAAK,CAAC;AACnD,QAAM,QAAQ,cAAc,MAAM,MAAM,SAAS;AACjD,QAAM,oBAAoB,GAAG,KAAK,EAAE;AACpC,QAAM,gBAAgB,GAAG,KAAK,EAAE;AAChC,QAAM,cAAc;AAAA,IAClB,KAAK,QAAQ,eAAe;AAAA,IAC5B,KAAK,QAAQ,WAAW;AAAA,EAC1B,EACG,OAAO,OAAO,EACd,KAAK,GAAG;AACX,SAAO;AAAA,IACL,IAAI,KAAK;AAAA,IACT,MAAM,MAAM;AAAA,IACZ,YAAY,GAAG,KAAK,EAAE;AAAA,IACtB;AAAA,IACA;AAAA;AAAA;AAAA,IAGA,aAAa,eAAe;AAAA,IAC5B,GAAG;AAAA,EACL;AACF;AAOO,SAAS,SAAS,EAAE,WAAW,GAAG,KAAK,GAAkB;AAC9D,QAAM,KAAK,MAAM;AACjB,QAAM,CAAC,SAAS,UAAU,IAAI,SAAqC;AAAA,IACjE,aAAa;AAAA,IACb,SAAS;AAAA,EACX,CAAC;AACD,QAAM,OAAO;AAAA,IACX,CAAC,MAAiB,OAChB,WAAW,CAAC,SAAU,KAAK,IAAI,MAAM,KAAK,OAAO,EAAE,GAAG,MAAM,CAAC,IAAI,GAAG,GAAG,CAAE;AAAA,IAC3E,CAAC;AAAA,EACH;AACA,QAAM,QAAQ,QAAQ,OAAO,EAAE,IAAI,SAAS,KAAK,IAAI,CAAC,IAAI,SAAS,IAAI,CAAC;AACxE,SACE,oBAAC,gBAAgB,UAAhB,EAAyB,OACxB,8BAAC,SAAI,aAAU,aAAa,GAAG,MAAM,WAAW,GAAG,cAAc,SAAS,GAAG,GAC/E;AAEJ;AAIA,SAAS,aAAa,MAAiB,IAAa;AAClD,QAAM,OAAO,WAAW,eAAe;AACvC,QAAM,OAAO,MAAM;AACnB,kBAAgB,MAAM;AACpB,QAAI,CAAC,MAAM,CAAC,KAAM;AAClB,SAAK,MAAM,IAAI;AACf,WAAO,MAAM,KAAK,MAAM,KAAK;AAAA,EAC/B,GAAG,CAAC,MAAM,IAAI,IAAI,CAAC;AACrB;AAWO,SAAS,UAAU,EAAE,WAAW,GAAG,KAAK,GAAmB;AAChE,QAAM,EAAE,OAAO,WAAW,IAAI,aAAa;AAC3C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,cAAY,QAAQ,OAAO;AAAA,MAC3B,SAAS;AAAA,MACR,GAAG;AAAA,MACJ,WAAW,GAAG,0CAA0C,SAAS;AAAA;AAAA,EACnE;AAEJ;AAyBO,SAAS,YAAY,EAAE,SAAS,GAAqB;AAC1D,QAAM,EAAE,SAAS,YAAY,YAAY,IAAI,aAAa;AAC1D,QAAM,QAAQ,SAAS,KAAK,QAAQ;AACpC,MAAI,CAAC,eAA0B,KAAK,EAAG,QAAO;AAC9C,QAAM,MAAM,MAAM;AAClB,QAAM,SAAS,CAAC,IAAI,kBAAkB,GAAG,WAAW,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAC9E,SAAO,aAAa,OAAO;AAAA,IACzB,IAAI,IAAI,MAAM;AAAA,IACd,oBAAoB,UAAU;AAAA,IAC9B,gBAAgB,IAAI,cAAc,MAAM,WAAW;AAAA,EACrD,CAAC;AACH;AAOO,SAAS,gBAAgB,EAAE,WAAW,GAAG,KAAK,GAAyB;AAC5E,QAAM,EAAE,kBAAkB,IAAI,aAAa;AAC3C,eAAa,eAAe,IAAI;AAChC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACT,GAAG;AAAA,MACJ,IAAI;AAAA,MACJ,WAAW,GAAG,sDAAsD,SAAS;AAAA;AAAA,EAC/E;AAEJ;AAcO,SAAS,YAAY,EAAE,WAAW,UAAU,GAAG,KAAK,GAAqB;AAC9E,QAAM,EAAE,OAAO,cAAc,IAAI,aAAa;AAC9C,QAAM,OAAO,QAAQ,OAAO,MAAM,WAAW,EAAE,IAAI;AACnD,QAAM,QAAQ,SAAS,UAAa,SAAS,QAAQ,SAAS,SAAS,SAAS;AAChF,eAAa,WAAW,KAAK;AAC7B,MAAI,CAAC,MAAO,QAAO;AACnB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACT,GAAG;AAAA,MACJ,IAAI;AAAA,MACJ,WAAW,GAAG,kDAAkD,SAAS;AAAA,MAExE;AAAA;AAAA,EACH;AAEJ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/rhf/form.tsx"],"sourcesContent":["/**\n * The react-hook-form adapter: the five parts every form is built from, and the hook\n * they share. `@eifi1/ui-kit/rhf`.\n *\n * ```tsx\n * <Form {...form}>\n * <FormField control={form.control} name=\"amount\" render={({ field }) => (\n * <FormItem>\n * <FormLabel required>Amount</FormLabel>\n * <FormControl>\n * <NumberField value={field.value} onCommit={field.onChange} />\n * </FormControl>\n * <FormMessage />\n * </FormItem>\n * )} />\n * </Form>\n * ```\n *\n * The shape is shadcn's `form.tsx`, on purpose: Kastlan builds every form from that\n * file, so moving onto this one is an import line rather than a rewrite. What differs\n * is what the shadcn file gets wrong:\n *\n * - **`aria-describedby` names only what is on screen.** shadcn always points the\n * control at a description id, rendered or not, and at the message id whenever the\n * field has an error, whether a message was rendered for it or not. A reference to\n * a node that does not exist describes the field as nothing. Here the description\n * and the message say when they are mounted, and the control points at exactly\n * those.\n * - **Merged, never replaced.** A control that already carries its own\n * `aria-describedby` keeps it, first — the same rule as the kit's `error` prop\n * (see `useFieldError` in components/ui.tsx).\n * - **No Radix.** `FormControl` is a one-child `cloneElement`, not `Slot`, and the\n * label is the kit's own `Label` — the kit carries no Radix dependency and this\n * entry is not the place to start.\n *\n * ## Why this is its own entry\n *\n * The main barrel once shipped a react-hook-form hook (`use-rhf-wizard-step`) and\n * removed it: it made react-hook-form an install every consumer's typecheck paid for,\n * for a hook nobody called (see the wizard section of src/index.ts). This is the\n * answer to that, not a reversal of it. Nothing outside `src/rhf*` imports\n * react-hook-form — `__tests__/packaging-contract.test.ts` holds that — and the peer is\n * optional, so an app that does not use it installs nothing and imports nothing.\n *\n * ## Painting the field\n *\n * `FormControl` sets `aria-invalid` on its child. `NumberField` and the pickers paint\n * from that attribute; `Input`, `Select` and `Textarea` paint only from their\n * `invalid` prop (see its note in components/ui.tsx: a bare attribute announces but\n * does not paint), so pass it from the render prop —\n * `<Input {...field} invalid={fieldState.invalid} />`. `FormControl` does not inject\n * `invalid` itself because its child may be a native element, which would print it\n * into the DOM as an unknown attribute.\n *\n * ## Clearing a picker: `null`, unless the picker is told otherwise\n *\n * Nothing here touches a value. `FormField` is `Controller`, so what a control hands\n * `field.onChange` is exactly what lands in the form — and what the entity pickers\n * hand it on a clear is `null`: `EntityCombobox`'s \"×\", `InlineEntityCombobox`'s \"×\"\n * and its emptied text. (`MultiEntityCombobox` and `MultiSelect` clear to `[]`.)\n *\n * A zod schema that spells \"no choice\" as `\"\"` (`z.string()`, or `z.literal(\"\")` in a\n * union) then fails on the `null`. Say so on the PICKER, not here:\n *\n * ```tsx\n * <EntityCombobox clearValue=\"\" value={field.value} onChange={field.onChange} … />\n * ```\n *\n * `clearValue` also types `onChange` (`(v: V | \"\") => void` rather than\n * `V | null`) and reads `\"\"` back as \"nothing selected\", so an initial `defaultValues`\n * of `\"\"` shows the placeholder rather than an unresolvable id. The adapter does not\n * coerce because it cannot see the schema: mapping `null` to `\"\"` for every field\n * would break every schema that wants `null` (`z.string().nullable()`), which is the\n * pickers' default for a reason — it is the one value no option can have.\n */\nimport {\n Children,\n cloneElement,\n createContext,\n isValidElement,\n useCallback,\n useContext,\n useId,\n useLayoutEffect,\n useMemo,\n useState,\n type ComponentProps,\n type ReactElement,\n} from \"react\";\nimport {\n Controller,\n FormProvider,\n useFormContext,\n useFormState,\n type ControllerProps,\n type FieldPath,\n type FieldValues,\n} from \"react-hook-form\";\nimport { Label, type LabelProps } from \"../components/ui\";\nimport { cn } from \"../lib/cn\";\n\n/** The form's `useForm()` return, spread in: `<Form {...form}>`. react-hook-form's own\n * `FormProvider`, under the name the shadcn file gave it. */\nexport const Form = FormProvider;\n\n// ── contexts ─────────────────────────────────────────────────────────────────\n\nconst FormFieldContext = createContext<{ name: string } | null>(null);\n\n/** The two optional nodes a control can be described by. */\ntype Described = \"description\" | \"message\";\n\ninterface FormItemContextValue {\n id: string;\n mounted: Record<Described, boolean>;\n mark: (slot: Described, on: boolean) => void;\n}\n\nconst FormItemContext = createContext<FormItemContextValue | null>(null);\n\n// ── FormField ────────────────────────────────────────────────────────────────\n\n/**\n * react-hook-form's `Controller`, with the field's name put in context for the parts\n * below it. Takes exactly `Controller`'s props.\n */\nexport function FormField<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformedValues = TFieldValues,\n>(props: ControllerProps<TFieldValues, TName, TTransformedValues>) {\n const value = useMemo(() => ({ name: props.name as string }), [props.name]);\n return (\n <FormFieldContext.Provider value={value}>\n <Controller {...props} />\n </FormFieldContext.Provider>\n );\n}\n\n// ── useFormField ─────────────────────────────────────────────────────────────\n\n/**\n * The ids and the state of the field around the caller: for a part of your own that\n * sits beside the kit's (a character counter that belongs in `aria-describedby`, a\n * label with a different look).\n *\n * Throws outside a `FormField` + `FormItem` pair. shadcn's version answered there with\n * ids like `undefined-form-item`, which label nothing and fail nowhere.\n */\nexport function useFormField() {\n const field = useContext(FormFieldContext);\n const item = useContext(FormItemContext);\n if (!field) throw new Error(\"useFormField must be used inside <FormField>.\");\n if (!item) throw new Error(\"useFormField must be used inside <FormItem>.\");\n const { getFieldState } = useFormContext();\n // Subscribes this part to the field's state, so a label or message re-renders when\n // the field's error changes without the whole form doing so.\n const formState = useFormState({ name: field.name });\n const state = getFieldState(field.name, formState);\n const formDescriptionId = `${item.id}-description`;\n const formMessageId = `${item.id}-message`;\n const describedBy = [\n item.mounted.description && formDescriptionId,\n item.mounted.message && formMessageId,\n ]\n .filter(Boolean)\n .join(\" \");\n return {\n id: item.id,\n name: field.name,\n formItemId: `${item.id}-control`,\n formDescriptionId,\n formMessageId,\n /** The ids of the description and message that are actually rendered, or\n * `undefined` when neither is. */\n describedBy: describedBy || undefined,\n ...state,\n };\n}\n\n// ── FormItem ─────────────────────────────────────────────────────────────────\n\nexport type FormItemProps = ComponentProps<\"div\">;\n\n/** One field's box: mints the id its label, control, description and message share. */\nexport function FormItem({ className, ...rest }: FormItemProps) {\n const id = useId();\n const [mounted, setMounted] = useState<Record<Described, boolean>>({\n description: false,\n message: false,\n });\n const mark = useCallback(\n (slot: Described, on: boolean) =>\n setMounted((prev) => (prev[slot] === on ? prev : { ...prev, [slot]: on })),\n [],\n );\n const value = useMemo(() => ({ id, mounted, mark }), [id, mounted, mark]);\n return (\n <FormItemContext.Provider value={value}>\n {/* `content-start`: stretched to a taller neighbour's height in a grid row, the\n item gave the extra to its rows and its control sat lower (showcase audit). */}\n <div data-slot=\"form-item\" {...rest} className={cn(\"grid content-start gap-1\", className)} />\n </FormItemContext.Provider>\n );\n}\n\n/** Report a describing node's presence to the item, so the control points at it only\n * while it is on screen. A layout effect, so the reference lands before paint. */\nfunction useDescribes(slot: Described, on: boolean) {\n const item = useContext(FormItemContext);\n const mark = item?.mark;\n useLayoutEffect(() => {\n if (!on || !mark) return;\n mark(slot, true);\n return () => mark(slot, false);\n }, [slot, on, mark]);\n}\n\n// ── FormLabel ────────────────────────────────────────────────────────────────\n\nexport type FormLabelProps = LabelProps;\n\n/**\n * The kit's {@link Label}, bound to the control by `htmlFor` and turned to the danger\n * colour while the field is invalid. `required` draws the kit's `aria-hidden` mark:\n * whether the field is required is the control's to announce.\n */\nexport function FormLabel({ className, ...rest }: FormLabelProps) {\n const { error, formItemId } = useFormField();\n return (\n <Label\n data-slot=\"form-label\"\n data-error={error ? true : undefined}\n htmlFor={formItemId}\n {...rest}\n className={cn(\"data-[error=true]:text-[var(--danger)]\", className)}\n />\n );\n}\n\n// ── FormControl ──────────────────────────────────────────────────────────────\n\nexport interface FormControlProps {\n /** Exactly one element: the kit field, or a native one. It receives `id`,\n * `aria-describedby` and `aria-invalid`. */\n children: ReactElement;\n}\n\ntype AriaProps = {\n id?: string;\n \"aria-describedby\"?: string;\n \"aria-invalid\"?: ComponentProps<\"input\">[\"aria-invalid\"];\n};\n\n/**\n * Wires its one child to the item: the `id` the label points at, `aria-describedby`\n * naming the rendered description and message, and `aria-invalid` while the field has\n * an error.\n *\n * The child's own values win where it has them (an explicit `id`, a set\n * `aria-invalid`), as they did under Radix `Slot`; its own `aria-describedby` is\n * merged in front of the item's rather than replaced.\n */\nexport function FormControl({ children }: FormControlProps) {\n const { invalid, formItemId, describedBy } = useFormField();\n const child = Children.only(children);\n if (!isValidElement<AriaProps>(child)) return child;\n const own = child.props;\n const merged = [own[\"aria-describedby\"], describedBy].filter(Boolean).join(\" \");\n return cloneElement(child, {\n id: own.id ?? formItemId,\n \"aria-describedby\": merged || undefined,\n \"aria-invalid\": own[\"aria-invalid\"] ?? (invalid || undefined),\n });\n}\n\n// ── FormDescription / FormMessage ────────────────────────────────────────────\n\nexport type FormDescriptionProps = ComponentProps<\"p\">;\n\n/** Standing advice under the field (\"at least twelve characters\"). */\nexport function FormDescription({ className, ...rest }: FormDescriptionProps) {\n const { formDescriptionId } = useFormField();\n useDescribes(\"description\", true);\n return (\n <p\n data-slot=\"form-description\"\n {...rest}\n id={formDescriptionId}\n className={cn(\"text-[11px] leading-tight text-[var(--text-muted)]\", className)}\n />\n );\n}\n\nexport type FormMessageProps = ComponentProps<\"p\">;\n\n/**\n * The field's error message, from the form — the kit renders no string of its own\n * here; the schema or the `rules` carry the words. Without an error it renders its\n * `children`, if any, and otherwise nothing.\n *\n * Deliberately NOT `role=\"alert\"`, for the reason the kit's `error` prop gives: the\n * message is read when focus reaches the control, which is where a field's own error\n * is wanted, and an alert would interrupt on every keystroke of a form that\n * re-validates as you type.\n */\nexport function FormMessage({ className, children, ...rest }: FormMessageProps) {\n const { error, formMessageId } = useFormField();\n const body = error ? String(error.message ?? \"\") : children;\n const shown = body !== undefined && body !== null && body !== false && body !== \"\";\n useDescribes(\"message\", shown);\n if (!shown) return null;\n return (\n <p\n data-slot=\"form-message\"\n {...rest}\n id={formMessageId}\n className={cn(\"text-[11px] leading-tight text-[var(--danger)]\", className)}\n >\n {body}\n </p>\n );\n}\n"],"mappings":"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","names":[]}
|
package/dist/rhf.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { RhfCheckbox, RhfCheckboxProps, RhfCombobox, RhfComboboxProps, RhfDateFi
|
|
|
4
4
|
export { RhfLineItemCellContext, RhfLineItems, RhfLineItemsColumn, RhfLineItemsProps } from './rhf/line-items.js';
|
|
5
5
|
import 'react';
|
|
6
6
|
import 'react-hook-form';
|
|
7
|
-
import './kit-labels-
|
|
7
|
+
import './kit-labels-BHfRBbHs.js';
|
|
8
8
|
import './components/data-table-labels.js';
|
|
9
9
|
import './components/mini-calendar.js';
|
|
10
10
|
import './components/calendar-heatmap.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ComponentPropsWithoutRef, ReactNode } from 'react';
|
|
3
3
|
import { LucideIcon } from 'lucide-react';
|
|
4
|
-
import { az as KitLinkComponent } from '../kit-labels-
|
|
4
|
+
import { az as KitLinkComponent } from '../kit-labels-BHfRBbHs.js';
|
|
5
5
|
import '../components/data-table-labels.js';
|
|
6
6
|
import '../components/mini-calendar.js';
|
|
7
7
|
import '../components/calendar-heatmap.js';
|
|
@@ -177,6 +177,15 @@ interface AppShellProps extends ComponentPropsWithoutRef<"div"> {
|
|
|
177
177
|
* bottom bar — the phone's counterpart of the sidebar's second level. Default true;
|
|
178
178
|
* `false` keeps the single bar, where a group entry only links to its own `to`. */
|
|
179
179
|
mobileSubNav?: boolean;
|
|
180
|
+
/**
|
|
181
|
+
* How the phone sub-nav lays out a group with more pages than fit on one row.
|
|
182
|
+
* `"wrap"` (default): every page in view, on as many rows as it takes — the bar
|
|
183
|
+
* grows. `"scroll"`: one row that scrolls sideways, faded at a cut edge, with the
|
|
184
|
+
* current page scrolled into view. A long group took four rows (~130px) of a 390px
|
|
185
|
+
* screen above the bottom bar (showcase audit); scrolling gives that back at the
|
|
186
|
+
* price of pages hidden past the edge, so it is the app's call, per shell.
|
|
187
|
+
*/
|
|
188
|
+
mobileSubNavLayout?: "wrap" | "scroll";
|
|
180
189
|
/**
|
|
181
190
|
* Lay the shell out inside its PARENT'S box instead of the viewport: `h-full` rather
|
|
182
191
|
* than `h-dvh`, its own scroll container at every width, a bottom bar pinned to the
|
|
@@ -197,6 +206,6 @@ interface AppShellProps extends ComponentPropsWithoutRef<"div"> {
|
|
|
197
206
|
* `NavLink`; domain-free — nav items, brand, footer and the top bar's actions
|
|
198
207
|
* are all supplied by the app.
|
|
199
208
|
*/
|
|
200
|
-
declare function AppShell({ nav, topBar, children, footer, sidebarFooter, sidebarFooterItems, renderLink, collapseStorageKey: collapseStorageKeyProp, collapseLabel, expandLabel, subNav, mobileSubNav, toggleGroupLabel, embedded: embeddedProp, className, ...rest }: AppShellProps): react.JSX.Element;
|
|
209
|
+
declare function AppShell({ nav, topBar, children, footer, sidebarFooter, sidebarFooterItems, renderLink, collapseStorageKey: collapseStorageKeyProp, collapseLabel, expandLabel, subNav, mobileSubNav, mobileSubNavLayout, toggleGroupLabel, embedded: embeddedProp, className, ...rest }: AppShellProps): react.JSX.Element;
|
|
201
210
|
|
|
202
211
|
export { AppShell, type AppShellNavItem, type AppShellProps, type AppShellSidebarFooterItem, type AppShellSubItem };
|
package/dist/shell/app-shell.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { createContext, useCallback, useContext, useEffect, useId, useRef, useState } from "react";
|
|
3
|
+
import { createContext, useCallback, useContext, useEffect, useId, useLayoutEffect, useRef, useState } from "react";
|
|
4
4
|
import { createPortal } from "react-dom";
|
|
5
5
|
import { Link, NavLink, matchPath, useLocation } from "react-router";
|
|
6
6
|
import { ChevronRight, PanelLeftClose, PanelLeftOpen } from "lucide-react";
|
|
7
7
|
import { cn } from "../lib/cn.js";
|
|
8
|
+
import { scrollIntoStrip, useStripFade } from "../lib/strip-fade.js";
|
|
8
9
|
import { dirOf } from "../lib/direction.js";
|
|
9
10
|
import { readStored, writeStored } from "../lib/safe-storage.js";
|
|
10
11
|
import { Tooltip } from "../components/tooltip.js";
|
|
@@ -49,6 +50,7 @@ function AppShell({
|
|
|
49
50
|
expandLabel,
|
|
50
51
|
subNav = "flyout",
|
|
51
52
|
mobileSubNav = true,
|
|
53
|
+
mobileSubNavLayout = "wrap",
|
|
52
54
|
toggleGroupLabel,
|
|
53
55
|
embedded: embeddedProp,
|
|
54
56
|
className,
|
|
@@ -166,7 +168,7 @@ function AppShell({
|
|
|
166
168
|
ref: navRef,
|
|
167
169
|
className: "md:hidden fixed bottom-0 inset-x-0 z-30 border-t border-[var(--border)] bg-[var(--bg-surface)]",
|
|
168
170
|
children: [
|
|
169
|
-
mobileSubNav && /* @__PURE__ */ jsx(MobileSubNav, { nav }),
|
|
171
|
+
mobileSubNav && /* @__PURE__ */ jsx(MobileSubNav, { nav, layout: mobileSubNavLayout }),
|
|
170
172
|
/* @__PURE__ */ jsx(
|
|
171
173
|
"nav",
|
|
172
174
|
{
|
|
@@ -260,8 +262,16 @@ function MobileNavItem({ item }) {
|
|
|
260
262
|
}
|
|
261
263
|
);
|
|
262
264
|
}
|
|
263
|
-
function MobileSubNav({ nav }) {
|
|
265
|
+
function MobileSubNav({ nav, layout }) {
|
|
264
266
|
const { pathname } = useLocation();
|
|
267
|
+
const scroll = layout === "scroll";
|
|
268
|
+
const listRef = useRef(null);
|
|
269
|
+
const fade = useStripFade(listRef);
|
|
270
|
+
useLayoutEffect(() => {
|
|
271
|
+
const list = listRef.current;
|
|
272
|
+
const current = list?.querySelector('[aria-current="page"]');
|
|
273
|
+
if (scroll && list && current) scrollIntoStrip(list, current);
|
|
274
|
+
}, [scroll, pathname]);
|
|
265
275
|
const group = nav.find(
|
|
266
276
|
(item) => !!item.items?.length && (matchPath({ path: item.to, end: item.end ?? true }, pathname) || item.items.some((sub) => matchPath({ path: sub.to, end: sub.end ?? true }, pathname)))
|
|
267
277
|
);
|
|
@@ -274,7 +284,13 @@ function MobileSubNav({ nav }) {
|
|
|
274
284
|
children: /* @__PURE__ */ jsx(
|
|
275
285
|
"ul",
|
|
276
286
|
{
|
|
277
|
-
|
|
287
|
+
ref: listRef,
|
|
288
|
+
className: cn(
|
|
289
|
+
"flex gap-1.5 px-3 py-2",
|
|
290
|
+
scroll ? "overflow-x-auto overscroll-x-contain [scrollbar-width:none]" : "flex-wrap"
|
|
291
|
+
),
|
|
292
|
+
"data-overflow": scroll ? fade.overflow : void 0,
|
|
293
|
+
style: scroll && fade.mask ? { maskImage: fade.mask, WebkitMaskImage: fade.mask } : void 0,
|
|
278
294
|
children: group.items.map((sub) => /* @__PURE__ */ jsx("li", { className: "shrink-0", children: /* @__PURE__ */ jsxs(
|
|
279
295
|
NavLink,
|
|
280
296
|
{
|