@k2b/ui 0.34.0 → 0.36.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 (126) hide show
  1. package/dist/browser/actions/Dropdown.js +1 -0
  2. package/dist/browser/actions/Dropdown.js.map +1 -1
  3. package/dist/browser/content/MapView.js +128 -13
  4. package/dist/browser/content/MapView.js.map +1 -1
  5. package/dist/browser/content/MapViewFrame.js +1 -1
  6. package/dist/browser/content/MapViewFrame.js.map +1 -1
  7. package/dist/browser/content/MatchText.js +61 -0
  8. package/dist/browser/content/MatchText.js.map +1 -0
  9. package/dist/browser/content/index.js +2 -0
  10. package/dist/browser/content/index.js.map +1 -1
  11. package/dist/browser/content/map-view-glyphs.js +23 -0
  12. package/dist/browser/content/map-view-glyphs.js.map +1 -0
  13. package/dist/browser/content/map-view-live.js +45 -22
  14. package/dist/browser/content/map-view-live.js.map +1 -1
  15. package/dist/browser/content/map-view-snapshot.js +191 -0
  16. package/dist/browser/content/map-view-snapshot.js.map +1 -0
  17. package/dist/browser/content/map-view-types.js.map +1 -1
  18. package/dist/browser/inputs/Combobox.js +139 -62
  19. package/dist/browser/inputs/Combobox.js.map +1 -1
  20. package/dist/browser/inputs/TextInput.js +1 -1
  21. package/dist/browser/inputs/TextInput.js.map +1 -1
  22. package/dist/browser/layout/AppWorkspace.js +73 -70
  23. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  24. package/dist/browser/layout/ScrollArea.js +4 -1
  25. package/dist/browser/layout/ScrollArea.js.map +1 -1
  26. package/dist/browser/text-editor/TextEditor.js +1358 -0
  27. package/dist/browser/text-editor/TextEditor.js.map +1 -0
  28. package/dist/browser/text-editor/clipboard-html.js +152 -0
  29. package/dist/browser/text-editor/clipboard-html.js.map +1 -0
  30. package/dist/browser/text-editor/clipboard-loading.js +68 -0
  31. package/dist/browser/text-editor/clipboard-loading.js.map +1 -0
  32. package/dist/browser/text-editor/clipboard.js +51 -0
  33. package/dist/browser/text-editor/clipboard.js.map +1 -0
  34. package/dist/browser/text-editor/engine.js +125 -0
  35. package/dist/browser/text-editor/engine.js.map +1 -0
  36. package/dist/browser/text-editor/format.js +218 -0
  37. package/dist/browser/text-editor/format.js.map +1 -0
  38. package/dist/browser/text-editor/formatted.js +164 -0
  39. package/dist/browser/text-editor/formatted.js.map +1 -0
  40. package/dist/browser/text-editor/language.js +19 -0
  41. package/dist/browser/text-editor/language.js.map +1 -0
  42. package/dist/browser/text-editor/markdown-table.js +563 -0
  43. package/dist/browser/text-editor/markdown-table.js.map +1 -0
  44. package/dist/browser/text-editor/messages.js +233 -0
  45. package/dist/browser/text-editor/messages.js.map +1 -0
  46. package/dist/browser/text-editor/paste.js +115 -0
  47. package/dist/browser/text-editor/paste.js.map +1 -0
  48. package/dist/browser/text-editor/table.js +1760 -0
  49. package/dist/browser/text-editor/table.js.map +1 -0
  50. package/dist/browser/text-editor.js +5 -0
  51. package/dist/browser/text-editor.js.map +1 -0
  52. package/dist/ssr/actions/Dropdown.js +1 -0
  53. package/dist/ssr/actions/Dropdown.js.map +1 -1
  54. package/dist/ssr/content/MapView.js +128 -13
  55. package/dist/ssr/content/MapView.js.map +1 -1
  56. package/dist/ssr/content/MapViewFrame.js +1 -1
  57. package/dist/ssr/content/MapViewFrame.js.map +1 -1
  58. package/dist/ssr/content/MatchText.js +56 -0
  59. package/dist/ssr/content/MatchText.js.map +1 -0
  60. package/dist/ssr/content/index.js +2 -0
  61. package/dist/ssr/content/index.js.map +1 -1
  62. package/dist/ssr/content/map-view-glyphs.js +23 -0
  63. package/dist/ssr/content/map-view-glyphs.js.map +1 -0
  64. package/dist/ssr/content/map-view-snapshot.js +191 -0
  65. package/dist/ssr/content/map-view-snapshot.js.map +1 -0
  66. package/dist/ssr/content/map-view-types.js.map +1 -1
  67. package/dist/ssr/inputs/Combobox.js +66 -20
  68. package/dist/ssr/inputs/Combobox.js.map +1 -1
  69. package/dist/ssr/inputs/TextInput.js.map +1 -1
  70. package/dist/ssr/layout/AppWorkspace.js +1 -1
  71. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  72. package/dist/ssr/layout/ScrollArea.js +4 -1
  73. package/dist/ssr/layout/ScrollArea.js.map +1 -1
  74. package/dist/ssr/text-editor/TextEditor.js +1155 -0
  75. package/dist/ssr/text-editor/TextEditor.js.map +1 -0
  76. package/dist/ssr/text-editor/clipboard-html.js +152 -0
  77. package/dist/ssr/text-editor/clipboard-html.js.map +1 -0
  78. package/dist/ssr/text-editor/clipboard-loading.js +68 -0
  79. package/dist/ssr/text-editor/clipboard-loading.js.map +1 -0
  80. package/dist/ssr/text-editor/clipboard.js +51 -0
  81. package/dist/ssr/text-editor/clipboard.js.map +1 -0
  82. package/dist/ssr/text-editor/engine.js +125 -0
  83. package/dist/ssr/text-editor/engine.js.map +1 -0
  84. package/dist/ssr/text-editor/format.js +218 -0
  85. package/dist/ssr/text-editor/format.js.map +1 -0
  86. package/dist/ssr/text-editor/formatted.js +164 -0
  87. package/dist/ssr/text-editor/formatted.js.map +1 -0
  88. package/dist/ssr/text-editor/language.js +19 -0
  89. package/dist/ssr/text-editor/language.js.map +1 -0
  90. package/dist/ssr/text-editor/markdown-table.js +563 -0
  91. package/dist/ssr/text-editor/markdown-table.js.map +1 -0
  92. package/dist/ssr/text-editor/messages.js +233 -0
  93. package/dist/ssr/text-editor/messages.js.map +1 -0
  94. package/dist/ssr/text-editor/paste.js +115 -0
  95. package/dist/ssr/text-editor/paste.js.map +1 -0
  96. package/dist/ssr/text-editor/table.js +1760 -0
  97. package/dist/ssr/text-editor/table.js.map +1 -0
  98. package/dist/ssr/text-editor.js +5 -0
  99. package/dist/ssr/text-editor.js.map +1 -0
  100. package/dist/styles.css +1 -1
  101. package/dist/types/actions/Dropdown.d.ts +2 -0
  102. package/dist/types/content/MapViewFrame.d.ts +1 -1
  103. package/dist/types/content/MatchText.d.ts +21 -0
  104. package/dist/types/content/index.d.ts +3 -1
  105. package/dist/types/content/map-view-glyphs.d.ts +5 -0
  106. package/dist/types/content/map-view-live.d.ts +1 -1
  107. package/dist/types/content/map-view-snapshot.d.ts +13 -0
  108. package/dist/types/content/map-view-types.d.ts +15 -0
  109. package/dist/types/inputs/Combobox.d.ts +12 -0
  110. package/dist/types/inputs/TextInput.d.ts +2 -1
  111. package/dist/types/layout/AppWorkspace.d.ts +4 -1
  112. package/dist/types/layout/ScrollArea.d.ts +2 -0
  113. package/dist/types/text-editor/TextEditor.d.ts +69 -0
  114. package/dist/types/text-editor/clipboard-html.d.ts +9 -0
  115. package/dist/types/text-editor/clipboard-loading.d.ts +8 -0
  116. package/dist/types/text-editor/clipboard.d.ts +20 -0
  117. package/dist/types/text-editor/engine.d.ts +34 -0
  118. package/dist/types/text-editor/format.d.ts +34 -0
  119. package/dist/types/text-editor/formatted.d.ts +1 -0
  120. package/dist/types/text-editor/language.d.ts +8 -0
  121. package/dist/types/text-editor/markdown-table.d.ts +105 -0
  122. package/dist/types/text-editor/messages.d.ts +113 -0
  123. package/dist/types/text-editor/paste.d.ts +6 -0
  124. package/dist/types/text-editor/table.d.ts +81 -0
  125. package/dist/types/text-editor.d.ts +4 -0
  126. package/package.json +24 -3
