@bizapps/ui 1.4.1 → 1.5.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/main.cjs CHANGED
@@ -1688,31 +1688,37 @@ function SelectContent({
1688
1688
  className,
1689
1689
  children,
1690
1690
  position = "popper",
1691
+ maxHeight,
1692
+ style,
1691
1693
  ...props
1692
1694
  }) {
1695
+ const resolvedMaxHeight = typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight;
1693
1696
  return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Select.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
1694
1697
  radixUi.Select.Content,
1695
1698
  {
1696
1699
  "data-slot": "select-content",
1697
1700
  className: cn(
1698
- "border-border bg-popover text-popover-foreground relative z-50 max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
1701
+ "border-border bg-popover text-popover-foreground relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-hidden rounded-md border shadow-md",
1699
1702
  "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
1700
1703
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
1701
1704
  "data-[side=bottom]:translate-y-1 data-[side=top]:-translate-y-1",
1702
- position === "popper" && "w-[--radix-select-trigger-width]",
1705
+ position === "popper" && "w-(--radix-select-trigger-width)",
1703
1706
  className
1704
1707
  ),
1705
1708
  position,
1709
+ style: {
1710
+ ...resolvedMaxHeight ? {
1711
+ maxHeight: `min(${resolvedMaxHeight}, var(--radix-select-content-available-height))`
1712
+ } : null,
1713
+ ...style
1714
+ },
1706
1715
  ...props,
1707
1716
  children: [
1708
1717
  /* @__PURE__ */ jsxRuntime.jsx(SelectScrollUpButton, {}),
1709
1718
  /* @__PURE__ */ jsxRuntime.jsx(
1710
1719
  radixUi.Select.Viewport,
1711
1720
  {
1712
- className: cn(
1713
- "p-1",
1714
- position === "popper" && "h-[--radix-select-trigger-height]"
1715
- ),
1721
+ className: cn("scroll-my-1 p-1", position === "popper" && "w-full"),
1716
1722
  children
1717
1723
  }
1718
1724
  ),
@@ -4374,6 +4380,7 @@ ColorPickerPresets.displayName = "ColorPickerPresets";
4374
4380
  function Calendar({
4375
4381
  className,
4376
4382
  classNames,
4383
+ modifiersClassNames,
4377
4384
  showOutsideDays = true,
4378
4385
  captionLayout = "dropdown",
4379
4386
  buttonVariant = "ghost",
@@ -4385,6 +4392,36 @@ function Calendar({
4385
4392
  ...props
4386
4393
  }) {
4387
4394
  const defaultClassNames = reactDayPicker.getDefaultClassNames();
4395
+ const resolvedComponents = react.useMemo(
4396
+ () => ({
4397
+ Root: ({ className: className2, rootRef, ...rootProps }) => {
4398
+ return /* @__PURE__ */ jsxRuntime.jsx(
4399
+ "div",
4400
+ {
4401
+ "data-slot": "calendar",
4402
+ ref: rootRef,
4403
+ className: cn(className2),
4404
+ ...rootProps
4405
+ }
4406
+ );
4407
+ },
4408
+ Chevron: ({ className: className2, orientation, ...chevronProps }) => {
4409
+ if (orientation === "left") {
4410
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeftIcon, { className: cn("size-4", className2), ...chevronProps });
4411
+ }
4412
+ if (orientation === "right") {
4413
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRightIcon, { className: cn("size-4", className2), ...chevronProps });
4414
+ }
4415
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, { className: cn("size-4", className2), ...chevronProps });
4416
+ },
4417
+ DayButton: (dayButtonProps) => /* @__PURE__ */ jsxRuntime.jsx(CalendarDayButton, { locale, ...dayButtonProps }),
4418
+ WeekNumber: ({ children, ...weekNumberProps }) => {
4419
+ return /* @__PURE__ */ jsxRuntime.jsx("td", { ...weekNumberProps, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-(--cell-size) items-center justify-center text-center", children }) });
4420
+ },
4421
+ ...components
4422
+ }),
4423
+ [locale, components]
4424
+ );
4388
4425
  return /* @__PURE__ */ jsxRuntime.jsx(
4389
4426
  reactDayPicker.DayPicker,
4390
4427
  {
@@ -4476,33 +4513,13 @@ function Calendar({
4476
4513
  hidden: cn("invisible", defaultClassNames.hidden),
4477
4514
  ...classNames
4478
4515
  },
4479
- components: {
4480
- Root: ({ className: className2, rootRef, ...props2 }) => {
4481
- return /* @__PURE__ */ jsxRuntime.jsx(
4482
- "div",
4483
- {
4484
- "data-slot": "calendar",
4485
- ref: rootRef,
4486
- className: cn(className2),
4487
- ...props2
4488
- }
4489
- );
4490
- },
4491
- Chevron: ({ className: className2, orientation, ...props2 }) => {
4492
- if (orientation === "left") {
4493
- return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeftIcon, { className: cn("size-4", className2), ...props2 });
4494
- }
4495
- if (orientation === "right") {
4496
- return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRightIcon, { className: cn("size-4", className2), ...props2 });
4497
- }
4498
- return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, { className: cn("size-4", className2), ...props2 });
4499
- },
4500
- DayButton: ({ ...props2 }) => /* @__PURE__ */ jsxRuntime.jsx(CalendarDayButton, { locale, ...props2 }),
4501
- WeekNumber: ({ children, ...props2 }) => {
4502
- return /* @__PURE__ */ jsxRuntime.jsx("td", { ...props2, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-(--cell-size) items-center justify-center text-center", children }) });
4503
- },
4504
- ...components
4516
+ modifiersClassNames: {
4517
+ preview_start: "relative isolate z-0 rounded-l-md bg-primary/8 after:absolute after:inset-y-0 after:right-0 after:w-3 after:bg-primary/8",
4518
+ preview_middle: "rounded-none bg-primary/8",
4519
+ preview_end: "relative isolate z-0 rounded-r-md bg-primary/8 after:absolute after:inset-y-0 after:left-0 after:w-3 after:bg-primary/8",
4520
+ ...modifiersClassNames
4505
4521
  },
4522
+ components: resolvedComponents,
4506
4523
  ...props
4507
4524
  }
4508
4525
  );
@@ -4519,6 +4536,9 @@ function CalendarDayButton({
4519
4536
  react.useEffect(() => {
4520
4537
  if (modifiers.focused) ref.current?.focus();
4521
4538
  }, [modifiers.focused]);
4539
+ const isPreviewEdge = Boolean(
4540
+ (modifiers.preview_start || modifiers.preview_end) && !modifiers.selected
4541
+ );
4522
4542
  return /* @__PURE__ */ jsxRuntime.jsx(
4523
4543
  Button,
4524
4544
  {
@@ -4530,8 +4550,10 @@ function CalendarDayButton({
4530
4550
  "data-range-start": modifiers.range_start,
4531
4551
  "data-range-end": modifiers.range_end,
4532
4552
  "data-range-middle": modifiers.range_middle,
4553
+ "data-preview-middle": Boolean(modifiers.preview_middle),
4554
+ "data-preview-edge": isPreviewEdge,
4533
4555
  className: cn(
4534
- "group-data-[focused=true]/day:ring-primary/40 data-[range-end=true]:!bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:!bg-primary/8 data-[range-middle=true]:text-foreground data-[range-start=true]:!bg-primary data-[range-start=true]:text-primary-foreground data-[selected-single=true]:!bg-primary data-[selected-single=true]:text-primary-foreground relative isolate z-10 flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 !rounded-md border-0 !bg-transparent leading-none font-normal transition-colors duration-150 group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:rounded-md group-data-[focused=true]/day:ring-[2px] hover:!bg-transparent data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md data-[selected-single=true]:rounded-md [&>span]:text-xs [&>span]:font-medium [&>span]:opacity-75",
4556
+ "group-data-[focused=true]/day:ring-primary/40 data-[preview-edge=true]:ring-primary/50 data-[preview-edge=true]:text-primary data-[preview-middle=true]:text-primary data-[range-end=true]:!bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:!bg-primary/8 data-[range-middle=true]:text-foreground data-[range-start=true]:!bg-primary data-[range-start=true]:text-primary-foreground data-[selected-single=true]:!bg-primary data-[selected-single=true]:text-primary-foreground relative isolate z-10 flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 !rounded-md border-0 !bg-transparent leading-none font-normal transition-colors duration-150 group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:rounded-md group-data-[focused=true]/day:ring-[2px] hover:!bg-transparent data-[preview-edge=true]:rounded-md data-[preview-edge=true]:font-medium data-[preview-edge=true]:ring-[2px] data-[preview-middle=true]:font-medium data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md data-[selected-single=true]:rounded-md [&>span]:text-xs [&>span]:font-medium [&>span]:opacity-75",
4535
4557
  defaultClassNames.day,
4536
4558
  className
4537
4559
  ),
@@ -4539,35 +4561,37 @@ function CalendarDayButton({
4539
4561
  }
4540
4562
  );
4541
4563
  }
4542
- function DatePicker({
4543
- mode = "single",
4544
- selected,
4545
- onSelect,
4546
- placeholder = "Pick a date",
4547
- disabled = false,
4548
- className,
4549
- fromDate,
4550
- toDate,
4551
- numberOfMonths = 1
4552
- }) {
4564
+ function DatePicker(props) {
4565
+ const {
4566
+ placeholder = "Pick a date",
4567
+ disabled = false,
4568
+ className,
4569
+ fromDate,
4570
+ toDate,
4571
+ numberOfMonths = 1
4572
+ } = props;
4553
4573
  const [open, setOpen] = react.useState(false);
4554
4574
  const [awaitingRangeEnd, setAwaitingRangeEnd] = react.useState(false);
4575
+ const [previewDate, setPreviewDate] = react.useState(void 0);
4555
4576
  const label = react.useMemo(() => {
4556
- if (mode === "range") {
4557
- const range = selected;
4577
+ if (props.mode === "range") {
4578
+ const range = props.selected;
4558
4579
  if (!range?.from) return placeholder;
4559
4580
  if (!range.to) return `${dateFns.format(range.from, "MMM d, yyyy")} \u2013 \u2026`;
4560
4581
  return `${dateFns.format(range.from, "MMM d, yyyy")} \u2013 ${dateFns.format(range.to, "MMM d, yyyy")}`;
4561
4582
  }
4562
- const date = selected;
4563
- return date ? dateFns.format(date, "MMM d, yyyy") : placeholder;
4564
- }, [mode, selected, placeholder]);
4583
+ return props.selected ? dateFns.format(props.selected, "MMM d, yyyy") : placeholder;
4584
+ }, [props.mode, props.selected, placeholder]);
4565
4585
  const handleOpenChange = (nextOpen) => {
4566
4586
  setOpen(nextOpen);
4567
- if (!nextOpen) setAwaitingRangeEnd(false);
4587
+ if (!nextOpen) {
4588
+ setAwaitingRangeEnd(false);
4589
+ setPreviewDate(void 0);
4590
+ }
4568
4591
  };
4569
4592
  const handleRangeSelect = (range, triggerDate) => {
4570
- const emit = onSelect;
4593
+ if (props.mode !== "range") return;
4594
+ const emit = props.onSelect;
4571
4595
  if (!awaitingRangeEnd) {
4572
4596
  setAwaitingRangeEnd(true);
4573
4597
  emit?.({ from: triggerDate, to: void 0 });
@@ -4579,8 +4603,25 @@ function DatePicker({
4579
4603
  return;
4580
4604
  }
4581
4605
  setAwaitingRangeEnd(false);
4606
+ setPreviewDate(void 0);
4582
4607
  setOpen(false);
4583
4608
  };
4609
+ const rangeFrom = props.mode === "range" ? props.selected?.from : void 0;
4610
+ const previewModifiers = react.useMemo(() => {
4611
+ if (!awaitingRangeEnd || !rangeFrom || !previewDate) return void 0;
4612
+ if (dateFns.isSameDay(rangeFrom, previewDate)) return void 0;
4613
+ const [start, end] = previewDate < rangeFrom ? [previewDate, rangeFrom] : [rangeFrom, previewDate];
4614
+ return {
4615
+ preview_start: start,
4616
+ preview_middle: { after: start, before: end },
4617
+ preview_end: end
4618
+ };
4619
+ }, [awaitingRangeEnd, rangeFrom, previewDate]);
4620
+ const handleDayPreview = (day, dayModifiers) => {
4621
+ if (!awaitingRangeEnd) return;
4622
+ if (dayModifiers.disabled || dayModifiers.hidden) return;
4623
+ setPreviewDate((current) => current && dateFns.isSameDay(current, day) ? current : day);
4624
+ };
4584
4625
  const dateConstraints = react.useMemo(() => {
4585
4626
  const disabledMatchers = [];
4586
4627
  if (fromDate) disabledMatchers.push({ before: fromDate });
@@ -4591,7 +4632,7 @@ function DatePicker({
4591
4632
  ...toDate && { endMonth: toDate }
4592
4633
  };
4593
4634
  }, [fromDate, toDate]);
4594
- const hasValue = mode === "range" ? !!selected?.from : !!selected;
4635
+ const hasValue = props.mode === "range" ? !!props.selected?.from : !!props.selected;
4595
4636
  return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
4596
4637
  /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
4597
4638
  Button,
@@ -4610,32 +4651,36 @@ function DatePicker({
4610
4651
  ]
4611
4652
  }
4612
4653
  ) }),
4613
- /* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { "data-slot": "date-picker-content", className: "w-auto p-0", align: "start", children: mode === "range" ? /* @__PURE__ */ jsxRuntime.jsx(
4614
- Calendar,
4615
- {
4616
- ...{
4654
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { "data-slot": "date-picker-content", className: "w-auto p-0", align: "start", children: props.mode === "range" ? (
4655
+ // Clearing the preview on the wrapper instead of per day
4656
+ // avoids the blank frame `onDayMouseLeave` would cause when
4657
+ // the pointer travels from one day to the next.
4658
+ /* @__PURE__ */ jsxRuntime.jsx("div", { onMouseLeave: () => setPreviewDate(void 0), children: /* @__PURE__ */ jsxRuntime.jsx(
4659
+ Calendar,
4660
+ {
4617
4661
  mode: "range",
4618
- selected,
4662
+ selected: props.selected,
4619
4663
  onSelect: handleRangeSelect,
4620
- ...dateConstraints,
4664
+ modifiers: previewModifiers,
4665
+ onDayMouseEnter: handleDayPreview,
4666
+ onDayFocus: handleDayPreview,
4621
4667
  numberOfMonths,
4622
- autoFocus: true
4668
+ autoFocus: true,
4669
+ ...dateConstraints
4623
4670
  }
4624
- }
4671
+ ) })
4625
4672
  ) : /* @__PURE__ */ jsxRuntime.jsx(
4626
4673
  Calendar,
4627
4674
  {
4628
- ...{
4629
- mode: "single",
4630
- selected,
4631
- onSelect: (date) => {
4632
- onSelect?.(date);
4633
- setOpen(false);
4634
- },
4635
- ...dateConstraints,
4636
- numberOfMonths,
4637
- autoFocus: true
4638
- }
4675
+ mode: "single",
4676
+ selected: props.selected,
4677
+ onSelect: (date) => {
4678
+ props.onSelect?.(date);
4679
+ setOpen(false);
4680
+ },
4681
+ numberOfMonths,
4682
+ autoFocus: true,
4683
+ ...dateConstraints
4639
4684
  }
4640
4685
  ) })
4641
4686
  ] });
@@ -5098,6 +5143,8 @@ function AbilityProvider({ children, permissions }) {
5098
5143
  const [permissionSet, setPermissionSet] = react.useState(
5099
5144
  () => new Set(permissions ?? [])
5100
5145
  );
5146
+ const [imperativelyResolved, setImperativelyResolved] = react.useState(false);
5147
+ const status = permissions !== void 0 || imperativelyResolved ? "ready" : "loading";
5101
5148
  const can = react.useCallback(
5102
5149
  (perms, mode = "any") => {
5103
5150
  const list = Array.isArray(perms) ? perms : [perms];
@@ -5112,21 +5159,23 @@ function AbilityProvider({ children, permissions }) {
5112
5159
  );
5113
5160
  const setAbilities = react.useCallback((perms) => {
5114
5161
  setPermissionSet(new Set(perms));
5162
+ setImperativelyResolved(true);
5115
5163
  }, []);
5116
5164
  const clearAbilities = react.useCallback(() => {
5117
5165
  setPermissionSet(/* @__PURE__ */ new Set());
5166
+ setImperativelyResolved(true);
5118
5167
  }, []);
5119
- const syncedKey = react.useRef(permissions ? permissions.join("|") : null);
5168
+ const permissionKey = permissions === void 0 ? null : [...permissions].sort().join("|");
5169
+ const syncedKey = react.useRef(permissionKey);
5120
5170
  react.useEffect(() => {
5121
- if (permissions === void 0) return;
5122
- const key = permissions.join("|");
5123
- if (key === syncedKey.current) return;
5124
- syncedKey.current = key;
5171
+ if (permissionKey === null) return;
5172
+ if (permissionKey === syncedKey.current) return;
5173
+ syncedKey.current = permissionKey;
5125
5174
  setPermissionSet(new Set(permissions));
5126
- }, [permissions]);
5175
+ }, [permissionKey, permissions]);
5127
5176
  const value = react.useMemo(
5128
- () => ({ can, setAbilities, clearAbilities }),
5129
- [can, setAbilities, clearAbilities]
5177
+ () => ({ can, setAbilities, clearAbilities, status }),
5178
+ [can, setAbilities, clearAbilities, status]
5130
5179
  );
5131
5180
  return /* @__PURE__ */ jsxRuntime.jsx(AbilityContext.Provider, { value, children });
5132
5181
  }
@@ -5141,18 +5190,173 @@ function useCan(permissions, mode = "any") {
5141
5190
  const { can } = useAbility();
5142
5191
  return can(permissions, mode);
5143
5192
  }
5144
- function Can({ permission, mode = "any", negate = false, fallback = null, children }) {
5145
- const { can } = useAbility();
5146
- const hasPermission = can(permission, mode);
5193
+ function useAbilityStatus() {
5194
+ return useAbility().status;
5195
+ }
5196
+
5197
+ // src/components/authorization/permissions.generated.ts
5198
+ var KNOWN_PERMISSIONS = [];
5199
+
5200
+ // src/components/authorization/permission-catalog.ts
5201
+ var CATALOG = new Set(KNOWN_PERMISSIONS);
5202
+ var warned = /* @__PURE__ */ new Set();
5203
+ function warnUnknownPermission(permission) {
5204
+ if (process.env.NODE_ENV === "production") return;
5205
+ if (CATALOG.size === 0) return;
5206
+ const requested = Array.isArray(permission) ? permission : [permission];
5207
+ for (const entry of requested) {
5208
+ if (entry.includes("*")) continue;
5209
+ if (CATALOG.has(entry) || warned.has(entry)) continue;
5210
+ warned.add(entry);
5211
+ console.warn(
5212
+ `[Can] Unknown permission "${entry}". It is not in the generated permission catalog. Check for a typo, or regenerate the catalog with \`pnpm generate-permissions\`.`
5213
+ );
5214
+ }
5215
+ }
5216
+ var FOCUS_TRAVERSAL_KEYS = /* @__PURE__ */ new Set(["Tab", "Escape"]);
5217
+ function blockInteraction(event) {
5218
+ event.preventDefault();
5219
+ event.stopPropagation();
5220
+ }
5221
+ function blockNonTraversalKey(event) {
5222
+ if (!FOCUS_TRAVERSAL_KEYS.has(event.key)) blockInteraction(event);
5223
+ }
5224
+ var warnedRenderPropMisuse = /* @__PURE__ */ new Set();
5225
+ function warnRenderPropVoidsProps(voided) {
5226
+ if (process.env.NODE_ENV === "production") return;
5227
+ if (voided.length === 0) return;
5228
+ const key = voided.join(",");
5229
+ if (warnedRenderPropMisuse.has(key)) return;
5230
+ warnedRenderPropMisuse.add(key);
5231
+ console.warn(
5232
+ `[Can] \`children\` is a function, so ${voided.map((prop) => `\`${prop}\``).join(", ")} ${voided.length === 1 ? "is" : "are"} ignored. A render prop owns every state: read \`allowed\` and \`status\` and render the disabled, loading and denied cases yourself, or pass an element instead of a function.`
5233
+ );
5234
+ }
5235
+ function disableElement(child) {
5236
+ return react.cloneElement(child, {
5237
+ "aria-disabled": "true",
5238
+ className: cn(child.props.className, "cursor-not-allowed opacity-50"),
5239
+ onClickCapture: blockInteraction,
5240
+ onKeyDownCapture: blockNonTraversalKey,
5241
+ onKeyUpCapture: blockNonTraversalKey,
5242
+ onPointerDownCapture: blockInteraction,
5243
+ onMouseDownCapture: blockInteraction
5244
+ });
5245
+ }
5246
+ function InteractionFirewall({ children }) {
5247
+ return /* @__PURE__ */ jsxRuntime.jsx(
5248
+ "span",
5249
+ {
5250
+ "data-slot": "can-blocked",
5251
+ className: "contents",
5252
+ onClickCapture: blockInteraction,
5253
+ onPointerDownCapture: blockInteraction,
5254
+ onMouseDownCapture: blockInteraction,
5255
+ onKeyDownCapture: blockNonTraversalKey,
5256
+ onKeyUpCapture: blockNonTraversalKey,
5257
+ children
5258
+ }
5259
+ );
5260
+ }
5261
+ function DisabledSubtree({
5262
+ children,
5263
+ className,
5264
+ ...props
5265
+ }) {
5266
+ const { "data-slot": _incomingDataSlot, ...restProps } = props;
5267
+ return /* @__PURE__ */ jsxRuntime.jsx(
5268
+ "span",
5269
+ {
5270
+ "data-slot": "can-disabled",
5271
+ "aria-disabled": "true",
5272
+ className: cn(
5273
+ "inline-flex cursor-not-allowed opacity-50",
5274
+ "*:pointer-events-none",
5275
+ className
5276
+ ),
5277
+ onClickCapture: blockInteraction,
5278
+ onPointerDownCapture: blockInteraction,
5279
+ onMouseDownCapture: blockInteraction,
5280
+ onKeyDownCapture: blockNonTraversalKey,
5281
+ onKeyUpCapture: blockNonTraversalKey,
5282
+ ...restProps,
5283
+ children
5284
+ }
5285
+ );
5286
+ }
5287
+ function Can({
5288
+ permission,
5289
+ mode = "any",
5290
+ negate = false,
5291
+ behavior = "hide",
5292
+ reason = null,
5293
+ fallback = null,
5294
+ loading,
5295
+ children
5296
+ }) {
5297
+ warnUnknownPermission(permission);
5298
+ const { can, status } = useAbility();
5299
+ const hasPermission = status === "ready" && can(permission, mode);
5147
5300
  const show = negate ? !hasPermission : hasPermission;
5148
5301
  if (typeof children === "function") {
5149
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children(show) });
5302
+ warnRenderPropVoidsProps([
5303
+ ...behavior === "disable" ? ["behavior='disable'"] : [],
5304
+ ...reason !== null ? ["reason"] : [],
5305
+ ...fallback !== null ? ["fallback"] : [],
5306
+ ...loading !== void 0 ? ["loading"] : []
5307
+ ]);
5308
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children({ allowed: show, status }) });
5309
+ }
5310
+ if (status === "loading" && loading !== void 0) {
5311
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: loading });
5150
5312
  }
5151
- return show ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children }) : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback });
5313
+ if (show) {
5314
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
5315
+ }
5316
+ if (behavior === "disable") {
5317
+ if (react.isValidElement(children) && children.type !== react.Fragment) {
5318
+ const disabledChild = disableElement(children);
5319
+ if (reason === null) {
5320
+ return /* @__PURE__ */ jsxRuntime.jsx(InteractionFirewall, { children: disabledChild });
5321
+ }
5322
+ return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
5323
+ /* @__PURE__ */ jsxRuntime.jsx(InteractionFirewall, { children: /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: disabledChild }) }),
5324
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: reason })
5325
+ ] });
5326
+ }
5327
+ if (reason === null) {
5328
+ return /* @__PURE__ */ jsxRuntime.jsx(DisabledSubtree, { children });
5329
+ }
5330
+ return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
5331
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(DisabledSubtree, { children }) }),
5332
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: reason })
5333
+ ] });
5334
+ }
5335
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback });
5152
5336
  }
