@seedgrid/fe-components 2026.3.20 → 2026.3.27

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 (174) hide show
  1. package/dist/buttons/SgFloatActionButton.d.ts.map +1 -1
  2. package/dist/buttons/SgFloatActionButton.js +5 -26
  3. package/dist/buttons/SgSplitButton.d.ts.map +1 -1
  4. package/dist/buttons/SgSplitButton.js +3 -1
  5. package/dist/buttons/fab-helpers.d.ts +6 -0
  6. package/dist/buttons/fab-helpers.d.ts.map +1 -0
  7. package/dist/buttons/fab-helpers.js +29 -0
  8. package/dist/commons/SgAvatar.d.ts.map +1 -1
  9. package/dist/commons/SgAvatar.js +6 -3
  10. package/dist/commons/SgBadge.d.ts.map +1 -1
  11. package/dist/commons/SgBadge.js +5 -2
  12. package/dist/commons/SgToast.d.ts.map +1 -1
  13. package/dist/commons/SgToast.js +3 -1
  14. package/dist/commons/SgToaster.d.ts.map +1 -1
  15. package/dist/commons/SgToaster.js +3 -1
  16. package/dist/environment/SgEnvironmentProvider.d.ts.map +1 -1
  17. package/dist/environment/SgEnvironmentProvider.js +10 -15
  18. package/dist/environment/persistent-state.d.ts +22 -0
  19. package/dist/environment/persistent-state.d.ts.map +1 -0
  20. package/dist/environment/persistent-state.js +33 -0
  21. package/dist/gadgets/calendar/SgCalendar.d.ts.map +1 -1
  22. package/dist/gadgets/calendar/SgCalendar.js +5 -23
  23. package/dist/gadgets/clock/SgClock.d.ts.map +1 -1
  24. package/dist/gadgets/clock/SgClock.js +12 -10
  25. package/dist/gadgets/clock/themes/SgClockThemePicker.d.ts +2 -1
  26. package/dist/gadgets/clock/themes/SgClockThemePicker.d.ts.map +1 -1
  27. package/dist/gadgets/clock/themes/SgClockThemePicker.js +23 -28
  28. package/dist/gadgets/clock/themes/search.d.ts +9 -0
  29. package/dist/gadgets/clock/themes/search.d.ts.map +1 -0
  30. package/dist/gadgets/clock/themes/search.js +15 -0
  31. package/dist/gadgets/gauge/SgLinearGauge.d.ts.map +1 -1
  32. package/dist/gadgets/gauge/SgLinearGauge.js +39 -28
  33. package/dist/gadgets/gauge/SgRadialGauge.d.ts.map +1 -1
  34. package/dist/gadgets/gauge/SgRadialGauge.js +44 -37
  35. package/dist/gadgets/gauge/math.d.ts +90 -0
  36. package/dist/gadgets/gauge/math.d.ts.map +1 -0
  37. package/dist/gadgets/gauge/math.js +81 -0
  38. package/dist/gadgets/qr-code/SgQRCode.d.ts.map +1 -1
  39. package/dist/gadgets/qr-code/SgQRCode.js +3 -1
  40. package/dist/i18n/en-US.d.ts.map +1 -1
  41. package/dist/i18n/en-US.js +99 -1
  42. package/dist/i18n/es.d.ts.map +1 -1
  43. package/dist/i18n/es.js +155 -57
  44. package/dist/i18n/fr.d.ts +3 -0
  45. package/dist/i18n/fr.d.ts.map +1 -0
  46. package/dist/i18n/fr.js +208 -0
  47. package/dist/i18n/index.d.ts +5 -1
  48. package/dist/i18n/index.d.ts.map +1 -1
  49. package/dist/i18n/index.js +50 -14
  50. package/dist/i18n/pt-BR.d.ts.map +1 -1
  51. package/dist/i18n/pt-BR.js +99 -1
  52. package/dist/i18n/pt-PT.d.ts.map +1 -1
  53. package/dist/i18n/pt-PT.js +99 -1
  54. package/dist/index.d.ts +12 -2
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +10 -2
  57. package/dist/inputs/SgAutocomplete.d.ts +1 -1
  58. package/dist/inputs/SgAutocomplete.d.ts.map +1 -1
  59. package/dist/inputs/SgAutocomplete.js +7 -4
  60. package/dist/inputs/SgCheckboxGroup.d.ts +2 -6
  61. package/dist/inputs/SgCheckboxGroup.d.ts.map +1 -1
  62. package/dist/inputs/SgCheckboxGroup.js +6 -6
  63. package/dist/inputs/SgCombobox.d.ts.map +1 -1
  64. package/dist/inputs/SgCombobox.js +11 -2
  65. package/dist/inputs/SgDatatable.d.ts.map +1 -1
  66. package/dist/inputs/SgDatatable.js +10 -10
  67. package/dist/inputs/SgInputBirthDate.d.ts.map +1 -1
  68. package/dist/inputs/SgInputBirthDate.js +6 -1
  69. package/dist/inputs/SgInputCNPJ.d.ts +3 -1
  70. package/dist/inputs/SgInputCNPJ.d.ts.map +1 -1
  71. package/dist/inputs/SgInputCNPJ.js +4 -3
  72. package/dist/inputs/SgInputCPF.d.ts +3 -1
  73. package/dist/inputs/SgInputCPF.d.ts.map +1 -1
  74. package/dist/inputs/SgInputCPF.js +8 -3
  75. package/dist/inputs/SgInputCPFCNPJ.d.ts +3 -1
  76. package/dist/inputs/SgInputCPFCNPJ.d.ts.map +1 -1
  77. package/dist/inputs/SgInputCPFCNPJ.js +8 -3
  78. package/dist/inputs/SgInputCurrency.d.ts +3 -7
  79. package/dist/inputs/SgInputCurrency.d.ts.map +1 -1
  80. package/dist/inputs/SgInputCurrency.js +5 -2
  81. package/dist/inputs/SgInputDate.d.ts.map +1 -1
  82. package/dist/inputs/SgInputDate.js +6 -1
  83. package/dist/inputs/SgInputEmail.d.ts.map +1 -1
  84. package/dist/inputs/SgInputEmail.js +1 -1
  85. package/dist/inputs/SgInputNumber.d.ts +3 -7
  86. package/dist/inputs/SgInputNumber.d.ts.map +1 -1
  87. package/dist/inputs/SgInputNumber.js +5 -2
  88. package/dist/inputs/SgInputOTP.d.ts +5 -12
  89. package/dist/inputs/SgInputOTP.d.ts.map +1 -1
  90. package/dist/inputs/SgInputOTP.js +7 -4
  91. package/dist/inputs/SgInputPassword.d.ts.map +1 -1
  92. package/dist/inputs/SgInputPassword.js +1 -1
  93. package/dist/inputs/SgInputPhone.d.ts +3 -1
  94. package/dist/inputs/SgInputPhone.d.ts.map +1 -1
  95. package/dist/inputs/SgInputPhone.js +2 -1
  96. package/dist/inputs/SgInputPostalCode.d.ts.map +1 -1
  97. package/dist/inputs/SgInputPostalCode.js +2 -1
  98. package/dist/inputs/SgInputSelect.d.ts +4 -2
  99. package/dist/inputs/SgInputSelect.d.ts.map +1 -1
  100. package/dist/inputs/SgInputSelect.js +38 -3
  101. package/dist/inputs/SgInputText.d.ts +3 -7
  102. package/dist/inputs/SgInputText.d.ts.map +1 -1
  103. package/dist/inputs/SgInputText.js +5 -2
  104. package/dist/inputs/SgInputTextArea.d.ts +4 -2
  105. package/dist/inputs/SgInputTextArea.d.ts.map +1 -1
  106. package/dist/inputs/SgInputTextArea.js +37 -2
  107. package/dist/inputs/SgOrderList.d.ts +3 -1
  108. package/dist/inputs/SgOrderList.d.ts.map +1 -1
  109. package/dist/inputs/SgOrderList.js +24 -8
  110. package/dist/inputs/SgPickList.d.ts +3 -1
  111. package/dist/inputs/SgPickList.d.ts.map +1 -1
  112. package/dist/inputs/SgPickList.js +33 -17
  113. package/dist/inputs/SgRadioGroup.d.ts +2 -6
  114. package/dist/inputs/SgRadioGroup.d.ts.map +1 -1
  115. package/dist/inputs/SgRadioGroup.js +6 -6
  116. package/dist/inputs/SgRating.d.ts +2 -10
  117. package/dist/inputs/SgRating.d.ts.map +1 -1
  118. package/dist/inputs/SgRating.js +6 -3
  119. package/dist/inputs/SgSlider.d.ts +8 -2
  120. package/dist/inputs/SgSlider.d.ts.map +1 -1
  121. package/dist/inputs/SgSlider.js +62 -10
  122. package/dist/inputs/SgStepperInput.d.ts +8 -2
  123. package/dist/inputs/SgStepperInput.d.ts.map +1 -1
  124. package/dist/inputs/SgStepperInput.js +62 -8
  125. package/dist/inputs/SgTextEditor.d.ts +3 -1
  126. package/dist/inputs/SgTextEditor.d.ts.map +1 -1
  127. package/dist/inputs/SgTextEditor.js +30 -16
  128. package/dist/inputs/SgToggleSwitch.d.ts +3 -7
  129. package/dist/inputs/SgToggleSwitch.d.ts.map +1 -1
  130. package/dist/inputs/SgToggleSwitch.js +6 -3
  131. package/dist/layout/SgBreadcrumb.d.ts.map +1 -1
  132. package/dist/layout/SgBreadcrumb.js +7 -3
  133. package/dist/layout/SgCard.d.ts.map +1 -1
  134. package/dist/layout/SgCard.js +3 -1
  135. package/dist/layout/SgCarousel.d.ts.map +1 -1
  136. package/dist/layout/SgCarousel.js +3 -1
  137. package/dist/layout/SgExpandablePanel.d.ts.map +1 -1
  138. package/dist/layout/SgExpandablePanel.js +3 -1
  139. package/dist/layout/SgMenu.d.ts.map +1 -1
  140. package/dist/layout/SgMenu.js +174 -298
  141. package/dist/layout/SgPageControl.d.ts.map +1 -1
  142. package/dist/layout/SgPageControl.js +7 -3
  143. package/dist/layout/SgToolBar.d.ts.map +1 -1
  144. package/dist/layout/SgToolBar.js +19 -55
  145. package/dist/layout/SgTreeView.d.ts.map +1 -1
  146. package/dist/layout/SgTreeView.js +7 -3
  147. package/dist/layout/drag-position.d.ts +7 -0
  148. package/dist/layout/drag-position.d.ts.map +1 -0
  149. package/dist/layout/drag-position.js +30 -0
  150. package/dist/layout/menu-logic.d.ts +187 -0
  151. package/dist/layout/menu-logic.d.ts.map +1 -0
  152. package/dist/layout/menu-logic.js +349 -0
  153. package/dist/layout/toolbar-logic.d.ts +26 -0
  154. package/dist/layout/toolbar-logic.d.ts.map +1 -0
  155. package/dist/layout/toolbar-logic.js +38 -0
  156. package/dist/menus/SgDockMenu.d.ts.map +1 -1
  157. package/dist/menus/SgDockMenu.js +44 -120
  158. package/dist/menus/dock-menu-logic.d.ts +50 -0
  159. package/dist/menus/dock-menu-logic.d.ts.map +1 -0
  160. package/dist/menus/dock-menu-logic.js +113 -0
  161. package/dist/overlay/SgDialog.d.ts.map +1 -1
  162. package/dist/overlay/SgDialog.js +4 -2
  163. package/dist/overlay/SgPopup.d.ts.map +1 -1
  164. package/dist/overlay/SgPopup.js +4 -1
  165. package/dist/rhf.d.ts +8 -3
  166. package/dist/rhf.d.ts.map +1 -1
  167. package/dist/rhf.js +18 -1
  168. package/dist/sandbox.cjs +64 -64
  169. package/dist/wizard/SgWizard.d.ts.map +1 -1
  170. package/dist/wizard/SgWizard.js +20 -32
  171. package/dist/wizard/logic.d.ts +9 -0
  172. package/dist/wizard/logic.d.ts.map +1 -0
  173. package/dist/wizard/logic.js +20 -0
  174. package/package.json +8 -6
