@ticketmaster/tm-global-address 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 (70) hide show
  1. package/dist/components/AddressCard/AddressCard.d.ts +5 -0
  2. package/dist/components/AddressCard/AddressCard.js +45 -46
  3. package/dist/components/AddressForm/AddressForm.d.ts +14 -2
  4. package/dist/components/AddressForm/AddressForm.js +204 -227
  5. package/dist/components/AddressList/AddressList.d.ts +7 -2
  6. package/dist/components/AddressList/AddressList.js +41 -37
  7. package/dist/components/PhoneField/PhoneField.d.ts +57 -0
  8. package/dist/components/PhoneField/PhoneField.js +119 -0
  9. package/dist/i18n/defaultLabels.d.ts +2 -0
  10. package/dist/i18n/defaultLabels.js +66 -0
  11. package/dist/i18n/index.d.ts +14 -0
  12. package/dist/i18n/index.js +45 -0
  13. package/dist/i18n/labelResolver.d.ts +24 -0
  14. package/dist/i18n/labelResolver.js +98 -0
  15. package/dist/i18n/locales/ar-sa.json.d.ts +159 -0
  16. package/dist/i18n/locales/ar-sa.json.js +163 -0
  17. package/dist/i18n/locales/ca-es.json.d.ts +159 -0
  18. package/dist/i18n/locales/ca-es.json.js +163 -0
  19. package/dist/i18n/locales/cs-cz.json.d.ts +159 -0
  20. package/dist/i18n/locales/cs-cz.json.js +163 -0
  21. package/dist/i18n/locales/da-dk.json.d.ts +159 -0
  22. package/dist/i18n/locales/da-dk.json.js +163 -0
  23. package/dist/i18n/locales/de-at.json.d.ts +159 -0
  24. package/dist/i18n/locales/de-at.json.js +163 -0
  25. package/dist/i18n/locales/de-ch.json.d.ts +159 -0
  26. package/dist/i18n/locales/de-ch.json.js +163 -0
  27. package/dist/i18n/locales/de-de.json.d.ts +159 -0
  28. package/dist/i18n/locales/de-de.json.js +163 -0
  29. package/dist/i18n/locales/en-au.json.d.ts +159 -0
  30. package/dist/i18n/locales/en-au.json.js +163 -0
  31. package/dist/i18n/locales/en-ca.json.d.ts +159 -0
  32. package/dist/i18n/locales/en-ca.json.js +163 -0
  33. package/dist/i18n/locales/en-gb.json.d.ts +159 -0
  34. package/dist/i18n/locales/en-gb.json.js +163 -0
  35. package/dist/i18n/locales/en-nz.json.d.ts +159 -0
  36. package/dist/i18n/locales/en-nz.json.js +163 -0
  37. package/dist/i18n/locales/en-us.json.d.ts +159 -0
  38. package/dist/i18n/locales/en-us.json.js +163 -0
  39. package/dist/i18n/locales/es-es.json.d.ts +159 -0
  40. package/dist/i18n/locales/es-es.json.js +163 -0
  41. package/dist/i18n/locales/es-mx.json.d.ts +159 -0
  42. package/dist/i18n/locales/es-mx.json.js +163 -0
  43. package/dist/i18n/locales/fi-fi.json.d.ts +159 -0
  44. package/dist/i18n/locales/fi-fi.json.js +163 -0
  45. package/dist/i18n/locales/fr-be.json.d.ts +159 -0
  46. package/dist/i18n/locales/fr-be.json.js +163 -0
  47. package/dist/i18n/locales/fr-ca.json.d.ts +159 -0
  48. package/dist/i18n/locales/fr-ca.json.js +163 -0
  49. package/dist/i18n/locales/fr-ch.json.d.ts +159 -0
  50. package/dist/i18n/locales/fr-ch.json.js +163 -0
  51. package/dist/i18n/locales/fr-fr.json.d.ts +159 -0
  52. package/dist/i18n/locales/fr-fr.json.js +163 -0
  53. package/dist/i18n/locales/it-ch.json.d.ts +159 -0
  54. package/dist/i18n/locales/it-ch.json.js +163 -0
  55. package/dist/i18n/locales/ja-jp.json.d.ts +159 -0
  56. package/dist/i18n/locales/ja-jp.json.js +163 -0
  57. package/dist/i18n/locales/nl-be.json.d.ts +159 -0
  58. package/dist/i18n/locales/nl-be.json.js +163 -0
  59. package/dist/i18n/locales/nl-nl.json.d.ts +159 -0
  60. package/dist/i18n/locales/nl-nl.json.js +163 -0
  61. package/dist/i18n/locales/no-no.json.d.ts +159 -0
  62. package/dist/i18n/locales/no-no.json.js +163 -0
  63. package/dist/i18n/locales/pl-pl.json.d.ts +159 -0
  64. package/dist/i18n/locales/pl-pl.json.js +163 -0
  65. package/dist/i18n/locales/sv-se.json.d.ts +159 -0
  66. package/dist/i18n/locales/sv-se.json.js +163 -0
  67. package/dist/i18n/types.d.ts +67 -0
  68. package/dist/index.d.ts +4 -0
  69. package/dist/index.js +48 -38
  70. package/package.json +1 -1
