@marwes-ui/vue 1.0.2 → 1.0.4
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 +41 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +61 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -352,6 +352,47 @@ import ThemeMenu from "./theme-menu.vue"
|
|
|
352
352
|
|
|
353
353
|
This layer does not provide SSR no-flash behavior. Server output can still render the fallback mode before the client applies a stored or system preference. Use it for client-side preference and persistence, not for a no-flash SSR guarantee.
|
|
354
354
|
|
|
355
|
+
### Root Target Sync
|
|
356
|
+
|
|
357
|
+
By default Marwes keeps theme state scoped to the provider element. If your app shell also needs the resolved mode on `html` or `body`, set `target` and `attribute`:
|
|
358
|
+
|
|
359
|
+
```vue
|
|
360
|
+
<template>
|
|
361
|
+
<MarwesProvider
|
|
362
|
+
default-preference="system"
|
|
363
|
+
storage-key="marwes-theme"
|
|
364
|
+
target="html"
|
|
365
|
+
attribute="class"
|
|
366
|
+
disable-transition-on-change
|
|
367
|
+
>
|
|
368
|
+
<AppShell />
|
|
369
|
+
</MarwesProvider>
|
|
370
|
+
</template>
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
`target` can be `"provider"`, `"html"`, or `"body"`. `attribute` can be `"class"`, `"data-theme"`, or `"data-mode"`. Class mode only adds the active `light` / `dark` class and removes the opposite one; unrelated classes are preserved. The provider root still keeps `mw-theme--light` / `mw-theme--dark` and provider-scoped `--mw-*` variables in every target mode.
|
|
374
|
+
|
|
375
|
+
Use one global-target provider per app shell. If multiple providers target `html` or `body`, deciding which provider owns that global element is app-owned behavior.
|
|
376
|
+
|
|
377
|
+
### Tailwind And shadcn Compatibility
|
|
378
|
+
|
|
379
|
+
Marwes is compatible with Tailwind and shadcn-style dark variants through `target="html" attribute="class"`. App-owned Tailwind tokens can also reference Marwes `--mw-*` variables when rendered inside the provider subtree.
|
|
380
|
+
|
|
381
|
+
```vue
|
|
382
|
+
<template>
|
|
383
|
+
<MarwesProvider
|
|
384
|
+
default-preference="system"
|
|
385
|
+
storage-key="marwes-theme"
|
|
386
|
+
target="html"
|
|
387
|
+
attribute="class"
|
|
388
|
+
>
|
|
389
|
+
<AppShell />
|
|
390
|
+
</MarwesProvider>
|
|
391
|
+
</template>
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
Read the [Tailwind and shadcn integration guide](https://github.com/niklas-westman/marwes/blob/main/docs/guides/tailwind-shadcn-integration.md) for Tailwind v3/v4 examples, token mapping, provider-scoped variable limits, and the SSR no-flash boundary.
|
|
395
|
+
|
|
355
396
|
For a simple brand pass, override shared values once and let Marwes fill the rest. If your product needs different brand colors in light and dark mode, control `mode` and switch between two small `ThemeInput` override objects:
|
|
356
397
|
|
|
357
398
|
```vue
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,9 @@ import * as _marwes_ui_core from '@marwes-ui/core';
|
|
|
4
4
|
import { ThemeInput, ThemePreference, ThemeMode, FontLoadingConfig, ResolvedTheme, ButtonOptions, InputOptions, SelectOptions, SelectAppearance as SelectAppearance$1, SelectOption as SelectOption$1, TextareaOptions, RichTextOptions, InputOtpOptions, CurrencyCode, iconRegistry, IconSize, IconStrokeWidth, AvatarOptions, CheckboxProps as CheckboxProps$1, DividerOptions, DividerSize, DividerOrientation, SpinnerOptions, SpacingOptions, SpacingSize, HeadingOptions, HeadingSize, ParagraphOptions, ParagraphSize, ToastOptions, ToastVariant, ToastIntent, ToastPlacement, TooltipOptions, IconNameType, RadioOptions, BadgeOptions, SwitchOptions, SliderOptions, TabOptions, DialogOptions } from '@marwes-ui/core';
|
|
5
5
|
export { AvatarSize, AvatarType, BadgeVariant, ButtonAction, ButtonSize, ButtonVariant, Density, FontLoadingConfig, FontLoadingMode, FontLoadingOptions, IconName, MwAvailableFont, MwFontFallback, MwGoogleFontFamily, MwStyledTheme, MwThemeVarName, MwThemeVarNames, MwThemeVarReference, MwThemeVars, ResolvedTheme, SpacingSize, Spacings, SwitchSize, Theme, ThemeInput, ThemeMode, ThemePreference, ToneName, createFontStack, mwAvailableFonts, mwFontFallbacks, mwGoogleFontFamilies, mwStyledTheme, mwThemeVarNames, mwThemeVars, mwVar } from '@marwes-ui/core';
|
|
6
6
|
|
|
7
|
+
type ThemeTarget = "provider" | "html" | "body";
|
|
8
|
+
type ThemeAttribute = "class" | "data-theme" | "data-mode";
|
|
9
|
+
|
|
7
10
|
type MarwesProviderProps = {
|
|
8
11
|
theme?: ThemeInput;
|
|
9
12
|
defaultPreference?: ThemePreference;
|
|
@@ -15,9 +18,14 @@ type MarwesProviderProps = {
|
|
|
15
18
|
onModeChange?: (mode: ThemeMode) => void;
|
|
16
19
|
storageKey?: string | false;
|
|
17
20
|
enableSystem?: boolean;
|
|
21
|
+
target?: ThemeTarget;
|
|
22
|
+
attribute?: ThemeAttribute;
|
|
23
|
+
disableTransitionOnChange?: boolean;
|
|
18
24
|
};
|
|
19
25
|
declare const MarwesProvider: vue.DefineComponent<{
|
|
20
26
|
mode?: any;
|
|
27
|
+
target?: any;
|
|
28
|
+
attribute?: any;
|
|
21
29
|
theme?: any;
|
|
22
30
|
defaultPreference?: any;
|
|
23
31
|
preference?: any;
|
|
@@ -27,10 +35,13 @@ declare const MarwesProvider: vue.DefineComponent<{
|
|
|
27
35
|
onModeChange?: any;
|
|
28
36
|
storageKey?: any;
|
|
29
37
|
enableSystem?: any;
|
|
38
|
+
disableTransitionOnChange?: any;
|
|
30
39
|
}, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
|
|
31
40
|
[key: string]: any;
|
|
32
41
|
}>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<{
|
|
33
42
|
mode?: any;
|
|
43
|
+
target?: any;
|
|
44
|
+
attribute?: any;
|
|
34
45
|
theme?: any;
|
|
35
46
|
defaultPreference?: any;
|
|
36
47
|
preference?: any;
|
|
@@ -40,6 +51,7 @@ declare const MarwesProvider: vue.DefineComponent<{
|
|
|
40
51
|
onModeChange?: any;
|
|
41
52
|
storageKey?: any;
|
|
42
53
|
enableSystem?: any;
|
|
54
|
+
disableTransitionOnChange?: any;
|
|
43
55
|
}> & Readonly<{}>, {}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
|
|
44
56
|
|
|
45
57
|
declare function useTheme(): ResolvedTheme;
|
package/dist/index.js
CHANGED
|
@@ -102,6 +102,42 @@ function writeStoredThemePreference(storageKey, preference) {
|
|
|
102
102
|
} catch {
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
|
+
function applyModeAttribute({
|
|
106
|
+
target,
|
|
107
|
+
providerElement,
|
|
108
|
+
mode,
|
|
109
|
+
attribute
|
|
110
|
+
}) {
|
|
111
|
+
const element = getTargetElement(target, providerElement);
|
|
112
|
+
if (!element) return;
|
|
113
|
+
if (attribute === "class") {
|
|
114
|
+
const oppositeMode = mode === ThemeMode.dark ? ThemeMode.light : ThemeMode.dark;
|
|
115
|
+
element.classList.remove(oppositeMode);
|
|
116
|
+
element.classList.add(mode);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
element.setAttribute(attribute, mode);
|
|
120
|
+
}
|
|
121
|
+
function withoutModeTransitions(callback) {
|
|
122
|
+
if (typeof document === "undefined" || typeof window === "undefined") {
|
|
123
|
+
callback();
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const style = document.createElement("style");
|
|
127
|
+
style.dataset.marwesDisableTransitions = "true";
|
|
128
|
+
style.textContent = "* { transition: none !important; }";
|
|
129
|
+
document.head.appendChild(style);
|
|
130
|
+
callback();
|
|
131
|
+
window.getComputedStyle(document.body);
|
|
132
|
+
window.requestAnimationFrame(() => {
|
|
133
|
+
style.remove();
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
function getTargetElement(target, providerElement) {
|
|
137
|
+
if (target === "provider") return providerElement;
|
|
138
|
+
if (typeof document === "undefined") return null;
|
|
139
|
+
return target === "html" ? document.documentElement : document.body;
|
|
140
|
+
}
|
|
105
141
|
|
|
106
142
|
// src/provider/marwes-provider.ts
|
|
107
143
|
var MarwesProvider = defineComponent({
|
|
@@ -116,7 +152,10 @@ var MarwesProvider = defineComponent({
|
|
|
116
152
|
"onPreferenceChange",
|
|
117
153
|
"onModeChange",
|
|
118
154
|
"storageKey",
|
|
119
|
-
"enableSystem"
|
|
155
|
+
"enableSystem",
|
|
156
|
+
"target",
|
|
157
|
+
"attribute",
|
|
158
|
+
"disableTransitionOnChange"
|
|
120
159
|
],
|
|
121
160
|
setup(rawProps, { slots }) {
|
|
122
161
|
const props = rawProps;
|
|
@@ -128,6 +167,9 @@ var MarwesProvider = defineComponent({
|
|
|
128
167
|
);
|
|
129
168
|
const enableSystem = computed(() => props.enableSystem !== false);
|
|
130
169
|
const storageKey = computed(() => props.storageKey ?? false);
|
|
170
|
+
const target = computed(() => props.target ?? "provider");
|
|
171
|
+
const attribute = computed(() => props.attribute ?? "class");
|
|
172
|
+
const disableTransitionOnChange = computed(() => props.disableTransitionOnChange === true);
|
|
131
173
|
const isPreferenceControlled = computed(
|
|
132
174
|
() => props.preference !== void 0 || props.mode !== void 0 || props.theme?.mode !== void 0
|
|
133
175
|
);
|
|
@@ -161,6 +203,22 @@ var MarwesProvider = defineComponent({
|
|
|
161
203
|
}
|
|
162
204
|
loadThemeFonts(resolved.value, props.fontLoading ?? "auto");
|
|
163
205
|
}
|
|
206
|
+
function syncTargetModeAttribute() {
|
|
207
|
+
if (target.value === "provider") return;
|
|
208
|
+
const apply = () => {
|
|
209
|
+
applyModeAttribute({
|
|
210
|
+
target: target.value,
|
|
211
|
+
providerElement: rootRef.value,
|
|
212
|
+
mode: activeMode.value,
|
|
213
|
+
attribute: attribute.value
|
|
214
|
+
});
|
|
215
|
+
};
|
|
216
|
+
if (disableTransitionOnChange.value) {
|
|
217
|
+
withoutModeTransitions(apply);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
apply();
|
|
221
|
+
}
|
|
164
222
|
let unsubscribeSystemThemeMode;
|
|
165
223
|
function syncSystemThemeSubscription() {
|
|
166
224
|
unsubscribeSystemThemeMode?.();
|
|
@@ -183,11 +241,13 @@ var MarwesProvider = defineComponent({
|
|
|
183
241
|
}
|
|
184
242
|
syncSystemThemeSubscription();
|
|
185
243
|
syncThemeToRuntime();
|
|
244
|
+
syncTargetModeAttribute();
|
|
186
245
|
});
|
|
187
246
|
onUnmounted(() => {
|
|
188
247
|
unsubscribeSystemThemeMode?.();
|
|
189
248
|
});
|
|
190
249
|
watch(resolved, syncThemeToRuntime);
|
|
250
|
+
watch([activeMode, target, attribute, disableTransitionOnChange], syncTargetModeAttribute);
|
|
191
251
|
watch([activePreference, enableSystem], syncSystemThemeSubscription);
|
|
192
252
|
provide(marwesContextKey, {
|
|
193
253
|
theme: resolved,
|