@godxjp/ui 11.0.2 → 12.0.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.
Files changed (107) hide show
  1. package/README.md +40 -12
  2. package/dist/app/index.d.ts +1 -5
  3. package/dist/app/index.js +4 -4
  4. package/dist/{checkbox-em-oFM5D.d.ts → checkbox-DPFcnsMZ.d.ts} +1 -1
  5. package/dist/{chunk-QVLUCB47.js → chunk-2JCSS6B4.js} +2 -2
  6. package/dist/{chunk-6CSBMMZS.js → chunk-3ELRYXJK.js} +27 -0
  7. package/dist/{chunk-NXVCI6YB.js → chunk-3LPY7YA4.js} +2 -2
  8. package/dist/chunk-BCBK4FLV.js +83 -0
  9. package/dist/{chunk-FAB3LMTK.js → chunk-F7BEIY7S.js} +3 -3
  10. package/dist/chunk-FK2JDABO.js +318 -0
  11. package/dist/{chunk-X2VY4MOW.js → chunk-FK5QEFVY.js} +2 -11
  12. package/dist/{chunk-SARQRCKO.js → chunk-FOANNF6Z.js} +1 -1
  13. package/dist/{chunk-DNGJHWJZ.js → chunk-FTOG7D4T.js} +4 -2
  14. package/dist/{chunk-PUGEOUWZ.js → chunk-I6HD36IU.js} +2 -2
  15. package/dist/{chunk-2HOTP7RL.js → chunk-JSQOCVM6.js} +4 -78
  16. package/dist/{chunk-Z46J47FY.js → chunk-L2MEN2VK.js} +1 -1
  17. package/dist/{chunk-3Q4A4U2P.js → chunk-MMFIL33F.js} +1 -1
  18. package/dist/{chunk-IHRMOJXD.js → chunk-N6ELT7KB.js} +0 -47
  19. package/dist/{chunk-UNVRNJCB.js → chunk-PO5ISUFA.js} +1 -1
  20. package/dist/{chunk-T2QO2S65.js → chunk-PY3CXDO2.js} +3 -3
  21. package/dist/{chunk-EE5DKOHX.js → chunk-SIUIIIQW.js} +1 -1
  22. package/dist/{chunk-HTG5VHU7.js → chunk-TXRYSMOD.js} +2 -6
  23. package/dist/{chunk-IY347EQA.js → chunk-UDEPO3UF.js} +1 -1
  24. package/dist/{chunk-BG5RNXTH.js → chunk-UJUWAQE5.js} +1 -1
  25. package/dist/{chunk-PDXFQS7M.js → chunk-VWDXRNOK.js} +4 -6
  26. package/dist/{chunk-QR7MITE6.js → chunk-WBUUCU7R.js} +52 -20
  27. package/dist/{chunk-54R5TEXH.js → chunk-WJNR3RAG.js} +40 -20
  28. package/dist/{chunk-USNR424B.js → chunk-XT2AI6WJ.js} +4 -11
  29. package/dist/{chunk-JWGLJXQU.js → chunk-XVD5SLDL.js} +1 -1
  30. package/dist/chunk-YD7V2HGZ.js +13 -0
  31. package/dist/{chunk-VSM44AYE.js → chunk-YGD4CCQC.js} +36 -15
  32. package/dist/components/admin/index.d.ts +7 -15
  33. package/dist/components/admin/index.js +28 -26
  34. package/dist/components/data-display/badge.js +3 -3
  35. package/dist/components/data-display/card.d.ts +2 -2
  36. package/dist/components/data-display/carousel.js +3 -3
  37. package/dist/components/data-display/index.js +8 -7
  38. package/dist/components/data-entry/calendar.d.ts +1 -1
  39. package/dist/components/data-entry/calendar.js +1 -1
  40. package/dist/components/data-entry/cascader.d.ts +1 -1
  41. package/dist/components/data-entry/cascader.js +3 -6
  42. package/dist/components/data-entry/checkbox.d.ts +2 -2
  43. package/dist/components/data-entry/color-picker.d.ts +1 -1
  44. package/dist/components/data-entry/color-picker.js +3 -3
  45. package/dist/components/data-entry/command.d.ts +10 -10
  46. package/dist/components/data-entry/date-picker.d.ts +1 -1
  47. package/dist/components/data-entry/date-picker.js +4 -4
  48. package/dist/components/data-entry/date-range-picker.d.ts +1 -1
  49. package/dist/components/data-entry/date-range-picker.js +4 -4
  50. package/dist/components/data-entry/index.d.ts +3 -3
  51. package/dist/components/data-entry/index.js +18 -17
  52. package/dist/components/data-entry/radio.d.ts +1 -1
  53. package/dist/components/data-entry/select.d.ts +1 -1
  54. package/dist/components/data-entry/select.js +4 -4
  55. package/dist/components/data-entry/slider.d.ts +1 -1
  56. package/dist/components/data-entry/switch.d.ts +1 -1
  57. package/dist/components/data-entry/time-input.js +2 -2
  58. package/dist/components/data-entry/time-picker.d.ts +1 -1
  59. package/dist/components/data-entry/time-picker.js +3 -3
  60. package/dist/components/data-entry/transfer.d.ts +2 -2
  61. package/dist/components/data-entry/transfer.js +5 -4
  62. package/dist/components/data-entry/tree-select.d.ts +1 -1
  63. package/dist/components/data-entry/tree-select.js +3 -3
  64. package/dist/components/data-entry/upload.d.ts +2 -2
  65. package/dist/components/data-entry/upload.js +5 -5
  66. package/dist/components/data-grid/index.d.ts +71 -0
  67. package/dist/components/data-grid/index.js +372 -0
  68. package/dist/components/feedback/alert.js +4 -4
  69. package/dist/components/feedback/dialog.js +3 -3
  70. package/dist/components/feedback/index.d.ts +3 -3
  71. package/dist/components/feedback/index.js +6 -6
  72. package/dist/components/layout/index.d.ts +3 -3
  73. package/dist/components/layout/index.js +5 -5
  74. package/dist/components/navigation/index.d.ts +2 -2
  75. package/dist/components/navigation/index.js +9 -9
  76. package/dist/components/navigation/pagination.d.ts +1 -1
  77. package/dist/components/navigation/pagination.js +5 -5
  78. package/dist/components/navigation/steps.d.ts +2 -2
  79. package/dist/components/navigation/steps.js +3 -3
  80. package/dist/components/query/index.d.ts +1 -2
  81. package/dist/components/query/index.js +4 -4
  82. package/dist/components/ui/index.d.ts +3 -3
  83. package/dist/components/ui/index.js +25 -25
  84. package/dist/{data-entry.prop-BR4vNA1j.d.ts → data-entry.prop-6J0o45se.d.ts} +3 -25
  85. package/dist/{filter-bar-BxjSJJnQ.d.ts → filter-bar-B07JSxME.d.ts} +1 -1
  86. package/dist/{flex-D_EXRFSW.d.ts → flex-DXtIALBh.d.ts} +1 -1
  87. package/dist/i18n/index.d.ts +10 -0
  88. package/dist/i18n/index.js +2 -2
  89. package/dist/index.d.ts +7 -7
  90. package/dist/index.js +37 -35
  91. package/dist/{layout.prop-JE2TcRyL.d.ts → layout.prop-B1yQPUNZ.d.ts} +2 -17
  92. package/dist/lib/datetime/index.js +1 -1
  93. package/dist/{navigation.prop-DMcXkR-J.d.ts → navigation.prop-Dumy196X.d.ts} +1 -5
  94. package/dist/props/components/index.d.ts +4 -4
  95. package/dist/props/index.d.ts +4 -4
  96. package/dist/props/index.js +2 -2
  97. package/dist/props/registry.d.ts +0 -47
  98. package/dist/props/registry.js +1 -1
  99. package/dist/{query.prop-BDdz9L1G.d.ts → query.prop-Dog-EAfG.d.ts} +2 -6
  100. package/dist/{search-input-C_x-JFD3.d.ts → search-input-BR4nAWiT.d.ts} +1 -1
  101. package/dist/styles/control.css +3 -8
  102. package/dist/styles/layout.css +7 -3
  103. package/dist/styles/navigation-layout.css +3 -3
  104. package/dist/styles/shell-layout.css +4 -4
  105. package/package.json +15 -3
  106. package/dist/chunk-5NCFLCM7.js +0 -255
  107. /package/dist/{chunk-7CFO5FFE.js → chunk-GJXOBDER.js} +0 -0
