@k2b/ui 0.30.0 → 0.32.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 (186) hide show
  1. package/README.md +1 -1
  2. package/dist/base.css +2 -0
  3. package/dist/browser/actions/Toolbar.js +2 -0
  4. package/dist/browser/actions/Toolbar.js.map +1 -1
  5. package/dist/browser/actions/ViewTabs.js +8 -0
  6. package/dist/browser/actions/ViewTabs.js.map +1 -1
  7. package/dist/browser/chat/ChatDecision.js +28 -2
  8. package/dist/browser/chat/ChatDecision.js.map +1 -1
  9. package/dist/browser/content/Chart.js +104 -55
  10. package/dist/browser/content/Chart.js.map +1 -1
  11. package/dist/browser/content/ChartExplorer.js +5 -3
  12. package/dist/browser/content/ChartExplorer.js.map +1 -1
  13. package/dist/browser/content/MapAttribution.js +27 -0
  14. package/dist/browser/content/MapAttribution.js.map +1 -0
  15. package/dist/browser/content/MapView.js +553 -0
  16. package/dist/browser/content/MapView.js.map +1 -0
  17. package/dist/browser/content/MapViewFrame.js +395 -0
  18. package/dist/browser/content/MapViewFrame.js.map +1 -0
  19. package/dist/browser/content/chart-inspection-core.js +4 -1
  20. package/dist/browser/content/chart-inspection-core.js.map +1 -1
  21. package/dist/browser/content/code-highlight.js +66 -0
  22. package/dist/browser/content/code-highlight.js.map +1 -1
  23. package/dist/browser/content/index.js +6 -0
  24. package/dist/browser/content/index.js.map +1 -1
  25. package/dist/browser/content/map-palette.js +39 -0
  26. package/dist/browser/content/map-palette.js.map +1 -0
  27. package/dist/browser/content/map-style.js +276 -0
  28. package/dist/browser/content/map-style.js.map +1 -0
  29. package/dist/browser/content/map-view-geometry.js +269 -0
  30. package/dist/browser/content/map-view-geometry.js.map +1 -0
  31. package/dist/browser/content/map-view-live.js +65 -0
  32. package/dist/browser/content/map-view-live.js.map +1 -0
  33. package/dist/browser/content/map-view-messages.js +53 -0
  34. package/dist/browser/content/map-view-messages.js.map +1 -0
  35. package/dist/browser/content/map-view-types.js +2 -0
  36. package/dist/browser/content/map-view-types.js.map +1 -0
  37. package/dist/browser/content/map-view-worker.js +10 -0
  38. package/dist/browser/feedback/dialog-core.js +19 -0
  39. package/dist/browser/feedback/dialog-core.js.map +1 -1
  40. package/dist/browser/inputs/AutocompleteEditor.js +167 -104
  41. package/dist/browser/inputs/AutocompleteEditor.js.map +1 -1
  42. package/dist/browser/inputs/RichSelect.js +1474 -0
  43. package/dist/browser/inputs/RichSelect.js.map +1 -0
  44. package/dist/browser/inputs/TextInput.js +95 -60
  45. package/dist/browser/inputs/TextInput.js.map +1 -1
  46. package/dist/browser/inputs/choice.js +19 -8
  47. package/dist/browser/inputs/choice.js.map +1 -1
  48. package/dist/browser/inputs/index.js +1 -0
  49. package/dist/browser/inputs/index.js.map +1 -1
  50. package/dist/browser/inputs/rich-select-messages.js +46 -0
  51. package/dist/browser/inputs/rich-select-messages.js.map +1 -0
  52. package/dist/browser/layout/AppWorkspace.js +194 -144
  53. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  54. package/dist/browser/layout/DetailPanel.js +10 -1
  55. package/dist/browser/layout/DetailPanel.js.map +1 -1
  56. package/dist/browser/layout/Navigation.js +14 -5
  57. package/dist/browser/layout/Navigation.js.map +1 -1
  58. package/dist/browser/layout/PageTitle.js +9 -3
  59. package/dist/browser/layout/PageTitle.js.map +1 -1
  60. package/dist/browser/layout/ResizeSeparator.js +8 -2
  61. package/dist/browser/layout/ResizeSeparator.js.map +1 -1
  62. package/dist/browser/layout/app-workspace-controller.js +301 -34
  63. package/dist/browser/layout/app-workspace-controller.js.map +1 -1
  64. package/dist/browser/layout/app-workspace-width.js +26 -0
  65. package/dist/browser/layout/app-workspace-width.js.map +1 -0
  66. package/dist/browser/layout/index.js +1 -1
  67. package/dist/browser/layout/index.js.map +1 -1
  68. package/dist/browser/layout/navigation-model.js.map +1 -1
  69. package/dist/browser/layout/resize-separator.js +25 -1
  70. package/dist/browser/layout/resize-separator.js.map +1 -1
  71. package/dist/browser/surfaces/Skeleton.js +14 -0
  72. package/dist/browser/surfaces/Skeleton.js.map +1 -0
  73. package/dist/browser/surfaces/index.js +1 -0
  74. package/dist/browser/surfaces/index.js.map +1 -1
  75. package/dist/licenses/maplibre-gl.txt +116 -0
  76. package/dist/ssr/actions/Toolbar.js +2 -0
  77. package/dist/ssr/actions/Toolbar.js.map +1 -1
  78. package/dist/ssr/actions/ViewTabs.js +8 -0
  79. package/dist/ssr/actions/ViewTabs.js.map +1 -1
  80. package/dist/ssr/chat/ChatDecision.js +11 -0
  81. package/dist/ssr/chat/ChatDecision.js.map +1 -1
  82. package/dist/ssr/content/Chart.js +27 -7
  83. package/dist/ssr/content/Chart.js.map +1 -1
  84. package/dist/ssr/content/ChartExplorer.js +5 -3
  85. package/dist/ssr/content/ChartExplorer.js.map +1 -1
  86. package/dist/ssr/content/MapAttribution.js +19 -0
  87. package/dist/ssr/content/MapAttribution.js.map +1 -0
  88. package/dist/ssr/content/MapView.js +474 -0
  89. package/dist/ssr/content/MapView.js.map +1 -0
  90. package/dist/ssr/content/MapViewFrame.js +193 -0
  91. package/dist/ssr/content/MapViewFrame.js.map +1 -0
  92. package/dist/ssr/content/chart-inspection-core.js +4 -1
  93. package/dist/ssr/content/chart-inspection-core.js.map +1 -1
  94. package/dist/ssr/content/code-highlight.js +66 -0
  95. package/dist/ssr/content/code-highlight.js.map +1 -1
  96. package/dist/ssr/content/index.js +6 -0
  97. package/dist/ssr/content/index.js.map +1 -1
  98. package/dist/ssr/content/map-palette.js +39 -0
  99. package/dist/ssr/content/map-palette.js.map +1 -0
  100. package/dist/ssr/content/map-style.js +276 -0
  101. package/dist/ssr/content/map-style.js.map +1 -0
  102. package/dist/ssr/content/map-view-geometry.js +269 -0
  103. package/dist/ssr/content/map-view-geometry.js.map +1 -0
  104. package/dist/ssr/content/map-view-live.js +1 -0
  105. package/dist/ssr/content/map-view-messages.js +53 -0
  106. package/dist/ssr/content/map-view-messages.js.map +1 -0
  107. package/dist/ssr/content/map-view-types.js +2 -0
  108. package/dist/ssr/content/map-view-types.js.map +1 -0
  109. package/dist/ssr/feedback/dialog-core.js +19 -0
  110. package/dist/ssr/feedback/dialog-core.js.map +1 -1
  111. package/dist/ssr/inputs/AutocompleteEditor.js +64 -24
  112. package/dist/ssr/inputs/AutocompleteEditor.js.map +1 -1
  113. package/dist/ssr/inputs/RichSelect.js +950 -0
  114. package/dist/ssr/inputs/RichSelect.js.map +1 -0
  115. package/dist/ssr/inputs/TextInput.js +40 -16
  116. package/dist/ssr/inputs/TextInput.js.map +1 -1
  117. package/dist/ssr/inputs/choice.js +19 -8
  118. package/dist/ssr/inputs/choice.js.map +1 -1
  119. package/dist/ssr/inputs/index.js +1 -0
  120. package/dist/ssr/inputs/index.js.map +1 -1
  121. package/dist/ssr/inputs/rich-select-messages.js +46 -0
  122. package/dist/ssr/inputs/rich-select-messages.js.map +1 -0
  123. package/dist/ssr/layout/AppWorkspace.js +53 -16
  124. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  125. package/dist/ssr/layout/DetailPanel.js +1 -1
  126. package/dist/ssr/layout/DetailPanel.js.map +1 -1
  127. package/dist/ssr/layout/Navigation.js +1 -1
  128. package/dist/ssr/layout/Navigation.js.map +1 -1
  129. package/dist/ssr/layout/PageTitle.js +9 -3
  130. package/dist/ssr/layout/PageTitle.js.map +1 -1
  131. package/dist/ssr/layout/ResizeSeparator.js +4 -1
  132. package/dist/ssr/layout/ResizeSeparator.js.map +1 -1
  133. package/dist/ssr/layout/app-workspace-controller.js +301 -34
  134. package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
  135. package/dist/ssr/layout/app-workspace-width.js +26 -0
  136. package/dist/ssr/layout/app-workspace-width.js.map +1 -0
  137. package/dist/ssr/layout/index.js +1 -1
  138. package/dist/ssr/layout/index.js.map +1 -1
  139. package/dist/ssr/layout/navigation-model.js.map +1 -1
  140. package/dist/ssr/layout/resize-separator.js +25 -1
  141. package/dist/ssr/layout/resize-separator.js.map +1 -1
  142. package/dist/ssr/surfaces/Skeleton.js +8 -0
  143. package/dist/ssr/surfaces/Skeleton.js.map +1 -0
  144. package/dist/ssr/surfaces/index.js +1 -0
  145. package/dist/ssr/surfaces/index.js.map +1 -1
  146. package/dist/styles.css +1 -1
  147. package/dist/types/content/Chart.d.ts +4 -2
  148. package/dist/types/content/ChartExplorer.d.ts +0 -1
  149. package/dist/types/content/MapAttribution.d.ts +6 -0
  150. package/dist/types/content/MapView.d.ts +5 -0
  151. package/dist/types/content/MapViewFrame.d.ts +31 -0
  152. package/dist/types/content/code-highlight.d.ts +3 -1
  153. package/dist/types/content/index.d.ts +7 -0
  154. package/dist/types/content/map-palette.d.ts +58 -0
  155. package/dist/types/content/map-style.d.ts +29 -0
  156. package/dist/types/content/map-view-geometry.d.ts +55 -0
  157. package/dist/types/content/map-view-live.d.ts +2 -0
  158. package/dist/types/content/map-view-messages.d.ts +21 -0
  159. package/dist/types/content/map-view-types.d.ts +63 -0
  160. package/dist/types/feedback/dialog-core.d.ts +1 -0
  161. package/dist/types/inputs/AutocompleteEditor.d.ts +6 -1
  162. package/dist/types/inputs/RichSelect.d.ts +93 -0
  163. package/dist/types/inputs/TextInput.d.ts +5 -2
  164. package/dist/types/inputs/choice.d.ts +24 -4
  165. package/dist/types/inputs/index.d.ts +2 -0
  166. package/dist/types/inputs/rich-select-messages.d.ts +21 -0
  167. package/dist/types/layout/AppWorkspace.d.ts +14 -3
  168. package/dist/types/layout/DetailPanel.d.ts +2 -0
  169. package/dist/types/layout/app-workspace-controller.d.ts +2 -0
  170. package/dist/types/layout/app-workspace-width.d.ts +13 -0
  171. package/dist/types/layout/index.d.ts +2 -2
  172. package/dist/types/layout/navigation-model.d.ts +2 -0
  173. package/dist/types/layout/resize-separator.d.ts +1 -0
  174. package/dist/types/surfaces/Skeleton.d.ts +6 -0
  175. package/dist/types/surfaces/index.d.ts +1 -0
  176. package/map-glyphs/IBM Plex Sans Medium/0-255.pbf +0 -0
  177. package/map-glyphs/IBM Plex Sans Medium/1024-1279.pbf +0 -0
  178. package/map-glyphs/IBM Plex Sans Medium/256-511.pbf +0 -0
  179. package/map-glyphs/IBM Plex Sans Medium/512-767.pbf +0 -0
  180. package/map-glyphs/IBM Plex Sans Medium/768-1023.pbf +0 -0
  181. package/map-glyphs/IBM Plex Sans Medium/7680-7935.pbf +0 -0
  182. package/map-glyphs/IBM Plex Sans Medium/8192-8447.pbf +0 -0
  183. package/map-glyphs/IBM Plex Sans Medium/8448-8703.pbf +0 -0
  184. package/map-glyphs/IBM Plex Sans Medium/8704-8959.pbf +0 -0
  185. package/map-glyphs/OFL.txt +93 -0
  186. package/package.json +11 -6
