@anvilkit/plugin-asset-manager 0.1.4 → 0.1.6

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 (40) hide show
  1. package/README.md +2 -2
  2. package/dist/adapters/data-url.cjs +9 -5
  3. package/dist/adapters/extract-image-dimensions.cjs +12 -8
  4. package/dist/adapters/in-memory.cjs +9 -5
  5. package/dist/adapters/s3-presigned.cjs +9 -5
  6. package/dist/index.cjs +9 -5
  7. package/dist/plugin.cjs +13 -6
  8. package/dist/plugin.d.cts.map +1 -1
  9. package/dist/plugin.d.ts.map +1 -1
  10. package/dist/plugin.js +4 -1
  11. package/dist/testing/index.cjs +9 -5
  12. package/dist/ui/AssetBrowser.cjs +37 -93
  13. package/dist/ui/AssetBrowser.d.cts +5 -6
  14. package/dist/ui/AssetBrowser.d.cts.map +1 -1
  15. package/dist/ui/AssetBrowser.d.ts +5 -6
  16. package/dist/ui/AssetBrowser.d.ts.map +1 -1
  17. package/dist/ui/AssetBrowser.js +28 -88
  18. package/dist/ui/AssetCommandPalette.cjs +9 -5
  19. package/dist/ui/AssetManagerUI.cjs +9 -5
  20. package/dist/ui/DeleteAssetDialog.cjs +9 -5
  21. package/dist/ui/MetadataPanel.cjs +9 -5
  22. package/dist/ui/ReplaceAssetDialog.cjs +9 -5
  23. package/dist/ui/UploadButton.cjs +9 -5
  24. package/dist/ui/index.cjs +9 -5
  25. package/dist/utils/asset-reference.cjs +12 -8
  26. package/dist/utils/csp.cjs +12 -8
  27. package/dist/utils/errors.cjs +13 -9
  28. package/dist/utils/header-action.cjs +12 -8
  29. package/dist/utils/infer-kind.cjs +12 -8
  30. package/dist/utils/registry.cjs +9 -5
  31. package/dist/utils/resolver.cjs +9 -5
  32. package/dist/utils/retry.cjs +13 -9
  33. package/dist/utils/studio-asset-source.cjs +9 -5
  34. package/dist/utils/validate-upload-result.cjs +9 -5
  35. package/dist/version.cjs +12 -8
  36. package/dist/version.d.cts +1 -1
  37. package/dist/version.d.ts +1 -1
  38. package/dist/version.js +1 -1
  39. package/meta/config.json +2 -2
  40. package/package.json +10 -9
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @anvilkit/plugin-asset-manager
2
2
 
3
- > **Alpha (`0.1.3`).** Public surface may still shift before `v1.0`. Bundle budgets enforced in CI: headless ≤ 6 KB gzip, UI subpath ≤ 12 KB gzip.
3
+ > **Alpha (`0.1.6`).** Public surface may still shift before `v1.0`. Bundle budgets enforced in CI: headless ≤ 6 KB gzip, UI subpath ≤ 12 KB gzip.
4
4
 
5
5
  Headless asset manager plugin for Anvilkit Studio. The host provides the upload backend; the plugin handles validation, registration, search, IR-time resolution, CSP guidance, and (optionally) a React UI for the upload + browse experience. Designed for pluggable production backends (S3, GCS, custom HTTP) with strict trust-boundary enforcement on every adapter response.
6
6
 
@@ -10,7 +10,7 @@ Headless asset manager plugin for Anvilkit Studio. The host provides the upload
10
10
  pnpm add @anvilkit/plugin-asset-manager @anvilkit/core react react-dom @puckeditor/core
