@alepha/ui 0.11.6 → 0.11.9

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/index.js CHANGED
@@ -1,16 +1,17 @@
1
- import { i as ToastService, n as Omnibar_default, r as useToast, t as AlephaMantineProvider_default } from "./AlephaMantineProvider-Be0DAazb.js";
2
- import { $module, TypeBoxError, t } from "@alepha/core";
1
+ import { i as ToastService, n as Omnibar_default, r as useToast, t as AlephaMantineProvider_default } from "./AlephaMantineProvider-CzMrw7V3.js";
2
+ import { $module, Alepha, TypeBoxError, t } from "@alepha/core";
3
3
  import { AlephaReactForm, useForm, useFormState } from "@alepha/react-form";
4
4
  import { AlephaReactHead } from "@alepha/react-head";
5
5
  import { AlephaReactI18n, useI18n } from "@alepha/react-i18n";
6
6
  import { $page, NestedView, useAction, useActive, useEvents, useInject, useRouter, useStore } from "@alepha/react";
7
+ import { ActionIcon, AppShell, Autocomplete, Badge, Box, Burger, Button, Collapse, ColorInput, CopyButton, Divider, FileInput, Flex, Flex as Flex$1, Grid, Group, Input, Kbd, Menu, MultiSelect, NumberInput, Pagination, PasswordInput, Popover, SegmentedControl, Select, Slider, Stack, Switch, Table, TagsInput, Text, Text as Text$1, TextInput, Textarea, ThemeIcon, Tooltip, useComputedColorScheme, useMantineColorScheme } from "@mantine/core";
7
8
  import { modals } from "@mantine/modals";
8
- import { ActionIcon, AppShell, Autocomplete, Badge, Burger, Button, Code, ColorInput, Divider, FileInput, Flex, Flex as Flex$1, Grid, Group, Input, Kbd, Menu, MultiSelect, NumberInput, Pagination, Paper, PasswordInput, Popover, SegmentedControl, Select, Slider, Stack, Switch, Table, TagsInput, Text, Text as Text$1, TextInput, Textarea, ThemeIcon, Tooltip, useComputedColorScheme, useMantineColorScheme } from "@mantine/core";
9
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
+ import { IconAt, IconCalendar, IconCheck, IconChevronDown, IconChevronRight, IconClock, IconColorPicker, IconCopy, IconFile, IconFilter, IconHash, IconInfoTriangle, IconKey, IconLanguage, IconLetterCase, IconLink, IconList, IconMail, IconMoon, IconPalette, IconPhone, IconSearch, IconSelector, IconSquareRounded, IconSun, IconToggleLeft, IconX } from "@tabler/icons-react";
10
10
  import { useCallback, useEffect, useRef, useState } from "react";
11
- import { IconAt, IconCalendar, IconCheck, IconChevronDown, IconChevronRight, IconClock, IconColorPicker, IconFile, IconFilter, IconHash, IconKey, IconLanguage, IconLetterCase, IconLink, IconList, IconMail, IconMoon, IconPalette, IconPhone, IconSearch, IconSelector, IconSquareRounded, IconSun, IconToggleLeft, IconX } from "@tabler/icons-react";
11
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
12
12
  import { spotlight } from "@mantine/spotlight";
13
13
  import { DateInput, DateTimePicker, TimeInput } from "@mantine/dates";
14
+ import { parseQueryString } from "@alepha/postgres";
14
15
  import { DateTimeProvider } from "@alepha/datetime";
15
16
  import { useDebouncedCallback } from "@mantine/hooks";
16
17
 
