@multiplatform.one/components 7.81.1 → 7.82.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 (187) hide show
  1. package/dist/cjs/charts/BarChart.cjs +1 -0
  2. package/dist/cjs/charts/BarChart.native.js +1 -0
  3. package/dist/cjs/charts/BarChart.native.js.map +1 -1
  4. package/dist/cjs/charts/ChartDataView.cjs +89 -9
  5. package/dist/cjs/charts/ChartDataView.native.js +94 -9
  6. package/dist/cjs/charts/ChartDataView.native.js.map +1 -1
  7. package/dist/cjs/charts/ChartSurface.cjs +26 -8
  8. package/dist/cjs/charts/ChartSurface.native.js +27 -9
  9. package/dist/cjs/charts/ChartSurface.native.js.map +1 -1
  10. package/dist/cjs/charts/chartHeight.cjs +1 -1
  11. package/dist/cjs/charts/chartHeight.native.js +1 -1
  12. package/dist/cjs/charts/chartHeight.native.js.map +1 -1
  13. package/dist/cjs/charts/composeChart.cjs +1 -1
  14. package/dist/cjs/charts/composeChart.native.js +1 -1
  15. package/dist/cjs/charts/composeChart.native.js.map +1 -1
  16. package/dist/cjs/code/CodeBlock/index.cjs +38 -31
  17. package/dist/cjs/code/CodeBlock/index.native.js +38 -31
  18. package/dist/cjs/code/CodeBlock/index.native.js.map +1 -1
  19. package/dist/cjs/code/LogView.cjs +142 -0
  20. package/dist/cjs/code/LogView.native.js +151 -0
  21. package/dist/cjs/code/LogView.native.js.map +1 -0
  22. package/dist/cjs/code/index.cjs +2 -1
  23. package/dist/cjs/code/index.native.js +1 -0
  24. package/dist/cjs/code/index.native.js.map +1 -1
  25. package/dist/cjs/layouts/EmptyState.cjs +9 -43
  26. package/dist/cjs/layouts/EmptyState.native.js +9 -45
  27. package/dist/cjs/layouts/EmptyState.native.js.map +1 -1
  28. package/dist/cjs/layouts/PageTemplates.cjs +61 -0
  29. package/dist/cjs/layouts/PageTemplates.native.js +62 -0
  30. package/dist/cjs/layouts/PageTemplates.native.js.map +1 -1
  31. package/dist/cjs/layouts/barTitleSpan.cjs +54 -0
  32. package/dist/cjs/layouts/barTitleSpan.native.js +78 -0
  33. package/dist/cjs/layouts/barTitleSpan.native.js.map +1 -0
  34. package/dist/cjs/layouts/page.cjs +130 -41
  35. package/dist/cjs/layouts/page.native.js +143 -45
  36. package/dist/cjs/layouts/page.native.js.map +1 -1
  37. package/dist/cjs/views/ImageGrid.cjs +9 -0
  38. package/dist/cjs/views/ImageGrid.native.js +12 -1
  39. package/dist/cjs/views/ImageGrid.native.js.map +1 -1
  40. package/dist/esm/charts/BarChart.mjs +1 -0
  41. package/dist/esm/charts/BarChart.mjs.map +1 -1
  42. package/dist/esm/charts/BarChart.native.js +1 -0
  43. package/dist/esm/charts/BarChart.native.js.map +1 -1
  44. package/dist/esm/charts/ChartDataView.mjs +83 -3
  45. package/dist/esm/charts/ChartDataView.mjs.map +1 -1
  46. package/dist/esm/charts/ChartDataView.native.js +88 -3
  47. package/dist/esm/charts/ChartDataView.native.js.map +1 -1
  48. package/dist/esm/charts/ChartSurface.mjs +26 -8
  49. package/dist/esm/charts/ChartSurface.mjs.map +1 -1
  50. package/dist/esm/charts/ChartSurface.native.js +27 -9
  51. package/dist/esm/charts/ChartSurface.native.js.map +1 -1
  52. package/dist/esm/charts/chartHeight.mjs +1 -1
  53. package/dist/esm/charts/chartHeight.mjs.map +1 -1
  54. package/dist/esm/charts/chartHeight.native.js +1 -1
  55. package/dist/esm/charts/chartHeight.native.js.map +1 -1
  56. package/dist/esm/charts/composeChart.mjs +1 -1
  57. package/dist/esm/charts/composeChart.mjs.map +1 -1
  58. package/dist/esm/charts/composeChart.native.js +1 -1
  59. package/dist/esm/charts/composeChart.native.js.map +1 -1
  60. package/dist/esm/code/CodeBlock/index.mjs +39 -32
  61. package/dist/esm/code/CodeBlock/index.mjs.map +1 -1
  62. package/dist/esm/code/CodeBlock/index.native.js +39 -32
  63. package/dist/esm/code/CodeBlock/index.native.js.map +1 -1
  64. package/dist/esm/code/LogView.mjs +117 -0
  65. package/dist/esm/code/LogView.mjs.map +1 -0
  66. package/dist/esm/code/LogView.native.js +123 -0
  67. package/dist/esm/code/LogView.native.js.map +1 -0
  68. package/dist/esm/code/index.mjs +1 -0
  69. package/dist/esm/code/index.mjs.map +1 -1
  70. package/dist/esm/code/index.native.js +1 -0
  71. package/dist/esm/code/index.native.js.map +1 -1
  72. package/dist/esm/layouts/EmptyState.mjs +9 -43
  73. package/dist/esm/layouts/EmptyState.mjs.map +1 -1
  74. package/dist/esm/layouts/EmptyState.native.js +9 -45
  75. package/dist/esm/layouts/EmptyState.native.js.map +1 -1
  76. package/dist/esm/layouts/PageTemplates.mjs +61 -1
  77. package/dist/esm/layouts/PageTemplates.mjs.map +1 -1
  78. package/dist/esm/layouts/PageTemplates.native.js +62 -1
  79. package/dist/esm/layouts/PageTemplates.native.js.map +1 -1
  80. package/dist/esm/layouts/barTitleSpan.mjs +27 -0
  81. package/dist/esm/layouts/barTitleSpan.mjs.map +1 -0
  82. package/dist/esm/layouts/barTitleSpan.native.js +48 -0
  83. package/dist/esm/layouts/barTitleSpan.native.js.map +1 -0
  84. package/dist/esm/layouts/page.mjs +132 -43
  85. package/dist/esm/layouts/page.mjs.map +1 -1
  86. package/dist/esm/layouts/page.native.js +145 -47
  87. package/dist/esm/layouts/page.native.js.map +1 -1
  88. package/dist/esm/views/ImageGrid.mjs +10 -1
  89. package/dist/esm/views/ImageGrid.mjs.map +1 -1
  90. package/dist/esm/views/ImageGrid.native.js +13 -2
  91. package/dist/esm/views/ImageGrid.native.js.map +1 -1
  92. package/dist/jsx/charts/BarChart.mjs +1 -0
  93. package/dist/jsx/charts/BarChart.mjs.map +1 -1
  94. package/dist/jsx/charts/BarChart.native.js +1 -0
  95. package/dist/jsx/charts/BarChart.native.js.map +1 -1
  96. package/dist/jsx/charts/ChartDataView.mjs +83 -3
  97. package/dist/jsx/charts/ChartDataView.mjs.map +1 -1
  98. package/dist/jsx/charts/ChartDataView.native.js +94 -9
  99. package/dist/jsx/charts/ChartDataView.native.js.map +1 -1
  100. package/dist/jsx/charts/ChartSurface.mjs +26 -8
  101. package/dist/jsx/charts/ChartSurface.mjs.map +1 -1
  102. package/dist/jsx/charts/ChartSurface.native.js +27 -9
  103. package/dist/jsx/charts/ChartSurface.native.js.map +1 -1
  104. package/dist/jsx/charts/chartHeight.mjs +1 -1
  105. package/dist/jsx/charts/chartHeight.mjs.map +1 -1
  106. package/dist/jsx/charts/chartHeight.native.js +1 -1
  107. package/dist/jsx/charts/chartHeight.native.js.map +1 -1
  108. package/dist/jsx/charts/composeChart.mjs +1 -1
  109. package/dist/jsx/charts/composeChart.mjs.map +1 -1
  110. package/dist/jsx/charts/composeChart.native.js +1 -1
  111. package/dist/jsx/charts/composeChart.native.js.map +1 -1
  112. package/dist/jsx/code/CodeBlock/index.mjs +39 -32
  113. package/dist/jsx/code/CodeBlock/index.mjs.map +1 -1
  114. package/dist/jsx/code/CodeBlock/index.native.js +38 -31
  115. package/dist/jsx/code/CodeBlock/index.native.js.map +1 -1
  116. package/dist/jsx/code/LogView.mjs +117 -0
  117. package/dist/jsx/code/LogView.mjs.map +1 -0
  118. package/dist/jsx/code/LogView.native.js +151 -0
  119. package/dist/jsx/code/LogView.native.js.map +1 -0
  120. package/dist/jsx/code/index.mjs +1 -0
  121. package/dist/jsx/code/index.mjs.map +1 -1
  122. package/dist/jsx/code/index.native.js +1 -0
  123. package/dist/jsx/code/index.native.js.map +1 -1
  124. package/dist/jsx/layouts/EmptyState.mjs +9 -43
  125. package/dist/jsx/layouts/EmptyState.mjs.map +1 -1
  126. package/dist/jsx/layouts/EmptyState.native.js +9 -45
  127. package/dist/jsx/layouts/EmptyState.native.js.map +1 -1
  128. package/dist/jsx/layouts/PageTemplates.mjs +61 -1
  129. package/dist/jsx/layouts/PageTemplates.mjs.map +1 -1
  130. package/dist/jsx/layouts/PageTemplates.native.js +62 -0
  131. package/dist/jsx/layouts/PageTemplates.native.js.map +1 -1
  132. package/dist/jsx/layouts/barTitleSpan.mjs +27 -0
  133. package/dist/jsx/layouts/barTitleSpan.mjs.map +1 -0
  134. package/dist/jsx/layouts/barTitleSpan.native.js +78 -0
  135. package/dist/jsx/layouts/barTitleSpan.native.js.map +1 -0
  136. package/dist/jsx/layouts/page.mjs +132 -43
  137. package/dist/jsx/layouts/page.mjs.map +1 -1
  138. package/dist/jsx/layouts/page.native.js +143 -45
  139. package/dist/jsx/layouts/page.native.js.map +1 -1
  140. package/dist/jsx/views/ImageGrid.mjs +10 -1
  141. package/dist/jsx/views/ImageGrid.mjs.map +1 -1
  142. package/dist/jsx/views/ImageGrid.native.js +12 -1
  143. package/dist/jsx/views/ImageGrid.native.js.map +1 -1
  144. package/package.json +9 -9
  145. package/src/charts/BarChart.tsx +8 -2
  146. package/src/charts/ChartDataView.spec.tsx +23 -2
  147. package/src/charts/ChartDataView.tsx +87 -6
  148. package/src/charts/ChartSurface.tsx +17 -8
  149. package/src/charts/chartHeight.ts +8 -2
  150. package/src/charts/composeChart.ts +3 -2
  151. package/src/code/CodeBlock/CodeBlock.copy.spec.tsx +13 -0
  152. package/src/code/CodeBlock/index.tsx +46 -30
  153. package/src/code/LogView.tsx +127 -0
  154. package/src/code/index.ts +1 -0
  155. package/src/layouts/DenseContent.stories.tsx +93 -0
  156. package/src/layouts/EmptyState.spec.tsx +2 -0
  157. package/src/layouts/EmptyState.tsx +6 -39
  158. package/src/layouts/PageHeader.stories.tsx +238 -38
  159. package/src/layouts/PageTemplates.tsx +90 -0
  160. package/src/layouts/barTitleSpan.spec.ts +35 -0
  161. package/src/layouts/barTitleSpan.ts +44 -0
  162. package/src/layouts/glyphCentre.spec.tsx +218 -0
  163. package/src/layouts/navBar.spec.tsx +58 -2
  164. package/src/layouts/page.tsx +126 -34
  165. package/src/views/ImageGrid.tsx +19 -2
  166. package/types/charts/BarChart.d.ts +1 -1
  167. package/types/charts/BarChart.d.ts.map +1 -1
  168. package/types/charts/ChartDataView.d.ts +3 -1
  169. package/types/charts/ChartDataView.d.ts.map +1 -1
  170. package/types/charts/ChartSurface.d.ts.map +1 -1
  171. package/types/charts/chartHeight.d.ts +2 -1
  172. package/types/charts/chartHeight.d.ts.map +1 -1
  173. package/types/charts/composeChart.d.ts +2 -1
  174. package/types/charts/composeChart.d.ts.map +1 -1
  175. package/types/code/CodeBlock/index.d.ts.map +1 -1
  176. package/types/code/LogView.d.ts +31 -0
  177. package/types/code/LogView.d.ts.map +1 -0
  178. package/types/code/index.d.ts +1 -0
  179. package/types/code/index.d.ts.map +1 -1
  180. package/types/layouts/EmptyState.d.ts.map +1 -1
  181. package/types/layouts/PageTemplates.d.ts +26 -0
  182. package/types/layouts/PageTemplates.d.ts.map +1 -1
  183. package/types/layouts/barTitleSpan.d.ts +29 -0
  184. package/types/layouts/barTitleSpan.d.ts.map +1 -0
  185. package/types/layouts/page.d.ts +6 -1
  186. package/types/layouts/page.d.ts.map +1 -1
  187. package/types/views/ImageGrid.d.ts.map +1 -1
@@ -0,0 +1,218 @@
1
+ /**
2
+ * LC-176 (FZ-8442): a glyph on a glass circle sits at the circle's centre.
3
+ * Clay on the Kitchen Sink SHC Nodes story: "the icons inside of these are
4
+ * aligned wrong". The back caret was pulled toward the bar's edge and the "+"
5
+ * pushed past its circle's centre.
6
+ *
7
+ * jsdom has no layout, so the ink centre is computed: the offset each box
8
+ * between the glyph and its circle adds (a margin moves a centred child by
9
+ * half of it, a translate by all of it), plus where the glyph's ink sits in
10
+ * its 256-unit Phosphor grid, read from the rendered path.
11
+ */
12
+ import { IconButton } from "@multiplatform.one/forms";
13
+ import { renderWithProviders } from "@multiplatform.one/test-utils";
14
+ import { Surface } from "@multiplatform.one/theme";
15
+ import { PlusIcon, XIcon } from "@phosphor-icons/react";
16
+ import { cleanup, screen } from "@testing-library/react";
17
+ import { afterEach, describe, expect, it, vi } from "vitest";
18
+ import { PageBackButton, ScreenToolbar } from "./page";
19
+
20
+ const IPHONE =
21
+ "Mozilla/5.0 (iPhone; CPU iPhone OS 26_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Mobile/15E148 Safari/604.1";
22
+ const GRID = 256;
23
+ const TOLERANCE_PT = 0.5;
24
+
25
+ type Box = { minX: number; maxX: number; minY: number; maxY: number };
26
+
27
+ function arcExtremes(
28
+ box: Box,
29
+ from: [number, number],
30
+ r: number,
31
+ large: number,
32
+ sweep: number,
33
+ to: [number, number],
34
+ ) {
35
+ const [x1, y1] = from;
36
+ const [x2, y2] = to;
37
+ const mx = (x1 - x2) / 2;
38
+ const my = (y1 - y2) / 2;
39
+ const d2 = mx * mx + my * my;
40
+ const radius = Math.max(r, Math.sqrt(d2));
41
+ const k = (large === sweep ? -1 : 1) * Math.sqrt(Math.max(0, radius ** 2 / d2 - 1));
42
+ const cx = k * my + (x1 + x2) / 2;
43
+ const cy = -k * mx + (y1 + y2) / 2;
44
+ const start = Math.atan2(y1 - cy, x1 - cx);
45
+ let delta = Math.atan2(y2 - cy, x2 - cx) - start;
46
+ if (sweep && delta < 0) delta += 2 * Math.PI;
47
+ if (!sweep && delta > 0) delta -= 2 * Math.PI;
48
+ for (const angle of [0, Math.PI / 2, Math.PI, -Math.PI / 2]) {
49
+ let t = angle - start;
50
+ while (t < 0) t += 2 * Math.PI;
51
+ while (t >= 2 * Math.PI) t -= 2 * Math.PI;
52
+ const within = delta >= 0 ? t <= delta : t >= 2 * Math.PI + delta || t === 0;
53
+ if (within) include(box, cx + radius * Math.cos(angle), cy + radius * Math.sin(angle));
54
+ }
55
+ }
56
+
57
+ function include(box: Box, x: number, y: number) {
58
+ box.minX = Math.min(box.minX, x);
59
+ box.maxX = Math.max(box.maxX, x);
60
+ box.minY = Math.min(box.minY, y);
61
+ box.maxY = Math.max(box.maxY, y);
62
+ }
63
+
64
+ /** The ink box of an SVG path made of the commands Phosphor uses. */
65
+ function inkBox(d: string): Box {
66
+ const box: Box = { minX: Infinity, maxX: -Infinity, minY: Infinity, maxY: -Infinity };
67
+ const tokens = d.match(/[a-zA-Z]|-?(?:\d*\.\d+|\d+)(?:e-?\d+)?/g) ?? [];
68
+ let i = 0;
69
+ let command = "";
70
+ let x = 0;
71
+ let y = 0;
72
+ let startX = 0;
73
+ let startY = 0;
74
+ const num = () => Number(tokens[i++]);
75
+ while (i < tokens.length) {
76
+ if (/[a-zA-Z]/.test(tokens[i]!)) command = tokens[i++]!;
77
+ const rel = command === command.toLowerCase();
78
+ const ox = rel ? x : 0;
79
+ const oy = rel ? y : 0;
80
+ switch (command.toUpperCase()) {
81
+ case "M":
82
+ x = ox + num();
83
+ y = oy + num();
84
+ startX = x;
85
+ startY = y;
86
+ include(box, x, y);
87
+ command = rel ? "l" : "L";
88
+ break;
89
+ case "L":
90
+ x = ox + num();
91
+ y = oy + num();
92
+ include(box, x, y);
93
+ break;
94
+ case "H":
95
+ x = ox + num();
96
+ include(box, x, y);
97
+ break;
98
+ case "V":
99
+ y = oy + num();
100
+ include(box, x, y);
101
+ break;
102
+ case "C": {
103
+ for (let n = 0; n < 2; n++) include(box, ox + num(), oy + num());
104
+ x = ox + num();
105
+ y = oy + num();
106
+ include(box, x, y);
107
+ break;
108
+ }
109
+ case "A": {
110
+ const r = num();
111
+ num();
112
+ num();
113
+ const large = num();
114
+ const sweep = num();
115
+ const to: [number, number] = [ox + num(), oy + num()];
116
+ arcExtremes(box, [x, y], r, large, sweep, to);
117
+ [x, y] = to;
118
+ include(box, x, y);
119
+ break;
120
+ }
121
+ case "Z":
122
+ x = startX;
123
+ y = startY;
124
+ break;
125
+ default:
126
+ throw new Error(`inkBox: unhandled path command ${command}`);
127
+ }
128
+ }
129
+ return box;
130
+ }
131
+
132
+ const px = (value: string | undefined) => Number.parseFloat(value || "0") || 0;
133
+
134
+ function translate(transform: string, axis: "X" | "Y") {
135
+ const one = transform.match(new RegExp(`translate${axis}\\((-?[\\d.]+)px\\)`));
136
+ if (one) return Number(one[1]);
137
+ const both = transform.match(/translate\((-?[\d.]+)px(?:,\s*(-?[\d.]+)px)?\)/);
138
+ if (!both) return 0;
139
+ return axis === "X" ? Number(both[1]) : Number(both[2] ?? 0);
140
+ }
141
+
142
+ /** How far the glyph's ink centre sits from its circle's centre, in pt. */
143
+ function inkOffset(button: HTMLElement) {
144
+ const svg = button.querySelector("svg");
145
+ if (!svg) throw new Error("no glyph");
146
+ const size = Number(svg.getAttribute("width"));
147
+ const scale = size / GRID;
148
+ const box = inkBox(
149
+ Array.from(svg.querySelectorAll("path"))
150
+ .map((path) => path.getAttribute("d") ?? "")
151
+ .join(" "),
152
+ );
153
+ let dx = ((box.minX + box.maxX) / 2 - GRID / 2) * scale;
154
+ let dy = ((box.minY + box.maxY) / 2 - GRID / 2) * scale;
155
+ const frame = getComputedStyle(button);
156
+ dx += (px(frame.paddingLeft) - px(frame.paddingRight)) / 2;
157
+ dy += (px(frame.paddingTop) - px(frame.paddingBottom)) / 2;
158
+ for (let el: Element | null = svg; el && el !== button; el = el.parentElement) {
159
+ const style = getComputedStyle(el);
160
+ dx +=
161
+ (px(style.marginLeft) +
162
+ px(style.marginInlineStart) -
163
+ px(style.marginRight) -
164
+ px(style.marginInlineEnd)) /
165
+ 2 +
166
+ translate(style.transform, "X");
167
+ dy += (px(style.marginTop) - px(style.marginBottom)) / 2 + translate(style.transform, "Y");
168
+ }
169
+ return { dx, dy, size };
170
+ }
171
+
172
+ afterEach(() => {
173
+ vi.unstubAllGlobals();
174
+ cleanup();
175
+ });
176
+
177
+ describe("glyph centre == glass circle centre (LC-176, FZ-8442)", () => {
178
+ it("the ink box reads Phosphor's bold glyphs where they draw", () => {
179
+ const plus = inkBox(
180
+ "M228,128a12,12,0,0,1-12,12H140v76a12,12,0,0,1-24,0V140H40a12,12,0,0,1,0-24h76V40a12,12,0,0,1,24,0v76h76A12,12,0,0,1,228,128Z",
181
+ );
182
+ expect([plus.minX, plus.maxX, plus.minY, plus.maxY].map(Math.round)).toEqual([
183
+ 28, 228, 28, 228,
184
+ ]);
185
+ const caret = inkBox(
186
+ "M168.49,199.51a12,12,0,0,1-17,17l-80-80a12,12,0,0,1,0-17l80-80a12,12,0,0,1,17,17L97,128Z",
187
+ );
188
+ expect(Math.round((caret.minX + caret.maxX) / 2)).toBe(120);
189
+ });
190
+
191
+ it("off glass the back caret keeps its optical pull, so the measure sees margins", () => {
192
+ renderWithProviders(<ScreenToolbar leading={<PageBackButton />} />);
193
+ const back = screen.getByLabelText("Back");
194
+ expect(back.getAttribute("data-mp-icon-button")).not.toBe("glass");
195
+ const { dx, size } = inkOffset(back);
196
+ expect(dx).toBeLessThan(-size * 0.05);
197
+ });
198
+
199
+ it("back caret, + and ✕ sit at their circle's centre within 0.5pt on iPhone", () => {
200
+ vi.stubGlobal("navigator", { userAgent: IPHONE, platform: "iPhone", maxTouchPoints: 5 });
201
+ renderWithProviders(
202
+ <Surface bar>
203
+ <ScreenToolbar
204
+ leading={<PageBackButton />}
205
+ trailing={<IconButton icon={PlusIcon} aria-label="Add node" edge="end" />}
206
+ />
207
+ <IconButton icon={XIcon} aria-label="Close" edge="start" />
208
+ </Surface>,
209
+ );
210
+ for (const name of ["Back", "Add node", "Close"]) {
211
+ const button = screen.getByLabelText(name);
212
+ expect(button.getAttribute("data-mp-icon-button"), name).toBe("glass");
213
+ const { dx, dy } = inkOffset(button);
214
+ expect(Math.abs(dx), `${name} dx`).toBeLessThanOrEqual(TOLERANCE_PT);
215
+ expect(Math.abs(dy), `${name} dy`).toBeLessThanOrEqual(TOLERANCE_PT);
216
+ }
217
+ });
218
+ });
@@ -8,10 +8,10 @@
8
8
  * jsdom has no layout: the large title's geometry is stubbed through
