@santi020k/lumen-core 3.0.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/PHONE_FLAG_LICENSE.txt +21 -0
  2. package/README.md +379 -4
  3. package/THIRD_PARTY_NOTICES.md +16 -2
  4. package/dist/ai-surfaces.d.ts +25 -0
  5. package/dist/ai-surfaces.d.ts.map +1 -0
  6. package/dist/ai-surfaces.js +162 -0
  7. package/dist/amount-field.d.ts +22 -0
  8. package/dist/amount-field.d.ts.map +1 -0
  9. package/dist/amount-field.js +207 -0
  10. package/dist/attachments.d.ts +15 -0
  11. package/dist/attachments.d.ts.map +1 -0
  12. package/dist/attachments.js +123 -0
  13. package/dist/bullet-chart.d.ts +33 -0
  14. package/dist/bullet-chart.d.ts.map +1 -0
  15. package/dist/bullet-chart.js +80 -0
  16. package/dist/chart-activation.d.ts +32 -0
  17. package/dist/chart-activation.d.ts.map +1 -0
  18. package/dist/chart-activation.js +97 -0
  19. package/dist/chart-interaction.d.ts +12 -0
  20. package/dist/chart-interaction.d.ts.map +1 -0
  21. package/dist/chart-interaction.js +274 -0
  22. package/dist/chart-models.d.ts +156 -0
  23. package/dist/chart-models.d.ts.map +1 -0
  24. package/dist/chart-models.js +348 -0
  25. package/dist/chart-motion.d.ts +6 -0
  26. package/dist/chart-motion.d.ts.map +1 -0
  27. package/dist/chart-motion.js +107 -0
  28. package/dist/charts.d.ts +68 -3
  29. package/dist/charts.d.ts.map +1 -1
  30. package/dist/charts.js +328 -29
  31. package/dist/code.js +1 -1
  32. package/dist/combobox.d.ts +7 -0
  33. package/dist/combobox.d.ts.map +1 -0
  34. package/dist/combobox.js +253 -0
  35. package/dist/comparison-chart.d.ts +32 -0
  36. package/dist/comparison-chart.d.ts.map +1 -0
  37. package/dist/comparison-chart.js +64 -0
  38. package/dist/components.d.ts +210 -25
  39. package/dist/components.d.ts.map +1 -1
  40. package/dist/components.js +102 -26
  41. package/dist/dashboard.d.ts +16 -0
  42. package/dist/dashboard.d.ts.map +1 -0
  43. package/dist/dashboard.js +21 -0
  44. package/dist/data.d.ts.map +1 -1
  45. package/dist/data.js +21 -5
  46. package/dist/dates.d.ts +13 -0
  47. package/dist/dates.d.ts.map +1 -0
  48. package/dist/dates.js +37 -0
  49. package/dist/device-frame.d.ts +25 -0
  50. package/dist/device-frame.d.ts.map +1 -0
  51. package/dist/device-frame.js +50 -0
  52. package/dist/direction.d.ts +3 -0
  53. package/dist/direction.d.ts.map +1 -0
  54. package/dist/direction.js +10 -0
  55. package/dist/extended-charts.d.ts +95 -0
  56. package/dist/extended-charts.d.ts.map +1 -0
  57. package/dist/extended-charts.js +175 -0
  58. package/dist/figma.d.ts.map +1 -1
  59. package/dist/figma.js +10 -1
  60. package/dist/forms.d.ts.map +1 -1
  61. package/dist/forms.js +18 -4
  62. package/dist/icon-data.generated.d.ts +1 -1
  63. package/dist/icon-data.generated.d.ts.map +1 -1
  64. package/dist/icon-data.generated.js +1 -1
  65. package/dist/icons.js +3 -4
  66. package/dist/illustrations.generated.d.ts +1 -1
  67. package/dist/image-comparison.d.ts +14 -0
  68. package/dist/image-comparison.d.ts.map +1 -0
  69. package/dist/image-comparison.js +48 -0
  70. package/dist/index.d.ts +35 -4
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +34 -3
  73. package/dist/media-viewport.d.ts +24 -0
  74. package/dist/media-viewport.d.ts.map +1 -0
  75. package/dist/media-viewport.js +119 -0
  76. package/dist/media-workspace.d.ts +27 -0
  77. package/dist/media-workspace.d.ts.map +1 -0
  78. package/dist/media-workspace.js +83 -0
  79. package/dist/message-scroller.d.ts +14 -0
  80. package/dist/message-scroller.d.ts.map +1 -0
  81. package/dist/message-scroller.js +113 -0
  82. package/dist/motion-workflows.d.ts +24 -0
  83. package/dist/motion-workflows.d.ts.map +1 -0
  84. package/dist/motion-workflows.js +220 -0
  85. package/dist/motion.d.ts +12 -0
  86. package/dist/motion.d.ts.map +1 -0
  87. package/dist/motion.js +96 -0
  88. package/dist/native-input.d.ts +25 -0
  89. package/dist/native-input.d.ts.map +1 -0
  90. package/dist/native-input.js +188 -0
  91. package/dist/phone-flags.generated.d.ts +2 -0
  92. package/dist/phone-flags.generated.d.ts.map +1 -0
  93. package/dist/phone-flags.generated.js +263 -0
  94. package/dist/phone.d.ts +4 -0
  95. package/dist/phone.d.ts.map +1 -1
  96. package/dist/phone.js +6 -1
  97. package/dist/rich-text.d.ts +7 -0
  98. package/dist/rich-text.d.ts.map +1 -1
  99. package/dist/rich-text.js +13 -0
  100. package/dist/rive.d.ts +37 -0
  101. package/dist/rive.d.ts.map +1 -0
  102. package/dist/rive.js +129 -0
  103. package/dist/schedule.d.ts.map +1 -1
  104. package/dist/schedule.js +63 -23
  105. package/dist/tab-indicator.d.ts +3 -0
  106. package/dist/tab-indicator.d.ts.map +1 -0
  107. package/dist/tab-indicator.js +57 -0
  108. package/dist/theme-audit.d.ts +16 -0
  109. package/dist/theme-audit.d.ts.map +1 -0
  110. package/dist/theme-audit.js +57 -0
  111. package/dist/theme-builder.d.ts +7 -1
  112. package/dist/theme-builder.d.ts.map +1 -1
  113. package/dist/theme-builder.js +45 -23
  114. package/dist/theme-presets.generated.d.ts +217 -0
  115. package/dist/theme-presets.generated.d.ts.map +1 -0
  116. package/dist/theme-presets.generated.js +231 -0
  117. package/dist/theme.d.ts +11 -3
  118. package/dist/theme.d.ts.map +1 -1
  119. package/dist/theme.js +56 -6
  120. package/dist/virtual-collection.d.ts +14 -0
  121. package/dist/virtual-collection.d.ts.map +1 -0
  122. package/dist/virtual-collection.js +132 -0
  123. package/dist/virtual-list.d.ts +7 -0
  124. package/dist/virtual-list.d.ts.map +1 -0
  125. package/dist/virtual-list.js +135 -0
  126. package/dist/virtual-window.d.ts +19 -0
  127. package/dist/virtual-window.d.ts.map +1 -0
  128. package/dist/virtual-window.js +84 -0
  129. package/dist/visual-effects.d.ts +6 -0
  130. package/dist/visual-effects.d.ts.map +1 -0
  131. package/dist/visual-effects.js +44 -0
  132. package/dist/world-map-data.generated.d.ts +9 -0
  133. package/dist/world-map-data.generated.d.ts.map +1 -0
  134. package/dist/world-map-data.generated.js +240 -0
  135. package/dist/world-map-navigation.d.ts +16 -0
  136. package/dist/world-map-navigation.d.ts.map +1 -0
  137. package/dist/world-map-navigation.js +53 -0
  138. package/dist/world-map-pan.d.ts +3 -0
  139. package/dist/world-map-pan.d.ts.map +1 -0
  140. package/dist/world-map-pan.js +66 -0
  141. package/dist/world-map-zoom.d.ts +13 -0
  142. package/dist/world-map-zoom.d.ts.map +1 -0
  143. package/dist/world-map-zoom.js +61 -0
  144. package/dist/world-map.d.ts +71 -0
  145. package/dist/world-map.d.ts.map +1 -0
  146. package/dist/world-map.js +143 -0
  147. package/package.json +51 -4
