@panneau/fields 5.0.0-alpha.3 → 5.0.0-alpha.4
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 +36 -1
- package/dist/file/FileField.css +54 -0
- package/dist/file/FileField.d.ts +50 -0
- package/dist/file/FileField.d.ts.map +1 -0
- package/dist/file/FileField.js +198 -0
- package/dist/file/FileField.js.map +1 -0
- package/dist/file/FileField.module.js +22 -0
- package/dist/file/FileField.module.js.map +1 -0
- package/dist/file/index.d.ts +3 -0
- package/dist/file/index.d.ts.map +1 -0
- package/dist/file/index.js +1 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -2
- package/dist/shared/builtIn.d.ts +3 -2
- package/dist/shared/builtIn.d.ts.map +1 -1
- package/dist/shared/builtIn.js +5 -2
- package/dist/shared/builtIn.js.map +1 -1
- package/dist/shared/context.d.ts +10 -2
- package/dist/shared/context.d.ts.map +1 -1
- package/dist/shared/context.js +22 -18
- package/dist/shared/context.js.map +1 -1
- package/dist/shared/entry.d.ts +4 -0
- package/dist/shared/entry.d.ts.map +1 -1
- package/dist/shared/entry.js +12 -1
- package/dist/shared/entry.js.map +1 -1
- package/dist/upload/FilePicker.css +24 -0
- package/dist/upload/FilePicker.d.ts +14 -0
- package/dist/upload/FilePicker.d.ts.map +1 -0
- package/dist/upload/FilePicker.js +47 -0
- package/dist/upload/FilePicker.js.map +1 -0
- package/dist/upload/FilePicker.module.js +12 -0
- package/dist/upload/FilePicker.module.js.map +1 -0
- package/dist/upload/UploadList.css +93 -0
- package/dist/upload/UploadList.d.ts +18 -0
- package/dist/upload/UploadList.d.ts.map +1 -0
- package/dist/upload/UploadList.js +144 -0
- package/dist/upload/UploadList.js.map +1 -0
- package/dist/upload/UploadList.module.js +32 -0
- package/dist/upload/UploadList.module.js.map +1 -0
- package/dist/upload/files.d.ts +5 -0
- package/dist/upload/files.d.ts.map +1 -0
- package/dist/upload/files.js +26 -0
- package/dist/upload/files.js.map +1 -0
- package/dist/upload/types.d.ts +58 -0
- package/dist/upload/types.d.ts.map +1 -0
- package/dist/upload/useRejectionMessage.d.ts +4 -0
- package/dist/upload/useRejectionMessage.d.ts.map +1 -0
- package/dist/upload/useRejectionMessage.js +25 -0
- package/dist/upload/useRejectionMessage.js.map +1 -0
- package/dist/upload/useUploads.d.ts +30 -0
- package/dist/upload/useUploads.d.ts.map +1 -0
- package/dist/upload/useUploads.js +115 -0
- package/dist/upload/useUploads.js.map +1 -0
- package/dist/uppy/index.d.ts +3 -0
- package/dist/uppy/index.d.ts.map +1 -0
- package/dist/uppy/index.js +1 -0
- package/dist/uppy/uploader.d.ts +44 -0
- package/dist/uppy/uploader.d.ts.map +1 -0
- package/dist/uppy/uploader.js +139 -0
- package/dist/uppy/uploader.js.map +1 -0
- package/package.json +30 -5
package/dist/shared/context.js
CHANGED
|
@@ -6,6 +6,7 @@ var FieldsContext = createContext({
|
|
|
6
6
|
components: {},
|
|
7
7
|
locales: [],
|
|
8
8
|
relationSource: null,
|
|
9
|
+
uploadSource: null,
|
|
9
10
|
binding: null
|
|
10
11
|
});
|
|
11
12
|
/** The fields context of the closest `FieldsProvider`. */
|
|
@@ -14,12 +15,12 @@ function useFieldsContext() {
|
|
|
14
15
|
}
|
|
15
16
|
/**
|
|
16
17
|
* Provides what fields rendered from a definition need: the components of each type, the locales
|
|
17
|
-
* of localized values, a relation source and a binding. Values not given come from the parent
|
|
18
|
+
* of localized values, a relation source, an upload source and a binding. Values not given come from the parent
|
|
18
19
|
* provider.
|
|
19
20
|
*/
|
|
20
21
|
function FieldsProvider(t0) {
|
|
21
|
-
const $ = c(
|
|
22
|
-
const { components, locales, relationSource, binding, children } = t0;
|
|
22
|
+
const $ = c(12);
|
|
23
|
+
const { components, locales, relationSource, uploadSource, binding, children } = t0;
|
|
23
24
|
const parent = use(FieldsContext);
|
|
24
25
|
let t1;
|
|
25
26
|
if ($[0] !== components || $[1] !== parent.components) {
|
|
@@ -33,33 +34,36 @@ function FieldsProvider(t0) {
|
|
|
33
34
|
} else t1 = $[2];
|
|
34
35
|
const t2 = locales ?? parent.locales;
|
|
35
36
|
const t3 = relationSource === void 0 ? parent.relationSource : relationSource;
|
|
36
|
-
const t4 =
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
const t4 = uploadSource === void 0 ? parent.uploadSource : uploadSource;
|
|
38
|
+
const t5 = binding === void 0 ? parent.binding : binding;
|
|
39
|
+
let t6;
|
|
40
|
+
if ($[3] !== t1 || $[4] !== t2 || $[5] !== t3 || $[6] !== t4 || $[7] !== t5) {
|
|
41
|
+
t6 = {
|
|
40
42
|
components: t1,
|
|
41
43
|
locales: t2,
|
|
42
44
|
relationSource: t3,
|
|
43
|
-
|
|
45
|
+
uploadSource: t4,
|
|
46
|
+
binding: t5
|
|
44
47
|
};
|
|
45
48
|
$[3] = t1;
|
|
46
49
|
$[4] = t2;
|
|
47
50
|
$[5] = t3;
|
|
48
51
|
$[6] = t4;
|
|
49
52
|
$[7] = t5;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
$[8] = t6;
|
|
54
|
+
} else t6 = $[8];
|
|
55
|
+
const value = t6;
|
|
56
|
+
let t7;
|
|
57
|
+
if ($[9] !== children || $[10] !== value) {
|
|
58
|
+
t7 = /* @__PURE__ */ jsx(FieldsContext, {
|
|
55
59
|
value,
|
|
56
60
|
children
|
|
57
61
|
});
|
|
58
|
-
$[
|
|
59
|
-
$[
|
|
60
|
-
$[
|
|
61
|
-
} else
|
|
62
|
-
return
|
|
62
|
+
$[9] = children;
|
|
63
|
+
$[10] = value;
|
|
64
|
+
$[11] = t7;
|
|
65
|
+
} else t7 = $[11];
|
|
66
|
+
return t7;
|
|
63
67
|
}
|
|
64
68
|
/** The parent path of a path: `blocks.2` for `blocks.2.title`, `''` for `title`. */
|
|
65
69
|
function getParentPath(path) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","names":["value","children","_c"],"sources":["../../src/shared/context.tsx"],"sourcesContent":["import { type ComponentType, type ReactNode, createContext, use } from 'react';\n\nimport type { Field } from '@panneau/protocol';\n\nimport type { RelationSource } from './relation';\nimport type { FieldEntry } from './types';\n\n/** What a binding gives a field: its value, handlers and errors at a path. */\nexport interface BoundFieldProps {\n value: unknown;\n onChange: (value: unknown) => void;\n onBlur?: () => void;\n errors?: readonly string[];\n}\n\n/** Props of a binding: it decides whether a field shows, and where its value comes from. */\nexport interface FieldBindingProps {\n field: Field;\n /** Dot path of the field's value. */\n path: string;\n /** Dot path of the object the field belongs to: `''` at the top, `blocks.2` in a block. */\n parentPath: string;\n /** Renders the field with its bound value. */\n render: (bound: BoundFieldProps) => ReactNode;\n}\n\n/**\n * Binds nested fields (in groups, blocks and localized values) to a store by path, instead of the\n * value and `onChange` of their parent. `@panneau/forms` binds them to its form state, so that\n * every value is set, validated and shown in error by its own path.\n */\nexport type FieldBinding = ComponentType<FieldBindingProps>;\n\nexport interface FieldsContextValue {\n /** Registry entries, by field type, over the built-in ones. */\n components: Readonly<Record<string, FieldEntry>>;\n /** Locales of localized values, in order. */\n locales: readonly string[];\n /** Where relation fields search for items. */\n relationSource: RelationSource | null;\n binding: FieldBinding | null;\n}\n\nconst FieldsContext = createContext<FieldsContextValue>({\n components: {},\n locales: [],\n relationSource: null,\n binding: null,\n});\n\n/** The fields context of the closest `FieldsProvider`. */\nexport function useFieldsContext(): FieldsContextValue {\n return use(FieldsContext);\n}\n\nexport interface FieldsProviderProps {\n /** Registry entries by type, added over those of a parent provider. */\n components?: Readonly<Record<string, FieldEntry>>;\n locales?: readonly string[];\n relationSource?: RelationSource | null;\n binding?: FieldBinding | null;\n children?: ReactNode;\n}\n\n/**\n * Provides what fields rendered from a definition need: the components of each type, the locales\n * of localized values, a relation source and a binding. Values not given come from the parent\n * provider.\n */\nexport function FieldsProvider({\n components,\n locales,\n relationSource,\n binding,\n children,\n}: FieldsProviderProps) {\n const parent = use(FieldsContext);\n const value: FieldsContextValue = {\n components:\n components !== undefined ? { ...parent.components, ...components } : parent.components,\n locales: locales ?? parent.locales,\n relationSource: relationSource === undefined ? parent.relationSource : relationSource,\n binding: binding === undefined ? parent.binding : binding,\n };\n return <FieldsContext value={value}>{children}</FieldsContext>;\n}\n\n/** The parent path of a path: `blocks.2` for `blocks.2.title`, `''` for `title`. */\nexport function getParentPath(path: string): string {\n const index = path.lastIndexOf('.');\n return index === -1 ? '' : path.slice(0, index);\n}\n"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"context.js","names":["value","children","_c"],"sources":["../../src/shared/context.tsx"],"sourcesContent":["import { type ComponentType, type ReactNode, createContext, use } from 'react';\n\nimport type { Field } from '@panneau/protocol';\n\nimport type { UploadSource } from '../upload/types';\nimport type { RelationSource } from './relation';\nimport type { FieldEntry } from './types';\n\n/** What a binding gives a field: its value, handlers and errors at a path. */\nexport interface BoundFieldProps {\n value: unknown;\n onChange: (value: unknown) => void;\n onBlur?: () => void;\n errors?: readonly string[];\n}\n\n/** Props of a binding: it decides whether a field shows, and where its value comes from. */\nexport interface FieldBindingProps {\n field: Field;\n /** Dot path of the field's value. */\n path: string;\n /** Dot path of the object the field belongs to: `''` at the top, `blocks.2` in a block. */\n parentPath: string;\n /** Renders the field with its bound value. */\n render: (bound: BoundFieldProps) => ReactNode;\n}\n\n/**\n * Binds nested fields (in groups, blocks and localized values) to a store by path, instead of the\n * value and `onChange` of their parent. `@panneau/forms` binds them to its form state, so that\n * every value is set, validated and shown in error by its own path.\n */\nexport type FieldBinding = ComponentType<FieldBindingProps>;\n\nexport interface FieldsContextValue {\n /** Registry entries, by field type, over the built-in ones. */\n components: Readonly<Record<string, FieldEntry>>;\n /** Locales of localized values, in order. */\n locales: readonly string[];\n /** Where relation fields search for items. */\n relationSource: RelationSource | null;\n /**\n * Where fields that take files upload them directly to storage. Without one, they give the\n * files themselves.\n */\n uploadSource: UploadSource | null;\n binding: FieldBinding | null;\n}\n\nconst FieldsContext = createContext<FieldsContextValue>({\n components: {},\n locales: [],\n relationSource: null,\n uploadSource: null,\n binding: null,\n});\n\n/** The fields context of the closest `FieldsProvider`. */\nexport function useFieldsContext(): FieldsContextValue {\n return use(FieldsContext);\n}\n\nexport interface FieldsProviderProps {\n /** Registry entries by type, added over those of a parent provider. */\n components?: Readonly<Record<string, FieldEntry>>;\n locales?: readonly string[];\n relationSource?: RelationSource | null;\n /** Make it once, outside of render: fields make an uploader for each source they get. */\n uploadSource?: UploadSource | null;\n binding?: FieldBinding | null;\n children?: ReactNode;\n}\n\n/**\n * Provides what fields rendered from a definition need: the components of each type, the locales\n * of localized values, a relation source, an upload source and a binding. Values not given come from the parent\n * provider.\n */\nexport function FieldsProvider({\n components,\n locales,\n relationSource,\n uploadSource,\n binding,\n children,\n}: FieldsProviderProps) {\n const parent = use(FieldsContext);\n const value: FieldsContextValue = {\n components:\n components !== undefined ? { ...parent.components, ...components } : parent.components,\n locales: locales ?? parent.locales,\n relationSource: relationSource === undefined ? parent.relationSource : relationSource,\n uploadSource: uploadSource === undefined ? parent.uploadSource : uploadSource,\n binding: binding === undefined ? parent.binding : binding,\n };\n return <FieldsContext value={value}>{children}</FieldsContext>;\n}\n\n/** The parent path of a path: `blocks.2` for `blocks.2.title`, `''` for `title`. */\nexport function getParentPath(path: string): string {\n const index = path.lastIndexOf('.');\n return index === -1 ? '' : path.slice(0, index);\n}\n"],"mappings":";;;;AAiDA,IAAM,gBAAgB,cAAkC;CACpD,YAAY,CAAC;CACb,SAAS,CAAA;CACT,gBAAgB;CAChB,cAAc;CACd,SAAS;AACb,CAAC;;AAGD,SAAgB,mBAAuC;CACnD,OAAO,IAAI,aAAa;AAC5B;;;;;;AAkBA,SAAO,eAAA,IAAA;CAAA,MAAA,IAAAE,EAAA,EAAA;CAAwB,MAAA,EAAA,YAAA,SAAA,gBAAA,cAAA,SAAA,aAAA;CAQ3B,MAAA,SAAe,IAAI,aAAa;CAAE,IAAA;CAAA,IAAA,EAAA,OAAA,cAAA,EAAA,OAAA,OAAA,YAAA;EAG1B,KAAA,eAAe,KAAA,IAAf;GAAA,GAAgC,OAAM;GAAW,GAAK;EAA+B,IAAhB,OAAM;EAAW,EAAA,KAAA;EAAA,EAAA,KAAA,OAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CACjF,MAAA,KAAA,WAAW,OAAM;CACV,MAAA,KAAA,mBAAmB,KAAA,IAAY,OAAM,iBAArC;CACF,MAAA,KAAA,iBAAiB,KAAA,IAAY,OAAM,eAAnC;CACL,MAAA,KAAA,YAAY,KAAA,IAAY,OAAM,UAA9B;CAAgD,IAAA;CAAA,IAAA,EAAA,OAAA,MAAA,EAAA,OAAA,MAAA,EAAA,OAAA,MAAA,EAAA,OAAA,MAAA,EAAA,OAAA,IAAA;EAN3B,KAAA;GAAA,YAE1B;GAAsF,SACjF;GAAyB,gBAClB;GAAqE,cACvE;GAA+D,SACpE;EACb;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAPD,MAAA,QAAkC;CAOhC,IAAA;CAAA,IAAA,EAAA,OAAA,YAAA,EAAA,QAAA,OAAA;EACK,KAAA,oBAAC,eAAD;GAAsB;GAAQ;EAAhB,CAAA;EAAyC,EAAA,KAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;CAAA,OAAA,KAAA,EAAA;CAAA,OAAvD;AAAuD;;AAIlE,SAAgB,cAAc,MAAsB;CAChD,MAAM,QAAQ,KAAK,YAAY,GAAG;CAClC,OAAO,UAAU,KAAK,KAAK,KAAK,MAAM,GAAG,KAAK;AAClD"}
|
package/dist/shared/entry.d.ts
CHANGED
|
@@ -20,4 +20,8 @@ export declare function getFieldProps(props: FieldEntryProps): Omit<FieldProps<n
|
|
|
20
20
|
};
|
|
21
21
|
/** The value as a string, or `null`. */
|
|
22
22
|
export declare function asString(value: unknown): string | null;
|
|
23
|
+
/** The accepted MIME types of a field that takes files: its `accept`, or its `accept` rule. */
|
|
24
|
+
export declare function getAccept(field: Field): string[] | null;
|
|
25
|
+
/** The largest file of a field, in bytes: its `maxSize` rule. */
|
|
26
|
+
export declare function getMaxSize(field: Field): number | null;
|
|
23
27
|
//# sourceMappingURL=entry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../../src/shared/entry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE3D,kDAAkD;AAClD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,SAAS,CAE3E;AAED,8DAA8D;AAC9D,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,CAKnF;AAED,+CAA+C;AAC/C,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAEhD;AAED,+EAA+E;AAC/E,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,KAAK,IAAI,CAAC,iBAG9F;AAED,eAAO,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAmC,CAAC;AACvF,eAAO,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MACE,CAAC;AAEtD;;;;GAIG;AACH,wBAAgB,aAAa,CACzB,KAAK,EAAE,eAAe,GACvB,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAe1E;AAED,wCAAwC;AACxC,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAEtD"}
|
|
1
|
+
{"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../../src/shared/entry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE3D,kDAAkD;AAClD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,SAAS,CAE3E;AAED,8DAA8D;AAC9D,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,CAKnF;AAED,+CAA+C;AAC/C,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAEhD;AAED,+EAA+E;AAC/E,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,KAAK,IAAI,CAAC,iBAG9F;AAED,eAAO,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAmC,CAAC;AACvF,eAAO,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MACE,CAAC;AAEtD;;;;GAIG;AACH,wBAAgB,aAAa,CACzB,KAAK,EAAE,eAAe,GACvB,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAe1E;AAED,wCAAwC;AACxC,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAEtD;AAED,+FAA+F;AAC/F,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,GAAG,IAAI,CAQvD;AAED,iEAAiE;AACjE,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,IAAI,CAGtD"}
|
package/dist/shared/entry.js
CHANGED
|
@@ -39,7 +39,18 @@ function getFieldProps(props) {
|
|
|
39
39
|
...props.className !== void 0 ? { className: props.className } : {}
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
|
+
/** The accepted MIME types of a field that takes files: its `accept`, or its `accept` rule. */
|
|
43
|
+
function getAccept(field) {
|
|
44
|
+
if (field.accept !== void 0 && field.accept.length > 0) return field.accept;
|
|
45
|
+
const rule = findRule(field, "accept");
|
|
46
|
+
return rule !== void 0 && "value" in rule && Array.isArray(rule.value) ? rule.value.filter(isString) : null;
|
|
47
|
+
}
|
|
48
|
+
/** The largest file of a field, in bytes: its `maxSize` rule. */
|
|
49
|
+
function getMaxSize(field) {
|
|
50
|
+
const rule = findRule(field, "maxSize");
|
|
51
|
+
return rule !== void 0 && "value" in rule && isNumber(rule.value) ? rule.value : null;
|
|
52
|
+
}
|
|
42
53
|
//#endregion
|
|
43
|
-
export { findRule, getFieldProps, getRuleNumber, getSetting, isNumber, isRequired, isString };
|
|
54
|
+
export { findRule, getAccept, getFieldProps, getMaxSize, getRuleNumber, getSetting, isNumber, isRequired, isString };
|
|
44
55
|
|
|
45
56
|
//# sourceMappingURL=entry.js.map
|
package/dist/shared/entry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry.js","names":[],"sources":["../../src/shared/entry.ts"],"sourcesContent":["import type { Field, Rule } from '@panneau/protocol';\n\nimport type { FieldEntryProps, FieldProps } from './types';\n\n/** The rule of a field with this name, if any. */\nexport function findRule(field: Field, rule: Rule['rule']): Rule | undefined {\n return field.rules?.find((candidate) => candidate.rule === rule);\n}\n\n/** The number of a `min` or `max` rule of a field, if any. */\nexport function getRuleNumber(field: Field, rule: 'min' | 'max'): number | undefined {\n const found = findRule(field, rule);\n return found !== undefined && 'value' in found && typeof found.value === 'number'\n ? found.value\n : undefined;\n}\n\n/** Whether a field has the `required` rule. */\nexport function isRequired(field: Field): boolean {\n return findRule(field, 'required') !== undefined;\n}\n\n/** A setting of a field (`settings.<name>`), when it has the expected type. */\nexport function getSetting<T>(field: Field, name: string, guard: (value: unknown) => value is T) {\n const value = field.settings?.[name];\n return guard(value) ? value : undefined;\n}\n\nexport const isString = (value: unknown): value is string => typeof value === 'string';\nexport const isNumber = (value: unknown): value is number =>\n typeof value === 'number' && !Number.isNaN(value);\n\n/**\n * The props that every field takes, from a registry entry's props: label (the field's name\n * without one), help, required mark, read-only, errors and handlers. Plugins use it to write their\n * own entries.\n */\nexport function getFieldProps(\n props: FieldEntryProps,\n): Omit<FieldProps<never>, 'value' | 'onChange'> & { placeholder?: string } {\n const { field } = props;\n return {\n name: props.path,\n // A field always has a label: its name when the definition gives none.\n label: field.label ?? field.name,\n description: field.help,\n ...(field.placeholder !== undefined ? { placeholder: field.placeholder } : {}),\n required: isRequired(field),\n readOnly: props.readOnly === true || field.readOnly === true,\n disabled: props.disabled === true,\n errors: props.errors ?? [],\n ...(props.onBlur !== undefined ? { onBlur: props.onBlur } : {}),\n ...(props.className !== undefined ? { className: props.className } : {}),\n };\n}\n\n/** The value as a string, or `null`. */\nexport function asString(value: unknown): string | null {\n return typeof value === 'string' ? value : null;\n}\n"],"mappings":";;AAKA,SAAgB,SAAS,OAAc,MAAsC;CACzE,OAAO,MAAM,OAAO,MAAM,cAAc,UAAU,SAAS,IAAI;AACnE;;AAGA,SAAgB,cAAc,OAAc,MAAyC;CACjF,MAAM,QAAQ,SAAS,OAAO,IAAI;CAClC,OAAO,UAAU,KAAA,KAAa,WAAW,SAAS,OAAO,MAAM,UAAU,WACnE,MAAM,QACN,KAAA;AACV;;AAGA,SAAgB,WAAW,OAAuB;CAC9C,OAAO,SAAS,OAAO,UAAU,MAAM,KAAA;AAC3C;;AAGA,SAAgB,WAAc,OAAc,MAAc,OAAuC;CAC7F,MAAM,QAAQ,MAAM,WAAW;CAC/B,OAAO,MAAM,KAAK,IAAI,QAAQ,KAAA;AAClC;AAEA,IAAa,YAAY,UAAoC,OAAO,UAAU;AAC9E,IAAa,YAAY,UACrB,OAAO,UAAU,YAAY,CAAC,OAAO,MAAM,KAAK;;;;;;AAOpD,SAAgB,cACZ,OACwE;CACxE,MAAM,EAAE,UAAU;CAClB,OAAO;EACH,MAAM,MAAM;EAEZ,OAAO,MAAM,SAAS,MAAM;EAC5B,aAAa,MAAM;EACnB,GAAI,MAAM,gBAAgB,KAAA,IAAY,EAAE,aAAa,MAAM,YAAY,IAAI,CAAC;EAC5E,UAAU,WAAW,KAAK;EAC1B,UAAU,MAAM,aAAa,QAAQ,MAAM,aAAa;EACxD,UAAU,MAAM,aAAa;EAC7B,QAAQ,MAAM,UAAU,CAAA;EACxB,GAAI,MAAM,WAAW,KAAA,IAAY,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;EAC7D,GAAI,MAAM,cAAc,KAAA,IAAY,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;CAC1E;AACJ"}
|
|
1
|
+
{"version":3,"file":"entry.js","names":[],"sources":["../../src/shared/entry.ts"],"sourcesContent":["import type { Field, Rule } from '@panneau/protocol';\n\nimport type { FieldEntryProps, FieldProps } from './types';\n\n/** The rule of a field with this name, if any. */\nexport function findRule(field: Field, rule: Rule['rule']): Rule | undefined {\n return field.rules?.find((candidate) => candidate.rule === rule);\n}\n\n/** The number of a `min` or `max` rule of a field, if any. */\nexport function getRuleNumber(field: Field, rule: 'min' | 'max'): number | undefined {\n const found = findRule(field, rule);\n return found !== undefined && 'value' in found && typeof found.value === 'number'\n ? found.value\n : undefined;\n}\n\n/** Whether a field has the `required` rule. */\nexport function isRequired(field: Field): boolean {\n return findRule(field, 'required') !== undefined;\n}\n\n/** A setting of a field (`settings.<name>`), when it has the expected type. */\nexport function getSetting<T>(field: Field, name: string, guard: (value: unknown) => value is T) {\n const value = field.settings?.[name];\n return guard(value) ? value : undefined;\n}\n\nexport const isString = (value: unknown): value is string => typeof value === 'string';\nexport const isNumber = (value: unknown): value is number =>\n typeof value === 'number' && !Number.isNaN(value);\n\n/**\n * The props that every field takes, from a registry entry's props: label (the field's name\n * without one), help, required mark, read-only, errors and handlers. Plugins use it to write their\n * own entries.\n */\nexport function getFieldProps(\n props: FieldEntryProps,\n): Omit<FieldProps<never>, 'value' | 'onChange'> & { placeholder?: string } {\n const { field } = props;\n return {\n name: props.path,\n // A field always has a label: its name when the definition gives none.\n label: field.label ?? field.name,\n description: field.help,\n ...(field.placeholder !== undefined ? { placeholder: field.placeholder } : {}),\n required: isRequired(field),\n readOnly: props.readOnly === true || field.readOnly === true,\n disabled: props.disabled === true,\n errors: props.errors ?? [],\n ...(props.onBlur !== undefined ? { onBlur: props.onBlur } : {}),\n ...(props.className !== undefined ? { className: props.className } : {}),\n };\n}\n\n/** The value as a string, or `null`. */\nexport function asString(value: unknown): string | null {\n return typeof value === 'string' ? value : null;\n}\n\n/** The accepted MIME types of a field that takes files: its `accept`, or its `accept` rule. */\nexport function getAccept(field: Field): string[] | null {\n if (field.accept !== undefined && field.accept.length > 0) {\n return field.accept;\n }\n const rule = findRule(field, 'accept');\n return rule !== undefined && 'value' in rule && Array.isArray(rule.value)\n ? rule.value.filter(isString)\n : null;\n}\n\n/** The largest file of a field, in bytes: its `maxSize` rule. */\nexport function getMaxSize(field: Field): number | null {\n const rule = findRule(field, 'maxSize');\n return rule !== undefined && 'value' in rule && isNumber(rule.value) ? rule.value : null;\n}\n"],"mappings":";;AAKA,SAAgB,SAAS,OAAc,MAAsC;CACzE,OAAO,MAAM,OAAO,MAAM,cAAc,UAAU,SAAS,IAAI;AACnE;;AAGA,SAAgB,cAAc,OAAc,MAAyC;CACjF,MAAM,QAAQ,SAAS,OAAO,IAAI;CAClC,OAAO,UAAU,KAAA,KAAa,WAAW,SAAS,OAAO,MAAM,UAAU,WACnE,MAAM,QACN,KAAA;AACV;;AAGA,SAAgB,WAAW,OAAuB;CAC9C,OAAO,SAAS,OAAO,UAAU,MAAM,KAAA;AAC3C;;AAGA,SAAgB,WAAc,OAAc,MAAc,OAAuC;CAC7F,MAAM,QAAQ,MAAM,WAAW;CAC/B,OAAO,MAAM,KAAK,IAAI,QAAQ,KAAA;AAClC;AAEA,IAAa,YAAY,UAAoC,OAAO,UAAU;AAC9E,IAAa,YAAY,UACrB,OAAO,UAAU,YAAY,CAAC,OAAO,MAAM,KAAK;;;;;;AAOpD,SAAgB,cACZ,OACwE;CACxE,MAAM,EAAE,UAAU;CAClB,OAAO;EACH,MAAM,MAAM;EAEZ,OAAO,MAAM,SAAS,MAAM;EAC5B,aAAa,MAAM;EACnB,GAAI,MAAM,gBAAgB,KAAA,IAAY,EAAE,aAAa,MAAM,YAAY,IAAI,CAAC;EAC5E,UAAU,WAAW,KAAK;EAC1B,UAAU,MAAM,aAAa,QAAQ,MAAM,aAAa;EACxD,UAAU,MAAM,aAAa;EAC7B,QAAQ,MAAM,UAAU,CAAA;EACxB,GAAI,MAAM,WAAW,KAAA,IAAY,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;EAC7D,GAAI,MAAM,cAAc,KAAA,IAAY,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;CAC1E;AACJ;;AAQA,SAAgB,UAAU,OAA+B;CACrD,IAAI,MAAM,WAAW,KAAA,KAAa,MAAM,OAAO,SAAS,GACpD,OAAO,MAAM;CAEjB,MAAM,OAAO,SAAS,OAAO,QAAQ;CACrC,OAAO,SAAS,KAAA,KAAa,WAAW,QAAQ,MAAM,QAAQ,KAAK,KAAK,IAClE,KAAK,MAAM,OAAO,QAAQ,IAC1B;AACV;;AAGA,SAAgB,WAAW,OAA6B;CACpD,MAAM,OAAO,SAAS,OAAO,SAAS;CACtC,OAAO,SAAS,KAAA,KAAa,WAAW,QAAQ,SAAS,KAAK,KAAK,IAAI,KAAK,QAAQ;AACxF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
.panneau-file-picker-zone {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-wrap: wrap;
|
|
4
|
+
align-items: center;
|
|
5
|
+
gap: var(--panneau-space-2);
|
|
6
|
+
padding: var(--panneau-space-3);
|
|
7
|
+
border: var(--panneau-border-width) dashed var(--panneau-color-border-control);
|
|
8
|
+
border-radius: var(--panneau-radius-md);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.panneau-file-picker-zone[data-drop-target] {
|
|
12
|
+
background-color: var(--panneau-color-accent-subtle);
|
|
13
|
+
border-color: var(--panneau-color-accent);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.panneau-file-picker-zone[data-focus-visible] {
|
|
17
|
+
outline: 2px solid var(--panneau-color-focus);
|
|
18
|
+
outline-offset: 2px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.panneau-file-picker-hint {
|
|
22
|
+
font-size: var(--panneau-font-size-sm);
|
|
23
|
+
color: var(--panneau-color-text-muted);
|
|
24
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface FilePickerProps {
|
|
2
|
+
/** Called with the files chosen or dropped. */
|
|
3
|
+
onSelect: (files: File[]) => void;
|
|
4
|
+
/** Accepted MIME types, which the file dialog offers. */
|
|
5
|
+
accept?: readonly string[] | null;
|
|
6
|
+
multiple?: boolean;
|
|
7
|
+
isDisabled?: boolean;
|
|
8
|
+
/** Text of the button. Defaults to "Choose a file", or "Choose files" with `multiple`. */
|
|
9
|
+
label?: string;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
/** A button that opens the file dialog, in a zone where files can be dropped. */
|
|
13
|
+
export declare function FilePicker({ onSelect, accept, multiple, isDisabled, label, className, }: FilePickerProps): import("react").JSX.Element;
|
|
14
|
+
//# sourceMappingURL=FilePicker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FilePicker.d.ts","sourceRoot":"","sources":["../../src/upload/FilePicker.tsx"],"names":[],"mappings":"AASA,MAAM,WAAW,eAAe;IAC5B,+CAA+C;IAC/C,QAAQ,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;IAClC,yDAAyD;IACzD,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,0FAA0F;IAC1F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AASD,iFAAiF;AACjF,wBAAgB,UAAU,CAAC,EACvB,QAAQ,EACR,MAAM,EACN,QAAgB,EAChB,UAAkB,EAClB,KAAK,EACL,SAAS,GACZ,EAAE,eAAe,+BAmCjB"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { cx } from "../shared/cx.js";
|
|
2
|
+
import { messages } from "../shared/messages.js";
|
|
3
|
+
import FilePicker_module_default from "./FilePicker.module.js";
|
|
4
|
+
import { Button, usePanneauIntl } from "@panneau/ui";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { Upload } from "lucide-react";
|
|
7
|
+
import { DropZone, FileTrigger } from "react-aria-components";
|
|
8
|
+
//#region src/upload/FilePicker.tsx
|
|
9
|
+
async function readDrop(items) {
|
|
10
|
+
return (await Promise.all(items.map((item) => item.kind === "file" ? item.getFile() : Promise.resolve(null)))).filter((file) => file !== null);
|
|
11
|
+
}
|
|
12
|
+
/** A button that opens the file dialog, in a zone where files can be dropped. */
|
|
13
|
+
function FilePicker({ onSelect, accept, multiple = false, isDisabled = false, label, className }) {
|
|
14
|
+
const intl = usePanneauIntl();
|
|
15
|
+
return /* @__PURE__ */ jsxs(DropZone, {
|
|
16
|
+
className: cx(FilePicker_module_default.zone, className),
|
|
17
|
+
"aria-label": intl.formatMessage(messages.dropZone),
|
|
18
|
+
isDisabled,
|
|
19
|
+
onDrop: (event) => {
|
|
20
|
+
readDrop(event.items).then((files) => {
|
|
21
|
+
if (files.length > 0) onSelect(multiple ? files : files.slice(0, 1));
|
|
22
|
+
});
|
|
23
|
+
},
|
|
24
|
+
children: [/* @__PURE__ */ jsx(FileTrigger, {
|
|
25
|
+
...accept !== null && accept !== void 0 && accept.length > 0 ? { acceptedFileTypes: accept } : {},
|
|
26
|
+
allowsMultiple: multiple,
|
|
27
|
+
onSelect: (list) => {
|
|
28
|
+
const files_0 = list === null ? [] : [...list];
|
|
29
|
+
if (files_0.length > 0) onSelect(files_0);
|
|
30
|
+
},
|
|
31
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
32
|
+
size: "sm",
|
|
33
|
+
appearance: "outline",
|
|
34
|
+
icon: Upload,
|
|
35
|
+
isDisabled,
|
|
36
|
+
children: label ?? intl.formatMessage(multiple ? messages.chooseFiles : messages.chooseFile)
|
|
37
|
+
})
|
|
38
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
39
|
+
className: FilePicker_module_default.hint,
|
|
40
|
+
children: intl.formatMessage(messages.dropHere)
|
|
41
|
+
})]
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { FilePicker };
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=FilePicker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FilePicker.js","names":["files","styles"],"sources":["../../src/upload/FilePicker.tsx"],"sourcesContent":["import { Upload } from 'lucide-react';\nimport { type DropItem, DropZone, FileTrigger } from 'react-aria-components';\n\nimport { Button, usePanneauIntl } from '@panneau/ui';\n\nimport { cx } from '../shared/cx';\nimport { messages } from '../shared/messages';\nimport styles from './FilePicker.module.css';\n\nexport interface FilePickerProps {\n /** Called with the files chosen or dropped. */\n onSelect: (files: File[]) => void;\n /** Accepted MIME types, which the file dialog offers. */\n accept?: readonly string[] | null;\n multiple?: boolean;\n isDisabled?: boolean;\n /** Text of the button. Defaults to \"Choose a file\", or \"Choose files\" with `multiple`. */\n label?: string;\n className?: string;\n}\n\nasync function readDrop(items: DropItem[]): Promise<File[]> {\n const files = await Promise.all(\n items.map((item) => (item.kind === 'file' ? item.getFile() : Promise.resolve(null))),\n );\n return files.filter((file): file is File => file !== null);\n}\n\n/** A button that opens the file dialog, in a zone where files can be dropped. */\nexport function FilePicker({\n onSelect,\n accept,\n multiple = false,\n isDisabled = false,\n label,\n className,\n}: FilePickerProps) {\n const intl = usePanneauIntl();\n return (\n <DropZone\n className={cx(styles.zone, className)}\n aria-label={intl.formatMessage(messages.dropZone)}\n isDisabled={isDisabled}\n onDrop={(event) => {\n void readDrop(event.items).then((files) => {\n if (files.length > 0) {\n onSelect(multiple ? files : files.slice(0, 1));\n }\n });\n }}\n >\n <FileTrigger\n {...(accept !== null && accept !== undefined && accept.length > 0\n ? { acceptedFileTypes: accept }\n : {})}\n allowsMultiple={multiple}\n onSelect={(list) => {\n const files = list === null ? [] : [...list];\n if (files.length > 0) {\n onSelect(files);\n }\n }}\n >\n <Button size=\"sm\" appearance=\"outline\" icon={Upload} isDisabled={isDisabled}>\n {label ??\n intl.formatMessage(multiple ? messages.chooseFiles : messages.chooseFile)}\n </Button>\n </FileTrigger>\n <span className={styles.hint}>{intl.formatMessage(messages.dropHere)}</span>\n </DropZone>\n );\n}\n"],"mappings":";;;;;;;;AAqBA,eAAe,SAAS,OAAoC;CAIxD,QAAO,MAHa,QAAQ,IACxB,MAAM,KAAK,SAAU,KAAK,SAAS,SAAS,KAAK,QAAQ,IAAI,QAAQ,QAAQ,IAAI,CAAE,CACvF,EAAA,CACa,QAAQ,SAAuB,SAAS,IAAI;AAC7D;;AAGA,SAAgB,WAAW,EACvB,UACA,QACA,WAAW,OACX,aAAa,OACb,OACA,aACgB;CAChB,MAAM,OAAO,eAAe;CAC5B,OACI,qBAAC,UAAD;EACI,WAAW,GAAGC,0BAAO,MAAM,SAAS;EACpC,cAAY,KAAK,cAAc,SAAS,QAAQ;EACpC;EACZ,SAAS,UAAU;GACf,SAAc,MAAM,KAAK,CAAC,CAAC,MAAM,UAAU;IACvC,IAAI,MAAM,SAAS,GACf,SAAS,WAAW,QAAQ,MAAM,MAAM,GAAG,CAAC,CAAC;GAErD,CAAC;EACL;EAVJ,UAAA,CAYI,oBAAC,aAAD;GACI,GAAK,WAAW,QAAQ,WAAW,KAAA,KAAa,OAAO,SAAS,IAC1D,EAAE,mBAAmB,OAAO,IAC5B,CAAC;GACP,gBAAgB;GAChB,WAAW,SAAS;IAChB,MAAMD,UAAQ,SAAS,OAAO,CAAA,IAAK,CAAC,GAAG,IAAI;IAC3C,IAAIA,QAAM,SAAS,GACf,SAASA,OAAK;GAEtB;GAEA,UAAA,oBAAC,QAAD;IAAQ,MAAK;IAAK,YAAW;IAAU,MAAM;IAAoB;IAC5D,UAAA,SACG,KAAK,cAAc,WAAW,SAAS,cAAc,SAAS,UAAU;GACxE,CAAA;EACC,CAAA,GACb,oBAAC,QAAD;GAAM,WAAWC,0BAAO;GAAO,UAAA,KAAK,cAAc,SAAS,QAAQ;EAAQ,CAAA,CACrE;;AAElB"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import "./FilePicker.css";
|
|
2
|
+
//#region src/upload/FilePicker.module.css
|
|
3
|
+
var zone = "panneau-file-picker-zone";
|
|
4
|
+
var hint = "panneau-file-picker-hint";
|
|
5
|
+
var FilePicker_module_default = {
|
|
6
|
+
zone,
|
|
7
|
+
hint
|
|
8
|
+
};
|
|
9
|
+
//#endregion
|
|
10
|
+
export { FilePicker_module_default as default, hint, zone };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=FilePicker.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FilePicker.module.js","names":[],"sources":["../../src/upload/FilePicker.module.css"],"sourcesContent":[".zone {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--panneau-space-2);\n padding: var(--panneau-space-3);\n border: var(--panneau-border-width) dashed var(--panneau-color-border-control);\n border-radius: var(--panneau-radius-md);\n}\n\n.zone[data-drop-target] {\n background-color: var(--panneau-color-accent-subtle);\n border-color: var(--panneau-color-accent);\n}\n\n.zone[data-focus-visible] {\n outline: 2px solid var(--panneau-color-focus);\n outline-offset: 2px;\n}\n\n.hint {\n font-size: var(--panneau-font-size-sm);\n color: var(--panneau-color-text-muted);\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
.panneau-upload-list-list {
|
|
2
|
+
display: grid;
|
|
3
|
+
gap: var(--panneau-space-2);
|
|
4
|
+
margin: 0;
|
|
5
|
+
padding: 0;
|
|
6
|
+
list-style: none;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.panneau-upload-list-item {
|
|
10
|
+
display: grid;
|
|
11
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
12
|
+
align-items: center;
|
|
13
|
+
gap: var(--panneau-space-1) var(--panneau-space-2);
|
|
14
|
+
padding: var(--panneau-space-2) var(--panneau-space-3);
|
|
15
|
+
background-color: var(--panneau-color-surface-sunken);
|
|
16
|
+
border: var(--panneau-border-width) solid var(--panneau-color-border);
|
|
17
|
+
border-radius: var(--panneau-radius-md);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.panneau-upload-list-failed {
|
|
21
|
+
border-color: var(--panneau-color-danger-border);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.panneau-upload-list-name {
|
|
25
|
+
overflow: hidden;
|
|
26
|
+
font-size: var(--panneau-font-size-sm);
|
|
27
|
+
font-weight: var(--panneau-font-weight-medium);
|
|
28
|
+
text-overflow: ellipsis;
|
|
29
|
+
white-space: nowrap;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.panneau-upload-list-buttons {
|
|
33
|
+
display: flex;
|
|
34
|
+
gap: var(--panneau-space-1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.panneau-upload-list-progress {
|
|
38
|
+
grid-column: 1 / -1;
|
|
39
|
+
display: grid;
|
|
40
|
+
gap: var(--panneau-space-1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.panneau-upload-list-status {
|
|
44
|
+
font-size: var(--panneau-font-size-sm);
|
|
45
|
+
color: var(--panneau-color-text-muted);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.panneau-upload-list-error {
|
|
49
|
+
grid-column: 1 / -1;
|
|
50
|
+
font-size: var(--panneau-font-size-sm);
|
|
51
|
+
color: var(--panneau-color-danger);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.panneau-upload-list-track {
|
|
55
|
+
height: 0.375rem;
|
|
56
|
+
overflow: hidden;
|
|
57
|
+
background: var(--panneau-color-surface);
|
|
58
|
+
border-radius: var(--panneau-radius-full);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.panneau-upload-list-fill {
|
|
62
|
+
display: block;
|
|
63
|
+
height: 100%;
|
|
64
|
+
background: var(--panneau-color-accent);
|
|
65
|
+
border-radius: inherit;
|
|
66
|
+
transition: width var(--panneau-duration) ease-out;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.panneau-upload-list-indeterminate .panneau-upload-list-fill {
|
|
70
|
+
width: 30%;
|
|
71
|
+
animation: panneau-upload-list-slide 1.2s ease-in-out infinite;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@keyframes panneau-upload-list-slide {
|
|
75
|
+
from {
|
|
76
|
+
transform: translateX(-100%);
|
|
77
|
+
}
|
|
78
|
+
to {
|
|
79
|
+
transform: translateX(340%);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@media (prefers-reduced-motion: reduce) {
|
|
84
|
+
.panneau-upload-list-fill {
|
|
85
|
+
transition: none;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.panneau-upload-list-indeterminate .panneau-upload-list-fill {
|
|
89
|
+
width: 100%;
|
|
90
|
+
animation: none;
|
|
91
|
+
opacity: 0.5;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { UploadItem } from './types';
|
|
2
|
+
export interface UploadListProps {
|
|
3
|
+
/** The files being uploaded, from `useUploads()`. */
|
|
4
|
+
items: readonly UploadItem[];
|
|
5
|
+
onPause?: (id: string) => void;
|
|
6
|
+
onResume?: (id: string) => void;
|
|
7
|
+
onCancel?: (id: string) => void;
|
|
8
|
+
onRetry?: (id: string) => void;
|
|
9
|
+
/** Accessible name of the list. Defaults to "Uploads". */
|
|
10
|
+
'aria-label'?: string;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The files being uploaded: a progress bar for each, and buttons to pause and resume a file sent
|
|
15
|
+
* in parts, to cancel it, and to retry it when it failed. Renders nothing without files.
|
|
16
|
+
*/
|
|
17
|
+
export declare function UploadList({ items, onPause, onResume, onCancel, onRetry, 'aria-label': ariaLabel, className, }: UploadListProps): import("react").JSX.Element | null;
|
|
18
|
+
//# sourceMappingURL=UploadList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UploadList.d.ts","sourceRoot":"","sources":["../../src/upload/UploadList.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,MAAM,WAAW,eAAe;IAC5B,qDAAqD;IACrD,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;IAC7B,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EACvB,KAAK,EACL,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,YAAY,EAAE,SAAS,EACvB,SAAS,GACZ,EAAE,eAAe,sCAsGjB"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { cx } from "../shared/cx.js";
|
|
2
|
+
import { messages } from "../shared/messages.js";
|
|
3
|
+
import UploadList_module_default from "./UploadList.module.js";
|
|
4
|
+
import { formatSize } from "./files.js";
|
|
5
|
+
import { c } from "react/compiler-runtime";
|
|
6
|
+
import { IconButton, usePanneauIntl } from "@panneau/ui";
|
|
7
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { Pause, Play, RotateCcw, X } from "lucide-react";
|
|
9
|
+
import { ProgressBar } from "react-aria-components";
|
|
10
|
+
//#region src/upload/UploadList.tsx
|
|
11
|
+
/**
|
|
12
|
+
* The files being uploaded: a progress bar for each, and buttons to pause and resume a file sent
|
|
13
|
+
* in parts, to cancel it, and to retry it when it failed. Renders nothing without files.
|
|
14
|
+
*/
|
|
15
|
+
function UploadList(t0) {
|
|
16
|
+
const $ = c(22);
|
|
17
|
+
const { items, onPause, onResume, onCancel, onRetry, "aria-label": ariaLabel, className } = t0;
|
|
18
|
+
const intl = usePanneauIntl();
|
|
19
|
+
if (items.length === 0) return null;
|
|
20
|
+
let t1;
|
|
21
|
+
if ($[0] !== className) {
|
|
22
|
+
t1 = cx(UploadList_module_default.list, className);
|
|
23
|
+
$[0] = className;
|
|
24
|
+
$[1] = t1;
|
|
25
|
+
} else t1 = $[1];
|
|
26
|
+
let t2;
|
|
27
|
+
if ($[2] !== ariaLabel || $[3] !== intl) {
|
|
28
|
+
t2 = ariaLabel ?? intl.formatMessage(messages.uploads);
|
|
29
|
+
$[2] = ariaLabel;
|
|
30
|
+
$[3] = intl;
|
|
31
|
+
$[4] = t2;
|
|
32
|
+
} else t2 = $[4];
|
|
33
|
+
let t3;
|
|
34
|
+
if ($[5] !== intl || $[6] !== items || $[7] !== onCancel || $[8] !== onPause || $[9] !== onResume || $[10] !== onRetry) {
|
|
35
|
+
let t4;
|
|
36
|
+
if ($[12] !== intl || $[13] !== onCancel || $[14] !== onPause || $[15] !== onResume || $[16] !== onRetry) {
|
|
37
|
+
t4 = (item) => {
|
|
38
|
+
const { name } = item;
|
|
39
|
+
const failed = item.status === "failed";
|
|
40
|
+
const indeterminate = item.progress === null || item.status === "completing";
|
|
41
|
+
const status = {
|
|
42
|
+
uploading: intl.formatMessage(messages.uploading),
|
|
43
|
+
paused: intl.formatMessage(messages.uploadPaused),
|
|
44
|
+
completing: intl.formatMessage(messages.uploadCompleting),
|
|
45
|
+
failed: intl.formatMessage(messages.uploadFailed, { error: item.error ?? "" })
|
|
46
|
+
}[item.status];
|
|
47
|
+
const percent = item.progress === null ? null : Math.round(item.progress * 100);
|
|
48
|
+
return /* @__PURE__ */ jsxs("li", {
|
|
49
|
+
className: cx(UploadList_module_default.item, failed && UploadList_module_default.failed),
|
|
50
|
+
children: [
|
|
51
|
+
/* @__PURE__ */ jsxs("span", {
|
|
52
|
+
className: UploadList_module_default.name,
|
|
53
|
+
children: [name, item.size !== null ? ` · ${formatSize(item.size, intl.locale)}` : null]
|
|
54
|
+
}),
|
|
55
|
+
/* @__PURE__ */ jsxs("span", {
|
|
56
|
+
className: UploadList_module_default.buttons,
|
|
57
|
+
children: [
|
|
58
|
+
item.canPause && item.status === "uploading" && onPause ? /* @__PURE__ */ jsx(IconButton, {
|
|
59
|
+
icon: Pause,
|
|
60
|
+
size: "sm",
|
|
61
|
+
label: intl.formatMessage(messages.pauseUpload, { name }),
|
|
62
|
+
onPress: () => onPause(item.id)
|
|
63
|
+
}) : null,
|
|
64
|
+
item.status === "paused" && onResume ? /* @__PURE__ */ jsx(IconButton, {
|
|
65
|
+
icon: Play,
|
|
66
|
+
size: "sm",
|
|
67
|
+
label: intl.formatMessage(messages.resumeUpload, { name }),
|
|
68
|
+
onPress: () => onResume(item.id)
|
|
69
|
+
}) : null,
|
|
70
|
+
failed && onRetry ? /* @__PURE__ */ jsx(IconButton, {
|
|
71
|
+
icon: RotateCcw,
|
|
72
|
+
size: "sm",
|
|
73
|
+
label: intl.formatMessage(messages.retryUpload, { name }),
|
|
74
|
+
onPress: () => onRetry(item.id)
|
|
75
|
+
}) : null,
|
|
76
|
+
item.status !== "completing" && onCancel ? /* @__PURE__ */ jsx(IconButton, {
|
|
77
|
+
icon: X,
|
|
78
|
+
size: "sm",
|
|
79
|
+
label: intl.formatMessage(messages.cancelUpload, { name }),
|
|
80
|
+
onPress: () => onCancel(item.id)
|
|
81
|
+
}) : null
|
|
82
|
+
]
|
|
83
|
+
}),
|
|
84
|
+
failed ? /* @__PURE__ */ jsx("span", {
|
|
85
|
+
className: UploadList_module_default.error,
|
|
86
|
+
role: "alert",
|
|
87
|
+
children: status
|
|
88
|
+
}) : /* @__PURE__ */ jsx(ProgressBar, {
|
|
89
|
+
"aria-label": name,
|
|
90
|
+
className: cx(UploadList_module_default.progress, indeterminate && UploadList_module_default.indeterminate),
|
|
91
|
+
value: percent ?? 0,
|
|
92
|
+
isIndeterminate: indeterminate,
|
|
93
|
+
valueLabel: item.progress !== null && !indeterminate ? `${status} · ${intl.formatNumber(item.progress, { style: "percent" })}` : status,
|
|
94
|
+
children: (t5) => {
|
|
95
|
+
const { valueText } = t5;
|
|
96
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
97
|
+
className: UploadList_module_default.status,
|
|
98
|
+
children: valueText
|
|
99
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
100
|
+
className: UploadList_module_default.track,
|
|
101
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
102
|
+
className: UploadList_module_default.fill,
|
|
103
|
+
style: indeterminate ? void 0 : { width: `${String(percent ?? 0)}%` }
|
|
104
|
+
})
|
|
105
|
+
})] });
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
]
|
|
109
|
+
}, item.id);
|
|
110
|
+
};
|
|
111
|
+
$[12] = intl;
|
|
112
|
+
$[13] = onCancel;
|
|
113
|
+
$[14] = onPause;
|
|
114
|
+
$[15] = onResume;
|
|
115
|
+
$[16] = onRetry;
|
|
116
|
+
$[17] = t4;
|
|
117
|
+
} else t4 = $[17];
|
|
118
|
+
t3 = items.map(t4);
|
|
119
|
+
$[5] = intl;
|
|
120
|
+
$[6] = items;
|
|
121
|
+
$[7] = onCancel;
|
|
122
|
+
$[8] = onPause;
|
|
123
|
+
$[9] = onResume;
|
|
124
|
+
$[10] = onRetry;
|
|
125
|
+
$[11] = t3;
|
|
126
|
+
} else t3 = $[11];
|
|
127
|
+
let t4;
|
|
128
|
+
if ($[18] !== t1 || $[19] !== t2 || $[20] !== t3) {
|
|
129
|
+
t4 = /* @__PURE__ */ jsx("ul", {
|
|
130
|
+
className: t1,
|
|
131
|
+
"aria-label": t2,
|
|
132
|
+
children: t3
|
|
133
|
+
});
|
|
134
|
+
$[18] = t1;
|
|
135
|
+
$[19] = t2;
|
|
136
|
+
$[20] = t3;
|
|
137
|
+
$[21] = t4;
|
|
138
|
+
} else t4 = $[21];
|
|
139
|
+
return t4;
|
|
140
|
+
}
|
|
141
|
+
//#endregion
|
|
142
|
+
export { UploadList };
|
|
143
|
+
|
|
144
|
+
//# sourceMappingURL=UploadList.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UploadList.js","names":["name","Pause","Play","RotateCcw","X","status","indeterminate","valueText","_c","styles","_Fragment"],"sources":["../../src/upload/UploadList.tsx"],"sourcesContent":["import { Pause, Play, RotateCcw, X } from 'lucide-react';\nimport { ProgressBar } from 'react-aria-components';\n\nimport { IconButton, usePanneauIntl } from '@panneau/ui';\n\nimport { cx } from '../shared/cx';\nimport { messages } from '../shared/messages';\nimport styles from './UploadList.module.css';\nimport { formatSize } from './files';\nimport type { UploadItem } from './types';\n\nexport interface UploadListProps {\n /** The files being uploaded, from `useUploads()`. */\n items: readonly UploadItem[];\n onPause?: (id: string) => void;\n onResume?: (id: string) => void;\n onCancel?: (id: string) => void;\n onRetry?: (id: string) => void;\n /** Accessible name of the list. Defaults to \"Uploads\". */\n 'aria-label'?: string;\n className?: string;\n}\n\n/**\n * The files being uploaded: a progress bar for each, and buttons to pause and resume a file sent\n * in parts, to cancel it, and to retry it when it failed. Renders nothing without files.\n */\nexport function UploadList({\n items,\n onPause,\n onResume,\n onCancel,\n onRetry,\n 'aria-label': ariaLabel,\n className,\n}: UploadListProps) {\n const intl = usePanneauIntl();\n if (items.length === 0) {\n return null;\n }\n return (\n <ul\n className={cx(styles.list, className)}\n aria-label={ariaLabel ?? intl.formatMessage(messages.uploads)}\n >\n {items.map((item) => {\n const { name } = item;\n const failed = item.status === 'failed';\n const indeterminate = item.progress === null || item.status === 'completing';\n const status = {\n uploading: intl.formatMessage(messages.uploading),\n paused: intl.formatMessage(messages.uploadPaused),\n completing: intl.formatMessage(messages.uploadCompleting),\n failed: intl.formatMessage(messages.uploadFailed, { error: item.error ?? '' }),\n }[item.status];\n const percent = item.progress === null ? null : Math.round(item.progress * 100);\n return (\n <li key={item.id} className={cx(styles.item, failed && styles.failed)}>\n <span className={styles.name}>\n {name}\n {item.size !== null ? ` · ${formatSize(item.size, intl.locale)}` : null}\n </span>\n <span className={styles.buttons}>\n {item.canPause && item.status === 'uploading' && onPause ? (\n <IconButton\n icon={Pause}\n size=\"sm\"\n label={intl.formatMessage(messages.pauseUpload, { name })}\n onPress={() => onPause(item.id)}\n />\n ) : null}\n {item.status === 'paused' && onResume ? (\n <IconButton\n icon={Play}\n size=\"sm\"\n label={intl.formatMessage(messages.resumeUpload, { name })}\n onPress={() => onResume(item.id)}\n />\n ) : null}\n {failed && onRetry ? (\n <IconButton\n icon={RotateCcw}\n size=\"sm\"\n label={intl.formatMessage(messages.retryUpload, { name })}\n onPress={() => onRetry(item.id)}\n />\n ) : null}\n {item.status !== 'completing' && onCancel ? (\n <IconButton\n icon={X}\n size=\"sm\"\n label={intl.formatMessage(messages.cancelUpload, { name })}\n onPress={() => onCancel(item.id)}\n />\n ) : null}\n </span>\n {failed ? (\n <span className={styles.error} role=\"alert\">\n {status}\n </span>\n ) : (\n <ProgressBar\n aria-label={name}\n className={cx(\n styles.progress,\n indeterminate && styles.indeterminate,\n )}\n value={percent ?? 0}\n isIndeterminate={indeterminate}\n valueLabel={\n item.progress !== null && !indeterminate\n ? `${status} · ${intl.formatNumber(item.progress, { style: 'percent' })}`\n : status\n }\n >\n {({ valueText }) => (\n <>\n <span className={styles.status}>{valueText}</span>\n <span className={styles.track}>\n <span\n className={styles.fill}\n style={\n indeterminate\n ? undefined\n : { width: `${String(percent ?? 0)}%` }\n }\n />\n </span>\n </>\n )}\n </ProgressBar>\n )}\n </li>\n );\n })}\n </ul>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import "./UploadList.css";
|
|
2
|
+
//#region src/upload/UploadList.module.css
|
|
3
|
+
var list = "panneau-upload-list-list";
|
|
4
|
+
var item = "panneau-upload-list-item";
|
|
5
|
+
var failed = "panneau-upload-list-failed";
|
|
6
|
+
var name = "panneau-upload-list-name";
|
|
7
|
+
var buttons = "panneau-upload-list-buttons";
|
|
8
|
+
var progress = "panneau-upload-list-progress";
|
|
9
|
+
var status = "panneau-upload-list-status";
|
|
10
|
+
var error = "panneau-upload-list-error";
|
|
11
|
+
var track = "panneau-upload-list-track";
|
|
12
|
+
var fill = "panneau-upload-list-fill";
|
|
13
|
+
var indeterminate = "panneau-upload-list-indeterminate";
|
|
14
|
+
var slide = "panneau-upload-list-slide";
|
|
15
|
+
var UploadList_module_default = {
|
|
16
|
+
list,
|
|
17
|
+
item,
|
|
18
|
+
failed,
|
|
19
|
+
name,
|
|
20
|
+
buttons,
|
|
21
|
+
progress,
|
|
22
|
+
status,
|
|
23
|
+
error,
|
|
24
|
+
track,
|
|
25
|
+
fill,
|
|
26
|
+
indeterminate,
|
|
27
|
+
slide
|
|
28
|
+
};
|
|
29
|
+
//#endregion
|
|
30
|
+
export { buttons, UploadList_module_default as default, error, failed, fill, indeterminate, item, list, name, progress, slide, status, track };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=UploadList.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UploadList.module.js","names":[],"sources":["../../src/upload/UploadList.module.css"],"sourcesContent":[".list {\n display: grid;\n gap: var(--panneau-space-2);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.item {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n align-items: center;\n gap: var(--panneau-space-1) var(--panneau-space-2);\n padding: var(--panneau-space-2) var(--panneau-space-3);\n background-color: var(--panneau-color-surface-sunken);\n border: var(--panneau-border-width) solid var(--panneau-color-border);\n border-radius: var(--panneau-radius-md);\n}\n\n.failed {\n border-color: var(--panneau-color-danger-border);\n}\n\n.name {\n overflow: hidden;\n font-size: var(--panneau-font-size-sm);\n font-weight: var(--panneau-font-weight-medium);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.buttons {\n display: flex;\n gap: var(--panneau-space-1);\n}\n\n.progress {\n grid-column: 1 / -1;\n display: grid;\n gap: var(--panneau-space-1);\n}\n\n.status {\n font-size: var(--panneau-font-size-sm);\n color: var(--panneau-color-text-muted);\n}\n\n.error {\n grid-column: 1 / -1;\n font-size: var(--panneau-font-size-sm);\n color: var(--panneau-color-danger);\n}\n\n.track {\n height: 0.375rem;\n overflow: hidden;\n background: var(--panneau-color-surface);\n border-radius: var(--panneau-radius-full);\n}\n\n.fill {\n display: block;\n height: 100%;\n background: var(--panneau-color-accent);\n border-radius: inherit;\n transition: width var(--panneau-duration) ease-out;\n}\n\n.indeterminate .fill {\n width: 30%;\n animation: slide 1.2s ease-in-out infinite;\n}\n\n@keyframes slide {\n from {\n transform: translateX(-100%);\n }\n to {\n transform: translateX(340%);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .fill {\n transition: none;\n }\n\n .indeterminate .fill {\n width: 100%;\n animation: none;\n opacity: 0.5;\n }\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Whether a MIME type matches one of the patterns of an `accept` rule (`image/*`, `application/pdf`). */
|
|
2
|
+
export declare function matchesMime(mime: string, patterns: readonly string[]): boolean;
|
|
3
|
+
/** A size in bytes, for people: `1.5 MB`. Uses the locale's number format. */
|
|
4
|
+
export declare function formatSize(bytes: number, locale?: string): string;
|
|
5
|
+
//# sourceMappingURL=files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/upload/files.ts"],"names":[],"mappings":"AAAA,0GAA0G;AAC1G,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAI9E;AAID,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAWjE"}
|