@sanity/themer 0.4.0 → 0.6.1

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.js CHANGED
@@ -1,13 +1,17 @@
1
+ import "@sanity/themer/bundle.css";
1
2
  import { a as DEFAULT_BACKGROUND, c as resolveThemeOptions, d as hslToHex, f as relativeLuminance, i as DEFAULT_ACCENT, l as isColor, n as buildTheme, o as SCHEMES, r as buildPalette, s as deriveTextColor, t as presets, u as hexToHsl } from "./presets-CqBgS3A-.js";
2
- import { c } from "react-compiler-runtime";
3
+ import { c } from "react/compiler-runtime";
3
4
  import { definePlugin, useColorSchemeValue } from "sanity";
4
- import { Badge, Box, Button, Card, Dialog, Flex, Layer, Stack, Text, TextInput, ThemeProvider, useTheme_v2 } from "@sanity/ui";
5
- import { createContext, useContext, useEffect, useRef, useState } from "react";
6
- import { styled } from "styled-components";
5
+ import { Badge, Box, Button, Card, Dialog, Flex, Layer, Stack, Text, TextInput, ThemeProvider, useMediaIndex, useRootTheme, useTheme_v2 } from "@sanity/ui";
6
+ import { useActor, useSelector } from "@xstate/react";
7
+ import { Activity, ViewTransition, addTransitionType, createContext, startTransition, useContext, useEffect, useRef, useState } from "react";
8
+ import { assign, not, setup, stateIn } from "xstate";
7
9
  import { ArrowLeftIcon } from "@sanity/icons/ArrowLeft";
8
10
  import { CloseIcon } from "@sanity/icons/Close";
9
11
  import { CodeBlockIcon } from "@sanity/icons/CodeBlock";
12
+ import { SplitVerticalIcon } from "@sanity/icons/SplitVertical";
10
13
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
14
+ import { assignInlineVars } from "@vanilla-extract/dynamic";
11
15
  import { ResetIcon } from "@sanity/icons/Reset";
12
16
  import { TrashIcon } from "@sanity/icons/Trash";
13
17
  import { SparklesIcon } from "@sanity/icons/Sparkles";
@@ -16,16 +20,18 @@ import { ImageIcon } from "@sanity/icons/Image";
16
20
  import { useToast } from "@sanity/ui/toast";
17
21
  import { AddIcon } from "@sanity/icons/Add";
18
22
  import { RestoreIcon } from "@sanity/icons/Restore";
23
+ import { MotionConfig, Reorder, useDragControls } from "motion/react";
24
+ import { ArrowDownIcon } from "@sanity/icons/ArrowDown";
25
+ import { ArrowUpIcon } from "@sanity/icons/ArrowUp";
19
26
  import { CopyIcon } from "@sanity/icons/Copy";
20
27
  import { EditIcon } from "@sanity/icons/Edit";
21
28
  import { EllipsisHorizontalIcon } from "@sanity/icons/EllipsisHorizontal";
22
29
  import { Menu, MenuButton, MenuDivider, MenuItem } from "@sanity/ui/menu";
30
+ import scrollIntoView from "scroll-into-view-if-needed";
23
31
  import { ClipboardIcon } from "@sanity/icons/Clipboard";
24
32
  import { Code } from "@sanity/ui/code";
25
33
  import { registerLanguage } from "react-refractor";
26
34
  import typescript from "refractor/typescript";
27
- import { useActor, useSelector } from "@xstate/react";
28
- import { assign, not, setup } from "xstate";
29
35
  import { ColorWheelIcon } from "@sanity/icons/ColorWheel";
30
36
  /** @internal */
31
37
  const ThemerContext = createContext(null);
@@ -35,41 +41,6 @@ function useThemer() {
35
41
  if (!context) throw Error("useThemer must be used within the `themerTool` plugin");
36
42
  return context;
37
43
  }
38
- const Root$2 = styled(Box).withConfig({
39
- displayName: "Root",
40
- componentId: "sc-6zqwg0-0"
41
- })`scrollbar-gutter:stable;`;
42
- /**
43
- * The scrolling body of a sidebar flow. It always reserves the scrollbar's
44
- * space, so the content does not shift when the list grows or shrinks past
45
- * the point where it needs to scroll — and it takes that space out of its
46
- * right padding, so the content stays centered rather than hugging the left.
47
- * With overlay scrollbars there is no gutter and the padding stays even.
48
- *
49
- * @internal
50
- */
51
- function ScrollArea(props) {
52
- let $ = c(8), { children, padding } = props, { space } = useTheme_v2(), ref = useRef(null), [gutter, setGutter] = useState(0), t0, t1;
53
- $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = () => {
54
- let element = ref.current;
55
- if (!element) return;
56
- let measure = () => setGutter(element.offsetWidth - element.clientWidth);
57
- measure();
58
- let observer = new ResizeObserver(measure);
59
- return observer.observe(element), () => observer.disconnect();
60
- }, t1 = [], $[0] = t0, $[1] = t1) : (t0 = $[0], t1 = $[1]), useEffect(t0, t1);
61
- let t2 = Math.max(0, space[padding] - gutter), t3;
62
- $[2] === t2 ? t3 = $[3] : (t3 = { paddingRight: t2 }, $[2] = t2, $[3] = t3);
63
- let t4;
64
- return $[4] !== children || $[5] !== padding || $[6] !== t3 ? (t4 = /* @__PURE__ */ jsx(Root$2, {
65
- flex: 1,
66
- overflow: "auto",
67
- padding,
68
- ref,
69
- style: t3,
70
- children
71
- }), $[4] = children, $[5] = padding, $[6] = t3, $[7] = t4) : t4 = $[7], t4;
72
- }
73
44
  /**
74
45
  * Reduces theme options to the minimal object that recreates them through
75
46
  * `buildTheme`: in each scheme the accent is dropped when it is the stock
@@ -106,14 +77,17 @@ function sameScheme(a, b) {
106
77
  const initialThemerState = {
107
78
  active: null,
108
79
  custom: [],
109
- removed: []
80
+ removed: [],
81
+ order: []
110
82
  };
111
83
  /**
112
84
  * Resolves the list of themes: the configured theme first, then the presets
113
85
  * (minus the ones that would only repeat the configured theme), then the
114
- * user's own themes. Removed themes are set aside so they can be restored,
115
- * and the active theme falls back to the configured one when its slug no
116
- * longer resolves.
86
+ * user's own themes — rearranged into the order the user dragged them into,
87
+ * with themes that order does not know about kept in that default order after
88
+ * the ones it does. Removed themes are set aside so they can be restored, and
89
+ * the active theme falls back to the configured one when its slug no longer
90
+ * resolves.
117
91
  *
118
92
  * @internal
119
93
  */
@@ -137,6 +111,8 @@ function resolveThemes(state, baseOptions) {
137
111
  source: "custom",
138
112
  ...theme.palette ? { palette: theme.palette } : {}
139
113
  });
114
+ let position = new Map(state.order.map((slug, index) => [slug, index])), rank = (theme) => position.get(theme.slug) ?? state.order.length;
115
+ all.sort((a, b) => rank(a) - rank(b));
140
116
  let removedSlugs = new Set(state.removed), themes = all.filter((theme) => !removedSlugs.has(theme.slug));
141
117
  return {
142
118
  themes,
@@ -169,15 +145,338 @@ function displayTitle(title) {
169
145
  function randomId() {
170
146
  return typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`;
171
147
  }
148
+ function themesOf(context) {
149
+ return resolveThemes(context, context.baseOptions);
150
+ }
151
+ /**
152
+ * The state of the themer tool: three parallel regions, whether the
153
+ * `sidebar` is open, which `flow` it is in — picking a theme from the `list`,
154
+ * `edit`ing one of the user's own themes, or restoring `removed` ones — and
155
+ * whether the `preview` shows the Studio once (`single`) or in light and dark
156
+ * side by side (`split`). The context carries the persisted state (the
157
+ * applied theme, the user's themes and what was removed) alongside what the
158
+ * flows need.
159
+ *
160
+ * Theme operations are handled in every flow, and the flows leave on their
161
+ * own when they lose their subject: the editor when its theme is removed or
162
+ * deleted, and the removed view when its last theme is restored or deleted.
163
+ *
164
+ * @internal
165
+ */
166
+ const themerMachine = setup({
167
+ types: {
168
+ context: {},
169
+ events: {},
170
+ input: {}
171
+ },
172
+ guards: {
173
+ isCustomTheme: ({ context }, params) => themesOf(context).themes.some((theme) => theme.slug === params.slug && theme.source === "custom"),
174
+ isEditingListedTheme: ({ context }) => context.editing !== null && themesOf(context).themes.some((theme) => theme.slug === context.editing?.slug && theme.source === "custom"),
175
+ hasRemovedThemes: ({ context }) => themesOf(context).removed.length > 0
176
+ },
177
+ actions: {
178
+ pick: assign((_, params) => ({ active: params.slug === "config" ? null : params.slug })),
179
+ add: assign(({ context }, params) => {
180
+ let theme = createCustomTheme(params.title ?? "Untitled theme", params.options ?? themesOf(context).active.options, params.palette);
181
+ return {
182
+ active: theme.slug,
183
+ custom: [...context.custom, theme],
184
+ editing: {
185
+ slug: theme.slug,
186
+ focusTitle: params.title === void 0
187
+ },
188
+ images: params.imageUrl ? {
189
+ ...context.images,
190
+ [theme.slug]: params.imageUrl
191
+ } : context.images
192
+ };
193
+ }),
194
+ duplicate: assign(({ context }, params) => {
195
+ let { themes, removed } = themesOf(context), source = [...themes, ...removed].find((theme) => theme.slug === params.slug);
196
+ if (!source) return {};
197
+ let theme = createCustomTheme(duplicateTitle(source.title), source.options, source.palette);
198
+ return {
199
+ active: theme.slug,
200
+ custom: [...context.custom, theme],
201
+ editing: {
202
+ slug: theme.slug,
203
+ focusTitle: !0
204
+ }
205
+ };
206
+ }),
207
+ startEditing: assign((_, params) => ({
208
+ active: params.slug,
209
+ editing: {
210
+ slug: params.slug,
211
+ focusTitle: !1
212
+ }
213
+ })),
214
+ stopEditing: assign({ editing: null }),
215
+ update: assign(({ context }, params) => ({
216
+ custom: context.custom.map((theme) => theme.slug === params.slug ? {
217
+ ...theme,
218
+ title: params.title ?? theme.title,
219
+ options: params.options ?? theme.options,
220
+ ...params.palette ? { palette: params.palette } : {}
221
+ } : theme),
222
+ images: params.imageUrl && context.custom.some((theme) => theme.slug === params.slug) ? {
223
+ ...context.images,
224
+ [params.slug]: params.imageUrl
225
+ } : context.images
226
+ })),
227
+ remove: assign(({ context }, params) => params.slug === "config" || context.removed.includes(params.slug) ? {} : {
228
+ active: context.active === params.slug ? null : context.active,
229
+ removed: [...context.removed, params.slug]
230
+ }),
231
+ restore: assign(({ context }, params) => ({ removed: context.removed.filter((slug) => slug !== params.slug) })),
232
+ reorder: assign(({ context }, params) => {
233
+ let listed = new Set(themesOf(context).themes.map((theme) => theme.slug)), order = params.order.filter((slug) => listed.has(slug));
234
+ return { order: [...order, ...context.order.filter((slug) => !order.includes(slug))] };
235
+ }),
236
+ delete: assign(({ context }, params) => {
237
+ if (!context.custom.some((theme) => theme.slug === params.slug)) return {};
238
+ let { [params.slug]: _deleted, ...images } = context.images;
239
+ return {
240
+ active: context.active === params.slug ? null : context.active,
241
+ custom: context.custom.filter((theme) => theme.slug !== params.slug),
242
+ removed: context.removed.filter((slug) => slug !== params.slug),
243
+ images
244
+ };
245
+ })
246
+ }
247
+ }).createMachine({
248
+ id: "themer",
249
+ context: ({ input }) => ({
250
+ ...input.stored,
251
+ baseOptions: input.baseOptions,
252
+ editing: null,
253
+ images: {}
254
+ }),
255
+ type: "parallel",
256
+ states: {
257
+ sidebar: {
258
+ initial: "closed",
259
+ states: {
260
+ closed: { on: { "sidebar.toggle": "open" } },
261
+ open: { on: {
262
+ "sidebar.toggle": "closed",
263
+ "sidebar.close": "closed"
264
+ } }
265
+ }
266
+ },
267
+ preview: {
268
+ initial: "single",
269
+ states: {
270
+ single: { on: { "preview.toggle": "split" } },
271
+ split: { on: {
272
+ "preview.toggle": "single",
273
+ "sidebar.close": "single",
274
+ "sidebar.toggle": {
275
+ guard: stateIn({ sidebar: "open" }),
276
+ target: "single"
277
+ }
278
+ } }
279
+ }
280
+ },
281
+ flow: {
282
+ initial: "list",
283
+ on: {
284
+ "theme.pick": { actions: {
285
+ type: "pick",
286
+ params: ({ event }) => ({ slug: event.slug })
287
+ } },
288
+ "theme.add": {
289
+ target: ".edit",
290
+ actions: {
291
+ type: "add",
292
+ params: ({ event }) => ({
293
+ title: event.title,
294
+ options: event.options,
295
+ palette: event.palette,
296
+ imageUrl: event.imageUrl
297
+ })
298
+ }
299
+ },
300
+ "theme.duplicate": {
301
+ target: ".edit",
302
+ actions: {
303
+ type: "duplicate",
304
+ params: ({ event }) => ({ slug: event.slug })
305
+ }
306
+ },
307
+ "theme.edit": {
308
+ target: ".edit",
309
+ guard: {
310
+ type: "isCustomTheme",
311
+ params: ({ event }) => ({ slug: event.slug })
312
+ },
313
+ actions: {
314
+ type: "startEditing",
315
+ params: ({ event }) => ({ slug: event.slug })
316
+ }
317
+ },
318
+ "theme.update": { actions: {
319
+ type: "update",
320
+ params: ({ event }) => ({
321
+ slug: event.slug,
322
+ title: event.title,
323
+ options: event.options,
324
+ palette: event.palette,
325
+ imageUrl: event.imageUrl
326
+ })
327
+ } },
328
+ "theme.remove": { actions: {
329
+ type: "remove",
330
+ params: ({ event }) => ({ slug: event.slug })
331
+ } },
332
+ "theme.restore": { actions: {
333
+ type: "restore",
334
+ params: ({ event }) => ({ slug: event.slug })
335
+ } },
336
+ "theme.delete": { actions: {
337
+ type: "delete",
338
+ params: ({ event }) => ({ slug: event.slug })
339
+ } },
340
+ "theme.reorder": { actions: {
341
+ type: "reorder",
342
+ params: ({ event }) => ({ order: event.order })
343
+ } },
344
+ "flow.list": ".list",
345
+ "flow.removed": {
346
+ target: ".removed",
347
+ guard: "hasRemovedThemes"
348
+ }
349
+ },
350
+ states: {
351
+ list: {},
352
+ edit: {
353
+ exit: "stopEditing",
354
+ always: {
355
+ guard: not("isEditingListedTheme"),
356
+ target: "list"
357
+ }
358
+ },
359
+ removed: { always: {
360
+ guard: not("hasRemovedThemes"),
361
+ target: "list"
362
+ } }
363
+ }
364
+ }
365
+ }
366
+ });
367
+ /** The part of the machine context that is persisted between sessions @internal */
368
+ function selectStoredState(snapshot) {
369
+ let { active, custom, removed, order } = snapshot.context;
370
+ return {
371
+ active,
372
+ custom,
373
+ removed,
374
+ order
375
+ };
376
+ }
377
+ var root$2 = "_1o50s7t0";
378
+ const ScrollAreaInsetContext = createContext({
379
+ left: 0,
380
+ right: 0,
381
+ bottom: 0
382
+ });
172
383
  /**
173
- * The dark scheme covers the right side of the preview behind a diagonal cut,
174
- * like the "Auto" appearance preview in macOS System Settings shows both
175
- * schemes at once.
384
+ * The gutter the last scroll area measured. It is the same for every scroll
385
+ * area (the reserved gutter does not depend on the content), so the next one
386
+ * starts out with the right padding instead of shifting after its first
387
+ * measurement — which would also throw off anything scrolling into view as
388
+ * the content mounts.
176
389
  */
177
- const Root$1 = styled.div.withConfig({
178
- displayName: "Root",
179
- componentId: "sc-w55yz9-0"
180
- })`position:relative;aspect-ratio:16 / 9;overflow:hidden;`, LIST_ROWS = [
390
+ let lastGutter = 0;
391
+ /**
392
+ * The scrolling body of a sidebar flow. It always reserves the scrollbar's
393
+ * space, so the content does not shift when the list grows or shrinks past
394
+ * the point where it needs to scroll — and it takes that space out of its
395
+ * right padding, so the content stays centered rather than hugging the left.
396
+ * With overlay scrollbars there is no gutter and the padding stays even.
397
+ *
398
+ * @internal
399
+ */
400
+ function ScrollArea(props) {
401
+ let $ = c(15), { children, padding } = props, { space } = useTheme_v2(), ref = useRef(null), [gutter, setGutter] = useState(_temp$7), t0, t1;
402
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = () => {
403
+ let element = ref.current;
404
+ if (!element) return;
405
+ let measure = () => {
406
+ lastGutter = element.offsetWidth - element.clientWidth, setGutter(lastGutter);
407
+ };
408
+ measure();
409
+ let observer = new ResizeObserver(measure);
410
+ return observer.observe(element), () => observer.disconnect();
411
+ }, t1 = [], $[0] = t0, $[1] = t1) : (t0 = $[0], t1 = $[1]), useEffect(t0, t1);
412
+ let t2 = space[padding], t3 = Math.max(0, space[padding] - gutter), t4 = space[padding], t5;
413
+ $[2] !== t2 || $[3] !== t3 || $[4] !== t4 ? (t5 = {
414
+ left: t2,
415
+ right: t3,
416
+ bottom: t4
417
+ }, $[2] = t2, $[3] = t3, $[4] = t4, $[5] = t5) : t5 = $[5];
418
+ let inset = t5, t6;
419
+ $[6] === inset.right ? t6 = $[7] : (t6 = { paddingRight: inset.right }, $[6] = inset.right, $[7] = t6);
420
+ let t7;
421
+ $[8] !== children || $[9] !== inset ? (t7 = /* @__PURE__ */ jsx(ScrollAreaInsetContext.Provider, {
422
+ value: inset,
423
+ children
424
+ }), $[8] = children, $[9] = inset, $[10] = t7) : t7 = $[10];
425
+ let t8;
426
+ return $[11] !== padding || $[12] !== t6 || $[13] !== t7 ? (t8 = /* @__PURE__ */ jsx(Box, {
427
+ className: root$2,
428
+ flex: 1,
429
+ overflow: "auto",
430
+ padding,
431
+ ref,
432
+ style: t6,
433
+ children: t7
434
+ }), $[11] = padding, $[12] = t6, $[13] = t7, $[14] = t8) : t8 = $[14], t8;
435
+ }
436
+ function _temp$7() {
437
+ return lastGutter;
438
+ }
439
+ /**
440
+ * Content that runs edge to edge in a scroll area — up to the scrollbar —
441
+ * instead of sitting inside its padding. It goes last: it runs down to the
442
+ * bottom edge too.
443
+ *
444
+ * @internal
445
+ */
446
+ function ScrollAreaBleed(props) {
447
+ let $ = c(7), { left, right, bottom } = useContext(ScrollAreaInsetContext), t0 = -left, t1 = -right, t2 = -bottom, t3;
448
+ $[0] !== t0 || $[1] !== t1 || $[2] !== t2 ? (t3 = {
449
+ marginLeft: t0,
450
+ marginRight: t1,
451
+ marginBottom: t2
452
+ }, $[0] = t0, $[1] = t1, $[2] = t2, $[3] = t3) : t3 = $[3];
453
+ let t4;
454
+ return $[4] !== props.children || $[5] !== t3 ? (t4 = /* @__PURE__ */ jsx("div", {
455
+ style: t3,
456
+ children: props.children
457
+ }), $[4] = props.children, $[5] = t3, $[6] = t4) : t4 = $[6], t4;
458
+ }
459
+ var avatar = "_1aa9huuh", body = "_1aa9huui", button = "_1aa9huuq", colors = {
460
+ bg: "var(--_1aa9huu0)",
461
+ fg: "var(--_1aa9huu1)",
462
+ mutedFg: "var(--_1aa9huu2)",
463
+ border: "var(--_1aa9huu3)",
464
+ accent: "var(--_1aa9huu4)",
465
+ avatar: "var(--_1aa9huu5)",
466
+ selectedBg: "var(--_1aa9huu6)",
467
+ selectedFg: "var(--_1aa9huu7)",
468
+ inputBg: "var(--_1aa9huu8)",
469
+ inputBorder: "var(--_1aa9huu9)"
470
+ }, field = "_1aa9huun", footer = "_1aa9huup", form = "_1aa9huum", input = "_1aa9huuo", line = {
471
+ fg: "_1aa9huus _1aa9huur",
472
+ muted: "_1aa9huut _1aa9huur",
473
+ selected: "_1aa9huuu _1aa9huur"
474
+ }, list = "_1aa9huuj", listRow = "_1aa9huuk", logo = "_1aa9huuf", navbar = "_1aa9huue", pane = "_1aa9huul", root$1 = "_1aa9huua", spacer = "_1aa9huug", studio = {
475
+ light: "_1aa9huub",
476
+ dark: "_1aa9huud _1aa9huub"
477
+ };
478
+ /** The document rows in the list pane — the widths of their title lines */
479
+ const LIST_ROWS = [
181
480
  "62%",
182
481
  "46%",
183
482
  "70%",
@@ -198,7 +497,7 @@ function ThemePreview(props) {
198
497
  let $ = c(11), { options } = props, t0;
199
498
  $[0] === options ? t0 = $[1] : (t0 = buildTheme(options), $[0] = options, $[1] = t0);
200
499
  let theme = t0, t1;
201
- $[2] === Symbol.for("react.memo_cache_sentinel") ? (t1 = /* @__PURE__ */ jsx(MockStudio, {}), $[2] = t1) : t1 = $[2];
500
+ $[2] === Symbol.for("react.memo_cache_sentinel") ? (t1 = /* @__PURE__ */ jsx(MockStudio, { scheme: "light" }), $[2] = t1) : t1 = $[2];
202
501
  let t2;
203
502
  $[3] === theme ? t2 = $[4] : (t2 = /* @__PURE__ */ jsx(ThemeProvider, {
204
503
  scheme: "light",
@@ -207,7 +506,7 @@ function ThemePreview(props) {
207
506
  children: t1
208
507
  }), $[3] = theme, $[4] = t2);
209
508
  let t3;
210
- $[5] === Symbol.for("react.memo_cache_sentinel") ? (t3 = /* @__PURE__ */ jsx(MockStudio, { style: { clipPath: "polygon(58% 0, 100% 0, 100% 100%, 42% 100%)" } }), $[5] = t3) : t3 = $[5];
509
+ $[5] === Symbol.for("react.memo_cache_sentinel") ? (t3 = /* @__PURE__ */ jsx(MockStudio, { scheme: "dark" }), $[5] = t3) : t3 = $[5];
211
510
  let t4;
212
511
  $[6] === theme ? t4 = $[7] : (t4 = /* @__PURE__ */ jsx(ThemeProvider, {
213
512
  scheme: "dark",
@@ -216,178 +515,91 @@ function ThemePreview(props) {
216
515
  children: t3
217
516
  }), $[6] = theme, $[7] = t4);
218
517
  let t5;
219
- return $[8] !== t2 || $[9] !== t4 ? (t5 = /* @__PURE__ */ jsxs(Root$1, {
518
+ return $[8] !== t2 || $[9] !== t4 ? (t5 = /* @__PURE__ */ jsxs("div", {
220
519
  "aria-hidden": !0,
520
+ className: root$1,
221
521
  children: [t2, t4]
222
522
  }), $[8] = t2, $[9] = t4, $[10] = t5) : t5 = $[10], t5;
223
523
  }
224
524
  function MockStudio(props) {
225
- let $ = c(53), { color } = useTheme_v2(), primary = color.button.default.primary.enabled, selected = color.selectable.default.selected, input = color.input.default.enabled, border = `1px solid ${color.border}`, line = _temp$4, t0;
226
- $[0] !== color.bg || $[1] !== props.style ? (t0 = {
227
- position: "absolute",
228
- inset: 0,
229
- display: "flex",
230
- flexDirection: "column",
231
- background: color.bg,
232
- ...props.style
233
- }, $[0] = color.bg, $[1] = props.style, $[2] = t0) : t0 = $[2];
234
- let t1;
235
- $[3] === border ? t1 = $[4] : (t1 = {
236
- flex: "none",
237
- display: "flex",
238
- alignItems: "center",
239
- gap: 5,
240
- height: "18%",
241
- padding: "0 5%",
242
- borderBottom: border
243
- }, $[3] = border, $[4] = t1);
525
+ let $ = c(19), { scheme } = props, { color } = useTheme_v2(), selected = color.selectable.default.selected, inputColor = color.input.default.enabled, t0 = studio[scheme], t1;
526
+ $[0] !== color.avatar.blue.bg || $[1] !== color.bg || $[2] !== color.border || $[3] !== color.button.default.primary.enabled.bg || $[4] !== color.fg || $[5] !== color.muted.fg || $[6] !== inputColor.bg || $[7] !== inputColor.border || $[8] !== selected.bg || $[9] !== selected.fg ? (t1 = assignInlineVars({
527
+ [colors.bg]: color.bg,
528
+ [colors.fg]: color.fg,
529
+ [colors.mutedFg]: color.muted.fg,
530
+ [colors.border]: color.border,
531
+ [colors.accent]: color.button.default.primary.enabled.bg,
532
+ [colors.avatar]: color.avatar.blue.bg,
533
+ [colors.selectedBg]: selected.bg,
534
+ [colors.selectedFg]: selected.fg,
535
+ [colors.inputBg]: inputColor.bg,
536
+ [colors.inputBorder]: inputColor.border
537
+ }), $[0] = color.avatar.blue.bg, $[1] = color.bg, $[2] = color.border, $[3] = color.button.default.primary.enabled.bg, $[4] = color.fg, $[5] = color.muted.fg, $[6] = inputColor.bg, $[7] = inputColor.border, $[8] = selected.bg, $[9] = selected.fg, $[10] = t1) : t1 = $[10];
244
538
  let t2;
245
- $[5] === primary.bg ? t2 = $[6] : (t2 = /* @__PURE__ */ jsx("div", { style: {
246
- flex: "none",
247
- width: 8,
248
- height: 8,
249
- borderRadius: 2,
250
- background: primary.bg
251
- } }), $[5] = primary.bg, $[6] = t2);
539
+ $[11] === Symbol.for("react.memo_cache_sentinel") ? (t2 = /* @__PURE__ */ jsx("div", { className: logo }), $[11] = t2) : t2 = $[11];
252
540
  let t3;
253
- $[7] === color.fg ? t3 = $[8] : (t3 = /* @__PURE__ */ jsx("div", { style: line("22%", color.fg) }), $[7] = color.fg, $[8] = t3);
254
- let t4;
255
- $[9] === Symbol.for("react.memo_cache_sentinel") ? (t4 = /* @__PURE__ */ jsx("div", { style: { flex: 1 } }), $[9] = t4) : t4 = $[9];
256
- let t5;
257
- $[10] === color.avatar.blue.bg ? t5 = $[11] : (t5 = /* @__PURE__ */ jsx("div", { style: {
258
- flex: "none",
259
- width: 8,
260
- height: 8,
261
- borderRadius: "50%",
262
- background: color.avatar.blue.bg
263
- } }), $[10] = color.avatar.blue.bg, $[11] = t5);
264
- let t6;
265
- $[12] !== t1 || $[13] !== t2 || $[14] !== t3 || $[15] !== t5 ? (t6 = /* @__PURE__ */ jsxs("div", {
266
- style: t1,
541
+ $[12] === Symbol.for("react.memo_cache_sentinel") ? (t3 = /* @__PURE__ */ jsxs("div", {
542
+ className: navbar,
267
543
  children: [
268
544
  t2,
269
- t3,
270
- t4,
271
- t5
545
+ /* @__PURE__ */ jsx("div", {
546
+ className: line.fg,
547
+ style: { width: "22%" }
548
+ }),
549
+ /* @__PURE__ */ jsx("div", { className: spacer }),
550
+ /* @__PURE__ */ jsx("div", { className: avatar })
272
551
  ]
273
- }), $[12] = t1, $[13] = t2, $[14] = t3, $[15] = t5, $[16] = t6) : t6 = $[16];
552
+ }), $[12] = t3) : t3 = $[12];
553
+ let t4;
554
+ $[13] === Symbol.for("react.memo_cache_sentinel") ? (t4 = /* @__PURE__ */ jsx("div", {
555
+ className: list,
556
+ children: LIST_ROWS.map(_temp$6)
557
+ }), $[13] = t4) : t4 = $[13];
558
+ let t5;
559
+ $[14] === Symbol.for("react.memo_cache_sentinel") ? (t5 = /* @__PURE__ */ jsxs("div", {
560
+ className: form,
561
+ children: [/* @__PURE__ */ jsx("div", {
562
+ className: line.fg,
563
+ style: { width: "45%" }
564
+ }), FIELDS.map(_temp2)]
565
+ }), $[14] = t5) : t5 = $[14];
566
+ let t6;
567
+ $[15] === Symbol.for("react.memo_cache_sentinel") ? (t6 = /* @__PURE__ */ jsxs("div", {
568
+ className: body,
569
+ children: [t4, /* @__PURE__ */ jsxs("div", {
570
+ className: pane,
571
+ children: [t5, /* @__PURE__ */ jsx("div", {
572
+ className: footer,
573
+ children: /* @__PURE__ */ jsx("div", { className: button })
574
+ })]
575
+ })]
576
+ }), $[15] = t6) : t6 = $[15];
274
577
  let t7;
275
- $[17] === Symbol.for("react.memo_cache_sentinel") ? (t7 = {
276
- flex: 1,
277
- display: "flex",
278
- minHeight: 0
279
- }, $[17] = t7) : t7 = $[17];
280
- let t8;
281
- $[18] === border ? t8 = $[19] : (t8 = {
282
- flex: "none",
283
- display: "flex",
284
- flexDirection: "column",
285
- width: "36%",
286
- borderRight: border
287
- }, $[18] = border, $[19] = t8);
288
- let t9;
289
- $[20] !== color.muted || $[21] !== selected ? (t9 = LIST_ROWS.map((width_0, index) => {
290
- let isSelected = index === 1;
291
- return /* @__PURE__ */ jsx("div", {
292
- style: {
293
- flex: "none",
294
- display: "flex",
295
- alignItems: "center",
296
- height: "18%",
297
- padding: "0 9%",
298
- background: isSelected ? selected.bg : void 0
299
- },
300
- children: /* @__PURE__ */ jsx("div", { style: line(width_0, isSelected ? selected.fg : color.muted.fg) })
301
- }, width_0);
302
- }), $[20] = color.muted, $[21] = selected, $[22] = t9) : t9 = $[22];
303
- let t10;
304
- $[23] !== t8 || $[24] !== t9 ? (t10 = /* @__PURE__ */ jsx("div", {
305
- style: t8,
306
- children: t9
307
- }), $[23] = t8, $[24] = t9, $[25] = t10) : t10 = $[25];
308
- let t11, t12;
309
- $[26] === Symbol.for("react.memo_cache_sentinel") ? (t11 = {
310
- flex: 1,
311
- display: "flex",
312
- flexDirection: "column",
313
- minWidth: 0
314
- }, t12 = {
315
- flex: 1,
316
- display: "flex",
317
- flexDirection: "column",
318
- gap: 7,
319
- padding: "9% 8% 0",
320
- minHeight: 0,
321
- overflow: "hidden"
322
- }, $[26] = t11, $[27] = t12) : (t11 = $[26], t12 = $[27]);
323
- let t13;
324
- $[28] === color.fg ? t13 = $[29] : (t13 = /* @__PURE__ */ jsx("div", { style: line("45%", color.fg) }), $[28] = color.fg, $[29] = t13);
325
- let t14;
326
- $[30] !== color.muted || $[31] !== input ? (t14 = FIELDS.map((width_1) => /* @__PURE__ */ jsxs("div", {
327
- style: {
328
- flex: "none",
329
- display: "flex",
330
- flexDirection: "column",
331
- gap: 3
332
- },
333
- children: [/* @__PURE__ */ jsx("div", { style: line(width_1, color.muted.fg) }), /* @__PURE__ */ jsx("div", { style: {
334
- height: 12,
335
- borderRadius: 3,
336
- background: input.bg,
337
- boxShadow: `inset 0 0 0 1px ${input.border}`
338
- } })]
339
- }, width_1)), $[30] = color.muted, $[31] = input, $[32] = t14) : t14 = $[32];
340
- let t15;
341
- $[33] !== t13 || $[34] !== t14 ? (t15 = /* @__PURE__ */ jsxs("div", {
342
- style: t12,
343
- children: [t13, t14]
344
- }), $[33] = t13, $[34] = t14, $[35] = t15) : t15 = $[35];
345
- let t16;
346
- $[36] === border ? t16 = $[37] : (t16 = {
347
- flex: "none",
348
- display: "flex",
349
- alignItems: "center",
350
- justifyContent: "flex-end",
351
- height: "20%",
352
- padding: "0 8%",
353
- borderTop: border
354
- }, $[36] = border, $[37] = t16);
355
- let t17;
356
- $[38] === primary.bg ? t17 = $[39] : (t17 = /* @__PURE__ */ jsx("div", { style: {
357
- width: "32%",
358
- height: "50%",
359
- borderRadius: 3,
360
- background: primary.bg
361
- } }), $[38] = primary.bg, $[39] = t17);
362
- let t18;
363
- $[40] !== t16 || $[41] !== t17 ? (t18 = /* @__PURE__ */ jsx("div", {
364
- style: t16,
365
- children: t17
366
- }), $[40] = t16, $[41] = t17, $[42] = t18) : t18 = $[42];
367
- let t19;
368
- $[43] !== t15 || $[44] !== t18 ? (t19 = /* @__PURE__ */ jsxs("div", {
369
- style: t11,
370
- children: [t15, t18]
371
- }), $[43] = t15, $[44] = t18, $[45] = t19) : t19 = $[45];
372
- let t20;
373
- $[46] !== t10 || $[47] !== t19 ? (t20 = /* @__PURE__ */ jsxs("div", {
374
- style: t7,
375
- children: [t10, t19]
376
- }), $[46] = t10, $[47] = t19, $[48] = t20) : t20 = $[48];
377
- let t21;
378
- return $[49] !== t0 || $[50] !== t20 || $[51] !== t6 ? (t21 = /* @__PURE__ */ jsxs("div", {
379
- style: t0,
380
- children: [t6, t20]
381
- }), $[49] = t0, $[50] = t20, $[51] = t6, $[52] = t21) : t21 = $[52], t21;
382
- }
383
- function _temp$4(width, background) {
384
- return {
385
- flex: "none",
386
- width,
387
- height: 4,
388
- borderRadius: 2,
389
- background
390
- };
578
+ return $[16] !== t0 || $[17] !== t1 ? (t7 = /* @__PURE__ */ jsxs("div", {
579
+ className: t0,
580
+ style: t1,
581
+ children: [t3, t6]
582
+ }), $[16] = t0, $[17] = t1, $[18] = t7) : t7 = $[18], t7;
583
+ }
584
+ function _temp2(width_0) {
585
+ return /* @__PURE__ */ jsxs("div", {
586
+ className: field,
587
+ children: [/* @__PURE__ */ jsx("div", {
588
+ className: line.muted,
589
+ style: { width: width_0 }
590
+ }), /* @__PURE__ */ jsx("div", { className: input })]
591
+ }, width_0);
592
+ }
593
+ function _temp$6(width, index) {
594
+ let isSelected = index === 1;
595
+ return /* @__PURE__ */ jsx("div", {
596
+ className: listRow,
597
+ "data-selected": isSelected,
598
+ children: /* @__PURE__ */ jsx("div", {
599
+ className: isSelected ? line.selected : line.muted,
600
+ style: { width }
601
+ })
602
+ }, width);
391
603
  }
392
604
  /**
393
605
  * The floating preview card of a theme: the lo-fi studio mockup on a raised,
@@ -404,6 +616,7 @@ function ThemeThumbnail(props) {
404
616
  children: /* @__PURE__ */ jsx(ThemePreview, { options: props.options })
405
617
  }), $[0] = props.options, $[1] = t0), t0;
406
618
  }
619
+ var removedThumbnail = "_1vdkp0v0";
407
620
  /**
408
621
  * The flow for restoring removed themes: the presets and custom themes the
409
622
  * user took out of the list, each with a button to put it back — and, for
@@ -420,7 +633,7 @@ function RemovedThemes() {
420
633
  gap: 3,
421
634
  children: [
422
635
  /* @__PURE__ */ jsx(Box, {
423
- style: { opacity: .6 },
636
+ className: removedThumbnail,
424
637
  children: /* @__PURE__ */ jsx(ThemeThumbnail, { options: theme.options })
425
638
  }),
426
639
  /* @__PURE__ */ jsx(Text, {
@@ -886,7 +1099,7 @@ function useImagePalette(onPalette) {
886
1099
  setBusy(!0);
887
1100
  let isCurrent = () => mountedRef.current && latestPickRef.current === pick, extract = async () => {
888
1101
  let palette = extractImagePalette(await readImagePixels(file));
889
- isCurrent() && (Object.values(palette).every(_temp$3) ? toast.push({
1102
+ isCurrent() && (Object.values(palette).every(_temp$5) ? toast.push({
890
1103
  status: "warning",
891
1104
  title: "Found no colors in that image"
892
1105
  }) : onPaletteRef.current(palette, file));
@@ -906,9 +1119,10 @@ function useImagePalette(onPalette) {
906
1119
  pickImage
907
1120
  }, $[7] = busy, $[8] = pickImage, $[9] = t5) : t5 = $[9], t5;
908
1121
  }
909
- function _temp$3(swatch) {
1122
+ function _temp$5(swatch) {
910
1123
  return swatch === null;
911
1124
  }
1125
+ var paletteGrid = "_17s80v42", tile = "_17s80v44", variantButton = "_17s80v46", variantFrame = "_17s80v47", variantRow = "_17s80v45", variantScale = "var(--_17s80v41)", variantScaleBox = "_17s80v48", variantWidth = "var(--_17s80v40)";
912
1126
  /** The swatches on display: the vibrant family over the muted one */
913
1127
  const TILES = [
914
1128
  "vibrant",
@@ -917,28 +1131,7 @@ const TILES = [
917
1131
  "muted",
918
1132
  "lightMuted",
919
1133
  "darkMuted"
920
- ], PaletteGrid = styled.div.withConfig({
921
- displayName: "PaletteGrid",
922
- componentId: "sc-j2tqre-0"
923
- })`display:grid;grid-template-columns:repeat(3,${24}px);grid-auto-rows:${24}px;gap:${4}px;&[data-with-image='true']{grid-template-columns:${52}px repeat(3,${24}px);}`, ImageTile = styled.img.withConfig({
924
- displayName: "ImageTile",
925
- componentId: "sc-j2tqre-1"
926
- })`display:block;grid-row:span 2;width:${52}px;height:${52}px;border-radius:3px;object-fit:cover;box-shadow:inset 0 0 0 1px var(--card-border-color);`, Tile = styled.span.withConfig({
927
- displayName: "Tile",
928
- componentId: "sc-j2tqre-2"
929
- })`display:block;border-radius:3px;box-shadow:inset 0 0 0 1px var(--card-border-color);&[data-empty='true']{background:repeating-linear-gradient( -45deg,transparent 0 3px,var(--card-border-color) 3px 4px );}`, VariantRow = styled.div.withConfig({
930
- displayName: "VariantRow",
931
- componentId: "sc-j2tqre-3"
932
- })`display:flex;gap:${8}px;margin:0 -${12}px;padding:0 ${12}px;overflow-x:auto;scroll-snap-type:x mandatory;scroll-padding-left:${12}px;scrollbar-width:thin;`, VariantButton = styled.button.withConfig({
933
- displayName: "VariantButton",
934
- componentId: "sc-j2tqre-4"
935
- })`appearance:none;flex:none;display:block;box-sizing:border-box;width:calc(var(--variant-width) + 8px);margin:0;padding:0;border:0;background:none;color:inherit;font:inherit;text-align:center;cursor:pointer;scroll-snap-align:start;&:focus{outline:none;}`, VariantFrame = styled.span.withConfig({
936
- displayName: "VariantFrame",
937
- componentId: "sc-j2tqre-5"
938
- })`display:block;box-sizing:border-box;width:calc(var(--variant-width) + 8px);height:calc(var(--variant-width) * 9 / 16 + 8px);padding:4px;border-radius:7px;overflow:hidden;transition:box-shadow 100ms;${VariantButton}:hover &{box-shadow:inset 0 0 0 2px var(--card-border-color);}${VariantButton}[aria-pressed='true'] &{box-shadow:inset 0 0 0 2px var(--card-focus-ring-color);}${VariantButton}:focus-visible &{outline:2px solid var(--card-focus-ring-color);outline-offset:-2px;}`, VariantScale = styled.span.withConfig({
939
- displayName: "VariantScale",
940
- componentId: "sc-j2tqre-6"
941
- })`display:block;width:${144}px;transform:scale(var(--variant-scale));transform-origin:top left;`;
1134
+ ];
942
1135
  /**
943
1136
  * Takes the colors of a theme from an image, on device: the image is read
944
1137
  * into a canvas and its palette extracted right there — nothing is uploaded.
@@ -951,13 +1144,13 @@ const TILES = [
951
1144
  function ImagePaletteSection(props) {
952
1145
  let $ = c(38), { imageUrl, onPalette, onVariant, onLucky, options, palette } = props, { busy, pickImage } = useImagePalette(onPalette), [dragging, setDragging] = useState(!1), dragDepth = useRef(0), t0;
953
1146
  $[0] !== options || $[1] !== palette ? (t0 = palette ? currentImageVariant(options, palette) : null, $[0] = options, $[1] = palette, $[2] = t0) : t0 = $[2];
954
- let current = t0, rowRef = useRef(null), [variantWidth, setVariantWidth] = useState(58), t1;
1147
+ let current = t0, rowRef = useRef(null), [thumbnailWidth, setThumbnailWidth] = useState(58), t1;
955
1148
  $[3] === Symbol.for("react.memo_cache_sentinel") ? (t1 = () => {
956
1149
  let row = rowRef.current;
957
1150
  if (!row) return;
958
1151
  let measure = () => {
959
1152
  let visible = row.clientWidth - 12 - 16;
960
- setVariantWidth(Math.max(24, Math.floor(visible / 2.5) - 8));
1153
+ setThumbnailWidth(Math.max(24, Math.floor(visible / 2.5) - 8));
961
1154
  };
962
1155
  measure();
963
1156
  let observer = new ResizeObserver(measure);
@@ -975,6 +1168,7 @@ function ImagePaletteSection(props) {
975
1168
  let t4;
976
1169
  $[7] !== options || $[8] !== palette ? (t4 = IMAGE_PALETTE_VARIANTS.flatMap((variant) => palette[variant] === null ? [] : [{
977
1170
  variant,
1171
+ title: IMAGE_PALETTE_TITLES[variant],
978
1172
  options: applyImagePalette(options, palette, variant)
979
1173
  }]), $[7] = options, $[8] = palette, $[9] = t4) : t4 = $[9], t3 = t4;
980
1174
  }
@@ -1014,11 +1208,13 @@ function ImagePaletteSection(props) {
1014
1208
  children: [t8, t9]
1015
1209
  }), $[19] = t9, $[20] = t10);
1016
1210
  let t11;
1017
- $[21] !== busy || $[22] !== current || $[23] !== imageUrl || $[24] !== onLucky || $[25] !== onVariant || $[26] !== palette || $[27] !== pickImage || $[28] !== variantWidth || $[29] !== variants ? (t11 = palette ? /* @__PURE__ */ jsxs(Fragment, { children: [
1018
- /* @__PURE__ */ jsxs(PaletteGrid, {
1211
+ $[21] !== busy || $[22] !== current || $[23] !== imageUrl || $[24] !== onLucky || $[25] !== onVariant || $[26] !== palette || $[27] !== pickImage || $[28] !== thumbnailWidth || $[29] !== variants ? (t11 = palette ? /* @__PURE__ */ jsxs(Fragment, { children: [
1212
+ /* @__PURE__ */ jsxs("div", {
1213
+ className: paletteGrid,
1019
1214
  "data-with-image": imageUrl !== void 0,
1020
- children: [imageUrl && /* @__PURE__ */ jsx(ImageTile, {
1215
+ children: [imageUrl && /* @__PURE__ */ jsx("img", {
1021
1216
  alt: "",
1217
+ className: "_17s80v43",
1022
1218
  src: imageUrl
1023
1219
  }), TILES.map((key) => {
1024
1220
  let hex = palette[key], title = IMAGE_PALETTE_TITLES[key];
@@ -1030,7 +1226,8 @@ function ImagePaletteSection(props) {
1030
1226
  }),
1031
1227
  placement: "bottom",
1032
1228
  portal: !0,
1033
- children: /* @__PURE__ */ jsx(Tile, {
1229
+ children: /* @__PURE__ */ jsx("span", {
1230
+ className: tile,
1034
1231
  "data-empty": hex === null,
1035
1232
  style: { background: hex ?? void 0 }
1036
1233
  })
@@ -1043,26 +1240,37 @@ function ImagePaletteSection(props) {
1043
1240
  muted: !0,
1044
1241
  size: 0,
1045
1242
  children: "Pick the swatch to build the theme around"
1046
- }), /* @__PURE__ */ jsx(VariantRow, {
1243
+ }), /* @__PURE__ */ jsx("div", {
1244
+ className: variantRow,
1047
1245
  ref: rowRef,
1048
- style: {
1049
- "--variant-width": `${variantWidth}px`,
1050
- "--variant-scale": variantWidth / 144
1051
- },
1246
+ style: assignInlineVars({
1247
+ [variantWidth]: `${thumbnailWidth}px`,
1248
+ [variantScale]: String(thumbnailWidth / 144)
1249
+ }),
1052
1250
  children: variants.map((t12) => {
1053
- let { variant: variant_0, options: variantOptions } = t12;
1054
- return /* @__PURE__ */ jsxs(VariantButton, {
1251
+ let { variant: variant_0, title: title_0, options: variantOptions } = t12;
1252
+ return /* @__PURE__ */ jsxs("button", {
1055
1253
  "aria-pressed": variant_0 === current,
1254
+ className: variantButton,
1056
1255
  onClick: () => onVariant(variant_0),
1057
1256
  type: "button",
1058
- children: [/* @__PURE__ */ jsx(VariantFrame, { children: /* @__PURE__ */ jsx(VariantScale, { children: /* @__PURE__ */ jsx(ThemeThumbnail, { options: variantOptions }) }) }), /* @__PURE__ */ jsx(Box, {
1257
+ children: [/* @__PURE__ */ jsx("span", {
1258
+ className: variantFrame,
1259
+ children: /* @__PURE__ */ jsx("span", {
1260
+ className: variantScaleBox,
1261
+ children: /* @__PURE__ */ jsx(ThemeThumbnail, { options: variantOptions })
1262
+ })
1263
+ }), /* @__PURE__ */ jsx(Box, {
1264
+ as: "span",
1265
+ display: "block",
1059
1266
  paddingTop: 1,
1060
1267
  children: /* @__PURE__ */ jsx(Text, {
1061
1268
  align: "center",
1269
+ as: "span",
1062
1270
  size: 0,
1063
1271
  textOverflow: "ellipsis",
1064
1272
  weight: variant_0 === current ? "medium" : "regular",
1065
- children: IMAGE_PALETTE_TITLES[variant_0]
1273
+ children: title_0
1066
1274
  })
1067
1275
  })]
1068
1276
  }, variant_0);
@@ -1091,7 +1299,7 @@ function ImagePaletteSection(props) {
1091
1299
  tooltip: "Take the colors from an image on your device",
1092
1300
  width: "fill"
1093
1301
  })]
1094
- }), $[21] = busy, $[22] = current, $[23] = imageUrl, $[24] = onLucky, $[25] = onVariant, $[26] = palette, $[27] = pickImage, $[28] = variantWidth, $[29] = variants, $[30] = t11) : t11 = $[30];
1302
+ }), $[21] = busy, $[22] = current, $[23] = imageUrl, $[24] = onLucky, $[25] = onVariant, $[26] = palette, $[27] = pickImage, $[28] = thumbnailWidth, $[29] = variants, $[30] = t11) : t11 = $[30];
1095
1303
  let t12;
1096
1304
  $[31] !== t10 || $[32] !== t11 ? (t12 = /* @__PURE__ */ jsxs(Stack, {
1097
1305
  gap: 3,
@@ -1102,7 +1310,7 @@ function ImagePaletteSection(props) {
1102
1310
  border: !0,
1103
1311
  onDragEnter: t4,
1104
1312
  onDragLeave: t5,
1105
- onDragOver: _temp$2,
1313
+ onDragOver: _temp$4,
1106
1314
  onDrop: t6,
1107
1315
  padding: 3,
1108
1316
  radius: 3,
@@ -1110,34 +1318,44 @@ function ImagePaletteSection(props) {
1110
1318
  children: t12
1111
1319
  }), $[34] = t12, $[35] = t6, $[36] = t7, $[37] = t13) : t13 = $[37], t13;
1112
1320
  }
1113
- function _temp$2(event_0) {
1321
+ function _temp$4(event_0) {
1114
1322
  event_0.preventDefault();
1115
1323
  }
1324
+ var colorRowText = "os3rj2", range = "os3rj1", swatch = "os3rj0";
1116
1325
  const SCHEME_TITLES = {
1117
1326
  dark: "Dark mode",
1118
1327
  light: "Light mode"
1119
- }, SCHEME_OPTION_KEYS = [
1328
+ };
1329
+ /**
1330
+ * Where the split preview shows a scheme: the Studio's own scheme stays next
1331
+ * to the sidebar (or at the bottom, stacked on small screens), the other one
1332
+ * takes the far side
1333
+ */
1334
+ function splitHint(own, mobile) {
1335
+ return mobile ? own ? "Shown at the bottom" : "Shown at the top" : own ? "Shown on the right, next to the themer" : "Shown on the left";
1336
+ }
1337
+ const SCHEME_OPTION_KEYS = [
1120
1338
  "accent",
1121
1339
  "text",
1122
1340
  "background",
1123
1341
  "contrast"
1124
- ], Swatch = styled.input.withConfig({
1125
- displayName: "Swatch",
1126
- componentId: "sc-vs5143-0"
1127
- })`box-sizing:border-box;flex:none;width:33px;height:33px;padding:0;border:1px solid var(--card-border-color);border-radius:4px;background:none;cursor:pointer;&::-webkit-color-swatch-wrapper{padding:0;}&::-webkit-color-swatch{border:none;border-radius:3px;}&::-moz-color-swatch{border:none;border-radius:3px;}`, Range = styled.input.withConfig({
1128
- displayName: "Range",
1129
- componentId: "sc-vs5143-1"
1130
- })`display:block;width:100%;margin:0;accent-color:var(--card-focus-ring-color);`;
1342
+ ];
1343
+ /**
1344
+ * `<input type="color">` paints the color into a shadow-DOM swatch that brings
1345
+ * its own border and padding, which then sits inside ours as a second border.
1346
+ * Stripping that chrome leaves the themed border as the only one.
1347
+ */
1131
1348
  /**
1132
1349
  * The flow for editing one of the user's own themes: its title, a live
1133
1350
  * preview, and a card per color scheme with the accent/text/background
1134
1351
  * pickers and the contrast slider of that scheme. Every change applies to the
1135
- * whole Studio right away — in the scheme the Studio is showing.
1352
+ * whole Studio right away — in the scheme the Studio is showing, or in both
1353
+ * side by side in the split preview.
1136
1354
  *
1137
1355
  * @internal
1138
1356
  */
1139
1357
  function ThemeEditor(props) {
1140
- let $ = c(40), { focusTitle, slug } = props, { themes, images, send } = useThemer(), t0;
1358
+ let $ = c(42), { focusTitle, slug } = props, { themes, images, split, mobile, send } = useThemer(), t0;
1141
1359
  if ($[0] !== slug || $[1] !== themes) {
1142
1360
  let t1;
1143
1361
  $[3] === slug ? t1 = $[4] : (t1 = (candidate) => candidate.slug === slug && candidate.source === "custom", $[3] = slug, $[4] = t1), t0 = themes.find(t1), $[0] = slug, $[1] = themes, $[2] = t0;
@@ -1182,7 +1400,7 @@ function ThemeEditor(props) {
1182
1400
  title
1183
1401
  }), $[23] = send, $[24] = slug, $[25] = t7, $[26] = t8) : (t7 = $[25], t8 = $[26]);
1184
1402
  let t9;
1185
- return $[27] !== applyVariant || $[28] !== focusTitle || $[29] !== t2 || $[30] !== t3 || $[31] !== t4 || $[32] !== t5 || $[33] !== t6 || $[34] !== t7 || $[35] !== t8 || $[36] !== theme.options || $[37] !== theme.palette || $[38] !== theme.title ? (t9 = /* @__PURE__ */ jsx(ThemeEditorForm, {
1403
+ return $[27] !== applyVariant || $[28] !== focusTitle || $[29] !== mobile || $[30] !== split || $[31] !== t2 || $[32] !== t3 || $[33] !== t4 || $[34] !== t5 || $[35] !== t6 || $[36] !== t7 || $[37] !== t8 || $[38] !== theme.options || $[39] !== theme.palette || $[40] !== theme.title ? (t9 = /* @__PURE__ */ jsx(ThemeEditorForm, {
1186
1404
  focusTitle,
1187
1405
  imageUrl: t2,
1188
1406
  onDone: t3,
@@ -1194,11 +1412,13 @@ function ThemeEditor(props) {
1194
1412
  onVariant: applyVariant,
1195
1413
  options: theme.options,
1196
1414
  palette: theme.palette,
1415
+ split,
1416
+ mobile,
1197
1417
  title: theme.title
1198
- }), $[27] = applyVariant, $[28] = focusTitle, $[29] = t2, $[30] = t3, $[31] = t4, $[32] = t5, $[33] = t6, $[34] = t7, $[35] = t8, $[36] = theme.options, $[37] = theme.palette, $[38] = theme.title, $[39] = t9) : t9 = $[39], t9;
1418
+ }), $[27] = applyVariant, $[28] = focusTitle, $[29] = mobile, $[30] = split, $[31] = t2, $[32] = t3, $[33] = t4, $[34] = t5, $[35] = t6, $[36] = t7, $[37] = t8, $[38] = theme.options, $[39] = theme.palette, $[40] = theme.title, $[41] = t9) : t9 = $[41], t9;
1199
1419
  }
1200
1420
  function ThemeEditorForm(props) {
1201
- let $ = c(46), { focusTitle, imageUrl, onDone, onLucky, onOptionsChange, onPalette, onRemove, onTitleChange, onVariant, options, palette, title } = props, studioScheme = useColorSchemeValue(), t0;
1421
+ let $ = c(50), { focusTitle, imageUrl, onDone, onLucky, onOptionsChange, onPalette, onRemove, onTitleChange, onVariant, options, palette, split, mobile, title } = props, studioScheme = useColorSchemeValue(), t0;
1202
1422
  $[0] === options ? t0 = $[1] : (t0 = resolveThemeOptions(options), $[0] = options, $[1] = t0);
1203
1423
  let resolved = t0, t1;
1204
1424
  $[2] === options ? t1 = $[3] : (t1 = buildPalette(options), $[2] = options, $[3] = t1);
@@ -1222,7 +1442,7 @@ function ThemeEditorForm(props) {
1222
1442
  }), $[9] = t4) : t4 = $[9];
1223
1443
  let t5;
1224
1444
  $[10] === onTitleChange ? t5 = $[11] : (t5 = (event) => onTitleChange(event.currentTarget.value), $[10] = onTitleChange, $[11] = t5);
1225
- let t6 = focusTitle ? _temp$1 : void 0, t7;
1445
+ let t6 = focusTitle ? _temp$3 : void 0, t7;
1226
1446
  $[12] !== focusTitle || $[13] !== t5 || $[14] !== t6 || $[15] !== title ? (t7 = /* @__PURE__ */ jsxs(Stack, {
1227
1447
  gap: 2,
1228
1448
  children: [t4, /* @__PURE__ */ jsx(TextInput, {
@@ -1245,16 +1465,20 @@ function ThemeEditorForm(props) {
1245
1465
  palette
1246
1466
  }), $[17] = imageUrl, $[18] = onLucky, $[19] = onPalette, $[20] = onVariant, $[21] = options, $[22] = palette, $[23] = t8) : t8 = $[23];
1247
1467
  let t9;
1248
- $[24] !== options || $[25] !== palettes || $[26] !== patchScheme || $[27] !== resolved || $[28] !== studioScheme ? (t9 = SCHEMES.map((scheme_0) => /* @__PURE__ */ jsx(SchemeCard, {
1249
- active: scheme_0 === studioScheme,
1468
+ $[24] !== mobile || $[25] !== options || $[26] !== palettes || $[27] !== patchScheme || $[28] !== resolved || $[29] !== split || $[30] !== studioScheme ? (t9 = SCHEMES.map((scheme_0) => /* @__PURE__ */ jsx(SchemeCard, {
1469
+ active: split || scheme_0 === studioScheme,
1250
1470
  onChange: (changes_0) => patchScheme(scheme_0, changes_0),
1251
1471
  options: options[scheme_0] ?? {},
1252
1472
  palette: palettes[scheme_0],
1253
1473
  resolved: resolved[scheme_0],
1254
- scheme: scheme_0
1255
- }, scheme_0)), $[24] = options, $[25] = palettes, $[26] = patchScheme, $[27] = resolved, $[28] = studioScheme, $[29] = t9) : t9 = $[29];
1474
+ scheme: scheme_0,
1475
+ split,
1476
+ splitHint: splitHint(scheme_0 === studioScheme, mobile)
1477
+ }, scheme_0)), $[24] = mobile, $[25] = options, $[26] = palettes, $[27] = patchScheme, $[28] = resolved, $[29] = split, $[30] = studioScheme, $[31] = t9) : t9 = $[31];
1256
1478
  let t10;
1257
- $[30] !== t3 || $[31] !== t7 || $[32] !== t8 || $[33] !== t9 ? (t10 = /* @__PURE__ */ jsx(ScrollArea, {
1479
+ $[32] === t9 ? t10 = $[33] : (t10 = /* @__PURE__ */ jsx(ScrollAreaBleed, { children: t9 }), $[32] = t9, $[33] = t10);
1480
+ let t11;
1481
+ $[34] !== t10 || $[35] !== t3 || $[36] !== t7 || $[37] !== t8 ? (t11 = /* @__PURE__ */ jsx(ScrollArea, {
1258
1482
  padding: 3,
1259
1483
  children: /* @__PURE__ */ jsxs(Stack, {
1260
1484
  gap: 4,
@@ -1262,54 +1486,56 @@ function ThemeEditorForm(props) {
1262
1486
  t3,
1263
1487
  t7,
1264
1488
  t8,
1265
- t9
1489
+ t10
1266
1490
  ]
1267
1491
  })
1268
- }), $[30] = t3, $[31] = t7, $[32] = t8, $[33] = t9, $[34] = t10) : t10 = $[34];
1269
- let t11;
1270
- $[35] === onRemove ? t11 = $[36] : (t11 = /* @__PURE__ */ jsx(TooltipButton, {
1492
+ }), $[34] = t10, $[35] = t3, $[36] = t7, $[37] = t8, $[38] = t11) : t11 = $[38];
1493
+ let t12;
1494
+ $[39] === onRemove ? t12 = $[40] : (t12 = /* @__PURE__ */ jsx(TooltipButton, {
1271
1495
  icon: TrashIcon,
1272
1496
  mode: "ghost",
1273
1497
  onClick: onRemove,
1274
1498
  text: "Remove",
1275
1499
  tone: "critical",
1276
1500
  tooltip: "Remove the theme — it can be restored until it is deleted"
1277
- }), $[35] = onRemove, $[36] = t11);
1278
- let t12;
1279
- $[37] === Symbol.for("react.memo_cache_sentinel") ? (t12 = /* @__PURE__ */ jsx(Box, { flex: 1 }), $[37] = t12) : t12 = $[37];
1501
+ }), $[39] = onRemove, $[40] = t12);
1280
1502
  let t13;
1281
- $[38] === onDone ? t13 = $[39] : (t13 = /* @__PURE__ */ jsx(Button, {
1503
+ $[41] === Symbol.for("react.memo_cache_sentinel") ? (t13 = /* @__PURE__ */ jsx(Box, { flex: 1 }), $[41] = t13) : t13 = $[41];
1504
+ let t14;
1505
+ $[42] === onDone ? t14 = $[43] : (t14 = /* @__PURE__ */ jsx(Button, {
1282
1506
  mode: "ghost",
1283
1507
  onClick: onDone,
1284
1508
  text: "Done"
1285
- }), $[38] = onDone, $[39] = t13);
1286
- let t14;
1287
- $[40] !== t11 || $[41] !== t13 ? (t14 = /* @__PURE__ */ jsx(Card, {
1509
+ }), $[42] = onDone, $[43] = t14);
1510
+ let t15;
1511
+ $[44] !== t12 || $[45] !== t14 ? (t15 = /* @__PURE__ */ jsx(Card, {
1288
1512
  borderTop: !0,
1289
1513
  padding: 3,
1290
1514
  children: /* @__PURE__ */ jsxs(Flex, {
1291
1515
  gap: 2,
1292
1516
  children: [
1293
- t11,
1294
1517
  t12,
1295
- t13
1518
+ t13,
1519
+ t14
1296
1520
  ]
1297
1521
  })
1298
- }), $[40] = t11, $[41] = t13, $[42] = t14) : t14 = $[42];
1299
- let t15;
1300
- return $[43] !== t10 || $[44] !== t14 ? (t15 = /* @__PURE__ */ jsxs(Fragment, { children: [t10, t14] }), $[43] = t10, $[44] = t14, $[45] = t15) : t15 = $[45], t15;
1522
+ }), $[44] = t12, $[45] = t14, $[46] = t15) : t15 = $[46];
1523
+ let t16;
1524
+ return $[47] !== t11 || $[48] !== t15 ? (t16 = /* @__PURE__ */ jsxs(Fragment, { children: [t11, t15] }), $[47] = t11, $[48] = t15, $[49] = t16) : t16 = $[49], t16;
1301
1525
  }
1302
- function _temp$1(event_0) {
1526
+ function _temp$3(event_0) {
1303
1527
  return event_0.currentTarget.select();
1304
1528
  }
1305
1529
  /**
1306
- * The colors of one scheme, on a card painted in that scheme so that each
1307
- * card shows the colors it edits. The scheme the Studio is showing is marked
1308
- * as active: its changes show up in the Studio right away, the other scheme's
1309
- * only once the appearance setting switches to it.
1530
+ * The colors of one scheme. The cards span the sidebar edge to edge, one
1531
+ * after the other with a border between them, in the sidebar's own scheme —
1532
+ * the swatches show the colors they edit. The scheme the Studio is showing is
1533
+ * marked as active: its changes show up in the Studio right away, the other
1534
+ * scheme's only once the appearance setting switches to it — or both are
1535
+ * active, in the split preview.
1310
1536
  */
1311
1537
  function SchemeCard(props) {
1312
- let $ = c(69), { active, onChange, options, palette, resolved, scheme } = props, name = SCHEME_TITLES[scheme], t0;
1538
+ let $ = c(66), { active, onChange, options, palette, resolved, scheme, split, splitHint } = props, name = SCHEME_TITLES[scheme], t0;
1313
1539
  $[0] === name ? t0 = $[1] : (t0 = /* @__PURE__ */ jsx(Box, {
1314
1540
  flex: 1,
1315
1541
  children: /* @__PURE__ */ jsx(Text, {
@@ -1330,7 +1556,7 @@ function SchemeCard(props) {
1330
1556
  gap: 2,
1331
1557
  children: [t0, t1]
1332
1558
  }), $[4] = t0, $[5] = t1, $[6] = t2) : t2 = $[6];
1333
- let t3 = active ? "Shown in the Studio right now" : `Shown once the Studio appearance is ${scheme}`, t4;
1559
+ let t3 = split ? splitHint : active ? "Shown in the Studio right now" : `Shown once the Studio appearance is ${scheme}`, t4;
1334
1560
  $[7] === t3 ? t4 = $[8] : (t4 = /* @__PURE__ */ jsx(Text, {
1335
1561
  muted: !0,
1336
1562
  size: 0,
@@ -1408,8 +1634,9 @@ function SchemeCard(props) {
1408
1634
  let t27 = `${name} contrast`, t28;
1409
1635
  $[50] === onChange ? t28 = $[51] : (t28 = (event) => onChange({ contrast: Number(event.currentTarget.value) }), $[50] = onChange, $[51] = t28);
1410
1636
  let t29;
1411
- $[52] !== resolved.contrast || $[53] !== t27 || $[54] !== t28 ? (t29 = /* @__PURE__ */ jsx(Range, {
1637
+ $[52] !== resolved.contrast || $[53] !== t27 || $[54] !== t28 ? (t29 = /* @__PURE__ */ jsx("input", {
1412
1638
  "aria-label": t27,
1639
+ className: range,
1413
1640
  max: 100,
1414
1641
  min: 15,
1415
1642
  onChange: t28,
@@ -1433,114 +1660,137 @@ function SchemeCard(props) {
1433
1660
  ]
1434
1661
  }), $[57] = t26, $[58] = t29, $[59] = t31) : t31 = $[59];
1435
1662
  let t32;
1436
- $[60] !== t10 || $[61] !== t15 || $[62] !== t21 || $[63] !== t31 || $[64] !== t5 ? (t32 = /* @__PURE__ */ jsxs(Stack, {
1437
- gap: 4,
1438
- children: [
1439
- t5,
1440
- t10,
1441
- t15,
1442
- t21,
1443
- t31
1444
- ]
1445
- }), $[60] = t10, $[61] = t15, $[62] = t21, $[63] = t31, $[64] = t5, $[65] = t32) : t32 = $[65];
1446
- let t33;
1447
- return $[66] !== scheme || $[67] !== t32 ? (t33 = /* @__PURE__ */ jsx(Card, {
1448
- border: !0,
1663
+ return $[60] !== t10 || $[61] !== t15 || $[62] !== t21 || $[63] !== t31 || $[64] !== t5 ? (t32 = /* @__PURE__ */ jsx(Card, {
1664
+ borderTop: !0,
1449
1665
  padding: 3,
1450
- radius: 3,
1451
- scheme,
1452
- tone: "default",
1453
- children: t32
1454
- }), $[66] = scheme, $[67] = t32, $[68] = t33) : t33 = $[68], t33;
1666
+ children: /* @__PURE__ */ jsxs(Stack, {
1667
+ gap: 4,
1668
+ children: [
1669
+ t5,
1670
+ t10,
1671
+ t15,
1672
+ t21,
1673
+ t31
1674
+ ]
1675
+ })
1676
+ }), $[60] = t10, $[61] = t15, $[62] = t21, $[63] = t31, $[64] = t5, $[65] = t32) : t32 = $[65], t32;
1455
1677
  }
1456
1678
  /** One color of a scheme: a swatch with its value and an optional reset button */
1457
1679
  function ColorRow(props) {
1458
- let $ = c(24), { adjusted, auto, autoLabel: t0, label, onChange, onClear, title, value } = props, autoLabel = t0 === void 0 ? "auto" : t0, t1;
1680
+ let $ = c(23), { adjusted, auto, autoLabel: t0, label, onChange, onClear, title, value } = props, autoLabel = t0 === void 0 ? "auto" : t0, t1;
1459
1681
  $[0] === onChange ? t1 = $[1] : (t1 = (event) => onChange(event.currentTarget.value), $[0] = onChange, $[1] = t1);
1460
1682
  let t2;
1461
- $[2] !== label || $[3] !== t1 || $[4] !== value ? (t2 = /* @__PURE__ */ jsx(Swatch, {
1683
+ $[2] !== label || $[3] !== t1 || $[4] !== value ? (t2 = /* @__PURE__ */ jsx("input", {
1462
1684
  "aria-label": label,
1685
+ className: swatch,
1463
1686
  onChange: t1,
1464
1687
  type: "color",
1465
1688
  value
1466
1689
  }), $[2] = label, $[3] = t1, $[4] = value, $[5] = t2) : t2 = $[5];
1467
1690
  let t3;
1468
- $[6] === Symbol.for("react.memo_cache_sentinel") ? (t3 = { minWidth: 0 }, $[6] = t3) : t3 = $[6];
1469
- let t4;
1470
- $[7] === title ? t4 = $[8] : (t4 = /* @__PURE__ */ jsx(Text, {
1691
+ $[6] === title ? t3 = $[7] : (t3 = /* @__PURE__ */ jsx(Text, {
1471
1692
  size: 1,
1472
1693
  children: title
1473
- }), $[7] = title, $[8] = t4);
1474
- let t5 = adjusted !== void 0 && adjusted !== value ? ` → ${adjusted}` : "", t6 = auto ? ` · ${autoLabel}` : "", t7;
1475
- $[9] !== t5 || $[10] !== t6 || $[11] !== value ? (t7 = /* @__PURE__ */ jsxs(Text, {
1694
+ }), $[6] = title, $[7] = t3);
1695
+ let t4 = adjusted !== void 0 && adjusted !== value ? ` → ${adjusted}` : "", t5 = auto ? ` · ${autoLabel}` : "", t6;
1696
+ $[8] !== t4 || $[9] !== t5 || $[10] !== value ? (t6 = /* @__PURE__ */ jsxs(Text, {
1476
1697
  muted: !0,
1477
1698
  size: 0,
1478
1699
  textOverflow: "ellipsis",
1479
1700
  children: [
1480
1701
  value,
1481
- t5,
1482
- t6
1702
+ t4,
1703
+ t5
1483
1704
  ]
1484
- }), $[9] = t5, $[10] = t6, $[11] = value, $[12] = t7) : t7 = $[12];
1485
- let t8;
1486
- $[13] !== t4 || $[14] !== t7 ? (t8 = /* @__PURE__ */ jsxs(Stack, {
1705
+ }), $[8] = t4, $[9] = t5, $[10] = value, $[11] = t6) : t6 = $[11];
1706
+ let t7;
1707
+ $[12] !== t3 || $[13] !== t6 ? (t7 = /* @__PURE__ */ jsxs(Stack, {
1708
+ className: colorRowText,
1487
1709
  flex: 1,
1488
1710
  gap: 2,
1489
- style: t3,
1490
- children: [t4, t7]
1491
- }), $[13] = t4, $[14] = t7, $[15] = t8) : t8 = $[15];
1492
- let t9;
1493
- $[16] !== auto || $[17] !== autoLabel || $[18] !== onClear ? (t9 = onClear && !auto && /* @__PURE__ */ jsx(TooltipButton, {
1711
+ children: [t3, t6]
1712
+ }), $[12] = t3, $[13] = t6, $[14] = t7) : t7 = $[14];
1713
+ let t8;
1714
+ $[15] !== auto || $[16] !== autoLabel || $[17] !== onClear ? (t8 = onClear && !auto && /* @__PURE__ */ jsx(TooltipButton, {
1494
1715
  icon: ResetIcon,
1495
1716
  mode: "bleed",
1496
1717
  onClick: onClear,
1497
1718
  padding: 2,
1498
1719
  tooltip: `Reset to ${autoLabel}`
1499
- }), $[16] = auto, $[17] = autoLabel, $[18] = onClear, $[19] = t9) : t9 = $[19];
1500
- let t10;
1501
- return $[20] !== t2 || $[21] !== t8 || $[22] !== t9 ? (t10 = /* @__PURE__ */ jsxs(Flex, {
1720
+ }), $[15] = auto, $[16] = autoLabel, $[17] = onClear, $[18] = t8) : t8 = $[18];
1721
+ let t9;
1722
+ return $[19] !== t2 || $[20] !== t7 || $[21] !== t8 ? (t9 = /* @__PURE__ */ jsxs(Flex, {
1502
1723
  align: "center",
1503
1724
  gap: 2,
1504
1725
  children: [
1505
1726
  t2,
1506
- t8,
1507
- t9
1727
+ t7,
1728
+ t8
1508
1729
  ]
1509
- }), $[20] = t2, $[21] = t8, $[22] = t9, $[23] = t10) : t10 = $[23], t10;
1510
- }
1511
- const Root = styled.div.withConfig({
1512
- displayName: "Root",
1513
- componentId: "sc-a1a6d4-0"
1514
- })`position:relative;`, PickButton = styled.button.withConfig({
1515
- displayName: "PickButton",
1516
- componentId: "sc-a1a6d4-1"
1517
- })`appearance:none;display:block;box-sizing:border-box;width:100%;margin:0;padding:0;border:0;background:none;color:inherit;font:inherit;text-align:center;cursor:pointer;&:focus{outline:none;}`, Frame = styled.span.withConfig({
1518
- displayName: "Frame",
1519
- componentId: "sc-a1a6d4-2"
1520
- })`display:block;padding:4px;border-radius:10px;transition:box-shadow 100ms;${PickButton}:hover &{box-shadow:inset 0 0 0 2px var(--card-border-color);}${PickButton}[aria-pressed='true'] &{box-shadow:inset 0 0 0 2px var(--card-focus-ring-color);}${PickButton}:focus-visible &{outline:2px solid var(--card-focus-ring-color);outline-offset:-2px;}`, MenuSlot = styled.div.withConfig({
1521
- displayName: "MenuSlot",
1522
- componentId: "sc-a1a6d4-3"
1523
- })`position:absolute;top:10px;right:10px;opacity:0;transition:opacity 100ms;${Root}:hover &,${Root}:focus-within &,&[data-visible='true']{opacity:1;}`;
1730
+ }), $[19] = t2, $[20] = t7, $[21] = t8, $[22] = t9) : t9 = $[22], t9;
1731
+ }
1732
+ var frame$1 = "_1wsn7882", menuCard = "_1wsn7884", menuSlot = "_1wsn7883", pickButton = "_1wsn7881", root = "_1wsn7880";
1733
+ /**
1734
+ * Scrolls the applied theme's card into view when it is not already, as a
1735
+ * ref: the list scrolls to it as it mounts — coming back from the editor or
1736
+ * the removed themes — and when another theme gets applied
1737
+ */
1738
+ function scrollRefIntoViewIfNeeded(node) {
1739
+ node && scrollIntoView(node, {
1740
+ block: "nearest",
1741
+ scrollMode: "if-needed"
1742
+ });
1743
+ }
1524
1744
  /**
1525
1745
  * One theme in the list: the floating preview with the title below it, like
1526
1746
  * an appearance option in macOS System Settings. Clicking it applies the
1527
- * theme to the whole Studio; its menu holds the edit, duplicate and remove
1528
- * flows that apply to the theme.
1747
+ * theme to the whole Studio, dragging it moves the theme to another place in
1748
+ * the list; its menu holds the move, edit, duplicate and remove flows that
1749
+ * apply to the theme.
1529
1750
  *
1530
1751
  * @internal
1531
1752
  */
1532
1753
  function ThemeCard(props) {
1533
- let $ = c(50), { active, theme } = props, { send } = useThemer(), [menuOpen, setMenuOpen] = useState(!1), t0;
1754
+ let $ = c(81), { active, theme } = props, { themes, send } = useThemer(), { scheme } = useRootTheme(), [menuOpen, setMenuOpen] = useState(!1), dragControls = useDragControls(), dragged = useRef(!1), t0;
1534
1755
  $[0] === theme.title ? t0 = $[1] : (t0 = displayTitle(theme.title), $[0] = theme.title, $[1] = t0);
1535
1756
  let title = t0, t1;
1536
- $[2] !== send || $[3] !== theme.slug ? (t1 = () => send({
1537
- type: "theme.pick",
1538
- slug: theme.slug
1539
- }), $[2] = send, $[3] = theme.slug, $[4] = t1) : t1 = $[4];
1540
- let t2;
1541
- $[5] === theme.options ? t2 = $[6] : (t2 = /* @__PURE__ */ jsx(Frame, { children: /* @__PURE__ */ jsx(ThemeThumbnail, { options: theme.options }) }), $[5] = theme.options, $[6] = t2);
1542
- let t3 = active ? "medium" : "regular", t4;
1543
- $[7] !== t3 || $[8] !== title ? (t4 = /* @__PURE__ */ jsx(Box, {
1757
+ $[2] === theme.slug ? t1 = $[3] : (t1 = (candidate) => candidate.slug === theme.slug, $[2] = theme.slug, $[3] = t1);
1758
+ let index = themes.findIndex(t1), t2;
1759
+ $[4] !== index || $[5] !== send || $[6] !== themes ? (t2 = (to) => {
1760
+ let order = themes.map(_temp$2);
1761
+ order.splice(to, 0, ...order.splice(index, 1)), send({
1762
+ type: "theme.reorder",
1763
+ order
1764
+ });
1765
+ }, $[4] = index, $[5] = send, $[6] = themes, $[7] = t2) : t2 = $[7];
1766
+ let moveTo = t2, t3, t4;
1767
+ $[8] === Symbol.for("react.memo_cache_sentinel") ? (t3 = () => {
1768
+ requestAnimationFrame(() => {
1769
+ dragged.current = !1;
1770
+ });
1771
+ }, t4 = () => {
1772
+ dragged.current = !0;
1773
+ }, $[8] = t3, $[9] = t4) : (t3 = $[8], t4 = $[9]);
1774
+ let t5 = active ? scrollRefIntoViewIfNeeded : void 0, t6;
1775
+ $[10] === Symbol.for("react.memo_cache_sentinel") ? (t6 = { scale: 1.04 }, $[10] = t6) : t6 = $[10];
1776
+ let t7;
1777
+ $[11] !== send || $[12] !== theme.slug ? (t7 = () => {
1778
+ dragged.current || send({
1779
+ type: "theme.pick",
1780
+ slug: theme.slug
1781
+ });
1782
+ }, $[11] = send, $[12] = theme.slug, $[13] = t7) : t7 = $[13];
1783
+ let t8;
1784
+ $[14] === dragControls ? t8 = $[15] : (t8 = (event) => {
1785
+ event.pointerType !== "touch" && dragControls.start(event);
1786
+ }, $[14] = dragControls, $[15] = t8);
1787
+ let t9;
1788
+ $[16] === theme.options ? t9 = $[17] : (t9 = /* @__PURE__ */ jsx("span", {
1789
+ className: frame$1,
1790
+ children: /* @__PURE__ */ jsx(ThemeThumbnail, { options: theme.options })
1791
+ }), $[16] = theme.options, $[17] = t9);
1792
+ let t10 = active ? "medium" : "regular", t11;
1793
+ $[18] !== t10 || $[19] !== title ? (t11 = /* @__PURE__ */ jsx(Box, {
1544
1794
  as: "span",
1545
1795
  display: "block",
1546
1796
  paddingTop: 2,
@@ -1550,55 +1800,75 @@ function ThemeCard(props) {
1550
1800
  as: "span",
1551
1801
  size: 1,
1552
1802
  textOverflow: "ellipsis",
1553
- weight: t3,
1803
+ weight: t10,
1554
1804
  children: title
1555
1805
  })
1556
- }), $[7] = t3, $[8] = title, $[9] = t4) : t4 = $[9];
1557
- let t5;
1558
- $[10] !== active || $[11] !== t1 || $[12] !== t2 || $[13] !== t4 ? (t5 = /* @__PURE__ */ jsxs(PickButton, {
1806
+ }), $[18] = t10, $[19] = title, $[20] = t11) : t11 = $[20];
1807
+ let t12;
1808
+ $[21] !== active || $[22] !== t11 || $[23] !== t7 || $[24] !== t8 || $[25] !== t9 ? (t12 = /* @__PURE__ */ jsxs("button", {
1559
1809
  "aria-pressed": active,
1560
- onClick: t1,
1810
+ className: pickButton,
1811
+ onClick: t7,
1812
+ onPointerDown: t8,
1561
1813
  type: "button",
1562
- children: [t2, t4]
1563
- }), $[10] = active, $[11] = t1, $[12] = t2, $[13] = t4, $[14] = t5) : t5 = $[14];
1564
- let t6;
1565
- $[15] === Symbol.for("react.memo_cache_sentinel") ? (t6 = /* @__PURE__ */ jsx(Text, {
1814
+ children: [t9, t11]
1815
+ }), $[21] = active, $[22] = t11, $[23] = t7, $[24] = t8, $[25] = t9, $[26] = t12) : t12 = $[26];
1816
+ let t13;
1817
+ $[27] === Symbol.for("react.memo_cache_sentinel") ? (t13 = /* @__PURE__ */ jsx(Text, {
1566
1818
  size: 1,
1567
1819
  children: "Show more"
1568
- }), $[15] = t6) : t6 = $[15];
1569
- let t7;
1570
- $[16] === Symbol.for("react.memo_cache_sentinel") ? (t7 = { display: "inline-block" }, $[16] = t7) : t7 = $[16];
1571
- let t8 = `Show more for ${title}`, t9;
1572
- $[17] === t8 ? t9 = $[18] : (t9 = /* @__PURE__ */ jsx(Button, {
1573
- "aria-label": t8,
1820
+ }), $[27] = t13) : t13 = $[27];
1821
+ let t14 = `Show more for ${title}`, t15;
1822
+ $[28] === t14 ? t15 = $[29] : (t15 = /* @__PURE__ */ jsx(Button, {
1823
+ "aria-label": t14,
1574
1824
  fontSize: 1,
1575
1825
  icon: EllipsisHorizontalIcon,
1576
1826
  mode: "ghost",
1577
1827
  padding: 1,
1578
1828
  radius: 2
1579
- }), $[17] = t8, $[18] = t9);
1580
- let t10 = `themer-theme-${theme.slug}`, t11;
1581
- $[19] !== send || $[20] !== theme.slug || $[21] !== theme.source ? (t11 = theme.source === "custom" && /* @__PURE__ */ jsx(MenuItem, {
1829
+ }), $[28] = t14, $[29] = t15);
1830
+ let t16 = `themer-theme-${theme.slug}`, t17 = index <= 0, t18;
1831
+ $[30] !== index || $[31] !== moveTo ? (t18 = () => moveTo(index - 1), $[30] = index, $[31] = moveTo, $[32] = t18) : t18 = $[32];
1832
+ let t19;
1833
+ $[33] !== t17 || $[34] !== t18 ? (t19 = /* @__PURE__ */ jsx(MenuItem, {
1834
+ disabled: t17,
1835
+ icon: ArrowUpIcon,
1836
+ onClick: t18,
1837
+ text: "Move up"
1838
+ }), $[33] = t17, $[34] = t18, $[35] = t19) : t19 = $[35];
1839
+ let t20 = index >= themes.length - 1, t21;
1840
+ $[36] !== index || $[37] !== moveTo ? (t21 = () => moveTo(index + 1), $[36] = index, $[37] = moveTo, $[38] = t21) : t21 = $[38];
1841
+ let t22;
1842
+ $[39] !== t20 || $[40] !== t21 ? (t22 = /* @__PURE__ */ jsx(MenuItem, {
1843
+ disabled: t20,
1844
+ icon: ArrowDownIcon,
1845
+ onClick: t21,
1846
+ text: "Move down"
1847
+ }), $[39] = t20, $[40] = t21, $[41] = t22) : t22 = $[41];
1848
+ let t23;
1849
+ $[42] === Symbol.for("react.memo_cache_sentinel") ? (t23 = /* @__PURE__ */ jsx(MenuDivider, {}), $[42] = t23) : t23 = $[42];
1850
+ let t24;
1851
+ $[43] !== send || $[44] !== theme.slug || $[45] !== theme.source ? (t24 = theme.source === "custom" && /* @__PURE__ */ jsx(MenuItem, {
1582
1852
  icon: EditIcon,
1583
1853
  onClick: () => send({
1584
1854
  type: "theme.edit",
1585
1855
  slug: theme.slug
1586
1856
  }),
1587
1857
  text: "Edit"
1588
- }), $[19] = send, $[20] = theme.slug, $[21] = theme.source, $[22] = t11) : t11 = $[22];
1589
- let t12;
1590
- $[23] !== send || $[24] !== theme.slug ? (t12 = () => send({
1858
+ }), $[43] = send, $[44] = theme.slug, $[45] = theme.source, $[46] = t24) : t24 = $[46];
1859
+ let t25;
1860
+ $[47] !== send || $[48] !== theme.slug ? (t25 = () => send({
1591
1861
  type: "theme.duplicate",
1592
1862
  slug: theme.slug
1593
- }), $[23] = send, $[24] = theme.slug, $[25] = t12) : t12 = $[25];
1594
- let t13 = theme.source === "custom" ? "Duplicate" : "Duplicate to edit", t14;
1595
- $[26] !== t12 || $[27] !== t13 ? (t14 = /* @__PURE__ */ jsx(MenuItem, {
1863
+ }), $[47] = send, $[48] = theme.slug, $[49] = t25) : t25 = $[49];
1864
+ let t26 = theme.source === "custom" ? "Duplicate" : "Duplicate to edit", t27;
1865
+ $[50] !== t25 || $[51] !== t26 ? (t27 = /* @__PURE__ */ jsx(MenuItem, {
1596
1866
  icon: CopyIcon,
1597
- onClick: t12,
1598
- text: t13
1599
- }), $[26] = t12, $[27] = t13, $[28] = t14) : t14 = $[28];
1600
- let t15;
1601
- $[29] !== send || $[30] !== theme.slug || $[31] !== theme.source ? (t15 = theme.source !== "config" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(MenuDivider, {}), /* @__PURE__ */ jsx(MenuItem, {
1867
+ onClick: t25,
1868
+ text: t26
1869
+ }), $[50] = t25, $[51] = t26, $[52] = t27) : t27 = $[52];
1870
+ let t28;
1871
+ $[53] !== send || $[54] !== theme.slug || $[55] !== theme.source ? (t28 = theme.source !== "config" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(MenuDivider, {}), /* @__PURE__ */ jsx(MenuItem, {
1602
1872
  icon: TrashIcon,
1603
1873
  onClick: () => send({
1604
1874
  type: "theme.remove",
@@ -1606,54 +1876,82 @@ function ThemeCard(props) {
1606
1876
  }),
1607
1877
  text: "Remove",
1608
1878
  tone: "critical"
1609
- })] }), $[29] = send, $[30] = theme.slug, $[31] = theme.source, $[32] = t15) : t15 = $[32];
1610
- let t16;
1611
- $[33] !== t11 || $[34] !== t14 || $[35] !== t15 ? (t16 = /* @__PURE__ */ jsxs(Menu, { children: [
1612
- t11,
1613
- t14,
1614
- t15
1615
- ] }), $[33] = t11, $[34] = t14, $[35] = t15, $[36] = t16) : t16 = $[36];
1616
- let t17, t18, t19;
1617
- $[37] === Symbol.for("react.memo_cache_sentinel") ? (t17 = () => setMenuOpen(!1), t18 = () => setMenuOpen(!0), t19 = {
1879
+ })] }), $[53] = send, $[54] = theme.slug, $[55] = theme.source, $[56] = t28) : t28 = $[56];
1880
+ let t29;
1881
+ $[57] !== t19 || $[58] !== t22 || $[59] !== t24 || $[60] !== t27 || $[61] !== t28 ? (t29 = /* @__PURE__ */ jsxs(Menu, { children: [
1882
+ t19,
1883
+ t22,
1884
+ t23,
1885
+ t24,
1886
+ t27,
1887
+ t28
1888
+ ] }), $[57] = t19, $[58] = t22, $[59] = t24, $[60] = t27, $[61] = t28, $[62] = t29) : t29 = $[62];
1889
+ let t30, t31;
1890
+ $[63] === Symbol.for("react.memo_cache_sentinel") ? (t30 = () => setMenuOpen(!1), t31 = () => setMenuOpen(!0), $[63] = t30, $[64] = t31) : (t30 = $[63], t31 = $[64]);
1891
+ let t32;
1892
+ $[65] === scheme ? t32 = $[66] : (t32 = {
1618
1893
  animate: !0,
1619
1894
  placement: "bottom-end",
1620
- portal: !0
1621
- }, $[37] = t17, $[38] = t18, $[39] = t19) : (t17 = $[37], t18 = $[38], t19 = $[39]);
1622
- let t20;
1623
- $[40] !== t10 || $[41] !== t16 || $[42] !== t9 ? (t20 = /* @__PURE__ */ jsx(Tooltip, {
1895
+ portal: !0,
1896
+ scheme
1897
+ }, $[65] = scheme, $[66] = t32);
1898
+ let t33;
1899
+ $[67] !== t15 || $[68] !== t16 || $[69] !== t29 || $[70] !== t32 ? (t33 = /* @__PURE__ */ jsx(Tooltip, {
1624
1900
  animate: !0,
1625
- content: t6,
1901
+ content: t13,
1626
1902
  placement: "bottom",
1627
1903
  portal: !0,
1628
- children: /* @__PURE__ */ jsx("span", {
1629
- style: t7,
1904
+ children: /* @__PURE__ */ jsx(Card, {
1905
+ className: menuCard,
1906
+ radius: 2,
1907
+ scheme: "dark",
1630
1908
  children: /* @__PURE__ */ jsx(MenuButton, {
1631
- button: t9,
1632
- id: t10,
1633
- menu: t16,
1634
- onClose: t17,
1635
- onOpen: t18,
1636
- popover: t19
1909
+ button: t15,
1910
+ id: t16,
1911
+ menu: t29,
1912
+ onClose: t30,
1913
+ onOpen: t31,
1914
+ popover: t32
1637
1915
  })
1638
1916
  })
1639
- }), $[40] = t10, $[41] = t16, $[42] = t9, $[43] = t20) : t20 = $[43];
1640
- let t21;
1641
- $[44] !== menuOpen || $[45] !== t20 ? (t21 = /* @__PURE__ */ jsx(MenuSlot, {
1917
+ }), $[67] = t15, $[68] = t16, $[69] = t29, $[70] = t32, $[71] = t33) : t33 = $[71];
1918
+ let t34;
1919
+ $[72] !== menuOpen || $[73] !== t33 ? (t34 = /* @__PURE__ */ jsx("div", {
1920
+ className: menuSlot,
1642
1921
  "data-visible": menuOpen,
1643
- children: t20
1644
- }), $[44] = menuOpen, $[45] = t20, $[46] = t21) : t21 = $[46];
1645
- let t22;
1646
- return $[47] !== t21 || $[48] !== t5 ? (t22 = /* @__PURE__ */ jsxs(Root, { children: [t5, t21] }), $[47] = t21, $[48] = t5, $[49] = t22) : t22 = $[49], t22;
1647
- }
1922
+ children: t33
1923
+ }), $[72] = menuOpen, $[73] = t33, $[74] = t34) : t34 = $[74];
1924
+ let t35;
1925
+ return $[75] !== dragControls || $[76] !== t12 || $[77] !== t34 || $[78] !== t5 || $[79] !== theme.slug ? (t35 = /* @__PURE__ */ jsxs(Reorder.Item, {
1926
+ as: "div",
1927
+ className: root,
1928
+ dragControls,
1929
+ dragListener: !1,
1930
+ onDragEnd: t3,
1931
+ onDragStart: t4,
1932
+ ref: t5,
1933
+ value: theme.slug,
1934
+ whileDrag: t6,
1935
+ children: [t12, t34]
1936
+ }), $[75] = dragControls, $[76] = t12, $[77] = t34, $[78] = t5, $[79] = theme.slug, $[80] = t35) : t35 = $[80], t35;
1937
+ }
1938
+ function _temp$2(candidate_0) {
1939
+ return candidate_0.slug;
1940
+ }
1941
+ var cardGrid = "twjqgh0";
1942
+ /**
1943
+ * One column at the sidebar's default width; wider sidebars — and the
1944
+ * overlay on small screens — fit more cards per row
1945
+ */
1648
1946
  /**
1649
- * The flow for picking a theme: one column of theme cards — the configured
1650
- * theme, the presets and the user's own themes — with the entry points to
1651
- * the add and restore flows below.
1947
+ * The flow for picking a theme: a grid of theme cards — the configured theme,
1948
+ * the presets and the user's own themes — that drag into the order the user
1949
+ * wants, with the entry points to the add and restore flows below.
1652
1950
  *
1653
1951
  * @internal
1654
1952
  */
1655
1953
  function ThemeList() {
1656
- let $ = c(24), { themes, removed, active, send } = useThemer(), t0;
1954
+ let $ = c(32), { themes, removed, active, send } = useThemer(), t0;
1657
1955
  $[0] === send ? t0 = $[1] : (t0 = (palette, file) => send({
1658
1956
  type: "theme.add",
1659
1957
  title: titleFromFileName(file.name),
@@ -1662,31 +1960,49 @@ function ThemeList() {
1662
1960
  imageUrl: URL.createObjectURL(file)
1663
1961
  }), $[0] = send, $[1] = t0);
1664
1962
  let { busy, pickImage } = useImagePalette(t0), t1;
1665
- if ($[2] !== active || $[3] !== themes) {
1666
- let t2;
1667
- $[5] === active ? t2 = $[6] : (t2 = (theme) => /* @__PURE__ */ jsx(ThemeCard, {
1668
- active: theme.slug === active.slug,
1669
- theme
1670
- }, theme.slug), $[5] = active, $[6] = t2), t1 = themes.map(t2), $[2] = active, $[3] = themes, $[4] = t1;
1671
- } else t1 = $[4];
1963
+ $[2] === send ? t1 = $[3] : (t1 = (order) => send({
1964
+ type: "theme.reorder",
1965
+ order
1966
+ }), $[2] = send, $[3] = t1);
1672
1967
  let t2;
1673
- $[7] !== removed.length || $[8] !== send ? (t2 = removed.length > 0 && /* @__PURE__ */ jsx(Button, {
1968
+ $[4] === themes ? t2 = $[5] : (t2 = themes.map(_temp$1), $[4] = themes, $[5] = t2);
1969
+ let t3;
1970
+ if ($[6] !== active || $[7] !== themes) {
1971
+ let t4;
1972
+ $[9] === active ? t4 = $[10] : (t4 = (theme_0) => /* @__PURE__ */ jsx(ThemeCard, {
1973
+ active: theme_0.slug === active.slug,
1974
+ theme: theme_0
1975
+ }, theme_0.slug), $[9] = active, $[10] = t4), t3 = themes.map(t4), $[6] = active, $[7] = themes, $[8] = t3;
1976
+ } else t3 = $[8];
1977
+ let t4;
1978
+ $[11] !== t1 || $[12] !== t2 || $[13] !== t3 ? (t4 = /* @__PURE__ */ jsx(MotionConfig, {
1979
+ reducedMotion: "user",
1980
+ children: /* @__PURE__ */ jsx(Reorder.Group, {
1981
+ as: "div",
1982
+ className: cardGrid,
1983
+ onReorder: t1,
1984
+ values: t2,
1985
+ children: t3
1986
+ })
1987
+ }), $[11] = t1, $[12] = t2, $[13] = t3, $[14] = t4) : t4 = $[14];
1988
+ let t5;
1989
+ $[15] !== removed.length || $[16] !== send ? (t5 = removed.length > 0 && /* @__PURE__ */ jsx(Button, {
1674
1990
  icon: RestoreIcon,
1675
1991
  mode: "bleed",
1676
1992
  onClick: () => send({ type: "flow.removed" }),
1677
1993
  text: `Show removed (${removed.length})`,
1678
1994
  width: "fill"
1679
- }), $[7] = removed.length, $[8] = send, $[9] = t2) : t2 = $[9];
1680
- let t3;
1681
- $[10] !== t1 || $[11] !== t2 ? (t3 = /* @__PURE__ */ jsx(ScrollArea, {
1995
+ }), $[15] = removed.length, $[16] = send, $[17] = t5) : t5 = $[17];
1996
+ let t6;
1997
+ $[18] !== t4 || $[19] !== t5 ? (t6 = /* @__PURE__ */ jsx(ScrollArea, {
1682
1998
  padding: 3,
1683
1999
  children: /* @__PURE__ */ jsxs(Stack, {
1684
2000
  gap: 4,
1685
- children: [t1, t2]
2001
+ children: [t4, t5]
1686
2002
  })
1687
- }), $[10] = t1, $[11] = t2, $[12] = t3) : t3 = $[12];
1688
- let t4;
1689
- $[13] === send ? t4 = $[14] : (t4 = /* @__PURE__ */ jsx(Box, {
2003
+ }), $[18] = t4, $[19] = t5, $[20] = t6) : t6 = $[20];
2004
+ let t7;
2005
+ $[21] === send ? t7 = $[22] : (t7 = /* @__PURE__ */ jsx(Box, {
1690
2006
  flex: 1,
1691
2007
  children: /* @__PURE__ */ jsx(TooltipButton, {
1692
2008
  icon: AddIcon,
@@ -1696,25 +2012,28 @@ function ThemeList() {
1696
2012
  tooltip: "Add a theme based on the applied one",
1697
2013
  width: "fill"
1698
2014
  })
1699
- }), $[13] = send, $[14] = t4);
1700
- let t5;
1701
- $[15] !== busy || $[16] !== pickImage ? (t5 = /* @__PURE__ */ jsx(ImageFileButton, {
2015
+ }), $[21] = send, $[22] = t7);
2016
+ let t8;
2017
+ $[23] !== busy || $[24] !== pickImage ? (t8 = /* @__PURE__ */ jsx(ImageFileButton, {
1702
2018
  loading: busy,
1703
2019
  mode: "ghost",
1704
2020
  onFile: pickImage,
1705
2021
  tooltip: "Add a theme from the colors of an image"
1706
- }), $[15] = busy, $[16] = pickImage, $[17] = t5) : t5 = $[17];
1707
- let t6;
1708
- $[18] !== t4 || $[19] !== t5 ? (t6 = /* @__PURE__ */ jsx(Card, {
2022
+ }), $[23] = busy, $[24] = pickImage, $[25] = t8) : t8 = $[25];
2023
+ let t9;
2024
+ $[26] !== t7 || $[27] !== t8 ? (t9 = /* @__PURE__ */ jsx(Card, {
1709
2025
  borderTop: !0,
1710
2026
  padding: 3,
1711
2027
  children: /* @__PURE__ */ jsxs(Flex, {
1712
2028
  gap: 2,
1713
- children: [t4, t5]
2029
+ children: [t7, t8]
1714
2030
  })
1715
- }), $[18] = t4, $[19] = t5, $[20] = t6) : t6 = $[20];
1716
- let t7;
1717
- return $[21] !== t3 || $[22] !== t6 ? (t7 = /* @__PURE__ */ jsxs(Fragment, { children: [t3, t6] }), $[21] = t3, $[22] = t6, $[23] = t7) : t7 = $[23], t7;
2031
+ }), $[26] = t7, $[27] = t8, $[28] = t9) : t9 = $[28];
2032
+ let t10;
2033
+ return $[29] !== t6 || $[30] !== t9 ? (t10 = /* @__PURE__ */ jsxs(Fragment, { children: [t6, t9] }), $[29] = t6, $[30] = t9, $[31] = t10) : t10 = $[31], t10;
2034
+ }
2035
+ function _temp$1(theme) {
2036
+ return theme.slug;
1718
2037
  }
1719
2038
  /**
1720
2039
  * Serializes theme options into the `buildTheme` call to paste into
@@ -1837,84 +2156,98 @@ function ThemeSnippetDialog(props) {
1837
2156
  children: t9
1838
2157
  }), $[19] = onClose, $[20] = t2, $[21] = t9, $[22] = t10) : t10 = $[22], t10;
1839
2158
  }
2159
+ var title = "c2pqej0";
1840
2160
  const VIEW_TITLES = {
1841
2161
  list: "Themer",
1842
2162
  edit: "Edit theme",
1843
2163
  removed: "Removed themes"
1844
2164
  };
1845
2165
  /**
1846
- * The themer sidebar: a header that navigates between the flows, the flow
1847
- * itself — picking a theme, editing one, or restoring removed ones — and the
1848
- * dialog with the `buildTheme` snippet of the applied theme.
2166
+ * The themer sidebar: a header that navigates between the flows and toggles
2167
+ * the split preview, the flow itself — picking a theme, editing one, or
2168
+ * restoring removed ones — and the dialog with the `buildTheme` snippet of
2169
+ * the applied theme.
1849
2170
  *
1850
2171
  * @internal
1851
2172
  */
1852
2173
  function ThemerSidebar() {
1853
- let $ = c(37), { active, view, send } = useThemer(), [snippetOpen, setSnippetOpen] = useState(!1), inList = view.name === "list", t0;
1854
- $[0] !== inList || $[1] !== send ? (t0 = !inList && /* @__PURE__ */ jsx(TooltipButton, {
2174
+ let $ = c(42), { active, split, view, navbarHeight, send } = useThemer(), [snippetOpen, setSnippetOpen] = useState(!1), inList = view.name === "list", t0;
2175
+ $[0] === navbarHeight ? t0 = $[1] : (t0 = navbarHeight === null ? void 0 : { height: navbarHeight }, $[0] = navbarHeight, $[1] = t0);
2176
+ let t1;
2177
+ $[2] !== inList || $[3] !== send ? (t1 = !inList && /* @__PURE__ */ jsx(TooltipButton, {
1855
2178
  icon: ArrowLeftIcon,
1856
2179
  mode: "bleed",
1857
2180
  onClick: () => send({ type: "flow.list" }),
1858
2181
  padding: 2,
1859
2182
  tooltip: "Back to the themes"
1860
- }), $[0] = inList, $[1] = send, $[2] = t0) : t0 = $[2];
1861
- let t1 = +!!inList, t2;
1862
- $[3] === Symbol.for("react.memo_cache_sentinel") ? (t2 = { minWidth: 0 }, $[3] = t2) : t2 = $[3];
1863
- let t3 = VIEW_TITLES[view.name], t4;
1864
- $[4] === t3 ? t4 = $[5] : (t4 = /* @__PURE__ */ jsx(Text, {
1865
- size: 1,
1866
- textOverflow: "ellipsis",
1867
- weight: "semibold",
1868
- children: t3
1869
- }), $[4] = t3, $[5] = t4);
1870
- let t5;
1871
- $[6] !== t1 || $[7] !== t4 ? (t5 = /* @__PURE__ */ jsx(Box, {
2183
+ }), $[2] = inList, $[3] = send, $[4] = t1) : t1 = $[4];
2184
+ let t2 = VIEW_TITLES[view.name], t3;
2185
+ $[5] === t2 ? t3 = $[6] : (t3 = /* @__PURE__ */ jsx(Box, {
2186
+ className: title,
1872
2187
  flex: 1,
1873
- paddingLeft: t1,
1874
- style: t2,
1875
- children: t4
1876
- }), $[6] = t1, $[7] = t4, $[8] = t5) : t5 = $[8];
1877
- let t6;
1878
- $[9] === view.name ? t6 = $[10] : (t6 = view.name !== "removed" && /* @__PURE__ */ jsx(TooltipButton, {
2188
+ children: /* @__PURE__ */ jsx(Text, {
2189
+ size: 1,
2190
+ textOverflow: "ellipsis",
2191
+ weight: "semibold",
2192
+ children: t2
2193
+ })
2194
+ }), $[5] = t2, $[6] = t3);
2195
+ let t4;
2196
+ $[7] !== send || $[8] !== split || $[9] !== view.name ? (t4 = view.name !== "removed" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(TooltipButton, {
2197
+ "aria-pressed": split,
2198
+ icon: SplitVerticalIcon,
2199
+ mode: "bleed",
2200
+ onClick: () => send({ type: "preview.toggle" }),
2201
+ padding: 2,
2202
+ selected: split,
2203
+ tooltip: "Show light and dark side by side"
2204
+ }), /* @__PURE__ */ jsx(TooltipButton, {
1879
2205
  icon: CodeBlockIcon,
1880
2206
  mode: "bleed",
1881
2207
  onClick: () => setSnippetOpen(!0),
1882
2208
  padding: 2,
1883
2209
  tooltip: "Show the code for the applied theme"
1884
- }), $[9] = view.name, $[10] = t6);
1885
- let t7;
1886
- $[11] === send ? t7 = $[12] : (t7 = /* @__PURE__ */ jsx(TooltipButton, {
2210
+ })] }), $[7] = send, $[8] = split, $[9] = view.name, $[10] = t4) : t4 = $[10];
2211
+ let t5;
2212
+ $[11] === send ? t5 = $[12] : (t5 = /* @__PURE__ */ jsx(TooltipButton, {
1887
2213
  icon: CloseIcon,
1888
2214
  mode: "bleed",
1889
2215
  onClick: () => send({ type: "sidebar.close" }),
1890
2216
  padding: 2,
1891
2217
  tooltip: "Close themer"
1892
- }), $[11] = send, $[12] = t7);
2218
+ }), $[11] = send, $[12] = t5);
2219
+ let t6;
2220
+ $[13] !== t4 || $[14] !== t5 ? (t6 = /* @__PURE__ */ jsxs(Flex, { children: [t4, t5] }), $[13] = t4, $[14] = t5, $[15] = t6) : t6 = $[15];
2221
+ let t7;
2222
+ $[16] !== t1 || $[17] !== t3 || $[18] !== t6 ? (t7 = /* @__PURE__ */ jsxs(Flex, {
2223
+ align: "center",
2224
+ gap: 1,
2225
+ height: "fill",
2226
+ children: [
2227
+ t1,
2228
+ t3,
2229
+ t6
2230
+ ]
2231
+ }), $[16] = t1, $[17] = t3, $[18] = t6, $[19] = t7) : t7 = $[19];
1893
2232
  let t8;
1894
- $[13] !== t0 || $[14] !== t5 || $[15] !== t6 || $[16] !== t7 ? (t8 = /* @__PURE__ */ jsx(Card, {
1895
- padding: 2,
1896
- children: /* @__PURE__ */ jsxs(Flex, {
1897
- align: "center",
1898
- gap: 1,
1899
- children: [
1900
- t0,
1901
- t5,
1902
- t6,
1903
- t7
1904
- ]
1905
- })
1906
- }), $[13] = t0, $[14] = t5, $[15] = t6, $[16] = t7, $[17] = t8) : t8 = $[17];
2233
+ $[20] !== t0 || $[21] !== t7 ? (t8 = /* @__PURE__ */ jsx(Card, {
2234
+ borderBottom: !0,
2235
+ padding: 3,
2236
+ sizing: "border",
2237
+ style: t0,
2238
+ children: t7
2239
+ }), $[20] = t0, $[21] = t7, $[22] = t8) : t8 = $[22];
1907
2240
  let t9;
1908
- $[18] === view.name ? t9 = $[19] : (t9 = view.name === "list" && /* @__PURE__ */ jsx(ThemeList, {}), $[18] = view.name, $[19] = t9);
2241
+ $[23] === view.name ? t9 = $[24] : (t9 = view.name === "list" && /* @__PURE__ */ jsx(ThemeList, {}), $[23] = view.name, $[24] = t9);
1909
2242
  let t10;
1910
- $[20] !== view.focusTitle || $[21] !== view.name || $[22] !== view.slug ? (t10 = view.name === "edit" && /* @__PURE__ */ jsx(ThemeEditor, {
2243
+ $[25] !== view.focusTitle || $[26] !== view.name || $[27] !== view.slug ? (t10 = view.name === "edit" && /* @__PURE__ */ jsx(ThemeEditor, {
1911
2244
  focusTitle: view.focusTitle,
1912
2245
  slug: view.slug
1913
- }), $[20] = view.focusTitle, $[21] = view.name, $[22] = view.slug, $[23] = t10) : t10 = $[23];
2246
+ }), $[25] = view.focusTitle, $[26] = view.name, $[27] = view.slug, $[28] = t10) : t10 = $[28];
1914
2247
  let t11;
1915
- $[24] === view.name ? t11 = $[25] : (t11 = view.name === "removed" && /* @__PURE__ */ jsx(RemovedThemes, {}), $[24] = view.name, $[25] = t11);
2248
+ $[29] === view.name ? t11 = $[30] : (t11 = view.name === "removed" && /* @__PURE__ */ jsx(RemovedThemes, {}), $[29] = view.name, $[30] = t11);
1916
2249
  let t12;
1917
- $[26] !== t10 || $[27] !== t11 || $[28] !== t8 || $[29] !== t9 ? (t12 = /* @__PURE__ */ jsxs(Flex, {
2250
+ $[31] !== t10 || $[32] !== t11 || $[33] !== t8 || $[34] !== t9 ? (t12 = /* @__PURE__ */ jsxs(Flex, {
1918
2251
  direction: "column",
1919
2252
  height: "fill",
1920
2253
  children: [
@@ -1923,23 +2256,20 @@ function ThemerSidebar() {
1923
2256
  t10,
1924
2257
  t11
1925
2258
  ]
1926
- }), $[26] = t10, $[27] = t11, $[28] = t8, $[29] = t9, $[30] = t12) : t12 = $[30];
2259
+ }), $[31] = t10, $[32] = t11, $[33] = t8, $[34] = t9, $[35] = t12) : t12 = $[35];
1927
2260
  let t13;
1928
- $[31] !== active || $[32] !== snippetOpen ? (t13 = snippetOpen && /* @__PURE__ */ jsx(ThemeSnippetDialog, {
2261
+ $[36] !== active || $[37] !== snippetOpen ? (t13 = snippetOpen && /* @__PURE__ */ jsx(ThemeSnippetDialog, {
1929
2262
  onClose: () => setSnippetOpen(!1),
1930
2263
  theme: active
1931
- }), $[31] = active, $[32] = snippetOpen, $[33] = t13) : t13 = $[33];
2264
+ }), $[36] = active, $[37] = snippetOpen, $[38] = t13) : t13 = $[38];
1932
2265
  let t14;
1933
- return $[34] !== t12 || $[35] !== t13 ? (t14 = /* @__PURE__ */ jsxs(Card, {
2266
+ return $[39] !== t12 || $[40] !== t13 ? (t14 = /* @__PURE__ */ jsxs(Card, {
1934
2267
  height: "fill",
1935
2268
  children: [t12, t13]
1936
- }), $[34] = t12, $[35] = t13, $[36] = t14) : t14 = $[36], t14;
2269
+ }), $[39] = t12, $[40] = t13, $[41] = t14) : t14 = $[41], t14;
1937
2270
  }
1938
- /**
1939
- * The narrowest the sidebar goes — and its default: narrow enough to leave the
1940
- * studio preview as much room as possible, while the themes stack in a single
1941
- * column of preview cards and the editor fits a swatch next to its label.
1942
- */
2271
+ var content = "bgn4np4", frame = "bgn4np3", sidebar = "bgn4np2";
2272
+ /** How far one arrow key press resizes the sidebar */
1943
2273
  const WIDTH_STORAGE_KEY = "sanityStudio:themer:width";
1944
2274
  function clampWidth(width) {
1945
2275
  return Math.min(400, Math.max(200, Math.round(width)));
@@ -1956,28 +2286,17 @@ function writeStoredWidth(width) {
1956
2286
  try {
1957
2287
  width === 200 ? localStorage.removeItem(WIDTH_STORAGE_KEY) : localStorage.setItem(WIDTH_STORAGE_KEY, String(width));
1958
2288
  } catch {}
1959
- }
1960
- /**
1961
- * The sidebar itself does not clip, so the resize handle can straddle its
1962
- * border — the content is clipped one level down instead
1963
- */
1964
- const Sidebar = styled(Layer).withConfig({
1965
- displayName: "Sidebar",
1966
- componentId: "sc-xkgsr1-0"
1967
- })`position:relative;flex:none;box-sizing:border-box;border-left:1px solid var(--card-border-color);`, ResizeHandle = styled.div.withConfig({
1968
- displayName: "ResizeHandle",
1969
- componentId: "sc-xkgsr1-1"
1970
- })`position:absolute;top:0;bottom:0;left:-3px;z-index:1;width:7px;cursor:col-resize;touch-action:none;&::after{content:'';position:absolute;top:0;bottom:0;left:2px;width:3px;background:var(--card-focus-ring-color);opacity:0;transition:opacity 100ms;}&:hover::after,&:focus-visible::after,&[data-dragging='true']::after{opacity:1;}&:focus{outline:none;}`;
2289
+ }
1971
2290
  /**
1972
- * Renders the themer sidebar next to the active tool, so the user can browse
1973
- * around their own studio while tweaking the theme. The sidebar's left edge
1974
- * drags (or arrow-keys) it wider, up to twice its default width — the width
1975
- * sticks between sessions.
2291
+ * The themer sidebar, in a layer along the right edge of the Studio. Its left
2292
+ * edge drags (or arrow-keys) it wider, up to twice its default width — the
2293
+ * width sticks between sessions. As an overlay (small screens) it covers the
2294
+ * Studio edge to edge instead, with nothing to resize.
1976
2295
  *
1977
2296
  * @internal
1978
2297
  */
1979
- function ThemerActiveToolLayout(props) {
1980
- let $ = c(20), { open } = useThemer(), [width, setWidth] = useState(readStoredWidth), [dragging, setDragging] = useState(!1), drag = useRef(null), t0, t1;
2298
+ function ResizableSidebar(props) {
2299
+ let $ = c(24), { overlay } = props, [width, setWidth] = useState(readStoredWidth), [dragging, setDragging] = useState(!1), drag = useRef(null), t0, t1;
1981
2300
  $[0] === width ? (t0 = $[1], t1 = $[2]) : (t0 = () => writeStoredWidth(width), t1 = [width], $[0] = width, $[1] = t0, $[2] = t1), useEffect(t0, t1);
1982
2301
  let t2;
1983
2302
  $[3] === width ? t2 = $[4] : (t2 = (event) => {
@@ -2006,250 +2325,47 @@ function ThemerActiveToolLayout(props) {
2006
2325
  step !== void 0 && (event_2.preventDefault(), setWidth((current) => clampWidth(current + step)));
2007
2326
  }, $[7] = t5) : t5 = $[7];
2008
2327
  let handleKeyDown = t5, t6;
2009
- $[8] === props ? t6 = $[9] : (t6 = props.renderDefault(props), $[8] = props, $[9] = t6);
2010
- let t7;
2011
- $[10] === t6 ? t7 = $[11] : (t7 = /* @__PURE__ */ jsx(Box, {
2012
- flex: 1,
2328
+ $[8] !== overlay || $[9] !== width ? (t6 = overlay ? void 0 : { width }, $[8] = overlay, $[9] = width, $[10] = t6) : t6 = $[10];
2329
+ let t7 = !overlay, t8;
2330
+ $[11] !== dragging || $[12] !== handlePointerDown || $[13] !== overlay || $[14] !== width ? (t8 = !overlay && /* @__PURE__ */ jsx("div", {
2331
+ "aria-label": "Resize the themer",
2332
+ className: "bgn4np5",
2333
+ "aria-orientation": "vertical",
2334
+ "aria-valuemax": 400,
2335
+ "aria-valuemin": 200,
2336
+ "aria-valuenow": width,
2337
+ "data-dragging": dragging,
2338
+ onDoubleClick: () => setWidth(200),
2339
+ onKeyDown: handleKeyDown,
2340
+ onPointerCancel: handlePointerUp,
2341
+ onPointerDown: handlePointerDown,
2342
+ onPointerMove: handlePointerMove,
2343
+ onPointerUp: handlePointerUp,
2344
+ role: "separator",
2345
+ tabIndex: 0
2346
+ }), $[11] = dragging, $[12] = handlePointerDown, $[13] = overlay, $[14] = width, $[15] = t8) : t8 = $[15];
2347
+ let t9;
2348
+ $[16] === Symbol.for("react.memo_cache_sentinel") ? (t9 = /* @__PURE__ */ jsx(Box, {
2349
+ className: content,
2013
2350
  height: "fill",
2014
- overflow: "auto",
2015
- children: t6
2016
- }), $[10] = t6, $[11] = t7);
2017
- let t8;
2018
- $[12] !== dragging || $[13] !== handlePointerDown || $[14] !== open || $[15] !== width ? (t8 = open && /* @__PURE__ */ jsxs(Sidebar, {
2351
+ overflow: "hidden",
2352
+ children: /* @__PURE__ */ jsx(ThemerSidebar, {})
2353
+ }), $[16] = t9) : t9 = $[16];
2354
+ let t10;
2355
+ $[17] !== t7 || $[18] !== t8 ? (t10 = /* @__PURE__ */ jsxs(Card, {
2356
+ borderLeft: t7,
2357
+ className: frame,
2019
2358
  height: "fill",
2020
- style: { width },
2359
+ children: [t8, t9]
2360
+ }), $[17] = t7, $[18] = t8, $[19] = t10) : t10 = $[19];
2361
+ let t11;
2362
+ return $[20] !== overlay || $[21] !== t10 || $[22] !== t6 ? (t11 = /* @__PURE__ */ jsx(Layer, {
2363
+ className: sidebar,
2364
+ "data-overlay": overlay,
2365
+ style: t6,
2021
2366
  zOffset: 100,
2022
- children: [/* @__PURE__ */ jsx(ResizeHandle, {
2023
- "aria-label": "Resize the themer",
2024
- "aria-orientation": "vertical",
2025
- "aria-valuemax": 400,
2026
- "aria-valuemin": 200,
2027
- "aria-valuenow": width,
2028
- "data-dragging": dragging,
2029
- onDoubleClick: () => setWidth(200),
2030
- onKeyDown: handleKeyDown,
2031
- onPointerCancel: handlePointerUp,
2032
- onPointerDown: handlePointerDown,
2033
- onPointerMove: handlePointerMove,
2034
- onPointerUp: handlePointerUp,
2035
- role: "separator",
2036
- tabIndex: 0
2037
- }), /* @__PURE__ */ jsx(Box, {
2038
- height: "fill",
2039
- overflow: "hidden",
2040
- children: /* @__PURE__ */ jsx(ThemerSidebar, {})
2041
- })]
2042
- }), $[12] = dragging, $[13] = handlePointerDown, $[14] = open, $[15] = width, $[16] = t8) : t8 = $[16];
2043
- let t9;
2044
- return $[17] !== t7 || $[18] !== t8 ? (t9 = /* @__PURE__ */ jsxs(Flex, {
2045
- height: "fill",
2046
- sizing: "border",
2047
- children: [t7, t8]
2048
- }), $[17] = t7, $[18] = t8, $[19] = t9) : t9 = $[19], t9;
2049
- }
2050
- function themesOf(context) {
2051
- return resolveThemes(context, context.baseOptions);
2052
- }
2053
- /**
2054
- * The state of the themer tool: two parallel regions, whether the `sidebar`
2055
- * is open and which `flow` it is in — picking a theme from the `list`,
2056
- * `edit`ing one of the user's own themes, or restoring `removed` ones. The
2057
- * context carries the persisted state (the applied theme, the user's themes
2058
- * and what was removed) alongside what the flows need.
2059
- *
2060
- * Theme operations are handled in every flow, and the flows leave on their
2061
- * own when they lose their subject: the editor when its theme is removed or
2062
- * deleted, and the removed view when its last theme is restored or deleted.
2063
- *
2064
- * @internal
2065
- */
2066
- const themerMachine = setup({
2067
- types: {
2068
- context: {},
2069
- events: {},
2070
- input: {}
2071
- },
2072
- guards: {
2073
- isCustomTheme: ({ context }, params) => themesOf(context).themes.some((theme) => theme.slug === params.slug && theme.source === "custom"),
2074
- isEditingListedTheme: ({ context }) => context.editing !== null && themesOf(context).themes.some((theme) => theme.slug === context.editing?.slug && theme.source === "custom"),
2075
- hasRemovedThemes: ({ context }) => themesOf(context).removed.length > 0
2076
- },
2077
- actions: {
2078
- pick: assign((_, params) => ({ active: params.slug === "config" ? null : params.slug })),
2079
- add: assign(({ context }, params) => {
2080
- let theme = createCustomTheme(params.title ?? "Untitled theme", params.options ?? themesOf(context).active.options, params.palette);
2081
- return {
2082
- active: theme.slug,
2083
- custom: [...context.custom, theme],
2084
- editing: {
2085
- slug: theme.slug,
2086
- focusTitle: params.title === void 0
2087
- },
2088
- images: params.imageUrl ? {
2089
- ...context.images,
2090
- [theme.slug]: params.imageUrl
2091
- } : context.images
2092
- };
2093
- }),
2094
- duplicate: assign(({ context }, params) => {
2095
- let { themes, removed } = themesOf(context), source = [...themes, ...removed].find((theme) => theme.slug === params.slug);
2096
- if (!source) return {};
2097
- let theme = createCustomTheme(duplicateTitle(source.title), source.options, source.palette);
2098
- return {
2099
- active: theme.slug,
2100
- custom: [...context.custom, theme],
2101
- editing: {
2102
- slug: theme.slug,
2103
- focusTitle: !0
2104
- }
2105
- };
2106
- }),
2107
- startEditing: assign((_, params) => ({
2108
- active: params.slug,
2109
- editing: {
2110
- slug: params.slug,
2111
- focusTitle: !1
2112
- }
2113
- })),
2114
- stopEditing: assign({ editing: null }),
2115
- update: assign(({ context }, params) => ({
2116
- custom: context.custom.map((theme) => theme.slug === params.slug ? {
2117
- ...theme,
2118
- title: params.title ?? theme.title,
2119
- options: params.options ?? theme.options,
2120
- ...params.palette ? { palette: params.palette } : {}
2121
- } : theme),
2122
- images: params.imageUrl && context.custom.some((theme) => theme.slug === params.slug) ? {
2123
- ...context.images,
2124
- [params.slug]: params.imageUrl
2125
- } : context.images
2126
- })),
2127
- remove: assign(({ context }, params) => params.slug === "config" || context.removed.includes(params.slug) ? {} : {
2128
- active: context.active === params.slug ? null : context.active,
2129
- removed: [...context.removed, params.slug]
2130
- }),
2131
- restore: assign(({ context }, params) => ({ removed: context.removed.filter((slug) => slug !== params.slug) })),
2132
- delete: assign(({ context }, params) => {
2133
- if (!context.custom.some((theme) => theme.slug === params.slug)) return {};
2134
- let { [params.slug]: _deleted, ...images } = context.images;
2135
- return {
2136
- active: context.active === params.slug ? null : context.active,
2137
- custom: context.custom.filter((theme) => theme.slug !== params.slug),
2138
- removed: context.removed.filter((slug) => slug !== params.slug),
2139
- images
2140
- };
2141
- })
2142
- }
2143
- }).createMachine({
2144
- id: "themer",
2145
- context: ({ input }) => ({
2146
- ...input.stored,
2147
- baseOptions: input.baseOptions,
2148
- editing: null,
2149
- images: {}
2150
- }),
2151
- type: "parallel",
2152
- states: {
2153
- sidebar: {
2154
- initial: "closed",
2155
- states: {
2156
- closed: { on: { "sidebar.toggle": "open" } },
2157
- open: { on: {
2158
- "sidebar.toggle": "closed",
2159
- "sidebar.close": "closed"
2160
- } }
2161
- }
2162
- },
2163
- flow: {
2164
- initial: "list",
2165
- on: {
2166
- "theme.pick": { actions: {
2167
- type: "pick",
2168
- params: ({ event }) => ({ slug: event.slug })
2169
- } },
2170
- "theme.add": {
2171
- target: ".edit",
2172
- actions: {
2173
- type: "add",
2174
- params: ({ event }) => ({
2175
- title: event.title,
2176
- options: event.options,
2177
- palette: event.palette,
2178
- imageUrl: event.imageUrl
2179
- })
2180
- }
2181
- },
2182
- "theme.duplicate": {
2183
- target: ".edit",
2184
- actions: {
2185
- type: "duplicate",
2186
- params: ({ event }) => ({ slug: event.slug })
2187
- }
2188
- },
2189
- "theme.edit": {
2190
- target: ".edit",
2191
- guard: {
2192
- type: "isCustomTheme",
2193
- params: ({ event }) => ({ slug: event.slug })
2194
- },
2195
- actions: {
2196
- type: "startEditing",
2197
- params: ({ event }) => ({ slug: event.slug })
2198
- }
2199
- },
2200
- "theme.update": { actions: {
2201
- type: "update",
2202
- params: ({ event }) => ({
2203
- slug: event.slug,
2204
- title: event.title,
2205
- options: event.options,
2206
- palette: event.palette,
2207
- imageUrl: event.imageUrl
2208
- })
2209
- } },
2210
- "theme.remove": { actions: {
2211
- type: "remove",
2212
- params: ({ event }) => ({ slug: event.slug })
2213
- } },
2214
- "theme.restore": { actions: {
2215
- type: "restore",
2216
- params: ({ event }) => ({ slug: event.slug })
2217
- } },
2218
- "theme.delete": { actions: {
2219
- type: "delete",
2220
- params: ({ event }) => ({ slug: event.slug })
2221
- } },
2222
- "flow.list": ".list",
2223
- "flow.removed": {
2224
- target: ".removed",
2225
- guard: "hasRemovedThemes"
2226
- }
2227
- },
2228
- states: {
2229
- list: {},
2230
- edit: {
2231
- exit: "stopEditing",
2232
- always: {
2233
- guard: not("isEditingListedTheme"),
2234
- target: "list"
2235
- }
2236
- },
2237
- removed: { always: {
2238
- guard: not("hasRemovedThemes"),
2239
- target: "list"
2240
- } }
2241
- }
2242
- }
2243
- }
2244
- });
2245
- /** The part of the machine context that is persisted between sessions @internal */
2246
- function selectStoredState(snapshot) {
2247
- let { active, custom, removed } = snapshot.context;
2248
- return {
2249
- active,
2250
- custom,
2251
- removed
2252
- };
2367
+ children: t10
2368
+ }), $[20] = overlay, $[21] = t10, $[22] = t6, $[23] = t11) : t11 = $[23], t11;
2253
2369
  }
2254
2370
  const STORAGE_KEY = "sanityStudio:themer:state", LEGACY_STORAGE_KEY = "sanityStudio:themer:options";
2255
2371
  function sanitizeColor(value) {
@@ -2329,11 +2445,14 @@ function sanitizeState(value) {
2329
2445
  }
2330
2446
  let removed = [], rawRemoved = Reflect.get(value, "removed");
2331
2447
  if (Array.isArray(rawRemoved)) for (let slug of rawRemoved) typeof slug == "string" && slug !== "config" && (presets.some((preset) => preset.slug === slug) || custom.some((theme) => theme.slug === slug)) && !removed.includes(slug) && removed.push(slug);
2448
+ let order = [], rawOrder = Reflect.get(value, "order");
2449
+ if (Array.isArray(rawOrder)) for (let slug of rawOrder) typeof slug == "string" && (slug === "config" || presets.some((preset) => preset.slug === slug) || custom.some((theme) => theme.slug === slug)) && !order.includes(slug) && order.push(slug);
2332
2450
  let rawActive = Reflect.get(value, "active");
2333
2451
  return {
2334
2452
  active: typeof rawActive == "string" ? rawActive : null,
2335
2453
  custom,
2336
- removed
2454
+ removed,
2455
+ order
2337
2456
  };
2338
2457
  }
2339
2458
  function readLegacyState() {
@@ -2345,7 +2464,8 @@ function readLegacyState() {
2345
2464
  return {
2346
2465
  active: theme.slug,
2347
2466
  custom: [theme],
2348
- removed: []
2467
+ removed: [],
2468
+ order: []
2349
2469
  };
2350
2470
  }
2351
2471
  /**
@@ -2371,8 +2491,49 @@ function writeStoredState(state) {
2371
2491
  localStorage.setItem(STORAGE_KEY, JSON.stringify(state)), localStorage.removeItem(LEGACY_STORAGE_KEY);
2372
2492
  } catch {}
2373
2493
  }
2494
+ /**
2495
+ * The height of the Studio navbar inside the given element, in pixels — kept
2496
+ * up to date as the navbar renders, remounts and resizes, and `null` until
2497
+ * there is one. The themer's header takes this height, so that its bottom
2498
+ * border lines up with the navbar's whatever height the Studio version, its
2499
+ * breakpoint or a custom navbar gives it.
2500
+ *
2501
+ * @internal
2502
+ */
2503
+ function useStudioNavbarHeight(ref) {
2504
+ let $ = c(3), [height, setHeight] = useState(null), t0, t1;
2505
+ return $[0] === ref ? (t0 = $[1], t1 = $[2]) : (t0 = () => {
2506
+ let root = ref.current;
2507
+ if (!root) return;
2508
+ let navbar = null, resizeObserver = new ResizeObserver(() => {
2509
+ navbar && setHeight(navbar.getBoundingClientRect().height);
2510
+ }), observeNavbar = () => {
2511
+ let next = root.querySelector("[data-testid=\"studio-navbar\"]");
2512
+ next !== navbar && (navbar && resizeObserver.unobserve(navbar), navbar = next, navbar ? (resizeObserver.observe(navbar), setHeight(navbar.getBoundingClientRect().height)) : setHeight(null));
2513
+ }, mutationObserver = new MutationObserver(observeNavbar);
2514
+ return mutationObserver.observe(root, {
2515
+ childList: !0,
2516
+ subtree: !0
2517
+ }), observeNavbar(), () => {
2518
+ mutationObserver.disconnect(), resizeObserver.disconnect();
2519
+ };
2520
+ }, t1 = [ref], $[0] = ref, $[1] = t0, $[2] = t1), useEffect(t0, t1), height;
2521
+ }
2522
+ var PANEL_TRANSITION = "_1yq4ar71", SPLIT_TRANSITION = "_1yq4ar70", layout = "_1yq4ar79", panelTransitionClasses = {
2523
+ slideIn: "_1yq4ar77",
2524
+ slideOut: "_1yq4ar78"
2525
+ }, splitTransitionClasses = {
2526
+ resize: "_1yq4ar72",
2527
+ slideIn: "_1yq4ar73",
2528
+ slideOut: "_1yq4ar74",
2529
+ dropIn: "_1yq4ar75",
2530
+ dropOut: "_1yq4ar76"
2531
+ }, studioScheme = {
2532
+ light: "_1yq4ar7a",
2533
+ dark: "_1yq4ar7b"
2534
+ };
2374
2535
  function sameStoredState(a, b) {
2375
- return a.active === b.active && a.custom === b.custom && a.removed === b.removed;
2536
+ return a.active === b.active && a.custom === b.custom && a.removed === b.removed && a.order === b.order;
2376
2537
  }
2377
2538
  function selectView(snapshot) {
2378
2539
  let { editing } = snapshot.context;
@@ -2387,18 +2548,23 @@ function sameView(a, b) {
2387
2548
  }
2388
2549
  /**
2389
2550
  * Wraps the whole Studio so that the theme picked in the themer sidebar
2390
- * applies everywhere while the user browses around, and runs the themer
2391
- * machine that the navbar toggle and the sidebar share: the user's themes,
2392
- * which one is applied, and which flow the sidebar is in.
2551
+ * applies everywhere while the user browses around, runs the themer machine
2552
+ * that the navbar toggle and the sidebar share — the user's themes, which one
2553
+ * is applied, which flow the sidebar is in and how the Studio is previewed —
2554
+ * and renders the sidebar next to the Studio. The sidebar sits at the
2555
+ * `layout` level rather than in `activeToolLayout` because the split preview
2556
+ * renders the Studio twice, and the sidebar must not come along.
2393
2557
  *
2394
- * The theme provider inherits the color scheme from the Studio, so the
2395
- * preview follows the appearance setting (light/dark/system) like any other
2396
- * theme.
2558
+ * The Studio next to the sidebar always follows the appearance setting
2559
+ * (light/dark/system) and the picked theme like any other theme would. The
2560
+ * split preview adds a second copy in the opposite scheme on the far side —
2561
+ * or on top, on small screens — through React's view transitions (React
2562
+ * 19.3), styled in `ThemerLayout.css.ts`.
2397
2563
  *
2398
2564
  * @internal
2399
2565
  */
2400
2566
  function ThemerLayout(props) {
2401
- let $ = c(38), { baseOptions, ...layoutProps } = props, t0;
2567
+ let $ = c(87), { baseOptions, ...layoutProps } = props, t0;
2402
2568
  $[0] === baseOptions ? t0 = $[1] : (t0 = () => ({
2403
2569
  baseOptions,
2404
2570
  stored: readStoredState()
@@ -2407,35 +2573,67 @@ function ThemerLayout(props) {
2407
2573
  $[2] === input ? t1 = $[3] : (t1 = { input }, $[2] = input, $[3] = t1);
2408
2574
  let [snapshot, send, actorRef] = useActor(themerMachine, t1), stored = useSelector(actorRef, selectStoredState, sameStoredState), view = useSelector(actorRef, selectView, sameView), t2;
2409
2575
  $[4] === snapshot ? t2 = $[5] : (t2 = snapshot.matches({ sidebar: "open" }), $[4] = snapshot, $[5] = t2);
2410
- let open = t2, { images } = snapshot.context, t3, t4;
2411
- $[6] === stored ? (t3 = $[7], t4 = $[8]) : (t3 = () => writeStoredState(stored), t4 = [stored], $[6] = stored, $[7] = t3, $[8] = t4), useEffect(t3, t4);
2412
- let previousImages = useRef(images), t5, t6;
2413
- $[9] === images ? (t5 = $[10], t6 = $[11]) : (t5 = () => {
2576
+ let open = t2, t3;
2577
+ $[6] === snapshot ? t3 = $[7] : (t3 = snapshot.matches({ preview: "split" }), $[6] = snapshot, $[7] = t3);
2578
+ let split = t3, { images } = snapshot.context, mobile = useMediaIndex() <= 1, studioRef = useRef(null), navbarHeight = useStudioNavbarHeight(studioRef), t4;
2579
+ $[8] !== open || $[9] !== split ? (t4 = {
2580
+ open,
2581
+ split
2582
+ }, $[8] = open, $[9] = split, $[10] = t4) : t4 = $[10];
2583
+ let [shown, setShown] = useState(t4), [resizing, setResizing] = useState(!1), t5;
2584
+ $[11] === Symbol.for("react.memo_cache_sentinel") ? (t5 = () => setResizing(!1), $[11] = t5) : t5 = $[11];
2585
+ let stopResizing = t5, t6;
2586
+ $[12] !== open || $[13] !== shown.open || $[14] !== shown.split || $[15] !== split ? (t6 = () => {
2587
+ (shown.open !== open || shown.split !== split) && startTransition(() => {
2588
+ shown.open !== open && addTransitionType(PANEL_TRANSITION), shown.split !== split && addTransitionType(SPLIT_TRANSITION), setShown({
2589
+ open,
2590
+ split
2591
+ }), setResizing(!0);
2592
+ });
2593
+ }, $[12] = open, $[13] = shown.open, $[14] = shown.split, $[15] = split, $[16] = t6) : t6 = $[16];
2594
+ let t7;
2595
+ $[17] !== open || $[18] !== shown || $[19] !== split ? (t7 = [
2596
+ open,
2597
+ shown,
2598
+ split
2599
+ ], $[17] = open, $[18] = shown, $[19] = split, $[20] = t7) : t7 = $[20], useEffect(t6, t7);
2600
+ let t8;
2601
+ $[21] === resizing ? t8 = $[22] : (t8 = () => {
2602
+ if (!resizing) return;
2603
+ let timer = setTimeout(() => setResizing(!1), 500);
2604
+ return () => clearTimeout(timer);
2605
+ }, $[21] = resizing, $[22] = t8);
2606
+ let t9;
2607
+ $[23] !== resizing || $[24] !== shown ? (t9 = [resizing, shown], $[23] = resizing, $[24] = shown, $[25] = t9) : t9 = $[25], useEffect(t8, t9);
2608
+ let t10, t11;
2609
+ $[26] === stored ? (t10 = $[27], t11 = $[28]) : (t10 = () => writeStoredState(stored), t11 = [stored], $[26] = stored, $[27] = t10, $[28] = t11), useEffect(t10, t11);
2610
+ let previousImages = useRef(images), t12, t13;
2611
+ $[29] === images ? (t12 = $[30], t13 = $[31]) : (t12 = () => {
2414
2612
  let current = new Set(Object.values(images));
2415
2613
  for (let url of Object.values(previousImages.current)) current.has(url) || URL.revokeObjectURL(url);
2416
2614
  previousImages.current = images;
2417
- }, t6 = [images], $[9] = images, $[10] = t5, $[11] = t6), useEffect(t5, t6);
2418
- let t7, t8;
2419
- $[12] === Symbol.for("react.memo_cache_sentinel") ? (t7 = () => () => {
2615
+ }, t13 = [images], $[29] = images, $[30] = t12, $[31] = t13), useEffect(t12, t13);
2616
+ let t14, t15;
2617
+ $[32] === Symbol.for("react.memo_cache_sentinel") ? (t14 = () => () => {
2420
2618
  for (let url_0 of Object.values(previousImages.current)) URL.revokeObjectURL(url_0);
2421
- }, t8 = [], $[12] = t7, $[13] = t8) : (t7 = $[12], t8 = $[13]), useEffect(t7, t8);
2422
- let t9;
2423
- $[14] !== baseOptions || $[15] !== stored ? (t9 = resolveThemes(stored, baseOptions), $[14] = baseOptions, $[15] = stored, $[16] = t9) : t9 = $[16];
2424
- let { themes, removed, active } = t9, activeOptions = active.source === "config" ? null : active.options, t10;
2425
- $[17] === activeOptions ? t10 = $[18] : (t10 = activeOptions === null ? null : buildTheme(activeOptions), $[17] = activeOptions, $[18] = t10);
2426
- let theme = t10, scheme = useColorSchemeValue(), t11;
2427
- $[19] !== scheme || $[20] !== theme?.v2?.color ? (t11 = () => {
2619
+ }, t15 = [], $[32] = t14, $[33] = t15) : (t14 = $[32], t15 = $[33]), useEffect(t14, t15);
2620
+ let t16;
2621
+ $[34] !== baseOptions || $[35] !== stored ? (t16 = resolveThemes(stored, baseOptions), $[34] = baseOptions, $[35] = stored, $[36] = t16) : t16 = $[36];
2622
+ let { themes, removed, active } = t16, activeOptions = active.source === "config" ? null : active.options, t17;
2623
+ $[37] === activeOptions ? t17 = $[38] : (t17 = activeOptions === null ? null : buildTheme(activeOptions), $[37] = activeOptions, $[38] = t17);
2624
+ let theme = t17, scheme = useColorSchemeValue(), oppositeScheme = scheme === "dark" ? "light" : "dark", t18;
2625
+ $[39] !== scheme || $[40] !== theme?.v2?.color ? (t18 = () => {
2428
2626
  let background = theme?.v2?.color[scheme].default.bg;
2429
2627
  if (background === void 0) return;
2430
2628
  let { style } = document.body, previous = style.backgroundColor;
2431
2629
  return style.backgroundColor = background, () => {
2432
2630
  style.backgroundColor = previous;
2433
2631
  };
2434
- }, $[19] = scheme, $[20] = theme?.v2?.color, $[21] = t11) : t11 = $[21];
2435
- let t12;
2436
- $[22] !== scheme || $[23] !== theme ? (t12 = [scheme, theme], $[22] = scheme, $[23] = theme, $[24] = t12) : t12 = $[24], useEffect(t11, t12);
2437
- let t13;
2438
- $[25] !== active || $[26] !== baseOptions || $[27] !== images || $[28] !== open || $[29] !== removed || $[30] !== send || $[31] !== themes || $[32] !== view ? (t13 = {
2632
+ }, $[39] = scheme, $[40] = theme?.v2?.color, $[41] = t18) : t18 = $[41];
2633
+ let t19;
2634
+ $[42] !== scheme || $[43] !== theme ? (t19 = [scheme, theme], $[42] = scheme, $[43] = theme, $[44] = t19) : t19 = $[44], useEffect(t18, t19);
2635
+ let t20;
2636
+ $[45] !== active || $[46] !== baseOptions || $[47] !== images || $[48] !== mobile || $[49] !== navbarHeight || $[50] !== open || $[51] !== removed || $[52] !== send || $[53] !== split || $[54] !== themes || $[55] !== view ? (t20 = {
2439
2637
  baseOptions,
2440
2638
  themes,
2441
2639
  removed,
@@ -2443,16 +2641,103 @@ function ThemerLayout(props) {
2443
2641
  images,
2444
2642
  view,
2445
2643
  open,
2644
+ split,
2645
+ mobile,
2646
+ navbarHeight,
2446
2647
  send
2447
- }, $[25] = active, $[26] = baseOptions, $[27] = images, $[28] = open, $[29] = removed, $[30] = send, $[31] = themes, $[32] = view, $[33] = t13) : t13 = $[33];
2448
- let context = t13, t14 = ThemerContext, t15 = theme === null ? layoutProps.renderDefault(layoutProps) : /* @__PURE__ */ jsx(ThemeProvider, {
2648
+ }, $[45] = active, $[46] = baseOptions, $[47] = images, $[48] = mobile, $[49] = navbarHeight, $[50] = open, $[51] = removed, $[52] = send, $[53] = split, $[54] = themes, $[55] = view, $[56] = t20) : t20 = $[56];
2649
+ let context = t20, studio = layoutProps.renderDefault(layoutProps), t21 = mobile ? "column" : "row", t22;
2650
+ $[57] !== mobile || $[58] !== oppositeScheme || $[59] !== shown.open || $[60] !== shown.split || $[61] !== studio || $[62] !== theme ? (t22 = shown.open && /* @__PURE__ */ jsx(Activity, {
2651
+ mode: shown.split ? "visible" : "hidden",
2652
+ children: /* @__PURE__ */ jsx(ViewTransition, {
2653
+ enter: mobile ? splitTransitionClasses.dropIn : splitTransitionClasses.slideIn,
2654
+ exit: mobile ? splitTransitionClasses.dropOut : splitTransitionClasses.slideOut,
2655
+ update: "none",
2656
+ children: /* @__PURE__ */ jsx(StudioPreview, {
2657
+ borderBottom: mobile,
2658
+ borderRight: !mobile,
2659
+ scheme: oppositeScheme,
2660
+ theme,
2661
+ children: studio
2662
+ })
2663
+ }, "opposite")
2664
+ }), $[57] = mobile, $[58] = oppositeScheme, $[59] = shown.open, $[60] = shown.split, $[61] = studio, $[62] = theme, $[63] = t22) : t22 = $[63];
2665
+ let t23 = resizing ? splitTransitionClasses.resize : "none", t24;
2666
+ $[64] !== studio || $[65] !== theme ? (t24 = /* @__PURE__ */ jsx(StudioPreview, {
2667
+ ref: studioRef,
2449
2668
  theme,
2450
- children: layoutProps.renderDefault(layoutProps)
2451
- }), t16;
2452
- return $[34] !== context || $[35] !== t14.Provider || $[36] !== t15 ? (t16 = /* @__PURE__ */ jsx(t14.Provider, {
2669
+ children: studio
2670
+ }), $[64] = studio, $[65] = theme, $[66] = t24) : t24 = $[66];
2671
+ let t25;
2672
+ $[67] !== stopResizing || $[68] !== t23 || $[69] !== t24 ? (t25 = /* @__PURE__ */ jsx(ViewTransition, {
2673
+ onUpdate: stopResizing,
2674
+ update: t23,
2675
+ children: t24
2676
+ }, "primary"), $[67] = stopResizing, $[68] = t23, $[69] = t24, $[70] = t25) : t25 = $[70];
2677
+ let t26 = shown.open ? "visible" : "hidden", t27 = theme ?? void 0, t28;
2678
+ $[71] === mobile ? t28 = $[72] : (t28 = /* @__PURE__ */ jsx(ResizableSidebar, { overlay: mobile }), $[71] = mobile, $[72] = t28);
2679
+ let t29;
2680
+ $[73] !== t27 || $[74] !== t28 ? (t29 = /* @__PURE__ */ jsx(ViewTransition, {
2681
+ enter: panelTransitionClasses.slideIn,
2682
+ exit: panelTransitionClasses.slideOut,
2683
+ update: "none",
2684
+ children: /* @__PURE__ */ jsx(ThemeProvider, {
2685
+ theme: t27,
2686
+ children: t28
2687
+ })
2688
+ }, "panel"), $[73] = t27, $[74] = t28, $[75] = t29) : t29 = $[75];
2689
+ let t30;
2690
+ $[76] !== t26 || $[77] !== t29 ? (t30 = /* @__PURE__ */ jsx(Activity, {
2691
+ mode: t26,
2692
+ children: t29
2693
+ }), $[76] = t26, $[77] = t29, $[78] = t30) : t30 = $[78];
2694
+ let t31;
2695
+ $[79] !== t21 || $[80] !== t22 || $[81] !== t25 || $[82] !== t30 ? (t31 = /* @__PURE__ */ jsxs(Flex, {
2696
+ className: layout,
2697
+ direction: t21,
2698
+ height: "fill",
2699
+ sizing: "border",
2700
+ children: [
2701
+ t22,
2702
+ t25,
2703
+ t30
2704
+ ]
2705
+ }), $[79] = t21, $[80] = t22, $[81] = t25, $[82] = t30, $[83] = t31) : t31 = $[83];
2706
+ let t32;
2707
+ return $[84] !== context || $[85] !== t31 ? (t32 = /* @__PURE__ */ jsx(ThemerContext.Provider, {
2453
2708
  value: context,
2454
- children: t15
2455
- }), $[34] = context, $[35] = t14.Provider, $[36] = t15, $[37] = t16) : t16 = $[37], t16;
2709
+ children: t31
2710
+ }), $[84] = context, $[85] = t31, $[86] = t32) : t32 = $[86], t32;
2711
+ }
2712
+ /**
2713
+ * One copy of the Studio, in the given color scheme — or, without one, in the
2714
+ * scheme the Studio is showing. The configured theme (`null`) goes through
2715
+ * the provider too, inheriting the Studio's, so picking a theme swaps it
2716
+ * instead of remounting the Studio under a new provider.
2717
+ *
2718
+ * The two copies of the split preview share the router, the document store
2719
+ * and every other provider above the layout — only the scheme differs — so
2720
+ * they stay in sync while navigating. The `color-scheme` of a forced scheme
2721
+ * keeps native form controls and scrollbars in step with it.
2722
+ */
2723
+ function StudioPreview(props) {
2724
+ let $ = c(10), { borderBottom, borderRight, children, ref, scheme, theme } = props, t0 = theme ?? void 0, t1 = scheme ? studioScheme[scheme] : void 0, t2;
2725
+ $[0] !== borderBottom || $[1] !== borderRight || $[2] !== children || $[3] !== ref || $[4] !== t1 ? (t2 = /* @__PURE__ */ jsx(Card, {
2726
+ borderBottom,
2727
+ borderRight,
2728
+ className: t1,
2729
+ flex: 1,
2730
+ height: "fill",
2731
+ overflow: "hidden",
2732
+ ref,
2733
+ children
2734
+ }), $[0] = borderBottom, $[1] = borderRight, $[2] = children, $[3] = ref, $[4] = t1, $[5] = t2) : t2 = $[5];
2735
+ let t3;
2736
+ return $[6] !== scheme || $[7] !== t0 || $[8] !== t2 ? (t3 = /* @__PURE__ */ jsx(ThemeProvider, {
2737
+ scheme,
2738
+ theme: t0,
2739
+ children: t2
2740
+ }), $[6] = scheme, $[7] = t0, $[8] = t2, $[9] = t3) : t3 = $[9], t3;
2456
2741
  }
2457
2742
  function ThemerNavbarButton() {
2458
2743
  let $ = c(6), { open, send } = useThemer(), t0;
@@ -2482,6 +2767,9 @@ function ThemerNavbarButton() {
2482
2767
  * navbar — an icon button with a tooltip in the top bar (like the Tasks
2483
2768
  * toggle), and a regular titled action in the narrow-screen sidebar menu.
2484
2769
  *
2770
+ * In the split preview every Studio copy renders its own navbar, so the
2771
+ * toggle shows up in both — they drive the same sidebar.
2772
+ *
2485
2773
  * @internal
2486
2774
  */
2487
2775
  function ThemerNavbar(props) {
@@ -2517,15 +2805,16 @@ function _temp() {
2517
2805
  }
2518
2806
  /**
2519
2807
  * A Studio plugin that adds a themer sidebar for `buildTheme` themes: a
2520
- * navbar toggle opens the sidebar next to the active tool, with a list of
2521
- * themes — the configured theme, the presets and your own — each previewed
2522
- * as a tiny Studio in both color schemes. Picking one applies it live to the
2523
- * whole Studio while you browse around; your own themes can be edited with
2808
+ * navbar toggle opens the sidebar next to the Studio, with a list of themes —
2809
+ * the configured theme, the presets and your own — each previewed as a tiny
2810
+ * Studio in both color schemes. Picking one applies it live to the whole
2811
+ * Studio while you browse around; your own themes can be edited with
2524
2812
  * accent/text/background pickers and a contrast slider per scheme, added,
2525
2813
  * duplicated, given the colors of an image (its palette is read on device),
2526
2814
  * removed and restored, and a dialog shows the `buildTheme` snippet that
2527
2815
  * makes the applied theme permanent. Toggle between light and dark mode with
2528
- * the regular appearance menu — the preview follows it.
2816
+ * the regular appearance menu — the preview follows it — or split the
2817
+ * preview to see the whole Studio in light and dark side by side.
2529
2818
  *
2530
2819
  * ```ts
2531
2820
  * import {themerTool} from '@sanity/themer/tool'
@@ -2555,8 +2844,7 @@ const themerTool = definePlugin((options) => {
2555
2844
  name: "@sanity/themer/tool",
2556
2845
  studio: { components: {
2557
2846
  layout: ThemerLayoutWithOptions,
2558
- navbar: ThemerNavbar,
2559
- activeToolLayout: ThemerActiveToolLayout
2847
+ navbar: ThemerNavbar
2560
2848
  } }
2561
2849
  };
2562
2850
  });