@tulip-systems/core 0.9.0 → 0.10.1
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/commands.d.mts +3 -2
- package/dist/commands.mjs +2 -1
- package/dist/components/client.d.mts +2 -1
- package/dist/components/client.mjs +2 -1
- package/dist/components/editor/extensions/file-handler/extension.d.mts +1 -1
- package/dist/components/editor/extensions/image/extension.d.mts +1 -1
- package/dist/components/editor/extensions/skeleton/extension.mjs +1 -1
- package/dist/components/editor/lib/constants.d.mts +1 -1
- package/dist/components/editor/lib/extensions.d.mts +1 -1
- package/dist/components/editor/lib/helpers.d.mts +5 -1
- package/dist/components/editor/lib/helpers.mjs +8 -1
- package/dist/components/layouts/root-layout.server.d.mts +3 -2
- package/dist/components/layouts/root-layout.server.mjs +1 -3
- package/dist/components/server.d.mts +2 -2
- package/dist/components/themes/color-theme-provider.client.d.mts +27 -0
- package/dist/components/themes/color-theme-provider.client.mjs +59 -0
- package/dist/components/themes/color-theme.d.mts +29 -0
- package/dist/components/themes/color-theme.mjs +32 -0
- package/dist/components/ui/badge.d.mts +1 -1
- package/dist/components/ui/button.d.mts +1 -1
- package/dist/components/ui/item.d.mts +1 -1
- package/dist/components.d.mts +3 -2
- package/dist/components.mjs +3 -2
- package/dist/data-tables/client.d.mts +2 -1
- package/dist/data-tables/client.mjs +2 -1
- package/dist/modules/auth/handler/create-client.client.d.mts +4 -4
- package/dist/modules/commands/components/menus/context-menu.client.d.mts +6 -7
- package/dist/modules/commands/components/menus/dropdown-menu.client.d.mts +6 -7
- package/dist/modules/commands/components/menus/floating-menu.client.d.mts +6 -7
- package/dist/modules/commands/components/menus/inline-menu.client.d.mts +6 -7
- package/dist/modules/commands/components/menus/responsive-menu.client.d.mts +5 -6
- package/dist/modules/commands/components/render-command.mjs +3 -5
- package/dist/modules/commands/lib/builder.d.mts +114 -18
- package/dist/modules/commands/lib/builder.mjs +42 -7
- package/dist/modules/commands/lib/registery.d.mts +47 -14
- package/dist/modules/commands/lib/registery.mjs +76 -16
- package/dist/modules/commands/lib/utils.d.mts +11 -0
- package/dist/modules/commands/lib/utils.mjs +14 -0
- package/dist/modules/data-tables/components/footer.mjs +3 -0
- package/dist/modules/data-tables/hooks/use-context.client.d.mts +2 -2
- package/dist/modules/data-tables/lib/types.d.mts +3 -3
- package/dist/modules/data-tables/strategies/local/components.mjs +25 -0
- package/dist/modules/data-tables/strategies/local/strategy.d.mts +12 -0
- package/dist/modules/data-tables/strategies/local/strategy.mjs +31 -0
- package/dist/modules/inline/components/inputs/combobox-dropdown.client.d.mts +4 -3
- package/dist/modules/inline/components/inputs/combobox.client.d.mts +4 -3
- package/dist/modules/inline/components/inputs/date-time.client.d.mts +4 -3
- package/dist/modules/inline/components/inputs/editor.client.d.mts +4 -3
- package/dist/modules/inline/components/inputs/input.client.d.mts +7 -5
- package/dist/modules/inline/components/inputs/select.client.d.mts +4 -3
- package/dist/modules/inline/components/inputs/switch.client.d.mts +4 -3
- package/dist/modules/inline/lib/variants.d.mts +1 -1
- package/dist/modules/router/lib/query-client.d.mts +2 -1
- package/dist/modules/router/lib/query-client.mjs +2 -2
- package/dist/modules/storage/components/dropzone.client.d.mts +2 -2
- package/dist/modules/storage/lib/service.server.d.mts +21 -21
- package/dist/router.d.mts +2 -1
- package/dist/router.mjs +2 -1
- package/dist/src/components/editor/extensions/file-handler/extension.d.mts +1 -1
- package/dist/src/components/editor/extensions/image/extension.d.mts +1 -1
- package/dist/src/components/editor/extensions/skeleton/extension.mjs +1 -1
- package/dist/src/components/editor/lib/constants.d.mts +1 -1
- package/dist/src/components/editor/lib/extensions.d.mts +1 -1
- package/dist/src/components/editor/lib/helpers.d.mts +5 -1
- package/dist/src/components/editor/lib/helpers.mjs +8 -1
- package/dist/src/components/layouts/root-layout.server.d.mts +3 -2
- package/dist/src/components/layouts/root-layout.server.mjs +1 -3
- package/dist/src/components/themes/color-theme-provider.client.d.mts +27 -0
- package/dist/src/components/themes/color-theme-provider.client.mjs +59 -0
- package/dist/src/components/themes/color-theme.d.mts +29 -0
- package/dist/src/components/themes/color-theme.mjs +32 -0
- package/dist/src/components/ui/badge.d.mts +1 -1
- package/dist/src/components/ui/button-group.d.mts +1 -1
- package/dist/src/components/ui/button.d.mts +2 -2
- package/dist/src/components/ui/field.client.d.mts +1 -1
- package/dist/src/modules/commands/components/menus/context-menu.client.d.mts +6 -7
- package/dist/src/modules/commands/components/menus/dropdown-menu.client.d.mts +6 -7
- package/dist/src/modules/commands/components/menus/floating-menu.client.d.mts +6 -7
- package/dist/src/modules/commands/components/menus/inline-menu.client.d.mts +6 -7
- package/dist/src/modules/commands/components/menus/responsive-menu.client.d.mts +5 -6
- package/dist/src/modules/commands/components/render-command.mjs +3 -5
- package/dist/src/modules/commands/lib/builder.d.mts +114 -18
- package/dist/src/modules/commands/lib/builder.mjs +42 -7
- package/dist/src/modules/commands/lib/registery.d.mts +47 -14
- package/dist/src/modules/commands/lib/registery.mjs +76 -16
- package/dist/src/modules/commands/lib/utils.d.mts +11 -0
- package/dist/src/modules/commands/lib/utils.mjs +14 -0
- package/dist/src/modules/data-tables/components/footer.mjs +3 -0
- package/dist/src/modules/data-tables/hooks/use-context.client.d.mts +2 -2
- package/dist/src/modules/data-tables/lib/types.d.mts +3 -3
- package/dist/src/modules/data-tables/strategies/local/components.mjs +25 -0
- package/dist/src/modules/data-tables/strategies/local/strategy.d.mts +12 -0
- package/dist/src/modules/data-tables/strategies/local/strategy.mjs +31 -0
- package/dist/src/modules/inline/components/inputs/combobox-dropdown.client.d.mts +4 -3
- package/dist/src/modules/inline/components/inputs/combobox.client.d.mts +4 -3
- package/dist/src/modules/inline/components/inputs/date-time.client.d.mts +4 -3
- package/dist/src/modules/inline/components/inputs/editor.client.d.mts +4 -3
- package/dist/src/modules/inline/components/inputs/input.client.d.mts +7 -5
- package/dist/src/modules/inline/components/inputs/select.client.d.mts +4 -3
- package/dist/src/modules/inline/components/inputs/switch.client.d.mts +4 -3
- package/dist/src/modules/router/lib/query-client.d.mts +2 -1
- package/dist/src/modules/router/lib/query-client.mjs +2 -2
- package/package.json +1 -1
- package/src/components/editor/lib/helpers.ts +8 -0
- package/src/components/entry.client.ts +1 -1
- package/src/components/entry.ts +1 -1
- package/src/components/layouts/root-layout.server.tsx +4 -2
- package/src/components/themes/color-theme-provider.client.tsx +82 -0
- package/src/components/themes/color-theme.ts +32 -0
- package/src/modules/commands/components/menus/context-menu.client.tsx +11 -11
- package/src/modules/commands/components/menus/dropdown-menu.client.tsx +9 -10
- package/src/modules/commands/components/menus/floating-menu.client.tsx +9 -10
- package/src/modules/commands/components/menus/inline-menu.client.tsx +9 -10
- package/src/modules/commands/components/menus/responsive-menu.client.tsx +7 -8
- package/src/modules/commands/components/render-command.tsx +17 -13
- package/src/modules/commands/entry.ts +1 -0
- package/src/modules/commands/lib/builder.ts +216 -36
- package/src/modules/commands/lib/registery.ts +210 -47
- package/src/modules/commands/lib/utils.ts +10 -0
- package/src/modules/data-tables/components/footer.tsx +9 -0
- package/src/modules/data-tables/entry.client.ts +1 -0
- package/src/modules/data-tables/hooks/use-context.client.tsx +2 -2
- package/src/modules/data-tables/lib/types.ts +3 -3
- package/src/modules/data-tables/strategies/local/components.tsx +17 -0
- package/src/modules/data-tables/strategies/local/strategy.ts +33 -0
- package/src/modules/inline/components/inputs/combobox-dropdown.client.tsx +11 -5
- package/src/modules/inline/components/inputs/combobox.client.tsx +11 -5
- package/src/modules/inline/components/inputs/date-time.client.tsx +11 -5
- package/src/modules/inline/components/inputs/editor.client.tsx +11 -5
- package/src/modules/inline/components/inputs/input.client.tsx +21 -9
- package/src/modules/inline/components/inputs/select.client.tsx +11 -5
- package/src/modules/inline/components/inputs/switch.client.tsx +11 -5
- package/src/modules/router/entry.ts +1 -0
- package/src/modules/router/lib/query-client.ts +2 -2
- package/src/styles.css +317 -2
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AnyCommandDef, ExtractCommandData } from "../../lib/builder.mjs";
|
|
2
2
|
import { CommandContextLifecycle } from "../../hooks/use-command.client.mjs";
|
|
3
3
|
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
4
4
|
import { HTMLAttributes, ReactNode } from "react";
|
|
5
|
-
import z from "zod";
|
|
6
5
|
|
|
7
6
|
//#region src/modules/commands/components/menus/floating-menu.client.d.ts
|
|
8
|
-
type FloatingCommandMenuProps<
|
|
9
|
-
data:
|
|
10
|
-
commands:
|
|
7
|
+
type FloatingCommandMenuProps<TCommand extends AnyCommandDef, TMeta = object> = HTMLAttributes<HTMLElement> & CommandContextLifecycle & {
|
|
8
|
+
data: NoInfer<ExtractCommandData<TCommand>>;
|
|
9
|
+
commands: TCommand[];
|
|
11
10
|
meta?: TMeta;
|
|
12
11
|
fallback?: ReactNode;
|
|
13
12
|
state: "open" | "closed";
|
|
14
13
|
emptyLabel?: string;
|
|
15
14
|
};
|
|
16
|
-
declare function FloatingCommandMenu<
|
|
15
|
+
declare function FloatingCommandMenu<TCommand extends AnyCommandDef, TMeta = object>({
|
|
17
16
|
data,
|
|
18
17
|
commands,
|
|
19
18
|
meta,
|
|
@@ -25,6 +24,6 @@ declare function FloatingCommandMenu<TSchema extends z.ZodTypeAny, TMeta>({
|
|
|
25
24
|
className,
|
|
26
25
|
emptyLabel,
|
|
27
26
|
...props
|
|
28
|
-
}: FloatingCommandMenuProps<
|
|
27
|
+
}: FloatingCommandMenuProps<TCommand, TMeta>): react_jsx_runtime0.JSX.Element;
|
|
29
28
|
//#endregion
|
|
30
29
|
export { FloatingCommandMenu, FloatingCommandMenuProps };
|
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AnyCommandDef, ExtractCommandData } from "../../lib/builder.mjs";
|
|
2
2
|
import { CommandContextLifecycle } from "../../hooks/use-command.client.mjs";
|
|
3
3
|
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
4
4
|
import { ComponentProps, HTMLAttributes, ReactNode } from "react";
|
|
5
|
-
import z from "zod";
|
|
6
5
|
|
|
7
6
|
//#region src/modules/commands/components/menus/inline-menu.client.d.ts
|
|
8
|
-
type InlineCommandMenuProps<
|
|
9
|
-
data:
|
|
10
|
-
commands:
|
|
7
|
+
type InlineCommandMenuProps<TCommand extends AnyCommandDef, TMeta = object> = HTMLAttributes<HTMLElement> & CommandContextLifecycle & {
|
|
8
|
+
data: NoInfer<ExtractCommandData<TCommand>>;
|
|
9
|
+
commands: TCommand[];
|
|
11
10
|
meta?: TMeta;
|
|
12
11
|
fallback?: ReactNode;
|
|
13
12
|
};
|
|
14
|
-
declare function InlineCommandMenu<
|
|
13
|
+
declare function InlineCommandMenu<TCommand extends AnyCommandDef, TMeta = object>({
|
|
15
14
|
data,
|
|
16
15
|
meta,
|
|
17
16
|
commands,
|
|
@@ -21,7 +20,7 @@ declare function InlineCommandMenu<TSchema extends z.ZodTypeAny, TMeta>({
|
|
|
21
20
|
onSettled,
|
|
22
21
|
className,
|
|
23
22
|
...props
|
|
24
|
-
}: InlineCommandMenuProps<
|
|
23
|
+
}: InlineCommandMenuProps<TCommand, TMeta>): react_jsx_runtime0.JSX.Element | null;
|
|
25
24
|
declare function InlineCommandMenuLoading({
|
|
26
25
|
className,
|
|
27
26
|
...props
|
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AnyCommandDef, ExtractCommandData } from "../../lib/builder.mjs";
|
|
2
2
|
import { CommandContextLifecycle } from "../../hooks/use-command.client.mjs";
|
|
3
3
|
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
4
4
|
import { ReactNode } from "react";
|
|
5
|
-
import z from "zod";
|
|
6
5
|
|
|
7
6
|
//#region src/modules/commands/components/menus/responsive-menu.client.d.ts
|
|
8
|
-
type ResponsiveCommandMenuProps<
|
|
9
|
-
data:
|
|
10
|
-
commands:
|
|
7
|
+
type ResponsiveCommandMenuProps<TCommand extends AnyCommandDef, TMeta = object> = CommandContextLifecycle & {
|
|
8
|
+
data: NoInfer<ExtractCommandData<TCommand>>;
|
|
9
|
+
commands: TCommand[];
|
|
11
10
|
meta?: TMeta;
|
|
12
11
|
fallback?: ReactNode;
|
|
13
12
|
};
|
|
14
|
-
declare function ResponsiveCommandMenu<
|
|
13
|
+
declare function ResponsiveCommandMenu<TCommand extends AnyCommandDef, TMeta = object>(props: ResponsiveCommandMenuProps<TCommand, TMeta>): react_jsx_runtime0.JSX.Element;
|
|
15
14
|
declare function ResponsiveCommandMenuLoading(): react_jsx_runtime0.JSX.Element;
|
|
16
15
|
//#endregion
|
|
17
16
|
export { ResponsiveCommandMenu, ResponsiveCommandMenuLoading, ResponsiveCommandMenuProps };
|
|
@@ -8,13 +8,11 @@ import { Fragment, jsx } from "react/jsx-runtime";
|
|
|
8
8
|
/**
|
|
9
9
|
* Command renderer.
|
|
10
10
|
*
|
|
11
|
-
* It
|
|
12
|
-
*
|
|
11
|
+
* It applies cheap visibility/disabled rules, exposes command status via context,
|
|
12
|
+
* and then renders the command content. Validation belongs at execution boundaries.
|
|
13
13
|
*/
|
|
14
14
|
function RenderCommand(props) {
|
|
15
|
-
const
|
|
16
|
-
if (!parsedData.success) return /* @__PURE__ */ jsx(Fragment, { children: props.fallback });
|
|
17
|
-
const data = parsedData.data;
|
|
15
|
+
const data = props.command.transform ? props.command.transform(props.data) : props.data;
|
|
18
16
|
const meta = props.meta ?? {};
|
|
19
17
|
const visibleResult = props.command.visibleWhen?.({
|
|
20
18
|
data,
|
|
@@ -1,39 +1,135 @@
|
|
|
1
1
|
import { Permission } from "../../auth/lib/permissions.mjs";
|
|
2
|
-
import { z as z$1 } from "zod";
|
|
3
2
|
|
|
4
3
|
//#region src/modules/commands/lib/builder.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The different UI contexts in which a command can be rendered.
|
|
6
|
+
*/
|
|
5
7
|
type CommandUI = "dropdown" | "context" | "table" | "inline" | "custom";
|
|
8
|
+
/**
|
|
9
|
+
* The status of a command, which can be used to style the command's UI appropriately.
|
|
10
|
+
*/
|
|
6
11
|
type CommandStatus = "idle" | "pending" | "success" | "error";
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
/**
|
|
13
|
+
* A string tag that can be added to a command for organizational and filtering purposes.
|
|
14
|
+
*/
|
|
15
|
+
type CommandTag = string;
|
|
16
|
+
/**
|
|
17
|
+
* Represents a command definition with its associated types and properties.
|
|
18
|
+
*/
|
|
19
|
+
type AnyCommandDef = CommandDef<any, any, any, any>;
|
|
20
|
+
/**
|
|
21
|
+
* Condition function that determines whether a command is visible or disabled based on the provided data and meta.
|
|
22
|
+
*/
|
|
23
|
+
type CommandCondition<TData, TMeta> = (params: {
|
|
24
|
+
data: TData;
|
|
9
25
|
meta: TMeta;
|
|
10
26
|
}) => boolean | boolean[];
|
|
11
|
-
|
|
12
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Render function that defines how a command should be rendered based on the provided data, meta, and UI context.
|
|
29
|
+
*/
|
|
30
|
+
type CommandRender<TData, TMeta> = (params: {
|
|
31
|
+
data: TData;
|
|
13
32
|
meta: TMeta;
|
|
14
33
|
ui: CommandUI;
|
|
15
34
|
}) => React.ReactNode;
|
|
16
35
|
/**
|
|
17
36
|
* Final command definition (without name).
|
|
18
37
|
* Name is derived from the object key in `defineCommands`.
|
|
38
|
+
*
|
|
39
|
+
* @typeParam TData - The type `visibleWhen`, `disabledWhen`, and `render` receive.
|
|
40
|
+
* When `.transform()` is used this is the post-transform type.
|
|
41
|
+
* @typeParam TMeta - Shared contextual metadata passed alongside data.
|
|
42
|
+
* @typeParam TTags - Literal tuple of tag strings preserved from the builder's
|
|
43
|
+
* `.tags()` call. Enables compile-time tag filtering in the
|
|
44
|
+
* registry. Defaults to `string[]` when not provided.
|
|
45
|
+
* @typeParam TInput - The type that menus must pass as `data`. Equals `TData`
|
|
46
|
+
* when no `.transform()` is used. When `.transform(fn)` is
|
|
47
|
+
* called, `TInput` captures the pre-transform type so menus
|
|
48
|
+
* remain correctly typed while `render` sees the transformed type.
|
|
49
|
+
* Structurally expressed as the parameter of `transform`.
|
|
19
50
|
*/
|
|
20
|
-
type CommandDef<
|
|
51
|
+
type CommandDef<TData = unknown, TMeta = object, TTags extends readonly string[] = string[], TInput = TData> = {
|
|
52
|
+
id?: string;
|
|
53
|
+
tags: TTags;
|
|
54
|
+
transform?: (data: TInput) => TData;
|
|
21
55
|
permission?: Permission;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
render: CommandRender<TSchema, TMeta>;
|
|
56
|
+
visibleWhen?: CommandCondition<TData, TMeta>;
|
|
57
|
+
disabledWhen?: CommandCondition<TData, TMeta>;
|
|
58
|
+
render: CommandRender<TData, TMeta>;
|
|
26
59
|
};
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Command typed by accepted input data.
|
|
62
|
+
*
|
|
63
|
+
* Useful for APIs that only care about what can be passed in (e.g. table
|
|
64
|
+
* providers that always pass selected rows), not the command's normalized
|
|
65
|
+
* render-time shape.
|
|
66
|
+
*/
|
|
67
|
+
type CommandFor<TInput, TMeta = object> = CommandDef<any, TMeta, any, TInput>;
|
|
68
|
+
/**
|
|
69
|
+
* Extracts the **input** data type of a command — what menus must pass as `data`.
|
|
70
|
+
*
|
|
71
|
+
* - When `.transform()` is used, this is the pre-transform type (e.g. `Template | Template[]`).
|
|
72
|
+
* - Otherwise it equals the render-time type.
|
|
73
|
+
*
|
|
74
|
+
* The type is read from the `transform` field's parameter when present, and
|
|
75
|
+
* falls back to the `render` parameter when there is no transformer.
|
|
76
|
+
*/
|
|
77
|
+
type ExtractCommandData<TCommand extends AnyCommandDef> = [NonNullable<TCommand["transform"]>] extends [never] ? TCommand extends {
|
|
78
|
+
render: (params: {
|
|
79
|
+
data: infer TData;
|
|
80
|
+
meta: any;
|
|
81
|
+
ui: any;
|
|
82
|
+
}) => any;
|
|
83
|
+
} ? TData : never : NonNullable<TCommand["transform"]> extends ((data: infer TInput) => any) ? TInput : never;
|
|
84
|
+
/**
|
|
85
|
+
* Builder state after `.$type<TData>()` has been called (or at initial state
|
|
86
|
+
* with `TData = unknown`).
|
|
87
|
+
*
|
|
88
|
+
* @typeParam TData - Current render-time data type (post-transform if used).
|
|
89
|
+
* @typeParam TTags - Literal tag tuple, carried through every method so that
|
|
90
|
+
* the final `CommandDef` retains the literal type.
|
|
91
|
+
* @typeParam TInput - Input data type for menus. Starts equal to `TData`.
|
|
92
|
+
* Freezes to the value of `TData` at the moment `.transform()`
|
|
93
|
+
* is called, while `TData` changes to the transformer's output.
|
|
94
|
+
*/
|
|
95
|
+
type ReadyCommandBuilder<TData, TMeta, TTags extends readonly string[] = string[], TInput = TData> = {
|
|
96
|
+
/** Override the data (and optionally meta) type. Resets `TInput` to the new `TData`. */$type<TNewData, TNewMeta = TMeta>(): ReadyCommandBuilder<TNewData, TNewMeta, TTags, TNewData>;
|
|
97
|
+
/**
|
|
98
|
+
* Set the command's tags as a literal tuple. The `const` modifier infers
|
|
99
|
+
* string arguments as literals, enabling compile-time tag narrowing in the registry.
|
|
100
|
+
*/
|
|
101
|
+
tags<const TNewTags extends string[]>(...tags: TNewTags): ReadyCommandBuilder<TData, TMeta, TNewTags, TInput>;
|
|
102
|
+
permission(permission: Permission): ReadyCommandBuilder<TData, TMeta, TTags, TInput>;
|
|
103
|
+
/**
|
|
104
|
+
* Declares a lightweight transformer that runs once per render — before `visibleWhen`,
|
|
105
|
+
* `disabledWhen`, and `render` — collapsing the input type into a single usable shape.
|
|
106
|
+
*
|
|
107
|
+
* Freezes `TInput` to the current `TData` (the pre-transform type) and advances
|
|
108
|
+
* `TData` to `TNewData` (the transformer's return type). This ensures:
|
|
109
|
+
* - Menus are typed against the union input (e.g. `Template | Template[]`)
|
|
110
|
+
* - `visibleWhen` and `render` work with the clean transformed type (e.g. `Template[]`)
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* commandBuilder
|
|
114
|
+
* .$type<Template | Template[]>()
|
|
115
|
+
* .transform((data) => (Array.isArray(data) ? data : [data]))
|
|
116
|
+
* .visibleWhen(({ data }) => data.length > 0) // data: Template[]
|
|
117
|
+
* .render(({ data }) => <ArchiveCommand ids={data.map(i => i.id)} />)
|
|
118
|
+
*/
|
|
119
|
+
transform<TNewData>(fn: (data: TData) => TNewData): ReadyCommandBuilder<TNewData, TMeta, TTags, TData>;
|
|
120
|
+
visibleWhen(condition: CommandCondition<TData, TMeta>): ReadyCommandBuilder<TData, TMeta, TTags, TInput>;
|
|
121
|
+
disabledWhen(condition: CommandCondition<TData, TMeta>): ReadyCommandBuilder<TData, TMeta, TTags, TInput>; /** Terminal — produces the final `CommandDef`. */
|
|
122
|
+
render(render: CommandRender<TData, TMeta>): CommandDef<TData, TMeta, TTags, TInput>;
|
|
32
123
|
};
|
|
33
|
-
|
|
34
|
-
|
|
124
|
+
/**
|
|
125
|
+
* The initial builder returned by `commandBuilder` / `createCommandBuilder()`.
|
|
126
|
+
* Before `.$type<>()` is called, `TData` is `unknown`.
|
|
127
|
+
*/
|
|
128
|
+
type InitialCommandBuilder<TMeta> = ReadyCommandBuilder<unknown, TMeta, string[], unknown> & {
|
|
129
|
+
$type<TNewData, TNewMeta = TMeta>(): ReadyCommandBuilder<TNewData, TNewMeta, string[], TNewData>;
|
|
130
|
+
tags<const TNewTags extends string[]>(...tags: TNewTags): ReadyCommandBuilder<unknown, TMeta, TNewTags, unknown>;
|
|
35
131
|
};
|
|
36
132
|
declare function createCommandBuilder<TMeta = object>(): InitialCommandBuilder<TMeta>;
|
|
37
133
|
declare const commandBuilder: InitialCommandBuilder<object>;
|
|
38
134
|
//#endregion
|
|
39
|
-
export { CommandCondition, CommandDef, CommandRender, CommandStatus, CommandUI, commandBuilder, createCommandBuilder };
|
|
135
|
+
export { AnyCommandDef, CommandCondition, CommandDef, CommandFor, CommandRender, CommandStatus, CommandTag, CommandUI, ExtractCommandData, commandBuilder, createCommandBuilder };
|
|
@@ -1,20 +1,54 @@
|
|
|
1
1
|
//#region src/modules/commands/lib/builder.ts
|
|
2
2
|
function createInitialBuilder(state) {
|
|
3
|
-
return {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
})
|
|
8
|
-
|
|
3
|
+
return {
|
|
4
|
+
...createReadyBuilder({
|
|
5
|
+
tags: state.tags ?? [],
|
|
6
|
+
permission: state.permission
|
|
7
|
+
}),
|
|
8
|
+
tags(...tags) {
|
|
9
|
+
return createReadyBuilder({
|
|
10
|
+
tags,
|
|
11
|
+
permission: state.permission
|
|
12
|
+
});
|
|
13
|
+
},
|
|
14
|
+
$type() {
|
|
15
|
+
return createReadyBuilder({
|
|
16
|
+
tags: state.tags ?? [],
|
|
17
|
+
permission: state.permission
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
};
|
|
9
21
|
}
|
|
10
22
|
function createReadyBuilder(state) {
|
|
11
23
|
return {
|
|
24
|
+
$type() {
|
|
25
|
+
return createReadyBuilder({
|
|
26
|
+
tags: state.tags,
|
|
27
|
+
permission: state.permission
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
tags(...tags) {
|
|
31
|
+
return createReadyBuilder({
|
|
32
|
+
tags,
|
|
33
|
+
permission: state.permission,
|
|
34
|
+
transform: state.transform,
|
|
35
|
+
visibleWhen: state.visibleWhen,
|
|
36
|
+
disabledWhen: state.disabledWhen
|
|
37
|
+
});
|
|
38
|
+
},
|
|
12
39
|
permission(permission) {
|
|
13
40
|
return createReadyBuilder({
|
|
14
41
|
...state,
|
|
15
42
|
permission
|
|
16
43
|
});
|
|
17
44
|
},
|
|
45
|
+
transform(fn) {
|
|
46
|
+
return createReadyBuilder({
|
|
47
|
+
tags: state.tags,
|
|
48
|
+
permission: state.permission,
|
|
49
|
+
transform: fn
|
|
50
|
+
});
|
|
51
|
+
},
|
|
18
52
|
visibleWhen(condition) {
|
|
19
53
|
return createReadyBuilder({
|
|
20
54
|
...state,
|
|
@@ -29,8 +63,9 @@ function createReadyBuilder(state) {
|
|
|
29
63
|
},
|
|
30
64
|
render(render) {
|
|
31
65
|
return {
|
|
66
|
+
tags: state.tags,
|
|
67
|
+
transform: state.transform,
|
|
32
68
|
permission: state.permission,
|
|
33
|
-
schema: state.schema,
|
|
34
69
|
visibleWhen: state.visibleWhen,
|
|
35
70
|
disabledWhen: state.disabledWhen,
|
|
36
71
|
render
|
|
@@ -1,11 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import z from "zod";
|
|
1
|
+
import { AnyCommandDef } from "./builder.mjs";
|
|
3
2
|
|
|
4
3
|
//#region src/modules/commands/lib/registery.d.ts
|
|
5
4
|
/**
|
|
6
5
|
* Command map type defining the shape of command definitions.
|
|
7
6
|
*/
|
|
8
|
-
type CommandMap = Record<string,
|
|
7
|
+
type CommandMap = Record<string, AnyCommandDef>;
|
|
8
|
+
/** Union of all values in a command map. */
|
|
9
|
+
type ValueOf<TCommands extends CommandMap> = TCommands[keyof TCommands];
|
|
10
|
+
/** Keep commands that have **every** of `TFilterTags`. */
|
|
11
|
+
type FilterAllTags<TCommand extends AnyCommandDef, TFilterTags extends readonly string[]> = TCommand extends {
|
|
12
|
+
tags: infer CmdTags extends readonly string[];
|
|
13
|
+
} ? TFilterTags[number] extends CmdTags[number] ? TCommand : never : TCommand;
|
|
14
|
+
/** Keep commands that have **some** of `TFilterTags`. */
|
|
15
|
+
type FilterAnyTags<TCommand extends AnyCommandDef, TFilterTags extends readonly string[]> = TCommand extends {
|
|
16
|
+
tags: infer CmdTags extends readonly string[];
|
|
17
|
+
} ? string[] extends CmdTags ? TCommand : Extract<CmdTags[number], TFilterTags[number]> extends never ? never : TCommand : TCommand;
|
|
18
|
+
/** Keep commands whose tag set equals `TFilterTags` (order-insensitive). */
|
|
19
|
+
type FilterExactTags<TCommand extends AnyCommandDef, TFilterTags extends readonly string[]> = TCommand extends {
|
|
20
|
+
tags: infer CmdTags extends readonly string[];
|
|
21
|
+
} ? string[] extends CmdTags ? TCommand : [CmdTags[number]] extends [TFilterTags[number]] ? [TFilterTags[number]] extends [CmdTags[number]] ? TCommand : never : never : TCommand;
|
|
22
|
+
/** Keep commands that have **without** of `TFilterTags`. */
|
|
23
|
+
type FilterWithoutTags<TCommand extends AnyCommandDef, TFilterTags extends readonly string[]> = TCommand extends {
|
|
24
|
+
tags: infer CmdTags extends readonly string[];
|
|
25
|
+
} ? string[] extends CmdTags ? TCommand : Extract<CmdTags[number], TFilterTags[number]> extends never ? TCommand : never : TCommand;
|
|
9
26
|
type CommandKey<TCommands extends CommandMap> = Extract<keyof TCommands, string>;
|
|
10
27
|
type CommandFlags<TCommands extends CommandMap> = Partial<Record<CommandKey<TCommands>, boolean>>;
|
|
11
28
|
type CommandInput<TCommands extends CommandMap> = readonly CommandKey<TCommands>[] | CommandFlags<TCommands>;
|
|
@@ -13,22 +30,38 @@ type TruthyKeys<T> = { [K in keyof T]-?: T[K] extends true ? K : never }[keyof T
|
|
|
13
30
|
type PickedCommands<TCommands extends CommandMap, TInput extends CommandInput<TCommands>> = TInput extends readonly CommandKey<TCommands>[] ? Pick<TCommands, TInput[number]> : TInput extends CommandFlags<TCommands> ? Pick<TCommands, Extract<TruthyKeys<TInput>, keyof TCommands>> : never;
|
|
14
31
|
type OmittedCommands<TCommands extends CommandMap, TInput extends CommandInput<TCommands>> = TInput extends readonly CommandKey<TCommands>[] ? Omit<TCommands, TInput[number]> : TInput extends CommandFlags<TCommands> ? Omit<TCommands, Extract<TruthyKeys<TInput>, keyof TCommands>> : never;
|
|
15
32
|
type ExtendedCommands<TBase extends CommandMap, TExtension extends CommandMap> = Omit<TBase, keyof TExtension> & TExtension;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
33
|
+
type CommandTagFilterRegistry<TCommand extends AnyCommandDef> = {
|
|
34
|
+
every<const TTags extends string[]>(...tags: TTags): CommandTagFilterRegistry<FilterAllTags<TCommand, TTags>>;
|
|
35
|
+
some<const TTags extends string[]>(...tags: TTags): CommandTagFilterRegistry<FilterAnyTags<TCommand, TTags>>;
|
|
36
|
+
exact<const TTags extends string[]>(...tags: TTags): CommandTagFilterRegistry<FilterExactTags<TCommand, TTags>>;
|
|
37
|
+
without<const TTags extends string[]>(...tags: TTags): CommandTagFilterRegistry<FilterWithoutTags<TCommand, TTags>>;
|
|
38
|
+
toArray(): TCommand[];
|
|
39
|
+
};
|
|
40
|
+
type CommandKeyFilterRegistry<TCommands extends CommandMap> = {
|
|
41
|
+
pick<const TInput extends CommandInput<TCommands>>(input: TInput): CommandKeyFilterRegistry<PickedCommands<TCommands, TInput>>;
|
|
42
|
+
omit<const TInput extends CommandInput<TCommands>>(input: TInput): CommandKeyFilterRegistry<OmittedCommands<TCommands, TInput>>;
|
|
43
|
+
toArray(): ValueOf<TCommands>[];
|
|
44
|
+
};
|
|
20
45
|
type CommandRegistry<TCommands extends CommandMap> = {
|
|
21
46
|
commands: TCommands;
|
|
22
|
-
|
|
23
|
-
|
|
47
|
+
keys: CommandKeyFilterRegistry<TCommands>;
|
|
48
|
+
tags: CommandTagFilterRegistry<ValueOf<TCommands>>;
|
|
49
|
+
extend<const TExtension extends CommandMap>(extension: TExtension): CommandRegistry<ExtendedCommands<TCommands, TExtension>>; /** @deprecated Use `commands.keys.pick(...)` instead. */
|
|
50
|
+
pick<const TInput extends CommandInput<TCommands>>(input: TInput): CommandRegistry<PickedCommands<TCommands, TInput>>; /** @deprecated Use `commands.keys.omit(...)` instead. */
|
|
24
51
|
omit<const TInput extends CommandInput<TCommands>>(input: TInput): CommandRegistry<OmittedCommands<TCommands, TInput>>;
|
|
25
|
-
toArray():
|
|
52
|
+
toArray(): ValueOf<TCommands>[];
|
|
26
53
|
};
|
|
27
54
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
55
|
+
* Define commands from a map of name → `CommandDef`.
|
|
56
|
+
*
|
|
57
|
+
* Returns a `CommandRegistry` with key-based and tag-based filtering, plus
|
|
58
|
+
* `extend` for composition. Filter chains are immutable — each call produces
|
|
59
|
+
* a new registry.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* const registry = defineCommands({ edit, delete, archive });
|
|
63
|
+
* registry.tags.every("danger", "table").toArray();
|
|
64
|
+
* registry.keys.omit({ delete: true }).toArray();
|
|
32
65
|
*/
|
|
33
66
|
declare function defineCommands<TCommands extends CommandMap>(commands: TCommands): CommandRegistry<TCommands>;
|
|
34
67
|
//#endregion
|
|
@@ -1,39 +1,99 @@
|
|
|
1
1
|
//#region src/modules/commands/lib/registery.ts
|
|
2
|
-
function
|
|
2
|
+
function resolveKeys(input) {
|
|
3
3
|
if (Array.isArray(input)) return [...input];
|
|
4
4
|
return Object.entries(input).filter(([, enabled]) => enabled === true).map(([key]) => key);
|
|
5
5
|
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
function dedupe(tags) {
|
|
7
|
+
return [...new Set(tags)];
|
|
8
|
+
}
|
|
9
|
+
function hasEveryTag(command, tags) {
|
|
10
|
+
return tags.every((tag) => command.tags.includes(tag));
|
|
11
|
+
}
|
|
12
|
+
function hasSomeTag(command, tags) {
|
|
13
|
+
return tags.some((tag) => command.tags.includes(tag));
|
|
14
|
+
}
|
|
15
|
+
function hasExactTags(command, tags) {
|
|
16
|
+
const ctags = dedupe(command.tags);
|
|
17
|
+
const ftags = dedupe(tags);
|
|
18
|
+
return ctags.length === ftags.length && ftags.every((t) => ctags.includes(t));
|
|
19
|
+
}
|
|
20
|
+
function injectIds(commands) {
|
|
21
|
+
return Object.fromEntries(Object.entries(commands).map(([id, c]) => [id, {
|
|
22
|
+
...c,
|
|
23
|
+
id
|
|
24
|
+
}]));
|
|
25
|
+
}
|
|
26
|
+
function pickCommands(commands, input) {
|
|
27
|
+
const keys = resolveKeys(input);
|
|
28
|
+
return Object.fromEntries(keys.filter((k) => k in commands).map((k) => [k, commands[k]]));
|
|
29
|
+
}
|
|
30
|
+
function omitCommands(commands, input) {
|
|
31
|
+
const keys = new Set(resolveKeys(input));
|
|
32
|
+
return Object.fromEntries(Object.entries(commands).filter(([k]) => !keys.has(k)));
|
|
33
|
+
}
|
|
34
|
+
function createTagFilterRegistry(commands) {
|
|
35
|
+
function apply(predicate) {
|
|
36
|
+
return (...tags) => {
|
|
37
|
+
return createTagFilterRegistry(commands.filter((c) => predicate(c, tags)));
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
every: apply(hasEveryTag),
|
|
42
|
+
some: apply(hasSomeTag),
|
|
43
|
+
exact: apply(hasExactTags),
|
|
44
|
+
without: apply((c, ts) => !hasSomeTag(c, ts)),
|
|
45
|
+
toArray() {
|
|
46
|
+
return commands;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function createKeyFilterRegistry(commands) {
|
|
51
|
+
return {
|
|
52
|
+
pick(input) {
|
|
53
|
+
return createKeyFilterRegistry(pickCommands(commands, input));
|
|
54
|
+
},
|
|
55
|
+
omit(input) {
|
|
56
|
+
return createKeyFilterRegistry(omitCommands(commands, input));
|
|
57
|
+
},
|
|
58
|
+
toArray() {
|
|
59
|
+
return Object.values(commands);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
9
63
|
function createRegistry(commands) {
|
|
64
|
+
const withIds = injectIds(commands);
|
|
10
65
|
return {
|
|
11
|
-
commands,
|
|
66
|
+
commands: withIds,
|
|
67
|
+
keys: createKeyFilterRegistry(withIds),
|
|
68
|
+
tags: createTagFilterRegistry(Object.values(withIds)),
|
|
12
69
|
extend(extension) {
|
|
13
70
|
return createRegistry({
|
|
14
|
-
...
|
|
71
|
+
...withIds,
|
|
15
72
|
...extension
|
|
16
73
|
});
|
|
17
74
|
},
|
|
18
75
|
pick(input) {
|
|
19
|
-
|
|
20
|
-
return createRegistry(Object.fromEntries(keys.flatMap((key) => key in commands ? [[key, commands[key]]] : [])));
|
|
76
|
+
return createRegistry(pickCommands(withIds, input));
|
|
21
77
|
},
|
|
22
78
|
omit(input) {
|
|
23
|
-
|
|
24
|
-
const blacklist = new Set(keys);
|
|
25
|
-
return createRegistry(Object.fromEntries(Object.entries(commands).filter(([key]) => !blacklist.has(key))));
|
|
79
|
+
return createRegistry(omitCommands(withIds, input));
|
|
26
80
|
},
|
|
27
81
|
toArray() {
|
|
28
|
-
return Object.values(
|
|
82
|
+
return Object.values(withIds);
|
|
29
83
|
}
|
|
30
84
|
};
|
|
31
85
|
}
|
|
32
86
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
87
|
+
* Define commands from a map of name → `CommandDef`.
|
|
88
|
+
*
|
|
89
|
+
* Returns a `CommandRegistry` with key-based and tag-based filtering, plus
|
|
90
|
+
* `extend` for composition. Filter chains are immutable — each call produces
|
|
91
|
+
* a new registry.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* const registry = defineCommands({ edit, delete, archive });
|
|
95
|
+
* registry.tags.every("danger", "table").toArray();
|
|
96
|
+
* registry.keys.omit({ delete: true }).toArray();
|
|
37
97
|
*/
|
|
38
98
|
function defineCommands(commands) {
|
|
39
99
|
return createRegistry(commands);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/modules/commands/lib/utils.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Normalizes command data into an array.
|
|
4
|
+
*
|
|
5
|
+
* Use this as a command transform when the same command should support both
|
|
6
|
+
* single-item and bulk contexts. After `.transform(ensureArray)`, command
|
|
7
|
+
* callbacks can safely use array helpers like `.map` and `.every`.
|
|
8
|
+
*/
|
|
9
|
+
declare function ensureArray<T>(data: T | T[]): T[];
|
|
10
|
+
//#endregion
|
|
11
|
+
export { ensureArray };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/modules/commands/lib/utils.ts
|
|
2
|
+
/**
|
|
3
|
+
* Normalizes command data into an array.
|
|
4
|
+
*
|
|
5
|
+
* Use this as a command transform when the same command should support both
|
|
6
|
+
* single-item and bulk contexts. After `.transform(ensureArray)`, command
|
|
7
|
+
* callbacks can safely use array helpers like `.map` and `.every`.
|
|
8
|
+
*/
|
|
9
|
+
function ensureArray(data) {
|
|
10
|
+
return Array.isArray(data) ? data : [data];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
//#endregion
|
|
14
|
+
export { ensureArray };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { InfinteTableBottombar, InfinteTableFooter } from "../strategies/infinite/components.mjs";
|
|
4
|
+
import { LocalTableFooter } from "../strategies/local/components.mjs";
|
|
4
5
|
import { PaginationTableFooter } from "../strategies/pagination/components.mjs";
|
|
5
6
|
import { jsx } from "react/jsx-runtime";
|
|
6
7
|
|
|
@@ -12,6 +13,7 @@ function TableFooter({ table }) {
|
|
|
12
13
|
const meta = table.options.meta;
|
|
13
14
|
if (meta.strategy.name === "pagination") return null;
|
|
14
15
|
if (meta.strategy.name === "infinite") return /* @__PURE__ */ jsx(InfinteTableFooter, { table });
|
|
16
|
+
if (meta.strategy.name === "local") return null;
|
|
15
17
|
throw new Error(`Unknown strategy: ${meta.strategy.name}`);
|
|
16
18
|
}
|
|
17
19
|
/**
|
|
@@ -21,6 +23,7 @@ function TableBottombar({ table }) {
|
|
|
21
23
|
const meta = table.options.meta;
|
|
22
24
|
if (meta.strategy.name === "pagination") return /* @__PURE__ */ jsx(PaginationTableFooter, { table });
|
|
23
25
|
if (meta.strategy.name === "infinite") return /* @__PURE__ */ jsx(InfinteTableBottombar, { table });
|
|
26
|
+
if (meta.strategy.name === "local") return /* @__PURE__ */ jsx(LocalTableFooter, { table });
|
|
24
27
|
throw new Error(`Unknown strategy: ${meta.strategy.name}`);
|
|
25
28
|
}
|
|
26
29
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CommandFor } from "../../commands/lib/builder.mjs";
|
|
2
2
|
import { TableFiltersResult } from "../lib/filters/config.mjs";
|
|
3
3
|
import { Selection, TableColumnDef, TableMetaInput, TableStrategy } from "../lib/types.mjs";
|
|
4
4
|
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
@@ -21,7 +21,7 @@ type TableConfigContextValue<TData, TFilters extends TableFiltersResult = TableF
|
|
|
21
21
|
strategy: TableStrategy;
|
|
22
22
|
selection?: Selection;
|
|
23
23
|
columnVisibility?: VisibilityState;
|
|
24
|
-
commands?:
|
|
24
|
+
commands?: CommandFor<TData[], TMeta>[];
|
|
25
25
|
meta?: TMeta;
|
|
26
26
|
where?: TFilters;
|
|
27
27
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Permission } from "../../auth/lib/permissions.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { CommandFor } from "../../commands/lib/builder.mjs";
|
|
3
3
|
import { UseQueryStatesKeysMap } from "nuqs";
|
|
4
4
|
import { ColumnDef, PaginationState, RowSelectionState, SortingState, TableMeta, Updater } from "@tanstack/react-table";
|
|
5
5
|
|
|
@@ -11,7 +11,7 @@ type TableMetaInput<TData> = TableMeta<TData>;
|
|
|
11
11
|
type TableMeta$1<TData, TMeta = TableMetaInput<TData>> = {
|
|
12
12
|
strategy: TableStrategy;
|
|
13
13
|
selectedData: TData[];
|
|
14
|
-
commands?:
|
|
14
|
+
commands?: CommandFor<TData[], TMeta>[];
|
|
15
15
|
};
|
|
16
16
|
/**
|
|
17
17
|
* Table column definition
|
|
@@ -24,7 +24,7 @@ type TableColumnDef<TData> = ColumnDef<TData> & {
|
|
|
24
24
|
* Data table strategy
|
|
25
25
|
*/
|
|
26
26
|
type TableStrategy = {
|
|
27
|
-
name: "pagination" | "infinite";
|
|
27
|
+
name: "pagination" | "infinite" | "local";
|
|
28
28
|
rowCount?: number;
|
|
29
29
|
paginationState?: PaginationState;
|
|
30
30
|
manualPagination?: boolean;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
|
|
5
|
+
//#region src/modules/data-tables/strategies/local/components.tsx
|
|
6
|
+
function LocalTableFooter({ table }) {
|
|
7
|
+
const selected = Object.keys(table.getState().rowSelection).length;
|
|
8
|
+
const total = table.getRowCount();
|
|
9
|
+
return /* @__PURE__ */ jsx("div", {
|
|
10
|
+
className: "flex flex-col gap-y-2 px-2 md:flex-row md:items-center md:justify-between",
|
|
11
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
12
|
+
className: "text-muted-foreground text-sm",
|
|
13
|
+
children: [
|
|
14
|
+
selected ?? table.getFilteredSelectedRowModel().rows.length,
|
|
15
|
+
" of",
|
|
16
|
+
" ",
|
|
17
|
+
total ?? table.getRowModel().rows.length,
|
|
18
|
+
" row(s) selected."
|
|
19
|
+
]
|
|
20
|
+
})
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
export { LocalTableFooter };
|