@marwes-ui/presets 1.0.0 → 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/README.md +87 -16
- package/package.json +2 -2
- package/src/firstEdition/toast.css +16 -16
package/README.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<img alt="Marwes Design System" src="https://raw.githubusercontent.com/niklas-westman/marwes/main/.github/assets/banner-light.png" width="100%">
|
|
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
4
|
|
|
5
5
|
<br>
|
|
6
6
|
<br>
|
|
7
7
|
|
|
8
8
|
# Marwes Design System - Presets
|
|
9
9
|
|
|
10
|
-
**Static
|
|
10
|
+
**Static default CSS and preset theme exports for Marwes React and Vue apps.**
|
|
11
11
|
|
|
12
|
-
Static `.mw-*` CSS • CSS variables •
|
|
12
|
+
Static `.mw-*` CSS • CSS variables • Default Marwes visuals • No runtime CSS-in-JS
|
|
13
13
|
|
|
14
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
15
|
|
|
@@ -19,11 +19,11 @@ Static `.mw-*` CSS • CSS variables • firstEdition visuals • No runtime CSS
|
|
|
19
19
|
|
|
20
20
|
## Why Use It
|
|
21
21
|
|
|
22
|
-
Most apps install `@marwes-ui/react` or `@marwes-ui/vue`, and those adapters load the
|
|
22
|
+
Most apps install `@marwes-ui/react` or `@marwes-ui/vue`, and those adapters load the default preset automatically. Install presets directly when you need the standalone CSS path, the explicit `firstEditionTheme` object, or preset CSS in a custom adapter.
|
|
23
23
|
|
|
24
24
|
Presets gives Marwes its default visual layer:
|
|
25
25
|
|
|
26
|
-
-
|
|
26
|
+
- default component CSS
|
|
27
27
|
- theme-variable driven colors, radius, focus, typography, density, and state styling
|
|
28
28
|
- stable `.mw-*` class styling for every shipped component family
|
|
29
29
|
- no CSS-in-JS runtime
|
|
@@ -38,7 +38,7 @@ Presets are the static visual layer, not the normal app entry point.
|
|
|
38
38
|
| `@marwes-ui/react` | You are building a React app. |
|
|
39
39
|
| `@marwes-ui/vue` | You are building a Vue app. |
|
|
40
40
|
| `@marwes-ui/core` | You need framework-agnostic recipes, theme utilities, accessibility contracts, or adapter/tooling APIs. |
|
|
41
|
-
| `@marwes-ui/presets` | You need standalone
|
|
41
|
+
| `@marwes-ui/presets` | You need standalone preset CSS or preset theme exports. |
|
|
42
42
|
|
|
43
43
|
This package gives humans and AI agents a predictable CSS contract: `.mw-*` classes consume `--mw-*` variables generated by the provider, while adapters stay thin.
|
|
44
44
|
|
|
@@ -53,12 +53,12 @@ pnpm add @marwes-ui/presets
|
|
|
53
53
|
React and Vue apps normally import only the adapter:
|
|
54
54
|
|
|
55
55
|
```tsx
|
|
56
|
-
import { Button, MarwesProvider } from "@marwes-ui/react"
|
|
56
|
+
import { Button, ButtonVariant, MarwesProvider } from "@marwes-ui/react"
|
|
57
57
|
|
|
58
58
|
export function App() {
|
|
59
59
|
return (
|
|
60
60
|
<MarwesProvider>
|
|
61
|
-
<Button variant=
|
|
61
|
+
<Button variant={ButtonVariant.primary}>Save</Button>
|
|
62
62
|
</MarwesProvider>
|
|
63
63
|
)
|
|
64
64
|
}
|
|
@@ -74,7 +74,7 @@ import "@marwes-ui/presets/firstEdition/styles.css"
|
|
|
74
74
|
|
|
75
75
|
## Available Styled Families
|
|
76
76
|
|
|
77
|
-
The
|
|
77
|
+
The default preset styles these Marwes families today:
|
|
78
78
|
|
|
79
79
|
- Accordion and accordion fields
|
|
80
80
|
- Avatar and avatar groups
|
|
@@ -98,10 +98,10 @@ The first edition preset styles these Marwes families today:
|
|
|
98
98
|
|
|
99
99
|
## Custom Theme With Preset CSS
|
|
100
100
|
|
|
101
|
-
Preset CSS consumes provider-generated `--mw-*` variables.
|
|
101
|
+
Preset CSS consumes provider-generated `--mw-*` variables. Marwes is designed to look great from the beginning: map an existing design library or graphical profile into a partial `ThemeInput`, override only the tokens your product owns, pass it to `MarwesProvider`, and the preset follows it.
|
|
102
102
|
|
|
103
103
|
```tsx
|
|
104
|
-
import { MarwesProvider, mwAvailableFonts } from "@marwes-ui/react"
|
|
104
|
+
import { MarwesProvider, mwAvailableFonts, type ThemeInput } from "@marwes-ui/react"
|
|
105
105
|
|
|
106
106
|
const brandTheme = {
|
|
107
107
|
color: {
|
|
@@ -125,16 +125,87 @@ const brandTheme = {
|
|
|
125
125
|
radius: 10,
|
|
126
126
|
density: "comfortable",
|
|
127
127
|
},
|
|
128
|
-
}
|
|
128
|
+
} satisfies ThemeInput
|
|
129
129
|
|
|
130
130
|
<MarwesProvider theme={brandTheme}>
|
|
131
131
|
<App />
|
|
132
132
|
</MarwesProvider>
|
|
133
133
|
```
|
|
134
134
|
|
|
135
|
+
## Light And Dark Mode
|
|
136
|
+
|
|
137
|
+
The preset CSS already contains the light and dark visual rules. In React and Vue apps, use `ThemeMode.light` and `ThemeMode.dark` instead of string literals, then let `MarwesProvider` own the active mode and toggle it with the adapter hook:
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
import { Button, ButtonVariant, MarwesProvider, ThemeMode, useThemeMode } from "@marwes-ui/react"
|
|
141
|
+
|
|
142
|
+
function ThemeToggle() {
|
|
143
|
+
const { mode, toggleMode } = useThemeMode()
|
|
144
|
+
|
|
145
|
+
return (
|
|
146
|
+
<Button variant={ButtonVariant.secondary} onClick={toggleMode}>
|
|
147
|
+
Use {mode === ThemeMode.dark ? ThemeMode.light : ThemeMode.dark} mode
|
|
148
|
+
</Button>
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function App() {
|
|
153
|
+
return (
|
|
154
|
+
<MarwesProvider defaultMode={ThemeMode.light}>
|
|
155
|
+
<ThemeToggle />
|
|
156
|
+
<AppShell />
|
|
157
|
+
</MarwesProvider>
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
When the mode changes, the provider updates the preset's `--mw-*` variables and root class. Preset selectors such as `.mw-theme--dark .mw-btn` then pick up the correct dark-mode component states without any extra CSS in the app.
|
|
163
|
+
|
|
164
|
+
You do not need a `themeByMode` map for the normal toggle. With no `theme` prop, Marwes uses its default light and dark palettes. With shared brand overrides, pass the same partial `theme` object and the provider still swaps every omitted token by mode.
|
|
165
|
+
|
|
166
|
+
Use a `themeByMode` map only when your product wants different brand overrides in light and dark mode, such as a different primary color or surface color per mode:
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
import { useState } from "react"
|
|
170
|
+
import {
|
|
171
|
+
Button,
|
|
172
|
+
ButtonVariant,
|
|
173
|
+
MarwesProvider,
|
|
174
|
+
ThemeMode,
|
|
175
|
+
type ThemeInput,
|
|
176
|
+
useThemeMode,
|
|
177
|
+
} from "@marwes-ui/react"
|
|
178
|
+
|
|
179
|
+
const themeByMode = {
|
|
180
|
+
[ThemeMode.light]: { color: { primary: "#2457FF", background: "#F8FAFC", text: "#111827" } },
|
|
181
|
+
[ThemeMode.dark]: { color: { primary: "#8BA2FF", background: "#0B1020", text: "#F8FAFC" } },
|
|
182
|
+
} satisfies Record<ThemeMode, ThemeInput>
|
|
183
|
+
|
|
184
|
+
function ThemeToggle() {
|
|
185
|
+
const { mode, toggleMode } = useThemeMode()
|
|
186
|
+
|
|
187
|
+
return (
|
|
188
|
+
<Button variant={ButtonVariant.secondary} onClick={toggleMode}>
|
|
189
|
+
Use {mode === ThemeMode.dark ? ThemeMode.light : ThemeMode.dark} mode
|
|
190
|
+
</Button>
|
|
191
|
+
)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export function App() {
|
|
195
|
+
const [mode, setMode] = useState<ThemeMode>(ThemeMode.light)
|
|
196
|
+
|
|
197
|
+
return (
|
|
198
|
+
<MarwesProvider mode={mode} theme={themeByMode[mode]} onModeChange={setMode}>
|
|
199
|
+
<ThemeToggle />
|
|
200
|
+
<AppShell />
|
|
201
|
+
</MarwesProvider>
|
|
202
|
+
)
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
135
206
|
## firstEditionTheme
|
|
136
207
|
|
|
137
|
-
`firstEditionTheme` remains exported for explicit or advanced use. React and Vue providers already use the same
|
|
208
|
+
`firstEditionTheme` remains exported for explicit or advanced use. React and Vue providers already use the same baseline by default, so normal app code does not need to pass it.
|
|
138
209
|
|
|
139
210
|
```ts
|
|
140
211
|
import { firstEditionTheme } from "@marwes-ui/presets"
|
|
@@ -185,13 +256,13 @@ const localOverride = {
|
|
|
185
256
|
}
|
|
186
257
|
```
|
|
187
258
|
|
|
188
|
-
These helpers exist so preset CSS, adapter components, and custom application styles all follow the same provider-generated variables. That enables custom layouts and third-party styling systems to stay visually aligned with the
|
|
259
|
+
These helpers exist so preset CSS, adapter components, and custom application styles all follow the same provider-generated variables. That enables custom layouts and third-party styling systems to stay visually aligned with the default preset without depending on React, Vue, styled-components, or Emotion.
|
|
189
260
|
|
|
190
261
|
## Accessible Styling Contract
|
|
191
262
|
|
|
192
263
|
Presets make the semantic contract visible without replacing it. Core and the adapters own roles, labels, state, and ARIA wiring; preset CSS owns the visual states that users need to perceive.
|
|
193
264
|
|
|
194
|
-
That means the
|
|
265
|
+
That means the default CSS includes styling for:
|
|
195
266
|
|
|
196
267
|
- visible focus states on interactive controls
|
|
197
268
|
- disabled, invalid, selected, expanded, checked, and busy states
|
|
@@ -203,7 +274,7 @@ Example: an invalid input field is accessible because the adapter applies `aria-
|
|
|
203
274
|
## Package Boundaries
|
|
204
275
|
|
|
205
276
|
- `@marwes-ui/core` owns recipes, semantic metadata, and theme resolution.
|
|
206
|
-
- `@marwes-ui/presets` owns static
|
|
277
|
+
- `@marwes-ui/presets` owns static default CSS.
|
|
207
278
|
- `@marwes-ui/react` and `@marwes-ui/vue` load this preset by default and render components.
|
|
208
279
|
|
|
209
280
|
## Scripts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@marwes-ui/presets",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@fontsource/instrument-sans": "5.2.8",
|
|
33
|
-
"@marwes-ui/core": "1.0.
|
|
33
|
+
"@marwes-ui/core": "1.0.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"rimraf": "6.1.2",
|
|
@@ -245,8 +245,8 @@
|
|
|
245
245
|
--mw-toast-surface: var(--mw-color-surface-elevated);
|
|
246
246
|
--mw-toast-border: var(--mw-color-primary-base);
|
|
247
247
|
--mw-toast-icon: var(--mw-color-primary-base);
|
|
248
|
-
--mw-toast-text: var(--mw-color-
|
|
249
|
-
--mw-toast-action: var(--mw-color-
|
|
248
|
+
--mw-toast-text: var(--mw-color-text);
|
|
249
|
+
--mw-toast-action: var(--mw-color-text);
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
.mw-theme--dark .mw-toast--outline[data-intent="neutral"] {
|
|
@@ -259,30 +259,30 @@
|
|
|
259
259
|
.mw-theme--dark .mw-toast--outline[data-intent="success"] {
|
|
260
260
|
--mw-toast-border: var(--mw-color-success-base);
|
|
261
261
|
--mw-toast-icon: var(--mw-color-success-base);
|
|
262
|
-
--mw-toast-text: var(--mw-color-
|
|
263
|
-
--mw-toast-action: var(--mw-color-
|
|
262
|
+
--mw-toast-text: var(--mw-color-text);
|
|
263
|
+
--mw-toast-action: var(--mw-color-text);
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
.mw-theme--dark .mw-toast--outline[data-intent="warning"] {
|
|
267
267
|
--mw-toast-border: var(--mw-color-warning-base);
|
|
268
268
|
--mw-toast-icon: var(--mw-color-warning-base);
|
|
269
|
-
--mw-toast-text: var(--mw-color-
|
|
270
|
-
--mw-toast-action: var(--mw-color-
|
|
269
|
+
--mw-toast-text: var(--mw-color-text);
|
|
270
|
+
--mw-toast-action: var(--mw-color-text);
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
.mw-theme--dark .mw-toast--outline[data-intent="error"] {
|
|
274
274
|
--mw-toast-border: var(--mw-color-danger-base);
|
|
275
275
|
--mw-toast-icon: var(--mw-color-danger-base);
|
|
276
|
-
--mw-toast-text: var(--mw-color-
|
|
277
|
-
--mw-toast-action: var(--mw-color-
|
|
276
|
+
--mw-toast-text: var(--mw-color-text);
|
|
277
|
+
--mw-toast-action: var(--mw-color-text);
|
|
278
278
|
}
|
|
279
279
|
|
|
280
280
|
.mw-theme--dark .mw-toast--rich {
|
|
281
281
|
--mw-toast-surface: color-mix(in srgb, var(--mw-color-primary-base) 18%, var(--mw-color-surface));
|
|
282
282
|
--mw-toast-border: var(--mw-color-primary-base);
|
|
283
283
|
--mw-toast-icon: var(--mw-color-primary-base);
|
|
284
|
-
--mw-toast-text: var(--mw-color-
|
|
285
|
-
--mw-toast-action: var(--mw-color-
|
|
284
|
+
--mw-toast-text: var(--mw-color-text);
|
|
285
|
+
--mw-toast-action: var(--mw-color-text);
|
|
286
286
|
}
|
|
287
287
|
|
|
288
288
|
.mw-theme--dark .mw-toast--rich[data-intent="neutral"] {
|
|
@@ -297,22 +297,22 @@
|
|
|
297
297
|
--mw-toast-surface: color-mix(in srgb, var(--mw-color-success-base) 18%, var(--mw-color-surface));
|
|
298
298
|
--mw-toast-border: var(--mw-color-success-base);
|
|
299
299
|
--mw-toast-icon: var(--mw-color-success-base);
|
|
300
|
-
--mw-toast-text: var(--mw-color-
|
|
301
|
-
--mw-toast-action: var(--mw-color-
|
|
300
|
+
--mw-toast-text: var(--mw-color-text);
|
|
301
|
+
--mw-toast-action: var(--mw-color-text);
|
|
302
302
|
}
|
|
303
303
|
|
|
304
304
|
.mw-theme--dark .mw-toast--rich[data-intent="warning"] {
|
|
305
305
|
--mw-toast-surface: color-mix(in srgb, var(--mw-color-warning-base) 20%, var(--mw-color-surface));
|
|
306
306
|
--mw-toast-border: var(--mw-color-warning-base);
|
|
307
307
|
--mw-toast-icon: var(--mw-color-warning-base);
|
|
308
|
-
--mw-toast-text: var(--mw-color-
|
|
309
|
-
--mw-toast-action: var(--mw-color-
|
|
308
|
+
--mw-toast-text: var(--mw-color-text);
|
|
309
|
+
--mw-toast-action: var(--mw-color-text);
|
|
310
310
|
}
|
|
311
311
|
|
|
312
312
|
.mw-theme--dark .mw-toast--rich[data-intent="error"] {
|
|
313
313
|
--mw-toast-surface: color-mix(in srgb, var(--mw-color-danger-base) 18%, var(--mw-color-surface));
|
|
314
314
|
--mw-toast-border: var(--mw-color-danger-base);
|
|
315
315
|
--mw-toast-icon: var(--mw-color-danger-base);
|
|
316
|
-
--mw-toast-text: var(--mw-color-
|
|
317
|
-
--mw-toast-action: var(--mw-color-
|
|
316
|
+
--mw-toast-text: var(--mw-color-text);
|
|
317
|
+
--mw-toast-action: var(--mw-color-text);
|
|
318
318
|
}
|