@histoire/shared 0.7.4

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Guillaume Chau
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ export declare const voidElements: string[];
@@ -0,0 +1,3 @@
1
+ export const voidElements = [
2
+ 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr',
3
+ ];
@@ -0,0 +1,3 @@
1
+ export * from './const.js';
2
+ export * from './serialize-js.js';
3
+ export * from './util.js';
@@ -0,0 +1,3 @@
1
+ export * from './const.js';
2
+ export * from './serialize-js.js';
3
+ export * from './util.js';
@@ -0,0 +1 @@
1
+ export declare function serializeJs(value: any): string;
@@ -0,0 +1,126 @@
1
+ const KEY_ESCAPE_REG = /[\s-.:|#@$£*%]/;
2
+ const MAX_SINGLE_LINE_ARRAY_LENGTH = 3;
3
+ export function serializeJs(value) {
4
+ const seen = new Set();
5
+ if (value === undefined) {
6
+ return 'undefined';
7
+ }
8
+ if (value === null) {
9
+ return 'null';
10
+ }
11
+ if (typeof value === 'string') {
12
+ return `'${value}'`;
13
+ }
14
+ if (typeof value === 'boolean') {
15
+ return value ? 'true' : 'false';
16
+ }
17
+ if (Array.isArray(value)) {
18
+ return printLines(arrayToSourceLines(value, seen));
19
+ }
20
+ if (typeof value === 'object') {
21
+ return printLines(objectToSourceLines(value, seen));
22
+ }
23
+ if (value?.__autoBuildingObject) {
24
+ return value;
25
+ }
26
+ if (typeof value === 'function' && value.name) {
27
+ return value.name;
28
+ }
29
+ return value.toString();
30
+ }
31
+ function printLines(lines) {
32
+ return lines.map(line => ' '.repeat(line.spaces) + line.line).join('\n');
33
+ }
34
+ function objectToSourceLines(object, seen, indentCount = 0) {
35
+ if (seen.has(object)) {
36
+ object = {};
37
+ }
38
+ else {
39
+ seen.add(object);
40
+ }
41
+ return createLines(indentCount, lines => {
42
+ lines.push('{');
43
+ lines.push(...createLines(1, lines => {
44
+ for (const key in object) {
45
+ const value = object[key];
46
+ let printedKey = key;
47
+ if (KEY_ESCAPE_REG.test(key)) {
48
+ printedKey = `'${printedKey}'`;
49
+ }
50
+ addLinesFromValue(lines, value, `${printedKey}: `, ',', seen);
51
+ }
52
+ }));
53
+ lines.push('}');
54
+ });
55
+ }
56
+ function arrayToSourceLines(array, seen, indentCount = 0) {
57
+ if (seen.has(array)) {
58
+ array = [];
59
+ }
60
+ else {
61
+ seen.add(array);
62
+ }
63
+ return createLines(indentCount, lines => {
64
+ const contentLines = createLines(1, lines => {
65
+ for (const value of array) {
66
+ addLinesFromValue(lines, value, '', ',', seen);
67
+ }
68
+ });
69
+ if (contentLines.length === 0) {
70
+ lines.push('[]');
71
+ }
72
+ else if (contentLines.length <= MAX_SINGLE_LINE_ARRAY_LENGTH && !contentLines.some(line => line.spaces > 1)) {
73
+ const [first] = contentLines;
74
+ first.line = contentLines.map(({ line }) => line.substring(0, line.length - 1)).join(', ');
75
+ first.line = `[${first.line}]`;
76
+ first.spaces--;
77
+ lines.push(first);
78
+ }
79
+ else {
80
+ lines.push('[', ...contentLines, ']');
81
+ }
82
+ });
83
+ }
84
+ function createLines(indentCount, handler) {
85
+ const lines = [];
86
+ handler(lines);
87
+ return lines.map(line => {
88
+ if (line.spaces != null) {
89
+ line.spaces += indentCount;
90
+ return line;
91
+ }
92
+ return { spaces: indentCount, line };
93
+ });
94
+ }
95
+ function addLinesFromValue(lines, value, before, after, seen) {
96
+ let result;
97
+ if (Array.isArray(value)) {
98
+ lines.push(...wrap(arrayToSourceLines(value, seen), before, after));
99
+ return;
100
+ }
101
+ else if (value && typeof value === 'object') {
102
+ lines.push(...wrap(objectToSourceLines(value, seen), before, after));
103
+ return;
104
+ }
105
+ else if (typeof value === 'string') {
106
+ result = value.includes('\'') ? `\`${value}\`` : `'${value}'`;
107
+ }
108
+ else if (typeof value === 'undefined') {
109
+ result = 'undefined';
110
+ }
111
+ else if (value === null) {
112
+ result = 'null';
113
+ }
114
+ else if (typeof value === 'boolean') {
115
+ result = value ? 'true' : 'false';
116
+ }
117
+ else {
118
+ result = value;
119
+ }
120
+ lines.push(before + result + after);
121
+ }
122
+ function wrap(lines, before, after) {
123
+ lines[0].line = before + lines[0].line;
124
+ lines[lines.length - 1].line += after;
125
+ return lines;
126
+ }
@@ -0,0 +1,10 @@
1
+ export declare function indent(lines: string[], count?: number): string[];
2
+ export declare function unindent(code: string): string;
3
+ interface AutoBuildingOject {
4
+ key: string;
5
+ cache: Record<string | symbol, AutoBuildingOject>;
6
+ target: any;
7
+ proxy: any;
8
+ }
9
+ export declare function createAutoBuildingObject(format?: (key: string) => string, specialKeysHandler?: (target: any, p: string | symbol) => (() => unknown) | null, key?: string, depth?: number): AutoBuildingOject;
10
+ export {};
@@ -0,0 +1,70 @@
1
+ /* eslint-disable @typescript-eslint/ban-types */
2
+ export function indent(lines, count = 1) {
3
+ return lines.map(line => `${' '.repeat(count)}${line}`);
4
+ }
5
+ export function unindent(code) {
6
+ const lines = code.split('\n');
7
+ let indentLevel = -1;
8
+ let indentText;
9
+ const linesToAnalyze = lines.filter(line => line.trim().length > 0);
10
+ for (const line of linesToAnalyze) {
11
+ const match = /^\s*/.exec(line);
12
+ if (match && (indentLevel === -1 || indentLevel > match[0].length)) {
13
+ indentLevel = match[0].length;
14
+ indentText = match[0];
15
+ }
16
+ }
17
+ const result = [];
18
+ for (const line of lines) {
19
+ result.push(line.replace(indentText, ''));
20
+ }
21
+ return result.join('\n').trim();
22
+ }
23
+ export function createAutoBuildingObject(format, specialKeysHandler, key = '', depth = 0) {
24
+ const cache = {};
25
+ if (depth > 32)
26
+ return { key, cache, target: {}, proxy: () => key };
27
+ const target = () => {
28
+ const k = key + '()';
29
+ return format ? format(k) : k;
30
+ };
31
+ const proxy = new Proxy(target, {
32
+ get(_, p) {
33
+ if (p === '__autoBuildingObject') {
34
+ return true;
35
+ }
36
+ if (p === '__autoBuildingObjectGetKey') {
37
+ return key;
38
+ }
39
+ if (specialKeysHandler) {
40
+ const fn = specialKeysHandler(target, p);
41
+ if (fn) {
42
+ return fn();
43
+ }
44
+ }
45
+ if (p === 'toString') {
46
+ const k = key + '.toString()';
47
+ return () => format ? format(k) : k;
48
+ }
49
+ if (p === Symbol.toPrimitive) {
50
+ return () => format ? format(key) : key;
51
+ }
52
+ if (!cache[p]) {
53
+ const childKey = key ? `${key}.${p.toString()}` : p.toString();
54
+ const child = createAutoBuildingObject(format, specialKeysHandler, childKey, depth + 1);
55
+ cache[p] = { key: childKey, ...child };
56
+ }
57
+ return cache[p].proxy;
58
+ },
59
+ apply(_, thisArg, args) {
60
+ const k = `${key}(${args.join(', ')})`;
61
+ return format ? format(k) : k;
62
+ },
63
+ });
64
+ return {
65
+ key,
66
+ cache,
67
+ target,
68
+ proxy,
69
+ };
70
+ }
@@ -0,0 +1,3 @@
1
+ export * from './codegen/index.js';
2
+ export * from './types.js';
3
+ export * from './state.js';
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from './codegen/index.js';
2
+ export * from './types.js';
3
+ export * from './state.js';
@@ -0,0 +1,4 @@
1
+ import type { Variant } from './types';
2
+ export declare function clone(data: any): any;
3
+ export declare function omit(data: any, keys: string[]): {};
4
+ export declare function applyStateToVariant(variant: Variant, state: any): void;
package/dist/state.js ADDED
@@ -0,0 +1,39 @@
1
+ export function clone(data) {
2
+ try {
3
+ return structuredClone(data);
4
+ }
5
+ catch (e) {
6
+ console.warn(e, `Fallback to JSON cloning`);
7
+ try {
8
+ return JSON.parse(JSON.stringify(data));
9
+ }
10
+ catch (e) {
11
+ console.error(e);
12
+ }
13
+ return data;
14
+ }
15
+ }
16
+ export function omit(data, keys) {
17
+ const copy = {};
18
+ for (const key in data) {
19
+ if (!keys.includes(key)) {
20
+ copy[key] = data[key];
21
+ }
22
+ }
23
+ return copy;
24
+ }
25
+ export function applyStateToVariant(variant, state) {
26
+ if (variant.state) {
27
+ for (const key in state) {
28
+ if (variant.state[key] && !key.startsWith('_h') && typeof variant.state[key] === 'object' && !Array.isArray(variant.state[key])) {
29
+ Object.assign(variant.state[key], state[key]);
30
+ }
31
+ else {
32
+ variant.state[key] = state[key];
33
+ }
34
+ }
35
+ }
36
+ else {
37
+ variant.state = state;
38
+ }
39
+ }
@@ -0,0 +1,125 @@
1
+ export interface StoryFile {
2
+ id: string;
3
+ framework: string;
4
+ component: any;
5
+ story: Story;
6
+ path: string[];
7
+ }
8
+ export declare type StoryLayout = {
9
+ type: 'single';
10
+ iframe?: boolean;
11
+ } | {
12
+ type: 'grid';
13
+ width?: number | string;
14
+ };
15
+ export interface Story {
16
+ id: string;
17
+ title: string;
18
+ group?: string;
19
+ variants: Variant[];
20
+ layout?: StoryLayout;
21
+ icon?: string;
22
+ iconColor?: string;
23
+ docsOnly?: boolean;
24
+ file?: StoryFile;
25
+ lastSelectedVariant?: Variant;
26
+ slots?: () => Readonly<any>;
27
+ }
28
+ export interface Variant {
29
+ id: string;
30
+ title: string;
31
+ icon?: string;
32
+ iconColor?: string;
33
+ initState?: () => any;
34
+ setupApp?: (payload: any) => unknown;
35
+ slots?: () => Readonly<any>;
36
+ state?: any;
37
+ source?: string;
38
+ responsiveDisabled?: boolean;
39
+ configReady?: boolean;
40
+ previewReady?: boolean;
41
+ }
42
+ export interface PropDefinition {
43
+ name: string;
44
+ types?: string[];
45
+ required?: boolean;
46
+ default?: any;
47
+ }
48
+ export interface AutoPropComponentDefinition {
49
+ name: string;
50
+ index: number;
51
+ props: PropDefinition[];
52
+ }
53
+ export interface ServerStoryFile {
54
+ id: string;
55
+ /**
56
+ * Absolute path
57
+ */
58
+ path: string;
59
+ /**
60
+ * File name without extension
61
+ */
62
+ fileName: string;
63
+ /**
64
+ * Generated path for tree UI
65
+ */
66
+ treePath?: string[];
67
+ /**
68
+ * Use the module id in imports to allow HMR
69
+ */
70
+ moduleId: string;
71
+ /**
72
+ * Resolved story data from story file execution
73
+ */
74
+ story?: ServerStory;
75
+ /**
76
+ * Data sent to user tree config functions
77
+ */
78
+ treeFile?: ServerTreeFile;
79
+ }
80
+ export interface ServerStory {
81
+ id: string;
82
+ title: string;
83
+ group?: string;
84
+ variants: ServerVariant[];
85
+ layout?: {
86
+ type: 'single';
87
+ } | {
88
+ type: 'grid';
89
+ width?: number | string;
90
+ };
91
+ icon?: string;
92
+ iconColor?: string;
93
+ docsOnly?: boolean;
94
+ docsText?: string;
95
+ }
96
+ export interface ServerVariant {
97
+ id: string;
98
+ title: string;
99
+ icon?: string;
100
+ iconColor?: string;
101
+ }
102
+ export interface ServerTreeFile {
103
+ title: string;
104
+ path: string;
105
+ }
106
+ export interface ServerTreeLeaf {
107
+ title: string;
108
+ index: number;
109
+ }
110
+ export interface ServerTreeFolder {
111
+ title: string;
112
+ children: (ServerTreeFolder | ServerTreeLeaf)[];
113
+ }
114
+ export interface ServerTreeGroup {
115
+ group: true;
116
+ id: string;
117
+ title: string;
118
+ children: (ServerTreeFolder | ServerTreeLeaf)[];
119
+ }
120
+ export declare type ServerTree = (ServerTreeGroup | ServerTreeFolder | ServerTreeLeaf)[];
121
+ export interface ServerRunPayload {
122
+ file: ServerStoryFile;
123
+ storyData: ServerStory[];
124
+ el: HTMLElement;
125
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@histoire/shared",
3
+ "version": "0.7.4",
4
+ "description": "Shared utilities for Histoire",
5
+ "license": "MIT",
6
+ "author": {
7
+ "name": "Guillaume Chau"
8
+ },
9
+ "repository": {
10
+ "url": "https://github.com/Akryum/histoire.git",
11
+ "type": "git",
12
+ "directory": "packages/histoire-shared"
13
+ },
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "type": "module",
18
+ "exports": {
19
+ ".": "./dist/index.js",
20
+ "./*": "./*",
21
+ "./client-node": "./dist/client/server/run.js"
22
+ },
23
+ "main": "./dist/index.js",
24
+ "module": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "sideEffects": false,
27
+ "dependencies": {},
28
+ "devDependencies": {
29
+ "typescript": "^4.6.3"
30
+ },
31
+ "scripts": {
32
+ "build": "rimraf dist && tsc -d",
33
+ "watch": "tsc -d -w --sourceMap"
34
+ }
35
+ }
@@ -0,0 +1,3 @@
1
+ export const voidElements = [
2
+ 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr',
3
+ ]
@@ -0,0 +1,3 @@
1
+ export * from './const.js'
2
+ export * from './serialize-js.js'
3
+ export * from './util.js'
@@ -0,0 +1,133 @@
1
+ const KEY_ESCAPE_REG = /[\s-.:|#@$£*%]/
2
+ const MAX_SINGLE_LINE_ARRAY_LENGTH = 3
3
+
4
+ interface Line {
5
+ spaces: number
6
+ line: string
7
+ }
8
+
9
+ export function serializeJs (value: any): string {
10
+ const seen = new Set()
11
+
12
+ if (value === undefined) {
13
+ return 'undefined'
14
+ }
15
+ if (value === null) {
16
+ return 'null'
17
+ }
18
+ if (typeof value === 'string') {
19
+ return `'${value}'`
20
+ }
21
+ if (typeof value === 'boolean') {
22
+ return value ? 'true' : 'false'
23
+ }
24
+ if (Array.isArray(value)) {
25
+ return printLines(arrayToSourceLines(value, seen))
26
+ }
27
+ if (typeof value === 'object') {
28
+ return printLines(objectToSourceLines(value, seen))
29
+ }
30
+ if (value?.__autoBuildingObject) {
31
+ return value
32
+ }
33
+ if (typeof value === 'function' && value.name) {
34
+ return value.name
35
+ }
36
+ return value.toString()
37
+ }
38
+
39
+ function printLines (lines: Line[]) {
40
+ return lines.map(line => ' '.repeat(line.spaces) + line.line).join('\n')
41
+ }
42
+
43
+ function objectToSourceLines (object, seen: Set<unknown>, indentCount = 0) {
44
+ if (seen.has(object)) {
45
+ object = {}
46
+ } else {
47
+ seen.add(object)
48
+ }
49
+
50
+ return createLines(indentCount, lines => {
51
+ lines.push('{')
52
+ lines.push(...createLines(1, lines => {
53
+ for (const key in object) {
54
+ const value = object[key]
55
+
56
+ let printedKey = key
57
+ if (KEY_ESCAPE_REG.test(key)) {
58
+ printedKey = `'${printedKey}'`
59
+ }
60
+
61
+ addLinesFromValue(lines, value, `${printedKey}: `, ',', seen)
62
+ }
63
+ }))
64
+ lines.push('}')
65
+ })
66
+ }
67
+
68
+ function arrayToSourceLines (array: any[], seen: Set<unknown>, indentCount = 0): Array<Line> {
69
+ if (seen.has(array)) {
70
+ array = []
71
+ } else {
72
+ seen.add(array)
73
+ }
74
+
75
+ return createLines(indentCount, lines => {
76
+ const contentLines = createLines(1, lines => {
77
+ for (const value of array) {
78
+ addLinesFromValue(lines, value, '', ',', seen)
79
+ }
80
+ })
81
+ if (contentLines.length === 0) {
82
+ lines.push('[]')
83
+ } else if (contentLines.length <= MAX_SINGLE_LINE_ARRAY_LENGTH && !contentLines.some(line => line.spaces > 1)) {
84
+ const [first] = contentLines
85
+ first.line = contentLines.map(({ line }) => line.substring(0, line.length - 1)).join(', ')
86
+ first.line = `[${first.line}]`
87
+ first.spaces--
88
+ lines.push(first)
89
+ } else {
90
+ lines.push('[', ...contentLines, ']')
91
+ }
92
+ })
93
+ }
94
+
95
+ function createLines (indentCount: number, handler: (lines: any[]) => unknown): Array<Line> {
96
+ const lines: any[] = []
97
+ handler(lines)
98
+ return lines.map(line => {
99
+ if (line.spaces != null) {
100
+ line.spaces += indentCount
101
+ return line
102
+ }
103
+ return { spaces: indentCount, line }
104
+ })
105
+ }
106
+
107
+ function addLinesFromValue (lines: Line[], value, before, after, seen) {
108
+ let result
109
+ if (Array.isArray(value)) {
110
+ lines.push(...wrap(arrayToSourceLines(value, seen), before, after))
111
+ return
112
+ } else if (value && typeof value === 'object') {
113
+ lines.push(...wrap(objectToSourceLines(value, seen), before, after))
114
+ return
115
+ } else if (typeof value === 'string') {
116
+ result = value.includes('\'') ? `\`${value}\`` : `'${value}'`
117
+ } else if (typeof value === 'undefined') {
118
+ result = 'undefined'
119
+ } else if (value === null) {
120
+ result = 'null'
121
+ } else if (typeof value === 'boolean') {
122
+ result = value ? 'true' : 'false'
123
+ } else {
124
+ result = value
125
+ }
126
+ lines.push(before + result + after)
127
+ }
128
+
129
+ function wrap (lines: Line[], before: string, after: string) {
130
+ lines[0].line = before + lines[0].line
131
+ lines[lines.length - 1].line += after
132
+ return lines
133
+ }
@@ -0,0 +1,79 @@
1
+ /* eslint-disable @typescript-eslint/ban-types */
2
+
3
+ export function indent (lines: string[], count = 1) {
4
+ return lines.map(line => `${' '.repeat(count)}${line}`)
5
+ }
6
+
7
+ export function unindent (code: string) {
8
+ const lines = code.split('\n')
9
+ let indentLevel = -1
10
+ let indentText: string
11
+ const linesToAnalyze = lines.filter(line => line.trim().length > 0)
12
+ for (const line of linesToAnalyze) {
13
+ const match = /^\s*/.exec(line)
14
+ if (match && (indentLevel === -1 || indentLevel > match[0].length)) {
15
+ indentLevel = match[0].length
16
+ indentText = match[0]
17
+ }
18
+ }
19
+ const result: string[] = []
20
+ for (const line of lines) {
21
+ result.push(line.replace(indentText, ''))
22
+ }
23
+ return result.join('\n').trim()
24
+ }
25
+
26
+ interface AutoBuildingOject {
27
+ key: string
28
+ cache: Record<string | symbol, AutoBuildingOject>
29
+ target: any
30
+ proxy: any
31
+ }
32
+
33
+ export function createAutoBuildingObject (format?: (key: string) => string, specialKeysHandler?: (target: any, p: string | symbol) => (() => unknown) | null, key = '', depth = 0): AutoBuildingOject {
34
+ const cache: Record<string | symbol, AutoBuildingOject> = {}
35
+ if (depth > 32) return { key, cache, target: {}, proxy: () => key }
36
+ const target: any = () => {
37
+ const k = key + '()'
38
+ return format ? format(k) : k
39
+ }
40
+ const proxy = new Proxy(target, {
41
+ get (_, p) {
42
+ if (p === '__autoBuildingObject') {
43
+ return true
44
+ }
45
+ if (p === '__autoBuildingObjectGetKey') {
46
+ return key
47
+ }
48
+ if (specialKeysHandler) {
49
+ const fn = specialKeysHandler(target, p)
50
+ if (fn) {
51
+ return fn()
52
+ }
53
+ }
54
+ if (p === 'toString') {
55
+ const k = key + '.toString()'
56
+ return () => format ? format(k) : k
57
+ }
58
+ if (p === Symbol.toPrimitive) {
59
+ return () => format ? format(key) : key
60
+ }
61
+ if (!cache[p]) {
62
+ const childKey = key ? `${key}.${p.toString()}` : p.toString()
63
+ const child = createAutoBuildingObject(format, specialKeysHandler, childKey, depth + 1)
64
+ cache[p] = { key: childKey, ...child }
65
+ }
66
+ return cache[p].proxy
67
+ },
68
+ apply (_, thisArg, args) {
69
+ const k = `${key}(${args.join(', ')})`
70
+ return format ? format(k) : k
71
+ },
72
+ })
73
+ return {
74
+ key,
75
+ cache,
76
+ target,
77
+ proxy,
78
+ }
79
+ }
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './codegen/index.js'
2
+ export * from './types.js'
3
+ export * from './state.js'
package/src/state.ts ADDED
@@ -0,0 +1,39 @@
1
+ import type { Variant } from './types'
2
+
3
+ export function clone (data) {
4
+ try {
5
+ return structuredClone(data)
6
+ } catch (e) {
7
+ console.warn(e, `Fallback to JSON cloning`)
8
+ try {
9
+ return JSON.parse(JSON.stringify(data))
10
+ } catch (e) {
11
+ console.error(e)
12
+ }
13
+ return data
14
+ }
15
+ }
16
+
17
+ export function omit (data, keys: string[]) {
18
+ const copy = {}
19
+ for (const key in data) {
20
+ if (!keys.includes(key)) {
21
+ copy[key] = data[key]
22
+ }
23
+ }
24
+ return copy
25
+ }
26
+
27
+ export function applyStateToVariant (variant: Variant, state: any) {
28
+ if (variant.state) {
29
+ for (const key in state) {
30
+ if (variant.state[key] && !key.startsWith('_h') && typeof variant.state[key] === 'object' && !Array.isArray(variant.state[key])) {
31
+ Object.assign(variant.state[key], state[key])
32
+ } else {
33
+ variant.state[key] = state[key]
34
+ }
35
+ }
36
+ } else {
37
+ variant.state = state
38
+ }
39
+ }
package/src/types.ts ADDED
@@ -0,0 +1,141 @@
1
+ export interface StoryFile {
2
+ id: string
3
+ framework: string
4
+ component: any
5
+ story: Story
6
+ path: string[]
7
+ }
8
+
9
+ export type StoryLayout = {
10
+ type: 'single'
11
+ iframe?: boolean
12
+ } | {
13
+ type: 'grid'
14
+ width?: number | string
15
+ }
16
+
17
+ export interface Story {
18
+ id: string
19
+ title: string
20
+ group?: string
21
+ variants: Variant[]
22
+ layout?: StoryLayout
23
+ icon?: string
24
+ iconColor?: string
25
+ docsOnly?: boolean
26
+ file?: StoryFile
27
+ lastSelectedVariant?: Variant
28
+ slots?: () => Readonly<any>
29
+ }
30
+
31
+ export interface Variant {
32
+ id: string
33
+ title: string
34
+ icon?: string
35
+ iconColor?: string
36
+ initState?: () => any
37
+ setupApp?: (payload: any) => unknown
38
+ slots?: () => Readonly<any>
39
+ state?: any
40
+ source?: string
41
+ responsiveDisabled?: boolean
42
+ configReady?: boolean
43
+ previewReady?: boolean
44
+ }
45
+
46
+ export interface PropDefinition {
47
+ name: string
48
+ types?: string[]
49
+ required?: boolean
50
+ default?: any
51
+ }
52
+
53
+ export interface AutoPropComponentDefinition {
54
+ name: string
55
+ index: number
56
+ props: PropDefinition[]
57
+ }
58
+
59
+ /* SERVER */
60
+
61
+ export interface ServerStoryFile {
62
+ id: string
63
+ /**
64
+ * Absolute path
65
+ */
66
+ path: string
67
+ /**
68
+ * File name without extension
69
+ */
70
+ fileName: string
71
+ /**
72
+ * Generated path for tree UI
73
+ */
74
+ treePath?: string[]
75
+ /**
76
+ * Use the module id in imports to allow HMR
77
+ */
78
+ moduleId: string
79
+ /**
80
+ * Resolved story data from story file execution
81
+ */
82
+ story?: ServerStory
83
+ /**
84
+ * Data sent to user tree config functions
85
+ */
86
+ treeFile?: ServerTreeFile
87
+ }
88
+
89
+ export interface ServerStory {
90
+ id: string
91
+ title: string
92
+ group?: string
93
+ variants: ServerVariant[]
94
+ layout?: {
95
+ type: 'single'
96
+ } | {
97
+ type: 'grid'
98
+ width?: number | string
99
+ }
100
+ icon?: string
101
+ iconColor?: string
102
+ docsOnly?: boolean
103
+ docsText?: string
104
+ }
105
+
106
+ export interface ServerVariant {
107
+ id: string
108
+ title: string
109
+ icon?: string
110
+ iconColor?: string
111
+ }
112
+
113
+ export interface ServerTreeFile {
114
+ title: string
115
+ path: string
116
+ }
117
+
118
+ export interface ServerTreeLeaf {
119
+ title: string
120
+ index: number
121
+ }
122
+
123
+ export interface ServerTreeFolder {
124
+ title: string
125
+ children: (ServerTreeFolder | ServerTreeLeaf)[]
126
+ }
127
+
128
+ export interface ServerTreeGroup {
129
+ group: true
130
+ id: string
131
+ title: string
132
+ children: (ServerTreeFolder | ServerTreeLeaf)[]
133
+ }
134
+
135
+ export type ServerTree = (ServerTreeGroup | ServerTreeFolder | ServerTreeLeaf)[]
136
+
137
+ export interface ServerRunPayload {
138
+ file: ServerStoryFile
139
+ storyData: ServerStory[]
140
+ el: HTMLElement
141
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "moduleResolution": "node",
6
+ "outDir": "dist",
7
+ "rootDir": "src",
8
+ "allowSyntheticDefaultImports": true,
9
+ "esModuleInterop": true,
10
+ "removeComments": false,
11
+ "resolveJsonModule": true,
12
+ "skipLibCheck": true,
13
+ "types": [
14
+ "node",
15
+ "@peeky/test"
16
+ ],
17
+ "lib": [
18
+ "ESNext",
19
+ "DOM"
20
+ ],
21
+ "sourceMap": false,
22
+ "preserveWatchOutput": true,
23
+ "preserveSymlinks": true,
24
+ // Strict
25
+ "noImplicitAny": false,
26
+ "noImplicitThis": true,
27
+ "alwaysStrict": true,
28
+ "strictBindCallApply": true,
29
+ "strictFunctionTypes": true,
30
+ // Volar
31
+ "jsx": "preserve",
32
+ },
33
+ "include": [
34
+ "src"
35
+ ],
36
+ "exclude": [
37
+ "node_modules",
38
+ "generated/**/*",
39
+ "dist/**/*",
40
+ "src/**/*.spec.ts"
41
+ ]
42
+ }