akanjs 2.4.2-rc.2 → 3.0.0-alpha.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/base/baseEnv.ts +0 -6
- package/client/cn.ts +52 -0
- package/client/csrTypes.ts +2 -2
- package/client/frameConfig.ts +2 -2
- package/client/index.ts +1 -0
- package/client/types.ts +0 -4
- package/common/fileUpload.ts +1 -1
- package/common/index.ts +1 -0
- package/common/isThenable.ts +12 -0
- package/constant/purify.ts +9 -10
- package/fetch/client/fetchClient.ts +1 -1
- package/fetch/client/httpClient.ts +9 -5
- package/fetch/fetchType/sliceFetch.type.ts +1 -1
- package/package.json +4 -7
- package/server/akanApp.ts +2 -0
- package/server/systemPageDocument.tsx +12 -12
- package/signal/endpointInfo.ts +2 -1
- package/signal/slice.ts +1 -1
- package/signal/sliceInfo.ts +2 -1
- package/store/action.ts +18 -2
- package/store/baseSt.ts +2 -2
- package/store/state.ts +9 -1
- package/store/storeInstance.ts +2 -0
- package/test/sampleOf.ts +3 -3
- package/test/signalTestRuntime.ts +0 -2
- package/types/base/baseEnv.d.ts +0 -2
- package/types/client/cn.d.ts +12 -0
- package/types/client/index.d.ts +1 -0
- package/types/client/types.d.ts +0 -3
- package/types/common/fileUpload.d.ts +1 -1
- package/types/common/index.d.ts +1 -0
- package/types/common/isThenable.d.ts +9 -0
- package/types/constant/purify.d.ts +3 -2
- package/types/fetch/fetchType/sliceFetch.type.d.ts +1 -1
- package/types/signal/endpointInfo.d.ts +2 -2
- package/types/signal/slice.d.ts +1 -1
- package/types/signal/sliceInfo.d.ts +2 -2
- package/types/store/action.d.ts +1 -1
- package/types/store/state.d.ts +4 -2
- package/types/test/sampleOf.d.ts +2 -2
- package/types/ui/Badge.d.ts +6 -0
- package/types/ui/Button.d.ts +26 -6
- package/types/ui/Load/Units.d.ts +3 -1
- package/types/ui/RecentTime.d.ts +1 -1
- package/types/ui/Signal/Collapse.d.ts +12 -0
- package/types/ui/Signal/style.d.ts +5 -6
- package/types/ui/Switch.d.ts +14 -0
- package/types/ui/Tooltip.d.ts +11 -0
- package/types/ui/UiOverride/Provider.d.ts +6 -5
- package/types/ui/UiOverride/context.d.ts +22 -1
- package/types/ui/UiOverride/index.d.ts +2 -1
- package/types/ui/UiOverride/override.d.ts +7 -6
- package/types/ui/UiOverride/useUiRecipe.d.ts +8 -0
- package/types/ui/index.d.ts +5 -1
- package/types/ui/recipe/badgeRecipe.d.ts +13 -0
- package/types/ui/recipe/buttonRecipe.d.ts +15 -0
- package/types/ui/recipe/factory.d.ts +24 -0
- package/types/ui/recipe/index.d.ts +18 -0
- package/types/ui/recipe/inputRecipe.d.ts +13 -0
- package/types/ui/recipe.d.ts +1 -0
- package/ui/Badge.tsx +17 -0
- package/ui/BottomSheet.tsx +8 -10
- package/ui/Button.tsx +158 -48
- package/ui/Clipboard.tsx +3 -3
- package/ui/Constant/Doc.tsx +108 -65
- package/ui/Constant/Mermaid.tsx +9 -9
- package/ui/Data/CardList.tsx +3 -3
- package/ui/Data/Dashboard.tsx +22 -13
- package/ui/Data/Insight.tsx +6 -6
- package/ui/Data/Item.tsx +49 -34
- package/ui/Data/ListContainer.tsx +11 -7
- package/ui/Data/Pagination.tsx +2 -2
- package/ui/DatePicker.tsx +5 -5
- package/ui/Dialog/Content.tsx +2 -2
- package/ui/Dialog/Modal.tsx +12 -8
- package/ui/Dialog/Provider.tsx +2 -2
- package/ui/DragAction.tsx +2 -2
- package/ui/DraggableList.tsx +10 -5
- package/ui/Dropdown.tsx +33 -26
- package/ui/Empty.tsx +5 -5
- package/ui/Field.tsx +82 -70
- package/ui/Image.tsx +2 -2
- package/ui/Input.tsx +62 -60
- package/ui/Layout/BottomInset.tsx +2 -2
- package/ui/Layout/BottomTab.tsx +5 -5
- package/ui/Layout/Header.tsx +3 -3
- package/ui/Layout/LeftSider.tsx +6 -5
- package/ui/Layout/Navbar.tsx +2 -12
- package/ui/Layout/RightSider.tsx +10 -8
- package/ui/Layout/Sider.tsx +5 -4
- package/ui/Layout/Template.tsx +2 -2
- package/ui/Layout/TopInset.tsx +2 -2
- package/ui/Layout/Unit.tsx +2 -2
- package/ui/Layout/View.tsx +2 -2
- package/ui/Layout/Zone.tsx +2 -2
- package/ui/Link/Back.tsx +2 -2
- package/ui/Link/Close.tsx +2 -2
- package/ui/Link/CsrLink.tsx +6 -4
- package/ui/Link/Lang.tsx +2 -2
- package/ui/Link/SsrLink.tsx +6 -5
- package/ui/Load/Page.tsx +1 -1
- package/ui/Load/Pagination.tsx +2 -2
- package/ui/Load/Units.tsx +19 -4
- package/ui/Load/View.tsx +2 -2
- package/ui/Loading/Area.tsx +4 -2
- package/ui/Loading/Button.tsx +2 -2
- package/ui/Loading/Input.tsx +2 -2
- package/ui/Loading/ProgressBar.tsx +2 -2
- package/ui/Loading/Skeleton.tsx +6 -6
- package/ui/Loading/Spin.tsx +2 -2
- package/ui/Menu.tsx +29 -27
- package/ui/Model/Edit.tsx +3 -3
- package/ui/Model/EditModal.tsx +5 -5
- package/ui/Model/EditWrapper.tsx +2 -2
- package/ui/Model/New.tsx +3 -3
- package/ui/Model/NewWrapper_Client.tsx +2 -2
- package/ui/Model/Remove.tsx +5 -4
- package/ui/Model/RemoveWrapper.tsx +2 -2
- package/ui/Model/SureToRemove.tsx +7 -6
- package/ui/Model/View.tsx +2 -2
- package/ui/Model/ViewEditModal.tsx +20 -21
- package/ui/Model/ViewWrapper.tsx +2 -2
- package/ui/More.tsx +2 -2
- package/ui/ObjectId.tsx +9 -3
- package/ui/Pagination.tsx +14 -11
- package/ui/Popconfirm.tsx +20 -11
- package/ui/Radio.tsx +4 -4
- package/ui/RecentTime.tsx +30 -83
- package/ui/Refresh.tsx +1 -1
- package/ui/ScreenNavigator.tsx +2 -2
- package/ui/Select.tsx +21 -23
- package/ui/Signal/Arg.tsx +21 -18
- package/ui/Signal/Collapse.tsx +29 -0
- package/ui/Signal/Doc.tsx +27 -22
- package/ui/Signal/Listener.tsx +3 -3
- package/ui/Signal/Message.tsx +31 -17
- package/ui/Signal/Object.tsx +13 -8
- package/ui/Signal/PubSub.tsx +26 -16
- package/ui/Signal/Request.tsx +3 -2
- package/ui/Signal/Response.tsx +5 -4
- package/ui/Signal/RestApi.tsx +27 -17
- package/ui/Signal/style.ts +16 -16
- package/ui/Switch.tsx +62 -0
- package/ui/System/CSR.tsx +40 -35
- package/ui/System/Client.tsx +2 -2
- package/ui/System/DevModeToggle.tsx +10 -12
- package/ui/System/Messages.tsx +14 -16
- package/ui/System/Reconnect.tsx +7 -7
- package/ui/System/SSR.tsx +25 -21
- package/ui/System/SelectLanguage.tsx +24 -28
- package/ui/System/ThemeToggle.tsx +38 -45
- package/ui/Tab/Menu.tsx +20 -18
- package/ui/Tab/Panel.tsx +3 -3
- package/ui/Tab/Provider.tsx +2 -2
- package/ui/Table.tsx +11 -8
- package/ui/ToggleSelect.tsx +14 -18
- package/ui/Tooltip.tsx +55 -0
- package/ui/UiOverride/Provider.tsx +10 -6
- package/ui/UiOverride/context.ts +22 -2
- package/ui/UiOverride/index.ts +8 -1
- package/ui/UiOverride/override.ts +7 -6
- package/ui/UiOverride/useUiRecipe.ts +15 -0
- package/ui/Unauthorized.tsx +5 -5
- package/ui/index.ts +16 -0
- package/ui/recipe/badgeRecipe.ts +23 -0
- package/ui/recipe/buttonRecipe.ts +32 -0
- package/ui/recipe/factory.ts +32 -0
- package/ui/recipe/index.ts +18 -0
- package/ui/recipe/inputRecipe.ts +13 -0
- package/ui/styles.css +150 -21
package/ui/Data/Item.tsx
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import type { Dayjs } from "akanjs/base";
|
|
3
|
-
import {
|
|
3
|
+
import { cn, type DataAction, type DataColumn, usePage } from "akanjs/client";
|
|
4
4
|
import { capitalize } from "akanjs/common";
|
|
5
5
|
import type { BaseObject } from "akanjs/constant";
|
|
6
6
|
import type { SliceMeta } from "akanjs/fetch";
|
|
7
7
|
import { st } from "akanjs/store";
|
|
8
8
|
import type { ReactNode } from "react";
|
|
9
9
|
import { AiOutlineDelete, AiOutlineEdit, AiOutlineEye, AiOutlineMore } from "react-icons/ai";
|
|
10
|
+
import { badgeRecipe } from "../Badge";
|
|
11
|
+
import { buttonRecipe } from "../Button";
|
|
10
12
|
import { Dropdown } from "../Dropdown";
|
|
11
13
|
import { ObjectId } from "../ObjectId";
|
|
12
14
|
import { Popconfirm } from "../Popconfirm";
|
|
@@ -129,7 +131,7 @@ export default function Item<T extends string, Full extends { id: string }, Ligh
|
|
|
129
131
|
});
|
|
130
132
|
|
|
131
133
|
return (
|
|
132
|
-
<div className={
|
|
134
|
+
<div className={cn("flex flex-col", className)}>
|
|
133
135
|
{children ? (
|
|
134
136
|
<div className="flex justify-center">
|
|
135
137
|
<div className="relative size-full" onClick={onClick}>
|
|
@@ -143,16 +145,14 @@ export default function Item<T extends string, Full extends { id: string }, Ligh
|
|
|
143
145
|
) : null}
|
|
144
146
|
<div className="mt-2 h-full rounded-lg bg-primary/5 p-2">
|
|
145
147
|
<div className="mb-2 flex justify-between">
|
|
146
|
-
<div
|
|
147
|
-
{columns.find((c) => c === "id") && <ObjectId id={model.id} />}
|
|
148
|
-
</div>
|
|
148
|
+
<div>{columns.find((c) => c === "id") && <ObjectId id={model.id} />}</div>
|
|
149
149
|
|
|
150
150
|
<div className="flex items-end justify-center gap-2">
|
|
151
151
|
{columns.find((c) => c === "createdAt") && (
|
|
152
152
|
<RecentTime date={(model as unknown as BaseObject).createdAt} className="text-xs opacity-60" />
|
|
153
153
|
)}
|
|
154
154
|
{columns.find((c) => c === "status") && (
|
|
155
|
-
<StatusTag status={(model as unknown as { status: string }).status} className="
|
|
155
|
+
<StatusTag status={(model as unknown as { status: string }).status} className="mr-0 p-2" />
|
|
156
156
|
)}
|
|
157
157
|
</div>
|
|
158
158
|
</div>
|
|
@@ -165,7 +165,7 @@ export default function Item<T extends string, Full extends { id: string }, Ligh
|
|
|
165
165
|
))}
|
|
166
166
|
{customActions.length ? (
|
|
167
167
|
<Dropdown
|
|
168
|
-
buttonClassName="
|
|
168
|
+
buttonClassName={buttonRecipe({ variant: "ghost", size: "icon" }, "m-1 size-8 text-center")}
|
|
169
169
|
value={<AiOutlineMore />}
|
|
170
170
|
content={customActions.map((action) => <div key={action.key}>{action.label}</div>)}
|
|
171
171
|
/>
|
|
@@ -205,14 +205,20 @@ export const Action = <T extends string, M extends { id: string }, L extends { i
|
|
|
205
205
|
};
|
|
206
206
|
return action === "edit" ? (
|
|
207
207
|
<button
|
|
208
|
-
className={
|
|
208
|
+
className={buttonRecipe({ variant: outline ? "outline" : "ghost", size: "icon" }, [
|
|
209
|
+
"m-1 size-8 text-center",
|
|
210
|
+
outline && "border-dashed",
|
|
211
|
+
])}
|
|
209
212
|
onClick={() => void storeDo[namesOfSlice.editModel](model.id)}
|
|
210
213
|
>
|
|
211
214
|
<AiOutlineEdit key={action} />
|
|
212
215
|
</button>
|
|
213
216
|
) : action === "view" ? (
|
|
214
217
|
<button
|
|
215
|
-
className={
|
|
218
|
+
className={buttonRecipe({ variant: outline ? "outline" : "ghost", size: "icon" }, [
|
|
219
|
+
"m-1 size-8 text-center",
|
|
220
|
+
outline && "border-dashed",
|
|
221
|
+
])}
|
|
216
222
|
onClick={() => void storeDo[namesOfSlice.viewModel](model.id)}
|
|
217
223
|
>
|
|
218
224
|
<AiOutlineEye key={action} />
|
|
@@ -223,7 +229,12 @@ export const Action = <T extends string, M extends { id: string }, L extends { i
|
|
|
223
229
|
title={l("base.removeMsg")}
|
|
224
230
|
onConfirm={() => void storeDo[namesOfSlice.removeModel](model.id)}
|
|
225
231
|
>
|
|
226
|
-
<button
|
|
232
|
+
<button
|
|
233
|
+
className={buttonRecipe({ variant: outline ? "outline" : "ghost", size: "icon" }, [
|
|
234
|
+
"m-1 size-8 text-center",
|
|
235
|
+
outline && "border-dashed",
|
|
236
|
+
])}
|
|
237
|
+
>
|
|
227
238
|
<AiOutlineDelete />
|
|
228
239
|
</button>
|
|
229
240
|
</Popconfirm>
|
|
@@ -233,28 +244,29 @@ export const Action = <T extends string, M extends { id: string }, L extends { i
|
|
|
233
244
|
};
|
|
234
245
|
|
|
235
246
|
const statusColors = {
|
|
236
|
-
active: "
|
|
237
|
-
applied: "
|
|
238
|
-
approved: "
|
|
239
|
-
denied: "
|
|
240
|
-
failed: "
|
|
241
|
-
restricted: "
|
|
242
|
-
paused: "
|
|
243
|
-
running: "
|
|
244
|
-
break: "
|
|
245
|
-
rejected: "
|
|
246
|
-
hidden: "
|
|
247
|
-
inProgress: "
|
|
248
|
-
resolved: "
|
|
249
|
-
finished: "
|
|
247
|
+
active: "border-info text-info",
|
|
248
|
+
applied: "border-transparent bg-warning text-warning-foreground",
|
|
249
|
+
approved: "border-transparent bg-success text-success-foreground",
|
|
250
|
+
denied: "border-destructive text-destructive",
|
|
251
|
+
failed: "border-destructive text-destructive",
|
|
252
|
+
restricted: "border-transparent bg-destructive text-destructive-foreground",
|
|
253
|
+
paused: "",
|
|
254
|
+
running: "border-warning text-warning",
|
|
255
|
+
break: "border-accent text-accent",
|
|
256
|
+
rejected: "border-destructive text-destructive",
|
|
257
|
+
hidden: "",
|
|
258
|
+
inProgress: "border-transparent bg-accent text-accent-foreground",
|
|
259
|
+
resolved: "border-success text-success",
|
|
260
|
+
finished: "border-transparent bg-secondary text-secondary-foreground",
|
|
250
261
|
};
|
|
251
262
|
const StatusTag = ({ status, className }: { status: string; className?: string }) => {
|
|
252
263
|
return (
|
|
253
264
|
<div
|
|
254
|
-
className={
|
|
255
|
-
|
|
265
|
+
className={badgeRecipe({ variant: "outline" }, [
|
|
266
|
+
"mr-1 p-3",
|
|
267
|
+
statusColors[status as keyof typeof statusColors] ?? "",
|
|
256
268
|
className,
|
|
257
|
-
)}
|
|
269
|
+
])}
|
|
258
270
|
>
|
|
259
271
|
{status}
|
|
260
272
|
</div>
|
|
@@ -263,21 +275,24 @@ const StatusTag = ({ status, className }: { status: string; className?: string }
|
|
|
263
275
|
Item.StatusTag = StatusTag;
|
|
264
276
|
|
|
265
277
|
const roleColors = {
|
|
266
|
-
user: "
|
|
267
|
-
business: "
|
|
268
|
-
admin: "
|
|
269
|
-
superAdmin: "
|
|
270
|
-
root: "
|
|
278
|
+
user: "border-transparent bg-success text-success-foreground",
|
|
279
|
+
business: "border-transparent bg-warning text-warning-foreground",
|
|
280
|
+
admin: "border-destructive text-destructive",
|
|
281
|
+
superAdmin: "border-transparent bg-destructive text-destructive-foreground",
|
|
282
|
+
root: "border-transparent bg-primary text-primary-foreground",
|
|
271
283
|
};
|
|
272
284
|
const RoleTags = ({ role }: { role: string | string[] }) => {
|
|
273
285
|
return Array.isArray(role) ? (
|
|
274
286
|
role.map((role) => (
|
|
275
|
-
<div
|
|
287
|
+
<div
|
|
288
|
+
className={badgeRecipe({ variant: "outline" }, ["mr-1", roleColors[role as keyof typeof roleColors]])}
|
|
289
|
+
key={role}
|
|
290
|
+
>
|
|
276
291
|
{role}
|
|
277
292
|
</div>
|
|
278
293
|
))
|
|
279
294
|
) : (
|
|
280
|
-
<div className="
|
|
295
|
+
<div className={badgeRecipe({ variant: "outline" }, ["mr-1", roleColors[role as keyof typeof roleColors]])}>
|
|
281
296
|
{role}
|
|
282
297
|
</div>
|
|
283
298
|
);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import type { DataList } from "akanjs/base";
|
|
3
3
|
import {
|
|
4
|
-
|
|
4
|
+
cn,
|
|
5
5
|
type DataAction,
|
|
6
6
|
type DataColumn,
|
|
7
7
|
type DataTool,
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
AiOutlineRedo,
|
|
24
24
|
} from "react-icons/ai";
|
|
25
25
|
|
|
26
|
+
import { buttonRecipe } from "../Button";
|
|
26
27
|
import { Dropdown } from "../Dropdown";
|
|
27
28
|
import { Loading } from "../Loading";
|
|
28
29
|
import { Model } from "../Model";
|
|
@@ -191,7 +192,7 @@ export default function ListContainer<
|
|
|
191
192
|
key: "export-csv",
|
|
192
193
|
render: () => (
|
|
193
194
|
<div
|
|
194
|
-
className="
|
|
195
|
+
className={buttonRecipe({ variant: "ghost", size: "sm" }, "flex flex-nowrap justify-start gap-2")}
|
|
195
196
|
onClick={() => {
|
|
196
197
|
const header = columns
|
|
197
198
|
.map((column) => {
|
|
@@ -225,7 +226,7 @@ export default function ListContainer<
|
|
|
225
226
|
{
|
|
226
227
|
render: () => (
|
|
227
228
|
<div
|
|
228
|
-
className="
|
|
229
|
+
className={buttonRecipe({ variant: "ghost", size: "sm" }, "flex flex-nowrap justify-start gap-2")}
|
|
229
230
|
onClick={() => {
|
|
230
231
|
const json = JSON.stringify(deepObjectify([...modelList], { serializable: true }));
|
|
231
232
|
const blob = new Blob([json], { type: "application/json" });
|
|
@@ -240,7 +241,10 @@ export default function ListContainer<
|
|
|
240
241
|
];
|
|
241
242
|
return (
|
|
242
243
|
<Dropdown
|
|
243
|
-
buttonClassName={
|
|
244
|
+
buttonClassName={buttonRecipe(
|
|
245
|
+
{ variant: "primary", size: "sm" },
|
|
246
|
+
renderTemplate && create ? "rounded-l-none" : "",
|
|
247
|
+
)}
|
|
244
248
|
value={<AiOutlineEllipsis />}
|
|
245
249
|
content={toolList.map((tool) => <tool.render key={tool.key} />)}
|
|
246
250
|
/>
|
|
@@ -261,7 +265,7 @@ export default function ListContainer<
|
|
|
261
265
|
);
|
|
262
266
|
};
|
|
263
267
|
return (
|
|
264
|
-
<div className={
|
|
268
|
+
<div className={cn("m-4", className)}>
|
|
265
269
|
<div className="mb-3 flex flex-wrap justify-between">
|
|
266
270
|
<div className="flex pb-1">
|
|
267
271
|
<p className="prose text-lg">
|
|
@@ -271,7 +275,7 @@ export default function ListContainer<
|
|
|
271
275
|
{renderTemplate && create ? (
|
|
272
276
|
<button
|
|
273
277
|
onClick={() => void storeDo[namesOfSlice.newModel]()}
|
|
274
|
-
className={
|
|
278
|
+
className={buttonRecipe({ variant: "primary", size: "sm" }, "mr-[0.5px] rounded-r-none")}
|
|
275
279
|
>
|
|
276
280
|
<AiOutlinePlus /> {l("base.new")}
|
|
277
281
|
</button>
|
|
@@ -281,7 +285,7 @@ export default function ListContainer<
|
|
|
281
285
|
</div>
|
|
282
286
|
<div className="flex">
|
|
283
287
|
<button
|
|
284
|
-
className="
|
|
288
|
+
className={buttonRecipe({ variant: "primary", size: "icon" }, "mx-1 size-8")}
|
|
285
289
|
onClick={() => void storeDo[namesOfSlice.refreshModel]()}
|
|
286
290
|
>
|
|
287
291
|
<AiOutlineRedo className="mx-2" />
|
package/ui/Data/Pagination.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { cn } from "akanjs/client";
|
|
3
3
|
import { capitalize } from "akanjs/common";
|
|
4
4
|
import type { BaseInsight } from "akanjs/constant";
|
|
5
5
|
import type { SliceMeta } from "akanjs/fetch";
|
|
@@ -39,7 +39,7 @@ export default function Pagination<T extends string>({ className, slice }: Pagin
|
|
|
39
39
|
const lastPageOfModel = storeUse[namesOfSlice.lastPageOfModel]() as number;
|
|
40
40
|
const pageOfModel = storeUse[namesOfSlice.pageOfModel]() as number;
|
|
41
41
|
return (
|
|
42
|
-
<div className={
|
|
42
|
+
<div className={cn("mt-4 flex flex-wrap justify-center", className)}>
|
|
43
43
|
<Pagn
|
|
44
44
|
currentPage={pageOfModel}
|
|
45
45
|
|
package/ui/DatePicker.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { type Dayjs, dayjs } from "akanjs/base";
|
|
3
|
-
import {
|
|
3
|
+
import { cn, msg } from "akanjs/client";
|
|
4
4
|
import { lazy } from "akanjs/webkit";
|
|
5
5
|
import { type FocusEvent, useEffect, useRef } from "react";
|
|
6
6
|
import { AiOutlineSwapRight } from "react-icons/ai";
|
|
@@ -58,7 +58,7 @@ const DefaultDatePicker = ({
|
|
|
58
58
|
|
|
59
59
|
return (
|
|
60
60
|
<ReactDatePicker
|
|
61
|
-
className={
|
|
61
|
+
className={cn("input text-center", className)}
|
|
62
62
|
selected={value ? value.toDate() : new Date()}
|
|
63
63
|
disabledKeyboardNavigation
|
|
64
64
|
onFocus={(e: FocusEvent<HTMLInputElement>) => {
|
|
@@ -112,7 +112,7 @@ const DefaultRangePicker = ({
|
|
|
112
112
|
|
|
113
113
|
const pickerClassName = "m-0 input focus:outline-hidden z-50 p-3 text-center h-full w-full ";
|
|
114
114
|
return (
|
|
115
|
-
<div className={
|
|
115
|
+
<div className={cn("input flex h-full w-fit items-center gap-2 p-0", className)}>
|
|
116
116
|
<ReactDatePicker
|
|
117
117
|
className={pickerClassName}
|
|
118
118
|
selected={value[0] ? value[0].toDate() : undefined}
|
|
@@ -125,7 +125,7 @@ const DefaultRangePicker = ({
|
|
|
125
125
|
filterDate={(date: Date) => (!disabledDate?.(dayjs(date)) ? true : false)}
|
|
126
126
|
dateFormat={format}
|
|
127
127
|
/>
|
|
128
|
-
<AiOutlineSwapRight className="text-3xl text-
|
|
128
|
+
<AiOutlineSwapRight className="text-3xl text-muted-foreground" />
|
|
129
129
|
<ReactDatePicker
|
|
130
130
|
className={pickerClassName}
|
|
131
131
|
selected={value[1] ? value[1].toDate() : undefined}
|
|
@@ -174,7 +174,7 @@ const DefaultTimePicker = ({
|
|
|
174
174
|
return (
|
|
175
175
|
<ReactDatePicker
|
|
176
176
|
wrapperClassName="inline-block"
|
|
177
|
-
className={
|
|
177
|
+
className={cn("inline-block w-auto", className)}
|
|
178
178
|
selected={value ? value.toDate() : new Date()}
|
|
179
179
|
onChange={handleDateChange}
|
|
180
180
|
showTimeSelect
|
package/ui/Dialog/Content.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { cn } from "akanjs/client";
|
|
3
3
|
import type { ReactNode } from "react";
|
|
4
4
|
|
|
5
5
|
export interface ContentProps {
|
|
@@ -7,5 +7,5 @@ export interface ContentProps {
|
|
|
7
7
|
children?: ReactNode;
|
|
8
8
|
}
|
|
9
9
|
export const Content = ({ className, children }: ContentProps) => {
|
|
10
|
-
return <div className={
|
|
10
|
+
return <div className={cn("block w-full", className)}>{children}</div>;
|
|
11
11
|
};
|
package/ui/Dialog/Modal.tsx
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useDrag } from "@use-gesture/react";
|
|
3
|
-
import {
|
|
3
|
+
import { cn, usePage } from "akanjs/client";
|
|
4
4
|
import { animated } from "akanjs/ui";
|
|
5
5
|
import { type ReactNode, useCallback, useContext, useEffect, useId, useRef, useState } from "react";
|
|
6
6
|
import { createPortal } from "react-dom";
|
|
7
7
|
import { BiX } from "react-icons/bi";
|
|
8
8
|
import { config, useSpring } from "react-spring";
|
|
9
|
+
import { buttonRecipe } from "../Button";
|
|
9
10
|
|
|
10
11
|
import { DialogContext } from "./context";
|
|
11
12
|
|
|
@@ -185,7 +186,7 @@ export const Modal = ({ className, bodyClassName, confirmClose, children, onCanc
|
|
|
185
186
|
return createPortal(
|
|
186
187
|
<>
|
|
187
188
|
<div
|
|
188
|
-
className={
|
|
189
|
+
className={cn("fixed inset-0 z-10", showBackground && "animate-fadeIn bg-black/50 backdrop-blur-md")}
|
|
189
190
|
onClick={(event) => {
|
|
190
191
|
if (event.target !== event.currentTarget) return;
|
|
191
192
|
requestClose();
|
|
@@ -205,14 +206,17 @@ export const Modal = ({ className, bodyClassName, confirmClose, children, onCanc
|
|
|
205
206
|
<button
|
|
206
207
|
type="button"
|
|
207
208
|
aria-label="Close"
|
|
208
|
-
className=
|
|
209
|
+
className={buttonRecipe(
|
|
210
|
+
{ variant: "secondary", size: "icon" },
|
|
211
|
+
"absolute top-[-16px] right-0 z-20 size-8 rounded-full md:top-[-40px]",
|
|
212
|
+
)}
|
|
209
213
|
onClick={() => requestClose()}
|
|
210
214
|
>
|
|
211
215
|
<BiX className="text-3xl" />
|
|
212
216
|
</button>
|
|
213
217
|
<div
|
|
214
|
-
className={
|
|
215
|
-
"mx-auto mt-6 flex max-h-[75vh] w-full max-w-screen animate-fadeIn flex-col items-center justify-center overflow-x-hidden rounded-lg bg-
|
|
218
|
+
className={cn(
|
|
219
|
+
"mx-auto mt-6 flex max-h-[75vh] w-full max-w-screen animate-fadeIn flex-col items-center justify-center overflow-x-hidden rounded-lg bg-background transition-all duration-100 sm:w-[90%] sm:px-2 sm:pb-2 md:mt-0 md:max-h-[90vh] md:pt-0",
|
|
216
220
|
className,
|
|
217
221
|
)}
|
|
218
222
|
>
|
|
@@ -222,7 +226,7 @@ export const Modal = ({ className, bodyClassName, confirmClose, children, onCanc
|
|
|
222
226
|
className="relative z-10 flex w-full animate-fadeIn cursor-pointer touch-pan-y flex-col items-center justify-center px-4 pt-1"
|
|
223
227
|
>
|
|
224
228
|
<div className="flex w-full cursor-pointer items-center justify-center pt-1 opacity-50">
|
|
225
|
-
<div className="h-1 w-24 rounded-full bg-
|
|
229
|
+
<div className="h-1 w-24 rounded-full bg-muted-foreground" />
|
|
226
230
|
</div>
|
|
227
231
|
<div className="flex w-full items-center justify-start">
|
|
228
232
|
<div className="w-full text-start font-bold text-lg">{title}</div>
|
|
@@ -230,8 +234,8 @@ export const Modal = ({ className, bodyClassName, confirmClose, children, onCanc
|
|
|
230
234
|
</animated.div>
|
|
231
235
|
<div
|
|
232
236
|
id={contentId}
|
|
233
|
-
className={
|
|
234
|
-
"scrollbar-none relative m-2 flex size-full min-w-[90vw] overflow-x-hidden overflow-y-scroll border-
|
|
237
|
+
className={cn(
|
|
238
|
+
"scrollbar-none relative m-2 flex size-full min-w-[90vw] overflow-x-hidden overflow-y-scroll border-foreground/30 border-t-[0.1px] p-4 sm:p-4 md:min-w-[384px] md:px-8 lg:min-w-[576px] xl:min-w-[768px]",
|
|
235
239
|
bodyClassName,
|
|
236
240
|
)}
|
|
237
241
|
>
|
package/ui/Dialog/Provider.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { cn } from "akanjs/client";
|
|
3
3
|
import { type ReactNode, useEffect, useState } from "react";
|
|
4
4
|
|
|
5
5
|
import { DialogContext } from "./context";
|
|
@@ -22,7 +22,7 @@ export const Provider = ({ className, defaultOpen = false, open = defaultOpen, c
|
|
|
22
22
|
}, [open]);
|
|
23
23
|
return (
|
|
24
24
|
<DialogContext.Provider value={{ open: openState, setOpen: setOpenState, title, setTitle, action, setAction }}>
|
|
25
|
-
<div data-open={openState} className={
|
|
25
|
+
<div data-open={openState} className={cn("group/dialog", className)}>
|
|
26
26
|
{children}
|
|
27
27
|
</div>
|
|
28
28
|
</DialogContext.Provider>
|
package/ui/DragAction.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useGesture } from "@use-gesture/react";
|
|
3
3
|
import type { ReactDOMAttributes } from "@use-gesture/react/dist/declarations/src/types";
|
|
4
|
-
import {
|
|
4
|
+
import { cn } from "akanjs/client";
|
|
5
5
|
import { animated } from "akanjs/ui";
|
|
6
6
|
import { createContext, type ReactNode, useContext, useRef } from "react";
|
|
7
7
|
import { SpringValue, useSpring } from "react-spring";
|
|
@@ -74,7 +74,7 @@ export const DragAction = ({ className, children, onClick, onLeft, onRight }: Dr
|
|
|
74
74
|
);
|
|
75
75
|
return (
|
|
76
76
|
<DragActionContext.Provider value={{ bind, x, y, leftOpacity, leftWidth, rightOpacity, rightWidth, onClick }}>
|
|
77
|
-
<div ref={ref} className={
|
|
77
|
+
<div ref={ref} className={cn("relative overflow-x-hidden", className)}>
|
|
78
78
|
{children}
|
|
79
79
|
</div>
|
|
80
80
|
</DragActionContext.Provider>
|
package/ui/DraggableList.tsx
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { config, useSprings } from "@react-spring/web";
|
|
3
3
|
import { useGesture } from "@use-gesture/react";
|
|
4
|
-
import {
|
|
4
|
+
import { cn } from "akanjs/client";
|
|
5
5
|
import { animated } from "akanjs/ui";
|
|
6
6
|
import { createContext, type ReactElement, type ReactNode, useContext, useRef } from "react";
|
|
7
7
|
import { BiTrash } from "react-icons/bi";
|
|
8
8
|
import { MdDragIndicator } from "react-icons/md";
|
|
9
|
+
import { buttonRecipe } from "./Button";
|
|
9
10
|
|
|
10
11
|
const clamp = (value: number, min: number, max: number) => Math.min(Math.max(value, min), max);
|
|
11
12
|
|
|
@@ -101,7 +102,7 @@ const DragList = <V,>({ className, mode = "vertical", children, onChange, onRemo
|
|
|
101
102
|
});
|
|
102
103
|
|
|
103
104
|
return (
|
|
104
|
-
<div className={
|
|
105
|
+
<div className={cn("isolate flex gap-0", mode === "vertical" && "flex-col", className)}>
|
|
105
106
|
{springs.map(({ zIndex, shadow, movement, scale }, i) => (
|
|
106
107
|
<animated.div
|
|
107
108
|
ref={(el: HTMLDivElement | null) => {
|
|
@@ -110,6 +111,7 @@ const DragList = <V,>({ className, mode = "vertical", children, onChange, onRemo
|
|
|
110
111
|
key={i}
|
|
111
112
|
style={{
|
|
112
113
|
zIndex,
|
|
114
|
+
|
|
113
115
|
boxShadow: shadow.to((s) => `rgba(0, 0, 0, 0.15) 0px ${s}px ${2 * s}px 0px`),
|
|
114
116
|
scale,
|
|
115
117
|
...(mode === "vertical" ? { y: movement } : { x: movement }),
|
|
@@ -140,7 +142,7 @@ DragList.Cursor = ({ className, children }: Cursor) => {
|
|
|
140
142
|
const { bind } = useDragList();
|
|
141
143
|
return (
|
|
142
144
|
<div
|
|
143
|
-
className={
|
|
145
|
+
className={cn("cursor-grab duration-200 hover:scale-[1.01] hover:opacity-70 hover:shadow-xl", className)}
|
|
144
146
|
{...bind()}
|
|
145
147
|
>
|
|
146
148
|
{children}
|
|
@@ -168,7 +170,7 @@ const Item = ({
|
|
|
168
170
|
}: ItemProps) => {
|
|
169
171
|
const { onRemove } = useDragList();
|
|
170
172
|
return (
|
|
171
|
-
<div className={
|
|
173
|
+
<div className={cn("flex w-full items-center gap-2", className)}>
|
|
172
174
|
{cursor ? (
|
|
173
175
|
<DraggableList.Cursor className={cursorClassName}>
|
|
174
176
|
<MdDragIndicator className="text-xl" />
|
|
@@ -177,7 +179,10 @@ const Item = ({
|
|
|
177
179
|
{children}
|
|
178
180
|
{removable && (
|
|
179
181
|
<button
|
|
180
|
-
className={
|
|
182
|
+
className={buttonRecipe({ variant: "outline", size: "xs" }, [
|
|
183
|
+
"size-6 border-destructive p-0 text-destructive hover:bg-destructive hover:text-destructive-foreground",
|
|
184
|
+
removeClassName,
|
|
185
|
+
])}
|
|
181
186
|
onClick={() => {
|
|
182
187
|
onRemove(value);
|
|
183
188
|
}}
|
package/ui/Dropdown.tsx
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import { type ReactNode, useState } from "react";
|
|
2
|
+
import { cn } from "akanjs/client";
|
|
3
|
+
import { type ReactNode, useEffect, useRef, useState } from "react";
|
|
4
4
|
|
|
5
|
+
import { buttonRecipe } from "./Button";
|
|
5
6
|
import { createOverridable } from "./UiOverride";
|
|
6
7
|
|
|
7
8
|
export interface DropdownProps {
|
|
@@ -19,35 +20,41 @@ export interface DropdownProps {
|
|
|
19
20
|
|
|
20
21
|
export const DefaultDropdown = ({ value, content, className, buttonClassName, dropdownClassName }: DropdownProps) => {
|
|
21
22
|
const [opened, setOpened] = useState(false);
|
|
23
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!opened) return;
|
|
26
|
+
const onClick = (e: MouseEvent) => {
|
|
27
|
+
if (ref.current && !ref.current.contains(e.target as Node)) setOpened(false);
|
|
28
|
+
};
|
|
29
|
+
document.addEventListener("mousedown", onClick);
|
|
30
|
+
return () => {
|
|
31
|
+
document.removeEventListener("mousedown", onClick);
|
|
32
|
+
};
|
|
33
|
+
}, [opened]);
|
|
22
34
|
return (
|
|
23
|
-
<div
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
className={clsx("dropdown dropdown-end", className)}
|
|
28
|
-
>
|
|
29
|
-
<label
|
|
30
|
-
tabIndex={0}
|
|
31
|
-
className={clsx("btn flex", buttonClassName)}
|
|
35
|
+
<div ref={ref} className={cn("relative inline-block", className)}>
|
|
36
|
+
<button
|
|
37
|
+
type="button"
|
|
38
|
+
className={buttonRecipe({ variant: "ghost" }, ["flex", buttonClassName])}
|
|
32
39
|
onClick={() => {
|
|
33
|
-
setOpened(
|
|
40
|
+
setOpened((o) => !o);
|
|
34
41
|
}}
|
|
35
42
|
>
|
|
36
43
|
{value}
|
|
37
|
-
</
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
44
|
+
</button>
|
|
45
|
+
{opened ? (
|
|
46
|
+
<ul
|
|
47
|
+
onClick={() => {
|
|
48
|
+
setOpened(false);
|
|
49
|
+
}}
|
|
50
|
+
className={cn(
|
|
51
|
+
"absolute right-0 z-[100] mt-1 grid max-h-52 gap-2 overflow-auto whitespace-nowrap rounded-md bg-popover p-1 pr-3 text-popover-foreground shadow-md",
|
|
52
|
+
dropdownClassName,
|
|
53
|
+
)}
|
|
54
|
+
>
|
|
55
|
+
{content}
|
|
56
|
+
</ul>
|
|
57
|
+
) : null}
|
|
51
58
|
</div>
|
|
52
59
|
);
|
|
53
60
|
};
|
package/ui/Empty.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { cn, usePage } from "akanjs/client";
|
|
3
3
|
import type { ReactNode } from "react";
|
|
4
4
|
import { AiOutlineMeh } from "react-icons/ai";
|
|
5
5
|
|
|
@@ -20,11 +20,11 @@ export const DefaultEmpty = ({ className = "", description, children, minHeight
|
|
|
20
20
|
const { l } = usePage();
|
|
21
21
|
return (
|
|
22
22
|
<div>
|
|
23
|
+
{/* minHeight is a runtime number, so it has to be a style prop: Tailwind extracts arbitrary values
|
|
24
|
+
from source text, so `min-h-[${minHeight}px]` compiles to no CSS and the prop is silently ignored. */}
|
|
23
25
|
<div
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
className,
|
|
27
|
-
)}
|
|
26
|
+
style={{ minHeight }}
|
|
27
|
+
className={cn("flex flex-col items-center justify-center gap-3 pt-6 pb-3 text-foreground/30", className)}
|
|
28
28
|
>
|
|
29
29
|
<AiOutlineMeh className="scale-150 text-4xl" />
|
|
30
30
|
<p>{description ?? l("base.noData")}</p>
|