@tenerife.music/ui 2.1.0 → 2.3.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 +89 -46
- package/dist/extensions/next/index.cjs +345 -8
- package/dist/extensions/next/index.d.cts +2 -2
- package/dist/extensions/next/index.d.ts +2 -2
- package/dist/extensions/next/index.mjs +344 -7
- package/dist/{index-EBreLTkZ.d.cts → index-BJmxMoZt.d.ts} +957 -1505
- package/dist/{index-EBreLTkZ.d.ts → index-mSVbRT6m.d.cts} +957 -1505
- package/dist/index.cjs +6168 -4207
- package/dist/index.d.cts +2655 -1304
- package/dist/index.d.ts +2655 -1304
- package/dist/index.mjs +6137 -4200
- package/dist/preset.cjs +57 -33
- package/dist/preset.mjs +57 -33
- package/dist/styles.css +177 -167
- package/dist/theme/index.cjs +420 -308
- package/dist/theme/index.d.cts +5 -82
- package/dist/theme/index.d.ts +5 -82
- package/dist/theme/index.mjs +413 -301
- package/dist/tokens/index.cjs +80 -80
- package/dist/tokens/index.d.cts +2 -651
- package/dist/tokens/index.d.ts +2 -651
- package/dist/tokens/index.mjs +80 -80
- package/dist/typography-DbkAGIlC.d.cts +1513 -0
- package/dist/typography-DbkAGIlC.d.ts +1513 -0
- package/package.json +11 -16
- package/dist/colors-vOdfG8tM.d.cts +0 -298
- package/dist/colors-vOdfG8tM.d.ts +0 -298
package/README.md
CHANGED
|
@@ -3,18 +3,18 @@
|
|
|
3
3
|
**Token-driven UI architecture for long-living React products**
|
|
4
4
|
Strict. Predictable. Built for system-level consistency.
|
|
5
5
|
|
|
6
|
-

|
|
7
|
+

|
|
8
8
|

|
|
9
9
|

|
|
10
10
|

|
|
11
11
|