@@ -0,0 +1,191 @@
1
+ /** Same decoded RGBA budget as Cloud's isolated print-image worker (64 MiB). */
2
+ export const MAP_SNAPSHOT_MAX_PIXELS = 16 * 1024 * 1024;
3
+ export class MapSnapshotError extends Error {
4
+ constructor(code) {
5
+ super(`Map snapshot: ${code}`);
6
+ this.code = code;
7
+ this.name = "MapSnapshotError";
8
+ }
9
+ }
10
+ export function snapshotAborted(signal) {
11
+ return signal.reason instanceof MapSnapshotError ? signal.reason : new MapSnapshotError("aborted");
12
+ }
13
+
14
+ /** Also observes late rejection; a cancelled image/font/encoding operation never becomes unhandled. */
15
+ export function snapshotWait(promise, signal) {
16
+ return new Promise((resolve, reject) => {
17
+ const abort = () => reject(snapshotAborted(signal));
18
+ if (signal.aborted) return abort();
19
+ signal.addEventListener("abort", abort, {
20
+ once: true
21
+ });
22
+ promise.then(resolve, reject).finally(() => signal.removeEventListener("abort", abort));
23
+ });
24
+ }
25
+ const svgNamespace = "http://www.w3.org/2000/svg";
26
+ // Only renderer-owned shapes and paint cross into the rasterizer; no foreignObject, links, images or CSS URLs.
27
+ const paints = ["fill", "fill-opacity", "stroke", "stroke-width", "stroke-opacity", "stroke-dasharray", "stroke-linecap", "stroke-linejoin"];
28
+ function geometryImage(root, bounds) {
29
+ const source = root.querySelector(".k2b-map-view__geometry");
30
+ if (!source) return;
31
+ const svg = document.createElementNS(svgNamespace, "svg");
32
+ svg.setAttribute("width", String(bounds.width));
33
+ svg.setAttribute("height", String(bounds.height));
34
+ const geometry = document.createElementNS(svgNamespace, "svg");
35
+ const box = source.getBoundingClientRect();
36
+ for (const [name, value] of Object.entries({
37
+ x: box.left - bounds.left,
38
+ y: box.top - bounds.top,
39
+ width: box.width,
40
+ height: box.height,
41
+ viewBox: source.getAttribute("viewBox") ?? "",
42
+ preserveAspectRatio: "none",
43
+ overflow: "visible"
44
+ })) geometry.setAttribute(name, String(value));
45
+ for (const shape of source.querySelectorAll("path")) {
46
+ const copy = document.createElementNS(svgNamespace, shape.localName);
47
+ for (const name of ["d", "cx", "cy", "r", "vector-effect"]) {
48
+ const value = shape.getAttribute(name);
49
+ if (value !== null) copy.setAttribute(name, value);
50
+ }
51
+ const style = getComputedStyle(shape);
52
+ for (const name of paints) {
53
+ const value = style.getPropertyValue(name);
54
+ if (value.includes("url(")) throw new MapSnapshotError("capture_failed");
55
+ copy.setAttribute(name, value);
56
+ }
57
+ geometry.append(copy);
58
+ }
59
+ svg.append(geometry);
60
+ const image = new Image();
61
+ image.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(new XMLSerializer().serializeToString(svg))}`;
62
+ return image;
63
+ }
64
+ function drawPins(ctx, root, bounds) {
65
+ const pins = Array.from(root.querySelectorAll(".k2b-map-view__pin"));
66
+ // The selected pin paints above the others, as in the DOM.
67
+ pins.sort((a, b) => Number(a.getAttribute("aria-pressed") === "true") - Number(b.getAttribute("aria-pressed") === "true"));
68
+ for (const pin of pins) {
69
+ const box = pin.getBoundingClientRect();
70
+ const style = getComputedStyle(pin);
71
+ const x = box.left - bounds.left,
72
+ y = box.top - bounds.top;
73
+ // Resolve CSS variables through a paint property, since custom properties can still contain var().
74
+ const selected = pin.getAttribute("aria-pressed") === "true" || pin.hasAttribute("data-selected");
75
+ const stop = pin.hasAttribute("data-stop");
76
+ const surface = getComputedStyle(root.querySelector(".k2b-map-view__attribution") ?? root).backgroundColor;
77
+ ctx.save();
78
+ if (pin.hasAttribute("data-drop")) {
79
+ const span = pin.querySelector("span");
80
+ ctx.fillStyle = getComputedStyle(span).backgroundColor;
81
+ ctx.beginPath();
82
+ ctx.ellipse(x + box.width / 2, y + box.height / 2, box.width / 2, box.height / 2, 0, Math.PI, Math.PI * 2);
83
+ ctx.lineTo(x + box.width, y + box.height * 0.68);
84
+ ctx.lineTo(x + box.width / 2, y + box.height);
85
+ ctx.lineTo(x, y + box.height * 0.68);
86
+ ctx.closePath();
87
+ ctx.fill();
88
+ if (selected) {
89
+ ctx.fillStyle = surface;
90
+ ctx.beginPath();
91
+ ctx.arc(x + box.width / 2, y + box.height * 0.34, 4, 0, Math.PI * 2);
92
+ ctx.fill();
93
+ }
94
+ } else {
95
+ ctx.beginPath();
96
+ ctx.arc(x + box.width / 2, y + box.height / 2, box.width / 2 + 2.5, 0, Math.PI * 2);
97
+ ctx.fillStyle = surface;
98
+ ctx.fill();
99
+ ctx.beginPath();
100
+ ctx.arc(x + box.width / 2, y + box.height / 2, box.width / 2, 0, Math.PI * 2);
101
+ ctx.fillStyle = style.backgroundColor;
102
+ ctx.fill();
103
+ // The first box-shadow is the resolved inset tone ring. Text ink can differ in dark mode.
104
+ const ring = style.boxShadow.match(/(?:rgba?|color|oklch|oklab)\([^)]*\)/)?.[0];
105
+ if (!ring && !stop && !selected) throw new MapSnapshotError("capture_failed");
106
+ ctx.strokeStyle = stop || selected ? style.backgroundColor : ring;
107
+ ctx.lineWidth = 2;
108
+ ctx.beginPath();
109
+ ctx.arc(x + box.width / 2, y + box.height / 2, box.width / 2 - 1, 0, Math.PI * 2);
110
+ ctx.stroke();
111
+ ctx.fillStyle = style.color;
112
+ ctx.font = `${style.fontWeight} ${style.fontSize} ${style.fontFamily}`;
113
+ ctx.textAlign = "center";
114
+ ctx.textBaseline = "middle";
115
+ ctx.fillText(pin.textContent ?? "", x + box.width / 2, y + box.height / 2);
116
+ }
117
+ ctx.restore();
118
+ }
119
+ }
120
+ function drawAttribution(ctx, root, bounds) {
121
+ const attribution = root.querySelector(".k2b-map-view__attribution");
122
+ if (!attribution?.textContent?.trim()) throw new MapSnapshotError("capture_failed");
123
+ const box = attribution.getBoundingClientRect();
124
+ const style = getComputedStyle(attribution);
125
+ ctx.fillStyle = style.backgroundColor;
126
+ ctx.fillRect(box.left - bounds.left, box.top - bounds.top, box.width, box.height);
127
+ const walker = document.createTreeWalker(attribution, NodeFilter.SHOW_TEXT);
128
+ while (walker.nextNode()) {
129
+ const node = walker.currentNode;
130
+ const parent = node.parentElement;
131
+ const ink = getComputedStyle(parent);
132
+ ctx.fillStyle = ink.color;
133
+ ctx.font = `${ink.fontWeight} ${ink.fontSize} ${ink.fontFamily}`;
134
+ ctx.textBaseline = "top";
135
+ ctx.textAlign = "left";
136
+ // Per-character ranges preserve line breaks, wrapping, and bidi positions without capturing arbitrary HTML.
137
+ const range = document.createRange();
138
+ for (let i = 0; i < (node.textContent?.length ?? 0); i++) {
139
+ range.setStart(node, i);
140
+ range.setEnd(node, i + 1);
141
+ const r = range.getBoundingClientRect();
142
+ ctx.fillText(node.textContent[i], r.left - bounds.left, r.top - bounds.top);
143
+ }
144
+ }
145
+ }
146
+
147
+ /** Called synchronously in MapLibre's render event, before WebGL clears its drawing buffer. */
148
+ export async function rasterizeMapView(root, base, signal) {
149
+ const bounds = root.getBoundingClientRect();
150
+ const width = Math.round(bounds.width),
151
+ height = Math.round(bounds.height);
152
+ if (width < 1 || height < 1 || width > 16383 || height > 16383 || width * height > MAP_SNAPSHOT_MAX_PIXELS) throw new MapSnapshotError("too_large");
153
+ const canvas = document.createElement("canvas");
154
+ canvas.width = width;
155
+ canvas.height = height;
156
+ const ctx = canvas.getContext("2d");
157
+ if (!ctx) throw new MapSnapshotError("capture_failed");
158
+ try {
159
+ // Copy the GPU frame immediately. No preserveDrawingBuffer overhead for ordinary interactive maps.
160
+ ctx.drawImage(base, 0, 0, width, height);
161
+ const geometry = geometryImage(root, bounds);
162
+ // Save all overlay pixels before yielding, so subsequent DOM changes cannot mix revisions.
163
+ const overlay = document.createElement("canvas");
164
+ overlay.width = width;
165
+ overlay.height = height;
166
+ try {
167
+ const ink = overlay.getContext("2d");
168
+ drawPins(ink, root, bounds);
169
+ drawAttribution(ink, root, bounds);
170
+ if (geometry) {
171
+ await snapshotWait(geometry.decode(), signal);
172
+ ctx.drawImage(geometry, 0, 0, width, height);
173
+ }
174
+ ctx.drawImage(overlay, 0, 0);
175
+ } finally {
176
+ overlay.width = overlay.height = 0;
177
+ }
178
+ const data = await snapshotWait(new Promise((resolve, reject) => canvas.toBlob(blob => blob ? resolve(blob) : reject(new MapSnapshotError("capture_failed")), "image/png")), signal);
179
+ return {
180
+ data,
181
+ width,
182
+ height
183
+ };
184
+ } catch (error) {
185
+ if (error instanceof MapSnapshotError) throw error;
186
+ throw new MapSnapshotError("capture_failed");
187
+ } finally {
188
+ canvas.width = canvas.height = 0;
189
+ }
190
+ }
191
+ //# sourceMappingURL=map-view-snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sources":["content/map-view-snapshot.ts"],"sourcesContent":["import type { MapViewSnapshot } from \"./map-view-types\";\n\n/** Same decoded RGBA budget as Cloud's isolated print-image worker (64 MiB). */\nexport const MAP_SNAPSHOT_MAX_PIXELS = 16 * 1024 * 1024;\nexport type MapSnapshotErrorCode =\n | \"not_ready\"\n | \"resource_failed\"\n | \"changed\"\n | \"disposed\"\n | \"busy\"\n | \"too_large\"\n | \"timed_out\"\n | \"aborted\"\n | \"capture_failed\";\nexport class MapSnapshotError extends Error {\n constructor(readonly code: MapSnapshotErrorCode) {\n super(`Map snapshot: ${code}`);\n this.name = \"MapSnapshotError\";\n }\n}\n\nexport function snapshotAborted(signal: AbortSignal): MapSnapshotError {\n return signal.reason instanceof MapSnapshotError ? signal.reason : new MapSnapshotError(\"aborted\");\n}\n\n/** Also observes late rejection; a cancelled image/font/encoding operation never becomes unhandled. */\nexport function snapshotWait<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {\n return new Promise((resolve, reject) => {\n const abort = () => reject(snapshotAborted(signal));\n if (signal.aborted) return abort();\n signal.addEventListener(\"abort\", abort, { once: true });\n promise.then(resolve, reject).finally(() => signal.removeEventListener(\"abort\", abort));\n });\n}\n\nconst svgNamespace = \"http://www.w3.org/2000/svg\";\n// Only renderer-owned shapes and paint cross into the rasterizer; no foreignObject, links, images or CSS URLs.\nconst paints = [\n \"fill\",\n \"fill-opacity\",\n \"stroke\",\n \"stroke-width\",\n \"stroke-opacity\",\n \"stroke-dasharray\",\n \"stroke-linecap\",\n \"stroke-linejoin\",\n] as const;\nfunction geometryImage(root: HTMLElement, bounds: DOMRect): HTMLImageElement | undefined {\n const source = root.querySelector<SVGSVGElement>(\".k2b-map-view__geometry\");\n if (!source) return;\n const svg = document.createElementNS(svgNamespace, \"svg\");\n svg.setAttribute(\"width\", String(bounds.width));\n svg.setAttribute(\"height\", String(bounds.height));\n const geometry = document.createElementNS(svgNamespace, \"svg\");\n const box = source.getBoundingClientRect();\n for (const [name, value] of Object.entries({\n x: box.left - bounds.left,\n y: box.top - bounds.top,\n width: box.width,\n height: box.height,\n viewBox: source.getAttribute(\"viewBox\") ?? \"\",\n preserveAspectRatio: \"none\",\n overflow: \"visible\",\n }))\n geometry.setAttribute(name, String(value));\n for (const shape of source.querySelectorAll(\"path\")) {\n const copy = document.createElementNS(svgNamespace, shape.localName);\n for (const name of [\"d\", \"cx\", \"cy\", \"r\", \"vector-effect\"]) {\n const value = shape.getAttribute(name);\n if (value !== null) copy.setAttribute(name, value);\n }\n const style = getComputedStyle(shape);\n for (const name of paints) {\n const value = style.getPropertyValue(name);\n if (value.includes(\"url(\")) throw new MapSnapshotError(\"capture_failed\");\n copy.setAttribute(name, value);\n }\n geometry.append(copy);\n }\n svg.append(geometry);\n const image = new Image();\n image.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(new XMLSerializer().serializeToString(svg))}`;\n return image;\n}\n\nfunction drawPins(ctx: CanvasRenderingContext2D, root: HTMLElement, bounds: DOMRect) {\n const pins = Array.from(root.querySelectorAll<HTMLElement>(\".k2b-map-view__pin\"));\n // The selected pin paints above the others, as in the DOM.\n pins.sort((a, b) => Number(a.getAttribute(\"aria-pressed\") === \"true\") - Number(b.getAttribute(\"aria-pressed\") === \"true\"));\n for (const pin of pins) {\n const box = pin.getBoundingClientRect();\n const style = getComputedStyle(pin);\n const x = box.left - bounds.left,\n y = box.top - bounds.top;\n // Resolve CSS variables through a paint property, since custom properties can still contain var().\n const selected = pin.getAttribute(\"aria-pressed\") === \"true\" || pin.hasAttribute(\"data-selected\");\n const stop = pin.hasAttribute(\"data-stop\");\n const surface = getComputedStyle(root.querySelector(\".k2b-map-view__attribution\") ?? root).backgroundColor;\n ctx.save();\n if (pin.hasAttribute(\"data-drop\")) {\n const span = pin.querySelector(\"span\")!;\n ctx.fillStyle = getComputedStyle(span).backgroundColor;\n ctx.beginPath();\n ctx.ellipse(x + box.width / 2, y + box.height / 2, box.width / 2, box.height / 2, 0, Math.PI, Math.PI * 2);\n ctx.lineTo(x + box.width, y + box.height * 0.68);\n ctx.lineTo(x + box.width / 2, y + box.height);\n ctx.lineTo(x, y + box.height * 0.68);\n ctx.closePath();\n ctx.fill();\n if (selected) {\n ctx.fillStyle = surface;\n ctx.beginPath();\n ctx.arc(x + box.width / 2, y + box.height * 0.34, 4, 0, Math.PI * 2);\n ctx.fill();\n }\n } else {\n ctx.beginPath();\n ctx.arc(x + box.width / 2, y + box.height / 2, box.width / 2 + 2.5, 0, Math.PI * 2);\n ctx.fillStyle = surface;\n ctx.fill();\n ctx.beginPath();\n ctx.arc(x + box.width / 2, y + box.height / 2, box.width / 2, 0, Math.PI * 2);\n ctx.fillStyle = style.backgroundColor;\n ctx.fill();\n // The first box-shadow is the resolved inset tone ring. Text ink can differ in dark mode.\n const ring = style.boxShadow.match(/(?:rgba?|color|oklch|oklab)\\([^)]*\\)/)?.[0];\n if (!ring && !stop && !selected) throw new MapSnapshotError(\"capture_failed\");\n ctx.strokeStyle = stop || selected ? style.backgroundColor : ring!;\n ctx.lineWidth = 2;\n ctx.beginPath();\n ctx.arc(x + box.width / 2, y + box.height / 2, box.width / 2 - 1, 0, Math.PI * 2);\n ctx.stroke();\n ctx.fillStyle = style.color;\n ctx.font = `${style.fontWeight} ${style.fontSize} ${style.fontFamily}`;\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n ctx.fillText(pin.textContent ?? \"\", x + box.width / 2, y + box.height / 2);\n }\n ctx.restore();\n }\n}\n\nfunction drawAttribution(ctx: CanvasRenderingContext2D, root: HTMLElement, bounds: DOMRect) {\n const attribution = root.querySelector<HTMLElement>(\".k2b-map-view__attribution\");\n if (!attribution?.textContent?.trim()) throw new MapSnapshotError(\"capture_failed\");\n const box = attribution.getBoundingClientRect();\n const style = getComputedStyle(attribution);\n ctx.fillStyle = style.backgroundColor;\n ctx.fillRect(box.left - bounds.left, box.top - bounds.top, box.width, box.height);\n const walker = document.createTreeWalker(attribution, NodeFilter.SHOW_TEXT);\n while (walker.nextNode()) {\n const node = walker.currentNode;\n const parent = node.parentElement!;\n const ink = getComputedStyle(parent);\n ctx.fillStyle = ink.color;\n ctx.font = `${ink.fontWeight} ${ink.fontSize} ${ink.fontFamily}`;\n ctx.textBaseline = \"top\";\n ctx.textAlign = \"left\";\n // Per-character ranges preserve line breaks, wrapping, and bidi positions without capturing arbitrary HTML.\n const range = document.createRange();\n for (let i = 0; i < (node.textContent?.length ?? 0); i++) {\n range.setStart(node, i);\n range.setEnd(node, i + 1);\n const r = range.getBoundingClientRect();\n ctx.fillText(node.textContent![i]!, r.left - bounds.left, r.top - bounds.top);\n }\n }\n}\n\n/** Called synchronously in MapLibre's render event, before WebGL clears its drawing buffer. */\nexport async function rasterizeMapView(root: HTMLElement, base: HTMLCanvasElement, signal: AbortSignal): Promise<MapViewSnapshot> {\n const bounds = root.getBoundingClientRect();\n const width = Math.round(bounds.width),\n height = Math.round(bounds.height);\n if (width < 1 || height < 1 || width > 16383 || height > 16383 || width * height > MAP_SNAPSHOT_MAX_PIXELS)\n throw new MapSnapshotError(\"too_large\");\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) throw new MapSnapshotError(\"capture_failed\");\n try {\n // Copy the GPU frame immediately. No preserveDrawingBuffer overhead for ordinary interactive maps.\n ctx.drawImage(base, 0, 0, width, height);\n const geometry = geometryImage(root, bounds);\n // Save all overlay pixels before yielding, so subsequent DOM changes cannot mix revisions.\n const overlay = document.createElement(\"canvas\");\n overlay.width = width;\n overlay.height = height;\n try {\n const ink = overlay.getContext(\"2d\")!;\n drawPins(ink, root, bounds);\n drawAttribution(ink, root, bounds);\n if (geometry) {\n await snapshotWait(geometry.decode(), signal);\n ctx.drawImage(geometry, 0, 0, width, height);\n }\n ctx.drawImage(overlay, 0, 0);\n } finally {\n overlay.width = overlay.height = 0;\n }\n const data = await snapshotWait(\n new Promise<Blob>((resolve, reject) =>\n canvas.toBlob((blob) => (blob ? resolve(blob) : reject(new MapSnapshotError(\"capture_failed\"))), \"image/png\"),\n ),\n signal,\n );\n return { data, width, height };\n } catch (error) {\n if (error instanceof MapSnapshotError) throw error;\n throw new MapSnapshotError(\"capture_failed\");\n } finally {\n canvas.width = canvas.height = 0;\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["content/map-view-types.ts"],"sourcesContent":["import type { StyleSpecification } from \"maplibre-gl\";\nimport type { JSX } from \"solid-js\";\n\nexport type MapViewPoint = { lat: number; lon: number };\nexport type MapViewTone = \"accent\" | \"second\" | \"neutral\" | \"warning\";\nexport type MapViewMarker = {\n id: string;\n point: MapViewPoint;\n /** A number, a single letter, or \"+\". Omit for a drop pin. */\n mark?: number | string;\n label: string;\n tone?: MapViewTone;\n selected?: boolean;\n};\nexport type MapViewLineTone = \"accent\" | \"muted\" | \"preview\" | \"previous\";\nexport type MapViewLine = { id: string; tone?: MapViewLineTone } & ({ polyline6: string } | { points: MapViewPoint[] });\nexport type MapViewArea = { id: string; polygon: MapViewPoint[]; tone?: MapViewTone };\nexport type MapViewOwnLocation = { point: MapViewPoint; accuracyMeters?: number };\nexport type MapViewStyle = string | StyleSpecification;\nexport type MapViewStyleSource = MapViewStyle | { light: MapViewStyle; dark: MapViewStyle };\nexport type MapViewFit = \"all\" | \"markers\";\nexport type MapViewFrameProps = {\n markers?: MapViewMarker[];\n lines?: MapViewLine[];\n areas?: MapViewArea[];\n ownLocation?: MapViewOwnLocation;\n height: number;\n padding?: number;\n fit?: MapViewFit;\n selectedId?: string;\n attribution?: JSX.Element;\n class?: string;\n};\nexport type MapViewProps = Omit<MapViewFrameProps, \"attribution\"> & {\n style: MapViewStyleSource;\n attribution: JSX.Element;\n onSelect?: (id: string) => void;\n infoTile?: (marker: MapViewMarker) => JSX.Element;\n notice?: JSX.Element;\n empty?: JSX.Element;\n onLocate?: () => void;\n /** Observe rendering and resource failures without receiving provider responses or URLs. */\n onStateChange?: (state: \"static\" | \"loading\" | \"ready\" | \"error\" | \"no-webgl\" | \"empty\") => void;\n};\n"],"mappings":"","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["content/map-view-types.ts"],"sourcesContent":["import type { StyleSpecification } from \"maplibre-gl\";\nimport type { JSX } from \"solid-js\";\n\nexport type MapViewPoint = { lat: number; lon: number };\nexport type MapViewTone = \"accent\" | \"second\" | \"neutral\" | \"warning\";\nexport type MapViewMarker = {\n id: string;\n point: MapViewPoint;\n /** A number, a single letter, or \"+\". Omit for a drop pin. */\n mark?: number | string;\n label: string;\n tone?: MapViewTone;\n selected?: boolean;\n};\nexport type MapViewLineTone = \"accent\" | \"muted\" | \"preview\" | \"previous\";\nexport type MapViewLine = { id: string; tone?: MapViewLineTone } & ({ polyline6: string } | { points: MapViewPoint[] });\nexport type MapViewArea = { id: string; polygon: MapViewPoint[]; tone?: MapViewTone };\nexport type MapViewOwnLocation = { point: MapViewPoint; accuracyMeters?: number };\nexport type MapViewStyle = string | StyleSpecification;\nexport type MapViewStyleSource = MapViewStyle | { light: MapViewStyle; dark: MapViewStyle };\nexport type MapViewFit = \"all\" | \"markers\";\nexport type MapViewFrameProps = {\n markers?: MapViewMarker[];\n lines?: MapViewLine[];\n areas?: MapViewArea[];\n ownLocation?: MapViewOwnLocation;\n height: number;\n padding?: number;\n fit?: MapViewFit;\n selectedId?: string;\n attribution?: JSX.Element;\n class?: string;\n};\nexport type MapViewSnapshot = { data: Blob; width: number; height: number };\nexport type MapViewSnapshotOptions = { signal?: AbortSignal; timeoutMs?: number };\nexport type MapViewHandle = {\n /** Capture the current complete view; never loads, pans, refits, or retries provider resources. */\n snapshot: (options?: MapViewSnapshotOptions) => Promise<MapViewSnapshot>;\n};\nexport type MapViewProps = Omit<MapViewFrameProps, \"attribution\"> & {\n style: MapViewStyleSource;\n /** Browser-only handle; remains safely callable after disposal (rejects disposed). */\n ref?: (handle: MapViewHandle) => void;\n attribution: JSX.Element;\n onSelect?: (id: string) => void;\n infoTile?: (marker: MapViewMarker) => JSX.Element;\n notice?: JSX.Element;\n empty?: JSX.Element;\n onLocate?: () => void;\n /** Observe rendering and resource failures without receiving provider responses or URLs. */\n onStateChange?: (state: \"static\" | \"loading\" | \"ready\" | \"error\" | \"no-webgl\" | \"empty\") => void;\n};\n"],"mappings":"","ignoreList":[]}
@@ -1,6 +1,7 @@
1
1
  import { template as _$template } from "solid-js/web";
2
2
  import { delegateEvents as _$delegateEvents } from "solid-js/web";
3
3
  import { className as _$className } from "solid-js/web";
4
+ import { setStyleProperty as _$setStyleProperty } from "solid-js/web";
4
5
  import { addEventListener as _$addEventListener } from "solid-js/web";
5
6
  import { effect as _$effect } from "solid-js/web";
6
7
  import { runHydrationEvents as _$runHydrationEvents } from "solid-js/web";
@@ -14,14 +15,17 @@ import { mergeProps as _$mergeProps } from "solid-js/web";
14
15
  import { memo as _$memo } from "solid-js/web";
15
16
  import { use as _$use } from "solid-js/web";
16
17
  var _tmpl$ = /*#__PURE__*/_$template(`<i class="ti ti-loader-2 k2b-spin"aria-hidden=true>`),
17
- _tmpl$2 = /*#__PURE__*/_$template(`<div class=k2b-combobox><div class=k2b-combobox__input><i class="ti ti-search"aria-hidden=true></i><input type=text role=combobox aria-autocomplete=list><!$><!/></div><div popover=manual class=k2b-choice-popover><div class=k2b-choice-options role=listbox><!$><!/><!$><!/>`),
18
+ _tmpl$2 = /*#__PURE__*/_$template(`<div class=k2b-combobox><div class=k2b-combobox__input><i class="ti ti-search"aria-hidden=true></i><input type=text role=combobox autocomplete=off aria-autocomplete=list><!$><!/></div><div popover=manual class=k2b-choice-popover><div class=k2b-choice-options role=listbox><!$><!/><!$><!/><!$><!/></div><!$><!/>`),
18
19
  _tmpl$3 = /*#__PURE__*/_$template(`<i class="ti ti-chevron-down"aria-hidden=true>`),
