@repraze/kernelkit 0.1.0-alpha.4 → 0.1.0-alpha.5
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/components/alert-dialog.d.ts.map +1 -1
- package/dist/components/alert-dialog.js +4 -1
- package/dist/components/alert-dialog.js.map +1 -1
- package/dist/components/alert.js +3 -3
- package/dist/components/alert.js.map +1 -1
- package/dist/components/badge.js +1 -1
- package/dist/components/badge.js.map +1 -1
- package/dist/components/button.js +1 -1
- package/dist/components/button.js.map +1 -1
- package/dist/components/calendar.d.ts +8 -1
- package/dist/components/calendar.d.ts.map +1 -1
- package/dist/components/calendar.js +33 -11
- package/dist/components/calendar.js.map +1 -1
- package/dist/components/callout.js +2 -2
- package/dist/components/callout.js.map +1 -1
- package/dist/components/combobox.js +1 -1
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/date-picker.d.ts +11 -5
- package/dist/components/date-picker.d.ts.map +1 -1
- package/dist/components/date-picker.js +29 -7
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/description-list.d.ts +26 -0
- package/dist/components/description-list.d.ts.map +1 -0
- package/dist/components/description-list.js +59 -0
- package/dist/components/description-list.js.map +1 -0
- package/dist/components/locale.d.ts +19 -0
- package/dist/components/locale.d.ts.map +1 -0
- package/dist/components/locale.js +54 -0
- package/dist/components/locale.js.map +1 -0
- package/dist/components/popover.d.ts +1 -1
- package/dist/components/popover.d.ts.map +1 -1
- package/dist/components/popover.js +2 -2
- package/dist/components/popover.js.map +1 -1
- package/dist/components/progress.d.ts +19 -6
- package/dist/components/progress.d.ts.map +1 -1
- package/dist/components/progress.js +18 -3
- package/dist/components/progress.js.map +1 -1
- package/dist/components/search-trigger.d.ts +4 -1
- package/dist/components/search-trigger.d.ts.map +1 -1
- package/dist/components/search-trigger.js +5 -2
- package/dist/components/search-trigger.js.map +1 -1
- package/dist/components/shimmer.d.ts +13 -0
- package/dist/components/shimmer.d.ts.map +1 -0
- package/dist/components/shimmer.js +21 -0
- package/dist/components/shimmer.js.map +1 -0
- package/dist/components/spinner.d.ts +28 -6
- package/dist/components/spinner.d.ts.map +1 -1
- package/dist/components/spinner.js +66 -14
- package/dist/components/spinner.js.map +1 -1
- package/dist/components/stepper.d.ts +64 -0
- package/dist/components/stepper.d.ts.map +1 -0
- package/dist/components/stepper.js +167 -0
- package/dist/components/stepper.js.map +1 -0
- package/dist/components/tag-input.d.ts +47 -0
- package/dist/components/tag-input.d.ts.map +1 -0
- package/dist/components/tag-input.js +211 -0
- package/dist/components/tag-input.js.map +1 -0
- package/dist/components/time-input.d.ts +75 -0
- package/dist/components/time-input.d.ts.map +1 -0
- package/dist/components/time-input.js +341 -0
- package/dist/components/time-input.js.map +1 -0
- package/dist/components/time-select.d.ts +49 -0
- package/dist/components/time-select.d.ts.map +1 -0
- package/dist/components/time-select.js +178 -0
- package/dist/components/time-select.js.map +1 -0
- package/dist/components/timeline.d.ts +41 -0
- package/dist/components/timeline.d.ts.map +1 -0
- package/dist/components/timeline.js +83 -0
- package/dist/components/timeline.js.map +1 -0
- package/dist/components/toast.d.ts.map +1 -1
- package/dist/components/toast.js +4 -2
- package/dist/components/toast.js.map +1 -1
- package/dist/components/tree.d.ts +87 -0
- package/dist/components/tree.d.ts.map +1 -0
- package/dist/components/tree.js +516 -0
- package/dist/components/tree.js.map +1 -0
- package/dist/hooks/use-time-format.d.ts +23 -0
- package/dist/hooks/use-time-format.d.ts.map +1 -0
- package/dist/hooks/use-time-format.js +52 -0
- package/dist/hooks/use-time-format.js.map +1 -0
- package/dist/lib/color.d.ts +5 -1
- package/dist/lib/color.d.ts.map +1 -1
- package/dist/lib/color.js +14 -2
- package/dist/lib/color.js.map +1 -1
- package/dist/lib/recipes.d.ts +5 -4
- package/dist/lib/recipes.d.ts.map +1 -1
- package/dist/lib/recipes.js +7 -5
- package/dist/lib/recipes.js.map +1 -1
- package/package.json +1 -1
- package/src/components/alert-dialog.tsx +4 -1
- package/src/components/alert.tsx +3 -3
- package/src/components/badge.tsx +1 -1
- package/src/components/button.tsx +1 -1
- package/src/components/calendar.tsx +48 -4
- package/src/components/callout.tsx +2 -2
- package/src/components/combobox.tsx +1 -1
- package/src/components/date-picker.tsx +43 -9
- package/src/components/description-list.tsx +107 -0
- package/src/components/locale.tsx +67 -0
- package/src/components/popover.tsx +3 -1
- package/src/components/progress.tsx +70 -4
- package/src/components/search-trigger.tsx +8 -2
- package/src/components/shimmer.tsx +36 -0
- package/src/components/spinner.tsx +126 -23
- package/src/components/stepper.tsx +346 -0
- package/src/components/tag-input.tsx +345 -0
- package/src/components/time-input.tsx +578 -0
- package/src/components/time-select.tsx +291 -0
- package/src/components/timeline.tsx +190 -0
- package/src/components/toast.tsx +4 -4
- package/src/components/tree.tsx +832 -0
- package/src/hooks/use-time-format.ts +72 -0
- package/src/lib/color.ts +19 -2
- package/src/lib/recipes.ts +7 -5
- package/src/styles/kernelkit.css +56 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { mergeProps } from "@base-ui/react/merge-props";
|
|
4
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
5
|
+
import { Spinner } from "@repraze/kernelkit/components/spinner";
|
|
6
|
+
import { focusRing } from "@repraze/kernelkit/lib/recipes";
|
|
7
|
+
import { cva } from "class-variance-authority";
|
|
8
|
+
import { cn } from "cn";
|
|
9
|
+
import { CheckIcon, SkipForwardIcon, XIcon } from "lucide-react";
|
|
10
|
+
import * as React from "react";
|
|
11
|
+
const StepperContext = React.createContext(null);
|
|
12
|
+
const StepperItemContext = React.createContext(null);
|
|
13
|
+
function useStepper() {
|
|
14
|
+
const ctx = React.useContext(StepperContext);
|
|
15
|
+
if (!ctx) {
|
|
16
|
+
throw new Error("Stepper parts must be used inside <Stepper>.");
|
|
17
|
+
}
|
|
18
|
+
return ctx;
|
|
19
|
+
}
|
|
20
|
+
function useStepperItem() {
|
|
21
|
+
const ctx = React.useContext(StepperItemContext);
|
|
22
|
+
if (!ctx) {
|
|
23
|
+
throw new Error("Stepper item parts must be used inside <StepperItem>.");
|
|
24
|
+
}
|
|
25
|
+
return ctx;
|
|
26
|
+
}
|
|
27
|
+
/** Data attributes every part carries, so each styles itself from its own state (§4). */
|
|
28
|
+
function itemState(item) {
|
|
29
|
+
return {
|
|
30
|
+
"data-state": item.state,
|
|
31
|
+
"data-orientation": item.orientation,
|
|
32
|
+
"data-error": item.error ? "" : undefined,
|
|
33
|
+
"data-loading": item.loading ? "" : undefined,
|
|
34
|
+
"data-disabled": item.disabled ? "" : undefined,
|
|
35
|
+
"data-skipped": item.skipped ? "" : undefined,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const stepperVariants = cva("flex", {
|
|
39
|
+
variants: {
|
|
40
|
+
orientation: {
|
|
41
|
+
horizontal: "w-full flex-row items-center gap-2",
|
|
42
|
+
vertical: "flex-col",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
defaultVariants: { orientation: "horizontal" },
|
|
46
|
+
});
|
|
47
|
+
/**
|
|
48
|
+
* A multi-step flow: numbered indicators joined by separators. Steps before the current one count as
|
|
49
|
+
* completed unless an item says otherwise. Arrow keys move focus between `StepperTrigger`s.
|
|
50
|
+
*/
|
|
51
|
+
function Stepper({ value, defaultValue = 1, onValueChange, orientation = "horizontal", className, onKeyDown, ...props }) {
|
|
52
|
+
const [inner, setInner] = React.useState(defaultValue);
|
|
53
|
+
const controlled = value !== undefined;
|
|
54
|
+
const current = controlled ? value : inner;
|
|
55
|
+
const setValue = React.useCallback((step) => {
|
|
56
|
+
if (!controlled) {
|
|
57
|
+
setInner(step);
|
|
58
|
+
}
|
|
59
|
+
onValueChange?.(step);
|
|
60
|
+
}, [controlled, onValueChange]);
|
|
61
|
+
const ctx = React.useMemo(() => ({ value: current, setValue, orientation }), [current, setValue, orientation]);
|
|
62
|
+
const handleKeyDown = (e) => {
|
|
63
|
+
onKeyDown?.(e);
|
|
64
|
+
const prev = orientation === "vertical" ? "ArrowUp" : "ArrowLeft";
|
|
65
|
+
const next = orientation === "vertical" ? "ArrowDown" : "ArrowRight";
|
|
66
|
+
if (e.defaultPrevented || ![prev, next, "Home", "End"].includes(e.key)) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const triggers = Array.from(e.currentTarget.querySelectorAll("[data-slot=stepper-trigger]:not(:disabled)")).filter((el) => el.closest("[data-slot=stepper]") === e.currentTarget);
|
|
70
|
+
const index = triggers.indexOf(document.activeElement);
|
|
71
|
+
if (index === -1) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
e.preventDefault();
|
|
75
|
+
const target = e.key === "Home"
|
|
76
|
+
? 0
|
|
77
|
+
: e.key === "End"
|
|
78
|
+
? triggers.length - 1
|
|
79
|
+
: (index + (e.key === next ? 1 : -1) + triggers.length) % triggers.length;
|
|
80
|
+
triggers[target]?.focus();
|
|
81
|
+
};
|
|
82
|
+
return (_jsx(StepperContext.Provider, { value: ctx, children: _jsx("ol", { "data-slot": "stepper", "data-orientation": orientation, "aria-orientation": orientation, className: cn(stepperVariants({ orientation }), className), onKeyDown: handleKeyDown, ...props }) }));
|
|
83
|
+
}
|
|
84
|
+
const stepperItemVariants = cva("group/stepper-item relative flex", {
|
|
85
|
+
variants: {
|
|
86
|
+
orientation: {
|
|
87
|
+
// every step but the last grows, so the separators share the free width
|
|
88
|
+
horizontal: "flex-1 items-center gap-2 last:flex-none",
|
|
89
|
+
// the separator hangs under the indicator; the padding is its length
|
|
90
|
+
vertical: "items-start gap-3 pb-6 last:pb-0",
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
defaultVariants: { orientation: "horizontal" },
|
|
94
|
+
});
|
|
95
|
+
function StepperItem({ step, completed, disabled = false, error = false, loading = false, skipped = false, className, ...props }) {
|
|
96
|
+
const { value, orientation } = useStepper();
|
|
97
|
+
const state = step === value ? "current" : skipped ? "upcoming" : (completed ?? step < value) ? "completed" : "upcoming";
|
|
98
|
+
const done = completed === true;
|
|
99
|
+
const item = React.useMemo(() => ({ step, state, error, loading, disabled, skipped, done, orientation }), [step, state, error, loading, disabled, skipped, done, orientation]);
|
|
100
|
+
// reached = the flow got here (completed, current or failed): the line leading into it fills
|
|
101
|
+
const reached = !skipped && (state !== "upcoming" || error || done);
|
|
102
|
+
return (_jsx(StepperItemContext.Provider, { value: item, children: _jsx("li", { "data-slot": "stepper-item", "data-reached": reached ? "" : undefined, ...itemState(item), className: cn(stepperItemVariants({ orientation }), className), ...props }) }));
|
|
103
|
+
}
|
|
104
|
+
/** Makes a step clickable: a button that sets the Stepper's value. Wraps the indicator and the text. */
|
|
105
|
+
function StepperTrigger({ className, render, onClick, ...props }) {
|
|
106
|
+
const { setValue } = useStepper();
|
|
107
|
+
const item = useStepperItem();
|
|
108
|
+
return useRender({
|
|
109
|
+
defaultTagName: "button",
|
|
110
|
+
props: mergeProps({
|
|
111
|
+
type: "button",
|
|
112
|
+
disabled: item.disabled,
|
|
113
|
+
"aria-current": item.state === "current" ? "step" : undefined,
|
|
114
|
+
className: cn("-m-1 flex min-w-0 items-center gap-2 rounded-md p-1 text-start transition-[color,background-color,box-shadow] duration-100 hover:bg-hover disabled:pointer-events-none disabled:opacity-50 motion-reduce:transition-none", "data-[orientation=vertical]:items-start data-[orientation=vertical]:gap-3", focusRing, className),
|
|
115
|
+
onClick: (e) => {
|
|
116
|
+
onClick?.(e);
|
|
117
|
+
if (!e.defaultPrevented) {
|
|
118
|
+
setValue(item.step);
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
...itemState(item),
|
|
122
|
+
}, props),
|
|
123
|
+
render,
|
|
124
|
+
state: { slot: "stepper-trigger" },
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
const stepperIndicatorVariants = cva([
|
|
128
|
+
"relative inline-flex size-6 shrink-0 items-center justify-center rounded-pill border font-alt text-xs font-medium tabular-nums transition-[color,background-color,border-color] duration-100 motion-reduce:transition-none [&_svg:not([class*='size-'])]:size-3.5",
|
|
129
|
+
// upcoming: a plain outlined number
|
|
130
|
+
"border-input bg-background text-muted-foreground",
|
|
131
|
+
// current: the solid accent fill
|
|
132
|
+
"data-[state=current]:border-primary data-[state=current]:bg-primary data-[state=current]:text-primary-foreground",
|
|
133
|
+
// completed: accent text tier, a check
|
|
134
|
+
"data-[state=completed]:border-primary-text data-[state=completed]:bg-primary-tint data-[state=completed]:text-primary-text",
|
|
135
|
+
// skipped: never ran, a dashed muted ring
|
|
136
|
+
"data-skipped:border-dashed data-skipped:border-input data-skipped:bg-background data-skipped:text-muted-foreground",
|
|
137
|
+
"data-[state=current]:data-skipped:border-foreground data-[state=current]:data-skipped:text-foreground",
|
|
138
|
+
// error outranks the step state; the selected failed step is the solid danger fill
|
|
139
|
+
"data-error:border-danger data-error:bg-danger-tint data-error:text-danger",
|
|
140
|
+
"data-[state=current]:data-error:border-(--tc-red-fill) data-[state=current]:data-error:bg-(--tc-red-fill) data-[state=current]:data-error:text-(--tc-red-on-fill)",
|
|
141
|
+
]);
|
|
142
|
+
/** The step's badge: its number, a check once completed, an X on error, a skip glyph, a spinner while loading. */
|
|
143
|
+
function StepperIndicator({ className, children, ...props }) {
|
|
144
|
+
const item = useStepperItem();
|
|
145
|
+
const content = item.loading ? (_jsx(Spinner, { size: "sm", "aria-label": "In progress" })) : item.error ? (_jsx(XIcon, { "aria-label": "Error" })) : item.skipped ? (_jsx(SkipForwardIcon, { "aria-label": "Skipped", className: "size-3" })) : item.state === "completed" || item.done ? (_jsx(CheckIcon, { "aria-label": "Completed" })) : ((children ?? item.step));
|
|
146
|
+
return (_jsx("span", { "data-slot": "stepper-indicator", ...itemState(item), className: cn(stepperIndicatorVariants(), className), ...props, children: content }));
|
|
147
|
+
}
|
|
148
|
+
function StepperTitle({ className, ...props }) {
|
|
149
|
+
const item = useStepperItem();
|
|
150
|
+
return (_jsx("span", { "data-slot": "stepper-title", ...itemState(item), className: cn("block truncate text-sm font-medium text-foreground not-data-error:data-[state=upcoming]:text-muted-foreground not-data-error:not-data-[state=current]:data-skipped:text-muted-foreground data-error:text-danger data-[orientation=vertical]:leading-6", className), ...props }));
|
|
151
|
+
}
|
|
152
|
+
function StepperDescription({ className, ...props }) {
|
|
153
|
+
const item = useStepperItem();
|
|
154
|
+
return (_jsx("span", { "data-slot": "stepper-description", ...itemState(item), className: cn("block text-xs text-muted-foreground", className), ...props }));
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* The line to the next step. Fills with the accent once the step it leads into has been reached
|
|
158
|
+
* (completed, current or failed); lines into skipped or upcoming steps stay plain. Leave it out of the last item.
|
|
159
|
+
*/
|
|
160
|
+
function StepperSeparator({ className, ...props }) {
|
|
161
|
+
const item = useStepperItem();
|
|
162
|
+
return (_jsx("span", { "data-slot": "stepper-separator", "aria-hidden": "true", ...itemState(item), className: cn("shrink-0 rounded-pill bg-border transition-colors duration-100 motion-reduce:transition-none [li:has(+[data-reached])>&]:bg-primary-text", "data-[orientation=horizontal]:h-0.5 data-[orientation=horizontal]:min-w-4 data-[orientation=horizontal]:flex-1",
|
|
163
|
+
// under the 24px indicator, centred on it, with a 4px gap at both ends
|
|
164
|
+
"data-[orientation=vertical]:absolute data-[orientation=vertical]:start-[calc(0.75rem-1px)] data-[orientation=vertical]:top-7 data-[orientation=vertical]:bottom-1 data-[orientation=vertical]:w-0.5", className), ...props }));
|
|
165
|
+
}
|
|
166
|
+
export { Stepper, StepperDescription, StepperIndicator, stepperIndicatorVariants, StepperItem, stepperItemVariants, StepperSeparator, StepperTitle, StepperTrigger, stepperVariants, useStepperItem, };
|
|
167
|
+
//# sourceMappingURL=stepper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stepper.js","sourceRoot":"","sources":["../../src/components/stepper.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Field that holds chips and a text input, the same surface as `ComboboxChips` (GUIDELINES §4, §6):
|
|
4
|
+
* focus rings the container when the inner input or a chip has keyboard focus.
|
|
5
|
+
*/
|
|
6
|
+
declare const tagInputVariants: (props?: ({
|
|
7
|
+
size?: "default" | "sm" | "lg" | null | undefined;
|
|
8
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
9
|
+
/** One tag: the `ComboboxChip` look. Keyboard focus (arrows, Backspace on an empty input) rings it. */
|
|
10
|
+
declare const tagInputChipVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
11
|
+
type Size = "sm" | "default" | "lg";
|
|
12
|
+
interface TagInputProps extends Omit<React.ComponentProps<"input">, "value" | "defaultValue" | "size" | "onChange" | "type" | "max"> {
|
|
13
|
+
value?: string[];
|
|
14
|
+
defaultValue?: string[];
|
|
15
|
+
onValueChange?: (tags: string[]) => void;
|
|
16
|
+
/** Keys that commit the typed text as a tag. */
|
|
17
|
+
separators?: string[];
|
|
18
|
+
/** Splits pasted text into several tags. */
|
|
19
|
+
delimiter?: string | RegExp;
|
|
20
|
+
/** Most tags allowed; extra ones are ignored. */
|
|
21
|
+
max?: number;
|
|
22
|
+
allowDuplicates?: boolean;
|
|
23
|
+
/** `false` rejects silently, a string rejects with that message (`onValidationError`). */
|
|
24
|
+
validate?: (tag: string) => boolean | string;
|
|
25
|
+
/** Called with the rejection message, then `null` once the text changes or a tag is added. */
|
|
26
|
+
onValidationError?: (message: string | null) => void;
|
|
27
|
+
/** Commit the pending text when the input loses focus. */
|
|
28
|
+
addOnBlur?: boolean;
|
|
29
|
+
size?: Size;
|
|
30
|
+
/** Classes for the inner `<input>` (`className` goes on the field). */
|
|
31
|
+
inputClassName?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A field of free-form tags. Enter or comma adds the typed text, a paste splits on commas, newlines and
|
|
35
|
+
* tabs. Backspace in an empty input focuses the last tag, a second press removes it; arrows move between
|
|
36
|
+
* tags, Delete / Backspace removes the focused one.
|
|
37
|
+
*/
|
|
38
|
+
declare function TagInput({ value, defaultValue, onValueChange, separators, delimiter, max, allowDuplicates, validate, onValidationError, addOnBlur, size, disabled, name, placeholder, className, inputClassName, onKeyDown, onPaste, onBlur, ref, "aria-invalid": ariaInvalid, ...inputProps }: TagInputProps): React.JSX.Element;
|
|
39
|
+
interface TagInputChipProps extends React.ComponentProps<"li"> {
|
|
40
|
+
/** Shows the × button. */
|
|
41
|
+
onRemove?: () => void;
|
|
42
|
+
}
|
|
43
|
+
/** A tag chip. Usable on its own for read-only tag lists. */
|
|
44
|
+
declare function TagInputChip({ className, children, onRemove, ...props }: TagInputChipProps): React.JSX.Element;
|
|
45
|
+
export { TagInput, TagInputChip, tagInputChipVariants, tagInputVariants };
|
|
46
|
+
export type { TagInputChipProps, TagInputProps };
|
|
47
|
+
//# sourceMappingURL=tag-input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tag-input.d.ts","sourceRoot":"","sources":["../../src/components/tag-input.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B;;;GAGG;AACH,QAAA,MAAM,gBAAgB;;8EAoBrB,CAAC;AAEF,uGAAuG;AACvG,QAAA,MAAM,oBAAoB,oFAEzB,CAAC;AAEF,KAAK,IAAI,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAAC;AAkBpC,UAAU,aAAc,SAAQ,IAAI,CAChC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,EAC7B,OAAO,GAAG,cAAc,GAAG,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,KAAK,CAClE;IACG,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACzC,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,iDAAiD;IACjD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,GAAG,MAAM,CAAC;IAC7C,8FAA8F;IAC9F,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACrD,0DAA0D;IAC1D,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;GAIG;AACH,iBAAS,QAAQ,CAAC,EACd,KAAK,EACL,YAAiB,EACjB,aAAa,EACb,UAA2B,EAC3B,SAAqB,EACrB,GAAG,EACH,eAAuB,EACvB,QAAQ,EACR,iBAAiB,EACjB,SAAiB,EACjB,IAAgB,EAChB,QAAQ,EACR,IAAI,EACJ,WAAW,EACX,SAAS,EACT,cAAc,EACd,SAAS,EACT,OAAO,EACP,MAAM,EACN,GAAG,EACH,cAAc,EAAE,WAAW,EAC3B,GAAG,UAAU,EAChB,EAAE,aAAa,qBA4Mf;AAED,UAAU,iBAAkB,SAAQ,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC;IAC1D,0BAA0B;IAC1B,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,6DAA6D;AAC7D,iBAAS,YAAY,CAAC,EAAC,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAC,EAAE,iBAAiB,qBAmBjF;AAED,OAAO,EAAC,QAAQ,EAAE,YAAY,EAAE,oBAAoB,EAAE,gBAAgB,EAAC,CAAC;AACxE,YAAY,EAAC,iBAAiB,EAAE,aAAa,EAAC,CAAC"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { fieldSurface } from "@repraze/kernelkit/lib/recipes";
|
|
4
|
+
import { cva } from "class-variance-authority";
|
|
5
|
+
import { cn } from "cn";
|
|
6
|
+
import { XIcon } from "lucide-react";
|
|
7
|
+
import * as React from "react";
|
|
8
|
+
/**
|
|
9
|
+
* Field that holds chips and a text input, the same surface as `ComboboxChips` (GUIDELINES §4, §6):
|
|
10
|
+
* focus rings the container when the inner input or a chip has keyboard focus.
|
|
11
|
+
*/
|
|
12
|
+
const tagInputVariants = cva([
|
|
13
|
+
fieldSurface,
|
|
14
|
+
"flex w-full min-w-0 cursor-text flex-wrap items-center gap-1 bg-clip-padding text-base md:text-sm",
|
|
15
|
+
"has-[:focus-visible]:border-ring has-[:focus-visible]:ring-3 has-[:focus-visible]:ring-ring/50",
|
|
16
|
+
"aria-invalid:border-danger aria-invalid:ring-3 aria-invalid:ring-danger/20 dark:aria-invalid:ring-danger/40",
|
|
17
|
+
"has-[input[aria-invalid=true]]:border-danger has-[input[aria-invalid=true]]:ring-3 has-[input[aria-invalid=true]]:ring-danger/20 dark:has-[input[aria-invalid=true]]:ring-danger/40",
|
|
18
|
+
"data-disabled:cursor-not-allowed data-disabled:bg-field-disabled data-disabled:opacity-50",
|
|
19
|
+
], {
|
|
20
|
+
variants: {
|
|
21
|
+
// Heights match Input (§4); a chip row adds 4px per line when it wraps.
|
|
22
|
+
size: {
|
|
23
|
+
sm: "min-h-7 rounded-md px-2 py-0.5 has-data-[slot=tag-input-chip]:px-0.5 md:text-[0.8rem]",
|
|
24
|
+
default: "min-h-8 px-2.5 py-1 has-data-[slot=tag-input-chip]:px-1",
|
|
25
|
+
lg: "min-h-9 px-3 py-1.5 has-data-[slot=tag-input-chip]:px-1.5",
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
defaultVariants: { size: "default" },
|
|
29
|
+
});
|
|
30
|
+
/** One tag: the `ComboboxChip` look. Keyboard focus (arrows, Backspace on an empty input) rings it. */
|
|
31
|
+
const tagInputChipVariants = cva("flex h-5.5 w-fit min-w-0 items-center gap-1 rounded-md border border-border bg-foreground/10 px-1.5 text-xs font-medium whitespace-nowrap text-foreground hc:bg-transparent outline-none transition-[border-color,box-shadow] focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/50 has-data-[slot=tag-input-chip-remove]:pe-0");
|
|
32
|
+
function useControllable(value, defaultValue, onChange) {
|
|
33
|
+
const [inner, setInner] = React.useState(defaultValue);
|
|
34
|
+
const controlled = value !== undefined;
|
|
35
|
+
const current = controlled ? value : inner;
|
|
36
|
+
const set = React.useCallback((next) => {
|
|
37
|
+
if (!controlled) {
|
|
38
|
+
setInner(next);
|
|
39
|
+
}
|
|
40
|
+
onChange?.(next);
|
|
41
|
+
}, [controlled, onChange]);
|
|
42
|
+
return [current, set];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A field of free-form tags. Enter or comma adds the typed text, a paste splits on commas, newlines and
|
|
46
|
+
* tabs. Backspace in an empty input focuses the last tag, a second press removes it; arrows move between
|
|
47
|
+
* tags, Delete / Backspace removes the focused one.
|
|
48
|
+
*/
|
|
49
|
+
function TagInput({ value, defaultValue = [], onValueChange, separators = ["Enter", ","], delimiter = /[,\n\t]/, max, allowDuplicates = false, validate, onValidationError, addOnBlur = false, size = "default", disabled, name, placeholder, className, inputClassName, onKeyDown, onPaste, onBlur, ref, "aria-invalid": ariaInvalid, ...inputProps }) {
|
|
50
|
+
const [tags, setTags] = useControllable(value, defaultValue, onValueChange);
|
|
51
|
+
const [text, setText] = React.useState("");
|
|
52
|
+
const [error, setError] = React.useState(null);
|
|
53
|
+
const inputRef = React.useRef(null);
|
|
54
|
+
const chipRefs = React.useRef([]);
|
|
55
|
+
const full = max !== undefined && tags.length >= max;
|
|
56
|
+
React.useImperativeHandle(ref, () => inputRef.current);
|
|
57
|
+
const report = (message) => {
|
|
58
|
+
setError(message);
|
|
59
|
+
onValidationError?.(message);
|
|
60
|
+
};
|
|
61
|
+
/** Adds what passes; returns the parts that did not (kept in the input). */
|
|
62
|
+
const add = (candidates) => {
|
|
63
|
+
const next = [...tags];
|
|
64
|
+
const rejected = [];
|
|
65
|
+
let message = null;
|
|
66
|
+
for (const raw of candidates) {
|
|
67
|
+
const tag = raw.trim();
|
|
68
|
+
if (!tag) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (max !== undefined && next.length >= max) {
|
|
72
|
+
rejected.push(tag);
|
|
73
|
+
message ??= `At most ${max} tags.`;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (!allowDuplicates && next.includes(tag)) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const verdict = validate?.(tag) ?? true;
|
|
80
|
+
if (verdict !== true) {
|
|
81
|
+
rejected.push(tag);
|
|
82
|
+
if (typeof verdict === "string") {
|
|
83
|
+
message ??= verdict;
|
|
84
|
+
}
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
next.push(tag);
|
|
88
|
+
}
|
|
89
|
+
if (next.length !== tags.length) {
|
|
90
|
+
setTags(next);
|
|
91
|
+
}
|
|
92
|
+
report(message);
|
|
93
|
+
return rejected;
|
|
94
|
+
};
|
|
95
|
+
const commit = () => {
|
|
96
|
+
if (!text.trim()) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const rejected = add([text]);
|
|
100
|
+
setText(rejected.join(", "));
|
|
101
|
+
};
|
|
102
|
+
const remove = (index, focusAfter = "input") => {
|
|
103
|
+
setTags(tags.filter((_, i) => i !== index));
|
|
104
|
+
report(null);
|
|
105
|
+
const target = focusAfter === "prev" ? index - 1 : index;
|
|
106
|
+
requestAnimationFrame(() => {
|
|
107
|
+
const chip = focusAfter !== "input" && target >= 0 ? chipRefs.current[target] : null;
|
|
108
|
+
// the list shrank by one: `index` now points at what was the next chip
|
|
109
|
+
if (chip && target < tags.length - 1) {
|
|
110
|
+
chip.focus();
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
inputRef.current?.focus();
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
const onInputKeyDown = (e) => {
|
|
118
|
+
onKeyDown?.(e);
|
|
119
|
+
if (e.defaultPrevented || e.nativeEvent.isComposing) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const el = e.currentTarget;
|
|
123
|
+
if (separators.includes(e.key)) {
|
|
124
|
+
if (text.trim() || e.key !== "Enter") {
|
|
125
|
+
e.preventDefault();
|
|
126
|
+
}
|
|
127
|
+
commit();
|
|
128
|
+
}
|
|
129
|
+
else if (e.key === "Backspace" && el.selectionStart === 0 && el.selectionEnd === 0 && tags.length) {
|
|
130
|
+
e.preventDefault();
|
|
131
|
+
chipRefs.current[tags.length - 1]?.focus();
|
|
132
|
+
}
|
|
133
|
+
else if (e.key === "ArrowLeft" && el.selectionStart === 0 && el.selectionEnd === 0 && tags.length) {
|
|
134
|
+
e.preventDefault();
|
|
135
|
+
chipRefs.current[tags.length - 1]?.focus();
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
const onChipKeyDown = (e, index) => {
|
|
139
|
+
const rtl = getComputedStyle(e.currentTarget).direction === "rtl";
|
|
140
|
+
const prev = rtl ? "ArrowRight" : "ArrowLeft";
|
|
141
|
+
const next = rtl ? "ArrowLeft" : "ArrowRight";
|
|
142
|
+
if (e.key === prev) {
|
|
143
|
+
e.preventDefault();
|
|
144
|
+
chipRefs.current[Math.max(0, index - 1)]?.focus();
|
|
145
|
+
}
|
|
146
|
+
else if (e.key === next) {
|
|
147
|
+
e.preventDefault();
|
|
148
|
+
(chipRefs.current[index + 1] ?? inputRef.current)?.focus();
|
|
149
|
+
}
|
|
150
|
+
else if (e.key === "Home") {
|
|
151
|
+
e.preventDefault();
|
|
152
|
+
chipRefs.current[0]?.focus();
|
|
153
|
+
}
|
|
154
|
+
else if (e.key === "End" || e.key === "Escape") {
|
|
155
|
+
e.preventDefault();
|
|
156
|
+
inputRef.current?.focus();
|
|
157
|
+
}
|
|
158
|
+
else if (e.key === "Backspace") {
|
|
159
|
+
e.preventDefault();
|
|
160
|
+
remove(index, index > 0 ? "prev" : "next");
|
|
161
|
+
}
|
|
162
|
+
else if (e.key === "Delete") {
|
|
163
|
+
e.preventDefault();
|
|
164
|
+
remove(index, "next");
|
|
165
|
+
}
|
|
166
|
+
else if (e.key.length === 1 && !e.metaKey && !e.ctrlKey && !e.altKey) {
|
|
167
|
+
// typing on a chip goes back to the input
|
|
168
|
+
inputRef.current?.focus();
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
const onInputPaste = (e) => {
|
|
172
|
+
onPaste?.(e);
|
|
173
|
+
if (e.defaultPrevented) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const pasted = e.clipboardData.getData("text");
|
|
177
|
+
const parts = pasted.split(delimiter);
|
|
178
|
+
if (parts.length < 2) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
e.preventDefault();
|
|
182
|
+
const rejected = add([text + parts[0], ...parts.slice(1)]);
|
|
183
|
+
setText(rejected.join(", "));
|
|
184
|
+
};
|
|
185
|
+
const invalid = ariaInvalid === true || ariaInvalid === "true" || error !== null;
|
|
186
|
+
return (_jsxs("div", { "data-slot": "tag-input", "data-size": size, "data-disabled": disabled ? "" : undefined, "data-full": full ? "" : undefined, className: cn(tagInputVariants({ size }), className), onMouseDown: (e) => {
|
|
187
|
+
// clicks on the field's padding focus the input, like a native field
|
|
188
|
+
if (e.target === e.currentTarget && !disabled) {
|
|
189
|
+
e.preventDefault();
|
|
190
|
+
inputRef.current?.focus();
|
|
191
|
+
}
|
|
192
|
+
}, children: [tags.length > 0 && (_jsx("ul", { "data-slot": "tag-input-list", "aria-label": "Tags", className: "contents", children: tags.map((tag, i) => (_jsx(TagInputChip, { ref: (el) => {
|
|
193
|
+
chipRefs.current[i] = el;
|
|
194
|
+
}, tabIndex: -1, onKeyDown: (e) => onChipKeyDown(e, i), onRemove: disabled ? undefined : () => remove(i), children: tag }, `${tag}-${i}`))) })), _jsx("input", { ref: inputRef, "data-slot": "tag-input-input", type: "text", disabled: disabled, "aria-invalid": invalid || undefined, enterKeyHint: "enter", autoComplete: "off", placeholder: tags.length ? undefined : placeholder, value: text, onChange: (e) => {
|
|
195
|
+
setText(e.target.value);
|
|
196
|
+
if (error) {
|
|
197
|
+
report(null);
|
|
198
|
+
}
|
|
199
|
+
}, onKeyDown: onInputKeyDown, onPaste: onInputPaste, onBlur: (e) => {
|
|
200
|
+
onBlur?.(e);
|
|
201
|
+
if (addOnBlur) {
|
|
202
|
+
commit();
|
|
203
|
+
}
|
|
204
|
+
}, className: cn("h-5.5 min-w-16 flex-1 bg-transparent outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed", tags.length > 0 && "ps-1", inputClassName), ...inputProps }), name && tags.map((tag, i) => _jsx("input", { type: "hidden", name: name, value: tag }, i))] }));
|
|
205
|
+
}
|
|
206
|
+
/** A tag chip. Usable on its own for read-only tag lists. */
|
|
207
|
+
function TagInputChip({ className, children, onRemove, ...props }) {
|
|
208
|
+
return (_jsxs("li", { "data-slot": "tag-input-chip", className: cn(tagInputChipVariants(), className), ...props, children: [_jsx("span", { className: "truncate", children: children }), onRemove && (_jsx("button", { type: "button", "data-slot": "tag-input-chip-remove", tabIndex: -1, "aria-label": typeof children === "string" ? `Remove ${children}` : "Remove", onMouseDown: (e) => e.preventDefault(), onClick: onRemove, className: "-ms-0.5 flex size-5 shrink-0 items-center justify-center rounded-box text-muted-foreground transition-[color,background-color] hover:bg-hover hover:text-foreground [&_svg]:size-3", children: _jsx(XIcon, { className: "pointer-events-none" }) }))] }));
|
|
209
|
+
}
|
|
210
|
+
export { TagInput, TagInputChip, tagInputChipVariants, tagInputVariants };
|
|
211
|
+
//# sourceMappingURL=tag-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tag-input.js","sourceRoot":"","sources":["../../src/components/tag-input.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { type HourCyclePreference } from "@repraze/kernelkit/hooks/use-time-format";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
/**
|
|
4
|
+
* Segmented time field (GUIDELINES §4, §6). The container is the field surface; it rings while any
|
|
5
|
+
* segment has focus, like a text input does on click.
|
|
6
|
+
*/
|
|
7
|
+
declare const timeInputVariants: (props?: ({
|
|
8
|
+
size?: "default" | "sm" | "lg" | null | undefined;
|
|
9
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
10
|
+
/** One editable part (hours, minutes, seconds, AM/PM). Focus is a solid accent chip, like a native text selection (a tint vanished on the dark field). */
|
|
11
|
+
declare const timeInputSegmentVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
12
|
+
type Size = "sm" | "default" | "lg";
|
|
13
|
+
type Period = "AM" | "PM";
|
|
14
|
+
interface Segments {
|
|
15
|
+
hour: number | null;
|
|
16
|
+
minute: number | null;
|
|
17
|
+
second: number | null;
|
|
18
|
+
period: Period | null;
|
|
19
|
+
}
|
|
20
|
+
declare function parse(value: string | null | undefined, cycle: 12 | 24): Segments;
|
|
21
|
+
declare function serialize(s: Segments, cycle: 12 | 24, seconds: boolean): string | null;
|
|
22
|
+
interface TimeInputProps extends Omit<React.ComponentProps<"div">, "defaultValue" | "onChange" | "children" | "color"> {
|
|
23
|
+
/** 24-hour `"HH:mm"` (or `"HH:mm:ss"` with `seconds`); `null` while incomplete. */
|
|
24
|
+
value?: string | null;
|
|
25
|
+
defaultValue?: string | null;
|
|
26
|
+
/** Fires with the full time once every segment is set, `null` when one is cleared. */
|
|
27
|
+
onValueChange?: (value: string | null) => void;
|
|
28
|
+
/** Adds a seconds segment. */
|
|
29
|
+
seconds?: boolean;
|
|
30
|
+
/** `"auto"` follows the user's locale; 12 adds a day-period segment. The value stays 24-hour. */
|
|
31
|
+
hourCycle?: HourCyclePreference;
|
|
32
|
+
/** BCP 47 locale for `"auto"` and the day-period labels; defaults to the browser's. */
|
|
33
|
+
locale?: string;
|
|
34
|
+
/** Minutes per arrow press. */
|
|
35
|
+
step?: number;
|
|
36
|
+
size?: Size;
|
|
37
|
+
disabled?: boolean;
|
|
38
|
+
/** Leading clock icon. */
|
|
39
|
+
icon?: boolean;
|
|
40
|
+
/** The clock icon opens a column picker (hours, minutes...) in a popover: tap and arrow-key friendly. */
|
|
41
|
+
picker?: boolean;
|
|
42
|
+
/** Form field name: a hidden input carries the value. */
|
|
43
|
+
name?: string;
|
|
44
|
+
/** Lands on the first segment, so `<FieldLabel htmlFor>` focuses it. */
|
|
45
|
+
id?: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* A time field split into segments, each a spinbutton: arrows step with wrap, digits fill and move on,
|
|
49
|
+
* Backspace clears, Left / Right (or `:`) move between segments, `a` / `p` set the period.
|
|
50
|
+
*/
|
|
51
|
+
declare function TimeInput({ value, defaultValue, onValueChange, seconds, hourCycle: hourCyclePreference, locale, step, size, disabled, icon, picker, name, id, className, ...props }: TimeInputProps): React.JSX.Element;
|
|
52
|
+
/** A column of the picker: a listbox of option buttons, scrolled so the selected one sits in the middle. */
|
|
53
|
+
declare const timeColumnsOptionVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
54
|
+
interface TimeColumnsProps extends Omit<React.ComponentProps<"div">, "defaultValue" | "onChange" | "children"> {
|
|
55
|
+
/** 24-hour `"HH:mm"` / `"HH:mm:ss"`; `null` shows no selection until a pick fills the rest with zeros. */
|
|
56
|
+
value: string | null;
|
|
57
|
+
onValueChange: (value: string) => void;
|
|
58
|
+
/** Enter in a column (close a popover). */
|
|
59
|
+
onCommit?: () => void;
|
|
60
|
+
seconds?: boolean;
|
|
61
|
+
/** `"auto"` follows the user's locale. */
|
|
62
|
+
hourCycle?: HourCyclePreference;
|
|
63
|
+
locale?: string;
|
|
64
|
+
/** Minutes between options. */
|
|
65
|
+
step?: number;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Hours | minutes | (seconds) | (AM/PM) as scrollable listboxes. A click or tap picks; ↑↓ / Home / End
|
|
69
|
+
* pick within a column, ← → move between columns, Enter commits. Every pick fires `onValueChange` with a
|
|
70
|
+
* full time. Embed it in a popover (TimeInput does) or inline.
|
|
71
|
+
*/
|
|
72
|
+
declare function TimeColumns({ value, onValueChange, onCommit, seconds, hourCycle: hourCyclePreference, locale, step, className, ...props }: TimeColumnsProps): React.JSX.Element;
|
|
73
|
+
export { parse as parseTime, serialize as serializeTime, TimeColumns, timeColumnsOptionVariants, TimeInput, timeInputSegmentVariants, timeInputVariants, };
|
|
74
|
+
export type { TimeColumnsProps, TimeInputProps };
|
|
75
|
+
//# sourceMappingURL=time-input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time-input.d.ts","sourceRoot":"","sources":["../../src/components/time-input.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAC,KAAK,mBAAmB,EAAgB,MAAM,0CAA0C,CAAC;AAKjG,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B;;;GAGG;AACH,QAAA,MAAM,iBAAiB;;8EAqBtB,CAAC;AAEF,0JAA0J;AAC1J,QAAA,MAAM,wBAAwB,oFAE7B,CAAC;AAEF,KAAK,IAAI,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAAC;AACpC,KAAK,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;AAG1B,UAAU,QAAQ;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAMD,iBAAS,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,GAAG,QAAQ,CAYzE;AAED,iBAAS,SAAS,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAM/E;AAED,UAAU,cAAe,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,cAAc,GAAG,UAAU,GAAG,UAAU,GAAG,OAAO,CAAC;IAClH,mFAAmF;IACnF,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,sFAAsF;IACtF,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC/C,8BAA8B;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iGAAiG;IACjG,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC,uFAAuF;IACvF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,0BAA0B;IAC1B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,yGAAyG;IACzG,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yDAAyD;IACzD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,EAAE,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,iBAAS,SAAS,CAAC,EACf,KAAK,EACL,YAAmB,EACnB,aAAa,EACb,OAAe,EACf,SAAS,EAAE,mBAA4B,EACvC,MAAM,EACN,IAAQ,EACR,IAAgB,EAChB,QAAgB,EAChB,IAAW,EACX,MAAa,EACb,IAAI,EACJ,EAAE,EACF,SAAS,EACT,GAAG,KAAK,EACX,EAAE,cAAc,qBA2OhB;AAmBD,4GAA4G;AAC5G,QAAA,MAAM,yBAAyB,oFAM7B,CAAC;AAEH,UAAU,gBAAiB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,cAAc,GAAG,UAAU,GAAG,UAAU,CAAC;IAC1G,0GAA0G;IAC1G,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,iBAAS,WAAW,CAAC,EACjB,KAAK,EACL,aAAa,EACb,QAAQ,EACR,OAAe,EACf,SAAS,EAAE,mBAA4B,EACvC,MAAM,EACN,IAAQ,EACR,SAAS,EACT,GAAG,KAAK,EACX,EAAE,gBAAgB,qBAqJlB;AAED,OAAO,EACH,KAAK,IAAI,SAAS,EAClB,SAAS,IAAI,aAAa,EAC1B,WAAW,EACX,yBAAyB,EACzB,SAAS,EACT,wBAAwB,EACxB,iBAAiB,GACpB,CAAC;AACF,YAAY,EAAC,gBAAgB,EAAE,cAAc,EAAC,CAAC"}
|