@bouku/core 0.0.6 → 0.0.8
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/dist/assets/icons/arrow-down.svg +6 -0
- package/dist/assets/icons/arrow-up.svg +6 -0
- package/dist/assets/icons/check-circle.svg +6 -0
- package/dist/assets/icons/x-circle.svg +6 -0
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.js +3 -2
- package/dist/components/table/header.d.ts +10 -0
- package/dist/components/table/header.js +19 -0
- package/dist/components/table/index.d.ts +14 -0
- package/dist/components/table/index.js +32 -0
- package/dist/components/table/row.d.ts +15 -0
- package/dist/components/table/row.js +31 -0
- package/dist/components/table/sorter.d.ts +10 -0
- package/dist/components/table/sorter.js +53 -0
- package/dist/utils/types/element.d.ts +4 -0
- package/dist/utils/types/element.js +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" width="1em" height="1em">
|
|
2
|
+
<path
|
|
3
|
+
d="M297.4 566.6C309.9 579.1 330.2 579.1 342.7 566.6L502.7 406.6C515.2 394.1 515.2 373.8 502.7 361.3C490.2 348.8 469.9 348.8 457.4 361.3L352 466.7L352 96C352 78.3 337.7 64 320 64C302.3 64 288 78.3 288 96L288 466.7L182.6 361.3C170.1 348.8 149.8 348.8 137.3 361.3C124.8 373.8 124.8 394.1 137.3 406.6L297.3 566.6z"
|
|
4
|
+
fill="currentColor"
|
|
5
|
+
/>
|
|
6
|
+
</svg>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" width="1em" height="1em">
|
|
2
|
+
<path
|
|
3
|
+
d="M342.6 73.4C330.1 60.9 309.8 60.9 297.3 73.4L137.3 233.4C124.8 245.9 124.8 266.2 137.3 278.7C149.8 291.2 170.1 291.2 182.6 278.7L288 173.3L288 544C288 561.7 302.3 576 320 576C337.7 576 352 561.7 352 544L352 173.3L457.4 278.7C469.9 291.2 490.2 291.2 502.7 278.7C515.2 266.2 515.2 245.9 502.7 233.4L342.7 73.4z"
|
|
4
|
+
fill="currentColor"
|
|
5
|
+
/>
|
|
6
|
+
</svg>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" width="1em" height="1em">
|
|
2
|
+
<path
|
|
3
|
+
d="M320 576C178.6 576 64 461.4 64 320C64 178.6 178.6 64 320 64C461.4 64 576 178.6 576 320C576 461.4 461.4 576 320 576zM438 209.7C427.3 201.9 412.3 204.3 404.5 215L285.1 379.2L233 327.1C223.6 317.7 208.4 317.7 199.1 327.1C189.8 336.5 189.7 351.7 199.1 361L271.1 433C276.1 438 282.9 440.5 289.9 440C296.9 439.5 303.3 435.9 307.4 430.2L443.3 243.2C451.1 232.5 448.7 217.5 438 209.7z"
|
|
4
|
+
fill="currentColor"
|
|
5
|
+
/>
|
|
6
|
+
</svg>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" width="1em" height="1em">
|
|
2
|
+
<path
|
|
3
|
+
d="M320 576C461.4 576 576 461.4 576 320C576 178.6 461.4 64 320 64C178.6 64 64 178.6 64 320C64 461.4 178.6 576 320 576zM231 231C240.4 221.6 255.6 221.6 264.9 231L319.9 286L374.9 231C384.3 221.6 399.5 221.6 408.8 231C418.1 240.4 418.2 255.6 408.8 264.9L353.8 319.9L408.8 374.9C418.2 384.3 418.2 399.5 408.8 408.8C399.4 418.1 384.2 418.2 374.9 408.8L319.9 353.8L264.9 408.8C255.5 418.2 240.3 418.2 231 408.8C221.7 399.4 221.6 384.2 231 374.9L286 319.9L231 264.9C221.6 255.5 221.6 240.3 231 231z"
|
|
4
|
+
fill="currentColor"
|
|
5
|
+
/>
|
|
6
|
+
</svg>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { default as Accordion } from "./accordion";
|
|
2
|
+
export { default as Table } from "./table";
|
|
2
3
|
export { default as Separator } from "./layout/separator";
|
|
3
4
|
export { default as FadeBox } from "./layout/fade";
|
|
4
5
|
export { default as AbsoluteBox } from "./layout/absolute";
|
|
@@ -17,4 +18,3 @@ export * from "./date/_";
|
|
|
17
18
|
export * from "./information/_";
|
|
18
19
|
export * from "./progress/_";
|
|
19
20
|
export * from "./text/_";
|
|
20
|
-
export * from "./table/_";
|
package/dist/components/index.js
CHANGED
|
@@ -17,9 +17,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
17
17
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
18
|
};
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
exports.Dropdown = exports.Section = exports.Pagination = exports.AbsoluteBox = exports.FadeBox = exports.Separator = exports.Accordion = void 0;
|
|
20
|
+
exports.Dropdown = exports.Section = exports.Pagination = exports.AbsoluteBox = exports.FadeBox = exports.Separator = exports.Table = exports.Accordion = void 0;
|
|
21
21
|
var accordion_1 = require("./accordion");
|
|
22
22
|
Object.defineProperty(exports, "Accordion", { enumerable: true, get: function () { return __importDefault(accordion_1).default; } });
|
|
23
|
+
var table_1 = require("./table");
|
|
24
|
+
Object.defineProperty(exports, "Table", { enumerable: true, get: function () { return __importDefault(table_1).default; } });
|
|
23
25
|
var separator_1 = require("./layout/separator");
|
|
24
26
|
Object.defineProperty(exports, "Separator", { enumerable: true, get: function () { return __importDefault(separator_1).default; } });
|
|
25
27
|
var fade_1 = require("./layout/fade");
|
|
@@ -44,4 +46,3 @@ __exportStar(require("./date/_"), exports);
|
|
|
44
46
|
__exportStar(require("./information/_"), exports);
|
|
45
47
|
__exportStar(require("./progress/_"), exports);
|
|
46
48
|
__exportStar(require("./text/_"), exports);
|
|
47
|
-
__exportStar(require("./table/_"), exports);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CellValue } from "./row";
|
|
2
|
+
type Props<T> = {
|
|
3
|
+
columnLabels: Record<string, string>;
|
|
4
|
+
sortColumn: keyof T | null;
|
|
5
|
+
sortDirection: "asc" | "desc";
|
|
6
|
+
sortBy: (x: string | null) => void;
|
|
7
|
+
toggleSortDirection: () => void;
|
|
8
|
+
};
|
|
9
|
+
export declare const Header: <T extends Record<keyof T, CellValue>>({ columnLabels, sortColumn, sortDirection, sortBy, toggleSortDirection }: Props<T>) => import("react").JSX.Element;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Header = void 0;
|
|
7
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
+
const react_1 = require("react");
|
|
9
|
+
const flex_1 = require("../layout/flex");
|
|
10
|
+
const arrow_up_svg_1 = __importDefault(require("../../assets/icons/arrow-up.svg"));
|
|
11
|
+
const arrow_down_svg_1 = __importDefault(require("../../assets/icons/arrow-down.svg"));
|
|
12
|
+
const Header = ({ columnLabels, sortColumn, sortDirection, sortBy, toggleSortDirection }) => ((0, jsx_runtime_1.jsx)(flex_1.RowBox, { style: s.container, children: Object.entries(columnLabels).map(([col, label], i) => ((0, jsx_runtime_1.jsxs)(flex_1.RowBox, { style: s.column, children: [(0, jsx_runtime_1.jsx)("span", { className: s.label, onClick: () => sortBy(col), children: label }), col === sortColumn && ((0, jsx_runtime_1.jsxs)(react_1.Fragment, { children: [sortDirection === "desc" && (0, jsx_runtime_1.jsx)(arrow_down_svg_1.default, { className: s.sorter, onClick: () => toggleSortDirection() }), sortDirection === "asc" && (0, jsx_runtime_1.jsx)(arrow_up_svg_1.default, { className: s.sorter, onClick: () => toggleSortDirection() })] }))] }, i))) }));
|
|
13
|
+
exports.Header = Header;
|
|
14
|
+
const s = {
|
|
15
|
+
container: "w-full px-4 py-3 bg-background-light border-b border-border",
|
|
16
|
+
column: "flex-1 gap-1 first:justify-start justify-center last:justify-end items-center uppercase text-primary-dark font-light text-sm",
|
|
17
|
+
label: "hover:brightness-120 duration-200 cursor-pointer",
|
|
18
|
+
sorter: "hover:text-primary cursor-pointer duration-200"
|
|
19
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Row } from "./row";
|
|
2
|
+
type ColumnOptions = {
|
|
3
|
+
label?: string;
|
|
4
|
+
pad?: number;
|
|
5
|
+
link?: string;
|
|
6
|
+
};
|
|
7
|
+
type Props<T extends Row> = {
|
|
8
|
+
style?: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
config: Partial<Record<keyof T, boolean | ColumnOptions>>;
|
|
11
|
+
items: T[];
|
|
12
|
+
};
|
|
13
|
+
export default function Table<T extends Row>({ style, title, config: initConfig, items }: Props<T>): import("react").JSX.Element;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.default = Table;
|
|
5
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
const sorter_1 = require("./sorter");
|
|
7
|
+
const flex_1 = require("../layout/flex");
|
|
8
|
+
const header_1 = require("./header");
|
|
9
|
+
const row_1 = require("./row");
|
|
10
|
+
const ts_helper_kit_1 = require("ts-helper-kit");
|
|
11
|
+
const style_1 = require("@bouko/style");
|
|
12
|
+
function Table({ style, title, config: initConfig, items }) {
|
|
13
|
+
const { sortedItems, ...sortOptions } = (0, sorter_1.useSort)(items);
|
|
14
|
+
const config = parseConfig(initConfig);
|
|
15
|
+
const columns = Object.keys(config);
|
|
16
|
+
const condensedItems = (0, ts_helper_kit_1.condenseArray)(sortedItems, columns);
|
|
17
|
+
return ((0, jsx_runtime_1.jsxs)(flex_1.ColumnBox, { style: (0, style_1.cn)(s.container, style), children: [title && ((0, jsx_runtime_1.jsx)("span", { className: s.title, children: title })), (0, jsx_runtime_1.jsxs)(flex_1.ColumnBox, { style: s.subcontainer, children: [(0, jsx_runtime_1.jsx)(header_1.Header, { ...sortOptions, columnLabels: Object.fromEntries(columns.map(c => [c, config[c].label])) }), (0, jsx_runtime_1.jsx)(flex_1.ColumnBox, { style: s.rows, children: condensedItems.map(({ item, count }, i) => ((0, jsx_runtime_1.jsx)(row_1.TableRow, { config: config, data: item, count: count }, i))) })] })] }));
|
|
18
|
+
}
|
|
19
|
+
function parseConfig(config) {
|
|
20
|
+
return Object.entries(config).reduce((acc, [key, value]) => {
|
|
21
|
+
const label = String(key).replaceAll("_", " ");
|
|
22
|
+
const isObject = typeof value === "object" && value !== null;
|
|
23
|
+
acc[key] = isObject ? { label, ...value } : { label };
|
|
24
|
+
return acc;
|
|
25
|
+
}, {});
|
|
26
|
+
}
|
|
27
|
+
const s = {
|
|
28
|
+
container: "gap-3 overflow-hidden",
|
|
29
|
+
title: "text-xl font-bold text-primary",
|
|
30
|
+
subcontainer: "grow w-full border border-border rounded-md overflow-hidden",
|
|
31
|
+
rows: "grow overflow-y-auto no-scrollbar"
|
|
32
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const isDateLike: (val: string) => boolean;
|
|
2
|
+
type ColumnOptions = {
|
|
3
|
+
label: string;
|
|
4
|
+
pad?: number;
|
|
5
|
+
link?: string;
|
|
6
|
+
};
|
|
7
|
+
interface Props<T> {
|
|
8
|
+
config: Record<string, ColumnOptions>;
|
|
9
|
+
data: T;
|
|
10
|
+
count: number;
|
|
11
|
+
}
|
|
12
|
+
export type Row = Record<string, CellValue>;
|
|
13
|
+
export type CellValue = string | number | boolean;
|
|
14
|
+
export declare function TableRow<T extends Row>({ config, data, count }: Props<T>): import("react").JSX.Element;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.isDateLike = void 0;
|
|
7
|
+
exports.TableRow = TableRow;
|
|
8
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
9
|
+
const flex_1 = require("../layout/flex");
|
|
10
|
+
const ts_helper_kit_1 = require("ts-helper-kit");
|
|
11
|
+
const check_circle_svg_1 = __importDefault(require("../../assets/icons/check-circle.svg"));
|
|
12
|
+
const x_circle_svg_1 = __importDefault(require("../../assets/icons/x-circle.svg"));
|
|
13
|
+
const isDateLike = (val) => !isNaN(Date.parse(val)) && isNaN(Number(val));
|
|
14
|
+
exports.isDateLike = isDateLike;
|
|
15
|
+
function TableRow({ config, data, count }) {
|
|
16
|
+
return ((0, jsx_runtime_1.jsxs)(flex_1.RowBox, { style: s.container, children: [Object.keys(config).map((key, i) => {
|
|
17
|
+
const rawValue = data[key];
|
|
18
|
+
const value = rawValue === 0 ? 0 : (data[key] ?? "N/A");
|
|
19
|
+
const options = config[key];
|
|
20
|
+
let cellValue = value;
|
|
21
|
+
if (options && options.pad)
|
|
22
|
+
cellValue = (0, ts_helper_kit_1.padNum)(cellValue, options.pad);
|
|
23
|
+
else if ((0, exports.isDateLike)(cellValue.toString()))
|
|
24
|
+
cellValue = new Date(cellValue.toString()).toLocaleDateString();
|
|
25
|
+
return ((0, jsx_runtime_1.jsxs)(flex_1.RowBox, { style: s.cell, children: [options && options?.link && (0, jsx_runtime_1.jsx)("a", { className: "text-primary underline duration-200 hover:text-accent", href: options.link?.replace("[x]", rawValue), children: cellValue }), options && !options?.link && ((0, jsx_runtime_1.jsx)("span", { className: "truncate", children: value === true ? (0, jsx_runtime_1.jsx)(check_circle_svg_1.default, { className: "text-success" }) : value === false ? (0, jsx_runtime_1.jsx)(x_circle_svg_1.default, { className: "text-error" }) : cellValue }))] }, i));
|
|
26
|
+
}), count > 1 && ((0, jsx_runtime_1.jsx)("span", { className: "absolute top-0 left-0 pb-px px-1 bg-surface-light border-b border-r rounded-br border-border-light font-bold font-mono text-px text-accent", children: count }))] }));
|
|
27
|
+
}
|
|
28
|
+
const s = {
|
|
29
|
+
container: "relative w-full px-4 py-4 even:bg-surface border-b border-border last:border-b-0",
|
|
30
|
+
cell: "flex-1 first-of-type:justify-start justify-center last-of-type:justify-end items-center gap-2 font-mono overflow-hidden"
|
|
31
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type CellValue = string | number | boolean;
|
|
2
|
+
type SortDirection = "asc" | "desc";
|
|
3
|
+
export declare function useSort<T extends Record<string, CellValue>>(items: T[]): {
|
|
4
|
+
sortedItems: T[];
|
|
5
|
+
sortBy: (col: keyof T | null) => void;
|
|
6
|
+
toggleSortDirection: () => void;
|
|
7
|
+
sortColumn: keyof T | null;
|
|
8
|
+
sortDirection: SortDirection;
|
|
9
|
+
};
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useSort = useSort;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
function useSort(items) {
|
|
6
|
+
const [column, setColumn] = (0, react_1.useState)(null);
|
|
7
|
+
const [isDescending, setDescending] = (0, react_1.useState)(true);
|
|
8
|
+
const sortBy = (col) => {
|
|
9
|
+
if (col === column)
|
|
10
|
+
return setColumn(null);
|
|
11
|
+
setDescending(true);
|
|
12
|
+
setColumn(col);
|
|
13
|
+
};
|
|
14
|
+
const sortedItems = (0, react_1.useMemo)(() => {
|
|
15
|
+
if (!column)
|
|
16
|
+
return items;
|
|
17
|
+
return [...items].sort((a, b) => {
|
|
18
|
+
const valA = a[column];
|
|
19
|
+
const valB = b[column];
|
|
20
|
+
if (valA === undefined || valA === null)
|
|
21
|
+
return 1;
|
|
22
|
+
if (valB === undefined || valB === null)
|
|
23
|
+
return -1;
|
|
24
|
+
let comparison = 0;
|
|
25
|
+
// 2. Date detection & comparison
|
|
26
|
+
const isDateLike = (val) => val instanceof Date ||
|
|
27
|
+
(typeof val === "string" && !isNaN(Date.parse(val)) && isNaN(Number(val)));
|
|
28
|
+
if (isDateLike(valA) && isDateLike(valB)) {
|
|
29
|
+
const timeA = new Date(valA).getTime();
|
|
30
|
+
const timeB = new Date(valB).getTime();
|
|
31
|
+
// Swap this to timeB - timeA so the base comparison defaults to descending
|
|
32
|
+
comparison = timeA - timeB;
|
|
33
|
+
}
|
|
34
|
+
// 3. Number comparison
|
|
35
|
+
else if (typeof valA === "number" && typeof valB === "number")
|
|
36
|
+
comparison = valA - valB;
|
|
37
|
+
// 4. String / Fallback comparison (case-insensitive)
|
|
38
|
+
else {
|
|
39
|
+
const strA = String(valA).toLowerCase();
|
|
40
|
+
const strB = String(valB).toLowerCase();
|
|
41
|
+
comparison = strA.localeCompare(strB);
|
|
42
|
+
}
|
|
43
|
+
return isDescending ? -comparison : comparison;
|
|
44
|
+
});
|
|
45
|
+
}, [items, column, isDescending]);
|
|
46
|
+
return {
|
|
47
|
+
sortedItems,
|
|
48
|
+
sortBy,
|
|
49
|
+
toggleSortDirection: () => setDescending(p => !p),
|
|
50
|
+
sortColumn: column,
|
|
51
|
+
sortDirection: isDescending ? "desc" : "asc"
|
|
52
|
+
};
|
|
53
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bouku/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
"framer-motion": "^12.23.6",
|
|
30
30
|
"react-rnd": "^10.5.2",
|
|
31
31
|
"react-time-ago": "^7.4.4",
|
|
32
|
-
"tailwind-variants": "^1.0.0"
|
|
32
|
+
"tailwind-variants": "^1.0.0",
|
|
33
|
+
"ts-helper-kit": "^0.0.6"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
|
35
36
|
"@types/node": "^24.3.1",
|