@diskette/palette 0.11.0 → 0.13.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/cli.js +66 -102
- package/dist/css.d.ts +39 -0
- package/dist/css.js +145 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/types.d.ts +1 -0
- package/dist/utils.d.ts +10 -0
- package/dist/utils.js +45 -0
- package/package.json +1 -1
- package/dist/lib.d.ts +0 -30
- package/dist/lib.js +0 -89
package/dist/cli.js
CHANGED
|
@@ -2,18 +2,35 @@ import * as p from '@clack/prompts';
|
|
|
2
2
|
import { mkdirSync, statSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
4
|
import { blackAlpha, whiteAlpha } from "./colors/index.js";
|
|
5
|
-
import { colors, css, grayColors } from "./index.js";
|
|
6
|
-
function
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
import { accentColors, colors, css, grayColors } from "./index.js";
|
|
6
|
+
function cancel() {
|
|
7
|
+
p.cancel('Operation cancelled.');
|
|
8
|
+
process.exit(0);
|
|
9
|
+
}
|
|
10
|
+
async function askColors(label, choices) {
|
|
11
|
+
const mode = await p.select({
|
|
12
|
+
message: `Which ${label} colors do you want to generate?`,
|
|
13
|
+
options: [
|
|
14
|
+
{ value: 'select', label: 'Select specific colors' },
|
|
15
|
+
{
|
|
16
|
+
value: 'all',
|
|
17
|
+
label: `All ${label} colors`,
|
|
18
|
+
hint: `${choices.length} colors`,
|
|
19
|
+
},
|
|
20
|
+
],
|
|
16
21
|
});
|
|
22
|
+
if (p.isCancel(mode))
|
|
23
|
+
cancel();
|
|
24
|
+
if (mode === 'all')
|
|
25
|
+
return choices;
|
|
26
|
+
const selected = await p.autocompleteMultiselect({
|
|
27
|
+
message: `Select ${label} colors:`,
|
|
28
|
+
options: choices.map((name) => ({ value: name, label: name })),
|
|
29
|
+
required: false,
|
|
30
|
+
});
|
|
31
|
+
if (p.isCancel(selected))
|
|
32
|
+
cancel();
|
|
33
|
+
return selected;
|
|
17
34
|
}
|
|
18
35
|
async function askOutputDir(message) {
|
|
19
36
|
const outputDir = await p.text({
|
|
@@ -31,105 +48,52 @@ async function askOutputDir(message) {
|
|
|
31
48
|
catch { }
|
|
32
49
|
},
|
|
33
50
|
});
|
|
34
|
-
if (p.isCancel(outputDir))
|
|
35
|
-
|
|
36
|
-
process.exit(0);
|
|
37
|
-
}
|
|
51
|
+
if (p.isCancel(outputDir))
|
|
52
|
+
cancel();
|
|
38
53
|
return outputDir;
|
|
39
54
|
}
|
|
40
55
|
async function main() {
|
|
41
56
|
p.intro('Palette CSS Generator');
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
{ value: 'select', label: 'Select specific colors' },
|
|
48
|
-
],
|
|
49
|
-
});
|
|
50
|
-
if (p.isCancel(scaleMode)) {
|
|
51
|
-
p.cancel('Operation cancelled.');
|
|
52
|
-
process.exit(0);
|
|
53
|
-
}
|
|
54
|
-
let scaleColors = colors;
|
|
55
|
-
if (scaleMode === 'select') {
|
|
56
|
-
const scaleChoices = await p.autocompleteMultiselect({
|
|
57
|
-
message: 'Select colors for scales:',
|
|
58
|
-
options: colorOptions(),
|
|
59
|
-
required: true,
|
|
60
|
-
});
|
|
61
|
-
if (p.isCancel(scaleChoices)) {
|
|
62
|
-
p.cancel('Operation cancelled.');
|
|
63
|
-
process.exit(0);
|
|
64
|
-
}
|
|
65
|
-
scaleColors = colors.filter((c) => scaleChoices.includes(c.name));
|
|
66
|
-
}
|
|
67
|
-
const scalesOutputDir = await askOutputDir('Output directory for color scales:');
|
|
68
|
-
// --- Semantic Tokens ---
|
|
69
|
-
const generateSemantic = await p.confirm({
|
|
70
|
-
message: 'Generate semantic tokens?',
|
|
57
|
+
const selectedAccentColors = await askColors('accent', accentColors);
|
|
58
|
+
const selectedGrayColors = await askColors('gray', grayColors.slice(1));
|
|
59
|
+
const selectedColors = [...selectedAccentColors, ...selectedGrayColors];
|
|
60
|
+
const generateAccents = await p.confirm({
|
|
61
|
+
message: 'Generate accents for selected colors?',
|
|
71
62
|
});
|
|
72
|
-
if (p.isCancel(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
let semanticColors = colors;
|
|
77
|
-
let semanticOutputDir = null;
|
|
78
|
-
if (generateSemantic) {
|
|
79
|
-
const semanticMode = await p.select({
|
|
80
|
-
message: 'Which colors for semantic tokens?',
|
|
81
|
-
options: [
|
|
82
|
-
{ value: 'all', label: 'All colors', hint: `${colors.length} colors` },
|
|
83
|
-
{ value: 'select', label: 'Select specific colors' },
|
|
84
|
-
],
|
|
85
|
-
});
|
|
86
|
-
if (p.isCancel(semanticMode)) {
|
|
87
|
-
p.cancel('Operation cancelled.');
|
|
88
|
-
process.exit(0);
|
|
89
|
-
}
|
|
90
|
-
if (semanticMode === 'select') {
|
|
91
|
-
const semanticChoices = await p.autocompleteMultiselect({
|
|
92
|
-
message: 'Select colors for semantic tokens:',
|
|
93
|
-
options: colorOptions(),
|
|
94
|
-
required: true,
|
|
95
|
-
});
|
|
96
|
-
if (p.isCancel(semanticChoices)) {
|
|
97
|
-
p.cancel('Operation cancelled.');
|
|
98
|
-
process.exit(0);
|
|
99
|
-
}
|
|
100
|
-
semanticColors = colors.filter((c) => semanticChoices.includes(c.name));
|
|
101
|
-
}
|
|
102
|
-
semanticOutputDir = await askOutputDir('Output directory for semantic tokens:');
|
|
103
|
-
}
|
|
63
|
+
if (p.isCancel(generateAccents))
|
|
64
|
+
cancel();
|
|
65
|
+
const outputDir = await askOutputDir('Output directory:');
|
|
104
66
|
// --- Generate Files ---
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
writeFileSync(`${
|
|
113
|
-
writeFileSync(`${scalesPath}/${name}-alpha.css`, css.scale('lightAlpha', color));
|
|
114
|
-
writeFileSync(`${scalesPath}/${name}-dark.css`, css.scale('dark', color));
|
|
115
|
-
writeFileSync(`${scalesPath}/${name}-dark-alpha.css`, css.scale('darkAlpha', color));
|
|
67
|
+
const outputPath = resolve(process.cwd(), outputDir);
|
|
68
|
+
mkdirSync(outputPath, { recursive: true });
|
|
69
|
+
for (const name of selectedColors) {
|
|
70
|
+
const palette = colors.find((c) => c.name === name);
|
|
71
|
+
// Light theme (scales + alphas + semantics)
|
|
72
|
+
writeFileSync(`${outputPath}/${name}.css`, css.palette(name, palette, { schemes: ['light'], alpha: true }));
|
|
73
|
+
// Dark theme (scales + alphas + semantics)
|
|
74
|
+
writeFileSync(`${outputPath}/${name}-dark.css`, css.palette(name, palette, { schemes: ['dark'], alpha: true }));
|
|
116
75
|
}
|
|
117
76
|
// Always generate alpha overlay files
|
|
118
|
-
writeFileSync(`${
|
|
119
|
-
writeFileSync(`${
|
|
120
|
-
// Generate
|
|
121
|
-
if (
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
writeFileSync(`${semanticPath}/${color.name}.css`, css.semantic(color.name, color));
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
s.stop();
|
|
129
|
-
let message = `Color scales saved to ${scalesPath}`;
|
|
130
|
-
if (semanticOutputDir) {
|
|
131
|
-
message += `\nSemantic tokens saved to ${resolve(process.cwd(), semanticOutputDir)}`;
|
|
77
|
+
writeFileSync(`${outputPath}/black-alpha.css`, css.alpha(blackAlpha));
|
|
78
|
+
writeFileSync(`${outputPath}/white-alpha.css`, css.alpha(whiteAlpha));
|
|
79
|
+
// Generate accents
|
|
80
|
+
if (generateAccents) {
|
|
81
|
+
const accents = css.accents([...selectedAccentColors]);
|
|
82
|
+
const grays = css.grays(selectedGrayColors, 'diskette-palette');
|
|
83
|
+
writeFileSync(`${outputPath}/accents.css`, `${accents}\n${grays}`);
|
|
132
84
|
}
|
|
133
|
-
|
|
85
|
+
// Generate Tailwind theme with imports
|
|
86
|
+
const imports = [
|
|
87
|
+
...selectedColors.flatMap((name) => [
|
|
88
|
+
`./${name}.css`,
|
|
89
|
+
`./${name}-dark.css`,
|
|
90
|
+
]),
|
|
91
|
+
'./black-alpha.css',
|
|
92
|
+
'./white-alpha.css',
|
|
93
|
+
]
|
|
94
|
+
.map((path) => `@import '${path}';`)
|
|
95
|
+
.join('\n');
|
|
96
|
+
writeFileSync(`${outputPath}/index.css`, `${imports}\n\n${css.tailwind(['white', 'black', 'accent', ...selectedColors])}`);
|
|
97
|
+
p.outro(`CSS saved to ${outputPath}`);
|
|
134
98
|
}
|
|
135
99
|
main().catch(console.error);
|
package/dist/css.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { AnyPalette } from './types.ts';
|
|
2
|
+
type AlphaConfig = {
|
|
3
|
+
srgb: Record<string, string>;
|
|
4
|
+
p3: Record<string, string>;
|
|
5
|
+
};
|
|
6
|
+
type PaletteOptions = {
|
|
7
|
+
/** Which color schemes to include. Defaults to ['light'] */
|
|
8
|
+
schemes?: ('light' | 'dark')[];
|
|
9
|
+
/** Include alpha scale variables (e.g., --amber-a1). Defaults to false */
|
|
10
|
+
alpha?: boolean;
|
|
11
|
+
};
|
|
12
|
+
declare function palette(name: string, config: AnyPalette, options?: PaletteOptions): string;
|
|
13
|
+
declare function alpha(config: AlphaConfig): string;
|
|
14
|
+
declare function accents(colorNames: string[]): string;
|
|
15
|
+
declare function grays(names: readonly string[], className: string): string;
|
|
16
|
+
declare function tailwind(colorNames: string[]): string;
|
|
17
|
+
export declare const css: {
|
|
18
|
+
/**
|
|
19
|
+
* Generate combined CSS for scale variables and semantic tokens
|
|
20
|
+
*/
|
|
21
|
+
palette: typeof palette;
|
|
22
|
+
/**
|
|
23
|
+
* Generate CSS for alpha-only color scales
|
|
24
|
+
*/
|
|
25
|
+
alpha: typeof alpha;
|
|
26
|
+
/**
|
|
27
|
+
* Generate CSS for accent color data attribute selectors
|
|
28
|
+
*/
|
|
29
|
+
accents: typeof accents;
|
|
30
|
+
/**
|
|
31
|
+
* Generate CSS for gray color data attribute selectors
|
|
32
|
+
*/
|
|
33
|
+
grays: typeof grays;
|
|
34
|
+
/**
|
|
35
|
+
* Generate Tailwind v4 @theme inline CSS mapping palette variables
|
|
36
|
+
*/
|
|
37
|
+
tailwind: typeof tailwind;
|
|
38
|
+
};
|
|
39
|
+
export {};
|
package/dist/css.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { formatNestedBlock, formatP3, formatRule, schemeSelector, toVarName, } from "./utils.js";
|
|
2
|
+
const steps = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
|
|
3
|
+
function palette(name, config, options = {}) {
|
|
4
|
+
const { schemes = ['light'], alpha = false } = options;
|
|
5
|
+
const output = [];
|
|
6
|
+
if (schemes.includes('light')) {
|
|
7
|
+
output.push(formatRule(':root', [
|
|
8
|
+
`--${name}-contrast: ${config.contrast}`,
|
|
9
|
+
`--${name}-indicator: var(${toVarName(config.indicator)})`,
|
|
10
|
+
`--${name}-track: var(${toVarName(config.track)})`,
|
|
11
|
+
]));
|
|
12
|
+
}
|
|
13
|
+
for (const scheme of schemes) {
|
|
14
|
+
const isLight = scheme === 'light';
|
|
15
|
+
const selector = schemeSelector(scheme);
|
|
16
|
+
const srgbScale = isLight ? config.srgb.light : config.srgb.dark;
|
|
17
|
+
const p3Scale = isLight ? config.p3.light : config.p3.dark;
|
|
18
|
+
const srgbSurface = isLight
|
|
19
|
+
? config.surface.srgb.light
|
|
20
|
+
: config.surface.srgb.dark;
|
|
21
|
+
const p3Surface = isLight ? config.surface.p3.light : config.surface.p3.dark;
|
|
22
|
+
const srgb = [];
|
|
23
|
+
const p3 = [];
|
|
24
|
+
for (const n of steps) {
|
|
25
|
+
srgb.push(`--${name}-${n}: ${srgbScale[`${name}${n}`]}`);
|
|
26
|
+
p3.push(`--${name}-${n}: ${p3Scale[`${name}${n}`]}`);
|
|
27
|
+
}
|
|
28
|
+
if (alpha) {
|
|
29
|
+
for (const n of steps) {
|
|
30
|
+
srgb.push(`--${name}-a${n}: ${srgbScale[`${name}A${n}`]}`);
|
|
31
|
+
p3.push(`--${name}-a${n}: ${p3Scale[`${name}A${n}`]}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
srgb.push(`--${name}-surface: ${srgbSurface}`);
|
|
35
|
+
p3.push(`--${name}-surface: ${p3Surface}`);
|
|
36
|
+
output.push(formatRule(selector, srgb));
|
|
37
|
+
output.push(formatP3(selector, p3));
|
|
38
|
+
}
|
|
39
|
+
return output.join('\n\n') + '\n';
|
|
40
|
+
}
|
|
41
|
+
function alpha(config) {
|
|
42
|
+
const srgb = [];
|
|
43
|
+
const p3 = [];
|
|
44
|
+
for (const key in config.srgb) {
|
|
45
|
+
srgb.push(`${toVarName(key)}: ${config.srgb[key]}`);
|
|
46
|
+
}
|
|
47
|
+
for (const key in config.p3) {
|
|
48
|
+
p3.push(`${toVarName(key)}: ${config.p3[key]}`);
|
|
49
|
+
}
|
|
50
|
+
return [formatRule(':root', srgb), formatP3(':root', p3)].join('\n\n') + '\n';
|
|
51
|
+
}
|
|
52
|
+
function accents(colorNames) {
|
|
53
|
+
const output = colorNames.map((colorName) => {
|
|
54
|
+
const srgb = [];
|
|
55
|
+
const alpha = [];
|
|
56
|
+
for (const n of steps) {
|
|
57
|
+
srgb.push(`--accent-${n}: var(--${colorName}-${n})`);
|
|
58
|
+
alpha.push(`--accent-a${n}: var(--${colorName}-a${n})`);
|
|
59
|
+
}
|
|
60
|
+
const semantic = [
|
|
61
|
+
`--accent-contrast: var(--${colorName}-contrast)`,
|
|
62
|
+
`--accent-surface: var(--${colorName}-surface)`,
|
|
63
|
+
`--accent-indicator: var(--${colorName}-indicator)`,
|
|
64
|
+
`--accent-track: var(--${colorName}-track)`,
|
|
65
|
+
];
|
|
66
|
+
return formatRule(`[data-accent-color='${colorName}']`, [
|
|
67
|
+
...srgb,
|
|
68
|
+
...alpha,
|
|
69
|
+
...semantic,
|
|
70
|
+
]);
|
|
71
|
+
});
|
|
72
|
+
const focus = [];
|
|
73
|
+
const focusAlpha = [];
|
|
74
|
+
for (const n of steps) {
|
|
75
|
+
focus.push(`--focus-${n}: var(--accent-${n})`);
|
|
76
|
+
focusAlpha.push(`--focus-a${n}: var(--accent-a${n})`);
|
|
77
|
+
}
|
|
78
|
+
output.push(formatRule(`[data-accent-color]:where(:not([data-accent-color=''], [data-accent-color='gray']))`, [...focus, ...focusAlpha]));
|
|
79
|
+
return output.join('\n\n') + '\n';
|
|
80
|
+
}
|
|
81
|
+
function grays(names, className) {
|
|
82
|
+
const grays = names.filter((n) => n !== 'gray');
|
|
83
|
+
const blocks = grays.map((colorName) => {
|
|
84
|
+
const srgb = [];
|
|
85
|
+
const alpha = [];
|
|
86
|
+
for (const n of steps) {
|
|
87
|
+
srgb.push(`--gray-${n}: var(--${colorName}-${n})`);
|
|
88
|
+
alpha.push(`--gray-a${n}: var(--${colorName}-a${n})`);
|
|
89
|
+
}
|
|
90
|
+
const semantic = [
|
|
91
|
+
`--gray-contrast: var(--${colorName}-contrast)`,
|
|
92
|
+
`--gray-surface: var(--${colorName}-surface)`,
|
|
93
|
+
`--gray-indicator: var(--${colorName}-indicator)`,
|
|
94
|
+
`--gray-track: var(--${colorName}-track)`,
|
|
95
|
+
];
|
|
96
|
+
return formatNestedBlock(`[data-gray-color='${colorName}']`, [
|
|
97
|
+
...srgb,
|
|
98
|
+
...alpha,
|
|
99
|
+
...semantic,
|
|
100
|
+
]);
|
|
101
|
+
});
|
|
102
|
+
return `.${className} {\n ${blocks.join('\n\n ')}\n}\n`;
|
|
103
|
+
}
|
|
104
|
+
function tailwind(colorNames) {
|
|
105
|
+
const blocks = [];
|
|
106
|
+
for (const name of colorNames) {
|
|
107
|
+
const declarations = [];
|
|
108
|
+
const isAlphaOnly = name === 'white' || name === 'black';
|
|
109
|
+
if (!isAlphaOnly) {
|
|
110
|
+
for (const n of steps) {
|
|
111
|
+
declarations.push(`--color-${name}-${n}: var(--${name}-${n})`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
for (const n of steps) {
|
|
115
|
+
declarations.push(`--color-${name}-a${n}: var(--${name}-a${n})`);
|
|
116
|
+
}
|
|
117
|
+
if (!isAlphaOnly) {
|
|
118
|
+
declarations.push(`--color-${name}-contrast: var(--${name}-contrast)`, `--color-${name}-surface: var(--${name}-surface)`, `--color-${name}-track: var(--${name}-track)`, `--color-${name}-indicator: var(--${name}-indicator)`);
|
|
119
|
+
}
|
|
120
|
+
blocks.push(declarations.join(';\n '));
|
|
121
|
+
}
|
|
122
|
+
return `@theme inline {\n ${blocks.join(';\n\n ')};\n}\n`;
|
|
123
|
+
}
|
|
124
|
+
export const css = {
|
|
125
|
+
/**
|
|
126
|
+
* Generate combined CSS for scale variables and semantic tokens
|
|
127
|
+
*/
|
|
128
|
+
palette,
|
|
129
|
+
/**
|
|
130
|
+
* Generate CSS for alpha-only color scales
|
|
131
|
+
*/
|
|
132
|
+
alpha,
|
|
133
|
+
/**
|
|
134
|
+
* Generate CSS for accent color data attribute selectors
|
|
135
|
+
*/
|
|
136
|
+
accents,
|
|
137
|
+
/**
|
|
138
|
+
* Generate CSS for gray color data attribute selectors
|
|
139
|
+
*/
|
|
140
|
+
grays,
|
|
141
|
+
/**
|
|
142
|
+
* Generate Tailwind v4 @theme inline CSS mapping palette variables
|
|
143
|
+
*/
|
|
144
|
+
tailwind,
|
|
145
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -3939,4 +3939,5 @@ export declare const colors: ({
|
|
|
3939
3939
|
export default colors;
|
|
3940
3940
|
export { accentColors, grayColors } from './types.ts';
|
|
3941
3941
|
export type { AccentColor, AlphaConfig, AlphaScale, Color, ColorPalette, ColorScale, GrayColor, } from './types.ts';
|
|
3942
|
-
export { css
|
|
3942
|
+
export { css } from './css.ts';
|
|
3943
|
+
export { getMatchingGrayColor } from './utils.ts';
|
package/dist/index.js
CHANGED
package/dist/types.d.ts
CHANGED
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AccentColor, GrayColor } from './types.ts';
|
|
2
|
+
export declare function getMatchingGrayColor(accentColor: AccentColor): GrayColor;
|
|
3
|
+
export declare const LIGHT_SELECTOR = ":root, .light, .light-theme";
|
|
4
|
+
export declare const DARK_SELECTOR = ".dark, .dark-theme";
|
|
5
|
+
export declare const schemeSelector: (scheme: "light" | "dark") => string;
|
|
6
|
+
/** Convert "amber9" to "--amber-9" or "amberA9" to "--amber-a9" */
|
|
7
|
+
export declare const toVarName: (key: string) => string;
|
|
8
|
+
export declare const formatRule: (selector: string, vars: string[]) => string;
|
|
9
|
+
export declare const formatP3: (selector: string, vars: string[]) => string;
|
|
10
|
+
export declare const formatNestedBlock: (selector: string, vars: string[]) => string;
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export function getMatchingGrayColor(accentColor) {
|
|
2
|
+
switch (accentColor) {
|
|
3
|
+
case 'tomato':
|
|
4
|
+
case 'red':
|
|
5
|
+
case 'ruby':
|
|
6
|
+
case 'crimson':
|
|
7
|
+
case 'pink':
|
|
8
|
+
case 'plum':
|
|
9
|
+
case 'purple':
|
|
10
|
+
case 'violet':
|
|
11
|
+
return 'mauve';
|
|
12
|
+
case 'iris':
|
|
13
|
+
case 'indigo':
|
|
14
|
+
case 'blue':
|
|
15
|
+
case 'sky':
|
|
16
|
+
case 'cyan':
|
|
17
|
+
return 'slate';
|
|
18
|
+
case 'teal':
|
|
19
|
+
case 'jade':
|
|
20
|
+
case 'mint':
|
|
21
|
+
case 'green':
|
|
22
|
+
return 'sage';
|
|
23
|
+
case 'grass':
|
|
24
|
+
case 'lime':
|
|
25
|
+
return 'olive';
|
|
26
|
+
case 'yellow':
|
|
27
|
+
case 'amber':
|
|
28
|
+
case 'orange':
|
|
29
|
+
case 'brown':
|
|
30
|
+
case 'gold':
|
|
31
|
+
case 'bronze':
|
|
32
|
+
return 'sand';
|
|
33
|
+
case 'gray':
|
|
34
|
+
default:
|
|
35
|
+
return 'gray';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export const LIGHT_SELECTOR = ':root, .light, .light-theme';
|
|
39
|
+
export const DARK_SELECTOR = '.dark, .dark-theme';
|
|
40
|
+
export const schemeSelector = (scheme) => scheme === 'light' ? LIGHT_SELECTOR : DARK_SELECTOR;
|
|
41
|
+
/** Convert "amber9" to "--amber-9" or "amberA9" to "--amber-a9" */
|
|
42
|
+
export const toVarName = (key) => `--${key.replace(/A?(\d+)/, (m, n) => (m.startsWith('A') ? `-a${n}` : `-${n}`))}`;
|
|
43
|
+
export const formatRule = (selector, vars) => `${selector} {\n ${vars.join(';\n ')};\n}`;
|
|
44
|
+
export const formatP3 = (selector, vars) => `@supports (color: color(display-p3 1 1 1)) {\n @media (color-gamut: p3) {\n ${selector} {\n ${vars.join(';\n ')};\n }\n }\n}`;
|
|
45
|
+
export const formatNestedBlock = (selector, vars) => `&:where(${selector}) {\n ${vars.join(';\n ')};\n }`;
|
package/package.json
CHANGED
package/dist/lib.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
export type AlphaConfig = {
|
|
2
|
-
srgb: Record<string, string>;
|
|
3
|
-
p3: Record<string, string>;
|
|
4
|
-
};
|
|
5
|
-
export type ColorConfig = {
|
|
6
|
-
srgb: {
|
|
7
|
-
light: Record<string, string> & {
|
|
8
|
-
surface: string;
|
|
9
|
-
};
|
|
10
|
-
dark: Record<string, string> & {
|
|
11
|
-
surface: string;
|
|
12
|
-
};
|
|
13
|
-
};
|
|
14
|
-
p3: {
|
|
15
|
-
light: Record<string, string> & {
|
|
16
|
-
surface: string;
|
|
17
|
-
};
|
|
18
|
-
dark: Record<string, string> & {
|
|
19
|
-
surface: string;
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
|
-
contrast: string;
|
|
23
|
-
indicator: string;
|
|
24
|
-
track: string;
|
|
25
|
-
};
|
|
26
|
-
export declare const css: {
|
|
27
|
-
scale(scheme: "light" | "lightAlpha" | "dark" | "darkAlpha", config: ColorConfig): string;
|
|
28
|
-
alpha(config: AlphaConfig): string;
|
|
29
|
-
semantic(name: string, config: ColorConfig): string;
|
|
30
|
-
};
|
package/dist/lib.js
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
const lightSelector = `:root, .light, .light-theme`;
|
|
2
|
-
const darkSelector = `.dark, .dark-theme`;
|
|
3
|
-
/** Convert color key to CSS variable name (e.g., "blue1" → "--blue-1", "blueA1" → "--blue-a1") */
|
|
4
|
-
const toVarName = (key) => '--' + key.replace(/A?(\d)/, (_, num) => (key.includes('A') ? `-a${num}` : `-${num}`));
|
|
5
|
-
export const css = {
|
|
6
|
-
scale(scheme, config) {
|
|
7
|
-
const isLight = scheme === 'light' || scheme === 'lightAlpha';
|
|
8
|
-
const isAlpha = scheme === 'lightAlpha' || scheme === 'darkAlpha';
|
|
9
|
-
const selector = isLight ? lightSelector : darkSelector;
|
|
10
|
-
const srgbScale = isLight ? config.srgb.light : config.srgb.dark;
|
|
11
|
-
const p3Scale = isLight ? config.p3.light : config.p3.dark;
|
|
12
|
-
const filterEntries = (obj) => Object.entries(obj).filter(([key]) => {
|
|
13
|
-
if (key === 'surface')
|
|
14
|
-
return false;
|
|
15
|
-
const hasAlpha = key.includes('A');
|
|
16
|
-
return isAlpha ? hasAlpha : !hasAlpha;
|
|
17
|
-
});
|
|
18
|
-
const baseVars = filterEntries(srgbScale)
|
|
19
|
-
.map(([key, value]) => ` ${toVarName(key)}: ${value};`)
|
|
20
|
-
.join('\n');
|
|
21
|
-
const p3Vars = filterEntries(p3Scale)
|
|
22
|
-
.map(([key, value]) => ` ${toVarName(key)}: ${value};`)
|
|
23
|
-
.join('\n');
|
|
24
|
-
return `${selector} {
|
|
25
|
-
${baseVars}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
@supports (color: color(display-p3 1 1 1)) {
|
|
29
|
-
@media (color-gamut: p3) {
|
|
30
|
-
${selector} {
|
|
31
|
-
${p3Vars}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
`;
|
|
36
|
-
},
|
|
37
|
-
alpha(config) {
|
|
38
|
-
const baseVars = Object.entries(config.srgb)
|
|
39
|
-
.map(([key, value]) => ` ${toVarName(key)}: ${value};`)
|
|
40
|
-
.join('\n');
|
|
41
|
-
const p3Vars = Object.entries(config.p3)
|
|
42
|
-
.map(([key, value]) => ` ${toVarName(key)}: ${value};`)
|
|
43
|
-
.join('\n');
|
|
44
|
-
return `:root {
|
|
45
|
-
${baseVars}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
@supports (color: color(display-p3 1 1 1)) {
|
|
49
|
-
@media (color-gamut: p3) {
|
|
50
|
-
:root {
|
|
51
|
-
${p3Vars}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
`;
|
|
56
|
-
},
|
|
57
|
-
semantic(name, config) {
|
|
58
|
-
const varRef = (key) => `var(${toVarName(key)})`;
|
|
59
|
-
return `:root {
|
|
60
|
-
--${name}-contrast: ${config.contrast};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
:root,
|
|
64
|
-
.light,
|
|
65
|
-
.light-theme {
|
|
66
|
-
--${name}-surface: ${config.srgb.light.surface};
|
|
67
|
-
--${name}-indicator: ${varRef(config.indicator)};
|
|
68
|
-
--${name}-track: ${varRef(config.track)};
|
|
69
|
-
@supports (color: color(display-p3 1 1 1)) {
|
|
70
|
-
@media (color-gamut: p3) {
|
|
71
|
-
--${name}-surface: ${config.p3.light.surface};
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
.dark,
|
|
77
|
-
.dark-theme {
|
|
78
|
-
--${name}-surface: ${config.srgb.dark.surface};
|
|
79
|
-
--${name}-indicator: ${varRef(config.indicator)};
|
|
80
|
-
--${name}-track: ${varRef(config.track)};
|
|
81
|
-
@supports (color: color(display-p3 1 1 1)) {
|
|
82
|
-
@media (color-gamut: p3) {
|
|
83
|
-
--${name}-surface: ${config.p3.dark.surface};
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
`;
|
|
88
|
-
},
|
|
89
|
-
};
|