@ixfx/components 0.7.0 → 0.7.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/bundle/index.d.ts +235 -27
- package/bundle/index.d.ts.map +1 -1
- package/bundle/index.js +799 -124
- package/bundle/index.js.map +1 -1
- package/dist/ac-text.d.ts +1 -1
- package/dist/ac-text.js +1 -1
- package/dist/{ac-token-BAa6ke09.d.ts → ac-token--_vCHXWw.d.ts} +2 -2
- package/dist/{ac-token-BAa6ke09.d.ts.map → ac-token--_vCHXWw.d.ts.map} +1 -1
- package/dist/ac-token.d.ts +1 -1
- package/dist/ac-token.js +1 -1
- package/dist/{button-Dat2yHAU.js → button-DsFbV4XD.js} +3 -3
- package/dist/{button-Dat2yHAU.js.map → button-DsFbV4XD.js.map} +1 -1
- package/dist/button.d.ts.map +1 -1
- package/dist/button.js +1 -1
- package/dist/{colour-picker-BSDBL-QL.js → colour-picker-Ddsk-7E_.js} +2 -2
- package/dist/{colour-picker-BSDBL-QL.js.map → colour-picker-Ddsk-7E_.js.map} +1 -1
- package/dist/colour-picker.js +1 -1
- package/dist/crumbs.d.ts +1 -1
- package/dist/crumbs.js +1 -1
- package/dist/{data-grid-C8qIo1-u.d.ts → data-grid-Bh4YrQGK.d.ts} +2 -2
- package/dist/{data-grid-C8qIo1-u.d.ts.map → data-grid-Bh4YrQGK.d.ts.map} +1 -1
- package/dist/data-grid.d.ts +1 -1
- package/dist/data-grid.js +1 -1
- package/dist/{defaults-BkWCPJFL.js → defaults-BJwDsMH4.js} +26 -2
- package/dist/defaults-BJwDsMH4.js.map +1 -0
- package/dist/{hex-editor-Bk6rxhfg.js → hex-editor-BiRfwTz1.js} +2 -2
- package/dist/{hex-editor-Bk6rxhfg.js.map → hex-editor-BiRfwTz1.js.map} +1 -1
- package/dist/hex.js +1 -1
- package/dist/{icon-DpA9x2Ve.d.ts → icon-CDGprSdE.d.ts} +1 -12
- package/dist/icon-CDGprSdE.d.ts.map +1 -0
- package/dist/{icon-CvnPanhA.js → icon-DcEEGQa_.js} +37 -8
- package/dist/icon-DcEEGQa_.js.map +1 -0
- package/dist/icons.d.ts +3 -3
- package/dist/icons.js +4 -4
- package/dist/icons.js.map +1 -1
- package/dist/{index-CKtLhgYj.d.ts → index-9AhaHIT2.d.ts} +3 -3
- package/dist/{index-CKtLhgYj.d.ts.map → index-9AhaHIT2.d.ts.map} +1 -1
- package/dist/{index-BtGFYfaK.d.ts → index-CS9yM8L-.d.ts} +14 -4
- package/dist/index-CS9yM8L-.d.ts.map +1 -0
- package/dist/index.d.ts +223 -23
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +674 -106
- package/dist/index.js.map +1 -1
- package/dist/{menu-BjRvlgPy.js → menu-CXDFJxNm.js} +3 -3
- package/dist/{menu-BjRvlgPy.js.map → menu-CXDFJxNm.js.map} +1 -1
- package/dist/{menu-item-Bs2MYyHq.d.ts → menu-item-CZi9vy5O.d.ts} +4 -2
- package/dist/menu-item-CZi9vy5O.d.ts.map +1 -0
- package/dist/{menu-item-B-zYrTTi.js → menu-item-D2S4i8u1.js} +16 -4
- package/dist/menu-item-D2S4i8u1.js.map +1 -0
- package/dist/menu.d.ts +2 -2
- package/dist/menu.js +2 -2
- package/dist/notification-pill-DyZydXoZ.d.ts.map +1 -1
- package/dist/notifier.js +2 -2
- package/dist/notifier.js.map +1 -1
- package/dist/panel.d.ts +1 -1
- package/dist/plots.js +1 -1
- package/dist/registry-BEtb8_wB.js +46 -0
- package/dist/registry-BEtb8_wB.js.map +1 -0
- package/dist/{tab-list-MPwq_1Jj.d.ts → tab-list-CGyPt07Z.d.ts} +9 -2
- package/dist/tab-list-CGyPt07Z.d.ts.map +1 -0
- package/dist/tabs.d.ts +1 -1
- package/dist/tabs.js +32 -13
- package/dist/tabs.js.map +1 -1
- package/dist/{titlebar-DaCfpliv.d.ts → titlebar-Bj5pfdw_.d.ts} +2 -2
- package/dist/{titlebar-DaCfpliv.d.ts.map → titlebar-Bj5pfdw_.d.ts.map} +1 -1
- package/dist/titlebar.d.ts +1 -1
- package/dist/titlebar.js +1 -1
- package/dist/tooltip-BlvBUQxx.d.ts.map +1 -1
- package/dist/{xy-axis-CxHC8z5E.js → xy-axis-DWizs0bt.js} +3 -3
- package/dist/xy-axis-DWizs0bt.js.map +1 -0
- package/docs-user/dock.md +166 -15
- package/docs-user/icons.md +4 -0
- package/docs-user/index.json +2 -2
- package/docs-user/tabs.md +20 -0
- package/docs-user/user-theming.md +109 -0
- package/package.json +1 -1
- package/dist/defaults-BkWCPJFL.js.map +0 -1
- package/dist/icon-CvnPanhA.js.map +0 -1
- package/dist/icon-DpA9x2Ve.d.ts.map +0 -1
- package/dist/index-BtGFYfaK.d.ts.map +0 -1
- package/dist/menu-item-B-zYrTTi.js.map +0 -1
- package/dist/menu-item-Bs2MYyHq.d.ts.map +0 -1
- package/dist/registry-CkW7q09Q.js +0 -21
- package/dist/registry-CkW7q09Q.js.map +0 -1
- package/dist/tab-list-MPwq_1Jj.d.ts.map +0 -1
- package/dist/xy-axis-CxHC8z5E.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xy-axis-DWizs0bt.js","names":["#options","#rangeManual","#recompute","#rangeAuto","#rangeStream","#renderIcon","customElement","#addToSeries","#ensurePlot","#seriesSet","#seriesOrder","#instances","#pendingStyles","#onSubPlotPointerMove","#onSubPlotPointerLeave","#escapeHTML","customElement","#bucketIndexFromPointer","#setInlineIndex","#updateBubbleTooltip","#hasProgrammaticData","#series","#parseDeclarativeData","#resetHoverState","#readCssVar","#computeGeometry","#getGapPx","#getBarLengthOverride","#computeBars","#valueRefreshTimer","#clearValueRefreshTimer","#scheduleValueRefresh","#tooltipShowTimer","#tooltipHideTimer","#tooltipVisible","#tooltipIndex","#tooltipPosition","#clearBubbleTooltip","#tooltipPositionFor","#refreshBubbleText","#formatBarAt","#emitClick","#onPointerMove","#onPointerLeave","customElement","#lastClientX","#lastClientY","#updateTooltip","#getIndexFromX","#series","#hasProgrammaticData","#updateTooltipAtLastPos","#parseDeclarativeData","#computePoints","#renderByStyle","#onPointerMove","#onPointerLeave","#onClick","customElement","#lastClientX","#lastClientY","#updateTooltip","#findNearestPoint","#lastPoints","#xSeries","#ySeries","#updateTooltipAtLastPos","#computePoints","#computeColours","#onPointerMove","#onPointerLeave","#onClick","customElement"],"sources":["../src/plots/colour-map.ts","../src/plots/data.ts","../src/util/is-numeric.ts","../src/util/tooltip.ts","../src/plots/svg-utils.ts","../src/plots/multi-axis.ts","../src/plots/plot-histogram.ts","../src/plots/single-axis.ts","../src/plots/xy-axis.ts"],"sourcesContent":["/**\n * Colour mapping for plot components.\n *\n * Pipeline:\n * scaledValue (0..1)\n * → applyMapping (easing / custom fn)\n * → computeColour (mode → ColourResult)\n * → applyAgeModification (xy-axis only, compounds age-style on top)\n */\nimport type { EasingName } from '@ixfx/modulation';\nimport { Easings } from '@ixfx/modulation';\nimport { Colour } from '@ixfx/visual';\n\n// --- Types ---\n\nexport type ColourMode = `fixed` | `opacity` | `hue` | `saturation` | `lightness` | `scale`;\n\nexport type ColourMapConfig = {\n mode: ColourMode;\n /** Parsed colours for 'scale' mode. Must have ≥ 2 entries. */\n palette: string[];\n /** ixfx easing name — applied before the colour mode mapping. Takes precedence over valueMap. */\n easingName: string;\n /** Custom value mapping fn (0..1 → 0..1). Used when easingName is empty. */\n valueMap: ((v: number) => number) | null;\n};\n\nexport type ColourResult = { fill: string; opacity: number };\n\n// --- Defaults ---\n\nconst DEFAULT_BASE = `oklch(60% 0.15 140)`;\nconst DEFAULT_PALETTE = [`green`, `yellow`, `red`];\n\n// --- Scale cache: keyed by palette string to avoid recomputing colour steps every render ---\n\nconst _scaleCache = new Map<string, string[]>();\n\nfunction getScaleSteps(palette: string[]): string[] {\n const key = palette.join(`\\x00`);\n if (!_scaleCache.has(key)) {\n _scaleCache.set(key, Colour.scale(palette as Parameters<typeof Colour.scale>[0], { stepsBetween: 99 }));\n }\n return _scaleCache.get(key)!;\n}\n\n// --- Helpers ---\n\n/** Resolve a CSS custom property to its final value, handling var() references. */\nfunction resolveCssVariable(el: Element, prop: string): string {\n const style = getComputedStyle(el);\n let value = style.getPropertyValue(prop).trim();\n\n // Handle var() references - resolve up to 5 levels deep\n const varRegex = /var\\((--[\\w-]+)(?:,\\s*(.*))?\\)/g;\n for (let i = 0; i < 5 && value.includes(`var(`); i++) {\n value = value.replace(varRegex, (_, varName, fallback) => {\n const resolved = style.getPropertyValue(varName).trim();\n if (resolved)\n return resolved;\n if (fallback)\n return fallback.trim();\n return ``;\n });\n }\n\n return value;\n}\n\n/** Read the resolved --plot-color CSS variable from an element. */\nexport function readBaseColour(el: Element): string {\n const v = resolveCssVariable(el, `--plot-color`);\n return v || DEFAULT_BASE;\n}\n\n/** Parse a comma-separated colour string attribute into an array. Falls back to default palette. */\nexport function parseColourScaleAttr(attr: string): string[] {\n if (!attr.trim())\n return DEFAULT_PALETTE;\n const parsed = attr.split(`,`).map(s => s.trim()).filter(Boolean);\n return parsed.length >= 2 ? parsed : DEFAULT_PALETTE;\n}\n\n/** Parse any CSS colour string to HSL scalars (h, s, l all 0..1). */\nfunction toHslScalar(css: string): { h: number; s: number; l: number } {\n try {\n const hsl = Colour.HslSpace.fromCss(css, { scalar: true });\n return { h: hsl.h, s: hsl.s, l: hsl.l };\n } catch {\n return { h: 0.39, s: 0.5, l: 0.55 }; // ~green fallback\n }\n}\n\n/** Apply easing or custom mapping to a 0..1 value. Returns clamped 0..1. */\nfunction applyMapping(v: number, config: ColourMapConfig): number {\n const clamped = Math.max(0, Math.min(1, v));\n if (config.easingName) {\n try {\n return Math.max(0, Math.min(1, Easings.get(config.easingName as EasingName)(clamped)));\n } catch { /* invalid easing name — fall through */ }\n }\n if (config.valueMap) {\n return Math.max(0, Math.min(1, config.valueMap(clamped)));\n }\n return clamped;\n}\n\n// --- Main colour computation ---\n\n/**\n * Compute the fill colour and opacity for a single data point.\n * @param scaledValue Normalised value in 0..1 (data range for single-axis; age fraction for xy).\n * @param baseColour Resolved base colour string (from --plot-color).\n * @param config Colour map configuration.\n */\nexport function computeColour(scaledValue: number, baseColour: string, config: ColourMapConfig): ColourResult {\n const mapped = applyMapping(scaledValue, config);\n\n switch (config.mode) {\n case `fixed`:\n return { fill: baseColour, opacity: 1 };\n\n case `opacity`:\n return { fill: baseColour, opacity: Math.max(0.04, mapped) };\n\n case `hue`: {\n const hsl = toHslScalar(baseColour);\n return {\n fill: `hsl(${Math.round(mapped * 360)}deg ${Math.round(hsl.s * 100)}% ${Math.round(hsl.l * 100)}%)`,\n opacity: 1,\n };\n }\n\n case `saturation`: {\n const hsl = toHslScalar(baseColour);\n return {\n fill: `hsl(${Math.round(hsl.h * 360)}deg ${Math.round(mapped * 100)}% ${Math.round(hsl.l * 100)}%)`,\n opacity: 1,\n };\n }\n\n case `lightness`: {\n const hsl = toHslScalar(baseColour);\n return {\n fill: `hsl(${Math.round(hsl.h * 360)}deg ${Math.round(hsl.s * 100)}% ${Math.round(mapped * 100)}%)`,\n opacity: 1,\n };\n }\n\n case `scale`: {\n const palette = config.palette.length >= 2 ? config.palette : DEFAULT_PALETTE;\n const steps = getScaleSteps(palette);\n const idx = Math.min(steps.length - 1, Math.floor(mapped * steps.length));\n return { fill: steps[idx], opacity: 1 };\n }\n\n default:\n return { fill: baseColour, opacity: 1 };\n }\n}\n\n/**\n * Apply xy-axis age-style modification on top of a base ColourResult.\n * 'size' is not handled here — the caller adjusts the radius separately.\n */\nexport function applyAgeModification(base: ColourResult, ageFraction: number, ageStyle: string): ColourResult {\n if (ageStyle === `opacity`) {\n return { ...base, opacity: base.opacity * Math.max(0.08, ageFraction ** 0.6) };\n }\n if (ageStyle === `desaturation`) {\n const hsl = toHslScalar(base.fill);\n const sFaded = hsl.s * ageFraction; // older → less saturation\n return {\n fill: `hsl(${Math.round(hsl.h * 360)}deg ${Math.round(sFaded * 100)}% ${Math.round(hsl.l * 100)}%)`,\n opacity: base.opacity,\n };\n }\n return base;\n}\n","import { rangeStream } from \"@ixfx/numbers\";\n\nexport type PlotDataSeriesOptions = {\n /**\n * Limit of how many data points to store.\n * Default: 100\n */\n capacityLimit: number;\n /**\n * If _true_, it maintains the same scale over its lifetime.\n * If _false_, scale adjusts based on items in its cache.\n *\n * Default: true\n */\n persistentScaling: boolean;\n\n fixedRange: { min: number; max: number } | null;\n};\n\n/**\n * A data series\n */\nexport class PlotDataSeries {\n values: number[] = [];\n #rangeStream = rangeStream();\n #rangeAuto: { min: number; max: number } = { min: 0, max: 0 };\n #rangeManual: { min: number; max: number } | null = null;\n #options: PlotDataSeriesOptions;\n\n /**\n * Constructor.\n *\n * Default options:\n * - `capacityLimit`: 100\n * - `persistentScaling`: true\n * - `fixedRange`: null\n * @param options\n */\n constructor(options: Partial<PlotDataSeriesOptions> = {}) {\n this.#options = {\n capacityLimit: 100,\n persistentScaling: true,\n fixedRange: null,\n ...options,\n };\n if (this.#options.fixedRange !== null) {\n this.#rangeManual = this.#options.fixedRange;\n }\n }\n\n /**\n * Sets a manual range, this disabled auto-scaling.\n * Use {@link unsetRange} to re-enable auto-scaling.\n * @param min\n * @param max\n */\n setRange(min: number, max: number) {\n this.#rangeManual = { min, max };\n }\n\n /**\n * Disable the manual range\n */\n unsetRange() {\n this.#rangeManual = null;\n this.#recompute();\n }\n\n get isAutoRange() {\n return this.#rangeManual === null;\n }\n\n /**\n * Adds a single value\n * @param valueOrValues Value to add\n */\n add(valueOrValues: number | number[]) {\n if (typeof valueOrValues === `number`) {\n this.values.push(valueOrValues);\n if (this.isAutoRange) {\n this.#rangeAuto = this.#rangeStream.seen(valueOrValues);\n }\n } else {\n this.values.push(...valueOrValues);\n if (this.isAutoRange) {\n for (const v of valueOrValues) {\n this.#rangeAuto = this.#rangeStream.seen(v);\n }\n }\n }\n if (this.values.length > this.#options.capacityLimit) {\n this.values = this.values.slice(this.values.length - this.#options.capacityLimit);\n if (!this.#options.persistentScaling && this.isAutoRange) {\n this.#recompute();\n }\n }\n }\n\n #recompute() {\n if (!this.#options.persistentScaling) {\n this.#rangeStream = rangeStream();\n }\n for (let i = 0; i < this.values.length; i++) {\n this.#rangeAuto = this.#rangeStream.seen(this.values[i]);\n }\n }\n\n /**\n * Sets the entire data series at once, replacing any existing data. If the number of values exceeds the `capacityLimit`, only the most recent values up to the limit are kept.\n * @param values\n */\n set(values: number[]) {\n if (values.length > this.#options.capacityLimit) {\n values = values.slice(values.length - this.#options.capacityLimit);\n }\n this.values = values;\n this.#recompute();\n }\n\n /**\n * Returns the manual range if this is in effect, or the automatic\n */\n get range() {\n if (this.#rangeManual)\n return this.#rangeManual;\n return this.#rangeAuto;\n }\n\n /**\n * Clear all data and reset range. If `persistentScaling` is _false_, also resets scaling to initial state.\n * @returns _true_ if there was data to clear\n */\n clear(): boolean {\n const empty = this.values.length === 0;\n this.values = [];\n if (!this.#options.persistentScaling) {\n this.#recompute();\n }\n return !empty;\n }\n}","export function isNumeric(str: unknown): boolean {\n if (typeof str === `number`)\n return true;\n if (typeof str !== `string`)\n return false;\n const trimmed = str.trim();\n return trimmed !== `` && !Number.isNaN(Number(trimmed));\n}","import { html, LitElement, nothing } from \"lit\";\nimport { property } from \"lit/decorators.js\";\nimport { classMap } from \"lit/directives/class-map.js\";\nimport { unsafeHTML } from \"lit/directives/unsafe-html.js\";\nimport { hasIcon } from \"../icons/index.js\";\nimport { safeCustomElement as customElement } from \"./custom-elements.js\";\nimport { isNumeric } from \"./is-numeric.js\";\n\nexport type FormatValueForHuman = (v: unknown) => string;\nexport type TooltipOrientations = `top` | `right` | `bottom` | `left`;\n\n// `ixfx-tooltip` renders to light DOM (see createRenderRoot() below) so it can inherit\n// styling from whatever shadow root it's embedded in (e.g. range-input bundles its own\n// tooltipValueStyles for a scoped bubble-arrow look). That means Lit's `static styles`\n// mechanism can't apply here (it needs adoptedStyleSheets, only available on a ShadowRoot\n// or Document) - so a *standalone* `ixfx-tooltip` (appended directly to <body>, not nested\n// in another component's shadow root) gets no styling at all unless something supplies it.\n// This injects that baseline once, globally, scoped to the bare tag so it never leaks into\n// (or fights with) a host component's own shadow-scoped tooltip styles.\nlet _baseStylesInjected = false;\nfunction ensureBaseTooltipStyles(): void {\n if (_baseStylesInjected)\n return;\n _baseStylesInjected = true;\n const style = document.createElement(`style`);\n style.textContent = `\n ixfx-tooltip {\n display: inline-block;\n background: var(--surface-5);\n color: var(--surface-5-text);\n border: var(--border);\n border-radius: var(--radius-l, 6px);\n box-shadow: var(--shadow-m);\n padding: var(--space-s, 4px);\n font-size: 10px;\n font-family: var(--font-family, inherit);\n }\n ixfx-tooltip .tooltip-type-number {\n font-family: var(--font-mono, ui-monospace, monospace);\n }\n `;\n document.head.appendChild(style);\n}\n\n@customElement(`ixfx-tooltip`)\nexport class TooltipElement extends LitElement {\n override connectedCallback(): void {\n super.connectedCallback();\n ensureBaseTooltipStyles();\n }\n\n static numberFormatter = (v: number) => Math.floor(v).toString();\n\n static defaultFormatter: FormatValueForHuman = (v) => {\n if (typeof v === `number`) {\n if (Number.isInteger(v))\n return v.toString();\n return v.toFixed(2);\n } else if (typeof v === `string`) {\n return v;\n } else {\n return JSON.stringify(v);\n }\n };\n\n valueFormatTooltip: FormatValueForHuman = TooltipElement.defaultFormatter;\n\n @property({ type: String })\n orientation: TooltipOrientations = `top`;\n\n @property({ type: String })\n anchor = `--tooltip`;\n\n @property()\n value: unknown;\n\n @property({ type: String })\n icon?: string;\n\n #renderIcon() {\n if (!this.icon)\n return nothing;\n\n if (this.icon.startsWith(`<svg`)) {\n return html`<span class=\"tooltip-icon\" style=\"display:inline-flex;align-items:center;margin-right:0.25em\">${unsafeHTML(this.icon)}</span>`;\n }\n\n if (!hasIcon(this.icon))\n return nothing;\n\n return html`<ixfx-icon class=\"tooltip-icon\" style=\"margin-right:0.25em\" name=\"${this.icon}\"></ixfx-icon>`;\n }\n\n protected render() {\n const classes = {\n \"tooltip\": true,\n \"tooltip-orientation-top\": this.orientation === `top`,\n \"tooltip-orientation-bottom\": this.orientation === `bottom`,\n \"tooltip-orientation-right\": this.orientation === `right`,\n \"tooltip-orientation-left\": this.orientation === `left`,\n \"tooltip-type-text\": true,\n \"tooltip-type-number\": false,\n \"tooltip-style-bubble\": true,\n };\n let value = ``;\n switch (typeof this.value) {\n case `number`:\n classes[`tooltip-type-number`] = true;\n value = this.valueFormatTooltip(this.value);\n break;\n case `string`:\n if (isNumeric(this.value)) {\n classes[`tooltip-type-number`] = true;\n value = this.valueFormatTooltip(Number.parseFloat(this.value));\n } else {\n value = this.value;\n }\n break;\n default:\n value = JSON.stringify(this.value);\n }\n return html`<output style=\"--anchor-id: ${this.anchor}\" class=${classMap(classes)}>${this.#renderIcon()}${value}</output>`;\n }\n\n protected createRenderRoot() {\n return this;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ixfx-tooltip\": TooltipElement;\n }\n}\n","/**\n * Shared utilities for SVG-based plot components.\n */\nimport type { TooltipElement } from '../util/tooltip.js';\nimport '../util/tooltip.js';\n\n// --- Tooltip singleton ---\n\nlet _tooltipEl: HTMLDivElement | null = null;\nlet _tooltipOwner: Element | null = null;\n\nfunction ensureTooltip(): HTMLDivElement {\n if (_tooltipEl)\n return _tooltipEl;\n const el = document.createElement(`div`);\n el.style.cssText = `\n position: fixed;\n pointer-events: none;\n z-index: 9999;\n background: var(--surface-5);\n color: var(--surface-5-text);\n border: var(--border);\n border-radius: var(--radius-l, 6px);\n box-shadow: var(--shadow-m);\n padding: 2px 6px;\n font-size: 10px;\n font-family: ui-monospace, monospace;\n opacity: 0;\n transition: opacity 0.1s ease;\n `;\n document.body.appendChild(el);\n _tooltipEl = el;\n return el;\n}\n\nexport function showTooltip(owner: Element, clientX: number, clientY: number, text: string): void {\n const el = ensureTooltip();\n _tooltipOwner = owner;\n el.textContent = text;\n el.style.whiteSpace = `nowrap`;\n el.style.left = `${clientX + 14}px`;\n el.style.top = `${clientY + 14}px`;\n el.style.opacity = `1`;\n}\n\nexport function showTooltipHTML(owner: Element, clientX: number, clientY: number, html: string): void {\n const el = ensureTooltip();\n _tooltipOwner = owner;\n el.innerHTML = html;\n el.style.whiteSpace = `normal`;\n el.style.left = `${clientX + 14}px`;\n el.style.top = `${clientY + 14}px`;\n el.style.opacity = `1`;\n}\n\nexport function hideTooltip(owner: Element): void {\n if (_tooltipOwner !== owner)\n return;\n const el = ensureTooltip();\n el.style.opacity = `0`;\n _tooltipOwner = null;\n}\n\n// --- Bar/segment bubble tooltip (ixfx-tooltip based) ---\n//\n// Unlike showTooltip() above (which tracks the cursor directly), this variant is meant\n// for discrete hover targets (e.g. histogram buckets): the caller decides *when* to\n// (re)position it (typically only on a hovered-index change, not on every pointermove),\n// and where along the cross-axis it should sit (typically cursor-relative, captured once).\n\nlet _bubbleEl: TooltipElement | null = null;\nlet _bubbleOwner: Element | null = null;\n\n// Visual chrome (background/border/radius/shadow/padding/font) is intrinsic to `ixfx-tooltip`\n// itself (see ensureBaseTooltipStyles() in util/tooltip.ts) - only positioning/animation is set here.\nfunction ensureBubble(): TooltipElement {\n if (_bubbleEl)\n return _bubbleEl;\n const el = document.createElement(`ixfx-tooltip`) as TooltipElement;\n el.style.cssText = `\n position: fixed;\n z-index: 9999;\n pointer-events: none;\n opacity: 0;\n transition: opacity 0.12s ease;\n `;\n document.body.appendChild(el);\n _bubbleEl = el;\n return el;\n}\n\n/**\n * Shows/repositions an `ixfx-tooltip` bubble.\n * `mainClient` centers the bubble along the given axis (e.g. a bar's midpoint);\n * `crossClient` places it along the other axis (e.g. an offset from the cursor).\n */\nexport function showBubbleTooltip(owner: Element, text: string, mainClient: number, crossClient: number, orientation: `horizontal` | `vertical`): void {\n const el = ensureBubble();\n _bubbleOwner = owner;\n el.value = text;\n if (orientation === `horizontal`) {\n el.style.left = `${mainClient}px`;\n el.style.top = `${crossClient}px`;\n el.style.transform = `translate(-50%, -100%)`;\n } else {\n el.style.left = `${crossClient}px`;\n el.style.top = `${mainClient}px`;\n el.style.transform = `translate(0, -50%)`;\n }\n el.style.opacity = `1`;\n}\n\nexport function hideBubbleTooltip(owner: Element): void {\n if (_bubbleOwner !== owner)\n return;\n const el = ensureBubble();\n el.style.opacity = `0`;\n _bubbleOwner = null;\n}\n\n// --- Sizing helpers ---\n\n/** Stroke width proportional to the smaller dimension of the viewport. */\nexport function adaptiveStroke(width: number, height: number): number {\n return Math.max(1, Math.min(width, height) / 25);\n}\n\n/** Dot radius based on available space per data point and viewport height. */\nexport function adaptiveRadius(width: number, height: number, dataLength: number): number {\n if (dataLength === 0)\n return 3;\n const widthPerPoint = width / dataLength;\n return Math.max(1.5, Math.min(widthPerPoint * 0.45, height * 0.2, 8));\n}\n\n// --- Value scaling ---\n\n/** Normalize a value from [min, max] to [0, 1]. Returns 0.5 if range is zero. */\nexport function scaleValue(v: number, min: number, max: number): number {\n const range = max - min;\n return range === 0 ? 0.5 : (v - min) / range;\n}\n","import type { PlotSingleAxis, PlotSingleAxisPointerMoveDetail } from './single-axis.js';\nimport { css, html, LitElement } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { safeCustomElement as customElement } from '../util/custom-elements.js';\nimport { hideTooltip, showTooltipHTML } from './svg-utils.js';\n\nexport type PlotMultiAxisLayout = `overlap` | `horizontal` | `vertical` | `grid`;\n\nexport type PlotMultiAxisDataPointClickDetail = {\n readonly value: number;\n readonly index: number;\n readonly series: string;\n};\n\nexport type PlotMultiAxisDataPointClickEvent = CustomEvent<PlotMultiAxisDataPointClickDetail>;\n\nexport interface PlotMultiAxisElementEventMap {\n 'plot-datapoint-click': PlotMultiAxisDataPointClickEvent;\n}\n\nconst PLOT_PALETTE = [\n `oklch(60% 0.15 30)`,\n `oklch(60% 0.15 90)`,\n `oklch(60% 0.15 150)`,\n `oklch(60% 0.15 210)`,\n `oklch(60% 0.15 270)`,\n `oklch(60% 0.15 330)`,\n `oklch(60% 0.15 60)`,\n `oklch(60% 0.15 180)`,\n];\n\n@customElement(`ixfx-plot-multi-axis`)\n// eslint-disable-next-line ts/no-unsafe-declaration-merging\nexport class PlotMultiAxis extends LitElement {\n @property() layout: PlotMultiAxisLayout = `overlap`;\n\n @property({ attribute: `grid-min-width`, type: Number })\n gridMinWidth = 200;\n\n /** Override to customize tooltip value display. */\n valueFormat: (v: number | undefined) => string = v => v ? v.toFixed(2) : ``;\n\n #instances = new Map<string, PlotSingleAxis>();\n #seriesOrder: string[] = [];\n #seriesSet = new Set<string>();\n #pendingStyles = new Map<string, Record<string, string>>();\n\n /**\n * Adds a single data point\n * @param name Series name\n * @param value Value\n * @param witholdRedraw If _false_ (default) plot is automatically redrawn\n */\n addData(name: string, value: number, witholdRedraw = false): PlotSingleAxis {\n const el = this.#addToSeries(name, value, witholdRedraw);\n // if (witholdRedraw)\n // return el;\n // this.requestUpdate();\n // this.redraw();\n return el;\n }\n\n setData(name: string, values: number[], witholdRedraw = false): PlotSingleAxis {\n const [el, created] = this.#ensurePlot(name);\n if (!this.#seriesSet.has(name)) {\n this.#seriesSet.add(name);\n this.#seriesOrder.push(name);\n }\n el.set(values, witholdRedraw);\n // if (witholdRedraw)\n // return el;\n if (created)\n this.requestUpdate();\n return el;\n }\n\n setObjects(data: Record<string, number[]>, witholdRedraw = false): void {\n const entries = Object.entries(data);\n for (const [name, vals] of entries) {\n this.setData(name, vals, true);\n }\n if (witholdRedraw)\n return;\n // this.requestUpdate();\n this.redraw();\n }\n\n /**\n * Calls redraw() on all subplots.\n */\n redraw(): void {\n for (const el of this.#instances.values()) {\n el.redraw();\n }\n }\n\n /**\n * Adds a record of data points to the plot. Each key in the record corresponds to a series name, and its value is added as a data point to that series. If a series does not exist for a given key, it will be created.\n * @param data Data to add\n * @param witholdRedraw If _false_ (default) plot is automatically redrawn after adding the data. If _true_, plot is not redrawn automatically, and you need to call `redraw()` manually to update the plot after adding the data.\n */\n addObject(data: Record<string, number | number[]>, witholdRedraw = false): void {\n const entries = Object.entries(data);\n for (const [name, val] of entries) {\n this.#addToSeries(name, val, true);\n }\n if (witholdRedraw)\n return;\n // this.requestUpdate();\n this.redraw();\n }\n\n /**\n * Styles a series by setting CSS variables on the subplot.\n * @param name Name of series\n * @param styles Styles to apply\n */\n styleSeries(name: string, styles: Record<string, string>): void {\n const normalised: Record<string, string> = {};\n for (const [key, val] of Object.entries(styles)) {\n normalised[key.startsWith(`--`) ? key : `--${key}`] = val;\n }\n\n const el = this.#instances.get(name);\n if (!el) {\n this.#pendingStyles.set(name, normalised);\n return;\n }\n for (const [key, val] of Object.entries(normalised)) {\n el.style.setProperty(key, val);\n }\n }\n\n /**\n * Clears data from all sub-plots\n * @returns _True_ if there was data to clear\n */\n clear(): boolean {\n let cleared = false;\n for (const el of this.#instances.values()) {\n cleared = cleared || el.clear();\n }\n return cleared;\n }\n\n /**\n * Clears data from a given series\n * @param name Series name\n * @returns _True_ if series was found and had data\n */\n clearSeries(name: string): boolean {\n const el = this.#instances.get(name);\n if (el) {\n el.clear();\n return true;\n }\n return false;\n }\n\n /**\n * Returns a copy of the series names\n */\n get series(): string[] {\n return [...this.#seriesOrder];\n }\n\n #addToSeries(name: string, valueOrValues: number[] | number, withholdRedraw = false): PlotSingleAxis {\n const [el, created] = this.#ensurePlot(name);\n\n if (!this.#seriesSet.has(name)) {\n this.#seriesSet.add(name);\n this.#seriesOrder.push(name);\n }\n\n el.add(valueOrValues, withholdRedraw);\n if (created)\n this.requestUpdate();\n return el;\n }\n\n #ensurePlot(name: string): [el: PlotSingleAxis, created: boolean] {\n let el = this.#instances.get(name);\n if (el)\n return [el, false];\n\n el = document.createElement(`ixfx-plot-single-axis`) as PlotSingleAxis;\n el.tooltips = false;\n this.#instances.set(name, el);\n\n const colorIndex = this.#instances.size % PLOT_PALETTE.length;\n el.style.setProperty(`--plot-color`, PLOT_PALETTE[colorIndex]);\n\n const pending = this.#pendingStyles.get(name);\n if (pending) {\n for (const [key, val] of Object.entries(pending)) {\n el.style.setProperty(key, val);\n }\n this.#pendingStyles.delete(name);\n }\n\n el.addEventListener(`plot-datapoint-click`, (e: Event) => {\n const ce = e as CustomEvent<{ value: number; index: number }>;\n this.dispatchEvent(\n new CustomEvent<PlotMultiAxisDataPointClickDetail>(`plot-datapoint-click`, {\n detail: { ...ce.detail, series: name },\n bubbles: true,\n composed: true,\n }),\n );\n });\n\n el.addEventListener(`plot-pointer-move`, (e: Event) => {\n const ce = e as CustomEvent<PlotSingleAxisPointerMoveDetail>;\n this.#onSubPlotPointerMove(ce.detail.clientX, ce.detail.clientY, ce.detail.index);\n });\n\n el.addEventListener(`plot-pointer-leave`, () => {\n this.#onSubPlotPointerLeave();\n });\n\n return [el, true];\n }\n\n #onSubPlotPointerMove(clientX: number, clientY: number, index: number): void {\n if (index < 0) {\n hideTooltip(this);\n return;\n }\n\n const parts: string[] = [];\n for (const [name, inst] of this.#instances) {\n const val = inst.getValueAt(index);\n if (val === undefined)\n continue;\n const color = getComputedStyle(inst).getPropertyValue(`--plot-color`).trim();\n parts.push(`<span style=\"color:${color}\">${this.#escapeHTML(name)}</span> ${this.valueFormat(val)}`);\n }\n\n if (parts.length === 0) {\n hideTooltip(this);\n return;\n }\n\n showTooltipHTML(this, clientX, clientY, parts.join(`<br>`));\n }\n\n #onSubPlotPointerLeave(): void {\n hideTooltip(this);\n }\n\n #escapeHTML(s: string): string {\n return s.replace(/&/g, `&`).replace(/</g, `<`).replace(/>/g, `>`).replace(/\"/g, `"`);\n }\n\n protected override render() {\n const gridStyle = this.layout === `grid` ? `--grid-min-width: ${this.gridMinWidth}px` : ``;\n\n return html`\n <div\n id=\"container\"\n class=\"layout layout-${this.layout}\"\n part=\"container\"\n style=${gridStyle}\n >\n ${repeat(\n this.#seriesOrder,\n name => name,\n name => this.#ensurePlot(name)[0],\n )}\n </div>\n `;\n }\n\n static override styles = css`\n :host {\n display: block;\n width: 100%;\n height: 100%;\n min-height: 40px;\n --plot-color: var(--accent);\n }\n\n #container {\n width: 100%;\n height: 100%;\n }\n\n #container.layout-overlap {\n display: grid;\n }\n #container.layout-overlap > * {\n grid-area: 1 / 1;\n background: transparent;\n }\n\n #container.layout-horizontal {\n display: flex;\n flex-direction: row;\n gap: var(--space-s, 4px);\n }\n #container.layout-horizontal > * {\n flex: 1;\n min-width: 0;\n }\n\n #container.layout-vertical {\n display: flex;\n flex-direction: column;\n gap: var(--space-s, 4px);\n }\n #container.layout-vertical > * {\n flex: 1;\n min-height: 0;\n }\n\n #container.layout-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(var(--grid-min-width, 200px), 1fr));\n gap: var(--space-s, 4px);\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ixfx-plot-multi-axis': PlotMultiAxis;\n }\n}\n\n// eslint-disable-next-line ts/no-unsafe-declaration-merging\nexport interface PlotMultiAxis {\n addEventListener: {\n <K extends keyof PlotMultiAxisElementEventMap>(\n type: K,\n listener: (this: PlotMultiAxis, event: PlotMultiAxisElementEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions,\n ): void;\n (\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void;\n };\n}\n","/* eslint-disable ts/no-unsafe-declaration-merging */\nimport type { PropertyValues } from 'lit';\nimport { css, html, LitElement, svg } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { safeCustomElement as customElement } from '../util/custom-elements.js';\nimport { PlotDataSeries } from './data.js';\nimport { hideBubbleTooltip, showBubbleTooltip } from './svg-utils.js';\n\nexport type PlotHistogramOrientation = `horizontal` | `vertical`;\n\n/**\n * - `hover`: floating `ixfx-tooltip` bubble, shown/hidden with a debounce delay.\n * - `inline`: the title overlay-text switches to the hovered bucket's value, instantly.\n * - `none`: no hover feedback.\n */\nexport type PlotHistogramValueTooltips = `hover` | `inline` | `none`;\n\nexport type PlotHistogramBucketClickDetail = {\n readonly bucketIndex: number;\n readonly valueMin: number;\n readonly valueMax: number;\n readonly relativeValue: number;\n};\n\nexport type PlotHistogramBucketClickEvent = CustomEvent<PlotHistogramBucketClickDetail>;\n\nexport interface PlotHistogramElementEventMap {\n 'plot-bucket-click': PlotHistogramBucketClickEvent;\n}\n\ntype BarLayout = {\n count: number;\n valueMin: number;\n valueMax: number;\n relativeValue: number;\n x: number;\n y: number;\n width: number;\n height: number;\n};\n\n@customElement(`ixfx-plot-histogram`)\nexport class PlotHistogram extends LitElement {\n @property({ attribute: `orientation` })\n orientation: PlotHistogramOrientation = `horizontal`;\n\n @property({ type: Number })\n resolution = 0.1;\n\n @property({ type: Number })\n min?: number;\n\n @property({ type: Number })\n max?: number;\n\n @property({ type: Number })\n capacity = 100;\n\n /**\n * Fallback overlay-text, shown when nothing is hovered.\n * Not reflected to the native `title` attribute, so the browser's own hover tooltip doesn't show.\n */\n @property({ attribute: false })\n title = ``;\n\n @property({ type: Boolean, reflect: true })\n paused = false;\n\n /** How hovering a bucket is communicated: a floating tooltip, the inline overlay-text, or nothing. */\n @property({ attribute: `value-tooltips` })\n valueTooltips: PlotHistogramValueTooltips = `hover`;\n\n /** Delay (ms) before the `hover` tooltip appears/disappears. Switching directly between buckets is instant. */\n @property({ type: Number, attribute: `tooltip-delay` })\n tooltipDelay = 400;\n\n /** Max rate (ms) at which an already-shown value display refreshes to match live-changing bucket data. */\n @property({ type: Number, attribute: `value-update-interval` })\n valueUpdateInterval = 500;\n\n /** Override to customize the value/frequency label used by the tooltip and overlay text. */\n valueFormat: (valueMin: number, valueMax: number, frequency: number) => string\n = (valueMin, valueMax, frequency) => `${valueMin.toFixed(2)} - ${valueMax.toFixed(2)}: ${frequency}`;\n\n @state() private _width = 100;\n @state() private _height = 40;\n @state() private _hoveredIndex: number | null = null;\n @state() private _inlineOverlayText: string | null = null;\n\n #series = new PlotDataSeries({ capacityLimit: 100, persistentScaling: true });\n #hasProgrammaticData = false;\n\n #parseDeclarativeData(text: string): number[] {\n if (!text)\n return [];\n const tokens = text.trim().split(/[,\\s;]+/);\n return tokens.map(t => Number.parseFloat(t)).filter(n => !Number.isNaN(n));\n }\n\n add(v: number): void {\n this.#hasProgrammaticData = true;\n this.#series.add(v);\n if (this.paused)\n return;\n this.requestUpdate();\n }\n\n set(values: number[]): void {\n this.#hasProgrammaticData = true;\n this.#series.set(values);\n if (this.paused)\n return;\n this.requestUpdate();\n }\n\n clear(): void {\n this.#series.clear();\n this.requestUpdate();\n }\n\n protected override firstUpdated(_changed: PropertyValues): void {\n this._width = this.clientWidth || 100;\n this._height = this.clientHeight || 40;\n const ro = new ResizeObserver((entries) => {\n const e = entries[0];\n this._width = e.contentRect.width;\n this._height = e.contentRect.height;\n });\n ro.observe(this);\n\n if (!this.#hasProgrammaticData) {\n const data = this.#parseDeclarativeData(this.textContent ?? ``);\n if (data.length > 0) {\n this.#series.set(data);\n }\n }\n\n // `title` is a standard global HTML attribute the browser uses for its own native hover\n // tooltip. Read any declarative value into our (attribute-less) property, then strip the\n // attribute so only our overlay-text/tooltip UI reacts to hover, not the browser's.\n const declaredTitle = this.getAttribute(`title`);\n if (declaredTitle !== null) {\n this.title = declaredTitle;\n this.removeAttribute(`title`);\n }\n }\n\n protected override updated(changed: PropertyValues): void {\n if (changed.has(`capacity`)) {\n const old = [...this.#series.values];\n this.#series = new PlotDataSeries({\n capacityLimit: this.capacity,\n persistentScaling: true,\n });\n if (old.length > 0)\n this.#series.set(old);\n }\n if (changed.has(`valueTooltips`))\n this.#resetHoverState();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.#resetHoverState();\n }\n\n #readCssVar(name: string): string {\n return getComputedStyle(this).getPropertyValue(name).trim();\n }\n\n #getGapPx(): number {\n const val = this.#readCssVar(`--plot-histogram-gap`);\n if (val === ``)\n return 1;\n const parsed = Number.parseFloat(val);\n return Number.isFinite(parsed) ? Math.max(0, parsed) : 1;\n }\n\n #getBarLengthOverride(): number | null {\n const val = this.#readCssVar(`--plot-histogram-bar-length`);\n if (val === `` || val === `auto`)\n return null;\n const parsed = Number.parseFloat(val);\n return Number.isFinite(parsed) ? Math.max(0, Math.min(1, parsed)) : null;\n }\n\n #emitClick(i: number, valueMin: number, valueMax: number, relativeValue: number): void {\n this.dispatchEvent(\n new CustomEvent<PlotHistogramBucketClickDetail>(`plot-bucket-click`, {\n detail: { bucketIndex: i, valueMin, valueMax, relativeValue },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n /** Bucket layout + counts, shared by render() and pointer hit-testing. */\n #computeGeometry() {\n const { values, range } = this.#series;\n const w = this._width;\n const h = this._height;\n const isHorizontal = this.orientation === `horizontal`;\n const padding = Math.min(4, (isHorizontal ? h : w) * 0.05);\n\n const dataMin = this.min ?? range.min;\n const dataMax = this.max ?? range.max;\n const dataSpan = dataMax - dataMin || 1;\n\n const bucketCount = Math.max(1, Math.floor(1 / this.resolution));\n\n const availableMain = (isHorizontal ? w : h) - padding * 2;\n const availableCross = (isHorizontal ? h : w) - padding * 2;\n\n const buckets: number[] = Array.from({ length: bucketCount }).fill(0) as number[];\n for (const v of values) {\n const normalized = (v - dataMin) / dataSpan;\n const index = Math.min(bucketCount - 1, Math.max(0, Math.floor(normalized * bucketCount)));\n buckets[index]++;\n }\n\n return { w, h, isHorizontal, padding, dataMin, dataMax, dataSpan, bucketCount, availableMain, availableCross, buckets };\n }\n\n /** Per-bucket rect geometry (SVG pixel coords) + value/count, shared by render() and pointer hit-testing. */\n #computeBars(): BarLayout[] {\n const { isHorizontal, padding, dataMin, dataSpan, bucketCount, availableMain, availableCross, buckets } = this.#computeGeometry();\n const bucketSize = availableMain / bucketCount;\n const gap = this.#getGapPx();\n const barLengthOverride = this.#getBarLengthOverride();\n const maxCount = Math.max(1, ...buckets);\n\n return buckets.map((count, i) => {\n const relativeValue = count / maxCount;\n const barLen = barLengthOverride !== null\n ? barLengthOverride * availableCross\n : relativeValue * availableCross;\n\n const valueMin = dataMin + (i / bucketCount) * dataSpan;\n const valueMax = dataMin + ((i + 1) / bucketCount) * dataSpan;\n\n if (isHorizontal) {\n const x = padding + i * bucketSize;\n const width = i === bucketCount - 1\n ? Math.max(0, padding + availableMain - x)\n : Math.max(0, bucketSize - gap);\n const y = padding + availableCross - barLen;\n return { count, valueMin, valueMax, relativeValue, x, y, width, height: barLen };\n } else {\n const y = padding + i * bucketSize;\n const height = i === bucketCount - 1\n ? Math.max(0, padding + availableMain - y)\n : Math.max(0, bucketSize - gap);\n return { count, valueMin, valueMax, relativeValue, x: padding, y, width: barLen, height };\n }\n });\n }\n\n /** Index of the bar rect under the pointer, or -1 if none (matches click hit-testing). */\n #bucketIndexFromPointer(clientX: number, clientY: number): number {\n const rect = this.getBoundingClientRect();\n const x = clientX - rect.left;\n const y = clientY - rect.top;\n return this.#computeBars().findIndex(b => x >= b.x && x <= b.x + b.width && y >= b.y && y <= b.y + b.height);\n }\n\n // --- Hover state (drives both the `inline` overlay-text and the `hover` bubble tooltip) ---\n\n #tooltipIndex: number | null = null;\n #tooltipVisible = false;\n #tooltipShowTimer: number | null = null;\n #tooltipHideTimer: number | null = null;\n #tooltipPosition: { mainClient: number; crossClient: number } | null = null;\n #valueRefreshTimer: number | null = null;\n\n #clearValueRefreshTimer(): void {\n if (this.#valueRefreshTimer !== null) {\n clearTimeout(this.#valueRefreshTimer);\n this.#valueRefreshTimer = null;\n }\n }\n\n /** While a bucket stays hovered, re-invoke `tick` at most every `valueUpdateInterval` ms, so a live-streaming bucket's displayed value stays fresh without updating on every single data point. */\n #scheduleValueRefresh(tick: () => void): void {\n this.#clearValueRefreshTimer();\n this.#valueRefreshTimer = window.setTimeout(() => {\n this.#valueRefreshTimer = null;\n tick();\n this.#scheduleValueRefresh(tick);\n }, this.valueUpdateInterval);\n }\n\n #clearBubbleTooltip(): void {\n if (this.#tooltipShowTimer !== null) {\n clearTimeout(this.#tooltipShowTimer);\n this.#tooltipShowTimer = null;\n }\n if (this.#tooltipHideTimer !== null) {\n clearTimeout(this.#tooltipHideTimer);\n this.#tooltipHideTimer = null;\n }\n if (this.#tooltipVisible) {\n this.#tooltipVisible = false;\n hideBubbleTooltip(this);\n }\n this.#tooltipIndex = null;\n this.#tooltipPosition = null;\n }\n\n #resetHoverState(): void {\n this.#clearValueRefreshTimer();\n this.#clearBubbleTooltip();\n this._hoveredIndex = null;\n this._inlineOverlayText = null;\n }\n\n /** Bubble position: centred on the bar along the bucket axis, offset from the cursor on the other axis. */\n #tooltipPositionFor(bar: BarLayout, clientX: number, clientY: number): { mainClient: number; crossClient: number } {\n const hostRect = this.getBoundingClientRect();\n const offset = 14;\n if (this.orientation === `horizontal`) {\n return { mainClient: hostRect.left + bar.x + bar.width / 2, crossClient: clientY - offset };\n }\n return { mainClient: hostRect.top + bar.y + bar.height / 2, crossClient: clientX + offset };\n }\n\n #refreshBubbleText(): void {\n if (this.#tooltipIndex === null || !this.#tooltipVisible || !this.#tooltipPosition)\n return;\n const bar = this.#computeBars()[this.#tooltipIndex];\n if (!bar)\n return;\n const text = this.valueFormat(bar.valueMin, bar.valueMax, bar.count);\n showBubbleTooltip(this, text, this.#tooltipPosition.mainClient, this.#tooltipPosition.crossClient, this.orientation);\n }\n\n /**\n * Drives the floating bubble tooltip. Only reacts to the hovered bucket *changing*\n * (not every pointermove), so the tooltip doesn't track minor cursor movement.\n * Debounces the initial show and the final hide; switching between buckets while\n * already visible updates instantly. While a bucket stays hovered, its displayed\n * value is refreshed at `valueUpdateInterval`.\n */\n #updateBubbleTooltip(index: number | null, clientX: number, clientY: number): void {\n if (index === this.#tooltipIndex)\n return;\n this.#tooltipIndex = index;\n this.#clearValueRefreshTimer();\n\n if (index === null) {\n if (this.#tooltipShowTimer !== null) {\n clearTimeout(this.#tooltipShowTimer);\n this.#tooltipShowTimer = null;\n }\n if (this.#tooltipVisible) {\n this.#tooltipHideTimer = window.setTimeout(() => {\n this.#tooltipHideTimer = null;\n this.#tooltipVisible = false;\n this.#tooltipPosition = null;\n hideBubbleTooltip(this);\n }, this.tooltipDelay);\n }\n return;\n }\n\n if (this.#tooltipHideTimer !== null) {\n clearTimeout(this.#tooltipHideTimer);\n this.#tooltipHideTimer = null;\n }\n\n const bar = this.#computeBars()[index];\n if (!bar)\n return;\n const text = this.valueFormat(bar.valueMin, bar.valueMax, bar.count);\n const position = this.#tooltipPositionFor(bar, clientX, clientY);\n this.#tooltipPosition = position;\n\n if (this.#tooltipVisible) {\n showBubbleTooltip(this, text, position.mainClient, position.crossClient, this.orientation);\n this.#scheduleValueRefresh(() => this.#refreshBubbleText());\n return;\n }\n\n if (this.#tooltipShowTimer !== null)\n clearTimeout(this.#tooltipShowTimer);\n this.#tooltipShowTimer = window.setTimeout(() => {\n this.#tooltipShowTimer = null;\n this.#tooltipVisible = true;\n showBubbleTooltip(this, text, position.mainClient, position.crossClient, this.orientation);\n this.#scheduleValueRefresh(() => this.#refreshBubbleText());\n }, this.tooltipDelay);\n }\n\n #formatBarAt(index: number): string | null {\n const bar = this.#computeBars()[index];\n return bar ? this.valueFormat(bar.valueMin, bar.valueMax, bar.count) : null;\n }\n\n /**\n * Drives the `inline` overlay-text: instant on hover change, throttled while stationary\n * over a live-changing bucket. `_inlineOverlayText` is cached reactive state rather than\n * being recomputed fresh in render() on every data change, since add()/set() trigger their\n * own re-render independent of the throttle timer.\n */\n #setInlineIndex(index: number | null): void {\n if (index === this._hoveredIndex)\n return;\n this._hoveredIndex = index;\n this.#clearValueRefreshTimer();\n if (index === null) {\n this._inlineOverlayText = null;\n return;\n }\n this._inlineOverlayText = this.#formatBarAt(index);\n this.#scheduleValueRefresh(() => {\n if (this._hoveredIndex !== null)\n this._inlineOverlayText = this.#formatBarAt(this._hoveredIndex);\n });\n }\n\n #onPointerMove = (e: PointerEvent): void => {\n if (this.valueTooltips === `none`)\n return;\n const index = this.#bucketIndexFromPointer(e.clientX, e.clientY);\n const bucketIndex = index >= 0 ? index : null;\n\n if (this.valueTooltips === `inline`)\n this.#setInlineIndex(bucketIndex);\n else\n this.#updateBubbleTooltip(bucketIndex, e.clientX, e.clientY);\n };\n\n #onPointerLeave = (): void => {\n if (this.valueTooltips === `none`)\n return;\n if (this.valueTooltips === `inline`)\n this.#setInlineIndex(null);\n else\n this.#updateBubbleTooltip(null, 0, 0);\n };\n\n override render() {\n const { w, h, padding } = this.#computeGeometry();\n const bars = this.#computeBars();\n\n const barsContent = bars.map((b, i) => svg`\n <rect class=\"bar\" x=${b.x} y=${b.y} width=${b.width} height=${b.height}\n style=\"--value: ${b.relativeValue}\"\n @click=${() => this.#emitClick(i, b.valueMin, b.valueMax, b.relativeValue)} />\n `);\n\n const textColor = `var(--plot-text, var(--surface-2-text, #fff))`;\n const overlayText = (this.valueTooltips === `inline` && this._inlineOverlayText !== null) ? this._inlineOverlayText : this.title;\n const titleContent = overlayText\n ? svg`<text x=${padding + 2} y=${padding + Math.min(10, h * 0.6)}\n class=\"overlay-text\" fill=${textColor}\n style=\"opacity: 0.6\">${overlayText}</text>`\n : svg``;\n\n return html`\n <svg width=${w} height=${h} viewBox=\"0 0 ${w} ${h}\"\n xmlns=\"http://www.w3.org/2000/svg\"\n @pointermove=${this.#onPointerMove}\n @pointerleave=${this.#onPointerLeave}>\n <rect width=${w} height=${h} fill=\"transparent\" />\n ${barsContent}\n ${titleContent}\n </svg>\n `;\n }\n\n static override styles = css`\n :host {\n display: inline-block;\n width: 100%;\n height: 100%;\n min-width: 20px;\n min-height: 20px;\n\n --plot-histogram-fill: currentColor;\n --plot-histogram-gap: 1px;\n --plot-histogram-border-radius: 0;\n --plot-histogram-bar-length: auto;\n }\n\n svg {\n display: block;\n cursor: crosshair;\n overflow: visible;\n }\n\n rect.bar {\n fill: var(--plot-histogram-fill, currentColor);\n rx: var(--plot-histogram-border-radius, 0);\n opacity: calc(0.15 + var(--value) * 0.85);\n }\n\n .overlay-text {\n font-family: var(--font-mono, ui-monospace, monospace);\n font-size: 9px;\n dominant-baseline: hanging;\n pointer-events: none;\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ixfx-plot-histogram': PlotHistogram;\n }\n}\n\nexport interface PlotHistogram {\n addEventListener: (<K extends keyof PlotHistogramElementEventMap>(\n type: K,\n listener: (this: PlotHistogram, event: PlotHistogramElementEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions,\n ) => void) & ((\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ) => void);\n}\n","import type { PropertyValues, SVGTemplateResult } from 'lit';\nimport type { ColourMode, ColourResult } from './colour-map.js';\nimport { clamp } from '@ixfx/numbers';\nimport { css, html, LitElement, svg } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { safeCustomElement as customElement } from '../util/custom-elements.js';\nimport { applyAgeModification, computeColour, parseColourScaleAttr, readBaseColour } from './colour-map.js';\nimport { PlotDataSeries } from './data.js';\nimport { adaptiveRadius, adaptiveStroke, hideTooltip, scaleValue, showTooltip } from './svg-utils.js';\n\nexport type SingleAxisDrawStyle\n = | `line-sharp`\n | `line-round`\n | `circles`\n | `squares`\n | `vbar`\n | `hbar`\n | `hist-bottom`\n | `hist-top`\n | `hist-middle`;\n\nexport type SingleAxisAgeStyle = `none` | `opacity` | `desaturation` | `size`;\n\ntype PlotPoint = { x: number; y: number; value: number; scaledValue: number; index: number; ageFraction: number };\n\n// --- Pure SVG fragment renderers ---\n// Lines use a single ColourResult (the last / most-recent point's colour).\n// Per-point styles use a ColourResult[] aligned with the points array.\n\nfunction buildLinePath(points: PlotPoint[]): string {\n if (points.length === 0)\n return ``;\n let d = `M ${points[0].x},${points[0].y}`;\n for (let i = 1; i < points.length; i++) {\n d += ` L ${points[i].x},${points[i].y}`;\n }\n return d;\n}\n\nfunction renderLine(points: PlotPoint[], cr: ColourResult, strokeW: number, round: boolean) {\n return svg`<path\n d=${buildLinePath(points)}\n fill=\"none\"\n stroke=${cr.fill}\n stroke-width=${strokeW}\n opacity=${cr.opacity}\n stroke-linecap=${round ? `round` : `butt`}\n stroke-linejoin=${round ? `round` : `miter`}\n />`;\n}\n\nfunction renderArea(points: PlotPoint[], cr: ColourResult, bottom: number, areaColor?: string): SVGTemplateResult {\n if (points.length < 2)\n return svg``;\n const lineD = buildLinePath(points);\n const fillColor = areaColor || cr.fill;\n const areaD = `${lineD} L ${points[points.length - 1].x},${bottom} L ${points[0].x},${bottom} Z`;\n return svg`<path d=${areaD} fill=${fillColor} opacity=${cr.opacity * 0.2} />`;\n}\n\nfunction renderCircles(points: PlotPoint[], crs: ColourResult[], radius: number, ageStyle: SingleAxisAgeStyle) {\n return points.map((p, i) => {\n const r = ageStyle === `size` ? radius * Math.max(0.2, p.ageFraction) : radius;\n return svg`<circle cx=${p.x} cy=${p.y} r=${r} fill=${crs[i].fill} opacity=${crs[i].opacity} />`;\n });\n}\n\nfunction renderSquares(points: PlotPoint[], crs: ColourResult[], size: number, ageStyle: SingleAxisAgeStyle) {\n return points.map((p, i) => {\n const s = ageStyle === `size` ? size * Math.max(0.2, p.ageFraction) : size;\n return svg`<rect\n x=${p.x - s / 2} y=${p.y - s / 2}\n width=${s} height=${s}\n fill=${crs[i].fill} opacity=${crs[i].opacity}\n />`;\n });\n}\n\nfunction renderVbars(points: PlotPoint[], crs: ColourResult[], strokeW: number, bottom: number, ageStyle: SingleAxisAgeStyle) {\n return points.map((p, i) => {\n const sw = ageStyle === `size` ? strokeW * Math.max(0.2, p.ageFraction) : strokeW;\n return svg`<line\n x1=${p.x} y1=${bottom} x2=${p.x} y2=${p.y}\n stroke=${crs[i].fill} stroke-width=${sw} opacity=${crs[i].opacity}\n />`;\n });\n}\n\nfunction renderHbars(points: PlotPoint[], crs: ColourResult[], strokeW: number, tickLen: number, ageStyle: SingleAxisAgeStyle) {\n return points.map((p, i) => {\n const tl = ageStyle === `size` ? tickLen * Math.max(0.2, p.ageFraction) : tickLen;\n return svg`<line\n x1=${p.x - tl / 2} y1=${p.y} x2=${p.x + tl / 2} y2=${p.y}\n stroke=${crs[i].fill} stroke-width=${strokeW} opacity=${crs[i].opacity}\n />`;\n });\n}\n\nfunction renderHistBottom(points: PlotPoint[], crs: ColourResult[], barW: number, bottom: number, ageStyle: SingleAxisAgeStyle) {\n return points.map((p, i) => {\n const w = ageStyle === `size` ? barW * Math.max(0.2, p.ageFraction) : barW;\n return svg`<rect\n x=${p.x - w / 2} y=${p.y}\n width=${w} height=${Math.max(1, bottom - p.y)}\n fill=${crs[i].fill} opacity=${crs[i].opacity}\n />`;\n });\n}\n\nfunction renderHistTop(points: PlotPoint[], crs: ColourResult[], barW: number, top: number, ageStyle: SingleAxisAgeStyle) {\n return points.map((p, i) => {\n const w = ageStyle === `size` ? barW * Math.max(0.2, p.ageFraction) : barW;\n return svg`<rect\n x=${p.x - w / 2} y=${top}\n width=${w} height=${Math.max(1, p.y - top)}\n fill=${crs[i].fill} opacity=${crs[i].opacity}\n />`;\n });\n}\n\nfunction renderHistMiddle(points: PlotPoint[], crs: ColourResult[], barW: number, mid: number, ageStyle: SingleAxisAgeStyle) {\n return points.map((p, i) => {\n const w = ageStyle === `size` ? barW * Math.max(0.2, p.ageFraction) : barW;\n return svg`<rect\n x=${p.x - w / 2} y=${Math.min(p.y, mid)}\n width=${w} height=${Math.max(1, Math.abs(p.y - mid))}\n fill=${crs[i].fill} opacity=${crs[i].opacity}\n />`;\n });\n}\n\n// --- Component ---\n\n/**\n * PlotSingleAxis\n *\n * Adding data:\n * - add(value: number): adds a single value to the end of the data series.\n * - set(values: number[]): replaces the entire data series at once.\n */\n@customElement(`ixfx-plot-single-axis`)\n// eslint-disable-next-line ts/no-unsafe-declaration-merging\nexport class PlotSingleAxis extends LitElement {\n @property({ attribute: `draw-style` })\n drawStyle: SingleAxisDrawStyle = `line-sharp`;\n\n @property({ attribute: `age-style` })\n ageStyle: SingleAxisAgeStyle = `none`;\n\n @property() title = ``;\n\n @property({ type: Boolean }) precise = false;\n @property({ type: Boolean }) tooltips = true;\n @property({ type: Number }) capacity = 100;\n\n @property({ type: Number }) rangeMin = Number.NaN;\n @property({ type: Number }) rangeMax = Number.NaN;\n\n @property({ type: Boolean, attribute: `persistent-scale` })\n persistentScale = true;\n\n @property({ type: Boolean, reflect: true }) paused = false;\n @property({ type: Boolean, attribute: `click-pauses` }) clickPauses = false;\n\n @property({ type: Boolean, attribute: `shaded` })\n shaded = false;\n\n @property({ attribute: `area-color` })\n areaColor = ``;\n\n // --- Colour mapping ---\n @property({ attribute: `color-mode` }) colorMode: ColourMode = `fixed`;\n @property({ attribute: `color-easing` }) colorEasing = ``;\n @property({ attribute: `color-scale` }) colorScale = ``;\n /** Custom value-mapping function (0..1 → 0..1). Ignored when color-easing is set. */\n colorValueMap: ((v: number) => number) | null = null;\n\n @state() private _width = 100;\n @state() private _height = 40;\n\n #series = new PlotDataSeries();\n #hasProgrammaticData = false;\n #lastClientX: number | null = null;\n #lastClientY: number | null = null;\n\n #parseDeclarativeData(text: string): number[] {\n if (!text)\n return [];\n const tokens = text.trim().split(/[,\\s;]+/);\n return tokens\n .map(t => Number.parseFloat(t))\n .filter(n => !Number.isNaN(n));\n }\n\n /** Override to customize tooltip label. */\n valueFormat: (v: number | undefined) => string = v => v ? v.toFixed(2) : ``;\n\n /**\n * Adds a value to the data series.\n *\n * Pass `withholdRedraw = true` to prevent automatic redraw after adding the value. In this case, call `redraw()` manually after adding all values to update the plot.\n *\n * Use {@link set} to replace the entire data series at once.\n * @param valueOrValues Single value, or several values\n * @param withholdRedraw If _false_ (default) plot is automatically redrawn\n */\n add(valueOrValues: number | number[], withholdRedraw = false): void {\n this.#hasProgrammaticData = true;\n this.#series.add(valueOrValues);\n if (this.paused)\n return;\n if (withholdRedraw)\n return;\n this.redraw();\n }\n\n /**\n * Redraws the plot.\n * Normally not needed, unless add() is called with withholdRedraw = true, or styleSeries() is used to update series styles.\n */\n redraw() {\n this.requestUpdate();\n this.#updateTooltipAtLastPos();\n }\n\n /**\n * Sets the entire data for a series at once, replacing contents.\n *\n * Use add() to add values one by one.\n *\n * Pass `withholdRedraw = true` to prevent automatic redraw after setting the values. In this case, call `redraw()` manually after setting the values to update the plot.\n * @param values Values\n * @param withholdRedraw If _false_ (default) plot is automatically redrawn\n */\n set(values: number[], withholdRedraw = false): void {\n this.#hasProgrammaticData = true;\n this.#series.set(values);\n if (this.paused)\n return;\n if (withholdRedraw)\n return;\n this.redraw();\n }\n\n /**\n * Clears all data and redraws\n */\n clear(): boolean {\n const result = this.#series.clear();\n this.requestUpdate();\n return result;\n }\n\n protected override firstUpdated(_changed: PropertyValues): void {\n this._width = this.clientWidth || 100;\n this._height = this.clientHeight || 40;\n const ro = new ResizeObserver((entries) => {\n const e = entries[0];\n this._width = e.contentRect.width;\n this._height = e.contentRect.height;\n });\n ro.observe(this);\n\n if (!this.#hasProgrammaticData) {\n const data = this.#parseDeclarativeData(this.textContent ?? ``);\n if (data.length > 0) {\n this.#series.set(data);\n }\n }\n }\n\n protected override updated(changed: PropertyValues): void {\n if (changed.has(`capacity`) || changed.has(`persistentScale`) || changed.has(`rangeMin`) || changed.has(`rangeMax`)) {\n const old = [...this.#series.values];\n const fixedRange = (!Number.isNaN(this.rangeMin) && !Number.isNaN(this.rangeMax)) ? { min: this.rangeMin, max: this.rangeMax } : null;\n this.#series = new PlotDataSeries({\n capacityLimit: this.capacity,\n persistentScaling: this.persistentScale,\n fixedRange,\n });\n if (old.length > 0)\n this.#series.set(old);\n }\n }\n\n #getIndexFromX(clientX: number, rect: DOMRect): number {\n const n = this.#series.values.length;\n if (n === 0)\n return -1;\n const x = clientX - rect.left;\n if (x < 0 || x > rect.width)\n return -1;\n const padding = rect.height < 20 ? 0 : Math.min(4, rect.height * 0.05);\n const plotW = rect.width - padding * 2;\n const index = Math.floor((x - padding) / (plotW / n));\n return index >= 0 && index < n ? index : -1;\n }\n\n #updateTooltip(clientX: number, clientY: number): void {\n if (!this.tooltips)\n return;\n const rect = this.getBoundingClientRect();\n const index = this.#getIndexFromX(clientX, rect);\n if (index < 0) {\n hideTooltip(this); return;\n }\n showTooltip(this, clientX, clientY, this.valueFormat(this.#series.values[index]));\n }\n\n #updateTooltipAtLastPos(): void {\n if (this.#lastClientX === null || this.#lastClientY === null)\n return;\n this.#updateTooltip(this.#lastClientX, this.#lastClientY);\n }\n\n #onPointerMove = (e: PointerEvent): void => {\n this.#lastClientX = e.clientX;\n this.#lastClientY = e.clientY;\n this.#updateTooltip(e.clientX, e.clientY);\n const index = this.#getIndexFromX(e.clientX, this.getBoundingClientRect());\n this.dispatchEvent(new CustomEvent(`plot-pointer-move`, {\n detail: { clientX: e.clientX, clientY: e.clientY, index },\n bubbles: true,\n composed: true,\n }));\n };\n\n #onPointerLeave = (): void => {\n this.#lastClientX = null;\n this.#lastClientY = null;\n hideTooltip(this);\n this.dispatchEvent(new CustomEvent(`plot-pointer-leave`, {\n bubbles: true,\n composed: true,\n }));\n };\n\n #onClick = (e: MouseEvent): void => {\n if (this.clickPauses)\n this.paused = !this.paused;\n const index = this.#getIndexFromX(e.clientX, this.getBoundingClientRect());\n if (index < 0)\n return;\n this.dispatchEvent(new CustomEvent(`plot-datapoint-click`, {\n detail: { value: this.#series.values[index], index },\n bubbles: true,\n composed: true,\n }));\n };\n\n #computePoints(values: number[], min: number, max: number, padding: number, plotW: number, plotH: number): PlotPoint[] {\n const n = values.length;\n const widthPerPoint = n > 0 ? plotW / n : plotW;\n const scaleX = (i: number) => padding + (i + 0.5) * widthPerPoint;\n return values.map((value, index) => {\n const sv = clamp(scaleValue(value, min, max));\n const ageFraction = n > 1 ? index / (n - 1) : 1;\n return { x: scaleX(index), y: padding + (1 - sv) * plotH, value, scaledValue: sv, index, ageFraction };\n });\n }\n\n get series() {\n return this.#series;\n }\n\n /**\n * Get all values in the data series as a readonly array.\n */\n get values(): readonly number[] {\n return this.#series.values;\n }\n\n /**\n * Get length of data series\n */\n get dataLength(): number {\n return this.#series.values.length;\n }\n\n /**\n * Get value at specific index of data series\n * @param index\n */\n getValueAt(index: number): number | undefined {\n return this.#series.values[index];\n }\n\n /**\n * Get value index based on client X position\n * @param clientX\n */\n getIndexFromClientX(clientX: number): number {\n return this.#getIndexFromX(clientX, this.getBoundingClientRect());\n }\n\n #renderByStyle(\n points: PlotPoint[],\n crs: ColourResult[],\n strokeW: number,\n radius: number,\n barW: number,\n bottom: number,\n top: number,\n mid: number,\n ): SVGTemplateResult[] {\n const lineCr = crs.at(-1) ?? { fill: `currentColor`, opacity: 1 };\n const isLine = this.drawStyle === `line-sharp` || this.drawStyle === `line-round`;\n const needsArea = isLine && this.shaded;\n const areaColor = this.areaColor || undefined;\n\n if (needsArea) {\n const area = renderArea(points, lineCr, bottom, areaColor);\n const line = this.drawStyle === `line-sharp`\n ? renderLine(points, lineCr, strokeW, false)\n : renderLine(points, lineCr, strokeW, true);\n return [area, line];\n }\n\n switch (this.drawStyle) {\n case `line-sharp`: return [renderLine(points, lineCr, strokeW, false)];\n case `line-round`: return [renderLine(points, lineCr, strokeW, true)];\n case `circles`: return renderCircles(points, crs, radius, this.ageStyle);\n case `squares`: return renderSquares(points, crs, radius * 2, this.ageStyle);\n case `vbar`: return renderVbars(points, crs, strokeW, bottom, this.ageStyle);\n case `hbar`: return renderHbars(points, crs, strokeW, barW, this.ageStyle);\n case `hist-bottom`: return renderHistBottom(points, crs, barW, bottom, this.ageStyle);\n case `hist-top`: return renderHistTop(points, crs, barW, top, this.ageStyle);\n case `hist-middle`: return renderHistMiddle(points, crs, barW, mid, this.ageStyle);\n default: return [];\n }\n }\n\n override render() {\n const { values, range } = this.#series;\n const w = this._width;\n const h = this._height;\n const padding = h < 20 ? 0 : Math.min(4, h * 0.05);\n const plotW = Math.max(1, w - padding * 2);\n const plotH = Math.max(1, h - padding * 2);\n const bottom = padding + plotH;\n const top = padding;\n const mid = padding + plotH / 2;\n\n const strokeW = adaptiveStroke(w, h);\n const radius = adaptiveRadius(w, h, values.length);\n const barW = values.length > 0\n ? Math.max(1, (plotW / values.length) * 0.85)\n : plotW;\n\n const textColor = `var(--plot-text, var(--surface-2-text, #fff))`;\n\n const points = values.length > 0\n ? this.#computePoints(values, range.min, range.max, padding, plotW, plotH)\n : [];\n\n // Colour mapping\n const baseColour = points.length > 0 ? readBaseColour(this) : ``;\n const colourConfig = {\n mode: this.colorMode,\n palette: parseColourScaleAttr(this.colorScale),\n easingName: this.colorEasing,\n valueMap: this.colorValueMap,\n };\n const isDiscrete = this.drawStyle !== `line-sharp` && this.drawStyle !== `line-round`;\n const crs: ColourResult[] = points.map((p) => {\n const base = computeColour(p.scaledValue, baseColour, colourConfig);\n return isDiscrete ? applyAgeModification(base, p.ageFraction, this.ageStyle) : base;\n });\n\n const dataContent = points.length > 0\n ? this.#renderByStyle(points, crs, strokeW, radius, barW, bottom, top, mid)\n : [];\n\n const titleContent = this.title\n ? svg`<text\n x=${padding + 2} y=${top + Math.min(10, h * 0.6)}\n class=\"overlay-text\"\n fill=${textColor}\n style=\"opacity: 0.6\"\n >${this.title}</text>`\n : svg``;\n\n const latestValue = values.length > 0 ? values.at(-1) : null;\n const preciseContent = this.precise && latestValue !== null\n ? svg`<text\n x=${w - padding - 2} y=${top + Math.min(10, h * 0.6)}\n class=\"overlay-text\"\n text-anchor=\"end\"\n fill=${textColor}\n style=\"opacity: 0.8\"\n >${this.valueFormat(latestValue)}</text>`\n : svg``;\n\n return html`\n <svg\n width=${w} height=${h}\n viewBox=\"0 0 ${w} ${h}\"\n xmlns=\"http://www.w3.org/2000/svg\"\n @pointermove=${this.#onPointerMove}\n @pointerleave=${this.#onPointerLeave}\n @click=${this.#onClick}\n >\n <rect width=${w} height=${h} fill=\"transparent\" />\n ${dataContent.map(c => c)}\n ${titleContent}\n ${preciseContent}\n </svg>\n `;\n }\n\n static override styles = css`\n :host {\n display: inline-block;\n width: 100%;\n height: 100%;\n min-width: 20px;\n min-height: 4px;\n }\n\n svg {\n display: block;\n cursor: crosshair;\n overflow: visible;\n }\n\n .overlay-text {\n font-family: var(--font-mono, ui-monospace, monospace);\n font-size: 9px;\n dominant-baseline: hanging;\n pointer-events: none;\n }\n `;\n}\n\nexport type PlotSingleAxisPointerMoveDetail = {\n readonly clientX: number;\n readonly clientY: number;\n readonly index: number;\n};\n\nexport type PlotSingleAxisPointerMoveEvent = CustomEvent<PlotSingleAxisPointerMoveDetail>;\n\nexport interface PlotSingleAxisElementEventMap {\n 'plot-pointer-move': PlotSingleAxisPointerMoveEvent;\n 'plot-pointer-leave': Event;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ixfx-plot-single-axis': PlotSingleAxis;\n }\n}\n\n// eslint-disable-next-line ts/no-unsafe-declaration-merging\nexport interface PlotSingleAxis {\n addEventListener: {\n <K extends keyof PlotSingleAxisElementEventMap>(\n type: K,\n listener: (this: PlotSingleAxis, event: PlotSingleAxisElementEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions,\n ): void;\n (\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void;\n };\n}\n","import type { PropertyValues } from 'lit';\nimport type { ColourMode, ColourResult } from './colour-map.js';\nimport { css, html, LitElement, svg } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { safeCustomElement as customElement } from '../util/custom-elements.js';\nimport { applyAgeModification, computeColour, parseColourScaleAttr, readBaseColour } from './colour-map.js';\nimport { PlotDataSeries } from './data.js';\nimport { adaptiveRadius, hideTooltip, scaleValue, showTooltip } from './svg-utils.js';\n\nexport type XyDrawStyle = `circles` | `squares`;\nexport type XyAgeStyle = `none` | `opacity` | `desaturation` | `size`;\n\ntype XyPoint = { x: number; y: number; xVal: number; yVal: number; index: number; ageFraction: number };\n\n// --- Component ---\n\n@customElement(`ixfx-plot-xy-axis`)\nexport class PlotXyAxis extends LitElement {\n @property({ attribute: `draw-style` })\n drawStyle: XyDrawStyle = `circles`;\n\n @property({ attribute: `age-style` })\n ageStyle: XyAgeStyle = `none`;\n\n @property() title = ``;\n @property({ type: Boolean }) precise = false;\n @property({ type: Boolean }) tooltips = true;\n @property({ type: Number }) capacity = 100;\n\n @property({ type: Boolean, attribute: `persistent-scale` })\n persistentScale = true;\n\n @property({ type: Boolean, reflect: true }) paused = false;\n @property({ type: Boolean, attribute: `click-pauses` }) clickPauses = false;\n\n // --- Colour mapping ---\n @property({ attribute: `color-mode` }) colorMode: ColourMode = `fixed`;\n @property({ attribute: `color-easing` }) colorEasing = ``;\n @property({ attribute: `color-scale` }) colorScale = ``;\n /**\n * Custom value-mapping fn (0..1 → 0..1). For xy-axis the input is the point's ageFraction\n * (0 = oldest, 1 = newest). Ignored when color-easing is set.\n */\n colorValueMap: ((v: number) => number) | null = null;\n\n @state() private _width = 100;\n @state() private _height = 100;\n\n #xSeries = new PlotDataSeries({ capacityLimit: 100, persistentScaling: true });\n #ySeries = new PlotDataSeries({ capacityLimit: 100, persistentScaling: true });\n\n /** Override to customize tooltip label. */\n valueFormat: (x: number, y: number) => string = (x, y) => `${x.toFixed(2)}, ${y.toFixed(2)}`;\n\n add(x: number, y: number): void {\n this.#xSeries.add(x);\n this.#ySeries.add(y);\n if (this.paused)\n return;\n this.requestUpdate();\n this.#updateTooltipAtLastPos();\n }\n\n setXY(xs: number[], ys: number[]): void {\n this.#xSeries.set(xs);\n this.#ySeries.set(ys);\n if (this.paused)\n return;\n this.requestUpdate();\n this.#updateTooltipAtLastPos();\n }\n\n clear(): void {\n this.#xSeries.clear();\n this.#ySeries.clear();\n this.requestUpdate();\n }\n\n protected override firstUpdated(_changed: PropertyValues): void {\n this._width = this.clientWidth || 100;\n this._height = this.clientHeight || 100;\n const ro = new ResizeObserver((entries) => {\n const e = entries[0];\n this._width = e.contentRect.width;\n this._height = e.contentRect.height;\n });\n ro.observe(this);\n }\n\n protected override updated(changed: PropertyValues): void {\n if (changed.has(`capacity`) || changed.has(`persistentScale`)) {\n const opts = { capacityLimit: this.capacity, persistentScaling: this.persistentScale };\n const oldX = [...this.#xSeries.values];\n const oldY = [...this.#ySeries.values];\n this.#xSeries = new PlotDataSeries(opts);\n this.#ySeries = new PlotDataSeries(opts);\n if (oldX.length > 0) {\n this.#xSeries.set(oldX); this.#ySeries.set(oldY);\n }\n }\n }\n\n #computePoints(padding: number, plotW: number, plotH: number): XyPoint[] {\n const xs = this.#xSeries.values;\n const ys = this.#ySeries.values;\n const n = Math.min(xs.length, ys.length);\n if (n === 0)\n return [];\n\n const { min: xMin, max: xMax } = this.#xSeries.range;\n const { min: yMin, max: yMax } = this.#ySeries.range;\n\n return Array.from({ length: n }, (_, i) => ({\n x: padding + scaleValue(xs[i], xMin, xMax) * plotW,\n y: padding + (1 - scaleValue(ys[i], yMin, yMax)) * plotH,\n xVal: xs[i],\n yVal: ys[i],\n index: i,\n ageFraction: n > 1 ? i / (n - 1) : 1,\n }));\n }\n\n /** Compute the final ColourResult for each xy point: base colour → age modification. */\n #computeColours(points: XyPoint[], baseColour: string): ColourResult[] {\n const config = {\n mode: this.colorMode,\n palette: parseColourScaleAttr(this.colorScale),\n easingName: this.colorEasing,\n valueMap: this.colorValueMap,\n };\n return points.map((p) => {\n const base = computeColour(p.ageFraction, baseColour, config);\n return applyAgeModification(base, p.ageFraction, this.ageStyle);\n });\n }\n\n #findNearestPoint(clientX: number, clientY: number, points: XyPoint[], rect: DOMRect): XyPoint | null {\n const x = clientX - rect.left;\n const y = clientY - rect.top;\n let best: XyPoint | null = null;\n let bestDist = Infinity;\n for (const p of points) {\n const dx = p.x - x;\n const dy = p.y - y;\n const d = dx * dx + dy * dy;\n if (d < bestDist) {\n bestDist = d; best = p;\n }\n }\n return best && Math.sqrt(bestDist) < 30 ? best : null;\n }\n\n #lastPoints: XyPoint[] = [];\n #lastClientX: number | null = null;\n #lastClientY: number | null = null;\n\n #updateTooltip(clientX: number, clientY: number): void {\n if (!this.tooltips)\n return;\n const rect = this.getBoundingClientRect();\n const nearest = this.#findNearestPoint(clientX, clientY, this.#lastPoints, rect);\n if (!nearest) {\n hideTooltip(this); return;\n }\n showTooltip(this, clientX, clientY, this.valueFormat(nearest.xVal, nearest.yVal));\n }\n\n #updateTooltipAtLastPos(): void {\n if (this.#lastClientX === null || this.#lastClientY === null)\n return;\n this.#updateTooltip(this.#lastClientX, this.#lastClientY);\n }\n\n #onPointerMove = (e: PointerEvent): void => {\n this.#lastClientX = e.clientX;\n this.#lastClientY = e.clientY;\n this.#updateTooltip(e.clientX, e.clientY);\n };\n\n #onPointerLeave = (): void => {\n this.#lastClientX = null;\n this.#lastClientY = null;\n hideTooltip(this);\n };\n\n #onClick = (e: MouseEvent): void => {\n if (this.clickPauses)\n this.paused = !this.paused;\n const rect = (e.currentTarget as SVGElement).getBoundingClientRect();\n const nearest = this.#findNearestPoint(e.clientX, e.clientY, this.#lastPoints, rect);\n if (!nearest)\n return;\n this.dispatchEvent(new CustomEvent(`plot-datapoint-click`, {\n detail: { x: nearest.xVal, y: nearest.yVal, index: nearest.index },\n bubbles: true,\n composed: true,\n }));\n };\n\n override render() {\n const w = this._width;\n const h = this._height;\n const padding = Math.min(6, Math.min(w, h) * 0.06);\n const plotW = Math.max(1, w - padding * 2);\n const plotH = Math.max(1, h - padding * 2);\n\n const points = this.#computePoints(padding, plotW, plotH);\n this.#lastPoints = points;\n\n const baseColour = points.length > 0 ? readBaseColour(this) : ``;\n const colours = this.#computeColours(points, baseColour);\n\n const radius = adaptiveRadius(w, h, points.length);\n const textColor = `var(--plot-text, var(--surface-2-text, #fff))`;\n\n const dataContent = points.map((p, i) => {\n const cr = colours[i];\n const sizeFactor = this.ageStyle === `size` ? Math.max(0.2, p.ageFraction) : 1;\n if (this.drawStyle === `circles`) {\n const r = radius * sizeFactor;\n return svg`<circle cx=${p.x} cy=${p.y} r=${r} fill=${cr.fill} opacity=${cr.opacity} />`;\n }\n const s = radius * 2 * sizeFactor;\n return svg`<rect x=${p.x - s / 2} y=${p.y - s / 2} width=${s} height=${s} fill=${cr.fill} opacity=${cr.opacity} />`;\n });\n\n const titleContent = this.title\n ? svg`<text\n x=${padding + 2} y=${padding + 2}\n class=\"overlay-text\"\n fill=${textColor}\n style=\"opacity: 0.6\"\n >${this.title}</text>`\n : svg``;\n\n const n = Math.min(this.#xSeries.values.length, this.#ySeries.values.length);\n const latestX = n > 0 ? this.#xSeries.values[n - 1] : null;\n const latestY = n > 0 ? this.#ySeries.values[n - 1] : null;\n const preciseContent = this.precise && latestX !== null && latestY !== null\n ? svg`<text\n x=${w - padding - 2} y=${padding + 2}\n class=\"overlay-text\"\n text-anchor=\"end\"\n fill=${textColor}\n style=\"opacity: 0.8\"\n >${this.valueFormat(latestX, latestY)}</text>`\n : svg``;\n\n return html`\n <svg\n width=${w} height=${h}\n viewBox=\"0 0 ${w} ${h}\"\n xmlns=\"http://www.w3.org/2000/svg\"\n @pointermove=${this.#onPointerMove}\n @pointerleave=${this.#onPointerLeave}\n @click=${this.#onClick}\n >\n <rect width=${w} height=${h} fill=\"transparent\" />\n ${dataContent}\n ${titleContent}\n ${preciseContent}\n </svg>\n `;\n }\n\n static override styles = css`\n :host {\n display: block;\n width: 100%;\n height: 100%;\n min-width: 40px;\n min-height: 40px;\n }\n\n svg {\n display: block;\n cursor: crosshair;\n }\n\n .overlay-text {\n font-family: var(--font-mono, ui-monospace, monospace);\n font-size: 9px;\n dominant-baseline: hanging;\n pointer-events: none;\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ixfx-plot-xy-axis': PlotXyAxis;\n }\n}\n"],"mappings":"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"}
|
package/docs-user/dock.md
CHANGED
|
@@ -7,11 +7,15 @@ top/bottom/left/right. Infinitely composable, serializable, and restrictable.
|
|
|
7
7
|
|
|
8
8
|
```
|
|
9
9
|
<ixfx-dock-host layout='{"version":1,"root":{…}}'>
|
|
10
|
-
<ixfx-dock-panel panel-id="explorer"
|
|
11
|
-
<ixfx-dock-panel panel-id="editor"
|
|
10
|
+
<ixfx-dock-panel panel-id="explorer" label="Explorer" closable>…</ixfx-dock-panel>
|
|
11
|
+
<ixfx-dock-panel panel-id="editor" label="Editor" closable>…</ixfx-dock-panel>
|
|
12
12
|
</ixfx-dock-host>
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
A panel's display text is the `label` attribute (the `title` *property* in
|
|
16
|
+
JS). A legacy `title` attribute is adopted once and then removed, so browsers
|
|
17
|
+
never show it as a hover tooltip.
|
|
18
|
+
|
|
15
19
|
## Architecture
|
|
16
20
|
|
|
17
21
|
- **Flat panel pool + model-driven host.** Panels stay direct light-DOM
|
|
@@ -42,6 +46,8 @@ type DockNode = DockSplitNode | DockStackNode;
|
|
|
42
46
|
type DockSplitNode = { kind: 'split'; direction: 'row' | 'column';
|
|
43
47
|
sizes: number[]; children: DockNode[] };
|
|
44
48
|
type DockStackNode = { kind: 'stack'; panels: string[]; active: string;
|
|
49
|
+
name?: string; // app-defined container name, e.g. 'primary-sidebar'
|
|
50
|
+
hideLabels?: boolean; // icon-only tabs (→ ixfx-tab-list hide-labels)
|
|
45
51
|
collapsed?: boolean; preCollapseSize?: string };
|
|
46
52
|
```
|
|
47
53
|
|
|
@@ -49,11 +55,27 @@ type DockStackNode = { kind: 'stack'; panels: string[]; active: string;
|
|
|
49
55
|
`column` = stacked. A "split horizontal" drop (horizontal divider, panels
|
|
50
56
|
stacked vertically) maps to `direction: "column"`.
|
|
51
57
|
|
|
52
|
-
`normalize()` runs after every mutation: empty stacks are removed
|
|
58
|
+
`normalize()` runs after every mutation: empty *unnamed* stacks are removed
|
|
59
|
+
(named empty stacks are kept so the name stays addressable), ≤1-child
|
|
53
60
|
splits dissolve, same-direction child splits flatten into their parent,
|
|
54
61
|
`sizes` stays parallel to `children`, and `active` always points at a member.
|
|
55
62
|
The tree is plain and mutable, owned exclusively by the host.
|
|
56
63
|
|
|
64
|
+
Named containers: give a stack leaf `name` (e.g. `"primary-sidebar"`) in the
|
|
65
|
+
initial layout JSON. Names must be unique per layout (first match wins),
|
|
66
|
+
serialize with `saveLayout()` / `loadLayout()`, and render as
|
|
67
|
+
`data-dock-name` on the leaf. Explicit leaf close still removes the stack.
|
|
68
|
+
When a `tabs` drop empties a named stack into an *unnamed* one, the name
|
|
69
|
+
(and its content rules) follows the panels to the merged leaf instead of
|
|
70
|
+
leaving an empty placeholder behind.
|
|
71
|
+
|
|
72
|
+
Spatial moves: `getNeighbours()` reports what sits above / below / left /
|
|
73
|
+
right of a leaf (flat `{ name, path }` lists, most-overlapping first).
|
|
74
|
+
`moveLeaf()` swaps one step with the longest-edge neighbour (both leaves keep
|
|
75
|
+
their size slots); `moveLeafToEdge()` relocates to a layout edge, keeping the
|
|
76
|
+
rest of the tree intact and preserving the leaf's absolute size. Both return
|
|
77
|
+
`false` when there is nowhere to go.
|
|
78
|
+
|
|
57
79
|
## Drop targeting — the 5-zone model
|
|
58
80
|
|
|
59
81
|
While dragging, the host overlay highlights the resulting region:
|
|
@@ -87,8 +109,19 @@ split resizes, and host resizes; handles are hidden during dock drags.
|
|
|
87
109
|
target. Default unrestricted.
|
|
88
110
|
- `host.canAccept = (panelId, op) => boolean` — finest-grained veto, consulted
|
|
89
111
|
per candidate zone.
|
|
90
|
-
|
|
91
|
-
|
|
112
|
+
- Leaf content rules by panel `kind` (default `'any'`, matched literally):
|
|
113
|
+
`setLeafExclusiveContents(name, kinds)` admits only those kinds into the
|
|
114
|
+
named leaf, `setLeafDenyContents(name, kinds)` refuses those kinds.
|
|
115
|
+
`clearLeafContentRestrictions(name)` lifts both; `[]` seals (exclusive) or
|
|
116
|
+
lifts (deny). Rules are host policy — kept across `loadLayout()`, never
|
|
117
|
+
serialized; already-docked panels are grandfathered.
|
|
118
|
+
|
|
119
|
+
A zone lights up only if every applicable rule allows it; disallowed zones
|
|
120
|
+
are inert. Content rules govern tabbing *into* a leaf (`tabs` drops,
|
|
121
|
+
`addPanel`, re-homing); edge splits beside the leaf stay allowed because they
|
|
122
|
+
create a new sibling leaf. Programmatic fallbacks (`addPanel` without a
|
|
123
|
+
target, external panels, leaf-close re-homing) use the first stack admitting
|
|
124
|
+
the panel's kind.
|
|
92
125
|
|
|
93
126
|
## Events
|
|
94
127
|
|
|
@@ -111,20 +144,35 @@ the model and emits `dock-panel-removed` + `dock-change`.
|
|
|
111
144
|
The host consumes `ixfx-split-layout` events: `ixfx-split-resize` /
|
|
112
145
|
`ixfx-split-change` (live gutter weights folded into `DockSplitNode.sizes`),
|
|
113
146
|
`ixfx-split-collapse` / `ixfx-split-expand` (→ `DockStackNode.collapsed`), and
|
|
114
|
-
`ixfx-split-close` (cancelable — prevented and rerouted so panel elements
|
|
115
|
-
survive, re-homed into the first other stack).
|
|
147
|
+
`ixfx-split-close` (cancelable — prevented and rerouted so panel elements
|
|
148
|
+
survive, re-homed into the first other stack admitting each kind).
|
|
116
149
|
|
|
117
150
|
## Public API — `ixfx-dock-host`
|
|
118
151
|
|
|
119
152
|
```ts
|
|
120
153
|
saveLayout(): DockLayout // folds live split weights from the DOM
|
|
121
154
|
loadLayout(layout: DockLayout): void
|
|
122
|
-
addPanel(panel: DockPanelElement | DockPanelInit, target?:
|
|
123
|
-
|
|
124
|
-
|
|
155
|
+
addPanel(panel: DockPanelElement | DockPanelInit, target?: DockAddPanelTarget): boolean
|
|
156
|
+
type DockAddPanelTarget = {
|
|
157
|
+
container?: string; // named stack leaf — takes precedence over `stack`
|
|
158
|
+
stack?: string; // a panel-id in the target stack (legacy lookup)
|
|
159
|
+
index?: number; op?: DockOperation
|
|
160
|
+
} // false when the target container denies the panel kind
|
|
125
161
|
removePanel(panelId: string): boolean // removes the element from the DOM too
|
|
126
162
|
activatePanel(panelId: string): boolean
|
|
127
163
|
getPanelIds(): string[]
|
|
164
|
+
setLeafExclusiveContents(name: string, kinds: string[]): void
|
|
165
|
+
setLeafDenyContents(name: string, kinds: string[]): void
|
|
166
|
+
clearLeafContentRestrictions(name: string): void
|
|
167
|
+
getLeafContentRestrictions(name: string): DockLeafContentRules | null
|
|
168
|
+
getContainerNames(): string[]
|
|
169
|
+
getContainer(name: string): { name: string; panels: string[]; active: string } | null
|
|
170
|
+
getContainerPanels(name: string): string[] // ids in tab order
|
|
171
|
+
getContainerElements(name: string): DockPanelElement[] // iterate children
|
|
172
|
+
// Spatial: leaves by `name` or numeric `path`; neighbours are `{ name, path }`
|
|
173
|
+
getNeighbours(leaf: DockLeafRef): DockNeighbours | null
|
|
174
|
+
moveLeaf(leaf: DockLeafRef, direction: 'up' | 'down' | 'left' | 'right'): boolean
|
|
175
|
+
moveLeafToEdge(leaf: DockLeafRef, edge: 'top' | 'bottom' | 'left' | 'right'): boolean
|
|
128
176
|
canAccept?: (panelId: string, op: DockOperation) => boolean
|
|
129
177
|
|
|
130
178
|
// Cross-window hooks (serializable in/out; no element handoff)
|
|
@@ -142,6 +190,30 @@ layout; without it, all pooled panels go into one root stack in source order.
|
|
|
142
190
|
Panels present in the pool but missing from a loaded layout are appended to
|
|
143
191
|
the first stack.
|
|
144
192
|
|
|
193
|
+
## Leaf toolbars
|
|
194
|
+
|
|
195
|
+
The host renders no strip chrome of its own. To add toolbar items to a leaf,
|
|
196
|
+
give it a name in the layout and provide light-DOM content in the matching
|
|
197
|
+
`toolbar-<name>` slot — the host forwards it into that leaf's tab-strip
|
|
198
|
+
toolbar (unnamed leaves have no toolbar target):
|
|
199
|
+
|
|
200
|
+
```html
|
|
201
|
+
<ixfx-dock-host layout='{"version":1,"root":{"kind":"stack","panels":["a"],"active":"a","name":"editor"}}'>
|
|
202
|
+
<ixfx-dock-panel panel-id="a" label="A">…</ixfx-dock-panel>
|
|
203
|
+
<div slot="toolbar-editor">
|
|
204
|
+
<ixfx-menu-trigger label="+" placement="bottom-end">
|
|
205
|
+
<ixfx-menu-container slot="menu">
|
|
206
|
+
<ixfx-menu-item command="new-document" label="New document"></ixfx-menu-item>
|
|
207
|
+
</ixfx-menu-container>
|
|
208
|
+
</ixfx-menu-trigger>
|
|
209
|
+
</div>
|
|
210
|
+
</ixfx-dock-host>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Menu commands surface as bubbling `menu-command` events (`{ command, checked,
|
|
214
|
+
args }`) — listen on the host. Multiple elements may share one toolbar slot;
|
|
215
|
+
content for unknown names is inert until a leaf with that name appears.
|
|
216
|
+
|
|
145
217
|
## Cross-host drags
|
|
146
218
|
|
|
147
219
|
Panels can be dragged between hosts (register via the shared drag
|
|
@@ -166,7 +238,7 @@ the far side.
|
|
|
166
238
|
```ts
|
|
167
239
|
interface DockPanelSnapshot { // structured-clone safe
|
|
168
240
|
panelId: string; title: string; iconName: string;
|
|
169
|
-
closable: boolean; collapsible: boolean; accepts: string;
|
|
241
|
+
closable: boolean; collapsible: boolean; kind: string; accepts: string;
|
|
170
242
|
contentHTML: string; // best-effort innerHTML snapshot; see note below
|
|
171
243
|
}
|
|
172
244
|
interface DockDropTarget { // serializable hit-test result
|
|
@@ -297,6 +369,84 @@ slight rounding (`var(--radius-m)`). An empty
|
|
|
297
369
|
host renders a placeholder; replace its content with
|
|
298
370
|
`<div slot="empty">…</div>`.
|
|
299
371
|
|
|
372
|
+
## Implementation notes from the Electron demo
|
|
373
|
+
|
|
374
|
+
A standalone Electron app demonstrates cross-window docking at
|
|
375
|
+
`../electron-dock-demo/`. Key insights:
|
|
376
|
+
|
|
377
|
+
### Ghost window pattern
|
|
378
|
+
|
|
379
|
+
For tear-out, create a frameless, transparent, always-on-top `BrowserWindow`
|
|
380
|
+
that follows the cursor. The renderer sends `dock-panel-drag-out` (pointer left
|
|
381
|
+
every host) and you open the ghost; subsequent `pointermove` updates its
|
|
382
|
+
position. `dock-panel-tear-out` (released over empty space) creates the real
|
|
383
|
+
panel window and tells the source to detach.
|
|
384
|
+
|
|
385
|
+
### Tear-out verdict
|
|
386
|
+
|
|
387
|
+
The **source keeps its panel** until the main process replies with a verdict:
|
|
388
|
+
|
|
389
|
+
| Drop point | Verdict | Effect |
|
|
390
|
+
|---|---|---|
|
|
391
|
+
| Inside another window | `transferred` | target hosts the panel; source detaches |
|
|
392
|
+
| Inside another window, but vetoed | `floated` | spawn panel window; source detaches |
|
|
393
|
+
| Over empty desktop | `floated` | spawn panel window; source detaches |
|
|
394
|
+
| Over source window's non-host chrome | `cancelled` | panel stays put; nothing happens |
|
|
395
|
+
|
|
396
|
+
This prevents losing a panel when a target vetoes the drop — the source still
|
|
397
|
+
has it. The renderer checks for `bridge.onTearOutVerdict` to know whether to
|
|
398
|
+
wait for a verdict or fall back to direct detach.
|
|
399
|
+
|
|
400
|
+
### Tear-in (panel window → another window)
|
|
401
|
+
|
|
402
|
+
Electron's `BrowserWindow` fires `move` on drag and `moved` on drop. The main
|
|
403
|
+
process hit-tests the cursor against every other window's content bounds:
|
|
404
|
+
|
|
405
|
+
```ts
|
|
406
|
+
// main process
|
|
407
|
+
win.on('move', () => {
|
|
408
|
+
const point = screen.getCursorScreenPoint();
|
|
409
|
+
const target = windowAt(point, win.id); // hit-test vs other windows
|
|
410
|
+
if (target) {
|
|
411
|
+
target.webContents.send('dock:external-drag-move', { snapshot, clientX, clientY });
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
win.on('moved', () => finishDrag(win));
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
**Platform quirk:** Windows/Linux may not fire `moved`. Use a fallback timer
|
|
418
|
+
(≈180ms) to detect drag end:
|
|
419
|
+
|
|
420
|
+
```ts
|
|
421
|
+
win.on('move', () => {
|
|
422
|
+
if (dragIn.endTimer) clearTimeout(dragIn.endTimer);
|
|
423
|
+
dragIn.endTimer = setTimeout(() => finishDrag(win), 180);
|
|
424
|
+
});
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### Coordinates
|
|
428
|
+
|
|
429
|
+
- `screen.getCursorScreenPoint()` + `win.getContentBounds()` are **DIP** (device
|
|
430
|
+
independent pixels)
|
|
431
|
+
- `PointerEvent.clientX/Y` are **CSS px**
|
|
432
|
+
- Equal at `devicePixelRatio: 1`; on fractional displays expect a few px of
|
|
433
|
+
slop in ghost position.
|
|
434
|
+
|
|
435
|
+
### IPC bridge
|
|
436
|
+
|
|
437
|
+
Use a preload script with `contextBridge.exposeInMainWorld` to expose a typed
|
|
438
|
+
bridge. The renderer calls imperative methods (`dragOut`, `dragMove`,
|
|
439
|
+
`tearOut`, `accepted`, `rejected`) and the main process pushes events
|
|
440
|
+
(`dock:external-drag-move`, `dock:external-drag-drop`, etc.).
|
|
441
|
+
|
|
442
|
+
### Content snapshots
|
|
443
|
+
|
|
444
|
+
`DockPanelSnapshot.contentHTML` captures `innerHTML`. For **stateful panels**
|
|
445
|
+
(e.g., live input edits), mirror the value back into the attribute — a
|
|
446
|
+
`input` event listener on the panel body keeps the attribute in sync across
|
|
447
|
+
body replacements. Better: rebuild content from your own model on the receiving
|
|
448
|
+
side instead of relying on DOM snapshotting.
|
|
449
|
+
|
|
300
450
|
## Deviations from the original plan (and why)
|
|
301
451
|
|
|
302
452
|
- **Tab-strip reorder** is handled by the dock drag coordinator (gap-index
|
|
@@ -304,7 +454,8 @@ host renders a placeholder; replace its content with
|
|
|
304
454
|
both would race two ghosts for the same pointer. The gap computation
|
|
305
455
|
reuses the tab-list midpoint rule.
|
|
306
456
|
- **Closing a leaf via `ixfx-split-close`** re-homes its panels into the first
|
|
307
|
-
other stack (or the pool if none) instead of dropping
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
457
|
+
other stack admitting each kind (or the pool if none) instead of dropping
|
|
458
|
+
them on the floor.
|
|
459
|
+
- **No default strip chrome.** The plan's per-strip split buttons are gone;
|
|
460
|
+
leaves expose `toolbar-<name>` slots instead (see [Leaf
|
|
461
|
+
toolbars](#leaf-toolbars)), so apps own their strip actions.
|
package/docs-user/icons.md
CHANGED
|
@@ -9,6 +9,10 @@ A centralized SVG icon system for `@ixfx/components`. Icons are stored by name,
|
|
|
9
9
|
| `chevron-down` | `<ixfx-split-button>`, `<ixfx-panel>` | `currentColor` |
|
|
10
10
|
| `check` | Available for use | `currentColor` |
|
|
11
11
|
| `close` | `<ixfx-panel>`, `<ixfx-split-button>` | `currentColor` |
|
|
12
|
+
| `add` | Available for use | `currentColor` |
|
|
13
|
+
| `file` | Available for use | `currentColor` |
|
|
14
|
+
| `folder` | Available for use | `currentColor` |
|
|
15
|
+
| `search` | Available for use | `currentColor` |
|
|
12
16
|
|
|
13
17
|
## Overriding a built-in icon
|
|
14
18
|
|
package/docs-user/index.json
CHANGED
package/docs-user/tabs.md
CHANGED
|
@@ -256,9 +256,15 @@ All `--ixfx-*` properties use internal bridge variables to work across the Shado
|
|
|
256
256
|
| Property | Default | Description |
|
|
257
257
|
|-----------------------------------|----------------------|-----------------------------------------------------------------------------|
|
|
258
258
|
| `--ixfx-selected-tab-color` | `var(--surface-2-text)` | Text color when selected. Can be set on `ixfx-tab-list` or individual items |
|
|
259
|
+
| `--ixfx-selected-tab-icon-color` | `var(--accent)` | Leading icon color when selected (close/toolbar icons unaffected). Can be set on `ixfx-tab-list` or individual items |
|
|
259
260
|
| `--ixfx-selected-tab-border-width`| `1px` | Border width when selected |
|
|
260
261
|
| `--ixfx-selected-tab-weight` | `bold` | Font weight when selected |
|
|
262
|
+
| `--ixfx-selected-tab-text-decoration` | `none` | Text decoration when selected (e.g. `underline`) |
|
|
263
|
+
| `--ixfx-selected-tab-text-decoration-color` | `var(--accent)` | Color of the text decoration when selected |
|
|
264
|
+
| `--ixfx-selected-tab-text-decoration-thickness` | `0px` | Thickness of the text decoration line when selected |
|
|
265
|
+
| `--ixfx-selected-tab-text-decoration-offset` | `2px` | Space between text and text decoration when selected |
|
|
261
266
|
| `--ixfx-tab-selected-background` | `var(--surface-5)` | Background when selected. Can be set on `ixfx-tab-list` or individual items |
|
|
267
|
+
| `--ixfx-tab-hover-background` | *(resting background)* | Background on hover. Unset by default, so each state keeps its resting background. Can be set on `ixfx-tab-list` or individual items |
|
|
262
268
|
| `--ixfx-tab-padding` | `var(--space-m)` | Inner padding of each tab. Can be set on `ixfx-tab-list` or individual items |
|
|
263
269
|
|
|
264
270
|
Example — set custom padding on a single tab:
|
|
@@ -278,6 +284,20 @@ Example — set custom padding for all tabs in a list:
|
|
|
278
284
|
</ixfx-tab-list>
|
|
279
285
|
```
|
|
280
286
|
|
|
287
|
+
Example — thick text underline instead of a border indicator:
|
|
288
|
+
|
|
289
|
+
```html
|
|
290
|
+
<ixfx-tab-list style="
|
|
291
|
+
--ixfx-selected-tab-border-width: 0;
|
|
292
|
+
--ixfx-selected-tab-text-decoration: underline;
|
|
293
|
+
--ixfx-selected-tab-text-decoration-thickness: 3px;
|
|
294
|
+
--ixfx-selected-tab-text-decoration-offset: 4px;
|
|
295
|
+
">
|
|
296
|
+
<ixfx-tab-list-item selected>Overview</ixfx-tab-list-item>
|
|
297
|
+
<ixfx-tab-list-item>Details</ixfx-tab-list-item>
|
|
298
|
+
</ixfx-tab-list>
|
|
299
|
+
```
|
|
300
|
+
|
|
281
301
|
### CSS parts
|
|
282
302
|
|
|
283
303
|
| Part | Description |
|