package/README.md CHANGED
@@ -67,13 +67,13 @@ Components emit `data-slot` / `data-*`; the look lives in `styles/*-layout.css`.
67
67
 
68
68
  | Group | Import | Examples |
69
69
  | ------------------ | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
70
- | **Layout** | `@godxjp/ui/layout` | `Flex` (+ `Stack`/`Inline`), `PageContainer`, `ResponsiveGrid`, `AppShell`, `Sidebar`, `Separator`, `AspectRatio`, `Resizable` |
70
+ | **Layout** | `@godxjp/ui/layout` | `Flex`, `PageContainer`, `ResponsiveGrid`, `AppShell`, `Sidebar`, `Separator`, `AspectRatio`, `Resizable` |
71
71
  | **General** | `@godxjp/ui/general` | `Button` |
72
72
  | **Data Entry** | `@godxjp/ui/data-entry` | `Input`, `Select`, `FormField`, `Field`, `DatePicker`, `TimePicker`, `Combobox`, `Switch`, `Toggle`, `Upload`, `Cascader`, `TreeSelect`, `ColorPicker`, `Slider`, `PasswordInput`, `PasswordStrength`, `InputOTP`, `Rating`, `TagInput` |
73
73
  | **Data Display** | `@godxjp/ui/data-display` | `Table`, `DataTable`, `Card`, `StatCard`, `Badge`, `Avatar`, `Descriptions`, `Timeline`, `EmptyState`, `Progress`, `Accordion`, `HoverCard`, `Carousel`, `Popover`, `Collapsible` |
74
74
  | **Feedback** | `@godxjp/ui/feedback` | `Dialog`, `AlertDialog`, `Sheet` (side), `Drawer` (bottom-sheet), `Toast`, `Skeleton`, `Alert`, `Tooltip` |
75
75
  | **Query** | `@godxjp/ui/query` | `DataState`, `InfiniteQueryState`, `PrefetchLink` (adapter subpath — pulls TanStack Query) |
76
- | **Navigation** | `@godxjp/ui/navigation` | `Tabs`, `Toolbar` (+ `FilterBar`), `DropdownMenu`, `ContextMenu`, `Menubar`, `NavigationMenu`, `Steps`, `Pagination`, `Breadcrumb`, `LocalePicker` |
76
+ | **Navigation** | `@godxjp/ui/navigation` | `Tabs`, `Toolbar`, `DropdownMenu`, `ContextMenu`, `Menubar`, `NavigationMenu`, `Steps`, `Pagination`, `Breadcrumb`, `AppSettingPicker` |
77
77
  | **App** | `@godxjp/ui/app` | `AppProvider`, `useDateTime` (adapter — i18n/datetime singleton) |
78
78
  | **Datetime** | `@godxjp/ui/datetime` | `formatDate` (mandatory for display) |
79
79
  | **Form** | `@godxjp/ui/form` | `useZodForm`, `FormRoot` (adapter subpath — pulls react-hook-form) |
@@ -81,9 +81,37 @@ Components emit `data-slot` / `data-*`; the look lives in `styles/*-layout.css`.
81
81
  | **shadcn paths** | `@godxjp/ui/ui` | Thin re-exports for shadcn-style imports (tree-shakeable) |
82
82
  | **Admin (legacy)** | `@godxjp/ui/admin` | Compound admin exports |
83
83
 
