@nanisoft/prism-ui 0.16.1 → 1.1.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
@@ -0,0 +1,144 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useId } from 'react';
4
+ import { Field, FieldDescription, FieldError, FieldGroup } from '../../components/ui/field.js';
5
+ import { FormWizard, } from '../../components/ui/form-wizard.js';
6
+ import { Label } from '../../components/ui/label.js';
7
+ import { NEEDS_HIDDEN, fieldText, renderControl, serialize, SELF_LABELLED, } from '../../lib/field-render.js';
8
+ import { cn } from '../../lib/utils.js';
9
+ /**
10
+ * Whether a caller's step list is a form nobody can finish, checked before anything
11
+ * is drawn so the run fails once with the name of the step rather than once per
12
+ * field with a nameless control on the page.
13
+ *
14
+ * A step with no `id` is a step whose saved answers have nowhere to live, and a step
15
+ * whose `label` is not a string is a step whose rail label and heading would have to
16
+ * be kept in step by the caller. Both reach a developer in a console and never a
17
+ * reader, which is what makes this a refusal rather than copy.
18
+ */
19
+ function assertSteps(steps) {
20
+ if (steps.length === 0) {
21
+ throw new Error('RecordWizard01: steps is empty, so the rail would be a row of nothing above a form with no route ' +
22
+ 'through it. Pass the steps the record has.');
23
+ }
24
+ for (const [index, step] of steps.entries()) {
25
+ if (step.id === undefined) {
26
+ throw new Error(`RecordWizard01: the step at index ${index} declares no id, so the caller's own per-step state has ` +
27
+ 'nowhere to live and this Block cannot tell two steps apart. Pass a stable id.');
28
+ }
29
+ if (typeof step.label !== 'string') {
30
+ throw new Error(`RecordWizard01: the step "${step.id}" declares no string label, so the rail would draw a word this ` +
31
+ 'Block cannot read and the step heading and its rail label would be two names kept in step by the ' +
32
+ 'caller. Pass the one word both should carry.');
33
+ }
34
+ }
35
+ }
36
+ /**
37
+ * One step's fields, drawn under the heading the shipped wizard already drew.
38
+ *
39
+ * Every field is controlled, and an issue is drawn under the control that owns it
40
+ * only while that control is on this step. A description that is a node rather than
41
+ * a string is rendered here, because the shipped wizard takes a string for the line
42
+ * under its heading.
43
+ */
44
+ function StepFields({ step, values, onValueChange, issues, prefix, }) {
45
+ return (_jsxs(FieldGroup, { "data-slot": "record-wizard-01-fields", className: "flex flex-col gap-6", children: [typeof step.description === 'string' ? null : step.description, step.fields.map((field, fieldIndex) => {
46
+ const kind = field.kind.toLowerCase();
47
+ const id = `${prefix}-${step.id}-${fieldIndex}`;
48
+ const labelId = `${id}-label`;
49
+ const helpId = field.help === undefined ? undefined : `${id}-help`;
50
+ const fieldIssues = issues.filter((issue) => issue.field === field.key);
51
+ const errorId = fieldIssues.length > 0 ? `${id}-error` : undefined;
52
+ const describedBy = helpId === undefined
53
+ ? errorId
54
+ : errorId === undefined
55
+ ? helpId
56
+ : `${helpId} ${errorId}`;
57
+ const ctx = {
58
+ id,
59
+ labelId,
60
+ describedBy,
61
+ invalid: fieldIssues.length > 0,
62
+ text: fieldText(field),
63
+ values,
64
+ setValue: onValueChange,
65
+ controlled: true,
66
+ };
67
+ return (_jsxs(Field, { "data-slot": "record-wizard-01-field", 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": "record-wizard-01-issue", children: issue.message }, issueIndex))) }))] }, field.key));
68
+ })] }));
69
+ }
70
+ /**
71
+ * The multi-step record write form: one group of fields at a time above the rail
72
+ * the package already ships.
73
+ *
74
+ * **This is the write form's second arrangement and not a `-02`.** A wizard draws
75
+ * one group of fields at a time, puts a rail above them, and asks a decision the
76
+ * plain form never asks, which is whether this step may be left forwards. One Item
77
+ * could not draw both without gaining the rail, the partition and that decision. It
78
+ * is a property of how many fields the record has rather than one of two renderings
79
+ * a consumer picks between on purpose, which is what a `-02` is for, so it earns
80
+ * its own name.
81
+ *
82
+ * **Back, the forward control and the rail are the shipped wizard's.** This Block
83
+ * renders none of them: it composes `FormWizard`, hands it the steps, and draws each
84
+ * step's fields as that step's children. Every one of those controls is a call on
85
+ * the caller's own step change, and the rail is an ordered indicator with no opinion
86
+ * about whether a reader may move, so a caller who wants a navigable rail writes
87
+ * call to action links carrying their own destinations beside this Block. A Block
88
+ * that cannot make a control work should not render one, which is why this one
89
+ * renders none of the three.
90
+ *
91
+ * **The stepped arm declares no submission arm of its own.** On the last step the
92
+ * forward control is the form's submit and it reports the last index with the
93
+ * direction `forward`, so the finish signal is a callback the caller already passes
94
+ * and no second prop is needed to name it. An `action` arm would be an arm that
95
+ * cannot be honoured: the shipped wizard refuses the browser's own submission
96
+ * because its submit *is* the forward control. A caller whose answer is a URL post
97
+ * composes the per-step form beside this Block.
98
+ *
99
+ * **Every field is controlled and the Block holds no value of its own across a step
100
+ * change.** Only the current step's fields are in the document, so a step that
101
+ * unmounts takes every uncontrolled value in it with it, and there is no draft to
102
+ * restore from because a Block that held the draft would be holding application
103
+ * state. The values are the consumer's from the first keystroke, and the cost is one
104
+ * state object per screen instead of one form.
105
+ *
106
+ * **The step is the consumer's, and the Block draws the step it was handed and no
107
+ * reachability at all.** It draws nothing about a step it is not showing: no
108
+ * completed mark beyond the one the shipped rail already derives from the index, no
109
+ * disabled step, no skipped step and no count of what has been answered. An index
110
+ * the specification does not contain draws a real step rather than nothing, because
111
+ * a region with no route out is worse and drawing the nearest step is the one answer
112
+ * that is not a claim about a cause. It publishes no state for a step that does not
113
+ * exist, because a step that does not exist, a stale link and a step this reader may
114
+ * not see are one index and three sentences.
115
+ *
116
+ * **An issue naming a key off the current step is left undrawn and the reader is not
117
+ * moved.** Validation is the consumer's, entirely: this Block evaluates no rule,
118
+ * carries no validator and derives no fraction complete, because a fraction over a
119
+ * sequence whose steps are gated by rules it cannot see is false the moment a
120
+ * consumer skips one. A cross-step rule arrives as an issue and is drawn only while
121
+ * its control is on the step being drawn.
122
+ *
123
+ * It is a client Component, because the shipped wizard is one and every value prop
124
+ * here is a function the caller hands it, which is a client-to-client boundary
125
+ * wherever it is written.
126
+ */
127
+ export function RecordWizard01({ steps, current, onStepChange, values, onValueChange, issues, backLabel, nextLabel, finishLabel, blockedLabel, progressLabel, issueLabel, instructionsLabel, className, }) {
128
+ const prefix = useId();
129
+ assertSteps(steps);
130
+ /*
131
+ Every step is mapped to the shipped wizard's own step shape, and each one's
132
+ children are that step's fields. The shipped wizard clamps the index and renders
133
+ only the current step's children, so an index outside the specification draws the
134
+ nearest real step rather than nothing.
135
+ */
136
+ const wizardSteps = steps.map((step) => ({
137
+ id: step.id,
138
+ label: step.label,
139
+ description: typeof step.description === 'string' ? step.description : undefined,
140
+ children: (_jsx(StepFields, { step: step, values: values, onValueChange: onValueChange, issues: issues ?? [], prefix: prefix })),
141
+ }));
142
+ return (_jsx("div", { "data-slot": "record-wizard-01", className: cn('flex w-full flex-col gap-8', className), children: _jsx(FormWizard, { steps: wizardSteps, current: current, onStepChange: onStepChange, backLabel: backLabel, nextLabel: nextLabel, finishLabel: finishLabel, blockedLabel: blockedLabel, progressLabel: progressLabel, issueLabel: issueLabel, instructionsLabel: instructionsLabel }) }));
143
+ }
144
+ export default RecordWizard01;
@@ -4,7 +4,8 @@ import { type HeadingLevel } from '../../components/ui/section.js';
4
4
  * One role a member can hold, as the caller names it.
5
5
  *
6
6
  * The option list is the caller's rather than a `Role` union in this module, and
7
- * the argument is the same one `SettingsPanel01`'s `options` makes: the set of
7
+ * the argument is the same one the shared field specification's choice options
8
+ * make: the set of
8
9
  * roles a workspace has is that workspace's own fact, it changes with its plan
9
10
  * and with its commercial agreements, and a Block that shipped a list would
10
11
  * install a permission model into every consumer's settings page.
@@ -1 +1 @@
1
- {"version":3,"file":"settings-members.d.ts","sourceRoot":"","sources":["../../../src/blocks/settings-members-01/settings-members.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"settings-members.d.ts","sourceRoot":"","sources":["../../../src/blocks/settings-members-01/settings-members.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAS,MAAM,OAAO,CAAA;AAK7C,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,6BAA6B,CAAA;AAkBpC;;;;;;;;;GASG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,+CAA+C;IAC/C,EAAE,EAAE,MAAM,CAAA;IACV;;;;;;OAMG;IACH,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC;;;OAGG;IACH,EAAE,EAAE,MAAM,CAAA;IACV,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAA;IACZ;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACxB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,KAAK,MAAM,CAAA;IAChD;;;;;;OAMG;IACH,MAAM,CAAC,EAAE;QACP,2EAA2E;QAC3E,GAAG,CAAC,EAAE,MAAM,CAAA;QACZ,wDAAwD;QACxD,IAAI,EAAE,MAAM,CAAA;KACb,CAAA;IACD;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,SAAS,CAAA;CACpB,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,4EAA4E;IAC5E,EAAE,EAAE,MAAM,CAAA;IACV,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACxB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,mCAAmC;IACnC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAA;IAC9B,oCAAoC;IACpC,MAAM,EAAE,SAAS,CAAA;IACjB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,+EAA+E;IAC/E,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,yFAAyF;IACzF,KAAK,EAAE,SAAS,CAAA;IAChB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB,oFAAoF;IACpF,OAAO,EAAE,SAAS,qBAAqB,EAAE,CAAA;IACzC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,SAAS,yBAAyB,EAAE,CAAA;IAClD;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,SAAS,CAAA;IACxB;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAA;IAC5C;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,MAAM,CAAA;IACnD;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IACzD;;;;;;;;OAQG;IACH,KAAK,EAAE,SAAS,CAAA;IAChB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,EAAE,SAAS,qBAAqB,EAAE,CAAA;IAC1C,8DAA8D;IAC9D,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAkGD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsHG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,KAAK,EACL,WAAW,EACX,OAAO,EACP,WAAW,EACX,YAAY,EACZ,WAAW,EACX,WAAW,EACX,SAAS,EACT,YAAY,EACZ,KAAK,EACL,OAAO,EACP,YAAmB,EACnB,SAAS,GACV,EAAE,sBAAsB,+BAmUxB;AAED,eAAe,iBAAiB,CAAA"}
@@ -1,3 +1,3 @@
1
1
  export { SettingsPanel01, default } from './settings-panel.js';
2
- export type { SettingsPanel01Props, SettingsPanelField, SettingsPanelOption, SettingsPanelSection, } from './settings-panel.js';
2
+ export type { SettingsPanel01Props } from './settings-panel.js';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/blocks/settings-panel-01/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC3D,YAAY,EACV,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/blocks/settings-panel-01/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC3D,YAAY,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA"}
@@ -1,81 +1,179 @@
1
- import { type FormEvent, type ReactNode } from 'react';
1
+ import { type ReactNode } from 'react';
2
2
  import { type HeadingLevel } from '../../components/ui/section.js';
3
- export type SettingsPanelOption = {
4
- label: string;
5
- value: string;
6
- };
7
- type SettingsPanelFieldBase = {
8
- id: string;
9
- label: string;
10
- description?: string;
11
- disabled?: boolean;
12
- };
13
- export type SettingsPanelField = (SettingsPanelFieldBase & {
14
- kind: 'text';
15
- type?: 'text' | 'email' | 'url';
16
- placeholder?: string;
17
- value?: string;
18
- defaultValue?: string;
19
- onChange?: (value: string) => void;
20
- }) | (SettingsPanelFieldBase & {
21
- kind: 'textarea';
22
- placeholder?: string;
23
- rows?: number;
24
- value?: string;
25
- defaultValue?: string;
26
- onChange?: (value: string) => void;
27
- }) | (SettingsPanelFieldBase & {
28
- kind: 'switch';
29
- checked?: boolean;
30
- defaultChecked?: boolean;
31
- onCheckedChange?: (checked: boolean) => void;
32
- }) | (SettingsPanelFieldBase & {
33
- kind: 'select';
34
- placeholder?: string;
35
- options: SettingsPanelOption[];
36
- value?: string;
37
- defaultValue?: string;
38
- onValueChange?: (value: string) => void;
39
- });
40
- export type SettingsPanelSection = {
41
- id: string;
42
- title: string;
43
- description?: string;
44
- fields: SettingsPanelField[];
45
- };
46
- export type SettingsPanel01Props = {
47
- title: string;
3
+ import type { FieldSpecGroup } from '../../lib/spec.js';
4
+ import type { RecordForm01Issue } from '../record-form-01/index.js';
5
+ /** The members every arm of the save union shares. */
6
+ type SettingsPanel01Base = {
7
+ /**
8
+ * The panel's own heading, drawn as the card title.
9
+ *
10
+ * Required, because a settings region with no name is a card a reader has to
11
+ * identify from its fields. The groups inside take their level from this one, so
12
+ * moving the panel in a document moves every heading in it together.
13
+ */
14
+ title: ReactNode;
15
+ /** One line under the heading, for the part the title cannot carry. */
16
+ description?: ReactNode;
17
+ /**
18
+ * The settings groups, as the shared field specification.
19
+ *
20
+ * Each group is a `FieldSpecGroup` from `@nanisoft/prism-ui/spec`: an optional
21
+ * heading, an optional description and an ordered list of `FieldSpec`. A field
22
+ * carries a stable `key`, a required `label`, a required `kind` drawn from
23
+ * Prism's own input vocabulary, and optional help, hint, placeholder, disabled
24
+ * flag and starting value. A control this package does not ship is the `slot`
25
+ * arm, and the Block still draws the label, the help and the error around the
26
+ * caller's node, so a field has the same shell whether Prism drew the control or
27
+ * the caller did. Order is the array's order, and the Block never reorders, hides
28
+ * or drops a field.
29
+ */
30
+ groups: readonly FieldSpecGroup[];
31
+ /**
32
+ * The values, controlled, keyed by field.
33
+ *
34
+ * **The values are the caller's, and the change handler is where a setting leaves.**
35
+ * A region that applies on change passes an `onValueChange` that applies the
36
+ * mutation; a region that saves explicitly passes one that updates its own state and
37
+ * a save arm below. The Block holds no value of its own and owns no storage, so it
38
+ * cannot see whether the setting is the organisation's, the project's or the
39
+ * reader's, and it cannot revert a value it never kept.
40
+ */
41
+ values: Record<string, unknown>;
42
+ /** Sets one field's value, keyed by field, on every change. */
43
+ onValueChange: (key: string, value: unknown) => void;
44
+ /**
45
+ * How many columns the fields sit in.
46
+ *
47
+ * One at every width by default, and one column again at the narrow breakpoint
48
+ * when two are asked for. There is no per-field layout prop and no slot per
49
+ * region.
50
+ *
51
+ * @defaultValue 1
52
+ */
53
+ columns?: 1 | 2;
54
+ /**
55
+ * The issues to draw, keyed by field.
56
+ *
57
+ * The shape `FormDialog`, `FormWizard` and the record write form already publish:
58
+ * an entry names a field's `key` and a message in the product's own words, and
59
+ * the message is drawn under the control that owns it. A caller who wants a rule
60
+ * before a mutation runs it itself and passes the result here.
61
+ */
62
+ issues?: readonly RecordForm01Issue[];
63
+ /**
64
+ * A message about the submission rather than about a control.
65
+ *
66
+ * It names no field and marks at most one, which is the arrangement `AuthForm01`
67
+ * argues for.
68
+ */
69
+ submitError?: ReactNode;
70
+ /**
71
+ * The caller's own node placed beside the save, such as a cancel link.
72
+ *
73
+ * **A node and not a declared secondary action.** The former `secondaryAction`
74
+ * prop took a label and an optional handler and rendered a button, so a caller who
75
+ * passed a label and no function got a focusable control, announced as a button,
76
+ * that activated to nothing. What replaces it is a node the caller wrote, placed
77
+ * without styling: a `CtaLink` with its required `href`, or a control the caller
78
+ * wired.
79
+ */
80
+ footerStart?: ReactNode;
48
81
  /**
49
82
  * Heading level for the card's title. See `HeadingLevel`.
50
83
  *
51
- * This Block draws no Section heading of its own, so the card title is the one
52
- * heading it renders and takes the level directly rather than a step below one.
53
84
  * The groups inside take their level from this one, so moving the panel in a
54
85
  * document moves every heading in it together.
86
+ *
87
+ * @defaultValue 'h2'
55
88
  */
56
89
  headingLevel?: HeadingLevel;
57
- description?: string;
58
- /** The settings groups, each rendered with a heading and its own fields. */
59
- sections: SettingsPanelSection[];
60
- /** The submit button label. Omit to render no footer. */
61
- submitLabel?: string;
62
- onSubmit?: (event: FormEvent<HTMLFormElement>) => void;
63
- /** A secondary control, such as Cancel. */
64
- secondaryAction?: {
65
- label: string;
66
- onClick?: () => void;
67
- };
68
- /** Extra content in the footer, e.g. a status note. */
69
- footer?: ReactNode;
90
+ /** Layout only. Changing a Prism-owned visual property from here is prohibited. */
91
+ className?: string;
70
92
  };
71
93
  /**
72
- * A settings form grouped into sections.
94
+ * The props a `SettingsPanel01` accepts.
95
+ *
96
+ * **A discriminated union over when the value leaves, and one arm is the absence of
97
+ * a save.** `action` posts the form to a URL the caller names; `onSubmit` hands the
98
+ * form's own element to a function and makes the Block a client Component; `submit`
99
+ * is a slot holding the caller's own control, placed unstyled in the footer. The
100
+ * first arm carries none of the three, and it is the on-change setting: a region
101
+ * that applies each change through the field's own handler has no moment at which
102
+ * the value is refused and draws no footer at all. Each arm forbids the others, so
103
+ * the compiler holds the rule rather than this paragraph.
104
+ */
105
+ export type SettingsPanel01Props = (SettingsPanel01Base & {
106
+ action?: never;
107
+ onSubmit?: never;
108
+ submit?: never;
109
+ submitLabel?: never;
110
+ }) | (SettingsPanel01Base & {
111
+ /** The URL the form posts to, the browser's own activation. */
112
+ action: string;
113
+ /** The label of the save control. */
114
+ submitLabel: ReactNode;
115
+ onSubmit?: never;
116
+ submit?: never;
117
+ }) | (SettingsPanel01Base & {
118
+ /** Called with the form element when the reader submits. */
119
+ onSubmit: (form: HTMLFormElement) => void;
120
+ /** The label of the save control. */
121
+ submitLabel: ReactNode;
122
+ action?: never;
123
+ submit?: never;
124
+ }) | (SettingsPanel01Base & {
125
+ /** The caller's own control, placed unstyled in the footer. */
126
+ submit: ReactNode;
127
+ action?: never;
128
+ onSubmit?: never;
129
+ submitLabel?: never;
130
+ });
131
+ /**
132
+ * A settings region: the shared field specification in a card, measured against the
133
+ * record write form Block.
134
+ *
135
+ * **The archetype is answered by the record write form Block and earns no Item of
136
+ * its own.** A setting changes behaviour and is often no record at all, but that
137
+ * difference is a fact about what sits behind the surface rather than about the
138
+ * surface, which is fields in groups with labels and help. So this Block takes the
139
+ * same `FieldSpec`, `FieldSpecGroup` and `FieldKind` the write form takes, which
140
+ * brings the `slot` arm with it and means the vocabulary a consumer learns on a
141
+ * record write form is the vocabulary here. Its own former field declaration, a
142
+ * union of text, textarea, switch and select, is gone from the published interface.
143
+ *
144
+ * **The one thing that differs is when the value leaves, and that is a caller's
145
+ * callback rather than a shape Prism can draw.** A setting may apply on change, on
146
+ * blur or at a save. A field whose change handler applies its mutation is a field
147
+ * that applies on change, and a region that saves explicitly passes `action` or
148
+ * `onSubmit` exactly as the write form does. Nothing in the surface tells the two
149
+ * apart to a reader, and Prism does not choose. A region that applies on change
150
+ * passes none of the three save arms and draws no footer.
151
+ *
152
+ * **It renders no revert control, no reset to defaults control and no storage of any
153
+ * kind.** A setting that applies on change has no moment at which the value is
154
+ * refused, so the caller's honest answers are to keep the previous value itself, or
155
+ * to accept the change and report the failure in its own `Alert`, `Toast` or
156
+ * `LiveRegion`. A revert control is refused twice over: a Block ships no behaviour
157
+ * and so cannot wire one, and it holds no previous value and so has nothing to
158
+ * revert to.
159
+ *
160
+ * **It draws no tab strip and no rail.** Which regions exist, what they are called
161
+ * and whether one of them is a destination are the consumer's information
162
+ * architecture. A tabbed settings screen is a composition of the shell, the page
163
+ * header, the tabs and this Block, which `SettingsPage` already ships, and a rail is
164
+ * the shell's own or the consumer's own links beside the regions. The Block also
165
+ * owns no persistence, no dirty tracking, no unsaved-changes guard, no reset, no
166
+ * navigation, no scope and no aggregate: it does not know whether a setting is the
167
+ * organisation's, the project's or the reader's, which is the whole difference
168
+ * between an organisation's default and a personal preference, and the words for
169
+ * that are the caller's.
73
170
  *
74
- * A field is a small object describing one control: a text input, a textarea,
75
- * a select or a switch, with its label, description and value handlers. The
76
- * block renders the card, the groups and the footer; it owns no values and no
77
- * copy, so a consumer wires it to whatever form state or mutation they use.
171
+ * **The save control is `type="submit"` inside a `<form>` the Block renders, and the
172
+ * Block never wires a save to a handler of its own.** A field whose control this
173
+ * package does not ship carries the `slot` arm, and the Block draws the label, the
174
+ * help and the error around the caller's node. It is a client Component for the same
175
+ * reason the write form is: an `onSubmit` is a function, and a function is state.
78
176
  */
79
- export declare function SettingsPanel01({ title, description, sections, submitLabel, onSubmit, secondaryAction, footer, headingLevel, }: SettingsPanel01Props): import("react").JSX.Element;
177
+ export declare function SettingsPanel01(props: SettingsPanel01Props): import("react").JSX.Element;
80
178
  export default SettingsPanel01;
81
179
  //# sourceMappingURL=settings-panel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"settings-panel.d.ts","sourceRoot":"","sources":["../../../src/blocks/settings-panel-01/settings-panel.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"settings-panel.d.ts","sourceRoot":"","sources":["../../../src/blocks/settings-panel-01/settings-panel.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAyB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAa7D,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAS3E,OAAO,KAAK,EAAa,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAE/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAE1D,sDAAsD;AACtD,KAAK,mBAAmB,GAAG;IACzB;;;;;;OAMG;IACH,KAAK,EAAE,SAAS,CAAA;IAChB,uEAAuE;IACvE,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB;;;;;;;;;;;;OAYG;IACH,MAAM,EAAE,SAAS,cAAc,EAAE,CAAA;IACjC;;;;;;;;;OASG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,+DAA+D;IAC/D,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IACpD;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;IACf;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAA;IACrC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,oBAAoB,GAC5B,CAAC,mBAAmB,GAAG;IACrB,MAAM,CAAC,EAAE,KAAK,CAAA;IACd,QAAQ,CAAC,EAAE,KAAK,CAAA;IAChB,MAAM,CAAC,EAAE,KAAK,CAAA;IACd,WAAW,CAAC,EAAE,KAAK,CAAA;CACpB,CAAC,GACF,CAAC,mBAAmB,GAAG;IACrB,+DAA+D;IAC/D,MAAM,EAAE,MAAM,CAAA;IACd,qCAAqC;IACrC,WAAW,EAAE,SAAS,CAAA;IACtB,QAAQ,CAAC,EAAE,KAAK,CAAA;IAChB,MAAM,CAAC,EAAE,KAAK,CAAA;CACf,CAAC,GACF,CAAC,mBAAmB,GAAG;IACrB,4DAA4D;IAC5D,QAAQ,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAA;IACzC,qCAAqC;IACrC,WAAW,EAAE,SAAS,CAAA;IACtB,MAAM,CAAC,EAAE,KAAK,CAAA;IACd,MAAM,CAAC,EAAE,KAAK,CAAA;CACf,CAAC,GACF,CAAC,mBAAmB,GAAG;IACrB,+DAA+D;IAC/D,MAAM,EAAE,SAAS,CAAA;IACjB,MAAM,CAAC,EAAE,KAAK,CAAA;IACd,QAAQ,CAAC,EAAE,KAAK,CAAA;IAChB,WAAW,CAAC,EAAE,KAAK,CAAA;CACpB,CAAC,CAAA;AAEN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,+BAwJ1D;AAED,eAAe,eAAe,CAAA"}
@@ -1,43 +1,102 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Fragment } from 'react';
3
+ import { useId } from 'react';
4
4
  import { Button } from '../../components/ui/button.js';
5
5
  import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, } from '../../components/ui/card.js';
6
- import { Field, FieldDescription, FieldGroup, FieldLabel, } from '../../components/ui/field.js';
7
- import { Input } from '../../components/ui/input.js';
8
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../../components/ui/select.js';
9
- import { Separator } from '../../components/ui/separator.js';
10
- import { Switch } from '../../components/ui/switch.js';
6
+ import { Field, FieldDescription, FieldError, FieldGroup } from '../../components/ui/field.js';
7
+ import { Label } from '../../components/ui/label.js';
11
8
  import { childLevel } from '../../components/ui/section.js';
12
- import { Textarea } from '../../components/ui/textarea.js';
13
- function SettingsField({ field }) {
14
- if (field.kind === 'switch') {
15
- return (_jsxs(Field, { className: "flex-row items-center justify-between gap-4", children: [_jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx(FieldLabel, { htmlFor: field.id, children: field.label }), field.description ? (_jsx(FieldDescription, { children: field.description })) : null] }), _jsx(Switch, { id: field.id, checked: field.checked, defaultChecked: field.defaultChecked, onCheckedChange: field.onCheckedChange, disabled: field.disabled })] }));
16
- }
17
- if (field.kind === 'select') {
18
- return (_jsxs(Field, { children: [_jsx(FieldLabel, { htmlFor: field.id, children: field.label }), _jsxs(Select, { value: field.value, defaultValue: field.defaultValue, onValueChange: field.onValueChange
19
- ? (value) => field.onValueChange?.(value ?? '')
20
- : undefined, disabled: field.disabled, items: Object.fromEntries(field.options.map((option) => [option.value, option.label])), children: [_jsx(SelectTrigger, { id: field.id, className: "w-full", children: _jsx(SelectValue, { placeholder: field.placeholder }) }), _jsx(SelectContent, { children: field.options.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))) })] }), field.description ? _jsx(FieldDescription, { children: field.description }) : null] }));
21
- }
22
- if (field.kind === 'textarea') {
23
- return (_jsxs(Field, { children: [_jsx(FieldLabel, { htmlFor: field.id, children: field.label }), _jsx(Textarea, { id: field.id, rows: field.rows, placeholder: field.placeholder, value: field.value, defaultValue: field.defaultValue, onChange: field.onChange ? (event) => field.onChange?.(event.target.value) : undefined, disabled: field.disabled }), field.description ? _jsx(FieldDescription, { children: field.description }) : null] }));
24
- }
25
- return (_jsxs(Field, { children: [_jsx(FieldLabel, { htmlFor: field.id, children: field.label }), _jsx(Input, { id: field.id, type: field.type ?? 'text', placeholder: field.placeholder, value: field.value, defaultValue: field.defaultValue, onChange: field.onChange ? (event) => field.onChange?.(event.target.value) : undefined, disabled: field.disabled }), field.description ? _jsx(FieldDescription, { children: field.description }) : null] }));
26
- }
9
+ import { fieldText, NEEDS_HIDDEN, renderControl, serialize, SELF_LABELLED, } from '../../lib/field-render.js';
10
+ import { cn } from '../../lib/utils.js';
27
11
  /**
28
- * A settings form grouped into sections.
12
+ * A settings region: the shared field specification in a card, measured against the
13
+ * record write form Block.
14
+ *
15
+ * **The archetype is answered by the record write form Block and earns no Item of
16
+ * its own.** A setting changes behaviour and is often no record at all, but that
17
+ * difference is a fact about what sits behind the surface rather than about the
18
+ * surface, which is fields in groups with labels and help. So this Block takes the
19
+ * same `FieldSpec`, `FieldSpecGroup` and `FieldKind` the write form takes, which
20
+ * brings the `slot` arm with it and means the vocabulary a consumer learns on a
21
+ * record write form is the vocabulary here. Its own former field declaration, a
22
+ * union of text, textarea, switch and select, is gone from the published interface.
23
+ *
24
+ * **The one thing that differs is when the value leaves, and that is a caller's
25
+ * callback rather than a shape Prism can draw.** A setting may apply on change, on
26
+ * blur or at a save. A field whose change handler applies its mutation is a field
27
+ * that applies on change, and a region that saves explicitly passes `action` or
28
+ * `onSubmit` exactly as the write form does. Nothing in the surface tells the two
29
+ * apart to a reader, and Prism does not choose. A region that applies on change
30
+ * passes none of the three save arms and draws no footer.
31
+ *
32
+ * **It renders no revert control, no reset to defaults control and no storage of any
33
+ * kind.** A setting that applies on change has no moment at which the value is
34
+ * refused, so the caller's honest answers are to keep the previous value itself, or
35
+ * to accept the change and report the failure in its own `Alert`, `Toast` or
36
+ * `LiveRegion`. A revert control is refused twice over: a Block ships no behaviour
37
+ * and so cannot wire one, and it holds no previous value and so has nothing to
38
+ * revert to.
39
+ *
40
+ * **It draws no tab strip and no rail.** Which regions exist, what they are called
41
+ * and whether one of them is a destination are the consumer's information
42
+ * architecture. A tabbed settings screen is a composition of the shell, the page
43
+ * header, the tabs and this Block, which `SettingsPage` already ships, and a rail is
44
+ * the shell's own or the consumer's own links beside the regions. The Block also
45
+ * owns no persistence, no dirty tracking, no unsaved-changes guard, no reset, no
46
+ * navigation, no scope and no aggregate: it does not know whether a setting is the
47
+ * organisation's, the project's or the reader's, which is the whole difference
48
+ * between an organisation's default and a personal preference, and the words for
49
+ * that are the caller's.
29
50
  *
30
- * A field is a small object describing one control: a text input, a textarea,
31
- * a select or a switch, with its label, description and value handlers. The
32
- * block renders the card, the groups and the footer; it owns no values and no
33
- * copy, so a consumer wires it to whatever form state or mutation they use.
51
+ * **The save control is `type="submit"` inside a `<form>` the Block renders, and the
52
+ * Block never wires a save to a handler of its own.** A field whose control this
53
+ * package does not ship carries the `slot` arm, and the Block draws the label, the
54
+ * help and the error around the caller's node. It is a client Component for the same
55
+ * reason the write form is: an `onSubmit` is a function, and a function is state.
34
56
  */
