@gomusdev/web-components 1.11.0 → 1.13.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.
@@ -5447,6 +5447,10 @@ function createGetDetails(KEY2) {
5447
5447
  return function(host) {
5448
5448
  if (host) {
5449
5449
  const container = proxy({ data: void 0 });
5450
+ if (!host.isConnected) {
5451
+ console.error("(createGetDetails) Host is not mounted");
5452
+ return void 0;
5453
+ }
5450
5454
  host.dispatchEvent(new CustomEvent(KEY2, { detail: container, bubbles: true }));
5451
5455
  return container.data;
5452
5456
  } else {
@@ -6579,6 +6583,24 @@ const getUserProvider = (type) => {
6579
6583
  throw new Error("Unhandled shop type: " + never);
6580
6584
  }
6581
6585
  };
6586
+ function isEmpty(value) {
6587
+ return value === null || value === void 0 || typeof value === "string" && value.trim() === "";
6588
+ }
6589
+ function validateRequiredFields(body, requiredFields) {
6590
+ const errors2 = {};
6591
+ if (!requiredFields || requiredFields.length === 0) {
6592
+ return errors2;
6593
+ }
6594
+ for (const field of requiredFields) {
6595
+ if (!(field in body) || isEmpty(body[field])) {
6596
+ errors2[field] = [`Field '${field}' is required and cannot be empty`];
6597
+ }
6598
+ }
6599
+ return errors2;
6600
+ }
6601
+ function validateApiPostBody(body, requiredFields) {
6602
+ return validateRequiredFields(body, requiredFields);
6603
+ }
6582
6604
  var util;
6583
6605
  (function(util2) {
6584
6606
  util2.assertEqual = (val) => val;
@@ -11854,7 +11876,7 @@ class Shop {
11854
11876
  return this.fetchAndCache(TICKETS_ENDPOINT, `tickets-${JSON.stringify(params)}`, "tickets", { cache: 60, query: params });
11855
11877
  }
11856
11878
  signIn(params) {
11857
- return this.apiPost(SIGN_IN_ENDPOINT, { body: params });
11879
+ return this.apiPost(SIGN_IN_ENDPOINT, { body: params, requiredFields: ["email", "password"] });
11858
11880
  }
11859
11881
  signUp(params, asGuest = false) {
11860
11882
  const defaultParams = {
@@ -11865,10 +11887,19 @@ class Shop {
11865
11887
  level: asGuest ? CustomerLevels.SHOP_GUEST : CustomerLevels.SHOP
11866
11888
  };
11867
11889
  params = assign(defaultParams, params);
11868
- return this.apiPost(SIGN_UP_ENDPOINT, { body: params });
11890
+ let requiredFields = [
11891
+ "name",
11892
+ //first name
11893
+ "surname",
11894
+ "email",
11895
+ "email_confirmation",
11896
+ "terms"
11897
+ ];
11898
+ if (!asGuest) requiredFields.push("password", "password_confirmation");
11899
+ return this.apiPost(SIGN_UP_ENDPOINT, { body: params, requiredFields });
11869
11900
  }
11870
11901
  checkout(params) {
11871
- return this.apiPost(`/api/v4/orders`, { body: params });
11902
+ return this.apiPost(`/api/v4/orders`, { body: params, requiredFields: ["items", "total"] });
11872
11903
  }
11873
11904
  order(token) {
11874
11905
  return this.fetchAndCache("/api/v4/orders/{id}", `order-${token}`, "order", { path: { id: token } });
@@ -11877,7 +11908,7 @@ class Shop {
11877
11908
  return this.fetchAndCache("/api/v4/annual/order", `annual-order-${token}`, "order", { query: { token } });
11878
11909
  }
11879
11910
  finalizePersonalizations(token, params) {
11880
- return this.apiPost("/api/v4/annual/personalization/finalize", { body: params }, { query: { token } });
11911
+ return this.apiPost("/api/v4/annual/personalization/finalize", { body: params, params: { query: { token } } });
11881
11912
  }
11882
11913
  /**
11883
11914
  * Returns a reactive value that will contain the fetched data, no need to await.
@@ -11951,8 +11982,24 @@ class Shop {
11951
11982
  }
11952
11983
  };
11953
11984
  }
11954
- async apiPost(path, { body }, params = {}) {
11985
+ /**
11986
+ * Sends a POST request to the specified API endpoint.
11987
+ *
11988
+ * @param {string} path - The API endpoint path to make the POST request.
11989
+ * @param {Object} options - The options for the POST request.
11990
+ * @param {Record<string, any>} options.body - The body of the POST request, containing the data to be sent.
11991
+ * @param {Record<string, unknown>} [options.params] - Optional query parameters to include in the request.
11992
+ * @param {string[]} [options.requiredFields] - Optional list of required field names to validate in the body.
11993
+ * @return {Promise<T>} A promise that resolves with the typed response of the POST request.
11994
+ */
11995
+ async apiPost(path, options) {
11955
11996
  this.#ensureApi();
11997
+ const { body, params = {}, requiredFields } = options;
11998
+ const validationErrors = validateApiPostBody(body, requiredFields);
11999
+ if (Object.keys(validationErrors).length > 0) {
12000
+ console.log("shop.apiPost: validationErrors", { validationErrors, body });
12001
+ return { error: { errors: validationErrors } };
12002
+ }
11956
12003
  const ret = await this.client.POST(path, { body, params: assign(this.#defaultApiParams, params) });
11957
12004
  return ret;
11958
12005
  }
@@ -14704,7 +14751,6 @@ function validateField(field) {
14704
14751
  const _Forms = class _Forms {
14705
14752
  static defineForm(options) {
14706
14753
  go.defineConfig({ forms: { [options.id]: { fields: options.fields } } });
14707
- __privateGet(_Forms, _requiredApiKeysMap)[options.id] = options.requiredApiKeys || [];
14708
14754
  }
14709
14755
  static defineFields(fields) {
14710
14756
  go.defineConfig({ fields });
@@ -14712,9 +14758,6 @@ const _Forms = class _Forms {
14712
14758
  static setRequiredApiKeys(formId, requiredApiKeys) {
14713
14759
  __privateGet(_Forms, _requiredApiKeysMap)[formId] = requiredApiKeys;
14714
14760
  }
14715
- static getRequiredApiKeys(formId) {
14716
- return __privateGet(_Forms, _requiredApiKeysMap)[formId];
14717
- }
14718
14761
  static createField(key, required) {
14719
14762
  const init2 = _Forms.getFieldInit(key);
14720
14763
  if (!init2) {
@@ -14779,9 +14822,9 @@ function AnnualTicketPersonalizationForm($$anchor, $$props) {
14779
14822
  },
14780
14823
  []
14781
14824
  );
14782
- personalizationForms.forEach((detail) => {
14783
- detail.fields.forEach((f) => {
14784
- f.validate();
14825
+ personalizationForms.forEach((details2) => {
14826
+ details2.fields.forEach((f) => {
14827
+ details2.validateField(f);
14785
14828
  });
14786
14829
  });
14787
14830
  const isValid2 = iterate(
@@ -14929,18 +14972,6 @@ class FormDetails {
14929
14972
  const ret = Object.fromEntries(validFields.map((f) => [f.apiKey, coerce2(f.value)]));
14930
14973
  return ret;
14931
14974
  }
14932
- ensureApiRequiredFields() {
14933
- const formData = this.formData;
14934
- const missingKeys = this.requiredApiKeys.filter((k) => !(k in formData));
14935
- if (missingKeys.length > 0) {
14936
- console.error("(ensureApiRequiredFields) Missing required API keys: " + missingKeys.join(","));
14937
- return false;
14938
- }
14939
- return true;
14940
- }
14941
- get requiredApiKeys() {
14942
- return Forms.getRequiredApiKeys(this.formId);
14943
- }
14944
14975
  get apiErrors() {
14945
14976
  return get$2(this.#apiErrors);
14946
14977
  }
@@ -14967,6 +14998,23 @@ class FormDetails {
14967
14998
  field.apiErrors = value;
14968
14999
  }
14969
15000
  }
15001
+ validateForm() {
15002
+ get$2(this.#fields).forEach((f) => this.validateField(f));
15003
+ }
15004
+ validateField(field) {
15005
+ field.validate();
15006
+ if (field.apiKey === "password_confirmation") {
15007
+ const passwordField = this.fields.find((f) => f.apiKey === "password");
15008
+ if (!passwordField || passwordField && field.value !== passwordField.value) {
15009
+ field.errors.push("Passwords do not match");
15010
+ }
15011
+ } else if (field.apiKey === "email_confirmation") {
15012
+ const emailField = this.fields.find((f) => f.apiKey === "email");
15013
+ if (!emailField || emailField && field.value !== emailField.value) {
15014
+ field.errors.push("Emails do not match");
15015
+ }
15016
+ }
15017
+ }
14970
15018
  addField(field) {
14971
15019
  get$2(this.#fields).push(field);
14972
15020
  }
@@ -15011,9 +15059,7 @@ function Form($$anchor, $$props) {
15011
15059
  setDetails($$props.$$host, details);
15012
15060
  async function handleSubmit(event) {
15013
15061
  event.preventDefault();
15014
- details.fields.forEach((f) => {
15015
- f.validate();
15016
- });
15062
+ details.validateForm();
15017
15063
  details?.form?.dispatchEvent(new Event("after-validation", event));
15018
15064
  if (details.isValid) {
15019
15065
  details?.form?.dispatchEvent(new Event("go-submit", event));
@@ -15074,7 +15120,6 @@ function SignIn($$anchor, $$props) {
15074
15120
  let form;
15075
15121
  Forms.defineForm({
15076
15122
  id: "signIn",
15077
- requiredApiKeys: ["email", "password"],
15078
15123
  fields: [
15079
15124
  { key: "email", required: true },
15080
15125
  { key: "password", required: true }
@@ -15085,7 +15130,6 @@ function SignIn($$anchor, $$props) {
15085
15130
  throw new Error("(go-sign-in: form not found");
15086
15131
  }
15087
15132
  const result = await shop.signIn(form.details.formData);
15088
- form.details.ensureApiRequiredFields();
15089
15133
  if (result.data) {
15090
15134
  $$props.$$host.dispatchEvent(new Event("go-success", { bubbles: true, composed: true }));
15091
15135
  } else {
@@ -15297,6 +15341,10 @@ function syncCartToLocalStorage(cart2) {
15297
15341
  let lastLS = "";
15298
15342
  setInterval(
15299
15343
  () => {
15344
+ if (!localStorage) {
15345
+ console.warn("(syncCartToLocalStorage) localStorage is not available");
15346
+ return;
15347
+ }
15300
15348
  let newLS = localStorage.getItem("go-cart");
15301
15349
  if (lastLS && lastLS !== newLS) {
15302
15350
  loadFromLocalStorage(cart2);
@@ -15560,13 +15608,6 @@ function CheckoutForm($$anchor, $$props) {
15560
15608
  { key: "email", required: true },
15561
15609
  { key: "confirmEmail", required: true },
15562
15610
  { key: "acceptTerms", required: true }
15563
- ],
15564
- requiredApiKeys: [
15565
- "firstName",
15566
- "lastName",
15567
- "email",
15568
- "confirmEmail",
15569
- "acceptTerms"
15570
15611
  ]
15571
15612
  });
15572
15613
  wrapInElement($$props.$$host, "go-form", { "form-id": "checkoutGuest", custom: custom2() });
@@ -27571,7 +27612,7 @@ class BaseNumericSegmentState {
27571
27612
  getSegmentProps() {
27572
27613
  const segmentValues = this.root.segmentValues;
27573
27614
  const placeholder = this.root.placeholder.current;
27574
- const isEmpty = segmentValues[this.part] === null;
27615
+ const isEmpty2 = segmentValues[this.part] === null;
27575
27616
  let date2 = placeholder;
27576
27617
  if (segmentValues[this.part]) {
27577
27618
  date2 = placeholder.set({ [this.part]: Number.parseInt(segmentValues[this.part]) });
@@ -27579,9 +27620,9 @@ class BaseNumericSegmentState {
27579
27620
  const valueNow = date2[this.part];
27580
27621
  const valueMin = this.#getMin();
27581
27622
  const valueMax = this.#getMax();
27582
- let valueText = isEmpty ? "Empty" : `${valueNow}`;
27623
+ let valueText = isEmpty2 ? "Empty" : `${valueNow}`;
27583
27624
  if (this.part === "hour" && "dayPeriod" in segmentValues && segmentValues.dayPeriod) {
27584
- valueText = isEmpty ? "Empty" : `${valueNow} ${segmentValues.dayPeriod}`;
27625
+ valueText = isEmpty2 ? "Empty" : `${valueNow} ${segmentValues.dayPeriod}`;
27585
27626
  }
27586
27627
  return {
27587
27628
  "aria-label": `${this.part}, `,
@@ -29382,7 +29423,7 @@ var root_6 = /* @__PURE__ */ from_html(`<!> <!>`, 1);
29382
29423
  var root_1$8 = /* @__PURE__ */ from_html(`<!> <!> <!>`, 1);
29383
29424
  function DatePicker_1($$anchor, $$props) {
29384
29425
  push($$props, true);
29385
- let dateString = prop($$props, "dateString", 15);
29426
+ let dateString = prop($$props, "dateString", 15), labelClass = prop($$props, "labelClass", 7), inputClass = prop($$props, "inputClass", 7);
29386
29427
  let date2 = /* @__PURE__ */ state(proxy($14e0f24ef4ac5c92$export$d0bdf45af03a6ea3($14e0f24ef4ac5c92$export$aa8b41735afcabd2())));
29387
29428
  user_effect(() => {
29388
29429
  dateString(get$2(date2).toString());
@@ -29394,6 +29435,20 @@ function DatePicker_1($$anchor, $$props) {
29394
29435
  set dateString($$value) {
29395
29436
  dateString($$value);
29396
29437
  flushSync();
29438
+ },
29439
+ get labelClass() {
29440
+ return labelClass();
29441
+ },
29442
+ set labelClass($$value) {
29443
+ labelClass($$value);
29444
+ flushSync();
29445
+ },
29446
+ get inputClass() {
29447
+ return inputClass();
29448
+ },
29449
+ set inputClass($$value) {
29450
+ inputClass($$value);
29451
+ flushSync();
29397
29452
  }
29398
29453
  };
29399
29454
  var fragment = comment();
@@ -29410,7 +29465,11 @@ function DatePicker_1($$anchor, $$props) {
29410
29465
  var fragment_1 = root_1$8();
29411
29466
  var node_1 = first_child(fragment_1);
29412
29467
  component(node_1, () => Date_field_label, ($$anchor4, DatePicker_Label) => {
29413
- DatePicker_Label($$anchor4, { class: "go-datepicker-label" });
29468
+ DatePicker_Label($$anchor4, {
29469
+ get class() {
29470
+ return `go-datepicker-label $${labelClass() ?? ""}`;
29471
+ }
29472
+ });
29414
29473
  });
29415
29474
  var node_2 = sibling(node_1, 2);
29416
29475
  {
@@ -29447,7 +29506,9 @@ function DatePicker_1($$anchor, $$props) {
29447
29506
  };
29448
29507
  component(node_2, () => Date_field_input, ($$anchor4, DatePicker_Input) => {
29449
29508
  DatePicker_Input($$anchor4, {
29450
- class: "go-datepicker-input",
29509
+ get class() {
29510
+ return `go-datepicker-input $${inputClass() ?? ""}`;
29511
+ },
29451
29512
  children,
29452
29513
  $$slots: { default: true }
29453
29514
  });
@@ -29607,7 +29668,7 @@ function DatePicker_1($$anchor, $$props) {
29607
29668
  append($$anchor, fragment);
29608
29669
  return pop($$exports);
29609
29670
  }
29610
- create_custom_element(DatePicker_1, { dateString: {} }, [], [], true);
29671
+ create_custom_element(DatePicker_1, { dateString: {}, labelClass: {}, inputClass: {} }, [], [], true);
29611
29672
  var root_2$6 = /* @__PURE__ */ from_html(`<span class="go-field-star" aria-hidden="true">*</span>`);
29612
29673
  var root_1$7 = /* @__PURE__ */ from_html(`<!> <!>`, 1);
29613
29674
  var root_3$4 = /* @__PURE__ */ from_html(`<label><!></label> <input/>`, 1);
@@ -29646,6 +29707,7 @@ function InputAndLabel($$anchor, $$props) {
29646
29707
  () => ({
29647
29708
  ...get$2(fieldAttributes),
29648
29709
  ...restProps,
29710
+ class: inputClass(),
29649
29711
  placeholder: field().placeholder,
29650
29712
  type: field().type,
29651
29713
  name: field().key
@@ -29656,7 +29718,10 @@ function InputAndLabel($$anchor, $$props) {
29656
29718
  void 0,
29657
29719
  true
29658
29720
  );
29659
- template_effect(() => set_attribute(label, "for", get$2(inputId)));
29721
+ template_effect(() => {
29722
+ set_class(label, 1, clsx(labelClass()));
29723
+ set_attribute(label, "for", get$2(inputId));
29724
+ });
29660
29725
  bind_value(input_1, () => field().value, ($$value) => field(field().value = $$value, true));
29661
29726
  append($$anchor2, fragment_1);
29662
29727
  };
@@ -29684,7 +29749,10 @@ function InputAndLabel($$anchor, $$props) {
29684
29749
  labelText(node_3);
29685
29750
  reset(span_1);
29686
29751
  reset(label_1);
29687
- template_effect(() => set_attribute(label_1, "for", get$2(inputId)));
29752
+ template_effect(() => {
29753
+ set_class(label_1, 1, clsx(labelClass()));
29754
+ set_attribute(label_1, "for", get$2(inputId));
29755
+ });
29688
29756
  append($$anchor2, label_1);
29689
29757
  };
29690
29758
  const select = ($$anchor2) => {
@@ -29694,7 +29762,12 @@ function InputAndLabel($$anchor, $$props) {
29694
29762
  labelText(node_4);
29695
29763
  reset(label_2);
29696
29764
  var select_1 = sibling(label_2, 2);
29697
- attribute_effect(select_1, () => ({ ...get$2(fieldAttributes), ...restProps, name: field().key }));
29765
+ attribute_effect(select_1, () => ({
29766
+ ...get$2(fieldAttributes),
29767
+ ...restProps,
29768
+ name: field().key,
29769
+ class: inputClass()
29770
+ }));
29698
29771
  var node_5 = child(select_1);
29699
29772
  {
29700
29773
  var consequent_1 = ($$anchor3) => {
@@ -29720,12 +29793,21 @@ function InputAndLabel($$anchor, $$props) {
29720
29793
  });
29721
29794
  }
29722
29795
  reset(select_1);
29723
- template_effect(() => set_attribute(label_2, "for", get$2(inputId)));
29796
+ template_effect(() => {
29797
+ set_class(label_2, 1, clsx(labelClass()));
29798
+ set_attribute(label_2, "for", get$2(inputId));
29799
+ });
29724
29800
  bind_select_value(select_1, () => field().value, ($$value) => field(field().value = $$value, true));
29725
29801
  append($$anchor2, fragment_2);
29726
29802
  };
29727
29803
  const date2 = ($$anchor2) => {
29728
29804
  DatePicker_1($$anchor2, {
29805
+ get labelClass() {
29806
+ return labelClass();
29807
+ },
29808
+ get inputClass() {
29809
+ return inputClass();
29810
+ },
29729
29811
  get dateString() {
29730
29812
  return field().value;
29731
29813
  },
@@ -29749,9 +29831,23 @@ function InputAndLabel($$anchor, $$props) {
29749
29831
  var label_3 = root_11$1();
29750
29832
  var text_1 = child(label_3);
29751
29833
  var input_3 = sibling(text_1);
29752
- attribute_effect(input_3, () => ({ ...get$2(fieldAttributes), ...restProps, type: "radio" }), void 0, void 0, void 0, void 0, true);
29834
+ attribute_effect(
29835
+ input_3,
29836
+ () => ({
29837
+ ...get$2(fieldAttributes),
29838
+ ...restProps,
29839
+ class: inputClass(),
29840
+ type: "radio"
29841
+ }),
29842
+ void 0,
29843
+ void 0,
29844
+ void 0,
29845
+ void 0,
29846
+ true
29847
+ );
29753
29848
  reset(label_3);
29754
29849
  template_effect(() => {
29850
+ set_class(label_3, 1, clsx(labelClass()));
29755
29851
  set_attribute(label_3, "for", get$2(inputId) + get$2(option));
29756
29852
  set_text(text_1, `${get$2(option) ?? ""} `);
29757
29853
  });
@@ -29767,14 +29863,21 @@ function InputAndLabel($$anchor, $$props) {
29767
29863
  reset(fieldset);
29768
29864
  append($$anchor2, fieldset);
29769
29865
  };
29770
- let field = prop($$props, "field", 15), describedById = prop($$props, "describedById", 7), restProps = /* @__PURE__ */ rest_props($$props, [
29866
+ let field = prop($$props, "field", 15), describedById = prop($$props, "describedById", 7), labelClass = prop($$props, "labelClass", 7), inputClass = prop($$props, "inputClass", 7), host = prop($$props, "host", 7), restProps = /* @__PURE__ */ rest_props($$props, [
29771
29867
  "$$slots",
29772
29868
  "$$events",
29773
29869
  "$$legacy",
29774
29870
  "$$host",
29775
29871
  "field",
29776
- "describedById"
29872
+ "describedById",
29873
+ "labelClass",
29874
+ "inputClass",
29875
+ "host"
29777
29876
  ]);
29877
+ let details = /* @__PURE__ */ state(void 0);
29878
+ onMount(async () => {
29879
+ set(details, await pollUntilTruthy(() => getDetails(host())), true);
29880
+ });
29778
29881
  const map = {
29779
29882
  input,
29780
29883
  text: input,
@@ -29794,7 +29897,9 @@ function InputAndLabel($$anchor, $$props) {
29794
29897
  let inputId = /* @__PURE__ */ user_derived(() => $$props.id || `go-field-${Math.random().toString(36).substring(2, 9)}`);
29795
29898
  function onblur() {
29796
29899
  if (field().type == "checkbox") return;
29797
- if (field().value) field().validate();
29900
+ if (field().value) if (get$2(details))
29901
+ get$2(details).validateField(field());
29902
+ else field().validate();
29798
29903
  }
29799
29904
  const fieldAttributes = /* @__PURE__ */ user_derived(() => ({
29800
29905
  id: get$2(inputId),
@@ -29818,6 +29923,27 @@ function InputAndLabel($$anchor, $$props) {
29818
29923
  set describedById($$value) {
29819
29924
  describedById($$value);
29820
29925
  flushSync();
29926
+ },
29927
+ get labelClass() {
29928
+ return labelClass();
29929
+ },
29930
+ set labelClass($$value) {
29931
+ labelClass($$value);
29932
+ flushSync();
29933
+ },
29934
+ get inputClass() {
29935
+ return inputClass();
29936
+ },
29937
+ set inputClass($$value) {
29938
+ inputClass($$value);
29939
+ flushSync();
29940
+ },
29941
+ get host() {
29942
+ return host();
29943
+ },
29944
+ set host($$value) {
29945
+ host($$value);
29946
+ flushSync();
29821
29947
  }
29822
29948
  };
29823
29949
  var fragment_6 = comment();
@@ -29836,14 +29962,26 @@ function InputAndLabel($$anchor, $$props) {
29836
29962
  append($$anchor, fragment_6);
29837
29963
  return pop($$exports);
29838
29964
  }
29839
- create_custom_element(InputAndLabel, { field: {}, describedById: {} }, [], [], true);
29965
+ create_custom_element(
29966
+ InputAndLabel,
29967
+ {
29968
+ field: {},
29969
+ describedById: {},
29970
+ labelClass: {},
29971
+ inputClass: {},
29972
+ host: {}
29973
+ },
29974
+ [],
29975
+ [],
29976
+ true
29977
+ );
29840
29978
  var root_1$6 = /* @__PURE__ */ from_html(`<span> </span>`);
29841
29979
  var root_3$3 = /* @__PURE__ */ from_html(`<li> </li>`);
29842
29980
  var root_2$5 = /* @__PURE__ */ from_html(`<ul class="go-field-errors" role="alert"></ul>`);
29843
29981
  var root$5 = /* @__PURE__ */ from_html(`<!> <!> <!>`, 1);
29844
29982
  function Field($$anchor, $$props) {
29845
29983
  push($$props, true);
29846
- let key = prop($$props, "key", 7), required = prop($$props, "required", 7, false);
29984
+ let key = prop($$props, "key", 7), required = prop($$props, "required", 7, false), labelClass = prop($$props, "labelClass", 7), inputClass = prop($$props, "inputClass", 7);
29847
29985
  let field = /* @__PURE__ */ state(proxy(Forms.createField(key(), required())));
29848
29986
  let details = /* @__PURE__ */ state(void 0);
29849
29987
  onMount(async () => {
@@ -29868,7 +30006,7 @@ function Field($$anchor, $$props) {
29868
30006
  // Track the value
29869
30007
  ).value;
29870
30008
  untrack(() => {
29871
- if (get$2(field)?.errors.length) get$2(field).validate();
30009
+ if (get$2(field)?.errors.length) get$2(details).validateField(get$2(field));
29872
30010
  });
29873
30011
  });
29874
30012
  var $$exports = {
@@ -29886,6 +30024,20 @@ function Field($$anchor, $$props) {
29886
30024
  set required($$value = false) {
29887
30025
  required($$value);
29888
30026
  flushSync();
30027
+ },
30028
+ get labelClass() {
30029
+ return labelClass();
30030
+ },
30031
+ set labelClass($$value) {
30032
+ labelClass($$value);
30033
+ flushSync();
30034
+ },
30035
+ get inputClass() {
30036
+ return inputClass();
30037
+ },
30038
+ set inputClass($$value) {
30039
+ inputClass($$value);
30040
+ flushSync();
29889
30041
  }
29890
30042
  };
29891
30043
  var fragment = root$5();
@@ -29894,6 +30046,13 @@ function Field($$anchor, $$props) {
29894
30046
  get describedById() {
29895
30047
  return get$2(describedById);
29896
30048
  },
30049
+ get labelClass() {
30050
+ return labelClass();
30051
+ },
30052
+ get inputClass() {
30053
+ return inputClass();
30054
+ },
30055
+ host: $$props.$$host,
29897
30056
  get field() {
29898
30057
  return get$2(field);
29899
30058
  },
@@ -29943,7 +30102,9 @@ customElements.define("go-field", create_custom_element(
29943
30102
  Field,
29944
30103
  {
29945
30104
  key: { attribute: "key", reflect: true, type: "String" },
29946
- required: { attribute: "required", reflect: true, type: "Boolean" }
30105
+ required: { attribute: "required", reflect: true, type: "Boolean" },
30106
+ labelClass: { attribute: "label-class", reflect: true, type: "String" },
30107
+ inputClass: { attribute: "input-class", reflect: true, type: "String" }
29947
30108
  },
29948
30109
  [],
29949
30110
  ["getField"],
@@ -29976,15 +30137,18 @@ var root_5 = /* @__PURE__ */ from_html(`<p aria-hidden="true"> </p>`);
29976
30137
  var root_1$4 = /* @__PURE__ */ from_html(`<div><!> <!> <!></div>`);
29977
30138
  function ErrorsFeedback($$anchor, $$props) {
29978
30139
  push($$props, true);
29979
- let details = getDetails($$props.$$host);
30140
+ let details = /* @__PURE__ */ state(void 0);
30141
+ onMount(async () => {
30142
+ set(details, await pollUntilTruthy(() => getDetails($$props.$$host)), true);
30143
+ });
29980
30144
  user_effect(() => {
29981
- details?.form?.addEventListener("after-validation", () => {
29982
- set(errorsOnSubmit, errors(details?.fields), true);
30145
+ get$2(details)?.form?.addEventListener("after-validation", () => {
30146
+ set(errorsOnSubmit, errors(get$2(details)?.fields), true);
29983
30147
  });
29984
30148
  });
29985
- let errorsRealtime = /* @__PURE__ */ user_derived(() => errors(details?.fields));
30149
+ let errorsRealtime = /* @__PURE__ */ user_derived(() => errors(get$2(details)?.fields));
29986
30150
  let errorsOnSubmit = /* @__PURE__ */ state(-1);
29987
- let generalApiErrors = /* @__PURE__ */ user_derived(() => details && isArray(details.apiErrors) && details.apiErrors.length > 0 ? details.apiErrors : []);
30151
+ let generalApiErrors = /* @__PURE__ */ user_derived(() => get$2(details) && isArray(get$2(details).apiErrors) && get$2(details).apiErrors.length > 0 ? get$2(details).apiErrors : []);
29988
30152
  var fragment = comment();
29989
30153
  var node = first_child(fragment);
29990
30154
  {
@@ -30008,7 +30172,7 @@ function ErrorsFeedback($$anchor, $$props) {
30008
30172
  {
30009
30173
  var consequent_1 = ($$anchor3) => {
30010
30174
  var ul = root_3$2();
30011
- each(ul, 21, () => details?.apiErrors, index$1, ($$anchor4, error) => {
30175
+ each(ul, 21, () => get$2(details)?.apiErrors, index$1, ($$anchor4, error) => {
30012
30176
  var li = root_4$1();
30013
30177
  var text_1 = child(li, true);
30014
30178
  reset(li);
@@ -30019,7 +30183,7 @@ function ErrorsFeedback($$anchor, $$props) {
30019
30183
  append($$anchor3, ul);
30020
30184
  };
30021
30185
  if_block(node_2, ($$render) => {
30022
- if (details && isArray(details.apiErrors) && details.apiErrors.length > 0) $$render(consequent_1);
30186
+ if (get$2(details) && isArray(get$2(details).apiErrors) && get$2(details).apiErrors.length > 0) $$render(consequent_1);
30023
30187
  });
30024
30188
  }
30025
30189
  var node_3 = sibling(node_2, 2);
@@ -30060,14 +30224,32 @@ function FormFeedback($$anchor, $$props) {
30060
30224
  customElements.define("go-form-feedback", create_custom_element(FormFeedback, {}, ["default"], [], false));
30061
30225
  function Submit($$anchor, $$props) {
30062
30226
  push($$props, true);
30227
+ let buttonClass = prop($$props, "buttonClass", 7, "");
30063
30228
  let details = /* @__PURE__ */ state(void 0);
30064
30229
  onMount(() => {
30065
30230
  set(details, getDetails($$props.$$host), true);
30066
- wrapInElement($$props.$$host, "button", { type: "submit" });
30231
+ wrapInElement($$props.$$host, "button", { type: "submit", class: buttonClass() });
30067
30232
  });
30068
- pop();
30233
+ var $$exports = {
30234
+ get buttonClass() {
30235
+ return buttonClass();
30236
+ },
30237
+ set buttonClass($$value = "") {
30238
+ buttonClass($$value);
30239
+ flushSync();
30240
+ }
30241
+ };
30242
+ return pop($$exports);
30069
30243
  }
30070
- customElements.define("go-submit", create_custom_element(Submit, {}, [], [], false));
30244
+ customElements.define("go-submit", create_custom_element(
30245
+ Submit,
30246
+ {
30247
+ buttonClass: { attribute: "button-class", reflect: true, type: "String" }
30248
+ },
30249
+ [],
30250
+ [],
30251
+ false
30252
+ ));
30071
30253
  var root_1$3 = /* @__PURE__ */ from_html(`<p>Form submitted successfully!</p>`);
30072
30254
  var root$3 = /* @__PURE__ */ from_html(`<div aria-live="assertive"><!></div>`);
30073
30255
  function SuccessFeedback($$anchor, $$props) {
@@ -30258,7 +30440,12 @@ function If($$anchor, $$props) {
30258
30440
  }
30259
30441
  });
30260
30442
  onMount(async () => {
30261
- set(formDetails, await pollUntilTruthy(() => getDetails($$props.$$host)), true);
30443
+ try {
30444
+ set(formDetails, await pollUntilTruthy(() => getDetails($$props.$$host)), true);
30445
+ } catch (error) {
30446
+ console.error("(IF) Error fetching form details:", error);
30447
+ console.error("Stack trace:", error instanceof Error ? error.stack : "No stack trace available");
30448
+ }
30262
30449
  });
30263
30450
  var $$exports = {
30264
30451
  get data() {
@@ -478,9 +478,21 @@ export declare class Shop {
478
478
  annualTicketPersonalizationList: (token: string) => string;
479
479
  annualTicketPersonalizationFormSubmit: (token: string) => string;
480
480
  } | undefined;
481
- apiPost<T>(path: string, { body }: {
481
+ /**
482
+ * Sends a POST request to the specified API endpoint.
483
+ *
484
+ * @param {string} path - The API endpoint path to make the POST request.
485
+ * @param {Object} options - The options for the POST request.
486
+ * @param {Record<string, any>} options.body - The body of the POST request, containing the data to be sent.
487
+ * @param {Record<string, unknown>} [options.params] - Optional query parameters to include in the request.
488
+ * @param {string[]} [options.requiredFields] - Optional list of required field names to validate in the body.
489
+ * @return {Promise<T>} A promise that resolves with the typed response of the POST request.
490
+ */
491
+ apiPost<T>(path: string, options: {
482
492
  body: Record<string, any>;
483
- }, params?: Record<string, unknown>): Promise<T>;
493
+ params?: Record<string, unknown>;
494
+ requiredFields?: string[];
495
+ }): Promise<T>;
484
496
  waitForAllFetches(...variables: unknown[]): Promise<void>;
485
497
  apiGet(path: `/api${string}`, query?: Record<string, unknown>, pathOptions?: Record<string, unknown>): Promise<unknown>;
486
498
  }
@@ -0,0 +1,18 @@
1
+ export type ValidationErrors = Record<string, string[]>;
2
+ /**
3
+ * Checks if a value is empty (null, undefined, empty string, or whitespace-only string)
4
+ */
5
+ export declare function isEmpty(value: unknown): boolean;
6
+ /**
7
+ * Validates that all required fields are present and non-empty in the body
8
+ * @returns Record of field names to error messages, empty if all valid
9
+ */
10
+ export declare function validateRequiredFields(body: Record<string, any>, requiredFields?: string[]): ValidationErrors;
11
+ /**
12
+ * Validates the entire request body for API POST requests
13
+ * - Validates required fields
14
+ * - Validates email fields
15
+ * - Validates password fields
16
+ * @returns Record of field names to error messages, empty if all valid
17
+ */
18
+ export declare function validateApiPostBody(body: Record<string, any>, requiredFields?: string[]): ValidationErrors;
@@ -0,0 +1 @@
1
+ export {};