kelt-ui-kit-react 2.0.2 → 2.0.3

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 (127) hide show
  1. package/README.md +0 -26
  2. package/dist/_core/type/generiqueType.d.ts +4 -0
  3. package/dist/badge/Badge.d.ts +3 -1
  4. package/dist/button/Button.d.ts +1 -1
  5. package/dist/button/button.interface.d.ts +1 -2
  6. package/dist/dataTable/DataTable.d.ts +17 -14
  7. package/dist/dataTable/dataTable.interface.d.ts +24 -19
  8. package/dist/dataTable/dataTableActions/DataTableAction.d.ts +3 -5
  9. package/dist/dataTable/dataTableColumn/DataTableColumn.d.ts +13 -7
  10. package/dist/dataTable/dataTableColumn/dataTableColumnFilter/DataTableColumnFilter.d.ts +10 -0
  11. package/dist/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterDate/DataTableColumnFilterDate.d.ts +9 -0
  12. package/dist/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterDateRange/dataTableColumnFilterDateRange.d.ts +9 -0
  13. package/dist/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterEnum/DataTableColumnFilterEnum.d.ts +13 -0
  14. package/dist/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterString/DataTableColumnFilterString.d.ts +9 -0
  15. package/dist/dataTable/dataTableColumn/dataTableColumnSort/DataTableColumnSort.d.ts +11 -0
  16. package/dist/dataTable/dataTableFilters/DataTableFilters.d.ts +7 -0
  17. package/dist/dataTable/dataTableLoading/DataTableLoading.d.ts +1 -3
  18. package/dist/dataTable/dataTableRow/DataTableRow.d.ts +5 -6
  19. package/dist/dataTable/dataTableRow/dataTableRowOverlay/DataTableRowOverlay.d.ts +12 -0
  20. package/dist/dataTable/dataTableRow/dataTableRowValue/DataTableRowValue.d.ts +11 -0
  21. package/dist/expands/expand/expand.d.ts +1 -1
  22. package/dist/form/Form.d.ts +2 -4
  23. package/dist/form/form.enum.d.ts +2 -3
  24. package/dist/form/form.interface.d.ts +2 -19
  25. package/dist/form/input/Input.d.ts +3 -0
  26. package/dist/form/inputNumber/InputNumber.d.ts +0 -2
  27. package/dist/grid/col/Col.d.ts +6 -3
  28. package/dist/grid/col/colStyled/ColStyled.d.ts +5 -7
  29. package/dist/grid/grid.interface.d.ts +5 -9
  30. package/dist/header/Header.d.ts +1 -1
  31. package/dist/header/header.interface.d.ts +1 -2
  32. package/dist/icon/Icon.d.ts +1 -1
  33. package/dist/icon/icon.interface.d.ts +1 -0
  34. package/dist/index.d.ts +1 -5
  35. package/dist/index.js +3606 -3543
  36. package/dist/menus/menu/Menu.d.ts +0 -1
  37. package/dist/overlayPanel/OverlayPanel.d.ts +4 -2
  38. package/dist/overlayPanel/overlayPanelStyled/OverlayPanelStyled.d.ts +2 -0
  39. package/dist/select/Select.d.ts +6 -2
  40. package/dist/select/selectOption.interface.d.ts +1 -0
  41. package/dist/style.css +1 -1
  42. package/dist/tabs/Tabs.d.ts +2 -1
  43. package/dist/toaster/store/useToasterStore.d.ts +0 -1
  44. package/index.html +2 -1
  45. package/package/package.json +56 -0
  46. package/package/src/sidebar/Sidebar.tsx +208 -0
  47. package/package/src/sidebar/sidebar.css +104 -0
  48. package/package.json +1 -1
  49. package/src/App.menu.tsx +0 -8
  50. package/src/_core/type/generiqueType.tsx +4 -0
  51. package/src/badge/Badge.tsx +9 -1
  52. package/src/badge/badge.css +4 -0
  53. package/src/button/Button.tsx +1 -3
  54. package/src/button/button.css +2 -2
  55. package/src/button/button.interface.tsx +1 -2
  56. package/src/card/card.css +25 -5
  57. package/src/card/cardAction/CardAction.tsx +4 -4
  58. package/src/damier/Damier.tsx +7 -16
  59. package/src/damier/damier.css +4 -11
  60. package/src/dataTable/DataTable.tsx +685 -542
  61. package/src/dataTable/DataTable.view.tsx +48 -24
  62. package/src/dataTable/dataTable.css +134 -159
  63. package/src/dataTable/dataTable.interface.ts +25 -19
  64. package/src/dataTable/dataTableActions/DataTableAction.tsx +14 -25
  65. package/src/dataTable/dataTableColumn/DataTableColumn.tsx +64 -14
  66. package/src/dataTable/dataTableColumn/dataTableColumnFilter/DataTableColumnFilter.tsx +36 -0
  67. package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilter.css +0 -0
  68. package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterDate/DataTableColumnFilterDate.tsx +39 -0
  69. package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterDateRange/dataTableColumnFilterDateRange.tsx +80 -0
  70. package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterEnum/DataTableColumnFilterEnum.tsx +89 -0
  71. package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterString/DataTableColumnFilterString.tsx +37 -0
  72. package/src/dataTable/dataTableColumn/dataTableColumnSort/DataTableColumnSort.tsx +42 -0
  73. package/src/dataTable/dataTableFilters/DataTableFilters.tsx +91 -0
  74. package/src/dataTable/dataTableFilters/dataTableFilters.css +16 -0
  75. package/src/dataTable/dataTableLoading/DataTableLoading.tsx +4 -15
  76. package/src/dataTable/dataTableRow/DataTableRow.tsx +64 -180
  77. package/src/dataTable/dataTableRow/dataTableRowOverlay/DataTableRowOverlay.tsx +80 -0
  78. package/src/dataTable/dataTableRow/dataTableRowValue/DataTableRowValue.tsx +123 -0
  79. package/src/expands/Expands.tsx +2 -16
  80. package/src/expands/expand/expand.tsx +5 -122
  81. package/src/expands/expands.css +3 -8
  82. package/src/form/Form.tsx +93 -258
  83. package/src/form/Form.view.tsx +1 -9
  84. package/src/form/form.css +1 -51
  85. package/src/form/form.enum.ts +1 -2
  86. package/src/form/form.interface.tsx +2 -28
  87. package/src/form/input/Input.tsx +61 -7
  88. package/src/form/input/input.css +23 -1
  89. package/src/form/inputNumber/InputNumber.tsx +6 -11
  90. package/src/form/inputPrice/InputPrice.tsx +2 -4
  91. package/src/grid/col/Col.tsx +7 -5
  92. package/src/grid/col/colStyled/ColStyled.tsx +7 -21
  93. package/src/grid/grid.interface.tsx +5 -11
  94. package/src/grid/row/row.css +2 -2
  95. package/src/header/Header.tsx +2 -4
  96. package/src/header/header.css +0 -17
  97. package/src/header/header.interface.tsx +1 -2
  98. package/src/icon/Icon.tsx +6 -2
  99. package/src/icon/icon.interface.tsx +1 -0
  100. package/src/index.css +12 -58
  101. package/src/index.ts +2 -12
  102. package/src/menus/Menus.tsx +0 -1
  103. package/src/menus/menu/Menu.tsx +1 -2
  104. package/src/overlayPanel/OverlayPanel.tsx +71 -18
  105. package/src/overlayPanel/overlay.context.tsx +6 -4
  106. package/src/overlayPanel/overlayPanel.css +10 -1
  107. package/src/overlayPanel/overlayPanelStyled/OverlayPanelStyled.tsx +7 -2
  108. package/src/select/Select.tsx +178 -41
  109. package/src/select/select.css +94 -13
  110. package/src/select/selectOption.interface.ts +1 -0
  111. package/src/sidebar/Sidebar.tsx +5 -107
  112. package/src/sidebar/sidebar.css +1 -18
  113. package/src/tabs/Tabs.tsx +20 -1
  114. package/src/tabs/tabs.css +3 -9
  115. package/src/toaster/Toaster.tsx +2 -7
  116. package/src/toaster/Toaster.view.tsx +0 -1
  117. package/src/toaster/store/useToasterStore.tsx +0 -2
  118. package/src/toaster/toaster.css +2 -7
  119. package/dist/addressSearch/AddressSearch.d.ts +0 -20
  120. package/dist/addressSearch/AddressSearch.view.d.ts +0 -1
  121. package/dist/geocoding/GeocodingService.d.ts +0 -13
  122. package/dist/geocoding/geocoding.interface.d.ts +0 -20
  123. package/src/addressSearch/AddressSearch.tsx +0 -246
  124. package/src/addressSearch/AddressSearch.view.tsx +0 -52
  125. package/src/addressSearch/addressSearch.css +0 -133
  126. package/src/geocoding/GeocodingService.ts +0 -89
  127. package/src/geocoding/geocoding.interface.ts +0 -25
