@ds-mo/ui 14.26.0 → 14.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.package-ready.json +1 -1
- package/dist/agent-patterns.json +1 -1
- package/dist/agent.json +5 -5
- package/dist/components/ds-card-overview.js +1 -1
- package/dist/components/ds-field.js +1 -1
- package/dist/components/ds-score.js +1 -1
- package/dist/components/ds-table-group.js +1 -1
- package/dist/components/ds-table-group.js.map +1 -1
- package/dist/components/ds-table-saved-views.js +1 -1
- package/dist/components/ds-table.js +1 -1
- package/dist/components/p-Ctnm9NJP.js +2 -0
- package/dist/components/p-Ctnm9NJP.js.map +1 -0
- package/dist/components/{p-DRyrcR2k.js → p-VT-5XDkB.js} +2 -2
- package/dist/components/p-VT-5XDkB.js.map +1 -0
- package/dist/docs/components.json +3 -3
- package/dist/mcp-data/registry/field.json +1 -1
- package/dist/mcp-data/registry/registry.json +4 -4
- package/dist/mcp-data/registry/score.json +1 -1
- package/dist/mcp-data/registry/table-group.json +5 -5
- package/dist/mcp-data/registry/table.json +1 -1
- package/dist/types/components/Field/Field.d.ts +7 -0
- package/dist/types/components/Table/table-types.d.ts +2 -0
- package/dist/types/components/TableGroup/TableGroup.d.ts +13 -3
- package/package.json +1 -1
- package/dist/components/p-DRyrcR2k.js.map +0 -1
- package/dist/components/p-DVLghmNY.js +0 -2
- package/dist/components/p-DVLghmNY.js.map +0 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{p as e,H as t,h as i,a as s,t as d}from"./index.js";import{d as n}from"./p-DQQsS9Rx.js";const r=()=>`.ds-field-stack.sc-ds-field-h,.ds-field-stack.sc-ds-field{display:flex;flex-direction:column;gap:var(--dimension-space-050)}.sc-ds-field-h{display:block}.field__control.sc-ds-field{display:flex;min-width:0}.field__control.sc-ds-field>*.sc-ds-field{width:100%}`;let a=0;const o=e=>e?.split(/\s+/).filter(Boolean)??[];const l=(...e)=>[...new Set(e.flat())];const h=e(class e extends t{constructor(e){super();if(e!==false){this.__registerHost()}this.error=false;this.focused=false;this.filled=false;this.dirty=false;this.touched=false;this.controlDisabled=false;this.controlRequired=false;this.slotRevision=0;this.generatedId=`ds-field-${++a}`;this.initialValue="";this.authoredAria=new WeakMap;this.didLoad=false;this.syncControl=()=>{const e=this.findControl();if(!e)return;if(e!==this.control){this.control=e;this.initialValue=this.readValue(e);this.authoredAria.set(e,{labelledby:o(e.getAttribute("aria-labelledby")),describedby:o(e.getAttribute("aria-describedby"))})}const t=e.tagName.startsWith("DS-");if(t&&"inputId"in e)e.inputId=this.controlId;else this.updateControlAttribute(e,"id",this.controlId);const i=this.authoredAria.get(e)??{labelledby:[],describedby:[]};const s=l(i.labelledby,[this.labelId]).join(" ");const d=l(i.describedby,this.renderedDescription?[this.descriptionId]:[],this.renderedError?[this.errorId]:[]).join(" ");this.updateControlAttribute(e,"aria-labelledby",s);this.updateControlAttribute(e,"aria-describedby",d||undefined);this.updateControlAttribute(e,"aria-invalid",this.error?"true":undefined);if(t&&"error"in e&&e.error!==this.error)e.error=this.error;const n=this.readValue(e);this.filled=n.length>0;this.dirty=n!==this.initialValue;this.controlDisabled=Boolean(e.disabled||e.isInactive||e.hasAttribute("disabled"));this.controlRequired=Boolean(e.required||e.hasAttribute("required"))};this.handleLabelClick=e=>{if(!this.control?.tagName.startsWith("DS-"))return;e.preventDefault();this.control.setFocus?.()};this.handleFocusIn=()=>{this.focused=true};this.handleFocusOut=e=>{if(e.relatedTarget instanceof Node&&this.el.contains(e.relatedTarget))return;this.focused=false;this.touched=true};this.handleValueChange=()=>{this.syncControl()}}connectedCallback(){if(this.didLoad)this.observeLateControls()}disconnectedCallback(){this.childObserver?.disconnect();this.childObserver=undefined}componentDidLoad(){this.syncControl();this.didLoad=true;this.observeLateControls();requestAnimationFrame((()=>this.syncControl()))}componentDidRender(){this.syncControl()}onFieldContractChange(){this.syncControl()}get controlId(){return this.fieldId||this.generatedId}get labelId(){return`${this.controlId}-label`}get descriptionId(){return`${this.controlId}-description`}get errorId(){return`${this.controlId}-error`}get renderedDescription(){return Boolean(this.description)&&!this.renderedError}get renderedError(){return this.error&&Boolean(this.errorMessage)}readValue(e){const t=e.value;return Array.isArray(t)?t.join(""):String(t??"")}updateControlAttribute(e,t,i){if(i===undefined){if(e.hasAttribute(t))e.removeAttribute(t);return}if(e.getAttribute(t)!==i)e.setAttribute(t,i)}findControl(){return this.controlContainer?.querySelector(":scope > :not(slot)")??undefined}observeLateControls(){if(this.childObserver||typeof MutationObserver==="undefined")return;this.childObserver=new MutationObserver((e=>{const t=e.some((e=>Array.from(e.addedNodes).some((e=>e.nodeType===1))));if(t)this.slotRevision++}));this.childObserver.observe(this.el,{childList:true})}render(){return i(s,{key:"9bbb2fddf6c4417143a28d9123181aa0515f4bb4","data-focused":this.focused?"":undefined,"data-filled":this.filled?"":undefined,"data-dirty":this.dirty?"":undefined,"data-touched":this.touched?"":undefined,"data-invalid":this.error?"":undefined,"data-disabled":this.controlDisabled?"":undefined,"data-required":this.controlRequired?"":undefined,onFocusin:this.handleFocusIn,onFocusout:this.handleFocusOut,onInput:this.handleValueChange,onChange:this.handleValueChange,onDsChange:this.handleValueChange},i("div",{key:"1eb5d30abed6a07f6c5f44e5efe47720b2c214e5",class:"field ds-field-stack"},i("ds-text",{key:"a0785cdfe626b6763be595dd75cc62552186e504",class:"field__label",as:"label",variant:"text-body-small",color:"primary",emphasis:true,for:this.controlId,textId:this.labelId,onClick:this.handleLabelClick},this.label),i("div",{key:"031b65fa70183a131788025e5b5068ef63a7fdb2",class:"field__control",ref:e=>this.controlContainer=e},i("slot",{key:"ceb36ae99106bc84c03a31fcf1e182f67dfa90a8",onSlotchange:this.syncControl})),this.renderedDescription&&i("ds-text",{key:"abe3fbe90db07cd5318c913ed74a0177f50ca268",class:"field__description",as:"div",variant:"text-body-small",color:"secondary",textId:this.descriptionId},this.description),this.renderedError&&i("ds-text",{key:"cb833346fc0b75b155442a4558720f6c81d71fdb",class:"field__error",as:"div",variant:"text-body-small",color:"negative",textId:this.errorId,role:"alert"},this.errorMessage)))}get el(){return this}static get watchers(){return{fieldId:[{onFieldContractChange:0}],description:[{onFieldContractChange:0}],error:[{onFieldContractChange:0}],errorMessage:[{onFieldContractChange:0}]}}static get style(){return r()}},[262,"ds-field",{label:[1],fieldId:[1,"field-id"],description:[1],error:[4],errorMessage:[1,"error-message"],focused:[32],filled:[32],dirty:[32],touched:[32],controlDisabled:[32],controlRequired:[32],slotRevision:[32]},undefined,{fieldId:[{onFieldContractChange:0}],description:[{onFieldContractChange:0}],error:[{onFieldContractChange:0}],errorMessage:[{onFieldContractChange:0}]}]);function c(){if(typeof customElements==="undefined"){return}const e=["ds-field","ds-text"];e.forEach((e=>{switch(e){case"ds-field":if(!customElements.get(d(e))){customElements.define(d(e),h)}break;case"ds-text":if(!customElements.get(d(e))){n()}break}}))}c();export{h as F,c as d};
|
|
2
|
+
//# sourceMappingURL=p-Ctnm9NJP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["fieldCss","fieldCounter","tokens","value","split","filter","Boolean","uniqueTokens","groups","Set","flat","Field","__stencil_proxyCustomElement","HTMLElement","constructor","registerHost","this","error","focused","filled","dirty","touched","controlDisabled","controlRequired","slotRevision","generatedId","initialValue","authoredAria","WeakMap","didLoad","syncControl","control","findControl","readValue","set","labelledby","getAttribute","describedby","isDsControl","tagName","startsWith","inputId","controlId","updateControlAttribute","authored","get","labelId","join","renderedDescription","descriptionId","renderedError","errorId","undefined","length","disabled","isInactive","hasAttribute","required","handleLabelClick","event","preventDefault","setFocus","handleFocusIn","handleFocusOut","relatedTarget","Node","el","contains","handleValueChange","connectedCallback","observeLateControls","disconnectedCallback","childObserver","disconnect","componentDidLoad","requestAnimationFrame","componentDidRender","onFieldContractChange","fieldId","description","errorMessage","Array","isArray","String","name","removeAttribute","setAttribute","controlContainer","querySelector","MutationObserver","records","addedControl","some","record","from","addedNodes","node","nodeType","observe","childList","render","h","Host","key","onFocusin","onFocusout","onInput","onChange","onDsChange","class","as","variant","color","emphasis","for","textId","onClick","label","ref","onSlotchange","role"],"sources":["src/wc/components/Field/Field.css?tag=ds-field&encapsulation=scoped","src/wc/components/Field/Field.tsx"],"sourcesContent":["@import '../../utils/field-stack.css';\n\n:host {\n display: block;\n}\n\n.field__control {\n display: flex;\n min-width: 0;\n}\n\n.field__control > * {\n width: 100%;\n}\n","import { Component, Element, Prop, State, Watch, h, Host } from '@stencil/core';\n\ninterface FieldControl extends HTMLElement {\n value?: string | string[];\n inputId?: string;\n error?: boolean;\n disabled?: boolean;\n isInactive?: boolean;\n required?: boolean;\n setFocus?: () => Promise<void> | void;\n}\n\ninterface AuthoredAria {\n labelledby: string[];\n describedby: string[];\n}\n\nlet fieldCounter = 0;\n\nconst tokens = (value: string | null | undefined): string[] =>\n value?.split(/\\s+/).filter(Boolean) ?? [];\n\nconst uniqueTokens = (...groups: string[][]): string[] => [...new Set(groups.flat())];\n\n@Component({\n tag: 'ds-field',\n styleUrl: 'Field.css',\n scoped: true,\n})\nexport class Field {\n @Element() el!: HTMLElement;\n\n /** Persistent visible label for the single slotted control. */\n @Prop() label!: string;\n /** Explicit ID for the slotted control; generated when omitted. */\n @Prop() fieldId: string | undefined;\n /** Optional guidance associated with the slotted control while no visible error is shown. */\n @Prop() description: string | undefined;\n /** Invalid visual and accessible state forwarded to supported ds controls. */\n @Prop() error: boolean = false;\n /** Visible error associated with the slotted control while error is true. */\n @Prop() errorMessage: string | undefined;\n\n @State() private focused = false;\n @State() private filled = false;\n @State() private dirty = false;\n @State() private touched = false;\n @State() private controlDisabled = false;\n @State() private controlRequired = false;\n /** Bumped to let Stencil relocate a control added after the initial render. */\n @State() private slotRevision = 0;\n\n private readonly generatedId = `ds-field-${++fieldCounter}`;\n private controlContainer?: HTMLDivElement;\n private control?: FieldControl;\n private initialValue = '';\n private authoredAria = new WeakMap<FieldControl, AuthoredAria>();\n private childObserver?: MutationObserver;\n private didLoad = false;\n\n connectedCallback() {\n if (this.didLoad) this.observeLateControls();\n }\n\n disconnectedCallback() {\n this.childObserver?.disconnect();\n this.childObserver = undefined;\n }\n\n componentDidLoad() {\n this.syncControl();\n this.didLoad = true;\n this.observeLateControls();\n requestAnimationFrame(() => this.syncControl());\n }\n\n componentDidRender() {\n this.syncControl();\n }\n\n @Watch('fieldId')\n @Watch('description')\n @Watch('error')\n @Watch('errorMessage')\n onFieldContractChange() {\n this.syncControl();\n }\n\n private get controlId(): string {\n return this.fieldId || this.generatedId;\n }\n\n private get labelId(): string {\n return `${this.controlId}-label`;\n }\n\n private get descriptionId(): string {\n return `${this.controlId}-description`;\n }\n\n private get errorId(): string {\n return `${this.controlId}-error`;\n }\n\n private get renderedDescription(): boolean {\n return Boolean(this.description) && !this.renderedError;\n }\n\n private get renderedError(): boolean {\n return this.error && Boolean(this.errorMessage);\n }\n\n private readValue(control: FieldControl): string {\n const value = control.value;\n return Array.isArray(value) ? value.join('\\u001f') : String(value ?? '');\n }\n\n private updateControlAttribute(control: FieldControl, name: string, value: string | undefined) {\n if (value === undefined) {\n if (control.hasAttribute(name)) control.removeAttribute(name);\n return;\n }\n if (control.getAttribute(name) !== value) control.setAttribute(name, value);\n }\n\n private findControl(): FieldControl | undefined {\n return this.controlContainer?.querySelector<FieldControl>(':scope > :not(slot)') ?? undefined;\n }\n\n private observeLateControls() {\n if (this.childObserver || typeof MutationObserver === 'undefined') return;\n this.childObserver = new MutationObserver(records => {\n const addedControl = records.some(record =>\n Array.from(record.addedNodes).some(node => node.nodeType === 1)\n );\n if (addedControl) this.slotRevision++;\n });\n this.childObserver.observe(this.el, { childList: true });\n }\n\n private syncControl = () => {\n const control = this.findControl();\n if (!control) return;\n\n if (control !== this.control) {\n this.control = control;\n this.initialValue = this.readValue(control);\n this.authoredAria.set(control, {\n labelledby: tokens(control.getAttribute('aria-labelledby')),\n describedby: tokens(control.getAttribute('aria-describedby')),\n });\n }\n\n const isDsControl = control.tagName.startsWith('DS-');\n if (isDsControl && 'inputId' in control) control.inputId = this.controlId;\n else this.updateControlAttribute(control, 'id', this.controlId);\n\n const authored = this.authoredAria.get(control) ?? { labelledby: [], describedby: [] };\n const labelledby = uniqueTokens(authored.labelledby, [this.labelId]).join(' ');\n const describedby = uniqueTokens(\n authored.describedby,\n this.renderedDescription ? [this.descriptionId] : [],\n this.renderedError ? [this.errorId] : []\n ).join(' ');\n\n this.updateControlAttribute(control, 'aria-labelledby', labelledby);\n this.updateControlAttribute(control, 'aria-describedby', describedby || undefined);\n this.updateControlAttribute(control, 'aria-invalid', this.error ? 'true' : undefined);\n\n if (isDsControl && 'error' in control && control.error !== this.error)\n control.error = this.error;\n\n const value = this.readValue(control);\n this.filled = value.length > 0;\n this.dirty = value !== this.initialValue;\n this.controlDisabled = Boolean(\n control.disabled || control.isInactive || control.hasAttribute('disabled')\n );\n this.controlRequired = Boolean(control.required || control.hasAttribute('required'));\n };\n\n private handleLabelClick = (event: MouseEvent) => {\n if (!this.control?.tagName.startsWith('DS-')) return;\n event.preventDefault();\n this.control.setFocus?.();\n };\n\n private handleFocusIn = () => {\n this.focused = true;\n };\n\n private handleFocusOut = (event: FocusEvent) => {\n if (event.relatedTarget instanceof Node && this.el.contains(event.relatedTarget)) return;\n this.focused = false;\n this.touched = true;\n };\n\n private handleValueChange = () => {\n this.syncControl();\n };\n\n render() {\n return (\n <Host\n data-focused={this.focused ? '' : undefined}\n data-filled={this.filled ? '' : undefined}\n data-dirty={this.dirty ? '' : undefined}\n data-touched={this.touched ? '' : undefined}\n data-invalid={this.error ? '' : undefined}\n data-disabled={this.controlDisabled ? '' : undefined}\n data-required={this.controlRequired ? '' : undefined}\n onFocusin={this.handleFocusIn}\n onFocusout={this.handleFocusOut}\n onInput={this.handleValueChange}\n onChange={this.handleValueChange}\n onDsChange={this.handleValueChange}\n >\n <div class=\"field ds-field-stack\">\n <ds-text\n class=\"field__label\"\n as=\"label\"\n variant=\"text-body-small\"\n color=\"primary\"\n emphasis\n for={this.controlId}\n textId={this.labelId}\n onClick={this.handleLabelClick}\n >\n {this.label}\n </ds-text>\n <div class=\"field__control\" ref={el => (this.controlContainer = el)}>\n <slot onSlotchange={this.syncControl} />\n </div>\n {this.renderedDescription && (\n <ds-text\n class=\"field__description\"\n as=\"div\"\n variant=\"text-body-small\"\n color=\"secondary\"\n textId={this.descriptionId}\n >\n {this.description}\n </ds-text>\n )}\n {this.renderedError && (\n <ds-text\n class=\"field__error\"\n as=\"div\"\n variant=\"text-body-small\"\n color=\"negative\"\n textId={this.errorId}\n role=\"alert\"\n >\n {this.errorMessage}\n </ds-text>\n )}\n </div>\n </Host>\n );\n }\n}\n"],"mappings":"+FAAA,MAAMA,EAAW,IAAM,sQCiBvB,IAAIC,EAAe,EAEnB,MAAMC,EAAUC,GACdA,GAAOC,MAAM,OAAOC,OAAOC,UAAY,GAEzC,MAAMC,EAAe,IAAIC,IAAiC,IAAI,IAAIC,IAAID,EAAOE,S,MAOhEC,EAAKC,EAAA,MAAAD,UAAAE,EALlB,WAAAC,CAAAC,G,4CAeUC,KAAAC,MAAiB,MAIRD,KAAAE,QAAU,MACVF,KAAAG,OAAS,MACTH,KAAAI,MAAQ,MACRJ,KAAAK,QAAU,MACVL,KAAAM,gBAAkB,MAClBN,KAAAO,gBAAkB,MAElBP,KAAAQ,aAAe,EAEfR,KAAAS,YAAc,cAAcxB,IAGrCe,KAAAU,aAAe,GACfV,KAAAW,aAAe,IAAIC,QAEnBZ,KAAAa,QAAU,MAkFVb,KAAAc,YAAc,KACpB,MAAMC,EAAUf,KAAKgB,cACrB,IAAKD,EAAS,OAEd,GAAIA,IAAYf,KAAKe,QAAS,CAC5Bf,KAAKe,QAAUA,EACff,KAAKU,aAAeV,KAAKiB,UAAUF,GACnCf,KAAKW,aAAaO,IAAIH,EAAS,CAC7BI,WAAYjC,EAAO6B,EAAQK,aAAa,oBACxCC,YAAanC,EAAO6B,EAAQK,aAAa,sB,CAI7C,MAAME,EAAcP,EAAQQ,QAAQC,WAAW,OAC/C,GAAIF,GAAe,YAAaP,EAASA,EAAQU,QAAUzB,KAAK0B,eAC3D1B,KAAK2B,uBAAuBZ,EAAS,KAAMf,KAAK0B,WAErD,MAAME,EAAW5B,KAAKW,aAAakB,IAAId,IAAY,CAAEI,WAAY,GAAIE,YAAa,IAClF,MAAMF,EAAa5B,EAAaqC,EAAST,WAAY,CAACnB,KAAK8B,UAAUC,KAAK,KAC1E,MAAMV,EAAc9B,EAClBqC,EAASP,YACTrB,KAAKgC,oBAAsB,CAAChC,KAAKiC,eAAiB,GAClDjC,KAAKkC,cAAgB,CAAClC,KAAKmC,SAAW,IACtCJ,KAAK,KAEP/B,KAAK2B,uBAAuBZ,EAAS,kBAAmBI,GACxDnB,KAAK2B,uBAAuBZ,EAAS,mBAAoBM,GAAee,WACxEpC,KAAK2B,uBAAuBZ,EAAS,eAAgBf,KAAKC,MAAQ,OAASmC,WAE3E,GAAId,GAAe,UAAWP,GAAWA,EAAQd,QAAUD,KAAKC,MAC9Dc,EAAQd,MAAQD,KAAKC,MAEvB,MAAMd,EAAQa,KAAKiB,UAAUF,GAC7Bf,KAAKG,OAAShB,EAAMkD,OAAS,EAC7BrC,KAAKI,MAAQjB,IAAUa,KAAKU,aAC5BV,KAAKM,gBAAkBhB,QACrByB,EAAQuB,UAAYvB,EAAQwB,YAAcxB,EAAQyB,aAAa,aAEjExC,KAAKO,gBAAkBjB,QAAQyB,EAAQ0B,UAAY1B,EAAQyB,aAAa,YAAY,EAG9ExC,KAAA0C,iBAAoBC,IAC1B,IAAK3C,KAAKe,SAASQ,QAAQC,WAAW,OAAQ,OAC9CmB,EAAMC,iBACN5C,KAAKe,QAAQ8B,YAAY,EAGnB7C,KAAA8C,cAAgB,KACtB9C,KAAKE,QAAU,IAAI,EAGbF,KAAA+C,eAAkBJ,IACxB,GAAIA,EAAMK,yBAAyBC,MAAQjD,KAAKkD,GAAGC,SAASR,EAAMK,eAAgB,OAClFhD,KAAKE,QAAU,MACfF,KAAKK,QAAU,IAAI,EAGbL,KAAAoD,kBAAoB,KAC1BpD,KAAKc,aAAa,CA8DrB,CAxMC,iBAAAuC,GACE,GAAIrD,KAAKa,QAASb,KAAKsD,qB,CAGzB,oBAAAC,GACEvD,KAAKwD,eAAeC,aACpBzD,KAAKwD,cAAgBpB,S,CAGvB,gBAAAsB,GACE1D,KAAKc,cACLd,KAAKa,QAAU,KACfb,KAAKsD,sBACLK,uBAAsB,IAAM3D,KAAKc,e,CAGnC,kBAAA8C,GACE5D,KAAKc,a,CAOP,qBAAA+C,GACE7D,KAAKc,a,CAGP,aAAYY,GACV,OAAO1B,KAAK8D,SAAW9D,KAAKS,W,CAG9B,WAAYqB,GACV,MAAO,GAAG9B,KAAK0B,iB,CAGjB,iBAAYO,GACV,MAAO,GAAGjC,KAAK0B,uB,CAGjB,WAAYS,GACV,MAAO,GAAGnC,KAAK0B,iB,CAGjB,uBAAYM,GACV,OAAO1C,QAAQU,KAAK+D,eAAiB/D,KAAKkC,a,CAG5C,iBAAYA,GACV,OAAOlC,KAAKC,OAASX,QAAQU,KAAKgE,a,CAG5B,SAAA/C,CAAUF,GAChB,MAAM5B,EAAQ4B,EAAQ5B,MACtB,OAAO8E,MAAMC,QAAQ/E,GAASA,EAAM4C,KAAK,KAAYoC,OAAOhF,GAAS,G,CAG/D,sBAAAwC,CAAuBZ,EAAuBqD,EAAcjF,GAClE,GAAIA,IAAUiD,UAAW,CACvB,GAAIrB,EAAQyB,aAAa4B,GAAOrD,EAAQsD,gBAAgBD,GACxD,M,CAEF,GAAIrD,EAAQK,aAAagD,KAAUjF,EAAO4B,EAAQuD,aAAaF,EAAMjF,E,CAG/D,WAAA6B,GACN,OAAOhB,KAAKuE,kBAAkBC,cAA4B,wBAA0BpC,S,CAG9E,mBAAAkB,GACN,GAAItD,KAAKwD,sBAAwBiB,mBAAqB,YAAa,OACnEzE,KAAKwD,cAAgB,IAAIiB,kBAAiBC,IACxC,MAAMC,EAAeD,EAAQE,MAAKC,GAChCZ,MAAMa,KAAKD,EAAOE,YAAYH,MAAKI,GAAQA,EAAKC,WAAa,MAE/D,GAAIN,EAAc3E,KAAKQ,cAAc,IAEvCR,KAAKwD,cAAc0B,QAAQlF,KAAKkD,GAAI,CAAEiC,UAAW,M,CAgEnD,MAAAC,GACE,OACEC,EAACC,EAAI,CAAAC,IAAA,0DACWvF,KAAKE,QAAU,GAAKkC,UAAS,cAC9BpC,KAAKG,OAAS,GAAKiC,UAAS,aAC7BpC,KAAKI,MAAQ,GAAKgC,UAAS,eACzBpC,KAAKK,QAAU,GAAK+B,UAAS,eAC7BpC,KAAKC,MAAQ,GAAKmC,UAAS,gBAC1BpC,KAAKM,gBAAkB,GAAK8B,UAAS,gBACrCpC,KAAKO,gBAAkB,GAAK6B,UAC3CoD,UAAWxF,KAAK8C,cAChB2C,WAAYzF,KAAK+C,eACjB2C,QAAS1F,KAAKoD,kBACduC,SAAU3F,KAAKoD,kBACfwC,WAAY5F,KAAKoD,mBAEjBiC,EAAA,OAAAE,IAAA,2CAAKM,MAAM,wBACTR,EAAA,WAAAE,IAAA,2CACEM,MAAM,eACNC,GAAG,QACHC,QAAQ,kBACRC,MAAM,UACNC,SAAQ,KACRC,IAAKlG,KAAK0B,UACVyE,OAAQnG,KAAK8B,QACbsE,QAASpG,KAAK0C,kBAEb1C,KAAKqG,OAERhB,EAAA,OAAAE,IAAA,2CAAKM,MAAM,iBAAiBS,IAAKpD,GAAOlD,KAAKuE,iBAAmBrB,GAC9DmC,EAAA,QAAAE,IAAA,2CAAMgB,aAAcvG,KAAKc,eAE1Bd,KAAKgC,qBACJqD,EAAA,WAAAE,IAAA,2CACEM,MAAM,qBACNC,GAAG,MACHC,QAAQ,kBACRC,MAAM,YACNG,OAAQnG,KAAKiC,eAEZjC,KAAK+D,aAGT/D,KAAKkC,eACJmD,EAAA,WAAAE,IAAA,2CACEM,MAAM,eACNC,GAAG,MACHC,QAAQ,kBACRC,MAAM,WACNG,OAAQnG,KAAKmC,QACbqE,KAAK,SAEJxG,KAAKgE,e","ignoreList":[]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{p as e,H as s,h as o,a as r,t as n}from"./index.js";import{d as i}from"./p-Is1lFmwp.js";import{d as c}from"./p-DQQsS9Rx.js";const a=["fair","good","excellent"];function d(e){return typeof e==="string"&&a.includes(e)}function t(e){if(typeof e==="string"&&e.trim()==="")return undefined;const s=typeof e==="number"?e:Number(e);if(!Number.isFinite(s)||s<0||s>100)return undefined;if(s<=50)return"fair";if(s<=80)return"good";return"excellent"}function l(e,s){return d(s)?s:t(e)}const b={sm:"text-title-small",md:"text-title-large",lg:"text-display-small"};const g=()=>`.ds-control-frame.sc-ds-score{display:inline-flex;align-items:center;box-sizing:border-box;height:var(--ds-control-height, var(--dimension-size-400));padding-inline:var(--ds-control-padding-inline, var(--dimension-space-075));gap:var(--ds-control-gap, var(--dimension-space-050));border-radius:var(--ds-control-radius, var(--dimension-radius-025))}.ds-control-section-heading.sc-ds-score{display:flex;align-items:center;box-sizing:border-box;height:var(--ds-control-height, var(--dimension-size-400));padding-inline:calc( var(--ds-control-padding-inline, var(--dimension-space-075)) + var(--ds-control-label-inset, var(--dimension-space-025)) )}.ds-control-icon-box.sc-ds-score{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--ds-control-icon, var(--dimension-iconography-md));height:var(--ds-control-icon, var(--dimension-iconography-md))}.ds-control-label-box.sc-ds-score{min-width:0;padding-inline:var(--ds-control-label-inset, var(--dimension-space-025))}.ds-control-label-dot.sc-ds-score{position:relative;padding-inline-end:calc( var(--ds-control-label-inset, var(--dimension-space-025)) + var(--ds-control-gap, var(--dimension-space-050)) )}.ds-control-label-dot__badge.sc-ds-score{position:absolute;inset-block-start:0;inset-inline-end:0;pointer-events:none}@media (forced-colors: active){.sc-ds-score:root,.sc-ds-score-h,.ds-forced-colors-scope.sc-ds-score{--ds-forced-color-surface:Canvas;--ds-forced-color-content:CanvasText;--ds-forced-color-control-boundary:ButtonText;--ds-forced-color-selected:Highlight;--ds-forced-color-on-selected:HighlightText;--ds-forced-color-disabled:GrayText}}.sc-ds-score-h{display:inline-flex;align-items:center;box-sizing:border-box;min-width:0;--_score-badge-inline-size:var(--dimension-size-500);--_score-badge-block-size:var(--dimension-size-400);--_score-skeleton-inset:calc(var(--_score-badge-block-size) / 8)}.score--sm.sc-ds-score-h{--_score-badge-inline-size:calc(var(--dimension-size-400) - var(--dimension-space-050));--_score-badge-block-size:var(--dimension-size-300)}.score--md.sc-ds-score-h{--_score-badge-inline-size:var(--dimension-size-500);--_score-badge-block-size:var(--dimension-size-400)}.score--lg.sc-ds-score-h{--_score-badge-inline-size:calc(var(--dimension-size-600) + var(--dimension-space-100));--_score-badge-block-size:var(--dimension-size-500)}.score__badge.sc-ds-score{display:flex;flex:0 0 auto;align-items:center;justify-content:center;box-sizing:border-box;inline-size:var(--_score-badge-inline-size);block-size:var(--_score-badge-block-size);overflow:hidden;border-radius:var(--dimension-radius-025);background:var(--color-background-faint-neutral);color:var(--color-foreground-bold-neutral);-webkit-user-select:none;user-select:none}.score__badge--fair.sc-ds-score{background:var(--color-safety-score-background-fair);color:var(--color-safety-score-foreground-on-fair)}.score__badge--good.sc-ds-score{background:var(--color-safety-score-background-good);color:var(--color-foreground-
|
|
2
|
-
//# sourceMappingURL=p-
|
|
1
|
+
import{p as e,H as s,h as o,a as r,t as n}from"./index.js";import{d as i}from"./p-Is1lFmwp.js";import{d as c}from"./p-DQQsS9Rx.js";const a=["fair","good","excellent"];function d(e){return typeof e==="string"&&a.includes(e)}function t(e){if(typeof e==="string"&&e.trim()==="")return undefined;const s=typeof e==="number"?e:Number(e);if(!Number.isFinite(s)||s<0||s>100)return undefined;if(s<=50)return"fair";if(s<=80)return"good";return"excellent"}function l(e,s){return d(s)?s:t(e)}const b={sm:"text-title-small",md:"text-title-large",lg:"text-display-small"};const g=()=>`.ds-control-frame.sc-ds-score{display:inline-flex;align-items:center;box-sizing:border-box;height:var(--ds-control-height, var(--dimension-size-400));padding-inline:var(--ds-control-padding-inline, var(--dimension-space-075));gap:var(--ds-control-gap, var(--dimension-space-050));border-radius:var(--ds-control-radius, var(--dimension-radius-025))}.ds-control-section-heading.sc-ds-score{display:flex;align-items:center;box-sizing:border-box;height:var(--ds-control-height, var(--dimension-size-400));padding-inline:calc( var(--ds-control-padding-inline, var(--dimension-space-075)) + var(--ds-control-label-inset, var(--dimension-space-025)) )}.ds-control-icon-box.sc-ds-score{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--ds-control-icon, var(--dimension-iconography-md));height:var(--ds-control-icon, var(--dimension-iconography-md))}.ds-control-label-box.sc-ds-score{min-width:0;padding-inline:var(--ds-control-label-inset, var(--dimension-space-025))}.ds-control-label-dot.sc-ds-score{position:relative;padding-inline-end:calc( var(--ds-control-label-inset, var(--dimension-space-025)) + var(--ds-control-gap, var(--dimension-space-050)) )}.ds-control-label-dot__badge.sc-ds-score{position:absolute;inset-block-start:0;inset-inline-end:0;pointer-events:none}@media (forced-colors: active){.sc-ds-score:root,.sc-ds-score-h,.ds-forced-colors-scope.sc-ds-score{--ds-forced-color-surface:Canvas;--ds-forced-color-content:CanvasText;--ds-forced-color-control-boundary:ButtonText;--ds-forced-color-selected:Highlight;--ds-forced-color-on-selected:HighlightText;--ds-forced-color-disabled:GrayText}}.sc-ds-score-h{display:inline-flex;align-items:center;box-sizing:border-box;min-width:0;--_score-badge-inline-size:var(--dimension-size-500);--_score-badge-block-size:var(--dimension-size-400);--_score-skeleton-inset:calc(var(--_score-badge-block-size) / 8)}.score--sm.sc-ds-score-h{--_score-badge-inline-size:calc(var(--dimension-size-400) - var(--dimension-space-050));--_score-badge-block-size:var(--dimension-size-300)}.score--md.sc-ds-score-h{--_score-badge-inline-size:var(--dimension-size-500);--_score-badge-block-size:var(--dimension-size-400)}.score--lg.sc-ds-score-h{--_score-badge-inline-size:calc(var(--dimension-size-600) + var(--dimension-space-100));--_score-badge-block-size:var(--dimension-size-500)}.score__badge.sc-ds-score{display:flex;flex:0 0 auto;align-items:center;justify-content:center;box-sizing:border-box;inline-size:var(--_score-badge-inline-size);block-size:var(--_score-badge-block-size);overflow:hidden;border-radius:var(--dimension-radius-025);background:var(--color-background-faint-neutral);color:var(--color-foreground-bold-neutral);-webkit-user-select:none;user-select:none}.score__badge--fair.sc-ds-score{background:var(--color-safety-score-background-fair);color:var(--color-safety-score-foreground-on-fair)}.score__badge--good.sc-ds-score{background:var(--color-safety-score-background-good);color:var(--color-safety-score-foreground-on-good)}.score__badge--excellent.sc-ds-score{background:var(--color-safety-score-background-excellent);color:var(--color-safety-score-foreground-on-excellent)}.score__value.sc-ds-score,.score__badge.sc-ds-score ds-skeleton.sc-ds-score{flex:0 0 auto}.score__badge--loading.sc-ds-score{padding-inline:var(--_score-skeleton-inset)}.score__badge--loading.sc-ds-score .score__value.sc-ds-score{flex:1 1 auto;inline-size:100%;block-size:100%;max-inline-size:100%;max-block-size:100%;min-inline-size:0}@media (forced-colors: active){.score__badge.sc-ds-score{border:var(--dimension-stroke-width-012) solid var(--ds-forced-color-content);background:var(--ds-forced-color-surface);color:var(--ds-forced-color-content)}}`;const f=e(class e extends s{constructor(e){super();if(e!==false){this.__registerHost()}this.value="";this.size="md";this.isLoading=false;this.label=""}render(){const e=this.size;const s=l(this.value,this.level);const n=b[e];const i=[this.label.trim(),this.isLoading?"":this.value].filter(Boolean).join(" ");return o(r,{key:"bd3d48d1ab1fd1f13e98e727e1d7de3b40fa886c",class:{score:true,[`score--${e}`]:true,"score--loading":this.isLoading},role:i?"img":undefined,"aria-busy":this.isLoading?"true":undefined,"aria-label":i||undefined},o("span",{key:"b3ca6f3000917055fc7c97d2d052930f40a94339",class:{score__badge:true,[`score__badge--${s}`]:Boolean(s),"score__badge--loading":this.isLoading}},this.isLoading?o("ds-skeleton",{class:"score__value",variant:"text",textVariant:n,background:s?"bold":"faint"}):o("ds-text",{as:"span",class:"score__value ds-control-label-box",variant:n,emphasis:true,color:"inherit",fontFeature:"tabular-nums"},this.value)))}static get style(){return g()}},[2,"ds-score",{value:[8],size:[1],level:[1],isLoading:[4,"is-loading"],label:[1]}]);function u(){if(typeof customElements==="undefined"){return}const e=["ds-score","ds-skeleton","ds-text"];e.forEach((e=>{switch(e){case"ds-score":if(!customElements.get(n(e))){customElements.define(n(e),f)}break;case"ds-skeleton":if(!customElements.get(n(e))){i()}break;case"ds-text":if(!customElements.get(n(e))){c()}break}}))}u();export{f as S,u as d,d as i};
|
|
2
|
+
//# sourceMappingURL=p-VT-5XDkB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["SAFETY_SCORE_LEVELS","isSafetyScoreLevel","value","includes","resolveSafetyScoreLevel","trim","undefined","numericValue","Number","isFinite","resolveScoreLevel","level","SCORE_VALUE_VARIANT","sm","md","lg","scoreCss","Score","__stencil_proxyCustomElement","HTMLElement","constructor","registerHost","this","size","isLoading","label","render","valueVariant","accessibleName","filter","Boolean","join","h","Host","key","class","score","role","score__badge","variant","textVariant","background","as","emphasis","color","fontFeature"],"sources":["src/wc/components/Score/score-types.ts","src/wc/components/Score/score-model.ts","src/wc/components/Score/Score.css?tag=ds-score&encapsulation=scoped","src/wc/components/Score/Score.tsx"],"sourcesContent":["export type SafetyScoreLevel = 'fair' | 'good' | 'excellent';\nexport type ScoreSize = 'sm' | 'md' | 'lg';\n\nexport const SCORE_SIZES = ['sm', 'md', 'lg'] as const;\nexport const SAFETY_SCORE_LEVELS = ['fair', 'good', 'excellent'] as const;\n","import { SAFETY_SCORE_LEVELS, type SafetyScoreLevel, type ScoreSize } from './score-types';\n\nexport function isSafetyScoreLevel(value: unknown): value is SafetyScoreLevel {\n return typeof value === 'string' && (SAFETY_SCORE_LEVELS as readonly string[]).includes(value);\n}\n\n/**\n * Infer a safety-score color level from a 0–100 figure. Non-numeric or out-of-range\n * values return undefined so the owner can supply `level` explicitly.\n */\nexport function resolveSafetyScoreLevel(value: string | number): SafetyScoreLevel | undefined {\n if (typeof value === 'string' && value.trim() === '') return undefined;\n const numericValue = typeof value === 'number' ? value : Number(value);\n if (!Number.isFinite(numericValue) || numericValue < 0 || numericValue > 100) return undefined;\n if (numericValue <= 50) return 'fair';\n if (numericValue <= 80) return 'good';\n return 'excellent';\n}\n\nexport function resolveScoreLevel(\n value: string | number,\n level?: SafetyScoreLevel\n): SafetyScoreLevel | undefined {\n return isSafetyScoreLevel(level) ? level : resolveSafetyScoreLevel(value);\n}\n\nexport const SCORE_VALUE_VARIANT = {\n sm: 'text-title-small',\n md: 'text-title-large',\n lg: 'text-display-small',\n} as const satisfies Record<\n ScoreSize,\n 'text-title-small' | 'text-title-large' | 'text-display-small'\n>;\n","@import '../../utils/control-parts.css';\n@import '../../utils/forced-colors.css';\n\n:host {\n display: inline-flex;\n align-items: center;\n box-sizing: border-box;\n min-width: 0;\n --_score-badge-inline-size: var(--dimension-size-500);\n --_score-badge-block-size: var(--dimension-size-400);\n /* Matches the text skeleton’s 75% bar so the fill inset is even on all sides. */\n --_score-skeleton-inset: calc(var(--_score-badge-block-size) / 8);\n}\n\n:host(.score--sm) {\n --_score-badge-inline-size: calc(var(--dimension-size-400) - var(--dimension-space-050));\n --_score-badge-block-size: var(--dimension-size-300);\n}\n\n:host(.score--md) {\n --_score-badge-inline-size: var(--dimension-size-500);\n --_score-badge-block-size: var(--dimension-size-400);\n}\n\n:host(.score--lg) {\n --_score-badge-inline-size: calc(var(--dimension-size-600) + var(--dimension-space-100));\n --_score-badge-block-size: var(--dimension-size-500);\n}\n\n.score__badge {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n inline-size: var(--_score-badge-inline-size);\n block-size: var(--_score-badge-block-size);\n overflow: hidden;\n border-radius: var(--dimension-radius-025);\n background: var(--color-background-faint-neutral);\n color: var(--color-foreground-bold-neutral);\n -webkit-user-select: none;\n user-select: none;\n}\n\n.score__badge--fair {\n background: var(--color-safety-score-background-fair);\n color: var(--color-safety-score-foreground-on-fair);\n}\n\n.score__badge--good {\n background: var(--color-safety-score-background-good);\n color: var(--color-safety-score-foreground-on-good);\n}\n\n.score__badge--excellent {\n background: var(--color-safety-score-background-excellent);\n color: var(--color-safety-score-foreground-on-excellent);\n}\n\n.score__value,\n.score__badge ds-skeleton {\n flex: 0 0 auto;\n}\n\n.score__badge--loading {\n padding-inline: var(--_score-skeleton-inset);\n}\n\n.score__badge--loading .score__value {\n flex: 1 1 auto;\n inline-size: 100%;\n block-size: 100%;\n max-inline-size: 100%;\n max-block-size: 100%;\n min-inline-size: 0;\n}\n\n@media (forced-colors: active) {\n .score__badge {\n border: var(--dimension-stroke-width-012) solid var(--ds-forced-color-content);\n background: var(--ds-forced-color-surface);\n color: var(--ds-forced-color-content);\n }\n}\n","import { Component, Prop, h, Host } from '@stencil/core';\nimport { SCORE_VALUE_VARIANT, resolveScoreLevel } from './score-model';\nimport type { SafetyScoreLevel, ScoreSize } from './score-types';\n\n@Component({\n tag: 'ds-score',\n styleUrl: 'Score.css',\n scoped: true,\n})\nexport class Score {\n /** Display-ready headline figure. */\n @Prop() value: string | number = '';\n /**\n * Visual density matching control height: `sm` 24px, `md` 32px, `lg` 40px.\n * `lg` is the Card Overview recipe.\n */\n @Prop() size: ScoreSize = 'md';\n /**\n * Safety-score color level. Numeric values from 0–100 infer fair (0–50),\n * good (51–80), or excellent (81–100) when this is omitted.\n */\n @Prop() level: SafetyScoreLevel | undefined;\n /** Replace the figure with a skeleton while data resolves. */\n @Prop() isLoading: boolean = false;\n /** Accessible name prefix, for example “Safety score”. */\n @Prop() label: string = '';\n\n render() {\n const size = this.size;\n const level = resolveScoreLevel(this.value, this.level);\n const valueVariant = SCORE_VALUE_VARIANT[size];\n const accessibleName = [this.label.trim(), this.isLoading ? '' : this.value]\n .filter(Boolean)\n .join(' ');\n\n return (\n <Host\n class={{\n score: true,\n [`score--${size}`]: true,\n 'score--loading': this.isLoading,\n }}\n role={accessibleName ? 'img' : undefined}\n aria-busy={this.isLoading ? 'true' : undefined}\n aria-label={accessibleName || undefined}\n >\n <span\n class={{\n score__badge: true,\n [`score__badge--${level}`]: Boolean(level),\n 'score__badge--loading': this.isLoading,\n }}\n >\n {this.isLoading ? (\n <ds-skeleton\n class=\"score__value\"\n variant=\"text\"\n textVariant={valueVariant}\n background={level ? 'bold' : 'faint'}\n />\n ) : (\n <ds-text\n as=\"span\"\n class=\"score__value ds-control-label-box\"\n variant={valueVariant}\n emphasis={true}\n color=\"inherit\"\n fontFeature=\"tabular-nums\"\n >\n {this.value}\n </ds-text>\n )}\n </span>\n </Host>\n );\n }\n}\n"],"mappings":"mIAIO,MAAMA,EAAsB,CAAC,OAAQ,OAAQ,aCF9C,SAAUC,EAAmBC,GACjC,cAAcA,IAAU,UAAaF,EAA0CG,SAASD,EAC1F,CAMM,SAAUE,EAAwBF,GACtC,UAAWA,IAAU,UAAYA,EAAMG,SAAW,GAAI,OAAOC,UAC7D,MAAMC,SAAsBL,IAAU,SAAWA,EAAQM,OAAON,GAChE,IAAKM,OAAOC,SAASF,IAAiBA,EAAe,GAAKA,EAAe,IAAK,OAAOD,UACrF,GAAIC,GAAgB,GAAI,MAAO,OAC/B,GAAIA,GAAgB,GAAI,MAAO,OAC/B,MAAO,WACT,CAEM,SAAUG,EACdR,EACAS,GAEA,OAAOV,EAAmBU,GAASA,EAAQP,EAAwBF,EACrE,CAEO,MAAMU,EAAsB,CACjCC,GAAI,mBACJC,GAAI,mBACJC,GAAI,sBC7BN,MAAMC,EAAW,IAAM,yqH,MCSVC,EAAKC,EAAA,MAAAD,UAAAE,EALlB,WAAAC,CAAAC,G,4CAOUC,KAAApB,MAAyB,GAKzBoB,KAAAC,KAAkB,KAOlBD,KAAAE,UAAqB,MAErBF,KAAAG,MAAgB,EAmDzB,CAjDC,MAAAC,GACE,MAAMH,EAAOD,KAAKC,KAClB,MAAMZ,EAAQD,EAAkBY,KAAKpB,MAAOoB,KAAKX,OACjD,MAAMgB,EAAef,EAAoBW,GACzC,MAAMK,EAAiB,CAACN,KAAKG,MAAMpB,OAAQiB,KAAKE,UAAY,GAAKF,KAAKpB,OACnE2B,OAAOC,SACPC,KAAK,KAER,OACEC,EAACC,EAAI,CAAAC,IAAA,2CACHC,MAAO,CACLC,MAAO,KACP,CAAC,UAAUb,KAAS,KACpB,iBAAkBD,KAAKE,WAEzBa,KAAMT,EAAiB,MAAQtB,UAAS,YAC7BgB,KAAKE,UAAY,OAASlB,UAAS,aAClCsB,GAAkBtB,WAE9B0B,EAAA,QAAAE,IAAA,2CACEC,MAAO,CACLG,aAAc,KACd,CAAC,iBAAiB3B,KAAUmB,QAAQnB,GACpC,wBAAyBW,KAAKE,YAG/BF,KAAKE,UACJQ,EAAA,eACEG,MAAM,eACNI,QAAQ,OACRC,YAAab,EACbc,WAAY9B,EAAQ,OAAS,UAG/BqB,EAAA,WACEU,GAAG,OACHP,MAAM,oCACNI,QAASZ,EACTgB,SAAU,KACVC,MAAM,UACNC,YAAY,gBAEXvB,KAAKpB,Q","ignoreList":[]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"timestamp": "2026-09-
|
|
2
|
+
"timestamp": "2026-09-03T17:36:47",
|
|
3
3
|
"compiler": {
|
|
4
4
|
"name": "@stencil/core",
|
|
5
5
|
"version": "4.43.5",
|
|
@@ -34871,12 +34871,12 @@
|
|
|
34871
34871
|
"path": "src/wc/components/Switch/Switch.tsx"
|
|
34872
34872
|
},
|
|
34873
34873
|
"src/wc/components/TableGroup/TableGroup.tsx::TableGroupOption": {
|
|
34874
|
-
"declaration": "export interface TableGroupOption {\n label: string;\n value: string;\n description?: string;\n isInactive?: boolean;\n}",
|
|
34874
|
+
"declaration": "export interface TableGroupOption {\n label: string;\n value: string;\n description?: string;\n isInactive?: boolean;\n /** Product-owned order choices for this grouping data point. */\n orderOptions?: TableGroupOrderOption[];\n}",
|
|
34875
34875
|
"docstring": "",
|
|
34876
34876
|
"path": "src/wc/components/TableGroup/TableGroup.tsx"
|
|
34877
34877
|
},
|
|
34878
34878
|
"src/wc/components/Table/table-types.ts::TableGroupingState": {
|
|
34879
|
-
"declaration": "export interface TableGroupingState {\n columnId: string;\n direction: TableSortDirection;\n}",
|
|
34879
|
+
"declaration": "export interface TableGroupingState {\n columnId: string;\n direction: TableSortDirection;\n /** Optional application-owned data point used to order the group sections. */\n orderBy?: string;\n}",
|
|
34880
34880
|
"docstring": "One controlled grouping level. Applications supply groups in their final fixed order.",
|
|
34881
34881
|
"path": "src/wc/components/Table/table-types.ts"
|
|
34882
34882
|
},
|
|
@@ -221,7 +221,7 @@
|
|
|
221
221
|
},
|
|
222
222
|
{
|
|
223
223
|
"path": "src/wc/components/Field/Field.tsx",
|
|
224
|
-
"content": "import { Component, Element, Prop, State, Watch, h, Host } from '@stencil/core';\n\ninterface FieldControl extends HTMLElement {\n value?: string | string[];\n inputId?: string;\n error?: boolean;\n disabled?: boolean;\n isInactive?: boolean;\n required?: boolean;\n setFocus?: () => Promise<void> | void;\n}\n\ninterface AuthoredAria {\n labelledby: string[];\n describedby: string[];\n}\n\nlet fieldCounter = 0;\n\nconst tokens = (value: string | null | undefined): string[] =>\n value?.split(/\\s+/).filter(Boolean) ?? [];\n\nconst uniqueTokens = (...groups: string[][]): string[] => [...new Set(groups.flat())];\n\n@Component({\n tag: 'ds-field',\n styleUrl: 'Field.css',\n scoped: true,\n})\nexport class Field {\n @Element() el!: HTMLElement;\n\n /** Persistent visible label for the single slotted control. */\n @Prop() label!: string;\n /** Explicit ID for the slotted control; generated when omitted. */\n @Prop() fieldId: string | undefined;\n /** Optional guidance associated with the slotted control while no visible error is shown. */\n @Prop() description: string | undefined;\n /** Invalid visual and accessible state forwarded to supported ds controls. */\n @Prop() error: boolean = false;\n /** Visible error associated with the slotted control while error is true. */\n @Prop() errorMessage: string | undefined;\n\n @State() private focused = false;\n @State() private filled = false;\n @State() private dirty = false;\n @State() private touched = false;\n @State() private controlDisabled = false;\n @State() private controlRequired = false;\n\n private readonly generatedId = `ds-field-${++fieldCounter}`;\n private controlContainer?: HTMLDivElement;\n private control?: FieldControl;\n private initialValue = '';\n private authoredAria = new WeakMap<FieldControl, AuthoredAria>();\n\n componentDidLoad() {\n this.syncControl();\n requestAnimationFrame(() => this.syncControl());\n }\n\n componentDidRender() {\n this.syncControl();\n }\n\n @Watch('fieldId')\n @Watch('description')\n @Watch('error')\n @Watch('errorMessage')\n onFieldContractChange() {\n this.syncControl();\n }\n\n private get controlId(): string {\n return this.fieldId || this.generatedId;\n }\n\n private get labelId(): string {\n return `${this.controlId}-label`;\n }\n\n private get descriptionId(): string {\n return `${this.controlId}-description`;\n }\n\n private get errorId(): string {\n return `${this.controlId}-error`;\n }\n\n private get renderedDescription(): boolean {\n return Boolean(this.description) && !this.renderedError;\n }\n\n private get renderedError(): boolean {\n return this.error && Boolean(this.errorMessage);\n }\n\n private readValue(control: FieldControl): string {\n const value = control.value;\n return Array.isArray(value) ? value.join('\\u001f') : String(value ?? '');\n }\n\n private updateControlAttribute(control: FieldControl, name: string, value: string | undefined) {\n if (value === undefined) {\n if (control.hasAttribute(name)) control.removeAttribute(name);\n return;\n }\n if (control.getAttribute(name) !== value) control.setAttribute(name, value);\n }\n\n private findControl(): FieldControl | undefined {\n return this.controlContainer?.querySelector<FieldControl>(':scope > :not(slot)') ?? undefined;\n }\n\n private syncControl = () => {\n const control = this.findControl();\n if (!control) return;\n\n if (control !== this.control) {\n this.control = control;\n this.initialValue = this.readValue(control);\n this.authoredAria.set(control, {\n labelledby: tokens(control.getAttribute('aria-labelledby')),\n describedby: tokens(control.getAttribute('aria-describedby')),\n });\n }\n\n const isDsControl = control.tagName.startsWith('DS-');\n if (isDsControl && 'inputId' in control) control.inputId = this.controlId;\n else this.updateControlAttribute(control, 'id', this.controlId);\n\n const authored = this.authoredAria.get(control) ?? { labelledby: [], describedby: [] };\n const labelledby = uniqueTokens(authored.labelledby, [this.labelId]).join(' ');\n const describedby = uniqueTokens(\n authored.describedby,\n this.renderedDescription ? [this.descriptionId] : [],\n this.renderedError ? [this.errorId] : []\n ).join(' ');\n\n this.updateControlAttribute(control, 'aria-labelledby', labelledby);\n this.updateControlAttribute(control, 'aria-describedby', describedby || undefined);\n this.updateControlAttribute(control, 'aria-invalid', this.error ? 'true' : undefined);\n\n if (isDsControl && 'error' in control && control.error !== this.error)\n control.error = this.error;\n\n const value = this.readValue(control);\n this.filled = value.length > 0;\n this.dirty = value !== this.initialValue;\n this.controlDisabled = Boolean(\n control.disabled || control.isInactive || control.hasAttribute('disabled')\n );\n this.controlRequired = Boolean(control.required || control.hasAttribute('required'));\n };\n\n private handleLabelClick = (event: MouseEvent) => {\n if (!this.control?.tagName.startsWith('DS-')) return;\n event.preventDefault();\n this.control.setFocus?.();\n };\n\n private handleFocusIn = () => {\n this.focused = true;\n };\n\n private handleFocusOut = (event: FocusEvent) => {\n if (event.relatedTarget instanceof Node && this.el.contains(event.relatedTarget)) return;\n this.focused = false;\n this.touched = true;\n };\n\n private handleValueChange = () => {\n this.syncControl();\n };\n\n render() {\n return (\n <Host\n data-focused={this.focused ? '' : undefined}\n data-filled={this.filled ? '' : undefined}\n data-dirty={this.dirty ? '' : undefined}\n data-touched={this.touched ? '' : undefined}\n data-invalid={this.error ? '' : undefined}\n data-disabled={this.controlDisabled ? '' : undefined}\n data-required={this.controlRequired ? '' : undefined}\n onFocusin={this.handleFocusIn}\n onFocusout={this.handleFocusOut}\n onInput={this.handleValueChange}\n onChange={this.handleValueChange}\n onDsChange={this.handleValueChange}\n >\n <div class=\"field ds-field-stack\">\n <ds-text\n class=\"field__label\"\n as=\"label\"\n variant=\"text-body-small\"\n color=\"primary\"\n emphasis\n for={this.controlId}\n textId={this.labelId}\n onClick={this.handleLabelClick}\n >\n {this.label}\n </ds-text>\n <div class=\"field__control\" ref={el => (this.controlContainer = el)}>\n <slot onSlotchange={this.syncControl} />\n </div>\n {this.renderedDescription && (\n <ds-text\n class=\"field__description\"\n as=\"div\"\n variant=\"text-body-small\"\n color=\"secondary\"\n textId={this.descriptionId}\n >\n {this.description}\n </ds-text>\n )}\n {this.renderedError && (\n <ds-text\n class=\"field__error\"\n as=\"div\"\n variant=\"text-body-small\"\n color=\"negative\"\n textId={this.errorId}\n role=\"alert\"\n >\n {this.errorMessage}\n </ds-text>\n )}\n </div>\n </Host>\n );\n }\n}\n",
|
|
224
|
+
"content": "import { Component, Element, Prop, State, Watch, h, Host } from '@stencil/core';\n\ninterface FieldControl extends HTMLElement {\n value?: string | string[];\n inputId?: string;\n error?: boolean;\n disabled?: boolean;\n isInactive?: boolean;\n required?: boolean;\n setFocus?: () => Promise<void> | void;\n}\n\ninterface AuthoredAria {\n labelledby: string[];\n describedby: string[];\n}\n\nlet fieldCounter = 0;\n\nconst tokens = (value: string | null | undefined): string[] =>\n value?.split(/\\s+/).filter(Boolean) ?? [];\n\nconst uniqueTokens = (...groups: string[][]): string[] => [...new Set(groups.flat())];\n\n@Component({\n tag: 'ds-field',\n styleUrl: 'Field.css',\n scoped: true,\n})\nexport class Field {\n @Element() el!: HTMLElement;\n\n /** Persistent visible label for the single slotted control. */\n @Prop() label!: string;\n /** Explicit ID for the slotted control; generated when omitted. */\n @Prop() fieldId: string | undefined;\n /** Optional guidance associated with the slotted control while no visible error is shown. */\n @Prop() description: string | undefined;\n /** Invalid visual and accessible state forwarded to supported ds controls. */\n @Prop() error: boolean = false;\n /** Visible error associated with the slotted control while error is true. */\n @Prop() errorMessage: string | undefined;\n\n @State() private focused = false;\n @State() private filled = false;\n @State() private dirty = false;\n @State() private touched = false;\n @State() private controlDisabled = false;\n @State() private controlRequired = false;\n /** Bumped to let Stencil relocate a control added after the initial render. */\n @State() private slotRevision = 0;\n\n private readonly generatedId = `ds-field-${++fieldCounter}`;\n private controlContainer?: HTMLDivElement;\n private control?: FieldControl;\n private initialValue = '';\n private authoredAria = new WeakMap<FieldControl, AuthoredAria>();\n private childObserver?: MutationObserver;\n private didLoad = false;\n\n connectedCallback() {\n if (this.didLoad) this.observeLateControls();\n }\n\n disconnectedCallback() {\n this.childObserver?.disconnect();\n this.childObserver = undefined;\n }\n\n componentDidLoad() {\n this.syncControl();\n this.didLoad = true;\n this.observeLateControls();\n requestAnimationFrame(() => this.syncControl());\n }\n\n componentDidRender() {\n this.syncControl();\n }\n\n @Watch('fieldId')\n @Watch('description')\n @Watch('error')\n @Watch('errorMessage')\n onFieldContractChange() {\n this.syncControl();\n }\n\n private get controlId(): string {\n return this.fieldId || this.generatedId;\n }\n\n private get labelId(): string {\n return `${this.controlId}-label`;\n }\n\n private get descriptionId(): string {\n return `${this.controlId}-description`;\n }\n\n private get errorId(): string {\n return `${this.controlId}-error`;\n }\n\n private get renderedDescription(): boolean {\n return Boolean(this.description) && !this.renderedError;\n }\n\n private get renderedError(): boolean {\n return this.error && Boolean(this.errorMessage);\n }\n\n private readValue(control: FieldControl): string {\n const value = control.value;\n return Array.isArray(value) ? value.join('\\u001f') : String(value ?? '');\n }\n\n private updateControlAttribute(control: FieldControl, name: string, value: string | undefined) {\n if (value === undefined) {\n if (control.hasAttribute(name)) control.removeAttribute(name);\n return;\n }\n if (control.getAttribute(name) !== value) control.setAttribute(name, value);\n }\n\n private findControl(): FieldControl | undefined {\n return this.controlContainer?.querySelector<FieldControl>(':scope > :not(slot)') ?? undefined;\n }\n\n private observeLateControls() {\n if (this.childObserver || typeof MutationObserver === 'undefined') return;\n this.childObserver = new MutationObserver(records => {\n const addedControl = records.some(record =>\n Array.from(record.addedNodes).some(node => node.nodeType === 1)\n );\n if (addedControl) this.slotRevision++;\n });\n this.childObserver.observe(this.el, { childList: true });\n }\n\n private syncControl = () => {\n const control = this.findControl();\n if (!control) return;\n\n if (control !== this.control) {\n this.control = control;\n this.initialValue = this.readValue(control);\n this.authoredAria.set(control, {\n labelledby: tokens(control.getAttribute('aria-labelledby')),\n describedby: tokens(control.getAttribute('aria-describedby')),\n });\n }\n\n const isDsControl = control.tagName.startsWith('DS-');\n if (isDsControl && 'inputId' in control) control.inputId = this.controlId;\n else this.updateControlAttribute(control, 'id', this.controlId);\n\n const authored = this.authoredAria.get(control) ?? { labelledby: [], describedby: [] };\n const labelledby = uniqueTokens(authored.labelledby, [this.labelId]).join(' ');\n const describedby = uniqueTokens(\n authored.describedby,\n this.renderedDescription ? [this.descriptionId] : [],\n this.renderedError ? [this.errorId] : []\n ).join(' ');\n\n this.updateControlAttribute(control, 'aria-labelledby', labelledby);\n this.updateControlAttribute(control, 'aria-describedby', describedby || undefined);\n this.updateControlAttribute(control, 'aria-invalid', this.error ? 'true' : undefined);\n\n if (isDsControl && 'error' in control && control.error !== this.error)\n control.error = this.error;\n\n const value = this.readValue(control);\n this.filled = value.length > 0;\n this.dirty = value !== this.initialValue;\n this.controlDisabled = Boolean(\n control.disabled || control.isInactive || control.hasAttribute('disabled')\n );\n this.controlRequired = Boolean(control.required || control.hasAttribute('required'));\n };\n\n private handleLabelClick = (event: MouseEvent) => {\n if (!this.control?.tagName.startsWith('DS-')) return;\n event.preventDefault();\n this.control.setFocus?.();\n };\n\n private handleFocusIn = () => {\n this.focused = true;\n };\n\n private handleFocusOut = (event: FocusEvent) => {\n if (event.relatedTarget instanceof Node && this.el.contains(event.relatedTarget)) return;\n this.focused = false;\n this.touched = true;\n };\n\n private handleValueChange = () => {\n this.syncControl();\n };\n\n render() {\n return (\n <Host\n data-focused={this.focused ? '' : undefined}\n data-filled={this.filled ? '' : undefined}\n data-dirty={this.dirty ? '' : undefined}\n data-touched={this.touched ? '' : undefined}\n data-invalid={this.error ? '' : undefined}\n data-disabled={this.controlDisabled ? '' : undefined}\n data-required={this.controlRequired ? '' : undefined}\n onFocusin={this.handleFocusIn}\n onFocusout={this.handleFocusOut}\n onInput={this.handleValueChange}\n onChange={this.handleValueChange}\n onDsChange={this.handleValueChange}\n >\n <div class=\"field ds-field-stack\">\n <ds-text\n class=\"field__label\"\n as=\"label\"\n variant=\"text-body-small\"\n color=\"primary\"\n emphasis\n for={this.controlId}\n textId={this.labelId}\n onClick={this.handleLabelClick}\n >\n {this.label}\n </ds-text>\n <div class=\"field__control\" ref={el => (this.controlContainer = el)}>\n <slot onSlotchange={this.syncControl} />\n </div>\n {this.renderedDescription && (\n <ds-text\n class=\"field__description\"\n as=\"div\"\n variant=\"text-body-small\"\n color=\"secondary\"\n textId={this.descriptionId}\n >\n {this.description}\n </ds-text>\n )}\n {this.renderedError && (\n <ds-text\n class=\"field__error\"\n as=\"div\"\n variant=\"text-body-small\"\n color=\"negative\"\n textId={this.errorId}\n role=\"alert\"\n >\n {this.errorMessage}\n </ds-text>\n )}\n </div>\n </Host>\n );\n }\n}\n",
|
|
225
225
|
"type": "registry:ui"
|
|
226
226
|
}
|
|
227
227
|
]
|
|
@@ -10022,7 +10022,7 @@
|
|
|
10022
10022
|
{
|
|
10023
10023
|
"name": "table-group",
|
|
10024
10024
|
"title": "TableGroup",
|
|
10025
|
-
"description": "Two-panel toolbar control for choosing one table grouping data point and the
|
|
10025
|
+
"description": "Two-panel toolbar control for choosing one table grouping data point and the order of its group sections.",
|
|
10026
10026
|
"type": "registry:ui",
|
|
10027
10027
|
"meta": {
|
|
10028
10028
|
"library": "@ds-mo/ui",
|
|
@@ -10033,7 +10033,7 @@
|
|
|
10033
10033
|
"intent": {
|
|
10034
10034
|
"audience": "general",
|
|
10035
10035
|
"status": "stable",
|
|
10036
|
-
"summary": "Two-panel toolbar control for choosing one table grouping data point and the
|
|
10036
|
+
"summary": "Two-panel toolbar control for choosing one table grouping data point and the order of its group sections.",
|
|
10037
10037
|
"useWhen": [
|
|
10038
10038
|
"A table toolbar needs explicit control of one grouping level and its section order.",
|
|
10039
10039
|
"Grouping data-point labels differ from compact table-header labels."
|
|
@@ -10064,8 +10064,8 @@
|
|
|
10064
10064
|
"The right pane remains present before a group is active as one complete empty state without the Order heading, and explains that a group must be selected."
|
|
10065
10065
|
],
|
|
10066
10066
|
"states": [
|
|
10067
|
-
"options and grouping are controlled. dsGroupChange reports a complete TableGroupingState and dsClear requests null grouping without mutating either input.",
|
|
10068
|
-
"Selecting a new data point starts its order
|
|
10067
|
+
"options and grouping are controlled. A data option may supply product-owned orderOptions; otherwise Order defaults to Ascending and Descending. dsGroupChange reports a complete TableGroupingState and dsClear requests null grouping without mutating either input.",
|
|
10068
|
+
"Selecting a new data point starts at its first custom order option, or ascending when it has no custom order options. Re-selecting the active data point preserves its complete order state.",
|
|
10069
10069
|
"Selecting a data point or direction applies immediately and leaves the dialog open so the other pane can be changed."
|
|
10070
10070
|
],
|
|
10071
10071
|
"responsiveBehavior": [
|
|
@@ -219,7 +219,7 @@
|
|
|
219
219
|
"files": [
|
|
220
220
|
{
|
|
221
221
|
"path": "src/wc/components/Score/Score.css",
|
|
222
|
-
"content": "@import '../../utils/control-parts.css';\n@import '../../utils/forced-colors.css';\n\n:host {\n display: inline-flex;\n align-items: center;\n box-sizing: border-box;\n min-width: 0;\n --_score-badge-inline-size: var(--dimension-size-500);\n --_score-badge-block-size: var(--dimension-size-400);\n /* Matches the text skeleton’s 75% bar so the fill inset is even on all sides. */\n --_score-skeleton-inset: calc(var(--_score-badge-block-size) / 8);\n}\n\n:host(.score--sm) {\n --_score-badge-inline-size: calc(var(--dimension-size-400) - var(--dimension-space-050));\n --_score-badge-block-size: var(--dimension-size-300);\n}\n\n:host(.score--md) {\n --_score-badge-inline-size: var(--dimension-size-500);\n --_score-badge-block-size: var(--dimension-size-400);\n}\n\n:host(.score--lg) {\n --_score-badge-inline-size: calc(var(--dimension-size-600) + var(--dimension-space-100));\n --_score-badge-block-size: var(--dimension-size-500);\n}\n\n.score__badge {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n inline-size: var(--_score-badge-inline-size);\n block-size: var(--_score-badge-block-size);\n overflow: hidden;\n border-radius: var(--dimension-radius-025);\n background: var(--color-background-faint-neutral);\n color: var(--color-foreground-bold-neutral);\n -webkit-user-select: none;\n user-select: none;\n}\n\n.score__badge--fair {\n background: var(--color-safety-score-background-fair);\n color: var(--color-safety-score-foreground-on-fair);\n}\n\n.score__badge--good {\n background: var(--color-safety-score-background-good);\n color: var(--color-foreground-
|
|
222
|
+
"content": "@import '../../utils/control-parts.css';\n@import '../../utils/forced-colors.css';\n\n:host {\n display: inline-flex;\n align-items: center;\n box-sizing: border-box;\n min-width: 0;\n --_score-badge-inline-size: var(--dimension-size-500);\n --_score-badge-block-size: var(--dimension-size-400);\n /* Matches the text skeleton’s 75% bar so the fill inset is even on all sides. */\n --_score-skeleton-inset: calc(var(--_score-badge-block-size) / 8);\n}\n\n:host(.score--sm) {\n --_score-badge-inline-size: calc(var(--dimension-size-400) - var(--dimension-space-050));\n --_score-badge-block-size: var(--dimension-size-300);\n}\n\n:host(.score--md) {\n --_score-badge-inline-size: var(--dimension-size-500);\n --_score-badge-block-size: var(--dimension-size-400);\n}\n\n:host(.score--lg) {\n --_score-badge-inline-size: calc(var(--dimension-size-600) + var(--dimension-space-100));\n --_score-badge-block-size: var(--dimension-size-500);\n}\n\n.score__badge {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n inline-size: var(--_score-badge-inline-size);\n block-size: var(--_score-badge-block-size);\n overflow: hidden;\n border-radius: var(--dimension-radius-025);\n background: var(--color-background-faint-neutral);\n color: var(--color-foreground-bold-neutral);\n -webkit-user-select: none;\n user-select: none;\n}\n\n.score__badge--fair {\n background: var(--color-safety-score-background-fair);\n color: var(--color-safety-score-foreground-on-fair);\n}\n\n.score__badge--good {\n background: var(--color-safety-score-background-good);\n color: var(--color-safety-score-foreground-on-good);\n}\n\n.score__badge--excellent {\n background: var(--color-safety-score-background-excellent);\n color: var(--color-safety-score-foreground-on-excellent);\n}\n\n.score__value,\n.score__badge ds-skeleton {\n flex: 0 0 auto;\n}\n\n.score__badge--loading {\n padding-inline: var(--_score-skeleton-inset);\n}\n\n.score__badge--loading .score__value {\n flex: 1 1 auto;\n inline-size: 100%;\n block-size: 100%;\n max-inline-size: 100%;\n max-block-size: 100%;\n min-inline-size: 0;\n}\n\n@media (forced-colors: active) {\n .score__badge {\n border: var(--dimension-stroke-width-012) solid var(--ds-forced-color-content);\n background: var(--ds-forced-color-surface);\n color: var(--ds-forced-color-content);\n }\n}\n",
|
|
223
223
|
"type": "registry:ui"
|
|
224
224
|
},
|
|
225
225
|
{
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
3
|
"name": "table-group",
|
|
4
4
|
"title": "TableGroup",
|
|
5
|
-
"description": "Two-panel toolbar control for choosing one table grouping data point and the
|
|
5
|
+
"description": "Two-panel toolbar control for choosing one table grouping data point and the order of its group sections.",
|
|
6
6
|
"type": "registry:ui",
|
|
7
7
|
"meta": {
|
|
8
8
|
"library": "@ds-mo/ui",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"intent": {
|
|
14
14
|
"audience": "general",
|
|
15
15
|
"status": "stable",
|
|
16
|
-
"summary": "Two-panel toolbar control for choosing one table grouping data point and the
|
|
16
|
+
"summary": "Two-panel toolbar control for choosing one table grouping data point and the order of its group sections.",
|
|
17
17
|
"useWhen": [
|
|
18
18
|
"A table toolbar needs explicit control of one grouping level and its section order.",
|
|
19
19
|
"Grouping data-point labels differ from compact table-header labels."
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"The right pane remains present before a group is active as one complete empty state without the Order heading, and explains that a group must be selected."
|
|
45
45
|
],
|
|
46
46
|
"states": [
|
|
47
|
-
"options and grouping are controlled. dsGroupChange reports a complete TableGroupingState and dsClear requests null grouping without mutating either input.",
|
|
48
|
-
"Selecting a new data point starts its order
|
|
47
|
+
"options and grouping are controlled. A data option may supply product-owned orderOptions; otherwise Order defaults to Ascending and Descending. dsGroupChange reports a complete TableGroupingState and dsClear requests null grouping without mutating either input.",
|
|
48
|
+
"Selecting a new data point starts at its first custom order option, or ascending when it has no custom order options. Re-selecting the active data point preserves its complete order state.",
|
|
49
49
|
"Selecting a data point or direction applies immediately and leaves the dialog open so the other pane can be changed."
|
|
50
50
|
],
|
|
51
51
|
"responsiveBehavior": [
|
|
@@ -294,7 +294,7 @@
|
|
|
294
294
|
},
|
|
295
295
|
{
|
|
296
296
|
"path": "src/wc/components/TableGroup/TableGroup.tsx",
|
|
297
|
-
"content": "import {\n Component,\n Element,\n Event,\n EventEmitter,\n h,\n Host,\n Listen,\n Prop,\n State,\n Watch,\n} from '@stencil/core';\nimport {\n resolveChoicePopupAlignOffset,\n resolveCssLengthPx,\n resolveMotionTimeMs,\n TOKEN_CSS_LENGTHS,\n TOKEN_DEFAULTS,\n} from '../../utils';\nimport { AnchoredPositionController } from '../../utils/anchored-position-controller';\nimport { AnchoredOverlayInteractionController } from '../../utils/anchored-overlay-interaction-controller';\nimport { resolveAnchoredOverlayBoundaryRect } from '../../utils/anchored-overlay-boundary';\nimport { ChoiceListSection, ChoiceOptionRow } from '../../utils/choice-list-parts';\nimport type { TableGroupingState, TableSortDirection } from '../Table/table-types';\n\nexport interface TableGroupOption {\n label: string;\n value: string;\n description?: string;\n isInactive?: boolean;\n}\n\nlet tableGroupSeq = 0;\n\n@Component({\n tag: 'ds-table-group',\n styleUrl: 'TableGroup.css',\n scoped: true,\n})\nexport class TableGroup {\n @Element() private el!: HTMLElement;\n\n /** Product-owned data points that may group the table. */\n @Prop() options: TableGroupOption[] = [];\n /** Controlled grouping field and the order of its group sections. */\n @Prop() grouping: TableGroupingState | null = null;\n /** Accessible name for the trigger and non-modal dialog. */\n @Prop({ attribute: 'aria-label' }) ariaLabel: string | null = null;\n /** Controlled popup visibility. */\n @Prop({ mutable: true }) open = false;\n /** Empty message kept in the order pane until a grouping data point is selected. */\n @Prop() emptyMessage = 'Select a group to choose its order.';\n /** Clear action label. */\n @Prop() clearLabel = 'Clear';\n\n /** Requests replacement of the complete controlled grouping state. */\n @Event() dsGroupChange!: EventEmitter<TableGroupingState>;\n /** Requests removal of the controlled grouping state. */\n @Event() dsClear!: EventEmitter<void>;\n /** Reports controlled popup visibility changes. */\n @Event() dsOpenChange!: EventEmitter<boolean>;\n\n @State() private shouldRender = false;\n @State() private closing = false;\n @State() private positionReady = false;\n @State() private pos = { x: 0, y: 0 };\n @State() private focusRingVisible = false;\n\n private readonly componentId = `ds-table-group-${++tableGroupSeq}`;\n private readonly triggerId = `${this.componentId}-trigger`;\n private readonly popupId = `${this.componentId}-popup`;\n private triggerElement: HTMLElement | null = null;\n private pendingInitialFocusVisible = false;\n private closeTimer: ReturnType<typeof setTimeout> | null = null;\n\n private readonly position = new AnchoredPositionController({\n getAnchor: () => this.triggerElement,\n getPopup: () => this.el.querySelector<HTMLElement>('.table-group-popup'),\n getOwnerDocument: () => this.el.ownerDocument,\n measure: (anchor, popup) => {\n if (!this.open) return null;\n const sectionInsetPx = resolveCssLengthPx(TOKEN_DEFAULTS.space050, TOKEN_DEFAULTS.space050);\n return {\n anchorRect: anchor.getBoundingClientRect(),\n popupWidth: popup.offsetWidth || this.popupFallbackWidth,\n popupHeight: popup.offsetHeight || this.popupFallbackHeight,\n side: 'bottom',\n align: 'end',\n sideOffsetPx: resolveCssLengthPx(TOKEN_CSS_LENGTHS.space050, TOKEN_DEFAULTS.space050),\n alignOffsetPx: resolveChoicePopupAlignOffset({\n align: 'end',\n alignOffsetPx: 0,\n sectionInsetPx,\n }),\n viewportPadPx: resolveCssLengthPx(TOKEN_DEFAULTS.space050, TOKEN_DEFAULTS.space050),\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n collisionRect: resolveAnchoredOverlayBoundaryRect(anchor),\n };\n },\n apply: ({ x, y }) => {\n this.pos = { x, y };\n },\n onReady: () => {\n this.positionReady = true;\n },\n liveUpdate: 'double-frame',\n observeResize: true,\n topLayer: true,\n });\n\n private readonly interaction = new AnchoredOverlayInteractionController({\n getAnchor: () => this.triggerElement,\n getPopup: () => this.el.querySelector<HTMLElement>('.table-group-popup'),\n getOwnerDocument: () => this.el.ownerDocument,\n onOutsideActivation: () => this.close(),\n });\n\n componentDidLoad() {\n if (this.open) this.onOpenChange(true);\n }\n\n disconnectedCallback() {\n this.position.unobserve();\n this.interaction.disconnect();\n if (this.closeTimer) clearTimeout(this.closeTimer);\n }\n\n @Watch('open')\n onOpenChange(isOpen: boolean) {\n if (isOpen) {\n this.teardown();\n this.shouldRender = true;\n this.closing = false;\n this.positionReady = false;\n this.focusRingVisible = this.pendingInitialFocusVisible;\n this.interaction.connect();\n this.position.observe();\n this.position.schedule(() => this.focusInitialDataPoint());\n return;\n }\n if (!this.shouldRender) return;\n this.position.cancel();\n this.closing = true;\n this.interaction.disconnect();\n this.position.unobserve();\n const duration = resolveMotionTimeMs(\n TOKEN_DEFAULTS.motionShort2,\n TOKEN_DEFAULTS.animationDurationShort3\n );\n if (duration <= 0) this.finishClose();\n else this.closeTimer = setTimeout(() => this.finishClose(), duration);\n }\n\n @Listen('keydown')\n handleKeyDown(event: KeyboardEvent) {\n if (!this.shouldRender || this.closing) return;\n if (event.key === 'Escape') {\n event.preventDefault();\n this.close();\n return;\n }\n if (event.key !== 'Tab' || !this.interaction.tabLeavesPopup(event)) return;\n event.preventDefault();\n this.close(false);\n this.interaction.moveFocusAfterTab(event.shiftKey);\n }\n\n private get popupFallbackWidth(): number {\n return resolveCssLengthPx(TOKEN_DEFAULTS.menuWidthLg, TOKEN_DEFAULTS.menuWidthLg);\n }\n\n private get popupFallbackHeight(): number {\n return resolveCssLengthPx(TOKEN_DEFAULTS.menuFallbackHeight, TOKEN_DEFAULTS.menuFallbackHeight);\n }\n\n private teardown() {\n this.position.unobserve();\n this.interaction.disconnect();\n if (this.closeTimer) {\n clearTimeout(this.closeTimer);\n this.closeTimer = null;\n }\n }\n\n private toggle(fromKeyboard = false) {\n if (this.open) {\n this.close();\n return;\n }\n this.pendingInitialFocusVisible = fromKeyboard;\n this.open = true;\n this.dsOpenChange.emit(true);\n this.onOpenChange(true);\n }\n\n private close(restoreFocus = true) {\n if (restoreFocus) this.interaction.focusAnchor();\n this.open = false;\n this.dsOpenChange.emit(false);\n this.onOpenChange(false);\n }\n\n private finishClose() {\n const popup = this.el.querySelector<HTMLElement>('.table-group-popup');\n if (popup?.matches(':popover-open')) popup.hidePopover();\n this.shouldRender = false;\n this.closing = false;\n this.closeTimer = null;\n }\n\n private focusInitialDataPoint() {\n requestAnimationFrame(() => {\n const selected = this.grouping\n ? this.el.querySelector<HTMLElement>(\n `[data-group-value=\"${CSS.escape(this.grouping.columnId)}\"] [role=\"option\"]`\n )\n : null;\n const initial =\n selected ??\n this.el.querySelector<HTMLElement>(\n '[data-group-value] [role=\"option\"]:not([aria-disabled=\"true\"])'\n );\n initial?.focus();\n this.pendingInitialFocusVisible = false;\n });\n }\n\n private selectData(option: TableGroupOption) {\n if (option.isInactive) return;\n this.dsGroupChange.emit({\n columnId: option.value,\n direction: this.grouping?.columnId === option.value ? this.grouping.direction : 'asc',\n });\n }\n\n private selectDirection(direction: TableSortDirection) {\n if (!this.grouping || this.grouping.direction === direction) return;\n this.dsGroupChange.emit({ ...this.grouping, direction });\n }\n\n private moveFocus(\n event: KeyboardEvent,\n selector: string,\n currentIndex: number,\n oppositeSelector?: string\n ) {\n if (oppositeSelector && (event.key === 'ArrowLeft' || event.key === 'ArrowRight')) {\n event.preventDefault();\n this.focusRingVisible = true;\n this.el.querySelector<HTMLElement>(oppositeSelector)?.focus();\n return;\n }\n if (!['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(event.key)) return;\n event.preventDefault();\n const items = Array.from(this.el.querySelectorAll<HTMLElement>(selector)).filter(\n item => item.getAttribute('aria-disabled') !== 'true'\n );\n if (!items.length) return;\n let next: number;\n if (event.key === 'Home') next = 0;\n else if (event.key === 'End') next = items.length - 1;\n else next = (currentIndex + (event.key === 'ArrowDown' ? 1 : -1) + items.length) % items.length;\n this.focusRingVisible = true;\n items[next]?.focus();\n }\n\n private renderDataOption(option: TableGroupOption, index: number) {\n const selected = option.value === this.grouping?.columnId;\n return (\n <ChoiceOptionRow\n id={`${this.componentId}-data-${index}`}\n option={{ ...option }}\n selected={selected}\n active={selected}\n focusRingVisible={this.focusRingVisible}\n usesSubtext={Boolean(option.description)}\n tabIndex={selected || (!this.grouping && index === 0) ? 0 : -1}\n onHover={() => {\n this.focusRingVisible = false;\n }}\n onSelect={() => this.selectData(option)}\n onKeyDown={(event: KeyboardEvent) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.selectData(option);\n return;\n }\n this.moveFocus(\n event,\n '[data-group-value] [role=\"option\"]',\n this.options\n .filter(candidate => !candidate.isInactive)\n .findIndex(candidate => candidate.value === option.value),\n this.grouping\n ? `[data-group-direction=\"${this.grouping.direction}\"] [role=\"option\"]`\n : undefined\n );\n }}\n />\n );\n }\n\n private renderDirection(direction: TableSortDirection, label: string, index: number) {\n const selected = direction === this.grouping?.direction;\n return (\n <ChoiceOptionRow\n id={`${this.componentId}-direction-${direction}`}\n option={{ label, value: direction }}\n selected={selected}\n active={selected}\n focusRingVisible={this.focusRingVisible}\n usesSubtext={false}\n tabIndex={selected ? 0 : -1}\n onHover={() => {\n this.focusRingVisible = false;\n }}\n onSelect={() => this.selectDirection(direction)}\n onKeyDown={(event: KeyboardEvent) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.selectDirection(direction);\n return;\n }\n this.moveFocus(\n event,\n '[data-group-direction] [role=\"option\"]',\n index,\n `[data-group-value=\"${CSS.escape(this.grouping?.columnId ?? '')}\"] [role=\"option\"]`\n );\n }}\n />\n );\n }\n\n render() {\n const name = this.ariaLabel?.trim() || 'Group table';\n const popupStyle: Record<string, string> = {\n position: 'fixed',\n left: '0',\n top: '0',\n transform: `translate(${Math.round(this.pos.x)}px, ${Math.round(this.pos.y)}px)`,\n zIndex: '9998',\n visibility: this.positionReady ? 'visible' : 'hidden',\n };\n\n return (\n <Host hidden={this.options.length === 0 ? true : undefined}>\n {this.options.length ? (\n <ds-button-unfilled\n ref={element => {\n this.triggerElement = (element as HTMLElement) ?? null;\n }}\n id={this.triggerId}\n variant=\"icon-label\"\n size=\"md\"\n icon=\"SectionList\"\n label=\"Group\"\n labelEmphasis={false}\n pressScale={false}\n aria-label={name}\n hasMenu={true}\n collapseLabel={true}\n expanded={this.open}\n controls={this.popupId}\n onDsClick={(event: CustomEvent<MouseEvent>) => this.toggle(event.detail.detail === 0)}\n />\n ) : null}\n\n {this.shouldRender ? (\n <div\n id={this.popupId}\n popover=\"manual\"\n class={{\n 'table-group-popup': true,\n 'ds-choice-popup': true,\n 'ds-choice-popup--closing': this.closing,\n }}\n style={popupStyle}\n role=\"dialog\"\n aria-label={name}\n >\n <div class=\"table-group__body\">\n <div class=\"table-group__data-pane\">\n <ChoiceListSection\n heading=\"Data\"\n ariaLabel=\"Group data\"\n className=\"table-group__list\"\n >\n {this.options.map((option, index) => (\n <div data-group-value={option.value}>\n {this.renderDataOption(option, index)}\n </div>\n ))}\n </ChoiceListSection>\n <div\n class=\"table-group__footer ds-choice-footer\"\n aria-hidden={!this.grouping ? 'true' : undefined}\n >\n <div class=\"ds-choice-footer__content ds-control--md\">\n {this.grouping ? (\n <button\n class=\"ds-choice-footer__clear ds-text-action ds-focus-ring\"\n type=\"button\"\n onClick={() => this.dsClear.emit()}\n >\n <ds-text as=\"span\" variant=\"text-body-medium\" color=\"inherit\">\n {this.clearLabel}\n </ds-text>\n </button>\n ) : null}\n </div>\n </div>\n </div>\n\n <div class=\"table-group__order-pane\">\n {this.grouping ? (\n <ChoiceListSection\n heading=\"Order\"\n ariaLabel=\"Group order\"\n className=\"table-group__list\"\n >\n <div data-group-direction=\"asc\">\n {this.renderDirection('asc', 'Ascending', 0)}\n </div>\n <div data-group-direction=\"desc\">\n {this.renderDirection('desc', 'Descending', 1)}\n </div>\n </ChoiceListSection>\n ) : (\n <div class=\"table-group__empty ds-choice-empty ds-empty-region\">\n <ds-empty-state body={this.emptyMessage} />\n </div>\n )}\n </div>\n </div>\n </div>\n ) : null}\n </Host>\n );\n }\n}\n",
|
|
297
|
+
"content": "import {\n Component,\n Element,\n Event,\n EventEmitter,\n h,\n Host,\n Listen,\n Prop,\n State,\n Watch,\n} from '@stencil/core';\nimport {\n resolveChoicePopupAlignOffset,\n resolveCssLengthPx,\n resolveMotionTimeMs,\n TOKEN_CSS_LENGTHS,\n TOKEN_DEFAULTS,\n} from '../../utils';\nimport { AnchoredPositionController } from '../../utils/anchored-position-controller';\nimport { AnchoredOverlayInteractionController } from '../../utils/anchored-overlay-interaction-controller';\nimport { resolveAnchoredOverlayBoundaryRect } from '../../utils/anchored-overlay-boundary';\nimport { ChoiceListSection, ChoiceOptionRow } from '../../utils/choice-list-parts';\nimport type { TableGroupingState, TableSortDirection } from '../Table/table-types';\n\nexport interface TableGroupOrderOption {\n label: string;\n direction: TableSortDirection;\n /** Optional application-owned data point used to order the group sections. */\n orderBy?: string;\n}\n\nexport interface TableGroupOption {\n label: string;\n value: string;\n description?: string;\n isInactive?: boolean;\n /** Product-owned order choices for this grouping data point. */\n orderOptions?: TableGroupOrderOption[];\n}\n\nconst DEFAULT_ORDER_OPTIONS: TableGroupOrderOption[] = [\n { label: 'Ascending', direction: 'asc' },\n { label: 'Descending', direction: 'desc' },\n];\n\nlet tableGroupSeq = 0;\n\n@Component({\n tag: 'ds-table-group',\n styleUrl: 'TableGroup.css',\n scoped: true,\n})\nexport class TableGroup {\n @Element() private el!: HTMLElement;\n\n /** Product-owned data points that may group the table. */\n @Prop() options: TableGroupOption[] = [];\n /** Controlled grouping field and the order of its group sections. */\n @Prop() grouping: TableGroupingState | null = null;\n /** Accessible name for the trigger and non-modal dialog. */\n @Prop({ attribute: 'aria-label' }) ariaLabel: string | null = null;\n /** Controlled popup visibility. */\n @Prop({ mutable: true }) open = false;\n /** Empty message kept in the order pane until a grouping data point is selected. */\n @Prop() emptyMessage = 'Select a group to choose its order.';\n /** Clear action label. */\n @Prop() clearLabel = 'Clear';\n\n /** Requests replacement of the complete controlled grouping state. */\n @Event() dsGroupChange!: EventEmitter<TableGroupingState>;\n /** Requests removal of the controlled grouping state. */\n @Event() dsClear!: EventEmitter<void>;\n /** Reports controlled popup visibility changes. */\n @Event() dsOpenChange!: EventEmitter<boolean>;\n\n @State() private shouldRender = false;\n @State() private closing = false;\n @State() private positionReady = false;\n @State() private pos = { x: 0, y: 0 };\n @State() private focusRingVisible = false;\n\n private readonly componentId = `ds-table-group-${++tableGroupSeq}`;\n private readonly triggerId = `${this.componentId}-trigger`;\n private readonly popupId = `${this.componentId}-popup`;\n private triggerElement: HTMLElement | null = null;\n private pendingInitialFocusVisible = false;\n private closeTimer: ReturnType<typeof setTimeout> | null = null;\n\n private readonly position = new AnchoredPositionController({\n getAnchor: () => this.triggerElement,\n getPopup: () => this.el.querySelector<HTMLElement>('.table-group-popup'),\n getOwnerDocument: () => this.el.ownerDocument,\n measure: (anchor, popup) => {\n if (!this.open) return null;\n const sectionInsetPx = resolveCssLengthPx(TOKEN_DEFAULTS.space050, TOKEN_DEFAULTS.space050);\n return {\n anchorRect: anchor.getBoundingClientRect(),\n popupWidth: popup.offsetWidth || this.popupFallbackWidth,\n popupHeight: popup.offsetHeight || this.popupFallbackHeight,\n side: 'bottom',\n align: 'end',\n sideOffsetPx: resolveCssLengthPx(TOKEN_CSS_LENGTHS.space050, TOKEN_DEFAULTS.space050),\n alignOffsetPx: resolveChoicePopupAlignOffset({\n align: 'end',\n alignOffsetPx: 0,\n sectionInsetPx,\n }),\n viewportPadPx: resolveCssLengthPx(TOKEN_DEFAULTS.space050, TOKEN_DEFAULTS.space050),\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n collisionRect: resolveAnchoredOverlayBoundaryRect(anchor),\n };\n },\n apply: ({ x, y }) => {\n this.pos = { x, y };\n },\n onReady: () => {\n this.positionReady = true;\n },\n liveUpdate: 'double-frame',\n observeResize: true,\n topLayer: true,\n });\n\n private readonly interaction = new AnchoredOverlayInteractionController({\n getAnchor: () => this.triggerElement,\n getPopup: () => this.el.querySelector<HTMLElement>('.table-group-popup'),\n getOwnerDocument: () => this.el.ownerDocument,\n onOutsideActivation: () => this.close(),\n });\n\n componentDidLoad() {\n if (this.open) this.onOpenChange(true);\n }\n\n disconnectedCallback() {\n this.position.unobserve();\n this.interaction.disconnect();\n if (this.closeTimer) clearTimeout(this.closeTimer);\n }\n\n @Watch('open')\n onOpenChange(isOpen: boolean) {\n if (isOpen) {\n this.teardown();\n this.shouldRender = true;\n this.closing = false;\n this.positionReady = false;\n this.focusRingVisible = this.pendingInitialFocusVisible;\n this.interaction.connect();\n this.position.observe();\n this.position.schedule(() => this.focusInitialDataPoint());\n return;\n }\n if (!this.shouldRender) return;\n this.position.cancel();\n this.closing = true;\n this.interaction.disconnect();\n this.position.unobserve();\n const duration = resolveMotionTimeMs(\n TOKEN_DEFAULTS.motionShort2,\n TOKEN_DEFAULTS.animationDurationShort3\n );\n if (duration <= 0) this.finishClose();\n else this.closeTimer = setTimeout(() => this.finishClose(), duration);\n }\n\n @Listen('keydown')\n handleKeyDown(event: KeyboardEvent) {\n if (!this.shouldRender || this.closing) return;\n if (event.key === 'Escape') {\n event.preventDefault();\n this.close();\n return;\n }\n if (event.key !== 'Tab' || !this.interaction.tabLeavesPopup(event)) return;\n event.preventDefault();\n this.close(false);\n this.interaction.moveFocusAfterTab(event.shiftKey);\n }\n\n private get popupFallbackWidth(): number {\n return resolveCssLengthPx(TOKEN_DEFAULTS.menuWidthLg, TOKEN_DEFAULTS.menuWidthLg);\n }\n\n private get popupFallbackHeight(): number {\n return resolveCssLengthPx(TOKEN_DEFAULTS.menuFallbackHeight, TOKEN_DEFAULTS.menuFallbackHeight);\n }\n\n private teardown() {\n this.position.unobserve();\n this.interaction.disconnect();\n if (this.closeTimer) {\n clearTimeout(this.closeTimer);\n this.closeTimer = null;\n }\n }\n\n private toggle(fromKeyboard = false) {\n if (this.open) {\n this.close();\n return;\n }\n this.pendingInitialFocusVisible = fromKeyboard;\n this.open = true;\n this.dsOpenChange.emit(true);\n this.onOpenChange(true);\n }\n\n private close(restoreFocus = true) {\n if (restoreFocus) this.interaction.focusAnchor();\n this.open = false;\n this.dsOpenChange.emit(false);\n this.onOpenChange(false);\n }\n\n private finishClose() {\n const popup = this.el.querySelector<HTMLElement>('.table-group-popup');\n if (popup?.matches(':popover-open')) popup.hidePopover();\n this.shouldRender = false;\n this.closing = false;\n this.closeTimer = null;\n }\n\n private focusInitialDataPoint() {\n requestAnimationFrame(() => {\n const selected = this.grouping\n ? this.el.querySelector<HTMLElement>(\n `[data-group-value=\"${CSS.escape(this.grouping.columnId)}\"] [role=\"option\"]`\n )\n : null;\n const initial =\n selected ??\n this.el.querySelector<HTMLElement>(\n '[data-group-value] [role=\"option\"]:not([aria-disabled=\"true\"])'\n );\n initial?.focus();\n this.pendingInitialFocusVisible = false;\n });\n }\n\n private selectData(option: TableGroupOption) {\n if (option.isInactive) return;\n if (this.grouping?.columnId === option.value) {\n this.dsGroupChange.emit({ ...this.grouping });\n return;\n }\n const initialOrder = option.orderOptions?.[0];\n this.dsGroupChange.emit({\n columnId: option.value,\n direction: initialOrder?.direction ?? 'asc',\n ...(initialOrder?.orderBy ? { orderBy: initialOrder.orderBy } : {}),\n });\n }\n\n private get activeOrderOptions(): TableGroupOrderOption[] {\n const configured = this.options.find(\n option => option.value === this.grouping?.columnId\n )?.orderOptions;\n return configured?.length ? configured : DEFAULT_ORDER_OPTIONS;\n }\n\n private get selectedOrderIndex(): number {\n if (!this.grouping) return -1;\n const exact = this.activeOrderOptions.findIndex(\n option =>\n option.direction === this.grouping?.direction && option.orderBy === this.grouping?.orderBy\n );\n if (exact >= 0) return exact;\n if (this.grouping.orderBy === undefined) {\n return this.activeOrderOptions.findIndex(\n option => option.direction === this.grouping?.direction\n );\n }\n return -1;\n }\n\n private selectOrder(option: TableGroupOrderOption, index: number) {\n if (!this.grouping || this.selectedOrderIndex === index) return;\n const grouping: TableGroupingState = {\n columnId: this.grouping.columnId,\n direction: option.direction,\n };\n if (option.orderBy) grouping.orderBy = option.orderBy;\n this.dsGroupChange.emit(grouping);\n }\n\n private moveFocus(\n event: KeyboardEvent,\n selector: string,\n currentIndex: number,\n oppositeSelector?: string\n ) {\n if (oppositeSelector && (event.key === 'ArrowLeft' || event.key === 'ArrowRight')) {\n event.preventDefault();\n this.focusRingVisible = true;\n this.el.querySelector<HTMLElement>(oppositeSelector)?.focus();\n return;\n }\n if (!['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(event.key)) return;\n event.preventDefault();\n const items = Array.from(this.el.querySelectorAll<HTMLElement>(selector)).filter(\n item => item.getAttribute('aria-disabled') !== 'true'\n );\n if (!items.length) return;\n let next: number;\n if (event.key === 'Home') next = 0;\n else if (event.key === 'End') next = items.length - 1;\n else next = (currentIndex + (event.key === 'ArrowDown' ? 1 : -1) + items.length) % items.length;\n this.focusRingVisible = true;\n items[next]?.focus();\n }\n\n private renderDataOption(option: TableGroupOption, index: number) {\n const selected = option.value === this.grouping?.columnId;\n return (\n <ChoiceOptionRow\n id={`${this.componentId}-data-${index}`}\n option={{ ...option }}\n selected={selected}\n active={selected}\n focusRingVisible={this.focusRingVisible}\n usesSubtext={Boolean(option.description)}\n tabIndex={selected || (!this.grouping && index === 0) ? 0 : -1}\n onHover={() => {\n this.focusRingVisible = false;\n }}\n onSelect={() => this.selectData(option)}\n onKeyDown={(event: KeyboardEvent) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.selectData(option);\n return;\n }\n this.moveFocus(\n event,\n '[data-group-value] [role=\"option\"]',\n this.options\n .filter(candidate => !candidate.isInactive)\n .findIndex(candidate => candidate.value === option.value),\n this.grouping\n ? `[data-group-order-index=\"${this.selectedOrderIndex}\"] [role=\"option\"]`\n : undefined\n );\n }}\n />\n );\n }\n\n private renderOrder(option: TableGroupOrderOption, index: number) {\n const selected = index === this.selectedOrderIndex;\n return (\n <ChoiceOptionRow\n id={`${this.componentId}-order-${index}`}\n option={{ label: option.label, value: String(index) }}\n selected={selected}\n active={selected}\n focusRingVisible={this.focusRingVisible}\n usesSubtext={false}\n tabIndex={selected ? 0 : -1}\n onHover={() => {\n this.focusRingVisible = false;\n }}\n onSelect={() => this.selectOrder(option, index)}\n onKeyDown={(event: KeyboardEvent) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.selectOrder(option, index);\n return;\n }\n this.moveFocus(\n event,\n '[data-group-order-index] [role=\"option\"]',\n index,\n `[data-group-value=\"${CSS.escape(this.grouping?.columnId ?? '')}\"] [role=\"option\"]`\n );\n }}\n />\n );\n }\n\n render() {\n const name = this.ariaLabel?.trim() || 'Group table';\n const popupStyle: Record<string, string> = {\n position: 'fixed',\n left: '0',\n top: '0',\n transform: `translate(${Math.round(this.pos.x)}px, ${Math.round(this.pos.y)}px)`,\n zIndex: '9998',\n visibility: this.positionReady ? 'visible' : 'hidden',\n };\n\n return (\n <Host hidden={this.options.length === 0 ? true : undefined}>\n {this.options.length ? (\n <ds-button-unfilled\n ref={element => {\n this.triggerElement = (element as HTMLElement) ?? null;\n }}\n id={this.triggerId}\n variant=\"icon-label\"\n size=\"md\"\n icon=\"SectionList\"\n label=\"Group\"\n labelEmphasis={false}\n pressScale={false}\n aria-label={name}\n hasMenu={true}\n collapseLabel={true}\n expanded={this.open}\n controls={this.popupId}\n onDsClick={(event: CustomEvent<MouseEvent>) => this.toggle(event.detail.detail === 0)}\n />\n ) : null}\n\n {this.shouldRender ? (\n <div\n id={this.popupId}\n popover=\"manual\"\n class={{\n 'table-group-popup': true,\n 'ds-choice-popup': true,\n 'ds-choice-popup--closing': this.closing,\n }}\n style={popupStyle}\n role=\"dialog\"\n aria-label={name}\n >\n <div class=\"table-group__body\">\n <div class=\"table-group__data-pane\">\n <ChoiceListSection\n heading=\"Data\"\n ariaLabel=\"Group data\"\n className=\"table-group__list\"\n >\n {this.options.map((option, index) => (\n <div data-group-value={option.value}>\n {this.renderDataOption(option, index)}\n </div>\n ))}\n </ChoiceListSection>\n <div\n class=\"table-group__footer ds-choice-footer\"\n aria-hidden={!this.grouping ? 'true' : undefined}\n >\n <div class=\"ds-choice-footer__content ds-control--md\">\n {this.grouping ? (\n <button\n class=\"ds-choice-footer__clear ds-text-action ds-focus-ring\"\n type=\"button\"\n onClick={() => this.dsClear.emit()}\n >\n <ds-text as=\"span\" variant=\"text-body-medium\" color=\"inherit\">\n {this.clearLabel}\n </ds-text>\n </button>\n ) : null}\n </div>\n </div>\n </div>\n\n <div class=\"table-group__order-pane\">\n {this.grouping ? (\n <ChoiceListSection\n heading=\"Order\"\n ariaLabel=\"Group order\"\n className=\"table-group__list\"\n >\n {this.activeOrderOptions.map((option, index) => (\n <div data-group-order-index={index}>{this.renderOrder(option, index)}</div>\n ))}\n </ChoiceListSection>\n ) : (\n <div class=\"table-group__empty ds-choice-empty ds-empty-region\">\n <ds-empty-state body={this.emptyMessage} />\n </div>\n )}\n </div>\n </div>\n </div>\n ) : null}\n </Host>\n );\n }\n}\n",
|
|
298
298
|
"type": "registry:ui"
|
|
299
299
|
}
|
|
300
300
|
]
|
|
@@ -1421,7 +1421,7 @@
|
|
|
1421
1421
|
},
|
|
1422
1422
|
{
|
|
1423
1423
|
"path": "src/wc/components/Table/table-types.ts",
|
|
1424
|
-
"content": "import type { TagContrast, TagIntent } from '../Tag/Tag';\nimport type { IconColor } from '../Icon/Icon';\nimport type { SafetyScoreLevel } from '../Score/score-types';\nimport type { TextColor } from '../Text/text-types';\nimport type { PaginationState } from '../Pagination/pagination-types';\n\nexport type TableSortDirection = 'asc' | 'desc';\nexport type TableSelectionMode = 'none' | 'multiple';\nexport type TableCellAlign = 'start' | 'center' | 'end';\nexport type TableCellLinkTarget = '_self' | '_blank';\nexport type TableColumnSticky = 'start' | 'end';\nexport type TableCaptionVisibility = 'visible' | 'hidden';\nexport type TableLoadMoreMode = 'auto' | 'manual';\nexport type TableDataMode = 'infinite' | 'pagination' | 'virtual';\nexport interface TableDataModeChangeDetail {\n dataMode: TableDataMode;\n}\nexport type TableLoadMoreReason = 'auto' | 'manual' | 'retry';\nexport type TableColumnWidth = 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n/** Visible line budget before a text track ellipsizes. */\nexport type TableCellMaxLines = 1 | 2 | 3;\n/** Resolved clamp, including unlimited wrapping. */\nexport type TableCellLineClamp = TableCellMaxLines | 'none';\n/** Semantic color for a group section header (faint surface + bold title). */\nexport type TableGroupIntent =\n | 'brand'\n | 'neutral'\n | 'negative'\n | 'warning'\n | 'caution'\n | 'positive';\n\n/** Independently sortable label within a compound column header. */\nexport interface TableHeaderSegment {\n /** Compact label rendered inside the table header. */\n label: string;\n /** Complete data-point label used when the segment is named outside the table header. */\n dataLabel?: string;\n /** Whether this data point is offered by TableSearch. Defaults to true. */\n searchable?: boolean;\n /** Stable key emitted through TableSortState.columnId. */\n sortKey: string;\n /** Visible separator rendered after this label when another segment follows. */\n separator?: string;\n}\n\n/** Controlled member-row sort state. Group order is controlled separately. */\nexport interface TableSortState {\n columnId: string;\n direction: TableSortDirection;\n}\n\n/** One controlled grouping level. Applications supply groups in their final fixed order. */\nexport interface TableGroupingState {\n columnId: string;\n direction: TableSortDirection;\n}\n\n/** One independently colored run inside a secondary or tertiary track. */\nexport interface TableCellTextRun {\n text: string;\n /** Defaults to the track’s standard color. */\n color?: TextColor;\n /** Optional supplementary copy shown from a dotted-underlined tooltip trigger. */\n help?: string;\n}\n\n/** A secondary or tertiary track: one string, or up to three colorable runs. */\nexport type TableCellTextTrack = string | TableCellTextRun[];\n\n/** Standard two- or three-line cell content owned by the table renderer. */\nexport interface TableCellText {\n primary: string | number;\n secondary?: TableCellTextTrack;\n /** Third subdued track; ignored on dual-primary cells. */\n tertiary?: TableCellTextTrack;\n /** Optional semantic foreground for a string secondary track. */\n secondaryColor?: TextColor;\n /** Optional semantic foreground for a string tertiary track. */\n tertiaryColor?: TextColor;\n /** Application-owned URL for the primary track only. Scalars stay unlinked. */\n href?: string;\n /** Native anchor target for a resolved primary link. */\n target?: TableCellLinkTarget;\n /** Allow this cell to wrap even when its column truncates by default. */\n wrap?: boolean;\n /** Clamp wrapping text after 1, 2, or 3 lines. Overrides column wrap. */\n maxLines?: TableCellMaxLines;\n fontFeature?: 'normal' | 'tabular-nums';\n}\n\n/** Two-line text content where both tracks use primary body text. */\nexport interface TableCellPrimaryText {\n kind: 'primary-text';\n primary: string | number;\n secondary: string | number;\n /** Application-owned URL for the primary track only. */\n href?: string;\n /** Native anchor target for a resolved primary link. */\n target?: TableCellLinkTarget;\n /** Allow this cell to wrap even when its column truncates by default. */\n wrap?: boolean;\n /** Clamp wrapping text after 1, 2, or 3 lines. Overrides column wrap. */\n maxLines?: TableCellMaxLines;\n fontFeature?: 'normal' | 'tabular-nums';\n}\n\n/** Applicable data point whose value is currently unavailable. */\nexport interface TableCellEmpty {\n kind: 'empty';\n}\n\n/** Data point that is intentionally not applicable to this row. */\nexport interface TableCellBlank {\n kind: 'blank';\n}\n\n/** Declarative icon-only content rendered by the table's standard cell primitive. */\nexport interface TableCellIcon {\n kind: 'icon';\n /** Exact canonical IcoMo export name. */\n icon: string;\n color?: IconColor;\n /** Accessible label for informative icons. Omit only when the icon is decorative. */\n label?: string;\n /** Application-owned value used when this icon column participates in sorting. */\n sortValue?: string | number | boolean;\n}\n\n/**\n * Prefix icon beside a text copy stack. Independent of icon-only and plain\n * text cells so those recipes stay unchanged.\n */\nexport interface TableCellIconText {\n kind: 'icon-text';\n /** Exact canonical IcoMo export name. */\n icon: string;\n iconColor?: IconColor;\n /** Accessible name. Omit when the glyph is decorative. */\n iconLabel?: string;\n primary: string | number;\n secondary?: TableCellTextTrack;\n tertiary?: TableCellTextTrack;\n secondaryColor?: TextColor;\n tertiaryColor?: TextColor;\n href?: string;\n target?: TableCellLinkTarget;\n wrap?: boolean;\n maxLines?: TableCellMaxLines;\n fontFeature?: 'normal' | 'tabular-nums';\n}\n\n/**\n * Compact safety-score fill at the top-right of a text copy stack. The score\n * occupies one 24px track while the copy keeps the standard text-cell anatomy.\n */\nexport interface TableCellScoreText {\n kind: 'score-text';\n /** Display-ready safety score. Numeric values infer their semantic level. */\n score: string | number;\n scoreLevel?: SafetyScoreLevel;\n /** Accessible name prefix. Defaults to “Safety score”. */\n scoreLabel?: string;\n /** Replace the score figure with its matching sm skeleton. */\n scoreLoading?: boolean;\n primary: string | number;\n secondary?: TableCellTextTrack;\n tertiary?: TableCellTextTrack;\n secondaryColor?: TextColor;\n tertiaryColor?: TextColor;\n href?: string;\n target?: TableCellLinkTarget;\n wrap?: boolean;\n maxLines?: TableCellMaxLines;\n fontFeature?: 'normal' | 'tabular-nums';\n}\n\n/** Body-row track stack an image preview occupies. */\nexport type TableCellImageTracks = 1 | 2 | 3;\n\n/** Declarative 16:9 image preview rendered by the table's standard cell primitive. */\nexport interface TableCellImage {\n kind: 'image';\n /** Optional image source. Omit it to render the standard bordered placeholder. */\n src?: string;\n /** Accessible description for either the image or its placeholder. */\n alt: string;\n /**\n * Which body-row contract the preview fills. The thumbnail height is that\n * cell height minus 8px padding; width follows 16:9. Defaults to 1.\n */\n tracks?: TableCellImageTracks;\n}\n\ninterface TableCellActionBase {\n kind: 'action';\n /** Add the ButtonUnfilled resting border. Action cells are unbordered by default. */\n hasBorder?: boolean;\n isInactive?: boolean;\n isLoading?: boolean;\n}\n\n/** One command inside an overflow action menu. */\nexport interface TableCellActionMenuItem {\n /** Stable application-owned action identity emitted with dsCellAction. */\n actionId: string;\n label: string;\n isInactive?: boolean;\n isDestructive?: boolean;\n}\n\n/** Visual separator between overflow action-menu commands. */\nexport interface TableCellActionDivider {\n kind: 'divider';\n}\n\nexport type TableCellActionMenuEntry = TableCellActionMenuItem | TableCellActionDivider;\n\n/** Declarative ButtonUnfilled content rendered by the table's standard action cell. */\nexport type TableCellAction = TableCellActionBase &\n (\n | {\n variant?: 'label';\n /** Stable application-owned action identity emitted with dsCellAction. */\n actionId: string;\n label: string;\n icon?: never;\n ariaLabel?: string;\n items?: never;\n }\n | {\n variant: 'icon-label';\n actionId: string;\n label: string;\n icon: string;\n ariaLabel?: string;\n items?: never;\n }\n | {\n variant: 'icon';\n actionId: string;\n label?: never;\n icon: string;\n ariaLabel: string;\n items?: never;\n }\n | {\n variant?: 'icon';\n /** Overflow commands. The Ellipses trigger opens ds-menu instead of emitting on click. */\n items: TableCellActionMenuEntry[];\n ariaLabel: string;\n icon?: string;\n actionId?: never;\n label?: never;\n }\n );\n\n/** Declarative Tag content rendered by the table's standard cell primitive. */\nexport type TableCellTagVariant = 'tag-only' | 'tag-with-text' | 'text-with-tag';\n\n/** One Tag inside a single- or multiple-Tag table cell. */\nexport interface TableCellTagItem {\n label: string;\n intent?: TagIntent;\n contrast?: TagContrast;\n icon?: string;\n rounded?: boolean;\n}\n\nexport type TableCellTag = TableCellTagItem & { kind: 'tag' } & (\n | {\n variant?: 'tag-only';\n text?: never;\n }\n | {\n variant: Exclude<TableCellTagVariant, 'tag-only'>;\n text: string;\n }\n );\n\n/** Multiple Tags that wrap inline while retaining the table's named track rhythm. */\nexport interface TableCellTags {\n kind: 'tags';\n items: TableCellTagItem[];\n /** Expected positive wrapped-line count used for row geometry and virtual estimates. */\n tracks: number;\n}\n\nexport type TableCellValue =\n | string\n | number\n | null\n | undefined\n | TableCellText\n | TableCellPrimaryText\n | TableCellTag\n | TableCellTags\n | TableCellIcon\n | TableCellIconText\n | TableCellScoreText\n | TableCellImage\n | TableCellAction\n | TableCellEmpty\n | TableCellBlank;\n\nexport type TableSkeletonWidth = string | number;\n\n/** Representative loading geometry for one table column. */\nexport type TableCellSkeleton =\n | {\n kind: 'text';\n /** One track for scalar content, two for primary and secondary, three when tertiary is present. */\n lines?: 1 | 2 | 3;\n primaryWidth?: TableSkeletonWidth;\n secondaryWidth?: TableSkeletonWidth;\n tertiaryWidth?: TableSkeletonWidth;\n }\n | {\n kind: 'image';\n /** Match the loaded image cell's track stack. Defaults to 1. */\n tracks?: TableCellImageTracks;\n }\n | {\n kind: 'tag';\n width?: TableSkeletonWidth;\n }\n | {\n kind: 'icon';\n rounded?: boolean;\n }\n | {\n kind: 'icon-text';\n lines?: 1 | 2 | 3;\n primaryWidth?: TableSkeletonWidth;\n secondaryWidth?: TableSkeletonWidth;\n tertiaryWidth?: TableSkeletonWidth;\n }\n | {\n kind: 'score-text';\n lines?: 1 | 2 | 3;\n primaryWidth?: TableSkeletonWidth;\n secondaryWidth?: TableSkeletonWidth;\n tertiaryWidth?: TableSkeletonWidth;\n }\n | {\n kind: 'action';\n /** Icon actions use a square control canvas; labeled actions may provide a wider width. */\n variant?: 'icon' | 'label' | 'icon-label';\n width?: TableSkeletonWidth;\n }\n | {\n kind: 'blank';\n };\n\nexport interface TableColumn {\n /** Stable column identity. */\n id: string;\n /** Visible column label. May be empty when headerLabel supplies a non-visual name. */\n header: string;\n /** Complete data-point label used by controls such as Sort and Search. */\n dataLabel?: string;\n /** Whether this data point is offered by TableSearch. Defaults to true for data columns. */\n searchable?: boolean;\n /** Screen-reader-only column name for an intentionally blank visual header. */\n headerLabel?: string;\n /** Supplementary header help. Does not replace the visible or accessible column name. */\n help?: string;\n /** Optional labels for columns that present and sort multiple related data points. */\n headerSegments?: TableHeaderSegment[];\n align?: TableCellAlign;\n sortable?: boolean;\n /** Preferred TokoMo table-column width. Numbers remain available for exceptional custom pixel widths. */\n size?: TableColumnWidth | number;\n /** Derive a fixed image-column width from the matching 1, 2, or 3 track cell geometry. Ignored when size is set. */\n imageTracks?: TableCellImageTracks;\n /** Minimum accepted preferred width in CSS pixels. */\n minSize?: number;\n /** Maximum accepted preferred width in CSS pixels. */\n maxSize?: number;\n /** Wrap cell text instead of truncating it to one line. */\n wrap?: boolean;\n /** Clamp wrapping text after 1, 2, or 3 lines. Omit with wrap for unlimited wrap. */\n maxLines?: TableCellMaxLines;\n /** Pin one application column to either inline edge during horizontal scrolling. */\n sticky?: TableColumnSticky;\n /**\n * Declare a trailing application-action lane. Action columns keep fixed\n * geometry and may host grouped table-level controls in their header.\n */\n kind?: 'data' | 'action';\n /** Representative loading geometry for this column. Defaults to one text line. */\n skeleton?: TableCellSkeleton;\n}\n\nexport interface TableRow {\n /** Stable identity, unique across all groups. */\n id: string;\n cells: Record<string, TableCellValue>;\n /** Accessible row name used by its selection control. Falls back to the first cell. */\n selectionLabel?: string;\n /** Exclude this row from selection without muting its content. */\n selectable?: boolean;\n /** Keep the row visible while disabling its selection control and styling it as inactive. */\n disabled?: boolean;\n /** Make the complete row a keyboard- and pointer-activatable application target. */\n interactive?: boolean;\n}\n\n/** Supporting copy on a group section header's second track. */\nexport interface TableGroupAccessory {\n text: string;\n /** Optional tooltip. Uses the shared dotted underline when present. */\n help?: string;\n}\n\n/** Leading group-header accessory. Score is the first supported hero. */\nexport interface TableGroupHeroScore {\n kind: 'score';\n value: string | number;\n level?: SafetyScoreLevel;\n /** Accessible name prefix, for example “Safety score”. */\n label?: string;\n isLoading?: boolean;\n}\n\nexport type TableGroupHero = TableGroupHeroScore;\n\nexport interface TableGroup {\n /** Stable group identity. */\n id: string;\n label: string;\n value?: string | number;\n /** Total server-side member count; may exceed the currently loaded row count. */\n totalCount?: number;\n /** Optional localized total-count phrase such as “166 events” for accessible loaded progress. */\n countLabel?: string;\n /**\n * Optional semantic intent for the group section header. Applies a faint\n * intent background and bold intent title color.\n */\n intent?: TableGroupIntent;\n /**\n * Optional accessory copy on a second 24px track under the label and count.\n * Middle-dot separated. At most four items are shown.\n */\n accessories?: TableGroupAccessory[];\n /**\n * Optional leading hero before the label and count. A score uses sm on both\n * single-track and two-track headers and sits at the start of the copy stack.\n */\n hero?: TableGroupHero;\n /** Whether this group has more member rows available to load. */\n hasMore?: boolean;\n /** Controlled incremental loading state for this group's member rows. */\n loadingMore?: boolean;\n /** Controlled incremental loading failure for this group's member rows. */\n loadMoreError?: string;\n /** Reset key for this group's query, sort, or filter state. Defaults to the group ID. */\n loadIdentity?: string | number;\n rows: TableRow[];\n}\n\nexport interface TableSortChangeDetail {\n sort: TableSortState | null;\n}\n\nexport interface TableSelectionChangeDetail {\n selectedRowIds: string[];\n scope: 'row' | 'all-loaded' | 'group';\n changedRowId?: string;\n /** Present when scope is `group`. */\n groupId?: string;\n selected?: boolean;\n}\n\nexport interface TableLoadMoreDetail {\n reason: TableLoadMoreReason;\n loadIdentity: string | number;\n loadedRowCount: number;\n}\n\nexport interface TableGroupLoadMoreDetail extends TableLoadMoreDetail {\n groupId: string;\n}\n\nexport interface TableCellActionDetail {\n actionId: string;\n rowId: string;\n columnId: string;\n}\n\nexport interface TableGroupCollapseChangeDetail {\n scope: 'group' | 'all';\n /** Present when a single group was toggled. */\n groupId?: string;\n collapsed: boolean;\n collapsedGroupIds: string[];\n}\n\nexport interface TableRowActivateDetail {\n rowId: string;\n}\n\n/** Controlled show/hide and data-column order for the table-owned customizer. */\nexport interface TableColumnsConfigChangeDetail {\n hiddenColumnIds: string[];\n columnOrder: string[];\n}\n\n/** Controlled top-level pagination state. Rows or groups contain only the active page. */\nexport interface TablePaginationState extends PaginationState {\n /** Change to request one fresh fitted-capacity snapshot for the current query shape. */\n fitIdentity?: string | number;\n}\n",
|
|
1424
|
+
"content": "import type { TagContrast, TagIntent } from '../Tag/Tag';\nimport type { IconColor } from '../Icon/Icon';\nimport type { SafetyScoreLevel } from '../Score/score-types';\nimport type { TextColor } from '../Text/text-types';\nimport type { PaginationState } from '../Pagination/pagination-types';\n\nexport type TableSortDirection = 'asc' | 'desc';\nexport type TableSelectionMode = 'none' | 'multiple';\nexport type TableCellAlign = 'start' | 'center' | 'end';\nexport type TableCellLinkTarget = '_self' | '_blank';\nexport type TableColumnSticky = 'start' | 'end';\nexport type TableCaptionVisibility = 'visible' | 'hidden';\nexport type TableLoadMoreMode = 'auto' | 'manual';\nexport type TableDataMode = 'infinite' | 'pagination' | 'virtual';\nexport interface TableDataModeChangeDetail {\n dataMode: TableDataMode;\n}\nexport type TableLoadMoreReason = 'auto' | 'manual' | 'retry';\nexport type TableColumnWidth = 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n/** Visible line budget before a text track ellipsizes. */\nexport type TableCellMaxLines = 1 | 2 | 3;\n/** Resolved clamp, including unlimited wrapping. */\nexport type TableCellLineClamp = TableCellMaxLines | 'none';\n/** Semantic color for a group section header (faint surface + bold title). */\nexport type TableGroupIntent =\n | 'brand'\n | 'neutral'\n | 'negative'\n | 'warning'\n | 'caution'\n | 'positive';\n\n/** Independently sortable label within a compound column header. */\nexport interface TableHeaderSegment {\n /** Compact label rendered inside the table header. */\n label: string;\n /** Complete data-point label used when the segment is named outside the table header. */\n dataLabel?: string;\n /** Whether this data point is offered by TableSearch. Defaults to true. */\n searchable?: boolean;\n /** Stable key emitted through TableSortState.columnId. */\n sortKey: string;\n /** Visible separator rendered after this label when another segment follows. */\n separator?: string;\n}\n\n/** Controlled member-row sort state. Group order is controlled separately. */\nexport interface TableSortState {\n columnId: string;\n direction: TableSortDirection;\n}\n\n/** One controlled grouping level. Applications supply groups in their final fixed order. */\nexport interface TableGroupingState {\n columnId: string;\n direction: TableSortDirection;\n /** Optional application-owned data point used to order the group sections. */\n orderBy?: string;\n}\n\n/** One independently colored run inside a secondary or tertiary track. */\nexport interface TableCellTextRun {\n text: string;\n /** Defaults to the track’s standard color. */\n color?: TextColor;\n /** Optional supplementary copy shown from a dotted-underlined tooltip trigger. */\n help?: string;\n}\n\n/** A secondary or tertiary track: one string, or up to three colorable runs. */\nexport type TableCellTextTrack = string | TableCellTextRun[];\n\n/** Standard two- or three-line cell content owned by the table renderer. */\nexport interface TableCellText {\n primary: string | number;\n secondary?: TableCellTextTrack;\n /** Third subdued track; ignored on dual-primary cells. */\n tertiary?: TableCellTextTrack;\n /** Optional semantic foreground for a string secondary track. */\n secondaryColor?: TextColor;\n /** Optional semantic foreground for a string tertiary track. */\n tertiaryColor?: TextColor;\n /** Application-owned URL for the primary track only. Scalars stay unlinked. */\n href?: string;\n /** Native anchor target for a resolved primary link. */\n target?: TableCellLinkTarget;\n /** Allow this cell to wrap even when its column truncates by default. */\n wrap?: boolean;\n /** Clamp wrapping text after 1, 2, or 3 lines. Overrides column wrap. */\n maxLines?: TableCellMaxLines;\n fontFeature?: 'normal' | 'tabular-nums';\n}\n\n/** Two-line text content where both tracks use primary body text. */\nexport interface TableCellPrimaryText {\n kind: 'primary-text';\n primary: string | number;\n secondary: string | number;\n /** Application-owned URL for the primary track only. */\n href?: string;\n /** Native anchor target for a resolved primary link. */\n target?: TableCellLinkTarget;\n /** Allow this cell to wrap even when its column truncates by default. */\n wrap?: boolean;\n /** Clamp wrapping text after 1, 2, or 3 lines. Overrides column wrap. */\n maxLines?: TableCellMaxLines;\n fontFeature?: 'normal' | 'tabular-nums';\n}\n\n/** Applicable data point whose value is currently unavailable. */\nexport interface TableCellEmpty {\n kind: 'empty';\n}\n\n/** Data point that is intentionally not applicable to this row. */\nexport interface TableCellBlank {\n kind: 'blank';\n}\n\n/** Declarative icon-only content rendered by the table's standard cell primitive. */\nexport interface TableCellIcon {\n kind: 'icon';\n /** Exact canonical IcoMo export name. */\n icon: string;\n color?: IconColor;\n /** Accessible label for informative icons. Omit only when the icon is decorative. */\n label?: string;\n /** Application-owned value used when this icon column participates in sorting. */\n sortValue?: string | number | boolean;\n}\n\n/**\n * Prefix icon beside a text copy stack. Independent of icon-only and plain\n * text cells so those recipes stay unchanged.\n */\nexport interface TableCellIconText {\n kind: 'icon-text';\n /** Exact canonical IcoMo export name. */\n icon: string;\n iconColor?: IconColor;\n /** Accessible name. Omit when the glyph is decorative. */\n iconLabel?: string;\n primary: string | number;\n secondary?: TableCellTextTrack;\n tertiary?: TableCellTextTrack;\n secondaryColor?: TextColor;\n tertiaryColor?: TextColor;\n href?: string;\n target?: TableCellLinkTarget;\n wrap?: boolean;\n maxLines?: TableCellMaxLines;\n fontFeature?: 'normal' | 'tabular-nums';\n}\n\n/**\n * Compact safety-score fill at the top-right of a text copy stack. The score\n * occupies one 24px track while the copy keeps the standard text-cell anatomy.\n */\nexport interface TableCellScoreText {\n kind: 'score-text';\n /** Display-ready safety score. Numeric values infer their semantic level. */\n score: string | number;\n scoreLevel?: SafetyScoreLevel;\n /** Accessible name prefix. Defaults to “Safety score”. */\n scoreLabel?: string;\n /** Replace the score figure with its matching sm skeleton. */\n scoreLoading?: boolean;\n primary: string | number;\n secondary?: TableCellTextTrack;\n tertiary?: TableCellTextTrack;\n secondaryColor?: TextColor;\n tertiaryColor?: TextColor;\n href?: string;\n target?: TableCellLinkTarget;\n wrap?: boolean;\n maxLines?: TableCellMaxLines;\n fontFeature?: 'normal' | 'tabular-nums';\n}\n\n/** Body-row track stack an image preview occupies. */\nexport type TableCellImageTracks = 1 | 2 | 3;\n\n/** Declarative 16:9 image preview rendered by the table's standard cell primitive. */\nexport interface TableCellImage {\n kind: 'image';\n /** Optional image source. Omit it to render the standard bordered placeholder. */\n src?: string;\n /** Accessible description for either the image or its placeholder. */\n alt: string;\n /**\n * Which body-row contract the preview fills. The thumbnail height is that\n * cell height minus 8px padding; width follows 16:9. Defaults to 1.\n */\n tracks?: TableCellImageTracks;\n}\n\ninterface TableCellActionBase {\n kind: 'action';\n /** Add the ButtonUnfilled resting border. Action cells are unbordered by default. */\n hasBorder?: boolean;\n isInactive?: boolean;\n isLoading?: boolean;\n}\n\n/** One command inside an overflow action menu. */\nexport interface TableCellActionMenuItem {\n /** Stable application-owned action identity emitted with dsCellAction. */\n actionId: string;\n label: string;\n isInactive?: boolean;\n isDestructive?: boolean;\n}\n\n/** Visual separator between overflow action-menu commands. */\nexport interface TableCellActionDivider {\n kind: 'divider';\n}\n\nexport type TableCellActionMenuEntry = TableCellActionMenuItem | TableCellActionDivider;\n\n/** Declarative ButtonUnfilled content rendered by the table's standard action cell. */\nexport type TableCellAction = TableCellActionBase &\n (\n | {\n variant?: 'label';\n /** Stable application-owned action identity emitted with dsCellAction. */\n actionId: string;\n label: string;\n icon?: never;\n ariaLabel?: string;\n items?: never;\n }\n | {\n variant: 'icon-label';\n actionId: string;\n label: string;\n icon: string;\n ariaLabel?: string;\n items?: never;\n }\n | {\n variant: 'icon';\n actionId: string;\n label?: never;\n icon: string;\n ariaLabel: string;\n items?: never;\n }\n | {\n variant?: 'icon';\n /** Overflow commands. The Ellipses trigger opens ds-menu instead of emitting on click. */\n items: TableCellActionMenuEntry[];\n ariaLabel: string;\n icon?: string;\n actionId?: never;\n label?: never;\n }\n );\n\n/** Declarative Tag content rendered by the table's standard cell primitive. */\nexport type TableCellTagVariant = 'tag-only' | 'tag-with-text' | 'text-with-tag';\n\n/** One Tag inside a single- or multiple-Tag table cell. */\nexport interface TableCellTagItem {\n label: string;\n intent?: TagIntent;\n contrast?: TagContrast;\n icon?: string;\n rounded?: boolean;\n}\n\nexport type TableCellTag = TableCellTagItem & { kind: 'tag' } & (\n | {\n variant?: 'tag-only';\n text?: never;\n }\n | {\n variant: Exclude<TableCellTagVariant, 'tag-only'>;\n text: string;\n }\n );\n\n/** Multiple Tags that wrap inline while retaining the table's named track rhythm. */\nexport interface TableCellTags {\n kind: 'tags';\n items: TableCellTagItem[];\n /** Expected positive wrapped-line count used for row geometry and virtual estimates. */\n tracks: number;\n}\n\nexport type TableCellValue =\n | string\n | number\n | null\n | undefined\n | TableCellText\n | TableCellPrimaryText\n | TableCellTag\n | TableCellTags\n | TableCellIcon\n | TableCellIconText\n | TableCellScoreText\n | TableCellImage\n | TableCellAction\n | TableCellEmpty\n | TableCellBlank;\n\nexport type TableSkeletonWidth = string | number;\n\n/** Representative loading geometry for one table column. */\nexport type TableCellSkeleton =\n | {\n kind: 'text';\n /** One track for scalar content, two for primary and secondary, three when tertiary is present. */\n lines?: 1 | 2 | 3;\n primaryWidth?: TableSkeletonWidth;\n secondaryWidth?: TableSkeletonWidth;\n tertiaryWidth?: TableSkeletonWidth;\n }\n | {\n kind: 'image';\n /** Match the loaded image cell's track stack. Defaults to 1. */\n tracks?: TableCellImageTracks;\n }\n | {\n kind: 'tag';\n width?: TableSkeletonWidth;\n }\n | {\n kind: 'icon';\n rounded?: boolean;\n }\n | {\n kind: 'icon-text';\n lines?: 1 | 2 | 3;\n primaryWidth?: TableSkeletonWidth;\n secondaryWidth?: TableSkeletonWidth;\n tertiaryWidth?: TableSkeletonWidth;\n }\n | {\n kind: 'score-text';\n lines?: 1 | 2 | 3;\n primaryWidth?: TableSkeletonWidth;\n secondaryWidth?: TableSkeletonWidth;\n tertiaryWidth?: TableSkeletonWidth;\n }\n | {\n kind: 'action';\n /** Icon actions use a square control canvas; labeled actions may provide a wider width. */\n variant?: 'icon' | 'label' | 'icon-label';\n width?: TableSkeletonWidth;\n }\n | {\n kind: 'blank';\n };\n\nexport interface TableColumn {\n /** Stable column identity. */\n id: string;\n /** Visible column label. May be empty when headerLabel supplies a non-visual name. */\n header: string;\n /** Complete data-point label used by controls such as Sort and Search. */\n dataLabel?: string;\n /** Whether this data point is offered by TableSearch. Defaults to true for data columns. */\n searchable?: boolean;\n /** Screen-reader-only column name for an intentionally blank visual header. */\n headerLabel?: string;\n /** Supplementary header help. Does not replace the visible or accessible column name. */\n help?: string;\n /** Optional labels for columns that present and sort multiple related data points. */\n headerSegments?: TableHeaderSegment[];\n align?: TableCellAlign;\n sortable?: boolean;\n /** Preferred TokoMo table-column width. Numbers remain available for exceptional custom pixel widths. */\n size?: TableColumnWidth | number;\n /** Derive a fixed image-column width from the matching 1, 2, or 3 track cell geometry. Ignored when size is set. */\n imageTracks?: TableCellImageTracks;\n /** Minimum accepted preferred width in CSS pixels. */\n minSize?: number;\n /** Maximum accepted preferred width in CSS pixels. */\n maxSize?: number;\n /** Wrap cell text instead of truncating it to one line. */\n wrap?: boolean;\n /** Clamp wrapping text after 1, 2, or 3 lines. Omit with wrap for unlimited wrap. */\n maxLines?: TableCellMaxLines;\n /** Pin one application column to either inline edge during horizontal scrolling. */\n sticky?: TableColumnSticky;\n /**\n * Declare a trailing application-action lane. Action columns keep fixed\n * geometry and may host grouped table-level controls in their header.\n */\n kind?: 'data' | 'action';\n /** Representative loading geometry for this column. Defaults to one text line. */\n skeleton?: TableCellSkeleton;\n}\n\nexport interface TableRow {\n /** Stable identity, unique across all groups. */\n id: string;\n cells: Record<string, TableCellValue>;\n /** Accessible row name used by its selection control. Falls back to the first cell. */\n selectionLabel?: string;\n /** Exclude this row from selection without muting its content. */\n selectable?: boolean;\n /** Keep the row visible while disabling its selection control and styling it as inactive. */\n disabled?: boolean;\n /** Make the complete row a keyboard- and pointer-activatable application target. */\n interactive?: boolean;\n}\n\n/** Supporting copy on a group section header's second track. */\nexport interface TableGroupAccessory {\n text: string;\n /** Optional tooltip. Uses the shared dotted underline when present. */\n help?: string;\n}\n\n/** Leading group-header accessory. Score is the first supported hero. */\nexport interface TableGroupHeroScore {\n kind: 'score';\n value: string | number;\n level?: SafetyScoreLevel;\n /** Accessible name prefix, for example “Safety score”. */\n label?: string;\n isLoading?: boolean;\n}\n\nexport type TableGroupHero = TableGroupHeroScore;\n\nexport interface TableGroup {\n /** Stable group identity. */\n id: string;\n label: string;\n value?: string | number;\n /** Total server-side member count; may exceed the currently loaded row count. */\n totalCount?: number;\n /** Optional localized total-count phrase such as “166 events” for accessible loaded progress. */\n countLabel?: string;\n /**\n * Optional semantic intent for the group section header. Applies a faint\n * intent background and bold intent title color.\n */\n intent?: TableGroupIntent;\n /**\n * Optional accessory copy on a second 24px track under the label and count.\n * Middle-dot separated. At most four items are shown.\n */\n accessories?: TableGroupAccessory[];\n /**\n * Optional leading hero before the label and count. A score uses sm on both\n * single-track and two-track headers and sits at the start of the copy stack.\n */\n hero?: TableGroupHero;\n /** Whether this group has more member rows available to load. */\n hasMore?: boolean;\n /** Controlled incremental loading state for this group's member rows. */\n loadingMore?: boolean;\n /** Controlled incremental loading failure for this group's member rows. */\n loadMoreError?: string;\n /** Reset key for this group's query, sort, or filter state. Defaults to the group ID. */\n loadIdentity?: string | number;\n rows: TableRow[];\n}\n\nexport interface TableSortChangeDetail {\n sort: TableSortState | null;\n}\n\nexport interface TableSelectionChangeDetail {\n selectedRowIds: string[];\n scope: 'row' | 'all-loaded' | 'group';\n changedRowId?: string;\n /** Present when scope is `group`. */\n groupId?: string;\n selected?: boolean;\n}\n\nexport interface TableLoadMoreDetail {\n reason: TableLoadMoreReason;\n loadIdentity: string | number;\n loadedRowCount: number;\n}\n\nexport interface TableGroupLoadMoreDetail extends TableLoadMoreDetail {\n groupId: string;\n}\n\nexport interface TableCellActionDetail {\n actionId: string;\n rowId: string;\n columnId: string;\n}\n\nexport interface TableGroupCollapseChangeDetail {\n scope: 'group' | 'all';\n /** Present when a single group was toggled. */\n groupId?: string;\n collapsed: boolean;\n collapsedGroupIds: string[];\n}\n\nexport interface TableRowActivateDetail {\n rowId: string;\n}\n\n/** Controlled show/hide and data-column order for the table-owned customizer. */\nexport interface TableColumnsConfigChangeDetail {\n hiddenColumnIds: string[];\n columnOrder: string[];\n}\n\n/** Controlled top-level pagination state. Rows or groups contain only the active page. */\nexport interface TablePaginationState extends PaginationState {\n /** Change to request one fresh fitted-capacity snapshot for the current query shape. */\n fitIdentity?: string | number;\n}\n",
|
|
1425
1425
|
"type": "registry:ui"
|
|
1426
1426
|
},
|
|
1427
1427
|
{
|
|
@@ -16,11 +16,17 @@ export declare class Field {
|
|
|
16
16
|
private touched;
|
|
17
17
|
private controlDisabled;
|
|
18
18
|
private controlRequired;
|
|
19
|
+
/** Bumped to let Stencil relocate a control added after the initial render. */
|
|
20
|
+
private slotRevision;
|
|
19
21
|
private readonly generatedId;
|
|
20
22
|
private controlContainer?;
|
|
21
23
|
private control?;
|
|
22
24
|
private initialValue;
|
|
23
25
|
private authoredAria;
|
|
26
|
+
private childObserver?;
|
|
27
|
+
private didLoad;
|
|
28
|
+
connectedCallback(): void;
|
|
29
|
+
disconnectedCallback(): void;
|
|
24
30
|
componentDidLoad(): void;
|
|
25
31
|
componentDidRender(): void;
|
|
26
32
|
onFieldContractChange(): void;
|
|
@@ -33,6 +39,7 @@ export declare class Field {
|
|
|
33
39
|
private readValue;
|
|
34
40
|
private updateControlAttribute;
|
|
35
41
|
private findControl;
|
|
42
|
+
private observeLateControls;
|
|
36
43
|
private syncControl;
|
|
37
44
|
private handleLabelClick;
|
|
38
45
|
private handleFocusIn;
|
|
@@ -44,6 +44,8 @@ export interface TableSortState {
|
|
|
44
44
|
export interface TableGroupingState {
|
|
45
45
|
columnId: string;
|
|
46
46
|
direction: TableSortDirection;
|
|
47
|
+
/** Optional application-owned data point used to order the group sections. */
|
|
48
|
+
orderBy?: string;
|
|
47
49
|
}
|
|
48
50
|
/** One independently colored run inside a secondary or tertiary track. */
|
|
49
51
|
export interface TableCellTextRun {
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import { EventEmitter } from '../../stencil-public-runtime';
|
|
2
|
-
import type { TableGroupingState } from '../Table/table-types';
|
|
2
|
+
import type { TableGroupingState, TableSortDirection } from '../Table/table-types';
|
|
3
|
+
export interface TableGroupOrderOption {
|
|
4
|
+
label: string;
|
|
5
|
+
direction: TableSortDirection;
|
|
6
|
+
/** Optional application-owned data point used to order the group sections. */
|
|
7
|
+
orderBy?: string;
|
|
8
|
+
}
|
|
3
9
|
export interface TableGroupOption {
|
|
4
10
|
label: string;
|
|
5
11
|
value: string;
|
|
6
12
|
description?: string;
|
|
7
13
|
isInactive?: boolean;
|
|
14
|
+
/** Product-owned order choices for this grouping data point. */
|
|
15
|
+
orderOptions?: TableGroupOrderOption[];
|
|
8
16
|
}
|
|
9
17
|
export declare class TableGroup {
|
|
10
18
|
private el;
|
|
@@ -51,10 +59,12 @@ export declare class TableGroup {
|
|
|
51
59
|
private finishClose;
|
|
52
60
|
private focusInitialDataPoint;
|
|
53
61
|
private selectData;
|
|
54
|
-
private
|
|
62
|
+
private get activeOrderOptions();
|
|
63
|
+
private get selectedOrderIndex();
|
|
64
|
+
private selectOrder;
|
|
55
65
|
private moveFocus;
|
|
56
66
|
private renderDataOption;
|
|
57
|
-
private
|
|
67
|
+
private renderOrder;
|
|
58
68
|
render(): any;
|
|
59
69
|
}
|
|
60
70
|
//# sourceMappingURL=TableGroup.d.ts.map
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["SAFETY_SCORE_LEVELS","isSafetyScoreLevel","value","includes","resolveSafetyScoreLevel","trim","undefined","numericValue","Number","isFinite","resolveScoreLevel","level","SCORE_VALUE_VARIANT","sm","md","lg","scoreCss","Score","__stencil_proxyCustomElement","HTMLElement","constructor","registerHost","this","size","isLoading","label","render","valueVariant","accessibleName","filter","Boolean","join","h","Host","key","class","score","role","score__badge","variant","textVariant","background","as","emphasis","color","fontFeature"],"sources":["src/wc/components/Score/score-types.ts","src/wc/components/Score/score-model.ts","src/wc/components/Score/Score.css?tag=ds-score&encapsulation=scoped","src/wc/components/Score/Score.tsx"],"sourcesContent":["export type SafetyScoreLevel = 'fair' | 'good' | 'excellent';\nexport type ScoreSize = 'sm' | 'md' | 'lg';\n\nexport const SCORE_SIZES = ['sm', 'md', 'lg'] as const;\nexport const SAFETY_SCORE_LEVELS = ['fair', 'good', 'excellent'] as const;\n","import { SAFETY_SCORE_LEVELS, type SafetyScoreLevel, type ScoreSize } from './score-types';\n\nexport function isSafetyScoreLevel(value: unknown): value is SafetyScoreLevel {\n return typeof value === 'string' && (SAFETY_SCORE_LEVELS as readonly string[]).includes(value);\n}\n\n/**\n * Infer a safety-score color level from a 0–100 figure. Non-numeric or out-of-range\n * values return undefined so the owner can supply `level` explicitly.\n */\nexport function resolveSafetyScoreLevel(value: string | number): SafetyScoreLevel | undefined {\n if (typeof value === 'string' && value.trim() === '') return undefined;\n const numericValue = typeof value === 'number' ? value : Number(value);\n if (!Number.isFinite(numericValue) || numericValue < 0 || numericValue > 100) return undefined;\n if (numericValue <= 50) return 'fair';\n if (numericValue <= 80) return 'good';\n return 'excellent';\n}\n\nexport function resolveScoreLevel(\n value: string | number,\n level?: SafetyScoreLevel\n): SafetyScoreLevel | undefined {\n return isSafetyScoreLevel(level) ? level : resolveSafetyScoreLevel(value);\n}\n\nexport const SCORE_VALUE_VARIANT = {\n sm: 'text-title-small',\n md: 'text-title-large',\n lg: 'text-display-small',\n} as const satisfies Record<\n ScoreSize,\n 'text-title-small' | 'text-title-large' | 'text-display-small'\n>;\n","@import '../../utils/control-parts.css';\n@import '../../utils/forced-colors.css';\n\n:host {\n display: inline-flex;\n align-items: center;\n box-sizing: border-box;\n min-width: 0;\n --_score-badge-inline-size: var(--dimension-size-500);\n --_score-badge-block-size: var(--dimension-size-400);\n /* Matches the text skeleton’s 75% bar so the fill inset is even on all sides. */\n --_score-skeleton-inset: calc(var(--_score-badge-block-size) / 8);\n}\n\n:host(.score--sm) {\n --_score-badge-inline-size: calc(var(--dimension-size-400) - var(--dimension-space-050));\n --_score-badge-block-size: var(--dimension-size-300);\n}\n\n:host(.score--md) {\n --_score-badge-inline-size: var(--dimension-size-500);\n --_score-badge-block-size: var(--dimension-size-400);\n}\n\n:host(.score--lg) {\n --_score-badge-inline-size: calc(var(--dimension-size-600) + var(--dimension-space-100));\n --_score-badge-block-size: var(--dimension-size-500);\n}\n\n.score__badge {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n inline-size: var(--_score-badge-inline-size);\n block-size: var(--_score-badge-block-size);\n overflow: hidden;\n border-radius: var(--dimension-radius-025);\n background: var(--color-background-faint-neutral);\n color: var(--color-foreground-bold-neutral);\n -webkit-user-select: none;\n user-select: none;\n}\n\n.score__badge--fair {\n background: var(--color-safety-score-background-fair);\n color: var(--color-safety-score-foreground-on-fair);\n}\n\n.score__badge--good {\n background: var(--color-safety-score-background-good);\n color: var(--color-foreground-primary);\n}\n\n.score__badge--excellent {\n background: var(--color-safety-score-background-excellent);\n color: var(--color-safety-score-foreground-on-excellent);\n}\n\n.score__value,\n.score__badge ds-skeleton {\n flex: 0 0 auto;\n}\n\n.score__badge--loading {\n padding-inline: var(--_score-skeleton-inset);\n}\n\n.score__badge--loading .score__value {\n flex: 1 1 auto;\n inline-size: 100%;\n block-size: 100%;\n max-inline-size: 100%;\n max-block-size: 100%;\n min-inline-size: 0;\n}\n\n@media (forced-colors: active) {\n .score__badge {\n border: var(--dimension-stroke-width-012) solid var(--ds-forced-color-content);\n background: var(--ds-forced-color-surface);\n color: var(--ds-forced-color-content);\n }\n}\n","import { Component, Prop, h, Host } from '@stencil/core';\nimport { SCORE_VALUE_VARIANT, resolveScoreLevel } from './score-model';\nimport type { SafetyScoreLevel, ScoreSize } from './score-types';\n\n@Component({\n tag: 'ds-score',\n styleUrl: 'Score.css',\n scoped: true,\n})\nexport class Score {\n /** Display-ready headline figure. */\n @Prop() value: string | number = '';\n /**\n * Visual density matching control height: `sm` 24px, `md` 32px, `lg` 40px.\n * `lg` is the Card Overview recipe.\n */\n @Prop() size: ScoreSize = 'md';\n /**\n * Safety-score color level. Numeric values from 0–100 infer fair (0–50),\n * good (51–80), or excellent (81–100) when this is omitted.\n */\n @Prop() level: SafetyScoreLevel | undefined;\n /** Replace the figure with a skeleton while data resolves. */\n @Prop() isLoading: boolean = false;\n /** Accessible name prefix, for example “Safety score”. */\n @Prop() label: string = '';\n\n render() {\n const size = this.size;\n const level = resolveScoreLevel(this.value, this.level);\n const valueVariant = SCORE_VALUE_VARIANT[size];\n const accessibleName = [this.label.trim(), this.isLoading ? '' : this.value]\n .filter(Boolean)\n .join(' ');\n\n return (\n <Host\n class={{\n score: true,\n [`score--${size}`]: true,\n 'score--loading': this.isLoading,\n }}\n role={accessibleName ? 'img' : undefined}\n aria-busy={this.isLoading ? 'true' : undefined}\n aria-label={accessibleName || undefined}\n >\n <span\n class={{\n score__badge: true,\n [`score__badge--${level}`]: Boolean(level),\n 'score__badge--loading': this.isLoading,\n }}\n >\n {this.isLoading ? (\n <ds-skeleton\n class=\"score__value\"\n variant=\"text\"\n textVariant={valueVariant}\n background={level ? 'bold' : 'faint'}\n />\n ) : (\n <ds-text\n as=\"span\"\n class=\"score__value ds-control-label-box\"\n variant={valueVariant}\n emphasis={true}\n color=\"inherit\"\n fontFeature=\"tabular-nums\"\n >\n {this.value}\n </ds-text>\n )}\n </span>\n </Host>\n );\n }\n}\n"],"mappings":"mIAIO,MAAMA,EAAsB,CAAC,OAAQ,OAAQ,aCF9C,SAAUC,EAAmBC,GACjC,cAAcA,IAAU,UAAaF,EAA0CG,SAASD,EAC1F,CAMM,SAAUE,EAAwBF,GACtC,UAAWA,IAAU,UAAYA,EAAMG,SAAW,GAAI,OAAOC,UAC7D,MAAMC,SAAsBL,IAAU,SAAWA,EAAQM,OAAON,GAChE,IAAKM,OAAOC,SAASF,IAAiBA,EAAe,GAAKA,EAAe,IAAK,OAAOD,UACrF,GAAIC,GAAgB,GAAI,MAAO,OAC/B,GAAIA,GAAgB,GAAI,MAAO,OAC/B,MAAO,WACT,CAEM,SAAUG,EACdR,EACAS,GAEA,OAAOV,EAAmBU,GAASA,EAAQP,EAAwBF,EACrE,CAEO,MAAMU,EAAsB,CACjCC,GAAI,mBACJC,GAAI,mBACJC,GAAI,sBC7BN,MAAMC,EAAW,IAAM,4pH,MCSVC,EAAKC,EAAA,MAAAD,UAAAE,EALlB,WAAAC,CAAAC,G,4CAOUC,KAAApB,MAAyB,GAKzBoB,KAAAC,KAAkB,KAOlBD,KAAAE,UAAqB,MAErBF,KAAAG,MAAgB,EAmDzB,CAjDC,MAAAC,GACE,MAAMH,EAAOD,KAAKC,KAClB,MAAMZ,EAAQD,EAAkBY,KAAKpB,MAAOoB,KAAKX,OACjD,MAAMgB,EAAef,EAAoBW,GACzC,MAAMK,EAAiB,CAACN,KAAKG,MAAMpB,OAAQiB,KAAKE,UAAY,GAAKF,KAAKpB,OACnE2B,OAAOC,SACPC,KAAK,KAER,OACEC,EAACC,EAAI,CAAAC,IAAA,2CACHC,MAAO,CACLC,MAAO,KACP,CAAC,UAAUb,KAAS,KACpB,iBAAkBD,KAAKE,WAEzBa,KAAMT,EAAiB,MAAQtB,UAAS,YAC7BgB,KAAKE,UAAY,OAASlB,UAAS,aAClCsB,GAAkBtB,WAE9B0B,EAAA,QAAAE,IAAA,2CACEC,MAAO,CACLG,aAAc,KACd,CAAC,iBAAiB3B,KAAUmB,QAAQnB,GACpC,wBAAyBW,KAAKE,YAG/BF,KAAKE,UACJQ,EAAA,eACEG,MAAM,eACNI,QAAQ,OACRC,YAAab,EACbc,WAAY9B,EAAQ,OAAS,UAG/BqB,EAAA,WACEU,GAAG,OACHP,MAAM,oCACNI,QAASZ,EACTgB,SAAU,KACVC,MAAM,UACNC,YAAY,gBAEXvB,KAAKpB,Q","ignoreList":[]}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{p as e,H as t,h as i,a as s,t as d}from"./index.js";import{d as n}from"./p-DQQsS9Rx.js";const r=()=>`.ds-field-stack.sc-ds-field-h,.ds-field-stack.sc-ds-field{display:flex;flex-direction:column;gap:var(--dimension-space-050)}.sc-ds-field-h{display:block}.field__control.sc-ds-field{display:flex;min-width:0}.field__control.sc-ds-field>*.sc-ds-field{width:100%}`;let a=0;const o=e=>e?.split(/\s+/).filter(Boolean)??[];const l=(...e)=>[...new Set(e.flat())];const h=e(class e extends t{constructor(e){super();if(e!==false){this.__registerHost()}this.error=false;this.focused=false;this.filled=false;this.dirty=false;this.touched=false;this.controlDisabled=false;this.controlRequired=false;this.generatedId=`ds-field-${++a}`;this.initialValue="";this.authoredAria=new WeakMap;this.syncControl=()=>{const e=this.findControl();if(!e)return;if(e!==this.control){this.control=e;this.initialValue=this.readValue(e);this.authoredAria.set(e,{labelledby:o(e.getAttribute("aria-labelledby")),describedby:o(e.getAttribute("aria-describedby"))})}const t=e.tagName.startsWith("DS-");if(t&&"inputId"in e)e.inputId=this.controlId;else this.updateControlAttribute(e,"id",this.controlId);const i=this.authoredAria.get(e)??{labelledby:[],describedby:[]};const s=l(i.labelledby,[this.labelId]).join(" ");const d=l(i.describedby,this.renderedDescription?[this.descriptionId]:[],this.renderedError?[this.errorId]:[]).join(" ");this.updateControlAttribute(e,"aria-labelledby",s);this.updateControlAttribute(e,"aria-describedby",d||undefined);this.updateControlAttribute(e,"aria-invalid",this.error?"true":undefined);if(t&&"error"in e&&e.error!==this.error)e.error=this.error;const n=this.readValue(e);this.filled=n.length>0;this.dirty=n!==this.initialValue;this.controlDisabled=Boolean(e.disabled||e.isInactive||e.hasAttribute("disabled"));this.controlRequired=Boolean(e.required||e.hasAttribute("required"))};this.handleLabelClick=e=>{if(!this.control?.tagName.startsWith("DS-"))return;e.preventDefault();this.control.setFocus?.()};this.handleFocusIn=()=>{this.focused=true};this.handleFocusOut=e=>{if(e.relatedTarget instanceof Node&&this.el.contains(e.relatedTarget))return;this.focused=false;this.touched=true};this.handleValueChange=()=>{this.syncControl()}}componentDidLoad(){this.syncControl();requestAnimationFrame((()=>this.syncControl()))}componentDidRender(){this.syncControl()}onFieldContractChange(){this.syncControl()}get controlId(){return this.fieldId||this.generatedId}get labelId(){return`${this.controlId}-label`}get descriptionId(){return`${this.controlId}-description`}get errorId(){return`${this.controlId}-error`}get renderedDescription(){return Boolean(this.description)&&!this.renderedError}get renderedError(){return this.error&&Boolean(this.errorMessage)}readValue(e){const t=e.value;return Array.isArray(t)?t.join(""):String(t??"")}updateControlAttribute(e,t,i){if(i===undefined){if(e.hasAttribute(t))e.removeAttribute(t);return}if(e.getAttribute(t)!==i)e.setAttribute(t,i)}findControl(){return this.controlContainer?.querySelector(":scope > :not(slot)")??undefined}render(){return i(s,{key:"7383bc4c008f0e7668e3fac1218c919fd07069fd","data-focused":this.focused?"":undefined,"data-filled":this.filled?"":undefined,"data-dirty":this.dirty?"":undefined,"data-touched":this.touched?"":undefined,"data-invalid":this.error?"":undefined,"data-disabled":this.controlDisabled?"":undefined,"data-required":this.controlRequired?"":undefined,onFocusin:this.handleFocusIn,onFocusout:this.handleFocusOut,onInput:this.handleValueChange,onChange:this.handleValueChange,onDsChange:this.handleValueChange},i("div",{key:"dad7f4200f32302c638bccb9d09feb84593304d1",class:"field ds-field-stack"},i("ds-text",{key:"3f6aad8393cb7d4e8966534a8e521089641ced9d",class:"field__label",as:"label",variant:"text-body-small",color:"primary",emphasis:true,for:this.controlId,textId:this.labelId,onClick:this.handleLabelClick},this.label),i("div",{key:"163ce6d43e79e3f4ec0457afd0f5ea34e368420c",class:"field__control",ref:e=>this.controlContainer=e},i("slot",{key:"09112a81b2814b1145e90ad971b2626aa9886655",onSlotchange:this.syncControl})),this.renderedDescription&&i("ds-text",{key:"4418aa1d18e8eb0a919866f22b25698ca1227d90",class:"field__description",as:"div",variant:"text-body-small",color:"secondary",textId:this.descriptionId},this.description),this.renderedError&&i("ds-text",{key:"f46afe2f3924188c5c5dc204e245e85a62d88016",class:"field__error",as:"div",variant:"text-body-small",color:"negative",textId:this.errorId,role:"alert"},this.errorMessage)))}get el(){return this}static get watchers(){return{fieldId:[{onFieldContractChange:0}],description:[{onFieldContractChange:0}],error:[{onFieldContractChange:0}],errorMessage:[{onFieldContractChange:0}]}}static get style(){return r()}},[262,"ds-field",{label:[1],fieldId:[1,"field-id"],description:[1],error:[4],errorMessage:[1,"error-message"],focused:[32],filled:[32],dirty:[32],touched:[32],controlDisabled:[32],controlRequired:[32]},undefined,{fieldId:[{onFieldContractChange:0}],description:[{onFieldContractChange:0}],error:[{onFieldContractChange:0}],errorMessage:[{onFieldContractChange:0}]}]);function c(){if(typeof customElements==="undefined"){return}const e=["ds-field","ds-text"];e.forEach((e=>{switch(e){case"ds-field":if(!customElements.get(d(e))){customElements.define(d(e),h)}break;case"ds-text":if(!customElements.get(d(e))){n()}break}}))}c();export{h as F,c as d};
|
|
2
|
-
//# sourceMappingURL=p-DVLghmNY.js.map
|