kelt-ui-kit-react 2.0.1 → 2.0.2
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/README.md +26 -0
- package/dist/addressSearch/AddressSearch.d.ts +20 -0
- package/dist/addressSearch/AddressSearch.view.d.ts +1 -0
- package/dist/form/Form.d.ts +3 -2
- package/dist/form/form.enum.d.ts +1 -0
- package/dist/form/form.interface.d.ts +15 -0
- package/dist/geocoding/GeocodingService.d.ts +13 -0
- package/dist/geocoding/geocoding.interface.d.ts +20 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +2385 -2151
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/App.menu.tsx +8 -0
- package/src/addressSearch/AddressSearch.tsx +246 -0
- package/src/addressSearch/AddressSearch.view.tsx +52 -0
- package/src/addressSearch/addressSearch.css +133 -0
- package/src/form/Form.tsx +166 -101
- package/src/form/form.css +14 -1
- package/src/form/form.enum.ts +1 -0
- package/src/form/form.interface.tsx +21 -0
- package/src/geocoding/GeocodingService.ts +89 -0
- package/src/geocoding/geocoding.interface.ts +25 -0
- package/src/grid/row/row.css +2 -2
- package/src/index.ts +12 -1
package/src/form/Form.tsx
CHANGED
|
@@ -12,6 +12,7 @@ import "./form.css";
|
|
|
12
12
|
import {
|
|
13
13
|
FormInterface,
|
|
14
14
|
FormMode,
|
|
15
|
+
FormSection,
|
|
15
16
|
FormValuesInterface,
|
|
16
17
|
} from "./form.interface";
|
|
17
18
|
import { Input } from "./input/Input";
|
|
@@ -20,6 +21,7 @@ import { TextArea } from "./textArea/TextArea";
|
|
|
20
21
|
import { Col } from "../grid/col/Col";
|
|
21
22
|
import { Row } from "../grid/row/Row";
|
|
22
23
|
import { TypeInputEnum } from "./form.enum";
|
|
24
|
+
import { AddressSearch } from "../addressSearch/AddressSearch";
|
|
23
25
|
|
|
24
26
|
const euroFormatter = new Intl.NumberFormat("fr-FR", {
|
|
25
27
|
style: "currency",
|
|
@@ -48,7 +50,8 @@ export type FormProps<
|
|
|
48
50
|
hideSubmit?: boolean;
|
|
49
51
|
autoComplete?: string;
|
|
50
52
|
children?: React.ReactNode;
|
|
51
|
-
initialForm
|
|
53
|
+
initialForm?: FormInterface[];
|
|
54
|
+
sections?: FormSection[];
|
|
52
55
|
disabledSubmit?: boolean;
|
|
53
56
|
mode?: FormMode;
|
|
54
57
|
onSubmit?: (values: FormValuesInterface<T>) => void;
|
|
@@ -59,6 +62,7 @@ export const DynamicForm = forwardRef(
|
|
|
59
62
|
<T extends { [key: string]: string | number | boolean | Date | string[] }>(
|
|
60
63
|
{
|
|
61
64
|
initialForm,
|
|
65
|
+
sections,
|
|
62
66
|
title,
|
|
63
67
|
onSubmit,
|
|
64
68
|
id,
|
|
@@ -79,11 +83,17 @@ export const DynamicForm = forwardRef(
|
|
|
79
83
|
setBtnDisabledSubmit?: (disabled: boolean) => void;
|
|
80
84
|
}>
|
|
81
85
|
) => {
|
|
86
|
+
const formFields = sections
|
|
87
|
+
? sections.reduce<FormInterface[]>(
|
|
88
|
+
(fields, section) => fields.concat(section.fields),
|
|
89
|
+
[],
|
|
90
|
+
)
|
|
91
|
+
: (initialForm ?? []);
|
|
82
92
|
const [btnDisabledSubmit, setBtnDisabledSubmit] = useState(disabledSubmit);
|
|
83
93
|
const [values, setValues] = useState<FormValuesInterface<T>>(() => {
|
|
84
94
|
const initialValues: FormValuesInterface<T> =
|
|
85
95
|
{} as FormValuesInterface<T>;
|
|
86
|
-
|
|
96
|
+
formFields.forEach((field) => {
|
|
87
97
|
(initialValues as any)[field.name] = field.value ?? "";
|
|
88
98
|
});
|
|
89
99
|
return initialValues;
|
|
@@ -164,7 +174,7 @@ export const DynamicForm = forwardRef(
|
|
|
164
174
|
setValues(() => {
|
|
165
175
|
const resetValues: FormValuesInterface<T> =
|
|
166
176
|
{} as FormValuesInterface<T>;
|
|
167
|
-
|
|
177
|
+
formFields.forEach((field) => {
|
|
168
178
|
(resetValues as any)[field.name] = field.value ?? "";
|
|
169
179
|
});
|
|
170
180
|
return resetValues;
|
|
@@ -179,7 +189,7 @@ export const DynamicForm = forwardRef(
|
|
|
179
189
|
}, []);
|
|
180
190
|
|
|
181
191
|
const focusInitialElement = () => {
|
|
182
|
-
const focusedField =
|
|
192
|
+
const focusedField = formFields.find((field) => field.focus);
|
|
183
193
|
if (focusedField && inputRefs.current[focusedField.name]) {
|
|
184
194
|
setTimeout(() => {
|
|
185
195
|
inputRefs.current[focusedField.name]?.select();
|
|
@@ -198,6 +208,17 @@ export const DynamicForm = forwardRef(
|
|
|
198
208
|
}));
|
|
199
209
|
};
|
|
200
210
|
|
|
211
|
+
const updateValues = useCallback(
|
|
212
|
+
(updatedValues: FormValuesInterface<T>) => {
|
|
213
|
+
setValues((previousValues) => {
|
|
214
|
+
const nextValues = { ...previousValues, ...updatedValues };
|
|
215
|
+
onChange?.(nextValues);
|
|
216
|
+
return nextValues;
|
|
217
|
+
});
|
|
218
|
+
},
|
|
219
|
+
[onChange],
|
|
220
|
+
);
|
|
221
|
+
|
|
201
222
|
useImperativeHandle(ref, () => ({
|
|
202
223
|
resetForm,
|
|
203
224
|
clearInput,
|
|
@@ -207,8 +228,6 @@ export const DynamicForm = forwardRef(
|
|
|
207
228
|
setBtnDisabledSubmit,
|
|
208
229
|
}));
|
|
209
230
|
|
|
210
|
-
const gridEnabled = initialForm.some((field) => field.col !== undefined);
|
|
211
|
-
const FieldsContainer = gridEnabled ? Row : React.Fragment;
|
|
212
231
|
const getReadValue = (field: FormInterface): React.ReactNode => {
|
|
213
232
|
const value = values[field.name];
|
|
214
233
|
|
|
@@ -253,15 +272,13 @@ export const DynamicForm = forwardRef(
|
|
|
253
272
|
: String(value);
|
|
254
273
|
};
|
|
255
274
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
<FieldsContainer>
|
|
264
|
-
{initialForm.map((v, key) => {
|
|
275
|
+
const renderFields = (fields: FormInterface[]) => {
|
|
276
|
+
const gridEnabled = fields.some((field) => field.col !== undefined);
|
|
277
|
+
const FieldsContainer = gridEnabled ? Row : React.Fragment;
|
|
278
|
+
|
|
279
|
+
return (
|
|
280
|
+
<FieldsContainer>
|
|
281
|
+
{fields.map((v, key) => {
|
|
265
282
|
const required = v.onRequired
|
|
266
283
|
? v.onRequired(v.value)
|
|
267
284
|
: v.required ?? false;
|
|
@@ -270,102 +287,150 @@ export const DynamicForm = forwardRef(
|
|
|
270
287
|
: v.disabled ?? false;
|
|
271
288
|
|
|
272
289
|
return (
|
|
273
|
-
<FormFieldContainer
|
|
290
|
+
<FormFieldContainer
|
|
291
|
+
key={v.name || key}
|
|
292
|
+
field={v}
|
|
293
|
+
gridEnabled={gridEnabled}
|
|
294
|
+
>
|
|
274
295
|
<div
|
|
275
|
-
className={`d-flex flex-column ${
|
|
276
|
-
v.
|
|
277
|
-
} form-group form-group-${v.type}`}
|
|
296
|
+
className={`d-flex flex-column ${v.className ?? ""
|
|
297
|
+
} form-group form-group-${v.type}`}
|
|
278
298
|
>
|
|
279
|
-
|
|
280
|
-
|
|
299
|
+
{v.label && <label>{v.label}</label>}
|
|
300
|
+
{v.icon && <Icon classIcon={v.icon} />}
|
|
281
301
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
v.type === TypeInputEnum.TEXTAREA
|
|
302
|
+
{mode === "read" ? (
|
|
303
|
+
<div
|
|
304
|
+
className={`form-read-value ${v.type === TypeInputEnum.TEXTAREA
|
|
286
305
|
? "form-read-value--textarea"
|
|
287
306
|
: ""
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
307
|
+
}`}
|
|
308
|
+
>
|
|
309
|
+
{getReadValue(v)}
|
|
310
|
+
</div>
|
|
311
|
+
) : v.type === TypeInputEnum.ADDRESS ? (
|
|
312
|
+
<AddressSearch
|
|
313
|
+
id={v.id ?? v.name}
|
|
314
|
+
label=""
|
|
315
|
+
placeholder={v.placeholder}
|
|
316
|
+
value={String(values[v.name] ?? "")}
|
|
317
|
+
disabled={disabled}
|
|
318
|
+
minimumQueryLength={v.addressSearch?.minimumQueryLength}
|
|
319
|
+
debounceTime={v.addressSearch?.debounceTime}
|
|
320
|
+
limit={v.addressSearch?.limit}
|
|
321
|
+
provider={v.addressSearch?.provider}
|
|
322
|
+
allowManualEntry
|
|
323
|
+
manualEntryLabel={v.addressSearch?.manualEntryLabel}
|
|
324
|
+
onChange={(value) =>
|
|
325
|
+
updateValues({ [v.name]: value } as FormValuesInterface<T>)
|
|
326
|
+
}
|
|
327
|
+
onSelect={(address) => {
|
|
328
|
+
const mappedValues =
|
|
329
|
+
v.addressSearch?.mapAddress?.(address) ?? {};
|
|
330
|
+
updateValues(mappedValues as FormValuesInterface<T>);
|
|
331
|
+
v.addressSearch?.onSelect?.(address);
|
|
332
|
+
}}
|
|
333
|
+
/>
|
|
334
|
+
) : v.type === "select" ? (
|
|
335
|
+
<Select
|
|
336
|
+
id={v.id ?? v.name}
|
|
337
|
+
label={undefined}
|
|
338
|
+
name={v.name}
|
|
339
|
+
options={v.options ?? []}
|
|
340
|
+
disabled={disabled}
|
|
341
|
+
multiple={v.multiple}
|
|
342
|
+
value={values[v.name] as any}
|
|
343
|
+
required={required}
|
|
344
|
+
defaultValue={v.value as string | string[]}
|
|
345
|
+
placeholder={v.placeholder}
|
|
346
|
+
onChangeMultiple={(newValue) =>
|
|
347
|
+
handleChangeSelect(newValue, v.name, v)
|
|
348
|
+
}
|
|
349
|
+
onChange={(newValue) =>
|
|
350
|
+
handleChangeSelect(newValue, v.name, v)
|
|
351
|
+
}
|
|
352
|
+
/>
|
|
353
|
+
) : v.type === "textarea" ? (
|
|
354
|
+
<TextArea
|
|
355
|
+
id={v.id ?? v.name}
|
|
356
|
+
name={v.name}
|
|
357
|
+
className="textarea-input"
|
|
358
|
+
placeholder={v.placeholder ?? ""}
|
|
359
|
+
disabled={disabled}
|
|
360
|
+
required={required}
|
|
361
|
+
value={values[v.name] as string}
|
|
362
|
+
onChange={(value, name) =>
|
|
363
|
+
handleChangeTextArea(name, value, v)
|
|
364
|
+
}
|
|
365
|
+
/>
|
|
366
|
+
) : v.type === TypeInputEnum.PRICE ? (
|
|
367
|
+
<InputPrice
|
|
368
|
+
id={v.id ?? v.name}
|
|
369
|
+
ref={(el) => (inputRefs.current[v.name] = el)}
|
|
370
|
+
name={v.name}
|
|
371
|
+
placeholder={v.placeholder ?? ""}
|
|
372
|
+
autoComplete={v.autoComplete}
|
|
373
|
+
tabIndex={0}
|
|
374
|
+
disabled={disabled}
|
|
375
|
+
autoFocus={v.focus ?? false}
|
|
376
|
+
required={required}
|
|
377
|
+
value={String(values[v.name] ?? "")}
|
|
378
|
+
onChange={(value) =>
|
|
379
|
+
handleChangeTextArea(v.name, value, v)
|
|
380
|
+
}
|
|
381
|
+
/>
|
|
382
|
+
) : (
|
|
383
|
+
<Input
|
|
384
|
+
id={v.id ?? v.name}
|
|
385
|
+
ref={(el) => (inputRefs.current[v.name] = el)}
|
|
386
|
+
name={v.name}
|
|
387
|
+
type={v.type}
|
|
388
|
+
placeholder={v.placeholder ?? ""}
|
|
389
|
+
autoComplete={v.autoComplete}
|
|
390
|
+
tabIndex={0}
|
|
391
|
+
disabled={disabled}
|
|
392
|
+
autoFocus={v.focus ?? false}
|
|
393
|
+
required={required}
|
|
394
|
+
step={v.step ?? "0.01"}
|
|
395
|
+
value={values[v.name] as string | number}
|
|
396
|
+
checked={
|
|
397
|
+
v.type === "checkbox" ? !!values[v.name] : undefined
|
|
398
|
+
}
|
|
399
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
|
400
|
+
handleChangeInput(e, v)
|
|
401
|
+
}
|
|
402
|
+
onInvalid={v.onInvalid ? v.onInvalid : undefined}
|
|
403
|
+
/>
|
|
404
|
+
)}
|
|
363
405
|
</div>
|
|
364
406
|
</FormFieldContainer>
|
|
365
407
|
);
|
|
366
408
|
})}
|
|
409
|
+
</FieldsContainer>
|
|
410
|
+
);
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
return (
|
|
414
|
+
<form
|
|
415
|
+
autoComplete={autoComplete ?? "off"}
|
|
416
|
+
onSubmit={handleSubmit}
|
|
417
|
+
className={className ?? ""}
|
|
418
|
+
>
|
|
419
|
+
<div className="form-content">
|
|
420
|
+
{sections
|
|
421
|
+
? sections.map((section, index) => (
|
|
422
|
+
<section
|
|
423
|
+
className={`form-section ${section.className ?? ""}`}
|
|
424
|
+
key={index}
|
|
425
|
+
>
|
|
426
|
+
{section.title && (
|
|
427
|
+
<h3 className="form-section-title">{section.title}</h3>
|
|
428
|
+
)}
|
|
429
|
+
{renderFields(section.fields)}
|
|
430
|
+
</section>
|
|
431
|
+
))
|
|
432
|
+
: renderFields(initialForm ?? [])}
|
|
367
433
|
{children}
|
|
368
|
-
</FieldsContainer>
|
|
369
434
|
</div>
|
|
370
435
|
<div className="d-flex justify-content-end form-footer">
|
|
371
436
|
{mode === "edit" && !hideSubmit && (
|
package/src/form/form.css
CHANGED
|
@@ -20,6 +20,19 @@ input[type="radio"] {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
form {
|
|
23
|
+
.form-section+.form-section {
|
|
24
|
+
margin-top: 1.25rem;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.form-section-title {
|
|
28
|
+
margin: 0 15px 0.5rem;
|
|
29
|
+
padding-bottom: 0.5rem;
|
|
30
|
+
border-bottom: 1px solid #dedede;
|
|
31
|
+
color: var(--primary-color);
|
|
32
|
+
font-size: 1rem;
|
|
33
|
+
font-weight: 600;
|
|
34
|
+
}
|
|
35
|
+
|
|
23
36
|
&.form-row {
|
|
24
37
|
display: flex;
|
|
25
38
|
flex-direction: row;
|
|
@@ -79,7 +92,7 @@ form {
|
|
|
79
92
|
border: 1px solid transparent;
|
|
80
93
|
border-radius: 4px;
|
|
81
94
|
margin: 0.25rem 0;
|
|
82
|
-
padding: 0
|
|
95
|
+
padding: 0;
|
|
83
96
|
font-size: 0.8rem;
|
|
84
97
|
line-height: normal;
|
|
85
98
|
overflow-wrap: anywhere;
|
package/src/form/form.enum.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { TypeInputEnum } from "./form.enum";
|
|
2
2
|
import { GridBreakpoints } from "../grid/grid.interface";
|
|
3
|
+
import {
|
|
4
|
+
GeocodedAddress,
|
|
5
|
+
GeocodingProvider,
|
|
6
|
+
} from "../geocoding/geocoding.interface";
|
|
3
7
|
|
|
4
8
|
export type FormMode = "read" | "edit";
|
|
5
9
|
|
|
@@ -13,6 +17,12 @@ export interface FormCondition {
|
|
|
13
17
|
regex: string;
|
|
14
18
|
}
|
|
15
19
|
|
|
20
|
+
export interface FormSection {
|
|
21
|
+
title?: React.ReactNode;
|
|
22
|
+
fields: FormInterface[];
|
|
23
|
+
className?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
16
26
|
export interface FormInterface {
|
|
17
27
|
value: string | number | boolean | Date;
|
|
18
28
|
id?: string;
|
|
@@ -29,6 +39,17 @@ export interface FormInterface {
|
|
|
29
39
|
options?: { value: string; label: string }[]; // <--- pour les <option>
|
|
30
40
|
className?: string;
|
|
31
41
|
col?: GridBreakpoints;
|
|
42
|
+
addressSearch?: {
|
|
43
|
+
minimumQueryLength?: number;
|
|
44
|
+
debounceTime?: number;
|
|
45
|
+
limit?: number;
|
|
46
|
+
provider?: GeocodingProvider;
|
|
47
|
+
manualEntryLabel?: string;
|
|
48
|
+
mapAddress?: (
|
|
49
|
+
address: GeocodedAddress,
|
|
50
|
+
) => Record<string, string | number | boolean | Date | string[]>;
|
|
51
|
+
onSelect?: (address: GeocodedAddress) => void;
|
|
52
|
+
};
|
|
32
53
|
formatReadValue?: (
|
|
33
54
|
value: string | number | boolean | Date | string[]
|
|
34
55
|
) => React.ReactNode;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GeocodedAddress,
|
|
3
|
+
GeocodingProvider,
|
|
4
|
+
GeocodingSearchOptions,
|
|
5
|
+
} from "./geocoding.interface";
|
|
6
|
+
|
|
7
|
+
const DEFAULT_GEOCODING_URL = "https://data.geopf.fr/geocodage/search";
|
|
8
|
+
|
|
9
|
+
interface GeocodingFeature {
|
|
10
|
+
geometry?: {
|
|
11
|
+
coordinates?: [number, number];
|
|
12
|
+
};
|
|
13
|
+
properties?: {
|
|
14
|
+
id?: string;
|
|
15
|
+
label?: string;
|
|
16
|
+
name?: string;
|
|
17
|
+
postcode?: string;
|
|
18
|
+
city?: string;
|
|
19
|
+
citycode?: string;
|
|
20
|
+
score?: number;
|
|
21
|
+
type?: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface GeocodingResponse {
|
|
26
|
+
features?: GeocodingFeature[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface GeocodingServiceOptions {
|
|
30
|
+
baseUrl?: string;
|
|
31
|
+
fetcher?: typeof fetch;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export class GeocodingService implements GeocodingProvider {
|
|
35
|
+
private readonly baseUrl: string;
|
|
36
|
+
private readonly fetcher: typeof fetch;
|
|
37
|
+
|
|
38
|
+
constructor(options: GeocodingServiceOptions = {}) {
|
|
39
|
+
this.baseUrl = options.baseUrl ?? DEFAULT_GEOCODING_URL;
|
|
40
|
+
this.fetcher = options.fetcher ?? globalThis.fetch.bind(globalThis);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async search(
|
|
44
|
+
query: string,
|
|
45
|
+
options: GeocodingSearchOptions = {},
|
|
46
|
+
): Promise<GeocodedAddress[]> {
|
|
47
|
+
const normalizedQuery = query.trim();
|
|
48
|
+
if (!normalizedQuery) return [];
|
|
49
|
+
|
|
50
|
+
const params = new URLSearchParams({
|
|
51
|
+
q: normalizedQuery,
|
|
52
|
+
limit: String(options.limit ?? 5),
|
|
53
|
+
autocomplete: "1",
|
|
54
|
+
index: "address",
|
|
55
|
+
});
|
|
56
|
+
const response = await this.fetcher(`${this.baseUrl}?${params}`, {
|
|
57
|
+
signal: options.signal,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
if (!response.ok) {
|
|
61
|
+
throw new Error(`Geocoding request failed (${response.status})`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const data = (await response.json()) as GeocodingResponse;
|
|
65
|
+
return (data.features ?? []).flatMap((feature) => {
|
|
66
|
+
const properties = feature.properties;
|
|
67
|
+
const coordinates = feature.geometry?.coordinates;
|
|
68
|
+
if (!properties?.label || !coordinates) return [];
|
|
69
|
+
|
|
70
|
+
return [
|
|
71
|
+
{
|
|
72
|
+
id: properties.id ?? properties.label,
|
|
73
|
+
label: properties.label,
|
|
74
|
+
addressLine: properties.name ?? properties.label,
|
|
75
|
+
postalCode: properties.postcode ?? "",
|
|
76
|
+
city: properties.city ?? "",
|
|
77
|
+
cityCode: properties.citycode,
|
|
78
|
+
countryCode: "FR",
|
|
79
|
+
longitude: coordinates[0],
|
|
80
|
+
latitude: coordinates[1],
|
|
81
|
+
score: properties.score,
|
|
82
|
+
type: properties.type,
|
|
83
|
+
},
|
|
84
|
+
];
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export const geocodingService = new GeocodingService();
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface GeocodedAddress {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
addressLine: string;
|
|
5
|
+
postalCode: string;
|
|
6
|
+
city: string;
|
|
7
|
+
cityCode?: string;
|
|
8
|
+
countryCode: string;
|
|
9
|
+
longitude: number;
|
|
10
|
+
latitude: number;
|
|
11
|
+
score?: number;
|
|
12
|
+
type?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface GeocodingSearchOptions {
|
|
16
|
+
limit?: number;
|
|
17
|
+
signal?: AbortSignal;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface GeocodingProvider {
|
|
21
|
+
search(
|
|
22
|
+
query: string,
|
|
23
|
+
options?: GeocodingSearchOptions,
|
|
24
|
+
): Promise<GeocodedAddress[]>;
|
|
25
|
+
}
|
package/src/grid/row/row.css
CHANGED
package/src/index.ts
CHANGED
|
@@ -20,6 +20,8 @@ export { useToken } from "./_core/hooks/useToken";
|
|
|
20
20
|
export { useValidate } from "./_core/hooks/useValidate";
|
|
21
21
|
export { WidgetSupport } from "./_core/hooks/widgetSupport";
|
|
22
22
|
export { ButtonAction } from "./action/ButtonAction";
|
|
23
|
+
export { AddressSearch } from "./addressSearch/AddressSearch";
|
|
24
|
+
export type { AddressSearchProps } from "./addressSearch/AddressSearch";
|
|
23
25
|
export { Badge } from "./badge/Badge";
|
|
24
26
|
export { Button } from "./button/Button";
|
|
25
27
|
export { ButtonActions } from "./button/buttonActions/ButtonActions";
|
|
@@ -33,12 +35,21 @@ export { Expands } from "./expands/Expands";
|
|
|
33
35
|
export { FilAriane } from "./filAriane/FilAriane";
|
|
34
36
|
export { DynamicForm } from "./form/Form";
|
|
35
37
|
export { TypeInputEnum } from "./form/form.enum";
|
|
36
|
-
export type { FormMode } from "./form/form.interface";
|
|
38
|
+
export type { FormMode, FormSection } from "./form/form.interface";
|
|
37
39
|
export { Input } from "./form/input/Input";
|
|
38
40
|
export { InputNumber } from "./form/inputNumber/InputNumber";
|
|
39
41
|
export { InputPrice } from "./form/inputPrice/InputPrice";
|
|
40
42
|
export { TextArea } from "./form/textArea/TextArea";
|
|
41
43
|
export { Grid } from "./grid/Grid";
|
|
44
|
+
export {
|
|
45
|
+
GeocodingService,
|
|
46
|
+
geocodingService,
|
|
47
|
+
} from "./geocoding/GeocodingService";
|
|
48
|
+
export type {
|
|
49
|
+
GeocodedAddress,
|
|
50
|
+
GeocodingProvider,
|
|
51
|
+
GeocodingSearchOptions,
|
|
52
|
+
} from "./geocoding/geocoding.interface";
|
|
42
53
|
export { Header } from "./header/Header";
|
|
43
54
|
export { Icon } from "./icon/Icon";
|
|
44
55
|
export { IconSizeEnum } from "./icon/iconSize.enum";
|