@marwes-ui/presets 1.0.0 → 1.0.2

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 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.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 first edition CSS and preset theme exports for Marwes React and Vue apps.**
10
+ **Static default CSS and preset theme exports for Marwes React and Vue apps.**
11
11
 
12
- Static `.mw-*` CSS • CSS variables • firstEdition visuals • No runtime CSS-in-JS
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 first edition preset automatically. Install presets directly when you need the standalone CSS path, the explicit `firstEditionTheme` object, or preset CSS in a custom adapter.
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
- - first edition component CSS
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 first edition CSS or preset theme exports. |
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="primary">Save</Button>
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 first edition preset styles these Marwes families today:
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. Map a graphical profile into `ThemeInput`, pass it to `MarwesProvider`, and the preset follows it.
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 first edition baseline by default, so normal app code does not need to pass it.
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 first edition preset without depending on React, Vue, styled-components, or Emotion.
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 first edition CSS includes styling for:
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 first edition CSS.
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.0",
3
+ "version": "1.0.2",
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.0"
33
+ "@marwes-ui/core": "1.0.2"
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-primary-base);
249
- --mw-toast-action: var(--mw-color-primary-base);
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-success-base);
263
- --mw-toast-action: var(--mw-color-success-base);
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-warning-base);
270
- --mw-toast-action: var(--mw-color-warning-base);
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-danger-base);
277
- --mw-toast-action: var(--mw-color-danger-base);
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-primary-base);
285
- --mw-toast-action: var(--mw-color-primary-base);
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-success-base);
301
- --mw-toast-action: var(--mw-color-success-base);
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-warning-base);
309
- --mw-toast-action: var(--mw-color-warning-base);
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-danger-base);
317
- --mw-toast-action: var(--mw-color-danger-base);
316
+ --mw-toast-text: var(--mw-color-text);
317
+ --mw-toast-action: var(--mw-color-text);
318
318
  }