@sanity/themer

0.10.10.10.2
dist/tool.js.map
~dist/tool.js.mapModified
+1−1
Index: package/dist/tool.js.map
===================================================================
--- package/dist/tool.js.map
+++ package/dist/tool.js.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"tool.js","names":["() =>\n    startBusyTransition(() => {\n      if (split) addThemerTransitionType('split-screen:open')\n      addThemerTransitionType('open')\n      dispatch({type: 'open'})\n    })","() =>\n    startBusyTransition(() => {\n      if (split) addThemerTransitionType('split-screen:close')\n      addThemerTransitionType('close')\n      dispatch({type: 'close'})\n    })","() =>\n    startTransition(() => {\n      // We want to trigger rerender in a transition, so that clicking the open button\n      // can interrupt a prerender, and hovering over the button won't abort an active view transition.\n      // But we also don't want the transition to trigger a view transition,\n      // so we intentionally do not set a transition type here.\n      dispatch({type: 'prerender'})\n      // Do a little fun spin\n      if (!open) iconRef.current?.spin()\n    })","(root: HTMLButtonElement | null) => {\n    const navbar = root?.closest(NAVBAR_SELECTOR)\n\n    if (!navbar) return undefined\n\n    const resizeObserver = new ResizeObserver((entries) => {\n      const height = entries[0]?.borderBoxSize[0]?.blockSize\n\n      if (height) {\n        startTransition(() => dispatch({type: 'set-navbar-height', height}))\n      }\n    })\n\n    resizeObserver.observe(navbar)\n\n    return () => resizeObserver.disconnect()\n  }","<Text size={1}>{title}</Text>","prefersReducedMotion ? (\n                  <ColorWheelIcon />\n                ) : (\n                  <Suspense fallback={<ColorWheelIcon />}>\n                    <AnimatedColorWheelIcon busy={busy} ref={iconRef} />\n                  </Suspense>\n                )","<Box>\n          <ViewTransition default=\"none\" update={viewTransitionClasses.navbarButton.update}>\n            <Button\n              ref={shouldDetectNavbarHeight ? observeNavbarHeight : undefined}\n              aria-busy={busy}\n              aria-label={title}\n              // The wheel itself shows the load, where the `loading` prop would\n              // cover it with a spinner\n              icon={\n                // The animated wheel needs `motion/react`, which is heavy, so it\n                // loads lazily — behind the plain icon it reimplements, which is\n                // all there is to show with `prefers-reduced-motion: reduce`\n                prefersReducedMotion ? (\n                  <ColorWheelIcon />\n                ) : (\n                  <Suspense fallback={<ColorWheelIcon />}>\n                    <AnimatedColorWheelIcon busy={busy} ref={iconRef} />\n                  </Suspense>\n                )\n              }\n              mode=\"bleed\"\n              onClick={open ? handleClose : handleOpen}\n              onFocus={handlePrerender}\n              onMouseEnter={handlePrerender}\n              // The Studio's own navbar buttons go through a wrapper that pins them\n              // to this padding, where `@sanity/ui` defaults to a roomier 3\n              padding={2}\n              selected={open || busy}\n            />\n          </ViewTransition>\n        </Box>","shouldDetectNavbarHeight ? observeNavbarHeight : undefined","open ? handleClose : handleOpen","open || busy","<ViewTransition default=\"none\" update={viewTransitionClasses.navbarButtonTooltip.update}>\n      <Tooltip animate content={<Text size={1}>{title}</Text>} portal>\n        <Box>\n          <ViewTransition default=\"none\" update={viewTransitionClasses.navbarButton.update}>\n            <Button\n              ref={shouldDetectNavbarHeight ? observeNavbarHeight : undefined}\n              aria-busy={busy}\n              aria-label={title}\n              // The wheel itself shows the load, where the `loading` prop would\n              // cover it with a spinner\n              icon={\n                // The animated wheel needs `motion/react`, which is heavy, so it\n                // loads lazily — behind the plain icon it reimplements, which is\n                // all there is to show with `prefers-reduced-motion: reduce`\n                prefersReducedMotion ? (\n                  <ColorWheelIcon />\n                ) : (\n                  <Suspense fallback={<ColorWheelIcon />}>\n                    <AnimatedColorWheelIcon busy={busy} ref={iconRef} />\n                  </Suspense>\n                )\n              }\n              mode=\"bleed\"\n              onClick={open ? handleClose : handleOpen}\n              onFocus={handlePrerender}\n              onMouseEnter={handlePrerender}\n              // The Studio's own navbar buttons go through a wrapper that pins them\n              // to this padding, where `@sanity/ui` defaults to a roomier 3\n              padding={2}\n              selected={open || busy}\n            />\n          </ViewTransition>\n        </Box>\n      </Tooltip>\n    </ViewTransition>","{\n        location: 'topbar',\n        name: 'themer-topbar',\n        // The component itself rather than a `() => <ThemerNavbarButton />`\n        // wrapper: the Studio renders `render` as a component, and a wrapper\n        // made anew on every render would remount the button each time —\n        // resetting its animation\n        render: ThemerNavbarButton,\n      }","props.__internal_actions ?? []","__internal_actions","props.renderDefault({\n    ...props,\n    __internal_actions: [...(props.__internal_actions ?? []), button],\n  })","{\n  children,\n  config,\n  dispatch,\n  open,\n  shouldDetectNavbarHeight,\n  split,\n}: {children: React.ReactNode; shouldDetectNavbarHeight?: boolean} & Pick<\n  ThemerProps,\n  'dispatch' | 'config' | 'open' | 'split'\n>","<ToolShouldDetectNavbarHeightContext value={shouldDetectNavbarHeight ?? false}>\n              {children}\n            </ToolShouldDetectNavbarHeightContext>","shouldDetectNavbarHeight ?? false","<ToolSplitIsOpenContext value={split}>\n            <ToolShouldDetectNavbarHeightContext value={shouldDetectNavbarHeight ?? false}>\n              {children}\n            </ToolShouldDetectNavbarHeightContext>\n          </ToolSplitIsOpenContext>","<ToolIsOpenContext value={open}>\n          <ToolSplitIsOpenContext value={split}>\n            <ToolShouldDetectNavbarHeightContext value={shouldDetectNavbarHeight ?? false}>\n              {children}\n            </ToolShouldDetectNavbarHeightContext>\n          </ToolSplitIsOpenContext>\n        </ToolIsOpenContext>","<ToolDispatchContext value={dispatch}>\n        <ToolIsOpenContext value={open}>\n          <ToolSplitIsOpenContext value={split}>\n            <ToolShouldDetectNavbarHeightContext value={shouldDetectNavbarHeight ?? false}>\n              {children}\n            </ToolShouldDetectNavbarHeightContext>\n          </ToolSplitIsOpenContext>\n        </ToolIsOpenContext>\n      </ToolDispatchContext>","<PluginConfigContext value={config}>\n      <ToolDispatchContext value={dispatch}>\n        <ToolIsOpenContext value={open}>\n          <ToolSplitIsOpenContext value={split}>\n            <ToolShouldDetectNavbarHeightContext value={shouldDetectNavbarHeight ?? false}>\n              {children}\n            </ToolShouldDetectNavbarHeightContext>\n          </ToolSplitIsOpenContext>\n        </ToolIsOpenContext>\n      </ToolDispatchContext>\n    </PluginConfigContext>","_c","unknown","{actorRef}: Pick<ThemerProps, 'actorRef'>","() => syncThemer(actorRef, {persist: writePersistedSnapshot})","[actorRef]","_c","{\n  children,\n  backgroundColor,\n  config,\n  dispatch,\n  navbarHeight,\n  open,\n  persistedSnapshot,\n  prerender,\n  prerenderSplitScreen,\n  scheme,\n  split,\n}: ThemerLayoutProps & {backgroundColor: string | undefined; scheme: ThemeColorSchemeKey}","{snapshot: persistedSnapshot}","{backgroundColor}","prerenderSplitScreen && (\n              <StudioPreview\n                borderRight\n                config={config}\n                dispatch={dispatch}\n                open={open}\n                scheme={oppositeScheme}\n                split={split}\n              >\n                {children}\n              </StudioPreview>\n            )","<ViewTransition\n            default=\"none\"\n            enter={viewTransitionClasses.splitscreen.enter}\n            update={viewTransitionClasses.splitscreen.update}\n            exit={viewTransitionClasses.splitscreen.exit}\n          >\n            {prerenderSplitScreen && (\n              <StudioPreview\n                borderRight\n                config={config}\n                dispatch={dispatch}\n                open={open}\n                scheme={oppositeScheme}\n                split={split}\n              >\n                {children}\n              </StudioPreview>\n            )}\n          </ViewTransition>","<Activity mode={split && open ? 'visible' : 'hidden'}>\n          <ViewTransition\n            default=\"none\"\n            enter={viewTransitionClasses.splitscreen.enter}\n            update={viewTransitionClasses.splitscreen.update}\n            exit={viewTransitionClasses.splitscreen.exit}\n          >\n            {prerenderSplitScreen && (\n              <StudioPreview\n                borderRight\n                config={config}\n                dispatch={dispatch}\n                open={open}\n                scheme={oppositeScheme}\n                split={split}\n              >\n                {children}\n              </StudioPreview>\n            )}\n          </ViewTransition>\n        </Activity>","split && open ? 'visible' : 'hidden'","<ViewTransition default=\"none\" update={viewTransitionClasses.studio.update}>\n          <StudioPreview\n            config={config}\n            dispatch={dispatch}\n            open={open}\n            shouldDetectNavbarHeight\n            split={split}\n          >\n            {children}\n          </StudioPreview>\n        </ViewTransition>","prerender && (\n              <ResizableSidebar\n                actorRef={actorRef}\n                dispatch={dispatch}\n                navbarHeight={navbarHeight}\n                split={split}\n              />\n            )","<ViewTransition\n            default=\"none\"\n            enter={viewTransitionClasses.sidebar.enter}\n            update={viewTransitionClasses.sidebar.update}\n            exit={viewTransitionClasses.sidebar.exit}\n          >\n            {prerender && (\n              <ResizableSidebar\n                actorRef={actorRef}\n                dispatch={dispatch}\n                navbarHeight={navbarHeight}\n                split={split}\n              />\n            )}\n          </ViewTransition>","<Activity mode={open ? 'visible' : 'hidden'}>\n          <ViewTransition\n            default=\"none\"\n            enter={viewTransitionClasses.sidebar.enter}\n            update={viewTransitionClasses.sidebar.update}\n            exit={viewTransitionClasses.sidebar.exit}\n          >\n            {prerender && (\n              <ResizableSidebar\n                actorRef={actorRef}\n                dispatch={dispatch}\n                navbarHeight={navbarHeight}\n                split={split}\n              />\n            )}\n          </ViewTransition>\n        </Activity>","open ? 'visible' : 'hidden'","<Flex\n        className={layout}\n        direction={'row'}\n        height=\"fill\"\n        sizing=\"border\"\n        style={{backgroundColor}}\n      >\n        {/* Renders the Studio for the second time, in the opposite scheme of the main studio. Hidden by default */}\n        <Activity mode={split && open ? 'visible' : 'hidden'}>\n          <ViewTransition\n            default=\"none\"\n            enter={viewTransitionClasses.splitscreen.enter}\n            update={viewTransitionClasses.splitscreen.update}\n            exit={viewTransitionClasses.splitscreen.exit}\n          >\n            {prerenderSplitScreen && (\n              <StudioPreview\n                borderRight\n                config={config}\n                dispatch={dispatch}\n                open={open}\n                scheme={oppositeScheme}\n                split={split}\n              >\n                {children}\n              </StudioPreview>\n            )}\n          </ViewTransition>\n        </Activity>\n        {/* Renders the Studio */}\n        <ViewTransition default=\"none\" update={viewTransitionClasses.studio.update}>\n          <StudioPreview\n            config={config}\n            dispatch={dispatch}\n            open={open}\n            shouldDetectNavbarHeight\n            split={split}\n          >\n            {children}\n          </StudioPreview>\n        </ViewTransition>\n        {/* Renders the Themer tool, hidden by default */}\n        <Activity mode={open ? 'visible' : 'hidden'}>\n          <ViewTransition\n            default=\"none\"\n            enter={viewTransitionClasses.sidebar.enter}\n            update={viewTransitionClasses.sidebar.update}\n            exit={viewTransitionClasses.sidebar.exit}\n          >\n            {prerender && (\n              <ResizableSidebar\n                actorRef={actorRef}\n                dispatch={dispatch}\n                navbarHeight={navbarHeight}\n                split={split}\n              />\n            )}\n          </ViewTransition>\n        </Activity>\n      </Flex>","<ThemerThemeCrossfader actorRef={actorRef} dispatch={dispatch} />","<RevokeImageUrls actorRef={actorRef} />","<PersistActorSnapshot actorRef={actorRef} />","<>\n      <Flex\n        className={layout}\n        direction={'row'}\n        height=\"fill\"\n        sizing=\"border\"\n        style={{backgroundColor}}\n      >\n        {/* Renders the Studio for the second time, in the opposite scheme of the main studio. Hidden by default */}\n        <Activity mode={split && open ? 'visible' : 'hidden'}>\n          <ViewTransition\n            default=\"none\"\n            enter={viewTransitionClasses.splitscreen.enter}\n            update={viewTransitionClasses.splitscreen.update}\n            exit={viewTransitionClasses.splitscreen.exit}\n          >\n            {prerenderSplitScreen && (\n              <StudioPreview\n                borderRight\n                config={config}\n                dispatch={dispatch}\n                open={open}\n                scheme={oppositeScheme}\n                split={split}\n              >\n                {children}\n              </StudioPreview>\n            )}\n          </ViewTransition>\n        </Activity>\n        {/* Renders the Studio */}\n        <ViewTransition default=\"none\" update={viewTransitionClasses.studio.update}>\n          <StudioPreview\n            config={config}\n            dispatch={dispatch}\n            open={open}\n            shouldDetectNavbarHeight\n            split={split}\n          >\n            {children}\n          </StudioPreview>\n        </ViewTransition>\n        {/* Renders the Themer tool, hidden by default */}\n        <Activity mode={open ? 'visible' : 'hidden'}>\n          <ViewTransition\n            default=\"none\"\n            enter={viewTransitionClasses.sidebar.enter}\n            update={viewTransitionClasses.sidebar.update}\n            exit={viewTransitionClasses.sidebar.exit}\n          >\n            {prerender && (\n              <ResizableSidebar\n                actorRef={actorRef}\n                dispatch={dispatch}\n                navbarHeight={navbarHeight}\n                split={split}\n              />\n            )}\n          </ViewTransition>\n        </Activity>\n      </Flex>\n\n      <ThemerThemeCrossfader actorRef={actorRef} dispatch={dispatch} />\n      <RevokeImageUrls actorRef={actorRef} />\n      <PersistActorSnapshot actorRef={actorRef} />\n    </>","{\n  borderRight,\n  children,\n  config,\n  dispatch,\n  open,\n  scheme,\n  shouldDetectNavbarHeight,\n  split,\n}: {\n  borderRight?: boolean\n  scheme?: ThemeColorSchemeKey\n} & React.ComponentProps<typeof ThemerNavbarProvider>","(boundaryElement) => {\n        startTransition(() => setBoundaryElement(boundaryElement))\n        // Intentionally not unsetting the element as it would create unnecessary work when <Activity> unhides\n        return () => {}\n      }","boundaryElement","() => {}","<ViewTransition update=\"none\">{children}</ViewTransition>","<ThemerNavbarProvider\n          config={config}\n          dispatch={dispatch}\n          open={open}\n          shouldDetectNavbarHeight={shouldDetectNavbarHeight}\n          split={split}\n        >\n          <ViewTransition update=\"none\">{children}</ViewTransition>\n        </ThemerNavbarProvider>","<BoundaryElementProvider element={boundaryElement}>\n        <ThemerNavbarProvider\n          config={config}\n          dispatch={dispatch}\n          open={open}\n          shouldDetectNavbarHeight={shouldDetectNavbarHeight}\n          split={split}\n        >\n          <ViewTransition update=\"none\">{children}</ViewTransition>\n        </ThemerNavbarProvider>\n      </BoundaryElementProvider>","<Card\n      borderRight={borderRight}\n      flex={1}\n      height=\"fill\"\n      overflow=\"hidden\"\n      scheme={scheme}\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      <BoundaryElementProvider element={boundaryElement}>\n        <ThemerNavbarProvider\n          config={config}\n          dispatch={dispatch}\n          open={open}\n          shouldDetectNavbarHeight={shouldDetectNavbarHeight}\n          split={split}\n        >\n          <ViewTransition update=\"none\">{children}</ViewTransition>\n        </ThemerNavbarProvider>\n      </BoundaryElementProvider>\n    </Card>","{actorRef, dispatch}: Pick<ThemerProps, 'actorRef' | 'dispatch'>","() => {\n    const subscription = actorRef.subscribe((snapshot) => {\n      const switching = snapshot.hasTag('switching')\n      const theme = resolveActiveThemeOptions(snapshot.context)\n\n      startTransition(() => {\n        if (switching) {\n          addThemerTransitionType('crossfade')\n        }\n        if (!theme) {\n          dispatch({type: 'unset-theme'})\n        } else {\n          dispatch({type: 'set-theme', theme})\n        }\n      })\n    })\n\n    return () => subscription.unsubscribe()\n  }","[actorRef, dispatch]","{actorRef}: Pick<ThemerProps, 'actorRef'>","() => () => {\n      for (const url of Object.values(actorRef.getSnapshot().context.images)) {\n        URL.revokeObjectURL(url)\n      }\n    }","[actorRef]","_c","_Fragment","{\n  children,\n  config,\n}: {\n  children: React.ReactNode\n} & Pick<ThemerProps, 'config'>","(initialState) => {\n    if (!persistedSnapshot) return initialState\n    const theme = resolveActiveThemeOptions(persistedSnapshot.context)\n    return theme ? {...initialState, theme} : initialState\n  }","(state.theme !== null ? buildTheme(state.theme) : null) ?? undefined","theme","<ThemerLayout\n        config={config}\n        backgroundColor={state.theme?.[scheme]?.background}\n        dispatch={dispatch}\n        navbarHeight={state.navbarHeight}\n        open={open}\n        persistedSnapshot={persistedSnapshot}\n        prerender={state.prerender}\n        prerenderSplitScreen={state.prerenderSplitScreen}\n        scheme={scheme}\n        split={split}\n      >\n        {children}\n      </ThemerLayout>","navbarHeight","prerender","prerenderSplitScreen","state.theme?.[scheme]?.background","<ThemeProvider theme={(state.theme !== null ? buildTheme(state.theme) : null) ?? undefined}>\n      <ThemerLayout\n        config={config}\n        backgroundColor={state.theme?.[scheme]?.background}\n        dispatch={dispatch}\n        navbarHeight={state.navbarHeight}\n        open={open}\n        persistedSnapshot={persistedSnapshot}\n        prerender={state.prerender}\n        prerenderSplitScreen={state.prerenderSplitScreen}\n        scheme={scheme}\n        split={split}\n      >\n        {children}\n      </ThemerLayout>\n    </ThemeProvider>","_c","props.renderDefault(props)","<ThemerProvider config={config}>{props.renderDefault(props)}</ThemerProvider>","_c"],"sources":["../src/tool/context.ts","../src/tool/ThemerNavbar.tsx","../src/tool/reducer.ts","../src/tool/selectors.ts","../src/tool/schemas.ts","../src/tool/storage.ts","../src/tool/machine.ts","../src/tool/sync.ts","../src/tool/PersistActorSnapshot.tsx","../src/tool/ThemerLayout.tsx","../src/tool/ThemerProvider.tsx","../src/tool/plugin.tsx"],"sourcesContent":["import {createContext} from 'react'\n\nimport type {PluginConfig} from '#types'\n\nimport type {ToolReducerAction} from './reducer'\n\n/*\n * The tool reducer's state that the navbar toggle shows and changes. The\n * Studio renders the navbar itself, out of the layout's reach, so this is\n * where the reducer's values travel by context — the layout and the sidebar\n * get them as props. One context per value, on purpose: a consumer only\n * re-renders for the value it reads, where one object would re-render every\n * consumer for any change.\n */\n\n/** @internal */\nexport const ToolIsOpenContext = createContext<boolean>(false)\n/**\n * The global top-level useReducer dispatch() for state that persists through open/close of the tool\n * @internal */\nexport const ToolDispatchContext = createContext<React.Dispatch<ToolReducerAction>>(() => {\n  throw new Error('ToolDispatchContext not initialized')\n})\n/** @internal */\nexport const ToolSplitIsOpenContext = createContext<boolean>(false)\n\n/** @internal */\nexport const ToolShouldDetectNavbarHeightContext = createContext<boolean>(false)\n\n/** @internal */\nexport const PluginConfigContext = createContext<Required<PluginConfig> | null>(null)\n\n/** @internal */\nexport type ThemerView =\n  | {name: 'list'}\n  | {\n      name: 'edit'\n      slug: string\n      /** Whether the title input should take focus, for themes that were just created */\n      focusTitle: boolean\n    }\n  | {name: 'removed'}\n","import {ColorWheelIcon} from '@sanity/icons/ColorWheel'\nimport {Box, Button, Text, usePrefersReducedMotion} from '@sanity/ui'\nimport {Tooltip} from '@sanity/ui/tooltip'\nimport {\n  lazy,\n  startTransition,\n  Suspense,\n  use,\n  useRef,\n  useTransition,\n  ViewTransition,\n  useMemo,\n} from 'react'\nimport {type NavbarProps} from 'sanity'\nimport type {NavbarAction} from 'sanity/_dangerously_use_private_internals_that_do_not_follow_semver'\n\nimport {NAVBAR_SELECTOR} from '#constants'\nimport {\n  PluginConfigContext,\n  ToolDispatchContext,\n  ToolIsOpenContext,\n  ToolShouldDetectNavbarHeightContext,\n  ToolSplitIsOpenContext,\n} from '#context'\nimport type {ThemerProps} from '#types'\n\nimport {addThemerTransitionType} from './addThemerTransitionType'\n\nimport {viewTransitionClasses} from './ViewTransitions.css'\n\nconst AnimatedColorWheelIcon = lazy(() => import('./AnimatedColorWheelIcon'))\n\nfunction ThemerNavbarButton() {\n  const config = use(PluginConfigContext)\n  const dispatch = use(ToolDispatchContext)\n  const open = use(ToolIsOpenContext)\n  const shouldDetectNavbarHeight = use(ToolShouldDetectNavbarHeightContext)\n  const split = use(ToolSplitIsOpenContext)\n\n  if (!config) {\n    throw new TypeError('PluginConfigContext.Provider is missing')\n  }\n\n  const [busy, startBusyTransition] = useTransition()\n  const iconRef = useRef<{spin: () => void}>(null)\n  const prefersReducedMotion = usePrefersReducedMotion()\n\n  const handleOpen = () =>\n    startBusyTransition(() => {\n      if (split) addThemerTransitionType('split-screen:open')\n      addThemerTransitionType('open')\n      dispatch({type: 'open'})\n    })\n  const handleClose = () =>\n    startBusyTransition(() => {\n      if (split) addThemerTransitionType('split-screen:close')\n      addThemerTransitionType('close')\n      dispatch({type: 'close'})\n    })\n  const handlePrerender = () =>\n    startTransition(() => {\n      // We want to trigger rerender in a transition, so that clicking the open button\n      // can interrupt a prerender, and hovering over the button won't abort an active view transition.\n      // But we also don't want the transition to trigger a view transition,\n      // so we intentionally do not set a transition type here.\n      dispatch({type: 'prerender'})\n      // Do a little fun spin\n      if (!open) iconRef.current?.spin()\n    })\n\n  // The sidebar's header takes the height of the Studio navbar, so the two\n  // line up — whatever height the Studio, its breakpoint or a custom navbar\n  // gives it. The button sits inside the navbar, so it is the one to measure\n  // it, as a ref callback: observed from mount to unmount, in a transition,\n  // since nothing urgent hangs on the number\n  const observeNavbarHeight = (root: HTMLButtonElement | null) => {\n    const navbar = root?.closest(NAVBAR_SELECTOR)\n\n    if (!navbar) return undefined\n\n    const resizeObserver = new ResizeObserver((entries) => {\n      const height = entries[0]?.borderBoxSize[0]?.blockSize\n\n      if (height) {\n        startTransition(() => dispatch({type: 'set-navbar-height', height}))\n      }\n    })\n\n    resizeObserver.observe(navbar)\n\n    return () => resizeObserver.disconnect()\n  }\n\n  const {title} = config\n\n  // The `Box` is here because a `ViewTransition` cannot be the direct child\n  // of the `Tooltip`: it needs a child that renders a DOM node\n  return (\n    <ViewTransition default=\"none\" update={viewTransitionClasses.navbarButtonTooltip.update}>\n      <Tooltip animate content={<Text size={1}>{title}</Text>} portal>\n        <Box>\n          <ViewTransition default=\"none\" update={viewTransitionClasses.navbarButton.update}>\n            <Button\n              ref={shouldDetectNavbarHeight ? observeNavbarHeight : undefined}\n              aria-busy={busy}\n              aria-label={title}\n              // The wheel itself shows the load, where the `loading` prop would\n              // cover it with a spinner\n              icon={\n                // The animated wheel needs `motion/react`, which is heavy, so it\n                // loads lazily — behind the plain icon it reimplements, which is\n                // all there is to show with `prefers-reduced-motion: reduce`\n                prefersReducedMotion ? (\n                  <ColorWheelIcon />\n                ) : (\n                  <Suspense fallback={<ColorWheelIcon />}>\n                    <AnimatedColorWheelIcon busy={busy} ref={iconRef} />\n                  </Suspense>\n                )\n              }\n              mode=\"bleed\"\n              onClick={open ? handleClose : handleOpen}\n              onFocus={handlePrerender}\n              onMouseEnter={handlePrerender}\n              // The Studio's own navbar buttons go through a wrapper that pins them\n              // to this padding, where `@sanity/ui` defaults to a roomier 3\n              padding={2}\n              selected={open || busy}\n            />\n          </ViewTransition>\n        </Box>\n      </Tooltip>\n    </ViewTransition>\n  )\n}\n\nexport function ThemerNavbar(props: NavbarProps) {\n  const button = useMemo(\n    () =>\n      ({\n        location: 'topbar',\n        name: 'themer-topbar',\n        // The component itself rather than a `() => <ThemerNavbarButton />`\n        // wrapper: the Studio renders `render` as a component, and a wrapper\n        // made anew on every render would remount the button each time —\n        // resetting its animation\n        render: ThemerNavbarButton,\n      }) satisfies NavbarAction,\n    [],\n  )\n  return props.renderDefault({\n    ...props,\n    __internal_actions: [...(props.__internal_actions ?? []), button],\n  })\n}\n\n// It can be easy to forget which contexts that ThemerNavbar requires and expects to be defined,\n// especially since TypeScript is unable to detect missing contexts statically,\n// parent views uses this component to ensure it doesn't miss anything and the props interface gives us type check validation.\nexport function ThemerNavbarProvider({\n  children,\n  config,\n  dispatch,\n  open,\n  shouldDetectNavbarHeight,\n  split,\n}: {children: React.ReactNode; shouldDetectNavbarHeight?: boolean} & Pick<\n  ThemerProps,\n  'dispatch' | 'config' | 'open' | 'split'\n>) {\n  return (\n    <PluginConfigContext value={config}>\n      <ToolDispatchContext value={dispatch}>\n        <ToolIsOpenContext value={open}>\n          <ToolSplitIsOpenContext value={split}>\n            <ToolShouldDetectNavbarHeightContext value={shouldDetectNavbarHeight ?? false}>\n              {children}\n            </ToolShouldDetectNavbarHeightContext>\n          </ToolSplitIsOpenContext>\n        </ToolIsOpenContext>\n      </ToolDispatchContext>\n    </PluginConfigContext>\n  )\n}\n","import {dequal} from 'dequal/lite'\n\nimport type {BuildThemeOptions} from '../theme/options'\n\n/**\n * What the layout shows, owned by the `useReducer` in `ThemerProvider` and\n * never persisted — it is each tab's own — handed down to the layout and the\n * sidebar as props and to the navbar toggle through the `Tool*Context`s:\n * whether the sidebar is open and whether the Studio shows twice, whether\n * either has been prerendered yet — they mount ahead of their first showing,\n * so that the code loads and the tree is warm before the transition — the\n * options of the applied theme, as the machine publishes them, and the\n * height of the Studio navbar, as the navbar toggle measures it, for the\n * sidebar's header to match.\n */\nexport type ToolReducerState = {\n  navbarHeight: number | null\n  open: boolean\n  prerender: boolean\n  prerenderSplitScreen: boolean\n  split: boolean\n  theme: BuildThemeOptions | null\n}\n\nexport type ToolReducerAction =\n  | {type: 'set-navbar-height'; height: number}\n  | {type: 'prerender'}\n  | {type: 'open'}\n  | {type: 'close'}\n  | {type: 'split-screen:prerender'}\n  | {type: 'split-screen:open'}\n  | {type: 'split-screen:close'}\n  | {type: 'set-theme'; theme: BuildThemeOptions}\n  | {type: 'unset-theme'}\n\nexport function toolReducer(state: ToolReducerState, action: ToolReducerAction): ToolReducerState {\n  switch (action.type) {\n    case 'set-navbar-height':\n      return state.navbarHeight === action.height ? state : {...state, navbarHeight: action.height}\n    case 'prerender':\n      return state.prerender ? state : {...state, prerender: true}\n    case 'open':\n      return state.open ? state : {...state, open: true, prerender: true}\n    case 'close':\n      return state.open ? {...state, open: false} : state\n    case 'split-screen:prerender':\n      return state.prerenderSplitScreen ? state : {...state, prerenderSplitScreen: true}\n    case 'split-screen:open':\n      return state.split ? state : {...state, prerenderSplitScreen: true, split: true}\n    case 'split-screen:close':\n      return state.split ? {...state, split: false} : state\n    case 'unset-theme':\n      return state.theme === null ? state : {...state, theme: null}\n    case 'set-theme':\n      return dequal(state.theme, action.theme) ? state : {...state, theme: action.theme}\n    default: {\n      // Every action is handled above, so only a dispatch the types do not\n      // know about gets here — a bug worth hearing of, not a silent no-op\n      const unknown: never = action\n      throw new Error(`Unknown themer tool action: ${JSON.stringify(unknown)}`)\n    }\n  }\n}\n\n/**\n * Where a tab starts: closed, nothing prerendered, no theme applied —\n * `ThemerProvider` seeds only the applied theme, from the machine's restored\n * snapshot\n */\nexport const initialToolState = {\n  navbarHeight: null,\n  open: false,\n  prerender: false,\n  prerenderSplitScreen: false,\n  split: false,\n  theme: null,\n} as const satisfies ToolReducerState\n","import type {BuildThemeOptions} from '../theme/options'\nimport {presets} from '../theme/presets'\nimport type {ThemerState} from './themes'\n\n/**\n * The options of the applied theme — `null` for the configured theme, which\n * applies nothing on top of the Studio's own, and for an applied theme that\n * no longer resolves. Cheaper than resolving the whole list when only the\n * applied theme matters.\n *\n * @internal\n */\nexport function resolveActiveThemeOptions(state: ThemerState): BuildThemeOptions | null {\n  if (state.active === null || state.removed.includes(state.active)) return null\n\n  for (const theme of state.custom) {\n    if (theme.slug === state.active) return theme.options\n  }\n  for (const preset of presets) {\n    if (preset.slug === state.active) return preset.options\n  }\n\n  return null\n}\n","import * as v from 'valibot'\n\nimport {isColor} from '../lib/mix'\nimport {\n  type BuildThemeOptions,\n  MAXIMUM_CONTRAST,\n  MINIMUM_CONTRAST,\n  SCHEMES,\n  type SchemeThemeOptions,\n} from '../theme/options'\nimport {presets} from '../theme/presets'\nimport type {ImagePalette} from './imagePalette'\nimport type {ThemerMachineContext} from './machine'\nimport {CONFIG_SLUG, type CustomTheme, displayTitle, type ThemerState} from './themes'\n\n/*\n * What the tool keeps in `localStorage` is parsed with these schemas as it is\n * read back, so that a session starts from what it can use of what an\n * earlier one left — whatever version of the tool wrote it, and whatever\n * happened to it since. The schemas are lenient where the old sanitizers\n * were: a color that is not one is dropped rather than failing the theme it\n * is part of, a theme that cannot be used is dropped rather than failing the\n * list, and the shapes of earlier versions are converted into today's.\n */\n\n/** Drops the keys whose value is `undefined`, which a dropped option leaves behind */\nfunction compact<T extends object>(value: T): T {\n  // oxlint-disable-next-line no-unsafe-type-assertion -- the same keys, minus the undefined ones\n  return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined)) as T\n}\n\n/** A `#rgb` or `#rrggbb` color, lowercased */\nconst color = v.pipe(v.string(), v.check(isColor), v.toLowerCase())\n\n/** A color that is dropped rather than failing what it is part of */\nconst optionalColor = v.fallback(v.optional(color), undefined)\n\n/** A contrast, clamped into range — dropped when it is not a number */\nconst optionalContrast = v.fallback(\n  v.optional(\n    v.pipe(v.number(), v.finite(), v.toMinValue(MINIMUM_CONTRAST), v.toMaxValue(MAXIMUM_CONTRAST)),\n  ),\n  undefined,\n)\n\nconst schemeOptionsSchema = v.pipe(\n  v.object({\n    accent: optionalColor,\n    text: optionalColor,\n    background: optionalColor,\n    contrast: optionalContrast,\n  }),\n  v.transform((options): SchemeThemeOptions => compact(options)),\n)\n\n/** Options grouped by scheme, as they are today — a scheme without usable options is left out */\nconst groupedOptionsSchema = v.pipe(\n  v.looseObject({\n    light: v.fallback(v.optional(schemeOptionsSchema), undefined),\n    dark: v.fallback(v.optional(schemeOptionsSchema), undefined),\n  }),\n  // The flat shape of earlier versions always had an accent at the top\n  v.check((input) => !('accent' in input), 'flat options'),\n  v.transform(({light, dark}): BuildThemeOptions => {\n    const options: BuildThemeOptions = {}\n\n    if (light && Object.keys(light).length > 0) options.light = light\n    if (dark && Object.keys(dark).length > 0) options.dark = dark\n\n    return options\n  }),\n)\n\n/**\n * Options from before they were grouped by scheme: one accent, text color and\n * contrast for both schemes, and a background per scheme. Both schemes get\n * the shared colors, so the theme keeps looking the same.\n */\nconst flatOptionsSchema = v.pipe(\n  v.object({\n    accent: color,\n    text: optionalColor,\n    contrast: optionalContrast,\n    background: v.fallback(\n      v.optional(v.object({light: optionalColor, dark: optionalColor})),\n      undefined,\n    ),\n  }),\n  v.transform(({accent, text, contrast, background}): BuildThemeOptions => {\n    const shared: SchemeThemeOptions = compact({accent, text, contrast})\n    const options: BuildThemeOptions = {}\n\n    for (const scheme of SCHEMES) {\n      const schemeBackground = background?.[scheme]\n\n      options[scheme] = schemeBackground ? {...shared, background: schemeBackground} : {...shared}\n    }\n\n    return options\n  }),\n)\n\n/** The `buildTheme` options of a theme, in today's shape or an earlier version's @internal */\nexport const themeOptionsSchema = v.union([flatOptionsSchema, groupedOptionsSchema])\n\n/** A swatch of an image palette — `null` when it is missing or not a color */\nconst swatch = v.fallback(v.optional(v.nullable(color), null), null)\n\n/** The palette a theme took its colors from — `null` without a single swatch */\nconst paletteSchema = v.pipe(\n  v.object({\n    vibrant: swatch,\n    lightVibrant: swatch,\n    darkVibrant: swatch,\n    muted: swatch,\n    lightMuted: swatch,\n    darkMuted: swatch,\n    dominant: swatch,\n  }),\n  v.transform((palette): ImagePalette | null =>\n    Object.values(palette).some((item) => item !== null) ? palette : null,\n  ),\n)\n\nfunction isReservedSlug(slug: string): boolean {\n  return slug === CONFIG_SLUG || presets.some((preset) => preset.slug === slug)\n}\n\nconst customThemeSchema = v.pipe(\n  v.object({\n    slug: v.pipe(\n      v.string(),\n      v.nonEmpty(),\n      v.check((slug) => !isReservedSlug(slug), 'reserved slug'),\n    ),\n    title: v.fallback(v.optional(v.string()), undefined),\n    options: themeOptionsSchema,\n    palette: v.fallback(v.optional(paletteSchema), undefined),\n  }),\n  v.transform(({slug, title, options, palette}): CustomTheme => ({\n    slug,\n    title: displayTitle(title ?? ''),\n    options,\n    ...(palette ? {palette} : {}),\n  })),\n)\n\n/** The items of a list that can be used, each parsed on its own so that one bad item does not fail the rest */\nconst lenientList = v.fallback(v.optional(v.array(v.unknown()), []), [])\n\n/**\n * The persisted themer state — the applied theme, the user's themes and\n * what was removed and reordered — as it is read back. Custom themes that\n * cannot be used, repeated slugs, and removed or ordered slugs that name no\n * theme are dropped.\n */\nconst themerStateSchema = v.pipe(\n  v.object({\n    active: v.fallback(v.nullable(v.string()), null),\n    custom: lenientList,\n    removed: lenientList,\n    order: lenientList,\n  }),\n  v.transform((state): ThemerState => {\n    const custom: CustomTheme[] = []\n\n    for (const item of state.custom) {\n      const result = v.safeParse(customThemeSchema, item)\n\n      if (result.success && !custom.some((theme) => theme.slug === result.output.slug)) {\n        custom.push(result.output)\n      }\n    }\n\n    const isCustom = (slug: string) => custom.some((theme) => theme.slug === slug)\n    const isPreset = (slug: string) => presets.some((preset) => preset.slug === slug)\n    const removed: string[] = []\n    const order: string[] = []\n\n    for (const slug of state.removed) {\n      if (typeof slug !== 'string' || slug === CONFIG_SLUG || removed.includes(slug)) continue\n      if (isPreset(slug) || isCustom(slug)) removed.push(slug)\n    }\n    for (const slug of state.order) {\n      if (typeof slug !== 'string' || order.includes(slug)) continue\n      if (slug === CONFIG_SLUG || isPreset(slug) || isCustom(slug)) order.push(slug)\n    }\n\n    return {active: state.active, custom, removed, order}\n  }),\n)\n\n/** The persisted themer state, or `null` for anything else @internal */\nexport function parseThemerState(input: unknown): ThemerState | null {\n  const result = v.safeParse(themerStateSchema, input)\n\n  return result.success ? result.output : null\n}\n\n/** The flows a session restores to */\nconst flowSchema = v.picklist(['list', 'edit', 'removed'])\n\n/**\n * The machine's state value, as persisted — only what the machine has states\n * for restores. The list's dialogs are states of the list, so a snapshot\n * written while one was open names it; the dialog does not reopen\n */\nconst snapshotValueSchema = v.object({\n  flow: v.union([flowSchema, v.object({list: v.picklist(['idle', 'pasting', 'snippet'])})]),\n  theme: v.picklist(['applied', 'switching']),\n})\n\n/**\n * The machine's persisted snapshot, as `getPersistedSnapshot()` writes it and\n * `createActor` restores it — `status`, `value`, `context`, `historyValue`\n * and `children`, with `output` and `error` left out as `undefined`.\n *\n * @internal\n */\nexport interface PersistedThemerSnapshot {\n  status: 'active'\n  output: undefined\n  error: undefined\n  value: {flow: v.InferOutput<typeof flowSchema>; theme: 'applied' | 'switching'}\n  context: ThemerMachineContext\n  historyValue: Record<string, never>\n  children: Record<string, never>\n}\n\n/**\n * A snapshot for the machine to start a session from: the given themes, with\n * nothing being switched to, in the list unless a flow and its subject are\n * given. It is how the themes alone — all that earlier versions persisted —\n * are handed to a machine that only restores snapshots, and what a restored\n * snapshot is made fit for this session as.\n *\n * @internal\n */\nexport function snapshotFromState(\n  state: ThemerState,\n  editing: ThemerMachineContext['editing'] = null,\n  flow: PersistedThemerSnapshot['value']['flow'] = 'list',\n): PersistedThemerSnapshot {\n  return {\n    status: 'active',\n    output: undefined,\n    error: undefined,\n    value: {flow, theme: 'applied'},\n    context: {...state, editing, images: {}},\n    historyValue: {},\n    children: {},\n  }\n}\n\n/**\n * The machine's snapshot as the last session persisted it, made fit for this\n * one: the themes are parsed like any persisted state, the flow keeps its\n * subject or falls back to the list, a dialog that was open is closed, a\n * switch that was under way is over, and the image URLs of the last session\n * are gone with it.\n *\n * @internal\n */\nexport const persistedSnapshotSchema = v.pipe(\n  v.object({\n    status: v.literal('active'),\n    value: snapshotValueSchema,\n    context: v.pipe(\n      v.looseObject({\n        editing: v.fallback(\n          v.nullable(v.object({slug: v.string(), focusTitle: v.boolean()})),\n          null,\n        ),\n      }),\n      v.transform(({editing, ...state}) => ({editing, state: parseThemerState(state)})),\n      v.check(({state}) => state !== null, 'no themes'),\n    ),\n  }),\n  v.transform(({value, context}): PersistedThemerSnapshot => {\n    // Checked above, but the type does not know\n    const state = context.state ?? {active: null, custom: [], removed: [], order: []}\n    const editing =\n      context.editing &&\n      state.custom.some((theme) => theme.slug === context.editing?.slug) &&\n      !state.removed.includes(context.editing.slug)\n        ? context.editing\n        : null\n    const flow =\n      typeof value.flow !== 'string' ||\n      (value.flow === 'edit' && editing === null) ||\n      (value.flow === 'removed' && state.removed.length === 0)\n        ? 'list'\n        : value.flow\n\n    return snapshotFromState(state, editing, flow)\n  }),\n)\n","import * as v from 'valibot'\nimport type {Snapshot} from 'xstate'\n\nimport {\n  parseThemerState,\n  type PersistedThemerSnapshot,\n  persistedSnapshotSchema,\n  snapshotFromState,\n  themeOptionsSchema,\n} from './schemas'\nimport type {CustomTheme} from './themes'\n\n/** Where the machine's snapshot is kept between sessions */\nconst SNAPSHOT_STORAGE_KEY = 'sanityStudio:themer:snapshot'\n\n/**\n * Where earlier versions kept the persisted state — the applied theme, the\n * user's themes and what was removed and reordered — before the machine's\n * whole snapshot was persisted. Read until the first snapshot is written.\n */\nconst STATE_STORAGE_KEY = 'sanityStudio:themer:state'\n\n/**\n * Where the earliest versions of the tool kept their single draft theme — it\n * is migrated into a custom theme, so a draft survives the upgrade.\n */\nconst LEGACY_STORAGE_KEY = 'sanityStudio:themer:options'\n\n/**\n * What the draft of the earliest versions is imported as — the same theme\n * whichever tab reads it first, so that tabs upgrading side by side agree\n */\nconst LEGACY_DRAFT: Omit<CustomTheme, 'options'> = {slug: 'custom-draft', title: 'Draft theme'}\n\nfunction readJson(key: string): unknown {\n  const raw = localStorage.getItem(key)\n\n  return raw ? JSON.parse(raw) : undefined\n}\n\n/**\n * Restores the machine's snapshot from what the last session persisted, for\n * `createActor` to start from, so the user's themes survive Studio reloads:\n * the snapshot itself where there is one that fits, and one made from the\n * themes alone where the snapshot no longer fits the machine or where\n * earlier versions of the tool stored the themes without a snapshot.\n * `undefined` when nothing usable is stored — or storage cannot be read at\n * all — leaves the machine to start from no themes.\n *\n * The parsing is the schemas' (see `schemas.ts`): nothing here or in the\n * machine looks at what is stored beyond handing it over.\n *\n * @internal\n */\nexport function readPersistedSnapshot(): PersistedThemerSnapshot | undefined {\n  try {\n    if (typeof localStorage === 'undefined') return undefined\n\n    const persisted = readJson(SNAPSHOT_STORAGE_KEY)\n\n    if (persisted !== undefined) {\n      const snapshot = v.safeParse(persistedSnapshotSchema, persisted)\n\n      if (snapshot.success) return snapshot.output\n\n      // A snapshot from a version of the machine with other states still\n      // holds the themes, which is what matters\n      const state = parseThemerState(\n        persisted && typeof persisted === 'object' ? Reflect.get(persisted, 'context') : undefined,\n      )\n\n      if (state) return snapshotFromState(state)\n    }\n\n    const state = parseThemerState(readJson(STATE_STORAGE_KEY))\n\n    if (state) return snapshotFromState(state)\n\n    return readLegacyDraft()\n  } catch {\n    return undefined\n  }\n}\n\nfunction readLegacyDraft(): PersistedThemerSnapshot | undefined {\n  const options = v.safeParse(themeOptionsSchema, readJson(LEGACY_STORAGE_KEY))\n\n  if (!options.success) return undefined\n\n  const theme: CustomTheme = {...LEGACY_DRAFT, options: options.output}\n\n  return snapshotFromState({active: theme.slug, custom: [theme], removed: [], order: []})\n}\n\n/**\n * Persists the machine's snapshot for the next session, and lets go of what\n * earlier versions stored once it is written — which completes their\n * migration.\n *\n * @internal\n */\nexport function writePersistedSnapshot(snapshot: Snapshot<unknown>): void {\n  try {\n    if (typeof localStorage === 'undefined') return\n\n    localStorage.setItem(SNAPSHOT_STORAGE_KEY, JSON.stringify(snapshot))\n    localStorage.removeItem(STATE_STORAGE_KEY)\n    localStorage.removeItem(LEGACY_STORAGE_KEY)\n  } catch {\n    // Storage can be unavailable (e.g. private browsing) — themes just won't persist\n  }\n}\n","import {assign, not, setup, type SnapshotFrom} from 'xstate'\n\nimport type {BuildThemeOptions} from '../theme/options'\nimport type {ImagePalette} from './imagePalette'\nimport {\n  CONFIG_SLUG,\n  CONFIG_TITLE,\n  createCustomTheme,\n  duplicateTitle,\n  initialThemerState,\n  resolveThemes,\n  type ThemerState,\n  UNTITLED_THEME,\n} from './themes'\n\n/**\n * How long the machine stays `switching` after an event that applies another\n * theme, when no edit to the applied theme ends it sooner. The layout\n * cross-fades the Studio to the theme in the commit that follows the switch,\n * so this only bounds how long the tag lingers once that is done. Generous,\n * so that it never runs out before a slow deferred commit starts the fade.\n *\n * @internal\n */\nexport const MOTION_DURATION = 2000\n\n/** @internal */\nexport interface ThemerMachineContext extends ThemerState {\n  /** The theme open in the editor, while the `flow` is `edit` */\n  editing: {\n    slug: string\n    /** Whether the title input should take focus, for themes that were just created */\n    focusTitle: boolean\n  } | null\n  /**\n   * Object URLs of the images that themes took their palette from, by theme\n   * slug — kept for the session only, so the image can be shown right after\n   * it was picked\n   */\n  images: Record<string, string>\n}\n\n/** @internal */\nexport type ThemerEvent =\n  /** Applies a theme to the whole Studio */\n  | {type: 'theme.pick'; slug: string}\n  /**\n   * Adds a theme and opens it in the editor — based on the applied theme, or\n   * on the given title, options and image palette (e.g. from an image)\n   */\n  | {\n      type: 'theme.add'\n      title?: string\n      options?: BuildThemeOptions\n      palette?: ImagePalette\n      imageUrl?: string\n    }\n  /** Adds a copy of a theme and opens it in the editor */\n  | {type: 'theme.duplicate'; slug: string}\n  /** Adds a theme someone shared as a code, and applies it — staying in the list */\n  | {type: 'theme.import'; title: string; options: BuildThemeOptions}\n  /** Opens one of the user's own themes in the editor */\n  | {type: 'theme.edit'; slug: string}\n  | {\n      type: 'theme.update'\n      slug: string\n      title?: string\n      options?: BuildThemeOptions\n      palette?: ImagePalette\n      imageUrl?: string\n    }\n  /** Takes a theme out of the list — it can be restored until it is deleted */\n  | {type: 'theme.remove'; slug: string}\n  /** Puts a removed theme back in the list */\n  | {type: 'theme.restore'; slug: string}\n  /** Deletes one of the user's own themes for good */\n  | {type: 'theme.delete'; slug: string}\n  /** Rearranges the list: the slugs of the listed themes, in their new order */\n  | {type: 'theme.reorder'; order: string[]}\n  /** Back to picking a theme */\n  | {type: 'flow.list'}\n  /** On to restoring removed themes */\n  | {type: 'flow.removed'}\n  /** Opens the dialog for adding a shared theme code by hand, from the list */\n  | {type: 'dialog.paste'}\n  /** Opens the dialog with the applied theme's `buildTheme` snippet, from the list */\n  | {type: 'dialog.snippet'}\n  /** Closes whichever dialog is open */\n  | {type: 'dialog.close'}\n  /**\n   * Takes over the persisted state as another tab of the same Studio changed\n   * it, so that every tab shows the same themes (see `sync.ts`)\n   */\n  | {type: 'themes.sync'; state: ThemerState}\n\nfunction themesOf(context: ThemerMachineContext) {\n  return resolveThemes(context)\n}\n\nfunction revokeObjectUrl(url: string) {\n  if (typeof URL !== 'undefined' && typeof URL.revokeObjectURL === 'function') {\n    URL.revokeObjectURL(url)\n  }\n}\n\n/**\n * The themes of the themer tool and the sidebar's way through them: which\n * `flow` the sidebar is in — picking a theme from the `list`, with its\n * dialogs for pasting a shared code and for the applied theme's snippet,\n * `edit`ing one of the user's own themes, or restoring `removed` ones — and,\n * in a parallel `theme` region, whether another theme was just applied. The\n * context carries the persisted state (the applied theme, the user's themes\n * and what was removed) alongside what the flows need. Whether the sidebar is\n * open and whether the Studio shows twice is not the machine's: the tool\n * reducer in `ThemerProvider` owns that, so that the navbar toggle and the\n * sidebar can change it in transitions of their own. Nor is persisting: the\n * machine never touches storage and takes no input — it starts from no\n * themes, and a session with something to pick up from restores its\n * persisted snapshot instead (see `storage.ts` and `sync.ts`), while the\n * persisted state of other tabs reaches it as a `themes.sync` event like any\n * other.\n *\n * The `theme` region is `switching` (its tag) right after an event that\n * applies another theme — picking one, adding, duplicating, importing or\n * editing one, removing or deleting the applied one — which is when the\n * layout cross-fades the Studio to it. Edits to the applied theme's colors are\n * not switches, they follow the pointer: the first one ends the switch, and so\n * does `MOTION_DURATION` when none follows.\n *\n * Theme operations are handled in every flow, and the flows leave on their\n * own when they lose their subject: the editor when its theme is removed or\n * deleted, and the removed view when its last theme is restored or deleted.\n *\n * @internal\n */\nexport const themerMachine = setup({\n  // XState reads `types` for their types only — the values are never used\n  types: {\n    // oxlint-disable-next-line no-unsafe-type-assertion -- type-level placeholder\n    context: {} as ThemerMachineContext,\n    // oxlint-disable-next-line no-unsafe-type-assertion -- type-level placeholder\n    events: {} as ThemerEvent,\n  },\n  guards: {\n    isCustomTheme: ({context}, params: {slug: string}) =>\n      themesOf(context).themes.some(\n        (theme) => theme.slug === params.slug && theme.source === 'custom',\n      ),\n    isEditingListedTheme: ({context}) =>\n      context.editing !== null &&\n      themesOf(context).themes.some(\n        (theme) => theme.slug === context.editing?.slug && theme.source === 'custom',\n      ),\n    hasRemovedThemes: ({context}) => themesOf(context).removed.length > 0,\n    // The configured theme has no code to show — it is the Studio's own\n    hasAppliedTheme: ({context}) => themesOf(context).active !== undefined,\n    // Only another theme than the applied one changes anything to cross-fade to\n    isAnotherTheme: ({context}, params: {slug: string}) =>\n      params.slug !== (context.active ?? CONFIG_SLUG),\n    // Removing or deleting the applied theme is what changes the applied theme\n    isAppliedTheme: ({context}, params: {slug: string}) => params.slug === context.active,\n    // Another tab applied another theme, which is as much of a switch as picking it here\n    appliesAnotherTheme: ({context}, params: {state: ThemerState}) =>\n      params.state.active !== context.active,\n    // A theme added from given options (an image's) looks different from the applied one\n    hasOptions: (_, params: {options: BuildThemeOptions | undefined}) =>\n      params.options !== undefined,\n  },\n  actions: {\n    // Another tab's persisted state replaces this one's: themes, order and\n    // all. The images of this session stay, they are this tab's\n    sync: assign((_, params: {state: ThemerState}) => ({\n      active: params.state.active,\n      custom: params.state.custom,\n      removed: params.state.removed,\n      order: params.state.order,\n    })),\n    // The image of a replaced palette or a deleted theme is released from memory\n    revokeImage: (_, params: {url: string | undefined}) => {\n      if (params.url) revokeObjectUrl(params.url)\n    },\n    pick: assign((_, params: {slug: string}) => ({\n      active: params.slug === CONFIG_SLUG ? null : params.slug,\n    })),\n    add: assign(\n      (\n        {context},\n        params: {\n          title?: string\n          options?: BuildThemeOptions\n          palette?: ImagePalette\n          imageUrl?: string\n        },\n      ) => {\n        // Based on the applied theme — the stock one when the configured\n        // theme applies, which is not in the list\n        const theme = createCustomTheme(\n          params.title ?? UNTITLED_THEME,\n          params.options ?? themesOf(context).active?.options ?? {},\n          params.palette,\n        )\n\n        return {\n          active: theme.slug,\n          custom: [...context.custom, theme],\n          // A theme named after its image needs no renaming right away\n          editing: {slug: theme.slug, focusTitle: params.title === undefined},\n          images: params.imageUrl\n            ? {...context.images, [theme.slug]: params.imageUrl}\n            : context.images,\n        }\n      },\n    ),\n    import: assign(({context}, params: {title: string; options: BuildThemeOptions}) => {\n      const theme = createCustomTheme(params.title, params.options)\n\n      return {active: theme.slug, custom: [...context.custom, theme]}\n    }),\n    duplicate: assign(({context}, params: {slug: string}) => {\n      const {themes, removed} = themesOf(context)\n      // The configured theme is not in the list: a copy of it starts from the\n      // stock options, as the Studio shows it\n      const source =\n        params.slug === CONFIG_SLUG\n          ? {title: CONFIG_TITLE, options: {}, palette: undefined}\n          : [...themes, ...removed].find((theme) => theme.slug === params.slug)\n\n      if (!source) return {}\n\n      const theme = createCustomTheme(duplicateTitle(source.title), source.options, source.palette)\n\n      return {\n        active: theme.slug,\n        custom: [...context.custom, theme],\n        editing: {slug: theme.slug, focusTitle: true},\n      }\n    }),\n    startEditing: assign((_, params: {slug: string}) => ({\n      active: params.slug,\n      editing: {slug: params.slug, focusTitle: false},\n    })),\n    stopEditing: assign({editing: null}),\n    update: assign(\n      (\n        {context},\n        params: {\n          slug: string\n          title?: string\n          options?: BuildThemeOptions\n          palette?: ImagePalette\n          imageUrl?: string\n        },\n      ) => ({\n        custom: context.custom.map((theme) => {\n          if (theme.slug !== params.slug) return theme\n\n          // Keep the options identity when only the title changes, so the\n          // applied theme is not rebuilt on every keystroke\n          return {\n            ...theme,\n            title: params.title ?? theme.title,\n            options: params.options ?? theme.options,\n            ...(params.palette ? {palette: params.palette} : {}),\n          }\n        }),\n        images:\n          params.imageUrl && context.custom.some((theme) => theme.slug === params.slug)\n            ? {...context.images, [params.slug]: params.imageUrl}\n            : context.images,\n      }),\n    ),\n    remove: assign(({context}, params: {slug: string}) => {\n      if (params.slug === CONFIG_SLUG || context.removed.includes(params.slug)) return {}\n\n      return {\n        active: context.active === params.slug ? null : context.active,\n        removed: [...context.removed, params.slug],\n      }\n    }),\n    restore: assign(({context}, params: {slug: string}) => ({\n      removed: context.removed.filter((slug) => slug !== params.slug),\n    })),\n    reorder: assign(({context}, params: {order: string[]}) => {\n      const listed = new Set(themesOf(context).themes.map((theme) => theme.slug))\n      const order = params.order.filter((slug) => listed.has(slug))\n\n      // The removed themes keep their place in line for when they are restored\n      return {\n        order: [...order, ...context.order.filter((slug) => !order.includes(slug))],\n      }\n    }),\n    delete: assign(({context}, params: {slug: string}) => {\n      if (!context.custom.some((theme) => theme.slug === params.slug)) return {}\n\n      const {[params.slug]: _deleted, ...images} = context.images\n\n      return {\n        active: context.active === params.slug ? null : context.active,\n        custom: context.custom.filter((theme) => theme.slug !== params.slug),\n        removed: context.removed.filter((slug) => slug !== params.slug),\n        images,\n      }\n    }),\n  },\n}).createMachine({\n  id: 'themer',\n  context: () => ({...initialThemerState, editing: null, images: {}}),\n  type: 'parallel',\n  states: {\n    theme: {\n      initial: 'applied',\n      states: {\n        // Only events that change what is applied count: adding a copy of the\n        // applied theme, editing or duplicating it, picking it again, or\n        // removing another theme leaves the Studio looking the same — with\n        // nothing to cross-fade, the switch would only linger until the first\n        // edit that followed, which must follow the pointer\n        applied: {\n          on: {\n            'theme.pick': {\n              guard: {type: 'isAnotherTheme', params: ({event}) => ({slug: event.slug})},\n              target: 'switching',\n            },\n            'theme.edit': {\n              guard: {type: 'isAnotherTheme', params: ({event}) => ({slug: event.slug})},\n              target: 'switching',\n            },\n            'theme.duplicate': {\n              guard: {type: 'isAnotherTheme', params: ({event}) => ({slug: event.slug})},\n              target: 'switching',\n            },\n            'theme.remove': {\n              guard: {type: 'isAppliedTheme', params: ({event}) => ({slug: event.slug})},\n              target: 'switching',\n            },\n            'theme.delete': {\n              guard: {type: 'isAppliedTheme', params: ({event}) => ({slug: event.slug})},\n              target: 'switching',\n            },\n            'theme.add': {\n              guard: {type: 'hasOptions', params: ({event}) => ({options: event.options})},\n              target: 'switching',\n            },\n            'theme.import': 'switching',\n            'themes.sync': {\n              guard: {type: 'appliesAnotherTheme', params: ({event}) => ({state: event.state})},\n              target: 'switching',\n            },\n          },\n        },\n        switching: {\n          tags: ['switching'],\n          after: {[MOTION_DURATION]: 'applied'},\n          on: {\n            // The editor edits the applied theme, and its colors must follow\n            // the pointer rather than cross-fade — a switch is over at the\n            // first edit, however soon it comes\n            'theme.update': 'applied',\n            // Another switch starts the clock over\n            'theme.pick': {\n              guard: {type: 'isAnotherTheme', params: ({event}) => ({slug: event.slug})},\n              target: 'switching',\n              reenter: true,\n            },\n            'theme.edit': {\n              guard: {type: 'isAnotherTheme', params: ({event}) => ({slug: event.slug})},\n              target: 'switching',\n              reenter: true,\n            },\n            'theme.duplicate': {\n              guard: {type: 'isAnotherTheme', params: ({event}) => ({slug: event.slug})},\n              target: 'switching',\n              reenter: true,\n            },\n            'theme.remove': {\n              guard: {type: 'isAppliedTheme', params: ({event}) => ({slug: event.slug})},\n              target: 'switching',\n              reenter: true,\n            },\n            'theme.delete': {\n              guard: {type: 'isAppliedTheme', params: ({event}) => ({slug: event.slug})},\n              target: 'switching',\n              reenter: true,\n            },\n            'theme.add': {\n              guard: {type: 'hasOptions', params: ({event}) => ({options: event.options})},\n              target: 'switching',\n              reenter: true,\n            },\n            'theme.import': {target: 'switching', reenter: true},\n            'themes.sync': {\n              guard: {type: 'appliesAnotherTheme', params: ({event}) => ({state: event.state})},\n              target: 'switching',\n              reenter: true,\n            },\n          },\n        },\n      },\n    },\n    flow: {\n      initial: 'list',\n      on: {\n        'theme.pick': {\n          actions: [{type: 'pick', params: ({event}) => ({slug: event.slug})}],\n        },\n        'theme.add': {\n          target: '.edit',\n          actions: [\n            {\n              type: 'add',\n              params: ({event}) => ({\n                title: event.title,\n                options: event.options,\n                palette: event.palette,\n                imageUrl: event.imageUrl,\n              }),\n            },\n          ],\n        },\n        'theme.duplicate': {\n          target: '.edit',\n          actions: [{type: 'duplicate', params: ({event}) => ({slug: event.slug})}],\n        },\n        'theme.edit': {\n          target: '.edit',\n          guard: {type: 'isCustomTheme', params: ({event}) => ({slug: event.slug})},\n          actions: [{type: 'startEditing', params: ({event}) => ({slug: event.slug})}],\n        },\n        'theme.update': {\n          actions: [\n            // A new image replaces the one the theme had\n            {\n              type: 'revokeImage',\n              params: ({context, event}) => ({\n                url: event.imageUrl ? context.images[event.slug] : undefined,\n              }),\n            },\n            {\n              type: 'update',\n              params: ({event}) => ({\n                slug: event.slug,\n                title: event.title,\n                options: event.options,\n                palette: event.palette,\n                imageUrl: event.imageUrl,\n              }),\n            },\n          ],\n        },\n        'theme.remove': {\n          actions: [{type: 'remove', params: ({event}) => ({slug: event.slug})}],\n        },\n        'theme.restore': {\n          actions: [{type: 'restore', params: ({event}) => ({slug: event.slug})}],\n        },\n        'theme.delete': {\n          actions: [\n            {\n              type: 'revokeImage',\n              params: ({context, event}) => ({url: context.images[event.slug]}),\n            },\n            {type: 'delete', params: ({event}) => ({slug: event.slug})},\n          ],\n        },\n        'theme.reorder': {\n          actions: [{type: 'reorder', params: ({event}) => ({order: event.order})}],\n        },\n        'theme.import': {\n          actions: [\n            {\n              type: 'import',\n              params: ({event}) => ({title: event.title, options: event.options}),\n            },\n          ],\n        },\n        'themes.sync': {\n          actions: {type: 'sync', params: ({event}) => ({state: event.state})},\n        },\n        'flow.list': '.list',\n        'flow.removed': {\n          target: '.removed',\n          guard: 'hasRemovedThemes',\n        },\n      },\n      states: {\n        list: {\n          initial: 'idle',\n          // The list's dialogs — for a shared code pasted by hand, and for the\n          // applied theme's snippet — are states of the list, so that leaving\n          // it, as adding a theme does for the editor, closes them\n          states: {\n            idle: {\n              on: {\n                'dialog.paste': 'pasting',\n                'dialog.snippet': {guard: 'hasAppliedTheme', target: 'snippet'},\n              },\n            },\n            pasting: {\n              on: {'dialog.close': 'idle'},\n            },\n            snippet: {\n              on: {'dialog.close': 'idle'},\n              // The applied theme can go away meanwhile — removed from another tab\n              always: {guard: not('hasAppliedTheme'), target: 'idle'},\n            },\n          },\n        },\n        edit: {\n          exit: 'stopEditing',\n          // The theme being edited can go away — removed from the editor, or\n          // duplicated from a theme that does not exist — and then there is\n          // nothing left to edit\n          always: {guard: not('isEditingListedTheme'), target: 'list'},\n        },\n        removed: {\n          always: {guard: not('hasRemovedThemes'), target: 'list'},\n        },\n      },\n    },\n  },\n})\n\n/** @internal */\nexport type ThemerSnapshot = SnapshotFrom<typeof themerMachine>\n\n/** The part of the machine context that is persisted between sessions @internal */\nexport function selectStoredState(snapshot: ThemerSnapshot): ThemerState {\n  const {active, custom, removed, order} = snapshot.context\n\n  return {active, custom, removed, order}\n}\n","import {dequal} from 'dequal/lite'\nimport type {ActorRefFrom, Snapshot} from 'xstate'\n\nimport {selectStoredState, type themerMachine} from './machine'\nimport {parseThemerState} from './schemas'\nimport type {ThemerState} from './themes'\n\n/** The channel every tab of the same origin shares — one Studio, one set of themes */\nconst CHANNEL_NAME = 'sanity-themer'\n\n/**\n * The lock the one tab that persists holds for as long as it lives. The\n * other tabs queue for it, so when that tab goes away the next one in line\n * takes over the persisting — nothing is ever written from two tabs at once\n */\nconst LOCK_NAME = 'sanity-themer:persist'\n\n/** How long a persist waits for the browser to be idle before it goes ahead anyway */\nconst PERSIST_TIMEOUT = 1_000\n\n/**\n * What the tabs tell each other. Every change to the persisted state goes\n * around as `state`, with the `revision` it brings the state to — one more\n * than the last one the tab heard of — and the tab it is `from`: a tab takes\n * a state only when it is newer than the one it has, ties going to the\n * higher tab id, so that two tabs changing at once end up with the same\n * state rather than each other's. A tab that just started asks for the\n * current state with `hello`, answered with a `state` addressed `to` it,\n * which only it takes, and only while it has changed nothing of its own yet\n * — a change it made meanwhile goes around again instead, ahead of the\n * answer, so that a late answer never undoes it\n */\ntype SyncMessage =\n  | {type: 'hello'; from: string}\n  | {type: 'state'; state: ThemerState; revision: number; from: string; to?: string}\n\n/** What the sync needs of a `BroadcastChannel` @internal */\nexport interface SyncChannel {\n  /** Sends a message to the other tabs — not to this one */\n  post(message: unknown): void\n  /** Hears the other tabs' messages; returns what stops listening */\n  listen(listener: (data: unknown) => void): () => void\n  close(): void\n}\n\n/** What the sync needs of `navigator.locks` @internal */\nexport interface SyncLocks {\n  request(\n    name: string,\n    options: {signal?: AbortSignal},\n    callback: () => Promise<unknown>,\n  ): Promise<unknown>\n}\n\n/**\n * What the sync does with the browser, each replaceable — so that it can run\n * under test, and so that it degrades where a browser lacks an API: without\n * a channel the tabs do not hear of each other, and without locks every tab\n * persists for itself\n *\n * @internal\n */\nexport interface ThemerSyncOptions {\n  /** Persists the machine's snapshot — from the one tab that holds the lock */\n  persist: (snapshot: Snapshot<unknown>) => void\n  /** Opens the channel to the other tabs, or `null` where there is none */\n  openChannel?: () => SyncChannel | null\n  /** Elects the tab that persists, or `undefined` where there is no lock manager */\n  locks?: SyncLocks | undefined\n  /** Defers a persist to an idle moment; returns what cancels it */\n  schedule?: (callback: () => void) => () => void\n}\n\nfunction openBroadcastChannel(): SyncChannel | null {\n  if (typeof BroadcastChannel !== 'function') return null\n\n  const channel = new BroadcastChannel(CHANNEL_NAME)\n\n  return {\n    // oxlint-disable-next-line require-post-message-target-origin -- a BroadcastChannel is same-origin by nature, its postMessage takes no target\n    post: (message) => channel.postMessage(message),\n    listen: (listener) => {\n      const onMessage = (event: MessageEvent) => listener(event.data)\n\n      channel.addEventListener('message', onMessage)\n\n      return () => channel.removeEventListener('message', onMessage)\n    },\n    close: () => channel.close(),\n  }\n}\n\nfunction browserLocks(): SyncLocks | undefined {\n  // Web Locks need a secure context, where `navigator.locks` is undefined otherwise\n  return typeof navigator !== 'undefined' && 'locks' in navigator ? navigator.locks : undefined\n}\n\nfunction scheduleIdle(callback: () => void): () => void {\n  if (typeof requestIdleCallback === 'function') {\n    const id = requestIdleCallback(callback, {timeout: PERSIST_TIMEOUT})\n\n    return () => cancelIdleCallback(id)\n  }\n\n  const id = setTimeout(callback, PERSIST_TIMEOUT)\n\n  return () => clearTimeout(id)\n}\n\nfunction parseMessage(data: unknown): SyncMessage | null {\n  if (!data || typeof data !== 'object') return null\n\n  const type: unknown = Reflect.get(data, 'type')\n\n  if (type === 'hello') {\n    const from: unknown = Reflect.get(data, 'from')\n\n    return typeof from === 'string' ? {type, from} : null\n  }\n\n  if (type === 'state') {\n    const state = parseThemerState(Reflect.get(data, 'state'))\n    const revision: unknown = Reflect.get(data, 'revision')\n    const from: unknown = Reflect.get(data, 'from')\n    const to: unknown = Reflect.get(data, 'to')\n\n    if (!state || typeof revision !== 'number' || !Number.isFinite(revision)) return null\n    if (typeof from !== 'string') return null\n\n    return {type, state, revision, from, ...(typeof to === 'string' ? {to} : {})}\n  }\n\n  return null\n}\n\nfunction tabId(): string {\n  return typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n    ? crypto.randomUUID()\n    : Math.random().toString(36).slice(2)\n}\n\n/**\n * Keeps the themes of every tab of the Studio the same, and persists them\n * from one tab only.\n *\n * Every tab runs its own machine, and what the machine persists — the\n * applied theme, the user's themes, what was removed and reordered — goes\n * around to the other tabs on a `BroadcastChannel` as it changes, where it\n * reaches their machines as a `themes.sync` event: the same themes\n * everywhere, with the flow each tab is in, the tool's open and split state\n * (the reducer's, in `plugin.tsx`) and the images of this session staying\n * the tab's own. A tab that starts asks the others for the current state,\n * in case what it read from storage was not written yet.\n *\n * Persisting is the business of one tab at a time: the one holding the Web\n * Lock, which it keeps for as long as it lives. The others queue for it, so\n * the next tab takes over as the holder goes away, and a tab that takes\n * over persists right away, in case the last one left with a write pending.\n * Writes happen when the browser is idle — a run of edits is written once —\n * and as the page hides, so that nothing pending is lost.\n *\n * Returns what stops the sync: it lets go of the lock, which hands the\n * persisting on, and closes the channel.\n *\n * @internal\n */\nexport function syncThemer(\n  actorRef: ActorRefFrom<typeof themerMachine>,\n  options: ThemerSyncOptions,\n): () => void {\n  const {persist, openChannel = openBroadcastChannel, schedule = scheduleIdle} = options\n  const channel = openChannel()\n  // Without a channel the tabs cannot hear of each other's changes, so each\n  // persists its own — a lock would only silence the tabs not holding it.\n  // Given as `undefined` means no lock manager, not the browser's: Node has\n  // one too these days\n  const locks = channel ? ('locks' in options ? options.locks : browserLocks()) : undefined\n  const id = tabId()\n  const abort = new AbortController()\n  let leader = false\n  let cancelPersist: (() => void) | undefined\n  /** Whether another tab's state is being sent into the machine, which is nothing to pass on */\n  let applying = false\n  /** The persisted state as the other tabs last heard it from this one, or this one from them */\n  let shared = selectStoredState(actorRef.getSnapshot())\n  /** The revision `shared` is at, and the tab whose change it was */\n  let revision = 0\n  let origin = id\n  /** Whether this tab still has what it started with, so that an answer to its `hello` is welcome */\n  let unchanged = true\n  /** The tabs that said hello before this one held the lock, to answer once it does */\n  const unanswered = new Set<string>()\n\n  const isNewer = (message: {revision: number; from: string}) =>\n    message.revision > revision || (message.revision === revision && message.from > origin)\n\n  const persistNow = () => {\n    cancelPersist?.()\n    cancelPersist = undefined\n    persist(actorRef.getPersistedSnapshot())\n  }\n  const persistSoon = () => {\n    cancelPersist?.()\n    cancelPersist = schedule(persistNow)\n  }\n  const answer = (to: string) => {\n    channel?.post({type: 'state', state: shared, revision, from: origin, to} satisfies SyncMessage)\n  }\n  const becomeLeader = () => {\n    leader = true\n    persistNow()\n    // Tabs that started alongside this one asked before anyone held the lock\n    for (const from of unanswered) answer(from)\n    unanswered.clear()\n  }\n\n  if (locks) {\n    locks\n      .request(LOCK_NAME, {signal: abort.signal}, () => {\n        becomeLeader()\n\n        // Held until the sync stops, which hands the lock to the next tab in line\n        return new Promise<void>((resolve) => {\n          abort.signal.addEventListener('abort', () => resolve(), {once: true})\n        })\n      })\n      .catch(() => {\n        // The sync stopped before the lock was granted — nothing to let go of\n      })\n  } else {\n    becomeLeader()\n  }\n\n  const subscription = actorRef.subscribe((snapshot) => {\n    if (leader) persistSoon()\n    if (applying) return\n\n    const state = selectStoredState(snapshot)\n\n    // Only changes to what is persisted concern the other tabs — the flow is this tab's\n    if (dequal(state, shared)) return\n\n    shared = state\n    unchanged = false\n    revision += 1\n    origin = id\n    channel?.post({type: 'state', state, revision, from: id} satisfies SyncMessage)\n  })\n\n  if (channel) {\n    channel.listen((data) => {\n      const message = parseMessage(data)\n\n      if (!message) return\n\n      if (message.type === 'hello') {\n        // The tab that persists speaks for all, so that the newcomer hears one\n        // answer — or hears it once a tab holds the lock\n        if (leader) {\n          answer(message.from)\n        } else {\n          unanswered.add(message.from)\n        }\n\n        return\n      }\n\n      if (message.to !== undefined) {\n        if (message.to !== id) return\n\n        if (!unchanged) {\n          // Asked before this tab changed anything, answered after: the change\n          // is the later one, and goes around again ahead of the answer\n          if (origin === id) {\n            revision = Math.max(revision, message.revision) + 1\n            channel.post({type: 'state', state: shared, revision, from: id} satisfies SyncMessage)\n\n            return\n          }\n\n          // Answered twice — without a lock manager every tab answers — the\n          // answers are ordered like any other state\n          if (!isNewer(message)) return\n        }\n      } else if (!isNewer(message)) {\n        return\n      }\n\n      revision = message.revision\n      origin = message.from\n      if (dequal(message.state, shared)) return\n\n      shared = message.state\n      unchanged = false\n      applying = true\n      try {\n        actorRef.send({type: 'themes.sync', state: message.state})\n      } finally {\n        applying = false\n      }\n    })\n    channel.post({type: 'hello', from: id} satisfies SyncMessage)\n  }\n\n  const flush = () => {\n    if (leader && cancelPersist) persistNow()\n  }\n  const page = typeof window === 'undefined' ? undefined : window\n\n  page?.addEventListener('pagehide', flush)\n\n  return () => {\n    subscription.unsubscribe()\n    page?.removeEventListener('pagehide', flush)\n    flush()\n    abort.abort()\n    channel?.close()\n  }\n}\n","import {useEffect} from 'react'\n\nimport type {ThemerProps} from '#types'\n\nimport {writePersistedSnapshot} from './storage'\nimport {syncThemer} from './sync'\n\n/**\n * Persists the machine's snapshot for the next session, and keeps the themes\n * in step with the other tabs of the Studio — from the one tab holding the\n * Web Lock, when the browser is idle; see `sync.ts`. Rendered by the layout,\n * outside the sidebar's `Activity`, so that it runs while the sidebar is\n * closed too: other tabs change the themes whether this one shows them or\n * not.\n */\nexport function PersistActorSnapshot({actorRef}: Pick<ThemerProps, 'actorRef'>) {\n  useEffect(() => syncThemer(actorRef, {persist: writePersistedSnapshot}), [actorRef])\n\n  return null\n}\n","import {BoundaryElementProvider, Card, Flex} from '@sanity/ui'\nimport type {ThemeColorSchemeKey} from '@sanity/ui/theme'\nimport {useActorRef} from '@xstate/react'\nimport {Activity, lazy, startTransition, useEffect, useState, ViewTransition} from 'react'\n\nimport type {PluginConfig} from '#types'\nimport type {ThemerProps} from '#types'\n\nimport {addThemerTransitionType} from './addThemerTransitionType'\nimport {themerMachine} from './machine'\nimport {PersistActorSnapshot} from './PersistActorSnapshot'\nimport type {ToolReducerState} from './reducer'\nimport {resolveActiveThemeOptions} from './selectors'\nimport type {readPersistedSnapshot} from './storage'\nimport {ThemerNavbarProvider} from './ThemerNavbar'\n\nimport {layout, viewTransitionClasses} from './ViewTransitions.css'\n\n/**\n * The sidebar — everything in it, from the theme list to the snippet dialog —\n * loads the first time it opens. There is no `Suspense` boundary around it,\n * so it must only ever mount from a transition: the navbar toggle prerenders\n * it in one as the pointer comes near, which keeps the Studio as it was while\n * the code loads, where an urgent render would suspend up to the Studio's\n * own boundary and swap the whole Studio for its loading screen.\n */\nconst ResizableSidebar = lazy(() => import('./ResizableSidebar'))\n\ninterface ThemerLayoutProps extends Omit<ToolReducerState, 'theme'> {\n  children: React.ReactNode\n  config: PluginConfig\n  dispatch: ThemerProps['dispatch']\n  /** The machine's snapshot as the last session persisted it, for the machine to pick up where it left off */\n  persistedSnapshot: ReturnType<typeof readPersistedSnapshot>\n}\n\n/**\n * Wraps the whole Studio to run the themer machine that the sidebar's flows\n * share — the user's themes, which one is applied and which flow the sidebar\n * is in — and renders the sidebar next to the Studio. The sidebar sits at\n * the `layout` level rather than in `activeToolLayout` because the split\n * preview renders the Studio twice, and the sidebar must not come along.\n *\n * Whether the sidebar is open and whether the Studio shows twice comes in as\n * props from the tool reducer in `ThemerProvider`, and goes on to the sidebar\n * as props along with the machine's actor, which the sidebar selects its\n * themes and flow from (see `ThemerProps`): the navbar toggle and the sidebar\n * dispatch to the reducer inside transitions tagged with a transition type\n * (see `addThemerTransitionType`), and the `ViewTransition` boundaries below\n * pick their classes by that type, so React animates the sidebar sliding in\n * and out, the split copy coming and going and a picked theme cross-fading\n * in (React 19.3), styled in `ViewTransitions.css.ts`. The sidebar and the\n * split copy stay mounted while hidden, in `Activity`, so that opening them\n * again is instant and they can prerender ahead of the transition. The\n * navbar toggle, which the Studio renders somewhere in `children`, reads the\n * same values and the plugin's options from the contexts\n * `ThemerNavbarProvider` provides in each copy of the Studio, and measures\n * the Studio navbar for the sidebar's header — in the Studio proper, not in\n * the split copy, which `ToolShouldDetectNavbarHeightContext` tells apart.\n *\n * The applied theme is the reducer's, provided above this layout in\n * `ThemerProvider`: the machine publishes it synchronously, which React does\n * not animate, so `ThemerThemeCrossfader` hands it to the reducer in a\n * transition of its own. The Studio next to the sidebar always follows the\n * appearance setting (light/dark/system) and the picked theme like any other\n * theme would; the split preview adds a second copy in the opposite scheme\n * on the far side.\n *\n * Whatever else on the page has a `view-transition-name` — an avatar the\n * Studio names so it moves as one piece — comes along in step: every\n * transition the layout starts carries `layoutTransitionType`, which the\n * stylesheet keys on to move every group in the layout's time (see\n * `ViewTransitions.css.ts`).\n *\n * @internal\n */\nexport function ThemerLayout({\n  children,\n  backgroundColor,\n  config,\n  dispatch,\n  navbarHeight,\n  open,\n  persistedSnapshot,\n  prerender,\n  prerenderSplitScreen,\n  scheme,\n  split,\n}: ThemerLayoutProps & {backgroundColor: string | undefined; scheme: ThemeColorSchemeKey}) {\n  const actorRef = useActorRef(themerMachine, {snapshot: persistedSnapshot})\n\n  const oppositeScheme: ThemeColorSchemeKey = scheme === 'dark' ? 'light' : 'dark'\n\n  return (\n    <>\n      <Flex\n        className={layout}\n        direction={'row'}\n        height=\"fill\"\n        sizing=\"border\"\n        style={{backgroundColor}}\n      >\n        {/* Renders the Studio for the second time, in the opposite scheme of the main studio. Hidden by default */}\n        <Activity mode={split && open ? 'visible' : 'hidden'}>\n          <ViewTransition\n            default=\"none\"\n            enter={viewTransitionClasses.splitscreen.enter}\n            update={viewTransitionClasses.splitscreen.update}\n            exit={viewTransitionClasses.splitscreen.exit}\n          >\n            {prerenderSplitScreen && (\n              <StudioPreview\n                borderRight\n                config={config}\n                dispatch={dispatch}\n                open={open}\n                scheme={oppositeScheme}\n                split={split}\n              >\n                {children}\n              </StudioPreview>\n            )}\n          </ViewTransition>\n        </Activity>\n        {/* Renders the Studio */}\n        <ViewTransition default=\"none\" update={viewTransitionClasses.studio.update}>\n          <StudioPreview\n            config={config}\n            dispatch={dispatch}\n            open={open}\n            shouldDetectNavbarHeight\n            split={split}\n          >\n            {children}\n          </StudioPreview>\n        </ViewTransition>\n        {/* Renders the Themer tool, hidden by default */}\n        <Activity mode={open ? 'visible' : 'hidden'}>\n          <ViewTransition\n            default=\"none\"\n            enter={viewTransitionClasses.sidebar.enter}\n            update={viewTransitionClasses.sidebar.update}\n            exit={viewTransitionClasses.sidebar.exit}\n          >\n            {prerender && (\n              <ResizableSidebar\n                actorRef={actorRef}\n                dispatch={dispatch}\n                navbarHeight={navbarHeight}\n                split={split}\n              />\n            )}\n          </ViewTransition>\n        </Activity>\n      </Flex>\n\n      <ThemerThemeCrossfader actorRef={actorRef} dispatch={dispatch} />\n      <RevokeImageUrls actorRef={actorRef} />\n      <PersistActorSnapshot actorRef={actorRef} />\n    </>\n  )\n}\n\n/**\n * One copy of the Studio, in the given color scheme — or, without one, in the\n * scheme the Studio is showing. The two copies of the split preview share the\n * router, the document store and every other provider above the layout —\n * only the scheme differs — so they stay in sync while navigating. The\n * `color-scheme` of a forced scheme keeps native form controls and scrollbars\n * in step with it. Each copy provides the navbar toggle it renders with the\n * contexts it reads (see `ThemerNavbarProvider`).\n */\nfunction StudioPreview({\n  borderRight,\n  children,\n  config,\n  dispatch,\n  open,\n  scheme,\n  shouldDetectNavbarHeight,\n  split,\n}: {\n  borderRight?: boolean\n  scheme?: ThemeColorSchemeKey\n} & React.ComponentProps<typeof ThemerNavbarProvider>) {\n  const [boundaryElement, setBoundaryElement] = useState<HTMLDivElement | null>(null)\n\n  return (\n    <Card\n      borderRight={borderRight}\n      flex={1}\n      height=\"fill\"\n      overflow=\"hidden\"\n      scheme={scheme}\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      <BoundaryElementProvider element={boundaryElement}>\n        <ThemerNavbarProvider\n          config={config}\n          dispatch={dispatch}\n          open={open}\n          shouldDetectNavbarHeight={shouldDetectNavbarHeight}\n          split={split}\n        >\n          <ViewTransition update=\"none\">{children}</ViewTransition>\n        </ThemerNavbarProvider>\n      </BoundaryElementProvider>\n    </Card>\n  )\n}\n\n/**\n * Hands the applied theme to the tool reducer as the machine publishes it —\n * in a transition tagged to cross-fade while the machine says a theme is\n * being switched to, so that editing the applied theme's colors applies live\n * while picking another theme fades the Studio over to it\n */\nfunction ThemerThemeCrossfader({actorRef, dispatch}: Pick<ThemerProps, 'actorRef' | 'dispatch'>) {\n  useEffect(() => {\n    const subscription = actorRef.subscribe((snapshot) => {\n      const switching = snapshot.hasTag('switching')\n      const theme = resolveActiveThemeOptions(snapshot.context)\n\n      startTransition(() => {\n        if (switching) {\n          addThemerTransitionType('crossfade')\n        }\n        if (!theme) {\n          dispatch({type: 'unset-theme'})\n        } else {\n          dispatch({type: 'set-theme', theme})\n        }\n      })\n    })\n\n    return () => subscription.unsubscribe()\n  }, [actorRef, dispatch])\n\n  return null\n}\n\nfunction RevokeImageUrls({actorRef}: Pick<ThemerProps, 'actorRef'>) {\n  // The machine releases the image of a palette as it is replaced or its\n  // theme deleted; whatever it still holds goes with the layout — the actor\n  // keeps its last snapshot once stopped\n  useEffect(\n    () => () => {\n      for (const url of Object.values(actorRef.getSnapshot().context.images)) {\n        URL.revokeObjectURL(url)\n      }\n    },\n    [actorRef],\n  )\n\n  return null\n}\n","import {ThemeProvider, useMediaIndex} from '@sanity/ui'\nimport {use, useReducer, useState} from 'react'\nimport {browser} from 'react-dom'\nimport {useColorSchemeValue} from 'sanity'\n\nimport {MIN_MEDIA_INDEX_FOR_SIDEBAR, MIN_MEDIA_INDEX_FOR_SPLIT_SCREEN} from '#constants'\nimport type {ThemerProps} from '#types'\n\nimport {buildTheme} from '../theme/buildTheme'\nimport {initialToolState, toolReducer} from './reducer'\nimport {resolveActiveThemeOptions} from './selectors'\nimport {readPersistedSnapshot} from './storage'\nimport {ThemerLayout} from './ThemerLayout'\n\n/**\n * Keep this component extremely lightweight, and only include state that are needed by both\n *  `studio.components.layout` and `studio.components.navbar`, where it's not possible to prop-drill into `studio.components.navbar`,\n * and that need to survive open/close of the tool\n * @TODO will mount on the future `studio.components.provider` entrypoint to ensure other plugins using `studio.components.layout` is correctly wrapped in the top-level theme regardless of plugin ordering\n */\nexport function ThemerProvider({\n  children,\n  config,\n}: {\n  children: React.ReactNode\n} & Pick<ThemerProps, 'config'>) {\n  use(browser('The current theme is stored in localStorage.'))\n\n  const [persistedSnapshot] = useState(readPersistedSnapshot)\n  const [state, dispatch] = useReducer(toolReducer, initialToolState, (initialState) => {\n    if (!persistedSnapshot) return initialState\n    const theme = resolveActiveThemeOptions(persistedSnapshot.context)\n    return theme ? {...initialState, theme} : initialState\n  })\n\n  const scheme = useColorSchemeValue()\n  const index = useMediaIndex()\n  const isMobile = index <= MIN_MEDIA_INDEX_FOR_SIDEBAR\n  const isTooSmallForSplitScreen = index <= MIN_MEDIA_INDEX_FOR_SPLIT_SCREEN\n\n  // @TODO Themer does not yet support mobile\n  const open = state.open && !isMobile\n  // Split screen needs some space\n  const split = state.split && !isTooSmallForSplitScreen\n\n  return (\n    <ThemeProvider theme={(state.theme !== null ? buildTheme(state.theme) : null) ?? undefined}>\n      <ThemerLayout\n        config={config}\n        backgroundColor={state.theme?.[scheme]?.background}\n        dispatch={dispatch}\n        navbarHeight={state.navbarHeight}\n        open={open}\n        persistedSnapshot={persistedSnapshot}\n        prerender={state.prerender}\n        prerenderSplitScreen={state.prerenderSplitScreen}\n        scheme={scheme}\n        split={split}\n      >\n        {children}\n      </ThemerLayout>\n    </ThemeProvider>\n  )\n}\n","import {definePlugin, type LayoutProps} from 'sanity'\n\nimport type {PluginConfig} from '#types'\n\nimport {ThemerNavbar} from './ThemerNavbar'\nimport {ThemerProvider} from './ThemerProvider'\n\n/**\n * Options for the {@link themerTool} plugin.\n *\n * This is experimental and may change or be removed in any release without\n * notice — use at your own risk.\n *\n * @alpha\n */\nexport interface ThemerToolOptions {\n  /**\n   * What the tool goes by in the Studio navbar — the toggle's label and\n   * tooltip. Defaults to `Themer`.\n   */\n  title?: string\n}\n\n/**\n * A Studio plugin that adds a themer sidebar for `buildTheme` themes: a\n * navbar toggle opens the sidebar next to the Studio, with a list of themes —\n * the configured theme, the presets and your own — each previewed as a tiny\n * Studio in both color schemes. Picking one applies it live to the whole\n * Studio while you browse around; your own themes can be edited with\n * accent/text/background pickers and a contrast slider per scheme, added,\n * duplicated, given the colors of an image (its palette is read on device),\n * removed and restored, and a dialog shows the `buildTheme` snippet that\n * makes the applied theme permanent. Toggle between light and dark mode with\n * the regular appearance menu — the preview follows it — or split the\n * preview to see the whole Studio in light and dark side by side.\n *\n * ```ts\n * import {themerTool} from '@sanity/themer/tool'\n * import {defineConfig} from 'sanity'\n *\n * export default defineConfig({\n *   plugins: [themerTool()],\n *   // ...rest of the config\n * })\n * ```\n *\n * This is experimental and may change or be removed in any release without\n * notice — use at your own risk.\n *\n * @alpha\n */\nexport const themerTool = definePlugin<ThemerToolOptions | void>((options) => {\n  const {title = 'Themer'} = options ?? {}\n  const ThemerLayoutProvider = defineThemerLayout({title})\n\n  return {\n    name: '@sanity/themer/tool',\n    studio: {\n      components: {layout: ThemerLayoutProvider, navbar: ThemerNavbar},\n    },\n  }\n})\n\n// This wrapper creates a clean closure that allows safely using the `'use memo'` directive\n// so that the dynamically created component can be memoized by react compiler\nfunction defineThemerLayout(config: PluginConfig) {\n  return function DefinedThemerLayoutProvider(props: LayoutProps) {\n    'use memo'\n\n    return <ThemerProvider config={config}>{props.renderDefault(props)}</ThemerProvider>\n  }\n}\n"],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"tool.js","names":["() =>\n    startBusyTransition(() => {\n      if (split) addThemerTransitionType('split-screen:open')\n      addThemerTransitionType('open')\n      dispatch({type: 'open'})\n    })","() =>\n    startBusyTransition(() => {\n      if (split) addThemerTransitionType('split-screen:close')\n      addThemerTransitionType('close')\n      dispatch({type: 'close'})\n    })","() =>\n    startTransition(() => {\n      // We want to trigger rerender in a transition, so that clicking the open button\n      // can interrupt a prerender, and hovering over the button won't abort an active view transition.\n      // But we also don't want the transition to trigger a view transition,\n      // so we intentionally do not set a transition type here.\n      dispatch({type: 'prerender'})\n      // Do a little fun spin\n      if (!open) iconRef.current?.spin()\n    })","(root: HTMLButtonElement | null) => {\n    const navbar = root?.closest(NAVBAR_SELECTOR)\n\n    if (!navbar) return undefined\n\n    const resizeObserver = new ResizeObserver((entries) => {\n      const height = entries[0]?.borderBoxSize[0]?.blockSize\n\n      if (height) {\n        startTransition(() => dispatch({type: 'set-navbar-height', height}))\n      }\n    })\n\n    resizeObserver.observe(navbar)\n\n    return () => resizeObserver.disconnect()\n  }","<Text size={1}>{title}</Text>","prefersReducedMotion ? (\n                  <ColorWheelIcon />\n                ) : (\n                  <Suspense fallback={<ColorWheelIcon />}>\n                    <AnimatedColorWheelIcon busy={busy} ref={iconRef} />\n                  </Suspense>\n                )","<Box>\n          <ViewTransition default=\"none\" update={viewTransitionClasses.navbarButton.update}>\n            <Button\n              ref={shouldDetectNavbarHeight ? observeNavbarHeight : undefined}\n              aria-busy={busy}\n              aria-label={title}\n              // The wheel itself shows the load, where the `loading` prop would\n              // cover it with a spinner\n              icon={\n                // The animated wheel needs `motion/react`, which is heavy, so it\n                // loads lazily — behind the plain icon it reimplements, which is\n                // all there is to show with `prefers-reduced-motion: reduce`\n                prefersReducedMotion ? (\n                  <ColorWheelIcon />\n                ) : (\n                  <Suspense fallback={<ColorWheelIcon />}>\n                    <AnimatedColorWheelIcon busy={busy} ref={iconRef} />\n                  </Suspense>\n                )\n              }\n              mode=\"bleed\"\n              onClick={open ? handleClose : handleOpen}\n              onFocus={handlePrerender}\n              onMouseEnter={handlePrerender}\n              // The Studio's own navbar buttons go through a wrapper that pins them\n              // to this padding, where `@sanity/ui` defaults to a roomier 3\n              padding={2}\n              selected={open || busy}\n            />\n          </ViewTransition>\n        </Box>","shouldDetectNavbarHeight ? observeNavbarHeight : undefined","open ? handleClose : handleOpen","open || busy","<ViewTransition default=\"none\" update={viewTransitionClasses.navbarButtonTooltip.update}>\n      <Tooltip animate content={<Text size={1}>{title}</Text>} portal>\n        <Box>\n          <ViewTransition default=\"none\" update={viewTransitionClasses.navbarButton.update}>\n            <Button\n              ref={shouldDetectNavbarHeight ? observeNavbarHeight : undefined}\n              aria-busy={busy}\n              aria-label={title}\n              // The wheel itself shows the load, where the `loading` prop would\n              // cover it with a spinner\n              icon={\n                // The animated wheel needs `motion/react`, which is heavy, so it\n                // loads lazily — behind the plain icon it reimplements, which is\n                // all there is to show with `prefers-reduced-motion: reduce`\n                prefersReducedMotion ? (\n                  <ColorWheelIcon />\n                ) : (\n                  <Suspense fallback={<ColorWheelIcon />}>\n                    <AnimatedColorWheelIcon busy={busy} ref={iconRef} />\n                  </Suspense>\n                )\n              }\n              mode=\"bleed\"\n              onClick={open ? handleClose : handleOpen}\n              onFocus={handlePrerender}\n              onMouseEnter={handlePrerender}\n              // The Studio's own navbar buttons go through a wrapper that pins them\n              // to this padding, where `@sanity/ui` defaults to a roomier 3\n              padding={2}\n              selected={open || busy}\n            />\n          </ViewTransition>\n        </Box>\n      </Tooltip>\n    </ViewTransition>","{\n        location: 'topbar',\n        name: 'themer-topbar',\n        // The component itself rather than a `() => <ThemerNavbarButton />`\n        // wrapper: the Studio renders `render` as a component, and a wrapper\n        // made anew on every render would remount the button each time —\n        // resetting its animation\n        render: ThemerNavbarButton,\n      }","props.__internal_actions ?? []","__internal_actions","props.renderDefault({\n    ...props,\n    __internal_actions: [...(props.__internal_actions ?? []), button],\n  })","{\n  children,\n  config,\n  dispatch,\n  open,\n  shouldDetectNavbarHeight,\n  split,\n}: {children: React.ReactNode; shouldDetectNavbarHeight?: boolean} & Pick<\n  ThemerProps,\n  'dispatch' | 'config' | 'open' | 'split'\n>","<ToolShouldDetectNavbarHeightContext value={shouldDetectNavbarHeight ?? false}>\n              {children}\n            </ToolShouldDetectNavbarHeightContext>","shouldDetectNavbarHeight ?? false","<ToolSplitIsOpenContext value={split}>\n            <ToolShouldDetectNavbarHeightContext value={shouldDetectNavbarHeight ?? false}>\n              {children}\n            </ToolShouldDetectNavbarHeightContext>\n          </ToolSplitIsOpenContext>","<ToolIsOpenContext value={open}>\n          <ToolSplitIsOpenContext value={split}>\n            <ToolShouldDetectNavbarHeightContext value={shouldDetectNavbarHeight ?? false}>\n              {children}\n            </ToolShouldDetectNavbarHeightContext>\n          </ToolSplitIsOpenContext>\n        </ToolIsOpenContext>","<ToolDispatchContext value={dispatch}>\n        <ToolIsOpenContext value={open}>\n          <ToolSplitIsOpenContext value={split}>\n            <ToolShouldDetectNavbarHeightContext value={shouldDetectNavbarHeight ?? false}>\n              {children}\n            </ToolShouldDetectNavbarHeightContext>\n          </ToolSplitIsOpenContext>\n        </ToolIsOpenContext>\n      </ToolDispatchContext>","<PluginConfigContext value={config}>\n      <ToolDispatchContext value={dispatch}>\n        <ToolIsOpenContext value={open}>\n          <ToolSplitIsOpenContext value={split}>\n            <ToolShouldDetectNavbarHeightContext value={shouldDetectNavbarHeight ?? false}>\n              {children}\n            </ToolShouldDetectNavbarHeightContext>\n          </ToolSplitIsOpenContext>\n        </ToolIsOpenContext>\n      </ToolDispatchContext>\n    </PluginConfigContext>","_c","unknown","{actorRef}: Pick<ThemerProps, 'actorRef'>","() => syncThemer(actorRef, {persist: writePersistedSnapshot})","[actorRef]","_c","{\n  children,\n  backgroundColor,\n  config,\n  dispatch,\n  navbarHeight,\n  open,\n  persistedSnapshot,\n  prerender,\n  prerenderSplitScreen,\n  scheme,\n  split,\n}: ThemerLayoutProps & {backgroundColor: string | undefined; scheme: ThemeColorSchemeKey}","{snapshot: persistedSnapshot}","{backgroundColor}","prerenderSplitScreen && (\n              <StudioPreview\n                borderRight\n                config={config}\n                dispatch={dispatch}\n                open={open}\n                scheme={oppositeScheme}\n                split={split}\n              >\n                {children}\n              </StudioPreview>\n            )","<ViewTransition\n            default=\"none\"\n            enter={viewTransitionClasses.splitscreen.enter}\n            update={viewTransitionClasses.splitscreen.update}\n            exit={viewTransitionClasses.splitscreen.exit}\n          >\n            {prerenderSplitScreen && (\n              <StudioPreview\n                borderRight\n                config={config}\n                dispatch={dispatch}\n                open={open}\n                scheme={oppositeScheme}\n                split={split}\n              >\n                {children}\n              </StudioPreview>\n            )}\n          </ViewTransition>","<Activity mode={split && open ? 'visible' : 'hidden'}>\n          <ViewTransition\n            default=\"none\"\n            enter={viewTransitionClasses.splitscreen.enter}\n            update={viewTransitionClasses.splitscreen.update}\n            exit={viewTransitionClasses.splitscreen.exit}\n          >\n            {prerenderSplitScreen && (\n              <StudioPreview\n                borderRight\n                config={config}\n                dispatch={dispatch}\n                open={open}\n                scheme={oppositeScheme}\n                split={split}\n              >\n                {children}\n              </StudioPreview>\n            )}\n          </ViewTransition>\n        </Activity>","split && open ? 'visible' : 'hidden'","<ViewTransition default=\"none\" update={viewTransitionClasses.studio.update}>\n          <StudioPreview\n            config={config}\n            dispatch={dispatch}\n            open={open}\n            shouldDetectNavbarHeight\n            split={split}\n          >\n            {children}\n          </StudioPreview>\n        </ViewTransition>","prerender && (\n              <ResizableSidebar\n                actorRef={actorRef}\n                dispatch={dispatch}\n                navbarHeight={navbarHeight}\n                split={split}\n              />\n            )","<ViewTransition\n            default=\"none\"\n            enter={viewTransitionClasses.sidebar.enter}\n            update={viewTransitionClasses.sidebar.update}\n            exit={viewTransitionClasses.sidebar.exit}\n          >\n            {prerender && (\n              <ResizableSidebar\n                actorRef={actorRef}\n                dispatch={dispatch}\n                navbarHeight={navbarHeight}\n                split={split}\n              />\n            )}\n          </ViewTransition>","<Activity mode={open ? 'visible' : 'hidden'}>\n          <ViewTransition\n            default=\"none\"\n            enter={viewTransitionClasses.sidebar.enter}\n            update={viewTransitionClasses.sidebar.update}\n            exit={viewTransitionClasses.sidebar.exit}\n          >\n            {prerender && (\n              <ResizableSidebar\n                actorRef={actorRef}\n                dispatch={dispatch}\n                navbarHeight={navbarHeight}\n                split={split}\n              />\n            )}\n          </ViewTransition>\n        </Activity>","open ? 'visible' : 'hidden'","<Flex\n        className={layout}\n        direction={'row'}\n        height=\"fill\"\n        sizing=\"border\"\n        style={{backgroundColor}}\n      >\n        {/* Renders the Studio for the second time, in the opposite scheme of the main studio. Hidden by default */}\n        <Activity mode={split && open ? 'visible' : 'hidden'}>\n          <ViewTransition\n            default=\"none\"\n            enter={viewTransitionClasses.splitscreen.enter}\n            update={viewTransitionClasses.splitscreen.update}\n            exit={viewTransitionClasses.splitscreen.exit}\n          >\n            {prerenderSplitScreen && (\n              <StudioPreview\n                borderRight\n                config={config}\n                dispatch={dispatch}\n                open={open}\n                scheme={oppositeScheme}\n                split={split}\n              >\n                {children}\n              </StudioPreview>\n            )}\n          </ViewTransition>\n        </Activity>\n        {/* Renders the Studio */}\n        <ViewTransition default=\"none\" update={viewTransitionClasses.studio.update}>\n          <StudioPreview\n            config={config}\n            dispatch={dispatch}\n            open={open}\n            shouldDetectNavbarHeight\n            split={split}\n          >\n            {children}\n          </StudioPreview>\n        </ViewTransition>\n        {/* Renders the Themer tool, hidden by default */}\n        <Activity mode={open ? 'visible' : 'hidden'}>\n          <ViewTransition\n            default=\"none\"\n            enter={viewTransitionClasses.sidebar.enter}\n            update={viewTransitionClasses.sidebar.update}\n            exit={viewTransitionClasses.sidebar.exit}\n          >\n            {prerender && (\n              <ResizableSidebar\n                actorRef={actorRef}\n                dispatch={dispatch}\n                navbarHeight={navbarHeight}\n                split={split}\n              />\n            )}\n          </ViewTransition>\n        </Activity>\n      </Flex>","<ThemerThemeCrossfader actorRef={actorRef} dispatch={dispatch} />","<RevokeImageUrls actorRef={actorRef} />","<PersistActorSnapshot actorRef={actorRef} />","<>\n      <Flex\n        className={layout}\n        direction={'row'}\n        height=\"fill\"\n        sizing=\"border\"\n        style={{backgroundColor}}\n      >\n        {/* Renders the Studio for the second time, in the opposite scheme of the main studio. Hidden by default */}\n        <Activity mode={split && open ? 'visible' : 'hidden'}>\n          <ViewTransition\n            default=\"none\"\n            enter={viewTransitionClasses.splitscreen.enter}\n            update={viewTransitionClasses.splitscreen.update}\n            exit={viewTransitionClasses.splitscreen.exit}\n          >\n            {prerenderSplitScreen && (\n              <StudioPreview\n                borderRight\n                config={config}\n                dispatch={dispatch}\n                open={open}\n                scheme={oppositeScheme}\n                split={split}\n              >\n                {children}\n              </StudioPreview>\n            )}\n          </ViewTransition>\n        </Activity>\n        {/* Renders the Studio */}\n        <ViewTransition default=\"none\" update={viewTransitionClasses.studio.update}>\n          <StudioPreview\n            config={config}\n            dispatch={dispatch}\n            open={open}\n            shouldDetectNavbarHeight\n            split={split}\n          >\n            {children}\n          </StudioPreview>\n        </ViewTransition>\n        {/* Renders the Themer tool, hidden by default */}\n        <Activity mode={open ? 'visible' : 'hidden'}>\n          <ViewTransition\n            default=\"none\"\n            enter={viewTransitionClasses.sidebar.enter}\n            update={viewTransitionClasses.sidebar.update}\n            exit={viewTransitionClasses.sidebar.exit}\n          >\n            {prerender && (\n              <ResizableSidebar\n                actorRef={actorRef}\n                dispatch={dispatch}\n                navbarHeight={navbarHeight}\n                split={split}\n              />\n            )}\n          </ViewTransition>\n        </Activity>\n      </Flex>\n\n      <ThemerThemeCrossfader actorRef={actorRef} dispatch={dispatch} />\n      <RevokeImageUrls actorRef={actorRef} />\n      <PersistActorSnapshot actorRef={actorRef} />\n    </>","{\n  borderRight,\n  children,\n  config,\n  dispatch,\n  open,\n  scheme,\n  shouldDetectNavbarHeight,\n  split,\n}: {\n  borderRight?: boolean\n  scheme?: ThemeColorSchemeKey\n} & React.ComponentProps<typeof ThemerNavbarProvider>","(boundaryElement) => {\n        startTransition(() => setBoundaryElement(boundaryElement))\n        // Intentionally not unsetting the element as it would create unnecessary work when <Activity> unhides\n        return () => {}\n      }","boundaryElement","() => {}","<ViewTransition update=\"none\">{children}</ViewTransition>","<ThemerNavbarProvider\n          config={config}\n          dispatch={dispatch}\n          open={open}\n          shouldDetectNavbarHeight={shouldDetectNavbarHeight}\n          split={split}\n        >\n          <ViewTransition update=\"none\">{children}</ViewTransition>\n        </ThemerNavbarProvider>","<BoundaryElementProvider element={boundaryElement}>\n        <ThemerNavbarProvider\n          config={config}\n          dispatch={dispatch}\n          open={open}\n          shouldDetectNavbarHeight={shouldDetectNavbarHeight}\n          split={split}\n        >\n          <ViewTransition update=\"none\">{children}</ViewTransition>\n        </ThemerNavbarProvider>\n      </BoundaryElementProvider>","<Card\n      borderRight={borderRight}\n      flex={1}\n      height=\"fill\"\n      overflow=\"hidden\"\n      scheme={scheme}\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      <BoundaryElementProvider element={boundaryElement}>\n        <ThemerNavbarProvider\n          config={config}\n          dispatch={dispatch}\n          open={open}\n          shouldDetectNavbarHeight={shouldDetectNavbarHeight}\n          split={split}\n        >\n          <ViewTransition update=\"none\">{children}</ViewTransition>\n        </ThemerNavbarProvider>\n      </BoundaryElementProvider>\n    </Card>","{actorRef, dispatch}: Pick<ThemerProps, 'actorRef' | 'dispatch'>","() => {\n    const subscription = actorRef.subscribe((snapshot) => {\n      const switching = snapshot.hasTag('switching')\n      const theme = resolveActiveThemeOptions(snapshot.context)\n\n      startTransition(() => {\n        if (switching) {\n          addThemerTransitionType('crossfade')\n        }\n        if (!theme) {\n          dispatch({type: 'unset-theme'})\n        } else {\n          dispatch({type: 'set-theme', theme})\n        }\n      })\n    })\n\n    return () => subscription.unsubscribe()\n  }","[actorRef, dispatch]","{actorRef}: Pick<ThemerProps, 'actorRef'>","() => () => {\n      for (const url of Object.values(actorRef.getSnapshot().context.images)) {\n        URL.revokeObjectURL(url)\n      }\n    }","[actorRef]","_c","_Fragment","{\n  children,\n  config,\n}: {\n  children: React.ReactNode\n} & Pick<ThemerProps, 'config'>","(initialState) => {\n    if (!persistedSnapshot) return initialState\n    const theme = resolveActiveThemeOptions(persistedSnapshot.context)\n    return theme ? {...initialState, theme} : initialState\n  }","(state.theme !== null ? buildTheme(state.theme) : null) ?? undefined","theme","<ThemerLayout\n        config={config}\n        backgroundColor={state.theme?.[scheme]?.background}\n        dispatch={dispatch}\n        navbarHeight={state.navbarHeight}\n        open={open}\n        persistedSnapshot={persistedSnapshot}\n        prerender={state.prerender}\n        prerenderSplitScreen={state.prerenderSplitScreen}\n        scheme={scheme}\n        split={split}\n      >\n        {children}\n      </ThemerLayout>","navbarHeight","prerender","prerenderSplitScreen","state.theme?.[scheme]?.background","<ThemeProvider theme={(state.theme !== null ? buildTheme(state.theme) : null) ?? undefined}>\n      <ThemerLayout\n        config={config}\n        backgroundColor={state.theme?.[scheme]?.background}\n        dispatch={dispatch}\n        navbarHeight={state.navbarHeight}\n        open={open}\n        persistedSnapshot={persistedSnapshot}\n        prerender={state.prerender}\n        prerenderSplitScreen={state.prerenderSplitScreen}\n        scheme={scheme}\n        split={split}\n      >\n        {children}\n      </ThemerLayout>\n    </ThemeProvider>","_c","props.renderDefault(props)","<ThemerProvider config={config}>{props.renderDefault(props)}</ThemerProvider>","_c"],"sources":["../src/tool/context.ts","../src/tool/ThemerNavbar.tsx","../src/tool/reducer.ts","../src/tool/selectors.ts","../src/tool/schemas.ts","../src/tool/storage.ts","../src/tool/machine.ts","../src/tool/sync.ts","../src/tool/PersistActorSnapshot.tsx","../src/tool/ThemerLayout.tsx","../src/tool/ThemerProvider.tsx","../src/tool/plugin.tsx"],"sourcesContent":["import {createContext} from 'react'\n\nimport type {PluginConfig} from '#types'\n\nimport type {ToolReducerAction} from './reducer'\n\n/*\n * The tool reducer's state that the navbar toggle shows and changes. The\n * Studio renders the navbar itself, out of the layout's reach, so this is\n * where the reducer's values travel by context — the layout and the sidebar\n * get them as props. One context per value, on purpose: a consumer only\n * re-renders for the value it reads, where one object would re-render every\n * consumer for any change.\n */\n\n/** @internal */\nexport const ToolIsOpenContext = createContext<boolean>(false)\n/**\n * The global top-level useReducer dispatch() for state that persists through open/close of the tool\n * @internal */\nexport const ToolDispatchContext = createContext<React.Dispatch<ToolReducerAction>>(() => {\n  throw new Error('ToolDispatchContext not initialized')\n})\n/** @internal */\nexport const ToolSplitIsOpenContext = createContext<boolean>(false)\n\n/** @internal */\nexport const ToolShouldDetectNavbarHeightContext = createContext<boolean>(false)\n\n/** @internal */\nexport const PluginConfigContext = createContext<Required<PluginConfig> | null>(null)\n\n/** @internal */\nexport type ThemerView =\n  | {name: 'list'}\n  | {\n      name: 'edit'\n      slug: string\n      /** Whether the title input should take focus, for themes that were just created */\n      focusTitle: boolean\n    }\n  | {name: 'removed'}\n","import {ColorWheelIcon} from '@sanity/icons/ColorWheel'\nimport {Box, Button, Text, usePrefersReducedMotion} from '@sanity/ui'\nimport {Tooltip} from '@sanity/ui/tooltip'\nimport {\n  lazy,\n  startTransition,\n  Suspense,\n  use,\n  useRef,\n  useTransition,\n  ViewTransition,\n  useMemo,\n} from 'react'\nimport {type NavbarProps} from 'sanity'\nimport type {NavbarAction} from 'sanity/_dangerously_use_private_internals_that_do_not_follow_semver'\n\nimport {NAVBAR_SELECTOR} from '#constants'\nimport {\n  PluginConfigContext,\n  ToolDispatchContext,\n  ToolIsOpenContext,\n  ToolShouldDetectNavbarHeightContext,\n  ToolSplitIsOpenContext,\n} from '#context'\nimport type {ThemerProps} from '#types'\n\nimport {addThemerTransitionType} from './addThemerTransitionType'\n\nimport {viewTransitionClasses} from './ViewTransitions.css'\n\nconst AnimatedColorWheelIcon = lazy(() => import('./AnimatedColorWheelIcon'))\n\nfunction ThemerNavbarButton() {\n  const config = use(PluginConfigContext)\n  const dispatch = use(ToolDispatchContext)\n  const open = use(ToolIsOpenContext)\n  const shouldDetectNavbarHeight = use(ToolShouldDetectNavbarHeightContext)\n  const split = use(ToolSplitIsOpenContext)\n\n  if (!config) {\n    throw new TypeError('PluginConfigContext.Provider is missing')\n  }\n\n  const [busy, startBusyTransition] = useTransition()\n  const iconRef = useRef<{spin: () => void}>(null)\n  const prefersReducedMotion = usePrefersReducedMotion()\n\n  const handleOpen = () =>\n    startBusyTransition(() => {\n      if (split) addThemerTransitionType('split-screen:open')\n      addThemerTransitionType('open')\n      dispatch({type: 'open'})\n    })\n  const handleClose = () =>\n    startBusyTransition(() => {\n      if (split) addThemerTransitionType('split-screen:close')\n      addThemerTransitionType('close')\n      dispatch({type: 'close'})\n    })\n  const handlePrerender = () =>\n    startTransition(() => {\n      // We want to trigger rerender in a transition, so that clicking the open button\n      // can interrupt a prerender, and hovering over the button won't abort an active view transition.\n      // But we also don't want the transition to trigger a view transition,\n      // so we intentionally do not set a transition type here.\n      dispatch({type: 'prerender'})\n      // Do a little fun spin\n      if (!open) iconRef.current?.spin()\n    })\n\n  // The sidebar's header takes the height of the Studio navbar, so the two\n  // line up — whatever height the Studio, its breakpoint or a custom navbar\n  // gives it. The button sits inside the navbar, so it is the one to measure\n  // it, as a ref callback: observed from mount to unmount, in a transition,\n  // since nothing urgent hangs on the number\n  const observeNavbarHeight = (root: HTMLButtonElement | null) => {\n    const navbar = root?.closest(NAVBAR_SELECTOR)\n\n    if (!navbar) return undefined\n\n    const resizeObserver = new ResizeObserver((entries) => {\n      const height = entries[0]?.borderBoxSize[0]?.blockSize\n\n      if (height) {\n        startTransition(() => dispatch({type: 'set-navbar-height', height}))\n      }\n    })\n\n    resizeObserver.observe(navbar)\n\n    return () => resizeObserver.disconnect()\n  }\n\n  const {title} = config\n\n  // The `Box` is here because a `ViewTransition` cannot be the direct child\n  // of the `Tooltip`: it needs a child that renders a DOM node\n  return (\n    <ViewTransition default=\"none\" update={viewTransitionClasses.navbarButtonTooltip.update}>\n      <Tooltip animate content={<Text size={1}>{title}</Text>} portal>\n        <Box>\n          <ViewTransition default=\"none\" update={viewTransitionClasses.navbarButton.update}>\n            <Button\n              ref={shouldDetectNavbarHeight ? observeNavbarHeight : undefined}\n              aria-busy={busy}\n              aria-label={title}\n              // The wheel itself shows the load, where the `loading` prop would\n              // cover it with a spinner\n              icon={\n                // The animated wheel needs `motion/react`, which is heavy, so it\n                // loads lazily — behind the plain icon it reimplements, which is\n                // all there is to show with `prefers-reduced-motion: reduce`\n                prefersReducedMotion ? (\n                  <ColorWheelIcon />\n                ) : (\n                  <Suspense fallback={<ColorWheelIcon />}>\n                    <AnimatedColorWheelIcon busy={busy} ref={iconRef} />\n                  </Suspense>\n                )\n              }\n              mode=\"bleed\"\n              onClick={open ? handleClose : handleOpen}\n              onFocus={handlePrerender}\n              onMouseEnter={handlePrerender}\n              // The Studio's own navbar buttons go through a wrapper that pins them\n              // to this padding, where `@sanity/ui` defaults to a roomier 3\n              padding={2}\n              selected={open || busy}\n            />\n          </ViewTransition>\n        </Box>\n      </Tooltip>\n    </ViewTransition>\n  )\n}\n\nexport function ThemerNavbar(props: NavbarProps) {\n  const button = useMemo(\n    () =>\n      ({\n        location: 'topbar',\n        name: 'themer-topbar',\n        // The component itself rather than a `() => <ThemerNavbarButton />`\n        // wrapper: the Studio renders `render` as a component, and a wrapper\n        // made anew on every render would remount the button each time —\n        // resetting its animation\n        render: ThemerNavbarButton,\n      }) satisfies NavbarAction,\n    [],\n  )\n  return props.renderDefault({\n    ...props,\n    __internal_actions: [...(props.__internal_actions ?? []), button],\n  })\n}\n\n// It can be easy to forget which contexts that ThemerNavbar requires and expects to be defined,\n// especially since TypeScript is unable to detect missing contexts statically,\n// parent views uses this component to ensure it doesn't miss anything and the props interface gives us type check validation.\nexport function ThemerNavbarProvider({\n  children,\n  config,\n  dispatch,\n  open,\n  shouldDetectNavbarHeight,\n  split,\n}: {children: React.ReactNode; shouldDetectNavbarHeight?: boolean} & Pick<\n  ThemerProps,\n  'dispatch' | 'config' | 'open' | 'split'\n>) {\n  return (\n    <PluginConfigContext value={config}>\n      <ToolDispatchContext value={dispatch}>\n        <ToolIsOpenContext value={open}>\n          <ToolSplitIsOpenContext value={split}>\n            <ToolShouldDetectNavbarHeightContext value={shouldDetectNavbarHeight ?? false}>\n              {children}\n            </ToolShouldDetectNavbarHeightContext>\n          </ToolSplitIsOpenContext>\n        </ToolIsOpenContext>\n      </ToolDispatchContext>\n    </PluginConfigContext>\n  )\n}\n","import {dequal} from 'dequal/lite'\n\nimport type {BuildThemeOptions} from '../theme/options'\n\n/**\n * What the layout shows, owned by the `useReducer` in `ThemerProvider` and\n * never persisted — it is each tab's own — handed down to the layout and the\n * sidebar as props and to the navbar toggle through the `Tool*Context`s:\n * whether the sidebar is open and whether the Studio shows twice, whether\n * either has been prerendered yet — they mount ahead of their first showing,\n * so that the code loads and the tree is warm before the transition — the\n * options of the applied theme, as the machine publishes them, and the\n * height of the Studio navbar, as the navbar toggle measures it, for the\n * sidebar's header to match.\n */\nexport type ToolReducerState = {\n  navbarHeight: number | null\n  open: boolean\n  prerender: boolean\n  prerenderSplitScreen: boolean\n  split: boolean\n  theme: BuildThemeOptions | null\n}\n\nexport type ToolReducerAction =\n  | {type: 'set-navbar-height'; height: number}\n  | {type: 'prerender'}\n  | {type: 'open'}\n  | {type: 'close'}\n  | {type: 'split-screen:prerender'}\n  | {type: 'split-screen:open'}\n  | {type: 'split-screen:close'}\n  | {type: 'set-theme'; theme: BuildThemeOptions}\n  | {type: 'unset-theme'}\n\nexport function toolReducer(state: ToolReducerState, action: ToolReducerAction): ToolReducerState {\n  switch (action.type) {\n    case 'set-navbar-height':\n      return state.navbarHeight === action.height ? state : {...state, navbarHeight: action.height}\n    case 'prerender':\n      return state.prerender ? state : {...state, prerender: true}\n    case 'open':\n      return state.open ? state : {...state, open: true, prerender: true}\n    case 'close':\n      return state.open ? {...state, open: false} : state\n    case 'split-screen:prerender':\n      return state.prerenderSplitScreen ? state : {...state, prerenderSplitScreen: true}\n    case 'split-screen:open':\n      return state.split ? state : {...state, prerenderSplitScreen: true, split: true}\n    case 'split-screen:close':\n      return state.split ? {...state, split: false} : state\n    case 'unset-theme':\n      return state.theme === null ? state : {...state, theme: null}\n    case 'set-theme':\n      return dequal(state.theme, action.theme) ? state : {...state, theme: action.theme}\n    default: {\n      // Every action is handled above, so only a dispatch the types do not\n      // know about gets here — a bug worth hearing of, not a silent no-op\n      const unknown: never = action\n      throw new Error(`Unknown themer tool action: ${JSON.stringify(unknown)}`)\n    }\n  }\n}\n\n/**\n * Where a tab starts: closed, nothing prerendered, no theme applied —\n * `ThemerProvider` seeds only the applied theme, from the machine's restored\n * snapshot\n */\nexport const initialToolState = {\n  navbarHeight: null,\n  open: false,\n  prerender: false,\n  prerenderSplitScreen: false,\n  split: false,\n  theme: null,\n} as const satisfies ToolReducerState\n","import type {BuildThemeOptions} from '../theme/options'\nimport {presets} from '../theme/presets'\nimport type {ThemerState} from './themes'\n\n/**\n * The options of the applied theme — `null` for the configured theme, which\n * applies nothing on top of the Studio's own, and for an applied theme that\n * no longer resolves. Cheaper than resolving the whole list when only the\n * applied theme matters.\n *\n * @internal\n */\nexport function resolveActiveThemeOptions(state: ThemerState): BuildThemeOptions | null {\n  if (state.active === null || state.removed.includes(state.active)) return null\n\n  for (const theme of state.custom) {\n    if (theme.slug === state.active) return theme.options\n  }\n  for (const preset of presets) {\n    if (preset.slug === state.active) return preset.options\n  }\n\n  return null\n}\n","import * as v from 'valibot'\n\nimport {isColor} from '../lib/mix'\nimport {\n  type BuildThemeOptions,\n  MAXIMUM_CONTRAST,\n  MINIMUM_CONTRAST,\n  SCHEMES,\n  type SchemeThemeOptions,\n} from '../theme/options'\nimport {presets} from '../theme/presets'\nimport type {ImagePalette} from './imagePalette'\nimport type {ThemerMachineContext} from './machine'\nimport {CONFIG_SLUG, type CustomTheme, displayTitle, type ThemerState} from './themes'\n\n/*\n * What the tool keeps in `localStorage` is parsed with these schemas as it is\n * read back, so that a session starts from what it can use of what an\n * earlier one left — whatever version of the tool wrote it, and whatever\n * happened to it since. The schemas are lenient where the old sanitizers\n * were: a color that is not one is dropped rather than failing the theme it\n * is part of, a theme that cannot be used is dropped rather than failing the\n * list, and the shapes of earlier versions are converted into today's.\n */\n\n/** Drops the keys whose value is `undefined`, which a dropped option leaves behind */\nfunction compact<T extends object>(value: T): T {\n  // oxlint-disable-next-line no-unsafe-type-assertion -- the same keys, minus the undefined ones\n  return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined)) as T\n}\n\n/** A `#rgb` or `#rrggbb` color, lowercased */\nconst color = v.pipe(v.string(), v.check(isColor), v.toLowerCase())\n\n/** A color that is dropped rather than failing what it is part of */\nconst optionalColor = v.fallback(v.optional(color), undefined)\n\n/** A contrast, clamped into range — dropped when it is not a number */\nconst optionalContrast = v.fallback(\n  v.optional(\n    v.pipe(v.number(), v.finite(), v.toMinValue(MINIMUM_CONTRAST), v.toMaxValue(MAXIMUM_CONTRAST)),\n  ),\n  undefined,\n)\n\nconst schemeOptionsSchema = v.pipe(\n  v.object({\n    accent: optionalColor,\n    text: optionalColor,\n    background: optionalColor,\n    contrast: optionalContrast,\n  }),\n  v.transform((options): SchemeThemeOptions => compact(options)),\n)\n\n/** Options grouped by scheme, as they are today — a scheme without usable options is left out */\nconst groupedOptionsSchema = v.pipe(\n  v.looseObject({\n    light: v.fallback(v.optional(schemeOptionsSchema), undefined),\n    dark: v.fallback(v.optional(schemeOptionsSchema), undefined),\n  }),\n  // The flat shape of earlier versions always had an accent at the top\n  v.check((input) => !('accent' in input), 'flat options'),\n  v.transform(({light, dark}): BuildThemeOptions => {\n    const options: BuildThemeOptions = {}\n\n    if (light && Object.keys(light).length > 0) options.light = light\n    if (dark && Object.keys(dark).length > 0) options.dark = dark\n\n    return options\n  }),\n)\n\n/**\n * Options from before they were grouped by scheme: one accent, text color and\n * contrast for both schemes, and a background per scheme. Both schemes get\n * the shared colors, so the theme keeps looking the same.\n */\nconst flatOptionsSchema = v.pipe(\n  v.object({\n    accent: color,\n    text: optionalColor,\n    contrast: optionalContrast,\n    background: v.fallback(\n      v.optional(v.object({light: optionalColor, dark: optionalColor})),\n      undefined,\n    ),\n  }),\n  v.transform(({accent, text, contrast, background}): BuildThemeOptions => {\n    const shared: SchemeThemeOptions = compact({accent, text, contrast})\n    const options: BuildThemeOptions = {}\n\n    for (const scheme of SCHEMES) {\n      const schemeBackground = background?.[scheme]\n\n      options[scheme] = schemeBackground ? {...shared, background: schemeBackground} : {...shared}\n    }\n\n    return options\n  }),\n)\n\n/** The `buildTheme` options of a theme, in today's shape or an earlier version's @internal */\nexport const themeOptionsSchema = v.union([flatOptionsSchema, groupedOptionsSchema])\n\n/** A swatch of an image palette — `null` when it is missing or not a color */\nconst swatch = v.fallback(v.optional(v.nullable(color), null), null)\n\n/** The palette a theme took its colors from — `null` without a single swatch */\nconst paletteSchema = v.pipe(\n  v.object({\n    vibrant: swatch,\n    lightVibrant: swatch,\n    darkVibrant: swatch,\n    muted: swatch,\n    lightMuted: swatch,\n    darkMuted: swatch,\n    dominant: swatch,\n  }),\n  v.transform((palette): ImagePalette | null =>\n    Object.values(palette).some((item) => item !== null) ? palette : null,\n  ),\n)\n\nfunction isReservedSlug(slug: string): boolean {\n  return slug === CONFIG_SLUG || presets.some((preset) => preset.slug === slug)\n}\n\nconst customThemeSchema = v.pipe(\n  v.object({\n    slug: v.pipe(\n      v.string(),\n      v.nonEmpty(),\n      v.check((slug) => !isReservedSlug(slug), 'reserved slug'),\n    ),\n    title: v.fallback(v.optional(v.string()), undefined),\n    options: themeOptionsSchema,\n    palette: v.fallback(v.optional(paletteSchema), undefined),\n  }),\n  v.transform(({slug, title, options, palette}): CustomTheme => ({\n    slug,\n    title: displayTitle(title ?? ''),\n    options,\n    ...(palette ? {palette} : {}),\n  })),\n)\n\n/** The items of a list that can be used, each parsed on its own so that one bad item does not fail the rest */\nconst lenientList = v.fallback(v.optional(v.array(v.unknown()), []), [])\n\n/**\n * The persisted themer state — the applied theme, the user's themes and\n * what was removed and reordered — as it is read back. Custom themes that\n * cannot be used, repeated slugs, and removed or ordered slugs that name no\n * theme are dropped.\n */\nconst themerStateSchema = v.pipe(\n  v.object({\n    active: v.fallback(v.nullable(v.string()), null),\n    custom: lenientList,\n    removed: lenientList,\n    order: lenientList,\n  }),\n  v.transform((state): ThemerState => {\n    const custom: CustomTheme[] = []\n\n    for (const item of state.custom) {\n      const result = v.safeParse(customThemeSchema, item)\n\n      if (result.success && !custom.some((theme) => theme.slug === result.output.slug)) {\n        custom.push(result.output)\n      }\n    }\n\n    const isCustom = (slug: string) => custom.some((theme) => theme.slug === slug)\n    const isPreset = (slug: string) => presets.some((preset) => preset.slug === slug)\n    const removed: string[] = []\n    const order: string[] = []\n\n    for (const slug of state.removed) {\n      if (typeof slug !== 'string' || slug === CONFIG_SLUG || removed.includes(slug)) continue\n      if (isPreset(slug) || isCustom(slug)) removed.push(slug)\n    }\n    for (const slug of state.order) {\n      if (typeof slug !== 'string' || order.includes(slug)) continue\n      if (slug === CONFIG_SLUG || isPreset(slug) || isCustom(slug)) order.push(slug)\n    }\n\n    return {active: state.active, custom, removed, order}\n  }),\n)\n\n/** The persisted themer state, or `null` for anything else @internal */\nexport function parseThemerState(input: unknown): ThemerState | null {\n  const result = v.safeParse(themerStateSchema, input)\n\n  return result.success ? result.output : null\n}\n\n/** The flows a session restores to */\nconst flowSchema = v.picklist(['list', 'edit', 'removed'])\n\n/**\n * The machine's state value, as persisted — only what the machine has states\n * for restores. The list's dialogs are states of the list, so a snapshot\n * written while one was open names it; the dialog does not reopen\n */\nconst snapshotValueSchema = v.object({\n  flow: v.union([flowSchema, v.object({list: v.picklist(['idle', 'pasting', 'snippet'])})]),\n  theme: v.picklist(['applied', 'switching']),\n})\n\n/**\n * The machine's persisted snapshot, as `getPersistedSnapshot()` writes it and\n * `createActor` restores it — `status`, `value`, `context`, `historyValue`\n * and `children`, with `output` and `error` left out as `undefined`.\n *\n * @internal\n */\nexport interface PersistedThemerSnapshot {\n  status: 'active'\n  output: undefined\n  error: undefined\n  value: {flow: v.InferOutput<typeof flowSchema>; theme: 'applied' | 'switching'}\n  context: ThemerMachineContext\n  historyValue: Record<string, never>\n  children: Record<string, never>\n}\n\n/**\n * A snapshot for the machine to start a session from: the given themes, with\n * nothing being switched to, in the list unless a flow and its subject are\n * given. It is how the themes alone — all that earlier versions persisted —\n * are handed to a machine that only restores snapshots, and what a restored\n * snapshot is made fit for this session as.\n *\n * @internal\n */\nexport function snapshotFromState(\n  state: ThemerState,\n  editing: ThemerMachineContext['editing'] = null,\n  flow: PersistedThemerSnapshot['value']['flow'] = 'list',\n): PersistedThemerSnapshot {\n  return {\n    status: 'active',\n    output: undefined,\n    error: undefined,\n    value: {flow, theme: 'applied'},\n    context: {...state, editing, images: {}},\n    historyValue: {},\n    children: {},\n  }\n}\n\n/**\n * The machine's snapshot as the last session persisted it, made fit for this\n * one: the themes are parsed like any persisted state, the flow keeps its\n * subject or falls back to the list, a dialog that was open is closed, a\n * switch that was under way is over, and the image URLs of the last session\n * are gone with it.\n *\n * @internal\n */\nexport const persistedSnapshotSchema = v.pipe(\n  v.object({\n    status: v.literal('active'),\n    value: snapshotValueSchema,\n    context: v.pipe(\n      v.looseObject({\n        editing: v.fallback(\n          v.nullable(v.object({slug: v.string(), focusTitle: v.boolean()})),\n          null,\n        ),\n      }),\n      v.transform(({editing, ...state}) => ({editing, state: parseThemerState(state)})),\n      v.check(({state}) => state !== null, 'no themes'),\n    ),\n  }),\n  v.transform(({value, context}): PersistedThemerSnapshot => {\n    // Checked above, but the type does not know\n    const state = context.state ?? {active: null, custom: [], removed: [], order: []}\n    const editing =\n      context.editing &&\n      state.custom.some((theme) => theme.slug === context.editing?.slug) &&\n      !state.removed.includes(context.editing.slug)\n        ? context.editing\n        : null\n    const flow =\n      typeof value.flow !== 'string' ||\n      (value.flow === 'edit' && editing === null) ||\n      (value.flow === 'removed' && state.removed.length === 0)\n        ? 'list'\n        : value.flow\n\n    return snapshotFromState(state, editing, flow)\n  }),\n)\n","import * as v from 'valibot'\nimport type {Snapshot} from 'xstate'\n\nimport {\n  parseThemerState,\n  type PersistedThemerSnapshot,\n  persistedSnapshotSchema,\n  snapshotFromState,\n  themeOptionsSchema,\n} from './schemas'\nimport type {CustomTheme} from './themes'\n\n/** Where the machine's snapshot is kept between sessions */\nconst SNAPSHOT_STORAGE_KEY = 'sanityStudio:themer:snapshot'\n\n/**\n * Where earlier versions kept the persisted state — the applied theme, the\n * user's themes and what was removed and reordered — before the machine's\n * whole snapshot was persisted. Read until the first snapshot is written.\n */\nconst STATE_STORAGE_KEY = 'sanityStudio:themer:state'\n\n/**\n * Where the earliest versions of the tool kept their single draft theme — it\n * is migrated into a custom theme, so a draft survives the upgrade.\n */\nconst LEGACY_STORAGE_KEY = 'sanityStudio:themer:options'\n\n/**\n * What the draft of the earliest versions is imported as — the same theme\n * whichever tab reads it first, so that tabs upgrading side by side agree\n */\nconst LEGACY_DRAFT: Omit<CustomTheme, 'options'> = {slug: 'custom-draft', title: 'Draft theme'}\n\nfunction readJson(key: string): unknown {\n  const raw = localStorage.getItem(key)\n\n  return raw ? JSON.parse(raw) : undefined\n}\n\n/**\n * Restores the machine's snapshot from what the last session persisted, for\n * `createActor` to start from, so the user's themes survive Studio reloads:\n * the snapshot itself where there is one that fits, and one made from the\n * themes alone where the snapshot no longer fits the machine or where\n * earlier versions of the tool stored the themes without a snapshot.\n * `undefined` when nothing usable is stored — or storage cannot be read at\n * all — leaves the machine to start from no themes.\n *\n * The parsing is the schemas' (see `schemas.ts`): nothing here or in the\n * machine looks at what is stored beyond handing it over.\n *\n * @internal\n */\nexport function readPersistedSnapshot(): PersistedThemerSnapshot | undefined {\n  try {\n    if (typeof localStorage === 'undefined') return undefined\n\n    const persisted = readJson(SNAPSHOT_STORAGE_KEY)\n\n    if (persisted !== undefined) {\n      const snapshot = v.safeParse(persistedSnapshotSchema, persisted)\n\n      if (snapshot.success) return snapshot.output\n\n      // A snapshot from a version of the machine with other states still\n      // holds the themes, which is what matters\n      const state = parseThemerState(\n        persisted && typeof persisted === 'object' ? Reflect.get(persisted, 'context') : undefined,\n      )\n\n      if (state) return snapshotFromState(state)\n    }\n\n    const state = parseThemerState(readJson(STATE_STORAGE_KEY))\n\n    if (state) return snapshotFromState(state)\n\n    return readLegacyDraft()\n  } catch {\n    return undefined\n  }\n}\n\nfunction readLegacyDraft(): PersistedThemerSnapshot | undefined {\n  const options = v.safeParse(themeOptionsSchema, readJson(LEGACY_STORAGE_KEY))\n\n  if (!options.success) return undefined\n\n  const theme: CustomTheme = {...LEGACY_DRAFT, options: options.output}\n\n  return snapshotFromState({active: theme.slug, custom: [theme], removed: [], order: []})\n}\n\n/**\n * Persists the machine's snapshot for the next session, and lets go of what\n * earlier versions stored once it is written — which completes their\n * migration.\n *\n * @internal\n */\nexport function writePersistedSnapshot(snapshot: Snapshot<unknown>): void {\n  try {\n    if (typeof localStorage === 'undefined') return\n\n    localStorage.setItem(SNAPSHOT_STORAGE_KEY, JSON.stringify(snapshot))\n    localStorage.removeItem(STATE_STORAGE_KEY)\n    localStorage.removeItem(LEGACY_STORAGE_KEY)\n  } catch {\n    // Storage can be unavailable (e.g. private browsing) — themes just won't persist\n  }\n}\n","import {assign, not, setup, type SnapshotFrom} from 'xstate'\n\nimport type {BuildThemeOptions} from '../theme/options'\nimport type {ImagePalette} from './imagePalette'\nimport {\n  CONFIG_SLUG,\n  CONFIG_TITLE,\n  createCustomTheme,\n  duplicateTitle,\n  initialThemerState,\n  resolveThemes,\n  type ThemerState,\n  UNTITLED_THEME,\n} from './themes'\n\n/**\n * How long the machine stays `switching` after an event that applies another\n * theme, when no edit to the applied theme ends it sooner. The layout\n * cross-fades the Studio to the theme in the commit that follows the switch,\n * so this only bounds how long the tag lingers once that is done. Generous,\n * so that it never runs out before a slow deferred commit starts the fade.\n *\n * @internal\n */\nexport const MOTION_DURATION = 2000\n\n/** @internal */\nexport interface ThemerMachineContext extends ThemerState {\n  /** The theme open in the editor, while the `flow` is `edit` */\n  editing: {\n    slug: string\n    /** Whether the title input should take focus, for themes that were just created */\n    focusTitle: boolean\n  } | null\n  /**\n   * Object URLs of the images that themes took their palette from, by theme\n   * slug — kept for the session only, so the image can be shown right after\n   * it was picked\n   */\n  images: Record<string, string>\n}\n\n/** @internal */\nexport type ThemerEvent =\n  /** Applies a theme to the whole Studio */\n  | {type: 'theme.pick'; slug: string}\n  /**\n   * Adds a theme and opens it in the editor — based on the applied theme, or\n   * on the given title, options and image palette (e.g. from an image)\n   */\n  | {\n      type: 'theme.add'\n      title?: string\n      options?: BuildThemeOptions\n      palette?: ImagePalette\n      imageUrl?: string\n    }\n  /** Adds a copy of a theme and opens it in the editor */\n  | {type: 'theme.duplicate'; slug: string}\n  /** Adds a theme someone shared as a code, and applies it — staying in the list */\n  | {type: 'theme.import'; title: string; options: BuildThemeOptions}\n  /** Opens one of the user's own themes in the editor */\n  | {type: 'theme.edit'; slug: string}\n  | {\n      type: 'theme.update'\n      slug: string\n      title?: string\n      options?: BuildThemeOptions\n      palette?: ImagePalette\n      imageUrl?: string\n    }\n  /** Takes a theme out of the list — it can be restored until it is deleted */\n  | {type: 'theme.remove'; slug: string}\n  /** Puts a removed theme back in the list */\n  | {type: 'theme.restore'; slug: string}\n  /** Deletes one of the user's own themes for good */\n  | {type: 'theme.delete'; slug: string}\n  /** Rearranges the list: the slugs of the listed themes, in their new order */\n  | {type: 'theme.reorder'; order: string[]}\n  /** Back to picking a theme */\n  | {type: 'flow.list'}\n  /** On to restoring removed themes */\n  | {type: 'flow.removed'}\n  /** Opens the dialog for adding a shared theme code by hand, from the list */\n  | {type: 'dialog.paste'}\n  /** Opens the dialog with the applied theme's `buildTheme` snippet, from the list */\n  | {type: 'dialog.snippet'}\n  /** Closes whichever dialog is open */\n  | {type: 'dialog.close'}\n  /**\n   * Takes over the persisted state as another tab of the same Studio changed\n   * it, so that every tab shows the same themes (see `sync.ts`)\n   */\n  | {type: 'themes.sync'; state: ThemerState}\n\nfunction themesOf(context: ThemerMachineContext) {\n  return resolveThemes(context)\n}\n\nfunction revokeObjectUrl(url: string) {\n  if (typeof URL !== 'undefined' && typeof URL.revokeObjectURL === 'function') {\n    URL.revokeObjectURL(url)\n  }\n}\n\n/**\n * The themes of the themer tool and the sidebar's way through them: which\n * `flow` the sidebar is in — picking a theme from the `list`, with its\n * dialogs for pasting a shared code and for the applied theme's snippet,\n * `edit`ing one of the user's own themes, or restoring `removed` ones — and,\n * in a parallel `theme` region, whether another theme was just applied. The\n * context carries the persisted state (the applied theme, the user's themes\n * and what was removed) alongside what the flows need. Whether the sidebar is\n * open and whether the Studio shows twice is not the machine's: the tool\n * reducer in `ThemerProvider` owns that, so that the navbar toggle and the\n * sidebar can change it in transitions of their own. Nor is persisting: the\n * machine never touches storage and takes no input — it starts from no\n * themes, and a session with something to pick up from restores its\n * persisted snapshot instead (see `storage.ts` and `sync.ts`), while the\n * persisted state of other tabs reaches it as a `themes.sync` event like any\n * other.\n *\n * The `theme` region is `switching` (its tag) right after an event that\n * applies another theme — picking one, adding, duplicating, importing or\n * editing one, removing or deleting the applied one — which is when the\n * layout cross-fades the Studio to it. Edits to the applied theme's colors are\n * not switches, they follow the pointer: the first one ends the switch, and so\n * does `MOTION_DURATION` when none follows.\n *\n * Theme operations are handled in every flow, and the flows leave on their\n * own when they lose their subject: the editor when its theme is removed or\n * deleted, and the removed view when its last theme is restored or deleted.\n *\n * @internal\n */\nexport const themerMachine = setup({\n  // XState reads `types` for their types only — the values are never used\n  types: {\n    // oxlint-disable-next-line no-unsafe-type-assertion -- type-level placeholder\n    context: {} as ThemerMachineContext,\n    // oxlint-disable-next-line no-unsafe-type-assertion -- type-level placeholder\n    events: {} as ThemerEvent,\n  },\n  guards: {\n    isCustomTheme: ({context}, params: {slug: string}) =>\n      themesOf(context).themes.some(\n        (theme) => theme.slug === params.slug && theme.source === 'custom',\n      ),\n    isEditingListedTheme: ({context}) =>\n      context.editing !== null &&\n      themesOf(context).themes.some(\n        (theme) => theme.slug === context.editing?.slug && theme.source === 'custom',\n      ),\n    hasRemovedThemes: ({context}) => themesOf(context).removed.length > 0,\n    // The configured theme has no code to show — it is the Studio's own\n    hasAppliedTheme: ({context}) => themesOf(context).active !== undefined,\n    // Only another theme than the applied one changes anything to cross-fade to\n    isAnotherTheme: ({context}, params: {slug: string}) =>\n      params.slug !== (context.active ?? CONFIG_SLUG),\n    // Removing or deleting the applied theme is what changes the applied theme\n    isAppliedTheme: ({context}, params: {slug: string}) => params.slug === context.active,\n    // Another tab applied another theme, which is as much of a switch as picking it here\n    appliesAnotherTheme: ({context}, params: {state: ThemerState}) =>\n      params.state.active !== context.active,\n    // A theme added from given options (an image's) looks different from the applied one\n    hasOptions: (_, params: {options: BuildThemeOptions | undefined}) =>\n      params.options !== undefined,\n  },\n  actions: {\n    // Another tab's persisted state replaces this one's: themes, order and\n    // all. The images of this session stay, they are this tab's\n    sync: assign((_, params: {state: ThemerState}) => ({\n      active: params.state.active,\n      custom: params.state.custom,\n      removed: params.state.removed,\n      order: params.state.order,\n    })),\n    // The image of a replaced palette or a deleted theme is released from memory\n    revokeImage: (_, params: {url: string | undefined}) => {\n      if (params.url) revokeObjectUrl(params.url)\n    },\n    pick: assign((_, params: {slug: string}) => ({\n      active: params.slug === CONFIG_SLUG ? null : params.slug,\n    })),\n    add: assign(\n      (\n        {context},\n        params: {\n          title?: string\n          options?: BuildThemeOptions\n          palette?: ImagePalette\n          imageUrl?: string\n        },\n      ) => {\n        // Based on the applied theme — the stock one when the configured\n        // theme applies, which is not in the list\n        const theme = createCustomTheme(\n          params.title ?? UNTITLED_THEME,\n          params.options ?? themesOf(context).active?.options ?? {},\n          params.palette,\n        )\n\n        return {\n          active: theme.slug,\n          custom: [...context.custom, theme],\n          // A theme named after its image needs no renaming right away\n          editing: {slug: theme.slug, focusTitle: params.title === undefined},\n          images: params.imageUrl\n            ? {...context.images, [theme.slug]: params.imageUrl}\n            : context.images,\n        }\n      },\n    ),\n    import: assign(({context}, params: {title: string; options: BuildThemeOptions}) => {\n      const theme = createCustomTheme(params.title, params.options)\n\n      return {active: theme.slug, custom: [...context.custom, theme]}\n    }),\n    duplicate: assign(({context}, params: {slug: string}) => {\n      const {themes, removed} = themesOf(context)\n      // The configured theme is not in the list: a copy of it starts from the\n      // stock options, as the Studio shows it\n      const source =\n        params.slug === CONFIG_SLUG\n          ? {title: CONFIG_TITLE, options: {}, palette: undefined}\n          : [...themes, ...removed].find((theme) => theme.slug === params.slug)\n\n      if (!source) return {}\n\n      const theme = createCustomTheme(duplicateTitle(source.title), source.options, source.palette)\n\n      return {\n        active: theme.slug,\n        custom: [...context.custom, theme],\n        editing: {slug: theme.slug, focusTitle: true},\n      }\n    }),\n    startEditing: assign((_, params: {slug: string}) => ({\n      active: params.slug,\n      editing: {slug: params.slug, focusTitle: false},\n    })),\n    stopEditing: assign({editing: null}),\n    update: assign(\n      (\n        {context},\n        params: {\n          slug: string\n          title?: string\n          options?: BuildThemeOptions\n          palette?: ImagePalette\n          imageUrl?: string\n        },\n      ) => ({\n        custom: context.custom.map((theme) => {\n          if (theme.slug !== params.slug) return theme\n\n          // Keep the options identity when only the title changes, so the\n          // applied theme is not rebuilt on every keystroke\n          return {\n            ...theme,\n            title: params.title ?? theme.title,\n            options: params.options ?? theme.options,\n            ...(params.palette ? {palette: params.palette} : {}),\n          }\n        }),\n        images:\n          params.imageUrl && context.custom.some((theme) => theme.slug === params.slug)\n            ? {...context.images, [params.slug]: params.imageUrl}\n            : context.images,\n      }),\n    ),\n    remove: assign(({context}, params: {slug: string}) => {\n      if (params.slug === CONFIG_SLUG || context.removed.includes(params.slug)) return {}\n\n      return {\n        active: context.active === params.slug ? null : context.active,\n        removed: [...context.removed, params.slug],\n      }\n    }),\n    restore: assign(({context}, params: {slug: string}) => ({\n      removed: context.removed.filter((slug) => slug !== params.slug),\n    })),\n    reorder: assign(({context}, params: {order: string[]}) => {\n      const listed = new Set(themesOf(context).themes.map((theme) => theme.slug))\n      const order = params.order.filter((slug) => listed.has(slug))\n\n      // The removed themes keep their place in line for when they are restored\n      return {\n        order: [...order, ...context.order.filter((slug) => !order.includes(slug))],\n      }\n    }),\n    delete: assign(({context}, params: {slug: string}) => {\n      if (!context.custom.some((theme) => theme.slug === params.slug)) return {}\n\n      const {[params.slug]: _deleted, ...images} = context.images\n\n      return {\n        active: context.active === params.slug ? null : context.active,\n        custom: context.custom.filter((theme) => theme.slug !== params.slug),\n        removed: context.removed.filter((slug) => slug !== params.slug),\n        images,\n      }\n    }),\n  },\n}).createMachine({\n  id: 'themer',\n  context: () => ({...initialThemerState, editing: null, images: {}}),\n  type: 'parallel',\n  states: {\n    theme: {\n      initial: 'applied',\n      states: {\n        // Only events that change what is applied count: adding a copy of the\n        // applied theme, editing or duplicating it, picking it again, or\n        // removing another theme leaves the Studio looking the same — with\n        // nothing to cross-fade, the switch would only linger until the first\n        // edit that followed, which must follow the pointer\n        applied: {\n          on: {\n            'theme.pick': {\n              guard: {type: 'isAnotherTheme', params: ({event}) => ({slug: event.slug})},\n              target: 'switching',\n            },\n            'theme.edit': {\n              guard: {type: 'isAnotherTheme', params: ({event}) => ({slug: event.slug})},\n              target: 'switching',\n            },\n            'theme.duplicate': {\n              guard: {type: 'isAnotherTheme', params: ({event}) => ({slug: event.slug})},\n              target: 'switching',\n            },\n            'theme.remove': {\n              guard: {type: 'isAppliedTheme', params: ({event}) => ({slug: event.slug})},\n              target: 'switching',\n            },\n            'theme.delete': {\n              guard: {type: 'isAppliedTheme', params: ({event}) => ({slug: event.slug})},\n              target: 'switching',\n            },\n            'theme.add': {\n              guard: {type: 'hasOptions', params: ({event}) => ({options: event.options})},\n              target: 'switching',\n            },\n            'theme.import': 'switching',\n            'themes.sync': {\n              guard: {type: 'appliesAnotherTheme', params: ({event}) => ({state: event.state})},\n              target: 'switching',\n            },\n          },\n        },\n        switching: {\n          tags: ['switching'],\n          after: {[MOTION_DURATION]: 'applied'},\n          on: {\n            // The editor edits the applied theme, and its colors must follow\n            // the pointer rather than cross-fade — a switch is over at the\n            // first edit, however soon it comes\n            'theme.update': 'applied',\n            // Another switch starts the clock over\n            'theme.pick': {\n              guard: {type: 'isAnotherTheme', params: ({event}) => ({slug: event.slug})},\n              target: 'switching',\n              reenter: true,\n            },\n            'theme.edit': {\n              guard: {type: 'isAnotherTheme', params: ({event}) => ({slug: event.slug})},\n              target: 'switching',\n              reenter: true,\n            },\n            'theme.duplicate': {\n              guard: {type: 'isAnotherTheme', params: ({event}) => ({slug: event.slug})},\n              target: 'switching',\n              reenter: true,\n            },\n            'theme.remove': {\n              guard: {type: 'isAppliedTheme', params: ({event}) => ({slug: event.slug})},\n              target: 'switching',\n              reenter: true,\n            },\n            'theme.delete': {\n              guard: {type: 'isAppliedTheme', params: ({event}) => ({slug: event.slug})},\n              target: 'switching',\n              reenter: true,\n            },\n            'theme.add': {\n              guard: {type: 'hasOptions', params: ({event}) => ({options: event.options})},\n              target: 'switching',\n              reenter: true,\n            },\n            'theme.import': {target: 'switching', reenter: true},\n            'themes.sync': {\n              guard: {type: 'appliesAnotherTheme', params: ({event}) => ({state: event.state})},\n              target: 'switching',\n              reenter: true,\n            },\n          },\n        },\n      },\n    },\n    flow: {\n      initial: 'list',\n      on: {\n        'theme.pick': {\n          actions: [{type: 'pick', params: ({event}) => ({slug: event.slug})}],\n        },\n        'theme.add': {\n          target: '.edit',\n          actions: [\n            {\n              type: 'add',\n              params: ({event}) => ({\n                title: event.title,\n                options: event.options,\n                palette: event.palette,\n                imageUrl: event.imageUrl,\n              }),\n            },\n          ],\n        },\n        'theme.duplicate': {\n          target: '.edit',\n          actions: [{type: 'duplicate', params: ({event}) => ({slug: event.slug})}],\n        },\n        'theme.edit': {\n          target: '.edit',\n          guard: {type: 'isCustomTheme', params: ({event}) => ({slug: event.slug})},\n          actions: [{type: 'startEditing', params: ({event}) => ({slug: event.slug})}],\n        },\n        'theme.update': {\n          actions: [\n            // A new image replaces the one the theme had\n            {\n              type: 'revokeImage',\n              params: ({context, event}) => ({\n                url: event.imageUrl ? context.images[event.slug] : undefined,\n              }),\n            },\n            {\n              type: 'update',\n              params: ({event}) => ({\n                slug: event.slug,\n                title: event.title,\n                options: event.options,\n                palette: event.palette,\n                imageUrl: event.imageUrl,\n              }),\n            },\n          ],\n        },\n        'theme.remove': {\n          actions: [{type: 'remove', params: ({event}) => ({slug: event.slug})}],\n        },\n        'theme.restore': {\n          actions: [{type: 'restore', params: ({event}) => ({slug: event.slug})}],\n        },\n        'theme.delete': {\n          actions: [\n            {\n              type: 'revokeImage',\n              params: ({context, event}) => ({url: context.images[event.slug]}),\n            },\n            {type: 'delete', params: ({event}) => ({slug: event.slug})},\n          ],\n        },\n        'theme.reorder': {\n          actions: [{type: 'reorder', params: ({event}) => ({order: event.order})}],\n        },\n        'theme.import': {\n          actions: [\n            {\n              type: 'import',\n              params: ({event}) => ({title: event.title, options: event.options}),\n            },\n          ],\n        },\n        'themes.sync': {\n          actions: {type: 'sync', params: ({event}) => ({state: event.state})},\n        },\n        'flow.list': '.list',\n        'flow.removed': {\n          target: '.removed',\n          guard: 'hasRemovedThemes',\n        },\n      },\n      states: {\n        list: {\n          initial: 'idle',\n          // The list's dialogs — for a shared code pasted by hand, and for the\n          // applied theme's snippet — are states of the list, so that leaving\n          // it, as adding a theme does for the editor, closes them\n          states: {\n            idle: {\n              on: {\n                'dialog.paste': 'pasting',\n                'dialog.snippet': {guard: 'hasAppliedTheme', target: 'snippet'},\n              },\n            },\n            pasting: {\n              on: {'dialog.close': 'idle'},\n            },\n            snippet: {\n              on: {'dialog.close': 'idle'},\n              // The applied theme can go away meanwhile — removed from another tab\n              always: {guard: not('hasAppliedTheme'), target: 'idle'},\n            },\n          },\n        },\n        edit: {\n          exit: 'stopEditing',\n          // The theme being edited can go away — removed from the editor, or\n          // duplicated from a theme that does not exist — and then there is\n          // nothing left to edit\n          always: {guard: not('isEditingListedTheme'), target: 'list'},\n        },\n        removed: {\n          always: {guard: not('hasRemovedThemes'), target: 'list'},\n        },\n      },\n    },\n  },\n})\n\n/** @internal */\nexport type ThemerSnapshot = SnapshotFrom<typeof themerMachine>\n\n/** The part of the machine context that is persisted between sessions @internal */\nexport function selectStoredState(snapshot: ThemerSnapshot): ThemerState {\n  const {active, custom, removed, order} = snapshot.context\n\n  return {active, custom, removed, order}\n}\n","import {dequal} from 'dequal/lite'\nimport type {ActorRefFrom, Snapshot} from 'xstate'\n\nimport {selectStoredState, type themerMachine} from './machine'\nimport {parseThemerState} from './schemas'\nimport type {ThemerState} from './themes'\n\n/** The channel every tab of the same origin shares — one Studio, one set of themes */\nconst CHANNEL_NAME = 'sanity-themer'\n\n/**\n * The lock the one tab that persists holds for as long as it lives. The\n * other tabs queue for it, so when that tab goes away the next one in line\n * takes over the persisting — nothing is ever written from two tabs at once\n */\nconst LOCK_NAME = 'sanity-themer:persist'\n\n/** How long a persist waits for the browser to be idle before it goes ahead anyway */\nconst PERSIST_TIMEOUT = 1_000\n\n/**\n * What the tabs tell each other. Every change to the persisted state goes\n * around as `state`, with the `revision` it brings the state to — one more\n * than the last one the tab heard of — and the tab it is `from`: a tab takes\n * a state only when it is newer than the one it has, ties going to the\n * higher tab id, so that two tabs changing at once end up with the same\n * state rather than each other's. A tab that just started asks for the\n * current state with `hello`, answered with a `state` addressed `to` it,\n * which only it takes, and only while it has changed nothing of its own yet\n * — a change it made meanwhile goes around again instead, ahead of the\n * answer, so that a late answer never undoes it\n */\ntype SyncMessage =\n  | {type: 'hello'; from: string}\n  | {type: 'state'; state: ThemerState; revision: number; from: string; to?: string}\n\n/** What the sync needs of a `BroadcastChannel` @internal */\nexport interface SyncChannel {\n  /** Sends a message to the other tabs — not to this one */\n  post(message: unknown): void\n  /** Hears the other tabs' messages; returns what stops listening */\n  listen(listener: (data: unknown) => void): () => void\n  close(): void\n}\n\n/** What the sync needs of `navigator.locks` @internal */\nexport interface SyncLocks {\n  request(\n    name: string,\n    options: {signal?: AbortSignal},\n    callback: () => Promise<unknown>,\n  ): Promise<unknown>\n}\n\n/**\n * What the sync does with the browser, each replaceable — so that it can run\n * under test, and so that it degrades where a browser lacks an API: without\n * a channel the tabs do not hear of each other, and without locks every tab\n * persists for itself\n *\n * @internal\n */\nexport interface ThemerSyncOptions {\n  /** Persists the machine's snapshot — from the one tab that holds the lock */\n  persist: (snapshot: Snapshot<unknown>) => void\n  /** Opens the channel to the other tabs, or `null` where there is none */\n  openChannel?: () => SyncChannel | null\n  /** Elects the tab that persists, or `undefined` where there is no lock manager */\n  locks?: SyncLocks | undefined\n  /** Defers a persist to an idle moment; returns what cancels it */\n  schedule?: (callback: () => void) => () => void\n}\n\nfunction openBroadcastChannel(): SyncChannel | null {\n  if (typeof BroadcastChannel !== 'function') return null\n\n  const channel = new BroadcastChannel(CHANNEL_NAME)\n\n  return {\n    // oxlint-disable-next-line require-post-message-target-origin -- a BroadcastChannel is same-origin by nature, its postMessage takes no target\n    post: (message) => channel.postMessage(message),\n    listen: (listener) => {\n      const onMessage = (event: MessageEvent) => listener(event.data)\n\n      channel.addEventListener('message', onMessage)\n\n      return () => channel.removeEventListener('message', onMessage)\n    },\n    close: () => channel.close(),\n  }\n}\n\nfunction browserLocks(): SyncLocks | undefined {\n  // Web Locks need a secure context, where `navigator.locks` is undefined otherwise\n  return typeof navigator !== 'undefined' && 'locks' in navigator ? navigator.locks : undefined\n}\n\nfunction scheduleIdle(callback: () => void): () => void {\n  if (typeof requestIdleCallback === 'function') {\n    const id = requestIdleCallback(callback, {timeout: PERSIST_TIMEOUT})\n\n    return () => cancelIdleCallback(id)\n  }\n\n  const id = setTimeout(callback, PERSIST_TIMEOUT)\n\n  return () => clearTimeout(id)\n}\n\nfunction parseMessage(data: unknown): SyncMessage | null {\n  if (!data || typeof data !== 'object') return null\n\n  const type: unknown = Reflect.get(data, 'type')\n\n  if (type === 'hello') {\n    const from: unknown = Reflect.get(data, 'from')\n\n    return typeof from === 'string' ? {type, from} : null\n  }\n\n  if (type === 'state') {\n    const state = parseThemerState(Reflect.get(data, 'state'))\n    const revision: unknown = Reflect.get(data, 'revision')\n    const from: unknown = Reflect.get(data, 'from')\n    const to: unknown = Reflect.get(data, 'to')\n\n    if (!state || typeof revision !== 'number' || !Number.isFinite(revision)) return null\n    if (typeof from !== 'string') return null\n\n    return {type, state, revision, from, ...(typeof to === 'string' ? {to} : {})}\n  }\n\n  return null\n}\n\nfunction tabId(): string {\n  return typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n    ? crypto.randomUUID()\n    : Math.random().toString(36).slice(2)\n}\n\n/**\n * Keeps the themes of every tab of the Studio the same, and persists them\n * from one tab only.\n *\n * Every tab runs its own machine, and what the machine persists — the\n * applied theme, the user's themes, what was removed and reordered — goes\n * around to the other tabs on a `BroadcastChannel` as it changes, where it\n * reaches their machines as a `themes.sync` event: the same themes\n * everywhere, with the flow each tab is in, the tool's open and split state\n * (the reducer's, in `plugin.tsx`) and the images of this session staying\n * the tab's own. A tab that starts asks the others for the current state,\n * in case what it read from storage was not written yet.\n *\n * Persisting is the business of one tab at a time: the one holding the Web\n * Lock, which it keeps for as long as it lives. The others queue for it, so\n * the next tab takes over as the holder goes away, and a tab that takes\n * over persists right away, in case the last one left with a write pending.\n * Writes happen when the browser is idle — a run of edits is written once —\n * and as the page hides, so that nothing pending is lost.\n *\n * Returns what stops the sync: it lets go of the lock, which hands the\n * persisting on, and closes the channel.\n *\n * @internal\n */\nexport function syncThemer(\n  actorRef: ActorRefFrom<typeof themerMachine>,\n  options: ThemerSyncOptions,\n): () => void {\n  const {persist, openChannel = openBroadcastChannel, schedule = scheduleIdle} = options\n  const channel = openChannel()\n  // Without a channel the tabs cannot hear of each other's changes, so each\n  // persists its own — a lock would only silence the tabs not holding it.\n  // Given as `undefined` means no lock manager, not the browser's: Node has\n  // one too these days\n  const locks = channel ? ('locks' in options ? options.locks : browserLocks()) : undefined\n  const id = tabId()\n  const abort = new AbortController()\n  let leader = false\n  let cancelPersist: (() => void) | undefined\n  /** Whether another tab's state is being sent into the machine, which is nothing to pass on */\n  let applying = false\n  /** The persisted state as the other tabs last heard it from this one, or this one from them */\n  let shared = selectStoredState(actorRef.getSnapshot())\n  /** The revision `shared` is at, and the tab whose change it was */\n  let revision = 0\n  let origin = id\n  /** Whether this tab still has what it started with, so that an answer to its `hello` is welcome */\n  let unchanged = true\n  /** The tabs that said hello before this one held the lock, to answer once it does */\n  const unanswered = new Set<string>()\n\n  const isNewer = (message: {revision: number; from: string}) =>\n    message.revision > revision || (message.revision === revision && message.from > origin)\n\n  const persistNow = () => {\n    cancelPersist?.()\n    cancelPersist = undefined\n    persist(actorRef.getPersistedSnapshot())\n  }\n  const persistSoon = () => {\n    cancelPersist?.()\n    cancelPersist = schedule(persistNow)\n  }\n  const answer = (to: string) => {\n    channel?.post({type: 'state', state: shared, revision, from: origin, to} satisfies SyncMessage)\n  }\n  const becomeLeader = () => {\n    leader = true\n    persistNow()\n    // Tabs that started alongside this one asked before anyone held the lock\n    for (const from of unanswered) answer(from)\n    unanswered.clear()\n  }\n\n  if (locks) {\n    locks\n      .request(LOCK_NAME, {signal: abort.signal}, () => {\n        becomeLeader()\n\n        // Held until the sync stops, which hands the lock to the next tab in line\n        return new Promise<void>((resolve) => {\n          abort.signal.addEventListener('abort', () => resolve(), {once: true})\n        })\n      })\n      .catch(() => {\n        // The sync stopped before the lock was granted — nothing to let go of\n      })\n  } else {\n    becomeLeader()\n  }\n\n  const subscription = actorRef.subscribe((snapshot) => {\n    if (leader) persistSoon()\n    if (applying) return\n\n    const state = selectStoredState(snapshot)\n\n    // Only changes to what is persisted concern the other tabs — the flow is this tab's\n    if (dequal(state, shared)) return\n\n    shared = state\n    unchanged = false\n    revision += 1\n    origin = id\n    channel?.post({type: 'state', state, revision, from: id} satisfies SyncMessage)\n  })\n\n  if (channel) {\n    channel.listen((data) => {\n      const message = parseMessage(data)\n\n      if (!message) return\n\n      if (message.type === 'hello') {\n        // The tab that persists speaks for all, so that the newcomer hears one\n        // answer — or hears it once a tab holds the lock\n        if (leader) {\n          answer(message.from)\n        } else {\n          unanswered.add(message.from)\n        }\n\n        return\n      }\n\n      if (message.to !== undefined) {\n        if (message.to !== id) return\n\n        if (!unchanged) {\n          // Asked before this tab changed anything, answered after: the change\n          // is the later one, and goes around again ahead of the answer\n          if (origin === id) {\n            revision = Math.max(revision, message.revision) + 1\n            channel.post({type: 'state', state: shared, revision, from: id} satisfies SyncMessage)\n\n            return\n          }\n\n          // Answered twice — without a lock manager every tab answers — the\n          // answers are ordered like any other state\n          if (!isNewer(message)) return\n        }\n      } else if (!isNewer(message)) {\n        return\n      }\n\n      revision = message.revision\n      origin = message.from\n      if (dequal(message.state, shared)) return\n\n      shared = message.state\n      unchanged = false\n      applying = true\n      try {\n        actorRef.send({type: 'themes.sync', state: message.state})\n      } finally {\n        applying = false\n      }\n    })\n    channel.post({type: 'hello', from: id} satisfies SyncMessage)\n  }\n\n  const flush = () => {\n    if (leader && cancelPersist) persistNow()\n  }\n  const page = typeof window === 'undefined' ? undefined : window\n\n  page?.addEventListener('pagehide', flush)\n\n  return () => {\n    subscription.unsubscribe()\n    page?.removeEventListener('pagehide', flush)\n    flush()\n    abort.abort()\n    channel?.close()\n  }\n}\n","import {useEffect} from 'react'\n\nimport type {ThemerProps} from '#types'\n\nimport {writePersistedSnapshot} from './storage'\nimport {syncThemer} from './sync'\n\n/**\n * Persists the machine's snapshot for the next session, and keeps the themes\n * in step with the other tabs of the Studio — from the one tab holding the\n * Web Lock, when the browser is idle; see `sync.ts`. Rendered by the layout,\n * outside the sidebar's `Activity`, so that it runs while the sidebar is\n * closed too: other tabs change the themes whether this one shows them or\n * not.\n */\nexport function PersistActorSnapshot({actorRef}: Pick<ThemerProps, 'actorRef'>) {\n  useEffect(() => syncThemer(actorRef, {persist: writePersistedSnapshot}), [actorRef])\n\n  return null\n}\n","import {BoundaryElementProvider, Card, Flex} from '@sanity/ui'\nimport type {ThemeColorSchemeKey} from '@sanity/ui/theme'\nimport {useActorRef} from '@xstate/react'\nimport {Activity, lazy, startTransition, useEffect, useState, ViewTransition} from 'react'\n\nimport type {PluginConfig} from '#types'\nimport type {ThemerProps} from '#types'\n\nimport {addThemerTransitionType} from './addThemerTransitionType'\nimport {themerMachine} from './machine'\nimport {PersistActorSnapshot} from './PersistActorSnapshot'\nimport type {ToolReducerState} from './reducer'\nimport {resolveActiveThemeOptions} from './selectors'\nimport type {readPersistedSnapshot} from './storage'\nimport {ThemerNavbarProvider} from './ThemerNavbar'\n\nimport {layout, viewTransitionClasses} from './ViewTransitions.css'\n\n/**\n * The sidebar — everything in it, from the theme list to the snippet dialog —\n * loads the first time it opens. There is no `Suspense` boundary around it,\n * so it must only ever mount from a transition: the navbar toggle prerenders\n * it in one as the pointer comes near, which keeps the Studio as it was while\n * the code loads, where an urgent render would suspend up to the Studio's\n * own boundary and swap the whole Studio for its loading screen.\n */\nconst ResizableSidebar = lazy(() => import('./ResizableSidebar'))\n\ninterface ThemerLayoutProps extends Omit<ToolReducerState, 'theme'> {\n  children: React.ReactNode\n  config: PluginConfig\n  dispatch: ThemerProps['dispatch']\n  /** The machine's snapshot as the last session persisted it, for the machine to pick up where it left off */\n  persistedSnapshot: ReturnType<typeof readPersistedSnapshot>\n}\n\n/**\n * Wraps the whole Studio to run the themer machine that the sidebar's flows\n * share — the user's themes, which one is applied and which flow the sidebar\n * is in — and renders the sidebar next to the Studio. The sidebar sits at\n * the `layout` level rather than in `activeToolLayout` because the split\n * preview renders the Studio twice, and the sidebar must not come along.\n *\n * Whether the sidebar is open and whether the Studio shows twice comes in as\n * props from the tool reducer in `ThemerProvider`, and goes on to the sidebar\n * as props along with the machine's actor, which the sidebar selects its\n * themes and flow from (see `ThemerProps`): the navbar toggle and the sidebar\n * dispatch to the reducer inside transitions tagged with a transition type\n * (see `addThemerTransitionType`), and the `ViewTransition` boundaries below\n * pick their classes by that type, so React animates the sidebar sliding in\n * and out, the split copy coming and going and a picked theme cross-fading\n * in (React 19.3), styled in `ViewTransitions.css.ts`. The sidebar and the\n * split copy stay mounted while hidden, in `Activity`, so that opening them\n * again is instant and they can prerender ahead of the transition. The\n * navbar toggle, which the Studio renders somewhere in `children`, reads the\n * same values and the plugin's options from the contexts\n * `ThemerNavbarProvider` provides in each copy of the Studio, and measures\n * the Studio navbar for the sidebar's header — in the Studio proper, not in\n * the split copy, which `ToolShouldDetectNavbarHeightContext` tells apart.\n *\n * The applied theme is the reducer's, provided above this layout in\n * `ThemerProvider`: the machine publishes it synchronously, which React does\n * not animate, so `ThemerThemeCrossfader` hands it to the reducer in a\n * transition of its own. The Studio next to the sidebar always follows the\n * appearance setting (light/dark/system) and the picked theme like any other\n * theme would; the split preview adds a second copy in the opposite scheme\n * on the far side.\n *\n * Whatever else on the page has a `view-transition-name` — an avatar the\n * Studio names so it moves as one piece — comes along in step: every\n * transition the layout starts carries `layoutTransitionType`, which the\n * stylesheet keys on to move every group in the layout's time (see\n * `ViewTransitions.css.ts`).\n *\n * @internal\n */\nexport function ThemerLayout({\n  children,\n  backgroundColor,\n  config,\n  dispatch,\n  navbarHeight,\n  open,\n  persistedSnapshot,\n  prerender,\n  prerenderSplitScreen,\n  scheme,\n  split,\n}: ThemerLayoutProps & {backgroundColor: string | undefined; scheme: ThemeColorSchemeKey}) {\n  const actorRef = useActorRef(themerMachine, {snapshot: persistedSnapshot})\n\n  const oppositeScheme: ThemeColorSchemeKey = scheme === 'dark' ? 'light' : 'dark'\n\n  return (\n    <>\n      <Flex\n        className={layout}\n        direction={'row'}\n        height=\"fill\"\n        sizing=\"border\"\n        style={{backgroundColor}}\n      >\n        {/* Renders the Studio for the second time, in the opposite scheme of the main studio. Hidden by default */}\n        <Activity mode={split && open ? 'visible' : 'hidden'}>\n          <ViewTransition\n            default=\"none\"\n            enter={viewTransitionClasses.splitscreen.enter}\n            update={viewTransitionClasses.splitscreen.update}\n            exit={viewTransitionClasses.splitscreen.exit}\n          >\n            {prerenderSplitScreen && (\n              <StudioPreview\n                borderRight\n                config={config}\n                dispatch={dispatch}\n                open={open}\n                scheme={oppositeScheme}\n                split={split}\n              >\n                {children}\n              </StudioPreview>\n            )}\n          </ViewTransition>\n        </Activity>\n        {/* Renders the Studio */}\n        <ViewTransition default=\"none\" update={viewTransitionClasses.studio.update}>\n          <StudioPreview\n            config={config}\n            dispatch={dispatch}\n            open={open}\n            shouldDetectNavbarHeight\n            split={split}\n          >\n            {children}\n          </StudioPreview>\n        </ViewTransition>\n        {/* Renders the Themer tool, hidden by default */}\n        <Activity mode={open ? 'visible' : 'hidden'}>\n          <ViewTransition\n            default=\"none\"\n            enter={viewTransitionClasses.sidebar.enter}\n            update={viewTransitionClasses.sidebar.update}\n            exit={viewTransitionClasses.sidebar.exit}\n          >\n            {prerender && (\n              <ResizableSidebar\n                actorRef={actorRef}\n                dispatch={dispatch}\n                navbarHeight={navbarHeight}\n                split={split}\n              />\n            )}\n          </ViewTransition>\n        </Activity>\n      </Flex>\n\n      <ThemerThemeCrossfader actorRef={actorRef} dispatch={dispatch} />\n      <RevokeImageUrls actorRef={actorRef} />\n      <PersistActorSnapshot actorRef={actorRef} />\n    </>\n  )\n}\n\n/**\n * One copy of the Studio, in the given color scheme — or, without one, in the\n * scheme the Studio is showing. The two copies of the split preview share the\n * router, the document store and every other provider above the layout —\n * only the scheme differs — so they stay in sync while navigating. The\n * `color-scheme` of a forced scheme keeps native form controls and scrollbars\n * in step with it. Each copy provides the navbar toggle it renders with the\n * contexts it reads (see `ThemerNavbarProvider`).\n */\nfunction StudioPreview({\n  borderRight,\n  children,\n  config,\n  dispatch,\n  open,\n  scheme,\n  shouldDetectNavbarHeight,\n  split,\n}: {\n  borderRight?: boolean\n  scheme?: ThemeColorSchemeKey\n} & React.ComponentProps<typeof ThemerNavbarProvider>) {\n  const [boundaryElement, setBoundaryElement] = useState<HTMLDivElement | null>(null)\n\n  return (\n    <Card\n      borderRight={borderRight}\n      flex={1}\n      height=\"fill\"\n      overflow=\"hidden\"\n      scheme={scheme}\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      <BoundaryElementProvider element={boundaryElement}>\n        <ThemerNavbarProvider\n          config={config}\n          dispatch={dispatch}\n          open={open}\n          shouldDetectNavbarHeight={shouldDetectNavbarHeight}\n          split={split}\n        >\n          <ViewTransition update=\"none\">{children}</ViewTransition>\n        </ThemerNavbarProvider>\n      </BoundaryElementProvider>\n    </Card>\n  )\n}\n\n/**\n * Hands the applied theme to the tool reducer as the machine publishes it —\n * in a transition tagged to cross-fade while the machine says a theme is\n * being switched to, so that editing the applied theme's colors applies live\n * while picking another theme fades the Studio over to it\n */\nfunction ThemerThemeCrossfader({actorRef, dispatch}: Pick<ThemerProps, 'actorRef' | 'dispatch'>) {\n  useEffect(() => {\n    const subscription = actorRef.subscribe((snapshot) => {\n      const switching = snapshot.hasTag('switching')\n      const theme = resolveActiveThemeOptions(snapshot.context)\n\n      startTransition(() => {\n        if (switching) {\n          addThemerTransitionType('crossfade')\n        }\n        if (!theme) {\n          dispatch({type: 'unset-theme'})\n        } else {\n          dispatch({type: 'set-theme', theme})\n        }\n      })\n    })\n\n    return () => subscription.unsubscribe()\n  }, [actorRef, dispatch])\n\n  return null\n}\n\nfunction RevokeImageUrls({actorRef}: Pick<ThemerProps, 'actorRef'>) {\n  // The machine releases the image of a palette as it is replaced or its\n  // theme deleted; whatever it still holds goes with the layout — the actor\n  // keeps its last snapshot once stopped\n  useEffect(\n    () => () => {\n      for (const url of Object.values(actorRef.getSnapshot().context.images)) {\n        URL.revokeObjectURL(url)\n      }\n    },\n    [actorRef],\n  )\n\n  return null\n}\n","import {ThemeProvider, useMediaIndex} from '@sanity/ui'\nimport {use, useReducer, useState} from 'react'\nimport {browser} from 'react-dom'\nimport {useColorSchemeValue} from 'sanity'\n\nimport {MIN_MEDIA_INDEX_FOR_SIDEBAR, MIN_MEDIA_INDEX_FOR_SPLIT_SCREEN} from '#constants'\nimport type {ThemerProps} from '#types'\n\nimport {buildTheme} from '../theme/buildTheme'\nimport {initialToolState, toolReducer} from './reducer'\nimport {resolveActiveThemeOptions} from './selectors'\nimport {readPersistedSnapshot} from './storage'\nimport {ThemerLayout} from './ThemerLayout'\n\n/**\n * Keep this component extremely lightweight, and only include state that are needed by both\n *  `studio.components.layout` and `studio.components.navbar`, where it's not possible to prop-drill into `studio.components.navbar`,\n * and that need to survive open/close of the tool\n * @TODO will mount on the future `studio.components.provider` entrypoint to ensure other plugins using `studio.components.layout` is correctly wrapped in the top-level theme regardless of plugin ordering\n */\nexport function ThemerProvider({\n  children,\n  config,\n}: {\n  children: React.ReactNode\n} & Pick<ThemerProps, 'config'>) {\n  use(browser('The current theme is stored in localStorage.'))\n\n  const [persistedSnapshot] = useState(readPersistedSnapshot)\n  const [state, dispatch] = useReducer(toolReducer, initialToolState, (initialState) => {\n    if (!persistedSnapshot) return initialState\n    const theme = resolveActiveThemeOptions(persistedSnapshot.context)\n    return theme ? {...initialState, theme} : initialState\n  })\n\n  const scheme = useColorSchemeValue()\n  const index = useMediaIndex()\n  const isMobile = index <= MIN_MEDIA_INDEX_FOR_SIDEBAR\n  const isTooSmallForSplitScreen = index <= MIN_MEDIA_INDEX_FOR_SPLIT_SCREEN\n\n  // @TODO Themer does not yet support mobile\n  const open = state.open && !isMobile\n  // Split screen needs some space\n  const split = state.split && !isTooSmallForSplitScreen\n\n  return (\n    <ThemeProvider theme={(state.theme !== null ? buildTheme(state.theme) : null) ?? undefined}>\n      <ThemerLayout\n        config={config}\n        backgroundColor={state.theme?.[scheme]?.background}\n        dispatch={dispatch}\n        navbarHeight={state.navbarHeight}\n        open={open}\n        persistedSnapshot={persistedSnapshot}\n        prerender={state.prerender}\n        prerenderSplitScreen={state.prerenderSplitScreen}\n        scheme={scheme}\n        split={split}\n      >\n        {children}\n      </ThemerLayout>\n    </ThemeProvider>\n  )\n}\n","import {definePlugin, type LayoutProps} from 'sanity'\n\nimport type {PluginConfig} from '#types'\n\nimport {ThemerNavbar} from './ThemerNavbar'\nimport {ThemerProvider} from './ThemerProvider'\n\n/**\n * Options for the {@link themerTool} plugin.\n *\n * This is experimental and may change or be removed in any release without\n * notice — use at your own risk.\n *\n * @alpha\n */\nexport interface ThemerToolOptions {\n  /**\n   * What the tool goes by in the Studio navbar — the toggle's label and\n   * tooltip. Defaults to `Themer`.\n   */\n  title?: string\n}\n\n/**\n * A Studio plugin that adds a themer sidebar for `buildTheme` themes: a\n * navbar toggle opens the sidebar next to the Studio, with a list of themes —\n * the configured theme, the presets and your own — each previewed as a tiny\n * Studio in both color schemes. Picking one applies it live to the whole\n * Studio while you browse around; your own themes can be edited with\n * accent/text/background pickers and a contrast slider per scheme, added,\n * duplicated, given the colors of an image (its palette is read on device),\n * removed and restored, and a dialog shows the `buildTheme` snippet that\n * makes the applied theme permanent. Toggle between light and dark mode with\n * the regular appearance menu — the preview follows it — or split the\n * preview to see the whole Studio in light and dark side by side.\n *\n * ```ts\n * import {themerTool} from '@sanity/themer/tool'\n * import {defineConfig} from 'sanity'\n *\n * export default defineConfig({\n *   plugins: [themerTool()],\n *   // ...rest of the config\n * })\n * ```\n *\n * This is experimental and may change or be removed in any release without\n * notice — use at your own risk.\n *\n * @alpha\n */\nexport const themerTool = definePlugin<ThemerToolOptions | void>((options) => {\n  const {title = 'Themer'} = options ?? {}\n  const ThemerLayoutProvider = defineThemerLayout({title})\n\n  return {\n    name: '@sanity/themer/tool',\n    studio: {\n      components: {layout: ThemerLayoutProvider, navbar: ThemerNavbar},\n    },\n  }\n})\n\n// This wrapper creates a clean closure that allows safely using the `'use memo'` directive\n// so that the dynamically created component can be memoized by react compiler\nfunction defineThemerLayout(config: PluginConfig) {\n  return function DefinedThemerLayoutProvider(props: LayoutProps) {\n    'use memo'\n\n    return <ThemerProvider config={config}>{props.renderDefault(props)}</ThemerProvider>\n  }\n}\n"],"mappings":"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"}
\ No newline at end of file