@taprootio/espalier 2.18.0 → 2.20.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/index.d.ts CHANGED
@@ -70,7 +70,8 @@ export * from "./shared/events.js";
70
70
  export { getImageDetails, releasePreviewUrl, type EspalierUploadImage, type ImageDetailsOptions, type SelectedUploadImage, type ExistingUploadImage, type ExistingImage, type ResponsiveImageUrl, type UploadCallbacks, type UploadEventDetail, } from "./image-upload/image-helpers.js";
71
71
  export { calculatePhotoLayout, type LayoutImage, type PhotoRow, } from "./shared/justified-layout.js";
72
72
  export { type TypeaheadFetchItems } from "./pickers/types.js";
73
- export { type EspalierTheme, type PartialTheme, type VariantColorSource, encodeTheme, parseTheme, mergePartials, layerThemes, buildTaprootLightTheme, buildTaprootDarkTheme, NESTED_THEME_KEYS, } from "./shared/theme.js";
73
+ export { type EspalierTheme, type PartialTheme, type PartialThemeContexts, type ThemeContext, type ThemeContexts, type VariantColorSource, encodeTheme, parseTheme, mergePartials, layerThemes, validateThemePair, buildTaprootLightTheme, buildTaprootDarkTheme, NESTED_THEME_KEYS, } from "./shared/theme.js";
74
+ export { auditDataPalette, generateSequentialRamp, generateDivergingRamp, COLOR_VISION_SIMULATIONS, DATA_SERIES_KEYS, DEFAULT_DATA_PALETTE, DEFAULT_DATA_RAMP_STEPS, DEFAULT_DIVERGING_NEUTRAL, MAX_DATA_RAMP_STEPS, MIN_DATA_COLOR_DISTANCE, MIN_DATA_RAMP_LIGHTNESS_STEP, MIN_DATA_RAMP_STEPS, type ColorVisionSimulation, type DataPalette, type DataPaletteIssue, type DataRamp, type DataRamps, type DataSeriesKey, type DivergingDataRamp, type DivergingRampOptions, type PartialDataRamp, type PartialDataRamps, type SequentialDataRamp, type SequentialRampOptions, } from "./shared/data-colors.js";
74
75
  export { WEIGHT_LABELS, extractWeights, normalizeWeight, bestAvailableWeight, extractFamily, getFallbackFont, } from "./shared/font-helpers.js";
75
76
  export { getGoogleFonts } from "./font-picker/esp-font-picker.js";
76
77
  export { themeFitReport, themeFitRows, printThemeFitReport, type ThemeFitReport, type ThemeFitToken, type ThemeFitApcaAction, type ThemeFitAnchor, type ThemeFitRow, } from "./shared/theme-fit-report.js";
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export*from"./box/esp-box.js";export*from"./action-menu/esp-action-menu.js";export*from"./action-menu/esp-action-menu-item.js";export*from"./avatar/esp-avatar.js";export*from"./avatar/esp-profile-chip.js";export*from"./badge/esp-badge.js";export*from"./checkbox/esp-checkbox.js";export*from"./checkbox/esp-checkbox-group.js";export*from"./data-cell/esp-data-cell.js";export*from"./radio-button/esp-radio-button.js";export*from"./radio-button/esp-radio-button-group.js";export*from"./repeater/esp-repeater.js";export*from"./breadcrumbs/esp-breadcrumbs.js";export*from"./button/esp-button.js";export*from"./button/esp-button-group.js";export*from"./color-picker/esp-color-picker.js";export*from"./flyout/esp-flyout.js";export*from"./form/esp-form.js";export*from"./form-item/esp-form-item.js";export*from"./help/esp-help-button.js";export*from"./help/esp-help-provider.js";export*from"./header/index.js";export*from"./page/esp-page.js";export*from"./popover/esp-popover.js";export*from"./dialog/esp-dialog.js";export*from"./empty-state/esp-empty-state.js";export*from"./image-upload/esp-image-upload.js";export*from"./file-upload/esp-file-upload.js";export*from"./font-picker/esp-font-picker.js";export*from"./focus-picker/esp-focus-picker.js";export*from"./footer/index.js";export*from"./grid/esp-grid.js";export*from"./image/esp-image.js";export*from"./image/image-focus.js";export*from"./lightbox/esp-lightbox.js";export*from"./info/esp-info.js";export*from"./input/esp-input.js";export*from"./textarea/esp-textarea.js";export*from"./pickers/esp-pick-one.js";export*from"./pickers/esp-pick-some.js";export*from"./pickers/esp-picker-menu.js";export*from"./pickers/esp-picker-item.js";export*from"./root/esp-root.js";export*from"./menu/index.js";export*from"./burger/esp-burger.js";export*from"./date-picker/esp-date-picker.js";export*from"./details/esp-details.js";export*from"./details/esp-details-group.js";export*from"./tabs/esp-tab.js";export*from"./tabs/esp-tab-group.js";export*from"./slider/esp-slider.js";export*from"./switch/esp-switch.js";export*from"./toaster/esp-toaster.js";export*from"./tooltip/esp-tooltip.js";export*from"./progress/esp-progress.js";export*from"./search/esp-search.js";export*from"./status-indicator/esp-status-indicator.js";export*from"./tree/esp-tree.js";export*from"./tree/esp-tree-item.js";import{DEFAULT_ICON_SPRITE_URL as xo,DEFAULT_ICON_VIEW_BOX as ao,INTENT_VARIANTS as lo,normalizeIntentVariant as so,getIconHref as io,getIconHrefForHost as To,getIconSpriteUrl as Eo}from"./shared/intent-values.js";import{EspalierElementBase as go}from"./shared/esp-element-base.js";import{VALIDITY_CHANGED_EVENT as Fo}from"./shared/validation.js";import{FormFieldController as _o}from"./shared/form-field-controller.js";import{traverseToClosest as uo}from"./shared/utilities.js";import{showToast as Lo}from"./shared/toast-events.js";import{showFlyout as Do,closeFlyout as Ho}from"./shared/flyout-events.js";import{requestHelp as So}from"./shared/help-events.js";import{getEspBus as yo}from"./shared/bus-events.js";export*from"./shared/events.js";import{getImageDetails as Vo,releasePreviewUrl as Wo}from"./image-upload/image-helpers.js";import{calculatePhotoLayout as Bo}from"./shared/justified-layout.js";import{encodeTheme as vo,parseTheme as Go,mergePartials as Oo,layerThemes as ko,buildTaprootLightTheme as zo,buildTaprootDarkTheme as Yo,NESTED_THEME_KEYS as qo}from"./shared/theme.js";import{WEIGHT_LABELS as Mo,extractWeights as Xo,normalizeWeight as jo,bestAvailableWeight as Jo,extractFamily as Qo,getFallbackFont as Zo}from"./shared/font-helpers.js";import{getGoogleFonts as or}from"./font-picker/esp-font-picker.js";import{themeFitReport as er,themeFitRows as tr,printThemeFitReport as mr}from"./shared/theme-fit-report.js";export{xo as DEFAULT_ICON_SPRITE_URL,ao as DEFAULT_ICON_VIEW_BOX,go as EspalierElementBase,_o as FormFieldController,lo as INTENT_VARIANTS,qo as NESTED_THEME_KEYS,Fo as VALIDITY_CHANGED_EVENT,Mo as WEIGHT_LABELS,Jo as bestAvailableWeight,Yo as buildTaprootDarkTheme,zo as buildTaprootLightTheme,Bo as calculatePhotoLayout,Ho as closeFlyout,vo as encodeTheme,Qo as extractFamily,Xo as extractWeights,yo as getEspBus,Zo as getFallbackFont,or as getGoogleFonts,io as getIconHref,To as getIconHrefForHost,Eo as getIconSpriteUrl,Vo as getImageDetails,ko as layerThemes,Oo as mergePartials,so as normalizeIntentVariant,jo as normalizeWeight,Go as parseTheme,mr as printThemeFitReport,Wo as releasePreviewUrl,So as requestHelp,Do as showFlyout,Lo as showToast,er as themeFitReport,tr as themeFitRows,uo as traverseToClosest};
1
+ export*from"./box/esp-box.js";export*from"./action-menu/esp-action-menu.js";export*from"./action-menu/esp-action-menu-item.js";export*from"./avatar/esp-avatar.js";export*from"./avatar/esp-profile-chip.js";export*from"./badge/esp-badge.js";export*from"./checkbox/esp-checkbox.js";export*from"./checkbox/esp-checkbox-group.js";export*from"./data-cell/esp-data-cell.js";export*from"./radio-button/esp-radio-button.js";export*from"./radio-button/esp-radio-button-group.js";export*from"./repeater/esp-repeater.js";export*from"./breadcrumbs/esp-breadcrumbs.js";export*from"./button/esp-button.js";export*from"./button/esp-button-group.js";export*from"./color-picker/esp-color-picker.js";export*from"./flyout/esp-flyout.js";export*from"./form/esp-form.js";export*from"./form-item/esp-form-item.js";export*from"./help/esp-help-button.js";export*from"./help/esp-help-provider.js";export*from"./header/index.js";export*from"./page/esp-page.js";export*from"./popover/esp-popover.js";export*from"./dialog/esp-dialog.js";export*from"./empty-state/esp-empty-state.js";export*from"./image-upload/esp-image-upload.js";export*from"./file-upload/esp-file-upload.js";export*from"./font-picker/esp-font-picker.js";export*from"./focus-picker/esp-focus-picker.js";export*from"./footer/index.js";export*from"./grid/esp-grid.js";export*from"./image/esp-image.js";export*from"./image/image-focus.js";export*from"./lightbox/esp-lightbox.js";export*from"./info/esp-info.js";export*from"./input/esp-input.js";export*from"./textarea/esp-textarea.js";export*from"./pickers/esp-pick-one.js";export*from"./pickers/esp-pick-some.js";export*from"./pickers/esp-picker-menu.js";export*from"./pickers/esp-picker-item.js";export*from"./root/esp-root.js";export*from"./menu/index.js";export*from"./burger/esp-burger.js";export*from"./date-picker/esp-date-picker.js";export*from"./details/esp-details.js";export*from"./details/esp-details-group.js";export*from"./tabs/esp-tab.js";export*from"./tabs/esp-tab-group.js";export*from"./slider/esp-slider.js";export*from"./switch/esp-switch.js";export*from"./toaster/esp-toaster.js";export*from"./tooltip/esp-tooltip.js";export*from"./progress/esp-progress.js";export*from"./search/esp-search.js";export*from"./status-indicator/esp-status-indicator.js";export*from"./tree/esp-tree.js";export*from"./tree/esp-tree-item.js";import{DEFAULT_ICON_SPRITE_URL as xr,DEFAULT_ICON_VIEW_BOX as Tr,INTENT_VARIANTS as ar,normalizeIntentVariant as _r,getIconHref as Ar,getIconHrefForHost as Er,getIconSpriteUrl as lr}from"./shared/intent-values.js";import{EspalierElementBase as Ir}from"./shared/esp-element-base.js";import{VALIDITY_CHANGED_EVENT as sr}from"./shared/validation.js";import{FormFieldController as gr}from"./shared/form-field-controller.js";import{traverseToClosest as Fr}from"./shared/utilities.js";import{showToast as Nr}from"./shared/toast-events.js";import{showFlyout as hr,closeFlyout as Pr}from"./shared/flyout-events.js";import{requestHelp as ur}from"./shared/help-events.js";import{getEspBus as Ur}from"./shared/bus-events.js";export*from"./shared/events.js";import{getImageDetails as Hr,releasePreviewUrl as Vr}from"./image-upload/image-helpers.js";import{calculatePhotoLayout as Gr}from"./shared/justified-layout.js";import{encodeTheme as vr,parseTheme as yr,mergePartials as Wr,layerThemes as wr,validateThemePair as Br,buildTaprootLightTheme as Yr,buildTaprootDarkTheme as kr,NESTED_THEME_KEYS as qr}from"./shared/theme.js";import{auditDataPalette as Kr,generateSequentialRamp as Xr,generateDivergingRamp as jr,COLOR_VISION_SIMULATIONS as Jr,DATA_SERIES_KEYS as Qr,DEFAULT_DATA_PALETTE as Zr,DEFAULT_DATA_RAMP_STEPS as $r,DEFAULT_DIVERGING_NEUTRAL as ro,MAX_DATA_RAMP_STEPS as oo,MIN_DATA_COLOR_DISTANCE as eo,MIN_DATA_RAMP_LIGHTNESS_STEP as to,MIN_DATA_RAMP_STEPS as mo}from"./shared/data-colors.js";import{WEIGHT_LABELS as fo,extractWeights as xo,normalizeWeight as To,bestAvailableWeight as ao,extractFamily as _o,getFallbackFont as Ao}from"./shared/font-helpers.js";import{getGoogleFonts as lo}from"./font-picker/esp-font-picker.js";import{themeFitReport as Io,themeFitRows as So,printThemeFitReport as so}from"./shared/theme-fit-report.js";export{Jr as COLOR_VISION_SIMULATIONS,Qr as DATA_SERIES_KEYS,Zr as DEFAULT_DATA_PALETTE,$r as DEFAULT_DATA_RAMP_STEPS,ro as DEFAULT_DIVERGING_NEUTRAL,xr as DEFAULT_ICON_SPRITE_URL,Tr as DEFAULT_ICON_VIEW_BOX,Ir as EspalierElementBase,gr as FormFieldController,ar as INTENT_VARIANTS,oo as MAX_DATA_RAMP_STEPS,eo as MIN_DATA_COLOR_DISTANCE,to as MIN_DATA_RAMP_LIGHTNESS_STEP,mo as MIN_DATA_RAMP_STEPS,qr as NESTED_THEME_KEYS,sr as VALIDITY_CHANGED_EVENT,fo as WEIGHT_LABELS,Kr as auditDataPalette,ao as bestAvailableWeight,kr as buildTaprootDarkTheme,Yr as buildTaprootLightTheme,Gr as calculatePhotoLayout,Pr as closeFlyout,vr as encodeTheme,_o as extractFamily,xo as extractWeights,jr as generateDivergingRamp,Xr as generateSequentialRamp,Ur as getEspBus,Ao as getFallbackFont,lo as getGoogleFonts,Ar as getIconHref,Er as getIconHrefForHost,lr as getIconSpriteUrl,Hr as getImageDetails,wr as layerThemes,Wr as mergePartials,_r as normalizeIntentVariant,To as normalizeWeight,yr as parseTheme,so as printThemeFitReport,Vr as releasePreviewUrl,ur as requestHelp,hr as showFlyout,Nr as showToast,Io as themeFitReport,So as themeFitRows,Fr as traverseToClosest,Br as validateThemePair};
@@ -63,6 +63,14 @@ export type { SchemeEvents } from "../shared/bus-events.js";
63
63
  *