@@ -92,14 +92,16 @@ export type ChartProps = {
92
92
  /** Target when zooming in from the world view. Defaults to Europe (50, 10). */
93
93
  zoomFocus?: Pick<MapViewport, "latitude" | "longitude">;
94
94
  } : {}) & (K extends "line" ? {
95
- maxGap?: number;
95
+ /** Largest connected X distance; positive, finite, without area/errorBand fills. */ maxGap?: number;
96
+ /** Wrap the legend above the plot inside the caller's total chart height. Requires legend=true. */
97
+ legendPlacement?: "top-start";
96
98
  } : {}) & (K extends "stateTimeline" ? StateTimelineChartOptions : Omit<Parameters<(typeof charts)[K]>[0], "width" | "height" | "inspect">);
97
99
  }[ChartKind];
98
100
  /** Pure renderer options: component layout, events and inspection are configured elsewhere. */
99
101
  export type ChartRenderOptions = {
100
102
  [K in ChartKind]: Omit<Extract<ChartProps, {
101
103
  kind: K;
102
- }>, "class" | "style" | "labels" | "interactive" | "onSelect" | "selected" | "tooltip" | "cursor">;
104
+ }>, "class" | "style" | "labels" | "interactive" | "onSelect" | "selected" | "tooltip" | "cursor" | "legendPlacement">;
103
105
  }[ChartKind];
