@marianmeres/stuic 3.88.0 → 3.89.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.
@@ -102,6 +102,10 @@
102
102
 
103
103
  <script lang="ts">
104
104
  import { twMerge } from "../../utils/tw-merge.js";
105
+ import {
106
+ scrollToFirstInvalidField,
107
+ validateAllFields,
108
+ } from "../../utils/validate-fields.js";
105
109
  import { t_default } from "./_internal/checkout-i18n-defaults.js";
106
110
  import { createEmptyAddress } from "./_internal/checkout-utils.js";
107
111
  import FieldInput from "../Input/FieldInput.svelte";
@@ -146,6 +150,56 @@
146
150
  let _class = $derived(
147
151
  unstyled ? classProp : twMerge("stuic-checkout-address", classProp)
148
152
  );
153
+
154
+ // Imperative API ----------------------------------------------------------
155
+ // Field refs collected during render so consumers can trigger validation
156
+ // without waiting for native form submission. Refs stay undefined for
157
+ // fields hidden via the `fields` prop or replaced by the `countryField`
158
+ // snippet — `validateAllFields` skips nullish entries.
159
+ let nameField = $state<FieldInput>();
160
+ let streetField = $state<FieldInput>();
161
+ let cityField = $state<FieldInput>();
162
+ let stateField = $state<FieldInput>();
163
+ let postalCodeField = $state<FieldInput>();
164
+ let countryFieldRef = $state<FieldCountry>();
165
+ let phoneField = $state<FieldPhoneNumber>();
166
+
167
+ // DOM order top-to-bottom — first invalid wins for scrollToFirstError.
168
+ function _fields() {
169
+ return [
170
+ nameField,
171
+ streetField,
172
+ cityField,
173
+ stateField,
174
+ postalCodeField,
175
+ countryFieldRef,
176
+ phoneField,
177
+ ];
178
+ }
179
+
180
+ /**
181
+ * Run every visible field's validator and render any inline errors.
182
+ * Returns true if all fields are valid. Pair with the `errors` prop:
183
+ * set external errors first, await `tick()`, then call `validate()`.
184
+ */
185
+ export function validate(): boolean {
186
+ return validateAllFields(_fields());
187
+ }
188
+
189
+ /**
190
+ * Scroll the first invalid field into view and focus it. Returns true
191
+ * if a field was scrolled. Call after `validate()`.
192
+ */
193
+ export function scrollToFirstError(
194
+ opts?: Parameters<typeof scrollToFirstInvalidField>[1]
195
+ ): boolean {
196
+ return scrollToFirstInvalidField(_fields(), opts);
197
+ }
198
+
199
+ /** Clear all inline validation messages on the rendered fields. */
200
+ export function clearValidation(): void {
201
+ for (const f of _fields()) f?.clearValidation?.();
202
+ }
149
203
  </script>
150
204
 
151
205
  <fieldset
