@nanisoft/prism-ui 0.16.0 → 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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/blocks/activity-feed-01/activity-feed-01.d.ts +120 -190
- package/dist/blocks/activity-feed-01/activity-feed-01.d.ts.map +1 -1
- package/dist/blocks/activity-feed-01/activity-feed-01.js +107 -97
- package/dist/blocks/activity-feed-01/index.d.ts +1 -1
- package/dist/blocks/activity-feed-01/index.d.ts.map +1 -1
- package/dist/blocks/auth-form-01/auth-form.d.ts +86 -53
- package/dist/blocks/auth-form-01/auth-form.d.ts.map +1 -1
- package/dist/blocks/auth-form-01/auth-form.js +95 -31
- package/dist/blocks/auth-form-01/index.d.ts +1 -1
- package/dist/blocks/auth-form-01/index.d.ts.map +1 -1
- package/dist/blocks/calendar-01/calendar.d.ts +28 -0
- package/dist/blocks/calendar-01/calendar.d.ts.map +1 -1
- package/dist/blocks/calendar-01/calendar.js +15 -1
- package/dist/blocks/card-index-01/card-index.d.ts +225 -0
- package/dist/blocks/card-index-01/card-index.d.ts.map +1 -0
- package/dist/blocks/card-index-01/card-index.js +154 -0
- package/dist/blocks/card-index-01/index.d.ts +3 -0
- package/dist/blocks/card-index-01/index.d.ts.map +1 -0
- package/dist/blocks/card-index-01/index.js +1 -0
- package/dist/blocks/chart-card-01/chart-card-01.d.ts +23 -21
- package/dist/blocks/chart-card-01/chart-card-01.d.ts.map +1 -1
- package/dist/blocks/chart-card-01/chart-card-01.js +46 -1
- package/dist/blocks/chart-card-01/index.d.ts +1 -1
- package/dist/blocks/chart-card-01/index.d.ts.map +1 -1
- package/dist/blocks/chart-group-01/chart-group-01.d.ts +3 -3
- package/dist/blocks/chart-group-01/chart-group-01.d.ts.map +1 -1
- package/dist/blocks/contact-01/contact.d.ts +30 -82
- package/dist/blocks/contact-01/contact.d.ts.map +1 -1
- package/dist/blocks/contact-01/contact.js +59 -30
- package/dist/blocks/contact-01/index.d.ts +1 -1
- package/dist/blocks/contact-01/index.d.ts.map +1 -1
- package/dist/blocks/dashboard-01/dashboard-01.d.ts +26 -71
- package/dist/blocks/dashboard-01/dashboard-01.d.ts.map +1 -1
- package/dist/blocks/dashboard-01/dashboard-01.js +34 -23
- package/dist/blocks/dashboard-01/index.d.ts +1 -1
- package/dist/blocks/dashboard-01/index.d.ts.map +1 -1
- package/dist/blocks/data-table-01/data-table.d.ts +276 -59
- package/dist/blocks/data-table-01/data-table.d.ts.map +1 -1
- package/dist/blocks/data-table-01/data-table.js +217 -35
- package/dist/blocks/data-table-01/index.d.ts +1 -1
- package/dist/blocks/data-table-01/index.d.ts.map +1 -1
- package/dist/blocks/directory-01/directory-01.d.ts +23 -2
- package/dist/blocks/directory-01/directory-01.d.ts.map +1 -1
- package/dist/blocks/directory-01/directory-01.js +3 -3
- package/dist/blocks/empty-state-01/empty-state.d.ts +60 -21
- package/dist/blocks/empty-state-01/empty-state.d.ts.map +1 -1
- package/dist/blocks/empty-state-01/empty-state.js +52 -17
- package/dist/blocks/index-detail-01/index-detail.d.ts +85 -0
- package/dist/blocks/index-detail-01/index-detail.d.ts.map +1 -0
- package/dist/blocks/index-detail-01/index-detail.js +58 -0
- package/dist/blocks/index-detail-01/index.d.ts +3 -0
- package/dist/blocks/index-detail-01/index.d.ts.map +1 -0
- package/dist/blocks/index-detail-01/index.js +1 -0
- package/dist/blocks/index.d.ts +20 -8
- package/dist/blocks/index.d.ts.map +1 -1
- package/dist/blocks/index.js +7 -0
- package/dist/blocks/issue-detail-01/issue-detail.d.ts +18 -0
- package/dist/blocks/issue-detail-01/issue-detail.d.ts.map +1 -1
- package/dist/blocks/issue-detail-01/issue-detail.js +18 -0
- package/dist/blocks/nothing-chosen-01/index.d.ts +3 -0
- package/dist/blocks/nothing-chosen-01/index.d.ts.map +1 -0
- package/dist/blocks/nothing-chosen-01/index.js +1 -0
- package/dist/blocks/nothing-chosen-01/nothing-chosen.d.ts +119 -0
- package/dist/blocks/nothing-chosen-01/nothing-chosen.d.ts.map +1 -0
- package/dist/blocks/nothing-chosen-01/nothing-chosen.js +79 -0
- package/dist/blocks/project-dashboard-01/index.d.ts +1 -1
- package/dist/blocks/project-dashboard-01/index.d.ts.map +1 -1
- package/dist/blocks/project-dashboard-01/project-dashboard.d.ts +21 -27
- package/dist/blocks/project-dashboard-01/project-dashboard.d.ts.map +1 -1
- package/dist/blocks/project-dashboard-01/project-dashboard.js +45 -5
- package/dist/blocks/provisioning-01/index.d.ts +1 -1
- package/dist/blocks/provisioning-01/index.d.ts.map +1 -1
- package/dist/blocks/provisioning-01/provisioning.d.ts +9 -97
- package/dist/blocks/provisioning-01/provisioning.d.ts.map +1 -1
- package/dist/blocks/provisioning-01/provisioning.js +26 -13
- package/dist/blocks/record-detail-01/index.d.ts +3 -0
- package/dist/blocks/record-detail-01/index.d.ts.map +1 -0
- package/dist/blocks/record-detail-01/index.js +1 -0
- package/dist/blocks/record-detail-01/record-detail.d.ts +239 -0
- package/dist/blocks/record-detail-01/record-detail.d.ts.map +1 -0
- package/dist/blocks/record-detail-01/record-detail.js +150 -0
- package/dist/blocks/record-form-01/index.d.ts +3 -0
- package/dist/blocks/record-form-01/index.d.ts.map +1 -0
- package/dist/blocks/record-form-01/index.js +1 -0
- package/dist/blocks/record-form-01/record-form.d.ts +148 -0
- package/dist/blocks/record-form-01/record-form.d.ts.map +1 -0
- package/dist/blocks/record-form-01/record-form.js +107 -0
- package/dist/blocks/record-grid-01/index.d.ts +3 -0
- package/dist/blocks/record-grid-01/index.d.ts.map +1 -0
- package/dist/blocks/record-grid-01/index.js +1 -0
- package/dist/blocks/record-grid-01/record-grid.d.ts +145 -0
- package/dist/blocks/record-grid-01/record-grid.d.ts.map +1 -0
- package/dist/blocks/record-grid-01/record-grid.js +114 -0
- package/dist/blocks/record-wizard-01/index.d.ts +3 -0
- package/dist/blocks/record-wizard-01/index.d.ts.map +1 -0
- package/dist/blocks/record-wizard-01/index.js +1 -0
- package/dist/blocks/record-wizard-01/record-wizard.d.ts +152 -0
- package/dist/blocks/record-wizard-01/record-wizard.d.ts.map +1 -0
- package/dist/blocks/record-wizard-01/record-wizard.js +144 -0
- package/dist/blocks/settings-members-01/settings-members.d.ts +2 -1
- package/dist/blocks/settings-members-01/settings-members.d.ts.map +1 -1
- package/dist/blocks/settings-panel-01/index.d.ts +1 -1
- package/dist/blocks/settings-panel-01/index.d.ts.map +1 -1
- package/dist/blocks/settings-panel-01/settings-panel.d.ts +165 -67
- package/dist/blocks/settings-panel-01/settings-panel.d.ts.map +1 -1
- package/dist/blocks/settings-panel-01/settings-panel.js +92 -33
- package/dist/blocks/signup-01/index.d.ts +1 -1
- package/dist/blocks/signup-01/index.d.ts.map +1 -1
- package/dist/blocks/signup-01/signup-01.d.ts +10 -84
- package/dist/blocks/signup-01/signup-01.d.ts.map +1 -1
- package/dist/blocks/signup-01/signup-01.js +41 -23
- package/dist/blocks/stats-01/index.d.ts +5 -5
- package/dist/blocks/stats-01/index.d.ts.map +1 -1
- package/dist/blocks/stats-01/index.js +4 -4
- package/dist/blocks/stats-01/stats.d.ts +49 -14
- package/dist/blocks/stats-01/stats.d.ts.map +1 -1
- package/dist/blocks/stats-01/stats.js +65 -15
- package/dist/blocks/trend-01/index.d.ts +1 -1
- package/dist/blocks/trend-01/index.d.ts.map +1 -1
- package/dist/blocks/trend-01/trend.d.ts +26 -73
- package/dist/blocks/trend-01/trend.d.ts.map +1 -1
- package/dist/blocks/trend-01/trend.js +47 -30
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +93 -3
- package/dist/components/ui/metric.d.ts +4 -2
- package/dist/components/ui/metric.d.ts.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/lib/field-render.d.ts +107 -0
- package/dist/lib/field-render.d.ts.map +1 -0
- package/dist/lib/field-render.js +251 -0
- package/dist/lib/spec.d.ts +609 -0
- package/dist/lib/spec.d.ts.map +1 -0
- package/dist/lib/spec.js +1 -0
- package/dist/live/index.d.ts +2 -0
- package/dist/live/index.d.ts.map +1 -1
- package/dist/live/index.js +6 -0
- package/dist/live/message-thread-01/index.d.ts +3 -0
- package/dist/live/message-thread-01/index.d.ts.map +1 -0
- package/dist/live/message-thread-01/index.js +1 -0
- package/dist/live/message-thread-01/message-thread.d.ts +282 -0
- package/dist/live/message-thread-01/message-thread.d.ts.map +1 -0
- package/dist/live/message-thread-01/message-thread.js +221 -0
- package/dist/live/run-stream-01/run-stream.d.ts +2 -1
- package/dist/live/run-stream-01/run-stream.d.ts.map +1 -1
- package/dist/live/run-stream-01/run-stream.js +1 -7
- package/dist/live/status.d.ts +27 -0
- package/dist/live/status.d.ts.map +1 -0
- package/dist/live/status.js +15 -0
- package/dist/live/tool-call-row.d.ts +26 -0
- package/dist/live/tool-call-row.d.ts.map +1 -0
- package/dist/live/tool-call-row.js +60 -0
- package/dist/live/tool-ledger-01/tool-ledger.d.ts.map +1 -1
- package/dist/live/tool-ledger-01/tool-ledger.js +2 -42
- package/dist/pages/contact-page/index.d.ts +7 -7
- package/dist/pages/contact-page/index.d.ts.map +1 -1
- package/dist/pages/contact-page/index.js +17 -5
- package/dist/pages/docs-shell/docs-shell.d.ts +42 -30
- package/dist/pages/docs-shell/docs-shell.d.ts.map +1 -1
- package/dist/pages/docs-shell/docs-shell.js +70 -48
- package/dist/pages/document-page/document-page.d.ts +146 -0
- package/dist/pages/document-page/document-page.d.ts.map +1 -0
- package/dist/pages/document-page/document-page.js +80 -0
- package/dist/pages/document-page/index.d.ts +3 -0
- package/dist/pages/document-page/index.d.ts.map +1 -0
- package/dist/pages/document-page/index.js +1 -0
- package/dist/pages/index.d.ts +2 -0
- package/dist/pages/index.d.ts.map +1 -1
- package/dist/pages/index.js +6 -0
- package/dist/styles.css +59 -3
- 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
|
|
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":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAS,MAAM,OAAO,CAAA;AAK7C,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,6BAA6B,CAAA;AAkBpC
|
|
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,3 +1,3 @@
|
|
|
1
1
|
export { SettingsPanel01, default } from './settings-panel.js';
|
|
2
|
-
export type { SettingsPanel01Props
|
|
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,
|
|
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
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
2
|
import { type HeadingLevel } from '../../components/ui/section.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
58
|
-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
75
|
-
* a
|
|
76
|
-
*
|
|
77
|
-
*
|
|
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(
|
|
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":"AAEA,OAAO,
|
|
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 {
|
|
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,
|
|
7
|
-
import {
|
|
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 {
|
|
13
|
-
|
|
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
|
|
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
|
-
*
|
|
31
|
-
* a
|
|
32
|
-
*
|
|
33
|
-
*
|
|
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(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
|
|
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,
|
|
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;
|
|
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"}
|