@santi020k/lumen-elements 3.0.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +497 -5
- package/dist/bullet-chart-html.d.ts +5 -0
- package/dist/bullet-chart-html.d.ts.map +1 -0
- package/dist/bullet-chart-html.js +56 -0
- package/dist/chart-activation.d.ts +15 -0
- package/dist/chart-activation.d.ts.map +1 -0
- package/dist/chart-activation.js +93 -0
- package/dist/chart-html.d.ts +22 -0
- package/dist/chart-html.d.ts.map +1 -0
- package/dist/chart-html.js +1 -0
- package/dist/comparison-chart-html.d.ts +4 -0
- package/dist/comparison-chart-html.d.ts.map +1 -0
- package/dist/comparison-chart-html.js +36 -0
- package/dist/components/ai-surfaces.d.ts +115 -0
- package/dist/components/ai-surfaces.d.ts.map +1 -0
- package/dist/components/ai-surfaces.js +270 -0
- package/dist/components/button.d.ts +51 -2
- package/dist/components/button.d.ts.map +1 -1
- package/dist/components/button.js +81 -2
- package/dist/components/card.d.ts +6 -0
- package/dist/components/card.d.ts.map +1 -1
- package/dist/components/card.js +6 -1
- package/dist/components/combobox.d.ts +1 -2
- package/dist/components/combobox.d.ts.map +1 -1
- package/dist/components/combobox.js +27 -121
- package/dist/components/dashboard.d.ts +41 -0
- package/dist/components/dashboard.d.ts.map +1 -0
- package/dist/components/dashboard.js +88 -0
- package/dist/components/device-frame.d.ts +31 -0
- package/dist/components/device-frame.d.ts.map +1 -0
- package/dist/components/device-frame.js +95 -0
- package/dist/components/foundations.d.ts +30 -2
- package/dist/components/foundations.d.ts.map +1 -1
- package/dist/components/foundations.js +27 -2
- package/dist/components/image-comparison.d.ts +33 -0
- package/dist/components/image-comparison.d.ts.map +1 -0
- package/dist/components/image-comparison.js +144 -0
- package/dist/components/media-selection.d.ts +41 -0
- package/dist/components/media-selection.d.ts.map +1 -0
- package/dist/components/media-selection.js +114 -0
- package/dist/components/media-viewport.d.ts +30 -0
- package/dist/components/media-viewport.d.ts.map +1 -0
- package/dist/components/media-viewport.js +108 -0
- package/dist/components/virtual-list.d.ts +38 -0
- package/dist/components/virtual-list.d.ts.map +1 -0
- package/dist/components/virtual-list.js +30 -0
- package/dist/components/visual-interactions.d.ts +65 -0
- package/dist/components/visual-interactions.d.ts.map +1 -0
- package/dist/components/visual-interactions.js +91 -0
- package/dist/components/world-map.d.ts +46 -0
- package/dist/components/world-map.d.ts.map +1 -0
- package/dist/components/world-map.js +312 -0
- package/dist/consumer-behaviors.d.ts +36 -0
- package/dist/consumer-behaviors.d.ts.map +1 -0
- package/dist/consumer-behaviors.js +1 -0
- package/dist/define.d.ts +229 -6
- package/dist/define.d.ts.map +1 -1
- package/dist/define.js +1 -1
- package/dist/element-base.js +1 -1
- package/dist/expanded-chart-html.d.ts +9 -0
- package/dist/expanded-chart-html.d.ts.map +1 -0
- package/dist/expanded-chart-html.js +61 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/package.json +34 -6
- package/styles/critical.css +634 -61
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type LumenChartDatumActivationDetail } from '@santi020k/lumen-core';
|
|
2
|
+
import { LumenElement } from './element-base.js';
|
|
3
|
+
export interface LumenChartDatumActionsElement extends HTMLElement {
|
|
4
|
+
datumActionFormatter: (context: string) => string;
|
|
5
|
+
}
|
|
6
|
+
export declare abstract class LumenDatumChartElement extends LumenElement {
|
|
7
|
+
#private;
|
|
8
|
+
get datumActionFormatter(): (context: string) => string;
|
|
9
|
+
set datumActionFormatter(value: (context: string) => string);
|
|
10
|
+
disconnectedCallback(): void;
|
|
11
|
+
protected abstract renderChart(): void;
|
|
12
|
+
protected datumAttributes(detail: LumenChartDatumActivationDetail | null, context: string): string;
|
|
13
|
+
protected renderChartContent(html: string): void;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=chart-activation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-activation.d.ts","sourceRoot":"","sources":["../src/chart-activation.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,+BAA+B,EAErC,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAoBhD,MAAM,WAAW,6BAA8B,SAAQ,WAAW;IAChE,oBAAoB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAA;CAClD;AAGD,8BAAsB,sBAAuB,SAAQ,YAAY;;IAI/D,IAAI,oBAAoB,IAAI,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAEtD;IAED,IAAI,oBAAoB,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,EAI1D;IAEQ,oBAAoB,IAAI,IAAI;IAQrC,SAAS,CAAC,QAAQ,CAAC,WAAW,IAAI,IAAI;IAEtC,SAAS,CAAC,eAAe,CAAC,MAAM,EAAE,+BAA+B,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAMlG,SAAS,CAAC,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;CAmFjD"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { createLumenChartActivationController, parseLumenChartDatumActivation } from '@santi020k/lumen-core';
|
|
2
|
+
import { LumenElement } from './element-base.js';
|
|
3
|
+
const escapeAttribute = (value) => value.replaceAll('&', '&')
|
|
4
|
+
.replaceAll('"', '"').replaceAll('<', '<').replaceAll('>', '>');
|
|
5
|
+
const datumKey = (detail) => detail.kind === 'series' ?
|
|
6
|
+
JSON.stringify([detail.kind, detail.seriesId, detail.x, detail.datumId]) :
|
|
7
|
+
JSON.stringify([detail.kind, detail.x, detail.kind === 'heatmap' ? detail.y : null, detail.datumId]);
|
|
8
|
+
const parseAttribute = (element) => {
|
|
9
|
+
try {
|
|
10
|
+
const value = JSON.parse(element.getAttribute('data-ui-chart-datum') ?? 'null');
|
|
11
|
+
return parseLumenChartDatumActivation(value);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
export class LumenDatumChartElement extends LumenElement {
|
|
18
|
+
#controller;
|
|
19
|
+
#datumActionFormatter;
|
|
20
|
+
get datumActionFormatter() {
|
|
21
|
+
return this.#datumActionFormatter ?? (context => `${this.getAttribute('datum-action-prefix') ?? 'Open details: '}${context}`);
|
|
22
|
+
}
|
|
23
|
+
set datumActionFormatter(value) {
|
|
24
|
+
this.#datumActionFormatter = value;
|
|
25
|
+
if (this.isConnected)
|
|
26
|
+
this.renderChart();
|
|
27
|
+
}
|
|
28
|
+
disconnectedCallback() {
|
|
29
|
+
this.#controller?.destroy();
|
|
30
|
+
this.#controller = undefined;
|
|
31
|
+
super.disconnectedCallback();
|
|
32
|
+
}
|
|
33
|
+
datumAttributes(detail, context) {
|
|
34
|
+
if (!detail || !this.hasAttribute('drilldown') || this.getAttribute('drilldown') === 'false')
|
|
35
|
+
return '';
|
|
36
|
+
return ` data-ui-chart-datum="${escapeAttribute(JSON.stringify(detail))}" data-ui-chart-datum-label="${escapeAttribute(this.datumActionFormatter(context))}"`;
|
|
37
|
+
}
|
|
38
|
+
renderChartContent(html) {
|
|
39
|
+
const enabled = this.hasAttribute('drilldown') && this.getAttribute('drilldown') !== 'false';
|
|
40
|
+
const focused = this.ownerDocument.activeElement;
|
|
41
|
+
const focusedKey = focused && this.contains(focused) ? focused.getAttribute('data-ui-chart-action-key') : null;
|
|
42
|
+
const wasOpen = this.querySelector('[data-ui-chart-actions]')?.hasAttribute('open') ?? false;
|
|
43
|
+
this.toggleAttribute('data-ui-chart-activation', enabled);
|
|
44
|
+
if (enabled)
|
|
45
|
+
this.setAttribute('data-ui-chart-adapter', 'elements');
|
|
46
|
+
else
|
|
47
|
+
this.removeAttribute('data-ui-chart-adapter');
|
|
48
|
+
this.innerHTML = html;
|
|
49
|
+
if (!enabled) {
|
|
50
|
+
this.#controller?.destroy();
|
|
51
|
+
this.#controller = undefined;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
this.#controller ??= createLumenChartActivationController(this);
|
|
55
|
+
this.#appendActions(wasOpen, focusedKey);
|
|
56
|
+
}
|
|
57
|
+
#appendActions(wasOpen, focusedKey) {
|
|
58
|
+
const actions = new Map();
|
|
59
|
+
for (const mark of this.querySelectorAll('[data-ui-chart-datum]')) {
|
|
60
|
+
const detail = parseAttribute(mark);
|
|
61
|
+
if (detail)
|
|
62
|
+
actions.set(datumKey(detail), { detail, label: mark.getAttribute('data-ui-chart-datum-label') ?? this.datumActionFormatter(JSON.stringify(detail)) });
|
|
63
|
+
}
|
|
64
|
+
if (actions.size === 0)
|
|
65
|
+
return;
|
|
66
|
+
const disclosure = this.ownerDocument.createElement('details');
|
|
67
|
+
disclosure.className = 'ui-chart__actions';
|
|
68
|
+
disclosure.setAttribute('data-ui-chart-actions', '');
|
|
69
|
+
disclosure.open = wasOpen;
|
|
70
|
+
const summary = this.ownerDocument.createElement('summary');
|
|
71
|
+
summary.textContent = this.getAttribute('explore-data-label') ?? 'Explore chart data';
|
|
72
|
+
disclosure.append(summary);
|
|
73
|
+
const list = this.ownerDocument.createElement('ul');
|
|
74
|
+
let restoreFocus;
|
|
75
|
+
for (const [key, action] of actions) {
|
|
76
|
+
const item = this.ownerDocument.createElement('li');
|
|
77
|
+
const button = this.ownerDocument.createElement('button');
|
|
78
|
+
button.type = 'button';
|
|
79
|
+
button.className = 'ui-button ui-button--ghost ui-button--default-size';
|
|
80
|
+
button.setAttribute('data-slot', 'button');
|
|
81
|
+
button.setAttribute('data-ui-chart-datum', JSON.stringify(action.detail));
|
|
82
|
+
button.setAttribute('data-ui-chart-action-key', key);
|
|
83
|
+
button.textContent = action.label;
|
|
84
|
+
item.append(button);
|
|
85
|
+
list.append(item);
|
|
86
|
+
if (key === focusedKey)
|
|
87
|
+
restoreFocus = button;
|
|
88
|
+
}
|
|
89
|
+
disclosure.append(list);
|
|
90
|
+
this.append(disclosure);
|
|
91
|
+
restoreFocus?.focus({ preventScroll: true });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type createLumenHistogramGeometry, type createLumenLineChartModel, type createLumenWaterfallGeometry, type LumenChartAnnotation, type LumenChartLabels, type LumenChartSeries, type LumenHeatmapDatum, type LumenHistogramBin, type LumenRangeDatum, type LumenScatterGeometry, type LumenScatterGeometryPoint, type LumenScatterReference, type LumenScatterScaleType, type LumenWaterfallDatum } from '@santi020k/lumen-core';
|
|
2
|
+
export declare const escapeChartHtml: (value: number | string) => string;
|
|
3
|
+
export declare const parseHistogramBins: (value: string | null) => LumenHistogramBin[];
|
|
4
|
+
export declare const parseWaterfallData: (value: string | null) => LumenWaterfallDatum[];
|
|
5
|
+
export declare const parseChartAnnotations: (value: string | null) => LumenChartAnnotation[];
|
|
6
|
+
export declare const chartNumberAttribute: (element: HTMLElement, name: string) => number | undefined;
|
|
7
|
+
export declare const chartInspectionHtml: (model: ReturnType<typeof createLumenLineChartModel>, labels: Readonly<LumenChartLabels>, formatValue: (value: number) => string, formatCategory?: (value: number | string) => string) => string;
|
|
8
|
+
export declare const chartAnnotationHtml: (model: ReturnType<typeof createLumenLineChartModel>) => string;
|
|
9
|
+
export declare const chartLabelsFor: (element: HTMLElement) => Readonly<LumenChartLabels>;
|
|
10
|
+
export declare const chartLegendHtml: (series: readonly LumenChartSeries[], labels: Readonly<LumenChartLabels>, interactive?: boolean) => string;
|
|
11
|
+
export declare const chartAxesHtml: (model: Pick<ReturnType<typeof createLumenHistogramGeometry>, "categoryTicks" | "height" | "left" | "right" | "ticks" | "y">, formatValue: (value: number) => string, labelOffset?: number) => string;
|
|
12
|
+
export declare const intervalChartHtml: (model: ReturnType<typeof createLumenWaterfallGeometry> | ReturnType<typeof createLumenHistogramGeometry>, labels: Readonly<LumenChartLabels>, formatValue: (value: number) => string, formatBoundary: (value: number) => string, valueLabel: string, showTable: boolean, summaryOverride?: string | null) => string;
|
|
13
|
+
export declare const scatterPlotHtml: (geometry: LumenScatterGeometry, referenceItems: readonly LumenScatterReference[], xScale: LumenScatterScaleType, plotId: string, formatX: (value: number | string) => string, formatY: (value: number) => string, labels: LumenChartLabels, datumTargets?: string) => string;
|
|
14
|
+
export declare const chartDataTableHtml: (categories: readonly (number | string)[], series: readonly LumenChartSeries[], formatCategory: ((category: number | string) => string) | undefined, formatValue: ((value: number) => string) | undefined, labels: Readonly<LumenChartLabels>) => string;
|
|
15
|
+
export declare const scatterDataTableHtml: (points: readonly LumenScatterGeometryPoint[], formatCategory: ((category: number | string) => string) | undefined, formatValue: ((value: number) => string) | undefined, labels: Readonly<LumenChartLabels>) => string;
|
|
16
|
+
export declare const heatmapDataTableHtml: (data: readonly LumenHeatmapDatum[], labels: Readonly<LumenChartLabels>, formatValue?: (value: number) => string) => string;
|
|
17
|
+
export declare const rangeDataTableHtml: (data: readonly LumenRangeDatum[], labels: Readonly<LumenChartLabels>) => string;
|
|
18
|
+
export declare const chartHeaderHtml: (element: HTMLElement, showValue?: boolean) => string;
|
|
19
|
+
export declare const chartCaptionHtml: (element: HTMLElement) => string;
|
|
20
|
+
export declare const parseHeatmapData: (value: string | null) => LumenHeatmapDatum[];
|
|
21
|
+
export declare const parseRangeData: (value: string | null) => LumenRangeDatum[];
|
|
22
|
+
//# sourceMappingURL=chart-html.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-html.d.ts","sourceRoot":"","sources":["../src/chart-html.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{alignLumenChartSeries as f,createLumenScatterReferences as _,formatLumenChartSummary as w,getLumenChartCategoryLabel as g,getLumenChartToneClassName as p,lumenChartTones as A,normalizeLumenHeatmapData as j,resolveLumenChartLabels as D}from"@santi020k/lumen-core";const e=t=>String(t).replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'"),b=t=>{try{const a=JSON.parse(t??"[]");return Array.isArray(a)?a:null}catch{return null}},m=t=>t!==null&&typeof t=="object"?{...t}:{},k=t=>{const a=b(t),r=[];for(const i of a??[null]){const l=m(i);if(typeof l.start!="number"||typeof l.end!="number"||typeof l.count!="number"||l.label!==void 0&&typeof l.label!="string")return[{start:NaN,end:NaN,count:NaN}];r.push({start:l.start,end:l.end,count:l.count,...typeof l.label=="string"?{label:l.label}:{}})}return r},v=t=>A.find(a=>a===t),L=t=>typeof t.id=="string"&&typeof t.label=="string"&&typeof t.value=="number"&&new Set([void 0,"delta","total"]).has(t.kind),S=t=>{const a=b(t),r=[];for(const i of a??[null]){const l=m(i);if(!L(l))return[{id:"invalid",label:"",value:NaN}];const n=v(l.tone);if(l.tone!==void 0&&!n)return[{id:"invalid",label:"",value:NaN}];const c=l.kind==="total"?"total":"delta";r.push({id:l.id,label:l.label,value:l.value,kind:c,...n?{tone:n}:{}})}return r},N=t=>t===void 0||t==="x"||t==="y",z=t=>{const a=[];for(const r of b(t)??[]){const i=m(r);if(typeof i.id!="string"||typeof i.label!="string"||typeof i.value!="number"&&typeof i.value!="string"||!N(i.axis))continue;const l=i.axis??"y",n=v(i.tone);a.push({id:i.id,label:i.label,value:i.value,axis:l,...n?{tone:n}:{}})}return a},F=(t,a)=>{const r=t.getAttribute(a);return r!==null&&r.trim()!==""&&Number.isFinite(Number(r))?Number(r):void 0},M=(t,a,r,i)=>{const l=t.series.map(n=>new Map(n.data.map(c=>[c.x,c])));return`<div class="ui-chart__inspection" data-ui-chart-inspection hidden>${t.categories.map((n,c)=>{const $=t.series.map((d,h)=>{const u=l[h]?.get(n)?.y,s=u==null||!Number.isFinite(u)?a.notAvailable:r(u);return`<span class="${p(d.tone,h)}" data-ui-chart-series-value="${e(d.id)}"><i aria-hidden="true"></i>${e(d.label)} <b>${e(s)}</b></span>`}).join("");return`<div hidden data-ui-chart-point="${e(JSON.stringify(n))}" data-ui-chart-position="${t.positions[c]??t.paddingLeft}"><strong>${e(g(t.series,n,i,"detail"))}</strong>${$}</div>`}).join("")}</div><p class="ui-sr-only" aria-live="polite" aria-atomic="true" data-ui-chart-announcement></p>`},T=t=>t.annotationMarks.map(a=>{const r=a.axis==="x"?`<line x1="${a.coordinate}" x2="${a.coordinate}" y1="${t.padding}" y2="${t.height-t.padding}"></line><text x="${a.coordinate+4}" y="${t.padding-8}">${e(a.label)}</text>`:`<line x1="${t.paddingLeft}" x2="${t.width-t.padding}" y1="${a.coordinate}" y2="${a.coordinate}"></line><text text-anchor="end" x="${t.width-t.padding}" y="${a.coordinate-8}">${e(a.label)}</text>`;return`<g class="ui-chart__annotation ${p(a.tone)}">${r}</g>`}).join(""),q=t=>{const a=D(void 0),r=(i,l)=>t.getAttribute(`${i}-label`)??l;return{...a,chartData:t.getAttribute("aria-label")??t.getAttribute("heading")??a.chartData,count:r("count",a.count),density:r("density",a.density),start:r("start",a.start),end:r("end",a.end),invalidData:r("invalid-data",a.invalidData),category:r("category",a.category),chartLegend:r("legend",a.chartLegend),column:r("column",a.column),empty:r("empty",a.empty),high:r("high",a.high),low:r("low",a.low),notAvailable:r("not-available",a.notAvailable),row:r("row",a.row),series:r("series",a.series),size:r("size",a.size),value:r("value",a.value),viewData:r("view-data",a.viewData),x:r("x",a.x)}},B=(t,a,r=!1)=>`<ul class="ui-chart__legend" aria-label="${e(a.chartLegend)}">${t.map((i,l)=>{const n=r?`<button type="button" class="ui-button ui-button--ghost ui-button--sm" aria-pressed="true" data-ui-chart-toggle="${e(i.id)}">${e(i.label)}</button>`:`<span aria-hidden="true"></span>${e(i.label)}`;return`<li class="${p(i.tone,l)}">${n}</li>`}).join("")}</ul>`,H=(t,a,r=16)=>{const i=t.ticks.map(n=>{const c=t.y(n);return`<line x1="${t.left}" x2="${t.right}" y1="${c}" y2="${c}"></line><text x="${t.left-8}" y="${c}">${e(a(n))}</text>`}).join(""),l=t.categoryTicks.map(n=>`<text text-anchor="${n.textAnchor}" x="${n.position}" y="${t.height-r}">${e(n.label)}</text>`).join("");return`<g class="ui-chart__grid">${i}</g><g class="ui-chart__axis-labels">${l}</g>`},J=(t,a,r,i,l,n,c=null)=>{if(t.marks.length===0)return`<p class="ui-chart__empty" role="status">${e(t.valid?a.empty:a.invalidData)}</p>`;const $="connectors"in t?t.connectors.map(o=>`<line class="ui-waterfall-chart__connector" x1="${o.x1}" x2="${o.x2}" y1="${o.y}" y2="${o.y}"></line>`).join(""):"",d=t.marks.map(o=>`<rect class="${p(o.tone)}" x="${o.x}" y="${o.y}" width="${o.width}" height="${o.height}"><title>${e(o.label)}: ${e(r(o.value))}</title></rect>`).join(""),h=t.marks.map((o,y)=>`<tr><th scope="row">${e(o.label)}</th><td>${e(i(o.start))}</td><td>${e(i(o.end))}</td><td>${e(r(o.value))}</td>${"bins"in t&&t.frequency==="density"?`<td>${t.bins[y]?.count??0}</td>`:""}</tr>`).join(""),u=n?`<details class="ui-chart__data"><summary>${e(a.viewData)}</summary><div role="group" tabindex="0" aria-label="${e(a.chartData)}"><table><thead><tr><th scope="col">${e(a.category)}</th><th scope="col">${e(a.start)}</th><th scope="col">${e(a.end)}</th><th scope="col">${e(l)}</th>${"bins"in t&&t.frequency==="density"?`<th scope="col">${e(a.count)}</th>`:""}</tr></thead><tbody>${h}</tbody></table></div></details>`:"",s=c??w([{id:"values",label:l,data:t.marks.map(o=>({x:o.key,y:o.value}))}],r,a);return`<p class="ui-sr-only" data-ui-chart-summary>${e(s)}</p><p class="ui-chart__axis-title">${e(l)}</p><div class="ui-chart__plot" role="region" tabindex="0" aria-label="${e(a.chartData)}"><svg aria-hidden="true" viewBox="0 0 ${t.width} ${t.height}">${H(t,r)}${$}<g class="ui-bar-chart__marks">${d}</g></svg></div>${u}`},O=(t,a,r,i,l,n,c,$="")=>{const d=_(a,t,r),h=d.map(s=>s.region?`<rect x="${Math.min(s.x1,s.x2)}" y="${Math.min(s.y1,s.y2)}" width="${Math.abs(s.x2-s.x1)}" height="${Math.abs(s.y2-s.y1)}"><title>${e(s.label)}</title></rect>`:`<line x1="${s.x1}" x2="${s.x2}" y1="${s.y1}" y2="${s.y2}"><title>${e(s.label)}</title></line>`).join(""),u=t.points.map(s=>[`<circle class="ui-chart-tone--${s.tone}" cx="${s.xCoordinate}"`,` cy="${s.yCoordinate}" r="${s.radius}"><title>`,`${e(s.xLabel??l(s.x))} · ${e(s.seriesLabel)}: `,`${e(s.label??n(s.y??0))}</title></circle>`].join("")).join("");return[`<div class="ui-chart__plot" role="region" tabindex="0" aria-label="${e(c.chartData)}"><svg aria-hidden="true" viewBox="0 0 ${t.width} ${t.height}">`,`<defs><clipPath id="${i}"><rect x="44" y="44" width="${t.width-88}" height="${t.height-88}"></rect></clipPath></defs>`,`<g class="ui-scatter-chart__references" clip-path="url(#${i})">${h}</g><g class="ui-scatter-chart__marks" clip-path="url(#${i})">${u}</g>${$}</svg></div>`,`<ul class="ui-scatter-chart__reference-labels">${d.map(s=>`<li>${e(s.label)}</li>`).join("")}</ul>`].join("")},P=(t,a,r,i=String,l)=>{const n=a.map(d=>f(d,t)),c=n.map(d=>`<th scope="col">${e(d.label)}</th>`).join(""),$=t.map(d=>{const h=n.map(s=>{const o=s.data.find(x=>x.x===d),y=o?.label??(o?.y===void 0||o.y===null||!Number.isFinite(o.y)?l.notAvailable:i(o.y));return`<td>${e(y)}</td>`}).join(""),u=g(n,d,r,"detail");return`<tr><th scope="row">${e(u)}</th>${h}</tr>`}).join("");return[`<details class="ui-chart__data"><summary>${e(l.viewData)}</summary>`,`<div role="group" tabindex="0" aria-label="${e(l.chartData)}"><table><thead><tr><th scope="col">${e(l.category)}</th>`,`${c}</tr></thead><tbody>${$}</tbody></table></div></details>`].join("")},R=(t,a=String,r=String,i)=>{const l=t.map(n=>[`<tr><th scope="row">${e(n.xLabel??a(n.x))}</th>`,`<td>${e(n.seriesLabel)}</td>`,`<td>${e(n.label??r(n.y??0))}</td>`,`<td>${e(n.size===void 0||n.size===null||!Number.isFinite(n.size)?i.notAvailable:r(n.size))}</td></tr>`].join("")).join("");return[`<details class="ui-chart__data"><summary>${e(i.viewData)}</summary>`,`<div role="group" tabindex="0" aria-label="${e(i.chartData)}"><table><thead><tr><th scope="col">${e(i.x)}</th>`,`<th scope="col">${e(i.series)}</th><th scope="col">${e(i.value)}</th>`,`<th scope="col">${e(i.size)}</th></tr></thead>`,`<tbody>${l}</tbody></table></div></details>`].join("")},W=(t,a,r=String)=>{const i=t.map(l=>{const n=l.label??(l.value===null||!Number.isFinite(l.value)?a.notAvailable:r(l.value));return[`<tr><th scope="row">${e(l.xLabel??l.x)}</th>`,`<td>${e(l.yLabel??l.y)}</td>`,`<td>${e(n)}</td></tr>`].join("")}).join("");return[`<details class="ui-chart__data"><summary>${e(a.viewData)}</summary>`,`<div role="group" tabindex="0" aria-label="${e(a.chartData)}"><table><thead><tr><th scope="col">${e(a.column)}</th>`,`<th scope="col">${e(a.row)}</th><th scope="col">${e(a.value)}</th></tr></thead>`,`<tbody>${i}</tbody></table></div></details>`].join("")},E=(t,a)=>{const r=t.map(i=>[`<tr><th scope="row">${e(i.xLabel??i.x)}</th>`,`<td>${e(i.low??a.notAvailable)}</td>`,`<td>${e(i.high??a.notAvailable)}</td></tr>`].join("")).join("");return[`<details class="ui-chart__data"><summary>${e(a.viewData)}</summary>`,`<div role="group" tabindex="0" aria-label="${e(a.chartData)}"><table><thead><tr><th scope="col">${e(a.category)}</th>`,`<th scope="col">${e(a.low)}</th><th scope="col">${e(a.high)}</th></tr></thead>`,`<tbody>${r}</tbody></table></div></details>`].join("")},G=(t,a=!0)=>{const r=t.getAttribute("heading"),i=t.getAttribute("description"),l=a?t.getAttribute("value"):null;return!r&&!i&&!l?"":`<header><div class="ui-chart__heading">${r?`<h3>${e(r)}</h3>`:""}${i?`<p>${e(i)}</p>`:""}</div>${l?`<strong data-ui-chart-value>${e(l)}</strong>`:""}</header>`},I=t=>{const a=t.getAttribute("caption");return a?`<figcaption>${e(a)}</figcaption>`:""},K=t=>{const a=b(t);return j(a??[])},Q=t=>{if(!t)return[];try{const a=JSON.parse(t);return Array.isArray(a)?a.flatMap(r=>{if(typeof r!="object"||r===null)return[];const i=m(r),l=n=>n===null||typeof n=="number"&&Number.isFinite(n);return typeof i.x!="string"&&typeof i.x!="number"||!l(i.low)||!l(i.high)?[]:[{high:i.high,...typeof i.id=="string"?{id:i.id}:{},...typeof i.label=="string"?{label:i.label}:{},low:i.low,x:i.x,...typeof i.xLabel=="string"?{xLabel:i.xLabel}:{}}]}):[]}catch{return[]}};export{T as chartAnnotationHtml,H as chartAxesHtml,I as chartCaptionHtml,P as chartDataTableHtml,G as chartHeaderHtml,M as chartInspectionHtml,q as chartLabelsFor,B as chartLegendHtml,F as chartNumberAttribute,e as escapeChartHtml,W as heatmapDataTableHtml,J as intervalChartHtml,z as parseChartAnnotations,K as parseHeatmapData,k as parseHistogramBins,Q as parseRangeData,S as parseWaterfallData,E as rangeDataTableHtml,R as scatterDataTableHtml,O as scatterPlotHtml};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type LumenChartLabels, type LumenComparisonDatum } from '@santi020k/lumen-core';
|
|
2
|
+
export declare const parseComparisonData: (source: string | null) => readonly LumenComparisonDatum[];
|
|
3
|
+
export declare const comparisonChartHtml: (element: HTMLElement, data: readonly LumenComparisonDatum[], paired: boolean, text: Readonly<LumenChartLabels>, formatter: (value: number) => string) => string;
|
|
4
|
+
//# sourceMappingURL=comparison-chart-html.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comparison-chart-html.d.ts","sourceRoot":"","sources":["../src/comparison-chart-html.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8G,KAAK,gBAAgB,EAAE,KAAK,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAKpM,eAAO,MAAM,mBAAmB,GAAI,QAAQ,MAAM,GAAG,IAAI,KAAG,SAAS,oBAAoB,EAQxF,CAAA;AAcD,eAAO,MAAM,mBAAmB,GAC9B,SAAS,WAAW,EAAE,MAAM,SAAS,oBAAoB,EAAE,EAAE,QAAQ,OAAO,EAC5E,MAAM,QAAQ,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,KACrE,MAuBF,CAAA"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { createLumenComparisonGeometry, formatLumenChartSummary, getLumenChartToneClassName, isLumenComparisonDatum } from '@santi020k/lumen-core';
|
|
2
|
+
import { bulletNumberAttribute } from './bullet-chart-html.js';
|
|
3
|
+
import { escapeChartHtml } from './chart-html.js';
|
|
4
|
+
export const parseComparisonData = (source) => {
|
|
5
|
+
try {
|
|
6
|
+
const parsed = JSON.parse(source ?? '[]');
|
|
7
|
+
if (Array.isArray(parsed) && parsed.every(isLumenComparisonDatum))
|
|
8
|
+
return parsed;
|
|
9
|
+
}
|
|
10
|
+
catch { }
|
|
11
|
+
return [{ id: '', label: '', value: NaN }];
|
|
12
|
+
};
|
|
13
|
+
const comparisonLabel = (element, attribute, fallback) => element.getAttribute(attribute) ?? fallback;
|
|
14
|
+
const comparisonSummary = (element, rows, paired, text, formatter) => escapeChartHtml(element.getAttribute('summary') ?? formatLumenChartSummary([
|
|
15
|
+
{ id: 'values', label: comparisonLabel(element, 'value-label', text.value), data: rows.map(row => ({ x: row.label, y: row.value })) },
|
|
16
|
+
...(paired ? [{ id: 'reference', label: comparisonLabel(element, 'reference-label', 'Before'), data: rows.map(row => ({ x: row.label, y: row.reference })) }] : [])
|
|
17
|
+
], formatter, text));
|
|
18
|
+
export const comparisonChartHtml = (element, data, paired, text, formatter) => {
|
|
19
|
+
const domain = element.hasAttribute('domain-min') || element.hasAttribute('domain-max') ? { min: bulletNumberAttribute(element, 'domain-min'), max: bulletNumberAttribute(element, 'domain-max') } : undefined;
|
|
20
|
+
const model = createLumenComparisonGeometry(data, { domain, paired });
|
|
21
|
+
if (!model.valid || !model.rows.length)
|
|
22
|
+
return `<p class="ui-chart__empty" role="status">${escapeChartHtml(model.valid ? text.empty : text.invalidData)}</p>`;
|
|
23
|
+
const format = (value) => escapeChartHtml(value === null ? text.notAvailable : formatter(value));
|
|
24
|
+
const before = escapeChartHtml(comparisonLabel(element, 'reference-label', 'Before'));
|
|
25
|
+
const title = escapeChartHtml(comparisonLabel(element, 'value-label', text.value));
|
|
26
|
+
const summary = comparisonSummary(element, model.rows, paired, text, formatter);
|
|
27
|
+
const rows = model.rows.map((row, index) => {
|
|
28
|
+
const connector = row.valuePosition !== null && row.referencePosition !== null ? `<span class="ui-comparison-chart__connector" style="left:${row.start * 100}%;width:${row.width * 100}%"></span>` : '';
|
|
29
|
+
const reference = paired && row.referencePosition !== null ? `<span class="ui-comparison-chart__reference" style="left:${row.referencePosition * 100}%"></span>` : '';
|
|
30
|
+
const dot = row.valuePosition !== null ? `<span class="ui-comparison-chart__dot" style="left:${row.valuePosition * 100}%"></span>` : '';
|
|
31
|
+
return `<li class="${getLumenChartToneClassName(row.tone, index)}"><div class="ui-comparison-chart__label"><span>${escapeChartHtml(row.label)}</span><span>${paired ? `${format(row.reference)} <span aria-hidden="true">→</span> ` : ''}<strong>${format(row.value)}</strong></span></div><div class="ui-comparison-chart__track" aria-hidden="true">${connector}${reference}${dot}</div></li>`;
|
|
32
|
+
}).join('');
|
|
33
|
+
const tableRows = model.rows.map(row => `<tr><th scope="row">${escapeChartHtml(row.label)}</th>${paired ? `<td>${format(row.reference)}</td>` : ''}<td>${format(row.value)}</td></tr>`).join('');
|
|
34
|
+
const table = element.getAttribute('show-table') === 'false' ? '' : `<details class="ui-chart__data"><summary>${escapeChartHtml(text.viewData)}</summary><div role="group" tabindex="0" aria-label="${escapeChartHtml(text.chartData)}"><table><thead><tr><th scope="col">${escapeChartHtml(text.category)}</th>${paired ? `<th scope="col">${before}</th>` : ''}<th scope="col">${title}</th></tr></thead><tbody>${tableRows}</tbody></table></div></details>`;
|
|
35
|
+
return `<p class="ui-sr-only" data-ui-chart-summary>${summary}</p><div class="ui-comparison-chart__legend"><span>${escapeChartHtml(text.category)}</span><span>${paired ? `${before} → ` : ''}${title}</span></div><ul class="ui-comparison-chart__rows">${rows}</ul><div class="ui-bullet-chart__ticks" aria-hidden="true">${model.ticks.map(tick => `<span>${format(tick)}</span>`).join('')}</div>${table}`;
|
|
36
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { LumenElement } from '../element-base.js';
|
|
2
|
+
declare abstract class LumenAiSurfaceElement extends LumenElement {
|
|
3
|
+
protected cleanup: (() => void) | undefined;
|
|
4
|
+
connectedCallback(): void;
|
|
5
|
+
disconnectedCallback(): void;
|
|
6
|
+
attributeChangedCallback(): void;
|
|
7
|
+
protected abstract render(): void;
|
|
8
|
+
}
|
|
9
|
+
export declare const lumenPromptComposerElementConfig: {
|
|
10
|
+
readonly baseClassName: "ui-prompt-composer";
|
|
11
|
+
readonly defaults: {
|
|
12
|
+
readonly 'data-ui-prompt-composer': "";
|
|
13
|
+
};
|
|
14
|
+
readonly observedAttributes: readonly ["action", "disabled", "label", "max-length", "pending", "send-label", "stop-label", "submit-on-enter", "value"];
|
|
15
|
+
readonly tagName: "lumen-prompt-composer";
|
|
16
|
+
};
|
|
17
|
+
export declare class LumenPromptComposerElement extends LumenAiSurfaceElement {
|
|
18
|
+
static config: {
|
|
19
|
+
readonly baseClassName: "ui-prompt-composer";
|
|
20
|
+
readonly defaults: {
|
|
21
|
+
readonly 'data-ui-prompt-composer': "";
|
|
22
|
+
};
|
|
23
|
+
readonly observedAttributes: readonly ["action", "disabled", "label", "max-length", "pending", "send-label", "stop-label", "submit-on-enter", "value"];
|
|
24
|
+
readonly tagName: "lumen-prompt-composer";
|
|
25
|
+
};
|
|
26
|
+
private form;
|
|
27
|
+
private input;
|
|
28
|
+
private label;
|
|
29
|
+
private send;
|
|
30
|
+
private stop;
|
|
31
|
+
get value(): string;
|
|
32
|
+
set value(value: string);
|
|
33
|
+
attributeChangedCallback(name?: string): void;
|
|
34
|
+
protected render(): void;
|
|
35
|
+
private elements;
|
|
36
|
+
private create;
|
|
37
|
+
}
|
|
38
|
+
export declare const lumenStreamMessageElementConfig: {
|
|
39
|
+
readonly baseClassName: "ui-stream-message ui-message ui-message--assistant";
|
|
40
|
+
readonly observedAttributes: readonly ["label", "status", "status-label", "text"];
|
|
41
|
+
readonly role: "article";
|
|
42
|
+
readonly tagName: "lumen-stream-message";
|
|
43
|
+
};
|
|
44
|
+
export declare class LumenStreamMessageElement extends LumenAiSurfaceElement {
|
|
45
|
+
static config: {
|
|
46
|
+
readonly baseClassName: "ui-stream-message ui-message ui-message--assistant";
|
|
47
|
+
readonly observedAttributes: readonly ["label", "status", "status-label", "text"];
|
|
48
|
+
readonly role: "article";
|
|
49
|
+
readonly tagName: "lumen-stream-message";
|
|
50
|
+
};
|
|
51
|
+
private content;
|
|
52
|
+
private statusText;
|
|
53
|
+
get text(): string;
|
|
54
|
+
set text(value: string);
|
|
55
|
+
protected render(): void;
|
|
56
|
+
}
|
|
57
|
+
export declare const lumenSourceCitationElementConfig: {
|
|
58
|
+
readonly baseClassName: "ui-source-citation";
|
|
59
|
+
readonly observedAttributes: readonly ["href", "label", "target"];
|
|
60
|
+
readonly tagName: "lumen-source-citation";
|
|
61
|
+
};
|
|
62
|
+
export declare class LumenSourceCitationElement extends LumenAiSurfaceElement {
|
|
63
|
+
static config: {
|
|
64
|
+
readonly baseClassName: "ui-source-citation";
|
|
65
|
+
readonly observedAttributes: readonly ["href", "label", "target"];
|
|
66
|
+
readonly tagName: "lumen-source-citation";
|
|
67
|
+
};
|
|
68
|
+
protected render(): void;
|
|
69
|
+
}
|
|
70
|
+
export declare const lumenToolActivityElementConfig: {
|
|
71
|
+
readonly baseClassName: "ui-tool-activity";
|
|
72
|
+
readonly observedAttributes: readonly ["label", "open", "status", "status-label"];
|
|
73
|
+
readonly tagName: "lumen-tool-activity";
|
|
74
|
+
};
|
|
75
|
+
export declare class LumenToolActivityElement extends LumenAiSurfaceElement {
|
|
76
|
+
static config: {
|
|
77
|
+
readonly baseClassName: "ui-tool-activity";
|
|
78
|
+
readonly observedAttributes: readonly ["label", "open", "status", "status-label"];
|
|
79
|
+
readonly tagName: "lumen-tool-activity";
|
|
80
|
+
};
|
|
81
|
+
private details;
|
|
82
|
+
private summary;
|
|
83
|
+
private statusText;
|
|
84
|
+
protected render(): void;
|
|
85
|
+
private create;
|
|
86
|
+
}
|
|
87
|
+
export declare const lumenApprovalCardElementConfig: {
|
|
88
|
+
readonly baseClassName: "ui-approval-card ui-card";
|
|
89
|
+
readonly defaults: {
|
|
90
|
+
readonly 'data-ui-approval-card': "";
|
|
91
|
+
};
|
|
92
|
+
readonly observedAttributes: readonly ["approve-label", "disabled", "label", "reject-label", "request-id", "status", "status-label"];
|
|
93
|
+
readonly role: "group";
|
|
94
|
+
readonly tagName: "lumen-approval-card";
|
|
95
|
+
};
|
|
96
|
+
export declare class LumenApprovalCardElement extends LumenAiSurfaceElement {
|
|
97
|
+
static config: {
|
|
98
|
+
readonly baseClassName: "ui-approval-card ui-card";
|
|
99
|
+
readonly defaults: {
|
|
100
|
+
readonly 'data-ui-approval-card': "";
|
|
101
|
+
};
|
|
102
|
+
readonly observedAttributes: readonly ["approve-label", "disabled", "label", "reject-label", "request-id", "status", "status-label"];
|
|
103
|
+
readonly role: "group";
|
|
104
|
+
readonly tagName: "lumen-approval-card";
|
|
105
|
+
};
|
|
106
|
+
private titleElement;
|
|
107
|
+
private statusText;
|
|
108
|
+
private approve;
|
|
109
|
+
private reject;
|
|
110
|
+
protected render(): void;
|
|
111
|
+
private elements;
|
|
112
|
+
private create;
|
|
113
|
+
}
|
|
114
|
+
export {};
|
|
115
|
+
//# sourceMappingURL=ai-surfaces.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-surfaces.d.ts","sourceRoot":"","sources":["../../src/components/ai-surfaces.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAA2B,MAAM,oBAAoB,CAAA;AAa1E,uBAAe,qBAAsB,SAAQ,YAAY;IACvD,SAAS,CAAC,OAAO,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAA;IAElC,iBAAiB,IAAI,IAAI;IAQzB,oBAAoB,IAAI,IAAI;IAM5B,wBAAwB,IAAI,IAAI;IAMzC,SAAS,CAAC,QAAQ,CAAC,MAAM,IAAI,IAAI;CAClC;AAED,eAAO,MAAM,gCAAgC;;;;;;;CAKN,CAAA;AAEvC,qBAAa,0BAA2B,SAAQ,qBAAqB;IACnE,OAAgB,MAAM;;;;;;;MAAmC;IACzD,OAAO,CAAC,IAAI,CAA6B;IACzC,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,KAAK,CAA8B;IAC3C,OAAO,CAAC,IAAI,CAA+B;IAC3C,OAAO,CAAC,IAAI,CAA+B;IAE3C,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAEtB;IAEQ,wBAAwB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;cAUnC,MAAM,IAAI,IAAI;IAqCjC,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,MAAM;CA6Cf;AAED,eAAO,MAAM,+BAA+B;;;;;CAKL,CAAA;AAEvC,qBAAa,yBAA0B,SAAQ,qBAAqB;IAClE,OAAgB,MAAM;;;;;MAAkC;IACxD,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,UAAU,CAA6B;IAE/C,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,EAErB;cAEkB,MAAM,IAAI,IAAI;CAyClC;AAED,eAAO,MAAM,gCAAgC;;;;CAIN,CAAA;AAEvC,qBAAa,0BAA2B,SAAQ,qBAAqB;IACnE,OAAgB,MAAM;;;;MAAmC;cAEtC,MAAM,IAAI,IAAI;CAkBlC;AAED,eAAO,MAAM,8BAA8B;;;;CAIJ,CAAA;AAEvC,qBAAa,wBAAyB,SAAQ,qBAAqB;IACjE,OAAgB,MAAM;;;;MAAiC;IACvD,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,UAAU,CAA6B;cAE5B,MAAM,IAAI,IAAI;IA0BjC,OAAO,CAAC,MAAM;CAef;AAID,eAAO,MAAM,8BAA8B;;;;;;;;CAMJ,CAAA;AAEvC,qBAAa,wBAAyB,SAAQ,qBAAqB;IACjE,OAAgB,MAAM;;;;;;;;MAAiC;IACvD,OAAO,CAAC,YAAY,CAAyB;IAC7C,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,MAAM,CAA+B;cAE1B,MAAM,IAAI,IAAI;IAoCjC,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,MAAM;CA2Bf"}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { bindLumenApprovalCard, createLumenPromptComposerController, normalizeLumenPromptLimit, resolveLumenCitationHref } from '@santi020k/lumen-core';
|
|
2
|
+
import { LumenElement } from '../element-base.js';
|
|
3
|
+
const node = (root, tag, className = '') => {
|
|
4
|
+
const element = root.ownerDocument.createElement(tag);
|
|
5
|
+
element.className = className;
|
|
6
|
+
return element;
|
|
7
|
+
};
|
|
8
|
+
const booleanAttribute = (root, name) => root.hasAttribute(name) && root.getAttribute(name) !== 'false';
|
|
9
|
+
const approvalDisabled = (root) => booleanAttribute(root, 'disabled') || root.dataset.status !== 'pending' || !root.dataset.requestId;
|
|
10
|
+
class LumenAiSurfaceElement extends LumenElement {
|
|
11
|
+
cleanup;
|
|
12
|
+
connectedCallback() {
|
|
13
|
+
super.connectedCallback();
|
|
14
|
+
queueMicrotask(() => {
|
|
15
|
+
if (this.isConnected)
|
|
16
|
+
this.render();
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
disconnectedCallback() {
|
|
20
|
+
this.cleanup?.();
|
|
21
|
+
this.cleanup = undefined;
|
|
22
|
+
}
|
|
23
|
+
attributeChangedCallback() {
|
|
24
|
+
super.attributeChangedCallback();
|
|
25
|
+
if (this.isConnected)
|
|
26
|
+
this.render();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export const lumenPromptComposerElementConfig = {
|
|
30
|
+
baseClassName: 'ui-prompt-composer',
|
|
31
|
+
defaults: { 'data-ui-prompt-composer': '' },
|
|
32
|
+
observedAttributes: ['action', 'disabled', 'label', 'max-length', 'pending', 'send-label', 'stop-label', 'submit-on-enter', 'value'],
|
|
33
|
+
tagName: 'lumen-prompt-composer'
|
|
34
|
+
};
|
|
35
|
+
export class LumenPromptComposerElement extends LumenAiSurfaceElement {
|
|
36
|
+
static config = lumenPromptComposerElementConfig;
|
|
37
|
+
form;
|
|
38
|
+
input;
|
|
39
|
+
label;
|
|
40
|
+
send;
|
|
41
|
+
stop;
|
|
42
|
+
get value() {
|
|
43
|
+
return this.input?.value ?? this.getAttribute('value') ?? '';
|
|
44
|
+
}
|
|
45
|
+
set value(value) {
|
|
46
|
+
this.setAttribute('value', value);
|
|
47
|
+
}
|
|
48
|
+
attributeChangedCallback(name) {
|
|
49
|
+
super.attributeChangedCallback();
|
|
50
|
+
if (name === 'value' && this.input) {
|
|
51
|
+
this.input.defaultValue = this.getAttribute('value') ?? '';
|
|
52
|
+
this.input.value = this.input.defaultValue;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
render() {
|
|
56
|
+
if (!this.form)
|
|
57
|
+
this.create();
|
|
58
|
+
const elements = this.elements();
|
|
59
|
+
if (!elements)
|
|
60
|
+
return;
|
|
61
|
+
const { form, input, label, send, stop } = elements;
|
|
62
|
+
this.cleanup?.();
|
|
63
|
+
this.dataset.pending = String(booleanAttribute(this, 'pending'));
|
|
64
|
+
this.dataset.disabled = String(booleanAttribute(this, 'disabled'));
|
|
65
|
+
this.dataset.submitOnEnter = String(booleanAttribute(this, 'submit-on-enter'));
|
|
66
|
+
const action = this.getAttribute('action');
|
|
67
|
+
if (action !== null)
|
|
68
|
+
form.setAttribute('action', action);
|
|
69
|
+
else
|
|
70
|
+
form.removeAttribute('action');
|
|
71
|
+
input.maxLength = normalizeLumenPromptLimit(Number(this.getAttribute('max-length')));
|
|
72
|
+
label.textContent = this.getAttribute('label') ?? 'Message';
|
|
73
|
+
send.textContent = this.getAttribute('send-label') ?? 'Send';
|
|
74
|
+
stop.textContent = this.getAttribute('stop-label') ?? 'Stop';
|
|
75
|
+
const controller = createLumenPromptComposerController(this);
|
|
76
|
+
this.cleanup = () => {
|
|
77
|
+
controller.destroy();
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
elements() {
|
|
81
|
+
if (!this.form || !this.input || !this.label || !this.send || !this.stop)
|
|
82
|
+
return undefined;
|
|
83
|
+
return { form: this.form, input: this.input, label: this.label, send: this.send, stop: this.stop };
|
|
84
|
+
}
|
|
85
|
+
create() {
|
|
86
|
+
const children = [...this.childNodes];
|
|
87
|
+
this.form = node(this, 'form', 'ui-form');
|
|
88
|
+
this.form.method = 'post';
|
|
89
|
+
this.label = node(this, 'label', 'ui-label');
|
|
90
|
+
this.input = node(this, 'textarea', 'ui-textarea');
|
|
91
|
+
this.input.id = `prompt-${this.ownerDocument.defaultView?.crypto.randomUUID() ?? crypto.randomUUID()}`;
|
|
92
|
+
this.input.rows = 3;
|
|
93
|
+
this.input.defaultValue = this.getAttribute('value') ?? '';
|
|
94
|
+
this.input.required = true;
|
|
95
|
+
this.input.name = 'prompt';
|
|
96
|
+
this.input.dataset.uiPromptInput = '';
|
|
97
|
+
this.label.htmlFor = this.input.id;
|
|
98
|
+
this.send = node(this, 'button', 'ui-button');
|
|
99
|
+
this.send.type = 'submit';
|
|
100
|
+
this.send.dataset.uiPromptSend = '';
|
|
101
|
+
this.stop = node(this, 'button', 'ui-button ui-button--secondary');
|
|
102
|
+
this.stop.type = 'button';
|
|
103
|
+
this.stop.dataset.uiPromptStop = '';
|
|
104
|
+
const actions = node(this, 'div', 'ui-prompt-composer__actions');
|
|
105
|
+
actions.append(this.send, this.stop);
|
|
106
|
+
this.form.append(this.label, this.input, actions, ...children);
|
|
107
|
+
this.append(this.form);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
export const lumenStreamMessageElementConfig = {
|
|
111
|
+
baseClassName: 'ui-stream-message ui-message ui-message--assistant',
|
|
112
|
+
observedAttributes: ['label', 'status', 'status-label', 'text'],
|
|
113
|
+
role: 'article',
|
|
114
|
+
tagName: 'lumen-stream-message'
|
|
115
|
+
};
|
|
116
|
+
export class LumenStreamMessageElement extends LumenAiSurfaceElement {
|
|
117
|
+
static config = lumenStreamMessageElementConfig;
|
|
118
|
+
content;
|
|
119
|
+
statusText;
|
|
120
|
+
get text() {
|
|
121
|
+
return this.content?.textContent ?? this.getAttribute('text') ?? '';
|
|
122
|
+
}
|
|
123
|
+
set text(value) {
|
|
124
|
+
this.setAttribute('text', value);
|
|
125
|
+
}
|
|
126
|
+
render() {
|
|
127
|
+
if (!this.content) {
|
|
128
|
+
const children = [...this.childNodes];
|
|
129
|
+
const actions = this.querySelector('[slot="actions"]');
|
|
130
|
+
const sources = this.querySelector('[slot="sources"]');
|
|
131
|
+
this.content = node(this, 'div', 'ui-prose');
|
|
132
|
+
this.content.dataset.uiStreamContent = '';
|
|
133
|
+
this.content.setAttribute('aria-live', 'off');
|
|
134
|
+
this.statusText = node(this, 'span');
|
|
135
|
+
this.statusText.setAttribute('role', 'status');
|
|
136
|
+
this.statusText.setAttribute('aria-live', 'polite');
|
|
137
|
+
const footer = node(this, 'div', 'ui-stream-message__actions');
|
|
138
|
+
footer.append(this.statusText);
|
|
139
|
+
if (actions)
|
|
140
|
+
footer.append(actions);
|
|
141
|
+
this.content.append(...children.filter(child => child !== actions && child !== sources));
|
|
142
|
+
this.append(this.content, footer);
|
|
143
|
+
if (sources)
|
|
144
|
+
this.append(sources);
|
|
145
|
+
}
|
|
146
|
+
this.dataset.status = this.getAttribute('status') ?? 'idle';
|
|
147
|
+
this.setAttribute('aria-label', this.getAttribute('label') ?? 'Assistant');
|
|
148
|
+
this.content.setAttribute('aria-busy', String(this.dataset.status === 'streaming'));
|
|
149
|
+
if (this.hasAttribute('text'))
|
|
150
|
+
this.content.textContent = this.getAttribute('text') ?? '';
|
|
151
|
+
if (this.statusText)
|
|
152
|
+
this.statusText.textContent = this.getAttribute('status-label') ?? 'Ready';
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
export const lumenSourceCitationElementConfig = {
|
|
156
|
+
baseClassName: 'ui-source-citation',
|
|
157
|
+
observedAttributes: ['href', 'label', 'target'],
|
|
158
|
+
tagName: 'lumen-source-citation'
|
|
159
|
+
};
|
|
160
|
+
export class LumenSourceCitationElement extends LumenAiSurfaceElement {
|
|
161
|
+
static config = lumenSourceCitationElementConfig;
|
|
162
|
+
render() {
|
|
163
|
+
const href = resolveLumenCitationHref(this.getAttribute('href') ?? '');
|
|
164
|
+
const label = this.getAttribute('label') ?? 'Source';
|
|
165
|
+
if (href) {
|
|
166
|
+
const anchor = node(this, 'a', 'ui-link');
|
|
167
|
+
anchor.href = href;
|
|
168
|
+
anchor.rel = 'noopener noreferrer';
|
|
169
|
+
anchor.target = this.getAttribute('target') === '_blank' ? '_blank' : '_self';
|
|
170
|
+
anchor.textContent = label;
|
|
171
|
+
this.replaceChildren(anchor);
|
|
172
|
+
}
|
|
173
|
+
else
|
|
174
|
+
this.textContent = label;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
export const lumenToolActivityElementConfig = {
|
|
178
|
+
baseClassName: 'ui-tool-activity',
|
|
179
|
+
observedAttributes: ['label', 'open', 'status', 'status-label'],
|
|
180
|
+
tagName: 'lumen-tool-activity'
|
|
181
|
+
};
|
|
182
|
+
export class LumenToolActivityElement extends LumenAiSurfaceElement {
|
|
183
|
+
static config = lumenToolActivityElementConfig;
|
|
184
|
+
details;
|
|
185
|
+
summary;
|
|
186
|
+
statusText;
|
|
187
|
+
render() {
|
|
188
|
+
if (!this.details)
|
|
189
|
+
this.create();
|
|
190
|
+
if (!this.details || !this.summary || !this.statusText)
|
|
191
|
+
return;
|
|
192
|
+
this.details.open = this.hasAttribute('open');
|
|
193
|
+
this.summary.textContent = this.getAttribute('label') ?? 'Tool activity';
|
|
194
|
+
this.statusText.textContent = this.getAttribute('status-label') ?? 'Queued';
|
|
195
|
+
this.dataset.status = this.getAttribute('status') ?? 'queued';
|
|
196
|
+
this.cleanup?.();
|
|
197
|
+
const toggle = () => {
|
|
198
|
+
this.toggleAttribute('open', this.details?.open ?? false);
|
|
199
|
+
};
|
|
200
|
+
this.details.addEventListener('toggle', toggle);
|
|
201
|
+
this.cleanup = () => {
|
|
202
|
+
this.details?.removeEventListener('toggle', toggle);
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
create() {
|
|
206
|
+
const children = [...this.childNodes];
|
|
207
|
+
this.details = node(this, 'details', 'ui-collapsible');
|
|
208
|
+
this.summary = node(this, 'summary');
|
|
209
|
+
this.statusText = node(this, 'span');
|
|
210
|
+
this.statusText.setAttribute('role', 'status');
|
|
211
|
+
this.details.append(this.summary, this.statusText, ...children);
|
|
212
|
+
this.append(this.details);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
const approvalStatusLabel = (root) => root.getAttribute('status-label') ?? `Decision: ${root.getAttribute('status') ?? 'pending'}`;
|
|
216
|
+
export const lumenApprovalCardElementConfig = {
|
|
217
|
+
baseClassName: 'ui-approval-card ui-card',
|
|
218
|
+
defaults: { 'data-ui-approval-card': '' },
|
|
219
|
+
observedAttributes: ['approve-label', 'disabled', 'label', 'reject-label', 'request-id', 'status', 'status-label'],
|
|
220
|
+
role: 'group',
|
|
221
|
+
tagName: 'lumen-approval-card'
|
|
222
|
+
};
|
|
223
|
+
export class LumenApprovalCardElement extends LumenAiSurfaceElement {
|
|
224
|
+
static config = lumenApprovalCardElementConfig;
|
|
225
|
+
titleElement;
|
|
226
|
+
statusText;
|
|
227
|
+
approve;
|
|
228
|
+
reject;
|
|
229
|
+
render() {
|
|
230
|
+
if (!this.titleElement)
|
|
231
|
+
this.create();
|
|
232
|
+
const elements = this.elements();
|
|
233
|
+
if (!elements)
|
|
234
|
+
return;
|
|
235
|
+
const { title, statusText, approve, reject } = elements;
|
|
236
|
+
title.textContent = this.getAttribute('label') ?? 'Review action';
|
|
237
|
+
this.setAttribute('aria-label', title.textContent);
|
|
238
|
+
statusText.textContent = approvalStatusLabel(this);
|
|
239
|
+
this.dataset.requestId = this.getAttribute('request-id') ?? '';
|
|
240
|
+
this.dataset.status = this.getAttribute('status') ?? 'pending';
|
|
241
|
+
this.dataset.disabled = String(booleanAttribute(this, 'disabled'));
|
|
242
|
+
const disabled = approvalDisabled(this);
|
|
243
|
+
approve.disabled = disabled;
|
|
244
|
+
reject.disabled = disabled;
|
|
245
|
+
approve.textContent = this.getAttribute('approve-label') ?? 'Approve';
|
|
246
|
+
reject.textContent = this.getAttribute('reject-label') ?? 'Reject';
|
|
247
|
+
this.cleanup?.();
|
|
248
|
+
this.cleanup = bindLumenApprovalCard(this);
|
|
249
|
+
}
|
|
250
|
+
elements() {
|
|
251
|
+
if (!this.titleElement || !this.statusText || !this.approve || !this.reject)
|
|
252
|
+
return undefined;
|
|
253
|
+
return { title: this.titleElement, statusText: this.statusText, approve: this.approve, reject: this.reject };
|
|
254
|
+
}
|
|
255
|
+
create() {
|
|
256
|
+
const children = [...this.childNodes];
|
|
257
|
+
this.titleElement = node(this, 'strong');
|
|
258
|
+
this.statusText = node(this, 'span');
|
|
259
|
+
this.statusText.setAttribute('role', 'status');
|
|
260
|
+
this.approve = node(this, 'button', 'ui-button');
|
|
261
|
+
this.approve.type = 'button';
|
|
262
|
+
this.approve.dataset.uiApprovalResponse = 'approve';
|
|
263
|
+
this.reject = node(this, 'button', 'ui-button ui-button--secondary');
|
|
264
|
+
this.reject.type = 'button';
|
|
265
|
+
this.reject.dataset.uiApprovalResponse = 'reject';
|
|
266
|
+
const actions = node(this, 'div', 'ui-approval-card__actions');
|
|
267
|
+
actions.append(this.approve, this.reject);
|
|
268
|
+
this.append(this.titleElement, ...children, this.statusText, actions);
|
|
269
|
+
}
|
|
270
|
+
}
|