kelt-ui-kit-react 2.0.3 → 2.0.4

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 +26 -0
  2. package/dist/addressSearch/AddressSearch.d.ts +20 -0
  3. package/dist/addressSearch/AddressSearch.view.d.ts +1 -0
  4. package/dist/badge/Badge.d.ts +1 -3
  5. package/dist/button/Button.d.ts +1 -1
  6. package/dist/button/button.interface.d.ts +2 -1
  7. package/dist/card/Card.d.ts +4 -1
  8. package/dist/dataTable/DataTable.d.ts +14 -17
  9. package/dist/dataTable/dataTable.interface.d.ts +19 -24
  10. package/dist/dataTable/dataTableActions/DataTableAction.d.ts +5 -3
  11. package/dist/dataTable/dataTableColumn/DataTableColumn.d.ts +7 -13
  12. package/dist/dataTable/dataTableLoading/DataTableLoading.d.ts +3 -1
  13. package/dist/dataTable/dataTableRow/DataTableRow.d.ts +6 -5
  14. package/dist/expands/Expands.d.ts +1 -0
  15. package/dist/expands/expand/expand.d.ts +3 -2
  16. package/dist/form/Form.d.ts +10 -2
  17. package/dist/form/form.enum.d.ts +3 -2
  18. package/dist/form/form.interface.d.ts +22 -3
  19. package/dist/form/input/Input.d.ts +0 -3
  20. package/dist/form/inputNumber/InputNumber.d.ts +2 -0
  21. package/dist/geocoding/GeocodingService.d.ts +13 -0
  22. package/dist/geocoding/geocoding.interface.d.ts +20 -0
  23. package/dist/grid/Grid.d.ts +5 -2
  24. package/dist/grid/col/Col.d.ts +3 -6
  25. package/dist/grid/col/colStyled/ColStyled.d.ts +8 -5
  26. package/dist/grid/grid.interface.d.ts +20 -5
  27. package/dist/grid/row/Row.d.ts +7 -0
  28. package/dist/header/Header.d.ts +1 -1
  29. package/dist/header/header.interface.d.ts +2 -1
  30. package/dist/icon/Icon.d.ts +1 -1
  31. package/dist/icon/icon.interface.d.ts +0 -1
  32. package/dist/index.d.ts +5 -1
  33. package/dist/index.js +3724 -3628
  34. package/dist/menus/menu/Menu.d.ts +1 -0
  35. package/dist/select/Select.d.ts +2 -1
  36. package/dist/style.css +1 -1
  37. package/dist/tabs/Tabs.d.ts +1 -2
  38. package/dist/toaster/store/useToasterStore.d.ts +1 -0
  39. package/index.html +1 -2
  40. package/package.json +1 -1
  41. package/src/App.menu.tsx +8 -0
  42. package/src/addressSearch/AddressSearch.tsx +246 -0
  43. package/src/addressSearch/AddressSearch.view.tsx +52 -0
  44. package/src/addressSearch/addressSearch.css +133 -0
  45. package/src/badge/Badge.tsx +1 -9
  46. package/src/badge/badge.css +0 -4
  47. package/src/button/Button.tsx +3 -1
  48. package/src/button/button.css +2 -2
  49. package/src/button/button.interface.tsx +2 -1
  50. package/src/card/Card.tsx +37 -11
  51. package/src/card/card.css +7 -28
  52. package/src/card/cardAction/CardAction.tsx +4 -4
  53. package/src/damier/Damier.tsx +16 -7
  54. package/src/damier/damier.css +11 -4
  55. package/src/dataTable/DataTable.tsx +542 -685
  56. package/src/dataTable/DataTable.view.tsx +24 -48
  57. package/src/dataTable/dataTable.css +159 -134
  58. package/src/dataTable/dataTable.interface.ts +19 -25
  59. package/src/dataTable/dataTableActions/DataTableAction.tsx +25 -14
  60. package/src/dataTable/dataTableColumn/DataTableColumn.tsx +14 -64
  61. package/src/dataTable/dataTableLoading/DataTableLoading.tsx +15 -4
  62. package/src/dataTable/dataTableRow/DataTableRow.tsx +180 -64
  63. package/src/expands/Expands.tsx +18 -2
  64. package/src/expands/expand/expand.tsx +128 -5
  65. package/src/expands/expands.css +8 -3
  66. package/src/form/Form.tsx +294 -99
  67. package/src/form/Form.view.tsx +9 -1
  68. package/src/form/form.css +64 -1
  69. package/src/form/form.enum.ts +2 -1
  70. package/src/form/form.interface.tsx +31 -3
  71. package/src/form/input/Input.tsx +7 -61
  72. package/src/form/input/input.css +1 -19
  73. package/src/form/inputNumber/InputNumber.tsx +11 -6
  74. package/src/form/inputPrice/InputPrice.tsx +4 -2
  75. package/src/geocoding/GeocodingService.ts +89 -0
  76. package/src/geocoding/geocoding.interface.ts +25 -0
  77. package/src/grid/Grid.tsx +34 -21
  78. package/src/grid/col/Col.tsx +24 -15
  79. package/src/grid/col/col.css +3 -0
  80. package/src/grid/col/colStyled/ColStyled.tsx +59 -41
  81. package/src/grid/container/container.css +2 -2
  82. package/src/grid/grid.interface.tsx +25 -5
  83. package/src/grid/row/Row.tsx +49 -12
  84. package/src/grid/row/row.css +11 -3
  85. package/src/header/Header.tsx +4 -2
  86. package/src/header/header.css +17 -0
  87. package/src/header/header.interface.tsx +2 -1
  88. package/src/icon/Icon.tsx +2 -6
  89. package/src/icon/icon.interface.tsx +0 -1
  90. package/src/index.css +58 -12
  91. package/src/index.ts +12 -2
  92. package/src/menus/Menus.tsx +1 -0
  93. package/src/menus/menu/Menu.tsx +2 -1
  94. package/src/select/Select.tsx +5 -3
  95. package/src/sidebar/Sidebar.tsx +107 -5
  96. package/src/sidebar/sidebar.css +18 -1
  97. package/src/tabs/Tabs.tsx +1 -20
  98. package/src/tabs/tabs.css +9 -3
  99. package/src/toaster/Toaster.tsx +7 -2
  100. package/src/toaster/Toaster.view.tsx +1 -0
  101. package/src/toaster/store/useToasterStore.tsx +2 -0
  102. package/src/toaster/toaster.css +7 -2
  103. package/dist/_core/type/generiqueType.d.ts +0 -4
  104. package/dist/dataTable/dataTableColumn/dataTableColumnFilter/DataTableColumnFilter.d.ts +0 -10
  105. package/dist/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterDate/DataTableColumnFilterDate.d.ts +0 -9
  106. package/dist/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterDateRange/dataTableColumnFilterDateRange.d.ts +0 -9
  107. package/dist/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterEnum/DataTableColumnFilterEnum.d.ts +0 -13
  108. package/dist/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterString/DataTableColumnFilterString.d.ts +0 -9
  109. package/dist/dataTable/dataTableColumn/dataTableColumnSort/DataTableColumnSort.d.ts +0 -11
  110. package/dist/dataTable/dataTableFilters/DataTableFilters.d.ts +0 -7
  111. package/dist/dataTable/dataTableRow/dataTableRowOverlay/DataTableRowOverlay.d.ts +0 -12
  112. package/dist/dataTable/dataTableRow/dataTableRowValue/DataTableRowValue.d.ts +0 -11
  113. package/package/package.json +0 -56
  114. package/package/src/sidebar/Sidebar.tsx +0 -208
  115. package/package/src/sidebar/sidebar.css +0 -104
  116. package/src/_core/type/generiqueType.tsx +0 -4
  117. package/src/dataTable/dataTableColumn/dataTableColumnFilter/DataTableColumnFilter.tsx +0 -36
  118. package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilter.css +0 -0
  119. package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterDate/DataTableColumnFilterDate.tsx +0 -39
  120. package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterDateRange/dataTableColumnFilterDateRange.tsx +0 -80
  121. package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterEnum/DataTableColumnFilterEnum.tsx +0 -89
  122. package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterString/DataTableColumnFilterString.tsx +0 -37
  123. package/src/dataTable/dataTableColumn/dataTableColumnSort/DataTableColumnSort.tsx +0 -42
  124. package/src/dataTable/dataTableFilters/DataTableFilters.tsx +0 -91
  125. package/src/dataTable/dataTableFilters/dataTableFilters.css +0 -16
  126. package/src/dataTable/dataTableRow/dataTableRowOverlay/DataTableRowOverlay.tsx +0 -80
  127. package/src/dataTable/dataTableRow/dataTableRowValue/DataTableRowValue.tsx +0 -123
@@ -14,6 +14,5 @@ export type TabsProps = {
14
14
  className?: string;
15
15
  tabClassName?: string;
16
16
  panelClassName?: string;
17
- keepMountedVisited?: boolean;
18
17
  };
19
- export declare const Tabs: ({ items, defaultIndex, index, onChange, className, tabClassName, panelClassName, keepMountedVisited, }: TabsProps) => import("react/jsx-runtime").JSX.Element;
18
+ export declare const Tabs: ({ items, defaultIndex, index, onChange, className, tabClassName, panelClassName, }: TabsProps) => import("react/jsx-runtime").JSX.Element;
@@ -12,6 +12,7 @@ type ToasterState = {
12
12
  severity?: "info" | "success" | "error" | "warning";
13
13
  duration?: number;
14
14
  children?: React.ReactNode;
15
+ close?: boolean;
15
16
  }) => void;
16
17
  hideToast: () => void;
17
18
  };
package/index.html CHANGED
@@ -5,8 +5,7 @@
5
5
  <meta charset="UTF-8" />
6
6
  <link rel="preconnect" href="https://fonts.googleapis.com">
7
7
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
8
- <link href="https://fonts.googleapis.com/css2?family=Raleway:ital,wght@0,100..900;1,100..900&display=swap"
9
- rel="stylesheet">
8
+ <link href="https://fonts.googleapis.com/css2?family=Lexend:wght@100..900&display=swap" rel="stylesheet">
10
9
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
11
10
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
12
11
  <title>Vite + React + TS</title>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kelt-ui-kit-react",
