@sanity/themer
0.8.10.9.0
dist/ResizableSidebar-DD787kQr.js−
dist/ResizableSidebar-DD787kQr.jsDeleted−2050
Index: package/dist/ResizableSidebar-DD787kQr.js
===================================================================
--- package/dist/ResizableSidebar-DD787kQr.js
+++ package/dist/ResizableSidebar-DD787kQr.js
@@ -1,2050 +0,0 @@
-import { c as resolveThemeOptions, l as isColor, n as buildTheme, o as SCHEMES, r as buildPalette } from "./presets-CqBgS3A-.js";
-import { _ as titleFromFileName, c as minimizeOptions, d as IMAGE_PALETTE_VARIANTS, f as applyImagePalette, g as pickLuckyVariant, h as optionsFromImagePalette, i as displayTitle, m as extractImagePalette, p as currentImageVariant, u as IMAGE_PALETTE_TITLES, y as useThemer } from "./ResizableSidebar.css.ts.vanilla-M9EuPu-q.js";
-import { c } from "react/compiler-runtime";
-import { useColorSchemeValue } from "sanity";
-import { Badge, Box, Button, Card, Dialog, Flex, Layer, Stack, Text, TextInput, ThemeProvider, useRootTheme, useTheme_v2 } from "@sanity/ui";
-import { createContext, useContext, useEffect, useRef, useState } from "react";
-import { Fragment, jsx, jsxs } from "react/jsx-runtime";
-import { Tooltip } from "@sanity/ui/tooltip";
-import { MotionConfig, Reorder, useDragControls } from "motion/react";
-import { ArrowLeftIcon } from "@sanity/icons/ArrowLeft";
-import { CloseIcon } from "@sanity/icons/Close";
-import { CodeBlockIcon } from "@sanity/icons/CodeBlock";
-import { SplitVerticalIcon } from "@sanity/icons/SplitVertical";
-import { assignInlineVars } from "@vanilla-extract/dynamic";
-import { ResetIcon } from "@sanity/icons/Reset";
-import { TrashIcon } from "@sanity/icons/Trash";
-import { SparklesIcon } from "@sanity/icons/Sparkles";
-import { ImageIcon } from "@sanity/icons/Image";
-import { useToast } from "@sanity/ui/toast";
-import { AddIcon } from "@sanity/icons/Add";
-import { ClipboardIcon } from "@sanity/icons/Clipboard";
-import { RestoreIcon } from "@sanity/icons/Restore";
-import { ArrowDownIcon } from "@sanity/icons/ArrowDown";
-import { ArrowUpIcon } from "@sanity/icons/ArrowUp";
-import { CopyIcon } from "@sanity/icons/Copy";
-import { EditIcon } from "@sanity/icons/Edit";
-import { EllipsisHorizontalIcon } from "@sanity/icons/EllipsisHorizontal";
-import { ShareIcon } from "@sanity/icons/Share";
-import { Menu, MenuButton, MenuDivider, MenuItem } from "@sanity/ui/menu";
-import scrollIntoView from "scroll-into-view-if-needed";
-import { Code } from "@sanity/ui/code";
-import { registerLanguage } from "react-refractor";
-import typescript from "refractor/typescript";
-var root$2 = "_1o50s7t0";
-const ScrollAreaInsetContext = createContext({
- left: 0,
- right: 0,
- bottom: 0
-});
-/**
-* The gutter the last scroll area measured. It is the same for every scroll
-* area (the reserved gutter does not depend on the content), so the next one
-* starts out with the right padding instead of shifting after its first
-* measurement — which would also throw off anything scrolling into view as
-* the content mounts.
-*/
-let lastGutter = 0;
-/**
-* The scrolling body of a sidebar flow. It always reserves the scrollbar's
-* space, so the content does not shift when the list grows or shrinks past
-* the point where it needs to scroll — and it takes that space out of its
-* right padding, so the content stays centered rather than hugging the left.
-* With overlay scrollbars there is no gutter and the padding stays even.
-*
-* @internal
-*/
-function ScrollArea(props) {
- let $ = c(15), { children, padding } = props, { space } = useTheme_v2(), ref = useRef(null), [gutter, setGutter] = useState(_temp$6), t0, t1;
- $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = () => {
- let element = ref.current;
- if (!element) return;
- let measure = () => {
- lastGutter = element.offsetWidth - element.clientWidth, setGutter(lastGutter);
- };
- measure();
- let observer = new ResizeObserver(measure);
- return observer.observe(element), () => observer.disconnect();
- }, t1 = [], $[0] = t0, $[1] = t1) : (t0 = $[0], t1 = $[1]), useEffect(t0, t1);
- let t2 = space[padding], t3 = Math.max(0, space[padding] - gutter), t4 = space[padding], t5;
- $[2] !== t2 || $[3] !== t3 || $[4] !== t4 ? (t5 = {
- left: t2,
- right: t3,
- bottom: t4
- }, $[2] = t2, $[3] = t3, $[4] = t4, $[5] = t5) : t5 = $[5];
- let inset = t5, t6;
- $[6] === inset.right ? t6 = $[7] : (t6 = { paddingRight: inset.right }, $[6] = inset.right, $[7] = t6);
- let t7;
- $[8] !== children || $[9] !== inset ? (t7 = /* @__PURE__ */ jsx(ScrollAreaInsetContext.Provider, {
- value: inset,
- children
- }), $[8] = children, $[9] = inset, $[10] = t7) : t7 = $[10];
- let t8;
- return $[11] !== padding || $[12] !== t6 || $[13] !== t7 ? (t8 = /* @__PURE__ */ jsx(Box, {
- className: root$2,
- flex: 1,
- overflow: "auto",
- padding,
- ref,
- style: t6,
- children: t7
- }), $[11] = padding, $[12] = t6, $[13] = t7, $[14] = t8) : t8 = $[14], t8;
-}
-function _temp$6() {
- return lastGutter;
-}
-/**
-* Content that runs edge to edge in a scroll area — up to the scrollbar —
-* instead of sitting inside its padding. It goes last: it runs down to the
-* bottom edge too.
-*
-* @internal
-*/
-function ScrollAreaBleed(props) {
- let $ = c(7), { left, right, bottom } = useContext(ScrollAreaInsetContext), t0 = -left, t1 = -right, t2 = -bottom, t3;
- $[0] !== t0 || $[1] !== t1 || $[2] !== t2 ? (t3 = {
- marginLeft: t0,
- marginRight: t1,
- marginBottom: t2
- }, $[0] = t0, $[1] = t1, $[2] = t2, $[3] = t3) : t3 = $[3];
- let t4;
- return $[4] !== props.children || $[5] !== t3 ? (t4 = /* @__PURE__ */ jsx("div", {
- style: t3,
- children: props.children
- }), $[4] = props.children, $[5] = t3, $[6] = t4) : t4 = $[6], t4;
-}
-var avatar = "_1aa9huuh", body = "_1aa9huui", button = "_1aa9huuq", colors = {
- bg: "var(--_1aa9huu0)",
- fg: "var(--_1aa9huu1)",
- mutedFg: "var(--_1aa9huu2)",
- border: "var(--_1aa9huu3)",
- accent: "var(--_1aa9huu4)",
- avatar: "var(--_1aa9huu5)",
- selectedBg: "var(--_1aa9huu6)",
- selectedFg: "var(--_1aa9huu7)",
- inputBg: "var(--_1aa9huu8)",
- inputBorder: "var(--_1aa9huu9)"
-}, field = "_1aa9huun", footer = "_1aa9huup", form = "_1aa9huum", input = "_1aa9huuo", line = {
- fg: "_1aa9huus _1aa9huur",
- muted: "_1aa9huut _1aa9huur",
- selected: "_1aa9huuu _1aa9huur"
-}, list = "_1aa9huuj", listRow = "_1aa9huuk", logo = "_1aa9huuf", navbar = "_1aa9huue", pane = "_1aa9huul", root$1 = "_1aa9huua", spacer = "_1aa9huug", studio = {
- light: "_1aa9huub",
- dark: "_1aa9huud _1aa9huub"
-};
-/** The document rows in the list pane — the widths of their title lines */
-const LIST_ROWS = [
- "62%",
- "46%",
- "70%",
- "52%"
-], FIELDS$1 = ["32%", "24%"];
-/**
-* A tiny, lo-fi mockup of a Studio in the given theme — the navbar over the
-* structure tool with a list of documents on the left and a document form on
-* the right — in both color schemes at once: the light scheme on the left and
-* the dark scheme on the right, split diagonally. It only paints colors the
-* theme options change (backgrounds, text, borders, the accent) so that a
-* glance shows what the theme does to the Studio — with few and bold enough
-* elements to still read when scaled down to a thumbnail.
-*
-* @internal
-*/
-function ThemePreview(props) {
- let $ = c(11), { options } = props, t0;
- $[0] === options ? t0 = $[1] : (t0 = buildTheme(options), $[0] = options, $[1] = t0);
- let theme = t0, t1;
- $[2] === Symbol.for("react.memo_cache_sentinel") ? (t1 = /* @__PURE__ */ jsx(MockStudio, { scheme: "light" }), $[2] = t1) : t1 = $[2];
- let t2;
- $[3] === theme ? t2 = $[4] : (t2 = /* @__PURE__ */ jsx(ThemeProvider, {
- scheme: "light",
- theme,
- tone: "default",
- children: t1
- }), $[3] = theme, $[4] = t2);
- let t3;
- $[5] === Symbol.for("react.memo_cache_sentinel") ? (t3 = /* @__PURE__ */ jsx(MockStudio, { scheme: "dark" }), $[5] = t3) : t3 = $[5];
- let t4;
- $[6] === theme ? t4 = $[7] : (t4 = /* @__PURE__ */ jsx(ThemeProvider, {
- scheme: "dark",
- theme,
- tone: "default",
- children: t3
- }), $[6] = theme, $[7] = t4);
- let t5;
- return $[8] !== t2 || $[9] !== t4 ? (t5 = /* @__PURE__ */ jsxs("div", {
- "aria-hidden": !0,
- className: root$1,
- children: [t2, t4]
- }), $[8] = t2, $[9] = t4, $[10] = t5) : t5 = $[10], t5;
-}
-function MockStudio(props) {
- let $ = c(19), { scheme } = props, { color } = useTheme_v2(), selected = color.selectable.default.selected, inputColor = color.input.default.enabled, t0 = studio[scheme], t1;
- $[0] !== color.avatar.blue.bg || $[1] !== color.bg || $[2] !== color.border || $[3] !== color.button.default.primary.enabled.bg || $[4] !== color.fg || $[5] !== color.muted.fg || $[6] !== inputColor.bg || $[7] !== inputColor.border || $[8] !== selected.bg || $[9] !== selected.fg ? (t1 = assignInlineVars({
- [colors.bg]: color.bg,
- [colors.fg]: color.fg,
- [colors.mutedFg]: color.muted.fg,
- [colors.border]: color.border,
- [colors.accent]: color.button.default.primary.enabled.bg,
- [colors.avatar]: color.avatar.blue.bg,
- [colors.selectedBg]: selected.bg,
- [colors.selectedFg]: selected.fg,
- [colors.inputBg]: inputColor.bg,
- [colors.inputBorder]: inputColor.border
- }), $[0] = color.avatar.blue.bg, $[1] = color.bg, $[2] = color.border, $[3] = color.button.default.primary.enabled.bg, $[4] = color.fg, $[5] = color.muted.fg, $[6] = inputColor.bg, $[7] = inputColor.border, $[8] = selected.bg, $[9] = selected.fg, $[10] = t1) : t1 = $[10];
- let t2;
- $[11] === Symbol.for("react.memo_cache_sentinel") ? (t2 = /* @__PURE__ */ jsx("div", { className: logo }), $[11] = t2) : t2 = $[11];
- let t3;
- $[12] === Symbol.for("react.memo_cache_sentinel") ? (t3 = /* @__PURE__ */ jsxs("div", {
- className: navbar,
- children: [
- t2,
- /* @__PURE__ */ jsx("div", {
- className: line.fg,
- style: { width: "22%" }
- }),
- /* @__PURE__ */ jsx("div", { className: spacer }),
- /* @__PURE__ */ jsx("div", { className: avatar })
- ]
- }), $[12] = t3) : t3 = $[12];
- let t4;
- $[13] === Symbol.for("react.memo_cache_sentinel") ? (t4 = /* @__PURE__ */ jsx("div", {
- className: list,
- children: LIST_ROWS.map(_temp$5)
- }), $[13] = t4) : t4 = $[13];
- let t5;
- $[14] === Symbol.for("react.memo_cache_sentinel") ? (t5 = /* @__PURE__ */ jsxs("div", {
- className: form,
- children: [/* @__PURE__ */ jsx("div", {
- className: line.fg,
- style: { width: "45%" }
- }), FIELDS$1.map(_temp2)]
- }), $[14] = t5) : t5 = $[14];
- let t6;
- $[15] === Symbol.for("react.memo_cache_sentinel") ? (t6 = /* @__PURE__ */ jsxs("div", {
- className: body,
- children: [t4, /* @__PURE__ */ jsxs("div", {
- className: pane,
- children: [t5, /* @__PURE__ */ jsx("div", {
- className: footer,
- children: /* @__PURE__ */ jsx("div", { className: button })
- })]
- })]
- }), $[15] = t6) : t6 = $[15];
- let t7;
- return $[16] !== t0 || $[17] !== t1 ? (t7 = /* @__PURE__ */ jsxs("div", {
- className: t0,
- style: t1,
- children: [t3, t6]
- }), $[16] = t0, $[17] = t1, $[18] = t7) : t7 = $[18], t7;
-}
-function _temp2(width_0) {
- return /* @__PURE__ */ jsxs("div", {
- className: field,
- children: [/* @__PURE__ */ jsx("div", {
- className: line.muted,
- style: { width: width_0 }
- }), /* @__PURE__ */ jsx("div", { className: input })]
- }, width_0);
-}
-function _temp$5(width, index) {
- let isSelected = index === 1;
- return /* @__PURE__ */ jsx("div", {
- className: listRow,
- "data-selected": isSelected,
- children: /* @__PURE__ */ jsx("div", {
- className: isSelected ? line.selected : line.muted,
- style: { width }
- })
- }, width);
-}
-/**
-* The floating preview card of a theme: the lo-fi studio mockup on a raised,
-* rounded card, like the appearance previews in macOS System Settings.
-*
-* @internal
-*/
-function ThemeThumbnail(props) {
- let $ = c(2), t0;
- return $[0] === props.options ? t0 = $[1] : (t0 = /* @__PURE__ */ jsx(Card, {
- overflow: "hidden",
- radius: 3,
- shadow: 1,
- children: /* @__PURE__ */ jsx(ThemePreview, { options: props.options })
- }), $[0] = props.options, $[1] = t0), t0;
-}
-var removedThumbnail = "_1vdkp0v0";
-/**
-* The flow for restoring removed themes: the presets and custom themes the
-* user took out of the list, each with a button to put it back — and, for
-* custom themes, one to delete it for good. The machine leaves the flow once
-* the last one is gone.
-*
-* @internal
-*/
-function RemovedThemes() {
- let $ = c(7), { removed, send } = useThemer(), t0;
- if ($[0] !== removed || $[1] !== send) {
- let t1;
- $[3] === send ? t1 = $[4] : (t1 = (theme) => /* @__PURE__ */ jsxs(Stack, {
- gap: 3,
- children: [
- /* @__PURE__ */ jsx(Box, {
- className: removedThumbnail,
- children: /* @__PURE__ */ jsx(ThemeThumbnail, { options: theme.options })
- }),
- /* @__PURE__ */ jsx(Text, {
- align: "center",
- size: 1,
- textOverflow: "ellipsis",
- children: displayTitle(theme.title)
- }),
- /* @__PURE__ */ jsxs(Flex, {
- gap: 2,
- justify: "center",
- children: [/* @__PURE__ */ jsx(Button, {
- mode: "ghost",
- onClick: () => send({
- type: "theme.restore",
- slug: theme.slug
- }),
- padding: 2,
- text: "Restore"
- }), theme.source === "custom" && /* @__PURE__ */ jsx(Button, {
- mode: "ghost",
- onClick: () => send({
- type: "theme.delete",
- slug: theme.slug
- }),
- padding: 2,
- text: "Delete",
- tone: "critical"
- })]
- })
- ]
- }, theme.slug), $[3] = send, $[4] = t1), t0 = removed.map(t1), $[0] = removed, $[1] = send, $[2] = t0;
- } else t0 = $[2];
- let t1;
- return $[5] === t0 ? t1 = $[6] : (t1 = /* @__PURE__ */ jsx(ScrollArea, {
- padding: 3,
- children: /* @__PURE__ */ jsx(Stack, {
- gap: 5,
- children: t0
- })
- }), $[5] = t0, $[6] = t1), t1;
-}
-/**
-* A button with an animated tooltip instead of a `title` attribute, sized like
-* the Studio's own buttons (`padding` and `gap` of 2). Icon-only buttons take
-* the tooltip as their accessible name.
-*
-* @internal
-*/
-function TooltipButton(props) {
- let $ = c(11), buttonProps, tooltip;
- $[0] === props ? (buttonProps = $[1], tooltip = $[2]) : ({tooltip, ...buttonProps} = props, $[0] = props, $[1] = buttonProps, $[2] = tooltip);
- let t0;
- $[3] === tooltip ? t0 = $[4] : (t0 = /* @__PURE__ */ jsx(Text, {
- size: 1,
- children: tooltip
- }), $[3] = tooltip, $[4] = t0);
- let t1 = buttonProps.text === void 0 ? tooltip : void 0, t2;
- $[5] !== buttonProps || $[6] !== t1 ? (t2 = /* @__PURE__ */ jsx(Button, {
- "aria-label": t1,
- gap: 2,
- padding: 2,
- ...buttonProps
- }), $[5] = buttonProps, $[6] = t1, $[7] = t2) : t2 = $[7];
- let t3;
- return $[8] !== t0 || $[9] !== t2 ? (t3 = /* @__PURE__ */ jsx(Tooltip, {
- animate: !0,
- content: t0,
- placement: "bottom",
- portal: !0,
- children: t2
- }), $[8] = t0, $[9] = t2, $[10] = t3) : t3 = $[10], t3;
-}
-/**
-* A button that opens the file picker for an image, and hands the chosen file
-* over — the picker is a hidden file input, so nothing is uploaded anywhere.
-*
-* @internal
-*/
-function ImageFileButton(props) {
- let $ = c(11), buttonProps, onFile;
- $[0] === props ? (buttonProps = $[1], onFile = $[2]) : ({onFile, ...buttonProps} = props, $[0] = props, $[1] = buttonProps, $[2] = onFile);
- let inputRef = useRef(null), t0;
- $[3] === Symbol.for("react.memo_cache_sentinel") ? (t0 = () => inputRef.current?.click(), $[3] = t0) : t0 = $[3];
- let t1;
- $[4] === buttonProps ? t1 = $[5] : (t1 = /* @__PURE__ */ jsx(TooltipButton, {
- ...buttonProps,
- icon: ImageIcon,
- onClick: t0
- }), $[4] = buttonProps, $[5] = t1);
- let t2;
- $[6] === onFile ? t2 = $[7] : (t2 = /* @__PURE__ */ jsx("input", {
- accept: "image/*",
- hidden: !0,
- onChange: (event) => {
- let file = event.currentTarget.files?.[0];
- event.currentTarget.value = "", file && onFile(file);
- },
- ref: inputRef,
- type: "file"
- }), $[6] = onFile, $[7] = t2);
- let t3;
- return $[8] !== t1 || $[9] !== t2 ? (t3 = /* @__PURE__ */ jsxs(Fragment, { children: [t1, t2] }), $[8] = t1, $[9] = t2, $[10] = t3) : t3 = $[10], t3;
-}
-/**
-* Reads the pixels of an image file on device: the image is decoded, drawn
-* onto a small canvas and read back, so nothing leaves the browser.
-*
-* @internal
-*/
-async function readImagePixels(file) {
- let image = await decodeImage(file);
- try {
- let scale = Math.min(1, 96 / Math.max(image.width, image.height)), width = Math.max(1, Math.round(image.width * scale)), height = Math.max(1, Math.round(image.height * scale)), canvas = document.createElement("canvas");
- canvas.width = width, canvas.height = height;
- let context = canvas.getContext("2d", { willReadFrequently: !0 });
- if (!context) throw Error("Could not draw the image");
- return context.drawImage(image, 0, 0, width, height), {
- data: context.getImageData(0, 0, width, height).data,
- width,
- height
- };
- } finally {
- typeof ImageBitmap < "u" && image instanceof ImageBitmap && image.close();
- }
-}
-async function decodeImage(file) {
- if (typeof createImageBitmap == "function") try {
- return await createImageBitmap(file);
- } catch {}
- let url = URL.createObjectURL(file);
- try {
- return await new Promise((resolve, reject) => {
- let image = new Image();
- image.addEventListener("load", () => resolve(image), { once: !0 }), image.addEventListener("error", () => reject(/* @__PURE__ */ Error("Could not decode the image")), { once: !0 }), image.src = url;
- });
- } finally {
- URL.revokeObjectURL(url);
- }
-}
-/**
-* Extracts the palette of image files on device and hands it to `onPalette`,
-* along with the file it came from. Failures end up as a toast.
-*
-* @internal
-*/
-function useImagePalette(onPalette) {
- let $ = c(10), toast = useToast(), [busy, setBusy] = useState(!1), onPaletteRef = useRef(onPalette), mountedRef = useRef(!0), latestPickRef = useRef(0), t0, t1;
- $[0] === onPalette ? (t0 = $[1], t1 = $[2]) : (t0 = () => {
- onPaletteRef.current = onPalette;
- }, t1 = [onPalette], $[0] = onPalette, $[1] = t0, $[2] = t1), useEffect(t0, t1);
- let t2, t3;
- $[3] === Symbol.for("react.memo_cache_sentinel") ? (t2 = () => (mountedRef.current = !0, () => {
- mountedRef.current = !1;
- }), t3 = [], $[3] = t2, $[4] = t3) : (t2 = $[3], t3 = $[4]), useEffect(t2, t3);
- let t4;
- $[5] === toast ? t4 = $[6] : (t4 = (file) => {
- let pick = latestPickRef.current += 1;
- setBusy(!0);
- let isCurrent = () => mountedRef.current && latestPickRef.current === pick, extract = async () => {
- let palette = extractImagePalette(await readImagePixels(file));
- isCurrent() && (Object.values(palette).every(_temp$4) ? toast.push({
- status: "warning",
- title: "Found no colors in that image"
- }) : onPaletteRef.current(palette, file));
- };
- extract().catch(() => {
- isCurrent() && toast.push({
- status: "error",
- title: "Could not read that image"
- });
- }).finally(() => {
- isCurrent() && setBusy(!1);
- });
- }, $[5] = toast, $[6] = t4);
- let pickImage = t4, t5;
- return $[7] !== busy || $[8] !== pickImage ? (t5 = {
- busy,
- pickImage
- }, $[7] = busy, $[8] = pickImage, $[9] = t5) : t5 = $[9], t5;
-}
-function _temp$4(swatch) {
- return swatch === null;
-}
-var paletteGrid = "_17s80v42", tile = "_17s80v44", variantButton = "_17s80v46", variantFrame = "_17s80v47", variantRow = "_17s80v45", variantScale = "var(--_17s80v41)", variantScaleBox = "_17s80v48", variantWidth = "var(--_17s80v40)";
-/** The swatches on display: the vibrant family over the muted one */
-const TILES = [
- "vibrant",
- "lightVibrant",
- "darkVibrant",
- "muted",
- "lightMuted",
- "darkMuted"
-];
-/**
-* Takes the colors of a theme from an image, on device: the image is read
-* into a canvas and its palette extracted right there — nothing is uploaded.
-* Shows the image (while the session lasts) next to its palette, offers a
-* theme variant built around each swatch as a small preview, and a lucky
-* button that picks an interesting one.
-*
-* @internal
-*/
-function ImagePaletteSection(props) {
- let $ = c(38), { imageUrl, onPalette, onVariant, onLucky, options, palette } = props, { busy, pickImage } = useImagePalette(onPalette), [dragging, setDragging] = useState(!1), dragDepth = useRef(0), t0;
- $[0] !== options || $[1] !== palette ? (t0 = palette ? currentImageVariant(options, palette) : null, $[0] = options, $[1] = palette, $[2] = t0) : t0 = $[2];
- let current = t0, rowRef = useRef(null), [thumbnailWidth, setThumbnailWidth] = useState(58), t1;
- $[3] === Symbol.for("react.memo_cache_sentinel") ? (t1 = () => {
- let row = rowRef.current;
- if (!row) return;
- let measure = () => {
- let visible = row.clientWidth - 12 - 16;
- setThumbnailWidth(Math.max(24, Math.floor(visible / 2.5) - 8));
- };
- measure();
- let observer = new ResizeObserver(measure);
- return observer.observe(row), () => observer.disconnect();
- }, $[3] = t1) : t1 = $[3];
- let t2;
- $[4] === palette ? t2 = $[5] : (t2 = [palette], $[4] = palette, $[5] = t2), useEffect(t1, t2);
- let t3;
- bb0: {
- if (!palette) {
- let t4;
- $[6] === Symbol.for("react.memo_cache_sentinel") ? (t4 = [], $[6] = t4) : t4 = $[6], t3 = t4;
- break bb0;
- }
- let t4;
- $[7] !== options || $[8] !== palette ? (t4 = IMAGE_PALETTE_VARIANTS.flatMap((variant) => palette[variant] === null ? [] : [{
- variant,
- title: IMAGE_PALETTE_TITLES[variant],
- options: applyImagePalette(options, palette, variant)
- }]), $[7] = options, $[8] = palette, $[9] = t4) : t4 = $[9], t3 = t4;
- }
- let variants = t3, t4, t5;
- $[10] === Symbol.for("react.memo_cache_sentinel") ? (t4 = (event) => {
- event.preventDefault(), dragDepth.current += 1, setDragging(!0);
- }, t5 = () => {
- dragDepth.current = Math.max(0, dragDepth.current - 1), dragDepth.current === 0 && setDragging(!1);
- }, $[10] = t4, $[11] = t5) : (t4 = $[10], t5 = $[11]);
- let t6;
- $[12] === pickImage ? t6 = $[13] : (t6 = (event_1) => {
- event_1.preventDefault(), dragDepth.current = 0, setDragging(!1);
- let file = event_1.dataTransfer.files[0];
- file && pickImage(file);
- }, $[12] = pickImage, $[13] = t6);
- let t7 = dragging ? "primary" : "default", t8;
- $[14] === Symbol.for("react.memo_cache_sentinel") ? (t8 = /* @__PURE__ */ jsx(Box, {
- flex: 1,
- children: /* @__PURE__ */ jsx(Text, {
- size: 1,
- weight: "medium",
- children: "Image palette"
- })
- }), $[14] = t8) : t8 = $[14];
- let t9;
- $[15] !== busy || $[16] !== palette || $[17] !== pickImage ? (t9 = palette && /* @__PURE__ */ jsx(ImageFileButton, {
- loading: busy,
- mode: "bleed",
- onFile: pickImage,
- padding: 2,
- tooltip: "Pick another image"
- }), $[15] = busy, $[16] = palette, $[17] = pickImage, $[18] = t9) : t9 = $[18];
- let t10;
- $[19] === t9 ? t10 = $[20] : (t10 = /* @__PURE__ */ jsxs(Flex, {
- align: "center",
- gap: 2,
- children: [t8, t9]
- }), $[19] = t9, $[20] = t10);
- let t11;
- $[21] !== busy || $[22] !== current || $[23] !== imageUrl || $[24] !== onLucky || $[25] !== onVariant || $[26] !== palette || $[27] !== pickImage || $[28] !== thumbnailWidth || $[29] !== variants ? (t11 = palette ? /* @__PURE__ */ jsxs(Fragment, { children: [
- /* @__PURE__ */ jsxs("div", {
- className: paletteGrid,
- "data-with-image": imageUrl !== void 0,
- children: [imageUrl && /* @__PURE__ */ jsx("img", {
- alt: "",
- className: "_17s80v43",
- src: imageUrl
- }), TILES.map((key) => {
- let hex = palette[key], title = IMAGE_PALETTE_TITLES[key];
- return /* @__PURE__ */ jsx(Tooltip, {
- animate: !0,
- content: /* @__PURE__ */ jsx(Text, {
- size: 1,
- children: hex ? `${title} · ${hex}` : `No ${title.toLowerCase()} color`
- }),
- placement: "bottom",
- portal: !0,
- children: /* @__PURE__ */ jsx("span", {
- className: tile,
- "data-empty": hex === null,
- style: { background: hex ?? void 0 }
- })
- }, key);
- })]
- }),
- /* @__PURE__ */ jsxs(Stack, {
- gap: 2,
- children: [/* @__PURE__ */ jsx(Text, {
- muted: !0,
- size: 0,
- children: "Pick the swatch to build the theme around"
- }), /* @__PURE__ */ jsx("div", {
- className: variantRow,
- ref: rowRef,
- style: assignInlineVars({
- [variantWidth]: `${thumbnailWidth}px`,
- [variantScale]: String(thumbnailWidth / 144)
- }),
- children: variants.map((t12) => {
- let { variant: variant_0, title: title_0, options: variantOptions } = t12;
- return /* @__PURE__ */ jsxs("button", {
- "aria-pressed": variant_0 === current,
- className: variantButton,
- onClick: () => onVariant(variant_0),
- type: "button",
- children: [/* @__PURE__ */ jsx("span", {
- className: variantFrame,
- children: /* @__PURE__ */ jsx("span", {
- className: variantScaleBox,
- children: /* @__PURE__ */ jsx(ThemeThumbnail, { options: variantOptions })
- })
- }), /* @__PURE__ */ jsx(Box, {
- as: "span",
- display: "block",
- paddingTop: 1,
- children: /* @__PURE__ */ jsx(Text, {
- align: "center",
- as: "span",
- size: 0,
- textOverflow: "ellipsis",
- weight: variant_0 === current ? "medium" : "regular",
- children: title_0
- })
- })]
- }, variant_0);
- })
- })]
- }),
- /* @__PURE__ */ jsx(TooltipButton, {
- icon: SparklesIcon,
- mode: "ghost",
- onClick: onLucky,
- text: "I'm feeling lucky",
- tooltip: "Build the theme around a swatch that looks interesting",
- width: "fill"
- })
- ] }) : /* @__PURE__ */ jsxs(Stack, {
- gap: 3,
- children: [/* @__PURE__ */ jsx(Text, {
- muted: !0,
- size: 0,
- children: "Take the accent, text and background colors from an image — read on device, nothing is uploaded."
- }), /* @__PURE__ */ jsx(ImageFileButton, {
- loading: busy,
- mode: "ghost",
- onFile: pickImage,
- text: "Pick an image",
- tooltip: "Take the colors from an image on your device",
- width: "fill"
- })]
- }), $[21] = busy, $[22] = current, $[23] = imageUrl, $[24] = onLucky, $[25] = onVariant, $[26] = palette, $[27] = pickImage, $[28] = thumbnailWidth, $[29] = variants, $[30] = t11) : t11 = $[30];
- let t12;
- $[31] !== t10 || $[32] !== t11 ? (t12 = /* @__PURE__ */ jsxs(Stack, {
- gap: 3,
- children: [t10, t11]
- }), $[31] = t10, $[32] = t11, $[33] = t12) : t12 = $[33];
- let t13;
- return $[34] !== t12 || $[35] !== t6 || $[36] !== t7 ? (t13 = /* @__PURE__ */ jsx(Card, {
- border: !0,
- onDragEnter: t4,
- onDragLeave: t5,
- onDragOver: _temp$3,
- onDrop: t6,
- padding: 3,
- radius: 3,
- tone: t7,
- children: t12
- }), $[34] = t12, $[35] = t6, $[36] = t7, $[37] = t13) : t13 = $[37], t13;
-}
-function _temp$3(event_0) {
- event_0.preventDefault();
-}
-var colorRowText = "os3rj2", range = "os3rj1", swatch = "os3rj0";
-const SCHEME_TITLES = {
- dark: "Dark mode",
- light: "Light mode"
-};
-/**
-* Where the split preview shows a scheme: the Studio's own scheme stays next
-* to the sidebar (or at the bottom, stacked on small screens), the other one
-* takes the far side
-*/
-function splitHint(own, mobile) {
- return mobile ? own ? "Shown at the bottom" : "Shown at the top" : own ? "Shown on the right, next to the themer" : "Shown on the left";
-}
-const SCHEME_OPTION_KEYS = [
- "accent",
- "text",
- "background",
- "contrast"
-];
-/**
-* `<input type="color">` paints the color into a shadow-DOM swatch that brings
-* its own border and padding, which then sits inside ours as a second border.
-* Stripping that chrome leaves the themed border as the only one.
-*/
-/**
-* The flow for editing one of the user's own themes: its title, a live
-* preview, and a card per color scheme with the accent/text/background
-* pickers and the contrast slider of that scheme. Every change applies to the
-* whole Studio right away — in the scheme the Studio is showing, or in both
-* side by side in the split preview.
-*
-* @internal
-*/
-function ThemeEditor(props) {
- let $ = c(42), { focusTitle, slug } = props, { themes, images, split, mobile, send } = useThemer(), t0;
- if ($[0] !== slug || $[1] !== themes) {
- let t1;
- $[3] === slug ? t1 = $[4] : (t1 = (candidate) => candidate.slug === slug && candidate.source === "custom", $[3] = slug, $[4] = t1), t0 = themes.find(t1), $[0] = slug, $[1] = themes, $[2] = t0;
- } else t0 = $[2];
- let theme = t0;
- if (!theme) return null;
- let t1;
- $[5] !== send || $[6] !== slug || $[7] !== theme.options || $[8] !== theme.palette ? (t1 = (variant) => {
- theme.palette && variant !== null && send({
- type: "theme.update",
- slug,
- options: applyImagePalette(theme.options, theme.palette, variant)
- });
- }, $[5] = send, $[6] = slug, $[7] = theme.options, $[8] = theme.palette, $[9] = t1) : t1 = $[9];
- let applyVariant = t1, t2 = images[slug], t3;
- $[10] === send ? t3 = $[11] : (t3 = () => send({ type: "flow.list" }), $[10] = send, $[11] = t3);
- let t4;
- $[12] !== applyVariant || $[13] !== theme.options || $[14] !== theme.palette ? (t4 = () => {
- theme.palette && applyVariant(pickLuckyVariant(theme.palette, { exclude: currentImageVariant(theme.options, theme.palette) }));
- }, $[12] = applyVariant, $[13] = theme.options, $[14] = theme.palette, $[15] = t4) : t4 = $[15];
- let t5;
- $[16] !== send || $[17] !== slug ? (t5 = (options) => send({
- type: "theme.update",
- slug,
- options
- }), $[16] = send, $[17] = slug, $[18] = t5) : t5 = $[18];
- let t6;
- $[19] !== send || $[20] !== slug || $[21] !== theme.options ? (t6 = (palette, file) => send({
- type: "theme.update",
- slug,
- options: applyImagePalette(theme.options, palette),
- palette,
- imageUrl: URL.createObjectURL(file)
- }), $[19] = send, $[20] = slug, $[21] = theme.options, $[22] = t6) : t6 = $[22];
- let t7, t8;
- $[23] !== send || $[24] !== slug ? (t7 = () => send({
- type: "theme.remove",
- slug
- }), t8 = (title) => send({
- type: "theme.update",
- slug,
- title
- }), $[23] = send, $[24] = slug, $[25] = t7, $[26] = t8) : (t7 = $[25], t8 = $[26]);
- let t9;
- return $[27] !== applyVariant || $[28] !== focusTitle || $[29] !== mobile || $[30] !== split || $[31] !== t2 || $[32] !== t3 || $[33] !== t4 || $[34] !== t5 || $[35] !== t6 || $[36] !== t7 || $[37] !== t8 || $[38] !== theme.options || $[39] !== theme.palette || $[40] !== theme.title ? (t9 = /* @__PURE__ */ jsx(ThemeEditorForm, {
- focusTitle,
- imageUrl: t2,
- onDone: t3,
- onLucky: t4,
- onOptionsChange: t5,
- onPalette: t6,
- onRemove: t7,
- onTitleChange: t8,
- onVariant: applyVariant,
- options: theme.options,
- palette: theme.palette,
- split,
- mobile,
- title: theme.title
- }), $[27] = applyVariant, $[28] = focusTitle, $[29] = mobile, $[30] = split, $[31] = t2, $[32] = t3, $[33] = t4, $[34] = t5, $[35] = t6, $[36] = t7, $[37] = t8, $[38] = theme.options, $[39] = theme.palette, $[40] = theme.title, $[41] = t9) : t9 = $[41], t9;
-}
-function ThemeEditorForm(props) {
- let $ = c(50), { focusTitle, imageUrl, onDone, onLucky, onOptionsChange, onPalette, onRemove, onTitleChange, onVariant, options, palette, split, mobile, title } = props, studioScheme = useColorSchemeValue(), t0;
- $[0] === options ? t0 = $[1] : (t0 = resolveThemeOptions(options), $[0] = options, $[1] = t0);
- let resolved = t0, t1;
- $[2] === options ? t1 = $[3] : (t1 = buildPalette(options), $[2] = options, $[3] = t1);
- let palettes = t1, t2;
- $[4] !== onOptionsChange || $[5] !== options ? (t2 = (scheme, changes) => {
- let values = {
- ...options[scheme],
- ...changes
- };
- for (let key of SCHEME_OPTION_KEYS) values[key] === void 0 && delete values[key];
- let next = { ...options };
- Object.keys(values).length === 0 ? delete next[scheme] : next[scheme] = values, onOptionsChange(next);
- }, $[4] = onOptionsChange, $[5] = options, $[6] = t2) : t2 = $[6];
- let patchScheme = t2, t3;
- $[7] === options ? t3 = $[8] : (t3 = /* @__PURE__ */ jsx(ThemeThumbnail, { options }), $[7] = options, $[8] = t3);
- let t4;
- $[9] === Symbol.for("react.memo_cache_sentinel") ? (t4 = /* @__PURE__ */ jsx(Text, {
- size: 1,
- weight: "medium",
- children: "Title"
- }), $[9] = t4) : t4 = $[9];
- let t5;
- $[10] === onTitleChange ? t5 = $[11] : (t5 = (event) => onTitleChange(event.currentTarget.value), $[10] = onTitleChange, $[11] = t5);
- let t6 = focusTitle ? _temp$2 : void 0, t7;
- $[12] !== focusTitle || $[13] !== t5 || $[14] !== t6 || $[15] !== title ? (t7 = /* @__PURE__ */ jsxs(Stack, {
- gap: 2,
- children: [t4, /* @__PURE__ */ jsx(TextInput, {
- autoFocus: focusTitle,
- fontSize: 1,
- onChange: t5,
- onFocus: t6,
- padding: 2,
- placeholder: "Untitled theme",
- value: title
- })]
- }), $[12] = focusTitle, $[13] = t5, $[14] = t6, $[15] = title, $[16] = t7) : t7 = $[16];
- let t8;
- $[17] !== imageUrl || $[18] !== onLucky || $[19] !== onPalette || $[20] !== onVariant || $[21] !== options || $[22] !== palette ? (t8 = /* @__PURE__ */ jsx(ImagePaletteSection, {
- imageUrl,
- onLucky,
- onPalette,
- onVariant,
- options,
- palette
- }), $[17] = imageUrl, $[18] = onLucky, $[19] = onPalette, $[20] = onVariant, $[21] = options, $[22] = palette, $[23] = t8) : t8 = $[23];
- let t9;
- $[24] !== mobile || $[25] !== options || $[26] !== palettes || $[27] !== patchScheme || $[28] !== resolved || $[29] !== split || $[30] !== studioScheme ? (t9 = SCHEMES.map((scheme_0) => /* @__PURE__ */ jsx(SchemeCard, {
- active: split || scheme_0 === studioScheme,
- onChange: (changes_0) => patchScheme(scheme_0, changes_0),
- options: options[scheme_0] ?? {},
- palette: palettes[scheme_0],
- resolved: resolved[scheme_0],
- scheme: scheme_0,
- split,
- splitHint: splitHint(scheme_0 === studioScheme, mobile)
- }, scheme_0)), $[24] = mobile, $[25] = options, $[26] = palettes, $[27] = patchScheme, $[28] = resolved, $[29] = split, $[30] = studioScheme, $[31] = t9) : t9 = $[31];
- let t10;
- $[32] === t9 ? t10 = $[33] : (t10 = /* @__PURE__ */ jsx(ScrollAreaBleed, { children: t9 }), $[32] = t9, $[33] = t10);
- let t11;
- $[34] !== t10 || $[35] !== t3 || $[36] !== t7 || $[37] !== t8 ? (t11 = /* @__PURE__ */ jsx(ScrollArea, {
- padding: 3,
- children: /* @__PURE__ */ jsxs(Stack, {
- gap: 4,
- children: [
- t3,
- t7,
- t8,
- t10
- ]
- })
- }), $[34] = t10, $[35] = t3, $[36] = t7, $[37] = t8, $[38] = t11) : t11 = $[38];
- let t12;
- $[39] === onRemove ? t12 = $[40] : (t12 = /* @__PURE__ */ jsx(TooltipButton, {
- icon: TrashIcon,
- mode: "ghost",
- onClick: onRemove,
- text: "Remove",
- tone: "critical",
- tooltip: "Remove the theme — it can be restored until it is deleted"
- }), $[39] = onRemove, $[40] = t12);
- let t13;
- $[41] === Symbol.for("react.memo_cache_sentinel") ? (t13 = /* @__PURE__ */ jsx(Box, { flex: 1 }), $[41] = t13) : t13 = $[41];
- let t14;
- $[42] === onDone ? t14 = $[43] : (t14 = /* @__PURE__ */ jsx(Button, {
- mode: "ghost",
- onClick: onDone,
- padding: 2,
- text: "Done"
- }), $[42] = onDone, $[43] = t14);
- let t15;
- $[44] !== t12 || $[45] !== t14 ? (t15 = /* @__PURE__ */ jsx(Card, {
- borderTop: !0,
- padding: 3,
- children: /* @__PURE__ */ jsxs(Flex, {
- gap: 2,
- children: [
- t12,
- t13,
- t14
- ]
- })
- }), $[44] = t12, $[45] = t14, $[46] = t15) : t15 = $[46];
- let t16;
- return $[47] !== t11 || $[48] !== t15 ? (t16 = /* @__PURE__ */ jsxs(Fragment, { children: [t11, t15] }), $[47] = t11, $[48] = t15, $[49] = t16) : t16 = $[49], t16;
-}
-function _temp$2(event_0) {
- return event_0.currentTarget.select();
-}
-/**
-* The colors of one scheme. The cards span the sidebar edge to edge, one
-* after the other with a border between them, in the sidebar's own scheme —
-* the swatches show the colors they edit. The scheme the Studio is showing is
-* marked as active: its changes show up in the Studio right away, the other
-* scheme's only once the appearance setting switches to it — or both are
-* active, in the split preview.
-*/
-function SchemeCard(props) {
- let $ = c(66), { active, onChange, options, palette, resolved, scheme, split, splitHint } = props, name = SCHEME_TITLES[scheme], t0;
- $[0] === name ? t0 = $[1] : (t0 = /* @__PURE__ */ jsx(Box, {
- flex: 1,
- children: /* @__PURE__ */ jsx(Text, {
- size: 1,
- weight: "medium",
- children: name
- })
- }), $[0] = name, $[1] = t0);
- let t1;
- $[2] === active ? t1 = $[3] : (t1 = active && /* @__PURE__ */ jsx(Badge, {
- fontSize: 0,
- tone: "primary",
- children: "Active"
- }), $[2] = active, $[3] = t1);
- let t2;
- $[4] !== t0 || $[5] !== t1 ? (t2 = /* @__PURE__ */ jsxs(Flex, {
- align: "center",
- gap: 2,
- children: [t0, t1]
- }), $[4] = t0, $[5] = t1, $[6] = t2) : t2 = $[6];
- let t3 = split ? splitHint : active ? "Shown in the Studio right now" : `Shown once the Studio appearance is ${scheme}`, t4;
- $[7] === t3 ? t4 = $[8] : (t4 = /* @__PURE__ */ jsx(Text, {
- muted: !0,
- size: 0,
- children: t3
- }), $[7] = t3, $[8] = t4);
- let t5;
- $[9] !== t2 || $[10] !== t4 ? (t5 = /* @__PURE__ */ jsxs(Stack, {
- gap: 2,
- children: [t2, t4]
- }), $[9] = t2, $[10] = t4, $[11] = t5) : t5 = $[11];
- let t6 = options.accent === void 0, t7 = `${name} accent`, t8, t9;
- $[12] === onChange ? (t8 = $[13], t9 = $[14]) : (t8 = (accent) => onChange({ accent }), t9 = () => onChange({ accent: void 0 }), $[12] = onChange, $[13] = t8, $[14] = t9);
- let t10;
- $[15] !== resolved.accent || $[16] !== t6 || $[17] !== t7 || $[18] !== t8 || $[19] !== t9 ? (t10 = /* @__PURE__ */ jsx(ColorRow, {
- auto: t6,
- autoLabel: "default",
- label: t7,
- onChange: t8,
- onClear: t9,
- title: "Accent",
- value: resolved.accent
- }), $[15] = resolved.accent, $[16] = t6, $[17] = t7, $[18] = t8, $[19] = t9, $[20] = t10) : t10 = $[20];
- let t11 = options.text === void 0, t12 = `${name} text`, t13, t14;
- $[21] === onChange ? (t13 = $[22], t14 = $[23]) : (t13 = (text) => onChange({ text }), t14 = () => onChange({ text: void 0 }), $[21] = onChange, $[22] = t13, $[23] = t14);
- let t15;
- $[24] !== resolved.text || $[25] !== t11 || $[26] !== t12 || $[27] !== t13 || $[28] !== t14 ? (t15 = /* @__PURE__ */ jsx(ColorRow, {
- auto: t11,
- label: t12,
- onChange: t13,
- onClear: t14,
- title: "Text",
- value: resolved.text
- }), $[24] = resolved.text, $[25] = t11, $[26] = t12, $[27] = t13, $[28] = t14, $[29] = t15) : t15 = $[29];
- let t16 = scheme === "dark" ? palette.black : palette.white, t17 = options.background === void 0, t18 = `${name} background`, t19, t20;
- $[30] === onChange ? (t19 = $[31], t20 = $[32]) : (t19 = (background) => onChange({ background }), t20 = () => onChange({ background: void 0 }), $[30] = onChange, $[31] = t19, $[32] = t20);
- let t21;
- $[33] !== resolved.background || $[34] !== t16 || $[35] !== t17 || $[36] !== t18 || $[37] !== t19 || $[38] !== t20 ? (t21 = /* @__PURE__ */ jsx(ColorRow, {
- adjusted: t16,
- auto: t17,
- label: t18,
- onChange: t19,
- onClear: t20,
- title: "Background",
- value: resolved.background
- }), $[33] = resolved.background, $[34] = t16, $[35] = t17, $[36] = t18, $[37] = t19, $[38] = t20, $[39] = t21) : t21 = $[39];
- let t22;
- $[40] === Symbol.for("react.memo_cache_sentinel") ? (t22 = /* @__PURE__ */ jsx(Text, {
- size: 1,
- children: "Contrast"
- }), $[40] = t22) : t22 = $[40];
- let t23 = options.contrast === void 0 ? " · auto" : "", t24;
- $[41] !== resolved.contrast || $[42] !== t23 ? (t24 = /* @__PURE__ */ jsxs(Stack, {
- flex: 1,
- gap: 2,
- children: [t22, /* @__PURE__ */ jsxs(Text, {
- muted: !0,
- size: 0,
- children: [resolved.contrast, t23]
- })]
- }), $[41] = resolved.contrast, $[42] = t23, $[43] = t24) : t24 = $[43];
- let t25;
- $[44] !== onChange || $[45] !== options.contrast ? (t25 = options.contrast !== void 0 && /* @__PURE__ */ jsx(TooltipButton, {
- icon: ResetIcon,
- mode: "bleed",
- onClick: () => onChange({ contrast: void 0 }),
- padding: 2,
- tooltip: "Reset to auto"
- }), $[44] = onChange, $[45] = options.contrast, $[46] = t25) : t25 = $[46];
- let t26;
- $[47] !== t24 || $[48] !== t25 ? (t26 = /* @__PURE__ */ jsxs(Flex, {
- align: "center",
- gap: 2,
- children: [t24, t25]
- }), $[47] = t24, $[48] = t25, $[49] = t26) : t26 = $[49];
- let t27 = `${name} contrast`, t28;
- $[50] === onChange ? t28 = $[51] : (t28 = (event) => onChange({ contrast: Number(event.currentTarget.value) }), $[50] = onChange, $[51] = t28);
- let t29;
- $[52] !== resolved.contrast || $[53] !== t27 || $[54] !== t28 ? (t29 = /* @__PURE__ */ jsx("input", {
- "aria-label": t27,
- className: range,
- max: 100,
- min: 15,
- onChange: t28,
- step: 1,
- type: "range",
- value: resolved.contrast
- }), $[52] = resolved.contrast, $[53] = t27, $[54] = t28, $[55] = t29) : t29 = $[55];
- let t30;
- $[56] === Symbol.for("react.memo_cache_sentinel") ? (t30 = /* @__PURE__ */ jsx(Text, {
- muted: !0,
- size: 0,
- children: "100 keeps text and borders neutral — lower values blend in the accent"
- }), $[56] = t30) : t30 = $[56];
- let t31;
- $[57] !== t26 || $[58] !== t29 ? (t31 = /* @__PURE__ */ jsxs(Stack, {
- gap: 3,
- children: [
- t26,
- t29,
- t30
- ]
- }), $[57] = t26, $[58] = t29, $[59] = t31) : t31 = $[59];
- let t32;
- return $[60] !== t10 || $[61] !== t15 || $[62] !== t21 || $[63] !== t31 || $[64] !== t5 ? (t32 = /* @__PURE__ */ jsx(Card, {
- borderTop: !0,
- padding: 3,
- children: /* @__PURE__ */ jsxs(Stack, {
- gap: 4,
- children: [
- t5,
- t10,
- t15,
- t21,
- t31
- ]
- })
- }), $[60] = t10, $[61] = t15, $[62] = t21, $[63] = t31, $[64] = t5, $[65] = t32) : t32 = $[65], t32;
-}
-/** One color of a scheme: a swatch with its value and an optional reset button */
-function ColorRow(props) {
- let $ = c(23), { adjusted, auto, autoLabel: t0, label, onChange, onClear, title, value } = props, autoLabel = t0 === void 0 ? "auto" : t0, t1;
- $[0] === onChange ? t1 = $[1] : (t1 = (event) => onChange(event.currentTarget.value), $[0] = onChange, $[1] = t1);
- let t2;
- $[2] !== label || $[3] !== t1 || $[4] !== value ? (t2 = /* @__PURE__ */ jsx("input", {
- "aria-label": label,
- className: swatch,
- onChange: t1,
- type: "color",
- value
- }), $[2] = label, $[3] = t1, $[4] = value, $[5] = t2) : t2 = $[5];
- let t3;
- $[6] === title ? t3 = $[7] : (t3 = /* @__PURE__ */ jsx(Text, {
- size: 1,
- children: title
- }), $[6] = title, $[7] = t3);
- let t4 = adjusted !== void 0 && adjusted !== value ? ` → ${adjusted}` : "", t5 = auto ? ` · ${autoLabel}` : "", t6;
- $[8] !== t4 || $[9] !== t5 || $[10] !== value ? (t6 = /* @__PURE__ */ jsxs(Text, {
- muted: !0,
- size: 0,
- textOverflow: "ellipsis",
- children: [
- value,
- t4,
- t5
- ]
- }), $[8] = t4, $[9] = t5, $[10] = value, $[11] = t6) : t6 = $[11];
- let t7;
- $[12] !== t3 || $[13] !== t6 ? (t7 = /* @__PURE__ */ jsxs(Stack, {
- className: colorRowText,
- flex: 1,
- gap: 2,
- children: [t3, t6]
- }), $[12] = t3, $[13] = t6, $[14] = t7) : t7 = $[14];
- let t8;
- $[15] !== auto || $[16] !== autoLabel || $[17] !== onClear ? (t8 = onClear && !auto && /* @__PURE__ */ jsx(TooltipButton, {
- icon: ResetIcon,
- mode: "bleed",
- onClick: onClear,
- padding: 2,
- tooltip: `Reset to ${autoLabel}`
- }), $[15] = auto, $[16] = autoLabel, $[17] = onClear, $[18] = t8) : t8 = $[18];
- let t9;
- return $[19] !== t2 || $[20] !== t7 || $[21] !== t8 ? (t9 = /* @__PURE__ */ jsxs(Flex, {
- align: "center",
- gap: 2,
- children: [
- t2,
- t7,
- t8
- ]
- }), $[19] = t2, $[20] = t7, $[21] = t8, $[22] = t9) : t9 = $[22], t9;
-}
-/**
-* The version of the code format, the first byte of every code — bumped if
-* the layout below ever changes, so older codes can still be told apart
-*/
-const FIELDS = [
- "accent",
- "text",
- "background",
- "contrast"
-];
-/**
-* Turns a theme into a short code to share in a message: `title`, and the
-* colors and contrasts of both schemes, packed into bytes — one flag byte says
-* which of the eight fields are set, each color is its three RGB bytes and a
-* contrast one byte, and the title takes up the rest — then base64url'd, so
-* it is one word without padding, safe in URLs and chat. A theme setting
-* everything comes to about 30 bytes plus its title.
-*
-* @internal
-*/
-function encodeTheme(theme) {
- let bytes = [1, 0], flags = 0;
- return SCHEMES.forEach((scheme, schemeIndex) => {
- let options = theme.options[scheme] ?? {};
- FIELDS.forEach((field, fieldIndex) => {
- let value = options[field];
- if (value !== void 0) {
- if (field === "contrast") {
- if (typeof value != "number" || !Number.isFinite(value)) return;
- bytes.push(Math.round(Math.min(100, Math.max(15, value))));
- } else {
- if (typeof value != "string" || !isColor(value)) return;
- bytes.push(...rgbBytes(value));
- }
- flags |= 1 << schemeIndex * FIELDS.length + fieldIndex;
- }
- });
- }), bytes[1] = flags, bytes.push(...new TextEncoder().encode(theme.title.trim())), toBase64Url(Uint8Array.from(bytes));
-}
-/**
-* Reads a theme back out of a code — as pasted, so surrounding whitespace and
-* words around the code are fine: the first word that is a code counts. `null`
-* when nothing in the text is one.
-*
-* @internal
-*/
-function decodeTheme(text) {
- for (let word of text.trim().split(/\s+/)) {
- let theme = decodeCode(word);
- if (theme) return theme;
- }
- return null;
-}
-function decodeCode(code) {
- let bytes = fromBase64Url(code);
- if (!bytes || bytes.length < 2 || bytes[0] !== 1) return null;
- let flags = bytes[1], options = {}, offset = 2;
- for (let [schemeIndex, scheme] of SCHEMES.entries()) {
- let schemeOptions = {};
- for (let [fieldIndex, field] of FIELDS.entries()) if (flags & 1 << schemeIndex * FIELDS.length + fieldIndex) {
- if (field === "contrast") {
- if (offset + 1 > bytes.length) return null;
- schemeOptions.contrast = Math.min(100, Math.max(15, bytes[offset])), offset += 1;
- } else {
- if (offset + 3 > bytes.length) return null;
- schemeOptions[field] = hexColor(bytes.subarray(offset, offset + 3)), offset += 3;
- }
- }
- Object.keys(schemeOptions).length > 0 && (options[scheme] = schemeOptions);
- }
- let title;
- try {
- title = new TextDecoder("utf-8", { fatal: !0 }).decode(bytes.subarray(offset));
- } catch {
- return null;
- }
- return {
- title: displayTitle(title),
- options
- };
-}
-/** The three RGB bytes of a `#rgb` or `#rrggbb` color */
-function rgbBytes(color) {
- let hex = color.length === 4 ? color.slice(1).replaceAll(/./g, "$&$&") : color.slice(1);
- return [
- 0,
- 2,
- 4
- ].map((start) => parseInt(hex.slice(start, start + 2), 16));
-}
-function hexColor(rgb) {
- return `#${[...rgb].map((byte) => byte.toString(16).padStart(2, "0")).join("")}`;
-}
-function toBase64Url(bytes) {
- let binary = "";
- for (let byte of bytes) binary += String.fromCharCode(byte);
- return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
-}
-function fromBase64Url(code) {
- if (!/^[A-Za-z0-9_-]+$/.test(code)) return null;
- let base64 = code.replaceAll("-", "+").replaceAll("_", "/");
- try {
- return Uint8Array.from(atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, "=")), (char) => char.charCodeAt(0));
- } catch {
- return null;
- }
-}
-/**
-* Copying a theme as a code to share, and adding a theme from a code someone
-* shared — with toasts telling how it went.
-*
-* @internal
-*/
-function useThemeCodes() {
- let $ = c(11), { send } = useThemer(), toast = useToast(), t0;
- $[0] === toast ? t0 = $[1] : (t0 = async (theme) => {
- let title = displayTitle(theme.title);
- try {
- await navigator.clipboard.writeText(encodeTheme(theme)), toast.push({
- status: "success",
- title: `Copied ${title} as a code`,
- description: "Paste it in the themer of another Studio to add the theme there"
- });
- } catch {
- toast.push({
- status: "error",
- title: `Could not copy ${title}`
- });
- }
- }, $[0] = toast, $[1] = t0);
- let copyTheme = t0, t1;
- $[2] !== send || $[3] !== toast ? (t1 = (text) => {
- let theme_0 = decodeTheme(text);
- return theme_0 ? (send({
- type: "theme.import",
- title: theme_0.title,
- options: theme_0.options
- }), toast.push({
- status: "success",
- title: `Added ${theme_0.title}`
- }), !0) : !1;
- }, $[2] = send, $[3] = toast, $[4] = t1) : t1 = $[4];
- let addThemeFromText = t1, t2;
- $[5] === addThemeFromText ? t2 = $[6] : (t2 = async () => {
- let text_0;
- try {
- text_0 = await navigator.clipboard.readText();
- } catch {
- return "no-clipboard";
- }
- return addThemeFromText(text_0) ? "added" : "no-theme";
- }, $[5] = addThemeFromText, $[6] = t2);
- let addThemeFromClipboard = t2, t3;
- return $[7] !== addThemeFromClipboard || $[8] !== addThemeFromText || $[9] !== copyTheme ? (t3 = {
- copyTheme,
- addThemeFromText,
- addThemeFromClipboard
- }, $[7] = addThemeFromClipboard, $[8] = addThemeFromText, $[9] = copyTheme, $[10] = t3) : t3 = $[10], t3;
-}
-/**
-* Adds a theme pasted anywhere in the Studio while the themer's list is
-* showing — pastes into inputs and other editable things are theirs.
-*
-* @internal
-*/
-function usePasteThemeCodes() {
- let $ = c(5), { open, send } = useThemer(), toast = useToast(), t0, t1;
- $[0] !== open || $[1] !== send || $[2] !== toast ? (t0 = () => {
- if (!open) return;
- let handlePaste = (event) => {
- if (isEditable(event.target)) return;
- let theme = decodeTheme(event.clipboardData?.getData("text/plain") ?? "");
- theme && (event.preventDefault(), send({
- type: "theme.import",
- title: theme.title,
- options: theme.options
- }), toast.push({
- status: "success",
- title: `Added ${theme.title}`
- }));
- };
- return document.addEventListener("paste", handlePaste), () => document.removeEventListener("paste", handlePaste);
- }, t1 = [
- open,
- send,
- toast
- ], $[0] = open, $[1] = send, $[2] = toast, $[3] = t0, $[4] = t1) : (t0 = $[3], t1 = $[4]), useEffect(t0, t1);
-}
-function isEditable(target) {
- return target instanceof HTMLElement && (target.isContentEditable || target.matches("input, textarea, select"));
-}
-/**
-* Where a theme code someone shared gets pasted by hand — for browsers that
-* do not hand the clipboard over, and for codes that are not on it.
-*
-* @internal
-*/
-function PasteThemeDialog(props) {
- let $ = c(35), { onClose } = props, { addThemeFromText } = useThemeCodes(), [text, setText] = useState(""), [invalid, setInvalid] = useState(!1), t0;
- $[0] !== addThemeFromText || $[1] !== onClose || $[2] !== text ? (t0 = () => {
- addThemeFromText(text) ? onClose() : setInvalid(!0);
- }, $[0] = addThemeFromText, $[1] = onClose, $[2] = text, $[3] = t0) : t0 = $[3];
- let add = t0, t1;
- $[4] === onClose ? t1 = $[5] : (t1 = /* @__PURE__ */ jsx(Button, {
- mode: "ghost",
- onClick: onClose,
- padding: 2,
- text: "Cancel"
- }), $[4] = onClose, $[5] = t1);
- let t2;
- $[6] === text ? t2 = $[7] : (t2 = text.trim(), $[6] = text, $[7] = t2);
- let t3 = t2 === "", t4;
- $[8] !== add || $[9] !== t3 ? (t4 = /* @__PURE__ */ jsx(Button, {
- disabled: t3,
- onClick: add,
- padding: 2,
- text: "Add theme",
- tone: "primary"
- }), $[8] = add, $[9] = t3, $[10] = t4) : t4 = $[10];
- let t5;
- $[11] !== t1 || $[12] !== t4 ? (t5 = /* @__PURE__ */ jsxs(Flex, {
- gap: 2,
- justify: "flex-end",
- padding: 3,
- children: [t1, t4]
- }), $[11] = t1, $[12] = t4, $[13] = t5) : t5 = $[13];
- let t6;
- $[14] === add ? t6 = $[15] : (t6 = (event) => {
- event.preventDefault(), add();
- }, $[14] = add, $[15] = t6);
- let t7;
- $[16] === Symbol.for("react.memo_cache_sentinel") ? (t7 = /* @__PURE__ */ jsx(Text, {
- muted: !0,
- size: 1,
- children: "Paste the code someone copied from their themer — the theme is added to your list and applied."
- }), $[16] = t7) : t7 = $[16];
- let t8 = invalid ? "themer-paste-error" : void 0, t9 = invalid ? "That is not a theme code" : void 0, t10;
- $[17] === Symbol.for("react.memo_cache_sentinel") ? (t10 = (event_0) => {
- setText(event_0.currentTarget.value), setInvalid(!1);
- }, $[17] = t10) : t10 = $[17];
- let t11;
- $[18] !== invalid || $[19] !== t8 || $[20] !== t9 || $[21] !== text ? (t11 = /* @__PURE__ */ jsx(TextInput, {
- "aria-describedby": t8,
- "aria-invalid": invalid,
- "aria-label": "Theme code",
- autoFocus: !0,
- customValidity: t9,
- fontSize: 1,
- onChange: t10,
- placeholder: "AQ…",
- value: text
- }), $[18] = invalid, $[19] = t8, $[20] = t9, $[21] = text, $[22] = t11) : t11 = $[22];
- let t12;
- $[23] === invalid ? t12 = $[24] : (t12 = invalid && /* @__PURE__ */ jsx(Card, {
- id: "themer-paste-error",
- padding: 3,
- radius: 2,
- role: "alert",
- tone: "critical",
- children: /* @__PURE__ */ jsx(Text, {
- size: 1,
- children: "That is not a theme code — codes are one word, copied from a theme's menu."
- })
- }), $[23] = invalid, $[24] = t12);
- let t13;
- $[25] !== t11 || $[26] !== t12 ? (t13 = /* @__PURE__ */ jsxs(Stack, {
- gap: 3,
- padding: 4,
- children: [
- t7,
- t11,
- t12
- ]
- }), $[25] = t11, $[26] = t12, $[27] = t13) : t13 = $[27];
- let t14;
- $[28] !== t13 || $[29] !== t6 ? (t14 = /* @__PURE__ */ jsx("form", {
- onSubmit: t6,
- children: t13
- }), $[28] = t13, $[29] = t6, $[30] = t14) : t14 = $[30];
- let t15;
- return $[31] !== onClose || $[32] !== t14 || $[33] !== t5 ? (t15 = /* @__PURE__ */ jsx(Dialog, {
- animate: !0,
- footer: t5,
- header: "Add a shared theme",
- id: "themer-paste",
- onClickOutside: onClose,
- onClose,
- width: 0,
- children: t14
- }), $[31] = onClose, $[32] = t14, $[33] = t5, $[34] = t15) : t15 = $[34], t15;
-}
-var frame$1 = "_1wsn7882", menuCard = "_1wsn7884", menuSlot = "_1wsn7883", pickButton = "_1wsn7881", root = "_1wsn7880";
-/**
-* Scrolls the applied theme's card into view when it is not already, as a
-* ref: the list scrolls to it as it mounts — coming back from the editor or
-* the removed themes — and when another theme gets applied
-*/
-function scrollRefIntoViewIfNeeded(node) {
- node && scrollIntoView(node, {
- block: "nearest",
- scrollMode: "if-needed"
- });
-}
-/**
-* One theme in the list: the floating preview with the title below it, like
-* an appearance option in macOS System Settings. Clicking it applies the
-* theme to the whole Studio, dragging it moves the theme to another place in
-* the list; its menu holds the move, edit, duplicate and remove flows that
-* apply to the theme.
-*
-* @internal
-*/
-function ThemeCard(props) {
- let $ = c(85), { active, theme } = props, { themes, send } = useThemer(), { copyTheme } = useThemeCodes(), { scheme } = useRootTheme(), [menuOpen, setMenuOpen] = useState(!1), dragControls = useDragControls(), dragged = useRef(!1), t0;
- $[0] === theme.title ? t0 = $[1] : (t0 = displayTitle(theme.title), $[0] = theme.title, $[1] = t0);
- let title = t0, t1;
- $[2] === theme.slug ? t1 = $[3] : (t1 = (candidate) => candidate.slug === theme.slug, $[2] = theme.slug, $[3] = t1);
- let index = themes.findIndex(t1), t2;
- $[4] !== index || $[5] !== send || $[6] !== themes ? (t2 = (to) => {
- let order = themes.map(_temp$1);
- order.splice(to, 0, ...order.splice(index, 1)), send({
- type: "theme.reorder",
- order
- });
- }, $[4] = index, $[5] = send, $[6] = themes, $[7] = t2) : t2 = $[7];
- let moveTo = t2, t3, t4;
- $[8] === Symbol.for("react.memo_cache_sentinel") ? (t3 = () => {
- requestAnimationFrame(() => {
- dragged.current = !1;
- });
- }, t4 = () => {
- dragged.current = !0;
- }, $[8] = t3, $[9] = t4) : (t3 = $[8], t4 = $[9]);
- let t5 = active ? scrollRefIntoViewIfNeeded : void 0, t6;
- $[10] === Symbol.for("react.memo_cache_sentinel") ? (t6 = { scale: 1.04 }, $[10] = t6) : t6 = $[10];
- let t7;
- $[11] !== send || $[12] !== theme.slug ? (t7 = () => {
- dragged.current || send({
- type: "theme.pick",
- slug: theme.slug
- });
- }, $[11] = send, $[12] = theme.slug, $[13] = t7) : t7 = $[13];
- let t8;
- $[14] === dragControls ? t8 = $[15] : (t8 = (event) => {
- event.pointerType !== "touch" && dragControls.start(event);
- }, $[14] = dragControls, $[15] = t8);
- let t9;
- $[16] === theme.options ? t9 = $[17] : (t9 = /* @__PURE__ */ jsx("span", {
- className: frame$1,
- children: /* @__PURE__ */ jsx(ThemeThumbnail, { options: theme.options })
- }), $[16] = theme.options, $[17] = t9);
- let t10 = active ? "medium" : "regular", t11;
- $[18] !== t10 || $[19] !== title ? (t11 = /* @__PURE__ */ jsx(Box, {
- as: "span",
- display: "block",
- paddingTop: 2,
- paddingX: 2,
- children: /* @__PURE__ */ jsx(Text, {
- align: "center",
- as: "span",
- size: 1,
- textOverflow: "ellipsis",
- weight: t10,
- children: title
- })
- }), $[18] = t10, $[19] = title, $[20] = t11) : t11 = $[20];
- let t12;
- $[21] !== active || $[22] !== t11 || $[23] !== t7 || $[24] !== t8 || $[25] !== t9 ? (t12 = /* @__PURE__ */ jsxs("button", {
- "aria-pressed": active,
- className: pickButton,
- onClick: t7,
- onPointerDown: t8,
- type: "button",
- children: [t9, t11]
- }), $[21] = active, $[22] = t11, $[23] = t7, $[24] = t8, $[25] = t9, $[26] = t12) : t12 = $[26];
- let t13;
- $[27] === Symbol.for("react.memo_cache_sentinel") ? (t13 = /* @__PURE__ */ jsx(Text, {
- size: 1,
- children: "Show more"
- }), $[27] = t13) : t13 = $[27];
- let t14 = `Show more for ${title}`, t15;
- $[28] === t14 ? t15 = $[29] : (t15 = /* @__PURE__ */ jsx(Button, {
- "aria-label": t14,
- fontSize: 1,
- icon: EllipsisHorizontalIcon,
- mode: "ghost",
- padding: 1,
- radius: 2
- }), $[28] = t14, $[29] = t15);
- let t16 = `themer-theme-${theme.slug}`, t17 = index <= 0, t18;
- $[30] !== index || $[31] !== moveTo ? (t18 = () => moveTo(index - 1), $[30] = index, $[31] = moveTo, $[32] = t18) : t18 = $[32];
- let t19;
- $[33] !== t17 || $[34] !== t18 ? (t19 = /* @__PURE__ */ jsx(MenuItem, {
- disabled: t17,
- icon: ArrowUpIcon,
- onClick: t18,
- text: "Move up"
- }), $[33] = t17, $[34] = t18, $[35] = t19) : t19 = $[35];
- let t20 = index >= themes.length - 1, t21;
- $[36] !== index || $[37] !== moveTo ? (t21 = () => moveTo(index + 1), $[36] = index, $[37] = moveTo, $[38] = t21) : t21 = $[38];
- let t22;
- $[39] !== t20 || $[40] !== t21 ? (t22 = /* @__PURE__ */ jsx(MenuItem, {
- disabled: t20,
- icon: ArrowDownIcon,
- onClick: t21,
- text: "Move down"
- }), $[39] = t20, $[40] = t21, $[41] = t22) : t22 = $[41];
- let t23;
- $[42] === Symbol.for("react.memo_cache_sentinel") ? (t23 = /* @__PURE__ */ jsx(MenuDivider, {}), $[42] = t23) : t23 = $[42];
- let t24;
- $[43] !== send || $[44] !== theme.slug || $[45] !== theme.source ? (t24 = theme.source === "custom" && /* @__PURE__ */ jsx(MenuItem, {
- icon: EditIcon,
- onClick: () => send({
- type: "theme.edit",
- slug: theme.slug
- }),
- text: "Edit"
- }), $[43] = send, $[44] = theme.slug, $[45] = theme.source, $[46] = t24) : t24 = $[46];
- let t25;
- $[47] !== send || $[48] !== theme.slug ? (t25 = () => send({
- type: "theme.duplicate",
- slug: theme.slug
- }), $[47] = send, $[48] = theme.slug, $[49] = t25) : t25 = $[49];
- let t26 = theme.source === "custom" ? "Duplicate" : "Duplicate to edit", t27;
- $[50] !== t25 || $[51] !== t26 ? (t27 = /* @__PURE__ */ jsx(MenuItem, {
- icon: CopyIcon,
- onClick: t25,
- text: t26
- }), $[50] = t25, $[51] = t26, $[52] = t27) : t27 = $[52];
- let t28;
- $[53] !== copyTheme || $[54] !== theme ? (t28 = /* @__PURE__ */ jsx(MenuItem, {
- icon: ShareIcon,
- onClick: () => void copyTheme(theme),
- text: "Copy to share"
- }), $[53] = copyTheme, $[54] = theme, $[55] = t28) : t28 = $[55];
- let t29;
- $[56] !== send || $[57] !== theme.slug || $[58] !== theme.source ? (t29 = theme.source !== "config" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(MenuDivider, {}), /* @__PURE__ */ jsx(MenuItem, {
- icon: TrashIcon,
- onClick: () => send({
- type: "theme.remove",
- slug: theme.slug
- }),
- text: "Remove",
- tone: "critical"
- })] }), $[56] = send, $[57] = theme.slug, $[58] = theme.source, $[59] = t29) : t29 = $[59];
- let t30;
- $[60] !== t19 || $[61] !== t22 || $[62] !== t24 || $[63] !== t27 || $[64] !== t28 || $[65] !== t29 ? (t30 = /* @__PURE__ */ jsxs(Menu, { children: [
- t19,
- t22,
- t23,
- t24,
- t27,
- t28,
- t29
- ] }), $[60] = t19, $[61] = t22, $[62] = t24, $[63] = t27, $[64] = t28, $[65] = t29, $[66] = t30) : t30 = $[66];
- let t31, t32;
- $[67] === Symbol.for("react.memo_cache_sentinel") ? (t31 = () => setMenuOpen(!1), t32 = () => setMenuOpen(!0), $[67] = t31, $[68] = t32) : (t31 = $[67], t32 = $[68]);
- let t33;
- $[69] === scheme ? t33 = $[70] : (t33 = {
- animate: !0,
- placement: "bottom-end",
- portal: !0,
- scheme
- }, $[69] = scheme, $[70] = t33);
- let t34;
- $[71] !== t15 || $[72] !== t16 || $[73] !== t30 || $[74] !== t33 ? (t34 = /* @__PURE__ */ jsx(Tooltip, {
- animate: !0,
- content: t13,
- placement: "bottom",
- portal: !0,
- children: /* @__PURE__ */ jsx(Card, {
- className: menuCard,
- radius: 2,
- scheme: "dark",
- children: /* @__PURE__ */ jsx(MenuButton, {
- button: t15,
- id: t16,
- menu: t30,
- onClose: t31,
- onOpen: t32,
- popover: t33
- })
- })
- }), $[71] = t15, $[72] = t16, $[73] = t30, $[74] = t33, $[75] = t34) : t34 = $[75];
- let t35;
- $[76] !== menuOpen || $[77] !== t34 ? (t35 = /* @__PURE__ */ jsx("div", {
- className: menuSlot,
- "data-visible": menuOpen,
- children: t34
- }), $[76] = menuOpen, $[77] = t34, $[78] = t35) : t35 = $[78];
- let t36;
- return $[79] !== dragControls || $[80] !== t12 || $[81] !== t35 || $[82] !== t5 || $[83] !== theme.slug ? (t36 = /* @__PURE__ */ jsxs(Reorder.Item, {
- as: "div",
- className: root,
- dragControls,
- dragListener: !1,
- onDragEnd: t3,
- onDragStart: t4,
- ref: t5,
- value: theme.slug,
- whileDrag: t6,
- children: [t12, t35]
- }), $[79] = dragControls, $[80] = t12, $[81] = t35, $[82] = t5, $[83] = theme.slug, $[84] = t36) : t36 = $[84], t36;
-}
-function _temp$1(candidate_0) {
- return candidate_0.slug;
-}
-var cardGrid = "twjqgh0";
-/**
-* One column at the sidebar's default width; wider sidebars — and the
-* overlay on small screens — fit more cards per row
-*/
-/**
-* The flow for picking a theme: a grid of theme cards — the configured theme,
-* the presets and the user's own themes — that drag into the order the user
-* wants, with the entry points to the add and restore flows below. A theme
-* code someone shared pastes right into the list, or through the paste button.
-*
-* @internal
-*/
-function ThemeList() {
- let $ = c(38), { themes, removed, active, send } = useThemer(), { addThemeFromClipboard } = useThemeCodes(), [pasting, setPasting] = useState(!1);
- usePasteThemeCodes();
- let t0;
- $[0] === send ? t0 = $[1] : (t0 = (palette, file) => send({
- type: "theme.add",
- title: titleFromFileName(file.name),
- options: optionsFromImagePalette(palette),
- palette,
- imageUrl: URL.createObjectURL(file)
- }), $[0] = send, $[1] = t0);
- let { busy, pickImage } = useImagePalette(t0), t1;
- $[2] === send ? t1 = $[3] : (t1 = (order) => send({
- type: "theme.reorder",
- order
- }), $[2] = send, $[3] = t1);
- let t2;
- $[4] === themes ? t2 = $[5] : (t2 = themes.map(_temp), $[4] = themes, $[5] = t2);
- let t3;
- if ($[6] !== active || $[7] !== themes) {
- let t4;
- $[9] === active ? t4 = $[10] : (t4 = (theme_0) => /* @__PURE__ */ jsx(ThemeCard, {
- active: theme_0.slug === active.slug,
- theme: theme_0
- }, theme_0.slug), $[9] = active, $[10] = t4), t3 = themes.map(t4), $[6] = active, $[7] = themes, $[8] = t3;
- } else t3 = $[8];
- let t4;
- $[11] !== t1 || $[12] !== t2 || $[13] !== t3 ? (t4 = /* @__PURE__ */ jsx(MotionConfig, {
- reducedMotion: "user",
- children: /* @__PURE__ */ jsx(Reorder.Group, {
- as: "div",
- className: cardGrid,
- onReorder: t1,
- values: t2,
- children: t3
- })
- }), $[11] = t1, $[12] = t2, $[13] = t3, $[14] = t4) : t4 = $[14];
- let t5;
- $[15] !== removed.length || $[16] !== send ? (t5 = removed.length > 0 && /* @__PURE__ */ jsx(Button, {
- gap: 2,
- icon: RestoreIcon,
- mode: "bleed",
- onClick: () => send({ type: "flow.removed" }),
- padding: 2,
- text: `Show removed (${removed.length})`,
- width: "fill"
- }), $[15] = removed.length, $[16] = send, $[17] = t5) : t5 = $[17];
- let t6;
- $[18] !== t4 || $[19] !== t5 ? (t6 = /* @__PURE__ */ jsx(ScrollArea, {
- padding: 3,
- children: /* @__PURE__ */ jsxs(Stack, {
- gap: 4,
- children: [t4, t5]
- })
- }), $[18] = t4, $[19] = t5, $[20] = t6) : t6 = $[20];
- let t7;
- $[21] === send ? t7 = $[22] : (t7 = /* @__PURE__ */ jsx(Box, {
- flex: 1,
- children: /* @__PURE__ */ jsx(TooltipButton, {
- icon: AddIcon,
- mode: "ghost",
- onClick: () => send({ type: "theme.add" }),
- text: "Add theme",
- tooltip: "Add a theme based on the applied one",
- width: "fill"
- })
- }), $[21] = send, $[22] = t7);
- let t8;
- $[23] !== busy || $[24] !== pickImage ? (t8 = /* @__PURE__ */ jsx(ImageFileButton, {
- loading: busy,
- mode: "ghost",
- onFile: pickImage,
- tooltip: "Add a theme from the colors of an image"
- }), $[23] = busy, $[24] = pickImage, $[25] = t8) : t8 = $[25];
- let t9;
- $[26] === addThemeFromClipboard ? t9 = $[27] : (t9 = /* @__PURE__ */ jsx(TooltipButton, {
- icon: ClipboardIcon,
- mode: "ghost",
- onClick: async () => {
- await addThemeFromClipboard() !== "added" && setPasting(!0);
- },
- tooltip: "Add a theme from a code someone shared"
- }), $[26] = addThemeFromClipboard, $[27] = t9);
- let t10;
- $[28] !== t7 || $[29] !== t8 || $[30] !== t9 ? (t10 = /* @__PURE__ */ jsx(Card, {
- borderTop: !0,
- padding: 3,
- children: /* @__PURE__ */ jsxs(Flex, {
- gap: 2,
- children: [
- t7,
- t8,
- t9
- ]
- })
- }), $[28] = t7, $[29] = t8, $[30] = t9, $[31] = t10) : t10 = $[31];
- let t11;
- $[32] === pasting ? t11 = $[33] : (t11 = pasting && /* @__PURE__ */ jsx(PasteThemeDialog, { onClose: () => setPasting(!1) }), $[32] = pasting, $[33] = t11);
- let t12;
- return $[34] !== t10 || $[35] !== t11 || $[36] !== t6 ? (t12 = /* @__PURE__ */ jsxs(Fragment, { children: [
- t6,
- t10,
- t11
- ] }), $[34] = t10, $[35] = t11, $[36] = t6, $[37] = t12) : t12 = $[37], t12;
-}
-function _temp(theme) {
- return theme.slug;
-}
-/**
-* Serializes theme options into the `buildTheme` call to paste into
-* `sanity.config.ts`, keeping only what differs from the derived defaults in
-* each scheme.
-*
-* Options that boil down to the stock Studio theme need nothing from this
-* package — so they serialize to a bare `buildTheme()` from `@sanity/ui/theme`
-* instead.
-*
-* @internal
-*/
-function createThemeSnippet(options) {
- let minimized = minimizeOptions(options);
- if (minimized === null) return "import {buildTheme} from '@sanity/ui/theme'\n\nexport const theme = buildTheme()\n";
- let lines = [];
- for (let scheme of SCHEMES) {
- let values = minimized[scheme];
- values && lines.push(serializeScheme(scheme, values));
- }
- return `import {buildTheme} from '@sanity/themer'\n\nexport const theme = buildTheme({\n${lines.join("\n")}\n})\n`;
-}
-/** A scheme with up to two options fits on one line, more spread out */
-function serializeScheme(scheme, values) {
- let entries = [];
- return values.accent !== void 0 && entries.push(`accent: '${values.accent}'`), values.text !== void 0 && entries.push(`text: '${values.text}'`), values.background !== void 0 && entries.push(`background: '${values.background}'`), values.contrast !== void 0 && entries.push(`contrast: ${values.contrast}`), entries.length <= 2 ? ` ${scheme}: {${entries.join(", ")}},` : ` ${scheme}: {\n${entries.map((entry) => ` ${entry},`).join("\n")}\n },`;
-}
-registerLanguage(typescript);
-/**
-* Shows the `buildTheme` snippet that makes a theme permanent, in a dialog so
-* that it does not take up sidebar space or make the sidebar scroll as the
-* snippet changes shape with the theme.
-*
-* @internal
-*/
-function ThemeSnippetDialog(props) {
- let $ = c(23), { onClose, theme } = props, toast = useToast(), t0;
- $[0] === theme.options ? t0 = $[1] : (t0 = createThemeSnippet(theme.options), $[0] = theme.options, $[1] = t0);
- let snippet = t0, t1;
- $[2] !== snippet || $[3] !== toast ? (t1 = async () => {
- try {
- await navigator.clipboard.writeText(snippet), toast.push({
- status: "success",
- title: "Copied the theme to the clipboard"
- });
- } catch {
- toast.push({
- status: "error",
- title: "Could not copy the theme"
- });
- }
- }, $[2] = snippet, $[3] = toast, $[4] = t1) : t1 = $[4];
- let handleCopy = t1, t2;
- $[5] === handleCopy ? t2 = $[6] : (t2 = /* @__PURE__ */ jsx(Flex, {
- gap: 2,
- justify: "flex-end",
- padding: 3,
- children: /* @__PURE__ */ jsx(Button, {
- gap: 2,
- icon: ClipboardIcon,
- mode: "ghost",
- onClick: () => void handleCopy(),
- padding: 2,
- text: "Copy"
- })
- }), $[5] = handleCopy, $[6] = t2);
- let t3;
- $[7] === Symbol.for("react.memo_cache_sentinel") ? (t3 = /* @__PURE__ */ jsx("code", { children: "sanity.config.ts" }), $[7] = t3) : t3 = $[7];
- let t4;
- $[8] === Symbol.for("react.memo_cache_sentinel") ? (t4 = /* @__PURE__ */ jsx("code", { children: "theme" }), $[8] = t4) : t4 = $[8];
- let t5;
- $[9] === Symbol.for("react.memo_cache_sentinel") ? (t5 = /* @__PURE__ */ jsx("code", { children: "defineConfig" }), $[9] = t5) : t5 = $[9];
- let t6;
- $[10] === theme.title ? t6 = $[11] : (t6 = displayTitle(theme.title), $[10] = theme.title, $[11] = t6);
- let t7;
- $[12] === t6 ? t7 = $[13] : (t7 = /* @__PURE__ */ jsxs(Text, {
- muted: !0,
- size: 1,
- children: [
- "Export this from ",
- t3,
- " and pass it as the ",
- t4,
- " of",
- " ",
- t5,
- " to make “",
- t6,
- "” the Studio theme without this tool."
- ]
- }), $[12] = t6, $[13] = t7);
- let t8;
- $[14] === snippet ? t8 = $[15] : (t8 = /* @__PURE__ */ jsx(Card, {
- border: !0,
- overflow: "auto",
- padding: 3,
- radius: 2,
- tone: "transparent",
- children: /* @__PURE__ */ jsx(Code, {
- language: "ts",
- size: 1,
- children: snippet
- })
- }), $[14] = snippet, $[15] = t8);
- let t9;
- $[16] !== t7 || $[17] !== t8 ? (t9 = /* @__PURE__ */ jsx(Box, {
- padding: 4,
- children: /* @__PURE__ */ jsxs(Stack, {
- gap: 4,
- children: [t7, t8]
- })
- }), $[16] = t7, $[17] = t8, $[18] = t9) : t9 = $[18];
- let t10;
- return $[19] !== onClose || $[20] !== t2 || $[21] !== t9 ? (t10 = /* @__PURE__ */ jsx(Dialog, {
- animate: !0,
- footer: t2,
- header: "Add to your config",
- id: "themer-snippet",
- onClickOutside: onClose,
- onClose,
- width: 1,
- children: t9
- }), $[19] = onClose, $[20] = t2, $[21] = t9, $[22] = t10) : t10 = $[22], t10;
-}
-var title = "c2pqej0";
-const VIEW_TITLES = {
- list: "Themer",
- edit: "Edit theme",
- removed: "Removed themes"
-};
-/**
-* The themer sidebar: a header that navigates between the flows and toggles
-* the split preview, the flow itself — picking a theme, editing one, or
-* restoring removed ones — and the dialog with the `buildTheme` snippet of
-* the applied theme.
-*
-* @internal
-*/
-function ThemerSidebar() {
- let $ = c(42), { active, split, view, navbarHeight, send } = useThemer(), [snippetOpen, setSnippetOpen] = useState(!1), inList = view.name === "list", t0;
- $[0] === navbarHeight ? t0 = $[1] : (t0 = navbarHeight === null ? void 0 : { height: navbarHeight }, $[0] = navbarHeight, $[1] = t0);
- let t1;
- $[2] !== inList || $[3] !== send ? (t1 = !inList && /* @__PURE__ */ jsx(TooltipButton, {
- icon: ArrowLeftIcon,
- mode: "bleed",
- onClick: () => send({ type: "flow.list" }),
- padding: 2,
- tooltip: "Back to the themes"
- }), $[2] = inList, $[3] = send, $[4] = t1) : t1 = $[4];
- let t2 = VIEW_TITLES[view.name], t3;
- $[5] === t2 ? t3 = $[6] : (t3 = /* @__PURE__ */ jsx(Box, {
- className: title,
- flex: 1,
- children: /* @__PURE__ */ jsx(Text, {
- size: 1,
- textOverflow: "ellipsis",
- weight: "semibold",
- children: t2
- })
- }), $[5] = t2, $[6] = t3);
- let t4;
- $[7] !== send || $[8] !== split || $[9] !== view.name ? (t4 = view.name !== "removed" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(TooltipButton, {
- "aria-pressed": split,
- icon: SplitVerticalIcon,
- mode: "bleed",
- onClick: () => send({ type: "preview.toggle" }),
- padding: 2,
- selected: split,
- tooltip: "Show light and dark side by side"
- }), /* @__PURE__ */ jsx(TooltipButton, {
- icon: CodeBlockIcon,
- mode: "bleed",
- onClick: () => setSnippetOpen(!0),
- padding: 2,
- tooltip: "Show the code for the applied theme"
- })] }), $[7] = send, $[8] = split, $[9] = view.name, $[10] = t4) : t4 = $[10];
- let t5;
- $[11] === send ? t5 = $[12] : (t5 = /* @__PURE__ */ jsx(TooltipButton, {
- icon: CloseIcon,
- mode: "bleed",
- onClick: () => send({ type: "sidebar.close" }),
- padding: 2,
- tooltip: "Close themer"
- }), $[11] = send, $[12] = t5);
- let t6;
- $[13] !== t4 || $[14] !== t5 ? (t6 = /* @__PURE__ */ jsxs(Flex, { children: [t4, t5] }), $[13] = t4, $[14] = t5, $[15] = t6) : t6 = $[15];
- let t7;
- $[16] !== t1 || $[17] !== t3 || $[18] !== t6 ? (t7 = /* @__PURE__ */ jsxs(Flex, {
- align: "center",
- gap: 1,
- height: "fill",
- children: [
- t1,
- t3,
- t6
- ]
- }), $[16] = t1, $[17] = t3, $[18] = t6, $[19] = t7) : t7 = $[19];
- let t8;
- $[20] !== t0 || $[21] !== t7 ? (t8 = /* @__PURE__ */ jsx(Card, {
- borderBottom: !0,
- padding: 3,
- sizing: "border",
- style: t0,
- children: t7
- }), $[20] = t0, $[21] = t7, $[22] = t8) : t8 = $[22];
- let t9;
- $[23] === view.name ? t9 = $[24] : (t9 = view.name === "list" && /* @__PURE__ */ jsx(ThemeList, {}), $[23] = view.name, $[24] = t9);
- let t10;
- $[25] !== view.focusTitle || $[26] !== view.name || $[27] !== view.slug ? (t10 = view.name === "edit" && /* @__PURE__ */ jsx(ThemeEditor, {
- focusTitle: view.focusTitle,
- slug: view.slug
- }), $[25] = view.focusTitle, $[26] = view.name, $[27] = view.slug, $[28] = t10) : t10 = $[28];
- let t11;
- $[29] === view.name ? t11 = $[30] : (t11 = view.name === "removed" && /* @__PURE__ */ jsx(RemovedThemes, {}), $[29] = view.name, $[30] = t11);
- let t12;
- $[31] !== t10 || $[32] !== t11 || $[33] !== t8 || $[34] !== t9 ? (t12 = /* @__PURE__ */ jsxs(Flex, {
- direction: "column",
- height: "fill",
- children: [
- t8,
- t9,
- t10,
- t11
- ]
- }), $[31] = t10, $[32] = t11, $[33] = t8, $[34] = t9, $[35] = t12) : t12 = $[35];
- let t13;
- $[36] !== active || $[37] !== snippetOpen ? (t13 = snippetOpen && /* @__PURE__ */ jsx(ThemeSnippetDialog, {
- onClose: () => setSnippetOpen(!1),
- theme: active
- }), $[36] = active, $[37] = snippetOpen, $[38] = t13) : t13 = $[38];
- let t14;
- return $[39] !== t12 || $[40] !== t13 ? (t14 = /* @__PURE__ */ jsxs(Card, {
- height: "fill",
- children: [t12, t13]
- }), $[39] = t12, $[40] = t13, $[41] = t14) : t14 = $[41], t14;
-}
-var content = "bgn4np4", frame = "bgn4np3", sidebar = "bgn4np2";
-/** How far one arrow key press resizes the sidebar */
-const WIDTH_STORAGE_KEY = "sanityStudio:themer:width";
-function clampWidth(width) {
- return Math.min(400, Math.max(200, Math.round(width)));
-}
-function readStoredWidth() {
- try {
- let stored = Number(localStorage.getItem(WIDTH_STORAGE_KEY));
- return Number.isFinite(stored) && stored > 0 ? clampWidth(stored) : 200;
- } catch {
- return 200;
- }
-}
-function writeStoredWidth(width) {
- try {
- width === 200 ? localStorage.removeItem(WIDTH_STORAGE_KEY) : localStorage.setItem(WIDTH_STORAGE_KEY, String(width));
- } catch {}
-}
-/**
-* The themer sidebar, in a layer along the right edge of the Studio. Its left
-* edge drags (or arrow-keys) it wider, up to twice its default width — the
-* width sticks between sessions. As an overlay (small screens) it covers the
-* Studio edge to edge instead, with nothing to resize.
-*
-* @internal
-*/
-function ResizableSidebar(props) {
- let $ = c(24), { overlay } = props, [width, setWidth] = useState(readStoredWidth), [dragging, setDragging] = useState(!1), drag = useRef(null), t0, t1;
- $[0] === width ? (t0 = $[1], t1 = $[2]) : (t0 = () => writeStoredWidth(width), t1 = [width], $[0] = width, $[1] = t0, $[2] = t1), useEffect(t0, t1);
- let t2;
- $[3] === width ? t2 = $[4] : (t2 = (event) => {
- event.button === 0 && (event.preventDefault(), event.currentTarget.setPointerCapture(event.pointerId), drag.current = {
- pointerId: event.pointerId,
- startX: event.clientX,
- startWidth: width
- }, setDragging(!0));
- }, $[3] = width, $[4] = t2);
- let handlePointerDown = t2, t3;
- $[5] === Symbol.for("react.memo_cache_sentinel") ? (t3 = (event_0) => {
- drag.current && drag.current.pointerId === event_0.pointerId && setWidth(clampWidth(drag.current.startWidth - (event_0.clientX - drag.current.startX)));
- }, $[5] = t3) : t3 = $[5];
- let handlePointerMove = t3, t4;
- $[6] === Symbol.for("react.memo_cache_sentinel") ? (t4 = (event_1) => {
- drag.current && drag.current.pointerId === event_1.pointerId && (drag.current = null, setDragging(!1));
- }, $[6] = t4) : t4 = $[6];
- let handlePointerUp = t4, t5;
- $[7] === Symbol.for("react.memo_cache_sentinel") ? (t5 = (event_2) => {
- let step = {
- ArrowLeft: 16,
- ArrowRight: -16,
- Home: 400,
- End: -400
- }[event_2.key];
- step !== void 0 && (event_2.preventDefault(), setWidth((current) => clampWidth(current + step)));
- }, $[7] = t5) : t5 = $[7];
- let handleKeyDown = t5, t6;
- $[8] !== overlay || $[9] !== width ? (t6 = overlay ? void 0 : { width }, $[8] = overlay, $[9] = width, $[10] = t6) : t6 = $[10];
- let t7 = !overlay, t8;
- $[11] !== dragging || $[12] !== handlePointerDown || $[13] !== overlay || $[14] !== width ? (t8 = !overlay && /* @__PURE__ */ jsx("div", {
- "aria-label": "Resize the themer",
- className: "bgn4np5",
- "aria-orientation": "vertical",
- "aria-valuemax": 400,
- "aria-valuemin": 200,
- "aria-valuenow": width,
- "data-dragging": dragging,
- onDoubleClick: () => setWidth(200),
- onKeyDown: handleKeyDown,
- onPointerCancel: handlePointerUp,
- onPointerDown: handlePointerDown,
- onPointerMove: handlePointerMove,
- onPointerUp: handlePointerUp,
- role: "separator",
- tabIndex: 0
- }), $[11] = dragging, $[12] = handlePointerDown, $[13] = overlay, $[14] = width, $[15] = t8) : t8 = $[15];
- let t9;
- $[16] === Symbol.for("react.memo_cache_sentinel") ? (t9 = /* @__PURE__ */ jsx(Box, {
- className: content,
- height: "fill",
- overflow: "hidden",
- children: /* @__PURE__ */ jsx(ThemerSidebar, {})
- }), $[16] = t9) : t9 = $[16];
- let t10;
- $[17] !== t7 || $[18] !== t8 ? (t10 = /* @__PURE__ */ jsxs(Card, {
- borderLeft: t7,
- className: frame,
- height: "fill",
- children: [t8, t9]
- }), $[17] = t7, $[18] = t8, $[19] = t10) : t10 = $[19];
- let t11;
- return $[20] !== overlay || $[21] !== t10 || $[22] !== t6 ? (t11 = /* @__PURE__ */ jsx(Layer, {
- className: sidebar,
- "data-overlay": overlay,
- style: t6,
- zOffset: 100,
- children: t10
- }), $[20] = overlay, $[21] = t10, $[22] = t6, $[23] = t11) : t11 = $[23], t11;
-}
-export { ResizableSidebar as default };
-
-//# sourceMappingURL=ResizableSidebar-DD787kQr.js.map
\ No newline at end of file