@jlunamena/design-system 1.0.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 +95 -0
- package/dist/index.d.mts +127 -0
- package/dist/index.d.ts +127 -0
- package/dist/index.js +287 -0
- package/dist/index.mjs +280 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Design System Contract
|
|
2
|
+
|
|
3
|
+
Short and practical agreement before building anything.
|
|
4
|
+
|
|
5
|
+
## 1) Purpose
|
|
6
|
+
- This design system provides reusable presentational components for the Expo app.
|
|
7
|
+
- It owns UI, visual states, tokens, and component consistency.
|
|
8
|
+
- The app owns data, navigation, API calls, and business logic.
|
|
9
|
+
|
|
10
|
+
## 2) What It Exports
|
|
11
|
+
Tokens:
|
|
12
|
+
- colors, spacing, typography, radius, shadows
|
|
13
|
+
|
|
14
|
+
Theme:
|
|
15
|
+
- ThemeProvider, useTheme
|
|
16
|
+
|
|
17
|
+
Components:
|
|
18
|
+
- Button, Text, Input, Card, Icon, Badge, Avatar, Divider
|
|
19
|
+
|
|
20
|
+
Layout:
|
|
21
|
+
- Box, Stack, Screen, Container
|
|
22
|
+
|
|
23
|
+
## 3) What It Does NOT Export
|
|
24
|
+
- Screens
|
|
25
|
+
- Navigation
|
|
26
|
+
- API logic
|
|
27
|
+
- Auth logic
|
|
28
|
+
- Workout logic
|
|
29
|
+
- Database logic
|
|
30
|
+
- Business rules
|
|
31
|
+
|
|
32
|
+
## 4) Component Done Checklist
|
|
33
|
+
- Has variants
|
|
34
|
+
- Has sizes
|
|
35
|
+
- Has states
|
|
36
|
+
- Has Storybook examples
|
|
37
|
+
- Has documented props
|
|
38
|
+
- Works in Expo app
|
|
39
|
+
- Reviewed visually by you
|
|
40
|
+
- Reviewed technically by him
|
|
41
|
+
|
|
42
|
+
## 5) First Components to Build
|
|
43
|
+
- Button
|
|
44
|
+
- Text
|
|
45
|
+
- Input
|
|
46
|
+
- Card
|
|
47
|
+
- Screen
|
|
48
|
+
- Box / Stack
|
|
49
|
+
|
|
50
|
+
## 6) Repo Workflow
|
|
51
|
+
Design system repo:
|
|
52
|
+
- Build component
|
|
53
|
+
- Document in Storybook
|
|
54
|
+
- Release/update package
|
|
55
|
+
|
|
56
|
+
Expo app repo:
|
|
57
|
+
- Install/update design system
|
|
58
|
+
- Connect real actions/data
|
|
59
|
+
- Test in app
|
|
60
|
+
|
|
61
|
+
## 7) Repo Structure Logic
|
|
62
|
+
- [src/tokens](src/tokens) holds design tokens only (no component logic).
|
|
63
|
+
- [src/theme](src/theme) exposes theme utilities and providers.
|
|
64
|
+
- [src/components](src/components) is one folder per component (no app screens).
|
|
65
|
+
- [src/layout](src/layout) holds layout primitives only.
|
|
66
|
+
- [src/stories/foundations](src/stories/foundations) documents tokens and foundations.
|
|
67
|
+
- [src/stories/components](src/stories/components) documents UI components.
|
|
68
|
+
- [src/stories/layout](src/stories/layout) documents layout primitives.
|
|
69
|
+
- [src/stories/examples](src/stories/examples) is for small composed examples.
|
|
70
|
+
|
|
71
|
+
## 8) Running Storybook
|
|
72
|
+
- On device: `npm run storybook:ios` or `npm run storybook:android`
|
|
73
|
+
- On web: `npm run storybook:web`
|
|
74
|
+
|
|
75
|
+
## 8.1) Storybook Notes (Current Setup)
|
|
76
|
+
- Stories are loaded from `storybook/storybook.requires.ts` via explicit `require` entries.
|
|
77
|
+
- The Intro story is a simple menu to jump to core stories on device.
|
|
78
|
+
- If you add new stories, update the require list so they show up.
|
|
79
|
+
|
|
80
|
+
## 9) Running the App (without Storybook)
|
|
81
|
+
- `npm run ios`
|
|
82
|
+
- `npm run android`
|
|
83
|
+
- `npm run web`
|
|
84
|
+
|
|
85
|
+
## 10) Public Exports (Auto-Generated)
|
|
86
|
+
Exports are generated into `src/index.ts` so new components can be added without
|
|
87
|
+
manually editing a root barrel.
|
|
88
|
+
|
|
89
|
+
How it works:
|
|
90
|
+
- Any folder in `src/components`, `src/layout`, or `src/theme` that has its own
|
|
91
|
+
`index.ts` (or `index.tsx`) will be exported automatically.
|
|
92
|
+
- `src/tokens/index.ts` is always exported.
|
|
93
|
+
|
|
94
|
+
Commands:
|
|
95
|
+
- `npm run generate:exports` regenerates `src/index.ts`.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
declare const colors: {
|
|
4
|
+
readonly primary: "#FDC026";
|
|
5
|
+
readonly accent: "#6AABDE";
|
|
6
|
+
readonly bodyDiagram: {
|
|
7
|
+
readonly muscleFill: "#FFBF00";
|
|
8
|
+
readonly muscleStroke: "#FF0090";
|
|
9
|
+
readonly muscleStrokeWidth: 2;
|
|
10
|
+
readonly muscleOpacity: 1;
|
|
11
|
+
};
|
|
12
|
+
readonly background: {
|
|
13
|
+
readonly default: "#161C26";
|
|
14
|
+
readonly muted: "#1C2434";
|
|
15
|
+
readonly highlight: "#383040";
|
|
16
|
+
readonly depth: "#08080A";
|
|
17
|
+
};
|
|
18
|
+
readonly text: {
|
|
19
|
+
readonly primary: "#E8E8E8";
|
|
20
|
+
readonly secondary: "#9B9B9B";
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
type Colors = typeof colors;
|
|
24
|
+
|
|
25
|
+
declare const spacing: {
|
|
26
|
+
readonly big: 32;
|
|
27
|
+
readonly default: 24;
|
|
28
|
+
readonly small: 12;
|
|
29
|
+
readonly textHorizontal: 4;
|
|
30
|
+
readonly textVertical: 0;
|
|
31
|
+
};
|
|
32
|
+
type Spacing = typeof spacing;
|
|
33
|
+
|
|
34
|
+
declare const radius: {
|
|
35
|
+
readonly button: 4;
|
|
36
|
+
readonly card: 8;
|
|
37
|
+
readonly input: 4;
|
|
38
|
+
readonly full: 9999;
|
|
39
|
+
};
|
|
40
|
+
type Radius = typeof radius;
|
|
41
|
+
|
|
42
|
+
declare const typography: {
|
|
43
|
+
readonly size: {
|
|
44
|
+
readonly xs: 11;
|
|
45
|
+
readonly sm: 13;
|
|
46
|
+
readonly base: 15;
|
|
47
|
+
readonly md: 17;
|
|
48
|
+
readonly lg: 20;
|
|
49
|
+
readonly xl: 24;
|
|
50
|
+
readonly '2xl': 30;
|
|
51
|
+
readonly '3xl': 36;
|
|
52
|
+
};
|
|
53
|
+
readonly weight: {
|
|
54
|
+
readonly regular: "400";
|
|
55
|
+
readonly medium: "500";
|
|
56
|
+
readonly semibold: "600";
|
|
57
|
+
readonly bold: "700";
|
|
58
|
+
};
|
|
59
|
+
readonly lineHeight: {
|
|
60
|
+
readonly tight: 1.2;
|
|
61
|
+
readonly normal: 1.5;
|
|
62
|
+
readonly relaxed: 1.75;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
type Typography = typeof typography;
|
|
66
|
+
|
|
67
|
+
declare const shadows: {
|
|
68
|
+
readonly sm: {
|
|
69
|
+
readonly shadowColor: "#08080A";
|
|
70
|
+
readonly shadowOffset: {
|
|
71
|
+
readonly width: 0;
|
|
72
|
+
readonly height: 1;
|
|
73
|
+
};
|
|
74
|
+
readonly shadowOpacity: 0.4;
|
|
75
|
+
readonly shadowRadius: 2;
|
|
76
|
+
readonly elevation: 2;
|
|
77
|
+
};
|
|
78
|
+
readonly md: {
|
|
79
|
+
readonly shadowColor: "#08080A";
|
|
80
|
+
readonly shadowOffset: {
|
|
81
|
+
readonly width: 0;
|
|
82
|
+
readonly height: 4;
|
|
83
|
+
};
|
|
84
|
+
readonly shadowOpacity: 0.5;
|
|
85
|
+
readonly shadowRadius: 8;
|
|
86
|
+
readonly elevation: 4;
|
|
87
|
+
};
|
|
88
|
+
readonly lg: {
|
|
89
|
+
readonly shadowColor: "#08080A";
|
|
90
|
+
readonly shadowOffset: {
|
|
91
|
+
readonly width: 0;
|
|
92
|
+
readonly height: 8;
|
|
93
|
+
};
|
|
94
|
+
readonly shadowOpacity: 0.6;
|
|
95
|
+
readonly shadowRadius: 16;
|
|
96
|
+
readonly elevation: 8;
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
type Shadows = typeof shadows;
|
|
100
|
+
|
|
101
|
+
type BodyDiagramView = 'front' | 'back';
|
|
102
|
+
type BodyDiagramPalette = {
|
|
103
|
+
muscleFill?: string;
|
|
104
|
+
muscleStroke?: string;
|
|
105
|
+
muscleStrokeWidth?: number;
|
|
106
|
+
muscleOpacity?: number;
|
|
107
|
+
};
|
|
108
|
+
type BodyDiagramOverlayStyle = {
|
|
109
|
+
blur?: number;
|
|
110
|
+
blendMode?: string;
|
|
111
|
+
};
|
|
112
|
+
type BodyDiagramIntensity = 'off' | 'low' | 'medium' | 'high';
|
|
113
|
+
type BodyDiagramProps = {
|
|
114
|
+
view: BodyDiagramView;
|
|
115
|
+
svgMarkupByView: Record<BodyDiagramView, string>;
|
|
116
|
+
baseImageByView?: Partial<Record<BodyDiagramView, string>>;
|
|
117
|
+
selectedMuscles: string[];
|
|
118
|
+
onSelectedChange: (selected: string[]) => void;
|
|
119
|
+
debugForceVisible?: boolean;
|
|
120
|
+
interactionMode?: 'auto' | 'editable' | 'readonly';
|
|
121
|
+
palette?: BodyDiagramPalette;
|
|
122
|
+
overlayStyle?: BodyDiagramOverlayStyle;
|
|
123
|
+
intensityByMuscle?: Record<string, BodyDiagramIntensity>;
|
|
124
|
+
};
|
|
125
|
+
declare const BodyDiagram: ({ view, svgMarkupByView, baseImageByView, selectedMuscles, onSelectedChange, debugForceVisible, interactionMode, palette, overlayStyle, intensityByMuscle, }: BodyDiagramProps) => react_jsx_runtime.JSX.Element;
|
|
126
|
+
|
|
127
|
+
export { BodyDiagram, type BodyDiagramIntensity, type BodyDiagramOverlayStyle, type BodyDiagramPalette, type BodyDiagramProps, type BodyDiagramView, type Colors, type Radius, type Shadows, type Spacing, type Typography, colors, radius, shadows, spacing, typography };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
declare const colors: {
|
|
4
|
+
readonly primary: "#FDC026";
|
|
5
|
+
readonly accent: "#6AABDE";
|
|
6
|
+
readonly bodyDiagram: {
|
|
7
|
+
readonly muscleFill: "#FFBF00";
|
|
8
|
+
readonly muscleStroke: "#FF0090";
|
|
9
|
+
readonly muscleStrokeWidth: 2;
|
|
10
|
+
readonly muscleOpacity: 1;
|
|
11
|
+
};
|
|
12
|
+
readonly background: {
|
|
13
|
+
readonly default: "#161C26";
|
|
14
|
+
readonly muted: "#1C2434";
|
|
15
|
+
readonly highlight: "#383040";
|
|
16
|
+
readonly depth: "#08080A";
|
|
17
|
+
};
|
|
18
|
+
readonly text: {
|
|
19
|
+
readonly primary: "#E8E8E8";
|
|
20
|
+
readonly secondary: "#9B9B9B";
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
type Colors = typeof colors;
|
|
24
|
+
|
|
25
|
+
declare const spacing: {
|
|
26
|
+
readonly big: 32;
|
|
27
|
+
readonly default: 24;
|
|
28
|
+
readonly small: 12;
|
|
29
|
+
readonly textHorizontal: 4;
|
|
30
|
+
readonly textVertical: 0;
|
|
31
|
+
};
|
|
32
|
+
type Spacing = typeof spacing;
|
|
33
|
+
|
|
34
|
+
declare const radius: {
|
|
35
|
+
readonly button: 4;
|
|
36
|
+
readonly card: 8;
|
|
37
|
+
readonly input: 4;
|
|
38
|
+
readonly full: 9999;
|
|
39
|
+
};
|
|
40
|
+
type Radius = typeof radius;
|
|
41
|
+
|
|
42
|
+
declare const typography: {
|
|
43
|
+
readonly size: {
|
|
44
|
+
readonly xs: 11;
|
|
45
|
+
readonly sm: 13;
|
|
46
|
+
readonly base: 15;
|
|
47
|
+
readonly md: 17;
|
|
48
|
+
readonly lg: 20;
|
|
49
|
+
readonly xl: 24;
|
|
50
|
+
readonly '2xl': 30;
|
|
51
|
+
readonly '3xl': 36;
|
|
52
|
+
};
|
|
53
|
+
readonly weight: {
|
|
54
|
+
readonly regular: "400";
|
|
55
|
+
readonly medium: "500";
|
|
56
|
+
readonly semibold: "600";
|
|
57
|
+
readonly bold: "700";
|
|
58
|
+
};
|
|
59
|
+
readonly lineHeight: {
|
|
60
|
+
readonly tight: 1.2;
|
|
61
|
+
readonly normal: 1.5;
|
|
62
|
+
readonly relaxed: 1.75;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
type Typography = typeof typography;
|
|
66
|
+
|
|
67
|
+
declare const shadows: {
|
|
68
|
+
readonly sm: {
|
|
69
|
+
readonly shadowColor: "#08080A";
|
|
70
|
+
readonly shadowOffset: {
|
|
71
|
+
readonly width: 0;
|
|
72
|
+
readonly height: 1;
|
|
73
|
+
};
|
|
74
|
+
readonly shadowOpacity: 0.4;
|
|
75
|
+
readonly shadowRadius: 2;
|
|
76
|
+
readonly elevation: 2;
|
|
77
|
+
};
|
|
78
|
+
readonly md: {
|
|
79
|
+
readonly shadowColor: "#08080A";
|
|
80
|
+
readonly shadowOffset: {
|
|
81
|
+
readonly width: 0;
|
|
82
|
+
readonly height: 4;
|
|
83
|
+
};
|
|
84
|
+
readonly shadowOpacity: 0.5;
|
|
85
|
+
readonly shadowRadius: 8;
|
|
86
|
+
readonly elevation: 4;
|
|
87
|
+
};
|
|
88
|
+
readonly lg: {
|
|
89
|
+
readonly shadowColor: "#08080A";
|
|
90
|
+
readonly shadowOffset: {
|
|
91
|
+
readonly width: 0;
|
|
92
|
+
readonly height: 8;
|
|
93
|
+
};
|
|
94
|
+
readonly shadowOpacity: 0.6;
|
|
95
|
+
readonly shadowRadius: 16;
|
|
96
|
+
readonly elevation: 8;
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
type Shadows = typeof shadows;
|
|
100
|
+
|
|
101
|
+
type BodyDiagramView = 'front' | 'back';
|
|
102
|
+
type BodyDiagramPalette = {
|
|
103
|
+
muscleFill?: string;
|
|
104
|
+
muscleStroke?: string;
|
|
105
|
+
muscleStrokeWidth?: number;
|
|
106
|
+
muscleOpacity?: number;
|
|
107
|
+
};
|
|
108
|
+
type BodyDiagramOverlayStyle = {
|
|
109
|
+
blur?: number;
|
|
110
|
+
blendMode?: string;
|
|
111
|
+
};
|
|
112
|
+
type BodyDiagramIntensity = 'off' | 'low' | 'medium' | 'high';
|
|
113
|
+
type BodyDiagramProps = {
|
|
114
|
+
view: BodyDiagramView;
|
|
115
|
+
svgMarkupByView: Record<BodyDiagramView, string>;
|
|
116
|
+
baseImageByView?: Partial<Record<BodyDiagramView, string>>;
|
|
117
|
+
selectedMuscles: string[];
|
|
118
|
+
onSelectedChange: (selected: string[]) => void;
|
|
119
|
+
debugForceVisible?: boolean;
|
|
120
|
+
interactionMode?: 'auto' | 'editable' | 'readonly';
|
|
121
|
+
palette?: BodyDiagramPalette;
|
|
122
|
+
overlayStyle?: BodyDiagramOverlayStyle;
|
|
123
|
+
intensityByMuscle?: Record<string, BodyDiagramIntensity>;
|
|
124
|
+
};
|
|
125
|
+
declare const BodyDiagram: ({ view, svgMarkupByView, baseImageByView, selectedMuscles, onSelectedChange, debugForceVisible, interactionMode, palette, overlayStyle, intensityByMuscle, }: BodyDiagramProps) => react_jsx_runtime.JSX.Element;
|
|
126
|
+
|
|
127
|
+
export { BodyDiagram, type BodyDiagramIntensity, type BodyDiagramOverlayStyle, type BodyDiagramPalette, type BodyDiagramProps, type BodyDiagramView, type Colors, type Radius, type Shadows, type Spacing, type Typography, colors, radius, shadows, spacing, typography };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
|
|
6
|
+
// src/tokens/colors.ts
|
|
7
|
+
var colors = {
|
|
8
|
+
primary: "#FDC026",
|
|
9
|
+
accent: "#6AABDE",
|
|
10
|
+
bodyDiagram: {
|
|
11
|
+
muscleFill: "#FFBF00",
|
|
12
|
+
muscleStroke: "#FF0090",
|
|
13
|
+
muscleStrokeWidth: 2,
|
|
14
|
+
muscleOpacity: 1
|
|
15
|
+
},
|
|
16
|
+
background: {
|
|
17
|
+
default: "#161C26",
|
|
18
|
+
muted: "#1C2434",
|
|
19
|
+
highlight: "#383040",
|
|
20
|
+
depth: "#08080A"
|
|
21
|
+
},
|
|
22
|
+
text: {
|
|
23
|
+
primary: "#E8E8E8",
|
|
24
|
+
secondary: "#9B9B9B"
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// src/tokens/spacing.ts
|
|
29
|
+
var spacing = {
|
|
30
|
+
big: 32,
|
|
31
|
+
default: 24,
|
|
32
|
+
small: 12,
|
|
33
|
+
textHorizontal: 4,
|
|
34
|
+
textVertical: 0
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// src/tokens/radius.ts
|
|
38
|
+
var radius = {
|
|
39
|
+
button: 4,
|
|
40
|
+
card: 8,
|
|
41
|
+
input: 4,
|
|
42
|
+
full: 9999
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// src/tokens/typography.ts
|
|
46
|
+
var typography = {
|
|
47
|
+
size: {
|
|
48
|
+
xs: 11,
|
|
49
|
+
sm: 13,
|
|
50
|
+
base: 15,
|
|
51
|
+
md: 17,
|
|
52
|
+
lg: 20,
|
|
53
|
+
xl: 24,
|
|
54
|
+
"2xl": 30,
|
|
55
|
+
"3xl": 36
|
|
56
|
+
},
|
|
57
|
+
weight: {
|
|
58
|
+
regular: "400",
|
|
59
|
+
medium: "500",
|
|
60
|
+
semibold: "600",
|
|
61
|
+
bold: "700"
|
|
62
|
+
},
|
|
63
|
+
lineHeight: {
|
|
64
|
+
tight: 1.2,
|
|
65
|
+
normal: 1.5,
|
|
66
|
+
relaxed: 1.75
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// src/tokens/shadows.ts
|
|
71
|
+
var shadows = {
|
|
72
|
+
sm: {
|
|
73
|
+
shadowColor: colors.background.depth,
|
|
74
|
+
shadowOffset: { width: 0, height: 1 },
|
|
75
|
+
shadowOpacity: 0.4,
|
|
76
|
+
shadowRadius: 2,
|
|
77
|
+
elevation: 2
|
|
78
|
+
},
|
|
79
|
+
md: {
|
|
80
|
+
shadowColor: colors.background.depth,
|
|
81
|
+
shadowOffset: { width: 0, height: 4 },
|
|
82
|
+
shadowOpacity: 0.5,
|
|
83
|
+
shadowRadius: 8,
|
|
84
|
+
elevation: 4
|
|
85
|
+
},
|
|
86
|
+
lg: {
|
|
87
|
+
shadowColor: colors.background.depth,
|
|
88
|
+
shadowOffset: { width: 0, height: 8 },
|
|
89
|
+
shadowOpacity: 0.6,
|
|
90
|
+
shadowRadius: 16,
|
|
91
|
+
elevation: 8
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// src/utils/bodyDiagramState.ts
|
|
96
|
+
var DEFAULT_LEVEL_OPACITY = {
|
|
97
|
+
off: 0,
|
|
98
|
+
low: 0.2,
|
|
99
|
+
medium: 0.5,
|
|
100
|
+
high: 0.9
|
|
101
|
+
};
|
|
102
|
+
var DEFAULT_DEBUG_STYLE = {
|
|
103
|
+
fill: "red",
|
|
104
|
+
stroke: "yellow",
|
|
105
|
+
strokeWidth: 4,
|
|
106
|
+
opacity: 1
|
|
107
|
+
};
|
|
108
|
+
var DEFAULT_PALETTE = {
|
|
109
|
+
muscleFill: colors.bodyDiagram.muscleFill,
|
|
110
|
+
muscleStroke: colors.bodyDiagram.muscleStroke,
|
|
111
|
+
muscleStrokeWidth: colors.bodyDiagram.muscleStrokeWidth,
|
|
112
|
+
muscleOpacity: colors.bodyDiagram.muscleOpacity
|
|
113
|
+
};
|
|
114
|
+
var LEVELS = ["off", "low", "medium", "high"];
|
|
115
|
+
var resolveBodyDiagramTheme = (input = {}) => {
|
|
116
|
+
const palette = { ...DEFAULT_PALETTE, ...input.palette };
|
|
117
|
+
const opacityByLevel = { ...DEFAULT_LEVEL_OPACITY, ...input.levelOpacity };
|
|
118
|
+
const baseOpacity = palette.muscleOpacity ?? 1;
|
|
119
|
+
const levels = LEVELS.reduce(
|
|
120
|
+
(acc, level) => {
|
|
121
|
+
acc[level] = {
|
|
122
|
+
fill: palette.muscleFill ?? "",
|
|
123
|
+
stroke: palette.muscleStroke,
|
|
124
|
+
strokeWidth: palette.muscleStrokeWidth,
|
|
125
|
+
opacity: baseOpacity * (opacityByLevel[level] ?? 1)
|
|
126
|
+
};
|
|
127
|
+
return acc;
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
off: { fill: "", opacity: 0 },
|
|
131
|
+
low: { fill: "", opacity: 0 },
|
|
132
|
+
medium: { fill: "", opacity: 0 },
|
|
133
|
+
high: { fill: "", opacity: 0 }
|
|
134
|
+
}
|
|
135
|
+
);
|
|
136
|
+
return {
|
|
137
|
+
levels,
|
|
138
|
+
debug: input.debugStyle ?? DEFAULT_DEBUG_STYLE
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
var resolveBodyDiagramMuscleState = (input) => {
|
|
142
|
+
const { muscleKey, selectedMuscles, intensityByMuscle, debugForceVisible } = input;
|
|
143
|
+
const explicitLevel = intensityByMuscle?.[muscleKey];
|
|
144
|
+
let level = "off";
|
|
145
|
+
let source = "defaultOff";
|
|
146
|
+
if (explicitLevel) {
|
|
147
|
+
level = explicitLevel;
|
|
148
|
+
source = "explicit";
|
|
149
|
+
} else if (selectedMuscles.includes(muscleKey)) {
|
|
150
|
+
level = "high";
|
|
151
|
+
source = "selectedFallback";
|
|
152
|
+
}
|
|
153
|
+
const theme = input.theme ?? resolveBodyDiagramTheme({ palette: input.palette });
|
|
154
|
+
const isDebugForced = Boolean(debugForceVisible);
|
|
155
|
+
const style = isDebugForced ? theme.debug ?? DEFAULT_DEBUG_STYLE : theme.levels[level];
|
|
156
|
+
const shouldRender = isDebugForced ? true : level !== "off";
|
|
157
|
+
const interactionMode = input.interactionMode ?? "auto";
|
|
158
|
+
const interactive = interactionMode === "readonly" ? false : interactionMode === "editable" ? true : level !== "off";
|
|
159
|
+
return {
|
|
160
|
+
key: muscleKey,
|
|
161
|
+
level,
|
|
162
|
+
interactive,
|
|
163
|
+
style,
|
|
164
|
+
source,
|
|
165
|
+
shouldRender,
|
|
166
|
+
isDebugForced
|
|
167
|
+
};
|
|
168
|
+
};
|
|
169
|
+
var BodyDiagram = ({
|
|
170
|
+
view,
|
|
171
|
+
svgMarkupByView,
|
|
172
|
+
baseImageByView,
|
|
173
|
+
selectedMuscles,
|
|
174
|
+
onSelectedChange,
|
|
175
|
+
debugForceVisible = false,
|
|
176
|
+
interactionMode = "auto",
|
|
177
|
+
palette,
|
|
178
|
+
overlayStyle,
|
|
179
|
+
intensityByMuscle
|
|
180
|
+
}) => {
|
|
181
|
+
const containerRef = react.useRef(null);
|
|
182
|
+
const svgMarkup = svgMarkupByView[view] || "";
|
|
183
|
+
const baseImage = baseImageByView?.[view] || "";
|
|
184
|
+
const handleClick = react.useCallback(
|
|
185
|
+
(event) => {
|
|
186
|
+
if (interactionMode === "readonly") return;
|
|
187
|
+
const target = event.target;
|
|
188
|
+
const element = target.closest("[data-muscle-key]");
|
|
189
|
+
const key = element?.getAttribute("data-muscle-key");
|
|
190
|
+
if (!key) return;
|
|
191
|
+
const next = new Set(selectedMuscles);
|
|
192
|
+
if (next.has(key)) {
|
|
193
|
+
next.delete(key);
|
|
194
|
+
} else {
|
|
195
|
+
next.add(key);
|
|
196
|
+
}
|
|
197
|
+
onSelectedChange(Array.from(next));
|
|
198
|
+
},
|
|
199
|
+
[interactionMode, onSelectedChange, selectedMuscles]
|
|
200
|
+
);
|
|
201
|
+
react.useEffect(() => {
|
|
202
|
+
const container = containerRef.current;
|
|
203
|
+
if (!container) return;
|
|
204
|
+
const svg = container.querySelector("svg");
|
|
205
|
+
if (!svg) return;
|
|
206
|
+
svg.style.width = "100%";
|
|
207
|
+
svg.style.height = "100%";
|
|
208
|
+
svg.setAttribute("preserveAspectRatio", "xMidYMid meet");
|
|
209
|
+
const elements = svg.querySelectorAll("[data-muscle-key]");
|
|
210
|
+
const theme = resolveBodyDiagramTheme({ palette });
|
|
211
|
+
elements.forEach((el) => {
|
|
212
|
+
const element = el;
|
|
213
|
+
const key = element.getAttribute("data-muscle-key");
|
|
214
|
+
if (!key) return;
|
|
215
|
+
const resolved = resolveBodyDiagramMuscleState({
|
|
216
|
+
muscleKey: key,
|
|
217
|
+
selectedMuscles,
|
|
218
|
+
intensityByMuscle,
|
|
219
|
+
palette,
|
|
220
|
+
debugForceVisible,
|
|
221
|
+
theme,
|
|
222
|
+
interactionMode
|
|
223
|
+
});
|
|
224
|
+
if (resolved.isDebugForced) {
|
|
225
|
+
element.removeAttribute("filter");
|
|
226
|
+
element.removeAttribute("mask");
|
|
227
|
+
element.removeAttribute("clip-path");
|
|
228
|
+
element.removeAttribute("style");
|
|
229
|
+
}
|
|
230
|
+
const isOff = resolved.level === "off";
|
|
231
|
+
const forceHitArea = isOff && !resolved.isDebugForced;
|
|
232
|
+
if (forceHitArea) {
|
|
233
|
+
element.setAttribute("fill", "rgba(0,0,0,0)");
|
|
234
|
+
} else if (resolved.style.fill) {
|
|
235
|
+
element.setAttribute("fill", resolved.style.fill);
|
|
236
|
+
}
|
|
237
|
+
if (resolved.style.stroke) {
|
|
238
|
+
element.setAttribute("stroke", resolved.style.stroke);
|
|
239
|
+
}
|
|
240
|
+
if (resolved.style.strokeWidth != null) {
|
|
241
|
+
element.setAttribute("stroke-width", String(resolved.style.strokeWidth));
|
|
242
|
+
}
|
|
243
|
+
element.setAttribute("opacity", String(resolved.style.opacity));
|
|
244
|
+
element.style.pointerEvents = "auto";
|
|
245
|
+
});
|
|
246
|
+
}, [selectedMuscles, svgMarkup, debugForceVisible, intensityByMuscle, palette, interactionMode]);
|
|
247
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: containerStyle, children: [
|
|
248
|
+
baseImage ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: baseImage, alt: "", style: baseImageStyle }) : null,
|
|
249
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
250
|
+
"div",
|
|
251
|
+
{
|
|
252
|
+
ref: containerRef,
|
|
253
|
+
style: {
|
|
254
|
+
position: "absolute",
|
|
255
|
+
inset: 0,
|
|
256
|
+
width: "100%",
|
|
257
|
+
height: "100%",
|
|
258
|
+
filter: overlayStyle?.blur ? `blur(${overlayStyle.blur}px)` : void 0,
|
|
259
|
+
mixBlendMode: overlayStyle?.blendMode
|
|
260
|
+
},
|
|
261
|
+
onClick: handleClick,
|
|
262
|
+
dangerouslySetInnerHTML: { __html: svgMarkup }
|
|
263
|
+
}
|
|
264
|
+
)
|
|
265
|
+
] });
|
|
266
|
+
};
|
|
267
|
+
var containerStyle = {
|
|
268
|
+
display: "flex",
|
|
269
|
+
width: "100%",
|
|
270
|
+
height: "100%",
|
|
271
|
+
position: "relative",
|
|
272
|
+
overflow: "hidden"
|
|
273
|
+
};
|
|
274
|
+
var baseImageStyle = {
|
|
275
|
+
position: "absolute",
|
|
276
|
+
inset: 0,
|
|
277
|
+
width: "100%",
|
|
278
|
+
height: "100%",
|
|
279
|
+
objectFit: "contain"
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
exports.BodyDiagram = BodyDiagram;
|
|
283
|
+
exports.colors = colors;
|
|
284
|
+
exports.radius = radius;
|
|
285
|
+
exports.shadows = shadows;
|
|
286
|
+
exports.spacing = spacing;
|
|
287
|
+
exports.typography = typography;
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { useRef, useCallback, useEffect } from 'react';
|
|
2
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
// src/tokens/colors.ts
|
|
5
|
+
var colors = {
|
|
6
|
+
primary: "#FDC026",
|
|
7
|
+
accent: "#6AABDE",
|
|
8
|
+
bodyDiagram: {
|
|
9
|
+
muscleFill: "#FFBF00",
|
|
10
|
+
muscleStroke: "#FF0090",
|
|
11
|
+
muscleStrokeWidth: 2,
|
|
12
|
+
muscleOpacity: 1
|
|
13
|
+
},
|
|
14
|
+
background: {
|
|
15
|
+
default: "#161C26",
|
|
16
|
+
muted: "#1C2434",
|
|
17
|
+
highlight: "#383040",
|
|
18
|
+
depth: "#08080A"
|
|
19
|
+
},
|
|
20
|
+
text: {
|
|
21
|
+
primary: "#E8E8E8",
|
|
22
|
+
secondary: "#9B9B9B"
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// src/tokens/spacing.ts
|
|
27
|
+
var spacing = {
|
|
28
|
+
big: 32,
|
|
29
|
+
default: 24,
|
|
30
|
+
small: 12,
|
|
31
|
+
textHorizontal: 4,
|
|
32
|
+
textVertical: 0
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// src/tokens/radius.ts
|
|
36
|
+
var radius = {
|
|
37
|
+
button: 4,
|
|
38
|
+
card: 8,
|
|
39
|
+
input: 4,
|
|
40
|
+
full: 9999
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// src/tokens/typography.ts
|
|
44
|
+
var typography = {
|
|
45
|
+
size: {
|
|
46
|
+
xs: 11,
|
|
47
|
+
sm: 13,
|
|
48
|
+
base: 15,
|
|
49
|
+
md: 17,
|
|
50
|
+
lg: 20,
|
|
51
|
+
xl: 24,
|
|
52
|
+
"2xl": 30,
|
|
53
|
+
"3xl": 36
|
|
54
|
+
},
|
|
55
|
+
weight: {
|
|
56
|
+
regular: "400",
|
|
57
|
+
medium: "500",
|
|
58
|
+
semibold: "600",
|
|
59
|
+
bold: "700"
|
|
60
|
+
},
|
|
61
|
+
lineHeight: {
|
|
62
|
+
tight: 1.2,
|
|
63
|
+
normal: 1.5,
|
|
64
|
+
relaxed: 1.75
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// src/tokens/shadows.ts
|
|
69
|
+
var shadows = {
|
|
70
|
+
sm: {
|
|
71
|
+
shadowColor: colors.background.depth,
|
|
72
|
+
shadowOffset: { width: 0, height: 1 },
|
|
73
|
+
shadowOpacity: 0.4,
|
|
74
|
+
shadowRadius: 2,
|
|
75
|
+
elevation: 2
|
|
76
|
+
},
|
|
77
|
+
md: {
|
|
78
|
+
shadowColor: colors.background.depth,
|
|
79
|
+
shadowOffset: { width: 0, height: 4 },
|
|
80
|
+
shadowOpacity: 0.5,
|
|
81
|
+
shadowRadius: 8,
|
|
82
|
+
elevation: 4
|
|
83
|
+
},
|
|
84
|
+
lg: {
|
|
85
|
+
shadowColor: colors.background.depth,
|
|
86
|
+
shadowOffset: { width: 0, height: 8 },
|
|
87
|
+
shadowOpacity: 0.6,
|
|
88
|
+
shadowRadius: 16,
|
|
89
|
+
elevation: 8
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// src/utils/bodyDiagramState.ts
|
|
94
|
+
var DEFAULT_LEVEL_OPACITY = {
|
|
95
|
+
off: 0,
|
|
96
|
+
low: 0.2,
|
|
97
|
+
medium: 0.5,
|
|
98
|
+
high: 0.9
|
|
99
|
+
};
|
|
100
|
+
var DEFAULT_DEBUG_STYLE = {
|
|
101
|
+
fill: "red",
|
|
102
|
+
stroke: "yellow",
|
|
103
|
+
strokeWidth: 4,
|
|
104
|
+
opacity: 1
|
|
105
|
+
};
|
|
106
|
+
var DEFAULT_PALETTE = {
|
|
107
|
+
muscleFill: colors.bodyDiagram.muscleFill,
|
|
108
|
+
muscleStroke: colors.bodyDiagram.muscleStroke,
|
|
109
|
+
muscleStrokeWidth: colors.bodyDiagram.muscleStrokeWidth,
|
|
110
|
+
muscleOpacity: colors.bodyDiagram.muscleOpacity
|
|
111
|
+
};
|
|
112
|
+
var LEVELS = ["off", "low", "medium", "high"];
|
|
113
|
+
var resolveBodyDiagramTheme = (input = {}) => {
|
|
114
|
+
const palette = { ...DEFAULT_PALETTE, ...input.palette };
|
|
115
|
+
const opacityByLevel = { ...DEFAULT_LEVEL_OPACITY, ...input.levelOpacity };
|
|
116
|
+
const baseOpacity = palette.muscleOpacity ?? 1;
|
|
117
|
+
const levels = LEVELS.reduce(
|
|
118
|
+
(acc, level) => {
|
|
119
|
+
acc[level] = {
|
|
120
|
+
fill: palette.muscleFill ?? "",
|
|
121
|
+
stroke: palette.muscleStroke,
|
|
122
|
+
strokeWidth: palette.muscleStrokeWidth,
|
|
123
|
+
opacity: baseOpacity * (opacityByLevel[level] ?? 1)
|
|
124
|
+
};
|
|
125
|
+
return acc;
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
off: { fill: "", opacity: 0 },
|
|
129
|
+
low: { fill: "", opacity: 0 },
|
|
130
|
+
medium: { fill: "", opacity: 0 },
|
|
131
|
+
high: { fill: "", opacity: 0 }
|
|
132
|
+
}
|
|
133
|
+
);
|
|
134
|
+
return {
|
|
135
|
+
levels,
|
|
136
|
+
debug: input.debugStyle ?? DEFAULT_DEBUG_STYLE
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
var resolveBodyDiagramMuscleState = (input) => {
|
|
140
|
+
const { muscleKey, selectedMuscles, intensityByMuscle, debugForceVisible } = input;
|
|
141
|
+
const explicitLevel = intensityByMuscle?.[muscleKey];
|
|
142
|
+
let level = "off";
|
|
143
|
+
let source = "defaultOff";
|
|
144
|
+
if (explicitLevel) {
|
|
145
|
+
level = explicitLevel;
|
|
146
|
+
source = "explicit";
|
|
147
|
+
} else if (selectedMuscles.includes(muscleKey)) {
|
|
148
|
+
level = "high";
|
|
149
|
+
source = "selectedFallback";
|
|
150
|
+
}
|
|
151
|
+
const theme = input.theme ?? resolveBodyDiagramTheme({ palette: input.palette });
|
|
152
|
+
const isDebugForced = Boolean(debugForceVisible);
|
|
153
|
+
const style = isDebugForced ? theme.debug ?? DEFAULT_DEBUG_STYLE : theme.levels[level];
|
|
154
|
+
const shouldRender = isDebugForced ? true : level !== "off";
|
|
155
|
+
const interactionMode = input.interactionMode ?? "auto";
|
|
156
|
+
const interactive = interactionMode === "readonly" ? false : interactionMode === "editable" ? true : level !== "off";
|
|
157
|
+
return {
|
|
158
|
+
key: muscleKey,
|
|
159
|
+
level,
|
|
160
|
+
interactive,
|
|
161
|
+
style,
|
|
162
|
+
source,
|
|
163
|
+
shouldRender,
|
|
164
|
+
isDebugForced
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
var BodyDiagram = ({
|
|
168
|
+
view,
|
|
169
|
+
svgMarkupByView,
|
|
170
|
+
baseImageByView,
|
|
171
|
+
selectedMuscles,
|
|
172
|
+
onSelectedChange,
|
|
173
|
+
debugForceVisible = false,
|
|
174
|
+
interactionMode = "auto",
|
|
175
|
+
palette,
|
|
176
|
+
overlayStyle,
|
|
177
|
+
intensityByMuscle
|
|
178
|
+
}) => {
|
|
179
|
+
const containerRef = useRef(null);
|
|
180
|
+
const svgMarkup = svgMarkupByView[view] || "";
|
|
181
|
+
const baseImage = baseImageByView?.[view] || "";
|
|
182
|
+
const handleClick = useCallback(
|
|
183
|
+
(event) => {
|
|
184
|
+
if (interactionMode === "readonly") return;
|
|
185
|
+
const target = event.target;
|
|
186
|
+
const element = target.closest("[data-muscle-key]");
|
|
187
|
+
const key = element?.getAttribute("data-muscle-key");
|
|
188
|
+
if (!key) return;
|
|
189
|
+
const next = new Set(selectedMuscles);
|
|
190
|
+
if (next.has(key)) {
|
|
191
|
+
next.delete(key);
|
|
192
|
+
} else {
|
|
193
|
+
next.add(key);
|
|
194
|
+
}
|
|
195
|
+
onSelectedChange(Array.from(next));
|
|
196
|
+
},
|
|
197
|
+
[interactionMode, onSelectedChange, selectedMuscles]
|
|
198
|
+
);
|
|
199
|
+
useEffect(() => {
|
|
200
|
+
const container = containerRef.current;
|
|
201
|
+
if (!container) return;
|
|
202
|
+
const svg = container.querySelector("svg");
|
|
203
|
+
if (!svg) return;
|
|
204
|
+
svg.style.width = "100%";
|
|
205
|
+
svg.style.height = "100%";
|
|
206
|
+
svg.setAttribute("preserveAspectRatio", "xMidYMid meet");
|
|
207
|
+
const elements = svg.querySelectorAll("[data-muscle-key]");
|
|
208
|
+
const theme = resolveBodyDiagramTheme({ palette });
|
|
209
|
+
elements.forEach((el) => {
|
|
210
|
+
const element = el;
|
|
211
|
+
const key = element.getAttribute("data-muscle-key");
|
|
212
|
+
if (!key) return;
|
|
213
|
+
const resolved = resolveBodyDiagramMuscleState({
|
|
214
|
+
muscleKey: key,
|
|
215
|
+
selectedMuscles,
|
|
216
|
+
intensityByMuscle,
|
|
217
|
+
palette,
|
|
218
|
+
debugForceVisible,
|
|
219
|
+
theme,
|
|
220
|
+
interactionMode
|
|
221
|
+
});
|
|
222
|
+
if (resolved.isDebugForced) {
|
|
223
|
+
element.removeAttribute("filter");
|
|
224
|
+
element.removeAttribute("mask");
|
|
225
|
+
element.removeAttribute("clip-path");
|
|
226
|
+
element.removeAttribute("style");
|
|
227
|
+
}
|
|
228
|
+
const isOff = resolved.level === "off";
|
|
229
|
+
const forceHitArea = isOff && !resolved.isDebugForced;
|
|
230
|
+
if (forceHitArea) {
|
|
231
|
+
element.setAttribute("fill", "rgba(0,0,0,0)");
|
|
232
|
+
} else if (resolved.style.fill) {
|
|
233
|
+
element.setAttribute("fill", resolved.style.fill);
|
|
234
|
+
}
|
|
235
|
+
if (resolved.style.stroke) {
|
|
236
|
+
element.setAttribute("stroke", resolved.style.stroke);
|
|
237
|
+
}
|
|
238
|
+
if (resolved.style.strokeWidth != null) {
|
|
239
|
+
element.setAttribute("stroke-width", String(resolved.style.strokeWidth));
|
|
240
|
+
}
|
|
241
|
+
element.setAttribute("opacity", String(resolved.style.opacity));
|
|
242
|
+
element.style.pointerEvents = "auto";
|
|
243
|
+
});
|
|
244
|
+
}, [selectedMuscles, svgMarkup, debugForceVisible, intensityByMuscle, palette, interactionMode]);
|
|
245
|
+
return /* @__PURE__ */ jsxs("div", { style: containerStyle, children: [
|
|
246
|
+
baseImage ? /* @__PURE__ */ jsx("img", { src: baseImage, alt: "", style: baseImageStyle }) : null,
|
|
247
|
+
/* @__PURE__ */ jsx(
|
|
248
|
+
"div",
|
|
249
|
+
{
|
|
250
|
+
ref: containerRef,
|
|
251
|
+
style: {
|
|
252
|
+
position: "absolute",
|
|
253
|
+
inset: 0,
|
|
254
|
+
width: "100%",
|
|
255
|
+
height: "100%",
|
|
256
|
+
filter: overlayStyle?.blur ? `blur(${overlayStyle.blur}px)` : void 0,
|
|
257
|
+
mixBlendMode: overlayStyle?.blendMode
|
|
258
|
+
},
|
|
259
|
+
onClick: handleClick,
|
|
260
|
+
dangerouslySetInnerHTML: { __html: svgMarkup }
|
|
261
|
+
}
|
|
262
|
+
)
|
|
263
|
+
] });
|
|
264
|
+
};
|
|
265
|
+
var containerStyle = {
|
|
266
|
+
display: "flex",
|
|
267
|
+
width: "100%",
|
|
268
|
+
height: "100%",
|
|
269
|
+
position: "relative",
|
|
270
|
+
overflow: "hidden"
|
|
271
|
+
};
|
|
272
|
+
var baseImageStyle = {
|
|
273
|
+
position: "absolute",
|
|
274
|
+
inset: 0,
|
|
275
|
+
width: "100%",
|
|
276
|
+
height: "100%",
|
|
277
|
+
objectFit: "contain"
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
export { BodyDiagram, colors, radius, shadows, spacing, typography };
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jlunamena/design-system",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "PT Design System",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"sideEffects": false,
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup",
|
|
21
|
+
"storybook": "storybook dev -p 6006",
|
|
22
|
+
"build-storybook": "storybook build",
|
|
23
|
+
"generate:exports": "node scripts/generate-exports.mjs"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"react": ">=18.0.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@storybook/addon-essentials": "^8.6.0",
|
|
30
|
+
"@storybook/react": "^8.6.0",
|
|
31
|
+
"@storybook/react-vite": "^8.6.0",
|
|
32
|
+
"@types/react": "^19.1.0",
|
|
33
|
+
"@types/react-dom": "^19.1.0",
|
|
34
|
+
"@vitejs/plugin-react": "^4.3.0",
|
|
35
|
+
"esbuild": "^0.28.0",
|
|
36
|
+
"react": "^19.1.0",
|
|
37
|
+
"react-dom": "^19.1.0",
|
|
38
|
+
"storybook": "^8.6.0",
|
|
39
|
+
"tsup": "^8.0.0",
|
|
40
|
+
"typescript": "~5.9.2",
|
|
41
|
+
"vite": "^5.0.0"
|
|
42
|
+
}
|
|
43
|
+
}
|