@l3mpire/ui 3.5.0 → 3.6.0

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.mjs CHANGED
@@ -492,7 +492,8 @@ var buttonVariants = cva3(
492
492
  },
493
493
  intent: {
494
494
  brand: [],
495
- alert: []
495
+ alert: [],
496
+ ai: []
496
497
  },
497
498
  size: {
498
499
  sm: [
@@ -614,6 +615,48 @@ var buttonVariants = cva3(
614
615
  "active:text-btn-ghost-alert-text-pressed"
615
616
  ]
616
617
  },
618
+ // ── Solid + AI ─────────────────────────────────────────────────────
619
+ // Vivid brand→violet gradient fill, white label/icons, violet outer
620
+ // border + a translucent-white inner border (via inset shadow).
621
+ {
622
+ appearance: "solid",
623
+ intent: "ai",
624
+ class: [
625
+ "bg-ai-strong",
626
+ "text-[var(--core-text-main-invert-primary)]",
627
+ "border-[var(--violet-500)]",
628
+ "shadow-[inset_0_0_0_1px_rgb(255_255_255/0.6),0_1px_3px_0_var(--shadow-4)]",
629
+ "hover:bg-ai-strong-hover",
630
+ "active:bg-ai-strong-pressed"
631
+ ]
632
+ },
633
+ // ── Outlined + AI ──────────────────────────────────────────────────
634
+ // Neutral surface (same as outlined brand), brand-blue border that
635
+ // deepens per state; label/icons are gradient-clipped (see component).
636
+ {
637
+ appearance: "outlined",
638
+ intent: "ai",
639
+ class: [
640
+ "bg-gradient-to-t from-btn-outlined-neutral-bg-default from-[10%] to-btn-outlined-neutral-bg-gradient-to-default",
641
+ "border-[var(--interactive-bg-primary-dark-default)]",
642
+ "shadow-[0_1px_3px_0_var(--shadow-4)]",
643
+ "hover:from-btn-outlined-neutral-bg-hover hover:from-[0%] hover:to-btn-outlined-neutral-bg-gradient-to-hover",
644
+ "hover:border-[var(--interactive-bg-primary-dark-hover)]",
645
+ "active:from-btn-outlined-neutral-bg-pressed active:to-btn-outlined-neutral-bg-gradient-to-pressed",
646
+ "active:border-[var(--interactive-bg-primary-dark-pressed)]"
647
+ ]
648
+ },
649
+ // ── Ghost + AI ─────────────────────────────────────────────────────
650
+ // Subtle translucent gradient wash, no border; gradient-clipped text.
651
+ {
652
+ appearance: "ghost",
653
+ intent: "ai",
654
+ class: [
655
+ "bg-ai-subtle border-transparent",
656
+ "hover:bg-ai-subtle-hover",
657
+ "active:bg-ai-subtle-pressed"
658
+ ]
659
+ },
617
660
  // ── Icon-only size overrides ───────────────────────────────────────
618
661
  { size: "sm", iconOnly: true, class: "w-6 min-w-0 px-0" },
619
662
  { size: "md", iconOnly: true, class: "w-8 min-w-0 px-0" },
@@ -676,6 +719,8 @@ var Button = React6.forwardRef(
676
719
  const isDisabled = disabled || loading;
677
720
  const isIconOnly = iconOnlyProp ?? !children;
678
721
  const iconSize = iconSizeMap[resolvedSize];
722
+ const aiGradientText = intent === "ai" && appearance !== "solid" && !isDisabled;
723
+ const aiTextClass = aiGradientText ? "ai-grad-text" : void 0;
679
724
  const variantClasses = buttonVariants({
680
725
  appearance,
681
726
  intent,
@@ -685,7 +730,7 @@ var Button = React6.forwardRef(
685
730
  className
686
731
  });
687
732
  const labelNode = !isIconOnly ? /* @__PURE__ */ jsxs5("span", { className: textWrapperClass(resolvedSize), children: [
688
- children,
733
+ aiGradientText ? /* @__PURE__ */ jsx6("span", { className: aiTextClass, children }) : children,
689
734
  badge != null && /* @__PURE__ */ jsx6(ButtonBadge, { size: resolvedSize, intent, children: badge })
690
735
  ] }) : null;
691
736
  if (asChild) {
@@ -698,11 +743,12 @@ var Button = React6.forwardRef(
698
743
  className: cn(variantClasses),
699
744
  disabled: isDisabled,
700
745
  "aria-busy": loading || void 0,
746
+ "data-ai-text": aiGradientText || void 0,
701
747
  ...props,
702
748
  children: [
703
- loading ? /* @__PURE__ */ jsx6(Icon4, { icon: faSpinnerSolid, size: iconSize, className: "animate-spin" }) : leftIcon ? /* @__PURE__ */ jsx6(Icon4, { icon: leftIcon, size: iconSize }) : null,
749
+ loading ? /* @__PURE__ */ jsx6(Icon4, { icon: faSpinnerSolid, size: iconSize, className: "animate-spin" }) : leftIcon ? /* @__PURE__ */ jsx6(Icon4, { icon: leftIcon, size: iconSize, className: aiTextClass }) : null,
704
750
  labelNode,
705
- rightIcon && !loading && /* @__PURE__ */ jsx6(Icon4, { icon: rightIcon, size: iconSize })
751
+ rightIcon && !loading && /* @__PURE__ */ jsx6(Icon4, { icon: rightIcon, size: iconSize, className: aiTextClass })
706
752
  ]
707
753
  }
708
754
  );
@@ -7172,6 +7218,18 @@ function ColumnFilterPopover({
7172
7218
  ) })
7173
7219
  ] });
