@bookinglab/booking-ui-react 1.12.1 → 1.14.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/index.d.cts CHANGED
@@ -869,8 +869,14 @@ interface BookingFormClassNames {
869
869
  dateInputItem?: string;
870
870
  /** Small "Day"/"Month"/"Year" label */
871
871
  dateInputLabel?: string;
872
- /** Date sub-input element (falls back to `input` / `inputError`) */
872
+ /** Date sub-input element (falls back to `input` / `inputError`). Applies to all 3 inputs unless overridden by dateInputDay/Month/Year. */
873
873
  dateInput?: string;
874
+ /** Day input specifically (falls back to `dateInput`) */
875
+ dateInputDay?: string;
876
+ /** Month input specifically (falls back to `dateInput`) */
877
+ dateInputMonth?: string;
878
+ /** Year input specifically (falls back to `dateInput`) */
879
+ dateInputYear?: string;
874
880
  }
875
881
  interface BookingFormProps {
876
882
  questions: Question[];
@@ -878,6 +884,8 @@ interface BookingFormProps {
878
884
  submitLabel?: string;
879
885
  /** Whether the current user is an admin. When false (default), questions with admin_only=true are hidden. */
880
886
  isAdmin?: boolean;
887
+ /** When true, renders each question's help_text directly below the label (or legend/heading) instead of below the input. Defaults to false. */
888
+ displayHelpTextBelowLabel?: boolean;
881
889
  /** Class name for the form element */
882
890
  className?: string;
883
891
  /** @deprecated Use classNames.label instead */
@@ -907,7 +915,7 @@ interface BookingUIConfig {
907
915
  * />
908
916
  * ```
909
917
  */
910
- declare function BookingForm({ questions, onSubmit, submitLabel, isAdmin, className, labelClassName, classNames: classNamesProp, }: BookingFormProps): react_jsx_runtime.JSX.Element;
918
+ declare function BookingForm({ questions, onSubmit, submitLabel, isAdmin, displayHelpTextBelowLabel, className, labelClassName, classNames: classNamesProp, }: BookingFormProps): react_jsx_runtime.JSX.Element;
911
919
 
912
920
  /**
913
921
  * A reusable, accessible registration form component.
package/dist/index.d.ts CHANGED
@@ -869,8 +869,14 @@ interface BookingFormClassNames {
869
869
  dateInputItem?: string;
870
870
  /** Small "Day"/"Month"/"Year" label */
871
871
  dateInputLabel?: string;
872
- /** Date sub-input element (falls back to `input` / `inputError`) */
872
+ /** Date sub-input element (falls back to `input` / `inputError`). Applies to all 3 inputs unless overridden by dateInputDay/Month/Year. */
873
873
  dateInput?: string;
874
+ /** Day input specifically (falls back to `dateInput`) */
875
+ dateInputDay?: string;
876
+ /** Month input specifically (falls back to `dateInput`) */
877
+ dateInputMonth?: string;
878
+ /** Year input specifically (falls back to `dateInput`) */
879
+ dateInputYear?: string;
874
880
  }
875
881
  interface BookingFormProps {
876
882
  questions: Question[];
@@ -878,6 +884,8 @@ interface BookingFormProps {
878
884
  submitLabel?: string;
879
885
  /** Whether the current user is an admin. When false (default), questions with admin_only=true are hidden. */
880
886
  isAdmin?: boolean;
887
+ /** When true, renders each question's help_text directly below the label (or legend/heading) instead of below the input. Defaults to false. */
888
+ displayHelpTextBelowLabel?: boolean;
881
889
  /** Class name for the form element */
882
890
  className?: string;
883
891
  /** @deprecated Use classNames.label instead */
@@ -907,7 +915,7 @@ interface BookingUIConfig {
907
915
  * />
908
916
  * ```
909
917
  */
910
- declare function BookingForm({ questions, onSubmit, submitLabel, isAdmin, className, labelClassName, classNames: classNamesProp, }: BookingFormProps): react_jsx_runtime.JSX.Element;
918
+ declare function BookingForm({ questions, onSubmit, submitLabel, isAdmin, displayHelpTextBelowLabel, className, labelClassName, classNames: classNamesProp, }: BookingFormProps): react_jsx_runtime.JSX.Element;
911
919
 
912
920
  /**
913
921
  * A reusable, accessible registration form component.
package/dist/index.js CHANGED
@@ -24,7 +24,11 @@ function DateInputGroup({
24
24
  itemCls,
25
25
  sublabelCls,
26
26
  dateInputCls,
27
- renderHelpText,
27
+ dayInputCls,
28
+ monthInputCls,
29
+ yearInputCls,
30
+ helpTextAbove,
31
+ helpTextBelow,
28
32
  renderError
29
33
  }) {
30
34
  const parseValue = (raw) => {
@@ -62,8 +66,9 @@ function DateInputGroup({
62
66
  return /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { className: fieldsetCls, "aria-describedby": hasError ? errorId : void 0, children: [
63
67
  /* @__PURE__ */ jsxRuntime.jsxs("legend", { className: legendCls, children: [
64
68
  question.name,
65
- question.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500 ml-1", "aria-hidden": "true", children: "*" })
69
+ question.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1", style: { color: "#DD2D1D" }, "aria-hidden": "true", children: "*" })
66
70
  ] }),
71
+ helpTextAbove,
67
72
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: groupCls, role: "group", children: [
68
73
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: itemCls, children: [
69
74
  /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: dayId, className: sublabelCls, children: "Day" }),
@@ -77,7 +82,7 @@ function DateInputGroup({
77
82
  maxLength: 2,
78
83
  value: parts.day,
79
84
  onChange: (e) => handleSubChange("day", e.target.value),
80
- className: cx(dateInputCls, "w-16"),
85
+ className: cx(dayInputCls ?? dateInputCls, "w-16"),
81
86
  "aria-invalid": hasError ? true : void 0,
82
87
  "aria-required": question.required || void 0
83
88
  }
@@ -95,7 +100,7 @@ function DateInputGroup({
95
100
  maxLength: 2,
96
101
  value: parts.month,
97
102
  onChange: (e) => handleSubChange("month", e.target.value),
98
- className: cx(dateInputCls, "w-16"),
103
+ className: cx(monthInputCls ?? dateInputCls, "w-16"),
99
104
  "aria-invalid": hasError ? true : void 0,
100
105
  "aria-required": question.required || void 0
101
106
  }
@@ -113,14 +118,14 @@ function DateInputGroup({
113
118
  maxLength: 4,
114
119
  value: parts.year,
115
120
  onChange: (e) => handleSubChange("year", e.target.value),
116
- className: cx(dateInputCls, "w-24"),
121
+ className: cx(yearInputCls ?? dateInputCls, "w-24"),
117
122
  "aria-invalid": hasError ? true : void 0,
118
123
  "aria-required": question.required || void 0
119
124
  }
120
125
  )
121
126
  ] })
122
127
  ] }),
