@underverse-ui/underverse 2.0.20 → 2.0.22

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
@@ -2416,8 +2416,7 @@ function UEditorPortalProvider({
2416
2416
  function useUEditorPortalContainerGetter() {
2417
2417
  return React12.useContext(UEditorPortalContext);
2418
2418
  }
2419
- function resolveUEditorPortalContainer(getPortalContainer, fallbackGetPortalContainer) {
2420
- if (typeof document === "undefined") return null;
2419
+ function resolveUEditorPortalContainer(getPortalContainer, fallbackGetPortalContainer, fallbackDocument) {
2421
2420
  const getters = [getPortalContainer, fallbackGetPortalContainer];
2422
2421
  for (const getter of getters) {
2423
2422
  if (!getter) continue;
@@ -2427,7 +2426,8 @@ function resolveUEditorPortalContainer(getPortalContainer, fallbackGetPortalCont
2427
2426
  } catch {
2428
2427
  }
2429
2428
  }
2430
- return document.body;
2429
+ if (fallbackDocument) return fallbackDocument.body;
2430
+ return typeof document !== "undefined" ? document.body : null;
2431
2431
  }
2432
2432
  var React12, import_jsx_runtime13, UEditorPortalContext;
2433
2433
  var init_portal_context = __esm({
@@ -4196,6 +4196,26 @@ function overflowAmount(left, width, viewportWidth, padding) {
4196
4196
  const overflowRight = Math.max(0, left + width - max);
4197
4197
  return overflowLeft + overflowRight;
4198
4198
  }
4199
+ function getScrollAncestors(trigger, ownerWindow) {
4200
+ const ancestors = [];
4201
+ let current = trigger.parentElement;
4202
+ while (current) {
4203
+ try {
4204
+ const style = ownerWindow.getComputedStyle(current);
4205
+ const overflow = `${style.overflow} ${style.overflowX} ${style.overflowY}`;
4206
+ if (/(auto|scroll|overlay|hidden)/.test(overflow)) ancestors.push(current);
4207
+ } catch {
4208
+ }
4209
+ current = current.parentElement;
4210
+ }
4211
+ return ancestors;
4212
+ }
4213
+ function isFiniteRect(rect) {
4214
+ return [rect.top, rect.right, rect.bottom, rect.left, rect.width, rect.height].every(Number.isFinite);
4215
+ }
4216
+ function isFullyOutsideViewport(rect, viewportWidth, viewportHeight) {
4217
+ return rect.bottom < 0 || rect.right < 0 || rect.top > viewportHeight || rect.left > viewportWidth;
4218
+ }
4199
4219
  function computePopoverPosition(args) {
4200
4220
  const { triggerRect, contentSize, placement, offset, padding, viewport, constrainToAvailableHeight } = args;
4201
4221
  let { side, align } = normalizePlacement(placement);
@@ -4293,17 +4313,19 @@ var init_Popover = __esm({
4293
4313
  const isControlled = open !== void 0;
4294
4314
  const [internalOpen, setInternalOpen] = React25.useState(false);
4295
4315
  const triggerRef = React25.useRef(null);
4316
+ const [triggerDocument, setTriggerDocument] = React25.useState(null);
4296
4317
  const positionerRef = React25.useRef(null);
4297
4318
  const panelRef = React25.useRef(null);
4319
+ const pendingFrameRef = React25.useRef(null);
4320
+ const closeRequestedRef = React25.useRef(false);
4298
4321
  const lastAppliedRef = React25.useRef(null);
4299
4322
  const globalConfig = useUnderverseUIConfig();
4300
4323
  const resolvedBorderMode = borderMode ?? globalConfig.popover?.borderMode ?? globalConfig.borderMode;
4301
4324
  const isOpen = isControlled ? open : internalOpen;
4302
4325
  const contextGetPortalContainer = useUEditorPortalContainerGetter();
4303
- const portalContainer = isOpen ? resolveUEditorPortalContainer(getPortalContainer, contextGetPortalContainer) : null;
4304
- const portalDocument = portalContainer?.ownerDocument ?? null;
4305
- const portalWindow = portalDocument?.defaultView ?? null;
4306
- useShadCNAnimations(portalDocument);
4326
+ const requestedPortalContainer = isOpen && triggerDocument ? resolveUEditorPortalContainer(getPortalContainer, contextGetPortalContainer, triggerDocument) : null;
4327
+ const portalContainer = requestedPortalContainer?.ownerDocument === triggerDocument ? requestedPortalContainer : triggerDocument?.body ?? null;
4328
+ useShadCNAnimations(isOpen ? triggerDocument : null);
4307
4329
  const setIsOpen = React25.useCallback(
4308
4330
  (next) => {
4309
4331
  if (!isControlled) setInternalOpen(next);
@@ -4314,126 +4336,205 @@ var init_Popover = __esm({
4314
4336
  const offset = 4;
4315
4337
  const padding = 8;
4316
4338
  const initialPlacement = React25.useMemo(() => normalizePlacement(placement), [placement]);
4339
+ const cancelScheduledPositionUpdate = React25.useCallback(() => {
4340
+ const pending = pendingFrameRef.current;
4341
+ if (!pending) return;
4342
+ pendingFrameRef.current = null;
4343
+ try {
4344
+ pending.ownerWindow.cancelAnimationFrame(pending.frameId);
4345
+ } catch {
4346
+ }
4347
+ }, []);
4348
+ const closeWhenPositioningIsUnsafe = React25.useCallback(() => {
4349
+ const positionerEl = positionerRef.current;
4350
+ if (positionerEl) {
4351
+ positionerEl.style.visibility = "hidden";
4352
+ positionerEl.style.pointerEvents = "none";
4353
+ }
4354
+ if (closeRequestedRef.current) return;
4355
+ closeRequestedRef.current = true;
4356
+ setIsOpen(false);
4357
+ }, [setIsOpen]);
4317
4358
  const updatePosition = React25.useCallback(() => {
4318
4359
  const triggerEl = triggerRef.current;
4319
4360
  const positionerEl = positionerRef.current;
4320
4361
  const panelEl = panelRef.current;
4321
- if (!triggerEl || !positionerEl || !panelEl || !portalWindow) return;
4362
+ if (!triggerEl || !positionerEl || !panelEl) return;
4363
+ const ownerDocument = triggerEl.ownerDocument;
4364
+ const ownerWindow = ownerDocument.defaultView;
4365
+ if (!ownerWindow || ownerWindow.closed || !triggerEl.isConnected || !positionerEl.isConnected || positionerEl.ownerDocument !== ownerDocument || panelEl.ownerDocument !== ownerDocument) {
4366
+ closeWhenPositioningIsUnsafe();
4367
+ return;
4368
+ }
4322
4369
  const contentEl = panelEl.firstElementChild;
4323
- if (!contentEl) return;
4324
- const triggerRect = triggerEl.getBoundingClientRect();
4325
- const widthWanted = matchTriggerWidth ? triggerRect.width : contentWidth;
4326
- const widthPx = widthWanted == null ? void 0 : Math.max(0, Math.round(widthWanted));
4327
- if (widthPx == null) {
4328
- if (positionerEl.style.width) positionerEl.style.width = "";
4329
- } else if (positionerEl.style.width !== `${widthPx}px`) {
4330
- positionerEl.style.width = `${widthPx}px`;
4331
- }
4332
- const prevApplied = lastAppliedRef.current;
4333
- const measuredWidth = positionerEl.offsetWidth;
4334
- const measuredHeight = positionerEl.offsetHeight;
4335
- const contentRect = positionerEl.getBoundingClientRect();
4336
- const contentBoxWidth = measuredWidth || contentRect.width;
4337
- const contentBoxHeight = Math.max(measuredHeight, contentRect.height, contentEl.scrollHeight);
4338
- const next = computePopoverPosition({
4339
- triggerRect,
4340
- contentSize: { width: contentBoxWidth, height: contentBoxHeight },
4341
- placement,
4342
- offset,
4343
- padding,
4344
- viewport: {
4345
- width: portalWindow.innerWidth,
4346
- height: portalWindow.innerHeight
4347
- },
4348
- constrainToAvailableHeight
4349
- });
4350
- const top = Math.round(next.top);
4351
- const left = Math.round(next.left);
4352
- const applied = prevApplied && Math.abs(prevApplied.top - top) < 0.5 && Math.abs(prevApplied.left - left) < 0.5 && prevApplied.side === next.side && prevApplied.align === next.align && prevApplied.width === widthPx && prevApplied.availableHeight === next.availableHeight;
4353
- if (applied) return;
4354
- lastAppliedRef.current = {
4355
- top,
4356
- left,
4357
- side: next.side,
4358
- align: next.align,
4359
- width: widthPx,
4360
- availableHeight: next.availableHeight
4361
- };
4362
- positionerEl.style.transform = `translate3d(${left}px, ${top}px, 0)`;
4363
- positionerEl.style.setProperty("--underverse-popover-available-height", `${next.availableHeight}px`);
4364
- positionerEl.dataset.side = next.side;
4365
- positionerEl.dataset.align = next.align;
4366
- panelEl.style.transformOrigin = getTransformOrigin2(next.side, next.align);
4367
- if (positionerEl.style.visibility !== "visible") positionerEl.style.visibility = "visible";
4368
- if (positionerEl.style.pointerEvents !== "auto") positionerEl.style.pointerEvents = "auto";
4369
- }, [placement, matchTriggerWidth, contentWidth, portalWindow, constrainToAvailableHeight]);
4370
+ if (!contentEl) {
4371
+ closeWhenPositioningIsUnsafe();
4372
+ return;
4373
+ }
4374
+ try {
4375
+ const triggerRect = triggerEl.getBoundingClientRect();
4376
+ const viewportWidth = ownerWindow.innerWidth;
4377
+ const viewportHeight = ownerWindow.innerHeight;
4378
+ if (!isFiniteRect(triggerRect) || !Number.isFinite(viewportWidth) || !Number.isFinite(viewportHeight) || viewportWidth <= 0 || viewportHeight <= 0 || isFullyOutsideViewport(triggerRect, viewportWidth, viewportHeight)) {
4379
+ closeWhenPositioningIsUnsafe();
4380
+ return;
4381
+ }
4382
+ const widthWanted = matchTriggerWidth ? triggerRect.width : contentWidth;
4383
+ const widthPx = widthWanted == null ? void 0 : Math.max(0, Math.round(widthWanted));
4384
+ if (widthPx == null) {
4385
+ if (positionerEl.style.width) positionerEl.style.width = "";
4386
+ } else if (positionerEl.style.width !== `${widthPx}px`) {
4387
+ positionerEl.style.width = `${widthPx}px`;
4388
+ }
4389
+ const prevApplied = lastAppliedRef.current;
4390
+ const measuredWidth = positionerEl.offsetWidth;
4391
+ const measuredHeight = positionerEl.offsetHeight;
4392
+ const contentRect = positionerEl.getBoundingClientRect();
4393
+ const contentBoxWidth = measuredWidth || contentRect.width;
4394
+ const contentBoxHeight = Math.max(measuredHeight, contentRect.height, contentEl.scrollHeight);
4395
+ const next = computePopoverPosition({
4396
+ triggerRect,
4397
+ contentSize: { width: contentBoxWidth, height: contentBoxHeight },
4398
+ placement,
4399
+ offset,
4400
+ padding,
4401
+ viewport: {
4402
+ width: viewportWidth,
4403
+ height: viewportHeight
4404
+ },
4405
+ constrainToAvailableHeight
4406
+ });
4407
+ const top = Math.round(next.top);
4408
+ const left = Math.round(next.left);
4409
+ const applied = prevApplied && prevApplied.positioner === positionerEl && Math.abs(prevApplied.top - top) < 0.5 && Math.abs(prevApplied.left - left) < 0.5 && prevApplied.side === next.side && prevApplied.align === next.align && prevApplied.width === widthPx && prevApplied.availableHeight === next.availableHeight;
4410
+ if (applied) return;
4411
+ lastAppliedRef.current = {
4412
+ positioner: positionerEl,
4413
+ top,
4414
+ left,
4415
+ side: next.side,
4416
+ align: next.align,
4417
+ width: widthPx,
4418
+ availableHeight: next.availableHeight
4419
+ };
4420
+ positionerEl.style.transform = `translate3d(${left}px, ${top}px, 0)`;
4421
+ positionerEl.style.setProperty("--underverse-popover-available-height", `${next.availableHeight}px`);
4422
+ positionerEl.dataset.side = next.side;
4423
+ positionerEl.dataset.align = next.align;
4424
+ panelEl.style.transformOrigin = getTransformOrigin2(next.side, next.align);
4425
+ if (positionerEl.style.visibility !== "visible") positionerEl.style.visibility = "visible";
4426
+ if (positionerEl.style.pointerEvents !== "auto") positionerEl.style.pointerEvents = "auto";
4427
+ } catch {
4428
+ closeWhenPositioningIsUnsafe();
4429
+ }
4430
+ }, [placement, matchTriggerWidth, contentWidth, constrainToAvailableHeight, closeWhenPositioningIsUnsafe]);
4431
+ const schedulePositionUpdate = React25.useCallback(() => {
4432
+ if (pendingFrameRef.current) return;
4433
+ const triggerEl = triggerRef.current;
4434
+ const ownerWindow = triggerEl?.ownerDocument.defaultView;
4435
+ if (!triggerEl || !ownerWindow || ownerWindow.closed) {
4436
+ closeWhenPositioningIsUnsafe();
4437
+ return;
4438
+ }
4439
+ try {
4440
+ const frameId = ownerWindow.requestAnimationFrame(() => {
4441
+ pendingFrameRef.current = null;
4442
+ updatePosition();
4443
+ });
4444
+ pendingFrameRef.current = { ownerWindow, frameId };
4445
+ } catch {
4446
+ closeWhenPositioningIsUnsafe();
4447
+ }
4448
+ }, [closeWhenPositioningIsUnsafe, updatePosition]);
4370
4449
  React25.useLayoutEffect(() => {
4371
- if (!isOpen || !portalWindow) return;
4450
+ if (isOpen) {
4451
+ closeRequestedRef.current = false;
4452
+ return;
4453
+ }
4454
+ lastAppliedRef.current = null;
4455
+ cancelScheduledPositionUpdate();
4456
+ }, [cancelScheduledPositionUpdate, isOpen]);
4457
+ React25.useLayoutEffect(() => {
4458
+ if (!isOpen || !portalContainer) return;
4372
4459
  updatePosition();
4373
- let raf1 = 0;
4374
- let raf2 = 0;
4375
- raf1 = portalWindow.requestAnimationFrame(() => {
4376
- updatePosition();
4377
- raf2 = portalWindow.requestAnimationFrame(() => updatePosition());
4378
- });
4379
- return () => {
4380
- portalWindow.cancelAnimationFrame(raf1);
4381
- portalWindow.cancelAnimationFrame(raf2);
4382
- };
4383
- }, [isOpen, portalWindow, updatePosition]);
4460
+ schedulePositionUpdate();
4461
+ return cancelScheduledPositionUpdate;
4462
+ }, [cancelScheduledPositionUpdate, isOpen, portalContainer, schedulePositionUpdate, updatePosition]);
4384
4463
  React25.useEffect(() => {
4385
- if (!isOpen || !portalWindow) return;
4386
- let raf = 0;
4387
- const tick = () => {
4388
- updatePosition();
4389
- raf = portalWindow.requestAnimationFrame(tick);
4390
- };
4391
- raf = portalWindow.requestAnimationFrame(tick);
4392
- return () => portalWindow.cancelAnimationFrame(raf);
4393
- }, [isOpen, portalWindow, updatePosition]);
4394
- React25.useEffect(() => {
4395
- if (!isOpen || !portalDocument || !portalWindow) return;
4396
- let raf = 0;
4397
- const handler = () => {
4398
- portalWindow.cancelAnimationFrame(raf);
4399
- raf = portalWindow.requestAnimationFrame(() => updatePosition());
4400
- };
4401
- handler();
4402
- portalWindow.addEventListener("resize", handler);
4403
- portalWindow.addEventListener("scroll", handler, true);
4404
- portalDocument.addEventListener("scroll", handler, true);
4464
+ const triggerEl = triggerRef.current;
4465
+ const positionerEl = positionerRef.current;
4466
+ if (!isOpen || !triggerEl || !positionerEl || !portalContainer) return;
4467
+ const ownerDocument = triggerEl.ownerDocument;
4468
+ const ownerWindow = ownerDocument.defaultView;
4469
+ if (!ownerWindow || ownerWindow.closed || portalContainer.ownerDocument !== ownerDocument) {
4470
+ closeWhenPositioningIsUnsafe();
4471
+ return;
4472
+ }
4473
+ const scrollAncestors = getScrollAncestors(triggerEl, ownerWindow);
4474
+ const passiveOptions = { passive: true };
4475
+ for (const ancestor of scrollAncestors) {
4476
+ ancestor.addEventListener("scroll", schedulePositionUpdate, passiveOptions);
4477
+ }
4478
+ ownerWindow.addEventListener("scroll", schedulePositionUpdate, passiveOptions);
4479
+ ownerWindow.addEventListener("resize", schedulePositionUpdate);
4480
+ ownerDocument.addEventListener("scroll", schedulePositionUpdate, { capture: true, passive: true });
4481
+ const visualViewport = ownerWindow.visualViewport;
4482
+ visualViewport?.addEventListener("scroll", schedulePositionUpdate, passiveOptions);
4483
+ visualViewport?.addEventListener("resize", schedulePositionUpdate);
4484
+ const ResizeObserverCtor = ownerWindow.ResizeObserver;
4485
+ const resizeObserver = ResizeObserverCtor ? new ResizeObserverCtor(schedulePositionUpdate) : null;
4486
+ resizeObserver?.observe(triggerEl);
4487
+ resizeObserver?.observe(positionerEl);
4488
+ const contentEl = panelRef.current?.firstElementChild;
4489
+ if (contentEl) resizeObserver?.observe(contentEl);
4490
+ const MutationObserverCtor = ownerWindow.MutationObserver;
4491
+ const mutationObserver = MutationObserverCtor ? new MutationObserverCtor(() => {
4492
+ const currentTrigger = triggerRef.current;
4493
+ if (!currentTrigger || !currentTrigger.isConnected || currentTrigger.ownerDocument !== ownerDocument) {
4494
+ closeWhenPositioningIsUnsafe();
4495
+ }
4496
+ }) : null;
4497
+ if (mutationObserver && ownerDocument.documentElement) {
4498
+ mutationObserver.observe(ownerDocument.documentElement, { childList: true, subtree: true });
4499
+ }
4500
+ schedulePositionUpdate();
4405
4501
  return () => {
4406
- portalWindow.cancelAnimationFrame(raf);
4407
- portalWindow.removeEventListener("resize", handler);
4408
- portalWindow.removeEventListener("scroll", handler, true);
4409
- portalDocument.removeEventListener("scroll", handler, true);
4502
+ for (const ancestor of scrollAncestors) {
4503
+ ancestor.removeEventListener("scroll", schedulePositionUpdate);
4504
+ }
4505
+ ownerWindow.removeEventListener("scroll", schedulePositionUpdate);
4506
+ ownerWindow.removeEventListener("resize", schedulePositionUpdate);
4507
+ ownerDocument.removeEventListener("scroll", schedulePositionUpdate, true);
4508
+ visualViewport?.removeEventListener("scroll", schedulePositionUpdate);
4509
+ visualViewport?.removeEventListener("resize", schedulePositionUpdate);
4510
+ resizeObserver?.disconnect();
4511
+ mutationObserver?.disconnect();
4512
+ cancelScheduledPositionUpdate();
4410
4513
  };
4411
- }, [isOpen, portalDocument, portalWindow, updatePosition]);
4514
+ }, [
4515
+ cancelScheduledPositionUpdate,
4516
+ closeWhenPositioningIsUnsafe,
4517
+ isOpen,
4518
+ portalContainer,
4519
+ schedulePositionUpdate
4520
+ ]);
4412
4521
  React25.useEffect(() => {
4413
- if (!isOpen || !portalWindow) return;
4414
- const ResizeObserverCtor = portalWindow.ResizeObserver;
4415
- if (!ResizeObserverCtor) return;
4416
- const ro = new ResizeObserverCtor(() => updatePosition());
4417
- if (positionerRef.current) ro.observe(positionerRef.current);
4418
- if (triggerRef.current) ro.observe(triggerRef.current);
4419
- return () => ro.disconnect();
4420
- }, [isOpen, portalWindow, updatePosition]);
4421
- React25.useLayoutEffect(() => {
4422
- if (!isOpen) {
4423
- lastAppliedRef.current = null;
4522
+ const triggerEl = triggerRef.current;
4523
+ if (!isOpen || !triggerEl || !portalContainer) return;
4524
+ const ownerDocument = triggerEl.ownerDocument;
4525
+ const ownerWindow = ownerDocument.defaultView;
4526
+ if (!ownerWindow || portalContainer.ownerDocument !== ownerDocument) {
4527
+ closeWhenPositioningIsUnsafe();
4424
4528
  return;
4425
4529
  }
4426
- }, [isOpen]);
4427
- React25.useEffect(() => {
4428
- if (!isOpen || !portalDocument || !portalWindow) return;
4429
4530
  const handleClickOutside = (event) => {
4430
4531
  const target = event.target;
4431
- const triggerEl = triggerRef.current;
4532
+ const currentTrigger = triggerRef.current;
4432
4533
  const popoverEl = positionerRef.current;
4433
- if (!triggerEl || !popoverEl) return;
4434
- if (triggerEl.contains(target)) return;
4534
+ if (!currentTrigger || !popoverEl) return;
4535
+ if (currentTrigger.contains(target)) return;
4435
4536
  if (popoverEl.contains(target)) return;
4436
- if (target instanceof portalWindow.Element && target.closest("[data-popover]")) return;
4537
+ if (target instanceof ownerWindow.Element && target.closest("[data-popover]")) return;
4437
4538
  setIsOpen(false);
4438
4539
  };
4439
4540
  const handleEscape = (event) => {
@@ -4441,18 +4542,30 @@ var init_Popover = __esm({
4441
4542
  setIsOpen(false);
4442
4543
  }
4443
4544
  };
4444
- portalDocument.addEventListener("mousedown", handleClickOutside);
4445
- portalDocument.addEventListener("keydown", handleEscape);
4545
+ ownerDocument.addEventListener("mousedown", handleClickOutside);
4546
+ ownerDocument.addEventListener("keydown", handleEscape);
4446
4547
  return () => {
4447
- portalDocument.removeEventListener("mousedown", handleClickOutside);
4448
- portalDocument.removeEventListener("keydown", handleEscape);
4548
+ ownerDocument.removeEventListener("mousedown", handleClickOutside);
4549
+ ownerDocument.removeEventListener("keydown", handleEscape);
4449
4550
  };
4450
- }, [isOpen, portalDocument, portalWindow, setIsOpen]);
4551
+ }, [closeWhenPositioningIsUnsafe, isOpen, portalContainer, setIsOpen]);
4451
4552
  const handleTriggerClick = () => {
4452
4553
  if (!disabled) {
4453
4554
  setIsOpen(!isOpen);
4454
4555
  }
4455
4556
  };
4557
+ const triggerProps = trigger.props;
4558
+ const childRef = triggerProps.ref;
4559
+ const setTriggerNode = React25.useCallback((node) => {
4560
+ triggerRef.current = node;
4561
+ if (node) {
4562
+ setTriggerDocument((currentDocument) => currentDocument === node.ownerDocument ? currentDocument : node.ownerDocument);
4563
+ }
4564
+ }, []);
4565
+ const composedTriggerRef = React25.useMemo(
4566
+ () => mergeRefs(childRef, setTriggerNode),
4567
+ [childRef, setTriggerNode]
4568
+ );
4456
4569
  const popoverContent = isOpen && portalContainer ? (0, import_react_dom3.createPortal)(
4457
4570
  /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
4458
4571
  "div",
@@ -4508,13 +4621,9 @@ var init_Popover = __esm({
4508
4621
  ) : null;
4509
4622
  return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
4510
4623
  (() => {
4511
- const triggerProps = trigger.props;
4512
- const childRef = triggerProps.ref;
4513
4624
  return React25.cloneElement(trigger, {
4514
4625
  ...triggerProps,
4515
- ref: mergeRefs(childRef, (node) => {
4516
- triggerRef.current = node;
4517
- }),
4626
+ ref: composedTriggerRef,
4518
4627
  onClick: chainEventHandlers(
4519
4628
  (e) => {
4520
4629
  triggerRef.current = e.currentTarget;
@@ -4565,7 +4674,6 @@ var init_DropdownMenu = __esm({
4565
4674
  "use strict";
4566
4675
  "use client";
4567
4676
  init_cn();
4568
- init_animations();
4569
4677
  import_react17 = __toESM(require("react"), 1);
4570
4678
  init_react_compose();
4571
4679
  init_Popover();
@@ -4573,7 +4681,6 @@ var init_DropdownMenu = __esm({
4573
4681
  init_radius();
4574
4682
  init_UnderverseConfigContext();
4575
4683
  init_form_control_size();
4576
- init_portal_context();
4577
4684
  import_jsx_runtime33 = require("react/jsx-runtime");
4578
4685
  DropdownMenuContext = import_react17.default.createContext(null);
4579
4686
  DropdownMenu = ({
@@ -4608,7 +4715,6 @@ var init_DropdownMenu = __esm({
4608
4715
  const [activeIndex, setActiveIndex] = useResettingIndex(open);
4609
4716
  const parentMenu = import_react17.default.useContext(DropdownMenuContext);
4610
4717
  const hoverCloseTimeoutRef = import_react17.default.useRef(null);
4611
- const getPortalContainer = useUEditorPortalContainerGetter();
4612
4718
  const cancelHoverClose = import_react17.default.useCallback(() => {
4613
4719
  if (hoverCloseTimeoutRef.current === null) return;
4614
4720
  clearTimeout(hoverCloseTimeoutRef.current);
@@ -4641,7 +4747,6 @@ var init_DropdownMenu = __esm({
4641
4747
  item.focus();
4642
4748
  item.scrollIntoView({ block: "nearest" });
4643
4749
  }, [getEnabledMenuItems, setActiveIndex]);
4644
- useShadCNAnimations();
4645
4750
  const globalConfig = useUnderverseUIConfig();
4646
4751
  const resolvedBorderMode = borderMode ?? globalConfig.dropdownMenu?.borderMode ?? globalConfig.borderMode;
4647
4752
  import_react17.default.useEffect(() => {
@@ -4762,8 +4867,11 @@ var init_DropdownMenu = __esm({
4762
4867
  triggerRef.current = node;
4763
4868
  }, [childRef]);
4764
4869
  const handleTriggerKeyDown = import_react17.default.useCallback((event) => {
4765
- const portalWindow = resolveUEditorPortalContainer(getPortalContainer)?.ownerDocument.defaultView;
4766
- const scheduleFrame = portalWindow?.requestAnimationFrame.bind(portalWindow) ?? requestAnimationFrame;
4870
+ const triggerWindow = event.currentTarget.ownerDocument.defaultView;
4871
+ const scheduleFrame = (callback) => {
4872
+ if (triggerWindow) triggerWindow.requestAnimationFrame(callback);
4873
+ else callback(0);
4874
+ };
4767
4875
  if (!disabled) {
4768
4876
  if (event.key === "ArrowDown") {
4769
4877
  event.preventDefault();
@@ -4782,7 +4890,7 @@ var init_DropdownMenu = __esm({
4782
4890
  }
4783
4891
  }
4784
4892
  triggerOnKeyDown?.(event);
4785
- }, [disabled, focusMenuItem, getEnabledMenuItems, getPortalContainer, setOpen, triggerOnKeyDown]);
4893
+ }, [disabled, focusMenuItem, getEnabledMenuItems, setOpen, triggerOnKeyDown]);
4786
4894
  const handleTriggerClick = import_react17.default.useCallback((event) => {
4787
4895
  if (openOnHover && !disabled) {
4788
4896
  cancelHoverClose();
@@ -31899,10 +32007,19 @@ function DataTablePagination({
31899
32007
  size,
31900
32008
  align,
31901
32009
  paginationRange,
31902
- borderMode
32010
+ borderMode,
32011
+ variant = "default"
31903
32012
  }) {
31904
32013
  const totalPages = Math.ceil(totalItems / curPageSize);
32014
+ const isClassic = variant === "classic";
32015
+ const classicBlockSize = 10;
31905
32016
  const pages = import_react35.default.useMemo(() => {
32017
+ if (isClassic) {
32018
+ const blockIndex = Math.floor((curPage - 1) / classicBlockSize);
32019
+ const startPage = blockIndex * classicBlockSize + 1;
32020
+ const endPage = Math.min(startPage + classicBlockSize - 1, totalPages);
32021
+ return Array.from({ length: endPage - startPage + 1 }, (_, i) => startPage + i);
32022
+ }
31906
32023
  const edgeCount = Math.max(1, Math.floor(paginationRange ?? (totalPages < 14 ? 3 : 5)));
31907
32024
  if (totalPages <= edgeCount * 2 + 3) return Array.from({ length: totalPages }, (_, index) => index + 1);
31908
32025
  const pageNumbers = /* @__PURE__ */ new Set();
@@ -31910,7 +32027,7 @@ function DataTablePagination({
31910
32027
  for (let page = totalPages - edgeCount + 1; page <= totalPages; page += 1) pageNumbers.add(page);
31911
32028
  for (let page = Math.max(1, curPage - 1); page <= Math.min(totalPages, curPage + 1); page += 1) pageNumbers.add(page);
31912
32029
  return Array.from(pageNumbers).sort((a, b) => a - b).flatMap((page, index, sortedPages) => index > 0 && page - sortedPages[index - 1] > 1 ? ["...", page] : [page]);
31913
- }, [curPage, paginationRange, totalPages]);
32030
+ }, [curPage, paginationRange, totalPages, isClassic]);
31914
32031
  if (totalItems === 0) return null;
31915
32032
  const controlButtonSize = size === "lg" ? "md" : "sm";
31916
32033
  const navBtnClass = size === "sm" ? "h-6 w-6 p-0 rounded-full" : size === "lg" ? "h-8 w-8 p-0 rounded-full" : "h-7 w-7 p-0 rounded-full";
@@ -31919,6 +32036,8 @@ function DataTablePagination({
31919
32036
  const pageBtnClass = size === "sm" ? "h-6 min-w-6 px-1.5 text-[11px] font-medium transition-colors" : size === "lg" ? "h-8 min-w-8 px-2.5 text-sm font-medium transition-colors" : "h-7 min-w-7 px-2 text-xs font-medium transition-colors";
31920
32037
  const containerTextClass = size === "sm" ? "text-[11px]" : size === "lg" ? "text-sm" : "text-xs";
31921
32038
  const pageSizeClass = size === "sm" ? "w-16" : size === "lg" ? "w-24" : "w-20";
32039
+ const showClassicNav = isClassic && totalPages > classicBlockSize;
32040
+ const showArrowNav = !isClassic || showClassicNav;
31922
32041
  return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("div", { className: cn("relative flex items-center gap-2 px-1 pt-3 text-muted-foreground", containerTextClass), children: [
31923
32042
  /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("div", { className: "flex items-center gap-2", children: [
31924
32043
  /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("div", { className: "tabular-nums", children: [
@@ -31928,7 +32047,7 @@ function DataTablePagination({
31928
32047
  "/",
31929
32048
  totalItems
31930
32049
  ] }),
31931
- pageSizeOptions && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
32050
+ pageSizeOptions && pageSizeOptions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
31932
32051
  Combobox,
31933
32052
  {
31934
32053
  options: pageSizeOptions.map(String),
@@ -31951,14 +32070,32 @@ function DataTablePagination({
31951
32070
  align === "right" && "ml-auto"
31952
32071
  ),
31953
32072
  children: [
31954
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
32073
+ showClassicNav && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
31955
32074
  Button_default,
31956
32075
  {
31957
32076
  variant: "ghost",
31958
32077
  size: controlButtonSize,
31959
32078
  className: navBtnClass,
31960
- onClick: () => setCurPage(Math.max(1, curPage - 1)),
32079
+ onClick: () => setCurPage(1),
31961
32080
  disabled: curPage === 1,
32081
+ children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("svg", { className: navIconClass, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11 19l-7-7 7-7m8 14l-7-7 7-7" }) })
32082
+ }
32083
+ ),
32084
+ showArrowNav && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
32085
+ Button_default,
32086
+ {
32087
+ variant: "ghost",
32088
+ size: controlButtonSize,
32089
+ className: navBtnClass,
32090
+ onClick: () => {
32091
+ if (isClassic) {
32092
+ const startPage = Math.floor((curPage - 1) / classicBlockSize) * classicBlockSize + 1;
32093
+ setCurPage(Math.max(1, startPage - classicBlockSize));
32094
+ } else {
32095
+ setCurPage(Math.max(1, curPage - 1));
32096
+ }
32097
+ },
32098
+ disabled: isClassic ? Math.floor((curPage - 1) / classicBlockSize) === 0 : curPage === 1,
31962
32099
  children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("svg", { className: navIconClass, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) })
31963
32100
  }
31964
32101
  ),
@@ -31973,16 +32110,34 @@ function DataTablePagination({
31973
32110
  p
31974
32111
  )
31975
32112
  ) }),
31976
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
32113
+ showArrowNav && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
31977
32114
  Button_default,
31978
32115
  {
31979
32116
  variant: "ghost",
31980
32117
  size: controlButtonSize,
31981
32118
  className: navBtnClass,
31982
- onClick: () => setCurPage(Math.min(totalPages, curPage + 1)),
31983
- disabled: curPage === totalPages,
32119
+ onClick: () => {
32120
+ if (isClassic) {
32121
+ const startPage = Math.floor((curPage - 1) / classicBlockSize) * classicBlockSize + 1;
32122
+ setCurPage(Math.min(totalPages, startPage + classicBlockSize));
32123
+ } else {
32124
+ setCurPage(Math.min(totalPages, curPage + 1));
32125
+ }
32126
+ },
32127
+ disabled: isClassic ? Math.floor((curPage - 1) / classicBlockSize) === Math.floor((totalPages - 1) / classicBlockSize) : curPage === totalPages,
31984
32128
  children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("svg", { className: navIconClass, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) })
31985
32129
  }
32130
+ ),
32131
+ showClassicNav && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
32132
+ Button_default,
32133
+ {
32134
+ variant: "ghost",
32135
+ size: controlButtonSize,
32136
+ className: navBtnClass,
32137
+ onClick: () => setCurPage(totalPages),
32138
+ disabled: curPage === totalPages,
32139
+ children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("svg", { className: navIconClass, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 5l7 7-7 7M5 5l7 7-7 7" }) })
32140
+ }
31986
32141
  )
31987
32142
  ]
31988
32143
  }
@@ -32701,7 +32856,8 @@ function DataTable({
32701
32856
  enableHeaderAutoFit = true,
32702
32857
  labels,
32703
32858
  columnColorGroups,
32704
- borderMode
32859
+ borderMode,
32860
+ paginationVariant = "default"
32705
32861
  }) {
32706
32862
  const t = useSmartTranslations("Common");
32707
32863
  const globalConfig = useUnderverseUIConfig();
@@ -32952,7 +33108,8 @@ function DataTable({
32952
33108
  size,
32953
33109
  align: paginationAlign,
32954
33110
  paginationRange,
32955
- borderMode: resolvedBorderMode
33111
+ borderMode: resolvedBorderMode,
33112
+ variant: paginationVariant
32956
33113
  }
32957
33114
  )
32958
33115
  ] });