19
- _tmpl$4 = /*#__PURE__*/_$template(`<div class=k2b-choice-status data-tone=danger><span></span><button type=button>`),
20
- _tmpl$5 = /*#__PURE__*/_$template(`<div class=k2b-choice-status>`),
21
- _tmpl$6 = /*#__PURE__*/_$template(`<button type=button class=k2b-choice-option role=option><!$><!/><span><strong></strong><!$><!/>`),
22
- _tmpl$7 = /*#__PURE__*/_$template(`<i aria-hidden=true>`),
23
- _tmpl$8 = /*#__PURE__*/_$template(`<small>`);
24
- import { createEffect, createSignal, For, Show } from "solid-js";
20
+ _tmpl$4 = /*#__PURE__*/_$template(`<div class=k2b-choice-status>`),
21
+ _tmpl$5 = /*#__PURE__*/_$template(`<div class=k2b-choice-status data-tone=danger><span></span><button type=button>`),
22
+ _tmpl$6 = /*#__PURE__*/_$template(`<div class=k2b-choice-loading role=status><span class=k2b-sr-only></span><!$><!/>`),
23
+ _tmpl$7 = /*#__PURE__*/_$template(`<div class=k2b-choice-loading__row aria-hidden=true><span class=k2b-skeleton></span><span class=k2b-skeleton>`),
24
+ _tmpl$8 = /*#__PURE__*/_$template(`<button type=button class=k2b-choice-option role=option><!$><!/><span><strong></strong><!$><!/>`),
25
+ _tmpl$9 = /*#__PURE__*/_$template(`<i aria-hidden=true>`),
26
+ _tmpl$0 = /*#__PURE__*/_$template(`<small>`),
27
+ _tmpl$1 = /*#__PURE__*/_$template(`<div class=k2b-choice-footer>`);
28
+ import { createEffect, createSignal, For, on, Show } from "solid-js";
25
29
  import { createFieldMeta, Field, fieldControlAria } from "../internal/field";
