@sit-onyx/storybook-utils 1.0.0-alpha.9 → 1.0.0-alpha.91

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 CHANGED
@@ -11,3 +11,9 @@
11
11
  # onyx Storybook utils
12
12
 
13
13
  Storybook utilities for Vue created by [Schwarz IT](https://it.schwarz).
14
+
15
+ <br />
16
+
17
+ ## Documentation
18
+
19
+ You can find our documentation [here](https://onyx.schwarz/development/packages/storybook-utils.html).
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sit-onyx/storybook-utils",
3
3
  "description": "Storybook utilities for Vue",
4
- "version": "1.0.0-alpha.9",
4
+ "version": "1.0.0-alpha.91",
5
5
  "type": "module",
6
6
  "author": "Schwarz IT KG",
7
7
  "license": "Apache-2.0",
@@ -13,18 +13,29 @@
13
13
  ".": "./src/index.ts",
14
14
  "./style.css": "./src/index.css"
15
15
  },
16
+ "homepage": "https://onyx.schwarz/development/packages/storybook-utils.html",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/SchwarzIT/onyx",
20
+ "directory": "packages/storybook-utils"
21
+ },
22
+ "bugs": {
23
+ "url": "https://github.com/SchwarzIT/onyx/issues"
24
+ },
16
25
  "peerDependencies": {
17
- "@storybook/core-events": ">= 7",
18
- "@storybook/preview-api": ">= 7",
19
- "@storybook/theming": ">= 7",
20
- "@storybook/vue3": ">= 7",
21
- "storybook-dark-mode": ">= 3",
22
- "sit-onyx": "^0.1.0-alpha.8"
26
+ "@storybook/core-events": ">= 8.0.0",
27
+ "@storybook/preview-api": ">= 8.0.0",
28
+ "@storybook/theming": ">= 8.0.0",
29
+ "@storybook/vue3": ">= 8.0.0",
30
+ "storybook-dark-mode": ">= 4",
31
+ "sit-onyx": "^1.0.0-alpha.88"
23
32
  },
24
33
  "dependencies": {
25
34
  "deepmerge-ts": "^5.1.0"
26
35
  },
27
36
  "scripts": {
28
- "build": "tsc --noEmit"
37
+ "build": "tsc --noEmit",
38
+ "test": "vitest",
39
+ "test:coverage": "vitest run --coverage"
29
40
  }
30
41
  }
package/src/index.css CHANGED
@@ -22,5 +22,5 @@
22
22
  /* the Storybook table of content headline is always black so we need to manually set it for the dark mode */
23
23
  #storybook-docs .sbdocs-wrapper > div:nth-child(2) {
24
24
  /* same as Storybook color "textMuted" inside ./theme.ts */
25
- color: var(--onyx-color-text-neutral-medium);
25
+ color: var(--onyx-color-text-icons-neutral-medium);
26
26
  }
@@ -0,0 +1,18 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import { sourceCodeTransformer } from "./preview";
3
+
4
+ describe("preview.ts", () => {
5
+ test("should transform source code", () => {
6
+ // ARRANGE
7
+ // mix double and single quotes to test that both are supported
8
+ const originalSourceCode = `<OnyxTest v-on:test="someFunction" @empty='()=>({})' v-bind="{}" :disabled='true' :readonly="false" test="true" />`;
9
+
10
+ const expectedOutput = `<OnyxTest @test="someFunction" disabled :readonly="false" test />`;
11
+
12
+ // ACT
13
+ const output = sourceCodeTransformer(originalSourceCode);
14
+
15
+ // ASSERT
16
+ expect(output).toBe(expectedOutput);
17
+ });
18
+ });
package/src/preview.ts CHANGED
@@ -4,6 +4,8 @@ import { type ThemeVars } from "@storybook/theming";
4
4
  import { type Preview } from "@storybook/vue3";
5
5
  import { deepmerge } from "deepmerge-ts";
6
6
  import { DARK_MODE_EVENT_NAME } from "storybook-dark-mode";
7
+
8
+ import { requiredGlobalType, withRequired } from "./required";
7
9
  import { ONYX_BREAKPOINTS, createTheme } from "./theme";
8
10
 
