@giddaa-housing/ui 1.2.0 → 2.1.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/css/generated/shared.css +1 -1
- package/dist/badge.js +1 -1
- package/dist/card.d.ts +4 -2
- package/dist/card.js +7 -7
- package/dist/combobox.d.ts +48 -1
- package/dist/combobox.js +77 -4
- package/dist/data-table.js +1 -1
- package/dist/date-picker.d.ts +5 -2
- package/dist/date-picker.js +11 -6
- package/dist/dialog-nesting.d.ts +9 -0
- package/dist/dialog-nesting.js +27 -0
- package/dist/dialog.js +9 -5
- package/dist/file-upload.d.ts +43 -0
- package/dist/file-upload.js +154 -0
- package/dist/infinite-scroll.d.ts +40 -0
- package/dist/infinite-scroll.js +125 -0
- package/dist/input-otp.d.ts +23 -0
- package/dist/input-otp.js +56 -0
- package/dist/picker-xSTzeYhc.js +50 -0
- package/dist/popover.d.ts +2 -2
- package/dist/popover.js +2 -1
- package/dist/sheet.d.ts +4 -2
- package/dist/sheet.js +22 -11
- package/dist/styles.css +357 -106
- package/dist/table.js +2 -2
- package/dist/tabs.d.ts +10 -4
- package/dist/tabs.js +16 -12
- package/dist/time-picker.d.ts +4 -1
- package/dist/time-picker.js +8 -5
- package/package.json +14 -1
- package/dist/picker-lzgmsNfG.js +0 -32
package/dist/combobox.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { t as ComponentSize } from "./size-context-D4mYvcg8.js";
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { Combobox as Combobox$1 } from "@base-ui/react";
|
|
4
|
+
import { Virtualizer } from "@tanstack/react-virtual";
|
|
4
5
|
//#region src/combobox.d.ts
|
|
5
6
|
type ComboboxSize = ComponentSize;
|
|
6
7
|
declare function Combobox<Value, Multiple extends boolean | undefined = false>({ multiple, children, size, ...props }: Combobox$1.Root.Props<Value, Multiple> & {
|
|
@@ -26,5 +27,51 @@ declare function ComboboxChip({ className, children, showRemove, ...props }: Com
|
|
|
26
27
|
}): React.JSX.Element;
|
|
27
28
|
declare function ComboboxChipsInput({ className, ...props }: Combobox$1.Input.Props): React.JSX.Element;
|
|
28
29
|
declare function useComboboxAnchor(): React.RefObject<HTMLDivElement | null>;
|
|
30
|
+
type ComboboxVirtualizer = Virtualizer<HTMLDivElement, Element>;
|
|
31
|
+
type ComboboxHighlightDetails = {
|
|
32
|
+
reason: "keyboard" | "pointer" | "none";
|
|
33
|
+
index: number;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Wires up an external virtualizer for a large `Combobox`. Spread the returned
|
|
37
|
+
* `onItemHighlighted` onto `<Combobox virtualized items={...}>` and pass
|
|
38
|
+
* `virtualizerRef` to `<ComboboxVirtualizedList>`. Keeps keyboard navigation in
|
|
39
|
+
* sync by scrolling the highlighted (off-screen) item into view.
|
|
40
|
+
*/
|
|
41
|
+
declare function useComboboxVirtualizer(): {
|
|
42
|
+
virtualizerRef: React.RefObject<ComboboxVirtualizer | null>;
|
|
43
|
+
onItemHighlighted: (item: unknown, { reason, index }: ComboboxHighlightDetails) => void;
|
|
44
|
+
};
|
|
45
|
+
type ComboboxVirtualItemProps = {
|
|
46
|
+
index: number;
|
|
47
|
+
"data-index": number;
|
|
48
|
+
"aria-setsize": number;
|
|
49
|
+
"aria-posinset": number;
|
|
50
|
+
style: React.CSSProperties;
|
|
51
|
+
};
|
|
52
|
+
declare function ComboboxVirtualizedList<Item>({ virtualizerRef, estimateSize, overscan, paddingStart, paddingEnd, maxHeight, className, children }: {
|
|
53
|
+
/** Ref returned by {@link useComboboxVirtualizer}. */
|
|
54
|
+
virtualizerRef: React.RefObject<ComboboxVirtualizer | null>;
|
|
55
|
+
/**
|
|
56
|
+
* Fixed row height in px (or a per-index function). Rows render at this
|
|
57
|
+
* exact height, so match it to the item size variant (roughly sm: 32,
|
|
58
|
+
* md: 40, lg: 44). Defaults to 40.
|
|
59
|
+
*/
|
|
60
|
+
estimateSize?: number | ((index: number) => number);
|
|
61
|
+
overscan?: number;
|
|
62
|
+
paddingStart?: number;
|
|
63
|
+
paddingEnd?: number;
|
|
64
|
+
/**
|
|
65
|
+
* Fixed max height of the scroll viewport (px number or CSS length).
|
|
66
|
+
* Must be a stable value — do NOT wire this to `--available-height` or any
|
|
67
|
+
* value the popup positioner writes, or react-virtual's resize observer and
|
|
68
|
+
* the positioner will feed back into each other and freeze the page on open.
|
|
69
|
+
* Defaults to `"22rem"`.
|
|
70
|
+
*/
|
|
71
|
+
maxHeight?: number | string;
|
|
72
|
+
className?: string;
|
|
73
|
+
/** Render a `ComboboxItem`, spreading the provided props onto it. */
|
|
74
|
+
children: (item: Item, props: ComboboxVirtualItemProps) => React.ReactNode;
|
|
75
|
+
}): React.JSX.Element | null;
|
|
29
76
|
//#endregion
|
|
30
|
-
export { Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxLabel, ComboboxList, ComboboxSeparator, type ComboboxSize, ComboboxTrigger, ComboboxValue, useComboboxAnchor };
|
|
77
|
+
export { Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxLabel, ComboboxList, ComboboxSeparator, type ComboboxSize, ComboboxTrigger, ComboboxValue, type ComboboxVirtualItemProps, ComboboxVirtualizedList, type ComboboxVirtualizer, useComboboxAnchor, useComboboxVirtualizer };
|
package/dist/combobox.js
CHANGED
|
@@ -8,6 +8,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
8
8
|
import { cva } from "class-variance-authority";
|
|
9
9
|
import * as React from "react";
|
|
10
10
|
import { Combobox as Combobox$1 } from "@base-ui/react";
|
|
11
|
+
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
11
12
|
//#region src/combobox.tsx
|
|
12
13
|
const ComboboxSelectionContext = React.createContext({ multiple: false });
|
|
13
14
|
function Combobox({ multiple, children, size, ...props }) {
|
|
@@ -115,7 +116,7 @@ function ComboboxInput({ className, children, disabled = false, showTrigger = tr
|
|
|
115
116
|
variant: "ghost",
|
|
116
117
|
render: /* @__PURE__ */ jsx(ComboboxTrigger, {}),
|
|
117
118
|
"data-slot": "input-group-button",
|
|
118
|
-
className: "
|
|
119
|
+
className: "border-0 bg-transparent p-0 shadow-none inset-ring-0 group-has-data-[slot=combobox-clear]/input-group:hidden hover:border-transparent focus-visible:border-transparent focus-visible:inset-ring-0 data-popup-open:border-transparent data-popup-open:bg-transparent data-popup-open:inset-ring-0 data-pressed:bg-transparent",
|
|
119
120
|
disabled
|
|
120
121
|
}), showClear && /* @__PURE__ */ jsx(ComboboxClear, { disabled })]
|
|
121
122
|
}),
|
|
@@ -135,7 +136,7 @@ function ComboboxContent({ className, side = "bottom", sideOffset = 6, align = "
|
|
|
135
136
|
children: /* @__PURE__ */ jsx(Combobox$1.Popup, {
|
|
136
137
|
"data-slot": "combobox-content",
|
|
137
138
|
"data-chips": !!anchor,
|
|
138
|
-
className: cn("group/combobox-content", comboboxContentVariants({ size: resolvedSize }), className),
|
|
139
|
+
className: cn("group/combobox-content", comboboxContentVariants({ size: resolvedSize }), "has-data-[slot=combobox-virtualized]:max-h-none", className),
|
|
139
140
|
...props
|
|
140
141
|
})
|
|
141
142
|
}) });
|
|
@@ -143,7 +144,7 @@ function ComboboxContent({ className, side = "bottom", sideOffset = 6, align = "
|
|
|
143
144
|
function ComboboxList({ className, ...props }) {
|
|
144
145
|
return /* @__PURE__ */ jsx(Combobox$1.List, {
|
|
145
146
|
"data-slot": "combobox-list",
|
|
146
|
-
className: cn("no-scrollbar max-h-(--available-height) space-y-0.5 scroll-py-1 overflow-y-auto overscroll-contain data-empty:p-0", className),
|
|
147
|
+
className: cn("no-scrollbar max-h-(--available-height) space-y-0.5 scroll-py-1 overflow-y-auto overscroll-contain data-empty:p-0 has-data-[slot=combobox-virtualized]:max-h-none has-data-[slot=combobox-virtualized]:space-y-0 has-data-[slot=combobox-virtualized]:overflow-hidden", className),
|
|
147
148
|
...props
|
|
148
149
|
});
|
|
149
150
|
}
|
|
@@ -233,5 +234,77 @@ function ComboboxChipsInput({ className, ...props }) {
|
|
|
233
234
|
function useComboboxAnchor() {
|
|
234
235
|
return React.useRef(null);
|
|
235
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* Wires up an external virtualizer for a large `Combobox`. Spread the returned
|
|
239
|
+
* `onItemHighlighted` onto `<Combobox virtualized items={...}>` and pass
|
|
240
|
+
* `virtualizerRef` to `<ComboboxVirtualizedList>`. Keeps keyboard navigation in
|
|
241
|
+
* sync by scrolling the highlighted (off-screen) item into view.
|
|
242
|
+
*/
|
|
243
|
+
function useComboboxVirtualizer() {
|
|
244
|
+
const virtualizerRef = React.useRef(null);
|
|
245
|
+
return {
|
|
246
|
+
virtualizerRef,
|
|
247
|
+
onItemHighlighted: React.useCallback((item, { reason, index }) => {
|
|
248
|
+
const virtualizer = virtualizerRef.current;
|
|
249
|
+
if (item == null || !virtualizer || index < 0) return;
|
|
250
|
+
const isStart = index === 0;
|
|
251
|
+
const isEnd = index === virtualizer.options.count - 1;
|
|
252
|
+
if (reason === "none" || reason === "keyboard" && (isStart || isEnd)) queueMicrotask(() => {
|
|
253
|
+
virtualizer.scrollToIndex(index, { align: isEnd ? "start" : "end" });
|
|
254
|
+
});
|
|
255
|
+
}, [])
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
function ComboboxVirtualizedList({ virtualizerRef, estimateSize = 40, overscan = 20, paddingStart = 4, paddingEnd = 4, maxHeight = "22rem", className, children }) {
|
|
259
|
+
const filteredItems = Combobox$1.useFilteredItems();
|
|
260
|
+
const scrollElementRef = React.useRef(null);
|
|
261
|
+
const virtualizer = useVirtualizer({
|
|
262
|
+
count: filteredItems.length,
|
|
263
|
+
getScrollElement: () => scrollElementRef.current,
|
|
264
|
+
estimateSize: typeof estimateSize === "function" ? estimateSize : () => estimateSize,
|
|
265
|
+
overscan,
|
|
266
|
+
paddingStart,
|
|
267
|
+
paddingEnd,
|
|
268
|
+
scrollPaddingStart: paddingStart,
|
|
269
|
+
scrollPaddingEnd: paddingEnd
|
|
270
|
+
});
|
|
271
|
+
React.useImperativeHandle(virtualizerRef, () => virtualizer, [virtualizer]);
|
|
272
|
+
const handleScrollElementRef = React.useCallback((element) => {
|
|
273
|
+
scrollElementRef.current = element;
|
|
274
|
+
if (element) virtualizer.measure();
|
|
275
|
+
}, [virtualizer]);
|
|
276
|
+
const totalSize = virtualizer.getTotalSize();
|
|
277
|
+
if (!filteredItems.length) return null;
|
|
278
|
+
return /* @__PURE__ */ jsx("div", {
|
|
279
|
+
role: "presentation",
|
|
280
|
+
ref: handleScrollElementRef,
|
|
281
|
+
"data-slot": "combobox-virtualized",
|
|
282
|
+
style: { maxHeight },
|
|
283
|
+
className: cn("no-scrollbar overflow-y-auto overscroll-contain", className),
|
|
284
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
285
|
+
role: "presentation",
|
|
286
|
+
className: "relative w-full",
|
|
287
|
+
style: { height: totalSize },
|
|
288
|
+
children: virtualizer.getVirtualItems().map((virtualItem) => {
|
|
289
|
+
const item = filteredItems[virtualItem.index];
|
|
290
|
+
if (item == null) return null;
|
|
291
|
+
return /* @__PURE__ */ jsx(React.Fragment, { children: children(item, {
|
|
292
|
+
index: virtualItem.index,
|
|
293
|
+
"data-index": virtualItem.index,
|
|
294
|
+
"aria-setsize": filteredItems.length,
|
|
295
|
+
"aria-posinset": virtualItem.index + 1,
|
|
296
|
+
style: {
|
|
297
|
+
position: "absolute",
|
|
298
|
+
top: 0,
|
|
299
|
+
left: 0,
|
|
300
|
+
width: "100%",
|
|
301
|
+
height: virtualItem.size,
|
|
302
|
+
transform: `translateY(${virtualItem.start}px)`
|
|
303
|
+
}
|
|
304
|
+
}) }, virtualItem.key);
|
|
305
|
+
})
|
|
306
|
+
})
|
|
307
|
+
});
|
|
308
|
+
}
|
|
236
309
|
//#endregion
|
|
237
|
-
export { Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxLabel, ComboboxList, ComboboxSeparator, ComboboxTrigger, ComboboxValue, useComboboxAnchor };
|
|
310
|
+
export { Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxLabel, ComboboxList, ComboboxSeparator, ComboboxTrigger, ComboboxValue, ComboboxVirtualizedList, useComboboxAnchor, useComboboxVirtualizer };
|
package/dist/data-table.js
CHANGED
|
@@ -243,7 +243,7 @@ function DataTable({ className, containerClassName, emptyState, interactiveColum
|
|
|
243
243
|
pinnedSide,
|
|
244
244
|
style: getCommonPinningStyles(header.column),
|
|
245
245
|
children: header.isPlaceholder ? null : /* @__PURE__ */ jsxs("div", {
|
|
246
|
-
className: "flex items-center gap-2",
|
|
246
|
+
className: "flex min-w-0 items-center gap-2",
|
|
247
247
|
children: [
|
|
248
248
|
flexRender(header.column.columnDef.header, header.getContext()),
|
|
249
249
|
header.column.getCanSort() ? /* @__PURE__ */ jsx("button", {
|
package/dist/date-picker.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { n as InputSize } from "./input-CfoEJ8A6.js";
|
|
1
2
|
import * as React from "react";
|
|
2
3
|
import { DateRange, Matcher } from "react-day-picker";
|
|
3
4
|
//#region src/date-picker.d.ts
|
|
4
5
|
type CaptionLayout = "label" | "dropdown" | "dropdown-months" | "dropdown-years";
|
|
5
6
|
interface DatePickerBaseProps {
|
|
6
7
|
disabled?: boolean;
|
|
8
|
+
/** Controls the trigger size. The calendar panel is not resized. */
|
|
9
|
+
size?: InputSize;
|
|
7
10
|
placeholder?: string;
|
|
8
11
|
className?: string;
|
|
9
12
|
/** Caption style. Defaults to month + year dropdowns for quick navigation. */
|
|
@@ -19,11 +22,11 @@ interface DatePickerProps extends DatePickerBaseProps {
|
|
|
19
22
|
value?: Date;
|
|
20
23
|
onChange?: (date: Date | undefined) => void;
|
|
21
24
|
}
|
|
22
|
-
declare function DatePicker({ value, onChange, disabled, placeholder, className, captionLayout, startMonth, endMonth, disabledDates }: DatePickerProps): React.JSX.Element;
|
|
25
|
+
declare function DatePicker({ value, onChange, disabled, size, placeholder, className, captionLayout, startMonth, endMonth, disabledDates }: DatePickerProps): React.JSX.Element;
|
|
23
26
|
interface DateRangePickerProps extends DatePickerBaseProps {
|
|
24
27
|
value?: DateRange;
|
|
25
28
|
onChange?: (range: DateRange | undefined) => void;
|
|
26
29
|
}
|
|
27
|
-
declare function DateRangePicker({ value, onChange, disabled, placeholder, className, captionLayout, startMonth, endMonth, disabledDates }: DateRangePickerProps): React.JSX.Element;
|
|
30
|
+
declare function DateRangePicker({ value, onChange, disabled, size, placeholder, className, captionLayout, startMonth, endMonth, disabledDates }: DateRangePickerProps): React.JSX.Element;
|
|
28
31
|
//#endregion
|
|
29
32
|
export { DatePicker, type DatePickerProps, type DateRange, DateRangePicker, type DateRangePickerProps };
|
package/dist/date-picker.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { t as cn } from "./cn-BI_4DMBf.js";
|
|
3
3
|
import { Calendar } from "./calendar.js";
|
|
4
4
|
import { Popover, PopoverContent } from "./popover.js";
|
|
5
|
-
import { n as PickerTrigger, t as
|
|
5
|
+
import { n as PickerFooter, r as PickerTrigger, t as PICKER_COLLISION_AVOIDANCE } from "./picker-xSTzeYhc.js";
|
|
6
6
|
import { CalendarIcon } from "lucide-react";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
import * as React from "react";
|
|
@@ -14,14 +14,14 @@ function formatDate(date) {
|
|
|
14
14
|
year: "numeric"
|
|
15
15
|
});
|
|
16
16
|
}
|
|
17
|
-
const PANEL_CLASSES = "flex min-w-(--anchor-width) flex-col items-center gap-0 overflow-hidden rounded-2xl p-0";
|
|
17
|
+
const PANEL_CLASSES = "flex min-w-(--anchor-width) flex-col items-center gap-0 overflow-hidden rounded-2xl p-0 border border-line-subtle";
|
|
18
18
|
function defaultStartMonth() {
|
|
19
19
|
return new Date((/* @__PURE__ */ new Date()).getFullYear() - 100, 0);
|
|
20
20
|
}
|
|
21
21
|
function defaultEndMonth() {
|
|
22
22
|
return new Date((/* @__PURE__ */ new Date()).getFullYear() + 10, 11);
|
|
23
23
|
}
|
|
24
|
-
function DatePicker({ value, onChange, disabled = false, placeholder = "Select date", className, captionLayout = "dropdown", startMonth, endMonth, disabledDates }) {
|
|
24
|
+
function DatePicker({ value, onChange, disabled = false, size, placeholder = "Select date", className, captionLayout = "dropdown", startMonth, endMonth, disabledDates }) {
|
|
25
25
|
const [open, setOpen] = React.useState(false);
|
|
26
26
|
const [pending, setPending] = React.useState(value);
|
|
27
27
|
const [month, setMonth] = React.useState(() => value ?? /* @__PURE__ */ new Date());
|
|
@@ -41,11 +41,13 @@ function DatePicker({ value, onChange, disabled = false, placeholder = "Select d
|
|
|
41
41
|
placeholder,
|
|
42
42
|
disabled,
|
|
43
43
|
open,
|
|
44
|
+
size,
|
|
44
45
|
className
|
|
45
46
|
}), /* @__PURE__ */ jsxs(PopoverContent, {
|
|
46
47
|
showArrow: false,
|
|
47
|
-
align: "
|
|
48
|
+
align: "center",
|
|
48
49
|
side: "bottom",
|
|
50
|
+
collisionAvoidance: PICKER_COLLISION_AVOIDANCE,
|
|
49
51
|
className: PANEL_CLASSES,
|
|
50
52
|
children: [/* @__PURE__ */ jsx(Calendar, {
|
|
51
53
|
mode: "single",
|
|
@@ -72,7 +74,7 @@ function DatePicker({ value, onChange, disabled = false, placeholder = "Select d
|
|
|
72
74
|
})]
|
|
73
75
|
});
|
|
74
76
|
}
|
|
75
|
-
function DateRangePicker({ value, onChange, disabled = false, placeholder = "Select date range", className, captionLayout = "dropdown", startMonth, endMonth, disabledDates }) {
|
|
77
|
+
function DateRangePicker({ value, onChange, disabled = false, size, placeholder = "Select date range", className, captionLayout = "dropdown", startMonth, endMonth, disabledDates }) {
|
|
76
78
|
const [open, setOpen] = React.useState(false);
|
|
77
79
|
const [pending, setPending] = React.useState(value);
|
|
78
80
|
const [month, setMonth] = React.useState(() => value?.from ?? /* @__PURE__ */ new Date());
|
|
@@ -96,10 +98,13 @@ function DateRangePicker({ value, onChange, disabled = false, placeholder = "Sel
|
|
|
96
98
|
placeholder,
|
|
97
99
|
disabled,
|
|
98
100
|
open,
|
|
101
|
+
size,
|
|
99
102
|
className
|
|
100
103
|
}), /* @__PURE__ */ jsxs(PopoverContent, {
|
|
101
104
|
showArrow: false,
|
|
102
|
-
align: "
|
|
105
|
+
align: "center",
|
|
106
|
+
side: "bottom",
|
|
107
|
+
collisionAvoidance: PICKER_COLLISION_AVOIDANCE,
|
|
103
108
|
className: cn(PANEL_CLASSES, "w-auto"),
|
|
104
109
|
children: [/* @__PURE__ */ jsx(Calendar, {
|
|
105
110
|
mode: "range",
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
//#region src/dialog-nesting.d.ts
|
|
3
|
+
declare function DialogNestingProvider({ children }: {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
}): import("react").JSX.Element;
|
|
6
|
+
/** Depth of the current dialog (1 = top-level, 2+ = nested). */
|
|
7
|
+
declare function useDialogNestingDepth(): number;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { DialogNestingProvider, useDialogNestingDepth };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext } from "react";
|
|
4
|
+
//#region src/dialog-nesting.tsx
|
|
5
|
+
/**
|
|
6
|
+
* Tracks how deep a Dialog/Sheet is nested. Sheet and Dialog share the same
|
|
7
|
+
* Base UI primitive, so they share this one context too — a Dialog opened
|
|
8
|
+
* inside a Sheet (or vice-versa) counts as nested.
|
|
9
|
+
*
|
|
10
|
+
* Depth is 0 outside any dialog, 1 for a top-level dialog, 2+ for nested ones.
|
|
11
|
+
* Overlays use `depth > 1` to render lighter (so the parent shows through),
|
|
12
|
+
* while the base overlay keeps the full page-hiding dim.
|
|
13
|
+
*/
|
|
14
|
+
const DialogNestingContext = createContext(0);
|
|
15
|
+
function DialogNestingProvider({ children }) {
|
|
16
|
+
const depth = useContext(DialogNestingContext);
|
|
17
|
+
return /* @__PURE__ */ jsx(DialogNestingContext.Provider, {
|
|
18
|
+
value: depth + 1,
|
|
19
|
+
children
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/** Depth of the current dialog (1 = top-level, 2+ = nested). */
|
|
23
|
+
function useDialogNestingDepth() {
|
|
24
|
+
return useContext(DialogNestingContext);
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { DialogNestingProvider, useDialogNestingDepth };
|
package/dist/dialog.js
CHANGED
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
import { t as cn } from "./cn-BI_4DMBf.js";
|
|
3
3
|
import { SizeProvider, useComponentSize } from "./size-context.js";
|
|
4
4
|
import { Button } from "./button.js";
|
|
5
|
+
import { DialogNestingProvider, useDialogNestingDepth } from "./dialog-nesting.js";
|
|
5
6
|
import { XIcon } from "lucide-react";
|
|
6
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
8
|
import { cva } from "class-variance-authority";
|
|
8
9
|
import { Dialog as Dialog$1 } from "@base-ui/react/dialog";
|
|
9
10
|
//#region src/dialog.tsx
|
|
10
11
|
function Dialog({ ...props }) {
|
|
11
|
-
return /* @__PURE__ */ jsx(Dialog$1.Root, {
|
|
12
|
+
return /* @__PURE__ */ jsx(DialogNestingProvider, { children: /* @__PURE__ */ jsx(Dialog$1.Root, {
|
|
12
13
|
"data-slot": "dialog",
|
|
13
14
|
...props
|
|
14
|
-
});
|
|
15
|
+
}) });
|
|
15
16
|
}
|
|
16
17
|
function DialogTrigger({ ...props }) {
|
|
17
18
|
return /* @__PURE__ */ jsx(Dialog$1.Trigger, {
|
|
@@ -32,13 +33,16 @@ function DialogClose({ ...props }) {
|
|
|
32
33
|
});
|
|
33
34
|
}
|
|
34
35
|
function DialogOverlay({ className, ...props }) {
|
|
36
|
+
const nested = useDialogNestingDepth() > 1;
|
|
35
37
|
return /* @__PURE__ */ jsx(Dialog$1.Backdrop, {
|
|
38
|
+
forceRender: true,
|
|
36
39
|
"data-slot": "dialog-overlay",
|
|
37
|
-
|
|
40
|
+
"data-nested": nested || void 0,
|
|
41
|
+
className: cn("fixed inset-0 z-50 transition-opacity duration-150 data-closed:opacity-0 data-open:opacity-100", nested ? "bg-black/25" : "bg-black/55 supports-backdrop-filter:backdrop-blur-xl", className),
|
|
38
42
|
...props
|
|
39
43
|
});
|
|
40
44
|
}
|
|
41
|
-
const dialogContentVariants = cva("group/dialog-content fixed top-1/2 left-1/2 z-50 flex max-h-[calc(100dvh-5rem)] w-full max-w-[calc(100vw-2rem)] -translate-x-1/2 -translate-y-1/2 flex-col gap-4 overflow-visible rounded-2xl border border-line-subtle bg-surface-overlay bg-clip-padding p-(--dialog-padding) text-fg-primary shadow-(--elevation-e2-shadow) outline-none [--dialog-padding:1.25rem] transition-[opacity,transform] duration-200 ease-in-out data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", {
|
|
45
|
+
const dialogContentVariants = cva("group/dialog-content fixed top-1/2 left-1/2 z-50 flex max-h-[calc(100dvh-5rem)] w-full max-w-[calc(100vw-2rem)] -translate-x-1/2 -translate-y-1/2 flex-col gap-4 overflow-visible rounded-2xl border border-line-subtle bg-surface-overlay bg-clip-padding p-(--dialog-padding) text-fg-primary shadow-(--elevation-e2-shadow) outline-none [--dialog-padding:1.25rem] transition-[opacity,transform] duration-200 ease-in-out data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 origin-center data-[nested-dialog-open]:scale-[0.96]", {
|
|
42
46
|
variants: { size: {
|
|
43
47
|
sm: "sm:w-90 sm:[--dialog-padding:1.5rem]",
|
|
44
48
|
md: "sm:w-105 sm:[--dialog-padding:1.5rem]",
|
|
@@ -78,7 +82,7 @@ function DialogContent({ className, children, size, showCloseButton = true, ...p
|
|
|
78
82
|
"data-slot": "dialog-close",
|
|
79
83
|
render: /* @__PURE__ */ jsxs(Button, {
|
|
80
84
|
variant: "tertiary",
|
|
81
|
-
className: "absolute -top-10 right-0 z-10",
|
|
85
|
+
className: "absolute -top-10 right-0 z-10 group-data-[nested-dialog-open]/dialog-content:hidden",
|
|
82
86
|
size: "icon-sm",
|
|
83
87
|
children: [/* @__PURE__ */ jsx(XIcon, {}), /* @__PURE__ */ jsx("span", {
|
|
84
88
|
className: "sr-only",
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { CircularProgressProps, ProgressProps } from "./progress.js";
|
|
2
|
+
import { ComponentProps, ReactNode } from "react";
|
|
3
|
+
//#region src/file-upload.d.ts
|
|
4
|
+
type FileUploadState = "pending" | "uploading" | "complete" | "error";
|
|
5
|
+
type FileUploadContextValue = {
|
|
6
|
+
state: FileUploadState;
|
|
7
|
+
value: number;
|
|
8
|
+
};
|
|
9
|
+
declare function useFileUpload(): FileUploadContextValue;
|
|
10
|
+
type FileUploadProps = ComponentProps<"div"> & {
|
|
11
|
+
state?: FileUploadState;
|
|
12
|
+
value: number;
|
|
13
|
+
};
|
|
14
|
+
declare function FileUpload({ className, state, value, "aria-busy": ariaBusy, ...props }: FileUploadProps): import("react").JSX.Element;
|
|
15
|
+
declare function FileUploadPreview({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
|
|
16
|
+
declare function FileUploadImage({ className, alt, ...props }: ComponentProps<"img">): import("react").JSX.Element;
|
|
17
|
+
declare function FileUploadOverlay({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
|
|
18
|
+
declare function FileUploadPreviewAction({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
|
|
19
|
+
declare function FileUploadIcon({ className, children, ...props }: ComponentProps<"div">): import("react").JSX.Element;
|
|
20
|
+
declare function FileUploadContent({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
|
|
21
|
+
declare function FileUploadHeader({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
|
|
22
|
+
declare function FileUploadName({ className, ...props }: ComponentProps<"p">): import("react").JSX.Element;
|
|
23
|
+
declare function FileUploadMeta({ className, ...props }: ComponentProps<"p">): import("react").JSX.Element;
|
|
24
|
+
type FileUploadStatusProps = Omit<ComponentProps<"output">, "children"> & {
|
|
25
|
+
children?: ReactNode | ((context: FileUploadContextValue) => ReactNode);
|
|
26
|
+
pendingLabel?: ReactNode;
|
|
27
|
+
uploadingLabel?: ReactNode;
|
|
28
|
+
completeLabel?: ReactNode;
|
|
29
|
+
errorLabel?: ReactNode;
|
|
30
|
+
};
|
|
31
|
+
declare function FileUploadStatus({ className, children, pendingLabel, uploadingLabel, completeLabel, errorLabel, ...props }: FileUploadStatusProps): import("react").JSX.Element;
|
|
32
|
+
type FileUploadProgressProps = Omit<ProgressProps, "value"> & {
|
|
33
|
+
showValue?: boolean;
|
|
34
|
+
};
|
|
35
|
+
declare function FileUploadProgress({ className, children, showValue, "aria-label": ariaLabel, ...props }: FileUploadProgressProps): import("react").JSX.Element;
|
|
36
|
+
type FileUploadCircularProgressProps = Omit<CircularProgressProps, "value">;
|
|
37
|
+
declare function FileUploadCircularProgress({ className, labelOverlay, "aria-label": ariaLabel, ...props }: FileUploadCircularProgressProps): import("react").JSX.Element;
|
|
38
|
+
type FileUploadCancelProps = ComponentProps<"button"> & {
|
|
39
|
+
variant?: "ghost" | "surface";
|
|
40
|
+
};
|
|
41
|
+
declare function FileUploadCancel({ className, type, children, variant, "aria-label": ariaLabel, ...props }: FileUploadCancelProps): import("react").JSX.Element;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { FileUpload, FileUploadCancel, type FileUploadCancelProps, FileUploadCircularProgress, type FileUploadCircularProgressProps, FileUploadContent, type FileUploadContextValue, FileUploadHeader, FileUploadIcon, FileUploadImage, FileUploadMeta, FileUploadName, FileUploadOverlay, FileUploadPreview, FileUploadPreviewAction, FileUploadProgress, type FileUploadProgressProps, type FileUploadProps, type FileUploadState, FileUploadStatus, type FileUploadStatusProps, useFileUpload };
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { t as cn } from "./cn-BI_4DMBf.js";
|
|
3
|
+
import { CircularProgress, Progress, ProgressValue } from "./progress.js";
|
|
4
|
+
import { File, X } from "lucide-react";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
import { createContext, useContext } from "react";
|
|
7
|
+
//#region src/file-upload.tsx
|
|
8
|
+
const FileUploadContext = createContext(null);
|
|
9
|
+
function normalizeProgress(value) {
|
|
10
|
+
if (!Number.isFinite(value)) return 0;
|
|
11
|
+
return Math.min(100, Math.max(0, Math.round(value)));
|
|
12
|
+
}
|
|
13
|
+
function useFileUpload() {
|
|
14
|
+
const context = useContext(FileUploadContext);
|
|
15
|
+
if (!context) throw new Error("FileUpload compound components must be rendered inside <FileUpload>.");
|
|
16
|
+
return context;
|
|
17
|
+
}
|
|
18
|
+
function FileUpload({ className, state = "uploading", value, "aria-busy": ariaBusy, ...props }) {
|
|
19
|
+
const progress = normalizeProgress(value);
|
|
20
|
+
return /* @__PURE__ */ jsx(FileUploadContext.Provider, {
|
|
21
|
+
value: {
|
|
22
|
+
state,
|
|
23
|
+
value: progress
|
|
24
|
+
},
|
|
25
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
26
|
+
"data-slot": "file-upload",
|
|
27
|
+
"data-state": state,
|
|
28
|
+
"data-value": progress,
|
|
29
|
+
"aria-busy": ariaBusy ?? (state === "uploading" || void 0),
|
|
30
|
+
className: cn("group/file-upload relative flex min-w-0 items-start gap-3 rounded-xl border border-line bg-surface p-3", "data-[state=error]:border-line-danger data-[state=error]:bg-surface-danger-subtle", className),
|
|
31
|
+
...props
|
|
32
|
+
})
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function FileUploadPreview({ className, ...props }) {
|
|
36
|
+
return /* @__PURE__ */ jsx("div", {
|
|
37
|
+
"data-slot": "file-upload-preview",
|
|
38
|
+
className: cn("relative flex size-20 shrink-0 items-center justify-center rounded-lg bg-surface-raised", className),
|
|
39
|
+
...props
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function FileUploadImage({ className, alt = "", ...props }) {
|
|
43
|
+
return /* @__PURE__ */ jsx("img", {
|
|
44
|
+
"data-slot": "file-upload-image",
|
|
45
|
+
className: cn("size-full rounded-[inherit] object-cover", className),
|
|
46
|
+
alt,
|
|
47
|
+
...props
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
function FileUploadOverlay({ className, ...props }) {
|
|
51
|
+
return /* @__PURE__ */ jsx("div", {
|
|
52
|
+
"data-slot": "file-upload-overlay",
|
|
53
|
+
className: cn("absolute inset-0 flex items-center justify-center rounded-[inherit] bg-black/45", className),
|
|
54
|
+
...props
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function FileUploadPreviewAction({ className, ...props }) {
|
|
58
|
+
return /* @__PURE__ */ jsx("div", {
|
|
59
|
+
"data-slot": "file-upload-preview-action",
|
|
60
|
+
className: cn("absolute -top-2 -right-2 z-10", className),
|
|
61
|
+
...props
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function FileUploadIcon({ className, children, ...props }) {
|
|
65
|
+
return /* @__PURE__ */ jsx("div", {
|
|
66
|
+
"data-slot": "file-upload-icon",
|
|
67
|
+
className: cn("flex size-11 shrink-0 items-center justify-center rounded-lg bg-surface-brand-subtle text-fg-brand", "group-data-[state=error]/file-upload:bg-surface-danger-subtle group-data-[state=error]/file-upload:text-status-danger", className),
|
|
68
|
+
...props,
|
|
69
|
+
children: children ?? /* @__PURE__ */ jsx(File, {
|
|
70
|
+
"aria-hidden": "true",
|
|
71
|
+
className: "size-5"
|
|
72
|
+
})
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function FileUploadContent({ className, ...props }) {
|
|
76
|
+
return /* @__PURE__ */ jsx("div", {
|
|
77
|
+
"data-slot": "file-upload-content",
|
|
78
|
+
className: cn("min-w-0 flex-1", className),
|
|
79
|
+
...props
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function FileUploadHeader({ className, ...props }) {
|
|
83
|
+
return /* @__PURE__ */ jsx("div", {
|
|
84
|
+
"data-slot": "file-upload-header",
|
|
85
|
+
className: cn("flex min-w-0 items-center gap-2", className),
|
|
86
|
+
...props
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function FileUploadName({ className, ...props }) {
|
|
90
|
+
return /* @__PURE__ */ jsx("p", {
|
|
91
|
+
"data-slot": "file-upload-name",
|
|
92
|
+
className: cn("min-w-0 flex-1 truncate text-gdt-sm font-semibold leading-snug text-fg-primary", className),
|
|
93
|
+
...props
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function FileUploadMeta({ className, ...props }) {
|
|
97
|
+
return /* @__PURE__ */ jsx("p", {
|
|
98
|
+
"data-slot": "file-upload-meta",
|
|
99
|
+
className: cn("mt-0.5 text-gdt-xs leading-snug text-fg-secondary", className),
|
|
100
|
+
...props
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function FileUploadStatus({ className, children, pendingLabel = "Waiting to upload", uploadingLabel, completeLabel = "Upload complete", errorLabel = "Upload failed", ...props }) {
|
|
104
|
+
const context = useFileUpload();
|
|
105
|
+
const defaultLabels = {
|
|
106
|
+
pending: pendingLabel,
|
|
107
|
+
uploading: uploadingLabel ?? `${context.value}% uploaded`,
|
|
108
|
+
complete: completeLabel,
|
|
109
|
+
error: errorLabel
|
|
110
|
+
};
|
|
111
|
+
const content = typeof children === "function" ? children(context) : children ?? defaultLabels[context.state];
|
|
112
|
+
return /* @__PURE__ */ jsx("output", {
|
|
113
|
+
"data-slot": "file-upload-status",
|
|
114
|
+
"aria-live": "polite",
|
|
115
|
+
className: cn("text-gdt-xs leading-snug text-fg-secondary", "group-data-[state=complete]/file-upload:text-status-success group-data-[state=error]/file-upload:text-status-danger", className),
|
|
116
|
+
...props,
|
|
117
|
+
children: content
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
function FileUploadProgress({ className, children, showValue = true, "aria-label": ariaLabel = "Upload progress", ...props }) {
|
|
121
|
+
const { state, value } = useFileUpload();
|
|
122
|
+
return /* @__PURE__ */ jsx(Progress, {
|
|
123
|
+
value,
|
|
124
|
+
"aria-label": ariaLabel,
|
|
125
|
+
className: cn("mt-2", state === "complete" && "[&_[data-slot=progress-indicator]]:bg-status-success", state === "error" && "[&_[data-slot=progress-indicator]]:bg-status-danger", className),
|
|
126
|
+
...props,
|
|
127
|
+
children: children ?? (showValue ? /* @__PURE__ */ jsx(ProgressValue, {}) : null)
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
function FileUploadCircularProgress({ className, labelOverlay = true, "aria-label": ariaLabel = "Upload progress", ...props }) {
|
|
131
|
+
const { state, value } = useFileUpload();
|
|
132
|
+
return /* @__PURE__ */ jsx(CircularProgress, {
|
|
133
|
+
value,
|
|
134
|
+
labelOverlay,
|
|
135
|
+
"aria-label": ariaLabel,
|
|
136
|
+
className: cn("text-white [&_circle:first-child]:text-white/35 [&_circle:last-child]:text-white", state === "complete" && "[&_circle:last-child]:text-status-success", state === "error" && "[&_circle:last-child]:text-status-danger", className),
|
|
137
|
+
...props
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
function FileUploadCancel({ className, type = "button", children, variant = "ghost", "aria-label": ariaLabel = "Cancel upload", ...props }) {
|
|
141
|
+
return /* @__PURE__ */ jsx("button", {
|
|
142
|
+
"data-slot": "file-upload-cancel",
|
|
143
|
+
type,
|
|
144
|
+
"aria-label": ariaLabel,
|
|
145
|
+
className: cn("inline-flex size-7 shrink-0 cursor-pointer items-center justify-center rounded-full border border-transparent bg-transparent p-0 text-fg-secondary", "transition-[background-color,border-color,color,box-shadow] hover:bg-surface-raised hover:text-fg-primary focus-visible:border-line-focus focus-visible:outline-none focus-visible:shadow-[0_0_0_2px_var(--color-line-focus)] disabled:pointer-events-none disabled:opacity-50", variant === "surface" && "border-line bg-surface-overlay shadow-sm hover:bg-surface-raised", className),
|
|
146
|
+
...props,
|
|
147
|
+
children: children ?? /* @__PURE__ */ jsx(X, {
|
|
148
|
+
"aria-hidden": "true",
|
|
149
|
+
className: "size-4"
|
|
150
|
+
})
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
//#endregion
|
|
154
|
+
export { FileUpload, FileUploadCancel, FileUploadCircularProgress, FileUploadContent, FileUploadHeader, FileUploadIcon, FileUploadImage, FileUploadMeta, FileUploadName, FileUploadOverlay, FileUploadPreview, FileUploadPreviewAction, FileUploadProgress, FileUploadStatus, useFileUpload };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
//#region src/infinite-scroll.d.ts
|
|
3
|
+
interface InfiniteScrollState {
|
|
4
|
+
/** Initial page load state, usually from useInfiniteQuery. */
|
|
5
|
+
isLoading: boolean;
|
|
6
|
+
/** Whether the flattened list has no items. */
|
|
7
|
+
isEmpty: boolean;
|
|
8
|
+
error?: Error | null;
|
|
9
|
+
hasNextPage: boolean | undefined;
|
|
10
|
+
isFetchingNextPage: boolean;
|
|
11
|
+
fetchNextPage: () => unknown;
|
|
12
|
+
}
|
|
13
|
+
declare function useInfiniteScrollSentinel({ hasNextPage, isFetchingNextPage, fetchNextPage, rootMargin }: Pick<InfiniteScrollState, "hasNextPage" | "isFetchingNextPage" | "fetchNextPage"> & {
|
|
14
|
+
rootMargin?: string;
|
|
15
|
+
}): import("react").RefCallback<HTMLDivElement | null>;
|
|
16
|
+
declare function InfiniteScroll({ children, isLoading, isEmpty, error, hasNextPage, isFetchingNextPage, fetchNextPage }: InfiniteScrollState & {
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
}): import("react").JSX.Element;
|
|
19
|
+
declare function InfiniteScrollLoading({ children }: {
|
|
20
|
+
children?: ReactNode;
|
|
21
|
+
}): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null;
|
|
22
|
+
declare function InfiniteScrollContent({ children }: {
|
|
23
|
+
children: ReactNode;
|
|
24
|
+
}): ReactNode;
|
|
25
|
+
declare function InfiniteScrollEmpty({ children }: {
|
|
26
|
+
children: ReactNode;
|
|
27
|
+
}): ReactNode;
|
|
28
|
+
declare function InfiniteScrollError({ children }: {
|
|
29
|
+
children?: ReactNode;
|
|
30
|
+
}): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null;
|
|
31
|
+
declare function InfiniteScrollEnd({ children }: {
|
|
32
|
+
children: ReactNode;
|
|
33
|
+
}): ReactNode;
|
|
34
|
+
declare function InfiniteScrollSentinel({ rootMargin, className }: {
|
|
35
|
+
/** Distance from the viewport at which the next fetch triggers. */
|
|
36
|
+
rootMargin?: string;
|
|
37
|
+
className?: string;
|
|
38
|
+
}): import("react").JSX.Element | null;
|
|
39
|
+
//#endregion
|
|
40
|
+
export { InfiniteScroll, InfiniteScrollContent, InfiniteScrollEmpty, InfiniteScrollEnd, InfiniteScrollError, InfiniteScrollLoading, InfiniteScrollSentinel, type InfiniteScrollState, useInfiniteScrollSentinel };
|