@marwes-ui/react 1.0.3 → 1.0.5

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
@@ -378,6 +378,29 @@ By default Marwes keeps theme state scoped to the provider element. If your app
378
378
 
379
379
  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.
380
380
 
381
+ ### Tailwind And shadcn Compatibility
382
+
383
+ 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.
384
+
385
+ ```tsx
386
+ <MarwesProvider
387
+ defaultPreference="system"
388
+ storageKey="marwes-theme"
389
+ target="html"
390
+ attribute="class"
391
+ >
392
+ <AppShell />
393
+ </MarwesProvider>
394
+ ```
395
+
396
+ 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.
397
+
398
+ ### Next.js App Router SSR
399
+
400
+ Use `MarwesThemeStyle`, `MarwesThemeScript`, and `variableStrategy="style-tag"` when a server-rendered app needs the correct light or dark variables before hydration. This is opt-in; normal React apps keep inline provider variables by default.
401
+
402
+ Read the [theme SSR no-flash guide](https://github.com/niklas-westman/marwes/blob/main/docs/guides/theme-ssr-no-flash.md) for Next.js App Router setup, CSP nonces, `suppressHydrationWarning`, custom light/dark themes, and stored/system preference behavior.
403
+
381
404
  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:
382
405
 
383
406
  ```tsx
@@ -0,0 +1,34 @@
1
+ import { createMarwesThemeScript as createMarwesThemeScript$1, createMarwesThemeStyle as createMarwesThemeStyle$1 } from '@marwes-ui/core';
2
+ import { jsx } from 'react/jsx-runtime';
3
+
4
+ // src/ssr.tsx
5
+ function createMarwesThemeScript(options) {
6
+ return createMarwesThemeScript$1(options);
7
+ }
8
+ function createMarwesThemeStyle(options) {
9
+ return createMarwesThemeStyle$1(options);
10
+ }
11
+ function MarwesThemeScript({ nonce, ...options }) {
12
+ return /* @__PURE__ */ jsx(
13
+ "script",
14
+ {
15
+ "data-marwes-ssr-theme-script": "true",
16
+ nonce,
17
+ dangerouslySetInnerHTML: { __html: createMarwesThemeScript(options) }
18
+ }
19
+ );
20
+ }
21
+ function MarwesThemeStyle({ nonce, ...options }) {
22
+ return /* @__PURE__ */ jsx(
23
+ "style",
24
+ {
25
+ "data-marwes-ssr-theme-style": "true",
26
+ nonce,
27
+ dangerouslySetInnerHTML: { __html: createMarwesThemeStyle(options) }
28
+ }
29
+ );
30
+ }
31
+
32
+ export { MarwesThemeScript, MarwesThemeStyle, createMarwesThemeScript, createMarwesThemeStyle };
33
+ //# sourceMappingURL=chunk-VFY2GW62.js.map
34
+ //# sourceMappingURL=chunk-VFY2GW62.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ssr.tsx"],"names":["createCoreMarwesThemeScript","createCoreMarwesThemeStyle"],"mappings":";;;;AAgBO,SAAS,wBAAwB,OAAA,EAA4C;AAClF,EAAA,OAAOA,0BAA4B,OAAO,CAAA;AAC5C;AAEO,SAAS,uBAAuB,OAAA,EAA2C;AAChF,EAAA,OAAOC,yBAA2B,OAAO,CAAA;AAC3C;AAEO,SAAS,iBAAA,CAAkB,EAAE,KAAA,EAAO,GAAG,SAAQ,EAA2B;AAC/E,EAAA,uBACE,GAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,8BAAA,EAA6B,MAAA;AAAA,MAC7B,KAAA;AAAA,MAEA,uBAAA,EAAyB,EAAE,MAAA,EAAQ,uBAAA,CAAwB,OAAO,CAAA;AAAE;AAAA,GACtE;AAEJ;AAEO,SAAS,gBAAA,CAAiB,EAAE,KAAA,EAAO,GAAG,SAAQ,EAA0B;AAC7E,EAAA,uBACE,GAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,6BAAA,EAA4B,MAAA;AAAA,MAC5B,KAAA;AAAA,MAEA,uBAAA,EAAyB,EAAE,MAAA,EAAQ,sBAAA,CAAuB,OAAO,CAAA;AAAE;AAAA,GACrE;AAEJ","file":"chunk-VFY2GW62.js","sourcesContent":["import type { MarwesThemeScriptOptions, MarwesThemeStyleOptions } from \"@marwes-ui/core\"\nimport {\n createMarwesThemeScript as createCoreMarwesThemeScript,\n createMarwesThemeStyle as createCoreMarwesThemeStyle,\n} from \"@marwes-ui/core\"\n\nexport type { MarwesThemeScriptOptions, MarwesThemeStyleOptions }\n\nexport type MarwesThemeScriptProps = MarwesThemeScriptOptions & {\n nonce?: string\n}\n\nexport type MarwesThemeStyleProps = MarwesThemeStyleOptions & {\n nonce?: string\n}\n\nexport function createMarwesThemeScript(options?: MarwesThemeScriptOptions): string {\n return createCoreMarwesThemeScript(options)\n}\n\nexport function createMarwesThemeStyle(options?: MarwesThemeStyleOptions): string {\n return createCoreMarwesThemeStyle(options)\n}\n\nexport function MarwesThemeScript({ nonce, ...options }: MarwesThemeScriptProps) {\n return (\n <script\n data-marwes-ssr-theme-script=\"true\"\n nonce={nonce}\n // biome-ignore lint/security/noDangerouslySetInnerHtml: SSR helper emits deterministic Marwes-owned code before hydration.\n dangerouslySetInnerHTML={{ __html: createMarwesThemeScript(options) }}\n />\n )\n}\n\nexport function MarwesThemeStyle({ nonce, ...options }: MarwesThemeStyleProps) {\n return (\n <style\n data-marwes-ssr-theme-style=\"true\"\n nonce={nonce}\n // biome-ignore lint/security/noDangerouslySetInnerHtml: SSR helper emits deterministic Marwes-owned CSS before hydration.\n dangerouslySetInnerHTML={{ __html: createMarwesThemeStyle(options) }}\n />\n )\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- 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';
3
- 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';
2
+ import { ThemeInput, ThemePreference, ThemeMode, FontLoadingConfig, ThemeVariableStrategy, 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';
3
+ export { AvatarSize, AvatarType, BadgeVariant, ButtonAction, ButtonSize, ButtonVariant, Density, FontLoadingConfig, FontLoadingMode, FontLoadingOptions, IconName, MarwesThemeScriptOptions, MarwesThemeStyleOptions, MwAvailableFont, MwFontFallback, MwGoogleFontFamily, MwStyledTheme, MwThemeVarName, MwThemeVarNames, MwThemeVarReference, MwThemeVars, ResolvedTheme, SpacingSize, Spacings, SwitchSize, Theme, ThemeInput, ThemeMode, ThemeModeAttribute, ThemeModeRootTarget, ThemePreference, ThemeVariableStrategy, ToneName, createFontStack, mwAvailableFonts, mwFontFallbacks, mwGoogleFontFamilies, mwStyledTheme, mwThemeVarNames, mwThemeVars, mwVar } from '@marwes-ui/core';
4
4
  import * as React from 'react';
5
+ export { MarwesThemeScript, MarwesThemeScriptProps, MarwesThemeStyle, MarwesThemeStyleProps, createMarwesThemeScript, createMarwesThemeStyle } from './ssr.js';
5
6
 
6
7
  type ThemeTarget = "provider" | "html" | "body";
7
8
  type ThemeAttribute = "class" | "data-theme" | "data-mode";
@@ -20,9 +21,10 @@ type MarwesProviderProps = {
20
21
  target?: ThemeTarget;
21
22
  attribute?: ThemeAttribute;
22
23
  disableTransitionOnChange?: boolean;
24
+ variableStrategy?: ThemeVariableStrategy;
23
25
  children: React.ReactNode;
24
26
  };
25
- declare function MarwesProvider({ theme, defaultPreference, preference: controlledPreference, defaultMode, mode: controlledMode, fontLoading, onPreferenceChange, onModeChange, storageKey, enableSystem, target, attribute, disableTransitionOnChange, children, }: MarwesProviderProps): react_jsx_runtime.JSX.Element;
27
+ declare function MarwesProvider({ theme, defaultPreference, preference: controlledPreference, defaultMode, mode: controlledMode, fontLoading, onPreferenceChange, onModeChange, storageKey, enableSystem, target, attribute, disableTransitionOnChange, variableStrategy, children, }: MarwesProviderProps): react_jsx_runtime.JSX.Element;
26
28
 
27
29
  declare function useTheme(): ResolvedTheme;
28
30
 
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ export { MarwesThemeScript, MarwesThemeStyle, createMarwesThemeScript, createMarwesThemeStyle } from './chunk-VFY2GW62.js';
1
2
  import '@marwes-ui/presets/firstEdition/styles.css';
2
3
  import { createRichTextRecipe, resolveRichTextAllowedFormats, normalizeRichTextHtml, isRichTextHtmlEmpty, createDividerRecipe, createSpacingRecipe, createSliderRecipe, richTextCommandByFormat, resolveIconSize, resolveIconStrokeWidth, iconRegistry, resolveIconA11y, ThemeMode, resolveThemePreference, nextThemeMode, resolveThemeInput, createSpinnerRecipe, createButtonRecipe, ButtonAction, ButtonVariant, IconName, createInputRecipe, createSelectRecipe, resolveSelectMode, createTextareaRecipe, paragraphRecipe, buildInputFieldA11yIds, sanitizeInputOtpValue, createInputOtpRecipe, buildRichTextFieldA11yIds, buildCurrencyHelperText, getCurrencySymbol, createAvatarRecipe, createPurposeSemanticAttributes, checkboxRecipe, buildCheckboxFieldA11yIds, buildCheckboxGroupFieldA11yIds, headingRecipe, createCardRecipe, createToastRecipe, createTooltipRecipe, createAccordionRecipe, buildAccordionFieldA11yIds, radioRecipe, buildRadioGroupFieldA11yIds, createBadgeRecipe, createSwitchRecipe, buildSwitchFieldA11yIds, buildSliderFieldA11yIds, createTabRecipe, resolveTabValue, buildTabGroupA11yIds, moveTabSelection, createDialogRecipe, sanitizeCurrencyValue, isThemePreference, themeToCSSVars, extractUsedWeights, extractFontFamilyName, shouldLoadGoogleFont, buildGoogleFontsUrl } from '@marwes-ui/core';
3
4
  export { AvatarSize, AvatarType, BadgeVariant, ButtonAction, ButtonSize, ButtonVariant, IconName, Spacings, SwitchSize, ThemeMode, createFontStack, mwAvailableFonts, mwFontFallbacks, mwGoogleFontFamilies, mwStyledTheme, mwThemeVarNames, mwThemeVars, mwVar } from '@marwes-ui/core';
@@ -6,7 +7,6 @@ import { useEffect } from 'react';
6
7
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
7
8
  import { createPortal } from 'react-dom';
8
9
 
9
- // src/index.ts
10
10
  var MarwesContext = React2.createContext(null);
11
11
  var loadedFonts = /* @__PURE__ */ new Set();
12
12
  var preconnected = false;
@@ -19,6 +19,7 @@ function themeToRootStyle(theme) {
19
19
  }
20
20
  function applyThemeToElement(element, theme) {
21
21
  element.setAttribute("data-marwes-theme", "true");
22
+ element.setAttribute("data-marwes-mode", theme.mode);
22
23
  for (const [property, value] of Object.entries(themeToRootStyle(theme))) {
23
24
  if (property === "backgroundColor") {
24
25
  element.style.backgroundColor = value;
@@ -153,6 +154,7 @@ function MarwesProvider({
153
154
  target = "provider",
154
155
  attribute = "class",
155
156
  disableTransitionOnChange = false,
157
+ variableStrategy = "inline",
156
158
  children
157
159
  }) {
158
160
  const rootRef = React2.useRef(null);
@@ -206,15 +208,16 @@ function MarwesProvider({
206
208
  () => resolveThemeInput({ ...theme ?? {}, mode: activeMode }),
207
209
  [activeMode, theme]
208
210
  );
209
- const rootStyle = React2.useMemo(
210
- () => themeToRootStyle(resolved),
211
- [resolved]
212
- );
211
+ const rootStyle = React2.useMemo(() => {
212
+ if (variableStrategy === "style-tag") return void 0;
213
+ return themeToRootStyle(resolved);
214
+ }, [resolved, variableStrategy]);
213
215
  React2.useEffect(() => {
216
+ if (variableStrategy === "style-tag") return;
214
217
  if (rootRef.current) {
215
218
  applyThemeToElement(rootRef.current, resolved);
216
219
  }
217
- }, [resolved]);
220
+ }, [resolved, variableStrategy]);
218
221
  React2.useEffect(() => {
219
222
  if (target === "provider") return;
220
223
  const apply = () => {
@@ -252,6 +255,7 @@ function MarwesProvider({
252
255
  ref: rootRef,
253
256
  className: `mw-theme--${resolved.mode}`,
254
257
  "data-marwes-theme": "true",
258
+ "data-marwes-mode": resolved.mode,
255
259
  style: rootStyle,
256
260
  children
257
261
  }