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 +113 -86
- package/dist/index.d.ts +95 -3
- package/dist/index.js +67 -22
- package/dist/index.js.map +1 -1
- package/dist/preset.js +0 -10
- package/dist/preset.js.map +1 -1
- package/dist/preview.d.ts +12 -3
- package/dist/preview.js +97 -25
- package/dist/preview.js.map +1 -1
- package/package.json +33 -28
- package/LICENSE +0 -21
package/README.md
CHANGED
|
@@ -1,149 +1,176 @@
|
|
|
1
|
-
#
|
|
1
|
+
# storybook-vrhythm
|
|
2
2
|
|
|
3
|
-
[![npm
|
|
3
|
+
[![npm version][npm-badge]][npm]
|
|
4
4
|
[![License: MIT][license-badge]][license]
|
|
5
5
|
[](https://bundlephobia.com/package/storybook-vrhythm)
|
|
6
|
+
[](https://www.npmjs.org/package/storybook-vrhythm)
|
|
6
7
|
|
|
7
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
12
|
+
## Features
|
|
13
13
|
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
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
|
-
##
|
|
23
|
+
## Requirements
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
- Node.js 20+
|
|
26
|
+
- Storybook 10+
|
|
24
27
|
|
|
25
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
}
|
|
41
|
+
};
|
|
65
42
|
|
|
66
43
|
export default config;
|
|
67
44
|
```
|
|
68
45
|
|
|
69
|
-
|
|
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(
|
|
75
|
-
lineHeight: '
|
|
76
|
-
offset: 0,
|
|
57
|
+
color: 'rgba(99, 102, 241, 0.2)',
|
|
58
|
+
lineHeight: '8px',
|
|
77
59
|
},
|
|
78
60
|
};
|
|
79
61
|
```
|
|
80
62
|
|
|
81
|
-
###
|
|
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
|
-
|
|
66
|
+
export const Compact = {
|
|
67
|
+
parameters: {
|
|
68
|
+
vrhythm: { lineHeight: '4px', color: 'rgba(244, 67, 54, 0.15)' },
|
|
69
|
+
},
|
|
70
|
+
};
|
|
87
71
|
|
|
88
|
-
export const
|
|
72
|
+
export const NoGrid = {
|
|
73
|
+
parameters: {
|
|
74
|
+
vrhythm: { hide: true },
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
```
|
|
89
78
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
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
|
-
|
|
101
|
+
### Column grid
|
|
102
|
+
|
|
103
|
+
Add vertical column lines on top of the horizontal baseline:
|
|
102
104
|
|
|
103
105
|
```typescript
|
|
104
|
-
export const
|
|
106
|
+
export const ColumnGrid = {
|
|
105
107
|
parameters: {
|
|
106
108
|
vrhythm: {
|
|
107
|
-
|
|
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
|
-
|
|
118
|
+
### Manual decorator
|
|
114
119
|
|
|
115
|
-
|
|
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
|
-
|
|
122
|
+
```typescript
|
|
123
|
+
import { withVRhythm } from 'storybook-vrhythm';
|
|
123
124
|
|
|
124
|
-
|
|
125
|
+
export const decorators = [withVRhythm];
|
|
126
|
+
```
|
|
125
127
|
|
|
126
|
-
##
|
|
128
|
+
## Options
|
|
127
129
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
|
|
159
|
+
Later sources override earlier ones. The story-level `hide` param takes precedence over the toolbar toggle.
|
|
137
160
|
|
|
138
|
-
|
|
161
|
+
## Why vertical rhythm?
|
|
139
162
|
|
|
140
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
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 '
|
|
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
|
-
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
...
|
|
102
|
+
...presetStyles,
|
|
103
|
+
...raw
|
|
64
104
|
};
|
|
65
|
-
|
|
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
|
|
69
|
-
|
|
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
|
package/dist/preset.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/preview.d.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
import
|
|
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
|
|
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 {
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
...
|
|
106
|
+
...presetStyles,
|
|
107
|
+
...raw
|
|
64
108
|
};
|
|
65
|
-
|
|
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
|
|
69
|
-
|
|
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
|
|
76
|
-
decorators: [withVRhythm]
|
|
77
|
-
|
|
78
|
-
|
|
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
|
package/dist/preview.js.map
CHANGED
|
@@ -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.
|
|
4
|
-
"description": "
|
|
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
|
-
"
|
|
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":
|
|
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": "^
|
|
56
|
+
"storybook": "^10.0.0"
|
|
49
57
|
},
|
|
50
58
|
"storybook": {
|
|
51
|
-
"displayName": "Vertical
|
|
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": "^
|
|
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.
|