@showwhat/configurator 1.0.0 → 2.0.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/README.md +3 -1
- package/dist/index.d.ts +45 -12
- package/dist/index.js +200 -148
- package/dist/index.js.map +1 -1
- package/package.json +19 -19
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# @showwhat/configurator
|
|
2
2
|
|
|
3
|
-
A reusable React component library for visually editing showwhat
|
|
3
|
+
A reusable React component library for visually editing showwhat definitions — like Swagger UI for your flag and config rules.
|
|
4
|
+
|
|
5
|
+
Provides a complete rule-builder UI while letting your app own storage, workflow, and persistence.
|
|
4
6
|
|
|
5
7
|
## Installation
|
|
6
8
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { Condition, Definition, Definitions, Variation, Presets, ConditionEvaluator, Resolution } from 'showwhat';
|
|
2
2
|
import { ClassValue } from 'clsx';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
|
-
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
5
4
|
import * as React$1 from 'react';
|
|
6
5
|
import React__default, { Component, ReactNode, ErrorInfo, ComponentType } from 'react';
|
|
7
|
-
import { VariantProps } from 'class-variance-authority';
|
|
8
6
|
import { Select as Select$1, Separator as Separator$1, ScrollArea as ScrollArea$1, Dialog as Dialog$1, DropdownMenu as DropdownMenu$1, Label as Label$1, Switch as Switch$1, Popover as Popover$1, Tabs as Tabs$1 } from 'radix-ui';
|
|
9
7
|
|
|
10
8
|
type DefinitionListProps = {
|
|
@@ -86,6 +84,7 @@ type ValueInputProps = {
|
|
|
86
84
|
type DateTimeInputProps = {
|
|
87
85
|
value: string;
|
|
88
86
|
onChange: (value: string) => void;
|
|
87
|
+
disabled?: boolean;
|
|
89
88
|
};
|
|
90
89
|
type ValidationIssueDisplay = {
|
|
91
90
|
path: (string | number)[];
|
|
@@ -115,11 +114,34 @@ declare const BUILTIN_CONDITION_TYPES: ConditionTypeMeta[];
|
|
|
115
114
|
declare const CONDITION_TYPE_MAP: Map<string, ConditionTypeMeta>;
|
|
116
115
|
declare function getConditionMeta(type: string): ConditionTypeMeta | undefined;
|
|
117
116
|
|
|
118
|
-
declare const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
117
|
+
declare const buttonVariantStyles: {
|
|
118
|
+
readonly default: "bg-primary text-primary-foreground hover:bg-primary/90";
|
|
119
|
+
readonly destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40";
|
|
120
|
+
readonly outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50";
|
|
121
|
+
readonly secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80";
|
|
122
|
+
readonly ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50";
|
|
123
|
+
readonly link: "text-primary underline-offset-4 hover:underline";
|
|
124
|
+
};
|
|
125
|
+
declare const buttonSizeStyles: {
|
|
126
|
+
readonly default: "h-9 px-4 py-2 has-[>svg]:px-3";
|
|
127
|
+
readonly xs: "h-6 gap-1 rounded px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3";
|
|
128
|
+
readonly sm: "h-8 gap-1.5 rounded px-3 has-[>svg]:px-2.5";
|
|
129
|
+
readonly lg: "h-10 rounded px-6 has-[>svg]:px-4";
|
|
130
|
+
readonly icon: "size-9";
|
|
131
|
+
readonly "icon-xs": "size-6 rounded [&_svg:not([class*='size-'])]:size-3";
|
|
132
|
+
readonly "icon-sm": "size-8";
|
|
133
|
+
readonly "icon-lg": "size-10";
|
|
134
|
+
};
|
|
135
|
+
type ButtonVariant = keyof typeof buttonVariantStyles;
|
|
136
|
+
type ButtonSize = keyof typeof buttonSizeStyles;
|
|
137
|
+
declare function buttonVariants(opts?: {
|
|
138
|
+
variant?: ButtonVariant;
|
|
139
|
+
size?: ButtonSize;
|
|
140
|
+
className?: string;
|
|
141
|
+
}): string;
|
|
142
|
+
declare function Button({ className, variant, size, asChild, ref, ...props }: React__default.ComponentProps<"button"> & {
|
|
143
|
+
variant?: ButtonVariant;
|
|
144
|
+
size?: ButtonSize;
|
|
123
145
|
asChild?: boolean;
|
|
124
146
|
}): react_jsx_runtime.JSX.Element;
|
|
125
147
|
|
|
@@ -136,10 +158,21 @@ declare function SelectLabel({ className, ...props }: React__default.ComponentPr
|
|
|
136
158
|
declare function SelectItem({ className, children, ...props }: React__default.ComponentProps<typeof Select$1.Item>): react_jsx_runtime.JSX.Element;
|
|
137
159
|
declare function SelectSeparator({ className, ...props }: React__default.ComponentProps<typeof Select$1.Separator>): react_jsx_runtime.JSX.Element;
|
|
138
160
|
|
|
139
|
-
declare const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
161
|
+
declare const badgeVariantStyles: {
|
|
162
|
+
readonly default: "bg-primary text-primary-foreground [a&]:hover:bg-primary/90";
|
|
163
|
+
readonly secondary: "bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90";
|
|
164
|
+
readonly destructive: "bg-destructive text-white focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40 [a&]:hover:bg-destructive/90";
|
|
165
|
+
readonly outline: "border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground";
|
|
166
|
+
readonly ghost: "[a&]:hover:bg-accent [a&]:hover:text-accent-foreground";
|
|
167
|
+
readonly link: "text-primary underline-offset-4 [a&]:hover:underline";
|
|
168
|
+
};
|
|
169
|
+
type BadgeVariant = keyof typeof badgeVariantStyles;
|
|
170
|
+
declare function badgeVariants(opts?: {
|
|
171
|
+
variant?: BadgeVariant;
|
|
172
|
+
className?: string;
|
|
173
|
+
}): string;
|
|
174
|
+
declare function Badge({ className, variant, asChild, ...props }: React__default.ComponentProps<"span"> & {
|
|
175
|
+
variant?: BadgeVariant;
|
|
143
176
|
asChild?: boolean;
|
|
144
177
|
}): react_jsx_runtime.JSX.Element;
|
|
145
178
|
|
|
@@ -187,7 +220,7 @@ declare function TabsContent({ className, ...props }: React__default.ComponentPr
|
|
|
187
220
|
|
|
188
221
|
declare function ValueInput({ value, onChange, placeholder }: ValueInputProps): react_jsx_runtime.JSX.Element;
|
|
189
222
|
|
|
190
|
-
declare function DateTimeInput({ value, onChange }: DateTimeInputProps): react_jsx_runtime.JSX.Element;
|
|
223
|
+
declare function DateTimeInput({ value, onChange, disabled }: DateTimeInputProps): react_jsx_runtime.JSX.Element;
|
|
191
224
|
|
|
192
225
|
declare function ValidationMessage({ errors }: ValidationMessageProps): react_jsx_runtime.JSX.Element | null;
|
|
193
226
|
|
package/dist/index.js
CHANGED
|
@@ -275,27 +275,20 @@ function OperatorSelect({ value, onChange, options, disabled }) {
|
|
|
275
275
|
import { useCallback, useState } from "react";
|
|
276
276
|
|
|
277
277
|
// src/components/ui/badge.tsx
|
|
278
|
-
import { cva } from "class-variance-authority";
|
|
279
278
|
import { Slot } from "radix-ui";
|
|
280
279
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
281
|
-
var
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
},
|
|
294
|
-
defaultVariants: {
|
|
295
|
-
variant: "default"
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
);
|
|
280
|
+
var badgeBase = "inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3";
|
|
281
|
+
var badgeVariantStyles = {
|
|
282
|
+
default: "bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
|
|
283
|
+
secondary: "bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
|
|
284
|
+
destructive: "bg-destructive text-white focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40 [a&]:hover:bg-destructive/90",
|
|
285
|
+
outline: "border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
|
286
|
+
ghost: "[a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
|
287
|
+
link: "text-primary underline-offset-4 [a&]:hover:underline"
|
|
288
|
+
};
|
|
289
|
+
function badgeVariants(opts) {
|
|
290
|
+
return cn(badgeBase, badgeVariantStyles[opts?.variant ?? "default"], opts?.className);
|
|
291
|
+
}
|
|
299
292
|
function Badge({
|
|
300
293
|
className,
|
|
301
294
|
variant = "default",
|
|
@@ -316,7 +309,7 @@ function Badge({
|
|
|
316
309
|
|
|
317
310
|
// src/components/condition-builder/TagInput.tsx
|
|
318
311
|
import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
319
|
-
function TagInput({ value, onChange, placeholder }) {
|
|
312
|
+
function TagInput({ value, onChange, placeholder, disabled }) {
|
|
320
313
|
const values = Array.isArray(value) ? value.filter(Boolean) : value ? [value] : [];
|
|
321
314
|
const [text, setText] = useState("");
|
|
322
315
|
const emit = useCallback(
|
|
@@ -365,32 +358,39 @@ function TagInput({ value, onChange, placeholder }) {
|
|
|
365
358
|
},
|
|
366
359
|
[addValues]
|
|
367
360
|
);
|
|
368
|
-
return /* @__PURE__ */ jsxs3(
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
{
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
361
|
+
return /* @__PURE__ */ jsxs3(
|
|
362
|
+
"div",
|
|
363
|
+
{
|
|
364
|
+
className: `border-input focus-within:border-ring focus-within:ring-ring/50 flex min-h-9 flex-1 flex-wrap items-center gap-1 rounded-md border px-2 py-1 focus-within:ring-[3px]${disabled ? " opacity-50" : ""}`,
|
|
365
|
+
children: [
|
|
366
|
+
values.map((v, i) => /* @__PURE__ */ jsxs3(Badge, { variant: "outline", className: "bg-muted gap-1 font-mono text-xs", children: [
|
|
367
|
+
v,
|
|
368
|
+
!disabled && /* @__PURE__ */ jsx7(
|
|
369
|
+
"button",
|
|
370
|
+
{
|
|
371
|
+
type: "button",
|
|
372
|
+
className: "text-muted-foreground hover:text-foreground ml-0.5 cursor-pointer leading-none",
|
|
373
|
+
onClick: () => removeValue(i),
|
|
374
|
+
"aria-label": `Remove ${v}`,
|
|
375
|
+
children: "\xD7"
|
|
376
|
+
}
|
|
377
|
+
)
|
|
378
|
+
] }, `${v}-${i}`)),
|
|
379
|
+
/* @__PURE__ */ jsx7(
|
|
380
|
+
"input",
|
|
381
|
+
{
|
|
382
|
+
className: "min-w-[80px] flex-1 bg-transparent py-0.5 font-mono text-sm outline-none placeholder:text-muted-foreground",
|
|
383
|
+
value: text,
|
|
384
|
+
placeholder: values.length === 0 ? placeholder ?? "type and press Enter" : "",
|
|
385
|
+
onChange: (e) => setText(e.target.value),
|
|
386
|
+
onKeyDown: handleKeyDown,
|
|
387
|
+
onPaste: handlePaste,
|
|
388
|
+
disabled
|
|
389
|
+
}
|
|
390
|
+
)
|
|
391
|
+
]
|
|
392
|
+
}
|
|
393
|
+
);
|
|
394
394
|
}
|
|
395
395
|
|
|
396
396
|
// src/components/condition-builder/condition-builders.ts
|
|
@@ -489,7 +489,7 @@ import { useCallback as useCallback4, useMemo as useMemo2 } from "react";
|
|
|
489
489
|
// src/components/condition-builder/NumberTagInput.tsx
|
|
490
490
|
import { useCallback as useCallback3, useState as useState2 } from "react";
|
|
491
491
|
import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
492
|
-
function NumberTagInput({ value, onChange, placeholder }) {
|
|
492
|
+
function NumberTagInput({ value, onChange, placeholder, disabled }) {
|
|
493
493
|
const values = Array.isArray(value) ? value : [value];
|
|
494
494
|
const [text, setText] = useState2("");
|
|
495
495
|
const emit = useCallback3(
|
|
@@ -538,33 +538,40 @@ function NumberTagInput({ value, onChange, placeholder }) {
|
|
|
538
538
|
},
|
|
539
539
|
[addValues]
|
|
540
540
|
);
|
|
541
|
-
return /* @__PURE__ */ jsxs5(
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
{
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
541
|
+
return /* @__PURE__ */ jsxs5(
|
|
542
|
+
"div",
|
|
543
|
+
{
|
|
544
|
+
className: `border-input focus-within:border-ring focus-within:ring-ring/50 flex min-h-9 flex-1 flex-wrap items-center gap-1 rounded-md border px-2 py-1 focus-within:ring-[3px]${disabled ? " opacity-50" : ""}`,
|
|
545
|
+
children: [
|
|
546
|
+
values.map((v, i) => /* @__PURE__ */ jsxs5(Badge, { variant: "outline", className: "bg-muted gap-1 font-mono text-xs", children: [
|
|
547
|
+
v,
|
|
548
|
+
!disabled && /* @__PURE__ */ jsx9(
|
|
549
|
+
"button",
|
|
550
|
+
{
|
|
551
|
+
type: "button",
|
|
552
|
+
className: "text-muted-foreground hover:text-foreground ml-0.5 cursor-pointer leading-none",
|
|
553
|
+
onClick: () => removeValue(i),
|
|
554
|
+
"aria-label": `Remove ${v}`,
|
|
555
|
+
children: "\xD7"
|
|
556
|
+
}
|
|
557
|
+
)
|
|
558
|
+
] }, `${v}-${i}`)),
|
|
559
|
+
/* @__PURE__ */ jsx9(
|
|
560
|
+
"input",
|
|
561
|
+
{
|
|
562
|
+
className: "min-w-[80px] flex-1 bg-transparent py-0.5 font-mono text-sm outline-none placeholder:text-muted-foreground",
|
|
563
|
+
type: "number",
|
|
564
|
+
value: text,
|
|
565
|
+
placeholder: values.length === 0 ? placeholder ?? "type and press Enter" : "",
|
|
566
|
+
onChange: (e) => setText(e.target.value),
|
|
567
|
+
onKeyDown: handleKeyDown,
|
|
568
|
+
onPaste: handlePaste,
|
|
569
|
+
disabled
|
|
570
|
+
}
|
|
571
|
+
)
|
|
572
|
+
]
|
|
573
|
+
}
|
|
574
|
+
);
|
|
568
575
|
}
|
|
569
576
|
|
|
570
577
|
// src/components/condition-builder/NumberConditionEditor.tsx
|
|
@@ -663,7 +670,7 @@ function fromLocalDatetime(local) {
|
|
|
663
670
|
if (Number.isNaN(d.getTime())) return local;
|
|
664
671
|
return d.toISOString();
|
|
665
672
|
}
|
|
666
|
-
function DateTimeInput({ value, onChange }) {
|
|
673
|
+
function DateTimeInput({ value, onChange, disabled }) {
|
|
667
674
|
const [rawValue, setRawValue] = useState3(value);
|
|
668
675
|
const [showRaw, setShowRaw] = useState3(false);
|
|
669
676
|
const prevValueRef = useRef(value);
|
|
@@ -682,7 +689,8 @@ function DateTimeInput({ value, onChange }) {
|
|
|
682
689
|
onChange: (e) => {
|
|
683
690
|
setRawValue(e.target.value);
|
|
684
691
|
onChange(e.target.value);
|
|
685
|
-
}
|
|
692
|
+
},
|
|
693
|
+
disabled
|
|
686
694
|
}
|
|
687
695
|
),
|
|
688
696
|
/* @__PURE__ */ jsx11(
|
|
@@ -704,7 +712,8 @@ function DateTimeInput({ value, onChange }) {
|
|
|
704
712
|
className: "h-8 flex-1 text-xs",
|
|
705
713
|
type: "datetime-local",
|
|
706
714
|
value: toLocalDatetime(value),
|
|
707
|
-
onChange: (e) => onChange(fromLocalDatetime(e.target.value))
|
|
715
|
+
onChange: (e) => onChange(fromLocalDatetime(e.target.value)),
|
|
716
|
+
disabled
|
|
708
717
|
}
|
|
709
718
|
),
|
|
710
719
|
/* @__PURE__ */ jsx11(
|
|
@@ -910,38 +919,35 @@ function getConditionMeta(type) {
|
|
|
910
919
|
}
|
|
911
920
|
|
|
912
921
|
// src/components/ui/button.tsx
|
|
913
|
-
import { cva as cva2 } from "class-variance-authority";
|
|
914
922
|
import { Slot as Slot2 } from "radix-ui";
|
|
915
923
|
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
916
|
-
var
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
}
|
|
944
|
-
);
|
|
924
|
+
var buttonBase = "inline-flex shrink-0 items-center justify-center gap-2 rounded text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 hover:cursor-pointer";
|
|
925
|
+
var buttonVariantStyles = {
|
|
926
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
927
|
+
destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
|
|
928
|
+
outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
|
|
929
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
930
|
+
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
931
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
932
|
+
};
|
|
933
|
+
var buttonSizeStyles = {
|
|
934
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
935
|
+
xs: "h-6 gap-1 rounded px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
936
|
+
sm: "h-8 gap-1.5 rounded px-3 has-[>svg]:px-2.5",
|
|
937
|
+
lg: "h-10 rounded px-6 has-[>svg]:px-4",
|
|
938
|
+
icon: "size-9",
|
|
939
|
+
"icon-xs": "size-6 rounded [&_svg:not([class*='size-'])]:size-3",
|
|
940
|
+
"icon-sm": "size-8",
|
|
941
|
+
"icon-lg": "size-10"
|
|
942
|
+
};
|
|
943
|
+
function buttonVariants(opts) {
|
|
944
|
+
return cn(
|
|
945
|
+
buttonBase,
|
|
946
|
+
buttonVariantStyles[opts?.variant ?? "default"],
|
|
947
|
+
buttonSizeStyles[opts?.size ?? "default"],
|
|
948
|
+
opts?.className
|
|
949
|
+
);
|
|
950
|
+
}
|
|
945
951
|
function Button({
|
|
946
952
|
className,
|
|
947
953
|
variant = "default",
|
|
@@ -2978,17 +2984,24 @@ function createPresetConditionMeta(presets) {
|
|
|
2978
2984
|
type: name,
|
|
2979
2985
|
label: capitalize(name),
|
|
2980
2986
|
description,
|
|
2981
|
-
defaults: { ...baseDefaults, ...preset.
|
|
2987
|
+
defaults: { ...baseDefaults, ...preset.overrides, type: name }
|
|
2982
2988
|
};
|
|
2983
2989
|
});
|
|
2984
2990
|
}
|
|
2985
|
-
function createPresetEditor(presetName, builtinType, presetKey) {
|
|
2991
|
+
function createPresetEditor(presetName, builtinType, presetKey, overrides = {}) {
|
|
2992
|
+
const lockedFields = new Set(Object.keys(overrides));
|
|
2986
2993
|
function PresetConditionEditor({ condition, onChange }) {
|
|
2987
2994
|
const rec = useMemo10(() => condition, [condition]);
|
|
2988
2995
|
const update = useCallback11(
|
|
2989
2996
|
(field, value) => {
|
|
2990
2997
|
onChange(
|
|
2991
|
-
buildCustomCondition({
|
|
2998
|
+
buildCustomCondition({
|
|
2999
|
+
...rec,
|
|
3000
|
+
[field]: value,
|
|
3001
|
+
...overrides,
|
|
3002
|
+
key: presetKey,
|
|
3003
|
+
type: presetName
|
|
3004
|
+
})
|
|
2992
3005
|
);
|
|
2993
3006
|
},
|
|
2994
3007
|
[rec, onChange]
|
|
@@ -3012,6 +3025,8 @@ function createPresetEditor(presetName, builtinType, presetKey) {
|
|
|
3012
3025
|
})
|
|
3013
3026
|
);
|
|
3014
3027
|
};
|
|
3028
|
+
const opLocked = lockedFields.has("op");
|
|
3029
|
+
const valueLocked = lockedFields.has("value");
|
|
3015
3030
|
return /* @__PURE__ */ jsxs31(ConditionRow, { children: [
|
|
3016
3031
|
/* @__PURE__ */ jsx45(KeyInput, { value: presetKey, disabled: true }),
|
|
3017
3032
|
/* @__PURE__ */ jsx45(
|
|
@@ -3019,7 +3034,8 @@ function createPresetEditor(presetName, builtinType, presetKey) {
|
|
|
3019
3034
|
{
|
|
3020
3035
|
value: String(rec.op ?? "eq"),
|
|
3021
3036
|
onChange: handleOpChange,
|
|
3022
|
-
options: OP_OPTIONS
|
|
3037
|
+
options: OP_OPTIONS,
|
|
3038
|
+
disabled: opLocked
|
|
3023
3039
|
}
|
|
3024
3040
|
),
|
|
3025
3041
|
isArray ? /* @__PURE__ */ jsx45(
|
|
@@ -3027,7 +3043,8 @@ function createPresetEditor(presetName, builtinType, presetKey) {
|
|
|
3027
3043
|
{
|
|
3028
3044
|
value: rec.value ?? "",
|
|
3029
3045
|
onChange: (v) => update("value", v),
|
|
3030
|
-
placeholder: `e.g. ${presetKey} value
|
|
3046
|
+
placeholder: `e.g. ${presetKey} value`,
|
|
3047
|
+
disabled: valueLocked
|
|
3031
3048
|
}
|
|
3032
3049
|
) : isRegex ? /* @__PURE__ */ jsx45(
|
|
3033
3050
|
Input,
|
|
@@ -3035,7 +3052,8 @@ function createPresetEditor(presetName, builtinType, presetKey) {
|
|
|
3035
3052
|
className: "h-8 font-mono text-sm",
|
|
3036
3053
|
value: String(rec.value ?? ""),
|
|
3037
3054
|
placeholder: "e.g. ^test.*$",
|
|
3038
|
-
onChange: (e) => update("value", e.target.value)
|
|
3055
|
+
onChange: (e) => update("value", e.target.value),
|
|
3056
|
+
disabled: valueLocked
|
|
3039
3057
|
}
|
|
3040
3058
|
) : /* @__PURE__ */ jsx45(
|
|
3041
3059
|
Input,
|
|
@@ -3043,7 +3061,8 @@ function createPresetEditor(presetName, builtinType, presetKey) {
|
|
|
3043
3061
|
className: "h-8 text-sm",
|
|
3044
3062
|
value: String(rec.value ?? ""),
|
|
3045
3063
|
placeholder: `e.g. ${presetKey} value`,
|
|
3046
|
-
onChange: (e) => update("value", e.target.value)
|
|
3064
|
+
onChange: (e) => update("value", e.target.value),
|
|
3065
|
+
disabled: valueLocked
|
|
3047
3066
|
}
|
|
3048
3067
|
)
|
|
3049
3068
|
] });
|
|
@@ -3065,6 +3084,8 @@ function createPresetEditor(presetName, builtinType, presetKey) {
|
|
|
3065
3084
|
})
|
|
3066
3085
|
);
|
|
3067
3086
|
};
|
|
3087
|
+
const numOpLocked = lockedFields.has("op");
|
|
3088
|
+
const numValueLocked = lockedFields.has("value");
|
|
3068
3089
|
return /* @__PURE__ */ jsxs31(ConditionRow, { children: [
|
|
3069
3090
|
/* @__PURE__ */ jsx45(KeyInput, { value: presetKey, disabled: true }),
|
|
3070
3091
|
/* @__PURE__ */ jsx45(
|
|
@@ -3072,7 +3093,8 @@ function createPresetEditor(presetName, builtinType, presetKey) {
|
|
|
3072
3093
|
{
|
|
3073
3094
|
value: String(rec.op ?? "eq"),
|
|
3074
3095
|
onChange: handleNumOpChange,
|
|
3075
|
-
options: OP_OPTIONS2
|
|
3096
|
+
options: OP_OPTIONS2,
|
|
3097
|
+
disabled: numOpLocked
|
|
3076
3098
|
}
|
|
3077
3099
|
),
|
|
3078
3100
|
isNumArray ? /* @__PURE__ */ jsx45(
|
|
@@ -3080,7 +3102,8 @@ function createPresetEditor(presetName, builtinType, presetKey) {
|
|
|
3080
3102
|
{
|
|
3081
3103
|
value: rec.value ?? [],
|
|
3082
3104
|
onChange: (v) => update("value", v),
|
|
3083
|
-
placeholder: `e.g. ${presetKey} value
|
|
3105
|
+
placeholder: `e.g. ${presetKey} value`,
|
|
3106
|
+
disabled: numValueLocked
|
|
3084
3107
|
}
|
|
3085
3108
|
) : /* @__PURE__ */ jsx45(
|
|
3086
3109
|
Input,
|
|
@@ -3089,12 +3112,14 @@ function createPresetEditor(presetName, builtinType, presetKey) {
|
|
|
3089
3112
|
className: "h-8 font-mono text-sm",
|
|
3090
3113
|
value: rec.value !== void 0 ? String(rec.value) : "",
|
|
3091
3114
|
placeholder: "e.g. 100",
|
|
3092
|
-
onChange: (e) => update("value", e.target.value === "" ? "" : Number(e.target.value))
|
|
3115
|
+
onChange: (e) => update("value", e.target.value === "" ? "" : Number(e.target.value)),
|
|
3116
|
+
disabled: numValueLocked
|
|
3093
3117
|
}
|
|
3094
3118
|
)
|
|
3095
3119
|
] });
|
|
3096
3120
|
}
|
|
3097
|
-
case "bool":
|
|
3121
|
+
case "bool": {
|
|
3122
|
+
const boolValueLocked = lockedFields.has("value");
|
|
3098
3123
|
return /* @__PURE__ */ jsxs31(ConditionRow, { children: [
|
|
3099
3124
|
/* @__PURE__ */ jsx45(KeyInput, { value: presetKey, disabled: true }),
|
|
3100
3125
|
/* @__PURE__ */ jsx45(OperatorSelect, { value: "eq", options: OP_OPTIONS4, disabled: true }),
|
|
@@ -3103,6 +3128,7 @@ function createPresetEditor(presetName, builtinType, presetKey) {
|
|
|
3103
3128
|
{
|
|
3104
3129
|
value: String(rec.value ?? "true"),
|
|
3105
3130
|
onValueChange: (v) => update("value", v === "true"),
|
|
3131
|
+
disabled: boolValueLocked,
|
|
3106
3132
|
children: [
|
|
3107
3133
|
/* @__PURE__ */ jsx45(SelectTrigger, { className: "h-8 text-sm", children: /* @__PURE__ */ jsx45(SelectValue, {}) }),
|
|
3108
3134
|
/* @__PURE__ */ jsxs31(SelectContent, { children: [
|
|
@@ -3113,7 +3139,10 @@ function createPresetEditor(presetName, builtinType, presetKey) {
|
|
|
3113
3139
|
}
|
|
3114
3140
|
)
|
|
3115
3141
|
] });
|
|
3116
|
-
|
|
3142
|
+
}
|
|
3143
|
+
case "datetime": {
|
|
3144
|
+
const dtOpLocked = lockedFields.has("op");
|
|
3145
|
+
const dtValueLocked = lockedFields.has("value");
|
|
3117
3146
|
return /* @__PURE__ */ jsxs31(ConditionRow, { children: [
|
|
3118
3147
|
/* @__PURE__ */ jsx45(KeyInput, { value: presetKey, disabled: true }),
|
|
3119
3148
|
/* @__PURE__ */ jsx45(
|
|
@@ -3121,11 +3150,20 @@ function createPresetEditor(presetName, builtinType, presetKey) {
|
|
|
3121
3150
|
{
|
|
3122
3151
|
value: String(rec.op ?? "eq"),
|
|
3123
3152
|
onChange: (v) => update("op", v),
|
|
3124
|
-
options: OP_OPTIONS3
|
|
3153
|
+
options: OP_OPTIONS3,
|
|
3154
|
+
disabled: dtOpLocked
|
|
3125
3155
|
}
|
|
3126
3156
|
),
|
|
3127
|
-
/* @__PURE__ */ jsx45(
|
|
3157
|
+
/* @__PURE__ */ jsx45(
|
|
3158
|
+
DateTimeInput,
|
|
3159
|
+
{
|
|
3160
|
+
value: String(rec.value ?? ""),
|
|
3161
|
+
onChange: (v) => update("value", v),
|
|
3162
|
+
disabled: dtValueLocked
|
|
3163
|
+
}
|
|
3164
|
+
)
|
|
3128
3165
|
] });
|
|
3166
|
+
}
|
|
3129
3167
|
}
|
|
3130
3168
|
return null;
|
|
3131
3169
|
}
|
|
@@ -3137,7 +3175,10 @@ function createPresetUI(presets) {
|
|
|
3137
3175
|
const editorOverrides = /* @__PURE__ */ new Map();
|
|
3138
3176
|
for (const [name, preset] of Object.entries(presets)) {
|
|
3139
3177
|
if (PRIMITIVE_TYPES.has(preset.type) && preset.key) {
|
|
3140
|
-
editorOverrides.set(
|
|
3178
|
+
editorOverrides.set(
|
|
3179
|
+
name,
|
|
3180
|
+
createPresetEditor(name, preset.type, preset.key, preset.overrides)
|
|
3181
|
+
);
|
|
3141
3182
|
}
|
|
3142
3183
|
}
|
|
3143
3184
|
return { extraConditionTypes, editorOverrides };
|
|
@@ -3202,7 +3243,7 @@ function useConfiguratorSelector(selector) {
|
|
|
3202
3243
|
// src/configurator/PreviewPanel.tsx
|
|
3203
3244
|
import { useCallback as useCallback14, useEffect, useMemo as useMemo11, useRef as useRef5, useState as useState11 } from "react";
|
|
3204
3245
|
import { ChevronRight as ChevronRight2, Eye as Eye2, Loader2, Maximize2, Play } from "lucide-react";
|
|
3205
|
-
import { resolve } from "showwhat";
|
|
3246
|
+
import { resolve, builtinEvaluators } from "showwhat";
|
|
3206
3247
|
import { DefinitionInactiveError, DefinitionNotFoundError, VariationNotFoundError } from "showwhat";
|
|
3207
3248
|
|
|
3208
3249
|
// src/configurator/selectors.ts
|
|
@@ -3407,38 +3448,49 @@ function PreviewPanel() {
|
|
|
3407
3448
|
const result = await resolve({
|
|
3408
3449
|
definitions: { [selectedKey]: definitions[selectedKey] },
|
|
3409
3450
|
context,
|
|
3410
|
-
options:
|
|
3451
|
+
options: {
|
|
3452
|
+
evaluators: builtinEvaluators,
|
|
3453
|
+
...fallback ? { fallback } : void 0
|
|
3454
|
+
}
|
|
3411
3455
|
});
|
|
3412
3456
|
if (controller.signal.aborted) return;
|
|
3413
3457
|
const resolution = result[selectedKey];
|
|
3414
|
-
|
|
3415
|
-
status: "success",
|
|
3416
|
-
value: resolution.value,
|
|
3417
|
-
meta: resolution.meta
|
|
3418
|
-
});
|
|
3419
|
-
} catch (err) {
|
|
3420
|
-
if (controller.signal.aborted) return;
|
|
3421
|
-
if (err instanceof DefinitionInactiveError) {
|
|
3458
|
+
if (resolution.success) {
|
|
3422
3459
|
setPreviewResult({
|
|
3423
|
-
status: "
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
} else if (err instanceof VariationNotFoundError) {
|
|
3427
|
-
setPreviewResult({
|
|
3428
|
-
status: "no-match",
|
|
3429
|
-
message: "No variation matched the given context"
|
|
3430
|
-
});
|
|
3431
|
-
} else if (err instanceof DefinitionNotFoundError) {
|
|
3432
|
-
setPreviewResult({
|
|
3433
|
-
status: "error",
|
|
3434
|
-
message: `Definition "${selectedKey}" not found`
|
|
3460
|
+
status: "success",
|
|
3461
|
+
value: resolution.value,
|
|
3462
|
+
meta: resolution.meta
|
|
3435
3463
|
});
|
|
3436
3464
|
} else {
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3465
|
+
const err = resolution.error;
|
|
3466
|
+
if (err instanceof DefinitionInactiveError) {
|
|
3467
|
+
setPreviewResult({
|
|
3468
|
+
status: "inactive",
|
|
3469
|
+
message: `"${selectedKey}" is inactive`
|
|
3470
|
+
});
|
|
3471
|
+
} else if (err instanceof VariationNotFoundError) {
|
|
3472
|
+
setPreviewResult({
|
|
3473
|
+
status: "no-match",
|
|
3474
|
+
message: "No variation matched the given context"
|
|
3475
|
+
});
|
|
3476
|
+
} else if (err instanceof DefinitionNotFoundError) {
|
|
3477
|
+
setPreviewResult({
|
|
3478
|
+
status: "error",
|
|
3479
|
+
message: `Definition "${selectedKey}" not found`
|
|
3480
|
+
});
|
|
3481
|
+
} else {
|
|
3482
|
+
setPreviewResult({
|
|
3483
|
+
status: "error",
|
|
3484
|
+
message: err.message
|
|
3485
|
+
});
|
|
3486
|
+
}
|
|
3441
3487
|
}
|
|
3488
|
+
} catch (err) {
|
|
3489
|
+
if (controller.signal.aborted) return;
|
|
3490
|
+
setPreviewResult({
|
|
3491
|
+
status: "error",
|
|
3492
|
+
message: err instanceof Error ? err.message : "Unknown error"
|
|
3493
|
+
});
|
|
3442
3494
|
} finally {
|
|
3443
3495
|
if (!controller.signal.aborted) {
|
|
3444
3496
|
setIsResolving(false);
|