@gouno/ui 0.3.2
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/CHANGELOG.md +120 -0
- package/LICENSE +21 -0
- package/README.md +144 -0
- package/dist/base.css +239 -0
- package/dist/bootstrap.js +22 -0
- package/dist/components/primitives/alert-dialog.d.ts +18 -0
- package/dist/components/primitives/alert-dialog.js +43 -0
- package/dist/components/primitives/alert.d.ts +9 -0
- package/dist/components/primitives/alert.js +25 -0
- package/dist/components/primitives/avatar.d.ts +14 -0
- package/dist/components/primitives/avatar.js +42 -0
- package/dist/components/primitives/badge.d.ts +9 -0
- package/dist/components/primitives/badge.js +25 -0
- package/dist/components/primitives/button.d.ts +10 -0
- package/dist/components/primitives/button.js +36 -0
- package/dist/components/primitives/checkbox.d.ts +4 -0
- package/dist/components/primitives/checkbox.js +10 -0
- package/dist/components/primitives/dialog.d.ts +20 -0
- package/dist/components/primitives/dialog.js +37 -0
- package/dist/components/primitives/dropdown-menu.d.ts +25 -0
- package/dist/components/primitives/dropdown-menu.js +51 -0
- package/dist/components/primitives/empty.d.ts +11 -0
- package/dist/components/primitives/empty.js +33 -0
- package/dist/components/primitives/field.d.ts +24 -0
- package/dist/components/primitives/field.js +75 -0
- package/dist/components/primitives/input.d.ts +3 -0
- package/dist/components/primitives/input.js +7 -0
- package/dist/components/primitives/label.d.ts +4 -0
- package/dist/components/primitives/label.js +8 -0
- package/dist/components/primitives/popover.d.ts +16 -0
- package/dist/components/primitives/popover.js +31 -0
- package/dist/components/primitives/radio-group.d.ts +5 -0
- package/dist/components/primitives/radio-group.js +13 -0
- package/dist/components/primitives/select.d.ts +15 -0
- package/dist/components/primitives/select.js +38 -0
- package/dist/components/primitives/separator.d.ts +4 -0
- package/dist/components/primitives/separator.js +8 -0
- package/dist/components/primitives/sheet.d.ts +17 -0
- package/dist/components/primitives/sheet.js +41 -0
- package/dist/components/primitives/skeleton.d.ts +2 -0
- package/dist/components/primitives/skeleton.js +6 -0
- package/dist/components/primitives/switch.d.ts +6 -0
- package/dist/components/primitives/switch.js +8 -0
- package/dist/components/primitives/table.d.ts +28 -0
- package/dist/components/primitives/table.js +44 -0
- package/dist/components/primitives/tabs.d.ts +11 -0
- package/dist/components/primitives/tabs.js +30 -0
- package/dist/components/primitives/textarea.d.ts +3 -0
- package/dist/components/primitives/textarea.js +7 -0
- package/dist/components/primitives/tooltip.d.ts +13 -0
- package/dist/components/primitives/tooltip.js +24 -0
- package/dist/core/affix.d.ts +14 -0
- package/dist/core/affix.js +29 -0
- package/dist/core/alert.d.ts +54 -0
- package/dist/core/alert.js +56 -0
- package/dist/core/anchor.d.ts +16 -0
- package/dist/core/anchor.js +31 -0
- package/dist/core/app.d.ts +5 -0
- package/dist/core/app.js +5 -0
- package/dist/core/aspect-ratio.d.ts +6 -0
- package/dist/core/aspect-ratio.js +6 -0
- package/dist/core/autocomplete.d.ts +24 -0
- package/dist/core/autocomplete.js +139 -0
- package/dist/core/avatar.d.ts +26 -0
- package/dist/core/avatar.js +20 -0
- package/dist/core/badge.d.ts +16 -0
- package/dist/core/badge.js +22 -0
- package/dist/core/breadcrumb.d.ts +55 -0
- package/dist/core/breadcrumb.js +69 -0
- package/dist/core/button.d.ts +49 -0
- package/dist/core/button.js +66 -0
- package/dist/core/calendar.d.ts +48 -0
- package/dist/core/calendar.js +179 -0
- package/dist/core/card.d.ts +30 -0
- package/dist/core/card.js +12 -0
- package/dist/core/carousel.d.ts +49 -0
- package/dist/core/carousel.js +166 -0
- package/dist/core/cascader.d.ts +19 -0
- package/dist/core/cascader.js +45 -0
- package/dist/core/code-block.d.ts +16 -0
- package/dist/core/code-block.js +47 -0
- package/dist/core/collapse.d.ts +49 -0
- package/dist/core/collapse.js +96 -0
- package/dist/core/color-picker.d.ts +9 -0
- package/dist/core/color-picker.js +8 -0
- package/dist/core/config-provider.d.ts +10 -0
- package/dist/core/config-provider.js +14 -0
- package/dist/core/control-types.d.ts +2 -0
- package/dist/core/control-types.js +7 -0
- package/dist/core/date-picker.d.ts +13 -0
- package/dist/core/date-picker.js +14 -0
- package/dist/core/date-range-picker.d.ts +26 -0
- package/dist/core/date-range-picker.js +10 -0
- package/dist/core/descriptions.d.ts +41 -0
- package/dist/core/descriptions.js +133 -0
- package/dist/core/drawer.d.ts +9 -0
- package/dist/core/drawer.js +58 -0
- package/dist/core/empty.d.ts +8 -0
- package/dist/core/empty.js +5 -0
- package/dist/core/feedback.d.ts +5 -0
- package/dist/core/feedback.js +5 -0
- package/dist/core/field.d.ts +15 -0
- package/dist/core/field.js +19 -0
- package/dist/core/float-button.d.ts +13 -0
- package/dist/core/float-button.js +22 -0
- package/dist/core/form.d.ts +19 -0
- package/dist/core/form.js +56 -0
- package/dist/core/icon-button.d.ts +7 -0
- package/dist/core/icon-button.js +4 -0
- package/dist/core/icon.d.ts +17 -0
- package/dist/core/icon.js +35 -0
- package/dist/core/image.d.ts +76 -0
- package/dist/core/image.js +189 -0
- package/dist/core/index.d.ts +79 -0
- package/dist/core/index.js +77 -0
- package/dist/core/input-number.d.ts +24 -0
- package/dist/core/input-number.js +70 -0
- package/dist/core/input-otp.d.ts +14 -0
- package/dist/core/input-otp.js +76 -0
- package/dist/core/input.d.ts +14 -0
- package/dist/core/input.js +51 -0
- package/dist/core/kbd.d.ts +8 -0
- package/dist/core/kbd.js +11 -0
- package/dist/core/layout-primitives.d.ts +11 -0
- package/dist/core/layout-primitives.js +8 -0
- package/dist/core/layout.d.ts +71 -0
- package/dist/core/layout.js +119 -0
- package/dist/core/list.d.ts +37 -0
- package/dist/core/list.js +35 -0
- package/dist/core/locale.d.ts +48 -0
- package/dist/core/locale.js +32 -0
- package/dist/core/mentions.d.ts +10 -0
- package/dist/core/mentions.js +112 -0
- package/dist/core/menu.d.ts +79 -0
- package/dist/core/menu.js +265 -0
- package/dist/core/message.d.ts +16 -0
- package/dist/core/message.js +36 -0
- package/dist/core/modal.d.ts +40 -0
- package/dist/core/modal.js +67 -0
- package/dist/core/notification.d.ts +15 -0
- package/dist/core/notification.js +39 -0
- package/dist/core/page-layout.d.ts +6 -0
- package/dist/core/page-layout.js +7 -0
- package/dist/core/pagination.d.ts +28 -0
- package/dist/core/pagination.js +69 -0
- package/dist/core/popconfirm.d.ts +13 -0
- package/dist/core/popconfirm.js +42 -0
- package/dist/core/progress.d.ts +6 -0
- package/dist/core/progress.js +8 -0
- package/dist/core/public-props.d.ts +82 -0
- package/dist/core/public-props.js +1 -0
- package/dist/core/qrcode.d.ts +14 -0
- package/dist/core/qrcode.js +17 -0
- package/dist/core/rate.d.ts +11 -0
- package/dist/core/rate.js +48 -0
- package/dist/core/result.d.ts +12 -0
- package/dist/core/result.js +19 -0
- package/dist/core/segmented.d.ts +29 -0
- package/dist/core/segmented.js +38 -0
- package/dist/core/select.d.ts +27 -0
- package/dist/core/select.js +143 -0
- package/dist/core/selection-controls.d.ts +12 -0
- package/dist/core/selection-controls.js +23 -0
- package/dist/core/separator.d.ts +24 -0
- package/dist/core/separator.js +17 -0
- package/dist/core/slider.d.ts +2 -0
- package/dist/core/slider.js +6 -0
- package/dist/core/spin.d.ts +7 -0
- package/dist/core/spin.js +7 -0
- package/dist/core/spinner.d.ts +3 -0
- package/dist/core/spinner.js +6 -0
- package/dist/core/splitter.d.ts +44 -0
- package/dist/core/splitter.js +208 -0
- package/dist/core/statistic.d.ts +12 -0
- package/dist/core/statistic.js +6 -0
- package/dist/core/steps.d.ts +54 -0
- package/dist/core/steps.js +106 -0
- package/dist/core/tabs.d.ts +40 -0
- package/dist/core/tabs.js +80 -0
- package/dist/core/tag.d.ts +19 -0
- package/dist/core/tag.js +29 -0
- package/dist/core/textarea.d.ts +8 -0
- package/dist/core/textarea.js +14 -0
- package/dist/core/time-picker.d.ts +9 -0
- package/dist/core/time-picker.js +8 -0
- package/dist/core/timeline.d.ts +37 -0
- package/dist/core/timeline.js +48 -0
- package/dist/core/tour.d.ts +18 -0
- package/dist/core/tour.js +51 -0
- package/dist/core/transfer.d.ts +16 -0
- package/dist/core/transfer.js +46 -0
- package/dist/core/tree-select.d.ts +19 -0
- package/dist/core/tree-select.js +19 -0
- package/dist/core/tree.d.ts +89 -0
- package/dist/core/tree.js +386 -0
- package/dist/core/typography.d.ts +20 -0
- package/dist/core/typography.js +12 -0
- package/dist/core/upload.d.ts +20 -0
- package/dist/core/upload.js +72 -0
- package/dist/core/watermark.d.ts +10 -0
- package/dist/core/watermark.js +21 -0
- package/dist/fonts/inter-LICENSE +93 -0
- package/dist/fonts/inter-latin-wght-normal.woff2 +0 -0
- package/dist/fonts/jetbrains-mono-LICENSE +93 -0
- package/dist/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
- package/dist/gouno/app-shell.d.ts +22 -0
- package/dist/gouno/app-shell.js +27 -0
- package/dist/gouno/index.d.ts +4 -0
- package/dist/gouno/index.js +4 -0
- package/dist/gouno/page-container.d.ts +4 -0
- package/dist/gouno/page-container.js +6 -0
- package/dist/gouno/page-header.d.ts +8 -0
- package/dist/gouno/page-header.js +6 -0
- package/dist/hooks/use-overlay-body.d.ts +6 -0
- package/dist/hooks/use-overlay-body.js +18 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +5 -0
- package/dist/patterns/bulk-action-bar.d.ts +8 -0
- package/dist/patterns/bulk-action-bar.js +7 -0
- package/dist/patterns/index.d.ts +5 -0
- package/dist/patterns/index.js +5 -0
- package/dist/theme/index.d.ts +2 -0
- package/dist/theme/index.js +2 -0
- package/dist/theme/provider.d.ts +22 -0
- package/dist/theme/provider.js +76 -0
- package/dist/theme/theme-toggle.d.ts +6 -0
- package/dist/theme/theme-toggle.js +10 -0
- package/dist/tokens.css +164 -0
- package/package.json +111 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useComponentLocale } from "./config-provider.js";
|
|
3
|
+
import { forwardRef, useState } from "react";
|
|
4
|
+
import { ChevronDown, ChevronUp } from "lucide-react";
|
|
5
|
+
import { cn } from "../lib/utils.js";
|
|
6
|
+
import { controlSizeClass } from "./control-types.js";
|
|
7
|
+
function normalize(value, min, max, precision) {
|
|
8
|
+
if (value === null || !Number.isFinite(value))
|
|
9
|
+
return null;
|
|
10
|
+
const bounded = Math.min(max ?? Infinity, Math.max(min ?? -Infinity, value));
|
|
11
|
+
return precision === undefined
|
|
12
|
+
? bounded
|
|
13
|
+
: Number(bounded.toFixed(Number.isFinite(precision)
|
|
14
|
+
? Math.max(0, Math.min(100, Math.trunc(precision)))
|
|
15
|
+
: 0));
|
|
16
|
+
}
|
|
17
|
+
export const InputNumber = forwardRef(function InputNumber({ locale, value, defaultValue = null, min, max, step = 1, precision, size = "middle", status, controls = true, keyboard = true, formatter, parser = (display) => (display.trim() === "" ? null : Number(display)), onChange, onStep, className, disabled, readOnly, ...props }, ref) {
|
|
18
|
+
const text = useComponentLocale("inputNumber", locale);
|
|
19
|
+
const [inner, setInner] = useState(() => normalize(defaultValue, min, max, precision));
|
|
20
|
+
const current = value === undefined ? inner : value;
|
|
21
|
+
const [draft, setDraft] = useState(null);
|
|
22
|
+
const displayValue = draft && Object.is(draft.value, current)
|
|
23
|
+
? draft.text
|
|
24
|
+
: formatter
|
|
25
|
+
? formatter(current)
|
|
26
|
+
: (current ?? "");
|
|
27
|
+
const commit = (next) => {
|
|
28
|
+
const normalized = normalize(next, min, max, precision);
|
|
29
|
+
if (value === undefined)
|
|
30
|
+
setInner(normalized);
|
|
31
|
+
onChange?.(normalized);
|
|
32
|
+
return normalized;
|
|
33
|
+
};
|
|
34
|
+
const changeBy = (direction) => {
|
|
35
|
+
if (disabled || readOnly)
|
|
36
|
+
return;
|
|
37
|
+
setDraft(null);
|
|
38
|
+
const offset = direction === "up" ? step : -step;
|
|
39
|
+
const next = commit((current ?? 0) + offset);
|
|
40
|
+
if (next !== null)
|
|
41
|
+
onStep?.(next, { offset, type: direction });
|
|
42
|
+
};
|
|
43
|
+
return (_jsxs("span", { "data-slot": "input-number", "data-status": status, className: cn("relative inline-flex w-full min-w-0 overflow-hidden rounded-md border border-border bg-input focus-within:ring-2 focus-within:ring-ring", status === "error" && "border-destructive", status === "warning" && "border-warning", disabled && "cursor-not-allowed opacity-50", className), children: [_jsx("input", { ...props, ref: ref, type: "text", inputMode: "decimal", role: "spinbutton", value: displayValue, disabled: disabled, readOnly: readOnly, "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": current ?? undefined, "aria-invalid": status === "error" || props["aria-invalid"] || undefined, className: cn("min-w-0 flex-1 border-0 bg-transparent px-3 outline-none", controlSizeClass(size), controls && "pr-10"), onChange: (event) => {
|
|
44
|
+
if (disabled || readOnly)
|
|
45
|
+
return;
|
|
46
|
+
const text = event.target.value;
|
|
47
|
+
const parsed = parser(text);
|
|
48
|
+
if (parsed !== null && !Number.isFinite(parsed)) {
|
|
49
|
+
setDraft({ text, value: current });
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const next = commit(parsed);
|
|
53
|
+
setDraft({ text, value: next });
|
|
54
|
+
}, onBlur: (event) => {
|
|
55
|
+
setDraft(null);
|
|
56
|
+
props.onBlur?.(event);
|
|
57
|
+
}, onKeyDown: (event) => {
|
|
58
|
+
props.onKeyDown?.(event);
|
|
59
|
+
if (!keyboard || event.defaultPrevented)
|
|
60
|
+
return;
|
|
61
|
+
if (event.key === "ArrowUp" || event.key === "ArrowDown") {
|
|
62
|
+
event.preventDefault();
|
|
63
|
+
changeBy(event.key === "ArrowUp" ? "up" : "down");
|
|
64
|
+
}
|
|
65
|
+
} }), controls ? (_jsxs("span", { className: "absolute inset-y-0 right-0 flex w-8 flex-col border-l", children: [_jsx("button", { type: "button", tabIndex: -1, "aria-label": text.increaseLabel, disabled: disabled ||
|
|
66
|
+
readOnly ||
|
|
67
|
+
(max !== undefined && current !== null && current >= max), className: "flex min-h-0 flex-1 items-center justify-center border-b hover:bg-muted disabled:opacity-40", onClick: () => changeBy("up"), children: _jsx(ChevronUp, { className: "size-3" }) }), _jsx("button", { type: "button", tabIndex: -1, "aria-label": text.decreaseLabel, disabled: disabled ||
|
|
68
|
+
readOnly ||
|
|
69
|
+
(min !== undefined && current !== null && current <= min), className: "flex min-h-0 flex-1 items-center justify-center hover:bg-muted disabled:opacity-40", onClick: () => changeBy("down"), children: _jsx(ChevronDown, { className: "size-3" }) })] })) : null] }));
|
|
70
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type HTMLAttributes } from "react";
|
|
2
|
+
import type { ControlSize } from "./control-types.js";
|
|
3
|
+
interface InputOTPRuntimeProps extends Omit<HTMLAttributes<HTMLDivElement>, "children" | "onChange" | "role" | "aria-disabled"> {
|
|
4
|
+
length?: number;
|
|
5
|
+
value?: string;
|
|
6
|
+
defaultValue?: string;
|
|
7
|
+
onChange?: (value: string) => void;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
mask?: boolean;
|
|
10
|
+
size?: ControlSize;
|
|
11
|
+
status?: "error" | "warning";
|
|
12
|
+
}
|
|
13
|
+
export declare const InputOTP: import("react").ForwardRefExoticComponent<InputOTPRuntimeProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useRef, useState, } from "react";
|
|
3
|
+
import { cn } from "../lib/utils.js";
|
|
4
|
+
const inputSizeClass = {
|
|
5
|
+
small: "size-8 text-sm",
|
|
6
|
+
middle: "size-9 text-base",
|
|
7
|
+
large: "size-11 text-lg",
|
|
8
|
+
};
|
|
9
|
+
export const InputOTP = forwardRef(function InputOTP({ length = 6, value, defaultValue = "", onChange, disabled = false, mask = false, size = "middle", status, className, ...props }, ref) {
|
|
10
|
+
const itemCount = Math.max(1, Math.floor(length));
|
|
11
|
+
const [inner, setInner] = useState(defaultValue.replace(/\D/g, "").slice(0, itemCount));
|
|
12
|
+
const itemRefs = useRef([]);
|
|
13
|
+
const canonicalValue = (value ?? inner).replace(/\D/g, "").slice(0, itemCount);
|
|
14
|
+
const current = canonicalValue.padEnd(itemCount, " ");
|
|
15
|
+
const invalid = status === "error" ? true : props["aria-invalid"];
|
|
16
|
+
const commit = (next) => {
|
|
17
|
+
const normalized = next.replace(/[^\d ]/g, "").slice(0, itemCount).trimEnd();
|
|
18
|
+
if (value === undefined)
|
|
19
|
+
setInner(normalized);
|
|
20
|
+
onChange?.(normalized);
|
|
21
|
+
};
|
|
22
|
+
const writeAt = (index, raw) => {
|
|
23
|
+
const digit = raw.replace(/\D/g, "").slice(-1);
|
|
24
|
+
const chars = current.split("");
|
|
25
|
+
chars[index] = digit || " ";
|
|
26
|
+
commit(chars.join(""));
|
|
27
|
+
if (digit && index < itemCount - 1)
|
|
28
|
+
itemRefs.current[index + 1]?.focus();
|
|
29
|
+
};
|
|
30
|
+
const pasteAt = (event, index) => {
|
|
31
|
+
const digits = event.clipboardData
|
|
32
|
+
.getData("text")
|
|
33
|
+
.replace(/\D/g, "")
|
|
34
|
+
.slice(0, itemCount - index);
|
|
35
|
+
if (!digits)
|
|
36
|
+
return;
|
|
37
|
+
event.preventDefault();
|
|
38
|
+
const chars = current.split("");
|
|
39
|
+
for (let offset = 0; offset < digits.length; offset += 1) {
|
|
40
|
+
chars[index + offset] = digits[offset] ?? " ";
|
|
41
|
+
}
|
|
42
|
+
commit(chars.join(""));
|
|
43
|
+
const nextIndex = Math.min(index + digits.length, itemCount - 1);
|
|
44
|
+
itemRefs.current[nextIndex]?.focus();
|
|
45
|
+
};
|
|
46
|
+
const handleKeyDown = (event, index) => {
|
|
47
|
+
if (event.key === "Backspace" && !current[index]?.trim() && index > 0) {
|
|
48
|
+
event.preventDefault();
|
|
49
|
+
const chars = current.split("");
|
|
50
|
+
chars[index - 1] = " ";
|
|
51
|
+
commit(chars.join(""));
|
|
52
|
+
itemRefs.current[index - 1]?.focus();
|
|
53
|
+
}
|
|
54
|
+
else if (event.key === "ArrowLeft" && index > 0) {
|
|
55
|
+
event.preventDefault();
|
|
56
|
+
itemRefs.current[index - 1]?.focus();
|
|
57
|
+
}
|
|
58
|
+
else if (event.key === "ArrowRight" && index < itemCount - 1) {
|
|
59
|
+
event.preventDefault();
|
|
60
|
+
itemRefs.current[index + 1]?.focus();
|
|
61
|
+
}
|
|
62
|
+
else if (event.key === "Home") {
|
|
63
|
+
event.preventDefault();
|
|
64
|
+
itemRefs.current[0]?.focus();
|
|
65
|
+
}
|
|
66
|
+
else if (event.key === "End") {
|
|
67
|
+
event.preventDefault();
|
|
68
|
+
itemRefs.current[itemCount - 1]?.focus();
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
return (_jsx("div", { ...props, ref: ref, role: "group", "aria-disabled": disabled || undefined, "aria-invalid": invalid, "data-slot": "input-otp", "data-status": status, className: cn("flex gap-2", className), children: Array.from({ length: itemCount }, (_, index) => (_jsx("input", { ref: (node) => {
|
|
72
|
+
itemRefs.current[index] = node;
|
|
73
|
+
}, "data-slot": "input-otp-input", "data-index": index, inputMode: "numeric", pattern: "[0-9]*", autoComplete: index === 0 ? "one-time-code" : "off", type: mask ? "password" : "text", maxLength: 1, disabled: disabled, value: current[index]?.trim() || "", "aria-label": String(index + 1), "aria-invalid": invalid, onChange: (event) => writeAt(index, event.target.value), onPaste: (event) => pasteAt(event, index), onKeyDown: (event) => handleKeyDown(event, index), className: cn("rounded-md border bg-input text-center outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", inputSizeClass[size], status === "error" &&
|
|
74
|
+
"border-destructive focus-visible:ring-destructive/30", status === "warning" &&
|
|
75
|
+
"border-warning focus-visible:ring-warning/30") }, index))) }));
|
|
76
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { InputLocale } from "./locale.js";
|
|
2
|
+
import { type InputHTMLAttributes, type ReactNode } from "react";
|
|
3
|
+
import { type ControlSize } from "./control-types.js";
|
|
4
|
+
export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "prefix"> {
|
|
5
|
+
locale?: Partial<InputLocale>;
|
|
6
|
+
size?: ControlSize;
|
|
7
|
+
prefix?: ReactNode;
|
|
8
|
+
suffix?: ReactNode;
|
|
9
|
+
allowClear?: boolean;
|
|
10
|
+
status?: "error" | "warning";
|
|
11
|
+
onClear?: () => void;
|
|
12
|
+
}
|
|
13
|
+
export declare const Input: import("react").ForwardRefExoticComponent<InputProps & import("react").RefAttributes<HTMLInputElement>>;
|
|
14
|
+
export declare const SearchField: import("react").ForwardRefExoticComponent<InputProps & import("react").RefAttributes<HTMLInputElement>>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useComponentLocale } from "./config-provider.js";
|
|
3
|
+
import { forwardRef, useEffect, useState, useRef, useImperativeHandle, } from "react";
|
|
4
|
+
import { Search } from "lucide-react";
|
|
5
|
+
import { Input as PrimitiveInput } from "../components/primitives/input.js";
|
|
6
|
+
import { cn } from "../lib/utils.js";
|
|
7
|
+
import { controlSizeClass } from "./control-types.js";
|
|
8
|
+
export const Input = forwardRef(function Input({ locale, size = "middle", prefix, suffix, allowClear, status, onClear, className, disabled, readOnly, value, defaultValue, onChange, ...props }, ref) {
|
|
9
|
+
const text = useComponentLocale("input", locale);
|
|
10
|
+
const suffixRef = useRef(null);
|
|
11
|
+
const [suffixWidth, setSuffixWidth] = useState(16);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
const element = suffixRef.current;
|
|
14
|
+
if (!element)
|
|
15
|
+
return;
|
|
16
|
+
const measure = () => setSuffixWidth(element.getBoundingClientRect().width);
|
|
17
|
+
measure();
|
|
18
|
+
if (typeof ResizeObserver === "undefined")
|
|
19
|
+
return;
|
|
20
|
+
const observer = new ResizeObserver(measure);
|
|
21
|
+
observer.observe(element);
|
|
22
|
+
return () => observer.disconnect();
|
|
23
|
+
}, [suffix]);
|
|
24
|
+
const inputRef = useRef(null);
|
|
25
|
+
useImperativeHandle(ref, () => inputRef.current);
|
|
26
|
+
const [inner, setInner] = useState(() => defaultValue ?? "");
|
|
27
|
+
const current = value === undefined ? inner : value;
|
|
28
|
+
const clearable = allowClear && !disabled && !readOnly && String(current ?? "").length > 0;
|
|
29
|
+
const control = (_jsx(PrimitiveInput, { ...props, ref: inputRef, value: current, disabled: disabled, readOnly: readOnly, onChange: (event) => {
|
|
30
|
+
if (value === undefined)
|
|
31
|
+
setInner(event.target.value);
|
|
32
|
+
onChange?.(event);
|
|
33
|
+
}, "aria-invalid": status === "error" || props["aria-invalid"] || undefined, "data-status": status, style: { paddingRight: suffix ? suffixWidth + (clearable ? 44 : 24) : undefined, ...props.style }, className: cn("bg-input text-foreground placeholder:text-muted-foreground", controlSizeClass(size), prefix && "pl-9", (suffix || clearable) && "pr-9", status === "warning" && "border-warning focus-visible:ring-warning", className) }));
|
|
34
|
+
if (!prefix && !suffix && !allowClear)
|
|
35
|
+
return control;
|
|
36
|
+
return (_jsxs("span", { "data-slot": "input-group", className: "relative block min-w-0", children: [prefix ? (_jsx("span", { "aria-hidden": "true", className: "pointer-events-none absolute left-3 top-1/2 z-10 -translate-y-1/2 text-muted-foreground [&_svg]:size-4", children: prefix })) : null, control, clearable ? (_jsx("button", { type: "button", "aria-label": text.clearLabel, className: "absolute right-2 top-1/2 z-10 flex size-6 -translate-y-1/2 items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground", onMouseDown: (event) => event.preventDefault(), onClick: () => {
|
|
37
|
+
const input = inputRef.current;
|
|
38
|
+
if (input) {
|
|
39
|
+
const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set;
|
|
40
|
+
setter?.call(input, "");
|
|
41
|
+
input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
42
|
+
input.focus();
|
|
43
|
+
}
|
|
44
|
+
if (value === undefined)
|
|
45
|
+
setInner("");
|
|
46
|
+
onClear?.();
|
|
47
|
+
}, children: "\u00D7" })) : null, suffix ? (_jsx("span", { ref: suffixRef, "data-slot": "input-suffix", className: cn("max-w-[40%] truncate absolute top-1/2 z-10 -translate-y-1/2 text-muted-foreground [&_svg]:size-4", clearable ? "right-9" : "right-3"), children: suffix })) : null] }));
|
|
48
|
+
});
|
|
49
|
+
export const SearchField = forwardRef(function SearchField({ className, ...props }, ref) {
|
|
50
|
+
return (_jsx(Input, { ...props, ref: ref, type: props.type || "search", prefix: _jsx(Search, {}), className: className }));
|
|
51
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type HTMLAttributes } from "react";
|
|
2
|
+
export type KbdProps = HTMLAttributes<HTMLElement>;
|
|
3
|
+
/**
|
|
4
|
+
* Semantic keyboard-input label. Kbd intentionally stays a thin native
|
|
5
|
+
* element: shortcut grouping, separators and platform-specific copy remain
|
|
6
|
+
* caller-owned content rather than hidden component behavior.
|
|
7
|
+
*/
|
|
8
|
+
export declare const Kbd: import("react").ForwardRefExoticComponent<KbdProps & import("react").RefAttributes<HTMLElement>>;
|
package/dist/core/kbd.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { cn } from "../lib/utils.js";
|
|
4
|
+
/**
|
|
5
|
+
* Semantic keyboard-input label. Kbd intentionally stays a thin native
|
|
6
|
+
* element: shortcut grouping, separators and platform-specific copy remain
|
|
7
|
+
* caller-owned content rather than hidden component behavior.
|
|
8
|
+
*/
|
|
9
|
+
export const Kbd = forwardRef(function Kbd({ className, ...props }, ref) {
|
|
10
|
+
return (_jsx("kbd", { ...props, ref: ref, "data-slot": "kbd", className: cn("inline-flex min-h-5 items-center justify-center rounded border bg-muted px-1.5 py-0.5 font-mono text-xs leading-none text-foreground", className) }));
|
|
11
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { HTMLAttributes, Ref } from "react";
|
|
2
|
+
export interface StackProps extends HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
direction?: "row" | "column" | "row-reverse" | "column-reverse";
|
|
4
|
+
gap?: number;
|
|
5
|
+
ref?: Ref<HTMLDivElement>;
|
|
6
|
+
}
|
|
7
|
+
export declare function Stack({ direction, gap, className, style, ref, ...props }: StackProps): import("react").JSX.Element;
|
|
8
|
+
export interface ContainerProps extends HTMLAttributes<HTMLDivElement> {
|
|
9
|
+
ref?: Ref<HTMLDivElement>;
|
|
10
|
+
}
|
|
11
|
+
export declare function Container({ className, ref, ...props }: ContainerProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
export function Stack({ direction = "column", gap = 16, className, style, ref, ...props }) {
|
|
4
|
+
return (_jsx("div", { ...props, ref: ref, "data-slot": "stack", style: { gap, ...style }, className: cn("flex", direction === "column" && "flex-col", direction === "row-reverse" && "flex-row-reverse", direction === "column-reverse" && "flex-col-reverse", className) }));
|
|
5
|
+
}
|
|
6
|
+
export function Container({ className, ref, ...props }) {
|
|
7
|
+
return (_jsx("div", { ...props, ref: ref, "data-slot": "container", className: cn("mx-auto w-full max-w-7xl px-4", className) }));
|
|
8
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { type CSSProperties, type HTMLAttributes, type ReactNode } from "react";
|
|
2
|
+
/** @deprecated Prefer canonical `Separator`; retained for established Core compatibility. */
|
|
3
|
+
export declare const Divider: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & {
|
|
4
|
+
orientation?: "horizontal" | "vertical";
|
|
5
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
6
|
+
export type SpaceAlign = "start" | "end" | "center" | "baseline" | "stretch";
|
|
7
|
+
export interface SpaceProps extends HTMLAttributes<HTMLDivElement> {
|
|
8
|
+
orientation?: "horizontal" | "vertical";
|
|
9
|
+
gap?: "xs" | "sm" | "md" | "lg" | "xl" | number;
|
|
10
|
+
align?: SpaceAlign;
|
|
11
|
+
wrap?: boolean;
|
|
12
|
+
block?: boolean;
|
|
13
|
+
split?: ReactNode;
|
|
14
|
+
children?: ReactNode;
|
|
15
|
+
}
|
|
16
|
+
export declare const Space: import("react").ForwardRefExoticComponent<SpaceProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
17
|
+
export type FlexDirection = "row" | "column" | "row-reverse" | "column-reverse";
|
|
18
|
+
export type FlexAlign = "start" | "center" | "end" | "stretch" | "baseline";
|
|
19
|
+
export type FlexJustify = "start" | "center" | "end" | "space-between" | "space-around" | "space-evenly";
|
|
20
|
+
export type FlexGap = "xs" | "sm" | "md" | "lg" | "xl" | number;
|
|
21
|
+
export type FlexWrap = boolean | "nowrap" | "wrap" | "wrap-reverse";
|
|
22
|
+
export interface FlexProps extends HTMLAttributes<HTMLDivElement> {
|
|
23
|
+
direction?: FlexDirection;
|
|
24
|
+
align?: FlexAlign;
|
|
25
|
+
justify?: FlexJustify;
|
|
26
|
+
gap?: FlexGap;
|
|
27
|
+
wrap?: FlexWrap;
|
|
28
|
+
flex?: CSSProperties["flex"];
|
|
29
|
+
children?: ReactNode;
|
|
30
|
+
}
|
|
31
|
+
export declare const Flex: import("react").ForwardRefExoticComponent<FlexProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
32
|
+
export declare const Grid: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & {
|
|
33
|
+
columns?: 1 | 2 | 3 | 4 | "auto";
|
|
34
|
+
gap?: "sm" | "md" | "lg" | number;
|
|
35
|
+
children?: ReactNode;
|
|
36
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
37
|
+
export type GridSpan = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24;
|
|
38
|
+
export type GridBreakpoint = "xs" | "sm" | "md" | "lg" | "xl" | "xxl";
|
|
39
|
+
export type RowAlign = "top" | "middle" | "bottom" | "stretch";
|
|
40
|
+
export type RowJustify = "start" | "center" | "end" | "space-between" | "space-around" | "space-evenly";
|
|
41
|
+
export type RowGutter = number | [number, number];
|
|
42
|
+
export interface RowProps extends HTMLAttributes<HTMLDivElement> {
|
|
43
|
+
gutter?: RowGutter;
|
|
44
|
+
align?: RowAlign;
|
|
45
|
+
justify?: RowJustify;
|
|
46
|
+
wrap?: boolean;
|
|
47
|
+
}
|
|
48
|
+
export declare const Row: import("react").ForwardRefExoticComponent<RowProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
49
|
+
export interface ColSize {
|
|
50
|
+
span?: GridSpan;
|
|
51
|
+
offset?: GridSpan;
|
|
52
|
+
order?: number;
|
|
53
|
+
push?: GridSpan;
|
|
54
|
+
pull?: GridSpan;
|
|
55
|
+
}
|
|
56
|
+
export type ColBreakpointValue = GridSpan | ColSize;
|
|
57
|
+
export interface ColProps extends HTMLAttributes<HTMLDivElement> {
|
|
58
|
+
span?: GridSpan;
|
|
59
|
+
offset?: GridSpan;
|
|
60
|
+
order?: number;
|
|
61
|
+
push?: GridSpan;
|
|
62
|
+
pull?: GridSpan;
|
|
63
|
+
flex?: CSSProperties["flex"];
|
|
64
|
+
xs?: ColBreakpointValue;
|
|
65
|
+
sm?: ColBreakpointValue;
|
|
66
|
+
md?: ColBreakpointValue;
|
|
67
|
+
lg?: ColBreakpointValue;
|
|
68
|
+
xl?: ColBreakpointValue;
|
|
69
|
+
xxl?: ColBreakpointValue;
|
|
70
|
+
}
|
|
71
|
+
export declare const Col: import("react").ForwardRefExoticComponent<ColProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment, createContext, forwardRef, useContext, } from "react";
|
|
3
|
+
import { cn } from "../lib/utils.js";
|
|
4
|
+
/** @deprecated Prefer canonical `Separator`; retained for established Core compatibility. */
|
|
5
|
+
export const Divider = forwardRef(function Divider({ orientation = "horizontal", className, ...props }, ref) {
|
|
6
|
+
return (_jsx("div", { ref: ref, role: "separator", "aria-orientation": orientation, ...props, "data-slot": "divider", className: cn(orientation === "vertical" ? "h-full w-px" : "h-px w-full", "shrink-0 bg-border", className) }));
|
|
7
|
+
});
|
|
8
|
+
export const Space = forwardRef(function Space({ orientation = "horizontal", gap: gapValue = "md", align, wrap = false, block = false, split, children, className, ...props }, ref) {
|
|
9
|
+
const gap = typeof gapValue === "number"
|
|
10
|
+
? `[gap:${gapValue}px]`
|
|
11
|
+
: { xs: "gap-1", sm: "gap-2", md: "gap-3", lg: "gap-4", xl: "gap-6" }[gapValue];
|
|
12
|
+
const items = Array.isArray(children) ? children : [children];
|
|
13
|
+
const content = split
|
|
14
|
+
? items.flatMap((child, index) => index === 0
|
|
15
|
+
? [child]
|
|
16
|
+
: [_jsx(Fragment, { children: split }, `space-split-${index}`), child])
|
|
17
|
+
: children;
|
|
18
|
+
return (_jsx("div", { ...props, ref: ref, "data-slot": "space", "data-orientation": orientation, "data-block": block || undefined, className: cn("flex min-w-0", orientation === "vertical" ? "flex-col" : "flex-row", align === "start" && "items-start", align === "end" && "items-end", align === "center" && "items-center", align === "baseline" && "items-baseline", align === "stretch" && "items-stretch", gap, wrap && "flex-wrap", block && "w-full", className), children: content }));
|
|
19
|
+
});
|
|
20
|
+
const flexGapClass = {
|
|
21
|
+
xs: "gap-1",
|
|
22
|
+
sm: "gap-2",
|
|
23
|
+
md: "gap-3",
|
|
24
|
+
lg: "gap-4",
|
|
25
|
+
xl: "gap-6",
|
|
26
|
+
};
|
|
27
|
+
export const Flex = forwardRef(function Flex({ direction = "row", align, justify, gap = "md", wrap = false, flex, children, className, style, ...props }, ref) {
|
|
28
|
+
const numericGap = typeof gap === "number" ? Math.max(0, gap) : undefined;
|
|
29
|
+
const resolvedWrap = wrap === true ? "wrap" : wrap === false ? "nowrap" : wrap;
|
|
30
|
+
return (_jsx("div", { ...props, ref: ref, "data-slot": "flex", "data-direction": direction, "data-wrap": resolvedWrap, className: cn("flex min-w-0", direction === "column" && "flex-col", direction === "row-reverse" && "flex-row-reverse", direction === "column-reverse" && "flex-col-reverse", align === "start" && "items-start", align === "center" && "items-center", align === "end" && "items-end", align === "stretch" && "items-stretch", align === "baseline" && "items-baseline", justify === "center" && "justify-center", justify === "end" && "justify-end", justify === "space-between" && "justify-between", justify === "space-around" && "justify-around", justify === "space-evenly" && "justify-evenly", resolvedWrap === "wrap" && "flex-wrap", resolvedWrap === "wrap-reverse" && "flex-wrap-reverse", typeof gap === "number" ? undefined : flexGapClass[gap], className), style: {
|
|
31
|
+
...style,
|
|
32
|
+
...(numericGap !== undefined ? { gap: numericGap } : undefined),
|
|
33
|
+
...(flex !== undefined ? { flex } : undefined),
|
|
34
|
+
}, children: children }));
|
|
35
|
+
});
|
|
36
|
+
export const Grid = forwardRef(function Grid({ columns = "auto", gap = "md", children, className, style, ...props }, ref) {
|
|
37
|
+
const numericGap = typeof gap === "number" ? Math.max(0, gap) : undefined;
|
|
38
|
+
return (_jsx("div", { ...props, ref: ref, "data-slot": "grid", "data-columns": columns, className: cn("grid", columns === "auto"
|
|
39
|
+
? "grid-cols-[repeat(auto-fit,minmax(180px,1fr))]"
|
|
40
|
+
: `grid-cols-${columns}`, typeof gap === "number" ? undefined : gap === "sm" ? "gap-2" : gap === "lg" ? "gap-6" : "gap-4", className), style: { ...style, ...(numericGap !== undefined ? { gap: numericGap } : undefined) }, children: children }));
|
|
41
|
+
});
|
|
42
|
+
const RowGutterContext = createContext(0);
|
|
43
|
+
export const Row = forwardRef(function Row({ gutter = 0, align = "top", justify = "start", wrap = true, className, style, children, ...props }, ref) {
|
|
44
|
+
const [horizontalRaw, verticalRaw] = Array.isArray(gutter) ? gutter : [gutter, 0];
|
|
45
|
+
const horizontal = Math.max(0, horizontalRaw);
|
|
46
|
+
const vertical = Math.max(0, verticalRaw);
|
|
47
|
+
return (_jsx(RowGutterContext.Provider, { value: horizontal, children: _jsx("div", { ...props, ref: ref, "data-slot": "row", "data-gutter-x": horizontal, "data-gutter-y": vertical, className: cn("flex min-w-0", wrap ? "flex-wrap" : "flex-nowrap", align === "top" && "items-start", align === "middle" && "items-center", align === "bottom" && "items-end", align === "stretch" && "items-stretch", justify === "center" && "justify-center", justify === "end" && "justify-end", justify === "space-between" && "justify-between", justify === "space-around" && "justify-around", justify === "space-evenly" && "justify-evenly", className), style: {
|
|
48
|
+
...style,
|
|
49
|
+
...(horizontal > 0 ? { marginInline: -horizontal / 2 } : undefined),
|
|
50
|
+
...(vertical > 0 ? { rowGap: vertical } : undefined),
|
|
51
|
+
}, children: children }) }));
|
|
52
|
+
});
|
|
53
|
+
function gridUnit(value, fallback) {
|
|
54
|
+
return Math.min(24, Math.max(0, Math.round(value ?? fallback)));
|
|
55
|
+
}
|
|
56
|
+
function breakpointSize(value) {
|
|
57
|
+
return typeof value === "number" ? { span: value } : (value ?? {});
|
|
58
|
+
}
|
|
59
|
+
function resolveColSize(previous, value) {
|
|
60
|
+
const next = breakpointSize(value);
|
|
61
|
+
return {
|
|
62
|
+
span: gridUnit(next.span, previous.span),
|
|
63
|
+
offset: gridUnit(next.offset, previous.offset),
|
|
64
|
+
order: next.order ?? previous.order,
|
|
65
|
+
push: gridUnit(next.push, previous.push),
|
|
66
|
+
pull: gridUnit(next.pull, previous.pull),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function percent(value) {
|
|
70
|
+
return `${(value / 24) * 100}%`;
|
|
71
|
+
}
|
|
72
|
+
export const Col = forwardRef(function Col({ span = 24, offset = 0, order = 0, push = 0, pull = 0, flex, xs, sm, md, lg, xl, xxl, className, style, ...props }, ref) {
|
|
73
|
+
const horizontalGutter = useContext(RowGutterContext);
|
|
74
|
+
const initial = {
|
|
75
|
+
span: gridUnit(span, 24),
|
|
76
|
+
offset: gridUnit(offset, 0),
|
|
77
|
+
order,
|
|
78
|
+
push: gridUnit(push, 0),
|
|
79
|
+
pull: gridUnit(pull, 0),
|
|
80
|
+
};
|
|
81
|
+
const base = resolveColSize(initial, xs);
|
|
82
|
+
const smSize = resolveColSize(base, sm);
|
|
83
|
+
const mdSize = resolveColSize(smSize, md);
|
|
84
|
+
const lgSize = resolveColSize(mdSize, lg);
|
|
85
|
+
const xlSize = resolveColSize(lgSize, xl);
|
|
86
|
+
const xxlSize = resolveColSize(xlSize, xxl);
|
|
87
|
+
const variables = {
|
|
88
|
+
"--gouno-col-basis": percent(base.span),
|
|
89
|
+
"--gouno-col-offset": percent(base.offset),
|
|
90
|
+
"--gouno-col-shift": percent(base.push - base.pull),
|
|
91
|
+
"--gouno-col-order": base.order,
|
|
92
|
+
"--gouno-col-sm-basis": percent(smSize.span),
|
|
93
|
+
"--gouno-col-sm-offset": percent(smSize.offset),
|
|
94
|
+
"--gouno-col-sm-shift": percent(smSize.push - smSize.pull),
|
|
95
|
+
"--gouno-col-sm-order": smSize.order,
|
|
96
|
+
"--gouno-col-md-basis": percent(mdSize.span),
|
|
97
|
+
"--gouno-col-md-offset": percent(mdSize.offset),
|
|
98
|
+
"--gouno-col-md-shift": percent(mdSize.push - mdSize.pull),
|
|
99
|
+
"--gouno-col-md-order": mdSize.order,
|
|
100
|
+
"--gouno-col-lg-basis": percent(lgSize.span),
|
|
101
|
+
"--gouno-col-lg-offset": percent(lgSize.offset),
|
|
102
|
+
"--gouno-col-lg-shift": percent(lgSize.push - lgSize.pull),
|
|
103
|
+
"--gouno-col-lg-order": lgSize.order,
|
|
104
|
+
"--gouno-col-xl-basis": percent(xlSize.span),
|
|
105
|
+
"--gouno-col-xl-offset": percent(xlSize.offset),
|
|
106
|
+
"--gouno-col-xl-shift": percent(xlSize.push - xlSize.pull),
|
|
107
|
+
"--gouno-col-xl-order": xlSize.order,
|
|
108
|
+
"--gouno-col-xxl-basis": percent(xxlSize.span),
|
|
109
|
+
"--gouno-col-xxl-offset": percent(xxlSize.offset),
|
|
110
|
+
"--gouno-col-xxl-shift": percent(xxlSize.push - xxlSize.pull),
|
|
111
|
+
"--gouno-col-xxl-order": xxlSize.order,
|
|
112
|
+
};
|
|
113
|
+
return (_jsx("div", { ...props, ref: ref, "data-slot": "col", "data-span": base.span, "data-sm-span": smSize.span, "data-md-span": mdSize.span, "data-lg-span": lgSize.span, "data-xl-span": xlSize.span, "data-xxl-span": xxlSize.span, className: cn("min-w-0", className), style: {
|
|
114
|
+
...style,
|
|
115
|
+
...variables,
|
|
116
|
+
...(horizontalGutter > 0 ? { paddingInline: horizontalGutter / 2 } : undefined),
|
|
117
|
+
...(flex !== undefined ? { flex, maxWidth: "none" } : undefined),
|
|
118
|
+
} }));
|
|
119
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type CSSProperties, type HTMLAttributes, type Key, type ReactNode, type Ref } from "react";
|
|
2
|
+
export type ListSize = "small" | "medium" | "large";
|
|
3
|
+
export type ListItemLayout = "horizontal" | "vertical";
|
|
4
|
+
export type ListSemantic = "root" | "header" | "body" | "item" | "empty" | "footer" | "loadMore";
|
|
5
|
+
export interface ListLocale {
|
|
6
|
+
emptyText?: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
export interface ListSemanticInfo {
|
|
9
|
+
props: Readonly<{
|
|
10
|
+
size: ListSize;
|
|
11
|
+
bordered: boolean;
|
|
12
|
+
split: boolean;
|
|
13
|
+
itemLayout: ListItemLayout;
|
|
14
|
+
loading: boolean;
|
|
15
|
+
empty: boolean;
|
|
16
|
+
}>;
|
|
17
|
+
}
|
|
18
|
+
export type ListClassNames = Partial<Record<ListSemantic, string>> | ((info: ListSemanticInfo) => Partial<Record<ListSemantic, string>>);
|
|
19
|
+
export type ListStyles = Partial<Record<ListSemantic, CSSProperties>> | ((info: ListSemanticInfo) => Partial<Record<ListSemantic, CSSProperties>>);
|
|
20
|
+
export interface ListProps<T = unknown> extends Omit<HTMLAttributes<HTMLDivElement>, "aria-busy" | "children"> {
|
|
21
|
+
dataSource?: readonly T[];
|
|
22
|
+
renderItem: (item: T, index: number) => ReactNode;
|
|
23
|
+
rowKey: keyof T | ((item: T) => Key);
|
|
24
|
+
bordered?: boolean;
|
|
25
|
+
split?: boolean;
|
|
26
|
+
size?: ListSize;
|
|
27
|
+
itemLayout?: ListItemLayout;
|
|
28
|
+
loading?: boolean;
|
|
29
|
+
header?: ReactNode;
|
|
30
|
+
footer?: ReactNode;
|
|
31
|
+
loadMore?: ReactNode;
|
|
32
|
+
locale?: ListLocale;
|
|
33
|
+
classNames?: ListClassNames;
|
|
34
|
+
styles?: ListStyles;
|
|
35
|
+
ref?: Ref<HTMLDivElement>;
|
|
36
|
+
}
|
|
37
|
+
export declare function List<T = unknown>({ dataSource, renderItem, rowKey, bordered, split, size, itemLayout, loading, header, footer, loadMore, locale, classNames, styles, className, style, ref, ...props }: ListProps<T>): import("react").JSX.Element;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import {} from "react";
|
|
3
|
+
import { cn } from "../lib/utils.js";
|
|
4
|
+
import { Spin } from "./spin.js";
|
|
5
|
+
const paddingBySize = {
|
|
6
|
+
small: "px-3 py-2",
|
|
7
|
+
medium: "px-4 py-3",
|
|
8
|
+
large: "px-5 py-4",
|
|
9
|
+
};
|
|
10
|
+
function defaultEmptyText() {
|
|
11
|
+
return typeof document !== "undefined" &&
|
|
12
|
+
document.documentElement.lang.startsWith("en")
|
|
13
|
+
? "No data"
|
|
14
|
+
: "暂无数据";
|
|
15
|
+
}
|
|
16
|
+
function resolveRowKey(item, rowKey) {
|
|
17
|
+
if (typeof rowKey === "function")
|
|
18
|
+
return rowKey(item);
|
|
19
|
+
const value = item?.[rowKey];
|
|
20
|
+
if (typeof value === "string" || typeof value === "number")
|
|
21
|
+
return value;
|
|
22
|
+
throw new TypeError(`List rowKey "${String(rowKey)}" must resolve to a string or number.`);
|
|
23
|
+
}
|
|
24
|
+
export function List({ dataSource = [], renderItem, rowKey, bordered = false, split = true, size = "medium", itemLayout = "horizontal", loading = false, header, footer, loadMore, locale, classNames, styles, className, style, ref, ...props }) {
|
|
25
|
+
const empty = dataSource.length === 0;
|
|
26
|
+
const semanticInfo = {
|
|
27
|
+
props: { size, bordered, split, itemLayout, loading, empty },
|
|
28
|
+
};
|
|
29
|
+
const semanticClassNames = typeof classNames === "function" ? classNames(semanticInfo) : (classNames ?? {});
|
|
30
|
+
const semanticStyles = typeof styles === "function" ? styles(semanticInfo) : (styles ?? {});
|
|
31
|
+
const padding = paddingBySize[size];
|
|
32
|
+
return (_jsxs("div", { ...props, ref: ref, "data-slot": "list", "data-size": size, "data-layout": itemLayout, "data-bordered": bordered || undefined, "data-split": split || undefined, className: cn("w-full min-w-0 text-sm text-foreground", bordered && "overflow-hidden rounded-lg border bg-background", semanticClassNames.root, className), style: { ...semanticStyles.root, ...style }, children: [header !== undefined && header !== null ? (_jsx("div", { "data-slot": "list-header", className: cn(padding, "font-medium", bordered && "border-b", semanticClassNames.header), style: semanticStyles.header, children: header })) : null, _jsx(Spin, { spinning: loading, children: empty ? (_jsx("div", { "data-slot": "list-empty", className: cn(padding, "text-center text-muted-foreground", semanticClassNames.empty), style: semanticStyles.empty, children: locale?.emptyText ?? defaultEmptyText() })) : (_jsx("ul", { "data-slot": "list-body", className: cn("min-w-0", split && "divide-y", semanticClassNames.body), style: semanticStyles.body, children: dataSource.map((item, index) => (_jsx("li", { "data-slot": "list-item", className: cn(padding, itemLayout === "horizontal"
|
|
33
|
+
? "flex min-w-0 items-start gap-4"
|
|
34
|
+
: "flex min-w-0 flex-col gap-2", semanticClassNames.item), style: semanticStyles.item, children: renderItem(item, index) }, resolveRowKey(item, rowKey)))) })) }), loadMore !== undefined && loadMore !== null ? (_jsx("div", { "data-slot": "list-load-more", className: cn(padding, "flex justify-center", bordered && "border-t", semanticClassNames.loadMore), style: semanticStyles.loadMore, children: loadMore })) : null, footer !== undefined && footer !== null ? (_jsx("div", { "data-slot": "list-footer", className: cn(padding, bordered && "border-t", semanticClassNames.footer), style: semanticStyles.footer, children: footer })) : null] }));
|
|
35
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** Generic component copy only. Product labels and content remain caller-owned. */
|
|
2
|
+
export interface InputLocale {
|
|
3
|
+
clearLabel: string;
|
|
4
|
+
}
|
|
5
|
+
export interface DatePickerLocale {
|
|
6
|
+
clearLabel: string;
|
|
7
|
+
}
|
|
8
|
+
export interface InputNumberLocale {
|
|
9
|
+
increaseLabel: string;
|
|
10
|
+
decreaseLabel: string;
|
|
11
|
+
}
|
|
12
|
+
export interface SelectLocale {
|
|
13
|
+
clearLabel: string;
|
|
14
|
+
searchLabel: string;
|
|
15
|
+
searchPlaceholder: string;
|
|
16
|
+
emptyText: string;
|
|
17
|
+
removeLabel: (label: string) => string;
|
|
18
|
+
}
|
|
19
|
+
export interface UploadLocale {
|
|
20
|
+
fileListLabel: string;
|
|
21
|
+
removeLabel: (fileName: string) => string;
|
|
22
|
+
}
|
|
23
|
+
export interface PaginationLocale {
|
|
24
|
+
pageLabel: (page: number) => string;
|
|
25
|
+
jumpBackwardLabel: string;
|
|
26
|
+
jumpForwardLabel: string;
|
|
27
|
+
pageSizeLabel: string;
|
|
28
|
+
pageSizeText: (size: number) => string;
|
|
29
|
+
jumpText: string;
|
|
30
|
+
jumpLabel: string;
|
|
31
|
+
}
|
|
32
|
+
export interface ComponentLocale {
|
|
33
|
+
readonly locale: string;
|
|
34
|
+
readonly input: Readonly<InputLocale>;
|
|
35
|
+
readonly datePicker: Readonly<DatePickerLocale>;
|
|
36
|
+
readonly inputNumber: Readonly<InputNumberLocale>;
|
|
37
|
+
readonly select: Readonly<SelectLocale & {
|
|
38
|
+
placeholder: string;
|
|
39
|
+
}>;
|
|
40
|
+
readonly upload: Readonly<UploadLocale>;
|
|
41
|
+
readonly pagination: Readonly<PaginationLocale & {
|
|
42
|
+
ariaLabel: string;
|
|
43
|
+
prevText: string;
|
|
44
|
+
nextText: string;
|
|
45
|
+
}>;
|
|
46
|
+
}
|
|
47
|
+
export declare const enUS: ComponentLocale;
|
|
48
|
+
export declare const zhCN: ComponentLocale;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export const enUS = {
|
|
2
|
+
locale: "en-US",
|
|
3
|
+
input: { clearLabel: "Clear input" },
|
|
4
|
+
datePicker: { clearLabel: "Clear date" },
|
|
5
|
+
inputNumber: { increaseLabel: "Increase", decreaseLabel: "Decrease" },
|
|
6
|
+
select: {
|
|
7
|
+
placeholder: "Please select", clearLabel: "Clear selection", searchLabel: "Search options",
|
|
8
|
+
searchPlaceholder: "Search", emptyText: "No options", removeLabel: (label) => `Remove ${label}`,
|
|
9
|
+
},
|
|
10
|
+
upload: { fileListLabel: "Selected files", removeLabel: (name) => `Remove ${name}` },
|
|
11
|
+
pagination: {
|
|
12
|
+
ariaLabel: "Pagination", prevText: "Previous", nextText: "Next", pageLabel: (page) => `Page ${page}`,
|
|
13
|
+
jumpBackwardLabel: "Jump backward", jumpForwardLabel: "Jump forward", pageSizeLabel: "Page size",
|
|
14
|
+
pageSizeText: (size) => `${size} / page`, jumpText: "Go to", jumpLabel: "Go to page",
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
export const zhCN = {
|
|
18
|
+
locale: "zh-CN",
|
|
19
|
+
input: { clearLabel: "清除输入" },
|
|
20
|
+
datePicker: { clearLabel: "清除日期" },
|
|
21
|
+
inputNumber: { increaseLabel: "增加", decreaseLabel: "减少" },
|
|
22
|
+
select: {
|
|
23
|
+
placeholder: "请选择", clearLabel: "清除选择", searchLabel: "搜索选项",
|
|
24
|
+
searchPlaceholder: "搜索", emptyText: "暂无选项", removeLabel: (label) => `移除 ${label}`,
|
|
25
|
+
},
|
|
26
|
+
upload: { fileListLabel: "已选择文件", removeLabel: (name) => `移除 ${name}` },
|
|
27
|
+
pagination: {
|
|
28
|
+
ariaLabel: "分页", prevText: "上一页", nextText: "下一页", pageLabel: (page) => `第 ${page} 页`,
|
|
29
|
+
jumpBackwardLabel: "向前跳页", jumpForwardLabel: "向后跳页", pageSizeLabel: "每页条数",
|
|
30
|
+
pageSizeText: (size) => `${size} 条 / 页`, jumpText: "跳至", jumpLabel: "跳转到页码",
|
|
31
|
+
},
|
|
32
|
+
};
|