@poveste/app 0.5.3 → 0.6.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 (90) hide show
  1. package/dist/app/style/font.css +78 -0
  2. package/dist/app/style/main.pcss +4 -1
  3. package/dist/app/style/sandbox.css +3 -0
  4. package/dist/bundle-main-dev.js +1 -0
  5. package/dist/bundle-main.js +3 -0
  6. package/dist/bundled/app.css +28 -20
  7. package/dist/bundled/components/app/AppActions.vue_vue_type_script_setup_true_lang.js +2 -2
  8. package/dist/bundled/components/base/BaseSelect.vue_vue_type_script_setup_true_lang.js +1 -1
  9. package/dist/bundled/components/layout/LayoutModal.vue_vue_type_script_setup_true_lang.js +2 -2
  10. package/dist/bundled/components/layout/LayoutPane.vue_vue_type_script_setup_true_lang.js +4 -4
  11. package/dist/bundled/components/panel/StatePresets.vue_vue_type_script_setup_true_lang.js +5 -5
  12. package/dist/bundled/components/panel/StoryControls.vue_vue_type_script_setup_true_lang.js +1 -1
  13. package/dist/bundled/components/panel/StoryDocs.vue_vue_type_script_setup_true_lang.js +1 -1
  14. package/dist/bundled/components/panel/StoryEvent.vue_vue_type_script_setup_true_lang.js +1 -1
  15. package/dist/bundled/components/panel/StorySidePanel.vue_vue_type_script_setup_true_lang.js +1 -1
  16. package/dist/bundled/components/panel/StorySourceCode.js +1 -1
  17. package/dist/bundled/components/panel/StorySourceCode.vue_vue_type_script_setup_true_lang.js +2 -2
  18. package/dist/bundled/components/search/SearchItem.js +1 -1
  19. package/dist/bundled/components/search/SearchItem.vue_vue_type_script_setup_true_lang.js +2 -2
  20. package/dist/bundled/components/search/SearchModal.vue_vue_type_script_setup_true_lang.js +1 -1
  21. package/dist/bundled/components/search/SearchPane.vue_vue_type_script_setup_true_lang.js +1 -0
  22. package/dist/bundled/components/story/StoryResponsivePreview.js +1 -1
  23. package/dist/bundled/components/story/StoryResponsivePreview.vue_vue_type_script_setup_true_lang.js +69 -64
  24. package/dist/bundled/components/story/StoryVariantGrid.js +3 -1
  25. package/dist/bundled/components/story/StoryVariantGrid.vue_vue_type_script_setup_true_lang.js +82 -35
  26. package/dist/bundled/components/story/StoryVariantGridItem.js +1 -1
  27. package/dist/bundled/components/story/StoryVariantGridItem.vue_vue_type_script_setup_true_lang.js +20 -12
  28. package/dist/bundled/components/story/StoryVariantListItem.js +1 -1
  29. package/dist/bundled/components/story/StoryVariantListItem.vue_vue_type_script_setup_true_lang.js +2 -2
  30. package/dist/bundled/components/story/StoryVariantSinglePreviewNative.vue_vue_type_script_setup_true_lang.js +1 -1
  31. package/dist/bundled/components/story/StoryVariantSinglePreviewRemote.vue_vue_type_script_setup_true_lang.js +97 -32
  32. package/dist/bundled/components/story/StoryVariantSingleView.vue_vue_type_script_setup_true_lang.js +1 -1
  33. package/dist/bundled/components/toolbar/ToolbarBackground.js +1 -1
  34. package/dist/bundled/components/toolbar/ToolbarBackground.vue_vue_type_script_setup_true_lang.js +7 -7
  35. package/dist/bundled/components/tree/StoryGroup.vue_vue_type_script_setup_true_lang.js +1 -1
  36. package/dist/bundled/components/tree/StoryListFolder.js +1 -1
  37. package/dist/bundled/components/tree/StoryListFolder.vue_vue_type_script_setup_true_lang.js +2 -2
  38. package/dist/bundled/components/tree/StoryListItem.js +1 -1
  39. package/dist/bundled/components/tree/StoryListItem.vue_vue_type_script_setup_true_lang.js +3 -3
  40. package/dist/bundled/index.js +3 -0
  41. package/dist/bundled/sandbox.js +53 -24
  42. package/dist/bundled/util/const.js +2 -1
  43. package/dist/bundled/util/grid-cell-height.js +18 -0
  44. package/dist/bundled/util/grid-slots.js +64 -0
  45. package/dist/bundled/util/icons.generated.js +104 -0
  46. package/dist/bundled/util/state-bridge.js +75 -0
  47. package/dist/bundled/util/state.js +19 -1
  48. package/dist/style.css +7 -2
  49. package/package.json +12 -5
  50. package/src/__tests__/font.spec.ts +30 -0
  51. package/src/__tests__/grid-slots.spec.ts +84 -0
  52. package/src/__tests__/icons.spec.ts +26 -0
  53. package/src/__tests__/state-bridge.spec.ts +155 -0
  54. package/src/__tests__/state-clone.spec.ts +66 -0
  55. package/src/app/components/app/AppActions.vue +2 -2
  56. package/src/app/components/layout/LayoutModal.vue +2 -2
  57. package/src/app/components/layout/LayoutPane.vue +4 -4
  58. package/src/app/components/panel/StatePresets.vue +5 -5
  59. package/src/app/components/panel/StoryControls.vue +1 -1
  60. package/src/app/components/panel/StoryDocs.vue +1 -1
  61. package/src/app/components/panel/StoryEvent.vue +1 -1
  62. package/src/app/components/panel/StorySidePanel.vue +1 -1
  63. package/src/app/components/panel/StorySourceCode.vue +2 -2
  64. package/src/app/components/search/SearchItem.vue +1 -1
  65. package/src/app/components/search/SearchModal.vue +1 -1
  66. package/src/app/components/search/SearchPane.vue +8 -0
  67. package/src/app/components/story/StoryResponsivePreview.vue +85 -50
  68. package/src/app/components/story/StoryVariantGrid.vue +126 -49
  69. package/src/app/components/story/StoryVariantGridItem.vue +35 -10
  70. package/src/app/components/story/StoryVariantListItem.vue +1 -1
  71. package/src/app/components/story/StoryVariantSinglePreviewNative.vue +1 -1
  72. package/src/app/components/story/StoryVariantSinglePreviewRemote.vue +165 -35
  73. package/src/app/components/story/StoryVariantSingleView.vue +1 -1
  74. package/src/app/components/toolbar/ToolbarBackground.vue +4 -4
  75. package/src/app/components/tree/StoryGroup.vue +1 -1
  76. package/src/app/components/tree/StoryListFolder.vue +1 -1
  77. package/src/app/components/tree/StoryListItem.vue +1 -1
  78. package/src/app/index.ts +10 -0
  79. package/src/app/sandbox.ts +95 -31
  80. package/src/app/style/font.css +78 -0
  81. package/src/app/style/main.pcss +4 -1
  82. package/src/app/style/sandbox.css +3 -0
  83. package/src/app/util/const.ts +1 -0
  84. package/src/app/util/grid-cell-height.ts +16 -0
  85. package/src/app/util/grid-slots.ts +72 -0
  86. package/src/app/util/icons.generated.ts +9 -0
  87. package/src/app/util/state-bridge.ts +95 -0
  88. package/src/app/util/state.ts +19 -0
  89. package/src/bundle-main-dev.js +1 -0
  90. package/src/bundle-main.js +3 -0
@@ -18,8 +18,8 @@ var StoryListItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
18
18
  },
