@stll/ui 0.33.0 → 0.34.1
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/components/button.d.ts +2 -2
- package/dist/components/file-input.d.ts +7 -5
- package/dist/components/file-input.js +19 -35
- package/dist/components/outline-rail.js +2 -2
- package/dist/components/segmented-icon-toggle.js +2 -0
- package/dist/components/sidebar.d.ts +2 -2
- package/dist/components/sidebar.js +2 -2
- package/dist/components/tabs.js +1 -1
- package/dist/inspector/facet-bar.js +10 -2
- package/dist/lib/file-picker.d.ts +20 -0
- package/dist/lib/file-picker.js +29 -0
- package/package.json +8 -4
|
@@ -13,8 +13,8 @@ import { VariantProps } from "class-variance-authority";
|
|
|
13
13
|
*/
|
|
14
14
|
declare const buttonAccessibleDisabledClass = "cursor-not-allowed opacity-64";
|
|
15
15
|
declare const buttonVariants: (props?: ({
|
|
16
|
-
size?: "
|
|
17
|
-
variant?: "
|
|
16
|
+
size?: "xs" | "sm" | "icon" | "default" | "chip" | "icon-lg" | "icon-sm" | "icon-xl" | "icon-xs" | "lg" | "row" | "xl" | null | undefined;
|
|
17
|
+
variant?: "destructive" | "outline" | "link" | "default" | "destructive-outline" | "destructive-ghost" | "ghost" | "muted" | "secondary" | null | undefined;
|
|
18
18
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
19
19
|
type ButtonProps = {
|
|
20
20
|
variant?: VariantProps<typeof buttonVariants>["variant"];
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import * as React$1 from "react";
|
|
2
1
|
//#region src/components/file-input.d.ts
|
|
3
|
-
type FileInputProps =
|
|
4
|
-
|
|
2
|
+
type FileInputProps = {
|
|
3
|
+
accept?: string | undefined;
|
|
4
|
+
"aria-labelledby"?: string | undefined;
|
|
5
|
+
className?: string | undefined;
|
|
6
|
+
disabled?: boolean | undefined;
|
|
5
7
|
file: File | null;
|
|
6
|
-
onFileChange: (file: File
|
|
8
|
+
onFileChange: (file: File) => void;
|
|
7
9
|
chooseLabel: string;
|
|
8
10
|
emptyLabel: string;
|
|
9
11
|
};
|
|
10
|
-
declare const FileInput: ({ className, disabled, file, onFileChange, chooseLabel, emptyLabel
|
|
12
|
+
declare const FileInput: ({ accept, "aria-labelledby": labelledBy, className, disabled, file, onFileChange, chooseLabel, emptyLabel }: FileInputProps) => import("react").JSX.Element;
|
|
11
13
|
//#endregion
|
|
12
14
|
export { FileInput, type FileInputProps };
|
|
@@ -1,49 +1,33 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/utils.js";
|
|
3
3
|
import { Button } from "./button.js";
|
|
4
|
+
import { openFilePicker } from "../lib/file-picker.js";
|
|
4
5
|
import { UploadIcon } from "lucide-react";
|
|
5
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
-
import { useId
|
|
7
|
+
import { useId } from "react";
|
|
7
8
|
//#region src/components/file-input.tsx
|
|
8
|
-
const FileInput = ({ className, disabled, file, onFileChange, chooseLabel, emptyLabel
|
|
9
|
-
const inputRef = useRef(null);
|
|
9
|
+
const FileInput = ({ accept, "aria-labelledby": labelledBy, className, disabled, file, onFileChange, chooseLabel, emptyLabel }) => {
|
|
10
10
|
const triggerId = useId();
|
|
11
11
|
return /* @__PURE__ */ jsxs("span", {
|
|
12
12
|
className: cn("flex min-w-0 items-center gap-3", className),
|
|
13
13
|
"data-slot": "file-input",
|
|
14
|
-
children: [
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
multiple: false,
|
|
23
|
-
onChange: (event) => {
|
|
24
|
-
const next = event.currentTarget.files?.item(0) ?? null;
|
|
25
|
-
event.currentTarget.value = "";
|
|
26
|
-
onFileChange(next);
|
|
27
|
-
},
|
|
28
|
-
type: "file",
|
|
29
|
-
value: void 0
|
|
14
|
+
children: [/* @__PURE__ */ jsxs(Button, {
|
|
15
|
+
"aria-labelledby": labelledBy ? `${labelledBy} ${triggerId}` : void 0,
|
|
16
|
+
"data-slot": "file-input-trigger",
|
|
17
|
+
disabled,
|
|
18
|
+
id: triggerId,
|
|
19
|
+
onClick: () => openFilePicker({
|
|
20
|
+
accept,
|
|
21
|
+
onPick: ([first]) => onFileChange(first)
|
|
30
22
|
}),
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
children: [/* @__PURE__ */ jsx(UploadIcon, { "aria-hidden": "true" }), chooseLabel]
|
|
40
|
-
}),
|
|
41
|
-
/* @__PURE__ */ jsx("span", {
|
|
42
|
-
className: "text-muted-foreground min-w-0 truncate text-sm",
|
|
43
|
-
"data-slot": "file-input-name",
|
|
44
|
-
children: file ? /* @__PURE__ */ jsx("bdi", { children: file.name }) : emptyLabel
|
|
45
|
-
})
|
|
46
|
-
]
|
|
23
|
+
type: "button",
|
|
24
|
+
variant: "outline",
|
|
25
|
+
children: [/* @__PURE__ */ jsx(UploadIcon, { "aria-hidden": "true" }), chooseLabel]
|
|
26
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
27
|
+
className: "text-muted-foreground min-w-0 truncate text-sm",
|
|
28
|
+
"data-slot": "file-input-name",
|
|
29
|
+
children: file ? /* @__PURE__ */ jsx("bdi", { children: file.name }) : emptyLabel
|
|
30
|
+
})]
|
|
47
31
|
});
|
|
48
32
|
};
|
|
49
33
|
//#endregion
|
|
@@ -267,7 +267,7 @@ const OutlineRail = ({ items, scrollContainerRef, resolvePct, onJump, activeId,
|
|
|
267
267
|
const highlighted = isActive || isHovered;
|
|
268
268
|
const indent = 8 + Math.min(node.item.level, maxLevel) * 12;
|
|
269
269
|
return /* @__PURE__ */ jsxs("li", { children: [/* @__PURE__ */ jsxs("div", {
|
|
270
|
-
className: cn("flex items-center rounded-md pe-2.5
|
|
270
|
+
className: cn("flex items-center rounded-md pe-2.5", !hasChildren && highlighted && "bg-accent"),
|
|
271
271
|
...isActive ? { [ACTIVE_ROW_ATTRIBUTE]: "" } : {},
|
|
272
272
|
onMouseEnter: () => setHoveredId(node.item.id),
|
|
273
273
|
onMouseLeave: () => setHoveredId(null),
|
|
@@ -367,7 +367,7 @@ const OutlineRail = ({ items, scrollContainerRef, resolvePct, onJump, activeId,
|
|
|
367
367
|
return /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, { render: /* @__PURE__ */ jsx("button", {
|
|
368
368
|
"aria-current": isActive ? "true" : void 0,
|
|
369
369
|
"aria-label": item.label,
|
|
370
|
-
className: cn("absolute end-0 rounded-full transition-[width,height,opacity
|
|
370
|
+
className: cn("absolute end-0 rounded-full transition-[width,height,opacity] duration-150", isHovered || isActive ? "opacity-100" : "opacity-45 hover:opacity-90"),
|
|
371
371
|
onClick: () => jumpTo(item.id),
|
|
372
372
|
onMouseEnter: () => setHoveredId(item.id),
|
|
373
373
|
onMouseLeave: () => setHoveredId(null),
|
|
@@ -9,6 +9,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
9
9
|
* the same across the app. */
|
|
10
10
|
const SegmentedIconToggle = ({ value, options, onChange, size = "compact" }) => /* @__PURE__ */ jsx("div", {
|
|
11
11
|
className: cn("border-border/70 bg-muted/30 inline-flex shrink-0 items-center overflow-hidden rounded-md border p-0.5", size === "touch" ? "h-7 [@media(any-pointer:coarse)]:h-12" : "h-7"),
|
|
12
|
+
"data-slot": "segmented-icon-toggle",
|
|
12
13
|
children: options.map((option) => {
|
|
13
14
|
const Icon = option.icon;
|
|
14
15
|
const isActive = value === option.value;
|
|
@@ -17,6 +18,7 @@ const SegmentedIconToggle = ({ value, options, onChange, size = "compact" }) =>
|
|
|
17
18
|
"aria-label": option.label,
|
|
18
19
|
"aria-pressed": isActive,
|
|
19
20
|
className: cn("text-muted-foreground h-6 min-h-0 w-7 rounded-[4px] p-0", size === "touch" && "[@media(any-pointer:coarse)]:h-11 [@media(any-pointer:coarse)]:min-h-11 [@media(any-pointer:coarse)]:w-11", isActive && "bg-muted text-foreground ring-border/80 hover:bg-muted hover:text-foreground shadow-xs ring-1"),
|
|
21
|
+
"data-control-value": option.value,
|
|
20
22
|
onClick: () => onChange(option.value),
|
|
21
23
|
size: "icon-xs",
|
|
22
24
|
type: "button",
|
|
@@ -30,7 +30,7 @@ declare function useSidebar(): SidebarContextProps;
|
|
|
30
30
|
* left for the content column. Mobile reports 0: there the sidebar is an
|
|
31
31
|
* overlay sheet and occupies no layout width.
|
|
32
32
|
*/
|
|
33
|
-
declare function useSidebarInlineSize(): 0 |
|
|
33
|
+
declare function useSidebarInlineSize(): 0 | 48 | 256;
|
|
34
34
|
declare const SidebarProvider: ({ defaultOpen, forceCollapsed, open: openProp, onOpenChange: setOpenProp, className, style, children, ...props }: React.ComponentProps<"div"> & {
|
|
35
35
|
defaultOpen?: boolean;
|
|
36
36
|
forceCollapsed?: boolean;
|
|
@@ -82,7 +82,7 @@ declare const SidebarGroupContent: ({ className, ...props }: React.ComponentProp
|
|
|
82
82
|
declare const SidebarMenu: ({ className, ...props }: React.ComponentProps<"ul">) => import("react").JSX.Element;
|
|
83
83
|
declare const SidebarMenuItem: ({ className, ...props }: React.ComponentProps<"li">) => import("react").JSX.Element;
|
|
84
84
|
declare const sidebarMenuButtonVariants: (props?: ({
|
|
85
|
-
variant?: "
|
|
85
|
+
variant?: "outline" | "default" | null | undefined;
|
|
86
86
|
size?: "sm" | "default" | "lg" | "rail" | null | undefined;
|
|
87
87
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
88
88
|
declare const SidebarMenuButton: ({ asChild, isActive, variant, size, tooltip, className, ...props }: React.ComponentProps<"button"> & {
|
|
@@ -174,7 +174,7 @@ const SidebarRail = ({ className, label = DEFAULT_TOGGLE_LABEL, "aria-label": ar
|
|
|
174
174
|
return /* @__PURE__ */ jsx("button", {
|
|
175
175
|
"aria-label": ariaLabel ?? label,
|
|
176
176
|
type: "button",
|
|
177
|
-
className: cn("hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 transition-
|
|
177
|
+
className: cn("hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 transition-transform ease-linear group-data-[side=left]:-end-4 group-data-[side=right]:start-0 after:absolute after:inset-y-0 after:start-1/2 after:w-[2px] sm:flex", "ltr:-translate-x-1/2 rtl:translate-x-1/2", "in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize", "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize", "hover:group-data-[collapsible=offcanvas]:bg-sidebar", "group-data-[collapsible=offcanvas]:ltr:translate-x-0 group-data-[collapsible=offcanvas]:rtl:translate-x-0", "group-data-[collapsible=offcanvas]:group-data-[side=left]:after:end-full group-data-[collapsible=offcanvas]:group-data-[side=right]:after:start-full", "[[data-side=left][data-collapsible=offcanvas]_&]:-end-2", "[[data-side=right][data-collapsible=offcanvas]_&]:-start-2", className),
|
|
178
178
|
"data-sidebar": "rail",
|
|
179
179
|
"data-slot": "sidebar-rail",
|
|
180
180
|
onClick: toggleSidebar,
|
|
@@ -257,7 +257,7 @@ const SidebarMenuItem = ({ className, ...props }) => /* @__PURE__ */ jsx("li", {
|
|
|
257
257
|
"data-slot": "sidebar-menu-item",
|
|
258
258
|
...props
|
|
259
259
|
});
|
|
260
|
-
const sidebarMenuButtonVariants = cva("peer/menu-button ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground data-[active=true]:bg-accent data-[active=true]:text-sidebar-accent-foreground data-[active=true]:hover:bg-sidebar-accent data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-start text-sm outline-hidden transition-[width,height,padding
|
|
260
|
+
const sidebarMenuButtonVariants = cva("peer/menu-button ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground data-[active=true]:bg-accent data-[active=true]:text-sidebar-accent-foreground data-[active=true]:hover:bg-sidebar-accent data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-start text-sm outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pe-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:font-medium [&>span:last-child]:truncate [&>span:last-child]:transition-opacity [&>span:last-child]:duration-200 group-data-[collapsible=icon]:[&>span:last-child]:opacity-0 [&>svg]:size-4 [&>svg]:shrink-0", {
|
|
261
261
|
variants: {
|
|
262
262
|
variant: {
|
|
263
263
|
default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
package/dist/components/tabs.js
CHANGED
|
@@ -33,7 +33,7 @@ const TabsList = ({ variant = "default", className, children, ref, ...props }) =
|
|
|
33
33
|
});
|
|
34
34
|
};
|
|
35
35
|
const TabsTab = ({ className, ...props }) => /* @__PURE__ */ jsx(Tabs$1.Tab, {
|
|
36
|
-
className: cn("hover:text-foreground focus-visible:ring-ring data-active:text-foreground relative flex h-9 shrink-0 grow cursor-pointer items-center justify-center gap-1.5 rounded-md border border-transparent px-[calc(--spacing(2.5)-1px)] text-base font-medium whitespace-nowrap
|
|
36
|
+
className: cn("hover:text-foreground focus-visible:ring-ring data-active:text-foreground relative flex h-9 shrink-0 grow cursor-pointer items-center justify-center gap-1.5 rounded-md border border-transparent px-[calc(--spacing(2.5)-1px)] text-base font-medium whitespace-nowrap outline-none focus-visible:ring-2 focus-visible:ring-inset data-disabled:pointer-events-none data-disabled:opacity-64 data-[orientation=vertical]:w-full data-[orientation=vertical]:justify-start sm:h-8 sm:text-sm [&_svg]:pointer-events-none [&_svg]:-mx-0.5 [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4", className),
|
|
37
37
|
"data-slot": "tabs-tab",
|
|
38
38
|
...props
|
|
39
39
|
});
|
|
@@ -79,6 +79,8 @@ const InspectorFacetBar = ({ facet, facets, labels, disabledFacets, pulseSeq, ac
|
|
|
79
79
|
}
|
|
80
80
|
return /* @__PURE__ */ jsxs("div", {
|
|
81
81
|
className: cn("bg-background/85 supports-[backdrop-filter]:bg-background/65 sticky top-0 z-10 flex shrink-0 items-center gap-0.5 overflow-hidden border-b px-1.5 backdrop-blur", TOOLBAR_ROW_HEIGHT),
|
|
82
|
+
"data-active-facet": facet,
|
|
83
|
+
"data-slot": "inspector-facet-bar",
|
|
82
84
|
ref: containerRef,
|
|
83
85
|
children: [
|
|
84
86
|
visibleFacets.map((value) => /* @__PURE__ */ jsx(FacetChip, {
|
|
@@ -86,11 +88,13 @@ const InspectorFacetBar = ({ facet, facets, labels, disabledFacets, pulseSeq, ac
|
|
|
86
88
|
disabled: disabledFacets?.has(value) ?? false,
|
|
87
89
|
isActive: value === facet,
|
|
88
90
|
label: labels[value],
|
|
89
|
-
onSelect: () => onChange(value)
|
|
91
|
+
onSelect: () => onChange(value),
|
|
92
|
+
value
|
|
90
93
|
}, value)),
|
|
91
94
|
overflowing && /* @__PURE__ */ jsxs(Menu, { children: [/* @__PURE__ */ jsx(MenuTrigger, {
|
|
92
95
|
"aria-label": overflowMenuLabel,
|
|
93
96
|
className: "ms-auto",
|
|
97
|
+
"data-slot": "inspector-facet-overflow-trigger",
|
|
94
98
|
render: /* @__PURE__ */ jsx(Button, {
|
|
95
99
|
size: "icon-sm",
|
|
96
100
|
type: "button",
|
|
@@ -101,6 +105,7 @@ const InspectorFacetBar = ({ facet, facets, labels, disabledFacets, pulseSeq, ac
|
|
|
101
105
|
align: "end",
|
|
102
106
|
side: "bottom",
|
|
103
107
|
children: overflowFacets.map((value) => /* @__PURE__ */ jsx(MenuItem, {
|
|
108
|
+
"data-facet-overflow-value": value,
|
|
104
109
|
disabled: disabledFacets?.has(value) ?? false,
|
|
105
110
|
onClick: () => onChange(value),
|
|
106
111
|
children: labels[value]
|
|
@@ -112,6 +117,8 @@ const InspectorFacetBar = ({ facet, facets, labels, disabledFacets, pulseSeq, ac
|
|
|
112
117
|
ref: measureRef,
|
|
113
118
|
children: [facets.map((value) => /* @__PURE__ */ jsx("span", {
|
|
114
119
|
className: cn(CHIP_CLASS, INACTIVE_CHIP_CLASS),
|
|
120
|
+
"data-facet-option": value,
|
|
121
|
+
"data-facet-option-disabled": disabledFacets?.has(value) ? "" : void 0,
|
|
115
122
|
children: labels[value]
|
|
116
123
|
}, value)), /* @__PURE__ */ jsx("span", { className: "size-8 shrink-0 rounded-lg border sm:size-7" })]
|
|
117
124
|
})
|
|
@@ -152,10 +159,11 @@ const flashFacetChip = (el) => {
|
|
|
152
159
|
};
|
|
153
160
|
const CHIP_CLASS = "shrink-0 rounded-md px-1.5 py-1 text-xs font-medium whitespace-nowrap transition-colors";
|
|
154
161
|
const INACTIVE_CHIP_CLASS = "text-muted-foreground hover:bg-muted hover:text-foreground";
|
|
155
|
-
const FacetChip = ({ label, isActive, disabled, activeBadge, onSelect }) => /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
|
|
162
|
+
const FacetChip = ({ label, value, isActive, disabled, activeBadge, onSelect }) => /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
|
|
156
163
|
render: /* @__PURE__ */ jsx("button", {
|
|
157
164
|
className: cn(CHIP_CLASS, isActive ? "bg-foreground text-background" : INACTIVE_CHIP_CLASS, disabled && "cursor-not-allowed opacity-40 hover:bg-transparent"),
|
|
158
165
|
"data-facet-chip-active": isActive ? "" : void 0,
|
|
166
|
+
"data-facet-value": value,
|
|
159
167
|
disabled,
|
|
160
168
|
onClick: onSelect,
|
|
161
169
|
type: "button"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/lib/file-picker.d.ts
|
|
2
|
+
type PickedFiles = [File, ...File[]];
|
|
3
|
+
type OpenFilePickerOptions = {
|
|
4
|
+
accept?: string | undefined;
|
|
5
|
+
multiple?: boolean | undefined;
|
|
6
|
+
onPick: (files: PickedFiles) => void;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Opens the browser's file chooser without an `<input type="file">` in the
|
|
10
|
+
* component tree, so no surface carries a hidden input, a ref, or the
|
|
11
|
+
* value-reset that lets the same file be picked twice.
|
|
12
|
+
*
|
|
13
|
+
* Call it synchronously inside a user gesture (a click or keydown handler):
|
|
14
|
+
* browsers open the chooser only under transient activation, so an `await`
|
|
15
|
+
* before the call silently does nothing. Dismissing the chooser calls nothing;
|
|
16
|
+
* `onPick` runs only with at least one file.
|
|
17
|
+
*/
|
|
18
|
+
declare const openFilePicker: ({ accept, multiple, onPick }: OpenFilePickerOptions) => void;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { type OpenFilePickerOptions, openFilePicker };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/lib/file-picker.ts
|
|
2
|
+
/**
|
|
3
|
+
* Opens the browser's file chooser without an `<input type="file">` in the
|
|
4
|
+
* component tree, so no surface carries a hidden input, a ref, or the
|
|
5
|
+
* value-reset that lets the same file be picked twice.
|
|
6
|
+
*
|
|
7
|
+
* Call it synchronously inside a user gesture (a click or keydown handler):
|
|
8
|
+
* browsers open the chooser only under transient activation, so an `await`
|
|
9
|
+
* before the call silently does nothing. Dismissing the chooser calls nothing;
|
|
10
|
+
* `onPick` runs only with at least one file.
|
|
11
|
+
*/
|
|
12
|
+
const openFilePicker = ({ accept, multiple = false, onPick }) => {
|
|
13
|
+
const input = document.createElement("input");
|
|
14
|
+
input.type = "file";
|
|
15
|
+
input.multiple = multiple;
|
|
16
|
+
if (accept !== void 0) input.accept = accept;
|
|
17
|
+
input.hidden = true;
|
|
18
|
+
const settle = () => {
|
|
19
|
+
input.remove();
|
|
20
|
+
const [first, ...rest] = Array.from(input.files ?? []);
|
|
21
|
+
if (first !== void 0) onPick([first, ...rest]);
|
|
22
|
+
};
|
|
23
|
+
input.addEventListener("change", settle, { once: true });
|
|
24
|
+
input.addEventListener("cancel", settle, { once: true });
|
|
25
|
+
document.body.append(input);
|
|
26
|
+
input.click();
|
|
27
|
+
};
|
|
28
|
+
//#endregion
|
|
29
|
+
export { openFilePicker };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stll/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.1",
|
|
4
4
|
"description": "Stella's design system: bidi-aware React primitives built on Base UI, the dockable inspector pane, and the Tailwind v4 theme they are styled with.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"base-ui",
|
|
@@ -578,6 +578,10 @@
|
|
|
578
578
|
"types": "./dist/hooks/use-viewport-width.d.ts",
|
|
579
579
|
"import": "./dist/hooks/use-viewport-width.js"
|
|
580
580
|
},
|
|
581
|
+
"./file-picker": {
|
|
582
|
+
"types": "./dist/lib/file-picker.d.ts",
|
|
583
|
+
"import": "./dist/lib/file-picker.js"
|
|
584
|
+
},
|
|
581
585
|
"./lib/overlay-layer": {
|
|
582
586
|
"types": "./dist/lib/overlay-layer.d.ts",
|
|
583
587
|
"import": "./dist/lib/overlay-layer.js"
|
|
@@ -614,7 +618,7 @@
|
|
|
614
618
|
"clsx": "^2.1.1",
|
|
615
619
|
"input-otp": "^1.5.0",
|
|
616
620
|
"lucide-react": "1.41.0",
|
|
617
|
-
"tailwind-merge": "^3.
|
|
621
|
+
"tailwind-merge": "^3.7.0",
|
|
618
622
|
"temporal-polyfill": "1.0.4"
|
|
619
623
|
},
|
|
620
624
|
"devDependencies": {
|
|
@@ -626,7 +630,7 @@
|
|
|
626
630
|
"@playwright/test": "^1.63.0",
|
|
627
631
|
"@stll/typescript-config": "0.0.0",
|
|
628
632
|
"@tailwindcss/vite": "4.3.3",
|
|
629
|
-
"@tanstack/react-virtual": "^3.14.
|
|
633
|
+
"@tanstack/react-virtual": "^3.14.13",
|
|
630
634
|
"@types/react": "^19.2.17",
|
|
631
635
|
"@types/react-dom": "^19.2.7",
|
|
632
636
|
"bun-types": "1.4.2",
|
|
@@ -642,7 +646,7 @@
|
|
|
642
646
|
"@base-ui/react": "^1.7.0",
|
|
643
647
|
"@dnd-kit/core": "^6.3.1",
|
|
644
648
|
"@dnd-kit/sortable": "^10.0.0",
|
|
645
|
-
"@tanstack/react-virtual": "^3.14.
|
|
649
|
+
"@tanstack/react-virtual": "^3.14.13",
|
|
646
650
|
"react": ">=19",
|
|
647
651
|
"react-dom": ">=19",
|
|
648
652
|
"tailwindcss": "^4.3.0"
|