@ai-matrx/tap-target 0.1.0 → 0.1.1
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/CHANGELOG.md +9 -0
- package/dist/buttons.cjs +22 -8
- package/dist/buttons.cjs.map +1 -1
- package/dist/buttons.js +22 -8
- package/dist/buttons.js.map +1 -1
- package/dist/index.cjs +22 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +22 -8
- package/dist/index.js.map +1 -1
- package/dist/styles.css +35 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -123,17 +123,17 @@ function IconContent({
|
|
|
123
123
|
}
|
|
124
124
|
);
|
|
125
125
|
}
|
|
126
|
-
function resolveTapGeometry(label, size) {
|
|
126
|
+
function resolveTapGeometry(label, size, mobileIconOnly) {
|
|
127
127
|
const inline = Boolean(label);
|
|
128
128
|
if (size === "sm") {
|
|
129
129
|
return {
|
|
130
|
-
outerClassName: inline ? "matrx-tap-target matrx-tap-target-sm matrx-tap-target-inline-sm group" : TAP_GROUP_OUTER_CLASS,
|
|
131
|
-
inlineModifier: "matrx-tap-pill-inline-sm"
|
|
130
|
+
outerClassName: inline && mobileIconOnly ? "matrx-tap-target matrx-tap-target-sm matrx-tap-target-mobile-icon-only-sm group" : inline ? "matrx-tap-target matrx-tap-target-sm matrx-tap-target-inline-sm group" : TAP_GROUP_OUTER_CLASS,
|
|
131
|
+
inlineModifier: mobileIconOnly ? "matrx-tap-pill-mobile-icon-only-sm" : "matrx-tap-pill-inline-sm"
|
|
132
132
|
};
|
|
133
133
|
}
|
|
134
134
|
return {
|
|
135
|
-
outerClassName: inline ? `${TAP_OUTER_CLASS} matrx-tap-target-inline` : TAP_OUTER_CLASS,
|
|
136
|
-
inlineModifier: "matrx-tap-pill-inline"
|
|
135
|
+
outerClassName: inline && mobileIconOnly ? `${TAP_OUTER_CLASS} matrx-tap-target-mobile-icon-only` : inline ? `${TAP_OUTER_CLASS} matrx-tap-target-inline` : TAP_OUTER_CLASS,
|
|
136
|
+
inlineModifier: mobileIconOnly ? "matrx-tap-pill-mobile-icon-only" : "matrx-tap-pill-inline"
|
|
137
137
|
};
|
|
138
138
|
}
|
|
139
139
|
function buildTapInner({
|
|
@@ -173,6 +173,7 @@ function renderTapTarget({
|
|
|
173
173
|
children,
|
|
174
174
|
strokeWidth,
|
|
175
175
|
label,
|
|
176
|
+
mobileIconOnly = false,
|
|
176
177
|
onClick,
|
|
177
178
|
as,
|
|
178
179
|
htmlFor,
|
|
@@ -189,19 +190,24 @@ function renderTapTarget({
|
|
|
189
190
|
rest,
|
|
190
191
|
buttonRef
|
|
191
192
|
}) {
|
|
192
|
-
const { outerClassName, inlineModifier } = resolveTapGeometry(
|
|
193
|
+
const { outerClassName, inlineModifier } = resolveTapGeometry(
|
|
194
|
+
label,
|
|
195
|
+
size,
|
|
196
|
+
mobileIconOnly
|
|
197
|
+
);
|
|
198
|
+
const responsiveLabelClassName = mobileIconOnly ? `${labelClassName ?? "matrx-tap-label"} matrx-tap-label-mobile-icon-only` : labelClassName;
|
|
193
199
|
const inner = buildTapInner({
|
|
194
200
|
label,
|
|
195
201
|
pillClassName,
|
|
196
202
|
iconClassName,
|
|
197
|
-
labelClassName,
|
|
203
|
+
labelClassName: responsiveLabelClassName,
|
|
198
204
|
inlineModifier: label ? inlineModifier : "",
|
|
199
205
|
icon,
|
|
200
206
|
children,
|
|
201
207
|
strokeWidth
|
|
202
208
|
});
|
|
203
209
|
const resolvedTooltip = tooltip !== void 0 ? tooltip : label ? false : void 0;
|
|
204
|
-
const triggerAriaLabel = label ? void 0 : ariaLabel;
|
|
210
|
+
const triggerAriaLabel = label && !mobileIconOnly ? void 0 : ariaLabel ?? label;
|
|
205
211
|
const trigger = renderTrigger({
|
|
206
212
|
href,
|
|
207
213
|
target,
|
|
@@ -359,6 +365,7 @@ var TapTargetButton = (0, import_react.forwardRef)(function TapTargetButton2({
|
|
|
359
365
|
tooltipSide,
|
|
360
366
|
tooltipAlign,
|
|
361
367
|
label,
|
|
368
|
+
mobileIconOnly,
|
|
362
369
|
...rest
|
|
363
370
|
}, ref) {
|
|
364
371
|
const color = className ?? "text-foreground";
|
|
@@ -380,6 +387,7 @@ var TapTargetButton = (0, import_react.forwardRef)(function TapTargetButton2({
|
|
|
380
387
|
tooltipSide,
|
|
381
388
|
tooltipAlign,
|
|
382
389
|
label,
|
|
390
|
+
mobileIconOnly,
|
|
383
391
|
pillClassName: "matrx-tap-pill matrx-glass-thin-border",
|
|
384
392
|
iconClassName: `matrx-tap-icon ${color}`,
|
|
385
393
|
rest,
|
|
@@ -405,6 +413,7 @@ var TapTargetButtonTransparent = (0, import_react.forwardRef)(function TapTarget
|
|
|
405
413
|
tooltipSide,
|
|
406
414
|
tooltipAlign,
|
|
407
415
|
label,
|
|
416
|
+
mobileIconOnly,
|
|
408
417
|
...rest
|
|
409
418
|
}, ref) {
|
|
410
419
|
const color = className ?? "text-foreground";
|
|
@@ -426,6 +435,7 @@ var TapTargetButtonTransparent = (0, import_react.forwardRef)(function TapTarget
|
|
|
426
435
|
tooltipSide,
|
|
427
436
|
tooltipAlign,
|
|
428
437
|
label,
|
|
438
|
+
mobileIconOnly,
|
|
429
439
|
pillClassName: "matrx-tap-pill hover:bg-muted active:bg-muted-foreground/15",
|
|
430
440
|
iconClassName: `matrx-tap-icon ${color}`,
|
|
431
441
|
rest,
|
|
@@ -454,6 +464,7 @@ var TapTargetButtonSolid = (0, import_react.forwardRef)(function TapTargetButton
|
|
|
454
464
|
tooltipSide,
|
|
455
465
|
tooltipAlign,
|
|
456
466
|
label,
|
|
467
|
+
mobileIconOnly,
|
|
457
468
|
...rest
|
|
458
469
|
}, ref) {
|
|
459
470
|
return renderTapTarget({
|
|
@@ -474,6 +485,7 @@ var TapTargetButtonSolid = (0, import_react.forwardRef)(function TapTargetButton
|
|
|
474
485
|
tooltipSide,
|
|
475
486
|
tooltipAlign,
|
|
476
487
|
label,
|
|
488
|
+
mobileIconOnly,
|
|
477
489
|
pillClassName: `matrx-tap-pill ${bgColor} ${iconColor} ${hoverBgColor} ${activeBgColor}`,
|
|
478
490
|
iconClassName: `matrx-tap-icon ${iconColor}`,
|
|
479
491
|
labelClassName: `matrx-tap-label ${iconColor}`,
|
|
@@ -517,6 +529,7 @@ var TapTargetButtonForGroup = (0, import_react.forwardRef)(function TapTargetBut
|
|
|
517
529
|
tooltipSide,
|
|
518
530
|
tooltipAlign,
|
|
519
531
|
label,
|
|
532
|
+
mobileIconOnly,
|
|
520
533
|
...rest
|
|
521
534
|
}, ref) {
|
|
522
535
|
const color = className ?? "text-foreground";
|
|
@@ -539,6 +552,7 @@ var TapTargetButtonForGroup = (0, import_react.forwardRef)(function TapTargetBut
|
|
|
539
552
|
tooltipSide,
|
|
540
553
|
tooltipAlign,
|
|
541
554
|
label,
|
|
555
|
+
mobileIconOnly,
|
|
542
556
|
pillClassName: "matrx-tap-pill matrx-tap-pill-sm matrx-glass-interactive",
|
|
543
557
|
iconClassName: `matrx-tap-icon ${color}`,
|
|
544
558
|
labelClassName: `matrx-tap-label ${color}`,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/tap-target-button.tsx","../src/tooltip.tsx","../src/cn.ts","../src/link.ts","../src/tap-target-labeled.tsx"],"sourcesContent":["// @ai-matrx/tap-target — primitives entry.\n// The ~60 pre-composed buttons live behind the opt-in \"./buttons\" subpath.\n// The geometry stylesheet ships as \"./styles.css\" — import it once at app root.\n\nexport {\n TapTargetButton,\n TapTargetButtonTransparent,\n TapTargetButtonSolid,\n TapTargetButtonDestructive,\n TapTargetButtonForGroup,\n TapTargetButtonGroup,\n type TapTargetButtonProps,\n type TapTargetButtonSolidProps,\n} from \"./tap-target-button\";\nexport { TapTargetLabeled } from \"./tap-target-labeled\";\nexport {\n setTapTargetLinkComponent,\n getTapTargetLinkComponent,\n type TapTargetLinkComponent,\n type TapTargetLinkProps,\n} from \"./link\";\n// Hosts mount TooltipProvider once near the app root (tooltips on every tap\n// button flow through it); the full tooltip quartet is exported for hosts\n// that do not already have their own Radix tooltip wrapper.\nexport {\n TooltipProvider,\n Tooltip,\n TooltipTrigger,\n TooltipContent,\n} from \"./tooltip\";\n","\"use client\";\n\nimport {\n cloneElement,\n forwardRef,\n isValidElement,\n type ButtonHTMLAttributes,\n type ReactElement,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport { TooltipContent, TooltipTrigger } from \"./tooltip\";\nimport { cn } from \"./cn\";\nimport {\n getTapTargetLinkComponent,\n type TapTargetLinkComponent,\n} from \"./link\";\n\nexport interface TapTargetButtonProps {\n icon?: React.ReactNode;\n children?: React.ReactNode;\n strokeWidth?: number | undefined;\n onClick?: (() => void) | undefined;\n className?: string | undefined;\n as?: \"button\" | \"label\" | undefined;\n htmlFor?: string | undefined;\n ariaLabel?: string | undefined;\n disabled?: boolean | undefined;\n /**\n * When set, the tap button renders as a link instead of a button.\n * - Internal hrefs (e.g. \"/tasks\") render via the injected link component\n * (`setTapTargetLinkComponent` / the `linkComponent` prop), falling back\n * to a plain `<a>` when none is registered.\n * - External hrefs (http://, https://, mailto:, tel:) render as `<a>`\n * with `target=\"_blank\"` and `rel=\"noopener noreferrer\"` by default.\n * - When combined with `disabled`, the trigger renders as a non-navigable\n * `<span aria-disabled=\"true\">` with the same visual styling.\n */\n href?: string | undefined;\n /** Override target. Works on both internal links and external anchors. */\n target?: \"_blank\" | \"_self\" | \"_parent\" | \"_top\" | undefined;\n /** Override rel. Works on both internal links and external anchors. */\n rel?: string | undefined;\n /** Forwarded to the injected link component. Pass `false` to disable prefetching. */\n prefetch?: boolean | null | undefined;\n /**\n * Per-instance link component for internal hrefs — overrides the\n * module-level `setTapTargetLinkComponent` registration.\n */\n linkComponent?: TapTargetLinkComponent | undefined;\n /**\n * Tooltip text. Defaults to `ariaLabel` when omitted.\n * Pass `false` to explicitly disable the tooltip.\n */\n tooltip?: string | false | undefined;\n /** Tooltip placement. Defaults to \"top\". */\n tooltipSide?: \"top\" | \"right\" | \"bottom\" | \"left\" | undefined;\n /** Tooltip alignment along its side. Defaults to \"center\". */\n tooltipAlign?: \"start\" | \"center\" | \"end\" | undefined;\n /**\n * Visible caption rendered inline after the icon (`[icon Label]`).\n * Widens the pill automatically. Tooltip defaults to off when set — the\n * label is self-describing. Visible text becomes the accessible name.\n */\n label?: string | undefined;\n}\n\nexport interface TapTargetButtonSolidProps extends TapTargetButtonProps {\n bgColor?: string | undefined;\n iconColor?: string | undefined;\n hoverBgColor?: string | undefined;\n /**\n * Press-state background. Defaults to `active:brightness-90` which works on\n * any color. Override when using a custom `bgColor` that should darken to a\n * specific shade on press (e.g. `active:bg-primary/60`).\n */\n activeBgColor?: string | undefined;\n}\n\nconst EXTERNAL_RE = /^(https?:|mailto:|tel:)/i;\n\n// Geometry + press feedback + tap hygiene are the SINGLE SOURCE OF TRUTH in\n// the shipped stylesheet (the `.matrx-tap-*` family in styles.css — import\n// \"@ai-matrx/tap-target/styles.css\" once at app root). This component only\n// picks the right class and layers each variant's decoration on top.\nconst TAP_OUTER_CLASS = \"matrx-tap-target group\";\nconst TAP_GROUP_OUTER_CLASS = \"matrx-tap-target matrx-tap-target-sm group\";\n\nfunction IconContent({\n icon,\n children,\n strokeWidth = 2,\n className,\n}: Pick<\n TapTargetButtonProps,\n \"icon\" | \"children\" | \"strokeWidth\" | \"className\"\n>) {\n if (icon) {\n if (isValidElement<{ className?: string }>(icon)) {\n return cloneElement(icon, {\n className: cn(className, icon.props.className),\n });\n }\n return <span className={className}>{icon}</span>;\n }\n return (\n <svg\n className={className}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={strokeWidth}\n >\n {children}\n </svg>\n );\n}\n\ntype TapTargetSize = \"default\" | \"sm\";\n\nfunction resolveTapGeometry(label: string | undefined, size: TapTargetSize) {\n const inline = Boolean(label);\n if (size === \"sm\") {\n return {\n outerClassName: inline\n ? \"matrx-tap-target matrx-tap-target-sm matrx-tap-target-inline-sm group\"\n : TAP_GROUP_OUTER_CLASS,\n inlineModifier: \"matrx-tap-pill-inline-sm\",\n };\n }\n return {\n outerClassName: inline\n ? `${TAP_OUTER_CLASS} matrx-tap-target-inline`\n : TAP_OUTER_CLASS,\n inlineModifier: \"matrx-tap-pill-inline\",\n };\n}\n\nfunction buildTapInner({\n label,\n pillClassName,\n iconClassName,\n labelClassName,\n inlineModifier,\n icon,\n children,\n strokeWidth = 2,\n}: {\n label?: string | undefined;\n pillClassName: string;\n iconClassName: string;\n labelClassName?: string | undefined;\n inlineModifier: string;\n icon?: React.ReactNode;\n children?: React.ReactNode;\n strokeWidth?: number | undefined;\n}) {\n const iconEl = (\n <IconContent\n icon={icon}\n strokeWidth={strokeWidth}\n className={iconClassName}\n >\n {children}\n </IconContent>\n );\n const pillClasses = label\n ? `${pillClassName} ${inlineModifier}`.trim()\n : pillClassName;\n\n if (!label) {\n return <div className={pillClasses}>{iconEl}</div>;\n }\n\n return (\n <div className={pillClasses}>\n {iconEl}\n <span className={labelClassName ?? \"matrx-tap-label\"}>{label}</span>\n </div>\n );\n}\n\ninterface RenderTapTargetArgs extends Pick<\n TapTargetButtonProps,\n | \"icon\"\n | \"children\"\n | \"strokeWidth\"\n | \"label\"\n | \"onClick\"\n | \"as\"\n | \"htmlFor\"\n | \"ariaLabel\"\n | \"disabled\"\n | \"href\"\n | \"target\"\n | \"rel\"\n | \"prefetch\"\n | \"linkComponent\"\n | \"tooltip\"\n | \"tooltipSide\"\n | \"tooltipAlign\"\n> {\n size?: TapTargetSize;\n pillClassName: string;\n iconClassName: string;\n labelClassName?: string | undefined;\n rest?: ButtonHTMLAttributes<HTMLButtonElement> | undefined;\n buttonRef?: Ref<HTMLButtonElement> | undefined;\n}\n\nfunction renderTapTarget({\n size = \"default\",\n pillClassName,\n iconClassName,\n labelClassName,\n icon,\n children,\n strokeWidth,\n label,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n rest,\n buttonRef,\n}: RenderTapTargetArgs): ReactElement {\n const { outerClassName, inlineModifier } = resolveTapGeometry(label, size);\n const inner = buildTapInner({\n label,\n pillClassName,\n iconClassName,\n labelClassName,\n inlineModifier: label ? inlineModifier : \"\",\n icon,\n children,\n strokeWidth,\n });\n const resolvedTooltip =\n tooltip !== undefined ? tooltip : label ? false : undefined;\n const triggerAriaLabel = label ? undefined : ariaLabel;\n const trigger = renderTrigger({\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n as,\n htmlFor,\n onClick,\n ariaLabel: triggerAriaLabel,\n disabled,\n outerClassName,\n children: inner,\n rest,\n buttonRef,\n });\n return withTooltip(trigger, {\n tooltip: resolvedTooltip,\n ariaLabel: triggerAriaLabel,\n disabled,\n tooltipSide,\n tooltipAlign,\n });\n}\n\ninterface RenderTriggerArgs {\n href?: string | undefined;\n target?: \"_blank\" | \"_self\" | \"_parent\" | \"_top\" | undefined;\n rel?: string | undefined;\n prefetch?: boolean | null | undefined;\n linkComponent?: TapTargetLinkComponent | undefined;\n as?: \"button\" | \"label\" | undefined;\n htmlFor?: string | undefined;\n onClick?: (() => void) | undefined;\n ariaLabel?: string | undefined;\n disabled?: boolean | undefined;\n outerClassName: string;\n children: ReactNode;\n rest?: ButtonHTMLAttributes<HTMLButtonElement> | undefined;\n buttonRef?: Ref<HTMLButtonElement> | undefined;\n}\n\n/**\n * Resolves the correct trigger element based on the props passed.\n *\n * - `href` + `disabled` → unclickable `<span aria-disabled>`\n * - `href` matching `http(s):|mailto:|tel:` → `<a target=\"_blank\" rel=\"noopener noreferrer\">`\n * - `href` (internal) → the injected link component (per-instance\n * `linkComponent` prop, else `setTapTargetLinkComponent` registration),\n * falling back to a plain `<a>` when none is registered\n * - `as=\"label\"` → `<label htmlFor=...>`\n * - default → `<button>`\n */\nfunction renderTrigger({\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n as,\n htmlFor,\n onClick,\n ariaLabel,\n disabled,\n outerClassName,\n children,\n rest,\n buttonRef,\n}: RenderTriggerArgs): ReactElement {\n if (disabled && href) {\n return (\n <span\n aria-disabled=\"true\"\n aria-label={ariaLabel}\n className={`${outerClassName} opacity-40 pointer-events-none`}\n >\n {children}\n </span>\n );\n }\n if (href) {\n const isExternal = EXTERNAL_RE.test(href);\n if (isExternal) {\n return (\n <a\n href={href}\n target={target ?? \"_blank\"}\n rel={rel ?? \"noopener noreferrer\"}\n aria-label={ariaLabel}\n className={outerClassName}\n >\n {children}\n </a>\n );\n }\n const Link = linkComponent ?? getTapTargetLinkComponent();\n if (Link) {\n return (\n <Link\n href={href}\n target={target}\n rel={rel}\n prefetch={prefetch}\n aria-label={ariaLabel}\n className={outerClassName}\n >\n {children}\n </Link>\n );\n }\n // No link component registered — plain <a>. `prefetch` is a router hint,\n // not a DOM attribute, so it is deliberately dropped here.\n return (\n <a\n href={href}\n target={target}\n rel={rel}\n aria-label={ariaLabel}\n className={outerClassName}\n >\n {children}\n </a>\n );\n }\n if (as === \"label\") {\n return (\n <label\n htmlFor={htmlFor}\n aria-label={ariaLabel}\n className={outerClassName}\n >\n {children}\n </label>\n );\n }\n return (\n <button\n ref={buttonRef}\n type=\"button\"\n onClick={onClick}\n aria-label={ariaLabel}\n disabled={disabled}\n {...rest}\n className={outerClassName}\n >\n {children}\n </button>\n );\n}\n\n/**\n * Wraps a trigger element in a Tooltip when a tooltip label is available.\n * Falls back to `ariaLabel` when `tooltip` is not explicitly set. If both\n * are absent (or `tooltip === false`), the trigger is returned unwrapped.\n */\nfunction withTooltip(\n trigger: ReactElement,\n {\n tooltip,\n ariaLabel,\n disabled,\n tooltipSide = \"top\",\n tooltipAlign = \"center\",\n }: {\n tooltip?: string | false | undefined;\n ariaLabel?: string | undefined;\n disabled?: boolean | undefined;\n tooltipSide?: \"top\" | \"right\" | \"bottom\" | \"left\" | undefined;\n tooltipAlign?: \"start\" | \"center\" | \"end\" | undefined;\n },\n): ReactElement {\n if (tooltip === false) return trigger;\n const label =\n typeof tooltip === \"string\" && tooltip.length > 0 ? tooltip : ariaLabel;\n if (!label) return trigger;\n return (\n <TooltipPrimitive.Root>\n <TooltipTrigger asChild>\n {disabled ? (\n // Radix Tooltip triggers need a hoverable element; a disabled button\n // does not dispatch pointer events, so we wrap in a span for the\n // trigger target while keeping the disabled visual state.\n <span className=\"inline-flex\">{trigger}</span>\n ) : (\n trigger\n )}\n </TooltipTrigger>\n <TooltipContent side={tooltipSide} align={tooltipAlign}>\n {label}\n </TooltipContent>\n </TooltipPrimitive.Root>\n );\n}\n\n// To resize/retune every tap button, edit styles.css — not here.\n\nexport const TapTargetButton = forwardRef<\n HTMLButtonElement,\n TapTargetButtonProps & ButtonHTMLAttributes<HTMLButtonElement>\n>(function TapTargetButton(\n {\n icon,\n children,\n strokeWidth = 2,\n onClick,\n className,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n ...rest\n },\n ref,\n) {\n const color = className ?? \"text-foreground\";\n return renderTapTarget({\n icon,\n children,\n strokeWidth,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n pillClassName: \"matrx-tap-pill matrx-glass-thin-border\",\n iconClassName: `matrx-tap-icon ${color}`,\n rest,\n buttonRef: ref,\n });\n});\n\nexport const TapTargetButtonTransparent = forwardRef<\n HTMLButtonElement,\n TapTargetButtonProps & React.ButtonHTMLAttributes<HTMLButtonElement>\n>(function TapTargetButtonTransparent(\n {\n icon,\n children,\n strokeWidth = 2,\n onClick,\n className,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n ...rest\n },\n ref,\n) {\n const color = className ?? \"text-foreground\";\n return renderTapTarget({\n icon,\n children,\n strokeWidth,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n pillClassName:\n \"matrx-tap-pill hover:bg-muted active:bg-muted-foreground/15\",\n iconClassName: `matrx-tap-icon ${color}`,\n rest,\n buttonRef: ref,\n });\n});\n\nexport const TapTargetButtonSolid = forwardRef<\n HTMLButtonElement,\n TapTargetButtonSolidProps & React.ButtonHTMLAttributes<HTMLButtonElement>\n>(function TapTargetButtonSolid(\n {\n icon,\n children,\n strokeWidth = 2,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n bgColor = \"bg-primary\",\n iconColor = \"text-primary-foreground\",\n hoverBgColor = \"hover:bg-primary/80\",\n activeBgColor = \"active:brightness-90\",\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n ...rest\n },\n ref,\n) {\n return renderTapTarget({\n icon,\n children,\n strokeWidth,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n pillClassName: `matrx-tap-pill ${bgColor} ${iconColor} ${hoverBgColor} ${activeBgColor}`,\n iconClassName: `matrx-tap-icon ${iconColor}`,\n labelClassName: `matrx-tap-label ${iconColor}`,\n rest,\n buttonRef: ref,\n });\n});\n\n/** Solid destructive pill — delete/remove actions. White-on-red like the\n * primary solid is white-on-blue. Use THIS, never hand-pass bg-destructive\n * with the default (dark) icon color. */\nexport const TapTargetButtonDestructive = forwardRef<\n HTMLButtonElement,\n TapTargetButtonSolidProps & React.ButtonHTMLAttributes<HTMLButtonElement>\n>(function TapTargetButtonDestructive(\n {\n bgColor = \"bg-destructive\",\n iconColor = \"text-destructive-foreground\",\n hoverBgColor = \"hover:bg-destructive/90\",\n ...rest\n },\n ref,\n) {\n return (\n <TapTargetButtonSolid\n ref={ref}\n bgColor={bgColor}\n iconColor={iconColor}\n hoverBgColor={hoverBgColor}\n {...rest}\n />\n );\n});\n\nexport const TapTargetButtonForGroup = forwardRef<\n HTMLButtonElement,\n TapTargetButtonProps & ButtonHTMLAttributes<HTMLButtonElement>\n>(function TapTargetButtonForGroup(\n {\n icon,\n children,\n strokeWidth = 2,\n onClick,\n className,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n ...rest\n },\n ref,\n) {\n const color = className ?? \"text-foreground\";\n return renderTapTarget({\n size: \"sm\",\n icon,\n children,\n strokeWidth,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n pillClassName: \"matrx-tap-pill matrx-tap-pill-sm matrx-glass-interactive\",\n iconClassName: `matrx-tap-icon ${color}`,\n labelClassName: `matrx-tap-label ${color}`,\n rest,\n buttonRef: ref,\n });\n});\n\nexport function TapTargetButtonGroup({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string | undefined;\n}) {\n return (\n <div\n className={\n className\n ? `relative inline-flex h-9 items-center ${className}`\n : \"relative inline-flex h-9 items-center\"\n }\n >\n <div className=\"pointer-events-none absolute inset-x-0 top-1/2 -translate-y-1/2 h-7 rounded-full matrx-glass-thin-border\" />\n {/* min-w-0 lets flexible children (e.g. a truncating filename) shrink\n under container pressure; fixed-size tap buttons are unaffected. */}\n <div className=\"relative flex min-w-0 items-center\">{children}</div>\n </div>\n );\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport { cn } from \"./cn\";\n\n/**\n * Inlined port of matrx-frontend `components/ui/tooltip.tsx` — the one `@/`\n * import the tap-target components consumed beyond `cn` and `next/link`.\n * Behavior deltas vs. the original, both documented in FEATURE.md:\n * - `useNestedPortalContainer` (a host-specific nested-overlay portal context)\n * is dropped: content portals to the Radix default (document.body).\n * - Everything else — unconditional Root render, popover-token styling — is\n * verbatim.\n *\n * Hosts must mount `TooltipProvider` once near the app root (matrx-frontend\n * already does); `TapTargetLabeled` brings its own provider like the original.\n */\nconst TooltipProvider = TooltipPrimitive.Provider;\n\nconst Tooltip = TooltipPrimitive.Root;\n\nconst TooltipTrigger = TooltipPrimitive.Trigger;\n\nconst TooltipContent = React.forwardRef<\n React.ComponentRef<typeof TooltipPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n // Neutral, theme-aware surface (popover tokens) so tooltip text is\n // ALWAYS legible in both light and dark mode — including rich content\n // that uses `text-muted-foreground`. A brand-colored `bg-primary`\n // background broke legibility for any non-default content.\n \"z-[10001] overflow-hidden rounded-md border border-border bg-popover px-3 py-1.5 text-xs text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n className,\n )}\n {...props}\n />\n </TooltipPrimitive.Portal>\n));\nTooltipContent.displayName = TooltipPrimitive.Content.displayName;\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };\n","/**\n * Minimal className join — the only piece of `cn` this package needs.\n * No tailwind-merge / clsx dependency by design: callers pass literal strings.\n */\nexport function cn(\n ...values: Array<string | null | undefined | false>\n): string {\n return values.filter(Boolean).join(\" \").trim();\n}\n","import type { ComponentType, ReactNode } from \"react\";\n\n/**\n * The injectable link seam — the package's replacement for the original\n * hard `next/link` import.\n *\n * Internal hrefs (anything NOT matching `http(s):`, `mailto:`, `tel:`) render\n * through the link component resolved here; external hrefs always render a\n * plain `<a target=\"_blank\" rel=\"noopener noreferrer\">`, exactly like the\n * original. When nothing is registered and no per-instance `linkComponent`\n * prop is given, internal hrefs fall back to a plain `<a>` (no prefetch, no\n * client-side routing — still a working link).\n */\nexport interface TapTargetLinkProps {\n href: string;\n target?: \"_blank\" | \"_self\" | \"_parent\" | \"_top\" | undefined;\n rel?: string | undefined;\n /** Router prefetch hint (next/link semantics). Plain `<a>` fallback ignores it. */\n prefetch?: boolean | null | undefined;\n \"aria-label\"?: string | undefined;\n className?: string | undefined;\n children?: ReactNode;\n}\n\nexport type TapTargetLinkComponent = ComponentType<TapTargetLinkProps>;\n\n/**\n * The registered component lives in a `Symbol.for` slot on `globalThis` — NOT\n * in module state — so it survives the module graph being instantiated more\n * than once: the `.` and `./buttons` dist bundles each inline the primitives\n * (tsup `splitting: false`), and a consumer may even mix `import` and\n * `require`. One registration must reach every copy.\n */\nconst LINK_SLOT = Symbol.for(\"@ai-matrx/tap-target:link-component\");\n\ntype GlobalWithLinkSlot = typeof globalThis & {\n [LINK_SLOT]?: TapTargetLinkComponent | null;\n};\n\n/**\n * Register the app's link component once at startup (e.g. `next/link`):\n *\n * ```tsx\n * import Link from \"next/link\";\n * import { setTapTargetLinkComponent } from \"@ai-matrx/tap-target\";\n * setTapTargetLinkComponent(Link);\n * ```\n *\n * Pass `null` to unregister (plain `<a>` fallback resumes).\n */\nexport function setTapTargetLinkComponent(\n component: TapTargetLinkComponent | null,\n): void {\n (globalThis as GlobalWithLinkSlot)[LINK_SLOT] = component;\n}\n\n/** The currently registered link component, or `null` when none is set. */\nexport function getTapTargetLinkComponent(): TapTargetLinkComponent | null {\n return (globalThis as GlobalWithLinkSlot)[LINK_SLOT] ?? null;\n}\n","\"use client\";\n\nimport {\n TooltipProvider,\n Tooltip,\n TooltipTrigger,\n TooltipContent,\n} from \"./tooltip\";\n\n/**\n * Wraps a TapTargetButton (or any tap control) like the button-demo page:\n * no extra padding on the control — only `gap-0.5` before the caption.\n * Tooltip shows the full `label`; the caption truncates at max-w-[52px].\n */\nexport function TapTargetLabeled({\n label,\n children,\n hideLabel = false,\n toolTipSide = \"bottom\",\n}: {\n label: string;\n children: React.ReactNode;\n hideLabel?: boolean | undefined;\n toolTipSide?: \"top\" | \"bottom\" | \"left\" | \"right\" | undefined;\n}) {\n return (\n <TooltipProvider delayDuration={200}>\n <Tooltip>\n <TooltipTrigger asChild>\n <div className=\"flex flex-col items-center p-0 gap-0 space-y-0 space-x-0 shrink-0\">\n {children}\n {!hideLabel && (\n <span className=\"text-[10px] text-muted-foreground/70 leading-tight max-w-[52px] text-center truncate\">\n {label}\n </span>\n )}\n </div>\n </TooltipTrigger>\n <TooltipContent side={toolTipSide}>\n <span className=\"font-mono text-xs max-w-[280px] break-all\">\n {label}\n </span>\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n );\n}\n"],"mappings":"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","names":["TooltipPrimitive","import_jsx_runtime","TapTargetButton","TapTargetButtonTransparent","TapTargetButtonSolid","TapTargetButtonDestructive","TapTargetButtonForGroup","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/tap-target-button.tsx","../src/tooltip.tsx","../src/cn.ts","../src/link.ts","../src/tap-target-labeled.tsx"],"sourcesContent":["// @ai-matrx/tap-target — primitives entry.\n// The ~60 pre-composed buttons live behind the opt-in \"./buttons\" subpath.\n// The geometry stylesheet ships as \"./styles.css\" — import it once at app root.\n\nexport {\n TapTargetButton,\n TapTargetButtonTransparent,\n TapTargetButtonSolid,\n TapTargetButtonDestructive,\n TapTargetButtonForGroup,\n TapTargetButtonGroup,\n type TapTargetButtonProps,\n type TapTargetButtonSolidProps,\n} from \"./tap-target-button\";\nexport { TapTargetLabeled } from \"./tap-target-labeled\";\nexport {\n setTapTargetLinkComponent,\n getTapTargetLinkComponent,\n type TapTargetLinkComponent,\n type TapTargetLinkProps,\n} from \"./link\";\n// Hosts mount TooltipProvider once near the app root (tooltips on every tap\n// button flow through it); the full tooltip quartet is exported for hosts\n// that do not already have their own Radix tooltip wrapper.\nexport {\n TooltipProvider,\n Tooltip,\n TooltipTrigger,\n TooltipContent,\n} from \"./tooltip\";\n","\"use client\";\n\nimport {\n cloneElement,\n forwardRef,\n isValidElement,\n type ButtonHTMLAttributes,\n type ReactElement,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport { TooltipContent, TooltipTrigger } from \"./tooltip\";\nimport { cn } from \"./cn\";\nimport {\n getTapTargetLinkComponent,\n type TapTargetLinkComponent,\n} from \"./link\";\n\nexport interface TapTargetButtonProps {\n icon?: React.ReactNode;\n children?: React.ReactNode;\n strokeWidth?: number | undefined;\n onClick?: (() => void) | undefined;\n className?: string | undefined;\n as?: \"button\" | \"label\" | undefined;\n htmlFor?: string | undefined;\n ariaLabel?: string | undefined;\n disabled?: boolean | undefined;\n /**\n * When set, the tap button renders as a link instead of a button.\n * - Internal hrefs (e.g. \"/tasks\") render via the injected link component\n * (`setTapTargetLinkComponent` / the `linkComponent` prop), falling back\n * to a plain `<a>` when none is registered.\n * - External hrefs (http://, https://, mailto:, tel:) render as `<a>`\n * with `target=\"_blank\"` and `rel=\"noopener noreferrer\"` by default.\n * - When combined with `disabled`, the trigger renders as a non-navigable\n * `<span aria-disabled=\"true\">` with the same visual styling.\n */\n href?: string | undefined;\n /** Override target. Works on both internal links and external anchors. */\n target?: \"_blank\" | \"_self\" | \"_parent\" | \"_top\" | undefined;\n /** Override rel. Works on both internal links and external anchors. */\n rel?: string | undefined;\n /** Forwarded to the injected link component. Pass `false` to disable prefetching. */\n prefetch?: boolean | null | undefined;\n /**\n * Per-instance link component for internal hrefs — overrides the\n * module-level `setTapTargetLinkComponent` registration.\n */\n linkComponent?: TapTargetLinkComponent | undefined;\n /**\n * Tooltip text. Defaults to `ariaLabel` when omitted.\n * Pass `false` to explicitly disable the tooltip.\n */\n tooltip?: string | false | undefined;\n /** Tooltip placement. Defaults to \"top\". */\n tooltipSide?: \"top\" | \"right\" | \"bottom\" | \"left\" | undefined;\n /** Tooltip alignment along its side. Defaults to \"center\". */\n tooltipAlign?: \"start\" | \"center\" | \"end\" | undefined;\n /**\n * Visible caption rendered inline after the icon (`[icon Label]`).\n * Widens the pill automatically. Tooltip defaults to off when set — the\n * label is self-describing. Visible text becomes the accessible name.\n */\n label?: string | undefined;\n /**\n * Collapse an icon + caption pill to its icon-only 44px tap target below\n * the `sm` breakpoint. The caption and inline geometry return at `sm+`;\n * `ariaLabel` (falling back to `label`) remains the accessible name.\n */\n mobileIconOnly?: boolean | undefined;\n}\n\nexport interface TapTargetButtonSolidProps extends TapTargetButtonProps {\n bgColor?: string | undefined;\n iconColor?: string | undefined;\n hoverBgColor?: string | undefined;\n /**\n * Press-state background. Defaults to `active:brightness-90` which works on\n * any color. Override when using a custom `bgColor` that should darken to a\n * specific shade on press (e.g. `active:bg-primary/60`).\n */\n activeBgColor?: string | undefined;\n}\n\nconst EXTERNAL_RE = /^(https?:|mailto:|tel:)/i;\n\n// Geometry + press feedback + tap hygiene are the SINGLE SOURCE OF TRUTH in\n// the shipped stylesheet (the `.matrx-tap-*` family in styles.css — import\n// \"@ai-matrx/tap-target/styles.css\" once at app root). This component only\n// picks the right class and layers each variant's decoration on top.\nconst TAP_OUTER_CLASS = \"matrx-tap-target group\";\nconst TAP_GROUP_OUTER_CLASS = \"matrx-tap-target matrx-tap-target-sm group\";\n\nfunction IconContent({\n icon,\n children,\n strokeWidth = 2,\n className,\n}: Pick<\n TapTargetButtonProps,\n \"icon\" | \"children\" | \"strokeWidth\" | \"className\"\n>) {\n if (icon) {\n if (isValidElement<{ className?: string }>(icon)) {\n return cloneElement(icon, {\n className: cn(className, icon.props.className),\n });\n }\n return <span className={className}>{icon}</span>;\n }\n return (\n <svg\n className={className}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={strokeWidth}\n >\n {children}\n </svg>\n );\n}\n\ntype TapTargetSize = \"default\" | \"sm\";\n\nfunction resolveTapGeometry(\n label: string | undefined,\n size: TapTargetSize,\n mobileIconOnly: boolean,\n) {\n const inline = Boolean(label);\n if (size === \"sm\") {\n return {\n outerClassName:\n inline && mobileIconOnly\n ? \"matrx-tap-target matrx-tap-target-sm matrx-tap-target-mobile-icon-only-sm group\"\n : inline\n ? \"matrx-tap-target matrx-tap-target-sm matrx-tap-target-inline-sm group\"\n : TAP_GROUP_OUTER_CLASS,\n inlineModifier: mobileIconOnly\n ? \"matrx-tap-pill-mobile-icon-only-sm\"\n : \"matrx-tap-pill-inline-sm\",\n };\n }\n return {\n outerClassName:\n inline && mobileIconOnly\n ? `${TAP_OUTER_CLASS} matrx-tap-target-mobile-icon-only`\n : inline\n ? `${TAP_OUTER_CLASS} matrx-tap-target-inline`\n : TAP_OUTER_CLASS,\n inlineModifier: mobileIconOnly\n ? \"matrx-tap-pill-mobile-icon-only\"\n : \"matrx-tap-pill-inline\",\n };\n}\n\nfunction buildTapInner({\n label,\n pillClassName,\n iconClassName,\n labelClassName,\n inlineModifier,\n icon,\n children,\n strokeWidth = 2,\n}: {\n label?: string | undefined;\n pillClassName: string;\n iconClassName: string;\n labelClassName?: string | undefined;\n inlineModifier: string;\n icon?: React.ReactNode;\n children?: React.ReactNode;\n strokeWidth?: number | undefined;\n}) {\n const iconEl = (\n <IconContent\n icon={icon}\n strokeWidth={strokeWidth}\n className={iconClassName}\n >\n {children}\n </IconContent>\n );\n const pillClasses = label\n ? `${pillClassName} ${inlineModifier}`.trim()\n : pillClassName;\n\n if (!label) {\n return <div className={pillClasses}>{iconEl}</div>;\n }\n\n return (\n <div className={pillClasses}>\n {iconEl}\n <span className={labelClassName ?? \"matrx-tap-label\"}>{label}</span>\n </div>\n );\n}\n\ninterface RenderTapTargetArgs extends Pick<\n TapTargetButtonProps,\n | \"icon\"\n | \"children\"\n | \"strokeWidth\"\n | \"label\"\n | \"mobileIconOnly\"\n | \"onClick\"\n | \"as\"\n | \"htmlFor\"\n | \"ariaLabel\"\n | \"disabled\"\n | \"href\"\n | \"target\"\n | \"rel\"\n | \"prefetch\"\n | \"linkComponent\"\n | \"tooltip\"\n | \"tooltipSide\"\n | \"tooltipAlign\"\n> {\n size?: TapTargetSize;\n pillClassName: string;\n iconClassName: string;\n labelClassName?: string | undefined;\n rest?: ButtonHTMLAttributes<HTMLButtonElement> | undefined;\n buttonRef?: Ref<HTMLButtonElement> | undefined;\n}\n\nfunction renderTapTarget({\n size = \"default\",\n pillClassName,\n iconClassName,\n labelClassName,\n icon,\n children,\n strokeWidth,\n label,\n mobileIconOnly = false,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n rest,\n buttonRef,\n}: RenderTapTargetArgs): ReactElement {\n const { outerClassName, inlineModifier } = resolveTapGeometry(\n label,\n size,\n mobileIconOnly,\n );\n const responsiveLabelClassName = mobileIconOnly\n ? `${labelClassName ?? \"matrx-tap-label\"} matrx-tap-label-mobile-icon-only`\n : labelClassName;\n const inner = buildTapInner({\n label,\n pillClassName,\n iconClassName,\n labelClassName: responsiveLabelClassName,\n inlineModifier: label ? inlineModifier : \"\",\n icon,\n children,\n strokeWidth,\n });\n const resolvedTooltip =\n tooltip !== undefined ? tooltip : label ? false : undefined;\n const triggerAriaLabel =\n label && !mobileIconOnly ? undefined : (ariaLabel ?? label);\n const trigger = renderTrigger({\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n as,\n htmlFor,\n onClick,\n ariaLabel: triggerAriaLabel,\n disabled,\n outerClassName,\n children: inner,\n rest,\n buttonRef,\n });\n return withTooltip(trigger, {\n tooltip: resolvedTooltip,\n ariaLabel: triggerAriaLabel,\n disabled,\n tooltipSide,\n tooltipAlign,\n });\n}\n\ninterface RenderTriggerArgs {\n href?: string | undefined;\n target?: \"_blank\" | \"_self\" | \"_parent\" | \"_top\" | undefined;\n rel?: string | undefined;\n prefetch?: boolean | null | undefined;\n linkComponent?: TapTargetLinkComponent | undefined;\n as?: \"button\" | \"label\" | undefined;\n htmlFor?: string | undefined;\n onClick?: (() => void) | undefined;\n ariaLabel?: string | undefined;\n disabled?: boolean | undefined;\n outerClassName: string;\n children: ReactNode;\n rest?: ButtonHTMLAttributes<HTMLButtonElement> | undefined;\n buttonRef?: Ref<HTMLButtonElement> | undefined;\n}\n\n/**\n * Resolves the correct trigger element based on the props passed.\n *\n * - `href` + `disabled` → unclickable `<span aria-disabled>`\n * - `href` matching `http(s):|mailto:|tel:` → `<a target=\"_blank\" rel=\"noopener noreferrer\">`\n * - `href` (internal) → the injected link component (per-instance\n * `linkComponent` prop, else `setTapTargetLinkComponent` registration),\n * falling back to a plain `<a>` when none is registered\n * - `as=\"label\"` → `<label htmlFor=...>`\n * - default → `<button>`\n */\nfunction renderTrigger({\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n as,\n htmlFor,\n onClick,\n ariaLabel,\n disabled,\n outerClassName,\n children,\n rest,\n buttonRef,\n}: RenderTriggerArgs): ReactElement {\n if (disabled && href) {\n return (\n <span\n aria-disabled=\"true\"\n aria-label={ariaLabel}\n className={`${outerClassName} opacity-40 pointer-events-none`}\n >\n {children}\n </span>\n );\n }\n if (href) {\n const isExternal = EXTERNAL_RE.test(href);\n if (isExternal) {\n return (\n <a\n href={href}\n target={target ?? \"_blank\"}\n rel={rel ?? \"noopener noreferrer\"}\n aria-label={ariaLabel}\n className={outerClassName}\n >\n {children}\n </a>\n );\n }\n const Link = linkComponent ?? getTapTargetLinkComponent();\n if (Link) {\n return (\n <Link\n href={href}\n target={target}\n rel={rel}\n prefetch={prefetch}\n aria-label={ariaLabel}\n className={outerClassName}\n >\n {children}\n </Link>\n );\n }\n // No link component registered — plain <a>. `prefetch` is a router hint,\n // not a DOM attribute, so it is deliberately dropped here.\n return (\n <a\n href={href}\n target={target}\n rel={rel}\n aria-label={ariaLabel}\n className={outerClassName}\n >\n {children}\n </a>\n );\n }\n if (as === \"label\") {\n return (\n <label\n htmlFor={htmlFor}\n aria-label={ariaLabel}\n className={outerClassName}\n >\n {children}\n </label>\n );\n }\n return (\n <button\n ref={buttonRef}\n type=\"button\"\n onClick={onClick}\n aria-label={ariaLabel}\n disabled={disabled}\n {...rest}\n className={outerClassName}\n >\n {children}\n </button>\n );\n}\n\n/**\n * Wraps a trigger element in a Tooltip when a tooltip label is available.\n * Falls back to `ariaLabel` when `tooltip` is not explicitly set. If both\n * are absent (or `tooltip === false`), the trigger is returned unwrapped.\n */\nfunction withTooltip(\n trigger: ReactElement,\n {\n tooltip,\n ariaLabel,\n disabled,\n tooltipSide = \"top\",\n tooltipAlign = \"center\",\n }: {\n tooltip?: string | false | undefined;\n ariaLabel?: string | undefined;\n disabled?: boolean | undefined;\n tooltipSide?: \"top\" | \"right\" | \"bottom\" | \"left\" | undefined;\n tooltipAlign?: \"start\" | \"center\" | \"end\" | undefined;\n },\n): ReactElement {\n if (tooltip === false) return trigger;\n const label =\n typeof tooltip === \"string\" && tooltip.length > 0 ? tooltip : ariaLabel;\n if (!label) return trigger;\n return (\n <TooltipPrimitive.Root>\n <TooltipTrigger asChild>\n {disabled ? (\n // Radix Tooltip triggers need a hoverable element; a disabled button\n // does not dispatch pointer events, so we wrap in a span for the\n // trigger target while keeping the disabled visual state.\n <span className=\"inline-flex\">{trigger}</span>\n ) : (\n trigger\n )}\n </TooltipTrigger>\n <TooltipContent side={tooltipSide} align={tooltipAlign}>\n {label}\n </TooltipContent>\n </TooltipPrimitive.Root>\n );\n}\n\n// To resize/retune every tap button, edit styles.css — not here.\n\nexport const TapTargetButton = forwardRef<\n HTMLButtonElement,\n TapTargetButtonProps & ButtonHTMLAttributes<HTMLButtonElement>\n>(function TapTargetButton(\n {\n icon,\n children,\n strokeWidth = 2,\n onClick,\n className,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n mobileIconOnly,\n ...rest\n },\n ref,\n) {\n const color = className ?? \"text-foreground\";\n return renderTapTarget({\n icon,\n children,\n strokeWidth,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n mobileIconOnly,\n pillClassName: \"matrx-tap-pill matrx-glass-thin-border\",\n iconClassName: `matrx-tap-icon ${color}`,\n rest,\n buttonRef: ref,\n });\n});\n\nexport const TapTargetButtonTransparent = forwardRef<\n HTMLButtonElement,\n TapTargetButtonProps & React.ButtonHTMLAttributes<HTMLButtonElement>\n>(function TapTargetButtonTransparent(\n {\n icon,\n children,\n strokeWidth = 2,\n onClick,\n className,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n mobileIconOnly,\n ...rest\n },\n ref,\n) {\n const color = className ?? \"text-foreground\";\n return renderTapTarget({\n icon,\n children,\n strokeWidth,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n mobileIconOnly,\n pillClassName:\n \"matrx-tap-pill hover:bg-muted active:bg-muted-foreground/15\",\n iconClassName: `matrx-tap-icon ${color}`,\n rest,\n buttonRef: ref,\n });\n});\n\nexport const TapTargetButtonSolid = forwardRef<\n HTMLButtonElement,\n TapTargetButtonSolidProps & React.ButtonHTMLAttributes<HTMLButtonElement>\n>(function TapTargetButtonSolid(\n {\n icon,\n children,\n strokeWidth = 2,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n bgColor = \"bg-primary\",\n iconColor = \"text-primary-foreground\",\n hoverBgColor = \"hover:bg-primary/80\",\n activeBgColor = \"active:brightness-90\",\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n mobileIconOnly,\n ...rest\n },\n ref,\n) {\n return renderTapTarget({\n icon,\n children,\n strokeWidth,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n mobileIconOnly,\n pillClassName: `matrx-tap-pill ${bgColor} ${iconColor} ${hoverBgColor} ${activeBgColor}`,\n iconClassName: `matrx-tap-icon ${iconColor}`,\n labelClassName: `matrx-tap-label ${iconColor}`,\n rest,\n buttonRef: ref,\n });\n});\n\n/** Solid destructive pill — delete/remove actions. White-on-red like the\n * primary solid is white-on-blue. Use THIS, never hand-pass bg-destructive\n * with the default (dark) icon color. */\nexport const TapTargetButtonDestructive = forwardRef<\n HTMLButtonElement,\n TapTargetButtonSolidProps & React.ButtonHTMLAttributes<HTMLButtonElement>\n>(function TapTargetButtonDestructive(\n {\n bgColor = \"bg-destructive\",\n iconColor = \"text-destructive-foreground\",\n hoverBgColor = \"hover:bg-destructive/90\",\n ...rest\n },\n ref,\n) {\n return (\n <TapTargetButtonSolid\n ref={ref}\n bgColor={bgColor}\n iconColor={iconColor}\n hoverBgColor={hoverBgColor}\n {...rest}\n />\n );\n});\n\nexport const TapTargetButtonForGroup = forwardRef<\n HTMLButtonElement,\n TapTargetButtonProps & ButtonHTMLAttributes<HTMLButtonElement>\n>(function TapTargetButtonForGroup(\n {\n icon,\n children,\n strokeWidth = 2,\n onClick,\n className,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n mobileIconOnly,\n ...rest\n },\n ref,\n) {\n const color = className ?? \"text-foreground\";\n return renderTapTarget({\n size: \"sm\",\n icon,\n children,\n strokeWidth,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n mobileIconOnly,\n pillClassName: \"matrx-tap-pill matrx-tap-pill-sm matrx-glass-interactive\",\n iconClassName: `matrx-tap-icon ${color}`,\n labelClassName: `matrx-tap-label ${color}`,\n rest,\n buttonRef: ref,\n });\n});\n\nexport function TapTargetButtonGroup({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string | undefined;\n}) {\n return (\n <div\n className={\n className\n ? `relative inline-flex h-9 items-center ${className}`\n : \"relative inline-flex h-9 items-center\"\n }\n >\n <div className=\"pointer-events-none absolute inset-x-0 top-1/2 -translate-y-1/2 h-7 rounded-full matrx-glass-thin-border\" />\n {/* min-w-0 lets flexible children (e.g. a truncating filename) shrink\n under container pressure; fixed-size tap buttons are unaffected. */}\n <div className=\"relative flex min-w-0 items-center\">{children}</div>\n </div>\n );\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport { cn } from \"./cn\";\n\n/**\n * Inlined port of matrx-frontend `components/ui/tooltip.tsx` — the one `@/`\n * import the tap-target components consumed beyond `cn` and `next/link`.\n * Behavior deltas vs. the original, both documented in FEATURE.md:\n * - `useNestedPortalContainer` (a host-specific nested-overlay portal context)\n * is dropped: content portals to the Radix default (document.body).\n * - Everything else — unconditional Root render, popover-token styling — is\n * verbatim.\n *\n * Hosts must mount `TooltipProvider` once near the app root (matrx-frontend\n * already does); `TapTargetLabeled` brings its own provider like the original.\n */\nconst TooltipProvider = TooltipPrimitive.Provider;\n\nconst Tooltip = TooltipPrimitive.Root;\n\nconst TooltipTrigger = TooltipPrimitive.Trigger;\n\nconst TooltipContent = React.forwardRef<\n React.ComponentRef<typeof TooltipPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n // Neutral, theme-aware surface (popover tokens) so tooltip text is\n // ALWAYS legible in both light and dark mode — including rich content\n // that uses `text-muted-foreground`. A brand-colored `bg-primary`\n // background broke legibility for any non-default content.\n \"z-[10001] overflow-hidden rounded-md border border-border bg-popover px-3 py-1.5 text-xs text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n className,\n )}\n {...props}\n />\n </TooltipPrimitive.Portal>\n));\nTooltipContent.displayName = TooltipPrimitive.Content.displayName;\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };\n","/**\n * Minimal className join — the only piece of `cn` this package needs.\n * No tailwind-merge / clsx dependency by design: callers pass literal strings.\n */\nexport function cn(\n ...values: Array<string | null | undefined | false>\n): string {\n return values.filter(Boolean).join(\" \").trim();\n}\n","import type { ComponentType, ReactNode } from \"react\";\n\n/**\n * The injectable link seam — the package's replacement for the original\n * hard `next/link` import.\n *\n * Internal hrefs (anything NOT matching `http(s):`, `mailto:`, `tel:`) render\n * through the link component resolved here; external hrefs always render a\n * plain `<a target=\"_blank\" rel=\"noopener noreferrer\">`, exactly like the\n * original. When nothing is registered and no per-instance `linkComponent`\n * prop is given, internal hrefs fall back to a plain `<a>` (no prefetch, no\n * client-side routing — still a working link).\n */\nexport interface TapTargetLinkProps {\n href: string;\n target?: \"_blank\" | \"_self\" | \"_parent\" | \"_top\" | undefined;\n rel?: string | undefined;\n /** Router prefetch hint (next/link semantics). Plain `<a>` fallback ignores it. */\n prefetch?: boolean | null | undefined;\n \"aria-label\"?: string | undefined;\n className?: string | undefined;\n children?: ReactNode;\n}\n\nexport type TapTargetLinkComponent = ComponentType<TapTargetLinkProps>;\n\n/**\n * The registered component lives in a `Symbol.for` slot on `globalThis` — NOT\n * in module state — so it survives the module graph being instantiated more\n * than once: the `.` and `./buttons` dist bundles each inline the primitives\n * (tsup `splitting: false`), and a consumer may even mix `import` and\n * `require`. One registration must reach every copy.\n */\nconst LINK_SLOT = Symbol.for(\"@ai-matrx/tap-target:link-component\");\n\ntype GlobalWithLinkSlot = typeof globalThis & {\n [LINK_SLOT]?: TapTargetLinkComponent | null;\n};\n\n/**\n * Register the app's link component once at startup (e.g. `next/link`):\n *\n * ```tsx\n * import Link from \"next/link\";\n * import { setTapTargetLinkComponent } from \"@ai-matrx/tap-target\";\n * setTapTargetLinkComponent(Link);\n * ```\n *\n * Pass `null` to unregister (plain `<a>` fallback resumes).\n */\nexport function setTapTargetLinkComponent(\n component: TapTargetLinkComponent | null,\n): void {\n (globalThis as GlobalWithLinkSlot)[LINK_SLOT] = component;\n}\n\n/** The currently registered link component, or `null` when none is set. */\nexport function getTapTargetLinkComponent(): TapTargetLinkComponent | null {\n return (globalThis as GlobalWithLinkSlot)[LINK_SLOT] ?? null;\n}\n","\"use client\";\n\nimport {\n TooltipProvider,\n Tooltip,\n TooltipTrigger,\n TooltipContent,\n} from \"./tooltip\";\n\n/**\n * Wraps a TapTargetButton (or any tap control) like the button-demo page:\n * no extra padding on the control — only `gap-0.5` before the caption.\n * Tooltip shows the full `label`; the caption truncates at max-w-[52px].\n */\nexport function TapTargetLabeled({\n label,\n children,\n hideLabel = false,\n toolTipSide = \"bottom\",\n}: {\n label: string;\n children: React.ReactNode;\n hideLabel?: boolean | undefined;\n toolTipSide?: \"top\" | \"bottom\" | \"left\" | \"right\" | undefined;\n}) {\n return (\n <TooltipProvider delayDuration={200}>\n <Tooltip>\n <TooltipTrigger asChild>\n <div className=\"flex flex-col items-center p-0 gap-0 space-y-0 space-x-0 shrink-0\">\n {children}\n {!hideLabel && (\n <span className=\"text-[10px] text-muted-foreground/70 leading-tight max-w-[52px] text-center truncate\">\n {label}\n </span>\n )}\n </div>\n </TooltipTrigger>\n <TooltipContent side={toolTipSide}>\n <span className=\"font-mono text-xs max-w-[280px] break-all\">\n {label}\n </span>\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n );\n}\n"],"mappings":"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","names":["TooltipPrimitive","import_jsx_runtime","TapTargetButton","TapTargetButtonTransparent","TapTargetButtonSolid","TapTargetButtonDestructive","TapTargetButtonForGroup","import_jsx_runtime"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -51,6 +51,12 @@ interface TapTargetButtonProps {
|
|
|
51
51
|
* label is self-describing. Visible text becomes the accessible name.
|
|
52
52
|
*/
|
|
53
53
|
label?: string | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* Collapse an icon + caption pill to its icon-only 44px tap target below
|
|
56
|
+
* the `sm` breakpoint. The caption and inline geometry return at `sm+`;
|
|
57
|
+
* `ariaLabel` (falling back to `label`) remains the accessible name.
|
|
58
|
+
*/
|
|
59
|
+
mobileIconOnly?: boolean | undefined;
|
|
54
60
|
}
|
|
55
61
|
interface TapTargetButtonSolidProps extends TapTargetButtonProps {
|
|
56
62
|
bgColor?: string | undefined;
|
package/dist/index.d.ts
CHANGED
|
@@ -51,6 +51,12 @@ interface TapTargetButtonProps {
|
|
|
51
51
|
* label is self-describing. Visible text becomes the accessible name.
|
|
52
52
|
*/
|
|
53
53
|
label?: string | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* Collapse an icon + caption pill to its icon-only 44px tap target below
|
|
56
|
+
* the `sm` breakpoint. The caption and inline geometry return at `sm+`;
|
|
57
|
+
* `ariaLabel` (falling back to `label`) remains the accessible name.
|
|
58
|
+
*/
|
|
59
|
+
mobileIconOnly?: boolean | undefined;
|
|
54
60
|
}
|
|
55
61
|
interface TapTargetButtonSolidProps extends TapTargetButtonProps {
|
|
56
62
|
bgColor?: string | undefined;
|
package/dist/index.js
CHANGED
|
@@ -80,17 +80,17 @@ function IconContent({
|
|
|
80
80
|
}
|
|
81
81
|
);
|
|
82
82
|
}
|
|
83
|
-
function resolveTapGeometry(label, size) {
|
|
83
|
+
function resolveTapGeometry(label, size, mobileIconOnly) {
|
|
84
84
|
const inline = Boolean(label);
|
|
85
85
|
if (size === "sm") {
|
|
86
86
|
return {
|
|
87
|
-
outerClassName: inline ? "matrx-tap-target matrx-tap-target-sm matrx-tap-target-inline-sm group" : TAP_GROUP_OUTER_CLASS,
|
|
88
|
-
inlineModifier: "matrx-tap-pill-inline-sm"
|
|
87
|
+
outerClassName: inline && mobileIconOnly ? "matrx-tap-target matrx-tap-target-sm matrx-tap-target-mobile-icon-only-sm group" : inline ? "matrx-tap-target matrx-tap-target-sm matrx-tap-target-inline-sm group" : TAP_GROUP_OUTER_CLASS,
|
|
88
|
+
inlineModifier: mobileIconOnly ? "matrx-tap-pill-mobile-icon-only-sm" : "matrx-tap-pill-inline-sm"
|
|
89
89
|
};
|
|
90
90
|
}
|
|
91
91
|
return {
|
|
92
|
-
outerClassName: inline ? `${TAP_OUTER_CLASS} matrx-tap-target-inline` : TAP_OUTER_CLASS,
|
|
93
|
-
inlineModifier: "matrx-tap-pill-inline"
|
|
92
|
+
outerClassName: inline && mobileIconOnly ? `${TAP_OUTER_CLASS} matrx-tap-target-mobile-icon-only` : inline ? `${TAP_OUTER_CLASS} matrx-tap-target-inline` : TAP_OUTER_CLASS,
|
|
93
|
+
inlineModifier: mobileIconOnly ? "matrx-tap-pill-mobile-icon-only" : "matrx-tap-pill-inline"
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
96
|
function buildTapInner({
|
|
@@ -130,6 +130,7 @@ function renderTapTarget({
|
|
|
130
130
|
children,
|
|
131
131
|
strokeWidth,
|
|
132
132
|
label,
|
|
133
|
+
mobileIconOnly = false,
|
|
133
134
|
onClick,
|
|
134
135
|
as,
|
|
135
136
|
htmlFor,
|
|
@@ -146,19 +147,24 @@ function renderTapTarget({
|
|
|
146
147
|
rest,
|
|
147
148
|
buttonRef
|
|
148
149
|
}) {
|
|
149
|
-
const { outerClassName, inlineModifier } = resolveTapGeometry(
|
|
150
|
+
const { outerClassName, inlineModifier } = resolveTapGeometry(
|
|
151
|
+
label,
|
|
152
|
+
size,
|
|
153
|
+
mobileIconOnly
|
|
154
|
+
);
|
|
155
|
+
const responsiveLabelClassName = mobileIconOnly ? `${labelClassName ?? "matrx-tap-label"} matrx-tap-label-mobile-icon-only` : labelClassName;
|
|
150
156
|
const inner = buildTapInner({
|
|
151
157
|
label,
|
|
152
158
|
pillClassName,
|
|
153
159
|
iconClassName,
|
|
154
|
-
labelClassName,
|
|
160
|
+
labelClassName: responsiveLabelClassName,
|
|
155
161
|
inlineModifier: label ? inlineModifier : "",
|
|
156
162
|
icon,
|
|
157
163
|
children,
|
|
158
164
|
strokeWidth
|
|
159
165
|
});
|
|
160
166
|
const resolvedTooltip = tooltip !== void 0 ? tooltip : label ? false : void 0;
|
|
161
|
-
const triggerAriaLabel = label ? void 0 : ariaLabel;
|
|
167
|
+
const triggerAriaLabel = label && !mobileIconOnly ? void 0 : ariaLabel ?? label;
|
|
162
168
|
const trigger = renderTrigger({
|
|
163
169
|
href,
|
|
164
170
|
target,
|
|
@@ -316,6 +322,7 @@ var TapTargetButton = forwardRef2(function TapTargetButton2({
|
|
|
316
322
|
tooltipSide,
|
|
317
323
|
tooltipAlign,
|
|
318
324
|
label,
|
|
325
|
+
mobileIconOnly,
|
|
319
326
|
...rest
|
|
320
327
|
}, ref) {
|
|
321
328
|
const color = className ?? "text-foreground";
|
|
@@ -337,6 +344,7 @@ var TapTargetButton = forwardRef2(function TapTargetButton2({
|
|
|
337
344
|
tooltipSide,
|
|
338
345
|
tooltipAlign,
|
|
339
346
|
label,
|
|
347
|
+
mobileIconOnly,
|
|
340
348
|
pillClassName: "matrx-tap-pill matrx-glass-thin-border",
|
|
341
349
|
iconClassName: `matrx-tap-icon ${color}`,
|
|
342
350
|
rest,
|
|
@@ -362,6 +370,7 @@ var TapTargetButtonTransparent = forwardRef2(function TapTargetButtonTransparent
|
|
|
362
370
|
tooltipSide,
|
|
363
371
|
tooltipAlign,
|
|
364
372
|
label,
|
|
373
|
+
mobileIconOnly,
|
|
365
374
|
...rest
|
|
366
375
|
}, ref) {
|
|
367
376
|
const color = className ?? "text-foreground";
|
|
@@ -383,6 +392,7 @@ var TapTargetButtonTransparent = forwardRef2(function TapTargetButtonTransparent
|
|
|
383
392
|
tooltipSide,
|
|
384
393
|
tooltipAlign,
|
|
385
394
|
label,
|
|
395
|
+
mobileIconOnly,
|
|
386
396
|
pillClassName: "matrx-tap-pill hover:bg-muted active:bg-muted-foreground/15",
|
|
387
397
|
iconClassName: `matrx-tap-icon ${color}`,
|
|
388
398
|
rest,
|
|
@@ -411,6 +421,7 @@ var TapTargetButtonSolid = forwardRef2(function TapTargetButtonSolid2({
|
|
|
411
421
|
tooltipSide,
|
|
412
422
|
tooltipAlign,
|
|
413
423
|
label,
|
|
424
|
+
mobileIconOnly,
|
|
414
425
|
...rest
|
|
415
426
|
}, ref) {
|
|
416
427
|
return renderTapTarget({
|
|
@@ -431,6 +442,7 @@ var TapTargetButtonSolid = forwardRef2(function TapTargetButtonSolid2({
|
|
|
431
442
|
tooltipSide,
|
|
432
443
|
tooltipAlign,
|
|
433
444
|
label,
|
|
445
|
+
mobileIconOnly,
|
|
434
446
|
pillClassName: `matrx-tap-pill ${bgColor} ${iconColor} ${hoverBgColor} ${activeBgColor}`,
|
|
435
447
|
iconClassName: `matrx-tap-icon ${iconColor}`,
|
|
436
448
|
labelClassName: `matrx-tap-label ${iconColor}`,
|
|
@@ -474,6 +486,7 @@ var TapTargetButtonForGroup = forwardRef2(function TapTargetButtonForGroup2({
|
|
|
474
486
|
tooltipSide,
|
|
475
487
|
tooltipAlign,
|
|
476
488
|
label,
|
|
489
|
+
mobileIconOnly,
|
|
477
490
|
...rest
|
|
478
491
|
}, ref) {
|
|
479
492
|
const color = className ?? "text-foreground";
|
|
@@ -496,6 +509,7 @@ var TapTargetButtonForGroup = forwardRef2(function TapTargetButtonForGroup2({
|
|
|
496
509
|
tooltipSide,
|
|
497
510
|
tooltipAlign,
|
|
498
511
|
label,
|
|
512
|
+
mobileIconOnly,
|
|
499
513
|
pillClassName: "matrx-tap-pill matrx-tap-pill-sm matrx-glass-interactive",
|
|
500
514
|
iconClassName: `matrx-tap-icon ${color}`,
|
|
501
515
|
labelClassName: `matrx-tap-label ${color}`,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tap-target-button.tsx","../src/tooltip.tsx","../src/cn.ts","../src/link.ts","../src/tap-target-labeled.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n cloneElement,\n forwardRef,\n isValidElement,\n type ButtonHTMLAttributes,\n type ReactElement,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport { TooltipContent, TooltipTrigger } from \"./tooltip\";\nimport { cn } from \"./cn\";\nimport {\n getTapTargetLinkComponent,\n type TapTargetLinkComponent,\n} from \"./link\";\n\nexport interface TapTargetButtonProps {\n icon?: React.ReactNode;\n children?: React.ReactNode;\n strokeWidth?: number | undefined;\n onClick?: (() => void) | undefined;\n className?: string | undefined;\n as?: \"button\" | \"label\" | undefined;\n htmlFor?: string | undefined;\n ariaLabel?: string | undefined;\n disabled?: boolean | undefined;\n /**\n * When set, the tap button renders as a link instead of a button.\n * - Internal hrefs (e.g. \"/tasks\") render via the injected link component\n * (`setTapTargetLinkComponent` / the `linkComponent` prop), falling back\n * to a plain `<a>` when none is registered.\n * - External hrefs (http://, https://, mailto:, tel:) render as `<a>`\n * with `target=\"_blank\"` and `rel=\"noopener noreferrer\"` by default.\n * - When combined with `disabled`, the trigger renders as a non-navigable\n * `<span aria-disabled=\"true\">` with the same visual styling.\n */\n href?: string | undefined;\n /** Override target. Works on both internal links and external anchors. */\n target?: \"_blank\" | \"_self\" | \"_parent\" | \"_top\" | undefined;\n /** Override rel. Works on both internal links and external anchors. */\n rel?: string | undefined;\n /** Forwarded to the injected link component. Pass `false` to disable prefetching. */\n prefetch?: boolean | null | undefined;\n /**\n * Per-instance link component for internal hrefs — overrides the\n * module-level `setTapTargetLinkComponent` registration.\n */\n linkComponent?: TapTargetLinkComponent | undefined;\n /**\n * Tooltip text. Defaults to `ariaLabel` when omitted.\n * Pass `false` to explicitly disable the tooltip.\n */\n tooltip?: string | false | undefined;\n /** Tooltip placement. Defaults to \"top\". */\n tooltipSide?: \"top\" | \"right\" | \"bottom\" | \"left\" | undefined;\n /** Tooltip alignment along its side. Defaults to \"center\". */\n tooltipAlign?: \"start\" | \"center\" | \"end\" | undefined;\n /**\n * Visible caption rendered inline after the icon (`[icon Label]`).\n * Widens the pill automatically. Tooltip defaults to off when set — the\n * label is self-describing. Visible text becomes the accessible name.\n */\n label?: string | undefined;\n}\n\nexport interface TapTargetButtonSolidProps extends TapTargetButtonProps {\n bgColor?: string | undefined;\n iconColor?: string | undefined;\n hoverBgColor?: string | undefined;\n /**\n * Press-state background. Defaults to `active:brightness-90` which works on\n * any color. Override when using a custom `bgColor` that should darken to a\n * specific shade on press (e.g. `active:bg-primary/60`).\n */\n activeBgColor?: string | undefined;\n}\n\nconst EXTERNAL_RE = /^(https?:|mailto:|tel:)/i;\n\n// Geometry + press feedback + tap hygiene are the SINGLE SOURCE OF TRUTH in\n// the shipped stylesheet (the `.matrx-tap-*` family in styles.css — import\n// \"@ai-matrx/tap-target/styles.css\" once at app root). This component only\n// picks the right class and layers each variant's decoration on top.\nconst TAP_OUTER_CLASS = \"matrx-tap-target group\";\nconst TAP_GROUP_OUTER_CLASS = \"matrx-tap-target matrx-tap-target-sm group\";\n\nfunction IconContent({\n icon,\n children,\n strokeWidth = 2,\n className,\n}: Pick<\n TapTargetButtonProps,\n \"icon\" | \"children\" | \"strokeWidth\" | \"className\"\n>) {\n if (icon) {\n if (isValidElement<{ className?: string }>(icon)) {\n return cloneElement(icon, {\n className: cn(className, icon.props.className),\n });\n }\n return <span className={className}>{icon}</span>;\n }\n return (\n <svg\n className={className}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={strokeWidth}\n >\n {children}\n </svg>\n );\n}\n\ntype TapTargetSize = \"default\" | \"sm\";\n\nfunction resolveTapGeometry(label: string | undefined, size: TapTargetSize) {\n const inline = Boolean(label);\n if (size === \"sm\") {\n return {\n outerClassName: inline\n ? \"matrx-tap-target matrx-tap-target-sm matrx-tap-target-inline-sm group\"\n : TAP_GROUP_OUTER_CLASS,\n inlineModifier: \"matrx-tap-pill-inline-sm\",\n };\n }\n return {\n outerClassName: inline\n ? `${TAP_OUTER_CLASS} matrx-tap-target-inline`\n : TAP_OUTER_CLASS,\n inlineModifier: \"matrx-tap-pill-inline\",\n };\n}\n\nfunction buildTapInner({\n label,\n pillClassName,\n iconClassName,\n labelClassName,\n inlineModifier,\n icon,\n children,\n strokeWidth = 2,\n}: {\n label?: string | undefined;\n pillClassName: string;\n iconClassName: string;\n labelClassName?: string | undefined;\n inlineModifier: string;\n icon?: React.ReactNode;\n children?: React.ReactNode;\n strokeWidth?: number | undefined;\n}) {\n const iconEl = (\n <IconContent\n icon={icon}\n strokeWidth={strokeWidth}\n className={iconClassName}\n >\n {children}\n </IconContent>\n );\n const pillClasses = label\n ? `${pillClassName} ${inlineModifier}`.trim()\n : pillClassName;\n\n if (!label) {\n return <div className={pillClasses}>{iconEl}</div>;\n }\n\n return (\n <div className={pillClasses}>\n {iconEl}\n <span className={labelClassName ?? \"matrx-tap-label\"}>{label}</span>\n </div>\n );\n}\n\ninterface RenderTapTargetArgs extends Pick<\n TapTargetButtonProps,\n | \"icon\"\n | \"children\"\n | \"strokeWidth\"\n | \"label\"\n | \"onClick\"\n | \"as\"\n | \"htmlFor\"\n | \"ariaLabel\"\n | \"disabled\"\n | \"href\"\n | \"target\"\n | \"rel\"\n | \"prefetch\"\n | \"linkComponent\"\n | \"tooltip\"\n | \"tooltipSide\"\n | \"tooltipAlign\"\n> {\n size?: TapTargetSize;\n pillClassName: string;\n iconClassName: string;\n labelClassName?: string | undefined;\n rest?: ButtonHTMLAttributes<HTMLButtonElement> | undefined;\n buttonRef?: Ref<HTMLButtonElement> | undefined;\n}\n\nfunction renderTapTarget({\n size = \"default\",\n pillClassName,\n iconClassName,\n labelClassName,\n icon,\n children,\n strokeWidth,\n label,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n rest,\n buttonRef,\n}: RenderTapTargetArgs): ReactElement {\n const { outerClassName, inlineModifier } = resolveTapGeometry(label, size);\n const inner = buildTapInner({\n label,\n pillClassName,\n iconClassName,\n labelClassName,\n inlineModifier: label ? inlineModifier : \"\",\n icon,\n children,\n strokeWidth,\n });\n const resolvedTooltip =\n tooltip !== undefined ? tooltip : label ? false : undefined;\n const triggerAriaLabel = label ? undefined : ariaLabel;\n const trigger = renderTrigger({\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n as,\n htmlFor,\n onClick,\n ariaLabel: triggerAriaLabel,\n disabled,\n outerClassName,\n children: inner,\n rest,\n buttonRef,\n });\n return withTooltip(trigger, {\n tooltip: resolvedTooltip,\n ariaLabel: triggerAriaLabel,\n disabled,\n tooltipSide,\n tooltipAlign,\n });\n}\n\ninterface RenderTriggerArgs {\n href?: string | undefined;\n target?: \"_blank\" | \"_self\" | \"_parent\" | \"_top\" | undefined;\n rel?: string | undefined;\n prefetch?: boolean | null | undefined;\n linkComponent?: TapTargetLinkComponent | undefined;\n as?: \"button\" | \"label\" | undefined;\n htmlFor?: string | undefined;\n onClick?: (() => void) | undefined;\n ariaLabel?: string | undefined;\n disabled?: boolean | undefined;\n outerClassName: string;\n children: ReactNode;\n rest?: ButtonHTMLAttributes<HTMLButtonElement> | undefined;\n buttonRef?: Ref<HTMLButtonElement> | undefined;\n}\n\n/**\n * Resolves the correct trigger element based on the props passed.\n *\n * - `href` + `disabled` → unclickable `<span aria-disabled>`\n * - `href` matching `http(s):|mailto:|tel:` → `<a target=\"_blank\" rel=\"noopener noreferrer\">`\n * - `href` (internal) → the injected link component (per-instance\n * `linkComponent` prop, else `setTapTargetLinkComponent` registration),\n * falling back to a plain `<a>` when none is registered\n * - `as=\"label\"` → `<label htmlFor=...>`\n * - default → `<button>`\n */\nfunction renderTrigger({\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n as,\n htmlFor,\n onClick,\n ariaLabel,\n disabled,\n outerClassName,\n children,\n rest,\n buttonRef,\n}: RenderTriggerArgs): ReactElement {\n if (disabled && href) {\n return (\n <span\n aria-disabled=\"true\"\n aria-label={ariaLabel}\n className={`${outerClassName} opacity-40 pointer-events-none`}\n >\n {children}\n </span>\n );\n }\n if (href) {\n const isExternal = EXTERNAL_RE.test(href);\n if (isExternal) {\n return (\n <a\n href={href}\n target={target ?? \"_blank\"}\n rel={rel ?? \"noopener noreferrer\"}\n aria-label={ariaLabel}\n className={outerClassName}\n >\n {children}\n </a>\n );\n }\n const Link = linkComponent ?? getTapTargetLinkComponent();\n if (Link) {\n return (\n <Link\n href={href}\n target={target}\n rel={rel}\n prefetch={prefetch}\n aria-label={ariaLabel}\n className={outerClassName}\n >\n {children}\n </Link>\n );\n }\n // No link component registered — plain <a>. `prefetch` is a router hint,\n // not a DOM attribute, so it is deliberately dropped here.\n return (\n <a\n href={href}\n target={target}\n rel={rel}\n aria-label={ariaLabel}\n className={outerClassName}\n >\n {children}\n </a>\n );\n }\n if (as === \"label\") {\n return (\n <label\n htmlFor={htmlFor}\n aria-label={ariaLabel}\n className={outerClassName}\n >\n {children}\n </label>\n );\n }\n return (\n <button\n ref={buttonRef}\n type=\"button\"\n onClick={onClick}\n aria-label={ariaLabel}\n disabled={disabled}\n {...rest}\n className={outerClassName}\n >\n {children}\n </button>\n );\n}\n\n/**\n * Wraps a trigger element in a Tooltip when a tooltip label is available.\n * Falls back to `ariaLabel` when `tooltip` is not explicitly set. If both\n * are absent (or `tooltip === false`), the trigger is returned unwrapped.\n */\nfunction withTooltip(\n trigger: ReactElement,\n {\n tooltip,\n ariaLabel,\n disabled,\n tooltipSide = \"top\",\n tooltipAlign = \"center\",\n }: {\n tooltip?: string | false | undefined;\n ariaLabel?: string | undefined;\n disabled?: boolean | undefined;\n tooltipSide?: \"top\" | \"right\" | \"bottom\" | \"left\" | undefined;\n tooltipAlign?: \"start\" | \"center\" | \"end\" | undefined;\n },\n): ReactElement {\n if (tooltip === false) return trigger;\n const label =\n typeof tooltip === \"string\" && tooltip.length > 0 ? tooltip : ariaLabel;\n if (!label) return trigger;\n return (\n <TooltipPrimitive.Root>\n <TooltipTrigger asChild>\n {disabled ? (\n // Radix Tooltip triggers need a hoverable element; a disabled button\n // does not dispatch pointer events, so we wrap in a span for the\n // trigger target while keeping the disabled visual state.\n <span className=\"inline-flex\">{trigger}</span>\n ) : (\n trigger\n )}\n </TooltipTrigger>\n <TooltipContent side={tooltipSide} align={tooltipAlign}>\n {label}\n </TooltipContent>\n </TooltipPrimitive.Root>\n );\n}\n\n// To resize/retune every tap button, edit styles.css — not here.\n\nexport const TapTargetButton = forwardRef<\n HTMLButtonElement,\n TapTargetButtonProps & ButtonHTMLAttributes<HTMLButtonElement>\n>(function TapTargetButton(\n {\n icon,\n children,\n strokeWidth = 2,\n onClick,\n className,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n ...rest\n },\n ref,\n) {\n const color = className ?? \"text-foreground\";\n return renderTapTarget({\n icon,\n children,\n strokeWidth,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n pillClassName: \"matrx-tap-pill matrx-glass-thin-border\",\n iconClassName: `matrx-tap-icon ${color}`,\n rest,\n buttonRef: ref,\n });\n});\n\nexport const TapTargetButtonTransparent = forwardRef<\n HTMLButtonElement,\n TapTargetButtonProps & React.ButtonHTMLAttributes<HTMLButtonElement>\n>(function TapTargetButtonTransparent(\n {\n icon,\n children,\n strokeWidth = 2,\n onClick,\n className,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n ...rest\n },\n ref,\n) {\n const color = className ?? \"text-foreground\";\n return renderTapTarget({\n icon,\n children,\n strokeWidth,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n pillClassName:\n \"matrx-tap-pill hover:bg-muted active:bg-muted-foreground/15\",\n iconClassName: `matrx-tap-icon ${color}`,\n rest,\n buttonRef: ref,\n });\n});\n\nexport const TapTargetButtonSolid = forwardRef<\n HTMLButtonElement,\n TapTargetButtonSolidProps & React.ButtonHTMLAttributes<HTMLButtonElement>\n>(function TapTargetButtonSolid(\n {\n icon,\n children,\n strokeWidth = 2,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n bgColor = \"bg-primary\",\n iconColor = \"text-primary-foreground\",\n hoverBgColor = \"hover:bg-primary/80\",\n activeBgColor = \"active:brightness-90\",\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n ...rest\n },\n ref,\n) {\n return renderTapTarget({\n icon,\n children,\n strokeWidth,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n pillClassName: `matrx-tap-pill ${bgColor} ${iconColor} ${hoverBgColor} ${activeBgColor}`,\n iconClassName: `matrx-tap-icon ${iconColor}`,\n labelClassName: `matrx-tap-label ${iconColor}`,\n rest,\n buttonRef: ref,\n });\n});\n\n/** Solid destructive pill — delete/remove actions. White-on-red like the\n * primary solid is white-on-blue. Use THIS, never hand-pass bg-destructive\n * with the default (dark) icon color. */\nexport const TapTargetButtonDestructive = forwardRef<\n HTMLButtonElement,\n TapTargetButtonSolidProps & React.ButtonHTMLAttributes<HTMLButtonElement>\n>(function TapTargetButtonDestructive(\n {\n bgColor = \"bg-destructive\",\n iconColor = \"text-destructive-foreground\",\n hoverBgColor = \"hover:bg-destructive/90\",\n ...rest\n },\n ref,\n) {\n return (\n <TapTargetButtonSolid\n ref={ref}\n bgColor={bgColor}\n iconColor={iconColor}\n hoverBgColor={hoverBgColor}\n {...rest}\n />\n );\n});\n\nexport const TapTargetButtonForGroup = forwardRef<\n HTMLButtonElement,\n TapTargetButtonProps & ButtonHTMLAttributes<HTMLButtonElement>\n>(function TapTargetButtonForGroup(\n {\n icon,\n children,\n strokeWidth = 2,\n onClick,\n className,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n ...rest\n },\n ref,\n) {\n const color = className ?? \"text-foreground\";\n return renderTapTarget({\n size: \"sm\",\n icon,\n children,\n strokeWidth,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n pillClassName: \"matrx-tap-pill matrx-tap-pill-sm matrx-glass-interactive\",\n iconClassName: `matrx-tap-icon ${color}`,\n labelClassName: `matrx-tap-label ${color}`,\n rest,\n buttonRef: ref,\n });\n});\n\nexport function TapTargetButtonGroup({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string | undefined;\n}) {\n return (\n <div\n className={\n className\n ? `relative inline-flex h-9 items-center ${className}`\n : \"relative inline-flex h-9 items-center\"\n }\n >\n <div className=\"pointer-events-none absolute inset-x-0 top-1/2 -translate-y-1/2 h-7 rounded-full matrx-glass-thin-border\" />\n {/* min-w-0 lets flexible children (e.g. a truncating filename) shrink\n under container pressure; fixed-size tap buttons are unaffected. */}\n <div className=\"relative flex min-w-0 items-center\">{children}</div>\n </div>\n );\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport { cn } from \"./cn\";\n\n/**\n * Inlined port of matrx-frontend `components/ui/tooltip.tsx` — the one `@/`\n * import the tap-target components consumed beyond `cn` and `next/link`.\n * Behavior deltas vs. the original, both documented in FEATURE.md:\n * - `useNestedPortalContainer` (a host-specific nested-overlay portal context)\n * is dropped: content portals to the Radix default (document.body).\n * - Everything else — unconditional Root render, popover-token styling — is\n * verbatim.\n *\n * Hosts must mount `TooltipProvider` once near the app root (matrx-frontend\n * already does); `TapTargetLabeled` brings its own provider like the original.\n */\nconst TooltipProvider = TooltipPrimitive.Provider;\n\nconst Tooltip = TooltipPrimitive.Root;\n\nconst TooltipTrigger = TooltipPrimitive.Trigger;\n\nconst TooltipContent = React.forwardRef<\n React.ComponentRef<typeof TooltipPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n // Neutral, theme-aware surface (popover tokens) so tooltip text is\n // ALWAYS legible in both light and dark mode — including rich content\n // that uses `text-muted-foreground`. A brand-colored `bg-primary`\n // background broke legibility for any non-default content.\n \"z-[10001] overflow-hidden rounded-md border border-border bg-popover px-3 py-1.5 text-xs text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n className,\n )}\n {...props}\n />\n </TooltipPrimitive.Portal>\n));\nTooltipContent.displayName = TooltipPrimitive.Content.displayName;\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };\n","/**\n * Minimal className join — the only piece of `cn` this package needs.\n * No tailwind-merge / clsx dependency by design: callers pass literal strings.\n */\nexport function cn(\n ...values: Array<string | null | undefined | false>\n): string {\n return values.filter(Boolean).join(\" \").trim();\n}\n","import type { ComponentType, ReactNode } from \"react\";\n\n/**\n * The injectable link seam — the package's replacement for the original\n * hard `next/link` import.\n *\n * Internal hrefs (anything NOT matching `http(s):`, `mailto:`, `tel:`) render\n * through the link component resolved here; external hrefs always render a\n * plain `<a target=\"_blank\" rel=\"noopener noreferrer\">`, exactly like the\n * original. When nothing is registered and no per-instance `linkComponent`\n * prop is given, internal hrefs fall back to a plain `<a>` (no prefetch, no\n * client-side routing — still a working link).\n */\nexport interface TapTargetLinkProps {\n href: string;\n target?: \"_blank\" | \"_self\" | \"_parent\" | \"_top\" | undefined;\n rel?: string | undefined;\n /** Router prefetch hint (next/link semantics). Plain `<a>` fallback ignores it. */\n prefetch?: boolean | null | undefined;\n \"aria-label\"?: string | undefined;\n className?: string | undefined;\n children?: ReactNode;\n}\n\nexport type TapTargetLinkComponent = ComponentType<TapTargetLinkProps>;\n\n/**\n * The registered component lives in a `Symbol.for` slot on `globalThis` — NOT\n * in module state — so it survives the module graph being instantiated more\n * than once: the `.` and `./buttons` dist bundles each inline the primitives\n * (tsup `splitting: false`), and a consumer may even mix `import` and\n * `require`. One registration must reach every copy.\n */\nconst LINK_SLOT = Symbol.for(\"@ai-matrx/tap-target:link-component\");\n\ntype GlobalWithLinkSlot = typeof globalThis & {\n [LINK_SLOT]?: TapTargetLinkComponent | null;\n};\n\n/**\n * Register the app's link component once at startup (e.g. `next/link`):\n *\n * ```tsx\n * import Link from \"next/link\";\n * import { setTapTargetLinkComponent } from \"@ai-matrx/tap-target\";\n * setTapTargetLinkComponent(Link);\n * ```\n *\n * Pass `null` to unregister (plain `<a>` fallback resumes).\n */\nexport function setTapTargetLinkComponent(\n component: TapTargetLinkComponent | null,\n): void {\n (globalThis as GlobalWithLinkSlot)[LINK_SLOT] = component;\n}\n\n/** The currently registered link component, or `null` when none is set. */\nexport function getTapTargetLinkComponent(): TapTargetLinkComponent | null {\n return (globalThis as GlobalWithLinkSlot)[LINK_SLOT] ?? null;\n}\n","\"use client\";\n\nimport {\n TooltipProvider,\n Tooltip,\n TooltipTrigger,\n TooltipContent,\n} from \"./tooltip\";\n\n/**\n * Wraps a TapTargetButton (or any tap control) like the button-demo page:\n * no extra padding on the control — only `gap-0.5` before the caption.\n * Tooltip shows the full `label`; the caption truncates at max-w-[52px].\n */\nexport function TapTargetLabeled({\n label,\n children,\n hideLabel = false,\n toolTipSide = \"bottom\",\n}: {\n label: string;\n children: React.ReactNode;\n hideLabel?: boolean | undefined;\n toolTipSide?: \"top\" | \"bottom\" | \"left\" | \"right\" | undefined;\n}) {\n return (\n <TooltipProvider delayDuration={200}>\n <Tooltip>\n <TooltipTrigger asChild>\n <div className=\"flex flex-col items-center p-0 gap-0 space-y-0 space-x-0 shrink-0\">\n {children}\n {!hideLabel && (\n <span className=\"text-[10px] text-muted-foreground/70 leading-tight max-w-[52px] text-center truncate\">\n {label}\n </span>\n )}\n </div>\n </TooltipTrigger>\n <TooltipContent side={toolTipSide}>\n <span className=\"font-mono text-xs max-w-[280px] break-all\">\n {label}\n </span>\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n );\n}\n"],"mappings":"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","names":["forwardRef","TooltipPrimitive","jsx","forwardRef","TapTargetButton","TapTargetButtonTransparent","TapTargetButtonSolid","TapTargetButtonDestructive","TapTargetButtonForGroup","jsx","jsxs"]}
|
|
1
|
+
{"version":3,"sources":["../src/tap-target-button.tsx","../src/tooltip.tsx","../src/cn.ts","../src/link.ts","../src/tap-target-labeled.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n cloneElement,\n forwardRef,\n isValidElement,\n type ButtonHTMLAttributes,\n type ReactElement,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport { TooltipContent, TooltipTrigger } from \"./tooltip\";\nimport { cn } from \"./cn\";\nimport {\n getTapTargetLinkComponent,\n type TapTargetLinkComponent,\n} from \"./link\";\n\nexport interface TapTargetButtonProps {\n icon?: React.ReactNode;\n children?: React.ReactNode;\n strokeWidth?: number | undefined;\n onClick?: (() => void) | undefined;\n className?: string | undefined;\n as?: \"button\" | \"label\" | undefined;\n htmlFor?: string | undefined;\n ariaLabel?: string | undefined;\n disabled?: boolean | undefined;\n /**\n * When set, the tap button renders as a link instead of a button.\n * - Internal hrefs (e.g. \"/tasks\") render via the injected link component\n * (`setTapTargetLinkComponent` / the `linkComponent` prop), falling back\n * to a plain `<a>` when none is registered.\n * - External hrefs (http://, https://, mailto:, tel:) render as `<a>`\n * with `target=\"_blank\"` and `rel=\"noopener noreferrer\"` by default.\n * - When combined with `disabled`, the trigger renders as a non-navigable\n * `<span aria-disabled=\"true\">` with the same visual styling.\n */\n href?: string | undefined;\n /** Override target. Works on both internal links and external anchors. */\n target?: \"_blank\" | \"_self\" | \"_parent\" | \"_top\" | undefined;\n /** Override rel. Works on both internal links and external anchors. */\n rel?: string | undefined;\n /** Forwarded to the injected link component. Pass `false` to disable prefetching. */\n prefetch?: boolean | null | undefined;\n /**\n * Per-instance link component for internal hrefs — overrides the\n * module-level `setTapTargetLinkComponent` registration.\n */\n linkComponent?: TapTargetLinkComponent | undefined;\n /**\n * Tooltip text. Defaults to `ariaLabel` when omitted.\n * Pass `false` to explicitly disable the tooltip.\n */\n tooltip?: string | false | undefined;\n /** Tooltip placement. Defaults to \"top\". */\n tooltipSide?: \"top\" | \"right\" | \"bottom\" | \"left\" | undefined;\n /** Tooltip alignment along its side. Defaults to \"center\". */\n tooltipAlign?: \"start\" | \"center\" | \"end\" | undefined;\n /**\n * Visible caption rendered inline after the icon (`[icon Label]`).\n * Widens the pill automatically. Tooltip defaults to off when set — the\n * label is self-describing. Visible text becomes the accessible name.\n */\n label?: string | undefined;\n /**\n * Collapse an icon + caption pill to its icon-only 44px tap target below\n * the `sm` breakpoint. The caption and inline geometry return at `sm+`;\n * `ariaLabel` (falling back to `label`) remains the accessible name.\n */\n mobileIconOnly?: boolean | undefined;\n}\n\nexport interface TapTargetButtonSolidProps extends TapTargetButtonProps {\n bgColor?: string | undefined;\n iconColor?: string | undefined;\n hoverBgColor?: string | undefined;\n /**\n * Press-state background. Defaults to `active:brightness-90` which works on\n * any color. Override when using a custom `bgColor` that should darken to a\n * specific shade on press (e.g. `active:bg-primary/60`).\n */\n activeBgColor?: string | undefined;\n}\n\nconst EXTERNAL_RE = /^(https?:|mailto:|tel:)/i;\n\n// Geometry + press feedback + tap hygiene are the SINGLE SOURCE OF TRUTH in\n// the shipped stylesheet (the `.matrx-tap-*` family in styles.css — import\n// \"@ai-matrx/tap-target/styles.css\" once at app root). This component only\n// picks the right class and layers each variant's decoration on top.\nconst TAP_OUTER_CLASS = \"matrx-tap-target group\";\nconst TAP_GROUP_OUTER_CLASS = \"matrx-tap-target matrx-tap-target-sm group\";\n\nfunction IconContent({\n icon,\n children,\n strokeWidth = 2,\n className,\n}: Pick<\n TapTargetButtonProps,\n \"icon\" | \"children\" | \"strokeWidth\" | \"className\"\n>) {\n if (icon) {\n if (isValidElement<{ className?: string }>(icon)) {\n return cloneElement(icon, {\n className: cn(className, icon.props.className),\n });\n }\n return <span className={className}>{icon}</span>;\n }\n return (\n <svg\n className={className}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={strokeWidth}\n >\n {children}\n </svg>\n );\n}\n\ntype TapTargetSize = \"default\" | \"sm\";\n\nfunction resolveTapGeometry(\n label: string | undefined,\n size: TapTargetSize,\n mobileIconOnly: boolean,\n) {\n const inline = Boolean(label);\n if (size === \"sm\") {\n return {\n outerClassName:\n inline && mobileIconOnly\n ? \"matrx-tap-target matrx-tap-target-sm matrx-tap-target-mobile-icon-only-sm group\"\n : inline\n ? \"matrx-tap-target matrx-tap-target-sm matrx-tap-target-inline-sm group\"\n : TAP_GROUP_OUTER_CLASS,\n inlineModifier: mobileIconOnly\n ? \"matrx-tap-pill-mobile-icon-only-sm\"\n : \"matrx-tap-pill-inline-sm\",\n };\n }\n return {\n outerClassName:\n inline && mobileIconOnly\n ? `${TAP_OUTER_CLASS} matrx-tap-target-mobile-icon-only`\n : inline\n ? `${TAP_OUTER_CLASS} matrx-tap-target-inline`\n : TAP_OUTER_CLASS,\n inlineModifier: mobileIconOnly\n ? \"matrx-tap-pill-mobile-icon-only\"\n : \"matrx-tap-pill-inline\",\n };\n}\n\nfunction buildTapInner({\n label,\n pillClassName,\n iconClassName,\n labelClassName,\n inlineModifier,\n icon,\n children,\n strokeWidth = 2,\n}: {\n label?: string | undefined;\n pillClassName: string;\n iconClassName: string;\n labelClassName?: string | undefined;\n inlineModifier: string;\n icon?: React.ReactNode;\n children?: React.ReactNode;\n strokeWidth?: number | undefined;\n}) {\n const iconEl = (\n <IconContent\n icon={icon}\n strokeWidth={strokeWidth}\n className={iconClassName}\n >\n {children}\n </IconContent>\n );\n const pillClasses = label\n ? `${pillClassName} ${inlineModifier}`.trim()\n : pillClassName;\n\n if (!label) {\n return <div className={pillClasses}>{iconEl}</div>;\n }\n\n return (\n <div className={pillClasses}>\n {iconEl}\n <span className={labelClassName ?? \"matrx-tap-label\"}>{label}</span>\n </div>\n );\n}\n\ninterface RenderTapTargetArgs extends Pick<\n TapTargetButtonProps,\n | \"icon\"\n | \"children\"\n | \"strokeWidth\"\n | \"label\"\n | \"mobileIconOnly\"\n | \"onClick\"\n | \"as\"\n | \"htmlFor\"\n | \"ariaLabel\"\n | \"disabled\"\n | \"href\"\n | \"target\"\n | \"rel\"\n | \"prefetch\"\n | \"linkComponent\"\n | \"tooltip\"\n | \"tooltipSide\"\n | \"tooltipAlign\"\n> {\n size?: TapTargetSize;\n pillClassName: string;\n iconClassName: string;\n labelClassName?: string | undefined;\n rest?: ButtonHTMLAttributes<HTMLButtonElement> | undefined;\n buttonRef?: Ref<HTMLButtonElement> | undefined;\n}\n\nfunction renderTapTarget({\n size = \"default\",\n pillClassName,\n iconClassName,\n labelClassName,\n icon,\n children,\n strokeWidth,\n label,\n mobileIconOnly = false,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n rest,\n buttonRef,\n}: RenderTapTargetArgs): ReactElement {\n const { outerClassName, inlineModifier } = resolveTapGeometry(\n label,\n size,\n mobileIconOnly,\n );\n const responsiveLabelClassName = mobileIconOnly\n ? `${labelClassName ?? \"matrx-tap-label\"} matrx-tap-label-mobile-icon-only`\n : labelClassName;\n const inner = buildTapInner({\n label,\n pillClassName,\n iconClassName,\n labelClassName: responsiveLabelClassName,\n inlineModifier: label ? inlineModifier : \"\",\n icon,\n children,\n strokeWidth,\n });\n const resolvedTooltip =\n tooltip !== undefined ? tooltip : label ? false : undefined;\n const triggerAriaLabel =\n label && !mobileIconOnly ? undefined : (ariaLabel ?? label);\n const trigger = renderTrigger({\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n as,\n htmlFor,\n onClick,\n ariaLabel: triggerAriaLabel,\n disabled,\n outerClassName,\n children: inner,\n rest,\n buttonRef,\n });\n return withTooltip(trigger, {\n tooltip: resolvedTooltip,\n ariaLabel: triggerAriaLabel,\n disabled,\n tooltipSide,\n tooltipAlign,\n });\n}\n\ninterface RenderTriggerArgs {\n href?: string | undefined;\n target?: \"_blank\" | \"_self\" | \"_parent\" | \"_top\" | undefined;\n rel?: string | undefined;\n prefetch?: boolean | null | undefined;\n linkComponent?: TapTargetLinkComponent | undefined;\n as?: \"button\" | \"label\" | undefined;\n htmlFor?: string | undefined;\n onClick?: (() => void) | undefined;\n ariaLabel?: string | undefined;\n disabled?: boolean | undefined;\n outerClassName: string;\n children: ReactNode;\n rest?: ButtonHTMLAttributes<HTMLButtonElement> | undefined;\n buttonRef?: Ref<HTMLButtonElement> | undefined;\n}\n\n/**\n * Resolves the correct trigger element based on the props passed.\n *\n * - `href` + `disabled` → unclickable `<span aria-disabled>`\n * - `href` matching `http(s):|mailto:|tel:` → `<a target=\"_blank\" rel=\"noopener noreferrer\">`\n * - `href` (internal) → the injected link component (per-instance\n * `linkComponent` prop, else `setTapTargetLinkComponent` registration),\n * falling back to a plain `<a>` when none is registered\n * - `as=\"label\"` → `<label htmlFor=...>`\n * - default → `<button>`\n */\nfunction renderTrigger({\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n as,\n htmlFor,\n onClick,\n ariaLabel,\n disabled,\n outerClassName,\n children,\n rest,\n buttonRef,\n}: RenderTriggerArgs): ReactElement {\n if (disabled && href) {\n return (\n <span\n aria-disabled=\"true\"\n aria-label={ariaLabel}\n className={`${outerClassName} opacity-40 pointer-events-none`}\n >\n {children}\n </span>\n );\n }\n if (href) {\n const isExternal = EXTERNAL_RE.test(href);\n if (isExternal) {\n return (\n <a\n href={href}\n target={target ?? \"_blank\"}\n rel={rel ?? \"noopener noreferrer\"}\n aria-label={ariaLabel}\n className={outerClassName}\n >\n {children}\n </a>\n );\n }\n const Link = linkComponent ?? getTapTargetLinkComponent();\n if (Link) {\n return (\n <Link\n href={href}\n target={target}\n rel={rel}\n prefetch={prefetch}\n aria-label={ariaLabel}\n className={outerClassName}\n >\n {children}\n </Link>\n );\n }\n // No link component registered — plain <a>. `prefetch` is a router hint,\n // not a DOM attribute, so it is deliberately dropped here.\n return (\n <a\n href={href}\n target={target}\n rel={rel}\n aria-label={ariaLabel}\n className={outerClassName}\n >\n {children}\n </a>\n );\n }\n if (as === \"label\") {\n return (\n <label\n htmlFor={htmlFor}\n aria-label={ariaLabel}\n className={outerClassName}\n >\n {children}\n </label>\n );\n }\n return (\n <button\n ref={buttonRef}\n type=\"button\"\n onClick={onClick}\n aria-label={ariaLabel}\n disabled={disabled}\n {...rest}\n className={outerClassName}\n >\n {children}\n </button>\n );\n}\n\n/**\n * Wraps a trigger element in a Tooltip when a tooltip label is available.\n * Falls back to `ariaLabel` when `tooltip` is not explicitly set. If both\n * are absent (or `tooltip === false`), the trigger is returned unwrapped.\n */\nfunction withTooltip(\n trigger: ReactElement,\n {\n tooltip,\n ariaLabel,\n disabled,\n tooltipSide = \"top\",\n tooltipAlign = \"center\",\n }: {\n tooltip?: string | false | undefined;\n ariaLabel?: string | undefined;\n disabled?: boolean | undefined;\n tooltipSide?: \"top\" | \"right\" | \"bottom\" | \"left\" | undefined;\n tooltipAlign?: \"start\" | \"center\" | \"end\" | undefined;\n },\n): ReactElement {\n if (tooltip === false) return trigger;\n const label =\n typeof tooltip === \"string\" && tooltip.length > 0 ? tooltip : ariaLabel;\n if (!label) return trigger;\n return (\n <TooltipPrimitive.Root>\n <TooltipTrigger asChild>\n {disabled ? (\n // Radix Tooltip triggers need a hoverable element; a disabled button\n // does not dispatch pointer events, so we wrap in a span for the\n // trigger target while keeping the disabled visual state.\n <span className=\"inline-flex\">{trigger}</span>\n ) : (\n trigger\n )}\n </TooltipTrigger>\n <TooltipContent side={tooltipSide} align={tooltipAlign}>\n {label}\n </TooltipContent>\n </TooltipPrimitive.Root>\n );\n}\n\n// To resize/retune every tap button, edit styles.css — not here.\n\nexport const TapTargetButton = forwardRef<\n HTMLButtonElement,\n TapTargetButtonProps & ButtonHTMLAttributes<HTMLButtonElement>\n>(function TapTargetButton(\n {\n icon,\n children,\n strokeWidth = 2,\n onClick,\n className,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n mobileIconOnly,\n ...rest\n },\n ref,\n) {\n const color = className ?? \"text-foreground\";\n return renderTapTarget({\n icon,\n children,\n strokeWidth,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n mobileIconOnly,\n pillClassName: \"matrx-tap-pill matrx-glass-thin-border\",\n iconClassName: `matrx-tap-icon ${color}`,\n rest,\n buttonRef: ref,\n });\n});\n\nexport const TapTargetButtonTransparent = forwardRef<\n HTMLButtonElement,\n TapTargetButtonProps & React.ButtonHTMLAttributes<HTMLButtonElement>\n>(function TapTargetButtonTransparent(\n {\n icon,\n children,\n strokeWidth = 2,\n onClick,\n className,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n mobileIconOnly,\n ...rest\n },\n ref,\n) {\n const color = className ?? \"text-foreground\";\n return renderTapTarget({\n icon,\n children,\n strokeWidth,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n mobileIconOnly,\n pillClassName:\n \"matrx-tap-pill hover:bg-muted active:bg-muted-foreground/15\",\n iconClassName: `matrx-tap-icon ${color}`,\n rest,\n buttonRef: ref,\n });\n});\n\nexport const TapTargetButtonSolid = forwardRef<\n HTMLButtonElement,\n TapTargetButtonSolidProps & React.ButtonHTMLAttributes<HTMLButtonElement>\n>(function TapTargetButtonSolid(\n {\n icon,\n children,\n strokeWidth = 2,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n bgColor = \"bg-primary\",\n iconColor = \"text-primary-foreground\",\n hoverBgColor = \"hover:bg-primary/80\",\n activeBgColor = \"active:brightness-90\",\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n mobileIconOnly,\n ...rest\n },\n ref,\n) {\n return renderTapTarget({\n icon,\n children,\n strokeWidth,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n mobileIconOnly,\n pillClassName: `matrx-tap-pill ${bgColor} ${iconColor} ${hoverBgColor} ${activeBgColor}`,\n iconClassName: `matrx-tap-icon ${iconColor}`,\n labelClassName: `matrx-tap-label ${iconColor}`,\n rest,\n buttonRef: ref,\n });\n});\n\n/** Solid destructive pill — delete/remove actions. White-on-red like the\n * primary solid is white-on-blue. Use THIS, never hand-pass bg-destructive\n * with the default (dark) icon color. */\nexport const TapTargetButtonDestructive = forwardRef<\n HTMLButtonElement,\n TapTargetButtonSolidProps & React.ButtonHTMLAttributes<HTMLButtonElement>\n>(function TapTargetButtonDestructive(\n {\n bgColor = \"bg-destructive\",\n iconColor = \"text-destructive-foreground\",\n hoverBgColor = \"hover:bg-destructive/90\",\n ...rest\n },\n ref,\n) {\n return (\n <TapTargetButtonSolid\n ref={ref}\n bgColor={bgColor}\n iconColor={iconColor}\n hoverBgColor={hoverBgColor}\n {...rest}\n />\n );\n});\n\nexport const TapTargetButtonForGroup = forwardRef<\n HTMLButtonElement,\n TapTargetButtonProps & ButtonHTMLAttributes<HTMLButtonElement>\n>(function TapTargetButtonForGroup(\n {\n icon,\n children,\n strokeWidth = 2,\n onClick,\n className,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n mobileIconOnly,\n ...rest\n },\n ref,\n) {\n const color = className ?? \"text-foreground\";\n return renderTapTarget({\n size: \"sm\",\n icon,\n children,\n strokeWidth,\n onClick,\n as,\n htmlFor,\n ariaLabel,\n disabled,\n href,\n target,\n rel,\n prefetch,\n linkComponent,\n tooltip,\n tooltipSide,\n tooltipAlign,\n label,\n mobileIconOnly,\n pillClassName: \"matrx-tap-pill matrx-tap-pill-sm matrx-glass-interactive\",\n iconClassName: `matrx-tap-icon ${color}`,\n labelClassName: `matrx-tap-label ${color}`,\n rest,\n buttonRef: ref,\n });\n});\n\nexport function TapTargetButtonGroup({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string | undefined;\n}) {\n return (\n <div\n className={\n className\n ? `relative inline-flex h-9 items-center ${className}`\n : \"relative inline-flex h-9 items-center\"\n }\n >\n <div className=\"pointer-events-none absolute inset-x-0 top-1/2 -translate-y-1/2 h-7 rounded-full matrx-glass-thin-border\" />\n {/* min-w-0 lets flexible children (e.g. a truncating filename) shrink\n under container pressure; fixed-size tap buttons are unaffected. */}\n <div className=\"relative flex min-w-0 items-center\">{children}</div>\n </div>\n );\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport { cn } from \"./cn\";\n\n/**\n * Inlined port of matrx-frontend `components/ui/tooltip.tsx` — the one `@/`\n * import the tap-target components consumed beyond `cn` and `next/link`.\n * Behavior deltas vs. the original, both documented in FEATURE.md:\n * - `useNestedPortalContainer` (a host-specific nested-overlay portal context)\n * is dropped: content portals to the Radix default (document.body).\n * - Everything else — unconditional Root render, popover-token styling — is\n * verbatim.\n *\n * Hosts must mount `TooltipProvider` once near the app root (matrx-frontend\n * already does); `TapTargetLabeled` brings its own provider like the original.\n */\nconst TooltipProvider = TooltipPrimitive.Provider;\n\nconst Tooltip = TooltipPrimitive.Root;\n\nconst TooltipTrigger = TooltipPrimitive.Trigger;\n\nconst TooltipContent = React.forwardRef<\n React.ComponentRef<typeof TooltipPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n // Neutral, theme-aware surface (popover tokens) so tooltip text is\n // ALWAYS legible in both light and dark mode — including rich content\n // that uses `text-muted-foreground`. A brand-colored `bg-primary`\n // background broke legibility for any non-default content.\n \"z-[10001] overflow-hidden rounded-md border border-border bg-popover px-3 py-1.5 text-xs text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n className,\n )}\n {...props}\n />\n </TooltipPrimitive.Portal>\n));\nTooltipContent.displayName = TooltipPrimitive.Content.displayName;\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };\n","/**\n * Minimal className join — the only piece of `cn` this package needs.\n * No tailwind-merge / clsx dependency by design: callers pass literal strings.\n */\nexport function cn(\n ...values: Array<string | null | undefined | false>\n): string {\n return values.filter(Boolean).join(\" \").trim();\n}\n","import type { ComponentType, ReactNode } from \"react\";\n\n/**\n * The injectable link seam — the package's replacement for the original\n * hard `next/link` import.\n *\n * Internal hrefs (anything NOT matching `http(s):`, `mailto:`, `tel:`) render\n * through the link component resolved here; external hrefs always render a\n * plain `<a target=\"_blank\" rel=\"noopener noreferrer\">`, exactly like the\n * original. When nothing is registered and no per-instance `linkComponent`\n * prop is given, internal hrefs fall back to a plain `<a>` (no prefetch, no\n * client-side routing — still a working link).\n */\nexport interface TapTargetLinkProps {\n href: string;\n target?: \"_blank\" | \"_self\" | \"_parent\" | \"_top\" | undefined;\n rel?: string | undefined;\n /** Router prefetch hint (next/link semantics). Plain `<a>` fallback ignores it. */\n prefetch?: boolean | null | undefined;\n \"aria-label\"?: string | undefined;\n className?: string | undefined;\n children?: ReactNode;\n}\n\nexport type TapTargetLinkComponent = ComponentType<TapTargetLinkProps>;\n\n/**\n * The registered component lives in a `Symbol.for` slot on `globalThis` — NOT\n * in module state — so it survives the module graph being instantiated more\n * than once: the `.` and `./buttons` dist bundles each inline the primitives\n * (tsup `splitting: false`), and a consumer may even mix `import` and\n * `require`. One registration must reach every copy.\n */\nconst LINK_SLOT = Symbol.for(\"@ai-matrx/tap-target:link-component\");\n\ntype GlobalWithLinkSlot = typeof globalThis & {\n [LINK_SLOT]?: TapTargetLinkComponent | null;\n};\n\n/**\n * Register the app's link component once at startup (e.g. `next/link`):\n *\n * ```tsx\n * import Link from \"next/link\";\n * import { setTapTargetLinkComponent } from \"@ai-matrx/tap-target\";\n * setTapTargetLinkComponent(Link);\n * ```\n *\n * Pass `null` to unregister (plain `<a>` fallback resumes).\n */\nexport function setTapTargetLinkComponent(\n component: TapTargetLinkComponent | null,\n): void {\n (globalThis as GlobalWithLinkSlot)[LINK_SLOT] = component;\n}\n\n/** The currently registered link component, or `null` when none is set. */\nexport function getTapTargetLinkComponent(): TapTargetLinkComponent | null {\n return (globalThis as GlobalWithLinkSlot)[LINK_SLOT] ?? null;\n}\n","\"use client\";\n\nimport {\n TooltipProvider,\n Tooltip,\n TooltipTrigger,\n TooltipContent,\n} from \"./tooltip\";\n\n/**\n * Wraps a TapTargetButton (or any tap control) like the button-demo page:\n * no extra padding on the control — only `gap-0.5` before the caption.\n * Tooltip shows the full `label`; the caption truncates at max-w-[52px].\n */\nexport function TapTargetLabeled({\n label,\n children,\n hideLabel = false,\n toolTipSide = \"bottom\",\n}: {\n label: string;\n children: React.ReactNode;\n hideLabel?: boolean | undefined;\n toolTipSide?: \"top\" | \"bottom\" | \"left\" | \"right\" | undefined;\n}) {\n return (\n <TooltipProvider delayDuration={200}>\n <Tooltip>\n <TooltipTrigger asChild>\n <div className=\"flex flex-col items-center p-0 gap-0 space-y-0 space-x-0 shrink-0\">\n {children}\n {!hideLabel && (\n <span className=\"text-[10px] text-muted-foreground/70 leading-tight max-w-[52px] text-center truncate\">\n {label}\n </span>\n )}\n </div>\n </TooltipTrigger>\n <TooltipContent side={toolTipSide}>\n <span className=\"font-mono text-xs max-w-[280px] break-all\">\n {label}\n </span>\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n );\n}\n"],"mappings":"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","names":["forwardRef","TooltipPrimitive","jsx","forwardRef","TapTargetButton","TapTargetButtonTransparent","TapTargetButtonSolid","TapTargetButtonDestructive","TapTargetButtonForGroup","jsx","jsxs"]}
|