@arbidocs/react 0.5.123 → 0.5.125

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.
@@ -3,6 +3,8 @@ import { forwardRef } from "react";
3
3
  import { MoreVertical } from "lucide-react";
4
4
  import { cn } from "../lib/utils.js";
5
5
  import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip.js";
6
+ const PILL_TOUCH_HIT = "pointer-coarse:after:absolute pointer-coarse:after:left-1/2 pointer-coarse:after:top-1/2 pointer-coarse:after:h-11 pointer-coarse:after:w-[max(100%,2.75rem)] pointer-coarse:after:-translate-x-1/2 pointer-coarse:after:-translate-y-1/2 pointer-coarse:after:content-['']";
7
+ const MAIN_AREA_TOUCH_HIT = "relative pointer-coarse:after:absolute pointer-coarse:after:inset-x-0 pointer-coarse:after:top-1/2 pointer-coarse:after:h-11 pointer-coarse:after:-translate-y-1/2 pointer-coarse:after:content-['']";
6
8
  const EntityPill = forwardRef(function EntityPill2({
7
9
  icon,
8
10
  label,
@@ -21,6 +23,7 @@ const EntityPill = forwardRef(function EntityPill2({
21
23
  moreContent,
22
24
  href,
23
25
  disabled = false,
26
+ pressed,
24
27
  tooltipContent,
25
28
  "data-testid": testId
26
29
  }, ref) {
@@ -36,7 +39,7 @@ const EntityPill = forwardRef(function EntityPill2({
36
39
  "transition-colors",
37
40
  className
38
41
  );
39
- const interactiveClasses = "relative cursor-pointer hover:bg-muted pointer-coarse:after:absolute pointer-coarse:after:inset-x-0 pointer-coarse:after:-inset-y-3 pointer-coarse:after:content-['']";
42
+ const interactiveClasses = cn("relative cursor-pointer hover:bg-muted", PILL_TOUCH_HIT);
40
43
  const disabledClasses = "cursor-default opacity-60";
41
44
  const highlightClasses = "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground";
42
45
  const mainContent = /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -82,7 +85,7 @@ const EntityPill = forwardRef(function EntityPill2({
82
85
  const mainAreaClass = cn("inline-flex items-center gap-1", fullWidth && "min-w-0 flex-1");
83
86
  const mainAreaTouchClass = cn(
84
87
  mainAreaClass,
85
- (onClick || href) && !disabled && "relative pointer-coarse:after:absolute pointer-coarse:after:inset-x-0 pointer-coarse:after:-inset-y-3 pointer-coarse:after:content-['']"
88
+ (onClick || href) && !disabled && MAIN_AREA_TOUCH_HIT
86
89
  );
87
90
  if (onMoreClick || moreContent) {
88
91
  let mainArea;
@@ -95,7 +98,8 @@ const EntityPill = forwardRef(function EntityPill2({
95
98
  {
96
99
  type: "button",
97
100
  onClick: href ? onClick : disabled ? void 0 : onClick,
98
- disabled: disabled || void 0
101
+ disabled: disabled || void 0,
102
+ "aria-pressed": href ? void 0 : pressed
99
103
  }
100
104
  );
101
105
  } else if (href) {
@@ -117,8 +121,10 @@ const EntityPill = forwardRef(function EntityPill2({
117
121
  type: "button",
118
122
  onClick: disabled ? void 0 : onClick,
119
123
  disabled,
124
+ "aria-pressed": pressed,
120
125
  className: cn(
121
- "relative inline-flex items-center gap-1 pointer-coarse:after:absolute pointer-coarse:after:inset-x-0 pointer-coarse:after:-inset-y-3 pointer-coarse:after:content-['']",
126
+ "inline-flex items-center gap-1",
127
+ MAIN_AREA_TOUCH_HIT,
122
128
  disabled && "opacity-60"
123
129
  ),
124
130
  children: mainContent
@@ -193,6 +199,7 @@ const EntityPill = forwardRef(function EntityPill2({
193
199
  ref,
194
200
  onClick: onClick && !disabled ? onClick : void 0,
195
201
  disabled: disabled || void 0,
202
+ "aria-pressed": pressed,
196
203
  "data-testid": testId,
197
204
  style
198
205
  }
@@ -222,6 +229,7 @@ const EntityPill = forwardRef(function EntityPill2({
222
229
  type: "button",
223
230
  onClick: disabled ? void 0 : onClick,
224
231
  disabled,
232
+ "aria-pressed": pressed,
225
233
  className: cn(
226
234
  baseClasses,
227
235
  disabled ? disabledClasses : interactiveClasses,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/entities/EntityPill.tsx"],
4
- "sourcesContent": ["/**\n * EntityPill Component\n *\n * Base component for pill-style entity displays. Provides consistent styling and\n * interaction patterns. At rest it is plain icon + text (no fill, no border); the\n * fill appears on hover, so a row of entities does not read as a row of buttons. Promoted verbatim from the ARBI app (import paths only\n * changed to resolve within the SDK).\n *\n * Pattern: [Icon] [Label] [Optional: secondary text] [MoreVertical when interactive]\n */\n\nimport React, { forwardRef } from 'react'\nimport { MoreVertical } from 'lucide-react'\nimport { cn } from '../lib/utils'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip'\n\n/**\n * The one size scale of the entity pills and avatars (`UserEntity`, `TagEntity`, `EntityPill`,\n * `DocumentEntity`, the call tiles...). Each takes the steps it draws: the pill itself has two,\n * `sm` for compact rows and `md` for a primary column or a tab header.\n */\nexport type EntitySize = 'xs' | 'sm' | 'md' | 'lg'\n\ninterface EntityPillProps {\n /** The icon element (Avatar, ShieldIcon, FileIcon, etc.) */\n icon: React.ReactNode\n /** Primary label text */\n label: string\n /** Optional secondary text (e.g., page notation \"p.1\") */\n secondaryText?: React.ReactNode\n\n // Styling\n /** `sm` (default) for compact rows, `md` for a primary column or a tab header. */\n size?: Extract<EntitySize, 'sm' | 'md'>\n /** Shape variant: 'pill' for rounded-full, 'rounded' for rounded-md */\n shape?: 'pill' | 'rounded'\n /** Additional CSS classes */\n className?: string\n style?: React.CSSProperties\n /** Max width for label truncation */\n labelMaxWidth?: string\n /** Extra classes on the label text (e.g. a heavier weight on a card face). */\n labelClassName?: string\n /** When true, the pill fills its container width (`flex w-full`) and the main\n * area flexes + truncates so the trailing control (\u22EF menu) pins to the right\n * edge \u2014 used by the documents table's Document column. Default: shrink-to-fit. */\n fullWidth?: boolean\n /** When true, render the pill with the active/\"viewing\" highlight \u2014 a solid\n * dark-navy background with light text, applied LAST so it wins over both the\n * default background and the interactive hover. */\n highlight?: boolean\n\n // Behavior\n /** Click handler for main area (icon + label) - primary action */\n onClick?: (e: React.MouseEvent) => void\n /** Click handler for icon only \u2014 when set, only the icon is clickable (not the label) */\n onIconClick?: (e: React.MouseEvent) => void\n /** Click handler for MoreVertical - opens popover/menu. When provided, shows MoreVertical icon */\n onMoreClick?: (e: React.MouseEvent) => void\n /** Custom trailing element (e.g. a \u22EF dropdown menu). Rendered in the same\n * trailing zone as MoreVertical, but as-is \u2014 so it stays outside the pill's\n * primary click area. Takes precedence over `onMoreClick`. */\n moreContent?: React.ReactNode\n /** Link URL - makes the main area an anchor tag */\n href?: string\n /** Whether the pill is disabled */\n disabled?: boolean\n\n // Tooltip\n /** Tooltip for main area (describes primary action, e.g., \"View document\") */\n tooltipContent?: React.ReactNode\n\n /** Test ID for testing */\n 'data-testid'?: string\n}\n\nexport const EntityPill = forwardRef<HTMLElement, EntityPillProps>(function EntityPill(\n {\n icon,\n label,\n secondaryText,\n size = 'sm',\n shape = 'rounded',\n className,\n style,\n labelMaxWidth = 'max-w-[320px]',\n labelClassName,\n fullWidth = false,\n highlight = false,\n onClick,\n onIconClick,\n onMoreClick,\n moreContent,\n href,\n disabled = false,\n tooltipContent,\n 'data-testid': testId,\n },\n ref\n) {\n const shapeClass = shape === 'pill' ? 'rounded-full' : 'rounded-md'\n\n // Size-based classes\n const sizeClasses = size === 'md' ? 'gap-1.5 px-1.5 py-0.5' : 'gap-1 px-1'\n const textSizeClass = size === 'md' ? 'text-base' : 'text-sm'\n\n const baseClasses = cn(\n 'group/pill items-center',\n fullWidth ? 'flex w-full' : 'inline-flex',\n sizeClasses,\n shapeClass,\n 'border border-transparent',\n 'transition-colors',\n className\n )\n\n // Coarse pointers: an invisible 44px-tall hit area (the pill itself stays compact).\n const interactiveClasses =\n \"relative cursor-pointer hover:bg-muted pointer-coarse:after:absolute pointer-coarse:after:inset-x-0 pointer-coarse:after:-inset-y-3 pointer-coarse:after:content-['']\"\n const disabledClasses = 'cursor-default opacity-60'\n const highlightClasses =\n 'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground'\n\n // Main content (icon + label + secondary text)\n const mainContent = (\n <>\n {onIconClick ? (\n <span\n role=\"button\"\n tabIndex={0}\n className=\"flex-shrink-0 cursor-pointer hover:opacity-70 transition-opacity\"\n onClick={(e) => {\n e.stopPropagation()\n onIconClick(e)\n }}\n >\n {icon}\n </span>\n ) : (\n icon\n )}\n <span\n className={cn(\n textSizeClass,\n 'font-medium truncate leading-tight min-w-0',\n labelMaxWidth,\n labelClassName\n )}\n >\n {label}\n </span>\n {secondaryText && (\n <span className=\"text-xs text-muted-foreground flex-shrink-0 leading-none\">\n {secondaryText}\n </span>\n )}\n </>\n )\n\n // Helper: wrap any content in a Tooltip (no asChild \u2014 TooltipTrigger renders its own button)\n const tooltipWrap = (\n content: React.ReactNode,\n tip: React.ReactNode,\n side: 'top' | 'bottom' | 'left' | 'right' = 'bottom',\n triggerClassName?: string,\n triggerProps?: Record<string, unknown>\n ) => (\n <Tooltip>\n <TooltipTrigger\n onFocusCapture={(e) => e.stopPropagation()}\n className={triggerClassName}\n {...triggerProps}\n >\n {content}\n </TooltipTrigger>\n <TooltipContent side={side} className=\"p-2\">\n {tip}\n </TooltipContent>\n </Tooltip>\n )\n\n // With a separate \"more\" control the touch hit area must grow on the MAIN area only: an overlay on\n // the whole pill would sit above both inner buttons and swallow their taps.\n const mainAreaClass = cn('inline-flex items-center gap-1', fullWidth && 'min-w-0 flex-1')\n const mainAreaTouchClass = cn(\n mainAreaClass,\n (onClick || href) &&\n !disabled &&\n \"relative pointer-coarse:after:absolute pointer-coarse:after:inset-x-0 pointer-coarse:after:-inset-y-3 pointer-coarse:after:content-['']\"\n )\n\n if (onMoreClick || moreContent) {\n let mainArea: React.ReactNode\n if (tooltipContent) {\n mainArea = tooltipWrap(\n mainContent,\n tooltipContent,\n 'bottom',\n cn(mainAreaTouchClass, disabled && 'opacity-60'),\n {\n type: 'button',\n onClick: href ? onClick : disabled ? undefined : onClick,\n disabled: disabled || undefined,\n }\n )\n } else if (href) {\n mainArea = (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={mainAreaTouchClass}\n onClick={onClick}\n >\n {mainContent}\n </a>\n )\n } else if (onClick) {\n mainArea = (\n <button\n type=\"button\"\n onClick={disabled ? undefined : onClick}\n disabled={disabled}\n className={cn(\n \"relative inline-flex items-center gap-1 pointer-coarse:after:absolute pointer-coarse:after:inset-x-0 pointer-coarse:after:-inset-y-3 pointer-coarse:after:content-['']\",\n disabled && 'opacity-60'\n )}\n >\n {mainContent}\n </button>\n )\n } else {\n mainArea = <span className={mainAreaTouchClass}>{mainContent}</span>\n }\n\n const moreArea = moreContent ? (\n <span className=\"flex-shrink-0 leading-none\">{moreContent}</span>\n ) : (\n tooltipWrap(\n <MoreVertical className=\"w-3.5 h-3.5\" />,\n 'Click for more',\n 'bottom',\n 'flex-shrink-0 leading-none text-muted-foreground hover:text-foreground',\n {\n type: 'button',\n onClick: (e: React.MouseEvent<HTMLButtonElement>) => {\n e.stopPropagation()\n onMoreClick?.(e)\n },\n }\n )\n )\n\n return (\n <span\n ref={ref as React.Ref<HTMLSpanElement>}\n className={cn(\n baseClasses,\n (onClick || href) && !disabled && 'cursor-pointer hover:bg-muted',\n highlight && highlightClasses\n )}\n style={style}\n data-testid={testId}\n >\n {mainArea}\n {moreArea}\n </span>\n )\n }\n\n if (tooltipContent) {\n if (href) {\n return tooltipWrap(\n <a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={mainAreaClass}\n onClick={onClick}\n >\n {mainContent}\n </a>,\n tooltipContent,\n 'bottom',\n cn(baseClasses, interactiveClasses),\n { 'data-testid': testId, style }\n )\n }\n\n return tooltipWrap(\n mainContent,\n tooltipContent,\n 'bottom',\n cn(\n baseClasses,\n onClick && !disabled ? interactiveClasses : '',\n disabled ? disabledClasses : '',\n highlight && highlightClasses\n ),\n {\n type: 'button',\n ref: ref as React.Ref<HTMLButtonElement>,\n onClick: onClick && !disabled ? onClick : undefined,\n disabled: disabled || undefined,\n 'data-testid': testId,\n style,\n }\n )\n }\n\n if (href) {\n return (\n <a\n ref={ref as React.Ref<HTMLAnchorElement>}\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={cn(baseClasses, interactiveClasses)}\n style={style}\n data-testid={testId}\n onClick={onClick}\n >\n {mainContent}\n </a>\n )\n }\n\n if (onClick) {\n return (\n <button\n ref={ref as React.Ref<HTMLButtonElement>}\n type=\"button\"\n onClick={disabled ? undefined : onClick}\n disabled={disabled}\n className={cn(\n baseClasses,\n disabled ? disabledClasses : interactiveClasses,\n highlight && highlightClasses\n )}\n style={style}\n data-testid={testId}\n >\n {mainContent}\n </button>\n )\n }\n\n return (\n <span\n ref={ref as React.Ref<HTMLSpanElement>}\n className={cn(baseClasses, highlight && highlightClasses)}\n style={style}\n data-testid={testId}\n >\n {mainContent}\n </span>\n )\n})\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * EntityPill Component\n *\n * Base component for pill-style entity displays. Provides consistent styling and\n * interaction patterns. At rest it is plain icon + text (no fill, no border); the\n * fill appears on hover, so a row of entities does not read as a row of buttons. Promoted verbatim from the ARBI app (import paths only\n * changed to resolve within the SDK).\n *\n * Pattern: [Icon] [Label] [Optional: secondary text] [MoreVertical when interactive]\n */\n\nimport React, { forwardRef } from 'react'\nimport { MoreVertical } from 'lucide-react'\nimport { cn } from '../lib/utils'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip'\n\n/**\n * The one size scale of the entity pills and avatars (`UserEntity`, `TagEntity`, `EntityPill`,\n * `DocumentEntity`, the call tiles...). Each takes the steps it draws: the pill itself has two,\n * `sm` for compact rows and `md` for a primary column or a tab header.\n */\nexport type EntitySize = 'xs' | 'sm' | 'md' | 'lg'\n\ninterface EntityPillProps {\n /** The icon element (Avatar, ShieldIcon, FileIcon, etc.) */\n icon: React.ReactNode\n /** Primary label text */\n label: string\n /** Optional secondary text (e.g., page notation \"p.1\") */\n secondaryText?: React.ReactNode\n\n // Styling\n /** `sm` (default) for compact rows, `md` for a primary column or a tab header. */\n size?: Extract<EntitySize, 'sm' | 'md'>\n /** Shape variant: 'pill' for rounded-full, 'rounded' for rounded-md */\n shape?: 'pill' | 'rounded'\n /** Additional CSS classes */\n className?: string\n style?: React.CSSProperties\n /** Max width for label truncation */\n labelMaxWidth?: string\n /** Extra classes on the label text (e.g. a heavier weight on a card face). */\n labelClassName?: string\n /** When true, the pill fills its container width (`flex w-full`) and the main\n * area flexes + truncates so the trailing control (\u22EF menu) pins to the right\n * edge \u2014 used by the documents table's Document column. Default: shrink-to-fit. */\n fullWidth?: boolean\n /** When true, render the pill with the active/\"viewing\" highlight \u2014 a solid\n * dark-navy background with light text, applied LAST so it wins over both the\n * default background and the interactive hover. */\n highlight?: boolean\n\n // Behavior\n /** Click handler for main area (icon + label) - primary action */\n onClick?: (e: React.MouseEvent) => void\n /** Click handler for icon only \u2014 when set, only the icon is clickable (not the label) */\n onIconClick?: (e: React.MouseEvent) => void\n /** Click handler for MoreVertical - opens popover/menu. When provided, shows MoreVertical icon */\n onMoreClick?: (e: React.MouseEvent) => void\n /** Custom trailing element (e.g. a \u22EF dropdown menu). Rendered in the same\n * trailing zone as MoreVertical, but as-is \u2014 so it stays outside the pill's\n * primary click area. Takes precedence over `onMoreClick`. */\n moreContent?: React.ReactNode\n /** Link URL - makes the main area an anchor tag */\n href?: string\n /** Whether the pill is disabled */\n disabled?: boolean\n /** For a pill that toggles a state on click: that state, exposed as `aria-pressed`. */\n pressed?: boolean\n\n // Tooltip\n /** Tooltip for main area (describes primary action, e.g., \"View document\") */\n tooltipContent?: React.ReactNode\n\n /** Test ID for testing */\n 'data-testid'?: string\n}\n\n/** Coarse pointers: a 44x44 (or wider, as wide as the pill) hit area centred on the pill. */\nconst PILL_TOUCH_HIT =\n \"pointer-coarse:after:absolute pointer-coarse:after:left-1/2 pointer-coarse:after:top-1/2 pointer-coarse:after:h-11 pointer-coarse:after:w-[max(100%,2.75rem)] pointer-coarse:after:-translate-x-1/2 pointer-coarse:after:-translate-y-1/2 pointer-coarse:after:content-['']\"\n\n/**\n * The main area of a pill with a separate \"more\" control: 44px tall but only as wide as the area,\n * so it never reaches over the \"more\" control and swallows its taps.\n */\nconst MAIN_AREA_TOUCH_HIT =\n \"relative pointer-coarse:after:absolute pointer-coarse:after:inset-x-0 pointer-coarse:after:top-1/2 pointer-coarse:after:h-11 pointer-coarse:after:-translate-y-1/2 pointer-coarse:after:content-['']\"\n\nexport const EntityPill = forwardRef<HTMLElement, EntityPillProps>(function EntityPill(\n {\n icon,\n label,\n secondaryText,\n size = 'sm',\n shape = 'rounded',\n className,\n style,\n labelMaxWidth = 'max-w-[320px]',\n labelClassName,\n fullWidth = false,\n highlight = false,\n onClick,\n onIconClick,\n onMoreClick,\n moreContent,\n href,\n disabled = false,\n pressed,\n tooltipContent,\n 'data-testid': testId,\n },\n ref\n) {\n const shapeClass = shape === 'pill' ? 'rounded-full' : 'rounded-md'\n\n // Size-based classes\n const sizeClasses = size === 'md' ? 'gap-1.5 px-1.5 py-0.5' : 'gap-1 px-1'\n const textSizeClass = size === 'md' ? 'text-base' : 'text-sm'\n\n const baseClasses = cn(\n 'group/pill items-center',\n fullWidth ? 'flex w-full' : 'inline-flex',\n sizeClasses,\n shapeClass,\n 'border border-transparent',\n 'transition-colors',\n className\n )\n\n // Coarse pointers: an invisible hit area of at least 44x44 centred on the pill (the pill itself\n // stays compact). Centred and sized, not inset: an absolute box is laid out against the padding\n // box, so `-inset-y-3` on a bordered 20px pill gave 42px, and an icon-only pill stayed 22px wide.\n const interactiveClasses = cn('relative cursor-pointer hover:bg-muted', PILL_TOUCH_HIT)\n const disabledClasses = 'cursor-default opacity-60'\n const highlightClasses =\n 'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground'\n\n // Main content (icon + label + secondary text)\n const mainContent = (\n <>\n {onIconClick ? (\n <span\n role=\"button\"\n tabIndex={0}\n className=\"flex-shrink-0 cursor-pointer hover:opacity-70 transition-opacity\"\n onClick={(e) => {\n e.stopPropagation()\n onIconClick(e)\n }}\n >\n {icon}\n </span>\n ) : (\n icon\n )}\n <span\n className={cn(\n textSizeClass,\n 'font-medium truncate leading-tight min-w-0',\n labelMaxWidth,\n labelClassName\n )}\n >\n {label}\n </span>\n {secondaryText && (\n <span className=\"text-xs text-muted-foreground flex-shrink-0 leading-none\">\n {secondaryText}\n </span>\n )}\n </>\n )\n\n // Helper: wrap any content in a Tooltip (no asChild \u2014 TooltipTrigger renders its own button)\n const tooltipWrap = (\n content: React.ReactNode,\n tip: React.ReactNode,\n side: 'top' | 'bottom' | 'left' | 'right' = 'bottom',\n triggerClassName?: string,\n triggerProps?: Record<string, unknown>\n ) => (\n <Tooltip>\n <TooltipTrigger\n onFocusCapture={(e) => e.stopPropagation()}\n className={triggerClassName}\n {...triggerProps}\n >\n {content}\n </TooltipTrigger>\n <TooltipContent side={side} className=\"p-2\">\n {tip}\n </TooltipContent>\n </Tooltip>\n )\n\n // With a separate \"more\" control the touch hit area must grow on the MAIN area only: an overlay on\n // the whole pill would sit above both inner buttons and swallow their taps.\n const mainAreaClass = cn('inline-flex items-center gap-1', fullWidth && 'min-w-0 flex-1')\n const mainAreaTouchClass = cn(\n mainAreaClass,\n (onClick || href) && !disabled && MAIN_AREA_TOUCH_HIT\n )\n\n if (onMoreClick || moreContent) {\n let mainArea: React.ReactNode\n if (tooltipContent) {\n mainArea = tooltipWrap(\n mainContent,\n tooltipContent,\n 'bottom',\n cn(mainAreaTouchClass, disabled && 'opacity-60'),\n {\n type: 'button',\n onClick: href ? onClick : disabled ? undefined : onClick,\n disabled: disabled || undefined,\n 'aria-pressed': href ? undefined : pressed,\n }\n )\n } else if (href) {\n mainArea = (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={mainAreaTouchClass}\n onClick={onClick}\n >\n {mainContent}\n </a>\n )\n } else if (onClick) {\n mainArea = (\n <button\n type=\"button\"\n onClick={disabled ? undefined : onClick}\n disabled={disabled}\n aria-pressed={pressed}\n className={cn(\n 'inline-flex items-center gap-1',\n MAIN_AREA_TOUCH_HIT,\n disabled && 'opacity-60'\n )}\n >\n {mainContent}\n </button>\n )\n } else {\n mainArea = <span className={mainAreaTouchClass}>{mainContent}</span>\n }\n\n const moreArea = moreContent ? (\n <span className=\"flex-shrink-0 leading-none\">{moreContent}</span>\n ) : (\n tooltipWrap(\n <MoreVertical className=\"w-3.5 h-3.5\" />,\n 'Click for more',\n 'bottom',\n 'flex-shrink-0 leading-none text-muted-foreground hover:text-foreground',\n {\n type: 'button',\n onClick: (e: React.MouseEvent<HTMLButtonElement>) => {\n e.stopPropagation()\n onMoreClick?.(e)\n },\n }\n )\n )\n\n return (\n <span\n ref={ref as React.Ref<HTMLSpanElement>}\n className={cn(\n baseClasses,\n (onClick || href) && !disabled && 'cursor-pointer hover:bg-muted',\n highlight && highlightClasses\n )}\n style={style}\n data-testid={testId}\n >\n {mainArea}\n {moreArea}\n </span>\n )\n }\n\n if (tooltipContent) {\n if (href) {\n return tooltipWrap(\n <a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={mainAreaClass}\n onClick={onClick}\n >\n {mainContent}\n </a>,\n tooltipContent,\n 'bottom',\n cn(baseClasses, interactiveClasses),\n { 'data-testid': testId, style }\n )\n }\n\n return tooltipWrap(\n mainContent,\n tooltipContent,\n 'bottom',\n cn(\n baseClasses,\n onClick && !disabled ? interactiveClasses : '',\n disabled ? disabledClasses : '',\n highlight && highlightClasses\n ),\n {\n type: 'button',\n ref: ref as React.Ref<HTMLButtonElement>,\n onClick: onClick && !disabled ? onClick : undefined,\n disabled: disabled || undefined,\n 'aria-pressed': pressed,\n 'data-testid': testId,\n style,\n }\n )\n }\n\n if (href) {\n return (\n <a\n ref={ref as React.Ref<HTMLAnchorElement>}\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={cn(baseClasses, interactiveClasses)}\n style={style}\n data-testid={testId}\n onClick={onClick}\n >\n {mainContent}\n </a>\n )\n }\n\n if (onClick) {\n return (\n <button\n ref={ref as React.Ref<HTMLButtonElement>}\n type=\"button\"\n onClick={disabled ? undefined : onClick}\n disabled={disabled}\n aria-pressed={pressed}\n className={cn(\n baseClasses,\n disabled ? disabledClasses : interactiveClasses,\n highlight && highlightClasses\n )}\n style={style}\n data-testid={testId}\n >\n {mainContent}\n </button>\n )\n }\n\n return (\n <span\n ref={ref as React.Ref<HTMLSpanElement>}\n className={cn(baseClasses, highlight && highlightClasses)}\n style={style}\n data-testid={testId}\n >\n {mainContent}\n </span>\n )\n})\n"],
5
+ "mappings": "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",
6
6
  "names": ["EntityPill"]
7
7
  }
@@ -46,6 +46,7 @@ function SharingEntity({
46
46
  labelClassName: cn(variant === "icon" && "sr-only", !shared && "text-muted-foreground"),
47
47
  className: cn(shared && "text-primary", className),
48
48
  onClick: handleClick,
49
+ pressed: onToggle ? shared : void 0,
49
50
  tooltipContent: !shared && hint ? hint : void 0,
50
51
  "data-testid": testId
51
52
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/entities/SharingEntity.tsx"],
4
- "sourcesContent": ["/**\n * SharingEntity\n *\n * The entity pill of who can see an item: \"Only me\" (one person) or \"Workspace\" (several people).\n * It is the one pill every sharing indicator uses, in two variants: `full` (icon + label) and `icon`\n * (the glyph alone, for a narrow cell or a header; the label stays as its accessible name).\n *\n * The \"Workspace\" pill owns its hover: a card (opened by hover, keyboard focus, or a tap on a touch\n * screen) with `members`, the workspace's member list. `members` is only mounted while the card is\n * open, so a data-reading list costs nothing until someone looks. \"Only me\" has no card.\n *\n * With `onToggle` a click flips the visibility (a tap on a touch screen opens the card instead, so\n * a stray tap never changes who can see an item); without, the pill is a plain indicator. A click never reaches a parent's\n * handler (a row or card selection).\n */\n\nimport { useRef, useState, type MouseEvent, type PointerEvent, type ReactNode } from 'react'\nimport { User, Users } from 'lucide-react'\nimport { cn } from '../lib/utils'\nimport { HoverCard, HoverCardContent, HoverCardTrigger } from '../ui/hover-card'\nimport { EntityPill } from './EntityPill'\n\nlet sharedMembers: ReactNode = null\n\n/**\n * Where every `SharingEntity` finds the member list of its card (the entity registry's seam: the\n * connected layer, which can read the workspace's members, registers it once; panels that portal\n * outside any one subtree still get it).\n */\nexport function configureSharingMembers(members: ReactNode): void {\n sharedMembers = members\n}\n\nexport const SHARING_LABELS = { onlyMe: 'Only me', workspace: 'Workspace' } as const\n\nexport interface SharingEntityProps {\n shared: boolean\n /** `full` (default) icon + label; `icon` the glyph alone. */\n variant?: 'full' | 'icon'\n size?: 'sm' | 'md'\n /** Called with true to share, false to make private. Omit for an indicator that is not clickable. */\n onToggle?: (shouldShare: boolean) => void\n disabled?: boolean\n /** Why the visibility cannot be changed (a line in the card, or the tooltip). */\n disabledTooltip?: string\n /** What a click does while shared / private. */\n tooltipActive?: string\n tooltipInactive?: string\n /** The member list of the Workspace card (default: the registered one, `configureSharingMembers`); mounted only while the card is open. */\n members?: ReactNode\n className?: string\n 'data-testid'?: string\n}\n\nexport function SharingEntity({\n shared,\n variant = 'full',\n size = 'sm',\n onToggle,\n disabled = false,\n disabledTooltip,\n tooltipActive,\n tooltipInactive,\n members: membersProp,\n className,\n 'data-testid': testId,\n}: SharingEntityProps) {\n const members = membersProp ?? sharedMembers\n const [open, setOpen] = useState(false)\n const lastPointer = useRef<string>('mouse')\n const canToggle = !!onToggle && !disabled\n const label = shared ? SHARING_LABELS.workspace : SHARING_LABELS.onlyMe\n const hint = disabled ? disabledTooltip : shared ? tooltipActive : tooltipInactive\n\n const handleClick = (e: MouseEvent) => {\n e.stopPropagation()\n // A touch screen has no hover: a tap on a Workspace pill shows who is in it (and never flips it).\n if (shared && lastPointer.current === 'touch') {\n setOpen(true)\n return\n }\n if (canToggle) onToggle(!shared)\n }\n\n const pill = (\n <EntityPill\n shape=\"pill\"\n size={size}\n icon={\n shared ? (\n <Users className=\"size-3.5 shrink-0 text-primary\" aria-hidden />\n ) : (\n <User className=\"size-3.5 shrink-0 text-muted-foreground\" aria-hidden />\n )\n }\n label={label}\n labelClassName={cn(variant === 'icon' && 'sr-only', !shared && 'text-muted-foreground')}\n className={cn(shared && 'text-primary', className)}\n onClick={handleClick}\n tooltipContent={!shared && hint ? hint : undefined}\n data-testid={testId}\n />\n )\n\n if (!shared) return pill\n\n return (\n <HoverCard open={open} onOpenChange={setOpen} openDelay={200} closeDelay={100}>\n <HoverCardTrigger\n asChild\n onPointerDown={(e: PointerEvent) => {\n lastPointer.current = e.pointerType\n }}\n >\n <span\n className=\"inline-flex\"\n role=\"group\"\n aria-label={`${SHARING_LABELS.workspace}: shared with all workspace members`}\n >\n {pill}\n </span>\n </HoverCardTrigger>\n {open && (\n <HoverCardContent side=\"left\" align=\"center\" className=\"w-60 space-y-2 p-3\">\n <p className=\"text-xs font-semibold\">Workspace members</p>\n {members}\n {hint && <p className=\"border-t pt-2 text-xs text-muted-foreground\">{hint}</p>}\n </HoverCardContent>\n )}\n </HoverCard>\n )\n}\n"],
5
- "mappings": "AA0FU,cAiCF,YAjCE;AA1EV,SAAS,QAAQ,gBAAoE;AACrF,SAAS,MAAM,aAAa;AAC5B,SAAS,UAAU;AACnB,SAAS,WAAW,kBAAkB,wBAAwB;AAC9D,SAAS,kBAAkB;AAE3B,IAAI,gBAA2B;AAOxB,SAAS,wBAAwB,SAA0B;AAChE,kBAAgB;AAClB;AAEO,MAAM,iBAAiB,EAAE,QAAQ,WAAW,WAAW,YAAY;AAqBnE,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA,UAAU;AAAA,EACV,OAAO;AAAA,EACP;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT;AAAA,EACA,eAAe;AACjB,GAAuB;AACrB,QAAM,UAAU,eAAe;AAC/B,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,cAAc,OAAe,OAAO;AAC1C,QAAM,YAAY,CAAC,CAAC,YAAY,CAAC;AACjC,QAAM,QAAQ,SAAS,eAAe,YAAY,eAAe;AACjE,QAAM,OAAO,WAAW,kBAAkB,SAAS,gBAAgB;AAEnE,QAAM,cAAc,CAAC,MAAkB;AACrC,MAAE,gBAAgB;AAElB,QAAI,UAAU,YAAY,YAAY,SAAS;AAC7C,cAAQ,IAAI;AACZ;AAAA,IACF;AACA,QAAI,UAAW,UAAS,CAAC,MAAM;AAAA,EACjC;AAEA,QAAM,OACJ;AAAA,IAAC;AAAA;AAAA,MACC,OAAM;AAAA,MACN;AAAA,MACA,MACE,SACE,oBAAC,SAAM,WAAU,kCAAiC,eAAW,MAAC,IAE9D,oBAAC,QAAK,WAAU,2CAA0C,eAAW,MAAC;AAAA,MAG1E;AAAA,MACA,gBAAgB,GAAG,YAAY,UAAU,WAAW,CAAC,UAAU,uBAAuB;AAAA,MACtF,WAAW,GAAG,UAAU,gBAAgB,SAAS;AAAA,MACjD,SAAS;AAAA,MACT,gBAAgB,CAAC,UAAU,OAAO,OAAO;AAAA,MACzC,eAAa;AAAA;AAAA,EACf;AAGF,MAAI,CAAC,OAAQ,QAAO;AAEpB,SACE,qBAAC,aAAU,MAAY,cAAc,SAAS,WAAW,KAAK,YAAY,KACxE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,SAAO;AAAA,QACP,eAAe,CAAC,MAAoB;AAClC,sBAAY,UAAU,EAAE;AAAA,QAC1B;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,MAAK;AAAA,YACL,cAAY,GAAG,eAAe,SAAS;AAAA,YAEtC;AAAA;AAAA,QACH;AAAA;AAAA,IACF;AAAA,IACC,QACC,qBAAC,oBAAiB,MAAK,QAAO,OAAM,UAAS,WAAU,sBACrD;AAAA,0BAAC,OAAE,WAAU,yBAAwB,+BAAiB;AAAA,MACrD;AAAA,MACA,QAAQ,oBAAC,OAAE,WAAU,+CAA+C,gBAAK;AAAA,OAC5E;AAAA,KAEJ;AAEJ;",
4
+ "sourcesContent": ["/**\n * SharingEntity\n *\n * The entity pill of who can see an item: \"Only me\" (one person) or \"Workspace\" (several people).\n * It is the one pill every sharing indicator uses, in two variants: `full` (icon + label) and `icon`\n * (the glyph alone, for a narrow cell or a header; the label stays as its accessible name).\n *\n * The \"Workspace\" pill owns its hover: a card (opened by hover, keyboard focus, or a tap on a touch\n * screen) with `members`, the workspace's member list. `members` is only mounted while the card is\n * open, so a data-reading list costs nothing until someone looks. \"Only me\" has no card.\n *\n * With `onToggle` a click flips the visibility (a tap on a touch screen opens the card instead, so\n * a stray tap never changes who can see an item) and the pill is a toggle button, `aria-pressed`\n * while shared; without, the pill is a plain indicator. A click never reaches a parent's handler\n * (a row or card selection).\n */\n\nimport { useRef, useState, type MouseEvent, type PointerEvent, type ReactNode } from 'react'\nimport { User, Users } from 'lucide-react'\nimport { cn } from '../lib/utils'\nimport { HoverCard, HoverCardContent, HoverCardTrigger } from '../ui/hover-card'\nimport { EntityPill } from './EntityPill'\n\nlet sharedMembers: ReactNode = null\n\n/**\n * Where every `SharingEntity` finds the member list of its card (the entity registry's seam: the\n * connected layer, which can read the workspace's members, registers it once; panels that portal\n * outside any one subtree still get it).\n */\nexport function configureSharingMembers(members: ReactNode): void {\n sharedMembers = members\n}\n\nexport const SHARING_LABELS = { onlyMe: 'Only me', workspace: 'Workspace' } as const\n\nexport interface SharingEntityProps {\n shared: boolean\n /** `full` (default) icon + label; `icon` the glyph alone. */\n variant?: 'full' | 'icon'\n size?: 'sm' | 'md'\n /** Called with true to share, false to make private. Omit for an indicator that is not clickable. */\n onToggle?: (shouldShare: boolean) => void\n disabled?: boolean\n /** Why the visibility cannot be changed (a line in the card, or the tooltip). */\n disabledTooltip?: string\n /** What a click does while shared / private. */\n tooltipActive?: string\n tooltipInactive?: string\n /** The member list of the Workspace card (default: the registered one, `configureSharingMembers`); mounted only while the card is open. */\n members?: ReactNode\n className?: string\n 'data-testid'?: string\n}\n\nexport function SharingEntity({\n shared,\n variant = 'full',\n size = 'sm',\n onToggle,\n disabled = false,\n disabledTooltip,\n tooltipActive,\n tooltipInactive,\n members: membersProp,\n className,\n 'data-testid': testId,\n}: SharingEntityProps) {\n const members = membersProp ?? sharedMembers\n const [open, setOpen] = useState(false)\n const lastPointer = useRef<string>('mouse')\n const canToggle = !!onToggle && !disabled\n const label = shared ? SHARING_LABELS.workspace : SHARING_LABELS.onlyMe\n const hint = disabled ? disabledTooltip : shared ? tooltipActive : tooltipInactive\n\n const handleClick = (e: MouseEvent) => {\n e.stopPropagation()\n // A touch screen has no hover: a tap on a Workspace pill shows who is in it (and never flips it).\n if (shared && lastPointer.current === 'touch') {\n setOpen(true)\n return\n }\n if (canToggle) onToggle(!shared)\n }\n\n const pill = (\n <EntityPill\n shape=\"pill\"\n size={size}\n icon={\n shared ? (\n <Users className=\"size-3.5 shrink-0 text-primary\" aria-hidden />\n ) : (\n <User className=\"size-3.5 shrink-0 text-muted-foreground\" aria-hidden />\n )\n }\n label={label}\n labelClassName={cn(variant === 'icon' && 'sr-only', !shared && 'text-muted-foreground')}\n className={cn(shared && 'text-primary', className)}\n onClick={handleClick}\n pressed={onToggle ? shared : undefined}\n tooltipContent={!shared && hint ? hint : undefined}\n data-testid={testId}\n />\n )\n\n if (!shared) return pill\n\n return (\n <HoverCard open={open} onOpenChange={setOpen} openDelay={200} closeDelay={100}>\n <HoverCardTrigger\n asChild\n onPointerDown={(e: PointerEvent) => {\n lastPointer.current = e.pointerType\n }}\n >\n <span\n className=\"inline-flex\"\n role=\"group\"\n aria-label={`${SHARING_LABELS.workspace}: shared with all workspace members`}\n >\n {pill}\n </span>\n </HoverCardTrigger>\n {open && (\n <HoverCardContent side=\"left\" align=\"center\" className=\"w-60 space-y-2 p-3\">\n <p className=\"text-xs font-semibold\">Workspace members</p>\n {members}\n {hint && <p className=\"border-t pt-2 text-xs text-muted-foreground\">{hint}</p>}\n </HoverCardContent>\n )}\n </HoverCard>\n )\n}\n"],
5
+ "mappings": "AA2FU,cAkCF,YAlCE;AA1EV,SAAS,QAAQ,gBAAoE;AACrF,SAAS,MAAM,aAAa;AAC5B,SAAS,UAAU;AACnB,SAAS,WAAW,kBAAkB,wBAAwB;AAC9D,SAAS,kBAAkB;AAE3B,IAAI,gBAA2B;AAOxB,SAAS,wBAAwB,SAA0B;AAChE,kBAAgB;AAClB;AAEO,MAAM,iBAAiB,EAAE,QAAQ,WAAW,WAAW,YAAY;AAqBnE,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA,UAAU;AAAA,EACV,OAAO;AAAA,EACP;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT;AAAA,EACA,eAAe;AACjB,GAAuB;AACrB,QAAM,UAAU,eAAe;AAC/B,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,cAAc,OAAe,OAAO;AAC1C,QAAM,YAAY,CAAC,CAAC,YAAY,CAAC;AACjC,QAAM,QAAQ,SAAS,eAAe,YAAY,eAAe;AACjE,QAAM,OAAO,WAAW,kBAAkB,SAAS,gBAAgB;AAEnE,QAAM,cAAc,CAAC,MAAkB;AACrC,MAAE,gBAAgB;AAElB,QAAI,UAAU,YAAY,YAAY,SAAS;AAC7C,cAAQ,IAAI;AACZ;AAAA,IACF;AACA,QAAI,UAAW,UAAS,CAAC,MAAM;AAAA,EACjC;AAEA,QAAM,OACJ;AAAA,IAAC;AAAA;AAAA,MACC,OAAM;AAAA,MACN;AAAA,MACA,MACE,SACE,oBAAC,SAAM,WAAU,kCAAiC,eAAW,MAAC,IAE9D,oBAAC,QAAK,WAAU,2CAA0C,eAAW,MAAC;AAAA,MAG1E;AAAA,MACA,gBAAgB,GAAG,YAAY,UAAU,WAAW,CAAC,UAAU,uBAAuB;AAAA,MACtF,WAAW,GAAG,UAAU,gBAAgB,SAAS;AAAA,MACjD,SAAS;AAAA,MACT,SAAS,WAAW,SAAS;AAAA,MAC7B,gBAAgB,CAAC,UAAU,OAAO,OAAO;AAAA,MACzC,eAAa;AAAA;AAAA,EACf;AAGF,MAAI,CAAC,OAAQ,QAAO;AAEpB,SACE,qBAAC,aAAU,MAAY,cAAc,SAAS,WAAW,KAAK,YAAY,KACxE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,SAAO;AAAA,QACP,eAAe,CAAC,MAAoB;AAClC,sBAAY,UAAU,EAAE;AAAA,QAC1B;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,MAAK;AAAA,YACL,cAAY,GAAG,eAAe,SAAS;AAAA,YAEtC;AAAA;AAAA,QACH;AAAA;AAAA,IACF;AAAA,IACC,QACC,qBAAC,oBAAiB,MAAK,QAAO,OAAM,UAAS,WAAU,sBACrD;AAAA,0BAAC,OAAE,WAAU,yBAAwB,+BAAiB;AAAA,MACrD;AAAA,MACA,QAAQ,oBAAC,OAAE,WAAU,+CAA+C,gBAAK;AAAA,OAC5E;AAAA,KAEJ;AAEJ;",
6
6
  "names": []
7
7
  }