@fluix-ui/vanilla 0.0.6 → 0.0.7
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 +106 -2
- package/dist/index.cjs +246 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -3
- package/dist/index.d.ts +35 -3
- package/dist/index.global.js +954 -0
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +247 -2
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.global.js
CHANGED
|
@@ -521,6 +521,713 @@ var Fluix = (function (exports) {
|
|
|
521
521
|
}
|
|
522
522
|
};
|
|
523
523
|
}
|
|
524
|
+
var MENU_DEFAULTS = {
|
|
525
|
+
orientation: "vertical",
|
|
526
|
+
roundness: 16
|
|
527
|
+
};
|
|
528
|
+
function createMenuMachine(initialConfig) {
|
|
529
|
+
const store = createStore({
|
|
530
|
+
activeId: initialConfig?.initialActiveId ?? null,
|
|
531
|
+
config: { ...initialConfig }
|
|
532
|
+
});
|
|
533
|
+
function setActive(id) {
|
|
534
|
+
store.update((prev) => {
|
|
535
|
+
if (prev.activeId === id) return prev;
|
|
536
|
+
return { ...prev, activeId: id };
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
function configure(config) {
|
|
540
|
+
store.update((prev) => ({ ...prev, config: { ...prev.config, ...config } }));
|
|
541
|
+
}
|
|
542
|
+
function destroy() {
|
|
543
|
+
}
|
|
544
|
+
return { store, setActive, configure, destroy };
|
|
545
|
+
}
|
|
546
|
+
function getMenuAttrs(context) {
|
|
547
|
+
const root = {
|
|
548
|
+
"data-fluix-menu": "",
|
|
549
|
+
"data-orientation": context.orientation
|
|
550
|
+
};
|
|
551
|
+
if (context.theme) {
|
|
552
|
+
root["data-theme"] = context.theme;
|
|
553
|
+
}
|
|
554
|
+
if (context.variant) {
|
|
555
|
+
root["data-variant"] = context.variant;
|
|
556
|
+
}
|
|
557
|
+
return {
|
|
558
|
+
root,
|
|
559
|
+
list: {
|
|
560
|
+
"data-fluix-menu-list": ""
|
|
561
|
+
},
|
|
562
|
+
canvas: {
|
|
563
|
+
"data-fluix-menu-canvas": ""
|
|
564
|
+
},
|
|
565
|
+
indicator: {
|
|
566
|
+
"data-fluix-menu-indicator": ""
|
|
567
|
+
},
|
|
568
|
+
item(itemContext) {
|
|
569
|
+
const item = {
|
|
570
|
+
"data-fluix-menu-item": "",
|
|
571
|
+
"data-menu-id": itemContext.id,
|
|
572
|
+
"data-state": itemContext.active ? "active" : "inactive"
|
|
573
|
+
};
|
|
574
|
+
if (itemContext.disabled) {
|
|
575
|
+
item["data-disabled"] = "true";
|
|
576
|
+
}
|
|
577
|
+
return item;
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
var ITEM_SELECTOR = "[data-fluix-menu-item]";
|
|
582
|
+
var TAB_CURVE_RADIUS = 14;
|
|
583
|
+
function readItemFrame(root, activeId, padding, variant, orientation) {
|
|
584
|
+
const activeItem = root.querySelector(
|
|
585
|
+
`${ITEM_SELECTOR}[data-menu-id="${CSS.escape(activeId)}"]`
|
|
586
|
+
);
|
|
587
|
+
if (!activeItem) return null;
|
|
588
|
+
const rootRect = root.getBoundingClientRect();
|
|
589
|
+
const itemRect = activeItem.getBoundingClientRect();
|
|
590
|
+
const width = Math.max(0, itemRect.width + padding * 2);
|
|
591
|
+
const height = Math.max(0, itemRect.height + padding * 2);
|
|
592
|
+
const x = itemRect.left - rootRect.left - padding;
|
|
593
|
+
const y = itemRect.top - rootRect.top - padding;
|
|
594
|
+
if (variant === "tab") {
|
|
595
|
+
if (orientation === "horizontal") {
|
|
596
|
+
const extendedHeight = rootRect.height - y + 1;
|
|
597
|
+
return {
|
|
598
|
+
x,
|
|
599
|
+
y,
|
|
600
|
+
width,
|
|
601
|
+
height: extendedHeight,
|
|
602
|
+
radius: height / 2,
|
|
603
|
+
// use original item height for top pill arc
|
|
604
|
+
visible: width > 0 && height > 0
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
const extendedWidth = rootRect.width - x;
|
|
608
|
+
return {
|
|
609
|
+
x,
|
|
610
|
+
y,
|
|
611
|
+
width: extendedWidth,
|
|
612
|
+
height,
|
|
613
|
+
radius: height / 2,
|
|
614
|
+
visible: width > 0 && height > 0
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
return {
|
|
618
|
+
x,
|
|
619
|
+
y,
|
|
620
|
+
width,
|
|
621
|
+
height,
|
|
622
|
+
radius: height / 2,
|
|
623
|
+
visible: width > 0 && height > 0
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
function generateTabPath(frame, cr) {
|
|
627
|
+
const { x, y, width, height } = frame;
|
|
628
|
+
const r = Math.min(frame.radius, height / 2, width / 2);
|
|
629
|
+
const rw = x + width;
|
|
630
|
+
const concaveR = Math.min(cr, height / 2, Math.max(0, width / 2 - r));
|
|
631
|
+
return [
|
|
632
|
+
`M ${x + r} ${y}`,
|
|
633
|
+
`L ${rw - concaveR} ${y}`,
|
|
634
|
+
`Q ${rw} ${y} ${rw} ${y - concaveR}`,
|
|
635
|
+
`L ${rw} ${y + height + concaveR}`,
|
|
636
|
+
`Q ${rw} ${y + height} ${rw - concaveR} ${y + height}`,
|
|
637
|
+
`L ${x + r} ${y + height}`,
|
|
638
|
+
`A ${r} ${r} 0 0 1 ${x} ${y + height - r}`,
|
|
639
|
+
`L ${x} ${y + r}`,
|
|
640
|
+
`A ${r} ${r} 0 0 1 ${x + r} ${y}`,
|
|
641
|
+
"Z"
|
|
642
|
+
].join(" ");
|
|
643
|
+
}
|
|
644
|
+
function generateHorizontalTabPath(frame, cr) {
|
|
645
|
+
const { x, y, width, height } = frame;
|
|
646
|
+
const r = Math.min(frame.radius, width / 2, height / 2);
|
|
647
|
+
const bottom = y + height;
|
|
648
|
+
const concaveR = Math.min(cr, width / 2, Math.max(0, height - r));
|
|
649
|
+
return [
|
|
650
|
+
// Start at top-left, after the rounded corner
|
|
651
|
+
`M ${x} ${y + r}`,
|
|
652
|
+
// Arc from left edge to top edge (top-left rounded corner)
|
|
653
|
+
`A ${r} ${r} 0 0 1 ${x + r} ${y}`,
|
|
654
|
+
// Top edge to top-right corner
|
|
655
|
+
`L ${x + width - r} ${y}`,
|
|
656
|
+
// Arc from top edge to right edge (top-right rounded corner)
|
|
657
|
+
`A ${r} ${r} 0 0 1 ${x + width} ${y + r}`,
|
|
658
|
+
// Right edge down to bottom-right concave
|
|
659
|
+
`L ${x + width} ${bottom - concaveR}`,
|
|
660
|
+
// Concave curve at bottom-right (curves outward)
|
|
661
|
+
`Q ${x + width} ${bottom} ${x + width + concaveR} ${bottom}`,
|
|
662
|
+
// Flat bottom edge (off to the right, then back to the left)
|
|
663
|
+
`L ${x - concaveR} ${bottom}`,
|
|
664
|
+
// Concave curve at bottom-left (curves outward)
|
|
665
|
+
`Q ${x} ${bottom} ${x} ${bottom - concaveR}`,
|
|
666
|
+
// Left edge back up
|
|
667
|
+
`L ${x} ${y + r}`,
|
|
668
|
+
"Z"
|
|
669
|
+
].join(" ");
|
|
670
|
+
}
|
|
671
|
+
function applyFrame(indicator, frame, variant, orientation) {
|
|
672
|
+
if (variant === "tab") {
|
|
673
|
+
const path = indicator;
|
|
674
|
+
const generator = orientation === "horizontal" ? generateHorizontalTabPath : generateTabPath;
|
|
675
|
+
path.setAttribute("d", generator(frame, TAB_CURVE_RADIUS));
|
|
676
|
+
path.setAttribute("opacity", frame.visible ? "1" : "0");
|
|
677
|
+
} else {
|
|
678
|
+
const rect = indicator;
|
|
679
|
+
rect.setAttribute("x", String(frame.x));
|
|
680
|
+
rect.setAttribute("y", String(frame.y));
|
|
681
|
+
rect.setAttribute("width", String(frame.width));
|
|
682
|
+
rect.setAttribute("height", String(frame.height));
|
|
683
|
+
rect.setAttribute("rx", String(frame.radius));
|
|
684
|
+
rect.setAttribute("ry", String(frame.radius));
|
|
685
|
+
rect.setAttribute("opacity", frame.visible ? "1" : "0");
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
function frameEquals(a, b) {
|
|
689
|
+
if (!a || !b) return false;
|
|
690
|
+
return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height && a.radius === b.radius && a.visible === b.visible;
|
|
691
|
+
}
|
|
692
|
+
function simulateSpringValues(config) {
|
|
693
|
+
const { stiffness, damping, mass } = config;
|
|
694
|
+
const dt = 1 / 120;
|
|
695
|
+
const maxDuration = 3;
|
|
696
|
+
const samples = [0];
|
|
697
|
+
let position = 0;
|
|
698
|
+
let velocity = 0;
|
|
699
|
+
let t = 0;
|
|
700
|
+
while (t < maxDuration) {
|
|
701
|
+
const acceleration = (-stiffness * (position - 1) - damping * velocity) / mass;
|
|
702
|
+
const midVelocity = velocity + acceleration * (dt / 2);
|
|
703
|
+
const midPosition = position + velocity * (dt / 2);
|
|
704
|
+
const midAcceleration = (-stiffness * (midPosition - 1) - damping * midVelocity) / mass;
|
|
705
|
+
velocity = velocity + midAcceleration * dt;
|
|
706
|
+
position = position + midVelocity * dt;
|
|
707
|
+
t += dt;
|
|
708
|
+
samples.push(position);
|
|
709
|
+
if (Math.abs(position - 1) < 1e-3 && Math.abs(velocity) < 1e-3) break;
|
|
710
|
+
}
|
|
711
|
+
samples.push(1);
|
|
712
|
+
return samples;
|
|
713
|
+
}
|
|
714
|
+
function lerp(a, b, t) {
|
|
715
|
+
return a + (b - a) * t;
|
|
716
|
+
}
|
|
717
|
+
function easeOutCubic(t) {
|
|
718
|
+
return 1 - (1 - t) ** 3;
|
|
719
|
+
}
|
|
720
|
+
var EXIT_MS = 130;
|
|
721
|
+
function animateTabEnter(path, from, to, cr, spring) {
|
|
722
|
+
const rightEdge = from.x + from.width;
|
|
723
|
+
const samples = simulateSpringValues(spring);
|
|
724
|
+
const count = samples.length;
|
|
725
|
+
const durationMs = count / 120 * 1e3;
|
|
726
|
+
const startTime = performance.now();
|
|
727
|
+
let cancelled = false;
|
|
728
|
+
const handle = {
|
|
729
|
+
onfinish: null,
|
|
730
|
+
cancel() {
|
|
731
|
+
cancelled = true;
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
function tick() {
|
|
735
|
+
if (cancelled) return;
|
|
736
|
+
const elapsed = performance.now() - startTime;
|
|
737
|
+
const progress = Math.min(elapsed / durationMs, 1);
|
|
738
|
+
const idx = Math.min(Math.floor(progress * (count - 1)), count - 1);
|
|
739
|
+
const t = samples[idx];
|
|
740
|
+
const frame = {
|
|
741
|
+
x: lerp(rightEdge, to.x, t),
|
|
742
|
+
y: to.y,
|
|
743
|
+
width: lerp(0, to.width, t),
|
|
744
|
+
height: to.height,
|
|
745
|
+
radius: to.radius
|
|
746
|
+
};
|
|
747
|
+
path.setAttribute("d", generateTabPath(frame, cr));
|
|
748
|
+
if (progress < 1) {
|
|
749
|
+
requestAnimationFrame(tick);
|
|
750
|
+
} else {
|
|
751
|
+
handle.onfinish?.();
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
requestAnimationFrame(tick);
|
|
755
|
+
return handle;
|
|
756
|
+
}
|
|
757
|
+
function animateHorizontalTabEnter(path, from, to, cr, spring) {
|
|
758
|
+
const bottomEdge = from.y + from.height;
|
|
759
|
+
const samples = simulateSpringValues(spring);
|
|
760
|
+
const count = samples.length;
|
|
761
|
+
const durationMs = count / 120 * 1e3;
|
|
762
|
+
const startTime = performance.now();
|
|
763
|
+
let cancelled = false;
|
|
764
|
+
const handle = {
|
|
765
|
+
onfinish: null,
|
|
766
|
+
cancel() {
|
|
767
|
+
cancelled = true;
|
|
768
|
+
}
|
|
769
|
+
};
|
|
770
|
+
function tick() {
|
|
771
|
+
if (cancelled) return;
|
|
772
|
+
const elapsed = performance.now() - startTime;
|
|
773
|
+
const progress = Math.min(elapsed / durationMs, 1);
|
|
774
|
+
const idx = Math.min(Math.floor(progress * (count - 1)), count - 1);
|
|
775
|
+
const t = samples[idx];
|
|
776
|
+
const frame = {
|
|
777
|
+
x: to.x,
|
|
778
|
+
y: lerp(bottomEdge, to.y, t),
|
|
779
|
+
width: to.width,
|
|
780
|
+
height: lerp(0, to.height, t),
|
|
781
|
+
radius: to.radius
|
|
782
|
+
};
|
|
783
|
+
path.setAttribute("d", generateHorizontalTabPath(frame, cr));
|
|
784
|
+
if (progress < 1) {
|
|
785
|
+
requestAnimationFrame(tick);
|
|
786
|
+
} else {
|
|
787
|
+
handle.onfinish?.();
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
requestAnimationFrame(tick);
|
|
791
|
+
return handle;
|
|
792
|
+
}
|
|
793
|
+
function animateTabIndicator(path, from, to, cr, spring, onEnterStart) {
|
|
794
|
+
const rightEdge = from.x + from.width;
|
|
795
|
+
const enterSamples = simulateSpringValues({
|
|
796
|
+
stiffness: spring.stiffness * 3,
|
|
797
|
+
damping: spring.damping * 1.8,
|
|
798
|
+
mass: spring.mass
|
|
799
|
+
});
|
|
800
|
+
const enterCount = enterSamples.length;
|
|
801
|
+
const enterMs = enterCount / 120 * 1e3;
|
|
802
|
+
const totalMs = EXIT_MS + enterMs;
|
|
803
|
+
const startTime = performance.now();
|
|
804
|
+
let cancelled = false;
|
|
805
|
+
let enteredPhase2 = false;
|
|
806
|
+
const handle = {
|
|
807
|
+
onfinish: null,
|
|
808
|
+
cancel() {
|
|
809
|
+
cancelled = true;
|
|
810
|
+
}
|
|
811
|
+
};
|
|
812
|
+
function tick() {
|
|
813
|
+
if (cancelled) return;
|
|
814
|
+
const elapsed = performance.now() - startTime;
|
|
815
|
+
let frame;
|
|
816
|
+
if (elapsed < EXIT_MS) {
|
|
817
|
+
const t = easeOutCubic(elapsed / EXIT_MS);
|
|
818
|
+
frame = {
|
|
819
|
+
x: lerp(from.x, rightEdge, t),
|
|
820
|
+
y: from.y,
|
|
821
|
+
width: lerp(from.width, 0, t),
|
|
822
|
+
height: from.height,
|
|
823
|
+
radius: from.radius,
|
|
824
|
+
visible: true
|
|
825
|
+
};
|
|
826
|
+
} else {
|
|
827
|
+
if (!enteredPhase2) {
|
|
828
|
+
enteredPhase2 = true;
|
|
829
|
+
onEnterStart?.();
|
|
830
|
+
}
|
|
831
|
+
const phaseElapsed = elapsed - EXIT_MS;
|
|
832
|
+
const phaseProgress = Math.min(phaseElapsed / enterMs, 1);
|
|
833
|
+
const idx = Math.min(
|
|
834
|
+
Math.floor(phaseProgress * (enterCount - 1)),
|
|
835
|
+
enterCount - 1
|
|
836
|
+
);
|
|
837
|
+
const t = enterSamples[idx];
|
|
838
|
+
frame = {
|
|
839
|
+
x: lerp(rightEdge, to.x, t),
|
|
840
|
+
y: to.y,
|
|
841
|
+
width: lerp(0, to.width, t),
|
|
842
|
+
height: to.height,
|
|
843
|
+
radius: to.radius,
|
|
844
|
+
visible: true
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
path.setAttribute("d", generateTabPath(frame, cr));
|
|
848
|
+
if (elapsed < totalMs) {
|
|
849
|
+
requestAnimationFrame(tick);
|
|
850
|
+
} else {
|
|
851
|
+
handle.onfinish?.();
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
requestAnimationFrame(tick);
|
|
855
|
+
return handle;
|
|
856
|
+
}
|
|
857
|
+
function animateHorizontalTabIndicator(path, from, to, cr, spring, onEnterStart) {
|
|
858
|
+
const bottomEdge = from.y + from.height;
|
|
859
|
+
const enterSamples = simulateSpringValues({
|
|
860
|
+
stiffness: spring.stiffness * 3,
|
|
861
|
+
damping: spring.damping * 1.8,
|
|
862
|
+
mass: spring.mass
|
|
863
|
+
});
|
|
864
|
+
const enterCount = enterSamples.length;
|
|
865
|
+
const enterMs = enterCount / 120 * 1e3;
|
|
866
|
+
const totalMs = EXIT_MS + enterMs;
|
|
867
|
+
const startTime = performance.now();
|
|
868
|
+
let cancelled = false;
|
|
869
|
+
let enteredPhase2 = false;
|
|
870
|
+
const handle = {
|
|
871
|
+
onfinish: null,
|
|
872
|
+
cancel() {
|
|
873
|
+
cancelled = true;
|
|
874
|
+
}
|
|
875
|
+
};
|
|
876
|
+
function tick() {
|
|
877
|
+
if (cancelled) return;
|
|
878
|
+
const elapsed = performance.now() - startTime;
|
|
879
|
+
let frame;
|
|
880
|
+
if (elapsed < EXIT_MS) {
|
|
881
|
+
const t = easeOutCubic(elapsed / EXIT_MS);
|
|
882
|
+
frame = {
|
|
883
|
+
x: from.x,
|
|
884
|
+
y: lerp(from.y, bottomEdge, t),
|
|
885
|
+
width: from.width,
|
|
886
|
+
height: lerp(from.height, 0, t),
|
|
887
|
+
radius: from.radius,
|
|
888
|
+
visible: true
|
|
889
|
+
};
|
|
890
|
+
} else {
|
|
891
|
+
if (!enteredPhase2) {
|
|
892
|
+
enteredPhase2 = true;
|
|
893
|
+
onEnterStart?.();
|
|
894
|
+
}
|
|
895
|
+
const phaseElapsed = elapsed - EXIT_MS;
|
|
896
|
+
const phaseProgress = Math.min(phaseElapsed / enterMs, 1);
|
|
897
|
+
const idx = Math.min(
|
|
898
|
+
Math.floor(phaseProgress * (enterCount - 1)),
|
|
899
|
+
enterCount - 1
|
|
900
|
+
);
|
|
901
|
+
const t = enterSamples[idx];
|
|
902
|
+
frame = {
|
|
903
|
+
x: to.x,
|
|
904
|
+
y: lerp(bottomEdge, to.y, t),
|
|
905
|
+
width: to.width,
|
|
906
|
+
height: lerp(0, to.height, t),
|
|
907
|
+
radius: to.radius,
|
|
908
|
+
visible: true
|
|
909
|
+
};
|
|
910
|
+
}
|
|
911
|
+
path.setAttribute("d", generateHorizontalTabPath(frame, cr));
|
|
912
|
+
if (elapsed < totalMs) {
|
|
913
|
+
requestAnimationFrame(tick);
|
|
914
|
+
} else {
|
|
915
|
+
handle.onfinish?.();
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
requestAnimationFrame(tick);
|
|
919
|
+
return handle;
|
|
920
|
+
}
|
|
921
|
+
var STRETCH_MS = 150;
|
|
922
|
+
function animatePillMorph(rect, from, to, spring) {
|
|
923
|
+
const stretchedX = Math.min(from.x, to.x);
|
|
924
|
+
const stretchedRight = Math.max(from.x + from.width, to.x + to.width);
|
|
925
|
+
const stretchedWidth = stretchedRight - stretchedX;
|
|
926
|
+
const contractSamples = simulateSpringValues({
|
|
927
|
+
stiffness: spring.stiffness * 2.5,
|
|
928
|
+
damping: spring.damping * 1.6,
|
|
929
|
+
mass: spring.mass
|
|
930
|
+
});
|
|
931
|
+
const contractCount = contractSamples.length;
|
|
932
|
+
const contractMs = contractCount / 120 * 1e3;
|
|
933
|
+
const totalMs = STRETCH_MS + contractMs;
|
|
934
|
+
const startTime = performance.now();
|
|
935
|
+
let cancelled = false;
|
|
936
|
+
const handle = {
|
|
937
|
+
onfinish: null,
|
|
938
|
+
cancel() {
|
|
939
|
+
cancelled = true;
|
|
940
|
+
}
|
|
941
|
+
};
|
|
942
|
+
function applyRect(x, y, w, h, r) {
|
|
943
|
+
rect.setAttribute("x", String(x));
|
|
944
|
+
rect.setAttribute("y", String(y));
|
|
945
|
+
rect.setAttribute("width", String(w));
|
|
946
|
+
rect.setAttribute("height", String(h));
|
|
947
|
+
rect.setAttribute("rx", String(r));
|
|
948
|
+
rect.setAttribute("ry", String(r));
|
|
949
|
+
}
|
|
950
|
+
function tick() {
|
|
951
|
+
if (cancelled) return;
|
|
952
|
+
const elapsed = performance.now() - startTime;
|
|
953
|
+
if (elapsed < STRETCH_MS) {
|
|
954
|
+
const t = easeOutCubic(elapsed / STRETCH_MS);
|
|
955
|
+
applyRect(
|
|
956
|
+
lerp(from.x, stretchedX, t),
|
|
957
|
+
lerp(from.y, to.y, t),
|
|
958
|
+
lerp(from.width, stretchedWidth, t),
|
|
959
|
+
lerp(from.height, to.height, t),
|
|
960
|
+
lerp(from.radius, to.radius, t)
|
|
961
|
+
);
|
|
962
|
+
} else {
|
|
963
|
+
const phaseElapsed = elapsed - STRETCH_MS;
|
|
964
|
+
const phaseProgress = Math.min(phaseElapsed / contractMs, 1);
|
|
965
|
+
const idx = Math.min(Math.floor(phaseProgress * (contractCount - 1)), contractCount - 1);
|
|
966
|
+
const t = contractSamples[idx];
|
|
967
|
+
applyRect(
|
|
968
|
+
lerp(stretchedX, to.x, t),
|
|
969
|
+
to.y,
|
|
970
|
+
lerp(stretchedWidth, to.width, t),
|
|
971
|
+
to.height,
|
|
972
|
+
to.radius
|
|
973
|
+
);
|
|
974
|
+
}
|
|
975
|
+
if (elapsed < totalMs) {
|
|
976
|
+
requestAnimationFrame(tick);
|
|
977
|
+
} else {
|
|
978
|
+
handle.onfinish?.();
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
requestAnimationFrame(tick);
|
|
982
|
+
return handle;
|
|
983
|
+
}
|
|
984
|
+
function connectMenu(options) {
|
|
985
|
+
const spring = options.spring ?? FLUIX_SPRING;
|
|
986
|
+
const padding = options.padding ?? 6;
|
|
987
|
+
const variant = options.variant;
|
|
988
|
+
const orientation = options.orientation;
|
|
989
|
+
const cleanups = [];
|
|
990
|
+
let currentAnimation = null;
|
|
991
|
+
let lastFrame = null;
|
|
992
|
+
let rafId = 0;
|
|
993
|
+
let resizeObserver = null;
|
|
994
|
+
let mutationObserver = null;
|
|
995
|
+
let previousActiveId = null;
|
|
996
|
+
let animOldId = null;
|
|
997
|
+
let animNewId = null;
|
|
998
|
+
let animPhase = null;
|
|
999
|
+
function setItemState(id, state) {
|
|
1000
|
+
const el = options.root.querySelector(
|
|
1001
|
+
`${ITEM_SELECTOR}[data-menu-id="${CSS.escape(id)}"]`
|
|
1002
|
+
);
|
|
1003
|
+
if (el && el.dataset["state"] !== state) {
|
|
1004
|
+
el.dataset["state"] = state;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
function enforceAnimStates() {
|
|
1008
|
+
if (!animPhase) return;
|
|
1009
|
+
if (animPhase === "exit") {
|
|
1010
|
+
if (animOldId) setItemState(animOldId, "active");
|
|
1011
|
+
if (animNewId) setItemState(animNewId, "inactive");
|
|
1012
|
+
} else {
|
|
1013
|
+
if (animOldId) setItemState(animOldId, "inactive");
|
|
1014
|
+
if (animNewId) setItemState(animNewId, "active");
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
function clearAnimState() {
|
|
1018
|
+
animOldId = null;
|
|
1019
|
+
animNewId = null;
|
|
1020
|
+
animPhase = null;
|
|
1021
|
+
}
|
|
1022
|
+
function apply(frame) {
|
|
1023
|
+
applyFrame(options.indicator, frame, variant, orientation);
|
|
1024
|
+
}
|
|
1025
|
+
const updateIndicator = (immediate = false) => {
|
|
1026
|
+
const activeId = options.getActiveId();
|
|
1027
|
+
const nextFrame = activeId ? readItemFrame(options.root, activeId, padding, variant, orientation) : null;
|
|
1028
|
+
const fallbackFrame = nextFrame ?? lastFrame ?? {
|
|
1029
|
+
x: 0,
|
|
1030
|
+
y: 0,
|
|
1031
|
+
width: 0,
|
|
1032
|
+
height: 0,
|
|
1033
|
+
radius: 0,
|
|
1034
|
+
visible: false
|
|
1035
|
+
};
|
|
1036
|
+
if (!lastFrame) {
|
|
1037
|
+
lastFrame = fallbackFrame;
|
|
1038
|
+
previousActiveId = activeId;
|
|
1039
|
+
apply(fallbackFrame);
|
|
1040
|
+
return;
|
|
1041
|
+
}
|
|
1042
|
+
if (frameEquals(lastFrame, fallbackFrame)) return;
|
|
1043
|
+
if (currentAnimation) {
|
|
1044
|
+
currentAnimation.cancel();
|
|
1045
|
+
currentAnimation = null;
|
|
1046
|
+
clearAnimState();
|
|
1047
|
+
}
|
|
1048
|
+
if (variant === "tab" && !immediate && fallbackFrame.visible && !lastFrame.visible) {
|
|
1049
|
+
const to2 = fallbackFrame;
|
|
1050
|
+
lastFrame = to2;
|
|
1051
|
+
previousActiveId = activeId;
|
|
1052
|
+
const isHorizontal = orientation === "horizontal";
|
|
1053
|
+
const collapsedFrom = isHorizontal ? {
|
|
1054
|
+
x: to2.x,
|
|
1055
|
+
y: to2.y + to2.height,
|
|
1056
|
+
// bottom edge
|
|
1057
|
+
width: to2.width,
|
|
1058
|
+
height: 0,
|
|
1059
|
+
radius: to2.radius
|
|
1060
|
+
} : {
|
|
1061
|
+
x: to2.x + to2.width,
|
|
1062
|
+
// right edge
|
|
1063
|
+
y: to2.y,
|
|
1064
|
+
width: 0,
|
|
1065
|
+
height: to2.height,
|
|
1066
|
+
radius: to2.radius
|
|
1067
|
+
};
|
|
1068
|
+
options.indicator.setAttribute("opacity", "1");
|
|
1069
|
+
const springConfig = { stiffness: spring.stiffness ?? 170, damping: spring.damping ?? 18, mass: spring.mass ?? 1 };
|
|
1070
|
+
const enterAnim = isHorizontal ? animateHorizontalTabEnter(
|
|
1071
|
+
options.indicator,
|
|
1072
|
+
collapsedFrom,
|
|
1073
|
+
to2,
|
|
1074
|
+
TAB_CURVE_RADIUS,
|
|
1075
|
+
springConfig
|
|
1076
|
+
) : animateTabEnter(
|
|
1077
|
+
options.indicator,
|
|
1078
|
+
collapsedFrom,
|
|
1079
|
+
to2,
|
|
1080
|
+
TAB_CURVE_RADIUS,
|
|
1081
|
+
springConfig
|
|
1082
|
+
);
|
|
1083
|
+
currentAnimation = enterAnim;
|
|
1084
|
+
enterAnim.onfinish = () => {
|
|
1085
|
+
currentAnimation = null;
|
|
1086
|
+
const settledId = options.getActiveId();
|
|
1087
|
+
const settled = settledId ? readItemFrame(options.root, settledId, padding, variant, orientation) : null;
|
|
1088
|
+
if (settled) {
|
|
1089
|
+
lastFrame = settled;
|
|
1090
|
+
apply(settled);
|
|
1091
|
+
} else {
|
|
1092
|
+
apply(to2);
|
|
1093
|
+
}
|
|
1094
|
+
};
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
if (immediate || !fallbackFrame.visible || !lastFrame.visible) {
|
|
1098
|
+
lastFrame = fallbackFrame;
|
|
1099
|
+
previousActiveId = activeId;
|
|
1100
|
+
apply(fallbackFrame);
|
|
1101
|
+
return;
|
|
1102
|
+
}
|
|
1103
|
+
const from = lastFrame;
|
|
1104
|
+
const to = fallbackFrame;
|
|
1105
|
+
const oldActiveId = previousActiveId;
|
|
1106
|
+
const newActiveId = activeId;
|
|
1107
|
+
lastFrame = to;
|
|
1108
|
+
previousActiveId = activeId;
|
|
1109
|
+
let animation = null;
|
|
1110
|
+
if (variant === "tab") {
|
|
1111
|
+
animOldId = oldActiveId;
|
|
1112
|
+
animNewId = newActiveId;
|
|
1113
|
+
animPhase = "exit";
|
|
1114
|
+
enforceAnimStates();
|
|
1115
|
+
const springConfig = { stiffness: spring.stiffness ?? 170, damping: spring.damping ?? 18, mass: spring.mass ?? 1 };
|
|
1116
|
+
const onEnterStart = () => {
|
|
1117
|
+
animPhase = "enter";
|
|
1118
|
+
enforceAnimStates();
|
|
1119
|
+
};
|
|
1120
|
+
animation = orientation === "horizontal" ? animateHorizontalTabIndicator(
|
|
1121
|
+
options.indicator,
|
|
1122
|
+
from,
|
|
1123
|
+
to,
|
|
1124
|
+
TAB_CURVE_RADIUS,
|
|
1125
|
+
springConfig,
|
|
1126
|
+
onEnterStart
|
|
1127
|
+
) : animateTabIndicator(
|
|
1128
|
+
options.indicator,
|
|
1129
|
+
from,
|
|
1130
|
+
to,
|
|
1131
|
+
TAB_CURVE_RADIUS,
|
|
1132
|
+
springConfig,
|
|
1133
|
+
onEnterStart
|
|
1134
|
+
);
|
|
1135
|
+
} else {
|
|
1136
|
+
animation = animatePillMorph(
|
|
1137
|
+
options.indicator,
|
|
1138
|
+
from,
|
|
1139
|
+
to,
|
|
1140
|
+
{ stiffness: spring.stiffness ?? 170, damping: spring.damping ?? 18, mass: spring.mass ?? 1 }
|
|
1141
|
+
);
|
|
1142
|
+
}
|
|
1143
|
+
if (!animation) {
|
|
1144
|
+
apply(to);
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
currentAnimation = animation;
|
|
1148
|
+
animation.onfinish = () => {
|
|
1149
|
+
currentAnimation = null;
|
|
1150
|
+
if (variant === "tab") {
|
|
1151
|
+
if (newActiveId) setItemState(newActiveId, "active");
|
|
1152
|
+
if (oldActiveId && oldActiveId !== newActiveId) setItemState(oldActiveId, "inactive");
|
|
1153
|
+
clearAnimState();
|
|
1154
|
+
}
|
|
1155
|
+
const settledId = options.getActiveId();
|
|
1156
|
+
const settled = settledId ? readItemFrame(options.root, settledId, padding, variant, orientation) : null;
|
|
1157
|
+
if (settled) {
|
|
1158
|
+
lastFrame = settled;
|
|
1159
|
+
apply(settled);
|
|
1160
|
+
} else {
|
|
1161
|
+
apply(to);
|
|
1162
|
+
}
|
|
1163
|
+
};
|
|
1164
|
+
};
|
|
1165
|
+
const sync = (immediate = false) => {
|
|
1166
|
+
cancelAnimationFrame(rafId);
|
|
1167
|
+
rafId = requestAnimationFrame(() => updateIndicator(immediate));
|
|
1168
|
+
};
|
|
1169
|
+
const handleClick = (event) => {
|
|
1170
|
+
if (!options.onSelect) return;
|
|
1171
|
+
const target = event.target;
|
|
1172
|
+
if (!target) return;
|
|
1173
|
+
const item = target.closest(ITEM_SELECTOR);
|
|
1174
|
+
if (!item || item.dataset["disabled"] === "true") return;
|
|
1175
|
+
const id = item.dataset["menuId"];
|
|
1176
|
+
if (!id) return;
|
|
1177
|
+
options.onSelect(id);
|
|
1178
|
+
};
|
|
1179
|
+
options.root.addEventListener("click", handleClick);
|
|
1180
|
+
cleanups.push(() => options.root.removeEventListener("click", handleClick));
|
|
1181
|
+
const scheduleSync = () => {
|
|
1182
|
+
if (animPhase) return;
|
|
1183
|
+
sync(false);
|
|
1184
|
+
};
|
|
1185
|
+
resizeObserver = new ResizeObserver(scheduleSync);
|
|
1186
|
+
resizeObserver.observe(options.root);
|
|
1187
|
+
for (const item of options.root.querySelectorAll(ITEM_SELECTOR)) {
|
|
1188
|
+
resizeObserver.observe(item);
|
|
1189
|
+
}
|
|
1190
|
+
cleanups.push(() => {
|
|
1191
|
+
resizeObserver?.disconnect();
|
|
1192
|
+
resizeObserver = null;
|
|
1193
|
+
});
|
|
1194
|
+
mutationObserver = new MutationObserver(() => {
|
|
1195
|
+
if (animPhase) {
|
|
1196
|
+
enforceAnimStates();
|
|
1197
|
+
return;
|
|
1198
|
+
}
|
|
1199
|
+
if (!resizeObserver) return;
|
|
1200
|
+
resizeObserver.disconnect();
|
|
1201
|
+
resizeObserver.observe(options.root);
|
|
1202
|
+
for (const item of options.root.querySelectorAll(ITEM_SELECTOR)) {
|
|
1203
|
+
resizeObserver.observe(item);
|
|
1204
|
+
}
|
|
1205
|
+
sync(false);
|
|
1206
|
+
});
|
|
1207
|
+
mutationObserver.observe(options.root, {
|
|
1208
|
+
childList: true,
|
|
1209
|
+
subtree: true,
|
|
1210
|
+
attributes: true,
|
|
1211
|
+
attributeFilter: ["data-menu-id", "data-state"]
|
|
1212
|
+
});
|
|
1213
|
+
cleanups.push(() => {
|
|
1214
|
+
mutationObserver?.disconnect();
|
|
1215
|
+
mutationObserver = null;
|
|
1216
|
+
});
|
|
1217
|
+
sync(true);
|
|
1218
|
+
return {
|
|
1219
|
+
sync,
|
|
1220
|
+
destroy() {
|
|
1221
|
+
cancelAnimationFrame(rafId);
|
|
1222
|
+
if (currentAnimation) {
|
|
1223
|
+
currentAnimation.cancel();
|
|
1224
|
+
currentAnimation = null;
|
|
1225
|
+
}
|
|
1226
|
+
for (const cleanup of cleanups) cleanup();
|
|
1227
|
+
cleanups.length = 0;
|
|
1228
|
+
}
|
|
1229
|
+
};
|
|
1230
|
+
}
|
|
524
1231
|
|
|
525
1232
|
// src/toast.ts
|
|
526
1233
|
var WIDTH = 350;
|
|
@@ -1758,6 +2465,253 @@ var Fluix = (function (exports) {
|
|
|
1758
2465
|
};
|
|
1759
2466
|
}
|
|
1760
2467
|
|
|
2468
|
+
// src/menu.ts
|
|
2469
|
+
var SVG_NS3 = "http://www.w3.org/2000/svg";
|
|
2470
|
+
var GOO_MATRIX = "1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 20 -10";
|
|
2471
|
+
function applyAttrs3(el, attrs) {
|
|
2472
|
+
for (const [key, value] of Object.entries(attrs)) {
|
|
2473
|
+
el.setAttribute(key, value);
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
function createMenu(container, options) {
|
|
2477
|
+
let {
|
|
2478
|
+
orientation = MENU_DEFAULTS.orientation,
|
|
2479
|
+
variant = "pill",
|
|
2480
|
+
theme = "dark",
|
|
2481
|
+
activeId: controlledActiveId,
|
|
2482
|
+
onActiveChange,
|
|
2483
|
+
spring,
|
|
2484
|
+
roundness = MENU_DEFAULTS.roundness,
|
|
2485
|
+
blur: blurProp,
|
|
2486
|
+
fill,
|
|
2487
|
+
items
|
|
2488
|
+
} = options;
|
|
2489
|
+
const springConfig = () => spring ?? FLUIX_SPRING;
|
|
2490
|
+
const resolvedBlur = () => blurProp ?? Math.min(10, Math.max(6, roundness * 0.45));
|
|
2491
|
+
const machine2 = createMenuMachine({
|
|
2492
|
+
orientation,
|
|
2493
|
+
variant,
|
|
2494
|
+
spring,
|
|
2495
|
+
roundness,
|
|
2496
|
+
blur: blurProp,
|
|
2497
|
+
fill,
|
|
2498
|
+
initialActiveId: controlledActiveId ?? null
|
|
2499
|
+
});
|
|
2500
|
+
let snapshot = machine2.store.getSnapshot();
|
|
2501
|
+
let lastActiveNotified = snapshot.activeId;
|
|
2502
|
+
const attrs = getMenuAttrs({ orientation, theme, variant });
|
|
2503
|
+
const filterId = `fluix-menu-goo-${Math.random().toString(36).slice(2, 8)}`;
|
|
2504
|
+
const isTab = variant === "tab";
|
|
2505
|
+
const navEl = document.createElement("nav");
|
|
2506
|
+
applyAttrs3(navEl, attrs.root);
|
|
2507
|
+
navEl.setAttribute("aria-label", "Fluix menu");
|
|
2508
|
+
const canvasDiv = document.createElement("div");
|
|
2509
|
+
applyAttrs3(canvasDiv, attrs.canvas);
|
|
2510
|
+
const svg = document.createElementNS(SVG_NS3, "svg");
|
|
2511
|
+
svg.setAttribute("xmlns", SVG_NS3);
|
|
2512
|
+
svg.setAttribute("width", "1");
|
|
2513
|
+
svg.setAttribute("height", "1");
|
|
2514
|
+
svg.setAttribute("viewBox", "0 0 1 1");
|
|
2515
|
+
svg.setAttribute("aria-hidden", "true");
|
|
2516
|
+
let indicatorEl;
|
|
2517
|
+
if (isTab) {
|
|
2518
|
+
indicatorEl = document.createElementNS(SVG_NS3, "path");
|
|
2519
|
+
applyAttrs3(indicatorEl, attrs.indicator);
|
|
2520
|
+
indicatorEl.setAttribute("d", "");
|
|
2521
|
+
indicatorEl.setAttribute("opacity", "0");
|
|
2522
|
+
indicatorEl.setAttribute("fill", fill ?? "var(--fluix-menu-indicator)");
|
|
2523
|
+
svg.appendChild(indicatorEl);
|
|
2524
|
+
} else {
|
|
2525
|
+
const defs = document.createElementNS(SVG_NS3, "defs");
|
|
2526
|
+
const filter = document.createElementNS(SVG_NS3, "filter");
|
|
2527
|
+
filter.setAttribute("id", filterId);
|
|
2528
|
+
filter.setAttribute("x", "-20%");
|
|
2529
|
+
filter.setAttribute("y", "-20%");
|
|
2530
|
+
filter.setAttribute("width", "140%");
|
|
2531
|
+
filter.setAttribute("height", "140%");
|
|
2532
|
+
filter.setAttribute("color-interpolation-filters", "sRGB");
|
|
2533
|
+
const feBlur = document.createElementNS(SVG_NS3, "feGaussianBlur");
|
|
2534
|
+
feBlur.setAttribute("in", "SourceGraphic");
|
|
2535
|
+
feBlur.setAttribute("stdDeviation", String(resolvedBlur()));
|
|
2536
|
+
feBlur.setAttribute("result", "blur");
|
|
2537
|
+
const feCM = document.createElementNS(SVG_NS3, "feColorMatrix");
|
|
2538
|
+
feCM.setAttribute("in", "blur");
|
|
2539
|
+
feCM.setAttribute("type", "matrix");
|
|
2540
|
+
feCM.setAttribute("values", GOO_MATRIX);
|
|
2541
|
+
feCM.setAttribute("result", "goo");
|
|
2542
|
+
const feComp = document.createElementNS(SVG_NS3, "feComposite");
|
|
2543
|
+
feComp.setAttribute("in", "SourceGraphic");
|
|
2544
|
+
feComp.setAttribute("in2", "goo");
|
|
2545
|
+
feComp.setAttribute("operator", "atop");
|
|
2546
|
+
filter.appendChild(feBlur);
|
|
2547
|
+
filter.appendChild(feCM);
|
|
2548
|
+
filter.appendChild(feComp);
|
|
2549
|
+
defs.appendChild(filter);
|
|
2550
|
+
svg.appendChild(defs);
|
|
2551
|
+
const gGroup = document.createElementNS(SVG_NS3, "g");
|
|
2552
|
+
gGroup.setAttribute("filter", `url(#${filterId})`);
|
|
2553
|
+
indicatorEl = document.createElementNS(SVG_NS3, "rect");
|
|
2554
|
+
applyAttrs3(indicatorEl, attrs.indicator);
|
|
2555
|
+
indicatorEl.setAttribute("x", "0");
|
|
2556
|
+
indicatorEl.setAttribute("y", "0");
|
|
2557
|
+
indicatorEl.setAttribute("width", "0");
|
|
2558
|
+
indicatorEl.setAttribute("height", "0");
|
|
2559
|
+
indicatorEl.setAttribute("rx", "0");
|
|
2560
|
+
indicatorEl.setAttribute("ry", "0");
|
|
2561
|
+
indicatorEl.setAttribute("opacity", "0");
|
|
2562
|
+
indicatorEl.setAttribute("fill", fill ?? "var(--fluix-menu-indicator)");
|
|
2563
|
+
gGroup.appendChild(indicatorEl);
|
|
2564
|
+
svg.appendChild(gGroup);
|
|
2565
|
+
}
|
|
2566
|
+
canvasDiv.appendChild(svg);
|
|
2567
|
+
navEl.appendChild(canvasDiv);
|
|
2568
|
+
const listDiv = document.createElement("div");
|
|
2569
|
+
applyAttrs3(listDiv, attrs.list);
|
|
2570
|
+
const buttonMap = /* @__PURE__ */ new Map();
|
|
2571
|
+
function createItemButton(item) {
|
|
2572
|
+
const btn = document.createElement("button");
|
|
2573
|
+
btn.type = "button";
|
|
2574
|
+
const active = snapshot.activeId === item.id;
|
|
2575
|
+
const itemAttrs = attrs.item({ id: item.id, active, disabled: item.disabled });
|
|
2576
|
+
applyAttrs3(btn, itemAttrs);
|
|
2577
|
+
if (item.disabled) btn.disabled = true;
|
|
2578
|
+
btn.textContent = item.label;
|
|
2579
|
+
btn.addEventListener("click", () => {
|
|
2580
|
+
if (item.disabled) return;
|
|
2581
|
+
if (controlledActiveId === void 0) {
|
|
2582
|
+
machine2.setActive(item.id);
|
|
2583
|
+
} else {
|
|
2584
|
+
onActiveChange?.(item.id);
|
|
2585
|
+
}
|
|
2586
|
+
});
|
|
2587
|
+
buttonMap.set(item.id, btn);
|
|
2588
|
+
listDiv.appendChild(btn);
|
|
2589
|
+
}
|
|
2590
|
+
for (const item of items) {
|
|
2591
|
+
createItemButton(item);
|
|
2592
|
+
}
|
|
2593
|
+
navEl.appendChild(listDiv);
|
|
2594
|
+
container.appendChild(navEl);
|
|
2595
|
+
let size = { width: 0, height: 0 };
|
|
2596
|
+
let measureRaf = 0;
|
|
2597
|
+
const measure = () => {
|
|
2598
|
+
const rect = navEl.getBoundingClientRect();
|
|
2599
|
+
const w = Math.ceil(rect.width);
|
|
2600
|
+
const h = Math.ceil(rect.height);
|
|
2601
|
+
if (size.width !== w || size.height !== h) {
|
|
2602
|
+
size = { width: w, height: h };
|
|
2603
|
+
updateSvgSize();
|
|
2604
|
+
connection?.sync(false);
|
|
2605
|
+
}
|
|
2606
|
+
};
|
|
2607
|
+
const resizeObs = new ResizeObserver(() => {
|
|
2608
|
+
cancelAnimationFrame(measureRaf);
|
|
2609
|
+
measureRaf = requestAnimationFrame(measure);
|
|
2610
|
+
});
|
|
2611
|
+
resizeObs.observe(navEl);
|
|
2612
|
+
function updateSvgSize() {
|
|
2613
|
+
const w = Math.max(1, size.width);
|
|
2614
|
+
const h = Math.max(1, size.height);
|
|
2615
|
+
svg.setAttribute("width", String(w));
|
|
2616
|
+
svg.setAttribute("height", String(h));
|
|
2617
|
+
svg.setAttribute("viewBox", `0 0 ${w} ${h}`);
|
|
2618
|
+
}
|
|
2619
|
+
let connection = connectMenu({
|
|
2620
|
+
root: navEl,
|
|
2621
|
+
indicator: indicatorEl,
|
|
2622
|
+
getActiveId: () => snapshot.activeId,
|
|
2623
|
+
onSelect(id) {
|
|
2624
|
+
if (controlledActiveId === void 0) {
|
|
2625
|
+
machine2.setActive(id);
|
|
2626
|
+
} else {
|
|
2627
|
+
onActiveChange?.(id);
|
|
2628
|
+
}
|
|
2629
|
+
},
|
|
2630
|
+
spring: springConfig(),
|
|
2631
|
+
variant,
|
|
2632
|
+
orientation
|
|
2633
|
+
});
|
|
2634
|
+
requestAnimationFrame(() => {
|
|
2635
|
+
measure();
|
|
2636
|
+
connection.sync(false);
|
|
2637
|
+
});
|
|
2638
|
+
const unsubscribe = machine2.store.subscribe(() => {
|
|
2639
|
+
const next = machine2.store.getSnapshot();
|
|
2640
|
+
snapshot = next;
|
|
2641
|
+
for (const item of items) {
|
|
2642
|
+
const btn = buttonMap.get(item.id);
|
|
2643
|
+
if (btn) {
|
|
2644
|
+
const active = next.activeId === item.id;
|
|
2645
|
+
const itemAttrs = attrs.item({ id: item.id, active, disabled: item.disabled });
|
|
2646
|
+
applyAttrs3(btn, itemAttrs);
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2649
|
+
if (next.activeId && lastActiveNotified !== next.activeId && onActiveChange) {
|
|
2650
|
+
onActiveChange(next.activeId);
|
|
2651
|
+
}
|
|
2652
|
+
lastActiveNotified = next.activeId;
|
|
2653
|
+
connection.sync(false);
|
|
2654
|
+
});
|
|
2655
|
+
return {
|
|
2656
|
+
setActive(id) {
|
|
2657
|
+
machine2.setActive(id);
|
|
2658
|
+
},
|
|
2659
|
+
update(opts) {
|
|
2660
|
+
if (opts.orientation !== void 0) orientation = opts.orientation;
|
|
2661
|
+
if (opts.variant !== void 0) variant = opts.variant;
|
|
2662
|
+
if (opts.theme !== void 0) theme = opts.theme;
|
|
2663
|
+
if (opts.activeId !== void 0) controlledActiveId = opts.activeId;
|
|
2664
|
+
if (opts.onActiveChange !== void 0) onActiveChange = opts.onActiveChange;
|
|
2665
|
+
if (opts.spring !== void 0) spring = opts.spring;
|
|
2666
|
+
if (opts.roundness !== void 0) roundness = opts.roundness;
|
|
2667
|
+
if (opts.blur !== void 0) blurProp = opts.blur;
|
|
2668
|
+
if (opts.fill !== void 0) fill = opts.fill;
|
|
2669
|
+
machine2.configure({ orientation, variant, spring, roundness, blur: blurProp, fill });
|
|
2670
|
+
if (controlledActiveId !== void 0) {
|
|
2671
|
+
machine2.setActive(controlledActiveId ?? null);
|
|
2672
|
+
}
|
|
2673
|
+
const newAttrs = getMenuAttrs({ orientation, theme, variant });
|
|
2674
|
+
applyAttrs3(navEl, newAttrs.root);
|
|
2675
|
+
if (opts.items !== void 0) {
|
|
2676
|
+
items = opts.items;
|
|
2677
|
+
listDiv.innerHTML = "";
|
|
2678
|
+
buttonMap.clear();
|
|
2679
|
+
for (const item of items) {
|
|
2680
|
+
createItemButton(item);
|
|
2681
|
+
}
|
|
2682
|
+
}
|
|
2683
|
+
connection.destroy();
|
|
2684
|
+
connection = connectMenu({
|
|
2685
|
+
root: navEl,
|
|
2686
|
+
indicator: indicatorEl,
|
|
2687
|
+
getActiveId: () => snapshot.activeId,
|
|
2688
|
+
onSelect(id) {
|
|
2689
|
+
if (controlledActiveId === void 0) {
|
|
2690
|
+
machine2.setActive(id);
|
|
2691
|
+
} else {
|
|
2692
|
+
onActiveChange?.(id);
|
|
2693
|
+
}
|
|
2694
|
+
},
|
|
2695
|
+
spring: springConfig(),
|
|
2696
|
+
variant,
|
|
2697
|
+
orientation
|
|
2698
|
+
});
|
|
2699
|
+
requestAnimationFrame(() => {
|
|
2700
|
+
measure();
|
|
2701
|
+
connection.sync(false);
|
|
2702
|
+
});
|
|
2703
|
+
},
|
|
2704
|
+
destroy() {
|
|
2705
|
+
unsubscribe();
|
|
2706
|
+
cancelAnimationFrame(measureRaf);
|
|
2707
|
+
resizeObs.disconnect();
|
|
2708
|
+
connection.destroy();
|
|
2709
|
+
navEl.remove();
|
|
2710
|
+
}
|
|
2711
|
+
};
|
|
2712
|
+
}
|
|
2713
|
+
|
|
2714
|
+
exports.createMenu = createMenu;
|
|
1761
2715
|
exports.createNotch = createNotch;
|
|
1762
2716
|
exports.createToaster = createToaster;
|
|
1763
2717
|
exports.fluix = fluix;
|