@esheet/renderer 0.0.1

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/README.md ADDED
@@ -0,0 +1,212 @@
1
+ # @esheet/renderer
2
+
3
+ Read-only questionnaire form renderer for eSheet. Renders forms in fill-out mode with conditional visibility logic.
4
+
5
+ ## Features
6
+
7
+ - ✅ Renders all 19 eSheet field types (reuses `@esheet/fields` components)
8
+ - ✅ Conditional visibility enforcement (fields/sections hide based on logic rules)
9
+ - ✅ Section nesting with recursive rendering
10
+ - ✅ Initial response pre-fill support
11
+ - ✅ YAML/JSON schema parsing with Zod validation
12
+ - ✅ Ref API for collecting responses
13
+ - ✅ TypeScript-first with full type safety
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @esheet/renderer @esheet/fields @esheet/core
19
+ ```
20
+
21
+ Standalone and Blaze integrations now ship as separate packages:
22
+
23
+ ```bash
24
+ npm install @esheet/renderer-standalone
25
+ npm install @esheet/renderer-blaze
26
+ ```
27
+
28
+ Migration for old subpath imports:
29
+
30
+ - `@esheet/renderer/standalone` -> `@esheet/renderer-standalone`
31
+ - `@esheet/renderer/blaze` -> `@esheet/renderer-blaze`
32
+
33
+ ## Usage
34
+
35
+ ### Basic Example
36
+
37
+ ```tsx
38
+ import { EsheetRenderer } from '@esheet/renderer';
39
+ import type { FormDefinition } from '@esheet/core';
40
+
41
+ const myForm: FormDefinition = {
42
+ schemaType: 'mieforms-v1.0',
43
+ title: 'Patient Intake',
44
+ fields: [
45
+ {
46
+ id: 'name',
47
+ fieldType: 'text',
48
+ question: 'Full Name',
49
+ required: true,
50
+ },
51
+ {
52
+ id: 'age',
53
+ fieldType: 'text',
54
+ question: 'Age',
55
+ },
56
+ ],
57
+ };
58
+
59
+ function App() {
60
+ return (
61
+ <div className="app-container">
62
+ <EsheetRenderer formData={myForm} />
63
+ </div>
64
+ );
65
+ }
66
+ ```
67
+
68
+ ### With Response Collection
69
+
70
+ ```tsx
71
+ import { useRef } from 'react';
72
+ import { EsheetRenderer, type EsheetRendererHandle } from '@esheet/renderer';
73
+
74
+ function App() {
75
+ const rendererRef = useRef<EsheetRendererHandle>(null);
76
+
77
+ const handleSubmit = () => {
78
+ const responses = rendererRef.current?.getResponse();
79
+ console.log('Form responses:', responses);
80
+ // { name: '...', age: '...' }
81
+ };
82
+
83
+ return (
84
+ <>
85
+ <EsheetRenderer formData={myForm} ref={rendererRef} />
86
+ <button onClick={handleSubmit}>Submit</button>
87
+ </>
88
+ );
89
+ }
90
+ ```
91
+
92
+ ### With Pre-filled Data
93
+
94
+ ```tsx
95
+ <EsheetRenderer
96
+ formData={myForm}
97
+ initialResponses={{
98
+ name: 'John Doe',
99
+ age: '42',
100
+ }}
101
+ />
102
+ ```
103
+
104
+ ### With YAML/JSON String
105
+
106
+ ```tsx
107
+ const yamlSchema = `
108
+ schemaType: mieforms-v1.0
109
+ title: Simple Form
110
+ fields:
111
+ - id: q1
112
+ fieldType: text
113
+ question: Your name?
114
+ `;
115
+
116
+ <EsheetRenderer formData={yamlSchema} />;
117
+ ```
118
+
119
+ ## API
120
+
121
+ ### `<EsheetRenderer>`
122
+
123
+ **Props:**
124
+
125
+ - `formData: FormDefinition | string` - Form schema (object, JSON string, or YAML string)
126
+ - `initialResponses?: FormResponse` - Pre-fill form with initial data
127
+ - `className?: string` - Additional CSS classes for root container
128
+ - `ref?: Ref<EsheetRendererHandle>` - Access ref API for collecting responses
129
+
130
+ **Ref API:**
131
+
132
+ ```tsx
133
+ interface EsheetRendererHandle {
134
+ getResponse: () => FormResponse;
135
+ getFormStore: () => FormStore;
136
+ getUIStore: () => UIStore;
137
+ }
138
+ ```
139
+
140
+ ## Architecture
141
+
142
+ EsheetRenderer is a thin wrapper that:
143
+
144
+ 1. Creates form and UI stores (vanilla Zustand)
145
+ 2. Parses and validates input (YAML/JSON → Zod schema check)
146
+ 3. Loads definition into store
147
+ 4. Sets preview mode (read-only, no editing UI)
148
+ 5. Iterates over visible fields via `RendererBody`
149
+ 6. Renders each field via `FieldNode` (uses `@esheet/fields` components)
150
+
151
+ **Conditional Logic:**
152
+
153
+ - Reuses `form.isVisible()`, `form.isEnabled()`, `form.isRequired()` from core
154
+ - Sections auto-hide when all children are invisible
155
+ - Field visibility updates reactively when responses change
156
+
157
+ **Section Nesting:**
158
+
159
+ - `FieldNode` recursively renders section children
160
+ - Each depth level adds left border and padding
161
+ - Respects visibility rules at every level
162
+
163
+ ## Example: Conditional Visibility
164
+
165
+ ```tsx
166
+ const conditionalForm: FormDefinition = {
167
+ schemaType: 'mieforms-v1.0',
168
+ title: 'Conditional Form',
169
+ fields: [
170
+ {
171
+ id: 'hasAllergies',
172
+ fieldType: 'boolean',
173
+ question: 'Do you have any allergies?',
174
+ },
175
+ {
176
+ id: 'allergyList',
177
+ fieldType: 'longtext',
178
+ question: 'Please list your allergies',
179
+ visible: {
180
+ conditions: [
181
+ {
182
+ conditionType: 'comparison',
183
+ fieldId: 'hasAllergies',
184
+ operator: '==',
185
+ value: true,
186
+ },
187
+ ],
188
+ logicalOperator: 'AND',
189
+ },
190
+ },
191
+ ],
192
+ };
193
+
194
+ // "allergyList" only shows when "hasAllergies" is checked
195
+ <EsheetRenderer formData={conditionalForm} />;
196
+ ```
197
+
198
+ ## CSS Architecture
199
+
200
+ The renderer uses Tailwind CSS v4 with `ms:` prefix. CSS is compiled via `@tailwindcss/cli` and embedded into the JS bundle at build time — consumers never need to import a stylesheet. A scoped reset on `.esheet-renderer-root` prevents style leakage in either direction. Dark mode is supported via `.dark` class on the root.
201
+
202
+ ## License
203
+
204
+ MIT
205
+
206
+ ## Building
207
+
208
+ Run `nx build @esheet/renderer` to build the library.
209
+
210
+ ## Running unit tests
211
+
212
+ Run `nx test @esheet/renderer` to execute the unit tests via [Vitest](https://vitest.dev/).
@@ -0,0 +1,97 @@
1
+ import { default as default_2 } from 'react';
2
+ import { FormDefinition } from '@esheet/core';
3
+ import { FormResponse } from '@esheet/core';
4
+ import { FormStore } from '@esheet/core';
5
+ import { JSX } from 'react/jsx-runtime';
6
+ import { UIStore } from '@esheet/core';
7
+ import { ValidationError } from '@esheet/core';
8
+
9
+ /**
10
+ * EsheetRenderer - Read-only questionnaire form renderer
11
+ *
12
+ * Renders a form in fill-out mode with conditional visibility logic.
13
+ * Reuses all field components from @esheet/fields.
14
+ *
15
+ * @example
16
+ * ```tsx
17
+ * const rendererRef = useRef<EsheetRendererHandle>(null);
18
+ *
19
+ * <EsheetRenderer
20
+ * formData={myFormDefinition}
21
+ * initialResponses={{ field1: 'answer' }}
22
+ * ref={rendererRef}
23
+ * />
24
+ *
25
+ * // Later: get responses
26
+ * const responses = rendererRef.current?.getResponse();
27
+ * ```
28
+ */
29
+ export declare const EsheetRenderer: default_2.ForwardRefExoticComponent<EsheetRendererProps & default_2.RefAttributes<EsheetRendererHandle>>;
30
+
31
+ export declare interface EsheetRendererHandle {
32
+ /** Get current form responses */
33
+ getResponse: () => FormResponse;
34
+ /** Get form store instance */
35
+ getFormStore: () => FormStore;
36
+ /** Get UI store instance */
37
+ getUIStore: () => UIStore;
38
+ /** Get validated form responses (returns null if invalid) */
39
+ getValidResponse: () => {
40
+ response: FormResponse | null;
41
+ errors: ValidationError[];
42
+ };
43
+ }
44
+
45
+ export declare interface EsheetRendererProps {
46
+ /** Form definition (JSON object, JSON string, or YAML string) */
47
+ formData: FormDefinition | string;
48
+ /** Additional CSS classes for root container */
49
+ className?: string;
50
+ /** Initial form responses (pre-fill data) */
51
+ initialResponses?: FormResponse;
52
+ }
53
+
54
+ /**
55
+ * FieldNode - Renders a single field or section with recursive children
56
+ *
57
+ * Looks up the field component from the registry and passes field props.
58
+ * For sections, recursively renders visible children.
59
+ */
60
+ export declare const FieldNode: default_2.NamedExoticComponent<FieldNodeProps>;
61
+
62
+ declare interface FieldNodeProps {
63
+ id: string;
64
+ form: FormStore;
65
+ ui: UIStore;
66
+ /** Nesting depth for visual styling (default: 0) */
67
+ depth?: number;
68
+ }
69
+
70
+ /**
71
+ * RendererBody - Iterates over visible root fields and renders them
72
+ *
73
+ * Respects conditional visibility logic from form store.
74
+ * Only renders fields where isVisible() returns true.
75
+ * Sections recursively render their visible children.
76
+ */
77
+ export declare function RendererBody({ form, ui }: RendererBodyProps): JSX.Element;
78
+
79
+ declare interface RendererBodyProps {
80
+ form: FormStore;
81
+ ui: UIStore;
82
+ }
83
+
84
+ /**
85
+ * Initialize renderer with form definition
86
+ *
87
+ * - Parses YAML/JSON string input or accepts object directly
88
+ * - Validates against formDefinitionSchema
89
+ * - Loads definition into form store
90
+ * - Sets UI to preview mode
91
+ * - Applies initial responses if provided
92
+ */
93
+ export declare function useRendererInit(form: FormStore, ui: UIStore, formData: FormDefinition | string, initialResponses?: FormResponse): void;
94
+
95
+ export { ValidationError }
96
+
97
+ export { }