@seedgrid/fe-components 0.2.10 → 2026.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/buttons/SgFloatActionButton.d.ts.map +1 -1
- package/dist/buttons/SgFloatActionButton.js +168 -38
- package/dist/commons/SgAvatar.d.ts +66 -0
- package/dist/commons/SgAvatar.d.ts.map +1 -0
- package/dist/commons/SgAvatar.js +136 -0
- package/dist/commons/SgSkeleton.d.ts +16 -0
- package/dist/commons/SgSkeleton.d.ts.map +1 -0
- package/dist/commons/SgSkeleton.js +58 -0
- package/dist/digits/discard-digit/SgDiscardDigit.d.ts +39 -0
- package/dist/digits/discard-digit/SgDiscardDigit.d.ts.map +1 -0
- package/dist/digits/discard-digit/SgDiscardDigit.js +303 -0
- package/dist/digits/discard-digit/index.d.ts +3 -0
- package/dist/digits/discard-digit/index.d.ts.map +1 -0
- package/dist/digits/discard-digit/index.js +1 -0
- package/dist/digits/fade-digit/SgFadeDigit.d.ts +27 -0
- package/dist/digits/fade-digit/SgFadeDigit.d.ts.map +1 -0
- package/dist/digits/fade-digit/SgFadeDigit.js +85 -0
- package/dist/digits/fade-digit/index.d.ts +3 -0
- package/dist/digits/fade-digit/index.d.ts.map +1 -0
- package/dist/digits/fade-digit/index.js +1 -0
- package/dist/digits/flip-digit/SgFlipDigit.d.ts +27 -0
- package/dist/digits/flip-digit/SgFlipDigit.d.ts.map +1 -0
- package/dist/digits/flip-digit/SgFlipDigit.js +70 -0
- package/dist/digits/flip-digit/index.d.ts.map +1 -0
- package/dist/digits/matrix-digit/SgMatrixDigit.d.ts +32 -0
- package/dist/digits/matrix-digit/SgMatrixDigit.d.ts.map +1 -0
- package/dist/digits/matrix-digit/SgMatrixDigit.js +86 -0
- package/dist/digits/matrix-digit/index.d.ts +3 -0
- package/dist/digits/matrix-digit/index.d.ts.map +1 -0
- package/dist/digits/matrix-digit/index.js +1 -0
- package/dist/digits/neon-digit/SgNeonDigit.d.ts +37 -0
- package/dist/digits/neon-digit/SgNeonDigit.d.ts.map +1 -0
- package/dist/digits/neon-digit/SgNeonDigit.js +59 -0
- package/dist/digits/neon-digit/index.d.ts +3 -0
- package/dist/digits/neon-digit/index.d.ts.map +1 -0
- package/dist/digits/neon-digit/index.js +1 -0
- package/dist/digits/roller3d-digit/SgRoller3DDigit.d.ts +37 -0
- package/dist/digits/roller3d-digit/SgRoller3DDigit.d.ts.map +1 -0
- package/dist/digits/roller3d-digit/SgRoller3DDigit.js +47 -0
- package/dist/digits/roller3d-digit/index.d.ts +3 -0
- package/dist/digits/roller3d-digit/index.d.ts.map +1 -0
- package/dist/digits/roller3d-digit/index.js +1 -0
- package/dist/environment/SgEnvironmentProvider.d.ts +1 -0
- package/dist/environment/SgEnvironmentProvider.d.ts.map +1 -1
- package/dist/environment/SgEnvironmentProvider.js +51 -12
- package/dist/gadgets/clock/SgClock.d.ts +3 -1
- package/dist/gadgets/clock/SgClock.d.ts.map +1 -1
- package/dist/gadgets/clock/SgClock.js +111 -180
- package/dist/gadgets/clock/SgTimeProvider.d.ts +1 -0
- package/dist/gadgets/clock/SgTimeProvider.d.ts.map +1 -1
- package/dist/gadgets/clock/SgTimeProvider.js +11 -4
- package/dist/gadgets/gauge/SgLinearGauge.d.ts +59 -0
- package/dist/gadgets/gauge/SgLinearGauge.d.ts.map +1 -0
- package/dist/gadgets/gauge/SgLinearGauge.js +258 -0
- package/dist/gadgets/gauge/SgRadialGauge.d.ts +73 -0
- package/dist/gadgets/gauge/SgRadialGauge.d.ts.map +1 -0
- package/dist/gadgets/gauge/SgRadialGauge.js +311 -0
- package/dist/gadgets/gauge/index.d.ts +5 -0
- package/dist/gadgets/gauge/index.d.ts.map +1 -0
- package/dist/gadgets/gauge/index.js +2 -0
- package/dist/gadgets/string-animator/SgStringAnimator.d.ts +91 -0
- package/dist/gadgets/string-animator/SgStringAnimator.d.ts.map +1 -0
- package/dist/gadgets/string-animator/SgStringAnimator.js +145 -0
- package/dist/gadgets/string-animator/index.d.ts +3 -0
- package/dist/gadgets/string-animator/index.d.ts.map +1 -0
- package/dist/gadgets/string-animator/index.js +1 -0
- package/dist/i18n/en-US.json +9 -1
- package/dist/i18n/es.json +55 -47
- package/dist/i18n/index.d.ts +32 -0
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/i18n/pt-BR.json +9 -1
- package/dist/i18n/pt-PT.json +9 -1
- package/dist/index.d.ts +46 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -1
- package/dist/inputs/SgAutocomplete.js +21 -5
- package/dist/inputs/SgCombobox.d.ts.map +1 -1
- package/dist/inputs/SgCombobox.js +8 -3
- package/dist/inputs/SgRadioGroup.d.ts +37 -0
- package/dist/inputs/SgRadioGroup.d.ts.map +1 -0
- package/dist/inputs/SgRadioGroup.js +139 -0
- package/dist/inputs/SgRating.d.ts +55 -0
- package/dist/inputs/SgRating.d.ts.map +1 -0
- package/dist/inputs/SgRating.js +135 -0
- package/dist/inputs/SgSlider.d.ts +20 -0
- package/dist/inputs/SgSlider.d.ts.map +1 -0
- package/dist/inputs/SgSlider.js +40 -0
- package/dist/inputs/SgStepperInput.d.ts +22 -0
- package/dist/inputs/SgStepperInput.d.ts.map +1 -0
- package/dist/inputs/SgStepperInput.js +51 -0
- package/dist/inputs/SgTextEditor.d.ts +1 -0
- package/dist/inputs/SgTextEditor.d.ts.map +1 -1
- package/dist/inputs/SgTextEditor.js +19 -3
- package/dist/layout/SgAccordion.d.ts +39 -0
- package/dist/layout/SgAccordion.d.ts.map +1 -0
- package/dist/layout/SgAccordion.js +116 -0
- package/dist/layout/SgBreadcrumb.d.ts +33 -0
- package/dist/layout/SgBreadcrumb.d.ts.map +1 -0
- package/dist/layout/SgBreadcrumb.js +121 -0
- package/dist/layout/SgCarousel.d.ts +43 -0
- package/dist/layout/SgCarousel.d.ts.map +1 -0
- package/dist/layout/SgCarousel.js +166 -0
- package/dist/layout/SgDockLayout.d.ts +14 -0
- package/dist/layout/SgDockLayout.d.ts.map +1 -1
- package/dist/layout/SgDockLayout.js +145 -13
- package/dist/layout/SgDockScreen.d.ts +15 -0
- package/dist/layout/SgDockScreen.d.ts.map +1 -0
- package/dist/layout/SgDockScreen.js +13 -0
- package/dist/layout/SgDockZone.d.ts.map +1 -1
- package/dist/layout/SgDockZone.js +36 -2
- package/dist/layout/SgExpandablePanel.d.ts +50 -0
- package/dist/layout/SgExpandablePanel.d.ts.map +1 -0
- package/dist/layout/SgExpandablePanel.js +302 -0
- package/dist/layout/SgMainPanel.d.ts.map +1 -1
- package/dist/layout/SgMainPanel.js +36 -14
- package/dist/layout/SgMenu.d.ts +91 -0
- package/dist/layout/SgMenu.d.ts.map +1 -0
- package/dist/layout/SgMenu.js +939 -0
- package/dist/layout/SgPageControl.d.ts +49 -0
- package/dist/layout/SgPageControl.d.ts.map +1 -0
- package/dist/layout/SgPageControl.js +152 -0
- package/dist/layout/SgPanel.d.ts.map +1 -1
- package/dist/layout/SgPanel.js +10 -1
- package/dist/layout/SgScreen.d.ts +2 -0
- package/dist/layout/SgScreen.d.ts.map +1 -1
- package/dist/layout/SgScreen.js +4 -2
- package/dist/layout/SgToolBar.d.ts +9 -3
- package/dist/layout/SgToolBar.d.ts.map +1 -1
- package/dist/layout/SgToolBar.js +461 -55
- package/dist/menus/SgDockMenu.d.ts +62 -0
- package/dist/menus/SgDockMenu.d.ts.map +1 -0
- package/dist/menus/SgDockMenu.js +480 -0
- package/dist/others/SgPlayground.js +72 -72
- package/package.json +72 -63
- package/dist/gadgets/flip-digit/SgFlipDigit.d.ts +0 -23
- package/dist/gadgets/flip-digit/SgFlipDigit.d.ts.map +0 -1
- package/dist/gadgets/flip-digit/SgFlipDigit.js +0 -118
- package/dist/gadgets/flip-digit/index.d.ts.map +0 -1
- /package/dist/{gadgets → digits}/flip-digit/index.d.ts +0 -0
- /package/dist/{gadgets → digits}/flip-digit/index.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SgFloatActionButton.d.ts","sourceRoot":"","sources":["../../src/buttons/SgFloatActionButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"SgFloatActionButton.d.ts","sourceRoot":"","sources":["../../src/buttons/SgFloatActionButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAuC/B,MAAM,MAAM,WAAW,GACnB,UAAU,GAAG,aAAa,GAAG,aAAa,GAC1C,YAAY,GAAG,eAAe,GAC9B,WAAW,GAAG,cAAc,GAAG,cAAc,CAAC;AAElD,MAAM,MAAM,WAAW,GACnB,SAAS,GACT,WAAW,GACX,SAAS,GACT,MAAM,GACN,SAAS,GACT,MAAM,GACN,QAAQ,GACR,OAAO,CAAC;AAEZ,MAAM,MAAM,UAAU,GAAG,WAAW,CAAC;AACrC,MAAM,MAAM,OAAO,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AACzC,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;AACvD,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AACvD,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AACpF,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAC9D,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,GAAG,aAAa,GAAG,gBAAgB,CAAC;AAEnF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,WAAW,CAAC;IAEvB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,MAAM,CAAC,EAAE;QAAE,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,WAAW,CAAC;IAEvB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAClC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAC7C,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AA6NF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,QAAQ,CAAC,wBAAwB,CAAC,2CAwhB5E;yBAxhBe,mBAAmB"}
|
|
@@ -3,10 +3,33 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { t, useComponentsI18n } from "../i18n";
|
|
5
5
|
import { SgPopup } from "../overlay/SgPopup";
|
|
6
|
+
import { useHasSgEnvironmentProvider, useSgPersistence } from "../environment/SgEnvironmentProvider";
|
|
6
7
|
/* ── helpers ── */
|
|
7
8
|
function cn(...parts) {
|
|
8
9
|
return parts.filter(Boolean).join(" ");
|
|
9
10
|
}
|
|
11
|
+
function parseStoredDragPosition(raw) {
|
|
12
|
+
const value = typeof raw === "string" ? (() => {
|
|
13
|
+
try {
|
|
14
|
+
return JSON.parse(raw);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
})() : raw;
|
|
20
|
+
if (!value ||
|
|
21
|
+
typeof value !== "object" ||
|
|
22
|
+
typeof value.x !== "number" ||
|
|
23
|
+
typeof value.y !== "number" ||
|
|
24
|
+
!Number.isFinite(value.x) ||
|
|
25
|
+
!Number.isFinite(value.y)) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
x: value.x,
|
|
30
|
+
y: value.y
|
|
31
|
+
};
|
|
32
|
+
}
|
|
10
33
|
/* ── constants ── */
|
|
11
34
|
const EDGE = 24;
|
|
12
35
|
const POS_CSS = {
|
|
@@ -177,9 +200,20 @@ function slideInit(pos) {
|
|
|
177
200
|
return "translateX(-24px)";
|
|
178
201
|
return "translateX(24px)";
|
|
179
202
|
}
|
|
203
|
+
function slideNudge(pos, dist = 10) {
|
|
204
|
+
if (pos.endsWith("bottom"))
|
|
205
|
+
return `translateY(${dist}px)`;
|
|
206
|
+
if (pos.endsWith("top"))
|
|
207
|
+
return `translateY(-${dist}px)`;
|
|
208
|
+
if (pos.startsWith("left"))
|
|
209
|
+
return `translateX(-${dist}px)`;
|
|
210
|
+
return `translateX(${dist}px)`;
|
|
211
|
+
}
|
|
180
212
|
/* ── component ── */
|
|
181
213
|
export function SgFloatActionButton(props) {
|
|
182
214
|
const i18n = useComponentsI18n();
|
|
215
|
+
const hasEnvironmentProvider = useHasSgEnvironmentProvider();
|
|
216
|
+
const { load: loadPersistedState, save: savePersistedState, clear: clearPersistedState } = useSgPersistence();
|
|
183
217
|
const { hint, hintDelay = 300, icon, activeIcon, position = "right-bottom", offset, enableDragDrop = false, dragId, severity = "primary", variant, color, size = "md", shape = "circle", elevation = "md", disabled = false, loading = false, autoHideOnScroll = false, hideDirection = "down", animation = "scale", animationOn = "mount", animationDuration = 200, type = "linear", radius, transitionDelay = 30, actions, onClick, className, style, zIndex = 50, absolute = false, } = props;
|
|
184
218
|
const hintPos = props.hintPosition ?? DEFAULT_HINT[position];
|
|
185
219
|
const dir = props.direction ?? DEFAULT_DIR[position];
|
|
@@ -199,7 +233,81 @@ export function SgFloatActionButton(props) {
|
|
|
199
233
|
const containerRef = React.useRef(null);
|
|
200
234
|
const fabBtnRef = React.useRef(null);
|
|
201
235
|
const hintTimer = React.useRef(null);
|
|
236
|
+
const dragCleanupRef = React.useRef(null);
|
|
202
237
|
const isAbsolute = absolute === true;
|
|
238
|
+
const storageKey = dragId ? `sg-fab-pos:${dragId}` : null;
|
|
239
|
+
const loadStoredPosition = React.useCallback(async () => {
|
|
240
|
+
if (!storageKey)
|
|
241
|
+
return null;
|
|
242
|
+
if (hasEnvironmentProvider) {
|
|
243
|
+
try {
|
|
244
|
+
const loaded = await loadPersistedState(storageKey);
|
|
245
|
+
if (loaded === null || loaded === undefined)
|
|
246
|
+
return null;
|
|
247
|
+
const parsed = parseStoredDragPosition(loaded);
|
|
248
|
+
if (!parsed) {
|
|
249
|
+
await clearPersistedState(storageKey);
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
return parsed;
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
try {
|
|
259
|
+
const raw = localStorage.getItem(storageKey);
|
|
260
|
+
if (!raw)
|
|
261
|
+
return null;
|
|
262
|
+
const parsed = parseStoredDragPosition(raw);
|
|
263
|
+
if (!parsed) {
|
|
264
|
+
localStorage.removeItem(storageKey);
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
return parsed;
|
|
268
|
+
}
|
|
269
|
+
catch {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
}, [clearPersistedState, hasEnvironmentProvider, loadPersistedState, storageKey]);
|
|
273
|
+
const saveStoredPosition = React.useCallback(async (nextPos) => {
|
|
274
|
+
if (!storageKey)
|
|
275
|
+
return;
|
|
276
|
+
if (hasEnvironmentProvider) {
|
|
277
|
+
try {
|
|
278
|
+
await savePersistedState(storageKey, nextPos);
|
|
279
|
+
}
|
|
280
|
+
catch {
|
|
281
|
+
// ignore
|
|
282
|
+
}
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
try {
|
|
286
|
+
localStorage.setItem(storageKey, JSON.stringify(nextPos));
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
// ignore
|
|
290
|
+
}
|
|
291
|
+
}, [hasEnvironmentProvider, savePersistedState, storageKey]);
|
|
292
|
+
const clearStoredPosition = React.useCallback(async () => {
|
|
293
|
+
if (!storageKey)
|
|
294
|
+
return;
|
|
295
|
+
if (hasEnvironmentProvider) {
|
|
296
|
+
try {
|
|
297
|
+
await clearPersistedState(storageKey);
|
|
298
|
+
}
|
|
299
|
+
catch {
|
|
300
|
+
// ignore
|
|
301
|
+
}
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
try {
|
|
305
|
+
localStorage.removeItem(storageKey);
|
|
306
|
+
}
|
|
307
|
+
catch {
|
|
308
|
+
// ignore
|
|
309
|
+
}
|
|
310
|
+
}, [clearPersistedState, hasEnvironmentProvider, storageKey]);
|
|
203
311
|
React.useEffect(() => { const t = setTimeout(() => setMounted(true), 20); return () => clearTimeout(t); }, []);
|
|
204
312
|
React.useEffect(() => {
|
|
205
313
|
if (!clicked)
|
|
@@ -228,19 +336,11 @@ export function SgFloatActionButton(props) {
|
|
|
228
336
|
React.useEffect(() => {
|
|
229
337
|
if (!enableDragDrop || !dragId)
|
|
230
338
|
return;
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
const parsed = JSON.parse(stored);
|
|
236
|
-
if (!parsed ||
|
|
237
|
-
typeof parsed.x !== "number" ||
|
|
238
|
-
typeof parsed.y !== "number" ||
|
|
239
|
-
!Number.isFinite(parsed.x) ||
|
|
240
|
-
!Number.isFinite(parsed.y)) {
|
|
241
|
-
localStorage.removeItem(`sg-fab-pos:${dragId}`);
|
|
339
|
+
let alive = true;
|
|
340
|
+
(async () => {
|
|
341
|
+
const parsed = await loadStoredPosition();
|
|
342
|
+
if (!alive || !parsed)
|
|
242
343
|
return;
|
|
243
|
-
}
|
|
244
344
|
const px = parsed.x;
|
|
245
345
|
const py = parsed.y;
|
|
246
346
|
const wh = BTN_WH[size];
|
|
@@ -261,11 +361,11 @@ export function SgFloatActionButton(props) {
|
|
|
261
361
|
dragPosRef.current = clamped;
|
|
262
362
|
setDragPos(clamped);
|
|
263
363
|
hasStoredPosRef.current = true;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
}
|
|
268
|
-
}, [enableDragDrop, dragId, size, isAbsolute]);
|
|
364
|
+
})();
|
|
365
|
+
return () => {
|
|
366
|
+
alive = false;
|
|
367
|
+
};
|
|
368
|
+
}, [enableDragDrop, dragId, loadStoredPosition, size, isAbsolute]);
|
|
269
369
|
React.useEffect(() => {
|
|
270
370
|
if (!open)
|
|
271
371
|
return;
|
|
@@ -279,6 +379,12 @@ export function SgFloatActionButton(props) {
|
|
|
279
379
|
document.addEventListener("keydown", onKey);
|
|
280
380
|
return () => { document.removeEventListener("mousedown", onMd); document.removeEventListener("keydown", onKey); };
|
|
281
381
|
}, [open]);
|
|
382
|
+
React.useEffect(() => {
|
|
383
|
+
return () => {
|
|
384
|
+
dragCleanupRef.current?.();
|
|
385
|
+
dragCleanupRef.current = null;
|
|
386
|
+
};
|
|
387
|
+
}, []);
|
|
282
388
|
const onEnter = React.useCallback(() => {
|
|
283
389
|
setHovered(true);
|
|
284
390
|
if (hint)
|
|
@@ -314,7 +420,11 @@ export function SgFloatActionButton(props) {
|
|
|
314
420
|
return;
|
|
315
421
|
if (!containerRef.current)
|
|
316
422
|
return;
|
|
423
|
+
dragCleanupRef.current?.();
|
|
424
|
+
dragCleanupRef.current = null;
|
|
317
425
|
event.preventDefault();
|
|
426
|
+
const doc = event.currentTarget.ownerDocument ?? document;
|
|
427
|
+
const view = doc.defaultView ?? window;
|
|
318
428
|
const rect = containerRef.current.getBoundingClientRect();
|
|
319
429
|
const parent = isAbsolute
|
|
320
430
|
? (containerRef.current.offsetParent?.getBoundingClientRect() ?? {
|
|
@@ -348,25 +458,38 @@ export function SgFloatActionButton(props) {
|
|
|
348
458
|
setDragPos(nextPos);
|
|
349
459
|
hasStoredPosRef.current = true;
|
|
350
460
|
};
|
|
351
|
-
|
|
461
|
+
let finalized = false;
|
|
462
|
+
const finalizeDrag = () => {
|
|
463
|
+
if (finalized)
|
|
464
|
+
return;
|
|
465
|
+
finalized = true;
|
|
352
466
|
setIsDragging(false);
|
|
353
467
|
dragStart.current = null;
|
|
354
468
|
if (enableDragDrop && dragId && dragPosRef.current) {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
469
|
+
void saveStoredPosition(dragPosRef.current);
|
|
470
|
+
}
|
|
471
|
+
view.removeEventListener("pointermove", handleMove);
|
|
472
|
+
view.removeEventListener("pointerup", handleUp);
|
|
473
|
+
view.removeEventListener("pointercancel", handleUp);
|
|
474
|
+
view.removeEventListener("blur", handleUp);
|
|
475
|
+
doc.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
476
|
+
if (dragCleanupRef.current === finalizeDrag) {
|
|
477
|
+
dragCleanupRef.current = null;
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
const handleUp = () => finalizeDrag();
|
|
481
|
+
const handleVisibilityChange = () => {
|
|
482
|
+
if (doc.visibilityState === "hidden") {
|
|
483
|
+
finalizeDrag();
|
|
361
484
|
}
|
|
362
|
-
window.removeEventListener("pointermove", handleMove);
|
|
363
|
-
window.removeEventListener("pointerup", handleUp);
|
|
364
|
-
window.removeEventListener("pointercancel", handleUp);
|
|
365
485
|
};
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
486
|
+
dragCleanupRef.current = finalizeDrag;
|
|
487
|
+
view.addEventListener("pointermove", handleMove);
|
|
488
|
+
view.addEventListener("pointerup", handleUp);
|
|
489
|
+
view.addEventListener("pointercancel", handleUp);
|
|
490
|
+
view.addEventListener("blur", handleUp);
|
|
491
|
+
doc.addEventListener("visibilitychange", handleVisibilityChange);
|
|
492
|
+
}, [enableDragDrop, disabled, loading, actions, dragId, isAbsolute, saveStoredPosition]);
|
|
370
493
|
const handleContextMenu = React.useCallback((event) => {
|
|
371
494
|
if (!enableDragDrop || !dragId)
|
|
372
495
|
return;
|
|
@@ -380,19 +503,14 @@ export function SgFloatActionButton(props) {
|
|
|
380
503
|
setMenuOpen(false);
|
|
381
504
|
return;
|
|
382
505
|
}
|
|
383
|
-
|
|
384
|
-
localStorage.removeItem(`sg-fab-pos:${dragId}`);
|
|
385
|
-
}
|
|
386
|
-
catch (error) {
|
|
387
|
-
// ignore
|
|
388
|
-
}
|
|
506
|
+
void clearStoredPosition();
|
|
389
507
|
dragPosRef.current = null;
|
|
390
508
|
setDragPos(null);
|
|
391
509
|
setOpen(false);
|
|
392
510
|
setMenuOpen(false);
|
|
393
511
|
hasStoredPosRef.current = false;
|
|
394
512
|
dragMoved.current = false;
|
|
395
|
-
}, [dragId]);
|
|
513
|
+
}, [clearStoredPosition, dragId]);
|
|
396
514
|
/* colors */
|
|
397
515
|
const resolvedSeverity = severity ?? variant ?? "primary";
|
|
398
516
|
const c = COLORS[resolvedSeverity];
|
|
@@ -465,6 +583,12 @@ export function SgFloatActionButton(props) {
|
|
|
465
583
|
case "scale":
|
|
466
584
|
anim.transform = hovered ? "scale(1.1)" : "scale(1)";
|
|
467
585
|
break;
|
|
586
|
+
case "fade":
|
|
587
|
+
anim.opacity = hovered ? 0.62 : 1;
|
|
588
|
+
break;
|
|
589
|
+
case "slide":
|
|
590
|
+
anim.transform = hovered ? slideNudge(position, 10) : "translate(0,0)";
|
|
591
|
+
break;
|
|
468
592
|
case "rotate":
|
|
469
593
|
anim.transform = hovered ? "rotate(15deg)" : "rotate(0deg)";
|
|
470
594
|
break;
|
|
@@ -479,6 +603,12 @@ export function SgFloatActionButton(props) {
|
|
|
479
603
|
case "scale":
|
|
480
604
|
anim.transform = clicked ? "scale(0.9)" : "scale(1)";
|
|
481
605
|
break;
|
|
606
|
+
case "fade":
|
|
607
|
+
anim.opacity = clicked ? 0.52 : 1;
|
|
608
|
+
break;
|
|
609
|
+
case "slide":
|
|
610
|
+
anim.transform = clicked ? slideNudge(position, 14) : "translate(0,0)";
|
|
611
|
+
break;
|
|
482
612
|
case "rotate":
|
|
483
613
|
anim.transform = clicked ? "rotate(90deg)" : "rotate(0deg)";
|
|
484
614
|
break;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type SgAvatarSeverity = "primary" | "secondary" | "success" | "warning" | "danger" | "info" | "neutral" | "custom";
|
|
3
|
+
export type SgAvatarShape = "circle" | "square";
|
|
4
|
+
export type SgAvatarSize = "xs" | "sm" | "md" | "lg" | "xl";
|
|
5
|
+
export type SgAvatarCustomColors = {
|
|
6
|
+
bg?: string;
|
|
7
|
+
fg?: string;
|
|
8
|
+
border?: string;
|
|
9
|
+
ring?: string;
|
|
10
|
+
};
|
|
11
|
+
export type SgAvatarProps = Omit<React.HTMLAttributes<HTMLSpanElement>, "children" | "color"> & {
|
|
12
|
+
src?: string;
|
|
13
|
+
alt?: string;
|
|
14
|
+
label?: React.ReactNode;
|
|
15
|
+
icon?: React.ReactNode;
|
|
16
|
+
fallback?: React.ReactNode;
|
|
17
|
+
size?: SgAvatarSize;
|
|
18
|
+
shape?: SgAvatarShape;
|
|
19
|
+
severity?: SgAvatarSeverity;
|
|
20
|
+
bordered?: boolean;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
customColors?: SgAvatarCustomColors;
|
|
23
|
+
imageClassName?: string;
|
|
24
|
+
children?: React.ReactNode;
|
|
25
|
+
onImageError?: (event: React.SyntheticEvent<HTMLImageElement, Event>) => void;
|
|
26
|
+
};
|
|
27
|
+
export type SgAvatarGroupOverlap = "none" | "sm" | "md" | "lg";
|
|
28
|
+
export type SgAvatarGroupProps = Omit<React.HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
29
|
+
children: React.ReactNode;
|
|
30
|
+
max?: number;
|
|
31
|
+
total?: number;
|
|
32
|
+
overlap?: SgAvatarGroupOverlap;
|
|
33
|
+
moreSeverity?: SgAvatarSeverity;
|
|
34
|
+
moreLabel?: (remaining: number) => React.ReactNode;
|
|
35
|
+
size?: SgAvatarSize;
|
|
36
|
+
shape?: SgAvatarShape;
|
|
37
|
+
bordered?: boolean;
|
|
38
|
+
};
|
|
39
|
+
export declare const SgAvatar: React.ForwardRefExoticComponent<Omit<React.HTMLAttributes<HTMLSpanElement>, "color" | "children"> & {
|
|
40
|
+
src?: string;
|
|
41
|
+
alt?: string;
|
|
42
|
+
label?: React.ReactNode;
|
|
43
|
+
icon?: React.ReactNode;
|
|
44
|
+
fallback?: React.ReactNode;
|
|
45
|
+
size?: SgAvatarSize;
|
|
46
|
+
shape?: SgAvatarShape;
|
|
47
|
+
severity?: SgAvatarSeverity;
|
|
48
|
+
bordered?: boolean;
|
|
49
|
+
disabled?: boolean;
|
|
50
|
+
customColors?: SgAvatarCustomColors;
|
|
51
|
+
imageClassName?: string;
|
|
52
|
+
children?: React.ReactNode;
|
|
53
|
+
onImageError?: (event: React.SyntheticEvent<HTMLImageElement, Event>) => void;
|
|
54
|
+
} & React.RefAttributes<HTMLSpanElement>>;
|
|
55
|
+
export declare const SgAvatarGroup: React.ForwardRefExoticComponent<Omit<React.HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
56
|
+
children: React.ReactNode;
|
|
57
|
+
max?: number;
|
|
58
|
+
total?: number;
|
|
59
|
+
overlap?: SgAvatarGroupOverlap;
|
|
60
|
+
moreSeverity?: SgAvatarSeverity;
|
|
61
|
+
moreLabel?: (remaining: number) => React.ReactNode;
|
|
62
|
+
size?: SgAvatarSize;
|
|
63
|
+
shape?: SgAvatarShape;
|
|
64
|
+
bordered?: boolean;
|
|
65
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
66
|
+
//# sourceMappingURL=SgAvatar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SgAvatar.d.ts","sourceRoot":"","sources":["../../src/commons/SgAvatar.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
function cn(...parts) {
|
|
5
|
+
return parts.filter(Boolean).join(" ");
|
|
6
|
+
}
|
|
7
|
+
const SIZE = {
|
|
8
|
+
xs: { box: "size-6", text: "text-[11px]", icon: "size-3.5" },
|
|
9
|
+
sm: { box: "size-8", text: "text-xs", icon: "size-4" },
|
|
10
|
+
md: { box: "size-10", text: "text-sm", icon: "size-5" },
|
|
11
|
+
lg: { box: "size-14", text: "text-lg", icon: "size-7" },
|
|
12
|
+
xl: { box: "size-20", text: "text-2xl", icon: "size-9" }
|
|
13
|
+
};
|
|
14
|
+
const GROUP_OVERLAP = {
|
|
15
|
+
none: "",
|
|
16
|
+
sm: "-ml-1",
|
|
17
|
+
md: "-ml-2",
|
|
18
|
+
lg: "-ml-3"
|
|
19
|
+
};
|
|
20
|
+
const PRESET = {
|
|
21
|
+
primary: {
|
|
22
|
+
bg: "hsl(var(--primary))",
|
|
23
|
+
fg: "hsl(var(--primary-foreground))",
|
|
24
|
+
border: "hsl(var(--primary))",
|
|
25
|
+
ring: "hsl(var(--ring, var(--primary)))"
|
|
26
|
+
},
|
|
27
|
+
secondary: {
|
|
28
|
+
bg: "hsl(var(--secondary))",
|
|
29
|
+
fg: "hsl(var(--secondary-foreground))",
|
|
30
|
+
border: "hsl(var(--secondary))",
|
|
31
|
+
ring: "hsl(var(--ring, var(--secondary)))"
|
|
32
|
+
},
|
|
33
|
+
success: {
|
|
34
|
+
bg: "hsl(var(--tertiary, var(--accent, var(--primary))))",
|
|
35
|
+
fg: "hsl(var(--tertiary-foreground, var(--accent-foreground, var(--primary-foreground))))",
|
|
36
|
+
border: "hsl(var(--tertiary, var(--accent, var(--primary))))",
|
|
37
|
+
ring: "hsl(var(--ring, var(--tertiary, var(--accent, var(--primary)))))"
|
|
38
|
+
},
|
|
39
|
+
warning: {
|
|
40
|
+
bg: "hsl(var(--accent, var(--secondary, var(--primary))))",
|
|
41
|
+
fg: "hsl(var(--accent-foreground, var(--secondary-foreground, var(--primary-foreground))))",
|
|
42
|
+
border: "hsl(var(--accent, var(--secondary, var(--primary))))",
|
|
43
|
+
ring: "hsl(var(--ring, var(--accent, var(--secondary, var(--primary)))))"
|
|
44
|
+
},
|
|
45
|
+
danger: {
|
|
46
|
+
bg: "hsl(var(--destructive))",
|
|
47
|
+
fg: "hsl(var(--destructive-foreground))",
|
|
48
|
+
border: "hsl(var(--destructive))",
|
|
49
|
+
ring: "hsl(var(--ring, var(--destructive)))"
|
|
50
|
+
},
|
|
51
|
+
info: {
|
|
52
|
+
bg: "hsl(var(--secondary, var(--primary)))",
|
|
53
|
+
fg: "hsl(var(--secondary-foreground, var(--primary-foreground)))",
|
|
54
|
+
border: "hsl(var(--secondary, var(--primary)))",
|
|
55
|
+
ring: "hsl(var(--ring, var(--secondary, var(--primary))))"
|
|
56
|
+
},
|
|
57
|
+
neutral: {
|
|
58
|
+
bg: "hsl(var(--muted))",
|
|
59
|
+
fg: "hsl(var(--muted-foreground))",
|
|
60
|
+
border: "hsl(var(--border))",
|
|
61
|
+
ring: "hsl(var(--ring, var(--muted)))"
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
function resolveAvatarColors(severity, custom) {
|
|
65
|
+
const base = severity === "custom" ? PRESET.primary : PRESET[severity];
|
|
66
|
+
return {
|
|
67
|
+
bg: custom?.bg ?? base.bg,
|
|
68
|
+
fg: custom?.fg ?? base.fg,
|
|
69
|
+
border: custom?.border ?? base.border,
|
|
70
|
+
ring: custom?.ring ?? base.ring
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function buildVars(severity, custom) {
|
|
74
|
+
const merged = resolveAvatarColors(severity, custom);
|
|
75
|
+
return {
|
|
76
|
+
["--sg-avatar-bg"]: merged.bg,
|
|
77
|
+
["--sg-avatar-fg"]: merged.fg,
|
|
78
|
+
["--sg-avatar-border"]: merged.border,
|
|
79
|
+
["--sg-avatar-ring"]: merged.ring
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function hasRenderable(value) {
|
|
83
|
+
if (value === null || value === undefined || value === false)
|
|
84
|
+
return false;
|
|
85
|
+
if (typeof value === "string")
|
|
86
|
+
return value.trim().length > 0;
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
function normalizeLabel(label) {
|
|
90
|
+
if (typeof label !== "string")
|
|
91
|
+
return label;
|
|
92
|
+
const trimmed = label.trim();
|
|
93
|
+
if (!trimmed)
|
|
94
|
+
return "";
|
|
95
|
+
if (trimmed.length <= 2)
|
|
96
|
+
return trimmed.toUpperCase();
|
|
97
|
+
const words = trimmed.split(/\s+/).filter(Boolean);
|
|
98
|
+
if (words.length >= 2) {
|
|
99
|
+
return `${words[0]?.[0] ?? ""}${words[1]?.[0] ?? ""}`.toUpperCase();
|
|
100
|
+
}
|
|
101
|
+
return trimmed.slice(0, 2).toUpperCase();
|
|
102
|
+
}
|
|
103
|
+
export const SgAvatar = React.forwardRef(({ src, alt = "Avatar", label, icon, fallback, size = "md", shape = "circle", severity = "primary", bordered = true, disabled = false, customColors, className, imageClassName, children, onImageError, onClick, role, tabIndex, style, title, ["aria-label"]: ariaLabel, ...rest }, ref) => {
|
|
104
|
+
const [imageFailed, setImageFailed] = React.useState(false);
|
|
105
|
+
const s = SIZE[size];
|
|
106
|
+
React.useEffect(() => {
|
|
107
|
+
setImageFailed(false);
|
|
108
|
+
}, [src]);
|
|
109
|
+
const hasChildren = hasRenderable(children);
|
|
110
|
+
const showImage = !hasChildren && !!src && !imageFailed;
|
|
111
|
+
const showIcon = !hasChildren && !showImage && hasRenderable(icon);
|
|
112
|
+
const showLabel = !hasChildren && !showImage && !showIcon && hasRenderable(label);
|
|
113
|
+
const interactive = typeof onClick === "function" || role === "button" || typeof tabIndex === "number";
|
|
114
|
+
const resolvedAriaLabel = ariaLabel ?? (typeof label === "string" ? label : alt);
|
|
115
|
+
const squareRadius = size === "xs" || size === "sm" ? "rounded-md" : "rounded-xl";
|
|
116
|
+
return (_jsx("span", { ref: ref, title: title, role: role, tabIndex: tabIndex, onClick: disabled ? undefined : onClick, "aria-label": resolvedAriaLabel, style: { ...buildVars(severity, customColors), ...style }, className: cn("relative inline-flex shrink-0 select-none items-center justify-center overflow-hidden", "font-medium leading-none", s.box, s.text, shape === "circle" ? "rounded-full" : squareRadius, bordered ? "border border-[var(--sg-avatar-border)]" : "border border-transparent", showImage ? "bg-muted text-transparent" : "bg-[var(--sg-avatar-bg)] text-[var(--sg-avatar-fg)]", interactive
|
|
117
|
+
? "cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--sg-avatar-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-background"
|
|
118
|
+
: "", disabled ? "pointer-events-none opacity-55" : "", className), ...rest, children: hasChildren ? (children) : showImage ? (_jsx("img", { src: src, alt: alt, loading: "lazy", draggable: false, className: cn("size-full object-cover", imageClassName), onError: (event) => {
|
|
119
|
+
setImageFailed(true);
|
|
120
|
+
onImageError?.(event);
|
|
121
|
+
} })) : showIcon ? (_jsx("span", { className: cn("inline-flex items-center justify-center", s.icon), children: icon })) : showLabel ? (_jsx("span", { className: "uppercase", children: normalizeLabel(label) })) : (_jsx("span", { className: cn("inline-flex items-center justify-center", s.icon), children: hasRenderable(fallback) ? fallback : "?" })) }));
|
|
122
|
+
});
|
|
123
|
+
SgAvatar.displayName = "SgAvatar";
|
|
124
|
+
export const SgAvatarGroup = React.forwardRef(({ children, max, total, overlap = "md", moreSeverity = "neutral", moreLabel, size = "md", shape = "circle", bordered = true, className, ...rest }, ref) => {
|
|
125
|
+
const avatars = React.Children.toArray(children).filter((item) => item !== null && item !== undefined);
|
|
126
|
+
const normalizedMax = typeof max === "number" && Number.isFinite(max) && max > 0 ? Math.floor(max) : undefined;
|
|
127
|
+
const visibleCount = normalizedMax ? Math.min(normalizedMax, avatars.length) : avatars.length;
|
|
128
|
+
const visible = avatars.slice(0, visibleCount);
|
|
129
|
+
const calculatedTotal = Math.max(total ?? avatars.length, avatars.length);
|
|
130
|
+
const hiddenCount = Math.max(calculatedTotal - visibleCount, 0);
|
|
131
|
+
return (_jsxs("div", { ref: ref, className: cn("inline-flex items-center", className), ...rest, children: [visible.map((child, index) => {
|
|
132
|
+
const key = React.isValidElement(child) && child.key != null ? String(child.key) : `sg-avatar-${index}`;
|
|
133
|
+
return (_jsx("span", { className: cn("inline-flex", index === 0 ? "" : GROUP_OVERLAP[overlap]), children: child }, key));
|
|
134
|
+
}), hiddenCount > 0 ? (_jsx("span", { className: cn("inline-flex", visibleCount === 0 ? "" : GROUP_OVERLAP[overlap]), children: _jsx(SgAvatar, { label: moreLabel ? moreLabel(hiddenCount) : `+${hiddenCount}`, size: size, shape: shape, severity: moreSeverity, bordered: bordered }) })) : null] }));
|
|
135
|
+
});
|
|
136
|
+
SgAvatarGroup.displayName = "SgAvatarGroup";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type SgSkeletonShape = "text" | "rectangle" | "rounded" | "square" | "circle";
|
|
3
|
+
export type SgSkeletonAnimation = "wave" | "pulse" | "none";
|
|
4
|
+
export type SgSkeletonProps = Omit<React.HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
5
|
+
width?: number | string;
|
|
6
|
+
height?: number | string;
|
|
7
|
+
size?: number | string;
|
|
8
|
+
borderRadius?: number | string;
|
|
9
|
+
shape?: SgSkeletonShape;
|
|
10
|
+
animation?: SgSkeletonAnimation;
|
|
11
|
+
};
|
|
12
|
+
export declare function SgSkeleton(props: Readonly<SgSkeletonProps>): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare namespace SgSkeleton {
|
|
14
|
+
var displayName: string;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=SgSkeleton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SgSkeleton.d.ts","sourceRoot":"","sources":["../../src/commons/SgSkeleton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAW/B,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;AACrF,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAE5D,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,GAAG;IACrF,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,SAAS,CAAC,EAAE,mBAAmB,CAAC;CACjC,CAAC;AAEF,wBAAgB,UAAU,CAAC,KAAK,EAAE,QAAQ,CAAC,eAAe,CAAC,2CAsF1D;yBAtFe,UAAU"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
function cn(...parts) {
|
|
5
|
+
return parts.filter(Boolean).join(" ");
|
|
6
|
+
}
|
|
7
|
+
function toCssSize(value) {
|
|
8
|
+
if (value === undefined || value === null)
|
|
9
|
+
return undefined;
|
|
10
|
+
return typeof value === "number" ? `${value}px` : value;
|
|
11
|
+
}
|
|
12
|
+
export function SgSkeleton(props) {
|
|
13
|
+
const { width, height, size, borderRadius, shape = "text", animation = "wave", className, style, ...rest } = props;
|
|
14
|
+
const waveOverlayRef = React.useRef(null);
|
|
15
|
+
React.useEffect(() => {
|
|
16
|
+
if (animation !== "wave")
|
|
17
|
+
return;
|
|
18
|
+
const node = waveOverlayRef.current;
|
|
19
|
+
if (!node || typeof node.animate !== "function")
|
|
20
|
+
return;
|
|
21
|
+
const wave = node.animate([{ transform: "translateX(-100%)" }, { transform: "translateX(100%)" }], {
|
|
22
|
+
duration: 1300,
|
|
23
|
+
iterations: Infinity,
|
|
24
|
+
easing: "ease-in-out"
|
|
25
|
+
});
|
|
26
|
+
return () => {
|
|
27
|
+
wave.cancel();
|
|
28
|
+
};
|
|
29
|
+
}, [animation]);
|
|
30
|
+
const cssSize = toCssSize(size);
|
|
31
|
+
const cssWidth = cssSize ??
|
|
32
|
+
toCssSize(width) ??
|
|
33
|
+
(shape === "square" || shape === "circle" ? "2.5rem" : "100%");
|
|
34
|
+
const cssHeight = cssSize ??
|
|
35
|
+
toCssSize(height) ??
|
|
36
|
+
(shape === "text" ? "1rem" : shape === "square" || shape === "circle" ? "2.5rem" : "2rem");
|
|
37
|
+
const cssBorderRadius = toCssSize(borderRadius) ??
|
|
38
|
+
(shape === "circle"
|
|
39
|
+
? "9999px"
|
|
40
|
+
: shape === "square"
|
|
41
|
+
? "0"
|
|
42
|
+
: shape === "rounded"
|
|
43
|
+
? "0.75rem"
|
|
44
|
+
: shape === "text"
|
|
45
|
+
? "9999px"
|
|
46
|
+
: "0.375rem");
|
|
47
|
+
return (_jsx("div", { className: cn("relative block overflow-hidden bg-muted/80", animation === "pulse" ? "animate-pulse" : "", className), style: {
|
|
48
|
+
width: cssWidth,
|
|
49
|
+
height: cssHeight,
|
|
50
|
+
borderRadius: cssBorderRadius,
|
|
51
|
+
...style
|
|
52
|
+
}, ...rest, children: animation === "wave" ? (_jsx("span", { ref: waveOverlayRef, "aria-hidden": "true", className: "pointer-events-none absolute inset-0", style: {
|
|
53
|
+
backgroundImage: "linear-gradient(90deg, transparent 0%, hsl(var(--background) / 0.55) 50%, transparent 100%)",
|
|
54
|
+
transform: "translateX(-100%)",
|
|
55
|
+
willChange: "transform"
|
|
56
|
+
} })) : null }));
|
|
57
|
+
}
|
|
58
|
+
SgSkeleton.displayName = "SgSkeleton";
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type SgDiscardDigitProps = {
|
|
3
|
+
/** Texto/valor exibido na folha do topo. */
|
|
4
|
+
value: string;
|
|
5
|
+
/** Cor do texto principal. */
|
|
6
|
+
color?: string;
|
|
7
|
+
/** Fonte (font-family) usada no texto. */
|
|
8
|
+
font?: string;
|
|
9
|
+
/** Cor de fundo das folhas. */
|
|
10
|
+
backgroundColor?: string;
|
|
11
|
+
/** Tamanho da fonte em px (escala geral do bloco). */
|
|
12
|
+
fontSize?: number;
|
|
13
|
+
/** Peso da fonte. */
|
|
14
|
+
fontWeight?: number | string;
|
|
15
|
+
/** Ativa animacao de descarte quando o valor muda. */
|
|
16
|
+
animateOnChange?: boolean;
|
|
17
|
+
/** Duracao total da animacao em ms. */
|
|
18
|
+
transitionMs?: number;
|
|
19
|
+
/** Quantidade de folhas visiveis na pilha (min 2, max 30). Ignorado se totalNumberPages for definido. */
|
|
20
|
+
stackDepth?: number;
|
|
21
|
+
/** Total de paginas do monte. Quando definido, a pilha visual encolhe a cada increasePage(). */
|
|
22
|
+
totalNumberPages?: number;
|
|
23
|
+
/** Estrategia de animacao para mudancas por prop `value`. */
|
|
24
|
+
changeAnimationMode?: "discard" | "incoming";
|
|
25
|
+
/** Classes CSS adicionais. */
|
|
26
|
+
className?: string;
|
|
27
|
+
/** Estilo inline adicional. */
|
|
28
|
+
style?: React.CSSProperties;
|
|
29
|
+
};
|
|
30
|
+
export type SgDiscardDigitHandle = {
|
|
31
|
+
/** Decrementa a pagina atual (minimo 1). */
|
|
32
|
+
decreasePage(): void;
|
|
33
|
+
/** Incrementa a pagina atual (maximo totalNumberPages). */
|
|
34
|
+
increasePage(): void;
|
|
35
|
+
/** Retorna a pagina atual (1-indexed). */
|
|
36
|
+
page(): number;
|
|
37
|
+
};
|
|
38
|
+
export declare const SgDiscardDigit: React.ForwardRefExoticComponent<SgDiscardDigitProps & React.RefAttributes<SgDiscardDigitHandle>>;
|
|
39
|
+
//# sourceMappingURL=SgDiscardDigit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SgDiscardDigit.d.ts","sourceRoot":"","sources":["../../../src/digits/discard-digit/SgDiscardDigit.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AA4B/B,MAAM,MAAM,mBAAmB,GAAG;IAChC,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+BAA+B;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qBAAqB;IACrB,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,sDAAsD;IACtD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uCAAuC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yGAAyG;IACzG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gGAAgG;IAChG,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6DAA6D;IAC7D,mBAAmB,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IAC7C,8BAA8B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,4CAA4C;IAC5C,YAAY,IAAI,IAAI,CAAC;IACrB,2DAA2D;IAC3D,YAAY,IAAI,IAAI,CAAC;IACrB,0CAA0C;IAC1C,IAAI,IAAI,MAAM,CAAC;CAChB,CAAC;AAmBF,eAAO,MAAM,cAAc,kGAkYzB,CAAC"}
|