material-theme-builder 3.2.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/README.md +284 -236
- package/dist/cli.js +520 -105
- package/dist/index.d.ts +30 -1
- package/dist/index.js +120 -67
- package/dist/react.d.ts +69 -49
- package/dist/react.js +120 -67
- package/dist/registry-item.json +75 -0
- package/dist/shadcn.css +43 -0
- package/dist/tailwind-plugin.d.ts +73 -0
- package/dist/tailwind-plugin.js +135 -0
- package/dist/tailwind.css +47 -81
- package/package.json +31 -10
- package/src/tailwind.css +0 -179
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
|
-
|
|
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
|
|
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,
|
|
@@ -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
|
+
}
|
package/dist/shadcn.css
ADDED
|
@@ -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
|
+
};
|