@@ -93,6 +93,7 @@ function buildRange(min, max) {
93
93
  return out;
94
94
  }
95
95
  function AnalogClock({ size = 280, initialServerTime, timezone, locale = "pt-BR", showSeconds = true, secondHandMode = "step", themeId = "classic", theme, className, style, centerOverlay }) {
96
+ const i18n = useComponentsI18n();
96
97
  const { nowMs, hasProvider, providerTick } = useClockNowMs(initialServerTime);
97
98
  void providerTick;
98
99
  useSecondTick(!hasProvider);
@@ -107,9 +108,10 @@ function AnalogClock({ size = 280, initialServerTime, timezone, locale = "pt-BR"
107
108
  const hourDeg = (((h % 12) + m / 60 + sec / 3600) / 12) * 360;
108
109
  const themeObj = theme ??
109
110
  (resolver ? resolveTheme(resolver, themeId, "classic") : getTheme(themeId) ?? getTheme("classic"));
110
- return (_jsx("div", { className: className, style: style, children: _jsxs("svg", { width: size, height: size, viewBox: "0 0 100 100", className: cn("block", dark ? "dark" : undefined), "aria-label": "Analog clock", children: [_jsx("g", { id: "theme", children: themeObj ? _jsx(ThemeLayer, { theme: themeObj, args: { size, dark } }) : null }), _jsxs("g", { id: "hands", children: [_jsx("g", { transform: `rotate(${hourDeg} 50 50)`, children: _jsx("line", { x1: "50", y1: "50", x2: "50", y2: "28", className: "stroke-neutral-800 dark:stroke-neutral-200", strokeWidth: "2.6", strokeLinecap: "round" }) }), _jsx("g", { transform: `rotate(${minDeg} 50 50)`, children: _jsx("line", { x1: "50", y1: "50", x2: "50", y2: "18", className: "stroke-neutral-800 dark:stroke-neutral-200", strokeWidth: "1.7", strokeLinecap: "round" }) }), showSeconds && (_jsx("g", { transform: `rotate(${secDeg} 50 50)`, children: _jsx("line", { x1: "50", y1: "54", x2: "50", y2: "14", className: "stroke-rose-500", strokeWidth: "0.9", strokeLinecap: "round" }) }))] }), _jsx("circle", { cx: "50", cy: "50", r: "2.2", className: "fill-neutral-800 dark:fill-neutral-200" }), showSeconds ? _jsx("circle", { cx: "50", cy: "50", r: "1.1", className: "fill-rose-500" }) : null, centerOverlay ? (_jsx("foreignObject", { x: "35", y: "35", width: "30", height: "30", children: _jsx("div", { className: "flex h-full w-full items-center justify-center", children: centerOverlay }) })) : null] }) }));
111
+ return (_jsx("div", { className: className, style: style, children: _jsxs("svg", { width: size, height: size, viewBox: "0 0 100 100", className: cn("block", dark ? "dark" : undefined), "aria-label": t(i18n, "components.gadgets.clock.analogAria"), children: [_jsx("g", { id: "theme", children: themeObj ? _jsx(ThemeLayer, { theme: themeObj, args: { size, dark } }) : null }), _jsxs("g", { id: "hands", children: [_jsx("g", { transform: `rotate(${hourDeg} 50 50)`, children: _jsx("line", { x1: "50", y1: "50", x2: "50", y2: "28", className: "stroke-neutral-800 dark:stroke-neutral-200", strokeWidth: "2.6", strokeLinecap: "round" }) }), _jsx("g", { transform: `rotate(${minDeg} 50 50)`, children: _jsx("line", { x1: "50", y1: "50", x2: "50", y2: "18", className: "stroke-neutral-800 dark:stroke-neutral-200", strokeWidth: "1.7", strokeLinecap: "round" }) }), showSeconds && (_jsx("g", { transform: `rotate(${secDeg} 50 50)`, children: _jsx("line", { x1: "50", y1: "54", x2: "50", y2: "14", className: "stroke-rose-500", strokeWidth: "0.9", strokeLinecap: "round" }) }))] }), _jsx("circle", { cx: "50", cy: "50", r: "2.2", className: "fill-neutral-800 dark:fill-neutral-200" }), showSeconds ? _jsx("circle", { cx: "50", cy: "50", r: "1.1", className: "fill-rose-500" }) : null, centerOverlay ? (_jsx("foreignObject", { x: "35", y: "35", width: "30", height: "30", children: _jsx("div", { className: "flex h-full w-full items-center justify-center", children: centerOverlay }) })) : null] }) }));
111
112
  }
112
113
  function DigitalClock({ initialServerTime, timezone, locale = "pt-BR", format = "24h", showSeconds = true, size = "md", digitalStyle = "default", className, style }) {
114
+ const i18n = useComponentsI18n();
113
115
  const { nowMs, hasProvider, providerTick } = useClockNowMs(initialServerTime);
114
116
  void providerTick;
115
117
  useSecondTick(!hasProvider);
@@ -158,7 +160,7 @@ function DigitalClock({ initialServerTime, timezone, locale = "pt-BR", format =
158
160
  fontWeight: 700,
159
161
  lineHeight: 1
160
162
  }, children: value }) }));
161
- return (_jsxs("div", { className: cn("flex items-center gap-2", className), style: style, "aria-label": "Digital clock", children: [_jsx(SgFlipDigit, { value: hh.charAt(0), fontSize: digitFont }), _jsx(SgFlipDigit, { value: hh.charAt(1), fontSize: digitFont }), _jsx(Colon, {}), _jsx(SgFlipDigit, { value: mm.charAt(0), fontSize: digitFont }), _jsx(SgFlipDigit, { value: mm.charAt(1), fontSize: digitFont }), showSeconds ? (_jsxs(_Fragment, { children: [_jsx(Colon, {}), _jsx(SgFlipDigit, { value: ss.charAt(0), fontSize: digitFont }), _jsx(SgFlipDigit, { value: ss.charAt(1), fontSize: digitFont })] })) : null, format === "12h" && dayPeriod ? _jsx(PeriodCell, { value: dayPeriod.toUpperCase() }) : null] }));
163
+ return (_jsxs("div", { className: cn("flex items-center gap-2", className), style: style, "aria-label": t(i18n, "components.gadgets.clock.digitalAria"), children: [_jsx(SgFlipDigit, { value: hh.charAt(0), fontSize: digitFont }), _jsx(SgFlipDigit, { value: hh.charAt(1), fontSize: digitFont }), _jsx(Colon, {}), _jsx(SgFlipDigit, { value: mm.charAt(0), fontSize: digitFont }), _jsx(SgFlipDigit, { value: mm.charAt(1), fontSize: digitFont }), showSeconds ? (_jsxs(_Fragment, { children: [_jsx(Colon, {}), _jsx(SgFlipDigit, { value: ss.charAt(0), fontSize: digitFont }), _jsx(SgFlipDigit, { value: ss.charAt(1), fontSize: digitFont })] })) : null, format === "12h" && dayPeriod ? _jsx(PeriodCell, { value: dayPeriod.toUpperCase() }) : null] }));
162
164
  }