19
19
  setup(__props) {
20
20
  useCssVars((_ctx) => ({
21
- "v8be95bec": filePadding.value,
22
- "c827ed74": _ctx.story.iconColor
21
+ "v00f90f2e": filePadding.value,
22
+ "fbc82fb6": _ctx.story.iconColor
23
23
  }));
24
24
  const props = __props;
25
25
  const filePadding = computed(() => {
@@ -33,7 +33,7 @@ var StoryListItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
33
33
  return openBlock(), createElementBlock("div", {
34
34
  ref_key: "el",
35
35
  ref: el,
36
- "data-test-id": "story-list-item",
36
+ "data-testid": "story-list-item",
37
37
  class: "poveste-story-list-item"
38
38
  }, [createVNode(BaseListItemLink_default, {
39
39
  to: {
@@ -1,12 +1,15 @@
1
1
  import { router } from "./router.js";
2
2
  import App_default from "./App.js";
3
3
  import "./plugin.js";
4
+ import { iconCollections } from "./util/icons.generated.js";
4
5
  import { createApp } from "@poveste/vendors/vue";
6
+ import { addCollection } from "@poveste/vendors/iconify";
5
7
  import FloatingVue from "@poveste/vendors/floating-vue";
6
8
  import { createPinia } from "@poveste/vendors/pinia";
7
9
  import "virtual:$poveste-theme";
8
10
  //#region src/app/index.ts
9
11
  async function mountMainApp() {
12
+ for (const collection of iconCollections) addCollection(collection);
10
13
  const app = createApp(App_default);
11
14
  app.use(createPinia());
12
15
  app.use(FloatingVue, {
@@ -4,18 +4,28 @@ import { previewDarkClasses, resolvePreviewDark } from "./util/color-scheme.js";
4
4
  import { applyPreviewSettings, loadStoredPreviewSettings, receivedSettings } from "./util/preview-settings.js";
5
5
  import GenericMountStory_default from "./components/story/GenericMountStory.js";
6
6
  import { mapFile } from "./util/mapping.js";
7
- import "./plugin.js";
8
7
  import GenericRenderStory_default from "./components/story/GenericRenderStory.js";
8
+ import { createStateBridge } from "./util/state-bridge.js";
9
9
  import { toRawDeep } from "./util/state.js";
10
10
  import { usePreferredDark } from "@poveste/vendors/vue-use";
11
11
  import { computed, createApp, h, onMounted, ref, watch } from "@poveste/vendors/vue";
12
12
  import { createPinia } from "@poveste/vendors/pinia";
13
- import { files } from "virtual:$poveste-stories";
13
+ import { files, onUpdate } from "virtual:$poveste-stories";
14
14
  import { parseQuery } from "@poveste/vendors/vue-router";
15
- import { applyState } from "@poveste/shared";
16
15
  //#region src/app/sandbox.ts
17
16
  var query = parseQuery(window.location.search);
18
- var file = ref(mapFile(files.find((f) => f.id === query.storyId)));
17
+ var storyId = ref(typeof query.storyId === "string" ? query.storyId : null);
18
+ var variantId = ref(typeof query.variantId === "string" ? query.variantId : null);
19
+ var file = ref(null);
20
+ function resolveFile(list = files) {
21
+ const found = list.find((f) => f.id === storyId.value);
22
+ if (found && file.value?.story.id === found.id) return;
23
+ file.value = found ? mapFile(found) : null;
24
+ }
25
+ resolveFile();
26
+ onUpdate((newFiles) => {
27
+ if (!file.value) resolveFile(newFiles);
28
+ });
19
29
  var storedSettings = loadStoredPreviewSettings();
20
30
  if (storedSettings) applyPreviewSettings(storedSettings);
21
31
  if (window.parent && window.parent !== window) window.parent.postMessage({ type: PREVIEW_SETTINGS_REQUEST }, window.location.origin);
@@ -28,28 +38,39 @@ watch(previewDark, (value) => {
28
38
  for (const className of previewDarkClasses()) el.classList.toggle(className, value);
29
39
  }
30
40
  }, { immediate: true });
41
+ var pendingFrame = null;
42
+ var lastReportedHeight = -1;
31
43
  var app = createApp({
32
44
  name: "SandboxApp",
33
45
  setup() {
34
- const story = computed(() => file.value.story);
35
- const variant = computed(() => story.value?.variants.find((v) => v.id === query.variantId));
36
- let synced = false;
46
+ const story = computed(() => file.value?.story);
47
+ const variant = computed(() => story.value?.variants.find((v) => v.id === variantId.value));
48
+ const postState = (changes) => {
49
+ window.parent?.postMessage({
50
+ type: STATE_SYNC,
51
+ state: changes,
52
+ storyId: storyId.value,
53
+ variantId: variantId.value
54
+ });
55
+ };
56
+ let bridge = createStateBridge(postState);
37
57
  let mounted = false;
38
58
  window.addEventListener("message", (event) => {
39
59
  if (event.data?.type === "__poveste:state-sync") {
40
- if (!mounted) return;
41
- synced = applyState(variant.value.state, event.data.state);
60
+ if (!mounted || !variant.value) return;
61
+ bridge.receive(variant.value.state, event.data.state);
42
62
  } else if (event.data?.type === "__poveste:preview-settings-sync") applyPreviewSettings(event.data.settings);
43
- });
44
- watch(() => variant.value.state, (value) => {
45
- if (synced && mounted) {
46
- synced = false;
47
- return;
63
+ else if (event.data?.type === "__poveste:sandbox-retarget") {
64
+ bridge = createStateBridge(postState);
65
+ lastReportedHeight = -1;
66
+ variantId.value = typeof event.data.variantId === "string" ? event.data.variantId : null;
67
+ storyId.value = typeof event.data.storyId === "string" ? event.data.storyId : null;
68
+ resolveFile();
48
69
  }
49
- window.parent?.postMessage({
50
- type: STATE_SYNC,
51
- state: toRawDeep(value, true)
52
- });
70
+ });
71
+ watch(() => variant.value?.state, (value, previous) => {
72
+ if (!value || value !== previous) return;
73
+ bridge.send(toRawDeep(value, true));
53
74
  }, { deep: true });
54
75
  onMounted(() => {
55
76
  mounted = true;
@@ -60,14 +81,22 @@ var app = createApp({
60
81
  };
61
82
  },
62
83
  render() {
84
+ if (!file.value) return null;
63
85
  return [h("div", { class: "__poveste-sandbox-hidden" }, [h(GenericMountStory_default, {
64
86
  key: file.value.story.id,
65
- story: file.value.story
87
+ story: file.value.story,
88
+ targetVariantId: variantId.value
66
89
  })]), this.story && this.variant ? h(GenericRenderStory_default, {
90
+ key: `${this.story.id}/${this.variant.id}`,
67
91
  story: this.story,
68
92
  variant: this.variant,
69
93
  onReady: () => {
70
- window.parent?.postMessage({ type: SANDBOX_READY });
94
+ window.parent?.postMessage({
95
+ type: SANDBOX_READY,
96
+ storyId: this.story.id,
97
+ variantId: this.variant.id
98
+ });
99
+ scheduleReport();
71
100
  }
72
101
  }) : null];
73
102
  }
@@ -75,8 +104,6 @@ var app = createApp({
75
104
  app.use(createPinia());
76
105
  app.mount("#app");
77
106
  document.body.classList.add("__poveste-render-story", "__poveste-render-custom-controls");
78
- var pendingFrame = null;
79
- var lastReportedHeight = -1;
80
107
  function reportHeight() {
81
108
  pendingFrame = null;
82
109
  const renderRoot = document.querySelector(".__poveste-render-story");
@@ -85,7 +112,9 @@ function reportHeight() {
85
112
  lastReportedHeight = h;
86
113
  window.parent?.postMessage({
87
114
  type: SANDBOX_HEIGHT,
88
- h
115
+ h,
116
+ storyId: storyId.value,
117
+ variantId: variantId.value
89
118
  }, window.location.origin);
90
119
  }
91
120
  function scheduleReport() {
@@ -94,5 +123,5 @@ function scheduleReport() {
94
123
  }
95
124
  new ResizeObserver(scheduleReport).observe(document.body);
96
125
  requestAnimationFrame(scheduleReport);
97
- if (import.meta.hot) {}
126
+ if (import.meta.env.DEV && import.meta.hot) import("./plugin.js").then(({ setupPluginApi }) => setupPluginApi());
98
127
  //#endregion
@@ -5,5 +5,6 @@ var EVENT_SEND = "__poveste:event";
5
5
  var PREVIEW_SETTINGS_SYNC = "__poveste:preview-settings-sync";
6
6
  var PREVIEW_SETTINGS_REQUEST = "__poveste:preview-settings-request";
7
7
  var SANDBOX_HEIGHT = "__poveste:sandbox-height";
8
+ var SANDBOX_RETARGET = "__poveste:sandbox-retarget";
8
9
  //#endregion
9
- export { EVENT_SEND, PREVIEW_SETTINGS_REQUEST, PREVIEW_SETTINGS_SYNC, SANDBOX_HEIGHT, SANDBOX_READY, STATE_SYNC };
10
+ export { EVENT_SEND, PREVIEW_SETTINGS_REQUEST, PREVIEW_SETTINGS_SYNC, SANDBOX_HEIGHT, SANDBOX_READY, SANDBOX_RETARGET, STATE_SYNC };
@@ -0,0 +1,18 @@
1
+ import { shallowRef } from "@poveste/vendors/vue";
2
+ //#region src/app/util/grid-cell-height.ts
3
+ /**
4
+ * The first height reported by any cell of a story's grid.
5
+ *
6
+ * Sandboxes boot one at a time: on the 1000-variant grid the last cell reports
7
+ * ~15s after the first. Until a cell reports it has nothing to size itself by,
8
+ * so the grid spends that time as a wall of stubs resizing one by one. Variants
9
+ * of one story are usually near-identical in size, which makes the first height
10
+ * to arrive a far better guess than a fixed floor.
11
+ *
12
+ * Keyed by story so the next one doesn't inherit it. Module scope rather than a
13
+ * component ref because `<script setup>` bodies run per instance — a ref
14
+ * declared there would be one per cell, and never shared.
15
+ */
16
+ var firstReportedHeight = shallowRef(null);
17
+ //#endregion
18
+ export { firstReportedHeight };
@@ -0,0 +1,64 @@
1
+ //#region src/app/util/grid-slots.ts
2
+ /**
3
+ * Hand the visible variants to slots. Assignment is sticky: a variant that is
4
+ * still visible keeps its slot, so a one-row scroll retargets one row's worth of
5
+ * cells. A variant that scrolled out stays in its slot, hidden, until a new one
6
+ * needs it — unmounting would throw the warm realm away, and the window wobbles
7
+ * by a row while a scroll settles.
8
+ */
9
+ function assignSlots(slots, storyId, visible) {
10
+ const position = new Map(visible.map((v, i) => [v.id, i]));
11
+ const next = slots.map((slot) => slot.storyId === storyId && position.has(slot.variant.id) ? {
12
+ ...slot,
13
+ visible: true,
14
+ order: position.get(slot.variant.id)
15
+ } : {
16
+ ...slot,
17
+ visible: false,
18
+ order: 0
19
+ });
20
+ const placed = new Set(next.filter((s) => s.visible).map((s) => s.variant.id));
21
+ for (const [i, variant] of visible.entries()) {
22
+ if (placed.has(variant.id)) continue;
23
+ const slot = {
24
+ storyId,
25
+ variant,
26
+ visible: true,
27
+ order: i
28
+ };
29
+ const free = next.findIndex((s) => !s.visible);
30
+ if (free === -1) next.push(slot);
31
+ else next[free] = slot;
32
+ }
33
+ return next;
34
+ }
35
+ /**
36
+ * Let idle slots go once the window has settled. A hidden slot is a realm that
37
+ * keeps running — timers, observers, a listener on every message — and with
38
+ * sticky assignment alone the pool would be the largest window ever seen.
39
+ *
40
+ * Slots are keyed by index, so only the tail can be dropped without moving
41
+ * anything. Trailing hidden slots go; interior ones stay as the spare for the
42
+ * next scroll — until they outnumber the visible ones, when the pool is
43
+ * compacted onto its first slots: a visible slot past that point moves down
44
+ * into a hidden one, which is one retarget, and the rest is cut.
45
+ */
46
+ function trimSlots(slots) {
47
+ const visibleCount = slots.filter((s) => s.visible).length;
48
+ const hiddenCount = slots.length - visibleCount;
49
+ if (hiddenCount === 0) return slots;
50
+ let next = slots;
51
+ if (hiddenCount > visibleCount) {
52
+ const kept = slots.slice(0, visibleCount).map((s) => s.visible ? s : void 0);
53
+ for (const slot of slots.slice(visibleCount)) {
54
+ if (!slot.visible) continue;
55
+ kept[kept.indexOf(void 0)] = slot;
56
+ }
57
+ next = kept;
58
+ }
59
+ let end = next.length;
60
+ while (end > 0 && !next[end - 1].visible) end--;
61
+ return end === next.length ? next : next.slice(0, end);
62
+ }
63
+ //#endregion
64
+ export { assignSlots, trimSlots };
@@ -0,0 +1,104 @@
1
+ //#region src/app/util/icons.generated.ts
2
+ var iconCollections = [
3
+ {
4
+ "prefix": "carbon",
5
+ "icons": {
6
+ "add-alt": { "body": "<path fill=\"currentColor\" d=\"M16 4c6.6 0 12 5.4 12 12s-5.4 12-12 12S4 22.6 4 16S9.4 4 16 4m0-2C8.3 2 2 8.3 2 16s6.3 14 14 14s14-6.3 14-14S23.7 2 16 2\"/><path fill=\"currentColor\" d=\"M24 15h-7V8h-2v7H8v2h7v7h2v-7h7z\"/>" },
7
+ "area": { "body": "<path fill=\"currentColor\" d=\"M27 22.142V9.858A3.992 3.992 0 1 0 22.142 5H9.858A3.992 3.992 0 1 0 5 9.858v12.284A3.992 3.992 0 1 0 9.858 27h12.284A3.992 3.992 0 1 0 27 22.142M26 4a2 2 0 1 1-2 2a2 2 0 0 1 2-2M4 6a2 2 0 1 1 2 2a2 2 0 0 1-2-2m2 22a2 2 0 1 1 2-2a2 2 0 0 1-2 2m16.142-3H9.858A4 4 0 0 0 7 22.142V9.858A4 4 0 0 0 9.858 7h12.284A4 4 0 0 0 25 9.858v12.284A3.99 3.99 0 0 0 22.142 25M26 28a2 2 0 1 1 2-2a2.003 2.003 0 0 1-2 2\"/>" },
8
+ "audio-console": { "body": "<path fill=\"currentColor\" d=\"M28 14.005h-1v-12h-2v12h-1a2 2 0 0 0-2 2v2a2 2 0 0 0 2 2h1v10h2v-10h1a2.003 2.003 0 0 0 2-2v-2a2 2 0 0 0-2-2m0 4h-4v-2h4Zm-10-12h-1v-4h-2v4h-1a2 2 0 0 0-2 2v2a2 2 0 0 0 2 2h1v18h2v-18h1a2 2 0 0 0 2-2v-2a2 2 0 0 0-2-2m0 4h-4v-2h4Zm-10 10H7v-18H5v18H4a2 2 0 0 0-2 2v2a2 2 0 0 0 2 2h1v4h2v-4h1a2 2 0 0 0 2-2v-2a2 2 0 0 0-2-2m0 4H4v-2h4Z\"/>" },
9
+ "bring-forward": { "body": "<path fill=\"currentColor\" d=\"M12 15h-2v-3a2 2 0 0 1 2-2h3v2h-3Zm3 15h-3a2 2 0 0 1-2-2v-3h2v3h3Zm3-2h4v2h-4zm10 2h-3v-2h3v-3h2v3a2 2 0 0 1-2 2M10 18h2v4h-2zm18 0h2v4h-2zm2-3h-2v-3h-3v-2h3a2 2 0 0 1 2 2Zm-12-5h4v2h-4z\"/><path fill=\"currentColor\" d=\"M8 22H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v4h-2V4H4v16h4Z\"/>" },
10
+ "caret-down": { "body": "<path fill=\"currentColor\" d=\"m24 12l-8 10l-8-10z\"/>" },
11
+ "caret-right": { "body": "<path fill=\"currentColor\" d=\"m12 8l10 8l-10 8z\"/>" },
12
+ "checkbox": { "body": "<path fill=\"currentColor\" d=\"M26 4H6a2 2 0 0 0-2 2v20a2 2 0 0 0 2 2h20a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2M6 26V6h20v20Z\"/>" },
13
+ "checkmark": { "body": "<path fill=\"currentColor\" d=\"m13 24l-9-9l1.414-1.414L13 21.171L26.586 7.586L28 9z\"/>" },
14
+ "chevron-down": { "body": "<path fill=\"currentColor\" d=\"M16 22L6 12l1.4-1.4l8.6 8.6l8.6-8.6L26 12z\"/>" },
15
+ "chevron-right": { "body": "<path fill=\"currentColor\" d=\"M22 16L12 26l-1.4-1.4l8.6-8.6l-8.6-8.6L12 6z\"/>" },
16
+ "chevron-sort": { "body": "<path fill=\"currentColor\" d=\"m16 28l-7-7l1.41-1.41L16 25.17l5.59-5.58L23 21zm0-24l7 7l-1.41 1.41L16 6.83l-5.59 5.58L9 11z\"/>" },
17
+ "close": { "body": "<path fill=\"currentColor\" d=\"M17.414 16L24 9.414L22.586 8L16 14.586L9.414 8L8 9.414L14.586 16L8 22.586L9.414 24L16 17.414L22.586 24L24 22.586z\"/>" },
18
+ "code": { "body": "<path fill=\"currentColor\" d=\"m31 16l-7 7l-1.41-1.41L28.17 16l-5.58-5.59L24 9zM1 16l7-7l1.41 1.41L3.83 16l5.58 5.59L8 23zm11.42 9.484L17.64 6l1.932.517L14.352 26z\"/>" },
19
+ "code-hide": { "body": "<path fill=\"currentColor\" d=\"m17.713 13.471l1.863-6.953L17.645 6l-1.565 5.838zm6.494 6.494l1.414 1.414L31 16l-7-7l-1.414 1.414L28.172 16zM30 28.586L3.414 2L2 3.414l5.793 5.793L1 16l7 7l1.414-1.414L3.828 16l5.379-5.379l5.677 5.677l-2.461 9.184l1.932.518l2.162-8.069L28.586 30z\"/>" },
20
+ "color-palette": { "body": "<circle cx=\"10\" cy=\"12\" r=\"2\" fill=\"currentColor\"/><circle cx=\"16\" cy=\"9\" r=\"2\" fill=\"currentColor\"/><circle cx=\"22\" cy=\"12\" r=\"2\" fill=\"currentColor\"/><circle cx=\"23\" cy=\"18\" r=\"2\" fill=\"currentColor\"/><circle cx=\"19\" cy=\"23\" r=\"2\" fill=\"currentColor\"/><path fill=\"currentColor\" d=\"M16.54 2A14 14 0 0 0 2 16a4.82 4.82 0 0 0 6.09 4.65l1.12-.31a3 3 0 0 1 3.79 2.9V27a3 3 0 0 0 3 3a14 14 0 0 0 14-14.54A14.05 14.05 0 0 0 16.54 2m8.11 22.31A11.93 11.93 0 0 1 16 28a1 1 0 0 1-1-1v-3.76a5 5 0 0 0-5-5a5 5 0 0 0-1.33.18l-1.12.31A2.82 2.82 0 0 1 4 16A12 12 0 0 1 16.47 4A12.18 12.18 0 0 1 28 15.53a11.9 11.9 0 0 1-3.35 8.79Z\"/>" },
21
+ "condition-wait-point": { "body": "<path fill=\"currentColor\" d=\"m8 16l8-8l8 8l-8 8z\"/><path fill=\"currentColor\" d=\"M16 4A12 12 0 1 1 4 16A12.014 12.014 0 0 1 16 4m0-2a14 14 0 1 0 14 14A14 14 0 0 0 16 2\"/>" },
22
+ "copy-file": { "body": "<path fill=\"currentColor\" d=\"m27.4 14.7l-6.1-6.1C21 8.2 20.5 8 20 8h-8c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V16.1c0-.5-.2-1-.6-1.4M20 10l5.9 6H20zm-8 18V10h6v6c0 1.1.9 2 2 2h6v10z\"/><path fill=\"currentColor\" d=\"M6 18H4V4c0-1.1.9-2 2-2h14v2H6z\"/>" },
23
+ "cube": { "body": "<path fill=\"currentColor\" d=\"m28.504 8.136l-12-7a1 1 0 0 0-1.008 0l-12 7A1 1 0 0 0 3 9v14a1 1 0 0 0 .496.864l12 7a1 1 0 0 0 1.008 0l12-7A1 1 0 0 0 29 23V9a1 1 0 0 0-.496-.864M16 3.158L26.016 9L16 14.842L5.984 9ZM5 10.74l10 5.833V28.26L5 22.426Zm12 17.52V16.574l10-5.833v11.685Z\"/>" },
24
+ "cube-view": { "body": "<circle cx=\"16\" cy=\"16\" r=\"2\" fill=\"currentColor\"/><path fill=\"currentColor\" d=\"M23.777 15.479A8.64 8.64 0 0 0 16 10a8.64 8.64 0 0 0-7.777 5.479L8 16l.223.522A8.64 8.64 0 0 0 16 22a8.64 8.64 0 0 0 7.777-5.478L24 16ZM16 20a4 4 0 1 1 4-4a4.005 4.005 0 0 1-4 4\"/><path fill=\"currentColor\" d=\"m28.504 8.136l-12-7a1 1 0 0 0-1.008 0l-12 7A1 1 0 0 0 3 9v14a1 1 0 0 0 .496.864l12 7a1 1 0 0 0 1.008 0l12-7A1 1 0 0 0 29 23V9a1 1 0 0 0-.496-.864M27 22.426l-11 6.416l-11-6.416V9.574l11-6.416l11 6.416Z\"/>" },
25
+ "data-vis-1": { "body": "<path fill=\"currentColor\" d=\"M26 22a3.96 3.96 0 0 0-2.02.567l-3.813-3.814a4.965 4.965 0 0 0 0-5.506l2.547-2.547A3.028 3.028 0 1 0 21.3 9.286l-2.547 2.547a4.965 4.965 0 0 0-5.506 0L9.433 8.019A3.96 3.96 0 0 0 10 6a4 4 0 1 0-4 4a3.96 3.96 0 0 0 2.02-.567l3.813 3.814a4.965 4.965 0 0 0 0 5.506l-3.814 3.814A3.96 3.96 0 0 0 6 22a4 4 0 1 0 4 4a3.96 3.96 0 0 0-.567-2.02l3.814-3.813a5 5 0 0 0 1.753.732v3.285a3 3 0 1 0 2 0v-3.285a5 5 0 0 0 1.753-.732l3.814 3.814A3.96 3.96 0 0 0 22 26a4 4 0 1 0 4-4m-10-9a3 3 0 1 1-3 3a3.003 3.003 0 0 1 3-3M4 6a2 2 0 1 1 2 2a2 2 0 0 1-2-2m2 22a2 2 0 1 1 2-2a2 2 0 0 1-2 2m20 0a2 2 0 1 1 2-2a2.003 2.003 0 0 1-2 2\"/>" },
26
+ "devices": { "body": "<path fill=\"currentColor\" d=\"M10 30H4a2 2 0 0 1-2-2V16a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2M4 16v12h6V16Z\"/><path fill=\"currentColor\" d=\"M28 4H6a2 2 0 0 0-2 2v6h2V6h22v14H14v2h2v4h-2v2h9v-2h-5v-4h10a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2\"/>" },
27
+ "document": { "body": "<path fill=\"currentColor\" d=\"m25.7 9.3l-7-7c-.2-.2-.4-.3-.7-.3H8c-1.1 0-2 .9-2 2v24c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V10c0-.3-.1-.5-.3-.7M18 4.4l5.6 5.6H18zM24 28H8V4h8v6c0 1.1.9 2 2 2h6z\"/><path fill=\"currentColor\" d=\"M10 22h12v2H10zm0-6h12v2H10z\"/>" },
28
+ "document-blank": { "body": "<path fill=\"currentColor\" d=\"m25.7 9.3l-7-7A.9.9 0 0 0 18 2H8a2.006 2.006 0 0 0-2 2v24a2.006 2.006 0 0 0 2 2h16a2.006 2.006 0 0 0 2-2V10a.9.9 0 0 0-.3-.7M18 4.4l5.6 5.6H18ZM24 28H8V4h8v6a2.006 2.006 0 0 0 2 2h6Z\"/>" },
29
+ "document-unknown": { "body": "<circle cx=\"9\" cy=\"28.5\" r=\"1.5\" fill=\"currentColor\"/><path fill=\"currentColor\" d=\"M10 25H8v-4h2a2 2 0 0 0 0-4H8a2 2 0 0 0-2 2v.5H4V19a4.005 4.005 0 0 1 4-4h2a4 4 0 0 1 0 8Z\"/><path fill=\"currentColor\" d=\"m27.7 9.3l-7-7A.9.9 0 0 0 20 2H10a2.006 2.006 0 0 0-2 2v8h2V4h8v6a2.006 2.006 0 0 0 2 2h6v16H14v2h12a2.006 2.006 0 0 0 2-2V10a.91.91 0 0 0-.3-.7M20 10V4.4l5.6 5.6Z\"/>" },
30
+ "edit": { "body": "<path fill=\"currentColor\" d=\"M2 26h28v2H2zM25.4 9c.8-.8.8-2 0-2.8l-3.6-3.6c-.8-.8-2-.8-2.8 0l-15 15V24h6.4zm-5-5L24 7.6l-3 3L17.4 7zM6 22v-3.6l10-10l3.6 3.6l-10 10z\"/>" },
31
+ "erase": { "body": "<path fill=\"currentColor\" d=\"M7 27h23v2H7zm20.38-16.49l-7.93-7.92a2 2 0 0 0-2.83 0l-14 14a2 2 0 0 0 0 2.83L7.13 24h9.59l10.66-10.66a2 2 0 0 0 0-2.83M15.89 22H8l-4-4l6.31-6.31l7.93 7.92Zm3.76-3.76l-7.92-7.93L18 4l8 7.93Z\"/>" },
32
+ "event-schedule": { "body": "<path fill=\"currentColor\" d=\"M21 30a8 8 0 1 1 8-8a8 8 0 0 1-8 8m0-14a6 6 0 1 0 6 6a6 6 0 0 0-6-6\"/><path fill=\"currentColor\" d=\"M22.59 25L20 22.41V18h2v3.59l2 2z\"/><path fill=\"currentColor\" d=\"M28 6a2 2 0 0 0-2-2h-4V2h-2v2h-8V2h-2v2H6a2 2 0 0 0-2 2v20a2 2 0 0 0 2 2h4v-2H6V6h4v2h2V6h8v2h2V6h4v6h2Z\"/>" },
33
+ "flash": { "body": "<path fill=\"currentColor\" d=\"M11.61 29.92a1 1 0 0 1-.6-1.07L12.83 17H8a1 1 0 0 1-1-1.23l3-13A1 1 0 0 1 11 2h10a1 1 0 0 1 .78.37a1 1 0 0 1 .2.85L20.25 11H25a1 1 0 0 1 .9.56a1 1 0 0 1-.11 1l-13 17A1 1 0 0 1 12 30a1.1 1.1 0 0 1-.39-.08M17.75 13l2-9H11.8L9.26 15h5.91l-1.59 10.28L23 13Z\"/>" },
34
+ "help": { "body": "<path fill=\"currentColor\" d=\"M16 2a14 14 0 1 0 14 14A14 14 0 0 0 16 2m0 26a12 12 0 1 1 12-12a12 12 0 0 1-12 12\"/><circle cx=\"16\" cy=\"23.5\" r=\"1.5\" fill=\"currentColor\"/><path fill=\"currentColor\" d=\"M17 8h-1.5a4.49 4.49 0 0 0-4.5 4.5v.5h2v-.5a2.5 2.5 0 0 1 2.5-2.5H17a2.5 2.5 0 0 1 0 5h-2v4.5h2V17a4.5 4.5 0 0 0 0-9\"/>" },
35
+ "launch": { "body": "<path fill=\"currentColor\" d=\"M26 28H6a2.003 2.003 0 0 1-2-2V6a2.003 2.003 0 0 1 2-2h10v2H6v20h20V16h2v10a2.003 2.003 0 0 1-2 2\"/><path fill=\"currentColor\" d=\"M20 2v2h6.586L18 12.586L19.414 14L28 5.414V12h2V2z\"/>" },
36
+ "moon": { "body": "<path fill=\"currentColor\" d=\"M13.503 5.414a15.076 15.076 0 0 0 11.593 18.194a11.1 11.1 0 0 1-7.975 3.39c-.138 0-.278.005-.418 0a11.094 11.094 0 0 1-3.2-21.584M14.98 3a1 1 0 0 0-.175.016a13.096 13.096 0 0 0 1.825 25.981c.164.006.328 0 .49 0a13.07 13.07 0 0 0 10.703-5.555a1.01 1.01 0 0 0-.783-1.565A13.08 13.08 0 0 1 15.89 4.38A1.015 1.015 0 0 0 14.98 3\"/>" },
37
+ "open-panel-filled-bottom": { "body": "<path fill=\"currentColor\" d=\"M28 4H4a2 2 0 0 0-2 2v20a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2m0 2v12H4V6Z\"/>" },
38
+ "open-panel-filled-left": { "body": "<path fill=\"currentColor\" d=\"M28 4H4a2 2 0 0 0-2 2v20a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2m0 22H12V6h16Z\"/>" },
39
+ "open-panel-filled-right": { "body": "<path fill=\"currentColor\" d=\"M28 4H4a2 2 0 0 0-2 2v20a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2M4 6h16v20H4Z\"/>" },
40
+ "pan-horizontal": { "body": "<path fill=\"currentColor\" d=\"m24 10l-1.414 1.414L26.172 15H5.828l3.586-3.586L8 10l-6 6l6 6l1.414-1.414L5.828 17h20.344l-3.586 3.586L24 22l6-6z\"/>" },
41
+ "pan-vertical": { "body": "<path fill=\"currentColor\" d=\"m10 8l1.414 1.414L15 5.828v20.344l-3.586-3.586L10 24l6 6l6-6l-1.414-1.414L17 26.172V5.828l3.586 3.586L22 8l-6-6z\"/>" },
42
+ "panel-expansion": { "body": "<path fill=\"currentColor\" d=\"M12 6H6a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2m-6 8V8h6v6Zm20-8h-6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2m-6 18V8h6v16Z\"/>" },
43
+ "reset": { "body": "<path fill=\"currentColor\" d=\"M18 28A12 12 0 1 0 6 16v6.2l-3.6-3.6L1 20l6 6l6-6l-1.4-1.4L8 22.2V16a10 10 0 1 1 10 10Z\"/>" },
44
+ "save": { "body": "<path fill=\"currentColor\" d=\"m27.71 9.29l-5-5A1 1 0 0 0 22 4H6a2 2 0 0 0-2 2v20a2 2 0 0 0 2 2h20a2 2 0 0 0 2-2V10a1 1 0 0 0-.29-.71M12 6h8v4h-8Zm8 20h-8v-8h8Zm2 0v-8a2 2 0 0 0-2-2h-8a2 2 0 0 0-2 2v8H6V6h4v4a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V6.41l4 4V26Z\"/>" },
45
+ "screen": { "body": "<path fill=\"currentColor\" d=\"M28 4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8v4H8v2h16v-2h-4v-4h8a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2M18 28h-4v-4h4Zm10-6H4V6h24Z\"/>" },
46
+ "script-reference": { "body": "<path fill=\"currentColor\" d=\"M4 20v2h4.586L2 28.586L3.414 30L10 23.414V28h2v-8zm23.17 6l-2.58 2.58L26 30l4-4l-4-4l-1.42 1.41zm-8.34 0l2.58-2.58L20 22l-4 4l4 4l1.42-1.41zM25.7 9.3l-7-7A.9.9 0 0 0 18 2H8a2.006 2.006 0 0 0-2 2v12h2V4h8v6a2.006 2.006 0 0 0 2 2h6v6h2v-8a.91.91 0 0 0-.3-.7M18 10V4.4l5.6 5.6Z\"/>" },
47
+ "search": { "body": "<path fill=\"currentColor\" d=\"m29 27.586l-7.552-7.552a11.018 11.018 0 1 0-1.414 1.414L27.586 29ZM4 13a9 9 0 1 1 9 9a9.01 9.01 0 0 1-9-9\"/>" },
48
+ "shape-except": { "body": "<path fill=\"currentColor\" d=\"M28 10h-6V4a2 2 0 0 0-2-2H4a2.003 2.003 0 0 0-2 2v16a2.003 2.003 0 0 0 2 2h6v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V12a2 2 0 0 0-2-2M12 20v-8h8v8ZM3.999 4H20v6h-8a2 2 0 0 0-2 2v8H4Z\"/>" },
49
+ "software-resource-reference": { "body": "<path fill=\"currentColor\" d=\"m6.899 10.283l3.394-3.394l1.414 1.414l-3.394 3.394zM4.9 19.7l-2.3-2.3C2.2 17 2 16.5 2 16s.2-1 .6-1.4l2.3-2.3l1.4 1.4L4 16l2.3 2.3zm1.989 2.007l1.414-1.414l3.394 3.394l-1.414 1.414zM16 30c-.5 0-1-.2-1.4-.6l-2.3-2.3l1.4-1.4L16 28l2.3-2.3l1.4 1.4l-2.3 2.3c-.4.4-.9.6-1.4.6m4.293-6.303l3.394-3.394l1.414 1.414l-3.394 3.394zM27.1 19.7l-1.4-1.4L28 16l-2.3-2.3l1.4-1.4l2.3 2.3c.4.4.6.9.6 1.4s-.2 1-.6 1.4zM20.303 8.313l1.414-1.414l3.394 3.394l-1.414 1.414zM16 2c-.5 0-1 .2-1.4.6l-2.3 2.3l1.4 1.4L16 4l2.3 2.3l1.4-1.4l-2.3-2.3C17 2.2 16.5 2 16 2\"/>" },
50
+ "sun": { "body": "<path fill=\"currentColor\" d=\"M16 12.005a4 4 0 1 1-4 4a4.005 4.005 0 0 1 4-4m0-2a6 6 0 1 0 6 6a6 6 0 0 0-6-6M5.394 6.813L6.81 5.399l3.505 3.506L8.9 10.319zM2 15.005h5v2H2zm3.394 10.193L8.9 21.692l1.414 1.414l-3.505 3.506zM15 25.005h2v5h-2zm6.687-1.9l1.414-1.414l3.506 3.506l-1.414 1.414zm3.313-8.1h5v2h-5zm-3.313-6.101l3.506-3.506l1.414 1.414l-3.506 3.506zM15 2.005h2v5h-2z\"/>" },
51
+ "text-color": { "body": "<path fill=\"currentColor\" d=\"M22 21h2L17 4h-2L8 21h2l1.61-4h8.74Zm-9.57-6l3.44-8.37h.26L19.54 15ZM6 24h20v4H6z\"/>" },
52
+ "text-font": { "body": "<path fill=\"currentColor\" d=\"M25 12h-5v2h5a1 1 0 0 1 1 1v2h-4a3.003 3.003 0 0 0-3 3v1a3.003 3.003 0 0 0 3 3h6v-9a3.003 3.003 0 0 0-3-3m-3 10a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h4v3Zm-6 2h2L12 7h-2L4 24h2l1.694-5h6.613Zm-7.629-7l2.497-7.371h.266L13.63 17Z\"/>" },
53
+ "trash-can": { "body": "<path fill=\"currentColor\" d=\"M12 12h2v12h-2zm6 0h2v12h-2z\"/><path fill=\"currentColor\" d=\"M4 6v2h2v20a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8h2V6Zm4 22V8h16v20Zm4-26h8v2h-8z\"/>" },
54
+ "view": { "body": "<path fill=\"currentColor\" d=\"M30.94 15.66A16.69 16.69 0 0 0 16 5A16.69 16.69 0 0 0 1.06 15.66a1 1 0 0 0 0 .68A16.69 16.69 0 0 0 16 27a16.69 16.69 0 0 0 14.94-10.66a1 1 0 0 0 0-.68M16 25c-5.3 0-10.9-3.93-12.93-9C5.1 10.93 10.7 7 16 7s10.9 3.93 12.93 9C26.9 21.07 21.3 25 16 25\"/><path fill=\"currentColor\" d=\"M16 10a6 6 0 1 0 6 6a6 6 0 0 0-6-6m0 10a4 4 0 1 1 4-4a4 4 0 0 1-4 4\"/>" },
55
+ "view-off": { "body": "<path fill=\"currentColor\" d=\"m5.24 22.51l1.43-1.42A14.06 14.06 0 0 1 3.07 16C5.1 10.93 10.7 7 16 7a12.4 12.4 0 0 1 4 .72l1.55-1.56A14.7 14.7 0 0 0 16 5A16.69 16.69 0 0 0 1.06 15.66a1 1 0 0 0 0 .68a16 16 0 0 0 4.18 6.17\"/><path fill=\"currentColor\" d=\"M12 15.73a4 4 0 0 1 3.7-3.7l1.81-1.82a6 6 0 0 0-7.33 7.33Zm18.94-.07a16.4 16.4 0 0 0-5.74-7.44L30 3.41L28.59 2L2 28.59L3.41 30l5.1-5.1A15.3 15.3 0 0 0 16 27a16.69 16.69 0 0 0 14.94-10.66a1 1 0 0 0 0-.68M20 16a4 4 0 0 1-6 3.44L19.44 14a4 4 0 0 1 .56 2m-4 9a13.05 13.05 0 0 1-6-1.58l2.54-2.54a6 6 0 0 0 8.35-8.35l2.87-2.87A14.54 14.54 0 0 1 28.93 16C26.9 21.07 21.3 25 16 25\"/>" },
56
+ "warning-alt": { "body": "<path fill=\"currentColor\" d=\"M16 23a1.5 1.5 0 1 0 1.5 1.5A1.5 1.5 0 0 0 16 23m-1-11h2v9h-2z\"/><path fill=\"currentColor\" d=\"M29 30H3a1 1 0 0 1-.887-1.461l13-25a1 1 0 0 1 1.774 0l13 25A1 1 0 0 1 29 30M4.65 28h22.7l.001-.003L16.002 6.17h-.004L4.648 27.997Z\"/>" }
57
+ },
58
+ "lastModified": 1785496919,
59
+ "aliases": { "software-resource-resource": { "parent": "software-resource-reference" } },
60
+ "width": 32,
61
+ "height": 32
62
+ },
63
+ {
64
+ "prefix": "fluent",
65
+ "icons": {
66
+ "text-paragraph-direction-left-16-regular": {
67
+ "body": "<path fill=\"currentColor\" d=\"M9 3a2.5 2.5 0 0 0 0 5h1V3zm2 0v10.5a.5.5 0 0 1-1 0V9H9a3.5 3.5 0 1 1 0-7h4.5a.5.5 0 0 1 0 1H13v10.5a.5.5 0 0 1-1 0V3zM3.854 6.146a.5.5 0 0 1 0 .708L2.707 8l1.147 1.146a.5.5 0 1 1-.708.708l-1.5-1.5a.5.5 0 0 1 0-.708l1.5-1.5a.5.5 0 0 1 .708 0\"/>",
68
+ "width": 16,
69
+ "height": 16
70
+ },
71
+ "text-paragraph-direction-right-16-regular": {
72
+ "body": "<path fill=\"currentColor\" d=\"M9 3a2.5 2.5 0 0 0 0 5h1V3zm2 0v10.5a.5.5 0 0 1-1 0V9H9a3.5 3.5 0 1 1 0-7h4.5a.5.5 0 0 1 0 1H13v10.5a.5.5 0 0 1-1 0V3zM2.146 6.146a.5.5 0 0 1 .708 0l1.5 1.5a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708-.708L3.293 8L2.146 6.854a.5.5 0 0 1 0-.708\"/>",
73
+ "width": 16,
74
+ "height": 16
75
+ }
76
+ },
77
+ "lastModified": 1786851660,
78
+ "width": 20,
79
+ "height": 20
80
+ },
81
+ {
82
+ "prefix": "mdi",
83
+ "icons": {
84
+ "drag-horizontal-variant": { "body": "<path fill=\"currentColor\" d=\"M21 11H3V9h18zm0 2H3v2h18z\"/>" },
85
+ "drag-vertical-variant": { "body": "<path fill=\"currentColor\" d=\"M11 21H9V3h2zm4-18h-2v18h2z\"/>" },
86
+ "tailwind": { "body": "<path fill=\"currentColor\" d=\"M12 6c-2.67 0-4.33 1.33-5 4c1-1.33 2.17-1.83 3.5-1.5c.76.19 1.31.74 1.91 1.35c.98 1 2.09 2.15 4.59 2.15c2.67 0 4.33-1.33 5-4c-1 1.33-2.17 1.83-3.5 1.5c-.76-.19-1.3-.74-1.91-1.35C15.61 7.15 14.5 6 12 6m-5 6c-2.67 0-4.33 1.33-5 4c1-1.33 2.17-1.83 3.5-1.5c.76.19 1.3.74 1.91 1.35C8.39 16.85 9.5 18 12 18c2.67 0 4.33-1.33 5-4c-1 1.33-2.17 1.83-3.5 1.5c-.76-.19-1.3-.74-1.91-1.35C10.61 13.15 9.5 12 7 12\"/>" }
87
+ },
88
+ "lastModified": 1737398331,
89
+ "width": 24,
90
+ "height": 24
91
+ },
92
+ {
93
+ "prefix": "ri",
94
+ "icons": {
95
+ "add-line": { "body": "<path fill=\"currentColor\" d=\"M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z\"/>" },
96
+ "subtract-line": { "body": "<path fill=\"currentColor\" d=\"M5 11v2h14v-2z\"/>" }
97
+ },
98
+ "lastModified": 1770712905,
99
+ "width": 24,
100
+ "height": 24
101
+ }
102
+ ];
103
+ //#endregion
104
+ export { iconCollections };
@@ -0,0 +1,75 @@
1
+ import { applyState, createStateBaseline, isEquivalent } from "@poveste/shared";
2
+ //#region src/app/util/state-bridge.ts
3
+ /**
4
+ * One end of the state bridge between the app and a sandbox iframe.
5
+ *
6
+ * Both ends used to send the *whole* state and tell an echo from a real edit
7
+ * with a boolean meaning "ignore the next firing, it is mine". Two writes in one
8
+ * task then put two messages in flight, each carrying its sender's stale copy of
9
+ * the key the other just changed, and each end applied the other's stale copy
10
+ * over its own fresh one. The two sides ended up disagreeing outright — the
11
+ * controls panel showing one value, the story another, with nothing left in
12
+ * flight to settle it. Same defect as #96 in `plugin-vue`, one transport out.
13
+ *
14
+ * So each end keeps a baseline of what both sides have agreed on, and sends only
15
+ * what its own side changed since. Nothing stale is ever sent, so nothing stale
16
+ * can be applied — and an echo diffs to nothing, which is what retires the flag.
17
+ *
18
+ * Unlike `plugin-vue`, the two ends cannot share one baseline: they are in
19
+ * different documents. Each holds its own and records what arrives, which is
20
+ * what `record` is for.
21
+ */
22
+ function createStateBridge(post) {
23
+ const baseline = createStateBaseline();
24
+ return {
25
+ /**
26
+ * This side's state moved. Sends what changed, or nothing if the move was
27
+ * this end applying what the far end sent.
28
+ */
29
+ send(next) {
30
+ const changes = baseline.take(next);
31
+ if (changes) post(changes);
32
+ },
33
+ /** The far end sent changes: apply them, and agree to the ones that landed. */
34
+ receive(target, changes) {
35
+ applyState(target, changes);
36
+ baseline.record(agreedFrom(target, changes));
37
+ }
38
+ };
39
+ }
40
+ /**
41
+ * Of `changes`, the part `target` actually took.
42
+ *
43
+ * `applyState` swallows a write a setter refuses — a read-only `computed` in
44
+ * state is the case that occurs — and reports it as written anyway. Recording
45
+ * that as agreed is worse than losing it: the far side still holds the old
46
+ * value, its next firing diffs that against a baseline claiming the new one,
47
+ * and it comes back as a fresh edit that reverts the sender. A control edit
48
+ * silently undoing itself, with nothing to show for it.
49
+ *
50
+ * So read the target back. Comparing per nested key as well as per key is what
51
+ * keeps a merged write recordable: `applyState` merges one level, so a narrowed
52
+ * change never equals the whole object it landed in.
53
+ */
54
+ function agreedFrom(target, changes) {
55
+ const agreed = {};
56
+ for (const key in changes) {
57
+ const wanted = changes[key];
58
+ const current = target[key];
59
+ if (isEquivalent(current, wanted)) {
60
+ agreed[key] = wanted;
61
+ continue;
62
+ }
63
+ if (wanted === null || typeof wanted !== "object" || Array.isArray(wanted)) continue;
64
+ if (current === null || typeof current !== "object") continue;
65
+ let landed = null;
66
+ for (const nested in wanted) if (isEquivalent(current[nested], wanted[nested])) {
67
+ landed ??= {};
68
+ landed[nested] = wanted[nested];
69
+ }
70
+ if (landed) agreed[key] = landed;
71
+ }
72
+ return agreed;
73
+ }
74
+ //#endregion
75
+ export { createStateBridge };
@@ -1,4 +1,5 @@
1
1
  import { isRef, unref } from "@poveste/vendors/vue";
2
+ import { clone, omit } from "@poveste/shared";
2
3
  //#region src/app/util/state.ts
3
4
  var isObject = (val) => val !== null && typeof val === "object";
4
5
  function toRawDeep(val, clean = false, seen = /* @__PURE__ */ new WeakMap()) {
@@ -26,5 +27,22 @@ function toRawObject(obj, target, clean = false, seen = /* @__PURE__ */ new Weak
26
27
  target[key] = toRawDeep(obj[key], clean, seen);
27
28
  });
28
29
  }
30
+ /**
31
+ * A variant's state as a preset holds it: a detached deep copy, with the keys
32
+ * a preset has no business storing dropped.
33
+ *
34
+ * The clean pass is what keeps `clone` from failing. A preset is a value — it
35
+ * is persisted as JSON, so a function could never be part of one — and leaving
36
+ * functions in made `structuredClone` throw `DataCloneError`, with the JSON
37
+ * fallback behind it throwing again on the cycle a self-referential prop
38
+ * produces. The copy came out correct anyway, because `toRawDeep` above had
39
+ * already detached it, but every mount of such a story logged the failure —
40
+ * a warning carrying the function's source, then an error — and paid for two
41
+ * doomed clone attempts. `structuredClone` handles the cycle by itself once
42
+ * the functions are gone.
43
+ */
44
+ function toPresetState(state, omitKeys = ["_hPropDefs"]) {
45
+ return clone(omit(toRawDeep(state, true), omitKeys));
46
+ }
29
47
  //#endregion
30
- export { toRawDeep };
48
+ export { toPresetState, toRawDeep };
package/dist/style.css CHANGED
@@ -1,4 +1,3 @@
1
- @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+Display&display=swap');
2
1
  @scope (:root) to (.__poveste-render-story:not(.__poveste-render-custom-controls)) {
3
2
  /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
4
3
  @layer properties;
@@ -175,7 +174,7 @@
175
174
  .bind-col-size {
176
175
  grid-template-columns: repeat(auto-fill, minmax(var(--poveste-col-size), 1fr));
177
176
  }
178
- .__poveste-json-code[data-v-8570567f] .cm-editor {
177
+ .__poveste-json-code[data-v-e4c89a1b] .cm-editor {
179
178
  min-width: 280px;
180
179
  height: 100%;
181
180
  }
@@ -447,6 +446,9 @@
447
446
  .static {
448
447
  position: static;
449
448
  }
449
+ .sticky {
450
+ position: sticky;
451
+ }
450
452
  .inset-0 {
451
453
  inset: 0px;
452
454
  }
@@ -1138,6 +1140,9 @@
1138
1140
  .min-h-\[26px\] {
1139
1141
  min-height: 26px;
1140
1142
  }
1143
+ .min-h-full {
1144
+ min-height: 100%;
1145
+ }
1141
1146
  .w-0 {
1142
1147
  width: 0px;
1143
1148
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@poveste/app",
3
3
  "type": "module",
4
- "version": "0.5.3",
4
+ "version": "0.6.1",
5
5
  "description": "Pre-bundled UI for Poveste",
6
6
  "author": {
7
7
  "name": "Sorin Gitlan"
@@ -28,13 +28,19 @@
28
28
  "src"
29
29
  ],
30
30
  "dependencies": {
31
+ "@fontsource/noto-sans-display": "^5.3.0",
31
32
  "fuse.js": "^7.0.0",
32
33
  "shiki": "^3.0.0",
33
- "@poveste/controls": "^0.5.3",
34
- "@poveste/shared": "^0.5.3",
35
- "@poveste/vendors": "^0.5.3"
34
+ "@poveste/controls": "^0.6.1",
35
+ "@poveste/shared": "^0.6.1",
36
+ "@poveste/vendors": "^0.6.1"
36
37
  },
37
38
  "devDependencies": {
39
+ "@iconify-json/carbon": "^1.2.25",
40
+ "@iconify-json/fluent": "1.2.56",
41
+ "@iconify-json/mdi": "^1.2.3",
42
+ "@iconify-json/ri": "^1.2.10",
43
+ "@iconify/utils": "^3.1.4",
38
44
  "@tailwindcss/postcss": "^4.3.3",
39
45
  "@tailwindcss/typography": "^0.5.15",
40
46
  "@types/fs-extra": "^11.0.4",
@@ -54,8 +60,9 @@
54
60
  "vue": "^3.5.26"
55
61
  },
56
62
  "scripts": {
57
- "build": "rimraf dist && vite build && pnpm run build:css && node ./scripts/copy.mjs",
63
+ "build": "pnpm run icons && rimraf dist && vite build && pnpm run build:css && node ./scripts/copy.mjs",
58
64
  "build:css": "postcss src/app/style/main.pcss -o ./dist/style.css",
65
+ "icons": "node ./scripts/icons.mjs",
59
66
  "test": "vitest run",
60
67
  "test:dev": "vitest",
61
68
  "watch": "concurrently \"vite build --watch\" \"pnpm run build:css --watch\" \"node ./scripts/watchAndCopy.mjs\""
@@ -0,0 +1,30 @@
1
+ import { readFileSync } from 'node:fs'
2
+ import { join } from 'node:path'
3
+ import { describe, expect, it } from 'vitest'
4
+ // @ts-expect-error plain script, no types
5
+ import { FONT_PACKAGE, generateFontCss } from '../../scripts/font.mjs'
6
+
7
+ // Vitest runs from the package root, and stubs `?raw` CSS imports to empty.
8
+ // Newlines are normalised: the shipped sheet is checked in, so a Windows
9
+ // checkout hands it back with CRLF, and this compares content against the
10
+ // LF-newline installed package, not line endings (#156).
11
+ const read = (path: string) => readFileSync(join(process.cwd(), path), 'utf8').replace(/\r\n/g, '\n')
12
+
13
+ const shipped = read('src/app/style/font.css')
14
+ const upstream = read(join('node_modules', FONT_PACKAGE, 'index.css'))
15
+
16
+ describe('the bundled app face', () => {
17
+ it('matches the installed package, so a bump cannot go unnoticed', () => {
18
+ expect(shipped).toBe(generateFontCss(upstream))
19
+ })
20
+
21
+ it('asks for no format the woff2 already covers', () => {
22
+ expect(shipped).not.toContain('format(\'woff\')')
23
+ })
24
+
25
+ it('keeps every subset upstream ships, so non-latin text stays on the face', () => {
26
+ const subsets = (css: string) => (css.match(/unicode-range: [^;]+/g) ?? []).sort()
27
+
28
+ expect(subsets(shipped)).toEqual(subsets(upstream))
29
+ })
30
+ })