@particle-academy/react-fancy 5.27.0 → 5.28.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 +1 -3
- package/dist/{chunk-JJBOKZWV.js → chunk-32HCJ5GD.js} +28 -8
- package/dist/chunk-32HCJ5GD.js.map +1 -0
- package/dist/{chunk-7HN4M5MV.cjs → chunk-JX6NKLQV.cjs} +8 -8
- package/dist/{chunk-7HN4M5MV.cjs.map → chunk-JX6NKLQV.cjs.map} +1 -1
- package/dist/{chunk-JAAJJJKI.js → chunk-L5KKMJ2Q.js} +52 -7
- package/dist/chunk-L5KKMJ2Q.js.map +1 -0
- package/dist/{chunk-ZVRVOKXH.cjs → chunk-LAQGBLIU.cjs} +28 -8
- package/dist/chunk-LAQGBLIU.cjs.map +1 -0
- package/dist/{chunk-HBCKKE24.cjs → chunk-LHNC42J3.cjs} +51 -6
- package/dist/chunk-LHNC42J3.cjs.map +1 -0
- package/dist/{chunk-IUWUXCCB.js → chunk-ZDVVE4OV.js} +3 -3
- package/dist/{chunk-IUWUXCCB.js.map → chunk-ZDVVE4OV.js.map} +1 -1
- package/dist/file-upload.cjs +3 -3
- package/dist/file-upload.d.cts +4 -1
- package/dist/file-upload.d.ts +4 -1
- package/dist/file-upload.js +1 -1
- package/dist/index.cjs +18 -18
- package/dist/index.js +3 -3
- package/dist/input.cjs +2 -2
- package/dist/input.js +1 -1
- package/dist/inputs.cjs +2 -2
- package/dist/inputs.js +1 -1
- package/dist/json-editor.cjs +13 -13
- package/dist/json-editor.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-HBCKKE24.cjs.map +0 -1
- package/dist/chunk-JAAJJJKI.js.map +0 -1
- package/dist/chunk-JJBOKZWV.js.map +0 -1
- package/dist/chunk-ZVRVOKXH.cjs.map +0 -1
|
@@ -6,9 +6,27 @@ import { useInlineEdit } from './chunk-OL53XYHF.js';
|
|
|
6
6
|
import { useFieldMode } from './chunk-NRXK42LO.js';
|
|
7
7
|
import { useControllableState } from './chunk-6FQGMVF2.js';
|
|
8
8
|
import { cn } from './chunk-MMW2JGKZ.js';
|
|
9
|
-
import { forwardRef, useId } from 'react';
|
|
9
|
+
import { forwardRef, useId, useState, useCallback, useEffect } from 'react';
|
|
10
10
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
11
11
|
|
|
12
|
+
function useAdornmentWidth() {
|
|
13
|
+
const [width, setWidth] = useState(0);
|
|
14
|
+
const [node, setNode] = useState(null);
|
|
15
|
+
const ref = useCallback((n) => setNode(n), []);
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (!node) {
|
|
18
|
+
setWidth(0);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const read = () => setWidth(node.getBoundingClientRect().width);
|
|
22
|
+
read();
|
|
23
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
24
|
+
const observer = new ResizeObserver(read);
|
|
25
|
+
observer.observe(node);
|
|
26
|
+
return () => observer.disconnect();
|
|
27
|
+
}, [node]);
|
|
28
|
+
return [ref, width];
|
|
29
|
+
}
|
|
12
30
|
var Input = forwardRef(
|
|
13
31
|
({
|
|
14
32
|
type = "text",
|
|
@@ -42,6 +60,8 @@ var Input = forwardRef(
|
|
|
42
60
|
const inputId = id ?? autoId;
|
|
43
61
|
const resolvedMode = useFieldMode(mode);
|
|
44
62
|
const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);
|
|
63
|
+
const [leadingRef, leadingWidth] = useAdornmentWidth();
|
|
64
|
+
const [trailingRef, trailingWidth] = useAdornmentWidth();
|
|
45
65
|
const canReveal = reveal === true && type === "password";
|
|
46
66
|
const [isRevealed, setRevealed] = useControllableState(revealed, false, onRevealedChange);
|
|
47
67
|
const shown = canReveal && isRevealed;
|
|
@@ -65,7 +85,14 @@ var Input = forwardRef(
|
|
|
65
85
|
suffixPosition,
|
|
66
86
|
size,
|
|
67
87
|
children: /* @__PURE__ */ jsxs("div", { "data-react-fancy-input": "", className: "relative flex items-center", children: [
|
|
68
|
-
leading && /* @__PURE__ */ jsx(
|
|
88
|
+
leading && /* @__PURE__ */ jsx(
|
|
89
|
+
"span",
|
|
90
|
+
{
|
|
91
|
+
ref: leadingRef,
|
|
92
|
+
className: "pointer-events-none absolute left-3 text-zinc-400 dark:text-zinc-500",
|
|
93
|
+
children: leading
|
|
94
|
+
}
|
|
95
|
+
),
|
|
69
96
|
/* @__PURE__ */ jsx(
|
|
70
97
|
"input",
|
|
71
98
|
{
|
|
@@ -80,10 +107,21 @@ var Input = forwardRef(
|
|
|
80
107
|
dirtyClasses(dirty),
|
|
81
108
|
errorClasses(error),
|
|
82
109
|
"w-full",
|
|
83
|
-
|
|
84
|
-
|
|
110
|
+
// The fixed classes are the PRE-MEASURE fallback only. Once the
|
|
111
|
+
// adornment is measured, the inline style below overrides them
|
|
112
|
+
// with its real width -- a fixed 36px is correct for one icon and
|
|
113
|
+
// wrong for anything wider, which is how `https://` came to
|
|
114
|
+
// render on top of the value.
|
|
115
|
+
leading && !leadingWidth && "pl-9",
|
|
116
|
+
(trailing || canReveal) && !trailingWidth && "pr-9",
|
|
85
117
|
className
|
|
86
118
|
),
|
|
119
|
+
style: {
|
|
120
|
+
// 12px clears `left-3`/`right-3`; 8px is the gap to the text.
|
|
121
|
+
...leadingWidth ? { paddingLeft: leadingWidth + 20 } : null,
|
|
122
|
+
...trailingWidth ? { paddingRight: trailingWidth + 20 } : null,
|
|
123
|
+
...props.style
|
|
124
|
+
},
|
|
87
125
|
onChange: (e) => {
|
|
88
126
|
onChange?.(e);
|
|
89
127
|
onValueChange?.(e.target.value);
|
|
@@ -112,7 +150,14 @@ var Input = forwardRef(
|
|
|
112
150
|
className: "absolute right-2 inline-flex items-center justify-center rounded p-1 text-zinc-400 transition-colors hover:text-zinc-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500/40 disabled:cursor-not-allowed disabled:opacity-50 dark:text-zinc-500 dark:hover:text-zinc-300",
|
|
113
151
|
children: shown ? /* @__PURE__ */ jsx(EyeOffIcon, {}) : /* @__PURE__ */ jsx(EyeIcon, {})
|
|
114
152
|
}
|
|
115
|
-
) : trailing && /* @__PURE__ */ jsx(
|
|
153
|
+
) : trailing && /* @__PURE__ */ jsx(
|
|
154
|
+
"span",
|
|
155
|
+
{
|
|
156
|
+
ref: trailingRef,
|
|
157
|
+
className: "pointer-events-none absolute right-3 text-zinc-400 dark:text-zinc-500",
|
|
158
|
+
children: trailing
|
|
159
|
+
}
|
|
160
|
+
)
|
|
116
161
|
] })
|
|
117
162
|
}
|
|
118
163
|
);
|
|
@@ -151,5 +196,5 @@ function EyeOffIcon() {
|
|
|
151
196
|
}
|
|
152
197
|
|
|
153
198
|
export { Input };
|
|
154
|
-
//# sourceMappingURL=chunk-
|
|
155
|
-
//# sourceMappingURL=chunk-
|
|
199
|
+
//# sourceMappingURL=chunk-L5KKMJ2Q.js.map
|
|
200
|
+
//# sourceMappingURL=chunk-L5KKMJ2Q.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/use-adornment-width.ts","../src/components/inputs/Input/Input.tsx"],"names":[],"mappings":"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","file":"chunk-L5KKMJ2Q.js","sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\n\n/**\n * Measure an inline adornment so the input can reserve exactly its width.\n *\n * ## Why this exists\n *\n * `leading` / `trailing` render ABSOLUTELY over the input, so they take no\n * space in flow and the input must be padded by hand to keep text clear of\n * them. That padding used to be a fixed `pl-9` / `pr-9` — 36px, sized for a\n * single icon. Any wider adornment ran straight under the value: `leading =\n * \"https://\"` is roughly 50px, so `https://` and `fancy.app` rendered on top of\n * one another.\n *\n * A fixed padding cannot be right for arbitrary content, and these props accept\n * arbitrary content — a currency code, a unit, a protocol, a short label. So\n * the width is measured rather than assumed.\n *\n * Returns `0` until measured (and on the server), which is the signal to keep\n * the old fixed padding as a fallback: an unmeasured render is then no worse\n * than it was before, rather than unpadded.\n *\n * `ResizeObserver` rather than a one-shot read, because the width changes after\n * first paint for reasons the first paint cannot see — a webfont swapping in,\n * the adornment's own content changing, a container query resizing the text.\n */\nexport function useAdornmentWidth(): [(node: HTMLElement | null) => void, number] {\n const [width, setWidth] = useState(0);\n const [node, setNode] = useState<HTMLElement | null>(null);\n\n const ref = useCallback((n: HTMLElement | null) => setNode(n), []);\n\n useEffect(() => {\n if (!node) {\n setWidth(0);\n\n return;\n }\n\n const read = () => setWidth(node.getBoundingClientRect().width);\n read();\n\n if (typeof ResizeObserver === \"undefined\") return;\n\n const observer = new ResizeObserver(read);\n observer.observe(node);\n\n return () => observer.disconnect();\n }, [node]);\n\n return [ref, width];\n}\n","import { forwardRef, useId } from \"react\";\nimport { cn } from \"../../../utils/cn\";\nimport { useControllableState } from \"../../../hooks/use-controllable-state\";\nimport { useAdornmentWidth } from \"../../../hooks/use-adornment-width\";\nimport { Field } from \"../Field\";\nimport { InputWrapper } from \"../InputWrapper\";\nimport {\n dirtyClasses,\n errorClasses,\n inputBaseClasses,\n inputSizeClasses,\n} from \"../inputs.utils\";\nimport { useFieldMode } from \"../mode/FieldMode.context\";\nimport { DisplayValue } from \"../mode/DisplayValue\";\nimport { useInlineEdit } from \"../mode/useInlineEdit\";\nimport type { InputProps } from \"./Input.types\";\n\nexport const Input = forwardRef<HTMLInputElement, InputProps>(\n (\n {\n type = \"text\",\n size = \"md\",\n dirty,\n error,\n label,\n labelHidden,\n description,\n required,\n disabled,\n className,\n id,\n leading,\n trailing,\n prefix,\n suffix,\n prefixPosition,\n suffixPosition,\n mode,\n onValueChange,\n onChange,\n reveal,\n revealed,\n onRevealedChange,\n revealLabel = \"Show password\",\n hideLabel = \"Hide password\",\n ...props\n },\n ref,\n ) => {\n const autoId = useId();\n const inputId = id ?? autoId;\n const resolvedMode = useFieldMode(mode);\n const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);\n\n // Measured, not assumed: `leading`/`trailing` take arbitrary content, and a\n // fixed padding can only ever be right for one width. See\n // `useAdornmentWidth` for what went wrong with the fixed version.\n const [leadingRef, leadingWidth] = useAdornmentWidth();\n const [trailingRef, trailingWidth] = useAdornmentWidth();\n\n // Only meaningful on a password field: a reveal on an already-visible input\n // is a button that does nothing.\n const canReveal = reveal === true && type === \"password\";\n const [isRevealed, setRevealed] = useControllableState(revealed, false, onRevealedChange);\n const shown = canReveal && isRevealed;\n // The rendered type, NOT the declared one — `type` stays \"password\" so the\n // display-mode masking below and any caller reading props are unaffected.\n const renderedType = shown ? \"text\" : type;\n\n const input = !showControl ? (\n <DisplayValue\n size={size}\n interactive={interactive}\n onActivate={enterEdit}\n leading={leading ?? prefix}\n trailing={trailing ?? suffix}\n >\n {type === \"password\" ? (props.value ? \"••••••\" : \"\") : (props.value as string | undefined)}\n </DisplayValue>\n ) : (\n <InputWrapper\n prefix={prefix}\n suffix={suffix}\n prefixPosition={prefixPosition}\n suffixPosition={suffixPosition}\n size={size}\n >\n <div data-react-fancy-input=\"\" className=\"relative flex items-center\">\n {leading && (\n <span\n ref={leadingRef}\n className=\"pointer-events-none absolute left-3 text-zinc-400 dark:text-zinc-500\"\n >\n {leading}\n </span>\n )}\n <input\n ref={ref}\n id={inputId}\n type={renderedType}\n disabled={disabled}\n required={required}\n className={cn(\n inputBaseClasses,\n inputSizeClasses[size],\n dirtyClasses(dirty),\n errorClasses(error),\n \"w-full\",\n // The fixed classes are the PRE-MEASURE fallback only. Once the\n // adornment is measured, the inline style below overrides them\n // with its real width -- a fixed 36px is correct for one icon and\n // wrong for anything wider, which is how `https://` came to\n // render on top of the value.\n leading && !leadingWidth && \"pl-9\",\n (trailing || canReveal) && !trailingWidth && \"pr-9\",\n className,\n )}\n style={{\n // 12px clears `left-3`/`right-3`; 8px is the gap to the text.\n ...(leadingWidth ? { paddingLeft: leadingWidth + 20 } : null),\n ...(trailingWidth ? { paddingRight: trailingWidth + 20 } : null),\n ...props.style,\n }}\n onChange={(e) => {\n onChange?.(e);\n onValueChange?.(e.target.value);\n }}\n {...props}\n // Inline click-to-edit: focus on entering edit, return to the display\n // (and run the host's onBlur) when focus leaves.\n autoFocus={interactive || props.autoFocus}\n onBlur={(e) => {\n props.onBlur?.(e);\n if (interactive) exitEdit();\n }}\n />\n {canReveal ? (\n <button\n type=\"button\"\n // type=\"button\" is load-bearing: the default is \"submit\", so a\n // reveal inside a login form would submit it on every click.\n id={`${inputId}-reveal`}\n data-react-fancy-reveal=\"\"\n onClick={() => setRevealed((v) => !v)}\n disabled={disabled}\n aria-controls={inputId}\n aria-pressed={shown}\n aria-label={shown ? hideLabel : revealLabel}\n title={shown ? hideLabel : revealLabel}\n // Not focusable by tab: the field and the submit button are the\n // path through a login form, and a reveal in between is a stop\n // most people do not want. Still reachable by click and by\n // screen readers.\n tabIndex={-1}\n className=\"absolute right-2 inline-flex items-center justify-center rounded p-1 text-zinc-400 transition-colors hover:text-zinc-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500/40 disabled:cursor-not-allowed disabled:opacity-50 dark:text-zinc-500 dark:hover:text-zinc-300\"\n >\n {shown ? <EyeOffIcon /> : <EyeIcon />}\n </button>\n ) : (\n trailing && (\n <span\n ref={trailingRef}\n className=\"pointer-events-none absolute right-3 text-zinc-400 dark:text-zinc-500\"\n >\n {trailing}\n </span>\n )\n )}\n </div>\n </InputWrapper>\n );\n\n if (label || error || description) {\n return (\n <Field\n label={label}\n labelHidden={labelHidden}\n description={description}\n error={error}\n required={required}\n htmlFor={inputId}\n size={size}\n >\n {input}\n </Field>\n );\n }\n\n return input;\n },\n);\n\nInput.displayName = \"Input\";\n\n/**\n * Inline SVGs rather than the Icon component: Input is the most-installed\n * primitive in the kit, and routing it through the icon registry would make\n * every consumer's password field depend on an icon set being configured.\n */\nfunction EyeIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n );\n}\n\nfunction EyeOffIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49\" />\n <path d=\"M14.084 14.158a3 3 0 0 1-4.242-4.242\" />\n <path d=\"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143\" />\n <path d=\"m2 2 20 20\" />\n </svg>\n );\n}\n"]}
|
|
@@ -19,7 +19,7 @@ function FileUploadDropzone({
|
|
|
19
19
|
children,
|
|
20
20
|
className
|
|
21
21
|
}) {
|
|
22
|
-
const { addFiles, disabled } = useFileUpload();
|
|
22
|
+
const { addFiles, disabled, accept, multiple } = useFileUpload();
|
|
23
23
|
const [dragOver, setDragOver] = react.useState(false);
|
|
24
24
|
const inputRef = react.useRef(null);
|
|
25
25
|
const handleDrop = react.useCallback(
|
|
@@ -58,7 +58,8 @@ function FileUploadDropzone({
|
|
|
58
58
|
type: "file",
|
|
59
59
|
className: "hidden",
|
|
60
60
|
onChange: (e) => e.target.files && addFiles(e.target.files),
|
|
61
|
-
|
|
61
|
+
accept,
|
|
62
|
+
multiple,
|
|
62
63
|
disabled
|
|
63
64
|
}
|
|
64
65
|
),
|
|
@@ -138,10 +139,25 @@ function FileUploadList({ thumbnail, className }) {
|
|
|
138
139
|
)) });
|
|
139
140
|
}
|
|
140
141
|
FileUploadList.displayName = "FileUploadList";
|
|
142
|
+
|
|
143
|
+
// src/components/FileUpload/matchesAccept.ts
|
|
144
|
+
function matchesAccept(file, accept) {
|
|
145
|
+
const rules = accept.split(",").map((rule) => rule.trim().toLowerCase()).filter(Boolean);
|
|
146
|
+
if (rules.length === 0) return true;
|
|
147
|
+
const type = file.type.toLowerCase();
|
|
148
|
+
const name = file.name.toLowerCase();
|
|
149
|
+
return rules.some((rule) => {
|
|
150
|
+
if (rule.startsWith(".")) return name.endsWith(rule);
|
|
151
|
+
if (rule.endsWith("/*")) return type.startsWith(rule.slice(0, -1));
|
|
152
|
+
return type === rule;
|
|
153
|
+
});
|
|
154
|
+
}
|
|
141
155
|
function FileUploadRoot({
|
|
142
156
|
children,
|
|
143
157
|
value,
|
|
144
158
|
onChange,
|
|
159
|
+
accept,
|
|
160
|
+
multiple = true,
|
|
145
161
|
maxFiles,
|
|
146
162
|
maxSize,
|
|
147
163
|
disabled = false,
|
|
@@ -152,15 +168,19 @@ function FileUploadRoot({
|
|
|
152
168
|
const addFiles = react.useCallback(
|
|
153
169
|
(newFiles) => {
|
|
154
170
|
let toAdd = Array.from(newFiles);
|
|
171
|
+
if (accept) {
|
|
172
|
+
toAdd = toAdd.filter((f) => matchesAccept(f, accept));
|
|
173
|
+
}
|
|
155
174
|
if (maxSize) {
|
|
156
175
|
toAdd = toAdd.filter((f) => f.size <= maxSize);
|
|
157
176
|
}
|
|
177
|
+
const cap = multiple === false ? 1 : maxFiles;
|
|
158
178
|
const updated = [...files, ...toAdd];
|
|
159
|
-
const limited =
|
|
179
|
+
const limited = cap ? updated.slice(0, cap) : updated;
|
|
160
180
|
if (value === void 0) setInternalFiles(limited);
|
|
161
181
|
onChange?.(limited);
|
|
162
182
|
},
|
|
163
|
-
[files, maxFiles, maxSize, onChange, value]
|
|
183
|
+
[accept, files, maxFiles, maxSize, multiple, onChange, value]
|
|
164
184
|
);
|
|
165
185
|
const removeFile = react.useCallback(
|
|
166
186
|
(index) => {
|
|
@@ -171,8 +191,8 @@ function FileUploadRoot({
|
|
|
171
191
|
[files, onChange, value]
|
|
172
192
|
);
|
|
173
193
|
const ctx = react.useMemo(
|
|
174
|
-
() => ({ files, addFiles, removeFile, disabled }),
|
|
175
|
-
[files, addFiles, removeFile, disabled]
|
|
194
|
+
() => ({ files, addFiles, removeFile, disabled, accept, multiple }),
|
|
195
|
+
[files, addFiles, removeFile, disabled, accept, multiple]
|
|
176
196
|
);
|
|
177
197
|
return /* @__PURE__ */ jsxRuntime.jsx(FileUploadContext.Provider, { value: ctx, children: /* @__PURE__ */ jsxRuntime.jsx("div", { "data-react-fancy-file-upload": "", className: chunkZU5Q77OT_cjs.cn(className), children }) });
|
|
178
198
|
}
|
|
@@ -183,5 +203,5 @@ var FileUpload = Object.assign(FileUploadRoot, {
|
|
|
183
203
|
|
|
184
204
|
exports.FileUpload = FileUpload;
|
|
185
205
|
exports.useFileUpload = useFileUpload;
|
|
186
|
-
//# sourceMappingURL=chunk-
|
|
187
|
-
//# sourceMappingURL=chunk-
|
|
206
|
+
//# sourceMappingURL=chunk-LAQGBLIU.cjs.map
|
|
207
|
+
//# sourceMappingURL=chunk-LAQGBLIU.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/FileUpload/FileUpload.context.ts","../src/components/FileUpload/FileUploadDropzone.tsx","../src/components/FileUpload/FileUploadList.tsx","../src/components/FileUpload/matchesAccept.ts","../src/components/FileUpload/FileUpload.tsx"],"names":["createContext","useContext","useState","useRef","useCallback","jsxs","cn","jsx","Fragment","Upload","useMemo","useEffect","File","X"],"mappings":";;;;;;;AAGO,IAAM,iBAAA,GACXA,oBAA6C,IAAI,CAAA;AAE5C,SAAS,aAAA,GAAwC;AACtD,EAAA,MAAM,GAAA,GAAMC,iBAAW,iBAAiB,CAAA;AACxC,EAAA,IAAI,CAAC,GAAA,EAAK;AACR,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AACA,EAAA,OAAO,GAAA;AACT;ACRO,SAAS,kBAAA,CAAmB;AAAA,EACjC,QAAA;AAAA,EACA;AACF,CAAA,EAA4B;AAC1B,EAAA,MAAM,EAAE,QAAA,EAAU,QAAA,EAAU,MAAA,EAAQ,QAAA,KAAa,aAAA,EAAc;AAC/D,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAIC,eAAS,KAAK,CAAA;AAC9C,EAAA,MAAM,QAAA,GAAWC,aAAyB,IAAI,CAAA;AAE9C,EAAA,MAAM,UAAA,GAAaC,iBAAA;AAAA,IACjB,CAAC,CAAA,KAAuB;AACtB,MAAA,CAAA,CAAE,cAAA,EAAe;AACjB,MAAA,WAAA,CAAY,KAAK,CAAA;AACjB,MAAA,IAAI,QAAA,EAAU;AACd,MAAA,QAAA,CAAS,CAAA,CAAE,aAAa,KAAK,CAAA;AAAA,IAC/B,CAAA;AAAA,IACA,CAAC,UAAU,QAAQ;AAAA,GACrB;AAEA,EAAA,MAAM,cAAA,GAAiBA,iBAAA,CAAY,CAAC,CAAA,KAAuB;AACzD,IAAA,CAAA,CAAE,cAAA,EAAe;AACjB,IAAA,WAAA,CAAY,IAAI,CAAA;AAAA,EAClB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,kBAAkBA,iBAAA,CAAY,MAAM,YAAY,KAAK,CAAA,EAAG,EAAE,CAAA;AAEhE,EAAA,uBACEC,eAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,uCAAA,EAAsC,EAAA;AAAA,MACtC,MAAA,EAAQ,UAAA;AAAA,MACR,UAAA,EAAY,cAAA;AAAA,MACZ,WAAA,EAAa,eAAA;AAAA,MACb,SAAS,MAAM,CAAC,QAAA,IAAY,QAAA,CAAS,SAAS,KAAA,EAAM;AAAA,MACpD,SAAA,EAAWC,oBAAA;AAAA,QACT,8HAAA;AAAA,QACA,WACI,kEAAA,GACA,uFAAA;AAAA,QACJ,QAAA,IAAY,+BAAA;AAAA,QACZ;AAAA,OACF;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAAC,cAAA;AAAA,UAAC,OAAA;AAAA,UAAA;AAAA,YACC,GAAA,EAAK,QAAA;AAAA,YACL,IAAA,EAAK,MAAA;AAAA,YACL,SAAA,EAAU,QAAA;AAAA,YACV,QAAA,EAAU,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,KAAA,IAAS,QAAA,CAAS,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA;AAAA,YAC1D,MAAA;AAAA,YACA,QAAA;AAAA,YACA;AAAA;AAAA,SACF;AAAA,QACC,4BACCF,eAAA,CAAAG,mBAAA,EAAA,EACE,QAAA,EAAA;AAAA,0BAAAD,cAAA,CAACE,sBAAO,IAAA,EAAM,EAAA,EAAI,WAAA,EAAa,GAAA,EAAK,WAAU,oBAAA,EAAqB,CAAA;AAAA,0BACnEF,cAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,uBAAA,EAAwB,QAAA,EAAA,oCAAA,EAErC;AAAA,SAAA,EACF;AAAA;AAAA;AAAA,GAEJ;AAEJ;AAEA,kBAAA,CAAmB,WAAA,GAAc,oBAAA;AC9DjC,SAAS,WAAW,KAAA,EAAuB;AACzC,EAAA,IAAI,KAAA,GAAQ,IAAA,EAAM,OAAO,CAAA,EAAG,KAAK,CAAA,EAAA,CAAA;AACjC,EAAA,IAAI,KAAA,GAAQ,OAAO,IAAA,EAAM,OAAO,IAAI,KAAA,GAAQ,IAAA,EAAM,OAAA,CAAQ,CAAC,CAAC,CAAA,GAAA,CAAA;AAC5D,EAAA,OAAO,IAAI,KAAA,IAAS,IAAA,GAAO,IAAA,CAAA,EAAO,OAAA,CAAQ,CAAC,CAAC,CAAA,GAAA,CAAA;AAC9C;AAEA,SAAS,aAAa,IAAA,EAAsB;AAC1C,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC5B,EAAA,OAAO,MAAM,MAAA,GAAS,CAAA,GAAI,MAAM,GAAA,EAAI,CAAG,aAAY,GAAI,EAAA;AACzD;AAEA,SAAS,aAAA,CAAc,EAAE,IAAA,EAAM,KAAA,EAAO,UAAS,EAAiE;AAC9G,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,IAAA,CAAK,UAAA,CAAW,QAAQ,CAAA;AAC7C,EAAA,MAAM,SAAA,GAAYG,aAAA,CAAQ,MAAO,OAAA,GAAU,GAAA,CAAI,eAAA,CAAgB,IAAI,CAAA,GAAI,IAAA,EAAO,CAAC,IAAA,EAAM,OAAO,CAAC,CAAA;AAE7F,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,OAAO,MAAM;AACX,MAAA,IAAI,SAAA,EAAW,GAAA,CAAI,eAAA,CAAgB,SAAS,CAAA;AAAA,IAC9C,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAEd,EAAA,uBACEN,eAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,sDAAA,EACb,QAAA,EAAA;AAAA,oBAAAA,eAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,uHAAA,EACZ,QAAA,EAAA;AAAA,MAAA,OAAA,IAAW,4BACVE,cAAAA,CAAC,KAAA,EAAA,EAAI,GAAA,EAAK,WAAW,GAAA,EAAK,IAAA,CAAK,IAAA,EAAM,SAAA,EAAU,8BAA6B,CAAA,mBAE5EF,eAAAA,CAAC,KAAA,EAAA,EAAI,WAAU,+DAAA,EACb,QAAA,EAAA;AAAA,wBAAAE,cAAAA,CAACK,gBAAA,EAAA,EAAK,IAAA,EAAM,EAAA,EAAI,WAAU,eAAA,EAAgB,CAAA;AAAA,wBAC1CL,eAAC,MAAA,EAAA,EAAK,SAAA,EAAU,yCAAyC,QAAA,EAAA,YAAA,CAAa,IAAA,CAAK,IAAI,CAAA,EAAE;AAAA,OAAA,EACnF,CAAA;AAAA,sBAEFA,cAAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,QAAA;AAAA,UACL,OAAA,EAAS,MAAM,QAAA,CAAS,KAAK,CAAA;AAAA,UAC7B,SAAA,EAAU,4KAAA;AAAA,UACV,YAAA,EAAY,CAAA,OAAA,EAAU,IAAA,CAAK,IAAI,CAAA,CAAA;AAAA,UAE/B,QAAA,kBAAAA,cAAAA,CAACM,aAAA,EAAA,EAAE,IAAA,EAAM,EAAA,EAAI;AAAA;AAAA;AACf,KAAA,EACF,CAAA;AAAA,oBACAN,cAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mDAAA,EAAqD,eAAK,IAAA,EAAK;AAAA,GAAA,EACjF,CAAA;AAEJ;AAEO,SAAS,cAAA,CAAe,EAAE,SAAA,EAAW,SAAA,EAAU,EAAwB;AAC5E,EAAA,MAAM,EAAE,KAAA,EAAO,UAAA,EAAW,GAAI,aAAA,EAAc;AAE5C,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAE/B,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,uBACEA,cAAAA,CAAC,KAAA,EAAA,EAAI,mCAAA,EAAkC,EAAA,EAAG,SAAA,EAAWD,oBAAA,CAAG,2BAAA,EAA6B,SAAS,CAAA,EAC3F,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,EAAM,CAAA,qBAChBC,cAAAA,CAAC,aAAA,EAAA,EAAwC,IAAA,EAAY,KAAA,EAAO,CAAA,EAAG,QAAA,EAAU,UAAA,EAAA,EAArD,CAAA,EAAG,IAAA,CAAK,IAAI,CAAA,CAAA,EAAI,CAAC,CAAA,CAAgD,CACtF,CAAA,EACH,CAAA;AAAA,EAEJ;AAEA,EAAA,uBACEA,cAAAA,CAAC,IAAA,EAAA,EAAG,mCAAA,EAAkC,IAAG,SAAA,EAAWD,oBAAA,CAAG,gBAAA,EAAkB,SAAS,GAC/E,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,EAAM,sBAChBD,eAAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MAEC,SAAA,EAAU,kGAAA;AAAA,MAEV,QAAA,EAAA;AAAA,wBAAAE,cAAAA,CAACK,gBAAA,EAAA,EAAK,IAAA,EAAM,EAAA,EAAI,WAAU,wBAAA,EAAyB,CAAA;AAAA,wBACnDL,cAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,iBAAA,EAAmB,eAAK,IAAA,EAAK,CAAA;AAAA,wBAC7CA,eAAC,MAAA,EAAA,EAAK,SAAA,EAAU,kCACb,QAAA,EAAA,UAAA,CAAW,IAAA,CAAK,IAAI,CAAA,EACvB,CAAA;AAAA,wBACAA,cAAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,OAAA,EAAS,MAAM,UAAA,CAAW,CAAC,CAAA;AAAA,YAC3B,SAAA,EAAU,qEAAA;AAAA,YACV,YAAA,EAAY,CAAA,OAAA,EAAU,IAAA,CAAK,IAAI,CAAA,CAAA;AAAA,YAE/B,QAAA,kBAAAA,cAAAA,CAACM,aAAA,EAAA,EAAE,IAAA,EAAM,EAAA,EAAI;AAAA;AAAA;AACf;AAAA,KAAA;AAAA,IAfK,CAAA,EAAG,IAAA,CAAK,IAAI,CAAA,CAAA,EAAI,CAAC,CAAA;AAAA,GAiBzB,CAAA,EACH,CAAA;AAEJ;AAEA,cAAA,CAAe,WAAA,GAAc,gBAAA;;;AC3EtB,SAAS,aAAA,CAAc,MAAY,MAAA,EAAyB;AACjE,EAAA,MAAM,KAAA,GAAQ,MAAA,CACX,KAAA,CAAM,GAAG,EACT,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,MAAK,CAAE,WAAA,EAAa,CAAA,CACvC,OAAO,OAAO,CAAA;AAIjB,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAE/B,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,WAAA,EAAY;AACnC,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,WAAA,EAAY;AAEnC,EAAA,OAAO,KAAA,CAAM,IAAA,CAAK,CAAC,IAAA,KAAS;AAC1B,IAAA,IAAI,KAAK,UAAA,CAAW,GAAG,GAAG,OAAO,IAAA,CAAK,SAAS,IAAI,CAAA;AACnD,IAAA,IAAI,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,EAAG,OAAO,IAAA,CAAK,UAAA,CAAW,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA;AACjE,IAAA,OAAO,IAAA,KAAS,IAAA;AAAA,EAClB,CAAC,CAAA;AACH;AC5BA,SAAS,cAAA,CAAe;AAAA,EACtB,QAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA,GAAW,IAAA;AAAA,EACX,QAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX;AACF,CAAA,EAAoB;AAClB,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAIX,cAAAA,CAAiB,EAAE,CAAA;AAC7D,EAAA,MAAM,QAAQ,KAAA,IAAS,aAAA;AAEvB,EAAA,MAAM,QAAA,GAAWE,iBAAAA;AAAA,IACf,CAAC,QAAA,KAAgC;AAC/B,MAAA,IAAI,KAAA,GAAQ,KAAA,CAAM,IAAA,CAAK,QAAQ,CAAA;AAI/B,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,KAAA,GAAQ,MAAM,MAAA,CAAO,CAAC,MAAM,aAAA,CAAc,CAAA,EAAG,MAAM,CAAC,CAAA;AAAA,MACtD;AAEA,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,KAAA,GAAQ,MAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,QAAQ,OAAO,CAAA;AAAA,MAC/C;AAKA,MAAA,MAAM,GAAA,GAAM,QAAA,KAAa,KAAA,GAAQ,CAAA,GAAI,QAAA;AAErC,MAAA,MAAM,OAAA,GAAU,CAAC,GAAG,KAAA,EAAO,GAAG,KAAK,CAAA;AACnC,MAAA,MAAM,UAAU,GAAA,GAAM,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,GAAG,CAAA,GAAI,OAAA;AAE9C,MAAA,IAAI,KAAA,KAAU,MAAA,EAAW,gBAAA,CAAiB,OAAO,CAAA;AACjD,MAAA,QAAA,GAAW,OAAO,CAAA;AAAA,IACpB,CAAA;AAAA,IACA,CAAC,MAAA,EAAQ,KAAA,EAAO,UAAU,OAAA,EAAS,QAAA,EAAU,UAAU,KAAK;AAAA,GAC9D;AAEA,EAAA,MAAM,UAAA,GAAaA,iBAAAA;AAAA,IACjB,CAAC,KAAA,KAAkB;AACjB,MAAA,MAAM,UAAU,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,EAAG,CAAA,KAAM,MAAM,KAAK,CAAA;AAClD,MAAA,IAAI,KAAA,KAAU,MAAA,EAAW,gBAAA,CAAiB,OAAO,CAAA;AACjD,MAAA,QAAA,GAAW,OAAO,CAAA;AAAA,IACpB,CAAA;AAAA,IACA,CAAC,KAAA,EAAO,QAAA,EAAU,KAAK;AAAA,GACzB;AAEA,EAAA,MAAM,GAAA,GAAMM,aAAAA;AAAA,IACV,OAAO,EAAE,KAAA,EAAO,UAAU,UAAA,EAAY,QAAA,EAAU,QAAQ,QAAA,EAAS,CAAA;AAAA,IACjE,CAAC,KAAA,EAAO,QAAA,EAAU,UAAA,EAAY,QAAA,EAAU,QAAQ,QAAQ;AAAA,GAC1D;AAEA,EAAA,uBACEH,cAAAA,CAAC,iBAAA,CAAkB,QAAA,EAAlB,EAA2B,OAAO,GAAA,EACjC,QAAA,kBAAAA,cAAAA,CAAC,KAAA,EAAA,EAAI,gCAA6B,EAAA,EAAG,SAAA,EAAWD,qBAAG,SAAS,CAAA,EAAI,UAAS,CAAA,EAC3E,CAAA;AAEJ;AAEO,IAAM,UAAA,GAAa,MAAA,CAAO,MAAA,CAAO,cAAA,EAAgB;AAAA,EACtD,QAAA,EAAU,kBAAA;AAAA,EACV,IAAA,EAAM;AACR,CAAC","file":"chunk-LAQGBLIU.cjs","sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { FileUploadContextValue } from \"./FileUpload.types\";\n\nexport const FileUploadContext =\n createContext<FileUploadContextValue | null>(null);\n\nexport function useFileUpload(): FileUploadContextValue {\n const ctx = useContext(FileUploadContext);\n if (!ctx) {\n throw new Error(\n \"FileUpload compound components must be used within <FileUpload>\",\n );\n }\n return ctx;\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport { Upload } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport { useFileUpload } from \"./FileUpload.context\";\nimport type { FileUploadDropzoneProps } from \"./FileUpload.types\";\n\nexport function FileUploadDropzone({\n children,\n className,\n}: FileUploadDropzoneProps) {\n const { addFiles, disabled, accept, multiple } = useFileUpload();\n const [dragOver, setDragOver] = useState(false);\n const inputRef = useRef<HTMLInputElement>(null);\n\n const handleDrop = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n setDragOver(false);\n if (disabled) return;\n addFiles(e.dataTransfer.files);\n },\n [addFiles, disabled],\n );\n\n const handleDragOver = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n setDragOver(true);\n }, []);\n\n const handleDragLeave = useCallback(() => setDragOver(false), []);\n\n return (\n <div\n data-react-fancy-file-upload-dropzone=\"\"\n onDrop={handleDrop}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onClick={() => !disabled && inputRef.current?.click()}\n className={cn(\n \"flex cursor-pointer flex-col items-center justify-center rounded-xl border-2 border-dashed p-8 text-center transition-colors\",\n dragOver\n ? \"border-blue-400 bg-blue-50 dark:border-blue-500 dark:bg-blue-950\"\n : \"border-zinc-300 hover:border-zinc-400 dark:border-zinc-700 dark:hover:border-zinc-500\",\n disabled && \"cursor-not-allowed opacity-50\",\n className,\n )}\n >\n <input\n ref={inputRef}\n type=\"file\"\n className=\"hidden\"\n onChange={(e) => e.target.files && addFiles(e.target.files)}\n accept={accept}\n multiple={multiple}\n disabled={disabled}\n />\n {children ?? (\n <>\n <Upload size={32} strokeWidth={1.5} className=\"mb-2 text-zinc-400\" />\n <p className=\"text-sm text-zinc-500\">\n Drop files here or click to browse\n </p>\n </>\n )}\n </div>\n );\n}\n\nFileUploadDropzone.displayName = \"FileUploadDropzone\";\n","import { useEffect, useMemo } from \"react\";\nimport { File, X } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport { useFileUpload } from \"./FileUpload.context\";\nimport type { FileUploadListProps } from \"./FileUpload.types\";\n\nfunction formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nfunction getExtension(name: string): string {\n const parts = name.split(\".\");\n return parts.length > 1 ? parts.pop()!.toUpperCase() : \"\";\n}\n\nfunction ThumbnailItem({ file, index, onRemove }: { file: File; index: number; onRemove: (i: number) => void }) {\n const isImage = file.type.startsWith(\"image/\");\n const objectUrl = useMemo(() => (isImage ? URL.createObjectURL(file) : null), [file, isImage]);\n\n useEffect(() => {\n return () => {\n if (objectUrl) URL.revokeObjectURL(objectUrl);\n };\n }, [objectUrl]);\n\n return (\n <div className=\"group relative flex w-20 flex-col items-center gap-1\">\n <div className=\"relative h-20 w-20 overflow-hidden rounded-lg border border-zinc-200 bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-800\">\n {isImage && objectUrl ? (\n <img src={objectUrl} alt={file.name} className=\"h-full w-full object-cover\" />\n ) : (\n <div className=\"flex h-full w-full flex-col items-center justify-center gap-1\">\n <File size={20} className=\"text-zinc-400\" />\n <span className=\"text-[10px] font-medium text-zinc-500\">{getExtension(file.name)}</span>\n </div>\n )}\n <button\n type=\"button\"\n onClick={() => onRemove(index)}\n className=\"absolute top-1 right-1 flex h-5 w-5 items-center justify-center rounded-full bg-black/60 text-white opacity-0 transition-opacity hover:bg-black/80 group-hover:opacity-100\"\n aria-label={`Remove ${file.name}`}\n >\n <X size={10} />\n </button>\n </div>\n <span className=\"w-full truncate text-center text-xs text-zinc-500\">{file.name}</span>\n </div>\n );\n}\n\nexport function FileUploadList({ thumbnail, className }: FileUploadListProps) {\n const { files, removeFile } = useFileUpload();\n\n if (files.length === 0) return null;\n\n if (thumbnail) {\n return (\n <div data-react-fancy-file-upload-list=\"\" className={cn(\"mt-3 flex flex-wrap gap-3\", className)}>\n {files.map((file, i) => (\n <ThumbnailItem key={`${file.name}-${i}`} file={file} index={i} onRemove={removeFile} />\n ))}\n </div>\n );\n }\n\n return (\n <ul data-react-fancy-file-upload-list=\"\" className={cn(\"mt-3 space-y-2\", className)}>\n {files.map((file, i) => (\n <li\n key={`${file.name}-${i}`}\n className=\"flex items-center gap-3 rounded-lg border border-zinc-200 px-3 py-2 text-sm dark:border-zinc-700\"\n >\n <File size={16} className=\"shrink-0 text-zinc-400\" />\n <span className=\"flex-1 truncate\">{file.name}</span>\n <span className=\"shrink-0 text-xs text-zinc-400\">\n {formatSize(file.size)}\n </span>\n <button\n type=\"button\"\n onClick={() => removeFile(i)}\n className=\"shrink-0 text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-300\"\n aria-label={`Remove ${file.name}`}\n >\n <X size={14} />\n </button>\n </li>\n ))}\n </ul>\n );\n}\n\nFileUploadList.displayName = \"FileUploadList\";\n","/**\n * Does a file satisfy an `accept` string?\n *\n * The browser enforces `accept` in the FILE PICKER only. A drag-and-drop never\n * opens a picker, so on the drop path this is the only thing standing between an\n * image-only dropzone and a dropped executable. Forwarding the attribute to the\n * hidden input is half the job; this is the other half.\n *\n * Follows the HTML `accept` grammar: a comma-separated list of extensions\n * (`.csv`), exact MIME types (`text/plain`) and type wildcards (`image/*`).\n * Matching is case-insensitive, because a drop reports whatever the OS says and\n * `TEXT/PLAIN` is a real thing to receive.\n *\n * A dropped file often carries an EMPTY `type` — the OS may not know it and\n * `File.type` is a hint, never a guarantee. That is why extension rules are\n * checked against the name and not the type: an `accept=\".csv\"` zone has to work\n * for a .csv whose type is `\"\"`, which is the common case rather than the edge.\n */\nexport function matchesAccept(file: File, accept: string): boolean {\n const rules = accept\n .split(\",\")\n .map((rule) => rule.trim().toLowerCase())\n .filter(Boolean);\n\n // An accept string that lists nothing constrains nothing. Failing closed here\n // would turn `accept=\"\"` into a dropzone that silently swallows every file.\n if (rules.length === 0) return true;\n\n const type = file.type.toLowerCase();\n const name = file.name.toLowerCase();\n\n return rules.some((rule) => {\n if (rule.startsWith(\".\")) return name.endsWith(rule);\n if (rule.endsWith(\"/*\")) return type.startsWith(rule.slice(0, -1));\n return type === rule;\n });\n}\n","import { useCallback, useMemo, useState } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { FileUploadContext } from \"./FileUpload.context\";\nimport { FileUploadDropzone } from \"./FileUploadDropzone\";\nimport { FileUploadList } from \"./FileUploadList\";\nimport { matchesAccept } from \"./matchesAccept\";\nimport type { FileUploadProps } from \"./FileUpload.types\";\n\nfunction FileUploadRoot({\n children,\n value,\n onChange,\n accept,\n multiple = true,\n maxFiles,\n maxSize,\n disabled = false,\n className,\n}: FileUploadProps) {\n const [internalFiles, setInternalFiles] = useState<File[]>([]);\n const files = value ?? internalFiles;\n\n const addFiles = useCallback(\n (newFiles: FileList | File[]) => {\n let toAdd = Array.from(newFiles);\n\n // `accept` is enforced HERE, not only on the input: the input's attribute\n // governs the picker, and a drop never opens one.\n if (accept) {\n toAdd = toAdd.filter((f) => matchesAccept(f, accept));\n }\n\n if (maxSize) {\n toAdd = toAdd.filter((f) => f.size <= maxSize);\n }\n\n // `multiple={false}` is a cap of one, applied the same way `maxFiles` is —\n // first-wins rather than replace-last, so the two props cannot disagree\n // about what a single-file upload means.\n const cap = multiple === false ? 1 : maxFiles;\n\n const updated = [...files, ...toAdd];\n const limited = cap ? updated.slice(0, cap) : updated;\n\n if (value === undefined) setInternalFiles(limited);\n onChange?.(limited);\n },\n [accept, files, maxFiles, maxSize, multiple, onChange, value],\n );\n\n const removeFile = useCallback(\n (index: number) => {\n const updated = files.filter((_, i) => i !== index);\n if (value === undefined) setInternalFiles(updated);\n onChange?.(updated);\n },\n [files, onChange, value],\n );\n\n const ctx = useMemo(\n () => ({ files, addFiles, removeFile, disabled, accept, multiple }),\n [files, addFiles, removeFile, disabled, accept, multiple],\n );\n\n return (\n <FileUploadContext.Provider value={ctx}>\n <div data-react-fancy-file-upload=\"\" className={cn(className)}>{children}</div>\n </FileUploadContext.Provider>\n );\n}\n\nexport const FileUpload = Object.assign(FileUploadRoot, {\n Dropzone: FileUploadDropzone,\n List: FileUploadList,\n});\n"]}
|
|
@@ -11,6 +11,24 @@ var chunkZU5Q77OT_cjs = require('./chunk-ZU5Q77OT.cjs');
|
|
|
11
11
|
var react = require('react');
|
|
12
12
|
var jsxRuntime = require('react/jsx-runtime');
|
|
13
13
|
|
|
14
|
+
function useAdornmentWidth() {
|
|
15
|
+
const [width, setWidth] = react.useState(0);
|
|
16
|
+
const [node, setNode] = react.useState(null);
|
|
17
|
+
const ref = react.useCallback((n) => setNode(n), []);
|
|
18
|
+
react.useEffect(() => {
|
|
19
|
+
if (!node) {
|
|
20
|
+
setWidth(0);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const read = () => setWidth(node.getBoundingClientRect().width);
|
|
24
|
+
read();
|
|
25
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
26
|
+
const observer = new ResizeObserver(read);
|
|
27
|
+
observer.observe(node);
|
|
28
|
+
return () => observer.disconnect();
|
|
29
|
+
}, [node]);
|
|
30
|
+
return [ref, width];
|
|
31
|
+
}
|
|
14
32
|
var Input = react.forwardRef(
|
|
15
33
|
({
|
|
16
34
|
type = "text",
|
|
@@ -44,6 +62,8 @@ var Input = react.forwardRef(
|
|
|
44
62
|
const inputId = id ?? autoId;
|
|
45
63
|
const resolvedMode = chunkL3V3BYVS_cjs.useFieldMode(mode);
|
|
46
64
|
const { showControl, interactive, enterEdit, exitEdit } = chunkKJ22KE56_cjs.useInlineEdit(resolvedMode, disabled);
|
|
65
|
+
const [leadingRef, leadingWidth] = useAdornmentWidth();
|
|
66
|
+
const [trailingRef, trailingWidth] = useAdornmentWidth();
|
|
47
67
|
const canReveal = reveal === true && type === "password";
|
|
48
68
|
const [isRevealed, setRevealed] = chunkOUOEQZHY_cjs.useControllableState(revealed, false, onRevealedChange);
|
|
49
69
|
const shown = canReveal && isRevealed;
|
|
@@ -67,7 +87,14 @@ var Input = react.forwardRef(
|
|
|
67
87
|
suffixPosition,
|
|
68
88
|
size,
|
|
69
89
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-react-fancy-input": "", className: "relative flex items-center", children: [
|
|
70
|
-
leading && /* @__PURE__ */ jsxRuntime.jsx(
|
|
90
|
+
leading && /* @__PURE__ */ jsxRuntime.jsx(
|
|
91
|
+
"span",
|
|
92
|
+
{
|
|
93
|
+
ref: leadingRef,
|
|
94
|
+
className: "pointer-events-none absolute left-3 text-zinc-400 dark:text-zinc-500",
|
|
95
|
+
children: leading
|
|
96
|
+
}
|
|
97
|
+
),
|
|
71
98
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
72
99
|
"input",
|
|
73
100
|
{
|
|
@@ -82,10 +109,21 @@ var Input = react.forwardRef(
|
|
|
82
109
|
chunkYLGTDBB2_cjs.dirtyClasses(dirty),
|
|
83
110
|
chunkYLGTDBB2_cjs.errorClasses(error),
|
|
84
111
|
"w-full",
|
|
85
|
-
|
|
86
|
-
|
|
112
|
+
// The fixed classes are the PRE-MEASURE fallback only. Once the
|
|
113
|
+
// adornment is measured, the inline style below overrides them
|
|
114
|
+
// with its real width -- a fixed 36px is correct for one icon and
|
|
115
|
+
// wrong for anything wider, which is how `https://` came to
|
|
116
|
+
// render on top of the value.
|
|
117
|
+
leading && !leadingWidth && "pl-9",
|
|
118
|
+
(trailing || canReveal) && !trailingWidth && "pr-9",
|
|
87
119
|
className
|
|
88
120
|
),
|
|
121
|
+
style: {
|
|
122
|
+
// 12px clears `left-3`/`right-3`; 8px is the gap to the text.
|
|
123
|
+
...leadingWidth ? { paddingLeft: leadingWidth + 20 } : null,
|
|
124
|
+
...trailingWidth ? { paddingRight: trailingWidth + 20 } : null,
|
|
125
|
+
...props.style
|
|
126
|
+
},
|
|
89
127
|
onChange: (e) => {
|
|
90
128
|
onChange?.(e);
|
|
91
129
|
onValueChange?.(e.target.value);
|
|
@@ -114,7 +152,14 @@ var Input = react.forwardRef(
|
|
|
114
152
|
className: "absolute right-2 inline-flex items-center justify-center rounded p-1 text-zinc-400 transition-colors hover:text-zinc-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500/40 disabled:cursor-not-allowed disabled:opacity-50 dark:text-zinc-500 dark:hover:text-zinc-300",
|
|
115
153
|
children: shown ? /* @__PURE__ */ jsxRuntime.jsx(EyeOffIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(EyeIcon, {})
|
|
116
154
|
}
|
|
117
|
-
) : trailing && /* @__PURE__ */ jsxRuntime.jsx(
|
|
155
|
+
) : trailing && /* @__PURE__ */ jsxRuntime.jsx(
|
|
156
|
+
"span",
|
|
157
|
+
{
|
|
158
|
+
ref: trailingRef,
|
|
159
|
+
className: "pointer-events-none absolute right-3 text-zinc-400 dark:text-zinc-500",
|
|
160
|
+
children: trailing
|
|
161
|
+
}
|
|
162
|
+
)
|
|
118
163
|
] })
|
|
119
164
|
}
|
|
120
165
|
);
|
|
@@ -153,5 +198,5 @@ function EyeOffIcon() {
|
|
|
153
198
|
}
|
|
154
199
|
|
|
155
200
|
exports.Input = Input;
|
|
156
|
-
//# sourceMappingURL=chunk-
|
|
157
|
-
//# sourceMappingURL=chunk-
|
|
201
|
+
//# sourceMappingURL=chunk-LHNC42J3.cjs.map
|
|
202
|
+
//# sourceMappingURL=chunk-LHNC42J3.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/use-adornment-width.ts","../src/components/inputs/Input/Input.tsx"],"names":["useState","useCallback","useEffect","forwardRef","useId","useFieldMode","useInlineEdit","useControllableState","jsx","DisplayValue","InputWrapper","jsxs","cn","inputBaseClasses","inputSizeClasses","dirtyClasses","errorClasses","Field"],"mappings":"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","file":"chunk-LHNC42J3.cjs","sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\n\n/**\n * Measure an inline adornment so the input can reserve exactly its width.\n *\n * ## Why this exists\n *\n * `leading` / `trailing` render ABSOLUTELY over the input, so they take no\n * space in flow and the input must be padded by hand to keep text clear of\n * them. That padding used to be a fixed `pl-9` / `pr-9` — 36px, sized for a\n * single icon. Any wider adornment ran straight under the value: `leading =\n * \"https://\"` is roughly 50px, so `https://` and `fancy.app` rendered on top of\n * one another.\n *\n * A fixed padding cannot be right for arbitrary content, and these props accept\n * arbitrary content — a currency code, a unit, a protocol, a short label. So\n * the width is measured rather than assumed.\n *\n * Returns `0` until measured (and on the server), which is the signal to keep\n * the old fixed padding as a fallback: an unmeasured render is then no worse\n * than it was before, rather than unpadded.\n *\n * `ResizeObserver` rather than a one-shot read, because the width changes after\n * first paint for reasons the first paint cannot see — a webfont swapping in,\n * the adornment's own content changing, a container query resizing the text.\n */\nexport function useAdornmentWidth(): [(node: HTMLElement | null) => void, number] {\n const [width, setWidth] = useState(0);\n const [node, setNode] = useState<HTMLElement | null>(null);\n\n const ref = useCallback((n: HTMLElement | null) => setNode(n), []);\n\n useEffect(() => {\n if (!node) {\n setWidth(0);\n\n return;\n }\n\n const read = () => setWidth(node.getBoundingClientRect().width);\n read();\n\n if (typeof ResizeObserver === \"undefined\") return;\n\n const observer = new ResizeObserver(read);\n observer.observe(node);\n\n return () => observer.disconnect();\n }, [node]);\n\n return [ref, width];\n}\n","import { forwardRef, useId } from \"react\";\nimport { cn } from \"../../../utils/cn\";\nimport { useControllableState } from \"../../../hooks/use-controllable-state\";\nimport { useAdornmentWidth } from \"../../../hooks/use-adornment-width\";\nimport { Field } from \"../Field\";\nimport { InputWrapper } from \"../InputWrapper\";\nimport {\n dirtyClasses,\n errorClasses,\n inputBaseClasses,\n inputSizeClasses,\n} from \"../inputs.utils\";\nimport { useFieldMode } from \"../mode/FieldMode.context\";\nimport { DisplayValue } from \"../mode/DisplayValue\";\nimport { useInlineEdit } from \"../mode/useInlineEdit\";\nimport type { InputProps } from \"./Input.types\";\n\nexport const Input = forwardRef<HTMLInputElement, InputProps>(\n (\n {\n type = \"text\",\n size = \"md\",\n dirty,\n error,\n label,\n labelHidden,\n description,\n required,\n disabled,\n className,\n id,\n leading,\n trailing,\n prefix,\n suffix,\n prefixPosition,\n suffixPosition,\n mode,\n onValueChange,\n onChange,\n reveal,\n revealed,\n onRevealedChange,\n revealLabel = \"Show password\",\n hideLabel = \"Hide password\",\n ...props\n },\n ref,\n ) => {\n const autoId = useId();\n const inputId = id ?? autoId;\n const resolvedMode = useFieldMode(mode);\n const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);\n\n // Measured, not assumed: `leading`/`trailing` take arbitrary content, and a\n // fixed padding can only ever be right for one width. See\n // `useAdornmentWidth` for what went wrong with the fixed version.\n const [leadingRef, leadingWidth] = useAdornmentWidth();\n const [trailingRef, trailingWidth] = useAdornmentWidth();\n\n // Only meaningful on a password field: a reveal on an already-visible input\n // is a button that does nothing.\n const canReveal = reveal === true && type === \"password\";\n const [isRevealed, setRevealed] = useControllableState(revealed, false, onRevealedChange);\n const shown = canReveal && isRevealed;\n // The rendered type, NOT the declared one — `type` stays \"password\" so the\n // display-mode masking below and any caller reading props are unaffected.\n const renderedType = shown ? \"text\" : type;\n\n const input = !showControl ? (\n <DisplayValue\n size={size}\n interactive={interactive}\n onActivate={enterEdit}\n leading={leading ?? prefix}\n trailing={trailing ?? suffix}\n >\n {type === \"password\" ? (props.value ? \"••••••\" : \"\") : (props.value as string | undefined)}\n </DisplayValue>\n ) : (\n <InputWrapper\n prefix={prefix}\n suffix={suffix}\n prefixPosition={prefixPosition}\n suffixPosition={suffixPosition}\n size={size}\n >\n <div data-react-fancy-input=\"\" className=\"relative flex items-center\">\n {leading && (\n <span\n ref={leadingRef}\n className=\"pointer-events-none absolute left-3 text-zinc-400 dark:text-zinc-500\"\n >\n {leading}\n </span>\n )}\n <input\n ref={ref}\n id={inputId}\n type={renderedType}\n disabled={disabled}\n required={required}\n className={cn(\n inputBaseClasses,\n inputSizeClasses[size],\n dirtyClasses(dirty),\n errorClasses(error),\n \"w-full\",\n // The fixed classes are the PRE-MEASURE fallback only. Once the\n // adornment is measured, the inline style below overrides them\n // with its real width -- a fixed 36px is correct for one icon and\n // wrong for anything wider, which is how `https://` came to\n // render on top of the value.\n leading && !leadingWidth && \"pl-9\",\n (trailing || canReveal) && !trailingWidth && \"pr-9\",\n className,\n )}\n style={{\n // 12px clears `left-3`/`right-3`; 8px is the gap to the text.\n ...(leadingWidth ? { paddingLeft: leadingWidth + 20 } : null),\n ...(trailingWidth ? { paddingRight: trailingWidth + 20 } : null),\n ...props.style,\n }}\n onChange={(e) => {\n onChange?.(e);\n onValueChange?.(e.target.value);\n }}\n {...props}\n // Inline click-to-edit: focus on entering edit, return to the display\n // (and run the host's onBlur) when focus leaves.\n autoFocus={interactive || props.autoFocus}\n onBlur={(e) => {\n props.onBlur?.(e);\n if (interactive) exitEdit();\n }}\n />\n {canReveal ? (\n <button\n type=\"button\"\n // type=\"button\" is load-bearing: the default is \"submit\", so a\n // reveal inside a login form would submit it on every click.\n id={`${inputId}-reveal`}\n data-react-fancy-reveal=\"\"\n onClick={() => setRevealed((v) => !v)}\n disabled={disabled}\n aria-controls={inputId}\n aria-pressed={shown}\n aria-label={shown ? hideLabel : revealLabel}\n title={shown ? hideLabel : revealLabel}\n // Not focusable by tab: the field and the submit button are the\n // path through a login form, and a reveal in between is a stop\n // most people do not want. Still reachable by click and by\n // screen readers.\n tabIndex={-1}\n className=\"absolute right-2 inline-flex items-center justify-center rounded p-1 text-zinc-400 transition-colors hover:text-zinc-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500/40 disabled:cursor-not-allowed disabled:opacity-50 dark:text-zinc-500 dark:hover:text-zinc-300\"\n >\n {shown ? <EyeOffIcon /> : <EyeIcon />}\n </button>\n ) : (\n trailing && (\n <span\n ref={trailingRef}\n className=\"pointer-events-none absolute right-3 text-zinc-400 dark:text-zinc-500\"\n >\n {trailing}\n </span>\n )\n )}\n </div>\n </InputWrapper>\n );\n\n if (label || error || description) {\n return (\n <Field\n label={label}\n labelHidden={labelHidden}\n description={description}\n error={error}\n required={required}\n htmlFor={inputId}\n size={size}\n >\n {input}\n </Field>\n );\n }\n\n return input;\n },\n);\n\nInput.displayName = \"Input\";\n\n/**\n * Inline SVGs rather than the Icon component: Input is the most-installed\n * primitive in the kit, and routing it through the icon registry would make\n * every consumer's password field depend on an icon set being configured.\n */\nfunction EyeIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n );\n}\n\nfunction EyeOffIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49\" />\n <path d=\"M14.084 14.158a3 3 0 0 1-4.242-4.242\" />\n <path d=\"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143\" />\n <path d=\"m2 2 20 20\" />\n </svg>\n );\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Switch } from './chunk-QJKWBU3I.js';
|
|
2
2
|
import { DatePicker } from './chunk-L2FPIFMN.js';
|
|
3
|
-
import { Input } from './chunk-
|
|
3
|
+
import { Input } from './chunk-L5KKMJ2Q.js';
|
|
4
4
|
import { Select } from './chunk-ZH3SPBVB.js';
|
|
5
5
|
import { Text } from './chunk-5RLP77KK.js';
|
|
6
6
|
import { Textarea } from './chunk-DEFGT75G.js';
|
|
@@ -1337,5 +1337,5 @@ function buildItems({
|
|
|
1337
1337
|
}
|
|
1338
1338
|
|
|
1339
1339
|
export { JSON_FIELD_TYPES, JsonEditor, applyJsonEdit, describeEdit, findJsonConflicts, getAtPath, inferType, parseKeyMap, parsePath, pathToString, resolveKeyRule, typeMatches };
|
|
1340
|
-
//# sourceMappingURL=chunk-
|
|
1341
|
-
//# sourceMappingURL=chunk-
|
|
1340
|
+
//# sourceMappingURL=chunk-ZDVVE4OV.js.map
|
|
1341
|
+
//# sourceMappingURL=chunk-ZDVVE4OV.js.map
|