@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.
Files changed (140) hide show
  1. package/dist/buttons/SgFloatActionButton.d.ts.map +1 -1
  2. package/dist/buttons/SgFloatActionButton.js +168 -38
  3. package/dist/commons/SgAvatar.d.ts +66 -0
  4. package/dist/commons/SgAvatar.d.ts.map +1 -0
  5. package/dist/commons/SgAvatar.js +136 -0
  6. package/dist/commons/SgSkeleton.d.ts +16 -0
  7. package/dist/commons/SgSkeleton.d.ts.map +1 -0
  8. package/dist/commons/SgSkeleton.js +58 -0
  9. package/dist/digits/discard-digit/SgDiscardDigit.d.ts +39 -0
  10. package/dist/digits/discard-digit/SgDiscardDigit.d.ts.map +1 -0
  11. package/dist/digits/discard-digit/SgDiscardDigit.js +303 -0
  12. package/dist/digits/discard-digit/index.d.ts +3 -0
  13. package/dist/digits/discard-digit/index.d.ts.map +1 -0
  14. package/dist/digits/discard-digit/index.js +1 -0
  15. package/dist/digits/fade-digit/SgFadeDigit.d.ts +27 -0
  16. package/dist/digits/fade-digit/SgFadeDigit.d.ts.map +1 -0
  17. package/dist/digits/fade-digit/SgFadeDigit.js +85 -0
  18. package/dist/digits/fade-digit/index.d.ts +3 -0
  19. package/dist/digits/fade-digit/index.d.ts.map +1 -0
  20. package/dist/digits/fade-digit/index.js +1 -0
  21. package/dist/digits/flip-digit/SgFlipDigit.d.ts +27 -0
  22. package/dist/digits/flip-digit/SgFlipDigit.d.ts.map +1 -0
  23. package/dist/digits/flip-digit/SgFlipDigit.js +70 -0
  24. package/dist/digits/flip-digit/index.d.ts.map +1 -0
  25. package/dist/digits/matrix-digit/SgMatrixDigit.d.ts +32 -0
  26. package/dist/digits/matrix-digit/SgMatrixDigit.d.ts.map +1 -0
  27. package/dist/digits/matrix-digit/SgMatrixDigit.js +86 -0
  28. package/dist/digits/matrix-digit/index.d.ts +3 -0
  29. package/dist/digits/matrix-digit/index.d.ts.map +1 -0
  30. package/dist/digits/matrix-digit/index.js +1 -0
  31. package/dist/digits/neon-digit/SgNeonDigit.d.ts +37 -0
  32. package/dist/digits/neon-digit/SgNeonDigit.d.ts.map +1 -0
  33. package/dist/digits/neon-digit/SgNeonDigit.js +59 -0
  34. package/dist/digits/neon-digit/index.d.ts +3 -0
  35. package/dist/digits/neon-digit/index.d.ts.map +1 -0
  36. package/dist/digits/neon-digit/index.js +1 -0
  37. package/dist/digits/roller3d-digit/SgRoller3DDigit.d.ts +37 -0
  38. package/dist/digits/roller3d-digit/SgRoller3DDigit.d.ts.map +1 -0
  39. package/dist/digits/roller3d-digit/SgRoller3DDigit.js +47 -0
  40. package/dist/digits/roller3d-digit/index.d.ts +3 -0
  41. package/dist/digits/roller3d-digit/index.d.ts.map +1 -0
  42. package/dist/digits/roller3d-digit/index.js +1 -0
  43. package/dist/environment/SgEnvironmentProvider.d.ts +1 -0
  44. package/dist/environment/SgEnvironmentProvider.d.ts.map +1 -1
  45. package/dist/environment/SgEnvironmentProvider.js +51 -12
  46. package/dist/gadgets/clock/SgClock.d.ts +3 -1
  47. package/dist/gadgets/clock/SgClock.d.ts.map +1 -1
  48. package/dist/gadgets/clock/SgClock.js +111 -180
  49. package/dist/gadgets/clock/SgTimeProvider.d.ts +1 -0
  50. package/dist/gadgets/clock/SgTimeProvider.d.ts.map +1 -1
  51. package/dist/gadgets/clock/SgTimeProvider.js +11 -4
  52. package/dist/gadgets/gauge/SgLinearGauge.d.ts +59 -0
  53. package/dist/gadgets/gauge/SgLinearGauge.d.ts.map +1 -0
  54. package/dist/gadgets/gauge/SgLinearGauge.js +258 -0
  55. package/dist/gadgets/gauge/SgRadialGauge.d.ts +73 -0
  56. package/dist/gadgets/gauge/SgRadialGauge.d.ts.map +1 -0
  57. package/dist/gadgets/gauge/SgRadialGauge.js +311 -0
  58. package/dist/gadgets/gauge/index.d.ts +5 -0
  59. package/dist/gadgets/gauge/index.d.ts.map +1 -0
  60. package/dist/gadgets/gauge/index.js +2 -0
  61. package/dist/gadgets/string-animator/SgStringAnimator.d.ts +91 -0
  62. package/dist/gadgets/string-animator/SgStringAnimator.d.ts.map +1 -0
  63. package/dist/gadgets/string-animator/SgStringAnimator.js +145 -0
  64. package/dist/gadgets/string-animator/index.d.ts +3 -0
  65. package/dist/gadgets/string-animator/index.d.ts.map +1 -0
  66. package/dist/gadgets/string-animator/index.js +1 -0
  67. package/dist/i18n/en-US.json +9 -1
  68. package/dist/i18n/es.json +55 -47
  69. package/dist/i18n/index.d.ts +32 -0
  70. package/dist/i18n/index.d.ts.map +1 -1
  71. package/dist/i18n/pt-BR.json +9 -1
  72. package/dist/i18n/pt-PT.json +9 -1
  73. package/dist/index.d.ts +46 -4
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +22 -1
  76. package/dist/inputs/SgAutocomplete.js +21 -5
  77. package/dist/inputs/SgCombobox.d.ts.map +1 -1
  78. package/dist/inputs/SgCombobox.js +8 -3
  79. package/dist/inputs/SgRadioGroup.d.ts +37 -0
  80. package/dist/inputs/SgRadioGroup.d.ts.map +1 -0
  81. package/dist/inputs/SgRadioGroup.js +139 -0
  82. package/dist/inputs/SgRating.d.ts +55 -0
  83. package/dist/inputs/SgRating.d.ts.map +1 -0
  84. package/dist/inputs/SgRating.js +135 -0
  85. package/dist/inputs/SgSlider.d.ts +20 -0
  86. package/dist/inputs/SgSlider.d.ts.map +1 -0
  87. package/dist/inputs/SgSlider.js +40 -0
  88. package/dist/inputs/SgStepperInput.d.ts +22 -0
  89. package/dist/inputs/SgStepperInput.d.ts.map +1 -0
  90. package/dist/inputs/SgStepperInput.js +51 -0
  91. package/dist/inputs/SgTextEditor.d.ts +1 -0
  92. package/dist/inputs/SgTextEditor.d.ts.map +1 -1
  93. package/dist/inputs/SgTextEditor.js +19 -3
  94. package/dist/layout/SgAccordion.d.ts +39 -0
  95. package/dist/layout/SgAccordion.d.ts.map +1 -0
  96. package/dist/layout/SgAccordion.js +116 -0
  97. package/dist/layout/SgBreadcrumb.d.ts +33 -0
  98. package/dist/layout/SgBreadcrumb.d.ts.map +1 -0
  99. package/dist/layout/SgBreadcrumb.js +121 -0
  100. package/dist/layout/SgCarousel.d.ts +43 -0
  101. package/dist/layout/SgCarousel.d.ts.map +1 -0
  102. package/dist/layout/SgCarousel.js +166 -0
  103. package/dist/layout/SgDockLayout.d.ts +14 -0
  104. package/dist/layout/SgDockLayout.d.ts.map +1 -1
  105. package/dist/layout/SgDockLayout.js +145 -13
  106. package/dist/layout/SgDockScreen.d.ts +15 -0
  107. package/dist/layout/SgDockScreen.d.ts.map +1 -0
  108. package/dist/layout/SgDockScreen.js +13 -0
  109. package/dist/layout/SgDockZone.d.ts.map +1 -1
  110. package/dist/layout/SgDockZone.js +36 -2
  111. package/dist/layout/SgExpandablePanel.d.ts +50 -0
  112. package/dist/layout/SgExpandablePanel.d.ts.map +1 -0
  113. package/dist/layout/SgExpandablePanel.js +302 -0
  114. package/dist/layout/SgMainPanel.d.ts.map +1 -1
  115. package/dist/layout/SgMainPanel.js +36 -14
  116. package/dist/layout/SgMenu.d.ts +91 -0
  117. package/dist/layout/SgMenu.d.ts.map +1 -0
  118. package/dist/layout/SgMenu.js +939 -0
  119. package/dist/layout/SgPageControl.d.ts +49 -0
  120. package/dist/layout/SgPageControl.d.ts.map +1 -0
  121. package/dist/layout/SgPageControl.js +152 -0
  122. package/dist/layout/SgPanel.d.ts.map +1 -1
  123. package/dist/layout/SgPanel.js +10 -1
  124. package/dist/layout/SgScreen.d.ts +2 -0
  125. package/dist/layout/SgScreen.d.ts.map +1 -1
  126. package/dist/layout/SgScreen.js +4 -2
  127. package/dist/layout/SgToolBar.d.ts +9 -3
  128. package/dist/layout/SgToolBar.d.ts.map +1 -1
  129. package/dist/layout/SgToolBar.js +461 -55
  130. package/dist/menus/SgDockMenu.d.ts +62 -0
  131. package/dist/menus/SgDockMenu.d.ts.map +1 -0
  132. package/dist/menus/SgDockMenu.js +480 -0
  133. package/dist/others/SgPlayground.js +72 -72
  134. package/package.json +72 -63
  135. package/dist/gadgets/flip-digit/SgFlipDigit.d.ts +0 -23
  136. package/dist/gadgets/flip-digit/SgFlipDigit.d.ts.map +0 -1
  137. package/dist/gadgets/flip-digit/SgFlipDigit.js +0 -118
  138. package/dist/gadgets/flip-digit/index.d.ts.map +0 -1
  139. /package/dist/{gadgets → digits}/flip-digit/index.d.ts +0 -0
  140. /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
+ }
@@ -16,6 +16,7 @@ export type SgTextEditorProps = {
16
16
  height?: number;
17
17
  placeholder?: string;
18
18
  disabled?: boolean;
19
+ borderRadius?: number | string;
19
20
  showCssEditor?: boolean;
20
21
  cssEditorLabel?: string;
21
22
  className?: string;
@@ -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;IAEnB,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,2CAgY9D;yBAhYe,YAAY"}
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
- 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", children: [_jsxs("select", { className: "h-9 rounded-md border px-2 text-sm bg-background", disabled: !editor || disabled, value: active("heading", { level: 1 })
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: { height }, 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" }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "CSS is embedded inside the saved HTML document." })] })) : null] }));
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"}