@@ -3,8 +3,8 @@ import { AddressData } from '../../types/AddressData';
3
3
  export interface AddressListProps {
4
4
  addresses: AddressData[];
5
5
  selectedAddressId?: number;
6
- /** Section label above the list */
7
- addressLabel: string;
6
+ /** Section label above the list (overrides i18n when provided) */
7
+ addressLabel?: string;
8
8
  maxAddresses: number;
9
9
  /** Called when user selects an address from the list */
10
10
  onSelect: (address: AddressData) => void;
@@ -19,6 +19,11 @@ export interface AddressListProps {
19
19
  disabled?: boolean;
20
20
  /** Per-card error messages, keyed by addressId */
21
21
  cardErrors?: Record<number, string>;
22
+ /**
23
+ * BCP-47 locale tag. Controls button labels.
24
+ * Defaults to "en-us".
25
+ */
26
+ locale?: string;
22
27
  }
23
28
  /**
24
29
  * AddressList — the LIST (expanded dropdown) state.
@@ -1,22 +1,23 @@
1
1
  import { jsxs as n, jsx as o } from "react/jsx-runtime";
2
2
  import r from "styled-components";
3
3
  import { tokens as e } from "../../styles/tokens.js";
4
- import { AddressCard as b } from "../AddressCard/AddressCard.js";
5
- const h = r.div`
4
+ import { AddressCard as y } from "../AddressCard/AddressCard.js";
5
+ import { useLabels as v } from "../../i18n/index.js";
6
+ const L = r.div`
6
7
  display: flex;
7
8
  flex-direction: column;
8
9
  gap: ${e.space2};
9
- `, g = r.div`
10
+ `, k = r.div`
10
11
  display: flex;
11
12
  align-items: center;
12
13
  justify-content: space-between;
13
14
  margin-block-end: ${e.space2};
14
- `, y = r.p`
15
+ `, I = r.p`
15
16
  margin: 0;
16
17
  font-size: ${e.fontSizeLabel};
17
18
  font-weight: ${e.fontWeightBold};
18
19
  color: ${e.colorTextPrimary};
19
- `, v = r.button`
20
+ `, S = r.button`
20
21
  appearance: none;
21
22
  background: none;
22
23
  border: none;
@@ -36,16 +37,16 @@ const h = r.div`
36
37
  outline-offset: 2px;
37
38
  border-radius: 2px;
38
39
  }
39
- `, k = r.ul`
40
+ `, B = r.ul`
40
41
  list-style: none;
41
42
  margin: 0;
42
43
  padding: 0;
43
44
  display: flex;
44
45
  flex-direction: column;
45
46
  gap: ${e.space3};
46
- `, I = r.li``, S = r.div`
47
+ `, z = r.li``, C = r.div`
47
48
  margin-block-start: ${e.space3};
48
- `, B = r.button`
49
+ `, w = r.button`
49
50
  appearance: none;
50
51
  background: none;
51
52
  border: none;
@@ -75,7 +76,7 @@ const h = r.div`
75
76
  cursor: not-allowed;
76
77
  text-decoration: none;
77
78
  }
78
- `, L = r.div`
79
+ `, P = r.div`
79
80
  display: flex;
80
81
  align-items: flex-start;
81
82
  gap: ${e.space2};
@@ -86,64 +87,67 @@ const h = r.div`
86
87
  font-size: ${e.fontSizeBody};
87
88
  color: ${e.colorTextSecondary};
88
89
  margin-block-start: ${e.space3};
89
- `, P = ({
90
+ `, M = ({
90
91
  addresses: a,
91
- selectedAddressId: l,
92
- addressLabel: d,
93
- maxAddresses: s,
94
- onSelect: c,
95
- onEdit: p,
96
- onDelete: u,
97
- onAdd: f,
98
- onCollapse: m,
92
+ selectedAddressId: c,
93
+ addressLabel: p,
94
+ maxAddresses: u,
95
+ onSelect: f,
96
+ onEdit: m,
97
+ onDelete: b,
98
+ onAdd: x,
99
+ onCollapse: $,
99
100
  disabled: i = !1,
100
- cardErrors: x = {}
101
+ cardErrors: g = {},
102
+ locale: d = "en-us"
101
103
  }) => {
102
- const $ = a.length >= s;
103
- return /* @__PURE__ */ n(h, { children: [
104
- /* @__PURE__ */ n(g, { children: [
105
- /* @__PURE__ */ o(y, { children: d }),
104
+ const { form: s } = v(d, ""), l = p ?? s.addressHeading, h = a.length >= u;
105
+ return /* @__PURE__ */ n(L, { children: [
106
+ /* @__PURE__ */ n(k, { children: [
107
+ /* @__PURE__ */ o(I, { children: l }),
106
108
  /* @__PURE__ */ o(
107
- v,
109
+ S,
108
110
  {
109
111
  type: "button",
110
- onClick: m,
112
+ onClick: $,
111
113
  disabled: i,
112
114
  "aria-label": "Collapse address list",
113
115
  children: "▲"
114
116
  }
115
117
  )
116
118
  ] }),
117
- /* @__PURE__ */ o(k, { role: "listbox", "aria-label": d, children: a.map((t) => /* @__PURE__ */ o(I, { children: /* @__PURE__ */ o(
118
- b,
119
+ /* @__PURE__ */ o(B, { role: "listbox", "aria-label": l, children: a.map((t) => /* @__PURE__ */ o(z, { children: /* @__PURE__ */ o(
120
+ y,
119
121
  {
120
122
  address: t,
121
- isSelected: t.addressId === l,
122
- onSelect: c,
123
- onEdit: p,
124
- onDelete: u,
123
+ isSelected: t.addressId === c,
124
+ onSelect: f,
125
+ onEdit: m,
126
+ onDelete: b,
125
127
  disabled: i,
126
- errorMessage: x[t.addressId]
128
+ errorMessage: g[t.addressId],
129
+ locale: d
127
130
  }
128
131
  ) }, t.addressId)) }),
129
- /* @__PURE__ */ o(S, { children: $ ? /* @__PURE__ */ n(L, { role: "status", children: [
132
+ /* @__PURE__ */ o(C, { children: h ? /* @__PURE__ */ n(P, { role: "status", children: [
130
133
  /* @__PURE__ */ o("span", { "aria-hidden": "true", children: "ℹ" }),
131
134
  /* @__PURE__ */ o("span", { children: "You've reached the maximum number of addresses. Please edit or remove one to add another." })
132
135
  ] }) : /* @__PURE__ */ n(
133
- B,
136
+ w,
134
137
  {
135
138
  type: "button",
136
139
  disabled: i,
137
- onClick: f,
140
+ onClick: x,
138
141
  "data-testid": "add-new-address",
139
142
  children: [
140
143
  /* @__PURE__ */ o("span", { "aria-hidden": "true", children: "+" }),
141
- " Add New Address"
144
+ " ",
145
+ s.addNewAddress
142
146
  ]
143
147
  }
144
148
  ) })
145
149
  ] });
146
150
  };
147
151
  export {
148
- P as AddressList
152
+ M as AddressList
149
153
  };
@@ -0,0 +1,57 @@
1
+ import { default as React } from 'react';
2
+ export interface PhoneFieldProps {
3
+ /** Current phone number value (local number, without dial code) */
4
+ value: string;
5
+ /** Dial code to display as non-editable prefix (e.g. '+1', '+44') */
6
+ dialCode: string;
7
+ /** Flag emoji for the selected country (e.g. '🇺🇸') */
8
+ flagEmoji: string;
9
+ /** ISO 3166-1 alpha-2 code used for aria-label on the dial code prefix */
10
+ countryCode: string;
11
+ /** Called when the input value changes */
12
+ onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
13
+ /** Called when the input loses focus */
14
+ onBlur: () => void;
15
+ /** Disable all interaction */
16
+ disabled?: boolean;
17
+ /** Whether the field is in an error state (red border) */
18
+ hasError?: boolean;
19
+ /** Error message to render below the field */
20
+ errorMessage?: string;
21
+ /** Screen reader prefix prepended to error messages (GDS requirement) */
22
+ screenReaderErrorPrefix?: string;
23
+ /** id attribute for the underlying <input> — used for label association */
24
+ id?: string;
25
+ }
26
+ /**
27
+ * PhoneField — a phone number input with a non-interactive country dial code prefix.
28
+ *
29
+ * The dial code is derived from the country selected in the parent `AddressForm` and
30
+ * is read-only — the fan selects their country in the country dropdown, which updates
31
+ * the dial code automatically. The fan only types the local number portion here.
32
+ *
33
+ * Phone is optional — empty value does not trigger validation. Validation occurs on
34
+ * blur when the field is non-empty, using `validatePhoneNumber` (libphonenumber-js/max).
35
+ *
36
+ * Usage in AddressForm:
37
+ * ```tsx
38
+ * <PhoneField
39
+ * id="field-phoneNumber"
40
+ * value={values.phoneNumber}
41
+ * dialCode={countryConfig.dialCode}
42
+ * flagEmoji={flag}
43
+ * countryCode={values.country}
44
+ * onChange={handleChange('phoneNumber')}
45
+ * onBlur={handleBlur('phoneNumber')}
46
+ * disabled={isDisabled}
47
+ * hasError={Boolean(getFieldError('phoneNumber'))}
48
+ * errorMessage={getFieldError('phoneNumber')}
49
+ * screenReaderErrorPrefix={screenReaderErrorPrefix}
50
+ * />
51
+ * ```
52
+ *
53
+ * TODO(GDS swap): Replace with GDS PhoneNumber component. The GDS PhoneNumber
54
+ * component provides built-in dial code selection integrated with the CountryPicker.
55
+ */
56
+ export declare const PhoneField: React.FC<PhoneFieldProps>;
57
+ export default PhoneField;
@@ -0,0 +1,119 @@
1
+ import { jsxs as r, jsx as c } from "react/jsx-runtime";
2
+ import e from "styled-components";
3
+ import { tokens as o } from "../../styles/tokens.js";
4
+ const f = e.div`
5
+ display: flex;
6
+ gap: ${o.space2};
7
+ align-items: flex-start;
8
+ `, m = e.div`
9
+ display: flex;
10
+ align-items: center;
11
+ gap: ${o.space1};
12
+ padding: ${o.space2} ${o.space3};
13
+ background: ${o.colorSurfaceSecondary};
14
+ border: ${o.borderWidthInput} solid ${o.colorBorderInput};
15
+ border-radius: ${o.borderRadiusInput};
16
+ font-size: ${o.fontSizeBody};
17
+ color: ${o.colorTextPrimary};
18
+ white-space: nowrap;
19
+ flex-shrink: 0;
20
+ /* Align vertically with the input */
21
+ height: fit-content;
22
+ `, x = e.input`
23
+ flex: 1;
24
+ width: 100%;
25
+ padding: ${o.space2} ${o.space3};
26
+ font-size: ${o.fontSizeInput};
27
+ font-family: ${o.fontFamily};
28
+ color: ${o.colorTextPrimary};
29
+ background: ${o.colorSurfacePrimary};
30
+ border: ${o.borderWidthInput} solid
31
+ ${(t) => t.$hasError ? o.colorBorderInputError : o.colorBorderInput};
32
+ border-radius: ${o.borderRadiusInput};
33
+ box-sizing: border-box;
34
+ transition: border-color ${o.transitionFast};
35
+
36
+ &::placeholder {
37
+ color: ${o.colorTextPlaceholder};
38
+ }
39
+
40
+ &:hover:not(:disabled) {
41
+ border-color: ${o.colorBorderInputFocus};
42
+ }
43
+
44
+ &:focus {
45
+ outline: none;
46
+ border-color: ${o.colorBorderInputFocus};
47
+ box-shadow: 0 0 0 ${o.borderWidthInputFocus} ${o.colorBorderInputFocus};
48
+ }
49
+
50
+ &:disabled {
51
+ background: ${o.colorSurfaceDisabled};
52
+ color: ${o.colorTextDisabled};
53
+ border-color: ${o.colorBorderInputDisabled};
54
+ cursor: not-allowed;
55
+ }
56
+ `, g = e.p`
57
+ margin: ${o.space1} 0 0;
58
+ font-size: ${o.fontSizeError};
59
+ color: ${o.colorTextError};
60
+ display: flex;
61
+ align-items: center;
62
+ gap: ${o.space1};
63
+ `, v = ({
64
+ value: t,
65
+ dialCode: i,
66
+ flagEmoji: s,
67
+ countryCode: p,
68
+ onChange: u,
69
+ onBlur: $,
70
+ disabled: b = !1,
71
+ hasError: a = !1,
72
+ errorMessage: d,
73
+ screenReaderErrorPrefix: h,
74
+ id: l = "field-phoneNumber"
75
+ }) => {
76
+ const n = `${l}-error`;
77
+ return /* @__PURE__ */ r("div", { children: [
78
+ /* @__PURE__ */ r(f, { children: [
79
+ i && /* @__PURE__ */ r(
80
+ m,
81
+ {
82
+ "aria-label": `Dial code ${i}`,
83
+ "data-testid": `dial-code-${p}`,
84
+ children: [
85
+ s,
86
+ " ",
87
+ i
88
+ ]
89
+ }
90
+ ),
91
+ /* @__PURE__ */ c(
92
+ x,
93
+ {
94
+ id: l,
95
+ type: "tel",
96
+ autoComplete: "tel",
97
+ value: t,
98
+ onChange: u,
99
+ onBlur: $,
100
+ maxLength: 20,
101
+ disabled: b,
102
+ $hasError: a,
103
+ "aria-invalid": a,
104
+ "aria-describedby": d ? n : void 0,
105
+ "data-testid": "phone-input"
106
+ }
107
+ )
108
+ ] }),
109
+ d && /* @__PURE__ */ r(g, { id: n, role: "alert", children: [
110
+ /* @__PURE__ */ c("span", { "aria-hidden": "true", children: "⚠" }),
111
+ h,
112
+ " ",
113
+ d
114
+ ] })
115
+ ] });
116
+ };
117
+ export {
118
+ v as PhoneField
119
+ };
@@ -0,0 +1,2 @@
1
+ import { LocaleBundle } from './types';
2
+ export declare const DEFAULT_LABELS: LocaleBundle;
@@ -0,0 +1,66 @@
1
+ const e = {
2
+ form: {
3
+ // Field labels
4
+ firstName: "First Name",
5
+ lastName: "Last Name",
6
+ address1: "Address Line 1",
7
+ address2: "Address Line 2 (Optional)",
8
+ city: "City",
9
+ postal: "Postal Code",
10
+ stateCode: "State / Province",
11
+ country: "Country",
12
+ phoneNumber: "Phone Number",
13
+ dialCode: "Dial Code",
14
+ defaultAddress: "Make this my default address",
15
+ // Placeholders
16
+ countryPlaceholder: "Please select",
17
+ stateCodePlaceholder: "Select state or province",
18
+ phoneNumberPlaceholder: "Enter your phone number",
19
+ // UI strings
20
+ addressHeading: "Address",
21
+ addNewAddress: "Add New Address",
22
+ confirm: "Confirm Address",
23
+ cancel: "Cancel",
24
+ editButton: "Edit",
25
+ deleteButton: "Delete",
26
+ defaultBadge: "Default",
27
+ makeDefault: "Make this my default address",
28
+ countrySelectPlaceholder: "Choose country"
29
+ },
30
+ validation: {
31
+ FIELD_REQUIRED: "{{field}} is required",
32
+ FIELD_TOO_LONG: "{{field}} must not exceed {{maxLength}} characters",
33
+ FIELD_TOO_SHORT: "{{field}} must be at least {{minLength}} characters",
34
+ FIELD_INVALID_FORMAT: "Please enter a valid {{field}}",
35
+ FIELD_INVALID_CHARACTERS: "{{field}} contains invalid characters",
36
+ POSTAL_CODE_MISMATCH: "Postal code does not match the selected {{stateLabel}}"
37
+ },
38
+ country: {
39
+ US: { stateCode: "State", stateCodePlaceholder: "Select the state" },
40
+ CA: { stateCode: "Province", stateCodePlaceholder: "Select the province" },
41
+ AU: { stateCode: "State", stateCodePlaceholder: "Select the state", city: "Suburb" },
42
+ GB: { postal: "Postcode" },
43
+ IE: { stateCode: "County", stateCodePlaceholder: "Select the county" },
44
+ NZ: { stateCode: "Region", stateCodePlaceholder: "Select the region", city: "Town/City" },
45
+ DE: { stateCode: "State", stateCodePlaceholder: "Select the state" },
46
+ AT: { stateCode: "State", stateCodePlaceholder: "Select the state" },
47
+ CH: { stateCode: "Canton", stateCodePlaceholder: "Select the canton" },
48
+ CZ: { stateCode: "Region", stateCodePlaceholder: "Select the region" },
49
+ DK: { stateCode: "Region", stateCodePlaceholder: "Select the region" },
50
+ ES: { stateCode: "State", stateCodePlaceholder: "Select the state" },
51
+ FI: { stateCode: "Region", stateCodePlaceholder: "Select the region" },
52
+ MX: { stateCode: "State", stateCodePlaceholder: "Select the state" },
53
+ NL: { stateCode: "Province", stateCodePlaceholder: "Select the province" },
54
+ NO: { stateCode: "County", stateCodePlaceholder: "Select the county" },
55
+ PL: { stateCode: "Region / Province", stateCodePlaceholder: "Select the region / province" },
56
+ SE: { stateCode: "Region", stateCodePlaceholder: "Select the region" },
57
+ ZA: { stateCode: "State", stateCodePlaceholder: "Select the state" },
58
+ // Postal-code overrides
59
+ IN: { postal: "PIN Code" },
60
+ JP: { postal: "Postal Code", stateCode: "Prefecture", stateCodePlaceholder: "Select the prefecture" },
61
+ AE: { stateCode: "Emirate", stateCodePlaceholder: "Select the emirate" }
62
+ }
63
+ };
64
+ export {
65
+ e as DEFAULT_LABELS
66
+ };
@@ -0,0 +1,14 @@
1
+ import { resolveLabels, isRTLLocale, interpolate, loadBundle } from './labelResolver';
2
+ import { ResolvedLabels, LocaleBundle, InterpolationVars } from './types';
3
+ export type { ResolvedLabels, LocaleBundle, InterpolationVars };
4
+ export type { FormLabels, ValidationLabels, CountryOverrides, } from './types';
5
+ export { isRTLLocale, interpolate, loadBundle, resolveLabels };
6
+ /**
7
+ * React hook that returns resolved labels for the given locale and country.
8
+ *
9
+ * Memoised on (locale, countryCode) — re-runs only when either changes.
10
+ */
11
+ export declare function useLabels(locale: string, countryCode: string): ResolvedLabels;
12
+ /** All supported locale codes */
13
+ export declare const SUPPORTED_LOCALES: readonly ["ar-sa", "ca-es", "cs-cz", "da-dk", "de-at", "de-ch", "de-de", "en-au", "en-ca", "en-gb", "en-nz", "en-us", "es-es", "es-mx", "fi-fi", "fr-be", "fr-ca", "fr-ch", "fr-fr", "it-ch", "ja-jp", "nl-be", "nl-nl", "no-no", "pl-pl", "sv-se"];
14
+ export type SupportedLocale = (typeof SUPPORTED_LOCALES)[number];
@@ -0,0 +1,45 @@
1
+ import { useMemo as r } from "react";
2
+ import { resolveLabels as s } from "./labelResolver.js";
3
+ import { interpolate as i, isRTLLocale as p, loadBundle as d } from "./labelResolver.js";
4
+ function f(e, n) {
5
+ return r(
6
+ () => s(e, n),
7
+ [e, n]
8
+ );
9
+ }
10
+ const l = [
11
+ "ar-sa",
12
+ "ca-es",
13
+ "cs-cz",
14
+ "da-dk",
15
+ "de-at",
16
+ "de-ch",
17
+ "de-de",
18
+ "en-au",
19
+ "en-ca",
20
+ "en-gb",
21
+ "en-nz",
22
+ "en-us",
23
+ "es-es",
24
+ "es-mx",
25
+ "fi-fi",
26
+ "fr-be",
27
+ "fr-ca",
28
+ "fr-ch",
29
+ "fr-fr",
30
+ "it-ch",
31
+ "ja-jp",
32
+ "nl-be",
33
+ "nl-nl",
34
+ "no-no",
35
+ "pl-pl",
36
+ "sv-se"
37
+ ];
38
+ export {
39
+ l as SUPPORTED_LOCALES,
40
+ i as interpolate,
41
+ p as isRTLLocale,
42
+ d as loadBundle,
43
+ s as resolveLabels,
44
+ f as useLabels
45
+ };
@@ -0,0 +1,24 @@
1
+ import { LocaleBundle, ResolvedLabels, InterpolationVars } from './types';
2
+ export declare function isRTLLocale(locale: string): boolean;
3
+ /**
4
+ * Replaces `{{key}}` placeholders in a template string with values from vars.
5
+ *
6
+ * @example
7
+ * interpolate("{{field}} is required", { field: "First Name" })
8
+ * // → "First Name is required"
9
+ */
10
+ export declare function interpolate(template: string, vars: InterpolationVars): string;
11
+ /**
12
+ * Loads a locale bundle. Falls back to en-us if the requested locale is
13
+ * not available, then falls back to in-memory DEFAULT_LABELS.
14
+ */
15
+ export declare function loadBundle(locale: string): LocaleBundle;
16
+ /**
17
+ * Resolves labels for a given locale and country code.
18
+ *
19
+ * Resolution order for country-adaptive fields (stateCode, city, postal):
20
+ * 1. bundle.country[CC].field ← country-specific override
21
+ * 2. bundle.form.field ← generic form default
22
+ * 3. DEFAULT_LABELS.form.field ← English ultimate fallback
23
+ */
24
+ export declare function resolveLabels(locale: string, countryCode: string): ResolvedLabels;
@@ -0,0 +1,98 @@
1
+ import { DEFAULT_LABELS as l } from "./defaultLabels.js";
2
+ import c from "./locales/ar-sa.json.js";
3
+ import d from "./locales/ca-es.json.js";
4
+ import h from "./locales/cs-cz.json.js";
5
+ import C from "./locales/da-dk.json.js";
6
+ import L from "./locales/de-at.json.js";
7
+ import b from "./locales/de-ch.json.js";
8
+ import E from "./locales/de-de.json.js";
9
+ import P from "./locales/en-au.json.js";
10
+ import S from "./locales/en-ca.json.js";
11
+ import g from "./locales/en-gb.json.js";
12
+ import A from "./locales/en-nz.json.js";
13
+ import k from "./locales/en-us.json.js";
14
+ import w from "./locales/es-es.json.js";
15
+ import B from "./locales/es-mx.json.js";
16
+ import j from "./locales/fi-fi.json.js";
17
+ import z from "./locales/fr-be.json.js";
18
+ import D from "./locales/fr-ca.json.js";
19
+ import N from "./locales/fr-ch.json.js";
20
+ import T from "./locales/fr-fr.json.js";
21
+ import U from "./locales/it-ch.json.js";
22
+ import _ from "./locales/ja-jp.json.js";
23
+ import u from "./locales/nl-be.json.js";
24
+ import x from "./locales/nl-nl.json.js";
25
+ import F from "./locales/no-no.json.js";
26
+ import M from "./locales/pl-pl.json.js";
27
+ import R from "./locales/sv-se.json.js";
28
+ const v = /* @__PURE__ */ new Set(["ar-sa", "ar", "he", "fa", "ur"]);
29
+ function G(a) {
30
+ return v.has(a.toLowerCase());
31
+ }
32
+ function Co(a, s) {
33
+ return a.replace(/\{\{(\w+)\}\}/g, (m, r) => {
34
+ const e = s[r];
35
+ return e !== void 0 ? String(e) : r;
36
+ });
37
+ }
38
+ const i = {
39
+ "ar-sa": c,
40
+ "ca-es": d,
41
+ "cs-cz": h,
42
+ "da-dk": C,
43
+ "de-at": L,
44
+ "de-ch": b,
45
+ "de-de": E,
46
+ "en-au": P,
47
+ "en-ca": S,
48
+ "en-gb": g,
49
+ "en-nz": A,
50
+ "en-us": k,
51
+ "es-es": w,
52
+ "es-mx": B,
53
+ "fi-fi": j,
54
+ "fr-be": z,
55
+ "fr-ca": D,
56
+ "fr-ch": N,
57
+ "fr-fr": T,
58
+ "it-ch": U,
59
+ "ja-jp": _,
60
+ "nl-be": u,
61
+ "nl-nl": x,
62
+ "no-no": F,
63
+ "pl-pl": M,
64
+ "sv-se": R
65
+ }, f = /* @__PURE__ */ new Map();
66
+ function J(a) {
67
+ const s = a.toLowerCase();
68
+ if (f.has(s))
69
+ return f.get(s);
70
+ if (i[s])
71
+ return f.set(s, i[s]), i[s];
72
+ const m = s.split("-")[0], r = Object.keys(i).find((n) => n.startsWith(`${m}-`));
73
+ if (r)
74
+ return f.set(s, i[r]), i[r];
75
+ const e = i["en-us"] ?? l;
76
+ return f.set(s, e), e;
77
+ }
78
+ function Lo(a, s) {
79
+ var p;
80
+ const m = J(a), r = l, e = {
81
+ ...r.form,
82
+ ...m.form
83
+ }, n = s.toUpperCase(), o = (p = m.country) == null ? void 0 : p[n], t = r.country[n];
84
+ return (o == null ? void 0 : o.stateCode) !== void 0 ? e.stateCode = o.stateCode : (t == null ? void 0 : t.stateCode) !== void 0 && (e.stateCode = t.stateCode), (o == null ? void 0 : o.stateCodePlaceholder) !== void 0 ? e.stateCodePlaceholder = o.stateCodePlaceholder : (t == null ? void 0 : t.stateCodePlaceholder) !== void 0 && (e.stateCodePlaceholder = t.stateCodePlaceholder), (o == null ? void 0 : o.city) !== void 0 ? e.city = o.city : (t == null ? void 0 : t.city) !== void 0 && (e.city = t.city), (o == null ? void 0 : o.postal) !== void 0 ? e.postal = o.postal : (t == null ? void 0 : t.postal) !== void 0 && (e.postal = t.postal), {
85
+ form: e,
86
+ validation: {
87
+ ...r.validation,
88
+ ...m.validation
89
+ },
90
+ isRTL: G(a)
91
+ };
92
+ }
93
+ export {
94
+ Co as interpolate,
95
+ G as isRTLLocale,
96
+ J as loadBundle,
97
+ Lo as resolveLabels
98
+ };