package/src/tabs/tabs.css CHANGED
@@ -1,30 +1,24 @@
1
1
  .tabs-root {
2
2
  height: 100%;
3
-
4
3
  .tabs-header {
5
4
  display: flex;
6
5
  border-bottom: 1px solid #b2a1a1;
7
-
8
6
  .tab-button {
9
7
  padding: 0.5rem 0.75rem;
10
8
  border: 0px;
11
9
  outline: none;
12
10
  background-color: transparent;
13
- color: #1e293b;
14
- /* slate-800 */
11
+ color: #1e293b; /* slate-800 */
15
12
  cursor: pointer;
16
13
 
17
14
  &.tab-button--active {
18
- border-bottom: 2px solid var(--primary-color);
19
- /* slate-800 */
15
+ border-bottom: 2px solid var(--primary-color); /* slate-800 */
20
16
  border-radius: 0px;
21
- font-weight: bold;
22
17
  }
23
-
24
18
  &.tab-button--disabled {
25
19
  opacity: 0.5;
26
20
  cursor: not-allowed;
27
21
  }
28
22
  }
29
23
  }
30
- }
24
+ }
@@ -34,14 +34,9 @@ export const Toaster = () => {
34
34
  return ReactDOM.createPortal(
35
35
  <div className={`toaster toaster-${severity}`}>
36
36
  {close && (
37
- <button
38
- type="button"
39
- className="toaster--close"
40
- onClick={onClose}
41
- aria-label="Fermer la notification"
42
- >
37
+ <div className="toaster--close" onClick={onClose}>
43
38
  <Icon classIcon="bi-x" />
44
- </button>
39
+ </div>
45
40
  )}
46
41
  <div>
47
42
  {severity === "info" && <Icon classIcon="bi-info-circle" />}
@@ -9,7 +9,6 @@ export const ToasterView = (): JSX.Element => {
9
9
  description: "This is a description for the toast message.",
10
10
  severity: "warning",
11
11
  duration: 10000,
12
- close: true,
13
12
  children: <div>Additional content can go here.</div>,
14
13
  });
15
14
  }, [showToast]);
