@seedgrid/fe-components 0.2.4 → 0.2.6

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 (85) hide show
  1. package/package.json +3 -2
  2. package/dist/buttons/SgSpeedDial.d.ts +0 -40
  3. package/dist/buttons/SgSpeedDial.d.ts.map +0 -1
  4. package/dist/buttons/SgSpeedDial.js +0 -149
  5. package/dist/clock/SgClock.d.ts +0 -28
  6. package/dist/clock/SgClock.d.ts.map +0 -1
  7. package/dist/clock/SgClock.js +0 -280
  8. package/dist/clock/SgTimeProvider.d.ts +0 -13
  9. package/dist/clock/SgTimeProvider.d.ts.map +0 -1
  10. package/dist/clock/SgTimeProvider.js +0 -44
  11. package/dist/clock/themes/SgClockThemePicker.d.ts +0 -14
  12. package/dist/clock/themes/SgClockThemePicker.d.ts.map +0 -1
  13. package/dist/clock/themes/SgClockThemePicker.js +0 -71
  14. package/dist/clock/themes/SgClockThemePreview.d.ts +0 -7
  15. package/dist/clock/themes/SgClockThemePreview.d.ts.map +0 -1
  16. package/dist/clock/themes/SgClockThemePreview.js +0 -11
  17. package/dist/clock/themes/builtins.d.ts +0 -3
  18. package/dist/clock/themes/builtins.d.ts.map +0 -1
  19. package/dist/clock/themes/builtins.js +0 -241
  20. package/dist/clock/themes/index.d.ts +0 -9
  21. package/dist/clock/themes/index.d.ts.map +0 -1
  22. package/dist/clock/themes/index.js +0 -7
  23. package/dist/clock/themes/provider.d.ts +0 -19
  24. package/dist/clock/themes/provider.d.ts.map +0 -1
  25. package/dist/clock/themes/provider.js +0 -54
  26. package/dist/clock/themes/registry.d.ts +0 -9
  27. package/dist/clock/themes/registry.d.ts.map +0 -1
  28. package/dist/clock/themes/registry.js +0 -25
  29. package/dist/clock/themes/renderTheme.d.ts +0 -7
  30. package/dist/clock/themes/renderTheme.d.ts.map +0 -1
  31. package/dist/clock/themes/renderTheme.js +0 -41
  32. package/dist/clock/themes/types.d.ts +0 -21
  33. package/dist/clock/themes/types.d.ts.map +0 -1
  34. package/dist/clock/themes/types.js +0 -1
  35. package/dist/clock/themes/urlThemeCache.d.ts +0 -2
  36. package/dist/clock/themes/urlThemeCache.d.ts.map +0 -1
  37. package/dist/clock/themes/urlThemeCache.js +0 -11
  38. package/dist/clock/themes/useDarkFlag.d.ts +0 -2
  39. package/dist/clock/themes/useDarkFlag.d.ts.map +0 -1
  40. package/dist/clock/themes/useDarkFlag.js +0 -14
  41. package/dist/commons/SgButton.d.ts +0 -39
  42. package/dist/commons/SgButton.d.ts.map +0 -1
  43. package/dist/commons/SgButton.js +0 -116
  44. package/dist/commons/SgPopup.d.ts +0 -42
  45. package/dist/commons/SgPopup.d.ts.map +0 -1
  46. package/dist/commons/SgPopup.js +0 -218
  47. package/dist/inputs/FloatingInput.d.ts +0 -13
  48. package/dist/inputs/FloatingInput.d.ts.map +0 -1
  49. package/dist/inputs/FloatingInput.js +0 -53
  50. package/dist/inputs/FloatingSelect.d.ts +0 -15
  51. package/dist/inputs/FloatingSelect.d.ts.map +0 -1
  52. package/dist/inputs/FloatingSelect.js +0 -52
  53. package/dist/inputs/FloatingTextArea.d.ts +0 -11
  54. package/dist/inputs/FloatingTextArea.d.ts.map +0 -1
  55. package/dist/inputs/FloatingTextArea.js +0 -34
  56. package/dist/inputs/InputBirthDate.d.ts +0 -13
  57. package/dist/inputs/InputBirthDate.d.ts.map +0 -1
  58. package/dist/inputs/InputBirthDate.js +0 -46
  59. package/dist/inputs/InputDate.d.ts +0 -8
  60. package/dist/inputs/InputDate.d.ts.map +0 -1
  61. package/dist/inputs/InputDate.js +0 -23
  62. package/dist/inputs/InputEmail.d.ts +0 -14
  63. package/dist/inputs/InputEmail.d.ts.map +0 -1
  64. package/dist/inputs/InputEmail.js +0 -43
  65. package/dist/inputs/InputPassword.d.ts +0 -12
  66. package/dist/inputs/InputPassword.d.ts.map +0 -1
  67. package/dist/inputs/InputPassword.js +0 -42
  68. package/dist/inputs/MaskedInputs.d.ts +0 -27
  69. package/dist/inputs/MaskedInputs.d.ts.map +0 -1
  70. package/dist/inputs/MaskedInputs.js +0 -161
  71. package/dist/inputs/SgInputCEP.d.ts +0 -33
  72. package/dist/inputs/SgInputCEP.d.ts.map +0 -1
  73. package/dist/inputs/SgInputCEP.js +0 -117
  74. package/dist/inputs/SgInputFone.d.ts +0 -15
  75. package/dist/inputs/SgInputFone.d.ts.map +0 -1
  76. package/dist/inputs/SgInputFone.js +0 -60
  77. package/dist/inputs/SgInputMasked.d.ts +0 -27
  78. package/dist/inputs/SgInputMasked.d.ts.map +0 -1
  79. package/dist/inputs/SgInputMasked.js +0 -161
  80. package/dist/layout/GroupBox.d.ts +0 -10
  81. package/dist/layout/GroupBox.d.ts.map +0 -1
  82. package/dist/layout/GroupBox.js +0 -14
  83. /package/dist/wizard/{SGWizard.d.ts → SgWizard.d.ts} +0 -0
  84. /package/dist/wizard/{SGWizard.d.ts.map → SgWizard.d.ts.map} +0 -0
  85. /package/dist/wizard/{SGWizard.js → SgWizard.js} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seedgrid/fe-components",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -14,7 +14,8 @@
