@sanmid/flux 0.1.4 → 0.1.5
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/README.md +1 -1
- package/dist/index.js +144 -41
- package/dist/index.js.map +1 -1
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ npm install @sanmid/flux -D
|
|
|
14
14
|
|
|
15
15
|
Or: `pnpm add -D @sanmid/flux` · `yarn add -D @sanmid/flux`
|
|
16
16
|
|
|
17
|
-
Icons, `clsx`, `tailwind-merge
|
|
17
|
+
Icons, `clsx`, and `tailwind-merge` are **dependencies of Flux** — you do not install them separately. You only need **`react` and `react-dom` (18+)** in your app (Flux lists them as peer dependencies so one React instance is shared with your UI).
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { useReducedMotion, AnimatePresence, motion } from 'framer-motion';
|
|
2
1
|
import { createContext, useState, useRef, useCallback, useEffect, useLayoutEffect, useMemo, useContext } from 'react';
|
|
3
2
|
import { flushSync, createPortal } from 'react-dom';
|
|
4
|
-
import { jsx,
|
|
3
|
+
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
5
4
|
import { X, CornerUpLeft, Check, Copy, AlignHorizontalJustifyStart, AlignHorizontalJustifyCenter, AlignHorizontalJustifyEnd, AlignVerticalJustifyStart, AlignVerticalJustifyCenter, AlignVerticalJustifyEnd, Rows3, SquareSquare, AlignVerticalSpaceAround, AlignHorizontalSpaceAround, ArrowUpDown, ArrowLeftRight, AlignLeft, AlignCenter, AlignRight, ArrowUpToLine, FoldVertical, ArrowDownToLine, SunDim, Minus, Plus, Eye, Ruler, SquareDashed, ChevronDown, Link2, Square, MoveDown, MoveRight } from 'lucide-react';
|
|
6
5
|
import { clsx } from 'clsx';
|
|
7
6
|
import { twMerge } from 'tailwind-merge';
|
|
@@ -149,10 +148,23 @@ function BoxModelOverlay({ enabled, target }) {
|
|
|
149
148
|
/* @__PURE__ */ jsx("div", { ref: contentRef, className: band, "aria-hidden": true })
|
|
150
149
|
] });
|
|
151
150
|
}
|
|
151
|
+
function usePrefersReducedMotion() {
|
|
152
|
+
const [reduced, setReduced] = useState(false);
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
155
|
+
const sync = () => setReduced(mq.matches);
|
|
156
|
+
sync();
|
|
157
|
+
mq.addEventListener("change", sync);
|
|
158
|
+
return () => mq.removeEventListener("change", sync);
|
|
159
|
+
}, []);
|
|
160
|
+
return reduced;
|
|
161
|
+
}
|
|
152
162
|
var MONO = "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', monospace";
|
|
153
163
|
var PROMPT_MS = 22;
|
|
154
164
|
var LINE_GAP_MS = 300;
|
|
155
165
|
var AFTER_LAST_MS = 450;
|
|
166
|
+
var EASE_OUT = "cubic-bezier(0.4, 0, 0.2, 1)";
|
|
167
|
+
var DIALOG_EASE = "cubic-bezier(0.34, 1.3, 0.64, 1)";
|
|
156
168
|
function TrafficLightsSvg() {
|
|
157
169
|
return /* @__PURE__ */ jsxs("svg", { width: "52", height: "12", viewBox: "0 0 52 12", "aria-hidden": true, className: "shrink-0", children: [
|
|
158
170
|
/* @__PURE__ */ jsx("circle", { cx: "6", cy: "6", r: "5", fill: "#FF5F57" }),
|
|
@@ -293,11 +305,12 @@ function TerminalTyping({
|
|
|
293
305
|
}
|
|
294
306
|
);
|
|
295
307
|
}
|
|
296
|
-
var EASE_OUT = [0.4, 0, 0.2, 1];
|
|
297
308
|
var DISMISS_AFTER_TYPING_MS = 5200;
|
|
298
309
|
function CopySuccessOverlay({ open, onClose }) {
|
|
299
|
-
const reduceMotion =
|
|
310
|
+
const reduceMotion = usePrefersReducedMotion();
|
|
300
311
|
const [typingComplete, setTypingComplete] = useState(false);
|
|
312
|
+
const [mounted, setMounted] = useState(false);
|
|
313
|
+
const [animIn, setAnimIn] = useState(false);
|
|
301
314
|
const handleTypingComplete = useCallback(() => setTypingComplete(true), []);
|
|
302
315
|
useEffect(() => {
|
|
303
316
|
if (!open) {
|
|
@@ -320,36 +333,57 @@ function CopySuccessOverlay({ open, onClose }) {
|
|
|
320
333
|
const t = window.setTimeout(onClose, DISMISS_AFTER_TYPING_MS);
|
|
321
334
|
return () => window.clearTimeout(t);
|
|
322
335
|
}, [open, typingComplete, onClose]);
|
|
336
|
+
useLayoutEffect(() => {
|
|
337
|
+
if (open) setMounted(true);
|
|
338
|
+
}, [open]);
|
|
339
|
+
useEffect(() => {
|
|
340
|
+
if (!open) {
|
|
341
|
+
setAnimIn(false);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
setAnimIn(false);
|
|
345
|
+
const id = requestAnimationFrame(() => {
|
|
346
|
+
requestAnimationFrame(() => setAnimIn(true));
|
|
347
|
+
});
|
|
348
|
+
return () => cancelAnimationFrame(id);
|
|
349
|
+
}, [open]);
|
|
350
|
+
const onBackdropTransitionEnd = useCallback((e) => {
|
|
351
|
+
if (e.target !== e.currentTarget) return;
|
|
352
|
+
if (e.propertyName !== "opacity") return;
|
|
353
|
+
if (!open) setMounted(false);
|
|
354
|
+
}, [open]);
|
|
323
355
|
if (typeof document === "undefined") return null;
|
|
324
356
|
const running = open && !typingComplete && !reduceMotion;
|
|
357
|
+
const backdropStyle = {
|
|
358
|
+
opacity: animIn ? 1 : 0,
|
|
359
|
+
transition: reduceMotion ? "none" : `opacity 220ms ${EASE_OUT}`
|
|
360
|
+
};
|
|
361
|
+
const dialogStyle = reduceMotion ? {
|
|
362
|
+
opacity: animIn ? 1 : 0,
|
|
363
|
+
transition: `opacity 180ms ${EASE_OUT}`
|
|
364
|
+
} : {
|
|
365
|
+
opacity: animIn ? 1 : 0,
|
|
366
|
+
transform: animIn ? "scale(1) translateY(0)" : "scale(0.94) translateY(14px)",
|
|
367
|
+
transition: `opacity 240ms ${EASE_OUT}, transform 450ms ${DIALOG_EASE}`
|
|
368
|
+
};
|
|
325
369
|
return createPortal(
|
|
326
|
-
/* @__PURE__ */ jsx(
|
|
327
|
-
|
|
370
|
+
/* @__PURE__ */ jsx(Fragment, { children: mounted && /* @__PURE__ */ jsx(
|
|
371
|
+
"div",
|
|
328
372
|
{
|
|
329
373
|
className: "fixed inset-0 z-[10020] flex items-center justify-center bg-black/50 p-4 backdrop-blur-[3px]",
|
|
330
|
-
style: { fontFamily: MONO },
|
|
331
|
-
initial: { opacity: 0 },
|
|
332
|
-
animate: { opacity: 1 },
|
|
333
|
-
exit: { opacity: 0 },
|
|
334
|
-
transition: { duration: 0.22, ease: EASE_OUT },
|
|
374
|
+
style: { ...backdropStyle, fontFamily: MONO },
|
|
335
375
|
onClick: onClose,
|
|
376
|
+
onTransitionEnd: onBackdropTransitionEnd,
|
|
336
377
|
role: "presentation",
|
|
337
378
|
children: /* @__PURE__ */ jsxs(
|
|
338
|
-
|
|
379
|
+
"div",
|
|
339
380
|
{
|
|
340
381
|
role: "dialog",
|
|
341
382
|
"aria-modal": "true",
|
|
342
383
|
"aria-labelledby": "flux-copy-success-title",
|
|
343
384
|
className: "max-h-[min(90vh,640px)] w-full max-w-[520px] overflow-hidden rounded-xl border border-zinc-200 bg-white shadow-[0_24px_80px_rgba(0,0,0,0.2)]",
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
animate: reduceMotion ? { opacity: 1 } : { opacity: 1, scale: 1, y: 0 },
|
|
347
|
-
exit: reduceMotion ? { opacity: 0 } : { opacity: 0, scale: 0.97, y: 8 },
|
|
348
|
-
transition: reduceMotion ? { duration: 0.18, ease: EASE_OUT } : {
|
|
349
|
-
opacity: { duration: 0.24, ease: EASE_OUT },
|
|
350
|
-
scale: { type: "spring", stiffness: 420, damping: 32, mass: 0.85 },
|
|
351
|
-
y: { type: "spring", stiffness: 420, damping: 34, mass: 0.85 }
|
|
352
|
-
},
|
|
385
|
+
style: dialogStyle,
|
|
386
|
+
onClick: (ev) => ev.stopPropagation(),
|
|
353
387
|
children: [
|
|
354
388
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 border-b border-zinc-200/90 bg-zinc-50/90 px-3 py-2", children: [
|
|
355
389
|
/* @__PURE__ */ jsx(TrafficLightsSvg, {}),
|
|
@@ -374,8 +408,7 @@ function CopySuccessOverlay({ open, onClose }) {
|
|
|
374
408
|
]
|
|
375
409
|
}
|
|
376
410
|
)
|
|
377
|
-
}
|
|
378
|
-
"flux-copy-success-overlay"
|
|
411
|
+
}
|
|
379
412
|
) }),
|
|
380
413
|
document.body
|
|
381
414
|
);
|
|
@@ -7459,6 +7492,7 @@ function DesignEditorImpl({
|
|
|
7459
7492
|
blockPageInteractions
|
|
7460
7493
|
}) {
|
|
7461
7494
|
const [enabled, setEnabled] = useState(false);
|
|
7495
|
+
const [isExiting, setIsExiting] = useState(false);
|
|
7462
7496
|
const [width, setWidth] = useState(DEFAULT_WIDTH);
|
|
7463
7497
|
const [layoutW, setLayoutW] = useState(0);
|
|
7464
7498
|
const resizeRef = useRef(null);
|
|
@@ -7572,6 +7606,9 @@ button[data-flux-floating-toggle]:hover {
|
|
|
7572
7606
|
flushSync(() => {
|
|
7573
7607
|
setExitClipVp(getEditorToggleViewportCenter());
|
|
7574
7608
|
});
|
|
7609
|
+
flushSync(() => {
|
|
7610
|
+
setIsExiting(true);
|
|
7611
|
+
});
|
|
7575
7612
|
flushSync(() => {
|
|
7576
7613
|
setEnabled(false);
|
|
7577
7614
|
});
|
|
@@ -7695,7 +7732,11 @@ button[data-flux-floating-toggle]:hover {
|
|
|
7695
7732
|
}
|
|
7696
7733
|
return copyCombinedPromptToClipboard(items, structuralReorders);
|
|
7697
7734
|
}, [getCopyBatchItems, structuralReorders]);
|
|
7698
|
-
const reduceMotion =
|
|
7735
|
+
const reduceMotion = usePrefersReducedMotion();
|
|
7736
|
+
const panelRef = useRef(null);
|
|
7737
|
+
const panelVisible = enabled || isExiting;
|
|
7738
|
+
const irisOpenDoneRef = useRef(false);
|
|
7739
|
+
const exitAnimStartedRef = useRef(false);
|
|
7699
7740
|
const themeRevealDuration = useMemo(() => readThemeTransitionDurationSeconds(), []);
|
|
7700
7741
|
const effectiveWidth = useMemo(() => {
|
|
7701
7742
|
const lw = layoutW > 0 ? layoutW : layoutViewportWidth();
|
|
@@ -7706,10 +7747,80 @@ button[data-flux-floating-toggle]:hover {
|
|
|
7706
7747
|
const openO = viewportToPanelClipOrigin(openClipVpRef.current.x, openClipVpRef.current.y, effectiveWidth);
|
|
7707
7748
|
const exitVpForClip = exitClipVp ?? defaultExitViewport();
|
|
7708
7749
|
const closeO = viewportToPanelClipOrigin(exitVpForClip.x, exitVpForClip.y, effectiveWidth);
|
|
7709
|
-
const
|
|
7710
|
-
const
|
|
7711
|
-
|
|
7750
|
+
const easeReveal = `cubic-bezier(${THEME_REVEAL_EASE.join(",")})`;
|
|
7751
|
+
const easeExit = `cubic-bezier(${IRIS_EXIT_EASE.join(",")})`;
|
|
7752
|
+
useEffect(() => {
|
|
7753
|
+
if (!enabled) irisOpenDoneRef.current = false;
|
|
7754
|
+
}, [enabled]);
|
|
7755
|
+
useEffect(() => {
|
|
7756
|
+
if (!isExiting) exitAnimStartedRef.current = false;
|
|
7757
|
+
}, [isExiting]);
|
|
7758
|
+
useLayoutEffect(() => {
|
|
7759
|
+
if (!panelVisible || !enabled || isExiting) return;
|
|
7760
|
+
if (irisOpenDoneRef.current) return;
|
|
7761
|
+
const el = panelRef.current;
|
|
7762
|
+
if (!el) return;
|
|
7763
|
+
irisOpenDoneRef.current = true;
|
|
7764
|
+
if (reduceMotion) {
|
|
7765
|
+
el.style.transition = "";
|
|
7766
|
+
el.style.clipPath = "none";
|
|
7767
|
+
return;
|
|
7768
|
+
}
|
|
7769
|
+
el.style.transition = "none";
|
|
7770
|
+
el.style.clipPath = `circle(0px at ${openO.ox}px ${openO.oy}px)`;
|
|
7771
|
+
const id = requestAnimationFrame(() => {
|
|
7772
|
+
requestAnimationFrame(() => {
|
|
7773
|
+
el.style.transition = `clip-path ${themeRevealDuration}s ${easeReveal}`;
|
|
7774
|
+
el.style.clipPath = `circle(150vmax at ${openO.ox}px ${openO.oy}px)`;
|
|
7775
|
+
});
|
|
7776
|
+
});
|
|
7777
|
+
return () => cancelAnimationFrame(id);
|
|
7778
|
+
}, [
|
|
7779
|
+
panelVisible,
|
|
7780
|
+
enabled,
|
|
7781
|
+
isExiting,
|
|
7782
|
+
reduceMotion,
|
|
7783
|
+
themeRevealDuration,
|
|
7784
|
+
easeReveal,
|
|
7785
|
+
openO.ox,
|
|
7786
|
+
openO.oy
|
|
7787
|
+
]);
|
|
7788
|
+
useLayoutEffect(() => {
|
|
7789
|
+
if (!isExiting || enabled) return;
|
|
7790
|
+
if (exitAnimStartedRef.current) return;
|
|
7791
|
+
const el = panelRef.current;
|
|
7792
|
+
if (!el) return;
|
|
7793
|
+
exitAnimStartedRef.current = true;
|
|
7794
|
+
if (reduceMotion) {
|
|
7795
|
+
el.style.transition = "";
|
|
7796
|
+
el.style.clipPath = `circle(0px at ${closeO.ox}px ${closeO.oy}px)`;
|
|
7797
|
+
queueMicrotask(() => {
|
|
7798
|
+
setIsExiting(false);
|
|
7799
|
+
setExitClipVp(null);
|
|
7800
|
+
});
|
|
7801
|
+
return;
|
|
7802
|
+
}
|
|
7803
|
+
el.style.transition = "none";
|
|
7804
|
+
el.style.clipPath = `circle(150vmax at ${openO.ox}px ${openO.oy}px)`;
|
|
7805
|
+
void el.offsetHeight;
|
|
7806
|
+
el.style.transition = `clip-path ${themeRevealDuration}s ${easeExit}`;
|
|
7807
|
+
el.style.clipPath = `circle(0px at ${closeO.ox}px ${closeO.oy}px)`;
|
|
7808
|
+
}, [isExiting, enabled, reduceMotion, themeRevealDuration, easeExit, openO.ox, openO.oy, closeO.ox, closeO.oy]);
|
|
7809
|
+
const onPanelTransitionEnd = useCallback(
|
|
7810
|
+
(e) => {
|
|
7811
|
+
if (e.propertyName !== "clip-path") return;
|
|
7812
|
+
if (!isExiting || enabled || reduceMotion) return;
|
|
7813
|
+
setIsExiting(false);
|
|
7814
|
+
setExitClipVp(null);
|
|
7815
|
+
},
|
|
7816
|
+
[isExiting, enabled, reduceMotion]
|
|
7817
|
+
);
|
|
7818
|
+
const panelContent = /* @__PURE__ */ jsx(Fragment, { children: panelVisible && /* @__PURE__ */ jsxs(
|
|
7819
|
+
"div",
|
|
7712
7820
|
{
|
|
7821
|
+
ref: panelRef,
|
|
7822
|
+
"data-flux-ui": true,
|
|
7823
|
+
onTransitionEnd: onPanelTransitionEnd,
|
|
7713
7824
|
style: {
|
|
7714
7825
|
position: "fixed",
|
|
7715
7826
|
top: 8,
|
|
@@ -7726,18 +7837,8 @@ button[data-flux-floating-toggle]:hover {
|
|
|
7726
7837
|
color: "#D9D9D9",
|
|
7727
7838
|
colorScheme: "dark",
|
|
7728
7839
|
WebkitFontSmoothing: "antialiased",
|
|
7729
|
-
pointerEvents: "auto"
|
|
7730
|
-
|
|
7731
|
-
initial: reduceMotion === true ? { clipPath: "none" } : { clipPath: `circle(0px at ${openO.ox}px ${openO.oy}px)` },
|
|
7732
|
-
animate: reduceMotion === true ? { clipPath: "none" } : { clipPath: `circle(150vmax at ${irisAt.ox}px ${irisAt.oy}px)` },
|
|
7733
|
-
exit: reduceMotion === true ? { clipPath: "none", transition: { duration: 0 } } : {
|
|
7734
|
-
clipPath: `circle(0px at ${closeO.ox}px ${closeO.oy}px)`,
|
|
7735
|
-
transition: {
|
|
7736
|
-
clipPath: { duration: themeRevealDuration, ease: IRIS_EXIT_EASE }
|
|
7737
|
-
}
|
|
7738
|
-
},
|
|
7739
|
-
transition: reduceMotion === true ? { duration: 0 } : {
|
|
7740
|
-
clipPath: { duration: themeRevealDuration, ease: THEME_REVEAL_EASE }
|
|
7840
|
+
pointerEvents: "auto",
|
|
7841
|
+
willChange: reduceMotion ? void 0 : "clip-path"
|
|
7741
7842
|
},
|
|
7742
7843
|
children: [
|
|
7743
7844
|
/* @__PURE__ */ jsx(
|
|
@@ -7764,6 +7865,9 @@ button[data-flux-floating-toggle]:hover {
|
|
|
7764
7865
|
flushSync(() => {
|
|
7765
7866
|
setExitClipVp(getEditorToggleViewportCenter());
|
|
7766
7867
|
});
|
|
7868
|
+
flushSync(() => {
|
|
7869
|
+
setIsExiting(true);
|
|
7870
|
+
});
|
|
7767
7871
|
flushSync(() => {
|
|
7768
7872
|
setEnabled(false);
|
|
7769
7873
|
});
|
|
@@ -7794,8 +7898,7 @@ button[data-flux-floating-toggle]:hover {
|
|
|
7794
7898
|
selectedElement ? getElementPath(selectedElement) : "none"
|
|
7795
7899
|
) })
|
|
7796
7900
|
]
|
|
7797
|
-
}
|
|
7798
|
-
"flux-panel"
|
|
7901
|
+
}
|
|
7799
7902
|
) });
|
|
7800
7903
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7801
7904
|
!enabled && /* @__PURE__ */ jsx(
|