@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
package/src/model.ts
ADDED
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
// Build the framework-agnostic ResolvedStory for one component: merge prop-derived
|
|
2
|
+
// propTypes with the story file (controls, prop defaults, slots, scenarios, omit).
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
isEventType,
|
|
6
|
+
relayedBindingsOf,
|
|
7
|
+
twoWayBindingsOf,
|
|
8
|
+
} from '@js-template-engine/core';
|
|
9
|
+
|
|
10
|
+
import { propTypeForProp, defaultPropForProp } from './prop-types.js';
|
|
11
|
+
import { isStructurallyOmitted } from './story.js';
|
|
12
|
+
import { collectSlotComponents } from './lib/slot-fill.js';
|
|
13
|
+
import { EMPTY_SCENARIO_ID, sanitize, scenarioStoryId } from './lib/naming.js';
|
|
14
|
+
import { isVoidElement } from './lib/void-elements.js';
|
|
15
|
+
import { ALL_TARGETS } from './lib/types.js';
|
|
16
|
+
import type {
|
|
17
|
+
PropTypeSpecification,
|
|
18
|
+
EnumeratedComponent,
|
|
19
|
+
JsonValue,
|
|
20
|
+
Scenario,
|
|
21
|
+
SlotFill,
|
|
22
|
+
SlotPlan,
|
|
23
|
+
Story,
|
|
24
|
+
PreviewBinding,
|
|
25
|
+
ResolvedStory,
|
|
26
|
+
PreviewPropType,
|
|
27
|
+
PreviewControlHints,
|
|
28
|
+
PreviewLabels,
|
|
29
|
+
Target,
|
|
30
|
+
} from './lib/types.js';
|
|
31
|
+
|
|
32
|
+
/** The category a component without a story file `category` sits in. */
|
|
33
|
+
export const DEFAULT_CATEGORY = 'Components';
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The two-way props a component's template declares, in prop order: each
|
|
37
|
+
* `bindable` object's prop, copy form or relayed, the props it names, and
|
|
38
|
+
* whether a Vue consumer binds it with a bare `v-model`. A component written
|
|
39
|
+
* by hand declares none.
|
|
40
|
+
*
|
|
41
|
+
* @param component - The enumerated component.
|
|
42
|
+
* @returns The bindings.
|
|
43
|
+
*/
|
|
44
|
+
export function bindingsOf(component: EnumeratedComponent): PreviewBinding[] {
|
|
45
|
+
const template = component.template;
|
|
46
|
+
if (!template || Array.isArray(template) || !template.props) return [];
|
|
47
|
+
const vue: unknown = template.extensions?.['vue'];
|
|
48
|
+
const vueModel =
|
|
49
|
+
typeof vue === 'object' && vue !== null
|
|
50
|
+
? (vue as { model?: unknown }).model
|
|
51
|
+
: undefined;
|
|
52
|
+
const order = Object.keys(template.props);
|
|
53
|
+
return [
|
|
54
|
+
...twoWayBindingsOf(template.props).map((binding) => ({
|
|
55
|
+
prop: binding.prop,
|
|
56
|
+
...(binding.defaultProp !== undefined
|
|
57
|
+
? { defaultProp: binding.defaultProp }
|
|
58
|
+
: {}),
|
|
59
|
+
changeProp: binding.changeProp,
|
|
60
|
+
})),
|
|
61
|
+
...relayedBindingsOf(template.props).map((binding) => ({
|
|
62
|
+
prop: binding.prop,
|
|
63
|
+
changeProp: binding.changeProp,
|
|
64
|
+
})),
|
|
65
|
+
]
|
|
66
|
+
.sort(
|
|
67
|
+
(first, second) => order.indexOf(first.prop) - order.indexOf(second.prop)
|
|
68
|
+
)
|
|
69
|
+
.map(({ changeProp, ...binding }) => ({
|
|
70
|
+
...binding,
|
|
71
|
+
...(changeProp !== undefined ? { changeProp } : {}),
|
|
72
|
+
...(vueModel === binding.prop ? { vueModel: true } : {}),
|
|
73
|
+
...(template.typeParameters?.length ? { generic: true } : {}),
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The values a prop's scenarios should cover: each select option and each
|
|
79
|
+
* boolean value other than the prop's default (a select's `false` too only
|
|
80
|
+
* when the prop has one), for every included select and
|
|
81
|
+
* boolean control. Shared by scenario generation and the check's coverage.
|
|
82
|
+
*/
|
|
83
|
+
export function scenarioValues(
|
|
84
|
+
propTypes: readonly PropTypeSpecification[],
|
|
85
|
+
defaultProps: Record<string, JsonValue>
|
|
86
|
+
): Array<{ prop: string; value: string | boolean }> {
|
|
87
|
+
const values: Array<{ prop: string; value: string | boolean }> = [];
|
|
88
|
+
for (const propType of propTypes) {
|
|
89
|
+
if (!propType.include) continue;
|
|
90
|
+
const current = defaultProps[propType.name];
|
|
91
|
+
if (propType.control === 'boolean') {
|
|
92
|
+
values.push({ prop: propType.name, value: current !== true });
|
|
93
|
+
} else if (propType.control === 'select') {
|
|
94
|
+
for (const option of propType.options ?? []) {
|
|
95
|
+
// As for a toggle, `false` is no departure from a prop left unset.
|
|
96
|
+
if (
|
|
97
|
+
option !== undefined &&
|
|
98
|
+
option !== current &&
|
|
99
|
+
!(option === false && current === undefined)
|
|
100
|
+
)
|
|
101
|
+
values.push({ prop: propType.name, value: option });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return values;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Whether a story file's `generate` lets this prop generate scenarios. */
|
|
109
|
+
export function generatesProp(
|
|
110
|
+
generate: Story['generate'],
|
|
111
|
+
prop: string
|
|
112
|
+
): boolean {
|
|
113
|
+
if (generate === undefined) return true;
|
|
114
|
+
if (generate === false) return false;
|
|
115
|
+
if (Array.isArray(generate)) return generate.includes(prop);
|
|
116
|
+
return !generate.exclude.includes(prop);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** The keys a story file sets. */
|
|
120
|
+
const STORY_KEYS = [
|
|
121
|
+
'omit',
|
|
122
|
+
'standalone',
|
|
123
|
+
'unlisted',
|
|
124
|
+
'category',
|
|
125
|
+
'label',
|
|
126
|
+
'defaultProps',
|
|
127
|
+
'controls',
|
|
128
|
+
'fixed',
|
|
129
|
+
'generate',
|
|
130
|
+
'slots',
|
|
131
|
+
'around',
|
|
132
|
+
'scenarios',
|
|
133
|
+
'options',
|
|
134
|
+
] as const satisfies readonly (keyof Story)[];
|
|
135
|
+
|
|
136
|
+
/** What to write for a key a story file does not take, where one thing is meant. */
|
|
137
|
+
const STORY_KEY_REPLACEMENTS: ReadonlyMap<string, string> = new Map([
|
|
138
|
+
['partial', 'standalone: false'],
|
|
139
|
+
['description', 'description on the template'],
|
|
140
|
+
]);
|
|
141
|
+
|
|
142
|
+
/** The keys a curated scenario may set. */
|
|
143
|
+
const CURATED_SCENARIO_KEYS: ReadonlySet<string> = new Set([
|
|
144
|
+
'id',
|
|
145
|
+
'label',
|
|
146
|
+
'description',
|
|
147
|
+
'props',
|
|
148
|
+
'slots',
|
|
149
|
+
'options',
|
|
150
|
+
'default',
|
|
151
|
+
]);
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* The component of the first element fill, at any depth of a fill tree,
|
|
155
|
+
* that fills its default slot through `slots.default` rather than
|
|
156
|
+
* `children`, or `undefined` when none does.
|
|
157
|
+
*/
|
|
158
|
+
function elementFillSettingDefaultSlot(
|
|
159
|
+
fill: SlotFill | undefined
|
|
160
|
+
): string | undefined {
|
|
161
|
+
if (!fill || typeof fill !== 'object' || Array.isArray(fill))
|
|
162
|
+
return undefined;
|
|
163
|
+
if (fill.kind === 'element') {
|
|
164
|
+
if (fill.slots && 'default' in fill.slots) return fill.component;
|
|
165
|
+
for (const nested of [...Object.values(fill.slots ?? {}), fill.children]) {
|
|
166
|
+
const found = elementFillSettingDefaultSlot(nested);
|
|
167
|
+
if (found !== undefined) return found;
|
|
168
|
+
}
|
|
169
|
+
} else if (fill.kind === 'html') {
|
|
170
|
+
return elementFillSettingDefaultSlot(fill.children);
|
|
171
|
+
} else if (fill.kind === 'fragment') {
|
|
172
|
+
for (const child of fill.children ?? []) {
|
|
173
|
+
const found = elementFillSettingDefaultSlot(child);
|
|
174
|
+
if (found !== undefined) return found;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* The tag of the first html fill, at any depth of a fill tree, that gives a
|
|
182
|
+
* void element (img, input, br) children, or `undefined` when none does.
|
|
183
|
+
*/
|
|
184
|
+
function voidElementWithChildren(
|
|
185
|
+
fill: SlotFill | undefined
|
|
186
|
+
): string | undefined {
|
|
187
|
+
if (!fill || typeof fill !== 'object' || Array.isArray(fill))
|
|
188
|
+
return undefined;
|
|
189
|
+
if (fill.kind === 'html') {
|
|
190
|
+
if (fill.children !== undefined && isVoidElement(fill.tag)) return fill.tag;
|
|
191
|
+
return voidElementWithChildren(fill.children);
|
|
192
|
+
}
|
|
193
|
+
if (fill.kind === 'element') {
|
|
194
|
+
for (const nested of [...Object.values(fill.slots ?? {}), fill.children]) {
|
|
195
|
+
const found = voidElementWithChildren(nested);
|
|
196
|
+
if (found !== undefined) return found;
|
|
197
|
+
}
|
|
198
|
+
} else if (fill.kind === 'fragment') {
|
|
199
|
+
for (const child of fill.children ?? []) {
|
|
200
|
+
const found = voidElementWithChildren(child);
|
|
201
|
+
if (found !== undefined) return found;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return undefined;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** The id a generated scenario takes: `<prop>-<value>`, or the prop for a
|
|
208
|
+
* boolean turned on, unless that is the preview's own Empty scenario's id,
|
|
209
|
+
* which a boolean named `empty` takes as `empty-true`. A curated scenario
|
|
210
|
+
* with this id replaces it. */
|
|
211
|
+
export function generatedScenarioId(
|
|
212
|
+
prop: string,
|
|
213
|
+
value: string | boolean
|
|
214
|
+
): string {
|
|
215
|
+
if (value === true) return prop === EMPTY_SCENARIO_ID ? `${prop}-true` : prop;
|
|
216
|
+
return `${prop}-${String(value)}`;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** The default label of a generated scenario: `prop: value`, or the bare prop
|
|
220
|
+
* for a boolean turned on. */
|
|
221
|
+
function defaultGeneratedLabel(prop: string, value: string | boolean): string {
|
|
222
|
+
return value === true ? prop : `${prop}: ${String(value)}`;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** Whether a scenario sets exactly one prop, to this value. */
|
|
226
|
+
function setsOnly(scenario: Scenario, prop: string, value: JsonValue): boolean {
|
|
227
|
+
const entries = Object.entries(scenario.props ?? {});
|
|
228
|
+
return (
|
|
229
|
+
entries.length === 1 && entries[0][0] === prop && entries[0][1] === value
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* One scenario per value `scenarioValues` lists, narrowed by the story file's
|
|
235
|
+
* `generate`, skipping a value a curated scenario already sets alone, and any
|
|
236
|
+
* id a curated scenario already uses: that scenario replaces the generated one.
|
|
237
|
+
* Labeled by the kit's `generatedScenario`, or `prop: value` and the bare prop
|
|
238
|
+
* for a boolean turned on.
|
|
239
|
+
*/
|
|
240
|
+
function generateScenarios(
|
|
241
|
+
propTypes: readonly PropTypeSpecification[],
|
|
242
|
+
defaultProps: Record<string, JsonValue>,
|
|
243
|
+
story: Story | undefined,
|
|
244
|
+
labels: PreviewLabels
|
|
245
|
+
): Scenario[] {
|
|
246
|
+
const generate = story?.generate;
|
|
247
|
+
if (generate === false) return [];
|
|
248
|
+
const curated = story?.scenarios ?? [];
|
|
249
|
+
const takenIds = new Set(curated.map((scenario) => scenario.id));
|
|
250
|
+
const label = labels.generatedScenario ?? defaultGeneratedLabel;
|
|
251
|
+
const scenarios: Scenario[] = [];
|
|
252
|
+
for (const { prop, value } of scenarioValues(propTypes, defaultProps)) {
|
|
253
|
+
if (!generatesProp(generate, prop)) continue;
|
|
254
|
+
if (curated.some((scenario) => setsOnly(scenario, prop, value))) continue;
|
|
255
|
+
const id = generatedScenarioId(prop, value);
|
|
256
|
+
if (takenIds.has(id)) continue;
|
|
257
|
+
takenIds.add(id);
|
|
258
|
+
scenarios.push({
|
|
259
|
+
id,
|
|
260
|
+
label: label(prop, value),
|
|
261
|
+
props: { [prop]: value },
|
|
262
|
+
generated: true,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
return scenarios;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Resolve the story of one component: its controls, default props,
|
|
270
|
+
* scenarios, slot content and the targets it renders in.
|
|
271
|
+
*
|
|
272
|
+
* @param component - The enumerated component.
|
|
273
|
+
* @param story - The component's story file, when it has one.
|
|
274
|
+
* @param hints - The kit's control hints.
|
|
275
|
+
* @param labels - The kit's preview labels.
|
|
276
|
+
* @param omitPattern - Component names matching it get no story.
|
|
277
|
+
* @param kitTargets - The scripted targets the kit builds; the component's own
|
|
278
|
+
* targets are narrowed to them.
|
|
279
|
+
* @returns The resolved story.
|
|
280
|
+
*/
|
|
281
|
+
export function resolveStory(
|
|
282
|
+
component: EnumeratedComponent,
|
|
283
|
+
story: Story | undefined,
|
|
284
|
+
hints: PreviewControlHints = {},
|
|
285
|
+
labels: PreviewLabels = {},
|
|
286
|
+
omitPattern?: RegExp,
|
|
287
|
+
kitTargets: readonly Target[] = ALL_TARGETS
|
|
288
|
+
): ResolvedStory {
|
|
289
|
+
const omit =
|
|
290
|
+
(story?.omit ?? false) ||
|
|
291
|
+
isStructurallyOmitted(component.name, omitPattern);
|
|
292
|
+
// A component that is not standalone (a compound's part, a shared building
|
|
293
|
+
// block) stays in the manifest for the editor but gets no story - set on the
|
|
294
|
+
// story file (templates) or the manual spec (hand-written components).
|
|
295
|
+
const standalone =
|
|
296
|
+
(story?.standalone ?? true) && (component.standalone ?? true);
|
|
297
|
+
// An unlisted story is generated as any other, only left out of what a
|
|
298
|
+
// reader browses; a component with no story of its own has nothing to hide.
|
|
299
|
+
const unlisted =
|
|
300
|
+
((story?.unlisted ?? false) || (component.unlisted ?? false)) &&
|
|
301
|
+
!omit &&
|
|
302
|
+
standalone;
|
|
303
|
+
|
|
304
|
+
// propTypes from props, then story file control overrides (false disables).
|
|
305
|
+
const propTypes: PreviewPropType[] = [];
|
|
306
|
+
for (const [propName, def] of Object.entries(component.props)) {
|
|
307
|
+
let propType = propTypeForProp(component.name, propName, def, hints);
|
|
308
|
+
if (def.description)
|
|
309
|
+
propType = { ...propType, description: def.description };
|
|
310
|
+
const override = story?.controls?.[propName];
|
|
311
|
+
if (override === false) propType = { ...propType, include: false };
|
|
312
|
+
else if (override) propType = { ...propType, ...override };
|
|
313
|
+
// A fixed prop is always passed and never shown.
|
|
314
|
+
if (story?.fixed && propName in story.fixed)
|
|
315
|
+
propType = { ...propType, include: false };
|
|
316
|
+
propTypes.push({
|
|
317
|
+
...propType,
|
|
318
|
+
declaredType: def.type,
|
|
319
|
+
required: def.required === true,
|
|
320
|
+
...(def.default !== undefined ? { declaredDefault: def.default } : {}),
|
|
321
|
+
...(def.documentedDefault !== undefined
|
|
322
|
+
? { documentedDefault: def.documentedDefault }
|
|
323
|
+
: {}),
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// default props: template defaults + size config, then story file defaultProps.
|
|
328
|
+
const defaultProps: Record<string, JsonValue> = {};
|
|
329
|
+
// The values the preview starts a prop from that a consumer never writes:
|
|
330
|
+
// a hint's, for a prop the component gives no default and the story file
|
|
331
|
+
// leaves alone.
|
|
332
|
+
const previewDefaults: Record<string, JsonValue> = {};
|
|
333
|
+
for (const [propName, def] of Object.entries(component.props)) {
|
|
334
|
+
const value = defaultPropForProp(component.name, propName, def, hints);
|
|
335
|
+
if (value !== undefined) defaultProps[propName] = value;
|
|
336
|
+
if (
|
|
337
|
+
value !== undefined &&
|
|
338
|
+
def.default === undefined &&
|
|
339
|
+
!(propName in (story?.defaultProps ?? {})) &&
|
|
340
|
+
!(propName in (story?.fixed ?? {}))
|
|
341
|
+
)
|
|
342
|
+
previewDefaults[propName] = value;
|
|
343
|
+
}
|
|
344
|
+
// A component with a default slot gets visible placeholder text - but only
|
|
345
|
+
// when the story file declares no slot plan at all. A story file that curates any
|
|
346
|
+
// slot (a named fill, an explicit default) owns the slot story: injecting
|
|
347
|
+
// children beside a named fill fabricates a mount no consumer writes.
|
|
348
|
+
// `slots: {}` forces a genuinely slotless mount. A default slot that
|
|
349
|
+
// exposes values gets none either: its content is a function of those
|
|
350
|
+
// values (React calls `children(scope)`), so text there is a mount no
|
|
351
|
+
// consumer writes, and the slot's fallback renders instead.
|
|
352
|
+
if (
|
|
353
|
+
component.hasDefaultSlot &&
|
|
354
|
+
!component.defaultSlotScoped &&
|
|
355
|
+
!story?.slots &&
|
|
356
|
+
defaultProps.children === undefined
|
|
357
|
+
) {
|
|
358
|
+
defaultProps.children = component.name;
|
|
359
|
+
// The preview's own, which a consumer's source leaves out, unless the
|
|
360
|
+
// story file gives the slot text of its own.
|
|
361
|
+
if (
|
|
362
|
+
!('children' in (story?.defaultProps ?? {})) &&
|
|
363
|
+
!('children' in (story?.fixed ?? {}))
|
|
364
|
+
)
|
|
365
|
+
previewDefaults.children = component.name;
|
|
366
|
+
}
|
|
367
|
+
Object.assign(defaultProps, story?.defaultProps ?? {}, story?.fixed ?? {});
|
|
368
|
+
|
|
369
|
+
// A named slot spelled flat (`slots: { header: ... }` instead of
|
|
370
|
+
// `slots: { named: { header: ... } }`) would silently never render - the
|
|
371
|
+
// emitters read only `default` and `named`. Fail loudly instead. A
|
|
372
|
+
// scenario's own slots are a plan of the same shape.
|
|
373
|
+
const slotPlans: Array<[string, SlotPlan | undefined]> = [
|
|
374
|
+
['', story?.slots],
|
|
375
|
+
...(story?.scenarios ?? [])
|
|
376
|
+
.filter((scenario) => scenario.generated !== true)
|
|
377
|
+
.map((scenario): [string, SlotPlan | undefined] => [
|
|
378
|
+
`scenario '${scenario.id}': `,
|
|
379
|
+
scenario.slots,
|
|
380
|
+
]),
|
|
381
|
+
];
|
|
382
|
+
for (const [where, plan] of slotPlans) {
|
|
383
|
+
if (plan === undefined) continue;
|
|
384
|
+
if (typeof plan !== 'object' || plan === null || Array.isArray(plan)) {
|
|
385
|
+
throw new Error(
|
|
386
|
+
`${component.name}: ${where}slots must be a slot plan, { default, named }`
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
const unknownSlotKeys = Object.keys(plan).filter(
|
|
390
|
+
(key) => key !== 'default' && key !== 'named'
|
|
391
|
+
);
|
|
392
|
+
if (unknownSlotKeys.length > 0) {
|
|
393
|
+
throw new Error(
|
|
394
|
+
`${component.name}: ${where}unknown slot-plan key(s) ${unknownSlotKeys.join(', ')} - ` +
|
|
395
|
+
`named slots go under "named": { slots: { named: { ... } } }.`
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
const planFills = slotPlans.flatMap(([, plan]) => [
|
|
400
|
+
plan?.default,
|
|
401
|
+
...Object.values(plan?.named ?? {}),
|
|
402
|
+
]);
|
|
403
|
+
|
|
404
|
+
// `around` holds the content before and after the component, and a scoped
|
|
405
|
+
// fill has no slot there to give it values.
|
|
406
|
+
const around: unknown = story?.around;
|
|
407
|
+
if (around !== undefined) {
|
|
408
|
+
if (typeof around !== 'object' || around === null || Array.isArray(around))
|
|
409
|
+
throw new Error(
|
|
410
|
+
`${component.name}: around must be { before, after }, each a fill`
|
|
411
|
+
);
|
|
412
|
+
const unknownAroundKeys = Object.keys(around).filter(
|
|
413
|
+
(key) => key !== 'before' && key !== 'after'
|
|
414
|
+
);
|
|
415
|
+
if (unknownAroundKeys.length > 0)
|
|
416
|
+
throw new Error(
|
|
417
|
+
`${component.name}: unknown around key(s) ${unknownAroundKeys.join(', ')} - around takes before and after`
|
|
418
|
+
);
|
|
419
|
+
for (const [where, fill] of Object.entries(around) as Array<
|
|
420
|
+
[string, SlotFill | undefined]
|
|
421
|
+
>) {
|
|
422
|
+
if (fill?.kind === 'scoped')
|
|
423
|
+
throw new Error(
|
|
424
|
+
`${component.name}: around.${where} is a scoped fill, which takes values from a slot; beside the component there is none`
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
const aroundFills = [story?.around?.before, story?.around?.after];
|
|
429
|
+
|
|
430
|
+
// The composed component's default slot takes an element fill's
|
|
431
|
+
// `children`; `slots` names its named slots only. A `default` there would
|
|
432
|
+
// otherwise reach the emitters as a slot named `default`, which Svelte
|
|
433
|
+
// refuses as a reserved word.
|
|
434
|
+
for (const fill of [...planFills, ...aroundFills]) {
|
|
435
|
+
const filled = elementFillSettingDefaultSlot(fill);
|
|
436
|
+
if (filled !== undefined) {
|
|
437
|
+
throw new Error(
|
|
438
|
+
`${component.name}: the element fill of '${filled}' sets slots.default - its default slot takes children`
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// A void element renders self-closed, so children on one would be dropped
|
|
444
|
+
// in one framework and refused by another's compiler.
|
|
445
|
+
for (const fill of [...planFills, ...aroundFills]) {
|
|
446
|
+
const tag = voidElementWithChildren(fill);
|
|
447
|
+
if (tag !== undefined) {
|
|
448
|
+
throw new Error(
|
|
449
|
+
`${component.name}: the html fill <${tag}> has children - ${tag} is a void element and takes none`
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// A story file sets only what a story holds; a key the preview does not
|
|
455
|
+
// read would otherwise change nothing without a word.
|
|
456
|
+
const unknownStoryKey = Object.keys(story ?? {}).find(
|
|
457
|
+
(key) => !(STORY_KEYS as readonly string[]).includes(key)
|
|
458
|
+
);
|
|
459
|
+
if (unknownStoryKey !== undefined) {
|
|
460
|
+
const replacement = STORY_KEY_REPLACEMENTS.get(unknownStoryKey);
|
|
461
|
+
throw new Error(
|
|
462
|
+
`${component.name}: story sets unknown key '${unknownStoryKey}' - ${
|
|
463
|
+
replacement === undefined
|
|
464
|
+
? `a story sets ${STORY_KEYS.join(', ')}`
|
|
465
|
+
: `use ${replacement}`
|
|
466
|
+
}`
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// A curated scenario sets only what a scenario holds. The scenarios the
|
|
471
|
+
// preview generates itself reach the model beside them, marked
|
|
472
|
+
// `generated`, and are not the story file's to check.
|
|
473
|
+
for (const scenario of story?.scenarios ?? []) {
|
|
474
|
+
if (scenario.generated === true) continue;
|
|
475
|
+
if (scenario.id === EMPTY_SCENARIO_ID)
|
|
476
|
+
throw new Error(
|
|
477
|
+
`${component.name}: scenario id '${EMPTY_SCENARIO_ID}' is the preview's own Empty scenario's; give the scenario another id`
|
|
478
|
+
);
|
|
479
|
+
const unknownKey = Object.keys(scenario).find(
|
|
480
|
+
(key) => !CURATED_SCENARIO_KEYS.has(key)
|
|
481
|
+
);
|
|
482
|
+
if (unknownKey !== undefined) {
|
|
483
|
+
throw new Error(
|
|
484
|
+
`${component.name}: scenario '${scenario.id}' sets unknown key '${unknownKey}' - a scenario sets ${[...CURATED_SCENARIO_KEYS].join(', ')}`
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// A scenario's description is text for a shell to show, and its options
|
|
490
|
+
// are option values by id; anything else is a story file mistake that would
|
|
491
|
+
// otherwise reach the catalog unnoticed. Whether each names one of the
|
|
492
|
+
// kit's options is the check's to say, which reads the kit's options.
|
|
493
|
+
for (const scenario of story?.scenarios ?? []) {
|
|
494
|
+
if (
|
|
495
|
+
scenario.description !== undefined &&
|
|
496
|
+
typeof scenario.description !== 'string'
|
|
497
|
+
) {
|
|
498
|
+
throw new Error(
|
|
499
|
+
`${component.name}: scenario '${scenario.id}' has a description that is not a string.`
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
const options: unknown = scenario.options;
|
|
503
|
+
if (
|
|
504
|
+
options !== undefined &&
|
|
505
|
+
(typeof options !== 'object' ||
|
|
506
|
+
options === null ||
|
|
507
|
+
Array.isArray(options) ||
|
|
508
|
+
Object.values(options).some(
|
|
509
|
+
(value) => typeof value !== 'string' && typeof value !== 'boolean'
|
|
510
|
+
))
|
|
511
|
+
) {
|
|
512
|
+
throw new Error(
|
|
513
|
+
`${component.name}: scenario '${scenario.id}' has options that are not option values by id, each a string or a boolean.`
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// slot components to import
|
|
519
|
+
const slotComponentSet = new Set<string>();
|
|
520
|
+
try {
|
|
521
|
+
// A scenario's own content is imported with the story's: one module
|
|
522
|
+
// per target holds them all.
|
|
523
|
+
for (const fill of planFills) collectSlotComponents(fill, slotComponentSet);
|
|
524
|
+
for (const fill of aroundFills)
|
|
525
|
+
collectSlotComponents(fill, slotComponentSet);
|
|
526
|
+
} catch (error) {
|
|
527
|
+
// Name the component so a bad story file is findable without a bisect.
|
|
528
|
+
throw new Error(`${component.name}: ${(error as Error).message}`, {
|
|
529
|
+
cause: error,
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
return {
|
|
534
|
+
name: component.name,
|
|
535
|
+
...(component.description !== undefined
|
|
536
|
+
? { description: component.description }
|
|
537
|
+
: {}),
|
|
538
|
+
title: `${story?.category ?? labels.category ?? DEFAULT_CATEGORY}/${story?.label ?? component.name}`,
|
|
539
|
+
omit,
|
|
540
|
+
standalone,
|
|
541
|
+
unlisted,
|
|
542
|
+
propTypes,
|
|
543
|
+
events: propTypes
|
|
544
|
+
.filter((propType) => isEventType(propType.declaredType))
|
|
545
|
+
.map((propType) => propType.name),
|
|
546
|
+
bindings: bindingsOf(component),
|
|
547
|
+
defaultProps,
|
|
548
|
+
...(Object.keys(previewDefaults).length > 0 ? { previewDefaults } : {}),
|
|
549
|
+
slots: story?.slots,
|
|
550
|
+
...(story?.around ? { around: story.around } : {}),
|
|
551
|
+
scenarios: [
|
|
552
|
+
...(story?.scenarios ?? []),
|
|
553
|
+
...generateScenarios(propTypes, defaultProps, story, labels),
|
|
554
|
+
],
|
|
555
|
+
slotComponents: [...slotComponentSet],
|
|
556
|
+
contentSlots: {
|
|
557
|
+
default: component.hasDefaultSlot,
|
|
558
|
+
named: component.slotNames,
|
|
559
|
+
...(component.scopeRequiredSlots?.length
|
|
560
|
+
? { scopeRequired: component.scopeRequiredSlots }
|
|
561
|
+
: {}),
|
|
562
|
+
},
|
|
563
|
+
options: story?.options,
|
|
564
|
+
targets: (component.targets ?? ALL_TARGETS).filter((target) =>
|
|
565
|
+
kitTargets.includes(target)
|
|
566
|
+
),
|
|
567
|
+
};
|
|
568
|
+
}
|