@scaffold-ui-kit/preview 0.0.0-stage → 2.3.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.
- package/LICENSE +21 -0
- package/README.md +1868 -2
- package/application/host/bootstrap.ts +43 -0
- package/application/host/main.ts +31 -0
- package/application/host/shell-host.ts +47 -0
- package/application/index.html +12 -0
- package/application/lib/base-url.ts +15 -0
- package/application/lib/no-code-block.ts +7 -0
- package/application/lib/no-setup.ts +3 -0
- package/application/lib/no-views.ts +6 -0
- package/application/preview/code/code.html +12 -0
- package/application/preview/code/main.ts +89 -0
- package/application/preview/globals.ts +254 -0
- package/application/preview/html/main.ts +93 -0
- package/application/preview/html/preview.html +12 -0
- package/application/preview/react/main.tsx +146 -0
- package/application/preview/react/preview.html +12 -0
- package/application/preview/svelte/Preview.svelte +104 -0
- package/application/preview/svelte/main.ts +13 -0
- package/application/preview/svelte/preview.html +12 -0
- package/application/preview/svelte/story-props.ts +172 -0
- package/application/preview/view/main.ts +124 -0
- package/application/preview/view/view.html +12 -0
- package/application/preview/vue/main.ts +145 -0
- package/application/preview/vue/preview.html +12 -0
- package/application/shells/charcell/components/Application/index.css +37 -0
- package/application/shells/charcell/components/Application/index.tsx +65 -0
- package/application/shells/charcell/components/Bar/index.css +68 -0
- package/application/shells/charcell/components/Bar/index.tsx +60 -0
- package/application/shells/charcell/components/CodePane/index.css +60 -0
- package/application/shells/charcell/components/CodePane/index.tsx +113 -0
- package/application/shells/charcell/components/ComponentStage/index.css +26 -0
- package/application/shells/charcell/components/ComponentStage/index.tsx +110 -0
- package/application/shells/charcell/components/Control/index.css +20 -0
- package/application/shells/charcell/components/Control/index.tsx +118 -0
- package/application/shells/charcell/components/CopyLink/index.tsx +35 -0
- package/application/shells/charcell/components/Description/index.css +6 -0
- package/application/shells/charcell/components/Description/index.tsx +24 -0
- package/application/shells/charcell/components/EditorAddDialog/index.css +9 -0
- package/application/shells/charcell/components/EditorAddDialog/index.tsx +158 -0
- package/application/shells/charcell/components/EditorPanel/index.css +48 -0
- package/application/shells/charcell/components/EditorPanel/index.tsx +496 -0
- package/application/shells/charcell/components/EventsRow/index.css +42 -0
- package/application/shells/charcell/components/EventsRow/index.tsx +68 -0
- package/application/shells/charcell/components/HeadingRow/index.css +11 -0
- package/application/shells/charcell/components/HeadingRow/index.tsx +16 -0
- package/application/shells/charcell/components/Hint/index.css +16 -0
- package/application/shells/charcell/components/Hint/index.tsx +81 -0
- package/application/shells/charcell/components/HtmlWarnings/index.tsx +45 -0
- package/application/shells/charcell/components/KeyHints/index.css +27 -0
- package/application/shells/charcell/components/KeyHints/index.tsx +106 -0
- package/application/shells/charcell/components/KitCodeBlock/index.css +55 -0
- package/application/shells/charcell/components/KitCodeBlock/index.tsx +18 -0
- package/application/shells/charcell/components/Markdown/index.tsx +16 -0
- package/application/shells/charcell/components/Navigation/index.css +13 -0
- package/application/shells/charcell/components/Navigation/index.tsx +98 -0
- package/application/shells/charcell/components/NavigationSplit/index.css +16 -0
- package/application/shells/charcell/components/NavigationSplit/index.tsx +82 -0
- package/application/shells/charcell/components/OptionControls/index.tsx +93 -0
- package/application/shells/charcell/components/PaneStatus/index.css +7 -0
- package/application/shells/charcell/components/PaneStatus/index.tsx +47 -0
- package/application/shells/charcell/components/PaneWidth/index.tsx +45 -0
- package/application/shells/charcell/components/PreviewGrid/index.css +39 -0
- package/application/shells/charcell/components/PreviewGrid/index.tsx +344 -0
- package/application/shells/charcell/components/PreviewPane/index.css +127 -0
- package/application/shells/charcell/components/PreviewPane/index.tsx +182 -0
- package/application/shells/charcell/components/PromptBar/index.tsx +133 -0
- package/application/shells/charcell/components/ScenarioRow/index.css +36 -0
- package/application/shells/charcell/components/ScenarioRow/index.tsx +71 -0
- package/application/shells/charcell/components/Select/index.tsx +48 -0
- package/application/shells/charcell/components/SlotOutlet/index.css +7 -0
- package/application/shells/charcell/components/SlotOutlet/index.tsx +25 -0
- package/application/shells/charcell/components/StageBar/index.css +7 -0
- package/application/shells/charcell/components/StageBar/index.tsx +109 -0
- package/application/shells/charcell/components/StageSplit/index.css +11 -0
- package/application/shells/charcell/components/StageSplit/index.tsx +99 -0
- package/application/shells/charcell/components/StatusBar/index.tsx +30 -0
- package/application/shells/charcell/components/ViewControls/index.css +15 -0
- package/application/shells/charcell/components/ViewControls/index.tsx +58 -0
- package/application/shells/charcell/components/ViewHeading/index.css +13 -0
- package/application/shells/charcell/components/ViewHeading/index.tsx +8 -0
- package/application/shells/charcell/components/ViewStage/index.css +9 -0
- package/application/shells/charcell/components/ViewStage/index.tsx +25 -0
- package/application/shells/charcell/components/WrapToggle/index.tsx +27 -0
- package/application/shells/charcell/configuration.ts +45 -0
- package/application/shells/charcell/controller-context.ts +27 -0
- package/application/shells/charcell/fit-labels.ts +42 -0
- package/application/shells/charcell/html-warnings.ts +18 -0
- package/application/shells/charcell/index.tsx +82 -0
- package/application/shells/charcell/page-loading.html +57 -0
- package/application/shells/charcell/placement.ts +24 -0
- package/application/shells/charcell/shell-options.ts +23 -0
- package/application/shells/charcell/shell.css +37 -0
- package/application/shells/charcell/shell.tsx +25 -0
- package/application/shells/charcell/split-reset.ts +47 -0
- package/application/shells/charcell/stacked-rows.ts +117 -0
- package/application/shells/charcell/stage-toggles.ts +93 -0
- package/application/types/manifest.d.ts +6 -0
- package/application/types/preview-configuration.d.ts +10 -0
- package/application/types/preview-shell.d.ts +7 -0
- package/application/types/react-registry.d.ts +15 -0
- package/application/types/vue-registry.d.ts +6 -0
- package/dist/build.d.ts +24 -0
- package/dist/build.js +34 -0
- package/dist/check.d.ts +48 -0
- package/dist/check.js +781 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +88 -0
- package/dist/context.d.ts +179 -0
- package/dist/context.js +783 -0
- package/dist/controller/catalog.d.ts +339 -0
- package/dist/controller/catalog.js +367 -0
- package/dist/controller/create-preview-controller.d.ts +532 -0
- package/dist/controller/create-preview-controller.js +1707 -0
- package/dist/controller/editor-tree.d.ts +161 -0
- package/dist/controller/editor-tree.js +373 -0
- package/dist/controller/html-source.d.ts +62 -0
- package/dist/controller/html-source.js +61 -0
- package/dist/controller/index.d.ts +9 -0
- package/dist/controller/index.js +12 -0
- package/dist/controller/persistence.d.ts +191 -0
- package/dist/controller/persistence.js +315 -0
- package/dist/controller/regeneration.d.ts +30 -0
- package/dist/controller/regeneration.js +27 -0
- package/dist/controller/source.d.ts +80 -0
- package/dist/controller/source.js +236 -0
- package/dist/controller/store.d.ts +27 -0
- package/dist/controller/store.js +40 -0
- package/dist/declarations/application/shells/charcell/components/Application/index.d.ts +2 -0
- package/dist/declarations/application/shells/charcell/components/Bar/index.d.ts +11 -0
- package/dist/declarations/application/shells/charcell/components/CodePane/index.d.ts +5 -0
- package/dist/declarations/application/shells/charcell/components/ComponentStage/index.d.ts +2 -0
- package/dist/declarations/application/shells/charcell/components/Control/index.d.ts +9 -0
- package/dist/declarations/application/shells/charcell/components/CopyLink/index.d.ts +1 -0
- package/dist/declarations/application/shells/charcell/components/Description/index.d.ts +5 -0
- package/dist/declarations/application/shells/charcell/components/EditorAddDialog/index.d.ts +6 -0
- package/dist/declarations/application/shells/charcell/components/EditorPanel/index.d.ts +2 -0
- package/dist/declarations/application/shells/charcell/components/EventsRow/index.d.ts +4 -0
- package/dist/declarations/application/shells/charcell/components/HeadingRow/index.d.ts +6 -0
- package/dist/declarations/application/shells/charcell/components/Hint/index.d.ts +11 -0
- package/dist/declarations/application/shells/charcell/components/HtmlWarnings/index.d.ts +5 -0
- package/dist/declarations/application/shells/charcell/components/KeyHints/index.d.ts +2 -0
- package/dist/declarations/application/shells/charcell/components/KitCodeBlock/index.d.ts +5 -0
- package/dist/declarations/application/shells/charcell/components/Markdown/index.d.ts +3 -0
- package/dist/declarations/application/shells/charcell/components/Navigation/index.d.ts +8 -0
- package/dist/declarations/application/shells/charcell/components/NavigationSplit/index.d.ts +7 -0
- package/dist/declarations/application/shells/charcell/components/OptionControls/index.d.ts +7 -0
- package/dist/declarations/application/shells/charcell/components/PaneStatus/index.d.ts +2 -0
- package/dist/declarations/application/shells/charcell/components/PaneWidth/index.d.ts +4 -0
- package/dist/declarations/application/shells/charcell/components/PreviewGrid/index.d.ts +7 -0
- package/dist/declarations/application/shells/charcell/components/PreviewPane/index.d.ts +9 -0
- package/dist/declarations/application/shells/charcell/components/PromptBar/index.d.ts +1 -0
- package/dist/declarations/application/shells/charcell/components/ScenarioRow/index.d.ts +2 -0
- package/dist/declarations/application/shells/charcell/components/Select/index.d.ts +16 -0
- package/dist/declarations/application/shells/charcell/components/SlotOutlet/index.d.ts +5 -0
- package/dist/declarations/application/shells/charcell/components/StageBar/index.d.ts +2 -0
- package/dist/declarations/application/shells/charcell/components/StageSplit/index.d.ts +17 -0
- package/dist/declarations/application/shells/charcell/components/StatusBar/index.d.ts +1 -0
- package/dist/declarations/application/shells/charcell/components/ViewControls/index.d.ts +9 -0
- package/dist/declarations/application/shells/charcell/components/ViewHeading/index.d.ts +4 -0
- package/dist/declarations/application/shells/charcell/components/ViewStage/index.d.ts +4 -0
- package/dist/declarations/application/shells/charcell/components/WrapToggle/index.d.ts +1 -0
- package/dist/declarations/application/shells/charcell/configuration.d.ts +31 -0
- package/dist/declarations/application/shells/charcell/controller-context.d.ts +9 -0
- package/dist/declarations/application/shells/charcell/fit-labels.d.ts +18 -0
- package/dist/declarations/application/shells/charcell/html-warnings.d.ts +5 -0
- package/dist/declarations/application/shells/charcell/index.d.ts +39 -0
- package/dist/declarations/application/shells/charcell/placement.d.ts +7 -0
- package/dist/declarations/application/shells/charcell/shell-options.d.ts +15 -0
- package/dist/declarations/application/shells/charcell/shell.d.ts +9 -0
- package/dist/declarations/application/shells/charcell/split-reset.d.ts +30 -0
- package/dist/declarations/application/shells/charcell/stacked-rows.d.ts +58 -0
- package/dist/declarations/application/shells/charcell/stage-toggles.d.ts +28 -0
- package/dist/declarations/src/controller/catalog.d.ts +339 -0
- package/dist/declarations/src/controller/create-preview-controller.d.ts +532 -0
- package/dist/declarations/src/controller/editor-tree.d.ts +161 -0
- package/dist/declarations/src/controller/html-source.d.ts +62 -0
- package/dist/declarations/src/controller/index.d.ts +9 -0
- package/dist/declarations/src/controller/persistence.d.ts +191 -0
- package/dist/declarations/src/controller/regeneration.d.ts +30 -0
- package/dist/declarations/src/controller/source.d.ts +80 -0
- package/dist/declarations/src/controller/store.d.ts +27 -0
- package/dist/declarations/src/emit/common.d.ts +103 -0
- package/dist/declarations/src/emit/manifest.d.ts +138 -0
- package/dist/declarations/src/emit/source.d.ts +87 -0
- package/dist/declarations/src/lib/jsx-roots.d.ts +22 -0
- package/dist/declarations/src/lib/module-of-source.d.ts +18 -0
- package/dist/declarations/src/lib/naming.d.ts +29 -0
- package/dist/declarations/src/lib/react-spelling.d.ts +68 -0
- package/dist/declarations/src/lib/scenario-story.d.ts +41 -0
- package/dist/declarations/src/lib/slot-fill.d.ts +15 -0
- package/dist/declarations/src/lib/types.d.ts +741 -0
- package/dist/declarations/src/options.d.ts +224 -0
- package/dist/declarations/src/protocol.d.ts +541 -0
- package/dist/declarations/src/react-view.d.ts +22 -0
- package/dist/declarations/src/react.d.ts +17 -0
- package/dist/declarations/src/shell.d.ts +99 -0
- package/dist/declarations/src/views.d.ts +152 -0
- package/dist/development-server.d.ts +121 -0
- package/dist/development-server.js +331 -0
- package/dist/emit/common.d.ts +103 -0
- package/dist/emit/common.js +170 -0
- package/dist/emit/html-source.d.ts +46 -0
- package/dist/emit/html-source.js +322 -0
- package/dist/emit/manifest.d.ts +138 -0
- package/dist/emit/manifest.js +74 -0
- package/dist/emit/react.d.ts +16 -0
- package/dist/emit/react.js +210 -0
- package/dist/emit/scratch.d.ts +40 -0
- package/dist/emit/scratch.js +116 -0
- package/dist/emit/source.d.ts +87 -0
- package/dist/emit/source.js +789 -0
- package/dist/emit/svelte.d.ts +9 -0
- package/dist/emit/svelte.js +177 -0
- package/dist/emit/vue.d.ts +2 -0
- package/dist/emit/vue.js +152 -0
- package/dist/enumerate.d.ts +2 -0
- package/dist/enumerate.js +162 -0
- package/dist/generate.d.ts +43 -0
- package/dist/generate.js +302 -0
- package/dist/html-stylesheet.d.ts +43 -0
- package/dist/html-stylesheet.js +145 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +21 -0
- package/dist/landing.d.ts +16 -0
- package/dist/landing.js +45 -0
- package/dist/lib/exported-types.d.ts +42 -0
- package/dist/lib/exported-types.js +86 -0
- package/dist/lib/html-attributes.d.ts +2 -0
- package/dist/lib/html-attributes.js +111 -0
- package/dist/lib/html-warnings.d.ts +19 -0
- package/dist/lib/html-warnings.js +79 -0
- package/dist/lib/jsx-roots.d.ts +22 -0
- package/dist/lib/jsx-roots.js +243 -0
- package/dist/lib/module-of-source.d.ts +18 -0
- package/dist/lib/module-of-source.js +24 -0
- package/dist/lib/naming.d.ts +29 -0
- package/dist/lib/naming.js +56 -0
- package/dist/lib/parse-type.d.ts +32 -0
- package/dist/lib/parse-type.js +103 -0
- package/dist/lib/react-spelling.d.ts +68 -0
- package/dist/lib/react-spelling.js +197 -0
- package/dist/lib/scenario-story.d.ts +41 -0
- package/dist/lib/scenario-story.js +84 -0
- package/dist/lib/slot-fill.d.ts +15 -0
- package/dist/lib/slot-fill.js +92 -0
- package/dist/lib/template-files.d.ts +14 -0
- package/dist/lib/template-files.js +25 -0
- package/dist/lib/types.d.ts +741 -0
- package/dist/lib/types.js +13 -0
- package/dist/lib/void-elements.d.ts +7 -0
- package/dist/lib/void-elements.js +13 -0
- package/dist/load.d.ts +37 -0
- package/dist/load.js +82 -0
- package/dist/model.d.ts +44 -0
- package/dist/model.js +464 -0
- package/dist/options.d.ts +224 -0
- package/dist/options.js +223 -0
- package/dist/prop-types.d.ts +26 -0
- package/dist/prop-types.js +102 -0
- package/dist/props-from.d.ts +84 -0
- package/dist/props-from.js +510 -0
- package/dist/protocol.d.ts +541 -0
- package/dist/protocol.js +819 -0
- package/dist/react-view.d.ts +22 -0
- package/dist/react-view.js +36 -0
- package/dist/react.d.ts +17 -0
- package/dist/react.js +23 -0
- package/dist/sass-importers.d.ts +26 -0
- package/dist/sass-importers.js +32 -0
- package/dist/shell-acceptance.d.ts +21 -0
- package/dist/shell-acceptance.js +37 -0
- package/dist/shell-page.d.ts +36 -0
- package/dist/shell-page.js +90 -0
- package/dist/shell-peers.d.ts +38 -0
- package/dist/shell-peers.js +61 -0
- package/dist/shell.d.ts +99 -0
- package/dist/shell.js +52 -0
- package/dist/shells/charcell/page.d.ts +8 -0
- package/dist/shells/charcell/page.js +69 -0
- package/dist/story-source.d.ts +113 -0
- package/dist/story-source.js +271 -0
- package/dist/story.d.ts +5 -0
- package/dist/story.js +28 -0
- package/dist/testing.d.ts +218 -0
- package/dist/testing.js +284 -0
- package/dist/views.d.ts +152 -0
- package/dist/views.js +7 -0
- package/dist/vite-configuration.d.ts +114 -0
- package/dist/vite-configuration.js +578 -0
- package/package.json +123 -3
- package/src/build.ts +51 -0
- package/src/check.ts +1062 -0
- package/src/cli.ts +123 -0
- package/src/context.ts +1168 -0
- package/src/controller/catalog.ts +719 -0
- package/src/controller/create-preview-controller.ts +2683 -0
- package/src/controller/editor-tree.ts +530 -0
- package/src/controller/html-source.ts +114 -0
- package/src/controller/index.ts +105 -0
- package/src/controller/persistence.ts +403 -0
- package/src/controller/regeneration.ts +55 -0
- package/src/controller/source.ts +333 -0
- package/src/controller/store.ts +55 -0
- package/src/development-server.ts +442 -0
- package/src/emit/common.ts +201 -0
- package/src/emit/html-source.ts +402 -0
- package/src/emit/manifest.ts +241 -0
- package/src/emit/react.ts +263 -0
- package/src/emit/scratch.ts +175 -0
- package/src/emit/source.ts +1094 -0
- package/src/emit/svelte.ts +230 -0
- package/src/emit/vue.ts +194 -0
- package/src/enumerate.ts +220 -0
- package/src/generate.ts +443 -0
- package/src/html-stylesheet.ts +173 -0
- package/src/index.ts +60 -0
- package/src/landing.ts +58 -0
- package/src/lib/exported-types.ts +114 -0
- package/src/lib/html-attributes.ts +113 -0
- package/src/lib/html-warnings.ts +81 -0
- package/src/lib/jsx-roots.ts +238 -0
- package/src/lib/module-of-source.ts +26 -0
- package/src/lib/naming.ts +65 -0
- package/src/lib/parse-type.ts +143 -0
- package/src/lib/react-spelling.ts +235 -0
- package/src/lib/scenario-story.ts +97 -0
- package/src/lib/slot-fill.ts +102 -0
- package/src/lib/template-files.ts +31 -0
- package/src/lib/types.ts +778 -0
- package/src/lib/void-elements.ts +15 -0
- package/src/load.ts +144 -0
- package/src/model.ts +568 -0
- package/src/options.ts +435 -0
- package/src/prop-types.ts +133 -0
- package/src/props-from.ts +678 -0
- package/src/protocol.ts +1135 -0
- package/src/react-view.ts +45 -0
- package/src/react.ts +34 -0
- package/src/sass-importers.ts +45 -0
- package/src/shell-acceptance.ts +45 -0
- package/src/shell-page.ts +133 -0
- package/src/shell-peers.ts +70 -0
- package/src/shell.ts +194 -0
- package/src/shells/charcell/page.ts +82 -0
- package/src/story-source.ts +391 -0
- package/src/story.ts +42 -0
- package/src/testing.ts +497 -0
- package/src/views.ts +183 -0
- package/src/vite-configuration.ts +675 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// Vue preview entry. Mounts a generated render unit (components + template) with
|
|
2
|
+
// a single reactive `props` object that is mutated in place on each update, so
|
|
3
|
+
// v-bind="props" re-renders the same component instance - the Zag driver machine
|
|
4
|
+
// stays alive across prop changes. Remounts each time the host sets a story or scenario.
|
|
5
|
+
import { createApp, h, reactive, shallowRef, type App } from 'vue';
|
|
6
|
+
import { registry } from '@preview-generated/vue/registry';
|
|
7
|
+
// The scenario editor's regenerated scratch story, merged under its reserved id.
|
|
8
|
+
import { registry as scratchRegistry } from '@preview-generated/scratch/vue';
|
|
9
|
+
// The kit's per-target setup module (side effects only) - see react/main.tsx.
|
|
10
|
+
import '@preview-setup/vue';
|
|
11
|
+
import { applyGlobals } from '../globals';
|
|
12
|
+
import {
|
|
13
|
+
announcePreviewReady,
|
|
14
|
+
announcePreviewShown,
|
|
15
|
+
announcePreviewStories,
|
|
16
|
+
announceStoryMounted,
|
|
17
|
+
PREVIEW_MESSAGE,
|
|
18
|
+
PREVIEW_MOUNT_ELEMENT_ID,
|
|
19
|
+
readPreviewMessage,
|
|
20
|
+
reportContentSize,
|
|
21
|
+
reportRenderError,
|
|
22
|
+
withEventRecorders,
|
|
23
|
+
withWriteBacks,
|
|
24
|
+
PendingWriteBacks,
|
|
25
|
+
type PreviewWriteBack,
|
|
26
|
+
} from '../../../src/protocol';
|
|
27
|
+
|
|
28
|
+
let props = reactive<Record<string, unknown>>({});
|
|
29
|
+
let application: App | null = null;
|
|
30
|
+
// The story's events, recorded with each set of props it gets.
|
|
31
|
+
let events: string[] = [];
|
|
32
|
+
// The story's two-way props, each written back as its event reports a value.
|
|
33
|
+
let bindings: PreviewWriteBack[] = [];
|
|
34
|
+
// The host's mount of the story, which each recorded event carries.
|
|
35
|
+
let mount: number | undefined;
|
|
36
|
+
// The values this pane has written back itself and the host has not yet
|
|
37
|
+
// answered: props the host sent before it took the newest keep that value.
|
|
38
|
+
const pending = new PendingWriteBacks();
|
|
39
|
+
|
|
40
|
+
// A controlled story takes a two-way prop's new value here, in the event
|
|
41
|
+
// that reports it, before the component puts a controlled input back to its
|
|
42
|
+
// prop's value at Vue's next tick: the prop holds the new value by then, so
|
|
43
|
+
// typing mid-text keeps the caret where it is. The host's write-back follows
|
|
44
|
+
// with the same value. Each write is numbered, the event reporting it
|
|
45
|
+
// carries the number, and props the host sent before it took the newest
|
|
46
|
+
// keep the pane's own value (`pending`).
|
|
47
|
+
function setProps(given: Record<string, unknown>) {
|
|
48
|
+
const next = withWriteBacks(withEventRecorders(given, events, window, mount, pending), bindings, (prop, value) => {
|
|
49
|
+
pending.wrote(prop, value);
|
|
50
|
+
if (props[prop] !== undefined) props[prop] = value;
|
|
51
|
+
});
|
|
52
|
+
for (const key of Object.keys(props)) if (!(key in next)) delete props[key];
|
|
53
|
+
Object.assign(props, next);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function errorMessage(error: unknown): string {
|
|
57
|
+
return error instanceof Error ? error.message : String(error);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Each story or scenario the host sets mounts fresh, so uncontrolled state
|
|
61
|
+
// never carries over from the last one; live prop edits update in place.
|
|
62
|
+
function setStory(id: string, nextProps?: Record<string, unknown>) {
|
|
63
|
+
// Each mount reads props of its own: an application that failed to mount
|
|
64
|
+
// cannot be unmounted, and would re-render on what it subscribed to.
|
|
65
|
+
props = reactive({});
|
|
66
|
+
setProps(nextProps ?? {});
|
|
67
|
+
reportRenderError();
|
|
68
|
+
// No longer current before it unmounts, so nothing it throws from here on
|
|
69
|
+
// counts against the story mounted next.
|
|
70
|
+
const previous = application;
|
|
71
|
+
application = null;
|
|
72
|
+
if (previous) previous.unmount();
|
|
73
|
+
// An application that could not mount left only its error message behind.
|
|
74
|
+
else document.getElementById(PREVIEW_MOUNT_ELEMENT_ID)!.replaceChildren();
|
|
75
|
+
const unit = { ...registry, ...scratchRegistry }[id];
|
|
76
|
+
if (!unit) return;
|
|
77
|
+
// The story's components are values its template's expressions read
|
|
78
|
+
// (`:as="Button"`), as a script-setup import is in an SFC, as well as tags.
|
|
79
|
+
const story = {
|
|
80
|
+
components: unit.components,
|
|
81
|
+
setup: () => ({ ...unit.components, props }),
|
|
82
|
+
template: unit.template,
|
|
83
|
+
};
|
|
84
|
+
// The root stands apart from the story, so it can still show the error the
|
|
85
|
+
// story throws as it sets up or renders.
|
|
86
|
+
// The message of an error the story throws, shown in its place - the way
|
|
87
|
+
// the React page's error boundary shows one - rather than an empty pane,
|
|
88
|
+
// and told to the host, as each story mounted since is.
|
|
89
|
+
const renderError = shallowRef<string | null>(null);
|
|
90
|
+
const current = createApp({
|
|
91
|
+
render: () => (renderError.value === null ? h(story) : h('pre', `render error: ${renderError.value}`)),
|
|
92
|
+
});
|
|
93
|
+
current.config.errorHandler = (error) => {
|
|
94
|
+
// A late error from a story since replaced says nothing of this one.
|
|
95
|
+
if (application !== current) return;
|
|
96
|
+
console.error(error);
|
|
97
|
+
renderError.value = errorMessage(error);
|
|
98
|
+
reportRenderError(renderError.value);
|
|
99
|
+
};
|
|
100
|
+
application = current;
|
|
101
|
+
const container = document.getElementById(PREVIEW_MOUNT_ELEMENT_ID)!;
|
|
102
|
+
try {
|
|
103
|
+
current.mount(container);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
// A failure the application could not handle itself leaves it unusable.
|
|
106
|
+
console.error(error);
|
|
107
|
+
application = null;
|
|
108
|
+
reportRenderError(errorMessage(error));
|
|
109
|
+
const message = document.createElement('pre');
|
|
110
|
+
message.textContent = `render error: ${errorMessage(error)}`;
|
|
111
|
+
container.replaceChildren(message);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
window.addEventListener('message', (event: MessageEvent) => {
|
|
116
|
+
const message = readPreviewMessage(event.data);
|
|
117
|
+
if (!message) return;
|
|
118
|
+
if (message.type === PREVIEW_MESSAGE.setStory) {
|
|
119
|
+
events = message.events ?? [];
|
|
120
|
+
bindings = message.bindings ?? [];
|
|
121
|
+
mount = message.mount;
|
|
122
|
+
pending.clear();
|
|
123
|
+
setStory(message.id, message.props);
|
|
124
|
+
// The first story, once painted, lets the host show the pane.
|
|
125
|
+
announcePreviewShown();
|
|
126
|
+
announceStoryMounted(message.id);
|
|
127
|
+
}
|
|
128
|
+
else if (message.type === PREVIEW_MESSAGE.props) setProps(pending.reconcile(message.props, message.answers));
|
|
129
|
+
else if (message.type === PREVIEW_MESSAGE.globals) applyGlobals(message.options);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
announcePreviewStories(Object.keys({ ...registry, ...scratchRegistry }));
|
|
133
|
+
announcePreviewReady();
|
|
134
|
+
// The story's size reaches the host on each change, so a shell can size the pane to it.
|
|
135
|
+
reportContentSize(document.getElementById(PREVIEW_MOUNT_ELEMENT_ID)!);
|
|
136
|
+
|
|
137
|
+
// The editor regenerates .preview-generated/scratch/vue.ts on each edit. Self-accept
|
|
138
|
+
// that dep (a no-op) so Vite scopes the change to *this* iframe instead of
|
|
139
|
+
// broadcasting a full-reload to every client on the shared dev server - which
|
|
140
|
+
// would wipe the host's editor state. The actual refresh is host-driven: after a
|
|
141
|
+
// regeneration it bumps this iframe's src, reloading it to pick up the new (invalidated)
|
|
142
|
+
// scratch module - deterministic, unlike relying on Vite's HMR event delivery.
|
|
143
|
+
if (import.meta.hot) {
|
|
144
|
+
import.meta.hot.accept('@preview-generated/scratch/vue', () => {});
|
|
145
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>preview - vue</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="app"></div>
|
|
10
|
+
<script type="module" src="./main.ts"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
@layer charcell.components {
|
|
2
|
+
/* The terminal screen: the shell is letterboxed to whole cells (round() snaps
|
|
3
|
+
both axes; older browsers fall back to the full viewport). Its ring is a
|
|
4
|
+
quiet charcell Frame, so the bars aren't edge to edge;
|
|
5
|
+
the Frame fills the screen as its one grid cell. The screen sits centered
|
|
6
|
+
in what is left over, by margins rounded down to whole pixels, so every
|
|
7
|
+
cell still starts on a whole pixel. */
|
|
8
|
+
.Application {
|
|
9
|
+
width: 100vw;
|
|
10
|
+
height: 100vh;
|
|
11
|
+
width: round(down, 100vw, 1ch);
|
|
12
|
+
height: round(down, 100vh, var(--charcell-row));
|
|
13
|
+
margin-left: round(down, calc((100vw - round(down, 100vw, 1ch)) / 2), 1px);
|
|
14
|
+
margin-top: round(down, calc((100vh - round(down, 100vh, var(--charcell-row))) / 2), 1px);
|
|
15
|
+
overflow: hidden;
|
|
16
|
+
display: grid;
|
|
17
|
+
grid-template: minmax(0, 1fr) / minmax(0, 1fr);
|
|
18
|
+
}
|
|
19
|
+
.Application__layout {
|
|
20
|
+
height: 100%;
|
|
21
|
+
display: grid;
|
|
22
|
+
grid-template-rows: auto 1fr auto;
|
|
23
|
+
}
|
|
24
|
+
/* The stage, a cell in from the ring at its sides; beside the navigation, the
|
|
25
|
+
split's handle is the cell at its start. */
|
|
26
|
+
.Application__main {
|
|
27
|
+
flex: 1 1 auto;
|
|
28
|
+
display: flex;
|
|
29
|
+
flex-direction: column;
|
|
30
|
+
min-width: 0;
|
|
31
|
+
min-height: 0;
|
|
32
|
+
padding: 0 1ch;
|
|
33
|
+
}
|
|
34
|
+
.Application__main--beside {
|
|
35
|
+
padding-left: 0;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// The shell's interface: the terminal screen, letterboxed to whole cells, and
|
|
2
|
+
// inside its ring the prompt bar (the top bar: the kit, its settings, and the
|
|
3
|
+
// view and target toggles), the navigation beside the stage in a split the
|
|
4
|
+
// reader can drag (NavigationSplit), and the status bar. The navigation is the
|
|
5
|
+
// shell's `navigation` option, toggled from the prompt bar, so the address keeps
|
|
6
|
+
// it; hidden, the stage takes the body's width, and shown again, its groups
|
|
7
|
+
// are open and collapsed as they were left. The stage keeps a cell from
|
|
8
|
+
// the ring at its sides; beside the navigation, the split's handle is the cell at
|
|
9
|
+
// its start. The page's title names what the preview shows and the kit, so
|
|
10
|
+
// each tab and history entry says which it is.
|
|
11
|
+
// Styled in its index.css.
|
|
12
|
+
import { Frame } from 'charcell/react/unlinked';
|
|
13
|
+
import { useEffect, useState } from 'react';
|
|
14
|
+
import { usePreviewController, usePreviewState } from '../../controller-context';
|
|
15
|
+
import { ComponentStage } from '../ComponentStage';
|
|
16
|
+
import { PromptBar } from '../PromptBar';
|
|
17
|
+
import { NAVIGATION_OPTION } from '../../shell-options';
|
|
18
|
+
import { Navigation } from '../Navigation';
|
|
19
|
+
import { NavigationSplit } from '../NavigationSplit';
|
|
20
|
+
import { StatusBar } from '../StatusBar';
|
|
21
|
+
import { ViewStage } from '../ViewStage';
|
|
22
|
+
import './index.css';
|
|
23
|
+
|
|
24
|
+
export function Application() {
|
|
25
|
+
const { catalog } = usePreviewController();
|
|
26
|
+
const selection = usePreviewState((state) => state.selection);
|
|
27
|
+
const shown =
|
|
28
|
+
selection.kind === 'view'
|
|
29
|
+
? catalog.views.find((view) => view.id === selection.id)?.label
|
|
30
|
+
: catalog.components.find((component) => component.id === selection.id)?.shortTitle;
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
document.title = shown ? `${shown} · ${catalog.kitName} preview` : `${catalog.kitName} preview`;
|
|
33
|
+
}, [shown, catalog.kitName]);
|
|
34
|
+
const navigationShown = usePreviewState((state) => state.options[NAVIGATION_OPTION] !== false);
|
|
35
|
+
// The navigation's collapsed groups, kept here while it is hidden.
|
|
36
|
+
const [collapsed, setCollapsed] = useState<ReadonlySet<string>>(() => new Set());
|
|
37
|
+
return (
|
|
38
|
+
<div className="Application">
|
|
39
|
+
{/* The terminal screen: the outermost ring, faint, so it groups everything
|
|
40
|
+
without outshining the content it groups. */}
|
|
41
|
+
<Frame as="div" quiet flush>
|
|
42
|
+
<div className="Application__layout">
|
|
43
|
+
<PromptBar />
|
|
44
|
+
<NavigationSplit
|
|
45
|
+
shown={navigationShown}
|
|
46
|
+
navigation={<Navigation collapsed={collapsed} onCollapsedChange={setCollapsed} />}
|
|
47
|
+
main={
|
|
48
|
+
<main className={`Application__main${navigationShown ? ' Application__main--beside' : ''}`}>
|
|
49
|
+
{selection.kind === 'view' ? (
|
|
50
|
+
// A custom view renders through the generic view iframe; the
|
|
51
|
+
// controller drives only its globals (the ready handshake delivers
|
|
52
|
+
// the current options, replayed on reload).
|
|
53
|
+
<ViewStage viewId={selection.id} />
|
|
54
|
+
) : (
|
|
55
|
+
<ComponentStage />
|
|
56
|
+
)}
|
|
57
|
+
</main>
|
|
58
|
+
}
|
|
59
|
+
/>
|
|
60
|
+
<StatusBar />
|
|
61
|
+
</div>
|
|
62
|
+
</Frame>
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
@layer charcell.components {
|
|
2
|
+
/* The bands: a content row and a rule row, the stroke centered in
|
|
3
|
+
its own row and the text on the other. The rule is `faint`, a separator.
|
|
4
|
+
When the zones do not fit on one row the content wraps onto more, a whole
|
|
5
|
+
row at a time, so no control is ever cut off; the rule row stays where it
|
|
6
|
+
was against the content, under it in a header and over it in a status
|
|
7
|
+
bar. */
|
|
8
|
+
.Bar {
|
|
9
|
+
display: flex;
|
|
10
|
+
flex-direction: column;
|
|
11
|
+
min-width: 0;
|
|
12
|
+
}
|
|
13
|
+
.Bar--status {
|
|
14
|
+
color: var(--charcell-mid);
|
|
15
|
+
}
|
|
16
|
+
/* An unruled band's empty rule row. */
|
|
17
|
+
.Bar__space {
|
|
18
|
+
height: var(--charcell-row);
|
|
19
|
+
}
|
|
20
|
+
/* The two zones on one row while they fit: the start packed from the
|
|
21
|
+
start, the end against the end. Crowded,
|
|
22
|
+
the zones wrap, the end zone keeping to the end of its row, and a zone
|
|
23
|
+
that does not fit a row by itself wraps its own items. Items sit a row
|
|
24
|
+
tall and rows stack with no gap, so every line stays on the cell grid. */
|
|
25
|
+
.Bar__content {
|
|
26
|
+
padding: 0 1ch;
|
|
27
|
+
display: flex;
|
|
28
|
+
flex-wrap: wrap;
|
|
29
|
+
align-items: center;
|
|
30
|
+
column-gap: 2ch;
|
|
31
|
+
row-gap: 0;
|
|
32
|
+
min-width: 0;
|
|
33
|
+
min-height: var(--charcell-row);
|
|
34
|
+
white-space: nowrap;
|
|
35
|
+
}
|
|
36
|
+
.Bar--flush .Bar__content {
|
|
37
|
+
padding: 0;
|
|
38
|
+
}
|
|
39
|
+
.Bar__start,
|
|
40
|
+
.Bar__end {
|
|
41
|
+
display: flex;
|
|
42
|
+
flex-wrap: wrap;
|
|
43
|
+
align-items: center;
|
|
44
|
+
column-gap: 2ch;
|
|
45
|
+
row-gap: 0;
|
|
46
|
+
min-width: 0;
|
|
47
|
+
min-height: var(--charcell-row);
|
|
48
|
+
}
|
|
49
|
+
.Bar__end {
|
|
50
|
+
margin-left: auto;
|
|
51
|
+
justify-content: flex-end;
|
|
52
|
+
}
|
|
53
|
+
/* A bar's start zone cluster: the lead and a picker sit a cell apart, tighter
|
|
54
|
+
than the 2ch the band's zones space their items by. */
|
|
55
|
+
.Bar__cluster {
|
|
56
|
+
display: flex;
|
|
57
|
+
flex-wrap: wrap;
|
|
58
|
+
align-items: center;
|
|
59
|
+
column-gap: 1ch;
|
|
60
|
+
row-gap: 0;
|
|
61
|
+
min-width: 0;
|
|
62
|
+
}
|
|
63
|
+
/* The bold word leading a bar - the prompt, the selected component. charcell's
|
|
64
|
+
reset flattens <strong>, so the weight is stated here. */
|
|
65
|
+
.Bar__lead {
|
|
66
|
+
font-weight: 700;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// The preview's bands: the prompt bar, the stage bar and the status bar. Two
|
|
2
|
+
// rows, each with one job, the way a terminal prints them: `header` is a
|
|
3
|
+
// content row over a rule row, `status` a rule row over a content row. The
|
|
4
|
+
// content row has two zones - the children pack from the start, `end` packs
|
|
5
|
+
// against the end. When they do not fit, the content wraps onto further rows, a whole row at a
|
|
6
|
+
// time, so a control is never cut off.
|
|
7
|
+
// `lead` is the bold word that opens the start zone (the prompt), the children beside it a cell apart. The rule row is a charcell
|
|
8
|
+
// Separator across the band's full width; `joined` runs its ends on to meet
|
|
9
|
+
// the lines beside the band (the frame's ring, a divider), as ├ and ┤.
|
|
10
|
+
// `unruled`, the rule row is left empty: a band that sits inside a place with
|
|
11
|
+
// edges of its own (the stage, beside the navigation's line), where a rule across
|
|
12
|
+
// it would cross them. `flush`, the content row takes no cells at its sides,
|
|
13
|
+
// the place around the band holding them.
|
|
14
|
+
// Styled in its index.css.
|
|
15
|
+
import { Separator } from 'charcell/react/unlinked';
|
|
16
|
+
import type { ReactNode } from 'react';
|
|
17
|
+
import './index.css';
|
|
18
|
+
|
|
19
|
+
export function Bar({
|
|
20
|
+
variant = 'header',
|
|
21
|
+
joined,
|
|
22
|
+
unruled,
|
|
23
|
+
flush,
|
|
24
|
+
lead,
|
|
25
|
+
end,
|
|
26
|
+
children,
|
|
27
|
+
}: {
|
|
28
|
+
variant?: 'header' | 'status';
|
|
29
|
+
joined?: boolean;
|
|
30
|
+
unruled?: boolean;
|
|
31
|
+
flush?: boolean;
|
|
32
|
+
lead?: ReactNode;
|
|
33
|
+
end?: ReactNode;
|
|
34
|
+
children?: ReactNode;
|
|
35
|
+
}) {
|
|
36
|
+
const rule = unruled ? (
|
|
37
|
+
<div className="Bar__space" />
|
|
38
|
+
) : (
|
|
39
|
+
<Separator decorative join={joined ? 'both' : undefined} />
|
|
40
|
+
);
|
|
41
|
+
return (
|
|
42
|
+
<div className={`Bar Bar--${variant}${flush ? ' Bar--flush' : ''}`}>
|
|
43
|
+
{variant === 'status' && rule}
|
|
44
|
+
<div className="Bar__content">
|
|
45
|
+
<div className="Bar__start">
|
|
46
|
+
{lead === undefined ? (
|
|
47
|
+
children
|
|
48
|
+
) : (
|
|
49
|
+
<div className="Bar__cluster">
|
|
50
|
+
<strong className="Bar__lead">{lead}</strong>
|
|
51
|
+
{children}
|
|
52
|
+
</div>
|
|
53
|
+
)}
|
|
54
|
+
</div>
|
|
55
|
+
{end !== undefined && <div className="Bar__end">{end}</div>}
|
|
56
|
+
</div>
|
|
57
|
+
{variant === 'header' && rule}
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
@layer charcell.components {
|
|
2
|
+
/* A code pane: a quiet charcell Frame titled with its
|
|
3
|
+
target, filling its cell of the grid (PreviewGrid), which holds its
|
|
4
|
+
height in whole rows. Inside, a row saying what the pane holds, with the
|
|
5
|
+
copy button at its end, over the source. */
|
|
6
|
+
.CodePane {
|
|
7
|
+
flex: 1;
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
min-width: 0;
|
|
11
|
+
min-height: 0;
|
|
12
|
+
}
|
|
13
|
+
.CodePane__content {
|
|
14
|
+
height: 100%;
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-direction: column;
|
|
17
|
+
min-height: 0;
|
|
18
|
+
}
|
|
19
|
+
/* In a pane too narrow for both, the actions wrap under the note, a whole
|
|
20
|
+
row down, rather than cutting the note short. */
|
|
21
|
+
/* The Frame is flush, so the scrollbars run beside its
|
|
22
|
+
ring: the row and the source each keep a cell from it. */
|
|
23
|
+
.CodePane__row {
|
|
24
|
+
padding: 0 1ch;
|
|
25
|
+
display: flex;
|
|
26
|
+
flex-wrap: wrap;
|
|
27
|
+
align-items: center;
|
|
28
|
+
column-gap: 2ch;
|
|
29
|
+
row-gap: 0;
|
|
30
|
+
min-height: var(--charcell-row);
|
|
31
|
+
}
|
|
32
|
+
.CodePane__note {
|
|
33
|
+
flex: 1 0 auto;
|
|
34
|
+
white-space: nowrap;
|
|
35
|
+
color: var(--charcell-mid);
|
|
36
|
+
}
|
|
37
|
+
/* How many warnings the html has, beside the note at its tone, the
|
|
38
|
+
count opening them (HtmlWarnings). */
|
|
39
|
+
.CodePane__warnings {
|
|
40
|
+
white-space: nowrap;
|
|
41
|
+
color: var(--charcell-mid);
|
|
42
|
+
}
|
|
43
|
+
.CodePane__actions {
|
|
44
|
+
display: flex;
|
|
45
|
+
align-items: center;
|
|
46
|
+
gap: 1ch;
|
|
47
|
+
margin-left: auto;
|
|
48
|
+
}
|
|
49
|
+
/* The source: pre-formatted in the shell's one monospace, in the charcell
|
|
50
|
+
ScrollArea that takes the rows the pane's row leaves, so
|
|
51
|
+
a long line never widens the stage and a long source never lengthens it.
|
|
52
|
+
Its lines keep to themselves, scrolling sideways, or wrap at the pane's
|
|
53
|
+
edge while the shell's wrap option is on. */
|
|
54
|
+
/* Why a pane has no source, in the box the source would fill. */
|
|
55
|
+
.CodePane__reason {
|
|
56
|
+
margin: 0;
|
|
57
|
+
padding: 0 1ch;
|
|
58
|
+
color: var(--charcell-mid);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// One code pane, under a target's preview pane in the stage's grid
|
|
2
|
+
// (PreviewGrid): the story's source as a consumer writes it for that
|
|
3
|
+
// target, in a quiet charcell Frame titled with the target. A row says what
|
|
4
|
+
// the pane holds, with a copy button at its end, over the source in a
|
|
5
|
+
// charcell CodeBlock that fills the rest of the pane and scrolls a whole row
|
|
6
|
+
// (and column) at a time. Wrapping is the
|
|
7
|
+
// shell's `wrap` option, toggled for every pane from the code view's heading
|
|
8
|
+
// row (WrapToggle): on, a long line wraps at the pane's edge and the source
|
|
9
|
+
// scrolls only down; off, a long line runs on and the source scrolls across
|
|
10
|
+
// too. A kit that names its own code block (KitCodeBlock) shows the source
|
|
11
|
+
// there instead, the row's note and copy button kept, and the block follows
|
|
12
|
+
// the same option. Without
|
|
13
|
+
// source, the row says so in a word (`printing`, `unavailable`) and the box
|
|
14
|
+
// says why, the copy button disabled. html that leaves out what it cannot
|
|
15
|
+
// evaluate at rest (script-held state) says how many warnings beside the
|
|
16
|
+
// note, the count opening them, one to a line, in a popover
|
|
17
|
+
// (HtmlWarnings), as the html pane's legend does. The
|
|
18
|
+
// code is the controller's (`state.code`), printed as the panes change,
|
|
19
|
+
// so the pane follows a scenario pick, a prop edit and the editor's tree.
|
|
20
|
+
// The scroll area takes keyboard focus and shows it as charcell's do, its
|
|
21
|
+
// scrollbar's thumb climbing to the foreground. The Frame is flush, so the scroll area's bars
|
|
22
|
+
// run beside its ring; the row and the source keep their own cell from it.
|
|
23
|
+
// Styled in its index.css.
|
|
24
|
+
import { useEffect, useState } from 'react';
|
|
25
|
+
import { Button, CodeBlock, Frame, ScrollArea } from 'charcell/react/unlinked';
|
|
26
|
+
import type { PreviewTarget } from '../../../../../src/shell';
|
|
27
|
+
import { usePreviewController, usePreviewState } from '../../controller-context';
|
|
28
|
+
import { KitCodeBlock } from '../KitCodeBlock';
|
|
29
|
+
import { WRAP_OPTION } from '../../shell-options';
|
|
30
|
+
import { HtmlWarnings } from '../HtmlWarnings';
|
|
31
|
+
import './index.css';
|
|
32
|
+
|
|
33
|
+
/** How long the copy button's confirmation shows, in milliseconds. */
|
|
34
|
+
const COPIED_MILLISECONDS = 1500;
|
|
35
|
+
|
|
36
|
+
/** What a code pane shows: the source, or, without it, a word and why. */
|
|
37
|
+
interface Shown {
|
|
38
|
+
text?: string;
|
|
39
|
+
status?: string;
|
|
40
|
+
reason?: string;
|
|
41
|
+
/** What the html leaves out at rest. */
|
|
42
|
+
warnings?: string[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function CodePane({ target }: { target: PreviewTarget }) {
|
|
46
|
+
const code = usePreviewState((state) => state.code);
|
|
47
|
+
// A kit's own code block shows the source in its place.
|
|
48
|
+
const kitBlock = usePreviewController().catalog.codeBlock !== undefined;
|
|
49
|
+
const wrapped = usePreviewState((state) => state.options[WRAP_OPTION] !== false);
|
|
50
|
+
const [copied, setCopied] = useState(false);
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (!copied) return;
|
|
53
|
+
const timer = setTimeout(() => setCopied(false), COPIED_MILLISECONDS);
|
|
54
|
+
return () => clearTimeout(timer);
|
|
55
|
+
}, [copied]);
|
|
56
|
+
// html is printed apart from the other targets, so it can be on its way or
|
|
57
|
+
// not to be had; another target's code is always there.
|
|
58
|
+
const { text, status, reason, warnings }: Shown = !code
|
|
59
|
+
? {}
|
|
60
|
+
: target !== 'html'
|
|
61
|
+
? { text: code.targets[target] }
|
|
62
|
+
: code.html.status === 'ready'
|
|
63
|
+
? { text: code.html.source, warnings: code.html.warnings }
|
|
64
|
+
: code.html.status === 'loading'
|
|
65
|
+
? { status: 'printing' }
|
|
66
|
+
: { status: 'unavailable', reason: code.html.reason };
|
|
67
|
+
const copy = () => {
|
|
68
|
+
if (text === undefined) return;
|
|
69
|
+
navigator.clipboard?.writeText(text).then(
|
|
70
|
+
() => setCopied(true),
|
|
71
|
+
() => undefined,
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
const lines = text === undefined ? 0 : text.split('\n').length - 1;
|
|
75
|
+
return (
|
|
76
|
+
<div className="CodePane" data-preview-code={target}>
|
|
77
|
+
<Frame title={target} quiet flush fill>
|
|
78
|
+
<div className="CodePane__content">
|
|
79
|
+
<div className="CodePane__row">
|
|
80
|
+
{/* The live region says how the code stands and that it was
|
|
81
|
+
copied; the line count, which follows every edit, sits
|
|
82
|
+
beside it, read but not announced. */}
|
|
83
|
+
<span className="CodePane__note">
|
|
84
|
+
<span role="status">{text === undefined ? (status ?? '') : copied ? `${target} copied` : ''}</span>
|
|
85
|
+
{text !== undefined && !copied ? `${lines} ${lines === 1 ? 'line' : 'lines'}` : null}
|
|
86
|
+
</span>
|
|
87
|
+
{warnings && warnings.length > 0 ? (
|
|
88
|
+
<HtmlWarnings warnings={warnings} className="CodePane__warnings" />
|
|
89
|
+
) : null}
|
|
90
|
+
<span className="CodePane__actions">
|
|
91
|
+
<Button variant="dense" label="copy" disabled={text === undefined} onClick={copy} />
|
|
92
|
+
</span>
|
|
93
|
+
</div>
|
|
94
|
+
{kitBlock ? (
|
|
95
|
+
<KitCodeBlock target={target} />
|
|
96
|
+
) : text !== undefined ? (
|
|
97
|
+
<CodeBlock
|
|
98
|
+
label={`${target} code`}
|
|
99
|
+
code={text}
|
|
100
|
+
wrap={wrapped}
|
|
101
|
+
orientation="both"
|
|
102
|
+
fill
|
|
103
|
+
/>
|
|
104
|
+
) : (
|
|
105
|
+
<ScrollArea label={`${target} code`} overscroll="none" fill>
|
|
106
|
+
<p className="CodePane__reason">{reason}</p>
|
|
107
|
+
</ScrollArea>
|
|
108
|
+
)}
|
|
109
|
+
</div>
|
|
110
|
+
</Frame>
|
|
111
|
+
</div>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
@layer charcell.components {
|
|
2
|
+
/* A component story's stage: its bar, and its body
|
|
3
|
+
taking the rest of the height - the grid of panes, under the scenario row
|
|
4
|
+
while it shows, in a stacked charcell Splitter (StageSplit) that
|
|
5
|
+
fills the body. The body ends on a whole row, as everything above it
|
|
6
|
+
does, so the split's rows and the grid's do too. */
|
|
7
|
+
.ComponentStage {
|
|
8
|
+
flex: 1;
|
|
9
|
+
display: flex;
|
|
10
|
+
flex-direction: column;
|
|
11
|
+
min-width: 0;
|
|
12
|
+
min-height: 0;
|
|
13
|
+
}
|
|
14
|
+
.ComponentStage__body {
|
|
15
|
+
flex: 1;
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
min-width: 0;
|
|
19
|
+
min-height: 0;
|
|
20
|
+
}
|
|
21
|
+
/* What the body says while no view shows. */
|
|
22
|
+
.ComponentStage__note {
|
|
23
|
+
margin: 0;
|
|
24
|
+
color: var(--charcell-mid);
|
|
25
|
+
}
|
|
26
|
+
}
|