123
- renderHelpText(),
128
+ helpTextBelow,
124
129
  renderError()
125
130
  ] });
126
131
  }
@@ -129,7 +134,8 @@ function FormField({
129
134
  value,
130
135
  error,
131
136
  onChange,
132
- classNames
137
+ classNames,
138
+ displayHelpTextBelowLabel = false
133
139
  }) {
134
140
  const inputId = `question-${question.id}`;
135
141
  const errorId = `${inputId}-error`;
@@ -149,7 +155,7 @@ function FormField({
149
155
  if (question.detail_type === "heading") return null;
150
156
  return /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: inputId, className: labelClasses, children: [
151
157
  question.name,
152
- question.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500 ml-1", "aria-hidden": "true", children: "*" })
158
+ question.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1", style: { color: "#DD2D1D" }, "aria-hidden": "true", children: "*" })
153
159
  ] });
154
160
  };
155
161
  const renderHelpText = () => {
@@ -162,6 +168,8 @@ function FormField({
162
168
  }
163
169
  );
164
170
  };
171
+ const helpTextAbove = displayHelpTextBelowLabel ? renderHelpText() : null;
172
+ const helpTextBelow = displayHelpTextBelowLabel ? null : renderHelpText();
165
173
  const renderError = () => {
166
174
  if (!error) return null;
167
175
  return /* @__PURE__ */ jsxRuntime.jsx("p", { id: errorId, className: classNames?.errorText ?? defaultErrorText, role: "alert", children: error });
@@ -180,6 +188,7 @@ function FormField({
180
188
  case "text_field":
181
189
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.fieldWrapper ?? defaultFieldWrapper, children: [
182
190
  renderLabel(),
191
+ helpTextAbove,
183
192
  /* @__PURE__ */ jsxRuntime.jsx(
184
193
  "input",
185
194
  {
@@ -192,12 +201,13 @@ function FormField({
192
201
  ...ariaProps
193
202
  }
194
203
  ),
195
- renderHelpText(),
204
+ helpTextBelow,
196
205
  renderError()
197
206
  ] });
198
207
  case "text_area":
199
208
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.fieldWrapper ?? defaultFieldWrapper, children: [
200
209
  renderLabel(),
210
+ helpTextAbove,
201
211
  /* @__PURE__ */ jsxRuntime.jsx(
202
212
  "textarea",
203
213
  {
@@ -210,12 +220,13 @@ function FormField({
210
220
  ...ariaProps
211
221
  }
212
222
  ),
213
- renderHelpText(),
223
+ helpTextBelow,
214
224
  renderError()
215
225
  ] });
216
226
  case "select":
217
227
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.fieldWrapper ?? defaultFieldWrapper, children: [
218
228
  renderLabel(),
229
+ helpTextAbove,
219
230
  /* @__PURE__ */ jsxRuntime.jsxs(
220
231
  "select",
221
232
  {
@@ -230,12 +241,13 @@ function FormField({
230
241
  ]
231
242
  }
232
243
  ),
233
- renderHelpText(),
244
+ helpTextBelow,
234
245
  renderError()
235
246
  ] });
236
247
  case "radio":
237
248
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.fieldWrapper ?? defaultFieldWrapper, children: [
238
249
  renderLabel(),
250
+ helpTextAbove,
239
251
  /* @__PURE__ */ jsxRuntime.jsx(
240
252
  "div",
241
253
  {
@@ -263,7 +275,7 @@ function FormField({
263
275
  })
264
276
  }
265
277
  ),
266
- renderHelpText(),
278
+ helpTextBelow,
267
279
  renderError()
268
280
  ] });
