@sanity/themer 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tool.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tool.js","names":[],"sources":["../src/tool/context.ts","../src/tool/fields.ts","../src/tool/snippet.ts","../src/tool/ThemerSidebar.tsx","../src/tool/ThemerActiveToolLayout.tsx","../src/tool/storage.ts","../src/tool/ThemerLayout.tsx","../src/tool/ThemerNavbar.tsx","../src/tool/plugin.tsx"],"sourcesContent":["import {createContext, useContext} from 'react'\n\nimport {CreateThemeOptions} from '../types'\n\n/** @internal */\nexport interface ThemerContextValue {\n /** The colors the Studio's configured theme was generated from */\n baseColors: CreateThemeOptions\n /** The draft colors, or `null` when the configured theme is untouched */\n colors: CreateThemeOptions | null\n setColors: (colors: CreateThemeOptions | null) => void\n /** Whether the themer sidebar is open */\n open: boolean\n setOpen: (open: boolean) => void\n}\n\n/** @internal */\nexport const ThemerContext = createContext<ThemerContextValue | null>(null)\n\n/** @internal */\nexport function useThemer(): ThemerContextValue {\n const context = useContext(ThemerContext)\n\n if (!context) {\n throw new Error('useThemer must be used within the `themerTool` plugin')\n }\n\n return context\n}\n","import {color} from '@sanity/color'\n\nimport {CreateThemeOptions} from '../types'\n\n/** @internal */\nexport interface ThemerField {\n key: keyof CreateThemeOptions\n title: string\n description: string\n /** The color the picker shows while the field is unset (6-digit hex) */\n defaultValue: string\n}\n\n/** @internal */\nexport const THEMER_FIELDS: ThemerField[] = [\n {\n key: 'primary',\n title: 'Primary',\n description: 'Buttons, focus rings and links',\n defaultValue: color.blue[500].hex,\n },\n {\n key: 'gray',\n title: 'Gray',\n description: 'Neutral surfaces, borders and text',\n defaultValue: color.gray[500].hex,\n },\n {\n key: 'positive',\n title: 'Positive',\n description: 'Success accents',\n defaultValue: color.green[500].hex,\n },\n {\n key: 'caution',\n title: 'Caution',\n description: 'Warning accents',\n defaultValue: color.yellow[500].hex,\n },\n {\n key: 'critical',\n title: 'Critical',\n description: 'Errors and destructive actions',\n defaultValue: color.red[500].hex,\n },\n {\n key: 'lightest',\n title: 'Lightest',\n description: 'Light mode background',\n defaultValue: color.white.hex,\n },\n {\n key: 'darkest',\n title: 'Darkest',\n description: 'Dark mode background',\n defaultValue: color.black.hex,\n },\n]\n","import {CreateThemeOptions} from '../types'\nimport {THEMER_FIELDS} from './fields'\n\n/**\n * Serializes colors into the `createTheme` call to paste into\n * `sanity.config.ts`.\n *\n * @internal\n */\nexport function createThemeSnippet(colors: CreateThemeOptions): string {\n const entries = THEMER_FIELDS.filter(({key}) => colors[key]).map(\n ({key}) => ` ${key}: '${colors[key]}',`,\n )\n\n const call = entries.length === 0 ? 'createTheme()' : `createTheme({\\n${entries.join('\\n')}\\n})`\n\n return `import {createTheme} from '@sanity/themer'\\n\\nexport const theme = ${call}\\n`\n}\n","import {ClipboardIcon} from '@sanity/icons/Clipboard'\nimport {CloseIcon} from '@sanity/icons/Close'\nimport {ResetIcon} from '@sanity/icons/Reset'\nimport {Box, Button, Card, Code, Flex, Select, Stack, Text, useToast} from '@sanity/ui'\n\nimport {presets} from '../presets'\nimport {CreateThemeOptions} from '../types'\nimport {useThemer} from './context'\nimport {THEMER_FIELDS, ThemerField} from './fields'\nimport {createThemeSnippet} from './snippet'\n\nconst swatchStyle: React.CSSProperties = {\n width: 33,\n height: 33,\n padding: 0,\n border: '1px solid var(--card-border-color)',\n borderRadius: 6,\n background: 'transparent',\n cursor: 'pointer',\n flex: 'none',\n}\n\nfunction sameColors(a: CreateThemeOptions, b: CreateThemeOptions): boolean {\n return THEMER_FIELDS.every(\n ({key}) => (a[key]?.toLowerCase() ?? undefined) === (b[key]?.toLowerCase() ?? undefined),\n )\n}\n\n/** Expands `#abc` to `#aabbcc`, which is the only format `<input type=\"color\">` accepts */\nfunction expandHex(hex: string): string {\n if (hex.length === 4) {\n return `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}`\n }\n\n return hex\n}\n\n/**\n * The themer sidebar: a preset picker and a handful of color pickers that\n * generate the previewed theme, plus the `createTheme` snippet to make it\n * permanent.\n *\n * @internal\n */\nexport function ThemerSidebar() {\n const {baseColors, colors, setColors, setOpen} = useThemer()\n const toast = useToast()\n\n const active = colors ?? baseColors\n const activePresetSlug = presets.find((preset) => sameColors(preset.colors, active))?.slug ?? ''\n const snippet = createThemeSnippet(active)\n\n const handleFieldChange = (key: keyof CreateThemeOptions, value: string | undefined) => {\n const next = {...active}\n\n if (value === undefined) {\n delete next[key]\n } else {\n next[key] = value\n }\n\n setColors(next)\n }\n\n const handlePresetChange = (slug: string) => {\n const preset = presets.find((candidate) => candidate.slug === slug)\n\n if (preset) {\n setColors({...preset.colors})\n }\n }\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(snippet)\n toast.push({status: 'success', title: 'Copied theme to the clipboard'})\n } catch {\n toast.push({status: 'error', title: 'Could not copy the theme'})\n }\n }\n\n return (\n <Card height=\"fill\">\n <Flex direction=\"column\" height=\"fill\">\n <Card borderBottom padding={3}>\n <Flex align=\"center\" gap={2}>\n <Box flex={1} paddingLeft={1}>\n <Text size={1} weight=\"semibold\">\n Themer\n </Text>\n </Box>\n <Button\n icon={CloseIcon}\n mode=\"bleed\"\n onClick={() => setOpen(false)}\n padding={2}\n title=\"Close themer\"\n />\n </Flex>\n </Card>\n\n <Box flex={1} overflow=\"auto\" padding={4}>\n <Stack gap={5}>\n <Stack gap={3}>\n <Text size={1} weight=\"medium\">\n Preset\n </Text>\n <Select\n onChange={(event) => handlePresetChange(event.currentTarget.value)}\n value={activePresetSlug}\n >\n {activePresetSlug === '' && <option value=\"\">Custom</option>}\n {presets.map((preset) => (\n <option key={preset.slug} value={preset.slug}>\n {preset.title}\n </option>\n ))}\n </Select>\n </Stack>\n\n <Stack gap={4}>\n {THEMER_FIELDS.map((field) => (\n <ColorField\n field={field}\n key={field.key}\n onChange={handleFieldChange}\n value={active[field.key]}\n />\n ))}\n </Stack>\n\n <Stack gap={3}>\n <Text size={1} weight=\"medium\">\n Add to your config\n </Text>\n <Card border overflow=\"auto\" padding={3} radius={2} tone=\"transparent\">\n <Code language=\"ts\" size={0}>\n {snippet}\n </Code>\n </Card>\n <Flex gap={2}>\n <Button\n icon={ClipboardIcon}\n mode=\"ghost\"\n onClick={() => void handleCopy()}\n text=\"Copy\"\n />\n <Button\n disabled={colors === null}\n icon={ResetIcon}\n mode=\"ghost\"\n onClick={() => setColors(null)}\n text=\"Reset\"\n tone=\"critical\"\n />\n </Flex>\n </Stack>\n </Stack>\n </Box>\n </Flex>\n </Card>\n )\n}\n\nfunction ColorField(props: {\n field: ThemerField\n value: string | undefined\n onChange: (key: keyof CreateThemeOptions, value: string | undefined) => void\n}) {\n const {field, value, onChange} = props\n\n return (\n <Flex align=\"center\" gap={3}>\n <Stack flex={1} gap={2}>\n <Text size={1} weight=\"medium\">\n {field.title}\n </Text>\n <Text muted size={0}>\n {value ?? field.description}\n </Text>\n </Stack>\n {value !== undefined && (\n <Button\n icon={CloseIcon}\n mode=\"bleed\"\n onClick={() => onChange(field.key, undefined)}\n padding={2}\n title={`Reset ${field.title}`}\n />\n )}\n <input\n aria-label={`${field.title} color`}\n onChange={(event) => onChange(field.key, event.currentTarget.value)}\n style={swatchStyle}\n type=\"color\"\n value={expandHex(value ?? field.defaultValue)}\n />\n </Flex>\n )\n}\n","import {Box, Flex, Layer} from '@sanity/ui'\nimport {type ActiveToolLayoutProps} from 'sanity'\n\nimport {useThemer} from './context'\nimport {ThemerSidebar} from './ThemerSidebar'\n\nconst sidebarStyle: React.CSSProperties = {\n width: 360,\n flex: 'none',\n borderLeft: '1px solid var(--card-border-color)',\n boxSizing: 'border-box',\n overflow: 'hidden',\n}\n\n/**\n * Renders the themer sidebar next to the active tool, so the user can browse\n * around their own studio while tweaking the theme.\n *\n * @internal\n */\nexport function ThemerActiveToolLayout(props: ActiveToolLayoutProps) {\n const {open} = useThemer()\n\n return (\n <Flex height=\"fill\" sizing=\"border\">\n <Box flex={1} height=\"fill\" overflow=\"auto\">\n {props.renderDefault(props)}\n </Box>\n\n {open && (\n <Layer height=\"fill\" style={sidebarStyle} zOffset={100}>\n <ThemerSidebar />\n </Layer>\n )}\n </Flex>\n )\n}\n","import {isColor} from '../lib/mix'\nimport {CreateThemeOptions} from '../types'\nimport {THEMER_FIELDS} from './fields'\n\nconst STORAGE_KEY = 'sanityStudio:themer:colors'\n\n/**\n * Restores draft colors from localStorage, so theme drafts survive studio\n * reloads.\n *\n * @internal\n */\nexport function readStoredColors(): CreateThemeOptions | null {\n try {\n if (typeof localStorage === 'undefined') return null\n\n const raw = localStorage.getItem(STORAGE_KEY)\n\n if (!raw) return null\n\n const parsed: unknown = JSON.parse(raw)\n\n if (!parsed || typeof parsed !== 'object') return null\n\n const colors: CreateThemeOptions = {}\n\n for (const {key} of THEMER_FIELDS) {\n const value: unknown = Reflect.get(parsed, key)\n\n if (typeof value === 'string' && isColor(value)) {\n colors[key] = value\n }\n }\n\n return colors\n } catch {\n return null\n }\n}\n\n/** @internal */\nexport function writeStoredColors(colors: CreateThemeOptions | null): void {\n try {\n if (typeof localStorage === 'undefined') return\n\n if (colors === null) {\n localStorage.removeItem(STORAGE_KEY)\n } else {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(colors))\n }\n } catch {\n // Storage can be unavailable (e.g. private browsing) — drafts just won't persist\n }\n}\n","import {ThemeProvider} from '@sanity/ui'\nimport {useEffect, useMemo, useState} from 'react'\nimport {type LayoutProps} from 'sanity'\n\nimport {createTheme} from '../createTheme'\nimport {CreateThemeOptions} from '../types'\nimport {ThemerContext, ThemerContextValue} from './context'\nimport {readStoredColors, writeStoredColors} from './storage'\n\n/**\n * Wraps the whole Studio so that draft themes generated by the themer sidebar\n * apply everywhere while the user browses around, and hosts the state that the\n * navbar toggle and the sidebar share.\n *\n * The draft theme provider inherits the color scheme from the Studio, so the\n * preview follows the appearance setting (light/dark/system) like any other\n * theme.\n *\n * @internal\n */\nexport function ThemerLayout(props: LayoutProps & {baseColors: CreateThemeOptions}) {\n const {baseColors, ...layoutProps} = props\n const [open, setOpen] = useState(false)\n const [colors, setColors] = useState<CreateThemeOptions | null>(readStoredColors)\n\n useEffect(() => writeStoredColors(colors), [colors])\n\n // The theme identity must be stable between renders: it feeds the\n // styled-components theme context for the whole Studio, and rebuilding it\n // would re-render everything\n const theme = useMemo(\n () => (colors === null ? null : createTheme({...baseColors, ...colors})),\n [baseColors, colors],\n )\n\n const context = useMemo<ThemerContextValue>(\n () => ({baseColors, colors, setColors, open, setOpen}),\n [baseColors, colors, open],\n )\n\n return (\n <ThemerContext.Provider value={context}>\n {theme === null ? (\n layoutProps.renderDefault(layoutProps)\n ) : (\n <ThemeProvider theme={theme}>{layoutProps.renderDefault(layoutProps)}</ThemeProvider>\n )}\n </ThemerContext.Provider>\n )\n}\n","import {ColorWheelIcon} from '@sanity/icons/ColorWheel'\nimport {type NavbarProps} from 'sanity'\n\nimport {useThemer} from './context'\n\n/**\n * Adds the toggle that opens and closes the themer sidebar to the Studio\n * navbar.\n *\n * @internal\n */\nexport function ThemerNavbar(props: NavbarProps) {\n const {open, setOpen} = useThemer()\n\n return props.renderDefault({\n ...props,\n __internal_actions: [\n ...(props.__internal_actions ?? []),\n {\n icon: ColorWheelIcon,\n location: 'topbar',\n name: 'themer',\n onAction: () => setOpen(!open),\n selected: open,\n title: 'Themer',\n },\n ],\n })\n}\n","import {definePlugin, type LayoutProps} from 'sanity'\n\nimport {CreateThemeOptions} from '../types'\nimport {ThemerActiveToolLayout} from './ThemerActiveToolLayout'\nimport {ThemerLayout} from './ThemerLayout'\nimport {ThemerNavbar} from './ThemerNavbar'\n\n/**\n * Options for the {@link themerTool} plugin.\n *\n * @public\n */\nexport interface ThemerToolOptions {\n /**\n * The colors that the Studio's configured theme was generated from — the\n * themer starts editing from these, so pass the same object that the\n * `theme` in the Studio config uses:\n *\n * ```ts\n * const colors = {primary: '#2276fc'}\n *\n * export default defineConfig({\n * theme: createTheme(colors),\n * plugins: [themerTool({colors})],\n * })\n * ```\n */\n colors?: CreateThemeOptions\n}\n\n/**\n * A Studio plugin that adds a themer sidebar for generating Studio themes:\n * a navbar toggle opens the sidebar next to the active tool, where presets\n * and color pickers preview a `createTheme` theme live on the whole Studio\n * while you browse around. Toggle between light and dark mode with the\n * regular appearance menu — the preview follows it.\n *\n * ```ts\n * import {themerTool} from '@sanity/themer/tool'\n * import {defineConfig} from 'sanity'\n *\n * export default defineConfig({\n * plugins: [themerTool()],\n * // ...rest of the config\n * })\n * ```\n *\n * @public\n */\nexport const themerTool = definePlugin<ThemerToolOptions | void>((options) => {\n const baseColors: CreateThemeOptions = options?.colors ?? {}\n\n function ThemerLayoutWithOptions(props: LayoutProps) {\n return <ThemerLayout {...props} baseColors={baseColors} />\n }\n\n return {\n name: '@sanity/themer/tool',\n studio: {\n components: {\n layout: ThemerLayoutWithOptions,\n navbar: ThemerNavbar,\n activeToolLayout: ThemerActiveToolLayout,\n },\n },\n }\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"tool.js","names":["createContext","useContext","Hues","ThemerContextValue","baseHues","hues","setHues","open","setOpen","ThemerContext","useThemer","context","Error","Hue","HueMidPoint","Hues","HUE_KEYS","const","ReadonlyArray","HueKey","HueField","key","title","description","HUE_FIELDS","MID_POINTS","HUE_PROPERTIES","sameHues","a","b","every","property","left","right","toLowerCase","hues","defaultHues","Hue","Hues","PartialHues","HUE_KEYS","diffHues","diff","key","hue","base","patch","Partial","mid","toLowerCase","impliedMidPoint","undefined","midPoint","lightest","darkest","Object","keys","length","Hue","Hues","diffHues","HUE_KEYS","serializeHue","hue","Partial","parts","mid","undefined","push","midPoint","lightest","darkest","join","createThemeSnippet","hues","diff","entries","key","patch","length","COLOR_TINTS","ColorTints","ChevronDownIcon","ChevronRightIcon","ClipboardIcon","CloseIcon","ResetIcon","Box","Button","Card","Code","Flex","Grid","Select","Stack","Text","TextInput","useToast","useMemo","useState","registerLanguage","typescript","styled","parseHuesFromUrl","createTonesFromHues","presets","Hue","ThemePreset","useThemer","HUE_FIELDS","HUE_KEYS","HueField","HueKey","MID_POINTS","sameHues","createThemeSnippet","TOOL_PRESETS","preset","slug","push","title","Swatch","input","expandHex","hex","length","normalizeImportUrl","trimmed","trim","startsWith","ThemerSidebar","$","_c","baseHues","hues","setHues","setOpen","toast","expandedHue","setExpandedHue","importUrl","setImportUrl","active","t0","tones","t1","find","activePresetSlug","t2","snippet","t3","key","patch","handleHueChange","t4","preset_0","candidate","handlePresetChange","t5","status","t6","error","description","Error","message","String","handleImport","navigator","clipboard","writeText","handleCopy","t7","Symbol","for","t8","t9","t10","map","preset_1","t11","t12","t13","event","preventDefault","t14","event_0","currentTarget","value","t15","t16","t17","t18","t19","t20","field","t21","t22","t23","t24","t25","t26","t27","t28","t29","t30","t31","paletteStyle","React","CSSProperties","display","gap","background","height","borderRadius","overflow","boxShadow","PresetButton","props","onClick","flex","mid","rampStyle","HueSection","expanded","hue","onChange","onToggle","tints","undefined","width","tint","Number","midPoint","_temp","lightest","darkest","midPoint_0","ColorRow","Box","Flex","Layer","ActiveToolLayoutProps","useThemer","ThemerSidebar","sidebarStyle","React","CSSProperties","width","flex","borderLeft","boxSizing","overflow","ThemerActiveToolLayout","props","$","_c","open","t0","renderDefault","t1","t2","t3","Hue","HueMidPoint","Hues","isColor","HUE_KEYS","MID_POINTS","STORAGE_KEY","sanitizeHue","value","mid","Reflect","get","midPoint","lightest","darkest","includes","toLowerCase","readStoredHues","localStorage","raw","getItem","parsed","JSON","parse","hues","Partial","key","hue","writeStoredHues","removeItem","setItem","stringify","ThemeProvider","useEffect","useMemo","useState","LayoutProps","createTheme","Hues","ThemerContext","ThemerContextValue","readStoredHues","writeStoredHues","ThemerLayout","props","$","_c","baseHues","layoutProps","open","setOpen","hues","setHues","t0","t1","t2","theme","t3","context","t4","t5","renderDefault","t6","Provider","ColorWheelIcon","Button","Text","Tooltip","NavbarProps","useThemer","ThemerNavbarButton","$","_c","open","setOpen","t0","Symbol","for","t1","t2","ThemerNavbar","props","renderDefault","__internal_actions","location","name","render","_temp","icon","onAction","selected","title","definePlugin","LayoutProps","applyHues","PartialHues","ThemerActiveToolLayout","ThemerLayout","ThemerNavbar","ThemerToolOptions","hues","themerTool","options","baseHues","ThemerLayoutWithOptions","props","$","_c","t0","name","studio","components","layout","navbar","activeToolLayout"],"sources":["../src/tool/context.ts","../src/tool/hues.ts","../src/tool/diffHues.ts","../src/tool/snippet.ts","../src/tool/ThemerSidebar.tsx","../src/tool/ThemerActiveToolLayout.tsx","../src/tool/storage.ts","../src/tool/ThemerLayout.tsx","../src/tool/ThemerNavbar.tsx","../src/tool/plugin.tsx"],"sourcesContent":["import {createContext, useContext} from 'react'\n\nimport {Hues} from '../legacy/types'\n\n/** @internal */\nexport interface ThemerContextValue {\n /** The hues the Studio's configured theme was generated from */\n baseHues: Hues\n /** The draft hues, or `null` when the configured theme is untouched */\n hues: Hues | null\n setHues: (hues: Hues | null) => void\n /** Whether the themer sidebar is open */\n open: boolean\n setOpen: (open: boolean) => void\n}\n\n/** @internal */\nexport const ThemerContext = createContext<ThemerContextValue | null>(null)\n\n/** @internal */\nexport function useThemer(): ThemerContextValue {\n const context = useContext(ThemerContext)\n\n if (!context) {\n throw new Error('useThemer must be used within the `themerTool` plugin')\n }\n\n return context\n}\n","import {Hue, HueMidPoint, Hues} from '../legacy/types'\n\n/**\n * The six hues in the order the hosted Themer service listed them, used for\n * the sidebar's editors and the generated snippet alike.\n *\n * @internal\n */\nexport const HUE_KEYS = [\n 'default',\n 'primary',\n 'transparent',\n 'positive',\n 'caution',\n 'critical',\n] as const satisfies ReadonlyArray<keyof Hues>\n\n/** @internal */\nexport type HueKey = (typeof HUE_KEYS)[number]\n\n/** @internal */\nexport interface HueField {\n key: HueKey\n title: string\n description: string\n}\n\n/**\n * The editor sections of the sidebar, one per hue.\n *\n * @internal\n */\nexport const HUE_FIELDS: HueField[] = [\n {key: 'default', title: 'Default', description: 'Text, icons and most surfaces'},\n {key: 'primary', title: 'Primary', description: 'Focus rings, links and primary buttons'},\n {key: 'transparent', title: 'Transparent', description: 'The backdrop behind panes'},\n {key: 'positive', title: 'Positive', description: 'Success badges and prompts'},\n {key: 'caution', title: 'Caution', description: 'Warnings and draft indicators'},\n {key: 'critical', title: 'Critical', description: 'Errors and destructive actions'},\n]\n\n/**\n * The tints a hue's `mid` color can sit at, matching the hosted Themer\n * service's mid point options.\n *\n * @internal\n */\nexport const MID_POINTS: readonly HueMidPoint[] = [\n 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950,\n]\n\n/** The properties of a `Hue`, in serialization order */\nconst HUE_PROPERTIES = ['mid', 'midPoint', 'lightest', 'darkest'] as const satisfies ReadonlyArray<\n keyof Hue\n>\n\n/** @internal */\nexport function sameHues(a: Hues, b: Hues): boolean {\n return HUE_KEYS.every((key) =>\n HUE_PROPERTIES.every((property) => {\n const left = a[key][property]\n const right = b[key][property]\n\n return typeof left === 'string' && typeof right === 'string'\n ? left.toLowerCase() === right.toLowerCase()\n : left === right\n }),\n )\n}\n","import {hues as defaultHues} from '../legacy/defaults'\nimport {Hue, Hues, PartialHues} from '../legacy/types'\nimport {HUE_KEYS} from './hues'\n\n/**\n * Reduces resolved hues to the minimal `PartialHues` that recreates them\n * through the legacy `createTheme`. The subtlety is `applyHues`' quirk of\n * resetting a customized `mid`'s mid point to 500: whenever `mid` is included,\n * the baseline for `midPoint` is 500 rather than the hue's default.\n *\n * @internal\n */\nexport function diffHues(hues: Hues): PartialHues {\n const diff: PartialHues = {}\n\n for (const key of HUE_KEYS) {\n const hue = hues[key]\n const base = defaultHues[key]\n const patch: Partial<Hue> = {}\n\n if (hue.mid.toLowerCase() !== base.mid) {\n patch.mid = hue.mid.toLowerCase()\n }\n\n const impliedMidPoint = patch.mid === undefined ? base.midPoint : 500\n\n if (hue.midPoint !== impliedMidPoint) {\n patch.midPoint = hue.midPoint\n }\n\n if (hue.lightest.toLowerCase() !== base.lightest) {\n patch.lightest = hue.lightest.toLowerCase()\n }\n\n if (hue.darkest.toLowerCase() !== base.darkest) {\n patch.darkest = hue.darkest.toLowerCase()\n }\n\n if (Object.keys(patch).length > 0) {\n diff[key] = patch\n }\n }\n\n return diff\n}\n","import {Hue, Hues} from '../legacy/types'\nimport {diffHues} from './diffHues'\nimport {HUE_KEYS} from './hues'\n\nfunction serializeHue(hue: Partial<Hue>): string {\n const parts: string[] = []\n\n if (hue.mid !== undefined) parts.push(`mid: '${hue.mid}'`)\n if (hue.midPoint !== undefined) parts.push(`midPoint: ${hue.midPoint}`)\n if (hue.lightest !== undefined) parts.push(`lightest: '${hue.lightest}'`)\n if (hue.darkest !== undefined) parts.push(`darkest: '${hue.darkest}'`)\n\n return `{${parts.join(', ')}}`\n}\n\n/**\n * Serializes hues into the `createTheme` call to paste into\n * `sanity.config.ts`, keeping only what differs from the default hues.\n *\n * Hues that match the defaults entirely are the stock Studio theme, which\n * needs nothing from this package — so they serialize to a bare `buildTheme()`\n * instead.\n *\n * @internal\n */\nexport function createThemeSnippet(hues: Hues): string {\n const diff = diffHues(hues)\n const entries: string[] = []\n\n for (const key of HUE_KEYS) {\n const patch = diff[key]\n\n if (patch) {\n entries.push(` ${key}: ${serializeHue(patch)},`)\n }\n }\n\n if (entries.length === 0) {\n return \"import {buildTheme} from '@sanity/ui/theme'\\n\\nexport const theme = buildTheme()\\n\"\n }\n\n return `import {createTheme} from '@sanity/themer/legacy'\\n\\nexport const theme = createTheme({\\n${entries.join('\\n')}\\n})\\n`\n}\n","import {COLOR_TINTS, ColorTints} from '@sanity/color'\nimport {ChevronDownIcon} from '@sanity/icons/ChevronDown'\nimport {ChevronRightIcon} from '@sanity/icons/ChevronRight'\nimport {ClipboardIcon} from '@sanity/icons/Clipboard'\nimport {CloseIcon} from '@sanity/icons/Close'\nimport {ResetIcon} from '@sanity/icons/Reset'\nimport {\n Box,\n Button,\n Card,\n Code,\n Flex,\n Grid,\n Select,\n Stack,\n Text,\n TextInput,\n useToast,\n} from '@sanity/ui'\nimport {useMemo, useState} from 'react'\nimport {registerLanguage} from 'react-refractor'\nimport typescript from 'refractor/typescript'\nimport {styled} from 'styled-components'\n\nimport {parseHuesFromUrl} from '../legacy/createTheme'\nimport {createTonesFromHues} from '../legacy/createTonesFromHues'\nimport {presets} from '../legacy/presets'\nimport {Hue, ThemePreset} from '../legacy/types'\nimport {useThemer} from './context'\nimport {HUE_FIELDS, HUE_KEYS, HueField, HueKey, MID_POINTS, sameHues} from './hues'\nimport {createThemeSnippet} from './snippet'\n\n// `Code` only highlights languages the surrounding app has registered with\n// react-refractor, and the Studio registers its own set from an async import\n// during startup — a race this sidebar keeps losing. Registering the one\n// language the snippet needs keeps it highlighted from the first render.\nregisterLanguage(typescript)\n\n/**\n * The tool's take on the hosted service's presets: Tailwind Cyan is hidden and\n * the default \"Studio v3\" preset reads just \"Studio\". The legacy `presets`\n * export itself keeps both untouched, for parity with\n * `https://themer.sanity.build/api/hues`.\n */\nconst TOOL_PRESETS: ThemePreset[] = []\n\nfor (const preset of presets) {\n if (preset.slug === 'tw-cyan') continue\n\n TOOL_PRESETS.push(preset.slug === 'default' ? {...preset, title: 'Studio'} : preset)\n}\n\n/**\n * `<input type=\"color\">` paints the color into a shadow-DOM swatch that brings\n * its own border and padding, which then sits inside ours as a second border.\n * Stripping that chrome leaves the themed border as the only one.\n */\nconst Swatch = styled.input`\n box-sizing: border-box;\n flex: none;\n width: 33px;\n height: 33px;\n padding: 0;\n border: 1px solid var(--card-border-color);\n border-radius: 4px;\n background: none;\n cursor: pointer;\n\n &::-webkit-color-swatch-wrapper {\n padding: 0;\n }\n\n &::-webkit-color-swatch {\n border: none;\n border-radius: 3px;\n }\n\n &::-moz-color-swatch {\n border: none;\n border-radius: 3px;\n }\n`\n\n/** Expands `#abc` to `#aabbcc`, which is the only format `<input type=\"color\">` accepts */\nfunction expandHex(hex: string): string {\n if (hex.length === 4) {\n return `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}`\n }\n\n return hex\n}\n\n/** Prefixes bare query strings so `parseHuesFromUrl` accepts them too */\nfunction normalizeImportUrl(input: string): string {\n const trimmed = input.trim()\n\n return trimmed.startsWith('http') || trimmed.startsWith('?') ? trimmed : `?${trimmed}`\n}\n\n/**\n * The themer sidebar: presets, a themer.sanity.build URL importer and the\n * per-hue editors of the hosted Themer service — mid color, mid point,\n * lightest and darkest — that generate the previewed legacy theme, plus the\n * `createTheme` snippet to make it permanent.\n *\n * @internal\n */\nexport function ThemerSidebar() {\n const {baseHues, hues, setHues, setOpen} = useThemer()\n const toast = useToast()\n const [expandedHue, setExpandedHue] = useState<HueKey | null>(null)\n const [importUrl, setImportUrl] = useState('')\n\n const active = hues ?? baseHues\n const tones = useMemo(() => createTonesFromHues(active), [active])\n const activePresetSlug = TOOL_PRESETS.find((preset) => sameHues(preset.hues, active))?.slug ?? ''\n const snippet = createThemeSnippet(active)\n\n const handleHueChange = (key: HueKey, patch: Partial<Hue>) => {\n setHues({...active, [key]: {...active[key], ...patch}})\n }\n\n const handlePresetChange = (slug: string) => {\n const preset = TOOL_PRESETS.find((candidate) => candidate.slug === slug)\n\n if (preset) {\n setHues(preset.hues)\n }\n }\n\n const handleImport = () => {\n if (!importUrl.trim()) return\n\n try {\n setHues(parseHuesFromUrl(normalizeImportUrl(importUrl)))\n setImportUrl('')\n toast.push({status: 'success', title: 'Imported theme from URL'})\n } catch (error) {\n toast.push({\n status: 'error',\n title: 'Could not import the URL',\n description: error instanceof Error ? error.message : String(error),\n })\n }\n }\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(snippet)\n toast.push({status: 'success', title: 'Copied theme to the clipboard'})\n } catch {\n toast.push({status: 'error', title: 'Could not copy the theme'})\n }\n }\n\n return (\n <Card height=\"fill\">\n <Flex direction=\"column\" height=\"fill\">\n <Card borderBottom padding={3}>\n <Flex align=\"center\" gap={2}>\n <Box flex={1} paddingLeft={1}>\n <Text size={1} weight=\"semibold\">\n Themer\n </Text>\n </Box>\n <Button\n icon={CloseIcon}\n mode=\"bleed\"\n onClick={() => setOpen(false)}\n padding={2}\n title=\"Close themer\"\n />\n </Flex>\n </Card>\n\n <Box flex={1} overflow=\"auto\" padding={3}>\n <Stack gap={4}>\n <Stack gap={3}>\n <Text size={1} weight=\"medium\">\n Presets\n </Text>\n <Grid gap={2} gridTemplateColumns={2}>\n {TOOL_PRESETS.map((preset) => (\n <PresetButton\n active={preset.slug === activePresetSlug}\n key={preset.slug}\n onClick={handlePresetChange}\n preset={preset}\n />\n ))}\n </Grid>\n </Stack>\n\n <Stack gap={3}>\n <Text size={1} weight=\"medium\">\n Import\n </Text>\n <form\n onSubmit={(event) => {\n event.preventDefault()\n handleImport()\n }}\n >\n <Flex gap={2}>\n <Box flex={1}>\n <TextInput\n aria-label=\"Hosted Themer URL\"\n fontSize={1}\n onChange={(event) => setImportUrl(event.currentTarget.value)}\n padding={2}\n placeholder=\"themer.sanity.build URL\"\n value={importUrl}\n />\n </Box>\n <Button mode=\"ghost\" padding={2} text=\"Import\" type=\"submit\" />\n </Flex>\n </form>\n </Stack>\n\n <Stack gap={3}>\n <Text size={1} weight=\"medium\">\n Hues\n </Text>\n <Stack gap={1}>\n {HUE_FIELDS.map((field) => (\n <HueSection\n expanded={expandedHue === field.key}\n field={field}\n hue={active[field.key]}\n key={field.key}\n onChange={handleHueChange}\n onToggle={() => setExpandedHue(expandedHue === field.key ? null : field.key)}\n tints={tones[field.key]}\n />\n ))}\n </Stack>\n </Stack>\n\n <Stack gap={3}>\n <Text size={1} weight=\"medium\">\n Add to your config\n </Text>\n <Card border overflow=\"auto\" padding={2} radius={2} tone=\"transparent\">\n <Code language=\"ts\" size={0}>\n {snippet}\n </Code>\n </Card>\n <Flex gap={2}>\n <Button\n icon={ClipboardIcon}\n mode=\"ghost\"\n onClick={() => void handleCopy()}\n text=\"Copy\"\n />\n <Button\n disabled={hues === null}\n icon={ResetIcon}\n mode=\"ghost\"\n onClick={() => setHues(null)}\n text=\"Reset\"\n tone=\"critical\"\n />\n </Flex>\n </Stack>\n </Stack>\n </Box>\n </Flex>\n </Card>\n )\n}\n\nconst paletteStyle: React.CSSProperties = {\n display: 'flex',\n // The gaps let the border color through, so a near-white light background\n // still reads as a swatch rather than a hole in the palette\n gap: 1,\n background: 'var(--card-border-color)',\n height: 21,\n borderRadius: 3,\n overflow: 'hidden',\n boxShadow: 'inset 0 0 0 1px var(--card-border-color)',\n}\n\n/** A little color palette of the hue mid colors a preset would apply */\nfunction PresetButton(props: {\n active: boolean\n onClick: (slug: string) => void\n preset: ThemePreset\n}) {\n const {active, onClick, preset} = props\n\n return (\n <Button\n mode=\"ghost\"\n onClick={() => onClick(preset.slug)}\n padding={2}\n selected={active}\n title={preset.title}\n >\n <Stack as=\"span\" gap={2}>\n <span style={paletteStyle}>\n {HUE_KEYS.map((key) => (\n <span key={key} style={{flex: 1, background: preset.hues[key].mid}} />\n ))}\n </span>\n <Text align=\"left\" size={1} textOverflow=\"ellipsis\">\n {preset.title}\n </Text>\n </Stack>\n </Button>\n )\n}\n\nconst rampStyle: React.CSSProperties = {\n ...paletteStyle,\n height: 13,\n borderRadius: 2,\n}\n\n/** One hue of the theme: a collapsible header with the generated tint ramp */\nfunction HueSection(props: {\n expanded: boolean\n field: HueField\n hue: Hue\n onChange: (key: HueKey, patch: Partial<Hue>) => void\n onToggle: () => void\n /** The hue's generated 50–950 tint ramp, for the header preview */\n tints: ColorTints\n}) {\n const {expanded, field, hue, onChange, onToggle, tints} = props\n\n return (\n <Card border={expanded} radius={2} tone={expanded ? 'transparent' : undefined}>\n <Stack gap={expanded ? 3 : 0} paddingBottom={expanded ? 3 : 0}>\n <Button\n aria-expanded={expanded}\n mode=\"bleed\"\n onClick={onToggle}\n padding={2}\n title={field.description}\n >\n <Flex align=\"center\" as=\"span\" gap={2}>\n <Text size={1}>{expanded ? <ChevronDownIcon /> : <ChevronRightIcon />}</Text>\n <Box as=\"span\" style={{width: 76}}>\n <Text size={1} textOverflow=\"ellipsis\" weight=\"medium\">\n {field.title}\n </Text>\n </Box>\n <span style={{...rampStyle, flex: 1}}>\n {COLOR_TINTS.map((tint) => (\n <span key={tint} style={{flex: 1, background: tints[tint].hex}} />\n ))}\n </span>\n </Flex>\n </Button>\n\n {expanded && (\n <Stack gap={3} paddingX={3}>\n <Text muted size={0}>\n {field.description}\n </Text>\n <ColorRow onChange={(mid) => onChange(field.key, {mid})} title=\"Mid\" value={hue.mid} />\n <Flex align=\"center\" gap={2}>\n <Stack flex={1} gap={2}>\n <Text size={1}>Mid point</Text>\n <Text muted size={0}>\n The tint the mid color sits at\n </Text>\n </Stack>\n <Select\n aria-label={`${field.title} mid point`}\n fontSize={1}\n onChange={(event) => {\n const value = Number(event.currentTarget.value)\n const midPoint = MID_POINTS.find((candidate) => candidate === value)\n\n if (midPoint !== undefined) {\n onChange(field.key, {midPoint})\n }\n }}\n padding={2}\n value={hue.midPoint}\n >\n {MID_POINTS.map((midPoint) => (\n <option key={midPoint} value={midPoint}>\n {midPoint}\n </option>\n ))}\n </Select>\n </Flex>\n <ColorRow\n onChange={(lightest) => onChange(field.key, {lightest})}\n title=\"Lightest\"\n value={hue.lightest}\n />\n <ColorRow\n onChange={(darkest) => onChange(field.key, {darkest})}\n title=\"Darkest\"\n value={hue.darkest}\n />\n </Stack>\n )}\n </Stack>\n </Card>\n )\n}\n\nfunction ColorRow(props: {onChange: (value: string) => void; title: string; value: string}) {\n const {onChange, title, value} = props\n\n return (\n <Flex align=\"center\" gap={2}>\n <Stack flex={1} gap={2}>\n <Text size={1}>{title}</Text>\n <Text muted size={0}>\n {value}\n </Text>\n </Stack>\n <Swatch\n aria-label={`${title} color`}\n onChange={(event) => onChange(event.currentTarget.value)}\n type=\"color\"\n value={expandHex(value)}\n />\n </Flex>\n )\n}\n","import {Box, Flex, Layer} from '@sanity/ui'\nimport {type ActiveToolLayoutProps} from 'sanity'\n\nimport {useThemer} from './context'\nimport {ThemerSidebar} from './ThemerSidebar'\n\n/**\n * Narrow enough to leave the studio preview as much room as possible: it fits\n * the widest picker label next to its swatch, and the code snippet scrolls\n * horizontally rather than widening the sidebar.\n */\nconst sidebarStyle: React.CSSProperties = {\n width: 240,\n flex: 'none',\n borderLeft: '1px solid var(--card-border-color)',\n boxSizing: 'border-box',\n overflow: 'hidden',\n}\n\n/**\n * Renders the themer sidebar next to the active tool, so the user can browse\n * around their own studio while tweaking the theme.\n *\n * @internal\n */\nexport function ThemerActiveToolLayout(props: ActiveToolLayoutProps) {\n const {open} = useThemer()\n\n return (\n <Flex height=\"fill\" sizing=\"border\">\n <Box flex={1} height=\"fill\" overflow=\"auto\">\n {props.renderDefault(props)}\n </Box>\n\n {open && (\n <Layer height=\"fill\" style={sidebarStyle} zOffset={100}>\n <ThemerSidebar />\n </Layer>\n )}\n </Flex>\n )\n}\n","import {Hue, HueMidPoint, Hues} from '../legacy/types'\nimport {isColor} from '../lib/mix'\nimport {HUE_KEYS, MID_POINTS} from './hues'\n\nconst STORAGE_KEY = 'sanityStudio:themer:hues'\n\nfunction sanitizeHue(value: unknown): Hue | null {\n if (!value || typeof value !== 'object') return null\n\n const mid: unknown = Reflect.get(value, 'mid')\n const midPoint: unknown = Reflect.get(value, 'midPoint')\n const lightest: unknown = Reflect.get(value, 'lightest')\n const darkest: unknown = Reflect.get(value, 'darkest')\n\n if (typeof mid !== 'string' || !isColor(mid)) return null\n if (typeof lightest !== 'string' || !isColor(lightest)) return null\n if (typeof darkest !== 'string' || !isColor(darkest)) return null\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- narrowed by the includes check\n if (typeof midPoint !== 'number' || !MID_POINTS.includes(midPoint as HueMidPoint)) return null\n\n return {\n mid: mid.toLowerCase(),\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- narrowed by the includes check\n midPoint: midPoint as HueMidPoint,\n lightest: lightest.toLowerCase(),\n darkest: darkest.toLowerCase(),\n }\n}\n\n/**\n * Restores draft hues from localStorage, so theme drafts survive studio\n * reloads.\n *\n * @internal\n */\nexport function readStoredHues(): Hues | null {\n try {\n if (typeof localStorage === 'undefined') return null\n\n const raw = localStorage.getItem(STORAGE_KEY)\n\n if (!raw) return null\n\n const parsed: unknown = JSON.parse(raw)\n\n if (!parsed || typeof parsed !== 'object') return null\n\n const hues: Partial<Hues> = {}\n\n for (const key of HUE_KEYS) {\n const hue = sanitizeHue(Reflect.get(parsed, key))\n\n if (!hue) return null\n\n hues[key] = hue\n }\n\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- the loop assigns every HUE_KEYS key or returns\n return hues as Hues\n } catch {\n return null\n }\n}\n\n/** @internal */\nexport function writeStoredHues(hues: Hues | null): void {\n try {\n if (typeof localStorage === 'undefined') return\n\n if (hues === null) {\n localStorage.removeItem(STORAGE_KEY)\n } else {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(hues))\n }\n } catch {\n // Storage can be unavailable (e.g. private browsing) — drafts just won't persist\n }\n}\n","import {ThemeProvider} from '@sanity/ui'\nimport {useEffect, useMemo, useState} from 'react'\nimport {type LayoutProps} from 'sanity'\n\nimport {createTheme} from '../legacy/createTheme'\nimport {Hues} from '../legacy/types'\nimport {ThemerContext, ThemerContextValue} from './context'\nimport {readStoredHues, writeStoredHues} from './storage'\n\n/**\n * Wraps the whole Studio so that draft themes generated by the themer sidebar\n * apply everywhere while the user browses around, and hosts the state that the\n * navbar toggle and the sidebar share.\n *\n * The draft theme provider inherits the color scheme from the Studio, so the\n * preview follows the appearance setting (light/dark/system) like any other\n * theme.\n *\n * @internal\n */\nexport function ThemerLayout(props: LayoutProps & {baseHues: Hues}) {\n const {baseHues, ...layoutProps} = props\n const [open, setOpen] = useState(false)\n const [hues, setHues] = useState<Hues | null>(readStoredHues)\n\n useEffect(() => writeStoredHues(hues), [hues])\n\n // The theme identity must be stable between renders: it feeds the\n // styled-components theme context for the whole Studio, and rebuilding it\n // would re-render everything\n const theme = useMemo(() => (hues === null ? null : createTheme(hues)), [hues])\n\n const context = useMemo<ThemerContextValue>(\n () => ({baseHues, hues, setHues, open, setOpen}),\n [baseHues, hues, open],\n )\n\n return (\n <ThemerContext.Provider value={context}>\n {theme === null ? (\n layoutProps.renderDefault(layoutProps)\n ) : (\n <ThemeProvider theme={theme}>{layoutProps.renderDefault(layoutProps)}</ThemeProvider>\n )}\n </ThemerContext.Provider>\n )\n}\n","import {ColorWheelIcon} from '@sanity/icons/ColorWheel'\nimport {Button, Text, Tooltip} from '@sanity/ui'\nimport {type NavbarProps} from 'sanity'\n\nimport {useThemer} from './context'\n\nfunction ThemerNavbarButton() {\n const {open, setOpen} = useThemer()\n\n return (\n <Tooltip content={<Text size={1}>Themer</Text>} portal>\n <Button\n aria-label=\"Themer\"\n icon={ColorWheelIcon}\n mode=\"bleed\"\n onClick={() => setOpen(!open)}\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}\n />\n </Tooltip>\n )\n}\n\n/**\n * Adds the toggle that opens and closes the themer sidebar to the Studio\n * navbar — an icon button with a tooltip in the top bar (like the Tasks\n * toggle), and a regular titled action in the narrow-screen sidebar menu.\n *\n * @internal\n */\nexport function ThemerNavbar(props: NavbarProps) {\n const {open, setOpen} = useThemer()\n\n return props.renderDefault({\n ...props,\n __internal_actions: [\n ...(props.__internal_actions ?? []),\n {\n location: 'topbar',\n name: 'themer-topbar',\n render: () => <ThemerNavbarButton />,\n },\n {\n icon: ColorWheelIcon,\n location: 'sidebar',\n name: 'themer-sidebar',\n onAction: () => setOpen(!open),\n selected: open,\n title: 'Themer',\n },\n ],\n })\n}\n","import {definePlugin, type LayoutProps} from 'sanity'\n\nimport {applyHues} from '../legacy/applyHues'\nimport {PartialHues} from '../legacy/types'\nimport {ThemerActiveToolLayout} from './ThemerActiveToolLayout'\nimport {ThemerLayout} from './ThemerLayout'\nimport {ThemerNavbar} from './ThemerNavbar'\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 * The hues that the Studio's configured theme was generated from — the\n * themer starts editing from these, so pass the same object that the\n * `theme` in the Studio config uses:\n *\n * ```ts\n * const hues = parseHuesFromUrl('https://themer.sanity.build/api/hues?preset=verdant')\n *\n * export default defineConfig({\n * theme: createTheme(hues),\n * plugins: [themerTool({hues})],\n * })\n * ```\n */\n hues?: PartialHues\n}\n\n/**\n * A Studio plugin that adds a themer sidebar for the legacy Themer themes:\n * a navbar toggle opens the sidebar next to the active tool, where presets,\n * per-hue editors and pasted themer.sanity.build URLs preview a legacy\n * `createTheme` theme live on the whole Studio while you browse around.\n * Toggle between light and dark mode with the regular appearance menu — the\n * preview follows it.\n *\n * ```ts\n * import {themerTool} from '@sanity/themer/tool'\n * import {defineConfig} from 'sanity'\n *\n * export default defineConfig({\n * plugins: [themerTool()],\n * // ...rest of the config\n * })\n * ```\n *\n * 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 baseHues = applyHues(options?.hues ?? {})\n\n function ThemerLayoutWithOptions(props: LayoutProps) {\n return <ThemerLayout {...props} baseHues={baseHues} />\n }\n\n return {\n name: '@sanity/themer/tool',\n studio: {\n components: {\n layout: ThemerLayoutWithOptions,\n navbar: ThemerNavbar,\n activeToolLayout: ThemerActiveToolLayout,\n },\n },\n }\n})\n"],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ import { RootTheme } from "@sanity/ui/theme";
2
+ /**
3
+ * The tint (between 50 and 950) that a `Hue`'s `mid` color is placed at.
4
+ *
5
+ * @public
6
+ */
7
+ type HueMidPoint = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 950;
8
+ /**
9
+ * A single hue configuration, matching the hosted Themer service
10
+ * (themer.sanity.build) hue format.
11
+ *
12
+ * @public
13
+ */
14
+ interface Hue {
15
+ /** The mid color of the hue's tint ramp, as a hex color */
16
+ mid: string;
17
+ /** The tint that `mid` is placed at — the rest of the ramp is interpolated */
18
+ midPoint: HueMidPoint;
19
+ /** The hex color that the ramp's lightest end interpolates towards */
20
+ lightest: string;
21
+ /** The hex color that the ramp's darkest end interpolates towards */
22
+ darkest: string;
23
+ }
24
+ /**
25
+ * The six hues a legacy Themer theme is generated from.
26
+ *
27
+ * @public
28
+ */
29
+ interface Hues {
30
+ default: Hue;
31
+ transparent: Hue;
32
+ primary: Hue;
33
+ positive: Hue;
34
+ caution: Hue;
35
+ critical: Hue;
36
+ }
37
+ /**
38
+ * `Hues` where every hue, and every property of each hue, is optional.
39
+ * Omitted properties fall back to the default Studio theme hues.
40
+ *
41
+ * @public
42
+ */
43
+ type PartialHues = { [TKey in keyof Hues]?: Partial<Hues[TKey]>; };
44
+ /**
45
+ * A theme generated by `createTheme`, compatible with the `theme` property in
46
+ * a Sanity Studio `defineConfig`.
47
+ *
48
+ * @public
49
+ */
50
+ type LegacyTheme = RootTheme & {
51
+ /**
52
+ * Set to `undefined` so that `@sanity/ui` derives the v2 theme internally
53
+ * from the generated colors.
54
+ */
55
+ v2: undefined;
56
+ };
57
+ /**
58
+ * A preset theme, carried over from the hosted Themer service.
59
+ *
60
+ * @public
61
+ */
62
+ interface ThemePreset {
63
+ slug: string;
64
+ title: string;
65
+ /**
66
+ * The canonical search params for this preset — the same query that
67
+ * `https://themer.sanity.build/api/hues` served the preset for.
68
+ */
69
+ searchParams: string;
70
+ /** The preset's resolved hues, ready to pass to `createTheme` */
71
+ hues: Hues;
72
+ }
73
+ export { PartialHues as a, LegacyTheme as i, HueMidPoint as n, ThemePreset as o, Hues as r, Hue as t };
74
+ //# sourceMappingURL=types-DfPLuLv0.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-DfPLuLv0.d.ts","names":[],"sources":["../src/legacy/types.ts"],"mappings":";;;;;;KAOY;;;;;;;UAQK;;EAEf;;EAEA,UAAU;;EAEV;;EAEA;;;;;;;UAQe;EACf,SAAS;EACT,aAAa;EACb,SAAS;EACT,UAAU;EACV,SAAS;EACT,UAAU;;;;;;;;KASA,iBAAgB,cAAc,QAAQ,QAAQ,KAAK;;;;;;;KAQnD,cAAc;;;;;EAKxB;;;;;;;UAQe;EACf;EACA;;;;;EAKA;;EAEA,MAAM"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/themer",
3
- "version": "0.0.0",
3
+ "version": "0.1.0",
4
4
  "description": "Generate Sanity Studio themes, and preview them with a Studio tool.",
5
5
  "keywords": [
6
6
  "sanity",
@@ -25,60 +25,43 @@
25
25
  ],
26
26
  "type": "module",
27
27
  "sideEffects": false,
28
- "main": "./dist/index.cjs",
29
- "module": "./dist/index.js",
30
- "types": "./dist/index.d.cts",
31
- "typesVersions": {
32
- "*": {
33
- "legacy": [
34
- "./dist/legacy.d.cts"
35
- ],
36
- "tool": [
37
- "./dist/tool.d.cts"
38
- ]
39
- }
40
- },
41
28
  "exports": {
42
- ".": {
43
- "import": "./dist/index.js",
44
- "require": "./dist/index.cjs"
45
- },
46
- "./legacy": {
47
- "import": "./dist/legacy.js",
48
- "require": "./dist/legacy.cjs"
49
- },
50
- "./tool": {
51
- "import": "./dist/tool.js",
52
- "require": "./dist/tool.cjs"
53
- },
29
+ "./legacy": "./dist/legacy.js",
30
+ "./tool": "./dist/tool.js",
54
31
  "./package.json": "./package.json"
55
32
  },
56
- "publishConfig": {
57
- "access": "public"
58
- },
59
33
  "dependencies": {
60
- "@sanity/color": "^3.0.7",
61
- "@sanity/ui": "^3.4.3",
62
- "@sanity/icons": "^5.2.1"
34
+ "react-compiler-runtime": "1.0.0",
35
+ "react-refractor": "^4.0.0",
36
+ "refractor": "^5.0.0",
37
+ "@sanity/color": "^3.0.8",
38
+ "@sanity/icons": "^5.2.1",
39
+ "@sanity/ui": "^3.5.0"
63
40
  },
64
41
  "devDependencies": {
65
- "@sanity/tsdown-config": "^0.19.6",
42
+ "@sanity/tsdown-config": "^0.21.1",
66
43
  "@types/node": "^24.13.3",
67
44
  "@types/react": "^19.2.17",
68
- "react": "^19.2.7",
45
+ "babel-plugin-react-compiler": "^1.0.0",
46
+ "react": "^19.2.8",
69
47
  "rimraf": "^5.0.5",
70
- "sanity": "^6.5.0",
71
- "tsdown": "^0.22.12",
72
- "typescript": "6.0.3",
48
+ "sanity": "^6.6.0",
49
+ "styled-components": "^6.4.4",
50
+ "tsdown": "^0.22.14",
51
+ "typescript": "7.0.2",
73
52
  "vitest": "^4.1.10"
74
53
  },
75
54
  "peerDependencies": {
76
- "react": "^18 || >=19.0.0-0",
77
- "sanity": "^5 || ^6"
55
+ "react": "^19",
56
+ "sanity": "^6",
57
+ "styled-components": "^6"
78
58
  },
79
59
  "peerDependenciesMeta": {
80
60
  "sanity": {
81
61
  "optional": true
62
+ },
63
+ "styled-components": {
64
+ "optional": true
82
65
  }
83
66
  },
84
67
  "engines": {
@@ -1,52 +0,0 @@
1
- /**
2
- * Color mixing that is byte-for-byte compatible with the `mix` function from
3
- * `polished`, which the hosted Themer service (themer.sanity.build) used to
4
- * interpolate hue tints. Only opaque hex colors are supported, which is all
5
- * the theme generators ever pass.
6
- *
7
- * @internal
8
- */
9
- function mix(weight, color, otherColor) {
10
- if (weight === 0) return otherColor;
11
- let [r1, g1, b1] = hexToRgb(color), [r2, g2, b2] = hexToRgb(otherColor), w2 = 1 - weight;
12
- return reduceHex(`#${channelToHex(Math.floor(r1 * weight + r2 * w2))}${channelToHex(Math.floor(g1 * weight + g2 * w2))}${channelToHex(Math.floor(b1 * weight + b2 * w2))}`);
13
- }
14
- /**
15
- * Matches `#abc` and `#aabbcc` hex colors (the only formats the theme
16
- * generators accept), same as the hosted Themer service did.
17
- *
18
- * @internal
19
- */
20
- function isColor(input) {
21
- return /^#(?:[0-9a-f]{3}){1,2}$/i.test(input);
22
- }
23
- function hexToRgb(color) {
24
- if (!isColor(color)) throw TypeError(`Invalid color: ${JSON.stringify(color)} — expected a hex color`);
25
- let hex = color.length === 4 ? `${color[1]}${color[1]}${color[2]}${color[2]}${color[3]}${color[3]}` : color.slice(1);
26
- return [
27
- parseInt(hex.slice(0, 2), 16),
28
- parseInt(hex.slice(2, 4), 16),
29
- parseInt(hex.slice(4, 6), 16)
30
- ];
31
- }
32
- function channelToHex(value) {
33
- let hex = value.toString(16);
34
- return hex.length === 1 ? `0${hex}` : hex;
35
- }
36
- /** Shortens `#aabbcc` to `#abc` when possible, same as `polished` does */
37
- function reduceHex(hex) {
38
- return hex[1] === hex[2] && hex[3] === hex[4] && hex[5] === hex[6] ? `#${hex[1]}${hex[3]}${hex[5]}` : hex;
39
- }
40
- Object.defineProperty(exports, "n", {
41
- enumerable: !0,
42
- get: function() {
43
- return mix;
44
- }
45
- }), Object.defineProperty(exports, "t", {
46
- enumerable: !0,
47
- get: function() {
48
- return isColor;
49
- }
50
- });
51
-
52
- //# sourceMappingURL=mix.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mix.cjs","names":[],"sources":["../../src/lib/mix.ts"],"sourcesContent":["/**\n * Color mixing that is byte-for-byte compatible with the `mix` function from\n * `polished`, which the hosted Themer service (themer.sanity.build) used to\n * interpolate hue tints. Only opaque hex colors are supported, which is all\n * the theme generators ever pass.\n *\n * @internal\n */\nexport function mix(weight: number, color: string, otherColor: string): string {\n // `polished` returns the other color as-is when the weight is 0\n if (weight === 0) return otherColor\n\n const [r1, g1, b1] = hexToRgb(color)\n const [r2, g2, b2] = hexToRgb(otherColor)\n\n const w2 = 1 - weight\n\n return reduceHex(\n `#${channelToHex(Math.floor(r1 * weight + r2 * w2))}${channelToHex(\n Math.floor(g1 * weight + g2 * w2),\n )}${channelToHex(Math.floor(b1 * weight + b2 * w2))}`,\n )\n}\n\n/**\n * Matches `#abc` and `#aabbcc` hex colors (the only formats the theme\n * generators accept), same as the hosted Themer service did.\n *\n * @internal\n */\nexport function isColor(input: string): boolean {\n return /^#(?:[0-9a-f]{3}){1,2}$/i.test(input)\n}\n\nfunction hexToRgb(color: string): [number, number, number] {\n if (!isColor(color)) {\n throw new TypeError(`Invalid color: ${JSON.stringify(color)} — expected a hex color`)\n }\n\n const hex =\n color.length === 4\n ? `${color[1]}${color[1]}${color[2]}${color[2]}${color[3]}${color[3]}`\n : color.slice(1)\n\n return [\n parseInt(hex.slice(0, 2), 16),\n parseInt(hex.slice(2, 4), 16),\n parseInt(hex.slice(4, 6), 16),\n ]\n}\n\nfunction channelToHex(value: number): string {\n const hex = value.toString(16)\n\n return hex.length === 1 ? `0${hex}` : hex\n}\n\n/** Shortens `#aabbcc` to `#abc` when possible, same as `polished` does */\nfunction reduceHex(hex: string): string {\n if (hex[1] === hex[2] && hex[3] === hex[4] && hex[5] === hex[6]) {\n return `#${hex[1]}${hex[3]}${hex[5]}`\n }\n\n return hex\n}\n"],"mappings":";;;;;;;;AAQA,SAAgB,IAAI,QAAgB,OAAe,YAA4B;CAE7E,IAAI,WAAW,GAAG,OAAO;CAEzB,IAAM,CAAC,IAAI,IAAI,MAAM,SAAS,KAAK,GAC7B,CAAC,IAAI,IAAI,MAAM,SAAS,UAAU,GAElC,KAAK,IAAI;CAEf,OAAO,UACL,IAAI,aAAa,KAAK,MAAM,KAAK,SAAS,KAAK,EAAE,CAAC,IAAI,aACpD,KAAK,MAAM,KAAK,SAAS,KAAK,EAAE,CAClC,IAAI,aAAa,KAAK,MAAM,KAAK,SAAS,KAAK,EAAE,CAAC,GACpD;AACF;;;;;;;AAQA,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,2BAA2B,KAAK,KAAK;AAC9C;AAEA,SAAS,SAAS,OAAyC;CACzD,IAAI,CAAC,QAAQ,KAAK,GAChB,MAAU,UAAU,kBAAkB,KAAK,UAAU,KAAK,EAAE,wBAAwB;CAGtF,IAAM,MACJ,MAAM,WAAW,IACb,GAAG,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM,OAChE,MAAM,MAAM,CAAC;CAEnB,OAAO;EACL,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE;EAC5B,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE;EAC5B,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE;CAC9B;AACF;AAEA,SAAS,aAAa,OAAuB;CAC3C,IAAM,MAAM,MAAM,SAAS,EAAE;CAE7B,OAAO,IAAI,WAAW,IAAI,IAAI,QAAQ;AACxC;;AAGA,SAAS,UAAU,KAAqB;CAKtC,OAJI,IAAI,OAAO,IAAI,MAAM,IAAI,OAAO,IAAI,MAAM,IAAI,OAAO,IAAI,KACpD,IAAI,IAAI,KAAK,IAAI,KAAK,IAAI,OAG5B;AACT"}
@@ -1,42 +0,0 @@
1
- /**
2
- * Color mixing that is byte-for-byte compatible with the `mix` function from
3
- * `polished`, which the hosted Themer service (themer.sanity.build) used to
4
- * interpolate hue tints. Only opaque hex colors are supported, which is all
5
- * the theme generators ever pass.
6
- *
7
- * @internal
8
- */
9
- function mix(weight, color, otherColor) {
10
- if (weight === 0) return otherColor;
11
- let [r1, g1, b1] = hexToRgb(color), [r2, g2, b2] = hexToRgb(otherColor), w2 = 1 - weight;
12
- return reduceHex(`#${channelToHex(Math.floor(r1 * weight + r2 * w2))}${channelToHex(Math.floor(g1 * weight + g2 * w2))}${channelToHex(Math.floor(b1 * weight + b2 * w2))}`);
13
- }
14
- /**
15
- * Matches `#abc` and `#aabbcc` hex colors (the only formats the theme
16
- * generators accept), same as the hosted Themer service did.
17
- *
18
- * @internal
19
- */
20
- function isColor(input) {
21
- return /^#(?:[0-9a-f]{3}){1,2}$/i.test(input);
22
- }
23
- function hexToRgb(color) {
24
- if (!isColor(color)) throw TypeError(`Invalid color: ${JSON.stringify(color)} — expected a hex color`);
25
- let hex = color.length === 4 ? `${color[1]}${color[1]}${color[2]}${color[2]}${color[3]}${color[3]}` : color.slice(1);
26
- return [
27
- parseInt(hex.slice(0, 2), 16),
28
- parseInt(hex.slice(2, 4), 16),
29
- parseInt(hex.slice(4, 6), 16)
30
- ];
31
- }
32
- function channelToHex(value) {
33
- let hex = value.toString(16);
34
- return hex.length === 1 ? `0${hex}` : hex;
35
- }
36
- /** Shortens `#aabbcc` to `#abc` when possible, same as `polished` does */
37
- function reduceHex(hex) {
38
- return hex[1] === hex[2] && hex[3] === hex[4] && hex[5] === hex[6] ? `#${hex[1]}${hex[3]}${hex[5]}` : hex;
39
- }
40
- export { mix as n, isColor as t };
41
-
42
- //# sourceMappingURL=mix.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mix.js","names":[],"sources":["../../src/lib/mix.ts"],"sourcesContent":["/**\n * Color mixing that is byte-for-byte compatible with the `mix` function from\n * `polished`, which the hosted Themer service (themer.sanity.build) used to\n * interpolate hue tints. Only opaque hex colors are supported, which is all\n * the theme generators ever pass.\n *\n * @internal\n */\nexport function mix(weight: number, color: string, otherColor: string): string {\n // `polished` returns the other color as-is when the weight is 0\n if (weight === 0) return otherColor\n\n const [r1, g1, b1] = hexToRgb(color)\n const [r2, g2, b2] = hexToRgb(otherColor)\n\n const w2 = 1 - weight\n\n return reduceHex(\n `#${channelToHex(Math.floor(r1 * weight + r2 * w2))}${channelToHex(\n Math.floor(g1 * weight + g2 * w2),\n )}${channelToHex(Math.floor(b1 * weight + b2 * w2))}`,\n )\n}\n\n/**\n * Matches `#abc` and `#aabbcc` hex colors (the only formats the theme\n * generators accept), same as the hosted Themer service did.\n *\n * @internal\n */\nexport function isColor(input: string): boolean {\n return /^#(?:[0-9a-f]{3}){1,2}$/i.test(input)\n}\n\nfunction hexToRgb(color: string): [number, number, number] {\n if (!isColor(color)) {\n throw new TypeError(`Invalid color: ${JSON.stringify(color)} — expected a hex color`)\n }\n\n const hex =\n color.length === 4\n ? `${color[1]}${color[1]}${color[2]}${color[2]}${color[3]}${color[3]}`\n : color.slice(1)\n\n return [\n parseInt(hex.slice(0, 2), 16),\n parseInt(hex.slice(2, 4), 16),\n parseInt(hex.slice(4, 6), 16),\n ]\n}\n\nfunction channelToHex(value: number): string {\n const hex = value.toString(16)\n\n return hex.length === 1 ? `0${hex}` : hex\n}\n\n/** Shortens `#aabbcc` to `#abc` when possible, same as `polished` does */\nfunction reduceHex(hex: string): string {\n if (hex[1] === hex[2] && hex[3] === hex[4] && hex[5] === hex[6]) {\n return `#${hex[1]}${hex[3]}${hex[5]}`\n }\n\n return hex\n}\n"],"mappings":";;;;;;;;AAQA,SAAgB,IAAI,QAAgB,OAAe,YAA4B;CAE7E,IAAI,WAAW,GAAG,OAAO;CAEzB,IAAM,CAAC,IAAI,IAAI,MAAM,SAAS,KAAK,GAC7B,CAAC,IAAI,IAAI,MAAM,SAAS,UAAU,GAElC,KAAK,IAAI;CAEf,OAAO,UACL,IAAI,aAAa,KAAK,MAAM,KAAK,SAAS,KAAK,EAAE,CAAC,IAAI,aACpD,KAAK,MAAM,KAAK,SAAS,KAAK,EAAE,CAClC,IAAI,aAAa,KAAK,MAAM,KAAK,SAAS,KAAK,EAAE,CAAC,GACpD;AACF;;;;;;;AAQA,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,2BAA2B,KAAK,KAAK;AAC9C;AAEA,SAAS,SAAS,OAAyC;CACzD,IAAI,CAAC,QAAQ,KAAK,GAChB,MAAU,UAAU,kBAAkB,KAAK,UAAU,KAAK,EAAE,wBAAwB;CAGtF,IAAM,MACJ,MAAM,WAAW,IACb,GAAG,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM,OAChE,MAAM,MAAM,CAAC;CAEnB,OAAO;EACL,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE;EAC5B,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE;EAC5B,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE;CAC9B;AACF;AAEA,SAAS,aAAa,OAAuB;CAC3C,IAAM,MAAM,MAAM,SAAS,EAAE;CAE7B,OAAO,IAAI,WAAW,IAAI,IAAI,QAAQ;AACxC;;AAGA,SAAS,UAAU,KAAqB;CAKtC,OAJI,IAAI,OAAO,IAAI,MAAM,IAAI,OAAO,IAAI,MAAM,IAAI,OAAO,IAAI,KACpD,IAAI,IAAI,KAAK,IAAI,KAAK,IAAI,OAG5B;AACT"}