@@ -18,9 +19,297 @@ import { useDebouncedCallback } from "@mantine/hooks";
18
19
  var RootRouter = class {
19
20
  root = $page({
20
21
  path: "/",
21
- lazy: () => import("./AlephaMantineProvider-Ba88lMeq.js")
22
+ lazy: () => import("./AlephaMantineProvider-B4TwQ4tY.js")
23
+ });
24
+ };
25
+
26
+ //#endregion
27
+ //#region src/components/data/JsonViewer.tsx
28
+ const getSizeConfig = (size = "sm") => {
29
+ const configs = {
30
+ xs: {
31
+ text: "xs",
32
+ icon: 12,
33
+ indent: 16,
34
+ gap: 2
35
+ },
36
+ sm: {
37
+ text: "sm",
38
+ icon: 14,
39
+ indent: 20,
40
+ gap: 4
41
+ },
42
+ md: {
43
+ text: "md",
44
+ icon: 16,
45
+ indent: 24,
46
+ gap: 6
47
+ },
48
+ lg: {
49
+ text: "lg",
50
+ icon: 18,
51
+ indent: 28,
52
+ gap: 8
53
+ },
54
+ xl: {
55
+ text: "xl",
56
+ icon: 20,
57
+ indent: 32,
58
+ gap: 10
59
+ }
60
+ };
61
+ return configs[size] || configs.sm;
62
+ };
63
+ const JsonNode = ({ name, value, depth, maxDepth, isLast = false, isArrayItem = false, size = "sm" }) => {
64
+ const [expanded, setExpanded] = useState(depth < 2);
65
+ const sizeConfig = getSizeConfig(size);
66
+ const getValueType = (val) => {
67
+ if (val === null) return "null";
68
+ if (val === void 0) return "undefined";
69
+ if (Array.isArray(val)) return "array";
70
+ return typeof val;
71
+ };
72
+ const valueType = getValueType(value);
73
+ const renderPrimitive = (val) => {
74
+ switch (getValueType(val)) {
75
+ case "string": return /* @__PURE__ */ jsxs(Text$1, {
76
+ component: "span",
77
+ c: "teal",
78
+ ff: "monospace",
79
+ size: sizeConfig.text,
80
+ style: { whiteSpace: "nowrap" },
81
+ children: [
82
+ "\"",
83
+ val,
84
+ "\""
85
+ ]
86
+ });
87
+ case "number": return /* @__PURE__ */ jsx(Text$1, {
88
+ component: "span",
89
+ c: "blue",
90
+ ff: "monospace",
91
+ size: sizeConfig.text,
92
+ style: { whiteSpace: "nowrap" },
93
+ children: val
94
+ });
95
+ case "boolean": return /* @__PURE__ */ jsx(Text$1, {
96
+ component: "span",
97
+ c: "violet",
98
+ ff: "monospace",
99
+ size: sizeConfig.text,
100
+ style: { whiteSpace: "nowrap" },
101
+ children: String(val)
102
+ });
103
+ case "null": return /* @__PURE__ */ jsx(Text$1, {
104
+ component: "span",
105
+ c: "dimmed",
106
+ ff: "monospace",
107
+ size: sizeConfig.text,
108
+ style: { whiteSpace: "nowrap" },
109
+ children: "null"
110
+ });
111
+ case "undefined": return /* @__PURE__ */ jsx(Text$1, {
112
+ component: "span",
113
+ c: "dimmed",
114
+ ff: "monospace",
115
+ size: sizeConfig.text,
116
+ style: { whiteSpace: "nowrap" },
117
+ children: "undefined"
118
+ });
119
+ default: return /* @__PURE__ */ jsx(Text$1, {
120
+ component: "span",
121
+ ff: "monospace",
122
+ size: sizeConfig.text,
123
+ style: { whiteSpace: "nowrap" },
124
+ children: String(val)
125
+ });
126
+ }
127
+ };
128
+ const renderKey = () => {
129
+ if (!name) return null;
130
+ return /* @__PURE__ */ jsxs(Text$1, {
131
+ component: "span",
132
+ c: "cyan",
133
+ ff: "monospace",
134
+ fw: 500,
135
+ size: sizeConfig.text,
136
+ children: [isArrayItem ? `[${name}]` : `"${name}"`, ":"]
137
+ });
138
+ };
139
+ if (valueType === "object" || valueType === "array") {
140
+ const isObject = valueType === "object";
141
+ const entries = isObject ? Object.entries(value) : value.map((v, i) => [i, v]);
142
+ const isEmpty = entries.length === 0;
143
+ const canExpand = depth < maxDepth && !isEmpty;
144
+ const preview = isObject ? "{...}" : "[...]";
145
+ const brackets = isObject ? ["{", "}"] : ["[", "]"];
146
+ return /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsxs(Box, {
147
+ style: {
148
+ display: "flex",
149
+ alignItems: "center",
150
+ gap: sizeConfig.gap,
151
+ minWidth: "max-content"
152
+ },
153
+ children: [
154
+ canExpand && /* @__PURE__ */ jsx(ActionIcon, {
155
+ size: "xs",
156
+ variant: "transparent",
157
+ c: "dimmed",
158
+ onClick: () => setExpanded(!expanded),
159
+ style: {
160
+ cursor: "pointer",
161
+ flexShrink: 0
162
+ },
163
+ children: expanded ? /* @__PURE__ */ jsx(IconChevronDown, { size: sizeConfig.icon }) : /* @__PURE__ */ jsx(IconChevronRight, { size: sizeConfig.icon })
164
+ }),
165
+ !canExpand && /* @__PURE__ */ jsx(Box, {
166
+ w: sizeConfig.icon + 6,
167
+ style: { flexShrink: 0 }
168
+ }),
169
+ /* @__PURE__ */ jsx(Box, {
170
+ style: { flexShrink: 0 },
171
+ children: renderKey()
172
+ }),
173
+ " ",
174
+ /* @__PURE__ */ jsx(Text$1, {
175
+ component: "span",
176
+ c: "dimmed",
177
+ ff: "monospace",
178
+ size: sizeConfig.text,
179
+ style: { flexShrink: 0 },
180
+ children: brackets[0]
181
+ }),
182
+ !expanded && !isEmpty && /* @__PURE__ */ jsx(Text$1, {
183
+ component: "span",
184
+ c: "dimmed",
185
+ ff: "monospace",
186
+ fs: "italic",
187
+ size: sizeConfig.text,
188
+ style: { flexShrink: 0 },
189
+ children: preview
190
+ }),
191
+ (isEmpty || !expanded) && /* @__PURE__ */ jsx(Text$1, {
192
+ component: "span",
193
+ c: "dimmed",
194
+ ff: "monospace",
195
+ size: sizeConfig.text,
196
+ style: { flexShrink: 0 },
197
+ children: brackets[1]
198
+ }),
199
+ !isEmpty && !expanded && /* @__PURE__ */ jsxs(Text$1, {
200
+ component: "span",
201
+ c: "dimmed",
202
+ size: sizeConfig.text,
203
+ style: { flexShrink: 0 },
204
+ children: [
205
+ entries.length,
206
+ " ",
207
+ entries.length === 1 ? "item" : "items"
208
+ ]
209
+ })
210
+ ]
211
+ }), /* @__PURE__ */ jsxs(Collapse, {
212
+ in: expanded && canExpand,
213
+ children: [/* @__PURE__ */ jsx(Box, {
214
+ pl: sizeConfig.indent,
215
+ style: {
216
+ borderLeft: "1px solid var(--mantine-color-default-border)",
217
+ marginLeft: Math.floor((sizeConfig.icon + 6) / 2)
218
+ },
219
+ children: entries.map(([key, val], index) => /* @__PURE__ */ jsx(JsonNode, {
220
+ name: String(key),
221
+ value: val,
222
+ depth: depth + 1,
223
+ maxDepth,
224
+ isLast: index === entries.length - 1,
225
+ isArrayItem: !isObject,
226
+ size
227
+ }, String(key)))
228
+ }), /* @__PURE__ */ jsxs(Box, {
229
+ style: {
230
+ display: "flex",
231
+ minWidth: "max-content"
232
+ },
233
+ children: [/* @__PURE__ */ jsx(Box, {
234
+ w: sizeConfig.icon + 6,
235
+ style: { flexShrink: 0 }
236
+ }), /* @__PURE__ */ jsx(Text$1, {
237
+ c: "dimmed",
238
+ ff: "monospace",
239
+ size: sizeConfig.text,
240
+ style: { flexShrink: 0 },
241
+ children: brackets[1]
242
+ })]
243
+ })]
244
+ })] });
245
+ }
246
+ return /* @__PURE__ */ jsxs(Box, {
247
+ style: {
248
+ display: "flex",
249
+ alignItems: "center",
250
+ gap: sizeConfig.gap,
251
+ minWidth: "max-content"
252
+ },
253
+ children: [
254
+ /* @__PURE__ */ jsx(Box, {
255
+ w: sizeConfig.icon + 6,
256
+ style: { flexShrink: 0 }
257
+ }),
258
+ /* @__PURE__ */ jsx(Box, {
259
+ style: { flexShrink: 0 },
260
+ children: renderKey()
261
+ }),
262
+ /* @__PURE__ */ jsx(Box, {
263
+ style: { flexShrink: 0 },
264
+ children: renderPrimitive(value)
265
+ }),
266
+ !isLast && /* @__PURE__ */ jsx(Text$1, {
267
+ component: "span",
268
+ c: "dimmed",
269
+ ff: "monospace",
270
+ size: sizeConfig.text,
271
+ style: { flexShrink: 0 },
272
+ children: ","
273
+ })
274
+ ]
275
+ });
276
+ };
277
+ const JsonViewer = ({ data, defaultExpanded = true, maxDepth = 10, copyable = true, size = "sm" }) => {
278
+ const copyIconSize = getSizeConfig(size).icon + 2;
279
+ return /* @__PURE__ */ jsxs(Box, {
280
+ pos: "relative",
281
+ w: "100%",
282
+ children: [copyable && /* @__PURE__ */ jsx(Box, {
283
+ pos: "absolute",
284
+ top: 0,
285
+ right: 0,
286
+ style: { zIndex: 1 },
287
+ children: /* @__PURE__ */ jsx(CopyButton, {
288
+ value: JSON.stringify(data, null, 2),
289
+ children: ({ copied, copy }) => /* @__PURE__ */ jsx(Tooltip, {
290
+ label: copied ? "Copied" : "Copy JSON",
291
+ children: /* @__PURE__ */ jsx(ActionIcon, {
292
+ color: copied ? "teal" : "gray",
293
+ variant: "subtle",
294
+ onClick: copy,
295
+ size,
296
+ children: copied ? /* @__PURE__ */ jsx(IconCheck, { size: copyIconSize }) : /* @__PURE__ */ jsx(IconCopy, { size: copyIconSize })
297
+ })
298
+ })
299
+ })
300
+ }), /* @__PURE__ */ jsx(Box, {
301
+ pt: copyable ? 30 : 0,
302
+ style: { overflowX: "auto" },
303
+ children: /* @__PURE__ */ jsx(JsonNode, {
304
+ value: data,
305
+ depth: 0,
306
+ maxDepth,
307
+ size
308
+ })
309
+ })]
22
310
  });
23
311
  };