269
281
  case "date": {
@@ -274,6 +286,10 @@ function FormField({
274
286
  const groupCls = classNames?.dateInputGroup ?? "flex flex-row gap-3 items-end";
275
287
  const legendCls = classNames?.dateLegend ?? labelClasses;
276
288
  const fieldsetCls = classNames?.dateFieldset ?? (classNames?.fieldWrapper ?? defaultFieldWrapper);
289
+ const wrapPerInput = (cls) => cls === void 0 ? void 0 : hasError ? cx(cls, classNames?.inputError ?? defaultInputError) : cls;
290
+ const dayInputCls = wrapPerInput(classNames?.dateInputDay);
291
+ const monthInputCls = wrapPerInput(classNames?.dateInputMonth);
292
+ const yearInputCls = wrapPerInput(classNames?.dateInputYear);
277
293
  return /* @__PURE__ */ jsxRuntime.jsx(
278
294
  DateInputGroup,
279
295
  {
@@ -289,7 +305,11 @@ function FormField({
289
305
  itemCls,
290
306
  sublabelCls,
291
307
  dateInputCls,
292
- renderHelpText,
308
+ dayInputCls,
309
+ monthInputCls,
310
+ yearInputCls,
311
+ helpTextAbove,
312
+ helpTextBelow,
293
313
  renderError
294
314
  }
295
315
  );
@@ -297,6 +317,7 @@ function FormField({
297
317
  case "number":
298
318
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.fieldWrapper ?? defaultFieldWrapper, children: [
299
319
  renderLabel(),
320
+ helpTextAbove,
300
321
  /* @__PURE__ */ jsxRuntime.jsx(
301
322
  "input",
302
323
  {
@@ -311,11 +332,12 @@ function FormField({
311
332
  ...ariaProps
312
333
  }
313
334
  ),
314
- renderHelpText(),
335
+ helpTextBelow,
315
336
  renderError()
316
337
  ] });
317
338
  case "check":
318
339
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.fieldWrapper ?? defaultFieldWrapper, children: [
340
+ helpTextAbove,
319
341
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
320
342
  /* @__PURE__ */ jsxRuntime.jsx(
321
343
  "input",
@@ -330,10 +352,10 @@ function FormField({
330
352
  ),
331
353
  /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: inputId, className: checkboxLabelClasses, children: [
332
354
  question.name,
333
- question.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500 ml-1", "aria-hidden": "true", children: "*" })
355
+ question.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1", style: { color: "#DD2D1D" }, "aria-hidden": "true", children: "*" })
334
356
  ] })
335
357
  ] }),
336
- renderHelpText(),
358
+ helpTextBelow,
337
359
  renderError()
338
360
  ] });
339
361
  default:
@@ -345,6 +367,7 @@ function BookingForm({
345
367
  onSubmit,
346
368
  submitLabel = "Submit",
347
369
  isAdmin = false,
370
+ displayHelpTextBelowLabel = false,
348
371
  className = "",
349
372
  labelClassName,
350
373
  classNames: classNamesProp
@@ -541,7 +564,8 @@ function BookingForm({
541
564
  value: values[question.id],
542
565
  error: touched[question.id] ? errors[question.id] : void 0,
543
566
  onChange: (value) => handleChange(question.id, value),
544
- classNames
567
+ classNames,
568
+ displayHelpTextBelowLabel
545
569
  },
546
570
  question.id
547
571
  )),