@poveste/app 0.13.1 → 0.14.0

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 (89) hide show
  1. package/dist/bundled/App.vue_vue_type_script_setup_true_lang.js +1 -1
  2. package/dist/bundled/app.css +16 -16
  3. package/dist/bundled/components/HomeView.vue_vue_type_script_setup_true_lang.js +1 -1
  4. package/dist/bundled/components/app/AppLogo.vue_vue_type_script_setup_true_lang.js +2 -2
  5. package/dist/bundled/components/app/Breadcrumb.js +1 -1
  6. package/dist/bundled/components/app/Breadcrumb.vue_vue_type_script_setup_true_lang.js +2 -2
  7. package/dist/bundled/components/app/TopBar.vue_vue_type_script_setup_true_lang.js +4 -3
  8. package/dist/bundled/components/base/BaseCheckbox.vue_vue_type_script_setup_true_lang.js +1 -1
  9. package/dist/bundled/components/base/BaseOverflowMenu.vue_vue_type_script_setup_true_lang.js +5 -2
  10. package/dist/bundled/components/base/BaseSplitPane.js +1 -1
  11. package/dist/bundled/components/base/BaseSplitPane.vue_vue_type_script_setup_true_lang.js +6 -4
  12. package/dist/bundled/components/command/CommandPrompts.vue_vue_type_script_setup_true_lang.js +1 -1
  13. package/dist/bundled/components/command/CommandPromptsModal.vue_vue_type_script_setup_true_lang.js +4 -3
  14. package/dist/bundled/components/command/PromptSelect.vue_vue_type_script_setup_true_lang.js +1 -1
  15. package/dist/bundled/components/command/PromptText.vue_vue_type_script_setup_true_lang.js +1 -1
  16. package/dist/bundled/components/panel/StatePresets.vue_vue_type_script_setup_true_lang.js +30 -20
  17. package/dist/bundled/components/panel/StoryControls.vue_vue_type_script_setup_true_lang.js +1 -1
  18. package/dist/bundled/components/panel/StoryDocs.vue_vue_type_script_setup_true_lang.js +3 -1
  19. package/dist/bundled/components/panel/StoryEvent.vue_vue_type_script_setup_true_lang.js +5 -1
  20. package/dist/bundled/components/panel/StoryEvents.vue_vue_type_script_setup_true_lang.js +2 -1
  21. package/dist/bundled/components/panel/StorySidePanel.vue_vue_type_script_setup_true_lang.js +7 -5
  22. package/dist/bundled/components/panel/StorySourceCode.js +1 -1
  23. package/dist/bundled/components/panel/StorySourceCode.vue_vue_type_script_setup_true_lang.js +3 -2
  24. package/dist/bundled/components/search/SearchPane.vue_vue_type_script_setup_true_lang.js +15 -7
  25. package/dist/bundled/components/story/GenericMountStory.vue_vue_type_script_setup_true_lang.js +2 -1
  26. package/dist/bundled/components/story/GenericRenderStory.vue_vue_type_script_setup_true_lang.js +2 -1
  27. package/dist/bundled/components/story/StoryResponsivePreview.js +1 -1
  28. package/dist/bundled/components/story/StoryResponsivePreview.vue_vue_type_script_setup_true_lang.js +17 -6
  29. package/dist/bundled/components/story/StoryVariantGrid.js +1 -1
  30. package/dist/bundled/components/story/StoryVariantGrid.vue_vue_type_script_setup_true_lang.js +15 -10
  31. package/dist/bundled/components/story/StoryView.vue_vue_type_script_setup_true_lang.js +3 -2
  32. package/dist/bundled/components/story/StoryViewer.js +1 -1
  33. package/dist/bundled/components/story/StoryViewer.vue_vue_type_script_setup_true_lang.js +3 -3
  34. package/dist/bundled/components/toolbar/ToolbarBackground.vue_vue_type_script_setup_true_lang.js +1 -1
  35. package/dist/bundled/components/toolbar/ToolbarResponsiveSize.vue_vue_type_script_setup_true_lang.js +17 -16
  36. package/dist/bundled/plugin.js +4 -3
  37. package/dist/bundled/sandbox.js +2 -2
  38. package/dist/bundled/stores/folder.js +1 -1
  39. package/dist/bundled/util/commands.js +20 -9
  40. package/dist/bundled/util/docs.js +2 -1
  41. package/dist/bundled/util/grid-slots.js +1 -1
  42. package/dist/bundled/util/icons.generated.js +0 -1
  43. package/dist/bundled/util/keyboard.js +1 -0
  44. package/dist/bundled/util/mapping.js +1 -1
  45. package/dist/bundled/util/preview-settings.js +1 -1
  46. package/package.json +5 -5
  47. package/src/app/App.vue +6 -3
  48. package/src/app/components/HomeView.vue +1 -1
  49. package/src/app/components/app/AppLogo.vue +6 -2
  50. package/src/app/components/app/Breadcrumb.vue +2 -1
  51. package/src/app/components/app/TopBar.vue +7 -2
  52. package/src/app/components/base/BaseCheckbox.vue +1 -1
  53. package/src/app/components/base/BaseOverflowMenu.vue +9 -3
  54. package/src/app/components/base/BaseSplitPane.vue +9 -4
  55. package/src/app/components/command/CommandPrompts.vue +1 -1
  56. package/src/app/components/command/CommandPromptsModal.vue +1 -0
  57. package/src/app/components/command/PromptSelect.vue +2 -1
  58. package/src/app/components/command/PromptText.vue +7 -3
  59. package/src/app/components/panel/StatePresets.vue +26 -5
  60. package/src/app/components/panel/StoryControls.vue +1 -1
  61. package/src/app/components/panel/StoryDocs.vue +3 -1
  62. package/src/app/components/panel/StoryEvent.vue +7 -2
  63. package/src/app/components/panel/StoryEvents.vue +4 -1
  64. package/src/app/components/panel/StorySidePanel.vue +2 -0
  65. package/src/app/components/panel/StorySourceCode.vue +6 -3
  66. package/src/app/components/search/SearchPane.vue +14 -5
  67. package/src/app/components/story/GenericMountStory.vue +2 -1
  68. package/src/app/components/story/GenericRenderStory.vue +2 -1
  69. package/src/app/components/story/StoryResponsivePreview.vue +30 -5
  70. package/src/app/components/story/StoryVariantGrid.vue +33 -16
  71. package/src/app/components/story/StoryView.vue +7 -3
  72. package/src/app/components/story/StoryViewer.vue +3 -3
  73. package/src/app/components/toolbar/ToolbarBackground.vue +1 -1
  74. package/src/app/components/toolbar/ToolbarResponsiveSize.vue +23 -3
  75. package/src/app/plugin.ts +7 -3
  76. package/src/app/sandbox.ts +1 -1
  77. package/src/app/stores/folder.ts +1 -1
  78. package/src/app/types.ts +2 -2
  79. package/src/app/util/commands.ts +26 -16
  80. package/src/app/util/docs.ts +2 -1
  81. package/src/app/util/grid-slots.ts +1 -1
  82. package/src/app/util/icons.generated.ts +1 -1
  83. package/src/app/util/keyboard.ts +3 -0
  84. package/src/app/util/mapping.ts +1 -1
  85. package/src/app/util/preview-settings.ts +1 -1
  86. package/src/app/util/scroll.ts +5 -1
  87. package/src/app/util/state.ts +1 -1
  88. package/src/app/util/variant.ts +4 -1
  89. package/src/app/components/base/BaseCopyIcon.vue +0 -34