84
- > **Renamed in 8.0** (thin aliases kept): `Stack`/`Inline`→`Flex`, `KeyValueGrid`→`Descriptions`,
85
- > `ProgressMeter`→`Progress`, `CardStat`→`StatCard`, `FilterBar`→`Toolbar`, `ChoiceField`→`Field`,
86
- > `SkeletonCard`→`SkeletonStat`. `StatusBadge`→`Badge` (`status`/`tone`), `DialogConfirm`/`Dialog mode="confirm"`→`AlertDialog`.
84
+ > **Renamed / removed** use the new names; the old aliases were **removed in v11** (they are no
85
+ > longer exported at runtime). See the [migration table](#migrating-6--11) below.
86
+
87
+ ---
88
+
89
+ ## Migrating 6 → 11
90
+
91
+ The v11 line dropped the deprecated compatibility aliases entirely — they are no longer exported
92
+ at runtime, and their leftover `*Prop` types and README references have now been removed too (issue
93
+ #99). Replace these at the call site:
94
+
95
+ | Removed / renamed (≤ v8) | Replacement (v11) |
96
+ | -------------------------------- | -------------------------------------------------- |
97
+ | `Stack` | `Flex direction="col"` (the default direction) |
98
+ | `Inline` | `Flex direction="row"` |
99
+ | `Autocomplete` | `Select` with `showSearch` + `options` |
100
+ | `CountrySelect` | `AppSettingPicker kind="country"` |
101
+ | `LocalePicker` | `AppSettingPicker kind="language"` |
102
+ | `CountryOptionLabel` | `Intl.DisplayNames` (ISO 3166-1 α-2) — no component |
103
+ | `SwitchField` | `Field` + `Switch` |
104
+ | `CardStat` | `StatCard` |
105
+ | `KeyValueGrid` | `Descriptions` |
106
+ | `ProgressMeter` | `Progress` |
107
+ | `FilterBar` | `Toolbar` |
108
+ | `ChoiceField` | `Field` |
109
+ | `SkeletonCard` | `SkeletonStat` |
110
+ | `StatusBadge` | `Badge` (`status` / `tone`) |
111
+ | `DialogConfirm` / `Dialog mode="confirm"` | `AlertDialog` |
112
+
113
+ For the full feature data grid (sort / search / column visibility / paging) see
114
+ `@godxjp/ui/data-grid` (`DataGrid`); the lean server-driven list stays `DataTable`.
87
115
 
88
116
  ---
89
117
 
@@ -109,7 +137,7 @@ import { PageContainer } from "@godxjp/ui/layout"; // every page wraps in this
109
137
 
110
138
  1. **Every page** uses `<PageContainer title subtitle extra footer>`.
111
139
  2. **Mobile-first** — verify at 320–390px in preview / browser.
112
- 3. **Spacing via `Stack`/`Inline` `gap` + `ResponsiveGrid`** — no Tailwind `p-*` /
140
+ 3. **Spacing via `Flex` `gap` + `ResponsiveGrid`** — no Tailwind `p-*` /
113
141
  `gap-*` / `space-x|y-*` for app layout (see `docs/SPACING.md`).
114
142
  4. **Semantic tokens only** — no raw colors / hex / `dark:` overrides.
115
143
  5. **Dates** display via `formatDate` from `@godxjp/ui/datetime`.
@@ -126,12 +154,12 @@ One token `--phi-unit` drives page/section/card spacing; micro control gaps use
126
154
  4px grid. Density (`compact` | `default` | `comfortable`) retunes `--phi-unit` with
127
155
  control + table heights together.
128
156
 
129
- | App API | φ level |
130
- | ------------------- | ------------------- |
131
- | `<Stack gap="md">` | φ⁰ (default) |
132
- | `<Stack gap="lg">` | φ¹ |
133
- | `<Stack gap="xl">` | φ² |
134
- | Card shell / footer | base × φ / base ÷ φ |
157
+ | App API | φ level |
158
+ | -------------------------------- | ------------------- |
159
+ | `<Flex direction="col" gap="md">`| φ⁰ (default) |
160
+ | `<Flex direction="col" gap="lg">`| φ¹ |
161
+ | `<Flex direction="col" gap="xl">`| φ² |
162
+ | Card shell / footer | base × φ / base ÷ φ |
135
163
 
136
164
  ---
137
165
 
@@ -26,8 +26,6 @@ declare function getDayPickerLocale(locale: AppLocale): react_day_picker.DayPick
26
26
 
27
27
  /** Curated preset — pass to `<AppProvider timezoneOptions={APP_TIMEZONE_PRESET} />`. */
28
28
  declare const APP_TIMEZONE_PRESET: readonly ["UTC", "Asia/Ho_Chi_Minh", "Asia/Bangkok", "Asia/Singapore", "Asia/Jakarta", "Asia/Manila", "Asia/Kuala_Lumpur", "Asia/Yangon", "Asia/Phnom_Penh", "Asia/Vientiane", "Asia/Brunei", "Asia/Tokyo", "Asia/Seoul", "Asia/Shanghai", "Asia/Hong_Kong", "Asia/Taipei", "Asia/Ulaanbaatar", "Asia/Kolkata", "Asia/Karachi", "Asia/Dhaka", "Asia/Colombo", "Asia/Dubai", "Asia/Riyadh", "Asia/Qatar", "Asia/Tehran", "Asia/Jerusalem", "Europe/London", "Europe/Paris", "Europe/Berlin", "Europe/Amsterdam", "Europe/Rome", "Europe/Madrid", "Europe/Moscow", "Europe/Istanbul", "America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles", "America/Toronto", "America/Vancouver", "America/Mexico_City", "America/Sao_Paulo", "America/Buenos_Aires", "Australia/Sydney", "Australia/Melbourne", "Australia/Perth", "Pacific/Auckland"];
29
- /** @deprecated Use `APP_TIMEZONE_PRESET` or `getAllIanaTimezones()`. */
30
- declare const APP_TIMEZONE_OPTIONS: readonly ["UTC", "Asia/Ho_Chi_Minh", "Asia/Bangkok", "Asia/Singapore", "Asia/Jakarta", "Asia/Manila", "Asia/Kuala_Lumpur", "Asia/Yangon", "Asia/Phnom_Penh", "Asia/Vientiane", "Asia/Brunei", "Asia/Tokyo", "Asia/Seoul", "Asia/Shanghai", "Asia/Hong_Kong", "Asia/Taipei", "Asia/Ulaanbaatar", "Asia/Kolkata", "Asia/Karachi", "Asia/Dhaka", "Asia/Colombo", "Asia/Dubai", "Asia/Riyadh", "Asia/Qatar", "Asia/Tehran", "Asia/Jerusalem", "Europe/London", "Europe/Paris", "Europe/Berlin", "Europe/Amsterdam", "Europe/Rome", "Europe/Madrid", "Europe/Moscow", "Europe/Istanbul", "America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles", "America/Toronto", "America/Vancouver", "America/Mexico_City", "America/Sao_Paulo", "America/Buenos_Aires", "Australia/Sydney", "Australia/Melbourne", "Australia/Perth", "Pacific/Auckland"];
31
29
  type AppTimezonePreset = (typeof APP_TIMEZONE_PRESET)[number];
32
30
  /**
33
31
  * Preferred IANA ids not returned by all runtimes (e.g. Node lists `Asia/Saigon` only).
@@ -39,8 +37,6 @@ declare function resolveTimezoneForIntl(timezone: string): string;
39
37
  /** Full IANA list from runtime — sorted lexicographically. */
40
38
  declare function getAllIanaTimezones(): readonly string[];
41
39
  declare function isValidIanaTimezone(value: string): boolean;
42
- /** @deprecated Use `isValidIanaTimezone`. */
43
- declare function isKnownAppTimezone(value: string): value is AppTimezonePreset;
44
40
  /**
45
41
  * Options for TimezonePicker.
46
42
  * - `configured` omitted/empty → full IANA list
@@ -137,4 +133,4 @@ declare function useFormatting(): {
137
133
  /** Alias for useFormatting — emphasises timezone-aware datetime helpers. */
138
134
  declare const useDateTime: typeof useFormatting;
139
135
 
140
- export { APP_DATE_FORMAT_OPTIONS, APP_LOCALE_CONFIG, APP_TIMEZONE_OPTIONS, APP_TIMEZONE_PRESET, APP_TIME_FORMAT_OPTIONS, AppDateFormat, AppLocale, type AppLocaleConfig, AppProvider, AppRequestHeaders, AppTimeFormat, AppTimezone, type AppTimezonePreset, DEFAULT_STORAGE_KEY, FormatDateOptions, type StoredAppPreferences, TIMEZONE_ALIASES, formatDate, formatTimezoneDisplayLabel, getAllIanaTimezones, getAppRequestHeaders, getBrowserTimezone, getDateFnsLocale, getDateFormatLabel, getDayPickerLocale, getTimeFormatLabel, getTimezoneCityName, getTimezoneLabel, getTimezoneOffsetLabel, isAppLocale, isKnownAppTimezone, isValidIanaTimezone, readStoredPreferences, resetAppRequestHeaders, resetIanaTimezoneCacheForTests, resolveDefaultDateFormat, resolveDefaultTimeFormat, resolveDefaultTimezone, resolveTimezoneForIntl, resolveTimezonePickerOptions, syncAppRequestHeaders, useAppContext, useAppDateFormat, useAppLocale, useAppTimeFormat, useAppTimezone, useDateTime, useFormatting, useOptionalAppContext, writeStoredPreferences };
136
+ export { APP_DATE_FORMAT_OPTIONS, APP_LOCALE_CONFIG, APP_TIMEZONE_PRESET, APP_TIME_FORMAT_OPTIONS, AppDateFormat, AppLocale, type AppLocaleConfig, AppProvider, AppRequestHeaders, AppTimeFormat, AppTimezone, type AppTimezonePreset, DEFAULT_STORAGE_KEY, FormatDateOptions, type StoredAppPreferences, TIMEZONE_ALIASES, formatDate, formatTimezoneDisplayLabel, getAllIanaTimezones, getAppRequestHeaders, getBrowserTimezone, getDateFnsLocale, getDateFormatLabel, getDayPickerLocale, getTimeFormatLabel, getTimezoneCityName, getTimezoneLabel, getTimezoneOffsetLabel, isAppLocale, isValidIanaTimezone, readStoredPreferences, resetAppRequestHeaders, resetIanaTimezoneCacheForTests, resolveDefaultDateFormat, resolveDefaultTimeFormat, resolveDefaultTimezone, resolveTimezoneForIntl, resolveTimezonePickerOptions, syncAppRequestHeaders, useAppContext, useAppDateFormat, useAppLocale, useAppTimeFormat, useAppTimezone, useDateTime, useFormatting, useOptionalAppContext, writeStoredPreferences };
package/dist/app/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { useAppContext } from '../chunk-HTG5VHU7.js';
2
- export { APP_LOCALES, APP_REQUEST_HEADER_LOCALE, APP_REQUEST_HEADER_TIMEZONE, APP_TIMEZONE_OPTIONS, APP_TIMEZONE_PRESET, APP_TIME_FORMAT_OPTIONS, AppProvider, DEFAULT_STORAGE_KEY, TIMEZONE_ALIASES, formatTimezoneDisplayLabel, getAllIanaTimezones, getAppRequestHeaders, getBrowserTimezone, getTimeFormatLabel, getTimezoneCityName, getTimezoneLabel, getTimezoneOffsetLabel, isKnownAppTimezone, isValidIanaTimezone, readStoredPreferences, resetAppRequestHeaders, resetIanaTimezoneCacheForTests, resolveDefaultTimeFormat, resolveDefaultTimezone, resolveTimezoneForIntl, resolveTimezonePickerOptions, syncAppRequestHeaders, useAppContext, useAppDateFormat, useAppLocale, useAppTimeFormat, useAppTimezone, useOptionalAppContext, usePickerLocales, useTranslation, writeStoredPreferences } from '../chunk-HTG5VHU7.js';
3
- import { formatDate } from '../chunk-6CSBMMZS.js';
4
- export { APP_DATE_FORMATS, APP_DATE_FORMAT_OPTIONS, APP_LOCALE_CONFIG, APP_REQUEST_HEADER_DATE_FORMAT, APP_REQUEST_HEADER_TIME_FORMAT, APP_TIME_FORMATS, detectFormatDateKind, formatAppDate, formatAppDateLong, formatAppDateTime, formatAppRelative, formatAppTime, formatCalendarDate, formatDate, formatTimeOfDay, getDateFnsLocale, getDateFormatLabel, getDatePattern, getDateTimePattern, getDatetimeContext, getDayPickerLocale, getTimePattern, isAppDateFormat, isAppLocale, isAppTimeFormat, isFormatDateValue, isValidHhmm, normalizeHhmm, parseDateInput, resolveDefaultDateFormat, syncDatetimeContext } from '../chunk-6CSBMMZS.js';
1
+ import { useAppContext } from '../chunk-TXRYSMOD.js';
2
+ export { APP_LOCALES, APP_REQUEST_HEADER_LOCALE, APP_REQUEST_HEADER_TIMEZONE, APP_TIMEZONE_PRESET, APP_TIME_FORMAT_OPTIONS, AppProvider, DEFAULT_STORAGE_KEY, TIMEZONE_ALIASES, formatTimezoneDisplayLabel, getAllIanaTimezones, getAppRequestHeaders, getBrowserTimezone, getTimeFormatLabel, getTimezoneCityName, getTimezoneLabel, getTimezoneOffsetLabel, isValidIanaTimezone, readStoredPreferences, resetAppRequestHeaders, resetIanaTimezoneCacheForTests, resolveDefaultTimeFormat, resolveDefaultTimezone, resolveTimezoneForIntl, resolveTimezonePickerOptions, syncAppRequestHeaders, useAppContext, useAppDateFormat, useAppLocale, useAppTimeFormat, useAppTimezone, useOptionalAppContext, usePickerLocales, useTranslation, writeStoredPreferences } from '../chunk-TXRYSMOD.js';
3
+ import { formatDate } from '../chunk-3ELRYXJK.js';
4
+ export { APP_DATE_FORMATS, APP_DATE_FORMAT_OPTIONS, APP_LOCALE_CONFIG, APP_REQUEST_HEADER_DATE_FORMAT, APP_REQUEST_HEADER_TIME_FORMAT, APP_TIME_FORMATS, detectFormatDateKind, formatAppDate, formatAppDateLong, formatAppDateTime, formatAppRelative, formatAppTime, formatCalendarDate, formatDate, formatTimeOfDay, getDateFnsLocale, getDateFormatLabel, getDatePattern, getDateTimePattern, getDatetimeContext, getDayPickerLocale, getTimePattern, isAppDateFormat, isAppLocale, isAppTimeFormat, isFormatDateValue, isValidHhmm, normalizeHhmm, parseDateInput, resolveDefaultDateFormat, syncDatetimeContext } from '../chunk-3ELRYXJK.js';
5
5
  import { useMemo } from 'react';
6
6
 
7
7
  function useFormatting() {
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
- import { c as CheckboxGroupProp } from './data-entry.prop-BR4vNA1j.js';
4
+ import { b as CheckboxGroupProp } from './data-entry.prop-6J0o45se.js';
5
5
 
6
6
  declare function CheckboxGroup({ value: controlledValue, defaultValue, onValueChange, options, orientation, disabled, name, className, children, }: CheckboxGroupProp): react_jsx_runtime.JSX.Element;
7
7
 
@@ -1,7 +1,7 @@
1
- import { humanError } from './chunk-X2VY4MOW.js';
1
+ import { humanError } from './chunk-FK5QEFVY.js';
2
2
  import { Flex } from './chunk-INIIF7F7.js';
3
3
  import { Button } from './chunk-M4PZNAMV.js';
4
- import { useTranslation } from './chunk-HTG5VHU7.js';
4
+ import { useTranslation } from './chunk-TXRYSMOD.js';
5
5
  import { cn } from './chunk-U7N2A7A3.js';
6
6
  import * as React from 'react';
7
7
  import { Info, CheckCircle2, TriangleAlert, AlertCircle, X, RefreshCw } from 'lucide-react';
@@ -63,6 +63,7 @@ var en_default = {
63
63
  clearSearch: "Clear search",
64
64
  clearFilters: "Clear filters",
65
65
  first: "First",
66
+ previous: "Previous",
66
67
  next: "Next",
67
68
  selectedCount: "{count} selected",
68
69
  typeToConfirm: "Type {phrase} to confirm"
@@ -278,6 +279,14 @@ var en_default = {
278
279
  empty: "No data",
279
280
  loading: "Loading\u2026"
280
281
  },
282
+ dataGrid: {
283
+ search: "Search",
284
+ searchPlaceholder: "Search\u2026",
285
+ view: "View",
286
+ toggleColumns: "Toggle columns",
287
+ rowsPerPage: "Rows per page",
288
+ pageOf: "Page {page} of {total}"
289
+ },
281
290
  status: {
282
291
  active: "Active",
283
292
  completed: "Completed",
@@ -319,6 +328,7 @@ var ja_default = {
319
328
  clearSearch: "\u691C\u7D22\u3092\u30AF\u30EA\u30A2",
320
329
  clearFilters: "\u30D5\u30A3\u30EB\u30BF\u30FC\u3092\u30AF\u30EA\u30A2",
321
330
  first: "\u6700\u521D",
331
+ previous: "\u524D\u3078",
322
332
  next: "\u6B21\u3078",
323
333
  selectedCount: "{count} \u4EF6\u9078\u629E",
324
334
  typeToConfirm: "\u78BA\u8A8D\u306E\u305F\u3081 {phrase} \u3068\u5165\u529B"
@@ -534,6 +544,14 @@ var ja_default = {
534
544
  empty: "\u30C7\u30FC\u30BF\u304C\u3042\u308A\u307E\u305B\u3093",
535
545
  loading: "\u8AAD\u307F\u8FBC\u307F\u4E2D\u2026"
536
546
  },
547
+ dataGrid: {
548
+ search: "\u691C\u7D22",
549
+ searchPlaceholder: "\u691C\u7D22\u2026",
550
+ view: "\u8868\u793A",
551
+ toggleColumns: "\u5217\u306E\u8868\u793A\u5207\u66FF",
552
+ rowsPerPage: "\u8868\u793A\u4EF6\u6570",
553
+ pageOf: "{page} / {total} \u30DA\u30FC\u30B8"
554
+ },
537
555
  status: {
538
556
  active: "\u6709\u52B9",
539
557
  completed: "\u5B8C\u4E86",
@@ -575,6 +593,7 @@ var vi_default = {
575
593
  clearSearch: "X\xF3a t\xECm ki\u1EBFm",
576
594
  clearFilters: "X\xF3a b\u1ED9 l\u1ECDc",
577
595
  first: "\u0110\u1EA7u",
596
+ previous: "Tr\u01B0\u1EDBc",
578
597
  next: "Ti\u1EBFp",
579
598
  selectedCount: "{count} \u0111\xE3 ch\u1ECDn",
580
599
  typeToConfirm: "Nh\u1EADp {phrase} \u0111\u1EC3 x\xE1c nh\u1EADn"
@@ -790,6 +809,14 @@ var vi_default = {
790
809
  empty: "Ch\u01B0a c\xF3 d\u1EEF li\u1EC7u",
791
810
  loading: "\u0110ang t\u1EA3i\u2026"
792
811
  },
812
+ dataGrid: {
813
+ search: "T\xECm ki\u1EBFm",
814
+ searchPlaceholder: "T\xECm ki\u1EBFm\u2026",
815
+ view: "Hi\u1EC3n th\u1ECB",
816
+ toggleColumns: "\u1EA8n/hi\u1EC7n c\u1ED9t",
817
+ rowsPerPage: "S\u1ED1 d\xF2ng/trang",
818
+ pageOf: "Trang {page}/{total}"
819
+ },
793
820
  status: {
794
821
  active: "\u0110ang ho\u1EA1t \u0111\u1ED9ng",
795
822
  completed: "Ho\xE0n th\xE0nh",
@@ -1,9 +1,9 @@
1
- import { Command, CommandList, CommandItem, CommandGroup } from './chunk-HTEL5DQI.js';
2
1
  import { Input } from './chunk-VOHTRR5X.js';
2
+ import { Command, CommandList, CommandItem, CommandGroup } from './chunk-HTEL5DQI.js';
3
3
  import { Button } from './chunk-M4PZNAMV.js';
4
4
  import { Popover, PopoverTrigger, PopoverContent } from './chunk-DY5C44UP.js';
5
5
  import { controlTriggerClass } from './chunk-IBK5D2Q6.js';
6
- import { useTranslation } from './chunk-HTG5VHU7.js';
6
+ import { useTranslation } from './chunk-TXRYSMOD.js';
7
7
  import { cn } from './chunk-U7N2A7A3.js';
8
8
  import * as React from 'react';
9
9
  import * as SelectPrimitive from '@radix-ui/react-select';
@@ -0,0 +1,83 @@
1
+ import { Input } from './chunk-VOHTRR5X.js';
2
+ import { Label } from './chunk-7PWBC4BY.js';
3
+ import { useTranslation } from './chunk-TXRYSMOD.js';
4
+ import { useDebouncedValue } from './chunk-LFW37FGG.js';
5
+ import { cn } from './chunk-U7N2A7A3.js';
6
+ import * as React from 'react';
7
+ import { Search, X } from 'lucide-react';
8
+ import { jsxs, jsx } from 'react/jsx-runtime';
9
+
10
+ function SearchInput({
11
+ value: controlledValue,
12
+ defaultValue = "",
13
+ placeholder,
14
+ debounce = 250,
15
+ onValueChange,
16
+ onSearch,
17
+ label,
18
+ ariaLabel,
19
+ className,
20
+ inputClassName,
21
+ id,
22
+ disabled = false
23
+ }) {
24
+ const { t } = useTranslation();
25
+ const isControlled = controlledValue !== void 0;
26
+ const [internal, setInternal] = React.useState(defaultValue);
27
+ const value = isControlled ? controlledValue : internal;
28
+ const debounced = useDebouncedValue(value, debounce);
29
+ const reactId = React.useId();
30
+ const inputId = id ?? `search-${reactId}`;
31
+ const resolvedPlaceholder = placeholder ?? t("dataEntry.searchInput.placeholder");
32
+ const resolvedAriaLabel = ariaLabel ?? t("common.search");
33
+ const onSearchRef = React.useRef(onSearch);
34
+ React.useEffect(() => {
35
+ onSearchRef.current = onSearch;
36
+ });
37
+ React.useEffect(() => {
38
+ onSearchRef.current(debounced);
39
+ }, [debounced]);
40
+ const setValue = (v) => {
41
+ if (!isControlled) setInternal(v);
42
+ onValueChange?.(v);
43
+ };
44
+ return /* @__PURE__ */ jsxs("div", { className: cn("ui-search-input", className), children: [
45
+ label !== void 0 ? /* @__PURE__ */ jsx(Label, { htmlFor: inputId, className: "ui-search-input-label", children: label }) : /* @__PURE__ */ jsx(Label, { htmlFor: inputId, className: "sr-only", children: resolvedAriaLabel }),
46
+ /* @__PURE__ */ jsxs("div", { className: "ui-search-input-field", children: [
47
+ /* @__PURE__ */ jsx(Search, { className: "ui-search-input-icon", "aria-hidden": "true" }),
48
+ /* @__PURE__ */ jsx(
49
+ Input,
50
+ {
51
+ id: inputId,
52
+ type: "text",
53
+ role: "searchbox",
54
+ value,
55
+ onChange: (e) => {
56
+ setValue(e.target.value);
57
+ },
58
+ placeholder: resolvedPlaceholder,
59
+ "aria-label": resolvedAriaLabel,
60
+ className: cn(
61
+ "ui-search-input-control !pr-[var(--search-input-end-padding)] !pl-[var(--search-input-start-padding)]",
62
+ inputClassName
63
+ ),
64
+ disabled
65
+ }
66
+ ),
67
+ value && !disabled && /* @__PURE__ */ jsx(
68
+ "button",
69
+ {
70
+ type: "button",
71
+ onClick: () => {
72
+ setValue("");
73
+ },
74
+ "aria-label": t("common.clearSearch"),
75
+ className: "ui-search-input-clear",
76
+ children: /* @__PURE__ */ jsx(X, {})
77
+ }
78
+ )
79
+ ] })
80
+ ] });
81
+ }
82
+
83
+ export { SearchInput };
@@ -1,9 +1,9 @@
1
- import { formatBytes } from './chunk-X2VY4MOW.js';
2
- import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from './chunk-BG5RNXTH.js';
3
1
  import { Slider } from './chunk-CRERCLIZ.js';
2
+ import { formatBytes } from './chunk-FK5QEFVY.js';
3
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from './chunk-UJUWAQE5.js';
4
4
  import { Button } from './chunk-M4PZNAMV.js';
5
5
  import { controlIconClass } from './chunk-IBK5D2Q6.js';
6
- import { useTranslation } from './chunk-HTG5VHU7.js';
6
+ import { useTranslation } from './chunk-TXRYSMOD.js';
7
7
  import { cn } from './chunk-U7N2A7A3.js';
8
8
  import * as React2 from 'react';
9
9
  import { Upload as Upload$1, ImagePlus, Camera, Trash2, RotateCcw, X } from 'lucide-react';
@@ -0,0 +1,318 @@
1
+ import { normalizeTreeOptions, formatPathLabels, getNodeByPath, filterTreeOptions, pathsEqual, pathKey } from './chunk-SMLKNECP.js';
2
+ import { Command, CommandInput } from './chunk-HTEL5DQI.js';
3
+ import { Button } from './chunk-M4PZNAMV.js';
4
+ import { Popover, PopoverTrigger, PopoverContent } from './chunk-DY5C44UP.js';
5
+ import { ScrollArea, ScrollBar } from './chunk-3KPEZ5CF.js';
6
+ import { useTranslation } from './chunk-TXRYSMOD.js';
7
+ import { cn } from './chunk-U7N2A7A3.js';
8
+ import * as React from 'react';
9
+ import { Check, X, ChevronsUpDown, ChevronRight, Minus } from 'lucide-react';
10
+ import { jsxs, jsx } from 'react/jsx-runtime';
11
+
12
+ function pathInValues(path, values) {
13
+ return values.some((v) => pathsEqual(v, path));
14
+ }
15
+ function togglePath(values, path) {
16
+ if (pathInValues(path, values)) return values.filter((v) => !pathsEqual(v, path));
17
+ return [...values, path];
18
+ }
19
+ function CheckboxVisual({
20
+ checked,
21
+ indeterminate,
22
+ disabled,
23
+ className
24
+ }) {
25
+ const state = indeterminate ? "indeterminate" : checked ? "checked" : "unchecked";
26
+ return /* @__PURE__ */ jsx(
27
+ "span",
28
+ {
29
+ "aria-hidden": "true",
30
+ "data-slot": "checkbox",
31
+ "data-state": state,
32
+ className: cn(
33
+ "ui-checkbox inline-flex items-center justify-center",
34
+ // The shared CSS fills the box for [data-state=checked]; mirror that fill for the
35
+ // indeterminate ("some children selected") state so a partial parent reads as partial.
36
+ "data-[state=indeterminate]:border-primary data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground",
37
+ disabled && "cursor-not-allowed opacity-50",
38
+ className
39
+ ),
40
+ children: indeterminate ? /* @__PURE__ */ jsx(Minus, { className: "ui-checkbox-icon", "aria-hidden": "true" }) : checked ? /* @__PURE__ */ jsx(Check, { className: "ui-checkbox-icon", "aria-hidden": "true" }) : null
41
+ }
42
+ );
43
+ }
44
+ function aggregateCheckState(node, path, values) {
45
+ let total = 0;
46
+ let selected = 0;
47
+ const walk = (n, p) => {
48
+ const isLeaf = (n.children?.length ?? 0) === 0 || n.isLeaf === true;
49
+ if (isLeaf) {
50
+ if (n.disabled || n.disableCheckbox) return;
51
+ total += 1;
52
+ if (pathInValues(p, values)) selected += 1;
53
+ return;
54
+ }
55
+ for (const child of n.children) walk(child, [...p, child.value]);
56
+ };
57
+ for (const child of node.children ?? []) walk(child, [...path, child.value]);
58
+ if (total === 0 || selected === 0) return "none";
59
+ return selected === total ? "checked" : "indeterminate";
60
+ }
61
+ function Cascader({
62
+ options: optionsProp,
63
+ value,
64
+ defaultValue,
65
+ onValueChange,
66
+ multiple,
67
+ changeOnSelect,
68
+ showSearch,
69
+ placeholder,
70
+ disabled,
71
+ className,
72
+ id,
73
+ expandTrigger = "click",
74
+ fieldNames,
75
+ allowClear = true
76
+ }) {
77
+ const { t } = useTranslation();
78
+ const options = React.useMemo(
79
+ () => normalizeTreeOptions(optionsProp, fieldNames),
80
+ [optionsProp, fieldNames]
81
+ );
82
+ const [open, setOpen] = React.useState(false);
83
+ const [activePath, setActivePath] = React.useState([]);
84
+ const [search, setSearch] = React.useState("");
85
+ const isControlledSingle = !multiple && value !== void 0;
86
+ const isControlledMulti = multiple && value !== void 0;
87
+ const [internalSingle, setInternalSingle] = React.useState(
88
+ multiple ? [] : defaultValue ?? []
89
+ );
90
+ const [internalMulti, setInternalMulti] = React.useState(
91
+ defaultValue ?? []
92
+ );
93
+ const singleValue = isControlledSingle ? value : internalSingle;
94
+ const multiValue = isControlledMulti ? value : internalMulti;
95
+ const resolvedPlaceholder = placeholder ?? t("dataEntry.cascader.placeholder");
96
+ const displayLabel = React.useMemo(() => {
97
+ if (multiple) {
98
+ if (!multiValue.length) return null;
99
+ return multiValue.map((path) => formatPathLabels(getNodeByPath(options, path))).join(", ");
100
+ }
101
+ if (!singleValue.length) return null;
102
+ return formatPathLabels(getNodeByPath(options, singleValue));
103
+ }, [multiple, multiValue, singleValue, options]);
104
+ const setSingleValue = (path) => {
105
+ if (!isControlledSingle) setInternalSingle(path);
106
+ onValueChange?.(path, getNodeByPath(options, path));
107
+ };
108
+ const commitSingle = (path) => {
109
+ setSingleValue(path);
110
+ setOpen(false);
111
+ setActivePath([]);
112
+ setSearch("");
113
+ };
114
+ const commitMulti = (paths) => {
115
+ if (!isControlledMulti) setInternalMulti(paths);
116
+ onValueChange?.(
117
+ paths,
118
+ paths.map((p) => getNodeByPath(options, p))
119
+ );
120
+ };
121
+ const columns = React.useMemo(() => {
122
+ const cols = [options];
123
+ for (const segment of activePath) {
124
+ const col = cols.at(-1);
125
+ const node = col?.find((n) => n.value === segment);
126
+ if (node?.children?.length) cols.push(node.children);
127
+ else break;
128
+ }
129
+ return cols;
130
+ }, [options, activePath]);
131
+ const handleSelectNode = (node, path) => {
132
+ const hasChildren = (node.children?.length ?? 0) > 0 && node.isLeaf !== true;
133
+ if (multiple) {
134
+ if (hasChildren && !changeOnSelect) setActivePath(path);
135
+ else if (!node.disableCheckbox) commitMulti(togglePath(multiValue, path));
136
+ return;
137
+ }
138
+ if (hasChildren) {
139
+ if (changeOnSelect) setSingleValue(path);
140
+ setActivePath(path);
141
+ return;
142
+ }
143
+ commitSingle(path);
144
+ };
145
+ const isSearching = showSearch && search.trim().length > 0;
146
+ const searchResults = React.useMemo(
147
+ () => isSearching ? filterTreeOptions(options, search) : [],
148
+ [options, search, isSearching]
149
+ );
150
+ const handleOpenChange = (next) => {
151
+ setOpen(next);
152
+ if (next) {
153
+ setActivePath(multiple ? [] : singleValue);
154
+ } else {
155
+ setSearch("");
156
+ setActivePath([]);
157
+ }
158
+ };
159
+ const clearValue = (e) => {
160
+ e.stopPropagation();
161
+ if (multiple) commitMulti([]);
162
+ else commitSingle([]);
163
+ };
164
+ const renderCascadeColumns = () => /* @__PURE__ */ jsxs(ScrollArea, { className: "w-full", children: [
165
+ /* @__PURE__ */ jsx("div", { className: "flex max-h-[min(280px,50vh)]", children: columns.map((col, colIndex) => /* @__PURE__ */ jsx(
166
+ "ul",
167
+ {
168
+ role: "listbox",
169
+ "aria-orientation": "vertical",
170
+ "aria-multiselectable": multiple ? true : void 0,
171
+ className: "min-w-[9rem] border-e last:border-e-0",
172
+ children: col.map((node) => {
173
+ const path = [...activePath.slice(0, colIndex), node.value];
174
+ const hasChildren = (node.children?.length ?? 0) > 0 && node.isLeaf !== true;
175
+ const active = activePath[colIndex] === node.value;
176
+ const selected = multiple ? pathInValues(path, multiValue) : pathsEqual(path, singleValue);
177
+ const aggregate = multiple && hasChildren ? aggregateCheckState(node, path, multiValue) : void 0;
178
+ return /* @__PURE__ */ jsx("li", { role: "none", children: /* @__PURE__ */ jsxs(
179
+ "button",
180
+ {
181
+ type: "button",
182
+ role: "option",
183
+ "aria-selected": selected,
184
+ "aria-haspopup": hasChildren ? "menu" : void 0,
185
+ "aria-expanded": hasChildren ? active : void 0,
186
+ disabled: node.disabled,
187
+ className: cn(
188
+ "flex w-full items-center gap-1 px-3 py-2 text-sm outline-none",
189
+ "hover:bg-accent hover:text-accent-foreground",
190
+ active && "bg-accent/70 font-medium",
191
+ node.disabled && "pointer-events-none opacity-50"
192
+ ),
193
+ onMouseEnter: (
194
+ // Hover-expand: a parent opens its children column; a leaf collapses any
195
+ // deeper column but keeps its own. Never collapse on the column's mouseleave
196
+ // — moving the pointer toward the next column would strand the deeper levels
197
+ // and make a depth-3 leaf unreachable.
198
+ expandTrigger === "hover" && !node.disabled ? () => setActivePath(hasChildren ? path : path.slice(0, -1)) : void 0
199
+ ),
200
+ onClick: () => !node.disabled && handleSelectNode(node, path),
201
+ children: [
202
+ multiple && /* @__PURE__ */ jsx(
203
+ CheckboxVisual,
204
+ {
205
+ checked: aggregate ? aggregate === "checked" : selected,
206
+ indeterminate: aggregate === "indeterminate",
207
+ disabled: node.disabled || node.disableCheckbox,
208
+ className: "me-1"
209
+ }
210
+ ),
211
+ !multiple && selected && /* @__PURE__ */ jsx(Check, { className: "me-1 size-4 shrink-0", "aria-hidden": "true" }),
212
+ /* @__PURE__ */ jsx("span", { className: "flex-1 truncate text-start", children: node.label }),
213
+ hasChildren && /* @__PURE__ */ jsx(ChevronRight, { className: "size-4 shrink-0 opacity-50", "aria-hidden": "true" })
214
+ ]
215
+ }
216
+ ) }, node.value);
217
+ })
218
+ },
219
+ colIndex
220
+ )) }),
221
+ /* @__PURE__ */ jsx(ScrollBar, { orientation: "horizontal" })
222
+ ] });
223
+ const showClear = allowClear && displayLabel && !disabled;
224
+ return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
225
+ /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
226
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
227
+ Button,
228
+ {
229
+ id,
230
+ type: "button",
231
+ variant: "outline",
232
+ role: "combobox",
233
+ "aria-expanded": open,
234
+ disabled,
235
+ className: cn(
236
+ "w-full justify-start font-normal",
237
+ // Reserve trailing room for the clear + chevron overlay rendered below.
238
+ showClear ? "pe-14" : "pe-9",
239
+ !displayLabel && "text-muted-foreground"
240
+ ),
241
+ children: /* @__PURE__ */ jsx("span", { className: "truncate", children: displayLabel ?? resolvedPlaceholder })
242
+ }
243
+ ) }),
244
+ /* @__PURE__ */ jsxs(
245
+ PopoverContent,
246
+ {
247
+ className: "w-auto min-w-[var(--radix-popover-trigger-width)] p-0",
248
+ align: "start",
249
+ children: [
250
+ showSearch && /* @__PURE__ */ jsx("div", { className: "border-b p-2", children: /* @__PURE__ */ jsx(Command, { shouldFilter: false, children: /* @__PURE__ */ jsx(
251
+ CommandInput,
252
+ {
253
+ placeholder: t("dataEntry.cascader.searchPlaceholder"),
254
+ value: search,
255
+ onValueChange: setSearch
256
+ }
257
+ ) }) }),
258
+ isSearching ? /* @__PURE__ */ jsx(ScrollArea, { className: "max-h-[min(300px,50vh)]", children: /* @__PURE__ */ jsx(
259
+ "div",
260
+ {
261
+ className: "p-1",
262
+ role: "listbox",
263
+ "aria-multiselectable": multiple ? true : void 0,
264
+ children: searchResults.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-muted-foreground py-6 text-center text-sm", children: t("dataEntry.cascader.empty") }) : searchResults.map(({ path, labels }) => {
265
+ const label = labels.join(" / ");
266
+ const selected = multiple ? pathInValues(path, multiValue) : pathsEqual(path, singleValue);
267
+ return /* @__PURE__ */ jsxs(
268
+ "button",
269
+ {
270
+ type: "button",
271
+ role: "option",
272
+ "aria-selected": selected,
273
+ className: cn(
274
+ "flex w-full items-center rounded-sm px-2 py-1.5 text-sm outline-none",
275
+ "hover:bg-accent hover:text-accent-foreground",
276
+ selected && "bg-accent/60"
277
+ ),
278
+ onClick: () => handleSelectNode({ value: path.at(-1)}, path),
279
+ children: [
280
+ multiple ? /* @__PURE__ */ jsx(CheckboxVisual, { checked: selected, className: "me-2" }) : /* @__PURE__ */ jsx(
281
+ Check,
282
+ {
283
+ className: cn(
284
+ "me-2 size-4 shrink-0",
285
+ selected ? "opacity-100" : "opacity-0"
286
+ ),
287
+ "aria-hidden": "true"
288
+ }
289
+ ),
290
+ /* @__PURE__ */ jsx("span", { className: "truncate text-start", children: label })
291
+ ]
292
+ },
293
+ pathKey(path)
294
+ );
295
+ })
296
+ }
297
+ ) }) : renderCascadeColumns()
298
+ ]
299
+ }
300
+ )
301
+ ] }),
302
+ /* @__PURE__ */ jsxs("div", { className: "pointer-events-none absolute inset-y-0 end-3 flex items-center gap-1", children: [
303
+ showClear && /* @__PURE__ */ jsx(
304
+ "button",
305
+ {
306
+ type: "button",
307
+ "aria-label": t("dataEntry.cascader.clear"),
308
+ className: "pointer-events-auto flex size-4 items-center justify-center rounded-sm opacity-50 hover:opacity-100 focus-visible:opacity-100",
309
+ onClick: clearValue,
310
+ children: /* @__PURE__ */ jsx(X, { className: "size-4", "aria-hidden": "true" })
311
+ }
312
+ ),
313
+ /* @__PURE__ */ jsx(ChevronsUpDown, { className: "size-4 shrink-0 opacity-50", "aria-hidden": "true" })
314
+ ] })
315
+ ] });
316
+ }
317
+
318
+ export { Cascader };