@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.
@@ -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
- default: Schema.optional(ColorValue),
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
- default: Schema.optional(ColorValue),
63
- subdued: Schema.optional(ColorValue),
49
+ base: Schema.optional(ColorValue),
50
+ muted: Schema.optional(ColorValue),
64
51
  });
65
52
  const BackgroundFeedbackDefinition = Schema.Struct({
66
- default: Schema.optional(ColorValue),
53
+ base: Schema.optional(ColorValue),
67
54
  });
68
55
  const TextDefinition = Schema.Struct({
69
- default: Schema.optional(ColorValue),
70
- subdued: Schema.optional(ColorValue),
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
- default: Schema.optional(ColorValue),
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({ default: Schema.optional(ColorValue) })),
153
- scrollbar: Schema.optional(Schema.Struct({ default: Schema.optional(ColorValue) })),
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: Schema.optional(CategoricalDefinition),
161
- ...ThemeTokensDefinition.fields,
195
+ categorical: CategoricalDefinition,
196
+ ...CompleteThemeTokensDefinition.fields,
162
197
  "@dialog": Schema.optional(ThemeTokensDefinition),
163
198
  });
164
199
  export const ThemeDefinition = ThemeDefinitionFields;
165
- const FileThemeDefinition = Schema.Struct({
166
- hue: Schema.optional(HueOverrideDefinition),
167
- categorical: Schema.optional(CategoricalDefinition),
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 MergeModeDefinition = Schema.Struct({
172
- mergeMode: Schema.Literal(true),
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({ ...FileMetadata, light: ModeDefinition, dark: Schema.optional(ModeDefinition) }),
186
- Schema.Struct({ ...FileMetadata, light: Schema.optional(ModeDefinition), dark: ModeDefinition }),
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
  ]);
@@ -1,13 +1,8 @@
1
- import type { FileThemeDefinition, Mode, ThemeDefinition, ThemeDocument } from "./index.js";
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: FileThemeDefinition;
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;
@@ -1,4 +1,4 @@
1
- import { expandTheme, mergeTheme } from "./expand.js";
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
- if (merges(document.light) && merges(document.dark))
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
- }
@@ -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.default),
8
+ rule(["default"], theme.text.base),
9
9
  rule(["prompt"], theme.hue.accent[step]),
10
- rule(["extmark.file"], feedback.warning.default, { bold: true }),
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.default,
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.default),
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.default }),
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.default),
58
- rule(["markup.underline"], theme.text.default, { underline: true }),
59
- rule(["comment.error"], feedback.error.default, { italic: true, bold: true }),
60
- rule(["comment.warning"], feedback.warning.default, { italic: true, bold: true }),
61
- rule(["comment.todo", "comment.note"], feedback.info.default, { italic: true, bold: true }),
62
- rule(["attribute", "annotation"], feedback.warning.default),
63
- rule(["tag"], feedback.error.default),
64
- rule(["markup.strikethrough", "markup.list.unchecked", "debug"], theme.text.subdued),
65
- rule(["markup.list.checked"], feedback.success.default),
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.default, { bold: true }),
70
- rule(["warning"], feedback.warning.default, { bold: true }),
71
- rule(["info"], feedback.info.default),
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 = {}) {
@@ -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 = "default" | ActionState;
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 default: RGBA;
25
- readonly subdued: RGBA;
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 default: RGBA;
36
- readonly subdued: RGBA;
29
+ readonly base: RGBA;
30
+ readonly muted: RGBA;
37
31
  }>>;
38
32
  };
39
33
  readonly background: {
40
- readonly default: RGBA;
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 default: RGBA;
43
+ readonly base: RGBA;
50
44
  }>>;
51
45
  };
52
46
  readonly border: {
53
- readonly default: RGBA;
47
+ readonly base: RGBA;
54
48
  };
55
49
  readonly scrollbar: {
56
- readonly default: RGBA;
50
+ readonly base: RGBA;
57
51
  };
58
52
  readonly diff: {
59
53
  readonly text: {
@@ -1,11 +1,36 @@
1
1
  import { RGBA } from "@opentui/core";
2
2
  import { oklchToHex, rgbToOklch } from "./color.js";
3
- import { DEFAULT_CATEGORICAL, DEFAULT_THEME } from "./defaults.js";
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 { version: 2, standalone: true, light: migrateMode(light, "light") };
18
- return { version: 2, standalone: true, dark: migrateMode(dark, "dark") };
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
- version: 2,
23
- standalone: true,
24
- light: migrateMode(light, "light"),
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, mode);
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
- default: text,
65
- subdued: textMuted,
95
+ base: text,
96
+ muted: textMuted,
66
97
  action: {
67
98
  primary: {
68
- default: "$text.default",
99
+ base: "$text.base",
69
100
  $disabled: textMuted,
70
101
  $focused: selected,
71
102
  $selected: primary,
72
103
  },
73
- secondary: { default: "$text.subdued", $hovered: "$text.default" },
74
- destructive: { default: destructive, $disabled: textMuted },
104
+ secondary: { base: "$text.muted", $hovered: "$text.base" },
105
+ destructive: { base: destructive, $disabled: textMuted },
75
106
  },
76
107
  formfield: {
77
- default: text,
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: { default: color("error") },
86
- warning: { default: color("warning") },
87
- success: { default: color("success") },
88
- info: { default: color("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
- default: background,
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: { default: "transparent", $hovered: backgroundPanel, $focused: primary, $selected: "transparent" },
100
- secondary: { default: "transparent" },
101
- destructive: { default: color("error") },
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
- default: "$background.default",
135
+ base: "$background.base",
105
136
  },
106
137
  feedback: {
107
- error: { default: "$background.default" },
108
- warning: { default: "$background.default" },
109
- success: { default: "$background.default" },
110
- info: { default: "$background.default" },
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: { default: color("border") },
114
- scrollbar: { default: color("borderActive") },
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
- default: "$background.raised.base",
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, mode) {
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, mode);
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, mode);
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, mode) {
289
+ function inferHue(color) {
259
290
  const value = toOklch(color);
260
291
  if (ambiguous(color, value.c))
261
292
  return;
262
- const anchor = inferenceAnchor(value.l, mode);
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, toOklch(RGBA.fromHex(DEFAULT_THEME[mode].hue[name][anchor])).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);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@opencode/theme",
4
- "version": "0.0.0-dev-19795",
4
+ "version": "0.0.0-dev-19812",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "repository": {