@@ -2,6 +2,6 @@ import _plugin_vue_export_helper_default from "../../_virtual/_plugin-vue_export
2
2
  import StoryResponsivePreview_vue_vue_type_script_setup_true_lang_default from "./StoryResponsivePreview.vue_vue_type_script_setup_true_lang.js";
3
3
  /* empty css */
4
4
  //#region src/app/components/story/StoryResponsivePreview.vue
5
- var StoryResponsivePreview_default = /*#__PURE__*/ _plugin_vue_export_helper_default(StoryResponsivePreview_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-380b627d"]]);
5
+ var StoryResponsivePreview_default = /*#__PURE__*/ _plugin_vue_export_helper_default(StoryResponsivePreview_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-d3057f34"]]);
6
6
  //#endregion
7
7
  export { StoryResponsivePreview_default as default };
@@ -23,7 +23,7 @@ var StoryResponsivePreview_vue_vue_type_script_setup_true_lang_default = /*@__PU
23
23
  }
24
24
  },
25
25
  setup(__props) {
26
- useCssVars((_ctx) => ({ "v0cb511a0": unref(settings).backgroundColor }));
26
+ useCssVars((_ctx) => ({ "v372ee944": unref(settings).backgroundColor }));
27
27
  const props = __props;
28
28
  const settings = usePreviewSettingsStore().currentSettings;
29
29
  const resizing = ref(false);
@@ -42,18 +42,29 @@ var StoryResponsivePreview_vue_vue_type_script_setup_true_lang_default = /*@__PU
42
42
  }
43
43
  const previewWrapper = ref();
44
44
  function useDragger(el, value, min, max, axis) {
45
+ function wrapperSize() {
46
+ const wrapper = previewWrapper.value;
47
+ if (!wrapper) return null;
48
+ return axis === "x" ? wrapper.clientWidth : wrapper.clientHeight;
49
+ }
50
+ function startFrom() {
51
+ if (value.value !== null) return value.value;
52
+ const size = wrapperSize();
53
+ if (size === null) return min;
54
+ return size - (axis === "x" ? 67 : 70);
55
+ }
45
56
  function onMouseDown(event) {
46
57
  event.preventDefault();
47
58
  event.stopPropagation();
48
59
  const start = axis === "x" ? event.clientX : event.clientY;
49
- const startValue = value.value ?? (axis === "x" ? previewWrapper.value.clientWidth - 67 : previewWrapper.value.clientHeight - 70);
60
+ const startValue = startFrom();
50
61
  resizing.value = true;
51
62
  const removeListeners = [addWindowListener("mousemove", onMouseMove), addWindowListener("mouseup", onMouseUp)];
52
63
  function onMouseMove(event) {
53
- const snapTarget = axis === "x" ? previewWrapper.value.clientWidth : previewWrapper.value.clientHeight;
64
+ const snapTarget = wrapperSize();
54
65
  const delta = (axis === "x" ? event.clientX : event.clientY) - start;
55
66
  value.value = Math.max(min, Math.min(max, startValue + delta));
56
- if (Math.abs(value.value - (snapTarget - 67)) < 16) value.value = null;
67
+ if (snapTarget !== null && Math.abs(value.value - (snapTarget - 67)) < 16) value.value = null;
57
68
  }
58
69
  function onMouseUp() {
59
70
  removeListeners.forEach((fn) => fn());
@@ -65,7 +76,7 @@ var StoryResponsivePreview_vue_vue_type_script_setup_true_lang_default = /*@__PU
65
76
  event.preventDefault();
66
77
  event.stopPropagation();
67
78
  const start = axis === "x" ? event.touches[0].clientX : event.touches[0].clientY;
68
- const startValue = value.value;
79
+ const startValue = startFrom();
69
80
  resizing.value = true;
70
81
  const removeListeners = [
71
82
  addWindowListener("touchmove", onTouchMove),
@@ -130,7 +141,7 @@ var StoryResponsivePreview_vue_vue_type_script_setup_true_lang_default = /*@__PU
130
141
  finalWidth: finalWidth.value,
131
142
  finalHeight: finalHeight.value,
132
143
  resizing: resizing.value
133
- }, void 0, true)]), isResponsiveEnabled.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [_cache[1] || (_cache[1] = createStaticVNode("<div class=\"absolute top-5 left-8 h-2 w-px bg-gray-400/25\" data-v-380b627d></div><div class=\"absolute top-5 right-8 h-2 w-px bg-gray-400/25\" data-v-380b627d></div><div class=\"absolute bottom-5 left-8 h-2 w-px bg-gray-400/25\" data-v-380b627d></div><div class=\"absolute bottom-5 right-8 h-2 w-px bg-gray-400/25\" data-v-380b627d></div><div class=\"absolute left-5 top-8 w-2 h-px bg-gray-400/25\" data-v-380b627d></div><div class=\"absolute left-5 bottom-8 w-2 h-px bg-gray-400/25\" data-v-380b627d></div><div class=\"absolute right-5 top-8 w-2 h-px bg-gray-400/25\" data-v-380b627d></div><div class=\"absolute right-5 bottom-8 w-2 h-px bg-gray-400/25\" data-v-380b627d></div>", 8))], 64)) : createCommentVNode("", true)], 2)], 10, _hoisted_3), isResponsiveEnabled.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
144
+ }, void 0, true)]), isResponsiveEnabled.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [_cache[1] || (_cache[1] = createStaticVNode("<div class=\"absolute top-5 left-8 h-2 w-px bg-gray-400/25\" data-v-d3057f34></div><div class=\"absolute top-5 right-8 h-2 w-px bg-gray-400/25\" data-v-d3057f34></div><div class=\"absolute bottom-5 left-8 h-2 w-px bg-gray-400/25\" data-v-d3057f34></div><div class=\"absolute bottom-5 right-8 h-2 w-px bg-gray-400/25\" data-v-d3057f34></div><div class=\"absolute left-5 top-8 w-2 h-px bg-gray-400/25\" data-v-d3057f34></div><div class=\"absolute left-5 bottom-8 w-2 h-px bg-gray-400/25\" data-v-d3057f34></div><div class=\"absolute right-5 top-8 w-2 h-px bg-gray-400/25\" data-v-d3057f34></div><div class=\"absolute right-5 bottom-8 w-2 h-px bg-gray-400/25\" data-v-d3057f34></div>", 8))], 64)) : createCommentVNode("", true)], 2)], 10, _hoisted_3), isResponsiveEnabled.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
134
145
  withDirectives((openBlock(), createElementBlock("div", {
135
146
  ref_key: "horizontalDragger",
136
147
  ref: horizontalDragger,
@@ -2,6 +2,6 @@ import _plugin_vue_export_helper_default from "../../_virtual/_plugin-vue_export
2
2
  import StoryVariantGrid_vue_vue_type_script_setup_true_lang_default from "./StoryVariantGrid.vue_vue_type_script_setup_true_lang.js";
3
3
  /* empty css */
4
4
  //#region src/app/components/story/StoryVariantGrid.vue
5
- var StoryVariantGrid_default = /*#__PURE__*/ _plugin_vue_export_helper_default(StoryVariantGrid_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-5f7bc1e1"]]);
5
+ var StoryVariantGrid_default = /*#__PURE__*/ _plugin_vue_export_helper_default(StoryVariantGrid_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-a753c25f"]]);
6
6
  //#endregion
7
7
  export { StoryVariantGrid_default as default };
@@ -2,7 +2,7 @@ import { useStoryStore } from "../../stores/story.js";
2
2
  import { assignSlots, trimSlots } from "../../util/grid-slots.js";
3
3
  import StoryVariantGridItem_default from "./StoryVariantGridItem.js";
4
4
  import { useDebounceFn, useResizeObserver } from "@poveste/vendors/vue-use";
5
- import { Fragment, computed, createBlock, createElementBlock, createElementVNode, defineComponent, normalizeStyle, onBeforeUnmount, onMounted, openBlock, ref, renderList, unref, watch } from "@poveste/vendors/vue";
5
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, defineComponent, normalizeStyle, onBeforeUnmount, onMounted, openBlock, ref, renderList, unref, watch } from "@poveste/vendors/vue";
6
6
  //#region src/app/components/story/StoryVariantGrid.vue?vue&type=script&setup=true&lang.ts
7
7
  var _hoisted_1 = { class: "poveste-story-variant-grid flex flex-col items-stretch h-full __poveste-pane-shadow-from-right" };
8
8
  var _hoisted_2 = { class: "flex w-0 flex-1 mx-4" };
@@ -17,17 +17,18 @@ var StoryVariantGrid_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
17
17
  setup(__props) {
18
18
  const storyStore = useStoryStore();
19
19
  const gridTemplateWidth = computed(() => {
20
- if (storyStore.currentStory.layout.type !== "grid") return;
21
- const layoutWidth = storyStore.currentStory.layout.width;
20
+ const layout = storyStore.currentStory?.layout;
21
+ if (layout?.type !== "grid") return;
22
+ const layoutWidth = layout.width;
22
23
  if (!layoutWidth) return "200px";
23
24
  if (typeof layoutWidth === "number") return `${layoutWidth}px`;
24
25
  return layoutWidth;
25
26
  });
26
27
  const maxItemHeight = ref(0);
27
- const el = ref(null);
28
+ const el = ref();
28
29
  const scrollTop = ref(0);
29
30
  const viewportHeight = ref(0);
30
- const variants = computed(() => storyStore.currentStory.variants);
31
+ const variants = computed(() => storyStore.currentStory?.variants ?? []);
31
32
  useResizeObserver(el, () => {
32
33
  updateWindow();
33
34
  updateSize();
@@ -60,14 +61,16 @@ var StoryVariantGrid_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
60
61
  updateWindow();
61
62
  }
62
63
  }
63
- const gridEl = ref(null);
64
+ const gridEl = ref();
64
65
  const gridColumnWidth = ref(1);
65
66
  const viewWidth = ref(1);
66
67
  function updateSize() {
67
68
  if (!el.value) return;
68
69
  viewWidth.value = el.value.clientWidth;
69
70
  if (!gridEl.value) return;
70
- if (gridTemplateWidth.value.endsWith("%")) gridColumnWidth.value = viewWidth.value * Number.parseInt(gridTemplateWidth.value) / 100 - gap;
71
+ const templateWidth = gridTemplateWidth.value;
72
+ if (!templateWidth) return;
73
+ if (templateWidth.endsWith("%")) gridColumnWidth.value = viewWidth.value * Number.parseInt(templateWidth) / 100 - gap;
71
74
  else gridColumnWidth.value = Number.parseInt(gridTemplateWidth.value);
72
75
  }
73
76
  onMounted(() => {
@@ -105,7 +108,9 @@ var StoryVariantGrid_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
105
108
  }, TRIM_DELAY);
106
109
  }
107
110
  watch(visibleVariants, (visible) => {
108
- slots.value = assignSlots(slots.value, storyStore.currentStory.id, visible);
111
+ const story = storyStore.currentStory;
112
+ if (!story) return;
113
+ slots.value = assignSlots(slots.value, story.id, visible);
109
114
  scheduleTrim();
110
115
  }, { immediate: true });
111
116
  onBeforeUnmount(() => {
@@ -143,7 +148,7 @@ var StoryVariantGrid_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
143
148
  gridTemplateColumns: `repeat(${columnCount.value}, ${gridColumnWidth.value}px)`,
144
149
  transform: offsetY.value ? `translateY(${offsetY.value}px)` : void 0
145
150
  })
146
- }, [(openBlock(true), createElementBlock(Fragment, null, renderList(slots.value, (slot, index) => {
151
+ }, [unref(storyStore).currentStory ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(slots.value, (slot, index) => {
147
152
  return openBlock(), createBlock(StoryVariantGridItem_default, {
148
153
  key: index,
149
154
  variant: slot.variant,
@@ -158,7 +163,7 @@ var StoryVariantGrid_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
158
163
  "story",
159
164
  "style"
160
165
  ]);
161
- }), 128))], 4)], 4)])], 544)]);
166
+ }), 128)) : createCommentVNode("", true)], 4)], 4)])], 544)]);
162
167
  };
