storybook-vrhythm 0.3.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 ADDED
@@ -0,0 +1,178 @@
1
+ # storybook-vrhythm
2
+
3
+ [![npm version][npm-badge]][npm]
4
+ [![License: MIT][license-badge]][license]
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)
7
+
8
+ > Baseline grid overlay for Storybook. See your vertical rhythm while you build.
9
+
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
+
12
+ ## Features
13
+
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
22
+
23
+ ## Requirements
24
+
25
+ - Node.js 20+
26
+ - Storybook 10+
27
+
28
+ ## Quick start
29
+
30
+ ```bash
31
+ pnpm add -D storybook-vrhythm
32
+ # or: npm install --save-dev storybook-vrhythm
33
+ # or: yarn add -D storybook-vrhythm
34
+ ```
35
+
36
+ Add to `.storybook/main.ts`:
37
+
38
+ ```typescript
39
+ const config = {
40
+ addons: ['storybook-vrhythm'],
41
+ };
42
+
43
+ export default config;
44
+ ```
45
+
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`:
53
+
54
+ ```typescript
55
+ export const parameters = {
56
+ vrhythm: {
57
+ color: 'rgba(99, 102, 241, 0.2)',
58
+ lineHeight: '8px',
59
+ },
60
+ };
61
+ ```
62
+
63
+ ### Per-story overrides
64
+
65
+ ```typescript
66
+ export const Compact = {
67
+ parameters: {
68
+ vrhythm: { lineHeight: '4px', color: 'rgba(244, 67, 54, 0.15)' },
69
+ },
70
+ };
71
+
72
+ export const NoGrid = {
73
+ parameters: {
74
+ vrhythm: { hide: true },
75
+ },
76
+ };
77
+ ```
78
+
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' },
87
+ },
88
+ };
89
+ ```
90
+
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
+
101
+ ### Column grid
102
+
103
+ Add vertical column lines on top of the horizontal baseline:
104
+
105
+ ```typescript
106
+ export const ColumnGrid = {
107
+ parameters: {
108
+ vrhythm: {
109
+ lineHeight: '8px',
110
+ columnWidth: '80px',
111
+ gutterWidth: '16px',
112
+ columnColor: 'rgba(99, 102, 241, 0.1)',
113
+ },
114
+ },
115
+ };
116
+ ```
117
+
118
+ ### Manual decorator
119
+
120
+ If you prefer to opt out of the addon preset:
121
+
122
+ ```typescript
123
+ import { withVRhythm } from 'storybook-vrhythm';
124
+
125
+ export const decorators = [withVRhythm];
126
+ ```
127
+
128
+ ## Options
129
+
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
157
+ ```
158
+
159
+ Later sources override earlier ones. The story-level `hide` param takes precedence over the toolbar toggle.
160
+
161
+ ## Why vertical rhythm?
162
+
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.
164
+
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.
170
+
171
+ ## License
172
+
173
+ [MIT](https://github.com/jmlweb/storybook-vrhythm/blob/master/LICENSE)
174
+
175
+ [npm-badge]: https://img.shields.io/npm/v/storybook-vrhythm.svg
176
+ [npm]: https://www.npmjs.org/package/storybook-vrhythm
177
+ [license-badge]: https://img.shields.io/badge/license-MIT-blue.svg
178
+ [license]: https://github.com/jmlweb/storybook-vrhythm/blob/master/LICENSE
package/dist/index.d.ts CHANGED
@@ -1,17 +1,36 @@
1
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` */
7
13
  opacity?: number;
14
+ /** Stack order of the overlay. Default: `9999` */
8
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'`). */
9
19
  columnWidth?: string | number;
20
+ /** CSS color for vertical column lines. Falls back to `color` when omitted. */
10
21
  columnColor?: string;
22
+ /** Gutter width between columns. Requires `columnWidth` to be set. */
23
+ gutterWidth?: string | number;
11
24
  }
