@anvilkit/plugin-asset-manager 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +159 -0
- package/dist/adapters/data-url.cjs +78 -0
- package/dist/adapters/data-url.d.cts +6 -0
- package/dist/adapters/data-url.d.cts.map +1 -0
- package/dist/adapters/data-url.d.ts +6 -0
- package/dist/adapters/data-url.d.ts.map +1 -0
- package/dist/adapters/data-url.js +44 -0
- package/dist/adapters/extract-image-dimensions.cjs +69 -0
- package/dist/adapters/extract-image-dimensions.d.cts +21 -0
- package/dist/adapters/extract-image-dimensions.d.cts.map +1 -0
- package/dist/adapters/extract-image-dimensions.d.ts +21 -0
- package/dist/adapters/extract-image-dimensions.d.ts.map +1 -0
- package/dist/adapters/extract-image-dimensions.js +35 -0
- package/dist/adapters/in-memory.cjs +62 -0
- package/dist/adapters/in-memory.d.cts +3 -0
- package/dist/adapters/in-memory.d.cts.map +1 -0
- package/dist/adapters/in-memory.d.ts +3 -0
- package/dist/adapters/in-memory.d.ts.map +1 -0
- package/dist/adapters/in-memory.js +28 -0
- package/dist/adapters/s3-presigned.cjs +166 -0
- package/dist/adapters/s3-presigned.d.cts +59 -0
- package/dist/adapters/s3-presigned.d.cts.map +1 -0
- package/dist/adapters/s3-presigned.d.ts +59 -0
- package/dist/adapters/s3-presigned.d.ts.map +1 -0
- package/dist/adapters/s3-presigned.js +129 -0
- package/dist/asset-reference.cjs +38 -0
- package/dist/asset-reference.d.cts +10 -0
- package/dist/asset-reference.d.cts.map +1 -0
- package/dist/asset-reference.d.ts +10 -0
- package/dist/asset-reference.d.ts.map +1 -0
- package/dist/asset-reference.js +4 -0
- package/dist/csp.cjs +83 -0
- package/dist/csp.d.cts +45 -0
- package/dist/csp.d.cts.map +1 -0
- package/dist/csp.d.ts +45 -0
- package/dist/csp.d.ts.map +1 -0
- package/dist/csp.js +49 -0
- package/dist/errors.cjs +58 -0
- package/dist/errors.d.cts +15 -0
- package/dist/errors.d.cts.map +1 -0
- package/dist/errors.d.ts +15 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +21 -0
- package/dist/header-action.cjs +44 -0
- package/dist/header-action.d.cts +3 -0
- package/dist/header-action.d.cts.map +1 -0
- package/dist/header-action.d.ts +3 -0
- package/dist/header-action.d.ts.map +1 -0
- package/dist/header-action.js +10 -0
- package/dist/index.cjs +90 -0
- package/dist/index.d.cts +18 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/infer-kind.cjs +45 -0
- package/dist/infer-kind.d.cts +8 -0
- package/dist/infer-kind.d.cts.map +1 -0
- package/dist/infer-kind.d.ts +8 -0
- package/dist/infer-kind.d.ts.map +1 -0
- package/dist/infer-kind.js +11 -0
- package/dist/plugin.cjs +258 -0
- package/dist/plugin.d.cts +9 -0
- package/dist/plugin.d.cts.map +1 -0
- package/dist/plugin.d.ts +9 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +212 -0
- package/dist/registry.cjs +198 -0
- package/dist/registry.d.cts +3 -0
- package/dist/registry.d.cts.map +1 -0
- package/dist/registry.d.ts +3 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +164 -0
- package/dist/resolver.cjs +185 -0
- package/dist/resolver.d.cts +10 -0
- package/dist/resolver.d.cts.map +1 -0
- package/dist/resolver.d.ts +10 -0
- package/dist/resolver.d.ts.map +1 -0
- package/dist/resolver.js +148 -0
- package/dist/retry.cjs +123 -0
- package/dist/retry.d.cts +71 -0
- package/dist/retry.d.cts.map +1 -0
- package/dist/retry.d.ts +71 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +86 -0
- package/dist/studio-asset-source.cjs +211 -0
- package/dist/studio-asset-source.d.cts +52 -0
- package/dist/studio-asset-source.d.cts.map +1 -0
- package/dist/studio-asset-source.d.ts +52 -0
- package/dist/studio-asset-source.d.ts.map +1 -0
- package/dist/studio-asset-source.js +171 -0
- package/dist/testing/index.cjs +66 -0
- package/dist/testing/index.d.cts +24 -0
- package/dist/testing/index.d.cts.map +1 -0
- package/dist/testing/index.d.ts +24 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +29 -0
- package/dist/types.cjs +18 -0
- package/dist/types.d.cts +132 -0
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.ts +132 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +0 -0
- package/dist/ui/AssetBrowser.cjs +271 -0
- package/dist/ui/AssetBrowser.d.cts +45 -0
- package/dist/ui/AssetBrowser.d.cts.map +1 -0
- package/dist/ui/AssetBrowser.d.ts +45 -0
- package/dist/ui/AssetBrowser.d.ts.map +1 -0
- package/dist/ui/AssetBrowser.js +237 -0
- package/dist/ui/AssetCommandPalette.cjs +135 -0
- package/dist/ui/AssetCommandPalette.d.cts +21 -0
- package/dist/ui/AssetCommandPalette.d.cts.map +1 -0
- package/dist/ui/AssetCommandPalette.d.ts +21 -0
- package/dist/ui/AssetCommandPalette.d.ts.map +1 -0
- package/dist/ui/AssetCommandPalette.js +101 -0
- package/dist/ui/AssetManagerUI.cjs +169 -0
- package/dist/ui/AssetManagerUI.d.cts +15 -0
- package/dist/ui/AssetManagerUI.d.cts.map +1 -0
- package/dist/ui/AssetManagerUI.d.ts +15 -0
- package/dist/ui/AssetManagerUI.d.ts.map +1 -0
- package/dist/ui/AssetManagerUI.js +135 -0
- package/dist/ui/DeleteAssetDialog.cjs +70 -0
- package/dist/ui/DeleteAssetDialog.d.cts +22 -0
- package/dist/ui/DeleteAssetDialog.d.cts.map +1 -0
- package/dist/ui/DeleteAssetDialog.d.ts +22 -0
- package/dist/ui/DeleteAssetDialog.d.ts.map +1 -0
- package/dist/ui/DeleteAssetDialog.js +36 -0
- package/dist/ui/MetadataPanel.cjs +147 -0
- package/dist/ui/MetadataPanel.d.cts +21 -0
- package/dist/ui/MetadataPanel.d.cts.map +1 -0
- package/dist/ui/MetadataPanel.d.ts +21 -0
- package/dist/ui/MetadataPanel.d.ts.map +1 -0
- package/dist/ui/MetadataPanel.js +113 -0
- package/dist/ui/ReplaceAssetDialog.cjs +125 -0
- package/dist/ui/ReplaceAssetDialog.d.cts +14 -0
- package/dist/ui/ReplaceAssetDialog.d.cts.map +1 -0
- package/dist/ui/ReplaceAssetDialog.d.ts +14 -0
- package/dist/ui/ReplaceAssetDialog.d.ts.map +1 -0
- package/dist/ui/ReplaceAssetDialog.js +91 -0
- package/dist/ui/UploadButton.cjs +189 -0
- package/dist/ui/UploadButton.d.cts +17 -0
- package/dist/ui/UploadButton.d.cts.map +1 -0
- package/dist/ui/UploadButton.d.ts +17 -0
- package/dist/ui/UploadButton.d.ts.map +1 -0
- package/dist/ui/UploadButton.js +155 -0
- package/dist/ui/index.cjs +60 -0
- package/dist/ui/index.d.cts +15 -0
- package/dist/ui/index.d.cts.map +1 -0
- package/dist/ui/index.d.ts +15 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +7 -0
- package/dist/validate-upload-result.cjs +149 -0
- package/dist/validate-upload-result.d.cts +9 -0
- package/dist/validate-upload-result.d.cts.map +1 -0
- package/dist/validate-upload-result.d.ts +9 -0
- package/dist/validate-upload-result.d.ts.map +1 -0
- package/dist/validate-upload-result.js +115 -0
- package/package.json +131 -0
package/dist/types.d.cts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
export interface AssetMeta {
|
|
2
|
+
readonly size?: number;
|
|
3
|
+
readonly mimeType?: string;
|
|
4
|
+
readonly width?: number;
|
|
5
|
+
readonly height?: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Library-management kind union surfaced by `AssetRegistry.search` and
|
|
9
|
+
* the sidebar filter row. Mirrors `@anvilkit/core/types`'
|
|
10
|
+
* `StudioAssetKind` shape so the same filter values flow through both
|
|
11
|
+
* the headless registry and the Studio surface without translation.
|
|
12
|
+
*/
|
|
13
|
+
export type AssetKind = "image" | "video" | "audio" | "font" | "document" | "other";
|
|
14
|
+
export interface UploadResult {
|
|
15
|
+
readonly url: string;
|
|
16
|
+
readonly id: string;
|
|
17
|
+
/**
|
|
18
|
+
* Optional human-readable name. The plugin's `uploadAsset()` seeds
|
|
19
|
+
* this from the source `File`'s `name` so the sidebar can render a
|
|
20
|
+
* filename under each tile; uploader adapters may also populate it
|
|
21
|
+
* directly when they know a friendlier label.
|
|
22
|
+
*/
|
|
23
|
+
readonly name?: string;
|
|
24
|
+
readonly meta?: AssetMeta;
|
|
25
|
+
/**
|
|
26
|
+
* Optional library tags. The plugin auto-derives a small set on
|
|
27
|
+
* register (kind + filename tokens); hosts may extend or replace via
|
|
28
|
+
* {@link AssetRegistry.setTags} or by attaching `tags` on a
|
|
29
|
+
* host-supplied `UploadResult`. Surfaced to the sidebar through
|
|
30
|
+
* `StudioAsset.tags` and consulted by `AssetRegistry.search`.
|
|
31
|
+
*/
|
|
32
|
+
readonly tags?: readonly string[];
|
|
33
|
+
}
|
|
34
|
+
export type UploadAdapter = (file: File) => Promise<UploadResult>;
|
|
35
|
+
export interface AssetManagerOptions {
|
|
36
|
+
readonly uploader: UploadAdapter;
|
|
37
|
+
readonly maxFileSize?: number;
|
|
38
|
+
readonly acceptedMimeTypes?: readonly string[];
|
|
39
|
+
/**
|
|
40
|
+
* Permit `data:` URLs to flow through the trust boundary. Defaults to
|
|
41
|
+
* `false` — `http`, `https`, and `blob` are always allowed; every
|
|
42
|
+
* other scheme is rejected. The previous `urlAllowlist: ["data"]`
|
|
43
|
+
* pattern is replaced by this typed flag in v1.0.
|
|
44
|
+
*/
|
|
45
|
+
readonly dataUrlAllowlistOptIn?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Permit `http(s)` URLs whose hostname mixes Unicode scripts (e.g.
|
|
48
|
+
* `аpple.com` blending Cyrillic and Latin). Defaults to `false` —
|
|
49
|
+
* mixed-script hostnames are rejected as a homoglyph-attack guard.
|
|
50
|
+
* Single-script IDN hosts (e.g. `münchen.de`, `日本.jp`) are always
|
|
51
|
+
* allowed regardless of this flag.
|
|
52
|
+
*/
|
|
53
|
+
readonly allowMixedScriptHostnames?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Optional thumbnail derivation passed to {@link createStudioAssetSource}.
|
|
56
|
+
* Returning a string sets `StudioAsset.thumbnailUrl`; returning
|
|
57
|
+
* `undefined` suppresses the thumbnail (overriding the default-for-images
|
|
58
|
+
* behavior).
|
|
59
|
+
*/
|
|
60
|
+
readonly getThumbnail?: (entry: UploadResult) => string | undefined;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Listener invoked after every registry mutation
|
|
64
|
+
* (`register` / `delete` / `rename` / `replace` / `setTags`). The
|
|
65
|
+
* `studio-asset-source` adapter wires its own listener set onto the
|
|
66
|
+
* registry so the sidebar re-runs `list()` whenever an asset changes.
|
|
67
|
+
*/
|
|
68
|
+
export type AssetRegistryListener = () => void;
|
|
69
|
+
/**
|
|
70
|
+
* Search and filter options accepted by {@link AssetRegistry.search}.
|
|
71
|
+
*
|
|
72
|
+
* `query` matches case-insensitively against `id`, `name`, `tags`, and
|
|
73
|
+
* the MIME type (prefix match — e.g. `"image"` matches `"image/png"`).
|
|
74
|
+
* Filters compose with AND semantics: an entry must satisfy every
|
|
75
|
+
* supplied filter to land in the page.
|
|
76
|
+
*/
|
|
77
|
+
export interface AssetSearchOptions {
|
|
78
|
+
readonly query?: string;
|
|
79
|
+
readonly kinds?: readonly AssetKind[];
|
|
80
|
+
readonly tags?: readonly string[];
|
|
81
|
+
readonly cursor?: string;
|
|
82
|
+
readonly limit?: number;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Pagination envelope returned by {@link AssetRegistry.search}.
|
|
86
|
+
*
|
|
87
|
+
* - `items` — the slice for the requested page.
|
|
88
|
+
* - `total` — total number of matches across all pages (post-filter).
|
|
89
|
+
* - `nextCursor` — opaque cursor for the next page, or `undefined` when
|
|
90
|
+
* the result set is exhausted.
|
|
91
|
+
*/
|
|
92
|
+
export interface AssetSearchPage {
|
|
93
|
+
readonly items: readonly UploadResult[];
|
|
94
|
+
readonly total: number;
|
|
95
|
+
readonly nextCursor: string | undefined;
|
|
96
|
+
}
|
|
97
|
+
export interface AssetRegistry {
|
|
98
|
+
readonly register: (asset: UploadResult) => UploadResult;
|
|
99
|
+
readonly get: (id: string) => UploadResult | undefined;
|
|
100
|
+
readonly list: () => readonly UploadResult[];
|
|
101
|
+
/** Remove an asset. Returns `true` if an entry was removed. */
|
|
102
|
+
readonly delete: (id: string) => boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Rename an asset in-place. Returns the updated entry, or `undefined`
|
|
105
|
+
* if no asset with that id exists.
|
|
106
|
+
*/
|
|
107
|
+
readonly rename: (id: string, name: string) => UploadResult | undefined;
|
|
108
|
+
/**
|
|
109
|
+
* Replace an asset in-place. Preserves the entry's `id` even if the
|
|
110
|
+
* incoming `next` carries a different one. Returns the updated entry,
|
|
111
|
+
* or `undefined` if no asset with that id exists.
|
|
112
|
+
*/
|
|
113
|
+
readonly replace: (id: string, next: UploadResult) => UploadResult | undefined;
|
|
114
|
+
/**
|
|
115
|
+
* Replace the tag set on an asset in-place. Empty arrays drop the
|
|
116
|
+
* `tags` field entirely. Tags are deduped, trimmed, lowercased, and
|
|
117
|
+
* frozen before storage. Returns the updated entry, or `undefined`
|
|
118
|
+
* if no asset with that id exists.
|
|
119
|
+
*/
|
|
120
|
+
readonly setTags: (id: string, tags: readonly string[]) => UploadResult | undefined;
|
|
121
|
+
/**
|
|
122
|
+
* Search and paginate the registry. See {@link AssetSearchOptions}
|
|
123
|
+
* for filter semantics.
|
|
124
|
+
*/
|
|
125
|
+
readonly search: (options?: AssetSearchOptions) => AssetSearchPage;
|
|
126
|
+
/**
|
|
127
|
+
* Subscribe to mutation notifications. The returned function
|
|
128
|
+
* unsubscribes the listener.
|
|
129
|
+
*/
|
|
130
|
+
readonly subscribe: (listener: AssetRegistryListener) => () => void;
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=types.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.cts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
export interface AssetMeta {
|
|
2
|
+
readonly size?: number;
|
|
3
|
+
readonly mimeType?: string;
|
|
4
|
+
readonly width?: number;
|
|
5
|
+
readonly height?: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Library-management kind union surfaced by `AssetRegistry.search` and
|
|
9
|
+
* the sidebar filter row. Mirrors `@anvilkit/core/types`'
|
|
10
|
+
* `StudioAssetKind` shape so the same filter values flow through both
|
|
11
|
+
* the headless registry and the Studio surface without translation.
|
|
12
|
+
*/
|
|
13
|
+
export type AssetKind = "image" | "video" | "audio" | "font" | "document" | "other";
|
|
14
|
+
export interface UploadResult {
|
|
15
|
+
readonly url: string;
|
|
16
|
+
readonly id: string;
|
|
17
|
+
/**
|
|
18
|
+
* Optional human-readable name. The plugin's `uploadAsset()` seeds
|
|
19
|
+
* this from the source `File`'s `name` so the sidebar can render a
|
|
20
|
+
* filename under each tile; uploader adapters may also populate it
|
|
21
|
+
* directly when they know a friendlier label.
|
|
22
|
+
*/
|
|
23
|
+
readonly name?: string;
|
|
24
|
+
readonly meta?: AssetMeta;
|
|
25
|
+
/**
|
|
26
|
+
* Optional library tags. The plugin auto-derives a small set on
|
|
27
|
+
* register (kind + filename tokens); hosts may extend or replace via
|
|
28
|
+
* {@link AssetRegistry.setTags} or by attaching `tags` on a
|
|
29
|
+
* host-supplied `UploadResult`. Surfaced to the sidebar through
|
|
30
|
+
* `StudioAsset.tags` and consulted by `AssetRegistry.search`.
|
|
31
|
+
*/
|
|
32
|
+
readonly tags?: readonly string[];
|
|
33
|
+
}
|
|
34
|
+
export type UploadAdapter = (file: File) => Promise<UploadResult>;
|
|
35
|
+
export interface AssetManagerOptions {
|
|
36
|
+
readonly uploader: UploadAdapter;
|
|
37
|
+
readonly maxFileSize?: number;
|
|
38
|
+
readonly acceptedMimeTypes?: readonly string[];
|
|
39
|
+
/**
|
|
40
|
+
* Permit `data:` URLs to flow through the trust boundary. Defaults to
|
|
41
|
+
* `false` — `http`, `https`, and `blob` are always allowed; every
|
|
42
|
+
* other scheme is rejected. The previous `urlAllowlist: ["data"]`
|
|
43
|
+
* pattern is replaced by this typed flag in v1.0.
|
|
44
|
+
*/
|
|
45
|
+
readonly dataUrlAllowlistOptIn?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Permit `http(s)` URLs whose hostname mixes Unicode scripts (e.g.
|
|
48
|
+
* `аpple.com` blending Cyrillic and Latin). Defaults to `false` —
|
|
49
|
+
* mixed-script hostnames are rejected as a homoglyph-attack guard.
|
|
50
|
+
* Single-script IDN hosts (e.g. `münchen.de`, `日本.jp`) are always
|
|
51
|
+
* allowed regardless of this flag.
|
|
52
|
+
*/
|
|
53
|
+
readonly allowMixedScriptHostnames?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Optional thumbnail derivation passed to {@link createStudioAssetSource}.
|
|
56
|
+
* Returning a string sets `StudioAsset.thumbnailUrl`; returning
|
|
57
|
+
* `undefined` suppresses the thumbnail (overriding the default-for-images
|
|
58
|
+
* behavior).
|
|
59
|
+
*/
|
|
60
|
+
readonly getThumbnail?: (entry: UploadResult) => string | undefined;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Listener invoked after every registry mutation
|
|
64
|
+
* (`register` / `delete` / `rename` / `replace` / `setTags`). The
|
|
65
|
+
* `studio-asset-source` adapter wires its own listener set onto the
|
|
66
|
+
* registry so the sidebar re-runs `list()` whenever an asset changes.
|
|
67
|
+
*/
|
|
68
|
+
export type AssetRegistryListener = () => void;
|
|
69
|
+
/**
|
|
70
|
+
* Search and filter options accepted by {@link AssetRegistry.search}.
|
|
71
|
+
*
|
|
72
|
+
* `query` matches case-insensitively against `id`, `name`, `tags`, and
|
|
73
|
+
* the MIME type (prefix match — e.g. `"image"` matches `"image/png"`).
|
|
74
|
+
* Filters compose with AND semantics: an entry must satisfy every
|
|
75
|
+
* supplied filter to land in the page.
|
|
76
|
+
*/
|
|
77
|
+
export interface AssetSearchOptions {
|
|
78
|
+
readonly query?: string;
|
|
79
|
+
readonly kinds?: readonly AssetKind[];
|
|
80
|
+
readonly tags?: readonly string[];
|
|
81
|
+
readonly cursor?: string;
|
|
82
|
+
readonly limit?: number;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Pagination envelope returned by {@link AssetRegistry.search}.
|
|
86
|
+
*
|
|
87
|
+
* - `items` — the slice for the requested page.
|
|
88
|
+
* - `total` — total number of matches across all pages (post-filter).
|
|
89
|
+
* - `nextCursor` — opaque cursor for the next page, or `undefined` when
|
|
90
|
+
* the result set is exhausted.
|
|
91
|
+
*/
|
|
92
|
+
export interface AssetSearchPage {
|
|
93
|
+
readonly items: readonly UploadResult[];
|
|
94
|
+
readonly total: number;
|
|
95
|
+
readonly nextCursor: string | undefined;
|
|
96
|
+
}
|
|
97
|
+
export interface AssetRegistry {
|
|
98
|
+
readonly register: (asset: UploadResult) => UploadResult;
|
|
99
|
+
readonly get: (id: string) => UploadResult | undefined;
|
|
100
|
+
readonly list: () => readonly UploadResult[];
|
|
101
|
+
/** Remove an asset. Returns `true` if an entry was removed. */
|
|
102
|
+
readonly delete: (id: string) => boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Rename an asset in-place. Returns the updated entry, or `undefined`
|
|
105
|
+
* if no asset with that id exists.
|
|
106
|
+
*/
|
|
107
|
+
readonly rename: (id: string, name: string) => UploadResult | undefined;
|
|
108
|
+
/**
|
|
109
|
+
* Replace an asset in-place. Preserves the entry's `id` even if the
|
|
110
|
+
* incoming `next` carries a different one. Returns the updated entry,
|
|
111
|
+
* or `undefined` if no asset with that id exists.
|
|
112
|
+
*/
|
|
113
|
+
readonly replace: (id: string, next: UploadResult) => UploadResult | undefined;
|
|
114
|
+
/**
|
|
115
|
+
* Replace the tag set on an asset in-place. Empty arrays drop the
|
|
116
|
+
* `tags` field entirely. Tags are deduped, trimmed, lowercased, and
|
|
117
|
+
* frozen before storage. Returns the updated entry, or `undefined`
|
|
118
|
+
* if no asset with that id exists.
|
|
119
|
+
*/
|
|
120
|
+
readonly setTags: (id: string, tags: readonly string[]) => UploadResult | undefined;
|
|
121
|
+
/**
|
|
122
|
+
* Search and paginate the registry. See {@link AssetSearchOptions}
|
|
123
|
+
* for filter semantics.
|
|
124
|
+
*/
|
|
125
|
+
readonly search: (options?: AssetSearchOptions) => AssetSearchPage;
|
|
126
|
+
/**
|
|
127
|
+
* Subscribe to mutation notifications. The returned function
|
|
128
|
+
* unsubscribes the listener.
|
|
129
|
+
*/
|
|
130
|
+
readonly subscribe: (listener: AssetRegistryListener) => () => void;
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
File without changes
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
AssetBrowser: ()=>AssetBrowser
|
|
28
|
+
});
|
|
29
|
+
const card_namespaceObject = require("@anvilkit/ui/card");
|
|
30
|
+
const input_namespaceObject = require("@anvilkit/ui/input");
|
|
31
|
+
const external_react_namespaceObject = require("react");
|
|
32
|
+
const external_infer_kind_cjs_namespaceObject = require("../infer-kind.cjs");
|
|
33
|
+
const KIND_FILTERS = [
|
|
34
|
+
"image",
|
|
35
|
+
"video",
|
|
36
|
+
"audio",
|
|
37
|
+
"font",
|
|
38
|
+
"document"
|
|
39
|
+
];
|
|
40
|
+
const DEFAULT_VIRTUALIZE_THRESHOLD = 50;
|
|
41
|
+
const DEFAULT_ITEM_HEIGHT = 56;
|
|
42
|
+
const DEFAULT_MAX_HEIGHT = 400;
|
|
43
|
+
const DEFAULT_PAGE_SIZE = 100;
|
|
44
|
+
const OVERSCAN = 4;
|
|
45
|
+
function AssetBrowser({ assets, onInsert, onDelete, onReplace, onEdit, searchEnabled = false, pageSize = DEFAULT_PAGE_SIZE, virtualizeThreshold = DEFAULT_VIRTUALIZE_THRESHOLD, itemHeight = DEFAULT_ITEM_HEIGHT, maxHeight = DEFAULT_MAX_HEIGHT }) {
|
|
46
|
+
const [activeIndex, setActiveIndex] = external_react_namespaceObject.useState(assets.length > 0 ? 0 : -1);
|
|
47
|
+
const [scrollTop, setScrollTop] = external_react_namespaceObject.useState(0);
|
|
48
|
+
const [query, setQuery] = external_react_namespaceObject.useState("");
|
|
49
|
+
const [activeKinds, setActiveKinds] = external_react_namespaceObject.useState([]);
|
|
50
|
+
const [pageLimit, setPageLimit] = external_react_namespaceObject.useState(pageSize);
|
|
51
|
+
const buttonRefs = external_react_namespaceObject.useRef([]);
|
|
52
|
+
const scrollContainerRef = external_react_namespaceObject.useRef(null);
|
|
53
|
+
const filteredAssets = external_react_namespaceObject.useMemo(()=>{
|
|
54
|
+
if (!searchEnabled) return assets;
|
|
55
|
+
const lower = query.trim().toLowerCase();
|
|
56
|
+
return assets.filter((asset)=>{
|
|
57
|
+
if (activeKinds.length > 0) {
|
|
58
|
+
if (!activeKinds.includes((0, external_infer_kind_cjs_namespaceObject.inferAssetKind)(asset))) return false;
|
|
59
|
+
}
|
|
60
|
+
if ("" === lower) return true;
|
|
61
|
+
if (asset.id.toLowerCase().includes(lower)) return true;
|
|
62
|
+
if (asset.name?.toLowerCase().includes(lower)) return true;
|
|
63
|
+
if (asset.meta?.mimeType?.toLowerCase().includes(lower)) return true;
|
|
64
|
+
if (asset.tags?.some((tag)=>tag.toLowerCase().includes(lower))) return true;
|
|
65
|
+
return false;
|
|
66
|
+
});
|
|
67
|
+
}, [
|
|
68
|
+
assets,
|
|
69
|
+
activeKinds,
|
|
70
|
+
query,
|
|
71
|
+
searchEnabled
|
|
72
|
+
]);
|
|
73
|
+
const visibleSlice = external_react_namespaceObject.useMemo(()=>searchEnabled ? filteredAssets.slice(0, pageLimit) : filteredAssets, [
|
|
74
|
+
filteredAssets,
|
|
75
|
+
pageLimit,
|
|
76
|
+
searchEnabled
|
|
77
|
+
]);
|
|
78
|
+
const total = visibleSlice.length;
|
|
79
|
+
const isVirtualized = total > virtualizeThreshold;
|
|
80
|
+
const hasMore = searchEnabled && filteredAssets.length > visibleSlice.length;
|
|
81
|
+
external_react_namespaceObject.useEffect(()=>{
|
|
82
|
+
if (0 === total) return void setActiveIndex(-1);
|
|
83
|
+
setActiveIndex((currentIndex)=>currentIndex >= 0 && currentIndex < total ? currentIndex : 0);
|
|
84
|
+
}, [
|
|
85
|
+
total
|
|
86
|
+
]);
|
|
87
|
+
function moveFocus(nextIndex) {
|
|
88
|
+
if (0 === total) return;
|
|
89
|
+
const clampedIndex = Math.max(0, Math.min(nextIndex, total - 1));
|
|
90
|
+
setActiveIndex(clampedIndex);
|
|
91
|
+
if (isVirtualized && scrollContainerRef.current) {
|
|
92
|
+
const targetTop = clampedIndex * itemHeight;
|
|
93
|
+
const targetBottom = targetTop + itemHeight;
|
|
94
|
+
const viewTop = scrollContainerRef.current.scrollTop;
|
|
95
|
+
const viewBottom = viewTop + maxHeight;
|
|
96
|
+
if (targetTop < viewTop) scrollContainerRef.current.scrollTop = targetTop;
|
|
97
|
+
else if (targetBottom > viewBottom) scrollContainerRef.current.scrollTop = targetBottom - maxHeight;
|
|
98
|
+
queueMicrotask(()=>{
|
|
99
|
+
buttonRefs.current[clampedIndex]?.focus();
|
|
100
|
+
});
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
buttonRefs.current[clampedIndex]?.focus();
|
|
104
|
+
}
|
|
105
|
+
function toggleKind(kind) {
|
|
106
|
+
setActiveKinds((current)=>current.includes(kind) ? current.filter((entry)=>entry !== kind) : [
|
|
107
|
+
...current,
|
|
108
|
+
kind
|
|
109
|
+
]);
|
|
110
|
+
}
|
|
111
|
+
const firstVisible = isVirtualized ? Math.max(0, Math.floor(scrollTop / itemHeight) - OVERSCAN) : 0;
|
|
112
|
+
const lastVisible = isVirtualized ? Math.min(total - 1, Math.ceil((scrollTop + maxHeight) / itemHeight) + OVERSCAN) : total - 1;
|
|
113
|
+
const visibleAssets = 0 === total ? [] : isVirtualized ? visibleSlice.slice(firstVisible, lastVisible + 1) : visibleSlice;
|
|
114
|
+
function renderRow(asset, index) {
|
|
115
|
+
return /*#__PURE__*/ external_react_namespaceObject.createElement("li", {
|
|
116
|
+
"aria-posinset": index + 1,
|
|
117
|
+
"aria-setsize": total,
|
|
118
|
+
key: asset.id,
|
|
119
|
+
role: "listitem"
|
|
120
|
+
}, /*#__PURE__*/ external_react_namespaceObject.createElement("button", {
|
|
121
|
+
"aria-label": `Insert asset ${asset.id}`,
|
|
122
|
+
onClick: ()=>{
|
|
123
|
+
onInsert(asset);
|
|
124
|
+
},
|
|
125
|
+
onFocus: ()=>{
|
|
126
|
+
setActiveIndex(index);
|
|
127
|
+
},
|
|
128
|
+
onKeyDown: (event)=>{
|
|
129
|
+
if ("ArrowDown" === event.key) {
|
|
130
|
+
event.preventDefault();
|
|
131
|
+
moveFocus(index + 1);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if ("ArrowUp" === event.key) {
|
|
135
|
+
event.preventDefault();
|
|
136
|
+
moveFocus(index - 1);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if ("Home" === event.key) {
|
|
140
|
+
event.preventDefault();
|
|
141
|
+
moveFocus(0);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if ("End" === event.key) {
|
|
145
|
+
event.preventDefault();
|
|
146
|
+
moveFocus(total - 1);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if ("Enter" === event.key || " " === event.key) {
|
|
150
|
+
event.preventDefault();
|
|
151
|
+
onInsert(asset);
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
ref: (node)=>{
|
|
155
|
+
buttonRefs.current[index] = node;
|
|
156
|
+
},
|
|
157
|
+
tabIndex: activeIndex === index ? 0 : -1,
|
|
158
|
+
type: "button"
|
|
159
|
+
}, /*#__PURE__*/ external_react_namespaceObject.createElement("span", null, asset.id), /*#__PURE__*/ external_react_namespaceObject.createElement("span", null, asset.meta?.mimeType ?? "unknown type")), void 0 !== onEdit ? /*#__PURE__*/ external_react_namespaceObject.createElement("button", {
|
|
160
|
+
"aria-label": `Edit asset ${asset.id}`,
|
|
161
|
+
"data-asset-action": "edit",
|
|
162
|
+
onClick: ()=>{
|
|
163
|
+
onEdit(asset);
|
|
164
|
+
},
|
|
165
|
+
type: "button"
|
|
166
|
+
}, "Edit") : null, void 0 !== onReplace ? /*#__PURE__*/ external_react_namespaceObject.createElement("button", {
|
|
167
|
+
"aria-label": `Replace asset ${asset.id}`,
|
|
168
|
+
"data-asset-action": "replace",
|
|
169
|
+
onClick: ()=>{
|
|
170
|
+
onReplace(asset);
|
|
171
|
+
},
|
|
172
|
+
type: "button"
|
|
173
|
+
}, "Replace") : null, void 0 !== onDelete ? /*#__PURE__*/ external_react_namespaceObject.createElement("button", {
|
|
174
|
+
"aria-label": `Delete asset ${asset.id}`,
|
|
175
|
+
"data-asset-action": "delete",
|
|
176
|
+
onClick: ()=>{
|
|
177
|
+
onDelete(asset);
|
|
178
|
+
},
|
|
179
|
+
type: "button"
|
|
180
|
+
}, "Delete") : null);
|
|
181
|
+
}
|
|
182
|
+
const filterRow = searchEnabled ? /*#__PURE__*/ external_react_namespaceObject.createElement("div", {
|
|
183
|
+
"data-asset-manager-filters": true
|
|
184
|
+
}, /*#__PURE__*/ external_react_namespaceObject.createElement(input_namespaceObject.Input, {
|
|
185
|
+
"aria-label": "Search assets",
|
|
186
|
+
onChange: (event)=>{
|
|
187
|
+
setQuery(event.target.value);
|
|
188
|
+
setPageLimit(pageSize);
|
|
189
|
+
},
|
|
190
|
+
placeholder: "Search by name, tag, or MIME",
|
|
191
|
+
value: query
|
|
192
|
+
}), /*#__PURE__*/ external_react_namespaceObject.createElement("div", {
|
|
193
|
+
"aria-label": "Asset kind filters",
|
|
194
|
+
role: "group"
|
|
195
|
+
}, KIND_FILTERS.map((kind)=>{
|
|
196
|
+
const active = activeKinds.includes(kind);
|
|
197
|
+
return /*#__PURE__*/ external_react_namespaceObject.createElement("button", {
|
|
198
|
+
"aria-label": `Filter ${kind} assets`,
|
|
199
|
+
"aria-pressed": active,
|
|
200
|
+
"data-asset-kind-filter": kind,
|
|
201
|
+
key: kind,
|
|
202
|
+
onClick: ()=>{
|
|
203
|
+
toggleKind(kind);
|
|
204
|
+
setPageLimit(pageSize);
|
|
205
|
+
},
|
|
206
|
+
type: "button"
|
|
207
|
+
}, kind);
|
|
208
|
+
}))) : null;
|
|
209
|
+
if (0 === total) {
|
|
210
|
+
const emptyLabel = searchEnabled && ("" !== query || activeKinds.length > 0) ? "No assets match the current filters." : "No assets uploaded yet.";
|
|
211
|
+
return /*#__PURE__*/ external_react_namespaceObject.createElement(card_namespaceObject.Card, null, /*#__PURE__*/ external_react_namespaceObject.createElement(card_namespaceObject.CardHeader, null, /*#__PURE__*/ external_react_namespaceObject.createElement(card_namespaceObject.CardTitle, null, "Asset browser"), /*#__PURE__*/ external_react_namespaceObject.createElement(card_namespaceObject.CardDescription, null, "Validated assets currently registered in memory.")), /*#__PURE__*/ external_react_namespaceObject.createElement(card_namespaceObject.CardContent, null, filterRow, /*#__PURE__*/ external_react_namespaceObject.createElement("ul", {
|
|
212
|
+
"aria-label": "Assets",
|
|
213
|
+
role: "list"
|
|
214
|
+
}, /*#__PURE__*/ external_react_namespaceObject.createElement("li", {
|
|
215
|
+
role: "listitem"
|
|
216
|
+
}, emptyLabel))));
|
|
217
|
+
}
|
|
218
|
+
if (!isVirtualized) return /*#__PURE__*/ external_react_namespaceObject.createElement(card_namespaceObject.Card, null, /*#__PURE__*/ external_react_namespaceObject.createElement(card_namespaceObject.CardHeader, null, /*#__PURE__*/ external_react_namespaceObject.createElement(card_namespaceObject.CardTitle, null, "Asset browser"), /*#__PURE__*/ external_react_namespaceObject.createElement(card_namespaceObject.CardDescription, null, "Validated assets currently registered in memory.")), /*#__PURE__*/ external_react_namespaceObject.createElement(card_namespaceObject.CardContent, null, filterRow, /*#__PURE__*/ external_react_namespaceObject.createElement("ul", {
|
|
219
|
+
"aria-label": "Assets",
|
|
220
|
+
role: "list"
|
|
221
|
+
}, visibleAssets.map((asset, offset)=>renderRow(asset, offset))), hasMore ? /*#__PURE__*/ external_react_namespaceObject.createElement("button", {
|
|
222
|
+
"data-asset-action": "load-more",
|
|
223
|
+
onClick: ()=>{
|
|
224
|
+
setPageLimit((current)=>current + pageSize);
|
|
225
|
+
},
|
|
226
|
+
type: "button"
|
|
227
|
+
}, "Load more") : null));
|
|
228
|
+
const totalHeight = total * itemHeight;
|
|
229
|
+
const offsetY = firstVisible * itemHeight;
|
|
230
|
+
return /*#__PURE__*/ external_react_namespaceObject.createElement(card_namespaceObject.Card, null, /*#__PURE__*/ external_react_namespaceObject.createElement(card_namespaceObject.CardHeader, null, /*#__PURE__*/ external_react_namespaceObject.createElement(card_namespaceObject.CardTitle, null, "Asset browser"), /*#__PURE__*/ external_react_namespaceObject.createElement(card_namespaceObject.CardDescription, null, "Validated assets currently registered in memory.")), /*#__PURE__*/ external_react_namespaceObject.createElement(card_namespaceObject.CardContent, null, filterRow, /*#__PURE__*/ external_react_namespaceObject.createElement("div", {
|
|
231
|
+
"data-asset-manager-virtual": true,
|
|
232
|
+
onScroll: (event)=>{
|
|
233
|
+
setScrollTop(event.currentTarget.scrollTop);
|
|
234
|
+
},
|
|
235
|
+
ref: scrollContainerRef,
|
|
236
|
+
style: {
|
|
237
|
+
height: maxHeight,
|
|
238
|
+
overflowY: "auto",
|
|
239
|
+
position: "relative"
|
|
240
|
+
}
|
|
241
|
+
}, /*#__PURE__*/ external_react_namespaceObject.createElement("div", {
|
|
242
|
+
style: {
|
|
243
|
+
height: totalHeight,
|
|
244
|
+
position: "relative"
|
|
245
|
+
}
|
|
246
|
+
}, /*#__PURE__*/ external_react_namespaceObject.createElement("ul", {
|
|
247
|
+
"aria-label": "Assets",
|
|
248
|
+
role: "list",
|
|
249
|
+
style: {
|
|
250
|
+
margin: 0,
|
|
251
|
+
padding: 0,
|
|
252
|
+
position: "absolute",
|
|
253
|
+
top: offsetY,
|
|
254
|
+
left: 0,
|
|
255
|
+
right: 0
|
|
256
|
+
}
|
|
257
|
+
}, visibleAssets.map((asset, offset)=>renderRow(asset, firstVisible + offset))))), hasMore ? /*#__PURE__*/ external_react_namespaceObject.createElement("button", {
|
|
258
|
+
"data-asset-action": "load-more",
|
|
259
|
+
onClick: ()=>{
|
|
260
|
+
setPageLimit((current)=>current + pageSize);
|
|
261
|
+
},
|
|
262
|
+
type: "button"
|
|
263
|
+
}, "Load more") : null));
|
|
264
|
+
}
|
|
265
|
+
exports.AssetBrowser = __webpack_exports__.AssetBrowser;
|
|
266
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
267
|
+
"AssetBrowser"
|
|
268
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
269
|
+
Object.defineProperty(exports, '__esModule', {
|
|
270
|
+
value: true
|
|
271
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { UploadResult } from "../types.js";
|
|
2
|
+
export interface AssetBrowserProps {
|
|
3
|
+
readonly assets: readonly UploadResult[];
|
|
4
|
+
readonly onInsert: (asset: UploadResult) => void;
|
|
5
|
+
/**
|
|
6
|
+
* Optional delete affordance. When provided each row renders a
|
|
7
|
+
* "Delete" action that hands the asset back to the host — typically
|
|
8
|
+
* to open a `DeleteAssetDialog`.
|
|
9
|
+
*/
|
|
10
|
+
readonly onDelete?: (asset: UploadResult) => void;
|
|
11
|
+
/**
|
|
12
|
+
* Optional replace affordance. When provided each row renders a
|
|
13
|
+
* "Replace" action — typically to open a `ReplaceAssetDialog`.
|
|
14
|
+
*/
|
|
15
|
+
readonly onReplace?: (asset: UploadResult) => void;
|
|
16
|
+
/**
|
|
17
|
+
* Optional metadata-edit affordance. When provided each row renders
|
|
18
|
+
* an "Edit" action — typically to open a `MetadataPanel` dialog so
|
|
19
|
+
* the user can rename + retag the asset.
|
|
20
|
+
*/
|
|
21
|
+
readonly onEdit?: (asset: UploadResult) => void;
|
|
22
|
+
/**
|
|
23
|
+
* When `true`, renders the search input + kind chip row above the
|
|
24
|
+
* list. Off by default so existing AssetBrowser embeds (which
|
|
25
|
+
* pre-filter at the host layer) keep their previous chrome.
|
|
26
|
+
*/
|
|
27
|
+
readonly searchEnabled?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Page size used by the "Load more" affordance once the visible
|
|
30
|
+
* slice exceeds this number. Defaults to 100.
|
|
31
|
+
*/
|
|
32
|
+
readonly pageSize?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Threshold above which the list windows visible items. Below the
|
|
35
|
+
* threshold the entire list renders inline so small libraries skip
|
|
36
|
+
* scroll math entirely.
|
|
37
|
+
*/
|
|
38
|
+
readonly virtualizeThreshold?: number;
|
|
39
|
+
/** Pixel height of a single row when virtualizing. */
|
|
40
|
+
readonly itemHeight?: number;
|
|
41
|
+
/** Pixel height of the scroll container when virtualizing. */
|
|
42
|
+
readonly maxHeight?: number;
|
|
43
|
+
}
|
|
44
|
+
export declare function AssetBrowser({ assets, onInsert, onDelete, onReplace, onEdit, searchEnabled, pageSize, virtualizeThreshold, itemHeight, maxHeight, }: AssetBrowserProps): import("react/jsx-runtime").JSX.Element;
|
|
45
|
+
//# sourceMappingURL=AssetBrowser.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AssetBrowser.d.cts","sourceRoot":"","sources":["../../src/ui/AssetBrowser.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAa,YAAY,EAAE,MAAM,aAAa,CAAC;AAU3D,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC;IACzC,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACjD;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAClD;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACnD;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAChD;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IACtC,sDAAsD;IACtD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,8DAA8D;IAC9D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5B;AAQD,wBAAgB,YAAY,CAAC,EAC5B,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,MAAM,EACN,aAAqB,EACrB,QAA4B,EAC5B,mBAAkD,EAClD,UAAgC,EAChC,SAA8B,GAC9B,EAAE,iBAAiB,2CAmVnB"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { UploadResult } from "../types.js";
|
|
2
|
+
export interface AssetBrowserProps {
|
|
3
|
+
readonly assets: readonly UploadResult[];
|
|
4
|
+
readonly onInsert: (asset: UploadResult) => void;
|
|
5
|
+
/**
|
|
6
|
+
* Optional delete affordance. When provided each row renders a
|
|
7
|
+
* "Delete" action that hands the asset back to the host — typically
|
|
8
|
+
* to open a `DeleteAssetDialog`.
|
|
9
|
+
*/
|
|
10
|
+
readonly onDelete?: (asset: UploadResult) => void;
|
|
11
|
+
/**
|
|
12
|
+
* Optional replace affordance. When provided each row renders a
|
|
13
|
+
* "Replace" action — typically to open a `ReplaceAssetDialog`.
|
|
14
|
+
*/
|
|
15
|
+
readonly onReplace?: (asset: UploadResult) => void;
|
|
16
|
+
/**
|
|
17
|
+
* Optional metadata-edit affordance. When provided each row renders
|
|
18
|
+
* an "Edit" action — typically to open a `MetadataPanel` dialog so
|
|
19
|
+
* the user can rename + retag the asset.
|
|
20
|
+
*/
|
|
21
|
+
readonly onEdit?: (asset: UploadResult) => void;
|
|
22
|
+
/**
|
|
23
|
+
* When `true`, renders the search input + kind chip row above the
|
|
24
|
+
* list. Off by default so existing AssetBrowser embeds (which
|
|
25
|
+
* pre-filter at the host layer) keep their previous chrome.
|
|
26
|
+
*/
|
|
27
|
+
readonly searchEnabled?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Page size used by the "Load more" affordance once the visible
|
|
30
|
+
* slice exceeds this number. Defaults to 100.
|
|
31
|
+
*/
|
|
32
|
+
readonly pageSize?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Threshold above which the list windows visible items. Below the
|
|
35
|
+
* threshold the entire list renders inline so small libraries skip
|
|
36
|
+
* scroll math entirely.
|
|
37
|
+
*/
|
|
38
|
+
readonly virtualizeThreshold?: number;
|
|
39
|
+
/** Pixel height of a single row when virtualizing. */
|
|
40
|
+
readonly itemHeight?: number;
|
|
41
|
+
/** Pixel height of the scroll container when virtualizing. */
|
|
42
|
+
readonly maxHeight?: number;
|
|
43
|
+
}
|
|
44
|
+
export declare function AssetBrowser({ assets, onInsert, onDelete, onReplace, onEdit, searchEnabled, pageSize, virtualizeThreshold, itemHeight, maxHeight, }: AssetBrowserProps): import("react/jsx-runtime").JSX.Element;
|
|
45
|
+
//# sourceMappingURL=AssetBrowser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AssetBrowser.d.ts","sourceRoot":"","sources":["../../src/ui/AssetBrowser.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAa,YAAY,EAAE,MAAM,aAAa,CAAC;AAU3D,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC;IACzC,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACjD;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAClD;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACnD;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAChD;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IACtC,sDAAsD;IACtD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,8DAA8D;IAC9D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5B;AAQD,wBAAgB,YAAY,CAAC,EAC5B,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,MAAM,EACN,aAAqB,EACrB,QAA4B,EAC5B,mBAAkD,EAClD,UAAgC,EAChC,SAA8B,GAC9B,EAAE,iBAAiB,2CAmVnB"}
|