@reopt-ai/opt-ui 1.6.0 → 1.7.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/COMPONENT_CATALOG.md +95 -12
- package/dist/app.css +24 -0
- package/dist/core/index.cjs +3 -3
- package/dist/core/index.d.cts +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +2 -2
- package/dist/docs/02-components/03-shells.md +104 -11
- package/dist/docs/02-components/index.md +3 -3
- package/dist/docs/05-migration/01-breaking-changes.md +18 -1
- package/dist/field-sidebar-BTZCBviA.d.cts +1031 -0
- package/dist/field-sidebar-BTZCBviA.d.cts.map +1 -0
- package/dist/field-sidebar-CB8vjvUM.d.ts +1031 -0
- package/dist/field-sidebar-CB8vjvUM.d.ts.map +1 -0
- package/dist/{workflow-canvas-BGBAcjf-.js → field-sidebar-Cs-J-5VE.js} +1882 -52
- package/dist/field-sidebar-Cs-J-5VE.js.map +1 -0
- package/dist/{workflow-canvas-3Jeevkgy.cjs → field-sidebar-CzIQX70-.cjs} +2010 -48
- package/dist/id-registry.cjs +41 -1
- package/dist/id-registry.d.cts +1 -1
- package/dist/id-registry.d.cts.map +1 -1
- package/dist/id-registry.d.ts +1 -1
- package/dist/id-registry.d.ts.map +1 -1
- package/dist/id-registry.js +41 -1
- package/dist/id-registry.js.map +1 -1
- package/dist/id-registry.json +85 -0
- package/dist/index.cjs +142 -56
- package/dist/index.d.cts +149 -80
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +149 -80
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +73 -11
- package/dist/index.js.map +1 -1
- package/dist/meta.cjs +292 -0
- package/dist/meta.d.cts.map +1 -1
- package/dist/meta.d.ts.map +1 -1
- package/dist/meta.js +292 -0
- package/dist/meta.js.map +1 -1
- package/dist/{pagination-By7Ozv3U.js → pagination-DWbvACuN.js} +93 -31
- package/dist/pagination-DWbvACuN.js.map +1 -0
- package/dist/{pagination-Uv3CnGJz.cjs → pagination-DjfxBcjX.cjs} +98 -36
- package/dist/query.cjs +386 -0
- package/dist/query.d.cts +141 -0
- package/dist/query.d.cts.map +1 -0
- package/dist/query.d.ts +141 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +371 -0
- package/dist/query.js.map +1 -0
- package/dist/{shader-surface-BWhO2xkk.js → shader-surface-BUPZ0P-n.js} +22 -83
- package/dist/shader-surface-BUPZ0P-n.js.map +1 -0
- package/dist/{shader-surface-DIVWtpFl.d.ts → shader-surface-BfTP9c1Q.d.ts} +139 -139
- package/dist/shader-surface-BfTP9c1Q.d.ts.map +1 -0
- package/dist/{shader-surface-BK1GMt5_.d.cts → shader-surface-DRrcLrWf.d.cts} +139 -139
- package/dist/shader-surface-DRrcLrWf.d.cts.map +1 -0
- package/dist/{shader-surface-DxLLfrE6.cjs → shader-surface-Fav5K9UC.cjs} +20 -87
- package/dist/shells/index.cjs +31 -24
- package/dist/shells/index.d.cts +2 -2
- package/dist/shells/index.d.ts +2 -2
- package/dist/shells/index.js +3 -2
- package/dist/theme/presets/default.css +2 -2
- package/dist/theme/presets/minimal.css +2 -2
- package/dist/theme/presets/mono-dark.css +2 -2
- package/dist/theme/presets/natural.css +1 -1
- package/dist/theme/presets/pro.css +2 -2
- package/package.json +17 -6
- package/dist/pagination-By7Ozv3U.js.map +0 -1
- package/dist/shader-surface-BK1GMt5_.d.cts.map +0 -1
- package/dist/shader-surface-BWhO2xkk.js.map +0 -1
- package/dist/shader-surface-DIVWtpFl.d.ts.map +0 -1
- package/dist/workflow-canvas-BGBAcjf-.js.map +0 -1
- package/dist/workflow-canvas-Bar_O2SQ.d.ts +0 -494
- package/dist/workflow-canvas-Bar_O2SQ.d.ts.map +0 -1
- package/dist/workflow-canvas-DghDRtHn.d.cts +0 -494
- package/dist/workflow-canvas-DghDRtHn.d.cts.map +0 -1
|
@@ -16,7 +16,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
16
|
}
|
|
17
17
|
return to;
|
|
18
18
|
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
20
20
|
value: mod,
|
|
21
21
|
enumerable: true
|
|
22
22
|
}) : target, mod));
|
|
@@ -45,7 +45,7 @@ function Kbd({ children, hint = false, className }) {
|
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
47
|
//#endregion
|
|
48
|
-
//#region \0@oxc-project+runtime@0.
|
|
48
|
+
//#region \0@oxc-project+runtime@0.146.0/helpers/esm/objectWithoutPropertiesLoose.js
|
|
49
49
|
function _objectWithoutPropertiesLoose(r, e) {
|
|
50
50
|
if (null == r) return {};
|
|
51
51
|
var t = {};
|
|
@@ -56,7 +56,7 @@ function _objectWithoutPropertiesLoose(r, e) {
|
|
|
56
56
|
return t;
|
|
57
57
|
}
|
|
58
58
|
//#endregion
|
|
59
|
-
//#region \0@oxc-project+runtime@0.
|
|
59
|
+
//#region \0@oxc-project+runtime@0.146.0/helpers/esm/objectWithoutProperties.js
|
|
60
60
|
function _objectWithoutProperties(e, t) {
|
|
61
61
|
if (null == e) return {};
|
|
62
62
|
var o, r, i = _objectWithoutPropertiesLoose(e, t);
|
|
@@ -67,7 +67,7 @@ function _objectWithoutProperties(e, t) {
|
|
|
67
67
|
return i;
|
|
68
68
|
}
|
|
69
69
|
//#endregion
|
|
70
|
-
//#region \0@oxc-project+runtime@0.
|
|
70
|
+
//#region \0@oxc-project+runtime@0.146.0/helpers/esm/typeof.js
|
|
71
71
|
function _typeof(o) {
|
|
72
72
|
"@babel/helpers - typeof";
|
|
73
73
|
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
|
|
@@ -77,7 +77,7 @@ function _typeof(o) {
|
|
|
77
77
|
}, _typeof(o);
|
|
78
78
|
}
|
|
79
79
|
//#endregion
|
|
80
|
-
//#region \0@oxc-project+runtime@0.
|
|
80
|
+
//#region \0@oxc-project+runtime@0.146.0/helpers/esm/toPrimitive.js
|
|
81
81
|
function toPrimitive(t, r) {
|
|
82
82
|
if ("object" != _typeof(t) || !t) return t;
|
|
83
83
|
var e = t[Symbol.toPrimitive];
|
|
@@ -89,13 +89,13 @@ function toPrimitive(t, r) {
|
|
|
89
89
|
return ("string" === r ? String : Number)(t);
|
|
90
90
|
}
|
|
91
91
|
//#endregion
|
|
92
|
-
//#region \0@oxc-project+runtime@0.
|
|
92
|
+
//#region \0@oxc-project+runtime@0.146.0/helpers/esm/toPropertyKey.js
|
|
93
93
|
function toPropertyKey(t) {
|
|
94
94
|
var i = toPrimitive(t, "string");
|
|
95
95
|
return "symbol" == _typeof(i) ? i : i + "";
|
|
96
96
|
}
|
|
97
97
|
//#endregion
|
|
98
|
-
//#region \0@oxc-project+runtime@0.
|
|
98
|
+
//#region \0@oxc-project+runtime@0.146.0/helpers/esm/defineProperty.js
|
|
99
99
|
function _defineProperty(e, r, t) {
|
|
100
100
|
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
101
101
|
value: t,
|
|
@@ -105,7 +105,7 @@ function _defineProperty(e, r, t) {
|
|
|
105
105
|
}) : e[r] = t, e;
|
|
106
106
|
}
|
|
107
107
|
//#endregion
|
|
108
|
-
//#region \0@oxc-project+runtime@0.
|
|
108
|
+
//#region \0@oxc-project+runtime@0.146.0/helpers/esm/objectSpread2.js
|
|
109
109
|
function ownKeys(e, r) {
|
|
110
110
|
var t = Object.keys(e);
|
|
111
111
|
if (Object.getOwnPropertySymbols) {
|
|
@@ -286,7 +286,7 @@ function MiniSparkline({ data, color }) {
|
|
|
286
286
|
const min = Math.min(...data);
|
|
287
287
|
const range = Math.max(...data) - min || 1;
|
|
288
288
|
const points = data.map((v, i) => {
|
|
289
|
-
return `${padding + i / (data.length - 1) *
|
|
289
|
+
return `${padding + i / (data.length - 1) * 76},${padding + (1 - (v - min) / range) * 28}`;
|
|
290
290
|
}).join(" ");
|
|
291
291
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
292
292
|
width,
|
|
@@ -329,7 +329,7 @@ const koBreadcrumbLabels = {
|
|
|
329
329
|
navAriaLabel: "{label}(으)로 이동" };
|
|
330
330
|
//#endregion
|
|
331
331
|
//#region src/core/button.tsx
|
|
332
|
-
const _excluded$
|
|
332
|
+
const _excluded$15 = [
|
|
333
333
|
"variant",
|
|
334
334
|
"size",
|
|
335
335
|
"loading",
|
|
@@ -353,7 +353,7 @@ const sizeStyles$3 = {
|
|
|
353
353
|
};
|
|
354
354
|
/** Renders the button component. */
|
|
355
355
|
function Button(_ref) {
|
|
356
|
-
let { variant = "primary", size = "md", loading = false, leftIcon, rightIcon, className, disabled, children, "aria-busy": ariaBusy } = _ref, props = _objectWithoutProperties(_ref, _excluded$
|
|
356
|
+
let { variant = "primary", size = "md", loading = false, leftIcon, rightIcon, className, disabled, children, "aria-busy": ariaBusy } = _ref, props = _objectWithoutProperties(_ref, _excluded$15);
|
|
357
357
|
const isDisabled = disabled || loading;
|
|
358
358
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", _objectSpread2(_objectSpread2({
|
|
359
359
|
type: "button",
|
|
@@ -436,7 +436,7 @@ function EmptyState({ icon, title, description, actions, className, iconSize = "
|
|
|
436
436
|
}
|
|
437
437
|
//#endregion
|
|
438
438
|
//#region src/core/badge.tsx
|
|
439
|
-
const _excluded$
|
|
439
|
+
const _excluded$14 = [
|
|
440
440
|
"variant",
|
|
441
441
|
"size",
|
|
442
442
|
"dot",
|
|
@@ -472,7 +472,7 @@ const sizeStyles$2 = {
|
|
|
472
472
|
};
|
|
473
473
|
/** Renders the badge component. */
|
|
474
474
|
function Badge(_ref) {
|
|
475
|
-
let { variant = "default", size = "md", dot = false, progress, progressSize = 16, className, children } = _ref, props = _objectWithoutProperties(_ref, _excluded$
|
|
475
|
+
let { variant = "default", size = "md", dot = false, progress, progressSize = 16, className, children } = _ref, props = _objectWithoutProperties(_ref, _excluded$14);
|
|
476
476
|
const hasProgress = progress != null;
|
|
477
477
|
const clampedProgress = hasProgress ? Math.min(100, Math.max(0, progress)) : 0;
|
|
478
478
|
const radius = (progressSize - 3) / 2;
|
|
@@ -518,7 +518,7 @@ function Badge(_ref) {
|
|
|
518
518
|
}
|
|
519
519
|
//#endregion
|
|
520
520
|
//#region src/core/spinner.tsx
|
|
521
|
-
const _excluded$
|
|
521
|
+
const _excluded$13 = [
|
|
522
522
|
"size",
|
|
523
523
|
"className",
|
|
524
524
|
"role",
|
|
@@ -532,7 +532,7 @@ const sizeStyles$1 = {
|
|
|
532
532
|
};
|
|
533
533
|
/** Renders the spinner component. */
|
|
534
534
|
function Spinner(_ref) {
|
|
535
|
-
let { size = "md", className, role, "aria-hidden": ariaHidden, "aria-label": ariaLabel } = _ref, props = _objectWithoutProperties(_ref, _excluded$
|
|
535
|
+
let { size = "md", className, role, "aria-hidden": ariaHidden, "aria-label": ariaLabel } = _ref, props = _objectWithoutProperties(_ref, _excluded$13);
|
|
536
536
|
const isDecorative = ariaHidden === true || ariaHidden === "true";
|
|
537
537
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", _objectSpread2(_objectSpread2({
|
|
538
538
|
className: cn("animate-spin text-current", sizeStyles$1[size], className),
|
|
@@ -560,7 +560,7 @@ function Spinner(_ref) {
|
|
|
560
560
|
}
|
|
561
561
|
//#endregion
|
|
562
562
|
//#region src/core/alert.tsx
|
|
563
|
-
const _excluded$
|
|
563
|
+
const _excluded$12 = [
|
|
564
564
|
"variant",
|
|
565
565
|
"title",
|
|
566
566
|
"icon",
|
|
@@ -629,7 +629,7 @@ const defaultIcons = {
|
|
|
629
629
|
};
|
|
630
630
|
/** Renders the alert component. */
|
|
631
631
|
function Alert(_ref) {
|
|
632
|
-
let { variant = "info", title, icon, dismissible = false, onDismiss, className, children } = _ref, props = _objectWithoutProperties(_ref, _excluded$
|
|
632
|
+
let { variant = "info", title, icon, dismissible = false, onDismiss, className, children } = _ref, props = _objectWithoutProperties(_ref, _excluded$12);
|
|
633
633
|
const displayIcon = icon !== null && icon !== void 0 ? icon : defaultIcons[variant];
|
|
634
634
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", _objectSpread2(_objectSpread2({
|
|
635
635
|
role: "alert",
|
|
@@ -684,6 +684,68 @@ function useInputId(id, label, prefix) {
|
|
|
684
684
|
return id !== null && id !== void 0 ? id : label ? `${prefix}-${label.replace(/\s+/g, "-").toLowerCase()}` : void 0;
|
|
685
685
|
}
|
|
686
686
|
//#endregion
|
|
687
|
+
//#region src/core/input.tsx
|
|
688
|
+
const _excluded$11 = [
|
|
689
|
+
"label",
|
|
690
|
+
"error",
|
|
691
|
+
"hint",
|
|
692
|
+
"leftIcon",
|
|
693
|
+
"rightIcon",
|
|
694
|
+
"fullWidth",
|
|
695
|
+
"size",
|
|
696
|
+
"required",
|
|
697
|
+
"className",
|
|
698
|
+
"id"
|
|
699
|
+
];
|
|
700
|
+
const inputSizeStyles = OPT_INPUT_SIZE;
|
|
701
|
+
const Input = (0, react.forwardRef)((_ref, ref) => {
|
|
702
|
+
var _useInputId;
|
|
703
|
+
let { label, error, hint, leftIcon, rightIcon, fullWidth = false, size = "md", required, className, id } = _ref, props = _objectWithoutProperties(_ref, _excluded$11);
|
|
704
|
+
const fallbackId = (0, react.useId)().replace(/:/g, "");
|
|
705
|
+
const inputId = (_useInputId = useInputId(id, label, "input")) !== null && _useInputId !== void 0 ? _useInputId : `input-${fallbackId}`;
|
|
706
|
+
const hasError = Boolean(error);
|
|
707
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
708
|
+
className: cn("flex flex-col gap-1.5", fullWidth && "w-full"),
|
|
709
|
+
"data-opt-id": "7BY1Q",
|
|
710
|
+
"data-opt-slug": "input.Input",
|
|
711
|
+
children: [
|
|
712
|
+
label && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
713
|
+
htmlFor: inputId,
|
|
714
|
+
className: "text-text-primary text-sm font-medium",
|
|
715
|
+
children: [label, required && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RequiredMark, {})]
|
|
716
|
+
}),
|
|
717
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
718
|
+
className: "relative",
|
|
719
|
+
children: [
|
|
720
|
+
leftIcon && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
721
|
+
className: "text-text-tertiary pointer-events-none absolute top-1/2 left-3 -translate-y-1/2",
|
|
722
|
+
children: leftIcon
|
|
723
|
+
}),
|
|
724
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", _objectSpread2({
|
|
725
|
+
ref,
|
|
726
|
+
id: inputId,
|
|
727
|
+
className: cn(OPT_INPUT, inputSizeStyles[size], leftIcon && (size === "sm" ? "pl-8" : "pl-10"), rightIcon && (size === "sm" ? "pr-8" : "pr-10"), hasError && "border-danger focus-visible:outline-danger", !fullWidth && "w-auto", className),
|
|
728
|
+
"aria-invalid": hasError,
|
|
729
|
+
"aria-required": required,
|
|
730
|
+
"aria-describedby": getDescribedBy(inputId, error, hint),
|
|
731
|
+
required
|
|
732
|
+
}, props)),
|
|
733
|
+
rightIcon && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
734
|
+
className: "text-text-tertiary pointer-events-none absolute top-1/2 right-3 -translate-y-1/2",
|
|
735
|
+
children: rightIcon
|
|
736
|
+
})
|
|
737
|
+
]
|
|
738
|
+
}),
|
|
739
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldMessages, {
|
|
740
|
+
id: inputId,
|
|
741
|
+
error,
|
|
742
|
+
hint
|
|
743
|
+
})
|
|
744
|
+
]
|
|
745
|
+
});
|
|
746
|
+
});
|
|
747
|
+
Input.displayName = "Input";
|
|
748
|
+
//#endregion
|
|
687
749
|
//#region src/core/star-rating.tsx
|
|
688
750
|
function interpolate(template, values) {
|
|
689
751
|
return template.replace(/\{(\w+)\}/g, (_, key) => key in values ? String(values[key]) : `{${key}}`);
|
|
@@ -1523,13 +1585,10 @@ function NumberInput({ value: controlledValue, defaultValue, onChange, nullable,
|
|
|
1523
1585
|
setTo(min);
|
|
1524
1586
|
}
|
|
1525
1587
|
break;
|
|
1526
|
-
case "End":
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
}
|
|
1531
|
-
break;
|
|
1532
|
-
default: break;
|
|
1588
|
+
case "End": if (max !== void 0) {
|
|
1589
|
+
e.preventDefault();
|
|
1590
|
+
setTo(max);
|
|
1591
|
+
}
|
|
1533
1592
|
}
|
|
1534
1593
|
}, [
|
|
1535
1594
|
interactionDisabled,
|
|
@@ -3166,12 +3225,13 @@ function FormSelect({ name, children, className, placeholder, minWidth = 140, "a
|
|
|
3166
3225
|
const error = form === null || form === void 0 ? void 0 : form.getError(name);
|
|
3167
3226
|
const touched = form === null || form === void 0 ? void 0 : form.getFieldTouched(name);
|
|
3168
3227
|
const hasError = Boolean(error && touched);
|
|
3228
|
+
const handleSetValue = (0, react.useCallback)((v) => {
|
|
3229
|
+
var _v$;
|
|
3230
|
+
return form.setValue(name, Array.isArray(v) ? (_v$ = v[0]) !== null && _v$ !== void 0 ? _v$ : "" : v);
|
|
3231
|
+
}, [form, name]);
|
|
3169
3232
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(SelectRoot, {
|
|
3170
3233
|
value,
|
|
3171
|
-
onValueChange:
|
|
3172
|
-
var _v$;
|
|
3173
|
-
return form.setValue(name, Array.isArray(v) ? (_v$ = v[0]) !== null && _v$ !== void 0 ? _v$ : "" : v);
|
|
3174
|
-
}, [form, name]),
|
|
3234
|
+
onValueChange: handleSetValue,
|
|
3175
3235
|
"data-opt-id": "A2XF7",
|
|
3176
3236
|
"data-opt-slug": "form.FormSelect",
|
|
3177
3237
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectTrigger, {
|
|
@@ -3377,8 +3437,9 @@ function FormSlider(_ref25) {
|
|
|
3377
3437
|
var _ref26;
|
|
3378
3438
|
let { name } = _ref25, props = _objectWithoutProperties(_ref25, _excluded22);
|
|
3379
3439
|
const form = useRequiredFormContext("FormSlider");
|
|
3440
|
+
const value = (_ref26 = (0, _reopt_ai_opt_ui_primitives.useFieldValue)(form, name)) !== null && _ref26 !== void 0 ? _ref26 : 0;
|
|
3380
3441
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Slider, _objectSpread2(_objectSpread2({
|
|
3381
|
-
value
|
|
3442
|
+
value,
|
|
3382
3443
|
onChange: (v) => form.setValue(name, v)
|
|
3383
3444
|
}, props), {}, {
|
|
3384
3445
|
"data-opt-id": "3XQ3A",
|
|
@@ -3390,8 +3451,9 @@ function FormStarRating(_ref27) {
|
|
|
3390
3451
|
var _ref28;
|
|
3391
3452
|
let { name } = _ref27, props = _objectWithoutProperties(_ref27, _excluded23);
|
|
3392
3453
|
const form = useRequiredFormContext("FormStarRating");
|
|
3454
|
+
const value = (_ref28 = (0, _reopt_ai_opt_ui_primitives.useFieldValue)(form, name)) !== null && _ref28 !== void 0 ? _ref28 : 0;
|
|
3393
3455
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StarRating, _objectSpread2(_objectSpread2({
|
|
3394
|
-
value
|
|
3456
|
+
value,
|
|
3395
3457
|
onChange: (v) => form.setValue(name, v)
|
|
3396
3458
|
}, props), {}, {
|
|
3397
3459
|
"data-opt-id": "EKNJJ",
|
|
@@ -4171,6 +4233,12 @@ Object.defineProperty(exports, "IconPicker", {
|
|
|
4171
4233
|
return IconPicker;
|
|
4172
4234
|
}
|
|
4173
4235
|
});
|
|
4236
|
+
Object.defineProperty(exports, "Input", {
|
|
4237
|
+
enumerable: true,
|
|
4238
|
+
get: function() {
|
|
4239
|
+
return Input;
|
|
4240
|
+
}
|
|
4241
|
+
});
|
|
4174
4242
|
Object.defineProperty(exports, "Kbd", {
|
|
4175
4243
|
enumerable: true,
|
|
4176
4244
|
get: function() {
|
|
@@ -4369,12 +4437,6 @@ Object.defineProperty(exports, "OPT_INPUT_ERROR", {
|
|
|
4369
4437
|
return OPT_INPUT_ERROR;
|
|
4370
4438
|
}
|
|
4371
4439
|
});
|
|
4372
|
-
Object.defineProperty(exports, "OPT_INPUT_SIZE", {
|
|
4373
|
-
enumerable: true,
|
|
4374
|
-
get: function() {
|
|
4375
|
-
return OPT_INPUT_SIZE;
|
|
4376
|
-
}
|
|
4377
|
-
});
|
|
4378
4440
|
Object.defineProperty(exports, "OPT_ITEM_BASE", {
|
|
4379
4441
|
enumerable: true,
|
|
4380
4442
|
get: function() {
|
package/dist/query.cjs
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/lib/query/query-ast.ts
|
|
3
|
+
const EMPTY_QUERY = { clauses: [] };
|
|
4
|
+
/** Whether a query constrains anything at all. */
|
|
5
|
+
function isEmptyQuery(query) {
|
|
6
|
+
return !query || query.clauses.length === 0;
|
|
7
|
+
}
|
|
8
|
+
function sameClause(a, b) {
|
|
9
|
+
if (a.type !== b.type) return false;
|
|
10
|
+
if (a.type === "term" && b.type === "term") return a.value === b.value && a.negated === b.negated;
|
|
11
|
+
const fieldA = a;
|
|
12
|
+
const fieldB = b;
|
|
13
|
+
return fieldA.field === fieldB.field && fieldA.operator === fieldB.operator && fieldA.negated === fieldB.negated && fieldA.values.length === fieldB.values.length && fieldA.values.every((value, index) => value === fieldB.values[index]);
|
|
14
|
+
}
|
|
15
|
+
/** Add a clause unless an identical one is already there. */
|
|
16
|
+
function addClause(query, clause) {
|
|
17
|
+
if (query.clauses.some((existing) => sameClause(existing, clause))) return query;
|
|
18
|
+
return { clauses: [...query.clauses, clause] };
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Constrain a field to a value — what a cell's "filter for this" action does.
|
|
22
|
+
*
|
|
23
|
+
* Applying the opposite of a constraint already present replaces it rather than
|
|
24
|
+
* adding it: `status:200` then "filter out 200" should read as one changed
|
|
25
|
+
* mind, not as a query that can never match.
|
|
26
|
+
*/
|
|
27
|
+
function withFieldValue(query, field, value, options = {}) {
|
|
28
|
+
var _options$negated, _options$operator;
|
|
29
|
+
const negated = (_options$negated = options.negated) !== null && _options$negated !== void 0 ? _options$negated : false;
|
|
30
|
+
const operator = (_options$operator = options.operator) !== null && _options$operator !== void 0 ? _options$operator : "eq";
|
|
31
|
+
return { clauses: [...query.clauses.filter((clause) => !(clause.type === "field" && clause.field === field && clause.operator === operator && clause.values.length === 1 && clause.values[0] === value)), {
|
|
32
|
+
type: "field",
|
|
33
|
+
field,
|
|
34
|
+
operator,
|
|
35
|
+
values: [value],
|
|
36
|
+
negated
|
|
37
|
+
}] };
|
|
38
|
+
}
|
|
39
|
+
/** Drop every clause naming `field`. */
|
|
40
|
+
function withoutField(query, field) {
|
|
41
|
+
return { clauses: query.clauses.filter((clause) => clause.type !== "field" || clause.field !== field) };
|
|
42
|
+
}
|
|
43
|
+
/** Drop the clause at `index`, for a removable chip. */
|
|
44
|
+
function removeClause(query, index) {
|
|
45
|
+
return { clauses: query.clauses.filter((_, at) => at !== index) };
|
|
46
|
+
}
|
|
47
|
+
/** Every field the query names, in the order they first appear. */
|
|
48
|
+
function queryFields(query) {
|
|
49
|
+
const seen = [];
|
|
50
|
+
for (const clause of query.clauses) if (clause.type === "field" && !seen.includes(clause.field)) seen.push(clause.field);
|
|
51
|
+
return seen;
|
|
52
|
+
}
|
|
53
|
+
/** The values a field is constrained to, if any — for showing a filter as active. */
|
|
54
|
+
function fieldValues(query, field) {
|
|
55
|
+
return query.clauses.flatMap((clause) => clause.type === "field" && clause.field === field && !clause.negated ? clause.values : []);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Fold a cell action into the query.
|
|
59
|
+
*
|
|
60
|
+
* The pair of buttons on a log cell is the fastest path from "I noticed this
|
|
61
|
+
* value" to a filtered view, and the reason it works is that the result is a
|
|
62
|
+
* query the reader can then see, edit and share — not a hidden filter stack
|
|
63
|
+
* with its own rules.
|
|
64
|
+
*/
|
|
65
|
+
function applyCellAction(query, action) {
|
|
66
|
+
return withFieldValue(query, action.field, action.value, { negated: action.intent === "exclude" });
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/lib/query/query-parse.ts
|
|
70
|
+
const FIELD_NAME = /^[A-Za-z_][A-Za-z0-9_.-]*$/;
|
|
71
|
+
/**
|
|
72
|
+
* Split on whitespace, but keep quoted runs and parenthesised groups whole.
|
|
73
|
+
*
|
|
74
|
+
* An unterminated quote or group swallows the rest of the line rather than
|
|
75
|
+
* erroring: the reader is mid-word, and the alternative is the query flickering
|
|
76
|
+
* between two different meanings as they type the closing character.
|
|
77
|
+
*/
|
|
78
|
+
function tokenize(input) {
|
|
79
|
+
const tokens = [];
|
|
80
|
+
let index = 0;
|
|
81
|
+
while (index < input.length) {
|
|
82
|
+
while (index < input.length && /\s/.test(input[index])) index += 1;
|
|
83
|
+
if (index >= input.length) break;
|
|
84
|
+
const start = index;
|
|
85
|
+
let text = "";
|
|
86
|
+
let quoted = false;
|
|
87
|
+
let atTokenStart = true;
|
|
88
|
+
let depth = 0;
|
|
89
|
+
while (index < input.length) {
|
|
90
|
+
const char = input[index];
|
|
91
|
+
if (char === "\"") {
|
|
92
|
+
if (atTokenStart) quoted = true;
|
|
93
|
+
atTokenStart = false;
|
|
94
|
+
index += 1;
|
|
95
|
+
while (index < input.length && input[index] !== "\"") {
|
|
96
|
+
text += input[index];
|
|
97
|
+
index += 1;
|
|
98
|
+
}
|
|
99
|
+
index += 1;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (char === "(") depth += 1;
|
|
103
|
+
if (char === ")") depth = Math.max(0, depth - 1);
|
|
104
|
+
if (/\s/.test(char) && depth === 0) break;
|
|
105
|
+
atTokenStart = false;
|
|
106
|
+
text += char;
|
|
107
|
+
index += 1;
|
|
108
|
+
}
|
|
109
|
+
if (text.length > 0 || quoted) tokens.push({
|
|
110
|
+
text,
|
|
111
|
+
at: start,
|
|
112
|
+
quoted
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return tokens;
|
|
116
|
+
}
|
|
117
|
+
/** `(a or b)` → `["a", "b"]`; anything else is a single value. */
|
|
118
|
+
function readValues(raw) {
|
|
119
|
+
const trimmed = raw.trim();
|
|
120
|
+
if (!trimmed.startsWith("(")) return [stripQuotes(trimmed)];
|
|
121
|
+
return trimmed.replace(/^\(/, "").replace(/\)$/, "").split(/\s+or\s+/i).map((part) => stripQuotes(part.trim())).filter((part) => part.length > 0);
|
|
122
|
+
}
|
|
123
|
+
function stripQuotes(value) {
|
|
124
|
+
if (value.length >= 2 && value.startsWith("\"") && value.endsWith("\"")) return value.slice(1, -1);
|
|
125
|
+
return value.replace(/^"/, "");
|
|
126
|
+
}
|
|
127
|
+
const OPERATORS = [
|
|
128
|
+
{
|
|
129
|
+
symbol: ">=",
|
|
130
|
+
operator: "gte"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
symbol: "<=",
|
|
134
|
+
operator: "lte"
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
symbol: ":",
|
|
138
|
+
operator: "eq"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
symbol: ">",
|
|
142
|
+
operator: "gt"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
symbol: "<",
|
|
146
|
+
operator: "lt"
|
|
147
|
+
}
|
|
148
|
+
];
|
|
149
|
+
/** Where a field operator starts in the token, or `-1`. */
|
|
150
|
+
function findOperator(text) {
|
|
151
|
+
let best = null;
|
|
152
|
+
for (const { symbol, operator } of OPERATORS) {
|
|
153
|
+
const index = text.indexOf(symbol);
|
|
154
|
+
if (index <= 0) continue;
|
|
155
|
+
if (!best || index < best.index || index === best.index && symbol.length > best.symbol.length) best = {
|
|
156
|
+
index,
|
|
157
|
+
symbol,
|
|
158
|
+
operator
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return best;
|
|
162
|
+
}
|
|
163
|
+
/** Parse, keeping whatever could not be understood as a plain term. */
|
|
164
|
+
function parseQueryWithDiagnostics(input) {
|
|
165
|
+
const diagnostics = [];
|
|
166
|
+
const clauses = [];
|
|
167
|
+
let trailing = null;
|
|
168
|
+
for (const token of tokenize(input)) {
|
|
169
|
+
let text = token.text;
|
|
170
|
+
let negated = false;
|
|
171
|
+
if (!token.quoted && text.startsWith("-") && text.length > 1) {
|
|
172
|
+
negated = true;
|
|
173
|
+
text = text.slice(1);
|
|
174
|
+
}
|
|
175
|
+
const operator = token.quoted ? null : findOperator(text);
|
|
176
|
+
if (!operator) {
|
|
177
|
+
if (text.length > 0) clauses.push({
|
|
178
|
+
type: "term",
|
|
179
|
+
value: text,
|
|
180
|
+
negated
|
|
181
|
+
});
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
const field = text.slice(0, operator.index);
|
|
185
|
+
const rawValue = text.slice(operator.index + operator.symbol.length);
|
|
186
|
+
if (!FIELD_NAME.test(field)) {
|
|
187
|
+
clauses.push({
|
|
188
|
+
type: "term",
|
|
189
|
+
value: text,
|
|
190
|
+
negated
|
|
191
|
+
});
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
if (rawValue === "") {
|
|
195
|
+
trailing = {
|
|
196
|
+
field,
|
|
197
|
+
operator: operator.operator,
|
|
198
|
+
value: ""
|
|
199
|
+
};
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (rawValue === "*" && operator.operator === "eq") {
|
|
203
|
+
clauses.push({
|
|
204
|
+
type: "field",
|
|
205
|
+
field,
|
|
206
|
+
operator: "exists",
|
|
207
|
+
values: [],
|
|
208
|
+
negated
|
|
209
|
+
});
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
if (operator.operator === "eq" && rawValue.length > 2 && rawValue.startsWith("*") && rawValue.endsWith("*")) {
|
|
213
|
+
clauses.push({
|
|
214
|
+
type: "field",
|
|
215
|
+
field,
|
|
216
|
+
operator: "contains",
|
|
217
|
+
values: [stripQuotes(rawValue.slice(1, -1))],
|
|
218
|
+
negated
|
|
219
|
+
});
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
const values = readValues(rawValue);
|
|
223
|
+
if (values.length === 0) {
|
|
224
|
+
diagnostics.push({
|
|
225
|
+
at: token.at,
|
|
226
|
+
text: token.text,
|
|
227
|
+
message: "Empty value group"
|
|
228
|
+
});
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (operator.operator !== "eq" && values.length > 1) diagnostics.push({
|
|
232
|
+
at: token.at,
|
|
233
|
+
text: token.text,
|
|
234
|
+
message: "A comparison takes a single value"
|
|
235
|
+
});
|
|
236
|
+
const clause = {
|
|
237
|
+
type: "field",
|
|
238
|
+
field,
|
|
239
|
+
operator: operator.operator,
|
|
240
|
+
values: operator.operator === "eq" ? values : values.slice(0, 1),
|
|
241
|
+
negated
|
|
242
|
+
};
|
|
243
|
+
clauses.push(clause);
|
|
244
|
+
if (!rawValue.startsWith("(")) {
|
|
245
|
+
var _values$;
|
|
246
|
+
trailing = {
|
|
247
|
+
field,
|
|
248
|
+
operator: operator.operator,
|
|
249
|
+
value: (_values$ = values[0]) !== null && _values$ !== void 0 ? _values$ : ""
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return {
|
|
254
|
+
query: { clauses },
|
|
255
|
+
diagnostics,
|
|
256
|
+
trailing
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
/** Parse, discarding diagnostics. */
|
|
260
|
+
function parseQuery(input) {
|
|
261
|
+
return parseQueryWithDiagnostics(input).query;
|
|
262
|
+
}
|
|
263
|
+
//#endregion
|
|
264
|
+
//#region src/lib/query/query-format.ts
|
|
265
|
+
const OPERATOR_SYMBOL = {
|
|
266
|
+
eq: ":",
|
|
267
|
+
contains: ":",
|
|
268
|
+
gt: ">",
|
|
269
|
+
gte: ">=",
|
|
270
|
+
lt: "<",
|
|
271
|
+
lte: "<=",
|
|
272
|
+
exists: ":"
|
|
273
|
+
};
|
|
274
|
+
/** Quote a value that would otherwise re-parse as something else. */
|
|
275
|
+
function quoteValue(value) {
|
|
276
|
+
return /[\s"()]/.test(value) || value === "" ? `"${value.replace(/"/g, "")}"` : value;
|
|
277
|
+
}
|
|
278
|
+
/** One clause as text. */
|
|
279
|
+
function formatClause(clause) {
|
|
280
|
+
var _clause$values$2;
|
|
281
|
+
const prefix = clause.negated ? "-" : "";
|
|
282
|
+
if (clause.type === "term") return `${prefix}${quoteValue(clause.value)}`;
|
|
283
|
+
if (clause.operator === "exists") return `${prefix}${clause.field}:*`;
|
|
284
|
+
if (clause.operator === "contains") {
|
|
285
|
+
var _clause$values$;
|
|
286
|
+
return `${prefix}${clause.field}:*${(_clause$values$ = clause.values[0]) !== null && _clause$values$ !== void 0 ? _clause$values$ : ""}*`;
|
|
287
|
+
}
|
|
288
|
+
const symbol = OPERATOR_SYMBOL[clause.operator];
|
|
289
|
+
if (clause.values.length > 1) return `${prefix}${clause.field}${symbol}(${clause.values.map(quoteValue).join(" or ")})`;
|
|
290
|
+
return `${prefix}${clause.field}${symbol}${quoteValue((_clause$values$2 = clause.values[0]) !== null && _clause$values$2 !== void 0 ? _clause$values$2 : "")}`;
|
|
291
|
+
}
|
|
292
|
+
/** The whole query as text. */
|
|
293
|
+
function formatQuery(query) {
|
|
294
|
+
return query.clauses.map(formatClause).join(" ");
|
|
295
|
+
}
|
|
296
|
+
/** A short human label for a clause chip. */
|
|
297
|
+
function describeClause(clause) {
|
|
298
|
+
if (clause.type === "term") return clause.negated ? `not "${clause.value}"` : `"${clause.value}"`;
|
|
299
|
+
if (clause.operator === "exists") return clause.negated ? `${clause.field} missing` : `${clause.field} present`;
|
|
300
|
+
if (clause.operator === "contains") {
|
|
301
|
+
var _clause$values$3;
|
|
302
|
+
return `${clause.negated ? "not " : ""}${clause.field} ⊃ ${(_clause$values$3 = clause.values[0]) !== null && _clause$values$3 !== void 0 ? _clause$values$3 : ""}`;
|
|
303
|
+
}
|
|
304
|
+
const values = clause.values.join(", ");
|
|
305
|
+
const symbol = OPERATOR_SYMBOL[clause.operator];
|
|
306
|
+
return `${clause.negated ? "not " : ""}${clause.field} ${symbol === ":" ? "=" : symbol} ${values}`;
|
|
307
|
+
}
|
|
308
|
+
//#endregion
|
|
309
|
+
//#region src/lib/query/query-match.ts
|
|
310
|
+
function toText(value) {
|
|
311
|
+
if (value === null || value === void 0) return "";
|
|
312
|
+
if (typeof value === "string") return value;
|
|
313
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
314
|
+
return JSON.stringify(value);
|
|
315
|
+
}
|
|
316
|
+
function compare(left, right) {
|
|
317
|
+
const leftNumber = typeof left === "number" ? left : Number(toText(left));
|
|
318
|
+
const rightNumber = Number(right);
|
|
319
|
+
if (Number.isFinite(leftNumber) && Number.isFinite(rightNumber)) return leftNumber - rightNumber;
|
|
320
|
+
return toText(left).localeCompare(right);
|
|
321
|
+
}
|
|
322
|
+
function matchesClause(clause, read, searchable) {
|
|
323
|
+
if (clause.type === "term") return searchable().toLowerCase().includes(clause.value.toLowerCase());
|
|
324
|
+
const value = read(clause.field);
|
|
325
|
+
switch (clause.operator) {
|
|
326
|
+
case "exists": return value !== void 0 && value !== null && value !== "";
|
|
327
|
+
case "eq": return clause.values.some((candidate) => toText(value).toLowerCase() === candidate.toLowerCase());
|
|
328
|
+
case "contains": return clause.values.some((candidate) => toText(value).toLowerCase().includes(candidate.toLowerCase()));
|
|
329
|
+
case "gt":
|
|
330
|
+
var _clause$values$;
|
|
331
|
+
return compare(value, (_clause$values$ = clause.values[0]) !== null && _clause$values$ !== void 0 ? _clause$values$ : "") > 0;
|
|
332
|
+
case "gte":
|
|
333
|
+
var _clause$values$2;
|
|
334
|
+
return compare(value, (_clause$values$2 = clause.values[0]) !== null && _clause$values$2 !== void 0 ? _clause$values$2 : "") >= 0;
|
|
335
|
+
case "lt":
|
|
336
|
+
var _clause$values$3;
|
|
337
|
+
return compare(value, (_clause$values$3 = clause.values[0]) !== null && _clause$values$3 !== void 0 ? _clause$values$3 : "") < 0;
|
|
338
|
+
case "lte":
|
|
339
|
+
var _clause$values$4;
|
|
340
|
+
return compare(value, (_clause$values$4 = clause.values[0]) !== null && _clause$values$4 !== void 0 ? _clause$values$4 : "") <= 0;
|
|
341
|
+
default: return true;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Whether one row satisfies every clause.
|
|
346
|
+
*
|
|
347
|
+
* `searchable` is lazy because most queries are field constraints, and
|
|
348
|
+
* flattening a row to text for a term match nobody asked for is the expensive
|
|
349
|
+
* part of filtering a live tail.
|
|
350
|
+
*/
|
|
351
|
+
function matchesQuery(query, read, searchable) {
|
|
352
|
+
return query.clauses.every((clause) => {
|
|
353
|
+
const matched = matchesClause(clause, read, searchable);
|
|
354
|
+
return clause.negated ? !matched : matched;
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
/** Convenience for plain objects, including one level of nested properties. */
|
|
358
|
+
function matchesQueryObject(query, row, options = {}) {
|
|
359
|
+
const nested = options.nested ? row[options.nested] : void 0;
|
|
360
|
+
const read = (field) => field in row ? row[field] : nested === null || nested === void 0 ? void 0 : nested[field];
|
|
361
|
+
let cached = null;
|
|
362
|
+
const searchable = () => {
|
|
363
|
+
var _cached;
|
|
364
|
+
(_cached = cached) !== null && _cached !== void 0 || (cached = [...Object.values(row).filter((value) => typeof value !== "object"), ...Object.values(nested !== null && nested !== void 0 ? nested : {})].map(toText).join(" "));
|
|
365
|
+
return cached;
|
|
366
|
+
};
|
|
367
|
+
return matchesQuery(query, read, searchable);
|
|
368
|
+
}
|
|
369
|
+
//#endregion
|
|
370
|
+
exports.EMPTY_QUERY = EMPTY_QUERY;
|
|
371
|
+
exports.addClause = addClause;
|
|
372
|
+
exports.applyCellAction = applyCellAction;
|
|
373
|
+
exports.describeClause = describeClause;
|
|
374
|
+
exports.fieldValues = fieldValues;
|
|
375
|
+
exports.formatClause = formatClause;
|
|
376
|
+
exports.formatQuery = formatQuery;
|
|
377
|
+
exports.isEmptyQuery = isEmptyQuery;
|
|
378
|
+
exports.matchesQuery = matchesQuery;
|
|
379
|
+
exports.matchesQueryObject = matchesQueryObject;
|
|
380
|
+
exports.parseQuery = parseQuery;
|
|
381
|
+
exports.parseQueryWithDiagnostics = parseQueryWithDiagnostics;
|
|
382
|
+
exports.queryFields = queryFields;
|
|
383
|
+
exports.quoteValue = quoteValue;
|
|
384
|
+
exports.removeClause = removeClause;
|
|
385
|
+
exports.withFieldValue = withFieldValue;
|
|
386
|
+
exports.withoutField = withoutField;
|