@@ -15,7 +15,6 @@ type ToasterState = {
15
15
  severity?: "info" | "success" | "error" | "warning";
16
16
  duration?: number;
17
17
  children?: React.ReactNode;
18
- close?: boolean;
19
18
  }
20
19
  ) => void;
21
20
  hideToast: () => void;
@@ -37,7 +36,6 @@ export const useToasterStore = create<ToasterState>((set) => ({
37
36
  duration: options.duration || 2500,
38
37
  visible: true,
39
38
  children: options.children || null,
40
- close: options.close ?? true,
41
39
  })),
42
40
  hideToast: () => set(() => ({ visible: false })),
43
41
  }));
@@ -15,12 +15,7 @@
15
15
  position: absolute;
16
16
  top: 2px;
17
17
  right: 2px;
18
- margin: 0;
19
- padding: 0;
20
- border: 0;
21
- background: transparent;
22
18
  color: #333;
23
- min-width: auto;
24
19
  cursor: pointer;
25
20
  .bi {
26
21
  font-size: 1.2rem;
@@ -60,7 +55,7 @@
60
55
  }
61
56
  .title {
62
57
  font-weight: 500;
63
- font-size: 18px;
58
+ font-size: 16px;
64
59
  &.title-info {
65
60
  color: var(--primary-color);
66
61
  }
@@ -75,7 +70,7 @@
75
70
  }