14
14
  "dist"
15
15
  ],
16
16
  "scripts": {
17
- "build": "tsc -p tsconfig.json",
17
+ "clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
18
+ "build": "pnpm run clean && tsc -p tsconfig.json",
18
19
  "typecheck": "tsc -p tsconfig.json --noEmit"
19
20
  },
20
21
  "peerDependencies": {
@@ -1,40 +0,0 @@
1
- import * as React from "react";
2
- import { type SgButtonProps } from "./SgButton";
3
- type Severity = NonNullable<SgButtonProps["severity"]>;
4
- type Appearance = NonNullable<SgButtonProps["appearance"]>;
5
- type Size = NonNullable<SgButtonProps["size"]>;
6
- export type SpeedDialDirection = "up" | "down" | "left" | "right";
7
- export type SpeedDialType = "linear" | "circle" | "semi-circle" | "quarter-circle";
8
- export type SgSpeedDialItem = {
9
- icon: React.ReactNode;
10
- label?: string;
11
- onClick?: () => void;
12
- severity?: Severity;
13
- disabled?: boolean;
14
- className?: string;
15
- };
16
- export type SgSpeedDialProps = {
17
- items: SgSpeedDialItem[];
18
- direction?: SpeedDialDirection;
19
- type?: SpeedDialType;
20
- severity?: Severity;
21
- appearance?: Appearance;
22
- size?: Size;
23
- icon?: React.ReactNode;
24
- activeIcon?: React.ReactNode;
25
- radius?: number;
26
- disabled?: boolean;
27
- className?: string;
28
- style?: React.CSSProperties;
29
- transitionDelay?: number;
30
- mask?: boolean;
31
- tooltipPosition?: "top" | "bottom" | "left" | "right";
32
- onOpen?: () => void;
33
- onClose?: () => void;
34
- };
35
- export declare function SgSpeedDial(props: Readonly<SgSpeedDialProps>): import("react/jsx-runtime").JSX.Element;
36
- export declare namespace SgSpeedDial {
37
- var displayName: string;
38
- }
39
- export {};
40
- //# sourceMappingURL=SgSpeedDial.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SgSpeedDial.d.ts","sourceRoot":"","sources":["../../src/buttons/SgSpeedDial.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAY,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAU1D,KAAK,QAAQ,GAAG,WAAW,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC;AACvD,KAAK,UAAU,GAAG,WAAW,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC;AAC3D,KAAK,IAAI,GAAG,WAAW,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;AAE/C,MAAM,MAAM,kBAAkB,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAClE,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,GAAG,aAAa,GAAG,gBAAgB,CAAC;AAEnF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,eAAe,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;IACtD,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AA4GF,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,gBAAgB,CAAC,2CA2J5D;yBA3Je,WAAW"}
@@ -1,149 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import * as React from "react";
4
- import { SgButton } from "./SgButton";
5
- /* ── helpers ── */
6
- function cn(...parts) {
7
- return parts.filter(Boolean).join(" ");
8
- }
9
- /* ── constants ── */
10
- const ITEM_GAP = { sm: 40, md: 48, lg: 56 };
11
- const DEFAULT_RADIUS = { sm: 100, md: 120, lg: 150 };
12
- const DIRECTION_START_ANGLE = {
13
- up: 270,
14
- down: 90,
15
- left: 180,
16
- right: 0
17
- };
18
- const DEFAULT_TOOLTIP = {
19
- up: "left",
20
- down: "right",
21
- left: "top",
22
- right: "bottom"
23
- };
24
- /* ── positioning ── */
25
- function degToRad(deg) {
26
- return (deg * Math.PI) / 180;
27
- }
28
- function computeItemPositions(items, type, direction, size, radius) {
29
- const count = items.length;
30
- if (count === 0)
31
- return [];
32
- if (type === "linear") {
33
- const gap = ITEM_GAP[size];
34
- return items.map((_, i) => {
35
- const dist = gap * (i + 1);
36
- switch (direction) {
37
- case "up":
38
- return { x: 0, y: -dist };
39
- case "down":
40
- return { x: 0, y: dist };
41
- case "left":
42
- return { x: -dist, y: 0 };
43
- case "right":
44
- return { x: dist, y: 0 };
45
- }
46
- });
47
- }
48
- const r = radius ?? DEFAULT_RADIUS[size];
49
- const centerAngle = DIRECTION_START_ANGLE[direction];
50
- let totalArc;
51
- switch (type) {
52
- case "circle":
53
- totalArc = 360;
54
- break;
55
- case "semi-circle":
56
- totalArc = 180;
57
- break;
58
- case "quarter-circle":
59
- totalArc = 90;
60
- break;
61
- default:
62
- totalArc = 360;
63
- }
64
- const step = type === "circle" ? totalArc / count : totalArc / Math.max(count - 1, 1);
65
- const startAngle = type === "circle" ? centerAngle : centerAngle - totalArc / 2;
66
- return items.map((_, i) => {
67
- const angle = startAngle + step * i;
68
- const rad = degToRad(angle);
69
- return {
70
- x: Math.round(r * Math.cos(rad)),
71
- y: Math.round(r * Math.sin(rad))
72
- };
73
- });
74
- }
75
- /* ── default icons ── */
76
- function PlusIcon() {
77
- return (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { d: "M5 12h14" }), _jsx("path", { d: "M12 5v14" })] }));
78
- }
79
- /* ── tooltip ── */
80
- const TOOLTIP_POS = {
81
- top: "bottom-full left-1/2 -translate-x-1/2 mb-2",
82
- bottom: "top-full left-1/2 -translate-x-1/2 mt-2",
83
- left: "right-full top-1/2 -translate-y-1/2 mr-2",
84
- right: "left-full top-1/2 -translate-y-1/2 ml-2"
85
- };
86
- /* ── component ── */
87
- export function SgSpeedDial(props) {
88
- const { items, direction = "up", type = "linear", severity = "primary", appearance = "solid", size = "md", icon, activeIcon, radius, disabled = false, className, style, transitionDelay = 30, mask = false, tooltipPosition, onOpen, onClose } = props;
89
- const [open, setOpen] = React.useState(false);
90
- const containerRef = React.useRef(null);
91
- const toggle = React.useCallback(() => {
92
- if (disabled)
93
- return;
94
- setOpen((prev) => {
95
- const next = !prev;
96
- if (next)
97
- onOpen?.();
98
- else
99
- onClose?.();
100
- return next;
101
- });
102
- }, [disabled, onOpen, onClose]);
103
- const close = React.useCallback(() => {
104
- if (open) {
105
- setOpen(false);
106
- onClose?.();
107
- }
108
- }, [open, onClose]);
109
- // click-outside
110
- React.useEffect(() => {
111
- if (!open)
112
- return;
113
- function handleClick(e) {
114
- if (containerRef.current && !containerRef.current.contains(e.target)) {
115
- close();
116
- }
117
- }
118
- function handleEscape(e) {
119
- if (e.key === "Escape")
120
- close();
121
- }
122
- document.addEventListener("mousedown", handleClick);
123
- document.addEventListener("keydown", handleEscape);
124
- return () => {
125
- document.removeEventListener("mousedown", handleClick);
126
- document.removeEventListener("keydown", handleEscape);
127
- };
128
- }, [open, close]);
129
- const positions = computeItemPositions(items, type, direction, size, radius);
130
- const tipPos = tooltipPosition ?? DEFAULT_TOOLTIP[direction];
131
- const triggerIcon = icon ?? _jsx(PlusIcon, {});
132
- const triggerActiveIcon = activeIcon ?? triggerIcon;
133
- return (_jsxs(_Fragment, { children: [mask ? (_jsx("div", { className: cn("fixed inset-0 bg-black/50 transition-opacity duration-300 z-40", open ? "opacity-100" : "opacity-0 pointer-events-none"), onClick: close })) : null, _jsxs("div", { ref: containerRef, className: cn("relative inline-flex items-center justify-center", mask && open ? "z-50" : "z-auto", className), style: style, children: [items.map((item, i) => {
134
- const pos = positions[i] ?? { x: 0, y: 0 };
135
- const itemSeverity = item.severity ?? "plain";
136
- return (_jsx("div", { className: "absolute", style: {
137
- transform: open
138
- ? `translate(${pos.x}px, ${pos.y}px) scale(1)`
139
- : "translate(0, 0) scale(0)",
140
- opacity: open ? 1 : 0,
141
- transition: `transform 200ms ease, opacity 200ms ease`,
142
- transitionDelay: open ? `${i * transitionDelay}ms` : `${(items.length - 1 - i) * transitionDelay}ms`
143
- }, children: _jsxs("div", { className: "relative group", children: [_jsx(SgButton, { severity: itemSeverity, appearance: itemSeverity === "plain" ? "solid" : appearance, size: size, shape: "rounded", disabled: item.disabled, className: item.className, onClick: () => {
144
- item.onClick?.();
145
- close();
146
- }, "aria-label": item.label, leftIcon: item.icon }), item.label ? (_jsx("span", { className: cn("absolute whitespace-nowrap rounded bg-foreground/90 px-2 py-1 text-xs text-background", "opacity-0 group-hover:opacity-100 transition-opacity duration-150 pointer-events-none", TOOLTIP_POS[tipPos]), children: item.label })) : null] }) }, i));
147
- }), _jsx(SgButton, { severity: severity, appearance: appearance, size: size, shape: "rounded", disabled: disabled, onClick: toggle, "aria-label": open ? "Close" : "Open", "aria-expanded": open, leftIcon: _jsx("span", { className: "inline-flex transition-transform duration-300", style: { transform: open ? "rotate(45deg)" : "rotate(0deg)" }, children: open ? triggerActiveIcon : triggerIcon }) })] })] }));
148
- }
149
- SgSpeedDial.displayName = "SgSpeedDial";
@@ -1,28 +0,0 @@
1
- import * as React from "react";
2
- import type { SgClockTheme } from "./themes/types";
3
- export type SgClockProps = {
4
- variant?: "digital" | "analog" | "instrument";
5
- size?: "sm" | "md" | "lg" | number;
6
- timezone?: string;
7
- locale?: string;
8
- format?: "12h" | "24h";
9
- showSeconds?: boolean;
10
- digitalStyle?: "default" | "segment";
11
- secondHandMode?: "step" | "smooth";
12
- instrumentMode?: "hours" | "minutes" | "seconds";
13
- instrumentWindow?: number;
14
- instrumentRange?: {
15
- start: number;
16
- end: number;
17
- };
18
- instrumentStep?: number;
19
- instrumentStyle?: "outlined" | "soft";
20
- instrumentHighlight?: boolean;
21
- instrumentSmooth?: boolean;
22
- themeId?: string;
23
- theme?: SgClockTheme;
24
- className?: string;
25
- centerOverlay?: React.ReactNode;
26
- };
27
- export declare function SgClock(props: SgClockProps): import("react/jsx-runtime").JSX.Element;
28
- //# sourceMappingURL=SgClock.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SgClock.d.ts","sourceRoot":"","sources":["../../src/clock/SgClock.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAenD,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,YAAY,CAAC;IAC9C,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IACrC,cAAc,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IACnC,cAAc,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;IACjD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IACtC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CACjC,CAAC;AA+bF,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,2CAqE1C"}
@@ -1,280 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import * as React from "react";
4
- import { useSgTime } from "./SgTimeProvider";
5
- import { useSgClockThemeResolver } from "./themes/provider";
6
- import { ThemeLayer, resolveTheme } from "./themes/renderTheme";
7
- import { useDarkFlag } from "./themes/useDarkFlag";
8
- import { getTheme } from "./themes/registry";
9
- function cn(...parts) {
10
- return parts.filter(Boolean).join(" ");
11
- }
12
- function useSecondTick() {
13
- const [, setTick] = React.useState(0);
14
- React.useEffect(() => {
15
- const id = window.setInterval(() => setTick((v) => v + 1), 1000);
16
- return () => window.clearInterval(id);
17
- }, []);
18
- }
19
- function getHmsForTimezone(date, locale, timeZone) {
20
- const parts = new Intl.DateTimeFormat(locale, {
21
- timeZone,
22
- hour: "2-digit",
23
- minute: "2-digit",
24
- second: "2-digit",
25
- hour12: false
26
- }).formatToParts(date);
27
- const get = (type) => {
28
- const p = parts.find((x) => x.type === type)?.value ?? "0";
29
- const n = Number.parseInt(p, 10);
30
- return Number.isFinite(n) ? n : 0;
31
- };
32
- return { h: get("hour"), m: get("minute"), s: get("second") };
33
- }
34
- function sizeToClass(size) {
35
- if (typeof size === "number")
36
- return "";
37
- if (size === "sm")
38
- return "text-sm";
39
- if (size === "lg")
40
- return "text-2xl";
41
- return "text-base";
42
- }
43
- function digitalSizeToNumber(size) {
44
- if (typeof size === "number")
45
- return size;
46
- if (size === "sm")
47
- return 12;
48
- if (size === "lg")
49
- return 28;
50
- return 16;
51
- }
52
- const SEGMENTS = {
53
- "0": [
54
- { x: 1, y: 0, w: 4, h: 1 },
55
- { x: 5, y: 1, w: 1, h: 4 },
56
- { x: 5, y: 5, w: 1, h: 4 },
57
- { x: 1, y: 9, w: 4, h: 1 },
58
- { x: 0, y: 5, w: 1, h: 4 },
59
- { x: 0, y: 1, w: 1, h: 4 }
60
- ],
61
- "1": [
62
- { x: 5, y: 1, w: 1, h: 4 },
63
- { x: 5, y: 5, w: 1, h: 4 }
64
- ],
65
- "2": [
66
- { x: 1, y: 0, w: 4, h: 1 },
67
- { x: 5, y: 1, w: 1, h: 4 },
68
- { x: 1, y: 4.5, w: 4, h: 1 },
69
- { x: 0, y: 5, w: 1, h: 4 },
70
- { x: 1, y: 9, w: 4, h: 1 }
71
- ],
72
- "3": [
73
- { x: 1, y: 0, w: 4, h: 1 },
74
- { x: 5, y: 1, w: 1, h: 4 },
75
- { x: 1, y: 4.5, w: 4, h: 1 },
76
- { x: 5, y: 5, w: 1, h: 4 },
77
- { x: 1, y: 9, w: 4, h: 1 }
78
- ],
79
- "4": [
80
- { x: 0, y: 1, w: 1, h: 4 },
81
- { x: 5, y: 1, w: 1, h: 4 },
82
- { x: 1, y: 4.5, w: 4, h: 1 },
83
- { x: 5, y: 5, w: 1, h: 4 }
84
- ],
85
- "5": [
86
- { x: 1, y: 0, w: 4, h: 1 },
87
- { x: 0, y: 1, w: 1, h: 4 },
88
- { x: 1, y: 4.5, w: 4, h: 1 },
89
- { x: 5, y: 5, w: 1, h: 4 },
90
- { x: 1, y: 9, w: 4, h: 1 }
91
- ],
92
- "6": [
93
- { x: 1, y: 0, w: 4, h: 1 },
94
- { x: 0, y: 1, w: 1, h: 4 },
95
- { x: 1, y: 4.5, w: 4, h: 1 },
96
- { x: 0, y: 5, w: 1, h: 4 },
97
- { x: 5, y: 5, w: 1, h: 4 },
98
- { x: 1, y: 9, w: 4, h: 1 }
99
- ],
100
- "7": [
101
- { x: 1, y: 0, w: 4, h: 1 },
102
- { x: 5, y: 1, w: 1, h: 4 },
103
- { x: 5, y: 5, w: 1, h: 4 }
104
- ],
105
- "8": [
106
- { x: 1, y: 0, w: 4, h: 1 },
107
- { x: 5, y: 1, w: 1, h: 4 },
108
- { x: 5, y: 5, w: 1, h: 4 },
109
- { x: 1, y: 9, w: 4, h: 1 },
110
- { x: 0, y: 5, w: 1, h: 4 },
111
- { x: 0, y: 1, w: 1, h: 4 },
112
- { x: 1, y: 4.5, w: 4, h: 1 }
113
- ],
114
- "9": [
115
- { x: 1, y: 0, w: 4, h: 1 },
116
- { x: 5, y: 1, w: 1, h: 4 },
117
- { x: 5, y: 5, w: 1, h: 4 },
118
- { x: 1, y: 9, w: 4, h: 1 },
119
- { x: 0, y: 1, w: 1, h: 4 },
120
- { x: 1, y: 4.5, w: 4, h: 1 }
121
- ]
122
- };
123
- function round(n) {
124
- return Math.round(n * 1000) / 1000;
125
- }
126
- function renderSegmentDigit(digit, x, y, scale, keyPrefix) {
127
- const segs = SEGMENTS[digit] ?? [];
128
- return segs.map((s, idx) => (_jsx("rect", { x: round(x + s.x * scale), y: round(y + s.y * scale), width: round(s.w * scale), height: round(s.h * scale), className: "fill-neutral-800 dark:fill-neutral-200", rx: round(0.3 * scale) }, `${keyPrefix}-${idx}`)));
129
- }
130
- function renderSegmentChar(ch, x, y, scale, keyPrefix) {
131
- if (ch === ":") {
132
- return (_jsxs("g", { children: [_jsx("rect", { x: round(x + 2.2 * scale), y: round(y + 2 * scale), width: round(1 * scale), height: round(1 * scale), className: "fill-neutral-800 dark:fill-neutral-200" }), _jsx("rect", { x: round(x + 2.2 * scale), y: round(y + 7 * scale), width: round(1 * scale), height: round(1 * scale), className: "fill-neutral-800 dark:fill-neutral-200" })] }, keyPrefix));
133
- }
134
- if (!SEGMENTS[ch])
135
- return null;
136
- return _jsx("g", { children: renderSegmentDigit(ch, x, y, scale, keyPrefix) }, keyPrefix);
137
- }
138
- function renderSegmentText(text, sizePx) {
139
- const baseScale = sizePx / 16;
140
- const digitW = 6 * baseScale;
141
- const digitH = 10 * baseScale;
142
- const gap = 1.4 * baseScale;
143
- const colonW = 4 * baseScale;
144
- let width = 0;
145
- for (const ch of text) {
146
- width += ch === ":" ? colonW : digitW;
147
- width += gap;
148
- }
149
- width -= gap;
150
- const height = digitH;
151
- let cursor = 0;
152
- const nodes = [];
153
- text.split("").forEach((ch, idx) => {
154
- const w = ch === ":" ? colonW : digitW;
155
- nodes.push(renderSegmentChar(ch, cursor, 0, baseScale, `seg-${idx}`));
156
- cursor += w + gap;
157
- });
158
- return { width, height, nodes };
159
- }
160
- function wrapRange(value, start, end) {
161
- const size = end - start + 1;
162
- const v = ((value - start) % size + size) % size;
163
- return start + v;
164
- }
165
- function getTimeValue(date, locale, timeZone, mode, smooth) {
166
- const { h, m, s } = getHmsForTimezone(date, locale, timeZone);
167
- const ms = date.getMilliseconds();
168
- if (mode === "hours") {
169
- if (!smooth)
170
- return { base: h, frac: 0 };
171
- const value = h + m / 60 + s / 3600;
172
- return { base: Math.floor(value), frac: value - Math.floor(value) };
173
- }
174
- if (mode === "minutes") {
175
- if (!smooth)
176
- return { base: m, frac: 0 };
177
- const value = m + s / 60;
178
- return { base: Math.floor(value), frac: value - Math.floor(value) };
179
- }
180
- if (!smooth)
181
- return { base: s, frac: 0 };
182
- const value = s + ms / 1000;
183
- return { base: Math.floor(value), frac: value - Math.floor(value) };
184
- }
185
- function InstrumentClock({ size = "md", locale = "pt-BR", timezone, instrumentWindow = 12, instrumentRange, instrumentStep = 1, instrumentStyle = "outlined", instrumentHighlight = true, instrumentSmooth = true, className }) {
186
- const { tick, nowMs } = useSgTime();
187
- void tick;
188
- useSecondTick();
189
- const date = new Date(nowMs());
190
- const windowSize = instrumentWindow % 2 === 0 ? instrumentWindow + 1 : instrumentWindow;
191
- const centerIndex = Math.floor(windowSize / 2);
192
- const cellWidth = typeof size === "number" ? size : size === "sm" ? 36 : size === "lg" ? 64 : 48;
193
- const height = Math.round(cellWidth * 0.9);
194
- const pad = instrumentStyle === "soft" ? "bg-muted/40" : "bg-background";
195
- const border = instrumentStyle === "outlined" ? "border border-border" : "";
196
- const lastPosRef = React.useRef({
197
- hours: null,
198
- minutes: null,
199
- seconds: null
200
- });
201
- const renderLine = (mode, range) => {
202
- const { base, frac } = getTimeValue(date, locale, timezone, mode, instrumentSmooth);
203
- const values = Array.from({ length: windowSize }).map((_, idx) => {
204
- const offset = (idx - centerIndex) * instrumentStep;
205
- const value = wrapRange(base + offset, range.start, range.end);
206
- return value;
207
- });
208
- const pos = base + frac;
209
- const lastPos = lastPosRef.current[mode] ?? null;
210
- if (lastPos === null) {
211
- lastPosRef.current[mode] = pos;
212
- }
213
- else if (instrumentSmooth) {
214
- const rangeSize = range.end - range.start + 1;
215
- const delta = pos - lastPos;
216
- if (delta < -rangeSize / 2) {
217
- lastPosRef.current[mode] = lastPos - rangeSize;
218
- }
219
- }
220
- const translateX = ((lastPosRef.current[mode] ?? pos) - pos) * cellWidth;
221
- lastPosRef.current[mode] = pos;
222
- return (_jsxs("div", { className: cn("relative overflow-hidden rounded-lg", pad, border), style: { height }, children: [_jsx("div", { className: "flex items-center", style: {
223
- transform: `translateX(${translateX}px)`,
224
- transition: instrumentSmooth ? "transform 60ms linear" : "none"
225
- }, children: values.map((v, idx) => {
226
- const isCenter = idx === centerIndex;
227
- return (_jsx("div", { className: cn("flex items-center justify-center font-mono tabular-nums text-muted-foreground", isCenter && instrumentHighlight ? "text-foreground font-semibold" : ""), style: { width: cellWidth, height }, children: String(v).padStart(2, "0") }, `${mode}-${v}-${idx}`));
228
- }) }), _jsx("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-center", children: _jsxs("div", { className: "relative", children: [_jsx("div", { className: "absolute -top-2 left-1/2 h-2 w-0.5 -translate-x-1/2 bg-foreground" }), _jsx("div", { className: "absolute -bottom-2 left-1/2 h-2 w-0.5 -translate-x-1/2 bg-foreground" }), _jsx("div", { className: "h-full w-0.5 bg-foreground", style: { height } })] }) })] }));
229
- };
230
- return (_jsxs("div", { className: cn("relative w-full max-w-full space-y-3", className), children: [renderLine("hours", instrumentRange ?? { start: 0, end: 23 }), renderLine("minutes", instrumentRange ?? { start: 0, end: 59 }), renderLine("seconds", instrumentRange ?? { start: 0, end: 59 })] }));
231
- }
232
- function AnalogClock({ size = 280, timezone, locale = "pt-BR", showSeconds = true, secondHandMode = "step", themeId = "classic", theme, className, centerOverlay }) {
233
- const { tick, nowMs } = useSgTime();
234
- void tick;
235
- useSecondTick();
236
- const resolver = useSgClockThemeResolver();
237
- const dark = useDarkFlag();
238
- const date = new Date(nowMs());
239
- const { h, m, s } = getHmsForTimezone(date, locale, timezone);
240
- const ms = date.getMilliseconds();
241
- const sec = secondHandMode === "smooth" ? s + ms / 1000 : s;
242
- const secDeg = (sec / 60) * 360;
243
- const minDeg = ((m + sec / 60) / 60) * 360;
244
- const hourDeg = (((h % 12) + m / 60 + sec / 3600) / 12) * 360;
245
- const themeObj = theme ??
246
- (resolver ? resolveTheme(resolver, themeId, "classic") : getTheme(themeId) ?? getTheme("classic"));
247
- return (_jsx("div", { className: className, children: _jsxs("svg", { width: size, height: size, viewBox: "0 0 100 100", className: "block", "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] }) }));
248
- }
249
- function DigitalClock({ timezone, locale = "pt-BR", format = "24h", showSeconds = true, size = "md", digitalStyle = "default", className }) {
250
- const { tick, nowMs } = useSgTime();
251
- void tick;
252
- useSecondTick();
253
- const d = new Date(nowMs());
254
- const text = new Intl.DateTimeFormat(locale, {
255
- timeZone: timezone,
256
- hour: "2-digit",
257
- minute: "2-digit",
258
- second: showSeconds ? "2-digit" : undefined,
259
- hour12: format === "12h"
260
- }).format(d);
261
- const classSize = sizeToClass(size);
262
- const fontSize = typeof size === "number" ? { fontSize: `${size}px`, lineHeight: 1 } : undefined;
263
- const sizePx = digitalSizeToNumber(size);
264
- if (digitalStyle === "segment") {
265
- const seg = renderSegmentText(text, sizePx);
266
- return (_jsx("svg", { width: seg.width, height: seg.height, viewBox: `0 0 ${seg.width} ${seg.height}`, className: cn("block", className), "aria-label": "Digital clock", children: seg.nodes }));
267
- }
268
- return (_jsx("div", { className: cn("font-mono tabular-nums", classSize, className), style: fontSize, children: text }));
269
- }
270
- export function SgClock(props) {
271
- const { variant = "digital", size = "md", timezone, locale = "pt-BR", format = "24h", showSeconds = true, digitalStyle = "default", secondHandMode = "step", instrumentMode = "minutes", instrumentWindow = 12, instrumentRange, instrumentStep = 1, instrumentStyle = "outlined", instrumentHighlight = true, instrumentSmooth = true, themeId = "classic", theme, className, centerOverlay } = props;
272
- if (variant === "analog") {
273
- const analogSize = typeof size === "number" ? size : size === "sm" ? 140 : size === "lg" ? 320 : 240;
274
- return (_jsx(AnalogClock, { size: analogSize, themeId: themeId, theme: theme, timezone: timezone, locale: locale, showSeconds: showSeconds, secondHandMode: secondHandMode, className: className, centerOverlay: centerOverlay }));
275
- }
276
- if (variant === "instrument") {
277
- return (_jsx(InstrumentClock, { size: size, locale: locale, timezone: timezone, instrumentMode: instrumentMode, instrumentWindow: instrumentWindow, instrumentRange: instrumentRange, instrumentStep: instrumentStep, instrumentStyle: instrumentStyle, instrumentHighlight: instrumentHighlight, instrumentSmooth: instrumentSmooth, className: className }));
278
- }
279
- return (_jsx(DigitalClock, { timezone: timezone, locale: locale, format: format, showSeconds: showSeconds, size: size, digitalStyle: digitalStyle, className: className }));
280
- }
@@ -1,13 +0,0 @@
1
- import * as React from "react";
2
- export type SgTimeContextValue = {
3
- serverStartMs: number;
4
- perfStartMs: number;
5
- tick: number;
6
- nowMs: () => number;
7
- };
8
- export declare function useSgTime(): SgTimeContextValue;
9
- export declare function SgTimeProvider({ initialServerTime, children }: {
10
- initialServerTime: string;
11
- children: React.ReactNode;
12
- }): import("react/jsx-runtime").JSX.Element;
13
- //# sourceMappingURL=SgTimeProvider.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SgTimeProvider.d.ts","sourceRoot":"","sources":["../../src/clock/SgTimeProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,MAAM,CAAC;CACrB,CAAC;AAIF,wBAAgB,SAAS,uBAIxB;AAED,wBAAgB,cAAc,CAAC,EAC7B,iBAAiB,EACjB,QAAQ,EACT,EAAE;IACD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,2CAyCA"}
@@ -1,44 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx } from "react/jsx-runtime";
3
- import * as React from "react";
4
- const SgTimeContext = React.createContext(null);
5
- export function useSgTime() {
6
- const ctx = React.useContext(SgTimeContext);
7
- if (!ctx)
8
- throw new Error("useSgTime must be used within <SgTimeProvider />");
9
- return ctx;
10
- }
11
- export function SgTimeProvider({ initialServerTime, children }) {
12
- const serverStartMsRef = React.useRef(Date.parse(initialServerTime));
13
- const perfStartMsRef = React.useRef(0);
14
- const [tick, setTick] = React.useState(0);
15
- const [hydrated, setHydrated] = React.useState(false);
16
- React.useEffect(() => {
17
- perfStartMsRef.current = performance.now();
18
- setHydrated(true);
19
- const alignDelay = 1000 - (Date.now() % 1000);
20
- let intervalId = null;
21
- const timeoutId = window.setTimeout(() => {
22
- setTick((x) => x + 1);
23
- intervalId = window.setInterval(() => setTick((x) => x + 1), 1000);
24
- }, alignDelay);
25
- return () => {
26
- window.clearTimeout(timeoutId);
27
- if (intervalId)
28
- window.clearInterval(intervalId);
29
- };
30
- }, []);
31
- const nowMs = React.useCallback(() => {
32
- if (!hydrated)
33
- return serverStartMsRef.current;
34
- const delta = performance.now() - perfStartMsRef.current;
35
- return serverStartMsRef.current + delta;
36
- }, [hydrated]);
37
- const value = React.useMemo(() => ({
38
- serverStartMs: serverStartMsRef.current,
39
- perfStartMs: perfStartMsRef.current,
40
- tick,
41
- nowMs
42
- }), [tick, nowMs]);
43
- return _jsx(SgTimeContext.Provider, { value: value, children: children });
44
- }
@@ -1,14 +0,0 @@
1
- import type { SgClockTheme } from "./types";
2
- export type SgClockThemePickerProps = {
3
- value: string;
4
- onChange: (id: string) => void;
5
- label?: string;
6
- placeholder?: string;
7
- className?: string;
8
- filter?: (theme: SgClockTheme) => boolean;
9
- previewSize?: number;
10
- searchable?: boolean;
11
- fallbackThemeId?: string;
12
- };
13
- export declare function SgClockThemePicker({ value, onChange, label, placeholder, className, filter, previewSize, searchable, fallbackThemeId }: SgClockThemePickerProps): import("react/jsx-runtime").JSX.Element;
14
- //# sourceMappingURL=SgClockThemePicker.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SgClockThemePicker.d.ts","sourceRoot":"","sources":["../../../src/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,2CAsJzB"}