64
64
  * @customElement esp-root
65
65
  * @slot - Place Espalier components and content here.
66
+ * @cssprop --esp-color-series-1 - First categorical data-series color.
67
+ * @cssprop --esp-color-series-2 - Second categorical data-series color.
68
+ * @cssprop --esp-color-series-3 - Third categorical data-series color.
69
+ * @cssprop --esp-color-series-4 - Fourth categorical data-series color.
70
+ * @cssprop --esp-color-series-5 - Fifth categorical data-series color.
71
+ * @cssprop --esp-color-series-6 - Sixth categorical data-series color.
72
+ * @cssprop --esp-color-series-7 - Seventh categorical data-series color.
73
+ * @cssprop --esp-color-series-8 - Eighth categorical data-series color.
66
74
  *
67
75
  * @docPageTitle Root
68
76
  * @docUrl /components/root
@@ -1,4 +1,4 @@
1
- var l=function(c,e,t,s){var h=arguments.length,o=h<3?e:s===null?s=Object.getOwnPropertyDescriptor(e,t):s,r;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")o=Reflect.decorate(c,e,t,s);else for(var d=c.length-1;d>=0;d--)(r=c[d])&&(o=(h<3?r(o):h>3?r(e,t,o):r(e,t))||o);return h>3&&o&&Object.defineProperty(e,t,o),o},n;import{css as k,html as b,LitElement as C}from"lit";import{customElement as E,property as a}from"lit/decorators.js";import{getEspBus as p}from"../shared/bus-events.js";import{subscribeToRootEvent as T}from"../shared/root-event-subscription.js";import{DEFAULT_LIGHT_THEME as g,DEFAULT_DARK_THEME as f,parseTheme as y,mergeTheme as v}from"../shared/theme.js";import{computeThemeProperties as x}from"./helpers/compute-theme-properties.js";import{registerImageTexture as R,registeredImageTextures as L}from"../shared/image-texture-registry.js";import{registerImageTexture as H,registeredImageTextures as M,BUILT_IN_IMAGE_TEXTURES as P}from"../shared/image-texture-registry.js";let i=n=class extends C{constructor(){super(...arguments),this.schemeBacker="",this.schemeExplicitlySet=!1,this.resolvingDefaultScheme=!1,this.themeEventsReady=!1,this.systemSchemeQuery=null,this.lastSeedColor="",this.resolvedLightTheme={...g},this.resolvedDarkTheme={...f},this.documentClickRegistrationActive=!1,this.correlationId=globalThis.crypto?.randomUUID?.()??Math.random().toString(36),this.lightThemeAttr="",this.darkThemeAttr="",this.fontCSSRoot="/css/fonts/",this.fontDefinitionsUrl="",this.googleFontLoading="auto",this.iconSpriteUrl="/assets/icons.svg",this.defaultScheme="light",this.resizeObserver=new ResizeObserver(()=>{p().publish("window-resized",{emWidth:window.innerWidth/parseFloat(getComputedStyle(document.documentElement).fontSize),emHeight:window.innerHeight/parseFloat(getComputedStyle(document.documentElement).fontSize),pxWidth:window.innerWidth,pxHeight:window.innerHeight})}),this.handleSystemSchemeChange=e=>{this.schemeExplicitlySet||this.defaultScheme!=="system"||(this.resolvingDefaultScheme=!0,this.scheme=e.matches?"dark":"light",this.resolvingDefaultScheme=!1)}}static registerTexture(e,t){R(e,t)}static registeredTextures(){return L()}subscribeScoped(e,t){return T(this,e,t)}get scheme(){return this.schemeBacker}set scheme(e){const t=e==="dark"?"dark":e==="light"?"light":"",s=this.schemeBacker,h=this.schemeExplicitlySet;this.resolvingDefaultScheme||(this.schemeExplicitlySet=t.length>0);const o=t||this.resolveDefaultScheme();h!==this.schemeExplicitlySet&&this.isConnected&&this.syncSystemSchemeListener(),o!==s&&(this.schemeBacker=o,this.requestUpdate("scheme",s),this.themeEventsReady&&p().publish("scheme-changed",{scheme:o,correlationId:this.correlationId}))}get seedColor(){return this.activeTheme.seedColor}static extractFamily(e){if(!e)return"";const t=e.match(/^"([^"]+)"|^'([^']+)'/);return t&&(t[1]||t[2])||""}injectGoogleFontLink(e,t,s){const h="data-esp-font",o=`${this.correlationId}-${e}`,r=document.head.querySelector(`link[${h}="${o}"]`);if(this.googleFontLoading==="none"){r?.remove();return}if(r&&t&&r.dataset.espFamily===t&&r.dataset.espWeight===(s??"")||(r?.remove(),!t))return;const d=encodeURIComponent(t),u=s==="bold"?"700":s==="normal"?"400":s,S=u&&u!=="400"?`:wght@${u}`:"",m=document.createElement("link");m.rel="stylesheet",m.href=`https://fonts.googleapis.com/css2?family=${d}${S}&display=swap`,m.setAttribute(h,o),m.dataset.espFamily=t,m.dataset.espWeight=s??"",document.head.appendChild(m)}syncGoogleFontLinks(){this.googleFontLoading==="none"&&this.removeRuntimeGoogleFontLinks();const e=this.activeTheme;this.injectGoogleFontLink("body",n.extractFamily(e.fontBody),e.fontWeightBody),this.injectGoogleFontLink("headings",n.extractFamily(e.fontHeadings),e.fontWeightHeadings),this.injectGoogleFontLink("brand",n.extractFamily(e.fontBrand),e.fontWeightBrand),this.injectGoogleFontLink("monospace",n.extractFamily(e.fontMonospace),e.fontWeightMonospace)}removeRuntimeGoogleFontLinks(){for(const e of document.head.querySelectorAll(`link[data-esp-font^="${this.correlationId}-"]`))e.remove();for(const e of document.head.querySelectorAll(`link[data-esp-font-picker-root="${CSS.escape(this.correlationId)}"]`))e.remove()}get activeTheme(){return this.scheme==="dark"?this.resolvedDarkTheme:this.resolvedLightTheme}resolveThemes(){const e=this.lightThemeAttr?y(this.lightThemeAttr):null;this.resolvedLightTheme=e?v(g,e):{...g};const t=this.darkThemeAttr?y(this.darkThemeAttr):null;this.resolvedDarkTheme=t?v(f,t):{...f}}connectedCallback(){super.connectedCallback(),this.registerDocumentClickBridge(),this.resizeObserver.observe(this),this.hasUpdated&&(this.applyDefaultScheme(),this.syncGoogleFontLinks())}willUpdate(e){const t=["lightThemeAttr","darkThemeAttr"];(!this.lastSeedColor||t.some(r=>e.has(r)))&&(this.resolveThemes(),this.themeEventsReady&&p().publish("theme-changed",{correlationId:this.correlationId}));const h=x(this.activeTheme,this.scheme==="dark"?"dark":"light");for(const[r,d]of Object.entries(h))this.style.setProperty(r,d);const o=this.activeTheme.seedColor;this.themeEventsReady&&this.lastSeedColor&&this.lastSeedColor!==o&&p().publish("seed-color-changed",{seedColor:o,correlationId:this.correlationId}),this.lastSeedColor=o,this.themeEventsReady&&e.has("iconSpriteUrl")&&p().publish("icon-sprite-url-changed",{iconSpriteUrl:this.iconSpriteUrl,correlationId:this.correlationId}),this.syncGoogleFontLinks()}firstUpdated(){const e=this.activeTheme.stylesheets;if(e.length)for(const t of e){const s=document.createElement("link");s.rel="stylesheet",s.href=t,document.head.appendChild(s)}if(!document.getElementById("esp-root-base-styles")){const t=document.createElement("style");t.id="esp-root-base-styles",t.textContent=n.lightDomStyles,document.head.appendChild(t)}this.applyDefaultScheme(),this.lastSeedColor=this.activeTheme.seedColor,this.themeEventsReady=!0}updated(e){(e.has("defaultScheme")||e.has("scheme"))&&!this.schemeExplicitlySet&&this.applyDefaultScheme()}disconnectedCallback(){this.unregisterDocumentClickBridge(),this.systemSchemeQuery?.removeEventListener("change",this.handleSystemSchemeChange),this.systemSchemeQuery=null,this.resizeObserver.disconnect(),this.removeRuntimeGoogleFontLinks(),super.disconnectedCallback()}registerDocumentClickBridge(){this.documentClickRegistrationActive||(this.documentClickRegistrationActive=!0,n.connectedRootCount+=1,n.connectedRootCount===1&&document.addEventListener("click",n.handleDocumentClick))}unregisterDocumentClickBridge(){this.documentClickRegistrationActive&&(this.documentClickRegistrationActive=!1,n.connectedRootCount=Math.max(0,n.connectedRootCount-1),n.connectedRootCount===0&&document.removeEventListener("click",n.handleDocumentClick))}applyDefaultScheme(){this.schemeExplicitlySet||(this.resolvingDefaultScheme=!0,this.scheme=this.resolveDefaultScheme(),this.resolvingDefaultScheme=!1,this.syncSystemSchemeListener())}resolveDefaultScheme(){return this.defaultScheme==="dark"||this.defaultScheme==="system"&&window.matchMedia?.("(prefers-color-scheme: dark)").matches?"dark":"light"}syncSystemSchemeListener(){if(this.schemeExplicitlySet||this.defaultScheme!=="system"||!window.matchMedia){this.systemSchemeQuery?.removeEventListener("change",this.handleSystemSchemeChange),this.systemSchemeQuery=null;return}this.systemSchemeQuery||(this.systemSchemeQuery=window.matchMedia("(prefers-color-scheme: dark)"),this.systemSchemeQuery.addEventListener("change",this.handleSystemSchemeChange))}render(){return b`<slot></slot>`}};i.connectedRootCount=0,i.handleDocumentClick=c=>{const e=c.composedPath().filter(t=>t instanceof HTMLElement&&t.tagName==="ESP-POPOVER");p().publish("close-popovers",{source:c.target??void 0,skipPopovers:e})},i.lightDomStyles=`
1
+ var a=function(d,e,t,o){var l=arguments.length,s=l<3?e:o===null?o=Object.getOwnPropertyDescriptor(e,t):o,r;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(d,e,t,o);else for(var n=d.length-1;n>=0;n--)(r=d[n])&&(s=(l<3?r(s):l>3?r(e,t,s):r(e,t))||s);return l>3&&s&&Object.defineProperty(e,t,s),s},h;import{css as k,html as b,LitElement as C}from"lit";import{customElement as E,property as c}from"lit/decorators.js";import{getEspBus as p}from"../shared/bus-events.js";import{subscribeToRootEvent as T}from"../shared/root-event-subscription.js";import{DEFAULT_LIGHT_THEME as g,DEFAULT_DARK_THEME as f,parseTheme as y,mergeTheme as v}from"../shared/theme.js";import{computeThemeProperties as x}from"./helpers/compute-theme-properties.js";import{registerImageTexture as R,registeredImageTextures as D}from"../shared/image-texture-registry.js";import{registerImageTexture as W,registeredImageTextures as _,BUILT_IN_IMAGE_TEXTURES as H}from"../shared/image-texture-registry.js";let i=h=class extends C{constructor(){super(...arguments),this.schemeBacker="",this.schemeExplicitlySet=!1,this.resolvingDefaultScheme=!1,this.themeEventsReady=!1,this.systemSchemeQuery=null,this.lastSeedColor="",this.resolvedLightTheme={...g},this.resolvedDarkTheme={...f},this.appliedDataRampProperties=new Set,this.documentClickRegistrationActive=!1,this.correlationId=globalThis.crypto?.randomUUID?.()??Math.random().toString(36),this.lightThemeAttr="",this.darkThemeAttr="",this.fontCSSRoot="/css/fonts/",this.fontDefinitionsUrl="",this.googleFontLoading="auto",this.iconSpriteUrl="/assets/icons.svg",this.defaultScheme="light",this.resizeObserver=new ResizeObserver(()=>{p().publish("window-resized",{emWidth:window.innerWidth/parseFloat(getComputedStyle(document.documentElement).fontSize),emHeight:window.innerHeight/parseFloat(getComputedStyle(document.documentElement).fontSize),pxWidth:window.innerWidth,pxHeight:window.innerHeight})}),this.handleSystemSchemeChange=e=>{this.schemeExplicitlySet||this.defaultScheme!=="system"||(this.resolvingDefaultScheme=!0,this.scheme=e.matches?"dark":"light",this.resolvingDefaultScheme=!1)}}static registerTexture(e,t){R(e,t)}static registeredTextures(){return D()}subscribeScoped(e,t){return T(this,e,t)}get scheme(){return this.schemeBacker}set scheme(e){const t=e==="dark"?"dark":e==="light"?"light":"",o=this.schemeBacker,l=this.schemeExplicitlySet;this.resolvingDefaultScheme||(this.schemeExplicitlySet=t.length>0);const s=t||this.resolveDefaultScheme();l!==this.schemeExplicitlySet&&this.isConnected&&this.syncSystemSchemeListener(),s!==o&&(this.schemeBacker=s,this.requestUpdate("scheme",o),this.themeEventsReady&&p().publish("scheme-changed",{scheme:s,correlationId:this.correlationId}))}get seedColor(){return this.activeTheme.seedColor}static extractFamily(e){if(!e)return"";const t=e.match(/^"([^"]+)"|^'([^']+)'/);return t&&(t[1]||t[2])||""}injectGoogleFontLink(e,t,o){const l="data-esp-font",s=`${this.correlationId}-${e}`,r=document.head.querySelector(`link[${l}="${s}"]`);if(this.googleFontLoading==="none"){r?.remove();return}if(r&&t&&r.dataset.espFamily===t&&r.dataset.espWeight===(o??"")||(r?.remove(),!t))return;const n=encodeURIComponent(t),u=o==="bold"?"700":o==="normal"?"400":o,S=u&&u!=="400"?`:wght@${u}`:"",m=document.createElement("link");m.rel="stylesheet",m.href=`https://fonts.googleapis.com/css2?family=${n}${S}&display=swap`,m.setAttribute(l,s),m.dataset.espFamily=t,m.dataset.espWeight=o??"",document.head.appendChild(m)}syncGoogleFontLinks(){this.googleFontLoading==="none"&&this.removeRuntimeGoogleFontLinks();const e=this.activeTheme;this.injectGoogleFontLink("body",h.extractFamily(e.fontBody),e.fontWeightBody),this.injectGoogleFontLink("headings",h.extractFamily(e.fontHeadings),e.fontWeightHeadings),this.injectGoogleFontLink("brand",h.extractFamily(e.fontBrand),e.fontWeightBrand),this.injectGoogleFontLink("monospace",h.extractFamily(e.fontMonospace),e.fontWeightMonospace)}removeRuntimeGoogleFontLinks(){for(const e of document.head.querySelectorAll(`link[data-esp-font^="${this.correlationId}-"]`))e.remove();for(const e of document.head.querySelectorAll(`link[data-esp-font-picker-root="${CSS.escape(this.correlationId)}"]`))e.remove()}get activeTheme(){return this.scheme==="dark"?this.resolvedDarkTheme:this.resolvedLightTheme}resolveThemes(){const e=this.lightThemeAttr?y(this.lightThemeAttr):null;this.resolvedLightTheme=e?v(g,e):{...g};const t=this.darkThemeAttr?y(this.darkThemeAttr):null;this.resolvedDarkTheme=t?v(f,t):{...f}}connectedCallback(){super.connectedCallback(),this.registerDocumentClickBridge(),this.resizeObserver.observe(this),this.hasUpdated&&(this.applyDefaultScheme(),this.syncGoogleFontLinks())}willUpdate(e){const t=["lightThemeAttr","darkThemeAttr"];(!this.lastSeedColor||t.some(n=>e.has(n)))&&(this.resolveThemes(),this.themeEventsReady&&p().publish("theme-changed",{correlationId:this.correlationId}));const l=x(this.activeTheme,this.scheme==="dark"?"dark":"light"),s=new Set(Object.keys(l).filter(n=>n.startsWith("--esp-color-ramp-")));for(const n of this.appliedDataRampProperties)s.has(n)||this.style.removeProperty(n);for(const[n,u]of Object.entries(l))this.style.setProperty(n,u);this.appliedDataRampProperties=s;const r=this.activeTheme.seedColor;this.themeEventsReady&&this.lastSeedColor&&this.lastSeedColor!==r&&p().publish("seed-color-changed",{seedColor:r,correlationId:this.correlationId}),this.lastSeedColor=r,this.themeEventsReady&&e.has("iconSpriteUrl")&&p().publish("icon-sprite-url-changed",{iconSpriteUrl:this.iconSpriteUrl,correlationId:this.correlationId}),this.syncGoogleFontLinks()}firstUpdated(){const e=this.activeTheme.stylesheets;if(e.length)for(const t of e){const o=document.createElement("link");o.rel="stylesheet",o.href=t,document.head.appendChild(o)}if(!document.getElementById("esp-root-base-styles")){const t=document.createElement("style");t.id="esp-root-base-styles",t.textContent=h.lightDomStyles,document.head.appendChild(t)}this.applyDefaultScheme(),this.lastSeedColor=this.activeTheme.seedColor,this.themeEventsReady=!0}updated(e){(e.has("defaultScheme")||e.has("scheme"))&&!this.schemeExplicitlySet&&this.applyDefaultScheme()}disconnectedCallback(){this.unregisterDocumentClickBridge(),this.systemSchemeQuery?.removeEventListener("change",this.handleSystemSchemeChange),this.systemSchemeQuery=null,this.resizeObserver.disconnect(),this.removeRuntimeGoogleFontLinks(),super.disconnectedCallback()}registerDocumentClickBridge(){this.documentClickRegistrationActive||(this.documentClickRegistrationActive=!0,h.connectedRootCount+=1,h.connectedRootCount===1&&document.addEventListener("click",h.handleDocumentClick))}unregisterDocumentClickBridge(){this.documentClickRegistrationActive&&(this.documentClickRegistrationActive=!1,h.connectedRootCount=Math.max(0,h.connectedRootCount-1),h.connectedRootCount===0&&document.removeEventListener("click",h.handleDocumentClick))}applyDefaultScheme(){this.schemeExplicitlySet||(this.resolvingDefaultScheme=!0,this.scheme=this.resolveDefaultScheme(),this.resolvingDefaultScheme=!1,this.syncSystemSchemeListener())}resolveDefaultScheme(){return this.defaultScheme==="dark"||this.defaultScheme==="system"&&window.matchMedia?.("(prefers-color-scheme: dark)").matches?"dark":"light"}syncSystemSchemeListener(){if(this.schemeExplicitlySet||this.defaultScheme!=="system"||!window.matchMedia){this.systemSchemeQuery?.removeEventListener("change",this.handleSystemSchemeChange),this.systemSchemeQuery=null;return}this.systemSchemeQuery||(this.systemSchemeQuery=window.matchMedia("(prefers-color-scheme: dark)"),this.systemSchemeQuery.addEventListener("change",this.handleSystemSchemeChange))}render(){return b`<slot></slot>`}};i.connectedRootCount=0,i.handleDocumentClick=d=>{const e=d.composedPath().filter(t=>t instanceof HTMLElement&&t.tagName==="ESP-POPOVER");p().publish("close-popovers",{source:d.target??void 0,skipPopovers:e})},i.lightDomStyles=`
2
2
 
3
3
  esp-root {
4
4
  font-family: var(--esp-font-body);
@@ -125,4 +125,4 @@ var l=function(c,e,t,s){var h=arguments.length,o=h<3?e:s===null?s=Object.getOwnP
125
125
  :host {
126
126
  display: block;
127
127
  }
128
- `,l([a({attribute:!1})],i.prototype,"correlationId",void 0),l([a({attribute:"light-theme"})],i.prototype,"lightThemeAttr",void 0),l([a({attribute:"dark-theme"})],i.prototype,"darkThemeAttr",void 0),l([a({attribute:"font-css-root",type:String})],i.prototype,"fontCSSRoot",void 0),l([a({attribute:"font-definitions-url",type:String})],i.prototype,"fontDefinitionsUrl",void 0),l([a({attribute:"google-font-loading",type:String})],i.prototype,"googleFontLoading",void 0),l([a({attribute:"icon-sprite-url",type:String})],i.prototype,"iconSpriteUrl",void 0),l([a({attribute:"default-scheme",type:String,reflect:!0})],i.prototype,"defaultScheme",void 0),l([a({attribute:"scheme",type:String,reflect:!0})],i.prototype,"scheme",null),i=n=l([E("esp-root")],i);export{P as BUILT_IN_IMAGE_TEXTURES,i as EspalierRoot,H as registerImageTexture,M as registeredImageTextures};
128
+ `,a([c({attribute:!1})],i.prototype,"correlationId",void 0),a([c({attribute:"light-theme"})],i.prototype,"lightThemeAttr",void 0),a([c({attribute:"dark-theme"})],i.prototype,"darkThemeAttr",void 0),a([c({attribute:"font-css-root",type:String})],i.prototype,"fontCSSRoot",void 0),a([c({attribute:"font-definitions-url",type:String})],i.prototype,"fontDefinitionsUrl",void 0),a([c({attribute:"google-font-loading",type:String})],i.prototype,"googleFontLoading",void 0),a([c({attribute:"icon-sprite-url",type:String})],i.prototype,"iconSpriteUrl",void 0),a([c({attribute:"default-scheme",type:String,reflect:!0})],i.prototype,"defaultScheme",void 0),a([c({attribute:"scheme",type:String,reflect:!0})],i.prototype,"scheme",null),i=h=a([E("esp-root")],i);export{H as BUILT_IN_IMAGE_TEXTURES,i as EspalierRoot,W as registerImageTexture,_ as registeredImageTextures};
@@ -0,0 +1 @@
1
+ import{deriveSemantic as C,deriveSemanticWithContrast as M,serializeOklch as d}from"../../shared/color-engine.js";import{SEMANTIC_COLOR_NAMES as v,TOKEN_PAIRINGS as S,semanticToCSS as R}from"../../shared/theme.js";import{resolveMappingSource as k}from"./compute-variants.js";function x(r,m,t={}){const i={},u={},p=(o,e)=>{const c=t.effectiveSource?.(o,e)??e,s=k(c,m,r.anchors);return s||t.onUnresolvedSource?.(c),{color:s??m.primary,resolved:s!==null,source:c}};for(const o of v){if(S[o])continue;const e=r.semanticMappings[o],c=r.chroma[o],s=p(o,e.source),n=r.lightness[e.lightness],l=C(s.color,n,c.min,c.max),a=R(o);u[o]=l,i[a]=d(l),t.trace&&t.trace.push({token:o,property:a,resolved:i[a],source:s.source,lightness:e.lightness,sourceResolved:s.resolved,base:s.color})}for(const o of v){const e=S[o];if(!e)continue;const c=r.semanticMappings[o],s=r.chroma[o],n=p(o,c.source),l=r.lightness[c.lightness],a=u[e.bg];let f;const h=M(n.color,l,s.min,s.max,a,e.targetLc,t.trace&&(b=>{f=b})),g=R(o);u[o]=h,i[g]=d(h),t.trace&&t.trace.push({token:o,property:g,resolved:i[g],source:n.source,lightness:c.lightness,sourceResolved:n.resolved,base:n.color,requested:f,contrast:{against:e.bg,background:a,targetLc:e.targetLc}})}return i}export{x as computeSemanticProperties};
@@ -1 +1 @@
1
- import{parseCssColor as I,serializeOklch as b,gamutMapToSRGB as M,deriveSemantic as O,deriveSemanticWithContrast as R}from"../../shared/color-engine.js";import{generateScaleProperties as x}from"../../shared/scale-engine.js";import{SEMANTIC_COLOR_NAMES as B,LIGHTNESS_KEYS as w,TOKEN_PAIRINGS as T,semanticToCSS as u}from"../../shared/theme.js";import{lightnessKeyToCSS as E}from"./lightness-key-to-css.js";import{computeVariants as L,resolveMappingSource as N}from"./compute-variants.js";function W(o){return{rootFontSize:o.rootFontSize,typeRatio:o.typeRatio,spaceRatio:o.spaceRatio,borderRadius:o.borderRadius,viewportMin:o.viewportMin,viewportMax:o.viewportMax}}function K(o,C,e){const v=I(o.seedColor);if(!v)return{};const n={};n["--esp-scheme"]=C,n["--esp-seed-color"]=o.seedColor;const f=L(v,o);for(const[a,s]of Object.entries(f))n[`--esp-color-${a}`]=b(M(s));for(const a of w)n[E(a)]=`${Math.round(o.lightness[a]*100)}%`;const m=T,c=new Set,k=a=>{const s=N(a,f,o.anchors);return s||(c.has(a)||(c.add(a),console.warn(`Espalier theme: color source "${a}" cannot be resolved \u2014 falling back to the seed. Run validateTheme for the declared anchors.`)),f.primary)},l={};for(const a of B){if(m[a])continue;const s=o.semanticMappings[a],r=o.chroma[a],i=k(s.source),g=o.lightness[s.lightness],p=O(i,g,r.min,r.max);if(l[a]=p,n[u(a)]=b(p),e){const t=u(a);e.push({token:a,property:t,resolved:n[t],source:s.source,lightness:s.lightness,sourceResolved:!c.has(s.source),base:i})}}for(const a of B){const s=m[a];if(!s)continue;const r=o.semanticMappings[a],i=o.chroma[a],g=k(r.source),p=o.lightness[r.lightness],t=l[s.bg];let y;const S=R(g,p,i.min,i.max,t,s.targetLc,e&&(d=>{y=d}));if(l[a]=S,n[u(a)]=b(S),e){const d=u(a);e.push({token:a,property:d,resolved:n[d],source:r.source,lightness:r.lightness,sourceResolved:!c.has(r.source),base:g,requested:y,contrast:{against:s.bg,background:t,targetLc:s.targetLc}})}}return Object.assign(n,x(W(o))),o.fontBody&&(n["--esp-font-body"]=o.fontBody),o.fontHeadings&&(n["--esp-font-headings"]=o.fontHeadings),o.fontBrand&&(n["--esp-font-brand"]=o.fontBrand),o.fontMonospace&&(n["--esp-font-monospace"]=o.fontMonospace),n["--esp-font-weight-body"]=o.fontWeightBody,n["--esp-font-weight-headings"]=o.fontWeightHeadings,n["--esp-font-weight-brand"]=o.fontWeightBrand,n["--esp-font-weight-monospace"]=o.fontWeightMonospace,o.pageBackgroundImage&&(n["--esp-page-background-image"]=o.pageBackgroundImage),o.pageBackgroundImageOpacity!==void 0&&(n["--esp-page-background-image-opacity"]=o.pageBackgroundImageOpacity.toString()),o.boxBackgroundImage&&(n["--esp-box-background-image"]=o.boxBackgroundImage),o.boxBackgroundImageOpacity!==void 0&&(n["--esp-box-background-image-opacity"]=o.boxBackgroundImageOpacity.toString()),o.vellumOpacity!==void 0&&(n["--esp-vellum-opacity"]=o.vellumOpacity.toString()),o.vellumBackgroundImage&&(n["--esp-vellum-background-image"]=o.vellumBackgroundImage),o.vellumBackgroundImageOpacity!==void 0&&(n["--esp-vellum-background-image-opacity"]=o.vellumBackgroundImageOpacity.toString()),n}export{K as computeThemeProperties};
1
+ import{parseCssColor as g,serializeOklch as l,gamutMapToSRGB as f}from"../../shared/color-engine.js";import{generateScaleProperties as k}from"../../shared/scale-engine.js";import{DATA_SERIES_KEYS as u,DEFAULT_DATA_PALETTE as v,generateDivergingRamp as B,generateSequentialRamp as R}from"../../shared/data-colors.js";import{LIGHTNESS_KEYS as w,resolveDataColorSource as E}from"../../shared/theme.js";import{lightnessKeyToCSS as $}from"./lightness-key-to-css.js";import{computeVariants as I}from"./compute-variants.js";import{computeSemanticProperties as O}from"./compute-semantic-properties.js";function T(o){return{rootFontSize:o.rootFontSize,typeRatio:o.typeRatio,spaceRatio:o.spaceRatio,borderRadius:o.borderRadius,viewportMin:o.viewportMin,viewportMax:o.viewportMax}}function j(o,S,b){const i=g(o.seedColor);if(!i)return{};const e={};e["--esp-scheme"]=S,e["--esp-seed-color"]=o.seedColor;const c=I(i,o);for(const[a,n]of Object.entries(c))e[`--esp-color-${a}`]=l(f(n));const d=new Set,t=(a,n)=>{const r=typeof a=="string"?E(a,o.anchors):null;if(r)return r;const s=typeof a=="string"?a:String(a);return d.has(s)||(d.add(s),console.warn(`Espalier theme: ${n} color source "${s}" cannot be resolved \u2014 falling back to the seed. Run validateTheme for the declared data colors.`)),o.seedColor},m=o.dataPalette??v;for(let a=0;a<u.length;a+=1){const n=u[a],r=g(t(m[n],`dataPalette.${n}`))??i;e[`--esp-color-series-${a+1}`]=l(f(r))}for(const[a,n]of Object.entries(o.dataRamps??{}))try{(n.type==="sequential"?R(t(n.source,`dataRamps.${a}.source`),{steps:n.steps,lightnessStart:n.lightnessStart,lightnessEnd:n.lightnessEnd}):B(t(n.start,`dataRamps.${a}.start`),t(n.end,`dataRamps.${a}.end`),{steps:n.steps,neutral:n.neutral===void 0?void 0:t(n.neutral,`dataRamps.${a}.neutral`)})).forEach((s,y)=>{e[`--esp-color-ramp-${a}-${y+1}`]=s})}catch(r){console.warn(`Espalier theme: dataRamps.${a} cannot be generated \u2014 ${r instanceof Error?r.message:String(r)}`)}for(const a of w)e[$(a)]=`${Math.round(o.lightness[a]*100)}%`;const p=new Set;return Object.assign(e,O(o,c,{trace:b,onUnresolvedSource:a=>{p.has(a)||(p.add(a),console.warn(`Espalier theme: color source "${a}" cannot be resolved \u2014 falling back to the seed. Run validateTheme for the declared anchors.`))}})),Object.assign(e,k(T(o))),o.fontBody&&(e["--esp-font-body"]=o.fontBody),o.fontHeadings&&(e["--esp-font-headings"]=o.fontHeadings),o.fontBrand&&(e["--esp-font-brand"]=o.fontBrand),o.fontMonospace&&(e["--esp-font-monospace"]=o.fontMonospace),e["--esp-font-weight-body"]=o.fontWeightBody,e["--esp-font-weight-headings"]=o.fontWeightHeadings,e["--esp-font-weight-brand"]=o.fontWeightBrand,e["--esp-font-weight-monospace"]=o.fontWeightMonospace,o.pageBackgroundImage&&(e["--esp-page-background-image"]=o.pageBackgroundImage),o.pageBackgroundImageOpacity!==void 0&&(e["--esp-page-background-image-opacity"]=o.pageBackgroundImageOpacity.toString()),o.boxBackgroundImage&&(e["--esp-box-background-image"]=o.boxBackgroundImage),o.boxBackgroundImageOpacity!==void 0&&(e["--esp-box-background-image-opacity"]=o.boxBackgroundImageOpacity.toString()),o.vellumOpacity!==void 0&&(e["--esp-vellum-opacity"]=o.vellumOpacity.toString()),o.vellumBackgroundImage&&(e["--esp-vellum-background-image"]=o.vellumBackgroundImage),o.vellumBackgroundImageOpacity!==void 0&&(e["--esp-vellum-background-image-opacity"]=o.vellumBackgroundImageOpacity.toString()),e}export{j as computeThemeProperties};
@@ -1 +1 @@
1
- const S=Math.PI/180,h=1e-4,X=50,m="[+-]?(?:\\d+|\\d*\\.\\d+)(?:[eE][+-]?\\d+)?",i="[\\t\\n\\f\\r ]",y=new RegExp(i+"*,"+i+"*"),H=new RegExp(i+"+");function G(t){return t.replace(/\/\*[\s\S]*?(?:\*\/|$)/g," ").replace(/^[\t\n\f\r ]+|[\t\n\f\r ]+$/g,"")}const b={"":1,deg:1,grad:.9,rad:180/Math.PI,turn:360},U=.4,V=new RegExp("^oklch\\("+i+"*("+m+")(%?)"+i+"+("+m+")(%?)"+i+"+("+m+")(deg|grad|rad|turn)?"+i+"*\\)$","i");function x(t){const n=t.h*S;return{L:t.l,a:t.c*Math.cos(n),b:t.c*Math.sin(n)}}function W(t){const n=t.L+.3963377774*t.a+.2158037573*t.b,r=t.L-.1055613458*t.a-.0638541728*t.b,e=t.L-.0894841775*t.a-1.291485548*t.b,o=n*n*n,c=r*r*r,u=e*e*e;return{r:4.0767416621*o-3.3077115913*c+.2309699292*u,g:-1.2684380046*o+2.6097574011*c-.3413193965*u,b:-.0041960863*o-.7034186147*c+1.707614701*u}}function A(t){return t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055}function z(t){return{r:A(t.r),g:A(t.g),b:A(t.b)}}function Y(t){return t.r>=-h&&t.r<=1+h&&t.g>=-h&&t.g<=1+h&&t.b>=-h&&t.b<=1+h}function g(t){return Math.max(0,Math.min(1,t))}function q(t){const n=G(t).match(V);if(!n)return null;let r=parseFloat(n[1]);n[2]==="%"&&(r/=100);let e=parseFloat(n[3]);n[4]==="%"&&(e=e/100*U);const o=parseFloat(n[5])*b[(n[6]??"").toLowerCase()];return!isFinite(r)||!isFinite(e)||!isFinite(o)?null:{l:Math.max(0,Math.min(1,r)),c:Math.max(0,e),h:(o%360+360)%360}}function ut(t){const n=p(t.l,6),r=p(t.c,6),e=p((t.h%360+360)%360,4);return`oklch(${n} ${r} ${e})`}function _(t){return z(W(x(t)))}function T(t){return Y(_(t))}function M(t){if(t.c<=h||T(t))return{...t};let n=0,r=t.c,e={...t};for(let o=0;o<X;o++){const c=(n+r)/2;if(e={l:t.l,c,h:t.h},T(e)?n=c:r=c,r-n<h)break}return{l:t.l,c:n,h:t.h}}function K(t,n,r){const e={l:t.l,c:Math.max(n,Math.min(r,t.c)),h:t.h};return M(e)}const C=.022,O=.012,w=.022,k=.57,B=.56,P=1.14,d=.001,R=.027;function I(t){const n=Math.pow(g(t.r),2.4),r=Math.pow(g(t.g),2.4),e=Math.pow(g(t.b),2.4);return .2126729*n+.7151522*r+.072175*e}function F(t,n){const r=_(M(t)),e=_(M(n));let o=I(r),c=I(e);if(o=o>C?o:o+Math.pow(C-o,1.414),c=c>C?c:c+Math.pow(C-c,1.414),Math.abs(c-o)<d)return 0;let u;if(c>o){const s=Math.pow(c,B),a=Math.pow(o,k);if(u=(s-a)*P,u<d)return 0;u=u<R?u-u*w*R:u-w}else{const s=Math.pow(c,B),a=Math.pow(o,k);if(u=(s-a)*P,u>-d)return 0;u=u>-R?u-u*O*R:u+O}return u*100}function j(t,n,r=60){let e=M({...t}),o=Math.abs(F(e,n));if(o>=r)return e;const c=n.l>.5,u=.01,s=c?0:1;for(let a=0;a<100;a++){if(c?e.l=Math.max(s,e.l-u):e.l=Math.min(s,e.l+u),e=M(e),o=Math.abs(F(e,n)),o>=r)return e;if(e.l<=0||e.l>=1)break}return e}function st(t,n){return((t+n)%360+360)%360}function at(t,n){const r=x(t),e=x(n),o=r.L-e.L,c=r.a-e.a,u=r.b-e.b;return Math.sqrt(o*o+c*c+u*u)}function J(t,n,r,e){return K({l:n,c:t.c,h:t.h},r,e)}function it(t,n,r,e,o,c=60,u){const s=J(t,n,r,e);return u?.(s),j(s,o,c)}function E(t){return t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function Q(t){const n=E(t.r),r=E(t.g),e=E(t.b),o=Math.cbrt(.4122214708*n+.5363325363*r+.0514459929*e),c=Math.cbrt(.2119034982*n+.6806995451*r+.1073969566*e),u=Math.cbrt(.0883024619*n+.2817188376*r+.6299787005*e);return{L:.2104542553*o+.793617785*c-.0040720468*u,a:1.9779984951*o-2.428592205*c+.4505937099*u,b:.0259040371*o+.7827717662*c-.808675766*u}}function Z(t){const n=Math.sqrt(t.a*t.a+t.b*t.b),r=(Math.atan2(t.b,t.a)/S%360+360)%360;return{l:t.L,c:n,h:r}}function tt(t){const n=p(t.c,4);return{l:p(t.l,3),c:n,h:n===0?0:p(t.h,1)}}function f(t){return Math.round(g(t)*255)}function L(t){const n=Z(Q(t)),r=t.r===t.g&&t.g===t.b?{l:n.l,c:0,h:0}:n,e=tt(r);if(T(e)){const o=_(e);if(f(o.r)===f(t.r)&&f(o.g)===f(t.g)&&f(o.b)===f(t.b))return e}return r}function nt(t){const n=t.slice(1);if(!/^[0-9a-f]+$/i.test(n))return null;if(n.length===3){const[r,e,o]=n.split("").map(c=>parseInt(c+c,16));return{r:r/255,g:e/255,b:o/255}}return n.length===6?{r:parseInt(n.slice(0,2),16)/255,g:parseInt(n.slice(2,4),16)/255,b:parseInt(n.slice(4,6),16)/255}:null}function D(t,n){const r=t.match(new RegExp("^"+n+"\\("+i+"*([^)]*?)"+i+"*\\)$","i"));if(!r)return null;const e=r[1];if(e.includes("/"))return null;const o=e.includes(","),c=e.split(o?y:H);return c.length!==3||c.some(u=>u.length===0)?null:{args:c,legacy:o}}const rt=new RegExp("^("+m+")([a-z%]*)$","i");function N(t){const n=t.match(rt);if(!n)return null;const r=parseFloat(n[1]);return isFinite(r)?{value:r,unit:n[2].toLowerCase()}:null}function et(t){if(t.unit!==""&&t.unit!=="%")return null;const n=t.unit==="%"?t.value/100:t.value/255;return Math.max(0,Math.min(1,n))}function ot(t){const n=b[t.unit];return n===void 0?null:t.value*n}function v(t){return t.unit!==""&&t.unit!=="%"?null:Math.max(0,Math.min(1,t.value/100))}function ct(t,n,r){const e=(t%360+360)%360,o=c=>{const u=(c+e/30)%12,s=n*Math.min(r,1-r);return r-s*Math.max(-1,Math.min(u-3,9-u,1))};return{r:o(0),g:o(8),b:o(4)}}const lt='"#rrggbb", "#rgb", "rgb(\u2026)", "hsl(\u2026)", "oklch(\u2026)"';function ht(t){const n=G(t);if(n.startsWith("#")){const r=nt(n);return r?L(r):null}if(/^oklch\(/i.test(n))return q(n);if(/^rgba?\(/i.test(n)){const r=D(n,"rgba?");if(!r)return null;const e=r.args.map(N);if(e.some(l=>l===null))return null;const o=e;if(r.legacy&&new Set(o.map(l=>l.unit)).size>1)return null;const c=o.map(et);if(c.some(l=>l===null))return null;const[u,s,a]=c;return L({r:u,g:s,b:a})}if(/^hsla?\(/i.test(n)){const r=D(n,"hsla?");if(!r)return null;const e=r.args.map(N);if(e.some($=>$===null))return null;const[o,c,u]=e;if(r.legacy&&(c.unit!=="%"||u.unit!=="%"))return null;const s=ot(o),a=v(c),l=v(u);return s===null||a===null||l===null?null:L(ct(s,a,l))}return null}function p(t,n){const r=Math.pow(10,n);return Math.round(t*r)/r}export{lt as ACCEPTED_COLOR_FORMS,F as apcaContrast,K as clampChromaAndGamutMap,at as deltaEOK,J as deriveSemantic,it as deriveSemanticWithContrast,j as ensureContrast,M as gamutMapToSRGB,T as isInSRGBGamut,_ as oklchToSRGB,ht as parseCssColor,q as parseOklch,st as rotateHue,ut as serializeOklch};
1
+ const G=Math.PI/180,h=1e-4,X=50,m="[+-]?(?:\\d+|\\d*\\.\\d+)(?:[eE][+-]?\\d+)?",i="[\\t\\n\\f\\r ]",y=new RegExp(i+"*,"+i+"*"),H=new RegExp(i+"+");function S(t){return t.replace(/\/\*[\s\S]*?(?:\*\/|$)/g," ").replace(/^[\t\n\f\r ]+|[\t\n\f\r ]+$/g,"")}const b={"":1,deg:1,grad:.9,rad:180/Math.PI,turn:360},U=.4,V=new RegExp("^oklch\\("+i+"*("+m+")(%?)"+i+"+("+m+")(%?)"+i+"+("+m+")(deg|grad|rad|turn)?"+i+"*\\)$","i");function T(t){const n=t.h*G;return{L:t.l,a:t.c*Math.cos(n),b:t.c*Math.sin(n)}}function W(t){const n=t.L+.3963377774*t.a+.2158037573*t.b,r=t.L-.1055613458*t.a-.0638541728*t.b,e=t.L-.0894841775*t.a-1.291485548*t.b,o=n*n*n,u=r*r*r,c=e*e*e;return{r:4.0767416621*o-3.3077115913*u+.2309699292*c,g:-1.2684380046*o+2.6097574011*u-.3413193965*c,b:-.0041960863*o-.7034186147*u+1.707614701*c}}function C(t){return t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055}function z(t){return{r:C(t.r),g:C(t.g),b:C(t.b)}}function Y(t){return t.r>=-h&&t.r<=1+h&&t.g>=-h&&t.g<=1+h&&t.b>=-h&&t.b<=1+h}function x(t){return Math.max(0,Math.min(1,t))}function q(t){const n=S(t).match(V);if(!n)return null;let r=parseFloat(n[1]);n[2]==="%"&&(r/=100);let e=parseFloat(n[3]);n[4]==="%"&&(e=e/100*U);const o=parseFloat(n[5])*b[(n[6]??"").toLowerCase()];return!isFinite(r)||!isFinite(e)||!isFinite(o)?null:{l:Math.max(0,Math.min(1,r)),c:Math.max(0,e),h:(o%360+360)%360}}function st(t){const n=p(t.l,6),r=p(t.c,6),e=p((t.h%360+360)%360,4);return`oklch(${n} ${r} ${e})`}function g(t){return z(W(T(t)))}function A(t){return Y(g(t))}function M(t){if(t.c<=h||A(t))return{...t};let n=0,r=t.c,e={...t};for(let o=0;o<X;o++){const u=(n+r)/2;if(e={l:t.l,c:u,h:t.h},A(e)?n=u:r=u,r-n<h)break}return{l:t.l,c:n,h:t.h}}function K(t,n,r){const e={l:t.l,c:Math.max(n,Math.min(r,t.c)),h:t.h};return M(e)}const _=.022,O=.012,k=.022,w=.57,B=.56,P=1.14,d=.001,R=.027;function I(t){const n=Math.pow(x(t.r),2.4),r=Math.pow(x(t.g),2.4),e=Math.pow(x(t.b),2.4);return .2126729*n+.7151522*r+.072175*e}function F(t,n){const r=g(M(t)),e=g(M(n));let o=I(r),u=I(e);if(o=o>_?o:o+Math.pow(_-o,1.414),u=u>_?u:u+Math.pow(_-u,1.414),Math.abs(u-o)<d)return 0;let c;if(u>o){const a=Math.pow(u,B),s=Math.pow(o,w);if(c=(a-s)*P,c<d)return 0;c=c<R?c-c*k*R:c-k}else{const a=Math.pow(u,B),s=Math.pow(o,w);if(c=(a-s)*P,c>-d)return 0;c=c>-R?c-c*O*R:c+O}return c*100}function j(t,n,r=60){let e=M({...t}),o=Math.abs(F(e,n));if(o>=r)return e;const u=n.l>.5,c=.01,a=u?0:1;for(let s=0;s<100;s++){if(u?e.l=Math.max(a,e.l-c):e.l=Math.min(a,e.l+c),e=M(e),o=Math.abs(F(e,n)),o>=r)return e;if(e.l<=0||e.l>=1)break}return e}function it(t,n){return((t+n)%360+360)%360}function lt(t,n){const r=T(t),e=T(n),o=r.L-e.L,u=r.a-e.a,c=r.b-e.b;return Math.sqrt(o*o+u*u+c*c)}function J(t,n,r,e){return K({l:n,c:t.c,h:t.h},r,e)}function ht(t,n,r,e,o,u=60,c){const a=J(t,n,r,e);return c?.(a),j(a,o,u)}function E(t){return t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function Q(t){return{r:E(t.r),g:E(t.g),b:E(t.b)}}function Z({r:t,g:n,b:r}){const e=Math.cbrt(.4122214708*t+.5363325363*n+.0514459929*r),o=Math.cbrt(.2119034982*t+.6806995451*n+.1073969566*r),u=Math.cbrt(.0883024619*t+.2817188376*n+.6299787005*r);return{L:.2104542553*e+.793617785*o-.0040720468*u,a:1.9779984951*e-2.428592205*o+.4505937099*u,b:.0259040371*e+.7827717662*o-.808675766*u}}function tt(t){return Z(Q(t))}function nt(t){const n=Math.sqrt(t.a*t.a+t.b*t.b),r=n<1e-12?0:(Math.atan2(t.b,t.a)/G%360+360)%360;return{l:t.L,c:n,h:r}}function rt(t){const n=p(t.c,4);return{l:p(t.l,3),c:n,h:n===0?0:p(t.h,1)}}function f(t){return Math.round(x(t)*255)}function L(t){const n=nt(tt(t)),r=t.r===t.g&&t.g===t.b?{l:n.l,c:0,h:0}:n,e=rt(r);if(A(e)){const o=g(e);if(f(o.r)===f(t.r)&&f(o.g)===f(t.g)&&f(o.b)===f(t.b))return e}return r}function et(t){const n=t.slice(1);if(!/^[0-9a-f]+$/i.test(n))return null;if(n.length===3){const[r,e,o]=n.split("").map(u=>parseInt(u+u,16));return{r:r/255,g:e/255,b:o/255}}return n.length===6?{r:parseInt(n.slice(0,2),16)/255,g:parseInt(n.slice(2,4),16)/255,b:parseInt(n.slice(4,6),16)/255}:null}function D(t,n){const r=t.match(new RegExp("^"+n+"\\("+i+"*([^)]*?)"+i+"*\\)$","i"));if(!r)return null;const e=r[1];if(e.includes("/"))return null;const o=e.includes(","),u=e.split(o?y:H);return u.length!==3||u.some(c=>c.length===0)?null:{args:u,legacy:o}}const ot=new RegExp("^("+m+")([a-z%]*)$","i");function N(t){const n=t.match(ot);if(!n)return null;const r=parseFloat(n[1]);return isFinite(r)?{value:r,unit:n[2].toLowerCase()}:null}function ut(t){if(t.unit!==""&&t.unit!=="%")return null;const n=t.unit==="%"?t.value/100:t.value/255;return Math.max(0,Math.min(1,n))}function ct(t){const n=b[t.unit];return n===void 0?null:t.value*n}function v(t){return t.unit!==""&&t.unit!=="%"?null:Math.max(0,Math.min(1,t.value/100))}function at(t,n,r){const e=(t%360+360)%360,o=u=>{const c=(u+e/30)%12,a=n*Math.min(r,1-r);return r-a*Math.max(-1,Math.min(c-3,9-c,1))};return{r:o(0),g:o(8),b:o(4)}}const ft='"#rrggbb", "#rgb", "rgb(\u2026)", "hsl(\u2026)", "oklch(\u2026)"';function pt(t){const n=S(t);if(n.startsWith("#")){const r=et(n);return r?L(r):null}if(/^oklch\(/i.test(n))return q(n);if(/^rgba?\(/i.test(n)){const r=D(n,"rgba?");if(!r)return null;const e=r.args.map(N);if(e.some(l=>l===null))return null;const o=e;if(r.legacy&&new Set(o.map(l=>l.unit)).size>1)return null;const u=o.map(ut);if(u.some(l=>l===null))return null;const[c,a,s]=u;return L({r:c,g:a,b:s})}if(/^hsla?\(/i.test(n)){const r=D(n,"hsla?");if(!r)return null;const e=r.args.map(N);if(e.some($=>$===null))return null;const[o,u,c]=e;if(r.legacy&&(u.unit!=="%"||c.unit!=="%"))return null;const a=ct(o),s=v(u),l=v(c);return a===null||s===null||l===null?null:L(at(a,s,l))}return null}function p(t,n){const r=Math.pow(10,n);return Math.round(t*r)/r}export{ft as ACCEPTED_COLOR_FORMS,F as apcaContrast,x as clampChannel,K as clampChromaAndGamutMap,lt as deltaEOK,J as deriveSemantic,ht as deriveSemanticWithContrast,j as ensureContrast,E as gammaToLinear,M as gamutMapToSRGB,A as isInSRGBGamut,Z as linearRgbToOklab,nt as oklabToOklch,T as oklchToOklab,g as oklchToSRGB,pt as parseCssColor,q as parseOklch,it as rotateHue,st as serializeOklch,Q as srgbToLinearRGB};
@@ -0,0 +1,122 @@
1
+ /**
2
+ * @module data-colors
3
+ *
4
+ * Categorical palette auditing and perceptual data-ramp generation.
5
+ *
6
+ * The theme layer resolves brand-anchor references before calling these
7
+ * helpers. The helpers themselves accept concrete CSS colors so they remain
8
+ * useful without an `EspalierTheme` instance.
9
+ */
10
+ /** Stable keys in the theme's categorical data palette. */
11
+ export declare const DATA_SERIES_KEYS: readonly ["series1", "series2", "series3", "series4", "series5", "series6", "series7", "series8"];
12
+ /** One stable slot in the categorical data palette. */
13
+ export type DataSeriesKey = (typeof DATA_SERIES_KEYS)[number];
14
+ /** Eight categorical colors, each a CSS color or theme anchor reference. */
15
+ export type DataPalette = Record<DataSeriesKey, string>;
16
+ /**
17
+ * The shipped categorical baseline: the eight-color Okabe–Ito palette.
18
+ *
19
+ * These familiar hex values are kept as the authoring contract. Theme output
20
+ * converts them to gamut-mapped OKLCH alongside consumer overrides.
21
+ */
22
+ export declare const DEFAULT_DATA_PALETTE: Readonly<DataPalette>;
23
+ /** Full color-vision-deficiency simulations used by the palette audit. */
24
+ export declare const COLOR_VISION_SIMULATIONS: readonly ["deuteranopia", "protanopia", "tritanopia"];
25
+ /** A supported full color-vision-deficiency simulation. */
26
+ export type ColorVisionSimulation = (typeof COLOR_VISION_SIMULATIONS)[number];
27
+ /**
28
+ * Minimum OKLab distance used for categorical-palette advice.
29
+ *
30
+ * This is a conservative separation heuristic, not an accessibility
31
+ * certification. The shipped Okabe–Ito palette clears it under every
32
+ * simulation; consumer failures are warnings because charts must also use
33
+ * labels, shapes, or patterns rather than color alone.
34
+ */
35
+ export declare const MIN_DATA_COLOR_DISTANCE = 0.07;
36
+ /** One pair that falls below the categorical distinguishability threshold. */
37
+ export interface DataPaletteIssue {
38
+ /** The two series slots whose simulated colors are too close. */
39
+ series: readonly [DataSeriesKey, DataSeriesKey];
40
+ /** The simulated color-vision deficiency under which they collide. */
41
+ simulation: ColorVisionSimulation;
42
+ /** Euclidean distance between the simulated colors in OKLab. */
43
+ distance: number;
44
+ /** The threshold the pair was checked against. */
45
+ threshold: number;
46
+ }
47
+ /**
48
+ * Audit every categorical pair after full CVD simulation.
49
+ *
50
+ * Palette values must be concrete CSS colors. Resolve `anchor:` references
51
+ * through the theme first. The return value is empty when every pair clears
52
+ * the threshold.
53
+ */
54
+ export declare function auditDataPalette(palette: Readonly<DataPalette>, threshold?: number): DataPaletteIssue[];
55
+ /** Minimum supported number of colors in a generated data ramp. */
56
+ export declare const MIN_DATA_RAMP_STEPS = 3;
57
+ /** Maximum supported number of colors in a generated data ramp. */
58
+ export declare const MAX_DATA_RAMP_STEPS = 11;
59
+ /** Default number of colors in a generated data ramp. */
60
+ export declare const DEFAULT_DATA_RAMP_STEPS = 7;
61
+ /** Smallest lightness separation preserved by serialized ramp output. */
62
+ export declare const MIN_DATA_RAMP_LIGHTNESS_STEP = 0.000001;
63
+ /** Default neutral midpoint for diverging ramps. */
64
+ export declare const DEFAULT_DIVERGING_NEUTRAL = "oklch(0.96 0 0)";
65
+ /** Options for a sequential, single-hue data ramp. */
66
+ export interface SequentialRampOptions {
67
+ /** Number of colors, from 3 through 11. @default 7 */
68
+ steps?: number;
69
+ /** Lightest output value. Must be greater than `lightnessEnd`. @default 0.95 */
70
+ lightnessStart?: number;
71
+ /** Darkest output value. Must be less than `lightnessStart`. @default 0.25 */
72
+ lightnessEnd?: number;
73
+ }
74
+ /** Options for a two-ended diverging data ramp. */
75
+ export interface DivergingRampOptions {
76
+ /** Odd number of colors, from 3 through 11. @default 7 */
77
+ steps?: number;
78
+ /** Concrete CSS color at the exact midpoint. @default oklch(0.96 0 0) */
79
+ neutral?: string;
80
+ }
81
+ /** A sequential ramp declaration inside a theme. */
82
+ export interface SequentialDataRamp {
83
+ type: "sequential";
84
+ /** CSS color or `anchor:<name>[.<slot>]` source. */
85
+ source: string;
86
+ steps?: number;
87
+ lightnessStart?: number;
88
+ lightnessEnd?: number;
89
+ }
90
+ /** A diverging ramp declaration inside a theme. */
91
+ export interface DivergingDataRamp {
92
+ type: "diverging";
93
+ /** CSS color or anchor reference at the low end. */
94
+ start: string;
95
+ /** CSS color or anchor reference at the high end. */
96
+ end: string;
97
+ /** CSS color or anchor reference at the exact midpoint. */
98
+ neutral?: string;
99
+ steps?: number;
100
+ }
101
+ /** A named data-ramp declaration inside a theme. */
102
+ export type DataRamp = SequentialDataRamp | DivergingDataRamp;
103
+ /** Named data ramps emitted by a theme. */
104
+ export type DataRamps = Record<string, DataRamp>;
105
+ /** One ramp while partial themes are being layered. */
106
+ export type PartialDataRamp = Partial<SequentialDataRamp> | Partial<DivergingDataRamp>;
107
+ /** Named ramp refinements in a partial theme. */
108
+ export type PartialDataRamps = Record<string, PartialDataRamp>;
109
+ /**
110
+ * Generate a single-hue, light-to-dark sequential ramp.
111
+ *
112
+ * Chroma is reduced only when needed to keep each stop in sRGB. Gamut mapping
113
+ * preserves lightness, so the requested sequence remains strictly monotone.
114
+ */
115
+ export declare function generateSequentialRamp(color: string, options?: SequentialRampOptions): string[];
116
+ /**
117
+ * Generate a two-ended diverging ramp with an exact neutral midpoint.
118
+ *
119
+ * Each half interpolates in OKLab, avoiding the hue spin that polar
120
+ * interpolation produces as chroma approaches zero.
121
+ */
122
+ export declare function generateDivergingRamp(start: string, end: string, options?: DivergingRampOptions): string[];
@@ -0,0 +1 @@
1
+ import{clampChannel as L,gamutMapToSRGB as E,linearRgbToOklab as I,oklabToOklch as C,oklchToOklab as S,oklchToSRGB as w,parseCssColor as M,serializeOklch as b,srgbToLinearRGB as N}from"./color-engine.js";const u=["series1","series2","series3","series4","series5","series6","series7","series8"],y={series1:"#000000",series2:"#E69F00",series3:"#56B4E9",series4:"#009E73",series5:"#F0E442",series6:"#0072B2",series7:"#D55E00",series8:"#CC79A7"},k=["deuteranopia","protanopia","tritanopia"],O=.07,P={protanopia:[[.152286,1.052583,-.204868],[.114503,.786281,.099216],[-.003882,-.048116,1.051998]],deuteranopia:[[.367322,.860646,-.227968],[.280085,.672501,.047413],[-.01182,.04294,.968881]],tritanopia:[[1.255528,-.076749,-.178779],[-.078411,.930809,.147602],[.004733,.691367,.3039]]};function x(e,t){const r=w(E(e)),o=N(r),n=s=>L(s[0]*o.r+s[1]*o.g+s[2]*o.b);return{r:n(t[0]),g:n(t[1]),b:n(t[2])}}function q(e,t){return Math.hypot(e.L-t.L,e.a-t.a,e.b-t.b)}function p(e,t){const r=M(e);if(!r)throw new TypeError(`${t} is not a valid opaque CSS color: "${e}".`);return r}function G(e,t=O){if(!Number.isFinite(t)||t<0)throw new RangeError("Data-palette distance threshold must be a finite number \u2265 0.");const r=new Map;for(const n of u)r.set(n,p(e[n],`dataPalette.${n}`));const o=[];for(const n of k){const s=new Map;for(const a of u)s.set(a,I(x(r.get(a),P[n])));for(let a=0;a<u.length;a+=1)for(let i=a+1;i<u.length;i+=1){const l=u[a],c=u[i],g=q(s.get(l),s.get(c));g<t&&o.push({series:[l,c],simulation:n,distance:g,threshold:t})}}return o}const A=3,f=11,m=7,T=1e-6,v="oklch(0.96 0 0)";function _(e,t){if(!Number.isInteger(e)||e<A||e>f)throw new RangeError(`Data-ramp steps must be an integer from ${A} through ${f}.`);if(t&&e%2===0)throw new RangeError("Diverging data-ramp steps must be odd so the neutral is the midpoint.")}function d(e,t){if(!Number.isFinite(e)||e<0||e>1)throw new RangeError(`${t} must be a finite number from 0 through 1.`)}function U(e,t={}){const r=p(e,"Sequential ramp source"),o=t.steps??m,n=t.lightnessStart??.95,s=t.lightnessEnd??.25;if(_(o,!1),d(n,"Sequential ramp lightnessStart"),d(s,"Sequential ramp lightnessEnd"),n<=s)throw new RangeError("Sequential ramp lightnessStart must be greater than lightnessEnd.");if((n-s)/(o-1)<=T)throw new RangeError(`Sequential ramp lightness bounds must leave more than ${T} lightness between serialized stops.`);return Array.from({length:o},(a,i)=>{const l=i/(o-1),c=n+(s-n)*l;return b(E({l:c,c:r.c,h:r.h}))})}function R(e,t,r){return{L:e.L+(t.L-e.L)*r,a:e.a+(t.a-e.a)*r,b:e.b+(t.b-e.b)*r}}function B(e,t,r={}){const o=p(e,"Diverging ramp start"),n=p(t,"Diverging ramp end"),s=p(r.neutral??v,"Diverging ramp neutral"),a=r.steps??m;_(a,!0);const i=(a-1)/2,l=S(o),c=S(s),g=S(n);return Array.from({length:a},(F,h)=>{if(h===i)return b(E(s));const D=h<i?R(l,c,h/i):R(c,g,(h-i)/i);return b(E(C(D)))})}export{k as COLOR_VISION_SIMULATIONS,u as DATA_SERIES_KEYS,y as DEFAULT_DATA_PALETTE,m as DEFAULT_DATA_RAMP_STEPS,v as DEFAULT_DIVERGING_NEUTRAL,f as MAX_DATA_RAMP_STEPS,O as MIN_DATA_COLOR_DISTANCE,T as MIN_DATA_RAMP_LIGHTNESS_STEP,A as MIN_DATA_RAMP_STEPS,G as auditDataPalette,B as generateDivergingRamp,U as generateSequentialRamp};
@@ -39,6 +39,13 @@ export declare class EspalierElementBase extends LitElement implements SeedColor
39
39
  */
40
40
  get variant(): EspalierVariant;
41
41
  set variant(val: EspalierVariant);
42
+ /**
43
+ * A theme-defined color zone. The selected context rebinds designer-facing
44
+ * roles and emits a complete, contrast-enforced semantic token table on this
45
+ * host for descendants to inherit.
46
+ */
47
+ get context(): string;
48
+ set context(value: string);
42
49
  connectedCallback(): void;
43
50
  disconnectedCallback(): void;
44
51
  protected firstUpdated(_changedProperties: PropertyValues): void;
@@ -51,14 +58,13 @@ export declare class EspalierElementBase extends LitElement implements SeedColor
51
58
  */
52
59
  traverseToClosest(selector: string): Element | null;
53
60
  /**
54
- * Compute and apply variant-specific semantic color tokens.
61
+ * Compute and apply context- and variant-specific semantic color tokens.
55
62
  *
56
- * For the **primary** variant (or none), all semantic tokens
57
- * cascade from `<esp-root>` any previous overrides are cleared.
63
+ * With no context and the **primary** variant (or none), all semantic
64
+ * tokens cascade from `<esp-root>` and previous overrides are cleared.
58
65
  *
59
- * For non-primary variants, semantic tokens whose source is
60
- * `primary` are recomputed using the variant color and applied
61
- * as inline styles on the host element.
66
+ * A non-primary legacy variant is then computed over the contextual theme
67
+ * and applied as the final inline layer until ESP0166 removes re-seeding.
62
68
  */
63
69
  protected applyVariantTokens(): void;
64
70
  protected getVariantColorSource(): ColorSource | "";
@@ -1,4 +1,4 @@
1
- var p=function(v,e,t,o){var r=arguments.length,s=r<3?e:o===null?o=Object.getOwnPropertyDescriptor(e,t):o,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(v,e,t,o);else for(var c=v.length-1;c>=0;c--)(a=v[c])&&(s=(r<3?a(s):r>3?a(e,t,s):a(e,t))||s);return r>3&&s&&Object.defineProperty(e,t,s),s};import{css as x,LitElement as A}from"lit";import{property as y,state as U}from"lit/decorators.js";import{subscribeToRootEvent as f}from"./root-event-subscription.js";import{traverseToClosest as T}from"./utilities.js";import{parseCssColor as O,serializeOklch as k,gamutMapToSRGB as F,deriveSemantic as _,deriveSemanticWithContrast as z}from"./color-engine.js";import{computeVariants as S,resolveMappingSource as D}from"../root/helpers/compute-variants.js";import{SEMANTIC_COLOR_NAMES as P,TOKEN_PAIRINGS as I,semanticToCSS as w}from"./theme.js";import{alignAttributeTextInheritance as M,focusRing as B}from"./style-fragments.js";class n extends A{constructor(){super(...arguments),this.seedColorBacker="oklch(0.7 0.125 216)",this.espRoot=null,this.variantTokenOriginalValues=new Map,this.rootEventSubscriptionsActive=!1,this.subscribedRoot=null,this.rootEventUnsubscribers=[],this.variantBacker="primary",this.correlationId=globalThis.crypto?.randomUUID?.()??Math.random().toString(36),this.scheme="light",this.handleSeedColorChanged=e=>{this.syncRootFromDom(!1)&&(this.seedColor=e.seedColor,this.applyVariantTokens())},this.handleSchemeChanged=e=>{!this.syncRootFromDom(!1)||this.scheme===e.scheme||(this.scheme=e.scheme,this.applyVariantTokens())},this.handleThemeChanged=()=>{this.syncRootFromDom(!1)&&this.applyVariantTokens()},this.handleIconSpriteUrlChanged=()=>{this.syncRootFromDom(!1)&&this.requestUpdate()}}get seedColor(){return this.seedColorBacker}set seedColor(e){this.seedColorBacker=e}focusResolvedElementAfterUpdate(e,t){const o=()=>{const r=e();return r?(r.focus(t),!0):!1};o()||this.updateComplete.then(()=>{o()})}focusShadowElementAfterUpdate(e,t){this.focusResolvedElementAfterUpdate(()=>this.shadowRoot?.querySelector(e),t)}emitValueChanged(e){this.dispatchEvent(new CustomEvent("value-changed",{detail:e,bubbles:!0,composed:!0}))}get variant(){return this.variantBacker}set variant(e){this.variantBacker=e,this.applyVariantTokens()}connectedCallback(){super.connectedCallback();const e=this.syncRootFromDom(!1);e&&this.subscribeToRootEvents(e)}disconnectedCallback(){super.disconnectedCallback(),this.unsubscribeFromRootEvents()}firstUpdated(e){this.syncRootFromDom(!0)}syncRootFromDom(e){const t=T(this,"esp-root");if(!t){if(this.espRoot&&this.clearVariantTokens(),this.unsubscribeFromRootEvents(),this.espRoot=null,!e)return null;throw new Error("No esp-root ancestor found. Espalier components must be placed inside an <esp-root> element.")}const o=t!==this.espRoot,s=t.scheme==="dark"?"dark":"light",a=this.scheme!==s,c=this.seedColor!==t.seedColor;return this.espRoot=t,o&&this.isConnected&&this.subscribeToRootEvents(t),(o||a||c)&&(this.scheme=s,this.seedColor=t.seedColor,this.applyVariantTokens()),o&&this.requestUpdate(),t}subscribeToRootEvents(e){this.rootEventSubscriptionsActive&&this.subscribedRoot===e||(this.unsubscribeFromRootEvents(),this.subscribedRoot=e,this.rootEventUnsubscribers=[f(e,"seed-color-changed",this.handleSeedColorChanged),f(e,"scheme-changed",this.handleSchemeChanged),f(e,"theme-changed",this.handleThemeChanged),f(e,"icon-sprite-url-changed",this.handleIconSpriteUrlChanged)],this.rootEventSubscriptionsActive=!0)}unsubscribeFromRootEvents(){if(this.rootEventSubscriptionsActive){for(const e of this.rootEventUnsubscribers)e();this.rootEventUnsubscribers=[],this.subscribedRoot=null,this.rootEventSubscriptionsActive=!1}}traverseToClosest(e){return T(this,e)}applyVariantTokens(){if(!this.espRoot)return;const e=this.getVariantColorSource();if(!e){this.clearVariantTokens();return}const t=this.espRoot.activeTheme,o=O(t.seedColor);if(!o)return;const s=S(o,t)[e];if(!s){this.clearVariantTokens();return}this.setVariantTokenProperty("--esp-color-primary",k(F(s)));const a=S(s,t),c=n.statusVariantSources.has(e),{textContrast:C}=n,g={},R=i=>D(i,a,t.anchors)??a.primary;for(const i of P){if(C[i])continue;const l=t.semanticMappings[i],h=t.chroma[i],d=this.effectiveVariantTokenSource(i,l.source,c),b=R(d),m=t.lightness[l.lightness],u=_(b,m,h.min,h.max);g[i]=u,this.setVariantTokenProperty(w(i),k(u))}for(const i of P){const l=C[i];if(!l)continue;const h=t.semanticMappings[i],d=t.chroma[i],b=this.effectiveVariantTokenSource(i,h.source,c),m=R(b),u=t.lightness[h.lightness],E=g[l.bg],V=z(m,u,d.min,d.max,E,l.targetLc);g[i]=V,this.setVariantTokenProperty(w(i),k(V))}}effectiveVariantTokenSource(e,t,o){return o&&n.semanticActionTokens.has(e)?"primary":t}getVariantColorSource(){switch(this.variant){case"":case"primary":case"neutral":return"";case"info":return"complementary";default:return this.variant}}setVariantTokenProperty(e,t){const o=this.variantTokenOriginalValues.get(e);if(o){const r=this.style.getPropertyValue(e),s=this.style.getPropertyPriority(e);(r!==o.generatedValue||s!==o.generatedPriority)&&(o.originalValue=r.length?r:null,o.originalPriority=s),o.generatedValue=t,o.generatedPriority=""}else{const r=this.style.getPropertyValue(e);this.variantTokenOriginalValues.set(e,{generatedPriority:"",generatedValue:t,originalPriority:this.style.getPropertyPriority(e),originalValue:r.length?r:null})}this.style.setProperty(e,t)}clearVariantTokens(){for(const[e,t]of this.variantTokenOriginalValues){const o=this.style.getPropertyValue(e),r=this.style.getPropertyPriority(e);(o!==t.generatedValue||r!==t.generatedPriority)&&(t.originalValue=o.length?o:null,t.originalPriority=r),t.originalValue===null?this.style.removeProperty(e):this.style.setProperty(e,t.originalValue,t.originalPriority)}this.variantTokenOriginalValues.clear()}}n.textContrast=I,n.statusVariantSources=new Set(["danger","success","warning"]),n.semanticActionTokens=new Set(["actionBackground","actionText"]),n.styles=[B(".esp-field:focus-within","--esp-field-focus-shadow"),M,x`
1
+ var c=function(u,e,t,o){var r=arguments.length,s=r<3?e:o===null?o=Object.getOwnPropertyDescriptor(e,t):o,n;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(u,e,t,o);else for(var i=u.length-1;i>=0;i--)(n=u[i])&&(s=(r<3?n(s):r>3?n(e,t,s):n(e,t))||s);return r>3&&s&&Object.defineProperty(e,t,s),s};import{css as R,LitElement as T}from"lit";import{property as d,state as C}from"lit/decorators.js";import{subscribeToRootEvent as p}from"./root-event-subscription.js";import{traverseToClosest as f}from"./utilities.js";import{parseCssColor as S,serializeOklch as x,gamutMapToSRGB as V}from"./color-engine.js";import{computeVariants as g}from"../root/helpers/compute-variants.js";import{computeSemanticProperties as b}from"../root/helpers/compute-semantic-properties.js";import{ROLE_NAMES as w,mergeTheme as P}from"./theme.js";import{alignAttributeTextInheritance as E,focusRing as U}from"./style-fragments.js";const v=new WeakMap;class a extends T{constructor(){super(...arguments),this.seedColorBacker="oklch(0.7 0.125 216)",this.espRoot=null,this.contextBacker="",this.scopedTokenOriginalValues=new Map,this.warnedUnknownContexts=new Set,this.pendingInitialThemeRoot=null,this.rootEventSubscriptionsActive=!1,this.subscribedRoot=null,this.rootEventUnsubscribers=[],this.variantBacker="primary",this.correlationId=globalThis.crypto?.randomUUID?.()??Math.random().toString(36),this.scheme="light",this.handleSeedColorChanged=e=>{this.syncRootFromDom(!1)&&(this.seedColor=e.seedColor,this.applyVariantTokens())},this.handleSchemeChanged=e=>{!this.syncRootFromDom(!1)||this.scheme===e.scheme||(this.scheme=e.scheme,this.applyVariantTokens())},this.handleThemeChanged=()=>{this.syncRootFromDom(!1)&&this.applyVariantTokens()},this.handleIconSpriteUrlChanged=()=>{this.syncRootFromDom(!1)&&this.requestUpdate()}}get seedColor(){return this.seedColorBacker}set seedColor(e){this.seedColorBacker=e}focusResolvedElementAfterUpdate(e,t){const o=()=>{const r=e();return r?(r.focus(t),!0):!1};o()||this.updateComplete.then(()=>{o()})}focusShadowElementAfterUpdate(e,t){this.focusResolvedElementAfterUpdate(()=>this.shadowRoot?.querySelector(e),t)}emitValueChanged(e){this.dispatchEvent(new CustomEvent("value-changed",{detail:e,bubbles:!0,composed:!0}))}get variant(){return this.variantBacker}set variant(e){this.variantBacker=e,this.applyTokensWhenRootReady()}get context(){return this.contextBacker}set context(e){const t=e??"";t!==this.contextBacker&&(this.contextBacker=t,this.applyTokensWhenRootReady())}connectedCallback(){super.connectedCallback();const e=this.syncRootFromDom(!1);e&&this.subscribeToRootEvents(e)}disconnectedCallback(){super.disconnectedCallback(),this.unsubscribeFromRootEvents()}firstUpdated(e){this.syncRootFromDom(!0),this.applyTokensWhenRootReady()}syncRootFromDom(e){const t=f(this,"esp-root");if(!t){if(this.espRoot&&this.clearScopedTokens(),this.unsubscribeFromRootEvents(),this.espRoot=null,!e)return null;throw new Error("No esp-root ancestor found. Espalier components must be placed inside an <esp-root> element.")}const o=t!==this.espRoot,s=t.scheme==="dark"?"dark":"light",n=this.scheme!==s,i=this.seedColor!==t.seedColor;return this.espRoot=t,o&&this.isConnected&&this.subscribeToRootEvents(t),(o||n||i)&&(this.scheme=s,this.seedColor=t.seedColor,this.applyTokensWhenRootReady()),o&&this.requestUpdate(),t}applyTokensWhenRootReady(){const e=this.espRoot;if(e&&(!e.hasUpdated||e.isUpdatePending)){this.applyTokensAfterInitialRootUpdate(e);return}this.applyVariantTokens()}applyTokensAfterInitialRootUpdate(e){if(this.pendingInitialThemeRoot===e)return;this.pendingInitialThemeRoot=e;const t=e.updateComplete;if(!t){this.pendingInitialThemeRoot=null,this.applyVariantTokens();return}t.then(()=>{this.pendingInitialThemeRoot===e&&(this.pendingInitialThemeRoot=null),!(!this.isConnected||this.espRoot!==e)&&(this.scheme=e.scheme==="dark"?"dark":"light",this.seedColor=e.seedColor,this.applyVariantTokens())})}subscribeToRootEvents(e){this.rootEventSubscriptionsActive&&this.subscribedRoot===e||(this.unsubscribeFromRootEvents(),this.subscribedRoot=e,this.rootEventUnsubscribers=[p(e,"seed-color-changed",this.handleSeedColorChanged),p(e,"scheme-changed",this.handleSchemeChanged),p(e,"theme-changed",this.handleThemeChanged),p(e,"icon-sprite-url-changed",this.handleIconSpriteUrlChanged)],this.rootEventSubscriptionsActive=!0)}unsubscribeFromRootEvents(){if(this.rootEventSubscriptionsActive){for(const e of this.rootEventUnsubscribers)e();this.rootEventUnsubscribers=[],this.subscribedRoot=null,this.rootEventSubscriptionsActive=!1}}traverseToClosest(e){return f(this,e)}applyVariantTokens(){if(!this.espRoot)return;const e=this.getVariantColorSource();if(!e&&!this.context.trim()){this.clearScopedTokens();return}const t=this.espRoot.activeTheme;if(!t){this.clearScopedTokens();return}const o=this.resolveContextTheme(t),r=o.theme,s=S(r.seedColor);if(!s)return;const n=g(s,r),i={};if(!e){o.applied&&Object.assign(i,b(r,n)),this.applyScopedTokenProperties(i);return}const l=n[e];if(!l){this.clearScopedTokens();return}i["--esp-color-primary"]=x(V(l));const h=g(l,r),y=a.statusVariantSources.has(e);Object.assign(i,b(r,h,{effectiveSource:(m,k)=>this.effectiveVariantTokenSource(m,k,y)})),this.applyScopedTokenProperties(i)}resolveContextTheme(e){const t=this.context.trim();if(!t)return{applied:!1,theme:e};const o=e.contexts&&Object.prototype.hasOwnProperty.call(e.contexts,t)?e.contexts[t]:void 0;if(o){let r=v.get(e);const s=r?.get(t);if(s)return{applied:!0,theme:s};const n={};for(const l of w){const h=o[l];h!==void 0&&(n[l]=h)}const i=P(e,{lightness:o.lightness,roles:n});return r||(r=new Map,v.set(e,r)),r.set(t,i),{applied:!0,theme:i}}return this.warnedUnknownContexts.has(t)||(this.warnedUnknownContexts.add(t),console.warn(`Espalier context: "${t}" is not defined by the active theme; inheriting root tokens.`)),{applied:!1,theme:e}}effectiveVariantTokenSource(e,t,o){return o&&a.semanticActionTokens.has(e)?"primary":t}getVariantColorSource(){switch(this.variant){case"":case"primary":case"neutral":return"";case"info":return"complementary";default:return this.variant}}applyScopedTokenProperties(e){for(const t of this.scopedTokenOriginalValues.keys())t in e||this.restoreScopedTokenProperty(t);for(const[t,o]of Object.entries(e))this.setScopedTokenProperty(t,o)}setScopedTokenProperty(e,t){const o=this.scopedTokenOriginalValues.get(e);if(o){const r=this.style.getPropertyValue(e),s=this.style.getPropertyPriority(e);(r!==o.generatedValue||s!==o.generatedPriority)&&(o.originalValue=r.length?r:null,o.originalPriority=s),o.generatedValue=t,o.generatedPriority=""}else{const r=this.style.getPropertyValue(e);this.scopedTokenOriginalValues.set(e,{generatedPriority:"",generatedValue:t,originalPriority:this.style.getPropertyPriority(e),originalValue:r.length?r:null})}this.style.setProperty(e,t)}restoreScopedTokenProperty(e){const t=this.scopedTokenOriginalValues.get(e);if(!t)return;const o=this.style.getPropertyValue(e),r=this.style.getPropertyPriority(e);(o!==t.generatedValue||r!==t.generatedPriority)&&(t.originalValue=o.length?o:null,t.originalPriority=r),t.originalValue===null?this.style.removeProperty(e):this.style.setProperty(e,t.originalValue,t.originalPriority),this.scopedTokenOriginalValues.delete(e)}clearScopedTokens(){for(const e of[...this.scopedTokenOriginalValues.keys()])this.restoreScopedTokenProperty(e)}}a.statusVariantSources=new Set(["danger","success","warning"]),a.semanticActionTokens=new Set(["actionBackground","actionText"]),a.styles=[U(".esp-field:focus-within","--esp-field-focus-shadow"),E,R`
2
2
  :host {
3
3
 
4
4
  --_esp-field-resolved-hover-bg: var(
@@ -122,4 +122,4 @@ var p=function(v,e,t,o){var r=arguments.length,s=r<3?e:o===null?o=Object.getOwnP
122
122
  .esp-field:has(textarea:disabled):hover {
123
123
  background-color: var(--esp-field-background, var(--esp-color-layer-2));
124
124
  }
125
- `],p([U()],n.prototype,"seedColor",null),p([y({attribute:!1})],n.prototype,"correlationId",void 0),p([y({type:String,reflect:!0})],n.prototype,"scheme",void 0),p([y({type:String,attribute:"variant",reflect:!0})],n.prototype,"variant",null);export{n as EspalierElementBase};
125
+ `],c([C()],a.prototype,"seedColor",null),c([d({attribute:!1})],a.prototype,"correlationId",void 0),c([d({type:String,reflect:!0})],a.prototype,"scheme",void 0),c([d({type:String,attribute:"variant",reflect:!0})],a.prototype,"variant",null),c([d({type:String,attribute:"context",reflect:!0})],a.prototype,"context",null);export{a as EspalierElementBase};
@@ -30,6 +30,7 @@
30
30
  * }
31
31
  * ```
32
32
  */
33
+ import { type DataPalette, type DataRamps, type PartialDataRamps } from "./data-colors.js";
33
34
  /** A key in the lightness ramp. Each maps to a perceptual role. */
34
35
  export type LightnessKey = "surface" | "raised1" | "raised2" | "raised3" | "raised4" | "accent" | "muted" | "text" | "border" | "ink" | "shadow";
35
36
  /** Lightness values (0–1) for every ramp position. */
@@ -123,6 +124,14 @@ export declare function parseAnchorSource(source: string): AnchorReference | nul
123
124
  * resolves `null`, as do unknown names and slots.
124
125
  */
125
126
  export declare function resolveAnchorColor(anchors: ThemeAnchors, reference: AnchorReference): string | null;
127
+ /**
128
+ * Resolve a data color source to a concrete CSS color.
129
+ *
130
+ * Data palettes and ramps accept either a CSS color directly or the same
131
+ * `anchor:<name>[.<slot>]` references as semantic mappings. The returned color
132
+ * is parseable and opaque; invalid or unresolved sources return `null`.
133
+ */
134
+ export declare function resolveDataColorSource(source: string, anchors: ThemeAnchors): string | null;
126
135
  /** Every semantic color token the system computes. */
127
136
  export type SemanticColorName = "background" | "layer1" | "layer2" | "layer3" | "layer4" | "actionBackground" | "actionText" | "border" | "shadow" | "text" | "dangerText" | "headings" | "headingsHover" | "link" | "linkHover" | "linkHoverBg" | "inputCaret" | "inputSelection" | "inputSelectionBg";
128
137
  /** Chroma range enforced on a semantic token before gamut mapping. */
@@ -196,6 +205,20 @@ export type RoleBinding<R extends RoleName = RoleName> = MappingSource | ({
196
205
  export type ThemeRoles = {
197
206
  [R in RoleName]?: RoleBinding<R>;
198
207
  };
208
+ /**
209
+ * One named zone-level rebinding of the designer-facing color roles.
210
+ *
211
+ * A context may also carry a partial lightness ramp. Color sources alone
212
+ * cannot make a dark zone inside a light scheme because semantic derivation
213
+ * deliberately takes lightness from the ramp rather than from an anchor.
214
+ */
215
+ export type ThemeContext = ThemeRoles & {
216
+ lightness?: Partial<LightnessMap>;
217
+ };
218
+ /** Named role-rebinding zones available to `context` attributes. */
219
+ export type ThemeContexts = Record<string, ThemeContext>;
220
+ /** Context declarations while partial themes are being layered. */
221
+ export type PartialThemeContexts = Record<string, ThemeContext | undefined>;
199
222
  /** Ordered role names, for validation and iteration. */
200
223
  export declare const ROLE_NAMES: readonly RoleName[];
201
224
  /**
@@ -385,6 +408,23 @@ export interface EspalierTheme {
385
408
  * See {@link ThemeRoles} and ADR-016.
386
409
  */
387
410
  roles: ThemeRoles;
411
+ /**
412
+ * Named zone-level role rebindings. A base-derived element selects one with
413
+ * its `context` attribute; the selected context is resolved against this
414
+ * scheme's complete theme and re-enforces every semantic ink pairing.
415
+ */
416
+ contexts: ThemeContexts;
417
+ /**
418
+ * Eight stable categorical data-series colors. Each value is a CSS color or
419
+ * an `anchor:<name>[.<slot>]` reference. Emitted as
420
+ * `--esp-color-series-1`–`--esp-color-series-8`.
421
+ */
422
+ dataPalette: DataPalette;
423
+ /**
424
+ * Named sequential and diverging data ramps. Empty by default; each
425
+ * declaration emits `--esp-color-ramp-<name>-1…<steps>`.
426
+ */
427
+ dataRamps: DataRamps;
388
428
  /** Optional CSS `background-image` for the page surface. */
389
429
  pageBackgroundImage?: string;
390
430
  /** Opacity (0–1) for the page background image. */
@@ -407,8 +447,10 @@ export interface EspalierTheme {
407
447
  * carry slot-only anchor overrides, which the resolved
408
448
  * {@link ThemeAnchor} deliberately does not permit.
409
449
  */
410
- export type PartialTheme = Omit<DeepPartial<EspalierTheme>, "anchors"> & {
450
+ export type PartialTheme = Omit<DeepPartial<EspalierTheme>, "anchors" | "contexts" | "dataRamps"> & {
411
451
  anchors?: PartialThemeAnchors;
452
+ contexts?: PartialThemeContexts;
453
+ dataRamps?: PartialDataRamps;
412
454
  };
413
455
  /** Validation result returned by {@link validateTheme}. */
414
456
  export interface ThemeValidationResult {
@@ -535,7 +577,7 @@ export declare function encodeTheme(partial: PartialTheme): string;
535
577
  * Deep-merge a {@link PartialTheme} over a set of defaults.
536
578
  *
537
579
  * Primitive fields are replaced; nested objects (`angles`,
538
- * `semanticHues`, `lightness`, `chroma`, `semanticMappings`)
580
+ * `semanticHues`, `lightness`, `chroma`, `semanticMappings`, `contexts`)
539
581
  * are merged key-by-key. Arrays (`stylesheets`) are replaced
540
582
  * wholesale.
541
583
  *
@@ -557,12 +599,20 @@ export declare function mergeTheme(defaults: EspalierTheme, overrides: PartialTh
557
599
  * and `warnings`.
558
600
  */
559
601
  export declare function validateTheme(base64: string): ThemeValidationResult;
602
+ /**
603
+ * Validate the light and dark partials that form one scheme-paired theme.
604
+ *
605
+ * Each partial first passes through {@link validateTheme}. Once both are
606
+ * structurally valid, their context-name sets must match exactly so a stable
607
+ * `context` attribute cannot silently change meaning when the scheme changes.
608
+ */
609
+ export declare function validateThemePair(lightBase64: string, darkBase64: string): ThemeValidationResult;
560
610
  /**
561
611
  * Keys of {@link EspalierTheme} whose values are nested objects
562
612
  * and therefore need key-by-key merging instead of wholesale
563
613
  * replacement when combining two {@link PartialTheme} objects.
564
614
  */
565
- export declare const NESTED_THEME_KEYS: readonly ["anchors", "angles", "roles", "chroma", "lightness", "semanticHues", "semanticMappings", "variantChroma"];
615
+ export declare const NESTED_THEME_KEYS: readonly ["anchors", "angles", "contexts", "dataPalette", "dataRamps", "roles", "chroma", "lightness", "semanticHues", "semanticMappings", "variantChroma"];
566
616
  /**
567
617
  * Deep-merge two {@link PartialTheme} objects.
568
618
  *