163
168
  }
164
169
  });
@@ -27,7 +27,8 @@ var StoryView_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
27
27
  const router = useRouter();
28
28
  const route = useRoute();
29
29
  watch(() => storyStore.currentVariant, (value) => {
30
- if (value) storyStore.currentStory.lastSelectedVariant = value;
30
+ const story = storyStore.currentStory;
31
+ if (value && story) story.lastSelectedVariant = value;
31
32
  }, { immediate: true });
32
33
  watch(() => [storyStore.currentStory, storyStore.currentVariant], () => {
33
34
  if (!storyStore.currentVariant && autoSelectsVariant(storyStore.currentStory)) setVariant((storyStore.currentStory.lastSelectedVariant ?? storyStore.currentStory.variants[0]).id);
@@ -41,7 +42,7 @@ var StoryView_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
41
42
  }
42
43
  });
43
44
  }
44
- const docsOnlyScroller = ref(null);
45
+ const docsOnlyScroller = ref();
45
46
  function scrollDocsToTop() {
46
47
  docsOnlyScroller.value?.scrollTo(0, 0);
47
48
  }
@@ -2,6 +2,6 @@ import _plugin_vue_export_helper_default from "../../_virtual/_plugin-vue_export
2
2
  import StoryViewer_vue_vue_type_script_setup_true_lang_default from "./StoryViewer.vue_vue_type_script_setup_true_lang.js";
