@sit-onyx/storybook-utils 1.0.0-beta.1 → 1.0.0-beta.100
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/README.md +1 -5
- package/package.json +21 -12
- package/src/actions.spec.ts +29 -0
- package/src/actions.ts +114 -55
- package/src/events.ts +777 -0
- package/src/index.ts +5 -4
- package/src/preview.spec.ts +9 -19
- package/src/preview.ts +58 -51
- package/src/required.ts +2 -3
- package/src/sbType.spec.ts +38 -0
- package/src/sbType.ts +104 -0
- package/src/style.css +161 -0
- package/src/theme.ts +50 -38
- package/src/types.ts +1 -49
- package/src/assets/logo-onyx.svg +0 -51
- package/src/index.css +0 -26
- package/src/source-code-generator.spec.ts +0 -258
- package/src/source-code-generator.ts +0 -539
package/src/theme.ts
CHANGED
|
@@ -1,34 +1,40 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
ONYX_BREAKPOINTS as RAW_ONYX_BREAKPOINTS,
|
|
3
|
+
type OnyxBreakpoint,
|
|
4
|
+
} from "@sit-onyx/shared/breakpoints";
|
|
5
|
+
import { create, type ThemeVars } from "storybook/internal/theming";
|
|
6
|
+
import type { Viewport } from "storybook/internal/viewport";
|
|
7
|
+
|
|
8
|
+
export type BrandDetails = Pick<ThemeVars, "brandTitle" | "brandImage" | "brandUrl">;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Get the computed value for a CSS custom property.
|
|
12
|
+
* Per default the property value is taken from the body element.
|
|
13
|
+
*/
|
|
14
|
+
export const getCustomProperty = (property: string, el: Element = document.body) =>
|
|
15
|
+
getComputedStyle(el).getPropertyValue(property);
|
|
6
16
|
|
|
7
17
|
/**
|
|
8
18
|
* Creates a custom theme for Storybook that uses onyx colors.
|
|
9
19
|
*
|
|
10
20
|
* @see https://storybook.js.org/docs/react/configure/theming#create-a-theme-quickstart
|
|
11
21
|
*/
|
|
12
|
-
export const createTheme = (
|
|
13
|
-
|
|
14
|
-
) => {
|
|
15
|
-
const base = options?.base ?? "light";
|
|
16
|
-
const primaryColor = onyxVariables["onyx-color-themed-primary-500"];
|
|
17
|
-
|
|
22
|
+
export const createTheme = (base: "light" | "dark" = "light", brandDetails?: BrandDetails) => {
|
|
23
|
+
const primaryColor = getCustomProperty("--onyx-color-onyx-500");
|
|
18
24
|
return create({
|
|
19
|
-
brandTitle:
|
|
20
|
-
brandUrl:
|
|
21
|
-
brandImage:
|
|
25
|
+
brandTitle: brandDetails?.brandTitle,
|
|
26
|
+
brandUrl: brandDetails?.brandUrl,
|
|
27
|
+
brandImage: brandDetails?.brandImage,
|
|
22
28
|
brandTarget: "_blank",
|
|
23
|
-
base
|
|
29
|
+
base,
|
|
24
30
|
|
|
25
31
|
// default theme values that are independent of the light/dark mode:
|
|
26
32
|
colorPrimary: primaryColor,
|
|
27
|
-
colorSecondary:
|
|
33
|
+
colorSecondary: getCustomProperty("--onyx-color-themed-secondary-500"),
|
|
28
34
|
barSelectedColor: primaryColor,
|
|
29
35
|
barHoverColor: primaryColor,
|
|
30
|
-
appBorderRadius: remToNumber(
|
|
31
|
-
inputBorderRadius: remToNumber(
|
|
36
|
+
appBorderRadius: remToNumber(getCustomProperty("--onyx-number-radius-300")),
|
|
37
|
+
inputBorderRadius: remToNumber(getCustomProperty("--onyx-number-radius-200")),
|
|
32
38
|
|
|
33
39
|
// custom colors depending on light/dark theme
|
|
34
40
|
...(base === "light" ? getLightTheme() : getDarkTheme()),
|
|
@@ -37,21 +43,21 @@ export const createTheme = (
|
|
|
37
43
|
|
|
38
44
|
const getLightTheme = (): Partial<ThemeVars> => {
|
|
39
45
|
return defineTheme({
|
|
40
|
-
background:
|
|
41
|
-
contentBackground:
|
|
42
|
-
text:
|
|
43
|
-
textMuted:
|
|
44
|
-
border:
|
|
46
|
+
background: getCustomProperty("--onyx-color-universal-grayscale-white"),
|
|
47
|
+
contentBackground: getCustomProperty("--onyx-color-neutral-steel-100"),
|
|
48
|
+
text: getCustomProperty("--onyx-color-neutral-steel-700"),
|
|
49
|
+
textMuted: getCustomProperty("--onyx-color-neutral-steel-600"),
|
|
50
|
+
border: getCustomProperty("--onyx-color-neutral-steel-300"),
|
|
45
51
|
});
|
|
46
52
|
};
|
|
47
53
|
|
|
48
54
|
const getDarkTheme = (): Partial<ThemeVars> => {
|
|
49
55
|
return defineTheme({
|
|
50
|
-
background:
|
|
51
|
-
contentBackground:
|
|
52
|
-
text:
|
|
53
|
-
textMuted:
|
|
54
|
-
border:
|
|
56
|
+
background: getCustomProperty("--onyx-color-neutral-steel-1100"),
|
|
57
|
+
contentBackground: getCustomProperty("--onyx-color-neutral-steel-1200"),
|
|
58
|
+
text: getCustomProperty("--onyx-color-neutral-steel-200"),
|
|
59
|
+
textMuted: getCustomProperty("--onyx-color-neutral-steel-400"),
|
|
60
|
+
border: getCustomProperty("--onyx-color-neutral-steel-900"),
|
|
55
61
|
});
|
|
56
62
|
};
|
|
57
63
|
|
|
@@ -94,20 +100,26 @@ const defineTheme = (colors: {
|
|
|
94
100
|
export const ONYX_BREAKPOINTS = Object.entries(RAW_ONYX_BREAKPOINTS).reduce(
|
|
95
101
|
(obj, [name, width]) => {
|
|
96
102
|
const breakpoint = name as OnyxBreakpoint;
|
|
97
|
-
|
|
103
|
+
|
|
104
|
+
const TYPES: Record<OnyxBreakpoint, Viewport["type"]> = {
|
|
105
|
+
"2xs": "mobile",
|
|
106
|
+
xs: "mobile",
|
|
107
|
+
sm: "tablet",
|
|
108
|
+
md: "tablet",
|
|
109
|
+
lg: "desktop",
|
|
110
|
+
xl: "desktop",
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
obj[breakpoint] = {
|
|
114
|
+
name: breakpoint,
|
|
115
|
+
styles: { width: `${width}px`, height: "100%" },
|
|
116
|
+
type: TYPES[breakpoint],
|
|
117
|
+
};
|
|
98
118
|
return obj;
|
|
99
119
|
},
|
|
100
|
-
{} as Record<OnyxBreakpoint,
|
|
120
|
+
{} as Record<OnyxBreakpoint, Viewport>,
|
|
101
121
|
);
|
|
102
122
|
|
|
103
|
-
export type StorybookBreakpoint = {
|
|
104
|
-
name: OnyxBreakpoint;
|
|
105
|
-
styles: {
|
|
106
|
-
width: string;
|
|
107
|
-
height: string;
|
|
108
|
-
};
|
|
109
|
-
};
|
|
110
|
-
|
|
111
123
|
/**
|
|
112
124
|
* Converts a rem string into a numeric value with a rem base of 16.
|
|
113
125
|
* @example "1rem" => 16
|
package/src/types.ts
CHANGED
|
@@ -1,52 +1,3 @@
|
|
|
1
|
-
import type { ComponentPropsAndSlots, Meta } from "@storybook/vue3";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Extracts all event names defined by e.g. `defineEmits()` from the given Vue component.
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* ```ts
|
|
8
|
-
* import Input from "./Input.vue";
|
|
9
|
-
* type InputEvents = ExtractVueEventNames<typeof Input>; // e.g. "input" | "change"
|
|
10
|
-
* ```
|
|
11
|
-
*/
|
|
12
|
-
export type ExtractVueEventNames<VueComponent> =
|
|
13
|
-
Extract<
|
|
14
|
-
// extract all props/events of the vue component that are functions
|
|
15
|
-
ExtractKeysByValueType<
|
|
16
|
-
// this generic type will extract ALL props and events from the given Vue component
|
|
17
|
-
ComponentPropsAndSlots<VueComponent>,
|
|
18
|
-
// emits are declared as functions, so we only take props/events that are functions and ignore the rest
|
|
19
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- We must use any here to match the type defined by Vue
|
|
20
|
-
((...args: any) => any) | undefined
|
|
21
|
-
>,
|
|
22
|
-
// filter out potential function properties by just picking events that start with "on"
|
|
23
|
-
`on${string}`
|
|
24
|
-
> extends `on${infer EventName}`
|
|
25
|
-
? // until now the extracted event names still start with "on" but we want to have the plain event name
|
|
26
|
-
// so we will remove the "on" prefix and uncapitalized the first letter so e.g. "onClick" becomes "click"
|
|
27
|
-
Uncapitalize<EventName>
|
|
28
|
-
: never;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Extracts only the keys from T whose value type satisfies U.
|
|
32
|
-
*
|
|
33
|
-
* @example
|
|
34
|
-
* ```ts
|
|
35
|
-
* type Test = ExtractKeysByValueType<{ a: boolean, b: number, c: boolean }, boolean>
|
|
36
|
-
* // result: "a" | "c"
|
|
37
|
-
* ```
|
|
38
|
-
*/
|
|
39
|
-
export type ExtractKeysByValueType<T, U> = { [P in keyof T]: T[P] extends U ? P : never }[keyof T] &
|
|
40
|
-
keyof T;
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Options for defining Storybook actions and v-models.
|
|
44
|
-
*/
|
|
45
|
-
export type DefineStorybookActionsAndVModelsOptions<T> = Meta<T> & {
|
|
46
|
-
component: NonNullable<T>;
|
|
47
|
-
events: ExtractVueEventNames<T>[];
|
|
48
|
-
};
|
|
49
|
-
|
|
50
1
|
export type StorybookGlobalType<TValue> = {
|
|
51
2
|
name: string;
|
|
52
3
|
description: string;
|
|
@@ -55,5 +6,6 @@ export type StorybookGlobalType<TValue> = {
|
|
|
55
6
|
icon: string;
|
|
56
7
|
items: { value: TValue; right?: string; title: string }[];
|
|
57
8
|
title?: string;
|
|
9
|
+
dynamicTitle?: boolean;
|
|
58
10
|
};
|
|
59
11
|
};
|
package/src/assets/logo-onyx.svg
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
-
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
3
|
-
<svg width="100%" height="100%" viewBox="0 0 128 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
|
4
|
-
<g transform="matrix(0.0550098,0,0,0.0550098,-13.9945,-10.7764)">
|
|
5
|
-
<g transform="matrix(1.00003,0,0,1,-5.18689,1.4)">
|
|
6
|
-
<path d="M1399.09,387.23L1457.51,302.52C1460.2,299.31 1462.88,297.7 1466.62,297.7L1526.12,297.7C1532.55,297.7 1534.17,301.99 1530.41,307.36L1437.8,438.74L1399.08,387.23L1399.09,387.23Z" style="fill:url(#_Linear1);fill-rule:nonzero;"/>
|
|
7
|
-
</g>
|
|
8
|
-
<g transform="matrix(1.00003,0,0,1,-5.18689,1.4)">
|
|
9
|
-
<path d="M1438.22,438.15L1541.14,584.49C1544.35,589.85 1542.75,594.14 1536.32,594.14L1476.82,594.14C1473.61,594.14 1470.92,592.53 1468.77,589.32L1399.09,488.54L1329.4,589.32C1327.27,592.53 1324.58,594.14 1321.36,594.14L1261.86,594.14C1255.43,594.14 1243.69,589.85 1247.45,584.49L1359.96,438.15L1267.76,307.36C1264,301.99 1265.62,297.7 1272.04,297.7L1331.54,297.7C1335.3,297.7 1338.51,299.31 1340.65,302.52L1399.08,387.23L1438.21,438.15L1438.22,438.15Z" style="fill:rgb(50,184,198);fill-rule:nonzero;"/>
|
|
10
|
-
</g>
|
|
11
|
-
</g>
|
|
12
|
-
<g transform="matrix(0.0550098,0,0,0.0550098,-13.9945,-10.7764)">
|
|
13
|
-
<g transform="matrix(1.00003,0,0,1,-5.18689,1.4)">
|
|
14
|
-
<path d="M520.64,448.86C520.64,569.47 497.06,599.49 389.85,599.49C282.63,599.49 259.58,569.47 259.58,448.86C259.58,327.71 282.63,297.69 389.85,297.69C497.05,297.69 520.64,327.71 520.64,448.86ZM324.45,448.86C324.45,524.44 332.49,543.21 389.85,543.21C447.2,543.21 455.24,524.44 455.24,448.86C455.24,372.74 447.19,353.98 389.85,353.98C332.48,353.98 324.45,372.74 324.45,448.86Z" style="fill:rgb(50,184,198);fill-rule:nonzero;"/>
|
|
15
|
-
</g>
|
|
16
|
-
<g transform="matrix(1.00003,0,0,1,-5.18689,1.4)">
|
|
17
|
-
<g>
|
|
18
|
-
<clipPath id="_clip2">
|
|
19
|
-
<path d="M519.88,480.88C520.37,470.95 520.64,460.4 520.64,448.86C520.64,327.71 497.06,297.69 389.85,297.69C388.74,297.69 367.12,297.69 351.01,299.54C339.69,316.68 332.26,373.81 327.82,394.43C328.83,388.21 332.15,379.08 334.43,374.91C339.44,365.73 346.24,361.39 354.56,358.41C368.59,353.39 384.37,353.98 389.86,353.98C447.22,353.98 455.26,372.74 455.26,448.86"/>
|
|
20
|
-
</clipPath>
|
|
21
|
-
<g clip-path="url(#_clip2)">
|
|
22
|
-
<g transform="matrix(0.999067,0,0,0.995598,327.82,297.69)">
|
|
23
|
-
<use id="_Image3_" serif:id="_Image3" xlink:href="#_Image3" x="0" y="0" width="193px" height="184px"/>
|
|
24
|
-
</g>
|
|
25
|
-
</g>
|
|
26
|
-
</g>
|
|
27
|
-
</g>
|
|
28
|
-
</g>
|
|
29
|
-
<g transform="matrix(0.0550098,0,0,0.0550098,-13.9945,-10.7764)">
|
|
30
|
-
<g transform="matrix(1.00003,0,0,1,-5.18689,1.4)">
|
|
31
|
-
<path d="M662.36,353.99L724.46,353.99C774.85,353.99 787.16,357.2 787.16,436.54L787.16,588.77C787.16,594.14 789.85,596.82 795.21,596.82L843.46,596.82C848.82,596.82 852.03,594.14 852.03,588.77L852.03,424.75C852.03,312.71 824.69,297.7 725.52,297.7C707.79,297.7 685.61,297.9 662.72,299.33L662.36,353.99Z" style="fill:url(#_Linear4);fill-rule:nonzero;"/>
|
|
32
|
-
</g>
|
|
33
|
-
<g transform="matrix(1.00003,0,0,1,-5.18689,1.4)">
|
|
34
|
-
<path d="M662.8,306.45L662.8,588.77C662.8,594.14 660.12,596.82 654.76,596.82L605.45,596.82C600.08,596.82 597.94,594.14 597.94,588.77L597.94,314.86C597.94,307.89 600.62,307.35 605.45,306.28C623.63,302.59 643.45,300.48 662.79,299.28L662.79,306.45L662.8,306.45Z" style="fill:rgb(50,184,198);fill-rule:nonzero;"/>
|
|
35
|
-
</g>
|
|
36
|
-
</g>
|
|
37
|
-
<g transform="matrix(0.0550098,0,0,0.0550098,-13.9945,-10.7764)">
|
|
38
|
-
<g transform="matrix(1.00003,0,0,1,-5.18689,1.4)">
|
|
39
|
-
<path d="M1123.83,591.43C1100.93,595.16 1080.37,596.19 1055.33,596.19C956.8,596.19 931.78,562.64 931.78,455.06L931.78,307.02C931.78,301.69 934.44,299.03 939.77,299.03L988.23,299.03C993.56,299.03 996.23,301.69 996.23,307.02L996.23,446.01C996.23,522.16 1005.81,539.73 1065.46,539.73C1083.04,539.73 1104.87,539.2 1123.51,536.54L1123.84,591.43L1123.83,591.43Z" style="fill:url(#_Linear5);fill-rule:nonzero;"/>
|
|
40
|
-
</g>
|
|
41
|
-
<g transform="matrix(1.00003,0,0,1,-5.18689,1.4)">
|
|
42
|
-
<path d="M1123.5,536.54L1123.5,307.02C1123.5,301.69 1126.16,299.03 1131.49,299.03L1179.96,299.03C1185.29,299.03 1187.95,301.69 1187.95,307.02L1187.95,576.49C1187.41,669.15 1169.31,702.7 1061.19,702.7C1025.52,702.7 1000.48,701.1 971.19,696.83C966.4,695.77 964.26,693.11 964.26,688.31L964.26,656.89C964.26,651.03 966.39,648.9 971.72,648.9L1057.46,648.9C1110.71,648.9 1123.49,636.12 1123.49,594.05L1123.49,536.54L1123.5,536.54Z" style="fill:rgb(50,184,198);fill-rule:nonzero;"/>
|
|
43
|
-
</g>
|
|
44
|
-
</g>
|
|
45
|
-
<defs>
|
|
46
|
-
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(133.32,0,0,133.32,1399.09,368.22)"><stop offset="0" style="stop-color:rgb(1,141,160);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(50,184,198);stop-opacity:1"/></linearGradient>
|
|
47
|
-
<image id="_Image3" width="193px" height="184px" xlink:href="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAC4AMEDAREAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAgAGAf/EABgQAQEBAQEAAAAAAAAAAAAAAAEAAhFh/8QAGQEBAQEBAQEAAAAAAAAAAAAAAAIBAwYH/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8Ayl7V8MUFBQUFBQUFAggQRphAwgQQIKQwgeSKMIGECCBhAggQWBhB3kUzFbkoKCgoKCgoEECCNMIEEDCBBSGEDCBhFGECCBhAggQWBhAgii5Bla3JQUFBQUFAggQRphAggYQIKQwgYQPJFGECCBhAggQWBhAgijCDvIMnW5KCgoKCgQQII0wgQQMIEFIYQMIHkijCBBAwgQQILAwgQRRhAggXIMhW5KCgoKBBAgjTCBBAwgQUhhAwijyQMIEEDCBBAgsDCBBFGECCBhB3nkGOrclBQUCCBBGmECCBhAgpDCBhFHkgYQIIGECCBBYGECCKMIEEDCBBAuUjF3VyUFAggQRphAggYQIKQwgYRR5IGECCBhAggQWBhAgijCBBAwgQQMKR3nkGJurkoEECCNMIEEDCBBSGEDCKPJAwgQQMIEECCwMIEEUYQIIGECCBhSGEHeQYa6uRBAgjTCBBAwgQUhhAwijyQMIEEDCBBAggYWBBFGECCBhAggYUhhAgg7yDDBdXIgjTCBBAwgQUhhAwijyQMIEEDCBBAggYWBBFGECCBhAggYUhhAggYQd5BhQurmYQIIGECCkMIGEUeSBhAggYQIIEEDCwIIowgQQMIEEDCkMIEEDCBBAuQYULq5kEDCBBSGEDCKPJAwgQQMIEECCBhYEEUYQIIGECCBhSEEDCBhAggYRpcgwgXVyMIEFIYQMIo8kDCBBAwgQQIIGFgQRRhAggYQIIGFIQQMIGECCBhGmEC5BhAurkQUhhA8kDCKMIEEDCBBAggYWBBFGECCBhAggYUhBAwgYQIIGEaYQIg7BhQrcjCBhAwiiCBhAggYQIIGFgQRRhAggYQIIGFIQQMIGECCBhGmECIOwUGICtyMIGEUQQMIEEDCBBYGECCKMIEEDCBBAwpCCBhAwgQQMI0wgRB2CgoMWFbkYRRBAwgQQMIEFgYQIIowgQQMIEEDCkIIGEDCBBAwjTCBEHYKCgoMcFaCCBhAggYQILAwgQRRhAggYQIIGFIQQMIGECCBhGmECIOwUFBQUGQCtBhAggYQILAwgQRRhAggYQIIGFIQQMIGECCBhGmECIOwUFBQUFBkwrQQQMIEFgYQIIowgQQMIEEDCkIIGEDCBBAwjTCBEHYKCgoKCgoMqFaDCBBYGECCKMIEEDCBBAwpCCBhAwgQQMI0wgRB2CgoKCgoKCgzAVoILAwgQRRhAggYQIIGFIQQMIGECCBhGmECIOwUFBQUFBQUFBmgqQYQIIowgQQMIEEDCkIIGECCB5IGEaYQIg7BQUFBQUFBQUFB//2Q=="/>
|
|
48
|
-
<linearGradient id="_Linear4" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(35974.7,0,0,35974.7,126292,134082)"><stop offset="0" style="stop-color:rgb(1,141,160);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(50,184,198);stop-opacity:1"/></linearGradient>
|
|
49
|
-
<linearGradient id="_Linear5" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(192.05,0,0,192.05,931.78,447.61)"><stop offset="0" style="stop-color:rgb(50,184,198);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(1,141,160);stop-opacity:1"/></linearGradient>
|
|
50
|
-
</defs>
|
|
51
|
-
</svg>
|
package/src/index.css
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
@import url("sit-onyx/themes/onyx.css");
|
|
2
|
-
|
|
3
|
-
.onyx-disclaimer {
|
|
4
|
-
border-radius: 0.5rem;
|
|
5
|
-
padding: 1rem;
|
|
6
|
-
line-height: 1.5rem;
|
|
7
|
-
margin: 1rem 0;
|
|
8
|
-
|
|
9
|
-
/* same color as VitePress var(--vp-c-tip-soft) */
|
|
10
|
-
background-color: color-mix(in srgb, var(--onyx-color-base-info-400) 25%, transparent);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
.onyx-disclaimer__title {
|
|
14
|
-
font-weight: 600;
|
|
15
|
-
margin-bottom: 0.5rem;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
.onyx-disclaimer p {
|
|
19
|
-
margin: 0;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/* the Storybook table of content headline is always black so we need to manually set it for the dark mode */
|
|
23
|
-
#storybook-docs .sbdocs-wrapper > div:nth-child(2) {
|
|
24
|
-
/* same as Storybook color "textMuted" inside ./theme.ts */
|
|
25
|
-
color: var(--onyx-color-text-icons-neutral-medium);
|
|
26
|
-
}
|
|
@@ -1,258 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
-
//
|
|
3
|
-
// This file is only a temporary copy of the improved source code generation for Storybook.
|
|
4
|
-
// It is intended to be deleted once its officially released in Storybook itself, see:
|
|
5
|
-
// https://github.com/storybookjs/storybook/pull/27194
|
|
6
|
-
//
|
|
7
|
-
import { expect, test } from "vitest";
|
|
8
|
-
import { h } from "vue";
|
|
9
|
-
import {
|
|
10
|
-
generatePropsSourceCode,
|
|
11
|
-
generateSlotSourceCode,
|
|
12
|
-
generateSourceCode,
|
|
13
|
-
getFunctionParamNames,
|
|
14
|
-
parseDocgenInfo,
|
|
15
|
-
type SourceCodeGeneratorContext,
|
|
16
|
-
} from "./source-code-generator";
|
|
17
|
-
|
|
18
|
-
test("should generate source code for props", () => {
|
|
19
|
-
const ctx: SourceCodeGeneratorContext = {
|
|
20
|
-
scriptVariables: {},
|
|
21
|
-
imports: {},
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const code = generatePropsSourceCode(
|
|
25
|
-
{
|
|
26
|
-
a: "foo",
|
|
27
|
-
b: '"I am double quoted"',
|
|
28
|
-
c: 42,
|
|
29
|
-
d: true,
|
|
30
|
-
e: false,
|
|
31
|
-
f: [1, 2, 3],
|
|
32
|
-
g: {
|
|
33
|
-
g1: "foo",
|
|
34
|
-
g2: 42,
|
|
35
|
-
},
|
|
36
|
-
h: undefined,
|
|
37
|
-
i: null,
|
|
38
|
-
j: "",
|
|
39
|
-
k: BigInt(9007199254740991),
|
|
40
|
-
l: Symbol(),
|
|
41
|
-
m: Symbol("foo"),
|
|
42
|
-
modelValue: "test-v-model",
|
|
43
|
-
otherModelValue: 42,
|
|
44
|
-
default: "default slot",
|
|
45
|
-
testSlot: "test slot",
|
|
46
|
-
},
|
|
47
|
-
["default", "testSlot"],
|
|
48
|
-
["update:modelValue", "update:otherModelValue"],
|
|
49
|
-
ctx,
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
expect(code).toBe(
|
|
53
|
-
`a="foo" b='"I am double quoted"' :c="42" d :e="false" :f="f" :g="g" :k="BigInt(9007199254740991)" :l="Symbol()" :m="Symbol('foo')" v-model="modelValue" v-model:otherModelValue="otherModelValue"`,
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
expect(ctx.scriptVariables).toStrictEqual({
|
|
57
|
-
f: `[1,2,3]`,
|
|
58
|
-
g: `{"g1":"foo","g2":42}`,
|
|
59
|
-
modelValue: 'ref("test-v-model")',
|
|
60
|
-
otherModelValue: "ref(42)",
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
expect(Array.from(ctx.imports.vue.values())).toStrictEqual(["ref"]);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test("should generate source code for slots", () => {
|
|
67
|
-
// slot code generator should support primitive values (string, number etc.)
|
|
68
|
-
// but also VNodes (e.g. created using h()) so custom Vue components can also be used
|
|
69
|
-
// inside slots with proper generated code
|
|
70
|
-
|
|
71
|
-
const slots = {
|
|
72
|
-
default: "default content",
|
|
73
|
-
a: "a content",
|
|
74
|
-
b: 42,
|
|
75
|
-
c: true,
|
|
76
|
-
// single VNode without props
|
|
77
|
-
d: h("div", "d content"),
|
|
78
|
-
// VNode with props and single child
|
|
79
|
-
e: h("div", { style: "color:red" }, "e content"),
|
|
80
|
-
// VNode with props and single child returned as getter
|
|
81
|
-
f: h("div", { style: "color:red" }, () => "f content"),
|
|
82
|
-
// VNode with multiple children
|
|
83
|
-
g: h("div", { style: "color:red" }, [
|
|
84
|
-
"child 1",
|
|
85
|
-
h("span", { style: "color:green" }, "child 2"),
|
|
86
|
-
]),
|
|
87
|
-
// VNode multiple children but returned as getter
|
|
88
|
-
h: h("div", { style: "color:red" }, () => [
|
|
89
|
-
"child 1",
|
|
90
|
-
h("span", { style: "color:green" }, "child 2"),
|
|
91
|
-
]),
|
|
92
|
-
// VNode with multiple and nested children
|
|
93
|
-
i: h("div", { style: "color:red" }, [
|
|
94
|
-
"child 1",
|
|
95
|
-
h("span", { style: "color:green" }, ["nested child 1", h("p", "nested child 2")]),
|
|
96
|
-
]),
|
|
97
|
-
j: ["child 1", "child 2"],
|
|
98
|
-
k: null,
|
|
99
|
-
l: { foo: "bar" },
|
|
100
|
-
m: BigInt(9007199254740991),
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
const expectedCode = `default content
|
|
104
|
-
|
|
105
|
-
<template #a>a content</template>
|
|
106
|
-
|
|
107
|
-
<template #b>42</template>
|
|
108
|
-
|
|
109
|
-
<template #c>true</template>
|
|
110
|
-
|
|
111
|
-
<template #d><div>d content</div></template>
|
|
112
|
-
|
|
113
|
-
<template #e><div style="color:red">e content</div></template>
|
|
114
|
-
|
|
115
|
-
<template #f><div style="color:red">f content</div></template>
|
|
116
|
-
|
|
117
|
-
<template #g><div style="color:red">child 1
|
|
118
|
-
<span style="color:green">child 2</span></div></template>
|
|
119
|
-
|
|
120
|
-
<template #h><div style="color:red">child 1
|
|
121
|
-
<span style="color:green">child 2</span></div></template>
|
|
122
|
-
|
|
123
|
-
<template #i><div style="color:red">child 1
|
|
124
|
-
<span style="color:green">nested child 1
|
|
125
|
-
<p>nested child 2</p></span></div></template>
|
|
126
|
-
|
|
127
|
-
<template #j>child 1
|
|
128
|
-
child 2</template>
|
|
129
|
-
|
|
130
|
-
<template #l>{"foo":"bar"}</template>
|
|
131
|
-
|
|
132
|
-
<template #m>{{ BigInt(9007199254740991) }}</template>`;
|
|
133
|
-
|
|
134
|
-
let actualCode = generateSlotSourceCode(slots, Object.keys(slots), {
|
|
135
|
-
scriptVariables: {},
|
|
136
|
-
imports: {},
|
|
137
|
-
});
|
|
138
|
-
expect(actualCode).toBe(expectedCode);
|
|
139
|
-
|
|
140
|
-
// should generate the same code if getters/functions are used to return the slot content
|
|
141
|
-
const slotsWithGetters = Object.entries(slots).reduce<
|
|
142
|
-
Record<string, () => (typeof slots)[keyof typeof slots]>
|
|
143
|
-
>((obj, [slotName, value]) => {
|
|
144
|
-
obj[slotName] = () => value;
|
|
145
|
-
return obj;
|
|
146
|
-
}, {});
|
|
147
|
-
|
|
148
|
-
actualCode = generateSlotSourceCode(slotsWithGetters, Object.keys(slotsWithGetters), {
|
|
149
|
-
scriptVariables: {},
|
|
150
|
-
imports: {},
|
|
151
|
-
});
|
|
152
|
-
expect(actualCode).toBe(expectedCode);
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
test("should generate source code for slots with bindings", () => {
|
|
156
|
-
type TestBindings = {
|
|
157
|
-
foo: string;
|
|
158
|
-
bar?: number;
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
const slots = {
|
|
162
|
-
a: ({ foo, bar }: TestBindings) => `Slot with bindings ${foo} and ${bar}`,
|
|
163
|
-
b: ({ foo }: TestBindings) => h("a", { href: foo, target: foo }, `Test link: ${foo}`),
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
const expectedCode = `<template #a="{ foo, bar }">Slot with bindings {{ foo }} and {{ bar }}</template>
|
|
167
|
-
|
|
168
|
-
<template #b="{ foo }"><a :href="foo" :target="foo">Test link: {{ foo }}</a></template>`;
|
|
169
|
-
|
|
170
|
-
const actualCode = generateSlotSourceCode(slots, Object.keys(slots), {
|
|
171
|
-
imports: {},
|
|
172
|
-
scriptVariables: {},
|
|
173
|
-
});
|
|
174
|
-
expect(actualCode).toBe(expectedCode);
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
test("should generate source code with <script setup> block", () => {
|
|
178
|
-
const actualCode = generateSourceCode({
|
|
179
|
-
title: "MyComponent",
|
|
180
|
-
component: {
|
|
181
|
-
__docgenInfo: {
|
|
182
|
-
slots: [{ name: "mySlot" }],
|
|
183
|
-
events: [{ name: "update:c" }],
|
|
184
|
-
},
|
|
185
|
-
},
|
|
186
|
-
args: {
|
|
187
|
-
a: 42,
|
|
188
|
-
b: "foo",
|
|
189
|
-
c: [1, 2, 3],
|
|
190
|
-
d: { bar: "baz" },
|
|
191
|
-
mySlot: () => h("div", { test: [1, 2], d: { nestedProp: "foo" } }),
|
|
192
|
-
},
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
expect(actualCode).toBe(`<script lang="ts" setup>
|
|
196
|
-
import { ref } from "vue";
|
|
197
|
-
|
|
198
|
-
const c = ref([1,2,3]);
|
|
199
|
-
|
|
200
|
-
const d = {"bar":"baz"};
|
|
201
|
-
|
|
202
|
-
const d1 = {"nestedProp":"foo"};
|
|
203
|
-
|
|
204
|
-
const test = [1,2];
|
|
205
|
-
</script>
|
|
206
|
-
|
|
207
|
-
<template>
|
|
208
|
-
<MyComponent :a="42" b="foo" v-model:c="c" :d="d"> <template #mySlot><div :d="d1" :test="test" /></template> </MyComponent>
|
|
209
|
-
</template>`);
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
test.each([
|
|
213
|
-
{ __docgenInfo: "invalid-value", slotNames: [] },
|
|
214
|
-
{ __docgenInfo: {}, slotNames: [] },
|
|
215
|
-
{ __docgenInfo: { slots: "invalid-value" }, slotNames: [] },
|
|
216
|
-
{ __docgenInfo: { slots: ["invalid-value"] }, slotNames: [] },
|
|
217
|
-
{
|
|
218
|
-
__docgenInfo: { slots: [{ name: "slot-1" }, { name: "slot-2" }, { notName: "slot-3" }] },
|
|
219
|
-
slotNames: ["slot-1", "slot-2"],
|
|
220
|
-
},
|
|
221
|
-
])("should parse slots names from __docgenInfo", ({ __docgenInfo, slotNames }) => {
|
|
222
|
-
const docgenInfo = parseDocgenInfo({ __docgenInfo });
|
|
223
|
-
expect(docgenInfo.slotNames).toStrictEqual(slotNames);
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
test.each([
|
|
227
|
-
{ __docgenInfo: "invalid-value", eventNames: [] },
|
|
228
|
-
{ __docgenInfo: {}, eventNames: [] },
|
|
229
|
-
{ __docgenInfo: { events: "invalid-value" }, eventNames: [] },
|
|
230
|
-
{ __docgenInfo: { events: ["invalid-value"] }, eventNames: [] },
|
|
231
|
-
{
|
|
232
|
-
__docgenInfo: { events: [{ name: "event-1" }, { name: "event-2" }, { notName: "event-3" }] },
|
|
233
|
-
eventNames: ["event-1", "event-2"],
|
|
234
|
-
},
|
|
235
|
-
])("should parse event names from __docgenInfo", ({ __docgenInfo, eventNames }) => {
|
|
236
|
-
const docgenInfo = parseDocgenInfo({ __docgenInfo });
|
|
237
|
-
expect(docgenInfo.eventNames).toStrictEqual(eventNames);
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
241
|
-
test.each<{ fn: (...args: any[]) => unknown; expectedNames: string[] }>([
|
|
242
|
-
{ fn: () => ({}), expectedNames: [] },
|
|
243
|
-
{ fn: (a) => ({}), expectedNames: ["a"] },
|
|
244
|
-
{ fn: (a, b) => ({}), expectedNames: ["a", "b"] },
|
|
245
|
-
{ fn: (a, b, { c }) => ({}), expectedNames: ["a", "b", "{", "c", "}"] },
|
|
246
|
-
{ fn: ({ a, b }) => ({}), expectedNames: ["{", "a", "b", "}"] },
|
|
247
|
-
{
|
|
248
|
-
fn: {
|
|
249
|
-
// simulate minified function after running "storybook build"
|
|
250
|
-
toString: () => "({a:foo,b:bar})=>({})",
|
|
251
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
252
|
-
} as (...args: any[]) => unknown,
|
|
253
|
-
expectedNames: ["{", "a", "b", "}"],
|
|
254
|
-
},
|
|
255
|
-
])("should extract function parameter names", ({ fn, expectedNames }) => {
|
|
256
|
-
const paramNames = getFunctionParamNames(fn);
|
|
257
|
-
expect(paramNames).toStrictEqual(expectedNames);
|
|
258
|
-
});
|