9
9
  * getBoundingClientRect, and scrolling sets scrollTop on the scroll element.
10
10
  */
11
- import { ICON_BUTTON_GLYPH_PX } from "@multiplatform.one/forms";
11
+ import { ICON_BUTTON_GLYPH_PX, IconButton } from "@multiplatform.one/forms";
12
12
  import { renderWithProviders } from "@multiplatform.one/test-utils";
13
13
  import { Preset, useGlyphTintOnSurface } from "@multiplatform.one/theme";
14
- import { SlidersHorizontalIcon } from "@phosphor-icons/react";
14
+ import { PlusIcon, SlidersHorizontalIcon } from "@phosphor-icons/react";
15
15
  import { act, cleanup, fireEvent, screen } from "@testing-library/react";
16
16
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
17
17
  import {
@@ -269,3 +269,59 @@ describe("bar glyphs carry their weight (LC-176)", () => {
269
269
  expect(screen.getByLabelText("Back").closest("[data-mp-icon-button-group]")).toBeNull();
270
270
  });
271
271
  });
272
+
273
+ const IPHONE =
274
+ "Mozilla/5.0 (iPhone; CPU iPhone OS 26_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Mobile/15E148 Safari/604.1";
275
+
276
+ describe("inline bar title and glyphs on glass (FZ-8442)", () => {
277
+ afterEach(() => vi.unstubAllGlobals());
278
+
279
+ it("a title is centred in the flow toolbar and shown at rest, clear of the back control", () => {
280
+ renderWithProviders(
281
+ <ScreenToolbar
282
+ leading={<PageBackButton />}
283
+ title="Inbox"
284
+ trailing={<PageBarButton icon={SlidersHorizontalIcon} aria-label="Filter" />}
285
+ />,
286
+ );
287
+ const title = document.querySelector("[data-bar-title]") as HTMLElement;
288
+ expect(title.textContent).toBe("Inbox");
289
+ expect(title.getAttribute("aria-hidden")).not.toBe("true");
290
+ const back = screen.getByLabelText("Back");
291
+ expect(title.contains(back)).toBe(false);
292
+ expect(back.parentElement?.contains(title)).toBe(false);
293
+ });
294
+
295
+ it("the pinned bar shows a given title at rest", () => {
296
+ renderWithProviders(
297
+ <Screen topBar={<ScreenToolbar leading={<PageBackButton />} title="Inbox" />}>
298
+ <div style={{ height: 2000 }} />
299
+ </Screen>,
300
+ );
301
+ const title = document.querySelector("[data-top-bar] [data-bar-title]") as HTMLElement;
302
+ expect(title.textContent).toBe("Inbox");
303
+ expect(title.getAttribute("aria-hidden")).not.toBe("true");
304
+ });
305
+
306
+ it("on glass the back caret drops its pull and a lone + keeps its own circle", () => {
307
+ vi.stubGlobal("navigator", { userAgent: IPHONE, platform: "iPhone", maxTouchPoints: 5 });
308
+ renderWithProviders(
309
+ <Screen topBar={<ScreenToolbar leading={<PageBackButton />} />}>
310
+ <PageHeader
311
+ title="Nodes"
312
+ actions={<IconButton icon={PlusIcon} aria-label="Add node" edge="end" />}
313
+ />
314
+ </Screen>,
315
+ );
316
+ const back = screen.getByLabelText("Back");
317
+ expect(back.getAttribute("data-mp-icon-button")).toBe("glass");
318
+ const caret = back.querySelector("svg")!;
319
+ const pull = Math.round(Number(caret.getAttribute("width")) * (72 / 256));
320
+ expect(Array.from(caret.parentElement!.classList).some((c) => c.includes(`-${pull}px`))).toBe(
321
+ false,
322
+ );
323
+ const add = screen.getByLabelText("Add node");
324
+ expect(add.getAttribute("data-mp-icon-button")).toBe("glass");
325
+ expect(add.closest("[data-mp-glass-capsule]")).toBeNull();
326
+ });
327
+ });
@@ -33,9 +33,15 @@ import {
33
33
  type PageTitleScale,
34
34
  type ParentScreen,
35
35
  } from "@multiplatform.one/theme";