@@ -164,6 +218,7 @@
164
218
  {#if fields?.name !== false}
165
219
  <!-- svelte-ignore binding_property_non_reactive -->
166
220
  <FieldInput
221
+ bind:this={nameField}
167
222
  bind:value={address.name}
168
223
  label={t("checkout.address.name_label")}
169
224
  placeholder={t("checkout.address.name_placeholder")}
@@ -183,6 +238,7 @@
183
238
  {#if fields?.street !== false}
184
239
  <!-- svelte-ignore binding_property_non_reactive -->
185
240
  <FieldInput
241
+ bind:this={streetField}
186
242
  bind:value={address.street}
187
243
  label={t("checkout.address.street_label")}
188
244
  placeholder={t("checkout.address.street_placeholder")}
@@ -204,6 +260,7 @@
204
260
  {#if fields?.city !== false}
205
261
  <!-- svelte-ignore binding_property_non_reactive -->
206
262
  <FieldInput
263
+ bind:this={cityField}
207
264
  bind:value={address.city}
208
265
  label={t("checkout.address.city_label")}
209
266
  labelLeftBreakpoint={0}
@@ -221,6 +278,7 @@
221
278
  {#if fields?.state_or_region !== false}
222
279
  <!-- svelte-ignore binding_property_non_reactive -->
223
280
  <FieldInput
281
+ bind:this={stateField}
224
282
  bind:value={address.state_or_region}
225
283
  label={t("checkout.address.state_or_region_label")}
226
284
  labelLeftBreakpoint={0}
@@ -238,6 +296,7 @@
238
296
  {#if fields?.postal_code !== false}
239
297
  <!-- svelte-ignore binding_property_non_reactive -->
240
298
  <FieldInput
299
+ bind:this={postalCodeField}
241
300
  bind:value={address.postal_code}
242
301
  label={t("checkout.address.postal_code_label")}
243
302
  labelLeftBreakpoint={0}
@@ -270,6 +329,7 @@
270
329
  {:else}
271
330
  <!-- svelte-ignore binding_property_non_reactive -->
272
331
  <FieldCountry
332
+ bind:this={countryFieldRef}
273
333
  bind:value={address.country}
274
334
  label={t("checkout.address.country_label")}
275
335
  placeholder={t("checkout.address.country_placeholder")}
@@ -294,6 +354,7 @@
294
354
  <!-- Phone (full width, block label) -->
295
355
  {#if fields?.phone !== false}
296
356
  <FieldPhoneNumber
357
+ bind:this={phoneField}
297
358
  value={address.phone ?? ""}
298
359
  onChange={(v) => {
299
360
  address.phone = v;
@@ -80,6 +80,11 @@ export interface Props extends Omit<HTMLAttributes<HTMLFieldSetElement>, "childr
80
80
  class?: string;
81
81
  el?: HTMLFieldSetElement;
82
82
  }
83
- declare const CheckoutAddressForm: import("svelte").Component<Props, {}, "el" | "address">;
83
+ import { scrollToFirstInvalidField } from "../../utils/validate-fields.js";
84
+ declare const CheckoutAddressForm: import("svelte").Component<Props, {
85
+ validate: () => boolean;
86
+ scrollToFirstError: (opts?: Parameters<typeof scrollToFirstInvalidField>[1]) => boolean;
87
+ clearValidation: () => void;
88
+ }, "el" | "address">;
84
89
  type CheckoutAddressForm = ReturnType<typeof CheckoutAddressForm>;
85
90
  export default CheckoutAddressForm;
@@ -71,6 +71,10 @@
71
71
 
72
72
  <script lang="ts">
73
73
  import { twMerge } from "../../utils/tw-merge.js";
74
+ import {
75
+ scrollToFirstInvalidField,
76
+ validateAllFields,
77
+ } from "../../utils/validate-fields.js";
74
78
  import { t_default } from "./_internal/checkout-i18n-defaults.js";
75
79
  import {
76
80
  createEmptyCustomerFormData,
@@ -139,6 +143,52 @@
139
143
  let _class = $derived(
140
144
  unstyled ? classProp : twMerge("stuic-checkout-guest-form", classProp)
141
145
  );
146
+
147
+ // Imperative API ----------------------------------------------------------
148
+ // Field refs collected during render so consumers can trigger per-field
149
+ // inline messages without going through native form submission.
150
+ let emailField = $state<FieldInput>();
151
+ let firstNameField = $state<FieldInput>();
152
+ let lastNameField = $state<FieldInput>();
153
+ let phoneField = $state<FieldPhoneNumber>();
154
+ let companyNameField = $state<FieldInput>();
155
+ let taxIdField = $state<FieldInput>();
156
+ let vatNumberField = $state<FieldInput>();
157
+
158
+ function _fields() {
159
+ return [
160
+ emailField,
161
+ firstNameField,
162
+ lastNameField,
163
+ phoneField,
164
+ companyNameField,
165
+ taxIdField,
166
+ vatNumberField,
167
+ ];
168
+ }
169
+
170
+ /**
171
+ * Run every visible field's validator and render any inline errors.
172
+ * Returns true if all fields are valid.
173
+ */
174
+ export function validate(): boolean {
175
+ return validateAllFields(_fields());
176
+ }
177
+
178
+ /**
179
+ * Scroll the first invalid field into view and focus it. Returns true
180
+ * if a field was scrolled. Call after `validate()`.
181
+ */
182
+ export function scrollToFirstError(
183
+ opts?: Parameters<typeof scrollToFirstInvalidField>[1]
184
+ ): boolean {
185
+ return scrollToFirstInvalidField(_fields(), opts);
186
+ }
187
+
188
+ /** Clear all inline validation messages on the rendered fields. */
189
+ export function clearValidation(): void {
190
+ for (const f of _fields()) f?.clearValidation?.();
191
+ }
142
192
  </script>
143
193
 
144
194
  <form
@@ -158,6 +208,7 @@
158
208
  <!-- Email (always shown, always required) -->
159
209
  <!-- svelte-ignore binding_property_non_reactive -->
160
210
  <FieldInput
211
+ bind:this={emailField}
161
212
  bind:value={formData.email}
162
213
  label={t("checkout.guest.email_label")}
163
214
  type="email"
@@ -178,6 +229,7 @@
178
229
  {#if fields?.first_name !== false}
179
230
  <!-- svelte-ignore binding_property_non_reactive -->
180
231
  <FieldInput
232
+ bind:this={firstNameField}
181
233
  bind:value={formData.first_name}
182
234
  label={t("checkout.guest.first_name_label")}
183
235
  labelLeftBreakpoint={0}
@@ -188,6 +240,7 @@
188
240
  {#if fields?.last_name !== false}
189
241
  <!-- svelte-ignore binding_property_non_reactive -->
190
242
  <FieldInput
243
+ bind:this={lastNameField}
191
244
  bind:value={formData.last_name}
192
245
  label={t("checkout.guest.last_name_label")}
193
246
  labelLeftBreakpoint={0}
@@ -202,6 +255,7 @@
202
255
  {#if fields?.phone !== false}
203
256
  <!-- svelte-ignore binding_property_non_reactive -->
204
257
  <FieldPhoneNumber
258
+ bind:this={phoneField}
205
259
  bind:value={formData.phone}
206
260
  label={t("checkout.guest.phone_label")}
207
261
  placeholder={t("checkout.guest.phone_placeholder")}
@@ -221,6 +275,7 @@
221
275
  {#if fields?.company_name !== false}
222
276
  <!-- svelte-ignore binding_property_non_reactive -->
223
277
  <FieldInput
278
+ bind:this={companyNameField}
224
279
  bind:value={formData.company_name}
225
280
  label={t("checkout.guest.company_name_label")}
226
281
  name="checkout-guest-company-name"
@@ -232,6 +287,7 @@
232
287
  {#if fields?.tax_id !== false}
233
288
  <!-- svelte-ignore binding_property_non_reactive -->
234
289
  <FieldInput
290
+ bind:this={taxIdField}
235
291
  bind:value={formData.tax_id}
236
292
  label={t("checkout.guest.tax_id_label")}
237
293
  name="checkout-guest-tax-id"
@@ -240,6 +296,7 @@
240
296
  {#if fields?.vat_number !== false}
241
297
  <!-- svelte-ignore binding_property_non_reactive -->
242
298
  <FieldInput
299
+ bind:this={vatNumberField}
243
300
  bind:value={formData.vat_number}
244
301
  label={t("checkout.guest.vat_number_label")}
245
302
  name="checkout-guest-vat-number"
@@ -52,6 +52,11 @@ export interface Props extends Omit<HTMLAttributes<HTMLFormElement>, "children">
52
52
  class?: string;
53
53
  el?: HTMLFormElement;
54
54
  }
55
- declare const CheckoutGuestForm: import("svelte").Component<Props, {}, "el" | "formData">;
55
+ import { scrollToFirstInvalidField } from "../../utils/validate-fields.js";
56
+ declare const CheckoutGuestForm: import("svelte").Component<Props, {
57
+ validate: () => boolean;
58
+ scrollToFirstError: (opts?: Parameters<typeof scrollToFirstInvalidField>[1]) => boolean;
59
+ clearValidation: () => void;
60
+ }, "el" | "formData">;
56
61
  type CheckoutGuestForm = ReturnType<typeof CheckoutGuestForm>;
57
62
  export default CheckoutGuestForm;
@@ -114,6 +114,7 @@
114
114
 
115
115
  <script lang="ts">
116
116
  import { twMerge } from "../../utils/tw-merge.js";
117
+ import type { scrollToFirstInvalidField } from "../../utils/validate-fields.js";
117
118
  import { t_default } from "./_internal/checkout-i18n-defaults.js";
118
119
  import CheckoutGuestForm from "./CheckoutGuestForm.svelte";
119
120
  import CheckoutLoginForm from "./CheckoutLoginForm.svelte";
@@ -262,6 +263,44 @@
262
263
  let _class = $derived(
263
264
  unstyled ? classProp : twMerge("stuic-checkout-guest-or-login-form", classProp)
264
265
  );
266
+
267
+ // Imperative API ----------------------------------------------------------
268
+ // Routes to whichever inner form is currently visible inline. Modal-based
269
+ // flows (loginModal, loginOrRegisterModal) own their own submit/validate
270
+ // flow and are not validated through here.
271
+ let guestFormRef = $state<CheckoutGuestForm>();
272
+ let loginFormRef = $state<CheckoutLoginForm>();
273
+
274
+ function _activeForm(): CheckoutGuestForm | CheckoutLoginForm | undefined {
275
+ if (formMode === "guest-only") return guestFormRef;
276
+ if (formMode === "login-only") return loginFormRef;
277
+ if (formMode === "stacked") {
278
+ return activeTab === "login" ? loginFormRef : guestFormRef;
279
+ }
280
+ // "tabbed"
281
+ if (activeTab === "guest") return guestFormRef;
282
+ // login tab — falls through to modal when configured; no inline form
283
+ if (_useLoginModal || _useLoginOrRegisterModal) return undefined;
284
+ return loginFormRef;
285
+ }
286
+
287
+ /** Run validation on the currently active inline form. */
288
+ export function validate(): boolean {
289
+ return _activeForm()?.validate() ?? true;
290
+ }
291
+
292
+ /** Scroll the first invalid field on the active inline form into view. */
293
+ export function scrollToFirstError(
294
+ opts?: Parameters<typeof scrollToFirstInvalidField>[1]
295
+ ): boolean {
296
+ return _activeForm()?.scrollToFirstError(opts) ?? false;
297
+ }
298
+
299
+ /** Clear all inline validation messages on both inner forms. */
300
+ export function clearValidation(): void {
301
+ guestFormRef?.clearValidation();
302
+ loginFormRef?.clearValidation();
303
+ }
265
304
  </script>
266
305
 
267
306
  <div bind:this={el} class={_class} {...rest}>
@@ -280,11 +319,23 @@
280
319
 
281
320
  {#if formMode === "guest-only"}
282
321
  {#if guestForm}
283
- <CheckoutGuestForm {...guestForm} {notifications} t={tProp} {unstyled} />
322
+ <CheckoutGuestForm
323
+ bind:this={guestFormRef}
324
+ {...guestForm}
325
+ {notifications}
326
+ t={tProp}
327
+ {unstyled}
328
+ />
284
329
  {/if}
285
330
  {:else if formMode === "login-only"}
286
331
  {#if loginForm}
287
- <CheckoutLoginForm {...loginForm} {notifications} t={tProp} {unstyled} />
332
+ <CheckoutLoginForm
333
+ bind:this={loginFormRef}
334
+ {...loginForm}
335
+ {notifications}
336
+ t={tProp}
337
+ {unstyled}
338
+ />
288
339
  {/if}
289
340
  {:else if formMode === "tabbed"}
290
341
  <ButtonGroupRadio
@@ -304,19 +355,43 @@
304
355
  }}
305
356
  />
306
357
  {#if activeTab === "guest" && guestForm}
307
- <CheckoutGuestForm {...guestForm} {notifications} t={tProp} {unstyled} />
358
+ <CheckoutGuestForm
359
+ bind:this={guestFormRef}
360
+ {...guestForm}
361
+ {notifications}
362
+ t={tProp}
363
+ {unstyled}
364
+ />
308
365
  {:else if activeTab === "login" && loginForm && !_useLoginOrRegisterModal && !_useLoginModal}
309
- <CheckoutLoginForm {...loginForm} {notifications} t={tProp} {unstyled} />
366
+ <CheckoutLoginForm
367
+ bind:this={loginFormRef}
368
+ {...loginForm}
369
+ {notifications}
370
+ t={tProp}
371
+ {unstyled}
372
+ />
310
373
  {/if}
311
374
  {:else if formMode === "stacked"}
312
375
  {#if loginForm}
313
- <CheckoutLoginForm {...loginForm} {notifications} t={tProp} {unstyled} />
376
+ <CheckoutLoginForm
377
+ bind:this={loginFormRef}
378
+ {...loginForm}
379
+ {notifications}
380
+ t={tProp}
381
+ {unstyled}
382
+ />
314
383
  {/if}
315
384
  <div class={unstyled ? undefined : "stuic-checkout-guest-or-login-divider"}>
316
385
  <span>{t("checkout.step.or_divider")}</span>
317
386
  </div>
318
387
  {#if guestForm}
319
- <CheckoutGuestForm {...guestForm} {notifications} t={tProp} {unstyled} />
388
+ <CheckoutGuestForm
389
+ bind:this={guestFormRef}
390
+ {...guestForm}
391
+ {notifications}
392
+ t={tProp}
393
+ {unstyled}
394
+ />
320
395
  {/if}
321
396
  {/if}
322
397
 
@@ -57,7 +57,12 @@ export interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "children">
57
57
  hLevel?: HLevel;
58
58
  hRenderLevel?: HLevel;
59
59
  }
60
+ import type { scrollToFirstInvalidField } from "../../utils/validate-fields.js";
60
61
  import { type HLevel } from "../H/index.js";
61
- declare const CheckoutGuestOrLoginForm: import("svelte").Component<Props, {}, "el" | "activeTab">;
62
+ declare const CheckoutGuestOrLoginForm: import("svelte").Component<Props, {
63
+ validate: () => boolean;
64
+ scrollToFirstError: (opts?: Parameters<typeof scrollToFirstInvalidField>[1]) => boolean;
65
+ clearValidation: () => void;
66
+ }, "el" | "activeTab">;
62
67
  type CheckoutGuestOrLoginForm = ReturnType<typeof CheckoutGuestOrLoginForm>;
63
68
  export default CheckoutGuestOrLoginForm;
@@ -75,6 +75,7 @@
75
75
 
76
76
  <script lang="ts">
77
77
  import { twMerge } from "../../utils/tw-merge.js";
78
+ import type { scrollToFirstInvalidField } from "../../utils/validate-fields.js";
78
79
  import { t_default } from "./_internal/checkout-i18n-defaults.js";
79
80
  import { createEmptyLoginFormData } from "./_internal/checkout-utils.js";
80
81
  import LoginForm from "../LoginForm/LoginForm.svelte";
@@ -120,6 +121,40 @@
120
121
  let _class = $derived(
121
122
  unstyled ? classProp : twMerge("stuic-checkout-login-form", classProp)
122
123
  );
124
+
125
+ // Imperative API ----------------------------------------------------------
126
+ // Thin delegation to the wrapped LoginForm's own imperative API.
127
+ let loginFormRef = $state<LoginForm>();
128
+
129
+ /** Run validation on the wrapped LoginForm. Returns true if valid. */
130
+ export function validate(): boolean {
131
+ return loginFormRef?.validate() ?? true;
132
+ }
133
+
134
+ /** Scroll the first invalid field into view. Call after `validate()`. */
135
+ export function scrollToFirstError(
136
+ opts?: Parameters<typeof scrollToFirstInvalidField>[1]
137
+ ): boolean {
138
+ return loginFormRef?.scrollToFirstError(opts) ?? false;
139
+ }
140
+
141
+ /**
142
+ * Clear all inline validation messages on the wrapped LoginForm.
143
+ * Currently a no-op because LoginForm doesn't yet expose
144
+ * clearValidation — present for API symmetry with the other Checkout
145
+ * composites; will start working once LoginForm gains the method.
146
+ */
147
+ export function clearValidation(): void {
148
+ // loginFormRef?.clearValidation?.();
149
+ }
123
150
  </script>
124
151
 
125
- <LoginForm bind:formData bind:el t={adaptedT} {unstyled} class={_class} {...rest} />
152
+ <LoginForm
153
+ bind:this={loginFormRef}
154
+ bind:formData
155
+ bind:el
156
+ t={adaptedT}
157
+ {unstyled}
158
+ class={_class}
159
+ {...rest}
160
+ />
@@ -56,6 +56,11 @@ export interface Props extends Omit<HTMLAttributes<HTMLFormElement>, "children">
56
56
  class?: string;
57
57
  el?: HTMLFormElement;
58
58
  }
59
- declare const CheckoutLoginForm: import("svelte").Component<Props, {}, "el" | "formData">;
59
+ import type { scrollToFirstInvalidField } from "../../utils/validate-fields.js";
60
+ declare const CheckoutLoginForm: import("svelte").Component<Props, {
61
+ validate: () => boolean;
62
+ scrollToFirstError: (opts?: Parameters<typeof scrollToFirstInvalidField>[1]) => boolean;
63
+ clearValidation: () => void;
64
+ }, "el" | "formData">;
60
65
  type CheckoutLoginForm = ReturnType<typeof CheckoutLoginForm>;
61
66
  export default CheckoutLoginForm;
@@ -115,6 +115,7 @@
115
115
 
116
116
  <script lang="ts">
117
117
  import { twMerge } from "../../utils/tw-merge.js";
118
+ import type { scrollToFirstInvalidField } from "../../utils/validate-fields.js";
118
119
  import Button from "../Button/Button.svelte";
119
120
  import FieldCheckbox from "../Input/FieldCheckbox.svelte";
120
121
  import Skeleton from "../Skeleton/Skeleton.svelte";
@@ -173,6 +174,44 @@
173
174
  let _class = $derived(
174
175
  unstyled ? classProp : twMerge("stuic-checkout-shipping-step", classProp)
175
176
  );
177
+
178
+ // Imperative API ----------------------------------------------------------
179
+ // Refs to the inner address forms so consumers can trigger validation
180
+ // across shipping + (conditionally) billing without binding to each form.
181
+ let shippingFormRef = $state<CheckoutAddressForm>();
182
+ let billingFormRef = $state<CheckoutAddressForm>();
183
+
184
+ /**
185
+ * Run validation on the shipping form (and billing, if visible).
186
+ * Returns true if everything is valid. Pair with the `*Errors` props:
187
+ * set external errors first, await `tick()`, then call `validate()`.
188
+ */
189
+ export function validate(): boolean {
190
+ const shippingValid = shippingFormRef?.validate() ?? true;
191
+ const billingValid = billingSameAsShipping
192
+ ? true
193
+ : (billingFormRef?.validate() ?? true);
194
+ return shippingValid && billingValid;
195
+ }
196
+
197
+ /**
198
+ * Scroll the first invalid field across both forms into view. Shipping
199
+ * comes first in the DOM, so it gets priority.
200
+ */
201
+ export function scrollToFirstError(
202
+ opts?: Parameters<typeof scrollToFirstInvalidField>[1]
203
+ ): boolean {
204
+ if (shippingFormRef?.scrollToFirstError(opts)) return true;
205
+ if (!billingSameAsShipping && billingFormRef?.scrollToFirstError(opts))
206
+ return true;
207
+ return false;
208
+ }
209
+
210
+ /** Clear all inline validation messages on both address forms. */
211
+ export function clearValidation(): void {
212
+ shippingFormRef?.clearValidation();
213
+ billingFormRef?.clearValidation();
214
+ }
176
215
  </script>
177
216
 
178
217
  <div bind:this={el} class={_class} {...rest}>
@@ -227,6 +266,7 @@
227
266
  </H>
228
267
  </CheckoutSectionHeader>
229
268
  <CheckoutAddressForm
269
+ bind:this={shippingFormRef}
230
270
  bind:address={shippingAddress}
231
271
  label="shipping"
232
272
  errors={shippingErrors}
@@ -252,6 +292,7 @@
252
292
  </H>
253
293
  </CheckoutSectionHeader>
254
294
  <CheckoutAddressForm
295
+ bind:this={billingFormRef}
255
296
  bind:address={billingAddress}
256
297
  label="billing"
257
298
  errors={billingErrors}
@@ -63,7 +63,12 @@ export interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "children">
63
63
  hLevel?: HLevel;
64
64
  hRenderLevel?: HLevel;
65
65
  }
66
+ import type { scrollToFirstInvalidField } from "../../utils/validate-fields.js";
66
67
  import { type HLevel } from "../H/H.svelte";
67
- declare const CheckoutShippingStep: import("svelte").Component<Props, {}, "el" | "shippingAddress" | "billingAddress" | "billingSameAsShipping" | "selectedDeliveryId">;
68
+ declare const CheckoutShippingStep: import("svelte").Component<Props, {
69
+ validate: () => boolean;
70
+ scrollToFirstError: (opts?: Parameters<typeof scrollToFirstInvalidField>[1]) => boolean;
71
+ clearValidation: () => void;
72
+ }, "el" | "shippingAddress" | "billingAddress" | "billingSameAsShipping" | "selectedDeliveryId">;
68
73
  type CheckoutShippingStep = ReturnType<typeof CheckoutShippingStep>;
69
74
  export default CheckoutShippingStep;
@@ -247,7 +247,13 @@
247
247
  }
248
248
  </script>
249
249
 
250
- <form bind:this={formEl} class={_class} use:onSubmitValidityCheck {...rest}>
250
+ <form
251
+ bind:this={formEl}
252
+ class={_class}
253
+ use:onSubmitValidityCheck
254
+ novalidate
255
+ {...rest}
256
+ >
251
257
  <!-- General error alert -->
252
258
  <DismissibleMessage message={error} intent="destructive" />
253
259
 
@@ -257,7 +257,13 @@
257
257
  }
258
258
  </script>
259
259
 
260
- <form bind:this={formEl} class={_class} use:onSubmitValidityCheck {...rest}>
260
+ <form
261
+ bind:this={formEl}
262
+ class={_class}
263
+ use:onSubmitValidityCheck
264
+ novalidate
265
+ {...rest}
266
+ >
261
267
  <!-- General error alert -->
262
268
  <DismissibleMessage message={error} intent="destructive" />
263
269
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marianmeres/stuic",
3
- "version": "3.88.0",
3
+ "version": "3.89.0",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && pnpm run prepack",