3
3
  "type": "module",
4
- "version": "2.0.3",
4
+ "version": "2.0.4",
5
5
  "private": false,
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
package/src/App.menu.tsx CHANGED
@@ -1,5 +1,6 @@
1
1
  import { NavLink } from "react-router-dom";
2
2
  import { ActionView } from "./action/Action.view";
3
+ import { AddressSearchView } from "./addressSearch/AddressSearch.view";
3
4
  import { BadgeView } from "./badge/Badge.view";
4
5
  import { ButtonView } from "./button/Button.view";
5
6
  import { ButtonFileView } from "./button/buttonFile/ButtonFile.view";
@@ -242,6 +243,13 @@ export const MenuList: MenuProps[] = [
242
243
  children: <NavLink to="/button-file">Button File</NavLink>,
243
244
  element: <ButtonFileView />,
244
245
  },
246
+ {
247
+ id: 30,
248
+ name: "Address search",
249
+ link: "/address-search",
250
+ children: <NavLink to="/address-search">Address search</NavLink>,
251
+ element: <AddressSearchView />,
252
+ },
245
253
  ];
246
254
 
247
255
  export const AppMenu = (): JSX.Element => {
@@ -0,0 +1,246 @@
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
+ };
@@ -0,0 +1,52 @@
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
+ };
@@ -0,0 +1,133 @@
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
+ }
@@ -6,17 +6,13 @@ export type BadgeInterface = {
6
6
  className?: string;
7
7
  onClick?: (e: React.MouseEvent) => void;
8
8
  title?: string;
9
- color?: string;
10
- onRemove?: (e: React.MouseEvent) => void;
11
9
  sizeIcon?: IconSizeEnum;
12
10
  classIcon?: string;
13
11
  };
