@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.
Files changed (159) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +159 -0
  3. package/dist/adapters/data-url.cjs +78 -0
  4. package/dist/adapters/data-url.d.cts +6 -0
  5. package/dist/adapters/data-url.d.cts.map +1 -0
  6. package/dist/adapters/data-url.d.ts +6 -0
  7. package/dist/adapters/data-url.d.ts.map +1 -0
  8. package/dist/adapters/data-url.js +44 -0
  9. package/dist/adapters/extract-image-dimensions.cjs +69 -0
  10. package/dist/adapters/extract-image-dimensions.d.cts +21 -0
  11. package/dist/adapters/extract-image-dimensions.d.cts.map +1 -0
  12. package/dist/adapters/extract-image-dimensions.d.ts +21 -0
  13. package/dist/adapters/extract-image-dimensions.d.ts.map +1 -0
  14. package/dist/adapters/extract-image-dimensions.js +35 -0
  15. package/dist/adapters/in-memory.cjs +62 -0
  16. package/dist/adapters/in-memory.d.cts +3 -0
  17. package/dist/adapters/in-memory.d.cts.map +1 -0
  18. package/dist/adapters/in-memory.d.ts +3 -0
  19. package/dist/adapters/in-memory.d.ts.map +1 -0
  20. package/dist/adapters/in-memory.js +28 -0
  21. package/dist/adapters/s3-presigned.cjs +166 -0
  22. package/dist/adapters/s3-presigned.d.cts +59 -0
  23. package/dist/adapters/s3-presigned.d.cts.map +1 -0
  24. package/dist/adapters/s3-presigned.d.ts +59 -0
  25. package/dist/adapters/s3-presigned.d.ts.map +1 -0
  26. package/dist/adapters/s3-presigned.js +129 -0
  27. package/dist/asset-reference.cjs +38 -0
  28. package/dist/asset-reference.d.cts +10 -0
  29. package/dist/asset-reference.d.cts.map +1 -0
  30. package/dist/asset-reference.d.ts +10 -0
  31. package/dist/asset-reference.d.ts.map +1 -0
  32. package/dist/asset-reference.js +4 -0
  33. package/dist/csp.cjs +83 -0
  34. package/dist/csp.d.cts +45 -0
  35. package/dist/csp.d.cts.map +1 -0
  36. package/dist/csp.d.ts +45 -0
  37. package/dist/csp.d.ts.map +1 -0
  38. package/dist/csp.js +49 -0
  39. package/dist/errors.cjs +58 -0
  40. package/dist/errors.d.cts +15 -0
  41. package/dist/errors.d.cts.map +1 -0
  42. package/dist/errors.d.ts +15 -0
  43. package/dist/errors.d.ts.map +1 -0
  44. package/dist/errors.js +21 -0
  45. package/dist/header-action.cjs +44 -0
  46. package/dist/header-action.d.cts +3 -0
  47. package/dist/header-action.d.cts.map +1 -0
  48. package/dist/header-action.d.ts +3 -0
  49. package/dist/header-action.d.ts.map +1 -0
  50. package/dist/header-action.js +10 -0
  51. package/dist/index.cjs +90 -0
  52. package/dist/index.d.cts +18 -0
  53. package/dist/index.d.cts.map +1 -0
  54. package/dist/index.d.ts +18 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +10 -0
  57. package/dist/infer-kind.cjs +45 -0
  58. package/dist/infer-kind.d.cts +8 -0
  59. package/dist/infer-kind.d.cts.map +1 -0
  60. package/dist/infer-kind.d.ts +8 -0
  61. package/dist/infer-kind.d.ts.map +1 -0
  62. package/dist/infer-kind.js +11 -0
  63. package/dist/plugin.cjs +258 -0
  64. package/dist/plugin.d.cts +9 -0
  65. package/dist/plugin.d.cts.map +1 -0
  66. package/dist/plugin.d.ts +9 -0
  67. package/dist/plugin.d.ts.map +1 -0
  68. package/dist/plugin.js +212 -0
  69. package/dist/registry.cjs +198 -0
  70. package/dist/registry.d.cts +3 -0
  71. package/dist/registry.d.cts.map +1 -0
  72. package/dist/registry.d.ts +3 -0
  73. package/dist/registry.d.ts.map +1 -0
  74. package/dist/registry.js +164 -0
  75. package/dist/resolver.cjs +185 -0
  76. package/dist/resolver.d.cts +10 -0
  77. package/dist/resolver.d.cts.map +1 -0
  78. package/dist/resolver.d.ts +10 -0
  79. package/dist/resolver.d.ts.map +1 -0
  80. package/dist/resolver.js +148 -0
  81. package/dist/retry.cjs +123 -0
  82. package/dist/retry.d.cts +71 -0
  83. package/dist/retry.d.cts.map +1 -0
  84. package/dist/retry.d.ts +71 -0
  85. package/dist/retry.d.ts.map +1 -0
  86. package/dist/retry.js +86 -0
  87. package/dist/studio-asset-source.cjs +211 -0
  88. package/dist/studio-asset-source.d.cts +52 -0
  89. package/dist/studio-asset-source.d.cts.map +1 -0
  90. package/dist/studio-asset-source.d.ts +52 -0
  91. package/dist/studio-asset-source.d.ts.map +1 -0
  92. package/dist/studio-asset-source.js +171 -0
  93. package/dist/testing/index.cjs +66 -0
  94. package/dist/testing/index.d.cts +24 -0
  95. package/dist/testing/index.d.cts.map +1 -0
  96. package/dist/testing/index.d.ts +24 -0
  97. package/dist/testing/index.d.ts.map +1 -0
  98. package/dist/testing/index.js +29 -0
  99. package/dist/types.cjs +18 -0
  100. package/dist/types.d.cts +132 -0
  101. package/dist/types.d.cts.map +1 -0
  102. package/dist/types.d.ts +132 -0
  103. package/dist/types.d.ts.map +1 -0
  104. package/dist/types.js +0 -0
  105. package/dist/ui/AssetBrowser.cjs +271 -0
  106. package/dist/ui/AssetBrowser.d.cts +45 -0
  107. package/dist/ui/AssetBrowser.d.cts.map +1 -0
  108. package/dist/ui/AssetBrowser.d.ts +45 -0
  109. package/dist/ui/AssetBrowser.d.ts.map +1 -0
  110. package/dist/ui/AssetBrowser.js +237 -0
  111. package/dist/ui/AssetCommandPalette.cjs +135 -0
  112. package/dist/ui/AssetCommandPalette.d.cts +21 -0
  113. package/dist/ui/AssetCommandPalette.d.cts.map +1 -0
  114. package/dist/ui/AssetCommandPalette.d.ts +21 -0
  115. package/dist/ui/AssetCommandPalette.d.ts.map +1 -0
  116. package/dist/ui/AssetCommandPalette.js +101 -0
  117. package/dist/ui/AssetManagerUI.cjs +169 -0
  118. package/dist/ui/AssetManagerUI.d.cts +15 -0
  119. package/dist/ui/AssetManagerUI.d.cts.map +1 -0
  120. package/dist/ui/AssetManagerUI.d.ts +15 -0
  121. package/dist/ui/AssetManagerUI.d.ts.map +1 -0
  122. package/dist/ui/AssetManagerUI.js +135 -0
  123. package/dist/ui/DeleteAssetDialog.cjs +70 -0
  124. package/dist/ui/DeleteAssetDialog.d.cts +22 -0
  125. package/dist/ui/DeleteAssetDialog.d.cts.map +1 -0
  126. package/dist/ui/DeleteAssetDialog.d.ts +22 -0
  127. package/dist/ui/DeleteAssetDialog.d.ts.map +1 -0
  128. package/dist/ui/DeleteAssetDialog.js +36 -0
  129. package/dist/ui/MetadataPanel.cjs +147 -0
  130. package/dist/ui/MetadataPanel.d.cts +21 -0
  131. package/dist/ui/MetadataPanel.d.cts.map +1 -0
  132. package/dist/ui/MetadataPanel.d.ts +21 -0
  133. package/dist/ui/MetadataPanel.d.ts.map +1 -0
  134. package/dist/ui/MetadataPanel.js +113 -0
  135. package/dist/ui/ReplaceAssetDialog.cjs +125 -0
  136. package/dist/ui/ReplaceAssetDialog.d.cts +14 -0
  137. package/dist/ui/ReplaceAssetDialog.d.cts.map +1 -0
  138. package/dist/ui/ReplaceAssetDialog.d.ts +14 -0
  139. package/dist/ui/ReplaceAssetDialog.d.ts.map +1 -0
  140. package/dist/ui/ReplaceAssetDialog.js +91 -0
  141. package/dist/ui/UploadButton.cjs +189 -0
  142. package/dist/ui/UploadButton.d.cts +17 -0
  143. package/dist/ui/UploadButton.d.cts.map +1 -0
  144. package/dist/ui/UploadButton.d.ts +17 -0
  145. package/dist/ui/UploadButton.d.ts.map +1 -0
  146. package/dist/ui/UploadButton.js +155 -0
  147. package/dist/ui/index.cjs +60 -0
  148. package/dist/ui/index.d.cts +15 -0
  149. package/dist/ui/index.d.cts.map +1 -0
  150. package/dist/ui/index.d.ts +15 -0
  151. package/dist/ui/index.d.ts.map +1 -0
  152. package/dist/ui/index.js +7 -0
  153. package/dist/validate-upload-result.cjs +149 -0
  154. package/dist/validate-upload-result.d.cts +9 -0
  155. package/dist/validate-upload-result.d.cts.map +1 -0
  156. package/dist/validate-upload-result.d.ts +9 -0
  157. package/dist/validate-upload-result.d.ts.map +1 -0
  158. package/dist/validate-upload-result.js +115 -0
  159. package/package.json +131 -0
@@ -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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"}
@@ -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"}