@formbox/htmx 0.5.0 → 0.7.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 (50) hide show
  1. package/README.md +43 -7
  2. package/dist/index.d.ts +71 -7
  3. package/dist/index.js +103 -65
  4. package/dist/templates/AnswerList.html.hbs +3 -0
  5. package/dist/templates/AnswerScaffold.html.hbs +3 -0
  6. package/dist/templates/Checkbox.html.hbs +3 -0
  7. package/dist/templates/CheckboxList.html.hbs +3 -0
  8. package/dist/templates/CustomOptionForm.html.hbs +3 -0
  9. package/dist/templates/DateInput.html.hbs +3 -0
  10. package/dist/templates/DateTimeInput.html.hbs +3 -0
  11. package/dist/templates/DisplayRenderer.html.hbs +3 -0
  12. package/dist/templates/Errors.html.hbs +3 -0
  13. package/dist/templates/FileInput.html.hbs +3 -0
  14. package/dist/templates/Flyover.html.hbs +3 -0
  15. package/dist/templates/Footer.html.hbs +3 -0
  16. package/dist/templates/Form.html.hbs +21 -4
  17. package/dist/templates/FormDescription.html.hbs +10 -0
  18. package/dist/templates/FormTitle.html.hbs +10 -0
  19. package/dist/templates/GroupList.html.hbs +3 -0
  20. package/dist/templates/GroupScaffold.html.hbs +3 -0
  21. package/dist/templates/Header.html.hbs +3 -0
  22. package/dist/templates/Help.html.hbs +3 -0
  23. package/dist/templates/InputGroup.html.hbs +3 -0
  24. package/dist/templates/Label.html.hbs +3 -0
  25. package/dist/templates/LabelContent.html.hbs +15 -0
  26. package/dist/templates/LanguageSelector.html.hbs +3 -0
  27. package/dist/templates/Legal.html.hbs +3 -0
  28. package/dist/templates/Link.html.hbs +3 -0
  29. package/dist/templates/Media.html.hbs +29 -0
  30. package/dist/templates/MultiSelectInput.html.hbs +3 -0
  31. package/dist/templates/NumberInput.html.hbs +3 -0
  32. package/dist/templates/OptionDisplay.html.hbs +3 -0
  33. package/dist/templates/OptionsLoading.html.hbs +3 -0
  34. package/dist/templates/Pagination.html.hbs +24 -0
  35. package/dist/templates/QuestionScaffold.html.hbs +3 -0
  36. package/dist/templates/RadioButton.html.hbs +3 -0
  37. package/dist/templates/RadioButtonList.html.hbs +3 -0
  38. package/dist/templates/SelectInput.html.hbs +3 -0
  39. package/dist/templates/ShortTextStyle.html.hbs +10 -0
  40. package/dist/templates/SignatureInput.html.hbs +3 -0
  41. package/dist/templates/SliderInput.html.hbs +3 -0
  42. package/dist/templates/SpinnerInput.html.hbs +3 -0
  43. package/dist/templates/Stack.html.hbs +3 -0
  44. package/dist/templates/SubmitButton.html.hbs +13 -0
  45. package/dist/templates/TabContainer.html.hbs +3 -0
  46. package/dist/templates/Table.html.hbs +3 -0
  47. package/dist/templates/TextArea.html.hbs +3 -0
  48. package/dist/templates/TextInput.html.hbs +3 -0
  49. package/dist/templates/TimeInput.html.hbs +3 -0
  50. package/package.json +3 -3
package/README.md CHANGED
@@ -113,7 +113,18 @@ const templates = {
113
113
  ...compileTemplates({
114
114
  Form: `
115
115
  <form{{{attrs attributes}}} hx-target="#questionnaire-app" hx-swap="morphdom">
116
- {{{fields}}}
116
+ {{{hiddenFields}}}
117
+ {{{shortTextStyle}}}
118
+ {{{titleHtml}}}
119
+ {{{descriptionHtml}}}
120
+ {{{languageSelector}}}
121
+ {{{errors}}}
122
+ {{{before}}}
123
+ {{{children}}}
124
+ {{{after}}}
125
+ {{{signature}}}
126
+ {{{paginationHtml}}}
127
+ {{{submitButton}}}
117
128
  </form>
118
129
  `,
119
130
  }),
@@ -162,7 +173,7 @@ Create one renderer instance for one request/render cycle:
162
173
 
163
174
  1. `new QuestionnaireRenderer(options)` creates a request-local renderer.
164
175
  2. `await renderer.process(formData)` applies submitted form state and returns submit result.
165
- 3. `await renderer.render()` returns HTML fields for the current renderer state.
176
+ 3. `await renderer.render()` returns form HTML for the current renderer state.
166
177
  4. `renderer.getQuestionnaireResponse()` reads the current FHIR response.
167
178
  5. `renderer.dispose()` releases the underlying renderer store.
168
179
 
@@ -256,7 +267,18 @@ const templates = {
256
267
  Form: `
257
268
  <form{{{attrs attributes}}}>
258
269
  ${csrf}
259
- {{{fields}}}
270
+ {{{hiddenFields}}}
271
+ {{{shortTextStyle}}}
272
+ {{{titleHtml}}}
273
+ {{{descriptionHtml}}}
274
+ {{{languageSelector}}}
275
+ {{{errors}}}
276
+ {{{before}}}
277
+ {{{children}}}
278
+ {{{after}}}
279
+ {{{signature}}}
280
+ {{{paginationHtml}}}
281
+ {{{submitButton}}}
260
282
  </form>
261
283
  `,
262
284
  }),
@@ -305,8 +327,21 @@ Callbacks and Handlebars strings can be mixed:
305
327
  ```ts
306
328
  const templates = compileTemplates({
307
329
  TextInput: `<input{{{fieldAttributes}}}{{{attr "id" id}}}>`,
308
- Form({ attributes, fields }) {
309
- return `<form${htmlAttributes(attributes)}>${fields}</form>`;
330
+ Form(properties) {
331
+ return `<form${htmlAttributes(properties.attributes)}>${[
332
+ properties.hiddenFields,
333
+ properties.shortTextStyle,
334
+ properties.titleHtml ?? "",
335
+ properties.descriptionHtml ?? "",
336
+ properties.languageSelector ?? "",
337
+ properties.errors ?? "",
338
+ properties.before ?? "",
339
+ properties.children,
340
+ properties.after ?? "",
341
+ properties.signature ?? "",
342
+ properties.paginationHtml ?? "",
343
+ properties.submitButton,
344
+ ].join("")}</form>`;
310
345
  },
311
346
  });
312
347
  ```
