@opencode/theme 0.0.0-dev-19795 → 0.0.0-dev-19812
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/tui/categorical.d.ts +1 -0
- package/dist/tui/categorical.js +1 -0
- package/dist/tui/expand.js +7 -7
- package/dist/tui/index.d.ts +2 -2
- package/dist/tui/index.js +2 -2
- package/dist/tui/resolve.js +11 -21
- package/dist/tui/schema.d.ts +1034 -2485
- package/dist/tui/schema.js +82 -42
- package/dist/tui/select.d.ts +3 -8
- package/dist/tui/select.js +2 -20
- package/dist/tui/syntax.js +17 -17
- package/dist/tui/types.d.ts +9 -15
- package/dist/tui/v1-migrate.js +67 -41
- package/package.json +1 -1
- package/dist/tui/defaults.d.ts +0 -546
- package/dist/tui/defaults.js +0 -441
- package/dist/tui/fallback.d.ts +0 -2
- package/dist/tui/fallback.js +0 -56
package/dist/tui/schema.js
CHANGED
|
@@ -32,21 +32,8 @@ const HueDefinition = Schema.Struct({
|
|
|
32
32
|
interactive: HueValueDefinition,
|
|
33
33
|
neutral: HueValueDefinition,
|
|
34
34
|
});
|
|
35
|
-
const HueOverrideDefinition = Schema.Struct({
|
|
36
|
-
gray: Schema.optional(HueValueDefinition),
|
|
37
|
-
red: Schema.optional(HueValueDefinition),
|
|
38
|
-
orange: Schema.optional(HueValueDefinition),
|
|
39
|
-
yellow: Schema.optional(HueValueDefinition),
|
|
40
|
-
green: Schema.optional(HueValueDefinition),
|
|
41
|
-
cyan: Schema.optional(HueValueDefinition),
|
|
42
|
-
blue: Schema.optional(HueValueDefinition),
|
|
43
|
-
purple: Schema.optional(HueValueDefinition),
|
|
44
|
-
accent: Schema.optional(HueValueDefinition),
|
|
45
|
-
interactive: Schema.optional(HueValueDefinition),
|
|
46
|
-
neutral: Schema.optional(HueValueDefinition),
|
|
47
|
-
});
|
|
48
35
|
const StatefulColorDefinition = Schema.Struct({
|
|
49
|
-
|
|
36
|
+
base: Schema.optional(ColorValue),
|
|
50
37
|
$hovered: Schema.optional(ColorValue),
|
|
51
38
|
$focused: Schema.optional(ColorValue),
|
|
52
39
|
$pressed: Schema.optional(ColorValue),
|
|
@@ -59,23 +46,17 @@ const ActionColorDefinition = Schema.Struct({
|
|
|
59
46
|
destructive: Schema.optional(StatefulColorDefinition),
|
|
60
47
|
});
|
|
61
48
|
const TextFeedbackDefinition = Schema.Struct({
|
|
62
|
-
|
|
63
|
-
|
|
49
|
+
base: Schema.optional(ColorValue),
|
|
50
|
+
muted: Schema.optional(ColorValue),
|
|
64
51
|
});
|
|
65
52
|
const BackgroundFeedbackDefinition = Schema.Struct({
|
|
66
|
-
|
|
53
|
+
base: Schema.optional(ColorValue),
|
|
67
54
|
});
|
|
68
55
|
const TextDefinition = Schema.Struct({
|
|
69
|
-
|
|
70
|
-
|
|
56
|
+
base: Schema.optional(ColorValue),
|
|
57
|
+
muted: Schema.optional(ColorValue),
|
|
71
58
|
action: Schema.optional(ActionColorDefinition),
|
|
72
59
|
formfield: Schema.optional(StatefulColorDefinition),
|
|
73
|
-
status: Schema.optional(Schema.Struct({
|
|
74
|
-
running: Schema.optional(ColorValue),
|
|
75
|
-
question: Schema.optional(ColorValue),
|
|
76
|
-
permission: Schema.optional(ColorValue),
|
|
77
|
-
unread: Schema.optional(ColorValue),
|
|
78
|
-
})),
|
|
79
60
|
feedback: Schema.optional(Schema.Struct({
|
|
80
61
|
error: Schema.optional(TextFeedbackDefinition),
|
|
81
62
|
warning: Schema.optional(TextFeedbackDefinition),
|
|
@@ -84,7 +65,7 @@ const TextDefinition = Schema.Struct({
|
|
|
84
65
|
})),
|
|
85
66
|
});
|
|
86
67
|
const BackgroundDefinition = Schema.Struct({
|
|
87
|
-
|
|
68
|
+
base: Schema.optional(ColorValue),
|
|
88
69
|
raised: Schema.optional(Schema.Struct({
|
|
89
70
|
base: Schema.optional(ColorValue),
|
|
90
71
|
high: Schema.optional(ColorValue),
|
|
@@ -149,39 +130,98 @@ const DiffDefinition = Schema.Struct({
|
|
|
149
130
|
const ThemeTokensDefinition = Schema.Struct({
|
|
150
131
|
text: Schema.optional(TextDefinition),
|
|
151
132
|
background: Schema.optional(BackgroundDefinition),
|
|
152
|
-
border: Schema.optional(Schema.Struct({
|
|
153
|
-
scrollbar: Schema.optional(Schema.Struct({
|
|
133
|
+
border: Schema.optional(Schema.Struct({ base: Schema.optional(ColorValue) })),
|
|
134
|
+
scrollbar: Schema.optional(Schema.Struct({ base: Schema.optional(ColorValue) })),
|
|
154
135
|
diff: Schema.optional(DiffDefinition),
|
|
155
136
|
syntax: Schema.optional(SyntaxDefinition),
|
|
156
137
|
markdown: Schema.optional(MarkdownDefinition),
|
|
157
138
|
});
|
|
139
|
+
const CompleteStatefulColorDefinition = Schema.Struct({
|
|
140
|
+
base: ColorValue,
|
|
141
|
+
$hovered: Schema.optional(ColorValue),
|
|
142
|
+
$focused: Schema.optional(ColorValue),
|
|
143
|
+
$pressed: Schema.optional(ColorValue),
|
|
144
|
+
$selected: Schema.optional(ColorValue),
|
|
145
|
+
$disabled: Schema.optional(ColorValue),
|
|
146
|
+
});
|
|
147
|
+
const CompleteActionColorDefinition = Schema.Struct({
|
|
148
|
+
primary: CompleteStatefulColorDefinition,
|
|
149
|
+
secondary: CompleteStatefulColorDefinition,
|
|
150
|
+
destructive: CompleteStatefulColorDefinition,
|
|
151
|
+
});
|
|
152
|
+
const CompleteTextFeedbackDefinition = Schema.Struct({ base: ColorValue, muted: Schema.optional(ColorValue) });
|
|
153
|
+
const CompleteBackgroundFeedbackDefinition = Schema.Struct({ base: ColorValue });
|
|
154
|
+
const CompleteThemeTokensDefinition = Schema.Struct({
|
|
155
|
+
text: Schema.Struct({
|
|
156
|
+
base: ColorValue,
|
|
157
|
+
muted: ColorValue,
|
|
158
|
+
action: CompleteActionColorDefinition,
|
|
159
|
+
formfield: CompleteStatefulColorDefinition,
|
|
160
|
+
feedback: Schema.Struct({
|
|
161
|
+
error: CompleteTextFeedbackDefinition,
|
|
162
|
+
warning: CompleteTextFeedbackDefinition,
|
|
163
|
+
success: CompleteTextFeedbackDefinition,
|
|
164
|
+
info: CompleteTextFeedbackDefinition,
|
|
165
|
+
}),
|
|
166
|
+
}),
|
|
167
|
+
background: Schema.Struct({
|
|
168
|
+
base: ColorValue,
|
|
169
|
+
raised: Schema.Struct({ base: ColorValue, high: ColorValue, max: ColorValue }),
|
|
170
|
+
action: CompleteActionColorDefinition,
|
|
171
|
+
formfield: CompleteStatefulColorDefinition,
|
|
172
|
+
feedback: Schema.Struct({
|
|
173
|
+
error: CompleteBackgroundFeedbackDefinition,
|
|
174
|
+
warning: CompleteBackgroundFeedbackDefinition,
|
|
175
|
+
success: CompleteBackgroundFeedbackDefinition,
|
|
176
|
+
info: CompleteBackgroundFeedbackDefinition,
|
|
177
|
+
}),
|
|
178
|
+
}),
|
|
179
|
+
border: Schema.Struct({ base: ColorValue }),
|
|
180
|
+
scrollbar: Schema.Struct({ base: ColorValue }),
|
|
181
|
+
diff: Schema.Struct({
|
|
182
|
+
text: Schema.Struct({ added: ColorValue, removed: ColorValue, context: ColorValue, hunkHeader: ColorValue }),
|
|
183
|
+
background: Schema.Struct({ added: ColorValue, removed: ColorValue, context: ColorValue }),
|
|
184
|
+
highlight: Schema.Struct({ added: ColorValue, removed: ColorValue }),
|
|
185
|
+
lineNumber: Schema.Struct({
|
|
186
|
+
text: ColorValue,
|
|
187
|
+
background: Schema.Struct({ added: ColorValue, removed: ColorValue }),
|
|
188
|
+
}),
|
|
189
|
+
}),
|
|
190
|
+
syntax: Schema.Record(SyntaxToken, HueColorValue),
|
|
191
|
+
markdown: Schema.Record(MarkdownToken, HueColorValue),
|
|
192
|
+
});
|
|
158
193
|
const ThemeDefinitionFields = Schema.Struct({
|
|
159
194
|
hue: HueDefinition,
|
|
160
|
-
categorical:
|
|
161
|
-
...
|
|
195
|
+
categorical: CategoricalDefinition,
|
|
196
|
+
...CompleteThemeTokensDefinition.fields,
|
|
162
197
|
"@dialog": Schema.optional(ThemeTokensDefinition),
|
|
163
198
|
});
|
|
164
199
|
export const ThemeDefinition = ThemeDefinitionFields;
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
...ThemeTokensDefinition.fields,
|
|
200
|
+
export const BaseThemeDefinition = Schema.Struct({
|
|
201
|
+
categorical: CategoricalDefinition,
|
|
202
|
+
...CompleteThemeTokensDefinition.fields,
|
|
169
203
|
"@dialog": Schema.optional(ThemeTokensDefinition),
|
|
170
204
|
});
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
hue: Schema.optional(HueOverrideDefinition),
|
|
205
|
+
export const ModeDefinition = Schema.Struct({
|
|
206
|
+
hue: HueDefinition,
|
|
174
207
|
categorical: Schema.optional(CategoricalDefinition),
|
|
175
208
|
...ThemeTokensDefinition.fields,
|
|
176
209
|
"@dialog": Schema.optional(ThemeTokensDefinition),
|
|
177
210
|
});
|
|
178
|
-
export const ModeDefinition = Schema.Union([MergeModeDefinition, FileThemeDefinition]);
|
|
179
211
|
const FileMetadata = {
|
|
180
212
|
$schema: Schema.optional(Schema.String),
|
|
181
|
-
version: Schema.Literal(2),
|
|
182
|
-
standalone: Schema.optional(Schema.Boolean),
|
|
183
213
|
};
|
|
184
214
|
export const ThemeDocument = Schema.Union([
|
|
185
|
-
Schema.Struct({
|
|
186
|
-
|
|
215
|
+
Schema.Struct({
|
|
216
|
+
...FileMetadata,
|
|
217
|
+
base: BaseThemeDefinition,
|
|
218
|
+
light: ModeDefinition,
|
|
219
|
+
dark: Schema.optional(ModeDefinition),
|
|
220
|
+
}),
|
|
221
|
+
Schema.Struct({
|
|
222
|
+
...FileMetadata,
|
|
223
|
+
base: BaseThemeDefinition,
|
|
224
|
+
light: Schema.optional(ModeDefinition),
|
|
225
|
+
dark: ModeDefinition,
|
|
226
|
+
}),
|
|
187
227
|
]);
|
package/dist/tui/select.d.ts
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function selectTheme(document: ThemeDocument
|
|
3
|
-
light: ThemeDefinition;
|
|
4
|
-
dark: ThemeDefinition;
|
|
5
|
-
}, mode?: Mode): ThemeDefinition;
|
|
6
|
-
export declare function selectTheme(document: ThemeDocument, mode?: Mode): FileThemeDefinition;
|
|
1
|
+
import type { Mode, ThemeDefinition, ThemeDocument } from "./index.js";
|
|
2
|
+
export declare function selectTheme(document: ThemeDocument, mode?: Mode): ThemeDefinition;
|
|
7
3
|
export declare function selectThemeMode(document: ThemeDocument, mode?: Mode): {
|
|
8
|
-
theme:
|
|
4
|
+
theme: ThemeDefinition;
|
|
9
5
|
mode: Mode;
|
|
10
|
-
expanded: boolean;
|
|
11
6
|
};
|
|
12
7
|
export declare function themeModes(document: ThemeDocument): readonly Mode[];
|
|
13
8
|
export declare function supportsThemeMode(document: ThemeDocument, mode: Mode): boolean;
|
package/dist/tui/select.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mergeTheme } from "./expand.js";
|
|
2
2
|
export function selectTheme(document, mode) {
|
|
3
3
|
return selectThemeMode(document, mode).theme;
|
|
4
4
|
}
|
|
@@ -8,29 +8,11 @@ export function selectThemeMode(document, mode = "light") {
|
|
|
8
8
|
const selected = document[selectedMode];
|
|
9
9
|
if (!selected)
|
|
10
10
|
throw new Error("Theme must provide at least one mode");
|
|
11
|
-
|
|
12
|
-
throw new Error("Light and dark themes cannot both merge modes");
|
|
13
|
-
if (!merges(selected))
|
|
14
|
-
return { theme: selected, mode: selectedMode, expanded: false };
|
|
15
|
-
const otherMode = selectedMode === "light" ? "dark" : "light";
|
|
16
|
-
const other = document[otherMode];
|
|
17
|
-
if (!other)
|
|
18
|
-
throw new Error(`The ${selectedMode} theme cannot merge without a ${otherMode} theme`);
|
|
19
|
-
const merged = mergeTheme(expandTheme(other), expandTheme(selected));
|
|
20
|
-
if (!merged["hue"])
|
|
21
|
-
throw new Error(`The ${otherMode} theme must provide hues when ${selectedMode} merges modes`);
|
|
22
|
-
return { theme: merged, mode: selectedMode, expanded: true };
|
|
11
|
+
return { theme: mergeTheme(document.base, selected), mode: selectedMode };
|
|
23
12
|
}
|
|
24
13
|
export function themeModes(document) {
|
|
25
|
-
if (merges(document.light) && !document.dark)
|
|
26
|
-
throw new Error("The light theme cannot merge without a dark theme");
|
|
27
|
-
if (merges(document.dark) && !document.light)
|
|
28
|
-
throw new Error("The dark theme cannot merge without a light theme");
|
|
29
14
|
return ["light", "dark"].filter((mode) => document[mode] !== undefined);
|
|
30
15
|
}
|
|
31
16
|
export function supportsThemeMode(document, mode) {
|
|
32
17
|
return themeModes(document).includes(mode);
|
|
33
18
|
}
|
|
34
|
-
function merges(definition) {
|
|
35
|
-
return definition !== undefined && "mergeMode" in definition && definition.mergeMode === true;
|
|
36
|
-
}
|
package/dist/tui/syntax.js
CHANGED
|
@@ -5,14 +5,14 @@ export function generateSyntax(theme) {
|
|
|
5
5
|
const markdown = theme.markdown;
|
|
6
6
|
const feedback = theme.text.feedback;
|
|
7
7
|
return SyntaxStyle.fromTheme([
|
|
8
|
-
rule(["default"], theme.text.
|
|
8
|
+
rule(["default"], theme.text.base),
|
|
9
9
|
rule(["prompt"], theme.hue.accent[step]),
|
|
10
|
-
rule(["extmark.file"], feedback.warning.
|
|
10
|
+
rule(["extmark.file"], feedback.warning.base, { bold: true }),
|
|
11
11
|
rule(["extmark.agent"], theme.categorical[0][step], { bold: true }),
|
|
12
12
|
rule(["extmark.skill"], (theme.categorical[1] ?? theme.categorical[0])[step], { bold: true }),
|
|
13
13
|
// V1 migration preserves its selected/inverse foreground in this action state.
|
|
14
14
|
rule(["extmark.paste"], theme.text.action.primary.focused, {
|
|
15
|
-
background: feedback.warning.
|
|
15
|
+
background: feedback.warning.base,
|
|
16
16
|
bold: true,
|
|
17
17
|
}),
|
|
18
18
|
rule(["comment", "comment.documentation"], syntax.comment, { italic: true }),
|
|
@@ -31,7 +31,7 @@ export function generateSyntax(theme) {
|
|
|
31
31
|
rule(["type", "module", "class", "namespace"], syntax.type),
|
|
32
32
|
rule(["type.definition"], syntax.type, { bold: true }),
|
|
33
33
|
rule(["punctuation", "punctuation.bracket"], syntax.punctuation),
|
|
34
|
-
rule(["variable.builtin", "type.builtin", "function.builtin", "module.builtin", "constant.builtin", "variable.super"], feedback.error.
|
|
34
|
+
rule(["variable.builtin", "type.builtin", "function.builtin", "module.builtin", "constant.builtin", "variable.super"], feedback.error.base),
|
|
35
35
|
rule(["keyword.directive", "keyword.modifier", "keyword.exception"], syntax.keyword, { italic: true }),
|
|
36
36
|
rule(["punctuation.special", "tag.delimiter"], syntax.operator),
|
|
37
37
|
rule([
|
|
@@ -48,27 +48,27 @@ export function generateSyntax(theme) {
|
|
|
48
48
|
rule(["markup.list"], markdown.listItem),
|
|
49
49
|
rule(["markup.quote"], markdown.blockQuote, { italic: true }),
|
|
50
50
|
rule(["markup.raw", "markup.raw.block"], markdown.code),
|
|
51
|
-
rule(["markup.raw.inline"], markdown.code, { background: theme.background.
|
|
51
|
+
rule(["markup.raw.inline"], markdown.code, { background: theme.background.base }),
|
|
52
52
|
rule(["markup.link", "markup.link.url", "string.special", "string.special.url"], markdown.link, {
|
|
53
53
|
underline: true,
|
|
54
54
|
}),
|
|
55
55
|
rule(["markup.link.label"], markdown.linkText, { underline: true }),
|
|
56
56
|
rule(["label"], markdown.linkText),
|
|
57
|
-
rule(["spell", "nospell"], theme.text.
|
|
58
|
-
rule(["markup.underline"], theme.text.
|
|
59
|
-
rule(["comment.error"], feedback.error.
|
|
60
|
-
rule(["comment.warning"], feedback.warning.
|
|
61
|
-
rule(["comment.todo", "comment.note"], feedback.info.
|
|
62
|
-
rule(["attribute", "annotation"], feedback.warning.
|
|
63
|
-
rule(["tag"], feedback.error.
|
|
64
|
-
rule(["markup.strikethrough", "markup.list.unchecked", "debug"], theme.text.
|
|
65
|
-
rule(["markup.list.checked"], feedback.success.
|
|
57
|
+
rule(["spell", "nospell"], theme.text.base),
|
|
58
|
+
rule(["markup.underline"], theme.text.base, { underline: true }),
|
|
59
|
+
rule(["comment.error"], feedback.error.base, { italic: true, bold: true }),
|
|
60
|
+
rule(["comment.warning"], feedback.warning.base, { italic: true, bold: true }),
|
|
61
|
+
rule(["comment.todo", "comment.note"], feedback.info.base, { italic: true, bold: true }),
|
|
62
|
+
rule(["attribute", "annotation"], feedback.warning.base),
|
|
63
|
+
rule(["tag"], feedback.error.base),
|
|
64
|
+
rule(["markup.strikethrough", "markup.list.unchecked", "debug"], theme.text.muted),
|
|
65
|
+
rule(["markup.list.checked"], feedback.success.base),
|
|
66
66
|
rule(["diff.plus"], theme.diff.text.added, { background: theme.diff.background.added }),
|
|
67
67
|
rule(["diff.minus"], theme.diff.text.removed, { background: theme.diff.background.removed }),
|
|
68
68
|
rule(["diff.delta"], theme.diff.text.context, { background: theme.diff.background.context }),
|
|
69
|
-
rule(["error"], feedback.error.
|
|
70
|
-
rule(["warning"], feedback.warning.
|
|
71
|
-
rule(["info"], feedback.info.
|
|
69
|
+
rule(["error"], feedback.error.base, { bold: true }),
|
|
70
|
+
rule(["warning"], feedback.warning.base, { bold: true }),
|
|
71
|
+
rule(["info"], feedback.info.base),
|
|
72
72
|
]);
|
|
73
73
|
}
|
|
74
74
|
function rule(scope, foreground, style = {}) {
|
package/dist/tui/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { RGBA } from "@opentui/core";
|
|
2
2
|
import type { ActionState, ActionVariant, BaseHue, FeedbackKind, HueAlias, HueStep, MarkdownToken, SurfaceName, SyntaxToken } from "./schema.js";
|
|
3
|
-
export type ResolvedActionState = "
|
|
3
|
+
export type ResolvedActionState = "base" | ActionState;
|
|
4
4
|
export type ResolvedFormfieldState = ResolvedActionState;
|
|
5
5
|
export type HueScale = Readonly<Record<HueStep, RGBA>>;
|
|
6
6
|
export type Hue = Readonly<Record<BaseHue | HueAlias, HueScale>>;
|
|
@@ -21,23 +21,17 @@ export type ResolvedThemeTokens = {
|
|
|
21
21
|
readonly increase: (color: RGBA, amount?: number) => RGBA;
|
|
22
22
|
readonly decrease: (color: RGBA, amount?: number) => RGBA;
|
|
23
23
|
readonly text: {
|
|
24
|
-
readonly
|
|
25
|
-
readonly
|
|
24
|
+
readonly base: RGBA;
|
|
25
|
+
readonly muted: RGBA;
|
|
26
26
|
readonly action: Readonly<Record<ActionVariant, StatefulColor>>;
|
|
27
27
|
readonly formfield: FormfieldColor;
|
|
28
|
-
readonly status: {
|
|
29
|
-
readonly running: RGBA;
|
|
30
|
-
readonly question: RGBA;
|
|
31
|
-
readonly permission: RGBA;
|
|
32
|
-
readonly unread: RGBA;
|
|
33
|
-
};
|
|
34
28
|
readonly feedback: Readonly<Record<FeedbackKind, {
|
|
35
|
-
readonly
|
|
36
|
-
readonly
|
|
29
|
+
readonly base: RGBA;
|
|
30
|
+
readonly muted: RGBA;
|
|
37
31
|
}>>;
|
|
38
32
|
};
|
|
39
33
|
readonly background: {
|
|
40
|
-
readonly
|
|
34
|
+
readonly base: RGBA;
|
|
41
35
|
readonly raised: {
|
|
42
36
|
readonly base: RGBA;
|
|
43
37
|
readonly high: RGBA;
|
|
@@ -46,14 +40,14 @@ export type ResolvedThemeTokens = {
|
|
|
46
40
|
readonly action: Readonly<Record<ActionVariant, StatefulColor>>;
|
|
47
41
|
readonly formfield: FormfieldColor;
|
|
48
42
|
readonly feedback: Readonly<Record<FeedbackKind, {
|
|
49
|
-
readonly
|
|
43
|
+
readonly base: RGBA;
|
|
50
44
|
}>>;
|
|
51
45
|
};
|
|
52
46
|
readonly border: {
|
|
53
|
-
readonly
|
|
47
|
+
readonly base: RGBA;
|
|
54
48
|
};
|
|
55
49
|
readonly scrollbar: {
|
|
56
|
-
readonly
|
|
50
|
+
readonly base: RGBA;
|
|
57
51
|
};
|
|
58
52
|
readonly diff: {
|
|
59
53
|
readonly text: {
|
package/dist/tui/v1-migrate.js
CHANGED
|
@@ -1,11 +1,36 @@
|
|
|
1
1
|
import { RGBA } from "@opentui/core";
|
|
2
2
|
import { oklchToHex, rgbToOklch } from "./color.js";
|
|
3
|
-
import { DEFAULT_CATEGORICAL
|
|
3
|
+
import { DEFAULT_CATEGORICAL } from "./categorical.js";
|
|
4
4
|
import { HueStep } from "./schema.js";
|
|
5
5
|
const chromaticHues = ["red", "orange", "yellow", "green", "cyan", "blue", "purple"];
|
|
6
6
|
const categoricalTokens = ["secondary", "accent", "success", "warning", "primary", "error"];
|
|
7
7
|
const minimumChroma = 0.03;
|
|
8
8
|
const lightThreshold = 0.6;
|
|
9
|
+
// Canonical swatches copied from the original default-theme classifier keep V1 migration self-contained.
|
|
10
|
+
const hueReferences = {
|
|
11
|
+
light: {
|
|
12
|
+
red: "#fca5a5",
|
|
13
|
+
orange: "#fdba74",
|
|
14
|
+
yellow: "#fde047",
|
|
15
|
+
green: "#86efac",
|
|
16
|
+
cyan: "#67e8f9",
|
|
17
|
+
blue: "#93c5fd",
|
|
18
|
+
purple: "#d8b4fe",
|
|
19
|
+
},
|
|
20
|
+
dark: {
|
|
21
|
+
red: "#b91c1c",
|
|
22
|
+
orange: "#c2410c",
|
|
23
|
+
yellow: "#a16207",
|
|
24
|
+
green: "#15803d",
|
|
25
|
+
cyan: "#0e7490",
|
|
26
|
+
blue: "#1d4ed8",
|
|
27
|
+
purple: "#7e22ce",
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
const hueAngles = Object.fromEntries(Object.entries(hueReferences).map(([level, colors]) => [
|
|
31
|
+
level,
|
|
32
|
+
Object.fromEntries(Object.entries(colors).map(([name, color]) => [name, toOklch(RGBA.fromHex(color)).h])),
|
|
33
|
+
]));
|
|
9
34
|
export function migrateV1(theme) {
|
|
10
35
|
const light = resolveV1(theme, "light");
|
|
11
36
|
const dark = resolveV1(theme, "dark");
|
|
@@ -13,18 +38,24 @@ export function migrateV1(theme) {
|
|
|
13
38
|
const lightMode = detectMode(light);
|
|
14
39
|
const darkMode = detectMode(dark);
|
|
15
40
|
if (lightMode === darkMode) {
|
|
41
|
+
const definition = migrateMode(lightMode === "light" ? light : dark, lightMode);
|
|
16
42
|
if (lightMode === "light")
|
|
17
|
-
return {
|
|
18
|
-
return {
|
|
43
|
+
return { base: base(definition), light: { hue: definition.hue } };
|
|
44
|
+
return { base: base(definition), dark: { hue: definition.hue } };
|
|
19
45
|
}
|
|
20
46
|
}
|
|
47
|
+
const lightDefinition = migrateMode(light, "light");
|
|
48
|
+
const darkDefinition = migrateMode(dark, "dark");
|
|
21
49
|
return {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
dark: migrateMode(dark, "dark"),
|
|
50
|
+
base: base(lightDefinition),
|
|
51
|
+
light: { hue: lightDefinition.hue },
|
|
52
|
+
dark: darkDefinition,
|
|
26
53
|
};
|
|
27
54
|
}
|
|
55
|
+
function base(definition) {
|
|
56
|
+
const { hue: _, ...base } = definition;
|
|
57
|
+
return base;
|
|
58
|
+
}
|
|
28
59
|
function detectMode(theme) {
|
|
29
60
|
return luminance(theme.text) > luminance(theme.background) ? "dark" : "light";
|
|
30
61
|
}
|
|
@@ -35,7 +66,7 @@ function migrateMode(theme, mode) {
|
|
|
35
66
|
const color = (key) => hex(theme[key]);
|
|
36
67
|
const selected = hex(selectedForeground(theme, theme.primary));
|
|
37
68
|
const destructive = hex(selectedForeground(theme, theme.error));
|
|
38
|
-
const hues = inferHues(theme
|
|
69
|
+
const hues = inferHues(theme);
|
|
39
70
|
const categorical = categoricalTokens.flatMap((token) => {
|
|
40
71
|
const hue = hues.byToken[token];
|
|
41
72
|
return hue ? [hue] : [];
|
|
@@ -61,20 +92,20 @@ function migrateMode(theme, mode) {
|
|
|
61
92
|
},
|
|
62
93
|
categorical: uniqueCategorical.length ? uniqueCategorical : DEFAULT_CATEGORICAL,
|
|
63
94
|
text: {
|
|
64
|
-
|
|
65
|
-
|
|
95
|
+
base: text,
|
|
96
|
+
muted: textMuted,
|
|
66
97
|
action: {
|
|
67
98
|
primary: {
|
|
68
|
-
|
|
99
|
+
base: "$text.base",
|
|
69
100
|
$disabled: textMuted,
|
|
70
101
|
$focused: selected,
|
|
71
102
|
$selected: primary,
|
|
72
103
|
},
|
|
73
|
-
secondary: {
|
|
74
|
-
destructive: {
|
|
104
|
+
secondary: { base: "$text.muted", $hovered: "$text.base" },
|
|
105
|
+
destructive: { base: destructive, $disabled: textMuted },
|
|
75
106
|
},
|
|
76
107
|
formfield: {
|
|
77
|
-
|
|
108
|
+
base: text,
|
|
78
109
|
$hovered: primary,
|
|
79
110
|
$focused: primary,
|
|
80
111
|
$pressed: primary,
|
|
@@ -82,36 +113,36 @@ function migrateMode(theme, mode) {
|
|
|
82
113
|
$selected: primary,
|
|
83
114
|
},
|
|
84
115
|
feedback: {
|
|
85
|
-
error: {
|
|
86
|
-
warning: {
|
|
87
|
-
success: {
|
|
88
|
-
info: {
|
|
116
|
+
error: { base: color("error") },
|
|
117
|
+
warning: { base: color("warning") },
|
|
118
|
+
success: { base: color("success") },
|
|
119
|
+
info: { base: color("info") },
|
|
89
120
|
},
|
|
90
121
|
},
|
|
91
122
|
background: {
|
|
92
|
-
|
|
123
|
+
base: background,
|
|
93
124
|
raised: {
|
|
94
125
|
base: backgroundPanel,
|
|
95
126
|
high: backgroundMenu,
|
|
96
127
|
max: backgroundRaisedMax,
|
|
97
128
|
},
|
|
98
129
|
action: {
|
|
99
|
-
primary: {
|
|
100
|
-
secondary: {
|
|
101
|
-
destructive: {
|
|
130
|
+
primary: { base: "transparent", $hovered: backgroundPanel, $focused: primary, $selected: "transparent" },
|
|
131
|
+
secondary: { base: "transparent" },
|
|
132
|
+
destructive: { base: color("error") },
|
|
102
133
|
},
|
|
103
134
|
formfield: {
|
|
104
|
-
|
|
135
|
+
base: "$background.base",
|
|
105
136
|
},
|
|
106
137
|
feedback: {
|
|
107
|
-
error: {
|
|
108
|
-
warning: {
|
|
109
|
-
success: {
|
|
110
|
-
info: {
|
|
138
|
+
error: { base: "$background.base" },
|
|
139
|
+
warning: { base: "$background.base" },
|
|
140
|
+
success: { base: "$background.base" },
|
|
141
|
+
info: { base: "$background.base" },
|
|
111
142
|
},
|
|
112
143
|
},
|
|
113
|
-
border: {
|
|
114
|
-
scrollbar: {
|
|
144
|
+
border: { base: color("border") },
|
|
145
|
+
scrollbar: { base: color("borderActive") },
|
|
115
146
|
diff: {
|
|
116
147
|
text: {
|
|
117
148
|
added: color("diffAdded"),
|
|
@@ -162,7 +193,7 @@ function migrateMode(theme, mode) {
|
|
|
162
193
|
},
|
|
163
194
|
"@dialog": {
|
|
164
195
|
background: {
|
|
165
|
-
|
|
196
|
+
base: "$background.raised.base",
|
|
166
197
|
action: { primary: { $hovered: "$background.raised.high" } },
|
|
167
198
|
},
|
|
168
199
|
},
|
|
@@ -220,7 +251,7 @@ function referenceHues(theme) {
|
|
|
220
251
|
}
|
|
221
252
|
return Object.fromEntries(Object.entries(theme).map(([key, value]) => [key, key === "hue" || key === "categorical" ? value : replace(value)]));
|
|
222
253
|
}
|
|
223
|
-
function inferHues(theme
|
|
254
|
+
function inferHues(theme) {
|
|
224
255
|
const colors = [
|
|
225
256
|
["accent", theme.accent],
|
|
226
257
|
["success", theme.success],
|
|
@@ -231,7 +262,7 @@ function inferHues(theme, mode) {
|
|
|
231
262
|
["secondary", theme.secondary],
|
|
232
263
|
];
|
|
233
264
|
const inferred = colors.reduce((result, [token, color]) => {
|
|
234
|
-
const nearest = inferHue(color
|
|
265
|
+
const nearest = inferHue(color);
|
|
235
266
|
if (!nearest)
|
|
236
267
|
return result;
|
|
237
268
|
const current = result.byHue[nearest.name];
|
|
@@ -246,7 +277,7 @@ function inferHues(theme, mode) {
|
|
|
246
277
|
["accent", theme.accent],
|
|
247
278
|
["primary", theme.primary],
|
|
248
279
|
].reduce((result, [token, color]) => {
|
|
249
|
-
const nearest = inferHue(color
|
|
280
|
+
const nearest = inferHue(color);
|
|
250
281
|
if (!nearest)
|
|
251
282
|
return result;
|
|
252
283
|
return {
|
|
@@ -255,23 +286,18 @@ function inferHues(theme, mode) {
|
|
|
255
286
|
};
|
|
256
287
|
}, inferred);
|
|
257
288
|
}
|
|
258
|
-
function inferHue(color
|
|
289
|
+
function inferHue(color) {
|
|
259
290
|
const value = toOklch(color);
|
|
260
291
|
if (ambiguous(color, value.c))
|
|
261
292
|
return;
|
|
262
|
-
const
|
|
293
|
+
const reference = value.l >= lightThreshold ? hueAngles.light : hueAngles.dark;
|
|
263
294
|
return chromaticHues
|
|
264
295
|
.map((name) => ({
|
|
265
296
|
name,
|
|
266
|
-
distance: hueDistance(value.h,
|
|
297
|
+
distance: hueDistance(value.h, reference[name]),
|
|
267
298
|
}))
|
|
268
299
|
.sort((first, second) => first.distance - second.distance)[0];
|
|
269
300
|
}
|
|
270
|
-
function inferenceAnchor(lightness, mode) {
|
|
271
|
-
if (mode === "light")
|
|
272
|
-
return lightness >= lightThreshold ? 700 : 300;
|
|
273
|
-
return lightness >= lightThreshold ? 300 : 700;
|
|
274
|
-
}
|
|
275
301
|
function hueDistance(first, second) {
|
|
276
302
|
const difference = Math.abs(first - second);
|
|
277
303
|
return Math.min(difference, 360 - difference);
|