|
|
12
12
|
|
|
13
|
-
**Current Release:** [v2.
|
|
13
|
+
**Current Release:** [v2.3.0](CHANGELOG.md#230) (npm)
|
|
14
14
|
**Next Release:** [Unreleased] — See [CHANGELOG](CHANGELOG.md#unreleased)
|
|
15
15
|
|
|
16
16
|
<p align="center">
|
|
17
|
-
<img src="
|
|
17
|
+
<img src=".github/banner.png" width="100%" alt="TUI Banner" />
|
|
18
18
|
</p>
|
|
19
19
|
|
|
20
20
|
<p align="center">
|
|
@@ -102,6 +102,12 @@ export default function App() {
|
|
|
102
102
|
> 📖 **Note:** This example demonstrates API shape only. Understanding the system
|
|
103
103
|
> requires familiarity with tokens, variants, and architectural constraints.
|
|
104
104
|
|
|
105
|
+
### Fonts (Optional)
|
|
106
|
+
|
|
107
|
+
TUI ships with **system font fallbacks** by default. We do **not** bundle or require fonts.
|
|
108
|
+
If you want canonical visuals, you can load Inter / Clash Display / Satoshi in your app,
|
|
109
|
+
but this is optional.
|
|
110
|
+
|
|
105
111
|
---
|
|
106
112
|
|
|
107
113
|
## ✨ Key Characteristics
|
|
@@ -119,22 +125,25 @@ export default function App() {
|
|
|
119
125
|
|
|
120
126
|
## 📚 Documentation
|
|
121
127
|
|
|
122
|
-
| Document
|
|
123
|
-
|
|
|
124
|
-
| **
|
|
125
|
-
|
|
|
126
|
-
|
|
|
127
|
-
| **
|
|
128
|
-
| **
|
|
129
|
-
| **
|
|
130
|
-
|
|
|
128
|
+
| Document | Description | Link |
|
|
129
|
+
| ------------------------ | --------------------------------------- | -------------------------------------------------------------------------------------- |
|
|
130
|
+
| **Architecture Context** | Single source of truth (IMMUTABLE) | [docs/ARCHITECTURE_CONTEXT.md](docs/ARCHITECTURE_CONTEXT.md) |
|
|
131
|
+
| **Foundation Lock** | Authoritative source of truth | [docs/architecture/FOUNDATION_LOCK.md](docs/architecture/FOUNDATION_LOCK.md) |
|
|
132
|
+
| **Architecture Lock** | Canonical architectural constraints | [docs/architecture/ARCHITECTURE_LOCK.md](docs/architecture/ARCHITECTURE_LOCK.md) |
|
|
133
|
+
| **A11Y Lock** | Accessibility system lock (WCAG 2.1 AA) | [docs/architecture/locks/A11Y_LOCK.md](docs/architecture/locks/A11Y_LOCK.md) |
|
|
134
|
+
| **Tokens Overview** | Design token structure and philosophy | [docs/reference/TOKENS_OVERVIEW.md](docs/reference/TOKENS_OVERVIEW.md) |
|
|
135
|
+
| **Theme System** | Theme architecture and tooling | [docs/theming/THEME_SYSTEM_ARCHITECTURE.md](docs/theming/THEME_SYSTEM_ARCHITECTURE.md) |
|
|
136
|
+
| **API Reference** | Public API documentation | [docs/reference/API_REFERENCE.md](docs/reference/API_REFERENCE.md) |
|
|
137
|
+
| **Components Inventory** | Complete component list | [docs/reference/COMPONENTS_INVENTORY.md](docs/reference/COMPONENTS_INVENTORY.md) |
|
|
138
|
+
| **Documentation Hub** | Complete documentation index | [docs/README.md](docs/README.md) |
|
|
139
|
+
| Storybook | Component examples and contracts | Run `pnpm storybook` locally |
|
|
131
140
|
|
|
132
141
|
### Development Resources
|
|
133
142
|
|
|
134
143
|
- **Component Creation**: [Extension Component Creation Checklist](docs/workflows/tasks/COMPONENT_CREATION_CHECKLIST.md)
|
|
135
|
-
- **CLI Generator**: Use `pnpm
|
|
144
|
+
- **CLI Generator**: Use `pnpm component:generate -- <ComponentName> [--category <category>]` to generate component scaffold
|
|
136
145
|
- See checklist for complete process and requirements
|
|
137
|
-
- **Component Refactoring**: [Component Refactoring Pipeline (18A)](docs/workflows/foundation/
|
|
146
|
+
- **Component Refactoring**: [Component Refactoring Pipeline (18A)](docs/workflows/foundation/FOUNDATION_STEP_PIPELINE.md)
|
|
138
147
|
- **Canonical process** for reviewing, improving, and validating existing components
|
|
139
148
|
- Mandatory 12-step pipeline (STEP 0-11) for Foundation and Extension components
|
|
140
149
|
- See pipeline for complete refactoring process and requirements
|
|
@@ -146,35 +155,69 @@ export default function App() {
|
|
|
146
155
|
|
|
147
156
|
## 🏗 Architecture Overview
|
|
148
157
|
|
|
149
|
-
|
|
158
|
+
TenerifeUI uses a **5-layer architecture** with strict boundaries:
|
|
159
|
+
|
|
160
|
+
### Foundation Layer (Locked & Closed)
|
|
161
|
+
|
|
162
|
+
**Status:** ✅ **LOCKED** (Foundation Closed - 2026-01-02)
|
|
163
|
+
**Purpose:** Tokens and theme system only
|
|
164
|
+
|
|
165
|
+
The Foundation layer is **immutable** and **closed**. All Foundation Authority Contracts are **LOCKED**.
|
|
166
|
+
|
|
167
|
+
**Reference:** [FOUNDATION_LOCK.md](docs/architecture/FOUNDATION_LOCK.md)
|
|
168
|
+
|
|
169
|
+
### Primitives Layer (Locked)
|
|
170
|
+
|
|
171
|
+
**Status:** ✅ **CANONICAL**
|
|
172
|
+
**Purpose:** Atomic UI components, no orchestration
|
|
173
|
+
|
|
174
|
+
**Location:** `src/PRIMITIVES/`
|
|
175
|
+
|
|
176
|
+
**Examples:**
|
|
177
|
+
|
|
178
|
+
- Button, Input, Textarea, Checkbox, Radio, Switch
|
|
179
|
+
- Badge, Alert, Heading, Text, Icon, Image
|
|
180
|
+
- Progress, Skeleton, Divider, Field, Label, Link
|
|
181
|
+
|
|
182
|
+
**Rule:** PRIMITIVES **MUST NOT** contain orchestration logic or overlay infrastructure.
|
|
183
|
+
|
|
184
|
+
### Composition Layer (Canonical)
|
|
185
|
+
|
|
186
|
+
**Status:** ✅ **CANONICAL**
|
|
187
|
+
**Purpose:** Layout, overlays, interaction orchestration
|
|
188
|
+
|
|
189
|
+
**Location:** `src/COMPOSITION/`
|
|
190
|
+
|
|
191
|
+
**Sub-layers:**
|
|
192
|
+
|
|
193
|
+
- `COMPOSITION/overlays/` - All overlay components (Modal, Popover, ContextMenu, Toast, Dialog, Tooltip)
|
|
194
|
+
- `COMPOSITION/layout/` - Layout components (Card, Flex, Grid, Stack, Container, Section)
|
|
195
|
+
- `COMPOSITION/navigation/` - Navigation components (Tabs, Breadcrumbs, Pagination)
|
|
196
|
+
- `COMPOSITION/controls/` - Control components (Select)
|
|
197
|
+
|
|
198
|
+
**Rule:** All overlays **MUST** live in COMPOSITION layer only.
|
|
199
|
+
|
|
200
|
+
### Patterns Layer (Canonical)
|
|
201
|
+
|
|
202
|
+
**Status:** ✅ **CANONICAL**
|
|
203
|
+
**Purpose:** Business/UI patterns (no overlays)
|
|
150
204
|
|
|
151
|
-
|
|
152
|
-
There is exactly **one Foundation component per category**.
|
|
205
|
+
**Location:** `src/PATTERNS/`
|
|
153
206
|
|
|
154
|
-
|
|
155
|
-
- Tabs
|
|
156
|
-
- Select
|
|
157
|
-
- ContextMenu
|
|
158
|
-
- Toast
|
|
159
|
-
- Button (**FINAL LOCK**)
|
|
207
|
+
**Examples:**
|
|
160
208
|
|
|
161
|
-
|
|
209
|
+
- Cards, Lists, Tables, Filters, Menus, States
|
|
162
210
|
|
|
163
|
-
|
|
164
|
-
- expose token-driven visual APIs
|
|
165
|
-
- are backward-compatible and locked
|
|
211
|
+
**Rule:** PATTERNS **MUST NOT** define overlay primitives or overlay infrastructure.
|
|
166
212
|
|
|
167
|
-
###
|
|
213
|
+
### Domain Layer (Canonical)
|
|
168
214
|
|
|
169
|
-
|
|
170
|
-
|
|
215
|
+
**Status:** ✅ **CANONICAL**
|
|
216
|
+
**Purpose:** App-specific sections
|
|
171
217
|
|
|
172
|
-
|
|
218
|
+
**Location:** `src/DOMAIN/`
|
|
173
219
|
|
|
174
|
-
|
|
175
|
-
- Card / Badge
|
|
176
|
-
- Layout primitives (Stack, Grid, Container)
|
|
177
|
-
- Data and feedback components
|
|
220
|
+
**Reference:** [ARCHITECTURE_STATE.md](docs/architecture/ARCHITECTURE_STATE.md) for complete layer definitions
|
|
178
221
|
|
|
179
222
|
---
|
|
180
223
|
|
|
@@ -205,7 +248,7 @@ TUI provides **build-time CLI tooling** for generating and validating themes.
|
|
|
205
248
|
**Key Points:**
|
|
206
249
|
|
|
207
250
|
- Themes are generated at **build time**, not runtime
|
|
208
|
-
- All themes live in `src/
|
|
251
|
+
- All themes live in `src/themes/` (canonical path)
|
|
209
252
|
- Validation is **mandatory** — invalid themes cannot be committed (CI enforced)
|
|
210
253
|
- UI library **never generates themes** — it only consumes pre-generated CSS
|
|
211
254
|
|
|
@@ -216,7 +259,7 @@ TUI provides **build-time CLI tooling** for generating and validating themes.
|
|
|
216
259
|
pnpm theme:generate -- --palette my-brand --base-color "210 40% 50%" --modes light,dark
|
|
217
260
|
|
|
218
261
|
# Validate themes
|
|
219
|
-
pnpm theme:validate -- src/
|
|
262
|
+
pnpm theme:validate -- src/themes/*.css
|
|
220
263
|
```
|
|
221
264
|
|
|
222
265
|
**Documentation:**
|
|
@@ -275,25 +318,25 @@ See [CHANGELOG Version Canon Rules](CHANGELOG.md#version-canon-rules) and [Relea
|
|
|
275
318
|
|
|
276
319
|
To create a new Extension component:
|
|
277
320
|
|
|
278
|
-
1. **Check Component Needs**: Review [Component Needs Inventory](docs/tasks/COMPONENT_NEEDS_INVENTORY.md) to ensure the component is needed
|
|
279
|
-
2. **Use
|
|
280
|
-
3. **Follow Checklist**: Complete all items in [Extension Component Creation Checklist](docs/tasks/
|
|
321
|
+
1. **Check Component Needs**: Review [Component Needs Inventory](docs/workflows/tasks/COMPONENT_NEEDS_INVENTORY.md) to ensure the component is needed
|
|
322
|
+
2. **Use CLI Generator**: Run `pnpm component:generate -- <ComponentName> [--category <category>]`
|
|
323
|
+
3. **Follow Checklist**: Complete all items in [Extension Component Creation Checklist](docs/workflows/tasks/COMPONENT_CREATION_CHECKLIST.md)
|
|
281
324
|
4. **Reference Examples**: Use [Extension Component Examples](docs/reference/EXTENSION_COMPONENT_EXAMPLES.md) as patterns
|
|
282
325
|
|
|
283
326
|
### Requesting Components
|
|
284
327
|
|
|
285
328
|
To request a new component:
|
|
286
329
|
|
|
287
|
-
1. **Create GitHub Issue**: Use the [Component Request template](.github/ISSUE_TEMPLATE/component-request.md)
|
|
330
|
+
1. **Create GitHub Issue**: Use the [Component Request template](.github/ISSUE_TEMPLATE/component-request.md) (if available)
|
|
288
331
|
2. **Provide Use Case**: Describe the specific use case and frequency of need
|
|
289
332
|
3. **Document Workaround**: Explain current solution and pain points
|
|
290
|
-
4. **Wait for Review**: Requests are reviewed
|
|
333
|
+
4. **Wait for Review**: Requests are reviewed according to project governance (see [Feedback Collection Process](docs/workflows/tasks/FEEDBACK_COLLECTION_PROCESS.md))
|
|
291
334
|
|
|
292
335
|
### Development Tools
|
|
293
336
|
|
|
294
|
-
- **Component Analysis**: `
|
|
295
|
-
- **Feedback Collection**: `
|
|
296
|
-
- **Component Generator**: `
|
|
337
|
+
- **Component Analysis**: `pnpm component:analyze` - Analyzes codebase for component patterns
|
|
338
|
+
- **Feedback Collection**: `pnpm feedback:collect` - Collects and analyzes usage feedback
|
|
339
|
+
- **Component Generator**: `pnpm component:generate -- <Name> [--category <category>]` - Generates component scaffold
|
|
297
340
|
|
|
298
341
|
---
|
|
299
342
|
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var NextLink = require('next/link');
|
|
4
|
-
var
|
|
5
|
-
var
|
|
4
|
+
var React2 = require('react');
|
|
5
|
+
var clsx = require('clsx');
|
|
6
|
+
var tailwindMerge = require('tailwind-merge');
|
|
6
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
+
var classVarianceAuthority = require('class-variance-authority');
|
|
7
9
|
|
|
8
10
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
11
|
|
|
@@ -26,9 +28,182 @@ function _interopNamespace(e) {
|
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
var NextLink__default = /*#__PURE__*/_interopDefault(NextLink);
|
|
29
|
-
var
|
|
31
|
+
var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
|
|
30
32
|
|
|
31
33
|
// src/EXTENSIONS/next/NextLinkAdapter.tsx
|
|
34
|
+
|
|
35
|
+
// src/FOUNDATION/lib/responsive-props.ts
|
|
36
|
+
function isResponsiveValue(value) {
|
|
37
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
38
|
+
}
|
|
39
|
+
function getBaseValue(value) {
|
|
40
|
+
if (value === void 0 || value === null) {
|
|
41
|
+
return void 0;
|
|
42
|
+
}
|
|
43
|
+
if (isResponsiveValue(value)) {
|
|
44
|
+
return value.base;
|
|
45
|
+
}
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
function getSpacingCSSVar(key) {
|
|
49
|
+
if (key === "none") {
|
|
50
|
+
return `var(--spacing-none)`;
|
|
51
|
+
}
|
|
52
|
+
if (key.includes("-") && !key.startsWith("--")) {
|
|
53
|
+
const parts = key.split("-");
|
|
54
|
+
if (parts.length >= 2) {
|
|
55
|
+
const type = parts[0];
|
|
56
|
+
const size = parts.slice(1).join("-");
|
|
57
|
+
if (type && ["section", "container", "grid", "stack", "component"].includes(type)) {
|
|
58
|
+
return `var(--layout-${type}-${size})`;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (key.includes(".")) {
|
|
63
|
+
const normalizedKey = key.replace(".", "-");
|
|
64
|
+
return `var(--spacing-${normalizedKey})`;
|
|
65
|
+
}
|
|
66
|
+
return `var(--spacing-${key})`;
|
|
67
|
+
}
|
|
68
|
+
function getRadiusCSSVar(key) {
|
|
69
|
+
return `var(--radius-${key})`;
|
|
70
|
+
}
|
|
71
|
+
function getColorCSSVar(key) {
|
|
72
|
+
if (key.startsWith("hsl(")) {
|
|
73
|
+
return key;
|
|
74
|
+
}
|
|
75
|
+
if (key.startsWith("var(")) {
|
|
76
|
+
return key;
|
|
77
|
+
}
|
|
78
|
+
const legacyMap = {
|
|
79
|
+
background: "--tm-surface-base",
|
|
80
|
+
foreground: "--tm-text-primary",
|
|
81
|
+
card: "--tm-surface-raised",
|
|
82
|
+
"card-foreground": "--tm-text-primary",
|
|
83
|
+
popover: "--tm-surface-overlay",
|
|
84
|
+
"popover-foreground": "--tm-text-primary",
|
|
85
|
+
muted: "--tm-muted",
|
|
86
|
+
"muted-foreground": "--tm-muted-foreground",
|
|
87
|
+
destructive: "--tm-destructive",
|
|
88
|
+
"destructive-foreground": "--tm-destructive-foreground",
|
|
89
|
+
border: "--tm-border-default",
|
|
90
|
+
ring: "--tm-focus-ring",
|
|
91
|
+
input: "--tm-border-default",
|
|
92
|
+
primary: "--tm-primary",
|
|
93
|
+
"primary-foreground": "--tm-primary-foreground",
|
|
94
|
+
secondary: "--tm-secondary",
|
|
95
|
+
"secondary-foreground": "--tm-secondary-foreground",
|
|
96
|
+
accent: "--tm-accent",
|
|
97
|
+
"accent-foreground": "--tm-accent-foreground",
|
|
98
|
+
disabled: "--tm-disabled",
|
|
99
|
+
"disabled-foreground": "--tm-disabled-foreground",
|
|
100
|
+
success: "--tm-status-success",
|
|
101
|
+
"success-foreground": "--tm-status-success-foreground",
|
|
102
|
+
error: "--tm-status-error",
|
|
103
|
+
"error-foreground": "--tm-status-error-foreground",
|
|
104
|
+
warning: "--tm-status-warning",
|
|
105
|
+
"warning-foreground": "--tm-status-warning-foreground",
|
|
106
|
+
info: "--tm-status-info",
|
|
107
|
+
"info-foreground": "--tm-status-info-foreground"
|
|
108
|
+
};
|
|
109
|
+
const mapped = legacyMap[key];
|
|
110
|
+
if (mapped) {
|
|
111
|
+
return `var(${mapped})`;
|
|
112
|
+
}
|
|
113
|
+
if (key.startsWith("surface-")) {
|
|
114
|
+
const suffix = key.replace("surface-", "");
|
|
115
|
+
if (suffix === "base") return "var(--tm-surface-base)";
|
|
116
|
+
if (suffix === "overlay" || suffix === "glass") return "var(--tm-surface-overlay)";
|
|
117
|
+
if (suffix.startsWith("elevated") || suffix === "raised") return "var(--tm-surface-raised)";
|
|
118
|
+
}
|
|
119
|
+
if (key.startsWith("text-")) {
|
|
120
|
+
const suffix = key.replace("text-", "");
|
|
121
|
+
if (suffix === "primary") return "var(--tm-text-primary)";
|
|
122
|
+
if (suffix === "secondary") return "var(--tm-text-secondary)";
|
|
123
|
+
if (suffix === "muted" || suffix === "tertiary") return "var(--tm-text-muted)";
|
|
124
|
+
if (suffix === "inverse") return "var(--tm-text-inverse)";
|
|
125
|
+
}
|
|
126
|
+
return `var(--${key})`;
|
|
127
|
+
}
|
|
128
|
+
function cn(...inputs) {
|
|
129
|
+
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
130
|
+
}
|
|
131
|
+
function getBaseValue2(value) {
|
|
132
|
+
return getBaseValue(value);
|
|
133
|
+
}
|
|
134
|
+
function shadowToClass(value) {
|
|
135
|
+
if (!value || value === "none") return void 0;
|
|
136
|
+
return `shadow-${value}`;
|
|
137
|
+
}
|
|
138
|
+
var BoxComponent = React2__namespace.forwardRef(
|
|
139
|
+
({
|
|
140
|
+
as: Component = "div",
|
|
141
|
+
px,
|
|
142
|
+
py,
|
|
143
|
+
m,
|
|
144
|
+
mx,
|
|
145
|
+
my,
|
|
146
|
+
mt,
|
|
147
|
+
mr,
|
|
148
|
+
mb,
|
|
149
|
+
ml,
|
|
150
|
+
radius,
|
|
151
|
+
shadow,
|
|
152
|
+
bg,
|
|
153
|
+
className,
|
|
154
|
+
style,
|
|
155
|
+
...props
|
|
156
|
+
}, ref) => {
|
|
157
|
+
const pxValue = getBaseValue2(px);
|
|
158
|
+
const pyValue = getBaseValue2(py);
|
|
159
|
+
const mValue = getBaseValue2(m);
|
|
160
|
+
const mxValue = getBaseValue2(mx);
|
|
161
|
+
const myValue = getBaseValue2(my);
|
|
162
|
+
const mtValue = getBaseValue2(mt);
|
|
163
|
+
const mrValue = getBaseValue2(mr);
|
|
164
|
+
const mbValue = getBaseValue2(mb);
|
|
165
|
+
const mlValue = getBaseValue2(ml);
|
|
166
|
+
const radiusValue = getBaseValue2(radius);
|
|
167
|
+
const bgValue = getBaseValue2(bg);
|
|
168
|
+
const inlineStyles = {
|
|
169
|
+
...pxValue !== void 0 && {
|
|
170
|
+
paddingLeft: getSpacingCSSVar(String(pxValue)),
|
|
171
|
+
paddingRight: getSpacingCSSVar(String(pxValue))
|
|
172
|
+
},
|
|
173
|
+
...pyValue !== void 0 && {
|
|
174
|
+
paddingTop: getSpacingCSSVar(String(pyValue)),
|
|
175
|
+
paddingBottom: getSpacingCSSVar(String(pyValue))
|
|
176
|
+
},
|
|
177
|
+
...mValue !== void 0 && { margin: getSpacingCSSVar(String(mValue)) },
|
|
178
|
+
...!m && mxValue !== void 0 && {
|
|
179
|
+
marginLeft: getSpacingCSSVar(String(mxValue)),
|
|
180
|
+
marginRight: getSpacingCSSVar(String(mxValue))
|
|
181
|
+
},
|
|
182
|
+
...!m && myValue !== void 0 && {
|
|
183
|
+
marginTop: getSpacingCSSVar(String(myValue)),
|
|
184
|
+
marginBottom: getSpacingCSSVar(String(myValue))
|
|
185
|
+
},
|
|
186
|
+
...!m && !my && mtValue !== void 0 && { marginTop: getSpacingCSSVar(String(mtValue)) },
|
|
187
|
+
...!m && !mx && mrValue !== void 0 && { marginRight: getSpacingCSSVar(String(mrValue)) },
|
|
188
|
+
...!m && !my && mbValue !== void 0 && { marginBottom: getSpacingCSSVar(String(mbValue)) },
|
|
189
|
+
...!m && !mx && mlValue !== void 0 && { marginLeft: getSpacingCSSVar(String(mlValue)) },
|
|
190
|
+
...radiusValue !== void 0 && { borderRadius: getRadiusCSSVar(radiusValue) },
|
|
191
|
+
...bgValue !== void 0 && { backgroundColor: getColorCSSVar(bgValue) },
|
|
192
|
+
...style
|
|
193
|
+
};
|
|
194
|
+
const classes = cn(
|
|
195
|
+
// Shadow
|
|
196
|
+
shadowToClass(shadow),
|
|
197
|
+
className
|
|
198
|
+
);
|
|
199
|
+
const ComponentAny = Component;
|
|
200
|
+
const finalStyle = Object.keys(inlineStyles).length > 0 || style ? { ...inlineStyles, ...style } : void 0;
|
|
201
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ComponentAny, { ref, className: classes, style: finalStyle, ...props });
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
BoxComponent.displayName = "Box";
|
|
205
|
+
var Box = BoxComponent;
|
|
206
|
+
Box.displayName = "Box";
|
|
32
207
|
var FORBIDDEN_SPACING_PATTERNS = [
|
|
33
208
|
// Raw color utilities (bg-red-500, text-blue-600, etc.)
|
|
34
209
|
// These are always forbidden as they bypass the color token system
|
|
@@ -505,9 +680,9 @@ var linkVariants = tokenCVA({
|
|
|
505
680
|
size: "md"
|
|
506
681
|
}
|
|
507
682
|
});
|
|
508
|
-
var Link =
|
|
683
|
+
var Link = React2__namespace.forwardRef(
|
|
509
684
|
({ variant, size, leftIcon, rightIcon, children, disabled, onClick, href, tabIndex, ...props }, ref) => {
|
|
510
|
-
const handleClick =
|
|
685
|
+
const handleClick = React2__namespace.useCallback(
|
|
511
686
|
(e) => {
|
|
512
687
|
if (disabled) {
|
|
513
688
|
e.preventDefault();
|
|
@@ -541,9 +716,142 @@ var Link = React__namespace.forwardRef(
|
|
|
541
716
|
}
|
|
542
717
|
);
|
|
543
718
|
Link.displayName = "Link";
|
|
544
|
-
|
|
545
|
-
|
|
719
|
+
|
|
720
|
+
// src/FOUNDATION/tokens/components/text.ts
|
|
721
|
+
var TEXT_TOKENS = {
|
|
722
|
+
/**
|
|
723
|
+
* Font sizes by text size variant
|
|
724
|
+
* Maps to foundation fontSize tokens
|
|
725
|
+
*/
|
|
726
|
+
fontSize: {
|
|
727
|
+
xs: "text-xs",
|
|
728
|
+
// Maps to fontSize.xs[0]
|
|
729
|
+
sm: "text-sm",
|
|
730
|
+
// Maps to fontSize.sm[0]
|
|
731
|
+
md: "text-base",
|
|
732
|
+
// Maps to fontSize.base[0]
|
|
733
|
+
lg: "text-lg",
|
|
734
|
+
// Maps to fontSize.lg[0]
|
|
735
|
+
xl: "text-xl"},
|
|
736
|
+
/**
|
|
737
|
+
* Font weights by weight variant
|
|
738
|
+
* Maps to foundation fontWeight tokens
|
|
739
|
+
*/
|
|
740
|
+
fontWeight: {
|
|
741
|
+
normal: "font-normal",
|
|
742
|
+
// Maps to fontWeight.normal (400)
|
|
743
|
+
medium: "font-medium",
|
|
744
|
+
// Maps to fontWeight.medium (500)
|
|
745
|
+
semibold: "font-semibold",
|
|
746
|
+
// Maps to fontWeight.semibold (600)
|
|
747
|
+
bold: "font-bold"
|
|
748
|
+
// Maps to fontWeight.bold (700)
|
|
749
|
+
}};
|
|
750
|
+
var TEXT_COLOR_CLASSES = {
|
|
751
|
+
primary: "text-[hsl(var(--tm-text-primary))]",
|
|
752
|
+
secondary: "text-[hsl(var(--tm-text-secondary))]",
|
|
753
|
+
tertiary: "text-[hsl(var(--tm-text-muted))]",
|
|
754
|
+
muted: "text-[hsl(var(--tm-text-muted))]",
|
|
755
|
+
inverse: "text-[hsl(var(--tm-text-inverse))]",
|
|
756
|
+
disabled: "text-[hsl(var(--tm-disabled-foreground))]",
|
|
757
|
+
success: "text-[hsl(var(--tm-status-success))]",
|
|
758
|
+
warning: "text-[hsl(var(--tm-status-warning))]",
|
|
759
|
+
error: "text-[hsl(var(--tm-status-error))]",
|
|
760
|
+
info: "text-[hsl(var(--tm-status-info))]"
|
|
761
|
+
};
|
|
762
|
+
var DEFAULT_SIZE = "md";
|
|
763
|
+
var DEFAULT_WEIGHT = "normal";
|
|
764
|
+
var textVariants = tokenCVA({
|
|
765
|
+
base: "text-[hsl(var(--tm-text-primary))]",
|
|
766
|
+
variants: {
|
|
767
|
+
size: {
|
|
768
|
+
xs: TEXT_TOKENS.fontSize.xs,
|
|
769
|
+
sm: TEXT_TOKENS.fontSize.sm,
|
|
770
|
+
md: TEXT_TOKENS.fontSize.md,
|
|
771
|
+
lg: TEXT_TOKENS.fontSize.lg,
|
|
772
|
+
xl: TEXT_TOKENS.fontSize.xl
|
|
773
|
+
},
|
|
774
|
+
weight: {
|
|
775
|
+
normal: TEXT_TOKENS.fontWeight.normal,
|
|
776
|
+
medium: TEXT_TOKENS.fontWeight.medium,
|
|
777
|
+
semibold: TEXT_TOKENS.fontWeight.semibold,
|
|
778
|
+
bold: TEXT_TOKENS.fontWeight.bold
|
|
779
|
+
},
|
|
780
|
+
// Role-based color variant (enforced via TypeScript generic)
|
|
781
|
+
color: {
|
|
782
|
+
primary: TEXT_COLOR_CLASSES.primary,
|
|
783
|
+
secondary: TEXT_COLOR_CLASSES.secondary,
|
|
784
|
+
tertiary: TEXT_COLOR_CLASSES.tertiary,
|
|
785
|
+
muted: TEXT_COLOR_CLASSES.muted,
|
|
786
|
+
inverse: TEXT_COLOR_CLASSES.inverse,
|
|
787
|
+
disabled: TEXT_COLOR_CLASSES.disabled,
|
|
788
|
+
success: TEXT_COLOR_CLASSES.success,
|
|
789
|
+
warning: TEXT_COLOR_CLASSES.warning,
|
|
790
|
+
error: TEXT_COLOR_CLASSES.error,
|
|
791
|
+
info: TEXT_COLOR_CLASSES.info
|
|
792
|
+
}
|
|
793
|
+
},
|
|
794
|
+
defaultVariants: {
|
|
795
|
+
size: DEFAULT_SIZE,
|
|
796
|
+
weight: DEFAULT_WEIGHT
|
|
797
|
+
}
|
|
798
|
+
});
|
|
799
|
+
var TextComponent = React2__namespace.forwardRef(
|
|
800
|
+
({ as = "span", size, weight, typographyRole: _typographyRole, color, ...props }, ref) => {
|
|
801
|
+
const Component = as;
|
|
802
|
+
const colorVariant = color ? { color } : void 0;
|
|
803
|
+
const className = textVariants({ size, weight, ...colorVariant });
|
|
804
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Component, { ref, className, ...props });
|
|
805
|
+
}
|
|
806
|
+
);
|
|
807
|
+
TextComponent.displayName = "Text";
|
|
808
|
+
var Text = TextComponent;
|
|
809
|
+
var NextLinkAdapter = React2__namespace.forwardRef(
|
|
810
|
+
({
|
|
811
|
+
href,
|
|
812
|
+
prefetch,
|
|
813
|
+
replace,
|
|
814
|
+
scroll,
|
|
815
|
+
shallow,
|
|
816
|
+
locale,
|
|
817
|
+
variant,
|
|
818
|
+
size,
|
|
819
|
+
leftIcon,
|
|
820
|
+
rightIcon,
|
|
821
|
+
disabled,
|
|
822
|
+
onClick,
|
|
823
|
+
target,
|
|
824
|
+
rel,
|
|
825
|
+
download,
|
|
826
|
+
tabIndex,
|
|
827
|
+
title,
|
|
828
|
+
role,
|
|
829
|
+
onFocus,
|
|
830
|
+
onBlur,
|
|
831
|
+
onMouseEnter,
|
|
832
|
+
onMouseLeave,
|
|
833
|
+
"aria-label": ariaLabel,
|
|
834
|
+
"aria-labelledby": ariaLabelledBy,
|
|
835
|
+
"aria-describedby": ariaDescribedBy,
|
|
836
|
+
"aria-current": ariaCurrent,
|
|
837
|
+
"aria-disabled": ariaDisabled,
|
|
838
|
+
children
|
|
839
|
+
}, ref) => {
|
|
546
840
|
const hrefString = typeof href === "string" ? href : href.pathname || String(href);
|
|
841
|
+
const finalAriaDisabled = disabled ? true : ariaDisabled;
|
|
842
|
+
const finalTabIndex = disabled ? tabIndex ?? -1 : tabIndex;
|
|
843
|
+
const className = linkVariants({ variant, size });
|
|
844
|
+
const handleClick = React2__namespace.useCallback(
|
|
845
|
+
(e) => {
|
|
846
|
+
if (disabled) {
|
|
847
|
+
e.preventDefault();
|
|
848
|
+
e.stopPropagation();
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
onClick?.(e);
|
|
852
|
+
},
|
|
853
|
+
[disabled, onClick]
|
|
854
|
+
);
|
|
547
855
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
548
856
|
NextLink__default.default,
|
|
549
857
|
{
|
|
@@ -553,7 +861,36 @@ var NextLinkAdapter = React__namespace.forwardRef(
|
|
|
553
861
|
scroll,
|
|
554
862
|
shallow,
|
|
555
863
|
locale,
|
|
556
|
-
children: /* @__PURE__ */ jsxRuntime.
|
|
864
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
865
|
+
Box,
|
|
866
|
+
{
|
|
867
|
+
as: "a",
|
|
868
|
+
ref,
|
|
869
|
+
className,
|
|
870
|
+
href: hrefString,
|
|
871
|
+
target,
|
|
872
|
+
rel,
|
|
873
|
+
download,
|
|
874
|
+
tabIndex: finalTabIndex,
|
|
875
|
+
title,
|
|
876
|
+
role,
|
|
877
|
+
onClick: handleClick,
|
|
878
|
+
onFocus,
|
|
879
|
+
onBlur,
|
|
880
|
+
onMouseEnter,
|
|
881
|
+
onMouseLeave,
|
|
882
|
+
"aria-label": ariaLabel,
|
|
883
|
+
"aria-labelledby": ariaLabelledBy,
|
|
884
|
+
"aria-describedby": ariaDescribedBy,
|
|
885
|
+
"aria-current": ariaCurrent,
|
|
886
|
+
"aria-disabled": finalAriaDisabled,
|
|
887
|
+
children: [
|
|
888
|
+
leftIcon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: LINK_TOKENS.iconWrapper, children: leftIcon }),
|
|
889
|
+
/* @__PURE__ */ jsxRuntime.jsx(Text, { as: "span", typographyRole: "link", size, children }),
|
|
890
|
+
rightIcon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: LINK_TOKENS.iconWrapper, children: rightIcon })
|
|
891
|
+
]
|
|
892
|
+
}
|
|
893
|
+
)
|
|
557
894
|
}
|
|
558
895
|
);
|
|
559
896
|
}
|
|
@@ -20,8 +20,8 @@ interface NextLinkAdapterProps extends Omit<LinkProps, "href"> {
|
|
|
20
20
|
/**
|
|
21
21
|
* NextLinkAdapter
|
|
22
22
|
*
|
|
23
|
-
* A compatibility adapter that bridges Next.js `next/link` with TenerifeUI
|
|
24
|
-
* This adapter
|
|
23
|
+
* A compatibility adapter that bridges Next.js `next/link` with TenerifeUI link tokens.
|
|
24
|
+
* This adapter renders a single <a> element as the child of NextLink.
|
|
25
25
|
* Next.js 13+ automatically handles <a> children without creating nested anchors.
|
|
26
26
|
*
|
|
27
27
|
* @example
|
|
@@ -20,8 +20,8 @@ interface NextLinkAdapterProps extends Omit<LinkProps, "href"> {
|
|
|
20
20
|
/**
|
|
21
21
|
* NextLinkAdapter
|
|
22
22
|
*
|
|
23
|
-
* A compatibility adapter that bridges Next.js `next/link` with TenerifeUI
|
|
24
|
-
* This adapter
|
|
23
|
+
* A compatibility adapter that bridges Next.js `next/link` with TenerifeUI link tokens.
|
|
24
|
+
* This adapter renders a single <a> element as the child of NextLink.
|
|
25
25
|
* Next.js 13+ automatically handles <a> children without creating nested anchors.
|
|
26
26
|
*
|
|
27
27
|
* @example
|