@k2b/ui 0.51.0 → 0.52.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 (206) hide show
  1. package/dist/base.css +3 -0
  2. package/dist/browser/actions/Toolbar.js +8 -2
  3. package/dist/browser/actions/Toolbar.js.map +1 -1
  4. package/dist/browser/charts/core/bar-labels.js +5 -0
  5. package/dist/browser/charts/core/bar-labels.js.map +1 -0
  6. package/dist/browser/charts/core/bubble.js +166 -0
  7. package/dist/browser/charts/core/bubble.js.map +1 -0
  8. package/dist/browser/charts/core/default-styles.js +83 -0
  9. package/dist/browser/charts/core/default-styles.js.map +1 -0
  10. package/dist/browser/charts/core/funnel-layout.js +79 -0
  11. package/dist/browser/charts/core/funnel-layout.js.map +1 -0
  12. package/dist/browser/charts/core/funnel.js +27 -0
  13. package/dist/browser/charts/core/funnel.js.map +1 -0
  14. package/dist/browser/charts/core/index.js +6 -1
  15. package/dist/browser/charts/core/index.js.map +1 -1
  16. package/dist/browser/charts/core/pareto.js +120 -0
  17. package/dist/browser/charts/core/pareto.js.map +1 -0
  18. package/dist/browser/charts/core/radar.js +101 -0
  19. package/dist/browser/charts/core/radar.js.map +1 -0
  20. package/dist/browser/charts/core/registry.js +11 -1
  21. package/dist/browser/charts/core/registry.js.map +1 -1
  22. package/dist/browser/charts/core/render-size.js +3 -1
  23. package/dist/browser/charts/core/render-size.js.map +1 -1
  24. package/dist/browser/charts/core/render.js +19 -0
  25. package/dist/browser/charts/core/render.js.map +1 -1
  26. package/dist/browser/charts/core/snapshot.js +1 -1
  27. package/dist/browser/charts/core/snapshot.js.map +1 -1
  28. package/dist/browser/charts/core/svg-barGauge.js +67 -0
  29. package/dist/browser/charts/core/svg-barGauge.js.map +1 -0
  30. package/dist/browser/charts/core/svg-boxplot.js +127 -0
  31. package/dist/browser/charts/core/svg-boxplot.js.map +1 -0
  32. package/dist/browser/charts/core/svg-common.js +1065 -0
  33. package/dist/browser/charts/core/svg-common.js.map +1 -0
  34. package/dist/browser/charts/core/svg-gauge.js +185 -0
  35. package/dist/browser/charts/core/svg-gauge.js.map +1 -0
  36. package/dist/browser/charts/core/svg-heatmap.js +80 -0
  37. package/dist/browser/charts/core/svg-heatmap.js.map +1 -0
  38. package/dist/browser/charts/core/svg-histogram.js +73 -0
  39. package/dist/browser/charts/core/svg-histogram.js.map +1 -0
  40. package/dist/browser/charts/core/svg-renderers.js +9 -1777
  41. package/dist/browser/charts/core/svg-renderers.js.map +1 -1
  42. package/dist/browser/charts/core/svg-scatter.js +114 -0
  43. package/dist/browser/charts/core/svg-scatter.js.map +1 -0
  44. package/dist/browser/charts/core/treemap.js +138 -0
  45. package/dist/browser/charts/core/treemap.js.map +1 -0
  46. package/dist/browser/charts/description.js.map +1 -1
  47. package/dist/browser/content/ChartRoot.js +21 -7
  48. package/dist/browser/content/ChartRoot.js.map +1 -1
  49. package/dist/browser/content/ChartSnapshotView.js +4 -1
  50. package/dist/browser/content/ChartSnapshotView.js.map +1 -1
  51. package/dist/browser/content/DataTable.js +186 -193
  52. package/dist/browser/content/DataTable.js.map +1 -1
  53. package/dist/browser/content/Lightbox.js +55 -23
  54. package/dist/browser/content/Lightbox.js.map +1 -1
  55. package/dist/browser/content/ThumbnailStrip.js +174 -0
  56. package/dist/browser/content/ThumbnailStrip.js.map +1 -0
  57. package/dist/browser/content/chart-bar.js +98 -0
  58. package/dist/browser/content/chart-bar.js.map +1 -1
  59. package/dist/browser/content/chart-inspection-core.js +28 -8
  60. package/dist/browser/content/chart-inspection-core.js.map +1 -1
  61. package/dist/browser/content/chart-message-catalog.js +18 -0
  62. package/dist/browser/content/chart-message-catalog.js.map +1 -1
  63. package/dist/browser/content/index.js +1 -0
  64. package/dist/browser/content/index.js.map +1 -1
  65. package/dist/browser/content/thumbnail-strip-messages.js +24 -0
  66. package/dist/browser/content/thumbnail-strip-messages.js.map +1 -0
  67. package/dist/browser/inputs/ChoiceInputs.js +132 -101
  68. package/dist/browser/inputs/ChoiceInputs.js.map +1 -1
  69. package/dist/browser/inputs/index.js +1 -0
  70. package/dist/browser/inputs/index.js.map +1 -1
  71. package/dist/browser/inputs/markdown/MarkdownSelectionToolbar.js +330 -0
  72. package/dist/browser/inputs/markdown/MarkdownSelectionToolbar.js.map +1 -0
  73. package/dist/browser/internal/field.js +96 -77
  74. package/dist/browser/internal/field.js.map +1 -1
  75. package/dist/browser/layout/AppWorkspace.js +7 -5
  76. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  77. package/dist/browser/layout/PanelDialog.js +92 -68
  78. package/dist/browser/layout/PanelDialog.js.map +1 -1
  79. package/dist/browser/surfaces/StatCell.js +82 -70
  80. package/dist/browser/surfaces/StatCell.js.map +1 -1
  81. package/dist/browser/surfaces/stat-cell-messages.js +4 -2
  82. package/dist/browser/surfaces/stat-cell-messages.js.map +1 -1
  83. package/dist/browser/widgets/DashboardFrame.js +93 -88
  84. package/dist/browser/widgets/DashboardFrame.js.map +1 -1
  85. package/dist/ssr/actions/Toolbar.js +8 -2
  86. package/dist/ssr/actions/Toolbar.js.map +1 -1
  87. package/dist/ssr/charts/core/bar-labels.js +5 -0
  88. package/dist/ssr/charts/core/bar-labels.js.map +1 -0
  89. package/dist/ssr/charts/core/bubble.js +166 -0
  90. package/dist/ssr/charts/core/bubble.js.map +1 -0
  91. package/dist/ssr/charts/core/default-styles.js +83 -0
  92. package/dist/ssr/charts/core/default-styles.js.map +1 -0
  93. package/dist/ssr/charts/core/funnel-layout.js +79 -0
  94. package/dist/ssr/charts/core/funnel-layout.js.map +1 -0
  95. package/dist/ssr/charts/core/funnel.js +27 -0
  96. package/dist/ssr/charts/core/funnel.js.map +1 -0
  97. package/dist/ssr/charts/core/index.js +6 -1
  98. package/dist/ssr/charts/core/index.js.map +1 -1
  99. package/dist/ssr/charts/core/pareto.js +120 -0
  100. package/dist/ssr/charts/core/pareto.js.map +1 -0
  101. package/dist/ssr/charts/core/radar.js +101 -0
  102. package/dist/ssr/charts/core/radar.js.map +1 -0
  103. package/dist/ssr/charts/core/registry.js +11 -1
  104. package/dist/ssr/charts/core/registry.js.map +1 -1
  105. package/dist/ssr/charts/core/render-size.js +3 -1
  106. package/dist/ssr/charts/core/render-size.js.map +1 -1
  107. package/dist/ssr/charts/core/render.js +19 -0
  108. package/dist/ssr/charts/core/render.js.map +1 -1
  109. package/dist/ssr/charts/core/snapshot.js +1 -1
  110. package/dist/ssr/charts/core/snapshot.js.map +1 -1
  111. package/dist/ssr/charts/core/svg-barGauge.js +67 -0
  112. package/dist/ssr/charts/core/svg-barGauge.js.map +1 -0
  113. package/dist/ssr/charts/core/svg-boxplot.js +127 -0
  114. package/dist/ssr/charts/core/svg-boxplot.js.map +1 -0
  115. package/dist/ssr/charts/core/svg-common.js +1065 -0
  116. package/dist/ssr/charts/core/svg-common.js.map +1 -0
  117. package/dist/ssr/charts/core/svg-gauge.js +185 -0
  118. package/dist/ssr/charts/core/svg-gauge.js.map +1 -0
  119. package/dist/ssr/charts/core/svg-heatmap.js +80 -0
  120. package/dist/ssr/charts/core/svg-heatmap.js.map +1 -0
  121. package/dist/ssr/charts/core/svg-histogram.js +73 -0
  122. package/dist/ssr/charts/core/svg-histogram.js.map +1 -0
  123. package/dist/ssr/charts/core/svg-renderers.js +9 -1777
  124. package/dist/ssr/charts/core/svg-renderers.js.map +1 -1
  125. package/dist/ssr/charts/core/svg-scatter.js +114 -0
  126. package/dist/ssr/charts/core/svg-scatter.js.map +1 -0
  127. package/dist/ssr/charts/core/treemap.js +138 -0
  128. package/dist/ssr/charts/core/treemap.js.map +1 -0
  129. package/dist/ssr/charts/description.js.map +1 -1
  130. package/dist/ssr/content/ChartRoot.js +21 -7
  131. package/dist/ssr/content/ChartRoot.js.map +1 -1
  132. package/dist/ssr/content/ChartSnapshotView.js +1 -0
  133. package/dist/ssr/content/ChartSnapshotView.js.map +1 -1
  134. package/dist/ssr/content/DataTable.js +12 -16
  135. package/dist/ssr/content/DataTable.js.map +1 -1
  136. package/dist/ssr/content/Lightbox.js +32 -3
  137. package/dist/ssr/content/Lightbox.js.map +1 -1
  138. package/dist/ssr/content/ThumbnailStrip.js +103 -0
  139. package/dist/ssr/content/ThumbnailStrip.js.map +1 -0
  140. package/dist/ssr/content/chart-bar.js +98 -0
  141. package/dist/ssr/content/chart-bar.js.map +1 -1
  142. package/dist/ssr/content/chart-inspection-core.js +28 -8
  143. package/dist/ssr/content/chart-inspection-core.js.map +1 -1
  144. package/dist/ssr/content/chart-message-catalog.js +18 -0
  145. package/dist/ssr/content/chart-message-catalog.js.map +1 -1
  146. package/dist/ssr/content/index.js +1 -0
  147. package/dist/ssr/content/index.js.map +1 -1
  148. package/dist/ssr/content/thumbnail-strip-messages.js +24 -0
  149. package/dist/ssr/content/thumbnail-strip-messages.js.map +1 -0
  150. package/dist/ssr/inputs/ChoiceInputs.js +55 -40
  151. package/dist/ssr/inputs/ChoiceInputs.js.map +1 -1
  152. package/dist/ssr/inputs/index.js +1 -0
  153. package/dist/ssr/inputs/index.js.map +1 -1
  154. package/dist/ssr/inputs/markdown/MarkdownSelectionToolbar.js +293 -0
  155. package/dist/ssr/inputs/markdown/MarkdownSelectionToolbar.js.map +1 -0
  156. package/dist/ssr/internal/field.js +36 -24
  157. package/dist/ssr/internal/field.js.map +1 -1
  158. package/dist/ssr/layout/AppWorkspace.js +5 -1
  159. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  160. package/dist/ssr/layout/PanelDialog.js +40 -26
  161. package/dist/ssr/layout/PanelDialog.js.map +1 -1
  162. package/dist/ssr/surfaces/StatCell.js +29 -18
  163. package/dist/ssr/surfaces/StatCell.js.map +1 -1
  164. package/dist/ssr/surfaces/stat-cell-messages.js +4 -2
  165. package/dist/ssr/surfaces/stat-cell-messages.js.map +1 -1
  166. package/dist/ssr/widgets/DashboardFrame.js +6 -11
  167. package/dist/ssr/widgets/DashboardFrame.js.map +1 -1
  168. package/dist/styles.css +1 -1
  169. package/dist/types/actions/Toolbar.d.ts +2 -0
  170. package/dist/types/charts/core/bar-labels.d.ts +1 -0
  171. package/dist/types/charts/core/bubble.d.ts +66 -0
  172. package/dist/types/charts/core/default-styles.d.ts +1 -0
  173. package/dist/types/charts/core/funnel-layout.d.ts +43 -0
  174. package/dist/types/charts/core/funnel.d.ts +13 -0
  175. package/dist/types/charts/core/index.d.ts +6 -1
  176. package/dist/types/charts/core/pareto.d.ts +40 -0
  177. package/dist/types/charts/core/radar.d.ts +47 -0
  178. package/dist/types/charts/core/registry.d.ts +10 -0
  179. package/dist/types/charts/core/render-size.d.ts +1 -1
  180. package/dist/types/charts/core/svg-barGauge.d.ts +3 -0
  181. package/dist/types/charts/core/svg-boxplot.d.ts +18 -0
  182. package/dist/types/charts/core/svg-common.d.ts +612 -0
  183. package/dist/types/charts/core/svg-gauge.d.ts +6 -0
  184. package/dist/types/charts/core/svg-heatmap.d.ts +6 -0
  185. package/dist/types/charts/core/svg-histogram.d.ts +16 -0
  186. package/dist/types/charts/core/svg-renderers.d.ts +8 -612
  187. package/dist/types/charts/core/svg-scatter.d.ts +23 -0
  188. package/dist/types/charts/core/treemap.d.ts +45 -0
  189. package/dist/types/charts/description.d.ts +63 -0
  190. package/dist/types/content/ChartRoot.d.ts +1 -1
  191. package/dist/types/content/Lightbox.d.ts +2 -0
  192. package/dist/types/content/ThumbnailStrip.d.ts +29 -0
  193. package/dist/types/content/chart-bar.d.ts +38 -2
  194. package/dist/types/content/chart-inspection-core.d.ts +7 -0
  195. package/dist/types/content/chart-inspection.d.ts +1 -0
  196. package/dist/types/content/chart-message-catalog.d.ts +8 -0
  197. package/dist/types/content/index.d.ts +1 -0
  198. package/dist/types/content/thumbnail-strip-messages.d.ts +10 -0
  199. package/dist/types/inputs/ChoiceInputs.d.ts +2 -0
  200. package/dist/types/inputs/index.d.ts +2 -0
  201. package/dist/types/inputs/markdown/MarkdownSelectionToolbar.d.ts +19 -0
  202. package/dist/types/internal/field.d.ts +2 -0
  203. package/dist/types/layout/PanelDialog.d.ts +5 -0
  204. package/dist/types/surfaces/stat-cell-messages.d.ts +1 -0
  205. package/dist/types/widgets/DashboardFrame.d.ts +4 -1
  206. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["surfaces/StatCell.tsx"],"sourcesContent":["import { type JSX, Match, Show, Switch } from \"solid-js\";\nimport type { ChartNumberFormat } from \"../charts/description\";\nimport { ChartSparkline } from \"../content/ChartSparkline\";\nimport type { ChartTooltipFormatter } from \"../content/chart-inspection-core\";\nimport { useLocale } from \"../intl/locale\";\nimport type { AccentColor } from \"../semantics\";\nimport { DeltaBadge } from \"./delta-badge\";\nimport { type StatGridSize, useStatGridSize, useStatGridSurface } from \"./StatGrid\";\nimport { useStatCellMessages } from \"./stat-cell-messages\";\n\nexport type StatCellTone = AccentColor;\n\nexport type StatCellAccent = {\n tone: StatCellTone;\n icon: string;\n text?: string;\n};\n\n/**\n * The change against a comparison period. `unit: \"ratio\"` (default) reads `0.082` as `+8.2 %`; `\"points\"` is the\n * difference of two shares in ratio units, so `0.031` reads `+3.1 pts`. Only with `better` does the badge carry a tone\n * and say \"better\" or \"worse\"; without it the change stays unrated.\n */\nexport type StatCellDelta = {\n value: number;\n unit?: \"ratio\" | \"points\" | \"absolute\";\n /** Existing measures can express a change in their own unit instead of a ratio. */\n format?: ChartNumberFormat;\n better?: \"up\" | \"down\";\n};\n\n/** The value the change compares against, shown under the figure, such as \"Last month 44,560\". */\nexport type StatCellCompare = {\n label: string;\n value: string | number;\n};\n\nexport type StatCellSize = StatGridSize;\n\nexport type StatCellProps = {\n label: string;\n /** The figure. `null` shows the empty dash; `sub` then says why. */\n value: string | number | JSX.Element | null;\n sub?: string;\n valueClass?: string;\n /** An icon in a chip before the label, in `tone`. `\"in\"` and `\"out\"` are the money colours of `FlowAmount`. */\n icon?: string;\n /** The chip colour of `icon`. Defaults to zinc. */\n tone?: StatCellTone | \"in\" | \"out\";\n accent?: StatCellAccent;\n delta?: StatCellDelta;\n /** Keep the figure and change on separate rows, including while loading. Defaults to beside the figure. */\n deltaPlacement?: \"below\";\n compare?: StatCellCompare;\n href?: string;\n title?: string;\n trend?: readonly number[];\n /**\n * Replaces the default trend tooltip in browser code, for example with a period title or a unit.\n * `selection.datum.index` is the source index into `trend`.\n */\n trendTooltip?: ChartTooltipFormatter;\n size?: StatCellSize;\n /**\n * Wraps the label, value and support line instead of truncating them. Use it for a cell whose height nothing\n * reserves, such as one figure on its own; cells compared in a row keep one line each.\n */\n wrap?: boolean;\n /** `\"loading\"` keeps the tile's size with placeholders; `\"error\"` says the figure did not load. */\n status?: \"loading\" | \"error\";\n /** Offers \"Try again\" after an error and \"Reload\" beside `stale`. */\n onRetry?: () => void;\n /** The figure is not current: a short note such as \"As of 09:12 · not current\" replaces the support line. */\n stale?: string;\n};\n\nfunction Body(props: StatCellProps): JSX.Element {\n const gridSize = useStatGridSize();\n const size = () => props.size ?? gridSize;\n const accent = () => props.accent;\n const locale = useLocale();\n const t = useStatCellMessages();\n const defaultTrendTooltip: ChartTooltipFormatter = ({ datum }) => {\n const y = datum.values.find((field) => field.key === \"y\")?.value ?? \"\";\n return {\n rows: [\n { label: props.label, value: typeof y === \"number\" ? new Intl.NumberFormat(locale(), { maximumFractionDigits: 6 }).format(y) : y },\n ],\n };\n };\n const compareValue = () => {\n const value = props.compare?.value;\n return typeof value === \"number\" ? new Intl.NumberFormat(locale()).format(value) : value;\n };\n const empty = () => props.value === null || props.value === undefined || props.value === \"\";\n return (\n <>\n <div class=\"k2b-stat-cell__head\">\n <Show when={props.icon}>\n {(icon) => (\n <span class=\"k2b-stat-cell__icon k2b-icon-tile\" data-tone={props.tone ?? \"zinc\"} aria-hidden=\"true\">\n <i class={icon()} />\n </span>\n )}\n </Show>\n <span class=\"k2b-stat-cell__label\" data-size={size()}>\n {props.label}\n </span>\n </div>\n <div class=\"k2b-stat-cell__main\">\n <Switch\n fallback={\n <>\n <span\n class={`k2b-stat-cell__value ${props.valueClass ?? \"\"}`}\n data-size={size()}\n data-empty={empty() || undefined}\n title={props.title}\n >\n {empty() ? \"–\" : props.value}\n </span>\n <Show when={!empty() && props.delta}>{(delta) => <DeltaBadge delta={delta()} compare={props.compare} />}</Show>\n </>\n }\n >\n <Match when={props.status === \"loading\"}>\n <span class=\"k2b-stat-cell__skeleton k2b-skeleton\" data-part=\"value\" aria-hidden=\"true\" />\n <span class=\"k2b-sr-only\">{t().loading}</span>\n </Match>\n <Match when={props.status === \"error\"}>\n <span class=\"k2b-stat-cell__error\">\n <i class=\"ti ti-alert-circle\" aria-hidden=\"true\" />\n {t().notLoaded}\n </span>\n </Match>\n </Switch>\n </div>\n <div class=\"k2b-stat-cell__support\">\n <Switch\n fallback={\n <Show\n when={props.stale}\n fallback={\n <>\n <Show when={props.compare}>\n {(compare) => (\n <span class=\"k2b-stat-cell__sub\">\n {compare().label} {compareValue()}\n </span>\n )}\n </Show>\n <Show when={props.sub}>{(sub) => <span class=\"k2b-stat-cell__sub\">{sub()}</span>}</Show>\n <Show when={accent()}>\n {(value) => (\n <Show\n when={value().text}\n fallback={<i class={`${value().icon} k2b-stat-cell__accent-icon`} data-tone={value().tone} aria-hidden=\"true\" />}\n >\n {(text) => (\n <span class=\"k2b-stat-cell__accent\" data-tone={value().tone}>\n <i class={value().icon} aria-hidden=\"true\" />\n {text()}\n </span>\n )}\n </Show>\n )}\n </Show>\n {/* No figure, no trend: an empty tile says why in `sub` and keeps the size of its other states. */}\n <Show when={!empty() && props.trend && props.trend.length > 1}>\n <ChartSparkline\n labels={{ interactiveChart: props.label }}\n tooltip={props.trendTooltip ?? defaultTrendTooltip}\n class=\"k2b-stat-cell__trend\"\n data={Array.from(props.trend ?? [])}\n showLast\n />\n </Show>\n </>\n }\n >\n {(stale) => (\n <>\n <span class=\"k2b-stat-cell__stale\">\n <i class=\"ti ti-clock-exclamation\" aria-hidden=\"true\" />\n {stale()}\n </span>\n <Show when={props.onRetry}>\n {(retry) => (\n <button type=\"button\" class=\"k2b-stat-cell__retry\" onClick={() => retry()()}>\n {t().reload}\n </button>\n )}\n </Show>\n </>\n )}\n </Show>\n }\n >\n <Match when={props.status === \"loading\"}>\n <span class=\"k2b-stat-cell__skeleton k2b-skeleton\" data-part=\"support\" aria-hidden=\"true\" />\n </Match>\n <Match when={props.status === \"error\"}>\n <Show when={props.onRetry}>\n {(retry) => (\n <button type=\"button\" class=\"k2b-stat-cell__retry\" onClick={() => retry()()}>\n {t().retry}\n </button>\n )}\n </Show>\n </Match>\n </Switch>\n </div>\n </>\n );\n}\n\n/**\n * One key figure as a framed tile: icon and label, the figure with its change, and a support line with the comparison\n * and the trend. Each state (loading, error, stale, empty) keeps the tile's place and size.\n */\nexport function StatCell(props: StatCellProps): JSX.Element {\n const gridSize = useStatGridSize();\n const size = () => props.size ?? gridSize;\n const surface = useStatGridSurface();\n return (\n <Show\n // A tile that offers a retry is no link: the button must not sit inside it.\n when={props.href && !props.status && !(props.stale && props.onRetry)}\n fallback={\n <div\n class=\"k2b-stat-cell\"\n data-size={size()}\n data-surface={surface}\n data-wrap={props.wrap || undefined}\n data-delta-placement={props.deltaPlacement}\n data-status={props.status}\n aria-busy={props.status === \"loading\" || undefined}\n >\n <Body {...props} />\n </div>\n }\n >\n <a\n href={props.href}\n class=\"k2b-stat-cell k2b-stat-cell--link\"\n data-size={size()}\n data-surface={surface}\n data-wrap={props.wrap || undefined}\n data-delta-placement={props.deltaPlacement}\n >\n <i class=\"ti ti-external-link k2b-stat-cell__link-icon\" aria-hidden=\"true\" />\n <Body {...props} />\n </a>\n </Show>\n );\n}\n\nexport default StatCell;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["surfaces/StatCell.tsx"],"sourcesContent":["import { type JSX, Match, Show, Switch } from \"solid-js\";\nimport type { ChartNumberFormat } from \"../charts/description\";\nimport { ChartSparkline } from \"../content/ChartSparkline\";\nimport type { ChartTooltipFormatter } from \"../content/chart-inspection-core\";\nimport { useLocale } from \"../intl/locale\";\nimport type { AccentColor } from \"../semantics\";\nimport { DeltaBadge } from \"./delta-badge\";\nimport { type StatGridSize, useStatGridSize, useStatGridSurface } from \"./StatGrid\";\nimport { useStatCellMessages } from \"./stat-cell-messages\";\n\nexport type StatCellTone = AccentColor;\n\nexport type StatCellAccent = {\n tone: StatCellTone;\n icon: string;\n text?: string;\n};\n\n/**\n * The change against a comparison period. `unit: \"ratio\"` (default) reads `0.082` as `+8.2 %`; `\"points\"` is the\n * difference of two shares in ratio units, so `0.031` reads `+3.1 pts`. Only with `better` does the badge carry a tone\n * and say \"better\" or \"worse\"; without it the change stays unrated.\n */\nexport type StatCellDelta = {\n value: number;\n unit?: \"ratio\" | \"points\" | \"absolute\";\n /** Existing measures can express a change in their own unit instead of a ratio. */\n format?: ChartNumberFormat;\n better?: \"up\" | \"down\";\n};\n\n/** The value the change compares against, shown under the figure, such as \"Last month 44,560\". */\nexport type StatCellCompare = {\n label: string;\n value: string | number;\n};\n\nexport type StatCellSize = StatGridSize;\n\nexport type StatCellProps = {\n label: string;\n /** The figure. `null` shows the empty dash; `sub` then says why. */\n value: string | number | JSX.Element | null;\n sub?: string;\n valueClass?: string;\n /** An icon in a chip before the label, in `tone`. `\"in\"` and `\"out\"` are the money colours of `FlowAmount`. */\n icon?: string;\n /** The chip colour of `icon`. Defaults to zinc. */\n tone?: StatCellTone | \"in\" | \"out\";\n accent?: StatCellAccent;\n delta?: StatCellDelta;\n /** Keep the figure and change on separate rows, including while loading. Defaults to beside the figure. */\n deltaPlacement?: \"below\";\n compare?: StatCellCompare;\n href?: string;\n title?: string;\n trend?: readonly number[];\n /**\n * Replaces the default trend tooltip in browser code, for example with a period title or a unit.\n * `selection.datum.index` is the source index into `trend`.\n */\n trendTooltip?: ChartTooltipFormatter;\n size?: StatCellSize;\n /**\n * Wraps the label, value and support line instead of truncating them. Use it for a cell whose height nothing\n * reserves, such as one figure on its own; cells compared in a row keep one line each.\n */\n wrap?: boolean;\n /** `\"loading\"` keeps the tile's size with placeholders; `\"error\"` says the figure did not load. */\n status?: \"loading\" | \"error\";\n /** Offers \"Try again\" after an error and \"Reload\" beside `stale`. */\n onRetry?: () => void;\n /** The figure is not current: a short note such as \"As of 09:12 · not current\" replaces the support line. */\n stale?: string;\n};\n\nfunction Body(props: StatCellProps): JSX.Element {\n const gridSize = useStatGridSize();\n const size = () => props.size ?? gridSize;\n const accent = () => props.accent;\n const locale = useLocale();\n const t = useStatCellMessages();\n const defaultTrendTooltip: ChartTooltipFormatter = ({ datum }) => {\n const y = datum.values.find((field) => field.key === \"y\")?.value ?? \"\";\n return {\n rows: [\n { label: props.label, value: typeof y === \"number\" ? new Intl.NumberFormat(locale(), { maximumFractionDigits: 6 }).format(y) : y },\n ],\n };\n };\n const compareValue = () => {\n const value = props.compare?.value;\n return typeof value === \"number\" ? new Intl.NumberFormat(locale()).format(value) : value;\n };\n const empty = () => props.value === null || props.value === undefined || props.value === \"\";\n return (\n <>\n <div class=\"k2b-stat-cell__head\">\n <Show when={props.icon}>\n {(icon) => (\n <span class=\"k2b-stat-cell__icon k2b-icon-tile\" data-tone={props.tone ?? \"zinc\"} aria-hidden=\"true\">\n <i class={icon()} />\n </span>\n )}\n </Show>\n <span class=\"k2b-stat-cell__label\" data-size={size()}>\n {props.label}\n </span>\n </div>\n <div class=\"k2b-stat-cell__main\">\n <Switch\n fallback={\n <>\n <span\n class={`k2b-stat-cell__value ${props.valueClass ?? \"\"}`}\n data-size={size()}\n data-empty={empty() || undefined}\n title={props.title}\n >\n {/* A missing figure is the shared empty dash, named for screen readers instead of read as a dash. */}\n <Show\n when={!empty()}\n fallback={\n <span role=\"img\" aria-label={t().noValue}>\n —\n </span>\n }\n >\n {props.value}\n </Show>\n </span>\n <Show when={!empty() && props.delta}>{(delta) => <DeltaBadge delta={delta()} compare={props.compare} />}</Show>\n </>\n }\n >\n <Match when={props.status === \"loading\"}>\n <span class=\"k2b-stat-cell__skeleton k2b-skeleton\" data-part=\"value\" aria-hidden=\"true\" />\n <span class=\"k2b-sr-only\">{t().loading}</span>\n </Match>\n <Match when={props.status === \"error\"}>\n <span class=\"k2b-stat-cell__error\">\n <i class=\"ti ti-alert-circle\" aria-hidden=\"true\" />\n {t().notLoaded}\n </span>\n </Match>\n </Switch>\n </div>\n <div class=\"k2b-stat-cell__support\">\n <Switch\n fallback={\n <Show\n when={props.stale}\n fallback={\n <>\n <Show when={props.compare}>\n {(compare) => (\n <span class=\"k2b-stat-cell__sub\">\n {compare().label} {compareValue()}\n </span>\n )}\n </Show>\n <Show when={props.sub}>{(sub) => <span class=\"k2b-stat-cell__sub\">{sub()}</span>}</Show>\n <Show when={accent()}>\n {(value) => (\n <Show\n when={value().text}\n fallback={<i class={`${value().icon} k2b-stat-cell__accent-icon`} data-tone={value().tone} aria-hidden=\"true\" />}\n >\n {(text) => (\n <span class=\"k2b-stat-cell__accent\" data-tone={value().tone}>\n <i class={value().icon} aria-hidden=\"true\" />\n {text()}\n </span>\n )}\n </Show>\n )}\n </Show>\n {/* No figure, no trend: an empty tile says why in `sub` and keeps the size of its other states. */}\n <Show when={!empty() && props.trend && props.trend.length > 1}>\n <ChartSparkline\n labels={{ interactiveChart: props.label }}\n tooltip={props.trendTooltip ?? defaultTrendTooltip}\n class=\"k2b-stat-cell__trend\"\n data={Array.from(props.trend ?? [])}\n showLast\n />\n </Show>\n </>\n }\n >\n {(stale) => (\n <>\n <span class=\"k2b-stat-cell__stale\">\n <i class=\"ti ti-clock-exclamation\" aria-hidden=\"true\" />\n {stale()}\n </span>\n <Show when={props.onRetry}>\n {(retry) => (\n <button type=\"button\" class=\"k2b-stat-cell__retry\" onClick={() => retry()()}>\n {t().reload}\n </button>\n )}\n </Show>\n </>\n )}\n </Show>\n }\n >\n <Match when={props.status === \"loading\"}>\n <span class=\"k2b-stat-cell__skeleton k2b-skeleton\" data-part=\"support\" aria-hidden=\"true\" />\n </Match>\n <Match when={props.status === \"error\"}>\n <Show when={props.onRetry}>\n {(retry) => (\n <button type=\"button\" class=\"k2b-stat-cell__retry\" onClick={() => retry()()}>\n {t().retry}\n </button>\n )}\n </Show>\n </Match>\n </Switch>\n </div>\n </>\n );\n}\n\n/**\n * One key figure as a framed tile: icon and label, the figure with its change, and a support line with the comparison\n * and the trend. Each state (loading, error, stale, empty) keeps the tile's place and size.\n */\nexport function StatCell(props: StatCellProps): JSX.Element {\n const gridSize = useStatGridSize();\n const size = () => props.size ?? gridSize;\n const surface = useStatGridSurface();\n return (\n <Show\n // A tile that offers a retry is no link: the button must not sit inside it.\n when={props.href && !props.status && !(props.stale && props.onRetry)}\n fallback={\n <div\n class=\"k2b-stat-cell\"\n data-size={size()}\n data-surface={surface}\n data-wrap={props.wrap || undefined}\n data-delta-placement={props.deltaPlacement}\n data-status={props.status}\n aria-busy={props.status === \"loading\" || undefined}\n >\n <Body {...props} />\n </div>\n }\n >\n <a\n href={props.href}\n class=\"k2b-stat-cell k2b-stat-cell--link\"\n data-size={size()}\n data-surface={surface}\n data-wrap={props.wrap || undefined}\n data-delta-placement={props.deltaPlacement}\n >\n <i class=\"ti ti-external-link k2b-stat-cell__link-icon\" aria-hidden=\"true\" />\n <Body {...props} />\n </a>\n </Show>\n );\n}\n\nexport default StatCell;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAmB,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,UAAU;AAExD,SAAS,cAAc,QAAQ,2BAA2B;AAE1D,SAAS,SAAS,QAAQ,gBAAgB;AAE1C,SAAS,UAAU,QAAQ,eAAe;AAC1C,SAA4B,eAAe,EAAE,kBAAkB,QAAQ,YAAY;AACnF,SAAS,mBAAmB,QAAQ,sBAAsB;;AAU1D;AACA;AACA;AACA;AACA;;AASA;;AA6CA,SAAS,IAAI,CAAC,KAAoB,EAAe;EAC/C,MAAM,QAAQ,GAAG,eAAe,CAAC,CAAC;EAClC,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,IAAI,QAAQ;EACzC,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,MAAM;EACjC,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;EAC1B,MAAM,CAAC,GAAG,mBAAmB,CAAC,CAAC;EAC/B,MAAM,mBAA0C,GAAG,CAAC;IAAE;EAAM,CAAC,KAAK;IAChE,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAE,KAAK,IAAK,KAAK,CAAC,GAAG,KAAK,GAAG,CAAC,EAAE,KAAK,IAAI,EAAE;IACtE,OAAO;MACL,IAAI,EAAE,CACJ;QAAE,KAAK,EAAE,KAAK,CAAC,KAAK;QAAE,KAAK,EAAE,OAAO,CAAC,KAAK,QAAQ,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,EAAE;UAAE,qBAAqB,EAAE;QAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG;MAAE,CAAC;IAEtI,CAAC;EACH,CAAC;EACD,MAAM,YAAY,GAAG,MAAM;IACzB,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,KAAK;IAClC,OAAO,OAAO,KAAK,KAAK,QAAQ,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK;EAC1F,CAAC;EACD,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,EAAE;EAC3F;IAAA;MAAA;MAAA;MAAA;IAAA,iCAGO,IAAI;MAAA,IAAC,IAAI;QAAA,OAAE,KAAK,CAAC,IAAI;MAAA;MAAA,UAClB,IAAI;QAAA;UAAA;QAAA;UAAA,UACuD,KAAK,CAAC,IAAI,IAAI,MAAM;YAAA,OACnE,IAAI,CAAC,CAAC;UAAA;UAAA;UAAA;QAAA;UAAA;UAAA;QAAA;QAAA;MAAA;IAEnB;IAAA,sBAGA,KAAK,CAAC,KAAK;IAAA,kDADgC,IAAI,CAAC,CAAC;IAAA;EAAA;IAAA;IAAA,kCAKnD,MAAM;MAAA,IACL,QAAQ;QAAA;UAAA;UAAA,mCASD,IAAI;YAAA,IACH,IAAI;cAAA,OAAE,CAAC,KAAK,CAAC,CAAC;YAAA;YAAA,IACd,QAAQ;cAAA;gBAAA;gBAAA,oDACuB,CAAC,CAAC,CAAC,CAAC,OAAO;gBAAA;cAAA;YAAA;YAAA;cAAA,OAKzC,KAAK,CAAC,KAAK;YAAA;UAAA;UAAA;YAAA,WAdP,wBAAwB,KAAK,CAAC,UAAU,IAAI,EAAE,EAAE;cAAA,OAC5C,IAAI,CAAC,CAAC;cAAA,OACL,KAAK,CAAC,CAAC,IAAI,SAAS;cAAA,OACzB,KAAK,CAAC,KAAK;YAAA;YAAA;YAAA;YAAA;YAAA;UAAA;YAAA;YAAA;YAAA;YAAA;UAAA;UAAA;QAAA,wBAcnB,IAAI;UAAA,IAAC,IAAI;YAAA,OAAE,gBAAC,KAAK,CAAC,CAAC,OAAI,KAAK,CAAC,KAAK;UAAA;UAAA,UAAI,KAAK,sBAAM,UAAU;YAAA,IAAC,KAAK;cAAA,OAAE,KAAK,CAAC,CAAC;YAAA;YAAA,IAAE,OAAO;cAAA,OAAE,KAAK,CAAC,OAAO;YAAA;UAAA;QAAI;MAAA;MAAA;QAAA,0BAI1G,KAAK;UAAA,IAAC,IAAI;YAAA,OAAE,KAAK,CAAC,MAAM,KAAK,SAAS;UAAA;UAAA;YAAA;cAAA;cAAA,sBAEV,CAAC,CAAC,CAAC,CAAC,OAAO;cAAA;YAAA;UAAA;QAAA,sBAEvC,KAAK;UAAA,IAAC,IAAI;YAAA,OAAE,KAAK,CAAC,MAAM,KAAK,OAAO;UAAA;UAAA;YAAA;cAAA;cAAA;cAAA;YAAA,sBAGhC,CAAC,CAAC,CAAC,CAAC,SAAS;YAAA;UAAA;QAAA;MAAA;IAAA;IAAA;EAAA;IAAA;IAAA,mCAMnB,MAAM;MAAA,IACL,QAAQ;QAAA,yBACL,IAAI;UAAA,IACH,IAAI;YAAA,OAAE,KAAK,CAAC,KAAK;UAAA;UAAA,IACjB,QAAQ;YAAA,0BAEH,IAAI;cAAA,IAAC,IAAI;gBAAA,OAAE,KAAK,CAAC,OAAO;cAAA;cAAA,UACrB,OAAO;gBAAA;kBAAA;kBAAA;kBAAA;kBAAA;kBAAA;gBAAA,uBAEJ,OAAO,CAAC,CAAC,CAAC,KAAK;gBAAA,iBAAG,YAAY;gBAAA;cAAA;YAElC,sBAEF,IAAI;cAAA,IAAC,IAAI;gBAAA,OAAE,KAAK,CAAC,GAAG;cAAA;cAAA,UAAI,GAAG;gBAAA;gBAAA,iBAAuC,GAAG;gBAAA;cAAA;YAAU,sBAC/E,IAAI;cAAA,IAAC,IAAI;gBAAA,OAAE,MAAM,CAAC,CAAC;cAAA;cAAA,UAChB,KAAK,sBACJ,IAAI;gBAAA,IACH,IAAI;kBAAA,OAAE,KAAK,CAAC,CAAC,CAAC,IAAI;gBAAA;gBAAA,IAClB,QAAQ;kBAAA;oBAAA;oBAAA;sBAAA,WAAY,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,6BAA6B;wBAAA,OAAa,KAAK,CAAC,CAAC,CAAC,IAAI;sBAAA;sBAAA;sBAAA;oBAAA;sBAAA;sBAAA;oBAAA;oBAAA;kBAAA;gBAAA;gBAAA,UAEvF,IAAI;kBAAA;oBAAA;oBAAA;oBAAA;kBAAA,iBAGD,IAAI;kBAAA;oBAAA,WAFwC,KAAK,CAAC,CAAC,CAAC,IAAI;sBAAA,OAC/C,KAAK,CAAC,CAAC,CAAC,IAAI;oBAAA;oBAAA;oBAAA;kBAAA;oBAAA;oBAAA;kBAAA;kBAAA;gBAAA;cAGzB;YAEJ,sBAGF,IAAI;cAAA,IAAC,IAAI;gBAAA,OAAE,iBAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,KAAK,QAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;cAAA;cAAA;gBAAA,yBAC1D,cAAc;kBAAA,IACb,MAAM;oBAAA,OAAE;sBAAE,gBAAgB,EAAE,KAAK,CAAC;oBAAM,CAAC;kBAAA;kBAAA,IACzC,OAAO;oBAAA,OAAE,KAAK,CAAC,YAAY,IAAI,mBAAmB;kBAAA;kBAAA;kBAAA,IAElD,IAAI;oBAAA,OAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;kBAAA;kBACnC,QAAQ;gBAAA;cAAA;YAAA;UAAA;UAAA,UAMd,KAAK;YAAA;cAAA;cAAA;cAAA;YAAA,iBAIA,KAAK;YAAA;UAAA,wBAEP,IAAI;YAAA,IAAC,IAAI;cAAA,OAAE,KAAK,CAAC,OAAO;YAAA;YAAA,UACrB,KAAK;cAAA;cAAA,iBACuD,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;cAAA,uBACxE,CAAC,CAAC,CAAC,CAAC,MAAM;cAAA;cAAA;YAAA;UAEd;QAGN;MAAA;MAAA;QAAA,0BAIJ,KAAK;UAAA,IAAC,IAAI;YAAA,OAAE,KAAK,CAAC,MAAM,KAAK,SAAS;UAAA;UAAA;YAAA;UAAA;QAAA,sBAGtC,KAAK;UAAA,IAAC,IAAI;YAAA,OAAE,KAAK,CAAC,MAAM,KAAK,OAAO;UAAA;UAAA;YAAA,yBAClC,IAAI;cAAA,IAAC,IAAI;gBAAA,OAAE,KAAK,CAAC,OAAO;cAAA;cAAA,UACrB,KAAK;gBAAA;gBAAA,iBACuD,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;gBAAA,uBACxE,CAAC,CAAC,CAAC,CAAC,KAAK;gBAAA;gBAAA;cAAA;YAEb;UAAA;QAAA;MAAA;IAAA;IAAA;EAAA;AAOf;;AAEA;AACA;AACA;AACA;AACA,OAAO,SAAS,QAAQ,CAAC,KAAoB,EAAe;EAC1D,MAAM,QAAQ,GAAG,eAAe,CAAC,CAAC;EAClC,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,IAAI,QAAQ;EACzC,MAAM,OAAO,GAAG,kBAAkB,CAAC,CAAC;EACpC,yBACG;EACC;EAAA;IAAA,IACA,IAAI;MAAA,OAAE,qBAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,QAAI,EAAE,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC;IAAA;IAAA,IACpE,QAAQ;MAAA;QAAA;QAAA,uCAIU,OAAO;QAAA,mCAMpB,IAAI,EAAK,KAAK;QAAA;UAAA,YAPJ,IAAI,CAAC,CAAC;YAAA,QAEN,KAAK,CAAC,IAAI,IAAI,SAAS;YAAA,QACZ,KAAK,CAAC,cAAc;YAAA,QAC7B,KAAK,CAAC,MAAM;YAAA,QACd,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,SAAS;UAAA;UAAA;UAAA;UAAA;UAAA;UAAA;QAAA;UAAA;UAAA;UAAA;UAAA;UAAA;QAAA;QAAA;MAAA;IAAA;IAAA;MAAA;QAAA;QAAA;QAAA;MAAA,uCAUtC,OAAO;MAAA,mCAKpB,IAAI,EAAK,KAAK;MAAA;QAAA,WART,KAAK,CAAC,IAAI;UAAA,QAEL,IAAI,CAAC,CAAC;UAAA,QAEN,KAAK,CAAC,IAAI,IAAI,SAAS;UAAA,QACZ,KAAK,CAAC,cAAc;QAAA;QAAA;QAAA;QAAA;QAAA;MAAA;QAAA;QAAA;QAAA;QAAA;MAAA;MAAA;IAAA;EAAA;AAOlD;AAEA,eAAe,QAAQ;AAAC","ignoreList":[]}