7174
7220
  }
7221
+ function pinnedStickyStyle(pinned, offset, zIndex) {
7222
+ if (pinned === "left") return { position: "sticky", left: offset, zIndex };
7223
+ if (pinned === "right") return { position: "sticky", right: offset, zIndex };
7224
+ return {};
7225
+ }
7226
+ function pinnedDividerClass(pinned) {
7227
+ if (pinned === "left")
7228
+ return "shadow-[1px_0_0_0_var(--core-border-main-primary)]";
7229
+ if (pinned === "right")
7230
+ return "shadow-[-1px_0_0_0_var(--core-border-main-primary)]";
7231
+ return "";
7232
+ }
7175
7233
  function DraggableHeaderCell({
7176
7234
  header,
7177
7235
  enableSorting,
@@ -7199,6 +7257,7 @@ function DraggableHeaderCell({
7199
7257
  disabled: !canDrag
7200
7258
  });
7201
7259
  const pinned = header.column.getIsPinned();
7260
+ const pinOffset = pinned === "left" ? header.column.getStart("left") : pinned === "right" ? header.column.getAfter("right") : void 0;
7202
7261
  const style = {
7203
7262
  width: enableColumnResizing ? header.getSize() : void 0,
7204
7263
  minWidth: enableColumnResizing ? header.column.columnDef.minSize : void 0,
@@ -7209,18 +7268,7 @@ function DraggableHeaderCell({
7209
7268
  // Pinning sticky positioning — must override the default `relative` we
7210
7269
  // also use for the resize handle. The resize handle is still absolutely
7211
7270
  // positioned because it references `right: 0` relative to the cell.
7212
- ...pinned === "left" ? {
7213
- position: "sticky",
7214
- left: header.column.getStart("left"),
7215
- zIndex: isDragging ? 5 : 3
7216
- } : pinned === "right" ? {
7217
- position: "sticky",
7218
- right: header.column.getAfter("right"),
7219
- zIndex: isDragging ? 5 : 3
7220
- } : {
7221
- position: "relative",
7222
- zIndex: isDragging ? 1 : void 0
7223
- }
7271
+ ...pinned ? pinnedStickyStyle(pinned, pinOffset, isDragging ? 5 : 3) : { position: "relative", zIndex: isDragging ? 1 : void 0 }
7224
7272
  };
7225
7273
  return /* @__PURE__ */ jsxs48(
7226
7274
  TableHead,
@@ -7234,8 +7282,7 @@ function DraggableHeaderCell({
7234
7282
  // Pinned columns keep their bg so the scrolling content can pass
7235
7283
  // under them. The default `bg-table-head-bg-default` is already on
7236
7284
  // <th> so we only need to add a divider on the boundary.
7237
- pinned === "left" && "shadow-[1px_0_0_0_var(--core-border-main-primary)]",
7238
- pinned === "right" && "shadow-[-1px_0_0_0_var(--core-border-main-primary)]"
7285
+ pinnedDividerClass(pinned)
7239
7286
  ),
7240
7287
  onClick: canSort ? header.column.getToggleSortingHandler() : void 0,
7241
7288
  onMouseEnter: () => setIsHovered(true),
@@ -7464,15 +7511,22 @@ function DataTableInner({
7464
7511
  }).filter(Boolean),
7465
7512
  [columns]
7466
7513
  );
7514
+ const lastSyncedColumnIdsRef = React54.useRef(null);
7467
7515
  React54.useEffect(() => {
7468
7516
  if (!enableColumnDrag) return;
7517
+ const signature = allColumnIds.join(" ");
7518
+ if (signature === lastSyncedColumnIdsRef.current) return;
7519
+ lastSyncedColumnIdsRef.current = signature;
7469
7520
  if (columnOrder.length === 0) {
7470
7521
  setColumnOrder(allColumnIds);
7471
7522
  return;
7472
7523
  }
7473
- const missing = allColumnIds.filter((id) => !columnOrder.includes(id));
7474
- if (missing.length > 0) {
7475
- setColumnOrder([...columnOrder, ...missing]);
7524
+ const pruned = columnOrder.filter((id) => allColumnIds.includes(id));
7525
+ const missing = allColumnIds.filter((id) => !pruned.includes(id));
7526
+ const next = [...pruned, ...missing];
7527
+ const changed = next.length !== columnOrder.length || next.some((id, i) => id !== columnOrder[i]);
7528
+ if (changed) {
7529
+ setColumnOrder(next);
7476
7530
  }
7477
7531
  }, [enableColumnDrag, columnOrder, allColumnIds, setColumnOrder]);
7478
7532
  const table = useReactTable({
@@ -7589,6 +7643,16 @@ function DataTableInner({
7589
7643
  return vars;
7590
7644
  }, [enableColumnResizing, table.getState().columnSizing]);
7591
7645
  const totalSize = enableColumnResizing ? table.getTotalSize() : void 0;
7646
+ const pinnedOffsets = React54.useMemo(() => {
7647
+ const map = /* @__PURE__ */ new Map();
7648
+ for (const col of table.getVisibleLeafColumns()) {
7649
+ const p = col.getIsPinned();
7650
+ if (p === "left") map.set(col.id, { side: "left", offset: col.getStart("left") });
7651
+ else if (p === "right")
7652
+ map.set(col.id, { side: "right", offset: col.getAfter("right") });
7653
+ }
7654
+ return map;
7655
+ }, [table, table.getState().columnPinning, table.getState().columnSizing]);
7592
7656
  const tableContent = /* @__PURE__ */ jsxs48("div", { className: cn("w-full", className), style: columnSizeVars, children: [
7593
7657
  /* @__PURE__ */ jsxs48(
7594
7658
  Table,
@@ -7664,17 +7728,10 @@ function DataTableInner({
7664
7728
  "data-state": row.getIsSelected() ? "selected" : void 0,
7665
7729
  children: row.getVisibleCells().map((cell) => {
7666
7730
  const cellPinned = cell.column.getIsPinned();
7731
+ const pin = cellPinned ? pinnedOffsets.get(cell.column.id) : void 0;
7667
7732
  const cellStyle = {
7668
7733
  ...enableColumnResizing ? { width: `var(--col-${cell.column.id}-size)` } : {},
7669
- ...cellPinned === "left" ? {
7670
- position: "sticky",
7671
- left: cell.column.getStart("left"),
7672
- zIndex: 2
7673
- } : cellPinned === "right" ? {
7674
- position: "sticky",
7675
- right: cell.column.getAfter("right"),
7676
- zIndex: 2
7677
- } : {}
7734
+ ...pinnedStickyStyle(cellPinned, pin?.offset, 2)
7678
7735
  };
7679
7736
  return /* @__PURE__ */ jsx54(
7680
7737
  TableCell,
@@ -7685,8 +7742,8 @@ function DataTableInner({
7685
7742
  enableColumnResizing && "truncate",
7686
7743
  // Pinned cells need an opaque background so scrolled
7687
7744
  // content does not show through.
7688
- cellPinned === "left" && "bg-table-row-bg-default group-hover/row:bg-table-row-bg-hover data-[state=selected]:bg-table-row-bg-selected shadow-[1px_0_0_0_var(--core-border-main-primary)]",
7689
- cellPinned === "right" && "bg-table-row-bg-default group-hover/row:bg-table-row-bg-hover data-[state=selected]:bg-table-row-bg-selected shadow-[-1px_0_0_0_var(--core-border-main-primary)]"
7745
+ cellPinned && "bg-table-row-bg-default group-hover/row:bg-table-row-bg-hover data-[state=selected]:bg-table-row-bg-selected",
7746
+ pinnedDividerClass(cellPinned)
7690
7747
  ),
7691
7748
  children: flexRender(
7692
7749
  cell.column.columnDef.cell,