@fluix-ui/vanilla 0.0.5 → 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/dist/index.cjs CHANGED
@@ -782,11 +782,712 @@ function createToaster(config) {
782
782
  }
783
783
  };
784
784
  }
785
+ var SVG_NS2 = "http://www.w3.org/2000/svg";
786
+ function applyAttrs2(el, attrs) {
787
+ for (const [key, value] of Object.entries(attrs)) {
788
+ el.setAttribute(key, value);
789
+ }
790
+ }
791
+ function resolveContent(source) {
792
+ if (source instanceof HTMLElement) return source;
793
+ const span = document.createElement("span");
794
+ span.textContent = source;
795
+ return span;
796
+ }
797
+ function createNotch(container, options) {
798
+ let {
799
+ trigger = "click",
800
+ position = "top-center",
801
+ spring,
802
+ dotSize = 36,
803
+ roundness = core.NOTCH_DEFAULTS.roundness,
804
+ theme = "dark",
805
+ fill,
806
+ open: controlledOpen,
807
+ onOpenChange
808
+ } = options;
809
+ const springConfig = () => spring ?? core.FLUIX_SPRING;
810
+ const machine = core.createNotchMachine({
811
+ position,
812
+ trigger,
813
+ roundness,
814
+ fill,
815
+ spring
816
+ });
817
+ let snapshot = machine.store.getSnapshot();
818
+ let prevOpenVal;
819
+ const blur = () => Math.min(10, Math.max(6, roundness * 0.45));
820
+ const collapsedW = () => dotSize;
821
+ const collapsedH = () => dotSize;
822
+ let contentSize = { w: 200, h: 44 };
823
+ const hlPad = 12;
824
+ const expandedW = () => contentSize.w + hlPad * 2;
825
+ const expandedH = () => Math.max(contentSize.h + hlPad, dotSize);
826
+ const targetW = () => snapshot.open ? expandedW() : collapsedW();
827
+ const targetH = () => snapshot.open ? expandedH() : collapsedH();
828
+ const rootW = () => Math.max(expandedW(), collapsedW());
829
+ const rootH = () => Math.max(expandedH(), collapsedH());
830
+ const prev = { w: 0, h: 0, initialized: false };
831
+ let currentAnim = null;
832
+ let highlightAnim = null;
833
+ const hlPrev = { x: 0, y: 0, w: 0, h: 0, visible: false };
834
+ const measureEl = document.createElement("div");
835
+ measureEl.setAttribute("data-fluix-notch-measure", "");
836
+ measureEl.appendChild(resolveContent(options.content).cloneNode(true));
837
+ container.appendChild(measureEl);
838
+ const rootEl = document.createElement("div");
839
+ const attrs = core.getNotchAttrs({ open: snapshot.open, position, theme });
840
+ applyAttrs2(rootEl, attrs.root);
841
+ rootEl.style.width = `${rootW()}px`;
842
+ rootEl.style.height = `${rootH()}px`;
843
+ const canvasDiv = document.createElement("div");
844
+ applyAttrs2(canvasDiv, attrs.canvas);
845
+ const svg = document.createElementNS(SVG_NS2, "svg");
846
+ svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
847
+ svg.setAttribute("width", String(rootW()));
848
+ svg.setAttribute("height", String(rootH()));
849
+ svg.setAttribute("viewBox", `0 0 ${rootW()} ${rootH()}`);
850
+ svg.setAttribute("aria-hidden", "true");
851
+ const defs = document.createElementNS(SVG_NS2, "defs");
852
+ const filter = document.createElementNS(SVG_NS2, "filter");
853
+ filter.setAttribute("id", "fluix-notch-goo");
854
+ filter.setAttribute("x", "-20%");
855
+ filter.setAttribute("y", "-20%");
856
+ filter.setAttribute("width", "140%");
857
+ filter.setAttribute("height", "140%");
858
+ filter.setAttribute("color-interpolation-filters", "sRGB");
859
+ const feBlur = document.createElementNS(SVG_NS2, "feGaussianBlur");
860
+ feBlur.setAttribute("in", "SourceGraphic");
861
+ feBlur.setAttribute("stdDeviation", String(blur()));
862
+ feBlur.setAttribute("result", "blur");
863
+ const feCM = document.createElementNS(SVG_NS2, "feColorMatrix");
864
+ feCM.setAttribute("in", "blur");
865
+ feCM.setAttribute("type", "matrix");
866
+ feCM.setAttribute("values", "1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 20 -10");
867
+ feCM.setAttribute("result", "goo");
868
+ const feComp = document.createElementNS(SVG_NS2, "feComposite");
869
+ feComp.setAttribute("in", "SourceGraphic");
870
+ feComp.setAttribute("in2", "goo");
871
+ feComp.setAttribute("operator", "atop");
872
+ filter.appendChild(feBlur);
873
+ filter.appendChild(feCM);
874
+ filter.appendChild(feComp);
875
+ defs.appendChild(filter);
876
+ svg.appendChild(defs);
877
+ const gGroup = document.createElementNS(SVG_NS2, "g");
878
+ gGroup.setAttribute("filter", "url(#fluix-notch-goo)");
879
+ const svgRectEl = document.createElementNS(SVG_NS2, "rect");
880
+ const cw = collapsedW();
881
+ const ch = collapsedH();
882
+ svgRectEl.setAttribute("x", String((rootW() - cw) / 2));
883
+ svgRectEl.setAttribute("y", String((rootH() - ch) / 2));
884
+ svgRectEl.setAttribute("width", String(cw));
885
+ svgRectEl.setAttribute("height", String(ch));
886
+ svgRectEl.setAttribute("rx", String(cw / 2));
887
+ svgRectEl.setAttribute("ry", String(ch / 2));
888
+ svgRectEl.setAttribute("fill", fill ?? "var(--fluix-notch-bg)");
889
+ gGroup.appendChild(svgRectEl);
890
+ svg.appendChild(gGroup);
891
+ const hoverBlobEl = document.createElementNS(SVG_NS2, "rect");
892
+ hoverBlobEl.setAttribute("x", String((rootW() - cw) / 2));
893
+ hoverBlobEl.setAttribute("y", String((rootH() - ch) / 2));
894
+ hoverBlobEl.setAttribute("width", "0");
895
+ hoverBlobEl.setAttribute("height", "0");
896
+ hoverBlobEl.setAttribute("rx", "0");
897
+ hoverBlobEl.setAttribute("ry", "0");
898
+ hoverBlobEl.setAttribute("opacity", "0");
899
+ hoverBlobEl.setAttribute("fill", fill ?? "var(--fluix-notch-bg)");
900
+ gGroup.appendChild(hoverBlobEl);
901
+ canvasDiv.appendChild(svg);
902
+ rootEl.appendChild(canvasDiv);
903
+ const pillDiv = document.createElement("div");
904
+ applyAttrs2(pillDiv, attrs.pill);
905
+ pillDiv.style.width = `${dotSize}px`;
906
+ pillDiv.style.height = `${dotSize}px`;
907
+ pillDiv.appendChild(resolveContent(options.pill));
908
+ rootEl.appendChild(pillDiv);
909
+ const contentDiv = document.createElement("div");
910
+ applyAttrs2(contentDiv, attrs.content);
911
+ contentDiv.appendChild(resolveContent(options.content));
912
+ rootEl.appendChild(contentDiv);
913
+ container.appendChild(rootEl);
914
+ prev.w = cw;
915
+ prev.h = ch;
916
+ prev.initialized = true;
917
+ let measureRaf = 0;
918
+ const measureObs = new ResizeObserver(() => {
919
+ cancelAnimationFrame(measureRaf);
920
+ measureRaf = requestAnimationFrame(() => {
921
+ const r = measureEl.getBoundingClientRect();
922
+ if (r.width > 0 && r.height > 0) {
923
+ const newSize = { w: Math.ceil(r.width), h: Math.ceil(r.height) };
924
+ if (newSize.w !== contentSize.w || newSize.h !== contentSize.h) {
925
+ contentSize = newSize;
926
+ updateLayout();
927
+ }
928
+ }
929
+ });
930
+ });
931
+ measureObs.observe(measureEl);
932
+ function onItemEnter(e) {
933
+ const target = e.target.closest("a, button");
934
+ if (!target || !snapshot.open) return;
935
+ const rootRect = rootEl.getBoundingClientRect();
936
+ const itemW = target.offsetWidth;
937
+ const itemH = target.offsetHeight;
938
+ const itemRect = target.getBoundingClientRect();
939
+ const itemCenterX = itemRect.left + itemRect.width / 2;
940
+ const itemCenterY = itemRect.top + itemRect.height / 2;
941
+ const padX = 8;
942
+ const padY = 4;
943
+ const blobOvershoot = Math.max(6, roundness * 0.35);
944
+ const toW = itemW + padX * 2;
945
+ const toH = Math.max(itemH + padY * 2, rootRect.height + blobOvershoot * 2);
946
+ const toX = itemCenterX - rootRect.left - toW / 2;
947
+ const toY = itemCenterY - rootRect.top - toH / 2;
948
+ const toRx = toH / 2;
949
+ const fromX = hlPrev.visible ? hlPrev.x : toX + toW / 2;
950
+ const fromY = hlPrev.visible ? hlPrev.y : toY + toH / 2;
951
+ const fromW = hlPrev.visible ? hlPrev.w : 0;
952
+ const fromH = hlPrev.visible ? hlPrev.h : 0;
953
+ const fromR = hlPrev.visible ? hlPrev.h / 2 : 0;
954
+ if (highlightAnim) {
955
+ highlightAnim.cancel();
956
+ highlightAnim = null;
957
+ }
958
+ const sc = springConfig();
959
+ const a = core.animateSpring(
960
+ hoverBlobEl,
961
+ {
962
+ x: { from: fromX, to: toX, unit: "px" },
963
+ y: { from: fromY, to: toY, unit: "px" },
964
+ width: { from: fromW, to: toW, unit: "px" },
965
+ height: { from: fromH, to: toH, unit: "px" },
966
+ rx: { from: fromR, to: toRx, unit: "px" },
967
+ ry: { from: fromR, to: toRx, unit: "px" }
968
+ },
969
+ { ...sc, stiffness: (sc.stiffness ?? 300) * 1.2 }
970
+ );
971
+ hlPrev.x = toX;
972
+ hlPrev.y = toY;
973
+ hlPrev.w = toW;
974
+ hlPrev.h = toH;
975
+ if (a) {
976
+ highlightAnim = a;
977
+ a.onfinish = () => {
978
+ highlightAnim = null;
979
+ hoverBlobEl.setAttribute("x", String(toX));
980
+ hoverBlobEl.setAttribute("y", String(toY));
981
+ hoverBlobEl.setAttribute("width", String(toW));
982
+ hoverBlobEl.setAttribute("height", String(toH));
983
+ hoverBlobEl.setAttribute("rx", String(toRx));
984
+ hoverBlobEl.setAttribute("ry", String(toRx));
985
+ hoverBlobEl.setAttribute("opacity", "1");
986
+ };
987
+ } else {
988
+ hoverBlobEl.setAttribute("x", String(toX));
989
+ hoverBlobEl.setAttribute("y", String(toY));
990
+ hoverBlobEl.setAttribute("width", String(toW));
991
+ hoverBlobEl.setAttribute("height", String(toH));
992
+ hoverBlobEl.setAttribute("rx", String(toRx));
993
+ hoverBlobEl.setAttribute("ry", String(toRx));
994
+ hoverBlobEl.setAttribute("opacity", "1");
995
+ }
996
+ hoverBlobEl.setAttribute("opacity", "1");
997
+ hlPrev.visible = true;
998
+ }
999
+ function resetHoverBlobImmediate() {
1000
+ if (highlightAnim) {
1001
+ highlightAnim.cancel();
1002
+ highlightAnim = null;
1003
+ }
1004
+ hoverBlobEl.setAttribute("x", String(rootW() / 2));
1005
+ hoverBlobEl.setAttribute("y", String(rootH() / 2));
1006
+ hoverBlobEl.setAttribute("width", "0");
1007
+ hoverBlobEl.setAttribute("height", "0");
1008
+ hoverBlobEl.setAttribute("rx", "0");
1009
+ hoverBlobEl.setAttribute("ry", "0");
1010
+ hoverBlobEl.setAttribute("opacity", "0");
1011
+ hlPrev.visible = false;
1012
+ }
1013
+ function onItemLeave() {
1014
+ if (!hlPrev.visible) return;
1015
+ const cx = hlPrev.x + hlPrev.w / 2;
1016
+ const cy = hlPrev.y + hlPrev.h / 2;
1017
+ const sc = springConfig();
1018
+ const a = core.animateSpring(
1019
+ hoverBlobEl,
1020
+ {
1021
+ x: { from: hlPrev.x, to: cx, unit: "px" },
1022
+ y: { from: hlPrev.y, to: cy, unit: "px" },
1023
+ width: { from: hlPrev.w, to: 0, unit: "px" },
1024
+ height: { from: hlPrev.h, to: 0, unit: "px" },
1025
+ rx: { from: hlPrev.h / 2, to: 0, unit: "px" },
1026
+ ry: { from: hlPrev.h / 2, to: 0, unit: "px" }
1027
+ },
1028
+ { ...sc, stiffness: (sc.stiffness ?? 300) * 1.2 }
1029
+ );
1030
+ if (a) {
1031
+ highlightAnim = a;
1032
+ a.onfinish = () => {
1033
+ highlightAnim = null;
1034
+ hoverBlobEl.setAttribute("x", String(cx));
1035
+ hoverBlobEl.setAttribute("y", String(cy));
1036
+ hoverBlobEl.setAttribute("width", "0");
1037
+ hoverBlobEl.setAttribute("height", "0");
1038
+ hoverBlobEl.setAttribute("rx", "0");
1039
+ hoverBlobEl.setAttribute("ry", "0");
1040
+ hoverBlobEl.setAttribute("opacity", "0");
1041
+ };
1042
+ } else {
1043
+ hoverBlobEl.setAttribute("x", String(cx));
1044
+ hoverBlobEl.setAttribute("y", String(cy));
1045
+ hoverBlobEl.setAttribute("width", "0");
1046
+ hoverBlobEl.setAttribute("height", "0");
1047
+ hoverBlobEl.setAttribute("rx", "0");
1048
+ hoverBlobEl.setAttribute("ry", "0");
1049
+ hoverBlobEl.setAttribute("opacity", "0");
1050
+ }
1051
+ hlPrev.visible = false;
1052
+ }
1053
+ function handleOpen() {
1054
+ if (controlledOpen === void 0) machine.open();
1055
+ else onOpenChange?.(true);
1056
+ }
1057
+ function handleClose() {
1058
+ if (controlledOpen === void 0) machine.close();
1059
+ else onOpenChange?.(false);
1060
+ }
1061
+ function handleToggle() {
1062
+ if (controlledOpen === void 0) machine.toggle();
1063
+ else onOpenChange?.(!snapshot.open);
1064
+ }
1065
+ function onMouseEnter() {
1066
+ if (trigger === "hover") handleOpen();
1067
+ }
1068
+ function onMouseLeave() {
1069
+ if (trigger === "hover") {
1070
+ handleClose();
1071
+ resetHoverBlobImmediate();
1072
+ return;
1073
+ }
1074
+ onItemLeave();
1075
+ }
1076
+ function onClick() {
1077
+ if (trigger === "click") handleToggle();
1078
+ }
1079
+ rootEl.addEventListener("mouseenter", onMouseEnter);
1080
+ rootEl.addEventListener("mouseleave", onMouseLeave);
1081
+ rootEl.addEventListener("mouseover", onItemEnter);
1082
+ rootEl.addEventListener("click", onClick);
1083
+ function animateRect() {
1084
+ const tw = targetW();
1085
+ const th = targetH();
1086
+ if (tw === prev.w && th === prev.h) return;
1087
+ if (currentAnim) {
1088
+ currentAnim.cancel();
1089
+ currentAnim = null;
1090
+ }
1091
+ const rw = rootW();
1092
+ const rh = rootH();
1093
+ const fromW = prev.w;
1094
+ const fromH = prev.h;
1095
+ const fromX = (rw - fromW) / 2;
1096
+ const fromY = (rh - fromH) / 2;
1097
+ const toX = (rw - tw) / 2;
1098
+ const toY = (rh - th) / 2;
1099
+ prev.w = tw;
1100
+ prev.h = th;
1101
+ const isCollapsing = tw === collapsedW() && th === collapsedH();
1102
+ const wasCollapsed = fromW === collapsedW() && fromH === collapsedH();
1103
+ const fromRx = wasCollapsed ? collapsedW() / 2 : roundness;
1104
+ const toRx = isCollapsing ? collapsedW() / 2 : roundness;
1105
+ const a = core.animateSpring(
1106
+ svgRectEl,
1107
+ {
1108
+ width: { from: fromW, to: tw, unit: "px" },
1109
+ height: { from: fromH, to: th, unit: "px" },
1110
+ x: { from: fromX, to: toX, unit: "px" },
1111
+ y: { from: fromY, to: toY, unit: "px" },
1112
+ rx: { from: fromRx, to: toRx, unit: "px" },
1113
+ ry: { from: fromRx, to: toRx, unit: "px" }
1114
+ },
1115
+ springConfig()
1116
+ );
1117
+ if (a) {
1118
+ currentAnim = a;
1119
+ a.onfinish = () => {
1120
+ currentAnim = null;
1121
+ svgRectEl.setAttribute("width", String(tw));
1122
+ svgRectEl.setAttribute("height", String(th));
1123
+ svgRectEl.setAttribute("x", String(toX));
1124
+ svgRectEl.setAttribute("y", String(toY));
1125
+ svgRectEl.setAttribute("rx", String(toRx));
1126
+ svgRectEl.setAttribute("ry", String(toRx));
1127
+ };
1128
+ } else {
1129
+ svgRectEl.setAttribute("width", String(tw));
1130
+ svgRectEl.setAttribute("height", String(th));
1131
+ svgRectEl.setAttribute("x", String(toX));
1132
+ svgRectEl.setAttribute("y", String(toY));
1133
+ svgRectEl.setAttribute("rx", String(toRx));
1134
+ svgRectEl.setAttribute("ry", String(toRx));
1135
+ }
1136
+ }
1137
+ function updateLayout() {
1138
+ const isOpen = snapshot.open;
1139
+ const newAttrs = core.getNotchAttrs({ open: isOpen, position, theme });
1140
+ applyAttrs2(rootEl, newAttrs.root);
1141
+ rootEl.style.width = `${rootW()}px`;
1142
+ rootEl.style.height = `${rootH()}px`;
1143
+ svg.setAttribute("width", String(rootW()));
1144
+ svg.setAttribute("height", String(rootH()));
1145
+ svg.setAttribute("viewBox", `0 0 ${rootW()} ${rootH()}`);
1146
+ feBlur.setAttribute("stdDeviation", String(blur()));
1147
+ svgRectEl.setAttribute("fill", fill ?? "var(--fluix-notch-bg)");
1148
+ hoverBlobEl.setAttribute("fill", fill ?? "var(--fluix-notch-bg)");
1149
+ applyAttrs2(contentDiv, newAttrs.content);
1150
+ animateRect();
1151
+ if (!isOpen) {
1152
+ resetHoverBlobImmediate();
1153
+ }
1154
+ document.documentElement.style.setProperty(
1155
+ "--fluix-notch-offset",
1156
+ `${rootH()}px`
1157
+ );
1158
+ }
1159
+ const unsubscribe = machine.store.subscribe(() => {
1160
+ const next = machine.store.getSnapshot();
1161
+ snapshot = next;
1162
+ if (controlledOpen !== void 0) {
1163
+ if (controlledOpen && !next.open) machine.open();
1164
+ else if (!controlledOpen && next.open) machine.close();
1165
+ }
1166
+ if (prevOpenVal !== void 0 && prevOpenVal !== next.open) {
1167
+ onOpenChange?.(next.open);
1168
+ }
1169
+ prevOpenVal = next.open;
1170
+ updateLayout();
1171
+ });
1172
+ updateLayout();
1173
+ document.documentElement.style.setProperty(
1174
+ "--fluix-notch-offset",
1175
+ `${rootH()}px`
1176
+ );
1177
+ return {
1178
+ open() {
1179
+ handleOpen();
1180
+ },
1181
+ close() {
1182
+ handleClose();
1183
+ },
1184
+ toggle() {
1185
+ handleToggle();
1186
+ },
1187
+ destroy() {
1188
+ unsubscribe();
1189
+ cancelAnimationFrame(measureRaf);
1190
+ measureObs.disconnect();
1191
+ currentAnim?.cancel();
1192
+ highlightAnim?.cancel();
1193
+ rootEl.removeEventListener("mouseenter", onMouseEnter);
1194
+ rootEl.removeEventListener("mouseleave", onMouseLeave);
1195
+ rootEl.removeEventListener("mouseover", onItemEnter);
1196
+ rootEl.removeEventListener("click", onClick);
1197
+ machine.destroy();
1198
+ measureEl.remove();
1199
+ rootEl.remove();
1200
+ document.documentElement.style.removeProperty("--fluix-notch-offset");
1201
+ },
1202
+ update(opts) {
1203
+ if (opts.trigger !== void 0) trigger = opts.trigger;
1204
+ if (opts.position !== void 0) position = opts.position;
1205
+ if (opts.spring !== void 0) spring = opts.spring;
1206
+ if (opts.dotSize !== void 0) dotSize = opts.dotSize;
1207
+ if (opts.roundness !== void 0) roundness = opts.roundness;
1208
+ if (opts.theme !== void 0) theme = opts.theme;
1209
+ if (opts.fill !== void 0) fill = opts.fill;
1210
+ if (opts.open !== void 0) controlledOpen = opts.open;
1211
+ if (opts.onOpenChange !== void 0) onOpenChange = opts.onOpenChange;
1212
+ if (opts.pill !== void 0) {
1213
+ pillDiv.textContent = "";
1214
+ pillDiv.appendChild(resolveContent(opts.pill));
1215
+ }
1216
+ if (opts.content !== void 0) {
1217
+ contentDiv.textContent = "";
1218
+ contentDiv.appendChild(resolveContent(opts.content));
1219
+ measureEl.textContent = "";
1220
+ measureEl.appendChild(resolveContent(opts.content).cloneNode(true));
1221
+ }
1222
+ pillDiv.style.width = `${dotSize}px`;
1223
+ pillDiv.style.height = `${dotSize}px`;
1224
+ machine.configure({ position, trigger, roundness, fill, spring });
1225
+ if (controlledOpen !== void 0) {
1226
+ if (controlledOpen && !snapshot.open) machine.open();
1227
+ else if (!controlledOpen && snapshot.open) machine.close();
1228
+ }
1229
+ rootEl.removeEventListener("mouseenter", onMouseEnter);
1230
+ rootEl.removeEventListener("mouseleave", onMouseLeave);
1231
+ rootEl.removeEventListener("click", onClick);
1232
+ rootEl.addEventListener("mouseenter", onMouseEnter);
1233
+ rootEl.addEventListener("mouseleave", onMouseLeave);
1234
+ rootEl.addEventListener("click", onClick);
1235
+ updateLayout();
1236
+ }
1237
+ };
1238
+ }
1239
+ var SVG_NS3 = "http://www.w3.org/2000/svg";
1240
+ var GOO_MATRIX = "1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 20 -10";
1241
+ function applyAttrs3(el, attrs) {
1242
+ for (const [key, value] of Object.entries(attrs)) {
1243
+ el.setAttribute(key, value);
1244
+ }
1245
+ }
1246
+ function createMenu(container, options) {
1247
+ let {
1248
+ orientation = core.MENU_DEFAULTS.orientation,
1249
+ variant = "pill",
1250
+ theme = "dark",
1251
+ activeId: controlledActiveId,
1252
+ onActiveChange,
1253
+ spring,
1254
+ roundness = core.MENU_DEFAULTS.roundness,
1255
+ blur: blurProp,
1256
+ fill,
1257
+ items
1258
+ } = options;
1259
+ const springConfig = () => spring ?? core.FLUIX_SPRING;
1260
+ const resolvedBlur = () => blurProp ?? Math.min(10, Math.max(6, roundness * 0.45));
1261
+ const machine = core.createMenuMachine({
1262
+ orientation,
1263
+ variant,
1264
+ spring,
1265
+ roundness,
1266
+ blur: blurProp,
1267
+ fill,
1268
+ initialActiveId: controlledActiveId ?? null
1269
+ });
1270
+ let snapshot = machine.store.getSnapshot();
1271
+ let lastActiveNotified = snapshot.activeId;
1272
+ const attrs = core.getMenuAttrs({ orientation, theme, variant });
1273
+ const filterId = `fluix-menu-goo-${Math.random().toString(36).slice(2, 8)}`;
1274
+ const isTab = variant === "tab";
1275
+ const navEl = document.createElement("nav");
1276
+ applyAttrs3(navEl, attrs.root);
1277
+ navEl.setAttribute("aria-label", "Fluix menu");
1278
+ const canvasDiv = document.createElement("div");
1279
+ applyAttrs3(canvasDiv, attrs.canvas);
1280
+ const svg = document.createElementNS(SVG_NS3, "svg");
1281
+ svg.setAttribute("xmlns", SVG_NS3);
1282
+ svg.setAttribute("width", "1");
1283
+ svg.setAttribute("height", "1");
1284
+ svg.setAttribute("viewBox", "0 0 1 1");
1285
+ svg.setAttribute("aria-hidden", "true");
1286
+ let indicatorEl;
1287
+ if (isTab) {
1288
+ indicatorEl = document.createElementNS(SVG_NS3, "path");
1289
+ applyAttrs3(indicatorEl, attrs.indicator);
1290
+ indicatorEl.setAttribute("d", "");
1291
+ indicatorEl.setAttribute("opacity", "0");
1292
+ indicatorEl.setAttribute("fill", fill ?? "var(--fluix-menu-indicator)");
1293
+ svg.appendChild(indicatorEl);
1294
+ } else {
1295
+ const defs = document.createElementNS(SVG_NS3, "defs");
1296
+ const filter = document.createElementNS(SVG_NS3, "filter");
1297
+ filter.setAttribute("id", filterId);
1298
+ filter.setAttribute("x", "-20%");
1299
+ filter.setAttribute("y", "-20%");
1300
+ filter.setAttribute("width", "140%");
1301
+ filter.setAttribute("height", "140%");
1302
+ filter.setAttribute("color-interpolation-filters", "sRGB");
1303
+ const feBlur = document.createElementNS(SVG_NS3, "feGaussianBlur");
1304
+ feBlur.setAttribute("in", "SourceGraphic");
1305
+ feBlur.setAttribute("stdDeviation", String(resolvedBlur()));
1306
+ feBlur.setAttribute("result", "blur");
1307
+ const feCM = document.createElementNS(SVG_NS3, "feColorMatrix");
1308
+ feCM.setAttribute("in", "blur");
1309
+ feCM.setAttribute("type", "matrix");
1310
+ feCM.setAttribute("values", GOO_MATRIX);
1311
+ feCM.setAttribute("result", "goo");
1312
+ const feComp = document.createElementNS(SVG_NS3, "feComposite");
1313
+ feComp.setAttribute("in", "SourceGraphic");
1314
+ feComp.setAttribute("in2", "goo");
1315
+ feComp.setAttribute("operator", "atop");
1316
+ filter.appendChild(feBlur);
1317
+ filter.appendChild(feCM);
1318
+ filter.appendChild(feComp);
1319
+ defs.appendChild(filter);
1320
+ svg.appendChild(defs);
1321
+ const gGroup = document.createElementNS(SVG_NS3, "g");
1322
+ gGroup.setAttribute("filter", `url(#${filterId})`);
1323
+ indicatorEl = document.createElementNS(SVG_NS3, "rect");
1324
+ applyAttrs3(indicatorEl, attrs.indicator);
1325
+ indicatorEl.setAttribute("x", "0");
1326
+ indicatorEl.setAttribute("y", "0");
1327
+ indicatorEl.setAttribute("width", "0");
1328
+ indicatorEl.setAttribute("height", "0");
1329
+ indicatorEl.setAttribute("rx", "0");
1330
+ indicatorEl.setAttribute("ry", "0");
1331
+ indicatorEl.setAttribute("opacity", "0");
1332
+ indicatorEl.setAttribute("fill", fill ?? "var(--fluix-menu-indicator)");
1333
+ gGroup.appendChild(indicatorEl);
1334
+ svg.appendChild(gGroup);
1335
+ }
1336
+ canvasDiv.appendChild(svg);
1337
+ navEl.appendChild(canvasDiv);
1338
+ const listDiv = document.createElement("div");
1339
+ applyAttrs3(listDiv, attrs.list);
1340
+ const buttonMap = /* @__PURE__ */ new Map();
1341
+ function createItemButton(item) {
1342
+ const btn = document.createElement("button");
1343
+ btn.type = "button";
1344
+ const active = snapshot.activeId === item.id;
1345
+ const itemAttrs = attrs.item({ id: item.id, active, disabled: item.disabled });
1346
+ applyAttrs3(btn, itemAttrs);
1347
+ if (item.disabled) btn.disabled = true;
1348
+ btn.textContent = item.label;
1349
+ btn.addEventListener("click", () => {
1350
+ if (item.disabled) return;
1351
+ if (controlledActiveId === void 0) {
1352
+ machine.setActive(item.id);
1353
+ } else {
1354
+ onActiveChange?.(item.id);
1355
+ }
1356
+ });
1357
+ buttonMap.set(item.id, btn);
1358
+ listDiv.appendChild(btn);
1359
+ }
1360
+ for (const item of items) {
1361
+ createItemButton(item);
1362
+ }
1363
+ navEl.appendChild(listDiv);
1364
+ container.appendChild(navEl);
1365
+ let size = { width: 0, height: 0 };
1366
+ let measureRaf = 0;
1367
+ const measure = () => {
1368
+ const rect = navEl.getBoundingClientRect();
1369
+ const w = Math.ceil(rect.width);
1370
+ const h = Math.ceil(rect.height);
1371
+ if (size.width !== w || size.height !== h) {
1372
+ size = { width: w, height: h };
1373
+ updateSvgSize();
1374
+ connection?.sync(false);
1375
+ }
1376
+ };
1377
+ const resizeObs = new ResizeObserver(() => {
1378
+ cancelAnimationFrame(measureRaf);
1379
+ measureRaf = requestAnimationFrame(measure);
1380
+ });
1381
+ resizeObs.observe(navEl);
1382
+ function updateSvgSize() {
1383
+ const w = Math.max(1, size.width);
1384
+ const h = Math.max(1, size.height);
1385
+ svg.setAttribute("width", String(w));
1386
+ svg.setAttribute("height", String(h));
1387
+ svg.setAttribute("viewBox", `0 0 ${w} ${h}`);
1388
+ }
1389
+ let connection = core.connectMenu({
1390
+ root: navEl,
1391
+ indicator: indicatorEl,
1392
+ getActiveId: () => snapshot.activeId,
1393
+ onSelect(id) {
1394
+ if (controlledActiveId === void 0) {
1395
+ machine.setActive(id);
1396
+ } else {
1397
+ onActiveChange?.(id);
1398
+ }
1399
+ },
1400
+ spring: springConfig(),
1401
+ variant,
1402
+ orientation
1403
+ });
1404
+ requestAnimationFrame(() => {
1405
+ measure();
1406
+ connection.sync(false);
1407
+ });
1408
+ const unsubscribe = machine.store.subscribe(() => {
1409
+ const next = machine.store.getSnapshot();
1410
+ snapshot = next;
1411
+ for (const item of items) {
1412
+ const btn = buttonMap.get(item.id);
1413
+ if (btn) {
1414
+ const active = next.activeId === item.id;
1415
+ const itemAttrs = attrs.item({ id: item.id, active, disabled: item.disabled });
1416
+ applyAttrs3(btn, itemAttrs);
1417
+ }
1418
+ }
1419
+ if (next.activeId && lastActiveNotified !== next.activeId && onActiveChange) {
1420
+ onActiveChange(next.activeId);
1421
+ }
1422
+ lastActiveNotified = next.activeId;
1423
+ connection.sync(false);
1424
+ });
1425
+ return {
1426
+ setActive(id) {
1427
+ machine.setActive(id);
1428
+ },
1429
+ update(opts) {
1430
+ if (opts.orientation !== void 0) orientation = opts.orientation;
1431
+ if (opts.variant !== void 0) variant = opts.variant;
1432
+ if (opts.theme !== void 0) theme = opts.theme;
1433
+ if (opts.activeId !== void 0) controlledActiveId = opts.activeId;
1434
+ if (opts.onActiveChange !== void 0) onActiveChange = opts.onActiveChange;
1435
+ if (opts.spring !== void 0) spring = opts.spring;
1436
+ if (opts.roundness !== void 0) roundness = opts.roundness;
1437
+ if (opts.blur !== void 0) blurProp = opts.blur;
1438
+ if (opts.fill !== void 0) fill = opts.fill;
1439
+ machine.configure({ orientation, variant, spring, roundness, blur: blurProp, fill });
1440
+ if (controlledActiveId !== void 0) {
1441
+ machine.setActive(controlledActiveId ?? null);
1442
+ }
1443
+ const newAttrs = core.getMenuAttrs({ orientation, theme, variant });
1444
+ applyAttrs3(navEl, newAttrs.root);
1445
+ if (opts.items !== void 0) {
1446
+ items = opts.items;
1447
+ listDiv.innerHTML = "";
1448
+ buttonMap.clear();
1449
+ for (const item of items) {
1450
+ createItemButton(item);
1451
+ }
1452
+ }
1453
+ connection.destroy();
1454
+ connection = core.connectMenu({
1455
+ root: navEl,
1456
+ indicator: indicatorEl,
1457
+ getActiveId: () => snapshot.activeId,
1458
+ onSelect(id) {
1459
+ if (controlledActiveId === void 0) {
1460
+ machine.setActive(id);
1461
+ } else {
1462
+ onActiveChange?.(id);
1463
+ }
1464
+ },
1465
+ spring: springConfig(),
1466
+ variant,
1467
+ orientation
1468
+ });
1469
+ requestAnimationFrame(() => {
1470
+ measure();
1471
+ connection.sync(false);
1472
+ });
1473
+ },
1474
+ destroy() {
1475
+ unsubscribe();
1476
+ cancelAnimationFrame(measureRaf);
1477
+ resizeObs.disconnect();
1478
+ connection.destroy();
1479
+ machine.destroy();
1480
+ navEl.remove();
1481
+ }
1482
+ };
1483
+ }
785
1484
 
786
1485
  Object.defineProperty(exports, "fluix", {
787
1486
  enumerable: true,
788
1487
  get: function () { return core.fluix; }
789
1488
  });
1489
+ exports.createMenu = createMenu;
1490
+ exports.createNotch = createNotch;
790
1491
  exports.createToaster = createToaster;
791
1492
  //# sourceMappingURL=index.cjs.map
792
1493
  //# sourceMappingURL=index.cjs.map