@@ -13,7 +13,8 @@ const statCellMessages = i18n.define({
13
13
  notLoaded: "Not loaded",
14
14
  retry: "Try again",
15
15
  reload: "Reload",
16
- loading: "Loading"
16
+ loading: "Loading",
17
+ noValue: "No value"
17
18
  },
18
19
  de: {
19
20
  points: "Pkt.",
@@ -25,7 +26,8 @@ const statCellMessages = i18n.define({
25
26
  notLoaded: "Nicht geladen",
26
27
  retry: "Erneut versuchen",
27
28
  reload: "Neu laden",
28
- loading: "Wird geladen"
29
+ loading: "Wird geladen",
30
+ noValue: "Kein Wert"
29
31
  }
30
32
  }
31
33
  });
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["surfaces/stat-cell-messages.ts"],"sourcesContent":["import { i18n } from \"@k2b/stdlib\";\nimport { useLocale } from \"../intl/locale\";\n\nconst statCellMessages = i18n.define({\n baseLocale: \"en\",\n messages: {\n en: {\n points: \"pts\",\n better: \"better\",\n worse: \"worse\",\n comparedWith: ({ label }: { label: string }) => `compared with ${label}`,\n notLoaded: \"Not loaded\",\n retry: \"Try again\",\n reload: \"Reload\",\n loading: \"Loading\",\n },\n de: {\n points: \"Pkt.\",\n better: \"besser\",\n worse: \"schlechter\",\n comparedWith: ({ label }: { label: string }) => `gegenüber ${label}`,\n notLoaded: \"Nicht geladen\",\n retry: \"Erneut versuchen\",\n reload: \"Neu laden\",\n loading: \"Wird geladen\",\n },\n },\n});\n\nexport type StatCellMessages = ReturnType<(typeof statCellMessages)[\"resolve\"]>[\"t\"];\n\n/** Resolved from the inherited render locale. */\nexport const useStatCellMessages = (): (() => StatCellMessages) => {\n const locale = useLocale();\n return () => statCellMessages.resolve([locale()]).t;\n};\n\n/** For a caller that already holds the locale, such as table text for search and copy. */\nexport const resolveStatCellMessages = (locale: string): StatCellMessages => statCellMessages.resolve([locale]).t;\n\nexport const checkStatCellMessages = () => statCellMessages.check();\n"],"mappings":"AAAA,SAAS,IAAI,QAAQ,aAAa;AAClC,SAAS,SAAS,QAAQ,gBAAgB;AAE1C,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC;EACnC,UAAU,EAAE,IAAI;EAChB,QAAQ,EAAE;IACR,EAAE,EAAE;MACF,MAAM,EAAE,KAAK;MACb,MAAM,EAAE,QAAQ;MAChB,KAAK,EAAE,OAAO;MACd,YAAY,EAAE,CAAC;QAAE;MAAyB,CAAC,KAAK,iBAAiB,KAAK,EAAE;MACxE,SAAS,EAAE,YAAY;MACvB,KAAK,EAAE,WAAW;MAClB,MAAM,EAAE,QAAQ;MAChB,OAAO,EAAE;IACX,CAAC;IACD,EAAE,EAAE;MACF,MAAM,EAAE,MAAM;MACd,MAAM,EAAE,QAAQ;MAChB,KAAK,EAAE,YAAY;MACnB,YAAY,EAAE,CAAC;QAAE;MAAyB,CAAC,KAAK,aAAa,KAAK,EAAE;MACpE,SAAS,EAAE,eAAe;MAC1B,KAAK,EAAE,kBAAkB;MACzB,MAAM,EAAE,WAAW;MACnB,OAAO,EAAE;IACX;EACF;AACF,CAAC,CAAC;AAIF;AACA,OAAO,MAAM,mBAAmB,GAAG,MAAgC;EACjE,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;EAC1B,OAAO,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC;;AAED;AACA,OAAO,MAAM,uBAAuB,GAAI,MAAc,IAAuB,gBAAgB,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAEjH,OAAO,MAAM,qBAAqB,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["surfaces/stat-cell-messages.ts"],"sourcesContent":["import { i18n } from \"@k2b/stdlib\";\nimport { useLocale } from \"../intl/locale\";\n\nconst statCellMessages = i18n.define({\n baseLocale: \"en\",\n messages: {\n en: {\n points: \"pts\",\n better: \"better\",\n worse: \"worse\",\n comparedWith: ({ label }: { label: string }) => `compared with ${label}`,\n notLoaded: \"Not loaded\",\n retry: \"Try again\",\n reload: \"Reload\",\n loading: \"Loading\",\n noValue: \"No value\",\n },\n de: {\n points: \"Pkt.\",\n better: \"besser\",\n worse: \"schlechter\",\n comparedWith: ({ label }: { label: string }) => `gegenüber ${label}`,\n notLoaded: \"Nicht geladen\",\n retry: \"Erneut versuchen\",\n reload: \"Neu laden\",\n loading: \"Wird geladen\",\n noValue: \"Kein Wert\",\n },\n },\n});\n\nexport type StatCellMessages = ReturnType<(typeof statCellMessages)[\"resolve\"]>[\"t\"];\n\n/** Resolved from the inherited render locale. */\nexport const useStatCellMessages = (): (() => StatCellMessages) => {\n const locale = useLocale();\n return () => statCellMessages.resolve([locale()]).t;\n};\n\n/** For a caller that already holds the locale, such as table text for search and copy. */\nexport const resolveStatCellMessages = (locale: string): StatCellMessages => statCellMessages.resolve([locale]).t;\n\nexport const checkStatCellMessages = () => statCellMessages.check();\n"],"mappings":"AAAA,SAAS,IAAI,QAAQ,aAAa;AAClC,SAAS,SAAS,QAAQ,gBAAgB;AAE1C,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC;EACnC,UAAU,EAAE,IAAI;EAChB,QAAQ,EAAE;IACR,EAAE,EAAE;MACF,MAAM,EAAE,KAAK;MACb,MAAM,EAAE,QAAQ;MAChB,KAAK,EAAE,OAAO;MACd,YAAY,EAAE,CAAC;QAAE;MAAyB,CAAC,KAAK,iBAAiB,KAAK,EAAE;MACxE,SAAS,EAAE,YAAY;MACvB,KAAK,EAAE,WAAW;MAClB,MAAM,EAAE,QAAQ;MAChB,OAAO,EAAE,SAAS;MAClB,OAAO,EAAE;IACX,CAAC;IACD,EAAE,EAAE;MACF,MAAM,EAAE,MAAM;MACd,MAAM,EAAE,QAAQ;MAChB,KAAK,EAAE,YAAY;MACnB,YAAY,EAAE,CAAC;QAAE;MAAyB,CAAC,KAAK,aAAa,KAAK,EAAE;MACpE,SAAS,EAAE,eAAe;MAC1B,KAAK,EAAE,kBAAkB;MACzB,MAAM,EAAE,WAAW;MACnB,OAAO,EAAE,cAAc;MACvB,OAAO,EAAE;IACX;EACF;AACF,CAAC,CAAC;AAIF;AACA,OAAO,MAAM,mBAAmB,GAAG,MAAgC;EACjE,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;EAC1B,OAAO,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC;;AAED;AACA,OAAO,MAAM,uBAAuB,GAAI,MAAc,IAAuB,gBAAgB,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAEjH,OAAO,MAAM,qBAAqB,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC","ignoreList":[]}
@@ -12,7 +12,7 @@ import { runHydrationEvents as _$runHydrationEvents } from "solid-js/web";
12
12
  import { insert as _$insert } from "solid-js/web";
