@seedgrid/fe-components 0.2.10 → 2026.3.1
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/buttons/SgFloatActionButton.d.ts.map +1 -1
- package/dist/buttons/SgFloatActionButton.js +168 -38
- package/dist/commons/SgAvatar.d.ts +66 -0
- package/dist/commons/SgAvatar.d.ts.map +1 -0
- package/dist/commons/SgAvatar.js +136 -0
- package/dist/commons/SgSkeleton.d.ts +16 -0
- package/dist/commons/SgSkeleton.d.ts.map +1 -0
- package/dist/commons/SgSkeleton.js +58 -0
- package/dist/digits/discard-digit/SgDiscardDigit.d.ts +39 -0
- package/dist/digits/discard-digit/SgDiscardDigit.d.ts.map +1 -0
- package/dist/digits/discard-digit/SgDiscardDigit.js +303 -0
- package/dist/digits/discard-digit/index.d.ts +3 -0
- package/dist/digits/discard-digit/index.d.ts.map +1 -0
- package/dist/digits/discard-digit/index.js +1 -0
- package/dist/digits/fade-digit/SgFadeDigit.d.ts +27 -0
- package/dist/digits/fade-digit/SgFadeDigit.d.ts.map +1 -0
- package/dist/digits/fade-digit/SgFadeDigit.js +85 -0
- package/dist/digits/fade-digit/index.d.ts +3 -0
- package/dist/digits/fade-digit/index.d.ts.map +1 -0
- package/dist/digits/fade-digit/index.js +1 -0
- package/dist/digits/flip-digit/SgFlipDigit.d.ts +27 -0
- package/dist/digits/flip-digit/SgFlipDigit.d.ts.map +1 -0
- package/dist/digits/flip-digit/SgFlipDigit.js +70 -0
- package/dist/digits/flip-digit/index.d.ts.map +1 -0
- package/dist/digits/matrix-digit/SgMatrixDigit.d.ts +32 -0
- package/dist/digits/matrix-digit/SgMatrixDigit.d.ts.map +1 -0
- package/dist/digits/matrix-digit/SgMatrixDigit.js +86 -0
- package/dist/digits/matrix-digit/index.d.ts +3 -0
- package/dist/digits/matrix-digit/index.d.ts.map +1 -0
- package/dist/digits/matrix-digit/index.js +1 -0
- package/dist/digits/neon-digit/SgNeonDigit.d.ts +37 -0
- package/dist/digits/neon-digit/SgNeonDigit.d.ts.map +1 -0
- package/dist/digits/neon-digit/SgNeonDigit.js +59 -0
- package/dist/digits/neon-digit/index.d.ts +3 -0
- package/dist/digits/neon-digit/index.d.ts.map +1 -0
- package/dist/digits/neon-digit/index.js +1 -0
- package/dist/digits/roller3d-digit/SgRoller3DDigit.d.ts +37 -0
- package/dist/digits/roller3d-digit/SgRoller3DDigit.d.ts.map +1 -0
- package/dist/digits/roller3d-digit/SgRoller3DDigit.js +47 -0
- package/dist/digits/roller3d-digit/index.d.ts +3 -0
- package/dist/digits/roller3d-digit/index.d.ts.map +1 -0
- package/dist/digits/roller3d-digit/index.js +1 -0
- package/dist/environment/SgEnvironmentProvider.d.ts +1 -0
- package/dist/environment/SgEnvironmentProvider.d.ts.map +1 -1
- package/dist/environment/SgEnvironmentProvider.js +51 -12
- package/dist/gadgets/clock/SgClock.d.ts +3 -1
- package/dist/gadgets/clock/SgClock.d.ts.map +1 -1
- package/dist/gadgets/clock/SgClock.js +111 -180
- package/dist/gadgets/clock/SgTimeProvider.d.ts +1 -0
- package/dist/gadgets/clock/SgTimeProvider.d.ts.map +1 -1
- package/dist/gadgets/clock/SgTimeProvider.js +11 -4
- package/dist/gadgets/gauge/SgLinearGauge.d.ts +59 -0
- package/dist/gadgets/gauge/SgLinearGauge.d.ts.map +1 -0
- package/dist/gadgets/gauge/SgLinearGauge.js +258 -0
- package/dist/gadgets/gauge/SgRadialGauge.d.ts +73 -0
- package/dist/gadgets/gauge/SgRadialGauge.d.ts.map +1 -0
- package/dist/gadgets/gauge/SgRadialGauge.js +311 -0
- package/dist/gadgets/gauge/index.d.ts +5 -0
- package/dist/gadgets/gauge/index.d.ts.map +1 -0
- package/dist/gadgets/gauge/index.js +2 -0
- package/dist/gadgets/string-animator/SgStringAnimator.d.ts +91 -0
- package/dist/gadgets/string-animator/SgStringAnimator.d.ts.map +1 -0
- package/dist/gadgets/string-animator/SgStringAnimator.js +145 -0
- package/dist/gadgets/string-animator/index.d.ts +3 -0
- package/dist/gadgets/string-animator/index.d.ts.map +1 -0
- package/dist/gadgets/string-animator/index.js +1 -0
- package/dist/i18n/en-US.json +9 -1
- package/dist/i18n/es.json +55 -47
- package/dist/i18n/index.d.ts +32 -0
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/i18n/pt-BR.json +9 -1
- package/dist/i18n/pt-PT.json +9 -1
- package/dist/index.d.ts +46 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -1
- package/dist/inputs/SgAutocomplete.js +21 -5
- package/dist/inputs/SgCombobox.d.ts.map +1 -1
- package/dist/inputs/SgCombobox.js +8 -3
- package/dist/inputs/SgRadioGroup.d.ts +37 -0
- package/dist/inputs/SgRadioGroup.d.ts.map +1 -0
- package/dist/inputs/SgRadioGroup.js +139 -0
- package/dist/inputs/SgRating.d.ts +55 -0
- package/dist/inputs/SgRating.d.ts.map +1 -0
- package/dist/inputs/SgRating.js +135 -0
- package/dist/inputs/SgSlider.d.ts +20 -0
- package/dist/inputs/SgSlider.d.ts.map +1 -0
- package/dist/inputs/SgSlider.js +40 -0
- package/dist/inputs/SgStepperInput.d.ts +22 -0
- package/dist/inputs/SgStepperInput.d.ts.map +1 -0
- package/dist/inputs/SgStepperInput.js +51 -0
- package/dist/inputs/SgTextEditor.d.ts +1 -0
- package/dist/inputs/SgTextEditor.d.ts.map +1 -1
- package/dist/inputs/SgTextEditor.js +19 -3
- package/dist/layout/SgAccordion.d.ts +39 -0
- package/dist/layout/SgAccordion.d.ts.map +1 -0
- package/dist/layout/SgAccordion.js +116 -0
- package/dist/layout/SgBreadcrumb.d.ts +33 -0
- package/dist/layout/SgBreadcrumb.d.ts.map +1 -0
- package/dist/layout/SgBreadcrumb.js +121 -0
- package/dist/layout/SgCarousel.d.ts +43 -0
- package/dist/layout/SgCarousel.d.ts.map +1 -0
- package/dist/layout/SgCarousel.js +166 -0
- package/dist/layout/SgDockLayout.d.ts +14 -0
- package/dist/layout/SgDockLayout.d.ts.map +1 -1
- package/dist/layout/SgDockLayout.js +145 -13
- package/dist/layout/SgDockScreen.d.ts +15 -0
- package/dist/layout/SgDockScreen.d.ts.map +1 -0
- package/dist/layout/SgDockScreen.js +13 -0
- package/dist/layout/SgDockZone.d.ts.map +1 -1
- package/dist/layout/SgDockZone.js +36 -2
- package/dist/layout/SgExpandablePanel.d.ts +50 -0
- package/dist/layout/SgExpandablePanel.d.ts.map +1 -0
- package/dist/layout/SgExpandablePanel.js +302 -0
- package/dist/layout/SgMainPanel.d.ts.map +1 -1
- package/dist/layout/SgMainPanel.js +36 -14
- package/dist/layout/SgMenu.d.ts +91 -0
- package/dist/layout/SgMenu.d.ts.map +1 -0
- package/dist/layout/SgMenu.js +939 -0
- package/dist/layout/SgPageControl.d.ts +49 -0
- package/dist/layout/SgPageControl.d.ts.map +1 -0
- package/dist/layout/SgPageControl.js +152 -0
- package/dist/layout/SgPanel.d.ts.map +1 -1
- package/dist/layout/SgPanel.js +10 -1
- package/dist/layout/SgScreen.d.ts +2 -0
- package/dist/layout/SgScreen.d.ts.map +1 -1
- package/dist/layout/SgScreen.js +4 -2
- package/dist/layout/SgToolBar.d.ts +9 -3
- package/dist/layout/SgToolBar.d.ts.map +1 -1
- package/dist/layout/SgToolBar.js +461 -55
- package/dist/menus/SgDockMenu.d.ts +62 -0
- package/dist/menus/SgDockMenu.d.ts.map +1 -0
- package/dist/menus/SgDockMenu.js +480 -0
- package/dist/others/SgPlayground.js +72 -72
- package/package.json +72 -63
- package/dist/gadgets/flip-digit/SgFlipDigit.d.ts +0 -23
- package/dist/gadgets/flip-digit/SgFlipDigit.d.ts.map +0 -1
- package/dist/gadgets/flip-digit/SgFlipDigit.js +0 -118
- package/dist/gadgets/flip-digit/index.d.ts.map +0 -1
- /package/dist/{gadgets → digits}/flip-digit/index.d.ts +0 -0
- /package/dist/{gadgets → digits}/flip-digit/index.js +0 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
function cn(...parts) {
|
|
5
|
+
return parts.filter(Boolean).join(" ");
|
|
6
|
+
}
|
|
7
|
+
function toCssSize(value) {
|
|
8
|
+
if (value === undefined || value === null)
|
|
9
|
+
return undefined;
|
|
10
|
+
if (typeof value === "number")
|
|
11
|
+
return `${value}px`;
|
|
12
|
+
const trimmed = value.trim();
|
|
13
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
14
|
+
}
|
|
15
|
+
function clamp(value, min, max) {
|
|
16
|
+
return Math.max(min, Math.min(max, value));
|
|
17
|
+
}
|
|
18
|
+
export function SgSlider(props) {
|
|
19
|
+
const { id, minValue, maxValue, value, defaultValue, step = 1, disabled = false, onChange, ariaLabel, className, width, inputProps } = props;
|
|
20
|
+
const safeMin = Number.isFinite(minValue) ? minValue : 0;
|
|
21
|
+
const rawMax = Number.isFinite(maxValue) ? maxValue : safeMin;
|
|
22
|
+
const safeMax = Math.max(safeMin, rawMax);
|
|
23
|
+
const safeStep = Number.isFinite(step) && step > 0 ? step : 1;
|
|
24
|
+
const isControlled = value !== undefined;
|
|
25
|
+
const [internalValue, setInternalValue] = React.useState(() => clamp(defaultValue ?? safeMin, safeMin, safeMax));
|
|
26
|
+
React.useEffect(() => {
|
|
27
|
+
if (isControlled)
|
|
28
|
+
return;
|
|
29
|
+
setInternalValue((prev) => clamp(prev, safeMin, safeMax));
|
|
30
|
+
}, [isControlled, safeMin, safeMax]);
|
|
31
|
+
const currentValue = clamp(isControlled ? value : internalValue, safeMin, safeMax);
|
|
32
|
+
return (_jsx("input", { id: id, type: "range", min: safeMin, max: safeMax, step: safeStep, value: currentValue, disabled: disabled, "aria-label": ariaLabel, onChange: (event) => {
|
|
33
|
+
const nextRaw = Number(event.currentTarget.value);
|
|
34
|
+
const next = clamp(Number.isFinite(nextRaw) ? nextRaw : safeMin, safeMin, safeMax);
|
|
35
|
+
if (!isControlled)
|
|
36
|
+
setInternalValue(next);
|
|
37
|
+
onChange?.(next);
|
|
38
|
+
}, className: cn("h-5 w-full cursor-pointer", disabled ? "cursor-not-allowed opacity-60" : "", className), style: { width: toCssSize(width) }, ...inputProps }));
|
|
39
|
+
}
|
|
40
|
+
SgSlider.displayName = "SgSlider";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type SgStepperInputProps = {
|
|
3
|
+
id: string;
|
|
4
|
+
minValue: number;
|
|
5
|
+
maxValue: number;
|
|
6
|
+
step?: number;
|
|
7
|
+
value?: number;
|
|
8
|
+
defaultValue?: number;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
readOnly?: boolean;
|
|
11
|
+
onChange?: (value: number) => void;
|
|
12
|
+
ariaLabel?: string;
|
|
13
|
+
className?: string;
|
|
14
|
+
inputClassName?: string;
|
|
15
|
+
width?: number | string;
|
|
16
|
+
inputProps?: Omit<React.InputHTMLAttributes<HTMLInputElement>, "type" | "id" | "min" | "max" | "step" | "value" | "defaultValue" | "disabled" | "readOnly" | "onChange" | "aria-label">;
|
|
17
|
+
};
|
|
18
|
+
export declare function SgStepperInput(props: Readonly<SgStepperInputProps>): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
export declare namespace SgStepperInput {
|
|
20
|
+
var displayName: string;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=SgStepperInput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SgStepperInput.d.ts","sourceRoot":"","sources":["../../src/inputs/SgStepperInput.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAiB/B,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,IAAI,CACf,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EACzC,MAAM,GACN,IAAI,GACJ,KAAK,GACL,KAAK,GACL,MAAM,GACN,OAAO,GACP,cAAc,GACd,UAAU,GACV,UAAU,GACV,UAAU,GACV,YAAY,CACf,CAAC;CACH,CAAC;AAEF,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,CAAC,mBAAmB,CAAC,2CAiHlE;yBAjHe,cAAc"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
function cn(...parts) {
|
|
5
|
+
return parts.filter(Boolean).join(" ");
|
|
6
|
+
}
|
|
7
|
+
function toCssSize(value) {
|
|
8
|
+
if (value === undefined || value === null)
|
|
9
|
+
return undefined;
|
|
10
|
+
if (typeof value === "number")
|
|
11
|
+
return `${value}px`;
|
|
12
|
+
const trimmed = value.trim();
|
|
13
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
14
|
+
}
|
|
15
|
+
function clamp(value, min, max) {
|
|
16
|
+
return Math.max(min, Math.min(max, value));
|
|
17
|
+
}
|
|
18
|
+
export function SgStepperInput(props) {
|
|
19
|
+
const { id, minValue, maxValue, step = 1, value, defaultValue, disabled = false, readOnly = false, onChange, ariaLabel, className, inputClassName, width, inputProps } = props;
|
|
20
|
+
const safeMin = Number.isFinite(minValue) ? minValue : 0;
|
|
21
|
+
const rawMax = Number.isFinite(maxValue) ? maxValue : safeMin;
|
|
22
|
+
const safeMax = Math.max(safeMin, rawMax);
|
|
23
|
+
const safeStep = Number.isFinite(step) && step > 0 ? step : 1;
|
|
24
|
+
const isControlled = value !== undefined;
|
|
25
|
+
const [internalValue, setInternalValue] = React.useState(() => clamp(defaultValue ?? safeMin, safeMin, safeMax));
|
|
26
|
+
React.useEffect(() => {
|
|
27
|
+
if (isControlled)
|
|
28
|
+
return;
|
|
29
|
+
setInternalValue((prev) => clamp(prev, safeMin, safeMax));
|
|
30
|
+
}, [isControlled, safeMin, safeMax]);
|
|
31
|
+
const currentValue = clamp(isControlled ? value : internalValue, safeMin, safeMax);
|
|
32
|
+
const emitValue = React.useCallback((nextRaw) => {
|
|
33
|
+
const next = clamp(nextRaw, safeMin, safeMax);
|
|
34
|
+
if (!isControlled)
|
|
35
|
+
setInternalValue(next);
|
|
36
|
+
onChange?.(next);
|
|
37
|
+
}, [isControlled, onChange, safeMax, safeMin]);
|
|
38
|
+
const canDecrease = !disabled && !readOnly && currentValue > safeMin;
|
|
39
|
+
const canIncrease = !disabled && !readOnly && currentValue < safeMax;
|
|
40
|
+
return (_jsxs("div", { className: cn("inline-flex h-10 overflow-hidden rounded-md border border-border bg-background", disabled ? "opacity-60" : "", className), style: { width: toCssSize(width) }, children: [_jsx("input", { id: id, type: "number", min: safeMin, max: safeMax, step: safeStep, value: currentValue, disabled: disabled, readOnly: readOnly, "aria-label": ariaLabel, onChange: (event) => {
|
|
41
|
+
const inputNext = Number(event.currentTarget.value);
|
|
42
|
+
if (!Number.isFinite(inputNext))
|
|
43
|
+
return;
|
|
44
|
+
emitValue(inputNext);
|
|
45
|
+
}, className: cn("min-w-0 flex-1 border-0 bg-transparent px-3 text-sm outline-none", "focus:ring-0 [appearance:textfield]", "[&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none", inputClassName), ...inputProps }), _jsxs("div", { className: "flex w-7 flex-col border-l border-border", children: [_jsx("button", { type: "button", "aria-label": "Increase value", disabled: !canIncrease, onClick: () => emitValue(currentValue + safeStep), className: cn("inline-flex h-1/2 items-center justify-center text-foreground", "border-b border-border text-[10px]", canIncrease ? "hover:bg-muted" : "cursor-not-allowed opacity-40"), children: _jsx(StepArrow, { direction: "up" }) }), _jsx("button", { type: "button", "aria-label": "Decrease value", disabled: !canDecrease, onClick: () => emitValue(currentValue - safeStep), className: cn("inline-flex h-1/2 items-center justify-center text-foreground text-[10px]", canDecrease ? "hover:bg-muted" : "cursor-not-allowed opacity-40"), children: _jsx(StepArrow, { direction: "down" }) })] })] }));
|
|
46
|
+
}
|
|
47
|
+
SgStepperInput.displayName = "SgStepperInput";
|
|
48
|
+
function StepArrow(props) {
|
|
49
|
+
const rotate = props.direction === "up" ? 0 : 180;
|
|
50
|
+
return (_jsx("svg", { viewBox: "0 0 24 24", className: "size-3", style: { transform: `rotate(${rotate}deg)` }, "aria-hidden": "true", children: _jsx("path", { d: "M12 8l5 8H7z", fill: "currentColor" }) }));
|
|
51
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SgTextEditor.d.ts","sourceRoot":"","sources":["../../src/inputs/SgTextEditor.tsx"],"names":[],"mappings":"AAgBA,MAAM,MAAM,oBAAoB,GAAG;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAE1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAE5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC1D,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAE9C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"SgTextEditor.d.ts","sourceRoot":"","sources":["../../src/inputs/SgTextEditor.tsx"],"names":[],"mappings":"AAgBA,MAAM,MAAM,oBAAoB,GAAG;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAE1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAE5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC1D,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAE9C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAE/B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AA2DF,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,iBAAiB,CAAC,2CAoZ9D;yBApZe,YAAY"}
|
|
@@ -68,7 +68,12 @@ function canRun(editor, fn) {
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
export function SgTextEditor(props) {
|
|
71
|
-
const { id, valueHtml, defaultValueHtml, onChangeHtml, cssText = "", onCssTextChange, fileName, onSave, onLoad, height = 320, placeholder = "Type here...", disabled, showCssEditor = false, cssEditorLabel = "Embedded CSS", className } = props;
|
|
71
|
+
const { id, valueHtml, defaultValueHtml, onChangeHtml, cssText = "", onCssTextChange, fileName, onSave, onLoad, height = 320, placeholder = "Type here...", disabled, borderRadius, showCssEditor = false, cssEditorLabel = "Embedded CSS", className } = props;
|
|
72
|
+
const resolvedBorderRadius = React.useMemo(() => {
|
|
73
|
+
if (borderRadius === undefined)
|
|
74
|
+
return undefined;
|
|
75
|
+
return typeof borderRadius === "number" ? `${borderRadius}px` : borderRadius;
|
|
76
|
+
}, [borderRadius]);
|
|
72
77
|
const isControlled = typeof valueHtml === "string";
|
|
73
78
|
const editor = useEditor({
|
|
74
79
|
editable: !disabled,
|
|
@@ -136,7 +141,18 @@ export function SgTextEditor(props) {
|
|
|
136
141
|
fn();
|
|
137
142
|
};
|
|
138
143
|
const active = (name, attrs) => !!editor?.isActive(name, attrs);
|
|
139
|
-
|
|
144
|
+
const toolbarStyle = resolvedBorderRadius
|
|
145
|
+
? { borderTopLeftRadius: resolvedBorderRadius, borderTopRightRadius: resolvedBorderRadius }
|
|
146
|
+
: undefined;
|
|
147
|
+
const editorContainerStyle = { height };
|
|
148
|
+
if (resolvedBorderRadius) {
|
|
149
|
+
editorContainerStyle.borderBottomLeftRadius = resolvedBorderRadius;
|
|
150
|
+
editorContainerStyle.borderBottomRightRadius = resolvedBorderRadius;
|
|
151
|
+
}
|
|
152
|
+
const cssTextareaStyle = resolvedBorderRadius
|
|
153
|
+
? { borderRadius: resolvedBorderRadius }
|
|
154
|
+
: undefined;
|
|
155
|
+
return (_jsxs("div", { className: cn("w-full", className), children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2 rounded-t-lg border border-b-0 bg-background p-2", style: toolbarStyle, children: [_jsxs("select", { className: "h-9 rounded-md border px-2 text-sm bg-background", disabled: !editor || disabled, value: active("heading", { level: 1 })
|
|
140
156
|
? "h1"
|
|
141
157
|
: active("heading", { level: 2 })
|
|
142
158
|
? "h2"
|
|
@@ -192,7 +208,7 @@ export function SgTextEditor(props) {
|
|
|
192
208
|
return;
|
|
193
209
|
void loadFromHtmlFile(f);
|
|
194
210
|
e.currentTarget.value = "";
|
|
195
|
-
} })] })] })] }), _jsx("div", { className: "rounded-b-lg border bg-background", style:
|
|
211
|
+
} })] })] })] }), _jsx("div", { className: "rounded-b-lg border bg-background", style: editorContainerStyle, children: _jsx("div", { className: "h-full overflow-auto p-3", children: _jsx(EditorContent, { editor: editor }) }) }), showCssEditor ? (_jsxs("div", { className: "mt-3", children: [_jsx("label", { className: "mb-1 block text-sm font-medium text-foreground", children: cssEditorLabel }), _jsx("textarea", { value: cssText, onChange: (e) => onCssTextChange?.(e.target.value), className: "min-h-[160px] w-full rounded-lg border p-2 font-mono text-xs", style: cssTextareaStyle }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "CSS is embedded inside the saved HTML document." })] })) : null] }));
|
|
196
212
|
}
|
|
197
213
|
function ToolbarButton(props) {
|
|
198
214
|
const { label, text, active, disabled, onClick } = props;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type SgAccordionOrientation = "vertical" | "horizontal";
|
|
3
|
+
export type SgAccordionItem = {
|
|
4
|
+
id?: string | number;
|
|
5
|
+
title: React.ReactNode;
|
|
6
|
+
content: React.ReactNode;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
icon?: React.ReactNode;
|
|
9
|
+
end?: React.ReactNode;
|
|
10
|
+
className?: string;
|
|
11
|
+
headerClassName?: string;
|
|
12
|
+
headerBackgroundColor?: string;
|
|
13
|
+
contentClassName?: string;
|
|
14
|
+
};
|
|
15
|
+
export type SgAccordionProps = Omit<React.HTMLAttributes<HTMLDivElement>, "onChange"> & {
|
|
16
|
+
id?: string;
|
|
17
|
+
items: SgAccordionItem[];
|
|
18
|
+
orientation?: SgAccordionOrientation;
|
|
19
|
+
multiple?: boolean;
|
|
20
|
+
collapsible?: boolean;
|
|
21
|
+
activeIndex?: number | number[];
|
|
22
|
+
defaultActiveIndex?: number | number[];
|
|
23
|
+
defaultOpenFirst?: boolean;
|
|
24
|
+
onActiveIndexChange?: (indexes: number[]) => void;
|
|
25
|
+
onItemToggle?: (index: number, isOpen: boolean) => void;
|
|
26
|
+
panelClassName?: string;
|
|
27
|
+
headerClassName?: string;
|
|
28
|
+
headerBackgroundColor?: string;
|
|
29
|
+
contentClassName?: string;
|
|
30
|
+
animationDuration?: number;
|
|
31
|
+
horizontalHeaderWidth?: number | string;
|
|
32
|
+
horizontalMinHeight?: number | string;
|
|
33
|
+
keepMounted?: boolean;
|
|
34
|
+
};
|
|
35
|
+
export declare function SgAccordion(props: Readonly<SgAccordionProps>): import("react/jsx-runtime").JSX.Element;
|
|
36
|
+
export declare namespace SgAccordion {
|
|
37
|
+
var displayName: string;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=SgAccordion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SgAccordion.d.ts","sourceRoot":"","sources":["../../src/layout/SgAccordion.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAsD/B,MAAM,MAAM,sBAAsB,GAAG,UAAU,GAAG,YAAY,CAAC;AAE/D,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,GAAG,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,GAAG;IACtF,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAChC,kBAAkB,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACvC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAClD,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qBAAqB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxC,mBAAmB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAKF,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,gBAAgB,CAAC,2CAgN5D;yBAhNe,WAAW"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
function cn(...parts) {
|
|
5
|
+
return parts.filter(Boolean).join(" ");
|
|
6
|
+
}
|
|
7
|
+
function toCssSize(value) {
|
|
8
|
+
if (value === undefined || value === null)
|
|
9
|
+
return undefined;
|
|
10
|
+
return typeof value === "number" ? `${value}px` : value;
|
|
11
|
+
}
|
|
12
|
+
function normalizeIndices(value, max, multiple) {
|
|
13
|
+
if (value === undefined)
|
|
14
|
+
return [];
|
|
15
|
+
const source = Array.isArray(value) ? value : [value];
|
|
16
|
+
const next = source
|
|
17
|
+
.filter((idx) => Number.isInteger(idx))
|
|
18
|
+
.map((idx) => Number(idx))
|
|
19
|
+
.filter((idx) => idx >= 0 && idx < max);
|
|
20
|
+
const unique = Array.from(new Set(next)).sort((a, b) => a - b);
|
|
21
|
+
return multiple ? unique : unique.slice(0, 1);
|
|
22
|
+
}
|
|
23
|
+
function ChevronIcon(props) {
|
|
24
|
+
const base = props.horizontal
|
|
25
|
+
? props.open
|
|
26
|
+
? "rotate-180"
|
|
27
|
+
: "rotate-90"
|
|
28
|
+
: props.open
|
|
29
|
+
? "rotate-180"
|
|
30
|
+
: "rotate-0";
|
|
31
|
+
return (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: cn("transition-transform duration-200", base), "aria-hidden": "true", children: _jsx("polyline", { points: "6 9 12 15 18 9" }) }));
|
|
32
|
+
}
|
|
33
|
+
const DEFAULT_HEADER_BACKGROUND = "var(--sg-accordion-header-bg, rgb(var(--sg-primary-50, 239 246 255)))";
|
|
34
|
+
export function SgAccordion(props) {
|
|
35
|
+
const { id, items, orientation = "vertical", multiple = false, collapsible = true, activeIndex, defaultActiveIndex, defaultOpenFirst = true, onActiveIndexChange, onItemToggle, panelClassName, headerClassName, headerBackgroundColor, contentClassName, animationDuration = 220, horizontalHeaderWidth = 52, horizontalMinHeight = 220, keepMounted = true, className, ...rest } = props;
|
|
36
|
+
const generatedId = React.useId().replace(/[:]/g, "");
|
|
37
|
+
const baseId = (id ?? `sg-accordion-${generatedId}`).replace(/\s+/g, "-");
|
|
38
|
+
const isHorizontal = orientation === "horizontal";
|
|
39
|
+
const headerWidth = toCssSize(horizontalHeaderWidth) ?? "52px";
|
|
40
|
+
const minHeight = toCssSize(horizontalMinHeight) ?? "220px";
|
|
41
|
+
const controlled = activeIndex !== undefined;
|
|
42
|
+
const controlledIndices = React.useMemo(() => normalizeIndices(activeIndex, items.length, multiple), [activeIndex, items.length, multiple]);
|
|
43
|
+
const [internalIndices, setInternalIndices] = React.useState(() => {
|
|
44
|
+
const seed = defaultActiveIndex !== undefined
|
|
45
|
+
? defaultActiveIndex
|
|
46
|
+
: defaultOpenFirst && items.length > 0
|
|
47
|
+
? 0
|
|
48
|
+
: [];
|
|
49
|
+
return normalizeIndices(seed, items.length, multiple);
|
|
50
|
+
});
|
|
51
|
+
React.useEffect(() => {
|
|
52
|
+
if (controlled)
|
|
53
|
+
return;
|
|
54
|
+
setInternalIndices((prev) => normalizeIndices(prev, items.length, multiple));
|
|
55
|
+
}, [controlled, items.length, multiple]);
|
|
56
|
+
const openIndices = controlled ? controlledIndices : internalIndices;
|
|
57
|
+
const openSet = React.useMemo(() => new Set(openIndices), [openIndices]);
|
|
58
|
+
const commitIndices = React.useCallback((next) => {
|
|
59
|
+
const normalized = normalizeIndices(next, items.length, multiple);
|
|
60
|
+
if (!controlled)
|
|
61
|
+
setInternalIndices(normalized);
|
|
62
|
+
onActiveIndexChange?.(normalized);
|
|
63
|
+
}, [controlled, items.length, multiple, onActiveIndexChange]);
|
|
64
|
+
const handleToggle = React.useCallback((index) => {
|
|
65
|
+
const item = items[index];
|
|
66
|
+
if (!item || item.disabled)
|
|
67
|
+
return;
|
|
68
|
+
const isOpen = openSet.has(index);
|
|
69
|
+
if (isOpen && !collapsible)
|
|
70
|
+
return;
|
|
71
|
+
let next;
|
|
72
|
+
if (isOpen) {
|
|
73
|
+
next = openIndices.filter((it) => it !== index);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
next = multiple ? [...openIndices, index] : [index];
|
|
77
|
+
}
|
|
78
|
+
commitIndices(next);
|
|
79
|
+
onItemToggle?.(index, !isOpen);
|
|
80
|
+
}, [items, openSet, collapsible, openIndices, multiple, commitIndices, onItemToggle]);
|
|
81
|
+
return (_jsx("div", { className: cn(isHorizontal ? "flex w-full gap-2 overflow-x-auto" : "space-y-2", className), "data-orientation": orientation, ...rest, children: items.map((item, index) => {
|
|
82
|
+
const isOpen = openSet.has(index);
|
|
83
|
+
const panelId = `${baseId}-panel-${item.id ?? index}`;
|
|
84
|
+
const headerId = `${baseId}-header-${item.id ?? index}`;
|
|
85
|
+
const contentId = `${baseId}-content-${item.id ?? index}`;
|
|
86
|
+
const resolvedHeaderBackground = item.headerBackgroundColor ?? headerBackgroundColor ?? DEFAULT_HEADER_BACKGROUND;
|
|
87
|
+
const sharedButtonClasses = cn("inline-flex items-center gap-2 text-left font-medium transition-[filter,colors] duration-150", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40", item.disabled ? "cursor-not-allowed opacity-55" : "cursor-pointer hover:brightness-95");
|
|
88
|
+
return (_jsxs("div", { id: panelId, className: cn("border border-border bg-background", isHorizontal ? "flex min-w-0 overflow-hidden rounded-lg" : "overflow-hidden rounded-lg", panelClassName, item.className), style: isHorizontal
|
|
89
|
+
? {
|
|
90
|
+
minHeight,
|
|
91
|
+
flex: isOpen ? "1 1 0%" : "0 0 auto",
|
|
92
|
+
transition: `flex-basis ${animationDuration}ms ease`
|
|
93
|
+
}
|
|
94
|
+
: undefined, children: [_jsx("button", { id: headerId, type: "button", disabled: item.disabled, "aria-controls": contentId, "aria-expanded": isOpen, className: cn(sharedButtonClasses, isHorizontal
|
|
95
|
+
? "h-full flex-col justify-between border-r border-border px-2 py-3 text-[11px] uppercase tracking-wide"
|
|
96
|
+
: "w-full justify-between px-4 py-3 text-sm", headerClassName, item.headerClassName), style: isHorizontal
|
|
97
|
+
? {
|
|
98
|
+
width: headerWidth,
|
|
99
|
+
backgroundColor: resolvedHeaderBackground
|
|
100
|
+
}
|
|
101
|
+
: {
|
|
102
|
+
backgroundColor: resolvedHeaderBackground
|
|
103
|
+
}, onClick: () => handleToggle(index), children: isHorizontal ? (_jsxs(_Fragment, { children: [_jsx(ChevronIcon, { open: isOpen, horizontal: true }), _jsx("span", { style: { writingMode: "vertical-rl", transform: "rotate(180deg)" }, className: "line-clamp-1 select-none text-center text-[10px] font-semibold tracking-wide", children: item.title }), item.icon ? _jsx("span", { className: "opacity-80", children: item.icon }) : _jsx("span", { "aria-hidden": "true" })] })) : (_jsxs(_Fragment, { children: [_jsxs("span", { className: "inline-flex items-center gap-2", children: [item.icon ? _jsx("span", { className: "opacity-80", children: item.icon }) : null, _jsx("span", { children: item.title })] }), _jsxs("span", { className: "inline-flex items-center gap-2", children: [item.end ? _jsx("span", { children: item.end }) : null, _jsx(ChevronIcon, { open: isOpen, horizontal: false })] })] })) }), _jsx("div", { id: contentId, role: "region", "aria-labelledby": headerId, className: cn("overflow-hidden", contentClassName, item.contentClassName), style: isHorizontal
|
|
104
|
+
? {
|
|
105
|
+
width: isOpen ? "100%" : "0px",
|
|
106
|
+
opacity: isOpen ? 1 : 0,
|
|
107
|
+
transition: `width ${animationDuration}ms ease, opacity ${animationDuration}ms ease`
|
|
108
|
+
}
|
|
109
|
+
: {
|
|
110
|
+
maxHeight: isOpen ? "960px" : "0px",
|
|
111
|
+
opacity: isOpen ? 1 : 0,
|
|
112
|
+
transition: `max-height ${animationDuration}ms ease, opacity ${animationDuration}ms ease`
|
|
113
|
+
}, children: keepMounted || isOpen ? (_jsx("div", { className: cn(isHorizontal ? "h-full min-w-[220px] p-4" : "p-4"), children: item.content })) : null })] }, panelId));
|
|
114
|
+
}) }));
|
|
115
|
+
}
|
|
116
|
+
SgAccordion.displayName = "SgAccordion";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type SgBreadcrumbItem = {
|
|
3
|
+
id: string;
|
|
4
|
+
label: React.ReactNode;
|
|
5
|
+
href?: string;
|
|
6
|
+
icon?: React.ReactNode;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
hidden?: boolean;
|
|
9
|
+
onClick?: () => void;
|
|
10
|
+
};
|
|
11
|
+
export type SgBreadcrumbSeparator = "slash" | "chevron" | "dot" | "arrow";
|
|
12
|
+
export type SgBreadcrumbProps = {
|
|
13
|
+
items: SgBreadcrumbItem[];
|
|
14
|
+
separator?: SgBreadcrumbSeparator | React.ReactNode;
|
|
15
|
+
maxItems?: number;
|
|
16
|
+
overflowBehavior?: "collapse" | "scroll";
|
|
17
|
+
showHomeIcon?: boolean;
|
|
18
|
+
homeHref?: string;
|
|
19
|
+
homeLabel?: React.ReactNode;
|
|
20
|
+
size?: "sm" | "md" | "lg";
|
|
21
|
+
variant?: "default" | "subtle" | "primary";
|
|
22
|
+
ariaLabel?: string;
|
|
23
|
+
overflowLabel?: string;
|
|
24
|
+
onNavigate?: (item: SgBreadcrumbItem, index: number) => void;
|
|
25
|
+
className?: string;
|
|
26
|
+
itemClassName?: string;
|
|
27
|
+
style?: React.CSSProperties;
|
|
28
|
+
};
|
|
29
|
+
export declare function SgBreadcrumb(props: Readonly<SgBreadcrumbProps>): import("react/jsx-runtime").JSX.Element;
|
|
30
|
+
export declare namespace SgBreadcrumb {
|
|
31
|
+
var displayName: string;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=SgBreadcrumb.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SgBreadcrumb.d.ts","sourceRoot":"","sources":["../../src/layout/SgBreadcrumb.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAO/B,MAAM,MAAM,gBAAgB,GAAG;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,SAAS,GAAG,KAAK,GAAG,OAAO,CAAC;AAE1E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,SAAS,CAAC,EAAE,qBAAqB,GAAG,KAAK,CAAC,SAAS,CAAC;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAC;IACzC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC5B,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B,CAAC;AAsGF,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,iBAAiB,CAAC,2CA8K9D;yBA9Ke,YAAY"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { ChevronRight, Home, MoreHorizontal } from "lucide-react";
|
|
5
|
+
function cn(...parts) {
|
|
6
|
+
return parts.filter(Boolean).join(" ");
|
|
7
|
+
}
|
|
8
|
+
function separatorNode(separator, iconClassName) {
|
|
9
|
+
if (React.isValidElement(separator))
|
|
10
|
+
return separator;
|
|
11
|
+
if (separator === "slash")
|
|
12
|
+
return _jsx("span", { className: iconClassName, children: "/" });
|
|
13
|
+
if (separator === "dot")
|
|
14
|
+
return _jsx("span", { className: iconClassName, children: "\u2022" });
|
|
15
|
+
if (separator === "arrow")
|
|
16
|
+
return _jsx("span", { className: iconClassName, children: "\u2192" });
|
|
17
|
+
return _jsx(ChevronRight, { className: iconClassName });
|
|
18
|
+
}
|
|
19
|
+
function toDisplayTokens(items, overflowBehavior, maxItems) {
|
|
20
|
+
if (overflowBehavior !== "collapse" ||
|
|
21
|
+
maxItems === undefined ||
|
|
22
|
+
maxItems < 2 ||
|
|
23
|
+
items.length <= maxItems) {
|
|
24
|
+
return items.map((item) => ({ type: "item", value: item }));
|
|
25
|
+
}
|
|
26
|
+
if (maxItems === 2) {
|
|
27
|
+
return [
|
|
28
|
+
{ type: "item", value: items[0] },
|
|
29
|
+
{ type: "item", value: items[items.length - 1] }
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
const tailCount = maxItems - 2;
|
|
33
|
+
const head = items[0];
|
|
34
|
+
const tail = items.slice(-tailCount);
|
|
35
|
+
const hidden = items.slice(1, items.length - tailCount);
|
|
36
|
+
const out = [{ type: "item", value: head }];
|
|
37
|
+
if (hidden.length > 0)
|
|
38
|
+
out.push({ type: "overflow", value: hidden });
|
|
39
|
+
for (const item of tail)
|
|
40
|
+
out.push({ type: "item", value: item });
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
function renderActionItem(item, index, className, iconClassName, onNavigate) {
|
|
44
|
+
const content = (_jsxs(_Fragment, { children: [item.icon ? _jsx("span", { className: cn("inline-flex items-center justify-center", iconClassName), children: item.icon }) : null, _jsx("span", { className: "truncate", children: item.label })] }));
|
|
45
|
+
if (item.disabled) {
|
|
46
|
+
return _jsx("span", { className: cn(className, "cursor-not-allowed opacity-45"), children: content });
|
|
47
|
+
}
|
|
48
|
+
if (item.href) {
|
|
49
|
+
return (_jsx("a", { href: item.href, className: className, onClick: () => {
|
|
50
|
+
item.onClick?.();
|
|
51
|
+
onNavigate?.(item, index);
|
|
52
|
+
}, children: content }));
|
|
53
|
+
}
|
|
54
|
+
if (item.onClick) {
|
|
55
|
+
return (_jsx("button", { type: "button", className: className, onClick: () => {
|
|
56
|
+
item.onClick?.();
|
|
57
|
+
onNavigate?.(item, index);
|
|
58
|
+
}, children: content }));
|
|
59
|
+
}
|
|
60
|
+
return _jsx("span", { className: cn(className, "cursor-default"), children: content });
|
|
61
|
+
}
|
|
62
|
+
export function SgBreadcrumb(props) {
|
|
63
|
+
const { items, separator = "chevron", maxItems, overflowBehavior = "collapse", showHomeIcon = false, homeHref = "/", homeLabel = "Home", size = "md", variant = "default", ariaLabel = "Breadcrumb", overflowLabel = "Mais caminhos", onNavigate, className, itemClassName, style } = props;
|
|
64
|
+
const visibleItems = React.useMemo(() => items.filter((item) => !item.hidden), [items]);
|
|
65
|
+
const normalizedItems = React.useMemo(() => {
|
|
66
|
+
const base = visibleItems.map((item, index) => ({ item, index }));
|
|
67
|
+
if (!showHomeIcon)
|
|
68
|
+
return base;
|
|
69
|
+
const homeItem = {
|
|
70
|
+
item: {
|
|
71
|
+
id: "__sg_breadcrumb_home__",
|
|
72
|
+
label: homeLabel,
|
|
73
|
+
href: homeHref,
|
|
74
|
+
icon: _jsx(Home, { className: "size-full" })
|
|
75
|
+
},
|
|
76
|
+
index: -1
|
|
77
|
+
};
|
|
78
|
+
return [homeItem, ...base];
|
|
79
|
+
}, [homeHref, homeLabel, showHomeIcon, visibleItems]);
|
|
80
|
+
const tokens = React.useMemo(() => toDisplayTokens(normalizedItems, overflowBehavior, maxItems), [maxItems, normalizedItems, overflowBehavior]);
|
|
81
|
+
const sizeClasses = size === "sm"
|
|
82
|
+
? {
|
|
83
|
+
root: "text-xs gap-1.5",
|
|
84
|
+
item: "px-1.5 py-0.5",
|
|
85
|
+
icon: "size-3.5",
|
|
86
|
+
sep: "text-[10px]"
|
|
87
|
+
}
|
|
88
|
+
: size === "lg"
|
|
89
|
+
? {
|
|
90
|
+
root: "text-base gap-2.5",
|
|
91
|
+
item: "px-2 py-1",
|
|
92
|
+
icon: "size-4.5",
|
|
93
|
+
sep: "text-sm"
|
|
94
|
+
}
|
|
95
|
+
: {
|
|
96
|
+
root: "text-sm gap-2",
|
|
97
|
+
item: "px-1.5 py-0.5",
|
|
98
|
+
icon: "size-4",
|
|
99
|
+
sep: "text-xs"
|
|
100
|
+
};
|
|
101
|
+
const variantClasses = variant === "subtle"
|
|
102
|
+
? {
|
|
103
|
+
item: "rounded-md text-muted-foreground hover:bg-muted/80 hover:text-foreground",
|
|
104
|
+
current: "rounded-md bg-muted text-foreground"
|
|
105
|
+
}
|
|
106
|
+
: variant === "primary"
|
|
107
|
+
? {
|
|
108
|
+
item: "rounded-md text-primary hover:bg-primary/10",
|
|
109
|
+
current: "rounded-md bg-primary/10 text-primary font-medium"
|
|
110
|
+
}
|
|
111
|
+
: {
|
|
112
|
+
item: "text-muted-foreground hover:text-foreground",
|
|
113
|
+
current: "text-foreground font-medium"
|
|
114
|
+
};
|
|
115
|
+
const separatorEl = separatorNode(separator, cn("text-muted-foreground", sizeClasses.sep));
|
|
116
|
+
return (_jsx("nav", { "aria-label": ariaLabel, className: cn("min-w-0", className), style: style, children: _jsx("div", { className: cn(overflowBehavior === "scroll" ? "overflow-x-auto" : ""), children: _jsx("ol", { className: cn("flex min-w-0 items-center whitespace-nowrap", sizeClasses.root), children: tokens.map((token, tokenIndex) => {
|
|
117
|
+
const isLast = tokenIndex === tokens.length - 1;
|
|
118
|
+
return (_jsxs(React.Fragment, { children: [tokenIndex > 0 ? (_jsx("li", { "aria-hidden": true, className: "inline-flex shrink-0 items-center", children: separatorEl })) : null, token.type === "item" ? (_jsx("li", { className: "inline-flex min-w-0 items-center", children: isLast ? (_jsxs("span", { "aria-current": "page", className: cn("inline-flex min-w-0 items-center gap-1.5", sizeClasses.item, variantClasses.current, itemClassName), children: [token.value.item.icon ? (_jsx("span", { className: cn("inline-flex items-center justify-center", sizeClasses.icon), children: token.value.item.icon })) : null, _jsx("span", { className: "truncate", children: token.value.item.label })] })) : (renderActionItem(token.value.item, token.value.index, cn("inline-flex min-w-0 items-center gap-1.5 transition-colors", sizeClasses.item, variantClasses.item, itemClassName), sizeClasses.icon, onNavigate)) })) : (_jsx("li", { className: "relative inline-flex items-center", children: _jsxs("details", { className: "group", children: [_jsx("summary", { "aria-label": overflowLabel, className: cn("list-none cursor-pointer rounded-md text-muted-foreground transition-colors", "inline-flex items-center justify-center", sizeClasses.item, "hover:bg-muted hover:text-foreground [&::-webkit-details-marker]:hidden"), children: _jsx(MoreHorizontal, { className: sizeClasses.icon }) }), _jsx("ul", { className: "absolute left-0 top-full z-20 mt-1 min-w-44 rounded-md border border-border bg-popover p-1 shadow-md", children: token.value.map((entry) => (_jsx("li", { children: renderActionItem(entry.item, entry.index, cn("inline-flex w-full min-w-0 items-center gap-1.5 rounded-md px-2 py-1.5 text-left text-sm", "text-popover-foreground hover:bg-muted"), "size-4", onNavigate) }, entry.item.id))) })] }) }))] }, token.type === "item" ? token.value.item.id : `overflow-${tokenIndex}`));
|
|
119
|
+
}) }) }) }));
|
|
120
|
+
}
|
|
121
|
+
SgBreadcrumb.displayName = "SgBreadcrumb";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export type SgCarouselOrientation = "horizontal" | "vertical";
|
|
3
|
+
export interface SgCarouselProps {
|
|
4
|
+
/** Unique identifier for the carousel */
|
|
5
|
+
id?: string;
|
|
6
|
+
/** Items to display in the carousel */
|
|
7
|
+
items: React.ReactNode[];
|
|
8
|
+
/** Number of items to display at once */
|
|
9
|
+
numVisible?: number;
|
|
10
|
+
/** Number of items to scroll at a time */
|
|
11
|
+
numScroll?: number;
|
|
12
|
+
/** Orientation of the carousel */
|
|
13
|
+
orientation?: SgCarouselOrientation;
|
|
14
|
+
/** Enable circular mode (infinite loop) */
|
|
15
|
+
circular?: boolean;
|
|
16
|
+
/** Enable auto play */
|
|
17
|
+
autoPlay?: boolean;
|
|
18
|
+
/** Auto play interval in milliseconds */
|
|
19
|
+
autoPlayInterval?: number;
|
|
20
|
+
/** Show navigation buttons */
|
|
21
|
+
showNavigators?: boolean;
|
|
22
|
+
/** Show indicators (dots) */
|
|
23
|
+
showIndicators?: boolean;
|
|
24
|
+
/** Custom class name for container */
|
|
25
|
+
className?: string;
|
|
26
|
+
/** Custom class name for items */
|
|
27
|
+
itemClassName?: string;
|
|
28
|
+
/** Width of the carousel container */
|
|
29
|
+
width?: number | string;
|
|
30
|
+
/** Height of the carousel container */
|
|
31
|
+
height?: number | string;
|
|
32
|
+
/** Gap between items in pixels */
|
|
33
|
+
gap?: number;
|
|
34
|
+
/** Callback when active index changes */
|
|
35
|
+
onIndexChange?: (index: number) => void;
|
|
36
|
+
/** Custom render for navigation buttons */
|
|
37
|
+
customNavigators?: {
|
|
38
|
+
prev?: React.ReactNode;
|
|
39
|
+
next?: React.ReactNode;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export declare function SgCarousel(props: SgCarouselProps): import("react/jsx-runtime").JSX.Element;
|
|
43
|
+
//# sourceMappingURL=SgCarousel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SgCarousel.d.ts","sourceRoot":"","sources":["../../src/layout/SgCarousel.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,MAAM,qBAAqB,GAAG,YAAY,GAAG,UAAU,CAAC;AAE9D,MAAM,WAAW,eAAe;IAC9B,yCAAyC;IACzC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,KAAK,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC;IACzB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uBAAuB;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yCAAyC;IACzC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,8BAA8B;IAC9B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,6BAA6B;IAC7B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,kCAAkC;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE;QACjB,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;QACvB,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;KACxB,CAAC;CACH;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,2CA2RhD"}
|