9
11
  const themes = {
@@ -17,7 +19,6 @@ const themes = {
17
19
  * - Improved Vue-specific code highlighting (e.g. using `@` instead of `v-on:`)
18
20
  * - Setup for dark mode (including docs page). Requires addon `storybook-dark-mode` to be enabled in .storybook/main.ts file
19
21
  * - Custom Storybook theme using onyx colors (light and dark mode)
20
- * - Support for setting the light/dark mode when Storybook is embedded as an iframe (via query parameter, e.g. `?theme=dark`)
21
22
  * - Configure viewports / breakpoints as defined by onyx
22
23
  *
23
24
  * @param overrides Custom preview / overrides, will be deep merged with the default preview.
@@ -39,6 +40,10 @@ const themes = {
39
40
  */
40
41
  export const createPreview = <T extends Preview = Preview>(overrides?: T) => {
41
42
  const defaultPreview = {
43
+ globalTypes: {
44
+ ...requiredGlobalType,
45
+ },
46
+ decorators: [withRequired],
42
47
  parameters: {
43
48
  controls: {
44
49
  matchers: {
@@ -52,20 +57,16 @@ export const createPreview = <T extends Preview = Preview>(overrides?: T) => {
52
57
  docs: {
53
58
  // see: https://github.com/hipstersmoothie/storybook-dark-mode/issues/127#issuecomment-840701971
54
59
  get theme(): ThemeVars {
55
- // support setting the theme via query parameters, useful if docs are embedded via an iframe
56
- const params = new URLSearchParams(window.location.search);
57
- const themeParam = params.get("theme");
58
-
59
- const isDark = themeParam
60
- ? themeParam === "dark"
61
- : parent.document.body.classList.contains("dark");
60
+ const isDark = parent.document.body.classList.contains("dark");
62
61
 
63
62
  if (isDark) {
64
63
  document.body.classList.remove("light");
65
64
  document.body.classList.add("dark");
65
+ document.documentElement.style.colorScheme = "dark";
66
66
  } else {
67
67
  document.body.classList.remove("dark");
68
68
  document.body.classList.add("light");
69
+ document.documentElement.style.colorScheme = "light";
69
70
  }
70
71
 
71
72
  return isDark ? themes.dark : themes.light;
@@ -78,22 +79,7 @@ export const createPreview = <T extends Preview = Preview>(overrides?: T) => {
78
79
  * we want it to look.
79
80
  * @see https://storybook.js.org/docs/react/api/doc-block-source
80
81
  */
81
- transform: (sourceCode: string): string => {
82
- const replacements = [
83
- // replace event bindings with shortcut
84
- { searchValue: "v-on:", replaceValue: "@" },
85
- // remove empty event handlers, e.g. @click="()=>({})" will be removed
86
- { searchValue: / @.*['"]\(\)=>\({}\)['"]/g, replaceValue: "" },
87
- // remove empty v-binds, e.g. v-bind="{}" will be removed
88
- { searchValue: / v-bind=['"]{}['"]/g, replaceValue: "" },
89
- // replace boolean shortcuts for true, e.g. disabled="true" will be changed to just disabled
90
- { searchValue: /:(.*)=['"]true['"]/g, replaceValue: "$1" },
91
- ];
92
-
93
- return replacements.reduce((code, replacement) => {
94
- return replaceAll(code, replacement.searchValue, replacement.replaceValue);
95
- }, sourceCode);
96
- },
82
+ transform: sourceCodeTransformer,
97
83
  },
98
84
  },
99
85
  darkMode: {
@@ -129,6 +115,29 @@ export const createPreview = <T extends Preview = Preview>(overrides?: T) => {
129
115
  return deepmerge<[T, typeof defaultPreview]>(overrides ?? ({} as T), defaultPreview);
130
116
  };
131
117
 
118
+ /**
119
+ * Custom transformer for the story source code to better fit to our
120
+ * Vue.js code because storybook per default does not render it exactly how
121
+ * we want it to look.
122
+ * @see https://storybook.js.org/docs/react/api/doc-block-source
123
+ */
124
+ export const sourceCodeTransformer = (sourceCode: string): string => {
125
+ const replacements = [
126
+ // replace event bindings with shortcut
127
+ { searchValue: "v-on:", replaceValue: "@" },
128
+ // remove empty event handlers, e.g. @click="()=>({})" will be removed
129
+ { searchValue: / @\S*['"]\(\)=>\({}\)['"]/g, replaceValue: "" },
130
+ // // remove empty v-binds, e.g. v-bind="{}" will be removed
131
+ { searchValue: / v-bind=['"]{}['"]/g, replaceValue: "" },
132
+ // // replace boolean shortcuts for true, e.g. disabled="true" will be changed to just disabled
133
+ { searchValue: /:?(\S*)=['"]true['"]/g, replaceValue: "$1" },
134
+ ];
135
+
136
+ return replacements.reduce((code, replacement) => {
137
+ return replaceAll(code, replacement.searchValue, replacement.replaceValue);
138
+ }, sourceCode);
139
+ };
140
+
132
141
  /**
133
142
  * Custom String.replaceAll implementation using a RegExp
134
143
  * because String.replaceAll() is not available in our specified EcmaScript target in tsconfig.json
@@ -0,0 +1,36 @@
1
+ import { type Decorator } from "@storybook/vue3";
2
+ import { ref, watch } from "vue";
3
+ import type { StorybookGlobalType } from "./types";
4
+
5
+ type RequiredIndicator = "required" | "optional";
6
+
7
+ export const requiredGlobalType = {
8
+ requiredMode: {
9
+ name: "Required mode",
10
+ description: "Switch between 'required' and 'optional' indicator",
11
+ defaultValue: "required",
12
+ toolbar: {
13
+ icon: "flag",
14
+ items: [
15
+ { value: "required", right: "*", title: "Required indicator" },
16
+ { value: "optional", right: "(optional)", title: "Optional indicator" },
17
+ ],
18
+ },
19
+ } satisfies StorybookGlobalType<RequiredIndicator>,
20
+ };
21
+
22
+ const requiredMode = ref<RequiredIndicator>("required");
23
+
24
+ export const withRequired: Decorator = (Story, context) => {
25
+ watch(
26
+ () => context.globals.requiredMode as RequiredIndicator,
27
+ (newRequiredMode) => (requiredMode.value = newRequiredMode),
28
+ { immediate: true },
29
+ );
30
+
31
+ return {
32
+ components: { Story },
33
+ setup: () => ({ requiredMode }),
34
+ template: `<div :class="{ ['onyx-use-optional']: requiredMode === 'optional' }"> <story /> </div>`,
35
+ };
36
+ };
package/src/types.ts CHANGED
@@ -46,3 +46,13 @@ export type DefineStorybookActionsAndVModelsOptions<T> = Meta<T> & {
46
46
  component: NonNullable<T>;
47
47
  events: ExtractVueEventNames<T>[];
48
48
  };
49
+
50
+ export type StorybookGlobalType<TValue> = {
51
+ name: string;
52
+ description: string;
53
+ defaultValue: TValue;
54
+ toolbar: {
55
+ icon: string;
56
+ items: { value: TValue; right: string; title: string }[];
57
+ };
58
+ };