13
13
  var _tmpl$ = /*#__PURE__*/_$template(`<button type=button class=k2b-dashboard-frame__link>`),
14
14
  _tmpl$2 = /*#__PURE__*/_$template(`<div class=k2b-dashboard-frame__tools>`),
15
- _tmpl$3 = /*#__PURE__*/_$template(`<header class=k2b-dashboard-frame__header><div><!$><!/><p role=status><!$><!/><!$><!/></p></div><!$><!/>`),
15
+ _tmpl$3 = /*#__PURE__*/_$template(`<header class=k2b-dashboard-frame__header><div><!$><!/><p role=status></p></div><!$><!/>`),
16
16
  _tmpl$4 = /*#__PURE__*/_$template(`<div class=k2b-dashboard-frame__content>`),
17
17
  _tmpl$5 = /*#__PURE__*/_$template(`<div class=k2b-dashboard-frame__stack><div class=k2b-dashboard-frame__reserve aria-hidden=true inert></div><!$><!/>`),
18
18
  _tmpl$6 = /*#__PURE__*/_$template(`<div class=k2b-dashboard-frame__skeleton aria-hidden=true><span></span><span>`),
@@ -90,15 +90,11 @@ export function DashboardFrame(props) {
90
90
  return [(() => {
91
91
  var _el$2 = _$getNextElement(_tmpl$3),
92
92
  _el$3 = _el$2.firstChild,
93
- _el$9 = _el$3.firstChild,
94
- [_el$0, _co$3] = _$getNextMarker(_el$9.nextSibling),
95
- _el$4 = _el$0.nextSibling,
96
- _el$5 = _el$4.firstChild,
93
+ _el$5 = _el$3.firstChild,
97
94
  [_el$6, _co$] = _$getNextMarker(_el$5.nextSibling),
98
- _el$7 = _el$6.nextSibling,
99
- [_el$8, _co$2] = _$getNextMarker(_el$7.nextSibling),
100
- _el$10 = _el$3.nextSibling,
101
- [_el$11, _co$4] = _$getNextMarker(_el$10.nextSibling);
95
+ _el$4 = _el$6.nextSibling,
96
+ _el$8 = _el$3.nextSibling,
97
+ [_el$9, _co$2] = _$getNextMarker(_el$8.nextSibling);
102
98
  _$insert(_el$3, _$createComponent(Dynamic, {
103
99
  get component() {
104
100
  return `h${props.headingLevel ?? 3}`;
@@ -106,26 +102,21 @@ export function DashboardFrame(props) {
106
102
  get children() {
107
103
  return props.title;
108
104
  }
109
- }), _el$0, _co$3);
110
- _$insert(_el$4, status, _el$6, _co$);
111
- _$insert(_el$4, _$createComponent(Show, {
112
- get when() {
113
- return _$memo(() => state() === "stale")() && props.onRetry;
114
- },
115
- get children() {
116
- return [" · ", _$memo(() => retryLink())];
117
- }
118
- }), _el$8, _co$2);
105
+ }), _el$6, _co$);
106
+ _$insert(_el$4, (() => {
107
+ var _c$ = _$memo(() => !!(state() === "stale" && props.onRetry));
108
+ return () => _c$() ? [status(), " · ", retryLink()] : status();
109
+ })());
119
110
  _$insert(_el$2, _$createComponent(Show, {
120
111
  get when() {
121
112
  return tools() !== undefined;
122
113
  },
123
114
  get children() {
124
- var _el$1 = _$getNextElement(_tmpl$2);
125
- _$insert(_el$1, tools);
126
- return _el$1;
115
+ var _el$7 = _$getNextElement(_tmpl$2);
116
+ _$insert(_el$7, tools);
117
+ return _el$7;
127
118
  }
128
- }), _el$11, _co$4);
119
+ }), _el$9, _co$2);
129
120
  _$effect(() => _$className(_el$4, state() === "stale" ? "k2b-dashboard-frame__stale" : undefined));
