@tulip-systems/core 0.9.0 → 0.10.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/dist/commands.d.mts +3 -2
- package/dist/commands.mjs +2 -1
- package/dist/components/ui/badge.d.mts +1 -1
- package/dist/components/ui/button-group.d.mts +1 -1
- package/dist/components/ui/button.d.mts +2 -2
- package/dist/components/ui/field.client.d.mts +1 -1
- package/dist/data-tables/client.d.mts +2 -1
- package/dist/data-tables/client.mjs +2 -1
- 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/lib/service.server.d.mts +9 -9
- package/dist/router.d.mts +2 -1
- package/dist/router.mjs +2 -1
- 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/components/ui/item.d.mts +1 -1
- package/dist/src/modules/auth/handler/create-client.client.d.mts +2 -2
- 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/inline/lib/variants.d.mts +1 -1
- package/dist/src/modules/router/lib/query-client.d.mts +2 -1
- package/dist/src/modules/router/lib/query-client.mjs +2 -2
- package/dist/src/modules/storage/lib/service.server.d.mts +21 -21
- package/package.json +1 -1
- 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 +91 -0
|
@@ -1,10 +1,66 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type { CommandDef } from "./builder";
|
|
1
|
+
import type { AnyCommandDef } from "./builder";
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* Command map type defining the shape of command definitions.
|
|
6
5
|
*/
|
|
7
|
-
export type CommandMap = Record<string,
|
|
6
|
+
export type CommandMap = Record<string, AnyCommandDef>;
|
|
7
|
+
|
|
8
|
+
/** Union of all values in a command map. */
|
|
9
|
+
type ValueOf<TCommands extends CommandMap> = TCommands[keyof TCommands];
|
|
10
|
+
|
|
11
|
+
// ─── Tag filter type helpers ───────────────────────────────────────────────────
|
|
12
|
+
// Each helper checks ONLY the `tags` field to avoid function-type variance issues.
|
|
13
|
+
// Commands with non-literal `string[]` tags are always kept (conservative fallback).
|
|
14
|
+
|
|
15
|
+
/** Keep commands that have **every** of `TFilterTags`. */
|
|
16
|
+
type FilterAllTags<
|
|
17
|
+
TCommand extends AnyCommandDef,
|
|
18
|
+
TFilterTags extends readonly string[],
|
|
19
|
+
> = TCommand extends { tags: infer CmdTags extends readonly string[] }
|
|
20
|
+
? TFilterTags[number] extends CmdTags[number]
|
|
21
|
+
? TCommand
|
|
22
|
+
: never
|
|
23
|
+
: TCommand;
|
|
24
|
+
|
|
25
|
+
/** Keep commands that have **some** of `TFilterTags`. */
|
|
26
|
+
type FilterAnyTags<
|
|
27
|
+
TCommand extends AnyCommandDef,
|
|
28
|
+
TFilterTags extends readonly string[],
|
|
29
|
+
> = TCommand extends { tags: infer CmdTags extends readonly string[] }
|
|
30
|
+
? string[] extends CmdTags
|
|
31
|
+
? TCommand
|
|
32
|
+
: Extract<CmdTags[number], TFilterTags[number]> extends never
|
|
33
|
+
? never
|
|
34
|
+
: TCommand
|
|
35
|
+
: TCommand;
|
|
36
|
+
|
|
37
|
+
/** Keep commands whose tag set equals `TFilterTags` (order-insensitive). */
|
|
38
|
+
type FilterExactTags<
|
|
39
|
+
TCommand extends AnyCommandDef,
|
|
40
|
+
TFilterTags extends readonly string[],
|
|
41
|
+
> = TCommand extends { tags: infer CmdTags extends readonly string[] }
|
|
42
|
+
? string[] extends CmdTags
|
|
43
|
+
? TCommand
|
|
44
|
+
: [CmdTags[number]] extends [TFilterTags[number]]
|
|
45
|
+
? [TFilterTags[number]] extends [CmdTags[number]]
|
|
46
|
+
? TCommand
|
|
47
|
+
: never
|
|
48
|
+
: never
|
|
49
|
+
: TCommand;
|
|
50
|
+
|
|
51
|
+
/** Keep commands that have **without** of `TFilterTags`. */
|
|
52
|
+
type FilterWithoutTags<
|
|
53
|
+
TCommand extends AnyCommandDef,
|
|
54
|
+
TFilterTags extends readonly string[],
|
|
55
|
+
> = TCommand extends { tags: infer CmdTags extends readonly string[] }
|
|
56
|
+
? string[] extends CmdTags
|
|
57
|
+
? TCommand
|
|
58
|
+
: Extract<CmdTags[number], TFilterTags[number]> extends never
|
|
59
|
+
? TCommand
|
|
60
|
+
: never
|
|
61
|
+
: TCommand;
|
|
62
|
+
|
|
63
|
+
// ─── Registry type definitions ─────────────────────────────────────────────────
|
|
8
64
|
|
|
9
65
|
type CommandKey<TCommands extends CommandMap> = Extract<keyof TCommands, string>;
|
|
10
66
|
type CommandFlags<TCommands extends CommandMap> = Partial<Record<CommandKey<TCommands>, boolean>>;
|
|
@@ -12,9 +68,7 @@ type CommandInput<TCommands extends CommandMap> =
|
|
|
12
68
|
| readonly CommandKey<TCommands>[]
|
|
13
69
|
| CommandFlags<TCommands>;
|
|
14
70
|
|
|
15
|
-
type TruthyKeys<T> = {
|
|
16
|
-
[K in keyof T]-?: T[K] extends true ? K : never;
|
|
17
|
-
}[keyof T];
|
|
71
|
+
type TruthyKeys<T> = { [K in keyof T]-?: T[K] extends true ? K : never }[keyof T];
|
|
18
72
|
|
|
19
73
|
type PickedCommands<
|
|
20
74
|
TCommands extends CommandMap,
|
|
@@ -22,8 +76,8 @@ type PickedCommands<
|
|
|
22
76
|
> = TInput extends readonly CommandKey<TCommands>[]
|
|
23
77
|
? Pick<TCommands, TInput[number]>
|
|
24
78
|
: TInput extends CommandFlags<TCommands>
|
|
25
|
-
|
|
26
|
-
|
|
79
|
+
? Pick<TCommands, Extract<TruthyKeys<TInput>, keyof TCommands>>
|
|
80
|
+
: never;
|
|
27
81
|
|
|
28
82
|
type OmittedCommands<
|
|
29
83
|
TCommands extends CommandMap,
|
|
@@ -31,8 +85,8 @@ type OmittedCommands<
|
|
|
31
85
|
> = TInput extends readonly CommandKey<TCommands>[]
|
|
32
86
|
? Omit<TCommands, TInput[number]>
|
|
33
87
|
: TInput extends CommandFlags<TCommands>
|
|
34
|
-
|
|
35
|
-
|
|
88
|
+
? Omit<TCommands, Extract<TruthyKeys<TInput>, keyof TCommands>>
|
|
89
|
+
: never;
|
|
36
90
|
|
|
37
91
|
type ExtendedCommands<TBase extends CommandMap, TExtension extends CommandMap> = Omit<
|
|
38
92
|
TBase,
|
|
@@ -40,74 +94,183 @@ type ExtendedCommands<TBase extends CommandMap, TExtension extends CommandMap> =
|
|
|
40
94
|
> &
|
|
41
95
|
TExtension;
|
|
42
96
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
97
|
+
type CommandTagFilterRegistry<TCommand extends AnyCommandDef> = {
|
|
98
|
+
every<const TTags extends string[]>(
|
|
99
|
+
...tags: TTags
|
|
100
|
+
): CommandTagFilterRegistry<FilterAllTags<TCommand, TTags>>;
|
|
101
|
+
some<const TTags extends string[]>(
|
|
102
|
+
...tags: TTags
|
|
103
|
+
): CommandTagFilterRegistry<FilterAnyTags<TCommand, TTags>>;
|
|
104
|
+
exact<const TTags extends string[]>(
|
|
105
|
+
...tags: TTags
|
|
106
|
+
): CommandTagFilterRegistry<FilterExactTags<TCommand, TTags>>;
|
|
107
|
+
without<const TTags extends string[]>(
|
|
108
|
+
...tags: TTags
|
|
109
|
+
): CommandTagFilterRegistry<FilterWithoutTags<TCommand, TTags>>;
|
|
110
|
+
toArray(): TCommand[];
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
type CommandKeyFilterRegistry<TCommands extends CommandMap> = {
|
|
114
|
+
pick<const TInput extends CommandInput<TCommands>>(
|
|
115
|
+
input: TInput,
|
|
116
|
+
): CommandKeyFilterRegistry<PickedCommands<TCommands, TInput>>;
|
|
117
|
+
omit<const TInput extends CommandInput<TCommands>>(
|
|
118
|
+
input: TInput,
|
|
119
|
+
): CommandKeyFilterRegistry<OmittedCommands<TCommands, TInput>>;
|
|
120
|
+
toArray(): ValueOf<TCommands>[];
|
|
121
|
+
};
|
|
122
|
+
|
|
47
123
|
type CommandRegistry<TCommands extends CommandMap> = {
|
|
48
124
|
commands: TCommands;
|
|
125
|
+
keys: CommandKeyFilterRegistry<TCommands>;
|
|
126
|
+
tags: CommandTagFilterRegistry<ValueOf<TCommands>>;
|
|
49
127
|
extend<const TExtension extends CommandMap>(
|
|
50
128
|
extension: TExtension,
|
|
51
129
|
): CommandRegistry<ExtendedCommands<TCommands, TExtension>>;
|
|
130
|
+
/** @deprecated Use `commands.keys.pick(...)` instead. */
|
|
52
131
|
pick<const TInput extends CommandInput<TCommands>>(
|
|
53
132
|
input: TInput,
|
|
54
133
|
): CommandRegistry<PickedCommands<TCommands, TInput>>;
|
|
134
|
+
/** @deprecated Use `commands.keys.omit(...)` instead. */
|
|
55
135
|
omit<const TInput extends CommandInput<TCommands>>(
|
|
56
136
|
input: TInput,
|
|
57
137
|
): CommandRegistry<OmittedCommands<TCommands, TInput>>;
|
|
58
|
-
toArray():
|
|
138
|
+
toArray(): ValueOf<TCommands>[];
|
|
59
139
|
};
|
|
60
140
|
|
|
61
|
-
|
|
141
|
+
// ─── Runtime helpers ───────────────────────────────────────────────────────────
|
|
142
|
+
|
|
143
|
+
function resolveKeys<TCommands extends CommandMap>(
|
|
62
144
|
input: CommandInput<TCommands>,
|
|
63
|
-
):
|
|
145
|
+
): CommandKey<TCommands>[] {
|
|
64
146
|
if (Array.isArray(input)) return [...input];
|
|
65
|
-
|
|
66
|
-
return (Object.entries(input) as Array<[CommandKey<TCommands>, boolean | undefined]>)
|
|
147
|
+
return Object.entries(input)
|
|
67
148
|
.filter(([, enabled]) => enabled === true)
|
|
68
|
-
.map(([key]) => key);
|
|
149
|
+
.map(([key]) => key as CommandKey<TCommands>);
|
|
69
150
|
}
|
|
70
151
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
152
|
+
function dedupe(tags: readonly string[]) {
|
|
153
|
+
return [...new Set(tags)];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function hasEveryTag(command: AnyCommandDef, tags: readonly string[]) {
|
|
157
|
+
return tags.every((tag) => command.tags.includes(tag));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function hasSomeTag(command: AnyCommandDef, tags: readonly string[]) {
|
|
161
|
+
return tags.some((tag) => command.tags.includes(tag));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function hasExactTags(command: AnyCommandDef, tags: readonly string[]) {
|
|
165
|
+
const ctags = dedupe(command.tags);
|
|
166
|
+
const ftags = dedupe(tags);
|
|
167
|
+
return ctags.length === ftags.length && ftags.every((t) => ctags.includes(t));
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function injectIds<TCommands extends CommandMap>(commands: TCommands): TCommands {
|
|
171
|
+
return Object.fromEntries(
|
|
172
|
+
Object.entries(commands).map(([id, c]) => [id, { ...c, id }]),
|
|
173
|
+
) as TCommands;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function pickCommands<TCommands extends CommandMap, TInput extends CommandInput<TCommands>>(
|
|
75
177
|
commands: TCommands,
|
|
76
|
-
|
|
178
|
+
input: TInput,
|
|
179
|
+
): PickedCommands<TCommands, TInput> {
|
|
180
|
+
const keys = resolveKeys<TCommands>(input);
|
|
181
|
+
return Object.fromEntries(
|
|
182
|
+
keys.filter((k) => k in commands).map((k) => [k, commands[k]]),
|
|
183
|
+
) as PickedCommands<TCommands, TInput>;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function omitCommands<TCommands extends CommandMap, TInput extends CommandInput<TCommands>>(
|
|
187
|
+
commands: TCommands,
|
|
188
|
+
input: TInput,
|
|
189
|
+
): OmittedCommands<TCommands, TInput> {
|
|
190
|
+
const keys = new Set(resolveKeys<TCommands>(input));
|
|
191
|
+
return Object.fromEntries(
|
|
192
|
+
Object.entries(commands).filter(([k]) => !keys.has(k as CommandKey<TCommands>)),
|
|
193
|
+
) as OmittedCommands<TCommands, TInput>;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function createTagFilterRegistry<TCommand extends AnyCommandDef>(
|
|
197
|
+
commands: TCommand[],
|
|
198
|
+
): CommandTagFilterRegistry<TCommand> {
|
|
199
|
+
function apply<const TTags extends string[]>(
|
|
200
|
+
predicate: (cmd: AnyCommandDef, tags: readonly string[]) => boolean,
|
|
201
|
+
) {
|
|
202
|
+
return (...tags: TTags) => {
|
|
203
|
+
const filtered = commands.filter((c) => predicate(c, tags));
|
|
204
|
+
return createTagFilterRegistry(filtered) as CommandTagFilterRegistry<any>;
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
77
208
|
return {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
209
|
+
every: apply(hasEveryTag) as CommandTagFilterRegistry<TCommand>["every"],
|
|
210
|
+
some: apply(hasSomeTag) as CommandTagFilterRegistry<TCommand>["some"],
|
|
211
|
+
exact: apply(hasExactTags) as CommandTagFilterRegistry<TCommand>["exact"],
|
|
212
|
+
without: apply((c, ts) => !hasSomeTag(c, ts)) as CommandTagFilterRegistry<TCommand>["without"],
|
|
213
|
+
toArray() {
|
|
214
|
+
return commands;
|
|
82
215
|
},
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const next = Object.fromEntries(
|
|
86
|
-
keys.flatMap((key) => (key in commands ? [[key, commands[key]]] : [])),
|
|
87
|
-
) as PickedCommands<TCommands, TInput>;
|
|
216
|
+
};
|
|
217
|
+
}
|
|
88
218
|
|
|
89
|
-
|
|
219
|
+
function createKeyFilterRegistry<TCommands extends CommandMap>(
|
|
220
|
+
commands: TCommands,
|
|
221
|
+
): CommandKeyFilterRegistry<TCommands> {
|
|
222
|
+
return {
|
|
223
|
+
pick<const TInput extends CommandInput<TCommands>>(input: TInput) {
|
|
224
|
+
return createKeyFilterRegistry(pickCommands(commands, input));
|
|
90
225
|
},
|
|
91
226
|
omit<const TInput extends CommandInput<TCommands>>(input: TInput) {
|
|
92
|
-
|
|
93
|
-
const blacklist = new Set(keys);
|
|
94
|
-
const next = Object.fromEntries(
|
|
95
|
-
Object.entries(commands).filter(([key]) => !blacklist.has(key as CommandKey<TCommands>)),
|
|
96
|
-
) as OmittedCommands<TCommands, TInput>;
|
|
97
|
-
|
|
98
|
-
return createRegistry(next);
|
|
227
|
+
return createKeyFilterRegistry(omitCommands(commands, input));
|
|
99
228
|
},
|
|
100
229
|
toArray() {
|
|
101
|
-
return Object.values(commands) as
|
|
230
|
+
return Object.values(commands) as ValueOf<TCommands>[];
|
|
102
231
|
},
|
|
103
232
|
};
|
|
104
233
|
}
|
|
105
234
|
|
|
235
|
+
function createRegistry<TCommands extends CommandMap>(
|
|
236
|
+
commands: TCommands,
|
|
237
|
+
): CommandRegistry<TCommands> {
|
|
238
|
+
const withIds = injectIds(commands);
|
|
239
|
+
const keys = createKeyFilterRegistry(withIds);
|
|
240
|
+
|
|
241
|
+
return {
|
|
242
|
+
commands: withIds,
|
|
243
|
+
keys,
|
|
244
|
+
tags: createTagFilterRegistry(Object.values(withIds) as ValueOf<TCommands>[]),
|
|
245
|
+
extend<const TExtension extends CommandMap>(extension: TExtension) {
|
|
246
|
+
return createRegistry({ ...withIds, ...extension } as ExtendedCommands<
|
|
247
|
+
TCommands,
|
|
248
|
+
TExtension
|
|
249
|
+
>);
|
|
250
|
+
},
|
|
251
|
+
pick(input) {
|
|
252
|
+
return createRegistry(pickCommands(withIds, input as CommandInput<TCommands>));
|
|
253
|
+
},
|
|
254
|
+
omit(input) {
|
|
255
|
+
return createRegistry(omitCommands(withIds, input as CommandInput<TCommands>));
|
|
256
|
+
},
|
|
257
|
+
toArray() {
|
|
258
|
+
return Object.values(withIds) as ValueOf<TCommands>[];
|
|
259
|
+
},
|
|
260
|
+
} as CommandRegistry<TCommands>;
|
|
261
|
+
}
|
|
262
|
+
|
|
106
263
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
264
|
+
* Define commands from a map of name → `CommandDef`.
|
|
265
|
+
*
|
|
266
|
+
* Returns a `CommandRegistry` with key-based and tag-based filtering, plus
|
|
267
|
+
* `extend` for composition. Filter chains are immutable — each call produces
|
|
268
|
+
* a new registry.
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* const registry = defineCommands({ edit, delete, archive });
|
|
272
|
+
* registry.tags.every("danger", "table").toArray();
|
|
273
|
+
* registry.keys.omit({ delete: true }).toArray();
|
|
111
274
|
*/
|
|
112
275
|
export function defineCommands<TCommands extends CommandMap>(
|
|
113
276
|
commands: TCommands,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes command data into an array.
|
|
3
|
+
*
|
|
4
|
+
* Use this as a command transform when the same command should support both
|
|
5
|
+
* single-item and bulk contexts. After `.transform(ensureArray)`, command
|
|
6
|
+
* callbacks can safely use array helpers like `.map` and `.every`.
|
|
7
|
+
*/
|
|
8
|
+
export function ensureArray<T>(data: T | T[]) {
|
|
9
|
+
return Array.isArray(data) ? data : [data];
|
|
10
|
+
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import type { Table } from "@tanstack/react-table";
|
|
4
4
|
import type { TableMeta } from "../lib/types";
|
|
5
5
|
import { InfinteTableBottombar, InfinteTableFooter } from "../strategies/infinite/components";
|
|
6
|
+
import { LocalTableFooter } from "../strategies/local/components";
|
|
6
7
|
import { PaginationTableFooter } from "../strategies/pagination/components";
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -19,6 +20,10 @@ export function TableFooter<TData>({ table }: { table: Table<TData> }) {
|
|
|
19
20
|
return <InfinteTableFooter table={table} />;
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
if (meta.strategy.name === "local") {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
22
27
|
throw new Error(`Unknown strategy: ${meta.strategy.name}`);
|
|
23
28
|
}
|
|
24
29
|
|
|
@@ -36,5 +41,9 @@ export function TableBottombar<TData>({ table }: { table: Table<TData> }) {
|
|
|
36
41
|
return <InfinteTableBottombar table={table} />;
|
|
37
42
|
}
|
|
38
43
|
|
|
44
|
+
if (meta.strategy.name === "local") {
|
|
45
|
+
return <LocalTableFooter table={table} />;
|
|
46
|
+
}
|
|
47
|
+
|
|
39
48
|
throw new Error(`Unknown strategy: ${meta.strategy.name}`);
|
|
40
49
|
}
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
useEffect,
|
|
11
11
|
useState,
|
|
12
12
|
} from "react";
|
|
13
|
-
import type {
|
|
13
|
+
import type { CommandFor } from "@/modules/commands/lib/builder";
|
|
14
14
|
import type { TableFiltersResult } from "../lib/filters/config";
|
|
15
15
|
import type { Selection, TableColumnDef, TableMetaInput, TableStrategy } from "../lib/types";
|
|
16
16
|
|
|
@@ -34,7 +34,7 @@ export type TableConfigContextValue<
|
|
|
34
34
|
strategy: TableStrategy;
|
|
35
35
|
selection?: Selection;
|
|
36
36
|
columnVisibility?: VisibilityState;
|
|
37
|
-
commands?:
|
|
37
|
+
commands?: CommandFor<TData[], TMeta>[];
|
|
38
38
|
meta?: TMeta;
|
|
39
39
|
where?: TFilters;
|
|
40
40
|
};
|
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
} from "@tanstack/react-table";
|
|
9
9
|
import type { UseQueryStatesKeysMap } from "nuqs";
|
|
10
10
|
import type { Permission } from "@/modules/auth/lib/permissions";
|
|
11
|
-
import type {
|
|
11
|
+
import type { CommandFor } from "@/modules/commands/lib/builder";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Data table meta
|
|
@@ -18,7 +18,7 @@ export type TableMetaInput<TData> = TanStackTableMeta<TData>;
|
|
|
18
18
|
export type TableMeta<TData, TMeta = TableMetaInput<TData>> = {
|
|
19
19
|
strategy: TableStrategy;
|
|
20
20
|
selectedData: TData[];
|
|
21
|
-
commands?:
|
|
21
|
+
commands?: CommandFor<TData[], TMeta>[];
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
/**
|
|
@@ -33,7 +33,7 @@ export type TableColumnDef<TData> = ColumnDef<TData> & {
|
|
|
33
33
|
* Data table strategy
|
|
34
34
|
*/
|
|
35
35
|
export type TableStrategy = {
|
|
36
|
-
name: "pagination" | "infinite";
|
|
36
|
+
name: "pagination" | "infinite" | "local";
|
|
37
37
|
// Pagination
|
|
38
38
|
rowCount?: number;
|
|
39
39
|
paginationState?: PaginationState;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { Table } from "@tanstack/react-table";
|
|
4
|
+
|
|
5
|
+
export function LocalTableFooter<TData>({ table }: { table: Table<TData> }) {
|
|
6
|
+
const selected = Object.keys(table.getState().rowSelection).length;
|
|
7
|
+
const total = table.getRowCount();
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<div className="flex flex-col gap-y-2 px-2 md:flex-row md:items-center md:justify-between">
|
|
11
|
+
<div className="text-muted-foreground text-sm">
|
|
12
|
+
{selected ?? table.getFilteredSelectedRowModel().rows.length} of{" "}
|
|
13
|
+
{total ?? table.getRowModel().rows.length} row(s) selected.
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { SortingState } from "@tanstack/react-table";
|
|
4
|
+
import { useQueryStates } from "nuqs";
|
|
5
|
+
import { tableSearchParams } from "../../entry";
|
|
6
|
+
import type { TableStrategy } from "../../lib/types";
|
|
7
|
+
import { handleSortingChange } from "../helpers/sorting";
|
|
8
|
+
|
|
9
|
+
export type UseLocalStrategyInput = {
|
|
10
|
+
total?: number;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type LocalStrategy = typeof useLocalStrategy;
|
|
14
|
+
|
|
15
|
+
export function useLocalStrategy({ total }: UseLocalStrategyInput = {}): TableStrategy {
|
|
16
|
+
const [query, setQuery] = useQueryStates(tableSearchParams);
|
|
17
|
+
|
|
18
|
+
const sortingState: SortingState = query.sort
|
|
19
|
+
? [{ id: query.sort, desc: query.order === "desc" }]
|
|
20
|
+
: [];
|
|
21
|
+
|
|
22
|
+
const resetCursor = () => null;
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
name: "local",
|
|
26
|
+
rowCount: total,
|
|
27
|
+
resetCursor,
|
|
28
|
+
tableSearchParams,
|
|
29
|
+
sortingState,
|
|
30
|
+
manualSorting: true,
|
|
31
|
+
onSortingChange: handleSortingChange({ sortingState, setQuery, resetCursor }),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -19,15 +19,20 @@ import { type InlineEditVariantsProps, inlineEditVariants } from "../../lib/vari
|
|
|
19
19
|
|
|
20
20
|
type ComboboxDropdownInlineTrigger = "commit";
|
|
21
21
|
|
|
22
|
+
type InlineStringSchema =
|
|
23
|
+
| z.ZodType<string | null, string | null>
|
|
24
|
+
| z.ZodType<string, string>;
|
|
25
|
+
|
|
22
26
|
export type InlineEditComboboxDropdownProps<
|
|
23
27
|
TValue extends ComboboxDropdownItem,
|
|
28
|
+
TSchema extends InlineStringSchema = z.ZodType<string | null, string | null>,
|
|
24
29
|
TData = unknown,
|
|
25
30
|
TError = DefaultError,
|
|
26
31
|
TVariables = unknown,
|
|
27
32
|
TOnMutateResult = unknown,
|
|
28
33
|
> = useInlineEditOptions<
|
|
29
34
|
ComboboxDropdownInlineTrigger,
|
|
30
|
-
|
|
35
|
+
TSchema,
|
|
31
36
|
TData,
|
|
32
37
|
TError,
|
|
33
38
|
TVariables,
|
|
@@ -40,6 +45,7 @@ export type InlineEditComboboxDropdownProps<
|
|
|
40
45
|
|
|
41
46
|
export function InlineComboboxDropdown<
|
|
42
47
|
TValue extends ComboboxDropdownItem,
|
|
48
|
+
TSchema extends InlineStringSchema = z.ZodType<string | null, string | null>,
|
|
43
49
|
TData = unknown,
|
|
44
50
|
TError = DefaultError,
|
|
45
51
|
TVariables = unknown,
|
|
@@ -56,11 +62,11 @@ export function InlineComboboxDropdown<
|
|
|
56
62
|
strategy,
|
|
57
63
|
disabled,
|
|
58
64
|
...props
|
|
59
|
-
}: InlineEditComboboxDropdownProps<TValue, TData, TError, TVariables, TOnMutateResult>) {
|
|
65
|
+
}: InlineEditComboboxDropdownProps<TValue, TSchema, TData, TError, TVariables, TOnMutateResult>) {
|
|
60
66
|
const state = useInlineState<string | null>(initialValue);
|
|
61
67
|
const access = useInlineAccess({ permission, disabled });
|
|
62
68
|
const mutations = useInlineMutation<
|
|
63
|
-
|
|
69
|
+
TSchema,
|
|
64
70
|
string | null,
|
|
65
71
|
TData,
|
|
66
72
|
TError,
|
|
@@ -75,7 +81,7 @@ export function InlineComboboxDropdown<
|
|
|
75
81
|
|
|
76
82
|
const { handleTrigger } = useInlineStrategy<
|
|
77
83
|
ComboboxDropdownInlineTrigger,
|
|
78
|
-
|
|
84
|
+
TSchema,
|
|
79
85
|
string | null
|
|
80
86
|
>({
|
|
81
87
|
strategy,
|
|
@@ -83,7 +89,7 @@ export function InlineComboboxDropdown<
|
|
|
83
89
|
mutations,
|
|
84
90
|
parser: {
|
|
85
91
|
decode: (value) => value,
|
|
86
|
-
encode: (value) => value
|
|
92
|
+
encode: (value) => value as z.input<TSchema>,
|
|
87
93
|
},
|
|
88
94
|
});
|
|
89
95
|
|
|
@@ -13,15 +13,20 @@ import {
|
|
|
13
13
|
|
|
14
14
|
type ComboboxInlineTrigger = "commit";
|
|
15
15
|
|
|
16
|
+
type InlineStringSchema =
|
|
17
|
+
| z.ZodType<string | null, string | null>
|
|
18
|
+
| z.ZodType<string, string>;
|
|
19
|
+
|
|
16
20
|
export type InlineComboboxProps<
|
|
17
21
|
TValue,
|
|
22
|
+
TSchema extends InlineStringSchema = z.ZodType<string | null, string | null>,
|
|
18
23
|
TData = unknown,
|
|
19
24
|
TError = DefaultError,
|
|
20
25
|
TVariables = unknown,
|
|
21
26
|
TOnMutateResult = unknown,
|
|
22
27
|
> = useInlineEditOptions<
|
|
23
28
|
ComboboxInlineTrigger,
|
|
24
|
-
|
|
29
|
+
TSchema,
|
|
25
30
|
TData,
|
|
26
31
|
TError,
|
|
27
32
|
TVariables,
|
|
@@ -31,6 +36,7 @@ export type InlineComboboxProps<
|
|
|
31
36
|
|
|
32
37
|
export function InlineCombobox<
|
|
33
38
|
TValue,
|
|
39
|
+
TSchema extends InlineStringSchema = z.ZodType<string | null, string | null>,
|
|
34
40
|
TData = unknown,
|
|
35
41
|
TError = DefaultError,
|
|
36
42
|
TVariables = unknown,
|
|
@@ -45,11 +51,11 @@ export function InlineCombobox<
|
|
|
45
51
|
disabled,
|
|
46
52
|
strategy,
|
|
47
53
|
...props
|
|
48
|
-
}: InlineComboboxProps<TValue, TData, TError, TVariables, TOnMutateResult>) {
|
|
54
|
+
}: InlineComboboxProps<TValue, TSchema, TData, TError, TVariables, TOnMutateResult>) {
|
|
49
55
|
const state = useInlineState<string | null>(initialValue);
|
|
50
56
|
const access = useInlineAccess({ permission, disabled });
|
|
51
57
|
const mutations = useInlineMutation<
|
|
52
|
-
|
|
58
|
+
TSchema,
|
|
53
59
|
string | null,
|
|
54
60
|
TData,
|
|
55
61
|
TError,
|
|
@@ -64,7 +70,7 @@ export function InlineCombobox<
|
|
|
64
70
|
|
|
65
71
|
const { handleTrigger } = useInlineStrategy<
|
|
66
72
|
ComboboxInlineTrigger,
|
|
67
|
-
|
|
73
|
+
TSchema,
|
|
68
74
|
string | null
|
|
69
75
|
>({
|
|
70
76
|
strategy,
|
|
@@ -72,7 +78,7 @@ export function InlineCombobox<
|
|
|
72
78
|
mutations,
|
|
73
79
|
parser: {
|
|
74
80
|
decode: (value) => value,
|
|
75
|
-
encode: (value) => value
|
|
81
|
+
encode: (value) => value as z.input<TSchema>,
|
|
76
82
|
},
|
|
77
83
|
});
|
|
78
84
|
|
|
@@ -17,7 +17,12 @@ import { type InlineEditVariantsProps, inlineEditVariants } from "../../lib/vari
|
|
|
17
17
|
|
|
18
18
|
type DateTimeInlineTrigger = "change" | "blur";
|
|
19
19
|
|
|
20
|
+
type InlineDateTimeSchema =
|
|
21
|
+
| z.ZodType<Date | null, Date | null>
|
|
22
|
+
| z.ZodType<Date, Date>;
|
|
23
|
+
|
|
20
24
|
type InlineDateTimeInputProps<
|
|
25
|
+
TSchema extends InlineDateTimeSchema = z.ZodType<Date | null, Date | null>,
|
|
21
26
|
TData = unknown,
|
|
22
27
|
TError = DefaultError,
|
|
23
28
|
TVariables = unknown,
|
|
@@ -25,7 +30,7 @@ type InlineDateTimeInputProps<
|
|
|
25
30
|
> = ComponentProps<typeof DateTimeInput> &
|
|
26
31
|
useInlineEditOptions<
|
|
27
32
|
DateTimeInlineTrigger,
|
|
28
|
-
|
|
33
|
+
TSchema,
|
|
29
34
|
TData,
|
|
30
35
|
TError,
|
|
31
36
|
TVariables,
|
|
@@ -34,6 +39,7 @@ type InlineDateTimeInputProps<
|
|
|
34
39
|
InlineEditVariantsProps;
|
|
35
40
|
|
|
36
41
|
export function InlineDateTimeInput<
|
|
42
|
+
TSchema extends InlineDateTimeSchema = z.ZodType<Date | null, Date | null>,
|
|
37
43
|
TData = unknown,
|
|
38
44
|
TError = DefaultError,
|
|
39
45
|
TVariables = unknown,
|
|
@@ -48,13 +54,13 @@ export function InlineDateTimeInput<
|
|
|
48
54
|
strategy,
|
|
49
55
|
disabled,
|
|
50
56
|
...props
|
|
51
|
-
}: InlineDateTimeInputProps<TData, TError, TVariables, TOnMutateResult>) {
|
|
57
|
+
}: InlineDateTimeInputProps<TSchema, TData, TError, TVariables, TOnMutateResult>) {
|
|
52
58
|
const state = useInlineState<string>(
|
|
53
59
|
initialValue ? format(initialValue, "yyyy-MM-dd'T'HH:mm") : "",
|
|
54
60
|
);
|
|
55
61
|
const access = useInlineAccess({ permission, disabled });
|
|
56
62
|
const mutations = useInlineMutation<
|
|
57
|
-
|
|
63
|
+
TSchema,
|
|
58
64
|
string,
|
|
59
65
|
TData,
|
|
60
66
|
TError,
|
|
@@ -69,7 +75,7 @@ export function InlineDateTimeInput<
|
|
|
69
75
|
|
|
70
76
|
const { handleTrigger } = useInlineStrategy<
|
|
71
77
|
DateTimeInlineTrigger,
|
|
72
|
-
|
|
78
|
+
TSchema,
|
|
73
79
|
string
|
|
74
80
|
>({
|
|
75
81
|
strategy,
|
|
@@ -77,7 +83,7 @@ export function InlineDateTimeInput<
|
|
|
77
83
|
mutations,
|
|
78
84
|
parser: {
|
|
79
85
|
decode: (date) => (date ? format(date, "yyyy-MM-dd'T'HH:mm") : ""),
|
|
80
|
-
encode: (dateTime) => (dateTime ? new Date(dateTime) : null)
|
|
86
|
+
encode: (dateTime) => (dateTime ? new Date(dateTime) : null) as z.input<TSchema>,
|
|
81
87
|
},
|
|
82
88
|
});
|
|
83
89
|
|