312
+ var JsonViewer_default = JsonViewer;
24
313
 
25
314
  //#endregion
26
315
  //#region src/components/dialogs/AlertDialog.tsx
@@ -100,6 +389,16 @@ const PromptDialog = ({ options, onSubmit }) => {
100
389
  };
101
390
  var PromptDialog_default = PromptDialog;
102
391
 
392
+ //#endregion
393
+ //#region src/constants/ui.ts
394
+ const ui = { colors: {
395
+ transparent: "transparent",
396
+ background: "var(--alepha-background)",
397
+ surface: "var(--alepha-surface)",
398
+ elevated: "var(--alepha-elevated)",
399
+ border: "var(--alepha-border)"
400
+ } };
401
+
103
402
  //#endregion
104
403
  //#region src/services/DialogService.tsx
105
404
  var DialogService = class {
@@ -194,7 +493,24 @@ var DialogService = class {
194
493
  /**
195
494
  * Show a JSON editor/viewer dialog
196
495
  */
197
- json(data, options) {}
496
+ json(data, options) {
497
+ this.open({
498
+ size: "lg",
499
+ title: options?.title || "Json Viewer",
500
+ ...options,
501
+ content: /* @__PURE__ */ jsx(Flex$1, {
502
+ bdrs: "md",
503
+ w: "100%",
504
+ flex: 1,
505
+ p: "sm",
506
+ bg: ui.colors.surface,
507
+ children: /* @__PURE__ */ jsx(JsonViewer_default, {
508
+ size: "xs",
509
+ data
510
+ })
511
+ })
512
+ });
513
+ }
198
514
  /**
199
515
  * Show a form dialog for structured input
200
516
  */
@@ -255,7 +571,7 @@ const ActionButton = (_props) => {
255
571
  variant: "subtle",
256
572
  ..._props
257
573
  };
258
- const { tooltip, menu, icon,...restProps } = props;
574
+ const { tooltip, menu, icon, ...restProps } = props;
259
575
  if (props.icon) {
260
576
  const icon$1 = /* @__PURE__ */ jsx(ThemeIcon, {
261
577
  w: 24,
@@ -275,7 +591,7 @@ const ActionButton = (_props) => {
275
591
  restProps.p ??= "xs";
276
592
  }
277
593
  if (props.textVisibleFrom) {
278
- const { children, textVisibleFrom, leftSection,...rest } = restProps;
594
+ const { children, textVisibleFrom, leftSection, ...rest } = restProps;
279
595
  return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Flex$1, {
280
596
  w: "100%",
281
597
  visibleFrom: textVisibleFrom,
@@ -375,7 +691,7 @@ var ActionButton_default = ActionButton;
375
691
  * Action button that submits a form with loading and disabled state handling.
376
692
  */
377
693
  const ActionSubmitButton = (props) => {
378
- const { form,...buttonProps } = props;
694
+ const { form, ...buttonProps } = props;
379
695
  const state = useFormState(form);
380
696
  return /* @__PURE__ */ jsx(Button, {
381
697
  ...buttonProps,
@@ -386,7 +702,7 @@ const ActionSubmitButton = (props) => {
386
702
  });
387
703
  };
388
704
  const ActionResetButton = (props) => {
389
- const { form,...buttonProps } = props;
705
+ const { form, ...buttonProps } = props;
390
706
  const state = useFormState(form);
391
707
  return /* @__PURE__ */ jsx(Button, {
392
708
  ...buttonProps,
@@ -413,7 +729,7 @@ const ActionResetButton = (props) => {
413
729
  * ```
414
730
  */
415
731
  const ActionHookButton = (props) => {
416
- const { action,...buttonProps } = props;
732
+ const { action, ...buttonProps } = props;
417
733
  return /* @__PURE__ */ jsx(Button, {
418
734
  ...buttonProps,
419
735
  disabled: action.loading || props.disabled,
@@ -448,7 +764,7 @@ const ActionClickButton = (props) => {
448
764
  * Action for navigation with active state support.
449
765
  */
450
766
  const ActionNavigationButton = (props) => {
451
- const { active: options, classNameActive, variantActive, routerGoOptions,...buttonProps } = props;
767
+ const { active: options, classNameActive, variantActive, routerGoOptions, ...buttonProps } = props;
452
768
  const router = useRouter();
453
769
  const { isPending, isActive } = useActive(options ? {
454
770
  href: props.href,
@@ -467,7 +783,7 @@ const ActionNavigationButton = (props) => {
467
783
  });
468
784
  };
469
785
  const ActionHrefButton = (props) => {
470
- const { active: options, classNameActive, variantActive, routerGoOptions, target,...buttonProps } = props;
786
+ const { active: options, classNameActive, variantActive, routerGoOptions, target, ...buttonProps } = props;
471
787
  return /* @__PURE__ */ jsx(Button, {
472
788
  component: "a",
473
789
  target,
@@ -742,7 +1058,7 @@ const ControlNumber = (props) => {
742
1058
  if (event.id === props.input?.form.id && ref.current) setValue(props.input.props.defaultValue);
743
1059
  } }, [props.input]);
744
1060
  if (!props.input?.props) return null;
745
- const { type,...inputPropsWithoutType } = props.input.props;
1061
+ const { type, ...inputPropsWithoutType } = props.input.props;
746
1062
  if (props.sliderProps) return /* @__PURE__ */ jsx(Input.Wrapper, {
747
1063
  ...inputProps,
748
1064
  children: /* @__PURE__ */ jsx("div", {
@@ -797,7 +1113,7 @@ function extractSchemaFields(schema, prefix = "") {
797
1113
  const fieldSchema = value;
798
1114
  const path = prefix ? `${prefix}.${key}` : key;
799
1115
  const format = "format" in fieldSchema ? fieldSchema.format : void 0;
800
- let displayType = "type" in fieldSchema ? fieldSchema.type : "unknown";
1116
+ let displayType = "type" in fieldSchema ? fieldSchema.type : "object";
801
1117
  if (format === "date-time") displayType = "datetime";
802
1118
  else if (format === "date") displayType = "date";
803
1119
  else if (format === "time") displayType = "time";
@@ -809,7 +1125,10 @@ function extractSchemaFields(schema, prefix = "") {
809
1125
  format,
810
1126
  description: "description" in fieldSchema ? fieldSchema.description : void 0
811
1127
  };
812
- if ("enum" in fieldSchema && fieldSchema.enum) field.enum = fieldSchema.enum;
1128
+ if ("enum" in fieldSchema && fieldSchema.enum) {
1129
+ field.enum = fieldSchema.enum;
1130
+ field.type = "enum";
1131
+ }
813
1132
  if ("type" in fieldSchema && fieldSchema.type === "object" && "properties" in fieldSchema && typeof fieldSchema.properties === "object") field.nested = extractSchemaFields(fieldSchema.properties, path);
814
1133
  fields.push(field);
815
1134
  if (field.nested) fields.push(...field.nested);
@@ -917,27 +1236,46 @@ const OPERATOR_INFO = {
917
1236
  * Query builder with text input and help popover.
918
1237
  * Generates query strings for parseQueryString syntax.
919
1238
  */
920
- const ControlQueryBuilder = ({ schema, value = "", onChange, placeholder = "Enter query or click help for assistance...",...textInputProps }) => {
1239
+ const ControlQueryBuilder = ({ schema, value = "", onChange, placeholder = "Enter query or click for assistance...", ...textInputProps }) => {
921
1240
  const [helpOpened, setHelpOpened] = useState(false);
922
1241
  const [textValue, setTextValue] = useState(value);
923
1242
  const inputRef = useRef(null);
924
1243
  const fields = schema ? extractSchemaFields(schema) : [];
1244
+ const [error, setError] = useState(null);
1245
+ const isValid = (value$1) => {
1246
+ try {
1247
+ parseQueryString(value$1.trim());
1248
+ } catch (e) {
1249
+ setError(e.message);
1250
+ return false;
1251
+ }
1252
+ setError(null);
1253
+ return true;
1254
+ };
925
1255
  const handleTextChange = (newValue) => {
926
1256
  setTextValue(newValue);
927
- onChange?.(newValue);
1257
+ if (isValid(newValue)) onChange?.(newValue);
928
1258
  };
929
1259
  const handleClear = () => {
930
1260
  setTextValue("");
931
1261
  onChange?.("");
1262
+ isValid("");
932
1263
  };
933
1264
  const handleInsert = (text) => {
934
1265
  const newValue = textValue ? `${textValue}${text} ` : `${text} `;
935
1266
  setTextValue(newValue);
936
- onChange?.(newValue);
1267
+ if (isValid(newValue)) onChange?.(newValue);
937
1268
  setTimeout(() => {
938
1269
  inputRef.current?.focus();
1270
+ const length = inputRef.current?.value.length || 0;
1271
+ inputRef.current?.setSelectionRange(length, length);
939
1272
  }, 0);
940
1273
  };
1274
+ useEvents({ "form:change": (event) => {
1275
+ if (event.id === inputRef.current?.form?.id) {
1276
+ if (event.path === textInputProps["data-path"]) setTextValue(event.value ?? "");
1277
+ }
1278
+ } }, []);
941
1279
  return /* @__PURE__ */ jsxs(Popover, {
942
1280
  width: 800,
943
1281
  position: "bottom-start",
@@ -946,10 +1284,8 @@ const ControlQueryBuilder = ({ schema, value = "", onChange, placeholder = "Ente
946
1284
  onChange: setHelpOpened,
947
1285
  closeOnClickOutside: true,
948
1286
  closeOnEscape: true,
949
- withArrow: true,
950
- arrowSize: 14,
951
1287
  transitionProps: {
952
- transition: "fade-down",
1288
+ transition: "fade-up",
953
1289
  duration: 200,
954
1290
  timingFunction: "ease"
955
1291
  },
@@ -959,7 +1295,7 @@ const ControlQueryBuilder = ({ schema, value = "", onChange, placeholder = "Ente
959
1295
  value: textValue,
960
1296
  onChange: (e) => handleTextChange(e.currentTarget.value),
961
1297
  onFocus: () => setHelpOpened(true),
962
- leftSection: /* @__PURE__ */ jsx(IconFilter, { size: 16 }),
1298
+ leftSection: error ? /* @__PURE__ */ jsx(IconInfoTriangle, { size: 16 }) : /* @__PURE__ */ jsx(IconFilter, { size: 16 }),
963
1299
  rightSection: textValue && /* @__PURE__ */ jsx(ActionIcon, {
964
1300
  size: "sm",
965
1301
  variant: "subtle",
@@ -968,10 +1304,16 @@ const ControlQueryBuilder = ({ schema, value = "", onChange, placeholder = "Ente
968
1304
  children: /* @__PURE__ */ jsx(IconX, { size: 14 })
969
1305
  }),
970
1306
  ...textInputProps
971
- }) }), /* @__PURE__ */ jsx(Popover.Dropdown, { children: /* @__PURE__ */ jsx(QueryHelp, {
972
- fields,
973
- onInsert: handleInsert
974
- }) })]
1307
+ }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
1308
+ bg: "transparent",
1309
+ p: "xs",
1310
+ bd: `1px solid ${ui.colors.border}`,
1311
+ style: { backdropFilter: "blur(20px)" },
1312
+ children: /* @__PURE__ */ jsx(QueryHelp, {
1313
+ fields,
1314
+ onInsert: handleInsert
1315
+ })
1316
+ })]
975
1317
  });
976
1318
  };
977
1319
  function QueryHelp({ fields, onInsert }) {
@@ -979,6 +1321,9 @@ function QueryHelp({ fields, onInsert }) {
979
1321
  gap: "md",
980
1322
  align: "flex-start",
981
1323
  wrap: "nowrap",
1324
+ bg: ui.colors.surface,
1325
+ p: "sm",
1326
+ bdrs: "sm",
982
1327
  children: [
983
1328
  /* @__PURE__ */ jsxs(Stack, {
984
1329
  gap: "md",
@@ -995,12 +1340,13 @@ function QueryHelp({ fields, onInsert }) {
995
1340
  children: Object.entries(OPERATOR_INFO).map(([key, info]) => /* @__PURE__ */ jsxs(Group, {
996
1341
  gap: "xs",
997
1342
  wrap: "nowrap",
998
- children: [/* @__PURE__ */ jsx(Code, {
999
- style: {
1000
- minWidth: 35,
1001
- textAlign: "center",
1002
- cursor: "pointer"
1003
- },
1343
+ children: [/* @__PURE__ */ jsx(ActionButton_default, {
1344
+ px: "xs",
1345
+ size: "xs",
1346
+ h: 24,
1347
+ variant: "default",
1348
+ justify: "center",
1349
+ miw: 48,
1004
1350
  onClick: () => onInsert(info.symbol),
1005
1351
  children: info.symbol
1006
1352
  }), /* @__PURE__ */ jsx(Text$1, {
@@ -1024,12 +1370,13 @@ function QueryHelp({ fields, onInsert }) {
1024
1370
  children: [/* @__PURE__ */ jsxs(Group, {
1025
1371
  gap: "xs",
1026
1372
  wrap: "nowrap",
1027
- children: [/* @__PURE__ */ jsx(Code, {
1028
- style: {
1029
- minWidth: 35,
1030
- textAlign: "center",
1031
- cursor: "pointer"
1032
- },
1373
+ children: [/* @__PURE__ */ jsx(ActionButton_default, {
1374
+ px: "xs",
1375
+ size: "xs",
1376
+ h: 24,
1377
+ variant: "default",
1378
+ justify: "center",
1379
+ miw: 48,
1033
1380
  onClick: () => onInsert("&"),
1034
1381
  children: "&"
1035
1382
  }), /* @__PURE__ */ jsx(Text$1, {
@@ -1040,12 +1387,13 @@ function QueryHelp({ fields, onInsert }) {
1040
1387
  }), /* @__PURE__ */ jsxs(Group, {
1041
1388
  gap: "xs",
1042
1389
  wrap: "nowrap",
1043
- children: [/* @__PURE__ */ jsx(Code, {
1044
- style: {
1045
- minWidth: 35,
1046
- textAlign: "center",
1047
- cursor: "pointer"
1048
- },
1390
+ children: [/* @__PURE__ */ jsx(ActionButton_default, {
1391
+ px: "xs",
1392
+ size: "xs",
1393
+ h: 24,
1394
+ variant: "default",
1395
+ justify: "center",
1396
+ miw: 48,
1049
1397
  onClick: () => onInsert("|"),
1050
1398
  children: "|"
1051
1399
  }), /* @__PURE__ */ jsx(Text$1, {
@@ -1059,33 +1407,39 @@ function QueryHelp({ fields, onInsert }) {
1059
1407
  ]
1060
1408
  }),
1061
1409
  fields.length > 0 && /* @__PURE__ */ jsx(Divider, { orientation: "vertical" }),
1062
- fields.length > 0 && /* @__PURE__ */ jsxs(Stack, {
1410
+ fields.length > 0 && /* @__PURE__ */ jsxs(Flex$1, {
1411
+ direction: "column",
1063
1412
  gap: "xs",
1064
1413
  style: { flex: 2 },
1065
1414
  children: [/* @__PURE__ */ jsx(Text$1, {
1066
1415
  size: "sm",
1067
1416
  fw: 600,
1068
1417
  children: "Fields"
1069
- }), /* @__PURE__ */ jsx(Stack, {
1418
+ }), /* @__PURE__ */ jsx(Flex$1, {
1419
+ direction: "column",
1070
1420
  gap: 4,
1071
1421
  style: {
1072
1422
  maxHeight: 300,
1073
1423
  overflowY: "auto"
1074
1424
  },
1075
- children: fields.map((field) => /* @__PURE__ */ jsxs(Group, {
1425
+ children: fields.map((field) => /* @__PURE__ */ jsxs(Flex$1, {
1076
1426
  gap: "xs",
1077
1427
  wrap: "nowrap",
1078
1428
  align: "flex-start",
1079
1429
  children: [
1080
- /* @__PURE__ */ jsx(Code, {
1081
- style: {
1082
- minWidth: 120,
1083
- cursor: "pointer"
1084
- },
1430
+ /* @__PURE__ */ jsx(ActionButton_default, {
1431
+ px: "xs",
1432
+ size: "xs",
1433
+ h: 24,
1434
+ variant: "default",
1435
+ justify: "end",
1436
+ miw: 120,
1085
1437
  onClick: () => onInsert(field.path),
1086
1438
  children: field.path
1087
1439
  }),
1088
- /* @__PURE__ */ jsxs(Stack, {
1440
+ /* @__PURE__ */ jsxs(Flex$1, {
1441
+ mt: 3,
1442
+ direction: "column",
1089
1443
  gap: 2,
1090
1444
  style: {
1091
1445
  flex: 1,
@@ -1097,15 +1451,12 @@ function QueryHelp({ fields, onInsert }) {
1097
1451
  lineClamp: 1,
1098
1452
  children: field.description || field.type
1099
1453
  }), field.enum && /* @__PURE__ */ jsx(Group, {
1100
- gap: 4,
1454
+ gap: 0,
1101
1455
  wrap: "wrap",
1102
- children: field.enum.map((enumValue) => /* @__PURE__ */ jsx(Code, {
1103
- style: {
1104
- cursor: "pointer",
1105
- fontStyle: "italic",
1106
- fontSize: "0.75rem"
1107
- },
1108
- c: "blue",
1456
+ children: field.enum.map((enumValue) => /* @__PURE__ */ jsx(ActionButton_default, {
1457
+ px: "xs",
1458
+ size: "xs",
1459
+ h: 24,
1109
1460
  onClick: () => onInsert(enumValue),
1110
1461
  children: enumValue
1111
1462
  }, enumValue))
@@ -1161,18 +1512,15 @@ const ControlSelect = (props) => {
1161
1512
  const segmentedControlProps = typeof props.segmented === "object" ? props.segmented : {};
1162
1513
  return /* @__PURE__ */ jsx(Input.Wrapper, {
1163
1514
  ...inputProps,
1164
- children: /* @__PURE__ */ jsx(Flex$1, {
1165
- mt: "calc(var(--mantine-spacing-xs) / 2)",
1166
- children: /* @__PURE__ */ jsx(SegmentedControl, {
1167
- disabled: inputProps.disabled,
1168
- defaultValue: String(props.input.props.defaultValue),
1169
- ...segmentedControlProps,
1170
- onChange: (value) => {
1171
- props.input.set(value);
1172
- },
1173
- data: data.slice(0, 10)
1174
- })
1175
- })
1515
+ children: /* @__PURE__ */ jsx(Flex$1, { children: /* @__PURE__ */ jsx(SegmentedControl, {
1516
+ disabled: inputProps.disabled,
1517
+ defaultValue: String(props.input.props.defaultValue),
1518
+ ...segmentedControlProps,
1519
+ onChange: (value) => {
1520
+ props.input.set(value);
1521
+ },
1522
+ data: data.slice(0, 10)
1523
+ }) })
1176
1524
  });
1177
1525
  }
1178
1526
  if (props.autocomplete) {
@@ -1260,15 +1608,14 @@ const Control = (_props) => {
1260
1608
  ..._props,
1261
1609
  ...schema.$control
1262
1610
  };
1263
- if (props.query) return /* @__PURE__ */ jsx(Input.Wrapper, {
1611
+ if (props.query) return /* @__PURE__ */ jsx(ControlQueryBuilder_default, {
1612
+ ...props.input.props,
1264
1613
  ...inputProps,
1265
- children: /* @__PURE__ */ jsx(ControlQueryBuilder_default, {
1266
- schema: props.query,
1267
- value: props.input.props.value,
1268
- onChange: (value) => {
1269
- props.input.set(value);
1270
- }
1271
- })
1614
+ schema: props.query,
1615
+ value: props.input.props.value,
1616
+ onChange: (value) => {
1617
+ props.input.set(value);
1618
+ }
1272
1619
  });
1273
1620
  if (props.custom) {
1274
1621
  const Custom = props.custom;
@@ -1482,16 +1829,6 @@ const TypeForm = (props) => {
1482
1829
  };
1483
1830
  var TypeForm_default = TypeForm;
1484
1831
 
1485
- //#endregion
1486
- //#region src/constants/ui.ts
1487
- const ui = { colors: {
1488
- transparent: "transparent",
1489
- background: "var(--alepha-background)",
1490
- surface: "var(--alepha-surface)",
1491
- elevated: "var(--alepha-elevated)",
1492
- border: "var(--alepha-border)"
1493
- } };
1494
-
1495
1832
  //#endregion
1496
1833
  //#region src/components/buttons/BurgerButton.tsx
1497
1834
  const BurgerButton = (props) => {
@@ -1848,11 +2185,11 @@ var AdminShell_default = AdminShell;
1848
2185
  //#region src/components/table/DataTable.tsx
1849
2186
  const DataTable = (props) => {
1850
2187
  const [items, setItems] = useState(typeof props.items === "function" ? { content: [] } : props.items);
1851
- const defaultSize = props.infinityScroll ? 50 : props.defaultSize || 10;
2188
+ const defaultSize = props.infinityScroll ? 100 : props.defaultSize || 10;
1852
2189
  const [page, setPage] = useState(1);
1853
2190
  const [size, setSize] = useState(String(defaultSize));
1854
- const [isLoadingMore, setIsLoadingMore] = useState(false);
1855
2191
  const [currentPage, setCurrentPage] = useState(0);
2192
+ const alepha = useInject(Alepha);
1856
2193
  const form = useForm({
1857
2194
  schema: t.object({
1858
2195
  ...props.filters ? props.filters.properties : {},
@@ -1862,14 +2199,13 @@ const DataTable = (props) => {
1862
2199
  }),
1863
2200
  handler: async (values, args) => {
1864
2201
  if (typeof props.items === "function") {
1865
- const response = await props.items(values);
2202
+ const response = await props.items(values, { items: items.content });
1866
2203
  if (props.infinityScroll && values.page > 0) setItems((prev) => ({
1867
2204
  ...response,
1868
2205
  content: [...prev.content, ...response.content]
1869
2206
  }));
1870
2207
  else setItems(response);
1871
2208
  setCurrentPage(values.page);
1872
- setIsLoadingMore(false);
1873
2209
  }
1874
2210
  },
1875
2211
  onReset: async () => {
@@ -1888,15 +2224,13 @@ const DataTable = (props) => {
1888
2224
  form.input.page.set(0);
1889
2225
  return;
1890
2226
  }
2227
+ props.onFilterChange?.(key, value, form);
1891
2228
  }
1892
- }, []);
1893
- useDebouncedCallback(() => form.submit(), { delay: 1e3 });
2229
+ }, [items]);
2230
+ useDebouncedCallback(() => form.submit(), { delay: 800 });
1894
2231
  const dt = useInject(DateTimeProvider);
1895
2232
  useEffect(() => {
1896
- if (props.submitOnInit) {
1897
- console.log("submitting");
1898
- form.submit();
1899
- }
2233
+ if (props.submitOnInit) form.submit();
1900
2234
  if (props.submitEvery) {
1901
2235
  const it = dt.createInterval(() => {
1902
2236
  form.submit();
@@ -1910,39 +2244,46 @@ const DataTable = (props) => {
1910
2244
  useEffect(() => {
1911
2245
  if (!props.infinityScroll || typeof props.items !== "function") return;
1912
2246
  const handleScroll = () => {
1913
- if (isLoadingMore) return;
2247
+ if (form.submitting) return;
1914
2248
  const scrollTop = window.scrollY;
1915
2249
  const windowHeight = window.innerHeight;
1916
2250
  const docHeight = document.documentElement.scrollHeight;
1917
- if (scrollTop + windowHeight >= docHeight - 200) {
2251
+ if (scrollTop + windowHeight >= docHeight - 300) {
1918
2252
  const totalPages = items.page?.totalPages ?? 1;
1919
- if (currentPage + 1 < totalPages) {
1920
- setIsLoadingMore(true);
1921
- form.input.page.set(currentPage + 1);
1922
- }
2253
+ if (currentPage + 1 < totalPages) form.input.page.set(currentPage + 1);
1923
2254
  }
1924
2255
  };
1925
2256
  window.addEventListener("scroll", handleScroll);
1926
2257
  return () => window.removeEventListener("scroll", handleScroll);
1927
2258
  }, [
1928
2259
  props.infinityScroll,
1929
- isLoadingMore,
2260
+ form.submitting,
1930
2261
  items.page?.totalPages,
1931
2262
  currentPage,
1932
2263
  form
1933
2264
  ]);
1934
- const head = Object.entries(props.columns).map(([key, col]) => /* @__PURE__ */ jsx(Table.Th, { children: /* @__PURE__ */ jsx(ActionButton_default, {
1935
- justify: "space-between",
1936
- radius: 0,
1937
- fullWidth: true,
1938
- size: "xs",
1939
- children: col.label
1940
- }) }, key));
2265
+ const head = Object.entries(props.columns).map(([key, col]) => /* @__PURE__ */ jsx(Table.Th, {
2266
+ style: { ...col.fit ? {
2267
+ width: "1%",
2268
+ whiteSpace: "nowrap"
2269
+ } : {} },
2270
+ children: /* @__PURE__ */ jsx(ActionButton_default, {
2271
+ justify: "space-between",
2272
+ radius: 0,
2273
+ fullWidth: true,
2274
+ size: "xs",
2275
+ children: col.label
2276
+ })
2277
+ }, key));
1941
2278
  const rows = items.content.map((item, index) => {
1942
2279
  const trProps = props.tableTrProps ? props.tableTrProps(item) : {};
1943
2280
  return /* @__PURE__ */ jsx(Table.Tr, {
1944
2281
  ...trProps,
1945
- children: Object.entries(props.columns).map(([key, col]) => /* @__PURE__ */ jsx(Table.Td, { children: col.value(item, index) }, key))
2282
+ children: Object.entries(props.columns).map(([key, col]) => /* @__PURE__ */ jsx(Table.Td, { children: col.value(item, {
2283
+ index,
2284
+ form,
2285
+ alepha
2286
+ }) }, key))
1946
2287
  }, JSON.stringify(item));
1947
2288
  });
1948
2289
  const schema = t.omit(form.options.schema, [
@@ -1955,19 +2296,23 @@ const DataTable = (props) => {
1955
2296
  gap: "sm",
1956
2297
  flex: 1,
1957
2298
  children: [
1958
- /* @__PURE__ */ jsx(Paper, {
1959
- withBorder: true,
1960
- p: "sm",
1961
- children: props.filters ? /* @__PURE__ */ jsx(TypeForm_default, {
1962
- form,
1963
- schema
1964
- }) : null
1965
- }),
1966
- /* @__PURE__ */ jsxs(Table, {
1967
- striped: true,
1968
- stripedColor: "",
1969
- ...props.tableProps,
1970
- children: [/* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsx(Table.Tr, { children: head }) }), /* @__PURE__ */ jsx(Table.Tbody, { children: rows })]
2299
+ props.filters ? /* @__PURE__ */ jsx(TypeForm_default, {
2300
+ ...props.typeFormProps,
2301
+ form,
2302
+ schema
2303
+ }) : null,
2304
+ /* @__PURE__ */ jsx(Flex$1, {
2305
+ flex: 1,
2306
+ className: "overflow-auto",
2307
+ children: /* @__PURE__ */ jsxs(Table, {
2308
+ striped: true,
2309
+ withRowBorders: true,
2310
+ withColumnBorders: true,
2311
+ withTableBorder: true,
2312
+ stripedColor: "",
2313
+ ...props.tableProps,
2314
+ children: [/* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsx(Table.Tr, { children: head }) }), /* @__PURE__ */ jsx(Table.Tbody, { children: rows })]
2315
+ })
1971
2316
  }),
1972
2317
  !props.infinityScroll && /* @__PURE__ */ jsxs(Flex$1, {
1973
2318
  justify: "space-between",
@@ -2052,5 +2397,5 @@ const AlephaUI = $module({
2052
2397
  });
2053
2398
 
2054
2399
  //#endregion
2055
- export { ActionButton_default as ActionButton, AdminShell_default as AdminShell, AlephaMantineProvider_default as AlephaMantineProvider, AlephaUI, AlertDialog_default as AlertDialog, AppBar_default as AppBar, ConfirmDialog_default as ConfirmDialog, Control_default as Control, ControlDate_default as ControlDate, ControlQueryBuilder_default as ControlQueryBuilder, ControlSelect_default as ControlSelect, DarkModeButton_default as DarkModeButton, DataTable_default as DataTable, DialogService, Flex, ICON_SIZES, OPERATOR_INFO, Omnibar_default as Omnibar, OmnibarButton_default as OmnibarButton, PromptDialog_default as PromptDialog, RootRouter, Sidebar, Text, ToastService, TypeForm_default as TypeForm, capitalize, extractSchemaFields, getDefaultIcon, getOperatorsForField, prettyName, ui, useDialog, useToast };
2400
+ export { ActionButton_default as ActionButton, AdminShell_default as AdminShell, AlephaMantineProvider_default as AlephaMantineProvider, AlephaUI, AlertDialog_default as AlertDialog, AppBar_default as AppBar, ConfirmDialog_default as ConfirmDialog, Control_default as Control, ControlDate_default as ControlDate, ControlQueryBuilder_default as ControlQueryBuilder, ControlSelect_default as ControlSelect, DarkModeButton_default as DarkModeButton, DataTable_default as DataTable, DialogService, Flex, ICON_SIZES, JsonViewer_default as JsonViewer, OPERATOR_INFO, Omnibar_default as Omnibar, OmnibarButton_default as OmnibarButton, PromptDialog_default as PromptDialog, RootRouter, Sidebar, Text, ToastService, TypeForm_default as TypeForm, capitalize, extractSchemaFields, getDefaultIcon, getOperatorsForField, prettyName, ui, useDialog, useToast };
2056
2401
  //# sourceMappingURL=index.js.map