@sanity/themer 0.3.16 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,17 +8,23 @@ npm install @sanity/themer
8
8
 
9
9
  ## Usage
10
10
 
11
- `buildTheme` builds the same type of theme as `buildTheme` from `@sanity/ui/theme` — ready for the `theme` property of a Studio config — but takes colors instead of design tokens. Under the hood it only swaps out the color palette that `@sanity/ui/theme` otherwise fills with [`@sanity/color`](https://www.sanity.io/docs/color):
11
+ `buildTheme` builds the same type of theme as `buildTheme` from `@sanity/ui/theme` — ready for the `theme` property of a Studio config — but takes a handful of colors per color scheme instead of design tokens. Under the hood it only swaps out the color palette that `@sanity/ui/theme` otherwise fills with [`@sanity/color`](https://www.sanity.io/docs/color), once for each scheme:
12
12
 
13
13
  ```ts
14
14
  import {buildTheme} from '@sanity/themer'
15
15
  import {defineConfig} from 'sanity'
16
16
 
17
17
  export const theme = buildTheme({
18
- accent: '#f00', // required
19
- text: '#727892', // optional
20
- background: {dark: '#0d0e12', light: '#ffffff'}, // optional
21
- contrast: 85, // optional, 15–100
18
+ light: {
19
+ accent: '#f00',
20
+ text: '#727892',
21
+ background: '#ffffff',
22
+ contrast: 85, // 15–100
23
+ },
24
+ dark: {
25
+ accent: '#f66',
26
+ background: '#0d0e12',
27
+ },
22
28
  })
23
29
 
24
30
  export default defineConfig({
@@ -27,16 +33,16 @@ export default defineConfig({
27
33
  })
28
34
  ```
29
35
 
30
- - `accent` replaces the `blue` scale of the palette, which Sanity UI uses for primary buttons, focus rings and links.
36
+ Everything is optional — both schemes, and every color in them. Whatever is omitted falls back to the stock Studio colors, so `buildTheme({})` matches `buildTheme()` from `@sanity/ui/theme` with no options exactly, and the two schemes are free to differ in every color rather than only their background:
37
+
38
+ - `accent` replaces the `blue` scale of the scheme's palette, which Sanity UI uses for primary buttons, focus rings and links.
31
39
  - `text` replaces the `gray` scale — text, icons, borders and neutral surfaces. When omitted it is derived from `accent`: a mostly desaturated version of it, the way the stock gray carries a hint of the stock blue.
32
- - `background.dark` replaces `black` and `background.light` replaces `white` — the backgrounds of the two color schemes that every other color blends onto.
40
+ - `background` replaces `black` in the dark scheme and `white` in the light scheme — the background that every other color of the scheme blends onto.
33
41
  - `contrast` controls how strongly text and borders separate from the accent. The default `85` uses the text color as-is; `100` removes its tint entirely (a high contrast scheme with no mixing of text and accent), and lower values blend more and more of the accent into the text scale, giving text and borders more color.
34
42
 
35
- A few ground rules keep the generated palette usable: the accent and text colors cannot be too dark or too light (they would mess with the rest of their scales), `background.dark` is made darker until it has enough contrast with both of them (it can never be lighter than either), and `background.light` can never be darker than either.
36
-
37
- Called with the stock colors — like `text` and `background` in the example — the generated colors match `buildTheme()` from `@sanity/ui/theme` with no options exactly.
43
+ A few ground rules keep the generated palettes usable: the accent and text colors cannot be too dark or too light (they would mess with the rest of their scales), the dark background is made darker until it has enough contrast with both of them (it can never be lighter than either), and the light background can never be darker than either.
38
44
 
39
- `buildPalette` returns the generated `@sanity/color`-shaped palette without building a theme from it, and `presets` ships the hosted Themer service presets translated to `buildTheme` options:
45
+ `buildPalette` returns the generated `@sanity/color`-shaped palettes (`{light, dark}`) without building a theme from them, and `presets` ships the hosted Themer service presets translated to `buildTheme` options:
40
46
 
41
47
  ```ts
42
48
  import {buildTheme, presets} from '@sanity/themer'
@@ -47,7 +53,7 @@ const theme = buildTheme(verdant.options)
47
53
 
48
54
  ## Studio tool
49
55
 
50
- `@sanity/themer/tool` adds a themer sidebar to the Studio for these themes: presets, accent/text/background pickers and a contrast slider preview a `buildTheme` theme live on the whole Studio, plus the snippet to make it permanent:
56
+ `@sanity/themer/tool` adds a themer sidebar to the Studio for these themes. It lists the configured theme, the presets and your own themes, each previewed as a tiny Studio in both color schemes, and picking one applies it live to the whole Studio while you browse around. Your own themes are edited scheme by scheme — a light mode and a dark mode card with accent/text/background pickers and a contrast slider each, the one the Studio is showing marked as active — add one from scratch, duplicate a preset to start from it, or take the colors from an image: its palette is read on device (the image is drawn onto a canvas and its vibrant and muted colors extracted right there, nothing is uploaded), the vibrant color becomes the accent (adjusted until a button label reads on it), the muted one the text color and the light and dark muted colors tint the backgrounds, and a row of variants previews the theme built around each swatch instead — with an "I'm feeling lucky" button that picks an interesting one. Themes can be removed and restored, and a dialog shows the `buildTheme` snippet that makes the applied theme permanent:
51
57
 
52
58
  ```ts
53
59
  import {themerTool} from '@sanity/themer/tool'
@@ -59,7 +65,7 @@ export default defineConfig({
59
65
  })
60
66
  ```
61
67
 
62
- If the Studio already uses a `buildTheme` theme, pass the same options so the tool starts editing from them: `themerTool({config: {accent: '#1cb485'}})`.
68
+ If the Studio already uses a `buildTheme` theme, pass the same options so the tool starts editing from them: `themerTool({config: {light: {accent: '#1cb485'}}})`.
63
69
 
64
70
  ## Migrating from themer.sanity.build
65
71
 
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { t as BuildThemeOptions } from "./options-BaqJJgRs.js";
1
+ import { n as SchemeThemeOptions, t as BuildThemeOptions } from "./options-CU-emn_p.js";
2
2
  import { ColorHueKey, ColorTintKey } from "@sanity/color";
3
- import { RootTheme } from "@sanity/ui/theme";
3
+ import { RootTheme, ThemeColorSchemeKey } from "@sanity/ui/theme";
4
4
  /**
5
- * The color palette generated by {@link buildPalette}: the `palette` config
6
- * of `buildTheme` from `@sanity/ui/theme`, with every color as a hex string.
5
+ * A color palette generated by {@link buildPalette}: the `palette` config of
6
+ * `buildTheme` from `@sanity/ui/theme`, with every color as a hex string.
7
7
  *
8
8
  * @public
9
9
  */
@@ -12,39 +12,53 @@ type GeneratedColorPalette = {
12
12
  white: string;
13
13
  } & Record<ColorHueKey, Record<ColorTintKey, string>>;
14
14
  /**
15
- * Generates a Sanity UI color palette from the theme options: the accent
16
- * color replaces the `blue` scale, the text color the `gray` scale, and the
17
- * backgrounds replace `black` and `white`. All other hues keep their stock
18
- * `@sanity/color` values. Called with the stock colors, it returns the stock
19
- * palette byte-for-byte.
15
+ * The palettes generated by {@link buildPalette} — one per color scheme.
16
+ *
17
+ * @public
18
+ */
19
+ type GeneratedColorPalettes = Record<ThemeColorSchemeKey, GeneratedColorPalette>;
20
+ /**
21
+ * Generates a Sanity UI color palette for each color scheme from the theme
22
+ * options: in each palette the scheme's accent color replaces the `blue`
23
+ * scale, its text color the `gray` scale, and the backgrounds replace `black`
24
+ * and `white`. All other hues keep their stock `@sanity/color` values. Called
25
+ * with the stock colors, both palettes come back as the stock palette
26
+ * byte-for-byte.
20
27
  *
21
28
  * ```ts
22
29
  * import {buildPalette} from '@sanity/themer'
23
30
  *
24
- * const palette = buildPalette({accent: '#556bfc'})
31
+ * const {light, dark} = buildPalette({light: {accent: '#556bfc'}})
25
32
  * ```
26
33
  *
27
34
  * @public
28
35
  */
29
- export declare function buildPalette(options: BuildThemeOptions): GeneratedColorPalette;
36
+ export declare function buildPalette(options?: BuildThemeOptions): GeneratedColorPalettes;
30
37
  /**
31
- * Generates a Studio theme from a handful of colors, by replacing the color
32
- * palette that the `buildTheme` from `@sanity/ui/theme` otherwise fills with
33
- * `@sanity/color`: the accent color replaces the `blue` scale (primary
34
- * buttons, focus rings, links), the optional text color the `gray` scale
35
- * (text, icons, borders), and the optional backgrounds replace `black` and
36
- * `white`. The result is the same type of theme that `@sanity/ui/theme`
37
- * builds, ready for the `theme` property of a Studio config.
38
+ * Generates a Studio theme from a handful of colors per color scheme, by
39
+ * replacing the color palette that the `buildTheme` from `@sanity/ui/theme`
40
+ * otherwise fills with `@sanity/color`: in each scheme the accent color
41
+ * replaces the `blue` scale (primary buttons, focus rings, links), the
42
+ * optional text color the `gray` scale (text, icons, borders), and the
43
+ * optional background replaces `black` (dark) or `white` (light). The result
44
+ * is the same type of theme that `@sanity/ui/theme` builds, ready for the
45
+ * `theme` property of a Studio config.
38
46
  *
39
47
  * ```ts
40
48
  * import {buildTheme} from '@sanity/themer'
41
49
  * import {defineConfig} from 'sanity'
42
50
  *
43
51
  * export const theme = buildTheme({
44
- * accent: '#556bfc',
45
- * text: '#727892', // optional — derived from `accent` when omitted
46
- * background: {dark: '#0d0e12', light: '#ffffff'}, // optional
47
- * contrast: 85, // optional, 15–100
52
+ * light: {
53
+ * accent: '#556bfc',
54
+ * text: '#727892', // optional — derived from `accent` when omitted
55
+ * background: '#ffffff', // optional
56
+ * contrast: 85, // optional, 15–100
57
+ * },
58
+ * dark: {
59
+ * accent: '#556bfc',
60
+ * background: '#0d0e12',
61
+ * },
48
62
  * })
49
63
  *
50
64
  * export default defineConfig({
@@ -53,12 +67,13 @@ export declare function buildPalette(options: BuildThemeOptions): GeneratedColor
53
67
  * })
54
68
  * ```
55
69
  *
56
- * Called with the stock colors — like the example — it returns the exact
57
- * same colors as `buildTheme()` from `@sanity/ui/theme` with no options.
70
+ * Every option is optional and falls back to the stock Studio colors: called
71
+ * with the stock colors — like the example — or with no options at all, it
72
+ * returns the exact same colors as `buildTheme()` from `@sanity/ui/theme`.
58
73
  *
59
74
  * @public
60
75
  */
61
- export declare function buildTheme(options: BuildThemeOptions): RootTheme;
76
+ export declare function buildTheme(options?: BuildThemeOptions): RootTheme;
62
77
  /**
63
78
  * A preset theme: a named set of {@link BuildThemeOptions} ready to pass to
64
79
  * `buildTheme`.
@@ -75,7 +90,7 @@ interface ThemePreset {
75
90
  * Preset themes for `buildTheme`, carried over from the hosted Themer service
76
91
  * (themer.sanity.build) presets: each one maps the legacy preset's primary
77
92
  * hue to `accent`, its default hue to `text` and its lightest/darkest colors
78
- * to the backgrounds.
93
+ * to the backgrounds of the light and dark scheme.
79
94
  *
80
95
  * ```ts
81
96
  * import {buildTheme, presets} from '@sanity/themer'
@@ -87,5 +102,5 @@ interface ThemePreset {
87
102
  * @public
88
103
  */
89
104
  export declare const presets: ThemePreset[];
90
- export type { BuildThemeOptions, GeneratedColorPalette, ThemePreset };
105
+ export type { BuildThemeOptions, GeneratedColorPalette, GeneratedColorPalettes, SchemeThemeOptions, ThemePreset };
91
106
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/theme/buildPalette.ts","../src/theme/buildTheme.ts","../src/theme/presets.ts"],"mappings":";;;;;;;;;KAqCY;EAAyB;EAAe;IAAiB,OACnE,aACA,OAAO;;;;;;;;;;;;;;;;wBAkBO,aAAa,SAAS,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBCrB1C,WAAW,SAAS,oBAAoB;;;;;;;UC5BvC;EACf;EACA;;EAEA,SAAS;;;;;;;;;;;;;;;;;qBAkBE,SAAS"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/theme/buildPalette.ts","../src/theme/buildTheme.ts","../src/theme/presets.ts"],"mappings":";;;;;;;;;KAuCY;EAAyB;EAAe;IAAiB,OACnE,aACA,OAAO;;;;;;KAQG,yBAAyB,OAAO,qBAAqB;;;;;;;;;;;;;;;;;wBAkBjD,aAAa,UAAS,oBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBCjB/C,WAAW,UAAS,oBAAyB;;;;;;;UC1C5C;EACf;EACA;;EAEA,SAAS;;;;;;;;;;;;;;;;;qBA6BE,SAAS"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { n as buildTheme, r as buildPalette, t as presets } from "./presets-By3s-D-S.js";
1
+ import { n as buildTheme, r as buildPalette, t as presets } from "./presets-CqBgS3A-.js";
2
2
  export { buildPalette, buildTheme, presets };
@@ -0,0 +1,69 @@
1
+ import { ThemeColorSchemeKey } from "@sanity/ui/theme";
2
+ /**
3
+ * The colors of one color scheme, for {@link BuildThemeOptions}. Every color
4
+ * is a hex color (`#rgb` or `#rrggbb`), and everything is optional: omitted
5
+ * options fall back to the stock Studio colors, so an empty object reproduces
6
+ * the stock scheme exactly.
7
+ *
8
+ * @public
9
+ */
10
+ interface SchemeThemeOptions {
11
+ /**
12
+ * The accent color — the brand color of the scheme. Replaces the `blue`
13
+ * scale of the palette, which Sanity UI uses for primary buttons, focus
14
+ * rings and links.
15
+ *
16
+ * The stock accent is `#556bfc` (`blue/500` of `@sanity/color`).
17
+ */
18
+ accent?: string;
19
+ /**
20
+ * The background of the scheme — every other color of the scheme is
21
+ * blended onto it. The dark scheme's background replaces `black` in the
22
+ * palette and the light scheme's replaces `white`.
23
+ *
24
+ * It is kept far enough from the text and accent colors to stay usable:
25
+ * a dark background is made darker until it has enough contrast with them
26
+ * (it can never be lighter than either), and a light background can never
27
+ * be darker than either.
28
+ *
29
+ * The stock backgrounds are `#0d0e12` (dark) and `#ffffff` (light).
30
+ */
31
+ background?: string;
32
+ /**
33
+ * How strongly text and borders separate from the accent color, between 15
34
+ * and 100. The default is 85, which uses the text color as-is. Above 85 the
35
+ * text scale loses its tint until it is fully neutral at 100 — a high
36
+ * contrast scheme with no mixing of the text and accent colors. Below 85
37
+ * more and more of the accent color mixes into the text scale, giving text
38
+ * and borders more color, until the scale fully adopts the accent hue and
39
+ * saturation at 15.
40
+ */
41
+ contrast?: number;
42
+ /**
43
+ * The text color. Replaces the `gray` scale of the palette, which Sanity UI
44
+ * uses for text, icons, borders and neutral surfaces. When omitted, it is
45
+ * derived from the accent color: a mostly desaturated version of it, the
46
+ * way the stock `gray` scale carries a hint of the stock blue.
47
+ *
48
+ * The stock text color is `#727892` (`gray/500` of `@sanity/color`).
49
+ */
50
+ text?: string;
51
+ }
52
+ /**
53
+ * Options for {@link buildTheme} and {@link buildPalette}: the colors of the
54
+ * dark and the light scheme, each with its own accent, text, background and
55
+ * contrast — so the two schemes can differ in more than their background.
56
+ * Both schemes are optional, and so is every color: whatever is omitted
57
+ * falls back to the stock Studio colors, so `buildTheme({})` matches
58
+ * `buildTheme()` from `@sanity/ui/theme` exactly.
59
+ *
60
+ * @public
61
+ */
62
+ interface BuildThemeOptions {
63
+ /** The colors of the dark scheme */
64
+ dark?: SchemeThemeOptions;
65
+ /** The colors of the light scheme */
66
+ light?: SchemeThemeOptions;
67
+ }
68
+ export { SchemeThemeOptions as n, BuildThemeOptions as t };
69
+ //# sourceMappingURL=options-CU-emn_p.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options-CU-emn_p.d.ts","names":[],"sources":["../src/theme/options.ts"],"mappings":";;;;;;;;;UAciB;;;;;;;;EAQf;;;;;;;;;;;;;EAcA;;;;;;;;;;EAWA;;;;;;;;;EAUA;;;;;;;;;;;;UAae;;EAEf,OAAO;;EAEP,QAAQ"}
@@ -1,5 +1,5 @@
1
1
  import { COLOR_TINTS, black, blue, color, gray, white } from "@sanity/color";
2
- import { buildTheme } from "@sanity/ui/theme";
2
+ import { buildTheme, v0_v2, v2_v0 } from "@sanity/ui/theme";
3
3
  /** @internal */
4
4
  function hexToHsl(hex) {
5
5
  let [r, g, b] = parseHex(hex), max = Math.max(r, g, b), min = Math.min(r, g, b), delta = max - min, l = (max + min) / 2;
@@ -71,19 +71,31 @@ function clamp01(value) {
71
71
  function isColor(input) {
72
72
  return /^#(?:[0-9a-f]{3}){1,2}$/i.test(input);
73
73
  }
74
- /** The stock accent color — `blue/500` of `@sanity/color` @internal */
75
- const DEFAULT_ACCENT = blue[500].hex, DEFAULT_TEXT = gray[500].hex, DEFAULT_BACKGROUND_DARK = black.hex, DEFAULT_BACKGROUND_LIGHT = white.hex;
74
+ /** The color schemes, in the order the tool presents them @internal */
75
+ const SCHEMES = ["light", "dark"], DEFAULT_ACCENT = blue[500].hex, DEFAULT_TEXT = gray[500].hex, DEFAULT_BACKGROUND = {
76
+ dark: black.hex,
77
+ light: white.hex
78
+ }, FLAT_OPTION_KEYS = [
79
+ "accent",
80
+ "text",
81
+ "background",
82
+ "contrast"
83
+ ];
76
84
  /** @internal */
77
- function resolveThemeOptions(options) {
78
- let accent = normalizeColor(options.accent, "accent");
85
+ function resolveThemeOptions(options = {}) {
86
+ if (FLAT_OPTION_KEYS.some((key) => key in options)) throw TypeError("The `buildTheme` options are grouped by color scheme: pass `{light: {accent, text, background, contrast}, dark: {…}}` instead of one set of colors for both");
87
+ return {
88
+ dark: resolveSchemeOptions(options.dark ?? {}, "dark"),
89
+ light: resolveSchemeOptions(options.light ?? {}, "light")
90
+ };
91
+ }
92
+ function resolveSchemeOptions(options, scheme) {
93
+ let accent = options.accent === void 0 ? DEFAULT_ACCENT : normalizeColor(options.accent, `${scheme}.accent`);
79
94
  return {
80
95
  accent,
81
- background: {
82
- dark: options.background?.dark === void 0 ? DEFAULT_BACKGROUND_DARK : normalizeColor(options.background.dark, "background.dark"),
83
- light: options.background?.light === void 0 ? DEFAULT_BACKGROUND_LIGHT : normalizeColor(options.background.light, "background.light")
84
- },
85
- contrast: normalizeContrast(options.contrast),
86
- text: options.text === void 0 ? deriveTextColor(accent) : normalizeColor(options.text, "text")
96
+ background: options.background === void 0 ? DEFAULT_BACKGROUND[scheme] : normalizeColor(options.background, `${scheme}.background`),
97
+ contrast: normalizeContrast(options.contrast, scheme),
98
+ text: options.text === void 0 ? deriveTextColor(accent) : normalizeColor(options.text, `${scheme}.text`)
87
99
  };
88
100
  }
89
101
  /**
@@ -108,9 +120,9 @@ function normalizeColor(value, name) {
108
120
  let lower = value.toLowerCase();
109
121
  return lower.length === 4 ? `#${lower[1]}${lower[1]}${lower[2]}${lower[2]}${lower[3]}${lower[3]}` : lower;
110
122
  }
111
- function normalizeContrast(value) {
123
+ function normalizeContrast(value, scheme) {
112
124
  if (value === void 0) return 85;
113
- if (typeof value != "number" || !Number.isFinite(value)) throw TypeError(`Invalid \`contrast\`: ${JSON.stringify(value)} — expected a number between 15 and 100`);
125
+ if (typeof value != "number" || !Number.isFinite(value)) throw TypeError(`Invalid \`${scheme}.contrast\`: ${JSON.stringify(value)} — expected a number between 15 and 100`);
114
126
  return Math.min(100, Math.max(15, value));
115
127
  }
116
128
  /**
@@ -120,28 +132,42 @@ function normalizeContrast(value) {
120
132
  */
121
133
  const BACKGROUND_LIGHTNESS_STEP = .005;
122
134
  /**
123
- * Generates a Sanity UI color palette from the theme options: the accent
124
- * color replaces the `blue` scale, the text color the `gray` scale, and the
125
- * backgrounds replace `black` and `white`. All other hues keep their stock
126
- * `@sanity/color` values. Called with the stock colors, it returns the stock
127
- * palette byte-for-byte.
135
+ * Generates a Sanity UI color palette for each color scheme from the theme
136
+ * options: in each palette the scheme's accent color replaces the `blue`
137
+ * scale, its text color the `gray` scale, and the backgrounds replace `black`
138
+ * and `white`. All other hues keep their stock `@sanity/color` values. Called
139
+ * with the stock colors, both palettes come back as the stock palette
140
+ * byte-for-byte.
128
141
  *
129
142
  * ```ts
130
143
  * import {buildPalette} from '@sanity/themer'
131
144
  *
132
- * const palette = buildPalette({accent: '#556bfc'})
145
+ * const {light, dark} = buildPalette({light: {accent: '#556bfc'}})
133
146
  * ```
134
147
  *
135
148
  * @public
136
149
  */
137
- function buildPalette(options) {
138
- let resolved = resolveThemeOptions(options), accentAnchor = clampAnchorLightness(hexToHsl(resolved.accent)), grayAnchor = applyContrast(clampAnchorLightness(hexToHsl(resolved.text)), accentAnchor, resolved.contrast), blueTints = remapTints(color.blue, hexToHsl(DEFAULT_ACCENT), accentAnchor), grayTints = remapTints(color.gray, hexToHsl(DEFAULT_TEXT), grayAnchor), anchorLuminances = [relativeLuminance(hslToHex(grayAnchor)), relativeLuminance(hslToHex(accentAnchor))];
150
+ function buildPalette(options = {}) {
151
+ let resolved = resolveThemeOptions(options);
152
+ return {
153
+ dark: buildSchemePalette("dark", resolved.dark, resolved.light.background),
154
+ light: buildSchemePalette("light", resolved.light, resolved.dark.background)
155
+ };
156
+ }
157
+ /**
158
+ * Generates the palette of one scheme. The scheme's own background takes the
159
+ * slot the scheme paints with (`black` for dark, `white` for light), while
160
+ * the other slot — which a scheme only touches for a few inverted details —
161
+ * takes the other scheme's background, so the theme stays one palette.
162
+ */
163
+ function buildSchemePalette(key, scheme, otherBackground) {
164
+ let accentAnchor = clampAnchorLightness(hexToHsl(scheme.accent)), grayAnchor = applyContrast(clampAnchorLightness(hexToHsl(scheme.text)), accentAnchor, scheme.contrast), blueTints = remapTints(color.blue, hexToHsl(DEFAULT_ACCENT), accentAnchor), grayTints = remapTints(color.gray, hexToHsl(DEFAULT_TEXT), grayAnchor), anchorLuminances = [relativeLuminance(hslToHex(grayAnchor)), relativeLuminance(hslToHex(accentAnchor))], darkBackground = key === "dark" ? scheme.background : otherBackground, lightBackground = key === "light" ? scheme.background : otherBackground;
139
165
  return {
140
- black: darkenBackground(resolved.background.dark, {
166
+ black: darkenBackground(darkBackground, {
141
167
  anchorLuminances,
142
168
  tints: [grayTints[400], blueTints[400]]
143
169
  }),
144
- white: lightenBackground(resolved.background.light, anchorLuminances),
170
+ white: lightenBackground(lightBackground, anchorLuminances),
145
171
  gray: grayTints,
146
172
  blue: blueTints,
147
173
  purple: tintHexes(color.purple),
@@ -243,23 +269,30 @@ function tintHexes(tints) {
243
269
  return result;
244
270
  }
245
271
  /**
246
- * Generates a Studio theme from a handful of colors, by replacing the color
247
- * palette that the `buildTheme` from `@sanity/ui/theme` otherwise fills with
248
- * `@sanity/color`: the accent color replaces the `blue` scale (primary
249
- * buttons, focus rings, links), the optional text color the `gray` scale
250
- * (text, icons, borders), and the optional backgrounds replace `black` and
251
- * `white`. The result is the same type of theme that `@sanity/ui/theme`
252
- * builds, ready for the `theme` property of a Studio config.
272
+ * Generates a Studio theme from a handful of colors per color scheme, by
273
+ * replacing the color palette that the `buildTheme` from `@sanity/ui/theme`
274
+ * otherwise fills with `@sanity/color`: in each scheme the accent color
275
+ * replaces the `blue` scale (primary buttons, focus rings, links), the
276
+ * optional text color the `gray` scale (text, icons, borders), and the
277
+ * optional background replaces `black` (dark) or `white` (light). The result
278
+ * is the same type of theme that `@sanity/ui/theme` builds, ready for the
279
+ * `theme` property of a Studio config.
253
280
  *
254
281
  * ```ts
255
282
  * import {buildTheme} from '@sanity/themer'
256
283
  * import {defineConfig} from 'sanity'
257
284
  *
258
285
  * export const theme = buildTheme({
259
- * accent: '#556bfc',
260
- * text: '#727892', // optional — derived from `accent` when omitted
261
- * background: {dark: '#0d0e12', light: '#ffffff'}, // optional
262
- * contrast: 85, // optional, 15–100
286
+ * light: {
287
+ * accent: '#556bfc',
288
+ * text: '#727892', // optional — derived from `accent` when omitted
289
+ * background: '#ffffff', // optional
290
+ * contrast: 85, // optional, 15–100
291
+ * },
292
+ * dark: {
293
+ * accent: '#556bfc',
294
+ * background: '#0d0e12',
295
+ * },
263
296
  * })
264
297
  *
265
298
  * export default defineConfig({
@@ -268,19 +301,49 @@ function tintHexes(tints) {
268
301
  * })
269
302
  * ```
270
303
  *
271
- * Called with the stock colors — like the example — it returns the exact
272
- * same colors as `buildTheme()` from `@sanity/ui/theme` with no options.
304
+ * Every option is optional and falls back to the stock Studio colors: called
305
+ * with the stock colors — like the example — or with no options at all, it
306
+ * returns the exact same colors as `buildTheme()` from `@sanity/ui/theme`.
273
307
  *
274
308
  * @public
275
309
  */
276
- function buildTheme$1(options) {
277
- return buildTheme({ palette: buildPalette(options) });
310
+ function buildTheme$1(options = {}) {
311
+ let palettes = buildPalette(options), light = v0_v2(buildTheme({ palette: palettes.light })), dark = v0_v2(buildTheme({ palette: palettes.dark })), color = {
312
+ get light() {
313
+ return light.color.light;
314
+ },
315
+ get dark() {
316
+ return dark.color.dark;
317
+ }
318
+ };
319
+ return v2_v0({
320
+ ...light,
321
+ color
322
+ });
323
+ }
324
+ /**
325
+ * The hosted Themer presets had one accent and one text color for both
326
+ * schemes, and a background per scheme
327
+ */
328
+ function scheme(accent, text, backgrounds) {
329
+ return {
330
+ dark: {
331
+ accent,
332
+ text,
333
+ background: backgrounds.dark
334
+ },
335
+ light: {
336
+ accent,
337
+ text,
338
+ background: backgrounds.light
339
+ }
340
+ };
278
341
  }
279
342
  /**
280
343
  * Preset themes for `buildTheme`, carried over from the hosted Themer service
281
344
  * (themer.sanity.build) presets: each one maps the legacy preset's primary
282
345
  * hue to `accent`, its default hue to `text` and its lightest/darkest colors
283
- * to the backgrounds.
346
+ * to the backgrounds of the light and dark scheme.
284
347
  *
285
348
  * ```ts
286
349
  * import {buildTheme, presets} from '@sanity/themer'
@@ -295,93 +358,65 @@ const presets = [
295
358
  {
296
359
  slug: "studio",
297
360
  title: "Studio",
298
- options: { accent: DEFAULT_ACCENT }
361
+ options: {}
299
362
  },
300
363
  {
301
364
  slug: "dew",
302
365
  title: "Dew",
303
- options: {
304
- accent: "#d1a308",
305
- text: "#5e63b4",
306
- background: {
307
- dark: "#0d0d15",
308
- light: "#fcfcfd"
309
- }
310
- }
366
+ options: scheme("#d1a308", "#5e63b4", {
367
+ dark: "#0d0d15",
368
+ light: "#fcfcfd"
369
+ })
311
370
  },
312
371
  {
313
372
  slug: "pink-synth",
314
373
  title: "Pink Synth",
315
- options: {
316
- accent: "#ec4899",
317
- text: "#8b6584",
318
- background: {
319
- dark: "#171721",
320
- light: "#f7f2f5"
321
- }
322
- }
374
+ options: scheme("#ec4899", "#8b6584", {
375
+ dark: "#171721",
376
+ light: "#f7f2f5"
377
+ })
323
378
  },
324
379
  {
325
380
  slug: "pixel-art",
326
381
  title: "Pixel Art",
327
- options: {
328
- accent: "#f10784",
329
- text: "#57619c",
330
- background: {
331
- dark: "#0d0e15",
332
- light: "#fcfcfd"
333
- }
334
- }
382
+ options: scheme("#f10784", "#57619c", {
383
+ dark: "#0d0e15",
384
+ light: "#fcfcfd"
385
+ })
335
386
  },
336
387
  {
337
388
  slug: "retro-colonial",
338
389
  title: "Retro Colonial",
339
- options: {
340
- accent: "#fa7a78",
341
- text: "#8bb9b5",
342
- background: {
343
- dark: "#0d1515",
344
- light: "#fcfdfd"
345
- }
346
- }
390
+ options: scheme("#fa7a78", "#8bb9b5", {
391
+ dark: "#0d1515",
392
+ light: "#fcfdfd"
393
+ })
347
394
  },
348
395
  {
349
396
  slug: "rosabel",
350
397
  title: "Rosabel",
351
- options: {
352
- accent: "#ed2555",
353
- text: "#9d8966",
354
- background: {
355
- dark: "#15120d",
356
- light: "#fdfdfc"
357
- }
358
- }
398
+ options: scheme("#ed2555", "#9d8966", {
399
+ dark: "#15120d",
400
+ light: "#fdfdfc"
401
+ })
359
402
  },
360
403
  {
361
404
  slug: "stereofidelic",
362
405
  title: "Stereofidelic",
363
- options: {
364
- accent: "#f13009",
365
- text: "#678e9a",
366
- background: {
367
- dark: "#0e1315",
368
- light: "#fcfdfd"
369
- }
370
- }
406
+ options: scheme("#f13009", "#678e9a", {
407
+ dark: "#0e1315",
408
+ light: "#fcfdfd"
409
+ })
371
410
  },
372
411
  {
373
412
  slug: "verdant",
374
413
  title: "Verdant",
375
- options: {
376
- accent: "#1cb485",
377
- text: "#5c9199",
378
- background: {
379
- dark: "#0d1415",
380
- light: "#fcfdfd"
381
- }
382
- }
414
+ options: scheme("#1cb485", "#5c9199", {
415
+ dark: "#0d1415",
416
+ light: "#fcfdfd"
417
+ })
383
418
  }
384
419
  ];
385
- export { DEFAULT_BACKGROUND_DARK as a, resolveThemeOptions as c, DEFAULT_ACCENT as i, isColor as l, buildTheme$1 as n, DEFAULT_BACKGROUND_LIGHT as o, buildPalette as r, deriveTextColor as s, presets as t };
420
+ export { DEFAULT_BACKGROUND as a, resolveThemeOptions as c, hslToHex as d, relativeLuminance as f, DEFAULT_ACCENT as i, isColor as l, buildTheme$1 as n, SCHEMES as o, buildPalette as r, deriveTextColor as s, presets as t, hexToHsl as u };
386
421
 
387
- //# sourceMappingURL=presets-By3s-D-S.js.map
422
+ //# sourceMappingURL=presets-CqBgS3A-.js.map