26
30
  import { useUiMessages } from "../intl/messages";
27
31
  import { createChoiceLoader, createChoicePopover, nextEnabledChoiceIndex } from "./choice";
@@ -53,8 +57,10 @@ export function Combobox(props) {
53
57
  // 150ms keeps typing responsive without hammering the loader.
54
58
  () => props.debounceMs ?? 150);
55
59
  const popover = createChoicePopover(() => Boolean(props.disabled || props.readOnly));
56
- const options = loader.options;
60
+ // A host notice or an error replaces the results; hidden results are never selectable.
61
+ const options = () => props.status || loader.error() ? [] : loader.options();
57
62
  const focusedOption = () => options()[focusedIndex()];
63
+ const searchable = value => value.trim().length >= (props.minQueryLength ?? 0);
58
64
  const focus = index => {
59
65
  setFocusedIndex(index);
60
66
  optionRefs[index]?.scrollIntoView({
@@ -64,9 +70,9 @@ export function Combobox(props) {
64
70
  /** `eager` loads the currently controlled query on open; typing supplies its
65
71
  * own query, so opening from `onInput` skips the duplicate request. */
66
72
  const open = (eager = true) => {
67
- if (props.disabled || props.readOnly || popover.open()) return;
73
+ if (props.disabled || props.readOnly || popover.open() || !searchable(query())) return;
68
74
  popover.show();
69
- if (eager) loader.load(query(), true);
75
+ if (eager && !props.status) loader.load(query(), true);
70
76
  focus(-1);
71
77
  };
72
78
  const reset = () => {
@@ -76,8 +82,14 @@ export function Combobox(props) {
76
82
  };
77
83
  const close = () => {
78
84
  popover.hide();
79
- reset();
85
+ if (!props.freeText) return reset();
86
+ loader.cancel();
87
+ focus(-1);
80
88
  };
89
+ createEffect(on(options, list => {
90
+ const index = props.autoHighlight;
91
+ if (index !== undefined && focusedIndex() < 0 && popover.open() && list.length > 0) setFocusedIndex(Math.min(index, list.length - 1));
92
+ }));
81
93
  createEffect(() => {
82
94
  if (props.readOnly) {
83
95
  popover.hide();
@@ -94,7 +106,10 @@ export function Combobox(props) {
94
106
  description: option.description,
95
107
  icon: option.icon
96
108
  });
97
- reset();
109
+ if (props.freeText) {
110
+ loader.cancel();
111
+ focus(-1);
112
+ } else reset();
98
113
  inputRef?.focus();
99
114
  };
100
115
  const onKeyDown = event => {
@@ -106,7 +121,7 @@ export function Combobox(props) {
106
121
  // While the results are open, Enter belongs to them: it never submits an enclosing form, even with no option active.
107
122
  event.preventDefault();
108
123
  const option = options()[focusedIndex()];
109
- if (option) select(option);
124
+ if (option) select(option);else if (props.freeText) close();
110
125
  } else if ((event.key === "Escape" || event.key === "Tab") && popover.open()) {
111
126
  // Escape is only ours while the list is open; otherwise it has to reach an
112
127
  // enclosing dialog or drawer.
@@ -146,7 +161,11 @@ export function Combobox(props) {
146
161
  _el$0 = _el$9.firstChild,
147
162
  [_el$1, _co$2] = _$getNextMarker(_el$0.nextSibling),
148
163
  _el$10 = _el$1.nextSibling,
149
- [_el$11, _co$3] = _$getNextMarker(_el$10.nextSibling);
164
+ [_el$11, _co$3] = _$getNextMarker(_el$10.nextSibling),
165
+ _el$12 = _el$11.nextSibling,
166
+ [_el$13, _co$4] = _$getNextMarker(_el$12.nextSibling),
167
+ _el$14 = _el$9.nextSibling,
168
+ [_el$15, _co$5] = _$getNextMarker(_el$14.nextSibling);
150
169
  var _ref$ = popover.setTrigger;
151
170
  typeof _ref$ === "function" ? _$use(_ref$, _el$2) : popover.setTrigger = _el$2;
152
171
  _$use(element => {
@@ -185,10 +204,16 @@ export function Combobox(props) {
185
204
  event.currentTarget.value = query();
186
205
  return;
187
206
  }
188
- setQuery(event.currentTarget.value);
189
- open(false);
190
- loader.load(event.currentTarget.value);
207
+ const value = event.currentTarget.value;
208
+ setQuery(value);
191
209
  focus(-1);
210
+ if (!searchable(value)) {
211
+ popover.hide();
212
+ loader.cancel();
213
+ return;
214
+ }
215
+ open(false);
216
+ if (!props.status) loader.load(value);
192
217
  },
193
218
  "onKeyDown": onKeyDown
194
219
  }), false, false);
@@ -208,73 +233,115 @@ export function Combobox(props) {
208
233
  _$setAttribute(_el$9, "id", listboxId);
209
234
  _$insert(_el$9, _$createComponent(Show, {
210
235
  get when() {
211
- return loader.error();
236
+ return props.status;
237
+ },
238
+ children: status => (() => {
239
+ var _el$17 = _$getNextElement(_tmpl$4);
240
+ _$insert(_el$17, status);
241
+ return _el$17;
242
+ })()
243
+ }), _el$1, _co$2);
244
+ _$insert(_el$9, _$createComponent(Show, {
245
+ get when() {
246
+ return _$memo(() => !!!props.status)() && loader.error();
212
247
  },
213
248
  children: message => (() => {
214
- var _el$13 = _$getNextElement(_tmpl$4),
215
- _el$14 = _el$13.firstChild,
216
- _el$15 = _el$14.nextSibling;
217
- _$insert(_el$14, message);
218
- _$addEventListener(_el$15, "click", loader.retry, true);
219
- _$insert(_el$15, () => messages().retry);
249
+ var _el$18 = _$getNextElement(_tmpl$5),
250
+ _el$19 = _el$18.firstChild,
251
+ _el$20 = _el$19.nextSibling;
252
+ _$insert(_el$19, message);
253
+ _$addEventListener(_el$20, "click", loader.retry, true);
254
+ _$insert(_el$20, () => messages().retry);
220
255
  _$runHydrationEvents();
221
- return _el$13;
256
+ return _el$18;
222
257
  })()
223
- }), _el$1, _co$2);
258
+ }), _el$11, _co$3);
224
259
  _$insert(_el$9, _$createComponent(For, {
225
260
  get each() {
226
- return _$memo(() => !!loader.error())() ? [] : options();
261
+ return options();
227
262
  },
228
263
  get fallback() {
229
- return (() => {
230
- var _el$16 = _$getNextElement(_tmpl$5);
231
- _$insert(_el$16, (() => {
232
- var _c$ = _$memo(() => query().length >= 2);
233
- return () => _c$() ? selectMessages().noResultsFound : selectMessages().typeToSearch;
234
- })());
235
- return _el$16;
236
- })();
264
+ return _$createComponent(Show, {
265
+ get when() {
266
+ return _$memo(() => !!!props.status)() && !loader.error();
267
+ },
268
+ get children() {
269
+ return _$createComponent(Show, {
270
+ get when() {
271
+ return loader.loading();
272
+ },
273
+ get fallback() {
274
+ return (() => {
275
+ var _el$25 = _$getNextElement(_tmpl$4);
276
+ _$insert(_el$25, (() => {
277
+ var _c$ = _$memo(() => query().length >= 2);
278
+ return () => _c$() ? props.empty ?? selectMessages().noResultsFound : selectMessages().typeToSearch;
279
+ })());
280
+ return _el$25;
281
+ })();
282
+ },
283
+ get children() {
284
+ var _el$21 = _$getNextElement(_tmpl$6),
285
+ _el$22 = _el$21.firstChild,
286
+ _el$23 = _el$22.nextSibling,
287
+ [_el$24, _co$6] = _$getNextMarker(_el$23.nextSibling);
288
+ _$insert(_el$22, () => messages().loading);
289
+ _$insert(_el$21, _$createComponent(For, {
290
+ each: [62, 48, 55],
291
+ children: width => (() => {
292
+ var _el$26 = _$getNextElement(_tmpl$7),
293
+ _el$27 = _el$26.firstChild,
294
+ _el$28 = _el$27.nextSibling;
295
+ _$setStyleProperty(_el$28, "width", `${width}%`);
296
+ return _el$26;
297
+ })()
298
+ }), _el$24, _co$6);
299
+ return _el$21;
300
+ }
301
+ });
302
+ }
303
+ });
237
304
  },
238
305
  children: (option, index) => (() => {
239
- var _el$17 = _$getNextElement(_tmpl$6),
240
- _el$22 = _el$17.firstChild,
241
- [_el$23, _co$5] = _$getNextMarker(_el$22.nextSibling),
242
- _el$18 = _el$23.nextSibling,
243
- _el$19 = _el$18.firstChild,
244
- _el$20 = _el$19.nextSibling,
245
- [_el$21, _co$4] = _$getNextMarker(_el$20.nextSibling);
246
- _el$17.$$click = () => select(option);
247
- _el$17.$$pointerdown = event => event.preventDefault();
248
- _el$17.$$pointermove = () => focus(index());
249
- _$use(element => optionRefs[index()] = element, _el$17);
250
- _$insert(_el$17, _$createComponent(Show, {
306
+ var _el$29 = _$getNextElement(_tmpl$8),
307
+ _el$34 = _el$29.firstChild,
308
+ [_el$35, _co$8] = _$getNextMarker(_el$34.nextSibling),
309
+ _el$30 = _el$35.nextSibling,
310
+ _el$31 = _el$30.firstChild,
311
+ _el$32 = _el$31.nextSibling,
312
+ [_el$33, _co$7] = _$getNextMarker(_el$32.nextSibling);
313
+ _el$29.$$click = () => select(option);
314
+ _el$29.$$pointerdown = event => event.preventDefault();
315
+ _el$29.$$pointermove = () => focus(index());
316
+ _$use(element => optionRefs[index()] = element, _el$29);
317
+ _$insert(_el$29, _$createComponent(Show, {
251
318
  get when() {
252
319
  return option.icon;
253
320
  },
254
321
  children: icon => (() => {
255
- var _el$24 = _$getNextElement(_tmpl$7);
256
- _$effect(() => _$className(_el$24, iconClass(icon())));
257
- return _el$24;
322
+ var _el$36 = _$getNextElement(_tmpl$9);
323
+ _$effect(() => _$className(_el$36, iconClass(icon())));
324
+ return _el$36;
258
325
  })()
259
- }), _el$23, _co$5);
260
- _$insert(_el$19, () => option.label);
261
- _$insert(_el$18, _$createComponent(Show, {
326
+ }), _el$35, _co$8);
327
+ _$insert(_el$31, () => option.label);
328
+ _$insert(_el$30, _$createComponent(Show, {
262
329
  get when() {
263
330
  return option.description;
264
331
  },
265
332
  children: description => (() => {
266
- var _el$25 = _$getNextElement(_tmpl$8);
267
- _$insert(_el$25, description);
268
- return _el$25;
333
+ var _el$37 = _$getNextElement(_tmpl$0);
334
+ _$insert(_el$37, description);
335
+ return _el$37;
269
336
  })()
270
- }), _el$21, _co$4);
337
+ }), _el$33, _co$7);
271
338
  _$effect(_p$ => {
272
339
  var _v$ = `${listboxId}-${index()}`,
273
340
  _v$2 = index() === focusedIndex(),
274
341
  _v$3 = index() === focusedIndex() ? "true" : undefined;
275
- _v$ !== _p$.e && _$setAttribute(_el$17, "id", _p$.e = _v$);
276
- _v$2 !== _p$.t && _$setAttribute(_el$17, "aria-selected", _p$.t = _v$2);
277
- _v$3 !== _p$.a && _$setAttribute(_el$17, "data-focused", _p$.a = _v$3);
342
+ _v$ !== _p$.e && _$setAttribute(_el$29, "id", _p$.e = _v$);
343
+ _v$2 !== _p$.t && _$setAttribute(_el$29, "aria-selected", _p$.t = _v$2);
344
+ _v$3 !== _p$.a && _$setAttribute(_el$29, "data-focused", _p$.a = _v$3);
278
345
  return _p$;
279
346
  }, {
280
347
  e: undefined,
@@ -282,9 +349,19 @@ export function Combobox(props) {
282
349
  a: undefined
283
350
  });
284
351
  _$runHydrationEvents();
285
- return _el$17;
352
+ return _el$29;
286
353
  })()
287
- }), _el$11, _co$3);
354
+ }), _el$13, _co$4);
355
+ _$insert(_el$8, _$createComponent(Show, {
356
+ get when() {
357
+ return props.footer;
358
+ },
359
+ children: footer => (() => {
360
+ var _el$38 = _$getNextElement(_tmpl$1);
361
+ _$insert(_el$38, footer);
362
+ return _el$38;
363
+ })()
364
+ }), _el$15, _co$5);
288
365
  _$effect(() => _$setAttribute(_el$, "data-invalid", error() ? "true" : undefined));
289
366
  _$runHydrationEvents();
290
367
  return _el$;
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["inputs/Combobox.tsx"],"sourcesContent":["import { createEffect, createSignal, For, type JSX, Show } from \"solid-js\";\nimport { createFieldMeta, Field, fieldControlAria } from \"../internal/field\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { type ChoiceOption, createChoiceLoader, createChoicePopover, nextEnabledChoiceIndex } from \"./choice\";\nimport type { FieldProps, MaybeAccessor } from \"./field-contract\";\nimport { resolveMaybeAccessor } from \"./field-contract\";\nimport { useSelectMessages } from \"./select-messages\";\n\nexport type ComboboxOption = { id: string; label: string; description?: string; icon?: string };\nexport type ComboboxProps = FieldProps & {\n readOnly?: boolean;\n query?: MaybeAccessor<string>;\n onQueryChange?: (query: string) => void;\n placeholder?: string;\n fetchData: (query: string, signal: AbortSignal) => Promise<ComboboxOption[]>;\n onSelect: (option: ComboboxOption) => void;\n debounceMs?: number;\n};\n\nconst iconClass = (icon: string) => (icon.split(/\\s+/).includes(\"ti\") ? icon : `ti ${icon}`);\n\nexport function Combobox(props: ComboboxProps): JSX.Element {\n const messages = useUiMessages();\n const selectMessages = useSelectMessages();\n const meta = createFieldMeta(props.id);\n const listboxId = `${meta.controlId}-listbox`;\n const [localQuery, setLocalQuery] = createSignal(\"\");\n const query = () => resolveMaybeAccessor(props.query) ?? localQuery();\n const setQuery = (value: string) => {\n setLocalQuery(value);\n props.onQueryChange?.(value);\n };\n const error = () => resolveMaybeAccessor(props.error);\n const [focusedIndex, setFocusedIndex] = createSignal(-1);\n let inputRef: HTMLInputElement | undefined;\n let optionRefs: HTMLButtonElement[] = [];\n const loader = createChoiceLoader(\n () => async (value, signal) => (await props.fetchData(value, signal)).map((option) => ({ ...option, value: option.id })),\n // Cloud debounces at 200ms and then pads the response with a 200ms minimum\n // load time to stop the spinner flickering. The spinner here sits in the\n // chevron slot and stale results stay visible, so there is nothing to pad —\n // 150ms keeps typing responsive without hammering the loader.\n () => props.debounceMs ?? 150,\n );\n const popover = createChoicePopover(() => Boolean(props.disabled || props.readOnly));\n const options = loader.options;\n const focusedOption = () => options()[focusedIndex()];\n const focus = (index: number) => {\n setFocusedIndex(index);\n optionRefs[index]?.scrollIntoView({ block: \"nearest\" });\n };\n /** `eager` loads the currently controlled query on open; typing supplies its\n * own query, so opening from `onInput` skips the duplicate request. */\n const open = (eager = true) => {\n if (props.disabled || props.readOnly || popover.open()) return;\n popover.show();\n if (eager) loader.load(query(), true);\n focus(-1);\n };\n const reset = () => {\n loader.cancel();\n setQuery(\"\");\n focus(-1);\n };\n const close = () => {\n popover.hide();\n reset();\n };\n createEffect(() => {\n if (props.readOnly) {\n popover.hide();\n loader.cancel();\n setFocusedIndex(-1);\n }\n });\n const select = (option: ChoiceOption<string>) => {\n if (props.disabled || props.readOnly) return;\n popover.hide();\n props.onSelect({ id: option.value, label: option.label, description: option.description, icon: option.icon });\n reset();\n inputRef?.focus();\n };\n const onKeyDown = (event: KeyboardEvent) => {\n if (props.disabled || props.readOnly) return;\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n if (!popover.open()) open();\n else focus(nextEnabledChoiceIndex(options(), focusedIndex(), event.key === \"ArrowDown\" ? 1 : -1));\n } else if (event.key === \"Enter\" && popover.open()) {\n // While the results are open, Enter belongs to them: it never submits an enclosing form, even with no option active.\n event.preventDefault();\n const option = options()[focusedIndex()];\n if (option) select(option);\n } else if ((event.key === \"Escape\" || event.key === \"Tab\") && popover.open()) {\n // Escape is only ours while the list is open; otherwise it has to reach an\n // enclosing dialog or drawer.\n if (event.key === \"Escape\") event.preventDefault();\n close();\n }\n };\n\n return (\n <Field\n class={props.class}\n label={props.label}\n description={props.description}\n error={error()}\n meta={meta}\n required={props.required}\n disabled={props.disabled}\n >\n <div class=\"k2b-combobox\" data-invalid={error() ? \"true\" : undefined}>\n <div ref={popover.setTrigger} class=\"k2b-combobox__input\">\n <i class=\"ti ti-search\" aria-hidden=\"true\" />\n {/* A click, typing, or an arrow key opens the list. Focus alone (Tab, a dialog's initial focus) does not, so Escape still closes the enclosing dialog. */}\n <input\n ref={(element) => {\n inputRef = element;\n }}\n id={meta.controlId}\n type=\"text\"\n value={query()}\n placeholder={props.placeholder ?? messages().search}\n disabled={props.disabled}\n readOnly={props.readOnly}\n aria-readonly={props.readOnly ? \"true\" : undefined}\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded={popover.open()}\n aria-controls={listboxId}\n aria-activedescendant={focusedOption() ? `${listboxId}-${focusedIndex()}` : undefined}\n {...fieldControlAria(meta, props)}\n onClick={() => open()}\n onInput={(event) => {\n if (props.disabled || props.readOnly) {\n event.currentTarget.value = query();\n return;\n }\n setQuery(event.currentTarget.value);\n open(false);\n loader.load(event.currentTarget.value);\n focus(-1);\n }}\n onKeyDown={onKeyDown}\n />\n <Show when={loader.loading()} fallback={<i class=\"ti ti-chevron-down\" aria-hidden=\"true\" />}>\n <i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\" />\n </Show>\n </div>\n <div ref={popover.setPopover} popover=\"manual\" class=\"k2b-choice-popover\">\n <div class=\"k2b-choice-options\" role=\"listbox\" id={listboxId}>\n <Show when={loader.error()}>\n {(message) => (\n <div class=\"k2b-choice-status\" data-tone=\"danger\">\n <span>{message()}</span>\n <button type=\"button\" onClick={loader.retry}>\n {messages().retry}\n </button>\n </div>\n )}\n </Show>\n <For\n each={loader.error() ? [] : options()}\n fallback={\n <div class=\"k2b-choice-status\">{query().length >= 2 ? selectMessages().noResultsFound : selectMessages().typeToSearch}</div>\n }\n >\n {(option, index) => (\n <button\n ref={(element) => (optionRefs[index()] = element)}\n type=\"button\"\n id={`${listboxId}-${index()}`}\n class=\"k2b-choice-option\"\n role=\"option\"\n aria-selected={index() === focusedIndex()}\n data-focused={index() === focusedIndex() ? \"true\" : undefined}\n onPointerMove={() => focus(index())}\n onPointerDown={(event) => event.preventDefault()}\n onClick={() => select(option)}\n >\n <Show when={option.icon}>{(icon) => <i class={iconClass(icon())} aria-hidden=\"true\" />}</Show>\n <span>\n <strong>{option.label}</strong>\n <Show when={option.description}>{(description) => <small>{description()}</small>}</Show>\n </span>\n </button>\n )}\n </For>\n </div>\n </div>\n </div>\n </Field>\n );\n}\n\nexport default Combobox;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["inputs/Combobox.tsx"],"sourcesContent":["import { createEffect, createSignal, For, type JSX, on, Show } from \"solid-js\";\nimport { createFieldMeta, Field, fieldControlAria } from \"../internal/field\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { type ChoiceOption, createChoiceLoader, createChoicePopover, nextEnabledChoiceIndex } from \"./choice\";\nimport type { FieldProps, MaybeAccessor } from \"./field-contract\";\nimport { resolveMaybeAccessor } from \"./field-contract\";\nimport { useSelectMessages } from \"./select-messages\";\n\nexport type ComboboxOption = { id: string; label: string; description?: string; icon?: string };\nexport type ComboboxProps = FieldProps & {\n readOnly?: boolean;\n query?: MaybeAccessor<string>;\n onQueryChange?: (query: string) => void;\n placeholder?: string;\n fetchData: (query: string, signal: AbortSignal) => Promise<ComboboxOption[]>;\n onSelect: (option: ComboboxOption) => void;\n debounceMs?: number;\n /** The query is the field's own value: picking or closing keeps the typed text, and Enter without an active option only closes the list. */\n freeText?: boolean;\n /** Below this many characters nothing loads and the list stays closed. */\n minQueryLength?: number;\n /** This result (by position) is active as soon as results arrive, so Enter takes it. */\n autoHighlight?: number;\n /** Replaces the results with a host-owned notice, such as an exhausted quota; nothing loads while it is set. */\n status?: JSX.Element;\n /** Shown instead of the default text when a search finds nothing. */\n empty?: JSX.Element;\n /** One line under the results, such as their source. */\n footer?: JSX.Element;\n};\n\nconst iconClass = (icon: string) => (icon.split(/\\s+/).includes(\"ti\") ? icon : `ti ${icon}`);\n\nexport function Combobox(props: ComboboxProps): JSX.Element {\n const messages = useUiMessages();\n const selectMessages = useSelectMessages();\n const meta = createFieldMeta(props.id);\n const listboxId = `${meta.controlId}-listbox`;\n const [localQuery, setLocalQuery] = createSignal(\"\");\n const query = () => resolveMaybeAccessor(props.query) ?? localQuery();\n const setQuery = (value: string) => {\n setLocalQuery(value);\n props.onQueryChange?.(value);\n };\n const error = () => resolveMaybeAccessor(props.error);\n const [focusedIndex, setFocusedIndex] = createSignal(-1);\n let inputRef: HTMLInputElement | undefined;\n let optionRefs: HTMLButtonElement[] = [];\n const loader = createChoiceLoader(\n () => async (value, signal) => (await props.fetchData(value, signal)).map((option) => ({ ...option, value: option.id })),\n // Cloud debounces at 200ms and then pads the response with a 200ms minimum\n // load time to stop the spinner flickering. The spinner here sits in the\n // chevron slot and stale results stay visible, so there is nothing to pad —\n // 150ms keeps typing responsive without hammering the loader.\n () => props.debounceMs ?? 150,\n );\n const popover = createChoicePopover(() => Boolean(props.disabled || props.readOnly));\n // A host notice or an error replaces the results; hidden results are never selectable.\n const options = () => (props.status || loader.error() ? [] : loader.options());\n const focusedOption = () => options()[focusedIndex()];\n const searchable = (value: string) => value.trim().length >= (props.minQueryLength ?? 0);\n const focus = (index: number) => {\n setFocusedIndex(index);\n optionRefs[index]?.scrollIntoView({ block: \"nearest\" });\n };\n /** `eager` loads the currently controlled query on open; typing supplies its\n * own query, so opening from `onInput` skips the duplicate request. */\n const open = (eager = true) => {\n if (props.disabled || props.readOnly || popover.open() || !searchable(query())) return;\n popover.show();\n if (eager && !props.status) loader.load(query(), true);\n focus(-1);\n };\n const reset = () => {\n loader.cancel();\n setQuery(\"\");\n focus(-1);\n };\n const close = () => {\n popover.hide();\n if (!props.freeText) return reset();\n loader.cancel();\n focus(-1);\n };\n createEffect(\n on(options, (list) => {\n const index = props.autoHighlight;\n if (index !== undefined && focusedIndex() < 0 && popover.open() && list.length > 0) setFocusedIndex(Math.min(index, list.length - 1));\n }),\n );\n createEffect(() => {\n if (props.readOnly) {\n popover.hide();\n loader.cancel();\n setFocusedIndex(-1);\n }\n });\n const select = (option: ChoiceOption<string>) => {\n if (props.disabled || props.readOnly) return;\n popover.hide();\n props.onSelect({ id: option.value, label: option.label, description: option.description, icon: option.icon });\n if (props.freeText) {\n loader.cancel();\n focus(-1);\n } else reset();\n inputRef?.focus();\n };\n const onKeyDown = (event: KeyboardEvent) => {\n if (props.disabled || props.readOnly) return;\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n if (!popover.open()) open();\n else focus(nextEnabledChoiceIndex(options(), focusedIndex(), event.key === \"ArrowDown\" ? 1 : -1));\n } else if (event.key === \"Enter\" && popover.open()) {\n // While the results are open, Enter belongs to them: it never submits an enclosing form, even with no option active.\n event.preventDefault();\n const option = options()[focusedIndex()];\n if (option) select(option);\n else if (props.freeText) close();\n } else if ((event.key === \"Escape\" || event.key === \"Tab\") && popover.open()) {\n // Escape is only ours while the list is open; otherwise it has to reach an\n // enclosing dialog or drawer.\n if (event.key === \"Escape\") event.preventDefault();\n close();\n }\n };\n\n return (\n <Field\n class={props.class}\n label={props.label}\n description={props.description}\n error={error()}\n meta={meta}\n required={props.required}\n disabled={props.disabled}\n >\n <div class=\"k2b-combobox\" data-invalid={error() ? \"true\" : undefined}>\n <div ref={popover.setTrigger} class=\"k2b-combobox__input\">\n <i class=\"ti ti-search\" aria-hidden=\"true\" />\n {/* A click, typing, or an arrow key opens the list. Focus alone (Tab, a dialog's initial focus) does not, so Escape still closes the enclosing dialog. */}\n <input\n ref={(element) => {\n inputRef = element;\n }}\n id={meta.controlId}\n type=\"text\"\n value={query()}\n placeholder={props.placeholder ?? messages().search}\n disabled={props.disabled}\n readOnly={props.readOnly}\n aria-readonly={props.readOnly ? \"true\" : undefined}\n role=\"combobox\"\n autocomplete=\"off\"\n aria-autocomplete=\"list\"\n aria-expanded={popover.open()}\n aria-controls={listboxId}\n aria-activedescendant={focusedOption() ? `${listboxId}-${focusedIndex()}` : undefined}\n {...fieldControlAria(meta, props)}\n onClick={() => open()}\n onInput={(event) => {\n if (props.disabled || props.readOnly) {\n event.currentTarget.value = query();\n return;\n }\n const value = event.currentTarget.value;\n setQuery(value);\n focus(-1);\n if (!searchable(value)) {\n popover.hide();\n loader.cancel();\n return;\n }\n open(false);\n if (!props.status) loader.load(value);\n }}\n onKeyDown={onKeyDown}\n />\n <Show when={loader.loading()} fallback={<i class=\"ti ti-chevron-down\" aria-hidden=\"true\" />}>\n <i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\" />\n </Show>\n </div>\n <div ref={popover.setPopover} popover=\"manual\" class=\"k2b-choice-popover\">\n <div class=\"k2b-choice-options\" role=\"listbox\" id={listboxId}>\n <Show when={props.status}>{(status) => <div class=\"k2b-choice-status\">{status()}</div>}</Show>\n <Show when={!props.status && loader.error()}>\n {(message) => (\n <div class=\"k2b-choice-status\" data-tone=\"danger\">\n <span>{message()}</span>\n <button type=\"button\" onClick={loader.retry}>\n {messages().retry}\n </button>\n </div>\n )}\n </Show>\n <For\n each={options()}\n fallback={\n <Show when={!props.status && !loader.error()}>\n <Show\n when={loader.loading()}\n fallback={\n <div class=\"k2b-choice-status\">\n {query().length >= 2 ? (props.empty ?? selectMessages().noResultsFound) : selectMessages().typeToSearch}\n </div>\n }\n >\n {/* The first search has nothing to keep visible yet: rows of the final size wait in its place. */}\n <div class=\"k2b-choice-loading\" role=\"status\">\n <span class=\"k2b-sr-only\">{messages().loading}</span>\n <For each={[62, 48, 55]}>\n {(width) => (\n <div class=\"k2b-choice-loading__row\" aria-hidden=\"true\">\n <span class=\"k2b-skeleton\" />\n <span class=\"k2b-skeleton\" style={{ width: `${width}%` }} />\n </div>\n )}\n </For>\n </div>\n </Show>\n </Show>\n }\n >\n {(option, index) => (\n <button\n ref={(element) => (optionRefs[index()] = element)}\n type=\"button\"\n id={`${listboxId}-${index()}`}\n class=\"k2b-choice-option\"\n role=\"option\"\n aria-selected={index() === focusedIndex()}\n data-focused={index() === focusedIndex() ? \"true\" : undefined}\n onPointerMove={() => focus(index())}\n onPointerDown={(event) => event.preventDefault()}\n onClick={() => select(option)}\n >\n <Show when={option.icon}>{(icon) => <i class={iconClass(icon())} aria-hidden=\"true\" />}</Show>\n <span>\n <strong>{option.label}</strong>\n <Show when={option.description}>{(description) => <small>{description()}</small>}</Show>\n </span>\n </button>\n )}\n </For>\n </div>\n <Show when={props.footer}>{(footer) => <div class=\"k2b-choice-footer\">{footer()}</div>}</Show>\n </div>\n </div>\n </Field>\n );\n}\n\nexport default Combobox;\n"],"mappings":"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","ignoreList":[]}