36
- import { Button, IconButtonGroup, type ButtonProps } from "@multiplatform.one/forms";
36
+ import {
37
+ Button,
38
+ IconButtonGroup,
39
+ useGlyphOnPlate,
40
+ type ButtonProps,
41
+ } from "@multiplatform.one/forms";
37
42
  import { CaretLeftIcon, CaretRightIcon, DotsThreeIcon } from "@phosphor-icons/react";
38
43
  import { useState, type ReactNode } from "react";
44
+ import { barTitleSpan, sideExtents } from "./barTitleSpan";
39
45
  import type { LayoutChangeEvent, NativeScrollEvent, NativeSyntheticEvent } from "react-native";
40
46
  import type { ScrollViewProps as TamaguiScrollViewProps, XStackProps, YStackProps } from "tamagui";
41
47
  import {
@@ -655,11 +661,94 @@ export { EmptyState, type EmptyStateProps } from "./EmptyState";
655
661
  // ScreenToolbar — minimal back/edit-style screen toolbar
656
662
  // ---------------------------------------------------------------------------
657
663
 
658
- export interface ScreenToolbarProps extends XStackProps {
664
+ export interface ScreenToolbarProps extends Omit<XStackProps, "title"> {
659
665
  /** Leading content (typically a back button). */
660
666
  leading?: ReactNode;
661
667
  /** Trailing content (typically primary/secondary actions). */
662
668
  trailing?: ReactNode;
669
+ /**
670
+ * The bar's inline title (the iOS inline navigation title): centred in the
671
+ * bar, clear of the wider side group, never set against the back control.
672
+ */
673
+ title?: string;
674
+ }
675
+
676
+ function useBarTitleSpan() {
677
+ const none = { x: 0, width: 0 };
678
+ const [box, setBox] = useState({ row: 0, leading: none, trailing: none, title: 0 });
679
+ const set = <K extends keyof typeof box>(key: K, value: (typeof box)[K]) =>
680
+ setBox((prev) =>
681
+ JSON.stringify(prev[key]) === JSON.stringify(value) ? prev : { ...prev, [key]: value },
682
+ );
683
+ const extent = (event: LayoutChangeEvent) => {
684
+ const { x, width } = event.nativeEvent.layout;
685
+ return { x, width };
686
+ };
687
+ return {
688
+ span: barTitleSpan({
689
+ row: box.row,
690
+ title: box.title,
691
+ ...sideExtents(box.row, box.leading, box.trailing),
692
+ }),
693
+ measureRow: (event: LayoutChangeEvent) => set("row", Math.floor(extent(event).width)),
694
+ measureLeading: (event: LayoutChangeEvent) => set("leading", extent(event)),
695
+ measureTrailing: (event: LayoutChangeEvent) => set("trailing", extent(event)),
696
+ measureTitle: (event: LayoutChangeEvent) => set("title", Math.ceil(extent(event).width)),
697
+ };
698
+ }
699
+
700
+ function BarTitle({
701
+ title,
702
+ span,
703
+ onTitleWidth,
704
+ shown = true,
705
+ ...rest
706
+ }: {
707
+ title: string;
708
+ span: { left: number; right: number };
709
+ onTitleWidth: (event: LayoutChangeEvent) => void;
710
+ shown?: boolean;
711
+ } & XStackProps) {
712
+ const { knobProps } = useResolvedKnobs({ component: "ScreenToolbar" });
713
+ const text = {
714
+ ...knobProps.body,
715
+ fontWeight: "600",
716
+ color: "$color12",
717
+ numberOfLines: 1,
718
+ } as const;
719
+ return (
720
+ <>
721
+ {shown ? (
722
+ <XStack
723
+ position="absolute"
724
+ top={0}
725
+ left={0}
726
+ opacity={0}
727
+ pointerEvents="none"
728
+ aria-hidden
729
+ onLayout={onTitleWidth}
730
+ >
731
+ <SizableText {...text}>{title}</SizableText>
732
+ </XStack>
733
+ ) : null}
734
+ <XStack
735
+ position="absolute"
736
+ top={0}
737
+ bottom={0}
738
+ left={span.left}
739
+ right={span.right}
740
+ alignItems="center"
741
+ justifyContent="center"
742
+ pointerEvents="none"
743
+ aria-hidden={!shown}
744
+ data-bar-title=""
745
+ opacity={shown ? 1 : 0}
746
+ {...rest}
747
+ >
748
+ <SizableText {...text}>{title}</SizableText>
749
+ </XStack>
750
+ </>
751
+ );
663
752
  }
664
753
 
665
754
  /**
@@ -679,8 +768,9 @@ export function ScreenToolbar(props: ScreenToolbarProps) {
679
768
  return slot ? <PinnedTopBar {...props} slot={slot} /> : <InlineToolbar {...props} />;
680
769
  }
681
770
 
682
- function InlineToolbar({ leading, trailing, children, ...rest }: ScreenToolbarProps) {
771
+ function InlineToolbar({ leading, trailing, title, children, ...rest }: ScreenToolbarProps) {
683
772
  const { knobProps } = useResolvedKnobs({ component: "ScreenToolbar" });
773
+ const titleSpan = useBarTitleSpan();
684
774
  const insetToken = usePageChromeInset();
685
775
  const bleed = insetToken ? { marginHorizontal: negateSpaceToken(insetToken) as "$4" } : null;
686
776
  // LC-145: a phone top bar is one row; the leading group shrinks first.
@@ -692,8 +782,9 @@ function InlineToolbar({ leading, trailing, children, ...rest }: ScreenToolbarPr
692
782
  data-testid="screen-toolbar"
693
783
  justifyContent="space-between"
694
784
  alignItems="center"
695
- flexWrap={oneRow ? "nowrap" : "wrap"}
785
+ flexWrap={oneRow || title ? "nowrap" : "wrap"}
696
786
  minHeight={MIN_PRESS_TARGET}
787
+ {...(title ? { position: "relative" as const, onLayout: titleSpan.measureRow } : null)}
697
788
  {...bleed}
698
789
  {...(insetToken ? { paddingHorizontal: insetToken as "$4" } : knobProps.panelPadding)}
699
790
  {...knobProps.gap}
@@ -706,6 +797,7 @@ function InlineToolbar({ leading, trailing, children, ...rest }: ScreenToolbarPr
706
797
  // Shrink weight, not a size: the back label gives way before the actions wrap.
707
798
  flexShrink={oneRow ? 1000 : 1}
708
799
  minWidth={0}
800
+ {...(title ? { onLayout: titleSpan.measureLeading } : null)}
709
801
  >
710
802
  {leading}
711
803
  </XStack>
@@ -716,9 +808,13 @@ function InlineToolbar({ leading, trailing, children, ...rest }: ScreenToolbarPr
716
808
  flexShrink={1}
717
809
  minWidth={0}
718
810
  justifyContent="flex-end"
811
+ {...(title ? { onLayout: titleSpan.measureTrailing } : null)}
719
812
  >
720
813
  {trailing}
721
814
  </IconButtonGroup>
815
+ {title ? (
816
+ <BarTitle title={title} span={titleSpan.span} onTitleWidth={titleSpan.measureTitle} />
817
+ ) : null}
722
818
  </XStack>
723
819
  </Surface>
724
820
  );
@@ -737,19 +833,16 @@ function InlineToolbar({ leading, trailing, children, ...rest }: ScreenToolbarPr
737
833
  function PinnedTopBar({
738
834
  leading,
739
835
  trailing,
836
+ title: inlineTitle,
740
837
  children,
741
838
  slot,
742
839
  ...rest
743
840
  }: ScreenToolbarProps & { slot: { inset: string | null; maxWidth: number | null } }) {
744
841
  const { knobProps } = useResolvedKnobs({ component: "ScreenToolbar" });
745
- const { scrolled, collapsed, title } = useScreenScroll();
746
- const [sides, setSides] = useState({ leading: 0, trailing: 0 });
747
- const measureSide = (side: "leading" | "trailing") => (event: LayoutChangeEvent) => {
748
- const width = Math.ceil(event.nativeEvent.layout.width);
749
- setSides((prev) => (prev[side] === width ? prev : { ...prev, [side]: width }));
750
- };
842
+ const { scrolled, collapsed, title: largeTitle } = useScreenScroll();
843
+ const titleSpan = useBarTitleSpan();
751
844
  const motion = transitionProps(knobProps.motion.control);
752
- const clearance = Math.max(sides.leading, sides.trailing);
845
+ const title = inlineTitle ?? largeTitle;
753
846
  // LC-153: the pinned bar is a bar, so its neutral buttons paint plain.
754
847
  return (
755
848
  <Surface bar>
@@ -772,6 +865,7 @@ function PinnedTopBar({
772
865
  flexWrap="nowrap"
773
866
  // The collapsed title is placed against this row, not the page.
774
867
  position="relative"
868
+ onLayout={titleSpan.measureRow}
775
869
  paddingHorizontal={(slot.inset ?? knobProps.panelPadding.padding) as "$4"}
776
870
  {...knobProps.gap}
777
871
  {...rest}
@@ -781,7 +875,7 @@ function PinnedTopBar({
781
875
  alignItems="center"
782
876
  flexShrink={1000}
783
877
  minWidth={0}
784
- onLayout={measureSide("leading")}
878
+ onLayout={titleSpan.measureLeading}
785
879
  >
786
880
  {leading}
787
881
  </XStack>
@@ -794,29 +888,18 @@ function PinnedTopBar({
794
888
  flexShrink={1}
795
889
  minWidth={0}
796
890
  justifyContent="flex-end"
797
- onLayout={measureSide("trailing")}
891
+ onLayout={titleSpan.measureTrailing}
798
892
  >
799
893
  {trailing}
800
894
  </IconButtonGroup>
801
895
  {title ? (
802
- <XStack
803
- position="absolute"
804
- top={0}
805
- bottom={0}
806
- left={clearance}
807
- right={clearance}
808
- alignItems="center"
809
- justifyContent="center"
810
- pointerEvents="none"
811
- aria-hidden={!collapsed}
812
- data-bar-title=""
813
- opacity={collapsed ? 1 : 0}
896
+ <BarTitle
897
+ title={title}
898
+ span={titleSpan.span}
899
+ onTitleWidth={titleSpan.measureTitle}
900
+ shown={Boolean(inlineTitle) || collapsed}
814
901
  {...motion}
815
- >
816
- <SizableText {...knobProps.body} fontWeight="600" color="$color12" numberOfLines={1}>
817
- {title}
818
- </SizableText>
819
- </XStack>
902
+ />
820
903
  ) : null}
821
904
  </XStack>
822
905
  </YStack>
@@ -841,8 +924,11 @@ function useTopBarControl() {
841
924
  // Phosphor's caret path starts 72 units into its 256 grid; back pulls by that
842
925
  // so the caret's point, not its box, lands on the title's leading edge.
843
926
  const CARET_OPTICAL_INSET = 72 / 256;
927
+ // Its ink is centred 8 units toward the point, so on a glass circle it moves
928
+ // back by that to sit at the circle's centre (FZ-8442).
929
+ const CARET_INK_OFFSET = 8 / 256;
844
930
 
845
- function backCaret(Caret: typeof CaretLeftIcon) {
931
+ function backCaret(Caret: typeof CaretLeftIcon, inkSign: 1 | -1) {
846
932
  return function BackCaret({
847
933
  size = 22,
848
934
  color,
@@ -856,16 +942,22 @@ function backCaret(Caret: typeof CaretLeftIcon) {
856
942
  strokeWidth?: number;
857
943
  strokeLinejoin?: "round";
858
944
  }) {
945
+ const plated = useGlyphOnPlate();
859
946
  return (
860
- <XStack data-back-caret="" marginInlineStart={-Math.round(size * CARET_OPTICAL_INSET)}>
947
+ <XStack
948
+ data-back-caret=""
949
+ {...(plated
950
+ ? { x: inkSign * size * CARET_INK_OFFSET }
951
+ : { marginInlineStart: -Math.round(size * CARET_OPTICAL_INSET) })}
952
+ >
861
953
  <Caret size={size} color={color} weight={weight} {...stroke} />
862
954
  </XStack>
863
955
  );
864
956
  };
865
957
  }
866
958
 
867
- const BackCaretLeft = backCaret(CaretLeftIcon);
868
- const BackCaretRight = backCaret(CaretRightIcon);
959
+ const BackCaretLeft = backCaret(CaretLeftIcon, 1);
960
+ const BackCaretRight = backCaret(CaretRightIcon, -1);
869
961
 
870
962
  export interface PageBackButtonProps extends Omit<ButtonProps, "children"> {
871
963
  /** Where back goes, shown beside the caret (the list's name). */
@@ -30,6 +30,7 @@ import {
30
30
  XStack,
31
31
  YStack,
32
32
  getTokenValue,
33
+ isWeb,
33
34
  useWindowDimensions,
34
35
  type YStackProps,
35
36
  } from "tamagui";
@@ -251,6 +252,7 @@ function ImageGridTile({
251
252
  data-focused={isFocused || undefined}
252
253
  data-media-tile="image-grid"
253
254
  position="relative"
255
+ flexGrow={1}
254
256
  {...radiusFragment}
255
257
  borderWidth={0}
256
258
  cursor={clickable ? "pointer" : undefined}
@@ -264,8 +266,23 @@ function ImageGridTile({
264
266
  onPress={onPress}
265
267
  >
266
268
  {/* Clip media to the radius; keep overflow off the ring node so
267
- LC-71 outline is not severed (same split as Input.Box). */}
268
- <View borderRadius={radius} overflow="hidden">
269
+ LC-71 outline is not severed (same split as Input.Box).
270
+ LC-179: every tile takes its row's height. On web the clip is a
271
+ one-cell grid so a card drawn inside stretches to that height. */}
272
+ <View
273
+ borderRadius={radius}
274
+ overflow="hidden"
275
+ flexGrow={1}
276
+ {...(isWeb
277
+ ? {
278
+ style: {
279
+ display: "grid",
280
+ gridTemplateColumns: "minmax(0, 1fr)",
281
+ justifyItems: "stretch",
282
+ },
283
+ }
284
+ : undefined)}
285
+ >
269
286
  <MediaRadiusContext.Provider value={radius}>{children}</MediaRadiusContext.Provider>
270
287
  </View>
271
288
  {hovered && !showRing ? (
@@ -3,7 +3,7 @@ import type { YStackProps } from "tamagui";
3
3
  import type { ChartDatum, ChartDatumEvents } from "./types";
4
4
  export interface BarChartProps extends ChartDatumEvents, Omit<YStackProps, "children" | "width" | "height"> {
5
5
  data: ChartDatum[];
6
- /** Drawing height as a theme size token or pixels (default 200). */
6
+ /** Drawing height as a theme size token, pixels, or "fill" (default 200). */
7
7
  height?: ChartHeight;
8
8
  /** Explicit width bypasses responsive measurement. */
9
9
  width?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"BarChart.d.ts","sourceRoot":"","sources":["../../src/charts/BarChart.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAc3C,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAG5D,MAAM,WAAW,aACf,SAAQ,gBAAgB,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC5E,IAAI,EAAE,UAAU,EAAE,CAAC;IACnB,oEAAoE;IACpE,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3C,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3B;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,MAAY,EACZ,KAAK,EACL,WAAmB,EACnB,KAAK,EACL,MAAM,EACN,SAAgB,EAChB,SAAgB,EAChB,QAAe,EACf,MAAU,EACV,cAAc,EACd,KAAK,EACL,KAAK,EACL,MAAM,EAAE,UAAU,EAClB,YAAY,EACZ,cAAc,EACd,eAAe,EACf,GAAG,UAAU,EACd,EAAE,aAAa,2CA6Ff"}
1
+ {"version":3,"file":"BarChart.d.ts","sourceRoot":"","sources":["../../src/charts/BarChart.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAc3C,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAG5D,MAAM,WAAW,aACf,SAAQ,gBAAgB,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC5E,IAAI,EAAE,UAAU,EAAE,CAAC;IACnB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3C,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3B;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,MAAY,EACZ,KAAK,EACL,WAAmB,EACnB,KAAK,EACL,MAAM,EACN,SAAgB,EAChB,SAAgB,EAChB,QAAe,EACf,MAAU,EACV,cAAc,EACd,KAAK,EACL,KAAK,EACL,MAAM,EAAE,UAAU,EAClB,YAAY,EACZ,cAAc,EACd,eAAe,EACf,GAAG,UAAU,EACd,EAAE,aAAa,2CAmGf"}
@@ -14,9 +14,11 @@ export interface ChartDataViewProps {
14
14
  /** One complete, reachable data view. The ordinary chart keeps its short name. */
15
15
  export declare function ChartDataView({ data, title, valueFormatter, children }: ChartDataViewProps): import("react/jsx-runtime").JSX.Element;
16
16
  /** Shared chart implementations join a composed header instead of adding a second action. */
17
- export declare function ChartDataFrame({ data, title, valueFormatter, width, children, }: Omit<ChartDataViewProps, "children"> & {
17
+ export declare function ChartDataFrame({ data, title, valueFormatter, width, fill, children, }: Omit<ChartDataViewProps, "children"> & {
18
18
  children: ReactNode;
19
19
  width?: number;
20
+ /** The chart flexes to its region's height (LC-215). */
21
+ fill?: boolean;
20
22
  }): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element | null | undefined;
21
23
  export declare function useChartDataViewProps(): Record<string, unknown>;
22
24
  //# sourceMappingURL=ChartDataView.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChartDataView.d.ts","sourceRoot":"","sources":["../../src/charts/ChartDataView.tsx"],"names":[],"mappings":"AAGA,OAAO,EAA8C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAWnF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAI1C,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3C,4EAA4E;IAC5E,QAAQ,EAAE,CAAC,IAAI,EAAE;QACf,MAAM,EAAE,SAAS,CAAC;QAClB,IAAI,EAAE,UAAU,EAAE,CAAC;QACnB,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;KAC3C,KAAK,SAAS,CAAC;CACjB;AAED,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,EAAE,kBAAkB,2CA2F1F;AAED,6FAA6F;AAC7F,wBAAgB,cAAc,CAAC,EAC7B,IAAI,EACJ,KAAK,EACL,cAAc,EACd,KAAK,EACL,QAAQ,GACT,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,CAAC,GAAG;IAAE,QAAQ,EAAE,SAAS,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,2UAchF;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAO/D"}
1
+ {"version":3,"file":"ChartDataView.d.ts","sourceRoot":"","sources":["../../src/charts/ChartDataView.tsx"],"names":[],"mappings":"AAIA,OAAO,EAA8C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAanF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAI1C,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3C,4EAA4E;IAC5E,QAAQ,EAAE,CAAC,IAAI,EAAE;QACf,MAAM,EAAE,SAAS,CAAC;QAClB,IAAI,EAAE,UAAU,EAAE,CAAC;QACnB,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;KAC3C,KAAK,SAAS,CAAC;CACjB;AAED,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,EAAE,kBAAkB,2CA2F1F;AAED,6FAA6F;AAC7F,wBAAgB,cAAc,CAAC,EAC7B,IAAI,EACJ,KAAK,EACL,cAAc,EACd,KAAK,EACL,IAAI,EACJ,QAAQ,GACT,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,CAAC,GAAG;IACxC,QAAQ,EAAE,SAAS,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,2UAkCA;AAsDD,wBAAgB,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAO/D"}
@@ -1 +1 @@
1
- {"version":3,"file":"ChartSurface.d.ts","sourceRoot":"","sources":["../../src/charts/ChartSurface.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjE,OAAO,EAAyB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE9D,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAA2B,KAAK,qBAAqB,EAAE,MAAM,OAAO,CAAC;AAE5E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGzC,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,WAAW,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC3F;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,oFAAoF;IACpF,KAAK,CAAC,EAAE,qBAAqB,CAAC;IAC9B,oEAAoE;IACpE,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,SAAS,CAAC;CAC1C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,KAAK,EACL,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,SAAS,EAChB,QAAQ,EACR,GAAG,UAAU,EACd,EAAE,iBAAiB,2CA6BnB"}
1
+ {"version":3,"file":"ChartSurface.d.ts","sourceRoot":"","sources":["../../src/charts/ChartSurface.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjE,OAAO,EAAyB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE9D,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAA2B,KAAK,qBAAqB,EAAE,MAAM,OAAO,CAAC;AAE5E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGzC,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,WAAW,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC3F;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,oFAAoF;IACpF,KAAK,CAAC,EAAE,qBAAqB,CAAC;IAC9B,oEAAoE;IACpE,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,SAAS,CAAC;CAC1C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,KAAK,EACL,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,SAAS,EAChB,QAAQ,EACR,GAAG,UAAU,EACd,EAAE,iBAAiB,2CAsCnB"}
@@ -1,4 +1,5 @@
1
1
  import { type SizeKey } from "@multiplatform.one/theme";
2
- export type ChartHeight = number | SizeKey;
2
+ /** `"fill"` flexes the chart to the height its region hands it (LC-215). */
3
+ export type ChartHeight = number | SizeKey | "fill";
3
4
  export declare function useChartHeight(height: ChartHeight | undefined, fallback: number): number;
4
5
  //# sourceMappingURL=chartHeight.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"chartHeight.d.ts","sourceRoot":"","sources":["../../src/charts/chartHeight.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0C,KAAK,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAEhG,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3C,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIxF"}
1
+ {"version":3,"file":"chartHeight.d.ts","sourceRoot":"","sources":["../../src/charts/chartHeight.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0C,KAAK,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAEhG,4EAA4E;AAC5E,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAEpD,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CASxF"}