@tokyo3rdhq/magi-design-system 0.1.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 +208 -0
- package/dist/components/Badge/Badge.d.ts +18 -0
- package/dist/components/Badge/Badge.d.ts.map +1 -0
- package/dist/components/Badge/index.d.ts +3 -0
- package/dist/components/Badge/index.d.ts.map +1 -0
- package/dist/components/Button/Button.d.ts +24 -0
- package/dist/components/Button/Button.d.ts.map +1 -0
- package/dist/components/Button/index.d.ts +3 -0
- package/dist/components/Button/index.d.ts.map +1 -0
- package/dist/components/Card/Card.d.ts +20 -0
- package/dist/components/Card/Card.d.ts.map +1 -0
- package/dist/components/Card/index.d.ts +3 -0
- package/dist/components/Card/index.d.ts.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +153 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/Container.d.ts +17 -0
- package/dist/layout/Container.d.ts.map +1 -0
- package/dist/layout/Section.d.ts +22 -0
- package/dist/layout/Section.d.ts.map +1 -0
- package/dist/layout/Stack.d.ts +24 -0
- package/dist/layout/Stack.d.ts.map +1 -0
- package/dist/layout/index.d.ts +7 -0
- package/dist/layout/index.d.ts.map +1 -0
- package/dist/styles.css +1 -0
- package/dist/theme.d.ts +37 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/utils/classnames.d.ts +3 -0
- package/dist/utils/classnames.d.ts.map +1 -0
- package/package.json +66 -0
- package/src/styles/index.css +17 -0
package/README.md
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# `@tokyo3rdhq/magi-design-system`
|
|
2
|
+
|
|
3
|
+
Shared visual foundation for the [MAGI](https://magi.website) product family — dark-first, near-monochrome, restrained.
|
|
4
|
+
|
|
5
|
+
- **React 18** + **TypeScript** (strict)
|
|
6
|
+
- **Plain CSS** with `magi-` prefixed classes — works in any React app, no Tailwind, no Next, no Vite, no Cloudflare coupling
|
|
7
|
+
- **CSS custom properties** for every token — readable from any stylesheet
|
|
8
|
+
- **~16 kB** stylesheet (gzip ~3 kB), **~4 kB** JS (gzip ~1 kB)
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @tokyo3rdhq/magi-design-system
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
// 1. Styles — import once at the application root.
|
|
20
|
+
import '@tokyo3rdhq/magi-design-system/styles.css';
|
|
21
|
+
|
|
22
|
+
// 2. <body> needs data-magi-app so foundation styles can scope themselves.
|
|
23
|
+
<body data-magi-app>
|
|
24
|
+
<div id="root"></div>
|
|
25
|
+
</body>
|
|
26
|
+
|
|
27
|
+
// 3. Wrap your app in <ProductTheme> to optionally override the accent.
|
|
28
|
+
import { ProductTheme } from '@tokyo3rdhq/magi-design-system';
|
|
29
|
+
|
|
30
|
+
<ProductTheme accent="green">
|
|
31
|
+
<App />
|
|
32
|
+
</ProductTheme>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## API
|
|
36
|
+
|
|
37
|
+
### `<Container>` — centers and constrains max-width
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import { Container } from '@tokyo3rdhq/magi-design-system';
|
|
41
|
+
|
|
42
|
+
<Container size="xl">…</Container>
|
|
43
|
+
// size: 'sm' | 'md' | 'lg' | 'xl' | 'wide' | 'full' (default: 'xl')
|
|
44
|
+
// as: 'div' | 'section' | … (default: 'div')
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
| Size | Max-width |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| `sm` | 640 px |
|
|
50
|
+
| `md` | 768 px |
|
|
51
|
+
| `lg` | 1024 px |
|
|
52
|
+
| `xl` (default) | 1200 px |
|
|
53
|
+
| `wide` | 1400 px |
|
|
54
|
+
| `full` | 100 % |
|
|
55
|
+
|
|
56
|
+
### `<Section>` — page-level vertical rhythm
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import { Section } from '@tokyo3rdhq/magi-design-system';
|
|
60
|
+
|
|
61
|
+
<Section spacing="lg" surface="default">…</Section>
|
|
62
|
+
// spacing: 'sm' | 'md' | 'lg' | 'xl' (default: 'lg')
|
|
63
|
+
// surface: 'default' | 'raised' | 'elevated' (default: 'default')
|
|
64
|
+
// fullWidth: boolean (default: false)
|
|
65
|
+
// as: 'section' | 'div' | …
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`spacing` maps to `--magi-space-12` / `20` / `32` / `40` (xl jumps to `40` on ≥ 768 px viewports).
|
|
69
|
+
|
|
70
|
+
### `<Stack>` — flex primitive with semantic gap tokens
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import { Stack } from '@tokyo3rdhq/magi-design-system';
|
|
74
|
+
|
|
75
|
+
<Stack direction="column" gap="4" align="stretch">
|
|
76
|
+
<div>Item 1</div>
|
|
77
|
+
<div>Item 2</div>
|
|
78
|
+
</Stack>
|
|
79
|
+
// direction: 'column' | 'row' (default: 'column')
|
|
80
|
+
// gap: '0' | '1' | '2' | '3' | '4' | '5' | '6' | '8' | '10' | '12' | '16' (default: '4')
|
|
81
|
+
// align: 'start' | 'center' | 'end' | 'stretch' (default: 'stretch')
|
|
82
|
+
// wrap: boolean (default: true)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### `<Button>` — pill action element
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
import { Button } from '@tokyo3rdhq/magi-design-system';
|
|
89
|
+
|
|
90
|
+
<Button variant="primary" size="md" loading={false}>Save</Button>
|
|
91
|
+
// variant: 'primary' | 'secondary' | 'ghost' | 'danger' (default: 'primary')
|
|
92
|
+
// size: 'sm' | 'md' | 'lg' (default: 'md')
|
|
93
|
+
// loading: boolean (default: false)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
All buttons include hover, active, focus-visible, disabled, and loading states. Focus ring uses `--magi-focus-ring`.
|
|
97
|
+
|
|
98
|
+
### `<Card>` — dark surface
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
import { Card } from '@tokyo3rdhq/magi-design-system';
|
|
102
|
+
|
|
103
|
+
<Card variant="elevated" padding="md">…</Card>
|
|
104
|
+
// variant: 'default' | 'elevated' | 'interactive' (default: 'default')
|
|
105
|
+
// padding: 'none' | 'sm' | 'md' | 'lg' (default: 'md')
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`interactive` adds hover (border lift + surface darken) and active (1 px lift) states.
|
|
109
|
+
|
|
110
|
+
### `<Badge>` — compact status / metadata label
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
import { Badge } from '@tokyo3rdhq/magi-design-system';
|
|
114
|
+
|
|
115
|
+
<Badge variant="accent" dot>128K context</Badge>
|
|
116
|
+
// variant: 'neutral' | 'accent' | 'success' | 'warning' | 'error' (default: 'neutral')
|
|
117
|
+
// dot: boolean (default: false)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### `<ProductTheme>` — accent override
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
import { ProductTheme } from '@tokyo3rdhq/magi-design-system';
|
|
124
|
+
|
|
125
|
+
<ProductTheme accent="cyan" name="token-factory">
|
|
126
|
+
<App />
|
|
127
|
+
</ProductTheme>
|
|
128
|
+
// accent: 'green' | 'cyan' | 'violet' | 'amber' | 'white' (default: 'green')
|
|
129
|
+
// name: string (optional product identifier)
|
|
130
|
+
// tokens: Partial<CSSProperties> (optional additional overrides)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
`<ProductTheme>` renders a `<div data-magi-product="…">` and sets the four accent tokens as inline custom properties on the wrapper. Children inherit the override automatically via CSS variable resolution.
|
|
134
|
+
|
|
135
|
+
**Allowed in `tokens`**: only overrideable tokens (accent family). Refrain from setting `--magi-space-*`, `--magi-text-primary`, or base surfaces — see spec §10.
|
|
136
|
+
|
|
137
|
+
#### Preset accent palettes
|
|
138
|
+
|
|
139
|
+
| Preset | `--magi-accent` | Use |
|
|
140
|
+
| --- | --- | --- |
|
|
141
|
+
| `green` (default) | `#00c853` | MAGI core |
|
|
142
|
+
| `cyan` | `#38bdf8` | Token Factory Initializr |
|
|
143
|
+
| `violet` | `#8b5cf6` | API product |
|
|
144
|
+
| `amber` | `#f59e0b` | Agent product |
|
|
145
|
+
| `white` | `#ffffff` | Monochrome MAGI |
|
|
146
|
+
|
|
147
|
+
## Typography utility classes
|
|
148
|
+
|
|
149
|
+
Apply with `className="…"` on any element. They consume the same tokens as the React components.
|
|
150
|
+
|
|
151
|
+
| Class | What |
|
|
152
|
+
| --- | --- |
|
|
153
|
+
| `.magi-display` | 72 px / semibold / -0.045em / 1.05 leading |
|
|
154
|
+
| `.magi-h1` | 48 px / semibold / -0.03em / 1.15 |
|
|
155
|
+
| `.magi-h2` | 36 px / semibold / -0.03em / 1.15 |
|
|
156
|
+
| `.magi-h3` | 24 px / semibold / -0.01em / 1.3 |
|
|
157
|
+
| `.magi-h4` | 20 px / medium / -0.01em / 1.3 |
|
|
158
|
+
| `.magi-body-lg` | 18 px / normal / 1.625 |
|
|
159
|
+
| `.magi-body` | 16 px / normal / 1.5 |
|
|
160
|
+
| `.magi-body-sm` | 14 px / normal / 1.5 |
|
|
161
|
+
| `.magi-label` | 13 px / medium / 1.3 |
|
|
162
|
+
| `.magi-caption` | 12 px / normal / 1.3 |
|
|
163
|
+
| `.magi-eyebrow` | 14 px / medium / 0.18em tracking / uppercase / accent |
|
|
164
|
+
| `.magi-code` | 14 px mono / surface bg / 1px border |
|
|
165
|
+
|
|
166
|
+
## Tokens
|
|
167
|
+
|
|
168
|
+
Every token is a CSS custom property on `:root`. See [`docs/tokens.md`](../../docs/tokens.md) for the complete reference.
|
|
169
|
+
|
|
170
|
+
```css
|
|
171
|
+
.my-thing {
|
|
172
|
+
color: var(--magi-text-primary);
|
|
173
|
+
background: var(--magi-surface);
|
|
174
|
+
padding: var(--magi-space-4);
|
|
175
|
+
border-radius: var(--magi-radius-lg);
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Accessibility
|
|
180
|
+
|
|
181
|
+
- All interactive elements have visible `:focus-visible` rings via `--magi-focus-ring`
|
|
182
|
+
- `@media (prefers-reduced-motion: reduce)` collapses all motion durations to `0.01ms`
|
|
183
|
+
- Buttons: `aria-busy` toggles with `loading`; `disabled` + `aria-disabled` covered
|
|
184
|
+
- Color tokens chosen to meet WCAG AA contrast on the dark background
|
|
185
|
+
|
|
186
|
+
## Build
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
npm run build # vite build (ESM) + tsc declarations
|
|
190
|
+
npm run typecheck # tsc --noEmit
|
|
191
|
+
npm run dev # vite build --watch (for showroom live reload)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Output: `dist/index.js` (ESM), `dist/index.d.ts`, `dist/styles.css` (tokens + foundation + components).
|
|
195
|
+
|
|
196
|
+
## What's NOT included
|
|
197
|
+
|
|
198
|
+
Per spec §36 / §4:
|
|
199
|
+
|
|
200
|
+
- Tailwind / Next / Vite / Cloudflare coupling
|
|
201
|
+
- Animation library
|
|
202
|
+
- i18n (consumers handle it themselves)
|
|
203
|
+
- Light theme (package is dark-first per spec §9)
|
|
204
|
+
- Navbar, Footer, Tabs, Input, CodeBlock, ProductHeader — Phase 4, only after duplication is observed in 2+ products
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
[MIT](../../LICENSE) © 2026 [tokyo3rdhq](https://github.com/tokyo3rdhq)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type HTMLAttributes, type ReactNode } from 'react';
|
|
2
|
+
export type BadgeVariant = 'neutral' | 'accent' | 'success' | 'warning' | 'error';
|
|
3
|
+
export interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {
|
|
4
|
+
/** Color/meaning. Default: `neutral`. */
|
|
5
|
+
variant?: BadgeVariant;
|
|
6
|
+
/** Show a leading colored dot. */
|
|
7
|
+
dot?: boolean;
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Badge — compact status / metadata label.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* <Badge variant="accent">128K context</Badge>
|
|
15
|
+
* <Badge variant="success" dot>Online</Badge>
|
|
16
|
+
*/
|
|
17
|
+
export declare const Badge: import("react").ForwardRefExoticComponent<BadgeProps & import("react").RefAttributes<HTMLSpanElement>>;
|
|
18
|
+
//# sourceMappingURL=Badge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Badge.d.ts","sourceRoot":"","sources":["../../../src/components/Badge/Badge.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGxE,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAElF,MAAM,WAAW,UAAW,SAAQ,cAAc,CAAC,eAAe,CAAC;IACjE,yCAAyC;IACzC,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,kCAAkC;IAClC,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,KAAK,wGAehB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Badge/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type ButtonHTMLAttributes } from 'react';
|
|
2
|
+
export type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger';
|
|
3
|
+
export type ButtonSize = 'sm' | 'md' | 'lg';
|
|
4
|
+
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
5
|
+
/** Visual style. Default: `primary`. */
|
|
6
|
+
variant?: ButtonVariant;
|
|
7
|
+
/** Height + padding tier. Default: `md`. */
|
|
8
|
+
size?: ButtonSize;
|
|
9
|
+
/** Show a spinner and disable interaction. */
|
|
10
|
+
loading?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Button — the canonical MAGI action element.
|
|
14
|
+
*
|
|
15
|
+
* Pill-shaped, four variants (primary/secondary/ghost/danger), three sizes.
|
|
16
|
+
* Use `primary` for the dominant action on a page; `secondary` for supporting
|
|
17
|
+
* actions; `ghost` for inline/tertiary; `danger` for destructive intent.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* <Button variant="primary" onClick={...}>Save</Button>
|
|
21
|
+
* <Button variant="secondary">Cancel</Button>
|
|
22
|
+
*/
|
|
23
|
+
export declare const Button: import("react").ForwardRefExoticComponent<ButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
24
|
+
//# sourceMappingURL=Button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../src/components/Button/Button.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAG9D,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,QAAQ,CAAC;AACzE,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE5C,MAAM,WAAW,WAAY,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;IAC1E,wCAAwC;IACxC,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,4CAA4C;IAC5C,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,MAAM,2GAmClB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Button/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type HTMLAttributes, type ReactNode } from 'react';
|
|
2
|
+
export type CardVariant = 'default' | 'elevated' | 'interactive';
|
|
3
|
+
export type CardPadding = 'none' | 'sm' | 'md' | 'lg';
|
|
4
|
+
export interface CardProps extends HTMLAttributes<HTMLDivElement> {
|
|
5
|
+
/** Visual emphasis. Default: `default`. `interactive` adds hover state. */
|
|
6
|
+
variant?: CardVariant;
|
|
7
|
+
/** Inner padding. Default: `md`. */
|
|
8
|
+
padding?: CardPadding;
|
|
9
|
+
children?: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Card — minimal dark surface with subtle border. Three variants:
|
|
13
|
+
* default (flat), elevated (more contrast), interactive (hover state).
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* <Card variant="elevated">...</Card>
|
|
17
|
+
* <Card variant="interactive" onClick={...}>...</Card>
|
|
18
|
+
*/
|
|
19
|
+
export declare const Card: import("react").ForwardRefExoticComponent<CardProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
20
|
+
//# sourceMappingURL=Card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Card.d.ts","sourceRoot":"","sources":["../../../src/components/Card/Card.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGxE,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,aAAa,CAAC;AACjE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEtD,MAAM,WAAW,SAAU,SAAQ,cAAc,CAAC,cAAc,CAAC;IAC/D,2EAA2E;IAC3E,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,oCAAoC;IACpC,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,IAAI,sGAef,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Card/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @magi/design-system — public API.
|
|
3
|
+
*
|
|
4
|
+
* import '@magi/design-system/styles.css';
|
|
5
|
+
* import { Container, Section, Stack, Button, Card, Badge, ProductTheme } from '@magi/design-system';
|
|
6
|
+
*/
|
|
7
|
+
import './styles/index.css';
|
|
8
|
+
export * from './layout/index';
|
|
9
|
+
export * from './components/Button/index';
|
|
10
|
+
export * from './components/Card/index';
|
|
11
|
+
export * from './components/Badge/index';
|
|
12
|
+
export { ProductTheme } from './theme';
|
|
13
|
+
export type { ProductThemeProps, ProductAccent } from './theme';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,oBAAoB,CAAC;AAE5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { jsx as r, jsxs as b } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef as u } from "react";
|
|
3
|
+
function m(...t) {
|
|
4
|
+
return t.filter(Boolean).join(" ");
|
|
5
|
+
}
|
|
6
|
+
function $({
|
|
7
|
+
size: t = "xl",
|
|
8
|
+
as: c,
|
|
9
|
+
className: n,
|
|
10
|
+
children: a,
|
|
11
|
+
...o
|
|
12
|
+
}) {
|
|
13
|
+
const e = c ?? "div", i = m("magi-container", `magi-container--${t}`, n);
|
|
14
|
+
return /* @__PURE__ */ r(e, { className: i, ...o, children: a });
|
|
15
|
+
}
|
|
16
|
+
function C({
|
|
17
|
+
spacing: t = "lg",
|
|
18
|
+
surface: c = "default",
|
|
19
|
+
fullWidth: n = !1,
|
|
20
|
+
as: a,
|
|
21
|
+
className: o,
|
|
22
|
+
children: e,
|
|
23
|
+
...i
|
|
24
|
+
}) {
|
|
25
|
+
const s = a ?? "section", g = m(
|
|
26
|
+
"magi-section",
|
|
27
|
+
`magi-section--${t}`,
|
|
28
|
+
`magi-section--${c}`,
|
|
29
|
+
n && "magi-section--fullWidth",
|
|
30
|
+
o
|
|
31
|
+
);
|
|
32
|
+
return /* @__PURE__ */ r(s, { className: g, ...i, children: e });
|
|
33
|
+
}
|
|
34
|
+
function N({
|
|
35
|
+
direction: t = "column",
|
|
36
|
+
gap: c = "4",
|
|
37
|
+
align: n = "stretch",
|
|
38
|
+
wrap: a = !0,
|
|
39
|
+
as: o,
|
|
40
|
+
className: e,
|
|
41
|
+
style: i,
|
|
42
|
+
children: s,
|
|
43
|
+
...g
|
|
44
|
+
}) {
|
|
45
|
+
const f = o ?? "div", l = t === "row" && !a ? { flexWrap: "nowrap" } : void 0, d = m(
|
|
46
|
+
"magi-stack",
|
|
47
|
+
t === "row" && "magi-stack--row",
|
|
48
|
+
`magi-stack--gap-${c}`,
|
|
49
|
+
`magi-stack--align-${n}`,
|
|
50
|
+
e
|
|
51
|
+
);
|
|
52
|
+
return /* @__PURE__ */ r(f, { className: d, style: { ...l, ...i }, ...g, children: s });
|
|
53
|
+
}
|
|
54
|
+
const w = u(
|
|
55
|
+
function({
|
|
56
|
+
variant: c = "primary",
|
|
57
|
+
size: n = "md",
|
|
58
|
+
loading: a = !1,
|
|
59
|
+
disabled: o,
|
|
60
|
+
className: e,
|
|
61
|
+
children: i,
|
|
62
|
+
type: s,
|
|
63
|
+
...g
|
|
64
|
+
}, f) {
|
|
65
|
+
const l = m(
|
|
66
|
+
"magi-button",
|
|
67
|
+
`magi-button--${c}`,
|
|
68
|
+
`magi-button--${n}`,
|
|
69
|
+
a && "magi-button--loading",
|
|
70
|
+
e
|
|
71
|
+
);
|
|
72
|
+
return /* @__PURE__ */ r(
|
|
73
|
+
"button",
|
|
74
|
+
{
|
|
75
|
+
ref: f,
|
|
76
|
+
className: l,
|
|
77
|
+
type: s ?? "button",
|
|
78
|
+
disabled: o || a,
|
|
79
|
+
"aria-busy": a || void 0,
|
|
80
|
+
...g,
|
|
81
|
+
children: i
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
), y = u(function({ variant: c = "default", padding: n = "md", className: a, children: o, ...e }, i) {
|
|
86
|
+
const s = m(
|
|
87
|
+
"magi-card",
|
|
88
|
+
`magi-card--${c}`,
|
|
89
|
+
`magi-card--padding-${n}`,
|
|
90
|
+
a
|
|
91
|
+
);
|
|
92
|
+
return /* @__PURE__ */ r("div", { ref: i, className: s, ...e, children: o });
|
|
93
|
+
}), x = u(function({ variant: c = "neutral", dot: n = !1, className: a, children: o, ...e }, i) {
|
|
94
|
+
const s = m(
|
|
95
|
+
"magi-badge",
|
|
96
|
+
`magi-badge--${c}`,
|
|
97
|
+
a
|
|
98
|
+
);
|
|
99
|
+
return /* @__PURE__ */ b("span", { ref: i, className: s, ...e, children: [
|
|
100
|
+
n ? /* @__PURE__ */ r("span", { className: "magi-badge__dot", "aria-hidden": "true" }) : null,
|
|
101
|
+
o
|
|
102
|
+
] });
|
|
103
|
+
}), p = {
|
|
104
|
+
green: {
|
|
105
|
+
"--magi-accent": "#00c853",
|
|
106
|
+
"--magi-accent-hover": "#00e676",
|
|
107
|
+
"--magi-accent-soft": "rgba(0, 200, 83, 0.08)",
|
|
108
|
+
"--magi-accent-contrast": "#050505"
|
|
109
|
+
},
|
|
110
|
+
cyan: {
|
|
111
|
+
"--magi-accent": "#38bdf8",
|
|
112
|
+
"--magi-accent-hover": "#7dd3fc",
|
|
113
|
+
"--magi-accent-soft": "rgba(56, 189, 248, 0.08)",
|
|
114
|
+
"--magi-accent-contrast": "#050505"
|
|
115
|
+
},
|
|
116
|
+
violet: {
|
|
117
|
+
"--magi-accent": "#8b5cf6",
|
|
118
|
+
"--magi-accent-hover": "#a78bfa",
|
|
119
|
+
"--magi-accent-soft": "rgba(139, 92, 246, 0.08)",
|
|
120
|
+
"--magi-accent-contrast": "#f5f5f7"
|
|
121
|
+
},
|
|
122
|
+
amber: {
|
|
123
|
+
"--magi-accent": "#f59e0b",
|
|
124
|
+
"--magi-accent-hover": "#fbbf24",
|
|
125
|
+
"--magi-accent-soft": "rgba(245, 158, 11, 0.08)",
|
|
126
|
+
"--magi-accent-contrast": "#050505"
|
|
127
|
+
},
|
|
128
|
+
white: {
|
|
129
|
+
"--magi-accent": "#ffffff",
|
|
130
|
+
"--magi-accent-hover": "#f5f5f7",
|
|
131
|
+
"--magi-accent-soft": "rgba(255, 255, 255, 0.08)",
|
|
132
|
+
"--magi-accent-contrast": "#050505"
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
function k({
|
|
136
|
+
accent: t = "green",
|
|
137
|
+
name: c,
|
|
138
|
+
tokens: n,
|
|
139
|
+
children: a
|
|
140
|
+
}) {
|
|
141
|
+
const e = { ...p[t], ...n };
|
|
142
|
+
return /* @__PURE__ */ r("div", { "data-magi-product": c, style: e, children: a });
|
|
143
|
+
}
|
|
144
|
+
export {
|
|
145
|
+
x as Badge,
|
|
146
|
+
w as Button,
|
|
147
|
+
y as Card,
|
|
148
|
+
$ as Container,
|
|
149
|
+
k as ProductTheme,
|
|
150
|
+
C as Section,
|
|
151
|
+
N as Stack
|
|
152
|
+
};
|
|
153
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/utils/classnames.ts","../src/layout/Container.tsx","../src/layout/Section.tsx","../src/layout/Stack.tsx","../src/components/Button/Button.tsx","../src/components/Card/Card.tsx","../src/components/Badge/Badge.tsx","../src/theme.tsx"],"sourcesContent":["/** Join truthy class strings with a space. */\nexport function cx(...parts: Array<string | false | null | undefined>): string {\n return parts.filter(Boolean).join(' ');\n}","import type { ElementType, HTMLAttributes, ReactNode } from 'react';\nimport { cx } from '../utils/classnames';\n\nexport type ContainerSize = 'sm' | 'md' | 'lg' | 'xl' | 'wide' | 'full';\n\nexport interface ContainerProps extends HTMLAttributes<HTMLElement> {\n /** Maximum width at desktop. Default: `xl` (1200px). */\n size?: ContainerSize;\n /** Override the rendered tag. Default: `div`. */\n as?: ElementType;\n children?: ReactNode;\n}\n\n/**\n * Container — centers content and constrains max-width.\n *\n * @example\n * <Container size=\"lg\">...</Container>\n */\nexport function Container({\n size = 'xl',\n as,\n className,\n children,\n ...rest\n}: ContainerProps) {\n const Component = (as ?? 'div') as ElementType;\n const cls = cx('magi-container', `magi-container--${size}`, className);\n return (\n <Component className={cls} {...rest}>\n {children}\n </Component>\n );\n}\n","import type { ElementType, HTMLAttributes, ReactNode } from 'react';\nimport { cx } from '../utils/classnames';\n\nexport type SectionSpacing = 'sm' | 'md' | 'lg' | 'xl';\nexport type SectionSurface = 'default' | 'raised' | 'elevated';\n\nexport interface SectionProps extends HTMLAttributes<HTMLElement> {\n /** Vertical padding scale. Default: `lg`. */\n spacing?: SectionSpacing;\n /** Background surface. Default: `default` (transparent). */\n surface?: SectionSurface;\n /** Drop the inner Container padding. Useful for full-bleed content. */\n fullWidth?: boolean;\n /** Override the rendered tag. Default: `section`. */\n as?: ElementType;\n children?: ReactNode;\n}\n\n/**\n * Section — page-level vertical rhythm primitive.\n *\n * @example\n * <Section spacing=\"xl\" surface=\"default\">...</Section>\n */\nexport function Section({\n spacing = 'lg',\n surface = 'default',\n fullWidth = false,\n as,\n className,\n children,\n ...rest\n}: SectionProps) {\n const Component = (as ?? 'section') as ElementType;\n const cls = cx(\n 'magi-section',\n `magi-section--${spacing}`,\n `magi-section--${surface}`,\n fullWidth && 'magi-section--fullWidth',\n className,\n );\n return (\n <Component className={cls} {...rest}>\n {children}\n </Component>\n );\n}\n","import type { ElementType, HTMLAttributes, ReactNode } from 'react';\nimport { cx } from '../utils/classnames';\n\nexport type StackGap =\n | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '8' | '10' | '12' | '16';\nexport type StackAlign = 'start' | 'center' | 'end' | 'stretch';\n\nexport interface StackProps extends HTMLAttributes<HTMLElement> {\n /** Layout direction. Default: vertical (column). */\n direction?: 'row' | 'column';\n /** Gap token. Default: `4` (16px). */\n gap?: StackGap;\n /** Cross-axis alignment. Default: `stretch`. */\n align?: StackAlign;\n /** Allow wrapping when `direction=\"row\"`. Default: true. */\n wrap?: boolean;\n as?: ElementType;\n children?: ReactNode;\n}\n\n/**\n * Stack — vertical or horizontal flex primitive with semantic gap tokens.\n *\n * @example\n * <Stack gap=\"6\" align=\"center\">...</Stack>\n * <Stack direction=\"row\" gap=\"3\">...</Stack>\n */\nexport function Stack({\n direction = 'column',\n gap = '4',\n align = 'stretch',\n wrap = true,\n as,\n className,\n style,\n children,\n ...rest\n}: StackProps) {\n const Component = (as ?? 'div') as ElementType;\n const wrapStyle =\n direction === 'row' && !wrap ? { flexWrap: 'nowrap' as const } : undefined;\n const cls = cx(\n 'magi-stack',\n direction === 'row' && 'magi-stack--row',\n `magi-stack--gap-${gap}`,\n `magi-stack--align-${align}`,\n className,\n );\n\n return (\n <Component className={cls} style={{ ...wrapStyle, ...style }} {...rest}>\n {children}\n </Component>\n );\n}\n","import { forwardRef, type ButtonHTMLAttributes } from 'react';\nimport { cx } from '../../utils/classnames';\n\nexport type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger';\nexport type ButtonSize = 'sm' | 'md' | 'lg';\n\nexport interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** Visual style. Default: `primary`. */\n variant?: ButtonVariant;\n /** Height + padding tier. Default: `md`. */\n size?: ButtonSize;\n /** Show a spinner and disable interaction. */\n loading?: boolean;\n}\n\n/**\n * Button — the canonical MAGI action element.\n *\n * Pill-shaped, four variants (primary/secondary/ghost/danger), three sizes.\n * Use `primary` for the dominant action on a page; `secondary` for supporting\n * actions; `ghost` for inline/tertiary; `danger` for destructive intent.\n *\n * @example\n * <Button variant=\"primary\" onClick={...}>Save</Button>\n * <Button variant=\"secondary\">Cancel</Button>\n */\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n function Button(\n {\n variant = 'primary',\n size = 'md',\n loading = false,\n disabled,\n className,\n children,\n type,\n ...rest\n },\n ref,\n ) {\n const cls = cx(\n 'magi-button',\n `magi-button--${variant}`,\n `magi-button--${size}`,\n loading && 'magi-button--loading',\n className,\n );\n\n return (\n <button\n ref={ref}\n className={cls}\n type={type ?? 'button'}\n disabled={disabled || loading}\n aria-busy={loading || undefined}\n {...rest}\n >\n {children}\n </button>\n );\n },\n);\n","import { forwardRef, type HTMLAttributes, type ReactNode } from 'react';\nimport { cx } from '../../utils/classnames';\n\nexport type CardVariant = 'default' | 'elevated' | 'interactive';\nexport type CardPadding = 'none' | 'sm' | 'md' | 'lg';\n\nexport interface CardProps extends HTMLAttributes<HTMLDivElement> {\n /** Visual emphasis. Default: `default`. `interactive` adds hover state. */\n variant?: CardVariant;\n /** Inner padding. Default: `md`. */\n padding?: CardPadding;\n children?: ReactNode;\n}\n\n/**\n * Card — minimal dark surface with subtle border. Three variants:\n * default (flat), elevated (more contrast), interactive (hover state).\n *\n * @example\n * <Card variant=\"elevated\">...</Card>\n * <Card variant=\"interactive\" onClick={...}>...</Card>\n */\nexport const Card = forwardRef<HTMLDivElement, CardProps>(function Card(\n { variant = 'default', padding = 'md', className, children, ...rest },\n ref,\n) {\n const cls = cx(\n 'magi-card',\n `magi-card--${variant}`,\n `magi-card--padding-${padding}`,\n className,\n );\n return (\n <div ref={ref} className={cls} {...rest}>\n {children}\n </div>\n );\n});\n","import { forwardRef, type HTMLAttributes, type ReactNode } from 'react';\nimport { cx } from '../../utils/classnames';\n\nexport type BadgeVariant = 'neutral' | 'accent' | 'success' | 'warning' | 'error';\n\nexport interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {\n /** Color/meaning. Default: `neutral`. */\n variant?: BadgeVariant;\n /** Show a leading colored dot. */\n dot?: boolean;\n children?: ReactNode;\n}\n\n/**\n * Badge — compact status / metadata label.\n *\n * @example\n * <Badge variant=\"accent\">128K context</Badge>\n * <Badge variant=\"success\" dot>Online</Badge>\n */\nexport const Badge = forwardRef<HTMLSpanElement, BadgeProps>(function Badge(\n { variant = 'neutral', dot = false, className, children, ...rest },\n ref,\n) {\n const cls = cx(\n 'magi-badge',\n `magi-badge--${variant}`,\n className,\n );\n return (\n <span ref={ref} className={cls} {...rest}>\n {dot ? <span className=\"magi-badge__dot\" aria-hidden=\"true\" /> : null}\n {children}\n </span>\n );\n});\n","/**\n * ProductTheme — allows a product to override the accent (and accent-muted\n * / accent-soft / accent-contrast) without touching typography, spacing, or\n * base surfaces. Implemented as CSS custom properties on a scoped selector;\n * components consume the variables and re-render automatically.\n *\n * Usage:\n * <ProductTheme accent=\"cyan\" name=\"token-factory\">\n * <App />\n * </ProductTheme>\n *\n * Or set them manually in CSS:\n * [data-magi-product='token-factory'] {\n * --magi-accent: #38bdf8;\n * --magi-accent-hover: #7dd3fc;\n * --magi-accent-soft: rgba(56, 189, 248, 0.08);\n * }\n */\n\nimport type { CSSProperties, ReactNode } from 'react';\n\nexport type ProductAccent =\n | 'green' // default — MAGI core\n | 'cyan' // Token Factory Initializr\n | 'violet' // API product\n | 'amber' // Agent product\n | 'white'; // monochrome MAGI\n\ninterface AccentTokens {\n '--magi-accent': string;\n '--magi-accent-hover': string;\n '--magi-accent-soft': string;\n '--magi-accent-contrast': string;\n}\n\nconst ACCENT_PRESETS: Record<ProductAccent, AccentTokens> = {\n green: {\n '--magi-accent': '#00c853',\n '--magi-accent-hover': '#00e676',\n '--magi-accent-soft': 'rgba(0, 200, 83, 0.08)',\n '--magi-accent-contrast': '#050505',\n },\n cyan: {\n '--magi-accent': '#38bdf8',\n '--magi-accent-hover': '#7dd3fc',\n '--magi-accent-soft': 'rgba(56, 189, 248, 0.08)',\n '--magi-accent-contrast': '#050505',\n },\n violet: {\n '--magi-accent': '#8b5cf6',\n '--magi-accent-hover': '#a78bfa',\n '--magi-accent-soft': 'rgba(139, 92, 246, 0.08)',\n '--magi-accent-contrast': '#f5f5f7',\n },\n amber: {\n '--magi-accent': '#f59e0b',\n '--magi-accent-hover': '#fbbf24',\n '--magi-accent-soft': 'rgba(245, 158, 11, 0.08)',\n '--magi-accent-contrast': '#050505',\n },\n white: {\n '--magi-accent': '#ffffff',\n '--magi-accent-hover': '#f5f5f7',\n '--magi-accent-soft': 'rgba(255, 255, 255, 0.08)',\n '--magi-accent-contrast': '#050505',\n },\n};\n\nexport interface ProductThemeProps {\n /** Accent preset. Default: `green`. */\n accent?: ProductAccent;\n /** Optional product identifier. Sets `data-magi-product=\"<name>\"`. */\n name?: string;\n /** Override individual token values; merged with the preset. */\n tokens?: Partial<CSSProperties>;\n children?: ReactNode;\n}\n\n/**\n * ProductTheme — overrides the MAGI accent for a subtree.\n *\n * Renders a `<div>` with `data-magi-product` and the accent tokens applied as\n * inline custom properties. All children consume the new accent automatically.\n */\nexport function ProductTheme({\n accent = 'green',\n name,\n tokens,\n children,\n}: ProductThemeProps) {\n const preset = ACCENT_PRESETS[accent];\n const style: CSSProperties = { ...preset, ...tokens };\n\n return (\n <div data-magi-product={name} style={style}>\n {children}\n </div>\n );\n}"],"names":["cx","parts","Container","size","as","className","children","rest","Component","cls","Section","spacing","surface","fullWidth","Stack","direction","gap","align","wrap","style","wrapStyle","jsx","Button","forwardRef","variant","loading","disabled","type","ref","Card","padding","Badge","dot","ACCENT_PRESETS","ProductTheme","accent","name","tokens"],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ElementType, HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export type ContainerSize = 'sm' | 'md' | 'lg' | 'xl' | 'wide' | 'full';
|
|
3
|
+
export interface ContainerProps extends HTMLAttributes<HTMLElement> {
|
|
4
|
+
/** Maximum width at desktop. Default: `xl` (1200px). */
|
|
5
|
+
size?: ContainerSize;
|
|
6
|
+
/** Override the rendered tag. Default: `div`. */
|
|
7
|
+
as?: ElementType;
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Container — centers content and constrains max-width.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* <Container size="lg">...</Container>
|
|
15
|
+
*/
|
|
16
|
+
export declare function Container({ size, as, className, children, ...rest }: ContainerProps): import("react").JSX.Element;
|
|
17
|
+
//# sourceMappingURL=Container.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Container.d.ts","sourceRoot":"","sources":["../../src/layout/Container.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGpE,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;AAExE,MAAM,WAAW,cAAe,SAAQ,cAAc,CAAC,WAAW,CAAC;IACjE,wDAAwD;IACxD,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,iDAAiD;IACjD,EAAE,CAAC,EAAE,WAAW,CAAC;IACjB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,EACxB,IAAW,EACX,EAAE,EACF,SAAS,EACT,QAAQ,EACR,GAAG,IAAI,EACR,EAAE,cAAc,+BAQhB"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ElementType, HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export type SectionSpacing = 'sm' | 'md' | 'lg' | 'xl';
|
|
3
|
+
export type SectionSurface = 'default' | 'raised' | 'elevated';
|
|
4
|
+
export interface SectionProps extends HTMLAttributes<HTMLElement> {
|
|
5
|
+
/** Vertical padding scale. Default: `lg`. */
|
|
6
|
+
spacing?: SectionSpacing;
|
|
7
|
+
/** Background surface. Default: `default` (transparent). */
|
|
8
|
+
surface?: SectionSurface;
|
|
9
|
+
/** Drop the inner Container padding. Useful for full-bleed content. */
|
|
10
|
+
fullWidth?: boolean;
|
|
11
|
+
/** Override the rendered tag. Default: `section`. */
|
|
12
|
+
as?: ElementType;
|
|
13
|
+
children?: ReactNode;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Section — page-level vertical rhythm primitive.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* <Section spacing="xl" surface="default">...</Section>
|
|
20
|
+
*/
|
|
21
|
+
export declare function Section({ spacing, surface, fullWidth, as, className, children, ...rest }: SectionProps): import("react").JSX.Element;
|
|
22
|
+
//# sourceMappingURL=Section.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Section.d.ts","sourceRoot":"","sources":["../../src/layout/Section.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGpE,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AACvD,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE/D,MAAM,WAAW,YAAa,SAAQ,cAAc,CAAC,WAAW,CAAC;IAC/D,6CAA6C;IAC7C,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,uEAAuE;IACvE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,qDAAqD;IACrD,EAAE,CAAC,EAAE,WAAW,CAAC;IACjB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,EACtB,OAAc,EACd,OAAmB,EACnB,SAAiB,EACjB,EAAE,EACF,SAAS,EACT,QAAQ,EACR,GAAG,IAAI,EACR,EAAE,YAAY,+BAcd"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ElementType, HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export type StackGap = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '8' | '10' | '12' | '16';
|
|
3
|
+
export type StackAlign = 'start' | 'center' | 'end' | 'stretch';
|
|
4
|
+
export interface StackProps extends HTMLAttributes<HTMLElement> {
|
|
5
|
+
/** Layout direction. Default: vertical (column). */
|
|
6
|
+
direction?: 'row' | 'column';
|
|
7
|
+
/** Gap token. Default: `4` (16px). */
|
|
8
|
+
gap?: StackGap;
|
|
9
|
+
/** Cross-axis alignment. Default: `stretch`. */
|
|
10
|
+
align?: StackAlign;
|
|
11
|
+
/** Allow wrapping when `direction="row"`. Default: true. */
|
|
12
|
+
wrap?: boolean;
|
|
13
|
+
as?: ElementType;
|
|
14
|
+
children?: ReactNode;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Stack — vertical or horizontal flex primitive with semantic gap tokens.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* <Stack gap="6" align="center">...</Stack>
|
|
21
|
+
* <Stack direction="row" gap="3">...</Stack>
|
|
22
|
+
*/
|
|
23
|
+
export declare function Stack({ direction, gap, align, wrap, as, className, style, children, ...rest }: StackProps): import("react").JSX.Element;
|
|
24
|
+
//# sourceMappingURL=Stack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Stack.d.ts","sourceRoot":"","sources":["../../src/layout/Stack.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGpE,MAAM,MAAM,QAAQ,GAChB,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AACvE,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,CAAC;AAEhE,MAAM,WAAW,UAAW,SAAQ,cAAc,CAAC,WAAW,CAAC;IAC7D,oDAAoD;IACpD,SAAS,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IAC7B,sCAAsC;IACtC,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,gDAAgD;IAChD,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,EAAE,CAAC,EAAE,WAAW,CAAC;IACjB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,EACpB,SAAoB,EACpB,GAAS,EACT,KAAiB,EACjB,IAAW,EACX,EAAE,EACF,SAAS,EACT,KAAK,EACL,QAAQ,EACR,GAAG,IAAI,EACR,EAAE,UAAU,+BAiBZ"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { Container } from './Container';
|
|
2
|
+
export type { ContainerProps, ContainerSize } from './Container';
|
|
3
|
+
export { Section } from './Section';
|
|
4
|
+
export type { SectionProps, SectionSpacing, SectionSurface } from './Section';
|
|
5
|
+
export { Stack } from './Stack';
|
|
6
|
+
export type { StackProps, StackGap, StackAlign } from './Stack';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/layout/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE9E,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/styles.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--magi-bg-base: #000000;--magi-bg-raised: #1d1d1f;--magi-bg-card: rgba(255, 255, 255, .04);--magi-bg-card-hover: rgba(255, 255, 255, .06);--magi-surface: #0a0a0a;--magi-surface-elevated: #171717;--magi-text-primary: #f5f5f7;--magi-text-secondary: #86868b;--magi-text-tertiary: #6e6e73;--magi-text-inverse: #050505;--magi-border: rgba(255, 255, 255, .08);--magi-border-strong: rgba(255, 255, 255, .14);--magi-accent: #00c853;--magi-accent-hover: #00e676;--magi-accent-soft: rgba(0, 200, 83, .08);--magi-accent-contrast: #050505;--magi-selection-bg: rgba(0, 200, 83, .3);--magi-selection-fg: #f5f5f7;--magi-success: #30d158;--magi-warning: #ff9f0a;--magi-error: #ff453a;--magi-scrollbar-thumb: rgba(255, 255, 255, .18);--magi-scrollbar-thumb-hover: rgba(255, 255, 255, .32)}:root{--magi-font-sans: Inter, -apple-system, BlinkMacSystemFont, "SF Pro Display", "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", Arial, system-ui, sans-serif;--magi-font-mono: "SFMono-Regular", "Cascadia Code", "Roboto Mono", Menlo, Consolas, monospace;--magi-font-size-display: 4.5rem;--magi-font-size-h1: 3rem;--magi-font-size-h2: 2.25rem;--magi-font-size-h3: 1.5rem;--magi-font-size-h4: 1.25rem;--magi-font-size-body-lg: 1.125rem;--magi-font-size-body: 1rem;--magi-font-size-body-sm: .875rem;--magi-font-size-label: .8125rem;--magi-font-size-caption: .75rem;--magi-font-size-code: .875rem;--magi-font-weight-light: 300;--magi-font-weight-normal: 400;--magi-font-weight-medium: 500;--magi-font-weight-semibold: 600;--magi-font-weight-bold: 700;--magi-tracking-tightest: -.045em;--magi-tracking-tighter: -.03em;--magi-tracking-tight: -.01em;--magi-tracking-normal: 0;--magi-tracking-wide: .05em;--magi-tracking-widest: .18em;--magi-leading-display: 1.05;--magi-leading-tight: 1.15;--magi-leading-snug: 1.3;--magi-leading-normal: 1.5;--magi-leading-relaxed: 1.625}:root{--magi-space-0: 0;--magi-space-1: .25rem;--magi-space-2: .5rem;--magi-space-3: .75rem;--magi-space-4: 1rem;--magi-space-5: 1.25rem;--magi-space-6: 1.5rem;--magi-space-8: 2rem;--magi-space-10: 2.5rem;--magi-space-12: 3rem;--magi-space-16: 4rem;--magi-space-20: 5rem;--magi-space-24: 6rem;--magi-space-32: 8rem;--magi-space-40: 10rem}:root{--magi-radius-sm: 6px;--magi-radius-md: 10px;--magi-radius-lg: 14px;--magi-radius-xl: 20px;--magi-radius-2xl: 28px;--magi-radius-full: 999px}:root{--magi-duration-fast: .12s;--magi-duration-normal: .2s;--magi-duration-slow: .32s;--magi-ease-standard: cubic-bezier(.2, 0, 0, 1);--magi-ease-emphasized: cubic-bezier(.3, 0, 0, 1);--magi-ease-out: cubic-bezier(0, 0, .2, 1)}@media (prefers-reduced-motion: reduce){:root{--magi-duration-fast: .01ms;--magi-duration-normal: .01ms;--magi-duration-slow: .01ms}}:root{--magi-bp-sm: 640px;--magi-bp-md: 768px;--magi-bp-lg: 1024px;--magi-bp-xl: 1280px;--magi-bp-2xl: 1536px}:root{--magi-z-base: 0;--magi-z-raised: 10;--magi-z-dropdown: 100;--magi-z-sticky: 200;--magi-z-overlay: 300;--magi-z-modal: 400;--magi-z-toast: 500;--magi-container-sm: 640px;--magi-container-md: 768px;--magi-container-lg: 1024px;--magi-container-xl: 1200px;--magi-container-wide: 1400px;--magi-shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);--magi-shadow-md: 0 4px 12px rgba(0, 0, 0, .5);--magi-shadow-lg: 0 12px 32px rgba(0, 0, 0, .6);--magi-focus-ring: 0 0 0 2px var(--magi-bg-base), 0 0 0 4px var(--magi-accent)}[data-magi-app]{box-sizing:border-box;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}[data-magi-app],[data-magi-app] *,[data-magi-app] *:before,[data-magi-app] *:after{box-sizing:inherit}body[data-magi-app]{margin:0}[data-magi-app] img,[data-magi-app] svg,[data-magi-app] video{max-width:100%;display:block}[data-magi-app] button{font:inherit;color:inherit;border:0;padding:0;cursor:pointer}[data-magi-app] a{color:inherit;text-decoration:none}[data-magi-app] input,[data-magi-app] textarea,[data-magi-app] select{font:inherit;color:inherit}[data-magi-app]{font-family:var(--magi-font-sans);font-size:var(--magi-font-size-body);font-weight:var(--magi-font-weight-normal);line-height:var(--magi-leading-normal);color:var(--magi-text-primary);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility}body[data-magi-app]{background-color:var(--magi-bg-base);background-image:radial-gradient(ellipse 80% 50% at 50% -10%,rgba(255,255,255,.06),transparent 60%),linear-gradient(180deg,var(--magi-bg-raised) 0%,var(--magi-bg-base) 35%);background-attachment:fixed;min-height:100vh}[data-magi-app] ::selection{background:var(--magi-selection-bg);color:var(--magi-selection-fg)}html:has(body[data-magi-app]){scrollbar-width:thin;scrollbar-color:var(--magi-scrollbar-thumb) transparent}body[data-magi-app] ::-webkit-scrollbar{width:6px;height:6px}body[data-magi-app] ::-webkit-scrollbar-track{background:transparent}body[data-magi-app] ::-webkit-scrollbar-thumb{background:#fff0;border-radius:var(--magi-radius-full);transition:background var(--magi-duration-slow) var(--magi-ease-out)}body[data-magi-app]:hover ::-webkit-scrollbar-thumb,body[data-magi-app][data-scrolling] ::-webkit-scrollbar-thumb{background:var(--magi-scrollbar-thumb)}body[data-magi-app]:hover ::-webkit-scrollbar-thumb:hover,body[data-magi-app][data-scrolling] ::-webkit-scrollbar-thumb:hover{background:var(--magi-scrollbar-thumb-hover)}[data-magi-app] a{transition:color var(--magi-duration-normal) var(--magi-ease-standard)}[data-magi-app] :focus-visible{outline:none;box-shadow:var(--magi-focus-ring);border-radius:var(--magi-radius-sm)}@media (prefers-reduced-motion: reduce){[data-magi-app] *,[data-magi-app] *:before,[data-magi-app] *:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}html:has(body[data-magi-app]){scroll-behavior:auto}}[data-magi-app] .magi-display{font-size:var(--magi-font-size-display);font-weight:var(--magi-font-weight-semibold);letter-spacing:var(--magi-tracking-tightest);line-height:var(--magi-leading-display);color:var(--magi-text-primary);text-wrap:balance}[data-magi-app] .magi-h1{font-size:var(--magi-font-size-h1);font-weight:var(--magi-font-weight-semibold);letter-spacing:var(--magi-tracking-tighter);line-height:var(--magi-leading-tight);color:var(--magi-text-primary)}[data-magi-app] .magi-h2{font-size:var(--magi-font-size-h2);font-weight:var(--magi-font-weight-semibold);letter-spacing:var(--magi-tracking-tighter);line-height:var(--magi-leading-tight);color:var(--magi-text-primary)}[data-magi-app] .magi-h3{font-size:var(--magi-font-size-h3);font-weight:var(--magi-font-weight-semibold);letter-spacing:var(--magi-tracking-tight);line-height:var(--magi-leading-snug);color:var(--magi-text-primary)}[data-magi-app] .magi-h4{font-size:var(--magi-font-size-h4);font-weight:var(--magi-font-weight-medium);letter-spacing:var(--magi-tracking-tight);line-height:var(--magi-leading-snug);color:var(--magi-text-primary)}[data-magi-app] .magi-body-lg{font-size:var(--magi-font-size-body-lg);line-height:var(--magi-leading-relaxed);color:var(--magi-text-secondary)}[data-magi-app] .magi-body{font-size:var(--magi-font-size-body);line-height:var(--magi-leading-normal);color:var(--magi-text-secondary)}[data-magi-app] .magi-body-sm{font-size:var(--magi-font-size-body-sm);line-height:var(--magi-leading-normal);color:var(--magi-text-secondary)}[data-magi-app] .magi-label{font-size:var(--magi-font-size-label);font-weight:var(--magi-font-weight-medium);line-height:var(--magi-leading-snug);color:var(--magi-text-primary)}[data-magi-app] .magi-caption{font-size:var(--magi-font-size-caption);line-height:var(--magi-leading-snug);color:var(--magi-text-tertiary)}[data-magi-app] .magi-eyebrow{font-size:var(--magi-font-size-body-sm);font-weight:var(--magi-font-weight-medium);text-transform:uppercase;letter-spacing:var(--magi-tracking-widest);color:var(--magi-accent)}[data-magi-app] .magi-code{font-family:var(--magi-font-mono);font-size:var(--magi-font-size-code);line-height:var(--magi-leading-snug);color:var(--magi-text-primary);background:var(--magi-surface);padding:0 var(--magi-space-1);border-radius:var(--magi-radius-sm);border:1px solid var(--magi-border)}body[data-magi-app] .magi-container{margin-inline:auto;padding-inline:var(--magi-space-6);width:100%}@media (min-width: 768px){.magi-container{padding-inline:var(--magi-space-8)}}body[data-magi-app] .magi-container--sm{max-width:var(--magi-container-sm)}body[data-magi-app] .magi-container--md{max-width:var(--magi-container-md)}body[data-magi-app] .magi-container--lg{max-width:var(--magi-container-lg)}body[data-magi-app] .magi-container--xl{max-width:var(--magi-container-xl)}body[data-magi-app] .magi-container--wide{max-width:var(--magi-container-wide)}body[data-magi-app] .magi-container--full{max-width:100%}body[data-magi-app] .magi-section{width:100%;position:relative}body[data-magi-app] .magi-section--sm{padding-block:var(--magi-space-12)}body[data-magi-app] .magi-section--md{padding-block:var(--magi-space-20)}body[data-magi-app] .magi-section--lg,body[data-magi-app] .magi-section--xl{padding-block:var(--magi-space-32)}@media (min-width: 768px){.magi-section--xl{padding-block:var(--magi-space-40)}}body[data-magi-app] .magi-section--default{background:transparent}body[data-magi-app] .magi-section--raised{background-color:var(--magi-surface);border-block:1px solid var(--magi-border)}body[data-magi-app] .magi-section--elevated{background-color:var(--magi-surface-elevated)}body[data-magi-app] .magi-section--fullWidth{padding-inline:0}body[data-magi-app] .magi-stack{display:flex;flex-direction:column;min-width:0}body[data-magi-app] .magi-stack--row{display:flex;flex-direction:row;flex-wrap:wrap;min-width:0}body[data-magi-app] .magi-stack--gap-0{gap:var(--magi-space-0)}body[data-magi-app] .magi-stack--gap-1{gap:var(--magi-space-1)}body[data-magi-app] .magi-stack--gap-2{gap:var(--magi-space-2)}body[data-magi-app] .magi-stack--gap-3{gap:var(--magi-space-3)}body[data-magi-app] .magi-stack--gap-4{gap:var(--magi-space-4)}body[data-magi-app] .magi-stack--gap-5{gap:var(--magi-space-5)}body[data-magi-app] .magi-stack--gap-6{gap:var(--magi-space-6)}body[data-magi-app] .magi-stack--gap-8{gap:var(--magi-space-8)}body[data-magi-app] .magi-stack--gap-10{gap:var(--magi-space-10)}body[data-magi-app] .magi-stack--gap-12{gap:var(--magi-space-12)}body[data-magi-app] .magi-stack--gap-16{gap:var(--magi-space-16)}body[data-magi-app] .magi-stack--align-start{align-items:flex-start}body[data-magi-app] .magi-stack--align-center{align-items:center}body[data-magi-app] .magi-stack--align-end{align-items:flex-end}body[data-magi-app] .magi-stack--align-stretch{align-items:stretch}body[data-magi-app] .magi-button{display:inline-flex;align-items:center;justify-content:center;gap:var(--magi-space-2);font-family:inherit;font-weight:var(--magi-font-weight-medium);line-height:1;text-align:center;white-space:nowrap;cursor:pointer;border-radius:var(--magi-radius-full);border:1px solid transparent;transition:background-color var(--magi-duration-normal) var(--magi-ease-standard),color var(--magi-duration-normal) var(--magi-ease-standard),border-color var(--magi-duration-normal) var(--magi-ease-standard),transform var(--magi-duration-fast) var(--magi-ease-standard);-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;text-decoration:none;background-color:transparent}.magi-button:disabled,body[data-magi-app] .magi-button[aria-disabled=true]{cursor:not-allowed;opacity:.5;pointer-events:none}body[data-magi-app] .magi-button:active:not(:disabled){transform:scale(.98)}body[data-magi-app] .magi-button--primary{background-color:var(--magi-accent);color:var(--magi-accent-contrast);border-color:var(--magi-accent)}body[data-magi-app] .magi-button--primary:hover:not(:disabled){background-color:var(--magi-accent-hover);border-color:var(--magi-accent-hover)}body[data-magi-app] .magi-button--secondary{background-color:transparent;color:var(--magi-text-primary);border-color:var(--magi-border-strong)}body[data-magi-app] .magi-button--secondary:hover:not(:disabled){background-color:#ffffff0d;border-color:#ffffff4d}body[data-magi-app] .magi-button--ghost{background-color:transparent;color:var(--magi-text-primary);border-color:transparent}body[data-magi-app] .magi-button--ghost:hover:not(:disabled){background-color:#ffffff0f}body[data-magi-app] .magi-button--danger{background-color:var(--magi-error);color:var(--magi-text-primary);border-color:var(--magi-error)}body[data-magi-app] .magi-button--danger:hover:not(:disabled){filter:brightness(1.1)}body[data-magi-app] .magi-button--sm{font-size:var(--magi-font-size-body-sm);padding:var(--magi-space-2) var(--magi-space-4);min-height:32px}body[data-magi-app] .magi-button--md{font-size:var(--magi-font-size-body-sm);padding:var(--magi-space-3) var(--magi-space-6);min-height:40px}body[data-magi-app] .magi-button--lg{font-size:var(--magi-font-size-body);padding:var(--magi-space-4) var(--magi-space-8);min-height:48px}body[data-magi-app] .magi-button--loading{position:relative;color:transparent!important;pointer-events:none}body[data-magi-app] .magi-button--loading:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;margin:auto;width:1em;height:1em;border:2px solid currentColor;border-top-color:transparent;border-radius:var(--magi-radius-full);animation:magiButtonSpin .8s linear infinite;color:var(--magi-accent-contrast)}.magi-button--primary.magi-button--loading:after,body[data-magi-app] .magi-button--danger.magi-button--loading:after{color:var(--magi-text-primary)}@keyframes magiButtonSpin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion: reduce){.magi-button--loading:after{animation-duration:1.6s}}body[data-magi-app] .magi-card{background-color:var(--magi-bg-card);border:1px solid var(--magi-border);border-radius:var(--magi-radius-xl);color:var(--magi-text-primary);transition:background-color var(--magi-duration-slow) var(--magi-ease-standard),border-color var(--magi-duration-slow) var(--magi-ease-standard),transform var(--magi-duration-normal) var(--magi-ease-standard);position:relative}body[data-magi-app] .magi-card--padding-none{padding:0}body[data-magi-app] .magi-card--padding-sm{padding:var(--magi-space-4)}body[data-magi-app] .magi-card--padding-md{padding:var(--magi-space-6)}body[data-magi-app] .magi-card--padding-lg{padding:var(--magi-space-8)}body[data-magi-app] .magi-card--elevated{background-color:var(--magi-surface-elevated);border-color:var(--magi-border);box-shadow:var(--magi-shadow-md)}body[data-magi-app] .magi-card--interactive{cursor:pointer;text-decoration:none}body[data-magi-app] .magi-card--interactive:hover{background-color:var(--magi-bg-card-hover);border-color:var(--magi-border-strong)}body[data-magi-app] .magi-card--interactive:active{transform:translateY(1px)}@media (prefers-reduced-motion: reduce){.magi-card,.magi-card--interactive{transition:none}.magi-card--interactive:active{transform:none}}body[data-magi-app] .magi-badge{display:inline-flex;align-items:center;gap:var(--magi-space-2);font-family:inherit;font-size:var(--magi-font-size-caption);font-weight:var(--magi-font-weight-medium);line-height:1;padding:var(--magi-space-2) var(--magi-space-3);border-radius:var(--magi-radius-full);border:1px solid transparent;white-space:nowrap;-webkit-user-select:none;user-select:none}body[data-magi-app] .magi-badge__dot{display:inline-block;width:6px;height:6px;border-radius:var(--magi-radius-full);background:currentColor;flex-shrink:0}body[data-magi-app] .magi-badge--neutral{background:#ffffff0f;color:var(--magi-text-secondary);border-color:var(--magi-border)}body[data-magi-app] .magi-badge--accent{background:var(--magi-accent-soft);color:var(--magi-accent);border-color:color-mix(in srgb,var(--magi-accent) 25%,transparent)}body[data-magi-app] .magi-badge--success{background:#30d1581f;color:var(--magi-success);border-color:#30d1584d}body[data-magi-app] .magi-badge--warning{background:#ff9f0a1f;color:var(--magi-warning);border-color:#ff9f0a4d}body[data-magi-app] .magi-badge--error{background:#ff453a1f;color:var(--magi-error);border-color:#ff453a4d}
|
package/dist/theme.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProductTheme — allows a product to override the accent (and accent-muted
|
|
3
|
+
* / accent-soft / accent-contrast) without touching typography, spacing, or
|
|
4
|
+
* base surfaces. Implemented as CSS custom properties on a scoped selector;
|
|
5
|
+
* components consume the variables and re-render automatically.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* <ProductTheme accent="cyan" name="token-factory">
|
|
9
|
+
* <App />
|
|
10
|
+
* </ProductTheme>
|
|
11
|
+
*
|
|
12
|
+
* Or set them manually in CSS:
|
|
13
|
+
* [data-magi-product='token-factory'] {
|
|
14
|
+
* --magi-accent: #38bdf8;
|
|
15
|
+
* --magi-accent-hover: #7dd3fc;
|
|
16
|
+
* --magi-accent-soft: rgba(56, 189, 248, 0.08);
|
|
17
|
+
* }
|
|
18
|
+
*/
|
|
19
|
+
import type { CSSProperties, ReactNode } from 'react';
|
|
20
|
+
export type ProductAccent = 'green' | 'cyan' | 'violet' | 'amber' | 'white';
|
|
21
|
+
export interface ProductThemeProps {
|
|
22
|
+
/** Accent preset. Default: `green`. */
|
|
23
|
+
accent?: ProductAccent;
|
|
24
|
+
/** Optional product identifier. Sets `data-magi-product="<name>"`. */
|
|
25
|
+
name?: string;
|
|
26
|
+
/** Override individual token values; merged with the preset. */
|
|
27
|
+
tokens?: Partial<CSSProperties>;
|
|
28
|
+
children?: ReactNode;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* ProductTheme — overrides the MAGI accent for a subtree.
|
|
32
|
+
*
|
|
33
|
+
* Renders a `<div>` with `data-magi-product` and the accent tokens applied as
|
|
34
|
+
* inline custom properties. All children consume the new accent automatically.
|
|
35
|
+
*/
|
|
36
|
+
export declare function ProductTheme({ accent, name, tokens, children, }: ProductThemeProps): import("react").JSX.Element;
|
|
37
|
+
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtD,MAAM,MAAM,aAAa,GACrB,OAAO,GACP,MAAM,GACN,QAAQ,GACR,OAAO,GACP,OAAO,CAAC;AA0CZ,MAAM,WAAW,iBAAiB;IAChC,uCAAuC;IACvC,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,sEAAsE;IACtE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAChC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,EAC3B,MAAgB,EAChB,IAAI,EACJ,MAAM,EACN,QAAQ,GACT,EAAE,iBAAiB,+BASnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classnames.d.ts","sourceRoot":"","sources":["../../src/utils/classnames.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,wBAAgB,EAAE,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,MAAM,CAE7E"}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tokyo3rdhq/magi-design-system",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shared visual foundation for the MAGI product family — dark-first, near-monochrome, restrained.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"src/styles",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"import": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./styles.css": "./dist/styles.css"
|
|
20
|
+
},
|
|
21
|
+
"sideEffects": [
|
|
22
|
+
"**/*.css"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "vite build && tsc -p tsconfig.build.json",
|
|
26
|
+
"dev": "vite build --watch",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
28
|
+
"clean": "rm -rf dist"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"react": "^18.0.0",
|
|
32
|
+
"react-dom": "^18.0.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/react": "^18.3.12",
|
|
36
|
+
"@types/react-dom": "^18.3.1",
|
|
37
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
38
|
+
"react": "^18.3.1",
|
|
39
|
+
"react-dom": "^18.3.1",
|
|
40
|
+
"typescript": "^5.7.2",
|
|
41
|
+
"vite": "^5.4.11"
|
|
42
|
+
},
|
|
43
|
+
"keywords": [
|
|
44
|
+
"magi",
|
|
45
|
+
"design-system",
|
|
46
|
+
"ui",
|
|
47
|
+
"react",
|
|
48
|
+
"dark-theme",
|
|
49
|
+
"tokens",
|
|
50
|
+
"components"
|
|
51
|
+
],
|
|
52
|
+
"license": "MIT",
|
|
53
|
+
"homepage": "https://github.com/tokyo3rdhq/magi-design-system#readme",
|
|
54
|
+
"repository": {
|
|
55
|
+
"type": "git",
|
|
56
|
+
"url": "git+https://github.com/tokyo3rdhq/magi-design-system.git",
|
|
57
|
+
"directory": "packages/design-system"
|
|
58
|
+
},
|
|
59
|
+
"bugs": {
|
|
60
|
+
"url": "https://github.com/tokyo3rdhq/magi-design-system/issues"
|
|
61
|
+
},
|
|
62
|
+
"publishConfig": {
|
|
63
|
+
"access": "public",
|
|
64
|
+
"registry": "https://registry.npmjs.org/"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/* MAGI Design System — Single entry point for consumers
|
|
2
|
+
*
|
|
3
|
+
* import '@magi/design-system/styles.css';
|
|
4
|
+
*
|
|
5
|
+
* Imports tokens + foundation + all component styles. Place on the application
|
|
6
|
+
* root. Components reference CSS variables only — they do not introduce new
|
|
7
|
+
* global class names.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
@import "../tokens/index.css";
|
|
11
|
+
@import "../foundation/index.css";
|
|
12
|
+
@import "../layout/Container.css";
|
|
13
|
+
@import "../layout/Section.css";
|
|
14
|
+
@import "../layout/Stack.css";
|
|
15
|
+
@import "../components/Button/Button.css";
|
|
16
|
+
@import "../components/Card/Card.css";
|
|
17
|
+
@import "../components/Badge/Badge.css";
|