kelt-ui-kit-react 2.0.0 → 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/src/form/form.css CHANGED
@@ -4,10 +4,12 @@ input {
4
4
  border-radius: 4px;
5
5
  margin: 0.25rem 0 0.25rem 0;
6
6
  min-width: 250px;
7
+
7
8
  &:focus-visible {
8
9
  outline: 1px solid #9696a7;
9
10
  }
10
11
  }
12
+
11
13
  input[type="checkbox"],
12
14
  input[type="radio"] {
13
15
  min-width: auto;
@@ -16,38 +18,59 @@ input[type="radio"] {
16
18
  height: 18px;
17
19
  width: 18px;
18
20
  }
21
+
19
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
+
20
36
  &.form-row {
21
37
  display: flex;
22
38
  flex-direction: row;
23
39
  flex-wrap: wrap;
24
40
  align-items: center;
41
+
25
42
  .form-group {
26
43
  margin-right: 1rem;
27
44
  flex: 1;
28
45
  padding: 0;
46
+
29
47
  .input-container {
30
48
  min-width: auto;
49
+
31
50
  input {
32
51
  min-width: auto;
33
52
  }
34
53
  }
35
54
  }
36
55
  }
56
+
37
57
  label {
38
58
  font-weight: 600;
39
59
  font-size: 0.85rem;
40
60
  padding-bottom: 0.15rem;
41
61
  }
62
+
42
63
  .form-group-checkbox {
43
64
  display: flex;
44
65
  flex-direction: row;
45
66
  align-items: center;
46
67
  margin-top: 0.5rem;
68
+
47
69
  label {
48
70
  margin-right: 1rem;
49
71
  padding: 0;
50
72
  }
73
+
51
74
  input {
52
75
  min-width: auto;
53
76
  padding: 0;
@@ -56,9 +79,11 @@ form {
56
79
  width: 18px;
57
80
  }
58
81
  }
82
+
59
83
  button {
60
84
  margin-top: 1rem;
61
85
  }
86
+
62
87
  .form-read-value {
63
88
  width: 100%;
64
89
  min-width: 250px;
@@ -67,13 +92,32 @@ form {
67
92
  border: 1px solid transparent;
68
93
  border-radius: 4px;
69
94
  margin: 0.25rem 0;
70
- padding: 0.5rem 1rem;
95
+ padding: 0;
71
96
  font-size: 0.8rem;
72
97
  line-height: normal;
73
98
  overflow-wrap: anywhere;
74
99
  }
100
+
75
101
  .form-read-value--textarea {
76
102
  min-height: 3.25rem;
77
103
  white-space: pre-wrap;
78
104
  }
79
- }
105
+
106
+ .grid-row {
107
+
108
+ .form-group,
109
+ .input-container,
110
+ .select-container,
111
+ .form-read-value {
112
+ min-width: 0;
113
+ }
114
+
115
+ input:not([type="checkbox"]):not([type="radio"]),
116
+ .form-control-textarea,
117
+ .form-read-value {
118
+ box-sizing: border-box;
119
+ min-width: 0;
120
+ width: 100%;
121
+ }
122
+ }
123
+ }
@@ -1,4 +1,5 @@
1
1
  export enum TypeInputEnum {
2
+ ADDRESS = "address",
2
3
  TEXT = "text",
3
4
  BUTTON = "button",
4
5
  EMAIL = "email",
@@ -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
+ }
@@ -10,6 +10,8 @@ type ColStyledProps = {
10
10
  $xl?: GridColumnSpan;
11
11
  };
12
12
  export const ColStyled = styled.div<ColStyledProps>`
13
+ box-sizing: border-box;
14
+ min-width: 0;
13
15
  padding: 0 15px;
14
16
  flex: 0 0 ${({ $xs }) => getColWidth($xs)};
15
17
  max-width: ${({ $xs }) => getColWidth($xs)};
@@ -18,7 +20,7 @@ export const ColStyled = styled.div<ColStyledProps>`
18
20
  ${({ $sm }) =>
19
21
  $sm &&
20
22
  css`
21
- @container (min-width: 576px) {
23
+ @media (min-width: 576px) {
22
24
  flex: 0 0 ${getColWidth($sm)};
23
25
  max-width: ${getColWidth($sm)};
24
26
  }
@@ -27,7 +29,7 @@ export const ColStyled = styled.div<ColStyledProps>`
27
29
  ${({ $md }) =>
28
30
  $md &&
29
31
  css`
30
- @container (min-width: 768px) {
32
+ @media (min-width: 768px) {
31
33
  flex: 0 0 ${getColWidth($md)};
32
34
  max-width: ${getColWidth($md)};
33
35
  }
@@ -36,7 +38,7 @@ export const ColStyled = styled.div<ColStyledProps>`
36
38
  ${({ $lg }) =>
37
39
  $lg &&
38
40
  css`
39
- @container (min-width: 992px) {
41
+ @media (min-width: 992px) {
40
42
  flex: 0 0 ${getColWidth($lg)};
41
43
  max-width: ${getColWidth($lg)};
42
44
  }
@@ -45,7 +47,7 @@ export const ColStyled = styled.div<ColStyledProps>`
45
47
  ${({ $xl }) =>
46
48
  $xl &&
47
49
  css`
48
- @container (min-width: 1200px) {
50
+ @media (min-width: 1200px) {
49
51
  flex: 0 0 ${getColWidth($xl)};
50
52
  max-width: ${getColWidth($xl)};
51
53
  }
@@ -1,7 +1,7 @@
1
1
  .grid-row {
2
2
  display: flex;
3
3
  flex-wrap: wrap;
4
- margin: 0 -15px;
4
+
5
5
  &.scroll {
6
6
  overflow-x: auto;
7
7
  flex-wrap: nowrap;
@@ -15,4 +15,4 @@
15
15
  flex-wrap: wrap;
16
16
  }
17
17
  }
18
- }
18
+ }
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";