storybook-vrhythm 0.2.0 → 0.4.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/README.md CHANGED
@@ -1,149 +1,176 @@
1
- # 📐 storybook-vrhythm
1
+ # storybook-vrhythm
2
2
 
3
- [![npm package][npm-badge]][npm]
3
+ [![npm version][npm-badge]][npm]
4
4
  [![License: MIT][license-badge]][license]
5
5
  [![Bundle Size](https://img.shields.io/bundlephobia/minzip/storybook-vrhythm)](https://bundlephobia.com/package/storybook-vrhythm)
6
+ [![Zero Dependencies](https://img.shields.io/badge/dependencies-0-brightgreen)](https://www.npmjs.org/package/storybook-vrhythm)
6
7
 
7
- **A Storybook decorator that overlays vertical rhythm guide lines on your stories.**
8
- Verify that your components align to a baseline grid — with zero effort.
8
+ > Baseline grid overlay for Storybook. See your vertical rhythm while you build.
9
9
 
10
- ![Vertical rhythm overlay example](storybook-vrhythm.jpg)
10
+ Stop guessing if your spacing is consistent. `storybook-vrhythm` draws a customizable baseline grid on top of your stories so you can **see** alignment issues as you develop — not after you ship.
11
11
 
12
- ## ✨ Features
12
+ ## Features
13
13
 
14
- - 🎯 **Framework agnostic** — Works with React, Vue, Angular, Svelte, and any Storybook-supported framework
15
- - 🎨 **Fully customizable** — Color, line height, offset, and visibility per story
16
- - 🪶 **Lightweight** — Pure CSS overlay using `linear-gradient` (no images, no canvas)
17
- - 🖱️ **Non-intrusive** — Overlay doesn't interfere with pointer events
18
- - ⚡ **Zero config** — Works out of the box with sensible defaults
14
+ - **Framework agnostic** — React, Vue, Angular, Svelte, Web Components, HTML
15
+ - **Toolbar toggle** — Show/hide the grid from Storybook's toolbar, no reload needed
16
+ - **Built-in presets** — Material, Tailwind, Bootstrap, and pixel-based grids ready to use
17
+ - **Column grids** — Optional vertical column overlay with configurable gutter width
18
+ - **Fully customizable** — Color, line height, line width, offset, opacity, z-index, max width
19
+ - **Lightweight** — Pure CSS overlay via `linear-gradient`. Zero runtime dependencies
20
+ - **Non-intrusive** — `pointer-events: none` keeps your stories fully interactive
21
+ - **TypeScript first** — Full type safety with Storybook parameter augmentation
19
22
 
20
- ## 📦 Installation
23
+ ## Requirements
21
24
 
22
- <details open>
23
- <summary><strong>pnpm</strong></summary>
25
+ - Node.js 20+
26
+ - Storybook 10+
24
27
 
25
- ```bash
26
- pnpm add -D storybook-vrhythm
27
- ```
28
-
29
- </details>
30
-
31
- <details>
32
- <summary><strong>npm</strong></summary>
33
-
34
- ```bash
35
- npm install --save-dev storybook-vrhythm
36
- ```
37
-
38
- </details>
39
-
40
- <details>
41
- <summary><strong>yarn</strong></summary>
28
+ ## Quick start
42
29
 
43
30
  ```bash
44
- yarn add -D storybook-vrhythm
31
+ pnpm add -D storybook-vrhythm
32
+ # or: npm install --save-dev storybook-vrhythm
33
+ # or: yarn add -D storybook-vrhythm
45
34
  ```
46
35
 
47
- </details>
48
-
49
- ## 🚀 Usage
50
-
51
- This package is a **Storybook preset addon**: you can register it in `main` (recommended) or add the decorator manually in `preview`.
52
-
53
- **Requirements:** Node.js 18+ and Storybook 8 or newer (see `peerDependencies` in `package.json`).
54
-
55
- ### Register as an addon (recommended)
56
-
57
- Add the package to `addons` in `.storybook/main.ts` (or `main.js`). Storybook loads the preset and applies the vertical rhythm decorator in the preview iframe.
36
+ Add to `.storybook/main.ts`:
58
37
 
59
38
  ```typescript
60
- import type { StorybookConfig } from '@storybook/react-vite'; // or your framework package
61
-
62
39
  const config = {
63
40
  addons: ['storybook-vrhythm'],
64
- } satisfies StorybookConfig;
41
+ };
65
42
 
66
43
  export default config;
67
44
  ```
68
45
 
69
- Optional defaults and overrides still use `parameters.vrhythm` in `.storybook/preview.ts`:
46
+ Done. A baseline grid overlay is now visible on every story, toggleable from the toolbar.
47
+
48
+ ## Configuration
49
+
50
+ ### Global defaults
51
+
52
+ Set defaults for all stories in `.storybook/preview.ts`:
70
53
 
71
54
  ```typescript
72
55
  export const parameters = {
73
56
  vrhythm: {
74
- color: 'rgba(178, 86, 18, 0.5)',
75
- lineHeight: '16px',
76
- offset: 0,
57
+ color: 'rgba(99, 102, 241, 0.2)',
58
+ lineHeight: '8px',
77
59
  },
78
60
  };
79
61
  ```
80
62
 
81
- ### Manual decorator
82
-
83
- If you prefer not to use the preset, import the decorator in `.storybook/preview.ts`:
63
+ ### Per-story overrides
84
64
 
85
65
  ```typescript
86
- import { withVRhythm } from 'storybook-vrhythm';
66
+ export const Compact = {
67
+ parameters: {
68
+ vrhythm: { lineHeight: '4px', color: 'rgba(244, 67, 54, 0.15)' },
69
+ },
70
+ };
87
71
 
88
- export const decorators = [withVRhythm];
72
+ export const NoGrid = {
73
+ parameters: {
74
+ vrhythm: { hide: true },
75
+ },
76
+ };
77
+ ```
89
78
 
90
- export const parameters = {
91
- vrhythm: {
92
- color: 'rgba(178, 86, 18, 0.5)',
93
- lineHeight: '16px',
94
- offset: 0,
79
+ ### Using presets
80
+
81
+ Skip manual configuration with built-in presets that match popular design systems:
82
+
83
+ ```typescript
84
+ export const MaterialGrid = {
85
+ parameters: {
86
+ vrhythm: { preset: 'material' },
95
87
  },
96
88
  };
97
89
  ```
98
90
 
99
- ### Per-story configuration
91
+ | Preset | Line height | Color | Best for |
92
+ | ----------- | ----------- | -------------------------- | ------------------------- |
93
+ | `4px` | 4px | `rgba(0, 150, 255, 0.15)` | Dense UIs, compact grids |
94
+ | `8px` | 8px | `rgba(0, 150, 255, 0.2)` | Standard 8pt grid systems |
95
+ | `16px` | 16px | `rgba(204, 204, 204, 0.5)` | Body text baseline |
96
+ | `24px` | 24px | `rgba(204, 204, 204, 0.5)` | Heading alignment |
97
+ | `material` | 4px | `rgba(244, 67, 54, 0.15)` | Material Design |
98
+ | `tailwind` | 4px | `rgba(99, 102, 241, 0.15)` | Tailwind CSS |
99
+ | `bootstrap` | 8px | `rgba(13, 110, 253, 0.2)` | Bootstrap |
100
100
 
101
- Override or hide the overlay on individual stories:
101
+ ### Column grid
102
+
103
+ Add vertical column lines on top of the horizontal baseline:
102
104
 
103
105
  ```typescript
104
- export const MyStory = {
106
+ export const ColumnGrid = {
105
107
  parameters: {
106
108
  vrhythm: {
107
- hide: true,
109
+ lineHeight: '8px',
110
+ columnWidth: '80px',
111
+ gutterWidth: '16px',
112
+ columnColor: 'rgba(99, 102, 241, 0.1)',
108
113
  },
109
114
  },
110
115
  };
111
116
  ```
112
117
 
113
- ## ⚙️ Options
118
+ ### Manual decorator
114
119
 
115
- | Option | Type | Default | Description |
116
- | ------------ | ------------------ | ---------------------- | ------------------------------------------ |
117
- | `color` | `string` | `'rgb(204, 204, 204)'` | Any valid CSS color for the guide lines |
118
- | `lineHeight` | `string \| number` | `'16px'` | Baseline grid height (e.g. `16px`, `1rem`) |
119
- | `offset` | `string \| number` | `0` | Vertical offset from the top |
120
- | `hide` | `boolean` | `false` | Hide the overlay for specific stories |
120
+ If you prefer to opt out of the addon preset:
121
121
 
122
- ## 💡 Why vertical rhythm?
122
+ ```typescript
123
+ import { withVRhythm } from 'storybook-vrhythm';
123
124
 
124
- Vertical rhythm is the practice of spacing elements on a page based on a consistent baseline grid. It improves readability and creates a sense of visual harmony. This decorator lets you **see** the grid while developing, so you can catch alignment issues before they reach production.
125
+ export const decorators = [withVRhythm];
126
+ ```
125
127
 
126
- ## 🛠️ Development
128
+ ## Options
127
129
 
128
- ```bash
129
- pnpm install # Install dependencies
130
- pnpm build # Build the package
131
- pnpm test # Run tests
132
- pnpm lint # Lint source code
133
- pnpm format # Format with Prettier
130
+ ### Style options
131
+
132
+ | Option | Type | Default | Description |
133
+ | ------------- | ------------------ | ---------------------- | -------------------------------------------------- |
134
+ | `color` | `string` | `'rgb(204, 204, 204)'` | CSS color for horizontal guide lines |
135
+ | `lineHeight` | `string \| number` | `'16px'` | Baseline grid height (`'8px'`, `'1rem'`, etc.) |
136
+ | `lineWidth` | `string \| number` | `'1px'` | Thickness of each horizontal guide line |
137
+ | `offset` | `string \| number` | `0` | Vertical offset from the top of the container |
138
+ | `opacity` | `number` | `1` | Overlay opacity (0–1) |
139
+ | `zIndex` | `number` | `9999` | Stack order of the overlay |
140
+ | `maxWidth` | `string \| number` | — | Centers the overlay with this max width |
141
+ | `columnWidth` | `string \| number` | — | Repeating column width for a vertical column grid |
142
+ | `columnColor` | `string` | — | CSS color for column lines (falls back to `color`) |
143
+ | `gutterWidth` | `string \| number` | — | Gutter between columns (requires `columnWidth`) |
144
+
145
+ ### Config options
146
+
147
+ | Option | Type | Default | Description |
148
+ | ----------- | --------- | ------- | ------------------------------------------------------------------ |
149
+ | `hide` | `boolean` | `false` | Hide the overlay for this story (overrides toolbar toggle) |
150
+ | `preset` | `string` | — | Built-in preset name (see table above) |
151
+ | `container` | `string` | — | CSS selector for the overlay's parent element (defaults to `body`) |
152
+
153
+ ### Parameter resolution order
154
+
155
+ ```text
156
+ DEFAULT_PARAMS → preset styles → story-level parameters
134
157
  ```
135
158
 
136
- ## 🤝 Contributing
159
+ Later sources override earlier ones. The story-level `hide` param takes precedence over the toolbar toggle.
137
160
 
138
- Contributions are welcome! Feel free to open an [issue](https://github.com/jmlweb/storybook-vrhythm/issues) or submit a pull request.
161
+ ## Why vertical rhythm?
139
162
 
140
- ## 🙏 Inspiration
163
+ Vertical rhythm is the practice of aligning elements to a consistent baseline grid. When text, images, and components share the same vertical cadence, layouts feel cohesive and polished — even if users can't articulate why.
141
164
 
142
- [Baseliner](https://jpedroribeiro.com/2015/08/baseliner-my-first-chrome-extension/) — a Chrome extension by JP Ribeiro for overlaying baseline grids.
165
+ This addon makes the invisible grid visible during development, so spacing inconsistencies get caught in Storybook instead of production.
166
+
167
+ ## Contributing
168
+
169
+ Contributions are welcome! Feel free to open an [issue](https://github.com/jmlweb/storybook-vrhythm/issues) or submit a pull request.
143
170
 
144
- ## 📄 License
171
+ ## License
145
172
 
146
- [MIT](LICENSE)
173
+ [MIT](https://github.com/jmlweb/storybook-vrhythm/blob/master/LICENSE)
147
174
 
148
175
  [npm-badge]: https://img.shields.io/npm/v/storybook-vrhythm.svg
149
176
  [npm]: https://www.npmjs.org/package/storybook-vrhythm
package/dist/index.d.ts CHANGED
@@ -1,15 +1,107 @@
1
- import { DecoratorFunction } from '@storybook/types';
1
+ import { DecoratorFunction, Renderer } from 'storybook/internal/types';
2
2
 
3
3
  interface StyleProps {
4
+ /** CSS color for the horizontal guide lines. Default: `'rgb(204, 204, 204)'` */
4
5
  color?: string;
6
+ /** Baseline grid height (e.g. `'8px'`, `'1rem'`). Default: `'16px'` */
5
7
  lineHeight?: string | number;
8
+ /** Thickness of each horizontal guide line. Default: `'1px'` */
9
+ lineWidth?: string | number;
10
+ /** Vertical offset from the top of the container. Default: `0` */
6
11
  offset?: string | number;
12
+ /** Overlay opacity (0–1). Default: `1` */
13
+ opacity?: number;
14
+ /** Stack order of the overlay. Default: `9999` */
15
+ zIndex?: number;
16
+ /** When set, centers the overlay horizontally with this max width. */
17
+ maxWidth?: string | number;
18
+ /** Repeating column width for a vertical column grid (e.g. `'80px'`). */
19
+ columnWidth?: string | number;
20
+ /** CSS color for vertical column lines. Falls back to `color` when omitted. */
21
+ columnColor?: string;
22
+ /** Gutter width between columns. Requires `columnWidth` to be set. */
23
+ gutterWidth?: string | number;
7
24
  }
8
25
  interface ConfigProps {
26
+ /** When `true`, hides the overlay for this story regardless of the toolbar toggle. */
9
27
  hide?: boolean;
28
+ /**
29
+ * Name of a built-in preset to apply. Story-level params override preset values.
30
+ * Available: `'4px'`, `'8px'`, `'16px'`, `'24px'`, `'material'`, `'tailwind'`, `'bootstrap'`
31
+ */
32
+ preset?: string;
33
+ /** CSS selector for the overlay's parent element. Defaults to `body`. */
34
+ container?: string;
10
35
  }
11
36
 
37
+ declare module 'storybook/internal/types' {
38
+ interface StorybookParameters {
39
+ /** Vertical rhythm overlay options (storybook-vrhythm). */
40
+ vrhythm?: StyleProps & ConfigProps;
41
+ }
42
+ }
43
+ declare module 'storybook/internal/csf' {
44
+ interface Globals {
45
+ /** Toolbar toggle/preset selector for the vertical rhythm overlay.
46
+ * Values: `'true'` (show with story params) | `'false'` (hide) | preset name (e.g. `'material'`, `'tailwind'`) | boolean. */
47
+ vrhythm?: string | boolean;
48
+ }
49
+ }
50
+
51
+ declare const presets: {
52
+ readonly '4px': {
53
+ readonly lineHeight: "4px";
54
+ readonly color: "rgba(0, 150, 255, 0.15)";
55
+ };
56
+ readonly '8px': {
57
+ readonly lineHeight: "8px";
58
+ readonly color: "rgba(0, 150, 255, 0.2)";
59
+ };
60
+ readonly '16px': {
61
+ readonly lineHeight: "16px";
62
+ readonly color: "rgba(204, 204, 204, 0.5)";
63
+ };
64
+ readonly '24px': {
65
+ readonly lineHeight: "24px";
66
+ readonly color: "rgba(204, 204, 204, 0.5)";
67
+ };
68
+ readonly material: {
69
+ readonly lineHeight: "4px";
70
+ readonly color: "rgba(244, 67, 54, 0.15)";
71
+ };
72
+ readonly tailwind: {
73
+ readonly lineHeight: "4px";
74
+ readonly color: "rgba(99, 102, 241, 0.15)";
75
+ };
76
+ readonly bootstrap: {
77
+ readonly lineHeight: "8px";
78
+ readonly color: "rgba(13, 110, 253, 0.2)";
79
+ };
80
+ };
81
+ type PresetName = keyof typeof presets;
82
+
12
83
  type VRhythmParams = StyleProps & ConfigProps;
13
- declare const withVRhythm: DecoratorFunction;
84
+ /**
85
+ * Storybook decorator that injects a vertical rhythm baseline grid overlay into stories.
86
+ *
87
+ * Register globally via the addon preset in `.storybook/main.ts` (recommended):
88
+ * ```ts
89
+ * export default { addons: ['storybook-vrhythm'] };
90
+ * ```
91
+ *
92
+ * Or manually in `.storybook/preview.ts`:
93
+ * ```ts
94
+ * import { withVRhythm } from 'storybook-vrhythm';
95
+ * export const decorators = [withVRhythm];
96
+ * ```
97
+ *
98
+ * Control per story via `parameters.vrhythm`:
99
+ * ```ts
100
+ * export const MyStory = {
101
+ * parameters: { vrhythm: { preset: 'material' } },
102
+ * };
103
+ * ```
104
+ */
105
+ declare const withVRhythm: DecoratorFunction<Renderer>;
14
106
 
15
- export { type ConfigProps, type StyleProps, type VRhythmParams, withVRhythm };
107
+ export { type ConfigProps, type PresetName, type StyleProps, type VRhythmParams, presets, withVRhythm };
package/dist/index.js CHANGED
@@ -1,7 +1,10 @@
1
1
  // src/constants.ts
2
2
  var DEFAULT_COLOR = "rgb(204, 204, 204)";
3
3
  var DEFAULT_LINE_HEIGHT = "16px";
4
+ var DEFAULT_LINE_WIDTH = "1px";
4
5
  var DEFAULT_OFFSET = 0;
6
+ var DEFAULT_OPACITY = 1;
7
+ var DEFAULT_Z_INDEX = 9999;
5
8
  var PARENT_SELECTOR = "body";
6
9
  var DIV_ID = "storybook-rhythm";
7
10
 
@@ -9,16 +12,41 @@ var DIV_ID = "storybook-rhythm";
9
12
  var getStyle = ({
10
13
  color = DEFAULT_COLOR,
11
14
  lineHeight = DEFAULT_LINE_HEIGHT,
12
- offset = DEFAULT_OFFSET
13
- }) => ({
14
- position: "absolute",
15
- top: offset,
16
- left: 0,
17
- right: 0,
18
- bottom: 0,
19
- background: `linear-gradient(${color} 1px, transparent 1px) left top / 1px ${lineHeight}`,
20
- pointerEvents: "none"
21
- });
15
+ lineWidth = DEFAULT_LINE_WIDTH,
16
+ offset = DEFAULT_OFFSET,
17
+ opacity = DEFAULT_OPACITY,
18
+ zIndex = DEFAULT_Z_INDEX,
19
+ maxWidth,
20
+ columnWidth,
21
+ columnColor,
22
+ gutterWidth
23
+ }) => {
24
+ const horizontal = `linear-gradient(${color} ${lineWidth}, transparent ${lineWidth}) left top / ${lineWidth} ${lineHeight}`;
25
+ const columnGradient = columnWidth != null ? gutterWidth != null ? `linear-gradient(90deg, transparent calc(${columnWidth} - ${gutterWidth}), ${columnColor ?? color} calc(${columnWidth} - ${gutterWidth})) left top / ${columnWidth} 100%` : `linear-gradient(90deg, ${columnColor ?? color} ${lineWidth}, transparent ${lineWidth}) left top / ${columnWidth} 100%` : null;
26
+ const background = columnGradient != null ? `${horizontal}, ${columnGradient}` : horizontal;
27
+ const positioning = maxWidth != null ? { left: "50%", width: maxWidth, transform: "translateX(-50%)" } : { left: 0, right: 0 };
28
+ return {
29
+ position: "absolute",
30
+ top: offset,
31
+ ...positioning,
32
+ bottom: 0,
33
+ background,
34
+ pointerEvents: "none",
35
+ opacity,
36
+ zIndex
37
+ };
38
+ };
39
+
40
+ // src/presets.ts
41
+ var presets = {
42
+ "4px": { lineHeight: "4px", color: "rgba(0, 150, 255, 0.15)" },
43
+ "8px": { lineHeight: "8px", color: "rgba(0, 150, 255, 0.2)" },
44
+ "16px": { lineHeight: "16px", color: "rgba(204, 204, 204, 0.5)" },
45
+ "24px": { lineHeight: "24px", color: "rgba(204, 204, 204, 0.5)" },
46
+ material: { lineHeight: "4px", color: "rgba(244, 67, 54, 0.15)" },
47
+ tailwind: { lineHeight: "4px", color: "rgba(99, 102, 241, 0.15)" },
48
+ bootstrap: { lineHeight: "8px", color: "rgba(13, 110, 253, 0.2)" }
49
+ };
22
50
 
23
51
  // src/utils.ts
24
52
  function createElement() {
@@ -39,38 +67,55 @@ function removeElement() {
39
67
  element.remove();
40
68
  }
41
69
  }
42
- function injectStyle(style) {
70
+ function injectStyle(style, container) {
43
71
  const element = getOrCreateElement();
44
72
  Object.assign(element.style, style);
45
- if (!element.parentNode) {
46
- const parent = document.querySelector(PARENT_SELECTOR);
47
- if (parent) {
48
- parent.append(element);
49
- }
73
+ let parent = null;
74
+ try {
75
+ parent = document.querySelector(container ?? PARENT_SELECTOR);
76
+ } catch {
77
+ }
78
+ if (!parent) {
79
+ parent = document.querySelector(PARENT_SELECTOR);
80
+ }
81
+ if (parent && element.parentNode !== parent) {
82
+ parent.append(element);
50
83
  }
51
84
  }
52
85
 
53
86
  // src/index.ts
54
87
  var DEFAULT_PARAMS = {
55
88
  hide: false,
89
+ preset: "",
90
+ container: "",
56
91
  color: DEFAULT_COLOR,
57
92
  lineHeight: DEFAULT_LINE_HEIGHT,
58
- offset: DEFAULT_OFFSET
93
+ offset: DEFAULT_OFFSET,
94
+ opacity: DEFAULT_OPACITY,
95
+ zIndex: DEFAULT_Z_INDEX
59
96
  };
60
97
  var withVRhythm = (storyFn, context) => {
98
+ const raw = context.parameters?.vrhythm;
99
+ const presetStyles = raw?.preset && raw.preset in presets ? presets[raw.preset] : {};
61
100
  const params = {
62
101
  ...DEFAULT_PARAMS,
63
- ...context.parameters?.vrhythm
102
+ ...presetStyles,
103
+ ...raw
64
104
  };
65
- if (params.hide) {
105
+ const globalsVrhythm = context.globals?.vrhythm;
106
+ const globalPresetName = typeof globalsVrhythm === "string" && globalsVrhythm !== "true" && globalsVrhythm !== "false" && globalsVrhythm in presets ? globalsVrhythm : null;
107
+ const globalPresetStyles = globalPresetName ? presets[globalPresetName] : {};
108
+ const isHidden = !!params.hide || globalsVrhythm === false || globalsVrhythm === "false";
109
+ if (isHidden) {
66
110
  removeElement();
67
111
  } else {
68
- const style = getStyle(params);
69
- injectStyle(style);
112
+ const finalParams = { ...params, ...globalPresetStyles };
113
+ const style = getStyle(finalParams);
114
+ injectStyle(style, params.container || void 0);
70
115
  }
71
116
  return storyFn(context);
72
117
  };
73
118
 
74
- export { withVRhythm };
119
+ export { presets, withVRhythm };
75
120
  //# sourceMappingURL=index.js.map
76
121
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/getStyle.ts","../src/utils.ts","../src/index.ts"],"names":[],"mappings":";AAAO,IAAM,aAAA,GAAgB,oBAAA;AACtB,IAAM,mBAAA,GAAsB,MAAA;AAC5B,IAAM,cAAA,GAAiB,CAAA;AACvB,IAAM,eAAA,GAAkB,MAAA;AACxB,IAAM,MAAA,GAAS,kBAAA;;;ACGf,IAAM,WAAW,CAAC;AAAA,EACvB,KAAA,GAAQ,aAAA;AAAA,EACR,UAAA,GAAa,mBAAA;AAAA,EACb,MAAA,GAAS;AACX,CAAA,MAA6B;AAAA,EAC3B,QAAA,EAAU,UAAA;AAAA,EACV,GAAA,EAAK,MAAA;AAAA,EACL,IAAA,EAAM,CAAA;AAAA,EACN,KAAA,EAAO,CAAA;AAAA,EACP,MAAA,EAAQ,CAAA;AAAA,EACR,UAAA,EAAY,CAAA,gBAAA,EAAmB,KAAK,CAAA,sCAAA,EAAyC,UAAU,CAAA,CAAA;AAAA,EACvF,aAAA,EAAe;AACjB,CAAA,CAAA;;;AChBA,SAAS,aAAA,GAAgC;AACvC,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC5C,EAAA,OAAA,CAAQ,YAAA,CAAa,MAAM,MAAM,CAAA;AACjC,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,kBAAA,GAAqC;AAC5C,EAAA,MAAM,QAAA,GAAW,QAAA,CAAS,cAAA,CAAe,MAAM,CAAA;AAC/C,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,OAAO,QAAA;AAAA,EACT;AACA,EAAA,OAAO,aAAA,EAAc;AACvB;AAEO,SAAS,aAAA,GAAsB;AACpC,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,cAAA,CAAe,MAAM,CAAA;AAC9C,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,OAAA,CAAQ,MAAA,EAAO;AAAA,EACjB;AACF;AAEO,SAAS,YAAY,KAAA,EAAuB;AACjD,EAAA,MAAM,UAAU,kBAAA,EAAmB;AACnC,EAAA,MAAA,CAAO,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,KAAK,CAAA;AAElC,EAAA,IAAI,CAAC,QAAQ,UAAA,EAAY;AACvB,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAA,CAAc,eAAe,CAAA;AACrD,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,MAAA,CAAO,OAAO,OAAO,CAAA;AAAA,IACvB;AAAA,EACF;AACF;;;ACrBA,IAAM,cAAA,GAA0C;AAAA,EAC9C,IAAA,EAAM,KAAA;AAAA,EACN,KAAA,EAAO,aAAA;AAAA,EACP,UAAA,EAAY,mBAAA;AAAA,EACZ,MAAA,EAAQ;AACV,CAAA;AAEO,IAAM,WAAA,GAAiC,CAAC,OAAA,EAAS,OAAA,KAAY;AAClE,EAAA,MAAM,MAAA,GAAkC;AAAA,IACtC,GAAG,cAAA;AAAA,IACH,GAAI,QAAQ,UAAA,EAAwD;AAAA,GACtE;AAEA,EAAA,IAAI,OAAO,IAAA,EAAM;AACf,IAAA,aAAA,EAAc;AAAA,EAChB,CAAA,MAAO;AACL,IAAA,MAAM,KAAA,GAAQ,SAAS,MAAM,CAAA;AAC7B,IAAA,WAAA,CAAY,KAAK,CAAA;AAAA,EACnB;AAEA,EAAA,OAAO,QAAQ,OAAO,CAAA;AACxB","file":"index.js","sourcesContent":["export const DEFAULT_COLOR = 'rgb(204, 204, 204)';\nexport const DEFAULT_LINE_HEIGHT = '16px';\nexport const DEFAULT_OFFSET = 0;\nexport const PARENT_SELECTOR = 'body';\nexport const DIV_ID = 'storybook-rhythm';\n","import { StyleObj, StyleProps } from './types';\nimport {\n DEFAULT_COLOR,\n DEFAULT_LINE_HEIGHT,\n DEFAULT_OFFSET,\n} from './constants';\n\nexport const getStyle = ({\n color = DEFAULT_COLOR,\n lineHeight = DEFAULT_LINE_HEIGHT,\n offset = DEFAULT_OFFSET,\n}: StyleProps): StyleObj => ({\n position: 'absolute',\n top: offset,\n left: 0,\n right: 0,\n bottom: 0,\n background: `linear-gradient(${color} 1px, transparent 1px) left top / 1px ${lineHeight}`,\n pointerEvents: 'none',\n});\n","import { PARENT_SELECTOR, DIV_ID } from './constants';\nimport { StyleObj } from './types';\n\nfunction createElement(): HTMLDivElement {\n const element = document.createElement('div');\n element.setAttribute('id', DIV_ID);\n return element;\n}\n\nfunction getOrCreateElement(): HTMLDivElement {\n const existing = document.getElementById(DIV_ID) as HTMLDivElement | null;\n if (existing) {\n return existing;\n }\n return createElement();\n}\n\nexport function removeElement(): void {\n const element = document.getElementById(DIV_ID);\n if (element) {\n element.remove();\n }\n}\n\nexport function injectStyle(style: StyleObj): void {\n const element = getOrCreateElement();\n Object.assign(element.style, style);\n\n if (!element.parentNode) {\n const parent = document.querySelector(PARENT_SELECTOR);\n if (parent) {\n parent.append(element);\n }\n }\n}\n","import type { DecoratorFunction } from '@storybook/types';\n\nimport { getStyle } from './getStyle';\nimport { StyleProps, ConfigProps } from './types';\nimport { injectStyle, removeElement } from './utils';\nimport {\n DEFAULT_COLOR,\n DEFAULT_LINE_HEIGHT,\n DEFAULT_OFFSET,\n} from './constants';\n\nexport type VRhythmParams = StyleProps & ConfigProps;\n\nconst DEFAULT_PARAMS: Required<VRhythmParams> = {\n hide: false,\n color: DEFAULT_COLOR,\n lineHeight: DEFAULT_LINE_HEIGHT,\n offset: DEFAULT_OFFSET,\n};\n\nexport const withVRhythm: DecoratorFunction = (storyFn, context) => {\n const params: Required<VRhythmParams> = {\n ...DEFAULT_PARAMS,\n ...(context.parameters as { vrhythm?: VRhythmParams } | undefined)?.vrhythm,\n };\n\n if (params.hide) {\n removeElement();\n } else {\n const style = getStyle(params);\n injectStyle(style);\n }\n\n return storyFn(context);\n};\n\nexport type { StyleProps, ConfigProps } from './types';\n"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/getStyle.ts","../src/presets.ts","../src/utils.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export const DEFAULT_COLOR = 'rgb(204, 204, 204)';\nexport const DEFAULT_LINE_HEIGHT = '16px';\nexport const DEFAULT_LINE_WIDTH = '1px';\nexport const DEFAULT_OFFSET = 0;\nexport const DEFAULT_OPACITY = 1;\nexport const DEFAULT_Z_INDEX = 9999;\nexport const PARENT_SELECTOR = 'body';\nexport const DIV_ID = 'storybook-rhythm';\n","import { StyleObj, StyleProps } from './types';\nimport {\n DEFAULT_COLOR,\n DEFAULT_LINE_HEIGHT,\n DEFAULT_LINE_WIDTH,\n DEFAULT_OFFSET,\n DEFAULT_OPACITY,\n DEFAULT_Z_INDEX,\n} from './constants';\n\nexport const getStyle = ({\n color = DEFAULT_COLOR,\n lineHeight = DEFAULT_LINE_HEIGHT,\n lineWidth = DEFAULT_LINE_WIDTH,\n offset = DEFAULT_OFFSET,\n opacity = DEFAULT_OPACITY,\n zIndex = DEFAULT_Z_INDEX,\n maxWidth,\n columnWidth,\n columnColor,\n gutterWidth,\n}: StyleProps): StyleObj => {\n const horizontal = `linear-gradient(${color} ${lineWidth}, transparent ${lineWidth}) left top / ${lineWidth} ${lineHeight}`;\n\n const columnGradient =\n columnWidth != null\n ? gutterWidth != null\n ? `linear-gradient(90deg, transparent calc(${columnWidth} - ${gutterWidth}), ${columnColor ?? color} calc(${columnWidth} - ${gutterWidth})) left top / ${columnWidth} 100%`\n : `linear-gradient(90deg, ${columnColor ?? color} ${lineWidth}, transparent ${lineWidth}) left top / ${columnWidth} 100%`\n : null;\n\n const background =\n columnGradient != null ? `${horizontal}, ${columnGradient}` : horizontal;\n\n const positioning: StyleObj =\n maxWidth != null\n ? { left: '50%', width: maxWidth, transform: 'translateX(-50%)' }\n : { left: 0, right: 0 };\n\n return {\n position: 'absolute',\n top: offset,\n ...positioning,\n bottom: 0,\n background,\n pointerEvents: 'none',\n opacity,\n zIndex,\n };\n};\n","import type { StyleProps } from './types';\n\nexport const presets = {\n '4px': { lineHeight: '4px', color: 'rgba(0, 150, 255, 0.15)' },\n '8px': { lineHeight: '8px', color: 'rgba(0, 150, 255, 0.2)' },\n '16px': { lineHeight: '16px', color: 'rgba(204, 204, 204, 0.5)' },\n '24px': { lineHeight: '24px', color: 'rgba(204, 204, 204, 0.5)' },\n material: { lineHeight: '4px', color: 'rgba(244, 67, 54, 0.15)' },\n tailwind: { lineHeight: '4px', color: 'rgba(99, 102, 241, 0.15)' },\n bootstrap: { lineHeight: '8px', color: 'rgba(13, 110, 253, 0.2)' },\n} as const satisfies Record<string, StyleProps>;\n\nexport type PresetName = keyof typeof presets;\n","import { PARENT_SELECTOR, DIV_ID } from './constants';\nimport { StyleObj } from './types';\n\nfunction createElement(): HTMLDivElement {\n const element = document.createElement('div');\n element.setAttribute('id', DIV_ID);\n return element;\n}\n\nfunction getOrCreateElement(): HTMLDivElement {\n const existing = document.getElementById(DIV_ID) as HTMLDivElement | null;\n if (existing) {\n return existing;\n }\n return createElement();\n}\n\nexport function removeElement(): void {\n const element = document.getElementById(DIV_ID);\n if (element) {\n element.remove();\n }\n}\n\nexport function injectStyle(style: StyleObj, container?: string): void {\n const element = getOrCreateElement();\n Object.assign(element.style, style);\n\n let parent: Element | null = null;\n try {\n parent = document.querySelector(container ?? PARENT_SELECTOR);\n } catch {\n // invalid selector string — fall through to body fallback\n }\n\n if (!parent) {\n parent = document.querySelector(PARENT_SELECTOR);\n }\n\n if (parent && element.parentNode !== parent) {\n parent.append(element);\n }\n}\n","import './storybook-parameter-augmentation';\n\nimport type { DecoratorFunction, Renderer } from 'storybook/internal/types';\n\nimport { getStyle } from './getStyle';\nimport { StyleProps, ConfigProps } from './types';\nimport { presets, PresetName } from './presets';\nimport { injectStyle, removeElement } from './utils';\nimport {\n DEFAULT_COLOR,\n DEFAULT_LINE_HEIGHT,\n DEFAULT_OFFSET,\n DEFAULT_OPACITY,\n DEFAULT_Z_INDEX,\n} from './constants';\n\nexport type VRhythmParams = StyleProps & ConfigProps;\n\nconst DEFAULT_PARAMS: VRhythmParams = {\n hide: false,\n preset: '',\n container: '',\n color: DEFAULT_COLOR,\n lineHeight: DEFAULT_LINE_HEIGHT,\n offset: DEFAULT_OFFSET,\n opacity: DEFAULT_OPACITY,\n zIndex: DEFAULT_Z_INDEX,\n};\n\n/**\n * Storybook decorator that injects a vertical rhythm baseline grid overlay into stories.\n *\n * Register globally via the addon preset in `.storybook/main.ts` (recommended):\n * ```ts\n * export default { addons: ['storybook-vrhythm'] };\n * ```\n *\n * Or manually in `.storybook/preview.ts`:\n * ```ts\n * import { withVRhythm } from 'storybook-vrhythm';\n * export const decorators = [withVRhythm];\n * ```\n *\n * Control per story via `parameters.vrhythm`:\n * ```ts\n * export const MyStory = {\n * parameters: { vrhythm: { preset: 'material' } },\n * };\n * ```\n */\nexport const withVRhythm: DecoratorFunction<Renderer> = (storyFn, context) => {\n const raw = (context.parameters as { vrhythm?: VRhythmParams } | undefined)\n ?.vrhythm;\n const presetStyles =\n raw?.preset && raw.preset in presets\n ? presets[raw.preset as PresetName]\n : {};\n const params: VRhythmParams = {\n ...DEFAULT_PARAMS,\n ...presetStyles,\n ...raw,\n };\n\n const globalsVrhythm = (\n context.globals as { vrhythm?: string | boolean } | undefined\n )?.vrhythm;\n\n const globalPresetName =\n typeof globalsVrhythm === 'string' &&\n globalsVrhythm !== 'true' &&\n globalsVrhythm !== 'false' &&\n globalsVrhythm in presets\n ? (globalsVrhythm as PresetName)\n : null;\n\n const globalPresetStyles = globalPresetName ? presets[globalPresetName] : {};\n\n const isHidden =\n !!params.hide || globalsVrhythm === false || globalsVrhythm === 'false';\n\n if (isHidden) {\n removeElement();\n } else {\n const finalParams: VRhythmParams = { ...params, ...globalPresetStyles };\n const style = getStyle(finalParams);\n injectStyle(style, params.container || undefined);\n }\n\n return storyFn(context);\n};\n\nexport { presets } from './presets';\nexport type { PresetName } from './presets';\nexport type { StyleProps, ConfigProps } from './types';\n"]}
package/dist/preset.js CHANGED
@@ -1,11 +1 @@
1
- // src/preset.ts
2
- import { dirname, join } from "path";
3
- import { fileURLToPath } from "url";
4
- var dir = dirname(fileURLToPath(import.meta.url));
5
- function previewAnnotations(entry = []) {
6
- return [...entry, join(dir, "preview.js")];
7
- }
8
- export {
9
- previewAnnotations
10
- };
11
1
  //# sourceMappingURL=preset.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/preset.ts"],"sourcesContent":["import { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst dir = dirname(fileURLToPath(import.meta.url));\n\nexport function previewAnnotations(entry: string[] = []) {\n return [...entry, join(dir, 'preview.js')];\n}\n"],"mappings":";AAAA,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAE9B,IAAM,MAAM,QAAQ,cAAc,YAAY,GAAG,CAAC;AAE3C,SAAS,mBAAmB,QAAkB,CAAC,GAAG;AACvD,SAAO,CAAC,GAAG,OAAO,KAAK,KAAK,YAAY,CAAC;AAC3C;","names":[]}
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/dist/preview.d.ts CHANGED
@@ -1,5 +1,14 @@
1
- import { ProjectAnnotations, Renderer } from '@storybook/types';
1
+ import * as storybook_internal_csf from 'storybook/internal/csf';
2
+ import { VRhythmParams } from './index.js';
3
+ import 'storybook/internal/types';
2
4
 
3
- declare const preview: ProjectAnnotations<Renderer>;
5
+ declare const _default: storybook_internal_csf.PreviewAddon<{
6
+ parameters: {
7
+ vrhythm?: VRhythmParams;
8
+ };
9
+ globals: {
10
+ vrhythm?: string | boolean;
11
+ };
12
+ }>;
4
13
 
5
- export { preview as default };
14
+ export { _default as default };
package/dist/preview.js CHANGED
@@ -1,7 +1,14 @@
1
+ import { definePreviewAddon } from 'storybook/internal/csf';
2
+
3
+ // src/preview.ts
4
+
1
5
  // src/constants.ts
2
6
  var DEFAULT_COLOR = "rgb(204, 204, 204)";
3
7
  var DEFAULT_LINE_HEIGHT = "16px";
8
+ var DEFAULT_LINE_WIDTH = "1px";
4
9
  var DEFAULT_OFFSET = 0;
10
+ var DEFAULT_OPACITY = 1;
11
+ var DEFAULT_Z_INDEX = 9999;
5
12
  var PARENT_SELECTOR = "body";
6
13
  var DIV_ID = "storybook-rhythm";
7
14
 
@@ -9,16 +16,41 @@ var DIV_ID = "storybook-rhythm";
9
16
  var getStyle = ({
10
17
  color = DEFAULT_COLOR,
11
18
  lineHeight = DEFAULT_LINE_HEIGHT,
12
- offset = DEFAULT_OFFSET
13
- }) => ({
14
- position: "absolute",
15
- top: offset,
16
- left: 0,
17
- right: 0,
18
- bottom: 0,
19
- background: `linear-gradient(${color} 1px, transparent 1px) left top / 1px ${lineHeight}`,
20
- pointerEvents: "none"
21
- });
19
+ lineWidth = DEFAULT_LINE_WIDTH,
20
+ offset = DEFAULT_OFFSET,
21
+ opacity = DEFAULT_OPACITY,
22
+ zIndex = DEFAULT_Z_INDEX,
23
+ maxWidth,
24
+ columnWidth,
25
+ columnColor,
26
+ gutterWidth
27
+ }) => {
28
+ const horizontal = `linear-gradient(${color} ${lineWidth}, transparent ${lineWidth}) left top / ${lineWidth} ${lineHeight}`;
29
+ const columnGradient = columnWidth != null ? gutterWidth != null ? `linear-gradient(90deg, transparent calc(${columnWidth} - ${gutterWidth}), ${columnColor ?? color} calc(${columnWidth} - ${gutterWidth})) left top / ${columnWidth} 100%` : `linear-gradient(90deg, ${columnColor ?? color} ${lineWidth}, transparent ${lineWidth}) left top / ${columnWidth} 100%` : null;
30
+ const background = columnGradient != null ? `${horizontal}, ${columnGradient}` : horizontal;
31
+ const positioning = maxWidth != null ? { left: "50%", width: maxWidth, transform: "translateX(-50%)" } : { left: 0, right: 0 };
32
+ return {
33
+ position: "absolute",
34
+ top: offset,
35
+ ...positioning,
36
+ bottom: 0,
37
+ background,
38
+ pointerEvents: "none",
39
+ opacity,
40
+ zIndex
41
+ };
42
+ };
43
+
44
+ // src/presets.ts
45
+ var presets = {
46
+ "4px": { lineHeight: "4px", color: "rgba(0, 150, 255, 0.15)" },
47
+ "8px": { lineHeight: "8px", color: "rgba(0, 150, 255, 0.2)" },
48
+ "16px": { lineHeight: "16px", color: "rgba(204, 204, 204, 0.5)" },
49
+ "24px": { lineHeight: "24px", color: "rgba(204, 204, 204, 0.5)" },
50
+ material: { lineHeight: "4px", color: "rgba(244, 67, 54, 0.15)" },
51
+ tailwind: { lineHeight: "4px", color: "rgba(99, 102, 241, 0.15)" },
52
+ bootstrap: { lineHeight: "8px", color: "rgba(13, 110, 253, 0.2)" }
53
+ };
22
54
 
23
55
  // src/utils.ts
24
56
  function createElement() {
@@ -39,43 +71,83 @@ function removeElement() {
39
71
  element.remove();
40
72
  }
41
73
  }
42
- function injectStyle(style) {
74
+ function injectStyle(style, container) {
43
75
  const element = getOrCreateElement();
44
76
  Object.assign(element.style, style);
45
- if (!element.parentNode) {
46
- const parent = document.querySelector(PARENT_SELECTOR);
47
- if (parent) {
48
- parent.append(element);
49
- }
77
+ let parent = null;
78
+ try {
79
+ parent = document.querySelector(container ?? PARENT_SELECTOR);
80
+ } catch {
81
+ }
82
+ if (!parent) {
83
+ parent = document.querySelector(PARENT_SELECTOR);
84
+ }
85
+ if (parent && element.parentNode !== parent) {
86
+ parent.append(element);
50
87
  }
51
88
  }
52
89
 
53
90
  // src/index.ts
54
91
  var DEFAULT_PARAMS = {
55
92
  hide: false,
93
+ preset: "",
94
+ container: "",
56
95
  color: DEFAULT_COLOR,
57
96
  lineHeight: DEFAULT_LINE_HEIGHT,
58
- offset: DEFAULT_OFFSET
97
+ offset: DEFAULT_OFFSET,
98
+ opacity: DEFAULT_OPACITY,
99
+ zIndex: DEFAULT_Z_INDEX
59
100
  };
60
101
  var withVRhythm = (storyFn, context) => {
102
+ const raw = context.parameters?.vrhythm;
103
+ const presetStyles = raw?.preset && raw.preset in presets ? presets[raw.preset] : {};
61
104
  const params = {
62
105
  ...DEFAULT_PARAMS,
63
- ...context.parameters?.vrhythm
106
+ ...presetStyles,
107
+ ...raw
64
108
  };
65
- if (params.hide) {
109
+ const globalsVrhythm = context.globals?.vrhythm;
110
+ const globalPresetName = typeof globalsVrhythm === "string" && globalsVrhythm !== "true" && globalsVrhythm !== "false" && globalsVrhythm in presets ? globalsVrhythm : null;
111
+ const globalPresetStyles = globalPresetName ? presets[globalPresetName] : {};
112
+ const isHidden = !!params.hide || globalsVrhythm === false || globalsVrhythm === "false";
113
+ if (isHidden) {
66
114
  removeElement();
67
115
  } else {
68
- const style = getStyle(params);
69
- injectStyle(style);
116
+ const finalParams = { ...params, ...globalPresetStyles };
117
+ const style = getStyle(finalParams);
118
+ injectStyle(style, params.container || void 0);
70
119
  }
71
120
  return storyFn(context);
72
121
  };
73
122
 
74
123
  // src/preview.ts
75
- var preview = {
76
- decorators: [withVRhythm]
77
- };
78
- var preview_default = preview;
124
+ var preview_default = definePreviewAddon({
125
+ decorators: [withVRhythm],
126
+ globalTypes: {
127
+ vrhythm: {
128
+ description: "Toggle vertical rhythm grid overlay",
129
+ toolbar: {
130
+ title: "Show vertical rhythm",
131
+ icon: "grid",
132
+ items: [
133
+ { value: "true", title: "Default (story params)", icon: "eye" },
134
+ { value: "false", title: "Hide", icon: "eyeclose" },
135
+ { value: "4px", title: "4px baseline", icon: "grid" },
136
+ { value: "8px", title: "8px baseline", icon: "grid" },
137
+ { value: "16px", title: "16px baseline", icon: "grid" },
138
+ { value: "24px", title: "24px baseline", icon: "grid" },
139
+ { value: "material", title: "Material Design", icon: "grid" },
140
+ { value: "tailwind", title: "Tailwind CSS", icon: "grid" },
141
+ { value: "bootstrap", title: "Bootstrap", icon: "grid" }
142
+ ],
143
+ dynamicTitle: true
144
+ }
145
+ }
146
+ },
147
+ initialGlobals: {
148
+ vrhythm: "true"
149
+ }
150
+ });
79
151
 
80
152
  export { preview_default as default };
81
153
  //# sourceMappingURL=preview.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/getStyle.ts","../src/utils.ts","../src/index.ts","../src/preview.ts"],"names":[],"mappings":";AAAO,IAAM,aAAA,GAAgB,oBAAA;AACtB,IAAM,mBAAA,GAAsB,MAAA;AAC5B,IAAM,cAAA,GAAiB,CAAA;AACvB,IAAM,eAAA,GAAkB,MAAA;AACxB,IAAM,MAAA,GAAS,kBAAA;;;ACGf,IAAM,WAAW,CAAC;AAAA,EACvB,KAAA,GAAQ,aAAA;AAAA,EACR,UAAA,GAAa,mBAAA;AAAA,EACb,MAAA,GAAS;AACX,CAAA,MAA6B;AAAA,EAC3B,QAAA,EAAU,UAAA;AAAA,EACV,GAAA,EAAK,MAAA;AAAA,EACL,IAAA,EAAM,CAAA;AAAA,EACN,KAAA,EAAO,CAAA;AAAA,EACP,MAAA,EAAQ,CAAA;AAAA,EACR,UAAA,EAAY,CAAA,gBAAA,EAAmB,KAAK,CAAA,sCAAA,EAAyC,UAAU,CAAA,CAAA;AAAA,EACvF,aAAA,EAAe;AACjB,CAAA,CAAA;;;AChBA,SAAS,aAAA,GAAgC;AACvC,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC5C,EAAA,OAAA,CAAQ,YAAA,CAAa,MAAM,MAAM,CAAA;AACjC,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,kBAAA,GAAqC;AAC5C,EAAA,MAAM,QAAA,GAAW,QAAA,CAAS,cAAA,CAAe,MAAM,CAAA;AAC/C,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,OAAO,QAAA;AAAA,EACT;AACA,EAAA,OAAO,aAAA,EAAc;AACvB;AAEO,SAAS,aAAA,GAAsB;AACpC,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,cAAA,CAAe,MAAM,CAAA;AAC9C,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,OAAA,CAAQ,MAAA,EAAO;AAAA,EACjB;AACF;AAEO,SAAS,YAAY,KAAA,EAAuB;AACjD,EAAA,MAAM,UAAU,kBAAA,EAAmB;AACnC,EAAA,MAAA,CAAO,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,KAAK,CAAA;AAElC,EAAA,IAAI,CAAC,QAAQ,UAAA,EAAY;AACvB,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAA,CAAc,eAAe,CAAA;AACrD,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,MAAA,CAAO,OAAO,OAAO,CAAA;AAAA,IACvB;AAAA,EACF;AACF;;;ACrBA,IAAM,cAAA,GAA0C;AAAA,EAC9C,IAAA,EAAM,KAAA;AAAA,EACN,KAAA,EAAO,aAAA;AAAA,EACP,UAAA,EAAY,mBAAA;AAAA,EACZ,MAAA,EAAQ;AACV,CAAA;AAEO,IAAM,WAAA,GAAiC,CAAC,OAAA,EAAS,OAAA,KAAY;AAClE,EAAA,MAAM,MAAA,GAAkC;AAAA,IACtC,GAAG,cAAA;AAAA,IACH,GAAI,QAAQ,UAAA,EAAwD;AAAA,GACtE;AAEA,EAAA,IAAI,OAAO,IAAA,EAAM;AACf,IAAA,aAAA,EAAc;AAAA,EAChB,CAAA,MAAO;AACL,IAAA,MAAM,KAAA,GAAQ,SAAS,MAAM,CAAA;AAC7B,IAAA,WAAA,CAAY,KAAK,CAAA;AAAA,EACnB;AAEA,EAAA,OAAO,QAAQ,OAAO,CAAA;AACxB,CAAA;;;AC9BA,IAAM,OAAA,GAAwC;AAAA,EAC5C,UAAA,EAAY,CAAC,WAAW;AAC1B,CAAA;AAEA,IAAO,eAAA,GAAQ","file":"preview.js","sourcesContent":["export const DEFAULT_COLOR = 'rgb(204, 204, 204)';\nexport const DEFAULT_LINE_HEIGHT = '16px';\nexport const DEFAULT_OFFSET = 0;\nexport const PARENT_SELECTOR = 'body';\nexport const DIV_ID = 'storybook-rhythm';\n","import { StyleObj, StyleProps } from './types';\nimport {\n DEFAULT_COLOR,\n DEFAULT_LINE_HEIGHT,\n DEFAULT_OFFSET,\n} from './constants';\n\nexport const getStyle = ({\n color = DEFAULT_COLOR,\n lineHeight = DEFAULT_LINE_HEIGHT,\n offset = DEFAULT_OFFSET,\n}: StyleProps): StyleObj => ({\n position: 'absolute',\n top: offset,\n left: 0,\n right: 0,\n bottom: 0,\n background: `linear-gradient(${color} 1px, transparent 1px) left top / 1px ${lineHeight}`,\n pointerEvents: 'none',\n});\n","import { PARENT_SELECTOR, DIV_ID } from './constants';\nimport { StyleObj } from './types';\n\nfunction createElement(): HTMLDivElement {\n const element = document.createElement('div');\n element.setAttribute('id', DIV_ID);\n return element;\n}\n\nfunction getOrCreateElement(): HTMLDivElement {\n const existing = document.getElementById(DIV_ID) as HTMLDivElement | null;\n if (existing) {\n return existing;\n }\n return createElement();\n}\n\nexport function removeElement(): void {\n const element = document.getElementById(DIV_ID);\n if (element) {\n element.remove();\n }\n}\n\nexport function injectStyle(style: StyleObj): void {\n const element = getOrCreateElement();\n Object.assign(element.style, style);\n\n if (!element.parentNode) {\n const parent = document.querySelector(PARENT_SELECTOR);\n if (parent) {\n parent.append(element);\n }\n }\n}\n","import type { DecoratorFunction } from '@storybook/types';\n\nimport { getStyle } from './getStyle';\nimport { StyleProps, ConfigProps } from './types';\nimport { injectStyle, removeElement } from './utils';\nimport {\n DEFAULT_COLOR,\n DEFAULT_LINE_HEIGHT,\n DEFAULT_OFFSET,\n} from './constants';\n\nexport type VRhythmParams = StyleProps & ConfigProps;\n\nconst DEFAULT_PARAMS: Required<VRhythmParams> = {\n hide: false,\n color: DEFAULT_COLOR,\n lineHeight: DEFAULT_LINE_HEIGHT,\n offset: DEFAULT_OFFSET,\n};\n\nexport const withVRhythm: DecoratorFunction = (storyFn, context) => {\n const params: Required<VRhythmParams> = {\n ...DEFAULT_PARAMS,\n ...(context.parameters as { vrhythm?: VRhythmParams } | undefined)?.vrhythm,\n };\n\n if (params.hide) {\n removeElement();\n } else {\n const style = getStyle(params);\n injectStyle(style);\n }\n\n return storyFn(context);\n};\n\nexport type { StyleProps, ConfigProps } from './types';\n","import type { ProjectAnnotations, Renderer } from '@storybook/types';\n\nimport { withVRhythm } from './index';\n\nconst preview: ProjectAnnotations<Renderer> = {\n decorators: [withVRhythm],\n};\n\nexport default preview;\n"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/getStyle.ts","../src/presets.ts","../src/utils.ts","../src/index.ts","../src/preview.ts"],"names":[],"mappings":"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","file":"preview.js","sourcesContent":["export const DEFAULT_COLOR = 'rgb(204, 204, 204)';\nexport const DEFAULT_LINE_HEIGHT = '16px';\nexport const DEFAULT_LINE_WIDTH = '1px';\nexport const DEFAULT_OFFSET = 0;\nexport const DEFAULT_OPACITY = 1;\nexport const DEFAULT_Z_INDEX = 9999;\nexport const PARENT_SELECTOR = 'body';\nexport const DIV_ID = 'storybook-rhythm';\n","import { StyleObj, StyleProps } from './types';\nimport {\n DEFAULT_COLOR,\n DEFAULT_LINE_HEIGHT,\n DEFAULT_LINE_WIDTH,\n DEFAULT_OFFSET,\n DEFAULT_OPACITY,\n DEFAULT_Z_INDEX,\n} from './constants';\n\nexport const getStyle = ({\n color = DEFAULT_COLOR,\n lineHeight = DEFAULT_LINE_HEIGHT,\n lineWidth = DEFAULT_LINE_WIDTH,\n offset = DEFAULT_OFFSET,\n opacity = DEFAULT_OPACITY,\n zIndex = DEFAULT_Z_INDEX,\n maxWidth,\n columnWidth,\n columnColor,\n gutterWidth,\n}: StyleProps): StyleObj => {\n const horizontal = `linear-gradient(${color} ${lineWidth}, transparent ${lineWidth}) left top / ${lineWidth} ${lineHeight}`;\n\n const columnGradient =\n columnWidth != null\n ? gutterWidth != null\n ? `linear-gradient(90deg, transparent calc(${columnWidth} - ${gutterWidth}), ${columnColor ?? color} calc(${columnWidth} - ${gutterWidth})) left top / ${columnWidth} 100%`\n : `linear-gradient(90deg, ${columnColor ?? color} ${lineWidth}, transparent ${lineWidth}) left top / ${columnWidth} 100%`\n : null;\n\n const background =\n columnGradient != null ? `${horizontal}, ${columnGradient}` : horizontal;\n\n const positioning: StyleObj =\n maxWidth != null\n ? { left: '50%', width: maxWidth, transform: 'translateX(-50%)' }\n : { left: 0, right: 0 };\n\n return {\n position: 'absolute',\n top: offset,\n ...positioning,\n bottom: 0,\n background,\n pointerEvents: 'none',\n opacity,\n zIndex,\n };\n};\n","import type { StyleProps } from './types';\n\nexport const presets = {\n '4px': { lineHeight: '4px', color: 'rgba(0, 150, 255, 0.15)' },\n '8px': { lineHeight: '8px', color: 'rgba(0, 150, 255, 0.2)' },\n '16px': { lineHeight: '16px', color: 'rgba(204, 204, 204, 0.5)' },\n '24px': { lineHeight: '24px', color: 'rgba(204, 204, 204, 0.5)' },\n material: { lineHeight: '4px', color: 'rgba(244, 67, 54, 0.15)' },\n tailwind: { lineHeight: '4px', color: 'rgba(99, 102, 241, 0.15)' },\n bootstrap: { lineHeight: '8px', color: 'rgba(13, 110, 253, 0.2)' },\n} as const satisfies Record<string, StyleProps>;\n\nexport type PresetName = keyof typeof presets;\n","import { PARENT_SELECTOR, DIV_ID } from './constants';\nimport { StyleObj } from './types';\n\nfunction createElement(): HTMLDivElement {\n const element = document.createElement('div');\n element.setAttribute('id', DIV_ID);\n return element;\n}\n\nfunction getOrCreateElement(): HTMLDivElement {\n const existing = document.getElementById(DIV_ID) as HTMLDivElement | null;\n if (existing) {\n return existing;\n }\n return createElement();\n}\n\nexport function removeElement(): void {\n const element = document.getElementById(DIV_ID);\n if (element) {\n element.remove();\n }\n}\n\nexport function injectStyle(style: StyleObj, container?: string): void {\n const element = getOrCreateElement();\n Object.assign(element.style, style);\n\n let parent: Element | null = null;\n try {\n parent = document.querySelector(container ?? PARENT_SELECTOR);\n } catch {\n // invalid selector string — fall through to body fallback\n }\n\n if (!parent) {\n parent = document.querySelector(PARENT_SELECTOR);\n }\n\n if (parent && element.parentNode !== parent) {\n parent.append(element);\n }\n}\n","import './storybook-parameter-augmentation';\n\nimport type { DecoratorFunction, Renderer } from 'storybook/internal/types';\n\nimport { getStyle } from './getStyle';\nimport { StyleProps, ConfigProps } from './types';\nimport { presets, PresetName } from './presets';\nimport { injectStyle, removeElement } from './utils';\nimport {\n DEFAULT_COLOR,\n DEFAULT_LINE_HEIGHT,\n DEFAULT_OFFSET,\n DEFAULT_OPACITY,\n DEFAULT_Z_INDEX,\n} from './constants';\n\nexport type VRhythmParams = StyleProps & ConfigProps;\n\nconst DEFAULT_PARAMS: VRhythmParams = {\n hide: false,\n preset: '',\n container: '',\n color: DEFAULT_COLOR,\n lineHeight: DEFAULT_LINE_HEIGHT,\n offset: DEFAULT_OFFSET,\n opacity: DEFAULT_OPACITY,\n zIndex: DEFAULT_Z_INDEX,\n};\n\n/**\n * Storybook decorator that injects a vertical rhythm baseline grid overlay into stories.\n *\n * Register globally via the addon preset in `.storybook/main.ts` (recommended):\n * ```ts\n * export default { addons: ['storybook-vrhythm'] };\n * ```\n *\n * Or manually in `.storybook/preview.ts`:\n * ```ts\n * import { withVRhythm } from 'storybook-vrhythm';\n * export const decorators = [withVRhythm];\n * ```\n *\n * Control per story via `parameters.vrhythm`:\n * ```ts\n * export const MyStory = {\n * parameters: { vrhythm: { preset: 'material' } },\n * };\n * ```\n */\nexport const withVRhythm: DecoratorFunction<Renderer> = (storyFn, context) => {\n const raw = (context.parameters as { vrhythm?: VRhythmParams } | undefined)\n ?.vrhythm;\n const presetStyles =\n raw?.preset && raw.preset in presets\n ? presets[raw.preset as PresetName]\n : {};\n const params: VRhythmParams = {\n ...DEFAULT_PARAMS,\n ...presetStyles,\n ...raw,\n };\n\n const globalsVrhythm = (\n context.globals as { vrhythm?: string | boolean } | undefined\n )?.vrhythm;\n\n const globalPresetName =\n typeof globalsVrhythm === 'string' &&\n globalsVrhythm !== 'true' &&\n globalsVrhythm !== 'false' &&\n globalsVrhythm in presets\n ? (globalsVrhythm as PresetName)\n : null;\n\n const globalPresetStyles = globalPresetName ? presets[globalPresetName] : {};\n\n const isHidden =\n !!params.hide || globalsVrhythm === false || globalsVrhythm === 'false';\n\n if (isHidden) {\n removeElement();\n } else {\n const finalParams: VRhythmParams = { ...params, ...globalPresetStyles };\n const style = getStyle(finalParams);\n injectStyle(style, params.container || undefined);\n }\n\n return storyFn(context);\n};\n\nexport { presets } from './presets';\nexport type { PresetName } from './presets';\nexport type { StyleProps, ConfigProps } from './types';\n","import { definePreviewAddon } from 'storybook/internal/csf';\n\nimport { withVRhythm, type VRhythmParams } from './index';\n\nexport default definePreviewAddon<{\n parameters: { vrhythm?: VRhythmParams };\n globals: { vrhythm?: string | boolean };\n}>({\n decorators: [withVRhythm],\n globalTypes: {\n vrhythm: {\n description: 'Toggle vertical rhythm grid overlay',\n toolbar: {\n title: 'Show vertical rhythm',\n icon: 'grid',\n items: [\n { value: 'true', title: 'Default (story params)', icon: 'eye' },\n { value: 'false', title: 'Hide', icon: 'eyeclose' },\n { value: '4px', title: '4px baseline', icon: 'grid' },\n { value: '8px', title: '8px baseline', icon: 'grid' },\n { value: '16px', title: '16px baseline', icon: 'grid' },\n { value: '24px', title: '24px baseline', icon: 'grid' },\n { value: 'material', title: 'Material Design', icon: 'grid' },\n { value: 'tailwind', title: 'Tailwind CSS', icon: 'grid' },\n { value: 'bootstrap', title: 'Bootstrap', icon: 'grid' },\n ],\n dynamicTitle: true,\n },\n },\n },\n initialGlobals: {\n vrhythm: 'true',\n },\n});\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "storybook-vrhythm",
3
- "version": "0.2.0",
4
- "description": "Storybook decorator and preset addon for vertical rhythm baseline guides",
3
+ "version": "0.4.0",
4
+ "description": "Baseline grid overlay for Storybook — see your vertical rhythm while you build",
5
5
  "license": "MIT",
6
6
  "author": "jmlweb",
7
7
  "homepage": "https://github.com/jmlweb/storybook-vrhythm",
@@ -11,13 +11,18 @@
11
11
  },
12
12
  "keywords": [
13
13
  "storybook-addon",
14
- "style",
15
- "debug",
16
- "layout",
17
- "baseline",
18
- "vertical-rhythm",
19
14
  "storybook",
20
- "decorator"
15
+ "vertical-rhythm",
16
+ "baseline-grid",
17
+ "typography",
18
+ "layout",
19
+ "design-system",
20
+ "css-grid",
21
+ "decorator",
22
+ "debug",
23
+ "spacing",
24
+ "material-design",
25
+ "tailwind"
21
26
  ],
22
27
  "type": "module",
23
28
  "main": "./dist/index.js",
@@ -34,7 +39,10 @@
34
39
  "import": "./dist/preview.js",
35
40
  "default": "./dist/preview.js"
36
41
  },
37
- "./preset": "./dist/preset.js",
42
+ "./preset": {
43
+ "import": "./dist/preset.js",
44
+ "default": "./dist/preset.js"
45
+ },
38
46
  "./package.json": "./package.json"
39
47
  },
40
48
  "files": [
@@ -45,22 +53,30 @@
45
53
  "node": ">=20"
46
54
  },
47
55
  "peerDependencies": {
48
- "storybook": "^8.0.0 || ^9.0.0 || ^10.0.0"
56
+ "storybook": "^10.0.0"
49
57
  },
50
58
  "storybook": {
51
- "displayName": "Vertical rhythm",
59
+ "displayName": "Vertical Rhythm Grid",
60
+ "icon": "https://raw.githubusercontent.com/jmlweb/storybook-vrhythm/master/packages/storybook-vrhythm/icon.png",
52
61
  "supportedFrameworks": [
53
62
  "react",
54
63
  "vue",
55
64
  "angular",
56
65
  "web-components",
57
- "ember",
58
66
  "html",
59
- "svelte",
60
- "preact",
61
- "react-native"
67
+ "svelte"
62
68
  ]
63
69
  },
70
+ "scripts": {
71
+ "build": "tsup",
72
+ "dev": "tsup --watch",
73
+ "test": "vitest run",
74
+ "test:watch": "vitest",
75
+ "test:coverage": "vitest run --coverage",
76
+ "typecheck": "tsc --noEmit",
77
+ "format": "prettier --write 'src/**/*.ts' 'test/**/*.ts'",
78
+ "format:check": "prettier --check 'src/**/*.ts' 'test/**/*.ts'"
79
+ },
64
80
  "prettier": {
65
81
  "printWidth": 80,
66
82
  "semi": true,
@@ -68,24 +84,13 @@
68
84
  "trailingComma": "es5"
69
85
  },
70
86
  "devDependencies": {
71
- "@storybook/types": "^8.6.14",
72
87
  "@types/node": "^25.5.0",
73
88
  "@vitest/coverage-v8": "^4.1.2",
74
89
  "jsdom": "^29.0.1",
75
90
  "prettier": "^3.5.3",
76
- "storybook": "^8.6.18",
91
+ "storybook": "^10.0.0",
77
92
  "tsup": "^8.5.1",
78
93
  "typescript": "^5.9.3",
79
94
  "vitest": "^4.1.2"
80
- },
81
- "scripts": {
82
- "build": "tsup",
83
- "dev": "tsup --watch",
84
- "test": "vitest run",
85
- "test:watch": "vitest",
86
- "test:coverage": "vitest run --coverage",
87
- "lint": "tsc --noEmit",
88
- "format": "prettier --write 'src/**/*.ts' 'test/**/*.ts'",
89
- "format:check": "prettier --check 'src/**/*.ts' 'test/**/*.ts'"
90
95
  }
91
- }
96
+ }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2019 José Manuel Lucas
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.