@sanity/themer 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tool.cjs DELETED
@@ -1,407 +0,0 @@
1
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_mix = require("./_chunks/mix.cjs"), require_presets = require("./_chunks/presets.cjs");
3
- let _sanity_color = require("@sanity/color"), sanity = require("sanity"), _sanity_ui = require("@sanity/ui"), react = require("react"), _sanity_icons_Clipboard = require("@sanity/icons/Clipboard"), _sanity_icons_Close = require("@sanity/icons/Close"), _sanity_icons_Reset = require("@sanity/icons/Reset"), react_jsx_runtime = require("react/jsx-runtime"), _sanity_icons_ColorWheel = require("@sanity/icons/ColorWheel");
4
- /** @internal */
5
- const ThemerContext = (0, react.createContext)(null);
6
- /** @internal */
7
- function useThemer() {
8
- let context = (0, react.useContext)(ThemerContext);
9
- if (!context) throw Error("useThemer must be used within the `themerTool` plugin");
10
- return context;
11
- }
12
- /** @internal */
13
- const THEMER_FIELDS = [
14
- {
15
- key: "primary",
16
- title: "Primary",
17
- description: "Buttons, focus rings and links",
18
- defaultValue: _sanity_color.color.blue[500].hex
19
- },
20
- {
21
- key: "gray",
22
- title: "Gray",
23
- description: "Neutral surfaces, borders and text",
24
- defaultValue: _sanity_color.color.gray[500].hex
25
- },
26
- {
27
- key: "positive",
28
- title: "Positive",
29
- description: "Success accents",
30
- defaultValue: _sanity_color.color.green[500].hex
31
- },
32
- {
33
- key: "caution",
34
- title: "Caution",
35
- description: "Warning accents",
36
- defaultValue: _sanity_color.color.yellow[500].hex
37
- },
38
- {
39
- key: "critical",
40
- title: "Critical",
41
- description: "Errors and destructive actions",
42
- defaultValue: _sanity_color.color.red[500].hex
43
- },
44
- {
45
- key: "lightest",
46
- title: "Lightest",
47
- description: "Light mode background",
48
- defaultValue: _sanity_color.color.white.hex
49
- },
50
- {
51
- key: "darkest",
52
- title: "Darkest",
53
- description: "Dark mode background",
54
- defaultValue: _sanity_color.color.black.hex
55
- }
56
- ];
57
- /**
58
- * Serializes colors into the `createTheme` call to paste into
59
- * `sanity.config.ts`.
60
- *
61
- * @internal
62
- */
63
- function createThemeSnippet(colors) {
64
- let entries = THEMER_FIELDS.filter(({ key }) => colors[key]).map(({ key }) => ` ${key}: '${colors[key]}',`);
65
- return `import {createTheme} from '@sanity/themer'\n\nexport const theme = ${entries.length === 0 ? "createTheme()" : `createTheme({\n${entries.join("\n")}\n})`}\n`;
66
- }
67
- const swatchStyle = {
68
- width: 33,
69
- height: 33,
70
- padding: 0,
71
- border: "1px solid var(--card-border-color)",
72
- borderRadius: 6,
73
- background: "transparent",
74
- cursor: "pointer",
75
- flex: "none"
76
- };
77
- function sameColors(a, b) {
78
- return THEMER_FIELDS.every(({ key }) => (a[key]?.toLowerCase() ?? void 0) === (b[key]?.toLowerCase() ?? void 0));
79
- }
80
- /** Expands `#abc` to `#aabbcc`, which is the only format `<input type="color">` accepts */
81
- function expandHex(hex) {
82
- return hex.length === 4 ? `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}` : hex;
83
- }
84
- /**
85
- * The themer sidebar: a preset picker and a handful of color pickers that
86
- * generate the previewed theme, plus the `createTheme` snippet to make it
87
- * permanent.
88
- *
89
- * @internal
90
- */
91
- function ThemerSidebar() {
92
- let { baseColors, colors, setColors, setOpen } = useThemer(), toast = (0, _sanity_ui.useToast)(), active = colors ?? baseColors, activePresetSlug = require_presets.t.find((preset) => sameColors(preset.colors, active))?.slug ?? "", snippet = createThemeSnippet(active), handleFieldChange = (key, value) => {
93
- let next = { ...active };
94
- value === void 0 ? delete next[key] : next[key] = value, setColors(next);
95
- }, handlePresetChange = (slug) => {
96
- let preset = require_presets.t.find((candidate) => candidate.slug === slug);
97
- preset && setColors({ ...preset.colors });
98
- }, handleCopy = async () => {
99
- try {
100
- await navigator.clipboard.writeText(snippet), toast.push({
101
- status: "success",
102
- title: "Copied theme to the clipboard"
103
- });
104
- } catch {
105
- toast.push({
106
- status: "error",
107
- title: "Could not copy the theme"
108
- });
109
- }
110
- };
111
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_sanity_ui.Card, {
112
- height: "fill",
113
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_sanity_ui.Flex, {
114
- direction: "column",
115
- height: "fill",
116
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_sanity_ui.Card, {
117
- borderBottom: !0,
118
- padding: 3,
119
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_sanity_ui.Flex, {
120
- align: "center",
121
- gap: 2,
122
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_sanity_ui.Box, {
123
- flex: 1,
124
- paddingLeft: 1,
125
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_sanity_ui.Text, {
126
- size: 1,
127
- weight: "semibold",
128
- children: "Themer"
129
- })
130
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_sanity_ui.Button, {
131
- icon: _sanity_icons_Close.CloseIcon,
132
- mode: "bleed",
133
- onClick: () => setOpen(!1),
134
- padding: 2,
135
- title: "Close themer"
136
- })]
137
- })
138
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_sanity_ui.Box, {
139
- flex: 1,
140
- overflow: "auto",
141
- padding: 4,
142
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_sanity_ui.Stack, {
143
- gap: 5,
144
- children: [
145
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_sanity_ui.Stack, {
146
- gap: 3,
147
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_sanity_ui.Text, {
148
- size: 1,
149
- weight: "medium",
150
- children: "Preset"
151
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_sanity_ui.Select, {
152
- onChange: (event) => handlePresetChange(event.currentTarget.value),
153
- value: activePresetSlug,
154
- children: [activePresetSlug === "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
155
- value: "",
156
- children: "Custom"
157
- }), require_presets.t.map((preset) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
158
- value: preset.slug,
159
- children: preset.title
160
- }, preset.slug))]
161
- })]
162
- }),
163
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_sanity_ui.Stack, {
164
- gap: 4,
165
- children: THEMER_FIELDS.map((field) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ColorField, {
166
- field,
167
- onChange: handleFieldChange,
168
- value: active[field.key]
169
- }, field.key))
170
- }),
171
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_sanity_ui.Stack, {
172
- gap: 3,
173
- children: [
174
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_sanity_ui.Text, {
175
- size: 1,
176
- weight: "medium",
177
- children: "Add to your config"
178
- }),
179
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_sanity_ui.Card, {
180
- border: !0,
181
- overflow: "auto",
182
- padding: 3,
183
- radius: 2,
184
- tone: "transparent",
185
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_sanity_ui.Code, {
186
- language: "ts",
187
- size: 0,
188
- children: snippet
189
- })
190
- }),
191
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_sanity_ui.Flex, {
192
- gap: 2,
193
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_sanity_ui.Button, {
194
- icon: _sanity_icons_Clipboard.ClipboardIcon,
195
- mode: "ghost",
196
- onClick: () => void handleCopy(),
197
- text: "Copy"
198
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_sanity_ui.Button, {
199
- disabled: colors === null,
200
- icon: _sanity_icons_Reset.ResetIcon,
201
- mode: "ghost",
202
- onClick: () => setColors(null),
203
- text: "Reset",
204
- tone: "critical"
205
- })]
206
- })
207
- ]
208
- })
209
- ]
210
- })
211
- })]
212
- })
213
- });
214
- }
215
- function ColorField(props) {
216
- let { field, value, onChange } = props;
217
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_sanity_ui.Flex, {
218
- align: "center",
219
- gap: 3,
220
- children: [
221
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_sanity_ui.Stack, {
222
- flex: 1,
223
- gap: 2,
224
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_sanity_ui.Text, {
225
- size: 1,
226
- weight: "medium",
227
- children: field.title
228
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_sanity_ui.Text, {
229
- muted: !0,
230
- size: 0,
231
- children: value ?? field.description
232
- })]
233
- }),
234
- value !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_sanity_ui.Button, {
235
- icon: _sanity_icons_Close.CloseIcon,
236
- mode: "bleed",
237
- onClick: () => onChange(field.key, void 0),
238
- padding: 2,
239
- title: `Reset ${field.title}`
240
- }),
241
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
242
- "aria-label": `${field.title} color`,
243
- onChange: (event) => onChange(field.key, event.currentTarget.value),
244
- style: swatchStyle,
245
- type: "color",
246
- value: expandHex(value ?? field.defaultValue)
247
- })
248
- ]
249
- });
250
- }
251
- const sidebarStyle = {
252
- width: 360,
253
- flex: "none",
254
- borderLeft: "1px solid var(--card-border-color)",
255
- boxSizing: "border-box",
256
- overflow: "hidden"
257
- };
258
- /**
259
- * Renders the themer sidebar next to the active tool, so the user can browse
260
- * around their own studio while tweaking the theme.
261
- *
262
- * @internal
263
- */
264
- function ThemerActiveToolLayout(props) {
265
- let { open } = useThemer();
266
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_sanity_ui.Flex, {
267
- height: "fill",
268
- sizing: "border",
269
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_sanity_ui.Box, {
270
- flex: 1,
271
- height: "fill",
272
- overflow: "auto",
273
- children: props.renderDefault(props)
274
- }), open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_sanity_ui.Layer, {
275
- height: "fill",
276
- style: sidebarStyle,
277
- zOffset: 100,
278
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThemerSidebar, {})
279
- })]
280
- });
281
- }
282
- const STORAGE_KEY = "sanityStudio:themer:colors";
283
- /**
284
- * Restores draft colors from localStorage, so theme drafts survive studio
285
- * reloads.
286
- *
287
- * @internal
288
- */
289
- function readStoredColors() {
290
- try {
291
- if (typeof localStorage > "u") return null;
292
- let raw = localStorage.getItem(STORAGE_KEY);
293
- if (!raw) return null;
294
- let parsed = JSON.parse(raw);
295
- if (!parsed || typeof parsed != "object") return null;
296
- let colors = {};
297
- for (let { key } of THEMER_FIELDS) {
298
- let value = Reflect.get(parsed, key);
299
- typeof value == "string" && require_mix.t(value) && (colors[key] = value);
300
- }
301
- return colors;
302
- } catch {
303
- return null;
304
- }
305
- }
306
- /** @internal */
307
- function writeStoredColors(colors) {
308
- try {
309
- if (typeof localStorage > "u") return;
310
- colors === null ? localStorage.removeItem(STORAGE_KEY) : localStorage.setItem(STORAGE_KEY, JSON.stringify(colors));
311
- } catch {}
312
- }
313
- /**
314
- * Wraps the whole Studio so that draft themes generated by the themer sidebar
315
- * apply everywhere while the user browses around, and hosts the state that the
316
- * navbar toggle and the sidebar share.
317
- *
318
- * The draft theme provider inherits the color scheme from the Studio, so the
319
- * preview follows the appearance setting (light/dark/system) like any other
320
- * theme.
321
- *
322
- * @internal
323
- */
324
- function ThemerLayout(props) {
325
- let { baseColors, ...layoutProps } = props, [open, setOpen] = (0, react.useState)(!1), [colors, setColors] = (0, react.useState)(readStoredColors);
326
- (0, react.useEffect)(() => writeStoredColors(colors), [colors]);
327
- let theme = (0, react.useMemo)(() => colors === null ? null : require_presets.n({
328
- ...baseColors,
329
- ...colors
330
- }), [baseColors, colors]), context = (0, react.useMemo)(() => ({
331
- baseColors,
332
- colors,
333
- setColors,
334
- open,
335
- setOpen
336
- }), [
337
- baseColors,
338
- colors,
339
- open
340
- ]);
341
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThemerContext.Provider, {
342
- value: context,
343
- children: theme === null ? layoutProps.renderDefault(layoutProps) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_sanity_ui.ThemeProvider, {
344
- theme,
345
- children: layoutProps.renderDefault(layoutProps)
346
- })
347
- });
348
- }
349
- /**
350
- * Adds the toggle that opens and closes the themer sidebar to the Studio
351
- * navbar.
352
- *
353
- * @internal
354
- */
355
- function ThemerNavbar(props) {
356
- let { open, setOpen } = useThemer();
357
- return props.renderDefault({
358
- ...props,
359
- __internal_actions: [...props.__internal_actions ?? [], {
360
- icon: _sanity_icons_ColorWheel.ColorWheelIcon,
361
- location: "topbar",
362
- name: "themer",
363
- onAction: () => setOpen(!open),
364
- selected: open,
365
- title: "Themer"
366
- }]
367
- });
368
- }
369
- /**
370
- * A Studio plugin that adds a themer sidebar for generating Studio themes:
371
- * a navbar toggle opens the sidebar next to the active tool, where presets
372
- * and color pickers preview a `createTheme` theme live on the whole Studio
373
- * while you browse around. Toggle between light and dark mode with the
374
- * regular appearance menu — the preview follows it.
375
- *
376
- * ```ts
377
- * import {themerTool} from '@sanity/themer/tool'
378
- * import {defineConfig} from 'sanity'
379
- *
380
- * export default defineConfig({
381
- * plugins: [themerTool()],
382
- * // ...rest of the config
383
- * })
384
- * ```
385
- *
386
- * @public
387
- */
388
- const themerTool = (0, sanity.definePlugin)((options) => {
389
- let baseColors = options?.colors ?? {};
390
- function ThemerLayoutWithOptions(props) {
391
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThemerLayout, {
392
- ...props,
393
- baseColors
394
- });
395
- }
396
- return {
397
- name: "@sanity/themer/tool",
398
- studio: { components: {
399
- layout: ThemerLayoutWithOptions,
400
- navbar: ThemerNavbar,
401
- activeToolLayout: ThemerActiveToolLayout
402
- } }
403
- };
404
- });
405
- exports.themerTool = themerTool;
406
-
407
- //# sourceMappingURL=tool.cjs.map
package/dist/tool.cjs.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"tool.cjs","names":["color","presets","Card","Flex","Box","Text","Button","CloseIcon","Stack","Select","Code","ClipboardIcon","ResetIcon","Flex","Box","Layer","isColor","createTheme","ThemeProvider","ColorWheelIcon"],"sources":["../src/tool/context.ts","../src/tool/fields.ts","../src/tool/snippet.ts","../src/tool/ThemerSidebar.tsx","../src/tool/ThemerActiveToolLayout.tsx","../src/tool/storage.ts","../src/tool/ThemerLayout.tsx","../src/tool/ThemerNavbar.tsx","../src/tool/plugin.tsx"],"sourcesContent":["import {createContext, useContext} from 'react'\n\nimport {CreateThemeOptions} from '../types'\n\n/** @internal */\nexport interface ThemerContextValue {\n /** The colors the Studio's configured theme was generated from */\n baseColors: CreateThemeOptions\n /** The draft colors, or `null` when the configured theme is untouched */\n colors: CreateThemeOptions | null\n setColors: (colors: CreateThemeOptions | null) => void\n /** Whether the themer sidebar is open */\n open: boolean\n setOpen: (open: boolean) => void\n}\n\n/** @internal */\nexport const ThemerContext = createContext<ThemerContextValue | null>(null)\n\n/** @internal */\nexport function useThemer(): ThemerContextValue {\n const context = useContext(ThemerContext)\n\n if (!context) {\n throw new Error('useThemer must be used within the `themerTool` plugin')\n }\n\n return context\n}\n","import {color} from '@sanity/color'\n\nimport {CreateThemeOptions} from '../types'\n\n/** @internal */\nexport interface ThemerField {\n key: keyof CreateThemeOptions\n title: string\n description: string\n /** The color the picker shows while the field is unset (6-digit hex) */\n defaultValue: string\n}\n\n/** @internal */\nexport const THEMER_FIELDS: ThemerField[] = [\n {\n key: 'primary',\n title: 'Primary',\n description: 'Buttons, focus rings and links',\n defaultValue: color.blue[500].hex,\n },\n {\n key: 'gray',\n title: 'Gray',\n description: 'Neutral surfaces, borders and text',\n defaultValue: color.gray[500].hex,\n },\n {\n key: 'positive',\n title: 'Positive',\n description: 'Success accents',\n defaultValue: color.green[500].hex,\n },\n {\n key: 'caution',\n title: 'Caution',\n description: 'Warning accents',\n defaultValue: color.yellow[500].hex,\n },\n {\n key: 'critical',\n title: 'Critical',\n description: 'Errors and destructive actions',\n defaultValue: color.red[500].hex,\n },\n {\n key: 'lightest',\n title: 'Lightest',\n description: 'Light mode background',\n defaultValue: color.white.hex,\n },\n {\n key: 'darkest',\n title: 'Darkest',\n description: 'Dark mode background',\n defaultValue: color.black.hex,\n },\n]\n","import {CreateThemeOptions} from '../types'\nimport {THEMER_FIELDS} from './fields'\n\n/**\n * Serializes colors into the `createTheme` call to paste into\n * `sanity.config.ts`.\n *\n * @internal\n */\nexport function createThemeSnippet(colors: CreateThemeOptions): string {\n const entries = THEMER_FIELDS.filter(({key}) => colors[key]).map(\n ({key}) => ` ${key}: '${colors[key]}',`,\n )\n\n const call = entries.length === 0 ? 'createTheme()' : `createTheme({\\n${entries.join('\\n')}\\n})`\n\n return `import {createTheme} from '@sanity/themer'\\n\\nexport const theme = ${call}\\n`\n}\n","import {ClipboardIcon} from '@sanity/icons/Clipboard'\nimport {CloseIcon} from '@sanity/icons/Close'\nimport {ResetIcon} from '@sanity/icons/Reset'\nimport {Box, Button, Card, Code, Flex, Select, Stack, Text, useToast} from '@sanity/ui'\n\nimport {presets} from '../presets'\nimport {CreateThemeOptions} from '../types'\nimport {useThemer} from './context'\nimport {THEMER_FIELDS, ThemerField} from './fields'\nimport {createThemeSnippet} from './snippet'\n\nconst swatchStyle: React.CSSProperties = {\n width: 33,\n height: 33,\n padding: 0,\n border: '1px solid var(--card-border-color)',\n borderRadius: 6,\n background: 'transparent',\n cursor: 'pointer',\n flex: 'none',\n}\n\nfunction sameColors(a: CreateThemeOptions, b: CreateThemeOptions): boolean {\n return THEMER_FIELDS.every(\n ({key}) => (a[key]?.toLowerCase() ?? undefined) === (b[key]?.toLowerCase() ?? undefined),\n )\n}\n\n/** Expands `#abc` to `#aabbcc`, which is the only format `<input type=\"color\">` accepts */\nfunction expandHex(hex: string): string {\n if (hex.length === 4) {\n return `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}`\n }\n\n return hex\n}\n\n/**\n * The themer sidebar: a preset picker and a handful of color pickers that\n * generate the previewed theme, plus the `createTheme` snippet to make it\n * permanent.\n *\n * @internal\n */\nexport function ThemerSidebar() {\n const {baseColors, colors, setColors, setOpen} = useThemer()\n const toast = useToast()\n\n const active = colors ?? baseColors\n const activePresetSlug = presets.find((preset) => sameColors(preset.colors, active))?.slug ?? ''\n const snippet = createThemeSnippet(active)\n\n const handleFieldChange = (key: keyof CreateThemeOptions, value: string | undefined) => {\n const next = {...active}\n\n if (value === undefined) {\n delete next[key]\n } else {\n next[key] = value\n }\n\n setColors(next)\n }\n\n const handlePresetChange = (slug: string) => {\n const preset = presets.find((candidate) => candidate.slug === slug)\n\n if (preset) {\n setColors({...preset.colors})\n }\n }\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(snippet)\n toast.push({status: 'success', title: 'Copied theme to the clipboard'})\n } catch {\n toast.push({status: 'error', title: 'Could not copy the theme'})\n }\n }\n\n return (\n <Card height=\"fill\">\n <Flex direction=\"column\" height=\"fill\">\n <Card borderBottom padding={3}>\n <Flex align=\"center\" gap={2}>\n <Box flex={1} paddingLeft={1}>\n <Text size={1} weight=\"semibold\">\n Themer\n </Text>\n </Box>\n <Button\n icon={CloseIcon}\n mode=\"bleed\"\n onClick={() => setOpen(false)}\n padding={2}\n title=\"Close themer\"\n />\n </Flex>\n </Card>\n\n <Box flex={1} overflow=\"auto\" padding={4}>\n <Stack gap={5}>\n <Stack gap={3}>\n <Text size={1} weight=\"medium\">\n Preset\n </Text>\n <Select\n onChange={(event) => handlePresetChange(event.currentTarget.value)}\n value={activePresetSlug}\n >\n {activePresetSlug === '' && <option value=\"\">Custom</option>}\n {presets.map((preset) => (\n <option key={preset.slug} value={preset.slug}>\n {preset.title}\n </option>\n ))}\n </Select>\n </Stack>\n\n <Stack gap={4}>\n {THEMER_FIELDS.map((field) => (\n <ColorField\n field={field}\n key={field.key}\n onChange={handleFieldChange}\n value={active[field.key]}\n />\n ))}\n </Stack>\n\n <Stack gap={3}>\n <Text size={1} weight=\"medium\">\n Add to your config\n </Text>\n <Card border overflow=\"auto\" padding={3} radius={2} tone=\"transparent\">\n <Code language=\"ts\" size={0}>\n {snippet}\n </Code>\n </Card>\n <Flex gap={2}>\n <Button\n icon={ClipboardIcon}\n mode=\"ghost\"\n onClick={() => void handleCopy()}\n text=\"Copy\"\n />\n <Button\n disabled={colors === null}\n icon={ResetIcon}\n mode=\"ghost\"\n onClick={() => setColors(null)}\n text=\"Reset\"\n tone=\"critical\"\n />\n </Flex>\n </Stack>\n </Stack>\n </Box>\n </Flex>\n </Card>\n )\n}\n\nfunction ColorField(props: {\n field: ThemerField\n value: string | undefined\n onChange: (key: keyof CreateThemeOptions, value: string | undefined) => void\n}) {\n const {field, value, onChange} = props\n\n return (\n <Flex align=\"center\" gap={3}>\n <Stack flex={1} gap={2}>\n <Text size={1} weight=\"medium\">\n {field.title}\n </Text>\n <Text muted size={0}>\n {value ?? field.description}\n </Text>\n </Stack>\n {value !== undefined && (\n <Button\n icon={CloseIcon}\n mode=\"bleed\"\n onClick={() => onChange(field.key, undefined)}\n padding={2}\n title={`Reset ${field.title}`}\n />\n )}\n <input\n aria-label={`${field.title} color`}\n onChange={(event) => onChange(field.key, event.currentTarget.value)}\n style={swatchStyle}\n type=\"color\"\n value={expandHex(value ?? field.defaultValue)}\n />\n </Flex>\n )\n}\n","import {Box, Flex, Layer} from '@sanity/ui'\nimport {type ActiveToolLayoutProps} from 'sanity'\n\nimport {useThemer} from './context'\nimport {ThemerSidebar} from './ThemerSidebar'\n\nconst sidebarStyle: React.CSSProperties = {\n width: 360,\n flex: 'none',\n borderLeft: '1px solid var(--card-border-color)',\n boxSizing: 'border-box',\n overflow: 'hidden',\n}\n\n/**\n * Renders the themer sidebar next to the active tool, so the user can browse\n * around their own studio while tweaking the theme.\n *\n * @internal\n */\nexport function ThemerActiveToolLayout(props: ActiveToolLayoutProps) {\n const {open} = useThemer()\n\n return (\n <Flex height=\"fill\" sizing=\"border\">\n <Box flex={1} height=\"fill\" overflow=\"auto\">\n {props.renderDefault(props)}\n </Box>\n\n {open && (\n <Layer height=\"fill\" style={sidebarStyle} zOffset={100}>\n <ThemerSidebar />\n </Layer>\n )}\n </Flex>\n )\n}\n","import {isColor} from '../lib/mix'\nimport {CreateThemeOptions} from '../types'\nimport {THEMER_FIELDS} from './fields'\n\nconst STORAGE_KEY = 'sanityStudio:themer:colors'\n\n/**\n * Restores draft colors from localStorage, so theme drafts survive studio\n * reloads.\n *\n * @internal\n */\nexport function readStoredColors(): CreateThemeOptions | null {\n try {\n if (typeof localStorage === 'undefined') return null\n\n const raw = localStorage.getItem(STORAGE_KEY)\n\n if (!raw) return null\n\n const parsed: unknown = JSON.parse(raw)\n\n if (!parsed || typeof parsed !== 'object') return null\n\n const colors: CreateThemeOptions = {}\n\n for (const {key} of THEMER_FIELDS) {\n const value: unknown = Reflect.get(parsed, key)\n\n if (typeof value === 'string' && isColor(value)) {\n colors[key] = value\n }\n }\n\n return colors\n } catch {\n return null\n }\n}\n\n/** @internal */\nexport function writeStoredColors(colors: CreateThemeOptions | null): void {\n try {\n if (typeof localStorage === 'undefined') return\n\n if (colors === null) {\n localStorage.removeItem(STORAGE_KEY)\n } else {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(colors))\n }\n } catch {\n // Storage can be unavailable (e.g. private browsing) — drafts just won't persist\n }\n}\n","import {ThemeProvider} from '@sanity/ui'\nimport {useEffect, useMemo, useState} from 'react'\nimport {type LayoutProps} from 'sanity'\n\nimport {createTheme} from '../createTheme'\nimport {CreateThemeOptions} from '../types'\nimport {ThemerContext, ThemerContextValue} from './context'\nimport {readStoredColors, writeStoredColors} from './storage'\n\n/**\n * Wraps the whole Studio so that draft themes generated by the themer sidebar\n * apply everywhere while the user browses around, and hosts the state that the\n * navbar toggle and the sidebar share.\n *\n * The draft theme provider inherits the color scheme from the Studio, so the\n * preview follows the appearance setting (light/dark/system) like any other\n * theme.\n *\n * @internal\n */\nexport function ThemerLayout(props: LayoutProps & {baseColors: CreateThemeOptions}) {\n const {baseColors, ...layoutProps} = props\n const [open, setOpen] = useState(false)\n const [colors, setColors] = useState<CreateThemeOptions | null>(readStoredColors)\n\n useEffect(() => writeStoredColors(colors), [colors])\n\n // The theme identity must be stable between renders: it feeds the\n // styled-components theme context for the whole Studio, and rebuilding it\n // would re-render everything\n const theme = useMemo(\n () => (colors === null ? null : createTheme({...baseColors, ...colors})),\n [baseColors, colors],\n )\n\n const context = useMemo<ThemerContextValue>(\n () => ({baseColors, colors, setColors, open, setOpen}),\n [baseColors, colors, open],\n )\n\n return (\n <ThemerContext.Provider value={context}>\n {theme === null ? (\n layoutProps.renderDefault(layoutProps)\n ) : (\n <ThemeProvider theme={theme}>{layoutProps.renderDefault(layoutProps)}</ThemeProvider>\n )}\n </ThemerContext.Provider>\n )\n}\n","import {ColorWheelIcon} from '@sanity/icons/ColorWheel'\nimport {type NavbarProps} from 'sanity'\n\nimport {useThemer} from './context'\n\n/**\n * Adds the toggle that opens and closes the themer sidebar to the Studio\n * navbar.\n *\n * @internal\n */\nexport function ThemerNavbar(props: NavbarProps) {\n const {open, setOpen} = useThemer()\n\n return props.renderDefault({\n ...props,\n __internal_actions: [\n ...(props.__internal_actions ?? []),\n {\n icon: ColorWheelIcon,\n location: 'topbar',\n name: 'themer',\n onAction: () => setOpen(!open),\n selected: open,\n title: 'Themer',\n },\n ],\n })\n}\n","import {definePlugin, type LayoutProps} from 'sanity'\n\nimport {CreateThemeOptions} from '../types'\nimport {ThemerActiveToolLayout} from './ThemerActiveToolLayout'\nimport {ThemerLayout} from './ThemerLayout'\nimport {ThemerNavbar} from './ThemerNavbar'\n\n/**\n * Options for the {@link themerTool} plugin.\n *\n * @public\n */\nexport interface ThemerToolOptions {\n /**\n * The colors that the Studio's configured theme was generated from — the\n * themer starts editing from these, so pass the same object that the\n * `theme` in the Studio config uses:\n *\n * ```ts\n * const colors = {primary: '#2276fc'}\n *\n * export default defineConfig({\n * theme: createTheme(colors),\n * plugins: [themerTool({colors})],\n * })\n * ```\n */\n colors?: CreateThemeOptions\n}\n\n/**\n * A Studio plugin that adds a themer sidebar for generating Studio themes:\n * a navbar toggle opens the sidebar next to the active tool, where presets\n * and color pickers preview a `createTheme` theme live on the whole Studio\n * while you browse around. Toggle between light and dark mode with the\n * regular appearance menu — the preview follows it.\n *\n * ```ts\n * import {themerTool} from '@sanity/themer/tool'\n * import {defineConfig} from 'sanity'\n *\n * export default defineConfig({\n * plugins: [themerTool()],\n * // ...rest of the config\n * })\n * ```\n *\n * @public\n */\nexport const themerTool = definePlugin<ThemerToolOptions | void>((options) => {\n const baseColors: CreateThemeOptions = options?.colors ?? {}\n\n function ThemerLayoutWithOptions(props: LayoutProps) {\n return <ThemerLayout {...props} baseColors={baseColors} />\n }\n\n return {\n name: '@sanity/themer/tool',\n studio: {\n components: {\n layout: ThemerLayoutWithOptions,\n navbar: ThemerNavbar,\n activeToolLayout: ThemerActiveToolLayout,\n },\n },\n }\n})\n"],"mappings":"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"}
package/dist/tool.d.cts DELETED
@@ -1,45 +0,0 @@
1
- import { t as CreateThemeOptions } from "./_chunks/types.cjs";
2
- /**
3
- * Options for the {@link themerTool} plugin.
4
- *
5
- * @public
6
- */
7
- interface ThemerToolOptions {
8
- /**
9
- * The colors that the Studio's configured theme was generated from — the
10
- * themer starts editing from these, so pass the same object that the
11
- * `theme` in the Studio config uses:
12
- *
13
- * ```ts
14
- * const colors = {primary: '#2276fc'}
15
- *
16
- * export default defineConfig({
17
- * theme: createTheme(colors),
18
- * plugins: [themerTool({colors})],
19
- * })
20
- * ```
21
- */
22
- colors?: CreateThemeOptions;
23
- }
24
- /**
25
- * A Studio plugin that adds a themer sidebar for generating Studio themes:
26
- * a navbar toggle opens the sidebar next to the active tool, where presets
27
- * and color pickers preview a `createTheme` theme live on the whole Studio
28
- * while you browse around. Toggle between light and dark mode with the
29
- * regular appearance menu — the preview follows it.
30
- *
31
- * ```ts
32
- * import {themerTool} from '@sanity/themer/tool'
33
- * import {defineConfig} from 'sanity'
34
- *
35
- * export default defineConfig({
36
- * plugins: [themerTool()],
37
- * // ...rest of the config
38
- * })
39
- * ```
40
- *
41
- * @public
42
- */
43
- declare const themerTool: import("sanity").Plugin<void | ThemerToolOptions>;
44
- export { type ThemerToolOptions, themerTool };
45
- //# sourceMappingURL=tool.d.cts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tool.d.cts","names":[],"sources":["../src/tool/plugin.tsx"],"mappings":";;;;;;UAYiB;;;;;;;;;;;;;;;EAef,SAAS;;;;;;;;;;;;;;;;;;;;;cAsBE,6BAAU,cAAA"}