11
11
  ```
12
12
 
13
- Non-optional peers: `react ^18.2.0 || ^19.0.0`, `react-dom ^18.2.0 || ^19.0.0`, `@puckeditor/core ^0.21.2`.
13
+ Non-optional peers: `react >=19.0.0`, `react-dom >=19.0.0`, `@puckeditor/core ^0.21.2`.
14
14
 
15
15
  Subpath imports:
16
16
 
@@ -1,11 +1,15 @@
1
1
  "use strict";
2
2
  var __webpack_require__ = {};
3
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
- });
4
+ __webpack_require__.d = (exports1, getters, values)=>{
5
+ var define = (defs, kind)=>{
6
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
7
+ enumerable: true,
8
+ [kind]: defs[key]
9
+ });
10
+ };
11
+ define(getters, "get");
12
+ define(values, "value");
9
13
  };
10
14
  })();
11
15
  (()=>{
@@ -1,11 +1,15 @@
1
1
  "use strict";
2
2
  var __webpack_require__ = {};
3
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
- });
4
+ __webpack_require__.d = (exports1, getters, values)=>{
5
+ var define = (defs, kind)=>{
6
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
7
+ enumerable: true,
8
+ [kind]: defs[key]
9
+ });
10
+ };
11
+ define(getters, "get");
12
+ define(values, "value");
9
13
  };
10
14
  })();
11
15
  (()=>{
@@ -23,9 +27,6 @@ var __webpack_require__ = {};
23
27
  })();
24
28
  var __webpack_exports__ = {};
25
29
  __webpack_require__.r(__webpack_exports__);
26
- __webpack_require__.d(__webpack_exports__, {
27
- extractImageDimensions: ()=>extractImageDimensions
28
- });
29
30
  const DEFAULT_TIMEOUT_MS = 3000;
30
31
  async function extractImageDimensions(url, mimeType, options = {}) {
31
32
  if (!mimeType || !mimeType.startsWith("image/")) return;
@@ -69,6 +70,9 @@ async function extractImageDimensions(url, mimeType, options = {}) {
69
70
  image.src = url;
70
71
  });
71
72
  }
73
+ __webpack_require__.d(__webpack_exports__, {
74
+ extractImageDimensions: ()=>extractImageDimensions
75
+ });
72
76
  exports.extractImageDimensions = __webpack_exports__.extractImageDimensions;
73
77
  for(var __rspack_i in __webpack_exports__)if (-1 === [
74
78
  "extractImageDimensions"
@@ -1,11 +1,15 @@
1
1
  "use strict";
2
2
  var __webpack_require__ = {};
3
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
- });
4
+ __webpack_require__.d = (exports1, getters, values)=>{
5
+ var define = (defs, kind)=>{
6
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
7
+ enumerable: true,
8
+ [kind]: defs[key]
9
+ });
10
+ };
11
+ define(getters, "get");
12
+ define(values, "value");
9
13
  };
10
14
  })();
11
15
  (()=>{
@@ -1,11 +1,15 @@
1
1
  "use strict";
2
2
  var __webpack_require__ = {};
3
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
- });
4
+ __webpack_require__.d = (exports1, getters, values)=>{
5
+ var define = (defs, kind)=>{
6
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
7
+ enumerable: true,
8
+ [kind]: defs[key]
9
+ });
10
+ };
11
+ define(getters, "get");
12
+ define(values, "value");
9
13
  };
10
14
  })();
11
15
  (()=>{
package/dist/index.cjs CHANGED
@@ -1,11 +1,15 @@
1
1
  "use strict";
2
2
  var __webpack_require__ = {};
3
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
- });
4
+ __webpack_require__.d = (exports1, getters, values)=>{
5
+ var define = (defs, kind)=>{
6
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
7
+ enumerable: true,
8
+ [kind]: defs[key]
9
+ });
10
+ };
11
+ define(getters, "get");
12
+ define(values, "value");
9
13
  };
10
14
  })();
11
15
  (()=>{
package/dist/plugin.cjs CHANGED
@@ -10,11 +10,15 @@ var __webpack_require__ = {};
10
10
  };
11
11
  })();
12
12
  (()=>{
13
- __webpack_require__.d = (exports1, definition)=>{
14
- for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
15
- enumerable: true,
16
- get: definition[key]
17
- });
13
+ __webpack_require__.d = (exports1, getters, values)=>{
14
+ var define = (defs, kind)=>{
15
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
16
+ enumerable: true,
17
+ [kind]: defs[key]
18
+ });
19
+ };
20
+ define(getters, "get");
21
+ define(values, "value");
18
22
  };
19
23
  })();
20
24
  (()=>{
@@ -39,6 +43,8 @@ __webpack_require__.d(__webpack_exports__, {
39
43
  uploadAsset: ()=>uploadAsset,
40
44
  validateSelectedFile: ()=>validateSelectedFile
41
45
  });
46
+ const external_lucide_react_namespaceObject = require("lucide-react");
47
+ const external_react_namespaceObject = require("react");
42
48
  const config_json_namespaceObject = require("../meta/config.json");
43
49
  var config_json_default = /*#__PURE__*/ __webpack_require__.n(config_json_namespaceObject);
44
50
  const asset_reference_cjs_namespaceObject = require("./utils/asset-reference.cjs");
@@ -52,7 +58,8 @@ const validate_upload_result_cjs_namespaceObject = require("./utils/validate-upl
52
58
  const external_version_cjs_namespaceObject = require("./version.cjs");
53
59
  const META = {
54
60
  ...config_json_default(),
55
- version: external_version_cjs_namespaceObject.ASSET_MANAGER_VERSION
61
+ version: external_version_cjs_namespaceObject.ASSET_MANAGER_VERSION,
62
+ icon: (0, external_react_namespaceObject.createElement)(external_lucide_react_namespaceObject.Images)
56
63
  };
57
64
  const stateByToken = new WeakMap();
58
65
  const tokenByContext = new WeakMap();
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.cts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEX,YAAY,EACZ,mBAAmB,EAEnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG7D,OAAO,KAAK,EACX,mBAAmB,EAEnB,aAAa,EACb,YAAY,EACZ,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAUlE,OAAO,EAAE,oBAAoB,EAAE,CAAC;AA0BhC,wBAAgB,wBAAwB,CACvC,UAAU,SAAS,UAAU,GAAG,UAAU,EACzC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAAC,UAAU,CAAC,CAwDxD;AAED,wBAAgB,gBAAgB,CAAC,UAAU,SAAS,UAAU,GAAG,UAAU,EAC1E,GAAG,EAAE,mBAAmB,CAAC,UAAU,CAAC,GAClC,aAAa,GAAG,SAAS,CAG3B;AAED,wBAAsB,WAAW,CAAC,UAAU,SAAS,UAAU,GAAG,UAAU,EAC3E,GAAG,EAAE,mBAAmB,CAAC,UAAU,CAAC,EACpC,IAAI,EAAE,IAAI,EACV,MAAM,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,YAAY,CAAC,CAwDvB;AAED,wBAAgB,oBAAoB,CACnC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,IAAI,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,aAAa,CAAC,GACrE,IAAI,CAmBN"}
1
+ {"version":3,"file":"plugin.d.cts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEX,YAAY,EACZ,mBAAmB,EAEnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAK7D,OAAO,KAAK,EACX,mBAAmB,EAEnB,aAAa,EACb,YAAY,EACZ,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAUlE,OAAO,EAAE,oBAAoB,EAAE,CAAC;AA2BhC,wBAAgB,wBAAwB,CACvC,UAAU,SAAS,UAAU,GAAG,UAAU,EACzC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAAC,UAAU,CAAC,CAwDxD;AAED,wBAAgB,gBAAgB,CAAC,UAAU,SAAS,UAAU,GAAG,UAAU,EAC1E,GAAG,EAAE,mBAAmB,CAAC,UAAU,CAAC,GAClC,aAAa,GAAG,SAAS,CAG3B;AAED,wBAAsB,WAAW,CAAC,UAAU,SAAS,UAAU,GAAG,UAAU,EAC3E,GAAG,EAAE,mBAAmB,CAAC,UAAU,CAAC,EACpC,IAAI,EAAE,IAAI,EACV,MAAM,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,YAAY,CAAC,CAwDvB;AAED,wBAAgB,oBAAoB,CACnC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,IAAI,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,aAAa,CAAC,GACrE,IAAI,CAmBN"}
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEX,YAAY,EACZ,mBAAmB,EAEnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG7D,OAAO,KAAK,EACX,mBAAmB,EAEnB,aAAa,EACb,YAAY,EACZ,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAUlE,OAAO,EAAE,oBAAoB,EAAE,CAAC;AA0BhC,wBAAgB,wBAAwB,CACvC,UAAU,SAAS,UAAU,GAAG,UAAU,EACzC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAAC,UAAU,CAAC,CAwDxD;AAED,wBAAgB,gBAAgB,CAAC,UAAU,SAAS,UAAU,GAAG,UAAU,EAC1E,GAAG,EAAE,mBAAmB,CAAC,UAAU,CAAC,GAClC,aAAa,GAAG,SAAS,CAG3B;AAED,wBAAsB,WAAW,CAAC,UAAU,SAAS,UAAU,GAAG,UAAU,EAC3E,GAAG,EAAE,mBAAmB,CAAC,UAAU,CAAC,EACpC,IAAI,EAAE,IAAI,EACV,MAAM,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,YAAY,CAAC,CAwDvB;AAED,wBAAgB,oBAAoB,CACnC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,IAAI,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,aAAa,CAAC,GACrE,IAAI,CAmBN"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEX,YAAY,EACZ,mBAAmB,EAEnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAK7D,OAAO,KAAK,EACX,mBAAmB,EAEnB,aAAa,EACb,YAAY,EACZ,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAUlE,OAAO,EAAE,oBAAoB,EAAE,CAAC;AA2BhC,wBAAgB,wBAAwB,CACvC,UAAU,SAAS,UAAU,GAAG,UAAU,EACzC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAAC,UAAU,CAAC,CAwDxD;AAED,wBAAgB,gBAAgB,CAAC,UAAU,SAAS,UAAU,GAAG,UAAU,EAC1E,GAAG,EAAE,mBAAmB,CAAC,UAAU,CAAC,GAClC,aAAa,GAAG,SAAS,CAG3B;AAED,wBAAsB,WAAW,CAAC,UAAU,SAAS,UAAU,GAAG,UAAU,EAC3E,GAAG,EAAE,mBAAmB,CAAC,UAAU,CAAC,EACpC,IAAI,EAAE,IAAI,EACV,MAAM,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,YAAY,CAAC,CAwDvB;AAED,wBAAgB,oBAAoB,CACnC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,IAAI,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,aAAa,CAAC,GACrE,IAAI,CAmBN"}
package/dist/plugin.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { Images } from "lucide-react";
2
+ import { createElement } from "react";
1
3
  import config from "../meta/config.json" with {
2
4
  type: "json"
3
5
  };
@@ -12,7 +14,8 @@ import { validateUploadResult } from "./utils/validate-upload-result.js";
12
14
  import { ASSET_MANAGER_VERSION } from "./version.js";
13
15
  const META = {
14
16
  ...config,
15
- version: ASSET_MANAGER_VERSION
17
+ version: ASSET_MANAGER_VERSION,
18
+ icon: createElement(Images)
16
19
  };
17
20
  const stateByToken = new WeakMap();
18
21
  const tokenByContext = new WeakMap();
@@ -1,11 +1,15 @@
1
1
  "use strict";
2
2
  var __webpack_require__ = {};
3
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
- });
4
+ __webpack_require__.d = (exports1, getters, values)=>{
5
+ var define = (defs, kind)=>{
6
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
7
+ enumerable: true,
8
+ [kind]: defs[key]
9
+ });
10
+ };
11
+ define(getters, "get");
12
+ define(values, "value");
9
13
  };
10
14
  })();
11
15
  (()=>{
@@ -2,11 +2,15 @@
2
2
  "use client";
3
3
  var __webpack_require__ = {};
4
4
  (()=>{
5
- __webpack_require__.d = (exports1, definition)=>{
6
- for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
7
- enumerable: true,
8
- get: definition[key]
9
- });
5
+ __webpack_require__.d = (exports1, getters, values)=>{
6
+ var define = (defs, kind)=>{
7
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
8
+ enumerable: true,
9
+ [kind]: defs[key]
10
+ });
11
+ };
12
+ define(getters, "get");
13
+ define(values, "value");
10
14
  };
11
15
  })();
12
16
  (()=>{
@@ -29,8 +33,8 @@ __webpack_require__.d(__webpack_exports__, {
29
33
  });
30
34
  const card_namespaceObject = require("@anvilkit/ui/card");
31
35
  const input_namespaceObject = require("@anvilkit/ui/input");
36
+ const windowed_namespaceObject = require("@anvilkit/ui/windowed");
32
37
  const external_react_namespaceObject = require("react");
33
- const external_react_dom_namespaceObject = require("react-dom");
34
38
  const infer_kind_cjs_namespaceObject = require("../utils/infer-kind.cjs");
35
39
  const KIND_FILTERS = [
36
40
  "image",
@@ -43,20 +47,13 @@ const DEFAULT_VIRTUALIZE_THRESHOLD = 50;
43
47
  const DEFAULT_ITEM_HEIGHT = 56;
44
48
  const DEFAULT_MAX_HEIGHT = 400;
45
49
  const DEFAULT_PAGE_SIZE = 100;
46
- const OVERSCAN = 4;
47
50
  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 }) {
48
51
  const [activeIndex, setActiveIndex] = external_react_namespaceObject.useState(assets.length > 0 ? 0 : -1);
49
- const [scrollTop, setScrollTop] = external_react_namespaceObject.useState(0);
50
52
  const [query, setQuery] = external_react_namespaceObject.useState("");
51
53
  const [activeKinds, setActiveKinds] = external_react_namespaceObject.useState([]);
52
54
  const [pageLimit, setPageLimit] = external_react_namespaceObject.useState(pageSize);
53
55
  const buttonRefs = external_react_namespaceObject.useRef([]);
54
- const scrollContainerRef = external_react_namespaceObject.useRef(null);
55
- const scrollFrameRef = external_react_namespaceObject.useRef(null);
56
- const pendingScrollTopRef = external_react_namespaceObject.useRef(0);
57
- external_react_namespaceObject.useEffect(()=>()=>{
58
- if (null !== scrollFrameRef.current && "function" == typeof cancelAnimationFrame) cancelAnimationFrame(scrollFrameRef.current);
59
- }, []);
56
+ const pendingFocusRef = external_react_namespaceObject.useRef(null);
60
57
  const searchIndex = external_react_namespaceObject.useMemo(()=>{
61
58
  if (!searchEnabled) return null;
62
59
  return assets.map((asset)=>({
@@ -96,7 +93,6 @@ function AssetBrowser({ assets, onInsert, onDelete, onReplace, onEdit, searchEna
96
93
  searchEnabled
97
94
  ]);
98
95
  const total = visibleSlice.length;
99
- const isVirtualized = total > virtualizeThreshold;
100
96
  const hasMore = searchEnabled && filteredAssets.length > visibleSlice.length;
101
97
  external_react_namespaceObject.useEffect(()=>{
102
98
  if (0 === total) return void setActiveIndex(-1);
@@ -104,31 +100,20 @@ function AssetBrowser({ assets, onInsert, onDelete, onReplace, onEdit, searchEna
104
100
  }, [
105
101
  total
106
102
  ]);
103
+ function focusRow(index) {
104
+ const node = buttonRefs.current[index];
105
+ if (node) {
106
+ node.focus();
107
+ return true;
108
+ }
109
+ return false;
110
+ }
107
111
  function moveFocus(nextIndex) {
108
112
  if (0 === total) return;
109
113
  const clampedIndex = Math.max(0, Math.min(nextIndex, total - 1));
110
- if (isVirtualized && scrollContainerRef.current) {
111
- const targetTop = clampedIndex * itemHeight;
112
- const targetBottom = targetTop + itemHeight;
113
- const viewTop = scrollContainerRef.current.scrollTop;
114
- let nextScrollTop = viewTop;
115
- if (targetTop < viewTop) nextScrollTop = targetTop;
116
- else if (targetBottom > viewTop + maxHeight) nextScrollTop = targetBottom - maxHeight;
117
- if (null !== scrollFrameRef.current && "function" == typeof cancelAnimationFrame) {
118
- cancelAnimationFrame(scrollFrameRef.current);
119
- scrollFrameRef.current = null;
120
- }
121
- pendingScrollTopRef.current = nextScrollTop;
122
- (0, external_react_dom_namespaceObject.flushSync)(()=>{
123
- setActiveIndex(clampedIndex);
124
- setScrollTop(nextScrollTop);
125
- });
126
- scrollContainerRef.current.scrollTop = nextScrollTop;
127
- buttonRefs.current[clampedIndex]?.focus();
128
- return;
129
- }
114
+ pendingFocusRef.current = clampedIndex;
130
115
  setActiveIndex(clampedIndex);
131
- buttonRefs.current[clampedIndex]?.focus();
116
+ if (focusRow(clampedIndex)) pendingFocusRef.current = null;
132
117
  }
133
118
  function toggleKind(kind) {
134
119
  setActiveKinds((current)=>current.includes(kind) ? current.filter((entry)=>entry !== kind) : [
@@ -136,16 +121,7 @@ function AssetBrowser({ assets, onInsert, onDelete, onReplace, onEdit, searchEna
136
121
  kind
137
122
  ]);
138
123
  }
139
- const firstVisible = isVirtualized ? Math.max(0, Math.floor(scrollTop / itemHeight) - OVERSCAN) : 0;
140
- const lastVisible = isVirtualized ? Math.min(total - 1, Math.ceil((scrollTop + maxHeight) / itemHeight) + OVERSCAN) : total - 1;
141
- const visibleAssets = 0 === total ? [] : isVirtualized ? visibleSlice.slice(firstVisible, lastVisible + 1) : visibleSlice;
142
- function renderRow(asset, index) {
143
- return /*#__PURE__*/ external_react_namespaceObject.createElement("li", {
144
- "aria-posinset": index + 1,
145
- "aria-setsize": total,
146
- key: asset.id,
147
- role: "listitem"
148
- }, /*#__PURE__*/ external_react_namespaceObject.createElement("button", {
124
+ const renderRow = (asset, index)=>/*#__PURE__*/ external_react_namespaceObject.createElement(external_react_namespaceObject.Fragment, null, /*#__PURE__*/ external_react_namespaceObject.createElement("button", {
149
125
  "aria-label": `Insert asset ${asset.id}`,
150
126
  onClick: ()=>{
151
127
  onInsert(asset);
@@ -181,6 +157,10 @@ function AssetBrowser({ assets, onInsert, onDelete, onReplace, onEdit, searchEna
181
157
  },
182
158
  ref: (node)=>{
183
159
  buttonRefs.current[index] = node;
160
+ if (node && pendingFocusRef.current === index) {
161
+ pendingFocusRef.current = null;
162
+ node.focus();
163
+ }
184
164
  },
185
165
  tabIndex: activeIndex === index ? 0 : -1,
186
166
  type: "button"
@@ -206,7 +186,6 @@ function AssetBrowser({ assets, onInsert, onDelete, onReplace, onEdit, searchEna
206
186
  },
207
187
  type: "button"
208
188
  }, "Delete") : null);
209
- }
210
189
  const filterRow = searchEnabled ? /*#__PURE__*/ external_react_namespaceObject.createElement("div", {
211
190
  "data-asset-manager-filters": true
212
191
  }, /*#__PURE__*/ external_react_namespaceObject.createElement(input_namespaceObject.Input, {
@@ -243,53 +222,18 @@ function AssetBrowser({ assets, onInsert, onDelete, onReplace, onEdit, searchEna
243
222
  role: "listitem"
244
223
  }, emptyLabel))));
245
224
  }
246
- 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", {
225
+ 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(windowed_namespaceObject.Windowed, {
226
+ activeIndex: activeIndex >= 0 ? activeIndex : void 0,
247
227
  "aria-label": "Assets",
248
- role: "list"
249
- }, visibleAssets.map((asset, offset)=>renderRow(asset, offset))), hasMore ? /*#__PURE__*/ external_react_namespaceObject.createElement("button", {
250
- "data-asset-action": "load-more",
251
- onClick: ()=>{
252
- setPageLimit((current)=>current + pageSize);
253
- },
254
- type: "button"
255
- }, "Load more") : null));
256
- const totalHeight = total * itemHeight;
257
- const offsetY = firstVisible * itemHeight;
258
- 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", {
259
- "data-asset-manager-virtual": true,
260
- onScroll: (event)=>{
261
- const next = event.currentTarget.scrollTop;
262
- if ("function" != typeof requestAnimationFrame) return void setScrollTop(next);
263
- pendingScrollTopRef.current = next;
264
- if (null !== scrollFrameRef.current) return;
265
- scrollFrameRef.current = requestAnimationFrame(()=>{
266
- scrollFrameRef.current = null;
267
- setScrollTop(pendingScrollTopRef.current);
268
- });
269
- },
270
- ref: scrollContainerRef,
271
- style: {
272
- height: maxHeight,
273
- overflowY: "auto",
274
- position: "relative"
275
- }
276
- }, /*#__PURE__*/ external_react_namespaceObject.createElement("div", {
277
- style: {
278
- height: totalHeight,
279
- position: "relative"
280
- }
281
- }, /*#__PURE__*/ external_react_namespaceObject.createElement("ul", {
282
- "aria-label": "Assets",
283
- role: "list",
284
- style: {
285
- margin: 0,
286
- padding: 0,
287
- position: "absolute",
288
- top: offsetY,
289
- left: 0,
290
- right: 0
291
- }
292
- }, visibleAssets.map((asset, offset)=>renderRow(asset, firstVisible + offset))))), hasMore ? /*#__PURE__*/ external_react_namespaceObject.createElement("button", {
228
+ as: "ul",
229
+ "data-testid": "asset-browser-virtualized",
230
+ estimateSize: itemHeight,
231
+ items: visibleSlice,
232
+ itemKey: (asset)=>asset.id,
233
+ maxHeight: maxHeight,
234
+ renderItem: renderRow,
235
+ threshold: virtualizeThreshold
236
+ }), hasMore ? /*#__PURE__*/ external_react_namespaceObject.createElement("button", {
293
237
  "data-asset-action": "load-more",
294
238
  onClick: ()=>{
295
239
  setPageLimit((current)=>current + pageSize);
@@ -33,17 +33,16 @@ export interface AssetBrowserProps {
33
33
  /**
34
34
  * Threshold above which the list windows visible items. Below the
35
35
  * threshold the entire list renders inline so small libraries skip
36
- * scroll math entirely.
36
+ * scroll math entirely. Forwarded to the shared `Windowed` primitive.
37
37
  */
38
38
  readonly virtualizeThreshold?: number;
39
39
  /**
40
40
  * Pixel height of a single row when virtualizing.
41
41
  *
42
- * **Fixed-height contract:** the windowing math (visible range, scroll
43
- * offset, and keyboard-focus scroll) assumes every row is exactly
44
- * `itemHeight` tall. Rows that wrap or vary in height (long names,
45
- * thumbnails) will desync the scroll position and focus calculation.
46
- * Keep rows uniform, or raise `virtualizeThreshold` so the list renders
42
+ * **Fixed-height contract:** the windowing math assumes every row is
43
+ * roughly `itemHeight` tall. Rows that wrap or vary in height (long
44
+ * names, thumbnails) will desync the scroll-into-view calculation. Keep
45
+ * rows uniform, or raise `virtualizeThreshold` so the list renders
47
46
  * inline instead.
48
47
  */
49
48
  readonly itemHeight?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"AssetBrowser.d.cts","sourceRoot":"","sources":["../../src/ui/AssetBrowser.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAa,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAWjE,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;;;;;;;;;OASG;IACH,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,2CAkZnB"}
1
+ {"version":3,"file":"AssetBrowser.d.cts","sourceRoot":"","sources":["../../src/ui/AssetBrowser.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAa,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAWjE,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;;;;;;;;OAQG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,8DAA8D;IAC9D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5B;AAOD,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,2CAuSnB"}
@@ -33,17 +33,16 @@ export interface AssetBrowserProps {
33
33
  /**
34
34
  * Threshold above which the list windows visible items. Below the
35
35
  * threshold the entire list renders inline so small libraries skip
36
- * scroll math entirely.
36
+ * scroll math entirely. Forwarded to the shared `Windowed` primitive.
37
37
  */
38
38
  readonly virtualizeThreshold?: number;
39
39
  /**
40
40
  * Pixel height of a single row when virtualizing.
41
41
  *
42
- * **Fixed-height contract:** the windowing math (visible range, scroll
43
- * offset, and keyboard-focus scroll) assumes every row is exactly
44
- * `itemHeight` tall. Rows that wrap or vary in height (long names,
45
- * thumbnails) will desync the scroll position and focus calculation.
46
- * Keep rows uniform, or raise `virtualizeThreshold` so the list renders
42
+ * **Fixed-height contract:** the windowing math assumes every row is
43
+ * roughly `itemHeight` tall. Rows that wrap or vary in height (long
44
+ * names, thumbnails) will desync the scroll-into-view calculation. Keep
45
+ * rows uniform, or raise `virtualizeThreshold` so the list renders
47
46
  * inline instead.
48
47
  */
49
48
  readonly itemHeight?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"AssetBrowser.d.ts","sourceRoot":"","sources":["../../src/ui/AssetBrowser.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAa,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAWjE,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;;;;;;;;;OASG;IACH,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,2CAkZnB"}
1
+ {"version":3,"file":"AssetBrowser.d.ts","sourceRoot":"","sources":["../../src/ui/AssetBrowser.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAa,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAWjE,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;;;;;;;;OAQG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,8DAA8D;IAC9D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5B;AAOD,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,2CAuSnB"}