@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.
- package/README.md +40 -12
- package/dist/app/index.d.ts +1 -5
- package/dist/app/index.js +4 -4
- package/dist/{checkbox-em-oFM5D.d.ts → checkbox-DPFcnsMZ.d.ts} +1 -1
- package/dist/{chunk-QVLUCB47.js → chunk-2JCSS6B4.js} +2 -2
- package/dist/{chunk-6CSBMMZS.js → chunk-3ELRYXJK.js} +27 -0
- package/dist/{chunk-NXVCI6YB.js → chunk-3LPY7YA4.js} +2 -2
- package/dist/chunk-BCBK4FLV.js +83 -0
- package/dist/{chunk-FAB3LMTK.js → chunk-F7BEIY7S.js} +3 -3
- package/dist/chunk-FK2JDABO.js +318 -0
- package/dist/{chunk-X2VY4MOW.js → chunk-FK5QEFVY.js} +2 -11
- package/dist/{chunk-SARQRCKO.js → chunk-FOANNF6Z.js} +1 -1
- package/dist/{chunk-DNGJHWJZ.js → chunk-FTOG7D4T.js} +4 -2
- package/dist/{chunk-PUGEOUWZ.js → chunk-I6HD36IU.js} +2 -2
- package/dist/{chunk-2HOTP7RL.js → chunk-JSQOCVM6.js} +4 -78
- package/dist/{chunk-Z46J47FY.js → chunk-L2MEN2VK.js} +1 -1
- package/dist/{chunk-3Q4A4U2P.js → chunk-MMFIL33F.js} +1 -1
- package/dist/{chunk-IHRMOJXD.js → chunk-N6ELT7KB.js} +0 -47
- package/dist/{chunk-UNVRNJCB.js → chunk-PO5ISUFA.js} +1 -1
- package/dist/{chunk-T2QO2S65.js → chunk-PY3CXDO2.js} +3 -3
- package/dist/{chunk-EE5DKOHX.js → chunk-SIUIIIQW.js} +1 -1
- package/dist/{chunk-HTG5VHU7.js → chunk-TXRYSMOD.js} +2 -6
- package/dist/{chunk-IY347EQA.js → chunk-UDEPO3UF.js} +1 -1
- package/dist/{chunk-BG5RNXTH.js → chunk-UJUWAQE5.js} +1 -1
- package/dist/{chunk-PDXFQS7M.js → chunk-VWDXRNOK.js} +4 -6
- package/dist/{chunk-QR7MITE6.js → chunk-WBUUCU7R.js} +52 -20
- package/dist/{chunk-54R5TEXH.js → chunk-WJNR3RAG.js} +40 -20
- package/dist/{chunk-USNR424B.js → chunk-XT2AI6WJ.js} +4 -11
- package/dist/{chunk-JWGLJXQU.js → chunk-XVD5SLDL.js} +1 -1
- package/dist/chunk-YD7V2HGZ.js +13 -0
- package/dist/{chunk-VSM44AYE.js → chunk-YGD4CCQC.js} +36 -15
- package/dist/components/admin/index.d.ts +7 -15
- package/dist/components/admin/index.js +28 -26
- package/dist/components/data-display/badge.js +3 -3
- package/dist/components/data-display/card.d.ts +2 -2
- package/dist/components/data-display/carousel.js +3 -3
- package/dist/components/data-display/index.js +8 -7
- package/dist/components/data-entry/calendar.d.ts +1 -1
- package/dist/components/data-entry/calendar.js +1 -1
- package/dist/components/data-entry/cascader.d.ts +1 -1
- package/dist/components/data-entry/cascader.js +3 -6
- package/dist/components/data-entry/checkbox.d.ts +2 -2
- package/dist/components/data-entry/color-picker.d.ts +1 -1
- package/dist/components/data-entry/color-picker.js +3 -3
- package/dist/components/data-entry/command.d.ts +10 -10
- package/dist/components/data-entry/date-picker.d.ts +1 -1
- package/dist/components/data-entry/date-picker.js +4 -4
- package/dist/components/data-entry/date-range-picker.d.ts +1 -1
- package/dist/components/data-entry/date-range-picker.js +4 -4
- package/dist/components/data-entry/index.d.ts +3 -3
- package/dist/components/data-entry/index.js +18 -17
- package/dist/components/data-entry/radio.d.ts +1 -1
- package/dist/components/data-entry/select.d.ts +1 -1
- package/dist/components/data-entry/select.js +4 -4
- package/dist/components/data-entry/slider.d.ts +1 -1
- package/dist/components/data-entry/switch.d.ts +1 -1
- package/dist/components/data-entry/time-input.js +2 -2
- package/dist/components/data-entry/time-picker.d.ts +1 -1
- package/dist/components/data-entry/time-picker.js +3 -3
- package/dist/components/data-entry/transfer.d.ts +2 -2
- package/dist/components/data-entry/transfer.js +5 -4
- package/dist/components/data-entry/tree-select.d.ts +1 -1
- package/dist/components/data-entry/tree-select.js +3 -3
- package/dist/components/data-entry/upload.d.ts +2 -2
- package/dist/components/data-entry/upload.js +5 -5
- package/dist/components/data-grid/index.d.ts +71 -0
- package/dist/components/data-grid/index.js +372 -0
- package/dist/components/feedback/alert.js +4 -4
- package/dist/components/feedback/dialog.js +3 -3
- package/dist/components/feedback/index.d.ts +3 -3
- package/dist/components/feedback/index.js +6 -6
- package/dist/components/layout/index.d.ts +3 -3
- package/dist/components/layout/index.js +5 -5
- package/dist/components/navigation/index.d.ts +2 -2
- package/dist/components/navigation/index.js +9 -9
- package/dist/components/navigation/pagination.d.ts +1 -1
- package/dist/components/navigation/pagination.js +5 -5
- package/dist/components/navigation/steps.d.ts +2 -2
- package/dist/components/navigation/steps.js +3 -3
- package/dist/components/query/index.d.ts +1 -2
- package/dist/components/query/index.js +4 -4
- package/dist/components/ui/index.d.ts +3 -3
- package/dist/components/ui/index.js +25 -25
- package/dist/{data-entry.prop-BR4vNA1j.d.ts → data-entry.prop-6J0o45se.d.ts} +3 -25
- package/dist/{filter-bar-BxjSJJnQ.d.ts → filter-bar-B07JSxME.d.ts} +1 -1
- package/dist/{flex-D_EXRFSW.d.ts → flex-DXtIALBh.d.ts} +1 -1
- package/dist/i18n/index.d.ts +10 -0
- package/dist/i18n/index.js +2 -2
- package/dist/index.d.ts +7 -7
- package/dist/index.js +37 -35
- package/dist/{layout.prop-JE2TcRyL.d.ts → layout.prop-B1yQPUNZ.d.ts} +2 -17
- package/dist/lib/datetime/index.js +1 -1
- package/dist/{navigation.prop-DMcXkR-J.d.ts → navigation.prop-Dumy196X.d.ts} +1 -5
- package/dist/props/components/index.d.ts +4 -4
- package/dist/props/index.d.ts +4 -4
- package/dist/props/index.js +2 -2
- package/dist/props/registry.d.ts +0 -47
- package/dist/props/registry.js +1 -1
- package/dist/{query.prop-BDdz9L1G.d.ts → query.prop-Dog-EAfG.d.ts} +2 -6
- package/dist/{search-input-C_x-JFD3.d.ts → search-input-BR4nAWiT.d.ts} +1 -1
- package/dist/styles/control.css +3 -8
- package/dist/styles/layout.css +7 -3
- package/dist/styles/navigation-layout.css +3 -3
- package/dist/styles/shell-layout.css +4 -4
- package/package.json +15 -3
- package/dist/chunk-5NCFLCM7.js +0 -255
- /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
|
|
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
|
|
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
|
|
85
|
-
>
|
|
86
|
-
|
|
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 `
|
|
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
|
|
130
|
-
|
|
|
131
|
-
| `<
|
|
132
|
-
| `<
|
|
133
|
-
| `<
|
|
134
|
-
| Card shell / footer
|
|
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
|
|
package/dist/app/index.d.ts
CHANGED
|
@@ -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,
|
|
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-
|
|
2
|
-
export { APP_LOCALES, APP_REQUEST_HEADER_LOCALE, APP_REQUEST_HEADER_TIMEZONE,
|
|
3
|
-
import { formatDate } from '../chunk-
|
|
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-
|
|
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 {
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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 };
|