76
71
  }
77
72
  .subtitle {
78
- font-size: 16px;
73
+ font-size: 14px;
79
74
  }
80
75
  .bi-info-circle {
81
76
  color: var(--primary-color);
@@ -1,20 +0,0 @@
1
- import { GeocodedAddress, GeocodingProvider } from '../geocoding/geocoding.interface';
2
-
3
- export interface AddressSearchProps {
4
- id?: string;
5
- className?: string;
6
- label?: string;
7
- placeholder?: string;
8
- value?: string;
9
- disabled?: boolean;
10
- minimumQueryLength?: number;
11
- debounceTime?: number;
12
- limit?: number;
13
- provider?: GeocodingProvider;
14
- allowManualEntry?: boolean;
15
- manualEntryLabel?: string;
16
- onChange?: (value: string) => void;
17
- onManualEntry?: (addressLine: string) => void;
18
- onSelect: (address: GeocodedAddress) => void;
19
- }
20
- export declare const AddressSearch: ({ id, className, label, placeholder, value, disabled, minimumQueryLength, debounceTime, limit, provider, allowManualEntry, manualEntryLabel, onChange, onManualEntry, onSelect, }: AddressSearchProps) => import("react/jsx-runtime").JSX.Element;
@@ -1 +0,0 @@
1
- export declare const AddressSearchView: () => import("react/jsx-runtime").JSX.Element;
@@ -1,13 +0,0 @@
1
- import { GeocodedAddress, GeocodingProvider, GeocodingSearchOptions } from './geocoding.interface';
2
-
3
- export interface GeocodingServiceOptions {
4
- baseUrl?: string;
5
- fetcher?: typeof fetch;
6
- }
7
- export declare class GeocodingService implements GeocodingProvider {
8
- private readonly baseUrl;
9
- private readonly fetcher;
10
- constructor(options?: GeocodingServiceOptions);
11
- search(query: string, options?: GeocodingSearchOptions): Promise<GeocodedAddress[]>;
12
- }
13
- export declare const geocodingService: GeocodingService;
@@ -1,20 +0,0 @@
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
- export interface GeocodingSearchOptions {
15
- limit?: number;
16
- signal?: AbortSignal;
17
- }
18
- export interface GeocodingProvider {
19
- search(query: string, options?: GeocodingSearchOptions): Promise<GeocodedAddress[]>;
20
- }
@@ -1,246 +0,0 @@
1
- import {
2
- useCallback,
3
- useEffect,
4
- useId,
5
- useRef,
6
- useState,
7
- } from "react";
8
- import { Icon } from "../icon/Icon";
9
- import {
10
- GeocodedAddress,
11
- GeocodingProvider,
12
- } from "../geocoding/geocoding.interface";
13
- import { geocodingService } from "../geocoding/GeocodingService";
14
- import "./addressSearch.css";
15
-
16
- export interface AddressSearchProps {
17
- id?: string;
18
- className?: string;
19
- label?: string;
20
- placeholder?: string;
21
- value?: string;
22
- disabled?: boolean;
23
- minimumQueryLength?: number;
24
- debounceTime?: number;
25
- limit?: number;
26
- provider?: GeocodingProvider;
27
- allowManualEntry?: boolean;
28
- manualEntryLabel?: string;
29
- onChange?: (value: string) => void;
30
- onManualEntry?: (addressLine: string) => void;
31
- onSelect: (address: GeocodedAddress) => void;
32
- }
33
-
34
- export const AddressSearch = ({
35
- id,
36
- className,
37
- label = "Rechercher une adresse",
38
- placeholder = "Numéro, rue, code postal, ville",
39
- value,
40
- disabled = false,
41
- minimumQueryLength = 3,
42
- debounceTime = 300,
43
- limit = 5,
44
- provider = geocodingService,
45
- allowManualEntry = true,
46
- manualEntryLabel = "Je ne trouve pas mon adresse",
47
- onChange,
48
- onManualEntry,
49
- onSelect,
50
- }: AddressSearchProps) => {
51
- const generatedId = useId();
52
- const inputId = id ?? `address-search-${generatedId}`;
53
- const listboxId = `${inputId}-results`;
54
- const [query, setQuery] = useState(value ?? "");
55
- const [results, setResults] = useState<GeocodedAddress[]>([]);
56
- const [loading, setLoading] = useState(false);
57
- const [error, setError] = useState(false);
58
- const [isOpen, setIsOpen] = useState(false);
59
- const [activeIndex, setActiveIndex] = useState(-1);
60
- const containerRef = useRef<HTMLDivElement>(null);
61
- const requestRef = useRef<AbortController>();
62
- const skipNextSearchRef = useRef(false);
63
-
64
- useEffect(() => {
65
- if (value !== undefined) setQuery(value);
66
- }, [value]);
67
-
68
- useEffect(() => {
69
- const handlePointerDown = (event: PointerEvent) => {
70
- if (!containerRef.current?.contains(event.target as Node)) {
71
- setIsOpen(false);
72
- }
73
- };
74
-
75
- document.addEventListener("pointerdown", handlePointerDown);
76
- return () => document.removeEventListener("pointerdown", handlePointerDown);
77
- }, []);
78
-
79
- useEffect(() => {
80
- if (skipNextSearchRef.current) {
81
- skipNextSearchRef.current = false;
82
- return;
83
- }
84
-
85
- const normalizedQuery = query.trim();
86
- if (normalizedQuery.length < minimumQueryLength || disabled) {
87
- requestRef.current?.abort();
88
- setResults([]);
89
- setLoading(false);
90
- setError(false);
91
- setIsOpen(false);
92
- return;
93
- }
94
-
95
- const timeout = window.setTimeout(async () => {
96
- requestRef.current?.abort();
97
- const controller = new AbortController();
98
- requestRef.current = controller;
99
- setLoading(true);
100
- setError(false);
101
-
102
- try {
103
- const addresses = await provider.search(normalizedQuery, {
104
- limit,
105
- signal: controller.signal,
106
- });
107
- setResults(addresses);
108
- setActiveIndex(-1);
109
- setIsOpen(true);
110
- } catch (requestError) {
111
- if ((requestError as Error).name !== "AbortError") {
112
- setResults([]);
113
- setError(true);
114
- setIsOpen(true);
115
- }
116
- } finally {
117
- if (!controller.signal.aborted) setLoading(false);
118
- }
119
- }, debounceTime);
120
-
121
- return () => {
122
- window.clearTimeout(timeout);
123
- requestRef.current?.abort();
124
- };
125
- }, [debounceTime, disabled, limit, minimumQueryLength, provider, query]);
126
-
127
- const selectAddress = useCallback(
128
- (address: GeocodedAddress) => {
129
- requestRef.current?.abort();
130
- skipNextSearchRef.current = true;
131
- setQuery(address.addressLine);
132
- setResults([]);
133
- setIsOpen(false);
134
- setActiveIndex(-1);
135
- onChange?.(address.addressLine);
136
- onSelect(address);
137
- },
138
- [onChange, onSelect],
139
- );
140
-
141
- const selectManualAddress = useCallback(() => {
142
- const addressLine = query.trim();
143
- if (!addressLine) return;
144
-
145
- requestRef.current?.abort();
146
- skipNextSearchRef.current = true;
147
- setQuery(addressLine);
148
- setResults([]);
149
- setIsOpen(false);
150
- setActiveIndex(-1);
151
- onChange?.(addressLine);
152
- onManualEntry?.(addressLine);
153
- }, [onChange, onManualEntry, query]);
154
-
155
- const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
156
- if (!isOpen || results.length === 0) return;
157
-
158
- if (event.key === "ArrowDown") {
159
- event.preventDefault();
160
- setActiveIndex((index) => (index + 1) % results.length);
161
- } else if (event.key === "ArrowUp") {
162
- event.preventDefault();
163
- setActiveIndex((index) => (index <= 0 ? results.length - 1 : index - 1));
164
- } else if (event.key === "Enter" && activeIndex >= 0) {
165
- event.preventDefault();
166
- selectAddress(results[activeIndex]);
167
- } else if (event.key === "Escape") {
168
- setIsOpen(false);
169
- }
170
- };
171
-
172
- return (
173
- <div ref={containerRef} className={`address-search ${className ?? ""}`}>
174
- {label && <label htmlFor={inputId}>{label}</label>}
175
- <div className="address-search-input">
176
- <Icon classIcon="bi-geo-alt" />
177
- <input
178
- id={inputId}
179
- type="search"
180
- role="combobox"
181
- aria-autocomplete="list"
182
- aria-expanded={isOpen}
183
- aria-controls={listboxId}
184
- aria-activedescendant={
185
- activeIndex >= 0 ? `${inputId}-option-${activeIndex}` : undefined
186
- }
187
- autoComplete="off"
188
- disabled={disabled}
189
- value={query}
190
- placeholder={placeholder}
191
- onChange={(event) => {
192
- setQuery(event.target.value);
193
- onChange?.(event.target.value);
194
- }}
195
- onFocus={() => results.length > 0 && setIsOpen(true)}
196
- onKeyDown={handleKeyDown}
197
- />
198
- {loading && <span className="address-search-spinner" aria-hidden />}
199
- </div>
200
-
201
- {isOpen && (
202
- <div className="address-search-results">
203
- <div id={listboxId} role="listbox">
204
- {error ? (
205
- <div className="address-search-status" role="alert">
206
- La recherche d'adresse est indisponible.
207
- </div>
208
- ) : results.length === 0 && !loading ? (
209
- <div className="address-search-status">Aucune adresse trouvée.</div>
210
- ) : (
211
- results.map((address, index) => (
212
- <button
213
- id={`${inputId}-option-${index}`}
214
- key={`${address.id}-${index}`}
215
- type="button"
216
- role="option"
217
- aria-selected={activeIndex === index}
218
- className={activeIndex === index ? "active" : ""}
219
- onMouseDown={(event) => event.preventDefault()}
220
- onMouseEnter={() => setActiveIndex(index)}
221
- onClick={() => selectAddress(address)}
222
- >
223
- <span>{address.addressLine}</span>
224
- <small>
225
- {address.postalCode} {address.city}
226
- </small>
227
- </button>
228
- ))
229
- )}
230
- </div>
231
- {allowManualEntry && query.trim() && !loading && (
232
- <button
233
- type="button"
234
- className="address-search-manual"
235
- onMouseDown={(event) => event.preventDefault()}
236
- onClick={selectManualAddress}
237
- >
238
- <Icon classIcon="bi-pencil" />
239
- {manualEntryLabel}
240
- </button>
241
- )}
242
- </div>
243
- )}
244
- </div>
245
- );
246
- };
@@ -1,52 +0,0 @@
1
- import { useMemo } from "react";
2
- import { DynamicForm } from "../form/Form";
3
- import { TypeInputEnum } from "../form/form.enum";
4
- import { FormInterface } from "../form/form.interface";
5
-
6
- export const AddressSearchView = () => {
7
- const fields = useMemo<FormInterface[]>(
8
- () => [
9
- {
10
- name: "adresse1",
11
- label: "Adresse",
12
- type: TypeInputEnum.ADDRESS,
13
- value: "",
14
- col: { xs: 12, md: 6 },
15
- addressSearch: {
16
- mapAddress: (address) => ({
17
- adresse1: address.addressLine,
18
- codePostal: address.postalCode,
19
- ville: address.city,
20
- paysIso2: address.countryCode,
21
- }),
22
- },
23
- },
24
- {
25
- name: "codePostal",
26
- label: "Code postal",
27
- type: TypeInputEnum.TEXT,
28
- value: "",
29
- col: { xs: 12, md: 6 },
30
- },
31
- {
32
- name: "ville",
33
- label: "Ville",
34
- type: TypeInputEnum.TEXT,
35
- value: "",
36
- col: { xs: 12, md: 6 },
37
- },
38
- {
39
- name: "paysIso2",
40
- label: "Pays",
41
- type: TypeInputEnum.TEXT,
42
- value: "FR",
43
- col: { xs: 12, md: 6 },
44
- },
45
- ],
46
- [],
47
- );
48
-
49
- return (
50
- <DynamicForm initialForm={fields} hideSubmit />
51
- );
52
- };
@@ -1,133 +0,0 @@
1
- .address-search {
2
- position: relative;
3
- width: 100%;
4
-
5
- >label {
6
- display: block;
7
- padding-bottom: 0.15rem;
8
- font-size: 0.85rem;
9
- font-weight: 600;
10
- }
11
- }
12
-
13
- .address-search-input {
14
- position: relative;
15
- display: flex;
16
- align-items: center;
17
-
18
- >.bi {
19
- position: absolute;
20
- left: 0.75rem;
21
- z-index: 1;
22
- color: var(--primary-color);
23
- }
24
-
25
- >input {
26
- box-sizing: border-box;
27
- width: 100%;
28
- min-width: 0;
29
- padding-left: 2.25rem;
30
- padding-right: 2.25rem;
31
- }
32
- }
33
-
34
- .address-search-spinner {
35
- position: absolute;
36
- right: 0.75rem;
37
- width: 0.9rem;
38
- height: 0.9rem;
39
- border: 2px solid #dedede;
40
- border-top-color: var(--primary-color);
41
- border-radius: 50%;
42
- animation: address-search-spin 0.7s linear infinite;
43
- }
44
-
45
- .address-search-results {
46
- position: absolute;
47
- top: calc(100% + 0.25rem);
48
- right: 0;
49
- left: 0;
50
- z-index: 20;
51
- overflow: hidden;
52
- border: 1px solid #cfbdbd;
53
- border-radius: 4px;
54
- background: #fff;
55
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.14);
56
-
57
- [role="listbox"] {
58
- max-height: 15rem;
59
- overflow-y: auto;
60
- }
61
-
62
- [role="listbox"]>button {
63
- display: flex;
64
- width: 100%;
65
- min-width: 0;
66
- max-height: none;
67
- margin: 0;
68
- padding: 0.65rem 0.75rem;
69
- flex-direction: column;
70
- align-items: flex-start;
71
- gap: 0.2rem;
72
- border: 0;
73
- border-bottom: 1px solid #ece8e8;
74
- border-radius: 0;
75
- background: #fff;
76
- color: inherit;
77
- font-size: 0.85rem;
78
- line-height: 1.3;
79
- text-align: left;
80
- overflow-wrap: anywhere;
81
- cursor: pointer;
82
-
83
- &:last-child {
84
- border-bottom: 0;
85
- }
86
-
87
- &:hover,
88
- &.active {
89
- background: color-mix(in srgb, var(--primary-color), white 92%);
90
- }
91
-
92
- >small {
93
- color: #686868;
94
- }
95
- }
96
- }
97
-
98
- .address-search-manual {
99
- display: flex;
100
- width: 100%;
101
- min-width: 0;
102
- max-height: none;
103
- margin: 0;
104
- padding: 0.65rem 0.75rem;
105
- align-items: center;
106
- gap: 0.5rem;
107
- border: 0;
108
- border-top: 1px solid #dedede;
109
- border-radius: 0;
110
- background: #fff;
111
- color: var(--primary-color);
112
- font-size: 0.85rem;
113
- font-weight: 600;
114
- text-align: left;
115
- cursor: pointer;
116
-
117
- &:hover,
118
- &:focus-visible {
119
- background: color-mix(in srgb, var(--primary-color), white 92%);
120
- }
121
- }
122
-
123
- .address-search-status {
124
- padding: 0.75rem;
125
- color: #686868;
126
- font-size: 0.85rem;
127
- }
128
-
129
- @keyframes address-search-spin {
130
- to {
131
- transform: rotate(360deg);
132
- }
133
- }
@@ -1,89 +0,0 @@
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();