@@ -348,8 +383,9 @@ Available Handlebars helpers:
348
383
  - `{{{attrs attributes}}}` renders an object of escaped HTML attributes.
349
384
  - `{{{fieldAttributes}}}` renders `data-fb-link-id`, `data-fb-field`, `name`, and `hx-include` for the current field.
350
385
 
351
- Use triple braces for renderer-provided HTML slots such as `fields`, `children`,
352
- `label`, `errors`, and `customOptionForm`.
386
+ Use triple braces for renderer-provided HTML slots such as `hiddenFields`,
387
+ `children`, `paginationHtml`, `submitButton`, `label`, `errors`, and
388
+ `customOptionForm`.
353
389
 
354
390
  Default templates and user templates use the same data shape. The package does
355
391
  not keep a separate JSX fallback path.
package/dist/index.d.ts CHANGED
@@ -285,9 +285,9 @@ export declare type FooterTemplateProperties = Omit<TemplateBase<FooterPropertie
285
285
  readonly children: string;
286
286
  };
287
287
 
288
- declare type FormFieldsProperties = Omit<FormTemplateProperties, "attributes" | "fields">;
289
-
290
- export declare function formFieldsTemplate(properties: FormFieldsProperties): string;
288
+ export declare type FormDescriptionTemplateProperties = {
289
+ readonly description: string;
290
+ };
291
291
 
292
292
  declare type FormPagination = {
293
293
  current: number;
@@ -319,12 +319,21 @@ export declare type FormTemplateProperties = Omit<TemplateBase<FormProperties>,
319
319
  readonly before?: string | undefined;
320
320
  readonly children: string;
321
321
  readonly errors?: string | undefined;
322
- readonly fields: string;
322
+ readonly hiddenFields: string;
323
323
  readonly attributes: HtmlAttributes;
324
+ readonly titleHtml?: string | undefined;
325
+ readonly descriptionHtml?: string | undefined;
324
326
  readonly languageSelector?: string | undefined;
325
327
  readonly pagination?: TemplateFormPagination | undefined;
328
+ readonly paginationHtml?: string | undefined;
329
+ readonly shortTextStyle: string;
326
330
  readonly signature?: string | undefined;
327
331
  readonly submitLabel: string;
332
+ readonly submitButton: string;
333
+ };
334
+
335
+ export declare type FormTitleTemplateProperties = {
336
+ readonly title: string;
328
337
  };
329
338
 
