material-theme-builder 3.1.0 → 3.3.0

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/dist/react.js CHANGED
@@ -3973,6 +3973,39 @@ function toShadcnVars(mergedColors) {
3973
3973
  });
3974
3974
  return Object.fromEntries(entries);
3975
3975
  }
3976
+ function toShadcnAliasVars(prefix, fallbacks) {
3977
+ const entries = SHADCN_MAPPING.map(([cssVar, m3Token]) => {
3978
+ const bare = cssVar.slice(2);
3979
+ const property = `--${prefix}-sys-color-${m3Token}`;
3980
+ return [
3981
+ bare,
3982
+ fallbacks ? `var(${property}, ${fallbacks[bare]})` : `var(${property})`
3983
+ ];
3984
+ });
3985
+ return Object.fromEntries(entries);
3986
+ }
3987
+ function buildShadcnAliases(ctx) {
3988
+ const lines = Object.entries(toShadcnAliasVars(ctx.prefix)).map(
3989
+ ([name, value]) => `--${name}: ${value};`
3990
+ );
3991
+ return `:root,
3992
+ .dark {
3993
+ ${lines.join("\n ")}
3994
+ }
3995
+ `;
3996
+ }
3997
+ function buildShadcnRegistryItem(ctx, { fallback = false } = {}) {
3998
+ const concrete = fallback ? buildShadcn(ctx) : void 0;
3999
+ const vars = (mode) => toShadcnAliasVars(ctx.prefix, concrete?.[mode]);
4000
+ return {
4001
+ $schema: "https://ui.shadcn.com/schema/registry-item.json",
4002
+ name: "material-theme-builder",
4003
+ type: "registry:theme",
4004
+ title: "Material Theme Builder",
4005
+ description: `Points shadcn's CSS variables at the M3 custom properties \`<Mtb>\` emits, so every shadcn component follows whichever theme is above it in the tree.${fallback ? " Falls back to this theme's own colors where no `<Mtb>` is mounted." : ""}`,
4006
+ cssVars: { light: vars("light"), dark: vars("dark") }
4007
+ };
4008
+ }
3976
4009
  function buildShadcn(ctx) {
3977
4010
  const { mergedColorsLight, mergedColorsDark } = ctx;
3978
4011
  return {
@@ -3983,6 +4016,64 @@ function buildShadcn(ctx) {
3983
4016
 
3984
4017
  // src/lib/builder.tailwind.ts
3985
4018
  import { kebabCase as kebabCase3 } from "lodash-es";
4019
+
4020
+ // src/lib/tokens.ts
4021
+ var DEFAULT_PREFIX = "md";
4022
+ var tokenDescriptions = {
4023
+ background: "Default background color for screens and large surfaces.",
4024
+ error: "Color for error states, used on elements like error text and icons.",
4025
+ errorContainer: "Fill color for error container elements like error banners.",
4026
+ inverseOnSurface: "Color for text and icons on inverse surface backgrounds.",
4027
+ inversePrimary: "Primary color used on inverse surface, e.g. buttons on snackbars.",
4028
+ inverseSurface: "Background for elements that require reverse contrast, such as snackbars.",
4029
+ onBackground: "Color for text and icons displayed on the background.",
4030
+ onError: "Color for text and icons on error-colored elements.",
4031
+ onErrorContainer: "Color for text and icons on error container elements.",
4032
+ onPrimary: "Color for text and icons on primary-colored elements like filled buttons.",
4033
+ onPrimaryContainer: "Color for text and icons on primary container elements like tonal buttons.",
4034
+ onPrimaryFixed: "Color for text and icons on primary fixed elements, constant across themes.",
4035
+ onPrimaryFixedVariant: "Lower-emphasis color for text and icons on primary fixed elements.",
4036
+ onSecondary: "Color for text and icons on secondary-colored elements.",
4037
+ onSecondaryContainer: "Color for text and icons on secondary container elements.",
4038
+ onSecondaryFixed: "Color for text and icons on secondary fixed elements, constant across themes.",
4039
+ onSecondaryFixedVariant: "Lower-emphasis color for text and icons on secondary fixed elements.",
4040
+ onSurface: "High-emphasis color for text and icons on surface backgrounds.",
4041
+ onSurfaceVariant: "Medium-emphasis color for text and icons on surface variant backgrounds.",
4042
+ onTertiary: "Color for text and icons on tertiary-colored elements.",
4043
+ onTertiaryContainer: "Color for text and icons on tertiary container elements.",
4044
+ onTertiaryFixed: "Color for text and icons on tertiary fixed elements, constant across themes.",
4045
+ onTertiaryFixedVariant: "Lower-emphasis color for text and icons on tertiary fixed elements.",
4046
+ outline: "Subtle color for borders and dividers to create visual separation.",
4047
+ outlineVariant: "Lower-emphasis border color used for decorative dividers.",
4048
+ primary: "Main brand color, used for key components like filled buttons and active states.",
4049
+ primaryContainer: "Fill color for large primary elements like cards and tonal buttons.",
4050
+ primaryFixed: "Fixed primary color that stays the same in light and dark themes.",
4051
+ primaryFixedDim: "Dimmed variant of the fixed primary color for lower emphasis.",
4052
+ scrim: "Color overlay for modals and dialogs to obscure background content.",
4053
+ secondary: "Accent color for less prominent elements like filter chips and selections.",
4054
+ secondaryContainer: "Fill color for secondary container elements like tonal buttons and input fields.",
4055
+ secondaryFixed: "Fixed secondary color that stays the same in light and dark themes.",
4056
+ secondaryFixedDim: "Dimmed variant of the fixed secondary color for lower emphasis.",
4057
+ shadow: "Color for elevation shadows applied to surfaces and components.",
4058
+ surface: "Default surface color for cards, sheets, and dialogs.",
4059
+ surfaceBright: "Brightest surface variant, used for elevated surfaces in dark themes.",
4060
+ surfaceContainer: "Middle-emphasis container color for grouping related content.",
4061
+ surfaceContainerHigh: "Higher-emphasis container color for elements like cards.",
4062
+ surfaceContainerHighest: "Highest-emphasis container color for text fields and other input areas.",
4063
+ surfaceContainerLow: "Lower-emphasis container color for subtle surface groupings.",
4064
+ surfaceContainerLowest: "Lowest-emphasis container, typically the lightest surface in light theme.",
4065
+ surfaceDim: "Dimmest surface variant, used for recessed areas or dark theme backgrounds.",
4066
+ surfaceTint: "Tint color applied to surfaces for subtle primary color elevation overlay.",
4067
+ surfaceVariant: "Alternative surface color for differentiated areas like sidebar backgrounds.",
4068
+ tertiary: "Third accent color for complementary elements that balance primary and secondary.",
4069
+ tertiaryContainer: "Fill color for tertiary container elements like complementary cards.",
4070
+ tertiaryFixed: "Fixed tertiary color that stays the same in light and dark themes.",
4071
+ tertiaryFixedDim: "Dimmed variant of the fixed tertiary color for lower emphasis."
4072
+ };
4073
+ function isTokenName(key) {
4074
+ return key in tokenDescriptions;
4075
+ }
4076
+ var tokenNames = Object.keys(tokenDescriptions).filter(isTokenName);
3986
4077
  var SHADE_TO_TONE = [
3987
4078
  [50, 95],
3988
4079
  [100, 90],
@@ -4004,6 +4095,8 @@ var CORE_PALETTES = [
4004
4095
  "neutral",
4005
4096
  "neutral-variant"
4006
4097
  ];
4098
+
4099
+ // src/lib/builder.tailwind.ts
4007
4100
  function buildTailwind(ctx, options) {
4008
4101
  const { prefix, mergedColorsLight, hexCustomColors } = ctx;
4009
4102
  const lines = [];
@@ -4036,17 +4129,8 @@ function buildTailwind(ctx, options) {
4036
4129
  ${lines.join("\n ")}
4037
4130
  }
4038
4131
  `;
4039
- if (options?.shadcn) {
4040
- const shadcnLines = SHADCN_MAPPING.map(
4041
- ([shadcnVar, m3Token]) => `${shadcnVar}: var(--${prefix}-sys-color-${m3Token});`
4042
- );
4043
- output += `
4044
- :root,
4045
- .dark {
4046
- ${shadcnLines.join("\n ")}
4047
- }
4048
- `;
4049
- }
4132
+ if (options?.shadcn) output += `
4133
+ ${buildShadcnAliases(ctx)}`;
4050
4134
  return output;
4051
4135
  }
4052
4136
 
@@ -4064,7 +4148,24 @@ var DEFAULT_SCHEME = "tonalSpot";
4064
4148
  var DEFAULT_CONTRAST = 0;
4065
4149
  var DEFAULT_CUSTOM_COLORS = [];
4066
4150
  var DEFAULT_BLEND = true;
4067
- var DEFAULT_PREFIX = "md";
4151
+ var HEX_COLOR = /^#?(?:[0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
4152
+ function isHexColor(value) {
4153
+ return HEX_COLOR.test(value);
4154
+ }
4155
+ function assertHexColor(label, value) {
4156
+ if (!isHexColor(value))
4157
+ throw new Error(
4158
+ `Invalid ${label}: '${value}'. Expected a hex color \u2014 3, 6 or 8 hex digits, with or without '#' (e.g. #6750A4).`
4159
+ );
4160
+ }
4161
+ function assertHexInputs(source, cores, customColors) {
4162
+ assertHexColor("source", source);
4163
+ for (const [name, hex] of Object.entries(cores))
4164
+ if (hex !== void 0) assertHexColor(name, hex);
4165
+ customColors.forEach(
4166
+ (color, i) => assertHexColor(`customColors[${i}].hex`, color.hex)
4167
+ );
4168
+ }
4068
4169
  var STANDARD_TONES = [
4069
4170
  0,
4070
4171
  4,
@@ -4115,61 +4216,6 @@ var schemeToVariant = {
4115
4216
  fidelity: Variant.FIDELITY,
4116
4217
  content: Variant.CONTENT
4117
4218
  };
4118
- var tokenDescriptions = {
4119
- background: "Default background color for screens and large surfaces.",
4120
- error: "Color for error states, used on elements like error text and icons.",
4121
- errorContainer: "Fill color for error container elements like error banners.",
4122
- inverseOnSurface: "Color for text and icons on inverse surface backgrounds.",
4123
- inversePrimary: "Primary color used on inverse surface, e.g. buttons on snackbars.",
4124
- inverseSurface: "Background for elements that require reverse contrast, such as snackbars.",
4125
- onBackground: "Color for text and icons displayed on the background.",
4126
- onError: "Color for text and icons on error-colored elements.",
4127
- onErrorContainer: "Color for text and icons on error container elements.",
4128
- onPrimary: "Color for text and icons on primary-colored elements like filled buttons.",
4129
- onPrimaryContainer: "Color for text and icons on primary container elements like tonal buttons.",
4130
- onPrimaryFixed: "Color for text and icons on primary fixed elements, constant across themes.",
4131
- onPrimaryFixedVariant: "Lower-emphasis color for text and icons on primary fixed elements.",
4132
- onSecondary: "Color for text and icons on secondary-colored elements.",
4133
- onSecondaryContainer: "Color for text and icons on secondary container elements.",
4134
- onSecondaryFixed: "Color for text and icons on secondary fixed elements, constant across themes.",
4135
- onSecondaryFixedVariant: "Lower-emphasis color for text and icons on secondary fixed elements.",
4136
- onSurface: "High-emphasis color for text and icons on surface backgrounds.",
4137
- onSurfaceVariant: "Medium-emphasis color for text and icons on surface variant backgrounds.",
4138
- onTertiary: "Color for text and icons on tertiary-colored elements.",
4139
- onTertiaryContainer: "Color for text and icons on tertiary container elements.",
4140
- onTertiaryFixed: "Color for text and icons on tertiary fixed elements, constant across themes.",
4141
- onTertiaryFixedVariant: "Lower-emphasis color for text and icons on tertiary fixed elements.",
4142
- outline: "Subtle color for borders and dividers to create visual separation.",
4143
- outlineVariant: "Lower-emphasis border color used for decorative dividers.",
4144
- primary: "Main brand color, used for key components like filled buttons and active states.",
4145
- primaryContainer: "Fill color for large primary elements like cards and tonal buttons.",
4146
- primaryFixed: "Fixed primary color that stays the same in light and dark themes.",
4147
- primaryFixedDim: "Dimmed variant of the fixed primary color for lower emphasis.",
4148
- scrim: "Color overlay for modals and dialogs to obscure background content.",
4149
- secondary: "Accent color for less prominent elements like filter chips and selections.",
4150
- secondaryContainer: "Fill color for secondary container elements like tonal buttons and input fields.",
4151
- secondaryFixed: "Fixed secondary color that stays the same in light and dark themes.",
4152
- secondaryFixedDim: "Dimmed variant of the fixed secondary color for lower emphasis.",
4153
- shadow: "Color for elevation shadows applied to surfaces and components.",
4154
- surface: "Default surface color for cards, sheets, and dialogs.",
4155
- surfaceBright: "Brightest surface variant, used for elevated surfaces in dark themes.",
4156
- surfaceContainer: "Middle-emphasis container color for grouping related content.",
4157
- surfaceContainerHigh: "Higher-emphasis container color for elements like cards.",
4158
- surfaceContainerHighest: "Highest-emphasis container color for text fields and other input areas.",
4159
- surfaceContainerLow: "Lower-emphasis container color for subtle surface groupings.",
4160
- surfaceContainerLowest: "Lowest-emphasis container, typically the lightest surface in light theme.",
4161
- surfaceDim: "Dimmest surface variant, used for recessed areas or dark theme backgrounds.",
4162
- surfaceTint: "Tint color applied to surfaces for subtle primary color elevation overlay.",
4163
- surfaceVariant: "Alternative surface color for differentiated areas like sidebar backgrounds.",
4164
- tertiary: "Third accent color for complementary elements that balance primary and secondary.",
4165
- tertiaryContainer: "Fill color for tertiary container elements like complementary cards.",
4166
- tertiaryFixed: "Fixed tertiary color that stays the same in light and dark themes.",
4167
- tertiaryFixedDim: "Dimmed variant of the fixed tertiary color for lower emphasis."
4168
- };
4169
- function isTokenName(key) {
4170
- return key in tokenDescriptions;
4171
- }
4172
- var tokenNames = Object.keys(tokenDescriptions).filter(isTokenName);
4173
4219
  function deriveCustomPaletteName(tokenName, allPaletteNamesKebab) {
4174
4220
  let baseName = tokenName;
4175
4221
  if (/^on[A-Z]/.test(baseName) && baseName.length > 2) {
@@ -4288,6 +4334,11 @@ function builder(hexSource, {
4288
4334
  customColors: hexCustomColors = DEFAULT_CUSTOM_COLORS,
4289
4335
  prefix = DEFAULT_PREFIX
4290
4336
  } = {}) {
4337
+ assertHexInputs(
4338
+ hexSource,
4339
+ { primary, secondary, tertiary, error, neutral, neutralVariant },
4340
+ hexCustomColors
4341
+ );
4291
4342
  const sourceArgb = argbFromHex2(hexSource);
4292
4343
  const sourceHct = Hct2.fromInt(sourceArgb);
4293
4344
  const effectiveSource = primary || hexSource;
@@ -4431,6 +4482,8 @@ function builder(hexSource, {
4431
4482
  toFigmaTokens: () => buildFigmaTokens(ctx),
4432
4483
  toTailwind: (options) => buildTailwind(ctx, options),
4433
4484
  toShadcn: () => buildShadcn(ctx),
4485
+ toShadcnAliases: () => buildShadcnAliases(ctx),
4486
+ toShadcnRegistryItem: (options) => buildShadcnRegistryItem(ctx, options),
4434
4487
  toFlutter: () => buildFlutter(ctx),
4435
4488
  mergedColorsLight,
4436
4489
  mergedColorsDark,
@@ -4524,15 +4577,15 @@ var createRequiredContext = () => {
4524
4577
  import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
4525
4578
  var [useMtb, Provider, MtbContext] = createRequiredContext();
4526
4579
  var MtbProvider = ({
4527
- styleId,
4580
+ styleId: styleId2,
4528
4581
  children,
4529
4582
  ...configProps
4530
4583
  }) => {
4531
4584
  const [initials] = useState(() => configProps);
4532
- const [mcuConfig, setMcuConfig] = useState(initials);
4585
+ const [mtbConfig, setMtbConfig] = useState(initials);
4533
4586
  const configKey = JSON.stringify(configProps);
4534
4587
  React.useEffect(() => {
4535
- setMcuConfig(configProps);
4588
+ setMtbConfig(configProps);
4536
4589
  }, [configKey]);
4537
4590
  const {
4538
4591
  css,
@@ -4543,8 +4596,8 @@ var MtbProvider = ({
4543
4596
  figmaVariables
4544
4597
  } = useMemo(() => {
4545
4598
  const { toCss, toFigmaTokens, toFigmaVariables, ...rest } = builder(
4546
- mcuConfig.source,
4547
- mcuConfig
4599
+ mtbConfig.source,
4600
+ mtbConfig
4548
4601
  );
4549
4602
  return {
4550
4603
  css: toCss(),
@@ -4552,13 +4605,13 @@ var MtbProvider = ({
4552
4605
  figmaVariables: toFigmaVariables(),
4553
4606
  ...rest
4554
4607
  };
4555
- }, [mcuConfig]);
4556
- const getMcuColor = useCallback(
4608
+ }, [mtbConfig]);
4609
+ const getMtbColor = useCallback(
4557
4610
  (colorName, theme) => {
4558
4611
  const mergedColors = theme === "light" ? mergedColorsLight : mergedColorsDark;
4559
4612
  const colorValue = mergedColors[colorName];
4560
4613
  if (colorValue === void 0) {
4561
- throw new Error(`Unknown MCU token '${colorName}'`);
4614
+ throw new Error(`Unknown token '${colorName}'`);
4562
4615
  }
4563
4616
  return hexFromArgb5(colorValue);
4564
4617
  },
@@ -4567,24 +4620,28 @@ var MtbProvider = ({
4567
4620
  const value = useMemo(
4568
4621
  () => ({
4569
4622
  initials,
4570
- mcuConfig,
4571
- setMcuConfig,
4572
- getMcuColor,
4623
+ mtbConfig,
4624
+ setMtbConfig,
4625
+ getMtbColor,
4573
4626
  allPalettes,
4574
4627
  figmaTokens,
4575
- figmaVariables
4628
+ figmaVariables,
4629
+ // deprecated aliases
4630
+ mcuConfig: mtbConfig,
4631
+ setMcuConfig: setMtbConfig,
4632
+ getMcuColor: getMtbColor
4576
4633
  }),
4577
4634
  [
4578
- getMcuColor,
4635
+ getMtbColor,
4579
4636
  initials,
4580
- mcuConfig,
4637
+ mtbConfig,
4581
4638
  allPalettes,
4582
4639
  figmaTokens,
4583
4640
  figmaVariables
4584
4641
  ]
4585
4642
  );
4586
4643
  return /* @__PURE__ */ jsxs2(Provider, { value, children: [
4587
- /* @__PURE__ */ jsx3("style", { id: styleId, dangerouslySetInnerHTML: { __html: css } }),
4644
+ /* @__PURE__ */ jsx3("style", { id: styleId2, dangerouslySetInnerHTML: { __html: css } }),
4588
4645
  children
4589
4646
  ] });
4590
4647
  };
@@ -4592,7 +4649,7 @@ var useMcu = useMtb;
4592
4649
 
4593
4650
  // src/Mtb.tsx
4594
4651
  import { jsx as jsx4 } from "react/jsx-runtime";
4595
- var mcuStyleId = "mcu-styles";
4652
+ var styleId = "mcu-styles";
4596
4653
  var DEFAULT_COLOR_MATCH = false;
4597
4654
  function Mtb({
4598
4655
  source,
@@ -4639,7 +4696,7 @@ function Mtb({
4639
4696
  prefix
4640
4697
  ]
4641
4698
  );
4642
- return /* @__PURE__ */ jsx4(MtbProvider, { ...config, styleId: mcuStyleId, children });
4699
+ return /* @__PURE__ */ jsx4(MtbProvider, { ...config, styleId, children });
4643
4700
  }
4644
4701
  var Mcu = Mtb;
4645
4702
  export {
@@ -0,0 +1,75 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "material-theme-builder",
4
+ "type": "registry:theme",
5
+ "title": "Material Theme Builder",
6
+ "description": "Points shadcn's CSS variables at the M3 custom properties `<Mtb>` emits, so every shadcn component follows whichever theme is above it in the tree.",
7
+ "cssVars": {
8
+ "light": {
9
+ "background": "var(--md-sys-color-surface)",
10
+ "foreground": "var(--md-sys-color-on-surface)",
11
+ "card": "var(--md-sys-color-surface-container-low)",
12
+ "card-foreground": "var(--md-sys-color-on-surface)",
13
+ "popover": "var(--md-sys-color-surface-container-high)",
14
+ "popover-foreground": "var(--md-sys-color-on-surface)",
15
+ "primary": "var(--md-sys-color-primary)",
16
+ "primary-foreground": "var(--md-sys-color-on-primary)",
17
+ "secondary": "var(--md-sys-color-secondary-container)",
18
+ "secondary-foreground": "var(--md-sys-color-on-secondary-container)",
19
+ "muted": "var(--md-sys-color-surface-container-highest)",
20
+ "muted-foreground": "var(--md-sys-color-on-surface-variant)",
21
+ "accent": "var(--md-sys-color-secondary-container)",
22
+ "accent-foreground": "var(--md-sys-color-on-secondary-container)",
23
+ "destructive": "var(--md-sys-color-error)",
24
+ "border": "var(--md-sys-color-outline-variant)",
25
+ "input": "var(--md-sys-color-outline)",
26
+ "ring": "var(--md-sys-color-primary)",
27
+ "chart-1": "var(--md-sys-color-primary-fixed)",
28
+ "chart-2": "var(--md-sys-color-secondary-fixed)",
29
+ "chart-3": "var(--md-sys-color-tertiary-fixed)",
30
+ "chart-4": "var(--md-sys-color-primary-fixed-dim)",
31
+ "chart-5": "var(--md-sys-color-secondary-fixed-dim)",
32
+ "sidebar": "var(--md-sys-color-surface-container-low)",
33
+ "sidebar-foreground": "var(--md-sys-color-on-surface)",
34
+ "sidebar-primary": "var(--md-sys-color-primary)",
35
+ "sidebar-primary-foreground": "var(--md-sys-color-on-primary)",
36
+ "sidebar-accent": "var(--md-sys-color-secondary-container)",
37
+ "sidebar-accent-foreground": "var(--md-sys-color-on-secondary-container)",
38
+ "sidebar-border": "var(--md-sys-color-outline-variant)",
39
+ "sidebar-ring": "var(--md-sys-color-primary)"
40
+ },
41
+ "dark": {
42
+ "background": "var(--md-sys-color-surface)",
43
+ "foreground": "var(--md-sys-color-on-surface)",
44
+ "card": "var(--md-sys-color-surface-container-low)",
45
+ "card-foreground": "var(--md-sys-color-on-surface)",
46
+ "popover": "var(--md-sys-color-surface-container-high)",
47
+ "popover-foreground": "var(--md-sys-color-on-surface)",
48
+ "primary": "var(--md-sys-color-primary)",
49
+ "primary-foreground": "var(--md-sys-color-on-primary)",
50
+ "secondary": "var(--md-sys-color-secondary-container)",
51
+ "secondary-foreground": "var(--md-sys-color-on-secondary-container)",
52
+ "muted": "var(--md-sys-color-surface-container-highest)",
53
+ "muted-foreground": "var(--md-sys-color-on-surface-variant)",
54
+ "accent": "var(--md-sys-color-secondary-container)",
55
+ "accent-foreground": "var(--md-sys-color-on-secondary-container)",
56
+ "destructive": "var(--md-sys-color-error)",
57
+ "border": "var(--md-sys-color-outline-variant)",
58
+ "input": "var(--md-sys-color-outline)",
59
+ "ring": "var(--md-sys-color-primary)",
60
+ "chart-1": "var(--md-sys-color-primary-fixed)",
61
+ "chart-2": "var(--md-sys-color-secondary-fixed)",
62
+ "chart-3": "var(--md-sys-color-tertiary-fixed)",
63
+ "chart-4": "var(--md-sys-color-primary-fixed-dim)",
64
+ "chart-5": "var(--md-sys-color-secondary-fixed-dim)",
65
+ "sidebar": "var(--md-sys-color-surface-container-low)",
66
+ "sidebar-foreground": "var(--md-sys-color-on-surface)",
67
+ "sidebar-primary": "var(--md-sys-color-primary)",
68
+ "sidebar-primary-foreground": "var(--md-sys-color-on-primary)",
69
+ "sidebar-accent": "var(--md-sys-color-secondary-container)",
70
+ "sidebar-accent-foreground": "var(--md-sys-color-on-secondary-container)",
71
+ "sidebar-border": "var(--md-sys-color-outline-variant)",
72
+ "sidebar-ring": "var(--md-sys-color-primary)"
73
+ }
74
+ }
75
+ }
@@ -0,0 +1,43 @@
1
+ /*
2
+ * Generated by `scripts/generate.mjs` -- do not edit.
3
+ *
4
+ * Points shadcn's variables at the M3 custom properties `<Mtb>` emits, so
5
+ * shadcn components follow the theme above them in the tree. Import it after
6
+ * shadcn's own `:root` and `.dark` blocks, which it has to override -- or
7
+ * skip the ordering question entirely and install `registry-item.json` with
8
+ * `shadcn add`, which writes the same mapping into those blocks in place.
9
+ */
10
+ :root,
11
+ .dark {
12
+ --background: var(--md-sys-color-surface);
13
+ --foreground: var(--md-sys-color-on-surface);
14
+ --card: var(--md-sys-color-surface-container-low);
15
+ --card-foreground: var(--md-sys-color-on-surface);
16
+ --popover: var(--md-sys-color-surface-container-high);
17
+ --popover-foreground: var(--md-sys-color-on-surface);
18
+ --primary: var(--md-sys-color-primary);
19
+ --primary-foreground: var(--md-sys-color-on-primary);
20
+ --secondary: var(--md-sys-color-secondary-container);
21
+ --secondary-foreground: var(--md-sys-color-on-secondary-container);
22
+ --muted: var(--md-sys-color-surface-container-highest);
23
+ --muted-foreground: var(--md-sys-color-on-surface-variant);
24
+ --accent: var(--md-sys-color-secondary-container);
25
+ --accent-foreground: var(--md-sys-color-on-secondary-container);
26
+ --destructive: var(--md-sys-color-error);
27
+ --border: var(--md-sys-color-outline-variant);
28
+ --input: var(--md-sys-color-outline);
29
+ --ring: var(--md-sys-color-primary);
30
+ --chart-1: var(--md-sys-color-primary-fixed);
31
+ --chart-2: var(--md-sys-color-secondary-fixed);
32
+ --chart-3: var(--md-sys-color-tertiary-fixed);
33
+ --chart-4: var(--md-sys-color-primary-fixed-dim);
34
+ --chart-5: var(--md-sys-color-secondary-fixed-dim);
35
+ --sidebar: var(--md-sys-color-surface-container-low);
36
+ --sidebar-foreground: var(--md-sys-color-on-surface);
37
+ --sidebar-primary: var(--md-sys-color-primary);
38
+ --sidebar-primary-foreground: var(--md-sys-color-on-primary);
39
+ --sidebar-accent: var(--md-sys-color-secondary-container);
40
+ --sidebar-accent-foreground: var(--md-sys-color-on-secondary-container);
41
+ --sidebar-border: var(--md-sys-color-outline-variant);
42
+ --sidebar-ring: var(--md-sys-color-primary);
43
+ }
@@ -0,0 +1,73 @@
1
+ import * as node_modules_tailwindcss_dist_types_CJYAW1ql_mjs from 'node_modules/tailwindcss/dist/types-CJYAW1ql.mjs';
2
+
3
+ /**
4
+ * Options accepted by `@plugin "material-theme-builder/tailwind" { ... }`.
5
+ *
6
+ * Tailwind parses the block as CSS declarations, so the property names are
7
+ * kebab-case and a comma-separated value arrives as an array. Everything is
8
+ * typed loosely on the way in because the values come from a stylesheet, not
9
+ * from a type-checked call site.
10
+ */
11
+ type MtbTailwindPluginOptions = {
12
+ /**
13
+ * Custom color names, exactly as passed to `builder()` / `<Mtb>`:
14
+ *
15
+ * ```css
16
+ * @plugin "material-theme-builder/tailwind" {
17
+ * custom-colors: myCustomColor1, myCustomColor2;
18
+ * }
19
+ * ```
20
+ */
21
+ "custom-colors"?: string | string[] | number | (string | number)[];
22
+ /** CSS custom-property prefix, matching `builder({ prefix })`. Default `md`. */
23
+ prefix?: string;
24
+ };
25
+ /**
26
+ * The `--color-*` map the plugin registers, as a plain object.
27
+ *
28
+ * Keys are Tailwind color names (`primary`, `on-primary`, `primary-500`),
29
+ * values are `var()` references into the `--{prefix}-sys-color-*` /
30
+ * `--{prefix}-ref-palette-*` properties `<Mtb>` (or `builder().toCss()`) emits.
31
+ *
32
+ * Custom colors keep the name they were declared with — `myCustomColor1` stays
33
+ * `bg-myCustomColor1` — while the CSS property it points at is kebab-cased,
34
+ * because that is the spelling the builder writes.
35
+ */
36
+ declare function mtbColors({ customColors, prefix, }?: {
37
+ customColors?: string[];
38
+ prefix?: string;
39
+ }): Record<string, string>;
40
+ /**
41
+ * Tailwind v4 plugin — the `@theme inline` block of
42
+ * `material-theme-builder/tailwind.css`, minus the copy-paste.
43
+ *
44
+ * ```css
45
+ * @import "tailwindcss";
46
+ * @plugin "material-theme-builder/tailwind" {
47
+ * custom-colors: myCustomColor1, myCustomColor2;
48
+ * }
49
+ * ```
50
+ *
51
+ * Colors declared through a plugin's `theme` are inlined by Tailwind — the
52
+ * utility resolves straight to `var(--md-sys-color-primary)` and no
53
+ * `--color-*` indirection is emitted — which is what the stylesheet's
54
+ * `@theme inline` was there to get. That indirection is not cosmetic: a
55
+ * `--color-primary: var(--md-sys-color-primary)` declared on `:root` resolves
56
+ * once, against `:root`, so a nested `<Mtb>` re-declaring the M3 properties
57
+ * would not reach the utilities.
58
+ *
59
+ * Unlike the stylesheet, custom colors need no hand-written block: name them
60
+ * in the options and their four scheme roles plus eleven shades come with them.
61
+ *
62
+ * One thing the stylesheet does that this cannot: theme values a plugin
63
+ * contributes are defaults, so an `@theme` block in the consumer's own CSS
64
+ * wins over them whatever the order — where a later `@import` of the
65
+ * stylesheet would have won. Only colliding names are affected, and against
66
+ * shadcn there are exactly three (`background`, `primary`, `secondary`), which
67
+ * a three-line `@theme inline` of one's own hands back. See the README.
68
+ *
69
+ * @see https://tailwindcss.com/docs/functions-and-directives#plugin-directive
70
+ */
71
+ declare const mtbTailwindPlugin: node_modules_tailwindcss_dist_types_CJYAW1ql_mjs.c<MtbTailwindPluginOptions>;
72
+
73
+ export { type MtbTailwindPluginOptions, mtbTailwindPlugin as default, mtbColors };
@@ -0,0 +1,135 @@
1
+ // src/tailwind-plugin.ts
2
+ import { kebabCase } from "lodash-es";
3
+ import plugin from "tailwindcss/plugin";
4
+
5
+ // src/lib/tokens.ts
6
+ var DEFAULT_PREFIX = "md";
7
+ var tokenDescriptions = {
8
+ background: "Default background color for screens and large surfaces.",
9
+ error: "Color for error states, used on elements like error text and icons.",
10
+ errorContainer: "Fill color for error container elements like error banners.",
11
+ inverseOnSurface: "Color for text and icons on inverse surface backgrounds.",
12
+ inversePrimary: "Primary color used on inverse surface, e.g. buttons on snackbars.",
13
+ inverseSurface: "Background for elements that require reverse contrast, such as snackbars.",
14
+ onBackground: "Color for text and icons displayed on the background.",
15
+ onError: "Color for text and icons on error-colored elements.",
16
+ onErrorContainer: "Color for text and icons on error container elements.",
17
+ onPrimary: "Color for text and icons on primary-colored elements like filled buttons.",
18
+ onPrimaryContainer: "Color for text and icons on primary container elements like tonal buttons.",
19
+ onPrimaryFixed: "Color for text and icons on primary fixed elements, constant across themes.",
20
+ onPrimaryFixedVariant: "Lower-emphasis color for text and icons on primary fixed elements.",
21
+ onSecondary: "Color for text and icons on secondary-colored elements.",
22
+ onSecondaryContainer: "Color for text and icons on secondary container elements.",
23
+ onSecondaryFixed: "Color for text and icons on secondary fixed elements, constant across themes.",
24
+ onSecondaryFixedVariant: "Lower-emphasis color for text and icons on secondary fixed elements.",
25
+ onSurface: "High-emphasis color for text and icons on surface backgrounds.",
26
+ onSurfaceVariant: "Medium-emphasis color for text and icons on surface variant backgrounds.",
27
+ onTertiary: "Color for text and icons on tertiary-colored elements.",
28
+ onTertiaryContainer: "Color for text and icons on tertiary container elements.",
29
+ onTertiaryFixed: "Color for text and icons on tertiary fixed elements, constant across themes.",
30
+ onTertiaryFixedVariant: "Lower-emphasis color for text and icons on tertiary fixed elements.",
31
+ outline: "Subtle color for borders and dividers to create visual separation.",
32
+ outlineVariant: "Lower-emphasis border color used for decorative dividers.",
33
+ primary: "Main brand color, used for key components like filled buttons and active states.",
34
+ primaryContainer: "Fill color for large primary elements like cards and tonal buttons.",
35
+ primaryFixed: "Fixed primary color that stays the same in light and dark themes.",
36
+ primaryFixedDim: "Dimmed variant of the fixed primary color for lower emphasis.",
37
+ scrim: "Color overlay for modals and dialogs to obscure background content.",
38
+ secondary: "Accent color for less prominent elements like filter chips and selections.",
39
+ secondaryContainer: "Fill color for secondary container elements like tonal buttons and input fields.",
40
+ secondaryFixed: "Fixed secondary color that stays the same in light and dark themes.",
41
+ secondaryFixedDim: "Dimmed variant of the fixed secondary color for lower emphasis.",
42
+ shadow: "Color for elevation shadows applied to surfaces and components.",
43
+ surface: "Default surface color for cards, sheets, and dialogs.",
44
+ surfaceBright: "Brightest surface variant, used for elevated surfaces in dark themes.",
45
+ surfaceContainer: "Middle-emphasis container color for grouping related content.",
46
+ surfaceContainerHigh: "Higher-emphasis container color for elements like cards.",
47
+ surfaceContainerHighest: "Highest-emphasis container color for text fields and other input areas.",
48
+ surfaceContainerLow: "Lower-emphasis container color for subtle surface groupings.",
49
+ surfaceContainerLowest: "Lowest-emphasis container, typically the lightest surface in light theme.",
50
+ surfaceDim: "Dimmest surface variant, used for recessed areas or dark theme backgrounds.",
51
+ surfaceTint: "Tint color applied to surfaces for subtle primary color elevation overlay.",
52
+ surfaceVariant: "Alternative surface color for differentiated areas like sidebar backgrounds.",
53
+ tertiary: "Third accent color for complementary elements that balance primary and secondary.",
54
+ tertiaryContainer: "Fill color for tertiary container elements like complementary cards.",
55
+ tertiaryFixed: "Fixed tertiary color that stays the same in light and dark themes.",
56
+ tertiaryFixedDim: "Dimmed variant of the fixed tertiary color for lower emphasis."
57
+ };
58
+ function isTokenName(key) {
59
+ return key in tokenDescriptions;
60
+ }
61
+ var tokenNames = Object.keys(tokenDescriptions).filter(isTokenName);
62
+ var SHADE_TO_TONE = [
63
+ [50, 95],
64
+ [100, 90],
65
+ [200, 80],
66
+ [300, 70],
67
+ [400, 60],
68
+ [500, 50],
69
+ [600, 40],
70
+ [700, 30],
71
+ [800, 20],
72
+ [900, 10],
73
+ [950, 5]
74
+ ];
75
+ var CORE_PALETTES = [
76
+ "primary",
77
+ "secondary",
78
+ "tertiary",
79
+ "error",
80
+ "neutral",
81
+ "neutral-variant"
82
+ ];
83
+
84
+ // src/tailwind-plugin.ts
85
+ function toNames(value) {
86
+ if (value === void 0 || value === null) return [];
87
+ return (Array.isArray(value) ? value : [value]).flatMap((entry) => String(entry).split(/[\s,]+/)).map((name) => name.trim().replace(/^["']|["']$/g, "")).filter(Boolean);
88
+ }
89
+ function mtbColors({
90
+ customColors = [],
91
+ prefix = DEFAULT_PREFIX
92
+ } = {}) {
93
+ const colors = {};
94
+ const sys = (token) => `var(--${prefix}-sys-color-${token})`;
95
+ const ref = (palette, tone) => `var(--${prefix}-ref-palette-${palette}-${tone})`;
96
+ for (const name of tokenNames) {
97
+ const kebab = kebabCase(name);
98
+ colors[kebab] = sys(kebab);
99
+ }
100
+ for (const palette of CORE_PALETTES) {
101
+ for (const [shade, tone] of SHADE_TO_TONE) {
102
+ colors[`${palette}-${shade}`] = ref(palette, tone);
103
+ }
104
+ }
105
+ for (const name of customColors) {
106
+ const kebab = kebabCase(name);
107
+ colors[name] = sys(kebab);
108
+ colors[`on-${name}`] = sys(`on-${kebab}`);
109
+ colors[`${name}-container`] = sys(`${kebab}-container`);
110
+ colors[`on-${name}-container`] = sys(`on-${kebab}-container`);
111
+ for (const [shade, tone] of SHADE_TO_TONE) {
112
+ colors[`${name}-${shade}`] = ref(kebab, tone);
113
+ }
114
+ }
115
+ return colors;
116
+ }
117
+ var mtbTailwindPlugin = plugin.withOptions(
118
+ () => () => {
119
+ },
120
+ (options = {}) => ({
121
+ theme: {
122
+ extend: {
123
+ colors: mtbColors({
124
+ customColors: toNames(options["custom-colors"]),
125
+ prefix: options.prefix
126
+ })
127
+ }
128
+ }
129
+ })
130
+ );
131
+ var tailwind_plugin_default = mtbTailwindPlugin;
132
+ export {
133
+ tailwind_plugin_default as default,
134
+ mtbColors
135
+ };