kelt-ui-kit-react 2.0.9 → 2.1.0

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kelt-ui-kit-react",
3
3
  "type": "module",
4
- "version": "2.0.9",
4
+ "version": "2.1.0",
5
5
  "private": false,
6
6
  "repository": {
7
7
  "type": "git",
@@ -61,4 +61,4 @@
61
61
  "typescript": "^4.9.5",
62
62
  "vite-plugin-checker": "^0.8.0"
63
63
  }
64
- }
64
+ }
@@ -4,17 +4,11 @@ import { Icon } from "../../icon/Icon";
4
4
  import { IconSizeEnum } from "../../icon/iconSize.enum";
5
5
  import { MenuInterface } from "../../menus/menu/menu.interface";
6
6
  import { Menus } from "../../menus/Menus";
7
- import { OverlayPanel } from "../../overlayPanel/OverlayPanel";
7
+ import { OverlayPanel, PositionOverlay } from "../../overlayPanel/OverlayPanel";
8
8
  import { CardInterface } from "../card.interface";
9
9
  import { CardActionInterface } from "../cardAction.interface";
10
10
  import "./cardAction.css";
11
- export type PositionOverlay =
12
- | "left"
13
- | "right"
14
- | "topLeft"
15
- | "topRight"
16
- | "bottomLeft"
17
- | "bottomRight";
11
+ export type { PositionOverlay };
18
12
  export type CardActionProps = {
19
13
  actions: CardActionInterface[];
20
14
  item?: CardInterface;
@@ -22,6 +22,8 @@ export type {
22
22
  DataTableDateRangeFilterValue, DataTableFilterState, DataTableSortDirection,
23
23
  DataTableSortState, FilterValue,
24
24
  } from "./dataTable.utils";
25
+ const DEFAULT_FILTER_COLUMN_WIDTH = 100;
26
+
25
27
  export type DataTableProps<T> = {
26
28
  id: string;
27
29
  name?: string;
@@ -641,10 +643,13 @@ export function DataTable<T>(props: DataTableProps<T>) {
641
643
  {actions.length > 0 && <col style={{ width: actionsColumnWidth }} />}
642
644
  </colgroup>
643
645
  <thead>
644
- {tableState.visibleFilters.size > 0 && <tr ref={filterRowRef}>
646
+ {tableState.visibleFilters.size > 0 && <tr className="data-table-filter-row" ref={filterRowRef}>
645
647
  {onSelectionChange && <th />}
646
648
  {columns.map((column) => <th className="filter-row-cell" key={column.id}
647
- style={{ position: "sticky", top: 0, zIndex: 14, background: "#f9fbfc", minWidth: column.minWidth,
649
+ style={{ position: "sticky", top: 0, zIndex: 14, background: "#f9fbfc",
650
+ width: column.width ?? DEFAULT_FILTER_COLUMN_WIDTH,
651
+ minWidth: column.width ?? DEFAULT_FILTER_COLUMN_WIDTH,
652
+ maxWidth: column.width ?? DEFAULT_FILTER_COLUMN_WIDTH,
648
653
  ...(column.sticky ? { left: stickyOffsets.get(column.id) } : {}) }}>
649
654
  {tableState.renderFilter(column)}
650
655
  </th>)}
@@ -135,6 +135,102 @@
135
135
  color: var(--tertiary-color);
136
136
  min-width: 100px;
137
137
  padding: .5rem;
138
+
139
+ .data-table-column-filter,
140
+ .data-table-column-sort {
141
+ visibility: hidden;
142
+
143
+ &.active {
144
+ visibility: visible;
145
+ }
146
+ }
147
+
148
+ .data-table-column-filter-active,
149
+ .data-table-column-sort-active {
150
+ color: var(--tertiary-color);
151
+ }
152
+
153
+ &:hover,
154
+ &:focus-within {
155
+ .data-table-column-filter,
156
+ .data-table-column-sort {
157
+ visibility: visible;
158
+ }
159
+ }
160
+ }
161
+
162
+ .data-table-filter-row {
163
+ th {
164
+ padding-top: 6px;
165
+ padding-bottom: 6px;
166
+ overflow: visible;
167
+ }
168
+
169
+ .data-table-filter-select {
170
+ width: 100%;
171
+ max-width: 100%;
172
+
173
+ button {
174
+ width: 100%;
175
+ max-width: 100%;
176
+ overflow: hidden;
177
+ padding: 4px 6px;
178
+ border: 1px solid #dedede;
179
+ }
180
+
181
+ .select-container-value {
182
+ display: block;
183
+ min-width: 0;
184
+ overflow: hidden;
185
+ text-overflow: ellipsis;
186
+ white-space: nowrap;
187
+ font-size: 0.7rem;
188
+ }
189
+ }
190
+
191
+ .data-table-filter-input-wrapper {
192
+ width: 100%;
193
+ max-width: 100%;
194
+ overflow: visible;
195
+ box-sizing: border-box;
196
+
197
+ .input-clear-icon,
198
+ .input-clear-btn,
199
+ .clear-btn {
200
+ right: 5px;
201
+
202
+ .bi {
203
+ font-size: 0.8rem;
204
+ }
205
+ }
206
+
207
+ .input-container {
208
+ min-width: 0;
209
+ width: 100%;
210
+ }
211
+
212
+ .select-container,
213
+ .select-container-button {
214
+ max-width: 100%;
215
+ min-width: 0;
216
+ }
217
+ }
218
+
219
+ .data-table-filter-input {
220
+ width: 100%;
221
+ max-width: 100%;
222
+ min-width: 0;
223
+ box-sizing: border-box;
224
+ overflow: hidden;
225
+ text-overflow: ellipsis;
226
+ white-space: nowrap;
227
+ border: 1px solid #c9cfdb;
228
+ border-radius: 6px;
229
+ padding: 4px 6px;
230
+ font-size: 12px;
231
+ background-color: #fff;
232
+ color: #333;
233
+ }
138
234
  }
139
235
  }
140
236
 
@@ -214,7 +310,11 @@
214
310
  .data-table-column-heading {
215
311
  display: flex;
216
312
  align-items: center;
217
- gap: 8px;
313
+ gap: 4px;
314
+
315
+ > .flex-1 {
316
+ flex: 1;
317
+ }
218
318
  }
219
319
  .data-table-group-row th {
220
320
  height: 40px;
@@ -39,9 +39,9 @@ export const DataTableColumn = ({
39
39
  onClick={() => onColumnClick?.(column)}
40
40
  >
41
41
  <div className="data-table-column-heading">
42
- <span>{column.label}</span>
43
- {column.sortable && <DataTableColumnSort column={column} sortDirection={sortDirection} onToggleSort={onToggleSort} />}
42
+ <span className="flex-1">{column.label}</span>
44
43
  {column.filterable && <DataTableColumnFilter column={column} isFilterVisible={isFilterVisible} onToggleVisibility={onToggleFilter} />}
44
+ {column.sortable && <DataTableColumnSort column={column} sortDirection={sortDirection} onToggleSort={onToggleSort} />}
45
45
  </div>
46
46
  </th>
47
47
  );
@@ -60,6 +60,11 @@ export function useDataTableState<T>(
60
60
  }
61
61
 
62
62
  function renderFilter(column: dataTableColumnsInterface<T>) {
63
+ const control = renderFilterControl(column);
64
+ return control && <div className="data-table-filter-input-wrapper">{control}</div>;
65
+ }
66
+
67
+ function renderFilterControl(column: dataTableColumnsInterface<T>) {
63
68
  const key = getFilterKey(column);
64
69
  if (!column.filterable || !visibleFilters.has(key)) return null;
65
70
  const value = filters[key];
@@ -72,7 +77,7 @@ export function useDataTableState<T>(
72
77
  }
73
78
  if (column.filterType === TypeInputEnum.CHECKBOX || column.filterType === TypeInputEnum.RADIO) {
74
79
  return <Select id={inputId} options={column.filterDataEnum ?? []} multiple
75
- usePortal showOptions={focusKey === key}
80
+ className="data-table-filter-select" classNameOverlay="data-table-filter-select-overlay" usePortal showOptions={focusKey === key}
76
81
  value={String(value ?? "").split(",").filter(Boolean)}
77
82
  onChangeMultiple={(values) => updateFilter(key, values.join(","))}
78
83
  placeholder={`Filtrer ${column.label}`} />;
@@ -81,6 +86,7 @@ export function useDataTableState<T>(
81
86
  type={column.filterType === TypeInputEnum.DATE ? TypeInputEnum.DATE : TypeInputEnum.TEXT}
82
87
  value={String(value ?? "")} autoFocus={focusKey === key}
83
88
  disabledDebounce showClearButton placeholder={`Filtrer ${column.label}`}
89
+ className="data-table-filter-input"
84
90
  onClick={(event) => event.stopPropagation()}
85
91
  onChange={(event) => updateFilter(key, event.target.value)} />;
86
92
  }
@@ -20,6 +20,7 @@ export type PositionOverlay =
20
20
  | "right"
21
21
  | "topLeft"
22
22
  | "topRight"
23
+ | "bottom"
23
24
  | "bottomLeft"
24
25
  | "bottomRight";
25
26
 
@@ -107,6 +108,10 @@ export const OverlayPanel = forwardRef(
107
108
  top: rect.bottom,
108
109
  left: rect.left,
109
110
  }),
111
+ bottom: () => ({
112
+ top: rect.bottom,
113
+ left: rect.left + rect.width / 2 - boxRect.width / 2,
114
+ }),
110
115
  left: () => ({
111
116
  top: rect.top + rect.height / 2 - boxRect.height / 2,
112
117
  left: rect.left - boxRect.width,
@@ -122,7 +127,7 @@ export const OverlayPanel = forwardRef(
122
127
  ({ top, left } = positions[position]());
123
128
  // Manque d'espace en bas → afficher au-dessus de l'élément
124
129
  if (
125
- (position === "bottomLeft" || position === "bottomRight") &&
130
+ (position === "bottom" || position === "bottomLeft" || position === "bottomRight") &&
126
131
  top + boxRect.height > innerHeight &&
127
132
  rect.top - boxRect.height >= 0
128
133
  ) {
@@ -1,7 +1,7 @@
1
1
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2
2
  import { Icon } from "../icon/Icon";
3
3
 
4
- import { OverlayPanel } from "../overlayPanel/OverlayPanel";
4
+ import { OverlayPanel, PositionOverlay } from "../overlayPanel/OverlayPanel";
5
5
  import "./select.css";
6
6
  import { SelectOptionInterface } from "./selectOption.interface";
7
7
 
@@ -26,6 +26,7 @@ export interface SelectProps {
26
26
  onChange?: (value: string) => void;
27
27
  placeholder?: string;
28
28
  classNameOverlay?: string;
29
+ positionOverlay?: PositionOverlay;
29
30
  }
30
31
 
31
32
  export const Select = ({
@@ -46,6 +47,7 @@ export const Select = ({
46
47
  value,
47
48
  placeholder,
48
49
  classNameOverlay,
50
+ positionOverlay = "bottomLeft",
49
51
  }: SelectProps): JSX.Element => {
50
52
  const [showOverlay, setShowOverlay] = useState(false);
51
53
  const [overlayRef, setOverlayRef] = useState<HTMLElement | null>(null);
@@ -175,7 +177,7 @@ export const Select = ({
175
177
  {showOverlay && overlayRef && (
176
178
  <OverlayPanel
177
179
  show={showOverlay}
178
- position="bottomLeft"
180
+ position={positionOverlay}
179
181
  className={classNameOverlay ?? ""}
180
182
  closeOverlay={() => setShowOverlay(false)}
181
183
  referenceElement={overlayRef}