@sanity/themer

0.8.10.9.0
dist/ResizableSidebar-BpgLA4XQ.js.map
+dist/ResizableSidebar-BpgLA4XQ.js.mapNew file
+1
Index: package/dist/ResizableSidebar-BpgLA4XQ.js.map
===================================================================
--- package/dist/ResizableSidebar-BpgLA4XQ.js.map
+++ package/dist/ResizableSidebar-BpgLA4XQ.js.map
@@ -0,0 +1,1 @@
+{"version":3,"file":"ResizableSidebar-BpgLA4XQ.js","names":["root","() => lastGutter","() => {\n    const element = ref.current\n\n    if (!element) return undefined\n\n    // The reserved gutter is the part of the box the content cannot use\n    const measure = () => {\n      lastGutter = element.offsetWidth - element.clientWidth\n      setGutter(lastGutter)\n    }\n\n    measure()\n\n    const observer = new ResizeObserver(measure)\n\n    observer.observe(element)\n\n    return () => observer.disconnect()\n  }","[]","{\n      left: space[padding],\n      right: Math.max(0, space[padding] - gutter),\n      bottom: space[padding],\n    }","space[padding]","Math.max(0, space[padding] - gutter)","useMemo<ScrollAreaInset>(\n    () => ({\n      left: space[padding],\n      right: Math.max(0, space[padding] - gutter),\n      bottom: space[padding],\n    }),\n    [gutter, padding, space],\n  )","{paddingRight: inset.right}","right","<ScrollAreaInsetContext value={inset}>{children}</ScrollAreaInsetContext>","<Box\n      className={root}\n      flex={1}\n      overflow=\"auto\"\n      padding={padding}\n      ref={ref}\n      style={{paddingRight: inset.right}}\n    >\n      <ScrollAreaInsetContext value={inset}>{children}</ScrollAreaInsetContext>\n    </Box>","{marginLeft: -left, marginRight: -right, marginBottom: -bottom}","-left","-right","-bottom","<div style={{marginLeft: -left, marginRight: -right, marginBottom: -bottom}}>\n      {props.children}\n    </div>","children","_c","_temp","root","root","buildTheme(options)","useMemo(() => buildTheme(options), [options])","<MockStudio scheme=\"light\" />","<ThemeProvider scheme=\"light\" theme={theme} tone=\"default\">\n        <MockStudio scheme=\"light\" />\n      </ThemeProvider>","<MockStudio scheme=\"dark\" />","<ThemeProvider scheme=\"dark\" theme={theme} tone=\"default\">\n        <MockStudio scheme=\"dark\" />\n      </ThemeProvider>","<div aria-hidden className={root}>\n      <ThemeProvider scheme=\"light\" theme={theme} tone=\"default\">\n        <MockStudio scheme=\"light\" />\n      </ThemeProvider>\n      <ThemeProvider scheme=\"dark\" theme={theme} tone=\"default\">\n        <MockStudio scheme=\"dark\" />\n      </ThemeProvider>\n    </div>","assignInlineVars({\n        [colors.bg]: color.bg,\n        [colors.fg]: color.fg,\n        [colors.mutedFg]: color.muted.fg,\n        [colors.border]: color.border,\n        [colors.accent]: color.button.default.primary.enabled.bg,\n        [colors.avatar]: color.avatar.blue.bg,\n        [colors.selectedBg]: selected.bg,\n        [colors.selectedFg]: selected.fg,\n        [colors.inputBg]: inputColor.bg,\n        [colors.inputBorder]: inputColor.border,\n      })","bg","border","fg","<div className={logo} />","<div className={navbar}>\n        <div className={logo} />\n        <div className={line.fg} style={{width: '22%'}} />\n        <div className={spacer} />\n        <div className={avatar} />\n      </div>","<div className={list}>\n          {LIST_ROWS.map((width, index) => {\n            const isSelected = index === 1\n\n            return (\n              <div key={width} className={listRow} data-selected={isSelected}>\n                <div className={isSelected ? line.selected : line.muted} style={{width}} />\n              </div>\n            )\n          })}\n        </div>","(width, index) => {\n            const isSelected = index === 1\n\n            return (\n              <div key={width} className={listRow} data-selected={isSelected}>\n                <div className={isSelected ? line.selected : line.muted} style={{width}} />\n              </div>\n            )\n          }","<div className={form}>\n            <div className={line.fg} style={{width: '45%'}} />\n            {FIELDS.map((width) => (\n              <div key={width} className={field}>\n                <div className={line.muted} style={{width}} />\n                <div className={input} />\n              </div>\n            ))}\n          </div>","(width) => (\n              <div key={width} className={field}>\n                <div className={line.muted} style={{width}} />\n                <div className={input} />\n              </div>\n            )","<div className={body}>\n        <div className={list}>\n          {LIST_ROWS.map((width, index) => {\n            const isSelected = index === 1\n\n            return (\n              <div key={width} className={listRow} data-selected={isSelected}>\n                <div className={isSelected ? line.selected : line.muted} style={{width}} />\n              </div>\n            )\n          })}\n        </div>\n\n        <div className={pane}>\n          <div className={form}>\n            <div className={line.fg} style={{width: '45%'}} />\n            {FIELDS.map((width) => (\n              <div key={width} className={field}>\n                <div className={line.muted} style={{width}} />\n                <div className={input} />\n              </div>\n            ))}\n          </div>\n          <div className={footer}>\n            <div className={button} />\n          </div>\n        </div>\n      </div>","<div\n      className={studio[scheme]}\n      style={assignInlineVars({\n        [colors.bg]: color.bg,\n        [colors.fg]: color.fg,\n        [colors.mutedFg]: color.muted.fg,\n        [colors.border]: color.border,\n        [colors.accent]: color.button.default.primary.enabled.bg,\n        [colors.avatar]: color.avatar.blue.bg,\n        [colors.selectedBg]: selected.bg,\n        [colors.selectedFg]: selected.fg,\n        [colors.inputBg]: inputColor.bg,\n        [colors.inputBorder]: inputColor.border,\n      })}\n    >\n      <div className={navbar}>\n        <div className={logo} />\n        <div className={line.fg} style={{width: '22%'}} />\n        <div className={spacer} />\n        <div className={avatar} />\n      </div>\n\n      <div className={body}>\n        <div className={list}>\n          {LIST_ROWS.map((width, index) => {\n            const isSelected = index === 1\n\n            return (\n              <div key={width} className={listRow} data-selected={isSelected}>\n                <div className={isSelected ? line.selected : line.muted} style={{width}} />\n              </div>\n            )\n          })}\n        </div>\n\n        <div className={pane}>\n          <div className={form}>\n            <div className={line.fg} style={{width: '45%'}} />\n            {FIELDS.map((width) => (\n              <div key={width} className={field}>\n                <div className={line.muted} style={{width}} />\n                <div className={input} />\n              </div>\n            ))}\n          </div>\n          <div className={footer}>\n            <div className={button} />\n          </div>\n        </div>\n      </div>\n    </div>","studio[scheme]","width","FIELDS","_c","root","_temp","_temp2","<Card overflow=\"hidden\" radius={3} shadow={1}>\n      <ThemePreview options={props.options} />\n    </Card>","options","_c","{actorRef, removed}: Pick<ThemerProps, 'actorRef' | 'removed'>","removed.map((theme) => (\n          <Stack key={theme.slug} gap={3}>\n            <Box className={removedThumbnail}>\n              <ThemeThumbnail options={theme.options} />\n            </Box>\n            <Text align=\"center\" size={1} textOverflow=\"ellipsis\">\n              {displayTitle(theme.title)}\n            </Text>\n            <Flex gap={2} justify=\"center\">\n              <Button\n                mode=\"ghost\"\n                onClick={() => actorRef.send({type: 'theme.restore', slug: theme.slug})}\n                padding={2}\n                text=\"Restore\"\n              />\n              {theme.source === 'custom' && (\n                <Button\n                  mode=\"ghost\"\n                  onClick={() => actorRef.send({type: 'theme.delete', slug: theme.slug})}\n                  padding={2}\n                  text=\"Delete\"\n                  tone=\"critical\"\n                />\n              )}\n            </Flex>\n          </Stack>\n        ))","(theme) => (\n          <Stack key={theme.slug} gap={3}>\n            <Box className={removedThumbnail}>\n              <ThemeThumbnail options={theme.options} />\n            </Box>\n            <Text align=\"center\" size={1} textOverflow=\"ellipsis\">\n              {displayTitle(theme.title)}\n            </Text>\n            <Flex gap={2} justify=\"center\">\n              <Button\n                mode=\"ghost\"\n                onClick={() => actorRef.send({type: 'theme.restore', slug: theme.slug})}\n                padding={2}\n                text=\"Restore\"\n              />\n              {theme.source === 'custom' && (\n                <Button\n                  mode=\"ghost\"\n                  onClick={() => actorRef.send({type: 'theme.delete', slug: theme.slug})}\n                  padding={2}\n                  text=\"Delete\"\n                  tone=\"critical\"\n                />\n              )}\n            </Flex>\n          </Stack>\n        )","<ScrollArea padding={3}>\n      <Stack gap={5}>\n        {removed.map((theme) => (\n          <Stack key={theme.slug} gap={3}>\n            <Box className={removedThumbnail}>\n              <ThemeThumbnail options={theme.options} />\n            </Box>\n            <Text align=\"center\" size={1} textOverflow=\"ellipsis\">\n              {displayTitle(theme.title)}\n            </Text>\n            <Flex gap={2} justify=\"center\">\n              <Button\n                mode=\"ghost\"\n                onClick={() => actorRef.send({type: 'theme.restore', slug: theme.slug})}\n                padding={2}\n                text=\"Restore\"\n              />\n              {theme.source === 'custom' && (\n                <Button\n                  mode=\"ghost\"\n                  onClick={() => actorRef.send({type: 'theme.delete', slug: theme.slug})}\n                  padding={2}\n                  text=\"Delete\"\n                  tone=\"critical\"\n                />\n              )}\n            </Flex>\n          </Stack>\n        ))}\n      </Stack>\n    </ScrollArea>","_c","<Text size={1}>{tooltip}</Text>","<Button\n        aria-label={buttonProps.text === undefined ? tooltip : undefined}\n        gap={2}\n        padding={2}\n        {...buttonProps}\n      />","buttonProps.text === undefined ? tooltip : undefined","<Tooltip animate content={<Text size={1}>{tooltip}</Text>} placement=\"bottom\" portal>\n      <Button\n        aria-label={buttonProps.text === undefined ? tooltip : undefined}\n        gap={2}\n        padding={2}\n        {...buttonProps}\n      />\n    </Tooltip>","_c","() => inputRef.current?.click()","<TooltipButton {...buttonProps} icon={ImageIcon} onClick={() => inputRef.current?.click()} />","<input\n        accept=\"image/*\"\n        hidden\n        onChange={(event) => {\n          const file = event.currentTarget.files?.[0]\n\n          // Picking the same file again should work, so the input forgets it\n          event.currentTarget.value = ''\n\n          if (file) onFile(file)\n        }}\n        ref={inputRef}\n        type=\"file\"\n      />","<>\n      <TooltipButton {...buttonProps} icon={ImageIcon} onClick={() => inputRef.current?.click()} />\n      <input\n        accept=\"image/*\"\n        hidden\n        onChange={(event) => {\n          const file = event.currentTarget.files?.[0]\n\n          // Picking the same file again should work, so the input forgets it\n          event.currentTarget.value = ''\n\n          if (file) onFile(file)\n        }}\n        ref={inputRef}\n        type=\"file\"\n      />\n    </>","_c","_Fragment","() => {\n    onPaletteRef.current = onPalette\n  }","[onPalette]","() => {\n    mountedRef.current = true\n\n    return () => {\n      mountedRef.current = false\n    }\n  }","[]","(file: File) => {\n      const pick = ++latestPickRef.current\n\n      setBusy(true)\n\n      // Whether this pick still matters: it is the latest one and the\n      // component that asked for it is still around\n      const isCurrent = () => mountedRef.current && latestPickRef.current === pick\n\n      const extract = async () => {\n        const palette = extractImagePalette(await readImagePixels(file))\n\n        if (!isCurrent()) return\n\n        if (Object.values(palette).every((swatch) => swatch === null)) {\n          toast.push({status: 'warning', title: 'Found no colors in that image'})\n        } else {\n          onPaletteRef.current(palette, file)\n        }\n      }\n\n      extract()\n        .catch(() => {\n          if (isCurrent()) toast.push({status: 'error', title: 'Could not read that image'})\n        })\n        .finally(() => {\n          if (isCurrent()) setBusy(false)\n        })\n    }","(swatch) => swatch === null","useCallback(\n    (file: File) => {\n      const pick = ++latestPickRef.current\n\n      setBusy(true)\n\n      // Whether this pick still matters: it is the latest one and the\n      // component that asked for it is still around\n      const isCurrent = () => mountedRef.current && latestPickRef.current === pick\n\n      const extract = async () => {\n        const palette = extractImagePalette(await readImagePixels(file))\n\n        if (!isCurrent()) return\n\n        if (Object.values(palette).every((swatch) => swatch === null)) {\n          toast.push({status: 'warning', title: 'Found no colors in that image'})\n        } else {\n          onPaletteRef.current(palette, file)\n        }\n      }\n\n      extract()\n        .catch(() => {\n          if (isCurrent()) toast.push({status: 'error', title: 'Could not read that image'})\n        })\n        .finally(() => {\n          if (isCurrent()) setBusy(false)\n        })\n    },\n    [toast],\n  )","{busy, pickImage}","_c","_temp","palette ? currentImageVariant(options, palette) : null","() => {\n    const row = rowRef.current\n\n    if (!row) return undefined\n\n    const measure = () => {\n      const visible =\n        row.clientWidth - ROW_PADDING - (Math.ceil(VISIBLE_VARIANTS) - 1) * VARIANT_GAP\n\n      // Each variant is its thumbnail plus the frame on either side\n      setThumbnailWidth(Math.max(24, Math.floor(visible / VISIBLE_VARIANTS) - VARIANT_FRAME * 2))\n    }\n\n    measure()\n\n    const observer = new ResizeObserver(measure)\n\n    observer.observe(row)\n\n    return () => observer.disconnect()\n    // oxlint-disable-next-line react/exhaustive-effect-dependencies -- the row only renders with a palette, so a new palette has a new row to observe\n  }","[palette]","useMemo(() => {\n    if (!palette) return []\n\n    return IMAGE_PALETTE_VARIANTS.flatMap((variant) =>\n      palette[variant] === null\n        ? []\n        : [\n            {\n              variant,\n              title: IMAGE_PALETTE_TITLES[variant],\n              options: applyImagePalette(options, palette, variant),\n            },\n          ],\n    )\n  }, [options, palette])","[]","IMAGE_PALETTE_VARIANTS.flatMap((variant) =>\n      palette[variant] === null\n        ? []\n        : [\n            {\n              variant,\n              title: IMAGE_PALETTE_TITLES[variant],\n              options: applyImagePalette(options, palette, variant),\n            },\n          ],\n    )","(event) => {\n        event.preventDefault()\n        dragDepth.current++\n        setDragging(true)\n      }","() => {\n        dragDepth.current = Math.max(0, dragDepth.current - 1)\n\n        if (dragDepth.current === 0) setDragging(false)\n      }","(event) => {\n        event.preventDefault()\n        dragDepth.current = 0\n        setDragging(false)\n\n        const file = event.dataTransfer.files[0]\n\n        if (file) pickImage(file)\n      }","event","<Box flex={1}>\n            <Text size={1} weight=\"medium\">\n              Image palette\n            </Text>\n          </Box>","palette && (\n            <ImageFileButton\n              loading={busy}\n              mode=\"bleed\"\n              onFile={pickImage}\n              padding={2}\n              tooltip=\"Pick another image\"\n            />\n          )","<Flex align=\"center\" gap={2}>\n          <Box flex={1}>\n            <Text size={1} weight=\"medium\">\n              Image palette\n            </Text>\n          </Box>\n          {palette && (\n            <ImageFileButton\n              loading={busy}\n              mode=\"bleed\"\n              onFile={pickImage}\n              padding={2}\n              tooltip=\"Pick another image\"\n            />\n          )}\n        </Flex>","palette ? (\n          <>\n            <div className={paletteGrid} data-with-image={imageUrl !== undefined}>\n              {imageUrl && <img alt=\"\" className={imageTile} src={imageUrl} />}\n              {TILES.map((key) => {\n                const hex = palette[key]\n                const title = IMAGE_PALETTE_TITLES[key]\n\n                return (\n                  <Tooltip\n                    key={key}\n                    animate\n                    content={\n                      <Text size={1}>\n                        {hex ? `${title} · ${hex}` : `No ${title.toLowerCase()} color`}\n                      </Text>\n                    }\n\n                    placement=\"bottom\"\n                    portal\n                  >\n                    <span\n                      className={tile}\n                      data-empty={hex === null}\n                      style={{background: hex ?? undefined}}\n                    />\n                  </Tooltip>\n                )\n              })}\n            </div>\n\n            <Stack gap={2}>\n              <Text muted size={0}>\n                Pick the swatch to build the theme around\n              </Text>\n              <div\n                className={variantRow}\n                ref={rowRef}\n                style={assignInlineVars({\n                  [variantWidth]: `${thumbnailWidth}px`,\n                  [variantScale]: String(thumbnailWidth / VARIANT_WIDTH),\n                })}\n              >\n                {variants.map(({variant, title, options: variantOptions}) => (\n                  // oxlint-disable-next-line control-has-associated-label -- the title below the thumbnail is the label, deeper than the rule looks\n                  <button\n                    key={variant}\n                    aria-pressed={variant === current}\n                    className={variantButton}\n                    onClick={() => onVariant(variant)}\n                    type=\"button\"\n                  >\n                    <span className={variantFrame}>\n                      <span className={variantScaleBox}>\n                        <ThemeThumbnail options={variantOptions} />\n                      </span>\n                    </span>\n                    <Box as=\"span\" display=\"block\" paddingTop={1}>\n                      <Text\n                        align=\"center\"\n                        as=\"span\"\n                        size={0}\n                        textOverflow=\"ellipsis\"\n                        weight={variant === current ? 'medium' : 'regular'}\n                      >\n                        {title}\n                      </Text>\n                    </Box>\n                  </button>\n                ))}\n              </div>\n            </Stack>\n\n            <TooltipButton\n              icon={SparklesIcon}\n              mode=\"ghost\"\n              onClick={onLucky}\n              text=\"I'm feeling lucky\"\n              tooltip=\"Build the theme around a swatch that looks interesting\"\n              width=\"fill\"\n            />\n          </>\n        ) : (\n          <Stack gap={3}>\n            <Text muted size={0}>\n              Take the accent, text and background colors from an image — read on device, nothing is\n              uploaded.\n            </Text>\n            <ImageFileButton\n              loading={busy}\n              mode=\"ghost\"\n              onFile={pickImage}\n              text=\"Pick an image\"\n              tooltip=\"Take the colors from an image on your device\"\n              width=\"fill\"\n            />\n          </Stack>\n        )","{variant, title, options: variantOptions}","variant","title","<Stack gap={3}>\n        <Flex align=\"center\" gap={2}>\n          <Box flex={1}>\n            <Text size={1} weight=\"medium\">\n              Image palette\n            </Text>\n          </Box>\n          {palette && (\n            <ImageFileButton\n              loading={busy}\n              mode=\"bleed\"\n              onFile={pickImage}\n              padding={2}\n              tooltip=\"Pick another image\"\n            />\n          )}\n        </Flex>\n\n        {palette ? (\n          <>\n            <div className={paletteGrid} data-with-image={imageUrl !== undefined}>\n              {imageUrl && <img alt=\"\" className={imageTile} src={imageUrl} />}\n              {TILES.map((key) => {\n                const hex = palette[key]\n                const title = IMAGE_PALETTE_TITLES[key]\n\n                return (\n                  <Tooltip\n                    key={key}\n                    animate\n                    content={\n                      <Text size={1}>\n                        {hex ? `${title} · ${hex}` : `No ${title.toLowerCase()} color`}\n                      </Text>\n                    }\n\n                    placement=\"bottom\"\n                    portal\n                  >\n                    <span\n                      className={tile}\n                      data-empty={hex === null}\n                      style={{background: hex ?? undefined}}\n                    />\n                  </Tooltip>\n                )\n              })}\n            </div>\n\n            <Stack gap={2}>\n              <Text muted size={0}>\n                Pick the swatch to build the theme around\n              </Text>\n              <div\n                className={variantRow}\n                ref={rowRef}\n                style={assignInlineVars({\n                  [variantWidth]: `${thumbnailWidth}px`,\n                  [variantScale]: String(thumbnailWidth / VARIANT_WIDTH),\n                })}\n              >\n                {variants.map(({variant, title, options: variantOptions}) => (\n                  // oxlint-disable-next-line control-has-associated-label -- the title below the thumbnail is the label, deeper than the rule looks\n                  <button\n                    key={variant}\n                    aria-pressed={variant === current}\n                    className={variantButton}\n                    onClick={() => onVariant(variant)}\n                    type=\"button\"\n                  >\n                    <span className={variantFrame}>\n                      <span className={variantScaleBox}>\n                        <ThemeThumbnail options={variantOptions} />\n                      </span>\n                    </span>\n                    <Box as=\"span\" display=\"block\" paddingTop={1}>\n                      <Text\n                        align=\"center\"\n                        as=\"span\"\n                        size={0}\n                        textOverflow=\"ellipsis\"\n                        weight={variant === current ? 'medium' : 'regular'}\n                      >\n                        {title}\n                      </Text>\n                    </Box>\n                  </button>\n                ))}\n              </div>\n            </Stack>\n\n            <TooltipButton\n              icon={SparklesIcon}\n              mode=\"ghost\"\n              onClick={onLucky}\n              text=\"I'm feeling lucky\"\n              tooltip=\"Build the theme around a swatch that looks interesting\"\n              width=\"fill\"\n            />\n          </>\n        ) : (\n          <Stack gap={3}>\n            <Text muted size={0}>\n              Take the accent, text and background colors from an image — read on device, nothing is\n              uploaded.\n            </Text>\n            <ImageFileButton\n              loading={busy}\n              mode=\"ghost\"\n              onFile={pickImage}\n              text=\"Pick an image\"\n              tooltip=\"Take the colors from an image on your device\"\n              width=\"fill\"\n            />\n          </Stack>\n        )}\n      </Stack>","<Card\n      border\n      onDragEnter={(event) => {\n        event.preventDefault()\n        dragDepth.current++\n        setDragging(true)\n      }}\n      onDragLeave={() => {\n        dragDepth.current = Math.max(0, dragDepth.current - 1)\n\n        if (dragDepth.current === 0) setDragging(false)\n      }}\n      onDragOver={(event) => {\n        event.preventDefault()\n      }}\n      onDrop={(event) => {\n        event.preventDefault()\n        dragDepth.current = 0\n        setDragging(false)\n\n        const file = event.dataTransfer.files[0]\n\n        if (file) pickImage(file)\n      }}\n      padding={3}\n      radius={3}\n      tone={dragging ? 'primary' : 'default'}\n    >\n      <Stack gap={3}>\n        <Flex align=\"center\" gap={2}>\n          <Box flex={1}>\n            <Text size={1} weight=\"medium\">\n              Image palette\n            </Text>\n          </Box>\n          {palette && (\n            <ImageFileButton\n              loading={busy}\n              mode=\"bleed\"\n              onFile={pickImage}\n              padding={2}\n              tooltip=\"Pick another image\"\n            />\n          )}\n        </Flex>\n\n        {palette ? (\n          <>\n            <div className={paletteGrid} data-with-image={imageUrl !== undefined}>\n              {imageUrl && <img alt=\"\" className={imageTile} src={imageUrl} />}\n              {TILES.map((key) => {\n                const hex = palette[key]\n                const title = IMAGE_PALETTE_TITLES[key]\n\n                return (\n                  <Tooltip\n                    key={key}\n                    animate\n                    content={\n                      <Text size={1}>\n                        {hex ? `${title} · ${hex}` : `No ${title.toLowerCase()} color`}\n                      </Text>\n                    }\n\n                    placement=\"bottom\"\n                    portal\n                  >\n                    <span\n                      className={tile}\n                      data-empty={hex === null}\n                      style={{background: hex ?? undefined}}\n                    />\n                  </Tooltip>\n                )\n              })}\n            </div>\n\n            <Stack gap={2}>\n              <Text muted size={0}>\n                Pick the swatch to build the theme around\n              </Text>\n              <div\n                className={variantRow}\n                ref={rowRef}\n                style={assignInlineVars({\n                  [variantWidth]: `${thumbnailWidth}px`,\n                  [variantScale]: String(thumbnailWidth / VARIANT_WIDTH),\n                })}\n              >\n                {variants.map(({variant, title, options: variantOptions}) => (\n                  // oxlint-disable-next-line control-has-associated-label -- the title below the thumbnail is the label, deeper than the rule looks\n                  <button\n                    key={variant}\n                    aria-pressed={variant === current}\n                    className={variantButton}\n                    onClick={() => onVariant(variant)}\n                    type=\"button\"\n                  >\n                    <span className={variantFrame}>\n                      <span className={variantScaleBox}>\n                        <ThemeThumbnail options={variantOptions} />\n                      </span>\n                    </span>\n                    <Box as=\"span\" display=\"block\" paddingTop={1}>\n                      <Text\n                        align=\"center\"\n                        as=\"span\"\n                        size={0}\n                        textOverflow=\"ellipsis\"\n                        weight={variant === current ? 'medium' : 'regular'}\n                      >\n                        {title}\n                      </Text>\n                    </Box>\n                  </button>\n                ))}\n              </div>\n            </Stack>\n\n            <TooltipButton\n              icon={SparklesIcon}\n              mode=\"ghost\"\n              onClick={onLucky}\n              text=\"I'm feeling lucky\"\n              tooltip=\"Build the theme around a swatch that looks interesting\"\n              width=\"fill\"\n            />\n          </>\n        ) : (\n          <Stack gap={3}>\n            <Text muted size={0}>\n              Take the accent, text and background colors from an image — read on device, nothing is\n              uploaded.\n            </Text>\n            <ImageFileButton\n              loading={busy}\n              mode=\"ghost\"\n              onFile={pickImage}\n              text=\"Pick an image\"\n              tooltip=\"Take the colors from an image on your device\"\n              width=\"fill\"\n            />\n          </Stack>\n        )}\n      </Stack>\n    </Card>","dragging ? 'primary' : 'default'","(event) => {\n        event.preventDefault()\n      }","_c","_Fragment","_temp","{\n  actorRef,\n  focusTitle,\n  slug,\n  split,\n  themes,\n}: {focusTitle: boolean; slug: string} & Pick<ThemerProps, 'actorRef' | 'split' | 'themes'>","(snapshot) => snapshot.context.images","themes.find((candidate) => candidate.slug === slug && candidate.source === 'custom')","(candidate) => candidate.slug === slug && candidate.source === 'custom'","(variant: ImagePaletteVariant | null) => {\n    if (!theme.palette || variant === null) return\n\n    actorRef.send({\n      type: 'theme.update',\n      slug,\n      options: applyImagePalette(theme.options, theme.palette, variant),\n    })\n  }","options","palette","() => actorRef.send({type: 'flow.list'})","() => {\n        if (!theme.palette) return\n\n        applyVariant(\n          pickLuckyVariant(theme.palette, {\n            exclude: currentImageVariant(theme.options, theme.palette),\n          }),\n        )\n      }","(options) => actorRef.send({type: 'theme.update', slug, options})","(palette, file) =>\n        actorRef.send({\n          type: 'theme.update',\n          slug,\n          options: applyImagePalette(theme.options, palette),\n          palette,\n          imageUrl: URL.createObjectURL(file),\n        })","() => actorRef.send({type: 'theme.remove', slug})","(title) => actorRef.send({type: 'theme.update', slug, title})","<ThemeEditorForm\n      focusTitle={focusTitle}\n      imageUrl={images[slug]}\n      onDone={() => actorRef.send({type: 'flow.list'})}\n      onLucky={() => {\n        if (!theme.palette) return\n\n        applyVariant(\n          pickLuckyVariant(theme.palette, {\n            exclude: currentImageVariant(theme.options, theme.palette),\n          }),\n        )\n      }}\n      onOptionsChange={(options) => actorRef.send({type: 'theme.update', slug, options})}\n      onPalette={(palette, file) =>\n        actorRef.send({\n          type: 'theme.update',\n          slug,\n          options: applyImagePalette(theme.options, palette),\n          palette,\n          imageUrl: URL.createObjectURL(file),\n        })\n      }\n      onRemove={() => actorRef.send({type: 'theme.remove', slug})}\n      onTitleChange={(title) => actorRef.send({type: 'theme.update', slug, title})}\n      onVariant={applyVariant}\n      options={theme.options}\n      palette={theme.palette}\n      split={split}\n      title={theme.title}\n    />","images[slug]","title","resolveThemeOptions(options)","useMemo(() => resolveThemeOptions(options), [options])","buildPalette(options)","useMemo(() => buildPalette(options), [options])","(scheme: ThemeColorSchemeKey, changes: Partial<SchemeThemeOptions>) => {\n    const values: SchemeThemeOptions = {...options[scheme], ...changes}\n\n    // Clearing an option means falling back to its default, which is its absence\n    for (const key of SCHEME_OPTION_KEYS) {\n      if (values[key] === undefined) delete values[key]\n    }\n\n    const next: BuildThemeOptions = {...options}\n\n    if (Object.keys(values).length === 0) {\n      delete next[scheme]\n    } else {\n      next[scheme] = values\n    }\n\n    onOptionsChange(next)\n  }","<ThemeThumbnail options={options} />","<Text size={1} weight=\"medium\">\n              Title\n            </Text>","(event) => onTitleChange(event.currentTarget.value)","(event) => event.currentTarget.select()","<Stack gap={2}>\n            <Text size={1} weight=\"medium\">\n              Title\n            </Text>\n            <TextInput\n              autoFocus={focusTitle}\n              fontSize={1}\n              onChange={(event) => onTitleChange(event.currentTarget.value)}\n              onFocus={focusTitle ? (event) => event.currentTarget.select() : undefined}\n              padding={2}\n              placeholder=\"Untitled theme\"\n              value={title}\n            />\n          </Stack>","focusTitle ? (event) => event.currentTarget.select() : undefined","<ImagePaletteSection\n            imageUrl={imageUrl}\n            onLucky={onLucky}\n            onPalette={onPalette}\n            onVariant={onVariant}\n            options={options}\n            palette={palette}\n          />","SCHEMES.map((scheme) => (\n              <SchemeCard\n                key={scheme}\n                active={split || scheme === studioScheme}\n                onChange={(changes) => patchScheme(scheme, changes)}\n                options={options[scheme] ?? {}}\n                palette={palettes[scheme]}\n                resolved={resolved[scheme]}\n                scheme={scheme}\n                split={split}\n                splitHint={splitHint(scheme === studioScheme)}\n              />\n            ))","scheme","changes","<ScrollAreaBleed>\n            {SCHEMES.map((scheme) => (\n              <SchemeCard\n                key={scheme}\n                active={split || scheme === studioScheme}\n                onChange={(changes) => patchScheme(scheme, changes)}\n                options={options[scheme] ?? {}}\n                palette={palettes[scheme]}\n                resolved={resolved[scheme]}\n                scheme={scheme}\n                split={split}\n                splitHint={splitHint(scheme === studioScheme)}\n              />\n            ))}\n          </ScrollAreaBleed>","<ScrollArea padding={3}>\n        <Stack gap={4}>\n          <ThemeThumbnail options={options} />\n\n          <Stack gap={2}>\n            <Text size={1} weight=\"medium\">\n              Title\n            </Text>\n            <TextInput\n              autoFocus={focusTitle}\n              fontSize={1}\n              onChange={(event) => onTitleChange(event.currentTarget.value)}\n              onFocus={focusTitle ? (event) => event.currentTarget.select() : undefined}\n              padding={2}\n              placeholder=\"Untitled theme\"\n              value={title}\n            />\n          </Stack>\n\n          <ImagePaletteSection\n            imageUrl={imageUrl}\n            onLucky={onLucky}\n            onPalette={onPalette}\n            onVariant={onVariant}\n            options={options}\n            palette={palette}\n          />\n\n          <ScrollAreaBleed>\n            {SCHEMES.map((scheme) => (\n              <SchemeCard\n                key={scheme}\n                active={split || scheme === studioScheme}\n                onChange={(changes) => patchScheme(scheme, changes)}\n                options={options[scheme] ?? {}}\n                palette={palettes[scheme]}\n                resolved={resolved[scheme]}\n                scheme={scheme}\n                split={split}\n                splitHint={splitHint(scheme === studioScheme)}\n              />\n            ))}\n          </ScrollAreaBleed>\n        </Stack>\n      </ScrollArea>","<TooltipButton\n            icon={TrashIcon}\n            mode=\"ghost\"\n            onClick={onRemove}\n            text=\"Remove\"\n            tone=\"critical\"\n            tooltip=\"Remove the theme — it can be restored until it is deleted\"\n          />","<Box flex={1} />","<Button mode=\"ghost\" onClick={onDone} padding={2} text=\"Done\" />","<Card borderTop padding={3}>\n        <Flex gap={2}>\n          <TooltipButton\n            icon={TrashIcon}\n            mode=\"ghost\"\n            onClick={onRemove}\n            text=\"Remove\"\n            tone=\"critical\"\n            tooltip=\"Remove the theme — it can be restored until it is deleted\"\n          />\n          <Box flex={1} />\n          <Button mode=\"ghost\" onClick={onDone} padding={2} text=\"Done\" />\n        </Flex>\n      </Card>","<>\n      <ScrollArea padding={3}>\n        <Stack gap={4}>\n          <ThemeThumbnail options={options} />\n\n          <Stack gap={2}>\n            <Text size={1} weight=\"medium\">\n              Title\n            </Text>\n            <TextInput\n              autoFocus={focusTitle}\n              fontSize={1}\n              onChange={(event) => onTitleChange(event.currentTarget.value)}\n              onFocus={focusTitle ? (event) => event.currentTarget.select() : undefined}\n              padding={2}\n              placeholder=\"Untitled theme\"\n              value={title}\n            />\n          </Stack>\n\n          <ImagePaletteSection\n            imageUrl={imageUrl}\n            onLucky={onLucky}\n            onPalette={onPalette}\n            onVariant={onVariant}\n            options={options}\n            palette={palette}\n          />\n\n          <ScrollAreaBleed>\n            {SCHEMES.map((scheme) => (\n              <SchemeCard\n                key={scheme}\n                active={split || scheme === studioScheme}\n                onChange={(changes) => patchScheme(scheme, changes)}\n                options={options[scheme] ?? {}}\n                palette={palettes[scheme]}\n                resolved={resolved[scheme]}\n                scheme={scheme}\n                split={split}\n                splitHint={splitHint(scheme === studioScheme)}\n              />\n            ))}\n          </ScrollAreaBleed>\n        </Stack>\n      </ScrollArea>\n\n      <Card borderTop padding={3}>\n        <Flex gap={2}>\n          <TooltipButton\n            icon={TrashIcon}\n            mode=\"ghost\"\n            onClick={onRemove}\n            text=\"Remove\"\n            tone=\"critical\"\n            tooltip=\"Remove the theme — it can be restored until it is deleted\"\n          />\n          <Box flex={1} />\n          <Button mode=\"ghost\" onClick={onDone} padding={2} text=\"Done\" />\n        </Flex>\n      </Card>\n    </>","event","<Box flex={1}>\n              <Text size={1} weight=\"medium\">\n                {name}\n              </Text>\n            </Box>","active && (\n              <Badge fontSize={0} tone=\"primary\">\n                Active\n              </Badge>\n            )","<Flex align=\"center\" gap={2}>\n            <Box flex={1}>\n              <Text size={1} weight=\"medium\">\n                {name}\n              </Text>\n            </Box>\n            {active && (\n              <Badge fontSize={0} tone=\"primary\">\n                Active\n              </Badge>\n            )}\n          </Flex>","<Text muted size={0}>\n            {split\n              ? splitHint\n              : active\n                ? 'Shown in the Studio right now'\n                : `Shown once the Studio appearance is ${scheme}`}\n          </Text>","split\n              ? splitHint\n              : active\n                ? 'Shown in the Studio right now'\n                : `Shown once the Studio appearance is ${scheme}`","<Stack gap={2}>\n          <Flex align=\"center\" gap={2}>\n            <Box flex={1}>\n              <Text size={1} weight=\"medium\">\n                {name}\n              </Text>\n            </Box>\n            {active && (\n              <Badge fontSize={0} tone=\"primary\">\n                Active\n              </Badge>\n            )}\n          </Flex>\n          <Text muted size={0}>\n            {split\n              ? splitHint\n              : active\n                ? 'Shown in the Studio right now'\n                : `Shown once the Studio appearance is ${scheme}`}\n          </Text>\n        </Stack>","(accent) => onChange({accent})","() => onChange({accent: undefined})","<ColorRow\n          auto={options.accent === undefined}\n          autoLabel=\"default\"\n          label={`${name} accent`}\n          onChange={(accent) => onChange({accent})}\n          onClear={() => onChange({accent: undefined})}\n          title=\"Accent\"\n          value={resolved.accent}\n        />","accent","options.accent === undefined","`${name} accent`","(text) => onChange({text})","() => onChange({text: undefined})","<ColorRow\n          auto={options.text === undefined}\n          label={`${name} text`}\n          onChange={(text) => onChange({text})}\n          onClear={() => onChange({text: undefined})}\n          title=\"Text\"\n          value={resolved.text}\n        />","text","options.text === undefined","`${name} text`","(background) => onChange({background})","() => onChange({background: undefined})","<ColorRow\n          adjusted={scheme === 'dark' ? palette.black : palette.white}\n          auto={options.background === undefined}\n          label={`${name} background`}\n          onChange={(background) => onChange({background})}\n          onClear={() => onChange({background: undefined})}\n          title=\"Background\"\n          value={resolved.background}\n        />","background","scheme === 'dark' ? palette.black : palette.white","options.background === undefined","`${name} background`","<Text size={1}>Contrast</Text>","<Stack flex={1} gap={2}>\n              <Text size={1}>Contrast</Text>\n              <Text muted size={0}>\n                {resolved.contrast}\n                {options.contrast === undefined ? ' · auto' : ''}\n              </Text>\n            </Stack>","contrast","options.contrast === undefined ? ' · auto' : ''","options.contrast !== undefined && (\n              <TooltipButton\n                icon={ResetIcon}\n                mode=\"bleed\"\n                onClick={() => onChange({contrast: undefined})}\n                padding={2}\n                tooltip=\"Reset to auto\"\n              />\n            )","<Flex align=\"center\" gap={2}>\n            <Stack flex={1} gap={2}>\n              <Text size={1}>Contrast</Text>\n              <Text muted size={0}>\n                {resolved.contrast}\n                {options.contrast === undefined ? ' · auto' : ''}\n              </Text>\n            </Stack>\n            {options.contrast !== undefined && (\n              <TooltipButton\n                icon={ResetIcon}\n                mode=\"bleed\"\n                onClick={() => onChange({contrast: undefined})}\n                padding={2}\n                tooltip=\"Reset to auto\"\n              />\n            )}\n          </Flex>","(event) => onChange({contrast: Number(event.currentTarget.value)})","<input\n            aria-label={`${name} contrast`}\n            className={range}\n            max={100}\n            min={15}\n            onChange={(event) => onChange({contrast: Number(event.currentTarget.value)})}\n            step={1}\n            type=\"range\"\n            value={resolved.contrast}\n          />","`${name} contrast`","<Text muted size={0}>\n            100 keeps text and borders neutral — lower values blend in the accent\n          </Text>","<Stack gap={3}>\n          <Flex align=\"center\" gap={2}>\n            <Stack flex={1} gap={2}>\n              <Text size={1}>Contrast</Text>\n              <Text muted size={0}>\n                {resolved.contrast}\n                {options.contrast === undefined ? ' · auto' : ''}\n              </Text>\n            </Stack>\n            {options.contrast !== undefined && (\n              <TooltipButton\n                icon={ResetIcon}\n                mode=\"bleed\"\n                onClick={() => onChange({contrast: undefined})}\n                padding={2}\n                tooltip=\"Reset to auto\"\n              />\n            )}\n          </Flex>\n          <input\n            aria-label={`${name} contrast`}\n            className={range}\n            max={100}\n            min={15}\n            onChange={(event) => onChange({contrast: Number(event.currentTarget.value)})}\n            step={1}\n            type=\"range\"\n            value={resolved.contrast}\n          />\n          <Text muted size={0}>\n            100 keeps text and borders neutral — lower values blend in the accent\n          </Text>\n        </Stack>","<Card borderTop padding={3}>\n      <Stack gap={4}>\n        <Stack gap={2}>\n          <Flex align=\"center\" gap={2}>\n            <Box flex={1}>\n              <Text size={1} weight=\"medium\">\n                {name}\n              </Text>\n            </Box>\n            {active && (\n              <Badge fontSize={0} tone=\"primary\">\n                Active\n              </Badge>\n            )}\n          </Flex>\n          <Text muted size={0}>\n            {split\n              ? splitHint\n              : active\n                ? 'Shown in the Studio right now'\n                : `Shown once the Studio appearance is ${scheme}`}\n          </Text>\n        </Stack>\n\n        <ColorRow\n          auto={options.accent === undefined}\n          autoLabel=\"default\"\n          label={`${name} accent`}\n          onChange={(accent) => onChange({accent})}\n          onClear={() => onChange({accent: undefined})}\n          title=\"Accent\"\n          value={resolved.accent}\n        />\n        <ColorRow\n          auto={options.text === undefined}\n          label={`${name} text`}\n          onChange={(text) => onChange({text})}\n          onClear={() => onChange({text: undefined})}\n          title=\"Text\"\n          value={resolved.text}\n        />\n        <ColorRow\n          adjusted={scheme === 'dark' ? palette.black : palette.white}\n          auto={options.background === undefined}\n          label={`${name} background`}\n          onChange={(background) => onChange({background})}\n          onClear={() => onChange({background: undefined})}\n          title=\"Background\"\n          value={resolved.background}\n        />\n\n        <Stack gap={3}>\n          <Flex align=\"center\" gap={2}>\n            <Stack flex={1} gap={2}>\n              <Text size={1}>Contrast</Text>\n              <Text muted size={0}>\n                {resolved.contrast}\n                {options.contrast === undefined ? ' · auto' : ''}\n              </Text>\n            </Stack>\n            {options.contrast !== undefined && (\n              <TooltipButton\n                icon={ResetIcon}\n                mode=\"bleed\"\n                onClick={() => onChange({contrast: undefined})}\n                padding={2}\n                tooltip=\"Reset to auto\"\n              />\n            )}\n          </Flex>\n          <input\n            aria-label={`${name} contrast`}\n            className={range}\n            max={100}\n            min={15}\n            onChange={(event) => onChange({contrast: Number(event.currentTarget.value)})}\n            step={1}\n            type=\"range\"\n            value={resolved.contrast}\n          />\n          <Text muted size={0}>\n            100 keeps text and borders neutral — lower values blend in the accent\n          </Text>\n        </Stack>\n      </Stack>\n    </Card>","autoLabel = 'auto'","(event) => onChange(event.currentTarget.value)","<input\n        aria-label={label}\n        className={swatch}\n        onChange={(event) => onChange(event.currentTarget.value)}\n        type=\"color\"\n        value={value}\n      />","<Text size={1}>{title}</Text>","<Text muted size={0} textOverflow=\"ellipsis\">\n          {value}\n          {adjusted !== undefined && adjusted !== value ? ` → ${adjusted}` : ''}\n          {auto ? ` · ${autoLabel}` : ''}\n        </Text>","adjusted !== undefined && adjusted !== value ? ` → ${adjusted}` : ''","auto ? ` · ${autoLabel}` : ''","<Stack className={colorRowText} flex={1} gap={2}>\n        <Text size={1}>{title}</Text>\n        <Text muted size={0} textOverflow=\"ellipsis\">\n          {value}\n          {adjusted !== undefined && adjusted !== value ? ` → ${adjusted}` : ''}\n          {auto ? ` · ${autoLabel}` : ''}\n        </Text>\n      </Stack>","onClear && !auto && (\n        <TooltipButton\n          icon={ResetIcon}\n          mode=\"bleed\"\n          onClick={onClear}\n          padding={2}\n          tooltip={`Reset to ${autoLabel}`}\n        />\n      )","<Flex align=\"center\" gap={2}>\n      <input\n        aria-label={label}\n        className={swatch}\n        onChange={(event) => onChange(event.currentTarget.value)}\n        type=\"color\"\n        value={value}\n      />\n      <Stack className={colorRowText} flex={1} gap={2}>\n        <Text size={1}>{title}</Text>\n        <Text muted size={0} textOverflow=\"ellipsis\">\n          {value}\n          {adjusted !== undefined && adjusted !== value ? ` → ${adjusted}` : ''}\n          {auto ? ` · ${autoLabel}` : ''}\n        </Text>\n      </Stack>\n      {onClear && !auto && (\n        <TooltipButton\n          icon={ResetIcon}\n          mode=\"bleed\"\n          onClick={onClear}\n          padding={2}\n          tooltip={`Reset to ${autoLabel}`}\n        />\n      )}\n    </Flex>","_c","_temp","_Fragment","{actorRef}: Pick<ThemerProps, 'actorRef'>","async (theme: SharedTheme) => {\n    const title = displayTitle(theme.title)\n\n    try {\n      await navigator.clipboard.writeText(encodeTheme(theme))\n      toast.push({\n        status: 'success',\n        title: `Copied ${title} as a code`,\n        description: 'Paste it in the themer of another Studio to add the theme there',\n      })\n    } catch {\n      toast.push({status: 'error', title: `Could not copy ${title}`})\n    }\n  }","(text: string) => {\n    const theme = decodeTheme(text)\n\n    if (!theme) return false\n\n    actorRef.send({type: 'theme.import', title: theme.title, options: theme.options})\n    toast.push({status: 'success', title: `Added ${theme.title}`})\n\n    return true\n  }","theme","async () => {\n    let text: string\n\n    try {\n      text = await navigator.clipboard.readText()\n    } catch {\n      return 'no-clipboard'\n    }\n\n    return addThemeFromText(text) ? 'added' : 'no-theme'\n  }","text","{copyTheme, addThemeFromText, addThemeFromClipboard}","() => {\n    const handlePaste = (event: ClipboardEvent) => {\n      if (isEditable(event.target)) return\n\n      const theme = decodeTheme(event.clipboardData?.getData('text/plain') ?? '')\n\n      if (!theme) return\n\n      event.preventDefault()\n      actorRef.send({type: 'theme.import', title: theme.title, options: theme.options})\n      toast.push({status: 'success', title: `Added ${theme.title}`})\n    }\n\n    document.addEventListener('paste', handlePaste)\n\n    return () => document.removeEventListener('paste', handlePaste)\n  }","[actorRef, toast]","_c","{actorRef}","() => {\n    if (addThemeFromText(text)) {\n      onClose()\n    } else {\n      setInvalid(true)\n    }\n  }","<Button mode=\"ghost\" onClick={onClose} padding={2} text=\"Cancel\" />","text.trim()","<Button\n            disabled={text.trim() === ''}\n            onClick={add}\n            padding={2}\n            text=\"Add theme\"\n            tone=\"primary\"\n          />","text.trim() === ''","<Flex gap={2} justify=\"flex-end\" padding={3}>\n          <Button mode=\"ghost\" onClick={onClose} padding={2} text=\"Cancel\" />\n          <Button\n            disabled={text.trim() === ''}\n            onClick={add}\n            padding={2}\n            text=\"Add theme\"\n            tone=\"primary\"\n          />\n        </Flex>","(event) => {\n          event.preventDefault()\n          add()\n        }","<Text muted size={1}>\n            Paste the code someone copied from their themer — the theme is added to your list and\n            applied.\n          </Text>","(event) => {\n              setText(event.currentTarget.value)\n              setInvalid(false)\n            }","event","<TextInput\n            aria-describedby={invalid ? 'themer-paste-error' : undefined}\n            aria-invalid={invalid}\n            aria-label=\"Theme code\"\n            autoFocus\n            customValidity={invalid ? 'That is not a theme code' : undefined}\n            fontSize={1}\n            onChange={(event) => {\n              setText(event.currentTarget.value)\n              setInvalid(false)\n            }}\n            placeholder=\"AQ…\"\n            value={text}\n          />","invalid ? 'That is not a theme code' : undefined","invalid ? 'themer-paste-error' : undefined","invalid && (\n            <Card id=\"themer-paste-error\" padding={3} radius={2} role=\"alert\" tone=\"critical\">\n              <Text size={1}>\n                That is not a theme code — codes are one word, copied from a theme&apos;s menu.\n              </Text>\n            </Card>\n          )","<Stack gap={3} padding={4}>\n          <Text muted size={1}>\n            Paste the code someone copied from their themer — the theme is added to your list and\n            applied.\n          </Text>\n          <TextInput\n            aria-describedby={invalid ? 'themer-paste-error' : undefined}\n            aria-invalid={invalid}\n            aria-label=\"Theme code\"\n            autoFocus\n            customValidity={invalid ? 'That is not a theme code' : undefined}\n            fontSize={1}\n            onChange={(event) => {\n              setText(event.currentTarget.value)\n              setInvalid(false)\n            }}\n            placeholder=\"AQ…\"\n            value={text}\n          />\n          {invalid && (\n            <Card id=\"themer-paste-error\" padding={3} radius={2} role=\"alert\" tone=\"critical\">\n              <Text size={1}>\n                That is not a theme code — codes are one word, copied from a theme&apos;s menu.\n              </Text>\n            </Card>\n          )}\n        </Stack>","<form\n        onSubmit={(event) => {\n          event.preventDefault()\n          add()\n        }}\n      >\n        <Stack gap={3} padding={4}>\n          <Text muted size={1}>\n            Paste the code someone copied from their themer — the theme is added to your list and\n            applied.\n          </Text>\n          <TextInput\n            aria-describedby={invalid ? 'themer-paste-error' : undefined}\n            aria-invalid={invalid}\n            aria-label=\"Theme code\"\n            autoFocus\n            customValidity={invalid ? 'That is not a theme code' : undefined}\n            fontSize={1}\n            onChange={(event) => {\n              setText(event.currentTarget.value)\n              setInvalid(false)\n            }}\n            placeholder=\"AQ…\"\n            value={text}\n          />\n          {invalid && (\n            <Card id=\"themer-paste-error\" padding={3} radius={2} role=\"alert\" tone=\"critical\">\n              <Text size={1}>\n                That is not a theme code — codes are one word, copied from a theme&apos;s menu.\n              </Text>\n            </Card>\n          )}\n        </Stack>\n      </form>","<Dialog\n      animate\n      footer={\n        <Flex gap={2} justify=\"flex-end\" padding={3}>\n          <Button mode=\"ghost\" onClick={onClose} padding={2} text=\"Cancel\" />\n          <Button\n            disabled={text.trim() === ''}\n            onClick={add}\n            padding={2}\n            text=\"Add theme\"\n            tone=\"primary\"\n          />\n        </Flex>\n      }\n      header=\"Add a shared theme\"\n      id=\"themer-paste\"\n      onClickOutside={onClose}\n      onClose={onClose}\n      width={0}\n    >\n      <form\n        onSubmit={(event) => {\n          event.preventDefault()\n          add()\n        }}\n      >\n        <Stack gap={3} padding={4}>\n          <Text muted size={1}>\n            Paste the code someone copied from their themer — the theme is added to your list and\n            applied.\n          </Text>\n          <TextInput\n            aria-describedby={invalid ? 'themer-paste-error' : undefined}\n            aria-invalid={invalid}\n            aria-label=\"Theme code\"\n            autoFocus\n            customValidity={invalid ? 'That is not a theme code' : undefined}\n            fontSize={1}\n            onChange={(event) => {\n              setText(event.currentTarget.value)\n              setInvalid(false)\n            }}\n            placeholder=\"AQ…\"\n            value={text}\n          />\n          {invalid && (\n            <Card id=\"themer-paste-error\" padding={3} radius={2} role=\"alert\" tone=\"critical\">\n              <Text size={1}>\n                That is not a theme code — codes are one word, copied from a theme&apos;s menu.\n              </Text>\n            </Card>\n          )}\n        </Stack>\n      </form>\n    </Dialog>","_c","frame","{\n  actorRef,\n  active,\n  theme,\n  themes,\n}: {active: boolean; theme: ThemerTheme} & Pick<ThemerProps, 'actorRef' | 'themes'>","{actorRef}","displayTitle(theme.title)","title","(candidate) => candidate.slug === theme.slug","slug","(to: number) => {\n    const order = themes.map((candidate) => candidate.slug)\n\n    order.splice(to, 0, ...order.splice(index, 1))\n    actorRef.send({type: 'theme.reorder', order})\n  }","(candidate) => candidate.slug","() => {\n        // The click lands before the next frame\n        requestAnimationFrame(() => {\n          dragged.current = false\n        })\n      }","() => {\n        dragged.current = true\n      }","{scale: 1.04}","() => {\n          if (!dragged.current) actorRef.send({type: 'theme.pick', slug: theme.slug})\n        }","(event) => {\n          // A mouse or pen drags the card off the button; a finger scrolls the\n          // list instead, and moves themes from the menu\n          if (listed && event.pointerType !== 'touch') dragControls.start(event)\n        }","<span className={frame}>\n          <ThemeThumbnail options={theme.options} />\n        </span>","options","<Box as=\"span\" display=\"block\" paddingTop={2} paddingX={2}>\n          <Text\n            align=\"center\"\n            as=\"span\"\n            size={1}\n            textOverflow=\"ellipsis\"\n            weight={active ? 'medium' : 'regular'}\n          >\n            {title}\n          </Text>\n        </Box>","active ? 'medium' : 'regular'","<button\n        aria-pressed={active}\n        className={pickButton}\n        onClick={() => {\n          if (!dragged.current) actorRef.send({type: 'theme.pick', slug: theme.slug})\n        }}\n        onPointerDown={(event) => {\n          // A mouse or pen drags the card off the button; a finger scrolls the\n          // list instead, and moves themes from the menu\n          if (listed && event.pointerType !== 'touch') dragControls.start(event)\n        }}\n        type=\"button\"\n      >\n        <span className={frame}>\n          <ThemeThumbnail options={theme.options} />\n        </span>\n        <Box as=\"span\" display=\"block\" paddingTop={2} paddingX={2}>\n          <Text\n            align=\"center\"\n            as=\"span\"\n            size={1}\n            textOverflow=\"ellipsis\"\n            weight={active ? 'medium' : 'regular'}\n          >\n            {title}\n          </Text>\n        </Box>\n      </button>","<Text size={1}>Show more</Text>","<Button\n                  aria-label={`Show more for ${title}`}\n                  fontSize={1}\n                  icon={EllipsisHorizontalIcon}\n                  mode=\"ghost\"\n                  padding={1}\n                  radius={2}\n                />","`Show more for ${title}`","listed && (\n                    <>\n                      <MenuItem\n                        disabled={index <= 0}\n                        icon={ArrowUpIcon}\n                        onClick={() => moveTo(index - 1)}\n                        text=\"Move up\"\n                      />\n                      <MenuItem\n                        disabled={index >= themes.length - 1}\n                        icon={ArrowDownIcon}\n                        onClick={() => moveTo(index + 1)}\n                        text=\"Move down\"\n                      />\n                      <MenuDivider />\n                    </>\n                  )","length","theme.source === 'custom' && (\n                    <MenuItem\n                      icon={EditIcon}\n                      onClick={() => actorRef.send({type: 'theme.edit', slug: theme.slug})}\n                      text=\"Edit\"\n                    />\n                  )","source","() => actorRef.send({type: 'theme.duplicate', slug: theme.slug})","<MenuItem\n                    icon={CopyIcon}\n                    onClick={() => actorRef.send({type: 'theme.duplicate', slug: theme.slug})}\n                    text={theme.source === 'custom' ? 'Duplicate' : 'Duplicate to edit'}\n                  />","theme.source === 'custom' ? 'Duplicate' : 'Duplicate to edit'","<MenuItem\n                    icon={ShareIcon}\n                    onClick={() => void copyTheme(theme)}\n                    text=\"Copy to share\"\n                  />","theme.source !== 'config' && (\n                    <>\n                      <MenuDivider />\n                      <MenuItem\n                        icon={TrashIcon}\n                        onClick={() => actorRef.send({type: 'theme.remove', slug: theme.slug})}\n                        text=\"Remove\"\n                        tone=\"critical\"\n                      />\n                    </>\n                  )","<Menu>\n                  {listed && (\n                    <>\n                      <MenuItem\n                        disabled={index <= 0}\n                        icon={ArrowUpIcon}\n                        onClick={() => moveTo(index - 1)}\n                        text=\"Move up\"\n                      />\n                      <MenuItem\n                        disabled={index >= themes.length - 1}\n                        icon={ArrowDownIcon}\n                        onClick={() => moveTo(index + 1)}\n                        text=\"Move down\"\n                      />\n                      <MenuDivider />\n                    </>\n                  )}\n                  {theme.source === 'custom' && (\n                    <MenuItem\n                      icon={EditIcon}\n                      onClick={() => actorRef.send({type: 'theme.edit', slug: theme.slug})}\n                      text=\"Edit\"\n                    />\n                  )}\n                  <MenuItem\n                    icon={CopyIcon}\n                    onClick={() => actorRef.send({type: 'theme.duplicate', slug: theme.slug})}\n                    text={theme.source === 'custom' ? 'Duplicate' : 'Duplicate to edit'}\n                  />\n                  <MenuItem\n                    icon={ShareIcon}\n                    onClick={() => void copyTheme(theme)}\n                    text=\"Copy to share\"\n                  />\n                  {theme.source !== 'config' && (\n                    <>\n                      <MenuDivider />\n                      <MenuItem\n                        icon={TrashIcon}\n                        onClick={() => actorRef.send({type: 'theme.remove', slug: theme.slug})}\n                        text=\"Remove\"\n                        tone=\"critical\"\n                      />\n                    </>\n                  )}\n                </Menu>","() => setMenuOpen(false)","() => setMenuOpen(true)","{animate: true, placement: 'bottom-end', portal: true, scheme}","<Tooltip animate content={<Text size={1}>Show more</Text>} placement=\"bottom\" portal>\n          <Card className={menuCard} radius={2} scheme=\"dark\">\n            <MenuButton\n              button={\n                <Button\n                  aria-label={`Show more for ${title}`}\n                  fontSize={1}\n                  icon={EllipsisHorizontalIcon}\n                  mode=\"ghost\"\n                  padding={1}\n                  radius={2}\n                />\n              }\n              id={`themer-theme-${theme.slug}`}\n              menu={\n                <Menu>\n                  {listed && (\n                    <>\n                      <MenuItem\n                        disabled={index <= 0}\n                        icon={ArrowUpIcon}\n                        onClick={() => moveTo(index - 1)}\n                        text=\"Move up\"\n                      />\n                      <MenuItem\n                        disabled={index >= themes.length - 1}\n                        icon={ArrowDownIcon}\n                        onClick={() => moveTo(index + 1)}\n                        text=\"Move down\"\n                      />\n                      <MenuDivider />\n                    </>\n                  )}\n                  {theme.source === 'custom' && (\n                    <MenuItem\n                      icon={EditIcon}\n                      onClick={() => actorRef.send({type: 'theme.edit', slug: theme.slug})}\n                      text=\"Edit\"\n                    />\n                  )}\n                  <MenuItem\n                    icon={CopyIcon}\n                    onClick={() => actorRef.send({type: 'theme.duplicate', slug: theme.slug})}\n                    text={theme.source === 'custom' ? 'Duplicate' : 'Duplicate to edit'}\n                  />\n                  <MenuItem\n                    icon={ShareIcon}\n                    onClick={() => void copyTheme(theme)}\n                    text=\"Copy to share\"\n                  />\n                  {theme.source !== 'config' && (\n                    <>\n                      <MenuDivider />\n                      <MenuItem\n                        icon={TrashIcon}\n                        onClick={() => actorRef.send({type: 'theme.remove', slug: theme.slug})}\n                        text=\"Remove\"\n                        tone=\"critical\"\n                      />\n                    </>\n                  )}\n                </Menu>\n              }\n              onClose={() => setMenuOpen(false)}\n              onOpen={() => setMenuOpen(true)}\n              popover={{animate: true, placement: 'bottom-end', portal: true, scheme}}\n            />\n          </Card>\n        </Tooltip>","`themer-theme-${theme.slug}`","<div className={menuSlot} data-visible={menuOpen}>\n        <Tooltip animate content={<Text size={1}>Show more</Text>} placement=\"bottom\" portal>\n          <Card className={menuCard} radius={2} scheme=\"dark\">\n            <MenuButton\n              button={\n                <Button\n                  aria-label={`Show more for ${title}`}\n                  fontSize={1}\n                  icon={EllipsisHorizontalIcon}\n                  mode=\"ghost\"\n                  padding={1}\n                  radius={2}\n                />\n              }\n              id={`themer-theme-${theme.slug}`}\n              menu={\n                <Menu>\n                  {listed && (\n                    <>\n                      <MenuItem\n                        disabled={index <= 0}\n                        icon={ArrowUpIcon}\n                        onClick={() => moveTo(index - 1)}\n                        text=\"Move up\"\n                      />\n                      <MenuItem\n                        disabled={index >= themes.length - 1}\n                        icon={ArrowDownIcon}\n                        onClick={() => moveTo(index + 1)}\n                        text=\"Move down\"\n                      />\n                      <MenuDivider />\n                    </>\n                  )}\n                  {theme.source === 'custom' && (\n                    <MenuItem\n                      icon={EditIcon}\n                      onClick={() => actorRef.send({type: 'theme.edit', slug: theme.slug})}\n                      text=\"Edit\"\n                    />\n                  )}\n                  <MenuItem\n                    icon={CopyIcon}\n                    onClick={() => actorRef.send({type: 'theme.duplicate', slug: theme.slug})}\n                    text={theme.source === 'custom' ? 'Duplicate' : 'Duplicate to edit'}\n                  />\n                  <MenuItem\n                    icon={ShareIcon}\n                    onClick={() => void copyTheme(theme)}\n                    text=\"Copy to share\"\n                  />\n                  {theme.source !== 'config' && (\n                    <>\n                      <MenuDivider />\n                      <MenuItem\n                        icon={TrashIcon}\n                        onClick={() => actorRef.send({type: 'theme.remove', slug: theme.slug})}\n                        text=\"Remove\"\n                        tone=\"critical\"\n                      />\n                    </>\n                  )}\n                </Menu>\n              }\n              onClose={() => setMenuOpen(false)}\n              onOpen={() => setMenuOpen(true)}\n              popover={{animate: true, placement: 'bottom-end', portal: true, scheme}}\n            />\n          </Card>\n        </Tooltip>\n      </div>","<Reorder.Item\n      as=\"div\"\n      className={root}\n      dragControls={dragControls}\n      dragListener={false}\n      onDragEnd={() => {\n        // The click lands before the next frame\n        requestAnimationFrame(() => {\n          dragged.current = false\n        })\n      }}\n      onDragStart={() => {\n        dragged.current = true\n      }}\n      ref={active ? scrollRefIntoViewIfNeeded : undefined}\n      value={theme.slug}\n      whileDrag={{scale: 1.04}}\n    >\n      <button\n        aria-pressed={active}\n        className={pickButton}\n        onClick={() => {\n          if (!dragged.current) actorRef.send({type: 'theme.pick', slug: theme.slug})\n        }}\n        onPointerDown={(event) => {\n          // A mouse or pen drags the card off the button; a finger scrolls the\n          // list instead, and moves themes from the menu\n          if (listed && event.pointerType !== 'touch') dragControls.start(event)\n        }}\n        type=\"button\"\n      >\n        <span className={frame}>\n          <ThemeThumbnail options={theme.options} />\n        </span>\n        <Box as=\"span\" display=\"block\" paddingTop={2} paddingX={2}>\n          <Text\n            align=\"center\"\n            as=\"span\"\n            size={1}\n            textOverflow=\"ellipsis\"\n            weight={active ? 'medium' : 'regular'}\n          >\n            {title}\n          </Text>\n        </Box>\n      </button>\n\n      {/* The tooltip wraps a card rather than the button: the menu button\n          clones its button to wire it up, which a tooltip in between would\n          swallow. The card keeps the button dark, as it sits on the dark\n          half of the thumbnail, while the menu opens in the sidebar's scheme */}\n      <div className={menuSlot} data-visible={menuOpen}>\n        <Tooltip animate content={<Text size={1}>Show more</Text>} placement=\"bottom\" portal>\n          <Card className={menuCard} radius={2} scheme=\"dark\">\n            <MenuButton\n              button={\n                <Button\n                  aria-label={`Show more for ${title}`}\n                  fontSize={1}\n                  icon={EllipsisHorizontalIcon}\n                  mode=\"ghost\"\n                  padding={1}\n                  radius={2}\n                />\n              }\n              id={`themer-theme-${theme.slug}`}\n              menu={\n                <Menu>\n                  {listed && (\n                    <>\n                      <MenuItem\n                        disabled={index <= 0}\n                        icon={ArrowUpIcon}\n                        onClick={() => moveTo(index - 1)}\n                        text=\"Move up\"\n                      />\n                      <MenuItem\n                        disabled={index >= themes.length - 1}\n                        icon={ArrowDownIcon}\n                        onClick={() => moveTo(index + 1)}\n                        text=\"Move down\"\n                      />\n                      <MenuDivider />\n                    </>\n                  )}\n                  {theme.source === 'custom' && (\n                    <MenuItem\n                      icon={EditIcon}\n                      onClick={() => actorRef.send({type: 'theme.edit', slug: theme.slug})}\n                      text=\"Edit\"\n                    />\n                  )}\n                  <MenuItem\n                    icon={CopyIcon}\n                    onClick={() => actorRef.send({type: 'theme.duplicate', slug: theme.slug})}\n                    text={theme.source === 'custom' ? 'Duplicate' : 'Duplicate to edit'}\n                  />\n                  <MenuItem\n                    icon={ShareIcon}\n                    onClick={() => void copyTheme(theme)}\n                    text=\"Copy to share\"\n                  />\n                  {theme.source !== 'config' && (\n                    <>\n                      <MenuDivider />\n                      <MenuItem\n                        icon={TrashIcon}\n                        onClick={() => actorRef.send({type: 'theme.remove', slug: theme.slug})}\n                        text=\"Remove\"\n                        tone=\"critical\"\n                      />\n                    </>\n                  )}\n                </Menu>\n              }\n              onClose={() => setMenuOpen(false)}\n              onOpen={() => setMenuOpen(true)}\n              popover={{animate: true, placement: 'bottom-end', portal: true, scheme}}\n            />\n          </Card>\n        </Tooltip>\n      </div>\n    </Reorder.Item>","active ? scrollRefIntoViewIfNeeded : undefined","Reorder.Item","candidate","_c","_temp","frame","_Fragment","{\n  actorRef,\n  themes,\n  removed,\n  active,\n}: Pick<ThemerProps, 'actorRef' | 'themes' | 'removed' | 'active'>","{actorRef}","(palette, file) =>\n    actorRef.send({\n      type: 'theme.add',\n      title: titleFromFileName(file.name),\n      options: optionsFromImagePalette(palette),\n      palette,\n      imageUrl: URL.createObjectURL(file),\n    })","(order: string[]) => actorRef.send({type: 'theme.reorder', order})","themes.map((theme) => theme.slug)","(theme) => theme.slug","{\n                  slug: CONFIG_SLUG,\n                  title: CONFIG_TITLE,\n                  options: {},\n                  source: 'config',\n                }","<ThemeCard\n                actorRef={actorRef}\n                active={!active}\n                theme={{\n                  slug: CONFIG_SLUG,\n                  title: CONFIG_TITLE,\n                  options: {},\n                  source: 'config',\n                }}\n                themes={themes}\n              />","!active","themes.map((theme) => (\n                <ThemeCard\n                  key={theme.slug}\n                  actorRef={actorRef}\n                  active={theme.slug === active?.slug}\n                  theme={theme}\n                  themes={themes}\n                />\n              ))","slug","theme","<MotionConfig reducedMotion=\"user\">\n            <Reorder.Group\n              as=\"div\"\n              className={cardGrid}\n              onReorder={(order: string[]) => actorRef.send({type: 'theme.reorder', order})}\n              values={themes.map((theme) => theme.slug)}\n            >\n              <ThemeCard\n                actorRef={actorRef}\n                active={!active}\n                theme={{\n                  slug: CONFIG_SLUG,\n                  title: CONFIG_TITLE,\n                  options: {},\n                  source: 'config',\n                }}\n                themes={themes}\n              />\n              {themes.map((theme) => (\n                <ThemeCard\n                  key={theme.slug}\n                  actorRef={actorRef}\n                  active={theme.slug === active?.slug}\n                  theme={theme}\n                  themes={themes}\n                />\n              ))}\n            </Reorder.Group>\n          </MotionConfig>","Reorder.Group","removed.length > 0 && (\n            <Button\n              gap={2}\n              icon={RestoreIcon}\n              mode=\"bleed\"\n              onClick={() => actorRef.send({type: 'flow.removed'})}\n              padding={2}\n              text={`Show removed (${removed.length})`}\n              width=\"fill\"\n            />\n          )","length","<ScrollArea padding={3}>\n        <Stack gap={4}>\n          {/* The group tells a column from a grid by measuring the cards, and\n              lets go of the layout animations for users who prefer reduced motion */}\n          <MotionConfig reducedMotion=\"user\">\n            <Reorder.Group\n              as=\"div\"\n              className={cardGrid}\n              onReorder={(order: string[]) => actorRef.send({type: 'theme.reorder', order})}\n              values={themes.map((theme) => theme.slug)}\n            >\n              <ThemeCard\n                actorRef={actorRef}\n                active={!active}\n                theme={{\n                  slug: CONFIG_SLUG,\n                  title: CONFIG_TITLE,\n                  options: {},\n                  source: 'config',\n                }}\n                themes={themes}\n              />\n              {themes.map((theme) => (\n                <ThemeCard\n                  key={theme.slug}\n                  actorRef={actorRef}\n                  active={theme.slug === active?.slug}\n                  theme={theme}\n                  themes={themes}\n                />\n              ))}\n            </Reorder.Group>\n          </MotionConfig>\n          {/* Trails the list rather than sitting in the footer, so the footer\n              does not shift when the first theme gets removed */}\n          {removed.length > 0 && (\n            <Button\n              gap={2}\n              icon={RestoreIcon}\n              mode=\"bleed\"\n              onClick={() => actorRef.send({type: 'flow.removed'})}\n              padding={2}\n              text={`Show removed (${removed.length})`}\n              width=\"fill\"\n            />\n          )}\n        </Stack>\n      </ScrollArea>","<Box flex={1}>\n            <TooltipButton\n              icon={AddIcon}\n              mode=\"ghost\"\n              onClick={() => actorRef.send({type: 'theme.add'})}\n              text=\"Add theme\"\n              tooltip=\"Add a theme based on the applied one\"\n              width=\"fill\"\n            />\n          </Box>","<ImageFileButton\n            loading={busy}\n            mode=\"ghost\"\n            onFile={pickImage}\n            tooltip=\"Add a theme from the colors of an image\"\n          />","<TooltipButton\n            icon={ClipboardIcon}\n            mode=\"ghost\"\n            onClick={async () => {\n              // Straight from the clipboard where the browser allows; by hand otherwise\n              if ((await addThemeFromClipboard()) !== 'added') setPasting(true)\n            }}\n            tooltip=\"Add a theme from a code someone shared\"\n          />","<Card borderTop padding={3}>\n        <Flex gap={2}>\n          <Box flex={1}>\n            <TooltipButton\n              icon={AddIcon}\n              mode=\"ghost\"\n              onClick={() => actorRef.send({type: 'theme.add'})}\n              text=\"Add theme\"\n              tooltip=\"Add a theme based on the applied one\"\n              width=\"fill\"\n            />\n          </Box>\n          <ImageFileButton\n            loading={busy}\n            mode=\"ghost\"\n            onFile={pickImage}\n            tooltip=\"Add a theme from the colors of an image\"\n          />\n          <TooltipButton\n            icon={ClipboardIcon}\n            mode=\"ghost\"\n            onClick={async () => {\n              // Straight from the clipboard where the browser allows; by hand otherwise\n              if ((await addThemeFromClipboard()) !== 'added') setPasting(true)\n            }}\n            tooltip=\"Add a theme from a code someone shared\"\n          />\n        </Flex>\n      </Card>","pasting && <PasteThemeDialog actorRef={actorRef} onClose={() => setPasting(false)} />","<>\n      <ScrollArea padding={3}>\n        <Stack gap={4}>\n          {/* The group tells a column from a grid by measuring the cards, and\n              lets go of the layout animations for users who prefer reduced motion */}\n          <MotionConfig reducedMotion=\"user\">\n            <Reorder.Group\n              as=\"div\"\n              className={cardGrid}\n              onReorder={(order: string[]) => actorRef.send({type: 'theme.reorder', order})}\n              values={themes.map((theme) => theme.slug)}\n            >\n              <ThemeCard\n                actorRef={actorRef}\n                active={!active}\n                theme={{\n                  slug: CONFIG_SLUG,\n                  title: CONFIG_TITLE,\n                  options: {},\n                  source: 'config',\n                }}\n                themes={themes}\n              />\n              {themes.map((theme) => (\n                <ThemeCard\n                  key={theme.slug}\n                  actorRef={actorRef}\n                  active={theme.slug === active?.slug}\n                  theme={theme}\n                  themes={themes}\n                />\n              ))}\n            </Reorder.Group>\n          </MotionConfig>\n          {/* Trails the list rather than sitting in the footer, so the footer\n              does not shift when the first theme gets removed */}\n          {removed.length > 0 && (\n            <Button\n              gap={2}\n              icon={RestoreIcon}\n              mode=\"bleed\"\n              onClick={() => actorRef.send({type: 'flow.removed'})}\n              padding={2}\n              text={`Show removed (${removed.length})`}\n              width=\"fill\"\n            />\n          )}\n        </Stack>\n      </ScrollArea>\n\n      <Card borderTop padding={3}>\n        <Flex gap={2}>\n          <Box flex={1}>\n            <TooltipButton\n              icon={AddIcon}\n              mode=\"ghost\"\n              onClick={() => actorRef.send({type: 'theme.add'})}\n              text=\"Add theme\"\n              tooltip=\"Add a theme based on the applied one\"\n              width=\"fill\"\n            />\n          </Box>\n          <ImageFileButton\n            loading={busy}\n            mode=\"ghost\"\n            onFile={pickImage}\n            tooltip=\"Add a theme from the colors of an image\"\n          />\n          <TooltipButton\n            icon={ClipboardIcon}\n            mode=\"ghost\"\n            onClick={async () => {\n              // Straight from the clipboard where the browser allows; by hand otherwise\n              if ((await addThemeFromClipboard()) !== 'added') setPasting(true)\n            }}\n            tooltip=\"Add a theme from a code someone shared\"\n          />\n        </Flex>\n      </Card>\n\n      {pasting && <PasteThemeDialog actorRef={actorRef} onClose={() => setPasting(false)} />}\n    </>","_c","_temp","_Fragment","createThemeSnippet(theme.options)","options","async () => {\n    try {\n      await navigator.clipboard.writeText(snippet)\n      toast.push({status: 'success', title: 'Copied the theme to the clipboard'})\n    } catch {\n      toast.push({status: 'error', title: 'Could not copy the theme'})\n    }\n  }","<Flex gap={2} justify=\"flex-end\" padding={3}>\n          <Button\n            gap={2}\n            icon={ClipboardIcon}\n            mode=\"ghost\"\n            onClick={() => void handleCopy()}\n            padding={2}\n            text=\"Copy\"\n          />\n        </Flex>","<code>sanity.config.ts</code>","<code>theme</code>","<code>defineConfig</code>","displayTitle(theme.title)","title","<Text muted size={1}>\n            Export this from <code>sanity.config.ts</code> and pass it as the <code>theme</code> of{' '}\n            <code>defineConfig</code> to make “{displayTitle(theme.title)}” the Studio theme without\n            this tool.\n          </Text>","<Card border overflow=\"auto\" padding={3} radius={2} tone=\"transparent\">\n            <Code language=\"ts\" size={1}>\n              {snippet}\n            </Code>\n          </Card>","<Box padding={4}>\n        <Stack gap={4}>\n          <Text muted size={1}>\n            Export this from <code>sanity.config.ts</code> and pass it as the <code>theme</code> of{' '}\n            <code>defineConfig</code> to make “{displayTitle(theme.title)}” the Studio theme without\n            this tool.\n          </Text>\n          <Card border overflow=\"auto\" padding={3} radius={2} tone=\"transparent\">\n            <Code language=\"ts\" size={1}>\n              {snippet}\n            </Code>\n          </Card>\n        </Stack>\n      </Box>","<Dialog\n      animate\n      footer={\n        <Flex gap={2} justify=\"flex-end\" padding={3}>\n          <Button\n            gap={2}\n            icon={ClipboardIcon}\n            mode=\"ghost\"\n            onClick={() => void handleCopy()}\n            padding={2}\n            text=\"Copy\"\n          />\n        </Flex>\n      }\n      header=\"Add to your config\"\n      id=\"themer-snippet\"\n      onClickOutside={onClose}\n      onClose={onClose}\n      width={1}\n    >\n      <Box padding={4}>\n        <Stack gap={4}>\n          <Text muted size={1}>\n            Export this from <code>sanity.config.ts</code> and pass it as the <code>theme</code> of{' '}\n            <code>defineConfig</code> to make “{displayTitle(theme.title)}” the Studio theme without\n            this tool.\n          </Text>\n          <Card border overflow=\"auto\" padding={3} radius={2} tone=\"transparent\">\n            <Code language=\"ts\" size={1}>\n              {snippet}\n            </Code>\n          </Card>\n        </Stack>\n      </Box>\n    </Dialog>","_c","{\n  actorRef,\n  dispatch,\n  navbarHeight,\n  split,\n}: Pick<ThemerProps, 'actorRef' | 'dispatch' | 'navbarHeight' | 'split'>","(snapshot) => resolveThemes(snapshot.context)","navbarHeight === null ? undefined : {height: navbarHeight}","!inList && (\n              <TooltipButton\n                icon={ArrowLeftIcon}\n                mode=\"bleed\"\n                onClick={() => actorRef.send({type: 'flow.list'})}\n                padding={2}\n                tooltip=\"Back to the themes\"\n              />\n            )","<Box className={title} flex={1}>\n              <Text size={1} textOverflow=\"ellipsis\" weight=\"semibold\">\n                {VIEW_TITLES[view.name]}\n              </Text>\n            </Box>","VIEW_TITLES[view.name]","view.name !== 'removed' && (\n                <>\n                  {!isTooSmallForSplitScreen && (\n                    <TooltipButton\n                      aria-pressed={split}\n                      icon={SplitVerticalIcon}\n                      mode=\"bleed\"\n                      onClick={() =>\n                        startTransition(() => {\n                          const type = split ? 'split-screen:close' : 'split-screen:open'\n                          addThemerTransitionType(type)\n                          dispatch({type})\n                        })\n                      }\n                      onMouseEnter={() =>\n                        startTransition(() => {\n                          dispatch({type: 'split-screen:prerender'})\n                        })\n                      }\n                      padding={2}\n                      selected={split}\n                      tooltip=\"Show light and dark side by side\"\n                    />\n                  )}\n                  {active && (\n                    <TooltipButton\n                      icon={CodeBlockIcon}\n                      mode=\"bleed\"\n                      onClick={() => setSnippetOpen(true)}\n                      padding={2}\n                      tooltip=\"Show the code for the applied theme\"\n                    />\n                  )}\n                </>\n              )","name","<TooltipButton\n                icon={CloseIcon}\n                mode=\"bleed\"\n                onClick={() =>\n                  startTransition(() => {\n                    if (split) addThemerTransitionType('split-screen:close')\n                    addThemerTransitionType('close')\n                    dispatch({type: 'close'})\n                  })\n                }\n                padding={2}\n                tooltip=\"Close themer\"\n              />","<Flex>\n              {view.name !== 'removed' && (\n                <>\n                  {!isTooSmallForSplitScreen && (\n                    <TooltipButton\n                      aria-pressed={split}\n                      icon={SplitVerticalIcon}\n                      mode=\"bleed\"\n                      onClick={() =>\n                        startTransition(() => {\n                          const type = split ? 'split-screen:close' : 'split-screen:open'\n                          addThemerTransitionType(type)\n                          dispatch({type})\n                        })\n                      }\n                      onMouseEnter={() =>\n                        startTransition(() => {\n                          dispatch({type: 'split-screen:prerender'})\n                        })\n                      }\n                      padding={2}\n                      selected={split}\n                      tooltip=\"Show light and dark side by side\"\n                    />\n                  )}\n                  {active && (\n                    <TooltipButton\n                      icon={CodeBlockIcon}\n                      mode=\"bleed\"\n                      onClick={() => setSnippetOpen(true)}\n                      padding={2}\n                      tooltip=\"Show the code for the applied theme\"\n                    />\n                  )}\n                </>\n              )}\n              <TooltipButton\n                icon={CloseIcon}\n                mode=\"bleed\"\n                onClick={() =>\n                  startTransition(() => {\n                    if (split) addThemerTransitionType('split-screen:close')\n                    addThemerTransitionType('close')\n                    dispatch({type: 'close'})\n                  })\n                }\n                padding={2}\n                tooltip=\"Close themer\"\n              />\n            </Flex>","<Flex align=\"center\" gap={1} height=\"fill\">\n            {!inList && (\n              <TooltipButton\n                icon={ArrowLeftIcon}\n                mode=\"bleed\"\n                onClick={() => actorRef.send({type: 'flow.list'})}\n                padding={2}\n                tooltip=\"Back to the themes\"\n              />\n            )}\n            <Box className={title} flex={1}>\n              <Text size={1} textOverflow=\"ellipsis\" weight=\"semibold\">\n                {VIEW_TITLES[view.name]}\n              </Text>\n            </Box>\n            {/* Packed without gaps, so the title still fits next to them at the\n                narrowest sidebar width */}\n            <Flex>\n              {view.name !== 'removed' && (\n                <>\n                  {!isTooSmallForSplitScreen && (\n                    <TooltipButton\n                      aria-pressed={split}\n                      icon={SplitVerticalIcon}\n                      mode=\"bleed\"\n                      onClick={() =>\n                        startTransition(() => {\n                          const type = split ? 'split-screen:close' : 'split-screen:open'\n                          addThemerTransitionType(type)\n                          dispatch({type})\n                        })\n                      }\n                      onMouseEnter={() =>\n                        startTransition(() => {\n                          dispatch({type: 'split-screen:prerender'})\n                        })\n                      }\n                      padding={2}\n                      selected={split}\n                      tooltip=\"Show light and dark side by side\"\n                    />\n                  )}\n                  {active && (\n                    <TooltipButton\n                      icon={CodeBlockIcon}\n                      mode=\"bleed\"\n                      onClick={() => setSnippetOpen(true)}\n                      padding={2}\n                      tooltip=\"Show the code for the applied theme\"\n                    />\n                  )}\n                </>\n              )}\n              <TooltipButton\n                icon={CloseIcon}\n                mode=\"bleed\"\n                onClick={() =>\n                  startTransition(() => {\n                    if (split) addThemerTransitionType('split-screen:close')\n                    addThemerTransitionType('close')\n                    dispatch({type: 'close'})\n                  })\n                }\n                padding={2}\n                tooltip=\"Close themer\"\n              />\n            </Flex>\n          </Flex>","<Card\n          borderBottom\n          padding={3}\n          sizing=\"border\"\n          style={navbarHeight === null ? undefined : {height: navbarHeight}}\n        >\n          <Flex align=\"center\" gap={1} height=\"fill\">\n            {!inList && (\n              <TooltipButton\n                icon={ArrowLeftIcon}\n                mode=\"bleed\"\n                onClick={() => actorRef.send({type: 'flow.list'})}\n                padding={2}\n                tooltip=\"Back to the themes\"\n              />\n            )}\n            <Box className={title} flex={1}>\n              <Text size={1} textOverflow=\"ellipsis\" weight=\"semibold\">\n                {VIEW_TITLES[view.name]}\n              </Text>\n            </Box>\n            {/* Packed without gaps, so the title still fits next to them at the\n                narrowest sidebar width */}\n            <Flex>\n              {view.name !== 'removed' && (\n                <>\n                  {!isTooSmallForSplitScreen && (\n                    <TooltipButton\n                      aria-pressed={split}\n                      icon={SplitVerticalIcon}\n                      mode=\"bleed\"\n                      onClick={() =>\n                        startTransition(() => {\n                          const type = split ? 'split-screen:close' : 'split-screen:open'\n                          addThemerTransitionType(type)\n                          dispatch({type})\n                        })\n                      }\n                      onMouseEnter={() =>\n                        startTransition(() => {\n                          dispatch({type: 'split-screen:prerender'})\n                        })\n                      }\n                      padding={2}\n                      selected={split}\n                      tooltip=\"Show light and dark side by side\"\n                    />\n                  )}\n                  {active && (\n                    <TooltipButton\n                      icon={CodeBlockIcon}\n                      mode=\"bleed\"\n                      onClick={() => setSnippetOpen(true)}\n                      padding={2}\n                      tooltip=\"Show the code for the applied theme\"\n                    />\n                  )}\n                </>\n              )}\n              <TooltipButton\n                icon={CloseIcon}\n                mode=\"bleed\"\n                onClick={() =>\n                  startTransition(() => {\n                    if (split) addThemerTransitionType('split-screen:close')\n                    addThemerTransitionType('close')\n                    dispatch({type: 'close'})\n                  })\n                }\n                padding={2}\n                tooltip=\"Close themer\"\n              />\n            </Flex>\n          </Flex>\n        </Card>","<ThemeList actorRef={actorRef} active={active} removed={removed} themes={themes} />","<Activity key=\"list\" mode={view.name === 'list' ? 'visible' : 'hidden'}>\n          <ThemeList actorRef={actorRef} active={active} removed={removed} themes={themes} />\n        </Activity>","view.name === 'list' ? 'visible' : 'hidden'","view.name === 'edit' && (\n          <ThemeEditor\n            actorRef={actorRef}\n            focusTitle={view.focusTitle}\n            slug={view.slug}\n            split={split}\n            themes={themes}\n          />\n        )","focusTitle","slug","<RemovedThemes actorRef={actorRef} removed={removed} />","<Activity key=\"removed\" mode={view.name === 'removed' ? 'visible' : 'hidden'}>\n          <RemovedThemes actorRef={actorRef} removed={removed} />\n        </Activity>","view.name === 'removed' ? 'visible' : 'hidden'","<Flex direction=\"column\" height=\"fill\">\n        {/* The header sits next to the Studio navbar and takes its height, so\n            the two bottom borders line up — whatever height the Studio, its\n            breakpoint or a custom navbar gives it */}\n        <Card\n          borderBottom\n          padding={3}\n          sizing=\"border\"\n          style={navbarHeight === null ? undefined : {height: navbarHeight}}\n        >\n          <Flex align=\"center\" gap={1} height=\"fill\">\n            {!inList && (\n              <TooltipButton\n                icon={ArrowLeftIcon}\n                mode=\"bleed\"\n                onClick={() => actorRef.send({type: 'flow.list'})}\n                padding={2}\n                tooltip=\"Back to the themes\"\n              />\n            )}\n            <Box className={title} flex={1}>\n              <Text size={1} textOverflow=\"ellipsis\" weight=\"semibold\">\n                {VIEW_TITLES[view.name]}\n              </Text>\n            </Box>\n            {/* Packed without gaps, so the title still fits next to them at the\n                narrowest sidebar width */}\n            <Flex>\n              {view.name !== 'removed' && (\n                <>\n                  {!isTooSmallForSplitScreen && (\n                    <TooltipButton\n                      aria-pressed={split}\n                      icon={SplitVerticalIcon}\n                      mode=\"bleed\"\n                      onClick={() =>\n                        startTransition(() => {\n                          const type = split ? 'split-screen:close' : 'split-screen:open'\n                          addThemerTransitionType(type)\n                          dispatch({type})\n                        })\n                      }\n                      onMouseEnter={() =>\n                        startTransition(() => {\n                          dispatch({type: 'split-screen:prerender'})\n                        })\n                      }\n                      padding={2}\n                      selected={split}\n                      tooltip=\"Show light and dark side by side\"\n                    />\n                  )}\n                  {active && (\n                    <TooltipButton\n                      icon={CodeBlockIcon}\n                      mode=\"bleed\"\n                      onClick={() => setSnippetOpen(true)}\n                      padding={2}\n                      tooltip=\"Show the code for the applied theme\"\n                    />\n                  )}\n                </>\n              )}\n              <TooltipButton\n                icon={CloseIcon}\n                mode=\"bleed\"\n                onClick={() =>\n                  startTransition(() => {\n                    if (split) addThemerTransitionType('split-screen:close')\n                    addThemerTransitionType('close')\n                    dispatch({type: 'close'})\n                  })\n                }\n                padding={2}\n                tooltip=\"Close themer\"\n              />\n            </Flex>\n          </Flex>\n        </Card>\n\n        <Activity key=\"list\" mode={view.name === 'list' ? 'visible' : 'hidden'}>\n          <ThemeList actorRef={actorRef} active={active} removed={removed} themes={themes} />\n        </Activity>\n        {view.name === 'edit' && (\n          <ThemeEditor\n            actorRef={actorRef}\n            focusTitle={view.focusTitle}\n            slug={view.slug}\n            split={split}\n            themes={themes}\n          />\n        )}\n        <Activity key=\"removed\" mode={view.name === 'removed' ? 'visible' : 'hidden'}>\n          <RemovedThemes actorRef={actorRef} removed={removed} />\n        </Activity>\n      </Flex>","active && snippetOpen && (\n        <ThemeSnippetDialog onClose={() => setSnippetOpen(false)} theme={active} />\n      )","<Card height=\"fill\">\n      <Flex direction=\"column\" height=\"fill\">\n        {/* The header sits next to the Studio navbar and takes its height, so\n            the two bottom borders line up — whatever height the Studio, its\n            breakpoint or a custom navbar gives it */}\n        <Card\n          borderBottom\n          padding={3}\n          sizing=\"border\"\n          style={navbarHeight === null ? undefined : {height: navbarHeight}}\n        >\n          <Flex align=\"center\" gap={1} height=\"fill\">\n            {!inList && (\n              <TooltipButton\n                icon={ArrowLeftIcon}\n                mode=\"bleed\"\n                onClick={() => actorRef.send({type: 'flow.list'})}\n                padding={2}\n                tooltip=\"Back to the themes\"\n              />\n            )}\n            <Box className={title} flex={1}>\n              <Text size={1} textOverflow=\"ellipsis\" weight=\"semibold\">\n                {VIEW_TITLES[view.name]}\n              </Text>\n            </Box>\n            {/* Packed without gaps, so the title still fits next to them at the\n                narrowest sidebar width */}\n            <Flex>\n              {view.name !== 'removed' && (\n                <>\n                  {!isTooSmallForSplitScreen && (\n                    <TooltipButton\n                      aria-pressed={split}\n                      icon={SplitVerticalIcon}\n                      mode=\"bleed\"\n                      onClick={() =>\n                        startTransition(() => {\n                          const type = split ? 'split-screen:close' : 'split-screen:open'\n                          addThemerTransitionType(type)\n                          dispatch({type})\n                        })\n                      }\n                      onMouseEnter={() =>\n                        startTransition(() => {\n                          dispatch({type: 'split-screen:prerender'})\n                        })\n                      }\n                      padding={2}\n                      selected={split}\n                      tooltip=\"Show light and dark side by side\"\n                    />\n                  )}\n                  {active && (\n                    <TooltipButton\n                      icon={CodeBlockIcon}\n                      mode=\"bleed\"\n                      onClick={() => setSnippetOpen(true)}\n                      padding={2}\n                      tooltip=\"Show the code for the applied theme\"\n                    />\n                  )}\n                </>\n              )}\n              <TooltipButton\n                icon={CloseIcon}\n                mode=\"bleed\"\n                onClick={() =>\n                  startTransition(() => {\n                    if (split) addThemerTransitionType('split-screen:close')\n                    addThemerTransitionType('close')\n                    dispatch({type: 'close'})\n                  })\n                }\n                padding={2}\n                tooltip=\"Close themer\"\n              />\n            </Flex>\n          </Flex>\n        </Card>\n\n        <Activity key=\"list\" mode={view.name === 'list' ? 'visible' : 'hidden'}>\n          <ThemeList actorRef={actorRef} active={active} removed={removed} themes={themes} />\n        </Activity>\n        {view.name === 'edit' && (\n          <ThemeEditor\n            actorRef={actorRef}\n            focusTitle={view.focusTitle}\n            slug={view.slug}\n            split={split}\n            themes={themes}\n          />\n        )}\n        <Activity key=\"removed\" mode={view.name === 'removed' ? 'visible' : 'hidden'}>\n          <RemovedThemes actorRef={actorRef} removed={removed} />\n        </Activity>\n      </Flex>\n\n      {active && snippetOpen && (\n        <ThemeSnippetDialog onClose={() => setSnippetOpen(false)} theme={active} />\n      )}\n    </Card>","_c","_temp","_Fragment","{\n  actorRef,\n  dispatch,\n  navbarHeight,\n  split,\n}: Pick<ThemerProps, 'actorRef' | 'dispatch' | 'navbarHeight' | 'split'>","() => writeStoredWidth(width)","[width]","(event: React.PointerEvent<HTMLDivElement>) => {\n      if (event.button !== 0) return\n\n      event.preventDefault()\n      event.currentTarget.setPointerCapture(event.pointerId)\n      drag.current = {pointerId: event.pointerId, startX: event.clientX, startWidth: width}\n      setDragging(true)\n    }","useCallback(\n    (event: React.PointerEvent<HTMLDivElement>) => {\n      if (event.button !== 0) return\n\n      event.preventDefault()\n      event.currentTarget.setPointerCapture(event.pointerId)\n      drag.current = {pointerId: event.pointerId, startX: event.clientX, startWidth: width}\n      setDragging(true)\n    },\n    [width],\n  )","(event: React.PointerEvent<HTMLDivElement>) => {\n    if (!drag.current || drag.current.pointerId !== event.pointerId) return\n\n    // The sidebar sits on the right, so dragging left makes it wider\n    setWidth(clampWidth(drag.current.startWidth - (event.clientX - drag.current.startX)))\n  }","event","useCallback((event: React.PointerEvent<HTMLDivElement>) => {\n    if (!drag.current || drag.current.pointerId !== event.pointerId) return\n\n    // The sidebar sits on the right, so dragging left makes it wider\n    setWidth(clampWidth(drag.current.startWidth - (event.clientX - drag.current.startX)))\n  }, [])","(event: React.PointerEvent<HTMLDivElement>) => {\n    if (!drag.current || drag.current.pointerId !== event.pointerId) return\n\n    drag.current = null\n    setDragging(false)\n  }","useCallback((event: React.PointerEvent<HTMLDivElement>) => {\n    if (!drag.current || drag.current.pointerId !== event.pointerId) return\n\n    drag.current = null\n    setDragging(false)\n  }, [])","(event: React.KeyboardEvent<HTMLDivElement>) => {\n    const steps: Record<string, number> = {\n      ArrowLeft: KEYBOARD_STEP,\n      ArrowRight: -KEYBOARD_STEP,\n      Home: MAXIMUM_WIDTH,\n      End: -MAXIMUM_WIDTH,\n    }\n    const step = steps[event.key]\n\n    if (step === undefined) return\n\n    event.preventDefault()\n    setWidth((current) => clampWidth(current + step))\n  }","useCallback((event: React.KeyboardEvent<HTMLDivElement>) => {\n    const steps: Record<string, number> = {\n      ArrowLeft: KEYBOARD_STEP,\n      ArrowRight: -KEYBOARD_STEP,\n      Home: MAXIMUM_WIDTH,\n      End: -MAXIMUM_WIDTH,\n    }\n    const step = steps[event.key]\n\n    if (step === undefined) return\n\n    event.preventDefault()\n    setWidth((current) => clampWidth(current + step))\n  }, [])","{width}","(boundaryElement) => {\n          startTransition(() => setBoundaryElement(boundaryElement))\n          // Intentionally not unsetting the element as it would create unnecessary work when <Activity> unhides\n          return () => {}\n        }","boundaryElement","() => {}","() => setWidth(MINIMUM_WIDTH)","<div\n          aria-label=\"Resize the themer\"\n          className={resizeHandle}\n          aria-orientation=\"vertical\"\n          aria-valuemax={MAXIMUM_WIDTH}\n          aria-valuemin={MINIMUM_WIDTH}\n          aria-valuenow={width}\n          data-dragging={dragging}\n          onDoubleClick={() => setWidth(MINIMUM_WIDTH)}\n          onKeyDown={handleKeyDown}\n          onPointerCancel={handlePointerUp}\n          onPointerDown={handlePointerDown}\n          onPointerMove={handlePointerMove}\n          onPointerUp={handlePointerUp}\n          // oxlint-disable-next-line prefer-tag-over-role -- a window splitter is a focusable, draggable separator, which an hr is not\n          role=\"separator\"\n          tabIndex={0}\n        />","<ThemerSidebar\n              split={split}\n              navbarHeight={navbarHeight}\n              actorRef={actorRef}\n              dispatch={dispatch}\n            />","<Box className={content} height=\"fill\" overflow=\"hidden\">\n          <BoundaryElementProvider element={boundaryElement}>\n            <ThemerSidebar\n              split={split}\n              navbarHeight={navbarHeight}\n              actorRef={actorRef}\n              dispatch={dispatch}\n            />\n          </BoundaryElementProvider>\n        </Box>","<Card\n        borderLeft\n        className={frame}\n        height=\"fill\"\n        ref={(boundaryElement) => {\n          startTransition(() => setBoundaryElement(boundaryElement))\n          // Intentionally not unsetting the element as it would create unnecessary work when <Activity> unhides\n          return () => {}\n        }}\n      >\n        <div\n          aria-label=\"Resize the themer\"\n          className={resizeHandle}\n          aria-orientation=\"vertical\"\n          aria-valuemax={MAXIMUM_WIDTH}\n          aria-valuemin={MINIMUM_WIDTH}\n          aria-valuenow={width}\n          data-dragging={dragging}\n          onDoubleClick={() => setWidth(MINIMUM_WIDTH)}\n          onKeyDown={handleKeyDown}\n          onPointerCancel={handlePointerUp}\n          onPointerDown={handlePointerDown}\n          onPointerMove={handlePointerMove}\n          onPointerUp={handlePointerUp}\n          // oxlint-disable-next-line prefer-tag-over-role -- a window splitter is a focusable, draggable separator, which an hr is not\n          role=\"separator\"\n          tabIndex={0}\n        />\n        <Box className={content} height=\"fill\" overflow=\"hidden\">\n          <BoundaryElementProvider element={boundaryElement}>\n            <ThemerSidebar\n              split={split}\n              navbarHeight={navbarHeight}\n              actorRef={actorRef}\n              dispatch={dispatch}\n            />\n          </BoundaryElementProvider>\n        </Box>\n      </Card>","<Layer className={sidebar} style={{width}} zOffset={100}>\n      <Card\n        borderLeft\n        className={frame}\n        height=\"fill\"\n        ref={(boundaryElement) => {\n          startTransition(() => setBoundaryElement(boundaryElement))\n          // Intentionally not unsetting the element as it would create unnecessary work when <Activity> unhides\n          return () => {}\n        }}\n      >\n        <div\n          aria-label=\"Resize the themer\"\n          className={resizeHandle}\n          aria-orientation=\"vertical\"\n          aria-valuemax={MAXIMUM_WIDTH}\n          aria-valuemin={MINIMUM_WIDTH}\n          aria-valuenow={width}\n          data-dragging={dragging}\n          onDoubleClick={() => setWidth(MINIMUM_WIDTH)}\n          onKeyDown={handleKeyDown}\n          onPointerCancel={handlePointerUp}\n          onPointerDown={handlePointerDown}\n          onPointerMove={handlePointerMove}\n          onPointerUp={handlePointerUp}\n          // oxlint-disable-next-line prefer-tag-over-role -- a window splitter is a focusable, draggable separator, which an hr is not\n          role=\"separator\"\n          tabIndex={0}\n        />\n        <Box className={content} height=\"fill\" overflow=\"hidden\">\n          <BoundaryElementProvider element={boundaryElement}>\n            <ThemerSidebar\n              split={split}\n              navbarHeight={navbarHeight}\n              actorRef={actorRef}\n              dispatch={dispatch}\n            />\n          </BoundaryElementProvider>\n        </Box>\n      </Card>\n    </Layer>","_c"],"sources":["../src/tool/ScrollArea.css.ts","../src/tool/ScrollArea.tsx","../src/tool/ThemePreview.css.ts","../src/tool/ThemePreview.tsx","../src/tool/ThemeThumbnail.tsx","../src/tool/RemovedThemes.css.ts","../src/tool/RemovedThemes.tsx","../src/tool/imagePalette.ts","../src/tool/TooltipButton.tsx","../src/tool/ImageFileButton.tsx","../src/tool/imageFile.ts","../src/tool/useImagePalette.ts","../src/tool/ImagePaletteSection.css.ts","../src/tool/ImagePaletteSection.tsx","../src/tool/ThemeEditor.css.ts","../src/tool/ThemeEditor.tsx","../src/tool/share.ts","../src/tool/useThemeCodes.ts","../src/tool/PasteThemeDialog.tsx","../src/tool/ThemeCard.css.ts","../src/tool/ThemeCard.tsx","../src/tool/ThemeList.css.ts","../src/tool/ThemeList.tsx","../src/tool/options.ts","../src/tool/snippet.ts","../src/tool/ThemeSnippetDialog.tsx","../src/tool/useIsTooSmallForSplitScreen.ts","../src/tool/ThemerSidebar.css.ts","../src/tool/ThemerSidebar.tsx","../src/tool/ResizableSidebar.css.ts","../src/tool/ResizableSidebar.tsx"],"sourcesContent":["import {style} from '@vanilla-extract/css'\n\n/** Always reserves the scrollbar's space, so the content never shifts */\nexport const root = style({\n  scrollbarGutter: 'stable',\n})\n","import {Box, useTheme_v2} from '@sanity/ui'\nimport {createContext, useContext, useEffect, useMemo, useRef, useState} from 'react'\n\nimport {root} from './ScrollArea.css'\n\n/** How far the content of a scroll area sits from its edges, in pixels */\ninterface ScrollAreaInset {\n  left: number\n  right: number\n  bottom: number\n}\n\nconst ScrollAreaInsetContext = createContext<ScrollAreaInset>({left: 0, right: 0, bottom: 0})\n\n/**\n * The gutter the last scroll area measured. It is the same for every scroll\n * area (the reserved gutter does not depend on the content), so the next one\n * starts out with the right padding instead of shifting after its first\n * measurement — which would also throw off anything scrolling into view as\n * the content mounts.\n */\nlet lastGutter = 0\n\n/**\n * The scrolling body of a sidebar flow. It always reserves the scrollbar's\n * space, so the content does not shift when the list grows or shrinks past\n * the point where it needs to scroll — and it takes that space out of its\n * right padding, so the content stays centered rather than hugging the left.\n * With overlay scrollbars there is no gutter and the padding stays even.\n *\n * @internal\n */\nexport function ScrollArea(props: {children: React.ReactNode; padding: number}) {\n  const {children, padding} = props\n  const {space} = useTheme_v2()\n  const ref = useRef<HTMLDivElement | null>(null)\n  const [gutter, setGutter] = useState(() => lastGutter)\n\n  useEffect(() => {\n    const element = ref.current\n\n    if (!element) return undefined\n\n    // The reserved gutter is the part of the box the content cannot use\n    const measure = () => {\n      lastGutter = element.offsetWidth - element.clientWidth\n      setGutter(lastGutter)\n    }\n\n    measure()\n\n    const observer = new ResizeObserver(measure)\n\n    observer.observe(element)\n\n    return () => observer.disconnect()\n  }, [])\n\n  const inset = useMemo<ScrollAreaInset>(\n    () => ({\n      left: space[padding],\n      right: Math.max(0, space[padding] - gutter),\n      bottom: space[padding],\n    }),\n    [gutter, padding, space],\n  )\n\n  return (\n    <Box\n      className={root}\n      flex={1}\n      overflow=\"auto\"\n      padding={padding}\n      ref={ref}\n      style={{paddingRight: inset.right}}\n    >\n      <ScrollAreaInsetContext value={inset}>{children}</ScrollAreaInsetContext>\n    </Box>\n  )\n}\n\n/**\n * Content that runs edge to edge in a scroll area — up to the scrollbar —\n * instead of sitting inside its padding. It goes last: it runs down to the\n * bottom edge too.\n *\n * @internal\n */\nexport function ScrollAreaBleed(props: {children: React.ReactNode}) {\n  const {left, right, bottom} = useContext(ScrollAreaInsetContext)\n\n  return (\n    <div style={{marginLeft: -left, marginRight: -right, marginBottom: -bottom}}>\n      {props.children}\n    </div>\n  )\n}\n","import {createVar, style, styleVariants} from '@vanilla-extract/css'\n\n/**\n * The dark scheme covers the right side of the preview behind a diagonal cut,\n * like the \"Auto\" appearance preview in macOS System Settings shows both\n * schemes at once.\n */\nconst DARK_CLIP_PATH = 'polygon(58% 0, 100% 0, 100% 100%, 42% 100%)'\n\n/** The thickness of a line of text — bold enough to survive a half-size preview */\nconst LINE = 4\n\n/**\n * The colors a mockup paints with — only the ones the theme options change —\n * assigned per color scheme from the theme it previews\n */\nexport const colors = {\n  bg: createVar(),\n  fg: createVar(),\n  mutedFg: createVar(),\n  border: createVar(),\n  accent: createVar(),\n  avatar: createVar(),\n  selectedBg: createVar(),\n  selectedFg: createVar(),\n  inputBg: createVar(),\n  inputBorder: createVar(),\n}\n\nexport const root = style({\n  position: 'relative',\n  aspectRatio: '16 / 9',\n  overflow: 'hidden',\n})\n\nconst studioBase = style({\n  position: 'absolute',\n  inset: 0,\n  display: 'flex',\n  flexDirection: 'column',\n  background: colors.bg,\n})\n\nexport const studio = styleVariants({\n  light: [studioBase],\n  dark: [studioBase, {clipPath: DARK_CLIP_PATH}],\n})\n\nexport const navbar = style({\n  flex: 'none',\n  display: 'flex',\n  alignItems: 'center',\n  gap: 5,\n  height: '18%',\n  padding: '0 5%',\n  borderBottom: `1px solid ${colors.border}`,\n})\n\nexport const logo = style({\n  flex: 'none',\n  width: 8,\n  height: 8,\n  borderRadius: 2,\n  background: colors.accent,\n})\n\nexport const spacer = style({\n  flex: 1,\n})\n\nexport const avatar = style({\n  flex: 'none',\n  width: 8,\n  height: 8,\n  borderRadius: '50%',\n  background: colors.avatar,\n})\n\nexport const body = style({\n  flex: 1,\n  display: 'flex',\n  minHeight: 0,\n})\n\nexport const list = style({\n  flex: 'none',\n  display: 'flex',\n  flexDirection: 'column',\n  width: '36%',\n  borderRight: `1px solid ${colors.border}`,\n})\n\nexport const listRow = style({\n  flex: 'none',\n  display: 'flex',\n  alignItems: 'center',\n  height: '18%',\n  padding: '0 9%',\n  selectors: {\n    \"&[data-selected='true']\": {\n      background: colors.selectedBg,\n    },\n  },\n})\n\nexport const pane = style({\n  flex: 1,\n  display: 'flex',\n  flexDirection: 'column',\n  minWidth: 0,\n})\n\nexport const form = style({\n  flex: 1,\n  display: 'flex',\n  flexDirection: 'column',\n  gap: 7,\n  padding: '9% 8% 0',\n  minHeight: 0,\n  overflow: 'hidden',\n})\n\nexport const field = style({\n  flex: 'none',\n  display: 'flex',\n  flexDirection: 'column',\n  gap: 3,\n})\n\nexport const input = style({\n  height: 12,\n  borderRadius: 3,\n  background: colors.inputBg,\n  boxShadow: `inset 0 0 0 1px ${colors.inputBorder}`,\n})\n\nexport const footer = style({\n  flex: 'none',\n  display: 'flex',\n  alignItems: 'center',\n  justifyContent: 'flex-end',\n  height: '20%',\n  padding: '0 8%',\n  borderTop: `1px solid ${colors.border}`,\n})\n\nexport const button = style({\n  width: '32%',\n  height: '50%',\n  borderRadius: 3,\n  background: colors.accent,\n})\n\nconst lineBase = style({\n  flex: 'none',\n  height: LINE,\n  borderRadius: LINE / 2,\n})\n\n/** A line of text, in one of the text colors — its width is set inline */\nexport const line = styleVariants({\n  fg: [lineBase, {background: colors.fg}],\n  muted: [lineBase, {background: colors.mutedFg}],\n  selected: [lineBase, {background: colors.selectedFg}],\n})\n","import {ThemeProvider, useTheme_v2} from '@sanity/ui'\nimport {type ThemeColorSchemeKey} from '@sanity/ui/theme'\nimport {assignInlineVars} from '@vanilla-extract/dynamic'\nimport {useMemo} from 'react'\n\nimport {buildTheme} from '../theme/buildTheme'\nimport type {BuildThemeOptions} from '../theme/options'\n\nimport {\n  avatar,\n  body,\n  button,\n  colors,\n  field,\n  footer,\n  form,\n  input,\n  line,\n  list,\n  listRow,\n  logo,\n  navbar,\n  pane,\n  root,\n  spacer,\n  studio,\n} from './ThemePreview.css'\n\n/** The document rows in the list pane — the widths of their title lines */\nconst LIST_ROWS = ['62%', '46%', '70%', '52%']\n\n/** The fields in the document form — the widths of their labels */\nconst FIELDS = ['32%', '24%']\n\n/**\n * A tiny, lo-fi mockup of a Studio in the given theme — the navbar over the\n * structure tool with a list of documents on the left and a document form on\n * the right — in both color schemes at once: the light scheme on the left and\n * the dark scheme on the right, split diagonally. It only paints colors the\n * theme options change (backgrounds, text, borders, the accent) so that a\n * glance shows what the theme does to the Studio — with few and bold enough\n * elements to still read when scaled down to a thumbnail.\n *\n * @internal\n */\nexport function ThemePreview(props: {options: BuildThemeOptions}) {\n  const {options} = props\n  const theme = useMemo(() => buildTheme(options), [options])\n\n  return (\n    <div aria-hidden className={root}>\n      <ThemeProvider scheme=\"light\" theme={theme} tone=\"default\">\n        <MockStudio scheme=\"light\" />\n      </ThemeProvider>\n      <ThemeProvider scheme=\"dark\" theme={theme} tone=\"default\">\n        <MockStudio scheme=\"dark\" />\n      </ThemeProvider>\n    </div>\n  )\n}\n\nfunction MockStudio(props: {scheme: ThemeColorSchemeKey}) {\n  const {scheme} = props\n  const {color} = useTheme_v2()\n  const selected = color.selectable.default.selected\n  const inputColor = color.input.default.enabled\n\n  return (\n    <div\n      className={studio[scheme]}\n      style={assignInlineVars({\n        [colors.bg]: color.bg,\n        [colors.fg]: color.fg,\n        [colors.mutedFg]: color.muted.fg,\n        [colors.border]: color.border,\n        [colors.accent]: color.button.default.primary.enabled.bg,\n        [colors.avatar]: color.avatar.blue.bg,\n        [colors.selectedBg]: selected.bg,\n        [colors.selectedFg]: selected.fg,\n        [colors.inputBg]: inputColor.bg,\n        [colors.inputBorder]: inputColor.border,\n      })}\n    >\n      <div className={navbar}>\n        <div className={logo} />\n        <div className={line.fg} style={{width: '22%'}} />\n        <div className={spacer} />\n        <div className={avatar} />\n      </div>\n\n      <div className={body}>\n        <div className={list}>\n          {LIST_ROWS.map((width, index) => {\n            const isSelected = index === 1\n\n            return (\n              <div key={width} className={listRow} data-selected={isSelected}>\n                <div className={isSelected ? line.selected : line.muted} style={{width}} />\n              </div>\n            )\n          })}\n        </div>\n\n        <div className={pane}>\n          <div className={form}>\n            <div className={line.fg} style={{width: '45%'}} />\n            {FIELDS.map((width) => (\n              <div key={width} className={field}>\n                <div className={line.muted} style={{width}} />\n                <div className={input} />\n              </div>\n            ))}\n          </div>\n          <div className={footer}>\n            <div className={button} />\n          </div>\n        </div>\n      </div>\n    </div>\n  )\n}\n","import {Card} from '@sanity/ui'\n\nimport type {BuildThemeOptions} from '../theme/options'\nimport {ThemePreview} from './ThemePreview'\n\n/**\n * The floating preview card of a theme: the lo-fi studio mockup on a raised,\n * rounded card, like the appearance previews in macOS System Settings.\n *\n * @internal\n */\nexport function ThemeThumbnail(props: {options: BuildThemeOptions}) {\n  return (\n    <Card overflow=\"hidden\" radius={3} shadow={1}>\n      <ThemePreview options={props.options} />\n    </Card>\n  )\n}\n","import {style} from '@vanilla-extract/css'\n\n/** A removed theme's thumbnail, dimmed to read as removed */\nexport const removedThumbnail = style({\n  opacity: 0.6,\n})\n","import {Box, Button, Flex, Stack, Text} from '@sanity/ui'\n\nimport type {ThemerProps} from '#types'\n\nimport {ScrollArea} from './ScrollArea'\nimport {displayTitle} from './themes'\nimport {ThemeThumbnail} from './ThemeThumbnail'\n\nimport {removedThumbnail} from './RemovedThemes.css'\n\n/**\n * The flow for restoring removed themes: the presets and custom themes the\n * user took out of the list, each with a button to put it back — and, for\n * custom themes, one to delete it for good. The machine leaves the flow once\n * the last one is gone.\n *\n * @internal\n */\nexport function RemovedThemes({actorRef, removed}: Pick<ThemerProps, 'actorRef' | 'removed'>) {\n  return (\n    <ScrollArea padding={3}>\n      <Stack gap={5}>\n        {removed.map((theme) => (\n          <Stack key={theme.slug} gap={3}>\n            <Box className={removedThumbnail}>\n              <ThemeThumbnail options={theme.options} />\n            </Box>\n            <Text align=\"center\" size={1} textOverflow=\"ellipsis\">\n              {displayTitle(theme.title)}\n            </Text>\n            <Flex gap={2} justify=\"center\">\n              <Button\n                mode=\"ghost\"\n                onClick={() => actorRef.send({type: 'theme.restore', slug: theme.slug})}\n                padding={2}\n                text=\"Restore\"\n              />\n              {theme.source === 'custom' && (\n                <Button\n                  mode=\"ghost\"\n                  onClick={() => actorRef.send({type: 'theme.delete', slug: theme.slug})}\n                  padding={2}\n                  text=\"Delete\"\n                  tone=\"critical\"\n                />\n              )}\n            </Flex>\n          </Stack>\n        ))}\n      </Stack>\n    </ScrollArea>\n  )\n}\n","import {type ThemeColorSchemeKey} from '@sanity/ui/theme'\n\nimport {hexToHsl, hslToHex, relativeLuminance} from '../theme/hsl'\nimport {\n  type BuildThemeOptions,\n  DEFAULT_BACKGROUND,\n  SCHEMES,\n  type SchemeThemeOptions,\n} from '../theme/options'\n\n/**\n * The swatches of an image palette — the same set the Sanity image pipeline\n * derives for uploaded assets (`metadata.palette`), extracted on device here.\n *\n * @internal\n */\nexport type ImagePaletteKey =\n  | 'dominant'\n  | 'vibrant'\n  | 'lightVibrant'\n  | 'darkVibrant'\n  | 'muted'\n  | 'lightMuted'\n  | 'darkMuted'\n\n/**\n * An image palette: a hex color per swatch, or `null` when the image has no\n * color that qualifies for it.\n *\n * @internal\n */\nexport type ImagePalette = Record<ImagePaletteKey, string | null>\n\n/**\n * The swatches a theme can be built around — every swatch but the dominant\n * one, which only repeats one of them.\n *\n * @internal\n */\nexport type ImagePaletteVariant = Exclude<ImagePaletteKey, 'dominant'>\n\n/** The variants in the order the tool offers them @internal */\nexport const IMAGE_PALETTE_VARIANTS: ImagePaletteVariant[] = [\n  'muted',\n  'vibrant',\n  'lightMuted',\n  'lightVibrant',\n  'darkMuted',\n  'darkVibrant',\n]\n\n/** @internal */\nexport const IMAGE_PALETTE_TITLES: Record<ImagePaletteKey, string> = {\n  dominant: 'Dominant',\n  vibrant: 'Vibrant',\n  lightVibrant: 'Light vibrant',\n  darkVibrant: 'Dark vibrant',\n  muted: 'Muted',\n  lightMuted: 'Light muted',\n  darkMuted: 'Dark muted',\n}\n\n/** Pixels the way a canvas hands them out: rows of RGBA bytes @internal */\nexport interface PixelData {\n  data: ArrayLike<number>\n  width: number\n  height: number\n}\n\ninterface Bucket {\n  count: number\n  r: number\n  g: number\n  b: number\n}\n\ninterface Candidate {\n  hex: string\n  population: number\n  saturation: number\n  lightness: number\n}\n\n/** What a swatch looks for: a lightness and saturation to aim at, within bounds */\ninterface Target {\n  lightness: [target: number, min: number, max: number]\n  saturation: [target: number, min: number, max: number]\n}\n\n/**\n * The swatch targets of the Vibrant algorithm (the one behind Sanity's image\n * palettes), in the order they get to claim colors.\n */\nconst TARGETS: Array<[key: Exclude<ImagePaletteKey, 'dominant'>, target: Target]> = [\n  ['vibrant', {lightness: [0.5, 0.3, 0.7], saturation: [1, 0.35, 1]}],\n  ['lightVibrant', {lightness: [0.74, 0.55, 1], saturation: [1, 0.35, 1]}],\n  ['darkVibrant', {lightness: [0.26, 0, 0.45], saturation: [1, 0.35, 1]}],\n  ['muted', {lightness: [0.5, 0.3, 0.7], saturation: [0.3, 0, 0.4]}],\n  ['lightMuted', {lightness: [0.74, 0.55, 1], saturation: [0.3, 0, 0.4]}],\n  ['darkMuted', {lightness: [0.26, 0, 0.45], saturation: [0.3, 0, 0.4]}],\n]\n\nconst SATURATION_WEIGHT = 3\nconst LIGHTNESS_WEIGHT = 6.5\nconst POPULATION_WEIGHT = 0.5\n\n/** Pixels this transparent are not part of the picture */\nconst MINIMUM_ALPHA = 125\n\n/** Near-black and near-white pixels are backdrop rather than color */\nconst MINIMUM_LIGHTNESS = 0.05\nconst MAXIMUM_LIGHTNESS = 0.95\n\n/** How many of the 8 bits per channel survive the quantization */\nconst QUANTIZE_BITS = 5\n\n/**\n * Extracts the color palette of an image from its pixels, the way the Vibrant\n * algorithm does: the colors are quantized into a coarse histogram, and each\n * swatch claims the color that comes closest to its target lightness and\n * saturation — weighted by how much of the image it covers — that no other\n * swatch has claimed yet. The dominant swatch is simply the most common\n * color. Runs anywhere pixels come from, so it can run on device.\n *\n * @internal\n */\nexport function extractImagePalette(pixels: PixelData): ImagePalette {\n  const candidates = quantize(pixels)\n  const palette: ImagePalette = {\n    dominant: null,\n    vibrant: null,\n    lightVibrant: null,\n    darkVibrant: null,\n    muted: null,\n    lightMuted: null,\n    darkMuted: null,\n  }\n\n  if (candidates.length === 0) return palette\n\n  const maximumPopulation = Math.max(...candidates.map((candidate) => candidate.population))\n  const claimed = new Set<string>()\n\n  for (const [key, target] of TARGETS) {\n    let best: Candidate | null = null\n    let bestScore = -Infinity\n\n    for (const candidate of candidates) {\n      if (claimed.has(candidate.hex) || !matchesTarget(candidate, target)) continue\n\n      const score = scoreCandidate(candidate, target, maximumPopulation)\n\n      if (score > bestScore) {\n        best = candidate\n        bestScore = score\n      }\n    }\n\n    if (best) {\n      palette[key] = best.hex\n      claimed.add(best.hex)\n    }\n  }\n\n  palette.dominant = candidates.reduce((most, candidate) =>\n    candidate.population > most.population ? candidate : most,\n  ).hex\n\n  return palette\n}\n\n/**\n * Turns the pixels into a histogram of quantized colors, each averaged over\n * the pixels it stands for, leaving out transparent pixels and the near-black\n * and near-white ones that are backdrop rather than color.\n */\nfunction quantize(pixels: PixelData): Candidate[] {\n  const {data} = pixels\n  const buckets = new Map<number, Bucket>()\n  const shift = 8 - QUANTIZE_BITS\n  const length = Math.min(data.length, pixels.width * pixels.height * 4)\n\n  for (let offset = 0; offset + 3 < length; offset += 4) {\n    const r = data[offset]\n    const g = data[offset + 1]\n    const b = data[offset + 2]\n    const a = data[offset + 3]\n\n    if (a < MINIMUM_ALPHA) continue\n\n    const lightness = (Math.max(r, g, b) + Math.min(r, g, b)) / 510\n\n    if (lightness < MINIMUM_LIGHTNESS || lightness > MAXIMUM_LIGHTNESS) continue\n\n    const key =\n      ((r >> shift) << (QUANTIZE_BITS * 2)) | ((g >> shift) << QUANTIZE_BITS) | (b >> shift)\n    const bucket = buckets.get(key)\n\n    if (bucket) {\n      bucket.count++\n      bucket.r += r\n      bucket.g += g\n      bucket.b += b\n    } else {\n      buckets.set(key, {count: 1, r, g, b})\n    }\n  }\n\n  const candidates: Candidate[] = []\n\n  for (const bucket of buckets.values()) {\n    const r = Math.round(bucket.r / bucket.count)\n    const g = Math.round(bucket.g / bucket.count)\n    const b = Math.round(bucket.b / bucket.count)\n    const {saturation, lightness} = saturationAndLightness(r, g, b)\n\n    candidates.push({hex: rgbToHex(r, g, b), population: bucket.count, saturation, lightness})\n  }\n\n  return candidates\n}\n\nfunction matchesTarget(candidate: Candidate, target: Target): boolean {\n  return (\n    candidate.lightness >= target.lightness[1] &&\n    candidate.lightness <= target.lightness[2] &&\n    candidate.saturation >= target.saturation[1] &&\n    candidate.saturation <= target.saturation[2]\n  )\n}\n\nfunction scoreCandidate(candidate: Candidate, target: Target, maximumPopulation: number): number {\n  return (\n    SATURATION_WEIGHT * (1 - Math.abs(candidate.saturation - target.saturation[0])) +\n    LIGHTNESS_WEIGHT * (1 - Math.abs(candidate.lightness - target.lightness[0])) +\n    POPULATION_WEIGHT * (candidate.population / maximumPopulation)\n  )\n}\n\nfunction saturationAndLightness(r: number, g: number, b: number) {\n  const max = Math.max(r, g, b) / 255\n  const min = Math.min(r, g, b) / 255\n  const lightness = (max + min) / 2\n  const delta = max - min\n  const saturation =\n    delta === 0 ? 0 : lightness > 0.5 ? delta / (2 - max - min) : delta / (max + min)\n\n  return {saturation, lightness}\n}\n\nfunction rgbToHex(r: number, g: number, b: number): string {\n  return `#${[r, g, b].map((channel) => channel.toString(16).padStart(2, '0')).join('')}`\n}\n\n/** Reads `#rgb` and `#rrggbb` alike — stored palettes may hold either */\nfunction hexToRgb(hex: string): [number, number, number] {\n  const expanded =\n    hex.length === 4 ? `${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}` : hex.slice(1)\n\n  return [\n    parseInt(expanded.slice(0, 2), 16),\n    parseInt(expanded.slice(2, 4), 16),\n    parseInt(expanded.slice(4, 6), 16),\n  ]\n}\n\n/** Mixes `amount` of `color` into `base` */\nfunction tint(base: string, color: string, amount: number): string {\n  const [r1, g1, b1] = hexToRgb(base)\n  const [r2, g2, b2] = hexToRgb(color)\n\n  return rgbToHex(\n    Math.round(r1 + (r2 - r1) * amount),\n    Math.round(g1 + (g2 - g1) * amount),\n    Math.round(b1 + (b2 - b1) * amount),\n  )\n}\n\n/** How much of the palette tints each scheme's stock background */\nconst BACKGROUND_TINT = {light: 0.08, dark: 0.3}\n\n/**\n * The WCAG AA contrast for normal text — what a button label needs against\n * the button. Sanity UI labels solid buttons in white on the accent's 500\n * tint in the light scheme and in black on its 400 tint in the dark scheme\n * (lighter than the accent, so an accent that passes against black passes\n * there too).\n */\nconst MINIMUM_ACCENT_CONTRAST = 4.5\nconst BUTTON_LABEL: Record<ThemeColorSchemeKey, string> = {light: '#ffffff', dark: '#000000'}\nconst ACCENT_LIGHTNESS_STEP = 0.01\n\nfunction contrastRatio(a: string, b: string): number {\n  const [lighter, darker] = [relativeLuminance(a), relativeLuminance(b)].sort((x, y) => y - x)\n\n  return (lighter + 0.05) / (darker + 0.05)\n}\n\n/**\n * Makes an accent readable as a button in the given scheme: a light scheme\n * accent is darkened until white text on it reaches AA contrast, a dark\n * scheme accent lightened until black text does — as far as the accent's\n * hue and saturation allow. Accents that already pass come back untouched.\n *\n * @internal\n */\nexport function readableAccent(hex: string, scheme: ThemeColorSchemeKey): string {\n  const label = BUTTON_LABEL[scheme]\n  const {h, s} = hexToHsl(hex)\n  let {l} = hexToHsl(hex)\n  let current = hex\n\n  while (contrastRatio(current, label) < MINIMUM_ACCENT_CONTRAST) {\n    const next = scheme === 'light' ? l - ACCENT_LIGHTNESS_STEP : l + ACCENT_LIGHTNESS_STEP\n\n    if (next < 0 || next > 1) break\n\n    l = next\n    current = hslToHex({h, s, l})\n  }\n\n  return current\n}\n\n/** The accent a variant gives a scheme, made readable on a button */\nfunction variantAccent(\n  palette: ImagePalette,\n  variant: ImagePaletteVariant | null,\n  scheme: ThemeColorSchemeKey,\n): string | null {\n  const swatch =\n    (variant ? palette[variant] : null) ??\n    palette.vibrant ??\n    (scheme === 'light' ? palette.darkVibrant : palette.lightVibrant) ??\n    palette.dominant\n\n  return swatch === null ? null : readableAccent(swatch, scheme)\n}\n\n/**\n * Derives theme options from an image palette: the accent of both schemes is\n * the swatch of the chosen variant — or, without one, the vibrant swatch,\n * each scheme falling back to the vibrant swatch of its own end of the scale —\n * adjusted until it is readable as a button. The muted swatch becomes the text color, and the light and dark muted\n * swatches tint the stock backgrounds of their scheme — enough to carry the\n * image's tone without giving up a usable canvas. Whatever the palette lacks\n * stays at the theme defaults.\n *\n * @internal\n */\nexport function optionsFromImagePalette(\n  palette: ImagePalette,\n  variant?: ImagePaletteVariant,\n): BuildThemeOptions {\n  const options: BuildThemeOptions = {}\n\n  const light = schemeFromPalette(\n    variantAccent(palette, variant ?? null, 'light'),\n    palette.muted ?? palette.darkMuted,\n    palette.lightMuted ?? palette.muted ?? palette.lightVibrant,\n    'light',\n  )\n  const dark = schemeFromPalette(\n    variantAccent(palette, variant ?? null, 'dark'),\n    palette.muted ?? palette.lightMuted,\n    palette.darkMuted ?? palette.muted ?? palette.darkVibrant,\n    'dark',\n  )\n\n  if (light) options.light = light\n  if (dark) options.dark = dark\n\n  return options\n}\n\nfunction schemeFromPalette(\n  accent: string | null,\n  text: string | null,\n  backgroundTint: string | null,\n  scheme: 'light' | 'dark',\n): SchemeThemeOptions | null {\n  const options: SchemeThemeOptions = {}\n\n  if (accent) options.accent = accent\n  if (text) options.text = text\n  if (backgroundTint) {\n    options.background = tint(DEFAULT_BACKGROUND[scheme], backgroundTint, BACKGROUND_TINT[scheme])\n  }\n\n  return Object.keys(options).length > 0 ? options : null\n}\n\n/**\n * Applies an image palette to existing theme options: the colors the palette\n * provides replace the current ones scheme by scheme, and whatever it does\n * not touch — like the contrast — stays as it is.\n *\n * @internal\n */\nexport function applyImagePalette(\n  options: BuildThemeOptions,\n  palette: ImagePalette,\n  variant?: ImagePaletteVariant,\n): BuildThemeOptions {\n  const derived = optionsFromImagePalette(palette, variant)\n  const next: BuildThemeOptions = {...options}\n\n  for (const scheme of SCHEMES) {\n    if (derived[scheme]) next[scheme] = {...options[scheme], ...derived[scheme]}\n  }\n\n  return next\n}\n\n/**\n * The variant a theme is built around: the one whose swatch is the theme's\n * accent, or `null` when the accent comes from somewhere else.\n *\n * @internal\n */\nexport function currentImageVariant(\n  options: BuildThemeOptions,\n  palette: ImagePalette,\n): ImagePaletteVariant | null {\n  const accent = options.light?.accent\n\n  if (!accent) return null\n\n  return (\n    IMAGE_PALETTE_VARIANTS.find(\n      (variant) => palette[variant] !== null && variantAccent(palette, variant, 'light') === accent,\n    ) ?? null\n  )\n}\n\n/**\n * How much a swatch has going for it as an accent: saturation first, then\n * closeness to mid lightness — the range where an accent reads best.\n */\nfunction interest(hex: string): number {\n  const {s, l} = hexToHsl(hex)\n\n  return 0.1 + 0.55 * s + 0.35 * (1 - Math.abs(l - 0.5) * 2)\n}\n\n/**\n * Picks a variant for the \"I'm feeling lucky\" button: a random one, weighted\n * by how interesting its swatch is as an accent, and never the one the theme\n * already uses while there are others to pick from.\n *\n * @internal\n */\nexport function pickLuckyVariant(\n  palette: ImagePalette,\n  options: {exclude?: ImagePaletteVariant | null; random?: () => number} = {},\n): ImagePaletteVariant | null {\n  const {exclude = null, random = Math.random} = options\n  let candidates = IMAGE_PALETTE_VARIANTS.filter((variant) => palette[variant] !== null)\n\n  if (candidates.length > 1) {\n    candidates = candidates.filter((variant) => variant !== exclude)\n  }\n\n  if (candidates.length === 0) return null\n\n  const weights = candidates.map((variant) => interest(palette[variant]!))\n  const total = weights.reduce((sum, weight) => sum + weight, 0)\n  let pick = random() * total\n\n  for (const [index, variant] of candidates.entries()) {\n    pick -= weights[index]\n\n    if (pick < 0) return variant\n  }\n\n  return candidates.at(-1) ?? null\n}\n\n/** A theme title for the image a palette came from, e.g. `sunset-beach.jpg` → `sunset beach` @internal */\nexport function titleFromFileName(name: string): string {\n  return (\n    name\n      .replace(/\\.[^.]+$/, '')\n      .replace(/[-_]+/g, ' ')\n      .trim() || 'Image theme'\n  )\n}\n","import {Button, type ButtonProps, Text} from '@sanity/ui'\nimport {Tooltip} from '@sanity/ui/tooltip'\n\n/**\n * A button with an animated tooltip instead of a `title` attribute, sized like\n * the Studio's own buttons (`padding` and `gap` of 2). Icon-only buttons take\n * the tooltip as their accessible name.\n *\n * @internal\n */\nexport function TooltipButton(props: ButtonProps & {tooltip: string}) {\n  const {tooltip, ...buttonProps} = props\n\n  return (\n    <Tooltip animate content={<Text size={1}>{tooltip}</Text>} placement=\"bottom\" portal>\n      <Button\n        aria-label={buttonProps.text === undefined ? tooltip : undefined}\n        gap={2}\n        padding={2}\n        {...buttonProps}\n      />\n    </Tooltip>\n  )\n}\n","import {ImageIcon} from '@sanity/icons/Image'\nimport type {ButtonProps} from '@sanity/ui'\nimport {useRef} from 'react'\n\nimport {TooltipButton} from './TooltipButton'\n\n/**\n * A button that opens the file picker for an image, and hands the chosen file\n * over — the picker is a hidden file input, so nothing is uploaded anywhere.\n *\n * @internal\n */\nexport function ImageFileButton(\n  props: {onFile: (file: File) => void; tooltip: string} & Pick<\n    ButtonProps,\n    'disabled' | 'loading' | 'mode' | 'padding' | 'text' | 'width'\n  >,\n) {\n  const {onFile, ...buttonProps} = props\n  const inputRef = useRef<HTMLInputElement | null>(null)\n\n  return (\n    <>\n      <TooltipButton {...buttonProps} icon={ImageIcon} onClick={() => inputRef.current?.click()} />\n      <input\n        accept=\"image/*\"\n        hidden\n        onChange={(event) => {\n          const file = event.currentTarget.files?.[0]\n\n          // Picking the same file again should work, so the input forgets it\n          event.currentTarget.value = ''\n\n          if (file) onFile(file)\n        }}\n        ref={inputRef}\n        type=\"file\"\n      />\n    </>\n  )\n}\n","import type {PixelData} from './imagePalette'\n\n/**\n * The longest side the image is scaled down to before its colors are read —\n * a few thousand pixels are plenty for a palette, and keep it instant\n */\nconst SAMPLE_SIZE = 96\n\n/**\n * Reads the pixels of an image file on device: the image is decoded, drawn\n * onto a small canvas and read back, so nothing leaves the browser.\n *\n * @internal\n */\nexport async function readImagePixels(file: Blob): Promise<PixelData> {\n  const image = await decodeImage(file)\n\n  try {\n    const scale = Math.min(1, SAMPLE_SIZE / Math.max(image.width, image.height))\n    const width = Math.max(1, Math.round(image.width * scale))\n    const height = Math.max(1, Math.round(image.height * scale))\n    const canvas = document.createElement('canvas')\n\n    canvas.width = width\n    canvas.height = height\n\n    const context = canvas.getContext('2d', {willReadFrequently: true})\n\n    if (!context) throw new Error('Could not draw the image')\n\n    context.drawImage(image, 0, 0, width, height)\n\n    return {data: context.getImageData(0, 0, width, height).data, width, height}\n  } finally {\n    // Where `createImageBitmap` is missing, `ImageBitmap` may be too\n    if (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap) image.close()\n  }\n}\n\nasync function decodeImage(file: Blob): Promise<ImageBitmap | HTMLImageElement> {\n  if (typeof createImageBitmap === 'function') {\n    try {\n      return await createImageBitmap(file)\n    } catch {\n      // Some browsers cannot decode every format this way (e.g. SVG) — an\n      // image element handles whatever the browser can display\n    }\n  }\n\n  const url = URL.createObjectURL(file)\n\n  try {\n    return await new Promise<HTMLImageElement>((resolve, reject) => {\n      const image = new Image()\n\n      image.addEventListener('load', () => resolve(image), {once: true})\n      image.addEventListener('error', () => reject(new Error('Could not decode the image')), {\n        once: true,\n      })\n      image.src = url\n    })\n  } finally {\n    URL.revokeObjectURL(url)\n  }\n}\n","import {useToast} from '@sanity/ui/toast'\nimport {useCallback, useEffect, useRef, useState} from 'react'\n\nimport {readImagePixels} from './imageFile'\nimport {extractImagePalette, type ImagePalette} from './imagePalette'\n\n/**\n * Extracts the palette of image files on device and hands it to `onPalette`,\n * along with the file it came from. Failures end up as a toast.\n *\n * @internal\n */\nexport function useImagePalette(onPalette: (palette: ImagePalette, file: File) => void): {\n  busy: boolean\n  pickImage: (file: File) => void\n} {\n  const toast = useToast()\n  const [busy, setBusy] = useState(false)\n  const onPaletteRef = useRef(onPalette)\n  const mountedRef = useRef(true)\n  // Picks are numbered so that a slow earlier image cannot overwrite a later\n  // pick once its extraction finishes\n  const latestPickRef = useRef(0)\n\n  useEffect(() => {\n    onPaletteRef.current = onPalette\n  }, [onPalette])\n\n  useEffect(() => {\n    mountedRef.current = true\n\n    return () => {\n      mountedRef.current = false\n    }\n  }, [])\n\n  const pickImage = useCallback(\n    (file: File) => {\n      const pick = ++latestPickRef.current\n\n      setBusy(true)\n\n      // Whether this pick still matters: it is the latest one and the\n      // component that asked for it is still around\n      const isCurrent = () => mountedRef.current && latestPickRef.current === pick\n\n      const extract = async () => {\n        const palette = extractImagePalette(await readImagePixels(file))\n\n        if (!isCurrent()) return\n\n        if (Object.values(palette).every((swatch) => swatch === null)) {\n          toast.push({status: 'warning', title: 'Found no colors in that image'})\n        } else {\n          onPaletteRef.current(palette, file)\n        }\n      }\n\n      extract()\n        .catch(() => {\n          if (isCurrent()) toast.push({status: 'error', title: 'Could not read that image'})\n        })\n        .finally(() => {\n          if (isCurrent()) setBusy(false)\n        })\n    },\n    [toast],\n  )\n\n  return {busy, pickImage}\n}\n","import {createVar, style} from '@vanilla-extract/css'\n\nconst TILE_SIZE = 24\nconst TILE_GAP = 4\n\n/** The image spans both rows of tiles */\nconst IMAGE_SIZE = TILE_SIZE * 2 + TILE_GAP\n\n/** The variant previews are the theme thumbnails, laid out at this width and scaled down */\nexport const VARIANT_WIDTH = 144\n\nexport const VARIANT_GAP = 8\nexport const ROW_PADDING = 12\n\n/** The frame around a variant's thumbnail, on either side */\nexport const VARIANT_FRAME = 4\n\n/** The width of one variant's thumbnail, set on the row once it is measured */\nexport const variantWidth = createVar()\n\n/** How much a variant's thumbnail is scaled down from `VARIANT_WIDTH` */\nexport const variantScale = createVar()\n\nexport const paletteGrid = style({\n  display: 'grid',\n  gridTemplateColumns: `repeat(3, ${TILE_SIZE}px)`,\n  gridAutoRows: TILE_SIZE,\n  gap: TILE_GAP,\n  selectors: {\n    \"&[data-with-image='true']\": {\n      gridTemplateColumns: `${IMAGE_SIZE}px repeat(3, ${TILE_SIZE}px)`,\n    },\n  },\n})\n\nexport const imageTile = style({\n  display: 'block',\n  gridRow: 'span 2',\n  width: IMAGE_SIZE,\n  height: IMAGE_SIZE,\n  borderRadius: 3,\n  objectFit: 'cover',\n  boxShadow: 'inset 0 0 0 1px var(--card-border-color)',\n})\n\nexport const tile = style({\n  display: 'block',\n  borderRadius: 3,\n  boxShadow: 'inset 0 0 0 1px var(--card-border-color)',\n  selectors: {\n    \"&[data-empty='true']\": {\n      background:\n        'repeating-linear-gradient(-45deg, transparent 0 3px, var(--card-border-color) 3px 4px)',\n    },\n  },\n})\n\n/**\n * The variants scroll sideways and snap into place, bleeding into the card's\n * padding so the row runs from edge to edge\n */\nexport const variantRow = style({\n  display: 'flex',\n  gap: VARIANT_GAP,\n  margin: `0 -${ROW_PADDING}px`,\n  padding: `0 ${ROW_PADDING}px`,\n  overflowX: 'auto',\n  scrollSnapType: 'x mandatory',\n  scrollPaddingLeft: ROW_PADDING,\n  scrollbarWidth: 'thin',\n})\n\nexport const variantButton = style({\n  'appearance': 'none',\n  'flex': 'none',\n  'display': 'block',\n  'boxSizing': 'border-box',\n  'width': `calc(${variantWidth} + ${VARIANT_FRAME * 2}px)`,\n  'margin': 0,\n  'padding': 0,\n  'border': 0,\n  'background': 'none',\n  'color': 'inherit',\n  'font': 'inherit',\n  'textAlign': 'center',\n  'cursor': 'pointer',\n  'scrollSnapAlign': 'start',\n  ':focus': {\n    outline: 'none',\n  },\n})\n\n/**\n * Clips the scaled-down thumbnail to its visual size, with room for the ring\n * — drawn inside the frame, like the theme cards', so the scrolling row\n * never clips it\n */\nexport const variantFrame = style({\n  display: 'block',\n  boxSizing: 'border-box',\n  width: `calc(${variantWidth} + ${VARIANT_FRAME * 2}px)`,\n  height: `calc(${variantWidth} * 9 / 16 + ${VARIANT_FRAME * 2}px)`,\n  padding: VARIANT_FRAME,\n  borderRadius: 7,\n  overflow: 'hidden',\n  transition: 'box-shadow 100ms',\n  selectors: {\n    [`${variantButton}:hover &`]: {\n      boxShadow: 'inset 0 0 0 2px var(--card-border-color)',\n    },\n    [`${variantButton}[aria-pressed='true'] &`]: {\n      boxShadow: 'inset 0 0 0 2px var(--card-focus-ring-color)',\n    },\n    [`${variantButton}:focus-visible &`]: {\n      outline: '2px solid var(--card-focus-ring-color)',\n      outlineOffset: -2,\n    },\n  },\n})\n\nexport const variantScaleBox = style({\n  display: 'block',\n  width: VARIANT_WIDTH,\n  transform: `scale(${variantScale})`,\n  transformOrigin: 'top left',\n})\n","import {SparklesIcon} from '@sanity/icons/Sparkles'\nimport {Box, Card, Flex, Stack, Text} from '@sanity/ui'\nimport {Tooltip} from '@sanity/ui/tooltip'\nimport {assignInlineVars} from '@vanilla-extract/dynamic'\nimport {useEffect, useMemo, useRef, useState} from 'react'\n\nimport type {BuildThemeOptions} from '../theme/options'\nimport {ImageFileButton} from './ImageFileButton'\nimport {\n  applyImagePalette,\n  currentImageVariant,\n  IMAGE_PALETTE_TITLES,\n  IMAGE_PALETTE_VARIANTS,\n  type ImagePalette,\n  type ImagePaletteKey,\n  type ImagePaletteVariant,\n} from './imagePalette'\nimport {ThemeThumbnail} from './ThemeThumbnail'\nimport {TooltipButton} from './TooltipButton'\nimport {useImagePalette} from './useImagePalette'\n\nimport {\n  imageTile,\n  paletteGrid,\n  ROW_PADDING,\n  tile,\n  VARIANT_FRAME,\n  VARIANT_GAP,\n  VARIANT_WIDTH,\n  variantButton,\n  variantFrame,\n  variantRow,\n  variantScale,\n  variantScaleBox,\n  variantWidth,\n} from './ImagePaletteSection.css'\n\n/** The swatches on display: the vibrant family over the muted one */\nconst TILES: ImagePaletteKey[] = [\n  'vibrant',\n  'lightVibrant',\n  'darkVibrant',\n  'muted',\n  'lightMuted',\n  'darkMuted',\n]\n\n/**\n * How many variants show at once: two and a half, so that the cut-off third\n * one gives away that the row scrolls\n */\nconst VISIBLE_VARIANTS = 2.5\n\n/** The width of one variant, before the row has been measured */\nconst FALLBACK_VARIANT_WIDTH = 58\n\n/**\n * Takes the colors of a theme from an image, on device: the image is read\n * into a canvas and its palette extracted right there — nothing is uploaded.\n * Shows the image (while the session lasts) next to its palette, offers a\n * theme variant built around each swatch as a small preview, and a lucky\n * button that picks an interesting one.\n *\n * @internal\n */\nexport function ImagePaletteSection(props: {\n  imageUrl?: string\n  onPalette: (palette: ImagePalette, file: File) => void\n  onVariant: (variant: ImagePaletteVariant) => void\n  onLucky: () => void\n  options: BuildThemeOptions\n  palette?: ImagePalette\n}) {\n  const {imageUrl, onPalette, onVariant, onLucky, options, palette} = props\n  const {busy, pickImage} = useImagePalette(onPalette)\n  const [dragging, setDragging] = useState(false)\n  // `dragleave` also fires when the pointer crosses into a child, so the\n  // highlight tracks how deep the drag is rather than the last event\n  const dragDepth = useRef(0)\n  const current = palette ? currentImageVariant(options, palette) : null\n  const rowRef = useRef<HTMLDivElement | null>(null)\n  const [thumbnailWidth, setThumbnailWidth] = useState(FALLBACK_VARIANT_WIDTH)\n\n  // Size the variants to the row, so two and a half of them are in view\n  useEffect(() => {\n    const row = rowRef.current\n\n    if (!row) return undefined\n\n    const measure = () => {\n      const visible =\n        row.clientWidth - ROW_PADDING - (Math.ceil(VISIBLE_VARIANTS) - 1) * VARIANT_GAP\n\n      // Each variant is its thumbnail plus the frame on either side\n      setThumbnailWidth(Math.max(24, Math.floor(visible / VISIBLE_VARIANTS) - VARIANT_FRAME * 2))\n    }\n\n    measure()\n\n    const observer = new ResizeObserver(measure)\n\n    observer.observe(row)\n\n    return () => observer.disconnect()\n    // oxlint-disable-next-line react/exhaustive-effect-dependencies -- the row only renders with a palette, so a new palette has a new row to observe\n  }, [palette])\n\n  const variants = useMemo(() => {\n    if (!palette) return []\n\n    return IMAGE_PALETTE_VARIANTS.flatMap((variant) =>\n      palette[variant] === null\n        ? []\n        : [\n            {\n              variant,\n              title: IMAGE_PALETTE_TITLES[variant],\n              options: applyImagePalette(options, palette, variant),\n            },\n          ],\n    )\n  }, [options, palette])\n\n  return (\n    <Card\n      border\n      onDragEnter={(event) => {\n        event.preventDefault()\n        dragDepth.current++\n        setDragging(true)\n      }}\n      onDragLeave={() => {\n        dragDepth.current = Math.max(0, dragDepth.current - 1)\n\n        if (dragDepth.current === 0) setDragging(false)\n      }}\n      onDragOver={(event) => {\n        event.preventDefault()\n      }}\n      onDrop={(event) => {\n        event.preventDefault()\n        dragDepth.current = 0\n        setDragging(false)\n\n        const file = event.dataTransfer.files[0]\n\n        if (file) pickImage(file)\n      }}\n      padding={3}\n      radius={3}\n      tone={dragging ? 'primary' : 'default'}\n    >\n      <Stack gap={3}>\n        <Flex align=\"center\" gap={2}>\n          <Box flex={1}>\n            <Text size={1} weight=\"medium\">\n              Image palette\n            </Text>\n          </Box>\n          {palette && (\n            <ImageFileButton\n              loading={busy}\n              mode=\"bleed\"\n              onFile={pickImage}\n              padding={2}\n              tooltip=\"Pick another image\"\n            />\n          )}\n        </Flex>\n\n        {palette ? (\n          <>\n            <div className={paletteGrid} data-with-image={imageUrl !== undefined}>\n              {imageUrl && <img alt=\"\" className={imageTile} src={imageUrl} />}\n              {TILES.map((key) => {\n                const hex = palette[key]\n                const title = IMAGE_PALETTE_TITLES[key]\n\n                return (\n                  <Tooltip\n                    key={key}\n                    animate\n                    content={\n                      <Text size={1}>\n                        {hex ? `${title} · ${hex}` : `No ${title.toLowerCase()} color`}\n                      </Text>\n                    }\n\n                    placement=\"bottom\"\n                    portal\n                  >\n                    <span\n                      className={tile}\n                      data-empty={hex === null}\n                      style={{background: hex ?? undefined}}\n                    />\n                  </Tooltip>\n                )\n              })}\n            </div>\n\n            <Stack gap={2}>\n              <Text muted size={0}>\n                Pick the swatch to build the theme around\n              </Text>\n              <div\n                className={variantRow}\n                ref={rowRef}\n                style={assignInlineVars({\n                  [variantWidth]: `${thumbnailWidth}px`,\n                  [variantScale]: String(thumbnailWidth / VARIANT_WIDTH),\n                })}\n              >\n                {variants.map(({variant, title, options: variantOptions}) => (\n                  // oxlint-disable-next-line control-has-associated-label -- the title below the thumbnail is the label, deeper than the rule looks\n                  <button\n                    key={variant}\n                    aria-pressed={variant === current}\n                    className={variantButton}\n                    onClick={() => onVariant(variant)}\n                    type=\"button\"\n                  >\n                    <span className={variantFrame}>\n                      <span className={variantScaleBox}>\n                        <ThemeThumbnail options={variantOptions} />\n                      </span>\n                    </span>\n                    <Box as=\"span\" display=\"block\" paddingTop={1}>\n                      <Text\n                        align=\"center\"\n                        as=\"span\"\n                        size={0}\n                        textOverflow=\"ellipsis\"\n                        weight={variant === current ? 'medium' : 'regular'}\n                      >\n                        {title}\n                      </Text>\n                    </Box>\n                  </button>\n                ))}\n              </div>\n            </Stack>\n\n            <TooltipButton\n              icon={SparklesIcon}\n              mode=\"ghost\"\n              onClick={onLucky}\n              text=\"I'm feeling lucky\"\n              tooltip=\"Build the theme around a swatch that looks interesting\"\n              width=\"fill\"\n            />\n          </>\n        ) : (\n          <Stack gap={3}>\n            <Text muted size={0}>\n              Take the accent, text and background colors from an image — read on device, nothing is\n              uploaded.\n            </Text>\n            <ImageFileButton\n              loading={busy}\n              mode=\"ghost\"\n              onFile={pickImage}\n              text=\"Pick an image\"\n              tooltip=\"Take the colors from an image on your device\"\n              width=\"fill\"\n            />\n          </Stack>\n        )}\n      </Stack>\n    </Card>\n  )\n}\n","import {style} from '@vanilla-extract/css'\n\n/** A native color input, trimmed down to its swatch */\nexport const swatch = style({\n  boxSizing: 'border-box',\n  flex: 'none',\n  width: 33,\n  height: 33,\n  padding: 0,\n  border: '1px solid var(--card-border-color)',\n  borderRadius: 4,\n  background: 'none',\n  cursor: 'pointer',\n  selectors: {\n    '&::-webkit-color-swatch-wrapper': {\n      padding: 0,\n    },\n    '&::-webkit-color-swatch': {\n      border: 'none',\n      borderRadius: 3,\n    },\n    '&::-moz-color-swatch': {\n      border: 'none',\n      borderRadius: 3,\n    },\n  },\n})\n\n/** A native range input, themed through `accent-color` */\nexport const range = style({\n  display: 'block',\n  width: '100%',\n  margin: 0,\n  accentColor: 'var(--card-focus-ring-color)',\n})\n\n/** Lets the color row's text shrink and truncate instead of widening the row */\nexport const colorRowText = style({\n  minWidth: 0,\n})\n","import {ResetIcon} from '@sanity/icons/Reset'\nimport {TrashIcon} from '@sanity/icons/Trash'\nimport {Badge, Box, Button, Card, Flex, Stack, Text, TextInput} from '@sanity/ui'\nimport {type ThemeColorSchemeKey} from '@sanity/ui/theme'\nimport {useSelector} from '@xstate/react'\nimport {useMemo} from 'react'\nimport {useColorSchemeValue} from 'sanity'\n\nimport type {ThemerProps} from '#types'\n\nimport {buildPalette, type GeneratedColorPalette} from '../theme/buildPalette'\nimport {\n  type BuildThemeOptions,\n  type ResolvedSchemeOptions,\n  resolveThemeOptions,\n  SCHEMES,\n  type SchemeThemeOptions,\n} from '../theme/options'\nimport {\n  applyImagePalette,\n  currentImageVariant,\n  type ImagePalette,\n  type ImagePaletteVariant,\n  pickLuckyVariant,\n} from './imagePalette'\nimport {ImagePaletteSection} from './ImagePaletteSection'\nimport {ScrollArea, ScrollAreaBleed} from './ScrollArea'\nimport {ThemeThumbnail} from './ThemeThumbnail'\nimport {TooltipButton} from './TooltipButton'\n\nimport {colorRowText, range, swatch} from './ThemeEditor.css'\n\nconst SCHEME_TITLES: Record<ThemeColorSchemeKey, string> = {\n  dark: 'Dark mode',\n  light: 'Light mode',\n}\n\n/**\n * Where the split preview shows a scheme: the Studio's own scheme stays next\n * to the sidebar (or at the bottom, stacked on small screens), the other one\n * takes the far side\n */\nfunction splitHint(own: boolean): string {\n  return own ? 'Shown on the right, next to the themer' : 'Shown on the left'\n}\n\nconst SCHEME_OPTION_KEYS: Array<keyof SchemeThemeOptions> = [\n  'accent',\n  'text',\n  'background',\n  'contrast',\n]\n\n/**\n * `<input type=\"color\">` paints the color into a shadow-DOM swatch that brings\n * its own border and padding, which then sits inside ours as a second border.\n * Stripping that chrome leaves the themed border as the only one.\n */\n/**\n * The flow for editing one of the user's own themes: its title, a live\n * preview, and a card per color scheme with the accent/text/background\n * pickers and the contrast slider of that scheme. Every change applies to the\n * whole Studio right away — in the scheme the Studio is showing, or in both\n * side by side in the split preview.\n *\n * @internal\n */\nexport function ThemeEditor({\n  actorRef,\n  focusTitle,\n  slug,\n  split,\n  themes,\n}: {focusTitle: boolean; slug: string} & Pick<ThemerProps, 'actorRef' | 'split' | 'themes'>) {\n  const images = useSelector(actorRef, (snapshot) => snapshot.context.images)\n  const theme = themes.find((candidate) => candidate.slug === slug && candidate.source === 'custom')\n\n  // The machine only enters the edit flow for a listed custom theme, and\n  // leaves it as soon as the theme is removed or deleted\n  if (!theme) return null\n\n  const applyVariant = (variant: ImagePaletteVariant | null) => {\n    if (!theme.palette || variant === null) return\n\n    actorRef.send({\n      type: 'theme.update',\n      slug,\n      options: applyImagePalette(theme.options, theme.palette, variant),\n    })\n  }\n\n  return (\n    <ThemeEditorForm\n      focusTitle={focusTitle}\n      imageUrl={images[slug]}\n      onDone={() => actorRef.send({type: 'flow.list'})}\n      onLucky={() => {\n        if (!theme.palette) return\n\n        applyVariant(\n          pickLuckyVariant(theme.palette, {\n            exclude: currentImageVariant(theme.options, theme.palette),\n          }),\n        )\n      }}\n      onOptionsChange={(options) => actorRef.send({type: 'theme.update', slug, options})}\n      onPalette={(palette, file) =>\n        actorRef.send({\n          type: 'theme.update',\n          slug,\n          options: applyImagePalette(theme.options, palette),\n          palette,\n          imageUrl: URL.createObjectURL(file),\n        })\n      }\n      onRemove={() => actorRef.send({type: 'theme.remove', slug})}\n      onTitleChange={(title) => actorRef.send({type: 'theme.update', slug, title})}\n      onVariant={applyVariant}\n      options={theme.options}\n      palette={theme.palette}\n      split={split}\n      title={theme.title}\n    />\n  )\n}\n\n// Split from `ThemeEditor` so that the derived values below can be hooks\n// while the editor bails out early when the theme is gone\nfunction ThemeEditorForm(props: {\n  focusTitle: boolean\n  imageUrl?: string\n  onDone: () => void\n  onLucky: () => void\n  onOptionsChange: (options: BuildThemeOptions) => void\n  onPalette: (palette: ImagePalette, file: File) => void\n  onRemove: () => void\n  onTitleChange: (title: string) => void\n  onVariant: (variant: ImagePaletteVariant) => void\n  options: BuildThemeOptions\n  palette?: ImagePalette\n  /** Whether the Studio shows in light and dark side by side */\n  split: boolean\n  title: string\n}) {\n  const {\n    focusTitle,\n    imageUrl,\n    onDone,\n    onLucky,\n    onOptionsChange,\n    onPalette,\n    onRemove,\n    onTitleChange,\n    onVariant,\n    options,\n    palette,\n    split,\n    title,\n  } = props\n  // The scheme the Studio is showing, with the appearance setting resolved\n  const studioScheme = useColorSchemeValue()\n  const resolved = useMemo(() => resolveThemeOptions(options), [options])\n  const palettes = useMemo(() => buildPalette(options), [options])\n\n  const patchScheme = (scheme: ThemeColorSchemeKey, changes: Partial<SchemeThemeOptions>) => {\n    const values: SchemeThemeOptions = {...options[scheme], ...changes}\n\n    // Clearing an option means falling back to its default, which is its absence\n    for (const key of SCHEME_OPTION_KEYS) {\n      if (values[key] === undefined) delete values[key]\n    }\n\n    const next: BuildThemeOptions = {...options}\n\n    if (Object.keys(values).length === 0) {\n      delete next[scheme]\n    } else {\n      next[scheme] = values\n    }\n\n    onOptionsChange(next)\n  }\n\n  return (\n    <>\n      <ScrollArea padding={3}>\n        <Stack gap={4}>\n          <ThemeThumbnail options={options} />\n\n          <Stack gap={2}>\n            <Text size={1} weight=\"medium\">\n              Title\n            </Text>\n            <TextInput\n              autoFocus={focusTitle}\n              fontSize={1}\n              onChange={(event) => onTitleChange(event.currentTarget.value)}\n              onFocus={focusTitle ? (event) => event.currentTarget.select() : undefined}\n              padding={2}\n              placeholder=\"Untitled theme\"\n              value={title}\n            />\n          </Stack>\n\n          <ImagePaletteSection\n            imageUrl={imageUrl}\n            onLucky={onLucky}\n            onPalette={onPalette}\n            onVariant={onVariant}\n            options={options}\n            palette={palette}\n          />\n\n          <ScrollAreaBleed>\n            {SCHEMES.map((scheme) => (\n              <SchemeCard\n                key={scheme}\n                active={split || scheme === studioScheme}\n                onChange={(changes) => patchScheme(scheme, changes)}\n                options={options[scheme] ?? {}}\n                palette={palettes[scheme]}\n                resolved={resolved[scheme]}\n                scheme={scheme}\n                split={split}\n                splitHint={splitHint(scheme === studioScheme)}\n              />\n            ))}\n          </ScrollAreaBleed>\n        </Stack>\n      </ScrollArea>\n\n      <Card borderTop padding={3}>\n        <Flex gap={2}>\n          <TooltipButton\n            icon={TrashIcon}\n            mode=\"ghost\"\n            onClick={onRemove}\n            text=\"Remove\"\n            tone=\"critical\"\n            tooltip=\"Remove the theme — it can be restored until it is deleted\"\n          />\n          <Box flex={1} />\n          <Button mode=\"ghost\" onClick={onDone} padding={2} text=\"Done\" />\n        </Flex>\n      </Card>\n    </>\n  )\n}\n\n/**\n * The colors of one scheme. The cards span the sidebar edge to edge, one\n * after the other with a border between them, in the sidebar's own scheme —\n * the swatches show the colors they edit. The scheme the Studio is showing is\n * marked as active: its changes show up in the Studio right away, the other\n * scheme's only once the appearance setting switches to it — or both are\n * active, in the split preview.\n */\nfunction SchemeCard(props: {\n  active: boolean\n  onChange: (changes: Partial<SchemeThemeOptions>) => void\n  options: SchemeThemeOptions\n  palette: GeneratedColorPalette\n  resolved: ResolvedSchemeOptions\n  scheme: ThemeColorSchemeKey\n  split: boolean\n  /** Where the split preview shows this scheme */\n  splitHint: string\n}) {\n  const {active, onChange, options, palette, resolved, scheme, split, splitHint} = props\n  const name = SCHEME_TITLES[scheme]\n\n  return (\n    <Card borderTop padding={3}>\n      <Stack gap={4}>\n        <Stack gap={2}>\n          <Flex align=\"center\" gap={2}>\n            <Box flex={1}>\n              <Text size={1} weight=\"medium\">\n                {name}\n              </Text>\n            </Box>\n            {active && (\n              <Badge fontSize={0} tone=\"primary\">\n                Active\n              </Badge>\n            )}\n          </Flex>\n          <Text muted size={0}>\n            {split\n              ? splitHint\n              : active\n                ? 'Shown in the Studio right now'\n                : `Shown once the Studio appearance is ${scheme}`}\n          </Text>\n        </Stack>\n\n        <ColorRow\n          auto={options.accent === undefined}\n          autoLabel=\"default\"\n          label={`${name} accent`}\n          onChange={(accent) => onChange({accent})}\n          onClear={() => onChange({accent: undefined})}\n          title=\"Accent\"\n          value={resolved.accent}\n        />\n        <ColorRow\n          auto={options.text === undefined}\n          label={`${name} text`}\n          onChange={(text) => onChange({text})}\n          onClear={() => onChange({text: undefined})}\n          title=\"Text\"\n          value={resolved.text}\n        />\n        <ColorRow\n          adjusted={scheme === 'dark' ? palette.black : palette.white}\n          auto={options.background === undefined}\n          label={`${name} background`}\n          onChange={(background) => onChange({background})}\n          onClear={() => onChange({background: undefined})}\n          title=\"Background\"\n          value={resolved.background}\n        />\n\n        <Stack gap={3}>\n          <Flex align=\"center\" gap={2}>\n            <Stack flex={1} gap={2}>\n              <Text size={1}>Contrast</Text>\n              <Text muted size={0}>\n                {resolved.contrast}\n                {options.contrast === undefined ? ' · auto' : ''}\n              </Text>\n            </Stack>\n            {options.contrast !== undefined && (\n              <TooltipButton\n                icon={ResetIcon}\n                mode=\"bleed\"\n                onClick={() => onChange({contrast: undefined})}\n                padding={2}\n                tooltip=\"Reset to auto\"\n              />\n            )}\n          </Flex>\n          <input\n            aria-label={`${name} contrast`}\n            className={range}\n            max={100}\n            min={15}\n            onChange={(event) => onChange({contrast: Number(event.currentTarget.value)})}\n            step={1}\n            type=\"range\"\n            value={resolved.contrast}\n          />\n          <Text muted size={0}>\n            100 keeps text and borders neutral — lower values blend in the accent\n          </Text>\n        </Stack>\n      </Stack>\n    </Card>\n  )\n}\n\n/** One color of a scheme: a swatch with its value and an optional reset button */\nfunction ColorRow(props: {\n  /** The color the generator actually applied, when it may differ from the input */\n  adjusted?: string\n  /** Whether the value is derived or a default rather than explicitly set */\n  auto?: boolean\n  /** What the value is when it is not set: derived (`auto`) or the stock one (`default`) */\n  autoLabel?: 'auto' | 'default'\n  /** The accessible name of the picker */\n  label: string\n  onChange: (value: string) => void\n  onClear?: () => void\n  title: string\n  value: string\n}) {\n  const {adjusted, auto, autoLabel = 'auto', label, onChange, onClear, title, value} = props\n\n  return (\n    <Flex align=\"center\" gap={2}>\n      <input\n        aria-label={label}\n        className={swatch}\n        onChange={(event) => onChange(event.currentTarget.value)}\n        type=\"color\"\n        value={value}\n      />\n      <Stack className={colorRowText} flex={1} gap={2}>\n        <Text size={1}>{title}</Text>\n        <Text muted size={0} textOverflow=\"ellipsis\">\n          {value}\n          {adjusted !== undefined && adjusted !== value ? ` → ${adjusted}` : ''}\n          {auto ? ` · ${autoLabel}` : ''}\n        </Text>\n      </Stack>\n      {onClear && !auto && (\n        <TooltipButton\n          icon={ResetIcon}\n          mode=\"bleed\"\n          onClick={onClear}\n          padding={2}\n          tooltip={`Reset to ${autoLabel}`}\n        />\n      )}\n    </Flex>\n  )\n}\n","import {isColor} from '../lib/mix'\nimport {\n  type BuildThemeOptions,\n  MAXIMUM_CONTRAST,\n  MINIMUM_CONTRAST,\n  SCHEMES,\n  type SchemeThemeOptions,\n} from '../theme/options'\nimport {displayTitle} from './themes'\n\n/** What a theme code carries: a theme's title and its options @internal */\nexport interface SharedTheme {\n  title: string\n  options: BuildThemeOptions\n}\n\n/**\n * The version of the code format, the first byte of every code — bumped if\n * the layout below ever changes, so older codes can still be told apart\n */\nconst VERSION = 1\n\n/** The fields a scheme's options can set, in the order their bytes go */\nconst FIELDS = ['accent', 'text', 'background', 'contrast'] as const\n\n/**\n * Turns a theme into a short code to share in a message: `title`, and the\n * colors and contrasts of both schemes, packed into bytes — one flag byte says\n * which of the eight fields are set, each color is its three RGB bytes and a\n * contrast one byte, and the title takes up the rest — then base64url'd, so\n * it is one word without padding, safe in URLs and chat. A theme setting\n * everything comes to about 30 bytes plus its title.\n *\n * @internal\n */\nexport function encodeTheme(theme: SharedTheme): string {\n  const bytes: number[] = [VERSION, 0]\n  let flags = 0\n\n  SCHEMES.forEach((scheme, schemeIndex) => {\n    const options: SchemeThemeOptions = theme.options[scheme] ?? {}\n\n    FIELDS.forEach((field, fieldIndex) => {\n      const value = options[field]\n\n      if (value === undefined) return\n\n      if (field === 'contrast') {\n        if (typeof value !== 'number' || !Number.isFinite(value)) return\n\n        bytes.push(Math.round(Math.min(MAXIMUM_CONTRAST, Math.max(MINIMUM_CONTRAST, value))))\n      } else {\n        if (typeof value !== 'string' || !isColor(value)) return\n\n        bytes.push(...rgbBytes(value))\n      }\n\n      flags |= 1 << (schemeIndex * FIELDS.length + fieldIndex)\n    })\n  })\n\n  bytes[1] = flags\n  bytes.push(...new TextEncoder().encode(theme.title.trim()))\n\n  return toBase64Url(Uint8Array.from(bytes))\n}\n\n/**\n * Reads a theme back out of a code — as pasted, so surrounding whitespace and\n * words around the code are fine: the first word that is a code counts. `null`\n * when nothing in the text is one.\n *\n * @internal\n */\nexport function decodeTheme(text: string): SharedTheme | null {\n  for (const word of text.trim().split(/\\s+/)) {\n    const theme = decodeCode(word)\n\n    if (theme) return theme\n  }\n\n  return null\n}\n\nfunction decodeCode(code: string): SharedTheme | null {\n  const bytes = fromBase64Url(code)\n\n  if (!bytes || bytes.length < 2 || bytes[0] !== VERSION) return null\n\n  const flags = bytes[1]\n  const options: BuildThemeOptions = {}\n  let offset = 2\n\n  for (const [schemeIndex, scheme] of SCHEMES.entries()) {\n    const schemeOptions: SchemeThemeOptions = {}\n\n    for (const [fieldIndex, field] of FIELDS.entries()) {\n      if (!(flags & (1 << (schemeIndex * FIELDS.length + fieldIndex)))) continue\n\n      if (field === 'contrast') {\n        if (offset + 1 > bytes.length) return null\n\n        schemeOptions.contrast = Math.min(\n          MAXIMUM_CONTRAST,\n          Math.max(MINIMUM_CONTRAST, bytes[offset]),\n        )\n        offset += 1\n      } else {\n        if (offset + 3 > bytes.length) return null\n\n        schemeOptions[field] = hexColor(bytes.subarray(offset, offset + 3))\n        offset += 3\n      }\n    }\n\n    if (Object.keys(schemeOptions).length > 0) options[scheme] = schemeOptions\n  }\n\n  let title: string\n\n  try {\n    title = new TextDecoder('utf-8', {fatal: true}).decode(bytes.subarray(offset))\n  } catch {\n    return null\n  }\n\n  return {title: displayTitle(title), options}\n}\n\n/** The three RGB bytes of a `#rgb` or `#rrggbb` color */\nfunction rgbBytes(color: string): number[] {\n  const hex = color.length === 4 ? color.slice(1).replaceAll(/./g, '$&$&') : color.slice(1)\n\n  return [0, 2, 4].map((start) => parseInt(hex.slice(start, start + 2), 16))\n}\n\nfunction hexColor(rgb: Uint8Array): string {\n  return `#${[...rgb].map((byte) => byte.toString(16).padStart(2, '0')).join('')}`\n}\n\nfunction toBase64Url(bytes: Uint8Array): string {\n  let binary = ''\n\n  for (const byte of bytes) binary += String.fromCharCode(byte)\n\n  return btoa(binary).replaceAll('+', '-').replaceAll('/', '_').replace(/=+$/, '')\n}\n\nfunction fromBase64Url(code: string): Uint8Array | null {\n  if (!/^[A-Za-z0-9_-]+$/.test(code)) return null\n\n  const base64 = code.replaceAll('-', '+').replaceAll('_', '/')\n\n  try {\n    return Uint8Array.from(atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, '=')), (char) =>\n      char.charCodeAt(0),\n    )\n  } catch {\n    return null\n  }\n}\n","import {useToast} from '@sanity/ui/toast'\nimport {useEffect} from 'react'\n\nimport type {ThemerProps} from '#types'\n\nimport {decodeTheme, encodeTheme, type SharedTheme} from './share'\nimport {displayTitle} from './themes'\n\n/**\n * Copying a theme as a code to share, and adding a theme from a code someone\n * shared — with toasts telling how it went.\n *\n * @internal\n */\nexport function useThemeCodes({actorRef}: Pick<ThemerProps, 'actorRef'>): {\n  copyTheme: (theme: SharedTheme) => Promise<void>\n  /** Adds the theme in the text, if there is one — the result says whether there was */\n  addThemeFromText: (text: string) => boolean\n  /** Adds the theme on the clipboard, if there is one and the browser hands the clipboard over */\n  addThemeFromClipboard: () => Promise<'added' | 'no-theme' | 'no-clipboard'>\n} {\n  const toast = useToast()\n\n  const copyTheme = async (theme: SharedTheme) => {\n    const title = displayTitle(theme.title)\n\n    try {\n      await navigator.clipboard.writeText(encodeTheme(theme))\n      toast.push({\n        status: 'success',\n        title: `Copied ${title} as a code`,\n        description: 'Paste it in the themer of another Studio to add the theme there',\n      })\n    } catch {\n      toast.push({status: 'error', title: `Could not copy ${title}`})\n    }\n  }\n\n  const addThemeFromText = (text: string) => {\n    const theme = decodeTheme(text)\n\n    if (!theme) return false\n\n    actorRef.send({type: 'theme.import', title: theme.title, options: theme.options})\n    toast.push({status: 'success', title: `Added ${theme.title}`})\n\n    return true\n  }\n\n  const addThemeFromClipboard = async () => {\n    let text: string\n\n    try {\n      text = await navigator.clipboard.readText()\n    } catch {\n      return 'no-clipboard'\n    }\n\n    return addThemeFromText(text) ? 'added' : 'no-theme'\n  }\n\n  return {copyTheme, addThemeFromText, addThemeFromClipboard}\n}\n\n/**\n * Adds a theme pasted anywhere in the Studio while the themer's list is\n * showing — pastes into inputs and other editable things are theirs.\n *\n * @internal\n */\nexport function usePasteThemeCodes({actorRef}: Pick<ThemerProps, 'actorRef'>): void {\n  const toast = useToast()\n\n  useEffect(() => {\n    const handlePaste = (event: ClipboardEvent) => {\n      if (isEditable(event.target)) return\n\n      const theme = decodeTheme(event.clipboardData?.getData('text/plain') ?? '')\n\n      if (!theme) return\n\n      event.preventDefault()\n      actorRef.send({type: 'theme.import', title: theme.title, options: theme.options})\n      toast.push({status: 'success', title: `Added ${theme.title}`})\n    }\n\n    document.addEventListener('paste', handlePaste)\n\n    return () => document.removeEventListener('paste', handlePaste)\n  }, [actorRef, toast])\n}\n\nfunction isEditable(target: EventTarget | null): boolean {\n  return (\n    target instanceof HTMLElement &&\n    (target.isContentEditable || target.matches('input, textarea, select'))\n  )\n}\n","import {Button, Card, Dialog, Flex, Stack, Text, TextInput} from '@sanity/ui'\nimport {useState} from 'react'\n\nimport type {ThemerProps} from '#types'\n\nimport {useThemeCodes} from './useThemeCodes'\n\n/**\n * Where a theme code someone shared gets pasted by hand — for browsers that\n * do not hand the clipboard over, and for codes that are not on it.\n *\n * @internal\n */\nexport function PasteThemeDialog(props: {onClose: () => void} & Pick<ThemerProps, 'actorRef'>) {\n  const {actorRef, onClose} = props\n  const {addThemeFromText} = useThemeCodes({actorRef})\n  const [text, setText] = useState('')\n  const [invalid, setInvalid] = useState(false)\n\n  const add = () => {\n    if (addThemeFromText(text)) {\n      onClose()\n    } else {\n      setInvalid(true)\n    }\n  }\n\n  return (\n    <Dialog\n      animate\n      footer={\n        <Flex gap={2} justify=\"flex-end\" padding={3}>\n          <Button mode=\"ghost\" onClick={onClose} padding={2} text=\"Cancel\" />\n          <Button\n            disabled={text.trim() === ''}\n            onClick={add}\n            padding={2}\n            text=\"Add theme\"\n            tone=\"primary\"\n          />\n        </Flex>\n      }\n      header=\"Add a shared theme\"\n      id=\"themer-paste\"\n      onClickOutside={onClose}\n      onClose={onClose}\n      width={0}\n    >\n      <form\n        onSubmit={(event) => {\n          event.preventDefault()\n          add()\n        }}\n      >\n        <Stack gap={3} padding={4}>\n          <Text muted size={1}>\n            Paste the code someone copied from their themer — the theme is added to your list and\n            applied.\n          </Text>\n          <TextInput\n            aria-describedby={invalid ? 'themer-paste-error' : undefined}\n            aria-invalid={invalid}\n            aria-label=\"Theme code\"\n            autoFocus\n            customValidity={invalid ? 'That is not a theme code' : undefined}\n            fontSize={1}\n            onChange={(event) => {\n              setText(event.currentTarget.value)\n              setInvalid(false)\n            }}\n            placeholder=\"AQ…\"\n            value={text}\n          />\n          {invalid && (\n            <Card id=\"themer-paste-error\" padding={3} radius={2} role=\"alert\" tone=\"critical\">\n              <Text size={1}>\n                That is not a theme code — codes are one word, copied from a theme&apos;s menu.\n              </Text>\n            </Card>\n          )}\n        </Stack>\n      </form>\n    </Dialog>\n  )\n}\n","import {style} from '@vanilla-extract/css'\n\nexport const root = style({\n  position: 'relative',\n})\n\n/** A bare button, so that the thumbnail and the title can carry the styling */\nexport const pickButton = style({\n  'appearance': 'none',\n  'display': 'block',\n  'boxSizing': 'border-box',\n  'width': '100%',\n  'margin': 0,\n  'padding': 0,\n  'border': 0,\n  'background': 'none',\n  'color': 'inherit',\n  'font': 'inherit',\n  'textAlign': 'center',\n  'cursor': 'pointer',\n  ':focus': {\n    outline: 'none',\n  },\n})\n\n/**\n * Wraps the thumbnail with room for the ring that marks the applied theme —\n * hovering shows a faint ring, the applied theme the focus ring color, and\n * keyboard focus an outline. The rings are drawn inside the frame's padding,\n * so nothing sticks out to be clipped by the scrolling list.\n */\nexport const frame = style({\n  display: 'block',\n  padding: 4,\n  borderRadius: 10,\n  transition: 'box-shadow 100ms',\n  selectors: {\n    [`${pickButton}:hover &`]: {\n      boxShadow: 'inset 0 0 0 2px var(--card-border-color)',\n    },\n    [`${pickButton}[aria-pressed='true'] &`]: {\n      boxShadow: 'inset 0 0 0 2px var(--card-focus-ring-color)',\n    },\n    [`${pickButton}:focus-visible &`]: {\n      outline: '2px solid var(--card-focus-ring-color)',\n      outlineOffset: -2,\n    },\n  },\n})\n\n/**\n * The actions menu sits on the thumbnail's top right corner, like the actions\n * of an image input, and only shows on hover, on keyboard focus, and while it\n * is open — its popover is portaled, so an open menu does not count as focus\n * within\n */\nexport const menuSlot = style({\n  position: 'absolute',\n  top: 10,\n  right: 10,\n  opacity: 0,\n  transition: 'opacity 100ms',\n  selectors: {\n    [`${root}:hover &, ${root}:focus-within &, &[data-visible='true']`]: {\n      opacity: 1,\n    },\n  },\n})\n\n/** The dark card behind the menu button sizes to the button, not the slot */\nexport const menuCard = style({\n  display: 'inline-block',\n})\n","import {ArrowDownIcon} from '@sanity/icons/ArrowDown'\nimport {ArrowUpIcon} from '@sanity/icons/ArrowUp'\nimport {CopyIcon} from '@sanity/icons/Copy'\nimport {EditIcon} from '@sanity/icons/Edit'\nimport {EllipsisHorizontalIcon} from '@sanity/icons/EllipsisHorizontal'\nimport {ShareIcon} from '@sanity/icons/Share'\nimport {TrashIcon} from '@sanity/icons/Trash'\nimport {Box, Button, Card, Text, useRootTheme} from '@sanity/ui'\nimport {Menu, MenuButton, MenuDivider, MenuItem} from '@sanity/ui/menu'\nimport {Tooltip} from '@sanity/ui/tooltip'\nimport {Reorder, useDragControls} from 'motion/react'\nimport {useRef, useState} from 'react'\nimport scrollIntoView from 'scroll-into-view-if-needed'\n\nimport type {ThemerProps} from '#types'\n\nimport {displayTitle, type ThemerTheme} from './themes'\nimport {ThemeThumbnail} from './ThemeThumbnail'\nimport {useThemeCodes} from './useThemeCodes'\n\nimport {frame, menuCard, menuSlot, pickButton, root} from './ThemeCard.css'\n\n/**\n * Scrolls the applied theme's card into view when it is not already, as a\n * ref: the list scrolls to it as it mounts — coming back from the editor or\n * the removed themes — and when another theme gets applied\n */\nfunction scrollRefIntoViewIfNeeded(node: HTMLElement | null) {\n  if (node) scrollIntoView(node, {block: 'nearest', scrollMode: 'if-needed'})\n}\n\n/**\n * One theme in the list: the floating preview with the title below it, like\n * an appearance option in macOS System Settings. Clicking it applies the\n * theme to the whole Studio, dragging it moves the theme to another place in\n * the list; its menu holds the move, edit, duplicate and remove flows that\n * apply to the theme.\n *\n * @internal\n */\nexport function ThemeCard({\n  actorRef,\n  active,\n  theme,\n  themes,\n}: {active: boolean; theme: ThemerTheme} & Pick<ThemerProps, 'actorRef' | 'themes'>) {\n  const {copyTheme} = useThemeCodes({actorRef})\n  const {scheme} = useRootTheme()\n  const [menuOpen, setMenuOpen] = useState(false)\n  const dragControls = useDragControls()\n  // Letting go of a drag also clicks the card, and that click must not pick\n  const dragged = useRef(false)\n  const title = displayTitle(theme.title)\n  const index = themes.findIndex((candidate) => candidate.slug === theme.slug)\n  // The configured theme sits ahead of the list, and does not move within it\n  const listed = index !== -1\n\n  const moveTo = (to: number) => {\n    const order = themes.map((candidate) => candidate.slug)\n\n    order.splice(to, 0, ...order.splice(index, 1))\n    actorRef.send({type: 'theme.reorder', order})\n  }\n\n  return (\n    <Reorder.Item\n      as=\"div\"\n      className={root}\n      dragControls={dragControls}\n      dragListener={false}\n      onDragEnd={() => {\n        // The click lands before the next frame\n        requestAnimationFrame(() => {\n          dragged.current = false\n        })\n      }}\n      onDragStart={() => {\n        dragged.current = true\n      }}\n      ref={active ? scrollRefIntoViewIfNeeded : undefined}\n      value={theme.slug}\n      whileDrag={{scale: 1.04}}\n    >\n      <button\n        aria-pressed={active}\n        className={pickButton}\n        onClick={() => {\n          if (!dragged.current) actorRef.send({type: 'theme.pick', slug: theme.slug})\n        }}\n        onPointerDown={(event) => {\n          // A mouse or pen drags the card off the button; a finger scrolls the\n          // list instead, and moves themes from the menu\n          if (listed && event.pointerType !== 'touch') dragControls.start(event)\n        }}\n        type=\"button\"\n      >\n        <span className={frame}>\n          <ThemeThumbnail options={theme.options} />\n        </span>\n        <Box as=\"span\" display=\"block\" paddingTop={2} paddingX={2}>\n          <Text\n            align=\"center\"\n            as=\"span\"\n            size={1}\n            textOverflow=\"ellipsis\"\n            weight={active ? 'medium' : 'regular'}\n          >\n            {title}\n          </Text>\n        </Box>\n      </button>\n\n      {/* The tooltip wraps a card rather than the button: the menu button\n          clones its button to wire it up, which a tooltip in between would\n          swallow. The card keeps the button dark, as it sits on the dark\n          half of the thumbnail, while the menu opens in the sidebar's scheme */}\n      <div className={menuSlot} data-visible={menuOpen}>\n        <Tooltip animate content={<Text size={1}>Show more</Text>} placement=\"bottom\" portal>\n          <Card className={menuCard} radius={2} scheme=\"dark\">\n            <MenuButton\n              button={\n                <Button\n                  aria-label={`Show more for ${title}`}\n                  fontSize={1}\n                  icon={EllipsisHorizontalIcon}\n                  mode=\"ghost\"\n                  padding={1}\n                  radius={2}\n                />\n              }\n              id={`themer-theme-${theme.slug}`}\n              menu={\n                <Menu>\n                  {listed && (\n                    <>\n                      <MenuItem\n                        disabled={index <= 0}\n                        icon={ArrowUpIcon}\n                        onClick={() => moveTo(index - 1)}\n                        text=\"Move up\"\n                      />\n                      <MenuItem\n                        disabled={index >= themes.length - 1}\n                        icon={ArrowDownIcon}\n                        onClick={() => moveTo(index + 1)}\n                        text=\"Move down\"\n                      />\n                      <MenuDivider />\n                    </>\n                  )}\n                  {theme.source === 'custom' && (\n                    <MenuItem\n                      icon={EditIcon}\n                      onClick={() => actorRef.send({type: 'theme.edit', slug: theme.slug})}\n                      text=\"Edit\"\n                    />\n                  )}\n                  <MenuItem\n                    icon={CopyIcon}\n                    onClick={() => actorRef.send({type: 'theme.duplicate', slug: theme.slug})}\n                    text={theme.source === 'custom' ? 'Duplicate' : 'Duplicate to edit'}\n                  />\n                  <MenuItem\n                    icon={ShareIcon}\n                    onClick={() => void copyTheme(theme)}\n                    text=\"Copy to share\"\n                  />\n                  {theme.source !== 'config' && (\n                    <>\n                      <MenuDivider />\n                      <MenuItem\n                        icon={TrashIcon}\n                        onClick={() => actorRef.send({type: 'theme.remove', slug: theme.slug})}\n                        text=\"Remove\"\n                        tone=\"critical\"\n                      />\n                    </>\n                  )}\n                </Menu>\n              }\n              onClose={() => setMenuOpen(false)}\n              onOpen={() => setMenuOpen(true)}\n              popover={{animate: true, placement: 'bottom-end', portal: true, scheme}}\n            />\n          </Card>\n        </Tooltip>\n      </div>\n    </Reorder.Item>\n  )\n}\n","import {style} from '@vanilla-extract/css'\n\nimport {MAXIMUM_WIDTH, MINIMUM_WIDTH} from './sidebarWidth'\n\nimport {sidebarContent} from './ResizableSidebar.css'\n\nconst CARD_GAP = 16\n\n/**\n * The theme cards flow into two columns once the sidebar has been dragged a\n * third of the way from its narrowest to its widest. The breakpoints are\n * container queries on the sidebar's content (`ResizableSidebar`), which is\n * as wide as the sidebar itself.\n */\nconst TWO_COLUMNS_FROM = MINIMUM_WIDTH + (MAXIMUM_WIDTH - MINIMUM_WIDTH) * 0.3\n\n/**\n * The columns share the width equally whatever the titles: a plain `1fr` may\n * not shrink below a card's min-content width, and a card's title does not\n * wrap, so one long title would widen its column past the sidebar\n */\nconst COLUMN = 'minmax(0, 1fr)'\n\nexport const cardGrid = style({\n  'display': 'grid',\n  'gridTemplateColumns': COLUMN,\n  'gap': CARD_GAP,\n  '@container': {\n    [`${sidebarContent} (min-width: ${TWO_COLUMNS_FROM}px)`]: {\n      gridTemplateColumns: `repeat(2, ${COLUMN})`,\n    },\n  },\n})\n","import {AddIcon} from '@sanity/icons/Add'\nimport {ClipboardIcon} from '@sanity/icons/Clipboard'\nimport {RestoreIcon} from '@sanity/icons/Restore'\nimport {Box, Button, Card, Flex, Stack} from '@sanity/ui'\nimport {MotionConfig, Reorder} from 'motion/react'\nimport {useState} from 'react'\n\nimport type {ThemerProps} from '#types'\n\nimport {ImageFileButton} from './ImageFileButton'\nimport {optionsFromImagePalette, titleFromFileName} from './imagePalette'\nimport {PasteThemeDialog} from './PasteThemeDialog'\nimport {ScrollArea} from './ScrollArea'\nimport {ThemeCard} from './ThemeCard'\nimport {CONFIG_SLUG, CONFIG_TITLE} from './themes'\nimport {TooltipButton} from './TooltipButton'\nimport {useImagePalette} from './useImagePalette'\nimport {usePasteThemeCodes, useThemeCodes} from './useThemeCodes'\n\nimport {cardGrid} from './ThemeList.css'\n\n/**\n * The flow for picking a theme: a grid of theme cards — the configured theme,\n * the presets and the user's own themes — that drag into the order the user\n * wants, with the entry points to the add and restore flows below. A theme\n * code someone shared pastes right into the list, or through the paste button.\n *\n * @internal\n */\nexport function ThemeList({\n  actorRef,\n  themes,\n  removed,\n  active,\n}: Pick<ThemerProps, 'actorRef' | 'themes' | 'removed' | 'active'>) {\n  const {addThemeFromClipboard} = useThemeCodes({actorRef})\n  const [pasting, setPasting] = useState(false)\n\n  usePasteThemeCodes({actorRef})\n\n  const {busy, pickImage} = useImagePalette((palette, file) =>\n    actorRef.send({\n      type: 'theme.add',\n      title: titleFromFileName(file.name),\n      options: optionsFromImagePalette(palette),\n      palette,\n      imageUrl: URL.createObjectURL(file),\n    }),\n  )\n\n  return (\n    <>\n      <ScrollArea padding={3}>\n        <Stack gap={4}>\n          {/* The group tells a column from a grid by measuring the cards, and\n              lets go of the layout animations for users who prefer reduced motion */}\n          <MotionConfig reducedMotion=\"user\">\n            <Reorder.Group\n              as=\"div\"\n              className={cardGrid}\n              onReorder={(order: string[]) => actorRef.send({type: 'theme.reorder', order})}\n              values={themes.map((theme) => theme.slug)}\n            >\n              <ThemeCard\n                actorRef={actorRef}\n                active={!active}\n                theme={{\n                  slug: CONFIG_SLUG,\n                  title: CONFIG_TITLE,\n                  options: {},\n                  source: 'config',\n                }}\n                themes={themes}\n              />\n              {themes.map((theme) => (\n                <ThemeCard\n                  key={theme.slug}\n                  actorRef={actorRef}\n                  active={theme.slug === active?.slug}\n                  theme={theme}\n                  themes={themes}\n                />\n              ))}\n            </Reorder.Group>\n          </MotionConfig>\n          {/* Trails the list rather than sitting in the footer, so the footer\n              does not shift when the first theme gets removed */}\n          {removed.length > 0 && (\n            <Button\n              gap={2}\n              icon={RestoreIcon}\n              mode=\"bleed\"\n              onClick={() => actorRef.send({type: 'flow.removed'})}\n              padding={2}\n              text={`Show removed (${removed.length})`}\n              width=\"fill\"\n            />\n          )}\n        </Stack>\n      </ScrollArea>\n\n      <Card borderTop padding={3}>\n        <Flex gap={2}>\n          <Box flex={1}>\n            <TooltipButton\n              icon={AddIcon}\n              mode=\"ghost\"\n              onClick={() => actorRef.send({type: 'theme.add'})}\n              text=\"Add theme\"\n              tooltip=\"Add a theme based on the applied one\"\n              width=\"fill\"\n            />\n          </Box>\n          <ImageFileButton\n            loading={busy}\n            mode=\"ghost\"\n            onFile={pickImage}\n            tooltip=\"Add a theme from the colors of an image\"\n          />\n          <TooltipButton\n            icon={ClipboardIcon}\n            mode=\"ghost\"\n            onClick={async () => {\n              // Straight from the clipboard where the browser allows; by hand otherwise\n              if ((await addThemeFromClipboard()) !== 'added') setPasting(true)\n            }}\n            tooltip=\"Add a theme from a code someone shared\"\n          />\n        </Flex>\n      </Card>\n\n      {pasting && <PasteThemeDialog actorRef={actorRef} onClose={() => setPasting(false)} />}\n    </>\n  )\n}\n","import {\n  type BuildThemeOptions,\n  DEFAULT_ACCENT,\n  DEFAULT_BACKGROUND,\n  DEFAULT_CONTRAST,\n  deriveTextColor,\n  type ResolvedSchemeOptions,\n  resolveThemeOptions,\n  SCHEMES,\n  type SchemeThemeOptions,\n} from '../theme/options'\n\n/**\n * Reduces theme options to the minimal object that recreates them through\n * `buildTheme`: in each scheme the accent is dropped when it is the stock\n * one, the text color when it matches the one derived from the accent, and\n * the background and contrast when they match the defaults — and a scheme\n * with nothing left is dropped altogether. Options that boil down to the\n * stock Studio theme reduce to `null` — they need nothing from this package.\n *\n * @internal\n */\nexport function minimizeOptions(options: BuildThemeOptions): BuildThemeOptions | null {\n  const resolved = resolveThemeOptions(options)\n  const minimized: BuildThemeOptions = {}\n\n  for (const scheme of SCHEMES) {\n    const values = resolved[scheme]\n    const kept: SchemeThemeOptions = {}\n\n    if (values.accent !== DEFAULT_ACCENT) kept.accent = values.accent\n    if (values.text !== deriveTextColor(values.accent)) kept.text = values.text\n    if (values.background !== DEFAULT_BACKGROUND[scheme]) kept.background = values.background\n    if (values.contrast !== DEFAULT_CONTRAST) kept.contrast = values.contrast\n\n    if (Object.keys(kept).length > 0) minimized[scheme] = kept\n  }\n\n  return Object.keys(minimized).length === 0 ? null : minimized\n}\n\n/**\n * Whether two sets of theme options generate the same theme, comparing their\n * resolved forms so that derived and explicit values (and hex casing) don't\n * matter.\n *\n * @internal\n */\nexport function sameOptions(a: BuildThemeOptions, b: BuildThemeOptions): boolean {\n  const left = resolveThemeOptions(a)\n  const right = resolveThemeOptions(b)\n\n  return SCHEMES.every((scheme) => sameScheme(left[scheme], right[scheme]))\n}\n\nfunction sameScheme(a: ResolvedSchemeOptions, b: ResolvedSchemeOptions): boolean {\n  return (\n    a.accent === b.accent &&\n    a.text === b.text &&\n    a.background === b.background &&\n    a.contrast === b.contrast\n  )\n}\n","import {type BuildThemeOptions, SCHEMES, type SchemeThemeOptions} from '../theme/options'\nimport {minimizeOptions} from './options'\n\n/**\n * Serializes theme options into the `buildTheme` call to paste into\n * `sanity.config.ts`, keeping only what differs from the derived defaults in\n * each scheme.\n *\n * Options that boil down to the stock Studio theme need nothing from this\n * package — so they serialize to a bare `buildTheme()` from `@sanity/ui/theme`\n * instead.\n *\n * @internal\n */\nexport function createThemeSnippet(options: BuildThemeOptions): string {\n  const minimized = minimizeOptions(options)\n\n  if (minimized === null) {\n    return \"import {buildTheme} from '@sanity/ui/theme'\\n\\nexport const theme = buildTheme()\\n\"\n  }\n\n  const lines: string[] = []\n\n  for (const scheme of SCHEMES) {\n    const values = minimized[scheme]\n\n    if (values) lines.push(serializeScheme(scheme, values))\n  }\n\n  return `import {buildTheme} from '@sanity/themer'\\n\\nexport const theme = buildTheme({\\n${lines.join('\\n')}\\n})\\n`\n}\n\n/** A scheme with up to two options fits on one line, more spread out */\nfunction serializeScheme(scheme: string, values: SchemeThemeOptions): string {\n  const entries: string[] = []\n\n  if (values.accent !== undefined) entries.push(`accent: '${values.accent}'`)\n  if (values.text !== undefined) entries.push(`text: '${values.text}'`)\n  if (values.background !== undefined) entries.push(`background: '${values.background}'`)\n  if (values.contrast !== undefined) entries.push(`contrast: ${values.contrast}`)\n\n  if (entries.length <= 2) {\n    return `  ${scheme}: {${entries.join(', ')}},`\n  }\n\n  return `  ${scheme}: {\\n${entries.map((entry) => `    ${entry},`).join('\\n')}\\n  },`\n}\n","import {ClipboardIcon} from '@sanity/icons/Clipboard'\nimport {Box, Button, Card, Dialog, Flex, Stack, Text} from '@sanity/ui'\nimport {Code} from '@sanity/ui/code'\nimport {useToast} from '@sanity/ui/toast'\nimport {registerLanguage} from 'react-refractor'\nimport typescript from 'refractor/typescript'\n\nimport {createThemeSnippet} from './snippet'\nimport {displayTitle, type ThemerTheme} from './themes'\n\n// `Code` only highlights languages the surrounding app has registered with\n// react-refractor, and the Studio registers its own set from an async import\n// during startup — a race this dialog keeps losing. Registering the one\n// language the snippet needs keeps it highlighted from the first render.\nregisterLanguage(typescript)\n\n/**\n * Shows the `buildTheme` snippet that makes a theme permanent, in a dialog so\n * that it does not take up sidebar space or make the sidebar scroll as the\n * snippet changes shape with the theme.\n *\n * @internal\n */\nexport function ThemeSnippetDialog(props: {onClose: () => void; theme: ThemerTheme}) {\n  const {onClose, theme} = props\n  const toast = useToast()\n  const snippet = createThemeSnippet(theme.options)\n\n  const handleCopy = async () => {\n    try {\n      await navigator.clipboard.writeText(snippet)\n      toast.push({status: 'success', title: 'Copied the theme to the clipboard'})\n    } catch {\n      toast.push({status: 'error', title: 'Could not copy the theme'})\n    }\n  }\n\n  return (\n    <Dialog\n      animate\n      footer={\n        <Flex gap={2} justify=\"flex-end\" padding={3}>\n          <Button\n            gap={2}\n            icon={ClipboardIcon}\n            mode=\"ghost\"\n            onClick={() => void handleCopy()}\n            padding={2}\n            text=\"Copy\"\n          />\n        </Flex>\n      }\n      header=\"Add to your config\"\n      id=\"themer-snippet\"\n      onClickOutside={onClose}\n      onClose={onClose}\n      width={1}\n    >\n      <Box padding={4}>\n        <Stack gap={4}>\n          <Text muted size={1}>\n            Export this from <code>sanity.config.ts</code> and pass it as the <code>theme</code> of{' '}\n            <code>defineConfig</code> to make “{displayTitle(theme.title)}” the Studio theme without\n            this tool.\n          </Text>\n          <Card border overflow=\"auto\" padding={3} radius={2} tone=\"transparent\">\n            <Code language=\"ts\" size={1}>\n              {snippet}\n            </Code>\n          </Card>\n        </Stack>\n      </Box>\n    </Dialog>\n  )\n}\n","import {useMediaIndex} from '@sanity/ui'\n\nimport {MIN_MEDIA_INDEX_FOR_SPLIT_SCREEN} from '#constants'\n\nexport function useIsTooSmallForSplitScreen() {\n  const index = useMediaIndex()\n  return index <= MIN_MEDIA_INDEX_FOR_SPLIT_SCREEN\n}\n","import {style} from '@vanilla-extract/css'\n\n/** Lets the title shrink and truncate instead of pushing the buttons out */\nexport const title = style({\n  minWidth: 0,\n})\n","import {ArrowLeftIcon} from '@sanity/icons/ArrowLeft'\nimport {CloseIcon} from '@sanity/icons/Close'\nimport {CodeBlockIcon} from '@sanity/icons/CodeBlock'\nimport {SplitVerticalIcon} from '@sanity/icons/SplitVertical'\nimport {Box, Card, Flex, Text} from '@sanity/ui'\nimport {useSelector} from '@xstate/react'\nimport {dequal} from 'dequal/lite'\nimport {Activity, startTransition, useState} from 'react'\n\nimport type {ThemerView} from '#context'\nimport type {ThemerProps} from '#types'\n\nimport {addThemerTransitionType} from './addThemerTransitionType'\nimport type {ThemerSnapshot} from './machine'\nimport {RemovedThemes} from './RemovedThemes'\nimport {ThemeEditor} from './ThemeEditor'\nimport {ThemeList} from './ThemeList'\nimport {resolveThemes} from './themes'\nimport {ThemeSnippetDialog} from './ThemeSnippetDialog'\nimport {TooltipButton} from './TooltipButton'\nimport {useIsTooSmallForSplitScreen} from './useIsTooSmallForSplitScreen'\n\nimport {title} from './ThemerSidebar.css'\n\nconst VIEW_TITLES = {\n  list: 'Themer',\n  edit: 'Edit theme',\n  removed: 'Removed themes',\n} as const\n\n/**\n * The themer sidebar: a header that navigates between the flows and toggles\n * the split preview, the flow itself — picking a theme, editing one, or\n * restoring removed ones — and the dialog with the `buildTheme` snippet of\n * the applied theme.\n *\n * @internal\n */\nexport function ThemerSidebar({\n  actorRef,\n  dispatch,\n  navbarHeight,\n  split,\n}: Pick<ThemerProps, 'actorRef' | 'dispatch' | 'navbarHeight' | 'split'>) {\n  const [snippetOpen, setSnippetOpen] = useState(false)\n  const view = useSelector(actorRef, selectView, sameView)\n  const inList = view.name === 'list'\n  const isTooSmallForSplitScreen = useIsTooSmallForSplitScreen()\n\n  const {themes, removed, active} = useSelector(\n    actorRef,\n    (snapshot) => resolveThemes(snapshot.context),\n    dequal,\n  )\n\n  return (\n    <Card height=\"fill\">\n      <Flex direction=\"column\" height=\"fill\">\n        {/* The header sits next to the Studio navbar and takes its height, so\n            the two bottom borders line up — whatever height the Studio, its\n            breakpoint or a custom navbar gives it */}\n        <Card\n          borderBottom\n          padding={3}\n          sizing=\"border\"\n          style={navbarHeight === null ? undefined : {height: navbarHeight}}\n        >\n          <Flex align=\"center\" gap={1} height=\"fill\">\n            {!inList && (\n              <TooltipButton\n                icon={ArrowLeftIcon}\n                mode=\"bleed\"\n                onClick={() => actorRef.send({type: 'flow.list'})}\n                padding={2}\n                tooltip=\"Back to the themes\"\n              />\n            )}\n            <Box className={title} flex={1}>\n              <Text size={1} textOverflow=\"ellipsis\" weight=\"semibold\">\n                {VIEW_TITLES[view.name]}\n              </Text>\n            </Box>\n            {/* Packed without gaps, so the title still fits next to them at the\n                narrowest sidebar width */}\n            <Flex>\n              {view.name !== 'removed' && (\n                <>\n                  {!isTooSmallForSplitScreen && (\n                    <TooltipButton\n                      aria-pressed={split}\n                      icon={SplitVerticalIcon}\n                      mode=\"bleed\"\n                      onClick={() =>\n                        startTransition(() => {\n                          const type = split ? 'split-screen:close' : 'split-screen:open'\n                          addThemerTransitionType(type)\n                          dispatch({type})\n                        })\n                      }\n                      onMouseEnter={() =>\n                        startTransition(() => {\n                          dispatch({type: 'split-screen:prerender'})\n                        })\n                      }\n                      padding={2}\n                      selected={split}\n                      tooltip=\"Show light and dark side by side\"\n                    />\n                  )}\n                  {active && (\n                    <TooltipButton\n                      icon={CodeBlockIcon}\n                      mode=\"bleed\"\n                      onClick={() => setSnippetOpen(true)}\n                      padding={2}\n                      tooltip=\"Show the code for the applied theme\"\n                    />\n                  )}\n                </>\n              )}\n              <TooltipButton\n                icon={CloseIcon}\n                mode=\"bleed\"\n                onClick={() =>\n                  startTransition(() => {\n                    if (split) addThemerTransitionType('split-screen:close')\n                    addThemerTransitionType('close')\n                    dispatch({type: 'close'})\n                  })\n                }\n                padding={2}\n                tooltip=\"Close themer\"\n              />\n            </Flex>\n          </Flex>\n        </Card>\n\n        <Activity key=\"list\" mode={view.name === 'list' ? 'visible' : 'hidden'}>\n          <ThemeList actorRef={actorRef} active={active} removed={removed} themes={themes} />\n        </Activity>\n        {view.name === 'edit' && (\n          <ThemeEditor\n            actorRef={actorRef}\n            focusTitle={view.focusTitle}\n            slug={view.slug}\n            split={split}\n            themes={themes}\n          />\n        )}\n        <Activity key=\"removed\" mode={view.name === 'removed' ? 'visible' : 'hidden'}>\n          <RemovedThemes actorRef={actorRef} removed={removed} />\n        </Activity>\n      </Flex>\n\n      {active && snippetOpen && (\n        <ThemeSnippetDialog onClose={() => setSnippetOpen(false)} theme={active} />\n      )}\n    </Card>\n  )\n}\n\nfunction selectView(snapshot: ThemerSnapshot): ThemerView {\n  const {editing} = snapshot.context\n\n  if (snapshot.matches({flow: 'edit'}) && editing) {\n    return {name: 'edit', slug: editing.slug, focusTitle: editing.focusTitle}\n  }\n\n  if (snapshot.matches({flow: 'removed'})) {\n    return {name: 'removed'}\n  }\n\n  return {name: 'list'}\n}\n\nfunction sameView(a: ThemerView, b: ThemerView): boolean {\n  if (a.name !== b.name) return false\n\n  return (\n    a.name !== 'edit' || b.name !== 'edit' || (a.slug === b.slug && a.focusTitle === b.focusTitle)\n  )\n}\n","import {createContainer, style} from '@vanilla-extract/css'\n\n/** The sidebar's content, which the content's layout queries — as wide as the sidebar itself */\nexport const sidebarContent = createContainer()\n\nexport const sidebar = style({\n  flex: 'none',\n})\n\n/**\n * Draws the sidebar's border and gives the resize handle its card colors. It\n * does not clip, so the handle can straddle the border — the content is\n * clipped one level down instead.\n */\nexport const frame = style({\n  position: 'relative',\n})\n\n/**\n * Clips the content, and is the container its layout queries: as wide as\n * the sidebar, whether or not a scrollbar takes room inside — see the theme\n * grid's columns in `ThemeList.css.ts`\n */\nexport const content = style({\n  containerType: 'inline-size',\n  containerName: sidebarContent,\n})\n\n/**\n * The grab area along the sidebar's left edge. It straddles the border so it\n * is easy to hit, and highlights while hovered, focused or dragged.\n */\nexport const resizeHandle = style({\n  'position': 'absolute',\n  'top': 0,\n  'bottom': 0,\n  'left': -3,\n  'zIndex': 1,\n  'width': 7,\n  'cursor': 'col-resize',\n  'touchAction': 'none',\n  '::after': {\n    content: '',\n    position: 'absolute',\n    top: 0,\n    bottom: 0,\n    left: 2,\n    width: 3,\n    background: 'var(--card-focus-ring-color)',\n    opacity: 0,\n    transition: 'opacity 100ms',\n  },\n  ':focus': {\n    outline: 'none',\n  },\n  'selectors': {\n    \"&:hover::after, &:focus-visible::after, &[data-dragging='true']::after\": {\n      opacity: 1,\n    },\n  },\n})\n","import {BoundaryElementProvider, Box, Card, Layer} from '@sanity/ui'\nimport {startTransition, useCallback, useEffect, useRef, useState} from 'react'\n\nimport type {ThemerProps} from '#types'\n\nimport {MAXIMUM_WIDTH, MINIMUM_WIDTH} from './sidebarWidth'\nimport {ThemerSidebar} from './ThemerSidebar'\n\nimport {content, frame, resizeHandle, sidebar} from './ResizableSidebar.css'\n\n/** How far one arrow key press resizes the sidebar */\nconst KEYBOARD_STEP = 16\n\nconst WIDTH_STORAGE_KEY = 'sanityStudio:themer:width'\n\nfunction clampWidth(width: number): number {\n  return Math.min(MAXIMUM_WIDTH, Math.max(MINIMUM_WIDTH, Math.round(width)))\n}\n\nfunction readStoredWidth(): number {\n  try {\n    const stored = Number(localStorage.getItem(WIDTH_STORAGE_KEY))\n\n    return Number.isFinite(stored) && stored > 0 ? clampWidth(stored) : MINIMUM_WIDTH\n  } catch {\n    return MINIMUM_WIDTH\n  }\n}\n\nfunction writeStoredWidth(width: number): void {\n  try {\n    if (width === MINIMUM_WIDTH) {\n      localStorage.removeItem(WIDTH_STORAGE_KEY)\n    } else {\n      localStorage.setItem(WIDTH_STORAGE_KEY, String(width))\n    }\n  } catch {\n    // Storage can be unavailable (e.g. private browsing) — the width just won't persist\n  }\n}\n\n/**\n * The themer sidebar, in a layer along the right edge of the Studio. Its left\n * edge drags (or arrow-keys) it wider, up to twice its default width — the\n * width sticks between sessions. As an overlay (small screens) it covers the\n * Studio edge to edge instead, with nothing to resize.\n *\n * @internal\n */\nexport default function ResizableSidebar({\n  actorRef,\n  dispatch,\n  navbarHeight,\n  split,\n}: Pick<ThemerProps, 'actorRef' | 'dispatch' | 'navbarHeight' | 'split'>) {\n  const [width, setWidth] = useState(readStoredWidth)\n  const [dragging, setDragging] = useState(false)\n  const drag = useRef<{pointerId: number; startX: number; startWidth: number} | null>(null)\n\n  // @TODO schedule the write to localStorage to avoid blocking the main thread\n  useEffect(() => writeStoredWidth(width), [width])\n\n  const handlePointerDown = useCallback(\n    (event: React.PointerEvent<HTMLDivElement>) => {\n      if (event.button !== 0) return\n\n      event.preventDefault()\n      event.currentTarget.setPointerCapture(event.pointerId)\n      drag.current = {pointerId: event.pointerId, startX: event.clientX, startWidth: width}\n      setDragging(true)\n    },\n    [width],\n  )\n\n  const handlePointerMove = useCallback((event: React.PointerEvent<HTMLDivElement>) => {\n    if (!drag.current || drag.current.pointerId !== event.pointerId) return\n\n    // The sidebar sits on the right, so dragging left makes it wider\n    setWidth(clampWidth(drag.current.startWidth - (event.clientX - drag.current.startX)))\n  }, [])\n\n  const handlePointerUp = useCallback((event: React.PointerEvent<HTMLDivElement>) => {\n    if (!drag.current || drag.current.pointerId !== event.pointerId) return\n\n    drag.current = null\n    setDragging(false)\n  }, [])\n\n  const handleKeyDown = useCallback((event: React.KeyboardEvent<HTMLDivElement>) => {\n    const steps: Record<string, number> = {\n      ArrowLeft: KEYBOARD_STEP,\n      ArrowRight: -KEYBOARD_STEP,\n      Home: MAXIMUM_WIDTH,\n      End: -MAXIMUM_WIDTH,\n    }\n    const step = steps[event.key]\n\n    if (step === undefined) return\n\n    event.preventDefault()\n    setWidth((current) => clampWidth(current + step))\n  }, [])\n\n  const [boundaryElement, setBoundaryElement] = useState<HTMLDivElement | null>(null)\n\n  return (\n    <Layer className={sidebar} style={{width}} zOffset={100}>\n      <Card\n        borderLeft\n        className={frame}\n        height=\"fill\"\n        ref={(boundaryElement) => {\n          startTransition(() => setBoundaryElement(boundaryElement))\n          // Intentionally not unsetting the element as it would create unnecessary work when <Activity> unhides\n          return () => {}\n        }}\n      >\n        <div\n          aria-label=\"Resize the themer\"\n          className={resizeHandle}\n          aria-orientation=\"vertical\"\n          aria-valuemax={MAXIMUM_WIDTH}\n          aria-valuemin={MINIMUM_WIDTH}\n          aria-valuenow={width}\n          data-dragging={dragging}\n          onDoubleClick={() => setWidth(MINIMUM_WIDTH)}\n          onKeyDown={handleKeyDown}\n          onPointerCancel={handlePointerUp}\n          onPointerDown={handlePointerDown}\n          onPointerMove={handlePointerMove}\n          onPointerUp={handlePointerUp}\n          // oxlint-disable-next-line prefer-tag-over-role -- a window splitter is a focusable, draggable separator, which an hr is not\n          role=\"separator\"\n          tabIndex={0}\n        />\n        <Box className={content} height=\"fill\" overflow=\"hidden\">\n          <BoundaryElementProvider element={boundaryElement}>\n            <ThemerSidebar\n              split={split}\n              navbarHeight={navbarHeight}\n              actorRef={actorRef}\n              dispatch={dispatch}\n            />\n          </BoundaryElementProvider>\n        </Box>\n      </Card>\n    </Layer>\n  )\n}\n"],"mappings":"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"}
\ No newline at end of file