@taprootio/espalier 3.2.0 → 3.4.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/custom-elements.json +4475 -3579
  3. package/dist/action-menu/esp-action-menu-item.d.ts +2 -1
  4. package/dist/action-menu/esp-action-menu-item.js +1 -1
  5. package/dist/action-menu/esp-action-menu.js +1 -1
  6. package/dist/button/esp-button-group.js +1 -1
  7. package/dist/cli/espalier.js +2 -0
  8. package/dist/cli/theme-check.js +2 -0
  9. package/dist/form/esp-form.d.ts +2 -2
  10. package/dist/form/esp-form.js +1 -1
  11. package/dist/header/esp-header-button.d.ts +1 -0
  12. package/dist/header/esp-header-button.js +2 -2
  13. package/dist/icons/icon-sprite.generated.d.ts +17 -0
  14. package/dist/icons/icon-sprite.generated.js +702 -0
  15. package/dist/icons/index.d.ts +40 -0
  16. package/dist/icons/index.js +1 -0
  17. package/dist/index.d.ts +5 -3
  18. package/dist/index.js +1 -1
  19. package/dist/pickers/esp-picker-item.js +3 -3
  20. package/dist/popover/esp-popover.js +2 -2
  21. package/dist/root/esp-root.d.ts +16 -0
  22. package/dist/root/helpers/compute-theme-properties.js +1 -1
  23. package/dist/root/helpers/data-companion-properties.js +1 -0
  24. package/dist/shared/document-sprite.js +1 -0
  25. package/dist/shared/esp-element-base.d.ts +1 -0
  26. package/dist/shared/esp-element-base.js +2 -2
  27. package/dist/shared/intent-values.d.ts +29 -0
  28. package/dist/shared/intent-values.js +1 -1
  29. package/dist/shared/theme-fit-report.d.ts +94 -4
  30. package/dist/shared/theme-fit-report.js +1 -1
  31. package/dist/shared/theme-swatches.d.ts +79 -0
  32. package/dist/shared/theme-swatches.js +1 -0
  33. package/dist/shared/theme.d.ts +36 -0
  34. package/dist/shared/theme.js +1 -1
  35. package/dist/shared/unsafe-keys.js +1 -0
  36. package/espalier.token-manifest.json +80 -0
  37. package/licenses/asset-provenance.json +9 -7
  38. package/package.json +8 -1
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @module icons
3
+ *
4
+ * The offline story for Espalier icons (ESP0176).
5
+ *
6
+ * A fully self-contained page — an email attachment, an artifact, a
7
+ * USB-stick deliverable — cannot fetch `/assets/icons.svg`, and the
8
+ * browser blocks `data:` URLs as `<use>` targets. This module ships the
9
+ * sprite as a string instead: inline it once, point the root at it with
10
+ * the same-document form of `icon-sprite-url`, and every component
11
+ * renders icons with zero network requests:
12
+ *
13
+ * ```js
14
+ * import { installIconSprite } from "@taprootio/espalier/icons";
15
+ *
16
+ * document.querySelector("esp-root")
17
+ * .setAttribute("icon-sprite-url", installIconSprite());
18
+ * ```
19
+ *
20
+ * The same-document form works for any sprite, not only this one: give
21
+ * your own `<svg id="brand-icons"><symbol id="…">…</symbol></svg>` an
22
+ * id, inline it, and set `icon-sprite-url="#brand-icons"` — components
23
+ * adopt the referenced symbols into their shadow roots, which is what
24
+ * makes same-document references work across shadow boundaries.
25
+ */
26
+ import { ICON_SPRITE, ICON_SPRITE_ID } from "./icon-sprite.generated.js";
27
+ export { ICON_SPRITE, ICON_SPRITE_ID };
28
+ /**
29
+ * Inline the Espalier sprite into a document (once — reruns are
30
+ * no-ops) and return the `icon-sprite-url` value that references it.
31
+ *
32
+ * The sprite lands at the end of `<body>` (or the document element
33
+ * before body exists), hidden and aria-hidden. Set the returned value
34
+ * on the root *after* installing, so components adopt from a sprite
35
+ * that is already present.
36
+ *
37
+ * @param target The document to install into; defaults to `document`.
38
+ * @returns The same-document sprite reference, `"#esp-icons"`.
39
+ */
40
+ export declare function installIconSprite(target?: Document): string;
@@ -0,0 +1 @@
1
+ import{ICON_SPRITE as r,ICON_SPRITE_ID as t}from"./icon-sprite.generated.js";function a(n=document){const e=n.getElementById(t);if(e){if(!(e.namespaceURI==="http://www.w3.org/2000/svg"&&e.localName==="svg"&&e.hasAttribute("data-esp-icon-sprite")))throw new Error(`installIconSprite: an unrelated <${e.localName}> already has id="${t}". Rename that element (the id belongs to the Espalier icon sprite) or inline the sprite under a different id and reference it directly.`);return`#${t}`}return(n.body??n.documentElement).insertAdjacentHTML("beforeend",r),`#${t}`}export{r as ICON_SPRITE,t as ICON_SPRITE_ID,a as installIconSprite};
package/dist/index.d.ts CHANGED
@@ -60,7 +60,7 @@ export * from "./search/esp-search.js";
60
60
  export * from "./status-indicator/esp-status-indicator.js";
61
61
  export * from "./tree/esp-tree.js";
62
62
  export * from "./tree/esp-tree-item.js";
63
- export { DEFAULT_ICON_SPRITE_URL, DEFAULT_ICON_VIEW_BOX, INTENT_VARIANTS, type EspalierIntentVariant, normalizeIntentVariant, getIconHref, getIconHrefForHost, getIconSpriteUrl, } from "./shared/intent-values.js";
63
+ export { DEFAULT_ICON_SPRITE_URL, DEFAULT_ICON_VIEW_BOX, INTENT_VARIANTS, type EspalierIntentVariant, normalizeIntentVariant, getIconHref, getIconHrefForHost, getIconSpriteUrl, getIconSpriteReference, type IconSpriteReference, } from "./shared/intent-values.js";
64
64
  export { EspalierElementBase } from "./shared/esp-element-base.js";
65
65
  export { type ValidationError, VALIDITY_CHANGED_EVENT, type ValidityChangedDetail, } from "./shared/validation.js";
66
66
  export { FormFieldController, type FormFieldControllerOptions, } from "./shared/form-field-controller.js";
@@ -73,8 +73,10 @@ export * from "./shared/events.js";
73
73
  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";
74
74
  export { calculatePhotoLayout, type LayoutImage, type PhotoRow, } from "./shared/justified-layout.js";
75
75
  export { type TypeaheadFetchItems } from "./pickers/types.js";
76
- 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";
76
+ export { type EspalierTheme, type PartialTheme, type PartialThemeContexts, type ThemeContext, type ThemeContexts, type VariantColorSource, encodeTheme, parseTheme, mergePartials, layerThemes, validateThemePair, resolveContextTheme, buildTaprootLightTheme, buildTaprootDarkTheme, NESTED_THEME_KEYS, } from "./shared/theme.js";
77
77
  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";
78
78
  export { WEIGHT_LABELS, extractWeights, normalizeWeight, bestAvailableWeight, extractFamily, getFallbackFont, } from "./shared/font-helpers.js";
79
79
  export { getGoogleFonts } from "./font-picker/esp-font-picker.js";