104
106
  /** Keep the fixed 28-unit bar-gauge rows inside the shared SSR/browser coordinate space. */
105
107
  export declare const chartRenderHeight: (props: ChartRenderOptions) => number;
@@ -10,7 +10,6 @@ export type ChartExplorerColumn<T> = {
10
10
  render?: (row: T) => JSX.Element;
11
11
  /**
12
12
  * Explicit comparable value. Omit to leave the column unsortable.
13
- * Returning a number also exempts the cell from spreadsheet formula guarding on copy.
14
13
  */
15
14
  sortValue?: (row: T) => string | number | null;
16
15
  align?: "left" | "center" | "right";
@@ -0,0 +1,6 @@
1
+ import { type JSX } from "solid-js";
2
+ /**
3
+ * The required credits for maps built with `mapStyle()`, each one a link, for MapView's `attribution` slot.
4
+ * @example <MapView style={style} attribution={<MapAttribution />} height={320} />
5
+ */
6
+ export declare function MapAttribution(): JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { type JSX } from "solid-js";
2
+ import type { MapViewProps } from "./map-view-types";
3
+ export type { MapViewProps } from "./map-view-types";
4
+ /** A static server frame enhanced with a same-origin MapLibre worker only after it enters the viewport. */
5
+ export declare function MapView(props: MapViewProps): JSX.Element;
@@ -0,0 +1,31 @@
1
+ import { type JSX } from "solid-js";
2
+ import { type MapFrame } from "./map-view-geometry";
3
+ import type { MapViewFrameProps, MapViewMarker } from "./map-view-types";
4
+ export type { MapViewFrameProps } from "./map-view-types";
5
+ export declare const mapNumber: (value: number) => string;
6
+ export declare const selectedMarker: (markers: MapViewMarker[], selectedId?: string) => MapViewMarker | undefined;
7
+ export declare function frameStyle(frame: MapFrame, padding: number): JSX.CSSProperties;
8
+ export declare function MapGeometry(props: MapViewFrameProps & {
9
+ frame: MapFrame;
10
+ boxStyle?: JSX.CSSProperties;
11
+ onSelect?: (id: string) => void;
12
+ /** Pins are buttons in MapView; the standalone frame draws them as labelled images, never focusable. */
13
+ interactive?: boolean;
14
+ /** 2^(live zoom - fitted zoom), so pin separation follows the person's zoom; 1 until then. */
15
+ zoomFactor?: number;
16
+ }): JSX.Element;
17
+ export type MapScale = {
18
+ label: string;
19
+ width: string;
20
+ };
21
+ export declare function referenceScale(frame: MapFrame, padding: number): MapScale;
22
+ export declare function MapScaleBar(props: {
23
+ scale: MapScale;
24
+ }): JSX.Element;
25
+ /** The scale bar and the attribution share the bottom row, so a long attribution wraps before it covers the scale. */
26
+ export declare function MapFootRow(props: {
27
+ scale?: MapScale;
28
+ children?: JSX.Element;
29
+ }): JSX.Element;
30
+ /** Geometry without a browser, a canvas, or a network dependency; suitable for server rendering and PDF output. */
31
+ export declare function MapViewFrame(props: MapViewFrameProps): JSX.Element;
@@ -6,9 +6,11 @@
6
6
  * in token spans, so the returned strings are safe to inject with
7
7
  * `innerHTML`.
8
8
  */
9
- export type CodeDisplayLanguage = "ts" | "tsx" | "js" | "jsx" | "script" | "markdown" | "md" | "text";
9
+ export type CodeDisplayLanguage = "ts" | "tsx" | "js" | "jsx" | "script" | "markdown" | "md" | "text" | "sql";
10
10
  export declare const escapeCodeHtml: (s: string) => string;
11
11
  export declare const highlightCode: (code: string) => string;
12
12
  export declare const highlightMarkdownDisplay: (code: string) => string;
13
13
  export declare const highlightCodeDisplayLines: (code: string, language?: CodeDisplayLanguage) => string[];
14
14
  export declare const highlightCodeDisplay: (code: string, language?: CodeDisplayLanguage) => string;
15
+ /** Display-only, tolerant of incomplete SQL while typing. Source is always escaped. */
16
+ export declare const highlightSql: (code: string) => string;
@@ -17,6 +17,7 @@ export type { ChartDatumRef, ChartSelection, ChartTooltip, ChartTooltipFormatter
17
17
  export type { ChartSnapshot } from "./chart-snapshot";
18
18
  export { prepareChartSnapshot } from "./chart-snapshot";
19
19
  export type { StateTimelineChartOptions, StateTimelineDomain, StateTimelineInterval, StateTimelineRow, StateTimelineState, } from "./chart-state-timeline";
20
+ export { highlightSql } from "./code-highlight";
20
21
  export { type CollectionSelection, createCollectionSelection, type SelectionModifiers } from "./collection-selection";
21
22
  export type { DataTableColumn, DataTableControlsProps, DataTableFooter, DataTableHeaderProps, DataTablePanelFooterProps, DataTablePanelProps, DataTableProps, DataTableRenderCell, DataTableRenderHeader, DataTableSort, } from "./DataTable";
22
23
  export { default as DataTable } from "./DataTable";
@@ -35,9 +36,15 @@ export type { LightboxAction, LightboxImage } from "./Lightbox";
35
36
  export { default as Lightbox } from "./Lightbox";
36
37
  export type { LogTableEntry } from "./LogEntriesTable";
37
38
  export { default as LogEntriesTable } from "./LogEntriesTable";
39
+ export { MapAttribution } from "./MapAttribution";
40
+ export { MapView } from "./MapView";
41
+ export { MapViewFrame } from "./MapViewFrame";
38
42
  export { default as MarkdownView, type MarkdownRenderOptions, type MarkdownViewProps, renderSafeMarkdown } from "./MarkdownView";
39
43
  export type { MessageGroupEntry, MessageRowAction, MessageRowAttachment, MessageRowAuthor, MessageRowFile, MessageRowMedia, MessageRowProgress, MessageRowProps, MessageRowQuote, MessageRowReaction, MessageRowStatus, MessageRowThread, MessageSystemRowProps, } from "./MessageRow";
40
44
  export { MessageRow, MessageSystemRow, startsMessageGroup } from "./MessageRow";
45
+ export { type MapPaletteColors, type MapTheme, mapPalette } from "./map-palette";
46
+ export { type MapStyleOptions, mapAttribution, mapStyle } from "./map-style";
47
+ export type { MapViewArea, MapViewFit, MapViewFrameProps, MapViewLine, MapViewLineTone, MapViewMarker, MapViewOwnLocation, MapViewPoint, MapViewProps, MapViewStyle, MapViewStyleSource, MapViewTone, } from "./map-view-types";
41
48
  export { MARKDOWN_CALLOUT_CLASSES, MARKDOWN_CALLOUT_ICON_ATTRIBUTES, type MarkdownInfoBlock, type MarkdownInfoBlockRenderInput, type MarkdownInfoBlockType, markdownInfoBlocks, renderMarkdownInfoBlock, scanMarkdownInfoBlock, } from "./markdown-info-blocks";
42
49
  export { type MarkdownLinkInput, type MarkdownReference, type MarkdownReferenceKind, type MarkdownReferenceType, markdownLinkReference, markdownReferenceIcon, markdownReferenceType, markdownReferenceTypeLabel, markStandaloneLinks, renderMarkdownLink, } from "./markdown-links";
43
50
  export { Pagination, type PaginationProps } from "./Pagination";
@@ -0,0 +1,58 @@
1
+ /** The map image colours. Each key is also the CSS token `--k2b-map-<kebab-key>` on `.k2b-map-view`. */
2
+ export type MapPaletteColors = {
3
+ /** Background land, also behind the server frame before the map image arrives. */
4
+ land: string;
5
+ /** Woods, grass, and city green; large protected areas stay plain land. */
6
+ green: string;
7
+ water: string;
8
+ building: string;
9
+ road: string;
10
+ roadCasing: string;
11
+ motorway: string;
12
+ motorwayCasing: string;
13
+ /** Rail lines and footpaths. */
14
+ rail: string;
15
+ boundary: string;
16
+ /** Streets, suburbs, villages, and states. */
17
+ label: string;
18
+ /** Cities, towns, and countries. */
19
+ labelStrong: string;
20
+ waterLabel: string;
21
+ };
22
+ export type MapTheme = "light" | "dark";
23
+ /**
24
+ * Plain data so a server can build the style JSON without CSS. The accent stays with the host's
25
+ * pins and lines; the map image only uses calm land, water, green, and road tones.
26
+ */
27
+ export declare const mapPalette: {
28
+ readonly light: {
29
+ readonly land: "#f1efe9";
30
+ readonly green: "#e3ecd9";
31
+ readonly water: "#cfe3f3";
32
+ readonly building: "#e8e5dd";
33
+ readonly road: "#ffffff";
34
+ readonly roadCasing: "#dcd8ce";
35
+ readonly motorway: "#f6c76b";
36
+ readonly motorwayCasing: "#d9a443";
37
+ readonly rail: "#c4bfb4";
38
+ readonly boundary: "#aea89c";
39
+ readonly label: "#52525b";
40
+ readonly labelStrong: "#27272a";
41
+ readonly waterLabel: "#3a6383";
42
+ };
43
+ readonly dark: {
44
+ readonly land: "#1a1f26";
45
+ readonly green: "#1c2a22";
46
+ readonly water: "#14283a";
47
+ readonly building: "#20262e";
48
+ readonly road: "#2c333d";
49
+ readonly roadCasing: "#222830";
50
+ readonly motorway: "#5d6470";
51
+ readonly motorwayCasing: "#444a54";
52
+ readonly rail: "#39404a";
53
+ readonly boundary: "#4f5763";
54
+ readonly label: "#a1a1aa";
55
+ readonly labelStrong: "#e4e4e7";
56
+ readonly waterLabel: "#8fb5d3";
57
+ };
58
+ };
@@ -0,0 +1,29 @@
1
+ import type { StyleSpecification } from "maplibre-gl";
2
+ import { type MapTheme } from "./map-palette";
3
+ export type MapStyleOptions = {
4
+ theme: MapTheme;
5
+ /** Request locale such as `de` or `de-DE`; labels prefer `name:<language>`. */
6
+ locale: string;
7
+ /** Vector tile template with `{z}`, `{x}`, and `{y}`, for example `/_geo/tiles/{z}/{x}/{y}.pbf`. */
8
+ tiles: string;
9
+ /** Glyph template with `{fontstack}` and `{range}`, served from `@k2b/ui/map-glyphs/*`. */
10
+ glyphs: string;
11
+ /** Highest zoom the tiles carry; the map scales the last level up beyond it. Defaults to 14. */
12
+ maxzoom?: number;
13
+ };
14
+ /** Attribution for OpenMapTiles-schema maps with OpenStreetMap data from Geoapify, in display order. */
15
+ export declare const mapAttribution: readonly [{
16
+ readonly label: "© OpenStreetMap";
17
+ readonly href: "https://www.openstreetmap.org/copyright";
18
+ }, {
19
+ readonly label: "© OpenMapTiles";
20
+ readonly href: "https://openmaptiles.org/";
21
+ }, {
22
+ readonly label: "Geoapify";
23
+ readonly href: "https://www.geoapify.com/";
24
+ }];
25
+ /**
26
+ * A flat Cloud map style for OpenMapTiles-schema vector tiles. The host passes the tile and glyph
27
+ * templates; there are no network defaults, sprites, extrusions, or relief.
28
+ */
29
+ export declare function mapStyle(options: MapStyleOptions): StyleSpecification;
@@ -0,0 +1,55 @@
1
+ import type { MapViewFrameProps, MapViewLine, MapViewMarker, MapViewPoint } from "./map-view-types";
2
+ export declare const MIN_SPAN: number;
3
+ export declare const EARTH_CIRCUMFERENCE = 40075016.686;
4
+ /** Room around the fitted geometry: clears the floating controls, the notice, the scale bar and the attribution. */
5
+ export declare const DEFAULT_PADDING = 64;
6
+ /**
7
+ * `referenceWidth` is the fitted width when the container is wide enough; `minWidth` keeps the whole world at least as
8
+ * tall as the map, the smallest zoom MapLibre allows, so a world-scale fit lands where MapLibre puts it.
9
+ */
10
+ export type MapFrame = {
11
+ minX: number;
12
+ minY: number;
13
+ spanX: number;
14
+ spanY: number;
15
+ aspect: number;
16
+ referenceWidth: number;
17
+ minWidth: number;
18
+ /** The fitted width on a 320 px phone: pins are kept apart from this scale up, so they never cover each other there. */
19
+ overlapWidth: number;
20
+ };
21
+ export declare function decodePolyline6(encoded: string): MapViewPoint[];
22
+ export declare const linePoints: (line: MapViewLine) => MapViewPoint[];
23
+ export declare function projectPoint(point: MapViewPoint): {
24
+ x: number;
25
+ y: number;
26
+ };
27
+ export declare function unprojectPoint(x: number, y: number): MapViewPoint;
28
+ export declare function mapFrame(geometry: Pick<MapViewFrameProps, "markers" | "lines" | "areas" | "ownLocation" | "fit">, height: number, padding?: number): MapFrame | null;
29
+ export declare function fitCamera(frame: MapFrame, width: number, padding?: number): {
30
+ center: [number, number];
31
+ zoom: number;
32
+ };
33
+ export declare const isStop: (marker: MapViewMarker) => boolean;
34
+ export declare function sortMarkers(markers: MapViewMarker[]): MapViewMarker[];
35
+ type PinOffset = {
36
+ dx: number;
37
+ dy: number;
38
+ };
39
+ /**
40
+ * Pin offsets in px, decided from the data alone: at the phone fit and checked for every wider fit up to the widest
41
+ * one, so they hold at any width. `zoomFactor` is 2^(live zoom - fitted zoom): 1 for the server frame, the first client
42
+ * frame and the untouched live map, so all three agree; when the person zooms, separation is decided for the new scale.
43
+ */
44
+ export declare function pinOffsets(sortedMarkers: MapViewMarker[], frame: MapFrame, zoomFactor?: number, ownLocation?: MapViewPoint): Map<string, PinOffset>;
45
+ /**
46
+ * The touch hit radius of each pin in px: up to 22 px (a 44 px target), but never into a neighbour's visible mark
47
+ * (radius up to 14 px) at any width, so a tap on a visible pin always reaches it.
48
+ */
49
+ export declare function pinHitRadii(sortedMarkers: MapViewMarker[], frame: MapFrame, offsets: Map<string, PinOffset>, zoomFactor?: number): Map<string, number>;
50
+ export declare const metersPerPixel: (lat: number, zoom: number) => number;
51
+ export declare function scaleBar(mpp: number, maxPx?: number): {
52
+ meters: number;
53
+ label: string;
54
+ };
55
+ export {};
@@ -0,0 +1,2 @@
1
+ import { Map, type MapOptions } from "maplibre-gl";
2
+ export declare function createMap(options: MapOptions, onResourceError: () => void): Map;
@@ -0,0 +1,21 @@
1
+ export declare const useMapViewMessages: () => () => {
2
+ mapLabel: string;
3
+ summary: ({ count }: {
4
+ count: number;
5
+ }) => string;
6
+ pins: string;
7
+ zoomIn: string;
8
+ zoomOut: string;
9
+ locate: string;
10
+ loading: string;
11
+ error: string;
12
+ retry: string;
13
+ reload: string;
14
+ noWebgl: string;
15
+ ownLocation: string;
16
+ canvasTitle: string;
17
+ gestureWindows: string;
18
+ gestureMac: string;
19
+ gestureMobile: string;
20
+ };
21
+ export declare const checkMapViewMessages: () => import("@k2b/stdlib").CatalogIssue[];
@@ -0,0 +1,63 @@
1
+ import type { StyleSpecification } from "maplibre-gl";
2
+ import type { JSX } from "solid-js";
3
+ export type MapViewPoint = {
4
+ lat: number;
5
+ lon: number;
6
+ };
7
+ export type MapViewTone = "accent" | "second" | "neutral" | "warning";
8
+ export type MapViewMarker = {
9
+ id: string;
10
+ point: MapViewPoint;
11
+ /** A number, a single letter, or "+". Omit for a drop pin. */
12
+ mark?: number | string;
13
+ label: string;
14
+ tone?: MapViewTone;
15
+ selected?: boolean;
16
+ };
17
+ export type MapViewLineTone = "accent" | "muted" | "preview" | "previous";
18
+ export type MapViewLine = {
19
+ id: string;
20
+ tone?: MapViewLineTone;
21
+ } & ({
22
+ polyline6: string;
23
+ } | {
24
+ points: MapViewPoint[];
25
+ });
26
+ export type MapViewArea = {
27
+ id: string;
28
+ polygon: MapViewPoint[];
29
+ tone?: MapViewTone;
30
+ };
31
+ export type MapViewOwnLocation = {
32
+ point: MapViewPoint;
33
+ accuracyMeters?: number;
34
+ };
35
+ export type MapViewStyle = string | StyleSpecification;
36
+ export type MapViewStyleSource = MapViewStyle | {
37
+ light: MapViewStyle;
38
+ dark: MapViewStyle;
39
+ };
40
+ export type MapViewFit = "all" | "markers";
41
+ export type MapViewFrameProps = {
42
+ markers?: MapViewMarker[];
43
+ lines?: MapViewLine[];
44
+ areas?: MapViewArea[];
45
+ ownLocation?: MapViewOwnLocation;
46
+ height: number;
47
+ padding?: number;
48
+ fit?: MapViewFit;
49
+ selectedId?: string;
50
+ attribution?: JSX.Element;
51
+ class?: string;
52
+ };
53
+ export type MapViewProps = Omit<MapViewFrameProps, "attribution"> & {
54
+ style: MapViewStyleSource;
55
+ attribution: JSX.Element;
56
+ onSelect?: (id: string) => void;
57
+ infoTile?: (marker: MapViewMarker) => JSX.Element;
58
+ notice?: JSX.Element;
59
+ empty?: JSX.Element;
60
+ onLocate?: () => void;
61
+ /** Observe rendering and resource failures without receiving provider responses or URLs. */
62
+ onStateChange?: (state: "static" | "loading" | "ready" | "error" | "no-webgl" | "empty") => void;
63
+ };
@@ -15,6 +15,7 @@ export type OpenDialogOptions = {
15
15
  * Without it, only the synthetic Back on close is suppressed.
16
16
  * Island disposal closes every open dialog immediately and forgets its marker without traversing history.
17
17
  * The same-URL entry remains for the router to replace and counts as a page entry for later dialogs.
18
+ * A traversal that `@k2b/ssr/nav` hides from popstate listeners reaches this core through `ssr:nav-popstate`.
18
19
  */
19
20
  history?: boolean;
20
21
  };
@@ -14,7 +14,12 @@ export type AutocompleteEditorProps = ValueFieldProps<string> & {
14
14
  name?: string;
15
15
  maxLength?: number;
16
16
  textareaRef?: (element: HTMLTextAreaElement) => void;
17
- variant?: "default" | "paper";
17
+ variant?: "default" | "paper" | "embedded";
18
+ readOnly?: boolean;
19
+ /** Number logical lines; disables soft wrapping to keep the gutter aligned. */
20
+ lineNumbers?: boolean;
21
+ /** One-based line to mark in the gutter, for example a parser error. */
22
+ markedLine?: number;
18
23
  };
19
24
  export declare function AutocompleteEditor(props: AutocompleteEditorProps): JSX.Element;
20
25
  export type { Completion, SuggestContext, Suggestion } from "./completion";
@@ -0,0 +1,93 @@
1
+ import { type JSX } from "solid-js";
2
+ import type { ValueFieldProps } from "./field-contract";
3
+ import type { ChoiceAppearance } from "./Select";
4
+ /** One option: a name plus at most one short line. */
5
+ export type RichSelectItem = {
6
+ value: string;
7
+ /** Wraps; never truncated. */
8
+ label: string;
9
+ /** At most one short line that says what the choice changes. */
10
+ description?: string;
11
+ /** Icon class shown before the name. */
12
+ icon?: string;
13
+ /** Color dot shown before the name, such as a space color. Replaces `icon`. */
14
+ color?: string;
15
+ /** Creates a fresh visual for each render location. Replaces `icon` and `color`. */
16
+ visual?: () => JSX.Element;
17
+ /** Makes the row unavailable. The reason replaces `description`; the arrow keys still reach the row. */
18
+ disabledReason?: string;
19
+ /** Section id. Headings show only from eight options; keep each section's items together. */
20
+ section?: string;
21
+ /** Extra search terms that are not shown. */
22
+ keywords?: readonly string[];
23
+ };
24
+ export type RichSelectSection = {
25
+ id: string;
26
+ label: string;
27
+ };
28
+ export type RichSelectStatus = "ready" | "loading" | "error";
29
+ export type RichSelectFooter = {
30
+ label: string;
31
+ icon?: string;
32
+ onActivate: () => void;
33
+ } | {
34
+ label: string;
35
+ icon?: string;
36
+ create: {
37
+ placeholder: string;
38
+ onCreate: (name: string) => void;
39
+ };
40
+ };
41
+ export type RichSelectFact = {
42
+ icon: string;
43
+ text: JSX.Element;
44
+ tone?: "default" | "warning";
45
+ };
46
+ export type RichSelectProps = ValueFieldProps<string | null> & {
47
+ items: readonly RichSelectItem[];
48
+ /** Labels for the `section` ids of the items. */
49
+ sections?: readonly RichSelectSection[];
50
+ /** Names the list: the heading of a list without preview, the phone sheet title, and the listbox label. */
51
+ title?: string;
52
+ placeholder?: string;
53
+ /** Replaces the selected item's name in the trigger, such as "Name · address". */
54
+ triggerLabel?: string;
55
+ /** Icon class for the trigger while no item with its own visual is selected. */
56
+ icon?: string;
57
+ tone?: "default" | "warning";
58
+ /** Custom content inside the shared trigger button, which keeps the combobox semantics. */
59
+ renderTrigger?: (selected: RichSelectItem | undefined) => JSX.Element;
60
+ /**
61
+ * The body of the preview beside the list, for options whose consequences differ.
62
+ * Without it the picker shows only the list. Keep it to at most three facts.
63
+ */
64
+ renderPreview?: (item: RichSelectItem) => JSX.Element;
65
+ searchPlaceholder?: string;
66
+ status?: RichSelectStatus;
67
+ onRetry?: () => void;
68
+ /** Shown when the list is ready and has no items. */
69
+ empty?: JSX.Element;
70
+ footer?: RichSelectFooter;
71
+ appearance?: ChoiceAppearance;
72
+ placement?: "bottom-start" | "top-start";
73
+ /** CSS lengths for the desktop popover. */
74
+ size?: {
75
+ width?: string;
76
+ height?: string;
77
+ };
78
+ name?: string;
79
+ };
80
+ /** Search and section headings appear from this many options. */
81
+ export declare const RICH_SELECT_SEARCH_FROM = 8;
82
+ /** Up to three short facts for a preview, each with an icon; warnings in the warning tone. */
83
+ export declare function RichSelectFacts(props: {
84
+ facts: readonly RichSelectFact[];
85
+ }): JSX.Element;
86
+ /**
87
+ * A dropdown whose rows explain each choice: a name plus one short line, an
88
+ * unavailable row with its reason, and an optional preview of what a choice
89
+ * changes. Desktop opens a popover beside the trigger; a phone opens a bottom
90
+ * sheet whose info buttons show the preview as a second level.
91
+ */
92
+ export declare function RichSelect(props: RichSelectProps): JSX.Element;
93
+ export default RichSelect;
@@ -5,9 +5,12 @@ export type TextInputProps = Omit<JSX.InputHTMLAttributes<HTMLInputElement>, "on
5
5
  minLength?: number;
6
6
  maxLength?: number;
7
7
  type?: "text" | "search" | "email" | "url" | "tel";
8
- variant?: "default" | "ai";
9
- icon?: string;
8
+ variant?: "default" | "ai" | "compact";
9
+ /** Set false for a plain field without a leading icon. */
10
+ icon?: string | false;
10
11
  activeIcon?: string;
12
+ /** ID of a consumer-owned visible error; caller owns its announcement. Native controls only. */
13
+ externalErrorId?: string;
11
14
  prefix?: JSX.Element;
12
15
  suffix?: JSX.Element;
13
16
  clearable?: boolean;
@@ -10,8 +10,19 @@ export type ChoiceOption<T extends string = string> = {
10
10
  groups?: readonly string[];
11
11
  };
12
12
  export type ChoiceOptionsLoader<T extends string = string> = (query: string, signal: AbortSignal) => Promise<readonly ChoiceOption<T>[]>;
13
- export declare const filterChoiceOptions: <T extends string>(options: readonly ChoiceOption<T>[], query: string) => readonly ChoiceOption<T>[];
14
- export declare const nextEnabledChoiceIndex: <T extends string>(options: readonly ChoiceOption<T>[], current: number, direction: 1 | -1) => number;
13
+ /** Matches label, description, value, and optional extra keywords. */
14
+ export declare const filterChoiceOptions: <O extends Pick<ChoiceOption<string>, "label" | "description" | "value"> & {
15
+ keywords?: readonly string[];
16
+ }>(options: readonly O[], query: string) => readonly O[];
17
+ /**
18
+ * Moves through the options and wraps at the ends, skipping `disabled` ones. A
19
+ * RichSelect row that cannot be chosen carries a `disabledReason` instead, so
20
+ * the arrow keys still reach it and its reason can be read.
21
+ */
22
+ export declare const nextEnabledChoiceIndex: <O extends {
23
+ label: string;
24
+ disabled?: boolean;
25
+ }>(options: readonly O[], current: number, direction: 1 | -1) => number;
15
26
  /**
16
27
  * Counts the leading pills that fit into `available` pixels and measures the
17
28
  * whole row. When not all of them fit, the rest collapse into a summary pill
@@ -32,8 +43,17 @@ export declare function createChoiceLoader<T extends string>(loader: () => Choic
32
43
  retry: () => void;
33
44
  cancel: () => void;
34
45
  };
35
- export declare const placeChoicePopover: (trigger: HTMLElement, popover: HTMLElement) => void;
36
- export declare function createChoicePopover(disabled: () => boolean): {
46
+ export type ChoicePopoverPlacement = {
47
+ /**
48
+ * `trigger` (default) gives the popover the trigger's width; `own` keeps the
49
+ * width its stylesheet sets, such as a RichSelect with a preview.
50
+ */
51
+ width?: "trigger" | "own";
52
+ /** The side tried first. The popover flips when the other side has more room. */
53
+ side?: "below" | "above";
54
+ };
55
+ export declare const placeChoicePopover: (trigger: HTMLElement, popover: HTMLElement, placement?: ChoicePopoverPlacement) => void;
56
+ export declare function createChoicePopover(disabled: () => boolean, placement?: () => ChoicePopoverPlacement): {
37
57
  open: () => boolean;
38
58
  setTrigger: Setter<HTMLElement | undefined>;
39
59
  setPopover: Setter<HTMLElement | undefined>;
@@ -37,6 +37,8 @@ export type { NumberInputProps } from "./NumberInput";
37
37
  export { NumberInput } from "./NumberInput";
38
38
  export type { QrScannerError, QrScannerProps } from "./QrScanner";
39
39
  export { QrScanner } from "./QrScanner";
40
+ export type { RichSelectFact, RichSelectFooter, RichSelectItem, RichSelectProps, RichSelectSection, RichSelectStatus, } from "./RichSelect";
41
+ export { RichSelect, RichSelectFacts } from "./RichSelect";
40
42
  export type { ChoiceAppearance, SelectGridSize, SelectGroup, SelectOption, SelectProps, SelectSourceOption, SelectView } from "./Select";
41
43
  export { Select } from "./Select";
42
44
  export type { SelectChipOption, SelectChipProps } from "./SelectChip";
@@ -0,0 +1,21 @@
1
+ declare const richSelectMessages: import("@k2b/stdlib").Catalog<{
2
+ back: string;
3
+ choose: string;
4
+ chooseOption: string;
5
+ close: string;
6
+ couldNotLoad: string;
7
+ create: string;
8
+ detailsFor: ({ name }: {
9
+ name: string;
10
+ }) => string;
11
+ loading: string;
12
+ noOptions: string;
13
+ noResults: string;
14
+ retry: string;
15
+ search: string;
16
+ }>;
17
+ export type RichSelectMessages = ReturnType<(typeof richSelectMessages)["resolve"]>["t"];
18
+ /** Resolved from the inherited render locale. */
19
+ export declare const useRichSelectMessages: () => (() => RichSelectMessages);
20
+ export declare const checkRichSelectMessages: () => import("@k2b/stdlib").CatalogIssue[];
21
+ export {};
@@ -1,9 +1,13 @@
1
1
  import { type LinkNavigateEvent, type NavigationScrollMode } from "@k2b/ssr/nav";
2
2
  import { type JSX } from "solid-js";
3
3
  import { type AppWorkspaceLayoutState } from "./app-workspace-state";
4
+ import { type AppWorkspaceWidthShare } from "./app-workspace-width";
4
5
  import type { ScrollAreaProps } from "./ScrollArea";
5
6
  import { type AppWorkspaceSidebarSwitcherProps } from "./SidebarSwitcher";
7
+ export type { AppWorkspaceWidthShare } from "./app-workspace-width";
6
8
  export type AppWorkspaceHeadProps = {
9
+ /** Below 48rem, show this head only with this active Main region. Unsplit Mains keep their head. */
10
+ mobilePane?: string;
7
11
  /** View tabs, usually a ViewTabs. */
8
12
  views?: JSX.Element;
9
13
  /** Filter chips, usually FilterChip elements. */
@@ -63,13 +67,13 @@ export type AppWorkspaceMainProps = {
63
67
  /** `"content"` centers the children as one reading column with the shared page width on large screens. */
64
68
  width?: "full" | "content";
65
69
  /**
66
- * The width in px that Main keeps beside the sidebar and an open Detail,
70
+ * The width in px or a workspace width share that Main keeps beside the sidebar and an open Detail,
67
71
  * from 48rem (768 px); at least the default 320. A Detail that does not fit
68
72
  * beside it waits behind the head's Details button, and from 64rem of host
69
73
  * width a sidebar that does not fit becomes the overlay. CSS decides, so
70
74
  * the server renders the first frame.
71
75
  */
72
- minWidth?: number;
76
+ minWidth?: number | AppWorkspaceWidthShare;
73
77
  mobilePane?: string;
74
78
  /** Levels in DOM order, shallowest first. The URL selects the deepest level by id. */
75
79
  level?: string;
@@ -93,7 +97,7 @@ export type AppWorkspaceMainPaneProps = {
93
97
  open?: boolean;
94
98
  resizable?: boolean;
95
99
  resizeShadow?: boolean;
96
- defaultSize?: number;
100
+ defaultSize?: number | AppWorkspaceWidthShare;
97
101
  minSize?: number;
98
102
  maxSize?: number;
99
103
  class?: string;
@@ -105,6 +109,10 @@ export type AppWorkspaceDetailWidth = "sm" | "md" | "lg" | "xl";
105
109
  export type AppWorkspaceDetailProps = {
106
110
  children: JSX.Element;
107
111
  open: boolean;
112
+ /** Keeps the shared head control reachable while closed; set the app's existing open state synchronously. */
113
+ onOpen?: () => void;
114
+ /** Whether the current object may show details. False disables reopening and hides the panel. */
115
+ available?: boolean;
108
116
  /**
109
117
  * Whether choosing an item in Main opens this Detail as the drawer while it waits.
110
118
  * Set false when Main itself shows the chosen item, such as a reader beside a list:
@@ -122,6 +130,7 @@ export type AppWorkspaceDetailProps = {
122
130
  maxWidth?: number;
123
131
  /**
124
132
  * Closes the column with Escape, or the phone sheet with a downward drag.
133
+ * With onOpen, the shared head control also closes the column or phone sheet.
125
134
  * Server-rendered panels mark their close control with
126
135
  * `data-workspace-detail-close` instead; those gestures click it.
127
136
  * Escape and a rightward touch swipe park an open waiting drawer without
@@ -395,6 +404,8 @@ export type AppWorkspaceNavTreeItemProps = {
395
404
  type AppWorkspaceNavTreeComponent = ((props: AppWorkspaceNavTreeProps) => JSX.Element) & {
396
405
  Item: (props: AppWorkspaceNavTreeItemProps) => JSX.Element;
397
406
  };
407
+ /** The Detail region's DOM id, for application controls that target it with aria-controls. */
408
+ export declare const appWorkspaceDetailElementId: (id: string) => string;
398
409
  type AppWorkspaceComponent = ((props: AppWorkspaceProps) => JSX.Element) & {
399
410
  LayoutStateProvider: (props: AppWorkspaceLayoutStateProviderProps) => JSX.Element;
400
411
  Head: (props: AppWorkspaceHeadProps) => JSX.Element;
@@ -2,6 +2,8 @@ import { type JSX } from "solid-js";
2
2
  import { type ButtonLinkProps, type ButtonProps } from "../actions/Button";
3
3
  import { type DropdownItem } from "../actions/Dropdown";
4
4
  export type DetailPanelProps = {
5
+ /** Plain sections share their host surface, as in AppWorkspace.Detail. */
6
+ surface?: "default" | "plain";
5
7
  children: JSX.Element;
6
8
  class?: string;
7
9
  };
@@ -11,6 +11,8 @@ export declare const parkWorkspaceDetailDrawers: (root?: ParentNode) => void;
11
11
  * stays application state, so the controller only requests the change.
12
12
  */
13
13
  export declare const APP_WORKSPACE_SIDEBAR_HIDE_EVENT = "k2b-app-workspace-sidebar-hide";
14
+ /** Asks the owning Detail to reopen its current available object. */
15
+ export declare const APP_WORKSPACE_DETAIL_OPEN_EVENT = "k2b-app-workspace-detail-open";
14
16
  /** Asks the owning `AppWorkspace.Detail` to close; its `onClose` decides. */
15
17
  export declare const APP_WORKSPACE_DETAIL_CLOSE_EVENT = "k2b-app-workspace-detail-close";
16
18
  /**