@sanity/themer
0.8.10.9.0
dist/themes-Bxgltjmb.js.map+
dist/themes-Bxgltjmb.js.mapNew file+1
Index: package/dist/themes-Bxgltjmb.js.map
===================================================================
--- package/dist/themes-Bxgltjmb.js.map
+++ package/dist/themes-Bxgltjmb.js.map
@@ -0,0 +1,1 @@
+{"version":3,"file":"themes-Bxgltjmb.js","names":["\"default\""],"sources":["../src/tool/constants.ts","../src/tool/ViewTransitions.css.ts","../src/tool/addThemerTransitionType.ts","../src/tool/themes.ts"],"sourcesContent":["export const MIN_MEDIA_INDEX_FOR_SPLIT_SCREEN = 3\n/**\n * The Studio navbar's root, the `Card` that draws its bottom border — its\n * test id is stable and unique to the navbar, unlike its `data-ui` name\n */\nexport const NAVBAR_SELECTOR = '[data-testid=\"studio-navbar\"]'\n","import {\n createViewTransition,\n globalStyle,\n keyframes,\n style,\n type GlobalStyleRule,\n} from '@vanilla-extract/css'\nimport type {ViewTransitionClass} from 'react'\n\nfunction createViewTransitionType(\n rules: Partial<Record<'new' | 'old' | 'group' | 'imagePair', GlobalStyleRule>>,\n debugId?: string,\n) {\n const type = style({}, debugId)\n if (rules.new) {\n globalStyle(`::view-transition-new(.${type})`, rules.new)\n }\n if (rules.old) {\n globalStyle(`::view-transition-old(.${type})`, rules.old)\n }\n if (rules.group) {\n globalStyle(`::view-transition-group(.${type})`, rules.group)\n }\n if (rules.imagePair) {\n globalStyle(`::view-transition-image-pair(.${type})`, rules.imagePair)\n }\n return type\n}\n\n/**\n * The transition type of the layout's motions — what `ThemerLayout` adds to\n * every transition it starts, and React passes on to the view transition.\n * `:active-view-transition-type()` tells the layout's transitions from any\n * other on the page while they run.\n *\n * It's used on all transition types that userland might want to participate in, for example by setting their own:\n * ```tsx\n * <ViewTransition update={{'sanity-themer': 'auto', default: 'none'}}>\n * ```\n */\nexport const layoutTransitionType = 'sanity-themer'\n\n/**\n * Used with addTransitionType, and on `update` props on <ViewTransition> as the object key\n */\nexport const viewTransitionTypes = {\n 'open': createViewTransition('open'),\n 'close': createViewTransition('close'),\n 'split-screen:open': createViewTransition('split-screen-open'),\n 'split-screen:close': createViewTransition('split-screen-close'),\n 'crossfade': createViewTransition('crossfade'),\n}\n\nconst navbarButtonUpdateTransition = createViewTransitionType({\n new: {animation: 'none'},\n old: {display: 'none'},\n})\n\nconst resizeStudioRules = {inlineSize: '100%', blockSize: '100%', objectFit: 'fill'} as const\nconst resizeStudioTransition = createViewTransitionType(\n {old: resizeStudioRules, new: resizeStudioRules},\n 'resizeStudio',\n)\n\nconst splitScreenFilter = 'blur(12px)'\nconst splitStudioTransition = createViewTransitionType({\n old: {\n ...resizeStudioRules,\n animationName: keyframes({to: {opacity: 0, filter: splitScreenFilter}}),\n },\n new: {\n ...resizeStudioRules,\n animationName: keyframes({from: {opacity: 0, filter: splitScreenFilter}}),\n },\n})\n/**\n * The split copy slides in from the side, or out to it — hidden for the first\n * quarter of the way in, and for the last quarter of the way out\n */\nconst splitScreenSlideIn = keyframes({\n 'from': {transform: 'translateX(-100%)', opacity: 0},\n '25%': {opacity: 0},\n})\nconst splitScreenSlideOut = keyframes({\n 'to': {transform: 'translateX(-100%)', opacity: 0},\n '75%': {opacity: 0},\n})\n\nexport const viewTransitionClasses = {\n navbarButton: {\n update: {\n [viewTransitionTypes['split-screen:open']]: 'none',\n [viewTransitionTypes['split-screen:close']]: 'none',\n [viewTransitionTypes.open]: navbarButtonUpdateTransition,\n [viewTransitionTypes.close]: navbarButtonUpdateTransition,\n [viewTransitionTypes.crossfade]: navbarButtonUpdateTransition,\n default: 'none',\n },\n } as const satisfies Record<string, ViewTransitionClass>,\n navbarButtonTooltip: {\n update: {\n [viewTransitionTypes['split-screen:open']]: 'none',\n [viewTransitionTypes['split-screen:close']]: 'none',\n [viewTransitionTypes.open]: 'auto',\n [viewTransitionTypes.close]: 'auto',\n default: 'none',\n },\n } as const satisfies Record<string, ViewTransitionClass>,\n sidebar: {\n enter: {\n [viewTransitionTypes.open]: createViewTransitionType(\n {new: {animationName: keyframes({from: {transform: 'translateX(100%)'}})}},\n 'panelSlideIn',\n ),\n default: 'none',\n },\n update: {\n [viewTransitionTypes['split-screen:open']]: 'none',\n [viewTransitionTypes['split-screen:close']]: 'none',\n [viewTransitionTypes.crossfade]: 'auto',\n default: 'none',\n },\n exit: {\n [viewTransitionTypes.close]: createViewTransitionType(\n {old: {animationName: keyframes({to: {transform: 'translateX(100%)'}})}},\n 'panelSlideOut',\n ),\n default: 'none',\n },\n } as const satisfies Record<string, ViewTransitionClass>,\n splitscreen: {\n enter: {\n [viewTransitionTypes['split-screen:open']]: createViewTransitionType({\n new: {animationName: splitScreenSlideIn},\n }),\n default: 'none',\n },\n update: {\n [viewTransitionTypes.crossfade]: 'auto',\n default: 'none',\n },\n exit: {\n [viewTransitionTypes['split-screen:close']]: createViewTransitionType({\n old: {animationName: splitScreenSlideOut},\n }),\n default: 'none',\n },\n } as const satisfies Record<string, ViewTransitionClass>,\n studio: {\n update: {\n // [viewTransitionTypes.crossfade]: createViewTransitionType(\n // {\n // imagePair: {perspective: '1000px', transformStyle: 'preserve-3d'},\n // group: {animationDuration: '6s !important', animationTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1) !important', animationFillMode: 'both'},\n // old: {animationName: flipOut, backfaceVisibility: 'hidden', },\n // new: {animationName: flipIn, backfaceVisibility: 'hidden', }},\n // 'crossfadeStudio',\n // ),\n [viewTransitionTypes['open']]: resizeStudioTransition,\n [viewTransitionTypes['close']]: resizeStudioTransition,\n [viewTransitionTypes['split-screen:open']]: splitStudioTransition,\n [viewTransitionTypes['split-screen:close']]: splitStudioTransition,\n [viewTransitionTypes.crossfade]: 'auto',\n default: 'none',\n },\n } as const satisfies Record<string, ViewTransitionClass>,\n}\n\n/**\n * Default animation timings for all Themer view transitions\n */\nglobalStyle(\n `:root:active-view-transition-type(${layoutTransitionType})::view-transition-group(*)`,\n {animationDuration: '320ms', animationTimingFunction: 'cubic-bezier(0.65, 0, 0.35, 1)'},\n)\n\nglobalStyle(\n [\n `:root:active-view-transition-type(${viewTransitionTypes['split-screen:open']})::view-transition-group(*)`,\n `:root:active-view-transition-type(${viewTransitionTypes['split-screen:close']})::view-transition-group(*)`,\n ].join(','),\n {animationDuration: '480ms'},\n)\n\n/** The layout's `Flex` positions the sidebar overlay on small screens */\nexport const layout = style({\n position: 'relative',\n})\n\n/**\n * Disable animations automatically for themer view transitions if the user signals to do so\n */\nglobalStyle(\n `:root:active-view-transition-type(${layoutTransitionType})::view-transition-group(*),:root:active-view-transition-type(${layoutTransitionType})::view-transition-old(*),:root:active-view-transition-type(${layoutTransitionType})::view-transition-new(*)`,\n {\n '@media': {\n '(prefers-reduced-motion: reduce)': {\n animation: 'none !important',\n },\n },\n },\n)\n","import {addTransitionType} from 'react'\n\nimport {layoutTransitionType, viewTransitionTypes} from './ViewTransitions.css'\n\n/**\n * Adds the default sanity-themer transition type, which allows custom view transition overrides, as well as customization in userland\n */\nexport function addThemerTransitionType(type: keyof typeof viewTransitionTypes) {\n if (!(type in viewTransitionTypes)) {\n throw new Error(`Invalid transition type`, {cause: {type}})\n }\n addTransitionType(viewTransitionTypes[type])\n // Used to mark that a themer transition is happening, can be styled with vanilla css, but also by setting class props on <ViewTransition>\n addTransitionType(layoutTransitionType)\n}\n","import type {BuildThemeOptions} from '../theme/options'\nimport {presets} from '../theme/presets'\nimport type {ImagePalette} from './imagePalette'\n\n/**\n * Where a theme in the themer list comes from: the theme the Studio config\n * was generated from, one of the presets defined in code, or one the user\n * added in the tool. Only custom themes are editable — the others are\n * duplicated into a custom theme first.\n */\ntype ThemerThemeSource = 'config' | 'preset' | 'custom'\n\n/** A theme the themer tool lists @internal */\nexport interface ThemerTheme {\n slug: string\n title: string\n options: BuildThemeOptions\n source: ThemerThemeSource\n /** The palette of the image the theme's colors were taken from, for custom themes */\n palette?: ImagePalette\n}\n\n/** A theme the user added in the tool, as persisted @internal */\nexport interface CustomTheme {\n slug: string\n title: string\n options: BuildThemeOptions\n /** The palette of the image the theme's colors were taken from */\n palette?: ImagePalette\n}\n\n/** The persisted themer state @internal */\nexport interface ThemerState {\n /**\n * The slug of the applied theme — `null` applies nothing on top of the\n * Studio's configured theme\n */\n active: string | null\n /** The themes the user added */\n custom: CustomTheme[]\n /** The slugs of the themes the user removed from the list */\n removed: string[]\n /**\n * The slugs of the themes in the order the user arranged them — themes not\n * in it (new presets, themes added since) follow in their default order\n */\n order: string[]\n}\n\n/** The slug of the theme the Studio config was generated from @internal */\nexport const CONFIG_SLUG = 'config'\n\n/** The title of the theme the Studio config was generated from */\nexport const CONFIG_TITLE = 'Studio config'\n\n/** The title new themes start out with @internal */\nexport const UNTITLED_THEME = 'Untitled theme'\n\n/** @internal */\nexport const initialThemerState: ThemerState = {active: null, custom: [], removed: [], order: []}\n\n/** The themes the tool works with, derived from the persisted state @internal */\nexport interface ResolvedThemes {\n /** The themes to pick from, in list order */\n themes: ThemerTheme[]\n /** The removed themes, which can be restored */\n removed: ThemerTheme[]\n /** The applied theme */\n active: ThemerTheme | undefined\n}\n\nconst presetsWithSource = presets.map((preset) =>\n Object.assign({}, preset, {source: 'preset' as const}),\n)\n\n/**\n * Resolves the list of themes: the presets, then the user's own themes —\n * rearranged into the order the user dragged them into, with themes that\n * order does not know about kept in that default order after the ones it\n * does. Removed themes are set aside so they can be restored. The configured\n * theme is not in the list — `ThemeList` shows it ahead of it — and it is\n * what applies when no listed theme does: `active` is `undefined` for it, and\n * for an applied slug that no longer resolves.\n *\n * @internal\n */\nexport function resolveThemes(state: ThemerState): ResolvedThemes {\n const all: ThemerTheme[] = [...presetsWithSource]\n\n for (const theme of state.custom) {\n all.push({\n slug: theme.slug,\n title: theme.title,\n options: theme.options,\n source: 'custom',\n ...(theme.palette ? {palette: theme.palette} : {}),\n })\n }\n\n const position = new Map(state.order.map((slug, index) => [slug, index]))\n const rank = (theme: ThemerTheme) => position.get(theme.slug) ?? state.order.length\n\n // A stable sort: the themes the order does not know about keep their default order\n all.sort((a, b) => rank(a) - rank(b))\n\n const removedSlugs = new Set(state.removed)\n const themes = all.filter((theme) => !removedSlugs.has(theme.slug))\n const removed = all.filter((theme) => removedSlugs.has(theme.slug))\n const active = themes.find((theme) => theme.slug === state.active)\n\n return {themes, removed, active}\n}\n\n/**\n * Creates a custom theme with a slug that cannot collide with the presets or\n * the configured theme.\n *\n * @internal\n */\nexport function createCustomTheme(\n title: string,\n options: BuildThemeOptions,\n palette?: ImagePalette,\n): CustomTheme {\n return {slug: `custom-${randomId()}`, title, options, ...(palette ? {palette} : {})}\n}\n\n/** The title of a duplicated theme @internal */\nexport function duplicateTitle(title: string): string {\n return `${displayTitle(title)} copy`\n}\n\n/** The title to show for a theme, falling back when the user cleared it @internal */\nexport function displayTitle(title: string): string {\n return title.trim() || UNTITLED_THEME\n}\n\nfunction randomId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID()\n }\n\n return `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`\n}\n"],"mappings":";;;;;;AAKA,MAAa,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AEE/B,SAAgB,wBAAwB,MAAwC;CAC9E,IAAI,EAAE,QAAQ,sBACZ,MAAU,MAAM,2BAA2B,EAAC,OAAO,EAAC,KAAI,EAAC,CAAC;CAI5D,AAFA,kBAAkB,oBAAoB,KAAK,GAE3C,kBAAkB,oBAAoB;AACxC;;ACoCA,MAAa,cAAc,UAGd,eAAe,iBAGf,iBAAiB,kBAGjB,qBAAkC;CAAC,QAAQ;CAAM,QAAQ,CAAC;CAAG,SAAS,CAAC;CAAG,OAAO,CAAC;AAAC,GAY1F,oBAAoB,QAAQ,KAAK,WACrC,OAAO,OAAO,CAAC,GAAG,QAAQ,EAAC,QAAQ,SAAiB,CAAC,CACvD;;;;;;;;;;;;AAaA,SAAgB,cAAc,OAAoC;CAChE,IAAM,MAAqB,CAAC,GAAG,iBAAiB;CAEhD,KAAK,IAAM,SAAS,MAAM,QACxB,IAAI,KAAK;EACP,MAAM,MAAM;EACZ,OAAO,MAAM;EACb,SAAS,MAAM;EACf,QAAQ;EACR,GAAI,MAAM,UAAU,EAAC,SAAS,MAAM,QAAO,IAAI,CAAC;CAClD,CAAC;CAGH,IAAM,WAAW,IAAI,IAAI,MAAM,MAAM,KAAK,MAAM,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,GAClE,QAAQ,UAAuB,SAAS,IAAI,MAAM,IAAI,KAAK,MAAM,MAAM;CAG7E,IAAI,MAAM,GAAG,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC;CAEpC,IAAM,eAAe,IAAI,IAAI,MAAM,OAAO,GACpC,SAAS,IAAI,QAAQ,UAAU,CAAC,aAAa,IAAI,MAAM,IAAI,CAAC;CAIlE,OAAO;EAAC;EAAQ,SAHA,IAAI,QAAQ,UAAU,aAAa,IAAI,MAAM,IAAI,CAGjD;EAAS,QAFV,OAAO,MAAM,UAAU,MAAM,SAAS,MAAM,MAElC;CAAM;AACjC;;;;;;;AAQA,SAAgB,kBACd,OACA,SACA,SACa;CACb,OAAO;EAAC,MAAM,UAAU,SAAS;EAAK;EAAO;EAAS,GAAI,UAAU,EAAC,QAAO,IAAI,CAAC;CAAE;AACrF;;AAGA,SAAgB,eAAe,OAAuB;CACpD,OAAO,GAAG,aAAa,KAAK,EAAE;AAChC;;AAGA,SAAgB,aAAa,OAAuB;CAClD,OAAO,MAAM,KAAK,KAAA;AACpB;AAEA,SAAS,WAAmB;CAK1B,OAJI,OAAO,SAAW,OAAe,OAAO,OAAO,cAAe,aACzD,OAAO,WAAW,IAGpB,GAAG,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,EAAE;AAC5E"}
\ No newline at end of file