@dimaan/ui 0.0.27 → 0.0.28
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/dist/index.cjs +102 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.js +103 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -213,6 +213,23 @@ interface SidebarNavGroupProps extends Omit<ButtonHTMLAttributes<HTMLButtonEleme
|
|
|
213
213
|
onOpenChange?: (open: boolean) => void;
|
|
214
214
|
children: ReactNode;
|
|
215
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* Collapsible group of nav links inside a `<SidebarNav>`.
|
|
218
|
+
*
|
|
219
|
+
* Route-aware out of the box: when one of its `<SidebarNavItem>` children
|
|
220
|
+
* matches the current route, the group auto-opens and highlights itself — no
|
|
221
|
+
* need to wire `active`/`open` by hand. It opens on navigation into a child but
|
|
222
|
+
* stays user-closable; pass `open`/`onOpenChange` for full control, or
|
|
223
|
+
* `defaultOpen` / `active` to override the initial/derived state.
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* ```tsx
|
|
227
|
+
* <SidebarNavGroup label="Platform" icon={<Settings />}>
|
|
228
|
+
* <SidebarNavItem to="/platform/branches">Branches</SidebarNavItem>
|
|
229
|
+
* <SidebarNavItem to="/platform/warehouses">Warehouses</SidebarNavItem>
|
|
230
|
+
* </SidebarNavGroup>
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
216
233
|
declare function SidebarNavGroup({ icon, label, endSlot, active, defaultOpen, open: openProp, onOpenChange, className, children, onClick, ...props }: SidebarNavGroupProps): react_jsx_runtime.JSX.Element;
|
|
217
234
|
|
|
218
235
|
type SidebarNavItemRenderProps = {
|
|
@@ -1538,6 +1555,17 @@ interface SelectProps {
|
|
|
1538
1555
|
options?: SelectOptions;
|
|
1539
1556
|
/** Placeholder shown when no value is selected. */
|
|
1540
1557
|
placeholder?: string;
|
|
1558
|
+
/**
|
|
1559
|
+
* Show a loading indicator — in the trigger (when a `value` is set but its
|
|
1560
|
+
* option hasn't arrived yet) and as a row inside the popup. Use it while the
|
|
1561
|
+
* `options` are still being fetched so the control reads as "loading" instead
|
|
1562
|
+
* of blank. Flip back to `false` once the data lands.
|
|
1563
|
+
*/
|
|
1564
|
+
loading?: boolean;
|
|
1565
|
+
/** Message shown while `loading`. Defaults to `'Loading…'`. */
|
|
1566
|
+
loadingText?: ReactNode;
|
|
1567
|
+
/** Message shown when `options` is empty (and not loading). Defaults to `'No options'`. */
|
|
1568
|
+
emptyText?: ReactNode;
|
|
1541
1569
|
/** Controlled value. */
|
|
1542
1570
|
value?: string;
|
|
1543
1571
|
/** Initial value for uncontrolled usage. */
|
|
@@ -1598,6 +1626,19 @@ interface SelectProps {
|
|
|
1598
1626
|
* { label: 'Levant', options: [{ value: 'jo', label: 'Jordan' }] },
|
|
1599
1627
|
* ]} />
|
|
1600
1628
|
* ```
|
|
1629
|
+
*
|
|
1630
|
+
* @example Async options (edit page) — show loading, then the fetched value
|
|
1631
|
+
* ```tsx
|
|
1632
|
+
* <Select
|
|
1633
|
+
* options={categories} // [] until the request resolves
|
|
1634
|
+
* loading={isLoading} // spinner in the trigger + popup meanwhile
|
|
1635
|
+
* value={String(item.categoryId)} // ⚠️ value must be a string that matches an option's value
|
|
1636
|
+
* onValueChange={(v) => setCategoryId(Number(v))}
|
|
1637
|
+
* placeholder="Category"
|
|
1638
|
+
* loadingText="جارٍ التحميل…"
|
|
1639
|
+
* emptyText="لا توجد عناصر"
|
|
1640
|
+
* />
|
|
1641
|
+
* ```
|
|
1601
1642
|
*/
|
|
1602
1643
|
declare const Select: react.ForwardRefExoticComponent<SelectProps & react.RefAttributes<HTMLButtonElement>>;
|
|
1603
1644
|
|
|
@@ -1811,6 +1852,8 @@ interface MultiSelectLabels {
|
|
|
1811
1852
|
search?: string;
|
|
1812
1853
|
/** Empty-state text when the search matches nothing. Default: `"No results"` / `"لا نتائج"`. */
|
|
1813
1854
|
empty?: string;
|
|
1855
|
+
/** Loading text shown while `loading`. Default: `"Loading…"` / `"جارٍ التحميل…"`. */
|
|
1856
|
+
loading?: string;
|
|
1814
1857
|
}
|
|
1815
1858
|
interface MultiSelectProps {
|
|
1816
1859
|
variant?: SelectVariant;
|
|
@@ -1820,6 +1863,12 @@ interface MultiSelectProps {
|
|
|
1820
1863
|
options: SelectOption[];
|
|
1821
1864
|
/** Placeholder shown when nothing is selected. */
|
|
1822
1865
|
placeholder?: string;
|
|
1866
|
+
/**
|
|
1867
|
+
* Show a loading indicator — in the trigger and as a row inside the popup —
|
|
1868
|
+
* while the `options` are still being fetched. Flip back to `false` once the
|
|
1869
|
+
* data lands. The empty state (`labels.empty`) covers a resolved empty list.
|
|
1870
|
+
*/
|
|
1871
|
+
loading?: boolean;
|
|
1823
1872
|
/** Controlled value (array of selected option values). */
|
|
1824
1873
|
value?: string[];
|
|
1825
1874
|
/** Initial value for uncontrolled usage. */
|
|
@@ -1876,6 +1925,17 @@ interface MultiSelectProps {
|
|
|
1876
1925
|
* aria-label="Roles filter"
|
|
1877
1926
|
* />
|
|
1878
1927
|
* ```
|
|
1928
|
+
*
|
|
1929
|
+
* @example Async options — show loading while fetching
|
|
1930
|
+
* ```tsx
|
|
1931
|
+
* <MultiSelect
|
|
1932
|
+
* options={roleOptions} // [] until the request resolves
|
|
1933
|
+
* loading={isLoading} // spinner in the trigger + popup meanwhile
|
|
1934
|
+
* value={roleIds.map(String)} // ⚠️ values must be strings matching option values
|
|
1935
|
+
* onValueChange={setRoleIds}
|
|
1936
|
+
* placeholder="Roles"
|
|
1937
|
+
* />
|
|
1938
|
+
* ```
|
|
1879
1939
|
*/
|
|
1880
1940
|
declare const MultiSelect: react.ForwardRefExoticComponent<MultiSelectProps & react.RefAttributes<HTMLDivElement>>;
|
|
1881
1941
|
|
package/dist/index.d.ts
CHANGED
|
@@ -213,6 +213,23 @@ interface SidebarNavGroupProps extends Omit<ButtonHTMLAttributes<HTMLButtonEleme
|
|
|
213
213
|
onOpenChange?: (open: boolean) => void;
|
|
214
214
|
children: ReactNode;
|
|
215
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* Collapsible group of nav links inside a `<SidebarNav>`.
|
|
218
|
+
*
|
|
219
|
+
* Route-aware out of the box: when one of its `<SidebarNavItem>` children
|
|
220
|
+
* matches the current route, the group auto-opens and highlights itself — no
|
|
221
|
+
* need to wire `active`/`open` by hand. It opens on navigation into a child but
|
|
222
|
+
* stays user-closable; pass `open`/`onOpenChange` for full control, or
|
|
223
|
+
* `defaultOpen` / `active` to override the initial/derived state.
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* ```tsx
|
|
227
|
+
* <SidebarNavGroup label="Platform" icon={<Settings />}>
|
|
228
|
+
* <SidebarNavItem to="/platform/branches">Branches</SidebarNavItem>
|
|
229
|
+
* <SidebarNavItem to="/platform/warehouses">Warehouses</SidebarNavItem>
|
|
230
|
+
* </SidebarNavGroup>
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
216
233
|
declare function SidebarNavGroup({ icon, label, endSlot, active, defaultOpen, open: openProp, onOpenChange, className, children, onClick, ...props }: SidebarNavGroupProps): react_jsx_runtime.JSX.Element;
|
|
217
234
|
|
|
218
235
|
type SidebarNavItemRenderProps = {
|
|
@@ -1538,6 +1555,17 @@ interface SelectProps {
|
|
|
1538
1555
|
options?: SelectOptions;
|
|
1539
1556
|
/** Placeholder shown when no value is selected. */
|
|
1540
1557
|
placeholder?: string;
|
|
1558
|
+
/**
|
|
1559
|
+
* Show a loading indicator — in the trigger (when a `value` is set but its
|
|
1560
|
+
* option hasn't arrived yet) and as a row inside the popup. Use it while the
|
|
1561
|
+
* `options` are still being fetched so the control reads as "loading" instead
|
|
1562
|
+
* of blank. Flip back to `false` once the data lands.
|
|
1563
|
+
*/
|
|
1564
|
+
loading?: boolean;
|
|
1565
|
+
/** Message shown while `loading`. Defaults to `'Loading…'`. */
|
|
1566
|
+
loadingText?: ReactNode;
|
|
1567
|
+
/** Message shown when `options` is empty (and not loading). Defaults to `'No options'`. */
|
|
1568
|
+
emptyText?: ReactNode;
|
|
1541
1569
|
/** Controlled value. */
|
|
1542
1570
|
value?: string;
|
|
1543
1571
|
/** Initial value for uncontrolled usage. */
|
|
@@ -1598,6 +1626,19 @@ interface SelectProps {
|
|
|
1598
1626
|
* { label: 'Levant', options: [{ value: 'jo', label: 'Jordan' }] },
|
|
1599
1627
|
* ]} />
|
|
1600
1628
|
* ```
|
|
1629
|
+
*
|
|
1630
|
+
* @example Async options (edit page) — show loading, then the fetched value
|
|
1631
|
+
* ```tsx
|
|
1632
|
+
* <Select
|
|
1633
|
+
* options={categories} // [] until the request resolves
|
|
1634
|
+
* loading={isLoading} // spinner in the trigger + popup meanwhile
|
|
1635
|
+
* value={String(item.categoryId)} // ⚠️ value must be a string that matches an option's value
|
|
1636
|
+
* onValueChange={(v) => setCategoryId(Number(v))}
|
|
1637
|
+
* placeholder="Category"
|
|
1638
|
+
* loadingText="جارٍ التحميل…"
|
|
1639
|
+
* emptyText="لا توجد عناصر"
|
|
1640
|
+
* />
|
|
1641
|
+
* ```
|
|
1601
1642
|
*/
|
|
1602
1643
|
declare const Select: react.ForwardRefExoticComponent<SelectProps & react.RefAttributes<HTMLButtonElement>>;
|
|
1603
1644
|
|
|
@@ -1811,6 +1852,8 @@ interface MultiSelectLabels {
|
|
|
1811
1852
|
search?: string;
|
|
1812
1853
|
/** Empty-state text when the search matches nothing. Default: `"No results"` / `"لا نتائج"`. */
|
|
1813
1854
|
empty?: string;
|
|
1855
|
+
/** Loading text shown while `loading`. Default: `"Loading…"` / `"جارٍ التحميل…"`. */
|
|
1856
|
+
loading?: string;
|
|
1814
1857
|
}
|
|
1815
1858
|
interface MultiSelectProps {
|
|
1816
1859
|
variant?: SelectVariant;
|
|
@@ -1820,6 +1863,12 @@ interface MultiSelectProps {
|
|
|
1820
1863
|
options: SelectOption[];
|
|
1821
1864
|
/** Placeholder shown when nothing is selected. */
|
|
1822
1865
|
placeholder?: string;
|
|
1866
|
+
/**
|
|
1867
|
+
* Show a loading indicator — in the trigger and as a row inside the popup —
|
|
1868
|
+
* while the `options` are still being fetched. Flip back to `false` once the
|
|
1869
|
+
* data lands. The empty state (`labels.empty`) covers a resolved empty list.
|
|
1870
|
+
*/
|
|
1871
|
+
loading?: boolean;
|
|
1823
1872
|
/** Controlled value (array of selected option values). */
|
|
1824
1873
|
value?: string[];
|
|
1825
1874
|
/** Initial value for uncontrolled usage. */
|
|
@@ -1876,6 +1925,17 @@ interface MultiSelectProps {
|
|
|
1876
1925
|
* aria-label="Roles filter"
|
|
1877
1926
|
* />
|
|
1878
1927
|
* ```
|
|
1928
|
+
*
|
|
1929
|
+
* @example Async options — show loading while fetching
|
|
1930
|
+
* ```tsx
|
|
1931
|
+
* <MultiSelect
|
|
1932
|
+
* options={roleOptions} // [] until the request resolves
|
|
1933
|
+
* loading={isLoading} // spinner in the trigger + popup meanwhile
|
|
1934
|
+
* value={roleIds.map(String)} // ⚠️ values must be strings matching option values
|
|
1935
|
+
* onValueChange={setRoleIds}
|
|
1936
|
+
* placeholder="Roles"
|
|
1937
|
+
* />
|
|
1938
|
+
* ```
|
|
1879
1939
|
*/
|
|
1880
1940
|
declare const MultiSelect: react.ForwardRefExoticComponent<MultiSelectProps & react.RefAttributes<HTMLDivElement>>;
|
|
1881
1941
|
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { twMerge } from 'tailwind-merge';
|
|
|
5
5
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
6
|
import { Loader2, Check, Minus, Calendar, X, ChevronLeft, ChevronRight, Upload, File as File$1, ChevronDown, Search, ChevronUp, ArrowLeft, Menu, FileQuestion, ChevronsUpDown, Inbox, RefreshCw, SearchX, Trash2, Pencil, Eye } from 'lucide-react';
|
|
7
7
|
import { DirectionProvider } from '@radix-ui/react-direction';
|
|
8
|
-
import { Link,
|
|
8
|
+
import { Link, useResolvedPath, useMatch, useNavigate } from 'react-router-dom';
|
|
9
9
|
import * as RadixPopover from '@radix-ui/react-popover';
|
|
10
10
|
import { DayPicker } from 'react-day-picker';
|
|
11
11
|
import * as RadixDialog from '@radix-ui/react-dialog';
|
|
@@ -574,6 +574,7 @@ function SidebarHeader({ className, children, ...props }) {
|
|
|
574
574
|
function SidebarNav({ className, children, ...props }) {
|
|
575
575
|
return /* @__PURE__ */ jsx("nav", { className: cn("flex flex-1 flex-col gap-1 overflow-y-auto p-2", className), ...props, children });
|
|
576
576
|
}
|
|
577
|
+
var SidebarNavGroupContext = createContext(null);
|
|
577
578
|
function SidebarNavGroup({
|
|
578
579
|
icon,
|
|
579
580
|
label,
|
|
@@ -599,19 +600,39 @@ function SidebarNavGroup({
|
|
|
599
600
|
},
|
|
600
601
|
[isControlled, onOpenChange]
|
|
601
602
|
);
|
|
603
|
+
const [activeChildIds, setActiveChildIds] = useState(() => /* @__PURE__ */ new Set());
|
|
604
|
+
const reportActive = useCallback((id, isItemActive) => {
|
|
605
|
+
setActiveChildIds((prev) => {
|
|
606
|
+
if (isItemActive === prev.has(id)) return prev;
|
|
607
|
+
const next = new Set(prev);
|
|
608
|
+
if (isItemActive) next.add(id);
|
|
609
|
+
else next.delete(id);
|
|
610
|
+
return next;
|
|
611
|
+
});
|
|
612
|
+
}, []);
|
|
613
|
+
const contextValue = useMemo(() => ({ reportActive }), [reportActive]);
|
|
614
|
+
const hasActiveChild = activeChildIds.size > 0;
|
|
615
|
+
const isActive = active || hasActiveChild;
|
|
616
|
+
const prevHasActiveChild = useRef(false);
|
|
617
|
+
useEffect(() => {
|
|
618
|
+
if (hasActiveChild && !prevHasActiveChild.current && !collapsed) {
|
|
619
|
+
setOpen(true);
|
|
620
|
+
}
|
|
621
|
+
prevHasActiveChild.current = hasActiveChild;
|
|
622
|
+
}, [hasActiveChild, collapsed, setOpen]);
|
|
602
623
|
useEffect(() => {
|
|
603
624
|
if (collapsed && open) setOpen(false);
|
|
604
625
|
}, [collapsed, open, setOpen]);
|
|
605
626
|
const titleAttr = collapsed && typeof label === "string" ? label : props.title ?? void 0;
|
|
606
627
|
const showChildren = !collapsed;
|
|
607
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
|
|
628
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 flex-col", children: [
|
|
608
629
|
/* @__PURE__ */ jsxs(
|
|
609
630
|
"button",
|
|
610
631
|
{
|
|
611
632
|
type: "button",
|
|
612
633
|
"aria-expanded": showChildren ? open : void 0,
|
|
613
634
|
"aria-controls": showChildren ? submenuId : void 0,
|
|
614
|
-
"data-active":
|
|
635
|
+
"data-active": isActive ? "true" : void 0,
|
|
615
636
|
title: titleAttr,
|
|
616
637
|
onClick: (e) => {
|
|
617
638
|
if (showChildren) setOpen(!open);
|
|
@@ -621,12 +642,19 @@ function SidebarNavGroup({
|
|
|
621
642
|
"group relative flex h-9 w-full items-center gap-3 rounded-md px-3 text-sm font-medium outline-none transition-colors",
|
|
622
643
|
"text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
|
623
644
|
"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-sidebar",
|
|
624
|
-
|
|
645
|
+
isActive && "bg-sidebar-accent text-sidebar-accent-foreground",
|
|
625
646
|
collapsed && "justify-center px-0",
|
|
626
647
|
className
|
|
627
648
|
),
|
|
628
649
|
...props,
|
|
629
650
|
children: [
|
|
651
|
+
isActive ? /* @__PURE__ */ jsx(
|
|
652
|
+
"span",
|
|
653
|
+
{
|
|
654
|
+
"aria-hidden": "true",
|
|
655
|
+
className: "absolute inset-y-1.5 start-0 w-1 rounded-full bg-primary"
|
|
656
|
+
}
|
|
657
|
+
) : null,
|
|
630
658
|
icon ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "flex h-5 w-5 shrink-0 items-center justify-center", children: icon }) : null,
|
|
631
659
|
/* @__PURE__ */ jsx(
|
|
632
660
|
"span",
|
|
@@ -652,7 +680,7 @@ function SidebarNavGroup({
|
|
|
652
680
|
"grid transition-[grid-template-rows] duration-200 ease-out",
|
|
653
681
|
showChildren && open ? "grid-rows-[1fr]" : "grid-rows-[0fr]"
|
|
654
682
|
),
|
|
655
|
-
children: /* @__PURE__ */ jsx("div", { className: "overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-0.5 ps-7 pt-1", children }) })
|
|
683
|
+
children: /* @__PURE__ */ jsx("div", { className: "overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-0.5 ps-7 pt-1", children: /* @__PURE__ */ jsx(SidebarNavGroupContext.Provider, { value: contextValue, children }) }) })
|
|
656
684
|
}
|
|
657
685
|
)
|
|
658
686
|
] });
|
|
@@ -682,13 +710,20 @@ function SidebarNavItem({
|
|
|
682
710
|
...props
|
|
683
711
|
}) {
|
|
684
712
|
const { collapsed } = useDashboardLayout();
|
|
685
|
-
const location = useLocation();
|
|
686
713
|
const resolved = useResolvedPath(to);
|
|
687
|
-
const
|
|
714
|
+
const group = useContext(SidebarNavGroupContext);
|
|
715
|
+
const itemId = useId();
|
|
716
|
+
const routeMatch = useMatch({ path: resolved.pathname, end: end ?? false });
|
|
717
|
+
const isActive = forcedActive || routeMatch != null;
|
|
718
|
+
useEffect(() => {
|
|
719
|
+
if (!group) return;
|
|
720
|
+
group.reportActive(itemId, isActive);
|
|
721
|
+
return () => group.reportActive(itemId, false);
|
|
722
|
+
}, [group, itemId, isActive]);
|
|
688
723
|
const labelContent = label ?? children;
|
|
689
724
|
const titleAttr = collapsed && typeof labelContent === "string" ? labelContent : props.title;
|
|
690
725
|
const getClassName = (active) => cn(
|
|
691
|
-
"group relative flex h-9 items-center gap-3 rounded-md px-3 text-sm font-medium outline-none transition-colors",
|
|
726
|
+
"group relative flex h-9 shrink-0 items-center gap-3 rounded-md px-3 text-sm font-medium outline-none transition-colors",
|
|
692
727
|
"text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
|
693
728
|
"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-sidebar",
|
|
694
729
|
active && "bg-sidebar-accent text-sidebar-accent-foreground",
|
|
@@ -696,6 +731,13 @@ function SidebarNavItem({
|
|
|
696
731
|
className
|
|
697
732
|
);
|
|
698
733
|
const innerContent = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
734
|
+
isActive ? /* @__PURE__ */ jsx(
|
|
735
|
+
"span",
|
|
736
|
+
{
|
|
737
|
+
"aria-hidden": "true",
|
|
738
|
+
className: "absolute inset-y-1.5 start-0 w-1 rounded-full bg-primary"
|
|
739
|
+
}
|
|
740
|
+
) : null,
|
|
699
741
|
icon ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "flex h-5 w-5 shrink-0 items-center justify-center", children: icon }) : null,
|
|
700
742
|
/* @__PURE__ */ jsx(
|
|
701
743
|
"span",
|
|
@@ -2593,6 +2635,7 @@ var selectItemClass = "relative flex w-full cursor-pointer select-none items-cen
|
|
|
2593
2635
|
var selectItemIndicatorClass = "absolute start-2 inline-flex h-3.5 w-3.5 items-center justify-center [&_svg]:h-3.5 [&_svg]:w-3.5";
|
|
2594
2636
|
var selectGroupLabelClass = "px-2 py-1.5 text-xs font-semibold text-muted-foreground";
|
|
2595
2637
|
var selectSeparatorClass = "-mx-1 my-1 h-px bg-border";
|
|
2638
|
+
var selectStatusClass = "flex items-center justify-center gap-2 px-2 py-6 text-center text-sm text-muted-foreground";
|
|
2596
2639
|
|
|
2597
2640
|
// src/components/multi-select/multiSelectVariants.ts
|
|
2598
2641
|
var multiSelectTriggerSizeClass = {
|
|
@@ -2610,11 +2653,13 @@ var multiSelectOptionClass = "flex w-full cursor-pointer select-none items-cente
|
|
|
2610
2653
|
var multiSelectEmptyClass = "px-2 py-6 text-center text-sm text-muted-foreground";
|
|
2611
2654
|
var DEFAULT_LABELS_LTR4 = {
|
|
2612
2655
|
search: "Search\u2026",
|
|
2613
|
-
empty: "No results"
|
|
2656
|
+
empty: "No results",
|
|
2657
|
+
loading: "Loading\u2026"
|
|
2614
2658
|
};
|
|
2615
2659
|
var DEFAULT_LABELS_RTL4 = {
|
|
2616
2660
|
search: "\u0628\u062D\u062B\u2026",
|
|
2617
|
-
empty: "\u0644\u0627 \u0646\u062A\u0627\u0626\u062C"
|
|
2661
|
+
empty: "\u0644\u0627 \u0646\u062A\u0627\u0626\u062C",
|
|
2662
|
+
loading: "\u062C\u0627\u0631\u064D \u0627\u0644\u062A\u062D\u0645\u064A\u0644\u2026"
|
|
2618
2663
|
};
|
|
2619
2664
|
function toArray(value) {
|
|
2620
2665
|
return Array.isArray(value) ? value : [];
|
|
@@ -2624,6 +2669,7 @@ var MultiSelect = forwardRef(function MultiSelect2({
|
|
|
2624
2669
|
selectSize = "md",
|
|
2625
2670
|
options,
|
|
2626
2671
|
placeholder,
|
|
2672
|
+
loading = false,
|
|
2627
2673
|
value,
|
|
2628
2674
|
defaultValue,
|
|
2629
2675
|
onValueChange,
|
|
@@ -2704,7 +2750,10 @@ var MultiSelect = forwardRef(function MultiSelect2({
|
|
|
2704
2750
|
className
|
|
2705
2751
|
),
|
|
2706
2752
|
children: [
|
|
2707
|
-
/* @__PURE__ */ jsx("span", { className: multiSelectValueRowClass, children:
|
|
2753
|
+
/* @__PURE__ */ jsx("span", { className: multiSelectValueRowClass, children: loading ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 text-muted-foreground", children: [
|
|
2754
|
+
/* @__PURE__ */ jsx(Loader2, { "aria-hidden": "true", className: "size-4 shrink-0 animate-spin" }),
|
|
2755
|
+
labels.loading
|
|
2756
|
+
] }) : selected.length === 0 ? /* @__PURE__ */ jsx("span", { className: "truncate text-muted-foreground", children: placeholder }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2708
2757
|
shownValues.map((v) => /* @__PURE__ */ jsxs(Badge, { variant: "default", size: "sm", className: multiSelectChipClass, children: [
|
|
2709
2758
|
/* @__PURE__ */ jsx("span", { className: "truncate", children: labelByValue.get(v) ?? v }),
|
|
2710
2759
|
/* @__PURE__ */ jsx(
|
|
@@ -2739,7 +2788,7 @@ var MultiSelect = forwardRef(function MultiSelect2({
|
|
|
2739
2788
|
]
|
|
2740
2789
|
}
|
|
2741
2790
|
) }),
|
|
2742
|
-
/* @__PURE__ */ jsx(RadixPopover.Portal, { children: /* @__PURE__ */
|
|
2791
|
+
/* @__PURE__ */ jsx(RadixPopover.Portal, { children: /* @__PURE__ */ jsx(
|
|
2743
2792
|
RadixPopover.Content,
|
|
2744
2793
|
{
|
|
2745
2794
|
align: "start",
|
|
@@ -2749,7 +2798,10 @@ var MultiSelect = forwardRef(function MultiSelect2({
|
|
|
2749
2798
|
onOpenAutoFocus: (event) => {
|
|
2750
2799
|
if (!searchable) event.preventDefault();
|
|
2751
2800
|
},
|
|
2752
|
-
children: [
|
|
2801
|
+
children: loading ? /* @__PURE__ */ jsx("div", { className: multiSelectEmptyClass, children: /* @__PURE__ */ jsxs("span", { className: "flex items-center justify-center gap-2", children: [
|
|
2802
|
+
/* @__PURE__ */ jsx(Loader2, { "aria-hidden": "true", className: "size-4 shrink-0 animate-spin" }),
|
|
2803
|
+
labels.loading
|
|
2804
|
+
] }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2753
2805
|
searchable ? /* @__PURE__ */ jsx("div", { className: multiSelectSearchRowClass, children: /* @__PURE__ */ jsx(
|
|
2754
2806
|
Input,
|
|
2755
2807
|
{
|
|
@@ -2789,7 +2841,7 @@ var MultiSelect = forwardRef(function MultiSelect2({
|
|
|
2789
2841
|
option.value
|
|
2790
2842
|
);
|
|
2791
2843
|
}) })
|
|
2792
|
-
]
|
|
2844
|
+
] })
|
|
2793
2845
|
}
|
|
2794
2846
|
) })
|
|
2795
2847
|
] });
|
|
@@ -2803,6 +2855,9 @@ var Select = forwardRef(function Select2({
|
|
|
2803
2855
|
selectSize = "md",
|
|
2804
2856
|
options,
|
|
2805
2857
|
placeholder,
|
|
2858
|
+
loading = false,
|
|
2859
|
+
loadingText = "Loading\u2026",
|
|
2860
|
+
emptyText = "No options",
|
|
2806
2861
|
value,
|
|
2807
2862
|
defaultValue,
|
|
2808
2863
|
onValueChange,
|
|
@@ -2861,7 +2916,7 @@ var Select = forwardRef(function Select2({
|
|
|
2861
2916
|
className
|
|
2862
2917
|
),
|
|
2863
2918
|
children: [
|
|
2864
|
-
/* @__PURE__ */ jsx(RadixSelect.Value, { placeholder }),
|
|
2919
|
+
/* @__PURE__ */ jsx(RadixSelect.Value, { placeholder, children: loading ? /* @__PURE__ */ jsx("span", { className: "flex items-center gap-2 text-muted-foreground", children: /* @__PURE__ */ jsx(SelectLoading, { text: loadingText }) }) : void 0 }),
|
|
2865
2920
|
/* @__PURE__ */ jsx(RadixSelect.Icon, { asChild: true, children: /* @__PURE__ */ jsx(ChevronDown, { className: "pointer-events-none absolute end-3 top-1/2 size-4 shrink-0 -translate-y-1/2 text-muted-foreground" }) })
|
|
2866
2921
|
]
|
|
2867
2922
|
}
|
|
@@ -2875,7 +2930,7 @@ var Select = forwardRef(function Select2({
|
|
|
2875
2930
|
className: selectContentClass,
|
|
2876
2931
|
children: [
|
|
2877
2932
|
/* @__PURE__ */ jsx(RadixSelect.ScrollUpButton, { className: "flex h-6 cursor-default items-center justify-center bg-popover text-muted-foreground", children: /* @__PURE__ */ jsx(ChevronUp, { className: "size-4" }) }),
|
|
2878
|
-
/* @__PURE__ */ jsx(RadixSelect.Viewport, { className: selectViewportClass, children: children ?? (
|
|
2933
|
+
/* @__PURE__ */ jsx(RadixSelect.Viewport, { className: selectViewportClass, children: children ?? renderViewportContent({ loading, options, loadingText, emptyText }) }),
|
|
2879
2934
|
/* @__PURE__ */ jsx(RadixSelect.ScrollDownButton, { className: "flex h-6 cursor-default items-center justify-center bg-popover text-muted-foreground", children: /* @__PURE__ */ jsx(ChevronDown, { className: "size-4" }) })
|
|
2880
2935
|
]
|
|
2881
2936
|
}
|
|
@@ -2884,6 +2939,26 @@ var Select = forwardRef(function Select2({
|
|
|
2884
2939
|
}
|
|
2885
2940
|
);
|
|
2886
2941
|
});
|
|
2942
|
+
function SelectLoading({ text }) {
|
|
2943
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2944
|
+
/* @__PURE__ */ jsx(Loader2, { "aria-hidden": "true", className: "size-4 shrink-0 animate-spin" }),
|
|
2945
|
+
text
|
|
2946
|
+
] });
|
|
2947
|
+
}
|
|
2948
|
+
function renderViewportContent({
|
|
2949
|
+
loading,
|
|
2950
|
+
options,
|
|
2951
|
+
loadingText,
|
|
2952
|
+
emptyText
|
|
2953
|
+
}) {
|
|
2954
|
+
if (loading) {
|
|
2955
|
+
return /* @__PURE__ */ jsx("div", { className: selectStatusClass, role: "presentation", children: /* @__PURE__ */ jsx(SelectLoading, { text: loadingText }) });
|
|
2956
|
+
}
|
|
2957
|
+
if (!options || options.length === 0) {
|
|
2958
|
+
return /* @__PURE__ */ jsx("div", { className: selectStatusClass, role: "presentation", children: emptyText });
|
|
2959
|
+
}
|
|
2960
|
+
return renderOptions(options);
|
|
2961
|
+
}
|
|
2887
2962
|
function renderOptions(options) {
|
|
2888
2963
|
if (isGroupedOptions(options)) {
|
|
2889
2964
|
const lastIndex = options.length - 1;
|
|
@@ -2924,6 +2999,7 @@ function DebouncedFilterInput({
|
|
|
2924
2999
|
value,
|
|
2925
3000
|
onChange,
|
|
2926
3001
|
debounceMs,
|
|
3002
|
+
id,
|
|
2927
3003
|
ariaLabel,
|
|
2928
3004
|
placeholder,
|
|
2929
3005
|
wrapperClassName,
|
|
@@ -2961,6 +3037,7 @@ function DebouncedFilterInput({
|
|
|
2961
3037
|
return /* @__PURE__ */ jsx(
|
|
2962
3038
|
Input,
|
|
2963
3039
|
{
|
|
3040
|
+
id,
|
|
2964
3041
|
type: "search",
|
|
2965
3042
|
"aria-label": ariaLabel,
|
|
2966
3043
|
placeholder,
|
|
@@ -3045,6 +3122,16 @@ function ListPageFilterBar({
|
|
|
3045
3122
|
}
|
|
3046
3123
|
function FilterControl({ filter, value, onChange, disabled, mode }) {
|
|
3047
3124
|
const spanClass = FILTER_SPAN_CLASS[filter.width ?? "default"];
|
|
3125
|
+
const label = filter.label ?? filter.key;
|
|
3126
|
+
return /* @__PURE__ */ jsx(Field, { label, className: spanClass, children: renderFilterControl({ filter, value, onChange, disabled, mode }) });
|
|
3127
|
+
}
|
|
3128
|
+
function renderFilterControl({
|
|
3129
|
+
filter,
|
|
3130
|
+
value,
|
|
3131
|
+
onChange,
|
|
3132
|
+
disabled,
|
|
3133
|
+
mode
|
|
3134
|
+
}) {
|
|
3048
3135
|
const ariaLabel = typeof filter.label === "string" ? filter.label : filter.key;
|
|
3049
3136
|
switch (filter.type) {
|
|
3050
3137
|
case "select":
|
|
@@ -3055,7 +3142,6 @@ function FilterControl({ filter, value, onChange, disabled, mode }) {
|
|
|
3055
3142
|
value: value ?? filterDefaultValue(filter),
|
|
3056
3143
|
onValueChange: (v) => onChange?.(filter.key, v),
|
|
3057
3144
|
options: filter.options,
|
|
3058
|
-
className: spanClass,
|
|
3059
3145
|
disabled
|
|
3060
3146
|
}
|
|
3061
3147
|
);
|
|
@@ -3068,7 +3154,6 @@ function FilterControl({ filter, value, onChange, disabled, mode }) {
|
|
|
3068
3154
|
debounceMs: mode === "live" ? filter.debounceMs ?? DEFAULT_TEXT_DEBOUNCE_MS : 0,
|
|
3069
3155
|
ariaLabel,
|
|
3070
3156
|
placeholder: filter.placeholder,
|
|
3071
|
-
wrapperClassName: spanClass,
|
|
3072
3157
|
disabled
|
|
3073
3158
|
}
|
|
3074
3159
|
);
|
|
@@ -3080,7 +3165,6 @@ function FilterControl({ filter, value, onChange, disabled, mode }) {
|
|
|
3080
3165
|
placeholder: filter.placeholder,
|
|
3081
3166
|
value: value ?? "",
|
|
3082
3167
|
onValueChange: (v) => onChange?.(filter.key, v),
|
|
3083
|
-
className: spanClass,
|
|
3084
3168
|
disabled
|
|
3085
3169
|
}
|
|
3086
3170
|
);
|
|
@@ -3093,7 +3177,6 @@ function FilterControl({ filter, value, onChange, disabled, mode }) {
|
|
|
3093
3177
|
options: filter.options,
|
|
3094
3178
|
value: value ? value.split(",").filter(Boolean) : [],
|
|
3095
3179
|
onValueChange: (values) => onChange?.(filter.key, values.join(",")),
|
|
3096
|
-
className: spanClass,
|
|
3097
3180
|
disabled
|
|
3098
3181
|
}
|
|
3099
3182
|
);
|