@seedgrid/fe-components 2026.3.11 → 2026.3.13

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 (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +181 -0
  3. package/dist/buttons/SgButton.d.ts +2 -0
  4. package/dist/buttons/SgButton.d.ts.map +1 -1
  5. package/dist/buttons/SgButton.js +4 -3
  6. package/dist/digits/roller3d-digit/SgRoller3DDigit.d.ts.map +1 -1
  7. package/dist/digits/roller3d-digit/SgRoller3DDigit.js +4 -2
  8. package/dist/digits/segment-digit/SgSegmentDigit.js +1 -1
  9. package/dist/gadgets/calendar/SgCalendar.js +1 -1
  10. package/dist/gadgets/clock/SgClock.d.ts.map +1 -1
  11. package/dist/gadgets/clock/SgClock.js +10 -5
  12. package/dist/gadgets/clock/themes/SgClockThemePicker.d.ts.map +1 -1
  13. package/dist/gadgets/clock/themes/SgClockThemePicker.js +3 -3
  14. package/dist/gadgets/clock/themes/renderTheme.d.ts.map +1 -1
  15. package/dist/gadgets/clock/themes/renderTheme.js +3 -1
  16. package/dist/gadgets/clock/themes/useDarkFlag.d.ts.map +1 -1
  17. package/dist/gadgets/clock/themes/useDarkFlag.js +34 -3
  18. package/dist/inputs/SgAutocomplete.js +3 -3
  19. package/dist/inputs/SgCombobox.js +4 -4
  20. package/dist/inputs/SgDatatable.js +3 -3
  21. package/dist/inputs/SgInputCurrency.d.ts.map +1 -1
  22. package/dist/inputs/SgInputCurrency.js +5 -3
  23. package/dist/inputs/SgInputDate.js +2 -2
  24. package/dist/inputs/SgInputNumber.d.ts.map +1 -1
  25. package/dist/inputs/SgInputNumber.js +8 -4
  26. package/dist/inputs/SgInputOTP.js +1 -1
  27. package/dist/inputs/SgInputSelect.js +3 -3
  28. package/dist/inputs/SgInputText.d.ts.map +1 -1
  29. package/dist/inputs/SgInputText.js +8 -4
  30. package/dist/inputs/SgInputTextArea.d.ts.map +1 -1
  31. package/dist/inputs/SgInputTextArea.js +8 -4
  32. package/dist/inputs/SgOrderList.js +2 -2
  33. package/dist/inputs/SgPickList.js +3 -3
  34. package/dist/inputs/SgTextEditor.d.ts.map +1 -1
  35. package/dist/inputs/SgTextEditor.js +9 -4
  36. package/dist/inputs/SgToggleSwitch.js +1 -1
  37. package/dist/layout/SgCarousel.js +3 -3
  38. package/dist/layout/SgGroupBox.js +1 -1
  39. package/dist/layout/SgMenu.js +1 -1
  40. package/dist/menus/SgDockMenu.d.ts.map +1 -1
  41. package/dist/menus/SgDockMenu.js +20 -10
  42. package/dist/others/SgPlayground.d.ts.map +1 -1
  43. package/dist/others/SgPlayground.js +24 -1
  44. package/dist/overlay/SgDialog.d.ts.map +1 -1
  45. package/dist/overlay/SgDialog.js +203 -1
  46. package/dist/sandbox.cjs +80 -80
  47. package/dist/wizard/SgWizard.js +4 -4
  48. package/package.json +5 -4
@@ -383,6 +383,7 @@ const SANDPACK_NODE_FS_PROMISES_PACKAGE_JSON_SHIM = JSON.stringify({
383
383
  module: "index.js"
384
384
  });
385
385
  const SANDPACK_FALLBACK_THEME_VARS = {
386
+ "--sg-mode": "light",
386
387
  // shadcn/ui design tokens (HSL)
387
388
  "--background": "0 0% 100%",
388
389
  "--foreground": "222.2 84% 4.9%",
@@ -564,6 +565,7 @@ const SANDPACK_CORE_THEME_VARS = [
564
565
  // CSSStyleDeclaration.length/.item() does NOT enumerate CSS custom properties,
565
566
  // so we must call getPropertyValue() for each var by name.
566
567
  const SANDPACK_SG_VARS = [
568
+ "--sg-mode",
567
569
  // Neutrals
568
570
  "--sg-bg", "--sg-surface", "--sg-muted-surface",
569
571
  "--sg-text", "--sg-muted", "--sg-border", "--sg-ring",
@@ -856,6 +858,25 @@ function readThemeVarsFromHost() {
856
858
  Object.assign(themeVars, mapSgVarsToCoreVars(themeVars));
857
859
  return themeVars;
858
860
  }
861
+ function resolveSandpackThemeFromHost() {
862
+ if (typeof window === "undefined")
863
+ return "light";
864
+ const root = document.documentElement;
865
+ const computed = window.getComputedStyle(root);
866
+ const mode = computed.getPropertyValue("--sg-mode").trim().toLowerCase();
867
+ if (mode === "dark")
868
+ return "dark";
869
+ if (mode === "light")
870
+ return "light";
871
+ const dataTheme = root.getAttribute("data-theme")?.trim().toLowerCase();
872
+ if (dataTheme === "dark")
873
+ return "dark";
874
+ if (dataTheme === "light")
875
+ return "light";
876
+ if (root.classList.contains("dark"))
877
+ return "dark";
878
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
879
+ }
859
880
  function getStyleSheetHref(styleSheet) {
860
881
  const cssSheet = styleSheet;
861
882
  if (cssSheet.href)
@@ -1035,6 +1056,7 @@ export default function SgPlayground(props) {
1035
1056
  const { code, interactive = false, codeContract = "renderBody", preset = "auto", title, description, height = 360, expandedHeight = "70vh", expandable = true, resizable = true, resizeAxis = "vertical", previewPadding, className, style, dependencies, defaultImports, previewWrapperClassName = "h-[420px] rounded-xl border border-border bg-muted/30 p-3", seedgridDependency, bundlerURL, bundlerTimeoutMs, npmRegistries, withCard = true, collapsible = true, defaultOpen = true, cardId } = props;
1036
1057
  const effectivePreviewPadding = normalizeCssSize(previewPadding ?? (codeContract === "appFile" ? 12 : 0));
1037
1058
  const [sandpackStylesCss, setSandpackStylesCss] = React.useState(() => buildSandpackStylesCss({}, effectivePreviewPadding));
1059
+ const [sandpackTheme, setSandpackTheme] = React.useState(() => resolveSandpackThemeFromHost());
1038
1060
  const [isExpanded, setIsExpanded] = React.useState(false);
1039
1061
  const [activePanel, setActivePanel] = React.useState("code");
1040
1062
  React.useEffect(() => {
@@ -1045,6 +1067,7 @@ export default function SgPlayground(props) {
1045
1067
  const liveThemeVars = readThemeVarsFromHost();
1046
1068
  const hostCss = readHostNextCssText();
1047
1069
  setSandpackStylesCss(buildSandpackStylesCss(liveThemeVars, effectivePreviewPadding, hostCss));
1070
+ setSandpackTheme(resolveSandpackThemeFromHost());
1048
1071
  };
1049
1072
  let frameId = null;
1050
1073
  const scheduleRefresh = () => {
@@ -1427,7 +1450,7 @@ export default function SgPlayground(props) {
1427
1450
  visibleFiles: ["/App.tsx"],
1428
1451
  externalResources: includeSeedgridDependency ? SANDPACK_EXTERNAL_RESOURCES : []
1429
1452
  }), [includeSeedgridDependency, resolvedBundlerTimeoutMs, resolvedBundlerURL]);
1430
- const content = interactive ? (_jsx("div", { className: cn(withCard ? "" : "rounded-lg border border-border", withCard ? undefined : className), style: withCard ? undefined : style, children: _jsxs(SandpackProvider, { template: "react-ts", files: files, customSetup: sandpackCustomSetup, options: sandpackOptions, children: [_jsx("style", { children: SANDPACK_HOST_STYLES_CSS }), _jsxs("div", { className: "flex items-center justify-between border-b border-border px-3 py-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [withCard ? null : _jsx("span", { className: "text-sm font-medium", children: title ?? "Example" }), _jsx("span", { className: "text-xs text-muted-foreground", children: codeContract === "renderBody" ? "editable snippet" : "editable App.tsx" })] }), _jsxs("div", { className: "flex items-center gap-2", children: [expandable ? (_jsx(SgButton, { appearance: "outline", size: "sm", onClick: () => setIsExpanded((prev) => !prev), children: isExpanded ? "Reduzir" : "Expandir" })) : null, _jsx(RunButton, { onRun: () => setActivePanel("preview") })] })] }), _jsxs("div", { className: "flex md:hidden border-b border-border", children: [_jsx("button", { type: "button", className: cn("flex-1 py-2 text-sm font-medium border-b-2 -mb-px transition-colors", activePanel === "code"
1453
+ const content = interactive ? (_jsx("div", { className: cn(withCard ? "" : "rounded-lg border border-border", withCard ? undefined : className), style: withCard ? undefined : style, children: _jsxs(SandpackProvider, { template: "react-ts", files: files, customSetup: sandpackCustomSetup, options: sandpackOptions, theme: sandpackTheme, children: [_jsx("style", { children: SANDPACK_HOST_STYLES_CSS }), _jsxs("div", { className: "flex items-center justify-between border-b border-border px-3 py-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [withCard ? null : _jsx("span", { className: "text-sm font-medium", children: title ?? "Example" }), _jsx("span", { className: "text-xs text-muted-foreground", children: codeContract === "renderBody" ? "editable snippet" : "editable App.tsx" })] }), _jsxs("div", { className: "flex items-center gap-2", children: [expandable ? (_jsx(SgButton, { appearance: "outline", size: "sm", onClick: () => setIsExpanded((prev) => !prev), children: isExpanded ? "Reduzir" : "Expandir" })) : null, _jsx(RunButton, { onRun: () => setActivePanel("preview") })] })] }), _jsxs("div", { className: "flex md:hidden border-b border-border", children: [_jsx("button", { type: "button", className: cn("flex-1 py-2 text-sm font-medium border-b-2 -mb-px transition-colors", activePanel === "code"
1431
1454
  ? "border-primary text-foreground"
1432
1455
  : "border-transparent text-muted-foreground hover:text-foreground"), onClick: () => setActivePanel("code"), children: "C\u00F3digo" }), _jsx("button", { type: "button", className: cn("flex-1 py-2 text-sm font-medium border-b-2 -mb-px transition-colors", activePanel === "preview"
1433
1456
  ? "border-primary text-foreground"
@@ -1 +1 @@
1
- {"version":3,"file":"SgDialog.d.ts","sourceRoot":"","sources":["../../src/overlay/SgDialog.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;AAC9D,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,WAAW,GACX,SAAS,GACT,MAAM,GACN,SAAS,GACT,MAAM,GACN,QAAQ,GACR,OAAO,CAAC;AACZ,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAE5D,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAEzB,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,WAAW,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC;IACrD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;IAC3E,gCAAgC;IAChC,MAAM,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;IAC1C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,eAAe,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAC/C,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AA2EF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,4BAmQtD;yBAnQe,QAAQ"}
1
+ {"version":3,"file":"SgDialog.d.ts","sourceRoot":"","sources":["../../src/overlay/SgDialog.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;AAC9D,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,WAAW,GACX,SAAS,GACT,MAAM,GACN,SAAS,GACT,MAAM,GACN,QAAQ,GACR,OAAO,CAAC;AACZ,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAE5D,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAEzB,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,WAAW,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC;IACrD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;IAC3E,gCAAgC;IAChC,MAAM,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;IAC1C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,eAAe,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAC/C,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAsRF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,4BA4QtD;yBA5Qe,QAAQ"}
@@ -69,6 +69,199 @@ function resolveDialogShadow(elevation, shadow) {
69
69
  return elevation;
70
70
  }
71
71
  }
72
+ function clampByte(value) {
73
+ return Math.min(255, Math.max(0, Math.round(value)));
74
+ }
75
+ function parseHexColor(input) {
76
+ const hex = input.replace("#", "").trim();
77
+ if (!hex)
78
+ return null;
79
+ if (hex.length === 3 || hex.length === 4) {
80
+ const r = Number.parseInt((hex.slice(0, 1) || "0").repeat(2), 16);
81
+ const g = Number.parseInt((hex.slice(1, 2) || "0").repeat(2), 16);
82
+ const b = Number.parseInt((hex.slice(2, 3) || "0").repeat(2), 16);
83
+ if (!Number.isFinite(r) || !Number.isFinite(g) || !Number.isFinite(b))
84
+ return null;
85
+ return { r, g, b };
86
+ }
87
+ if (hex.length === 6 || hex.length === 8) {
88
+ const r = Number.parseInt(hex.slice(0, 2), 16);
89
+ const g = Number.parseInt(hex.slice(2, 4), 16);
90
+ const b = Number.parseInt(hex.slice(4, 6), 16);
91
+ if (!Number.isFinite(r) || !Number.isFinite(g) || !Number.isFinite(b))
92
+ return null;
93
+ return { r, g, b };
94
+ }
95
+ return null;
96
+ }
97
+ function parseRgbChannel(token) {
98
+ const value = token.trim();
99
+ if (!value)
100
+ return null;
101
+ if (value.endsWith("%")) {
102
+ const numeric = Number.parseFloat(value.slice(0, -1));
103
+ if (!Number.isFinite(numeric))
104
+ return null;
105
+ return clampByte((numeric / 100) * 255);
106
+ }
107
+ const numeric = Number.parseFloat(value);
108
+ if (!Number.isFinite(numeric))
109
+ return null;
110
+ return clampByte(numeric);
111
+ }
112
+ function parseRgbColor(input) {
113
+ const match = input.match(/^rgba?\((.+)\)$/i);
114
+ if (!match)
115
+ return null;
116
+ const raw = match[1]?.trim() ?? "";
117
+ const withoutAlpha = raw.replace(/\s*\/\s*[\d.]+%?\s*$/, "");
118
+ const tokens = withoutAlpha.includes(",")
119
+ ? withoutAlpha.split(",")
120
+ : withoutAlpha.split(/\s+/);
121
+ if (tokens.length < 3)
122
+ return null;
123
+ const r = parseRgbChannel(tokens[0] ?? "");
124
+ const g = parseRgbChannel(tokens[1] ?? "");
125
+ const b = parseRgbChannel(tokens[2] ?? "");
126
+ if (r === null || g === null || b === null)
127
+ return null;
128
+ return { r, g, b };
129
+ }
130
+ function parseHue(token) {
131
+ const value = token.trim().toLowerCase();
132
+ if (!value)
133
+ return null;
134
+ if (value.endsWith("turn")) {
135
+ const numeric = Number.parseFloat(value.slice(0, -4));
136
+ if (!Number.isFinite(numeric))
137
+ return null;
138
+ return numeric * 360;
139
+ }
140
+ if (value.endsWith("rad")) {
141
+ const numeric = Number.parseFloat(value.slice(0, -3));
142
+ if (!Number.isFinite(numeric))
143
+ return null;
144
+ return (numeric * 180) / Math.PI;
145
+ }
146
+ if (value.endsWith("deg")) {
147
+ const numeric = Number.parseFloat(value.slice(0, -3));
148
+ if (!Number.isFinite(numeric))
149
+ return null;
150
+ return numeric;
151
+ }
152
+ const numeric = Number.parseFloat(value);
153
+ return Number.isFinite(numeric) ? numeric : null;
154
+ }
155
+ function parsePercent(token) {
156
+ const value = token.trim();
157
+ if (!value.endsWith("%"))
158
+ return null;
159
+ const numeric = Number.parseFloat(value.slice(0, -1));
160
+ if (!Number.isFinite(numeric))
161
+ return null;
162
+ return Math.min(100, Math.max(0, numeric));
163
+ }
164
+ function hslToRgb(h, s, l) {
165
+ const sat = Math.min(1, Math.max(0, s / 100));
166
+ const lig = Math.min(1, Math.max(0, l / 100));
167
+ const hue = ((h % 360) + 360) % 360;
168
+ const c = (1 - Math.abs(2 * lig - 1)) * sat;
169
+ const x = c * (1 - Math.abs(((hue / 60) % 2) - 1));
170
+ const m = lig - c / 2;
171
+ let r = 0;
172
+ let g = 0;
173
+ let b = 0;
174
+ if (hue < 60) {
175
+ r = c;
176
+ g = x;
177
+ }
178
+ else if (hue < 120) {
179
+ r = x;
180
+ g = c;
181
+ }
182
+ else if (hue < 180) {
183
+ g = c;
184
+ b = x;
185
+ }
186
+ else if (hue < 240) {
187
+ g = x;
188
+ b = c;
189
+ }
190
+ else if (hue < 300) {
191
+ r = x;
192
+ b = c;
193
+ }
194
+ else {
195
+ r = c;
196
+ b = x;
197
+ }
198
+ return {
199
+ r: clampByte((r + m) * 255),
200
+ g: clampByte((g + m) * 255),
201
+ b: clampByte((b + m) * 255)
202
+ };
203
+ }
204
+ function parseHslColor(input) {
205
+ const match = input.match(/^hsla?\((.+)\)$/i);
206
+ if (!match)
207
+ return null;
208
+ const raw = match[1]?.trim() ?? "";
209
+ const withoutAlpha = raw.replace(/\s*\/\s*[\d.]+%?\s*$/, "");
210
+ const tokens = withoutAlpha.includes(",")
211
+ ? withoutAlpha.split(",")
212
+ : withoutAlpha.split(/\s+/);
213
+ if (tokens.length < 3)
214
+ return null;
215
+ const h = parseHue(tokens[0] ?? "");
216
+ const s = parsePercent(tokens[1] ?? "");
217
+ const l = parsePercent(tokens[2] ?? "");
218
+ if (h === null || s === null || l === null)
219
+ return null;
220
+ return hslToRgb(h, s, l);
221
+ }
222
+ function parseCssColorToRgb(color) {
223
+ const input = color.trim();
224
+ if (!input)
225
+ return null;
226
+ if (input.startsWith("#"))
227
+ return parseHexColor(input);
228
+ if (/^rgba?\(/i.test(input))
229
+ return parseRgbColor(input);
230
+ if (/^hsla?\(/i.test(input))
231
+ return parseHslColor(input);
232
+ return null;
233
+ }
234
+ function relativeLuminance({ r, g, b }) {
235
+ const normalize = (channel) => {
236
+ const n = channel / 255;
237
+ return n <= 0.03928 ? n / 12.92 : ((n + 0.055) / 1.055) ** 2.4;
238
+ };
239
+ return 0.2126 * normalize(r) + 0.7152 * normalize(g) + 0.0722 * normalize(b);
240
+ }
241
+ function resolveCustomSurfacePalette(backgroundColor) {
242
+ if (typeof backgroundColor !== "string")
243
+ return null;
244
+ const parsed = parseCssColorToRgb(backgroundColor);
245
+ if (!parsed)
246
+ return null;
247
+ const lightSurface = relativeLuminance(parsed) >= 0.56;
248
+ if (lightSurface) {
249
+ return {
250
+ foreground: "rgb(17 24 39)",
251
+ mutedForeground: "rgb(71 85 105)",
252
+ border: "rgba(15, 23, 42, 0.16)",
253
+ hoverBg: "rgba(15, 23, 42, 0.08)",
254
+ activeBg: "rgba(15, 23, 42, 0.14)"
255
+ };
256
+ }
257
+ return {
258
+ foreground: "rgb(243 244 246)",
259
+ mutedForeground: "rgb(203 213 225)",
260
+ border: "rgba(248, 250, 252, 0.18)",
261
+ hoverBg: "rgba(248, 250, 252, 0.08)",
262
+ activeBg: "rgba(248, 250, 252, 0.14)"
263
+ };
264
+ }
72
265
  export function SgDialog(props) {
73
266
  const { open: openProp, onOpenChange, defaultOpen = false, title, subtitle, leading, trailing, children, footer, size = "md", severity = "plain", animation = "zoom", transitionMs = 160, autoCloseMs, className, style, customColor, elevation, shadow, showTopAccent = true, overlayClassName, contentClassName, headerClassName, bodyClassName, footerClassName, closeable = true, onClose, closeOnOverlayClick = true, closeOnEsc = true, lockBodyScroll = true, initialFocusRef, restoreFocus = true, ariaLabel } = props;
74
267
  const isControlled = openProp !== undefined;
@@ -188,13 +381,22 @@ export function SgDialog(props) {
188
381
  "max-h-[85vh] flex flex-col transition duration-150 ease-out" +
189
382
  (showTopAccent ? " border-t-4" : "");
190
383
  const resolvedShadow = resolveDialogShadow(elevation, shadow);
384
+ const customPalette = resolveCustomSurfacePalette(customColor);
385
+ const dialogVars = {
386
+ "--sg-dialog-muted-foreground": customPalette?.mutedForeground ?? "hsl(var(--muted-foreground))",
387
+ "--sg-dialog-divider": customPalette?.border ?? "hsl(var(--border))",
388
+ "--sg-dialog-hover-bg": customPalette?.hoverBg ?? "hsl(var(--muted) / 0.6)",
389
+ "--sg-dialog-active-bg": customPalette?.activeBg ?? "hsl(var(--muted))"
390
+ };
191
391
  const transitionStyle = { transitionDuration: `${transitionMs}ms` };
192
392
  const contentStyle = {
393
+ ...dialogVars,
193
394
  ...transitionStyle,
194
395
  ...(customColor !== undefined ? { backgroundColor: customColor } : {}),
396
+ ...(customPalette ? { color: customPalette.foreground, borderColor: customPalette.border } : {}),
195
397
  ...(resolvedShadow !== undefined ? { boxShadow: resolvedShadow } : {})
196
398
  };
197
- return createPortal(_jsxs("div", { className: cn("fixed inset-0 z-[1000]", className), style: style, role: "dialog", "aria-modal": "true", "aria-label": a11yLabel, children: [_jsx("div", { ref: overlayRef, onMouseDown: onOverlayMouseDown, className: cn(overlayBase, overlayState, overlayClassName), style: transitionStyle }), _jsx("div", { className: "fixed inset-0 flex items-center justify-center p-4", children: _jsxs("div", { ref: contentRef, className: cn(contentBase, sizeClass(size), contentStateClass(animation, entered), showTopAccent ? severityClass(severity) : false, contentClassName), style: contentStyle, children: [(title || subtitle || closeable || leading || trailing) && (_jsxs("div", { className: cn("px-5 py-4 border-b border-border flex items-start gap-3", headerClassName), children: [leading ? _jsx("div", { className: "shrink-0 pt-0.5", children: leading }) : null, _jsxs("div", { className: "min-w-0 flex-1", children: [title ? _jsx("div", { className: "text-base font-semibold leading-6", children: title }) : null, subtitle ? _jsx("div", { className: "text-sm text-muted-foreground mt-1", children: subtitle }) : null] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [trailing ? _jsx("div", { className: "shrink-0", children: trailing }) : null, closeable ? (_jsx("button", { type: "button", onClick: close, className: cn("inline-flex items-center justify-center h-9 w-9 rounded-lg", "hover:bg-muted/60 active:bg-muted", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--ring,var(--primary)))]"), "aria-label": "Close", children: _jsx(CloseIcon, {}) })) : null] })] })), _jsx("div", { className: cn("px-5 py-4 overflow-auto", bodyClassName), children: children }), footer ? (_jsx("div", { className: cn("px-5 py-4 border-t border-border flex items-center justify-end gap-2", footerClassName), children: footer })) : null] }) })] }), document.body);
399
+ return createPortal(_jsxs("div", { className: cn("fixed inset-0 z-[1000]", className), style: style, role: "dialog", "aria-modal": "true", "aria-label": a11yLabel, children: [_jsx("div", { ref: overlayRef, onMouseDown: onOverlayMouseDown, className: cn(overlayBase, overlayState, overlayClassName), style: transitionStyle }), _jsx("div", { className: "fixed inset-0 flex items-center justify-center p-4", children: _jsxs("div", { ref: contentRef, className: cn(contentBase, sizeClass(size), contentStateClass(animation, entered), showTopAccent ? severityClass(severity) : false, contentClassName), style: contentStyle, children: [(title || subtitle || closeable || leading || trailing) && (_jsxs("div", { className: cn("px-5 py-4 border-b border-[var(--sg-dialog-divider)] flex items-start gap-3", headerClassName), children: [leading ? _jsx("div", { className: "shrink-0 pt-0.5", children: leading }) : null, _jsxs("div", { className: "min-w-0 flex-1", children: [title ? _jsx("div", { className: "text-base font-semibold leading-6", children: title }) : null, subtitle ? _jsx("div", { className: "mt-1 text-sm text-[var(--sg-dialog-muted-foreground)]", children: subtitle }) : null] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [trailing ? _jsx("div", { className: "shrink-0", children: trailing }) : null, closeable ? (_jsx("button", { type: "button", onClick: close, className: cn("inline-flex items-center justify-center h-9 w-9 rounded-lg", "hover:bg-[var(--sg-dialog-hover-bg)] active:bg-[var(--sg-dialog-active-bg)]", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--ring,var(--primary)))]"), "aria-label": "Close", children: _jsx(CloseIcon, {}) })) : null] })] })), _jsx("div", { className: cn("px-5 py-4 overflow-auto", bodyClassName), children: children }), footer ? (_jsx("div", { className: cn("px-5 py-4 border-t border-[var(--sg-dialog-divider)] flex items-center justify-end gap-2", footerClassName), children: footer })) : null] }) })] }), document.body);
198
400
  }
199
401
  function CloseIcon() {
200
402
  return (_jsx("svg", { viewBox: "0 0 24 24", className: "size-5", "aria-hidden": "true", children: _jsx("path", { d: "M18 6L6 18M6 6l12 12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }));