@nanisoft/prism-ui 0.16.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/blocks/activity-feed-01/activity-feed-01.d.ts +120 -190
  3. package/dist/blocks/activity-feed-01/activity-feed-01.d.ts.map +1 -1
  4. package/dist/blocks/activity-feed-01/activity-feed-01.js +107 -97
  5. package/dist/blocks/activity-feed-01/index.d.ts +1 -1
  6. package/dist/blocks/activity-feed-01/index.d.ts.map +1 -1
  7. package/dist/blocks/auth-form-01/auth-form.d.ts +86 -53
  8. package/dist/blocks/auth-form-01/auth-form.d.ts.map +1 -1
  9. package/dist/blocks/auth-form-01/auth-form.js +95 -31
  10. package/dist/blocks/auth-form-01/index.d.ts +1 -1
  11. package/dist/blocks/auth-form-01/index.d.ts.map +1 -1
  12. package/dist/blocks/calendar-01/calendar.d.ts +28 -0
  13. package/dist/blocks/calendar-01/calendar.d.ts.map +1 -1
  14. package/dist/blocks/calendar-01/calendar.js +15 -1
  15. package/dist/blocks/card-index-01/card-index.d.ts +225 -0
  16. package/dist/blocks/card-index-01/card-index.d.ts.map +1 -0
  17. package/dist/blocks/card-index-01/card-index.js +154 -0
  18. package/dist/blocks/card-index-01/index.d.ts +3 -0
  19. package/dist/blocks/card-index-01/index.d.ts.map +1 -0
  20. package/dist/blocks/card-index-01/index.js +1 -0
  21. package/dist/blocks/chart-card-01/chart-card-01.d.ts +23 -21
  22. package/dist/blocks/chart-card-01/chart-card-01.d.ts.map +1 -1
  23. package/dist/blocks/chart-card-01/chart-card-01.js +46 -1
  24. package/dist/blocks/chart-card-01/index.d.ts +1 -1
  25. package/dist/blocks/chart-card-01/index.d.ts.map +1 -1
  26. package/dist/blocks/chart-group-01/chart-group-01.d.ts +3 -3
  27. package/dist/blocks/chart-group-01/chart-group-01.d.ts.map +1 -1
  28. package/dist/blocks/contact-01/contact.d.ts +30 -82
  29. package/dist/blocks/contact-01/contact.d.ts.map +1 -1
  30. package/dist/blocks/contact-01/contact.js +59 -30
  31. package/dist/blocks/contact-01/index.d.ts +1 -1
  32. package/dist/blocks/contact-01/index.d.ts.map +1 -1
  33. package/dist/blocks/dashboard-01/dashboard-01.d.ts +26 -71
  34. package/dist/blocks/dashboard-01/dashboard-01.d.ts.map +1 -1
  35. package/dist/blocks/dashboard-01/dashboard-01.js +34 -23
  36. package/dist/blocks/dashboard-01/index.d.ts +1 -1
  37. package/dist/blocks/dashboard-01/index.d.ts.map +1 -1
  38. package/dist/blocks/data-table-01/data-table.d.ts +276 -59
  39. package/dist/blocks/data-table-01/data-table.d.ts.map +1 -1
  40. package/dist/blocks/data-table-01/data-table.js +217 -35
  41. package/dist/blocks/data-table-01/index.d.ts +1 -1
  42. package/dist/blocks/data-table-01/index.d.ts.map +1 -1
  43. package/dist/blocks/directory-01/directory-01.d.ts +23 -2
  44. package/dist/blocks/directory-01/directory-01.d.ts.map +1 -1
  45. package/dist/blocks/directory-01/directory-01.js +3 -3
  46. package/dist/blocks/empty-state-01/empty-state.d.ts +60 -21
  47. package/dist/blocks/empty-state-01/empty-state.d.ts.map +1 -1
  48. package/dist/blocks/empty-state-01/empty-state.js +52 -17
  49. package/dist/blocks/index-detail-01/index-detail.d.ts +85 -0
  50. package/dist/blocks/index-detail-01/index-detail.d.ts.map +1 -0
  51. package/dist/blocks/index-detail-01/index-detail.js +58 -0
  52. package/dist/blocks/index-detail-01/index.d.ts +3 -0
  53. package/dist/blocks/index-detail-01/index.d.ts.map +1 -0
  54. package/dist/blocks/index-detail-01/index.js +1 -0
  55. package/dist/blocks/index.d.ts +20 -8
  56. package/dist/blocks/index.d.ts.map +1 -1
  57. package/dist/blocks/index.js +7 -0
  58. package/dist/blocks/issue-detail-01/issue-detail.d.ts +18 -0
  59. package/dist/blocks/issue-detail-01/issue-detail.d.ts.map +1 -1
  60. package/dist/blocks/issue-detail-01/issue-detail.js +18 -0
  61. package/dist/blocks/nothing-chosen-01/index.d.ts +3 -0
  62. package/dist/blocks/nothing-chosen-01/index.d.ts.map +1 -0
  63. package/dist/blocks/nothing-chosen-01/index.js +1 -0
  64. package/dist/blocks/nothing-chosen-01/nothing-chosen.d.ts +119 -0
  65. package/dist/blocks/nothing-chosen-01/nothing-chosen.d.ts.map +1 -0
  66. package/dist/blocks/nothing-chosen-01/nothing-chosen.js +79 -0
  67. package/dist/blocks/project-dashboard-01/index.d.ts +1 -1
  68. package/dist/blocks/project-dashboard-01/index.d.ts.map +1 -1
  69. package/dist/blocks/project-dashboard-01/project-dashboard.d.ts +21 -27
  70. package/dist/blocks/project-dashboard-01/project-dashboard.d.ts.map +1 -1
  71. package/dist/blocks/project-dashboard-01/project-dashboard.js +45 -5
  72. package/dist/blocks/provisioning-01/index.d.ts +1 -1
  73. package/dist/blocks/provisioning-01/index.d.ts.map +1 -1
  74. package/dist/blocks/provisioning-01/provisioning.d.ts +9 -97
  75. package/dist/blocks/provisioning-01/provisioning.d.ts.map +1 -1
  76. package/dist/blocks/provisioning-01/provisioning.js +26 -13
  77. package/dist/blocks/record-detail-01/index.d.ts +3 -0
  78. package/dist/blocks/record-detail-01/index.d.ts.map +1 -0
  79. package/dist/blocks/record-detail-01/index.js +1 -0
  80. package/dist/blocks/record-detail-01/record-detail.d.ts +239 -0
  81. package/dist/blocks/record-detail-01/record-detail.d.ts.map +1 -0
  82. package/dist/blocks/record-detail-01/record-detail.js +150 -0
  83. package/dist/blocks/record-form-01/index.d.ts +3 -0
  84. package/dist/blocks/record-form-01/index.d.ts.map +1 -0
  85. package/dist/blocks/record-form-01/index.js +1 -0
  86. package/dist/blocks/record-form-01/record-form.d.ts +148 -0
  87. package/dist/blocks/record-form-01/record-form.d.ts.map +1 -0
  88. package/dist/blocks/record-form-01/record-form.js +107 -0
  89. package/dist/blocks/record-grid-01/index.d.ts +3 -0
  90. package/dist/blocks/record-grid-01/index.d.ts.map +1 -0
  91. package/dist/blocks/record-grid-01/index.js +1 -0
  92. package/dist/blocks/record-grid-01/record-grid.d.ts +145 -0
  93. package/dist/blocks/record-grid-01/record-grid.d.ts.map +1 -0
  94. package/dist/blocks/record-grid-01/record-grid.js +114 -0
  95. package/dist/blocks/record-wizard-01/index.d.ts +3 -0
  96. package/dist/blocks/record-wizard-01/index.d.ts.map +1 -0
  97. package/dist/blocks/record-wizard-01/index.js +1 -0
  98. package/dist/blocks/record-wizard-01/record-wizard.d.ts +152 -0
  99. package/dist/blocks/record-wizard-01/record-wizard.d.ts.map +1 -0
  100. package/dist/blocks/record-wizard-01/record-wizard.js +144 -0
  101. package/dist/blocks/settings-members-01/settings-members.d.ts +2 -1
  102. package/dist/blocks/settings-members-01/settings-members.d.ts.map +1 -1
  103. package/dist/blocks/settings-panel-01/index.d.ts +1 -1
  104. package/dist/blocks/settings-panel-01/index.d.ts.map +1 -1
  105. package/dist/blocks/settings-panel-01/settings-panel.d.ts +165 -67
  106. package/dist/blocks/settings-panel-01/settings-panel.d.ts.map +1 -1
  107. package/dist/blocks/settings-panel-01/settings-panel.js +92 -33
  108. package/dist/blocks/signup-01/index.d.ts +1 -1
  109. package/dist/blocks/signup-01/index.d.ts.map +1 -1
  110. package/dist/blocks/signup-01/signup-01.d.ts +10 -84
  111. package/dist/blocks/signup-01/signup-01.d.ts.map +1 -1
  112. package/dist/blocks/signup-01/signup-01.js +41 -23
  113. package/dist/blocks/stats-01/index.d.ts +5 -5
  114. package/dist/blocks/stats-01/index.d.ts.map +1 -1
  115. package/dist/blocks/stats-01/index.js +4 -4
  116. package/dist/blocks/stats-01/stats.d.ts +49 -14
  117. package/dist/blocks/stats-01/stats.d.ts.map +1 -1
  118. package/dist/blocks/stats-01/stats.js +65 -15
  119. package/dist/blocks/trend-01/index.d.ts +1 -1
  120. package/dist/blocks/trend-01/index.d.ts.map +1 -1
  121. package/dist/blocks/trend-01/trend.d.ts +26 -73
  122. package/dist/blocks/trend-01/trend.d.ts.map +1 -1
  123. package/dist/blocks/trend-01/trend.js +47 -30
  124. package/dist/catalog.d.ts.map +1 -1
  125. package/dist/catalog.js +93 -3
  126. package/dist/components/ui/metric.d.ts +4 -2
  127. package/dist/components/ui/metric.d.ts.map +1 -1
  128. package/dist/index.d.ts +10 -0
  129. package/dist/index.d.ts.map +1 -1
  130. package/dist/index.js +6 -0
  131. package/dist/lib/field-render.d.ts +107 -0
  132. package/dist/lib/field-render.d.ts.map +1 -0
  133. package/dist/lib/field-render.js +251 -0
  134. package/dist/lib/spec.d.ts +609 -0
  135. package/dist/lib/spec.d.ts.map +1 -0
  136. package/dist/lib/spec.js +1 -0
  137. package/dist/live/index.d.ts +2 -0
  138. package/dist/live/index.d.ts.map +1 -1
  139. package/dist/live/index.js +6 -0
  140. package/dist/live/message-thread-01/index.d.ts +3 -0
  141. package/dist/live/message-thread-01/index.d.ts.map +1 -0
  142. package/dist/live/message-thread-01/index.js +1 -0
  143. package/dist/live/message-thread-01/message-thread.d.ts +282 -0
  144. package/dist/live/message-thread-01/message-thread.d.ts.map +1 -0
  145. package/dist/live/message-thread-01/message-thread.js +221 -0
  146. package/dist/live/run-stream-01/run-stream.d.ts +2 -1
  147. package/dist/live/run-stream-01/run-stream.d.ts.map +1 -1
  148. package/dist/live/run-stream-01/run-stream.js +1 -7
  149. package/dist/live/status.d.ts +27 -0
  150. package/dist/live/status.d.ts.map +1 -0
  151. package/dist/live/status.js +15 -0
  152. package/dist/live/tool-call-row.d.ts +26 -0
  153. package/dist/live/tool-call-row.d.ts.map +1 -0
  154. package/dist/live/tool-call-row.js +60 -0
  155. package/dist/live/tool-ledger-01/tool-ledger.d.ts.map +1 -1
  156. package/dist/live/tool-ledger-01/tool-ledger.js +2 -42
  157. package/dist/pages/contact-page/index.d.ts +7 -7
  158. package/dist/pages/contact-page/index.d.ts.map +1 -1
  159. package/dist/pages/contact-page/index.js +17 -5
  160. package/dist/pages/document-page/document-page.d.ts +146 -0
  161. package/dist/pages/document-page/document-page.d.ts.map +1 -0
  162. package/dist/pages/document-page/document-page.js +80 -0
  163. package/dist/pages/document-page/index.d.ts +3 -0
  164. package/dist/pages/document-page/index.d.ts.map +1 -0
  165. package/dist/pages/document-page/index.js +1 -0
  166. package/dist/pages/index.d.ts +2 -0
  167. package/dist/pages/index.d.ts.map +1 -1
  168. package/dist/pages/index.js +6 -0
  169. package/dist/styles.css +35 -3
  170. package/package.json +7 -2
@@ -1,14 +1,13 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useId } from 'react';
3
+ import { useId, useState } from 'react';
4
4
  import { Button } from '../../components/ui/button.js';
5
5
  import { CtaLink } from '../../components/ui/cta-link.js';
6
- import { Field, FieldDescription, FieldLabel } from '../../components/ui/field.js';
7
- import { Input } from '../../components/ui/input.js';
6
+ import { Field, FieldDescription, FieldError, FieldGroup } from '../../components/ui/field.js';
7
+ import { Label } from '../../components/ui/label.js';
8
8
  import { LiveRegion } from '../../components/ui/live-region.js';
9
- import { NativeSelect } from '../../components/ui/native-select.js';
10
9
  import { Section, SectionHeading } from '../../components/ui/section.js';
11
- import { Textarea } from '../../components/ui/textarea.js';
10
+ import { CHOICE_KINDS, fieldText, NEEDS_HIDDEN, renderControl, serialize, SELF_LABELLED, } from '../../lib/field-render.js';
12
11
  import { cn } from '../../lib/utils.js';
13
12
  /**
14
13
  * Whether a caller-supplied string never arrived, arrived empty, or arrived as
@@ -41,19 +40,27 @@ function blankList(value) {
41
40
  *
42
41
  * Both reach a developer in a console rather than a reader, which is what makes
43
42
  * them refusals rather than copy: the message says what was passed and what to
44
- * pass instead, and neither of those sentences is ever shown to a reader.
43
+ * pass instead, and neither of those sentences is ever shown to a reader. The
44
+ * type catches both for a TypeScript caller, and the check is here for the
45
+ * JavaScript caller and for the value that came out of a database with the
46
+ * type's guarantee already gone.
45
47
  */
46
- function assertField(field) {
47
- if (blank(field.label)) {
48
- throw new Error(`Contact01: the field "${field.id}" declares no label, so the control would be announced with no name and ` +
49
- 'two fields on this page would be announced identically. Every control this Block draws is named by its ' +
50
- 'label, so there is no fallback to fall back to.');
51
- }
52
- if (field.type === 'select' && blankList(field.options)) {
53
- throw new Error(`Contact01: the field "${field.id}" is a select and passes no options, so it would render a control with ` +
54
- 'nothing in it, which is a question no reader can answer and looks answered only because the control is ' +
55
- 'there and focusable. Pass the choices, or declare the field as a text field and check the answer in your ' +
56
- 'own handler.');
48
+ function assertGroups(groups) {
49
+ for (const group of groups) {
50
+ for (const field of group.fields) {
51
+ if (blank(typeof field.label === 'string' ? field.label : undefined)) {
52
+ throw new Error(`Contact01: the field "${field.key}" declares no label, so the control would be announced with no name and ` +
53
+ 'two fields on this page would be announced identically. Every control this Block draws is named by its ' +
54
+ 'label, so there is no fallback to fall back to.');
55
+ }
56
+ if (CHOICE_KINDS.has(field.kind) &&
57
+ blankList(field.options)) {
58
+ throw new Error(`Contact01: the field "${field.key}" is a choice and passes no options, so it would render a control with ` +
59
+ 'nothing in it, which is a question no reader can answer and looks answered only because the control is ' +
60
+ 'there and focusable. Pass the choices, or declare the field as a text field and check the answer in your ' +
61
+ 'own handler.');
62
+ }
63
+ }
57
64
  }
58
65
  }
59
66
  /**
@@ -156,34 +163,56 @@ function assertField(field) {
156
163
  * nothing. The rest of the rendering is a section and five controls, which is the
157
164
  * price of the argument above and not a claim about what else this Block might do.
158
165
  */
159
- export function Contact01({ eyebrow, title, description, onSubmit, fields, submitLabel, consent, address, variant = 'split', status, headingLevel = 'h2', className, }) {
166
+ export function Contact01({ eyebrow, title, description, onSubmit, groups, issues, submitLabel, consent, address, variant = 'split', status, headingLevel = 'h2', className, }) {
160
167
  const generated = useId();
161
168
  const sending = status?.state === 'sending';
162
- for (const field of fields)
163
- assertField(field);
169
+ const [values, setValues] = useState({});
170
+ const setValue = (key, value) => setValues((previous) => ({ ...previous, [key]: value }));
171
+ assertGroups(groups);
172
+ const fields = groups.flatMap((group) => group.fields);
164
173
  /*
165
174
  * The values are read out of the form rather than out of any prop, because a
166
175
  * contact form is uncontrolled by nature: there are as many fields as the caller
167
- * declared and no state to hold them in. The keys are the caller's own `id`s, so
168
- * the record that arrives is shaped like the declaration that produced it, and a
169
- * caller that renames a field in one place renames it in one place.
176
+ * declared and no state to hold them in. The keys are the caller's own field
177
+ * `key`s, so the record that arrives is shaped like the declaration that produced
178
+ * it, and a caller that renames a field in one place renames it in one place. The
179
+ * handful of Prism controls the platform will not submit on their own hold their
180
+ * value here and carry a hidden input under the field's key.
170
181
  */
171
182
  const handleSubmit = (event) => {
172
183
  event.preventDefault();
173
184
  const read = new FormData(event.currentTarget);
174
185
  const next = {};
175
186
  for (const field of fields) {
176
- const one = read.get(field.id);
187
+ const one = read.get(field.key);
177
188
  if (typeof one === 'string')
178
- next[field.id] = one;
189
+ next[field.key] = one;
179
190
  }
180
191
  onSubmit(next);
181
192
  };
182
- return (_jsx(Section, { "data-slot": "contact-01", className: cn(className), children: _jsxs("div", { "data-slot": "contact-01-body", className: "flex flex-col gap-8", children: [_jsx(SectionHeading, { eyebrow: eyebrow, title: title, description: description, align: "left", as: headingLevel }), _jsxs("div", { "data-slot": "contact-01-columns", "data-variant": variant, className: cn('grid items-start gap-10', variant === 'split' ? 'lg:grid-cols-[minmax(0,3fr)_minmax(0,2fr)] lg:gap-14' : null), children: [_jsxs("form", { "data-slot": "contact-01-form", onSubmit: handleSubmit, className: "flex w-full max-w-measure flex-col gap-4", children: [fields.map((field) => {
183
- const controlId = `${generated}-${field.id}`;
184
- const descriptionId = `${controlId}-description`;
185
- return (_jsxs(Field, { "data-slot": "contact-01-field", "data-field": field.type, children: [_jsx(FieldLabel, { htmlFor: controlId, children: field.label }), field.type === 'textarea' ? (_jsx(Textarea, { id: controlId, name: field.id, rows: 4, placeholder: field.placeholder, required: field.required, "aria-describedby": field.description === undefined ? undefined : descriptionId })) : field.type === 'select' ? (_jsx(NativeSelect, { id: controlId, name: field.id, required: field.required, "aria-describedby": field.description === undefined ? undefined : descriptionId, children: field.options.map((option) => (_jsx("option", { value: option.value, children: option.label }, option.value))) })) : (_jsx(Input, { id: controlId, name: field.id, type: field.type, placeholder: field.placeholder, autoComplete: field.autoComplete, required: field.required, "aria-describedby": field.description === undefined ? undefined : descriptionId })), field.description === undefined ? null : (_jsx(FieldDescription, { id: descriptionId, children: field.description }))] }, field.id));
186
- }), consent === undefined ? null : (_jsx("p", { "data-slot": "contact-01-consent", className: "text-muted-foreground text-sm", children: consent })), _jsxs("div", { "data-slot": "contact-01-actions", className: "flex flex-col gap-3", children: [_jsx(Button, { "data-slot": "contact-01-submit", type: "submit", disabled: sending, className: "self-start", children: submitLabel }), _jsx(LiveRegion, { politeness: status?.state === 'error' ? 'assertive' : 'polite', busy: sending, className: "text-sm", children: status?.message })] })] }), address === undefined ? null : (
193
+ return (_jsx(Section, { "data-slot": "contact-01", className: cn(className), children: _jsxs("div", { "data-slot": "contact-01-body", className: "flex flex-col gap-8", children: [_jsx(SectionHeading, { eyebrow: eyebrow, title: title, description: description, align: "left", as: headingLevel }), _jsxs("div", { "data-slot": "contact-01-columns", "data-variant": variant, className: cn('grid items-start gap-10', variant === 'split' ? 'lg:grid-cols-[minmax(0,3fr)_minmax(0,2fr)] lg:gap-14' : null), children: [_jsxs("form", { "data-slot": "contact-01-form", onSubmit: handleSubmit, className: "flex w-full max-w-measure flex-col gap-4", children: [groups.map((group, groupIndex) => (_jsxs(FieldGroup, { "data-slot": "contact-01-group", className: "flex flex-col gap-4", children: [group.label === undefined ? null : (_jsx("p", { "data-slot": "contact-01-group-label", className: "text-foreground text-sm font-medium", children: group.label })), group.description === undefined ? null : (_jsx("p", { "data-slot": "contact-01-group-description", className: "text-muted-foreground text-sm", children: group.description })), group.fields.map((field, fieldIndex) => {
194
+ const id = `${generated}-${groupIndex}-${fieldIndex}`;
195
+ const labelId = `${id}-label`;
196
+ const helpId = field.help === undefined ? undefined : `${id}-help`;
197
+ const fieldIssues = (issues ?? []).filter((issue) => issue.field === field.key);
198
+ const errorId = fieldIssues.length > 0 ? `${id}-error` : undefined;
199
+ const describedBy = helpId === undefined
200
+ ? errorId
201
+ : errorId === undefined
202
+ ? helpId
203
+ : `${helpId} ${errorId}`;
204
+ const kind = field.kind.toLowerCase();
205
+ const ctx = {
206
+ id,
207
+ labelId,
208
+ describedBy,
209
+ invalid: fieldIssues.length > 0,
210
+ text: fieldText(field),
211
+ values,
212
+ setValue,
213
+ };
214
+ return (_jsxs(Field, { "data-slot": "contact-01-field", "data-field": field.kind, children: [SELF_LABELLED.has(kind) ? null : (_jsx(Label, { id: labelId, htmlFor: id, required: field.required, disabled: field.disabled, children: field.label })), renderControl(field, ctx), NEEDS_HIDDEN.has(kind) ? (_jsx("input", { type: "hidden", name: field.key, value: serialize(values[field.key] ?? field.defaultValue) })) : null, field.help === undefined ? null : (_jsx(FieldDescription, { id: helpId, children: field.help })), fieldIssues.length === 0 ? null : (_jsx(FieldError, { id: errorId, children: fieldIssues.map((issue, issueIndex) => (_jsx("span", { "data-slot": "contact-01-issue", children: issue.message }, issueIndex))) }))] }, field.key));
215
+ })] }, group.id ?? groupIndex))), consent === undefined ? null : (_jsx("p", { "data-slot": "contact-01-consent", className: "text-muted-foreground text-sm", children: consent })), _jsxs("div", { "data-slot": "contact-01-actions", className: "flex flex-col gap-3", children: [_jsx(Button, { "data-slot": "contact-01-submit", type: "submit", disabled: sending, className: "self-start", children: submitLabel }), _jsx(LiveRegion, { politeness: status?.state === 'error' ? 'assertive' : 'polite', busy: sending, className: "text-sm", children: status?.message })] })] }), address === undefined ? null : (
187
216
  /*
188
217
  * An `address` element, because that is what this is: contact
189
218
  * information for the organisation, which is what the element names and
@@ -1,3 +1,3 @@
1
1
  export { Contact01, default } from './contact.js';
2
- export type { Contact01Address, Contact01Option, Contact01Props, Contact01Status, ContactField, ContactValue, } from './contact.js';
2
+ export type { Contact01Address, Contact01Issue, Contact01Props, Contact01Status, ContactValue, } from './contact.js';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/blocks/contact-01/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAM9C,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,eAAe,EACf,YAAY,EACZ,YAAY,GACb,MAAM,WAAW,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/blocks/contact-01/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAO9C,YAAY,EACV,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,eAAe,EACf,YAAY,GACb,MAAM,WAAW,CAAA"}
@@ -1,5 +1,6 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import { type HeadingLevel } from '../../components/ui/section.js';
3
+ import type { MetricSpec } from '../../lib/spec.js';
3
4
  /**
4
5
  * How much of the six-track panel grid one panel takes.
5
6
  *
@@ -13,64 +14,6 @@ import { type HeadingLevel } from '../../components/ui/section.js';
13
14
  * full width under a row of thirds, two thirds above a row of halves.
14
15
  */
15
16
  export type Dashboard01Span = 'full' | 'half' | 'third';
16
- /**
17
- * One figure at the top of an overview, and the four optional things a figure
18
- * comes with.
19
- *
20
- * `label` and `value` are the two that make a figure a figure. The rest are
21
- * annotation, and a metric with no annotation renders the two it has rather than a
22
- * card with a line of empty space where the annotation would have been, which is
23
- * the rule every optional field on this type follows.
24
- *
25
- * `deltaFormat` is here for the reason `Metric` refuses to guess: a delta of `0.12`
26
- * is twelve percent, twelve cents or twelve milliseconds, and a Component that
27
- * attached a percent sign to it would be claiming a caller's units. The cost of the
28
- * refusal is that a caller who passes a fraction and no formatter gets `0.12`
29
- * printed, which is honest and almost never what was wanted, so the formatter is a
30
- * prop here and the alternative was a Block guessing on every consumer's behalf.
31
- */
32
- export type Dashboard01Metric = {
33
- /** What the figure measures, read under the figure rather than above it. */
34
- label: string;
35
- /** The figure itself, in the caller's own units and the caller's own formatting. */
36
- value: ReactNode;
37
- /**
38
- * The change against the previous reading, where the sign is the direction.
39
- *
40
- * A `number` and not an object with a `direction`, for the reason `Metric` states
41
- * in full: a number has exactly one sign, and a shape with both lets a caller put
42
- * a rising mark on a falling reading.
43
- */
44
- delta?: number;
45
- /** The words for the delta, given the number. See the note on this type. */
46
- deltaFormat?: (value: number) => string;
47
- /** The line under the label: the period, the source, the caveat that matters. */
48
- hint?: ReactNode;
49
- /** The readings behind the figure, drawn small beside it. See `sparklineLabel`. */
50
- sparkline?: number[];
51
- /**
52
- * The name of the series the sparkline draws, and the only thing a screen reader
53
- * reads before the numbers.
54
- *
55
- * Required whenever `sparkline` is set, and the pair is checked together rather
56
- * than left to the Component. `Sparkline` needs a name for the same reason `Chart`
57
- * does: two sparklines in a row of four are two pictures a reader cannot tell
58
- * apart, and a picture with no name is not announced and not linkable. Requiring
59
- * it at the Block's own boundary rather than letting the Component throw means the
60
- * diagnostic names the field the caller has to add.
61
- */
62
- sparklineLabel?: string;
63
- /** Where the figure is kept. Its presence makes the tile carry a link. */
64
- href?: string;
65
- /**
66
- * The words on the link, and required whenever `href` is.
67
- *
68
- * A link whose only words are the figure itself tells a reader nothing about what
69
- * following it does, and the same rule holds in every Block in this package that
70
- * draws a link.
71
- */
72
- hrefLabel?: string;
73
- };
74
17
  /**
75
18
  * One panel in the grid: an identifier, how much width it takes, and the caller's
76
19
  * own content.
@@ -130,13 +73,22 @@ export type Dashboard01Props = {
130
73
  */
131
74
  header?: ReactNode;
132
75
  /**
133
- * The figures along the top, in the order a reader should meet them.
76
+ * The figures along the top, as the shared `MetricSpec` typed data, in the order
77
+ * a reader should meet them.
78
+ *
79
+ * **It is the shared specification and not a shape of this Block's own.** `key`,
80
+ * `label` and `value` are required on each figure, `delta` is a number whose sign
81
+ * is the direction, `deltaFormat` is the caller's own words for that change,
82
+ * `hint` carries the period or the caveat, and a `series` and an `href` each
83
+ * travel with the label or the words they cannot be read without. The type is
84
+ * published as `@nanisoft/prism-ui/spec` so the words a caller learns on this row
85
+ * are the words on every other figure surface.
134
86
  *
135
87
  * Order is the caller's because it is a claim about what matters first. A row
136
88
  * that sorted itself by size or by name would be making that claim on the
137
89
  * caller's behalf, and on a dashboard the claim is the whole point.
138
90
  */
139
- metrics?: Dashboard01Metric[];
91
+ metrics?: MetricSpec[];
140
92
  /** The panels, in the order a reader should meet them. See `Dashboard01Panel`. */
141
93
  panels?: Dashboard01Panel[];
142
94
  /**
@@ -179,17 +131,20 @@ export type Dashboard01Props = {
179
131
  * Prism happened to put first. So `panels` is a list with a width on each entry and
180
132
  * this Block's only remaining opinion is the six-track grid they are placed on.
181
133
  *
182
- * **The figures are `Metric` and `Sparkline`, and a dashboard that hand-drew its own
183
- * metric row would be a second implementation of a Component whose whole argument is
184
- * that the direction is derived rather than declared.** `Metric`'s delta is a
185
- * `number` and the sign is the direction, so a rising mark cannot be drawn on a
186
- * falling reading; a Block that took `{ value, direction }` could, and the mistake
187
- * would be invisible in review and visible to every reader of that dashboard. It
188
- * also puts the label under the value, which is the arrangement a dashboard row
189
- * wants, because a row is scanned by its figures and settled by its names. And
190
- * `Sparkline` draws the numbers behind its shape as a table in the document, so a
191
- * metric row of six costs six tables in the accessibility tree rather than six
192
- * pictures nobody can query. The cost is stated rather than implied: a sparkline
134
+ * **The figures are typed by the shared `MetricSpec` and drawn by `Metric` and
135
+ * `Sparkline`, and a dashboard that hand-drew its own metric row would be a second
136
+ * implementation of a Component whose whole argument is that the direction is derived
137
+ * rather than declared.** The row is a list of the same specification every other
138
+ * figure surface takes, published as `@nanisoft/prism-ui/spec`, so a consumer that
139
+ * learned the shape here exports it unchanged to a project dashboard and a summary
140
+ * panel. `Metric`'s delta is a `number` and the sign is the direction, so a rising
141
+ * mark cannot be drawn on a falling reading; a Block that took `{ value, direction }`
142
+ * could, and the mistake would be invisible in review and visible to every reader of
143
+ * that dashboard. It also puts the label under the value, which is the arrangement a
144
+ * dashboard row wants, because a row is scanned by its figures and settled by its
145
+ * names. And `Sparkline` draws the numbers behind its shape as a table in the
146
+ * document, so a metric row of six costs six tables in the accessibility tree rather
147
+ * than six pictures nobody can query. The cost is stated rather than implied: a series
193
148
  * needs a name and a series that is not flat, and a caller who passes an empty array
194
149
  * or a series of one repeated value gets `Sparkline`'s own refusal, which is the
195
150
  * right place for it.
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-01.d.ts","sourceRoot":"","sources":["../../../src/blocks/dashboard-01/dashboard-01.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAWtC,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,6BAA6B,CAAA;AAIpC;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AAEvD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAA;IACb,oFAAoF;IACpF,KAAK,EAAE,SAAS,CAAA;IAChB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4EAA4E;IAC5E,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IACvC,iFAAiF;IACjF,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,0EAA0E;IAC1E,EAAE,EAAE,MAAM,CAAA;IACV,wEAAwE;IACxE,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,mEAAmE;IACnE,IAAI,CAAC,EAAE,eAAe,CAAA;IACtB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,4EAA4E;IAC5E,QAAQ,EAAE,SAAS,CAAA;CACpB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,iFAAiF;IACjF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,iBAAiB,EAAE,CAAA;IAC7B,kFAAkF;IAClF,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAA;IAC3B;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AA+CD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8EG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,KAAK,EACL,WAAW,EACX,MAAM,EACN,OAAY,EACZ,MAAW,EACX,IAAI,EACJ,KAAK,EACL,YAAmB,EACnB,SAAS,GACV,EAAE,gBAAgB,+BA+KlB;AAED,eAAe,WAAW,CAAA"}
1
+ {"version":3,"file":"dashboard-01.d.ts","sourceRoot":"","sources":["../../../src/blocks/dashboard-01/dashboard-01.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAWtC,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,6BAA6B,CAAA;AAEpC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAGhD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AAEvD;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,0EAA0E;IAC1E,EAAE,EAAE,MAAM,CAAA;IACV,wEAAwE;IACxE,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,mEAAmE;IACnE,IAAI,CAAC,EAAE,eAAe,CAAA;IACtB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,4EAA4E;IAC5E,QAAQ,EAAE,SAAS,CAAA;CACpB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,iFAAiF;IACjF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,EAAE,UAAU,EAAE,CAAA;IACtB,kFAAkF;IAClF,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAA;IAC3B;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAiDD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiFG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,KAAK,EACL,WAAW,EACX,MAAM,EACN,OAAY,EACZ,MAAW,EACX,IAAI,EACJ,KAAK,EACL,YAAmB,EACnB,SAAS,GACV,EAAE,gBAAgB,+BAoLlB;AAED,eAAe,WAAW,CAAA"}
@@ -23,24 +23,26 @@ const SPAN = {
23
23
  * The refusals, as checks, so a tile that would render a control nobody can name is
24
24
  * a diagnostic in a console rather than a rendered link.
25
25
  *
26
- * The pair rule is the same one `Changelog01` and `ContentGrid01` make: a link whose
27
- * only words are the figure's own value tells a reader nothing about what following
28
- * it does, and an accessible name that is an address is punctuation rather than a
29
- * name. The sparkline's label is checked here rather than left to the Component
30
- * because the Component's own message names a Component's field, and a caller who
31
- * wired a dashboard up would rather be told which of their own props to add.
26
+ * **The type already holds both pairs, and these checks exist for the caller the
27
+ * type never saw.** `MetricSpec` requires a destination's words wherever it has a
28
+ * destination and a series name wherever it has a series, so a typed caller cannot
29
+ * reach either diagnostic. A JavaScript caller can, and the cost of reaching one is
30
+ * a tile that draws a link with no words or a shape no reader can announce, so the
31
+ * same rule is stated once more where a runtime value can be read: the pair rule is
32
+ * the one `Changelog01` and `ContentGrid01` make, and the series name is the one
33
+ * `Sparkline` gives in full.
32
34
  */
33
35
  function assertMetrics(metrics) {
34
36
  for (const metric of metrics) {
35
37
  if ((metric.href === undefined) !== (metric.hrefLabel === undefined)) {
36
- throw new Error(`Dashboard01: the metric "${metric.label}" declares one of href and hrefLabel without the other, so the ` +
38
+ throw new Error(`Dashboard01: the metric "${metric.key}" declares one of href and hrefLabel without the other, so the ` +
37
39
  'tile would carry a link with no words on it, or a name with no link beside it. Pass the words that say ' +
38
40
  'what following it does, or omit the href.');
39
41
  }
40
- if (metric.sparkline !== undefined && metric.sparklineLabel === undefined) {
41
- throw new Error(`Dashboard01: the metric "${metric.label}" passes a sparkline with no sparklineLabel, so the figure would ` +
42
- 'be a picture with no name, which a screen reader cannot announce and two sparklines in one row cannot be ' +
43
- 'told apart. Pass the series name in the words the product uses.');
42
+ if ((metric.series === undefined) !== (metric.seriesLabel === undefined)) {
43
+ throw new Error(`Dashboard01: the metric "${metric.key}" declares one of series and seriesLabel without the other, so the ` +
44
+ 'figure would be a picture with no name, which a screen reader cannot announce and two shapes in one row ' +
45
+ 'cannot be told apart. Pass the series name in the words the product uses, or omit the series.');
44
46
  }
45
47
  }
46
48
  }
@@ -60,17 +62,20 @@ function assertMetrics(metrics) {
60
62
  * Prism happened to put first. So `panels` is a list with a width on each entry and
61
63
  * this Block's only remaining opinion is the six-track grid they are placed on.
62
64
  *
63
- * **The figures are `Metric` and `Sparkline`, and a dashboard that hand-drew its own
64
- * metric row would be a second implementation of a Component whose whole argument is
65
- * that the direction is derived rather than declared.** `Metric`'s delta is a
66
- * `number` and the sign is the direction, so a rising mark cannot be drawn on a
67
- * falling reading; a Block that took `{ value, direction }` could, and the mistake
68
- * would be invisible in review and visible to every reader of that dashboard. It
69
- * also puts the label under the value, which is the arrangement a dashboard row
70
- * wants, because a row is scanned by its figures and settled by its names. And
71
- * `Sparkline` draws the numbers behind its shape as a table in the document, so a
72
- * metric row of six costs six tables in the accessibility tree rather than six
73
- * pictures nobody can query. The cost is stated rather than implied: a sparkline
65
+ * **The figures are typed by the shared `MetricSpec` and drawn by `Metric` and
66
+ * `Sparkline`, and a dashboard that hand-drew its own metric row would be a second
67
+ * implementation of a Component whose whole argument is that the direction is derived
68
+ * rather than declared.** The row is a list of the same specification every other
69
+ * figure surface takes, published as `@nanisoft/prism-ui/spec`, so a consumer that
70
+ * learned the shape here exports it unchanged to a project dashboard and a summary
71
+ * panel. `Metric`'s delta is a `number` and the sign is the direction, so a rising
72
+ * mark cannot be drawn on a falling reading; a Block that took `{ value, direction }`
73
+ * could, and the mistake would be invisible in review and visible to every reader of
74
+ * that dashboard. It also puts the label under the value, which is the arrangement a
75
+ * dashboard row wants, because a row is scanned by its figures and settled by its
76
+ * names. And `Sparkline` draws the numbers behind its shape as a table in the
77
+ * document, so a metric row of six costs six tables in the accessibility tree rather
78
+ * than six pictures nobody can query. The cost is stated rather than implied: a series
74
79
  * needs a name and a series that is not flat, and a caller who passes an empty array
75
80
  * or a series of one repeated value gets `Sparkline`'s own refusal, which is the
76
81
  * right place for it.
@@ -136,6 +141,12 @@ export function Dashboard01({ eyebrow, title, description, header, metrics = [],
136
141
  // The gap between the header and the body is a fact about whether the lead
137
142
  // drew anything, so it arrives with that fact rather than as a margin on
138
143
  // two of the three possible children.
139
- hasLead ? 'mt-8' : null, hasRail ? 'lg:grid lg:grid-cols-4 lg:items-start lg:gap-6' : null), children: [_jsxs("div", { "data-slot": "dashboard-01-main", className: cn('flex min-w-0 flex-col gap-6', hasRail ? 'lg:col-span-3' : null), children: [metrics.length > 0 ? (_jsx("div", { "data-slot": "dashboard-01-metrics", className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4", children: metrics.map((metric) => (_jsxs(Card, { "data-slot": "dashboard-01-metric", "data-metric": metric.label, className: "gap-4 py-5", children: [_jsxs(CardContent, { className: "flex flex-col gap-3", children: [_jsx(Metric, { value: metric.value, label: metric.label, delta: metric.delta, deltaFormat: metric.deltaFormat, hint: metric.hint }), metric.sparkline === undefined ? null : (_jsx("div", { "data-slot": "dashboard-01-sparkline", className: "flex", children: _jsx(Sparkline, { values: metric.sparkline, label: metric.sparklineLabel, className: "ms-auto" }) }))] }), metric.href === undefined ? null : (_jsx(CardFooter, { "data-slot": "dashboard-01-metric-link", className: "justify-end", children: _jsx(CtaLink, { href: metric.href, variant: "ghost", size: "sm", children: metric.hrefLabel }) }))] }, metric.label))) })) : null, panels.length > 0 ? (_jsx("div", { "data-slot": "dashboard-01-panels", className: "grid gap-4 lg:grid-cols-6", children: panels.map((panel) => (_jsx("div", { "data-slot": "dashboard-01-panel", "data-panel": panel.id, className: SPAN[panel.span ?? 'full'], children: _jsxs(Card, { className: "h-full gap-4 py-5", children: [panel.title === undefined && panel.toolbar === undefined ? null : (_jsxs(CardHeader, { className: "grid-cols-[minmax(0,1fr)_auto] gap-x-3", children: [panel.title === undefined ? null : (_jsx(CardTitle, { as: PanelTitle, className: "text-base", children: panel.title })), panel.toolbar === undefined ? null : (_jsx("div", { "data-slot": "dashboard-01-panel-toolbar", className: "flex min-w-0 items-center gap-2", children: panel.toolbar }))] })), _jsx(CardContent, { children: panel.children }), panel.footer === undefined ? null : (_jsx(CardFooter, { "data-slot": "dashboard-01-panel-footer", children: panel.footer }))] }) }, panel.id))) })) : null, hasBody ? null : _jsx("div", { "data-slot": "dashboard-01-empty", children: empty })] }), hasRail ? (_jsx("div", { "data-slot": "dashboard-01-rail", className: "flex min-w-0 flex-col gap-4 lg:col-span-1", children: rail })) : null] })] }));
144
+ hasLead ? 'mt-8' : null, hasRail ? 'lg:grid lg:grid-cols-4 lg:items-start lg:gap-6' : null), children: [_jsxs("div", { "data-slot": "dashboard-01-main", className: cn('flex min-w-0 flex-col gap-6', hasRail ? 'lg:col-span-3' : null), children: [metrics.length > 0 ? (_jsx("div", { "data-slot": "dashboard-01-metrics", className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4", children: metrics.map((metric) => {
145
+ // The delta's words are the caller's own node, and `Metric` takes a
146
+ // formatter, so the node is placed through one. A delta with no words
147
+ // is left to `Metric`, which prints the number the caller passed.
148
+ const deltaWords = metric.deltaFormat;
149
+ return (_jsxs(Card, { "data-slot": "dashboard-01-metric", "data-metric": metric.key, className: "gap-4 py-5", children: [_jsxs(CardContent, { className: "flex flex-col gap-3", children: [_jsx(Metric, { value: metric.value, label: metric.label, delta: metric.delta, deltaFormat: deltaWords === undefined ? undefined : () => deltaWords, hint: metric.hint }), metric.series === undefined ? null : (_jsx("div", { "data-slot": "dashboard-01-sparkline", className: "flex", children: _jsx(Sparkline, { values: metric.series, label: metric.seriesLabel, className: "ms-auto" }) }))] }), metric.href === undefined ? null : (_jsx(CardFooter, { "data-slot": "dashboard-01-metric-link", className: "justify-end", children: _jsx(CtaLink, { href: metric.href, variant: "ghost", size: "sm", children: metric.hrefLabel }) }))] }, metric.key));
150
+ }) })) : null, panels.length > 0 ? (_jsx("div", { "data-slot": "dashboard-01-panels", className: "grid gap-4 lg:grid-cols-6", children: panels.map((panel) => (_jsx("div", { "data-slot": "dashboard-01-panel", "data-panel": panel.id, className: SPAN[panel.span ?? 'full'], children: _jsxs(Card, { className: "h-full gap-4 py-5", children: [panel.title === undefined && panel.toolbar === undefined ? null : (_jsxs(CardHeader, { className: "grid-cols-[minmax(0,1fr)_auto] gap-x-3", children: [panel.title === undefined ? null : (_jsx(CardTitle, { as: PanelTitle, className: "text-base", children: panel.title })), panel.toolbar === undefined ? null : (_jsx("div", { "data-slot": "dashboard-01-panel-toolbar", className: "flex min-w-0 items-center gap-2", children: panel.toolbar }))] })), _jsx(CardContent, { children: panel.children }), panel.footer === undefined ? null : (_jsx(CardFooter, { "data-slot": "dashboard-01-panel-footer", children: panel.footer }))] }) }, panel.id))) })) : null, hasBody ? null : _jsx("div", { "data-slot": "dashboard-01-empty", children: empty })] }), hasRail ? (_jsx("div", { "data-slot": "dashboard-01-rail", className: "flex min-w-0 flex-col gap-4 lg:col-span-1", children: rail })) : null] })] }));
140
151
  }
141
152
  export default Dashboard01;
@@ -1,3 +1,3 @@
1
1
  export { Dashboard01, default } from './dashboard-01.js';
2
- export type { Dashboard01Metric, Dashboard01Panel, Dashboard01Props, Dashboard01Span, } from './dashboard-01.js';
2
+ export type { Dashboard01Panel, Dashboard01Props, Dashboard01Span } from './dashboard-01.js';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/blocks/dashboard-01/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAIrD,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,GAChB,MAAM,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/blocks/dashboard-01/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAIrD,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA"}