@simplybusiness/mobius 6.3.3 → 6.4.1
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/CHANGELOG.md +12 -0
- package/dist/cjs/index.js +26 -3
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/index.js +26 -3
- package/dist/types/src/components/AddressLookup/LoqateAddressLookupService.d.ts +10 -1
- package/package.json +1 -1
- package/src/components/AddressLookup/LoqateAddressLookupService.test.tsx +180 -43
- package/src/components/AddressLookup/LoqateAddressLookupService.tsx +33 -2
- package/src/components/Alert/Alert.css +2 -1
- package/src/components/Alert/Alert.stories.tsx +3 -6
package/dist/esm/index.js
CHANGED
|
@@ -1778,14 +1778,21 @@ var LoqateAddressLookupService = class {
|
|
|
1778
1778
|
* 2 or 3 character ISO country codes
|
|
1779
1779
|
*/
|
|
1780
1780
|
#countries;
|
|
1781
|
+
/**
|
|
1782
|
+
* Optional filters for the Loqate API
|
|
1783
|
+
* E.g., { AdministrativeArea: "CA", PostalCode: "90210" }
|
|
1784
|
+
*/
|
|
1785
|
+
#filters;
|
|
1781
1786
|
constructor({
|
|
1782
1787
|
baseUrl,
|
|
1783
1788
|
apiKey,
|
|
1784
|
-
countries
|
|
1789
|
+
countries,
|
|
1790
|
+
filters
|
|
1785
1791
|
}) {
|
|
1786
1792
|
this.#apiKey = apiKey;
|
|
1787
1793
|
this.#baseUrl = baseUrl || LOQATE_BASE_URL;
|
|
1788
1794
|
this.#countries = countries || DEFAULT_COUNTRIES;
|
|
1795
|
+
this.#filters = filters;
|
|
1789
1796
|
}
|
|
1790
1797
|
fetchFromApi(url) {
|
|
1791
1798
|
return fetch(`${this.#baseUrl}${url}`).then((response) => response.json()).then((json) => {
|
|
@@ -1795,12 +1802,28 @@ var LoqateAddressLookupService = class {
|
|
|
1795
1802
|
return json;
|
|
1796
1803
|
});
|
|
1797
1804
|
}
|
|
1805
|
+
/**
|
|
1806
|
+
* Builds the Filters query parameter for Loqate API requests.
|
|
1807
|
+
* - Filter keys (e.g., "AdministrativeArea", "PostalCode") are predefined by Loqate API (no need to encode)
|
|
1808
|
+
* - Filter values (e.g., "New York", "90210") contain user input that may have special characters (need encoding)
|
|
1809
|
+
*
|
|
1810
|
+
* @returns Empty string if no filters, otherwise "&Filters=key1:value1&key2:value2" (Loqate's expected format for Filters)
|
|
1811
|
+
*/
|
|
1812
|
+
buildFiltersQuery() {
|
|
1813
|
+
if (!this.#filters || Object.keys(this.#filters).length === 0) {
|
|
1814
|
+
return "";
|
|
1815
|
+
}
|
|
1816
|
+
const encodedFilters = Object.entries(this.#filters).map(([key, value]) => `${key}:${encodeURIComponent(value)}`).join("&");
|
|
1817
|
+
return `&Filters=${encodedFilters}`;
|
|
1818
|
+
}
|
|
1798
1819
|
search(searchTerm) {
|
|
1799
|
-
|
|
1820
|
+
let url = `${LOQATE_FIND_URL}?Key=${this.#apiKey}&Text=${searchTerm}&Countries=${this.#countries?.join(",")}`;
|
|
1821
|
+
url += this.buildFiltersQuery();
|
|
1800
1822
|
return this.fetchFromApi(url);
|
|
1801
1823
|
}
|
|
1802
1824
|
findById(id) {
|
|
1803
|
-
|
|
1825
|
+
let url = `${LOQATE_FIND_URL}?Key=${this.#apiKey}&Container=${id}&Countries=${this.#countries?.join(",")}`;
|
|
1826
|
+
url += this.buildFiltersQuery();
|
|
1804
1827
|
return this.fetchFromApi(url);
|
|
1805
1828
|
}
|
|
1806
1829
|
async get(id) {
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import type { LoqateAddressDetailsItem, LoqateSearchResponse } from "./types";
|
|
2
2
|
export declare class LoqateAddressLookupService {
|
|
3
3
|
#private;
|
|
4
|
-
constructor({ baseUrl, apiKey, countries, }: {
|
|
4
|
+
constructor({ baseUrl, apiKey, countries, filters, }: {
|
|
5
5
|
baseUrl?: string;
|
|
6
6
|
apiKey?: string;
|
|
7
7
|
countries?: string[];
|
|
8
|
+
filters?: Record<string, string>;
|
|
8
9
|
});
|
|
9
10
|
private fetchFromApi;
|
|
11
|
+
/**
|
|
12
|
+
* Builds the Filters query parameter for Loqate API requests.
|
|
13
|
+
* - Filter keys (e.g., "AdministrativeArea", "PostalCode") are predefined by Loqate API (no need to encode)
|
|
14
|
+
* - Filter values (e.g., "New York", "90210") contain user input that may have special characters (need encoding)
|
|
15
|
+
*
|
|
16
|
+
* @returns Empty string if no filters, otherwise "&Filters=key1:value1&key2:value2" (Loqate's expected format for Filters)
|
|
17
|
+
*/
|
|
18
|
+
private buildFiltersQuery;
|
|
10
19
|
search(searchTerm: string): Promise<LoqateSearchResponse>;
|
|
11
20
|
findById(id: string): Promise<LoqateSearchResponse>;
|
|
12
21
|
get(id: string): Promise<LoqateAddressDetailsItem>;
|
package/package.json
CHANGED
|
@@ -6,6 +6,53 @@ describe("LoqateAddressLookupService", () => {
|
|
|
6
6
|
const mockBaseUrl = "https://test-api.com";
|
|
7
7
|
const mockCountries = ["GB", "USA"];
|
|
8
8
|
|
|
9
|
+
// Helper functions for mock responses
|
|
10
|
+
const createEmptyMockResponse = () => ({ items: [] });
|
|
11
|
+
|
|
12
|
+
const createAddressDetailsMockResponse = (overrides = {}) => ({
|
|
13
|
+
Items: [
|
|
14
|
+
{
|
|
15
|
+
Id: "address123",
|
|
16
|
+
Type: "Address",
|
|
17
|
+
City: "Test City",
|
|
18
|
+
Line1: "Test Line 1",
|
|
19
|
+
Line2: "Test Line 2",
|
|
20
|
+
PostalCode: "12345",
|
|
21
|
+
Label: "Test Label",
|
|
22
|
+
...overrides,
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const createErrorMockResponse = (overrides = {}) => ({
|
|
28
|
+
Items: [
|
|
29
|
+
{
|
|
30
|
+
Error: "Test error code",
|
|
31
|
+
Description: "Test error",
|
|
32
|
+
Cause: "Test cause",
|
|
33
|
+
Resolution: "Test resolution",
|
|
34
|
+
...overrides,
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Helper function for creating service with filters
|
|
40
|
+
const createServiceWithFilters = (filters: Record<string, string>) => {
|
|
41
|
+
return new LoqateAddressLookupService({
|
|
42
|
+
baseUrl: mockBaseUrl,
|
|
43
|
+
apiKey: mockApiKey,
|
|
44
|
+
countries: mockCountries,
|
|
45
|
+
filters,
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Helper function for mocking fetch responses
|
|
50
|
+
const mockFetchResponse = (response: unknown) => {
|
|
51
|
+
(global.fetch as jest.Mock).mockResolvedValueOnce({
|
|
52
|
+
json: () => Promise.resolve(response),
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
|
|
9
56
|
beforeEach(() => {
|
|
10
57
|
global.fetch = jest.fn();
|
|
11
58
|
service = new LoqateAddressLookupService({
|
|
@@ -23,10 +70,8 @@ describe("LoqateAddressLookupService", () => {
|
|
|
23
70
|
const serviceWithDefaultUrl = new LoqateAddressLookupService({
|
|
24
71
|
apiKey: mockApiKey,
|
|
25
72
|
});
|
|
26
|
-
const mockResponse =
|
|
27
|
-
(
|
|
28
|
-
json: () => Promise.resolve(mockResponse),
|
|
29
|
-
});
|
|
73
|
+
const mockResponse = createEmptyMockResponse();
|
|
74
|
+
mockFetchResponse(mockResponse);
|
|
30
75
|
|
|
31
76
|
await serviceWithDefaultUrl.search("test");
|
|
32
77
|
|
|
@@ -37,25 +82,21 @@ describe("LoqateAddressLookupService", () => {
|
|
|
37
82
|
|
|
38
83
|
describe("find", () => {
|
|
39
84
|
it("calls the correct URL with search term", async () => {
|
|
40
|
-
const mockResponse =
|
|
41
|
-
(
|
|
42
|
-
json: () => Promise.resolve(mockResponse),
|
|
43
|
-
});
|
|
85
|
+
const mockResponse = createEmptyMockResponse();
|
|
86
|
+
mockFetchResponse(mockResponse);
|
|
44
87
|
|
|
45
|
-
await service.search("
|
|
88
|
+
await service.search("123 Main Street");
|
|
46
89
|
|
|
47
90
|
expect(global.fetch).toHaveBeenCalledWith(
|
|
48
|
-
`${mockBaseUrl}/Find/v1.00/json3.ws?Key=${mockApiKey}&Text=
|
|
91
|
+
`${mockBaseUrl}/Find/v1.00/json3.ws?Key=${mockApiKey}&Text=123 Main Street&Countries=GB,USA`,
|
|
49
92
|
);
|
|
50
93
|
});
|
|
51
94
|
});
|
|
52
95
|
|
|
53
96
|
describe("findById", () => {
|
|
54
97
|
it("calls the correct URL with container ID", async () => {
|
|
55
|
-
const mockResponse =
|
|
56
|
-
(
|
|
57
|
-
json: () => Promise.resolve(mockResponse),
|
|
58
|
-
});
|
|
98
|
+
const mockResponse = createEmptyMockResponse();
|
|
99
|
+
mockFetchResponse(mockResponse);
|
|
59
100
|
|
|
60
101
|
await service.findById("container123");
|
|
61
102
|
|
|
@@ -67,22 +108,8 @@ describe("LoqateAddressLookupService", () => {
|
|
|
67
108
|
|
|
68
109
|
describe("get", () => {
|
|
69
110
|
it("calls the correct URL with ID", async () => {
|
|
70
|
-
const mockResponse =
|
|
71
|
-
|
|
72
|
-
{
|
|
73
|
-
Id: "address123",
|
|
74
|
-
Type: "Address",
|
|
75
|
-
City: "Test City",
|
|
76
|
-
Line1: "Test Line 1",
|
|
77
|
-
Line2: "Test Line 2",
|
|
78
|
-
PostalCode: "12345",
|
|
79
|
-
Label: "Test Label",
|
|
80
|
-
},
|
|
81
|
-
],
|
|
82
|
-
};
|
|
83
|
-
(global.fetch as jest.Mock).mockResolvedValueOnce({
|
|
84
|
-
json: () => Promise.resolve(mockResponse),
|
|
85
|
-
});
|
|
111
|
+
const mockResponse = createAddressDetailsMockResponse();
|
|
112
|
+
mockFetchResponse(mockResponse);
|
|
86
113
|
|
|
87
114
|
await service.get("address123");
|
|
88
115
|
|
|
@@ -92,21 +119,131 @@ describe("LoqateAddressLookupService", () => {
|
|
|
92
119
|
});
|
|
93
120
|
});
|
|
94
121
|
|
|
122
|
+
describe("filters functionality", () => {
|
|
123
|
+
it("includes no filters when filters are not provided", async () => {
|
|
124
|
+
const mockResponse = createEmptyMockResponse();
|
|
125
|
+
mockFetchResponse(mockResponse);
|
|
126
|
+
|
|
127
|
+
await service.search("456 Oak Avenue");
|
|
128
|
+
|
|
129
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
130
|
+
`${mockBaseUrl}/Find/v1.00/json3.ws?Key=${mockApiKey}&Text=456 Oak Avenue&Countries=GB,USA`,
|
|
131
|
+
);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("includes single filter in search URL", async () => {
|
|
135
|
+
const serviceWithFilters = createServiceWithFilters({
|
|
136
|
+
AdministrativeArea: "NY",
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const mockResponse = createEmptyMockResponse();
|
|
140
|
+
mockFetchResponse(mockResponse);
|
|
141
|
+
|
|
142
|
+
await serviceWithFilters.search("789 Broadway");
|
|
143
|
+
|
|
144
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
145
|
+
`${mockBaseUrl}/Find/v1.00/json3.ws?Key=${mockApiKey}&Text=789 Broadway&Countries=GB,USA&Filters=AdministrativeArea:NY`,
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("includes multiple filters in search URL", async () => {
|
|
150
|
+
const serviceWithFilters = createServiceWithFilters({
|
|
151
|
+
AdministrativeArea: "CA",
|
|
152
|
+
PostalCode: "90210",
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
const mockResponse = createEmptyMockResponse();
|
|
156
|
+
mockFetchResponse(mockResponse);
|
|
157
|
+
|
|
158
|
+
await serviceWithFilters.search("321 Sunset Boulevard");
|
|
159
|
+
|
|
160
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
161
|
+
`${mockBaseUrl}/Find/v1.00/json3.ws?Key=${mockApiKey}&Text=321 Sunset Boulevard&Countries=GB,USA&Filters=AdministrativeArea:CA&PostalCode:90210`,
|
|
162
|
+
);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it("encodes filter values with special characters", async () => {
|
|
166
|
+
const serviceWithFilters = createServiceWithFilters({
|
|
167
|
+
AdministrativeArea: "New York",
|
|
168
|
+
CustomFilter: "100% Match & More",
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const mockResponse = createEmptyMockResponse();
|
|
172
|
+
mockFetchResponse(mockResponse);
|
|
173
|
+
|
|
174
|
+
await serviceWithFilters.search("654 Fifth Avenue");
|
|
175
|
+
|
|
176
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
177
|
+
`${mockBaseUrl}/Find/v1.00/json3.ws?Key=${mockApiKey}&Text=654 Fifth Avenue&Countries=GB,USA&Filters=AdministrativeArea:New%20York&CustomFilter:100%25%20Match%20%26%20More`,
|
|
178
|
+
);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("does not encode filter keys", async () => {
|
|
182
|
+
const serviceWithFilters = createServiceWithFilters({
|
|
183
|
+
AdministrativeArea: "NY",
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const mockResponse = createEmptyMockResponse();
|
|
187
|
+
mockFetchResponse(mockResponse);
|
|
188
|
+
|
|
189
|
+
await serviceWithFilters.search("987 Park Avenue");
|
|
190
|
+
|
|
191
|
+
const calledUrl = (global.fetch as jest.Mock).mock.calls[0][0];
|
|
192
|
+
expect(calledUrl).toContain("AdministrativeArea:NY");
|
|
193
|
+
expect(calledUrl).not.toContain("AdministrativeArea%3ANY");
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it("includes filters in findById URL", async () => {
|
|
197
|
+
const serviceWithFilters = createServiceWithFilters({
|
|
198
|
+
AdministrativeArea: "TX",
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
const mockResponse = createEmptyMockResponse();
|
|
202
|
+
mockFetchResponse(mockResponse);
|
|
203
|
+
|
|
204
|
+
await serviceWithFilters.findById("container123");
|
|
205
|
+
|
|
206
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
207
|
+
`${mockBaseUrl}/Find/v1.00/json3.ws?Key=${mockApiKey}&Container=container123&Countries=GB,USA&Filters=AdministrativeArea:TX`,
|
|
208
|
+
);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it("handles empty filters object", async () => {
|
|
212
|
+
const serviceWithEmptyFilters = createServiceWithFilters({});
|
|
213
|
+
|
|
214
|
+
const mockResponse = createEmptyMockResponse();
|
|
215
|
+
mockFetchResponse(mockResponse);
|
|
216
|
+
|
|
217
|
+
await serviceWithEmptyFilters.search("147 Wall Street");
|
|
218
|
+
|
|
219
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
220
|
+
`${mockBaseUrl}/Find/v1.00/json3.ws?Key=${mockApiKey}&Text=147 Wall Street&Countries=GB,USA`,
|
|
221
|
+
);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it("does not include filters in get URL (retrieve endpoint)", async () => {
|
|
225
|
+
const serviceWithFilters = createServiceWithFilters({
|
|
226
|
+
AdministrativeArea: "FL",
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
const mockResponse = createAddressDetailsMockResponse();
|
|
230
|
+
mockFetchResponse(mockResponse);
|
|
231
|
+
|
|
232
|
+
await serviceWithFilters.get("address123");
|
|
233
|
+
|
|
234
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
235
|
+
`${mockBaseUrl}/Retrieve/v1.2/json3.ws?Key=${mockApiKey}&Id=address123`,
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
const calledUrl = (global.fetch as jest.Mock).mock.calls[0][0];
|
|
239
|
+
expect(calledUrl).not.toContain("Filters");
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
|
|
95
243
|
describe("error handling", () => {
|
|
96
244
|
it("propagates API errors", async () => {
|
|
97
|
-
const errorResponse =
|
|
98
|
-
|
|
99
|
-
{
|
|
100
|
-
Error: "Test error code",
|
|
101
|
-
Description: "Test error",
|
|
102
|
-
Cause: "Test cause",
|
|
103
|
-
Resolution: "Test resolution",
|
|
104
|
-
},
|
|
105
|
-
],
|
|
106
|
-
};
|
|
107
|
-
(global.fetch as jest.Mock).mockResolvedValueOnce({
|
|
108
|
-
json: () => Promise.resolve(errorResponse),
|
|
109
|
-
});
|
|
245
|
+
const errorResponse = createErrorMockResponse();
|
|
246
|
+
mockFetchResponse(errorResponse);
|
|
110
247
|
|
|
111
248
|
await expect(service.search("test")).rejects.toThrow();
|
|
112
249
|
});
|
|
@@ -27,18 +27,27 @@ export class LoqateAddressLookupService {
|
|
|
27
27
|
*/
|
|
28
28
|
#countries?: string[];
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Optional filters for the Loqate API
|
|
32
|
+
* E.g., { AdministrativeArea: "CA", PostalCode: "90210" }
|
|
33
|
+
*/
|
|
34
|
+
#filters?: Record<string, string>;
|
|
35
|
+
|
|
30
36
|
constructor({
|
|
31
37
|
baseUrl,
|
|
32
38
|
apiKey,
|
|
33
39
|
countries,
|
|
40
|
+
filters,
|
|
34
41
|
}: {
|
|
35
42
|
baseUrl?: string;
|
|
36
43
|
apiKey?: string;
|
|
37
44
|
countries?: string[];
|
|
45
|
+
filters?: Record<string, string>;
|
|
38
46
|
}) {
|
|
39
47
|
this.#apiKey = apiKey;
|
|
40
48
|
this.#baseUrl = baseUrl || LOQATE_BASE_URL;
|
|
41
49
|
this.#countries = countries || DEFAULT_COUNTRIES;
|
|
50
|
+
this.#filters = filters;
|
|
42
51
|
}
|
|
43
52
|
|
|
44
53
|
private fetchFromApi<TResponse = unknown>(url: string): Promise<TResponse> {
|
|
@@ -52,13 +61,35 @@ export class LoqateAddressLookupService {
|
|
|
52
61
|
});
|
|
53
62
|
}
|
|
54
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Builds the Filters query parameter for Loqate API requests.
|
|
66
|
+
* - Filter keys (e.g., "AdministrativeArea", "PostalCode") are predefined by Loqate API (no need to encode)
|
|
67
|
+
* - Filter values (e.g., "New York", "90210") contain user input that may have special characters (need encoding)
|
|
68
|
+
*
|
|
69
|
+
* @returns Empty string if no filters, otherwise "&Filters=key1:value1&key2:value2" (Loqate's expected format for Filters)
|
|
70
|
+
*/
|
|
71
|
+
private buildFiltersQuery(): string {
|
|
72
|
+
if (!this.#filters || Object.keys(this.#filters).length === 0) {
|
|
73
|
+
return "";
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Transform Record<string, string> to Loqate's "key:value&key:value" format
|
|
77
|
+
const encodedFilters = Object.entries(this.#filters)
|
|
78
|
+
.map(([key, value]) => `${key}:${encodeURIComponent(value)}`)
|
|
79
|
+
.join("&");
|
|
80
|
+
|
|
81
|
+
return `&Filters=${encodedFilters}`;
|
|
82
|
+
}
|
|
83
|
+
|
|
55
84
|
search(searchTerm: string): Promise<LoqateSearchResponse> {
|
|
56
|
-
|
|
85
|
+
let url = `${LOQATE_FIND_URL}?Key=${this.#apiKey}&Text=${searchTerm}&Countries=${this.#countries?.join(",")}`;
|
|
86
|
+
url += this.buildFiltersQuery();
|
|
57
87
|
return this.fetchFromApi<LoqateSearchResponse>(url);
|
|
58
88
|
}
|
|
59
89
|
|
|
60
90
|
findById(id: string): Promise<LoqateSearchResponse> {
|
|
61
|
-
|
|
91
|
+
let url = `${LOQATE_FIND_URL}?Key=${this.#apiKey}&Container=${id}&Countries=${this.#countries?.join(",")}`;
|
|
92
|
+
url += this.buildFiltersQuery();
|
|
62
93
|
return this.fetchFromApi<LoqateSearchResponse>(url);
|
|
63
94
|
}
|
|
64
95
|
|
|
@@ -11,6 +11,7 @@ const meta: Meta<typeof Alert> = {
|
|
|
11
11
|
variant: {
|
|
12
12
|
control: { type: "radio" },
|
|
13
13
|
options: ["info", "success", "warning", "error"],
|
|
14
|
+
header: { control: "text" },
|
|
14
15
|
},
|
|
15
16
|
},
|
|
16
17
|
};
|
|
@@ -33,17 +34,13 @@ export const Default: StoryType = {
|
|
|
33
34
|
|
|
34
35
|
export const WithHeader: StoryType = {
|
|
35
36
|
render: (args: AlertProps) => (
|
|
36
|
-
<Alert {...args}>
|
|
37
|
-
Today is{" "}
|
|
38
|
-
{new Intl.DateTimeFormat("en-GB", {
|
|
39
|
-
dateStyle: "long",
|
|
40
|
-
}).format(new Date())}
|
|
41
|
-
</Alert>
|
|
37
|
+
<Alert {...args}>{args.children || "This is an alert with a header"}</Alert>
|
|
42
38
|
),
|
|
43
39
|
args: {
|
|
44
40
|
variant: "info",
|
|
45
41
|
show: true,
|
|
46
42
|
header: "Information",
|
|
43
|
+
children: "This is an alert with a header",
|
|
47
44
|
},
|
|
48
45
|
};
|
|
49
46
|
|