12
25
  interface ConfigProps {
26
+ /** When `true`, hides the overlay for this story regardless of the toolbar toggle. */
13
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
+ */
14
32
  preset?: string;
33
+ /** CSS selector for the overlay's parent element. Defaults to `body`. */
15
34
  container?: string;
16
35
  }
17
36
 
@@ -23,7 +42,8 @@ declare module 'storybook/internal/types' {
23
42
  }
24
43
  declare module 'storybook/internal/csf' {
25
44
  interface Globals {
26
- /** Toolbar toggle for the vertical rhythm overlay (`'true'` | `'false'` or boolean). */
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. */
27
47
  vrhythm?: string | boolean;
28
48
  }
29
49
  }
@@ -61,6 +81,27 @@ declare const presets: {
61
81
  type PresetName = keyof typeof presets;
62
82
 
63
83
  type VRhythmParams = StyleProps & ConfigProps;
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
+ */
64
105
  declare const withVRhythm: DecoratorFunction<Renderer>;
65
106
 
66
107
  export { type ConfigProps, type PresetName, type StyleProps, type VRhythmParams, presets, withVRhythm };
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
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;
5
6
  var DEFAULT_OPACITY = 1;
6
7
  var DEFAULT_Z_INDEX = 9999;
@@ -11,19 +12,23 @@ var DIV_ID = "storybook-rhythm";
11
12
  var getStyle = ({
12
13
  color = DEFAULT_COLOR,
13
14
  lineHeight = DEFAULT_LINE_HEIGHT,
15
+ lineWidth = DEFAULT_LINE_WIDTH,
14
16
  offset = DEFAULT_OFFSET,
15
17
  opacity = DEFAULT_OPACITY,
16
18
  zIndex = DEFAULT_Z_INDEX,
19
+ maxWidth,
17
20
  columnWidth,
18
- columnColor
21
+ columnColor,
22
+ gutterWidth
19
23
  }) => {
20
- const horizontal = `linear-gradient(${color} 1px, transparent 1px) left top / 1px ${lineHeight}`;
21
- const background = columnWidth != null ? `${horizontal}, linear-gradient(90deg, ${columnColor ?? color} 1px, transparent 1px) left top / ${columnWidth} 1px` : horizontal;
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 };
22
28
  return {
23
29
  position: "absolute",
24
30
  top: offset,
25
- left: 0,
26
- right: 0,
31
+ ...positioning,
27
32
  bottom: 0,
28
33
  background,
29
34
  pointerEvents: "none",
@@ -65,11 +70,16 @@ function removeElement() {
65
70
  function injectStyle(style, container) {
66
71
  const element = getOrCreateElement();
67
72
  Object.assign(element.style, style);
68
- if (!element.parentNode) {
69
- const parent = document.querySelector(container ?? PARENT_SELECTOR);
70
- if (parent) {
71
- parent.append(element);
72
- }
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);
73
83
  }
74
84
  }
75
85
 
@@ -93,11 +103,14 @@ var withVRhythm = (storyFn, context) => {
93
103
  ...raw
94
104
  };
95
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] : {};
96
108
  const isHidden = !!params.hide || globalsVrhythm === false || globalsVrhythm === "false";
97
109
  if (isHidden) {
98
110
  removeElement();
99
111
  } else {
100
- const style = getStyle(params);
112
+ const finalParams = { ...params, ...globalPresetStyles };
113
+ const style = getStyle(finalParams);
101
114
  injectStyle(style, params.container || void 0);
102
115
  }
103
116
  return storyFn(context);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/getStyle.ts","../src/presets.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,CAAA;AACxB,IAAM,eAAA,GAAkB,IAAA;AACxB,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,cAAA;AAAA,EACT,OAAA,GAAU,eAAA;AAAA,EACV,MAAA,GAAS,eAAA;AAAA,EACT,WAAA;AAAA,EACA;AACF,CAAA,KAA4B;AAC1B,EAAA,MAAM,UAAA,GAAa,CAAA,gBAAA,EAAmB,KAAK,CAAA,sCAAA,EAAyC,UAAU,CAAA,CAAA;AAE9F,EAAA,MAAM,UAAA,GACJ,WAAA,IAAe,IAAA,GACX,CAAA,EAAG,UAAU,4BAA4B,WAAA,IAAe,KAAK,CAAA,kCAAA,EAAqC,WAAW,CAAA,IAAA,CAAA,GAC7G,UAAA;AAEN,EAAA,OAAO;AAAA,IACL,QAAA,EAAU,UAAA;AAAA,IACV,GAAA,EAAK,MAAA;AAAA,IACL,IAAA,EAAM,CAAA;AAAA,IACN,KAAA,EAAO,CAAA;AAAA,IACP,MAAA,EAAQ,CAAA;AAAA,IACR,UAAA;AAAA,IACA,aAAA,EAAe,MAAA;AAAA,IACf,OAAA;AAAA,IACA;AAAA,GACF;AACF,CAAA;;;AClCO,IAAM,OAAA,GAAU;AAAA,EACrB,KAAA,EAAO,EAAE,UAAA,EAAY,KAAA,EAAO,OAAO,yBAAA,EAA0B;AAAA,EAC7D,KAAA,EAAO,EAAE,UAAA,EAAY,KAAA,EAAO,OAAO,wBAAA,EAAyB;AAAA,EAC5D,MAAA,EAAQ,EAAE,UAAA,EAAY,MAAA,EAAQ,OAAO,0BAAA,EAA2B;AAAA,EAChE,MAAA,EAAQ,EAAE,UAAA,EAAY,MAAA,EAAQ,OAAO,0BAAA,EAA2B;AAAA,EAChE,QAAA,EAAU,EAAE,UAAA,EAAY,KAAA,EAAO,OAAO,yBAAA,EAA0B;AAAA,EAChE,QAAA,EAAU,EAAE,UAAA,EAAY,KAAA,EAAO,OAAO,0BAAA,EAA2B;AAAA,EACjE,SAAA,EAAW,EAAE,UAAA,EAAY,KAAA,EAAO,OAAO,yBAAA;AACzC;;;ACPA,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,WAAA,CAAY,OAAiB,SAAA,EAA0B;AACrE,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,SAAA,IAAa,eAAe,CAAA;AAClE,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,MAAA,CAAO,OAAO,OAAO,CAAA;AAAA,IACvB;AAAA,EACF;AACF;;;AChBA,IAAM,cAAA,GAAgC;AAAA,EACpC,IAAA,EAAM,KAAA;AAAA,EACN,MAAA,EAAQ,EAAA;AAAA,EACR,SAAA,EAAW,EAAA;AAAA,EACX,KAAA,EAAO,aAAA;AAAA,EACP,UAAA,EAAY,mBAAA;AAAA,EACZ,MAAA,EAAQ,cAAA;AAAA,EACR,OAAA,EAAS,eAAA;AAAA,EACT,MAAA,EAAQ;AACV,CAAA;AAEO,IAAM,WAAA,GAA2C,CAAC,OAAA,EAAS,OAAA,KAAY;AAC5E,EAAA,MAAM,GAAA,GAAO,QAAQ,UAAA,EACjB,OAAA;AACJ,EAAA,MAAM,YAAA,GACJ,GAAA,EAAK,MAAA,IAAU,GAAA,CAAI,MAAA,IAAU,UACzB,OAAA,CAAQ,GAAA,CAAI,MAAoB,CAAA,GAChC,EAAC;AACP,EAAA,MAAM,MAAA,GAAwB;AAAA,IAC5B,GAAG,cAAA;AAAA,IACH,GAAG,YAAA;AAAA,IACH,GAAG;AAAA,GACL;AAEA,EAAA,MAAM,cAAA,GACJ,QAAQ,OAAA,EACP,OAAA;AACH,EAAA,MAAM,WACJ,CAAC,CAAC,OAAO,IAAA,IAAQ,cAAA,KAAmB,SAAS,cAAA,KAAmB,OAAA;AAElE,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,aAAA,EAAc;AAAA,EAChB,CAAA,MAAO;AACL,IAAA,MAAM,KAAA,GAAQ,SAAS,MAAM,CAAA;AAC7B,IAAA,WAAA,CAAY,KAAA,EAAO,MAAA,CAAO,SAAA,IAAa,MAAS,CAAA;AAAA,EAClD;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 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_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 offset = DEFAULT_OFFSET,\n opacity = DEFAULT_OPACITY,\n zIndex = DEFAULT_Z_INDEX,\n columnWidth,\n columnColor,\n}: StyleProps): StyleObj => {\n const horizontal = `linear-gradient(${color} 1px, transparent 1px) left top / 1px ${lineHeight}`;\n\n const background =\n columnWidth != null\n ? `${horizontal}, linear-gradient(90deg, ${columnColor ?? color} 1px, transparent 1px) left top / ${columnWidth} 1px`\n : horizontal;\n\n return {\n position: 'absolute',\n top: offset,\n left: 0,\n right: 0,\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 if (!element.parentNode) {\n const parent = document.querySelector(container ?? PARENT_SELECTOR);\n if (parent) {\n parent.append(element);\n }\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\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 const isHidden =\n !!params.hide || globalsVrhythm === false || globalsVrhythm === 'false';\n\n if (isHidden) {\n removeElement();\n } else {\n const style = getStyle(params);\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"]}
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/preview.js CHANGED
@@ -5,6 +5,7 @@ import { definePreviewAddon } from 'storybook/internal/csf';
5
5
  // src/constants.ts
6
6
  var DEFAULT_COLOR = "rgb(204, 204, 204)";
7
7
  var DEFAULT_LINE_HEIGHT = "16px";
8
+ var DEFAULT_LINE_WIDTH = "1px";
8
9
  var DEFAULT_OFFSET = 0;
9
10
  var DEFAULT_OPACITY = 1;
10
11
  var DEFAULT_Z_INDEX = 9999;
@@ -15,19 +16,23 @@ var DIV_ID = "storybook-rhythm";
15
16
  var getStyle = ({
16
17
  color = DEFAULT_COLOR,
17
18
  lineHeight = DEFAULT_LINE_HEIGHT,
19
+ lineWidth = DEFAULT_LINE_WIDTH,
18
20
  offset = DEFAULT_OFFSET,
19
21
  opacity = DEFAULT_OPACITY,
20
22
  zIndex = DEFAULT_Z_INDEX,
23
+ maxWidth,
21
24
  columnWidth,
22
- columnColor
25
+ columnColor,
26
+ gutterWidth
23
27
  }) => {
24
- const horizontal = `linear-gradient(${color} 1px, transparent 1px) left top / 1px ${lineHeight}`;
25
- const background = columnWidth != null ? `${horizontal}, linear-gradient(90deg, ${columnColor ?? color} 1px, transparent 1px) left top / ${columnWidth} 1px` : horizontal;
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 };
26
32
  return {
27
33
  position: "absolute",
28
34
  top: offset,
29
- left: 0,
30
- right: 0,
35
+ ...positioning,
31
36
  bottom: 0,
32
37
  background,
33
38
  pointerEvents: "none",
@@ -69,11 +74,16 @@ function removeElement() {
69
74
  function injectStyle(style, container) {
70
75
  const element = getOrCreateElement();
71
76
  Object.assign(element.style, style);
72
- if (!element.parentNode) {
73
- const parent = document.querySelector(container ?? PARENT_SELECTOR);
74
- if (parent) {
75
- parent.append(element);
76
- }
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);
77
87
  }
78
88
  }
79
89
 
@@ -97,11 +107,14 @@ var withVRhythm = (storyFn, context) => {
97
107
  ...raw
98
108
  };
99
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] : {};
100
112
  const isHidden = !!params.hide || globalsVrhythm === false || globalsVrhythm === "false";
101
113
  if (isHidden) {
102
114
  removeElement();
103
115
  } else {
104
- const style = getStyle(params);
116
+ const finalParams = { ...params, ...globalPresetStyles };
117
+ const style = getStyle(finalParams);
105
118
  injectStyle(style, params.container || void 0);
106
119
  }
107
120
  return storyFn(context);
@@ -114,11 +127,18 @@ var preview_default = definePreviewAddon({
114
127
  vrhythm: {
115
128
  description: "Toggle vertical rhythm grid overlay",
116
129
  toolbar: {
117
- title: "V-Rhythm",
130
+ title: "Show vertical rhythm",
118
131
  icon: "grid",
119
132
  items: [
120
- { value: "true", title: "Show grid", icon: "eye" },
121
- { value: "false", title: "Hide grid", icon: "eyeclose" }
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" }
122
142
  ],
123
143
  dynamicTitle: true
124
144
  }
@@ -1 +1 @@
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_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_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 offset = DEFAULT_OFFSET,\n opacity = DEFAULT_OPACITY,\n zIndex = DEFAULT_Z_INDEX,\n columnWidth,\n columnColor,\n}: StyleProps): StyleObj => {\n const horizontal = `linear-gradient(${color} 1px, transparent 1px) left top / 1px ${lineHeight}`;\n\n const background =\n columnWidth != null\n ? `${horizontal}, linear-gradient(90deg, ${columnColor ?? color} 1px, transparent 1px) left top / ${columnWidth} 1px`\n : horizontal;\n\n return {\n position: 'absolute',\n top: offset,\n left: 0,\n right: 0,\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 if (!element.parentNode) {\n const parent = document.querySelector(container ?? PARENT_SELECTOR);\n if (parent) {\n parent.append(element);\n }\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\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 const isHidden =\n !!params.hide || globalsVrhythm === false || globalsVrhythm === 'false';\n\n if (isHidden) {\n removeElement();\n } else {\n const style = getStyle(params);\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: 'V-Rhythm',\n icon: 'grid',\n items: [\n { value: 'true', title: 'Show grid', icon: 'eye' },\n { value: 'false', title: 'Hide grid', icon: 'eyeclose' },\n ],\n dynamicTitle: true,\n },\n },\n },\n initialGlobals: {\n vrhythm: 'true',\n },\n});\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,6 +1,6 @@
1
1
  {
2
2
  "name": "storybook-vrhythm",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Baseline grid overlay for Storybook — see your vertical rhythm while you build",
5
5
  "license": "MIT",
6
6
  "author": "jmlweb",
@@ -53,16 +53,17 @@
53
53
  "node": ">=20"
54
54
  },
55
55
  "peerDependencies": {
56
- "storybook": "^10.0.0 || ^11.0.0"
56
+ "storybook": "^10.0.0"
57
57
  },
58
58
  "storybook": {
59
59
  "displayName": "Vertical Rhythm Grid",
60
+ "icon": "https://raw.githubusercontent.com/jmlweb/storybook-vrhythm/master/packages/storybook-vrhythm/icon.png",
60
61
  "supportedFrameworks": [
61
62
  "react",
62
63
  "vue",
63
64
  "angular",
64
65
  "web-components",
65
- "html-vite",
66
+ "html",
66
67
  "svelte"
67
68
  ]
68
69
  },
@@ -72,7 +73,7 @@
72
73
  "test": "vitest run",
73
74
  "test:watch": "vitest",
74
75
  "test:coverage": "vitest run --coverage",
75
- "lint": "tsc --noEmit",
76
+ "typecheck": "tsc --noEmit",
76
77
  "format": "prettier --write 'src/**/*.ts' 'test/**/*.ts'",
77
78
  "format:check": "prettier --check 'src/**/*.ts' 'test/**/*.ts'"
78
79
  },