@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.
- package/dist/components/AddressCard/AddressCard.d.ts +5 -0
- package/dist/components/AddressCard/AddressCard.js +45 -46
- package/dist/components/AddressForm/AddressForm.d.ts +14 -2
- package/dist/components/AddressForm/AddressForm.js +204 -227
- package/dist/components/AddressList/AddressList.d.ts +7 -2
- package/dist/components/AddressList/AddressList.js +41 -37
- package/dist/components/PhoneField/PhoneField.d.ts +57 -0
- package/dist/components/PhoneField/PhoneField.js +119 -0
- package/dist/i18n/defaultLabels.d.ts +2 -0
- package/dist/i18n/defaultLabels.js +66 -0
- package/dist/i18n/index.d.ts +14 -0
- package/dist/i18n/index.js +45 -0
- package/dist/i18n/labelResolver.d.ts +24 -0
- package/dist/i18n/labelResolver.js +98 -0
- package/dist/i18n/locales/ar-sa.json.d.ts +159 -0
- package/dist/i18n/locales/ar-sa.json.js +163 -0
- package/dist/i18n/locales/ca-es.json.d.ts +159 -0
- package/dist/i18n/locales/ca-es.json.js +163 -0
- package/dist/i18n/locales/cs-cz.json.d.ts +159 -0
- package/dist/i18n/locales/cs-cz.json.js +163 -0
- package/dist/i18n/locales/da-dk.json.d.ts +159 -0
- package/dist/i18n/locales/da-dk.json.js +163 -0
- package/dist/i18n/locales/de-at.json.d.ts +159 -0
- package/dist/i18n/locales/de-at.json.js +163 -0
- package/dist/i18n/locales/de-ch.json.d.ts +159 -0
- package/dist/i18n/locales/de-ch.json.js +163 -0
- package/dist/i18n/locales/de-de.json.d.ts +159 -0
- package/dist/i18n/locales/de-de.json.js +163 -0
- package/dist/i18n/locales/en-au.json.d.ts +159 -0
- package/dist/i18n/locales/en-au.json.js +163 -0
- package/dist/i18n/locales/en-ca.json.d.ts +159 -0
- package/dist/i18n/locales/en-ca.json.js +163 -0
- package/dist/i18n/locales/en-gb.json.d.ts +159 -0
- package/dist/i18n/locales/en-gb.json.js +163 -0
- package/dist/i18n/locales/en-nz.json.d.ts +159 -0
- package/dist/i18n/locales/en-nz.json.js +163 -0
- package/dist/i18n/locales/en-us.json.d.ts +159 -0
- package/dist/i18n/locales/en-us.json.js +163 -0
- package/dist/i18n/locales/es-es.json.d.ts +159 -0
- package/dist/i18n/locales/es-es.json.js +163 -0
- package/dist/i18n/locales/es-mx.json.d.ts +159 -0
- package/dist/i18n/locales/es-mx.json.js +163 -0
- package/dist/i18n/locales/fi-fi.json.d.ts +159 -0
- package/dist/i18n/locales/fi-fi.json.js +163 -0
- package/dist/i18n/locales/fr-be.json.d.ts +159 -0
- package/dist/i18n/locales/fr-be.json.js +163 -0
- package/dist/i18n/locales/fr-ca.json.d.ts +159 -0
- package/dist/i18n/locales/fr-ca.json.js +163 -0
- package/dist/i18n/locales/fr-ch.json.d.ts +159 -0
- package/dist/i18n/locales/fr-ch.json.js +163 -0
- package/dist/i18n/locales/fr-fr.json.d.ts +159 -0
- package/dist/i18n/locales/fr-fr.json.js +163 -0
- package/dist/i18n/locales/it-ch.json.d.ts +159 -0
- package/dist/i18n/locales/it-ch.json.js +163 -0
- package/dist/i18n/locales/ja-jp.json.d.ts +159 -0
- package/dist/i18n/locales/ja-jp.json.js +163 -0
- package/dist/i18n/locales/nl-be.json.d.ts +159 -0
- package/dist/i18n/locales/nl-be.json.js +163 -0
- package/dist/i18n/locales/nl-nl.json.d.ts +159 -0
- package/dist/i18n/locales/nl-nl.json.js +163 -0
- package/dist/i18n/locales/no-no.json.d.ts +159 -0
- package/dist/i18n/locales/no-no.json.js +163 -0
- package/dist/i18n/locales/pl-pl.json.d.ts +159 -0
- package/dist/i18n/locales/pl-pl.json.js +163 -0
- package/dist/i18n/locales/sv-se.json.d.ts +159 -0
- package/dist/i18n/locales/sv-se.json.js +163 -0
- package/dist/i18n/types.d.ts +67 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +48 -38
- 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
|
|
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
|
|
5
|
-
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
47
|
+
`, z = r.li``, C = r.div`
|
|
47
48
|
margin-block-start: ${e.space3};
|
|
48
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
90
|
+
`, M = ({
|
|
90
91
|
addresses: a,
|
|
91
|
-
selectedAddressId:
|
|
92
|
-
addressLabel:
|
|
93
|
-
maxAddresses:
|
|
94
|
-
onSelect:
|
|
95
|
-
onEdit:
|
|
96
|
-
onDelete:
|
|
97
|
-
onAdd:
|
|
98
|
-
onCollapse:
|
|
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:
|
|
101
|
+
cardErrors: g = {},
|
|
102
|
+
locale: d = "en-us"
|
|
101
103
|
}) => {
|
|
102
|
-
const
|
|
103
|
-
return /* @__PURE__ */ n(
|
|
104
|
-
/* @__PURE__ */ n(
|
|
105
|
-
/* @__PURE__ */ o(
|
|
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
|
-
|
|
109
|
+
S,
|
|
108
110
|
{
|
|
109
111
|
type: "button",
|
|
110
|
-
onClick:
|
|
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(
|
|
118
|
-
|
|
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 ===
|
|
122
|
-
onSelect:
|
|
123
|
-
onEdit:
|
|
124
|
-
onDelete:
|
|
123
|
+
isSelected: t.addressId === c,
|
|
124
|
+
onSelect: f,
|
|
125
|
+
onEdit: m,
|
|
126
|
+
onDelete: b,
|
|
125
127
|
disabled: i,
|
|
126
|
-
errorMessage:
|
|
128
|
+
errorMessage: g[t.addressId],
|
|
129
|
+
locale: d
|
|
127
130
|
}
|
|
128
131
|
) }, t.addressId)) }),
|
|
129
|
-
/* @__PURE__ */ o(
|
|
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
|
-
|
|
136
|
+
w,
|
|
134
137
|
{
|
|
135
138
|
type: "button",
|
|
136
139
|
disabled: i,
|
|
137
|
-
onClick:
|
|
140
|
+
onClick: x,
|
|
138
141
|
"data-testid": "add-new-address",
|
|
139
142
|
children: [
|
|
140
143
|
/* @__PURE__ */ o("span", { "aria-hidden": "true", children: "+" }),
|
|
141
|
-
"
|
|
144
|
+
" ",
|
|
145
|
+
s.addNewAddress
|
|
142
146
|
]
|
|
143
147
|
}
|
|
144
148
|
) })
|
|
145
149
|
] });
|
|
146
150
|
};
|
|
147
151
|
export {
|
|
148
|
-
|
|
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,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
|
+
};
|