130
121
  return _el$2;
131
122
  })(), _$createComponent(Show, {
@@ -134,8 +125,8 @@ export function DashboardFrame(props) {
134
125
  },
135
126
  get fallback() {
136
127
  return (() => {
137
- var _el$17 = _$getNextElement(_tmpl$8);
138
- _$insert(_el$17, _$createComponent(Switch, {
128
+ var _el$13 = _$getNextElement(_tmpl$8);
129
+ _$insert(_el$13, _$createComponent(Switch, {
139
130
  get fallback() {
140
131
  return props.children;
141
132
  },
@@ -152,45 +143,45 @@ export function DashboardFrame(props) {
152
143
  return _$memo(() => !!(failed() || empty()))() && props.compact;
153
144
  },
154
145
  get children() {
155
- var _el$19 = _$getNextElement(_tmpl$7),
156
- _el$20 = _el$19.firstChild,
146
+ var _el$15 = _$getNextElement(_tmpl$7),
147
+ _el$16 = _el$15.firstChild,
148
+ _el$17 = _el$16.nextSibling,
149
+ [_el$18, _co$4] = _$getNextMarker(_el$17.nextSibling),
150
+ _el$19 = _el$18.nextSibling,
151
+ [_el$20, _co$5] = _$getNextMarker(_el$19.nextSibling),
157
152
  _el$21 = _el$20.nextSibling,
158
- [_el$22, _co$6] = _$getNextMarker(_el$21.nextSibling),
159
- _el$23 = _el$22.nextSibling,
160
- [_el$24, _co$7] = _$getNextMarker(_el$23.nextSibling),
161
- _el$25 = _el$24.nextSibling,
162
- [_el$26, _co$8] = _$getNextMarker(_el$25.nextSibling);
163
- _$insert(_el$19, (() => {
164
- var _c$ = _$memo(() => !!failed());
165
- return () => _c$() ? chart().chartLoadFailed : sentence();
166
- })(), _el$22, _co$6);
167
- _$insert(_el$19, _$createComponent(Show, {
153
+ [_el$22, _co$6] = _$getNextMarker(_el$21.nextSibling);
154
+ _$insert(_el$15, (() => {
155
+ var _c$2 = _$memo(() => !!failed());
156
+ return () => _c$2() ? chart().chartLoadFailed : sentence();
157
+ })(), _el$18, _co$4);
158
+ _$insert(_el$15, _$createComponent(Show, {
168
159
  get when() {
169
160
  return _$memo(() => !!failed())() && props.onRetry;
170
161
  },
171
162
  get children() {
172
163
  return retryLink();
173
164
  }
174
- }), _el$24, _co$7);
175
- _$insert(_el$19, _$createComponent(Show, {
165
+ }), _el$20, _co$5);
166
+ _$insert(_el$15, _$createComponent(Show, {
176
167
  get when() {
177
168
  return empty();
178
169
  },
179
170
  get children() {
180
171
  return props.emptyAction;
181
172
  }
182
- }), _el$26, _co$8);
173
+ }), _el$22, _co$6);
183
174
  _$effect(_p$ => {
184
- var _v$ = failed() ? "alert" : undefined,
185
- _v$2 = failed() ? "ti ti-alert-circle" : props.emptyIcon ?? "ti ti-chart-bar-off";
186
- _v$ !== _p$.e && _$setAttribute(_el$19, "role", _p$.e = _v$);
187
- _v$2 !== _p$.t && _$className(_el$20, _p$.t = _v$2);
175
+ var _v$4 = failed() ? "alert" : undefined,
176
+ _v$5 = failed() ? "ti ti-alert-circle" : props.emptyIcon ?? "ti ti-chart-bar-off";
177
+ _v$4 !== _p$.e && _$setAttribute(_el$15, "role", _p$.e = _v$4);
178
+ _v$5 !== _p$.t && _$className(_el$16, _p$.t = _v$5);
188
179
  return _p$;
189
180
  }, {
190
181
  e: undefined,
191
182
  t: undefined
192
183
  });
193
- return _el$19;
184
+ return _el$15;
194
185
  }
195
186
  }), _$createComponent(Match, {
196
187
  get when() {
@@ -203,27 +194,27 @@ export function DashboardFrame(props) {
203
194
  }
204
195
  }));
205
196
  _$effect(_p$ => {
206
- var _v$3 = props.height ? {
197
+ var _v$6 = props.height ? {
207
198
  height: props.height
208
199
  } : undefined,
209
- _v$4 = busy();
210
- _p$.e = _$style(_el$17, _v$3, _p$.e);
211
- _v$4 !== _p$.t && _$setAttribute(_el$17, "aria-busy", _p$.t = _v$4);
200
+ _v$7 = busy();
201
+ _p$.e = _$style(_el$13, _v$6, _p$.e);
202
+ _v$7 !== _p$.t && _$setAttribute(_el$13, "aria-busy", _p$.t = _v$7);
212
203
  return _p$;
213
204
  }, {
214
205
  e: undefined,
215
206
  t: undefined
216
207
  });
217
- return _el$17;
208
+ return _el$13;
218
209
  })();
219
210
  },
220
211
  get children() {
221
- var _el$12 = _$getNextElement(_tmpl$5),
222
- _el$13 = _el$12.firstChild,
223
- _el$15 = _el$13.nextSibling,
224
- [_el$16, _co$5] = _$getNextMarker(_el$15.nextSibling);
225
- _$insert(_el$13, reserve);
226
- _$insert(_el$12, _$createComponent(Show, {
212
+ var _el$0 = _$getNextElement(_tmpl$5),
213
+ _el$1 = _el$0.firstChild,
214
+ _el$11 = _el$1.nextSibling,
215
+ [_el$12, _co$3] = _$getNextMarker(_el$11.nextSibling);
216
+ _$insert(_el$1, reserve);
217
+ _$insert(_el$0, _$createComponent(Show, {
227
218
  get when() {
228
219
  return shown();
229
220
  },
@@ -231,13 +222,27 @@ export function DashboardFrame(props) {
231
222
  return _$createComponent(Message, {});
232
223
  },
233
224
  get children() {
234
- var _el$14 = _$getNextElement(_tmpl$4);
235
- _$insert(_el$14, () => props.children);
236
- return _el$14;
225
+ var _el$10 = _$getNextElement(_tmpl$4);
226
+ _$insert(_el$10, () => props.children);
227
+ return _el$10;
237
228
  }
238
- }), _el$16, _co$5);
239
- _$effect(() => _$setAttribute(_el$12, "aria-busy", busy()));
240
- return _el$12;
229
+ }), _el$12, _co$3);
230
+ _$effect(_p$ => {
231
+ var _v$ = props.height ? "" : undefined,
232
+ _v$2 = props.height ? {
233
+ height: props.height
234
+ } : undefined,
235
+ _v$3 = busy();
236
+ _v$ !== _p$.e && _$setAttribute(_el$0, "data-height", _p$.e = _v$);
237
+ _p$.t = _$style(_el$0, _v$2, _p$.t);
238
+ _v$3 !== _p$.a && _$setAttribute(_el$0, "aria-busy", _p$.a = _v$3);
239
+ return _p$;
240
+ }, {
241
+ e: undefined,
242
+ t: undefined,
243
+ a: undefined
244
+ });
245
+ return _el$0;
241
246
  }
242
247
  })];
243
248
  }
@@ -246,30 +251,30 @@ export function DashboardFrame(props) {
246
251
  });
247
252
  function Message() {
248
253
  return (() => {
249
- var _el$27 = _$getNextElement(_tmpl$1),
250
- _el$32 = _el$27.firstChild,
251
- [_el$33, _co$9] = _$getNextMarker(_el$32.nextSibling),
252
- _el$30 = _el$33.nextSibling,
253
- _el$34 = _el$30.nextSibling,
254
- [_el$35, _co$0] = _$getNextMarker(_el$34.nextSibling),
255
- _el$36 = _el$35.nextSibling,
256
- [_el$37, _co$1] = _$getNextMarker(_el$36.nextSibling);
257
- _$insert(_el$27, _$createComponent(Show, {
254
+ var _el$23 = _$getNextElement(_tmpl$1),
255
+ _el$28 = _el$23.firstChild,
256
+ [_el$29, _co$7] = _$getNextMarker(_el$28.nextSibling),
257
+ _el$26 = _el$29.nextSibling,
258
+ _el$30 = _el$26.nextSibling,
259
+ [_el$31, _co$8] = _$getNextMarker(_el$30.nextSibling),
260
+ _el$32 = _el$31.nextSibling,
261
+ [_el$33, _co$9] = _$getNextMarker(_el$32.nextSibling);
262
+ _$insert(_el$23, _$createComponent(Show, {
258
263
  get when() {
259
264
  return state() !== "loading";
260
265
  },
261
266
  get children() {
262
- var _el$28 = _$getNextElement(_tmpl$9),
263
- _el$29 = _el$28.firstChild;
264
- _$effect(() => _$className(_el$29, failed() ? "ti ti-alert-circle" : props.emptyIcon ?? "ti ti-chart-bar-off"));
265
- return _el$28;
267
+ var _el$24 = _$getNextElement(_tmpl$9),
268
+ _el$25 = _el$24.firstChild;
269
+ _$effect(() => _$className(_el$25, failed() ? "ti ti-alert-circle" : props.emptyIcon ?? "ti ti-chart-bar-off"));
270
+ return _el$24;
266
271
  }
267
- }), _el$33, _co$9);
268
- _$insert(_el$30, (() => {
269
- var _c$2 = _$memo(() => !!failed());
270
- return () => _c$2() ? chart().chartLoadFailed : _$memo(() => state() === "loading")() ? "" : sentence();
272
+ }), _el$29, _co$7);
273
+ _$insert(_el$26, (() => {
274
+ var _c$3 = _$memo(() => !!failed());
275
+ return () => _c$3() ? chart().chartLoadFailed : _$memo(() => state() === "loading")() ? "" : sentence();
271
276
  })());
272
- _$insert(_el$27, _$createComponent(Show, {
277
+ _$insert(_el$23, _$createComponent(Show, {
273
278
  get when() {
274
279
  return _$memo(() => !!failed())() && props.onRetry;
275
280
  },
@@ -283,26 +288,26 @@ export function DashboardFrame(props) {
283
288
  }
284
289
  });
285
290
  }
286
- }), _el$35, _co$0);
287
- _$insert(_el$27, _$createComponent(Show, {
291
+ }), _el$31, _co$8);
292
+ _$insert(_el$23, _$createComponent(Show, {
288
293
  get when() {
289
294
  return empty();
290
295
  },
291
296
  get children() {
292
297
  return props.emptyAction;
293
298
  }
294
- }), _el$37, _co$1);
299
+ }), _el$33, _co$9);
295
300
  _$effect(_p$ => {
296
- var _v$5 = state(),
297
- _v$6 = failed() ? "alert" : undefined;
298
- _v$5 !== _p$.e && _$setAttribute(_el$27, "data-state", _p$.e = _v$5);
299
- _v$6 !== _p$.t && _$setAttribute(_el$27, "role", _p$.t = _v$6);
301
+ var _v$8 = state(),
302
+ _v$9 = failed() ? "alert" : undefined;
303
+ _v$8 !== _p$.e && _$setAttribute(_el$23, "data-state", _p$.e = _v$8);
304
+ _v$9 !== _p$.t && _$setAttribute(_el$23, "role", _p$.t = _v$9);
300
305
  return _p$;
301
306
  }, {
302
307
  e: undefined,
303
308
  t: undefined
304
309
  });
305
- return _el$27;
310
+ return _el$23;
306
311
  })();
307
312
  }
308
313
  }
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["widgets/DashboardFrame.tsx"],"sourcesContent":["import { children, type JSX, Match, Show, Switch } from \"solid-js\";\nimport { Dynamic } from \"solid-js/web\";\nimport { Button } from \"../actions/Button\";\nimport { useChartMessages } from \"../content/chart-messages\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { Paper } from \"../surfaces/Paper\";\nimport type { DashboardWidth } from \"./Dashboard\";\n\n/**\n * What the host's read shows: its content (`ready`), the first read in flight (`loading`), nothing to show (`empty`),\n * a failed first read (`error`), or content whose refresh failed (`stale`).\n */\nexport type DashboardFrameState = \"ready\" | \"loading\" | \"empty\" | \"error\" | \"stale\";\n\nexport type DashboardFrameProps = {\n /**\n * Heading of the frame. Without it the frame is only the surface, for content that brings its own head and states,\n * such as `ChartExplorer` with `inset=\"1rem\"`.\n */\n title?: string;\n /** One line under the title; loading and stale notes take its place, so nothing moves. */\n subtitle?: JSX.Element;\n /** Level of the title heading; defaults to 3. */\n headingLevel?: 2 | 3 | 4 | 5 | 6;\n /** Controls at the right of the head, such as a search field or a grouping chip. */\n tools?: JSX.Element;\n /** Defaults to `ready`. */\n state?: DashboardFrameState;\n /** When the shown content was read, formatted by the host (\"09:12\"); a stale note names it. */\n asOf?: string;\n /** Try again after a failure; without it a failure has no button. */\n onRetry?: () => void;\n /** The empty sentence, such as \"No campaign in this period.\" */\n empty?: JSX.Element;\n /** Tabler icon of the empty state; defaults to `ti ti-chart-bar-off`. */\n emptyIcon?: string;\n /** An action under the empty sentence, such as \"Clear search\". */\n emptyAction?: JSX.Element;\n /**\n * The content has nothing to show right now although the read succeeded, such as a search without matches: the body\n * shows the empty sentence and action while the head keeps its state, so a stale note stays.\n */\n emptyContent?: boolean;\n /** Height of the body, a CSS length. Every state keeps it. */\n height?: string;\n /**\n * A hidden copy of the full content that holds the body's height in every state, such as every row of a table. The\n * body then reaches the frame's left, right and bottom edges, like a table that brings its own rows.\n */\n reserve?: JSX.Element;\n /** States as one quiet line instead of a centred message, for short content such as an amount or one bar. */\n compact?: boolean;\n /**\n * Share of a `DashboardSection`'s six columns, like `DashboardPanel`: the frame is the grid cell itself, so it never\n * sits in a second frame. Defaults to a third there; ignored elsewhere.\n */\n width?: DashboardWidth;\n class?: string;\n children?: JSX.Element;\n};\n\n/**\n * One framed dashboard panel: title, subtitle, tools and the content the host passes, with loading, empty, failure and\n * stale in the same place and at the same height.\n */\nexport function DashboardFrame(props: DashboardFrameProps): JSX.Element {\n const ui = useUiMessages();\n const chart = useChartMessages();\n const state = () => props.state ?? \"ready\";\n const failed = () => state() === \"error\";\n const read = () => state() === \"ready\" || state() === \"stale\";\n const shown = () => read() && !props.emptyContent;\n const empty = () => state() === \"empty\" || (read() && props.emptyContent === true);\n // Slots resolve once: checking a slot and then rendering it must not mount its components twice.\n const tools = children(() => props.tools);\n const reserve = children(() => props.reserve);\n const busy = () => (state() === \"loading\" ? \"true\" : undefined);\n const className = () => (props.class ? `k2b-dashboard-frame ${props.class}` : \"k2b-dashboard-frame\");\n const retryLink = () => (\n <button type=\"button\" class=\"k2b-dashboard-frame__link\" onClick={() => props.onRetry?.()}>\n {ui().tryAgain}\n </button>\n );\n const status = () =>\n state() === \"loading\"\n ? chart().chartLoading\n : state() === \"stale\"\n ? [props.asOf ? chart().chartAsOf({ time: props.asOf }) : undefined, chart().chartRefreshFailed].filter(Boolean).join(\" · \")\n : props.subtitle;\n const sentence = () => props.empty ?? ui().noData;\n return (\n <Show\n when={props.title !== undefined}\n fallback={\n <Paper class={className()} data-width={props.width ?? \"third\"}>\n {props.children}\n </Paper>\n }\n >\n <Paper class={className()} data-width={props.width ?? \"third\"}>\n <header class=\"k2b-dashboard-frame__header\">\n <div>\n <Dynamic component={`h${props.headingLevel ?? 3}`}>{props.title}</Dynamic>\n {/* One reserved line and a polite live region: loading and stale replace the subtitle without moving. */}\n <p role=\"status\" class={state() === \"stale\" ? \"k2b-dashboard-frame__stale\" : undefined}>\n {status()}\n <Show when={state() === \"stale\" && props.onRetry}>\n {\" · \"}\n {retryLink()}\n </Show>\n </p>\n </div>\n <Show when={tools() !== undefined}>\n <div class=\"k2b-dashboard-frame__tools\">{tools()}</div>\n </Show>\n </header>\n <Show\n when={reserve() !== undefined}\n fallback={\n <div class=\"k2b-dashboard-frame__body\" style={props.height ? { height: props.height } : undefined} aria-busy={busy()}>\n <Switch fallback={props.children}>\n <Match when={state() === \"loading\" && props.compact}>\n <div class=\"k2b-dashboard-frame__skeleton\" aria-hidden=\"true\">\n <span />\n <span />\n </div>\n </Match>\n <Match when={(failed() || empty()) && props.compact}>\n <p class=\"k2b-dashboard-frame__inline-state\" role={failed() ? \"alert\" : undefined}>\n <i class={failed() ? \"ti ti-alert-circle\" : (props.emptyIcon ?? \"ti ti-chart-bar-off\")} aria-hidden=\"true\" />\n {failed() ? chart().chartLoadFailed : sentence()}\n <Show when={failed() && props.onRetry}>{retryLink()}</Show>\n <Show when={empty()}>{props.emptyAction}</Show>\n </p>\n </Match>\n <Match when={!shown()}>\n <Message />\n </Match>\n </Switch>\n </div>\n }\n >\n <div class=\"k2b-dashboard-frame__stack\" aria-busy={busy()}>\n {/* The full content, hidden: the body's height in every state. */}\n <div class=\"k2b-dashboard-frame__reserve\" aria-hidden=\"true\" inert>\n {reserve()}\n </div>\n <Show when={shown()} fallback={<Message />}>\n <div class=\"k2b-dashboard-frame__content\">{props.children}</div>\n </Show>\n </div>\n </Show>\n </Paper>\n </Show>\n );\n\n function Message(): JSX.Element {\n return (\n <div class=\"k2b-chart-explorer__state\" data-state={state()} role={failed() ? \"alert\" : undefined}>\n <Show when={state() !== \"loading\"}>\n <span class=\"k2b-chart-explorer__state-icon\" aria-hidden=\"true\">\n <i class={failed() ? \"ti ti-alert-circle\" : (props.emptyIcon ?? \"ti ti-chart-bar-off\")} />\n </span>\n </Show>\n <p>{failed() ? chart().chartLoadFailed : state() === \"loading\" ? \"\" : sentence()}</p>\n <Show when={failed() && props.onRetry}>\n <Button variant=\"secondary\" size=\"sm\" onClick={() => props.onRetry?.()}>\n <i class=\"ti ti-refresh\" aria-hidden=\"true\" />\n {ui().tryAgain}\n </Button>\n </Show>\n <Show when={empty()}>{props.emptyAction}</Show>\n </div>\n );\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["widgets/DashboardFrame.tsx"],"sourcesContent":["import { children, type JSX, Match, Show, Switch } from \"solid-js\";\nimport { Dynamic } from \"solid-js/web\";\nimport { Button } from \"../actions/Button\";\nimport { useChartMessages } from \"../content/chart-messages\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { Paper } from \"../surfaces/Paper\";\nimport type { DashboardWidth } from \"./Dashboard\";\n\n/**\n * What the host's read shows: its content (`ready`), the first read in flight (`loading`), nothing to show (`empty`),\n * a failed first read (`error`), or content whose refresh failed (`stale`).\n */\nexport type DashboardFrameState = \"ready\" | \"loading\" | \"empty\" | \"error\" | \"stale\";\n\nexport type DashboardFrameProps = {\n /**\n * Heading of the frame. Without it the frame is only the surface, for content that brings its own head and states,\n * such as `ChartExplorer` with `inset=\"1rem\"`.\n */\n title?: string;\n /** One line under the title; loading and stale notes take its place, so nothing moves. */\n subtitle?: JSX.Element;\n /** Level of the title heading; defaults to 3. */\n headingLevel?: 2 | 3 | 4 | 5 | 6;\n /** Controls at the right of the head, such as a search field or a grouping chip. */\n tools?: JSX.Element;\n /** Defaults to `ready`. */\n state?: DashboardFrameState;\n /** When the shown content was read, formatted by the host (\"09:12\"); a stale note names it. */\n asOf?: string;\n /** Try again after a failure; without it a failure has no button. */\n onRetry?: () => void;\n /** The empty sentence, such as \"No campaign in this period.\" */\n empty?: JSX.Element;\n /** Tabler icon of the empty state; defaults to `ti ti-chart-bar-off`. */\n emptyIcon?: string;\n /** An action under the empty sentence, such as \"Clear search\". */\n emptyAction?: JSX.Element;\n /**\n * The content has nothing to show right now although the read succeeded, such as a search without matches: the body\n * shows the empty sentence and action while the head keeps its state, so a stale note stays.\n */\n emptyContent?: boolean;\n /**\n * Height of the body, a CSS length. Every state keeps it. With `reserve`, the content fills it and scrolls inside, so\n * a table keeps its header in view; without it, the hidden copy sets the height.\n */\n height?: string;\n /**\n * A hidden copy of the full content that holds the body's height in every state, such as every row of a table. The\n * body then reaches the frame's left, right and bottom edges, like a table that brings its own rows.\n */\n reserve?: JSX.Element;\n /** States as one quiet line instead of a centred message, for short content such as an amount or one bar. */\n compact?: boolean;\n /**\n * Share of a `DashboardSection`'s six columns, like `DashboardPanel`: the frame is the grid cell itself, so it never\n * sits in a second frame. Defaults to a third there; ignored elsewhere.\n */\n width?: DashboardWidth;\n class?: string;\n children?: JSX.Element;\n};\n\n/**\n * One framed dashboard panel: title, subtitle, tools and the content the host passes, with loading, empty, failure and\n * stale in the same place and at the same height.\n */\nexport function DashboardFrame(props: DashboardFrameProps): JSX.Element {\n const ui = useUiMessages();\n const chart = useChartMessages();\n const state = () => props.state ?? \"ready\";\n const failed = () => state() === \"error\";\n const read = () => state() === \"ready\" || state() === \"stale\";\n const shown = () => read() && !props.emptyContent;\n const empty = () => state() === \"empty\" || (read() && props.emptyContent === true);\n // Slots resolve once: checking a slot and then rendering it must not mount its components twice.\n const tools = children(() => props.tools);\n const reserve = children(() => props.reserve);\n const busy = () => (state() === \"loading\" ? \"true\" : undefined);\n const className = () => (props.class ? `k2b-dashboard-frame ${props.class}` : \"k2b-dashboard-frame\");\n const retryLink = () => (\n <button type=\"button\" class=\"k2b-dashboard-frame__link\" onClick={() => props.onRetry?.()}>\n {ui().tryAgain}\n </button>\n );\n const status = () =>\n state() === \"loading\"\n ? chart().chartLoading\n : state() === \"stale\"\n ? [props.asOf ? chart().chartAsOf({ time: props.asOf }) : undefined, chart().chartRefreshFailed].filter(Boolean).join(\" · \")\n : props.subtitle;\n const sentence = () => props.empty ?? ui().noData;\n return (\n <Show\n when={props.title !== undefined}\n fallback={\n <Paper class={className()} data-width={props.width ?? \"third\"}>\n {props.children}\n </Paper>\n }\n >\n <Paper class={className()} data-width={props.width ?? \"third\"}>\n <header class=\"k2b-dashboard-frame__header\">\n <div>\n <Dynamic component={`h${props.headingLevel ?? 3}`}>{props.title}</Dynamic>\n {/* One reserved line and a polite live region: loading and stale replace the subtitle without moving. The\n line is one expression: a trailing conditional anchor would change WebKit's rendered text after the\n first client render. */}\n <p role=\"status\" class={state() === \"stale\" ? \"k2b-dashboard-frame__stale\" : undefined}>\n {state() === \"stale\" && props.onRetry ? [status(), \" · \", retryLink()] : status()}\n </p>\n </div>\n <Show when={tools() !== undefined}>\n <div class=\"k2b-dashboard-frame__tools\">{tools()}</div>\n </Show>\n </header>\n <Show\n when={reserve() !== undefined}\n fallback={\n <div class=\"k2b-dashboard-frame__body\" style={props.height ? { height: props.height } : undefined} aria-busy={busy()}>\n <Switch fallback={props.children}>\n <Match when={state() === \"loading\" && props.compact}>\n <div class=\"k2b-dashboard-frame__skeleton\" aria-hidden=\"true\">\n <span />\n <span />\n </div>\n </Match>\n <Match when={(failed() || empty()) && props.compact}>\n <p class=\"k2b-dashboard-frame__inline-state\" role={failed() ? \"alert\" : undefined}>\n <i class={failed() ? \"ti ti-alert-circle\" : (props.emptyIcon ?? \"ti ti-chart-bar-off\")} aria-hidden=\"true\" />\n {failed() ? chart().chartLoadFailed : sentence()}\n <Show when={failed() && props.onRetry}>{retryLink()}</Show>\n <Show when={empty()}>{props.emptyAction}</Show>\n </p>\n </Match>\n <Match when={!shown()}>\n <Message />\n </Match>\n </Switch>\n </div>\n }\n >\n <div\n class=\"k2b-dashboard-frame__stack\"\n data-height={props.height ? \"\" : undefined}\n style={props.height ? { height: props.height } : undefined}\n aria-busy={busy()}\n >\n {/* The full content, hidden: the body's height in every state. */}\n <div class=\"k2b-dashboard-frame__reserve\" aria-hidden=\"true\" inert>\n {reserve()}\n </div>\n <Show when={shown()} fallback={<Message />}>\n <div class=\"k2b-dashboard-frame__content\">{props.children}</div>\n </Show>\n </div>\n </Show>\n </Paper>\n </Show>\n );\n\n function Message(): JSX.Element {\n return (\n <div class=\"k2b-chart-explorer__state\" data-state={state()} role={failed() ? \"alert\" : undefined}>\n <Show when={state() !== \"loading\"}>\n <span class=\"k2b-chart-explorer__state-icon\" aria-hidden=\"true\">\n <i class={failed() ? \"ti ti-alert-circle\" : (props.emptyIcon ?? \"ti ti-chart-bar-off\")} />\n </span>\n </Show>\n <p>{failed() ? chart().chartLoadFailed : state() === \"loading\" ? \"\" : sentence()}</p>\n <Show when={failed() && props.onRetry}>\n <Button variant=\"secondary\" size=\"sm\" onClick={() => props.onRetry?.()}>\n <i class=\"ti ti-refresh\" aria-hidden=\"true\" />\n {ui().tryAgain}\n </Button>\n </Show>\n <Show when={empty()}>{props.emptyAction}</Show>\n </div>\n );\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1,8 +1,8 @@
1
1
  import { createComponent as _$createComponent } from "solid-js/web";
2
- import { memo as _$memo } from "solid-js/web";
3
2
  import { ssr as _$ssr } from "solid-js/web";
4
3
  import { ssrAttribute as _$ssrAttribute } from "solid-js/web";
5
4
  import { escape as _$escape } from "solid-js/web";
5
+ import { memo as _$memo } from "solid-js/web";
6
6
  var _tmpl$ = ["<i", " aria-hidden=\"true\"></i>"],
7
7
  _tmpl$2 = ["<span class=\"", "\">", "</span>"],
8
8
  _tmpl$3 = ["<div class=\"", "\" role=\"group\"", ">", "</div>"],
@@ -95,6 +95,9 @@ const ToolbarAction = props => {
95
95
  get ["aria-keyshortcuts"]() {
96
96
  return ariaShortcut(props.keys, platform());
97
97
  },
98
+ get ["aria-pressed"]() {
99
+ return _$memo(() => props.pressed === undefined)() ? undefined : props.pressed ? "true" : "false";
100
+ },
98
101
  get ["data-priority"]() {
99
102
  return props.priority;
100
103
  },
@@ -140,7 +143,10 @@ const rovingFocus = (root, orientation) => {
140
143
  });
141
144
  const items = () => controls().filter(item => !item.matches(":disabled") && !item.closest('[data-overflow="hidden"]') && item.getClientRects().length > 0);
142
145
  const sync = () => {
143
- const available = items();
146
+ // A toolbar that is still hidden, such as a SelectionToolbar about to show, keeps one stop: otherwise Tab right
147
+ // after it shows would pass it before the next measure.
148
+ const shown = items();
149
+ const available = shown.length ? shown : controls().filter(item => !item.matches(":disabled") && !item.closest('[data-overflow="hidden"]'));
144
150
  if (!last || !available.includes(last)) setLast(available[0]);
145
151
  for (const item of controls()) item.tabIndex = item === last ? 0 : -1;
146
152
  };