5153
5337
  Can.displayName = "Can";
5154
- function CanNot({ permission, mode = "any", fallback = null, children }) {
5155
- return /* @__PURE__ */ jsxRuntime.jsx(Can, { permission, mode, negate: true, fallback, children });
5338
+ function CanNot({
5339
+ permission,
5340
+ mode = "any",
5341
+ behavior = "hide",
5342
+ reason = null,
5343
+ fallback = null,
5344
+ loading,
5345
+ children
5346
+ }) {
5347
+ return /* @__PURE__ */ jsxRuntime.jsx(
5348
+ Can,
5349
+ {
5350
+ permission,
5351
+ mode,
5352
+ negate: true,
5353
+ behavior,
5354
+ reason,
5355
+ fallback,
5356
+ loading,
5357
+ children
5358
+ }
5359
+ );
5156
5360
  }
5157
5361
  CanNot.displayName = "CanNot";
5158
5362
  function useMediaQuery(query) {
@@ -6949,7 +7153,7 @@ function TableHead({ className, ...props }) {
6949
7153
  {
6950
7154
  "data-slot": "table-head",
6951
7155
  className: cn(
6952
- "text-foreground has([role=checkbox])]:pr-0 h-12 px-3 text-left align-middle font-medium whitespace-nowrap",
7156
+ "text-foreground has-[[role=checkbox]]:pr-0 h-12 px-3 text-left align-middle font-medium whitespace-nowrap",
6953
7157
  className
6954
7158
  ),
6955
7159
  ...props
@@ -6962,7 +7166,7 @@ function TableCell({ className, ...props }) {
6962
7166
  {
6963
7167
  "data-slot": "table-cell",
6964
7168
  className: cn(
6965
- "has([role=checkbox])]:pr-0 p-3 align-middle whitespace-nowrap",
7169
+ "has-[[role=checkbox]]:pr-0 p-3 align-middle whitespace-nowrap",
6966
7170
  className
6967
7171
  ),
6968
7172
  ...props
@@ -7223,6 +7427,13 @@ function useTableContext() {
7223
7427
  function useTableContextSafe() {
7224
7428
  return react.useContext(TableContext);
7225
7429
  }
7430
+
7431
+ // src/components/compounds/Table/cell-size-class.ts
7432
+ var cellSizeClass = {
7433
+ sm: "px-3 py-1.5 text-xs",
7434
+ md: "px-5 py-2.5 text-sm",
7435
+ lg: "px-6 py-3 text-sm"
7436
+ };
7226
7437
  var cardPadding = {
7227
7438
  sm: "p-3",
7228
7439
  md: "p-4",
@@ -7560,6 +7771,9 @@ function DataTableHeaderCell({ header }) {
7560
7771
  },
7561
7772
  className: cn(
7562
7773
  "bg-primary text-primary-foreground",
7774
+ // Same density padding as the body cells: without it the header
7775
+ // label and the cell value below it sit at different offsets.
7776
+ cellSizeClass[meta.size ?? tableSize],
7563
7777
  canResize && "relative",
7564
7778
  meta.align === "center" && "text-center",
7565
7779
  meta.align === "right" && "text-right",
@@ -7949,11 +8163,6 @@ function useTablePersistence({
7949
8163
  persistDensity
7950
8164
  };
7951
8165
  }
7952
- var cellSizeClass = {
7953
- sm: "px-1 py-0 text-xs",
7954
- md: "px-5 py-2.5 text-sm",
7955
- lg: "px-6 py-3 text-sm"
7956
- };
7957
8166
  function resolveClassName(value, row) {
7958
8167
  return typeof value === "function" ? value(row) : value;
7959
8168
  }
@@ -7994,6 +8203,13 @@ function DataTableCell({
7994
8203
  }
7995
8204
  );
7996
8205
  }
8206
+ var INTERACTIVE_CELL_CONTENT = 'button, a, input, select, textarea, [role="button"], [role="checkbox"], [role="menuitem"], [role="link"]';
8207
+ function isInteractiveCellEvent(event) {
8208
+ const target = event.target;
8209
+ if (!(target instanceof Element)) return false;
8210
+ const match = target.closest(INTERACTIVE_CELL_CONTENT);
8211
+ return match !== null && match !== event.currentTarget;
8212
+ }
7997
8213
  function DataTableRow({ row, classNames }) {
7998
8214
  const { onRowClick, variant } = useTableContext();
7999
8215
  const clickable = Boolean(onRowClick);
@@ -8006,12 +8222,15 @@ function DataTableRow({ row, classNames }) {
8006
8222
  "data-clickable": clickable || void 0,
8007
8223
  role: clickable ? "button" : void 0,
8008
8224
  tabIndex: clickable ? 0 : void 0,
8009
- onClick: clickable ? () => onRowClick?.(row.original) : void 0,
8225
+ onClick: clickable ? (e) => {
8226
+ if (isInteractiveCellEvent(e)) return;
8227
+ onRowClick?.(row.original);
8228
+ } : void 0,
8010
8229
  onKeyDown: clickable ? (e) => {
8011
- if (e.key === "Enter" || e.key === " ") {
8012
- e.preventDefault();
8013
- onRowClick?.(row.original);
8014
- }
8230
+ if (e.key !== "Enter" && e.key !== " ") return;
8231
+ if (isInteractiveCellEvent(e)) return;
8232
+ e.preventDefault();
8233
+ onRowClick?.(row.original);
8015
8234
  } : void 0,
8016
8235
  className: cn("hover:bg-muted", clickable && "cursor-pointer", rowClassName),
8017
8236
  children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsxRuntime.jsx(DataTableCell, { cell, cellClassName }, cell.id))
@@ -8612,7 +8831,7 @@ function DataTableFooter({ pagination, selectedCount, className }) {
8612
8831
  className: cn("flex items-center justify-between border-t px-4 py-2", className),
8613
8832
  children: [
8614
8833
  selectedCount != null && selectedCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-live": "polite", className: "text-muted-foreground text-xs", children: `${selectedCount} row${selectedCount > 1 ? "s" : ""} selected` }),
8615
- /* @__PURE__ */ jsxRuntime.jsx(TablePagination, { ...pagination })
8834
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto", children: /* @__PURE__ */ jsxRuntime.jsx(TablePagination, { ...pagination }) })
8616
8835
  ]
8617
8836
  }
8618
8837
  );
@@ -8721,18 +8940,21 @@ function DataTableSearch({
8721
8940
  debounce = 300
8722
8941
  }) {
8723
8942
  const ctx = useTableContextSafe();
8724
- const [inputValue, setInputValue] = react.useState("");
8725
8943
  const globalFilter = ctx?.globalFilter;
8726
8944
  const setGlobalFilter = ctx?.setGlobalFilter;
8945
+ const committedValue = globalFilter ?? "";
8946
+ const [inputValue, setInputValue] = react.useState(committedValue);
8727
8947
  react.useEffect(() => {
8728
- if (globalFilter === "") setInputValue("");
8948
+ if (globalFilter === void 0) return;
8949
+ setInputValue(globalFilter);
8729
8950
  }, [globalFilter]);
8730
8951
  react.useEffect(() => {
8952
+ if (inputValue === committedValue) return;
8731
8953
  const timer = setTimeout(() => {
8732
8954
  setGlobalFilter?.(inputValue);
8733
8955
  }, debounce);
8734
8956
  return () => clearTimeout(timer);
8735
- }, [inputValue, debounce, setGlobalFilter]);
8957
+ }, [inputValue, committedValue, debounce, setGlobalFilter]);
8736
8958
  const handleClear = () => {
8737
8959
  setInputValue("");
8738
8960
  setGlobalFilter?.("");
@@ -8753,7 +8975,13 @@ function DataTableSearch({
8753
8975
  onChange: (e) => setInputValue(e.target.value),
8754
8976
  placeholder,
8755
8977
  "aria-label": placeholder,
8756
- className: "h-8 w-48 pr-8 pl-8 text-sm"
8978
+ className: cn(
8979
+ "h-8 w-48 pr-9 pl-9 text-sm",
8980
+ "[&::-webkit-search-cancel-button]:appearance-none",
8981
+ "[&::-webkit-search-decoration]:appearance-none",
8982
+ "[&::-webkit-search-results-button]:appearance-none",
8983
+ "[&::-webkit-search-results-decoration]:appearance-none"
8984
+ )
8757
8985
  }
8758
8986
  ),
8759
8987
  inputValue && /* @__PURE__ */ jsxRuntime.jsx(
@@ -8763,7 +8991,7 @@ function DataTableSearch({
8763
8991
  size: "icon-sm",
8764
8992
  onClick: handleClear,
8765
8993
  "aria-label": "Clear search",
8766
- className: "text-muted-foreground hover:text-foreground absolute right-0.5 size-6",
8994
+ className: "text-muted-foreground hover:text-foreground absolute top-1/2 right-1.5 size-6 -translate-y-1/2",
8767
8995
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-3.5", "aria-hidden": "true" })
8768
8996
  }
8769
8997
  )
@@ -9298,6 +9526,7 @@ exports.ItemHeader = ItemHeader;
9298
9526
  exports.ItemMedia = ItemMedia;
9299
9527
  exports.ItemSeparator = ItemSeparator;
9300
9528
  exports.ItemTitle = ItemTitle;
9529
+ exports.KNOWN_PERMISSIONS = KNOWN_PERMISSIONS;
9301
9530
  exports.Label = Label;
9302
9531
  exports.Link = Link;
9303
9532
  exports.Logo = Logo;
@@ -9458,6 +9687,7 @@ exports.toggleVariants = toggleVariants;
9458
9687
  exports.tooltipContentVariants = tooltipContentVariants;
9459
9688
  exports.transition = transition;
9460
9689
  exports.useAbility = useAbility;
9690
+ exports.useAbilityStatus = useAbilityStatus;
9461
9691
  exports.useAppForm = useAppForm;
9462
9692
  exports.useCan = useCan;
9463
9693
  exports.useCarousel = useCarousel;