@godxjp/ui 2.2.0 → 5.0.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/BRAND.md +39 -29
- package/CHANGELOG.md +554 -10
- package/README.md +143 -168
- package/config/eslint.js +54 -0
- package/config/prettier.cjs +20 -0
- package/config/tsconfig.base.json +22 -0
- package/config/vitest.base.ts +26 -0
- package/dist/MiniMonth-YAmPGEpC.d.ts +143 -0
- package/dist/Table.types-BbsxoIYE.d.ts +352 -0
- package/dist/color-DO0qqUAb.d.ts +38 -0
- package/dist/components/composites.d.ts +963 -0
- package/dist/components/composites.js +7340 -0
- package/dist/components/composites.js.map +1 -0
- package/dist/components/primitives.d.ts +2633 -163
- package/dist/components/primitives.js +7264 -165
- package/dist/components/primitives.js.map +1 -1
- package/dist/components/shell.d.ts +82 -12
- package/dist/components/shell.js +168 -162
- package/dist/components/shell.js.map +1 -1
- package/dist/hooks.d.ts +83 -8
- package/dist/hooks.js +497 -83
- package/dist/hooks.js.map +1 -1
- package/dist/i18n.d.ts +55 -3
- package/dist/i18n.js +456 -5
- package/dist/i18n.js.map +1 -1
- package/dist/index.d.ts +24 -5
- package/dist/index.js +12522 -267
- package/dist/index.js.map +1 -1
- package/dist/padding-DY0JV5Ja.d.ts +16 -0
- package/dist/preferences.d.ts +132 -0
- package/dist/preferences.js +262 -0
- package/dist/preferences.js.map +1 -0
- package/dist/props.d.ts +86 -0
- package/dist/props.js +16 -0
- package/dist/props.js.map +1 -0
- package/dist/size-CQwNvOWd.d.ts +19 -0
- package/dist/{data.d.ts → types-LTj-2bl-.d.ts} +7 -12
- package/dist/useTableViews-D5NIAJ7h.d.ts +154 -0
- package/package.json +92 -35
- package/src/tokens/tailwind.css +158 -0
- package/dist/components/screens.d.ts +0 -51
- package/dist/components/screens.js +0 -806
- package/dist/components/screens.js.map +0 -1
- package/dist/data.js +0 -93
- package/dist/data.js.map +0 -1
- package/src/tokens/tokens-ext.css +0 -401
- package/src/tokens/tokens.css +0 -765
package/dist/hooks.js
CHANGED
|
@@ -1,91 +1,152 @@
|
|
|
1
|
-
import { useState, useEffect, useCallback } from 'react';
|
|
1
|
+
import { useState, useEffect, useCallback, useSyncExternalStore, useMemo } from 'react';
|
|
2
2
|
import i18next from 'i18next';
|
|
3
3
|
import 'i18next-browser-languagedetector';
|
|
4
4
|
import 'react-i18next';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
// src/hooks/useTweaks.ts
|
|
7
|
+
|
|
8
|
+
// src/preferences/holder.ts
|
|
9
|
+
var DEFAULT = {
|
|
10
|
+
locale: "ja",
|
|
11
|
+
timezone: "Asia/Tokyo"
|
|
12
|
+
};
|
|
13
|
+
var CURRENT = { ...DEFAULT };
|
|
14
|
+
var subscribers = /* @__PURE__ */ new Set();
|
|
15
|
+
function getGodxConfig() {
|
|
16
|
+
return CURRENT;
|
|
17
|
+
}
|
|
18
|
+
function subscribeGodxConfig(fn) {
|
|
19
|
+
subscribers.add(fn);
|
|
20
|
+
return () => {
|
|
21
|
+
subscribers.delete(fn);
|
|
22
|
+
};
|
|
23
|
+
}
|
|
8
24
|
|
|
9
|
-
// src/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
{ id: "pos", name: "restaurant-pos", stack: "Tauri \xB7 Vue 3", kind: "desktop", devs: 1, status: "active", branch: "feature/print", lastCommit: "30\u5206\u524D", openIssues: 3, prs: 1, sandbox: true },
|
|
24
|
-
{ id: "kds", name: "restaurant-kds", stack: "React \xB7 Electron", kind: "workstation", devs: 1, status: "review", branch: "main", lastCommit: "\u6628\u65E5", openIssues: 2, prs: 1, sandbox: true },
|
|
25
|
-
{ id: "kintai", name: "restaurant-kintai", stack: "Vue 3 \xB7 Laravel", kind: "service", devs: 2, status: "active", branch: "main", lastCommit: "5\u5206\u524D", openIssues: 4, prs: 0, sandbox: true },
|
|
26
|
-
{ id: "mobile", name: "restaurant-mobile", stack: "React Native", kind: "mobile", devs: 1, status: "planning", branch: "develop", lastCommit: "3\u65E5\u524D", openIssues: 1, prs: 0, sandbox: false }
|
|
27
|
-
]
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
id: "godx",
|
|
31
|
-
name: "godx-admin",
|
|
32
|
-
tenant: "godx",
|
|
33
|
-
role: "Platform admin",
|
|
34
|
-
desc: "GoDX Forge developer workspace",
|
|
35
|
-
color: "oklch(60% 0.137 163)",
|
|
36
|
-
owner: "Satoshi F",
|
|
37
|
-
devs: 4,
|
|
38
|
-
projects: [
|
|
39
|
-
{ id: "frontend", name: "godx-admin-frontend", stack: "React \xB7 Vite", kind: "web", devs: 2, status: "active", branch: "master", lastCommit: "2\u6642\u9593\u524D", openIssues: 6, prs: 2, sandbox: true },
|
|
40
|
-
{ id: "api", name: "godx-admin-api", stack: "Go \xB7 Gin", kind: "service", devs: 1, status: "active", branch: "master", lastCommit: "4\u6642\u9593\u524D", openIssues: 3, prs: 1, sandbox: true },
|
|
41
|
-
{ id: "ui", name: "@godxjp/ui", stack: "TypeScript \xB7 React", kind: "library", devs: 2, status: "active", branch: "master", lastCommit: "1\u6642\u9593\u524D", openIssues: 2, prs: 0, sandbox: false }
|
|
42
|
-
]
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
id: "kintai",
|
|
46
|
-
name: "dxs-kintai",
|
|
47
|
-
tenant: "kintai",
|
|
48
|
-
role: "HR / Attendance",
|
|
49
|
-
desc: "\u52E4\u6020\u7BA1\u7406\u30D7\u30E9\u30C3\u30C8\u30D5\u30A9\u30FC\u30E0",
|
|
50
|
-
color: "oklch(56% 0.15 240)",
|
|
51
|
-
owner: "Naoki N",
|
|
52
|
-
devs: 3,
|
|
53
|
-
projects: [
|
|
54
|
-
{ id: "frontend", name: "kintai-web", stack: "Vue 3 \xB7 Vite", kind: "web", devs: 2, status: "active", branch: "main", lastCommit: "20\u5206\u524D", openIssues: 7, prs: 1, sandbox: true },
|
|
55
|
-
{ id: "backend", name: "kintai-api", stack: "Laravel 11", kind: "service", devs: 1, status: "active", branch: "main", lastCommit: "1\u65E5\u524D", openIssues: 4, prs: 0, sandbox: true }
|
|
56
|
-
]
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
id: "tempo",
|
|
60
|
-
name: "dxs-tempo",
|
|
61
|
-
tenant: "tempo",
|
|
62
|
-
role: "Shop / Inventory",
|
|
63
|
-
desc: "\u5E97\u8217\u30FB\u5728\u5EAB\u30D0\u30C3\u30AF\u30A8\u30F3\u30C9",
|
|
64
|
-
color: "oklch(48% 0.16 285)",
|
|
65
|
-
owner: "Naoki N",
|
|
66
|
-
devs: 2,
|
|
67
|
-
projects: [
|
|
68
|
-
{ id: "api", name: "tempo-api", stack: "Go \xB7 Echo", kind: "service", devs: 2, status: "active", branch: "main", lastCommit: "5\u6642\u9593\u524D", openIssues: 9, prs: 1, sandbox: true },
|
|
69
|
-
{ id: "ops", name: "tempo-ops", stack: "Terraform", kind: "infra", devs: 1, status: "planning", branch: "main", lastCommit: "1\u9031\u9593\u524D", openIssues: 1, prs: 0, sandbox: false }
|
|
70
|
-
]
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
id: "betoya",
|
|
74
|
-
name: "betoya",
|
|
75
|
-
tenant: "betoya",
|
|
76
|
-
role: "Vietnamese restaurant",
|
|
77
|
-
desc: "\u30D9\u30C8\u5C4B Tenant",
|
|
78
|
-
color: "oklch(58% 0.159 150)",
|
|
79
|
-
owner: "Anh K",
|
|
80
|
-
devs: 1,
|
|
81
|
-
projects: [
|
|
82
|
-
{ id: "site", name: "betoya-site", stack: "Astro", kind: "web", devs: 1, status: "active", branch: "main", lastCommit: "\u6628\u65E5", openIssues: 2, prs: 0, sandbox: false }
|
|
83
|
-
]
|
|
25
|
+
// src/i18n/format.ts
|
|
26
|
+
function resolveLocale(opts) {
|
|
27
|
+
return opts?.locale ?? getGodxConfig().locale;
|
|
28
|
+
}
|
|
29
|
+
function resolveTimezone(opts) {
|
|
30
|
+
return opts?.timezone ?? getGodxConfig().timezone;
|
|
31
|
+
}
|
|
32
|
+
function toDate(value) {
|
|
33
|
+
if (value instanceof Date) return value;
|
|
34
|
+
if (typeof value === "number") return new Date(value);
|
|
35
|
+
if (typeof value === "string") return new Date(value);
|
|
36
|
+
if (typeof value === "object" && value !== null && "toDate" in value) {
|
|
37
|
+
const v = value;
|
|
38
|
+
return v.toDate(getGodxConfig().timezone);
|
|
84
39
|
}
|
|
85
|
-
|
|
40
|
+
throw new TypeError(`format helpers: unsupported value ${String(value)}`);
|
|
41
|
+
}
|
|
42
|
+
function extractIntlOpts(opts) {
|
|
43
|
+
if (!opts) return {};
|
|
44
|
+
const { locale: _l, timezone: _t, ...rest } = opts;
|
|
45
|
+
return rest;
|
|
46
|
+
}
|
|
47
|
+
function formatDate(value, opts) {
|
|
48
|
+
const locale = resolveLocale(opts);
|
|
49
|
+
const timezone = resolveTimezone(opts);
|
|
50
|
+
const intlOpts = {
|
|
51
|
+
dateStyle: "medium",
|
|
52
|
+
...extractIntlOpts(opts),
|
|
53
|
+
timeZone: timezone
|
|
54
|
+
};
|
|
55
|
+
return new Intl.DateTimeFormat(locale, intlOpts).format(toDate(value));
|
|
56
|
+
}
|
|
57
|
+
function formatTime(value, opts) {
|
|
58
|
+
const locale = resolveLocale(opts);
|
|
59
|
+
const timezone = resolveTimezone(opts);
|
|
60
|
+
const intlOpts = {
|
|
61
|
+
timeStyle: "short",
|
|
62
|
+
...extractIntlOpts(opts),
|
|
63
|
+
timeZone: timezone
|
|
64
|
+
};
|
|
65
|
+
return new Intl.DateTimeFormat(locale, intlOpts).format(toDate(value));
|
|
66
|
+
}
|
|
67
|
+
function formatDateTime(value, opts) {
|
|
68
|
+
const locale = resolveLocale(opts);
|
|
69
|
+
const timezone = resolveTimezone(opts);
|
|
70
|
+
const intlOpts = {
|
|
71
|
+
dateStyle: "medium",
|
|
72
|
+
timeStyle: "short",
|
|
73
|
+
...extractIntlOpts(opts),
|
|
74
|
+
timeZone: timezone
|
|
75
|
+
};
|
|
76
|
+
return new Intl.DateTimeFormat(locale, intlOpts).format(toDate(value));
|
|
77
|
+
}
|
|
78
|
+
function formatNumber(value, opts) {
|
|
79
|
+
const locale = resolveLocale(opts);
|
|
80
|
+
return new Intl.NumberFormat(locale, extractIntlOpts(opts)).format(value);
|
|
81
|
+
}
|
|
82
|
+
function formatCurrency(value, opts) {
|
|
83
|
+
const locale = resolveLocale(opts);
|
|
84
|
+
const intlOpts = {
|
|
85
|
+
style: "currency",
|
|
86
|
+
...extractIntlOpts(opts)
|
|
87
|
+
};
|
|
88
|
+
return new Intl.NumberFormat(locale, intlOpts).format(value);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// src/i18n/relative.ts
|
|
92
|
+
var SECOND = 1e3;
|
|
93
|
+
var MINUTE = 60 * SECOND;
|
|
94
|
+
var HOUR = 60 * MINUTE;
|
|
95
|
+
var DAY = 24 * HOUR;
|
|
96
|
+
var WEEK = 7 * DAY;
|
|
97
|
+
var MONTH = 30 * DAY;
|
|
98
|
+
var YEAR = 365 * DAY;
|
|
99
|
+
function toMs(value) {
|
|
100
|
+
if (value instanceof Date) return value.getTime();
|
|
101
|
+
if (typeof value === "number") return value;
|
|
102
|
+
if (typeof value === "string") return new Date(value).getTime();
|
|
103
|
+
if (typeof value === "object" && value !== null && "toDate" in value) {
|
|
104
|
+
return value.toDate(getGodxConfig().timezone).getTime();
|
|
105
|
+
}
|
|
106
|
+
throw new TypeError(`formatRelative: unsupported value ${String(value)}`);
|
|
107
|
+
}
|
|
108
|
+
function formatRelative(value, opts = {}) {
|
|
109
|
+
const locale = opts.locale ?? getGodxConfig().locale;
|
|
110
|
+
const nowMs = opts.now instanceof Date ? opts.now.getTime() : opts.now ?? Date.now();
|
|
111
|
+
const valueMs = toMs(value);
|
|
112
|
+
const diffMs = valueMs - nowMs;
|
|
113
|
+
const abs = Math.abs(diffMs);
|
|
114
|
+
let unit;
|
|
115
|
+
let amount;
|
|
116
|
+
if (abs < MINUTE) {
|
|
117
|
+
unit = "second";
|
|
118
|
+
amount = Math.round(diffMs / SECOND);
|
|
119
|
+
} else if (abs < HOUR) {
|
|
120
|
+
unit = "minute";
|
|
121
|
+
amount = Math.round(diffMs / MINUTE);
|
|
122
|
+
} else if (abs < DAY) {
|
|
123
|
+
unit = "hour";
|
|
124
|
+
amount = Math.round(diffMs / HOUR);
|
|
125
|
+
} else if (abs < WEEK) {
|
|
126
|
+
unit = "day";
|
|
127
|
+
amount = Math.round(diffMs / DAY);
|
|
128
|
+
} else if (abs < MONTH) {
|
|
129
|
+
unit = "week";
|
|
130
|
+
amount = Math.round(diffMs / WEEK);
|
|
131
|
+
} else if (abs < YEAR) {
|
|
132
|
+
unit = "month";
|
|
133
|
+
amount = Math.round(diffMs / MONTH);
|
|
134
|
+
} else {
|
|
135
|
+
unit = "year";
|
|
136
|
+
amount = Math.round(diffMs / YEAR);
|
|
137
|
+
}
|
|
138
|
+
return new Intl.RelativeTimeFormat(locale, {
|
|
139
|
+
numeric: opts.numeric ?? "auto",
|
|
140
|
+
style: opts.style ?? "long"
|
|
141
|
+
}).format(amount, unit);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// src/i18n/index.ts
|
|
145
|
+
var GODX_LOCALE_STORAGE_KEY = "godx.locale";
|
|
146
|
+
var i18n_default = i18next;
|
|
86
147
|
|
|
87
148
|
// src/hooks/useTweaks.ts
|
|
88
|
-
var STORAGE_KEY = "
|
|
149
|
+
var STORAGE_KEY = "godx.tweaks";
|
|
89
150
|
var DEFAULTS = {
|
|
90
151
|
density: "default",
|
|
91
152
|
theme: "light",
|
|
@@ -124,10 +185,11 @@ function useTweaks() {
|
|
|
124
185
|
html.lang = tweaks.locale;
|
|
125
186
|
}, [tweaks.theme, tweaks.density, tweaks.tenant, tweaks.locale]);
|
|
126
187
|
useEffect(() => {
|
|
188
|
+
if (!i18n_default.isInitialized) return;
|
|
127
189
|
if (i18n_default.language?.slice(0, 2) !== tweaks.locale) {
|
|
128
190
|
void i18n_default.changeLanguage(tweaks.locale);
|
|
129
191
|
try {
|
|
130
|
-
window.localStorage.setItem(
|
|
192
|
+
window.localStorage.setItem(GODX_LOCALE_STORAGE_KEY, tweaks.locale);
|
|
131
193
|
} catch {
|
|
132
194
|
}
|
|
133
195
|
}
|
|
@@ -137,8 +199,360 @@ function useTweaks() {
|
|
|
137
199
|
}, []);
|
|
138
200
|
return { tweaks, setTweak, setTweaks };
|
|
139
201
|
}
|
|
140
|
-
|
|
202
|
+
function productOptions(products) {
|
|
203
|
+
return products.map((p) => ({ value: p.tenant, label: p.name }));
|
|
204
|
+
}
|
|
205
|
+
var BP_ORDER = ["xxl", "xl", "lg", "md", "sm", "xs"];
|
|
206
|
+
var BP_ORDER_ASC = ["xs", "sm", "md", "lg", "xl", "xxl"];
|
|
207
|
+
var FALLBACK_WIDTH = {
|
|
208
|
+
xs: "0px",
|
|
209
|
+
sm: "640px",
|
|
210
|
+
md: "768px",
|
|
211
|
+
lg: "1024px",
|
|
212
|
+
xl: "1280px",
|
|
213
|
+
xxl: "1536px"
|
|
214
|
+
};
|
|
215
|
+
function widthOf(bp) {
|
|
216
|
+
if (typeof window === "undefined") return FALLBACK_WIDTH[bp];
|
|
217
|
+
const v = getComputedStyle(document.documentElement).getPropertyValue(`--breakpoint-${bp}`).trim();
|
|
218
|
+
return v || FALLBACK_WIDTH[bp];
|
|
219
|
+
}
|
|
220
|
+
function currentBreakpoint() {
|
|
221
|
+
if (typeof window === "undefined") return "xs";
|
|
222
|
+
for (const bp of BP_ORDER) {
|
|
223
|
+
if (window.matchMedia(`(min-width: ${widthOf(bp)})`).matches) {
|
|
224
|
+
return bp;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return "xs";
|
|
228
|
+
}
|
|
229
|
+
function useBreakpoint() {
|
|
230
|
+
const [bp, setBp] = useState(() => currentBreakpoint());
|
|
231
|
+
useEffect(() => {
|
|
232
|
+
if (typeof window === "undefined") return;
|
|
233
|
+
const mqls = BP_ORDER.map(
|
|
234
|
+
(b) => window.matchMedia(`(min-width: ${widthOf(b)})`)
|
|
235
|
+
);
|
|
236
|
+
const update = () => setBp(currentBreakpoint());
|
|
237
|
+
mqls.forEach((mql) => mql.addEventListener("change", update));
|
|
238
|
+
update();
|
|
239
|
+
return () => {
|
|
240
|
+
mqls.forEach((mql) => mql.removeEventListener("change", update));
|
|
241
|
+
};
|
|
242
|
+
}, []);
|
|
243
|
+
return bp;
|
|
244
|
+
}
|
|
245
|
+
function matchBreakpoint(current, target) {
|
|
246
|
+
return BP_ORDER_ASC.indexOf(current) >= BP_ORDER_ASC.indexOf(target);
|
|
247
|
+
}
|
|
248
|
+
function useFormatters() {
|
|
249
|
+
const { locale, timezone } = useSyncExternalStore(
|
|
250
|
+
subscribeGodxConfig,
|
|
251
|
+
getGodxConfig,
|
|
252
|
+
getGodxConfig
|
|
253
|
+
);
|
|
254
|
+
return useMemo(
|
|
255
|
+
() => ({
|
|
256
|
+
locale,
|
|
257
|
+
timezone,
|
|
258
|
+
formatDate: (value, opts) => formatDate(value, { ...opts, locale, timezone }),
|
|
259
|
+
formatTime: (value, opts) => formatTime(value, { ...opts, locale, timezone }),
|
|
260
|
+
formatDateTime: (value, opts) => formatDateTime(value, { ...opts, locale, timezone }),
|
|
261
|
+
formatRelative: (value, opts) => formatRelative(value, { ...opts, locale }),
|
|
262
|
+
formatNumber: (value, opts) => formatNumber(value, { ...opts, locale }),
|
|
263
|
+
formatCurrency: (value, opts) => formatCurrency(value, { ...opts, locale })
|
|
264
|
+
}),
|
|
265
|
+
[locale, timezone]
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
function useTablePagination(options = {}) {
|
|
269
|
+
const {
|
|
270
|
+
defaultPage = 1,
|
|
271
|
+
defaultPageSize = 20,
|
|
272
|
+
page: controlledPage,
|
|
273
|
+
pageSize: controlledPageSize,
|
|
274
|
+
onChange
|
|
275
|
+
} = options;
|
|
276
|
+
const [internalPage, setInternalPage] = useState(defaultPage);
|
|
277
|
+
const [internalPageSize, setInternalPageSize] = useState(defaultPageSize);
|
|
278
|
+
const page = controlledPage ?? internalPage;
|
|
279
|
+
const pageSize = controlledPageSize ?? internalPageSize;
|
|
280
|
+
const setPage = useCallback(
|
|
281
|
+
(nextPage) => {
|
|
282
|
+
if (controlledPage === void 0) setInternalPage(nextPage);
|
|
283
|
+
onChange?.(nextPage, pageSize);
|
|
284
|
+
},
|
|
285
|
+
[controlledPage, onChange, pageSize]
|
|
286
|
+
);
|
|
287
|
+
const setPageSize = useCallback(
|
|
288
|
+
(nextPageSize) => {
|
|
289
|
+
if (controlledPageSize === void 0) setInternalPageSize(nextPageSize);
|
|
290
|
+
if (controlledPage === void 0) setInternalPage(1);
|
|
291
|
+
onChange?.(1, nextPageSize);
|
|
292
|
+
},
|
|
293
|
+
[controlledPage, controlledPageSize, onChange]
|
|
294
|
+
);
|
|
295
|
+
const handleChange = useCallback(
|
|
296
|
+
(nextPage, nextPageSize) => {
|
|
297
|
+
if (controlledPage === void 0) setInternalPage(nextPage);
|
|
298
|
+
if (controlledPageSize === void 0) setInternalPageSize(nextPageSize);
|
|
299
|
+
onChange?.(nextPage, nextPageSize);
|
|
300
|
+
},
|
|
301
|
+
[controlledPage, controlledPageSize, onChange]
|
|
302
|
+
);
|
|
303
|
+
const resetPage = useCallback(() => {
|
|
304
|
+
if (controlledPage === void 0) setInternalPage(1);
|
|
305
|
+
onChange?.(1, pageSize);
|
|
306
|
+
}, [controlledPage, onChange, pageSize]);
|
|
307
|
+
const reset = useCallback(() => {
|
|
308
|
+
if (controlledPage === void 0) setInternalPage(defaultPage);
|
|
309
|
+
if (controlledPageSize === void 0) setInternalPageSize(defaultPageSize);
|
|
310
|
+
onChange?.(defaultPage, defaultPageSize);
|
|
311
|
+
}, [
|
|
312
|
+
controlledPage,
|
|
313
|
+
controlledPageSize,
|
|
314
|
+
defaultPage,
|
|
315
|
+
defaultPageSize,
|
|
316
|
+
onChange
|
|
317
|
+
]);
|
|
318
|
+
return {
|
|
319
|
+
page,
|
|
320
|
+
pageSize,
|
|
321
|
+
setPage,
|
|
322
|
+
setPageSize,
|
|
323
|
+
onChange: handleChange,
|
|
324
|
+
resetPage,
|
|
325
|
+
reset
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
function useTableSelection(options = {}) {
|
|
329
|
+
const {
|
|
330
|
+
mode = "multiple",
|
|
331
|
+
defaultSelected = [],
|
|
332
|
+
selected: controlledSelected,
|
|
333
|
+
onChange
|
|
334
|
+
} = options;
|
|
335
|
+
const [internal, setInternal] = useState(defaultSelected);
|
|
336
|
+
const selectedRowKeys = controlledSelected ?? internal;
|
|
337
|
+
const setSelectedRowKeys = useCallback(
|
|
338
|
+
(next) => {
|
|
339
|
+
if (controlledSelected === void 0) setInternal(next);
|
|
340
|
+
onChange?.(next);
|
|
341
|
+
},
|
|
342
|
+
[controlledSelected, onChange]
|
|
343
|
+
);
|
|
344
|
+
const select = useCallback(
|
|
345
|
+
(key) => {
|
|
346
|
+
const next = mode === "single" ? [key] : selectedRowKeys.includes(key) ? selectedRowKeys : [...selectedRowKeys, key];
|
|
347
|
+
if (next === selectedRowKeys) return;
|
|
348
|
+
setSelectedRowKeys(next);
|
|
349
|
+
},
|
|
350
|
+
[mode, selectedRowKeys, setSelectedRowKeys]
|
|
351
|
+
);
|
|
352
|
+
const deselect = useCallback(
|
|
353
|
+
(key) => {
|
|
354
|
+
if (!selectedRowKeys.includes(key)) return;
|
|
355
|
+
setSelectedRowKeys(selectedRowKeys.filter((k) => k !== key));
|
|
356
|
+
},
|
|
357
|
+
[selectedRowKeys, setSelectedRowKeys]
|
|
358
|
+
);
|
|
359
|
+
const toggle = useCallback(
|
|
360
|
+
(key) => {
|
|
361
|
+
if (selectedRowKeys.includes(key)) {
|
|
362
|
+
setSelectedRowKeys(selectedRowKeys.filter((k) => k !== key));
|
|
363
|
+
} else {
|
|
364
|
+
setSelectedRowKeys(mode === "single" ? [key] : [...selectedRowKeys, key]);
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
[mode, selectedRowKeys, setSelectedRowKeys]
|
|
368
|
+
);
|
|
369
|
+
const clear = useCallback(() => {
|
|
370
|
+
if (selectedRowKeys.length === 0) return;
|
|
371
|
+
setSelectedRowKeys([]);
|
|
372
|
+
}, [selectedRowKeys.length, setSelectedRowKeys]);
|
|
373
|
+
const isSelected = useCallback(
|
|
374
|
+
(key) => selectedRowKeys.includes(key),
|
|
375
|
+
[selectedRowKeys]
|
|
376
|
+
);
|
|
377
|
+
return {
|
|
378
|
+
selectedRowKeys,
|
|
379
|
+
setSelectedRowKeys,
|
|
380
|
+
toggle,
|
|
381
|
+
select,
|
|
382
|
+
deselect,
|
|
383
|
+
clear,
|
|
384
|
+
isSelected,
|
|
385
|
+
count: selectedRowKeys.length
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
function readPersisted(storage, storageKey, currentVersion, migrate) {
|
|
389
|
+
if (!storage) return void 0;
|
|
390
|
+
try {
|
|
391
|
+
const raw = storage.getItem(storageKey);
|
|
392
|
+
if (raw === null) return void 0;
|
|
393
|
+
const parsed = JSON.parse(raw);
|
|
394
|
+
if (typeof parsed !== "object" || parsed === null) return void 0;
|
|
395
|
+
const envelope = parsed;
|
|
396
|
+
if (typeof envelope.version !== "number" || !("value" in envelope))
|
|
397
|
+
return void 0;
|
|
398
|
+
if (envelope.version === currentVersion) return envelope.value;
|
|
399
|
+
if (migrate)
|
|
400
|
+
return migrate({
|
|
401
|
+
version: envelope.version,
|
|
402
|
+
value: envelope.value
|
|
403
|
+
});
|
|
404
|
+
return void 0;
|
|
405
|
+
} catch {
|
|
406
|
+
return void 0;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
function writePersisted(storage, storageKey, version, value) {
|
|
410
|
+
if (!storage) return;
|
|
411
|
+
try {
|
|
412
|
+
storage.setItem(
|
|
413
|
+
storageKey,
|
|
414
|
+
JSON.stringify({ version, value })
|
|
415
|
+
);
|
|
416
|
+
} catch {
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
function resolveStorage(override) {
|
|
420
|
+
if (override !== void 0) return override;
|
|
421
|
+
if (typeof window === "undefined") return null;
|
|
422
|
+
try {
|
|
423
|
+
return window.localStorage;
|
|
424
|
+
} catch {
|
|
425
|
+
return null;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
function useTableState(options) {
|
|
429
|
+
const {
|
|
430
|
+
storageKey,
|
|
431
|
+
defaultValue,
|
|
432
|
+
version = 1,
|
|
433
|
+
migrate,
|
|
434
|
+
storage: storageOverride
|
|
435
|
+
} = options;
|
|
436
|
+
const storage = resolveStorage(storageOverride);
|
|
437
|
+
const [value, setValue] = useState(() => {
|
|
438
|
+
if (storageKey === void 0) return defaultValue;
|
|
439
|
+
const persisted = readPersisted(storage, storageKey, version, migrate);
|
|
440
|
+
return persisted !== void 0 ? persisted : defaultValue;
|
|
441
|
+
});
|
|
442
|
+
useEffect(() => {
|
|
443
|
+
if (storageKey === void 0) return;
|
|
444
|
+
writePersisted(storage, storageKey, version, value);
|
|
445
|
+
}, [storage, storageKey, value, version]);
|
|
446
|
+
const setNext = useCallback(
|
|
447
|
+
(next) => {
|
|
448
|
+
setValue(
|
|
449
|
+
(prev) => typeof next === "function" ? next(prev) : next
|
|
450
|
+
);
|
|
451
|
+
},
|
|
452
|
+
[]
|
|
453
|
+
);
|
|
454
|
+
return [value, setNext];
|
|
455
|
+
}
|
|
456
|
+
var CUSTOM_KEY = "custom";
|
|
457
|
+
function isPersistableLabel(label) {
|
|
458
|
+
return typeof label === "string";
|
|
459
|
+
}
|
|
460
|
+
function generateKey() {
|
|
461
|
+
if (typeof crypto !== "undefined" && "randomUUID" in crypto) {
|
|
462
|
+
return `view-${crypto.randomUUID()}`;
|
|
463
|
+
}
|
|
464
|
+
return `view-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
465
|
+
}
|
|
466
|
+
function useTableViews(options) {
|
|
467
|
+
const {
|
|
468
|
+
items: builtInItems,
|
|
469
|
+
defaultActive,
|
|
470
|
+
activeKey: controlledActiveKey,
|
|
471
|
+
onActiveKeyChange,
|
|
472
|
+
onSavedViewsChange,
|
|
473
|
+
storageKey,
|
|
474
|
+
maxSavedViews = 20
|
|
475
|
+
} = options;
|
|
476
|
+
const [internalActiveKey, setInternalActiveKey] = useState(
|
|
477
|
+
defaultActive ?? builtInItems[0]?.key
|
|
478
|
+
);
|
|
479
|
+
const activeKey = controlledActiveKey ?? internalActiveKey;
|
|
480
|
+
const [savedViews, setSavedViewsState] = useTableState({
|
|
481
|
+
storageKey,
|
|
482
|
+
defaultValue: [],
|
|
483
|
+
version: 1
|
|
484
|
+
});
|
|
485
|
+
const updateSavedViews = useCallback(
|
|
486
|
+
(next) => {
|
|
487
|
+
setSavedViewsState((prev) => {
|
|
488
|
+
const resolved = typeof next === "function" ? next(prev) : next;
|
|
489
|
+
const trimmed = resolved.slice(-maxSavedViews);
|
|
490
|
+
onSavedViewsChange?.(trimmed);
|
|
491
|
+
return trimmed;
|
|
492
|
+
});
|
|
493
|
+
},
|
|
494
|
+
[maxSavedViews, onSavedViewsChange, setSavedViewsState]
|
|
495
|
+
);
|
|
496
|
+
const setActiveKey = useCallback(
|
|
497
|
+
(key) => {
|
|
498
|
+
if (controlledActiveKey === void 0) setInternalActiveKey(key);
|
|
499
|
+
onActiveKeyChange?.(key);
|
|
500
|
+
},
|
|
501
|
+
[controlledActiveKey, onActiveKeyChange]
|
|
502
|
+
);
|
|
503
|
+
const applyView = useCallback(
|
|
504
|
+
(view) => {
|
|
505
|
+
setActiveKey(view.key);
|
|
506
|
+
return {
|
|
507
|
+
filters: view.filters,
|
|
508
|
+
sort: view.sort,
|
|
509
|
+
columnVisibility: view.columnVisibility
|
|
510
|
+
};
|
|
511
|
+
},
|
|
512
|
+
[setActiveKey]
|
|
513
|
+
);
|
|
514
|
+
const saveView = useCallback(
|
|
515
|
+
(label, snapshot) => {
|
|
516
|
+
const next = {
|
|
517
|
+
key: generateKey(),
|
|
518
|
+
label,
|
|
519
|
+
...snapshot,
|
|
520
|
+
deletable: true
|
|
521
|
+
};
|
|
522
|
+
updateSavedViews((prev) => [...prev, next]);
|
|
523
|
+
setActiveKey(next.key);
|
|
524
|
+
return next;
|
|
525
|
+
},
|
|
526
|
+
[setActiveKey, updateSavedViews]
|
|
527
|
+
);
|
|
528
|
+
const deleteView = useCallback(
|
|
529
|
+
(key) => {
|
|
530
|
+
const target = savedViews.find((view) => view.key === key);
|
|
531
|
+
if (!target || !isPersistableLabel(target.label)) return;
|
|
532
|
+
updateSavedViews((prev) => prev.filter((view) => view.key !== key));
|
|
533
|
+
if (activeKey === key) {
|
|
534
|
+
const firstBuiltIn = builtInItems[0]?.key;
|
|
535
|
+
if (firstBuiltIn !== void 0) setActiveKey(firstBuiltIn);
|
|
536
|
+
}
|
|
537
|
+
},
|
|
538
|
+
[activeKey, builtInItems, savedViews, setActiveKey, updateSavedViews]
|
|
539
|
+
);
|
|
540
|
+
const markCustom = useCallback(() => {
|
|
541
|
+
if (activeKey === CUSTOM_KEY) return;
|
|
542
|
+
setActiveKey(CUSTOM_KEY);
|
|
543
|
+
}, [activeKey, setActiveKey]);
|
|
544
|
+
return {
|
|
545
|
+
items: [...builtInItems, ...savedViews],
|
|
546
|
+
savedViews,
|
|
547
|
+
activeKey,
|
|
548
|
+
setActiveKey,
|
|
549
|
+
applyView,
|
|
550
|
+
saveView,
|
|
551
|
+
deleteView,
|
|
552
|
+
markCustom
|
|
553
|
+
};
|
|
554
|
+
}
|
|
141
555
|
|
|
142
|
-
export {
|
|
556
|
+
export { matchBreakpoint, productOptions, useBreakpoint, useFormatters, useTablePagination, useTableSelection, useTableState, useTableViews, useTweaks };
|
|
143
557
|
//# sourceMappingURL=hooks.js.map
|
|
144
558
|
//# sourceMappingURL=hooks.js.map
|