@taprootio/espalier 2.18.0 → 2.19.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/custom-elements.json +3863 -3180
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -1
- package/dist/root/esp-root.d.ts +8 -0
- package/dist/root/esp-root.js +2 -2
- package/dist/root/helpers/compute-theme-properties.js +1 -1
- package/dist/shared/color-engine.js +1 -1
- package/dist/shared/data-colors.d.ts +122 -0
- package/dist/shared/data-colors.js +1 -0
- package/dist/shared/theme.d.ts +23 -2
- package/dist/shared/theme.js +1 -1
- package/espalier.css-data.json +32 -0
- package/espalier.token-manifest.json +49 -1
- package/package.json +5 -1
package/dist/index.d.ts
CHANGED
|
@@ -71,6 +71,7 @@ export { getImageDetails, releasePreviewUrl, type EspalierUploadImage, type Imag
|
|
|
71
71
|
export { calculatePhotoLayout, type LayoutImage, type PhotoRow, } from "./shared/justified-layout.js";
|
|
72
72
|
export { type TypeaheadFetchItems } from "./pickers/types.js";
|
|
73
73
|
export { type EspalierTheme, type PartialTheme, type VariantColorSource, encodeTheme, parseTheme, mergePartials, layerThemes, 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
|
|
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 To,INTENT_VARIANTS as ao,normalizeIntentVariant as _o,getIconHref as Ao,getIconHrefForHost as Eo,getIconSpriteUrl as lo}from"./shared/intent-values.js";import{EspalierElementBase as io}from"./shared/esp-element-base.js";import{VALIDITY_CHANGED_EVENT as so}from"./shared/validation.js";import{FormFieldController as go}from"./shared/form-field-controller.js";import{traverseToClosest as Fo}from"./shared/utilities.js";import{showToast as No}from"./shared/toast-events.js";import{showFlyout as ho,closeFlyout as Po}from"./shared/flyout-events.js";import{requestHelp as uo}from"./shared/help-events.js";import{getEspBus as Uo}from"./shared/bus-events.js";export*from"./shared/events.js";import{getImageDetails as Ho,releasePreviewUrl as Vo}from"./image-upload/image-helpers.js";import{calculatePhotoLayout as bo}from"./shared/justified-layout.js";import{encodeTheme as Wo,parseTheme as vo,mergePartials as wo,layerThemes as Bo,buildTaprootLightTheme as Yo,buildTaprootDarkTheme as ko,NESTED_THEME_KEYS as qo}from"./shared/theme.js";import{auditDataPalette as Ko,generateSequentialRamp as Xo,generateDivergingRamp as jo,COLOR_VISION_SIMULATIONS as Jo,DATA_SERIES_KEYS as Qo,DEFAULT_DATA_PALETTE as Zo,DEFAULT_DATA_RAMP_STEPS as $o,DEFAULT_DIVERGING_NEUTRAL as or,MAX_DATA_RAMP_STEPS as rr,MIN_DATA_COLOR_DISTANCE as er,MIN_DATA_RAMP_LIGHTNESS_STEP as tr,MIN_DATA_RAMP_STEPS as mr}from"./shared/data-colors.js";import{WEIGHT_LABELS as fr,extractWeights as xr,normalizeWeight as Tr,bestAvailableWeight as ar,extractFamily as _r,getFallbackFont as Ar}from"./shared/font-helpers.js";import{getGoogleFonts as lr}from"./font-picker/esp-font-picker.js";import{themeFitReport as ir,themeFitRows as Sr,printThemeFitReport as sr}from"./shared/theme-fit-report.js";export{Jo as COLOR_VISION_SIMULATIONS,Qo as DATA_SERIES_KEYS,Zo as DEFAULT_DATA_PALETTE,$o as DEFAULT_DATA_RAMP_STEPS,or as DEFAULT_DIVERGING_NEUTRAL,xo as DEFAULT_ICON_SPRITE_URL,To as DEFAULT_ICON_VIEW_BOX,io as EspalierElementBase,go as FormFieldController,ao as INTENT_VARIANTS,rr as MAX_DATA_RAMP_STEPS,er as MIN_DATA_COLOR_DISTANCE,tr as MIN_DATA_RAMP_LIGHTNESS_STEP,mr as MIN_DATA_RAMP_STEPS,qo as NESTED_THEME_KEYS,so as VALIDITY_CHANGED_EVENT,fr as WEIGHT_LABELS,Ko as auditDataPalette,ar as bestAvailableWeight,ko as buildTaprootDarkTheme,Yo as buildTaprootLightTheme,bo as calculatePhotoLayout,Po as closeFlyout,Wo as encodeTheme,_r as extractFamily,xr as extractWeights,jo as generateDivergingRamp,Xo as generateSequentialRamp,Uo as getEspBus,Ar as getFallbackFont,lr as getGoogleFonts,Ao as getIconHref,Eo as getIconHrefForHost,lo as getIconSpriteUrl,Ho as getImageDetails,Bo as layerThemes,wo as mergePartials,_o as normalizeIntentVariant,Tr as normalizeWeight,vo as parseTheme,sr as printThemeFitReport,Vo as releasePreviewUrl,uo as requestHelp,ho as showFlyout,No as showToast,ir as themeFitReport,Sr as themeFitRows,Fo as traverseToClosest};
|
package/dist/root/esp-root.d.ts
CHANGED
|
@@ -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
|
package/dist/root/esp-root.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var
|
|
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
|
-
`,
|
|
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};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{parseCssColor as
|
|
1
|
+
import{parseCssColor as C,serializeOklch as u,gamutMapToSRGB as E,deriveSemantic as M,deriveSemanticWithContrast as T}from"../../shared/color-engine.js";import{generateScaleProperties as x}from"../../shared/scale-engine.js";import{DATA_SERIES_KEYS as I,DEFAULT_DATA_PALETTE as h,generateDivergingRamp as A,generateSequentialRamp as L}from"../../shared/data-colors.js";import{SEMANTIC_COLOR_NAMES as w,LIGHTNESS_KEYS as _,TOKEN_PAIRINGS as P,resolveDataColorSource as D,semanticToCSS as f}from"../../shared/theme.js";import{lightnessKeyToCSS as N}from"./lightness-key-to-css.js";import{computeVariants as W,resolveMappingSource as H}from"./compute-variants.js";function K(o){return{rootFontSize:o.rootFontSize,typeRatio:o.typeRatio,spaceRatio:o.spaceRatio,borderRadius:o.borderRadius,viewportMin:o.viewportMin,viewportMax:o.viewportMax}}function U(o,O,i){const m=C(o.seedColor);if(!m)return{};const e={};e["--esp-scheme"]=O,e["--esp-seed-color"]=o.seedColor;const S=W(m,o);for(const[n,a]of Object.entries(S))e[`--esp-color-${n}`]=u(E(a));const v=new Set,c=(n,a)=>{const s=typeof n=="string"?D(n,o.anchors):null;if(s)return s;const t=typeof n=="string"?n:String(n);return v.has(t)||(v.add(t),console.warn(`Espalier theme: ${a} color source "${t}" cannot be resolved \u2014 falling back to the seed. Run validateTheme for the declared data colors.`)),o.seedColor},$=o.dataPalette??h;for(let n=0;n<I.length;n+=1){const a=I[n],s=C(c($[a],`dataPalette.${a}`))??m;e[`--esp-color-series-${n+1}`]=u(E(s))}for(const[n,a]of Object.entries(o.dataRamps??{}))try{(a.type==="sequential"?L(c(a.source,`dataRamps.${n}.source`),{steps:a.steps,lightnessStart:a.lightnessStart,lightnessEnd:a.lightnessEnd}):A(c(a.start,`dataRamps.${n}.start`),c(a.end,`dataRamps.${n}.end`),{steps:a.steps,neutral:a.neutral===void 0?void 0:c(a.neutral,`dataRamps.${n}.neutral`)})).forEach((t,r)=>{e[`--esp-color-ramp-${n}-${r+1}`]=t})}catch(s){console.warn(`Espalier theme: dataRamps.${n} cannot be generated \u2014 ${s instanceof Error?s.message:String(s)}`)}for(const n of _)e[N(n)]=`${Math.round(o.lightness[n]*100)}%`;const y=P,p=new Set,k=n=>{const a=H(n,S,o.anchors);return a||(p.has(n)||(p.add(n),console.warn(`Espalier theme: color source "${n}" cannot be resolved \u2014 falling back to the seed. Run validateTheme for the declared anchors.`)),S.primary)},b={};for(const n of w){if(y[n])continue;const a=o.semanticMappings[n],s=o.chroma[n],t=k(a.source),r=o.lightness[a.lightness],d=M(t,r,s.min,s.max);if(b[n]=d,e[f(n)]=u(d),i){const g=f(n);i.push({token:n,property:g,resolved:e[g],source:a.source,lightness:a.lightness,sourceResolved:!p.has(a.source),base:t})}}for(const n of w){const a=y[n];if(!a)continue;const s=o.semanticMappings[n],t=o.chroma[n],r=k(s.source),d=o.lightness[s.lightness],g=b[a.bg];let R;const B=T(r,d,t.min,t.max,g,a.targetLc,i&&(l=>{R=l}));if(b[n]=B,e[f(n)]=u(B),i){const l=f(n);i.push({token:n,property:l,resolved:e[l],source:s.source,lightness:s.lightness,sourceResolved:!p.has(s.source),base:r,requested:R,contrast:{against:a.bg,background:g,targetLc:a.targetLc}})}}return Object.assign(e,x(K(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{U as computeThemeProperties};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
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};
|
package/dist/shared/theme.d.ts
CHANGED
|
@@ -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. */
|
|
@@ -385,6 +394,17 @@ export interface EspalierTheme {
|
|
|
385
394
|
* See {@link ThemeRoles} and ADR-016.
|
|
386
395
|
*/
|
|
387
396
|
roles: ThemeRoles;
|
|
397
|
+
/**
|
|
398
|
+
* Eight stable categorical data-series colors. Each value is a CSS color or
|
|
399
|
+
* an `anchor:<name>[.<slot>]` reference. Emitted as
|
|
400
|
+
* `--esp-color-series-1`–`--esp-color-series-8`.
|
|
401
|
+
*/
|
|
402
|
+
dataPalette: DataPalette;
|
|
403
|
+
/**
|
|
404
|
+
* Named sequential and diverging data ramps. Empty by default; each
|
|
405
|
+
* declaration emits `--esp-color-ramp-<name>-1…<steps>`.
|
|
406
|
+
*/
|
|
407
|
+
dataRamps: DataRamps;
|
|
388
408
|
/** Optional CSS `background-image` for the page surface. */
|
|
389
409
|
pageBackgroundImage?: string;
|
|
390
410
|
/** Opacity (0–1) for the page background image. */
|
|
@@ -407,8 +427,9 @@ export interface EspalierTheme {
|
|
|
407
427
|
* carry slot-only anchor overrides, which the resolved
|
|
408
428
|
* {@link ThemeAnchor} deliberately does not permit.
|
|
409
429
|
*/
|
|
410
|
-
export type PartialTheme = Omit<DeepPartial<EspalierTheme>, "anchors"> & {
|
|
430
|
+
export type PartialTheme = Omit<DeepPartial<EspalierTheme>, "anchors" | "dataRamps"> & {
|
|
411
431
|
anchors?: PartialThemeAnchors;
|
|
432
|
+
dataRamps?: PartialDataRamps;
|
|
412
433
|
};
|
|
413
434
|
/** Validation result returned by {@link validateTheme}. */
|
|
414
435
|
export interface ThemeValidationResult {
|
|
@@ -562,7 +583,7 @@ export declare function validateTheme(base64: string): ThemeValidationResult;
|
|
|
562
583
|
* and therefore need key-by-key merging instead of wholesale
|
|
563
584
|
* replacement when combining two {@link PartialTheme} objects.
|
|
564
585
|
*/
|
|
565
|
-
export declare const NESTED_THEME_KEYS: readonly ["anchors", "angles", "roles", "chroma", "lightness", "semanticHues", "semanticMappings", "variantChroma"];
|
|
586
|
+
export declare const NESTED_THEME_KEYS: readonly ["anchors", "angles", "dataPalette", "dataRamps", "roles", "chroma", "lightness", "semanticHues", "semanticMappings", "variantChroma"];
|
|
566
587
|
/**
|
|
567
588
|
* Deep-merge two {@link PartialTheme} objects.
|
|
568
589
|
*
|
package/dist/shared/theme.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ACCEPTED_COLOR_FORMS as j,apcaContrast as J,deriveSemantic as Y,parseCssColor as O,parseOklch as X,serializeOklch as Z}from"./color-engine.js";import{computeVariants as q,parseAnchorSource as Q,resolveAnchorColor as ee,resolveMappingSource as ne}from"./variant-engine.js";const L=/^[a-z][a-z0-9-]*$/;function te(t){return Q(t)}function xe(t,e){return ee(t,e)}const E=["canvas","ink","accent","action","structure"],N={canvas:{color:[["background","surface"],["layer1","raised1"],["layer2","raised2"],["layer3","raised3"],["layer4","raised4"]]},ink:{color:[["text","text"],["inputSelection","text"]],heading:[["headings","muted"],["headingsHover","ink"]]},accent:{color:[["linkHoverBg","raised2"],["inputSelectionBg","raised2"],["inputCaret","ink"]],text:[["link","accent"],["linkHover","text"]]},action:{color:[["actionBackground","muted"]],ink:[["actionText","surface"]]},structure:{color:[["border","border"],["shadow","shadow"]]}},oe=new Set(["action.color"]),se={canvas:"background",ink:"text",accent:"link",action:"actionBackground",structure:"border"},re={"action.ink":{role:"canvas",slot:"color"}},ie=.45;function W(t,e){const i=F.actionText,a=[...x].sort((p,m)=>t[p]-t[m]||x.indexOf(p)-x.indexOf(m)),u=e?a.filter(p=>e(p)>=i.targetLc):a,s=u.length>0?u:a;let l,f=1/0;for(const p of s){const m=Math.abs(t[p]-ie);m<f&&(f=m,l=p)}return l??"muted"}function ae(t,e){const i=e[t]>.5;let a=x[0];for(const u of x)(i?e[u]<e[a]:e[u]>e[a])&&(a=u);return a}function A(t,e){if(t===void 0)return;if(typeof t=="string")return e==="color"?t:void 0;const i=t[e];return typeof i=="string"?i:void 0}function D(t,e,i,a={}){const u={},s={};for(const[l,f]of Object.entries(a.explicitMappings??{}))f!==void 0&&(s[l]=f.lightness);for(const l of E){const f=t[l];if(f!==void 0)for(const[p,m]of Object.entries(N[l])){const h=re[`${l}.${p}`];let n=A(f,p),o=!1;if(n===void 0&&(h&&(n=A(t[h.role],h.slot),n??=i[se[h.role]]?.source,o=n!==void 0),n??=A(f,"color")),n!==void 0)for(const[r,c]of m){let g=c;if(oe.has(`${l}.${p}`))g=W(e,a.actionSurfaceContrast?y=>a.actionSurfaceContrast(n,y):void 0);else if(o&&h){const y=F[r],b=(y&&s[y.bg])??W(e,a.actionSurfaceContrast?S=>a.actionSurfaceContrast(A(f,"color"),S):void 0);g=ae(b,e)}u[r]={source:n,lightness:g}}}}return u}const F={text:{bg:"background",targetLc:75},dangerText:{bg:"background",targetLc:75},headings:{bg:"background",targetLc:60},headingsHover:{bg:"background",targetLc:60},link:{bg:"background",targetLc:75},linkHover:{bg:"background",targetLc:75},actionText:{bg:"actionBackground",targetLc:75},inputCaret:{bg:"layer2",targetLc:60},inputSelection:{bg:"inputSelectionBg",targetLc:60}},I=["background","layer1","layer2","layer3","layer4","actionBackground","actionText","border","shadow","text","dangerText","headings","headingsHover","link","linkHover","linkHoverBg","inputCaret","inputSelection","inputSelectionBg"],T=["primary","analogous-left","analogous-right","complementary","split-complementary-left","split-complementary-right","triadic-left","triadic-right","danger","success","warning"],ce=["analogous-left","analogous-right","complementary","split-complementary-left","split-complementary-right","triadic-left","triadic-right","danger","success","warning"],x=["surface","raised1","raised2","raised3","raised4","accent","muted","text","border","ink","shadow"],ue={surface:.99,raised1:.97,raised2:.9,raised3:.8,raised4:.72,accent:.5,muted:.45,text:.35,border:.3,ink:.25,shadow:.2},le={surface:.15,raised1:.2,raised2:.3,raised3:.4,raised4:.36,accent:.6,muted:.75,text:.85,border:.7,ink:.95,shadow:.6},w={background:{source:"primary",lightness:"surface"},layer1:{source:"primary",lightness:"raised1"},layer2:{source:"primary",lightness:"raised2"},layer3:{source:"primary",lightness:"raised3"},layer4:{source:"primary",lightness:"raised4"},actionBackground:{source:"primary",lightness:"raised3"},actionText:{source:"primary",lightness:"ink"},border:{source:"primary",lightness:"border"},shadow:{source:"primary",lightness:"shadow"},text:{source:"primary",lightness:"text"},dangerText:{source:"danger",lightness:"text"},headings:{source:"primary",lightness:"muted"},headingsHover:{source:"primary",lightness:"text"},link:{source:"complementary",lightness:"accent"},linkHover:{source:"complementary",lightness:"text"},linkHoverBg:{source:"triadic-left",lightness:"raised2"},inputCaret:{source:"triadic-right",lightness:"ink"},inputSelection:{source:"complementary",lightness:"text"},inputSelectionBg:{source:"triadic-left",lightness:"raised2"}},v=.4;function R(){const t={};for(const e of I)t[e]={min:0,max:v};return t}const P={seedColor:"oklch(0.7 0.125 216)",fontBody:"",fontHeadings:"",fontBrand:"",fontMonospace:"",fontWeightBody:"normal",fontWeightHeadings:"bold",fontWeightBrand:"bold",fontWeightMonospace:"normal",stylesheets:[],rootFontSize:16,typeRatio:1.25,spaceRatio:1.618,borderRadius:.2,viewportMin:320,viewportMax:1200,angles:{analogous:30,complementary:180,splitComplementary:30,triadic:120},semanticHues:{danger:27,success:150,warning:90},variantChroma:{},chroma:R(),semanticMappings:{...w},anchors:{},roles:{}},fe={...P,chroma:R(),semanticMappings:{...w},anchors:{},roles:{},lightness:{...ue}},pe={...P,chroma:R(),semanticMappings:{...w},anchors:{},roles:{},lightness:{...le}},M=new WeakMap;M.set(fe,new Set),M.set(pe,new Set);const K=new Set(["__proto__","constructor","prototype"]);function d(t){return!K.has(t)}function ge(t,e){return K.has(t)?void 0:e}function Se(t){return`--esp-color-${t.replace(/([A-Z])/g,"-$1").replace(/(\d)/g,"-$1").toLowerCase()}`}function me(t){try{const e=atob(t),i=JSON.parse(e,ge);return typeof i!="object"||i===null||Array.isArray(i)?null:i}catch{return null}}function H(t){return btoa(JSON.stringify(t))}function _(t){if(X(t))return t;const e=O(t);return e?Z(e):t}function U(t,e){const i={};for(const[a,u]of Object.entries(t))d(a)&&(i[a]=u);if(!e)return i;for(const[a,u]of Object.entries(e)){if(u===void 0||!d(a))continue;const s=i[a];if(s!==void 0&&typeof u=="object"&&u!==null){const l={};if(typeof s=="string")l.color=s;else for(const[f,p]of Object.entries(s))d(f)&&(l[f]=p);for(const[f,p]of Object.entries(u))p!==void 0&&d(f)&&(l[f]=p);i[a]=l;continue}i[a]=u}return i}function de(t){const e={};for(const[i,a]of Object.entries(t)){if(!d(i))continue;if(typeof a=="string"){e[i]=_(a);continue}const u={};for(const[s,l]of Object.entries(a))d(s)&&(u[s]=typeof l=="string"?_(l):l);e[i]=u}return e}function z(t){const e=O(t.seedColor);if(!e)return;const i=q(e,t);return(a,u)=>{const s=ne(a,i,t.anchors)??i.primary,l=t.chroma.actionBackground,f=Y(s,t.lightness[u],l.min,l.max),p={l:f.l>.5?0:1,c:0,h:0};return Math.abs(J(p,f))}}function he(t){const e=M.get(t);if(e)return new Set(e);const i=new Set,a=D(t.roles,t.lightness,t.semanticMappings,{actionSurfaceContrast:z(t)});for(const[u,s]of Object.entries(a)){const l=t.semanticMappings[u];(l.source!==s.source||l.lightness!==s.lightness)&&i.add(u)}return i}function Oe(t,e){const i={...t.roles,...e.roles},a={...t.lightness,...e.lightness},u=de(U(t.anchors,e.anchors)),s=typeof e.seedColor=="string"?_(e.seedColor):t.seedColor,l=e.semanticMappings,f={...t.angles,...e.angles},p={...t.semanticHues,...e.semanticHues},m={...t.variantChroma,...e.variantChroma},h=B(t.chroma,e.chroma),n=he(t),o=new Set(n),r={};for(const $ of n)r[$]=t.semanticMappings[$];for(const[$,C]of Object.entries(l??{}))C!==void 0&&(o.add($),r[$]=C);const c=B(t.semanticMappings,l),g=z({angles:f,anchors:u,chroma:h,lightness:a,seedColor:s,semanticHues:p,variantChroma:m}),y=D(i,a,c,{explicitMappings:r,actionSurfaceContrast:g}),b={};for(const[$,C]of Object.entries(y))o.has($)||(b[$]=C);const S=B(B(t.semanticMappings,b),l),k={...t,seedColor:s,fontBody:e.fontBody??t.fontBody,fontHeadings:e.fontHeadings??t.fontHeadings,fontBrand:e.fontBrand??t.fontBrand,fontMonospace:e.fontMonospace??t.fontMonospace,fontWeightBody:String(e.fontWeightBody??t.fontWeightBody),fontWeightHeadings:String(e.fontWeightHeadings??t.fontWeightHeadings),fontWeightBrand:String(e.fontWeightBrand??t.fontWeightBrand),fontWeightMonospace:String(e.fontWeightMonospace??t.fontWeightMonospace),stylesheets:e.stylesheets??[...t.stylesheets],rootFontSize:e.rootFontSize??t.rootFontSize,typeRatio:e.typeRatio??t.typeRatio,spaceRatio:e.spaceRatio??t.spaceRatio,borderRadius:e.borderRadius??t.borderRadius,viewportMin:e.viewportMin??t.viewportMin,viewportMax:e.viewportMax??t.viewportMax,angles:f,semanticHues:p,variantChroma:m,lightness:a,chroma:h,semanticMappings:S,anchors:u,roles:i};return e.pageBackgroundImage!==void 0&&(k.pageBackgroundImage=e.pageBackgroundImage),e.pageBackgroundImageOpacity!==void 0&&(k.pageBackgroundImageOpacity=e.pageBackgroundImageOpacity),e.boxBackgroundImage!==void 0&&(k.boxBackgroundImage=e.boxBackgroundImage),e.boxBackgroundImageOpacity!==void 0&&(k.boxBackgroundImageOpacity=e.boxBackgroundImageOpacity),e.vellumOpacity!==void 0&&(k.vellumOpacity=e.vellumOpacity),e.vellumBackgroundImage!==void 0&&(k.vellumBackgroundImage=e.vellumBackgroundImage),e.vellumBackgroundImageOpacity!==void 0&&(k.vellumBackgroundImageOpacity=e.vellumBackgroundImageOpacity),M.set(k,new Set(o)),k}function B(t,e){if(!e)return{...t};const i={...t};for(const a of Object.keys(e)){const u=e[a];u!==void 0&&(i[a]=u)}return i}function ve(t){const e=[],i=[];let a;try{a=atob(t)}catch{return e.push("Failed to decode Base64 string."),{valid:!1,errors:e,warnings:i}}let u;try{u=JSON.parse(a)}catch{return e.push("Decoded string is not valid JSON."),{valid:!1,errors:e,warnings:i}}if(typeof u!="object"||u===null||Array.isArray(u))return e.push("Theme must be a JSON object."),{valid:!1,errors:e,warnings:i};const s=u;"seedColor"in s&&(typeof s.seedColor!="string"?e.push("seedColor must be a string."):O(s.seedColor)||e.push(`seedColor is not a valid CSS color: "${s.seedColor}". Accepted forms: ${j}.`));for(const n of["fontBody","fontHeadings","fontBrand","fontMonospace"])n in s&&typeof s[n]!="string"&&e.push(`${n} must be a string.`);const l=["normal","bold","lighter","bolder"],f=["inherit","initial","unset","revert","revert-layer"];for(const n of["fontWeightBody","fontWeightHeadings","fontWeightBrand","fontWeightMonospace"])if(n in s){const o=s[n];if(typeof o=="number")(o<1||o>1e3)&&e.push(`${n} numeric value must be 1\u20131000 (got ${o}).`);else if(typeof o=="string"){const r=l.includes(o)||f.includes(o);if(/^\d+$/.test(o)){const g=Number(o);(g<1||g>1e3)&&e.push(`${n} numeric value must be 1\u20131000 (got "${o}").`)}else r||i.push(`${n} = "${o}" is not a standard font-weight value.`)}else e.push(`${n} must be a string or number.`)}"stylesheets"in s&&(Array.isArray(s.stylesheets)?s.stylesheets.some(n=>typeof n!="string")&&e.push("Every entry in stylesheets must be a string."):e.push("stylesheets must be an array of strings."));const p=[["rootFontSize",1,100],["borderRadius",0,10],["viewportMin",100,1e4],["viewportMax",200,1e4]];for(const[n,o,r]of p)if(n in s)if(typeof s[n]!="number"||!isFinite(s[n]))e.push(`${n} must be a finite number.`);else{const c=s[n];o!==void 0&&c<o&&e.push(`${n} must be \u2265 ${o} (got ${c}).`),r!==void 0&&c>r&&i.push(`${n} = ${c} is unusually high (max ${r}).`)}for(const n of["typeRatio","spaceRatio"])if(n in s)if(typeof s[n]!="number"||!isFinite(s[n]))e.push(`${n} must be a finite number.`);else{const o=s[n];o<=1&&e.push(`${n} must be > 1 (got ${o}).`);const r=n==="typeRatio"?1.3:2;o>r&&i.push(`${n} = ${o} is very high (max ${r}); scales may be extreme.`)}if("viewportMin"in s&&"viewportMax"in s){const n=s.viewportMin,o=s.viewportMax;typeof n=="number"&&typeof o=="number"&&n>=o&&e.push(`viewportMin (${n}) must be less than viewportMax (${o}).`)}if("angles"in s)if(typeof s.angles!="object"||s.angles===null)e.push("angles must be an object.");else{const n=s.angles;for(const o of["analogous","complementary","splitComplementary","triadic"])if(o in n)if(typeof n[o]!="number"||!isFinite(n[o]))e.push(`angles.${o} must be a finite number.`);else{const r=n[o];(r<0||r>360)&&i.push(`angles.${o} = ${r} is outside 0\u2013360.`)}}if("semanticHues"in s)if(typeof s.semanticHues!="object"||s.semanticHues===null)e.push("semanticHues must be an object.");else{const n=s.semanticHues;for(const o of["danger","success","warning"])if(o in n)if(typeof n[o]!="number"||!isFinite(n[o]))e.push(`semanticHues.${o} must be a finite number.`);else{const r=n[o];(r<0||r>360)&&i.push(`semanticHues.${o} = ${r} is outside 0\u2013360.`)}}if("variantChroma"in s)if(typeof s.variantChroma!="object"||s.variantChroma===null)e.push("variantChroma must be an object.");else{const n=s.variantChroma;for(const o of ce)if(o in n)if(typeof n[o]!="number"||!isFinite(n[o]))e.push(`variantChroma["${o}"] must be a finite number.`);else{const r=n[o];r<0&&e.push(`variantChroma["${o}"] must be \u2265 0 (got ${r}).`),r>v&&i.push(`variantChroma["${o}"] = ${r} exceeds ${v}.`)}}if("lightness"in s)if(typeof s.lightness!="object"||s.lightness===null)e.push("lightness must be an object.");else{const n=s.lightness;for(const o of x)if(o in n)if(typeof n[o]!="number"||!isFinite(n[o]))e.push(`lightness.${o} must be a finite number.`);else{const r=n[o];(r<0||r>1)&&e.push(`lightness.${o} must be 0\u20131 (got ${r}).`)}}if("chroma"in s)if(typeof s.chroma!="object"||s.chroma===null)e.push("chroma must be an object.");else{const n=s.chroma;for(const o of I)if(o in n){const r=n[o];if(typeof r!="object"||r===null){e.push(`chroma.${o} must be { min, max }.`);continue}const c=r;(typeof c.min!="number"||c.min<0)&&e.push(`chroma.${o}.min must be \u2265 0.`),(typeof c.max!="number"||c.max<0||c.max>v)&&e.push(`chroma.${o}.max must be 0\u2013${v}.`),typeof c.min=="number"&&typeof c.max=="number"&&c.min>c.max&&e.push(`chroma.${o}.min (${c.min}) must be \u2264 max (${c.max}).`)}}if("anchors"in s)if(typeof s.anchors!="object"||s.anchors===null||Array.isArray(s.anchors))e.push("anchors must be an object of named colors.");else for(const[n,o]of Object.entries(s.anchors))if(d(n)?L.test(n)||e.push(`anchors: "${n}" is not a valid anchor name; use a lowercase slug (letters, digits, hyphens).`):e.push(`anchors: "${n}" is a reserved JavaScript property name and cannot be an anchor name; rename it.`),T.includes(n)&&e.push(`anchors: "${n}" collides with a reserved color source name.`),typeof o=="string")O(o)||e.push(`anchors.${n} is not a valid CSS color: "${o}". Accepted forms: ${j}.`);else if(typeof o=="object"&&o!==null&&!Array.isArray(o)){const r=o;typeof r.color!="string"&&e.push(`anchors.${n} must declare its base "color".`);for(const[c,g]of Object.entries(r))d(c)?c!=="color"&&!L.test(c)&&e.push(`anchors.${n}: "${c}" is not a valid slot name; use a lowercase slug.`):e.push(`anchors.${n}: "${c}" is a reserved JavaScript property name and cannot be a slot name; rename it.`),typeof g!="string"?e.push(`anchors.${n}.${c} must be a CSS color string.`):O(g)||e.push(`anchors.${n}.${c} is not a valid CSS color: "${g}". Accepted forms: ${j}.`)}else e.push(`anchors.${n} must be a color string or a { color, \u2026slots } object.`);const m=new Map;if("anchors"in s&&typeof s.anchors=="object"&&s.anchors!==null&&!Array.isArray(s.anchors))for(const[n,o]of Object.entries(s.anchors))m.set(n,o);function h(n,o){if(!n.startsWith("anchor:")){T.includes(n)||e.push(`${o} must be one of: ${T.join(", ")}, or a declared anchor as anchor:<name> / anchor:<name>.<slot>.`);return}const r=te(n);if(!r){e.push(`${o} "${n}" is not valid anchor syntax; use anchor:<name> or anchor:<name>.<slot>.`);return}if(!m.has(r.name)){const c=[...m.keys()];e.push(`${o} references undeclared anchor "${r.name}". Declared anchors: ${c.length>0?c.join(", "):"(none)"}.`);return}if(r.slot!==void 0){const c=m.get(r.name);if(typeof(typeof c=="object"&&c!==null&&!Array.isArray(c)?c[r.slot]:void 0)!="string"){const y=typeof c=="object"&&c!==null?Object.keys(c).filter(b=>b!=="color"):[];e.push(`${o} references unknown slot "${r.slot}" on anchor "${r.name}". Declared slots: ${y.length>0?y.join(", "):"(none)"}.`)}}}if("roles"in s)if(typeof s.roles!="object"||s.roles===null||Array.isArray(s.roles))e.push("roles must be an object.");else{const n=s.roles;for(const[o,r]of Object.entries(n)){if(!E.includes(o)){e.push(`roles.${o} is not a role; expected one of: ${E.join(", ")}. (The status family is reserved and is not a role.)`);continue}const c=o,g=N[c];if(typeof r=="string"){h(r,`roles.${c}`);continue}if(typeof r!="object"||r===null||Array.isArray(r)){e.push(`roles.${c} must be a color source or a { color, \u2026slots } object.`);continue}const y=r;typeof y.color!="string"&&e.push(`roles.${c} must declare its base "color".`);for(const[b,S]of Object.entries(y)){if(!Object.prototype.hasOwnProperty.call(g,b)||!d(b)){const k=Object.keys(g).filter($=>$!=="color");e.push(`roles.${c}.${b} is not a slot of the ${c} role. Declared slots: ${k.length>0?k.join(", "):"(none)"}.`);continue}typeof S!="string"?e.push(`roles.${c}.${b} must be a color source string.`):h(S,`roles.${c}.${b}`)}}}if("semanticMappings"in s)if(typeof s.semanticMappings!="object"||s.semanticMappings===null)e.push("semanticMappings must be an object.");else{const n=s.semanticMappings;for(const o of I)if(o in n){const r=n[o];if(typeof r!="object"||r===null){e.push(`semanticMappings.${o} must be { source, lightness }.`);continue}const c=r;typeof c.source!="string"?e.push(`semanticMappings.${o}.source must be a string.`):h(c.source,`semanticMappings.${o}.source`),(typeof c.lightness!="string"||!x.includes(c.lightness))&&e.push(`semanticMappings.${o}.lightness must be one of: ${x.join(", ")}.`)}}for(const n of["pageBackgroundImage","boxBackgroundImage","vellumBackgroundImage"])n in s&&typeof s[n]!="string"&&e.push(`${n} must be a string.`);for(const n of["pageBackgroundImageOpacity","boxBackgroundImageOpacity","vellumOpacity","vellumBackgroundImageOpacity"])if(n in s)if(typeof s[n]!="number"||!isFinite(s[n]))e.push(`${n} must be a finite number.`);else{const o=s[n];(o<0||o>1)&&e.push(`${n} must be 0\u20131 (got ${o}).`)}return{valid:e.length===0,errors:e,warnings:i}}const ye=["anchors","angles","roles","chroma","lightness","semanticHues","semanticMappings","variantChroma"];function be(t,e){const i={};for(const[a,u]of Object.entries(t))d(a)&&(i[a]=u);for(const[a,u]of Object.entries(e))u!==void 0&&d(a)&&(i[a]=u);for(const a of ye){const u=t[a],s=e[a];if(u&&typeof u=="object"&&!Array.isArray(u)&&s&&typeof s=="object"&&!Array.isArray(s)){if(a==="anchors"){i[a]=U(u,s);continue}const l={};for(const[f,p]of Object.entries(u))d(f)&&(l[f]=p);for(const[f,p]of Object.entries(s))p!==void 0&&d(f)&&(l[f]=p);i[a]=l}}return i}function Ce(...t){let e={};for(const i of t){if(!i)continue;const a=me(i);a&&(e=be(e,a))}return H(e)}function G(t){return t.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r")}const V={borderRadius:.1,fontBody:'"Noto Sans", sans-serif',fontWeightBody:"normal",fontHeadings:'"Inika", serif',fontWeightHeadings:"normal",fontBrand:'"Inika", serif',fontWeightBrand:"normal",fontMonospace:'"JetBrains Mono", monospace',fontWeightMonospace:"normal",seedColor:"oklch(.07 0.15 216)"};function Ae(t){return H({...V,pageBackgroundImage:`url("${G(t)}")`,pageBackgroundImageOpacity:.5})}function Me(t){return H({...V,pageBackgroundImage:`url("${G(t)}")`,pageBackgroundImageOpacity:.55})}export{L as ANCHOR_SLUG_PATTERN,T as COLOR_SOURCES,le as DEFAULT_DARK_LIGHTNESS,pe as DEFAULT_DARK_THEME,ue as DEFAULT_LIGHT_LIGHTNESS,fe as DEFAULT_LIGHT_THEME,w as DEFAULT_SEMANTIC_MAPPINGS,x as LIGHTNESS_KEYS,ye as NESTED_THEME_KEYS,E as ROLE_NAMES,re as ROLE_PAIRED_INK,N as ROLE_TOKEN_PLAN,I as SEMANTIC_COLOR_NAMES,F as TOKEN_PAIRINGS,ce as VARIANT_COLOR_SOURCES,Me as buildTaprootDarkTheme,Ae as buildTaprootLightTheme,D as compileRoles,H as encodeTheme,Ce as layerThemes,be as mergePartials,Oe as mergeTheme,te as parseAnchorSource,me as parseTheme,xe as resolveAnchorColor,Se as semanticToCSS,ve as validateTheme};
|
|
1
|
+
import{ACCEPTED_COLOR_FORMS as T,apcaContrast as ae,deriveSemantic as re,parseCssColor as v,parseOklch as ie,serializeOklch as ce}from"./color-engine.js";import{computeVariants as ue,parseAnchorSource as le,resolveAnchorColor as fe,resolveMappingSource as pe}from"./variant-engine.js";import{auditDataPalette as me,DATA_SERIES_KEYS as B,DEFAULT_DATA_PALETTE as H,DEFAULT_DATA_RAMP_STEPS as ge,MAX_DATA_RAMP_STEPS as P,MIN_DATA_RAMP_LIGHTNESS_STEP as U,MIN_DATA_RAMP_STEPS as L}from"./data-colors.js";const C=/^[a-z][a-z0-9-]*$/;function G(n){return le(n)}function de(n,e){return fe(n,e)}function he(n,e){const c=G(n);if(c){const a=de(e,c);return a&&v(a)?a:null}return v(n)?n:null}const D=["canvas","ink","accent","action","structure"],V={canvas:{color:[["background","surface"],["layer1","raised1"],["layer2","raised2"],["layer3","raised3"],["layer4","raised4"]]},ink:{color:[["text","text"],["inputSelection","text"]],heading:[["headings","muted"],["headingsHover","ink"]]},accent:{color:[["linkHoverBg","raised2"],["inputSelectionBg","raised2"],["inputCaret","ink"]],text:[["link","accent"],["linkHover","text"]]},action:{color:[["actionBackground","muted"]],ink:[["actionText","surface"]]},structure:{color:[["border","border"],["shadow","shadow"]]}},ye=new Set(["action.color"]),be={canvas:"background",ink:"text",accent:"link",action:"actionBackground",structure:"border"},$e={"action.ink":{role:"canvas",slot:"color"}},Se=.45;function J(n,e){const c=Y.actionText,a=[...R].sort((m,h)=>n[m]-n[h]||R.indexOf(m)-R.indexOf(h)),u=e?a.filter(m=>e(m)>=c.targetLc):a,s=u.length>0?u:a;let l,f=1/0;for(const m of s){const h=Math.abs(n[m]-Se);h<f&&(f=h,l=m)}return l??"muted"}function ke(n,e){const c=e[n]>.5;let a=R[0];for(const u of R)(c?e[u]<e[a]:e[u]>e[a])&&(a=u);return a}function _(n,e){if(n===void 0)return;if(typeof n=="string")return e==="color"?n:void 0;const c=n[e];return typeof c=="string"?c:void 0}function q(n,e,c,a={}){const u={},s={};for(const[l,f]of Object.entries(a.explicitMappings??{}))f!==void 0&&(s[l]=f.lightness);for(const l of D){const f=n[l];if(f!==void 0)for(const[m,h]of Object.entries(V[l])){const S=$e[`${l}.${m}`];let y=_(f,m),A=!1;if(y===void 0&&(S&&(y=_(n[S.role],S.slot),y??=c[be[S.role]]?.source,A=y!==void 0),y??=_(f,"color")),y!==void 0)for(const[t,o]of h){let r=o;if(ye.has(`${l}.${m}`))r=J(e,a.actionSurfaceContrast?i=>a.actionSurfaceContrast(y,i):void 0);else if(A&&S){const i=Y[t],p=(i&&s[i.bg])??J(e,a.actionSurfaceContrast?d=>a.actionSurfaceContrast(_(f,"color"),d):void 0);r=ke(p,e)}u[t]={source:y,lightness:r}}}}return u}const Y={text:{bg:"background",targetLc:75},dangerText:{bg:"background",targetLc:75},headings:{bg:"background",targetLc:60},headingsHover:{bg:"background",targetLc:60},link:{bg:"background",targetLc:75},linkHover:{bg:"background",targetLc:75},actionText:{bg:"actionBackground",targetLc:75},inputCaret:{bg:"layer2",targetLc:60},inputSelection:{bg:"inputSelectionBg",targetLc:60}},N=["background","layer1","layer2","layer3","layer4","actionBackground","actionText","border","shadow","text","dangerText","headings","headingsHover","link","linkHover","linkHoverBg","inputCaret","inputSelection","inputSelectionBg"],F=["primary","analogous-left","analogous-right","complementary","split-complementary-left","split-complementary-right","triadic-left","triadic-right","danger","success","warning"],Ae=["analogous-left","analogous-right","complementary","split-complementary-left","split-complementary-right","triadic-left","triadic-right","danger","success","warning"],R=["surface","raised1","raised2","raised3","raised4","accent","muted","text","border","ink","shadow"],xe={surface:.99,raised1:.97,raised2:.9,raised3:.8,raised4:.72,accent:.5,muted:.45,text:.35,border:.3,ink:.25,shadow:.2},ve={surface:.15,raised1:.2,raised2:.3,raised3:.4,raised4:.36,accent:.6,muted:.75,text:.85,border:.7,ink:.95,shadow:.6},W={background:{source:"primary",lightness:"surface"},layer1:{source:"primary",lightness:"raised1"},layer2:{source:"primary",lightness:"raised2"},layer3:{source:"primary",lightness:"raised3"},layer4:{source:"primary",lightness:"raised4"},actionBackground:{source:"primary",lightness:"raised3"},actionText:{source:"primary",lightness:"ink"},border:{source:"primary",lightness:"border"},shadow:{source:"primary",lightness:"shadow"},text:{source:"primary",lightness:"text"},dangerText:{source:"danger",lightness:"text"},headings:{source:"primary",lightness:"muted"},headingsHover:{source:"primary",lightness:"text"},link:{source:"complementary",lightness:"accent"},linkHover:{source:"complementary",lightness:"text"},linkHoverBg:{source:"triadic-left",lightness:"raised2"},inputCaret:{source:"triadic-right",lightness:"ink"},inputSelection:{source:"complementary",lightness:"text"},inputSelectionBg:{source:"triadic-left",lightness:"raised2"}},O=.4;function z(){const n={};for(const e of N)n[e]={min:0,max:O};return n}const X={seedColor:"oklch(0.7 0.125 216)",fontBody:"",fontHeadings:"",fontBrand:"",fontMonospace:"",fontWeightBody:"normal",fontWeightHeadings:"bold",fontWeightBrand:"bold",fontWeightMonospace:"normal",stylesheets:[],rootFontSize:16,typeRatio:1.25,spaceRatio:1.618,borderRadius:.2,viewportMin:320,viewportMax:1200,angles:{analogous:30,complementary:180,splitComplementary:30,triadic:120},semanticHues:{danger:27,success:150,warning:90},variantChroma:{},chroma:z(),semanticMappings:{...W},anchors:{},roles:{},dataPalette:{...H},dataRamps:{}},Z={...X,chroma:z(),semanticMappings:{...W},anchors:{},roles:{},dataPalette:{...H},dataRamps:{},lightness:{...xe}},Re={...X,chroma:z(),semanticMappings:{...W},anchors:{},roles:{},dataPalette:{...H},dataRamps:{},lightness:{...ve}},I=new WeakMap;I.set(Z,new Set),I.set(Re,new Set);const Q=new Set(["__proto__","constructor","prototype"]);function g(n){return!Q.has(n)}function Ce(n,e){return Q.has(n)?void 0:e}function Le(n){return`--esp-color-${n.replace(/([A-Z])/g,"-$1").replace(/(\d)/g,"-$1").toLowerCase()}`}function Oe(n){try{const e=atob(n),c=JSON.parse(e,Ce);return typeof c!="object"||c===null||Array.isArray(c)?null:c}catch{return null}}function K(n){return btoa(JSON.stringify(n))}function w(n){if(ie(n))return n;const e=v(n);return e?ce(e):n}function ee(n,e){const c={};for(const[a,u]of Object.entries(n))g(a)&&(c[a]=u);if(!e)return c;for(const[a,u]of Object.entries(e)){if(u===void 0||!g(a))continue;const s=c[a];if(s!==void 0&&typeof u=="object"&&u!==null){const l={};if(typeof s=="string")l.color=s;else for(const[f,m]of Object.entries(s))g(f)&&(l[f]=m);for(const[f,m]of Object.entries(u))m!==void 0&&g(f)&&(l[f]=m);c[a]=l;continue}c[a]=u}return c}function Me(n){const e={};for(const[c,a]of Object.entries(n)){if(!g(c))continue;if(typeof a=="string"){e[c]=w(a);continue}const u={};for(const[s,l]of Object.entries(a))g(s)&&(u[s]=typeof l=="string"?w(l):l);e[c]=u}return e}function M(n){return typeof n!="string"?"":n.startsWith("anchor:")?n:w(n)}function je(n){const e={};for(const c of B)e[c]=M(n[c]);return e}function te(n,e){const c={};for(const[a,u]of Object.entries(n))g(a)&&C.test(a)&&u&&typeof u=="object"&&!Array.isArray(u)&&(c[a]={...u});if(!e)return c;for(const[a,u]of Object.entries(e)){if(!g(a)||!C.test(a)||!u||typeof u!="object"||Array.isArray(u))continue;const s=c[a],l=s!==void 0&&u.type!==void 0&&u.type!==s.type;c[a]={...l?{}:s??{},...u}}return c}function Ee(n){const e={};for(const[c,a]of Object.entries(n))if(g(c)){if(a.type==="sequential"&&typeof a.source=="string"){e[c]={...a,source:M(a.source)};continue}if(a.type==="diverging"&&typeof a.start=="string"&&typeof a.end=="string"){e[c]={...a,start:M(a.start),end:M(a.end),...typeof a.neutral=="string"?{neutral:M(a.neutral)}:{}};continue}e[c]={...a}}return e}function ne(n){const e=v(n.seedColor);if(!e)return;const c=ue(e,n);return(a,u)=>{const s=pe(a,c,n.anchors)??c.primary,l=n.chroma.actionBackground,f=re(s,n.lightness[u],l.min,l.max),m={l:f.l>.5?0:1,c:0,h:0};return Math.abs(ae(m,f))}}function Te(n){const e=I.get(n);if(e)return new Set(e);const c=new Set,a=q(n.roles,n.lightness,n.semanticMappings,{actionSurfaceContrast:ne(n)});for(const[u,s]of Object.entries(a)){const l=n.semanticMappings[u];(l.source!==s.source||l.lightness!==s.lightness)&&c.add(u)}return c}function Be(n,e){const c={...n.roles,...e.roles},a={...n.lightness,...e.lightness},u=Me(ee(n.anchors,e.anchors)),s=typeof e.seedColor=="string"?w(e.seedColor):n.seedColor,l=e.semanticMappings,f={...n.angles,...e.angles},m={...n.semanticHues,...e.semanticHues},h={...n.variantChroma,...e.variantChroma},S=j(n.chroma,e.chroma),y=je(j(n.dataPalette,e.dataPalette)),A=Ee(te(n.dataRamps,e.dataRamps)),t=Te(n),o=new Set(t),r={};for(const k of t)r[k]=n.semanticMappings[k];for(const[k,E]of Object.entries(l??{}))E!==void 0&&(o.add(k),r[k]=E);const i=j(n.semanticMappings,l),p=ne({angles:f,anchors:u,chroma:S,lightness:a,seedColor:s,semanticHues:m,variantChroma:h}),d=q(c,a,i,{explicitMappings:r,actionSurfaceContrast:p}),b={};for(const[k,E]of Object.entries(d))o.has(k)||(b[k]=E);const x=j(j(n.semanticMappings,b),l),$={...n,seedColor:s,fontBody:e.fontBody??n.fontBody,fontHeadings:e.fontHeadings??n.fontHeadings,fontBrand:e.fontBrand??n.fontBrand,fontMonospace:e.fontMonospace??n.fontMonospace,fontWeightBody:String(e.fontWeightBody??n.fontWeightBody),fontWeightHeadings:String(e.fontWeightHeadings??n.fontWeightHeadings),fontWeightBrand:String(e.fontWeightBrand??n.fontWeightBrand),fontWeightMonospace:String(e.fontWeightMonospace??n.fontWeightMonospace),stylesheets:e.stylesheets??[...n.stylesheets],rootFontSize:e.rootFontSize??n.rootFontSize,typeRatio:e.typeRatio??n.typeRatio,spaceRatio:e.spaceRatio??n.spaceRatio,borderRadius:e.borderRadius??n.borderRadius,viewportMin:e.viewportMin??n.viewportMin,viewportMax:e.viewportMax??n.viewportMax,angles:f,semanticHues:m,variantChroma:h,lightness:a,chroma:S,semanticMappings:x,anchors:u,roles:c,dataPalette:y,dataRamps:A};return e.pageBackgroundImage!==void 0&&($.pageBackgroundImage=e.pageBackgroundImage),e.pageBackgroundImageOpacity!==void 0&&($.pageBackgroundImageOpacity=e.pageBackgroundImageOpacity),e.boxBackgroundImage!==void 0&&($.boxBackgroundImage=e.boxBackgroundImage),e.boxBackgroundImageOpacity!==void 0&&($.boxBackgroundImageOpacity=e.boxBackgroundImageOpacity),e.vellumOpacity!==void 0&&($.vellumOpacity=e.vellumOpacity),e.vellumBackgroundImage!==void 0&&($.vellumBackgroundImage=e.vellumBackgroundImage),e.vellumBackgroundImageOpacity!==void 0&&($.vellumBackgroundImageOpacity=e.vellumBackgroundImageOpacity),I.set($,new Set(o)),$}function j(n,e){if(!e)return{...n};const c={...n};for(const a of Object.keys(e)){const u=e[a];u!==void 0&&(c[a]=u)}return c}function De(n){const e=[],c=[];let a;try{a=atob(n)}catch{return e.push("Failed to decode Base64 string."),{valid:!1,errors:e,warnings:c}}let u;try{u=JSON.parse(a)}catch{return e.push("Decoded string is not valid JSON."),{valid:!1,errors:e,warnings:c}}if(typeof u!="object"||u===null||Array.isArray(u))return e.push("Theme must be a JSON object."),{valid:!1,errors:e,warnings:c};const s=u;"seedColor"in s&&(typeof s.seedColor!="string"?e.push("seedColor must be a string."):v(s.seedColor)||e.push(`seedColor is not a valid CSS color: "${s.seedColor}". Accepted forms: ${T}.`));for(const t of["fontBody","fontHeadings","fontBrand","fontMonospace"])t in s&&typeof s[t]!="string"&&e.push(`${t} must be a string.`);const l=["normal","bold","lighter","bolder"],f=["inherit","initial","unset","revert","revert-layer"];for(const t of["fontWeightBody","fontWeightHeadings","fontWeightBrand","fontWeightMonospace"])if(t in s){const o=s[t];if(typeof o=="number")(o<1||o>1e3)&&e.push(`${t} numeric value must be 1\u20131000 (got ${o}).`);else if(typeof o=="string"){const r=l.includes(o)||f.includes(o);if(/^\d+$/.test(o)){const p=Number(o);(p<1||p>1e3)&&e.push(`${t} numeric value must be 1\u20131000 (got "${o}").`)}else r||c.push(`${t} = "${o}" is not a standard font-weight value.`)}else e.push(`${t} must be a string or number.`)}"stylesheets"in s&&(Array.isArray(s.stylesheets)?s.stylesheets.some(t=>typeof t!="string")&&e.push("Every entry in stylesheets must be a string."):e.push("stylesheets must be an array of strings."));const m=[["rootFontSize",1,100],["borderRadius",0,10],["viewportMin",100,1e4],["viewportMax",200,1e4]];for(const[t,o,r]of m)if(t in s)if(typeof s[t]!="number"||!isFinite(s[t]))e.push(`${t} must be a finite number.`);else{const i=s[t];o!==void 0&&i<o&&e.push(`${t} must be \u2265 ${o} (got ${i}).`),r!==void 0&&i>r&&c.push(`${t} = ${i} is unusually high (max ${r}).`)}for(const t of["typeRatio","spaceRatio"])if(t in s)if(typeof s[t]!="number"||!isFinite(s[t]))e.push(`${t} must be a finite number.`);else{const o=s[t];o<=1&&e.push(`${t} must be > 1 (got ${o}).`);const r=t==="typeRatio"?1.3:2;o>r&&c.push(`${t} = ${o} is very high (max ${r}); scales may be extreme.`)}if("viewportMin"in s&&"viewportMax"in s){const t=s.viewportMin,o=s.viewportMax;typeof t=="number"&&typeof o=="number"&&t>=o&&e.push(`viewportMin (${t}) must be less than viewportMax (${o}).`)}if("angles"in s)if(typeof s.angles!="object"||s.angles===null)e.push("angles must be an object.");else{const t=s.angles;for(const o of["analogous","complementary","splitComplementary","triadic"])if(o in t)if(typeof t[o]!="number"||!isFinite(t[o]))e.push(`angles.${o} must be a finite number.`);else{const r=t[o];(r<0||r>360)&&c.push(`angles.${o} = ${r} is outside 0\u2013360.`)}}if("semanticHues"in s)if(typeof s.semanticHues!="object"||s.semanticHues===null)e.push("semanticHues must be an object.");else{const t=s.semanticHues;for(const o of["danger","success","warning"])if(o in t)if(typeof t[o]!="number"||!isFinite(t[o]))e.push(`semanticHues.${o} must be a finite number.`);else{const r=t[o];(r<0||r>360)&&c.push(`semanticHues.${o} = ${r} is outside 0\u2013360.`)}}if("variantChroma"in s)if(typeof s.variantChroma!="object"||s.variantChroma===null)e.push("variantChroma must be an object.");else{const t=s.variantChroma;for(const o of Ae)if(o in t)if(typeof t[o]!="number"||!isFinite(t[o]))e.push(`variantChroma["${o}"] must be a finite number.`);else{const r=t[o];r<0&&e.push(`variantChroma["${o}"] must be \u2265 0 (got ${r}).`),r>O&&c.push(`variantChroma["${o}"] = ${r} exceeds ${O}.`)}}if("lightness"in s)if(typeof s.lightness!="object"||s.lightness===null)e.push("lightness must be an object.");else{const t=s.lightness;for(const o of R)if(o in t)if(typeof t[o]!="number"||!isFinite(t[o]))e.push(`lightness.${o} must be a finite number.`);else{const r=t[o];(r<0||r>1)&&e.push(`lightness.${o} must be 0\u20131 (got ${r}).`)}}if("chroma"in s)if(typeof s.chroma!="object"||s.chroma===null)e.push("chroma must be an object.");else{const t=s.chroma;for(const o of N)if(o in t){const r=t[o];if(typeof r!="object"||r===null){e.push(`chroma.${o} must be { min, max }.`);continue}const i=r;(typeof i.min!="number"||i.min<0)&&e.push(`chroma.${o}.min must be \u2265 0.`),(typeof i.max!="number"||i.max<0||i.max>O)&&e.push(`chroma.${o}.max must be 0\u2013${O}.`),typeof i.min=="number"&&typeof i.max=="number"&&i.min>i.max&&e.push(`chroma.${o}.min (${i.min}) must be \u2264 max (${i.max}).`)}}if("anchors"in s)if(typeof s.anchors!="object"||s.anchors===null||Array.isArray(s.anchors))e.push("anchors must be an object of named colors.");else for(const[t,o]of Object.entries(s.anchors))if(g(t)?C.test(t)||e.push(`anchors: "${t}" is not a valid anchor name; use a lowercase slug (letters, digits, hyphens).`):e.push(`anchors: "${t}" is a reserved JavaScript property name and cannot be an anchor name; rename it.`),F.includes(t)&&e.push(`anchors: "${t}" collides with a reserved color source name.`),typeof o=="string")v(o)||e.push(`anchors.${t} is not a valid CSS color: "${o}". Accepted forms: ${T}.`);else if(typeof o=="object"&&o!==null&&!Array.isArray(o)){const r=o;typeof r.color!="string"&&e.push(`anchors.${t} must declare its base "color".`);for(const[i,p]of Object.entries(r))g(i)?i!=="color"&&!C.test(i)&&e.push(`anchors.${t}: "${i}" is not a valid slot name; use a lowercase slug.`):e.push(`anchors.${t}: "${i}" is a reserved JavaScript property name and cannot be a slot name; rename it.`),typeof p!="string"?e.push(`anchors.${t}.${i} must be a CSS color string.`):v(p)||e.push(`anchors.${t}.${i} is not a valid CSS color: "${p}". Accepted forms: ${T}.`)}else e.push(`anchors.${t} must be a color string or a { color, \u2026slots } object.`);const h=new Map;if("anchors"in s&&typeof s.anchors=="object"&&s.anchors!==null&&!Array.isArray(s.anchors))for(const[t,o]of Object.entries(s.anchors))h.set(t,o);function S(t,o){const r=G(t);if(!r){e.push(`${o} "${t}" is not valid anchor syntax; use anchor:<name> or anchor:<name>.<slot>.`);return}if(!h.has(r.name)){const i=[...h.keys()];e.push(`${o} references undeclared anchor "${r.name}". Declared anchors: ${i.length>0?i.join(", "):"(none)"}.`);return}if(r.slot!==void 0){const i=h.get(r.name);if(typeof(typeof i=="object"&&i!==null&&!Array.isArray(i)?i[r.slot]:void 0)!="string"){const d=typeof i=="object"&&i!==null?Object.keys(i).filter(b=>b!=="color"):[];e.push(`${o} references unknown slot "${r.slot}" on anchor "${r.name}". Declared slots: ${d.length>0?d.join(", "):"(none)"}.`)}}}function y(t,o){if(t.startsWith("anchor:")){S(t,o);return}F.includes(t)||e.push(`${o} must be one of: ${F.join(", ")}, or a declared anchor as anchor:<name> / anchor:<name>.<slot>.`)}function A(t,o){if(t.startsWith("anchor:")){S(t,o);return}v(t)||e.push(`${o} is not a valid CSS color: "${t}". Accepted forms: ${T}, or a declared anchor as anchor:<name> / anchor:<name>.<slot>.`)}if("dataPalette"in s)if(typeof s.dataPalette!="object"||s.dataPalette===null||Array.isArray(s.dataPalette))e.push("dataPalette must be an object with series1\u2013series8 color values.");else{const t=s.dataPalette;for(const[o,r]of Object.entries(t)){if(!B.includes(o)){e.push(`dataPalette.${o} is not a series slot; expected one of: ${B.join(", ")}.`);continue}typeof r!="string"?e.push(`dataPalette.${o} must be a CSS color or anchor reference string.`):A(r,`dataPalette.${o}`)}}if("dataRamps"in s)if(typeof s.dataRamps!="object"||s.dataRamps===null||Array.isArray(s.dataRamps))e.push("dataRamps must be an object of named ramp declarations.");else for(const[t,o]of Object.entries(s.dataRamps)){if(g(t)?C.test(t)||e.push(`dataRamps: "${t}" is not a valid ramp name; use a lowercase slug (letters, digits, hyphens).`):e.push(`dataRamps: "${t}" is a reserved JavaScript property name and cannot be a ramp name; rename it.`),typeof o!="object"||o===null||Array.isArray(o)){e.push(`dataRamps.${t} must be a sequential or diverging ramp object.`);continue}const r=o,i=r.steps??ge;if((typeof i!="number"||!Number.isInteger(i)||i<L||i>P)&&e.push(`dataRamps.${t}.steps must be an integer from ${L} through ${P}.`),r.type==="sequential"){typeof r.source!="string"?e.push(`dataRamps.${t}.source must be a CSS color or anchor reference string.`):A(r.source,`dataRamps.${t}.source`);const p=r.lightnessStart??.95,d=r.lightnessEnd??.25;for(const[b,x]of[["lightnessStart",p],["lightnessEnd",d]])(typeof x!="number"||!Number.isFinite(x)||x<0||x>1)&&e.push(`dataRamps.${t}.${b} must be a finite number from 0 through 1.`);typeof p=="number"&&typeof d=="number"&&p<=d?e.push(`dataRamps.${t}.lightnessStart must be greater than lightnessEnd.`):typeof p=="number"&&Number.isFinite(p)&&typeof d=="number"&&Number.isFinite(d)&&typeof i=="number"&&Number.isInteger(i)&&i>=L&&i<=P&&(p-d)/(i-1)<=U&&e.push(`dataRamps.${t} lightness bounds must leave more than ${U} lightness between serialized stops.`);continue}if(r.type==="diverging"){typeof i=="number"&&Number.isInteger(i)&&i%2===0&&e.push(`dataRamps.${t}.steps must be odd so the neutral is the exact midpoint.`);for(const p of["start","end"])typeof r[p]!="string"?e.push(`dataRamps.${t}.${p} must be a CSS color or anchor reference string.`):A(r[p],`dataRamps.${t}.${p}`);"neutral"in r&&(typeof r.neutral!="string"?e.push(`dataRamps.${t}.neutral must be a CSS color or anchor reference string.`):A(r.neutral,`dataRamps.${t}.neutral`));continue}e.push(`dataRamps.${t}.type must be "sequential" or "diverging".`)}if("dataPalette"in s&&e.length===0){const t=Be(Z,s),o={};let r=!0;for(const i of B){const p=he(t.dataPalette[i],t.anchors);if(!p){r=!1;break}o[i]=p}if(r)for(const i of me(o))c.push(`dataPalette.${i.series[0]} and dataPalette.${i.series[1]} are only ${i.distance.toFixed(4)} apart under ${i.simulation} simulation (minimum ${i.threshold.toFixed(4)}); also distinguish the series with labels, shapes, or patterns.`)}if("roles"in s)if(typeof s.roles!="object"||s.roles===null||Array.isArray(s.roles))e.push("roles must be an object.");else{const t=s.roles;for(const[o,r]of Object.entries(t)){if(!D.includes(o)){e.push(`roles.${o} is not a role; expected one of: ${D.join(", ")}. (The status family is reserved and is not a role.)`);continue}const i=o,p=V[i];if(typeof r=="string"){y(r,`roles.${i}`);continue}if(typeof r!="object"||r===null||Array.isArray(r)){e.push(`roles.${i} must be a color source or a { color, \u2026slots } object.`);continue}const d=r;typeof d.color!="string"&&e.push(`roles.${i} must declare its base "color".`);for(const[b,x]of Object.entries(d)){if(!Object.prototype.hasOwnProperty.call(p,b)||!g(b)){const $=Object.keys(p).filter(k=>k!=="color");e.push(`roles.${i}.${b} is not a slot of the ${i} role. Declared slots: ${$.length>0?$.join(", "):"(none)"}.`);continue}typeof x!="string"?e.push(`roles.${i}.${b} must be a color source string.`):y(x,`roles.${i}.${b}`)}}}if("semanticMappings"in s)if(typeof s.semanticMappings!="object"||s.semanticMappings===null)e.push("semanticMappings must be an object.");else{const t=s.semanticMappings;for(const o of N)if(o in t){const r=t[o];if(typeof r!="object"||r===null){e.push(`semanticMappings.${o} must be { source, lightness }.`);continue}const i=r;typeof i.source!="string"?e.push(`semanticMappings.${o}.source must be a string.`):y(i.source,`semanticMappings.${o}.source`),(typeof i.lightness!="string"||!R.includes(i.lightness))&&e.push(`semanticMappings.${o}.lightness must be one of: ${R.join(", ")}.`)}}for(const t of["pageBackgroundImage","boxBackgroundImage","vellumBackgroundImage"])t in s&&typeof s[t]!="string"&&e.push(`${t} must be a string.`);for(const t of["pageBackgroundImageOpacity","boxBackgroundImageOpacity","vellumOpacity","vellumBackgroundImageOpacity"])if(t in s)if(typeof s[t]!="number"||!isFinite(s[t]))e.push(`${t} must be a finite number.`);else{const o=s[t];(o<0||o>1)&&e.push(`${t} must be 0\u20131 (got ${o}).`)}return{valid:e.length===0,errors:e,warnings:c}}const _e=["anchors","angles","dataPalette","dataRamps","roles","chroma","lightness","semanticHues","semanticMappings","variantChroma"];function Ie(n,e){const c={};for(const[a,u]of Object.entries(n))g(a)&&(c[a]=u);for(const[a,u]of Object.entries(e))u!==void 0&&g(a)&&(c[a]=u);for(const a of _e){const u=n[a],s=e[a];if(u&&typeof u=="object"&&!Array.isArray(u)&&s&&typeof s=="object"&&!Array.isArray(s)){if(a==="anchors"){c[a]=ee(u,s);continue}if(a==="dataRamps"){c[a]=te(u,s);continue}const l={};for(const[f,m]of Object.entries(u))g(f)&&(l[f]=m);for(const[f,m]of Object.entries(s))m!==void 0&&g(f)&&(l[f]=m);c[a]=l}}return c}function Ne(...n){let e={};for(const c of n){if(!c)continue;const a=Oe(c);a&&(e=Ie(e,a))}return K(e)}function oe(n){return n.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r")}const se={borderRadius:.1,fontBody:'"Noto Sans", sans-serif',fontWeightBody:"normal",fontHeadings:'"Inika", serif',fontWeightHeadings:"normal",fontBrand:'"Inika", serif',fontWeightBrand:"normal",fontMonospace:'"JetBrains Mono", monospace',fontWeightMonospace:"normal",seedColor:"oklch(.07 0.15 216)"};function Fe(n){return K({...se,pageBackgroundImage:`url("${oe(n)}")`,pageBackgroundImageOpacity:.5})}function We(n){return K({...se,pageBackgroundImage:`url("${oe(n)}")`,pageBackgroundImageOpacity:.55})}export{C as ANCHOR_SLUG_PATTERN,F as COLOR_SOURCES,ve as DEFAULT_DARK_LIGHTNESS,Re as DEFAULT_DARK_THEME,xe as DEFAULT_LIGHT_LIGHTNESS,Z as DEFAULT_LIGHT_THEME,W as DEFAULT_SEMANTIC_MAPPINGS,R as LIGHTNESS_KEYS,_e as NESTED_THEME_KEYS,D as ROLE_NAMES,$e as ROLE_PAIRED_INK,V as ROLE_TOKEN_PLAN,N as SEMANTIC_COLOR_NAMES,Y as TOKEN_PAIRINGS,Ae as VARIANT_COLOR_SOURCES,We as buildTaprootDarkTheme,Fe as buildTaprootLightTheme,q as compileRoles,K as encodeTheme,Ne as layerThemes,Ie as mergePartials,Be as mergeTheme,G as parseAnchorSource,Oe as parseTheme,de as resolveAnchorColor,he as resolveDataColorSource,Le as semanticToCSS,De as validateTheme};
|
package/espalier.css-data.json
CHANGED
|
@@ -9,6 +9,38 @@
|
|
|
9
9
|
"name": "--esp-seed-color",
|
|
10
10
|
"description": "The OKLCH seed color string that drives the entire palette."
|
|
11
11
|
},
|
|
12
|
+
{
|
|
13
|
+
"name": "--esp-color-series-1",
|
|
14
|
+
"description": "First categorical data-series color."
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"name": "--esp-color-series-2",
|
|
18
|
+
"description": "Second categorical data-series color."
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "--esp-color-series-3",
|
|
22
|
+
"description": "Third categorical data-series color."
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "--esp-color-series-4",
|
|
26
|
+
"description": "Fourth categorical data-series color."
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "--esp-color-series-5",
|
|
30
|
+
"description": "Fifth categorical data-series color."
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "--esp-color-series-6",
|
|
34
|
+
"description": "Sixth categorical data-series color."
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "--esp-color-series-7",
|
|
38
|
+
"description": "Seventh categorical data-series color."
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"name": "--esp-color-series-8",
|
|
42
|
+
"description": "Eighth categorical data-series color."
|
|
43
|
+
},
|
|
12
44
|
|
|
13
45
|
{
|
|
14
46
|
"name": "--esp-color-primary",
|