@marwes-ui/core 0.0.4 → 1.0.1
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/LICENSE +1 -1
- package/README.md +273 -64
- package/dist/index.d.ts +4543 -191
- package/dist/index.js +5377 -292
- package/dist/index.js.map +1 -1
- package/package.json +9 -6
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2026 Niklas Westman
|
|
3
|
+
Copyright (c) 2026 Niklas Westman, Martino Ognissanti and contributors
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -1,68 +1,277 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
- `
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
Core
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img alt="Marwes Design System" src="https://raw.githubusercontent.com/niklas-westman/marwes/main/.github/assets/banner-light.png" width="100%" style="border-radius: 40px;">
|
|
4
|
+
|
|
5
|
+
<br>
|
|
6
|
+
<br>
|
|
7
|
+
|
|
8
|
+
# Marwes Design System - Core
|
|
9
|
+
|
|
10
|
+
**The framework-agnostic engine behind Marwes themes, recipes, accessibility, and semantic metadata.**
|
|
11
|
+
|
|
12
|
+
Pure TypeScript • No React/Vue dependency • Typed RenderKit • Shared ThemeInput • AI-readable contracts
|
|
13
|
+
|
|
14
|
+
[Documentation](https://github.com/niklas-westman/marwes/tree/main/docs) • [Storybook](https://d3hobet9plpuvm.cloudfront.net/storybook-react/latest/) • [GitHub](https://github.com/niklas-westman/marwes)
|
|
15
|
+
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Why Use It
|
|
21
|
+
|
|
22
|
+
Most app teams should install `@marwes-ui/react` or `@marwes-ui/vue`. Install core directly when you are building an adapter, validating design-system contracts, or using Marwes theme and recipe utilities without a framework.
|
|
23
|
+
|
|
24
|
+
Core gives every adapter the same:
|
|
25
|
+
|
|
26
|
+
- `ThemeInput` contract
|
|
27
|
+
- resolved theme model
|
|
28
|
+
- CSS variable generation
|
|
29
|
+
- component recipes
|
|
30
|
+
- accessibility mapping
|
|
31
|
+
- semantic `data-*` metadata
|
|
32
|
+
- typed enums and token helpers
|
|
33
|
+
|
|
34
|
+
## Package Map
|
|
35
|
+
|
|
36
|
+
Core is the contract layer, not the normal app entry point.
|
|
37
|
+
|
|
38
|
+
| Package | Use it when |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| `@marwes-ui/react` | You are building a React app. |
|
|
41
|
+
| `@marwes-ui/vue` | You are building a Vue app. |
|
|
42
|
+
| `@marwes-ui/core` | You need framework-agnostic recipes, theme utilities, accessibility contracts, or adapter/tooling APIs. |
|
|
43
|
+
| `@marwes-ui/presets` | You need standalone preset CSS or preset theme exports. |
|
|
44
|
+
|
|
45
|
+
This package is useful for humans and AI agents that need stable contracts without framework rendering: component recipes, theme variable names, semantic attributes, and accessibility mapping all live here.
|
|
46
|
+
|
|
47
|
+
## Install
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pnpm add @marwes-ui/core
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Theme Engine
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { mwAvailableFonts, resolveThemeInput, themeToCSSVars } from "@marwes-ui/core"
|
|
57
|
+
|
|
58
|
+
const theme = resolveThemeInput({
|
|
59
|
+
color: {
|
|
60
|
+
primary: "#2457FF",
|
|
61
|
+
background: "#F8FAFC",
|
|
62
|
+
surface: "#FFFFFF",
|
|
63
|
+
text: "#111827",
|
|
64
|
+
border: "#D1D5DB",
|
|
65
|
+
focus: "#2457FF",
|
|
66
|
+
},
|
|
67
|
+
font: {
|
|
68
|
+
primary: mwAvailableFonts.Poppins,
|
|
69
|
+
secondary: mwAvailableFonts.Lora,
|
|
70
|
+
},
|
|
71
|
+
ui: {
|
|
72
|
+
radius: 10,
|
|
73
|
+
density: "comfortable",
|
|
74
|
+
},
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
const cssVars = themeToCSSVars(theme)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
React and Vue providers apply these variables to the provider root. Preset CSS consumes them across buttons, inputs, typography, cards, toasts, overlays, and layout primitives.
|
|
81
|
+
|
|
82
|
+
Marwes is designed to look great from the beginning. `ThemeInput` is intentionally partial: start from the polished defaults, map an existing design library into the tokens you own, and override only those product decisions.
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { resolveThemeInput, ThemeMode, type ThemeInput } from "@marwes-ui/core"
|
|
86
|
+
|
|
87
|
+
const themeByMode = {
|
|
88
|
+
[ThemeMode.light]: { color: { primary: "#2457FF" } },
|
|
89
|
+
[ThemeMode.dark]: { color: { primary: "#8BA2FF", background: "#0B1020", text: "#F8FAFC" } },
|
|
90
|
+
} satisfies Record<ThemeMode, ThemeInput>
|
|
91
|
+
|
|
92
|
+
const darkBrandTheme = resolveThemeInput({
|
|
93
|
+
mode: ThemeMode.dark,
|
|
94
|
+
...themeByMode[ThemeMode.dark],
|
|
95
|
+
})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Every omitted token is filled from the selected light or dark default, so adapters can expose simple light/dark toggles without requiring a full theme object.
|
|
99
|
+
|
|
100
|
+
### Light And Dark Mode Contract
|
|
101
|
+
|
|
102
|
+
Core owns the runtime `ThemeMode` contract that the React and Vue providers use for `useThemeMode()`. Use `ThemeMode.light` and `ThemeMode.dark` instead of string literals. A mode change resolves a normal theme, swaps the provider-scoped `--mw-*` variables, and keeps the active class aligned as `mw-theme--light` or `mw-theme--dark`.
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import { resolveThemeInput, themeToCSSVars, ThemeMode } from "@marwes-ui/core"
|
|
106
|
+
|
|
107
|
+
function resolveMode(mode: ThemeMode) {
|
|
108
|
+
const theme = resolveThemeInput({ mode })
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
className: `mw-theme--${theme.mode}`,
|
|
112
|
+
cssVars: themeToCSSVars(theme),
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
resolveMode(ThemeMode.dark)
|
|
117
|
+
// {
|
|
118
|
+
// className: "mw-theme--dark",
|
|
119
|
+
// cssVars: { "--mw-color-background": "#141414", ... }
|
|
120
|
+
// }
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Most apps should use `useThemeMode()` from `@marwes-ui/react` or `@marwes-ui/vue`. Core is the framework-agnostic piece that makes the resolved variables and mode classes consistent across adapters.
|
|
124
|
+
|
|
125
|
+
## Theme Variables
|
|
126
|
+
|
|
127
|
+
Marwes components are styled by CSS custom properties on the `MarwesProvider` root. The theme variable helpers expose that same token surface to application code, adapters, and tooling without creating a second runtime theme system.
|
|
128
|
+
|
|
129
|
+
Use these helpers when custom styling needs to stay connected to the active provider theme:
|
|
130
|
+
|
|
131
|
+
- `mwThemeVars` is the default custom styling API. It returns CSS `var(...)` references such as `"var(--mw-spacing-sp-24)"`.
|
|
132
|
+
- `mwThemeVarNames` returns raw custom property names such as `"--mw-spacing-sp-24"` for assignment, inspection, tests, and bridge packages.
|
|
133
|
+
- `mwVar()` wraps a custom `--mw-*` property name in `var(...)`, with optional fallback support.
|
|
134
|
+
- `mwStyledTheme` mirrors `mwThemeVars` as a plain object for styled-components and Emotion theme providers.
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
import { mwStyledTheme, mwThemeVarNames, mwThemeVars, mwVar } from "@marwes-ui/core"
|
|
138
|
+
|
|
139
|
+
mwThemeVars.spacing.sp24 // "var(--mw-spacing-sp-24)"
|
|
140
|
+
mwThemeVars.color.text // "var(--mw-color-text)"
|
|
141
|
+
mwThemeVars.color.primary.base // "var(--mw-color-primary-base)"
|
|
142
|
+
mwThemeVars.ui.radius // "var(--mw-ui-radius)"
|
|
143
|
+
|
|
144
|
+
mwThemeVarNames.spacing.sp24 // "--mw-spacing-sp-24"
|
|
145
|
+
mwVar("--mw-color-text", "#141414") // "var(--mw-color-text, #141414)"
|
|
146
|
+
mwStyledTheme.spacing.sp24 // "var(--mw-spacing-sp-24)"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
This enables one theme contract across plain CSS, CSS Modules, CSS-in-JS, vanilla-extract, Tailwind-style config files, inline style objects, React, Vue, and future adapters. Because the helpers only expose CSS variable references and names, they remain framework-agnostic and follow any `ThemeInput` resolved by the provider.
|
|
150
|
+
|
|
151
|
+
Keep the APIs separate:
|
|
152
|
+
- `Spacings.sp24` returns `"sp-24"` for Marwes component props.
|
|
153
|
+
- `mwThemeVars.spacing.sp24` returns `"var(--mw-spacing-sp-24)"` for custom styling.
|
|
154
|
+
- `mwThemeVarNames.spacing.sp24` returns `"--mw-spacing-sp-24"` when code needs the property name itself.
|
|
155
|
+
- `themeToCSSVars()` maps resolved theme values into custom property declarations.
|
|
156
|
+
- Adapter `useTheme()` hooks return resolved runtime values for logic and inspection.
|
|
157
|
+
|
|
158
|
+
## Recipe Engine
|
|
159
|
+
|
|
160
|
+
Core recipes return a typed RenderKit object instead of framework elements. Adapters map that object to React, Vue, or future renderers.
|
|
161
|
+
|
|
162
|
+
RenderKit includes:
|
|
163
|
+
- `tag`
|
|
164
|
+
- `className`
|
|
165
|
+
- `vars`
|
|
166
|
+
- `a11y`
|
|
167
|
+
- optional data attributes and component-specific control fields
|
|
168
|
+
|
|
169
|
+
## Available Component Contracts
|
|
170
|
+
|
|
171
|
+
Core currently powers these component families:
|
|
172
|
+
|
|
173
|
+
- Buttons and semantic button purposes
|
|
174
|
+
- Inputs, textareas, selects, rich text, OTP, and field wrappers
|
|
175
|
+
- Checkbox and radio families
|
|
176
|
+
- Switches and sliders
|
|
177
|
+
- Cards, typography, icons, avatars, dividers, and spacing
|
|
178
|
+
- Badges and contextual badge variants
|
|
179
|
+
- Toasts, tooltips, dialogs, tabs, accordions, and spinners
|
|
180
|
+
|
|
181
|
+
React and Vue expose the public components. Core exposes the shared recipes, types, enum objects, semantic utilities, and theme helpers that keep those adapters consistent.
|
|
182
|
+
|
|
183
|
+
## Accessibility Contract
|
|
184
|
+
|
|
185
|
+
Core is where Marwes accessibility is made reusable. Recipes return typed `a11y` output alongside classes, vars, and semantic metadata, so every adapter receives the same source of truth.
|
|
186
|
+
|
|
187
|
+
That contract covers:
|
|
188
|
+
|
|
189
|
+
- native-first semantics for controls that should stay native
|
|
190
|
+
- label and description wiring for fields and grouped controls
|
|
191
|
+
- invalid, disabled, selected, expanded, checked, and busy state mapping
|
|
192
|
+
- coordinated widget roles such as dialog, tablist, tab, tabpanel, tooltip, status, and alert
|
|
193
|
+
- stable `data-*` metadata for purpose components and agent-readable intent
|
|
194
|
+
|
|
195
|
+
Example: field helpers generate the ids that adapters use to connect helper text and errors to the control:
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
import { buildInputFieldA11yIds } from "@marwes-ui/core"
|
|
199
|
+
|
|
200
|
+
buildInputFieldA11yIds({
|
|
201
|
+
id: "email",
|
|
202
|
+
hasHelperText: true,
|
|
203
|
+
hasError: true,
|
|
204
|
+
})
|
|
205
|
+
// {
|
|
206
|
+
// helperTextId: "email-helper",
|
|
207
|
+
// errorId: "email-error",
|
|
208
|
+
// describedBy: "email-helper email-error"
|
|
209
|
+
// }
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
React and Vue tests run the same shared contracts against their DOM output. Storybook a11y smoke checks then add an axe-powered browser-level signal for the promoted families.
|
|
213
|
+
|
|
214
|
+
## Semantic Metadata
|
|
215
|
+
|
|
216
|
+
Purpose components use the core semantic registry to emit stable metadata. That makes components easier for tests, audits, and AI agents to reason about.
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
import { createPurposeSemanticAttributes } from "@marwes-ui/core"
|
|
220
|
+
|
|
221
|
+
createPurposeSemanticAttributes("destructive")
|
|
222
|
+
// {
|
|
223
|
+
// "data-purpose": "destructive",
|
|
224
|
+
// "data-action": "delete",
|
|
225
|
+
// "data-destructive": "true",
|
|
226
|
+
// "data-confirmation-required": "true"
|
|
227
|
+
// }
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
This is intentionally practical. A destructive action can carry `data-destructive="true"` and `data-confirmation-required="true"`, which gives an AI agent or browser automation rule a clear signal to ask before clicking. It also gives tests a stable assertion target that does not depend on button text, color, or visual styling.
|
|
231
|
+
|
|
232
|
+
## Public API Highlights
|
|
233
|
+
|
|
234
|
+
Theme:
|
|
235
|
+
- `resolveThemeInput`
|
|
236
|
+
- `themeToCSSVars`
|
|
237
|
+
- `mwThemeVars`
|
|
238
|
+
- `mwThemeVarNames`
|
|
239
|
+
- `mwStyledTheme`
|
|
240
|
+
- `mwVar`
|
|
241
|
+
- `lightThemeDefaults`
|
|
242
|
+
- `darkThemeDefaults`
|
|
243
|
+
- `mwAvailableFonts`
|
|
244
|
+
- `mwFontFallbacks`
|
|
245
|
+
- `mwGoogleFontFamilies`
|
|
246
|
+
- `createFontStack`
|
|
247
|
+
|
|
248
|
+
Recipe and semantic helpers:
|
|
249
|
+
- component recipe functions such as `createButtonRecipe`, `createInputRecipe`, `checkboxRecipe`, `radioRecipe`, `createDialogRecipe`, `createToastRecipe`
|
|
250
|
+
- accessibility helpers for supported families
|
|
251
|
+
- semantic builders and validators
|
|
252
|
+
|
|
253
|
+
Types and tokens:
|
|
254
|
+
- `Theme`, `ThemeInput`, `ThemeMode`, `ResolvedTheme`
|
|
255
|
+
- `ColorRole`, `SecondaryColorRole`, `ColorInput`
|
|
256
|
+
- `ButtonVariant`, `ButtonSize`, `ButtonAction`
|
|
257
|
+
- `BadgeVariant`, `AvatarSize`, `AvatarType`, `SwitchSize`, `IconName`, `Spacings`
|
|
258
|
+
|
|
259
|
+
## Package Boundaries
|
|
260
|
+
|
|
261
|
+
- Core has no React, Vue, DOM, or CSS runtime dependency.
|
|
262
|
+
- Presets own static CSS and the default visual layer.
|
|
263
|
+
- React and Vue own rendering, provider lifecycle, and framework APIs.
|
|
59
264
|
|
|
60
265
|
## Scripts
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
pnpm --filter @marwes-ui/core build
|
|
269
|
+
pnpm --filter @marwes-ui/core typecheck
|
|
270
|
+
pnpm --filter @marwes-ui/core test
|
|
271
|
+
```
|
|
64
272
|
|
|
65
273
|
## Related Docs
|
|
66
|
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
274
|
+
|
|
275
|
+
- [Docs index](https://github.com/niklas-westman/marwes/tree/main/docs)
|
|
276
|
+
- [Architecture](https://github.com/niklas-westman/marwes/blob/main/docs/reference/architecture.md)
|
|
277
|
+
- [Figma to Marwes](https://github.com/niklas-westman/marwes/blob/main/docs/guides/figma-to-marwes.md)
|