14
12
  export const Badge = ({
15
13
  className,
16
14
  onClick,
17
- color,
18
15
  title,
19
- onRemove,
20
16
  sizeIcon,
21
17
  classIcon,
22
18
  }: BadgeInterface) => {
@@ -29,14 +25,10 @@ export const Badge = ({
29
25
  return (
30
26
  <div
31
27
  onClick={handleClick}
32
- style={{
33
- ...(color ? { backgroundColor: color } : {}),
34
- }}
35
- className={`badge ${className ? className : ""} ${onRemove && "cursor-pointer"}`}
28
+ className={`badge ${className ? className : ""}`}
36
29
  >
37
30
  {classIcon && <Icon size={sizeIcon} classIcon={classIcon}></Icon>}
38
31
  <span>{title}</span>
39
- {onRemove && <Icon classIcon="bi-x" onClick={onRemove} />}
40
32
  </div>
41
33
  );
42
34
  };
@@ -15,10 +15,6 @@
15
15
  font-size: 0.8rem;
16
16
  margin-right: 0.25rem;
17
17
  }
18
- .bi-x {
19
- font-size: 1rem;
20
- margin-right: 0;
21
- }
22
18
  &.badge-primary {
23
19
  background-color: var(--primary-color);
24
20
  border-color: var(--primary-color);
@@ -13,8 +13,9 @@ export const Button = ({
13
13
  classIcon,
14
14
  positionicon = 1,
15
15
  disabled = false,
16
+ style,
16
17
  }: ButtonInterface) => {
17
- const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
18
+ const handleClick = (e: React.MouseEvent) => {
18
19
  e.stopPropagation();
19
20
  if (onClick) {
20
21
  onClick(e);
@@ -28,6 +29,7 @@ export const Button = ({
28
29
  type="submit"
29
30
  onClick={(e) => handleClick(e)}
30
31
  className={className}
32
+ style={style}
31
33
  >
32
34
  {badge && <Badge {...badge} />}
33
35
  {classIcon && positionicon == 1 && (
@@ -5,7 +5,7 @@ button {
5
5
  padding: 10px;
6
6
  border-radius: 5px;
7
7
  cursor: pointer;
8
- font-size: 16px;
8
+ font-size: 18px;
9
9
  font-weight: 500;
10
10
  transition: background-color 0.3s;
11
11
  display: flex;
@@ -14,7 +14,7 @@ button {
14
14
  position: relative;
15
15
  align-items: center;
16
16
  justify-content: center;
17
- font-family: "Raleway", sans-serif !important;
17
+ font-family: "Lexend", sans-serif;
18
18
  .badge {
19
19
  position: absolute;
20
20
  right: 10px;
@@ -5,12 +5,13 @@ export interface ButtonInterface {
5
5
  className?: string;
6
6
  badge?: BadgeInterface;
7
7
  id?: string;
8
- onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
8
+ onClick?: (e: React.MouseEvent) => void;
9
9
  title: string;
10
10
  classIcon?: string;
11
11
  positionicon?: number;
12
12
  disabled?: boolean;
13
13
  sizeIcon?: IconSizeEnum;
14
+ style?: React.CSSProperties;
14
15
  }
15
16
  export interface buttonActionInterface {
16
17
  icon?: string;
package/src/card/Card.tsx CHANGED
@@ -1,10 +1,12 @@
1
- import { useCallback, useState } from "react";
1
+ import { useCallback, useMemo, useState } from "react";
2
2
  import { Icon } from "../icon/Icon";
3
3
  import { PositionOverlay } from "../overlayPanel/OverlayPanel";
4
4
  import "./card.css";
5
5
  import { CardInterface } from "./card.interface";
6
6
  import { CardActionInterface } from "./cardAction.interface";
7
7
  import { CardAction } from "./cardAction/CardAction";
8
+ import { GridInterface, GridResponsive } from "../grid/grid.interface";
9
+ import { Grid } from "../grid/Grid";
8
10
  type CardProps = {
9
11
  item: CardInterface;
10
12
  actions?: CardActionInterface[];
@@ -14,6 +16,8 @@ type CardProps = {
14
16
  children?: JSX.Element;
15
17
  customAction?: JSX.Element;
16
18
  positionOverlay?: PositionOverlay;
19
+ /** Largeur sur laquelle se basent les breakpoints du footer, défaut : "app" */
20
+ responsive?: GridResponsive;
17
21
  };
18
22
 
19
23
  // Composant Card modifié
@@ -25,6 +29,7 @@ export const Card = ({
25
29
  onClose,
26
30
  customAction,
27
31
  positionOverlay,
32
+ responsive = "app",
28
33
  children,
29
34
  }: CardProps): JSX.Element => {
30
35
  const [cliqueAction, setCliqueAction] = useState(false);
@@ -69,14 +74,38 @@ export const Card = ({
69
74
  cliqueAction,
70
75
  ]
71
76
  );
77
+ const customeActionGrid: GridInterface[] = useMemo(() => {
78
+ return customAction ? [
79
+ {
80
+ xs: 12,
81
+ md: 6,
82
+ children: (
83
+ <div className="card-custom-action">{customAction}</div>
84
+ ),
85
+ }
86
+ ] : [];
87
+ }, [customAction]);
72
88
 
89
+ const footerGrid: GridInterface[] = useMemo(() => {
90
+ return [
91
+ ...customeActionGrid,
92
+ {
93
+ xs: 12,
94
+ md: customAction ? 6 : 12,
95
+ children: (
96
+ <div className="d-flex flex-1 align-items-center">
97
+ {item.prix && <div className="card-prix">{item.prix}</div>}
98
+ </div>
99
+ ),
100
+ },
101
+ ];
102
+ }, [customAction, item.prix]);
73
103
  return (
74
104
  <div
75
105
  onContextMenu={(e) => e.preventDefault()}
76
106
  onMouseDown={(e) => onClickCard(e, item)}
77
- className={`card ${className ?? ""} ${
78
- cliqueAction ? "card--active" : ""
79
- } `}
107
+ className={`card ${className ?? ""} ${cliqueAction ? "card--active" : ""
108
+ } `}
80
109
  >
81
110
  {children}
82
111
  {!children && (
@@ -92,14 +121,11 @@ export const Card = ({
92
121
  <div className="card-content">{item.description}</div>
93
122
  )}
94
123
  </div>
95
- <div className="card-footer">
96
- {customAction && (
97
- <div className="card-custom-action">{customAction}</div>
98
- )}
99
- <div className="d-flex flex-1 align-items-center">
100
- {item.prix && <div className="card-prix">{item.prix}</div>}
124
+ {footerGrid.length > 0 && (
125
+ <div className="card-footer">
126
+ <Grid items={footerGrid} responsive={responsive} />
101
127
  </div>
102
- </div>
128
+ )}
103
129
  {onClose && (
104
130
  <div
105
131
  className="ml-2 cursor-pointer"