@poveste/app 0.5.1 → 0.5.3

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.
@@ -1,8 +1,11 @@
1
1
  @import '@poveste/controls/dist/index.es.css';
2
2
 
3
+ /* Lets the toolbar's preview background show through. Not `!important`: this
4
+ file is wrapped in `@layer poveste-defaults` so consumer rules outrank it,
5
+ and an important declaration would invert that. */
3
6
  html,
4
7
  body {
5
- background: transparent !important;
8
+ background: transparent;
6
9
  }
7
10
 
8
11
  body {
@@ -113,11 +113,11 @@
113
113
  }
114
114
  }
115
115
  @scope (:root) to (.__poveste-render-story:not(.__poveste-render-custom-controls)) {
116
- .bind-icon-color[data-v-270b4ce8] {
117
- color: var(--v0884d9dc);
116
+ .bind-icon-color[data-v-74c04c7c] {
117
+ color: var(--v2e50e6e6);
118
118
  }
119
- .bind-preview-bg[data-v-270b4ce8] {
120
- background-color: var(--v233de319);
119
+ .bind-preview-bg[data-v-74c04c7c] {
120
+ background-color: var(--v7d5058c5);
121
121
  }
122
122
  }
123
123
  @scope (:root) to (.__poveste-render-story:not(.__poveste-render-custom-controls)) {
@@ -45,7 +45,7 @@ var StoryControls_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
45
45
  "slot-name": "controls",
46
46
  variant: __props.variant,
47
47
  story: __props.story,
48
- class: "__poveste-render-custom-controls __histoire-render-custom-controls flex-none",
48
+ class: "__poveste-controls-slot __poveste-render-custom-controls __histoire-render-custom-controls flex-none",
49
49
  onReady: _cache[0] || (_cache[0] = ($event) => ready.value = true)
50
50
  }, null, 8, ["variant", "story"])) : hasInitState.value ? (openBlock(), createElementBlock("div", _hoisted_3, [createVNode(ControlsComponentState_default, {
51
51
  class: "flex-none my-2",
@@ -2,6 +2,6 @@ import _plugin_vue_export_helper_default from "../../_virtual/_plugin-vue_export
2
2
  import StoryVariantGridItem_vue_vue_type_script_setup_true_lang_default from "./StoryVariantGridItem.vue_vue_type_script_setup_true_lang.js";
3
3
  /* empty css */
4
4
  //#region src/app/components/story/StoryVariantGridItem.vue
5
- var StoryVariantGridItem_default = /*#__PURE__*/ _plugin_vue_export_helper_default(StoryVariantGridItem_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-270b4ce8"]]);
5
+ var StoryVariantGridItem_default = /*#__PURE__*/ _plugin_vue_export_helper_default(StoryVariantGridItem_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-74c04c7c"]]);
6
6
  //#endregion
7
7
  export { StoryVariantGridItem_default as default };
@@ -1,7 +1,7 @@
1
1
  import { povesteConfig } from "../../util/config.js";
2
2
  import { useStoryStore } from "../../stores/story.js";
3
3
  import { useScrollOnActive } from "../../util/scroll.js";
4
- import { usePreviewDark } from "../../util/color-scheme.js";
4
+ import { previewDarkClasses, usePreviewDark } from "../../util/color-scheme.js";
5
5
  import { getContrastColor } from "../../util/preview-settings.js";
6
6
  import { usePreviewSettingsStore } from "../../stores/preview-settings.js";
7
7
  import ToolbarNewTab_default from "../toolbar/ToolbarNewTab.js";
@@ -34,8 +34,8 @@ var StoryVariantGridItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE
34
34
  emits: { resize: (_width, _height) => true },
35
35
  setup(__props, { emit: __emit }) {
36
36
  useCssVars((_ctx) => ({
37
- "v0884d9dc": unref(variant).iconColor,
38
- "v233de319": unref(settings).backgroundColor
37
+ "v2e50e6e6": unref(variant).iconColor,
38
+ "v7d5058c5": unref(settings).backgroundColor
39
39
  }));
40
40
  const props = __props;
41
41
  const emit = __emit;
@@ -126,7 +126,7 @@ var StoryVariantGridItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE
126
126
  variant: unref(variant),
127
127
  story: __props.story,
128
128
  dir: unref(settings).textDirection,
129
- class: normalizeClass({ [unref(povesteConfig).theme.darkClass]: unref(previewDark) }),
129
+ class: normalizeClass(unref(previewDark) ? unref(previewDarkClasses)() : void 0),
130
130
  onReady
131
131
  }, null, 8, [
132
132
  "variant",
@@ -1,6 +1,6 @@
1
1
  import { povesteConfig } from "../../util/config.js";
2
2
  import { useStoryStore } from "../../stores/story.js";
3
- import { usePreviewDark } from "../../util/color-scheme.js";
3
+ import { previewDarkClasses, usePreviewDark } from "../../util/color-scheme.js";
4
4
  import { getContrastColor } from "../../util/preview-settings.js";
5
5
  import { usePreviewSettingsStore } from "../../stores/preview-settings.js";
6
6
  import GenericRenderStory_default from "./GenericRenderStory.js";
@@ -47,10 +47,7 @@ var StoryVariantSinglePreviewNative_vue_vue_type_script_setup_true_lang_default
47
47
  key: `${__props.story.id}-${__props.variant.id}`,
48
48
  variant: __props.variant,
49
49
  story: __props.story,
50
- class: normalizeClass(["h-full", {
51
- [unref(povesteConfig).sandboxDarkClass]: unref(previewDark),
52
- [unref(povesteConfig).theme.darkClass]: unref(previewDark)
53
- }]),
50
+ class: normalizeClass(["h-full", unref(previewDark) ? unref(previewDarkClasses)() : void 0]),
54
51
  dir: unref(settings).textDirection,
55
52
  onReady
56
53
  }, null, 8, [
@@ -1,4 +1,4 @@
1
- import { EVENT_SEND, PREVIEW_SETTINGS_SYNC, SANDBOX_HEIGHT, SANDBOX_READY, STATE_SYNC } from "../../util/const.js";
1
+ import { EVENT_SEND, PREVIEW_SETTINGS_REQUEST, PREVIEW_SETTINGS_SYNC, SANDBOX_HEIGHT, SANDBOX_READY, STATE_SYNC } from "../../util/const.js";
2
2
  import { trackWindow } from "../../util/keyboard.js";
3
3
  import { useStoryStore } from "../../stores/story.js";
4
4
  import { usePreviewSettingsStore } from "../../stores/preview-settings.js";
@@ -23,7 +23,7 @@ var StoryVariantSinglePreviewRemote_vue_vue_type_script_setup_true_lang_default
23
23
  const settings = usePreviewSettingsStore().currentSettings;
24
24
  const iframe = ref();
25
25
  function syncState() {
26
- if (iframe.value && props.variant.previewReady) iframe.value.contentWindow.postMessage({
26
+ if (iframe.value?.contentWindow && props.variant.previewReady) iframe.value.contentWindow.postMessage({
27
27
  type: STATE_SYNC,
28
28
  state: toRawDeep(props.variant.state, true)
29
29
  });
@@ -54,6 +54,9 @@ var StoryVariantSinglePreviewRemote_vue_vue_type_script_setup_true_lang_default
54
54
  case SANDBOX_READY:
55
55
  setPreviewReady();
56
56
  break;
57
+ case PREVIEW_SETTINGS_REQUEST:
58
+ syncSettings();
59
+ break;
57
60
  case SANDBOX_HEIGHT: if (typeof event.data.h === "number") {
58
61
  const next = Math.max(40, event.data.h);
59
62
  if (next !== reportedHeight.value) reportedHeight.value = next;
@@ -86,7 +89,7 @@ var StoryVariantSinglePreviewRemote_vue_vue_type_script_setup_true_lang_default
86
89
  stopTrackKeyboard?.();
87
90
  });
88
91
  function syncSettings() {
89
- if (iframe.value) iframe.value.contentWindow.postMessage({
92
+ if (iframe.value?.contentWindow) iframe.value.contentWindow.postMessage({
90
93
  type: PREVIEW_SETTINGS_SYNC,
91
94
  settings: toRaw(settings)
92
95
  });
@@ -1,7 +1,6 @@
1
- import { povesteConfig } from "./util/config.js";
2
1
  import { isDark } from "./util/dark.js";
3
- import { SANDBOX_HEIGHT, SANDBOX_READY, STATE_SYNC } from "./util/const.js";
4
- import { resolvePreviewDark } from "./util/color-scheme.js";
2
+ import { PREVIEW_SETTINGS_REQUEST, SANDBOX_HEIGHT, SANDBOX_READY, STATE_SYNC } from "./util/const.js";
3
+ import { previewDarkClasses, resolvePreviewDark } from "./util/color-scheme.js";
5
4
  import { applyPreviewSettings, loadStoredPreviewSettings, receivedSettings } from "./util/preview-settings.js";
6
5
  import GenericMountStory_default from "./components/story/GenericMountStory.js";
7
6
  import { mapFile } from "./util/mapping.js";
@@ -19,14 +18,14 @@ var query = parseQuery(window.location.search);
19
18
  var file = ref(mapFile(files.find((f) => f.id === query.storyId)));
20
19
  var storedSettings = loadStoredPreviewSettings();
21
20
  if (storedSettings) applyPreviewSettings(storedSettings);
21
+ if (window.parent && window.parent !== window) window.parent.postMessage({ type: PREVIEW_SETTINGS_REQUEST }, window.location.origin);
22
22
  var prefersDark = usePreferredDark();
23
23
  var previewDark = computed(() => resolvePreviewDark(receivedSettings.colorScheme, prefersDark.value, isDark.value));
24
24
  var darkClassTargets = [document.documentElement, document.querySelector("#app")];
25
25
  watch(previewDark, (value) => {
26
26
  for (const el of darkClassTargets) {
27
27
  if (!el) continue;
28
- el.classList.toggle(povesteConfig.sandboxDarkClass, value);
29
- el.classList.toggle(povesteConfig.theme.darkClass, value);
28
+ for (const className of previewDarkClasses()) el.classList.toggle(className, value);
30
29
  }
31
30
  }, { immediate: true });
32
31
  var app = createApp({
@@ -31,5 +31,15 @@ function usePreviewDark(settings) {
31
31
  const prefersDark = usePreferredDark();
32
32
  return computed(() => resolvePreviewDark(settings.colorScheme, prefersDark.value, isDark.value));
33
33
  }
34
+ /**
35
+ * Classes the story root carries in dark mode, identical on all three render
36
+ * paths. The deprecated `sandboxDarkClass` is emitted only when a book sets it
37
+ * (#126).
38
+ */
39
+ function previewDarkClasses() {
40
+ const { darkClass } = povesteConfig.theme;
41
+ const legacy = povesteConfig.sandboxDarkClass;
42
+ return [.../* @__PURE__ */ new Set([darkClass, legacy])].filter((name) => !!name);
43
+ }
34
44
  //#endregion
35
- export { defaultPreviewColorScheme, resolvePreviewDark, usePreviewDark };
45
+ export { defaultPreviewColorScheme, previewDarkClasses, resolvePreviewDark, usePreviewDark };
@@ -3,6 +3,7 @@ var STATE_SYNC = "__poveste:state-sync";
3
3
  var SANDBOX_READY = "__poveste:sandbox-ready";
4
4
  var EVENT_SEND = "__poveste:event";
5
5
  var PREVIEW_SETTINGS_SYNC = "__poveste:preview-settings-sync";
6
+ var PREVIEW_SETTINGS_REQUEST = "__poveste:preview-settings-request";
6
7
  var SANDBOX_HEIGHT = "__poveste:sandbox-height";
7
8
  //#endregion
8
- export { EVENT_SEND, PREVIEW_SETTINGS_SYNC, SANDBOX_HEIGHT, SANDBOX_READY, STATE_SYNC };
9
+ export { EVENT_SEND, PREVIEW_SETTINGS_REQUEST, PREVIEW_SETTINGS_SYNC, SANDBOX_HEIGHT, SANDBOX_READY, STATE_SYNC };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@poveste/app",
3
3
  "type": "module",
4
- "version": "0.5.1",
4
+ "version": "0.5.3",
5
5
  "description": "Pre-bundled UI for Poveste",
6
6
  "author": {
7
7
  "name": "Sorin Gitlan"
@@ -30,9 +30,9 @@
30
30
  "dependencies": {
31
31
  "fuse.js": "^7.0.0",
32
32
  "shiki": "^3.0.0",
33
- "@poveste/controls": "^0.5.1",
34
- "@poveste/shared": "^0.5.1",
35
- "@poveste/vendors": "^0.5.1"
33
+ "@poveste/controls": "^0.5.3",
34
+ "@poveste/shared": "^0.5.3",
35
+ "@poveste/vendors": "^0.5.3"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@tailwindcss/postcss": "^4.3.3",
@@ -0,0 +1,55 @@
1
+ import { describe, expect, it, vi } from 'vitest'
2
+
3
+ // `util/config` re-exports a virtual module Vite generates from the book's own
4
+ // config, so the tests supply it directly.
5
+ const config: { theme: { darkClass?: string }, sandboxDarkClass?: string } = { theme: {} }
6
+
7
+ vi.mock('../app/util/config', () => ({
8
+ get povesteConfig() {
9
+ return config
10
+ },
11
+ }))
12
+
13
+ // Touches browser storage on import; unrelated to the pure function under test.
14
+ vi.mock('../app/util/dark', () => ({ isDark: { value: false } }))
15
+
16
+ const { previewDarkClasses } = await import('../app/util/color-scheme')
17
+
18
+ function darkClassesFor({ darkClass = 'dark', sandboxDarkClass }: { darkClass?: string, sandboxDarkClass?: string }) {
19
+ config.theme = { darkClass }
20
+ config.sandboxDarkClass = sandboxDarkClass
21
+ return previewDarkClasses()
22
+ }
23
+
24
+ describe('previewDarkClasses', () => {
25
+ it('returns the theme class for a book that configures neither', () => {
26
+ expect(darkClassesFor({})).toEqual(['dark'])
27
+ })
28
+
29
+ // #126: the deprecated option used to default to `dark` and be emitted here
30
+ // too, which is what made the three render paths disagree.
31
+ it('returns the theme class alone when only it is configured', () => {
32
+ expect(darkClassesFor({ darkClass: 'my-dark' })).toEqual(['my-dark'])
33
+ })
34
+
35
+ it('appends sandboxDarkClass when a book still sets it', () => {
36
+ expect(darkClassesFor({ darkClass: 'my-dark', sandboxDarkClass: 'legacy' })).toEqual(['my-dark', 'legacy'])
37
+ })
38
+
39
+ it('returns one class when both names are the same', () => {
40
+ expect(darkClassesFor({ darkClass: 'dark', sandboxDarkClass: 'dark' })).toEqual(['dark'])
41
+ })
42
+
43
+ // `classList.toggle('')` throws, and the sandbox runs it during boot, so an
44
+ // empty entry leaves every preview blank rather than merely unstyled. Only
45
+ // the empty string reaches here — defu fills an undefined class.
46
+ describe('when a configured class name is empty', () => {
47
+ it('drops an empty theme class', () => {
48
+ expect(darkClassesFor({ darkClass: '' })).toEqual([])
49
+ })
50
+
51
+ it('drops an empty sandboxDarkClass', () => {
52
+ expect(darkClassesFor({ sandboxDarkClass: '' })).toEqual(['dark'])
53
+ })
54
+ })
55
+ })
@@ -58,7 +58,7 @@ const hasInitState = computed(() => Object
58
58
  slot-name="controls"
59
59
  :variant="variant"
60
60
  :story="story"
61
- class="__poveste-render-custom-controls __histoire-render-custom-controls flex-none"
61
+ class="__poveste-controls-slot __poveste-render-custom-controls __histoire-render-custom-controls flex-none"
62
62
  @ready="ready = true"
63
63
  />
64
64
 
@@ -8,7 +8,7 @@ import { computed, ref, toRefs } from 'vue'
8
8
  import { useRouter } from 'vue-router'
9
9
  import { usePreviewSettingsStore } from '../../stores/preview-settings'
10
10
  import { useStoryStore } from '../../stores/story'
11
- import { usePreviewDark } from '../../util/color-scheme'
11
+ import { previewDarkClasses, usePreviewDark } from '../../util/color-scheme'
12
12
  import { povesteConfig } from '../../util/config'
13
13
  import { getSourceCode } from '../../util/docs'
14
14
  import { getContrastColor } from '../../util/preview-settings'
@@ -163,9 +163,7 @@ const useIframe = computed(() => {
163
163
  :variant="variant"
164
164
  :story="story"
165
165
  :dir="settings.textDirection"
166
- :class="{
167
- [povesteConfig.theme.darkClass]: previewDark,
168
- }"
166
+ :class="previewDark ? previewDarkClasses() : undefined"
169
167
  @ready="onReady"
170
168
  />
171
169
  </div>
@@ -3,7 +3,7 @@ import type { Story, Variant } from '../../types'
3
3
  import { computed } from 'vue'
4
4
  import { usePreviewSettingsStore } from '../../stores/preview-settings'
5
5
  import { useStoryStore } from '../../stores/story'
6
- import { usePreviewDark } from '../../util/color-scheme'
6
+ import { previewDarkClasses, usePreviewDark } from '../../util/color-scheme'
7
7
  import { povesteConfig } from '../../util/config'
8
8
  import { getContrastColor } from '../../util/preview-settings'
9
9
  import GenericRenderStory from './GenericRenderStory.vue'
@@ -57,10 +57,7 @@ const autoApplyContrastColor = computed(() => !!povesteConfig.autoApplyContrastC
57
57
  :variant="variant"
58
58
  :story="story"
59
59
  class="h-full"
60
- :class="{
61
- [povesteConfig.sandboxDarkClass]: previewDark, // @TODO remove
62
- [povesteConfig.theme.darkClass]: previewDark,
63
- }"
60
+ :class="previewDark ? previewDarkClasses() : undefined"
64
61
  :dir="settings.textDirection"
65
62
  @ready="onReady"
66
63
  />
@@ -7,7 +7,7 @@ import { computed, onBeforeUnmount, ref, toRaw, watch } from 'vue'
7
7
  import { useEventsStore } from '../../stores/events'
8
8
  import { usePreviewSettingsStore } from '../../stores/preview-settings'
9
9
  import { useStoryStore } from '../../stores/story'
10
- import { EVENT_SEND, PREVIEW_SETTINGS_SYNC, SANDBOX_HEIGHT, SANDBOX_READY, STATE_SYNC } from '../../util/const'
10
+ import { EVENT_SEND, PREVIEW_SETTINGS_REQUEST, PREVIEW_SETTINGS_SYNC, SANDBOX_HEIGHT, SANDBOX_READY, STATE_SYNC } from '../../util/const'
11
11
  import { trackWindow } from '../../util/keyboard'
12
12
  import { getSandboxUrl } from '../../util/sandbox'
13
13
  import { toRawDeep } from '../../util/state'
@@ -26,7 +26,7 @@ const settings = usePreviewSettingsStore().currentSettings
26
26
  const iframe = ref<HTMLIFrameElement>()
27
27
 
28
28
  function syncState() {
29
- if (iframe.value && props.variant.previewReady) {
29
+ if (iframe.value?.contentWindow && props.variant.previewReady) {
30
30
  iframe.value.contentWindow.postMessage({
31
31
  type: STATE_SYNC,
32
32
  state: toRawDeep(props.variant.state, true),
@@ -72,6 +72,9 @@ useEventListener(window, 'message', (event) => {
72
72
  case SANDBOX_READY:
73
73
  setPreviewReady()
74
74
  break
75
+ case PREVIEW_SETTINGS_REQUEST:
76
+ syncSettings()
77
+ break
75
78
  case SANDBOX_HEIGHT:
76
79
  if (typeof event.data.h === 'number') {
77
80
  const next = Math.max(40, event.data.h)
@@ -118,7 +121,7 @@ onBeforeUnmount(() => {
118
121
  // Settings
119
122
 
120
123
  function syncSettings() {
121
- if (iframe.value) {
124
+ if (iframe.value?.contentWindow) {
122
125
  iframe.value.contentWindow.postMessage({
123
126
  type: PREVIEW_SETTINGS_SYNC,
124
127
  settings: toRaw(settings),
@@ -8,9 +8,8 @@ import { parseQuery } from 'vue-router'
8
8
  import GenericMountStory from './components/story/GenericMountStory.vue'
9
9
  import GenericRenderStory from './components/story/GenericRenderStory.vue'
10
10
  import { setupPluginApi } from './plugin.js'
11
- import { resolvePreviewDark } from './util/color-scheme.js'
12
- import { povesteConfig } from './util/config.js'
13
- import { PREVIEW_SETTINGS_SYNC, SANDBOX_HEIGHT, SANDBOX_READY, STATE_SYNC } from './util/const.js'
11
+ import { previewDarkClasses, resolvePreviewDark } from './util/color-scheme.js'
12
+ import { PREVIEW_SETTINGS_REQUEST, PREVIEW_SETTINGS_SYNC, SANDBOX_HEIGHT, SANDBOX_READY, STATE_SYNC } from './util/const.js'
14
13
  import { isDark } from './util/dark.js'
15
14
  import { mapFile } from './util/mapping'
16
15
  import { applyPreviewSettings, loadStoredPreviewSettings, receivedSettings } from './util/preview-settings.js'
@@ -28,15 +27,20 @@ if (storedSettings) {
28
27
  applyPreviewSettings(storedSettings)
29
28
  }
30
29
 
30
+ // The app pushes settings when it sees the iframe load, which is one document
31
+ // swap away from being wrong: a push aimed at a document that is going away is
32
+ // dropped with no error and nothing re-sends it, leaving the sandbox on the
33
+ // stored value or on none at all (#75). Ask instead — a request can only come
34
+ // from a document that is running and listening.
35
+ if (window.parent && window.parent !== window) {
36
+ window.parent.postMessage({ type: PREVIEW_SETTINGS_REQUEST }, window.location.origin)
37
+ }
38
+
31
39
  // The story preview has its own color scheme, independent from the app chrome.
32
40
  // The fallback covers settings stored before the option existed.
33
41
  const prefersDark = usePreferredDark()
34
42
  const previewDark = computed(() => resolvePreviewDark(receivedSettings.colorScheme, prefersDark.value, isDark.value))
35
43
 
36
- // `sandboxDarkClass` is poveste's own deprecated config option, superseded by
37
- // `theme.darkClass`. Still honoured on purpose: dropping it would silently stop
38
- // applying the class for anyone who set it. Removing the option is a breaking
39
- // config change and belongs to a major, not here.
40
44
  /*
41
45
  * The class also has to land *inside* the story's `@scope` root, not only on
42
46
  * `<html>` (#101).
@@ -60,9 +64,9 @@ watch(previewDark, (value) => {
60
64
  for (const el of darkClassTargets) {
61
65
  if (!el) continue
62
66
 
63
- // eslint-disable-next-line ts/no-deprecated
64
- el.classList.toggle(povesteConfig.sandboxDarkClass, value)
65
- el.classList.toggle(povesteConfig.theme.darkClass, value)
67
+ for (const className of previewDarkClasses()) {
68
+ el.classList.toggle(className, value)
69
+ }
66
70
  }
67
71
  }, {
68
72
  immediate: true,
@@ -1,8 +1,11 @@
1
1
  @import '@poveste/controls/dist/index.es.css';
2
2
 
3
+ /* Lets the toolbar's preview background show through. Not `!important`: this
4
+ file is wrapped in `@layer poveste-defaults` so consumer rules outrank it,
5
+ and an important declaration would invert that. */
3
6
  html,
4
7
  body {
5
- background: transparent !important;
8
+ background: transparent;
6
9
  }
7
10
 
8
11
  body {
@@ -34,3 +34,16 @@ export function usePreviewDark(settings: PreviewSettings) {
34
34
  const prefersDark = usePreferredDark()
35
35
  return computed(() => resolvePreviewDark(settings.colorScheme, prefersDark.value, isDark.value))
36
36
  }
37
+
38
+ /**
39
+ * Classes the story root carries in dark mode, identical on all three render
40
+ * paths. The deprecated `sandboxDarkClass` is emitted only when a book sets it
41
+ * (#126).
42
+ */
43
+ export function previewDarkClasses(): string[] {
44
+ const { darkClass } = povesteConfig.theme
45
+ // eslint-disable-next-line ts/no-deprecated
46
+ const legacy = povesteConfig.sandboxDarkClass
47
+ // Empty entries are dropped: `classList.toggle('')` throws, during boot.
48
+ return [...new Set([darkClass, legacy])].filter((name): name is string => !!name)
49
+ }
@@ -2,4 +2,5 @@ export const STATE_SYNC = '__poveste:state-sync'
2
2
  export const SANDBOX_READY = '__poveste:sandbox-ready'
3
3
  export const EVENT_SEND = '__poveste:event'
4
4
  export const PREVIEW_SETTINGS_SYNC = '__poveste:preview-settings-sync'
5
+ export const PREVIEW_SETTINGS_REQUEST = '__poveste:preview-settings-request'
5
6
  export const SANDBOX_HEIGHT = '__poveste:sandbox-height'