3
3
  /* empty css */
4
4
  //#region src/app/components/story/StoryViewer.vue
5
- var StoryViewer_default = /*#__PURE__*/ _plugin_vue_export_helper_default(StoryViewer_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-d5a7fe4c"]]);
5
+ var StoryViewer_default = /*#__PURE__*/ _plugin_vue_export_helper_default(StoryViewer_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-5e1183de"]]);
6
6
  //#endregion
7
7
  export { StoryViewer_default as default };
@@ -9,7 +9,7 @@ var _hoisted_1 = { class: "poveste-story-viewer bg-gray-50 h-full dark:bg-gray-7
9
9
  var StoryViewer_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
10
10
  __name: "StoryViewer",
11
11
  setup(__props) {
12
- useCssVars((_ctx) => ({ "v4fc4017e": variant.value?.iconColor }));
12
+ useCssVars((_ctx) => ({ "v96d17610": variant.value?.iconColor }));
13
13
  const storyStore = useStoryStore();
14
14
  const variant = computed(() => storyStore.currentVariant);
15
15
  const isMenuOpened = ref(false);
@@ -20,7 +20,7 @@ var StoryViewer_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
20
20
  isMenuOpened.value = false;
21
21
  });
22
22
  return (_ctx, _cache) => {
23
- return openBlock(), createElementBlock(Fragment, null, [createElementVNode("div", _hoisted_1, [unref(storyStore).currentStory.layout.type === "grid" ? (openBlock(), createBlock(StoryVariantGrid_default, { key: 0 })) : unref(storyStore).currentStory.layout.type === "single" ? (openBlock(), createBlock(StoryVariantSingle_default, {
23
+ return openBlock(), createElementBlock(Fragment, null, [createElementVNode("div", _hoisted_1, [unref(storyStore).currentStory?.layout?.type === "grid" ? (openBlock(), createBlock(StoryVariantGrid_default, { key: 0 })) : unref(storyStore).currentStory?.layout?.type === "single" ? (openBlock(), createBlock(StoryVariantSingle_default, {
24
24
  key: 1,
25
25
  onOpenVariantMenu: _cache[0] || (_cache[0] = ($event) => isMenuOpened.value = true)
26
26
  })) : createCommentVNode("", true)]), createVNode(MobileOverlay_default, {
@@ -28,7 +28,7 @@ var StoryViewer_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
28
28
  opened: isMenuOpened.value,
29
29
  onClose: closeMenu
30
30
  }, {
31
- default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(storyStore).currentStory.variants, (v, index) => {
31
+ default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(storyStore).currentStory?.variants ?? [], (v, index) => {
32
32
  return openBlock(), createBlock(StoryVariantListItem_default, {
33
33
  key: index,
34
34
  variant: v
@@ -42,7 +42,7 @@ var ToolbarBackground_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*
42
42
  }
43
43
  ];
44
44
  const showColorScheme = !povesteConfig.theme.hideColorSchemeSwitch;
45
- const showDropdown = showColorScheme || !!povesteConfig.backgroundPresets.length;
45
+ const showDropdown = showColorScheme || !!povesteConfig.backgroundPresets?.length;
46
46
  return (_ctx, _cache) => {
47
47
  const _component_VDropdown = resolveComponent("VDropdown");
48
48
  const _directive_tooltip = resolveDirective("tooltip");
@@ -1,7 +1,7 @@
1
1
  import { povesteConfig } from "../../util/config.js";
2
2
  import { usePreviewSettingsStore } from "../../stores/preview-settings.js";
3
3
  import BaseCheckbox_default from "../base/BaseCheckbox.js";
4
- import { Fragment, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, openBlock, renderList, resolveComponent, resolveDirective, toDisplayString, unref, vModelText, withCtx, withDirectives } from "@poveste/vendors/vue";
4
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, isRef, normalizeClass, openBlock, renderList, resolveComponent, resolveDirective, toDisplayString, unref, vModelText, withCtx, withDirectives } from "@poveste/vendors/vue";
5
5
  import { Icon } from "@poveste/vendors/iconify";
6
6
  //#region src/app/components/toolbar/ToolbarResponsiveSize.vue?vue&type=script&setup=true&lang.ts
7
7
  var _hoisted_1 = { class: "flex flex-col items-stretch" };
@@ -17,6 +17,17 @@ var ToolbarResponsiveSize_vue_vue_type_script_setup_true_lang_default = /*@__PUR
17
17
  __name: "ToolbarResponsiveSize",
18
18
  setup(__props) {
19
19
  const settings = usePreviewSettingsStore().currentSettings;
20
+ function autoWhenEmpty(key) {
21
+ return computed({
22
+ get: () => settings[key],
23
+ set: (value) => {
24
+ const parsed = typeof value === "number" ? value : Number.parseFloat(value ?? "");
25
+ settings[key] = Number.isFinite(parsed) ? parsed : null;
26
+ }
27
+ });
28
+ }
29
+ const responsiveWidth = autoWhenEmpty("responsiveWidth");
30
+ const responsiveHeight = autoWhenEmpty("responsiveHeight");
20
31
  return (_ctx, _cache) => {
21
32
  const _component_VDropdown = resolveComponent("VDropdown");
22
33
  const _directive_tooltip = resolveDirective("tooltip");
@@ -36,30 +47,20 @@ var ToolbarResponsiveSize_vue_vue_type_script_setup_true_lang_default = /*@__PUR
36
47
  }, 8, ["modelValue"]),
37
48
  createElementVNode("div", _hoisted_2, [
38
49
  withDirectives(createElementVNode("input", {
39
- "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => unref(settings).responsiveWidth = $event),
50
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => isRef(responsiveWidth) ? responsiveWidth.value = $event : null),
40
51
  type: "number",
41
52
  class: "bg-transparent border border-gray-200 dark:border-gray-850 rounded w-20 opacity-50 focus:opacity-100 flex-1 min-w-0",
42
53
  step: "16",
43
54
  placeholder: "Auto"
44
- }, null, 512), [[
45
- vModelText,
46
- unref(settings).responsiveWidth,
47
- void 0,
48
- { number: true }
49
- ], [_directive_tooltip, "Responsive width (px)"]]),
55
+ }, null, 512), [[vModelText, unref(responsiveWidth)], [_directive_tooltip, "Responsive width (px)"]]),
50
56
  _cache[4] || (_cache[4] = createElementVNode("span", { class: "opacity-50" }, "×", -1)),
51
57
  withDirectives(createElementVNode("input", {
52
- "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => unref(settings).responsiveHeight = $event),
58
+ "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => isRef(responsiveHeight) ? responsiveHeight.value = $event : null),
53
59
  type: "number",
54
60
  class: "bg-transparent border border-gray-200 dark:border-gray-850 rounded w-20 opacity-50 focus:opacity-100 flex-1 min-w-0",
55
61
  step: "16",
56
62
  placeholder: "Auto"
57
- }, null, 512), [[
58
- vModelText,
59
- unref(settings).responsiveHeight,
60
- void 0,
61
- { number: true }
62
- ], [_directive_tooltip, "Responsive height (px)"]])
63
+ }, null, 512), [[vModelText, unref(responsiveHeight)], [_directive_tooltip, "Responsive height (px)"]])
63
64
  ]),
64
65
  (openBlock(true), createElementBlock(Fragment, null, renderList(unref(povesteConfig).responsivePresets, (preset, index) => {
65
66
  return openBlock(), createElementBlock("button", {
@@ -67,7 +68,7 @@ var ToolbarResponsiveSize_vue_vue_type_script_setup_true_lang_default = /*@__PUR
67
68
  class: normalizeClass(["px-4 py-3 cursor-pointer text-left flex gap-4", [unref(settings).responsiveWidth === preset.width && unref(settings).responsiveHeight === preset.height ? "bg-primary-500 hover:bg-primary-600 text-white dark:text-black" : "bg-transparent hover:bg-primary-100 dark:hover:bg-primary-700"]]),
68
69
  onClick: ($event) => {
69
70
  unref(settings).responsiveWidth = preset.width;
70
- unref(settings).responsiveHeight = preset.height;
71
+ unref(settings).responsiveHeight = preset.height ?? null;
71
72
  hide();
72
73
  }
73
74
  }, [createTextVNode(toDisplayString(preset.label) + " ", 1), createElementVNode("span", _hoisted_4, [
@@ -1,9 +1,10 @@
1
1
  import { router } from "./router.js";
2
2
  //#region src/app/plugin.ts
3
3
  function setupPluginApi() {
4
- if (!import.meta.hot) return;
4
+ const hot = import.meta.hot;
5
+ if (!hot) return;
5
6
  const listeners = {};
6
- import.meta.hot.on("poveste:dev-event-result", ({ event, result }) => {
7
+ hot.on("poveste:dev-event-result", ({ event, result }) => {
7
8
  const set = listeners[event];
8
9
  if (set) for (const listener of set) listener(result);
9
10
  });
@@ -21,7 +22,7 @@ function setupPluginApi() {
21
22
  window.__HST_PLUGIN_API__ = {
22
23
  sendEvent: (event, payload) => {
23
24
  return new Promise((resolve) => {
24
- import.meta.hot.send(`poveste:dev-event`, {
25
+ hot.send(`poveste:dev-event`, {
25
26
  event,
26
27
  payload
27
28
  });
@@ -38,8 +38,8 @@ if (storedSettings) applyPreviewSettings(storedSettings);
38
38
  if (window.parent && window.parent !== window) window.parent.postMessage({ type: PREVIEW_SETTINGS_REQUEST }, window.location.origin);
39
39
  function reportUncaught(error) {
40
40
  reportStoryError(error, {
41
- storyId: storyId.value,
42
- variantId: variantId.value
41
+ storyId: storyId.value ?? void 0,
42
+ variantId: variantId.value ?? void 0
43
43
  });
44
44
  }
45
45
  window.addEventListener("error", (event) => {
@@ -29,7 +29,7 @@ var useFolderStore = defineStore("folder", () => {
29
29
  }
30
30
  const storyStore = useStoryStore();
31
31
  watch(() => storyStore.currentStory, (story) => {
32
- if (story) openFileFolders(story.file.path);
32
+ if (story?.file) openFileFolders(story.file.path);
33
33
  });
34
34
  return {
35
35
  isFolderOpened,
@@ -2,20 +2,31 @@ import { router } from "../router.js";
2
2
  import { useStoryStore } from "../stores/story.js";
3
3
  import { openInEditor } from "./open-in-editor.js";
4
4
  //#region src/app/util/commands.ts
5
+ /**
6
+ * The path "Open file in editor" should open, or undefined when there is none.
7
+ *
8
+ * `Story.file` is optional, and `let file: string` used to be assigned
9
+ * `story.file?.filePath` in both branches — so a story without a file produced
10
+ * `file: undefined`, and `openInEditor` sent
11
+ * `__open-in-editor?file=undefined` to the dev server: a request to open a file
12
+ * literally named "undefined", with nothing said in the UI (#667).
13
+ *
14
+ * A docs-only story prefers its markdown, falling back to the component file
15
+ * when the story has both.
16
+ */
17
+ function editableFilePath(story) {
18
+ const file = story?.file;
19
+ if (!file) return void 0;
20
+ return story?.docsOnly ? file.docsFilePath ?? file.filePath : file.filePath;
21
+ }
5
22
  var builtinCommands = [{
6
23
  id: "builtin:open-in-editor",
7
24
  label: "Open file in editor",
8
25
  icon: "carbon:script-reference",
9
- showIf: ({ route }) => route.name === "story" && !!useStoryStore().currentStory,
10
- getParams: () => {
11
- const story = useStoryStore().currentStory;
12
- let file;
13
- if (story.docsOnly) file = story.file?.docsFilePath ?? story.file?.filePath;
14
- else file = story.file?.filePath;
15
- return { file };
16
- },
26
+ showIf: ({ route }) => route.name === "story" && !!editableFilePath(useStoryStore().currentStory),
27
+ getParams: () => ({ file: editableFilePath(useStoryStore().currentStory) }),
17
28
  clientAction: ({ file }) => {
18
- openInEditor(file);
29
+ if (file) openInEditor(file);
19
30
  }
20
31
  }, {
21
32
  id: "builtin:poveste-docs",
@@ -7,7 +7,8 @@ async function getSourceCode(story, variant) {
7
7
  const source = variant.slots?.().source()[0].children;
8
8
  if (source) return unindent(source);
9
9
  } else {
10
- const clientPlugin = clientSupportPlugins[story.file?.supportPluginId];
10
+ const supportPluginId = story.file?.supportPluginId;
11
+ const clientPlugin = supportPluginId ? clientSupportPlugins[supportPluginId] : void 0;
11
12
  if (clientPlugin) return (await clientPlugin()).generateSourceCode(variant);
12
13
  }
13
14
  const sourceLoader = story.file?.source;
@@ -11,7 +11,7 @@ function assignSlots(slots, storyId, visible) {
11
11
  const next = slots.map((slot) => slot.storyId === storyId && position.has(slot.variant.id) ? {
12
12
  ...slot,
13
13
  visible: true,
14
- order: position.get(slot.variant.id)
14
+ order: position.get(slot.variant.id) ?? 0
15
15
  } : {
16
16
  ...slot,
17
17
  visible: false,
@@ -6,7 +6,6 @@ var iconCollections = [
6
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
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
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
9
  "caret-down": { "body": "<path fill=\"currentColor\" d=\"m24 12l-8 10l-8-10z\"/>" },
11
10
  "caret-right": { "body": "<path fill=\"currentColor\" d=\"m12 8l10 8l-10 8z\"/>" },
12
11
  "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\"/>" },
@@ -88,6 +88,7 @@ function isMatchingShortcut(shortcut) {
88
88
  function isMatchingCombination(combination) {
89
89
  const splitted = combination.split("+").map((key) => key.trim());
90
90
  const targetKey = splitted.pop();
91
+ if (!targetKey) return false;
91
92
  for (const mod in modifiers) if (splitted.includes(mod) !== modifiers[mod].pressed) return false;
92
93
  return pressedKeys.has(targetKey);
93
94
  }
@@ -45,7 +45,7 @@ function mapVariant(variant, existingVariant) {
45
45
  _hPropState: {},
46
46
  _hPropDefs: {}
47
47
  }),
48
- setupApp: null,
48
+ setupApp: void 0,
49
49
  slots: () => ({
50
50
  default: void 0,
51
51
  controls: void 0,
@@ -24,7 +24,7 @@ function applyPreviewSettings(settings) {
24
24
  if (povesteConfig.autoApplyContrastColor) document.documentElement.style.color = contrastColor;
25
25
  }
26
26
  function getContrastColor(setting) {
27
- return povesteConfig.backgroundPresets.find((preset) => preset.color === setting.backgroundColor)?.contrastColor ?? "unset";
27
+ return povesteConfig.backgroundPresets?.find((preset) => preset.color === setting.backgroundColor)?.contrastColor ?? "unset";
28
28
  }
29
29
  //#endregion
30
30
  export { PREVIEW_SETTINGS_STORAGE_KEY, applyPreviewSettings, getContrastColor, loadStoredPreviewSettings, receivedSettings };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@poveste/app",
3
3
  "type": "module",
4
- "version": "0.13.1",
4
+ "version": "0.14.0",
5
5
  "description": "Pre-bundled UI for Poveste",
6
6
  "author": {
7
7
  "name": "Sorin Gitlan",
@@ -38,9 +38,9 @@
38
38
  "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
39
39
  },
40
40
  "dependencies": {
41
- "@poveste/controls": "^0.13.1",
42
- "@poveste/shared": "^0.13.1",
43
- "@poveste/vendors": "^0.13.1",
41
+ "@poveste/controls": "^0.14.0",
42
+ "@poveste/shared": "^0.14.0",
43
+ "@poveste/vendors": "^0.14.0",
44
44
  "fuse.js": "^7.0.0",
45
45
  "shiki": "^3.0.0"
46
46
  },
@@ -66,7 +66,7 @@
66
66
  "tailwindcss": "^4.3.3",
67
67
  "typescript": "5.6.3",
68
68
  "vite": "^8.2.0",
69
- "vitest": "^4.1.10",
69
+ "vitest": "^5.0.0",
70
70
  "vue": "^3.5.26",
71
71
  "vue-tsc": "^2.1.10"
72
72
  },
package/src/app/App.vue CHANGED
@@ -5,7 +5,7 @@ export default {
5
5
  </script>
6
6
 
7
7
  <script lang="ts" setup>
8
- import type { StoryFile, Tree } from './types'
8
+ import type { Story, StoryFile, Tree } from './types'
9
9
  import { useTitle } from '@vueuse/core'
10
10
  import { onUpdate, files as rawFiles, tree as rawTree } from 'virtual:$poveste-stories'
11
11
  import { computed, onMounted, ref, watch } from 'vue'
@@ -41,8 +41,11 @@ onUpdate((newFiles: StoryFile[], newTree: Tree) => {
41
41
  tree.value = newTree
42
42
  })
43
43
 
44
- const stories = computed(() => files.value.reduce((acc, file) => {
45
- acc.push(file.story)
44
+ // The accumulator needs a type: `[]` alone infers `never[]`, so the push was an
45
+ // error about the seed rather than about the story. A file whose story has not
46
+ // been collected yet contributes nothing.
47
+ const stories = computed(() => files.value.reduce<Story[]>((acc, file) => {
48
+ if (file.story) acc.push(file.story)
46
49
  return acc
47
50
  }, []))
48
51
 
@@ -5,7 +5,7 @@ import { useStoryStore } from '../stores/story'
5
5
  import { customLogos, povesteConfig } from '../util/config'
6
6
  import HomeCounter from './app/HomeCounter.vue'
7
7
 
8
- const logoUrl = computed(() => povesteConfig.theme?.logo?.square ? customLogos.square : PovesteLogo)
8
+ const logoUrl = computed(() => povesteConfig.theme?.logo?.square ? customLogos?.square ?? PovesteLogo : PovesteLogo)
9
9
  const storyStore = useStoryStore()
10
10
 
11
11
  const stats = computed(() => {
@@ -6,11 +6,15 @@ import PovesteLogoLight from '../../assets/poveste-text.svg'
6
6
  import { customLogos, povesteConfig } from '../../util/config'
7
7
  import { isDark } from '../../util/dark'
8
8
 
9
+ // `theme.logo` is what the config asked for; `customLogos` is the resolved URL
10
+ // map from the virtual module. Two objects, so a check on one narrows nothing
11
+ // about the other — and falling back to the bundled logo beats rendering an
12
+ // `<img>` with no `src` if they ever disagree.
9
13
  const logoUrl = computed(() => {
10
14
  if (isDark.value) {
11
- return povesteConfig.theme.logo?.dark ? customLogos.dark : PovesteLogoDark
15
+ return povesteConfig.theme.logo?.dark ? customLogos?.dark ?? PovesteLogoDark : PovesteLogoDark
12
16
  }
13
- return povesteConfig.theme.logo?.light ? customLogos.light : PovesteLogoLight
17
+ return povesteConfig.theme.logo?.light ? customLogos?.light ?? PovesteLogoLight : PovesteLogoLight
14
18
  })
15
19
 
16
20
  const altText = computed(() => `${povesteConfig.theme.title} logo`)
@@ -16,7 +16,8 @@ const storyStore = useStoryStore()
16
16
  const story = computed(() => storyStore.currentStory)
17
17
 
18
18
  const folders = computed(() => {
19
- return story.value.file.path.slice(0, -1)
19
+ // No story, or a story with no file behind it, means no trail to draw.
20
+ return story.value?.file?.path.slice(0, -1) ?? []
20
21
  })
21
22
 
22
23
  const isMenuOpened = ref(false)
@@ -1,4 +1,5 @@
1
1
  <script lang="ts" setup>
2
+ import { computed } from 'vue'
2
3
  import { useStoryStore } from '../../stores/story'
3
4
  import DevOnlyToolbarOpenInEditor from '../toolbar/DevOnlyToolbarOpenInEditor.vue'
4
5
  import ToolbarBackground from '../toolbar/ToolbarBackground.vue'
@@ -15,6 +16,10 @@ defineEmits({
15
16
  })
16
17
 
17
18
  const storyStore = useStoryStore()
19
+
20
+ // Named once so the `v-if` and the binding below read the same value; a story
21
+ // without a file has nothing to open.
22
+ const editableFile = computed(() => storyStore.currentStory?.file?.filePath)
18
23
  </script>
19
24
 
20
25
  <template>
@@ -51,8 +56,8 @@ const storyStore = useStoryStore()
51
56
  :story="storyStore.currentStory"
52
57
  />
53
58
  <DevOnlyToolbarOpenInEditor
54
- v-if="__POVESTE_DEV__"
55
- :file="storyStore.currentStory.file?.filePath"
59
+ v-if="__POVESTE_DEV__ && editableFile"
60
+ :file="editableFile"
56
61
  tooltip="Edit story in editor"
57
62
  />
58
63
  </TopBarChip>
@@ -28,7 +28,7 @@ const progress = computed(() => props.modelValue ? 1 : 0)
28
28
  const dashoffset = computed(() => (1 - progress.value) * dasharray.value)
29
29
 
30
30
  watch(path, () => {
31
- dasharray.value = path.value.getTotalLength?.() ?? 21.21
31
+ dasharray.value = path.value?.getTotalLength?.() ?? 21.21
32
32
  })
33
33
  </script>
34
34
 
@@ -49,15 +49,21 @@ const ChildWrapper = {
49
49
  const state = reactive({ width: 0, index: props.index })
50
50
 
51
51
  useResizeObserver(el, (entries) => {
52
+ // The observer only fires for an element it is observing, so this is
53
+ // never null here — but `children` is keyed by the element, and an
54
+ // undefined key would silently make a second entry for the same child.
55
+ const element = el.value
56
+ if (!element) return
52
57
  const width = entries[0].contentRect.width
53
- if (!children.value.has(el.value)) {
54
- children.value.set(el.value, state)
58
+ if (!children.value.has(element)) {
59
+ children.value.set(element, state)
55
60
  }
56
61
  state.width = width
57
62
  })
58
63
 
59
64
  onBeforeUnmount(() => {
60
- children.value.delete(el.value)
65
+ const element = el.value
66
+ if (element) children.value.delete(element)
61
67
  })
62
68
 
63
69
  const visible = computed(() => visibleChildrenCount.value > state.index)