330
339
  declare type GroupListProperties = {
@@ -432,6 +441,17 @@ export declare function isPreservedOptionToken(token: string): boolean;
432
441
 
433
442
  declare type LabelAs = "legend" | "label" | "text";
434
443
 
444
+ export declare type LabelContentTemplateProperties = {
445
+ readonly children: string;
446
+ readonly prefix?: string | undefined;
447
+ readonly shortText?: string | undefined;
448
+ readonly required?: boolean | undefined;
449
+ readonly help?: string | undefined;
450
+ readonly legal?: string | undefined;
451
+ readonly flyover?: string | undefined;
452
+ readonly hasShortText: boolean;
453
+ };
454
+
435
455
  declare type LabelProperties = {
436
456
  prefix?: ReactNode;
437
457
  shortText?: string | undefined;
@@ -519,7 +539,23 @@ export declare function loadDefaultTemplates(): Promise<RequiredTemplates>;
519
539
 
520
540
  export declare function loadTemplates(directory: string | URL): Promise<Templates>;
521
541
 
522
- export declare function mediaHtml(attachment: Attachment | undefined, fallbackLabel: string, id?: string | undefined): string;
542
+ export declare function mediaHtml(templates: Pick<RequiredTemplates, "Media">, attachment: Attachment | undefined, fallbackLabel: string, id?: string | undefined): string;
543
+
544
+ export declare type MediaKind = "fallback" | "image" | "audio" | "video" | "link";
545
+
546
+ export declare type MediaTemplateProperties = {
547
+ readonly attachment: Attachment;
548
+ readonly id?: string | undefined;
549
+ readonly label: string;
550
+ readonly source?: string | undefined;
551
+ readonly contentType?: string | undefined;
552
+ readonly kind: MediaKind;
553
+ readonly isFallback: boolean;
554
+ readonly isImage: boolean;
555
+ readonly isAudio: boolean;
556
+ readonly isVideo: boolean;
557
+ readonly isLink: boolean;
558
+ };
523
559
 
524
560
  declare type MultiSelectInputProperties = {
525
561
  options: readonly OptionItem[];
@@ -619,6 +655,18 @@ export declare function optionValueName(path: NodePath, token: string): string;
619
655
 
620
656
  export declare const PAGE_FIELD = "fb[page]";
621
657
 
658
+ export declare function pageHiddenField(currentPage: number | undefined): string;
659
+
660
+ export declare type PaginationTemplateProperties = TemplateFormPagination & {
661
+ readonly actionName: string;
662
+ readonly previousAction: "page-prev";
663
+ readonly nextAction: "page-next";
664
+ readonly navigationLabel: string;
665
+ readonly currentLabel: string;
666
+ readonly previousTargetLabel: string;
667
+ readonly nextTargetLabel: string;
668
+ };
669
+
622
670
  export declare function pathControlId(token: string, path: NodePath | undefined, ...parts: Array<string | number | undefined>): string | undefined;
623
671
 
624
672
  declare type PlaceholderString<Key extends string> = `${string}{${Key}}${string}`;
@@ -800,6 +848,8 @@ export declare type SelectOptionTemplateItem = TemplateOptionItem & {
800
848
  readonly selected: boolean;
801
849
  };
802
850
 
851
+ export declare type ShortTextStyleTemplateProperties = Record<string, never>;
852
+
803
853
  declare type SignatureInputProperties = {
804
854
  value: string | undefined;
805
855
  id: string;
@@ -1001,6 +1051,13 @@ declare type Strings = {
1001
1051
 
1002
1052
  export declare const SUBMIT_ATTEMPTED_FIELD = "fb[submitAttempted]";
1003
1053
 
1054
+ export declare type SubmitButtonTemplateProperties = {
1055
+ readonly id?: string | undefined;
1056
+ readonly actionName: string;
1057
+ readonly value: "submit";
1058
+ readonly label: string;
1059
+ };
1060
+
1004
1061
  declare type TabContainerProperties = {
1005
1062
  path?: NodePath | undefined;
1006
1063
  header?: ReactNode;
@@ -1090,13 +1147,13 @@ export declare type TemplateFormPagination = Omit<FormPagination, "onNext" | "on
1090
1147
 
1091
1148
  export declare type TemplateName = keyof Templates;
1092
1149
 
1093
- export declare const templateNames: readonly ["TextInput", "TextArea", "NumberInput", "DateInput", "DateTimeInput", "TimeInput", "SliderInput", "SpinnerInput", "OptionDisplay", "SelectInput", "RadioButton", "RadioButtonList", "Checkbox", "CheckboxList", "MultiSelectInput", "CustomOptionForm", "Errors", "Label", "QuestionScaffold", "OptionsLoading", "Help", "Legal", "Flyover", "Header", "Footer", "Form", "Stack", "AnswerList", "AnswerScaffold", "GroupList", "GroupScaffold", "Table", "InputGroup", "FileInput", "SignatureInput", "DisplayRenderer", "TabContainer", "Link", "LanguageSelector"];
1150
+ export declare const templateNames: readonly ["TextInput", "TextArea", "NumberInput", "DateInput", "DateTimeInput", "TimeInput", "SliderInput", "SpinnerInput", "OptionDisplay", "SelectInput", "RadioButton", "RadioButtonList", "Checkbox", "CheckboxList", "MultiSelectInput", "CustomOptionForm", "Media", "Errors", "Label", "LabelContent", "QuestionScaffold", "OptionsLoading", "Help", "Legal", "Flyover", "Header", "Footer", "FormTitle", "FormDescription", "Pagination", "SubmitButton", "ShortTextStyle", "Form", "Stack", "AnswerList", "AnswerScaffold", "GroupList", "GroupScaffold", "Table", "InputGroup", "FileInput", "SignatureInput", "DisplayRenderer", "TabContainer", "Link", "LanguageSelector"];
1094
1151
 
1095
1152
  export declare type TemplateOptionItem = Omit<OptionItem, "label"> & {
1096
1153
  readonly label: string;
1097
1154
  };
1098
1155
 
1099
- export declare type TemplateProperties = TextInputTemplateProperties | TextAreaTemplateProperties | NumberInputTemplateProperties | DateInputTemplateProperties | DateTimeInputTemplateProperties | TimeInputTemplateProperties | SliderInputTemplateProperties | SpinnerInputTemplateProperties | OptionDisplayTemplateProperties | SelectInputTemplateProperties | RadioButtonTemplateProperties | RadioButtonListTemplateProperties | CheckboxTemplateProperties | CheckboxListTemplateProperties | MultiSelectInputTemplateProperties | CustomOptionFormTemplateProperties | ErrorsTemplateProperties | LabelTemplateProperties | QuestionScaffoldTemplateProperties | OptionsLoadingTemplateProperties | HelpTemplateProperties | LegalTemplateProperties | FlyoverTemplateProperties | HeaderTemplateProperties | FooterTemplateProperties | FormTemplateProperties | StackTemplateProperties | AnswerListTemplateProperties | AnswerScaffoldTemplateProperties | GroupListTemplateProperties | GroupScaffoldTemplateProperties | TableTemplateProperties | InputGroupTemplateProperties | FileInputTemplateProperties | SignatureInputTemplateProperties | DisplayRendererTemplateProperties | TabContainerTemplateProperties | LinkTemplateProperties | LanguageSelectorTemplateProperties;
1156
+ export declare type TemplateProperties = TextInputTemplateProperties | TextAreaTemplateProperties | NumberInputTemplateProperties | DateInputTemplateProperties | DateTimeInputTemplateProperties | TimeInputTemplateProperties | SliderInputTemplateProperties | SpinnerInputTemplateProperties | OptionDisplayTemplateProperties | SelectInputTemplateProperties | RadioButtonTemplateProperties | RadioButtonListTemplateProperties | CheckboxTemplateProperties | CheckboxListTemplateProperties | MultiSelectInputTemplateProperties | CustomOptionFormTemplateProperties | MediaTemplateProperties | ErrorsTemplateProperties | LabelTemplateProperties | LabelContentTemplateProperties | QuestionScaffoldTemplateProperties | OptionsLoadingTemplateProperties | HelpTemplateProperties | LegalTemplateProperties | FlyoverTemplateProperties | HeaderTemplateProperties | FooterTemplateProperties | FormTitleTemplateProperties | FormDescriptionTemplateProperties | PaginationTemplateProperties | SubmitButtonTemplateProperties | ShortTextStyleTemplateProperties | FormTemplateProperties | StackTemplateProperties | AnswerListTemplateProperties | AnswerScaffoldTemplateProperties | GroupListTemplateProperties | GroupScaffoldTemplateProperties | TableTemplateProperties | InputGroupTemplateProperties | FileInputTemplateProperties | SignatureInputTemplateProperties | DisplayRendererTemplateProperties | TabContainerTemplateProperties | LinkTemplateProperties | LanguageSelectorTemplateProperties;
1100
1157
 
1101
1158
  export declare interface Templates {
1102
1159
  readonly TextInput?: Template<TextInputTemplateProperties> | undefined;
@@ -1115,8 +1172,10 @@ export declare interface Templates {
1115
1172
  readonly CheckboxList?: Template<CheckboxListTemplateProperties> | undefined;
1116
1173
  readonly MultiSelectInput?: Template<MultiSelectInputTemplateProperties> | undefined;
1117
1174
  readonly CustomOptionForm?: Template<CustomOptionFormTemplateProperties> | undefined;
1175
+ readonly Media?: Template<MediaTemplateProperties> | undefined;
1118
1176
  readonly Errors?: Template<ErrorsTemplateProperties> | undefined;
1119
1177
  readonly Label?: Template<LabelTemplateProperties> | undefined;
1178
+ readonly LabelContent?: Template<LabelContentTemplateProperties> | undefined;
1120
1179
  readonly QuestionScaffold?: Template<QuestionScaffoldTemplateProperties> | undefined;
1121
1180
  readonly OptionsLoading?: Template<OptionsLoadingTemplateProperties> | undefined;
1122
1181
  readonly Help?: Template<HelpTemplateProperties> | undefined;
@@ -1124,6 +1183,11 @@ export declare interface Templates {
1124
1183
  readonly Flyover?: Template<FlyoverTemplateProperties> | undefined;
1125
1184
  readonly Header?: Template<HeaderTemplateProperties> | undefined;
1126
1185
  readonly Footer?: Template<FooterTemplateProperties> | undefined;
1186
+ readonly FormTitle?: Template<FormTitleTemplateProperties> | undefined;
1187
+ readonly FormDescription?: Template<FormDescriptionTemplateProperties> | undefined;
1188
+ readonly Pagination?: Template<PaginationTemplateProperties> | undefined;
1189
+ readonly SubmitButton?: Template<SubmitButtonTemplateProperties> | undefined;
1190
+ readonly ShortTextStyle?: Template<ShortTextStyleTemplateProperties> | undefined;
1127
1191
  readonly Form?: Template<FormTemplateProperties> | undefined;
1128
1192
  readonly Stack?: Template<StackTemplateProperties> | undefined;
1129
1193
  readonly AnswerList?: Template<AnswerListTemplateProperties> | undefined;
package/dist/index.js CHANGED
@@ -59564,8 +59564,10 @@ const templateNames = [
59564
59564
  "CheckboxList",
59565
59565
  "MultiSelectInput",
59566
59566
  "CustomOptionForm",
59567
+ "Media",
59567
59568
  "Errors",
59568
59569
  "Label",
59570
+ "LabelContent",
59569
59571
  "QuestionScaffold",
59570
59572
  "OptionsLoading",
59571
59573
  "Help",
@@ -59573,6 +59575,11 @@ const templateNames = [
59573
59575
  "Flyover",
59574
59576
  "Header",
59575
59577
  "Footer",
59578
+ "FormTitle",
59579
+ "FormDescription",
59580
+ "Pagination",
59581
+ "SubmitButton",
59582
+ "ShortTextStyle",
59576
59583
  "Form",
59577
59584
  "Stack",
59578
59585
  "AnswerList",
@@ -59686,43 +59693,30 @@ function isDefined(value) {
59686
59693
  function isPreservedOptionToken$1(token) {
59687
59694
  return token.includes("__custom__") || token.includes("__legacy__");
59688
59695
  }
59689
- function mediaHtml(attachment, fallbackLabel, id2) {
59696
+ function mediaHtml(templates, attachment, fallbackLabel, id2) {
59690
59697
  if (attachment === void 0) {
59691
59698
  return "";
59692
59699
  }
59693
59700
  const label = attachment.title ?? attachment.url ?? fallbackLabel;
59694
59701
  const source = attachment.url ?? attachmentSource(attachment);
59695
59702
  const contentType = attachment.contentType?.toLowerCase();
59696
- if (source === void 0) {
59697
- return `<span>${escapeHtml$1(label)}</span>`;
59698
- }
59699
- if (contentType?.startsWith("image/")) {
59700
- return `<img${attribute("src", source)}${attribute("alt", label)}>`;
59701
- }
59702
- if (contentType?.startsWith("audio/")) {
59703
- return `<audio controls${attribute("id", id2)}${attribute("src", source)}></audio>`;
59704
- }
59705
- if (contentType?.startsWith("video/")) {
59706
- return `<video controls${attribute("id", id2)}${attribute("src", source)}></video>`;
59707
- }
59708
- return `<a${attribute("id", id2)}${attribute("href", source)} target="_blank" rel="noreferrer">${escapeHtml$1(label)}</a>`;
59703
+ const kind = source === void 0 ? "fallback" : contentType?.startsWith("image/") ? "image" : contentType?.startsWith("audio/") ? "audio" : contentType?.startsWith("video/") ? "video" : "link";
59704
+ return templates.Media({
59705
+ attachment,
59706
+ id: id2,
59707
+ label,
59708
+ source,
59709
+ contentType,
59710
+ kind,
59711
+ isFallback: kind === "fallback",
59712
+ isImage: kind === "image",
59713
+ isAudio: kind === "audio",
59714
+ isVideo: kind === "video",
59715
+ isLink: kind === "link"
59716
+ });
59709
59717
  }
59710
- function formFieldsTemplate(properties) {
59711
- const shortTextStyle = properties.children.includes("data-fb-label-short") ? "<style>[data-fb-label-short]{display:none}@media (max-width:40rem){[data-fb-label-full]{display:none}[data-fb-label-short]{display:inline}}</style>" : void 0;
59712
- return [
59713
- shortTextStyle ?? "",
59714
- `<input type="hidden" name="${PAGE_FIELD}" value="${String(properties.pagination?.current ?? 1)}">`,
59715
- properties.title ? `<h1>${escapeHtml$1(properties.title)}</h1>` : "",
59716
- properties.description ? `<p>${escapeHtml$1(properties.description)}</p>` : "",
59717
- properties.languageSelector ?? "",
59718
- properties.errors ?? "",
59719
- properties.before ?? "",
59720
- properties.children,
59721
- properties.after ?? "",
59722
- properties.signature ?? "",
59723
- renderPagination(properties),
59724
- `<button type="submit"${attribute("id", stableId(properties.id, "submit"))} name="${ACTION_FIELD}" value="submit">${escapeHtml$1(properties.submitLabel)}</button>`
59725
- ].join("");
59718
+ function pageHiddenField(currentPage) {
59719
+ return `<input type="hidden" name="${PAGE_FIELD}" value="${String(currentPage ?? 1)}">`;
59726
59720
  }
59727
59721
  function fieldAttributes$1(path2, field) {
59728
59722
  if (field === "signature") {
@@ -59861,19 +59855,6 @@ function defaultAttributes(action2) {
59861
59855
  "hx-include": "closest form"
59862
59856
  };
59863
59857
  }
59864
- function renderPagination(properties) {
59865
- const pagination = properties.pagination;
59866
- if (!pagination) {
59867
- return "";
59868
- }
59869
- return [
59870
- "<nav>",
59871
- pagination.disabledPrev ? "" : `<button type="submit"${attribute("id", pagination.previousId)} name="${ACTION_FIELD}" value="page-prev">${escapeHtml$1(pagination.previousLabel)}</button>`,
59872
- `<span>${String(pagination.current)} / ${String(pagination.total)}</span>`,
59873
- pagination.disabledNext ? "" : `<button type="submit"${attribute("id", pagination.nextId)} name="${ACTION_FIELD}" value="page-next">${escapeHtml$1(pagination.nextLabel)}</button>`,
59874
- "</nav>"
59875
- ].join("");
59876
- }
59877
59858
  function tableCell(cell, renderHtml) {
59878
59859
  return {
59879
59860
  token: cell.token,
@@ -61560,6 +61541,8 @@ function Form(properties) {
61560
61541
  const renderHtml = useHtml();
61561
61542
  const strings2 = useStrings();
61562
61543
  const id2 = properties.id ?? token;
61544
+ const submitLabel = strings2.form.submit;
61545
+ const children = renderHtml(properties.children);
61563
61546
  const pagination = properties.pagination ? {
61564
61547
  current: properties.pagination.current,
61565
61548
  total: properties.pagination.total,
@@ -61570,27 +61553,68 @@ function Form(properties) {
61570
61553
  previousId: stableId(id2, "pagination", "previous"),
61571
61554
  previousLabel: strings2.pagination.previous
61572
61555
  } : void 0;
61556
+ const titleHtml = properties.title ? templates.FormTitle({ title: properties.title }) : void 0;
61557
+ const descriptionHtml = properties.description ? templates.FormDescription({
61558
+ description: properties.description
61559
+ }) : void 0;
61560
+ const paginationHtml = pagination ? templates.Pagination({
61561
+ ...pagination,
61562
+ actionName: ACTION_FIELD,
61563
+ previousAction: "page-prev",
61564
+ nextAction: "page-next",
61565
+ navigationLabel: strings2.pagination.navigation,
61566
+ currentLabel: formatPageString(
61567
+ strings2.pagination.pageLabel,
61568
+ pagination.current
61569
+ ),
61570
+ previousTargetLabel: formatPageString(
61571
+ strings2.pagination.previousTargetPage,
61572
+ Math.max(pagination.current - 1, 1)
61573
+ ),
61574
+ nextTargetLabel: formatPageString(
61575
+ strings2.pagination.nextTargetPage,
61576
+ Math.min(pagination.current + 1, pagination.total)
61577
+ )
61578
+ }) : void 0;
61579
+ const submitButton = templates.SubmitButton({
61580
+ id: stableId(id2, "submit"),
61581
+ actionName: ACTION_FIELD,
61582
+ value: "submit",
61583
+ label: submitLabel
61584
+ });
61585
+ const rendererHiddenFields = [
61586
+ hiddenFields,
61587
+ pageHiddenField(pagination?.current)
61588
+ ].filter(Boolean).join("");
61589
+ const shortTextStyle = children.includes("data-fb-label-short") ? templates.ShortTextStyle({}) : "";
61573
61590
  const formProperties = {
61574
61591
  id: id2,
61575
61592
  title: properties.title,
61576
61593
  description: properties.description,
61577
61594
  customExtensions: properties.customExtensions,
61595
+ hiddenFields: rendererHiddenFields,
61596
+ titleHtml,
61597
+ descriptionHtml,
61578
61598
  after: renderHtml(properties.after),
61579
61599
  before: renderHtml(properties.before),
61580
- children: renderHtml(properties.children),
61600
+ children,
61581
61601
  errors: renderHtml(properties.errors),
61582
61602
  languageSelector: renderHtml(properties.languageSelector),
61583
61603
  pagination,
61604
+ paginationHtml,
61605
+ shortTextStyle,
61584
61606
  signature: renderHtml(properties.signature),
61585
- submitLabel: strings2.form.submit
61607
+ submitLabel,
61608
+ submitButton
61586
61609
  };
61587
- const fields = [hiddenFields, formFieldsTemplate(formProperties)].join("");
61588
61610
  return renderTemplate(templates.Form, {
61589
61611
  ...formProperties,
61590
- attributes: { id: id2, ...defaultAttributes(action2) },
61591
- fields
61612
+ attributes: { id: id2, ...defaultAttributes(action2) }
61592
61613
  });
61593
61614
  }
61615
+ function formatPageString(template, page) {
61616
+ return template.replaceAll("{page}", String(page));
61617
+ }
61594
61618
  function GroupList(properties) {
61595
61619
  const { templates, token } = useHtmxTheme();
61596
61620
  const renderHtml = useHtml();
@@ -61689,14 +61713,19 @@ function Label(properties) {
61689
61713
  const strings2 = useStrings();
61690
61714
  const children = renderHtml(properties.children);
61691
61715
  const prefix2 = properties.prefix === void 0 ? void 0 : renderHtml(properties.prefix);
61692
- const content = [
61693
- prefix2 === void 0 ? "" : `<span>${prefix2} </span>`,
61694
- properties.shortText === void 0 ? children : `<span data-fb-label-full>${children}</span><span data-fb-label-short>${escapeHtml$1(properties.shortText)}</span>`,
61695
- properties.required ? '<span aria-hidden="true"> *</span>' : "",
61696
- renderHtml(properties.help),
61697
- renderHtml(properties.legal),
61698
- renderHtml(properties.flyover)
61699
- ].join("");
61716
+ const help = renderHtml(properties.help);
61717
+ const legal = renderHtml(properties.legal);
61718
+ const flyover = renderHtml(properties.flyover);
61719
+ const content = templates.LabelContent({
61720
+ children,
61721
+ prefix: prefix2,
61722
+ shortText: properties.shortText,
61723
+ required: properties.required,
61724
+ help,
61725
+ legal,
61726
+ flyover,
61727
+ hasShortText: properties.shortText !== void 0
61728
+ });
61700
61729
  return renderTemplate(templates.Label, {
61701
61730
  shortText: properties.shortText,
61702
61731
  isExpanded: properties.isExpanded,
@@ -61710,10 +61739,11 @@ function Label(properties) {
61710
61739
  content,
61711
61740
  isLegend: properties.as === "legend",
61712
61741
  isText: properties.as === "text",
61713
- help: renderHtml(properties.help),
61714
- legal: renderHtml(properties.legal),
61715
- flyover: renderHtml(properties.flyover),
61742
+ help,
61743
+ legal,
61744
+ flyover,
61716
61745
  media: mediaHtml(
61746
+ templates,
61717
61747
  properties.media,
61718
61748
  strings2.inputs.attachmentLabel,
61719
61749
  stableId(properties.id, "media")
@@ -61847,7 +61877,11 @@ function OptionDisplay(properties) {
61847
61877
  const strings2 = useStrings();
61848
61878
  return renderTemplate(templates.OptionDisplay, {
61849
61879
  prefix: properties.prefix === void 0 ? void 0 : escapeHtml$1(properties.prefix),
61850
- media: mediaHtml(properties.media, strings2.inputs.attachmentLabel),
61880
+ media: mediaHtml(
61881
+ templates,
61882
+ properties.media,
61883
+ strings2.inputs.attachmentLabel
61884
+ ),
61851
61885
  attachmentLabel: strings2.inputs.attachmentLabel,
61852
61886
  children: renderHtml(properties.children)
61853
61887
  });
@@ -62177,7 +62211,7 @@ function renderStoreFields(store, templates, action2) {
62177
62211
  const htmxTheme = {
62178
62212
  templates,
62179
62213
  token: store.token,
62180
- hiddenFields: renderHiddenFieldsForStore(store),
62214
+ hiddenFields: renderHiddenFieldsForStore(store, templates),
62181
62215
  activeTabValue: activeTab,
62182
62216
  action: action2
62183
62217
  };
@@ -62221,7 +62255,7 @@ function ensureServerRenderableRepeatQuestions(store) {
62221
62255
  }
62222
62256
  });
62223
62257
  }
62224
- function renderHiddenFieldsForStore(store) {
62258
+ function renderHiddenFieldsForStore(store, templates) {
62225
62259
  const renderedNodes = /* @__PURE__ */ new Set([
62226
62260
  ...store.headerNodes,
62227
62261
  ...store.contentNodes,
@@ -62232,10 +62266,10 @@ function renderHiddenFieldsForStore(store) {
62232
62266
  store.nodes.map(
62233
62267
  (node) => renderHiddenFieldsForNode(node, [], renderedNodes.has(node))
62234
62268
  ).join(""),
62235
- renderHiddenNodeIssues(store)
62269
+ renderHiddenNodeIssues(store, templates)
62236
62270
  ].join("");
62237
62271
  }
62238
- function renderHiddenNodeIssues(store) {
62272
+ function renderHiddenNodeIssues(store, templates) {
62239
62273
  const messages = [];
62240
62274
  store.walkNodes({
62241
62275
  node(node) {
@@ -62245,7 +62279,11 @@ function renderHiddenNodeIssues(store) {
62245
62279
  hiddenNodeIssues(node).map((issue) => getIssueMessage(issue)).filter((message) => message !== void 0).forEach((message) => messages.push(message));
62246
62280
  }
62247
62281
  });
62248
- return messages.length === 0 ? "" : `<ul class="fb-errors">${messages.map((message) => `<li>${escapeHtml(message)}</li>`).join("")}</ul>`;
62282
+ return templates.Errors({
62283
+ id: `${store.token}__hidden-node-issues`,
62284
+ hasMessages: messages.length > 0,
62285
+ messages: messages.map((message) => ({ html: escapeHtml(message) }))
62286
+ });
62249
62287
  }
62250
62288
  function hiddenNodeIssues(node) {
62251
62289
  if (node.issues.length > 0) {
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: AnswerList
3
3
 
4
+ Purpose:
5
+ - Renders a repeated answer collection and its add-answer action.
6
+
4
7
  Inputs:
5
8
  - children: rendered repeated answer rows.
6
9
  - hasCount/countName/count: hidden occurrence count state.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: AnswerScaffold
3
3
 
4
+ Purpose:
5
+ - Renders one answer instance, including its controls, errors, and remove action.
6
+
4
7
  Inputs:
5
8
  - control: rendered answer control.
6
9
  - errors: rendered answer errors.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: Checkbox
3
3
 
4
+ Purpose:
5
+ - Renders one checkbox answer option input and its visible label.
6
+
4
7
  Inputs:
5
8
  - id: control id.
6
9
  - checkedValue/uncheckedValue: submitted values for checked and unchecked states.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: CheckboxList
3
3
 
4
+ Purpose:
5
+ - Renders a repeating choice question as a checkbox option list.
6
+
4
7
  Inputs:
5
8
  - id: fieldset id.
6
9
  - options: items with id, token, label, selected, disabled, and hiddenInput.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: CustomOptionForm
3
3
 
4
+ Purpose:
5
+ - Renders the inline custom/open-choice value editor and its actions.
6
+
4
7
  Inputs:
5
8
  - content: rendered custom option fields.
6
9
  - errors: rendered validation errors.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: DateInput
3
3
 
4
+ Purpose:
5
+ - Renders a date answer control and its native field constraints.
6
+
4
7
  Inputs:
5
8
  - id: control id.
6
9
  - inputType: date or text fallback input type.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: DateTimeInput
3
3
 
4
+ Purpose:
5
+ - Renders a date-time answer control and its preserved baseline value.
6
+
4
7
  Inputs:
5
8
  - id: control id.
6
9
  - inputType: datetime-local or text fallback input type.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: DisplayRenderer
3
3
 
4
+ Purpose:
5
+ - Renders display-only item content.
6
+
4
7
  Inputs:
5
8
  - linkId: display item link id.
6
9
  - children: rendered display html.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: Errors
3
3
 
4
+ Purpose:
5
+ - Renders visible validation or rendering issue messages for a field or form surface.
6
+
4
7
  Inputs:
5
8
  - id: error container id.
6
9
  - messages: escaped validation messages as html entries.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: FileInput
3
3
 
4
+ Purpose:
5
+ - Renders an attachment file control, preserved value, and clear action.
6
+
4
7
  Inputs:
5
8
  - id: control id.
6
9
  - value/hiddenValue: current attachment and hidden JSON mirror.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: Flyover
3
3
 
4
+ Purpose:
5
+ - Renders flyover guidance as an accessible disclosure control.
6
+
4
7
  Inputs:
5
8
  - id: tooltip id.
6
9
  - children: rendered flyover content.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: Footer
3
3
 
4
+ Purpose:
5
+ - Renders footer display content.
6
+
4
7
  Inputs:
5
8
  - linkId: item link id.
6
9
  - children: rendered footer content.
@@ -1,13 +1,30 @@
1
1
  {{!--
2
2
  Template: Form
3
3
 
4
+ Purpose:
5
+ - Renders the outer form element and the top-level form sections.
6
+
4
7
  Inputs:
5
8
  - attributes: native form attributes generated by the renderer.
6
- - fields: full rendered field html.
9
+ - hiddenFields: renderer-owned hidden protocol field html.
7
10
  - customExtensions: source extension values, if supplied.
8
- - title/description/languageSelector/errors/before/children/after/signature: source sections already included in fields.
9
- - pagination/submitLabel: source action state already included in fields.
11
+ - shortTextStyle: responsive short-label CSS markup when short labels are present.
12
+ - titleHtml/descriptionHtml/languageSelector/errors/before/children/after/signature: rendered form sections.
13
+ - paginationHtml: rendered pagination controls, if available.
14
+ - submitButton: rendered submit control.
15
+ - title/description/pagination/submitLabel: source values for custom form templates.
10
16
  --}}
11
17
  <form{{{attrs attributes}}}>
12
- {{{fields}}}
18
+ {{{hiddenFields}}}
19
+ {{{shortTextStyle}}}
20
+ {{{titleHtml}}}
21
+ {{{descriptionHtml}}}
22
+ {{{languageSelector}}}
23
+ {{{errors}}}
24
+ {{{before}}}
25
+ {{{children}}}
26
+ {{{after}}}
27
+ {{{signature}}}
28
+ {{{paginationHtml}}}
29
+ {{{submitButton}}}
13
30
  </form>
@@ -0,0 +1,10 @@
1
+ {{!--
2
+ Template: FormDescription
3
+
4
+ Purpose:
5
+ - Renders the questionnaire description slot.
6
+
7
+ Inputs:
8
+ - description: localized questionnaire description text.
9
+ --}}
10
+ <p>{{description}}</p>
@@ -0,0 +1,10 @@
1
+ {{!--
2
+ Template: FormTitle
3
+
4
+ Purpose:
5
+ - Renders the questionnaire title slot.
6
+
7
+ Inputs:
8
+ - title: localized questionnaire title text.
9
+ --}}
10
+ <h1>{{title}}</h1>
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: GroupList
3
3
 
4
+ Purpose:
5
+ - Renders a repeated group collection and its add-group action.
6
+
4
7
  Inputs:
5
8
  - linkId: repeated group link id.
6
9
  - header/errors/children: rendered group list sections.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: GroupScaffold
3
3
 
4
+ Purpose:
5
+ - Renders one group instance, including header, errors, children, and remove action.
6
+
4
7
  Inputs:
5
8
  - linkId: group link id.
6
9
  - header/children/expandedChildren/errors/signature: rendered group sections.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: Header
3
3
 
4
+ Purpose:
5
+ - Renders header display content.
6
+
4
7
  Inputs:
5
8
  - linkId: item link id.
6
9
  - children: rendered header content.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: Help
3
3
 
4
+ Purpose:
5
+ - Renders help text as an accessible disclosure control.
6
+
4
7
  Inputs:
5
8
  - id: tooltip id.
6
9
  - children: rendered help content.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: InputGroup
3
3
 
4
+ Purpose:
5
+ - Renders grouped input fragments that belong to one answer control.
6
+
4
7
  Inputs:
5
8
  - children: rendered grouped input controls.
6
9
  - spans: source layout spans, if supplied.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: Label
3
3
 
4
+ Purpose:
5
+ - Renders the label, legend, or text wrapper around item label content.
6
+
4
7
  Inputs:
5
8
  - id/htmlFor: label id and target control id.
6
9
  - as/isLegend/isText: rendered label element kind.
@@ -0,0 +1,15 @@
1
+ {{!--
2
+ Template: LabelContent
3
+
4
+ Purpose:
5
+ - Renders the inner label text, prefix, required marker, and support controls.
6
+
7
+ Inputs:
8
+ - children: rendered label text html.
9
+ - prefix: rendered prefix html, if supplied.
10
+ - shortText: responsive short label text, if supplied.
11
+ - required: true when required marker should render.
12
+ - help/legal/flyover: rendered extension control html.
13
+ - hasShortText: true when shortText is available.
14
+ --}}
15
+ {{#if prefix}}<span>{{{prefix}}} </span>{{/if}}{{#if hasShortText}}<span data-fb-label-full>{{{children}}}</span><span data-fb-label-short>{{shortText}}</span>{{else}}{{{children}}}{{/if}}{{#if required}}<span aria-hidden="true"> *</span>{{/if}}{{{help}}}{{{legal}}}{{{flyover}}}
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: LanguageSelector
3
3
 
4
+ Purpose:
5
+ - Renders the form language selection control.
6
+
4
7
  Inputs:
5
8
  - id: select id.
6
9
  - name: generated language field name.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: Legal
3
3
 
4
+ Purpose:
5
+ - Renders legal text as an accessible disclosure control.
6
+
4
7
  Inputs:
5
8
  - id: dialog id.
6
9
  - children: rendered legal content.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: Link
3
3
 
4
+ Purpose:
5
+ - Renders hyperlink display content.
6
+
4
7
  Inputs:
5
8
  - id: link id.
6
9
  - href: link target.
@@ -0,0 +1,29 @@
1
+ {{!--
2
+ Template: Media
3
+
4
+ Purpose:
5
+ - Renders item or answer-option attachment media and fallback links.
6
+
7
+ Inputs:
8
+ - attachment: source attachment object.
9
+ - id: stable media id when available.
10
+ - label: accessible fallback label.
11
+ - source: resolved URL or data URL, if available.
12
+ - contentType: lower-cased attachment content type, if available.
13
+ - kind/isFallback/isImage/isAudio/isVideo/isLink: selected media rendering branch.
14
+ --}}
15
+ {{#if isFallback}}
16
+ <span>{{label}}</span>
17
+ {{/if}}
18
+ {{#if isImage}}
19
+ <img{{{attr "src" source}}}{{{attr "alt" label}}}>
20
+ {{/if}}
21
+ {{#if isAudio}}
22
+ <audio controls{{{attr "id" id}}}{{{attr "src" source}}}></audio>
23
+ {{/if}}
24
+ {{#if isVideo}}
25
+ <video controls{{{attr "id" id}}}{{{attr "src" source}}}></video>
26
+ {{/if}}
27
+ {{#if isLink}}
28
+ <a{{{attr "id" id}}}{{{attr "href" source}}} target="_blank" rel="noreferrer">{{label}}</a>
29
+ {{/if}}
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: MultiSelectInput
3
3
 
4
+ Purpose:
5
+ - Renders a searchable multi-select choice control and preserved selections.
6
+
4
7
  Inputs:
5
8
  - id: fieldset id.
6
9
  - options: items with id, token, label, selected, disabled, and hiddenInput.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: NumberInput
3
3
 
4
+ Purpose:
5
+ - Renders a numeric answer control with unit and comparator context.
6
+
4
7
  Inputs:
5
8
  - id: control id.
6
9
  - value/inputValue: numeric answer value prepared for the native input.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: OptionDisplay
3
3
 
4
+ Purpose:
5
+ - Renders the visible content for one answer option.
6
+
4
7
  Inputs:
5
8
  - children: rendered option text.
6
9
  - prefix: optional option prefix.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: OptionsLoading
3
3
 
4
+ Purpose:
5
+ - Renders the loading indicator for asynchronously resolved answer options.
6
+
4
7
  Inputs:
5
8
  - isLoading: true when options are loading.
6
9
  - loadingLabel: loading message text.
@@ -0,0 +1,24 @@
1
+ {{!--
2
+ Template: Pagination
3
+
4
+ Purpose:
5
+ - Renders page navigation controls for paginated questionnaires.
6
+
7
+ Inputs:
8
+ - current/total: current page number and total page count.
9
+ - disabledPrev/disabledNext: whether each navigation action is unavailable.
10
+ - actionName: form action field name.
11
+ - previousAction/nextAction: submitted action values for page navigation.
12
+ - previousId/nextId: stable button ids.
13
+ - previousLabel/nextLabel: visible button labels.
14
+ - navigationLabel/currentLabel/previousTargetLabel/nextTargetLabel: accessible pagination labels.
15
+ --}}
16
+ <nav>
17
+ {{#unless disabledPrev}}
18
+ <button type="submit"{{{attr "id" previousId}}}{{{attr "name" actionName}}}{{{attr "value" previousAction}}}>{{previousLabel}}</button>
19
+ {{/unless}}
20
+ <span>{{current}} / {{total}}</span>
21
+ {{#unless disabledNext}}
22
+ <button type="submit"{{{attr "id" nextId}}}{{{attr "name" actionName}}}{{{attr "value" nextAction}}}>{{nextLabel}}</button>
23
+ {{/unless}}
24
+ </nav>
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: QuestionScaffold
3
3
 
4
+ Purpose:
5
+ - Renders a question wrapper with header, errors, answer controls, and expanded content.
6
+
4
7
  Inputs:
5
8
  - linkId: question link id.
6
9
  - header/children/expandedChildren/errors/signature: rendered question sections.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: RadioButton
3
3
 
4
+ Purpose:
5
+ - Renders one radio answer option input and its visible label.
6
+
4
7
  Inputs:
5
8
  - id: control id.
6
9
  - groupName: source radio group name, if supplied.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: RadioButtonList
3
3
 
4
+ Purpose:
5
+ - Renders a single-select choice question as a radio option list.
6
+
4
7
  Inputs:
5
8
  - id: fieldset id.
6
9
  - options: items with id, token, label, checked, and disabled.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: SelectInput
3
3
 
4
+ Purpose:
5
+ - Renders a select/open-choice dropdown with search and custom-option controls.
6
+
4
7
  Inputs:
5
8
  - id: select id.
6
9
  - value: selected option token.
@@ -0,0 +1,10 @@
1
+ {{!--
2
+ Template: ShortTextStyle
3
+
4
+ Purpose:
5
+ - Renders responsive CSS that swaps long labels for short labels on narrow screens.
6
+
7
+ Inputs:
8
+ - no inputs.
9
+ --}}
10
+ <style>[data-fb-label-short]{display:none}@media (max-width:40rem){[data-fb-label-full]{display:none}[data-fb-label-short]{display:inline}}</style>
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: SignatureInput
3
3
 
4
+ Purpose:
5
+ - Renders a signature answer control and its submitted value field.
6
+
4
7
  Inputs:
5
8
  - id: control id.
6
9
  - value/inputValue: serialized signature value.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: SliderInput
3
3
 
4
+ Purpose:
5
+ - Renders a numeric answer as a range slider.
6
+
4
7
  Inputs:
5
8
  - id: control id.
6
9
  - value/inputValue: numeric answer value prepared for the native range input.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: SpinnerInput
3
3
 
4
+ Purpose:
5
+ - Renders a numeric answer as a stepper-style input.
6
+
4
7
  Inputs:
5
8
  - id: control id.
6
9
  - value/inputValue: numeric answer value prepared for the native number input.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: Stack
3
3
 
4
+ Purpose:
5
+ - Renders a generic stack of child content.
6
+
4
7
  Inputs:
5
8
  - children: rendered stacked content.
6
9
  --}}
@@ -0,0 +1,13 @@
1
+ {{!--
2
+ Template: SubmitButton
3
+
4
+ Purpose:
5
+ - Renders the main form submit action.
6
+
7
+ Inputs:
8
+ - id: stable submit button id.
9
+ - actionName: form action field name.
10
+ - value: submitted action value.
11
+ - label: visible submit label.
12
+ --}}
13
+ <button type="submit"{{{attr "id" id}}}{{{attr "name" actionName}}}{{{attr "value" value}}}>{{label}}</button>
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: TabContainer
3
3
 
4
+ Purpose:
5
+ - Renders tabbed group navigation and the active panel content.
6
+
4
7
  Inputs:
5
8
  - linkId: tab group link id.
6
9
  - header/errors: rendered tab group sections.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: Table
3
3
 
4
+ Purpose:
5
+ - Renders matrix-style controls from prepared columns, rows, and cells.
6
+
4
7
  Inputs:
5
8
  - hasRowHeader: true when rows need a header column.
6
9
  - columns: column items with token, content, errors, width, widthStyle, and isLoading.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: TextArea
3
3
 
4
+ Purpose:
5
+ - Renders a multi-line text answer control.
6
+
4
7
  Inputs:
5
8
  - id: control id.
6
9
  - value: submitted text value.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: TextInput
3
3
 
4
+ Purpose:
5
+ - Renders a scalar text-style answer control.
6
+
4
7
  Inputs:
5
8
  - id: control id.
6
9
  - type/inputType: requested and rendered native input type.
@@ -1,6 +1,9 @@
1
1
  {{!--
2
2
  Template: TimeInput
3
3
 
4
+ Purpose:
5
+ - Renders a time answer control.
6
+
4
7
  Inputs:
5
8
  - id: control id.
6
9
  - value: submitted time string.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@formbox/htmx",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "Server-rendered HTMX HTML renderer for Formbox FHIR Questionnaires",
5
5
  "private": false,
6
6
  "type": "module",
@@ -45,8 +45,8 @@
45
45
  },
46
46
  "scripts": {
47
47
  "build": "tsc -b ./tsconfig.lib.json && vite build",
48
- "demo": "bun run ./demo/server.ts",
49
- "dev": "bun run ./demo/server.ts",
48
+ "demo": "bun run build && bun ./demo/server.ts",
49
+ "dev": "bun run build && bun ./demo/server.ts",
50
50
  "lint": "eslint .",
51
51
  "test:e2e": "pnpm run build && playwright test e2e",
52
52
  "typecheck": "tsc --noEmit -p tsconfig.lib.json",