@classic-homes/theme-tokens 0.1.51 → 0.1.53
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/contrast.d.mts +118 -0
- package/dist/contrast.d.ts +118 -0
- package/dist/contrast.js +117 -0
- package/dist/contrast.mjs +87 -0
- package/dist/index.d.mts +84 -5
- package/dist/index.d.ts +84 -5
- package/dist/index.js +34 -3
- package/dist/index.mjs +32 -3
- package/dist/tokens.css +1 -1
- package/package.json +8 -3
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Color Contrast Utilities
|
|
3
|
+
*
|
|
4
|
+
* Utilities for calculating and validating color contrast ratios
|
|
5
|
+
* for WCAG 2.1 compliance.
|
|
6
|
+
*
|
|
7
|
+
* @see https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html
|
|
8
|
+
* @see https://www.w3.org/WAI/WCAG21/Understanding/contrast-enhanced.html
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Calculates the relative luminance of a color.
|
|
12
|
+
*
|
|
13
|
+
* @param hex - Hex color string (e.g., '#ffffff' or '#fff')
|
|
14
|
+
* @returns Relative luminance value between 0 (black) and 1 (white)
|
|
15
|
+
*
|
|
16
|
+
* @see https://www.w3.org/WAI/GL/wiki/Relative_luminance
|
|
17
|
+
*/
|
|
18
|
+
declare function getLuminance(hex: string): number;
|
|
19
|
+
/**
|
|
20
|
+
* Calculates the contrast ratio between two colors.
|
|
21
|
+
*
|
|
22
|
+
* @param foreground - Foreground/text color as hex
|
|
23
|
+
* @param background - Background color as hex
|
|
24
|
+
* @returns Contrast ratio (1:1 to 21:1)
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* getContrastRatio('#000000', '#ffffff'); // 21
|
|
29
|
+
* getContrastRatio('#ffffff', '#ffffff'); // 1
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
declare function getContrastRatio(foreground: string, background: string): number;
|
|
33
|
+
/**
|
|
34
|
+
* WCAG conformance levels for contrast
|
|
35
|
+
*/
|
|
36
|
+
type WCAGLevel = 'AA' | 'AAA';
|
|
37
|
+
/**
|
|
38
|
+
* Text size categories for contrast requirements
|
|
39
|
+
*/
|
|
40
|
+
type TextSize = 'normal' | 'large';
|
|
41
|
+
/**
|
|
42
|
+
* Checks if a color combination meets WCAG contrast requirements.
|
|
43
|
+
*
|
|
44
|
+
* WCAG 2.1 contrast requirements:
|
|
45
|
+
* - Level AA: 4.5:1 for normal text, 3:1 for large text
|
|
46
|
+
* - Level AAA: 7:1 for normal text, 4.5:1 for large text
|
|
47
|
+
*
|
|
48
|
+
* Large text is defined as 18pt (24px) or 14pt (18.66px) bold and larger.
|
|
49
|
+
*
|
|
50
|
+
* @param foreground - Foreground/text color as hex
|
|
51
|
+
* @param background - Background color as hex
|
|
52
|
+
* @param level - WCAG conformance level ('AA' or 'AAA')
|
|
53
|
+
* @param size - Text size category ('normal' or 'large')
|
|
54
|
+
* @returns True if the contrast meets the requirement
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* meetsWCAGContrast('#000000', '#ffffff', 'AA', 'normal'); // true (21:1 >= 4.5:1)
|
|
59
|
+
* meetsWCAGContrast('#666666', '#ffffff', 'AAA', 'normal'); // false (5.74:1 < 7:1)
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
declare function meetsWCAGContrast(foreground: string, background: string, level?: WCAGLevel, size?: TextSize): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Result of contrast validation with details
|
|
65
|
+
*/
|
|
66
|
+
interface ContrastValidation {
|
|
67
|
+
/** Contrast ratio */
|
|
68
|
+
ratio: number;
|
|
69
|
+
/** Formatted ratio string (e.g., "4.5:1") */
|
|
70
|
+
ratioString: string;
|
|
71
|
+
/** Passes AA level for normal text */
|
|
72
|
+
passesAANormal: boolean;
|
|
73
|
+
/** Passes AA level for large text */
|
|
74
|
+
passesAALarge: boolean;
|
|
75
|
+
/** Passes AAA level for normal text */
|
|
76
|
+
passesAAANormal: boolean;
|
|
77
|
+
/** Passes AAA level for large text */
|
|
78
|
+
passesAAALarge: boolean;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Validates a color combination and returns detailed contrast information.
|
|
82
|
+
*
|
|
83
|
+
* @param foreground - Foreground/text color as hex
|
|
84
|
+
* @param background - Background color as hex
|
|
85
|
+
* @returns Detailed contrast validation results
|
|
86
|
+
*/
|
|
87
|
+
declare function validateContrast(foreground: string, background: string): ContrastValidation;
|
|
88
|
+
/**
|
|
89
|
+
* Gets an accessible text color (black or white) for a given background.
|
|
90
|
+
*
|
|
91
|
+
* Uses luminance threshold to determine which color provides better contrast.
|
|
92
|
+
*
|
|
93
|
+
* @param background - Background color as hex
|
|
94
|
+
* @returns '#000000' for light backgrounds, '#ffffff' for dark backgrounds
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* getContrastTextColor('#ffffff'); // '#000000'
|
|
99
|
+
* getContrastTextColor('#000000'); // '#ffffff'
|
|
100
|
+
* getContrastTextColor('#3ba4a7'); // '#ffffff' (teal background)
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
declare function getContrastTextColor(background: string): '#000000' | '#ffffff';
|
|
104
|
+
/**
|
|
105
|
+
* Suggests the minimum lightness adjustment needed to meet contrast requirements.
|
|
106
|
+
*
|
|
107
|
+
* @param foreground - Current foreground color as hex
|
|
108
|
+
* @param background - Background color as hex
|
|
109
|
+
* @param level - Target WCAG level
|
|
110
|
+
* @param size - Text size category
|
|
111
|
+
* @returns Suggested adjustment or null if already passing
|
|
112
|
+
*/
|
|
113
|
+
declare function suggestContrastAdjustment(foreground: string, background: string, level?: WCAGLevel, size?: TextSize): {
|
|
114
|
+
adjustLighter: boolean;
|
|
115
|
+
minimumRatio: number;
|
|
116
|
+
} | null;
|
|
117
|
+
|
|
118
|
+
export { type ContrastValidation, type TextSize, type WCAGLevel, getContrastRatio, getContrastTextColor, getLuminance, meetsWCAGContrast, suggestContrastAdjustment, validateContrast };
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Color Contrast Utilities
|
|
3
|
+
*
|
|
4
|
+
* Utilities for calculating and validating color contrast ratios
|
|
5
|
+
* for WCAG 2.1 compliance.
|
|
6
|
+
*
|
|
7
|
+
* @see https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html
|
|
8
|
+
* @see https://www.w3.org/WAI/WCAG21/Understanding/contrast-enhanced.html
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Calculates the relative luminance of a color.
|
|
12
|
+
*
|
|
13
|
+
* @param hex - Hex color string (e.g., '#ffffff' or '#fff')
|
|
14
|
+
* @returns Relative luminance value between 0 (black) and 1 (white)
|
|
15
|
+
*
|
|
16
|
+
* @see https://www.w3.org/WAI/GL/wiki/Relative_luminance
|
|
17
|
+
*/
|
|
18
|
+
declare function getLuminance(hex: string): number;
|
|
19
|
+
/**
|
|
20
|
+
* Calculates the contrast ratio between two colors.
|
|
21
|
+
*
|
|
22
|
+
* @param foreground - Foreground/text color as hex
|
|
23
|
+
* @param background - Background color as hex
|
|
24
|
+
* @returns Contrast ratio (1:1 to 21:1)
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* getContrastRatio('#000000', '#ffffff'); // 21
|
|
29
|
+
* getContrastRatio('#ffffff', '#ffffff'); // 1
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
declare function getContrastRatio(foreground: string, background: string): number;
|
|
33
|
+
/**
|
|
34
|
+
* WCAG conformance levels for contrast
|
|
35
|
+
*/
|
|
36
|
+
type WCAGLevel = 'AA' | 'AAA';
|
|
37
|
+
/**
|
|
38
|
+
* Text size categories for contrast requirements
|
|
39
|
+
*/
|
|
40
|
+
type TextSize = 'normal' | 'large';
|
|
41
|
+
/**
|
|
42
|
+
* Checks if a color combination meets WCAG contrast requirements.
|
|
43
|
+
*
|
|
44
|
+
* WCAG 2.1 contrast requirements:
|
|
45
|
+
* - Level AA: 4.5:1 for normal text, 3:1 for large text
|
|
46
|
+
* - Level AAA: 7:1 for normal text, 4.5:1 for large text
|
|
47
|
+
*
|
|
48
|
+
* Large text is defined as 18pt (24px) or 14pt (18.66px) bold and larger.
|
|
49
|
+
*
|
|
50
|
+
* @param foreground - Foreground/text color as hex
|
|
51
|
+
* @param background - Background color as hex
|
|
52
|
+
* @param level - WCAG conformance level ('AA' or 'AAA')
|
|
53
|
+
* @param size - Text size category ('normal' or 'large')
|
|
54
|
+
* @returns True if the contrast meets the requirement
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* meetsWCAGContrast('#000000', '#ffffff', 'AA', 'normal'); // true (21:1 >= 4.5:1)
|
|
59
|
+
* meetsWCAGContrast('#666666', '#ffffff', 'AAA', 'normal'); // false (5.74:1 < 7:1)
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
declare function meetsWCAGContrast(foreground: string, background: string, level?: WCAGLevel, size?: TextSize): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Result of contrast validation with details
|
|
65
|
+
*/
|
|
66
|
+
interface ContrastValidation {
|
|
67
|
+
/** Contrast ratio */
|
|
68
|
+
ratio: number;
|
|
69
|
+
/** Formatted ratio string (e.g., "4.5:1") */
|
|
70
|
+
ratioString: string;
|
|
71
|
+
/** Passes AA level for normal text */
|
|
72
|
+
passesAANormal: boolean;
|
|
73
|
+
/** Passes AA level for large text */
|
|
74
|
+
passesAALarge: boolean;
|
|
75
|
+
/** Passes AAA level for normal text */
|
|
76
|
+
passesAAANormal: boolean;
|
|
77
|
+
/** Passes AAA level for large text */
|
|
78
|
+
passesAAALarge: boolean;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Validates a color combination and returns detailed contrast information.
|
|
82
|
+
*
|
|
83
|
+
* @param foreground - Foreground/text color as hex
|
|
84
|
+
* @param background - Background color as hex
|
|
85
|
+
* @returns Detailed contrast validation results
|
|
86
|
+
*/
|
|
87
|
+
declare function validateContrast(foreground: string, background: string): ContrastValidation;
|
|
88
|
+
/**
|
|
89
|
+
* Gets an accessible text color (black or white) for a given background.
|
|
90
|
+
*
|
|
91
|
+
* Uses luminance threshold to determine which color provides better contrast.
|
|
92
|
+
*
|
|
93
|
+
* @param background - Background color as hex
|
|
94
|
+
* @returns '#000000' for light backgrounds, '#ffffff' for dark backgrounds
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* getContrastTextColor('#ffffff'); // '#000000'
|
|
99
|
+
* getContrastTextColor('#000000'); // '#ffffff'
|
|
100
|
+
* getContrastTextColor('#3ba4a7'); // '#ffffff' (teal background)
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
declare function getContrastTextColor(background: string): '#000000' | '#ffffff';
|
|
104
|
+
/**
|
|
105
|
+
* Suggests the minimum lightness adjustment needed to meet contrast requirements.
|
|
106
|
+
*
|
|
107
|
+
* @param foreground - Current foreground color as hex
|
|
108
|
+
* @param background - Background color as hex
|
|
109
|
+
* @param level - Target WCAG level
|
|
110
|
+
* @param size - Text size category
|
|
111
|
+
* @returns Suggested adjustment or null if already passing
|
|
112
|
+
*/
|
|
113
|
+
declare function suggestContrastAdjustment(foreground: string, background: string, level?: WCAGLevel, size?: TextSize): {
|
|
114
|
+
adjustLighter: boolean;
|
|
115
|
+
minimumRatio: number;
|
|
116
|
+
} | null;
|
|
117
|
+
|
|
118
|
+
export { type ContrastValidation, type TextSize, type WCAGLevel, getContrastRatio, getContrastTextColor, getLuminance, meetsWCAGContrast, suggestContrastAdjustment, validateContrast };
|
package/dist/contrast.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/contrast.ts
|
|
21
|
+
var contrast_exports = {};
|
|
22
|
+
__export(contrast_exports, {
|
|
23
|
+
getContrastRatio: () => getContrastRatio,
|
|
24
|
+
getContrastTextColor: () => getContrastTextColor,
|
|
25
|
+
getLuminance: () => getLuminance,
|
|
26
|
+
meetsWCAGContrast: () => meetsWCAGContrast,
|
|
27
|
+
suggestContrastAdjustment: () => suggestContrastAdjustment,
|
|
28
|
+
validateContrast: () => validateContrast
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(contrast_exports);
|
|
31
|
+
function hexToRgb(hex) {
|
|
32
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
33
|
+
if (result) {
|
|
34
|
+
return {
|
|
35
|
+
r: parseInt(result[1], 16),
|
|
36
|
+
g: parseInt(result[2], 16),
|
|
37
|
+
b: parseInt(result[3], 16)
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const shortResult = /^#?([a-f\d])([a-f\d])([a-f\d])$/i.exec(hex);
|
|
41
|
+
if (shortResult) {
|
|
42
|
+
return {
|
|
43
|
+
r: parseInt(shortResult[1] + shortResult[1], 16),
|
|
44
|
+
g: parseInt(shortResult[2] + shortResult[2], 16),
|
|
45
|
+
b: parseInt(shortResult[3] + shortResult[3], 16)
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
function getLuminance(hex) {
|
|
51
|
+
const rgb = hexToRgb(hex);
|
|
52
|
+
if (!rgb) {
|
|
53
|
+
throw new Error(`Invalid hex color: ${hex}`);
|
|
54
|
+
}
|
|
55
|
+
const { r, g, b } = rgb;
|
|
56
|
+
const rsrgb = r / 255;
|
|
57
|
+
const gsrgb = g / 255;
|
|
58
|
+
const bsrgb = b / 255;
|
|
59
|
+
const rLinear = rsrgb <= 0.03928 ? rsrgb / 12.92 : Math.pow((rsrgb + 0.055) / 1.055, 2.4);
|
|
60
|
+
const gLinear = gsrgb <= 0.03928 ? gsrgb / 12.92 : Math.pow((gsrgb + 0.055) / 1.055, 2.4);
|
|
61
|
+
const bLinear = bsrgb <= 0.03928 ? bsrgb / 12.92 : Math.pow((bsrgb + 0.055) / 1.055, 2.4);
|
|
62
|
+
return 0.2126 * rLinear + 0.7152 * gLinear + 0.0722 * bLinear;
|
|
63
|
+
}
|
|
64
|
+
function getContrastRatio(foreground, background) {
|
|
65
|
+
const l1 = getLuminance(foreground);
|
|
66
|
+
const l2 = getLuminance(background);
|
|
67
|
+
const lighter = Math.max(l1, l2);
|
|
68
|
+
const darker = Math.min(l1, l2);
|
|
69
|
+
return (lighter + 0.05) / (darker + 0.05);
|
|
70
|
+
}
|
|
71
|
+
function meetsWCAGContrast(foreground, background, level = "AA", size = "normal") {
|
|
72
|
+
const ratio = getContrastRatio(foreground, background);
|
|
73
|
+
const requirements = {
|
|
74
|
+
AA: { normal: 4.5, large: 3 },
|
|
75
|
+
AAA: { normal: 7, large: 4.5 }
|
|
76
|
+
};
|
|
77
|
+
return ratio >= requirements[level][size];
|
|
78
|
+
}
|
|
79
|
+
function validateContrast(foreground, background) {
|
|
80
|
+
const ratio = getContrastRatio(foreground, background);
|
|
81
|
+
return {
|
|
82
|
+
ratio,
|
|
83
|
+
ratioString: `${ratio.toFixed(2)}:1`,
|
|
84
|
+
passesAANormal: ratio >= 4.5,
|
|
85
|
+
passesAALarge: ratio >= 3,
|
|
86
|
+
passesAAANormal: ratio >= 7,
|
|
87
|
+
passesAAALarge: ratio >= 4.5
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function getContrastTextColor(background) {
|
|
91
|
+
const luminance = getLuminance(background);
|
|
92
|
+
return luminance > 0.179 ? "#000000" : "#ffffff";
|
|
93
|
+
}
|
|
94
|
+
function suggestContrastAdjustment(foreground, background, level = "AA", size = "normal") {
|
|
95
|
+
if (meetsWCAGContrast(foreground, background, level, size)) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
const requirements = {
|
|
99
|
+
AA: { normal: 4.5, large: 3 },
|
|
100
|
+
AAA: { normal: 7, large: 4.5 }
|
|
101
|
+
};
|
|
102
|
+
const fgLuminance = getLuminance(foreground);
|
|
103
|
+
const bgLuminance = getLuminance(background);
|
|
104
|
+
return {
|
|
105
|
+
adjustLighter: fgLuminance < bgLuminance,
|
|
106
|
+
minimumRatio: requirements[level][size]
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
110
|
+
0 && (module.exports = {
|
|
111
|
+
getContrastRatio,
|
|
112
|
+
getContrastTextColor,
|
|
113
|
+
getLuminance,
|
|
114
|
+
meetsWCAGContrast,
|
|
115
|
+
suggestContrastAdjustment,
|
|
116
|
+
validateContrast
|
|
117
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// src/contrast.ts
|
|
2
|
+
function hexToRgb(hex) {
|
|
3
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
4
|
+
if (result) {
|
|
5
|
+
return {
|
|
6
|
+
r: parseInt(result[1], 16),
|
|
7
|
+
g: parseInt(result[2], 16),
|
|
8
|
+
b: parseInt(result[3], 16)
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
const shortResult = /^#?([a-f\d])([a-f\d])([a-f\d])$/i.exec(hex);
|
|
12
|
+
if (shortResult) {
|
|
13
|
+
return {
|
|
14
|
+
r: parseInt(shortResult[1] + shortResult[1], 16),
|
|
15
|
+
g: parseInt(shortResult[2] + shortResult[2], 16),
|
|
16
|
+
b: parseInt(shortResult[3] + shortResult[3], 16)
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
function getLuminance(hex) {
|
|
22
|
+
const rgb = hexToRgb(hex);
|
|
23
|
+
if (!rgb) {
|
|
24
|
+
throw new Error(`Invalid hex color: ${hex}`);
|
|
25
|
+
}
|
|
26
|
+
const { r, g, b } = rgb;
|
|
27
|
+
const rsrgb = r / 255;
|
|
28
|
+
const gsrgb = g / 255;
|
|
29
|
+
const bsrgb = b / 255;
|
|
30
|
+
const rLinear = rsrgb <= 0.03928 ? rsrgb / 12.92 : Math.pow((rsrgb + 0.055) / 1.055, 2.4);
|
|
31
|
+
const gLinear = gsrgb <= 0.03928 ? gsrgb / 12.92 : Math.pow((gsrgb + 0.055) / 1.055, 2.4);
|
|
32
|
+
const bLinear = bsrgb <= 0.03928 ? bsrgb / 12.92 : Math.pow((bsrgb + 0.055) / 1.055, 2.4);
|
|
33
|
+
return 0.2126 * rLinear + 0.7152 * gLinear + 0.0722 * bLinear;
|
|
34
|
+
}
|
|
35
|
+
function getContrastRatio(foreground, background) {
|
|
36
|
+
const l1 = getLuminance(foreground);
|
|
37
|
+
const l2 = getLuminance(background);
|
|
38
|
+
const lighter = Math.max(l1, l2);
|
|
39
|
+
const darker = Math.min(l1, l2);
|
|
40
|
+
return (lighter + 0.05) / (darker + 0.05);
|
|
41
|
+
}
|
|
42
|
+
function meetsWCAGContrast(foreground, background, level = "AA", size = "normal") {
|
|
43
|
+
const ratio = getContrastRatio(foreground, background);
|
|
44
|
+
const requirements = {
|
|
45
|
+
AA: { normal: 4.5, large: 3 },
|
|
46
|
+
AAA: { normal: 7, large: 4.5 }
|
|
47
|
+
};
|
|
48
|
+
return ratio >= requirements[level][size];
|
|
49
|
+
}
|
|
50
|
+
function validateContrast(foreground, background) {
|
|
51
|
+
const ratio = getContrastRatio(foreground, background);
|
|
52
|
+
return {
|
|
53
|
+
ratio,
|
|
54
|
+
ratioString: `${ratio.toFixed(2)}:1`,
|
|
55
|
+
passesAANormal: ratio >= 4.5,
|
|
56
|
+
passesAALarge: ratio >= 3,
|
|
57
|
+
passesAAANormal: ratio >= 7,
|
|
58
|
+
passesAAALarge: ratio >= 4.5
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function getContrastTextColor(background) {
|
|
62
|
+
const luminance = getLuminance(background);
|
|
63
|
+
return luminance > 0.179 ? "#000000" : "#ffffff";
|
|
64
|
+
}
|
|
65
|
+
function suggestContrastAdjustment(foreground, background, level = "AA", size = "normal") {
|
|
66
|
+
if (meetsWCAGContrast(foreground, background, level, size)) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
const requirements = {
|
|
70
|
+
AA: { normal: 4.5, large: 3 },
|
|
71
|
+
AAA: { normal: 7, large: 4.5 }
|
|
72
|
+
};
|
|
73
|
+
const fgLuminance = getLuminance(foreground);
|
|
74
|
+
const bgLuminance = getLuminance(background);
|
|
75
|
+
return {
|
|
76
|
+
adjustLighter: fgLuminance < bgLuminance,
|
|
77
|
+
minimumRatio: requirements[level][size]
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export {
|
|
81
|
+
getContrastRatio,
|
|
82
|
+
getContrastTextColor,
|
|
83
|
+
getLuminance,
|
|
84
|
+
meetsWCAGContrast,
|
|
85
|
+
suggestContrastAdjustment,
|
|
86
|
+
validateContrast
|
|
87
|
+
};
|
package/dist/index.d.mts
CHANGED
|
@@ -218,7 +218,7 @@ declare const brandColors: {
|
|
|
218
218
|
*/
|
|
219
219
|
declare const statusColors: {
|
|
220
220
|
readonly success: "#10b981";
|
|
221
|
-
readonly warning: "#
|
|
221
|
+
readonly warning: "#d97706";
|
|
222
222
|
readonly error: "#ef4444";
|
|
223
223
|
readonly info: "#3b82f6";
|
|
224
224
|
};
|
|
@@ -263,7 +263,7 @@ declare const semanticColors: {
|
|
|
263
263
|
readonly ring: "#a91c22";
|
|
264
264
|
readonly success: "#10b981";
|
|
265
265
|
readonly successForeground: "#ffffff";
|
|
266
|
-
readonly warning: "#
|
|
266
|
+
readonly warning: "#d97706";
|
|
267
267
|
readonly warningForeground: "#ffffff";
|
|
268
268
|
readonly info: "#3b82f6";
|
|
269
269
|
readonly infoForeground: "#ffffff";
|
|
@@ -496,6 +496,60 @@ declare const transition: {
|
|
|
496
496
|
readonly linear: "linear";
|
|
497
497
|
};
|
|
498
498
|
};
|
|
499
|
+
/**
|
|
500
|
+
* Focus Ring Tokens
|
|
501
|
+
*
|
|
502
|
+
* Consistent focus indicator styling for accessibility.
|
|
503
|
+
* These values ensure visible focus states that meet WCAG 2.1 requirements.
|
|
504
|
+
*
|
|
505
|
+
* @see https://www.w3.org/WAI/WCAG21/Understanding/focus-visible.html
|
|
506
|
+
*/
|
|
507
|
+
declare const focusRing: {
|
|
508
|
+
/** Width of the focus ring outline */
|
|
509
|
+
readonly width: "2px";
|
|
510
|
+
/** Offset between the element and the focus ring */
|
|
511
|
+
readonly offset: "2px";
|
|
512
|
+
/** Outline style */
|
|
513
|
+
readonly style: "solid";
|
|
514
|
+
};
|
|
515
|
+
/**
|
|
516
|
+
* Animation Duration Tokens
|
|
517
|
+
*
|
|
518
|
+
* Includes reduced motion variants that should be used when
|
|
519
|
+
* the user has enabled `prefers-reduced-motion: reduce`.
|
|
520
|
+
*
|
|
521
|
+
* @see https://www.w3.org/WAI/WCAG21/Understanding/animation-from-interactions.html
|
|
522
|
+
*
|
|
523
|
+
* @example CSS usage with media query
|
|
524
|
+
* ```css
|
|
525
|
+
* .animated-element {
|
|
526
|
+
* transition-duration: var(--animation-duration-base);
|
|
527
|
+
* }
|
|
528
|
+
*
|
|
529
|
+
* @media (prefers-reduced-motion: reduce) {
|
|
530
|
+
* .animated-element {
|
|
531
|
+
* transition-duration: var(--animation-duration-reduced-base);
|
|
532
|
+
* }
|
|
533
|
+
* }
|
|
534
|
+
* ```
|
|
535
|
+
*/
|
|
536
|
+
declare const animation: {
|
|
537
|
+
/** Standard animation durations */
|
|
538
|
+
readonly duration: {
|
|
539
|
+
/** Fast animations like hover states */
|
|
540
|
+
readonly fast: "150ms";
|
|
541
|
+
/** Base duration for most UI animations */
|
|
542
|
+
readonly base: "200ms";
|
|
543
|
+
/** Slower animations for larger movements */
|
|
544
|
+
readonly slow: "300ms";
|
|
545
|
+
};
|
|
546
|
+
/** Reduced motion durations (instant or near-instant) */
|
|
547
|
+
readonly reducedMotion: {
|
|
548
|
+
readonly fast: "0ms";
|
|
549
|
+
readonly base: "0ms";
|
|
550
|
+
readonly slow: "0ms";
|
|
551
|
+
};
|
|
552
|
+
};
|
|
499
553
|
declare const tokens: {
|
|
500
554
|
readonly colors: {
|
|
501
555
|
readonly white: "#ffffff";
|
|
@@ -702,7 +756,7 @@ declare const tokens: {
|
|
|
702
756
|
};
|
|
703
757
|
readonly statusColors: {
|
|
704
758
|
readonly success: "#10b981";
|
|
705
|
-
readonly warning: "#
|
|
759
|
+
readonly warning: "#d97706";
|
|
706
760
|
readonly error: "#ef4444";
|
|
707
761
|
readonly info: "#3b82f6";
|
|
708
762
|
};
|
|
@@ -739,7 +793,7 @@ declare const tokens: {
|
|
|
739
793
|
readonly ring: "#a91c22";
|
|
740
794
|
readonly success: "#10b981";
|
|
741
795
|
readonly successForeground: "#ffffff";
|
|
742
|
-
readonly warning: "#
|
|
796
|
+
readonly warning: "#d97706";
|
|
743
797
|
readonly warningForeground: "#ffffff";
|
|
744
798
|
readonly info: "#3b82f6";
|
|
745
799
|
readonly infoForeground: "#ffffff";
|
|
@@ -964,6 +1018,31 @@ declare const tokens: {
|
|
|
964
1018
|
readonly linear: "linear";
|
|
965
1019
|
};
|
|
966
1020
|
};
|
|
1021
|
+
readonly focusRing: {
|
|
1022
|
+
/** Width of the focus ring outline */
|
|
1023
|
+
readonly width: "2px";
|
|
1024
|
+
/** Offset between the element and the focus ring */
|
|
1025
|
+
readonly offset: "2px";
|
|
1026
|
+
/** Outline style */
|
|
1027
|
+
readonly style: "solid";
|
|
1028
|
+
};
|
|
1029
|
+
readonly animation: {
|
|
1030
|
+
/** Standard animation durations */
|
|
1031
|
+
readonly duration: {
|
|
1032
|
+
/** Fast animations like hover states */
|
|
1033
|
+
readonly fast: "150ms";
|
|
1034
|
+
/** Base duration for most UI animations */
|
|
1035
|
+
readonly base: "200ms";
|
|
1036
|
+
/** Slower animations for larger movements */
|
|
1037
|
+
readonly slow: "300ms";
|
|
1038
|
+
};
|
|
1039
|
+
/** Reduced motion durations (instant or near-instant) */
|
|
1040
|
+
readonly reducedMotion: {
|
|
1041
|
+
readonly fast: "0ms";
|
|
1042
|
+
readonly base: "0ms";
|
|
1043
|
+
readonly slow: "0ms";
|
|
1044
|
+
};
|
|
1045
|
+
};
|
|
967
1046
|
};
|
|
968
1047
|
|
|
969
|
-
export { borderRadius, boxShadow, brandColors, breakpoints, colors, tokens as default, fontFamily, fontSize, fontWeight, layoutColors, semanticColors, spacing, statusColors, tokens, transition, zIndex };
|
|
1048
|
+
export { animation, borderRadius, boxShadow, brandColors, breakpoints, colors, tokens as default, focusRing, fontFamily, fontSize, fontWeight, layoutColors, semanticColors, spacing, statusColors, tokens, transition, zIndex };
|
package/dist/index.d.ts
CHANGED
|
@@ -218,7 +218,7 @@ declare const brandColors: {
|
|
|
218
218
|
*/
|
|
219
219
|
declare const statusColors: {
|
|
220
220
|
readonly success: "#10b981";
|
|
221
|
-
readonly warning: "#
|
|
221
|
+
readonly warning: "#d97706";
|
|
222
222
|
readonly error: "#ef4444";
|
|
223
223
|
readonly info: "#3b82f6";
|
|
224
224
|
};
|
|
@@ -263,7 +263,7 @@ declare const semanticColors: {
|
|
|
263
263
|
readonly ring: "#a91c22";
|
|
264
264
|
readonly success: "#10b981";
|
|
265
265
|
readonly successForeground: "#ffffff";
|
|
266
|
-
readonly warning: "#
|
|
266
|
+
readonly warning: "#d97706";
|
|
267
267
|
readonly warningForeground: "#ffffff";
|
|
268
268
|
readonly info: "#3b82f6";
|
|
269
269
|
readonly infoForeground: "#ffffff";
|
|
@@ -496,6 +496,60 @@ declare const transition: {
|
|
|
496
496
|
readonly linear: "linear";
|
|
497
497
|
};
|
|
498
498
|
};
|
|
499
|
+
/**
|
|
500
|
+
* Focus Ring Tokens
|
|
501
|
+
*
|
|
502
|
+
* Consistent focus indicator styling for accessibility.
|
|
503
|
+
* These values ensure visible focus states that meet WCAG 2.1 requirements.
|
|
504
|
+
*
|
|
505
|
+
* @see https://www.w3.org/WAI/WCAG21/Understanding/focus-visible.html
|
|
506
|
+
*/
|
|
507
|
+
declare const focusRing: {
|
|
508
|
+
/** Width of the focus ring outline */
|
|
509
|
+
readonly width: "2px";
|
|
510
|
+
/** Offset between the element and the focus ring */
|
|
511
|
+
readonly offset: "2px";
|
|
512
|
+
/** Outline style */
|
|
513
|
+
readonly style: "solid";
|
|
514
|
+
};
|
|
515
|
+
/**
|
|
516
|
+
* Animation Duration Tokens
|
|
517
|
+
*
|
|
518
|
+
* Includes reduced motion variants that should be used when
|
|
519
|
+
* the user has enabled `prefers-reduced-motion: reduce`.
|
|
520
|
+
*
|
|
521
|
+
* @see https://www.w3.org/WAI/WCAG21/Understanding/animation-from-interactions.html
|
|
522
|
+
*
|
|
523
|
+
* @example CSS usage with media query
|
|
524
|
+
* ```css
|
|
525
|
+
* .animated-element {
|
|
526
|
+
* transition-duration: var(--animation-duration-base);
|
|
527
|
+
* }
|
|
528
|
+
*
|
|
529
|
+
* @media (prefers-reduced-motion: reduce) {
|
|
530
|
+
* .animated-element {
|
|
531
|
+
* transition-duration: var(--animation-duration-reduced-base);
|
|
532
|
+
* }
|
|
533
|
+
* }
|
|
534
|
+
* ```
|
|
535
|
+
*/
|
|
536
|
+
declare const animation: {
|
|
537
|
+
/** Standard animation durations */
|
|
538
|
+
readonly duration: {
|
|
539
|
+
/** Fast animations like hover states */
|
|
540
|
+
readonly fast: "150ms";
|
|
541
|
+
/** Base duration for most UI animations */
|
|
542
|
+
readonly base: "200ms";
|
|
543
|
+
/** Slower animations for larger movements */
|
|
544
|
+
readonly slow: "300ms";
|
|
545
|
+
};
|
|
546
|
+
/** Reduced motion durations (instant or near-instant) */
|
|
547
|
+
readonly reducedMotion: {
|
|
548
|
+
readonly fast: "0ms";
|
|
549
|
+
readonly base: "0ms";
|
|
550
|
+
readonly slow: "0ms";
|
|
551
|
+
};
|
|
552
|
+
};
|
|
499
553
|
declare const tokens: {
|
|
500
554
|
readonly colors: {
|
|
501
555
|
readonly white: "#ffffff";
|
|
@@ -702,7 +756,7 @@ declare const tokens: {
|
|
|
702
756
|
};
|
|
703
757
|
readonly statusColors: {
|
|
704
758
|
readonly success: "#10b981";
|
|
705
|
-
readonly warning: "#
|
|
759
|
+
readonly warning: "#d97706";
|
|
706
760
|
readonly error: "#ef4444";
|
|
707
761
|
readonly info: "#3b82f6";
|
|
708
762
|
};
|
|
@@ -739,7 +793,7 @@ declare const tokens: {
|
|
|
739
793
|
readonly ring: "#a91c22";
|
|
740
794
|
readonly success: "#10b981";
|
|
741
795
|
readonly successForeground: "#ffffff";
|
|
742
|
-
readonly warning: "#
|
|
796
|
+
readonly warning: "#d97706";
|
|
743
797
|
readonly warningForeground: "#ffffff";
|
|
744
798
|
readonly info: "#3b82f6";
|
|
745
799
|
readonly infoForeground: "#ffffff";
|
|
@@ -964,6 +1018,31 @@ declare const tokens: {
|
|
|
964
1018
|
readonly linear: "linear";
|
|
965
1019
|
};
|
|
966
1020
|
};
|
|
1021
|
+
readonly focusRing: {
|
|
1022
|
+
/** Width of the focus ring outline */
|
|
1023
|
+
readonly width: "2px";
|
|
1024
|
+
/** Offset between the element and the focus ring */
|
|
1025
|
+
readonly offset: "2px";
|
|
1026
|
+
/** Outline style */
|
|
1027
|
+
readonly style: "solid";
|
|
1028
|
+
};
|
|
1029
|
+
readonly animation: {
|
|
1030
|
+
/** Standard animation durations */
|
|
1031
|
+
readonly duration: {
|
|
1032
|
+
/** Fast animations like hover states */
|
|
1033
|
+
readonly fast: "150ms";
|
|
1034
|
+
/** Base duration for most UI animations */
|
|
1035
|
+
readonly base: "200ms";
|
|
1036
|
+
/** Slower animations for larger movements */
|
|
1037
|
+
readonly slow: "300ms";
|
|
1038
|
+
};
|
|
1039
|
+
/** Reduced motion durations (instant or near-instant) */
|
|
1040
|
+
readonly reducedMotion: {
|
|
1041
|
+
readonly fast: "0ms";
|
|
1042
|
+
readonly base: "0ms";
|
|
1043
|
+
readonly slow: "0ms";
|
|
1044
|
+
};
|
|
1045
|
+
};
|
|
967
1046
|
};
|
|
968
1047
|
|
|
969
|
-
export { borderRadius, boxShadow, brandColors, breakpoints, colors, tokens as default, fontFamily, fontSize, fontWeight, layoutColors, semanticColors, spacing, statusColors, tokens, transition, zIndex };
|
|
1048
|
+
export { animation, borderRadius, boxShadow, brandColors, breakpoints, colors, tokens as default, focusRing, fontFamily, fontSize, fontWeight, layoutColors, semanticColors, spacing, statusColors, tokens, transition, zIndex };
|
package/dist/index.js
CHANGED
|
@@ -20,12 +20,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
animation: () => animation,
|
|
23
24
|
borderRadius: () => borderRadius,
|
|
24
25
|
boxShadow: () => boxShadow,
|
|
25
26
|
brandColors: () => brandColors,
|
|
26
27
|
breakpoints: () => breakpoints,
|
|
27
28
|
colors: () => colors,
|
|
28
29
|
default: () => index_default,
|
|
30
|
+
focusRing: () => focusRing,
|
|
29
31
|
fontFamily: () => fontFamily,
|
|
30
32
|
fontSize: () => fontSize,
|
|
31
33
|
fontWeight: () => fontWeight,
|
|
@@ -296,8 +298,8 @@ var brandColors = {
|
|
|
296
298
|
var statusColors = {
|
|
297
299
|
success: "#10b981",
|
|
298
300
|
// Green - positive actions
|
|
299
|
-
warning: "#
|
|
300
|
-
// Amber - warnings/cautions
|
|
301
|
+
warning: "#d97706",
|
|
302
|
+
// Amber - warnings/cautions (4.5:1 contrast ratio for WCAG AA)
|
|
301
303
|
error: "#ef4444",
|
|
302
304
|
// Red - errors/destructive
|
|
303
305
|
info: "#3b82f6"
|
|
@@ -666,6 +668,31 @@ var transition = {
|
|
|
666
668
|
linear: "linear"
|
|
667
669
|
}
|
|
668
670
|
};
|
|
671
|
+
var focusRing = {
|
|
672
|
+
/** Width of the focus ring outline */
|
|
673
|
+
width: "2px",
|
|
674
|
+
/** Offset between the element and the focus ring */
|
|
675
|
+
offset: "2px",
|
|
676
|
+
/** Outline style */
|
|
677
|
+
style: "solid"
|
|
678
|
+
};
|
|
679
|
+
var animation = {
|
|
680
|
+
/** Standard animation durations */
|
|
681
|
+
duration: {
|
|
682
|
+
/** Fast animations like hover states */
|
|
683
|
+
fast: "150ms",
|
|
684
|
+
/** Base duration for most UI animations */
|
|
685
|
+
base: "200ms",
|
|
686
|
+
/** Slower animations for larger movements */
|
|
687
|
+
slow: "300ms"
|
|
688
|
+
},
|
|
689
|
+
/** Reduced motion durations (instant or near-instant) */
|
|
690
|
+
reducedMotion: {
|
|
691
|
+
fast: "0ms",
|
|
692
|
+
base: "0ms",
|
|
693
|
+
slow: "0ms"
|
|
694
|
+
}
|
|
695
|
+
};
|
|
669
696
|
var tokens = {
|
|
670
697
|
colors,
|
|
671
698
|
brandColors,
|
|
@@ -680,16 +707,20 @@ var tokens = {
|
|
|
680
707
|
boxShadow,
|
|
681
708
|
zIndex,
|
|
682
709
|
breakpoints,
|
|
683
|
-
transition
|
|
710
|
+
transition,
|
|
711
|
+
focusRing,
|
|
712
|
+
animation
|
|
684
713
|
};
|
|
685
714
|
var index_default = tokens;
|
|
686
715
|
// Annotate the CommonJS export names for ESM import in node:
|
|
687
716
|
0 && (module.exports = {
|
|
717
|
+
animation,
|
|
688
718
|
borderRadius,
|
|
689
719
|
boxShadow,
|
|
690
720
|
brandColors,
|
|
691
721
|
breakpoints,
|
|
692
722
|
colors,
|
|
723
|
+
focusRing,
|
|
693
724
|
fontFamily,
|
|
694
725
|
fontSize,
|
|
695
726
|
fontWeight,
|
package/dist/index.mjs
CHANGED
|
@@ -257,8 +257,8 @@ var brandColors = {
|
|
|
257
257
|
var statusColors = {
|
|
258
258
|
success: "#10b981",
|
|
259
259
|
// Green - positive actions
|
|
260
|
-
warning: "#
|
|
261
|
-
// Amber - warnings/cautions
|
|
260
|
+
warning: "#d97706",
|
|
261
|
+
// Amber - warnings/cautions (4.5:1 contrast ratio for WCAG AA)
|
|
262
262
|
error: "#ef4444",
|
|
263
263
|
// Red - errors/destructive
|
|
264
264
|
info: "#3b82f6"
|
|
@@ -627,6 +627,31 @@ var transition = {
|
|
|
627
627
|
linear: "linear"
|
|
628
628
|
}
|
|
629
629
|
};
|
|
630
|
+
var focusRing = {
|
|
631
|
+
/** Width of the focus ring outline */
|
|
632
|
+
width: "2px",
|
|
633
|
+
/** Offset between the element and the focus ring */
|
|
634
|
+
offset: "2px",
|
|
635
|
+
/** Outline style */
|
|
636
|
+
style: "solid"
|
|
637
|
+
};
|
|
638
|
+
var animation = {
|
|
639
|
+
/** Standard animation durations */
|
|
640
|
+
duration: {
|
|
641
|
+
/** Fast animations like hover states */
|
|
642
|
+
fast: "150ms",
|
|
643
|
+
/** Base duration for most UI animations */
|
|
644
|
+
base: "200ms",
|
|
645
|
+
/** Slower animations for larger movements */
|
|
646
|
+
slow: "300ms"
|
|
647
|
+
},
|
|
648
|
+
/** Reduced motion durations (instant or near-instant) */
|
|
649
|
+
reducedMotion: {
|
|
650
|
+
fast: "0ms",
|
|
651
|
+
base: "0ms",
|
|
652
|
+
slow: "0ms"
|
|
653
|
+
}
|
|
654
|
+
};
|
|
630
655
|
var tokens = {
|
|
631
656
|
colors,
|
|
632
657
|
brandColors,
|
|
@@ -641,16 +666,20 @@ var tokens = {
|
|
|
641
666
|
boxShadow,
|
|
642
667
|
zIndex,
|
|
643
668
|
breakpoints,
|
|
644
|
-
transition
|
|
669
|
+
transition,
|
|
670
|
+
focusRing,
|
|
671
|
+
animation
|
|
645
672
|
};
|
|
646
673
|
var index_default = tokens;
|
|
647
674
|
export {
|
|
675
|
+
animation,
|
|
648
676
|
borderRadius,
|
|
649
677
|
boxShadow,
|
|
650
678
|
brandColors,
|
|
651
679
|
breakpoints,
|
|
652
680
|
colors,
|
|
653
681
|
index_default as default,
|
|
682
|
+
focusRing,
|
|
654
683
|
fontFamily,
|
|
655
684
|
fontSize,
|
|
656
685
|
fontWeight,
|
package/dist/tokens.css
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classic-homes/theme-tokens",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.53",
|
|
4
4
|
"description": "Design tokens for the Classic theme system",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
"import": "./dist/index.mjs",
|
|
12
12
|
"require": "./dist/index.js"
|
|
13
13
|
},
|
|
14
|
+
"./contrast": {
|
|
15
|
+
"types": "./dist/contrast.d.ts",
|
|
16
|
+
"import": "./dist/contrast.mjs",
|
|
17
|
+
"require": "./dist/contrast.js"
|
|
18
|
+
},
|
|
14
19
|
"./css": "./dist/tokens.css"
|
|
15
20
|
},
|
|
16
21
|
"sideEffects": [
|
|
@@ -20,8 +25,8 @@
|
|
|
20
25
|
"dist"
|
|
21
26
|
],
|
|
22
27
|
"scripts": {
|
|
23
|
-
"build": "tsup src/index.ts --format esm,cjs --dts && node scripts/generate-css.js",
|
|
24
|
-
"dev": "tsup src/index.ts --format esm,cjs --dts --watch",
|
|
28
|
+
"build": "tsup src/index.ts src/contrast.ts --format esm,cjs --dts && node scripts/generate-css.js",
|
|
29
|
+
"dev": "tsup src/index.ts src/contrast.ts --format esm,cjs --dts --watch",
|
|
25
30
|
"clean": "rm -rf dist"
|
|
26
31
|
},
|
|
27
32
|
"keywords": [
|