@dragunio/fe-libs 0.1.2 → 0.1.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.
- package/README.md +51 -14
- package/dist/index.d.mts +234 -5
- package/dist/index.d.ts +234 -5
- package/dist/index.js +656 -160
- package/dist/index.mjs +622 -140
- package/dist/styles.css +669 -10
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -22,15 +22,27 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
Button: () => Button,
|
|
24
24
|
ChevronDownIcon: () => ChevronDownIcon,
|
|
25
|
+
Chip: () => Chip,
|
|
25
26
|
CloseIcon: () => CloseIcon,
|
|
26
27
|
CurrencyInput: () => CurrencyInput,
|
|
27
28
|
DateTimePicker: () => DateTimePicker,
|
|
28
29
|
Drawer: () => Drawer,
|
|
29
30
|
ExpandableSection: () => ExpandableSection,
|
|
31
|
+
Loading: () => Loading,
|
|
32
|
+
Message: () => Message,
|
|
33
|
+
Modal: () => Modal,
|
|
30
34
|
NumberInput: () => NumberInput,
|
|
35
|
+
Pagination: () => Pagination,
|
|
31
36
|
PlusIcon: () => PlusIcon,
|
|
37
|
+
ProgressBar: () => ProgressBar,
|
|
32
38
|
SearchIcon: () => SearchIcon,
|
|
33
39
|
Selection: () => Selection,
|
|
40
|
+
Skeleton: () => Skeleton,
|
|
41
|
+
SkeletonBox: () => SkeletonBox,
|
|
42
|
+
SkeletonCircle: () => SkeletonCircle,
|
|
43
|
+
SkeletonLine: () => SkeletonLine,
|
|
44
|
+
SkeletonSquare: () => SkeletonSquare,
|
|
45
|
+
Snackbar: () => Snackbar,
|
|
34
46
|
Table: () => Table,
|
|
35
47
|
TableBody: () => TableBody,
|
|
36
48
|
TableCaption: () => TableCaption,
|
|
@@ -38,10 +50,13 @@ __export(index_exports, {
|
|
|
38
50
|
TableHead: () => TableHead,
|
|
39
51
|
TableHeader: () => TableHeader,
|
|
40
52
|
TableRow: () => TableRow,
|
|
53
|
+
TextArea: () => TextArea,
|
|
54
|
+
TextInput: () => TextInput,
|
|
41
55
|
Toggle: () => Toggle,
|
|
42
56
|
Tooltip: () => Tooltip,
|
|
43
57
|
formatNumber: () => formatNumber,
|
|
44
|
-
getIconSize: () => getIconSize
|
|
58
|
+
getIconSize: () => getIconSize,
|
|
59
|
+
message: () => message
|
|
45
60
|
});
|
|
46
61
|
module.exports = __toCommonJS(index_exports);
|
|
47
62
|
|
|
@@ -138,9 +153,76 @@ function SearchIcon(props) {
|
|
|
138
153
|
}
|
|
139
154
|
|
|
140
155
|
// packages/table/src/index.tsx
|
|
156
|
+
var import_react3 = require("react");
|
|
157
|
+
|
|
158
|
+
// packages/pagination/src/index.tsx
|
|
141
159
|
var import_react2 = require("react");
|
|
142
160
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
143
|
-
var
|
|
161
|
+
var clamp = (value, min, max) => Math.min(Math.max(value, min), max);
|
|
162
|
+
var range = (start, end) => Array.from({ length: Math.max(0, end - start + 1) }, (_, index) => start + index);
|
|
163
|
+
function getItems(totalPages, page, siblingCount, boundaryCount) {
|
|
164
|
+
const visibleCount = boundaryCount * 2 + siblingCount * 2 + 3;
|
|
165
|
+
if (totalPages <= visibleCount) return range(1, totalPages);
|
|
166
|
+
const startPages = range(1, boundaryCount);
|
|
167
|
+
const endPages = range(totalPages - boundaryCount + 1, totalPages);
|
|
168
|
+
const siblingsStart = Math.max(Math.min(page - siblingCount, totalPages - boundaryCount - siblingCount * 2 - 1), boundaryCount + 2);
|
|
169
|
+
const siblingsEnd = Math.min(Math.max(page + siblingCount, boundaryCount + siblingCount * 2 + 2), totalPages - boundaryCount - 1);
|
|
170
|
+
return [
|
|
171
|
+
...startPages,
|
|
172
|
+
...siblingsStart > boundaryCount + 2 ? ["start-ellipsis"] : siblingsStart === boundaryCount + 2 ? [boundaryCount + 1] : [],
|
|
173
|
+
...range(siblingsStart, siblingsEnd),
|
|
174
|
+
...siblingsEnd < totalPages - boundaryCount - 1 ? ["end-ellipsis"] : siblingsEnd === totalPages - boundaryCount - 1 ? [totalPages - boundaryCount] : [],
|
|
175
|
+
...endPages
|
|
176
|
+
];
|
|
177
|
+
}
|
|
178
|
+
function Pagination({
|
|
179
|
+
page,
|
|
180
|
+
defaultPage = 1,
|
|
181
|
+
totalPages,
|
|
182
|
+
onPageChange,
|
|
183
|
+
siblingCount = 1,
|
|
184
|
+
boundaryCount = 1,
|
|
185
|
+
disabled = false,
|
|
186
|
+
previousLabel = "Previous page",
|
|
187
|
+
nextLabel = "Next page",
|
|
188
|
+
className,
|
|
189
|
+
...props
|
|
190
|
+
}) {
|
|
191
|
+
const safeTotalPages = Math.max(1, Math.floor(totalPages));
|
|
192
|
+
const [uncontrolledPage, setUncontrolledPage] = (0, import_react2.useState)(() => clamp(defaultPage, 1, safeTotalPages));
|
|
193
|
+
const currentPage = clamp(page ?? uncontrolledPage, 1, safeTotalPages);
|
|
194
|
+
const items = (0, import_react2.useMemo)(
|
|
195
|
+
() => getItems(safeTotalPages, currentPage, Math.max(0, siblingCount), Math.max(0, boundaryCount)),
|
|
196
|
+
[safeTotalPages, currentPage, siblingCount, boundaryCount]
|
|
197
|
+
);
|
|
198
|
+
const selectPage = (nextPage) => {
|
|
199
|
+
const resolvedPage = clamp(nextPage, 1, safeTotalPages);
|
|
200
|
+
if (page === void 0) setUncontrolledPage(resolvedPage);
|
|
201
|
+
if (resolvedPage !== currentPage) onPageChange?.(resolvedPage);
|
|
202
|
+
};
|
|
203
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("nav", { className: ["fe-pagination", className].filter(Boolean).join(" "), "aria-label": "Pagination", ...props, children: [
|
|
204
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { className: "fe-pagination__button fe-pagination__button--control", hierarchy: "secondary-gray", size: "40", iconOnly: true, icon: "\u2039", "aria-label": previousLabel, disabled: disabled || currentPage === 1, onClick: () => selectPage(currentPage - 1) }),
|
|
205
|
+
items.map((item, index) => item === "start-ellipsis" || item === "end-ellipsis" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fe-pagination__ellipsis", "aria-hidden": "true", children: "\u2026" }, `${item}-${index}`) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
206
|
+
Button,
|
|
207
|
+
{
|
|
208
|
+
className: "fe-pagination__button",
|
|
209
|
+
hierarchy: item === currentPage ? "primary" : "secondary-gray",
|
|
210
|
+
size: "40",
|
|
211
|
+
"aria-label": `Page ${item}`,
|
|
212
|
+
"aria-current": item === currentPage ? "page" : void 0,
|
|
213
|
+
disabled,
|
|
214
|
+
onClick: () => selectPage(item),
|
|
215
|
+
children: item
|
|
216
|
+
},
|
|
217
|
+
item
|
|
218
|
+
)),
|
|
219
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { className: "fe-pagination__button fe-pagination__button--control", hierarchy: "secondary-gray", size: "40", iconOnly: true, icon: "\u203A", "aria-label": nextLabel, disabled: disabled || currentPage === safeTotalPages, onClick: () => selectPage(currentPage + 1) })
|
|
220
|
+
] });
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// packages/table/src/index.tsx
|
|
224
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
225
|
+
var TableContext = (0, import_react3.createContext)({ striped: false });
|
|
144
226
|
var MIN_COLUMN_WIDTH = 96;
|
|
145
227
|
var MAX_COLUMN_WIDTH = 1200;
|
|
146
228
|
function getColumnCount(headers, data) {
|
|
@@ -149,7 +231,7 @@ function getColumnCount(headers, data) {
|
|
|
149
231
|
function getText(value) {
|
|
150
232
|
if (typeof value === "string" || typeof value === "number") return String(value);
|
|
151
233
|
if (Array.isArray(value)) return value.map(getText).join("");
|
|
152
|
-
if ((0,
|
|
234
|
+
if ((0, import_react3.isValidElement)(value)) return getText(value.props.children);
|
|
153
235
|
return "";
|
|
154
236
|
}
|
|
155
237
|
function autoColumnSize(columnIndex, headers, data) {
|
|
@@ -157,9 +239,9 @@ function autoColumnSize(columnIndex, headers, data) {
|
|
|
157
239
|
const longestText = values.reduce((longest, value) => Math.max(longest, getText(value).length), 0);
|
|
158
240
|
return Math.min(MAX_COLUMN_WIDTH, Math.max(MIN_COLUMN_WIDTH, longestText * 8 + 40));
|
|
159
241
|
}
|
|
160
|
-
function getInitialColumnSizes(headers, data,
|
|
242
|
+
function getInitialColumnSizes(headers, data, sizes2, minColumnWidth = MIN_COLUMN_WIDTH) {
|
|
161
243
|
return Array.from({ length: getColumnCount(headers, data) }, (_, columnIndex) => {
|
|
162
|
-
const suppliedSize =
|
|
244
|
+
const suppliedSize = sizes2?.[columnIndex];
|
|
163
245
|
return typeof suppliedSize === "number" && Number.isFinite(suppliedSize) ? Math.min(MAX_COLUMN_WIDTH, Math.max(minColumnWidth, suppliedSize)) : autoColumnSize(columnIndex, headers, data);
|
|
164
246
|
});
|
|
165
247
|
}
|
|
@@ -174,33 +256,48 @@ function DataTable({
|
|
|
174
256
|
columnSizes,
|
|
175
257
|
onColumnResize,
|
|
176
258
|
minColumnWidth = MIN_COLUMN_WIDTH,
|
|
259
|
+
pagination,
|
|
260
|
+
pageSize,
|
|
261
|
+
page,
|
|
262
|
+
defaultPage = 1,
|
|
263
|
+
onPageChange,
|
|
264
|
+
paginationPosition = "bottom-right",
|
|
177
265
|
className,
|
|
178
266
|
...props
|
|
179
267
|
}) {
|
|
180
268
|
const columnCount = getColumnCount(headers, data);
|
|
181
269
|
const safeMinWidth = Math.max(1, minColumnWidth);
|
|
182
|
-
const generatedSizes = (0,
|
|
270
|
+
const generatedSizes = (0, import_react3.useMemo)(
|
|
183
271
|
() => getInitialColumnSizes(headers, data, defaultColumnSizes, safeMinWidth),
|
|
184
272
|
[headers, data, defaultColumnSizes, safeMinWidth]
|
|
185
273
|
);
|
|
186
|
-
const [uncontrolledSizes, setUncontrolledSizes] = (0,
|
|
187
|
-
const
|
|
188
|
-
const
|
|
189
|
-
const
|
|
190
|
-
(0,
|
|
274
|
+
const [uncontrolledSizes, setUncontrolledSizes] = (0, import_react3.useState)(generatedSizes);
|
|
275
|
+
const shouldPaginate = pagination ?? pageSize !== void 0;
|
|
276
|
+
const safePageSize = Math.max(1, Math.floor(pageSize ?? 10));
|
|
277
|
+
const totalPages = Math.max(1, Math.ceil(data.length / safePageSize));
|
|
278
|
+
const [uncontrolledPage, setUncontrolledPage] = (0, import_react3.useState)(() => Math.min(Math.max(1, defaultPage), totalPages));
|
|
279
|
+
const currentPage = Math.min(Math.max(1, page ?? uncontrolledPage), totalPages);
|
|
280
|
+
const pagedData = shouldPaginate ? data.slice((currentPage - 1) * safePageSize, currentPage * safePageSize) : data;
|
|
281
|
+
const resizeState = (0, import_react3.useRef)();
|
|
282
|
+
const [isResizing, setIsResizing] = (0, import_react3.useState)(false);
|
|
283
|
+
const sizes2 = columnSizes ? getInitialColumnSizes(headers, data, columnSizes, safeMinWidth).map((size) => Math.max(safeMinWidth, size)) : uncontrolledSizes.map((size) => Math.max(safeMinWidth, size));
|
|
284
|
+
(0, import_react3.useEffect)(() => {
|
|
191
285
|
if (columnSizes) return;
|
|
192
286
|
setUncontrolledSizes((currentSizes) => {
|
|
193
287
|
const nextSizes = generatedSizes.map((generatedSize, index) => currentSizes[index] ?? generatedSize);
|
|
194
288
|
return sameSizes(currentSizes, nextSizes) ? currentSizes : nextSizes;
|
|
195
289
|
});
|
|
196
290
|
}, [columnSizes, generatedSizes]);
|
|
197
|
-
|
|
291
|
+
(0, import_react3.useEffect)(() => {
|
|
292
|
+
if (page === void 0 && uncontrolledPage > totalPages) setUncontrolledPage(totalPages);
|
|
293
|
+
}, [page, totalPages, uncontrolledPage]);
|
|
294
|
+
const updateColumnSize = (0, import_react3.useCallback)((columnIndex, nextSize) => {
|
|
198
295
|
const clampedSize = Math.min(MAX_COLUMN_WIDTH, Math.max(safeMinWidth, Math.round(nextSize)));
|
|
199
|
-
const nextSizes =
|
|
296
|
+
const nextSizes = sizes2.map((size, index) => index === columnIndex ? clampedSize : size);
|
|
200
297
|
if (!columnSizes) setUncontrolledSizes(nextSizes);
|
|
201
298
|
onColumnResize?.(nextSizes, columnIndex);
|
|
202
|
-
}, [columnSizes, onColumnResize, safeMinWidth,
|
|
203
|
-
(0,
|
|
299
|
+
}, [columnSizes, onColumnResize, safeMinWidth, sizes2]);
|
|
300
|
+
(0, import_react3.useEffect)(() => {
|
|
204
301
|
const onPointerMove = (event) => {
|
|
205
302
|
const activeResize = resizeState.current;
|
|
206
303
|
if (!activeResize) return;
|
|
@@ -219,84 +316,106 @@ function DataTable({
|
|
|
219
316
|
window.removeEventListener("pointercancel", stopResizing);
|
|
220
317
|
};
|
|
221
318
|
}, [updateColumnSize]);
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
"
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
319
|
+
const changePage = (nextPage) => {
|
|
320
|
+
if (page === void 0) setUncontrolledPage(nextPage);
|
|
321
|
+
if (nextPage !== currentPage) onPageChange?.(nextPage);
|
|
322
|
+
};
|
|
323
|
+
const resolvedPaginationPosition = paginationPosition === "middle-bottom" ? "bottom-center" : paginationPosition;
|
|
324
|
+
const paginationControl = shouldPaginate && totalPages > 1 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: `fe-table__pagination fe-table__pagination--${resolvedPaginationPosition}`, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Pagination, { page: currentPage, totalPages, onPageChange: changePage }) }) : null;
|
|
325
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "fe-table", "data-resizing": isResizing || void 0, children: [
|
|
326
|
+
resolvedPaginationPosition === "top-right" && paginationControl,
|
|
327
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("table", { className: ["fe-table__table", className].filter(Boolean).join(" "), "data-fe-table": true, "data-striped": striped || void 0, ...props, children: [
|
|
328
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("colgroup", { children: sizes2.map((size, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("col", { style: { width: `${size}px` } }, index)) }),
|
|
329
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tr", { children: Array.from({ length: columnCount }, (_, columnIndex) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("th", { scope: "col", children: [
|
|
330
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "fe-table__header-content", children: headers[columnIndex] ?? `Column ${columnIndex + 1}` }),
|
|
331
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
332
|
+
"span",
|
|
333
|
+
{
|
|
334
|
+
className: "fe-table__resize-handle",
|
|
335
|
+
role: "separator",
|
|
336
|
+
"aria-label": `Resize ${getText(headers[columnIndex]) || `column ${columnIndex + 1}`}`,
|
|
337
|
+
"aria-orientation": "vertical",
|
|
338
|
+
"aria-valuemin": safeMinWidth,
|
|
339
|
+
"aria-valuemax": MAX_COLUMN_WIDTH,
|
|
340
|
+
"aria-valuenow": sizes2[columnIndex] ?? safeMinWidth,
|
|
341
|
+
tabIndex: 0,
|
|
342
|
+
onPointerDown: (event) => {
|
|
343
|
+
event.preventDefault();
|
|
344
|
+
resizeState.current = { columnIndex, startX: event.clientX, startWidth: sizes2[columnIndex] ?? safeMinWidth };
|
|
345
|
+
setIsResizing(true);
|
|
346
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
347
|
+
},
|
|
348
|
+
onKeyDown: (event) => {
|
|
349
|
+
if (event.key === "ArrowLeft") updateColumnSize(columnIndex, (sizes2[columnIndex] ?? safeMinWidth) - 16);
|
|
350
|
+
if (event.key === "ArrowRight") updateColumnSize(columnIndex, (sizes2[columnIndex] ?? safeMinWidth) + 16);
|
|
351
|
+
}
|
|
246
352
|
}
|
|
247
|
-
|
|
248
|
-
)
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
353
|
+
)
|
|
354
|
+
] }, columnIndex)) }) }),
|
|
355
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tbody", { children: pagedData.map((row, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tr", { children: Array.from({ length: columnCount }, (_, columnIndex) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { children: row[columnIndex] }, columnIndex)) }, shouldPaginate ? (currentPage - 1) * safePageSize + rowIndex : rowIndex)) })
|
|
356
|
+
] }),
|
|
357
|
+
resolvedPaginationPosition !== "top-right" && paginationControl
|
|
358
|
+
] });
|
|
252
359
|
}
|
|
253
|
-
function Table({
|
|
254
|
-
|
|
255
|
-
|
|
360
|
+
function Table({
|
|
361
|
+
headers,
|
|
362
|
+
data,
|
|
363
|
+
striped,
|
|
364
|
+
children,
|
|
365
|
+
pagination,
|
|
366
|
+
pageSize,
|
|
367
|
+
page,
|
|
368
|
+
defaultPage,
|
|
369
|
+
onPageChange,
|
|
370
|
+
paginationPosition,
|
|
371
|
+
...props
|
|
372
|
+
}) {
|
|
373
|
+
if (headers || data) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DataTable, { headers: headers ?? [], data: data ?? [], striped: striped ?? true, pagination, pageSize, page, defaultPage, onPageChange, paginationPosition, ...props });
|
|
374
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TableContext.Provider, { value: { striped: striped ?? false }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("table", { "data-fe-table": true, "data-striped": striped || void 0, ...props, children }) });
|
|
256
375
|
}
|
|
257
376
|
function TableHead(props) {
|
|
258
|
-
return /* @__PURE__ */ (0,
|
|
377
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("thead", { ...props });
|
|
259
378
|
}
|
|
260
379
|
function TableBody(props) {
|
|
261
|
-
return /* @__PURE__ */ (0,
|
|
380
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tbody", { ...props });
|
|
262
381
|
}
|
|
263
382
|
function TableRow({ children, ...props }) {
|
|
264
|
-
const { striped } = (0,
|
|
265
|
-
return /* @__PURE__ */ (0,
|
|
383
|
+
const { striped } = (0, import_react3.useContext)(TableContext);
|
|
384
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tr", { "data-striped": striped || void 0, ...props, children });
|
|
266
385
|
}
|
|
267
386
|
function TableCell({ children, ...props }) {
|
|
268
|
-
return /* @__PURE__ */ (0,
|
|
387
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { ...props, children });
|
|
269
388
|
}
|
|
270
389
|
function TableHeader({ children, ...props }) {
|
|
271
|
-
return /* @__PURE__ */ (0,
|
|
390
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { scope: "col", ...props, children });
|
|
272
391
|
}
|
|
273
392
|
function TableCaption(props) {
|
|
274
|
-
return /* @__PURE__ */ (0,
|
|
393
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("caption", { ...props });
|
|
275
394
|
}
|
|
276
395
|
|
|
277
396
|
// packages/toggle/src/index.tsx
|
|
278
|
-
var
|
|
279
|
-
var
|
|
280
|
-
var Toggle = (0,
|
|
397
|
+
var import_react4 = require("react");
|
|
398
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
399
|
+
var Toggle = (0, import_react4.forwardRef)(function Toggle2({ color = "#16a34a", label, className, style, id, ...props }, ref) {
|
|
281
400
|
const classes = ["fe-toggle", className].filter(Boolean).join(" ");
|
|
282
401
|
const toggleStyle = {
|
|
283
402
|
"--fe-toggle-color": color,
|
|
284
403
|
...style
|
|
285
404
|
};
|
|
286
|
-
return /* @__PURE__ */ (0,
|
|
287
|
-
/* @__PURE__ */ (0,
|
|
288
|
-
/* @__PURE__ */ (0,
|
|
289
|
-
label && /* @__PURE__ */ (0,
|
|
405
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: classes, style: toggleStyle, children: [
|
|
406
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { ref, id, className: "fe-toggle__input", type: "checkbox", role: "switch", ...props }),
|
|
407
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "fe-toggle__control", "aria-hidden": "true" }),
|
|
408
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "fe-toggle__label", children: label })
|
|
290
409
|
] });
|
|
291
410
|
});
|
|
292
411
|
Toggle.displayName = "Toggle";
|
|
293
412
|
|
|
294
413
|
// packages/drawer/src/index.tsx
|
|
295
|
-
var
|
|
414
|
+
var import_react5 = require("react");
|
|
296
415
|
var import_react_dom = require("react-dom");
|
|
297
|
-
var
|
|
416
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
298
417
|
function Drawer({ open, onClose, title, footer, side = "right", width = 400, fullScreen = false, children, closeOnBackdropClick = true, className, style, ...props }) {
|
|
299
|
-
(0,
|
|
418
|
+
(0, import_react5.useEffect)(() => {
|
|
300
419
|
if (!open) return;
|
|
301
420
|
const onKeyDown = (event) => {
|
|
302
421
|
if (event.key === "Escape") onClose();
|
|
@@ -306,40 +425,130 @@ function Drawer({ open, onClose, title, footer, side = "right", width = 400, ful
|
|
|
306
425
|
}, [onClose, open]);
|
|
307
426
|
if (!open || typeof document === "undefined") return null;
|
|
308
427
|
const panelStyle = !fullScreen && (side === "left" || side === "right") ? { ...style, width: typeof width === "number" ? `${width}px` : width } : style;
|
|
309
|
-
return (0, import_react_dom.createPortal)(/* @__PURE__ */ (0,
|
|
428
|
+
return (0, import_react_dom.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "fe-drawer-backdrop", role: "presentation", onMouseDown: (event) => {
|
|
310
429
|
if (event.target === event.currentTarget && closeOnBackdropClick) onClose();
|
|
311
|
-
}, children: /* @__PURE__ */ (0,
|
|
312
|
-
/* @__PURE__ */ (0,
|
|
313
|
-
title && /* @__PURE__ */ (0,
|
|
314
|
-
/* @__PURE__ */ (0,
|
|
430
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("aside", { className: ["fe-drawer", `fe-drawer--${side}`, fullScreen && "fe-drawer--full-screen", className].filter(Boolean).join(" "), style: panelStyle, role: "dialog", "aria-modal": "true", "aria-label": typeof title === "string" ? title : "Drawer", ...props, children: [
|
|
431
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("header", { className: "fe-drawer__header", children: [
|
|
432
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { children: title }),
|
|
433
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", "aria-label": "Close drawer", onClick: onClose, children: "\xD7" })
|
|
315
434
|
] }),
|
|
316
|
-
/* @__PURE__ */ (0,
|
|
317
|
-
footer && /* @__PURE__ */ (0,
|
|
435
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "fe-drawer__body", children }),
|
|
436
|
+
footer && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("footer", { className: "fe-drawer__footer", children: footer })
|
|
318
437
|
] }) }), document.body);
|
|
319
438
|
}
|
|
320
439
|
|
|
321
440
|
// packages/form-controls/src/index.tsx
|
|
322
|
-
var
|
|
323
|
-
var
|
|
324
|
-
var
|
|
325
|
-
|
|
441
|
+
var import_react6 = require("react");
|
|
442
|
+
var import_react_dom2 = require("react-dom");
|
|
443
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
444
|
+
function getFieldError(error, errorMessage) {
|
|
445
|
+
if (errorMessage !== void 0 && errorMessage !== null) return errorMessage;
|
|
446
|
+
if (typeof error !== "boolean") return error;
|
|
447
|
+
return error ? "Invalid value" : void 0;
|
|
448
|
+
}
|
|
449
|
+
function getDescribedBy(existing, messageId2) {
|
|
450
|
+
return [existing, messageId2].filter(Boolean).join(" ") || void 0;
|
|
451
|
+
}
|
|
452
|
+
var TextInput = (0, import_react6.forwardRef)(function TextInput2({ value, defaultValue = "", onChange, onValueChange, label, helperText, error, errorMessage, clearable = false, onClear, clearLabel = "Clear input", className, disabled, readOnly, id, "aria-describedby": ariaDescribedBy, "aria-labelledby": ariaLabelledBy, ...props }, ref) {
|
|
453
|
+
const generatedId = (0, import_react6.useId)();
|
|
454
|
+
const inputId = id ?? `${generatedId}-input`;
|
|
455
|
+
const labelId = `${generatedId}-label`;
|
|
456
|
+
const messageId2 = `${generatedId}-message`;
|
|
457
|
+
const controlled = value !== void 0;
|
|
458
|
+
const [internalValue, setInternalValue] = (0, import_react6.useState)(defaultValue);
|
|
459
|
+
const currentValue = controlled ? value : internalValue;
|
|
460
|
+
const fieldError = getFieldError(error, errorMessage);
|
|
461
|
+
const hasError = fieldError !== void 0 && fieldError !== false && fieldError !== null;
|
|
462
|
+
const displayedMessage = hasError ? fieldError : helperText;
|
|
463
|
+
const describedBy = getDescribedBy(ariaDescribedBy, displayedMessage ? messageId2 : void 0);
|
|
464
|
+
const clear = () => {
|
|
465
|
+
if (!controlled) setInternalValue("");
|
|
466
|
+
onValueChange?.("");
|
|
467
|
+
onClear?.();
|
|
468
|
+
};
|
|
469
|
+
const labelledBy = getDescribedBy(ariaLabelledBy, label ? labelId : void 0);
|
|
470
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: ["fe-text-input", hasError && "fe-text-input--error", className].filter(Boolean).join(" "), children: [
|
|
471
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { id: labelId, className: "fe-text-input__label", children: label }),
|
|
472
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "fe-text-input__control", children: [
|
|
473
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { ref, id: inputId, value: currentValue, disabled, readOnly, "aria-invalid": hasError || void 0, "aria-labelledby": labelledBy, "aria-describedby": describedBy, onChange: (event) => {
|
|
474
|
+
if (!controlled) setInternalValue(event.target.value);
|
|
475
|
+
onValueChange?.(event.target.value);
|
|
476
|
+
onChange?.(event);
|
|
477
|
+
}, ...props }),
|
|
478
|
+
clearable && currentValue && !disabled && !readOnly && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { hierarchy: "tertiary-gray", size: "24", iconOnly: true, icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CloseIcon, { size: 14 }), "aria-label": clearLabel, onClick: clear, className: "fe-text-input__clear" })
|
|
479
|
+
] }),
|
|
480
|
+
displayedMessage && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { id: messageId2, className: hasError ? "fe-text-input__error" : "fe-text-input__helper", children: displayedMessage })
|
|
481
|
+
] });
|
|
482
|
+
});
|
|
483
|
+
TextInput.displayName = "TextInput";
|
|
484
|
+
var TextArea = (0, import_react6.forwardRef)(function TextArea2({ value, defaultValue = "", onChange, onValueChange, label, helperText, error, errorMessage, clearable = false, onClear, clearLabel = "Clear text area", className, disabled, readOnly, id, "aria-describedby": ariaDescribedBy, "aria-labelledby": ariaLabelledBy, ...props }, ref) {
|
|
485
|
+
const generatedId = (0, import_react6.useId)();
|
|
486
|
+
const inputId = id ?? `${generatedId}-input`;
|
|
487
|
+
const labelId = `${generatedId}-label`;
|
|
488
|
+
const messageId2 = `${generatedId}-message`;
|
|
489
|
+
const controlled = value !== void 0;
|
|
490
|
+
const [internalValue, setInternalValue] = (0, import_react6.useState)(defaultValue);
|
|
491
|
+
const currentValue = controlled ? value : internalValue;
|
|
492
|
+
const fieldError = getFieldError(error, errorMessage);
|
|
493
|
+
const hasError = fieldError !== void 0 && fieldError !== false && fieldError !== null;
|
|
494
|
+
const displayedMessage = hasError ? fieldError : helperText;
|
|
495
|
+
const describedBy = getDescribedBy(ariaDescribedBy, displayedMessage ? messageId2 : void 0);
|
|
496
|
+
const clear = () => {
|
|
497
|
+
if (!controlled) setInternalValue("");
|
|
498
|
+
onValueChange?.("");
|
|
499
|
+
onClear?.();
|
|
500
|
+
};
|
|
501
|
+
const labelledBy = getDescribedBy(ariaLabelledBy, label ? labelId : void 0);
|
|
502
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: ["fe-text-area", hasError && "fe-text-area--error", className].filter(Boolean).join(" "), children: [
|
|
503
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { id: labelId, className: "fe-text-area__label", children: label }),
|
|
504
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "fe-text-area__control", children: [
|
|
505
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("textarea", { ref, id: inputId, value: currentValue, disabled, readOnly, "aria-invalid": hasError || void 0, "aria-labelledby": labelledBy, "aria-describedby": describedBy, onChange: (event) => {
|
|
506
|
+
if (!controlled) setInternalValue(event.target.value);
|
|
507
|
+
onValueChange?.(event.target.value);
|
|
508
|
+
onChange?.(event);
|
|
509
|
+
}, ...props }),
|
|
510
|
+
clearable && currentValue && !disabled && !readOnly && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { hierarchy: "tertiary-gray", size: "24", iconOnly: true, icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CloseIcon, { size: 14 }), "aria-label": clearLabel, onClick: clear, className: "fe-text-area__clear" })
|
|
511
|
+
] }),
|
|
512
|
+
displayedMessage && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { id: messageId2, className: hasError ? "fe-text-area__error" : "fe-text-area__helper", children: displayedMessage })
|
|
513
|
+
] });
|
|
514
|
+
});
|
|
515
|
+
TextArea.displayName = "TextArea";
|
|
516
|
+
var Selection = (0, import_react6.forwardRef)(function Selection2({ className, label, helperText, error, options, placeholder = "Select an option", size = "medium", id, value, defaultValue, onChange, multiple = false, searchable = false, tag = false, clearable = false, disabled = false, name, onKeyDown, ...props }, ref) {
|
|
517
|
+
const generatedId = (0, import_react6.useId)();
|
|
326
518
|
const listboxId = id ?? generatedId;
|
|
327
519
|
const isControlled = value !== void 0;
|
|
328
|
-
const [internalValue, setInternalValue] = (0,
|
|
520
|
+
const [internalValue, setInternalValue] = (0, import_react6.useState)(defaultValue ?? (multiple ? [] : ""));
|
|
329
521
|
const selectedValue = isControlled ? value : internalValue;
|
|
330
522
|
const selectedValues = Array.isArray(selectedValue) ? selectedValue : selectedValue === "" || selectedValue === null || selectedValue === void 0 ? [] : [selectedValue];
|
|
331
523
|
const selectedOptions = options.filter((option) => selectedValues.some((item) => String(item) === String(option.value)));
|
|
332
|
-
const [open, setOpen] = (0,
|
|
333
|
-
const [query, setQuery] = (0,
|
|
334
|
-
const [activeIndex, setActiveIndex] = (0,
|
|
335
|
-
const rootRef = (0,
|
|
336
|
-
(0,
|
|
524
|
+
const [open, setOpen] = (0, import_react6.useState)(false);
|
|
525
|
+
const [query, setQuery] = (0, import_react6.useState)("");
|
|
526
|
+
const [activeIndex, setActiveIndex] = (0, import_react6.useState)(0);
|
|
527
|
+
const rootRef = (0, import_react6.useRef)(null);
|
|
528
|
+
const menuRef = (0, import_react6.useRef)(null);
|
|
529
|
+
const [menuPosition, setMenuPosition] = (0, import_react6.useState)(null);
|
|
530
|
+
(0, import_react6.useEffect)(() => {
|
|
337
531
|
const close = (event) => {
|
|
338
|
-
|
|
532
|
+
const target = event.target;
|
|
533
|
+
if (!rootRef.current?.contains(target) && !menuRef.current?.contains(target)) setOpen(false);
|
|
339
534
|
};
|
|
340
535
|
document.addEventListener("mousedown", close);
|
|
341
536
|
return () => document.removeEventListener("mousedown", close);
|
|
342
537
|
}, []);
|
|
538
|
+
(0, import_react6.useLayoutEffect)(() => {
|
|
539
|
+
if (!open) return;
|
|
540
|
+
const updateMenuPosition = () => {
|
|
541
|
+
const rect = rootRef.current?.getBoundingClientRect();
|
|
542
|
+
if (rect) setMenuPosition({ top: rect.bottom + 7, left: rect.left, width: rect.width });
|
|
543
|
+
};
|
|
544
|
+
updateMenuPosition();
|
|
545
|
+
window.addEventListener("resize", updateMenuPosition);
|
|
546
|
+
document.addEventListener("scroll", updateMenuPosition, true);
|
|
547
|
+
return () => {
|
|
548
|
+
window.removeEventListener("resize", updateMenuPosition);
|
|
549
|
+
document.removeEventListener("scroll", updateMenuPosition, true);
|
|
550
|
+
};
|
|
551
|
+
}, [open]);
|
|
343
552
|
const filteredOptions = options.filter((option) => !query || (option.searchText ?? (typeof option.label === "string" ? option.label : String(option.value))).toLowerCase().includes(query.toLowerCase()));
|
|
344
553
|
const commit = (next) => {
|
|
345
554
|
if (!isControlled) setInternalValue(next);
|
|
@@ -376,39 +585,39 @@ var Selection = (0, import_react5.forwardRef)(function Selection2({ className, l
|
|
|
376
585
|
}
|
|
377
586
|
if (event.key === "Escape") setOpen(false);
|
|
378
587
|
};
|
|
379
|
-
return /* @__PURE__ */ (0,
|
|
380
|
-
label && /* @__PURE__ */ (0,
|
|
381
|
-
/* @__PURE__ */ (0,
|
|
382
|
-
name && selectedValues.map((item) => /* @__PURE__ */ (0,
|
|
383
|
-
/* @__PURE__ */ (0,
|
|
384
|
-
/* @__PURE__ */ (0,
|
|
588
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { ref, className: ["fe-selection", `fe-selection--${size}`, open && "fe-selection--open", clearable && selectedOptions.length > 0 && "fe-selection--clearable", error && "fe-selection--error", disabled && "fe-selection--disabled", className].filter(Boolean).join(" "), ...props, children: [
|
|
589
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "fe-selection__label", children: label }),
|
|
590
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { ref: rootRef, className: "fe-selection__control", children: [
|
|
591
|
+
name && selectedValues.map((item) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { type: "hidden", name: multiple ? `${name}[]` : name, value: item }, String(item))),
|
|
592
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("button", { type: "button", className: "fe-selection__trigger", disabled, "aria-invalid": error || void 0, "aria-haspopup": "listbox", "aria-expanded": open, "aria-controls": listboxId, onClick: () => setOpen((current) => !current), onKeyDown: onTriggerKeyDown, children: [
|
|
593
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: ["fe-selection__value", !selectedOptions.length && "is-placeholder", tag && selectedOptions.length > 1 && "is-tags"].filter(Boolean).join(" "), children: displayLabel ? tag && multiple ? selectedOptions.map((option) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "fe-selection__tag", children: [
|
|
385
594
|
option.label,
|
|
386
|
-
/* @__PURE__ */ (0,
|
|
387
|
-
] }, String(option.value))) : displayLabel.map((item, index) => /* @__PURE__ */ (0,
|
|
595
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { "aria-hidden": "true", children: "\xD7" })
|
|
596
|
+
] }, String(option.value))) : displayLabel.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
|
|
388
597
|
item,
|
|
389
598
|
index < displayLabel.length - 1 ? ", " : ""
|
|
390
599
|
] }, index)) : placeholder }),
|
|
391
|
-
/* @__PURE__ */ (0,
|
|
600
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "fe-selection__actions", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "fe-selection__chevron", "aria-hidden": "true" }) })
|
|
392
601
|
] }),
|
|
393
|
-
clearable && selectedOptions.length > 0 && /* @__PURE__ */ (0,
|
|
394
|
-
open && /* @__PURE__ */ (0,
|
|
395
|
-
searchable && /* @__PURE__ */ (0,
|
|
396
|
-
/* @__PURE__ */ (0,
|
|
397
|
-
/* @__PURE__ */ (0,
|
|
602
|
+
clearable && selectedOptions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "fe-selection__clear", "aria-label": "Clear selection", onClick: clear }),
|
|
603
|
+
open && menuPosition && (0, import_react_dom2.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { ref: menuRef, id: listboxId, className: "fe-selection__menu", style: { position: "fixed", top: menuPosition.top, left: menuPosition.left, width: menuPosition.width }, role: "listbox", "aria-multiselectable": multiple || void 0, children: [
|
|
604
|
+
searchable && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "fe-selection__search", children: [
|
|
605
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { "aria-hidden": "true", children: "\u2315" }),
|
|
606
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { autoFocus: true, value: query, onChange: (event) => {
|
|
398
607
|
setQuery(event.target.value);
|
|
399
608
|
setActiveIndex(0);
|
|
400
609
|
}, placeholder: "Search\u2026", "aria-label": "Search options" })
|
|
401
610
|
] }),
|
|
402
|
-
/* @__PURE__ */ (0,
|
|
611
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "fe-selection__options", children: filteredOptions.length ? filteredOptions.map((option, index) => {
|
|
403
612
|
const isSelected = selectedValues.some((item) => String(item) === String(option.value));
|
|
404
|
-
return /* @__PURE__ */ (0,
|
|
405
|
-
/* @__PURE__ */ (0,
|
|
406
|
-
isSelected && /* @__PURE__ */ (0,
|
|
613
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("button", { type: "button", className: [isSelected && "is-selected", index === activeIndex && "is-active"].filter(Boolean).join(" "), role: "option", "aria-selected": isSelected, disabled: option.disabled, onMouseMove: () => setActiveIndex(index), onClick: () => choose(option), children: [
|
|
614
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: option.label }),
|
|
615
|
+
isSelected && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "fe-selection__check", "aria-hidden": "true", children: "\u2713" })
|
|
407
616
|
] }, String(option.value));
|
|
408
|
-
}) : /* @__PURE__ */ (0,
|
|
409
|
-
] })
|
|
617
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "fe-selection__empty", children: "No matching options" }) })
|
|
618
|
+
] }), document.body)
|
|
410
619
|
] }),
|
|
411
|
-
helperText && /* @__PURE__ */ (0,
|
|
620
|
+
helperText && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "fe-selection__helper", children: helperText })
|
|
412
621
|
] });
|
|
413
622
|
});
|
|
414
623
|
Selection.displayName = "Selection";
|
|
@@ -445,13 +654,19 @@ function normalizeNumberInput(raw, options) {
|
|
|
445
654
|
if (value !== numericValue) return { display: formatNumber(value, decimals, thousandSeparator, decimalSeparator), value };
|
|
446
655
|
return { display: `${negative ? "-" : ""}${groupInteger(integer || "0", thousandSeparator)}${hasDecimal ? `${decimalSeparator}${fraction}` : ""}`, value };
|
|
447
656
|
}
|
|
448
|
-
var NumberInput = (0,
|
|
657
|
+
var NumberInput = (0, import_react6.forwardRef)(function NumberInput2({ value, defaultValue = null, onValueChange, allowDecimal = true, decimals = 2, min, max, decimalSeparator = ".", thousandSeparator = ",", label, helperText, error, errorMessage, className, onBlur, onFocus, "aria-describedby": ariaDescribedBy, ...props }, ref) {
|
|
658
|
+
const generatedId = (0, import_react6.useId)();
|
|
659
|
+
const messageId2 = `${generatedId}-message`;
|
|
449
660
|
const isControlled = value !== void 0;
|
|
450
|
-
const [internalValue, setInternalValue] = (0,
|
|
451
|
-
const [focused, setFocused] = (0,
|
|
661
|
+
const [internalValue, setInternalValue] = (0, import_react6.useState)(defaultValue);
|
|
662
|
+
const [focused, setFocused] = (0, import_react6.useState)(false);
|
|
452
663
|
const actualValue = isControlled ? value ?? null : internalValue;
|
|
453
|
-
const [text, setText] = (0,
|
|
454
|
-
(
|
|
664
|
+
const [text, setText] = (0, import_react6.useState)(actualValue === null ? "" : formatNumber(actualValue, decimals, thousandSeparator, decimalSeparator));
|
|
665
|
+
const fieldError = getFieldError(error, errorMessage);
|
|
666
|
+
const hasError = fieldError !== void 0 && fieldError !== false && fieldError !== null;
|
|
667
|
+
const displayedMessage = hasError ? fieldError : helperText;
|
|
668
|
+
const describedBy = getDescribedBy(ariaDescribedBy, displayedMessage ? messageId2 : void 0);
|
|
669
|
+
(0, import_react6.useEffect)(() => {
|
|
455
670
|
if (!focused) setText(actualValue === null ? "" : formatNumber(actualValue, decimals, thousandSeparator, decimalSeparator));
|
|
456
671
|
}, [actualValue, decimalSeparator, decimals, focused, thousandSeparator]);
|
|
457
672
|
const updateValue = (nextText) => {
|
|
@@ -461,32 +676,32 @@ var NumberInput = (0, import_react5.forwardRef)(function NumberInput2({ value, d
|
|
|
461
676
|
if (!isControlled) setInternalValue(nextValue);
|
|
462
677
|
onValueChange?.(nextValue);
|
|
463
678
|
};
|
|
464
|
-
return /* @__PURE__ */ (0,
|
|
465
|
-
label && /* @__PURE__ */ (0,
|
|
466
|
-
/* @__PURE__ */ (0,
|
|
679
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: ["fe-number-input", hasError && "fe-number-input--error", className].filter(Boolean).join(" "), children: [
|
|
680
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "fe-number-input__label", children: label }),
|
|
681
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { ref, inputMode: allowDecimal ? "decimal" : "numeric", value: text, onFocus: (event) => {
|
|
467
682
|
setFocused(true);
|
|
468
683
|
onFocus?.(event);
|
|
469
684
|
}, onChange: (event) => updateValue(event.target.value), onBlur: (event) => {
|
|
470
685
|
setFocused(false);
|
|
471
686
|
onBlur?.(event);
|
|
472
|
-
}, ...props }),
|
|
473
|
-
|
|
687
|
+
}, ...props, "aria-invalid": hasError || void 0, "aria-describedby": describedBy }),
|
|
688
|
+
displayedMessage && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { id: messageId2, className: hasError ? "fe-number-input__error" : "fe-number-input__helper", children: displayedMessage })
|
|
474
689
|
] });
|
|
475
690
|
});
|
|
476
691
|
NumberInput.displayName = "NumberInput";
|
|
477
692
|
function CurrencyInput({ suffix = "VND", currencies, currency, defaultCurrency, onCurrencyChange, className, ...props }) {
|
|
478
|
-
const [internalCurrency, setInternalCurrency] = (0,
|
|
693
|
+
const [internalCurrency, setInternalCurrency] = (0, import_react6.useState)(defaultCurrency ?? currencies?.[0]?.code ?? "");
|
|
479
694
|
const selectedCurrency = currency ?? internalCurrency;
|
|
480
695
|
const current = currencies?.find((item) => item.code === selectedCurrency);
|
|
481
696
|
const currencySuffix = current?.suffix ?? current?.code ?? suffix;
|
|
482
|
-
return /* @__PURE__ */ (0,
|
|
483
|
-
/* @__PURE__ */ (0,
|
|
484
|
-
currencies?.length ? /* @__PURE__ */ (0,
|
|
697
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: ["fe-currency-input", className].filter(Boolean).join(" "), children: [
|
|
698
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(NumberInput, { ...props, className: "fe-currency-input__number" }),
|
|
699
|
+
currencies?.length ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("select", { className: "fe-currency-input__currency", "aria-label": "Currency", value: selectedCurrency, onChange: (event) => {
|
|
485
700
|
const next = currencies.find((item) => item.code === event.target.value);
|
|
486
701
|
if (!next) return;
|
|
487
702
|
if (currency === void 0) setInternalCurrency(next.code);
|
|
488
703
|
onCurrencyChange?.(next);
|
|
489
|
-
}, children: currencies.map((item) => /* @__PURE__ */ (0,
|
|
704
|
+
}, children: currencies.map((item) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: item.code, children: item.label ?? item.code }, item.code)) }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "fe-currency-input__suffix", children: currencySuffix })
|
|
490
705
|
] });
|
|
491
706
|
}
|
|
492
707
|
var pad = (value) => String(value).padStart(2, "0");
|
|
@@ -509,15 +724,15 @@ function DateTimePicker(props) {
|
|
|
509
724
|
const { label, format = "dd/MM/yyyy HH:mm", disabled, placeholder, locale = "en-US", className, mode = "single" } = props;
|
|
510
725
|
const isRange = mode === "range";
|
|
511
726
|
const controlled = props.value !== void 0;
|
|
512
|
-
const [singleInternal, setSingleInternal] = (0,
|
|
513
|
-
const [rangeInternal, setRangeInternal] = (0,
|
|
727
|
+
const [singleInternal, setSingleInternal] = (0, import_react6.useState)((!isRange ? props.defaultValue : null) ?? null);
|
|
728
|
+
const [rangeInternal, setRangeInternal] = (0, import_react6.useState)((isRange ? props.defaultValue : void 0) ?? [null, null]);
|
|
514
729
|
const singleValue = !isRange ? props.value ?? singleInternal : null;
|
|
515
730
|
const rangeValue = isRange ? props.value ?? rangeInternal : [null, null];
|
|
516
|
-
const [open, setOpen] = (0,
|
|
517
|
-
const [month, setMonth] = (0,
|
|
518
|
-
const [editingEnd, setEditingEnd] = (0,
|
|
519
|
-
const rootRef = (0,
|
|
520
|
-
(0,
|
|
731
|
+
const [open, setOpen] = (0, import_react6.useState)(false);
|
|
732
|
+
const [month, setMonth] = (0, import_react6.useState)(() => new Date((isRange ? rangeValue[0] : singleValue) ?? /* @__PURE__ */ new Date()));
|
|
733
|
+
const [editingEnd, setEditingEnd] = (0, import_react6.useState)(false);
|
|
734
|
+
const rootRef = (0, import_react6.useRef)(null);
|
|
735
|
+
(0, import_react6.useEffect)(() => {
|
|
521
736
|
const onPointerDown = (event) => {
|
|
522
737
|
if (!rootRef.current?.contains(event.target)) setOpen(false);
|
|
523
738
|
};
|
|
@@ -559,44 +774,44 @@ function DateTimePicker(props) {
|
|
|
559
774
|
if (isRange) setRange(editingEnd ? [rangeValue[0], next] : [next, rangeValue[1]]);
|
|
560
775
|
else setSingle(next);
|
|
561
776
|
};
|
|
562
|
-
return /* @__PURE__ */ (0,
|
|
563
|
-
label && /* @__PURE__ */ (0,
|
|
564
|
-
/* @__PURE__ */ (0,
|
|
565
|
-
/* @__PURE__ */ (0,
|
|
566
|
-
/* @__PURE__ */ (0,
|
|
777
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { ref: rootRef, className: ["fe-datetime-picker", className].filter(Boolean).join(" "), children: [
|
|
778
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "fe-datetime-picker__label", children: label }),
|
|
779
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("button", { type: "button", className: "fe-datetime-picker__trigger", disabled, "aria-expanded": open, onClick: () => setOpen((current) => !current), children: [
|
|
780
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { "aria-hidden": "true", children: "\u25F7" }),
|
|
781
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: shownValue || placeholder || (isRange ? "Select date range" : "Select date and time") })
|
|
567
782
|
] }),
|
|
568
|
-
open && /* @__PURE__ */ (0,
|
|
569
|
-
/* @__PURE__ */ (0,
|
|
570
|
-
/* @__PURE__ */ (0,
|
|
571
|
-
/* @__PURE__ */ (0,
|
|
572
|
-
/* @__PURE__ */ (0,
|
|
783
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "fe-datetime-picker__popper", role: "dialog", "aria-label": "Date and time picker", children: [
|
|
784
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "fe-datetime-picker__month", children: [
|
|
785
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", "aria-label": "Previous month", onClick: () => setMonth((current) => new Date(current.getFullYear(), current.getMonth() - 1, 1)), children: "\u2039" }),
|
|
786
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: month.toLocaleDateString(locale, { month: "long", year: "numeric" }) }),
|
|
787
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", "aria-label": "Next month", onClick: () => setMonth((current) => new Date(current.getFullYear(), current.getMonth() + 1, 1)), children: "\u203A" })
|
|
573
788
|
] }),
|
|
574
|
-
/* @__PURE__ */ (0,
|
|
575
|
-
/* @__PURE__ */ (0,
|
|
789
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "fe-datetime-picker__weekdays", children: ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"].map((day) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: day }, day)) }),
|
|
790
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "fe-datetime-picker__days", children: days.map((day) => {
|
|
576
791
|
const inMonth = day.getMonth() === month.getMonth();
|
|
577
792
|
const selected = isRange ? sameDay(day, rangeValue[0]) || sameDay(day, rangeValue[1]) : sameDay(day, singleValue);
|
|
578
793
|
const inRange = isRange && rangeValue[0] && rangeValue[1] && day > startOfDay(rangeValue[0]) && day < startOfDay(rangeValue[1]);
|
|
579
|
-
return /* @__PURE__ */ (0,
|
|
794
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: [!inMonth && "is-other-month", selected && "is-selected", inRange && "is-in-range"].filter(Boolean).join(" "), onClick: () => selectDay(day), children: day.getDate() }, day.toISOString());
|
|
580
795
|
}) }),
|
|
581
|
-
isRange && /* @__PURE__ */ (0,
|
|
582
|
-
/* @__PURE__ */ (0,
|
|
583
|
-
/* @__PURE__ */ (0,
|
|
796
|
+
isRange && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "fe-datetime-picker__range-tabs", children: [
|
|
797
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: !editingEnd ? "is-active" : "", onClick: () => setEditingEnd(false), children: "Start" }),
|
|
798
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: editingEnd ? "is-active" : "", onClick: () => setEditingEnd(true), children: "End" })
|
|
584
799
|
] }),
|
|
585
|
-
/* @__PURE__ */ (0,
|
|
800
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "fe-datetime-picker__time", children: [
|
|
586
801
|
"Time",
|
|
587
|
-
/* @__PURE__ */ (0,
|
|
802
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { type: "time", value: selectedForTime ? `${pad(selectedForTime.getHours())}:${pad(selectedForTime.getMinutes())}` : "00:00", onChange: (event) => setTime(event.target.value), disabled: !selectedForTime })
|
|
588
803
|
] })
|
|
589
804
|
] })
|
|
590
805
|
] });
|
|
591
806
|
}
|
|
592
807
|
|
|
593
808
|
// packages/tooltip/src/index.tsx
|
|
594
|
-
var
|
|
595
|
-
var
|
|
809
|
+
var import_react7 = require("react");
|
|
810
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
596
811
|
function Tooltip({ content, children, placement = "top", disabled, className, ...props }) {
|
|
597
|
-
const [visible, setVisible] = (0,
|
|
598
|
-
const id = (0,
|
|
599
|
-
const trigger = (0,
|
|
812
|
+
const [visible, setVisible] = (0, import_react7.useState)(false);
|
|
813
|
+
const id = (0, import_react7.useId)();
|
|
814
|
+
const trigger = (0, import_react7.cloneElement)(children, { "aria-describedby": visible ? id : void 0, onMouseEnter: (event) => {
|
|
600
815
|
children.props.onMouseEnter?.(event);
|
|
601
816
|
setVisible(true);
|
|
602
817
|
}, onMouseLeave: (event) => {
|
|
@@ -609,46 +824,324 @@ function Tooltip({ content, children, placement = "top", disabled, className, ..
|
|
|
609
824
|
children.props.onBlur?.(event);
|
|
610
825
|
setVisible(false);
|
|
611
826
|
} });
|
|
612
|
-
return /* @__PURE__ */ (0,
|
|
827
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: ["fe-tooltip", `fe-tooltip--${placement}`, className].filter(Boolean).join(" "), ...props, children: [
|
|
613
828
|
trigger,
|
|
614
|
-
visible && !disabled && /* @__PURE__ */ (0,
|
|
829
|
+
visible && !disabled && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { id, role: "tooltip", className: "fe-tooltip__content", children: content })
|
|
615
830
|
] });
|
|
616
831
|
}
|
|
617
832
|
|
|
618
833
|
// packages/expandable-section/src/index.tsx
|
|
619
|
-
var
|
|
620
|
-
var
|
|
834
|
+
var import_react8 = require("react");
|
|
835
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
621
836
|
function ExpandableSection({ title, children, expanded, defaultExpanded = false, onExpandedChange, disabled, className, ...props }) {
|
|
622
|
-
const [internalExpanded, setInternalExpanded] = (0,
|
|
837
|
+
const [internalExpanded, setInternalExpanded] = (0, import_react8.useState)(defaultExpanded);
|
|
623
838
|
const isExpanded = expanded ?? internalExpanded;
|
|
624
|
-
const id = (0,
|
|
839
|
+
const id = (0, import_react8.useId)();
|
|
625
840
|
const toggle = () => {
|
|
626
841
|
if (disabled) return;
|
|
627
842
|
const next = !isExpanded;
|
|
628
843
|
if (expanded === void 0) setInternalExpanded(next);
|
|
629
844
|
onExpandedChange?.(next);
|
|
630
845
|
};
|
|
631
|
-
return /* @__PURE__ */ (0,
|
|
632
|
-
/* @__PURE__ */ (0,
|
|
633
|
-
/* @__PURE__ */ (0,
|
|
634
|
-
/* @__PURE__ */ (0,
|
|
846
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("section", { className: ["fe-expandable-section", isExpanded && "fe-expandable-section--expanded", disabled && "fe-expandable-section--disabled", className].filter(Boolean).join(" "), ...props, children: [
|
|
847
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("button", { className: "fe-expandable-section__trigger", type: "button", "aria-expanded": isExpanded, "aria-controls": id, disabled, onClick: toggle, children: [
|
|
848
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: title }),
|
|
849
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "fe-expandable-section__chevron", "aria-hidden": "true" })
|
|
850
|
+
] }),
|
|
851
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { id, className: "fe-expandable-section__content", "aria-hidden": !isExpanded, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "fe-expandable-section__content-inner", children }) })
|
|
852
|
+
] });
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// packages/loading/src/index.tsx
|
|
856
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
857
|
+
var sizes = {
|
|
858
|
+
small: "16px",
|
|
859
|
+
medium: "24px",
|
|
860
|
+
large: "40px"
|
|
861
|
+
};
|
|
862
|
+
function Loading({ size = "medium", color = "#2878f0", label, className, style, ...props }) {
|
|
863
|
+
const diameter = typeof size === "number" ? `${size}px` : sizes[size];
|
|
864
|
+
const loadingStyle = {
|
|
865
|
+
"--fe-loading-size": diameter,
|
|
866
|
+
"--fe-loading-color": color,
|
|
867
|
+
...style
|
|
868
|
+
};
|
|
869
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: ["fe-loading", className].filter(Boolean).join(" "), style: loadingStyle, role: "status", ...props, children: [
|
|
870
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fe-loading__spinner", "aria-hidden": "true" }),
|
|
871
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fe-loading__label", children: label }),
|
|
872
|
+
!label && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "fe-loading__sr-only", children: "Loading" })
|
|
873
|
+
] });
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
// packages/skeleton/src/index.tsx
|
|
877
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
878
|
+
var pixels = (value) => typeof value === "number" ? `${value}px` : value;
|
|
879
|
+
function SkeletonBase({ variant = "box", shape, width, height, count = 1, animated = true, className, style, ...props }) {
|
|
880
|
+
const resolvedVariant = shape ?? variant;
|
|
881
|
+
const resolvedWidth = pixels(width) ?? (resolvedVariant === "circle" ? "40px" : "100%");
|
|
882
|
+
const resolvedHeight = pixels(height) ?? (resolvedVariant === "circle" ? resolvedWidth : resolvedVariant === "line" ? "12px" : "80px");
|
|
883
|
+
const skeletonStyle = {
|
|
884
|
+
"--fe-skeleton-width": resolvedWidth,
|
|
885
|
+
"--fe-skeleton-height": resolvedHeight,
|
|
886
|
+
...style
|
|
887
|
+
};
|
|
888
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, { children: Array.from({ length: Math.max(1, count) }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
889
|
+
"div",
|
|
890
|
+
{
|
|
891
|
+
className: ["fe-skeleton", `fe-skeleton--${resolvedVariant}`, animated && "fe-skeleton--animated", className].filter(Boolean).join(" "),
|
|
892
|
+
style: skeletonStyle,
|
|
893
|
+
"aria-hidden": "true",
|
|
894
|
+
...props
|
|
895
|
+
},
|
|
896
|
+
index
|
|
897
|
+
)) });
|
|
898
|
+
}
|
|
899
|
+
function SkeletonCircle({ size = 40, ...props }) {
|
|
900
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SkeletonBase, { variant: "circle", width: size, height: size, ...props });
|
|
901
|
+
}
|
|
902
|
+
function SkeletonSquare({ size = 80, ...props }) {
|
|
903
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SkeletonBase, { variant: "box", width: size, height: size, ...props });
|
|
904
|
+
}
|
|
905
|
+
function SkeletonBox({ width = "100%", height = 80, ...props }) {
|
|
906
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SkeletonBase, { variant: "box", width, height, ...props });
|
|
907
|
+
}
|
|
908
|
+
function SkeletonLine({ width = "100%", height = 12, ...props }) {
|
|
909
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SkeletonBase, { variant: "line", width, height, ...props });
|
|
910
|
+
}
|
|
911
|
+
var Skeleton = Object.assign(SkeletonBase, {
|
|
912
|
+
Circle: SkeletonCircle,
|
|
913
|
+
Square: SkeletonSquare,
|
|
914
|
+
Box: SkeletonBox,
|
|
915
|
+
Line: SkeletonLine
|
|
916
|
+
});
|
|
917
|
+
|
|
918
|
+
// packages/modal/src/index.tsx
|
|
919
|
+
var import_react9 = require("react");
|
|
920
|
+
var import_react_dom3 = require("react-dom");
|
|
921
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
922
|
+
function Modal({
|
|
923
|
+
open,
|
|
924
|
+
onClose,
|
|
925
|
+
title,
|
|
926
|
+
description,
|
|
927
|
+
children,
|
|
928
|
+
footer,
|
|
929
|
+
actions = [],
|
|
930
|
+
size = "medium",
|
|
931
|
+
closeOnBackdropClick = true,
|
|
932
|
+
closeButton = true,
|
|
933
|
+
closeLabel = "Close modal",
|
|
934
|
+
className,
|
|
935
|
+
...props
|
|
936
|
+
}) {
|
|
937
|
+
const titleId = (0, import_react9.useId)();
|
|
938
|
+
const panelRef = (0, import_react9.useRef)(null);
|
|
939
|
+
(0, import_react9.useEffect)(() => {
|
|
940
|
+
if (!open) return;
|
|
941
|
+
const onKeyDown = (event) => {
|
|
942
|
+
if (event.key === "Escape") onClose();
|
|
943
|
+
};
|
|
944
|
+
document.addEventListener("keydown", onKeyDown);
|
|
945
|
+
panelRef.current?.focus();
|
|
946
|
+
return () => document.removeEventListener("keydown", onKeyDown);
|
|
947
|
+
}, [onClose, open]);
|
|
948
|
+
if (!open || typeof document === "undefined") return null;
|
|
949
|
+
const hasFooter = footer || actions.length > 0;
|
|
950
|
+
return (0, import_react_dom3.createPortal)(
|
|
951
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "fe-modal-backdrop", role: "presentation", onMouseDown: (event) => {
|
|
952
|
+
if (event.target === event.currentTarget && closeOnBackdropClick) onClose();
|
|
953
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
954
|
+
"div",
|
|
955
|
+
{
|
|
956
|
+
ref: panelRef,
|
|
957
|
+
className: ["fe-modal", `fe-modal--${size}`, className].filter(Boolean).join(" "),
|
|
958
|
+
role: "dialog",
|
|
959
|
+
"aria-modal": "true",
|
|
960
|
+
"aria-labelledby": title ? titleId : void 0,
|
|
961
|
+
"aria-label": title ? void 0 : "Modal",
|
|
962
|
+
tabIndex: -1,
|
|
963
|
+
...props,
|
|
964
|
+
children: [
|
|
965
|
+
(title || description || closeButton) && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("header", { className: "fe-modal__header", children: [
|
|
966
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "fe-modal__heading", children: [
|
|
967
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h2", { id: titleId, children: title }),
|
|
968
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { children: description })
|
|
969
|
+
] }),
|
|
970
|
+
closeButton && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Button, { hierarchy: "tertiary-gray", size: "32", iconOnly: true, icon: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CloseIcon, {}), "aria-label": closeLabel, onClick: onClose })
|
|
971
|
+
] }),
|
|
972
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "fe-modal__body", children }),
|
|
973
|
+
hasFooter && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("footer", { className: "fe-modal__footer", children: [
|
|
974
|
+
footer && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "fe-modal__footer-content", children: footer }),
|
|
975
|
+
actions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "fe-modal__actions", children: actions.map(({ label, ...action }, index) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Button, { ...action, children: label }, index)) })
|
|
976
|
+
] })
|
|
977
|
+
]
|
|
978
|
+
}
|
|
979
|
+
) }),
|
|
980
|
+
document.body
|
|
981
|
+
);
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
// packages/progress/src/index.tsx
|
|
985
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
986
|
+
function ProgressBar({ value, max = 100, label, showValue = true, size = "medium", color = "#2878f0", className, style, "aria-label": ariaLabel, ...props }) {
|
|
987
|
+
const indeterminate = value === null || value === void 0;
|
|
988
|
+
const percentage = indeterminate ? 0 : Math.min(100, Math.max(0, Number(value) / Math.max(1, max) * 100));
|
|
989
|
+
const progressStyle = {
|
|
990
|
+
"--fe-progress-value": `${percentage}%`,
|
|
991
|
+
"--fe-progress-color": color,
|
|
992
|
+
...style
|
|
993
|
+
};
|
|
994
|
+
const visibleValue = `${Math.round(percentage)}%`;
|
|
995
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: ["fe-progress", `fe-progress--${size}`, indeterminate && "fe-progress--indeterminate", className].filter(Boolean).join(" "), style: progressStyle, ...props, children: [
|
|
996
|
+
(label || !indeterminate && showValue) && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "fe-progress__meta", children: [
|
|
997
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "fe-progress__label", children: label }),
|
|
998
|
+
!indeterminate && showValue && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("output", { className: "fe-progress__value", children: visibleValue })
|
|
635
999
|
] }),
|
|
636
|
-
/* @__PURE__ */ (0,
|
|
1000
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "fe-progress__track", role: "progressbar", "aria-label": ariaLabel ?? (typeof label === "string" ? label : "Progress"), "aria-valuemin": indeterminate ? void 0 : 0, "aria-valuemax": indeterminate ? void 0 : max, "aria-valuenow": indeterminate ? void 0 : Number(value), "aria-valuetext": indeterminate ? "Loading" : visibleValue, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "fe-progress__indicator" }) })
|
|
1001
|
+
] });
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
// packages/chip/src/index.tsx
|
|
1005
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1006
|
+
var statuses = ["default", "info", "success", "warning", "error", "neutral", "pending", "processing"];
|
|
1007
|
+
function Chip({ children, status = "default", color, variant = "subtle", dot = false, onRemove, removeLabel = "Remove", className, style, ...props }) {
|
|
1008
|
+
const usesCustomColor = Boolean(color);
|
|
1009
|
+
const chipStyle = {
|
|
1010
|
+
...usesCustomColor ? { "--fe-chip-custom-color": color } : {},
|
|
1011
|
+
...style
|
|
1012
|
+
};
|
|
1013
|
+
const resolvedStatus = statuses.includes(status) ? status : "default";
|
|
1014
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: ["fe-chip", `fe-chip--${variant}`, `fe-chip--${usesCustomColor ? "custom" : resolvedStatus}`, className].filter(Boolean).join(" "), style: chipStyle, ...props, children: [
|
|
1015
|
+
dot && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "fe-chip__dot", "aria-hidden": "true" }),
|
|
1016
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "fe-chip__content", children }),
|
|
1017
|
+
onRemove && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Button, { hierarchy: "tertiary-gray", size: "24", iconOnly: true, icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CloseIcon, { size: 14 }), "aria-label": removeLabel, onClick: onRemove, className: "fe-chip__remove" })
|
|
637
1018
|
] });
|
|
638
1019
|
}
|
|
1020
|
+
|
|
1021
|
+
// packages/message/src/index.tsx
|
|
1022
|
+
var import_react10 = require("react");
|
|
1023
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1024
|
+
var messageId = 0;
|
|
1025
|
+
var entries = [];
|
|
1026
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
1027
|
+
var timers = /* @__PURE__ */ new Map();
|
|
1028
|
+
var publish = () => listeners.forEach((listener) => listener(entries));
|
|
1029
|
+
function dismiss(id) {
|
|
1030
|
+
const timer = timers.get(id);
|
|
1031
|
+
if (timer) window.clearTimeout(timer);
|
|
1032
|
+
timers.delete(id);
|
|
1033
|
+
const entry = entries.find((item) => item.id === id);
|
|
1034
|
+
entries = entries.filter((item) => item.id !== id);
|
|
1035
|
+
entry?.onClose?.();
|
|
1036
|
+
publish();
|
|
1037
|
+
}
|
|
1038
|
+
function show({ duration = 4500, severity = "info", ...options }) {
|
|
1039
|
+
const id = ++messageId;
|
|
1040
|
+
entries = [...entries, { id, duration, severity, ...options }];
|
|
1041
|
+
publish();
|
|
1042
|
+
if (duration !== null) timers.set(id, window.setTimeout(() => dismiss(id), duration));
|
|
1043
|
+
return id;
|
|
1044
|
+
}
|
|
1045
|
+
var message = {
|
|
1046
|
+
show,
|
|
1047
|
+
success: (content, options = {}) => show({ content, severity: "success", ...options }),
|
|
1048
|
+
info: (content, options = {}) => show({ content, severity: "info", ...options }),
|
|
1049
|
+
warning: (content, options = {}) => show({ content, severity: "warning", ...options }),
|
|
1050
|
+
error: (content, options = {}) => show({ content, severity: "error", ...options }),
|
|
1051
|
+
dismiss,
|
|
1052
|
+
clear: () => [...entries].forEach((entry) => dismiss(entry.id))
|
|
1053
|
+
};
|
|
1054
|
+
var icons = { success: "\u2713", info: "i", warning: "!", error: "\xD7" };
|
|
1055
|
+
function Message({ maxCount = 4, closeLabel = "Close notification", className, ...props }) {
|
|
1056
|
+
const [visibleEntries, setVisibleEntries] = (0, import_react10.useState)(entries);
|
|
1057
|
+
(0, import_react10.useEffect)(() => {
|
|
1058
|
+
const listener = (nextEntries) => setVisibleEntries(nextEntries);
|
|
1059
|
+
listeners.add(listener);
|
|
1060
|
+
return () => {
|
|
1061
|
+
listeners.delete(listener);
|
|
1062
|
+
};
|
|
1063
|
+
}, []);
|
|
1064
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: ["fe-message-viewport", className].filter(Boolean).join(" "), "aria-live": "polite", ...props, children: visibleEntries.slice(-Math.max(1, maxCount)).map((entry) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: `fe-message fe-message--${entry.severity ?? "info"}`, role: entry.severity === "error" ? "alert" : "status", children: [
|
|
1065
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "fe-message__icon", "aria-hidden": "true", children: icons[entry.severity ?? "info"] }),
|
|
1066
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "fe-message__body", children: [
|
|
1067
|
+
entry.title && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { className: "fe-message__title", children: entry.title }),
|
|
1068
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "fe-message__content", children: entry.content })
|
|
1069
|
+
] }),
|
|
1070
|
+
entry.action && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "fe-message__action", children: entry.action }),
|
|
1071
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Button, { className: "fe-message__close", hierarchy: "tertiary-gray", size: "24", iconOnly: true, icon: "\xD7", "aria-label": closeLabel, onClick: () => dismiss(entry.id) })
|
|
1072
|
+
] }, entry.id)) });
|
|
1073
|
+
}
|
|
1074
|
+
((Message2) => {
|
|
1075
|
+
Message2.show = message.show;
|
|
1076
|
+
Message2.success = message.success;
|
|
1077
|
+
Message2.info = message.info;
|
|
1078
|
+
Message2.warning = message.warning;
|
|
1079
|
+
Message2.error = message.error;
|
|
1080
|
+
Message2.dismiss = message.dismiss;
|
|
1081
|
+
Message2.clear = message.clear;
|
|
1082
|
+
})(Message || (Message = {}));
|
|
1083
|
+
|
|
1084
|
+
// packages/snackbar/src/index.tsx
|
|
1085
|
+
var import_react11 = require("react");
|
|
1086
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1087
|
+
function Snackbar({
|
|
1088
|
+
open,
|
|
1089
|
+
message: message2,
|
|
1090
|
+
autoHideDuration = 5e3,
|
|
1091
|
+
onClose,
|
|
1092
|
+
action,
|
|
1093
|
+
anchorOrigin = {},
|
|
1094
|
+
closeLabel = "Close notification",
|
|
1095
|
+
className,
|
|
1096
|
+
...props
|
|
1097
|
+
}) {
|
|
1098
|
+
const vertical = anchorOrigin.vertical ?? "bottom";
|
|
1099
|
+
const horizontal = anchorOrigin.horizontal ?? "center";
|
|
1100
|
+
(0, import_react11.useEffect)(() => {
|
|
1101
|
+
if (!open || autoHideDuration === null) return void 0;
|
|
1102
|
+
const timer = window.setTimeout(() => onClose?.("timeout"), autoHideDuration);
|
|
1103
|
+
return () => window.clearTimeout(timer);
|
|
1104
|
+
}, [open, autoHideDuration, onClose]);
|
|
1105
|
+
(0, import_react11.useEffect)(() => {
|
|
1106
|
+
if (!open) return void 0;
|
|
1107
|
+
const onKeyDown = (event) => {
|
|
1108
|
+
if (event.key === "Escape") onClose?.("escapeKeyDown");
|
|
1109
|
+
};
|
|
1110
|
+
window.addEventListener("keydown", onKeyDown);
|
|
1111
|
+
return () => window.removeEventListener("keydown", onKeyDown);
|
|
1112
|
+
}, [open, onClose]);
|
|
1113
|
+
if (!open) return null;
|
|
1114
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: ["fe-snackbar", `fe-snackbar--${vertical}`, `fe-snackbar--${horizontal}`, className].filter(Boolean).join(" "), ...props, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "fe-snackbar__content", role: "status", "aria-live": "polite", children: [
|
|
1115
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fe-snackbar__message", children: message2 }),
|
|
1116
|
+
action && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fe-snackbar__action", children: action }),
|
|
1117
|
+
onClose && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Button, { className: "fe-snackbar__close", hierarchy: "tertiary-gray", size: "24", iconOnly: true, icon: "\xD7", "aria-label": closeLabel, onClick: () => onClose("closeButton") })
|
|
1118
|
+
] }) });
|
|
1119
|
+
}
|
|
639
1120
|
// Annotate the CommonJS export names for ESM import in node:
|
|
640
1121
|
0 && (module.exports = {
|
|
641
1122
|
Button,
|
|
642
1123
|
ChevronDownIcon,
|
|
1124
|
+
Chip,
|
|
643
1125
|
CloseIcon,
|
|
644
1126
|
CurrencyInput,
|
|
645
1127
|
DateTimePicker,
|
|
646
1128
|
Drawer,
|
|
647
1129
|
ExpandableSection,
|
|
1130
|
+
Loading,
|
|
1131
|
+
Message,
|
|
1132
|
+
Modal,
|
|
648
1133
|
NumberInput,
|
|
1134
|
+
Pagination,
|
|
649
1135
|
PlusIcon,
|
|
1136
|
+
ProgressBar,
|
|
650
1137
|
SearchIcon,
|
|
651
1138
|
Selection,
|
|
1139
|
+
Skeleton,
|
|
1140
|
+
SkeletonBox,
|
|
1141
|
+
SkeletonCircle,
|
|
1142
|
+
SkeletonLine,
|
|
1143
|
+
SkeletonSquare,
|
|
1144
|
+
Snackbar,
|
|
652
1145
|
Table,
|
|
653
1146
|
TableBody,
|
|
654
1147
|
TableCaption,
|
|
@@ -656,8 +1149,11 @@ function ExpandableSection({ title, children, expanded, defaultExpanded = false,
|
|
|
656
1149
|
TableHead,
|
|
657
1150
|
TableHeader,
|
|
658
1151
|
TableRow,
|
|
1152
|
+
TextArea,
|
|
1153
|
+
TextInput,
|
|
659
1154
|
Toggle,
|
|
660
1155
|
Tooltip,
|
|
661
1156
|
formatNumber,
|
|
662
|
-
getIconSize
|
|
1157
|
+
getIconSize,
|
|
1158
|
+
message
|
|
663
1159
|
});
|