@@ -0,0 +1,32 @@
1
+ import type { LumenChartDatum, LumenHeatmapDatum, LumenRangeDatum } from './charts.js';
2
+ /** Data identities and values, never pixel coordinates or application navigation. */
3
+ export type LumenChartDatumActivationDetail = {
4
+ datumId?: string;
5
+ kind: 'series';
6
+ seriesId: string;
7
+ x: number | string;
8
+ y: number;
9
+ } | {
10
+ datumId?: string;
11
+ kind: 'heatmap';
12
+ value: number;
13
+ x: number | string;
14
+ y: number | string;
15
+ } | {
16
+ datumId?: string;
17
+ high: number;
18
+ kind: 'range';
19
+ low: number;
20
+ x: number | string;
21
+ };
22
+ /** Validate untrusted event data and copy only the documented fields. */
23
+ export declare const parseLumenChartDatumActivation: (value: unknown) => LumenChartDatumActivationDetail | null;
24
+ export declare const createLumenChartDatumActivation: (seriesId: string, datum: LumenChartDatum) => LumenChartDatumActivationDetail | null;
25
+ export declare const createLumenHeatmapDatumActivation: (datum: LumenHeatmapDatum) => LumenChartDatumActivationDetail | null;
26
+ export declare const createLumenRangeDatumActivation: (datum: LumenRangeDatum) => LumenChartDatumActivationDetail | null;
27
+ export interface LumenChartActivationController {
28
+ destroy: () => void;
29
+ }
30
+ /** Native buttons provide the keyboard path; decorative SVG marks use the same click path. */
31
+ export declare const createLumenChartActivationController: (root: HTMLElement) => LumenChartActivationController;
32
+ //# sourceMappingURL=chart-activation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart-activation.d.ts","sourceRoot":"","sources":["../src/chart-activation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAEtF,qFAAqF;AACrF,MAAM,MAAM,+BAA+B,GACvC;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GACvF;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,GAC5F;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAA;AAqCpF,yEAAyE;AACzE,eAAO,MAAM,8BAA8B,GAAI,OAAO,OAAO,KAAG,+BAA+B,GAAG,IAUjG,CAAA;AAED,eAAO,MAAM,+BAA+B,GAC1C,UAAU,MAAM,EAChB,OAAO,eAAe,KACrB,+BAA+B,GAAG,IAMnC,CAAA;AAEF,eAAO,MAAM,iCAAiC,GAC5C,OAAO,iBAAiB,KACvB,+BAA+B,GAAG,IAMnC,CAAA;AAEF,eAAO,MAAM,+BAA+B,GAC1C,OAAO,eAAe,KACrB,+BAA+B,GAAG,IAMnC,CAAA;AAEF,MAAM,WAAW,8BAA8B;IAC7C,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AA0BD,8FAA8F;AAC9F,eAAO,MAAM,oCAAoC,GAAI,MAAM,WAAW,KAAG,8BAqBxE,CAAA"}
@@ -0,0 +1,97 @@
1
+ const isAxisValue = (value) => typeof value === 'string' || (typeof value === 'number' && Number.isFinite(value));
2
+ const isFiniteNumber = (value) => typeof value === 'number' && Number.isFinite(value);
3
+ const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
4
+ const parseSeries = (value) => {
5
+ if (typeof value.seriesId !== 'string' || !isAxisValue(value.x) || !isFiniteNumber(value.y))
6
+ return null;
7
+ return { kind: 'series', seriesId: value.seriesId, x: value.x, y: value.y };
8
+ };
9
+ const parseHeatmap = (value) => {
10
+ if (!isAxisValue(value.x) || !isAxisValue(value.y) || !isFiniteNumber(value.value))
11
+ return null;
12
+ return { kind: 'heatmap', value: value.value, x: value.x, y: value.y };
13
+ };
14
+ const parseRange = (value) => {
15
+ if (!isAxisValue(value.x) || !isFiniteNumber(value.low) || !isFiniteNumber(value.high) ||
16
+ value.low > value.high)
17
+ return null;
18
+ return { high: value.high, kind: 'range', low: value.low, x: value.x };
19
+ };
20
+ const parseDatum = (value) => {
21
+ switch (value.kind) {
22
+ case 'series': return parseSeries(value);
23
+ case 'heatmap': return parseHeatmap(value);
24
+ case 'range': return parseRange(value);
25
+ default: return null;
26
+ }
27
+ };
28
+ /** Validate untrusted event data and copy only the documented fields. */
29
+ export const parseLumenChartDatumActivation = (value) => {
30
+ if (!isRecord(value))
31
+ return null;
32
+ if ('datumId' in value && typeof value.datumId !== 'string')
33
+ return null;
34
+ const detail = parseDatum(value);
35
+ if (!detail)
36
+ return null;
37
+ return typeof value.datumId === 'string' ? { ...detail, datumId: value.datumId } : detail;
38
+ };
39
+ export const createLumenChartDatumActivation = (seriesId, datum) => parseLumenChartDatumActivation({
40
+ ...(datum.id === undefined ? {} : { datumId: datum.id }),
41
+ kind: 'series',
42
+ seriesId,
43
+ x: datum.x,
44
+ y: datum.y
45
+ });
46
+ export const createLumenHeatmapDatumActivation = (datum) => parseLumenChartDatumActivation({
47
+ ...(datum.id === undefined ? {} : { datumId: datum.id }),
48
+ kind: 'heatmap',
49
+ value: datum.value,
50
+ x: datum.x,
51
+ y: datum.y
52
+ });
53
+ export const createLumenRangeDatumActivation = (datum) => parseLumenChartDatumActivation({
54
+ ...(datum.id === undefined ? {} : { datumId: datum.id }),
55
+ high: datum.high,
56
+ kind: 'range',
57
+ low: datum.low,
58
+ x: datum.x
59
+ });
60
+ const ownedActivationTarget = (root, target) => {
61
+ const ElementConstructor = root.ownerDocument.defaultView?.Element;
62
+ if (!ElementConstructor || !(target instanceof ElementConstructor))
63
+ return null;
64
+ const element = target.closest('[data-ui-chart-datum]');
65
+ if (element?.closest('[data-ui-chart-activation]') !== root)
66
+ return null;
67
+ if (element.closest('[inert], [hidden], [disabled], [aria-disabled="true"]'))
68
+ return null;
69
+ return element;
70
+ };
71
+ const parseSerializedDatum = (serialized) => {
72
+ try {
73
+ const value = JSON.parse(serialized);
74
+ return parseLumenChartDatumActivation(value);
75
+ }
76
+ catch {
77
+ return null;
78
+ }
79
+ };
80
+ /** Native buttons provide the keyboard path; decorative SVG marks use the same click path. */
81
+ export const createLumenChartActivationController = (root) => {
82
+ const activate = (event) => {
83
+ if (event.defaultPrevented || event.button !== 0 || !root.isConnected)
84
+ return;
85
+ const target = ownedActivationTarget(root, event.target);
86
+ const serialized = target?.getAttribute('data-ui-chart-datum');
87
+ if (!serialized)
88
+ return;
89
+ const detail = parseSerializedDatum(serialized);
90
+ if (detail)
91
+ root.dispatchEvent(new CustomEvent('ui:chart-datum-activate', { bubbles: true, composed: true, detail }));
92
+ };
93
+ root.addEventListener('click', activate);
94
+ return { destroy: () => {
95
+ root.removeEventListener('click', activate);
96
+ } };
97
+ };
@@ -0,0 +1,12 @@
1
+ export interface LumenChartCursorChangeDetail {
2
+ x: number | string | null;
3
+ }
4
+ export type LumenChartCursorChangeEvent = CustomEvent<LumenChartCursorChangeDetail>;
5
+ export interface LumenChartInteractionController {
6
+ destroy: () => void;
7
+ select: (x: number | string | null) => void;
8
+ setControlledCursor: (x: number | string | null | undefined) => void;
9
+ }
10
+ /** Optional DOM enhancement shared by web adapters; no global listeners or application data transport. */
11
+ export declare const createLumenChartInteractionController: (root: HTMLElement) => LumenChartInteractionController;
12
+ //# sourceMappingURL=chart-interaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart-interaction.d.ts","sourceRoot":"","sources":["../src/chart-interaction.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,4BAA4B;IAC3C,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;CAC1B;AAED,MAAM,MAAM,2BAA2B,GAAG,WAAW,CAAC,4BAA4B,CAAC,CAAA;AAEnF,MAAM,WAAW,+BAA+B;IAC9C,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IAC3C,mBAAmB,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,KAAK,IAAI,CAAA;CACrE;AA4ED,0GAA0G;AAC1G,eAAO,MAAM,qCAAqC,GAAI,MAAM,WAAW,KAAG,+BAqSzE,CAAA"}
@@ -0,0 +1,274 @@
1
+ const chartPeers = new WeakMap();
2
+ const parseCoordinate = (value) => {
3
+ try {
4
+ const parsed = JSON.parse(value ?? 'null');
5
+ return typeof parsed === 'string' || (typeof parsed === 'number' && Number.isFinite(parsed)) ? parsed : null;
6
+ }
7
+ catch {
8
+ return null;
9
+ }
10
+ };
11
+ const chartPoints = (root, svg) => {
12
+ const viewport = svg?.querySelector('svg[overflow="hidden"]');
13
+ const minX = Number(viewport?.getAttribute('x') ?? -Infinity);
14
+ const maxX = minX + Number(viewport?.getAttribute('width') ?? Infinity);
15
+ return [...root.querySelectorAll('[data-ui-chart-point]')].map(element => ({
16
+ element, position: Number(element.dataset.uiChartPosition), x: parseCoordinate(element.dataset.uiChartPoint)
17
+ })).filter(point => point.x !== null && Number.isFinite(point.position) &&
18
+ (!viewport || (point.position >= minX && point.position <= maxX)));
19
+ };
20
+ const revealCoordinate = (plot, svg, position) => {
21
+ if (!plot || !svg?.viewBox)
22
+ return;
23
+ const width = svg.viewBox.baseVal.width;
24
+ if (width <= 0)
25
+ return;
26
+ const x = position / width * svg.getBoundingClientRect().width;
27
+ plot.scrollLeft = Math.max(0, Math.min(plot.scrollWidth - plot.clientWidth, x - plot.clientWidth / 2));
28
+ };
29
+ const positionInspection = (panel, svg, position) => {
30
+ if (!panel || !svg?.viewBox || svg.viewBox.baseVal.width <= 0)
31
+ return;
32
+ const frame = panel.offsetParent?.getBoundingClientRect();
33
+ if (!frame)
34
+ return;
35
+ const bounds = svg.getBoundingClientRect();
36
+ const x = bounds.left - frame.left + position / svg.viewBox.baseVal.width * bounds.width;
37
+ const width = panel.getBoundingClientRect().width;
38
+ const left = x + width + 24 > frame.width ? x - width - 16 : x + 16;
39
+ panel.style.setProperty('--ui-chart-inspection-x', `${Math.max(12, Math.min(frame.width - width - 12, left))}px`);
40
+ panel.style.setProperty('--ui-chart-inspection-y', `${bounds.top - frame.top + 12}px`);
41
+ };
42
+ const observeChartLayout = (root, plot, reposition) => {
43
+ const Resize = root.ownerDocument.defaultView?.ResizeObserver;
44
+ const observer = Resize && plot ? new Resize(reposition) : undefined;
45
+ if (plot)
46
+ observer?.observe(plot);
47
+ plot?.addEventListener('scroll', reposition);
48
+ return () => {
49
+ plot?.removeEventListener('scroll', reposition);
50
+ observer?.disconnect();
51
+ };
52
+ };
53
+ /** Optional DOM enhancement shared by web adapters; no global listeners or application data transport. */
54
+ export const createLumenChartInteractionController = (root) => {
55
+ const plot = root.querySelector('[data-ui-chart-interaction-plot]');
56
+ const svg = plot?.querySelector('svg');
57
+ const crosshair = root.querySelector('[data-ui-chart-crosshair]');
58
+ const panel = root.querySelector('[data-ui-chart-inspection]');
59
+ const announcement = root.querySelector('[data-ui-chart-announcement]');
60
+ const points = chartPoints(root, svg);
61
+ const legend = [...root.querySelectorAll('[data-ui-chart-toggle]')];
62
+ const hiddenSeries = new Set();
63
+ const cleanups = [];
64
+ let controlledCursor;
65
+ let pendingAnnouncement;
66
+ let selected = null;
67
+ let pinned = false;
68
+ let dismissed = false;
69
+ let hovering = false;
70
+ const select = (x, reveal = false) => {
71
+ selected = x;
72
+ const point = points.find(item => item.x === x);
73
+ for (const item of points)
74
+ item.element.hidden = item !== point;
75
+ if (panel)
76
+ panel.hidden = !point;
77
+ if (point && reveal)
78
+ revealCoordinate(plot, svg, point.position);
79
+ if (point)
80
+ positionInspection(panel, svg, point.position);
81
+ if (crosshair) {
82
+ crosshair.style.display = point ? '' : 'none';
83
+ if (point) {
84
+ crosshair.setAttribute('x1', String(point.position));
85
+ crosshair.setAttribute('x2', String(point.position));
86
+ }
87
+ }
88
+ };
89
+ const peers = chartPeers.get(root.ownerDocument) ?? new Set();
90
+ chartPeers.set(root.ownerDocument, peers);
91
+ const peer = { group: root.dataset.uiChartSync ?? '',
92
+ select: x => {
93
+ if (controlledCursor !== undefined)
94
+ return;
95
+ hovering = false;
96
+ pinned = false;
97
+ dismissed = false;
98
+ select(x, true);
99
+ } };
100
+ peers.add(peer);
101
+ const announceSelection = (x) => {
102
+ if (!announcement)
103
+ return;
104
+ const point = points.find(item => item.x === x);
105
+ announcement.textContent = point ?
106
+ [...point.element.children]
107
+ .filter(child => !child.hasAttribute('hidden')).map(child => child.textContent).join('. ') :
108
+ '';
109
+ };
110
+ const synchronize = (x) => {
111
+ for (const other of peers) {
112
+ if (other !== peer && peer.group && other.group === peer.group)
113
+ other.select(x);
114
+ }
115
+ };
116
+ const emit = (x, announce = false) => {
117
+ if (controlledCursor === undefined) {
118
+ select(x, announce);
119
+ if (announce)
120
+ announceSelection(x);
121
+ synchronize(x);
122
+ }
123
+ else
124
+ pendingAnnouncement = announce ? x : undefined;
125
+ const EventClass = root.ownerDocument.defaultView?.CustomEvent;
126
+ if (EventClass)
127
+ root.dispatchEvent(new EventClass('ui:chart-cursor-change', {
128
+ bubbles: true, detail: { x }
129
+ }));
130
+ };
131
+ const closest = (event) => {
132
+ if (!svg)
133
+ return null;
134
+ const matrix = svg.getScreenCTM();
135
+ if (!matrix)
136
+ return null;
137
+ const point = svg.createSVGPoint();
138
+ point.x = event.clientX;
139
+ point.y = event.clientY;
140
+ const position = point.matrixTransform(matrix.inverse()).x;
141
+ let distance = Infinity;
142
+ let result = null;
143
+ for (const candidate of points) {
144
+ const difference = Math.abs(candidate.position - position);
145
+ if (difference < distance) {
146
+ result = candidate.x;
147
+ distance = difference;
148
+ }
149
+ }
150
+ return result;
151
+ };
152
+ const nextIndex = (key) => {
153
+ if (key === 'Home')
154
+ return 0;
155
+ if (key === 'End')
156
+ return points.length - 1;
157
+ const index = points.findIndex(point => point.x === selected);
158
+ if (index < 0)
159
+ return 0;
160
+ return Math.max(0, Math.min(points.length - 1, index + (key === 'ArrowRight' ? 1 : -1)));
161
+ };
162
+ const keydown = (event) => {
163
+ if (event.defaultPrevented || event.isComposing || event.target !== plot || points.length === 0)
164
+ return;
165
+ if (event.key === 'Escape') {
166
+ event.preventDefault();
167
+ pinned = false;
168
+ dismissed = true;
169
+ emit(null, true);
170
+ return;
171
+ }
172
+ if (!['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key))
173
+ return;
174
+ event.preventDefault();
175
+ pinned = true;
176
+ dismissed = false;
177
+ hovering = false;
178
+ const next = nextIndex(event.key);
179
+ emit(points[next]?.x ?? null, true);
180
+ };
181
+ const move = (event) => {
182
+ if (event.pointerType === 'touch' || pinned || dismissed)
183
+ return;
184
+ const x = closest(event);
185
+ hovering = true;
186
+ if (x !== selected)
187
+ emit(x);
188
+ };
189
+ const down = (event) => {
190
+ if (event.button !== 0)
191
+ return;
192
+ pinned = true;
193
+ dismissed = false;
194
+ hovering = false;
195
+ plot?.focus({ preventScroll: true });
196
+ emit(closest(event), true);
197
+ };
198
+ const leave = () => {
199
+ dismissed = false;
200
+ if (hovering && !pinned)
201
+ emit(null);
202
+ hovering = false;
203
+ };
204
+ plot?.addEventListener('keydown', keydown);
205
+ plot?.addEventListener('pointermove', move);
206
+ plot?.addEventListener('pointerdown', down);
207
+ root.addEventListener('pointerleave', leave);
208
+ const reposition = () => {
209
+ if (selected !== null)
210
+ select(selected);
211
+ };
212
+ cleanups.push(observeChartLayout(root, plot, reposition));
213
+ cleanups.push(() => {
214
+ plot?.removeEventListener('keydown', keydown);
215
+ plot?.removeEventListener('pointermove', move);
216
+ plot?.removeEventListener('pointerdown', down);
217
+ root.removeEventListener('pointerleave', leave);
218
+ });
219
+ for (const button of legend) {
220
+ button.hidden = false;
221
+ button.disabled = false;
222
+ button.classList.remove('ui-button--disabled');
223
+ const toggle = () => {
224
+ const id = button.dataset.uiChartToggle ?? '';
225
+ if (hiddenSeries.has(id))
226
+ hiddenSeries.delete(id);
227
+ else
228
+ hiddenSeries.add(id);
229
+ button.setAttribute('aria-pressed', String(!hiddenSeries.has(id)));
230
+ for (const mark of root.querySelectorAll('[data-ui-chart-series]')) {
231
+ mark.style.display = hiddenSeries.has(mark.dataset.uiChartSeries ?? '') ? 'none' : '';
232
+ }
233
+ for (const value of root.querySelectorAll('[data-ui-chart-series-value]')) {
234
+ value.hidden = hiddenSeries.has(value.dataset.uiChartSeriesValue ?? '');
235
+ }
236
+ };
237
+ button.addEventListener('click', toggle);
238
+ cleanups.push(() => {
239
+ button.removeEventListener('click', toggle);
240
+ button.disabled = true;
241
+ button.classList.add('ui-button--disabled');
242
+ });
243
+ }
244
+ root.dataset.uiChartEnhanced = 'true';
245
+ return {
246
+ destroy: () => {
247
+ cleanups.forEach(cleanup => {
248
+ cleanup();
249
+ });
250
+ peers.delete(peer);
251
+ select(null);
252
+ for (const mark of root.querySelectorAll('[data-ui-chart-series]'))
253
+ mark.style.display = '';
254
+ for (const value of root.querySelectorAll('[data-ui-chart-series-value]'))
255
+ value.hidden = false;
256
+ for (const button of legend)
257
+ button.setAttribute('aria-pressed', 'true');
258
+ delete root.dataset.uiChartEnhanced;
259
+ },
260
+ select,
261
+ setControlledCursor: value => {
262
+ controlledCursor = value;
263
+ if (value === undefined)
264
+ return;
265
+ const changed = value !== selected;
266
+ select(value, true);
267
+ if (pendingAnnouncement === value)
268
+ announceSelection(value);
269
+ pendingAnnouncement = undefined;
270
+ if (changed)
271
+ synchronize(value);
272
+ }
273
+ };
274
+ };
@@ -0,0 +1,156 @@
1
+ import { type LumenChartAnnotation, type LumenChartDomain, type LumenChartScaleType, type LumenChartSeries, type LumenChartTone } from './charts.js';
2
+ export interface LumenLineChartOptions {
3
+ annotations?: readonly LumenChartAnnotation[];
4
+ domain?: Partial<LumenChartDomain>;
5
+ formatCategory?: (value: number | string) => string;
6
+ formatValue?: (value: number) => string;
7
+ height?: number;
8
+ referenceValue?: number;
9
+ width?: number;
10
+ xDomain?: Partial<LumenChartDomain>;
11
+ xScale?: LumenChartScaleType;
12
+ }
13
+ /** Preserves category identity; continuous axes align every series against the same domain. */
14
+ export declare const createLumenLineChartModel: (input: readonly LumenChartSeries[], options?: LumenLineChartOptions) => {
15
+ annotationMarks: {
16
+ axis: "x" | "y";
17
+ coordinate: number;
18
+ id: string;
19
+ label: string;
20
+ tone?: LumenChartTone;
21
+ value: number | string;
22
+ }[];
23
+ categories: (string | number)[];
24
+ categoryTicks: import("./charts.js").LumenChartCategoryTick[];
25
+ domain: LumenChartDomain;
26
+ geometries: import("./charts.js").LumenLineGeometry[];
27
+ height: number;
28
+ padding: number;
29
+ paddingLeft: number;
30
+ positions: number[];
31
+ series: LumenChartSeries[];
32
+ ticks: number[];
33
+ width: number;
34
+ xDomain: LumenChartDomain;
35
+ };
36
+ export interface LumenWaterfallDatum {
37
+ id: string;
38
+ label: string;
39
+ /** A total resets the running balance to this explicit value. */
40
+ kind?: 'delta' | 'total';
41
+ tone?: LumenChartTone;
42
+ value: number;
43
+ }
44
+ export interface LumenHistogramBin {
45
+ count: number;
46
+ end: number;
47
+ label?: string;
48
+ start: number;
49
+ }
50
+ export interface LumenIntervalChartOptions {
51
+ /** Axis text size in geometry coordinates; native renderers use their unscaled font size. */
52
+ axisFontSize?: number;
53
+ formatValue?: (value: number) => string;
54
+ height?: number;
55
+ width?: number;
56
+ }
57
+ export interface LumenIntervalChartMark {
58
+ end: number;
59
+ height: number;
60
+ key: string;
61
+ label: string;
62
+ start: number;
63
+ tone: LumenChartTone;
64
+ value: number;
65
+ width: number;
66
+ x: number;
67
+ y: number;
68
+ }
69
+ /** Invalid steps fail closed: silently dropping a change would misstate every later balance. */
70
+ export declare const createLumenWaterfallGeometry: (data: readonly unknown[], options?: LumenIntervalChartOptions) => {
71
+ categoryTicks: import("./charts.js").LumenChartCategoryTick[];
72
+ connectors: {
73
+ x1: number;
74
+ x2: number;
75
+ y: number;
76
+ }[];
77
+ marks: LumenIntervalChartMark[];
78
+ valid: boolean;
79
+ bottom: number;
80
+ domain: LumenChartDomain;
81
+ height: number;
82
+ left: number;
83
+ right: number;
84
+ ticks: number[];
85
+ top: number;
86
+ width: number;
87
+ y: (value: number) => number;
88
+ };
89
+ export interface LumenHistogramOptions extends LumenIntervalChartOptions {
90
+ /** Density is count divided by bin width; required for unequal-width bins. */
91
+ frequency?: 'count' | 'density';
92
+ formatBoundary?: (value: number) => string;
93
+ tone?: LumenChartTone;
94
+ }
95
+ /** Bins are supplied by the application. Their numeric widths remain visible. */
96
+ export declare const createLumenHistogramGeometry: (data: readonly unknown[], options?: LumenHistogramOptions) => {
97
+ bins: LumenHistogramBin[];
98
+ categoryTicks: import("./charts.js").LumenChartCategoryTick[];
99
+ frequency: "count" | "density";
100
+ marks: LumenIntervalChartMark[];
101
+ valid: boolean;
102
+ xDomain: LumenChartDomain;
103
+ bottom: number;
104
+ domain: LumenChartDomain;
105
+ height: number;
106
+ left: number;
107
+ right: number;
108
+ ticks: number[];
109
+ top: number;
110
+ width: number;
111
+ y: (value: number) => number;
112
+ };
113
+ export interface LumenHeatmapOptions {
114
+ colorScale?: 'diverging' | 'sequential';
115
+ domain?: Partial<LumenChartDomain>;
116
+ midpoint?: number;
117
+ }
118
+ /** One cell per coordinate, including explicit missing measurements. */
119
+ export declare const createLumenHeatmapModel: (data: readonly unknown[], options?: LumenHeatmapOptions) => {
120
+ cells: {
121
+ xCoordinate: number;
122
+ yCoordinate: number;
123
+ height: number;
124
+ ratio: number;
125
+ width: number;
126
+ id?: string;
127
+ label?: string;
128
+ tone?: LumenChartTone;
129
+ value: number | null;
130
+ x: number | string;
131
+ xLabel?: string;
132
+ y: number | string;
133
+ yLabel?: string;
134
+ }[];
135
+ domain: LumenChartDomain;
136
+ height: number;
137
+ legendBackground: string;
138
+ midpoint: number;
139
+ midpointPercent: number;
140
+ width: number;
141
+ xTicks: import("./charts.js").LumenChartCategoryTick[];
142
+ yTicks: {
143
+ label: string;
144
+ position: number;
145
+ value: string | number;
146
+ }[];
147
+ };
148
+ export interface LumenHeatmapColorMix {
149
+ base: 'divergingMid' | 'sequentialLow';
150
+ overlay: 'divergingNegative' | 'divergingPositive' | 'sequentialHigh';
151
+ ratio: number;
152
+ }
153
+ /** Platform-neutral color weights; missing measurements have no color weight. */
154
+ export declare const getLumenHeatmapColorMix: (value: number | null, domain: LumenChartDomain, colorScale?: "diverging" | "sequential", midpoint?: number) => LumenHeatmapColorMix | null;
155
+ export declare const getLumenHeatmapColor: (value: number | null, domain: LumenChartDomain, colorScale?: "diverging" | "sequential", midpoint?: number) => string;
156
+ //# sourceMappingURL=chart-models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart-models.d.ts","sourceRoot":"","sources":["../src/chart-models.ts"],"names":[],"mappings":"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"}