@taprootio/espalier 2.19.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/custom-elements.json +45897 -34042
- package/dist/badge/esp-badge.d.ts +7 -6
- package/dist/badge/esp-badge.js +6 -6
- package/dist/box/esp-box.d.ts +5 -5
- package/dist/button/esp-button.d.ts +6 -12
- package/dist/button/esp-button.js +3 -3
- package/dist/date-picker/esp-date-picker.js +2 -2
- package/dist/details/esp-details-group.d.ts +0 -13
- package/dist/details/esp-details.d.ts +9 -9
- package/dist/dialog/esp-dialog.d.ts +4 -4
- package/dist/empty-state/esp-empty-state.d.ts +1 -1
- package/dist/form/esp-form.d.ts +5 -5
- package/dist/grid/esp-grid.d.ts +8 -8
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/info/esp-info.d.ts +6 -4
- package/dist/info/esp-info.js +15 -15
- package/dist/input/esp-input.d.ts +5 -3
- package/dist/lightbox/esp-lightbox.js +1 -1
- package/dist/pickers/esp-picker-menu.d.ts +1 -0
- package/dist/pickers/esp-picker-menu.js +6 -6
- package/dist/progress/esp-progress.d.ts +24 -24
- package/dist/repeater/esp-repeater.d.ts +0 -3
- package/dist/root/helpers/compute-semantic-properties.js +1 -0
- package/dist/root/helpers/compute-theme-properties.js +1 -1
- package/dist/root/helpers/lightness-ramp-properties.js +1 -0
- package/dist/shared/bus-events.d.ts +2 -2
- package/dist/shared/esp-element-base.d.ts +40 -16
- package/dist/shared/esp-element-base.js +2 -2
- package/dist/shared/style-fragments.js +39 -9
- package/dist/shared/theme.d.ts +34 -16
- package/dist/shared/theme.js +1 -1
- package/dist/shared/toast-events.d.ts +6 -5
- package/dist/status-indicator/esp-status-indicator.d.ts +13 -12
- package/dist/status-indicator/esp-status-indicator.js +7 -7
- package/dist/tabs/esp-tab-group.d.ts +8 -6
- package/dist/textarea/esp-textarea.d.ts +5 -4
- package/dist/toaster/esp-toaster.d.ts +9 -9
- package/dist/toaster/esp-toaster.js +3 -3
- package/dist/tree/esp-tree.js +2 -2
- package/package.json +1 -1
- package/dist/shared/esp-intent-element-base.d.ts +0 -10
- package/dist/shared/esp-intent-element-base.js +0 -31
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var
|
|
1
|
+
var a=function(p,t,e,i){var l=arguments.length,s=l<3?t:i===null?i=Object.getOwnPropertyDescriptor(t,e):i,r;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(p,t,e,i);else for(var n=p.length-1;n>=0;n--)(r=p[n])&&(s=(l<3?r(s):l>3?r(t,e,s):r(t,e))||s);return l>3&&s&&Object.defineProperty(t,e,s),s};import{LitElement as y,css as I,html as d}from"lit";import{customElement as b,property as u,state as f}from"lit/decorators.js";import{createRef as x,ref as P}from"lit/directives/ref.js";import{styleMap as w}from"lit/directives/style-map.js";import"../shared/virtualizer/lit-virtualizer.js";import{spaceAroundRect as v,viewportSize as g}from"../shared/viewport.js";const c="highlighted";let o=class extends y{constructor(){super(),this.internals=this.attachInternals(),this.virtualizerRef=x(),this.internalPoolClone=null,this.lastPoolFingerprint=null,this.preRenderScrollTop=null,this.openSessionGeneration=0,this.maxAvailableHeight=0,this.lastViewportHeight=0,this.label="",this.virtualizedItemsPool=[],this.highlightIndex=-1,this.multiSelect=!1,this.loading=!1,this.emptyMessage="",this.handleItemPointerDown=t=>{this.selectItemFromPointerEvent(t)},this.menuDirty=!1,this.settlerActive=!1,this.pendingItemsChanged=!1,this.retargetingSequence=!1,this.renderPickerItem=(t,e)=>{const i={display:"block",cursor:"pointer",width:"100%",...t.styles};return d`<esp-picker-item
|
|
2
2
|
class="picker-item"
|
|
3
3
|
data-picker-index=${e}
|
|
4
4
|
.text=${t.text}
|
|
@@ -6,17 +6,17 @@ var n=function(d,t,e,i){var l=arguments.length,s=l<3?t:i===null?i=Object.getOwnP
|
|
|
6
6
|
.selected=${t.selected}
|
|
7
7
|
.icon=${t.icon??""}
|
|
8
8
|
.highlightRanges=${t.highlightRanges}
|
|
9
|
-
style=${
|
|
9
|
+
style=${w(i)}
|
|
10
10
|
>
|
|
11
11
|
${t.slotNodes?.map(l=>l.cloneNode(!0))}
|
|
12
|
-
</esp-picker-item>`},this.internals.role="listbox"}connectedCallback(){super.connectedCallback(),this.setAttribute("popover","manual"),this.hasAttribute("role")||this.setAttribute("role","listbox")}updated(t){super.updated(t),t.has("multiSelect")&&(this.internals.ariaMultiSelectable=String(this.multiSelect),this.setAttribute("aria-multiselectable",String(this.multiSelect))),t.has("label")&&(this.internals.ariaLabel=this.label,this.label?this.setAttribute("aria-label",this.label):this.removeAttribute("aria-label")),(t.has("virtualizedItemsPool")||t.has("loading"))&&this.maxAvailableHeight>0&&this.matches(":popover-open")&&this.resizeAndHighlight(t.has("virtualizedItemsPool"))}get pickerItems(){return this.virtualizedItemsPool}set pickerItems(t){const e=this.virtualizedItemsPool.filter(s=>s.selected).map(s=>s.value);this.virtualizedItemsPool=t;const i=t.filter(s=>s.selected),l=i.map(s=>s.value);(e.length!==l.length||e.some((s,r)=>s!==l[r]))&&this.dispatchEvent(new CustomEvent("selection-changed",{detail:i,bubbles:!0,composed:!0}))}setHighlight(t){const e=this.virtualizedItemsPool;if(e.length===0)return;(this.highlightIndex<0||this.highlightIndex>e.length-1)&&(this.highlightIndex=t);const i=this.virtualizerRef.value;i&&i.scrollToIndex(this.highlightIndex,"nearest"),this.applyHighlightClass()}async setHighlightAsync(t){const e=this.virtualizedItemsPool;if(e.length===0)return;(this.highlightIndex<0||this.highlightIndex>e.length-1)&&(this.highlightIndex=t);const i=this.virtualizerRef.value;if(i)try{const l=i.layoutComplete;l&&await l,i.scrollToIndex(this.highlightIndex,"nearest");const s=i.layoutComplete;s&&await s}catch{return}this.applyHighlightClass()}applyHighlightClass(){this.clearHighlight();const t=this.getHighlightedElement();t&&t.classList.add(c)}clearHighlight(){const t=this.virtualizerRef.value;if(t)for(const e of t.querySelectorAll(`esp-picker-item.${c}`))e.classList.remove(c)}resetHighlight(){this.clearHighlight();const t=this.virtualizedItemsPool.find(e=>e.selected);this.highlightIndex=t?this.virtualizedItemsPool.indexOf(t):-1}applyHighlightWithRetry(t){if(!this.isConnected||!this.matches(":popover-open"))return;this.clearHighlight();const e=this.getHighlightedElement();if(e){e.classList.add(c);return}t>0&&requestAnimationFrame(()=>this.applyHighlightWithRetry(t-1))}getHighlightedElement(){if(this.highlightIndex<0)return null;const t=this.virtualizerRef.value;if(!t)return null;const e=t.querySelectorAll("esp-picker-item");for(const i of e)if(this.virtualizedItemsPool.findIndex(s=>s.value===i.value&&s.text===i.text)===this.highlightIndex)return i;return null}pickItem(t){for(const i of this.pickerItems)i===t?i.selected=!i.selected:this.multiSelect||(i.selected=!1);const e=this.virtualizedItemsPool.indexOf(t);if(e!==-1){this.highlightIndex=e,this.clearHighlight();const i=this.getHighlightedElement();i&&i.classList.add(c)}this.pickerItems=[...this.pickerItems],this.dispatchEvent(new CustomEvent("selection-changed",{detail:this.pickerItems.filter(i=>i.selected),bubbles:!0,composed:!0})),this.multiSelect||this.dispatchEvent(new CustomEvent("close-menu",{detail:this.pickerItems.filter(i=>i.selected),bubbles:!0,composed:!0}))}selectItemByIndex(t){const e=Number.isInteger(t)?this.virtualizedItemsPool[t]:void 0;return e?(this.pickItem(e),!0):!1}getPickerItemElementAtPoint(t,e){const i=this.shadowRoot?.querySelectorAll("esp-picker-item[data-picker-index]");if(!i)return null;for(const l of i){const s=l.getBoundingClientRect();if(t>=s.left&&t<=s.right&&e>=s.top&&e<=s.bottom)return l}return null}selectPickerItemElement(t){return t?this.selectItemByIndex(Number(t.dataset.pickerIndex)):!1}selectItemAtPoint(t,e){return this.selectPickerItemElement(this.getPickerItemElementAtPoint(t,e))}selectItemFromPointerEvent(t){const e=t.composedPath().find(l=>l instanceof HTMLElement&&l.matches("esp-picker-item[data-picker-index]"));return this.selectPickerItemElement(e??this.getPickerItemElementAtPoint(t.clientX,t.clientY))?(t.preventDefault(),t.stopPropagation(),!0):!1}positionSelf(t){const e=t.getBoundingClientRect(),{height:i}=u(),{spaceAbove:l,spaceBelow:s}=f(e,i),r=Math.max(Math.max(l,s)-75,0);this.maxAvailableHeight=r,this.lastViewportHeight=i,this.style.setProperty("height",`${r}px`),this.style.setProperty("min-width",`${e.width}px`),this.style.setProperty("left",`${e.left}px`),this.style.removeProperty("top"),this.style.removeProperty("bottom"),l>s?this.style.setProperty("bottom",`${i-e.top}px`):this.style.setProperty("top",`${e.bottom}px`),this.classList.remove("visible"),this.matches(":popover-open")||this.showPopover();const o=this.pickerItems.find(a=>a.selected);this.highlightIndex=o?this.pickerItems.indexOf(o):0,this.setHighlightAsync(0).then(()=>{requestAnimationFrame(()=>{this.shrinkToFit(r),this.widenToFitContent(e),this.classList.add("visible")})})}async resizeAndHighlight(t){try{await this.updateComplete}catch{return}if(!this.isConnected||!this.matches(":popover-open"))return;const e=this.virtualizerRef.value;if(!e){requestAnimationFrame(()=>{if(!this.isConnected)return;const s=this.shadowRoot?.querySelector(".status-message");if(s){const r=Math.min(s.scrollHeight,this.maxAvailableHeight);this.style.setProperty("height",`${r}px`)}});return}try{const s=e.layoutComplete;s&&await s}catch{return}if(!this.isConnected||!this.matches(":popover-open")||(e.scrollTop=0,this.sizeToContent(this.maxAvailableHeight),!t))return;try{const s=e.layoutComplete;s&&await s}catch{return}if(!this.isConnected||!this.matches(":popover-open"))return;const i=this.virtualizedItemsPool;if(i.length===0)return;const l=i.findIndex(s=>s.selected);l>=0?this.highlightIndex=l:this.highlightIndex>=i.length?this.highlightIndex=i.length-1:this.highlightIndex<0&&(this.highlightIndex=0);try{e.scrollToIndex(this.highlightIndex,"nearest")}catch{}try{const s=e.layoutComplete;s&&await s}catch{return}!this.isConnected||!this.matches(":popover-open")||this.applyHighlightWithRetry(3)}sizeToContent(t){const e=this.measureContentHeight();e>0&&this.style.setProperty("height",`${Math.min(e,t)}px`)}shrinkToFit(t){const e=this.measureContentHeight();e>2&&e<t&&this.style.setProperty("height",`${e}px`)}measureContentHeight(){const t=this.virtualizerRef.value;if(!t)return 0;const e=t.querySelectorAll("esp-picker-item");if(e.length===0)return 0;const i=getComputedStyle(this),l=(parseFloat(i.borderTopWidth)||0)+(parseFloat(i.borderBottomWidth)||0),s=this.virtualizedItemsPool.length;if(e.length<s)return t.scrollHeight+l;t.scrollTop=0;const r=t.getBoundingClientRect();return e[e.length-1].getBoundingClientRect().bottom-r.top+l}widenToFitContent(t){const e=this.virtualizerRef.value;if(!e)return;const i=e.querySelectorAll("esp-picker-item");let l=t.width;for(const s of i)l=Math.max(l,s.scrollWidth);if(l+=2,l>t.width){const{width:s}=u(),r=Math.min(l,s-t.left);this.style.setProperty("width",`${r}px`)}}updatePosition(t){const e=t.getBoundingClientRect(),{height:i}=u();if(i!==this.lastViewportHeight){const{spaceAbove:r,spaceBelow:o}=f(e,i),a=Math.max(Math.max(r,o)-75,0);this.maxAvailableHeight=a,this.lastViewportHeight=i,(parseFloat(this.style.getPropertyValue("height"))||0)>a&&this.style.setProperty("height",`${a}px`),this.sizeToContent(a)}this.style.setProperty("left",`${e.left}px`);const l=e.top,s=i-e.bottom;l>s?(this.style.removeProperty("top"),this.style.setProperty("bottom",`${i-e.top}px`)):(this.style.removeProperty("bottom"),this.style.setProperty("top",`${e.bottom}px`))}hideMenu(){this.classList.remove("visible");try{this.hidePopover()}catch{}}doKeyboardNav(t){const e=this.virtualizedItemsPool;if(e.length!==0)switch(t){case"ArrowDown":this.highlightIndex+=1,this.setHighlight(0);break;case"ArrowUp":this.highlightIndex-=1,this.setHighlight(e.length-1);break;case"Home":this.highlightIndex=0,this.setHighlight(0);break;case"End":this.highlightIndex=e.length-1,this.setHighlight(e.length-1);break;case"Enter":if(this.highlightIndex===-1)return;this.pickItem(e[this.highlightIndex]);break}}render(){return this.loading?p`<div class="status-message">Searching…</div>`:this.virtualizedItemsPool.length===0&&this.emptyMessage?p`<div class="status-message">${this.emptyMessage}</div>`:p`<lit-virtualizer
|
|
13
|
-
${
|
|
12
|
+
</esp-picker-item>`},this.internals.role="listbox"}connectedCallback(){super.connectedCallback(),this.setAttribute("popover","manual"),this.hasAttribute("role")||this.setAttribute("role","listbox")}willUpdate(t){if(super.willUpdate(t),t.has("virtualizedItemsPool")&&this.preRenderScrollTop===null&&!this.retargetingSequence&&this.matches(":popover-open")){const e=this.virtualizerRef.value?.scrollTop??0;e>0&&(this.preRenderScrollTop=e)}}updated(t){super.updated(t),t.has("multiSelect")&&(this.internals.ariaMultiSelectable=String(this.multiSelect),this.setAttribute("aria-multiselectable",String(this.multiSelect))),t.has("label")&&(this.internals.ariaLabel=this.label,this.label?this.setAttribute("aria-label",this.label):this.removeAttribute("aria-label"));const e=t.has("virtualizedItemsPool");let i=!1;if(e){const l=this.virtualizedItemsPool===this.internalPoolClone;this.internalPoolClone=null;const s=this.virtualizedItemsPool.map(r=>`${r.value}\0${r.text}\0${r.selected===!0}`);i=!l&&(this.lastPoolFingerprint===null||this.lastPoolFingerprint.length!==s.length||this.lastPoolFingerprint.some((r,n)=>r!==s[n])),this.lastPoolFingerprint=s}(e||t.has("loading"))&&this.maxAvailableHeight>0&&this.matches(":popover-open")&&(this.pendingItemsChanged||=i,this.menuDirty=!0,this.settleMenuAfterUpdate())}get pickerItems(){return this.virtualizedItemsPool}set pickerItems(t){const e=this.virtualizedItemsPool.filter(s=>s.selected).map(s=>s.value);this.virtualizedItemsPool=t;const i=t.filter(s=>s.selected),l=i.map(s=>s.value);(e.length!==l.length||e.some((s,r)=>s!==l[r]))&&this.dispatchEvent(new CustomEvent("selection-changed",{detail:i,bubbles:!0,composed:!0}))}setHighlight(t){const e=this.virtualizedItemsPool;if(e.length===0)return;(this.highlightIndex<0||this.highlightIndex>e.length-1)&&(this.highlightIndex=t);const i=this.virtualizerRef.value;i&&i.scrollToIndex(this.highlightIndex,"nearest"),this.applyHighlightClass()}async setHighlightAsync(t){const e=this.openSessionGeneration,i=()=>e!==this.openSessionGeneration||!this.isConnected,l=this.virtualizedItemsPool;if(l.length===0)return;(this.highlightIndex<0||this.highlightIndex>l.length-1)&&(this.highlightIndex=t);const s=this.virtualizerRef.value;if(s){if(await this.stableLayout(s),i())return;const r=s.scrollTop;for(let n=0;n<3;n+=1)try{s.scrollToIndex(this.highlightIndex,"nearest");break}catch{if(await this.stableLayout(s),i()||s.scrollTop!==r)return}if(await this.stableLayout(s),i())return}this.applyHighlightWithRetry(3)}applyHighlightClass(){const t=this.getHighlightedElement();t&&(this.clearHighlight(),t.classList.add(c))}clearHighlight(){const t=this.virtualizerRef.value;if(t)for(const e of t.querySelectorAll(`esp-picker-item.${c}`))e.classList.remove(c)}resetHighlight(){this.clearHighlight();const t=this.virtualizedItemsPool.find(e=>e.selected);this.highlightIndex=t?this.virtualizedItemsPool.indexOf(t):-1}applyHighlightWithRetry(t){if(!this.isConnected||!this.matches(":popover-open"))return;const e=this.getHighlightedElement();if(e){this.clearHighlight(),e.classList.add(c);return}t>0&&requestAnimationFrame(()=>this.applyHighlightWithRetry(t-1))}getHighlightedElement(){if(this.highlightIndex<0)return null;const t=this.virtualizerRef.value;if(!t)return null;const e=t.querySelectorAll("esp-picker-item");for(const i of e)if(this.virtualizedItemsPool.findIndex(s=>s.value===i.value&&s.text===i.text)===this.highlightIndex)return i;return null}pickItem(t){for(const l of this.pickerItems)l===t?l.selected=!l.selected:this.multiSelect||(l.selected=!1);const e=this.virtualizedItemsPool.indexOf(t);if(e!==-1){this.highlightIndex=e;const l=this.getHighlightedElement();l&&(this.clearHighlight(),l.classList.add(c))}const i=[...this.pickerItems];this.internalPoolClone=i,this.pickerItems=i,this.dispatchEvent(new CustomEvent("selection-changed",{detail:this.pickerItems.filter(l=>l.selected),bubbles:!0,composed:!0})),this.multiSelect||this.dispatchEvent(new CustomEvent("close-menu",{detail:this.pickerItems.filter(l=>l.selected),bubbles:!0,composed:!0}))}selectItemByIndex(t){const e=Number.isInteger(t)?this.virtualizedItemsPool[t]:void 0;return e?(this.pickItem(e),!0):!1}getPickerItemElementAtPoint(t,e){const i=this.shadowRoot?.querySelectorAll("esp-picker-item[data-picker-index]");if(!i)return null;for(const l of i){const s=l.getBoundingClientRect();if(t>=s.left&&t<=s.right&&e>=s.top&&e<=s.bottom)return l}return null}selectPickerItemElement(t){return t?this.selectItemByIndex(Number(t.dataset.pickerIndex)):!1}selectItemAtPoint(t,e){return this.selectPickerItemElement(this.getPickerItemElementAtPoint(t,e))}selectItemFromPointerEvent(t){const e=t.composedPath().find(l=>l instanceof HTMLElement&&l.matches("esp-picker-item[data-picker-index]"));return this.selectPickerItemElement(e??this.getPickerItemElementAtPoint(t.clientX,t.clientY))?(t.preventDefault(),t.stopPropagation(),!0):!1}positionSelf(t){const e=t.getBoundingClientRect(),{height:i}=g(),{spaceAbove:l,spaceBelow:s}=v(e,i),r=Math.max(Math.max(l,s)-75,0);this.maxAvailableHeight=r,this.lastViewportHeight=i,this.style.setProperty("height",`${r}px`),this.style.setProperty("min-width",`${e.width}px`),this.style.setProperty("left",`${e.left}px`),this.style.removeProperty("top"),this.style.removeProperty("bottom"),l>s?this.style.setProperty("bottom",`${i-e.top}px`):this.style.setProperty("top",`${e.bottom}px`),this.classList.remove("visible"),this.matches(":popover-open")||this.showPopover();const n=this.pickerItems.find(m=>m.selected);this.highlightIndex=n?this.pickerItems.indexOf(n):0,this.openSessionGeneration+=1;const h=this.openSessionGeneration;this.setHighlightAsync(0).then(()=>{requestAnimationFrame(()=>{h!==this.openSessionGeneration||!this.isConnected||(this.shrinkToFit(r),this.widenToFitContent(e),this.classList.add("visible"))})})}async stableLayout(t){for(let e=0;e<20;e+=1){const i=t.layoutComplete;if(!i)return;const l=await Promise.race([i.then(()=>"settled",()=>"superseded"),new Promise(s=>setTimeout(()=>s("deadline"),250))]);if(l==="settled"||l==="deadline"||t.layoutComplete===i)return}}async settleMenuAfterUpdate(){if(this.settlerActive)return;this.settlerActive=!0;const t=()=>!this.isConnected||!this.matches(":popover-open")?(this.menuDirty=!1,this.preRenderScrollTop=null,this.pendingItemsChanged=!1,this.retargetingSequence=!1,!0):!1;try{for(let e=0;e<10&&this.menuDirty;e+=1){this.menuDirty=!1;try{await this.updateComplete}catch{this.menuDirty=!1;return}if(t())return;const i=this.virtualizerRef.value;if(!i){requestAnimationFrame(()=>{if(!this.isConnected)return;const r=this.shadowRoot?.querySelector(".status-message");if(r){const n=Math.min(r.scrollHeight,this.maxAvailableHeight);this.style.setProperty("height",`${n}px`)}});continue}if(await this.stableLayout(i),t())return;if(this.menuDirty)continue;const l=this.preRenderScrollTop??0;if(i.scrollTop=0,this.sizeToContent(this.maxAvailableHeight),l>0&&!this.pendingItemsChanged&&!this.retargetingSequence&&i.scrollTop<l){if(i.scrollTop=l,await this.stableLayout(i),t())return;if(this.menuDirty)continue}const s=this.virtualizedItemsPool;if(s.length!==0){if(this.pendingItemsChanged){this.pendingItemsChanged=!1,this.retargetingSequence=!0,this.preRenderScrollTop=null;const r=s.findIndex(n=>n.selected);r>=0?this.highlightIndex=r:this.highlightIndex>=s.length?this.highlightIndex=s.length-1:this.highlightIndex<0&&(this.highlightIndex=0)}if(this.retargetingSequence){try{i.scrollToIndex(this.highlightIndex,"nearest")}catch{}if(await this.stableLayout(i),t())return;if(this.menuDirty)continue}this.applyHighlightWithRetry(3),this.preRenderScrollTop=null,this.retargetingSequence=!1}}}finally{this.settlerActive=!1,this.menuDirty&&this.settleMenuAfterUpdate()}}sizeToContent(t){const e=this.measureContentHeight();e>0&&this.style.setProperty("height",`${Math.min(e,t)}px`)}shrinkToFit(t){const e=this.measureContentHeight();e>2&&e<t&&this.style.setProperty("height",`${e}px`)}measureContentHeight(){const t=this.virtualizerRef.value;if(!t)return 0;const e=t.querySelectorAll("esp-picker-item");if(e.length===0)return 0;const i=getComputedStyle(this),l=(parseFloat(i.borderTopWidth)||0)+(parseFloat(i.borderBottomWidth)||0),s=this.virtualizedItemsPool.length;if(e.length<s)return t.scrollHeight+l;const r=t.scrollTop;t.scrollTop=0;const n=t.getBoundingClientRect(),h=e[e.length-1].getBoundingClientRect();return r>0&&(t.scrollTop=r),h.bottom-n.top+l}widenToFitContent(t){const e=this.virtualizerRef.value;if(!e)return;const i=e.querySelectorAll("esp-picker-item");let l=t.width;for(const s of i)l=Math.max(l,s.scrollWidth);if(l+=2,l>t.width){const{width:s}=g(),r=Math.min(l,s-t.left);this.style.setProperty("width",`${r}px`)}}updatePosition(t){const e=t.getBoundingClientRect(),{height:i}=g();if(i!==this.lastViewportHeight){const{spaceAbove:r,spaceBelow:n}=v(e,i),h=Math.max(Math.max(r,n)-75,0);this.maxAvailableHeight=h,this.lastViewportHeight=i,(parseFloat(this.style.getPropertyValue("height"))||0)>h&&this.style.setProperty("height",`${h}px`),this.sizeToContent(h)}this.style.setProperty("left",`${e.left}px`);const l=e.top,s=i-e.bottom;l>s?(this.style.removeProperty("top"),this.style.setProperty("bottom",`${i-e.top}px`)):(this.style.removeProperty("bottom"),this.style.setProperty("top",`${e.bottom}px`))}hideMenu(){this.openSessionGeneration+=1,this.classList.remove("visible"),this.preRenderScrollTop=null,this.pendingItemsChanged=!1,this.retargetingSequence=!1,this.menuDirty=!1;try{this.hidePopover()}catch{}}doKeyboardNav(t){const e=this.virtualizedItemsPool;if(e.length!==0)switch(t){case"ArrowDown":this.highlightIndex+=1,this.setHighlight(0);break;case"ArrowUp":this.highlightIndex-=1,this.setHighlight(e.length-1);break;case"Home":this.highlightIndex=0,this.setHighlight(0);break;case"End":this.highlightIndex=e.length-1,this.setHighlight(e.length-1);break;case"Enter":if(this.highlightIndex===-1)return;this.pickItem(e[this.highlightIndex]);break}}render(){return this.loading?d`<div class="status-message">Searching…</div>`:this.virtualizedItemsPool.length===0&&this.emptyMessage?d`<div class="status-message">${this.emptyMessage}</div>`:d`<lit-virtualizer
|
|
13
|
+
${P(this.virtualizerRef)}
|
|
14
14
|
scroller
|
|
15
15
|
.items=${this.virtualizedItemsPool}
|
|
16
16
|
.renderItem=${this.renderPickerItem}
|
|
17
17
|
@pointerdown=${this.handleItemPointerDown}
|
|
18
18
|
@rangeChanged=${t=>{this.dispatchEvent(new CustomEvent("range-changed",{detail:{first:t.first,last:t.last,items:this.virtualizedItemsPool},bubbles:!0,composed:!0}))}}
|
|
19
|
-
></lit-virtualizer>`}};
|
|
19
|
+
></lit-virtualizer>`}};o.styles=I`
|
|
20
20
|
:host {
|
|
21
21
|
position: fixed;
|
|
22
22
|
inset: unset;
|
|
@@ -54,4 +54,4 @@ var n=function(d,t,e,i){var l=arguments.length,s=l<3?t:i===null?i=Object.getOwnP
|
|
|
54
54
|
font-style: italic;
|
|
55
55
|
background: var(--esp-color-layer-2);
|
|
56
56
|
}
|
|
57
|
-
`,
|
|
57
|
+
`,a([u({type:String})],o.prototype,"label",void 0),a([f()],o.prototype,"virtualizedItemsPool",void 0),a([f()],o.prototype,"highlightIndex",void 0),a([u({attribute:"multi-select",type:Boolean})],o.prototype,"multiSelect",void 0),a([u({type:Boolean})],o.prototype,"loading",void 0),a([u({type:String,attribute:"empty-message"})],o.prototype,"emptyMessage",void 0),o=a([b("esp-picker-menu")],o);export{o as EspalierPickerMenu};
|
|
@@ -28,14 +28,14 @@ import { EspalierElementBase } from "../shared/esp-element-base.js";
|
|
|
28
28
|
* </div>
|
|
29
29
|
* ```
|
|
30
30
|
*
|
|
31
|
-
*
|
|
31
|
+
* Intent colors match the design system:
|
|
32
32
|
*
|
|
33
33
|
* ```html
|
|
34
34
|
* <div style="display: grid; gap: var(--esp-size-padding);">
|
|
35
|
-
* <esp-progress value="80" label="Primary"
|
|
36
|
-
* <esp-progress value="60" label="Success"
|
|
37
|
-
* <esp-progress value="40" label="Warning"
|
|
38
|
-
* <esp-progress value="20" label="Danger"
|
|
35
|
+
* <esp-progress value="80" label="Primary" show-value></esp-progress>
|
|
36
|
+
* <esp-progress value="60" label="Success" intent="success" show-value></esp-progress>
|
|
37
|
+
* <esp-progress value="40" label="Warning" intent="warning" show-value></esp-progress>
|
|
38
|
+
* <esp-progress value="20" label="Danger" intent="danger" show-value></esp-progress>
|
|
39
39
|
* </div>
|
|
40
40
|
* ```
|
|
41
41
|
*
|
|
@@ -43,10 +43,10 @@ import { EspalierElementBase } from "../shared/esp-element-base.js";
|
|
|
43
43
|
*
|
|
44
44
|
* ```html
|
|
45
45
|
* <esp-box>
|
|
46
|
-
* <esp-progress id="demo-progress" value="0" label="Demo progress"
|
|
46
|
+
* <esp-progress id="demo-progress" value="0" label="Demo progress" intent="success" size="large" show-value></esp-progress>
|
|
47
47
|
* <div style="display: flex; gap: var(--esp-size-small); margin-top: var(--esp-size-small);">
|
|
48
|
-
* <esp-button id="start-btn" label="Start"
|
|
49
|
-
* <esp-button id="reset-btn" label="Reset"
|
|
48
|
+
* <esp-button id="start-btn" label="Start" collapsed></esp-button>
|
|
49
|
+
* <esp-button id="reset-btn" label="Reset" collapsed></esp-button>
|
|
50
50
|
* </div>
|
|
51
51
|
* </esp-box>
|
|
52
52
|
* <script>
|
|
@@ -67,7 +67,7 @@ import { EspalierElementBase } from "../shared/esp-element-base.js";
|
|
|
67
67
|
* requestAnimationFrame(step);
|
|
68
68
|
* } else {
|
|
69
69
|
* running = false;
|
|
70
|
-
* showToast({ message: "Complete!",
|
|
70
|
+
* showToast({ message: "Complete!", intent: "success", icon: "bread" });
|
|
71
71
|
* }
|
|
72
72
|
* }
|
|
73
73
|
* requestAnimationFrame(step);
|
|
@@ -79,14 +79,14 @@ import { EspalierElementBase } from "../shared/esp-element-base.js";
|
|
|
79
79
|
* </script>
|
|
80
80
|
* ```
|
|
81
81
|
*
|
|
82
|
-
* Indeterminate mode with different
|
|
82
|
+
* Indeterminate mode with different intents:
|
|
83
83
|
*
|
|
84
84
|
* ```html
|
|
85
85
|
* <div style="display: grid; gap: var(--esp-size-small);">
|
|
86
|
-
* <esp-progress label="Primary loading"
|
|
87
|
-
* <esp-progress label="Success loading"
|
|
88
|
-
* <esp-progress label="Warning loading"
|
|
89
|
-
* <esp-progress label="Danger loading"
|
|
86
|
+
* <esp-progress label="Primary loading"></esp-progress>
|
|
87
|
+
* <esp-progress label="Success loading" intent="success"></esp-progress>
|
|
88
|
+
* <esp-progress label="Warning loading" intent="warning"></esp-progress>
|
|
89
|
+
* <esp-progress label="Danger loading" intent="danger"></esp-progress>
|
|
90
90
|
* </div>
|
|
91
91
|
* ```
|
|
92
92
|
*
|
|
@@ -96,10 +96,10 @@ import { EspalierElementBase } from "../shared/esp-element-base.js";
|
|
|
96
96
|
*
|
|
97
97
|
* ```html
|
|
98
98
|
* <div style="display: flex; gap: var(--esp-size-padding); align-items: center; flex-wrap: wrap;">
|
|
99
|
-
* <esp-progress mode="circle" value="80" label="Primary"
|
|
100
|
-
* <esp-progress mode="circle" value="60" label="Success"
|
|
101
|
-
* <esp-progress mode="circle" value="40" label="Warning"
|
|
102
|
-
* <esp-progress mode="circle" value="20" label="Danger"
|
|
99
|
+
* <esp-progress mode="circle" value="80" label="Primary" show-value></esp-progress>
|
|
100
|
+
* <esp-progress mode="circle" value="60" label="Success" intent="success" show-value></esp-progress>
|
|
101
|
+
* <esp-progress mode="circle" value="40" label="Warning" intent="warning" show-value></esp-progress>
|
|
102
|
+
* <esp-progress mode="circle" value="20" label="Danger" intent="danger" show-value></esp-progress>
|
|
103
103
|
* </div>
|
|
104
104
|
* ```
|
|
105
105
|
*
|
|
@@ -117,8 +117,8 @@ import { EspalierElementBase } from "../shared/esp-element-base.js";
|
|
|
117
117
|
*
|
|
118
118
|
* ```html
|
|
119
119
|
* <div style="display: flex; gap: var(--esp-size-padding); align-items: center;">
|
|
120
|
-
* <esp-progress mode="circle" label="Primary loading"
|
|
121
|
-
* <esp-progress mode="circle" label="Success loading"
|
|
120
|
+
* <esp-progress mode="circle" label="Primary loading"></esp-progress>
|
|
121
|
+
* <esp-progress mode="circle" label="Success loading" intent="success"></esp-progress>
|
|
122
122
|
* </div>
|
|
123
123
|
* ```
|
|
124
124
|
*
|
|
@@ -127,10 +127,10 @@ import { EspalierElementBase } from "../shared/esp-element-base.js";
|
|
|
127
127
|
* ```html
|
|
128
128
|
* <esp-box>
|
|
129
129
|
* <div style="display: flex; align-items: center; gap: var(--esp-size-padding);">
|
|
130
|
-
* <esp-progress id="demo-circle" mode="circle" value="0" label="Circle demo"
|
|
130
|
+
* <esp-progress id="demo-circle" mode="circle" value="0" label="Circle demo" intent="success" size="large" show-value></esp-progress>
|
|
131
131
|
* <div style="display: flex; gap: var(--esp-size-small);">
|
|
132
|
-
* <esp-button id="start-circle-btn" label="Start"
|
|
133
|
-
* <esp-button id="reset-circle-btn" label="Reset"
|
|
132
|
+
* <esp-button id="start-circle-btn" label="Start" collapsed></esp-button>
|
|
133
|
+
* <esp-button id="reset-circle-btn" label="Reset" collapsed></esp-button>
|
|
134
134
|
* </div>
|
|
135
135
|
* </div>
|
|
136
136
|
* </esp-box>
|
|
@@ -152,7 +152,7 @@ import { EspalierElementBase } from "../shared/esp-element-base.js";
|
|
|
152
152
|
* requestAnimationFrame(step);
|
|
153
153
|
* } else {
|
|
154
154
|
* circleRunning = false;
|
|
155
|
-
* showToast({ message: "Complete!",
|
|
155
|
+
* showToast({ message: "Complete!", intent: "success", icon: "bread" });
|
|
156
156
|
* }
|
|
157
157
|
* }
|
|
158
158
|
* requestAnimationFrame(step);
|
|
@@ -88,7 +88,6 @@ export type RepeaterRenderItem<T = unknown> = (item: T, index: number) => Repeat
|
|
|
88
88
|
*
|
|
89
89
|
* repeater.renderItem = (image) => {
|
|
90
90
|
* const card = document.createElement("esp-box");
|
|
91
|
-
* card.variant = "analogous-right";
|
|
92
91
|
* card.innerHTML = `
|
|
93
92
|
* <div style="display:grid; gap:var(--esp-size-small); grid-template-columns:7rem 1fr; align-items:start;">
|
|
94
93
|
* <img src="${image.thumbnail}" alt="" style="width:7rem; aspect-ratio:4 / 3; object-fit:cover; border-radius:var(--esp-size-border-radius);" />
|
|
@@ -185,7 +184,6 @@ export type RepeaterRenderItem<T = unknown> = (item: T, index: number) => Repeat
|
|
|
185
184
|
*
|
|
186
185
|
* repeater.renderItem = (image) => {
|
|
187
186
|
* const card = document.createElement("esp-box");
|
|
188
|
-
* card.variant = "analogous-right";
|
|
189
187
|
* card.innerHTML = `
|
|
190
188
|
* <article style="display:grid; gap:var(--esp-size-small);">
|
|
191
189
|
* <img src="${image.thumbnail}" alt="" style="width:100%; aspect-ratio:16 / 10; object-fit:cover; border-radius:var(--esp-size-border-radius);" />
|
|
@@ -256,7 +254,6 @@ export type RepeaterRenderItem<T = unknown> = (item: T, index: number) => Repeat
|
|
|
256
254
|
*
|
|
257
255
|
* repeater.renderItem = (image) => {
|
|
258
256
|
* const card = document.createElement("esp-box");
|
|
259
|
-
* card.variant = "analogous-right";
|
|
260
257
|
* card.innerHTML = `
|
|
261
258
|
* <article style="display:grid; gap:var(--esp-size-small);">
|
|
262
259
|
* <img src="${image.thumbnail}" alt="" style="width:100%; aspect-ratio:3 / 2; object-fit:cover; border-radius:var(--esp-size-border-radius);" />
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{deriveSemantic as C,deriveSemanticWithContrast as M,serializeOklch as d}from"../../shared/color-engine.js";import{SEMANTIC_COLOR_NAMES as v,TOKEN_PAIRINGS as S,semanticToCSS as R}from"../../shared/theme.js";import{resolveMappingSource as k}from"./compute-variants.js";function x(r,m,t={}){const i={},u={},p=(o,e)=>{const c=t.effectiveSource?.(o,e)??e,s=k(c,m,r.anchors);return s||t.onUnresolvedSource?.(c),{color:s??m.primary,resolved:s!==null,source:c}};for(const o of v){if(S[o])continue;const e=r.semanticMappings[o],c=r.chroma[o],s=p(o,e.source),n=r.lightness[e.lightness],l=C(s.color,n,c.min,c.max),a=R(o);u[o]=l,i[a]=d(l),t.trace&&t.trace.push({token:o,property:a,resolved:i[a],source:s.source,lightness:e.lightness,sourceResolved:s.resolved,base:s.color})}for(const o of v){const e=S[o];if(!e)continue;const c=r.semanticMappings[o],s=r.chroma[o],n=p(o,c.source),l=r.lightness[c.lightness],a=u[e.bg];let f;const h=M(n.color,l,s.min,s.max,a,e.targetLc,t.trace&&(b=>{f=b})),g=R(o);u[o]=h,i[g]=d(h),t.trace&&t.trace.push({token:o,property:g,resolved:i[g],source:n.source,lightness:c.lightness,sourceResolved:n.resolved,base:n.color,requested:f,contrast:{against:e.bg,background:a,targetLc:e.targetLc}})}return i}export{x as computeSemanticProperties};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{parseCssColor as
|
|
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};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LIGHTNESS_KEYS as s}from"../../shared/theme.js";import{lightnessKeyToCSS as e}from"./lightness-key-to-css.js";function p(t){const o={};for(const r of s)o[e(r)]=`${Math.round(t.lightness[r]*100)}%`;return o}export{p as lightnessRampProperties};
|
|
@@ -33,7 +33,7 @@ import type { HelpRequest, HelpState } from "./help-events.js";
|
|
|
33
33
|
/**
|
|
34
34
|
* Contract for elements that provide a seed color to their subtree.
|
|
35
35
|
* Implemented by `EspalierRoot` (the global provider) and
|
|
36
|
-
* `EspalierElementBase` (
|
|
36
|
+
* `EspalierElementBase` (scoped context and intent derivation).
|
|
37
37
|
*
|
|
38
38
|
* @docUrl /api/seed-color-root
|
|
39
39
|
* @menuGroup Bus Events
|
|
@@ -48,7 +48,7 @@ export interface SeedColorRoot {
|
|
|
48
48
|
*
|
|
49
49
|
* Published by `<esp-root>` after initial mount and subscribed to by every
|
|
50
50
|
* `EspalierElementBase` descendant so that scheme, seed, and full-theme changes
|
|
51
|
-
* propagate to
|
|
51
|
+
* propagate to scoped-token-aware descendants. All roots share one global bus, so
|
|
52
52
|
* consumers should use `EspalierRoot.subscribeScoped()` instead of subscribing
|
|
53
53
|
* to these events directly. Read initial values from the root; these events are
|
|
54
54
|
* change-only and are not replayed for late subscribers.
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { LitElement, type PropertyValues } from "lit";
|
|
2
2
|
import { type SeedColorRoot } from "./bus-events.js";
|
|
3
|
-
import { type
|
|
4
|
-
export type EspalierVariant = "analogous-left" | "analogous-right" | "complementary" | "danger" | "info" | "neutral" | "primary" | "split-complementary-left" | "split-complementary-right" | "success" | "triadic-left" | "triadic-right" | "warning" | "";
|
|
3
|
+
import { type EspalierIntentVariant } from "./intent-values.js";
|
|
5
4
|
/**
|
|
6
5
|
* Shared base class for Espalier elements.
|
|
7
6
|
*
|
|
@@ -18,7 +17,16 @@ export type EspalierVariant = "analogous-left" | "analogous-right" | "complement
|
|
|
18
17
|
* @cssprop --esp-field-focus-shadow - Shadow color used for shared field focus treatment. Defaults to `var(--esp-color-shadow)`.
|
|
19
18
|
*/
|
|
20
19
|
export declare class EspalierElementBase extends LitElement implements SeedColorRoot {
|
|
21
|
-
protected
|
|
20
|
+
protected intentBacker: EspalierIntentVariant;
|
|
21
|
+
/**
|
|
22
|
+
* Whether a non-neutral intent emits its inline tokens
|
|
23
|
+
* (`--esp-color-primary` and the filled-action pair). Interactive
|
|
24
|
+
* controls need them; chrome whose intent treatment is class-based
|
|
25
|
+
* (badges, callouts, status pills — see `intentSurfaceTokens`) opts
|
|
26
|
+
* out so a decorative intent never rewrites inherited tokens for
|
|
27
|
+
* slotted content.
|
|
28
|
+
*/
|
|
29
|
+
protected intentEmitsTokens: boolean;
|
|
22
30
|
get seedColor(): string;
|
|
23
31
|
set seedColor(val: string);
|
|
24
32
|
correlationId: `${string}-${string}-${string}-${string}-${string}`;
|
|
@@ -34,11 +42,27 @@ export declare class EspalierElementBase extends LitElement implements SeedColor
|
|
|
34
42
|
*/
|
|
35
43
|
scheme: "dark" | "light" | "";
|
|
36
44
|
/**
|
|
37
|
-
* The [
|
|
38
|
-
*
|
|
45
|
+
* The element's [intent](/espalier-guides/) — its meaning: `neutral`
|
|
46
|
+
* (no pin), `success`, `warning`, or `danger` (each pinned to its
|
|
47
|
+
* fixed status family), or `info` (pinned to the complementary
|
|
48
|
+
* family). On token-emitting controls a non-neutral intent pins the
|
|
49
|
+
* filled-action pair to that family, derived over the governing
|
|
50
|
+
* zone's theme; class-styled chrome (badges, callouts, status pills)
|
|
51
|
+
* opts out of inline emission and renders its treatment from CSS
|
|
52
|
+
* classes instead. An intent never repaints the surrounding zone,
|
|
53
|
+
* which is what contexts are for. Removing the attribute restores
|
|
54
|
+
* the element's own default intent.
|
|
55
|
+
* @type {EspalierIntentVariant}
|
|
39
56
|
*/
|
|
40
|
-
get
|
|
41
|
-
set
|
|
57
|
+
get intent(): EspalierIntentVariant;
|
|
58
|
+
set intent(value: EspalierIntentVariant | string | null);
|
|
59
|
+
/**
|
|
60
|
+
* A theme-defined color zone. The selected context rebinds designer-facing
|
|
61
|
+
* roles and emits a complete, contrast-enforced semantic token table on this
|
|
62
|
+
* host for descendants to inherit.
|
|
63
|
+
*/
|
|
64
|
+
get context(): string;
|
|
65
|
+
set context(value: string);
|
|
42
66
|
connectedCallback(): void;
|
|
43
67
|
disconnectedCallback(): void;
|
|
44
68
|
protected firstUpdated(_changedProperties: PropertyValues): void;
|
|
@@ -51,16 +75,16 @@ export declare class EspalierElementBase extends LitElement implements SeedColor
|
|
|
51
75
|
*/
|
|
52
76
|
traverseToClosest(selector: string): Element | null;
|
|
53
77
|
/**
|
|
54
|
-
* Compute and apply
|
|
55
|
-
*
|
|
56
|
-
* For the **primary** variant (or none), all semantic tokens
|
|
57
|
-
* cascade from `<esp-root>` — any previous overrides are cleared.
|
|
78
|
+
* Compute and apply context- and intent-specific semantic color tokens.
|
|
58
79
|
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
80
|
+
* With no context and a `neutral` intent, all semantic tokens cascade
|
|
81
|
+
* from `<esp-root>` and previous overrides are cleared. A context
|
|
82
|
+
* emits the zone's complete nineteen-token table; a non-neutral intent
|
|
83
|
+
* then overlays the filled-action pair, derived over the governing
|
|
84
|
+
* zone's theme — this host's own context, or the nearest ancestor
|
|
85
|
+
* zone's — so its APCA enforcement runs against the zone's actual
|
|
86
|
+
* action surface.
|
|
62
87
|
*/
|
|
63
|
-
protected
|
|
64
|
-
protected getVariantColorSource(): ColorSource | "";
|
|
88
|
+
protected applyScopedColorTokens(): void;
|
|
65
89
|
static styles: import("lit").CSSResult[];
|
|
66
90
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var
|
|
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{ROLE_NAMES as V,mergeTheme as U,semanticToCSS as A}from"./theme.js";import{alignAttributeTextInheritance as I,focusRing as O}from"./style-fragments.js";import{syncNormalizedAttribute as D}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);D(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))),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 V){const l=r[c];l!==void 0&&(a[c]=l)}const i=U(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:"complementary",neutral:"",success:"success",warning:"warning"},n.semanticActionTokens=new Set(["actionBackground","actionText"]),n.styles=[O(".esp-field:focus-within","--esp-field-focus-shadow"),I,R`
|
|
2
2
|
:host {
|
|
3
3
|
|
|
4
4
|
--_esp-field-resolved-hover-bg: var(
|
|
@@ -122,4 +122,4 @@ var p=function(v,e,t,o){var r=arguments.length,s=r<3?e:o===null?o=Object.getOwnP
|
|
|
122
122
|
.esp-field:has(textarea:disabled):hover {
|
|
123
123
|
background-color: var(--esp-field-background, var(--esp-color-layer-2));
|
|
124
124
|
}
|
|
125
|
-
`],
|
|
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};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{css as
|
|
1
|
+
import{css as o,unsafeCSS as e}from"lit";const l=o`
|
|
2
2
|
:host([align]) {
|
|
3
3
|
text-align: inherit;
|
|
4
4
|
}
|
|
5
|
-
`,
|
|
5
|
+
`,a=o`
|
|
6
6
|
.sr-only {
|
|
7
7
|
position: absolute;
|
|
8
8
|
width: 1px;
|
|
@@ -14,14 +14,44 @@ import{css as n,unsafeCSS as t}from"lit";const a=n`
|
|
|
14
14
|
white-space: nowrap;
|
|
15
15
|
border: 0;
|
|
16
16
|
}
|
|
17
|
-
`;function
|
|
18
|
-
${
|
|
17
|
+
`;function i(r){const n=r.includes(":host")||r.includes("[disabled]")?r:`:host([disabled]) ${r}`;return o`
|
|
18
|
+
${e(n)} {
|
|
19
19
|
opacity: 0.5;
|
|
20
20
|
cursor: not-allowed;
|
|
21
21
|
}
|
|
22
|
-
`}function p(
|
|
23
|
-
${
|
|
24
|
-
box-shadow: ${
|
|
25
|
-
var(${
|
|
22
|
+
`}function p(r,n,t="0 0 3px",s=""){return o`
|
|
23
|
+
${e(r)} {
|
|
24
|
+
box-shadow: ${e(s)} ${e(t)}
|
|
25
|
+
var(${e(n)}, var(--esp-color-shadow));
|
|
26
26
|
}
|
|
27
|
-
`}
|
|
27
|
+
`}const d=o`
|
|
28
|
+
.intent-neutral {
|
|
29
|
+
--_esp-intent-background: var(--esp-color-layer-2);
|
|
30
|
+
--_esp-intent-border-color: var(--esp-color-border);
|
|
31
|
+
--_esp-intent-color: var(--esp-color-text);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.intent-success {
|
|
35
|
+
--_esp-intent-background: oklch(from var(--esp-color-success) var(--esp-l-raised-2) c h);
|
|
36
|
+
--_esp-intent-border-color: oklch(from var(--esp-color-success) var(--esp-l-border) c h);
|
|
37
|
+
--_esp-intent-color: oklch(from var(--esp-color-success) var(--esp-l-text) c h);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.intent-warning {
|
|
41
|
+
--_esp-intent-background: oklch(from var(--esp-color-warning) var(--esp-l-raised-2) c h);
|
|
42
|
+
--_esp-intent-border-color: oklch(from var(--esp-color-warning) var(--esp-l-border) c h);
|
|
43
|
+
--_esp-intent-color: oklch(from var(--esp-color-warning) var(--esp-l-text) c h);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.intent-danger {
|
|
47
|
+
--_esp-intent-background: oklch(from var(--esp-color-danger) var(--esp-l-raised-2) c h);
|
|
48
|
+
--_esp-intent-border-color: oklch(from var(--esp-color-danger) var(--esp-l-border) c h);
|
|
49
|
+
--_esp-intent-color: var(--esp-color-danger-text);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.intent-info {
|
|
53
|
+
--_esp-intent-background: var(--esp-color-link-hover-bg);
|
|
54
|
+
--_esp-intent-border-color: oklch(from var(--esp-color-link) var(--esp-l-border) c h);
|
|
55
|
+
--_esp-intent-color: var(--esp-color-link);
|
|
56
|
+
}
|
|
57
|
+
`;export{l as alignAttributeTextInheritance,i as disabledControl,p as focusRing,d as intentSurfaceTokens,a as srOnly};
|
package/dist/shared/theme.d.ts
CHANGED
|
@@ -97,9 +97,10 @@ export type ThemeAnchors = Record<string, ThemeAnchor>;
|
|
|
97
97
|
*
|
|
98
98
|
* An anchor source contributes its own hue **and chroma**; lightness
|
|
99
99
|
* always comes from the mapping's ramp stop, and APCA enforcement
|
|
100
|
-
* applies unchanged.
|
|
101
|
-
*
|
|
102
|
-
* so
|
|
100
|
+
* applies unchanged. Anchors are absolute sources rather than seed
|
|
101
|
+
* rotations — a brand color is a color, not a relationship to the
|
|
102
|
+
* seed — so they hold steady while contexts rebind roles around them
|
|
103
|
+
* and intents replace the filled-action source.
|
|
103
104
|
*/
|
|
104
105
|
export type MappingSource = ColorSource | `anchor:${string}`;
|
|
105
106
|
/** Anchor names and slot names share one slug grammar. */
|
|
@@ -205,6 +206,20 @@ export type RoleBinding<R extends RoleName = RoleName> = MappingSource | ({
|
|
|
205
206
|
export type ThemeRoles = {
|
|
206
207
|
[R in RoleName]?: RoleBinding<R>;
|
|
207
208
|
};
|
|
209
|
+
/**
|
|
210
|
+
* One named zone-level rebinding of the designer-facing color roles.
|
|
211
|
+
*
|
|
212
|
+
* A context may also carry a partial lightness ramp. Color sources alone
|
|
213
|
+
* cannot make a dark zone inside a light scheme because semantic derivation
|
|
214
|
+
* deliberately takes lightness from the ramp rather than from an anchor.
|
|
215
|
+
*/
|
|
216
|
+
export type ThemeContext = ThemeRoles & {
|
|
217
|
+
lightness?: Partial<LightnessMap>;
|
|
218
|
+
};
|
|
219
|
+
/** Named role-rebinding zones available to `context` attributes. */
|
|
220
|
+
export type ThemeContexts = Record<string, ThemeContext>;
|
|
221
|
+
/** Context declarations while partial themes are being layered. */
|
|
222
|
+
export type PartialThemeContexts = Record<string, ThemeContext | undefined>;
|
|
208
223
|
/** Ordered role names, for validation and iteration. */
|
|
209
224
|
export declare const ROLE_NAMES: readonly RoleName[];
|
|
210
225
|
/**
|
|
@@ -394,6 +409,12 @@ export interface EspalierTheme {
|
|
|
394
409
|
* See {@link ThemeRoles} and ADR-016.
|
|
395
410
|
*/
|
|
396
411
|
roles: ThemeRoles;
|
|
412
|
+
/**
|
|
413
|
+
* Named zone-level role rebindings. A base-derived element selects one with
|
|
414
|
+
* its `context` attribute; the selected context is resolved against this
|
|
415
|
+
* scheme's complete theme and re-enforces every semantic ink pairing.
|
|
416
|
+
*/
|
|
417
|
+
contexts: ThemeContexts;
|
|
397
418
|
/**
|
|
398
419
|
* Eight stable categorical data-series colors. Each value is a CSS color or
|
|
399
420
|
* an `anchor:<name>[.<slot>]` reference. Emitted as
|
|
@@ -427,8 +448,9 @@ export interface EspalierTheme {
|
|
|
427
448
|
* carry slot-only anchor overrides, which the resolved
|
|
428
449
|
* {@link ThemeAnchor} deliberately does not permit.
|
|
429
450
|
*/
|
|
430
|
-
export type PartialTheme = Omit<DeepPartial<EspalierTheme>, "anchors" | "dataRamps"> & {
|
|
451
|
+
export type PartialTheme = Omit<DeepPartial<EspalierTheme>, "anchors" | "contexts" | "dataRamps"> & {
|
|
431
452
|
anchors?: PartialThemeAnchors;
|
|
453
|
+
contexts?: PartialThemeContexts;
|
|
432
454
|
dataRamps?: PartialDataRamps;
|
|
433
455
|
};
|
|
434
456
|
/** Validation result returned by {@link validateTheme}. */
|
|
@@ -556,7 +578,7 @@ export declare function encodeTheme(partial: PartialTheme): string;
|
|
|
556
578
|
* Deep-merge a {@link PartialTheme} over a set of defaults.
|
|
557
579
|
*
|
|
558
580
|
* Primitive fields are replaced; nested objects (`angles`,
|
|
559
|
-
* `semanticHues`, `lightness`, `chroma`, `semanticMappings`)
|
|
581
|
+
* `semanticHues`, `lightness`, `chroma`, `semanticMappings`, `contexts`)
|
|
560
582
|
* are merged key-by-key. Arrays (`stylesheets`) are replaced
|
|
561
583
|
* wholesale.
|
|
562
584
|
*
|
|
@@ -565,25 +587,21 @@ export declare function encodeTheme(partial: PartialTheme): string;
|
|
|
565
587
|
* @returns A new fully-resolved {@link EspalierTheme}.
|
|
566
588
|
*/
|
|
567
589
|
export declare function mergeTheme(defaults: EspalierTheme, overrides: PartialTheme): EspalierTheme;
|
|
590
|
+
export declare function validateTheme(base64: string): ThemeValidationResult;
|
|
568
591
|
/**
|
|
569
|
-
* Validate
|
|
592
|
+
* Validate the light and dark partials that form one scheme-paired theme.
|
|
570
593
|
*
|
|
571
|
-
*
|
|
572
|
-
*
|
|
573
|
-
*
|
|
574
|
-
*
|
|
575
|
-
* @param base64 A Base64-encoded JSON string representing a
|
|
576
|
-
* partial or full theme.
|
|
577
|
-
* @returns A {@link ThemeValidationResult} with `valid`, `errors`,
|
|
578
|
-
* and `warnings`.
|
|
594
|
+
* Each partial first passes through {@link validateTheme}. Once both are
|
|
595
|
+
* structurally valid, their context-name sets must match exactly so a stable
|
|
596
|
+
* `context` attribute cannot silently change meaning when the scheme changes.
|
|
579
597
|
*/
|
|
580
|
-
export declare function
|
|
598
|
+
export declare function validateThemePair(lightBase64: string, darkBase64: string): ThemeValidationResult;
|
|
581
599
|
/**
|
|
582
600
|
* Keys of {@link EspalierTheme} whose values are nested objects
|
|
583
601
|
* and therefore need key-by-key merging instead of wholesale
|
|
584
602
|
* replacement when combining two {@link PartialTheme} objects.
|
|
585
603
|
*/
|
|
586
|
-
export declare const NESTED_THEME_KEYS: readonly ["anchors", "angles", "dataPalette", "dataRamps", "roles", "chroma", "lightness", "semanticHues", "semanticMappings", "variantChroma"];
|
|
604
|
+
export declare const NESTED_THEME_KEYS: readonly ["anchors", "angles", "contexts", "dataPalette", "dataRamps", "roles", "chroma", "lightness", "semanticHues", "semanticMappings", "variantChroma"];
|
|
587
605
|
/**
|
|
588
606
|
* Deep-merge two {@link PartialTheme} objects.
|
|
589
607
|
*
|