163
165
  if (digitalStyle === "roller3d") {
164
166
  const hNum = Number.parseInt(hour, 10) || 0;
@@ -175,7 +177,7 @@ function DigitalClock({ initialServerTime, timezone, locale = "pt-BR", format =
175
177
  const hh = String(safeHour).padStart(2, "0");
176
178
  const mm = String(mNum).padStart(2, "0");
177
179
  const ss = String(sNum).padStart(2, "0");
178
- return (_jsxs("div", { className: cn("flex items-center gap-4", className), style: { ...fontSize, ...style }, "aria-label": "Digital clock", children: [_jsx(SgRoller3DDigit, { value: hh, items: hourItems, fontSize: digitFont }), _jsx(SgRoller3DDigit, { value: mm, items: minuteItems, fontSize: digitFont }), showSeconds ? _jsx(SgRoller3DDigit, { value: ss, items: secondItems, fontSize: digitFont }) : null, format === "12h" && dayPeriod ? (_jsx(SgRoller3DDigit, { value: dayPeriod.toUpperCase(), items: periodItems, fontSize: digitFont })) : null] }));
180
+ return (_jsxs("div", { className: cn("flex items-center gap-4", className), style: { ...fontSize, ...style }, "aria-label": t(i18n, "components.gadgets.clock.digitalAria"), children: [_jsx(SgRoller3DDigit, { value: hh, items: hourItems, fontSize: digitFont }), _jsx(SgRoller3DDigit, { value: mm, items: minuteItems, fontSize: digitFont }), showSeconds ? _jsx(SgRoller3DDigit, { value: ss, items: secondItems, fontSize: digitFont }) : null, format === "12h" && dayPeriod ? (_jsx(SgRoller3DDigit, { value: dayPeriod.toUpperCase(), items: periodItems, fontSize: digitFont })) : null] }));
179
181
  }
180
182
  if (digitalStyle === "fade") {
181
183
  const hNum = Number.parseInt(hour, 10) || 0;
@@ -188,7 +190,7 @@ function DigitalClock({ initialServerTime, timezone, locale = "pt-BR", format =
188
190
  const digitFont = Math.round(sizePx * 1.35);
189
191
  const cardH = Math.round(digitFont * 1.4);
190
192
  const Colon = () => (_jsxs("div", { className: "flex flex-col items-center justify-center gap-2", style: { height: cardH }, children: [_jsx("div", { className: "h-2 w-2 rounded-full bg-neutral-500/70" }), _jsx("div", { className: "h-2 w-2 rounded-full bg-neutral-500/70" })] }));
191
- return (_jsxs("div", { className: cn("flex items-center gap-2", className), style: style, "aria-label": "Digital clock", children: [_jsx(SgFadeDigit, { value: hh.charAt(0), fontSize: digitFont }), _jsx(SgFadeDigit, { value: hh.charAt(1), fontSize: digitFont }), _jsx(Colon, {}), _jsx(SgFadeDigit, { value: mm.charAt(0), fontSize: digitFont }), _jsx(SgFadeDigit, { value: mm.charAt(1), fontSize: digitFont }), showSeconds ? (_jsxs(_Fragment, { children: [_jsx(Colon, {}), _jsx(SgFadeDigit, { value: ss.charAt(0), fontSize: digitFont }), _jsx(SgFadeDigit, { value: ss.charAt(1), fontSize: digitFont })] })) : null, format === "12h" && dayPeriod ? (_jsx("span", { className: "text-xs font-semibold text-muted-foreground", children: dayPeriod.toUpperCase() })) : null] }));
193
+ return (_jsxs("div", { className: cn("flex items-center gap-2", className), style: style, "aria-label": t(i18n, "components.gadgets.clock.digitalAria"), children: [_jsx(SgFadeDigit, { value: hh.charAt(0), fontSize: digitFont }), _jsx(SgFadeDigit, { value: hh.charAt(1), fontSize: digitFont }), _jsx(Colon, {}), _jsx(SgFadeDigit, { value: mm.charAt(0), fontSize: digitFont }), _jsx(SgFadeDigit, { value: mm.charAt(1), fontSize: digitFont }), showSeconds ? (_jsxs(_Fragment, { children: [_jsx(Colon, {}), _jsx(SgFadeDigit, { value: ss.charAt(0), fontSize: digitFont }), _jsx(SgFadeDigit, { value: ss.charAt(1), fontSize: digitFont })] })) : null, format === "12h" && dayPeriod ? (_jsx("span", { className: "text-xs font-semibold text-muted-foreground", children: dayPeriod.toUpperCase() })) : null] }));
192
194
  }
193
195
  if (digitalStyle === "discard") {
194
196
  const hNum = Number.parseInt(hour, 10) || 0;
@@ -213,15 +215,15 @@ function DigitalClock({ initialServerTime, timezone, locale = "pt-BR", format =
213
215
  };
214
216
  const Colon = () => (_jsx(SgDiscardDigit, { value: ":", fontSize: Math.max(26, Math.round(digitFont * 0.72)), totalNumberPages: 1, transitionMs: 560, animateOnChange: false }));
215
217
  const PeriodCell = ({ value }) => (_jsx(SgDiscardDigit, { value: value, fontSize: Math.max(20, Math.round(digitFont * 0.52)), totalNumberPages: 1, transitionMs: 560, animateOnChange: false }));
216
- return (_jsxs("div", { className: cn("relative z-10 flex items-end gap-2", className), style: style, "aria-label": "Digital clock", children: [_jsx(SgDiscardDigit, { value: hh.charAt(0), fontSize: digitFont, totalNumberPages: pagesForDigit(hh.charAt(0)), transitionMs: 560, changeAnimationMode: "incoming" }), _jsx(SgDiscardDigit, { value: hh.charAt(1), fontSize: digitFont, totalNumberPages: pagesForDigit(hh.charAt(1)), transitionMs: 560, changeAnimationMode: "incoming" }), _jsx(Colon, {}), _jsx(SgDiscardDigit, { value: mm.charAt(0), fontSize: digitFont, totalNumberPages: pagesForDigit(mm.charAt(0)), transitionMs: 560, changeAnimationMode: "incoming" }), _jsx(SgDiscardDigit, { value: mm.charAt(1), fontSize: digitFont, totalNumberPages: pagesForDigit(mm.charAt(1)), transitionMs: 560, changeAnimationMode: "incoming" }), showSeconds ? (_jsxs(_Fragment, { children: [_jsx(Colon, {}), _jsx(SgDiscardDigit, { value: ss.charAt(0), fontSize: digitFont, totalNumberPages: pagesForDigit(ss.charAt(0)), transitionMs: 560, changeAnimationMode: "incoming" }), _jsx(SgDiscardDigit, { value: ss.charAt(1), fontSize: digitFont, totalNumberPages: pagesForDigit(ss.charAt(1)), transitionMs: 560, changeAnimationMode: "incoming" })] })) : null, format === "12h" && dayPeriod ? _jsx(PeriodCell, { value: dayPeriod.toUpperCase() }) : null] }));
218
+ return (_jsxs("div", { className: cn("relative z-10 flex items-end gap-2", className), style: style, "aria-label": t(i18n, "components.gadgets.clock.digitalAria"), children: [_jsx(SgDiscardDigit, { value: hh.charAt(0), fontSize: digitFont, totalNumberPages: pagesForDigit(hh.charAt(0)), transitionMs: 560, changeAnimationMode: "incoming" }), _jsx(SgDiscardDigit, { value: hh.charAt(1), fontSize: digitFont, totalNumberPages: pagesForDigit(hh.charAt(1)), transitionMs: 560, changeAnimationMode: "incoming" }), _jsx(Colon, {}), _jsx(SgDiscardDigit, { value: mm.charAt(0), fontSize: digitFont, totalNumberPages: pagesForDigit(mm.charAt(0)), transitionMs: 560, changeAnimationMode: "incoming" }), _jsx(SgDiscardDigit, { value: mm.charAt(1), fontSize: digitFont, totalNumberPages: pagesForDigit(mm.charAt(1)), transitionMs: 560, changeAnimationMode: "incoming" }), showSeconds ? (_jsxs(_Fragment, { children: [_jsx(Colon, {}), _jsx(SgDiscardDigit, { value: ss.charAt(0), fontSize: digitFont, totalNumberPages: pagesForDigit(ss.charAt(0)), transitionMs: 560, changeAnimationMode: "incoming" }), _jsx(SgDiscardDigit, { value: ss.charAt(1), fontSize: digitFont, totalNumberPages: pagesForDigit(ss.charAt(1)), transitionMs: 560, changeAnimationMode: "incoming" })] })) : null, format === "12h" && dayPeriod ? _jsx(PeriodCell, { value: dayPeriod.toUpperCase() }) : null] }));
217
219
  }
218
220
  if (digitalStyle === "matrix") {
219
221
  const dotSize = Math.max(3, Math.round(sizePx * 0.32));
220
- return (_jsx("div", { className: cn("flex items-center", className), style: style, "aria-label": "Digital clock", children: _jsx(SgMatrixDigit, { value: withPeriod, dotSize: dotSize, gap: Math.max(1, Math.round(dotSize * 0.35)), charGap: Math.max(3, Math.round(dotSize * 0.9)), padding: Math.max(6, Math.round(dotSize * 1.3)), rounded: Math.max(8, Math.round(dotSize * 1.1)) }) }));
222
+ return (_jsx("div", { className: cn("flex items-center", className), style: style, "aria-label": t(i18n, "components.gadgets.clock.digitalAria"), children: _jsx(SgMatrixDigit, { value: withPeriod, dotSize: dotSize, gap: Math.max(1, Math.round(dotSize * 0.35)), charGap: Math.max(3, Math.round(dotSize * 0.9)), padding: Math.max(6, Math.round(dotSize * 1.3)), rounded: Math.max(8, Math.round(dotSize * 1.1)) }) }));
221
223
  }
222
224
  if (digitalStyle === "neon") {
223
225
  const neonFont = Math.max(18, Math.round(sizePx * 1.35));
224
- return (_jsx("div", { className: cn("flex items-center", className), style: style, "aria-label": "Digital clock", children: _jsx(SgNeonDigit, { value: withPeriod, fontSize: neonFont, padding: Math.max(8, Math.round(sizePx * 0.6)), rounded: Math.max(10, Math.round(sizePx * 0.45)) }) }));
226
+ return (_jsx("div", { className: cn("flex items-center", className), style: style, "aria-label": t(i18n, "components.gadgets.clock.digitalAria"), children: _jsx(SgNeonDigit, { value: withPeriod, fontSize: neonFont, padding: Math.max(8, Math.round(sizePx * 0.6)), rounded: Math.max(10, Math.round(sizePx * 0.45)) }) }));
225
227
  }
226
228
  if (digitalStyle === "sevenSegment") {
227
229
  const hNum = Number.parseInt(hour, 10) || 0;
@@ -249,7 +251,7 @@ function DigitalClock({ initialServerTime, timezone, locale = "pt-BR", format =
249
251
  paddingLeft: separatorPadding,
250
252
  paddingRight: separatorPadding
251
253
  }, children: [_jsx("span", { className: "rounded-full bg-red-500/85", style: { width: dotSize, height: dotSize } }), _jsx("span", { className: "rounded-full bg-red-500/85", style: { width: dotSize, height: dotSize } })] }));
252
- return (_jsxs("div", { className: cn("flex items-center", className), style: { gap: digitGap, ...style }, "aria-label": "Digital clock", children: [_jsx(SgSevenSegmentDigit, { value: hh.charAt(0), size: digitSize, thickness: thickness }), _jsx(SgSevenSegmentDigit, { value: hh.charAt(1), size: digitSize, thickness: thickness }), _jsx(Colon, {}), _jsx(SgSevenSegmentDigit, { value: mm.charAt(0), size: digitSize, thickness: thickness }), _jsx(SgSevenSegmentDigit, { value: mm.charAt(1), size: digitSize, thickness: thickness }), showSeconds ? (_jsxs(_Fragment, { children: [_jsx(Colon, {}), _jsx(SgSevenSegmentDigit, { value: ss.charAt(0), size: digitSize, thickness: thickness }), _jsx(SgSevenSegmentDigit, { value: ss.charAt(1), size: digitSize, thickness: thickness })] })) : null, format === "12h" && dayPeriod ? (_jsx("span", { className: "text-xs font-semibold text-muted-foreground", children: dayPeriod.toUpperCase() })) : null] }));
254
+ return (_jsxs("div", { className: cn("flex items-center", className), style: { gap: digitGap, ...style }, "aria-label": t(i18n, "components.gadgets.clock.digitalAria"), children: [_jsx(SgSevenSegmentDigit, { value: hh.charAt(0), size: digitSize, thickness: thickness }), _jsx(SgSevenSegmentDigit, { value: hh.charAt(1), size: digitSize, thickness: thickness }), _jsx(Colon, {}), _jsx(SgSevenSegmentDigit, { value: mm.charAt(0), size: digitSize, thickness: thickness }), _jsx(SgSevenSegmentDigit, { value: mm.charAt(1), size: digitSize, thickness: thickness }), showSeconds ? (_jsxs(_Fragment, { children: [_jsx(Colon, {}), _jsx(SgSevenSegmentDigit, { value: ss.charAt(0), size: digitSize, thickness: thickness }), _jsx(SgSevenSegmentDigit, { value: ss.charAt(1), size: digitSize, thickness: thickness })] })) : null, format === "12h" && dayPeriod ? (_jsx("span", { className: "text-xs font-semibold text-muted-foreground", children: dayPeriod.toUpperCase() })) : null] }));
253
255
  }
254
256
  if (digitalStyle === "segment") {
255
257
  const hNum = Number.parseInt(hour, 10) || 0;
@@ -267,9 +269,9 @@ function DigitalClock({ initialServerTime, timezone, locale = "pt-BR", format =
267
269
  ? 42
268
270
  : 26;
269
271
  const gap = Math.max(2, Math.round(digitSize * 0.18));
270
- return (_jsxs("div", { className: cn("flex items-end", className), style: { gap, ...style }, "aria-label": "Digital clock", children: [_jsx(SgSegmentDigit, { value: hh.charAt(0), size: digitSize }), _jsx(SgSegmentDigit, { value: hh.charAt(1), size: digitSize }), _jsx(SgSegmentDigit, { value: ":", size: digitSize }), _jsx(SgSegmentDigit, { value: mm.charAt(0), size: digitSize }), _jsx(SgSegmentDigit, { value: mm.charAt(1), size: digitSize }), showSeconds ? (_jsxs(_Fragment, { children: [_jsx(SgSegmentDigit, { value: ":", size: digitSize }), _jsx(SgSegmentDigit, { value: ss.charAt(0), size: digitSize }), _jsx(SgSegmentDigit, { value: ss.charAt(1), size: digitSize })] })) : null, format === "12h" && dayPeriod ? (_jsx("span", { className: "text-xs font-semibold text-muted-foreground", children: dayPeriod })) : null] }));
272
+ return (_jsxs("div", { className: cn("flex items-end", className), style: { gap, ...style }, "aria-label": t(i18n, "components.gadgets.clock.digitalAria"), children: [_jsx(SgSegmentDigit, { value: hh.charAt(0), size: digitSize }), _jsx(SgSegmentDigit, { value: hh.charAt(1), size: digitSize }), _jsx(SgSegmentDigit, { value: ":", size: digitSize }), _jsx(SgSegmentDigit, { value: mm.charAt(0), size: digitSize }), _jsx(SgSegmentDigit, { value: mm.charAt(1), size: digitSize }), showSeconds ? (_jsxs(_Fragment, { children: [_jsx(SgSegmentDigit, { value: ":", size: digitSize }), _jsx(SgSegmentDigit, { value: ss.charAt(0), size: digitSize }), _jsx(SgSegmentDigit, { value: ss.charAt(1), size: digitSize })] })) : null, format === "12h" && dayPeriod ? (_jsx("span", { className: "text-xs font-semibold text-muted-foreground", children: dayPeriod })) : null] }));
271
273
  }
272
- return (_jsxs("div", { className: cn("font-mono tabular-nums", classSize, className), style: { ...fontSize, ...style }, children: [text, format === "12h" && dayPeriod ? (_jsx("span", { className: "ml-2 align-top text-xs font-semibold text-muted-foreground", children: dayPeriod })) : null] }));
274
+ return (_jsxs("div", { className: cn("font-mono tabular-nums", classSize, className), style: { ...fontSize, ...style }, "aria-label": t(i18n, "components.gadgets.clock.digitalAria"), children: [text, format === "12h" && dayPeriod ? (_jsx("span", { className: "ml-2 align-top text-xs font-semibold text-muted-foreground", children: dayPeriod })) : null] }));
273
275
  }
274
276
  export function SgClock(props) {
275
277
  const i18n = useComponentsI18n();
@@ -9,6 +9,7 @@ export type SgClockThemePickerProps = {
9
9
  previewSize?: number;
10
10
  searchable?: boolean;
11
11
  fallbackThemeId?: string;
12
+ defaultOpen?: boolean;
12
13
  };
13
- export declare function SgClockThemePicker({ value, onChange, label, placeholder, className, filter, previewSize, searchable, fallbackThemeId }: SgClockThemePickerProps): import("react/jsx-runtime").JSX.Element;
14
+ export declare function SgClockThemePicker({ value, onChange, label: labelProp, placeholder: placeholderProp, className, filter, previewSize, searchable, fallbackThemeId, defaultOpen }: SgClockThemePickerProps): import("react/jsx-runtime").JSX.Element;
14
15
  //# sourceMappingURL=SgClockThemePicker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SgClockThemePicker.d.ts","sourceRoot":"","sources":["../../../../src/gadgets/clock/themes/SgClockThemePicker.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAS5C,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,QAAQ,EACR,KAAe,EACf,WAAiC,EACjC,SAAS,EACT,MAAM,EACN,WAAgB,EAChB,UAAiB,EACjB,eAA2B,EAC5B,EAAE,uBAAuB,2CAoJzB"}
1
+ {"version":3,"file":"SgClockThemePicker.d.ts","sourceRoot":"","sources":["../../../../src/gadgets/clock/themes/SgClockThemePicker.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAW5C,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,QAAQ,EACR,KAAK,EAAE,SAAS,EAChB,WAAW,EAAE,eAAe,EAC5B,SAAS,EACT,MAAM,EACN,WAAgB,EAChB,UAAiB,EACjB,eAA2B,EAC3B,WAAmB,EACpB,EAAE,uBAAuB,2CA6JzB"}
@@ -3,33 +3,31 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { useSgClockThemeResolver } from "./provider";
5
5
  import { SgClockThemePreview } from "./SgClockThemePreview";
6
+ import { filterClockThemes, resolveClockThemeSelection } from "./search";
6
7
  import { SgAutocomplete } from "../../../inputs/SgAutocomplete";
8
+ import { t, useComponentsI18n } from "../../../i18n";
7
9
  function cn(...parts) {
8
10
  return parts.filter(Boolean).join(" ");
9
11
  }
10
- export function SgClockThemePicker({ value, onChange, label = "Theme", placeholder = "Select a theme...", className, filter, previewSize = 56, searchable = true, fallbackThemeId = "classic" }) {
12
+ export function SgClockThemePicker({ value, onChange, label: labelProp, placeholder: placeholderProp, className, filter, previewSize = 56, searchable = true, fallbackThemeId = "classic", defaultOpen = false }) {
13
+ const i18n = useComponentsI18n();
14
+ const label = labelProp ?? t(i18n, "components.gadgets.clock.theme");
15
+ const placeholder = placeholderProp ?? t(i18n, "components.gadgets.clock.selectTheme");
11
16
  const resolver = useSgClockThemeResolver();
12
17
  const all = React.useMemo(() => {
13
18
  const list = resolver?.list() ?? [];
14
19
  return filter ? list.filter(filter) : list;
15
20
  }, [resolver, filter]);
16
- const [open, setOpen] = React.useState(false);
21
+ const popupId = React.useId();
22
+ const [open, setOpen] = React.useState(defaultOpen);
17
23
  const [q, setQ] = React.useState("");
18
- const currentTheme = React.useMemo(() => {
19
- const found = resolver?.resolve(value) ?? all.find((t) => t.id === value) ?? null;
20
- if (found)
21
- return found;
22
- return resolver?.resolve(fallbackThemeId) ?? all.find((t) => t.id === fallbackThemeId) ?? null;
23
- }, [resolver, value, all, fallbackThemeId]);
24
- const filtered = React.useMemo(() => {
25
- const s = q.trim().toLowerCase();
26
- if (!s)
27
- return all;
28
- return all.filter((t) => {
29
- const hay = `${t.id} ${t.label ?? ""} ${(t.tags ?? []).join(" ")}`.toLowerCase();
30
- return hay.includes(s);
31
- });
32
- }, [all, q]);
24
+ const currentTheme = React.useMemo(() => resolveClockThemeSelection({
25
+ resolver,
26
+ allThemes: all,
27
+ value,
28
+ fallbackThemeId
29
+ }), [resolver, value, all, fallbackThemeId]);
30
+ const filtered = React.useMemo(() => filterClockThemes(all, q), [all, q]);
33
31
  const rootRef = React.useRef(null);
34
32
  React.useEffect(() => {
35
33
  if (!open)
@@ -44,28 +42,25 @@ export function SgClockThemePicker({ value, onChange, label = "Theme", placehold
44
42
  document.addEventListener("mousedown", onDoc);
45
43
  return () => document.removeEventListener("mousedown", onDoc);
46
44
  }, [open]);
47
- return (_jsxs("div", { ref: rootRef, className: cn("relative", className), children: [label ? _jsx("div", { className: "mb-1 text-xs font-medium opacity-70", children: label }) : null, _jsx("button", { type: "button", onClick: () => setOpen((v) => !v), className: cn("w-full rounded-lg border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-surface,var(--sg-bg)))] px-3 py-2 text-left text-[rgb(var(--sg-text,var(--sg-fg)))] shadow-sm", "hover:bg-[rgb(var(--sg-surface-2,var(--sg-surface,var(--sg-bg))))]"), children: _jsxs("div", { className: "flex items-center gap-3", children: [currentTheme ? (_jsx("div", { className: "text-[rgb(var(--sg-text,var(--sg-fg)))]", children: _jsx(SgClockThemePreview, { theme: currentTheme, size: previewSize }) })) : (_jsx("div", { className: "h-[56px] w-[56px] rounded-md border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-surface-2,var(--sg-surface,var(--sg-bg))))]" })), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "truncate text-sm font-medium", children: currentTheme?.label ?? currentTheme?.id ?? placeholder }), _jsx("div", { className: "truncate text-xs opacity-60", children: currentTheme?.id ?? "" })] }), _jsx("div", { className: "text-xs opacity-60", children: open ? "^" : "v" })] }) }), open && (_jsxs("div", { className: cn("absolute z-50 mt-2 w-full overflow-hidden rounded-xl border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-surface,var(--sg-bg)))] text-[rgb(var(--sg-text,var(--sg-fg)))] shadow-lg"), children: [searchable && (_jsx("div", { className: "p-2", children: _jsx(SgAutocomplete, { id: "sg-clock-theme-search", label: "Search theme", placeholder: "Search theme...", openOnFocus: true, showDropDownButton: true, clearOnSelect: true, minLengthForSearch: 0, source: (query) => {
48
- const s = (query ?? "").trim().toLowerCase();
49
- const items = all.map((t) => ({
45
+ return (_jsxs("div", { ref: rootRef, className: cn("relative", className), children: [label ? _jsx("div", { className: "mb-1 text-xs font-medium opacity-70", children: label }) : null, _jsx("button", { type: "button", onClick: () => setOpen((v) => !v), "aria-haspopup": "listbox", "aria-expanded": open, "aria-controls": popupId, className: cn("w-full rounded-lg border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-surface,var(--sg-bg)))] px-3 py-2 text-left text-[rgb(var(--sg-text,var(--sg-fg)))] shadow-sm", "hover:bg-[rgb(var(--sg-surface-2,var(--sg-surface,var(--sg-bg))))]"), children: _jsxs("div", { className: "flex items-center gap-3", children: [currentTheme ? (_jsx("div", { className: "text-[rgb(var(--sg-text,var(--sg-fg)))]", children: _jsx(SgClockThemePreview, { theme: currentTheme, size: previewSize }) })) : (_jsx("div", { className: "h-[56px] w-[56px] rounded-md border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-surface-2,var(--sg-surface,var(--sg-bg))))]" })), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "truncate text-sm font-medium", children: currentTheme?.label ?? currentTheme?.id ?? placeholder }), _jsx("div", { className: "truncate text-xs opacity-60", children: currentTheme?.id ?? "" })] }), _jsx("div", { className: "text-xs opacity-60", children: open ? "^" : "v" })] }) }), open && (_jsxs("div", { id: popupId, role: "listbox", className: cn("absolute z-50 mt-2 w-full overflow-hidden rounded-xl border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-surface,var(--sg-bg)))] text-[rgb(var(--sg-text,var(--sg-fg)))] shadow-lg"), children: [searchable && (_jsx("div", { className: "p-2", children: _jsx(SgAutocomplete, { value: q, onChange: setQ, id: "sg-clock-theme-search", label: t(i18n, "components.gadgets.clock.searchTheme"), placeholder: t(i18n, "components.gadgets.clock.searchThemePlaceholder"), openOnFocus: true, showDropDownButton: true, clearOnSelect: true, minLengthForSearch: 0, source: (query) => {
46
+ const items = filterClockThemes(all, query ?? "").map((t) => ({
50
47
  id: t.id,
51
48
  label: t.label ?? t.id,
52
49
  value: t.id,
53
50
  data: t
54
51
  }));
55
- if (!s)
56
- return items;
57
- return items.filter((item) => item.label?.toLowerCase().includes(s));
52
+ return items;
58
53
  }, onSelect: (item) => {
59
54
  const id = item.value ?? item.id;
60
55
  onChange(String(id));
61
56
  setOpen(false);
62
- } }) })), _jsx("div", { className: "max-h-80 overflow-auto p-2", children: filtered.length === 0 ? (_jsx("div", { className: "p-3 text-sm opacity-60", children: "No themes found." })) : (_jsx("div", { className: "space-y-1", children: filtered.map((t) => {
63
- const active = t.id === value;
64
- return (_jsx("button", { type: "button", onClick: () => {
65
- onChange(t.id);
57
+ } }) })), _jsx("div", { className: "max-h-80 overflow-auto p-2", children: filtered.length === 0 ? (_jsx("div", { className: "p-3 text-sm opacity-60", children: t(i18n, "components.gadgets.clock.noThemesFound") })) : (_jsx("div", { className: "space-y-1", children: filtered.map((themeOption) => {
58
+ const active = themeOption.id === value;
59
+ return (_jsx("button", { type: "button", role: "option", "aria-selected": active, onClick: () => {
60
+ onChange(themeOption.id);
66
61
  setOpen(false);
67
62
  }, className: cn("w-full rounded-lg p-2 text-left transition", active
68
63
  ? "bg-[rgb(var(--sg-primary))] text-[rgb(var(--sg-primary-contrast,var(--sg-bg)))]"
69
- : "hover:bg-[rgb(var(--sg-surface-2,var(--sg-surface,var(--sg-bg))))]"), children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: cn(active ? "text-[rgb(var(--sg-primary-contrast,var(--sg-bg)))]" : "text-[rgb(var(--sg-text,var(--sg-fg)))]"), children: _jsx(SgClockThemePreview, { theme: t, size: 44 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "truncate text-sm font-medium", children: t.label ?? t.id }), _jsx("div", { className: cn("truncate text-xs", active ? "opacity-80" : "opacity-60"), children: t.id })] }), active ? _jsx("div", { className: "text-xs opacity-80", children: "OK" }) : null] }) }, t.id));
64
+ : "hover:bg-[rgb(var(--sg-surface-2,var(--sg-surface,var(--sg-bg))))]"), children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: cn(active ? "text-[rgb(var(--sg-primary-contrast,var(--sg-bg)))]" : "text-[rgb(var(--sg-text,var(--sg-fg)))]"), children: _jsx(SgClockThemePreview, { theme: themeOption, size: 44 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "truncate text-sm font-medium", children: themeOption.label ?? themeOption.id }), _jsx("div", { className: cn("truncate text-xs", active ? "opacity-80" : "opacity-60"), children: themeOption.id })] }), active ? _jsx("div", { className: "text-xs opacity-80", children: t(i18n, "components.gadgets.clock.activeTheme") }) : null] }) }, themeOption.id));
70
65
  }) })) })] }))] }));
71
66
  }
@@ -0,0 +1,9 @@
1
+ import type { SgClockTheme, SgClockThemeResolver } from "./types";
2
+ export declare function filterClockThemes(themes: SgClockTheme[], query: string): SgClockTheme[];
3
+ export declare function resolveClockThemeSelection(params: {
4
+ resolver?: SgClockThemeResolver | null;
5
+ allThemes: SgClockTheme[];
6
+ value: string;
7
+ fallbackThemeId: string;
8
+ }): SgClockTheme | null;
9
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../../src/gadgets/clock/themes/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAElE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,MAAM,kBAOtE;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE;IACjD,QAAQ,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACvC,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;CACzB,uBAIA"}
@@ -0,0 +1,15 @@
1
+ export function filterClockThemes(themes, query) {
2
+ const s = query.trim().toLowerCase();
3
+ if (!s)
4
+ return themes;
5
+ return themes.filter((theme) => {
6
+ const hay = `${theme.id} ${theme.label ?? ""} ${(theme.tags ?? []).join(" ")}`.toLowerCase();
7
+ return hay.includes(s);
8
+ });
9
+ }
10
+ export function resolveClockThemeSelection(params) {
11
+ const found = params.resolver?.resolve(params.value) ?? params.allThemes.find((t) => t.id === params.value) ?? null;
12
+ if (found)
13
+ return found;
14
+ return params.resolver?.resolve(params.fallbackThemeId) ?? params.allThemes.find((t) => t.id === params.fallbackThemeId) ?? null;
15
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"SgLinearGauge.d.ts","sourceRoot":"","sources":["../../../src/gadgets/gauge/SgLinearGauge.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAc/B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GACjC,UAAU,GACV,mBAAmB,GACnB,QAAQ,GACR,SAAS,GACT,MAAM,CAAC;AAEX,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,yBAAyB,CAAC;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAExC,QAAQ,CAAC,EAAE,oBAAoB,EAAE,CAAC;IAClC,oBAAoB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAEjG,MAAM,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAE9B,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACxC,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,mBAAmB,CAAC,EAAE,yBAAyB,CAAC;IAChD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;IAEpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAWF,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,kBAAkB,CAAC,2CAogBhE;yBApgBe,aAAa"}
1
+ {"version":3,"file":"SgLinearGauge.d.ts","sourceRoot":"","sources":["../../../src/gadgets/gauge/SgLinearGauge.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAY/B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GACjC,UAAU,GACV,mBAAmB,GACnB,QAAQ,GACR,SAAS,GACT,MAAM,CAAC;AAEX,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,yBAAyB,CAAC;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAExC,QAAQ,CAAC,EAAE,oBAAoB,EAAE,CAAC;IAClC,oBAAoB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAEjG,MAAM,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAE9B,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACxC,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,mBAAmB,CAAC,EAAE,yBAAyB,CAAC;IAChD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;IAEpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAWF,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,kBAAkB,CAAC,2CAkhBhE;yBAlhBe,aAAa"}
@@ -1,18 +1,19 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
+ import { t, useComponentsI18n } from "../../i18n";
5
+ import { clampGaugeValue, clientPointToLinearGaugeValue, pointToLinearGaugeValue, ratioToGaugeValue, valueToGaugeRatio } from "./math";
4
6
  function cn(...parts) {
5
7
  return parts.filter(Boolean).join(" ");
6
8
  }
7
- function clamp(value, min, max) {
8
- return Math.max(min, Math.min(max, value));
9
- }
10
9
  function toNumber(value, fallback) {
11
10
  return Number.isFinite(value) ? value : fallback;
12
11
  }
13
12
  const MAIN_POINTER_ID = "__sg-linear-main-pointer__";
14
13
  export function SgLinearGauge(props) {
15
- const { min = 0, max = 100, value, defaultValue = min, onValueChange, pointers = [], onPointerValueChange, ranges = [], orientation = "horizontal", isAxisInversed = false, showPrimaryPointer = true, primaryPointerShape = "triangle", primaryPointerColor = "hsl(var(--primary))", primaryPointerSize = 11, primaryPointerDraggable = false, barPointer = true, barColor = "hsl(var(--primary))", barThickness = 8, showTicks = true, showLabels = true, majorTickCount = 5, minorTicksPerInterval = 1, labelFormatter, axisColor = "hsl(var(--border))", axisThickness = 10, width = orientation === "horizontal" ? 360 : 140, height = orientation === "horizontal" ? 120 : 360, animate = true, animationDuration = 350, className, style, ariaLabel = "Linear gauge" } = props;
14
+ const i18n = useComponentsI18n();
15
+ const { min = 0, max = 100, value, defaultValue = min, onValueChange, pointers = [], onPointerValueChange, ranges = [], orientation = "horizontal", isAxisInversed = false, showPrimaryPointer = true, primaryPointerShape = "triangle", primaryPointerColor = "hsl(var(--primary))", primaryPointerSize = 11, primaryPointerDraggable = false, barPointer = true, barColor = "hsl(var(--primary))", barThickness = 8, showTicks = true, showLabels = true, majorTickCount = 5, minorTicksPerInterval = 1, labelFormatter, axisColor = "hsl(var(--border))", axisThickness = 10, width = orientation === "horizontal" ? 360 : 140, height = orientation === "horizontal" ? 120 : 360, animate = true, animationDuration = 350, className, style, ariaLabel } = props;
16
+ const resolvedAriaLabel = ariaLabel ?? t(i18n, "components.gadgets.gauge.linearAria");
16
17
  const safeMin = toNumber(min, 0);
17
18
  const safeMax = toNumber(max, 100);
18
19
  const hasRange = safeMax > safeMin;
@@ -20,9 +21,9 @@ export function SgLinearGauge(props) {
20
21
  const [innerValue, setInnerValue] = React.useState(defaultValue);
21
22
  const isControlled = value !== undefined;
22
23
  const currentValueRaw = isControlled ? value : innerValue;
23
- const currentValue = clamp(currentValueRaw, safeMin, safeMax);
24
+ const currentValue = clampGaugeValue(currentValueRaw, safeMin, safeMax);
24
25
  const setMainValue = React.useCallback((next) => {
25
- const clamped = clamp(next, safeMin, safeMax);
26
+ const clamped = clampGaugeValue(next, safeMin, safeMax);
26
27
  if (!isControlled)
27
28
  setInnerValue(clamped);
28
29
  onValueChange?.(clamped);
@@ -30,7 +31,7 @@ export function SgLinearGauge(props) {
30
31
  React.useEffect(() => {
31
32
  if (isControlled)
32
33
  return;
33
- setInnerValue((prev) => clamp(prev, safeMin, safeMax));
34
+ setInnerValue((prev) => clampGaugeValue(prev, safeMin, safeMax));
34
35
  }, [isControlled, safeMin, safeMax]);
35
36
  const pointerIds = React.useMemo(() => pointers.map((pointer, index) => pointer.id ?? `sg-linear-pointer-${index}`), [pointers]);
36
37
  const [dragPointerValues, setDragPointerValues] = React.useState({});
@@ -43,7 +44,7 @@ export function SgLinearGauge(props) {
43
44
  if (!pointer)
44
45
  continue;
45
46
  const pointerId = pointerIds[i] ?? `sg-linear-pointer-${i}`;
46
- const clamped = clamp(pointer.value, safeMin, safeMax);
47
+ const clamped = clampGaugeValue(pointer.value, safeMin, safeMax);
47
48
  if (next[pointerId] !== clamped) {
48
49
  next[pointerId] = clamped;
49
50
  changed = true;
@@ -71,13 +72,10 @@ export function SgLinearGauge(props) {
71
72
  ? { x: totalWidth - 16, y: totalHeight - labelSpace - tickSpace - 4 }
72
73
  : { x: totalWidth - labelSpace - tickSpace - 4, y: 16 };
73
74
  const valueToRatio = React.useCallback((raw) => {
74
- const normalized = clamp((raw - safeMin) / span, 0, 1);
75
- return isAxisInversed ? 1 - normalized : normalized;
75
+ return valueToGaugeRatio(raw, safeMin, safeMax, isAxisInversed);
76
76
  }, [isAxisInversed, safeMin, span]);
77
77
  const ratioToValue = React.useCallback((ratioRaw) => {
78
- const ratio = clamp(ratioRaw, 0, 1);
79
- const normalized = isAxisInversed ? 1 - ratio : ratio;
80
- return safeMin + normalized * span;
78
+ return ratioToGaugeValue(ratioRaw, safeMin, safeMax, isAxisInversed);
81
79
  }, [isAxisInversed, safeMin, span]);
82
80
  const valueToPoint = React.useCallback((raw) => {
83
81
  const ratio = valueToRatio(raw);
@@ -86,12 +84,16 @@ export function SgLinearGauge(props) {
86
84
  return { x, y };
87
85
  }, [axisEnd.x, axisEnd.y, axisStart.x, axisStart.y, valueToRatio]);
88
86
  const pointToValue = React.useCallback((x, y) => {
89
- if (orientation === "horizontal") {
90
- const ratio = (x - axisStart.x) / (axisEnd.x - axisStart.x || 1);
91
- return ratioToValue(ratio);
92
- }
93
- const ratio = (y - axisStart.y) / (axisEnd.y - axisStart.y || 1);
94
- return ratioToValue(ratio);
87
+ return pointToLinearGaugeValue({
88
+ x,
89
+ y,
90
+ axisStart,
91
+ axisEnd,
92
+ orientation,
93
+ min: safeMin,
94
+ max: safeMax,
95
+ isAxisInversed
96
+ });
95
97
  }, [axisEnd.x, axisEnd.y, axisStart.x, axisStart.y, orientation, ratioToValue]);
96
98
  const pointerList = React.useMemo(() => {
97
99
  const list = [];
@@ -120,7 +122,7 @@ export function SgLinearGauge(props) {
120
122
  id: pointerId,
121
123
  isPrimary: false,
122
124
  pointer,
123
- value: clamp(dragValue ?? pointer.value, safeMin, safeMax)
125
+ value: clampGaugeValue(dragValue ?? pointer.value, safeMin, safeMax)
124
126
  });
125
127
  }
126
128
  return list;
@@ -154,11 +156,21 @@ export function SgLinearGauge(props) {
154
156
  if (!svg || !pointerMeta)
155
157
  return;
156
158
  const rect = svg.getBoundingClientRect();
157
- if (rect.width <= 0 || rect.height <= 0)
159
+ const next = clientPointToLinearGaugeValue({
160
+ clientX: event.clientX,
161
+ clientY: event.clientY,
162
+ rect,
163
+ totalWidth,
164
+ totalHeight,
165
+ axisStart,
166
+ axisEnd,
167
+ orientation,
168
+ min: safeMin,
169
+ max: safeMax,
170
+ isAxisInversed
171
+ });
172
+ if (next === null)
158
173
  return;
159
- const localX = ((event.clientX - rect.left) / rect.width) * totalWidth;
160
- const localY = ((event.clientY - rect.top) / rect.height) * totalHeight;
161
- const next = clamp(pointToValue(localX, localY), safeMin, safeMax);
162
174
  if (pointerMeta.isPrimary) {
163
175
  setMainValue(next);
164
176
  }
@@ -185,7 +197,6 @@ export function SgLinearGauge(props) {
185
197
  }, [
186
198
  draggingPointerId,
187
199
  onPointerValueChange,
188
- pointToValue,
189
200
  pointerMap,
190
201
  safeMax,
191
202
  safeMin,
@@ -205,9 +216,9 @@ export function SgLinearGauge(props) {
205
216
  : {};
206
217
  const primaryBarEnd = valueToPoint(currentValue);
207
218
  const primaryBarStart = valueToPoint(safeMin);
208
- return (_jsx("div", { className: cn("inline-flex select-none", className), role: "meter", "aria-label": ariaLabel, "aria-valuemin": safeMin, "aria-valuemax": safeMax, "aria-valuenow": currentValue, style: style, children: _jsxs("svg", { ref: svgRef, width: totalWidth, height: totalHeight, viewBox: `0 0 ${totalWidth} ${totalHeight}`, className: "overflow-visible", children: [_jsx("line", { x1: axisStart.x, y1: axisStart.y, x2: axisEnd.x, y2: axisEnd.y, stroke: axisColor, strokeLinecap: "round", strokeWidth: axisThickness }), ranges.map((range, index) => {
209
- const start = clamp(Math.min(range.start, range.end), safeMin, safeMax);
210
- const end = clamp(Math.max(range.start, range.end), safeMin, safeMax);
219
+ return (_jsx("div", { className: cn("inline-flex select-none", className), role: "meter", "aria-label": resolvedAriaLabel, "aria-valuemin": safeMin, "aria-valuemax": safeMax, "aria-valuenow": currentValue, style: style, children: _jsxs("svg", { ref: svgRef, width: totalWidth, height: totalHeight, viewBox: `0 0 ${totalWidth} ${totalHeight}`, className: "overflow-visible", children: [_jsx("line", { x1: axisStart.x, y1: axisStart.y, x2: axisEnd.x, y2: axisEnd.y, stroke: axisColor, strokeLinecap: "round", strokeWidth: axisThickness }), ranges.map((range, index) => {
220
+ const start = clampGaugeValue(Math.min(range.start, range.end), safeMin, safeMax);
221
+ const end = clampGaugeValue(Math.max(range.start, range.end), safeMin, safeMax);
211
222
  const p1 = valueToPoint(start);
212
223
  const p2 = valueToPoint(end);
213
224
  return (_jsx("line", { x1: p1.x, y1: p1.y, x2: p2.x, y2: p2.y, stroke: range.color ?? "hsl(var(--primary))", strokeLinecap: "round", strokeWidth: range.thickness ?? axisThickness + 2, strokeOpacity: range.opacity ?? 0.55 }, `range-${index}`));
@@ -1 +1 @@
1
- {"version":3,"file":"SgRadialGauge.d.ts","sourceRoot":"","sources":["../../../src/gadgets/gauge/SgRadialGauge.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SgRadialGauge.d.ts","sourceRoot":"","sources":["../../../src/gadgets/gauge/SgRadialGauge.tsx"],"names":[],"mappings":"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"}
@@ -1,16 +1,11 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
+ import { t, useComponentsI18n } from "../../i18n";
5
+ import { angleToRadialGaugeValue, clampGaugeValue, clientPointToRadialGaugeValue, normalizeAngle, normalizeGaugeRange, ratioToGaugeValue, valueToGaugeRatio } from "./math";
4
6
  function cn(...parts) {
5
7
  return parts.filter(Boolean).join(" ");
6
8
  }
7
- function clamp(value, min, max) {
8
- return Math.max(min, Math.min(max, value));
9
- }
10
- function normalizeAngle(angle) {
11
- const normalized = angle % 360;
12
- return normalized < 0 ? normalized + 360 : normalized;
13
- }
14
9
  function toSweep(startAngle, endAngle) {
15
10
  const start = normalizeAngle(startAngle);
16
11
  const end = normalizeAngle(endAngle);
@@ -35,16 +30,19 @@ function arcPath(cx, cy, radius, startAngle, endAngle) {
35
30
  }
36
31
  const MAIN_POINTER_ID = "__sg-radial-main-pointer__";
37
32
  export function SgRadialGauge(props) {
38
- const { min = 0, max = 100, value, defaultValue = min, onValueChange, pointers = [], onPointerValueChange, ranges = [], annotations = [], startAngle = 135, endAngle = 45, isAxisInversed = false, showPrimaryPointer = true, primaryPointerType = "needle", primaryPointerColor = "hsl(var(--primary))", primaryPointerWidth = 3, primaryPointerSize = 12, primaryPointerShape = "circle", primaryPointerDraggable = false, primaryPointerLabel, showTicks = true, showLabels = true, majorTickCount = 5, minorTicksPerInterval = 1, labelFormatter, axisColor = "hsl(var(--border))", ringThickness, axisWidth = 14, radiusFactor = 0.9, centerContent, width = 300, height = 300, animate = true, animationDuration = 350, className, style, ariaLabel = "Radial gauge" } = props;
39
- const safeMin = Number.isFinite(min) ? min : 0;
40
- const safeMax = Number.isFinite(max) && max > safeMin ? max : safeMin + 100;
41
- const span = safeMax - safeMin;
33
+ const i18n = useComponentsI18n();
34
+ const { min = 0, max = 100, value, defaultValue = min, onValueChange, pointers = [], onPointerValueChange, ranges = [], annotations = [], startAngle = 135, endAngle = 45, isAxisInversed = false, showPrimaryPointer = true, primaryPointerType = "needle", primaryPointerColor = "hsl(var(--primary))", primaryPointerWidth = 3, primaryPointerSize = 12, primaryPointerShape = "circle", primaryPointerDraggable = false, primaryPointerLabel, showTicks = true, showLabels = true, majorTickCount = 5, minorTicksPerInterval = 1, labelFormatter, axisColor = "hsl(var(--border))", ringThickness, axisWidth = 14, radiusFactor = 0.9, centerContent, width = 300, height = 300, animate = true, animationDuration = 350, className, style, ariaLabel } = props;
35
+ const resolvedAriaLabel = ariaLabel ?? t(i18n, "components.gadgets.gauge.radialAria");
36
+ const range = React.useMemo(() => normalizeGaugeRange(min, max), [min, max]);
37
+ const safeMin = range.min;
38
+ const safeMax = range.max;
39
+ const span = range.span;
42
40
  const [innerValue, setInnerValue] = React.useState(defaultValue);
43
41
  const isControlled = value !== undefined;
44
42
  const currentValueRaw = isControlled ? value : innerValue;
45
- const currentValue = clamp(currentValueRaw, safeMin, safeMax);
43
+ const currentValue = clampGaugeValue(currentValueRaw, safeMin, safeMax);
46
44
  const setMainValue = React.useCallback((next) => {
47
- const clamped = clamp(next, safeMin, safeMax);
45
+ const clamped = clampGaugeValue(next, safeMin, safeMax);
48
46
  if (!isControlled)
49
47
  setInnerValue(clamped);
50
48
  onValueChange?.(clamped);
@@ -52,7 +50,7 @@ export function SgRadialGauge(props) {
52
50
  React.useEffect(() => {
53
51
  if (isControlled)
54
52
  return;
55
- setInnerValue((prev) => clamp(prev, safeMin, safeMax));
53
+ setInnerValue((prev) => clampGaugeValue(prev, safeMin, safeMax));
56
54
  }, [isControlled, safeMin, safeMax]);
57
55
  const pointerIds = React.useMemo(() => pointers.map((pointer, index) => pointer.id ?? `sg-radial-pointer-${index}`), [pointers]);
58
56
  const [dragPointerValues, setDragPointerValues] = React.useState({});
@@ -65,7 +63,7 @@ export function SgRadialGauge(props) {
65
63
  if (!pointer)
66
64
  continue;
67
65
  const pointerId = pointerIds[i] ?? `sg-radial-pointer-${i}`;
68
- const clamped = clamp(pointer.value, safeMin, safeMax);
66
+ const clamped = clampGaugeValue(pointer.value, safeMin, safeMax);
69
67
  if (next[pointerId] !== clamped) {
70
68
  next[pointerId] = clamped;
71
69
  changed = true;
@@ -89,27 +87,27 @@ export function SgRadialGauge(props) {
89
87
  const safeRadiusFactorRaw = Number.isFinite(radiusFactor) ? radiusFactor : 0.9;
90
88
  const safeRadiusFactor = Math.max(0.1, safeRadiusFactorRaw);
91
89
  const availableRadius = Math.max(8, Math.min(totalWidth, totalHeight) / 2 - safeAxisWidth / 2 - 6);
92
- const baseRadius = clamp(availableRadius * safeRadiusFactor, 8, availableRadius);
90
+ const baseRadius = clampGaugeValue(availableRadius * safeRadiusFactor, 8, availableRadius);
93
91
  const sweep = React.useMemo(() => toSweep(startAngle, endAngle), [endAngle, startAngle]);
94
92
  const valueToRatio = React.useCallback((raw) => {
95
- const normalized = clamp((raw - safeMin) / span, 0, 1);
96
- return isAxisInversed ? 1 - normalized : normalized;
93
+ return valueToGaugeRatio(raw, safeMin, safeMax, isAxisInversed);
97
94
  }, [isAxisInversed, safeMin, span]);
98
95
  const ratioToValue = React.useCallback((ratioRaw) => {
99
- const ratio = clamp(ratioRaw, 0, 1);
100
- const normalized = isAxisInversed ? 1 - ratio : ratio;
101
- return safeMin + normalized * span;
96
+ return ratioToGaugeValue(ratioRaw, safeMin, safeMax, isAxisInversed);
102
97
  }, [isAxisInversed, safeMin, span]);
103
98
  const valueToAngle = React.useCallback((raw) => {
104
99
  const ratio = valueToRatio(raw);
105
100
  return startAngle + sweep * ratio;
106
101
  }, [startAngle, sweep, valueToRatio]);
107
102
  const angleToValue = React.useCallback((rawAngle) => {
108
- const start = normalizeAngle(startAngle);
109
- const target = normalizeAngle(rawAngle);
110
- const distance = (target - start + 360) % 360;
111
- const ratio = clamp(distance / sweep, 0, 1);
112
- return ratioToValue(ratio);
103
+ return angleToRadialGaugeValue({
104
+ rawAngle,
105
+ startAngle,
106
+ sweep,
107
+ min: safeMin,
108
+ max: safeMax,
109
+ isAxisInversed
110
+ });
113
111
  }, [ratioToValue, startAngle, sweep]);
114
112
  const majorCount = Math.max(1, Math.floor(majorTickCount));
115
113
  const minorCount = Math.max(0, Math.floor(minorTicksPerInterval));
@@ -143,7 +141,7 @@ export function SgRadialGauge(props) {
143
141
  id,
144
142
  isPrimary: false,
145
143
  pointer,
146
- value: clamp(dragValue ?? pointer.value, safeMin, safeMax)
144
+ value: clampGaugeValue(dragValue ?? pointer.value, safeMin, safeMax)
147
145
  });
148
146
  }
149
147
  return list;
@@ -180,12 +178,22 @@ export function SgRadialGauge(props) {
180
178
  if (!svg || !pointerMeta)
181
179
  return;
182
180
  const rect = svg.getBoundingClientRect();
183
- if (rect.width <= 0 || rect.height <= 0)
181
+ const next = clientPointToRadialGaugeValue({
182
+ clientX: event.clientX,
183
+ clientY: event.clientY,
184
+ rect,
185
+ totalWidth,
186
+ totalHeight,
187
+ cx,
188
+ cy,
189
+ startAngle,
190
+ sweep,
191
+ min: safeMin,
192
+ max: safeMax,
193
+ isAxisInversed
194
+ });
195
+ if (next === null)
184
196
  return;
185
- const localX = ((event.clientX - rect.left) / rect.width) * totalWidth;
186
- const localY = ((event.clientY - rect.top) / rect.height) * totalHeight;
187
- const angle = normalizeAngle((Math.atan2(localY - cy, localX - cx) * 180) / Math.PI);
188
- const next = clamp(angleToValue(angle), safeMin, safeMax);
189
197
  if (pointerMeta.isPrimary) {
190
198
  setMainValue(next);
191
199
  }
@@ -210,7 +218,6 @@ export function SgRadialGauge(props) {
210
218
  window.removeEventListener("pointercancel", onEnd);
211
219
  };
212
220
  }, [
213
- angleToValue,
214
221
  cx,
215
222
  cy,
216
223
  draggingPointerId,
@@ -232,10 +239,10 @@ export function SgRadialGauge(props) {
232
239
  const animatedStyle = animate
233
240
  ? { transition: `all ${animationDuration}ms ease-out` }
234
241
  : {};
235
- const centerNode = centerContent ?? (_jsxs("div", { className: "pointer-events-none select-none text-center", children: [_jsx("div", { className: "text-xs uppercase text-muted-foreground", children: "Value" }), _jsx("div", { className: "text-xl font-semibold text-foreground", children: Math.round(currentValue) })] }));
236
- return (_jsxs("div", { className: cn("relative inline-flex select-none", className), role: "meter", "aria-label": ariaLabel, "aria-valuemin": safeMin, "aria-valuemax": safeMax, "aria-valuenow": currentValue, style: style, children: [_jsxs("svg", { ref: svgRef, width: totalWidth, height: totalHeight, viewBox: `0 0 ${totalWidth} ${totalHeight}`, children: [_jsx("path", { d: arcPath(cx, cy, baseRadius, startAngle, endAngle), fill: "none", stroke: axisColor, strokeWidth: safeAxisWidth, strokeLinecap: "round" }), ranges.map((range, index) => {
237
- const start = clamp(Math.min(range.start, range.end), safeMin, safeMax);
238
- const end = clamp(Math.max(range.start, range.end), safeMin, safeMax);
242
+ const centerNode = centerContent ?? (_jsxs("div", { className: "pointer-events-none select-none text-center", children: [_jsx("div", { className: "text-xs uppercase text-muted-foreground", children: t(i18n, "components.gadgets.gauge.value") }), _jsx("div", { className: "text-xl font-semibold text-foreground", children: Math.round(currentValue) })] }));
243
+ return (_jsxs("div", { className: cn("relative inline-flex select-none", className), role: "meter", "aria-label": resolvedAriaLabel, "aria-valuemin": safeMin, "aria-valuemax": safeMax, "aria-valuenow": currentValue, style: style, children: [_jsxs("svg", { ref: svgRef, width: totalWidth, height: totalHeight, viewBox: `0 0 ${totalWidth} ${totalHeight}`, children: [_jsx("path", { d: arcPath(cx, cy, baseRadius, startAngle, endAngle), fill: "none", stroke: axisColor, strokeWidth: safeAxisWidth, strokeLinecap: "round" }), ranges.map((range, index) => {
244
+ const start = clampGaugeValue(Math.min(range.start, range.end), safeMin, safeMax);
245
+ const end = clampGaugeValue(Math.max(range.start, range.end), safeMin, safeMax);
239
246
  const startA = valueToAngle(start);
240
247
  const endA = valueToAngle(end);
241
248
  return (_jsx("path", { d: arcPath(cx, cy, baseRadius, startA, endA), fill: "none", stroke: range.color ?? "hsl(var(--primary))", strokeWidth: range.width ?? safeAxisWidth + 2, strokeOpacity: range.opacity ?? 0.55, strokeLinecap: "round" }, `range-${index}`));