35
- export function SettingsPanel01({ title, description, sections, submitLabel, onSubmit, secondaryAction, footer, headingLevel = 'h2', }) {
36
- // The panel title is the one heading the panel renders, and a group inside it is
37
- // one step below, so the whole outline moves together when the panel does.
38
- const Title = headingLevel;
39
- const GroupTitle = childLevel(headingLevel);
40
- const hasFooter = Boolean(submitLabel || secondaryAction || footer);
41
- return (_jsx("form", { onSubmit: onSubmit, className: "w-full", children: _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: _jsx(Title, { children: title }) }), description ? _jsx(CardDescription, { children: description }) : null] }), _jsx(CardContent, { className: "flex flex-col", children: sections.map((section, index) => (_jsxs(Fragment, { children: [index > 0 ? _jsx(Separator, { className: "my-6" }) : null, _jsxs("section", { className: "flex flex-col gap-4", "aria-labelledby": `${section.id}-heading`, children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(GroupTitle, { id: `${section.id}-heading`, className: "text-lg font-semibold tracking-tight", children: section.title }), section.description ? (_jsx("p", { className: "text-muted-foreground text-sm", children: section.description })) : null] }), _jsx(FieldGroup, { children: section.fields.map((field) => (_jsx(SettingsField, { field: field }, field.id))) })] })] }, section.id))) }), hasFooter ? (_jsxs(CardFooter, { className: "justify-end gap-2", children: [footer, secondaryAction ? (_jsx(Button, { type: "button", variant: "outline", onClick: secondaryAction.onClick, children: secondaryAction.label })) : null, submitLabel ? _jsx(Button, { type: "submit", children: submitLabel }) : null] })) : null] }) }));
57
+ export function SettingsPanel01(props) {
58
+ const { title, description, groups, values, onValueChange, columns = 1, issues, submitError, footerStart, headingLevel = 'h2', className, } = props;
59
+ const prefix = useId();
60
+ const hasSubmit = 'submit' in props;
61
+ const onSubmit = props.onSubmit;
62
+ const hasHandler = typeof onSubmit === 'function';
63
+ const hasAction = typeof props.action === 'string';
64
+ const hasSave = hasSubmit || hasHandler || hasAction;
65
+ const hasFooter = hasSave || footerStart !== undefined;
66
+ const handleSubmit = (event) => {
67
+ if (!hasHandler)
68
+ return;
69
+ event.preventDefault();
70
+ onSubmit(event.currentTarget);
71
+ };
72
+ const GroupHeading = childLevel(headingLevel);
73
+ const grid = columns === 2 ? 'grid grid-cols-1 gap-6 sm:grid-cols-2' : 'flex flex-col gap-6';
74
+ return (_jsx("form", { "data-slot": "settings-panel-01-form", ...(hasAction ? { action: props.action, method: 'post' } : null), onSubmit: hasHandler ? handleSubmit : undefined, className: cn('w-full', className), children: _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { as: headingLevel, className: "text-lg tracking-tight", children: title }), description ? _jsx(CardDescription, { children: description }) : null] }), _jsxs(CardContent, { className: "flex flex-col", children: [submitError ? (_jsx(FieldError, { "data-slot": "settings-panel-01-submit-error", children: submitError })) : null, groups.map((group, groupIndex) => {
75
+ const groupHeadingId = `${prefix}-g${groupIndex}`;
76
+ return (_jsxs("section", { "data-slot": "settings-panel-01-group", "aria-labelledby": group.label ? groupHeadingId : undefined, className: "flex flex-col gap-4 py-6 first:pt-0 last:pb-0 [&+&]:border-t", children: [group.label ? (_jsx(GroupHeading, { id: groupHeadingId, className: "font-semibold tracking-tight text-balance", children: group.label })) : null, group.description ? (_jsx("p", { className: "text-muted-foreground text-sm", children: group.description })) : null, _jsx(FieldGroup, { "data-slot": "settings-panel-01-fields", className: grid, children: group.fields.map((field, fieldIndex) => {
77
+ const kind = field.kind.toLowerCase();
78
+ const id = `${prefix}-f${fieldIndex}`;
79
+ const labelId = `${prefix}-l${fieldIndex}`;
80
+ const helpId = field.help === undefined ? undefined : `${prefix}-h${fieldIndex}`;
81
+ const fieldIssues = (issues ?? []).filter((issue) => issue.field === field.key);
82
+ const errorId = fieldIssues.length > 0 ? `${prefix}-e${fieldIndex}` : undefined;
83
+ const describedBy = helpId === undefined
84
+ ? errorId
85
+ : errorId === undefined
86
+ ? helpId
87
+ : `${helpId} ${errorId}`;
88
+ const ctx = {
89
+ id,
90
+ labelId,
91
+ describedBy,
92
+ invalid: fieldIssues.length > 0,
93
+ text: fieldText(field),
94
+ values,
95
+ setValue: onValueChange,
96
+ controlled: true,
97
+ };
98
+ return (_jsxs(Field, { "data-slot": "settings-panel-01-field", 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(ctx.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": "settings-panel-01-issue", children: issue.message }, issueIndex))) }))] }, field.key));
99
+ }) })] }, group.id ?? groupIndex));
100
+ })] }), hasFooter ? (_jsxs(CardFooter, { className: "justify-end gap-2", children: [footerStart, hasSubmit ? (props.submit) : hasSave ? (_jsx(Button, { "data-slot": "settings-panel-01-save", type: "submit", children: props.submitLabel })) : null] })) : null] }) }));
42
101
  }
43
102
  export default SettingsPanel01;
@@ -1,3 +1,3 @@
1
1
  export { Signup01, default } from './signup-01.js';
2
- export type { Signup01Password, Signup01Props, Signup01Reading, Signup01SignIn, Signup01Status, SignupField, SignupOption, SignupValue, } from './signup-01.js';
2
+ export type { Signup01Password, Signup01Props, Signup01Reading, Signup01SignIn, Signup01Status, SignupValue, } from './signup-01.js';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/blocks/signup-01/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAS/C,YAAY,EACV,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,cAAc,EACd,cAAc,EACd,WAAW,EACX,YAAY,EACZ,WAAW,GACZ,MAAM,aAAa,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/blocks/signup-01/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAO/C,YAAY,EACV,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,cAAc,EACd,cAAc,EACd,WAAW,GACZ,MAAM,aAAa,CAAA"}