80
- export { themeFitReport, themeFitRows, printThemeFitReport, type ThemeFitReport, type ThemeFitToken, type ThemeFitApcaAction, type ThemeFitAnchor, type ThemeFitRow, } from "./shared/theme-fit-report.js";
80
+ export { ROOT_SURFACE, themeFitReport, themeFitRows, themeFitLints, themeFitReportSuite, printThemeFitReport, type ThemeFitReport, type ThemeFitReportOptions, type ThemeFitToken, type ThemeFitApcaAction, type ThemeFitAnchor, type ThemeFitRow, type ThemeFitLint, type ThemeFitSurfaceReport, type ThemeFitSuite, } from "./shared/theme-fit-report.js";
81
+ export { ICON_SPRITE, ICON_SPRITE_ID, installIconSprite } from "./icons/index.js";
82
+ export { deriveLightnessRamp, themeFromSwatches, type ThemeFromSwatchesOptions, type ThemeFromSwatchesResult, } from "./shared/theme-swatches.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"./section/esp-section.js";export*from"./stack/esp-stack.js";export*from"./row/esp-row.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 _r,DEFAULT_ICON_VIEW_BOX as Ar,INTENT_VARIANTS as Er,normalizeIntentVariant as lr,getIconHref as ir,getIconHrefForHost as Ir,getIconSpriteUrl as Sr}from"./shared/intent-values.js";import{EspalierElementBase as Dr}from"./shared/esp-element-base.js";import{VALIDITY_CHANGED_EVENT as nr}from"./shared/validation.js";import{FormFieldController as Lr}from"./shared/form-field-controller.js";import{traverseToClosest as Rr}from"./shared/utilities.js";import{showToast as Pr}from"./shared/toast-events.js";import{showFlyout as ur,closeFlyout as Mr}from"./shared/flyout-events.js";import{requestHelp as Or}from"./shared/help-events.js";import{getEspBus as Hr}from"./shared/bus-events.js";export*from"./shared/events.js";import{getImageDetails as Gr,releasePreviewUrl as br}from"./image-upload/image-helpers.js";import{calculatePhotoLayout as yr}from"./shared/justified-layout.js";import{encodeTheme as wr,parseTheme as Br,mergePartials as Yr,layerThemes as kr,validateThemePair as qr,buildTaprootLightTheme as zr,buildTaprootDarkTheme as Kr,NESTED_THEME_KEYS as Xr}from"./shared/theme.js";import{auditDataPalette as Jr,generateSequentialRamp as Qr,generateDivergingRamp as Zr,COLOR_VISION_SIMULATIONS as $r,DATA_SERIES_KEYS as ro,DEFAULT_DATA_PALETTE as oo,DEFAULT_DATA_RAMP_STEPS as eo,DEFAULT_DIVERGING_NEUTRAL as to,MAX_DATA_RAMP_STEPS as mo,MIN_DATA_COLOR_DISTANCE as po,MIN_DATA_RAMP_LIGHTNESS_STEP as fo,MIN_DATA_RAMP_STEPS as xo}from"./shared/data-colors.js";import{WEIGHT_LABELS as ao,extractWeights as _o,normalizeWeight as Ao,bestAvailableWeight as Eo,extractFamily as lo,getFallbackFont as io}from"./shared/font-helpers.js";import{getGoogleFonts as So}from"./font-picker/esp-font-picker.js";import{themeFitReport as Do,themeFitRows as go,printThemeFitReport as no}from"./shared/theme-fit-report.js";export{$r as COLOR_VISION_SIMULATIONS,ro as DATA_SERIES_KEYS,oo as DEFAULT_DATA_PALETTE,eo as DEFAULT_DATA_RAMP_STEPS,to as DEFAULT_DIVERGING_NEUTRAL,_r as DEFAULT_ICON_SPRITE_URL,Ar as DEFAULT_ICON_VIEW_BOX,Dr as EspalierElementBase,Lr as FormFieldController,Er as INTENT_VARIANTS,mo as MAX_DATA_RAMP_STEPS,po as MIN_DATA_COLOR_DISTANCE,fo as MIN_DATA_RAMP_LIGHTNESS_STEP,xo as MIN_DATA_RAMP_STEPS,Xr as NESTED_THEME_KEYS,nr as VALIDITY_CHANGED_EVENT,ao as WEIGHT_LABELS,Jr as auditDataPalette,Eo as bestAvailableWeight,Kr as buildTaprootDarkTheme,zr as buildTaprootLightTheme,yr as calculatePhotoLayout,Mr as closeFlyout,wr as encodeTheme,lo as extractFamily,_o as extractWeights,Zr as generateDivergingRamp,Qr as generateSequentialRamp,Hr as getEspBus,io as getFallbackFont,So as getGoogleFonts,ir as getIconHref,Ir as getIconHrefForHost,Sr as getIconSpriteUrl,Gr as getImageDetails,kr as layerThemes,Yr as mergePartials,lr as normalizeIntentVariant,Ao as normalizeWeight,Br as parseTheme,no as printThemeFitReport,br as releasePreviewUrl,Or as requestHelp,ur as showFlyout,Pr as showToast,Do as themeFitReport,go as themeFitRows,Rr as traverseToClosest,qr as validateThemePair};
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"./section/esp-section.js";export*from"./stack/esp-stack.js";export*from"./row/esp-row.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 _r,DEFAULT_ICON_VIEW_BOX as Er,INTENT_VARIANTS as ir,normalizeIntentVariant as Ar,getIconHref as lr,getIconHrefForHost as Ir,getIconSpriteUrl as Sr,getIconSpriteReference as sr}from"./shared/intent-values.js";import{EspalierElementBase as Rr}from"./shared/esp-element-base.js";import{VALIDITY_CHANGED_EVENT as Dr}from"./shared/validation.js";import{FormFieldController as gr}from"./shared/form-field-controller.js";import{traverseToClosest as Nr}from"./shared/utilities.js";import{showToast as cr}from"./shared/toast-events.js";import{showFlyout as Cr,closeFlyout as ur}from"./shared/flyout-events.js";import{requestHelp as Mr}from"./shared/help-events.js";import{getEspBus as dr}from"./shared/bus-events.js";export*from"./shared/events.js";import{getImageDetails as Gr,releasePreviewUrl as br}from"./image-upload/image-helpers.js";import{calculatePhotoLayout as yr}from"./shared/justified-layout.js";import{encodeTheme as Br,parseTheme as Yr,mergePartials as kr,layerThemes as qr,validateThemePair as zr,resolveContextTheme as Kr,buildTaprootLightTheme as Xr,buildTaprootDarkTheme as jr,NESTED_THEME_KEYS as Jr}from"./shared/theme.js";import{auditDataPalette as Zr,generateSequentialRamp as $r,generateDivergingRamp as ro,COLOR_VISION_SIMULATIONS as oo,DATA_SERIES_KEYS as eo,DEFAULT_DATA_PALETTE as to,DEFAULT_DATA_RAMP_STEPS as mo,DEFAULT_DIVERGING_NEUTRAL as po,MAX_DATA_RAMP_STEPS as fo,MIN_DATA_COLOR_DISTANCE as xo,MIN_DATA_RAMP_LIGHTNESS_STEP as To,MIN_DATA_RAMP_STEPS as ao}from"./shared/data-colors.js";import{WEIGHT_LABELS as Eo,extractWeights as io,normalizeWeight as Ao,bestAvailableWeight as lo,extractFamily as Io,getFallbackFont as So}from"./shared/font-helpers.js";import{getGoogleFonts as no}from"./font-picker/esp-font-picker.js";import{ROOT_SURFACE as ho,themeFitReport as Do,themeFitRows as Fo,themeFitLints as go,themeFitReportSuite as Lo,printThemeFitReport as No}from"./shared/theme-fit-report.js";import{ICON_SPRITE as co,ICON_SPRITE_ID as Oo,installIconSprite as Co}from"./icons/index.js";import{deriveLightnessRamp as Uo,themeFromSwatches as Mo}from"./shared/theme-swatches.js";export{oo as COLOR_VISION_SIMULATIONS,eo as DATA_SERIES_KEYS,to as DEFAULT_DATA_PALETTE,mo as DEFAULT_DATA_RAMP_STEPS,po as DEFAULT_DIVERGING_NEUTRAL,_r as DEFAULT_ICON_SPRITE_URL,Er as DEFAULT_ICON_VIEW_BOX,Rr as EspalierElementBase,gr as FormFieldController,co as ICON_SPRITE,Oo as ICON_SPRITE_ID,ir as INTENT_VARIANTS,fo as MAX_DATA_RAMP_STEPS,xo as MIN_DATA_COLOR_DISTANCE,To as MIN_DATA_RAMP_LIGHTNESS_STEP,ao as MIN_DATA_RAMP_STEPS,Jr as NESTED_THEME_KEYS,ho as ROOT_SURFACE,Dr as VALIDITY_CHANGED_EVENT,Eo as WEIGHT_LABELS,Zr as auditDataPalette,lo as bestAvailableWeight,jr as buildTaprootDarkTheme,Xr as buildTaprootLightTheme,yr as calculatePhotoLayout,ur as closeFlyout,Uo as deriveLightnessRamp,Br as encodeTheme,Io as extractFamily,io as extractWeights,ro as generateDivergingRamp,$r as generateSequentialRamp,dr as getEspBus,So as getFallbackFont,no as getGoogleFonts,lr as getIconHref,Ir as getIconHrefForHost,sr as getIconSpriteReference,Sr as getIconSpriteUrl,Gr as getImageDetails,Co as installIconSprite,qr as layerThemes,kr as mergePartials,Ar as normalizeIntentVariant,Ao as normalizeWeight,Yr as parseTheme,No as printThemeFitReport,br as releasePreviewUrl,Mr as requestHelp,Kr as resolveContextTheme,Cr as showFlyout,cr as showToast,go as themeFitLints,Do as themeFitReport,Lo as themeFitReportSuite,Fo as themeFitRows,Mo as themeFromSwatches,Nr as traverseToClosest,zr as validateThemePair};
@@ -1,4 +1,4 @@
1
- var l=function(p,t,i,s){var o=arguments.length,e=o<3?t:s===null?s=Object.getOwnPropertyDescriptor(t,i):s,n;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")e=Reflect.decorate(p,t,i,s);else for(var h=p.length-1;h>=0;h--)(n=p[h])&&(e=(o<3?n(e):o>3?n(t,i,e):n(t,i))||e);return o>3&&e&&Object.defineProperty(t,i,e),e};import{LitElement as d,nothing as g,css as v,html as a}from"lit";import{customElement as u,property as c}from"lit/decorators.js";import{ref as m}from"lit/directives/ref.js";import{getIconHrefForHost as f}from"../shared/intent-values.js";import{SlottedIconController as y}from"../shared/slotted-icon-controller.js";import{renderSpriteIcon as b}from"../shared/svgs/render-sprite-icon.js";let r=class extends d{constructor(){super(),this.internals=this.attachInternals(),this.iconSlot=new y(this),this.text="",this.icon="",this.value="",this.selected=!1,this.internals.role="option"}connectedCallback(){super.connectedCallback(),this.hasAttribute("role")||this.setAttribute("role","option")}updated(t){super.updated(t),t.has("selected")&&(this.internals.ariaSelected=String(this.selected),this.setAttribute("aria-selected",String(this.selected)))}renderHighlightedText(){const t=this.highlightRanges;if(!t||t.length===0)return this.text;const i=[...t].sort((e,n)=>e[0]-n[0]),s=[];let o=0;for(const[e,n]of i)e>o&&s.push(a`${this.text.slice(o,e)}`),s.push(a`<mark>${this.text.slice(e,n)}</mark>`),o=n;return o<this.text.length&&s.push(a`${this.text.slice(o)}`),s}render(){const t=f(this.icon,this),i=this.iconSlot.hasSlottedIcon(":scope > *");return a`<div>
1
+ var l=function(p,t,i,s){var o=arguments.length,e=o<3?t:s===null?s=Object.getOwnPropertyDescriptor(t,i):s,n;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")e=Reflect.decorate(p,t,i,s);else for(var h=p.length-1;h>=0;h--)(n=p[h])&&(e=(o<3?n(e):o>3?n(t,i,e):n(t,i))||e);return o>3&&e&&Object.defineProperty(t,i,e),e};import{LitElement as d,nothing as g,css as u,html as a}from"lit";import{customElement as v,property as c}from"lit/decorators.js";import{ref as m}from"lit/directives/ref.js";import{getIconHrefForHost as f}from"../shared/intent-values.js";import{SlottedIconController as y}from"../shared/slotted-icon-controller.js";import{renderSpriteIcon as b}from"../shared/svgs/render-sprite-icon.js";import{DocumentSpriteController as k}from"../shared/document-sprite.js";let r=class extends d{constructor(){super(),this.internals=this.attachInternals(),this.iconSlot=new y(this),this.text="",this.icon="",this.value="",this.selected=!1,new k(this,{reactToSpriteChanges:!0}),this.internals.role="option"}connectedCallback(){super.connectedCallback(),this.hasAttribute("role")||this.setAttribute("role","option")}updated(t){super.updated(t),t.has("selected")&&(this.internals.ariaSelected=String(this.selected),this.setAttribute("aria-selected",String(this.selected)))}renderHighlightedText(){const t=this.highlightRanges;if(!t||t.length===0)return this.text;const i=[...t].sort((e,n)=>e[0]-n[0]),s=[];let o=0;for(const[e,n]of i)e>o&&s.push(a`${this.text.slice(o,e)}`),s.push(a`<mark>${this.text.slice(e,n)}</mark>`),o=n;return o<this.text.length&&s.push(a`${this.text.slice(o)}`),s}render(){const t=f(this.icon,this),i=this.iconSlot.hasSlottedIcon(":scope > *");return a`<div>
2
2
  <span class="icon">
3
3
  <slot ${m(this.iconSlot.slotRef)} @slotchange=${this.iconSlot.handleSlotChange}></slot>
4
4
  ${!i&&t?b(t):g}
@@ -19,7 +19,7 @@ var l=function(p,t,i,s){var o=arguments.length,e=o<3?t:s===null?s=Object.getOwnP
19
19
  />
20
20
  <path d="M9 12l2 2l4 -4" />
21
21
  </svg>`:a``}
22
- </div>`}};r.styles=v`
22
+ </div>`}};r.styles=u`
23
23
  :host(:hover),
24
24
  :host(.highlighted) {
25
25
  div {
@@ -77,4 +77,4 @@ var l=function(p,t,i,s){var o=arguments.length,e=o<3?t:s===null?s=Object.getOwnP
77
77
  margin: var(--esp-size-tiny);
78
78
  }
79
79
  }
80
- `,l([c({type:Object})],r.prototype,"styles",void 0),l([c({type:String})],r.prototype,"text",void 0),l([c({type:String})],r.prototype,"icon",void 0),l([c({type:String})],r.prototype,"value",void 0),l([c({type:Boolean})],r.prototype,"selected",void 0),l([c({attribute:"highlight-ranges",type:Array})],r.prototype,"highlightRanges",void 0),r=l([u("esp-picker-item")],r);export{r as EspalierPickerItem};
80
+ `,l([c({type:Object})],r.prototype,"styles",void 0),l([c({type:String})],r.prototype,"text",void 0),l([c({type:String})],r.prototype,"icon",void 0),l([c({type:String})],r.prototype,"value",void 0),l([c({type:Boolean})],r.prototype,"selected",void 0),l([c({attribute:"highlight-ranges",type:Array})],r.prototype,"highlightRanges",void 0),r=l([v("esp-picker-item")],r);export{r as EspalierPickerItem};
@@ -1,4 +1,4 @@
1
- var p=function(u,t,e,s){var i=arguments.length,o=i<3?t:s===null?s=Object.getOwnPropertyDescriptor(t,e):s,l;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")o=Reflect.decorate(u,t,e,s);else for(var r=u.length-1;r>=0;r--)(l=u[r])&&(o=(i<3?l(o):i>3?l(t,e,o):l(t,e))||o);return i>3&&o&&Object.defineProperty(t,e,o),o};import{LitElement as m,css as y,html as b}from"lit";import{customElement as T,property as n,state as w}from"lit/decorators.js";import{createRef as f,ref as d}from"lit/directives/ref.js";import{findContainingPopovers as v,PopoverController as D}from"../shared/popover-controller.js";import{viewportSize as g}from"../shared/viewport.js";import{RafThrottle as P}from"../shared/raf-throttle.js";import{alignAttributeTextInheritance as O}from"../shared/style-fragments.js";let C=0,h=class extends m{constructor(){super(...arguments),this.popoverOpen=!1,this.thePopover=f(),this.popoverSlot=f(),this.targetSlot=f(),this.attachTo=null,this.showDelayTimer=null,this.hideDelayTimer=null,this.isHovered=!1,this.isFocused=!1,this.collisionFrame=new P(()=>this.applyCollisionAdjustment()),this.popoverId=`esp-popover-${++C}`,this.popoverCtrl=new D({host:this,closeStrategy:"skip-list",isOpen:()=>this.popoverOpen,onShouldClose:()=>this.closePopover(),onPositionUpdate:()=>this.positionPopover(),getPositionElements:()=>[this.attachTo,this.thePopover.value],getInsideElements:()=>[this.thePopover.value??null],onOutsideClick:()=>this.closePopover()}),this.attach="below",this.collision="flip",this.align="start",this.offset="",this.offsetX=0,this.offsetY=0,this.trigger="click",this.showDelay=0,this.hideDelay=0,this.closePopover=()=>{this.cancelDelays(),this.cancelCollisionAdjustment();const t=this.thePopover.value;if(t&&this.popoverOpen)try{t.hidePopover()}catch{}this.popoverCtrl.stopTracking(),this.popoverCtrl.stopOutsideClick(),this.popoverOpen&&(this.popoverOpen=!1,this.dispatchEvent(new CustomEvent("popover-closed",{bubbles:!0,composed:!0})))},this.openPopover=()=>{this.scheduleOpen()},this.updatePosition=()=>{this.popoverOpen&&this.positionPopover()},this.toggleOpen=t=>{this.trigger==="click"&&(t.stopPropagation(),this.popoverOpen?this.closePopover():this.doOpen())}}cancelDelays(){this.showDelayTimer!==null&&(clearTimeout(this.showDelayTimer),this.showDelayTimer=null),this.hideDelayTimer!==null&&(clearTimeout(this.hideDelayTimer),this.hideDelayTimer=null)}cancelCollisionAdjustment(){this.collisionFrame.cancel()}applyPixelOffset(t,e){if(e===0)return t;const s=t.startsWith("calc(")&&t.endsWith(")")?t.slice(5,-1):t,i=e>0?"+":"-";return`calc(${s} ${i} ${Math.abs(e)}px)`}scheduleOpen(){this.hideDelayTimer!==null&&(clearTimeout(this.hideDelayTimer),this.hideDelayTimer=null),!this.popoverOpen&&(this.showDelay>0&&this.showDelayTimer===null?this.showDelayTimer=setTimeout(()=>{this.showDelayTimer=null,this.doOpen()},this.showDelay):this.showDelay<=0&&this.doOpen())}scheduleClose(){this.showDelayTimer!==null&&(clearTimeout(this.showDelayTimer),this.showDelayTimer=null),this.popoverOpen&&(this.hideDelay>0&&this.hideDelayTimer===null?this.hideDelayTimer=setTimeout(()=>{this.hideDelayTimer=null,this.closePopover()},this.hideDelay):this.hideDelay<=0&&this.closePopover())}doOpen(){if(this.popoverOpen)return;const t=v(this);this.popoverCtrl.publishCloseOthers(t),this.popoverOpen=!0,this.positionPopover(),this.popoverCtrl.startTracking(),this.popoverCtrl.startOutsideClick(),this.dispatchEvent(new CustomEvent("popover-opened",{bubbles:!0,composed:!0}))}positionPopover(){const t=this.thePopover.value;if(!t||!this.attachTo)return;const e=this.attachTo.getBoundingClientRect(),s=this.offset.length?this.offset:"0px";t.matches(":popover-open")||t.showPopover();const i=t.getBoundingClientRect(),{width:o,height:l}=g();this.cancelCollisionAdjustment();let r=this.attach;this.collision==="flip"&&(r==="above"&&e.top<i.height&&l-e.bottom>e.top?r="below":r==="below"&&l-e.bottom<i.height&&e.top>l-e.bottom?r="above":r==="left"&&e.left<i.width&&o-e.right>e.left?r="right":r==="right"&&o-e.right<i.width&&e.left>o-e.right&&(r="left"));let a="0px",c="0px";switch(r){case"above":a=`calc(${e.top-i.height}px - ${s})`;break;case"below":a=`calc(${e.bottom}px + ${s})`;break;case"left":c=`calc(${e.left-i.width}px - ${s})`;break;case"right":c=`calc(${e.right}px + ${s})`;break}if(r==="above"||r==="below")switch(this.align){case"start":c=`${e.left}px`;break;case"center":c=`${e.left+e.width/2-i.width/2}px`;break;case"end":c=`${e.right-i.width}px`;break}else switch(this.align){case"start":a=`${e.top}px`;break;case"center":a=`${e.top+e.height/2-i.height/2}px`;break;case"end":a=`${e.bottom-i.height}px`;break}c=this.applyPixelOffset(c,this.offsetX),a=this.applyPixelOffset(a,this.offsetY),t.style.top=a,t.style.left=c,this.collision!=="none"&&this.collisionFrame.schedule()}applyCollisionAdjustment(){const t=this.thePopover.value;if(!t||!this.popoverOpen||!t.matches(":popover-open"))return;const{width:e,height:s}=g(),i=t.getBoundingClientRect();let o=i.left;if(i.width>e?o=0:o=Math.min(Math.max(i.left,0),e-i.width),o!==i.left&&(t.style.left=`${o}px`),this.collision!=="shift")return;let l=i.top;i.height>s?l=0:l=Math.min(Math.max(i.top,0),s-i.height),l!==i.top&&(t.style.top=`${l}px`)}handleHoverEnter(){this.isHovered=!0,this.scheduleOpen()}handleHoverLeave(){if(this.isHovered=!1,this.trigger==="focus-hover"&&this.isFocused){this.hideDelayTimer!==null&&(clearTimeout(this.hideDelayTimer),this.hideDelayTimer=null);return}this.scheduleClose()}handleFocusIn(){this.isFocused=!0,this.scheduleOpen()}handleFocusOut(){if(this.isFocused=!1,this.trigger==="focus-hover"&&this.isHovered){this.hideDelayTimer!==null&&(clearTimeout(this.hideDelayTimer),this.hideDelayTimer=null);return}this.scheduleClose()}disconnectedCallback(){super.disconnectedCallback(),this.cancelDelays(),this.cancelCollisionAdjustment()}updated(t){t.has("trigger")&&(this.isHovered=!1,this.isFocused=!1,this.cancelDelays()),this.popoverOpen&&["attach","align","collision","offset","offsetX","offsetY"].some(e=>t.has(e))&&this.positionPopover()}firstUpdated(t){let e=this.targetSlot.value.assignedElements()[0];for(;e instanceof HTMLSlotElement;)e=e.assignedElements()[0];this.attachTo=e;const s=this.thePopover.value;s&&(s.setAttribute("popover","manual"),s.id=this.popoverId);const i=this.popoverSlot.value?.assignedElements();if(i?.length){let o=i[0];for(;o instanceof HTMLSlotElement;)o=o.assignedElements()[0];o&&(o["linked-popover"]=this,o.addEventListener("click",l=>{l.stopPropagation();const r=[this,...v(this)];this.popoverCtrl.publishCloseOthers(r)}))}}render(){return b`
1
+ var p=function(u,t,e,s){var i=arguments.length,o=i<3?t:s===null?s=Object.getOwnPropertyDescriptor(t,e):s,l;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")o=Reflect.decorate(u,t,e,s);else for(var r=u.length-1;r>=0;r--)(l=u[r])&&(o=(i<3?l(o):i>3?l(t,e,o):l(t,e))||o);return i>3&&o&&Object.defineProperty(t,e,o),o};import{LitElement as m,css as y,html as b}from"lit";import{customElement as T,property as n,state as w}from"lit/decorators.js";import{createRef as f,ref as d}from"lit/directives/ref.js";import{findContainingPopovers as v,PopoverController as D}from"../shared/popover-controller.js";import{viewportSize as g}from"../shared/viewport.js";import{RafThrottle as O}from"../shared/raf-throttle.js";import{alignAttributeTextInheritance as P}from"../shared/style-fragments.js";let C=0,h=class extends m{constructor(){super(...arguments),this.popoverOpen=!1,this.thePopover=f(),this.popoverSlot=f(),this.targetSlot=f(),this.attachTo=null,this.showDelayTimer=null,this.hideDelayTimer=null,this.isHovered=!1,this.isFocused=!1,this.collisionFrame=new O(()=>this.applyCollisionAdjustment()),this.popoverId=`esp-popover-${++C}`,this.popoverCtrl=new D({host:this,closeStrategy:"skip-list",isOpen:()=>this.popoverOpen,onShouldClose:()=>this.closePopover(),onPositionUpdate:()=>this.positionPopover(),getPositionElements:()=>[this.attachTo,this.thePopover.value],getInsideElements:()=>[this.thePopover.value??null],onOutsideClick:()=>this.closePopover()}),this.attach="below",this.collision="flip",this.align="start",this.offset="",this.offsetX=0,this.offsetY=0,this.trigger="click",this.showDelay=0,this.hideDelay=0,this.closePopover=()=>{this.cancelDelays(),this.cancelCollisionAdjustment();const t=this.thePopover.value;if(t&&this.popoverOpen)try{t.hidePopover()}catch{}this.popoverCtrl.stopTracking(),this.popoverCtrl.stopOutsideClick(),this.popoverOpen&&(this.popoverOpen=!1,this.dispatchEvent(new CustomEvent("popover-closed",{bubbles:!0,composed:!0})))},this.openPopover=()=>{this.scheduleOpen()},this.updatePosition=()=>{this.popoverOpen&&this.positionPopover()},this.toggleOpen=t=>{this.trigger==="click"&&(t.stopPropagation(),this.popoverOpen?this.closePopover():this.doOpen())}}cancelDelays(){this.showDelayTimer!==null&&(clearTimeout(this.showDelayTimer),this.showDelayTimer=null),this.hideDelayTimer!==null&&(clearTimeout(this.hideDelayTimer),this.hideDelayTimer=null)}cancelCollisionAdjustment(){this.collisionFrame.cancel()}applyPixelOffset(t,e){if(e===0)return t;const s=t.startsWith("calc(")&&t.endsWith(")")?t.slice(5,-1):t,i=e>0?"+":"-";return`calc(${s} ${i} ${Math.abs(e)}px)`}scheduleOpen(){this.hideDelayTimer!==null&&(clearTimeout(this.hideDelayTimer),this.hideDelayTimer=null),!this.popoverOpen&&(this.showDelay>0&&this.showDelayTimer===null?this.showDelayTimer=setTimeout(()=>{this.showDelayTimer=null,this.doOpen()},this.showDelay):this.showDelay<=0&&this.doOpen())}scheduleClose(){this.showDelayTimer!==null&&(clearTimeout(this.showDelayTimer),this.showDelayTimer=null),this.popoverOpen&&(this.hideDelay>0&&this.hideDelayTimer===null?this.hideDelayTimer=setTimeout(()=>{this.hideDelayTimer=null,this.closePopover()},this.hideDelay):this.hideDelay<=0&&this.closePopover())}doOpen(){if(this.popoverOpen)return;const t=v(this);this.popoverCtrl.publishCloseOthers(t),this.popoverOpen=!0,this.positionPopover(),this.popoverCtrl.startTracking(),this.popoverCtrl.startOutsideClick(),this.dispatchEvent(new CustomEvent("popover-opened",{bubbles:!0,composed:!0}))}positionPopover(){const t=this.thePopover.value;if(!t||!this.attachTo)return;const e=this.attachTo.getBoundingClientRect(),s=this.offset.length?this.offset:"0px";t.matches(":popover-open")||t.showPopover();const i=t.getBoundingClientRect(),{width:o,height:l}=g();this.cancelCollisionAdjustment();let r=this.attach;this.collision==="flip"&&(r==="above"&&e.top<i.height&&l-e.bottom>e.top?r="below":r==="below"&&l-e.bottom<i.height&&e.top>l-e.bottom?r="above":r==="left"&&e.left<i.width&&o-e.right>e.left?r="right":r==="right"&&o-e.right<i.width&&e.left>o-e.right&&(r="left"));let a="0px",c="0px";switch(r){case"above":a=`calc(${e.top-i.height}px - ${s})`;break;case"below":a=`calc(${e.bottom}px + ${s})`;break;case"left":c=`calc(${e.left-i.width}px - ${s})`;break;case"right":c=`calc(${e.right}px + ${s})`;break}if(r==="above"||r==="below")switch(this.align){case"start":c=`${e.left}px`;break;case"center":c=`${e.left+e.width/2-i.width/2}px`;break;case"end":c=`${e.right-i.width}px`;break}else switch(this.align){case"start":a=`${e.top}px`;break;case"center":a=`${e.top+e.height/2-i.height/2}px`;break;case"end":a=`${e.bottom-i.height}px`;break}c=this.applyPixelOffset(c,this.offsetX),a=this.applyPixelOffset(a,this.offsetY),t.style.top=a,t.style.left=c,this.collision!=="none"&&this.collisionFrame.schedule()}applyCollisionAdjustment(){const t=this.thePopover.value;if(!t||!this.popoverOpen||!t.matches(":popover-open"))return;const{width:e,height:s}=g(),i=t.getBoundingClientRect();let o=i.left;if(i.width>e?o=0:o=Math.min(Math.max(i.left,0),e-i.width),o!==i.left&&(t.style.left=`${o}px`),this.collision!=="shift")return;let l=i.top;i.height>s?l=0:l=Math.min(Math.max(i.top,0),s-i.height),l!==i.top&&(t.style.top=`${l}px`)}handleHoverEnter(){this.isHovered=!0,this.scheduleOpen()}handleHoverLeave(){if(this.isHovered=!1,this.trigger==="focus-hover"&&this.isFocused){this.hideDelayTimer!==null&&(clearTimeout(this.hideDelayTimer),this.hideDelayTimer=null);return}this.scheduleClose()}handleFocusIn(){this.isFocused=!0,this.scheduleOpen()}handleFocusOut(){if(this.isFocused=!1,this.trigger==="focus-hover"&&this.isHovered){this.hideDelayTimer!==null&&(clearTimeout(this.hideDelayTimer),this.hideDelayTimer=null);return}this.scheduleClose()}disconnectedCallback(){super.disconnectedCallback(),this.cancelDelays(),this.cancelCollisionAdjustment()}updated(t){super.updated(t),t.has("trigger")&&(this.isHovered=!1,this.isFocused=!1,this.cancelDelays()),this.popoverOpen&&["attach","align","collision","offset","offsetX","offsetY"].some(e=>t.has(e))&&this.positionPopover()}firstUpdated(t){let e=this.targetSlot.value.assignedElements()[0];for(;e instanceof HTMLSlotElement;)e=e.assignedElements()[0];this.attachTo=e;const s=this.thePopover.value;s&&(s.setAttribute("popover","manual"),s.id=this.popoverId);const i=this.popoverSlot.value?.assignedElements();if(i?.length){let o=i[0];for(;o instanceof HTMLSlotElement;)o=o.assignedElements()[0];o&&(o["linked-popover"]=this,o.addEventListener("click",l=>{l.stopPropagation();const r=[this,...v(this)];this.popoverCtrl.publishCloseOthers(r)}))}}render(){return b`
2
2
  <slot
3
3
  ${d(this.targetSlot)}
4
4
  @click=${t=>{this.trigger==="click"&&this.toggleOpen(t)}}
@@ -16,7 +16,7 @@ var p=function(u,t,e,s){var i=arguments.length,o=i<3?t:s===null?s=Object.getOwnP
16
16
  >
17
17
  <slot name="popover" ${d(this.popoverSlot)}></slot>
18
18
  </div>
19
- `}};h.styles=[O,y`
19
+ `}};h.styles=[P,y`
20
20
  :host {
21
21
  position: relative;
22
22
  display: flex;
@@ -71,6 +71,22 @@ export type { SchemeEvents } from "../shared/bus-events.js";
71
71
  * @cssprop --esp-color-series-6 - Sixth categorical data-series color.
72
72
  * @cssprop --esp-color-series-7 - Seventh categorical data-series color.
73
73
  * @cssprop --esp-color-series-8 - Eighth categorical data-series color.
74
+ * @cssprop --esp-color-series-1-wash - First series washed toward the local background (75% identity in OKLab) for large fills; theme zones re-emit it against their own canvas.
75
+ * @cssprop --esp-color-series-1-ink - First series pushed to the text contrast tier against the local background (best-contrast pole when a mid-lightness surface makes the tier unreachable).
76
+ * @cssprop --esp-color-series-2-wash - Second series washed toward the local background (75% identity in OKLab) for large fills; theme zones re-emit it against their own canvas.
77
+ * @cssprop --esp-color-series-2-ink - Second series pushed to the text contrast tier against the local background (best-contrast pole when a mid-lightness surface makes the tier unreachable).
78
+ * @cssprop --esp-color-series-3-wash - Third series washed toward the local background (75% identity in OKLab) for large fills; theme zones re-emit it against their own canvas.
79
+ * @cssprop --esp-color-series-3-ink - Third series pushed to the text contrast tier against the local background (best-contrast pole when a mid-lightness surface makes the tier unreachable).
80
+ * @cssprop --esp-color-series-4-wash - Fourth series washed toward the local background (75% identity in OKLab) for large fills; theme zones re-emit it against their own canvas.
81
+ * @cssprop --esp-color-series-4-ink - Fourth series pushed to the text contrast tier against the local background (best-contrast pole when a mid-lightness surface makes the tier unreachable).
82
+ * @cssprop --esp-color-series-5-wash - Fifth series washed toward the local background (75% identity in OKLab) for large fills; theme zones re-emit it against their own canvas.
83
+ * @cssprop --esp-color-series-5-ink - Fifth series pushed to the text contrast tier against the local background (best-contrast pole when a mid-lightness surface makes the tier unreachable).
84
+ * @cssprop --esp-color-series-6-wash - Sixth series washed toward the local background (75% identity in OKLab) for large fills; theme zones re-emit it against their own canvas.
85
+ * @cssprop --esp-color-series-6-ink - Sixth series pushed to the text contrast tier against the local background (best-contrast pole when a mid-lightness surface makes the tier unreachable).
86
+ * @cssprop --esp-color-series-7-wash - Seventh series washed toward the local background (75% identity in OKLab) for large fills; theme zones re-emit it against their own canvas.
87
+ * @cssprop --esp-color-series-7-ink - Seventh series pushed to the text contrast tier against the local background (best-contrast pole when a mid-lightness surface makes the tier unreachable).
88
+ * @cssprop --esp-color-series-8-wash - Eighth series washed toward the local background (75% identity in OKLab) for large fills; theme zones re-emit it against their own canvas.
89
+ * @cssprop --esp-color-series-8-ink - Eighth series pushed to the text contrast tier against the local background (best-contrast pole when a mid-lightness surface makes the tier unreachable).
74
90
  *
75
91
  * @docPageTitle Root
76
92
  * @docUrl /components/root
@@ -1 +1 @@
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{resolveDataColorSource as w}from"../../shared/theme.js";import{lightnessRampProperties as O}from"./lightness-ramp-properties.js";import{computeVariants as $}from"./compute-variants.js";import{computeSemanticProperties as E}from"./compute-semantic-properties.js";function I(o){return{rootFontSize:o.rootFontSize,typeRatio:o.typeRatio,spaceRatio:o.spaceRatio,borderRadius:o.borderRadius,viewportMin:o.viewportMin,viewportMax:o.viewportMax}}function j(o,b,m){const i=g(o.seedColor);if(!i)return{};const a={};a["--esp-scheme"]=b,a["--esp-seed-color"]=o.seedColor;const c=$(i,o);for(const[e,n]of Object.entries(c))a[`--esp-color-${e}`]=l(f(n));const p=new Set,t=(e,n)=>{const r=typeof e=="string"?w(e,o.anchors):null;if(r)return r;const s=typeof e=="string"?e:String(e);return p.has(s)||(p.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},y=o.dataPalette??v;for(let e=0;e<u.length;e+=1){const n=u[e],r=g(t(y[n],`dataPalette.${n}`))??i;a[`--esp-color-series-${e+1}`]=l(f(r))}for(const[e,n]of Object.entries(o.dataRamps??{}))try{(n.type==="sequential"?R(t(n.source,`dataRamps.${e}.source`),{steps:n.steps,lightnessStart:n.lightnessStart,lightnessEnd:n.lightnessEnd}):B(t(n.start,`dataRamps.${e}.start`),t(n.end,`dataRamps.${e}.end`),{steps:n.steps,neutral:n.neutral===void 0?void 0:t(n.neutral,`dataRamps.${e}.neutral`)})).forEach((s,S)=>{a[`--esp-color-ramp-${e}-${S+1}`]=s})}catch(r){console.warn(`Espalier theme: dataRamps.${e} cannot be generated \u2014 ${r instanceof Error?r.message:String(r)}`)}Object.assign(a,O(o));const d=new Set;return Object.assign(a,E(o,c,{trace:m,onUnresolvedSource:e=>{d.has(e)||(d.add(e),console.warn(`Espalier theme: color source "${e}" cannot be resolved \u2014 falling back to the seed. Run validateTheme for the declared anchors.`))}})),Object.assign(a,k(I(o))),o.fontBody&&(a["--esp-font-body"]=o.fontBody),o.fontHeadings&&(a["--esp-font-headings"]=o.fontHeadings),o.fontBrand&&(a["--esp-font-brand"]=o.fontBrand),o.fontMonospace&&(a["--esp-font-monospace"]=o.fontMonospace),a["--esp-font-weight-body"]=o.fontWeightBody,a["--esp-font-weight-headings"]=o.fontWeightHeadings,a["--esp-font-weight-brand"]=o.fontWeightBrand,a["--esp-font-weight-monospace"]=o.fontWeightMonospace,o.pageBackgroundImage&&(a["--esp-page-background-image"]=o.pageBackgroundImage),o.pageBackgroundImageOpacity!==void 0&&(a["--esp-page-background-image-opacity"]=o.pageBackgroundImageOpacity.toString()),o.boxBackgroundImage&&(a["--esp-box-background-image"]=o.boxBackgroundImage),o.boxBackgroundImageOpacity!==void 0&&(a["--esp-box-background-image-opacity"]=o.boxBackgroundImageOpacity.toString()),o.vellumOpacity!==void 0&&(a["--esp-vellum-opacity"]=o.vellumOpacity.toString()),o.vellumBackgroundImage&&(a["--esp-vellum-background-image"]=o.vellumBackgroundImage),o.vellumBackgroundImageOpacity!==void 0&&(a["--esp-vellum-background-image-opacity"]=o.vellumBackgroundImageOpacity.toString()),a}export{j as computeThemeProperties};
1
+ import{parseCssColor as f,serializeOklch as u,gamutMapToSRGB as m}from"../../shared/color-engine.js";import{generateScaleProperties as y}from"../../shared/scale-engine.js";import{DATA_SERIES_KEYS as b,DEFAULT_DATA_PALETTE as k,generateDivergingRamp as v,generateSequentialRamp as B}from"../../shared/data-colors.js";import{resolveDataColorSource as R}from"../../shared/theme.js";import{dataCompanionProperties as O}from"./data-companion-properties.js";import{lightnessRampProperties as w}from"./lightness-ramp-properties.js";import{computeVariants as $}from"./compute-variants.js";import{computeSemanticProperties as E}from"./compute-semantic-properties.js";function I(o){return{rootFontSize:o.rootFontSize,typeRatio:o.typeRatio,spaceRatio:o.spaceRatio,borderRadius:o.borderRadius,viewportMin:o.viewportMin,viewportMax:o.viewportMax}}function x(o,d,g){const i={},a=o.dataPalette??k;for(let r=0;r<b.length;r+=1){const c=b[r],t=f(g(a[c],`dataPalette.${c}`))??d;i[`--esp-color-series-${r+1}`]=u(m(t))}return i}function _(o,d,g){const i=f(o.seedColor);if(!i)return{};const a={};a["--esp-scheme"]=d,a["--esp-seed-color"]=o.seedColor;const r=$(i,o);for(const[e,n]of Object.entries(r))a[`--esp-color-${e}`]=u(m(n));const c=new Set,t=(e,n)=>{const s=typeof e=="string"?R(e,o.anchors):null;if(s)return s;const p=typeof e=="string"?e:String(e);return c.has(p)||(c.add(p),console.warn(`Espalier theme: ${n} color source "${p}" cannot be resolved \u2014 falling back to the seed. Run validateTheme for the declared data colors.`)),o.seedColor};Object.assign(a,x(o,i,t));for(const[e,n]of Object.entries(o.dataRamps??{}))try{(n.type==="sequential"?B(t(n.source,`dataRamps.${e}.source`),{steps:n.steps,lightnessStart:n.lightnessStart,lightnessEnd:n.lightnessEnd}):v(t(n.start,`dataRamps.${e}.start`),t(n.end,`dataRamps.${e}.end`),{steps:n.steps,neutral:n.neutral===void 0?void 0:t(n.neutral,`dataRamps.${e}.neutral`)})).forEach((p,S)=>{a[`--esp-color-ramp-${e}-${S+1}`]=p})}catch(s){console.warn(`Espalier theme: dataRamps.${e} cannot be generated \u2014 ${s instanceof Error?s.message:String(s)}`)}Object.assign(a,w(o));const l=new Set;return Object.assign(a,E(o,r,{trace:g,onUnresolvedSource:e=>{l.has(e)||(l.add(e),console.warn(`Espalier theme: color source "${e}" cannot be resolved \u2014 falling back to the seed. Run validateTheme for the declared anchors.`))}})),Object.assign(a,O(a)),Object.assign(a,y(I(o))),o.fontBody&&(a["--esp-font-body"]=o.fontBody),o.fontHeadings&&(a["--esp-font-headings"]=o.fontHeadings),o.fontBrand&&(a["--esp-font-brand"]=o.fontBrand),o.fontMonospace&&(a["--esp-font-monospace"]=o.fontMonospace),a["--esp-font-weight-body"]=o.fontWeightBody,a["--esp-font-weight-headings"]=o.fontWeightHeadings,a["--esp-font-weight-brand"]=o.fontWeightBrand,a["--esp-font-weight-monospace"]=o.fontWeightMonospace,o.pageBackgroundImage&&(a["--esp-page-background-image"]=o.pageBackgroundImage),o.pageBackgroundImageOpacity!==void 0&&(a["--esp-page-background-image-opacity"]=o.pageBackgroundImageOpacity.toString()),o.boxBackgroundImage&&(a["--esp-box-background-image"]=o.boxBackgroundImage),o.boxBackgroundImageOpacity!==void 0&&(a["--esp-box-background-image-opacity"]=o.boxBackgroundImageOpacity.toString()),o.vellumOpacity!==void 0&&(a["--esp-vellum-opacity"]=o.vellumOpacity.toString()),o.vellumBackgroundImage&&(a["--esp-vellum-background-image"]=o.vellumBackgroundImage),o.vellumBackgroundImageOpacity!==void 0&&(a["--esp-vellum-background-image-opacity"]=o.vellumBackgroundImageOpacity.toString()),a}export{_ as computeThemeProperties,x as dataSeriesProperties};
@@ -0,0 +1 @@
1
+ import{apcaContrast as s,ensureContrast as m,gamutMapToSRGB as i,oklabToOklch as E,oklchToOklab as l,parseOklch as p,serializeOklch as S}from"../../shared/color-engine.js";import{DATA_SERIES_KEYS as b}from"../../shared/data-colors.js";import{TOKEN_PAIRINGS as u}from"../../shared/theme.js";const A=.75,f=u.text?.targetLc??75;function _(c,n){const t=m({...c},n,f);if(Math.abs(s(t,n))>=f)return t;const o=i({l:n.l>.5?1:0,c:c.c,h:c.h});return Math.abs(s(o,n))>Math.abs(s(t,n))?o:t}function k(c,n,t){const o=l(c),r=l(n);return E({L:o.L*t+r.L*(1-t),a:o.a*t+r.a*(1-t),b:o.b*t+r.b*(1-t)})}function h(c,n){const t=p(c["--esp-color-background"]??"");if(!t)return{};const o={};for(let r=1;r<=b.length;r+=1){const a=`--esp-color-series-${r}`,e=p(c[a]??n?.[a]??"");e&&(o[`${a}-wash`]=S(i(k(e,t,A))),o[`${a}-ink`]=S(_(e,t)))}return o}export{A as DATA_WASH_SERIES_SHARE,h as dataCompanionProperties};
@@ -0,0 +1 @@
1
+ import{classifyIconSpriteValue as D}from"./intent-values.js";import{traverseToClosest as L}from"./utilities.js";import{subscribeToRootEvent as P}from"./root-event-subscription.js";const E="data-esp-adopted-icons",A="http://www.w3.org/2000/svg",k=new Set;function ee(){k.clear()}function N(e,t){k.has(e)||(k.add(e),console.warn(t))}const v=new Map,g=new WeakMap;function V(e,t){const n=g.get(t);if(n===e)return;n&&C(n,t),g.set(t,e);let o=v.get(e);if(!o){const s=new Set,c=new MutationObserver(a=>{if(a.some(f=>f.target===e||e.contains(f.target)||[...f.removedNodes].some(i=>i===e||i.contains(e))||[...f.addedNodes].some(i=>i===e||i.contains(e))))for(const f of s)f.requestUpdate()});c.observe(e,{attributes:!0,characterData:!0,childList:!0,subtree:!0});const u=e.ownerDocument?.documentElement;u&&c.observe(u,{childList:!0,subtree:!0}),o={hosts:s,observer:c},v.set(e,o)}o.hosts.add(t)}function C(e,t){const n=v.get(e);n&&(n.hosts.delete(t),n.hosts.size===0&&(n.observer.disconnect(),v.delete(e)))}function $(e){const t=g.get(e);t&&(C(t,e),g.delete(e)),U(e)}const T=new WeakMap,w=new WeakMap;function z(e,t,n){const o=w.get(n);o&&(o.document!==e||o.spriteId!==t)&&U(n);let s=T.get(e);s||(s=new Map,T.set(e,s));let c=s.get(t);if(!c){const u=new Set,a=new MutationObserver(()=>{if(e.getElementById(t)){a.disconnect(),s.delete(t);for(const h of u)w.delete(h),h.requestUpdate()}});a.observe(e.documentElement,{childList:!0,subtree:!0}),c={hosts:u,observer:a},s.set(t,c)}c.hosts.add(n),w.set(n,{document:e,spriteId:t})}function U(e){const t=w.get(e);if(!t)return;w.delete(e);const n=T.get(t.document),o=n?.get(t.spriteId);o&&(o.hosts.delete(e),o.hosts.size===0&&(o.observer.disconnect(),n.delete(t.spriteId)))}function B(e,t,n){if(!t)return;const o=D(e?e.iconSpriteUrl:null);let s=t.querySelector(`svg[${E}]`);if(o.kind!=="document"){s?.remove(),n&&$(n);return}const c=new Set;for(const i of t.querySelectorAll("use")){if(s&&s.contains(i))continue;const l=x(i);l&&c.add(l)}if(c.size===0&&!s)return;const u=e?.ownerDocument??document,a=u.getElementById(o.spriteId);if(!a){if(N(o.spriteId,`Espalier icons: icon-sprite-url references "#${o.spriteId}" but no element with that id is in the document. Inline the sprite before setting icon-sprite-url (or set it again after), and icons will render.`),s?.remove(),n){const i=g.get(n);i&&(C(i,n),g.delete(n)),z(u,o.spriteId,n)}return}if(n&&U(n),a.namespaceURI!==A||a.localName!=="svg"){N(o.spriteId,`Espalier icons: icon-sprite-url references "#${o.spriteId}", but that element is a <${a.localName}>, not an inline SVG sprite. Icons stay empty until the id names an <svg> containing <symbol>s.`),s?.remove(),n&&$(n);return}n&&V(a,n);{const i=new Set,l=[...c];for(;l.length>0;){const r=l.pop();if(i.has(r))continue;i.add(r);const d=M(a,r);if(d)for(const m of Z(d))i.has(m)||(c.add(m),l.push(m))}}s&&s.getAttribute(E)!==o.spriteId&&(s.remove(),s=null);const h=new Map,f=i=>{const l=M(a,i);return l?{clone:K(l,a,o.spriteId,h)?l.cloneNode(!0):null,source:l}:{clone:null,source:null}};if(s){for(const i of[...s.children]){const l=i.getAttribute("id")??"",{clone:r,source:d}=c.has(l)?f(l):{clone:null,source:null};!r||!d?i.remove():i.isEqualNode(d)||s.replaceChild(r,i)}s.children.length===0&&c.size===0&&(s.remove(),s=null)}for(const i of c){if(s?.querySelector(`#${R(i)}`))continue;const{clone:l}=f(i);if(l){if(!s){s=t.ownerDocument.createElementNS(A,"svg"),s.setAttribute(E,o.spriteId),s.setAttribute("aria-hidden","true");const r=s.style;r.position="absolute",r.width="0",r.height="0",r.overflow="hidden",t.appendChild(s)}s.appendChild(l)}}}const O="http://www.w3.org/1999/xlink",F=new Set(["a","animate","animatemotion","animatetransform","discard","foreignobject","script","set","style"]),H=["href","xlink:href"],G=/url\(/giu,j=/url\(\s*(?:"#([^"\\]*)"|'#([^'\\]*)'|#([^\s)"'\\]*))\s*\)/giu;function I(e){let t=!1;const n=e.replace(/(%[0-9A-Fa-f]{2})+/gu,o=>{try{return decodeURIComponent(o)}catch{return t=!0,o}});return t?null:n}function _(e){const t=[...e.matchAll(G)].length,n=[];for(const o of e.matchAll(j)){const s=o[1]??o[2]??o[3]??"";if(s.length===0)continue;const c=I(s);c!==null&&n.push(c)}return{ids:n,ok:n.length===t}}function x(e){const t=W(e);return t===null?null:I(t)}function W(e){if(e.localName!=="use")return null;const t=e.getAttribute("href")??e.getAttribute("xlink:href")??e.getAttributeNS(O,"href");if(!t)return null;const n=t.trim();return n.startsWith("#")&&n.length>1?n.slice(1):null}function K(e,t,n,o){const s=o.get(e);if(s!==void 0)return s;const c=new Map,u=[],a=new Map,h=r=>(a.has(r)||a.set(r,M(t,r)),a.get(r)??null),f=[e];for(;f.length>0;){const r=f.pop();if(c.has(r))continue;const d=o.get(r);if(d!==void 0){c.set(r,{dependencies:[],localOk:d,missing:[]}),u.push(r);continue}const m=X(r,n),b=[],S=[];for(const q of m.dependencyIds){const y=h(q);y?(b.push(y),f.push(y)):S.push(q)}c.set(r,{dependencies:b,localOk:m.ok,missing:S}),u.push(r)}const i=new Set;for(const r of u){const d=c.get(r);(!d.localOk||d.missing.length>0)&&i.add(r)}let l=!0;for(;l;){l=!1;for(const r of u)i.has(r)||c.get(r).dependencies.some(d=>i.has(d))&&(i.add(r),l=!0)}for(const r of u){const d=c.get(r),m=!i.has(r);if(!m&&d.localOk){const b=d.missing[0]??d.dependencies.find(S=>i.has(S))?.getAttribute("id")??"?";p(r,n,d.missing.length>0?`composes or paints through #${b}, which is not in the sprite`:`composes or paints through the refused member #${b}`)}o.set(r,m)}return o.get(e)}function X(e,t){const n=[],o=[e,...e.querySelectorAll("*")];for(const s of o){if(s.namespaceURI!==A)return p(e,t,`contains the non-SVG element <${s.localName}>`),{dependencyIds:n,ok:!1};if(F.has(s.localName.toLowerCase()))return p(e,t,`contains <${s.localName}>`),{dependencyIds:n,ok:!1};let c=s.getAttributeNS(O,"href")!==null;for(const h of s.getAttributeNames()){const f=h.toLowerCase();if(f.startsWith("on"))return p(e,t,`carries the event-handler attribute ${h}`),{dependencyIds:n,ok:!1};if(H.includes(f)&&(c=!0),f==="src")return p(e,t,"carries a src attribute"),{dependencyIds:n,ok:!1};if(f==="style")return p(e,t,"carries an inline style attribute \u2014 use presentation attributes"),{dependencyIds:n,ok:!1};const i=s.getAttribute(h)??"";if(i.includes("\\"))return p(e,t,`carries a CSS escape sequence in ${h}`),{dependencyIds:n,ok:!1};const l=_(i);if(!l.ok)return p(e,t,`carries an unparseable or external url() reference in ${h}`),{dependencyIds:n,ok:!1};n.push(...l.ids)}const u=W(s),a=u===null?null:I(u);if(u!==null&&a===null)return p(e,t,`composes <use href="#${u}">, an undecodable fragment the browser resolves to nothing`),{dependencyIds:n,ok:!1};if(c&&a===null)return p(e,t,"carries an href outside a local-fragment <use> reference"),{dependencyIds:n,ok:!1};a!==null&&n.push(a)}return{dependencyIds:n,ok:!0}}function p(e,t,n){const o=e.getAttribute("id")??"(unnamed)";N(`${t}#${o}`,`Espalier icons: symbol "${o}" in "#${t}" ${n} and was not adopted \u2014 sprite symbols must be passive SVG (shapes, paths, local <use> composition).`)}function M(e,t){if(!t)return null;const o=e.querySelector(`symbol#${R(t)}`)??e.querySelector(`#${R(t)}`);return o&&o.namespaceURI===A?o:null}function Z(e){const t=new Set,n=[e,...e.querySelectorAll("*")];for(const o of n){const s=x(o);s&&t.add(s);for(const c of o.getAttributeNames())for(const u of _(o.getAttribute(c)??"").ids)t.add(u)}return t}function R(e){const t=globalThis.CSS?.escape;return t?t(e):e.replace(/[^A-Za-z0-9_-]/gu,"\\$&")}class te{constructor(t,n){this.host=t,this.options=n,this.root=null,this.unsubscribe=null,t.addController(this)}hostConnected(){this.root=L(this.host,"esp-root"),this.options.reactToSpriteChanges&&this.root&&(this.unsubscribe=P(this.root,"icon-sprite-url-changed",()=>{this.host.requestUpdate()}))}hostDisconnected(){this.unsubscribe?.(),this.unsubscribe=null,this.root=null,$(this.host)}hostUpdated(){this.root??=L(this.host,"esp-root"),B(this.root,this.host.shadowRoot,this.host)}}export{te as DocumentSpriteController,B as adoptDocumentSpriteSymbols,I as decodeFragmentId,ee as resetWarnedMissingSprites};
@@ -66,6 +66,7 @@ export declare class EspalierElementBase extends LitElement implements SeedColor
66
66
  connectedCallback(): void;
67
67
  disconnectedCallback(): void;
68
68
  protected firstUpdated(_changedProperties: PropertyValues): void;
69
+ constructor();
69
70
  /**
70
71
  * Traverse up the DOM tree to find the closest element that
71
72
  * matches the selector. This method is aware of shadow DOM
@@ -1,4 +1,4 @@
1
- var h=function(f,e,t,r){var o=arguments.length,s=o<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,t):r,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(f,e,t,r);else for(var i=f.length-1;i>=0;i--)(a=f[i])&&(s=(o<3?a(s):o>3?a(e,t,s):a(e,t))||s);return o>3&&s&&Object.defineProperty(e,t,s),s};import{css as R,LitElement as C}from"lit";import{property as p,state as S}from"lit/decorators.js";import{subscribeToRootEvent as u}from"./root-event-subscription.js";import{traverseToClosest as b}from"./utilities.js";import{parseCssColor as w,serializeOklch as x,gamutMapToSRGB as P}from"./color-engine.js";import{computeVariants as v}from"../root/helpers/compute-variants.js";import{computeSemanticProperties as m}from"../root/helpers/compute-semantic-properties.js";import{lightnessRampProperties as E}from"../root/helpers/lightness-ramp-properties.js";import{ELEVATION_PROPERTIES as V}from"./scale-engine.js";import{ROLE_NAMES as U,mergeTheme as I,semanticToCSS as A}from"./theme.js";import{alignAttributeTextInheritance as O,focusRing as D}from"./style-fragments.js";import{syncNormalizedAttribute as N}from"./attribute-helpers.js";import{INTENT_VARIANTS as y,normalizeIntentVariant as z}from"./intent-values.js";const k=new WeakMap;class n extends C{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.intentBacker="neutral",this.intentEmitsTokens=!0,this.warnedUnknownIntents=new Set,this.correlationId=globalThis.crypto?.randomUUID?.()??Math.random().toString(36),this.scheme="light",this.handleSeedColorChanged=e=>{this.syncRootFromDom(!1)&&(this.seedColor=e.seedColor,this.applyScopedColorTokens())},this.handleSchemeChanged=e=>{!this.syncRootFromDom(!1)||this.scheme===e.scheme||(this.scheme=e.scheme,this.applyScopedColorTokens())},this.handleThemeChanged=()=>{this.syncRootFromDom(!1)&&this.applyScopedColorTokens()},this.handleIconSpriteUrlChanged=()=>{this.syncRootFromDom(!1)&&this.requestUpdate()}}get seedColor(){return this.seedColorBacker}set seedColor(e){this.seedColorBacker=e}focusResolvedElementAfterUpdate(e,t){const r=()=>{const o=e();return o?(o.focus(t),!0):!1};r()||this.updateComplete.then(()=>{r()})}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 intent(){return this.intentBacker}set intent(e){const t=typeof e=="string"?e.trim():"";t!==""&&!y.includes(t)&&!this.warnedUnknownIntents.has(t)&&(this.warnedUnknownIntents.add(t),console.warn(`Espalier intent: "${t}" is not an intent; expected one of ${y.join(", ")}. Treating it as "neutral".`));const r=this.intentBacker,o=z(e);N(this,"intent",o),o!==r&&(this.intentBacker=o,this.requestUpdate("intent",r),this.applyTokensWhenRootReady())}get context(){return this.contextBacker}set context(e){const t=e??"";t!==this.contextBacker&&(this.contextBacker=t,this.applyTokensWhenRootReady(),this.refreshDescendantIntentDerivations())}refreshDescendantIntentDerivations(){const e=new Set,t=o=>{for(const s of Array.from(o.children))r(s)},r=o=>{if(!e.has(o)){if(e.add(o),o instanceof n&&o.applyTokensWhenRootReady(),o.shadowRoot&&t(o.shadowRoot),o instanceof HTMLSlotElement)for(const s of o.assignedElements({flatten:!0}))r(s);t(o)}};t(this),this.shadowRoot&&t(this.shadowRoot)}static flattenedParent(e){return e instanceof Element&&e.assignedSlot?e.assignedSlot:e instanceof ShadowRoot?e.host:e.parentNode}resolveAncestorZoneTheme(e){let t=n.flattenedParent(this);for(;t;){if(t instanceof Element&&t.localName==="esp-root")return null;if(t instanceof n){const r=t.contextBacker.trim();if(r){const o=this.resolveNamedContextTheme(e,r);if(o)return o}}t=n.flattenedParent(t)}return null}connectedCallback(){super.connectedCallback();const e=this.syncRootFromDom(!1);e&&this.subscribeToRootEvents(e)}disconnectedCallback(){super.disconnectedCallback(),this.unsubscribeFromRootEvents(),this.clearScopedTokens(),this.espRoot=null}firstUpdated(e){this.syncRootFromDom(!0),this.applyTokensWhenRootReady()}syncRootFromDom(e){const t=b(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 r=t!==this.espRoot,s=t.scheme==="dark"?"dark":"light",a=this.scheme!==s,i=this.seedColor!==t.seedColor;return this.espRoot=t,r&&this.isConnected&&this.subscribeToRootEvents(t),(r||a||i)&&(this.scheme=s,this.seedColor=t.seedColor,this.applyTokensWhenRootReady()),r&&this.requestUpdate(),t}applyTokensWhenRootReady(){const e=this.espRoot;if(e&&(!e.hasUpdated||e.isUpdatePending)){this.applyTokensAfterInitialRootUpdate(e);return}this.applyScopedColorTokens()}applyTokensAfterInitialRootUpdate(e){if(this.pendingInitialThemeRoot===e)return;this.pendingInitialThemeRoot=e;const t=e.updateComplete;if(!t){this.pendingInitialThemeRoot=null,this.applyScopedColorTokens();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.applyScopedColorTokens())})}subscribeToRootEvents(e){this.rootEventSubscriptionsActive&&this.subscribedRoot===e||(this.unsubscribeFromRootEvents(),this.subscribedRoot=e,this.rootEventUnsubscribers=[u(e,"seed-color-changed",this.handleSeedColorChanged),u(e,"scheme-changed",this.handleSchemeChanged),u(e,"theme-changed",this.handleThemeChanged),u(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 b(this,e)}applyScopedColorTokens(){if(!this.espRoot)return;const e=this.intentEmitsTokens?n.intentColorSources[this.intentBacker]:"";if(!e&&!this.context.trim()){this.clearScopedTokens();return}const t=this.espRoot.activeTheme;if(!t){this.clearScopedTokens();return}const r=this.resolveContextTheme(t),o=r.theme,s=w(o.seedColor);if(!s)return;const a=v(s,o),i={};if(r.applied&&(Object.assign(i,m(o,a)),Object.assign(i,E(o)),Object.assign(i,V)),e){let c=o;r.applied||(c=this.resolveAncestorZoneTheme(t)??o);const l=c===o?a:v(s,c),T=m(c,l,{effectiveSource:(g,d)=>n.semanticActionTokens.has(g)?e:d});i["--esp-color-primary"]=x(P(l[e]));for(const g of n.semanticActionTokens){const d=A(g);i[d]=T[d]}}this.applyScopedTokenProperties(i)}resolveContextTheme(e){const t=this.context.trim();if(!t)return{applied:!1,theme:e};const r=this.resolveNamedContextTheme(e,t);return r?{applied:!0,theme:r}:(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})}resolveNamedContextTheme(e,t){const r=e.contexts&&Object.prototype.hasOwnProperty.call(e.contexts,t)?e.contexts[t]:void 0;if(!r)return null;let o=k.get(e);const s=o?.get(t);if(s)return s;const a={};for(const c of U){const l=r[c];l!==void 0&&(a[c]=l)}const i=I(e,{lightness:r.lightness,roles:a});return o||(o=new Map,k.set(e,o)),o.set(t,i),i}applyScopedTokenProperties(e){for(const t of this.scopedTokenOriginalValues.keys())t in e||this.restoreScopedTokenProperty(t);for(const[t,r]of Object.entries(e))this.setScopedTokenProperty(t,r)}setScopedTokenProperty(e,t){const r=this.scopedTokenOriginalValues.get(e);if(r){const o=this.style.getPropertyValue(e),s=this.style.getPropertyPriority(e);(o!==r.generatedValue||s!==r.generatedPriority)&&(r.originalValue=o.length?o:null,r.originalPriority=s),r.generatedValue=t,r.generatedPriority=""}else{const o=this.style.getPropertyValue(e);this.scopedTokenOriginalValues.set(e,{generatedPriority:"",generatedValue:t,originalPriority:this.style.getPropertyPriority(e),originalValue:o.length?o:null})}this.style.setProperty(e,t)}restoreScopedTokenProperty(e){const t=this.scopedTokenOriginalValues.get(e);if(!t)return;const r=this.style.getPropertyValue(e),o=this.style.getPropertyPriority(e);(r!==t.generatedValue||o!==t.generatedPriority)&&(t.originalValue=r.length?r:null,t.originalPriority=o),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)}}n.intentColorSources={danger:"danger",info:"info",neutral:"",success:"success",warning:"warning"},n.semanticActionTokens=new Set(["actionBackground","actionText"]),n.styles=[D(".esp-field:focus-within","--esp-field-focus-shadow"),O,R`
1
+ var c=function(u,e,t,r){var o=arguments.length,s=o<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,t):r,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(u,e,t,r);else for(var i=u.length-1;i>=0;i--)(a=u[i])&&(s=(o<3?a(s):o>3?a(e,t,s):a(e,t))||s);return o>3&&s&&Object.defineProperty(e,t,s),s};import{css as T,LitElement as R}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 m}from"./utilities.js";import{parseCssColor as S,serializeOklch as w,gamutMapToSRGB as P}from"./color-engine.js";import{computeVariants as b}from"../root/helpers/compute-variants.js";import{computeSemanticProperties as v}from"../root/helpers/compute-semantic-properties.js";import{DocumentSpriteController as x}from"./document-sprite.js";import{dataCompanionProperties as E}from"../root/helpers/data-companion-properties.js";import{dataSeriesProperties as V}from"../root/helpers/compute-theme-properties.js";import{lightnessRampProperties as U}from"../root/helpers/lightness-ramp-properties.js";import{ELEVATION_PROPERTIES as I}from"./scale-engine.js";import{resolveContextTheme as A,resolveDataColorSource as O,semanticToCSS as D}from"./theme.js";import{alignAttributeTextInheritance as z,focusRing as F}from"./style-fragments.js";import{syncNormalizedAttribute as N}from"./attribute-helpers.js";import{INTENT_VARIANTS as y,normalizeIntentVariant as j}from"./intent-values.js";class n extends R{get seedColor(){return this.seedColorBacker}set seedColor(e){this.seedColorBacker=e}focusResolvedElementAfterUpdate(e,t){const r=()=>{const o=e();return o?(o.focus(t),!0):!1};r()||this.updateComplete.then(()=>{r()})}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 intent(){return this.intentBacker}set intent(e){const t=typeof e=="string"?e.trim():"";t!==""&&!y.includes(t)&&!this.warnedUnknownIntents.has(t)&&(this.warnedUnknownIntents.add(t),console.warn(`Espalier intent: "${t}" is not an intent; expected one of ${y.join(", ")}. Treating it as "neutral".`));const r=this.intentBacker,o=j(e);N(this,"intent",o),o!==r&&(this.intentBacker=o,this.requestUpdate("intent",r),this.applyTokensWhenRootReady())}get context(){return this.contextBacker}set context(e){const t=e??"";t!==this.contextBacker&&(this.contextBacker=t,this.applyTokensWhenRootReady(),this.refreshDescendantIntentDerivations())}refreshDescendantIntentDerivations(){const e=new Set,t=o=>{for(const s of Array.from(o.children))r(s)},r=o=>{if(!e.has(o)){if(e.add(o),o instanceof n&&o.applyTokensWhenRootReady(),o.shadowRoot&&t(o.shadowRoot),o instanceof HTMLSlotElement)for(const s of o.assignedElements({flatten:!0}))r(s);t(o)}};t(this),this.shadowRoot&&t(this.shadowRoot)}static flattenedParent(e){return e instanceof Element&&e.assignedSlot?e.assignedSlot:e instanceof ShadowRoot?e.host:e.parentNode}resolveAncestorZoneTheme(e){let t=n.flattenedParent(this);for(;t;){if(t instanceof Element&&t.localName==="esp-root")return null;if(t instanceof n){const r=t.contextBacker.trim();if(r){const o=this.resolveNamedContextTheme(e,r);if(o)return o}}t=n.flattenedParent(t)}return null}connectedCallback(){super.connectedCallback();const e=this.syncRootFromDom(!1);e&&this.subscribeToRootEvents(e)}disconnectedCallback(){super.disconnectedCallback(),this.unsubscribeFromRootEvents(),this.clearScopedTokens(),this.espRoot=null}firstUpdated(e){this.syncRootFromDom(!0),this.applyTokensWhenRootReady()}syncRootFromDom(e){const t=m(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 r=t!==this.espRoot,s=t.scheme==="dark"?"dark":"light",a=this.scheme!==s,i=this.seedColor!==t.seedColor;return this.espRoot=t,r&&this.isConnected&&this.subscribeToRootEvents(t),(r||a||i)&&(this.scheme=s,this.seedColor=t.seedColor,this.applyTokensWhenRootReady()),r&&this.requestUpdate(),t}applyTokensWhenRootReady(){const e=this.espRoot;if(e&&(!e.hasUpdated||e.isUpdatePending)){this.applyTokensAfterInitialRootUpdate(e);return}this.applyScopedColorTokens()}applyTokensAfterInitialRootUpdate(e){if(this.pendingInitialThemeRoot===e)return;this.pendingInitialThemeRoot=e;const t=e.updateComplete;if(!t){this.pendingInitialThemeRoot=null,this.applyScopedColorTokens();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.applyScopedColorTokens())})}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}}constructor(){super(),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.intentBacker="neutral",this.intentEmitsTokens=!0,this.warnedUnknownIntents=new Set,this.correlationId=globalThis.crypto?.randomUUID?.()??Math.random().toString(36),this.scheme="light",this.handleSeedColorChanged=e=>{this.syncRootFromDom(!1)&&(this.seedColor=e.seedColor,this.applyScopedColorTokens())},this.handleSchemeChanged=e=>{!this.syncRootFromDom(!1)||this.scheme===e.scheme||(this.scheme=e.scheme,this.applyScopedColorTokens())},this.handleThemeChanged=()=>{this.syncRootFromDom(!1)&&this.applyScopedColorTokens()},this.handleIconSpriteUrlChanged=()=>{this.syncRootFromDom(!1)&&this.requestUpdate()},new x(this,{reactToSpriteChanges:!1})}traverseToClosest(e){return m(this,e)}applyScopedColorTokens(){if(!this.espRoot)return;const e=this.intentEmitsTokens?n.intentColorSources[this.intentBacker]:"";if(!e&&!this.context.trim()){this.clearScopedTokens();return}const t=this.espRoot.activeTheme;if(!t){this.clearScopedTokens();return}const r=this.resolveContextTheme(t),o=r.theme,s=S(o.seedColor);if(!s)return;const a=b(s,o),i={};if(r.applied&&(Object.assign(i,v(o,a)),Object.assign(i,U(o)),Object.assign(i,I),Object.assign(i,E(i,V(o,s,l=>(typeof l=="string"?O(l,o.anchors):null)??o.seedColor)))),e){let l=o;r.applied||(l=this.resolveAncestorZoneTheme(t)??o);const g=l===o?a:b(s,l),k=v(l,g,{effectiveSource:(f,h)=>n.semanticActionTokens.has(f)?e:h});i["--esp-color-primary"]=w(P(g[e]));for(const f of n.semanticActionTokens){const h=D(f);i[h]=k[h]}}this.applyScopedTokenProperties(i)}resolveContextTheme(e){const t=this.context.trim();if(!t)return{applied:!1,theme:e};const r=this.resolveNamedContextTheme(e,t);return r?{applied:!0,theme:r}:(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})}resolveNamedContextTheme(e,t){return A(e,t)}applyScopedTokenProperties(e){for(const t of this.scopedTokenOriginalValues.keys())t in e||this.restoreScopedTokenProperty(t);for(const[t,r]of Object.entries(e))this.setScopedTokenProperty(t,r)}setScopedTokenProperty(e,t){const r=this.scopedTokenOriginalValues.get(e);if(r){const o=this.style.getPropertyValue(e),s=this.style.getPropertyPriority(e);(o!==r.generatedValue||s!==r.generatedPriority)&&(r.originalValue=o.length?o:null,r.originalPriority=s),r.generatedValue=t,r.generatedPriority=""}else{const o=this.style.getPropertyValue(e);this.scopedTokenOriginalValues.set(e,{generatedPriority:"",generatedValue:t,originalPriority:this.style.getPropertyPriority(e),originalValue:o.length?o:null})}this.style.setProperty(e,t)}restoreScopedTokenProperty(e){const t=this.scopedTokenOriginalValues.get(e);if(!t)return;const r=this.style.getPropertyValue(e),o=this.style.getPropertyPriority(e);(r!==t.generatedValue||o!==t.generatedPriority)&&(t.originalValue=r.length?r:null,t.originalPriority=o),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)}}n.intentColorSources={danger:"danger",info:"info",neutral:"",success:"success",warning:"warning"},n.semanticActionTokens=new Set(["actionBackground","actionText"]),n.styles=[F(".esp-field:focus-within","--esp-field-focus-shadow"),z,T`
2
2
  :host {
3
3
 
4
4
  --_esp-field-resolved-hover-bg: var(
@@ -122,4 +122,4 @@ var h=function(f,e,t,r){var o=arguments.length,s=o<3?e:r===null?r=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
- `],h([S()],n.prototype,"seedColor",null),h([p({attribute:!1})],n.prototype,"correlationId",void 0),h([p({type:String,reflect:!0})],n.prototype,"scheme",void 0),h([p({type:String,attribute:"intent",reflect:!0,useDefault:!0})],n.prototype,"intent",null),h([p({type:String,attribute:"context",reflect:!0})],n.prototype,"context",null);export{n as EspalierElementBase};
125
+ `],c([C()],n.prototype,"seedColor",null),c([d({attribute:!1})],n.prototype,"correlationId",void 0),c([d({type:String,reflect:!0})],n.prototype,"scheme",void 0),c([d({type:String,attribute:"intent",reflect:!0,useDefault:!0})],n.prototype,"intent",null),c([d({type:String,attribute:"context",reflect:!0})],n.prototype,"context",null);export{n as EspalierElementBase};
@@ -16,6 +16,35 @@ export declare function getIconHrefForHost(icon: string | null | undefined, host
16
16
  * "Converting circular structure to JSON". A plain backticked name is safe.
17
17
  */
18
18
  export declare const getIconHref: typeof getIconHrefForHost;
19
+ /**
20
+ * The configured sprite, classified (ESP0176).
21
+ *
22
+ * - `url` — an ordinary sprite location; hrefs become `url#name`.
23
+ * - `document` — the same-document form: a value that IS a fragment
24
+ * (`#sprite-id`) names an inline `<svg>` sprite already in the
25
+ * document — Espalier's own `ICON_SPRITE`, or any sprite the site
26
+ * provides. Hrefs become bare `#name` and components adopt the
27
+ * referenced symbols into their shadow roots.
28
+ * - `none` — the empty value; generated sprite icons are disabled.
29
+ */
30
+ export type IconSpriteReference = {
31
+ kind: "url";
32
+ url: string;
33
+ } | {
34
+ kind: "document";
35
+ spriteId: string;
36
+ } | {
37
+ kind: "none";
38
+ };
39
+ export declare function getIconSpriteReference(host: Element | null | undefined): IconSpriteReference;
40
+ /** Classify a raw `icon-sprite-url` value. */
41
+ export declare function classifyIconSpriteValue(value: string | null | undefined): IconSpriteReference;
42
+ /**
43
+ * The configured sprite URL with any fragment stripped, or `""` when
44
+ * generated icons are off — including the same-document form, which
45
+ * has no URL. Prefer {@link getIconSpriteReference}, which the
46
+ * same-document mode of ESP0176 made the complete answer.
47
+ */
19
48
  export declare function getIconSpriteUrl(host: Element | null | undefined): string;
20
49
  /**
21
50
  * Reset the per-process record of which invalid icon names have
@@ -1 +1 @@
1
- import{traverseToClosest as a}from"./utilities.js";const i="/assets/icons.svg",p="0 0 24 24",c=/^[A-Za-z0-9][A-Za-z0-9_-]*$/u,l=100,r=new Set,o=[],u=["neutral","success","warning","danger","info"];function N(n){return u.includes(n)?n:"neutral"}function I(n,t=null){const e=n?.trim()??"";if(!c.test(e))return e.length>0&&m(e)&&console.warn(`Invalid Espalier icon name "${e}". Icon names must start with a letter or number and may only contain letters, numbers, dashes, and underscores.`),"";const s=d(t);return s?`${s}#${e}`:""}const _=I;function d(n){const t=n?a(n,"esp-root"):null;return(t?(t.iconSpriteUrl??"").trim():i).split("#")[0]?.trim()||""}function m(n){if(r.has(n))return!1;if(r.add(n),o.push(n),o.length>l){const t=o.shift();t&&r.delete(t)}return!0}function g(){r.clear(),o.length=0}export{i as DEFAULT_ICON_SPRITE_URL,p as DEFAULT_ICON_VIEW_BOX,u as INTENT_VARIANTS,_ as getIconHref,I as getIconHrefForHost,d as getIconSpriteUrl,N as normalizeIntentVariant,g as resetWarnedInvalidIconNames};
1
+ import{traverseToClosest as i}from"./utilities.js";const u="/assets/icons.svg",N="0 0 24 24",a=/^[A-Za-z0-9][A-Za-z0-9_-]*$/u,l=100,o=new Set,s=[],d=["neutral","success","warning","danger","info"];function _(n){return d.includes(n)?n:"neutral"}function I(n,e=null){const t=n?.trim()??"";if(!a.test(t))return t.length>0&&m(t)&&console.warn(`Invalid Espalier icon name "${t}". Icon names must start with a letter or number and may only contain letters, numbers, dashes, and underscores.`),"";const r=c(e);switch(r.kind){case"url":return`${r.url}#${t}`;case"document":return`#${t}`;default:return""}}const g=I;function c(n){const e=n?i(n,"esp-root"):null;return f(e?e.iconSpriteUrl:u)}function f(n){const e=(n??"").trim();if(e.startsWith("#")){const r=e.slice(1).trim();return r?{kind:"document",spriteId:r}:{kind:"none"}}const t=e.split("#")[0]?.trim()||"";return t?{kind:"url",url:t}:{kind:"none"}}function A(n){const e=c(n);return e.kind==="url"?e.url:""}function m(n){if(o.has(n))return!1;if(o.add(n),s.push(n),s.length>l){const e=s.shift();e&&o.delete(e)}return!0}function h(){o.clear(),s.length=0}export{u as DEFAULT_ICON_SPRITE_URL,N as DEFAULT_ICON_VIEW_BOX,d as INTENT_VARIANTS,f as classifyIconSpriteValue,g as getIconHref,I as getIconHrefForHost,c as getIconSpriteReference,A as getIconSpriteUrl,_ as normalizeIntentVariant,h as resetWarnedInvalidIconNames};
@@ -48,7 +48,7 @@
48
48
  * report.adjustedTokens; // ['linkHover']
49
49
  * ```
50
50
  */
51
- import { type EspalierTheme, type LightnessKey, type MappingSource, type SemanticColorName } from "./theme.js";
51
+ import { type EspalierTheme, type LightnessKey, type MappingSource, type PartialTheme, type SemanticColorName } from "./theme.js";
52
52
  /** What APCA enforcement did to one token. */
53
53
  export interface ThemeFitApcaAction {
54
54
  /** The requested value, as an `oklch()` string. */
@@ -105,6 +105,14 @@ export interface ThemeFitToken {
105
105
  anchor?: ThemeFitAnchor;
106
106
  /** Present for the text tokens APCA enforcement guards. */
107
107
  apca?: ThemeFitApcaAction;
108
+ /**
109
+ * Present when the mapping was pinned token-level rather than compiled
110
+ * from roles (ESP0175). `"declared"` means this surface's own
111
+ * declaration pinned it; `"inherited"` means a root-level pin survived
112
+ * into this context — the silent case this marker exists to surface,
113
+ * since a zone's unexpected value then traces to a root theme line.
114
+ */
115
+ explicit?: "declared" | "inherited";
108
116
  }
109
117
  /**
110
118
  * A theme's fit report — the stable JSON shape the docs site renders.
@@ -135,6 +143,17 @@ export interface ThemeFitRow {
135
143
  /** The anchor reference and its ΔE; empty for non-anchor sources. */
136
144
  anchor: string;
137
145
  }
146
+ /** Options for {@link themeFitReport}. */
147
+ export interface ThemeFitReportOptions {
148
+ /**
149
+ * Report a named context's surface instead of the root (ESP0175). The
150
+ * context compiles through the exact zone path a `context` attribute
151
+ * uses — `resolveContextTheme` — so the report cannot drift from what
152
+ * a zone host renders. Unknown names throw, mirroring the zone host's
153
+ * warning for an undefined context.
154
+ */
155
+ context?: string;
156
+ }
138
157
  /**
139
158
  * Build the fit report for a resolved theme.
140
159
  *
@@ -142,10 +161,11 @@ export interface ThemeFitRow {
142
161
  * what it did. An unparseable seed produces an empty token list, exactly
143
162
  * as it produces an empty property record.
144
163
  *
145
- * @param theme A resolved theme (as `mergeTheme` returns).
146
- * @param scheme The scheme to compute.
164
+ * @param theme A resolved theme (as `mergeTheme` returns).
165
+ * @param scheme The scheme to compute.
166
+ * @param options Surface selection; omit for the root surface.
147
167
  */
148
- export declare function themeFitReport(theme: EspalierTheme, scheme: "light" | "dark"): ThemeFitReport;
168
+ export declare function themeFitReport(theme: EspalierTheme, scheme: "light" | "dark", options?: ThemeFitReportOptions): ThemeFitReport;
149
169
  /**
150
170
  * Render a report as `console.table` rows.
151
171
  *
@@ -160,3 +180,73 @@ export declare function themeFitRows(report: ThemeFitReport): ThemeFitRow[];
160
180
  * then a `console.table` of every token.
161
181
  */
162
182
  export declare function printThemeFitReport(report: ThemeFitReport): void;
183
+ /** One cross-token finding over a single surface's emitted values. */
184
+ export interface ThemeFitLint {
185
+ /** Stable lint identifier. */
186
+ id: "action-canvas-separation" | "link-hover-ordering";
187
+ /** Lints describe design-quality hazards, not validation failures. */
188
+ severity: "warning";
189
+ /** The tokens the finding is about. */
190
+ tokens: SemanticColorName[];
191
+ /** The measured number the lint fired on (ΔE-OK, or an Lc deficit). */
192
+ measured: number;
193
+ /** Human-readable finding, with the remedy phrased as a retune. */
194
+ message: string;
195
+ }
196
+ /**
197
+ * Cross-token lints over one surface's report (ESP0175).
198
+ *
199
+ * Both checks consume only the report's `resolved` strings — the emitted
200
+ * custom-property values — so the lints, like the report, cannot
201
+ * disagree with the pipeline:
202
+ *
203
+ * - **action-canvas-separation** — a filled action within ΔE-OK 0.045 of
204
+ * the surface's own background vanishes into it. The stop placement
205
+ * avoids this when any viable stop exists; the lint reports the
206
+ * residue (explicit pins, ramps with no separated stop).
207
+ * - **link-hover-ordering** — measured on the surfaces the states
208
+ * actually render: resting `link` on `background`, hovered `linkHover`
209
+ * on the `linkHoverBg` wash. When the theme paints a real wash, the
210
+ * wash itself signals the state and the ink must clear the text tier
211
+ * there; when the wash equals the background (no visible wash), hover
212
+ * must not read weaker than rest — a dimming hover feels disabled.
213
+ */
214
+ export declare function themeFitLints(report: ThemeFitReport): ThemeFitLint[];
215
+ /**
216
+ * The root surface's identifier in a suite. Deliberately not a valid
217
+ * context slug (slugs are letter-first), so no theme-declared context
218
+ * name — `root` included, which has been a legal name since contexts
219
+ * shipped — can ever collide with it.
220
+ */
221
+ export declare const ROOT_SURFACE = ":root";
222
+ /** One surface's report inside a {@link ThemeFitSuite}. */
223
+ export interface ThemeFitSurfaceReport extends ThemeFitReport {
224
+ /** {@link ROOT_SURFACE}, or the context name a zone would set. */
225
+ surface: string;
226
+ /** Cross-token lints over this surface's emitted values. */
227
+ lints: ThemeFitLint[];
228
+ }
229
+ /**
230
+ * Every surface a themed site has, both schemes, in one stable shape.
231
+ */
232
+ export interface ThemeFitSuite {
233
+ /** Surface names in report order: {@link ROOT_SURFACE}, then contexts, sorted. */
234
+ surfaces: string[];
235
+ /** One report per surface the light theme defines. */
236
+ light: ThemeFitSurfaceReport[];
237
+ /** One report per surface the dark theme defines. */
238
+ dark: ThemeFitSurfaceReport[];
239
+ }
240
+ /**
241
+ * Fit-report every surface a themed site has (ESP0175): for each scheme,
242
+ * the root plus every declared context, each with its cross-token lints.
243
+ *
244
+ * Takes the partials an `esp-root` would take (they merge over the same
245
+ * scheme defaults the root uses), so the suite describes exactly the
246
+ * site the partials produce — the 448-line hand-rolled check script,
247
+ * minus the client-specific lines. Surfaces are the union of both
248
+ * schemes' context names so an asymmetric pair still reports every
249
+ * surface it can; `validateThemePair` is the gate that rejects the
250
+ * asymmetry itself.
251
+ */
252
+ export declare function themeFitReportSuite(lightPartial: PartialTheme, darkPartial: PartialTheme): ThemeFitSuite;
@@ -1 +1 @@
1
- import{apcaContrast as d,deltaEOK as f,parseOklch as u,serializeOklch as n}from"./color-engine.js";import{parseAnchorSource as l}from"./theme.js";import{computeThemeProperties as h}from"../root/helpers/compute-theme-properties.js";function A(e,o){const s=[];h(e,o,s);const r=s.map(v);return{scheme:o,seedColor:e.seedColor,anchors:m(e.anchors),tokens:r,adjustedTokens:r.filter(t=>t.adjusted).map(t=>t.token)}}function p(e){return e.tokens.map(o=>({token:o.token,source:o.source,requested:o.requested,resolved:o.resolved,apca:$(o),anchor:g(o)}))}function R(e){const o=e.adjustedTokens.length>0?`APCA moved ${e.adjustedTokens.join(", ")}`:"APCA moved nothing";console.info(`Espalier theme fit \u2014 ${e.scheme} scheme, seed ${e.seedColor}. ${o}.`),console.table(p(e))}function a(e,o){const s=Math.pow(10,o);return Math.round(e*s)/s}function i(e,o){return o===void 0?e:`${e}.${o}`}function m(e){const o={};for(const[s,r]of Object.entries(e)){if(typeof r=="string"){o[s]=r;continue}for(const[t,c]of Object.entries(r))o[t==="color"?s:i(s,t)]=c}return o}function v(e){const o=u(e.resolved),s=e.requested===void 0?e.resolved:n(e.requested),r={token:e.token,property:e.property,source:e.source,lightness:e.lightness,requested:s,resolved:e.resolved,adjusted:s!==e.resolved,sourceResolved:e.sourceResolved},t=l(e.source);if(t&&e.sourceResolved&&(r.anchor={reference:i(t.name,t.slot),color:n(e.base),deltaE:a(f(e.base,o),4)}),e.contrast){const c=e.contrast.background;r.apca={from:s,to:e.resolved,targetLc:e.contrast.targetLc,against:e.contrast.against,againstColor:n(c),fromLc:a(Math.abs(d(u(s),c)),1),toLc:a(Math.abs(d(o,c)),1)}}return r}function $(e){if(!e.apca)return"";const{targetLc:o,against:s,fromLc:r,toLc:t}=e.apca;return e.adjusted?`Lc ${o} vs ${s} \u2014 pushed from Lc ${r} to Lc ${t}`:`Lc ${o} vs ${s} \u2014 met at Lc ${r}`}function g(e){return e.anchor?`${e.anchor.reference} \u0394E ${e.anchor.deltaE}`:e.sourceResolved?"":"unresolved \u2014 seed used"}export{R as printThemeFitReport,A as themeFitReport,p as themeFitRows};
1
+ import{apcaContrast as h,deltaEOK as f,parseOklch as p,serializeOklch as v}from"./color-engine.js";import{DEFAULT_DARK_THEME as T,DEFAULT_LIGHT_THEME as R,explicitMappingTokens as $,mergeTheme as m,parseAnchorSource as x,resolveContextTheme as A}from"./theme.js";import{computeThemeProperties as H}from"../root/helpers/compute-theme-properties.js";function _(e,t,n={}){let o=e,r=null;if(n.context!==void 0){const c=A(e,n.context);if(!c)throw new Error(`themeFitReport: context "${n.context}" is not defined by the theme.`);o=c,r=new Set(Object.keys(e.contexts[n.context]?.semanticMappings??{}))}const i=[];H(o,t,i);const l=$(o),u=i.map(c=>{const s=j(c);return l.has(s.token)&&(s.explicit=r===null||r.has(s.token)?"declared":"inherited"),s});return{scheme:t,seedColor:o.seedColor,anchors:M(o.anchors),tokens:u,adjustedTokens:u.filter(c=>c.adjusted).map(c=>c.token)}}function w(e){return e.tokens.map(t=>({token:t.token,source:t.source,requested:t.requested,resolved:t.resolved,apca:I(t),anchor:F(t)}))}function D(e){const t=e.adjustedTokens.length>0?`APCA moved ${e.adjustedTokens.join(", ")}`:"APCA moved nothing";console.info(`Espalier theme fit \u2014 ${e.scheme} scheme, seed ${e.seedColor}. ${t}.`),console.table(w(e))}const L=.045,b=.5,k=75,O=.045;function C(e){const t=[],n=new Map(e.tokens.map(s=>[s.token,s.resolved])),o=s=>{const a=n.get(s);return a===void 0?null:p(a)},r=o("background"),i=o("actionBackground");if(r&&i){const s=f(i,r);if(s<L){const a=d(s,4);t.push({id:"action-canvas-separation",severity:"warning",tokens:["actionBackground","background"],measured:a,message:`actionBackground sits \u0394E ${a} from background (floor ${L}) \u2014 filled actions vanish into this canvas. Retune the surface apart: move the background stop, or pin actionBackground to a separated stop.`})}}const l=o("link"),u=o("linkHover"),c=o("linkHoverBg");if(r&&l&&u&&c){const s=Math.abs(h(l,r)),a=Math.abs(h(u,c));f(c,r)>=O?a+b<k&&t.push({id:"link-hover-ordering",severity:"warning",tokens:["linkHover","linkHoverBg"],measured:d(k-a,1),message:`linkHover reaches only Lc ${d(a,1)} on the linkHoverBg wash it actually paints (tier ${k}) \u2014 retune linkHover or the wash apart until the hovered state clears the text tier.`}):a+b<s&&t.push({id:"link-hover-ordering",severity:"warning",tokens:["linkHover","link"],measured:d(s-a,1),message:`linkHover reads weaker than link on the same canvas (Lc ${d(a,1)} vs ${d(s,1)}) \u2014 a dimming hover feels disabled. Retune linkHover toward more contrast than the resting link.`})}return t}const g=":root";function V(e,t){const n=m(R,e),o=m(T,t),r=[g,...[...new Set([...Object.keys(n.contexts),...Object.keys(o.contexts)])].sort()],i=(l,u)=>{const c=[];for(const s of r){if(s!==g&&!(s in l.contexts))continue;const a=_(l,u,s===g?{}:{context:s});c.push({...a,surface:s,lints:C(a)})}return c};return{surfaces:r,light:i(n,"light"),dark:i(o,"dark")}}function d(e,t){const n=Math.pow(10,t);return Math.round(e*n)/n}function E(e,t){return t===void 0?e:`${e}.${t}`}function M(e){const t={};for(const[n,o]of Object.entries(e)){if(typeof o=="string"){t[n]=o;continue}for(const[r,i]of Object.entries(o))t[r==="color"?n:E(n,r)]=i}return t}function j(e){const t=p(e.resolved),n=e.requested===void 0?e.resolved:v(e.requested),o={token:e.token,property:e.property,source:e.source,lightness:e.lightness,requested:n,resolved:e.resolved,adjusted:n!==e.resolved,sourceResolved:e.sourceResolved},r=x(e.source);if(r&&e.sourceResolved&&(o.anchor={reference:E(r.name,r.slot),color:v(e.base),deltaE:d(f(e.base,t),4)}),e.contrast){const i=e.contrast.background;o.apca={from:n,to:e.resolved,targetLc:e.contrast.targetLc,against:e.contrast.against,againstColor:v(i),fromLc:d(Math.abs(h(p(n),i)),1),toLc:d(Math.abs(h(t,i)),1)}}return o}function I(e){if(!e.apca)return"";const{targetLc:t,against:n,fromLc:o,toLc:r}=e.apca;return e.adjusted?`Lc ${t} vs ${n} \u2014 pushed from Lc ${o} to Lc ${r}`:`Lc ${t} vs ${n} \u2014 met at Lc ${o}`}function F(e){return e.anchor?`${e.anchor.reference} \u0394E ${e.anchor.deltaE}`:e.sourceResolved?"":"unresolved \u2014 seed used"}export{g as ROOT_SURFACE,D as printThemeFitReport,C as themeFitLints,_ as themeFitReport,V as themeFitReportSuite,w as themeFitRows};