@ai-matrx/design-system 0.18.21 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/content-transfer/alchemy.svg +1 -1
- package/dist/content-transfer/copy-transform.svg +1 -0
- package/dist/content-transfer/icon.cjs +8 -2
- package/dist/content-transfer/icon.cjs.map +1 -1
- package/dist/content-transfer/icon.d.cts +5 -3
- package/dist/content-transfer/icon.d.ts +5 -3
- package/dist/content-transfer/icon.js +8 -2
- package/dist/content-transfer/icon.js.map +1 -1
- package/dist/content-transfer/portal.svg +1 -0
- package/dist/content-transfer.cjs +923 -304
- package/dist/content-transfer.cjs.map +1 -1
- package/dist/content-transfer.css +17 -74
- package/dist/content-transfer.d.cts +14 -3
- package/dist/content-transfer.d.ts +14 -3
- package/dist/content-transfer.js +929 -305
- package/dist/content-transfer.js.map +1 -1
- package/dist/data-table/copy-helpers.d.cts +1 -1
- package/dist/data-table/copy-helpers.d.ts +1 -1
- package/dist/data-table/data-row-inspector.cjs +990 -397
- package/dist/data-table/data-row-inspector.cjs.map +1 -1
- package/dist/data-table/data-row-inspector.js +988 -390
- package/dist/data-table/data-row-inspector.js.map +1 -1
- package/dist/data-table/data-row-window.cjs +989 -396
- package/dist/data-table/data-row-window.cjs.map +1 -1
- package/dist/data-table/data-row-window.js +987 -389
- package/dist/data-table/data-row-window.js.map +1 -1
- package/dist/data-table/filter-engine.d.cts +1 -1
- package/dist/data-table/filter-engine.d.ts +1 -1
- package/dist/data-table/host.cjs.map +1 -1
- package/dist/data-table/host.d.cts +3 -2
- package/dist/data-table/host.d.ts +3 -2
- package/dist/data-table/host.js.map +1 -1
- package/dist/data-table/index.cjs +2733 -1441
- package/dist/data-table/index.cjs.map +1 -1
- package/dist/data-table/index.d.cts +2 -2
- package/dist/data-table/index.d.ts +2 -2
- package/dist/data-table/index.js +2742 -1440
- package/dist/data-table/index.js.map +1 -1
- package/dist/data-table/infer-filter.d.cts +1 -1
- package/dist/data-table/infer-filter.d.ts +1 -1
- package/dist/data-table/layered-filters.d.cts +1 -1
- package/dist/data-table/layered-filters.d.ts +1 -1
- package/dist/data-table/pagination.cjs +135 -97
- package/dist/data-table/pagination.cjs.map +1 -1
- package/dist/data-table/pagination.d.cts +8 -1
- package/dist/data-table/pagination.d.ts +8 -1
- package/dist/data-table/pagination.js +130 -92
- package/dist/data-table/pagination.js.map +1 -1
- package/dist/data-table/query-control.d.cts +1 -1
- package/dist/data-table/query-control.d.ts +1 -1
- package/dist/data-table/scroll-pagination.cjs +82 -54
- package/dist/data-table/scroll-pagination.cjs.map +1 -1
- package/dist/data-table/scroll-pagination.js +82 -54
- package/dist/data-table/scroll-pagination.js.map +1 -1
- package/dist/data-table/types.cjs.map +1 -1
- package/dist/data-table/types.d.cts +1 -1
- package/dist/data-table/types.d.ts +1 -1
- package/dist/data-table/url-state.cjs +7 -1
- package/dist/data-table/url-state.cjs.map +1 -1
- package/dist/data-table/url-state.d.cts +1 -1
- package/dist/data-table/url-state.d.ts +1 -1
- package/dist/data-table/url-state.js +7 -1
- package/dist/data-table/url-state.js.map +1 -1
- package/dist/data-table/uuid-cell.cjs +1 -1
- package/dist/data-table/uuid-cell.cjs.map +1 -1
- package/dist/data-table/uuid-cell.js +1 -1
- package/dist/data-table/uuid-cell.js.map +1 -1
- package/dist/data-table/xlsx.d.cts +1 -1
- package/dist/data-table/xlsx.d.ts +1 -1
- package/dist/index.cjs +527 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +531 -0
- package/dist/index.js.map +1 -1
- package/dist/tap-target.cjs +636 -0
- package/dist/tap-target.cjs.map +1 -0
- package/dist/tap-target.css +151 -0
- package/dist/tap-target.d.cts +131 -0
- package/dist/tap-target.d.ts +131 -0
- package/dist/tap-target.js +608 -0
- package/dist/tap-target.js.map +1 -0
- package/dist/{types-BuDKVpeF.d.ts → types-D1m14boM.d.ts} +49 -3
- package/dist/{types-Dqcb7jXO.d.cts → types-Di6QT0P1.d.cts} +49 -3
- package/package.json +14 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tap-target/index.ts","../src/tap-target/tap-target-button.tsx","../src/tooltip.tsx","../src/cn.ts","../src/motion.ts","../src/portal-container.tsx","../src/tap-target/cn.ts","../src/tap-target/link.ts","../src/tap-target/tap-target-labeled.tsx"],"sourcesContent":["export {\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","\"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\";\n\nimport { Tooltip, 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 <Tooltip>\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 </Tooltip>\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\n/**\n * Tooltip — the ONE tooltip in the fleet.\n *\n * THE COLLAPSE (0.6.0). Two implementations existed: matrx-frontend's\n * `components/ui/tooltip.tsx` (182 import sites) and `@ai-matrx/tap-target`'s\n * `src/tooltip.tsx` — the latter an explicit inlined PORT of the former,\n * carrying a header that said so. tap-target shipped it only because its ~60\n * tap buttons need a tooltip and no shared package owned one; four repos then\n * adopted `TooltipProvider` from tap-target. That made tap-target — a\n * button-geometry package — the accidental owner of a design-system primitive,\n * with a second copy living in the biggest host.\n *\n * A tooltip is a design-system surface, so it lives here. tap-target now takes\n * `@ai-matrx/design-system` as an ordinary sibling dependency and imports this\n * file; its own copy is deleted, and its re-export removed. The DAG already\n * ordered design-system before tap-target, so no cycle is introduced.\n *\n * BEHAVIOUR is matrx-frontend's, verbatim, including the ruling both copies\n * carried in prose:\n *\n * 1. THE ROOT RENDERS UNCONDITIONALLY — no hydration mount gate. The gate the\n * host wrapper once carried (\"Radix generates dynamic aria-controls ids that\n * differ between SSR and client\") was false: Radix ids come from React's\n * SSR-stable `useId`. It was actively harmful — a Trigger wraps\n * ALWAYS-VISIBLE content, so `return null` deleted that subtree from SSR and\n * the first client paint.\n *\n * 2. THE SURFACE IS NEUTRAL, NOT BRANDED. Popover tokens, not `bg-primary`:\n * rich tooltip content using `text-muted-foreground` was illegible on a\n * brand-coloured background in one theme or the other.\n *\n * SEAM INVERSION. The host resolved nested portal targets through\n * `useNestedPortalContainer` (an app hook wired to its dialog + window-panel\n * systems); tap-target's port dropped that seam entirely and always portalled\n * to `document.body` — which is why a tooltip inside a popped-out panel landed\n * in the wrong window. Here it is the package's `PortalContainerProvider`\n * seam: an explicit `container` prop wins, then the injected container, then\n * `document.body`. Both prior behaviours are reachable; neither is forked.\n */\n\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport * as React from \"react\";\n\nimport { cn } from \"./cn\";\nimport { MOTION_POPPER } from \"./motion\";\nimport { usePortalContainer } from \"./portal-container\";\n\n/**\n * Mount once near the app root. Every tooltip in the tree shares its\n * `delayDuration` / `skipDelayDuration` timing.\n */\nconst TooltipProvider = TooltipPrimitive.Provider;\n\nconst Tooltip = TooltipPrimitive.Root;\n\nconst TooltipTrigger = TooltipPrimitive.Trigger;\n\nexport interface TooltipContentProps\n extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> {\n /**\n * Explicit portal target; wins over the injected `PortalContainerProvider`\n * value. Pass `null` to force `document.body`.\n */\n container?: HTMLElement | null;\n /**\n * Package-owned open/close motion. Default `true`. Pass `false` for a\n * surface that must appear instantly. It is NOT the reduced-motion switch;\n * `styles.css` already honours `prefers-reduced-motion`.\n */\n animated?: boolean;\n}\n\nconst TooltipContent = React.forwardRef<\n React.ComponentRef<typeof TooltipPrimitive.Content>,\n TooltipContentProps\n>(({ className, sideOffset = 4, container, animated = true, ...props }, ref) => {\n const resolved = usePortalContainer(container);\n return (\n <TooltipPrimitive.Portal container={resolved ?? null}>\n <TooltipPrimitive.Content\n ref={ref}\n data-slot=\"tooltip-content\"\n sideOffset={sideOffset}\n className={cn(\n \"z-[10001] overflow-hidden rounded-md border border-border bg-popover px-3 py-1.5 text-xs text-popover-foreground shadow-md\",\n animated && MOTION_POPPER,\n className,\n )}\n {...props}\n />\n </TooltipPrimitive.Portal>\n );\n});\nTooltipContent.displayName = TooltipPrimitive.Content.displayName;\n\nexport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * THE MOTION CONTRACT (0.10.0) — the class names every animated surface in\n * this package puts on the DOM, in ONE place.\n *\n * Why a module and not ten inline strings: the sweep that produced this file\n * found the same defect ten times over, and it was invisible each time\n * because each primitive spelled its animation out by hand. Ten hand-written\n * copies of `data-[state=open]:animate-in data-[state=closed]:animate-out\n * data-[state=closed]:fade-out-0 …` meant ten chances to reach for a utility\n * nothing in the package defines — which is exactly what happened. A single\n * exported constant per motion SHAPE means the next primitive cannot invent\n * an eleventh spelling, and `styles.test.ts` can prove every one of them\n * resolves to a rule in the shipped stylesheet.\n *\n * Every rule these name lives in `styles.css` under the package's own\n * keyframes. NONE of them is a Tailwind utility, and none requires a host\n * plugin — see that file's header for the measurement that made this\n * necessary.\n */\n\n/** Modal scrims: Dialog, AlertDialog, Sheet, CommandDialog. Fade only. */\nexport const MOTION_OVERLAY = \"matrx-motion-overlay\";\n\n/** The centred dialog card. Fades and scales; centring is not its business. */\nexport const MOTION_DIALOG = \"matrx-motion-dialog\";\n\n/**\n * THE CENTRING OF A CENTRED DIALOG CARD — package-owned, in the `translate`\n * property, and NEVER a Tailwind `translate-x-[-50%] translate-y-[-50%]` pair.\n *\n * Those utilities do not compile to the same thing in every host: Tailwind v3\n * writes them into `transform`, Tailwind v4 writes them into the independent\n * `translate` property, which COMPOSES with `transform` instead of being\n * replaced by it. 0.10.0's keyframes restated the centring inside `transform`,\n * which was harmless on v3 and doubled the centring on v4 — the card flew in\n * from off the top-left of the viewport for the animation's whole duration and\n * snapped into place at the end (fixed in 0.10.1).\n *\n * Owning it here means one spelling that reads the same on both, and it frees\n * `transform` so the keyframes carry ONLY the delta. Put this on every centred\n * surface UNCONDITIONALLY — it is geometry, so unlike {@link MOTION_DIALOG} it\n * must survive `animated={false}`. Its rule ships in `styles.css`.\n */\nexport const CENTERED_DIALOG = \"matrx-dialog-centered\";\n\n/**\n * The resting gap between a `popper`-positioned surface and its trigger, for\n * the primitives that want one (today: `Select`). Same law and same reason as\n * {@link CENTERED_DIALOG} — a position an animated surface holds AT REST is\n * the `translate` property's job, never a Tailwind translate utility, because\n * those land in `transform` on a v3 host and in `translate` on a v4 one while\n * the keyframes animate `transform` either way. Sizes from\n * `--matrx-popper-offset`; keys off Radix's `data-side`.\n */\nexport const POPPER_OFFSET = \"matrx-popper-offset\";\n\n/** The mobile Dialog / CommandDialog bottom sheet. Slides up and fades. */\nexport const MOTION_BOTTOM_SHEET = \"matrx-motion-bottom-sheet\";\n\n/**\n * Radix-popper surfaces: Popover, DropdownMenu, ContextMenu, HoverCard,\n * Select, Tooltip. Reads `--radix-popper-transform-origin` so the surface\n * grows out of its trigger, and `data-side` so it travels from it.\n */\nexport const MOTION_POPPER = \"matrx-motion-popper\";\n\n/** Edge sheets, one class per `sheetVariants` side. */\nexport const MOTION_SHEET = {\n top: \"matrx-motion-sheet-top\",\n bottom: \"matrx-motion-sheet-bottom\",\n left: \"matrx-motion-sheet-left\",\n right: \"matrx-motion-sheet-right\",\n center: \"matrx-motion-sheet-center\",\n} as const;\n\n/** Skeleton's breathing loop. */\nexport const MOTION_PULSE = \"matrx-pulse\";\n\n/** The spinner loop, for every inline busy indicator in the package. */\nexport const MOTION_SPIN = \"matrx-spin\";\n\n/**\n * Every motion class the package ships, for the guards. If a rule for one of\n * these is missing from `styles.css`, a component animates in no consumer and\n * says nothing about it — the C26 failure this list exists to make loud.\n */\nexport const ALL_MOTION_CLASSES = [\n MOTION_OVERLAY,\n MOTION_DIALOG,\n MOTION_BOTTOM_SHEET,\n MOTION_POPPER,\n ...Object.values(MOTION_SHEET),\n MOTION_PULSE,\n MOTION_SPIN,\n] as const;\n\n/**\n * The host-plugin utilities this package is forbidden to emit. They are\n * supplied by `tailwindcss-animate` / `tw-animate-css`, which is a HOST CSS\n * entry concern a package cannot declare a dependency on: three of the four\n * AI Matrx consumers never loaded it, so every surface wearing these appeared\n * with no animation and no error. `styles.test.ts` fails the build if one\n * comes back.\n */\nexport const FORBIDDEN_HOST_MOTION_UTILITIES = [\n \"animate-in\",\n \"animate-out\",\n \"fade-in\",\n \"fade-out\",\n \"zoom-in\",\n \"zoom-out\",\n \"slide-in-from\",\n \"slide-out-to\",\n \"animate-accordion\",\n \"animate-slide-down\",\n \"animate-slide-up\",\n \"animate-pulse\",\n \"animate-spin\",\n] as const;\n","\"use client\";\n\n/**\n * Injected portal-container seam.\n *\n * The matrx-frontend original resolved nested portal targets through\n * `useNestedPortalContainer` (explicit prop > dialog content > popout body >\n * document.body) — a host-shaped hook wired to that app's dialog and\n * window-panel systems. The package inverts the seam: hosts provide the\n * resolved container through `PortalContainerProvider`; an explicit\n * `container` prop on a component still wins, and with neither the portal\n * falls through to `document.body` (Radix default). Priority semantics are\n * unchanged from the original.\n */\n\nimport * as React from \"react\";\n\n// Shared identity across independently bundled public entrypoints/loaders.\nconst CONTEXT_SLOT = Symbol.for(\"ai-matrx.design-system.portal-container-context\");\nconst contextRegistry = globalThis as typeof globalThis & { [CONTEXT_SLOT]?: React.Context<HTMLElement | null | undefined> };\nconst PortalContainerContext = contextRegistry[CONTEXT_SLOT] ??= React.createContext<HTMLElement | null | undefined>(undefined);\n\nexport interface PortalContainerProviderProps {\n /** Where nested Radix portals (Popover, etc.) should mount. `null`/`undefined` → document.body. */\n container: HTMLElement | null | undefined;\n children: React.ReactNode;\n}\n\nexport function PortalContainerProvider({\n container,\n children,\n}: PortalContainerProviderProps) {\n return (\n <PortalContainerContext.Provider value={container ?? undefined}>\n {children}\n </PortalContainerContext.Provider>\n );\n}\n\n/**\n * Resolve a portal target: explicit prop (including an explicit `null`,\n * meaning \"the default body\") beats the injected container.\n */\nexport function usePortalContainer(\n explicit?: HTMLElement | null,\n): HTMLElement | undefined {\n const injected = React.useContext(PortalContainerContext);\n\n if (explicit !== undefined) {\n return explicit ?? undefined;\n }\n\n return injected ?? undefined;\n}\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 { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } 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":["React","import_jsx_runtime","cn","import_jsx_runtime","cn","TapTargetButton","TapTargetButtonTransparent","TapTargetButtonSolid","TapTargetButtonDestructive","TapTargetButtonForGroup","import_jsx_runtime"]}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/* @ai-matrx/tap-target — REQUIRED stylesheet. Import once at your app root:
|
|
2
|
+
import "@ai-matrx/tap-target/styles.css";
|
|
3
|
+
Extracted VERBATIM from matrx-frontend app/globals.css (where it lives inside
|
|
4
|
+
`@layer components`; shipped unlayered here so it wins against unlayered host
|
|
5
|
+
CSS without requiring a layer-order declaration). Until the C9 swap removes
|
|
6
|
+
the matrx-frontend originals, any change here ships in BOTH places. */
|
|
7
|
+
|
|
8
|
+
/* Loaded by design-system/styles.css through content-transfer.css. */
|
|
9
|
+
|
|
10
|
+
/* =========================================================================
|
|
11
|
+
TapTargetButton — SINGLE SOURCE OF TRUTH for tap-button geometry + feedback.
|
|
12
|
+
This is the ONLY place these are defined (previously also duplicated in
|
|
13
|
+
styles/shell.css, which caused the same button to resolve differently
|
|
14
|
+
inside vs outside the shell). Consumed exclusively by
|
|
15
|
+
components/icons/TapTargetButton.tsx. To resize or retune EVERY tap button
|
|
16
|
+
in the app, edit HERE — nowhere else.
|
|
17
|
+
|
|
18
|
+
Structure per button:
|
|
19
|
+
.matrx-tap-target — outer 44px invisible touch target = the interactive
|
|
20
|
+
element (<button>/<a>/<label>). It owns the tap
|
|
21
|
+
hygiene (touch-action + tap-highlight) so it applies
|
|
22
|
+
to the WHOLE 44px target AND to the link variants —
|
|
23
|
+
the iOS gray flash paints on the anchor, not the
|
|
24
|
+
inner pill, so putting it on the pill never worked.
|
|
25
|
+
.matrx-tap-pill — inner 28px visible pill. Geometry + press feedback.
|
|
26
|
+
Each variant layers ONLY its decoration on top (glass
|
|
27
|
+
border / solid fill / hover bg) — the size is identical
|
|
28
|
+
across glass / transparent / solid, guaranteed here.
|
|
29
|
+
.matrx-tap-icon — 14px icon.
|
|
30
|
+
.matrx-tap-*-inline — wider auto-width geometry when `label` is set on
|
|
31
|
+
TapTargetButton (icon + caption on one row).
|
|
32
|
+
The `-sm` classes (32 / 20px) are the slimmer geometry used inside groups.
|
|
33
|
+
========================================================================= */
|
|
34
|
+
.matrx-tap-target {
|
|
35
|
+
display: flex;
|
|
36
|
+
height: 2.75rem; /* 44px outer tap target */
|
|
37
|
+
width: 2.75rem;
|
|
38
|
+
flex-shrink: 0; /* a tap target never squishes under flex pressure —
|
|
39
|
+
flexible neighbors (truncating labels) absorb it */
|
|
40
|
+
align-items: center;
|
|
41
|
+
justify-content: center;
|
|
42
|
+
background-color: transparent;
|
|
43
|
+
cursor: pointer;
|
|
44
|
+
outline: none;
|
|
45
|
+
touch-action: manipulation; /* kills the 300ms mobile tap delay */
|
|
46
|
+
-webkit-tap-highlight-color: transparent; /* kills the iOS gray tap flash */
|
|
47
|
+
}
|
|
48
|
+
.matrx-tap-target:disabled {
|
|
49
|
+
opacity: 0.4;
|
|
50
|
+
pointer-events: none;
|
|
51
|
+
}
|
|
52
|
+
.matrx-tap-target-sm {
|
|
53
|
+
height: 2rem; /* 32px */
|
|
54
|
+
width: 2rem;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.matrx-tap-pill {
|
|
58
|
+
display: flex;
|
|
59
|
+
height: 1.75rem; /* 28px visible pill */
|
|
60
|
+
width: 1.75rem;
|
|
61
|
+
align-items: center;
|
|
62
|
+
justify-content: center;
|
|
63
|
+
border-radius: 9999px;
|
|
64
|
+
transition:
|
|
65
|
+
background-color 150ms ease,
|
|
66
|
+
transform 100ms ease;
|
|
67
|
+
}
|
|
68
|
+
.matrx-tap-pill:active {
|
|
69
|
+
transform: scale(0.92);
|
|
70
|
+
}
|
|
71
|
+
.matrx-tap-target:focus-visible .matrx-tap-pill {
|
|
72
|
+
outline: 2px solid hsl(var(--ring, 240 5% 65%));
|
|
73
|
+
outline-offset: 2px;
|
|
74
|
+
}
|
|
75
|
+
.matrx-tap-pill-sm {
|
|
76
|
+
height: 1.25rem; /* 20px */
|
|
77
|
+
width: 1.25rem;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.matrx-tap-icon {
|
|
81
|
+
height: 0.875rem; /* 14px */
|
|
82
|
+
width: 0.875rem;
|
|
83
|
+
flex-shrink: 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* Inline label — icon + text on one row inside the pill */
|
|
87
|
+
.matrx-tap-target-inline {
|
|
88
|
+
width: auto;
|
|
89
|
+
min-width: 2.75rem;
|
|
90
|
+
padding-inline: 0.25rem;
|
|
91
|
+
}
|
|
92
|
+
.matrx-tap-pill-inline {
|
|
93
|
+
width: auto;
|
|
94
|
+
gap: 0.375rem;
|
|
95
|
+
padding-inline: 0.625rem;
|
|
96
|
+
}
|
|
97
|
+
.matrx-tap-label {
|
|
98
|
+
font-size: 0.75rem;
|
|
99
|
+
font-weight: 500;
|
|
100
|
+
line-height: 1;
|
|
101
|
+
white-space: nowrap;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.matrx-tap-target-inline-sm {
|
|
105
|
+
width: auto;
|
|
106
|
+
min-width: 2rem;
|
|
107
|
+
padding-inline: 0.125rem;
|
|
108
|
+
}
|
|
109
|
+
.matrx-tap-pill-inline-sm {
|
|
110
|
+
width: auto;
|
|
111
|
+
gap: 0.25rem;
|
|
112
|
+
padding-inline: 0.5rem;
|
|
113
|
+
}
|
|
114
|
+
.matrx-tap-pill-inline-sm .matrx-tap-label {
|
|
115
|
+
font-size: 0.625rem;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* Icon-only on phones, icon + caption from `sm` upward. Keep this geometry
|
|
119
|
+
in the canonical tap system so responsive header actions never hand-roll
|
|
120
|
+
smaller targets or duplicate controls at each breakpoint. */
|
|
121
|
+
.matrx-tap-label-mobile-icon-only {
|
|
122
|
+
display: none;
|
|
123
|
+
}
|
|
124
|
+
@media (min-width: 40rem) {
|
|
125
|
+
.matrx-tap-target-mobile-icon-only {
|
|
126
|
+
width: auto;
|
|
127
|
+
min-width: 2.75rem;
|
|
128
|
+
padding-inline: 0.25rem;
|
|
129
|
+
}
|
|
130
|
+
.matrx-tap-pill-mobile-icon-only {
|
|
131
|
+
width: auto;
|
|
132
|
+
gap: 0.375rem;
|
|
133
|
+
padding-inline: 0.625rem;
|
|
134
|
+
}
|
|
135
|
+
.matrx-tap-target-mobile-icon-only-sm {
|
|
136
|
+
width: auto;
|
|
137
|
+
min-width: 2rem;
|
|
138
|
+
padding-inline: 0.125rem;
|
|
139
|
+
}
|
|
140
|
+
.matrx-tap-pill-mobile-icon-only-sm {
|
|
141
|
+
width: auto;
|
|
142
|
+
gap: 0.25rem;
|
|
143
|
+
padding-inline: 0.5rem;
|
|
144
|
+
}
|
|
145
|
+
.matrx-tap-pill-mobile-icon-only-sm .matrx-tap-label {
|
|
146
|
+
font-size: 0.625rem;
|
|
147
|
+
}
|
|
148
|
+
.matrx-tap-label-mobile-icon-only {
|
|
149
|
+
display: inline;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import * as React$1 from 'react';
|
|
2
|
+
import { ComponentType, ReactNode, ButtonHTMLAttributes } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The injectable link seam — the package's replacement for the original
|
|
6
|
+
* hard `next/link` import.
|
|
7
|
+
*
|
|
8
|
+
* Internal hrefs (anything NOT matching `http(s):`, `mailto:`, `tel:`) render
|
|
9
|
+
* through the link component resolved here; external hrefs always render a
|
|
10
|
+
* plain `<a target="_blank" rel="noopener noreferrer">`, exactly like the
|
|
11
|
+
* original. When nothing is registered and no per-instance `linkComponent`
|
|
12
|
+
* prop is given, internal hrefs fall back to a plain `<a>` (no prefetch, no
|
|
13
|
+
* client-side routing — still a working link).
|
|
14
|
+
*/
|
|
15
|
+
interface TapTargetLinkProps {
|
|
16
|
+
href: string;
|
|
17
|
+
target?: "_blank" | "_self" | "_parent" | "_top" | undefined;
|
|
18
|
+
rel?: string | undefined;
|
|
19
|
+
/** Router prefetch hint (next/link semantics). Plain `<a>` fallback ignores it. */
|
|
20
|
+
prefetch?: boolean | null | undefined;
|
|
21
|
+
"aria-label"?: string | undefined;
|
|
22
|
+
className?: string | undefined;
|
|
23
|
+
children?: ReactNode;
|
|
24
|
+
}
|
|
25
|
+
type TapTargetLinkComponent = ComponentType<TapTargetLinkProps>;
|
|
26
|
+
/**
|
|
27
|
+
* Register the app's link component once at startup (e.g. `next/link`):
|
|
28
|
+
*
|
|
29
|
+
* ```tsx
|
|
30
|
+
* import Link from "next/link";
|
|
31
|
+
* import { setTapTargetLinkComponent } from "@ai-matrx/tap-target";
|
|
32
|
+
* setTapTargetLinkComponent(Link);
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* Pass `null` to unregister (plain `<a>` fallback resumes).
|
|
36
|
+
*/
|
|
37
|
+
declare function setTapTargetLinkComponent(component: TapTargetLinkComponent | null): void;
|
|
38
|
+
/** The currently registered link component, or `null` when none is set. */
|
|
39
|
+
declare function getTapTargetLinkComponent(): TapTargetLinkComponent | null;
|
|
40
|
+
|
|
41
|
+
interface TapTargetButtonProps {
|
|
42
|
+
icon?: React.ReactNode;
|
|
43
|
+
children?: React.ReactNode;
|
|
44
|
+
strokeWidth?: number | undefined;
|
|
45
|
+
onClick?: (() => void) | undefined;
|
|
46
|
+
className?: string | undefined;
|
|
47
|
+
as?: "button" | "label" | undefined;
|
|
48
|
+
htmlFor?: string | undefined;
|
|
49
|
+
ariaLabel?: string | undefined;
|
|
50
|
+
disabled?: boolean | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* When set, the tap button renders as a link instead of a button.
|
|
53
|
+
* - Internal hrefs (e.g. "/tasks") render via the injected link component
|
|
54
|
+
* (`setTapTargetLinkComponent` / the `linkComponent` prop), falling back
|
|
55
|
+
* to a plain `<a>` when none is registered.
|
|
56
|
+
* - External hrefs (http://, https://, mailto:, tel:) render as `<a>`
|
|
57
|
+
* with `target="_blank"` and `rel="noopener noreferrer"` by default.
|
|
58
|
+
* - When combined with `disabled`, the trigger renders as a non-navigable
|
|
59
|
+
* `<span aria-disabled="true">` with the same visual styling.
|
|
60
|
+
*/
|
|
61
|
+
href?: string | undefined;
|
|
62
|
+
/** Override target. Works on both internal links and external anchors. */
|
|
63
|
+
target?: "_blank" | "_self" | "_parent" | "_top" | undefined;
|
|
64
|
+
/** Override rel. Works on both internal links and external anchors. */
|
|
65
|
+
rel?: string | undefined;
|
|
66
|
+
/** Forwarded to the injected link component. Pass `false` to disable prefetching. */
|
|
67
|
+
prefetch?: boolean | null | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* Per-instance link component for internal hrefs — overrides the
|
|
70
|
+
* module-level `setTapTargetLinkComponent` registration.
|
|
71
|
+
*/
|
|
72
|
+
linkComponent?: TapTargetLinkComponent | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Tooltip text. Defaults to `ariaLabel` when omitted.
|
|
75
|
+
* Pass `false` to explicitly disable the tooltip.
|
|
76
|
+
*/
|
|
77
|
+
tooltip?: string | false | undefined;
|
|
78
|
+
/** Tooltip placement. Defaults to "top". */
|
|
79
|
+
tooltipSide?: "top" | "right" | "bottom" | "left" | undefined;
|
|
80
|
+
/** Tooltip alignment along its side. Defaults to "center". */
|
|
81
|
+
tooltipAlign?: "start" | "center" | "end" | undefined;
|
|
82
|
+
/**
|
|
83
|
+
* Visible caption rendered inline after the icon (`[icon Label]`).
|
|
84
|
+
* Widens the pill automatically. Tooltip defaults to off when set — the
|
|
85
|
+
* label is self-describing. Visible text becomes the accessible name.
|
|
86
|
+
*/
|
|
87
|
+
label?: string | undefined;
|
|
88
|
+
/**
|
|
89
|
+
* Collapse an icon + caption pill to its icon-only 44px tap target below
|
|
90
|
+
* the `sm` breakpoint. The caption and inline geometry return at `sm+`;
|
|
91
|
+
* `ariaLabel` (falling back to `label`) remains the accessible name.
|
|
92
|
+
*/
|
|
93
|
+
mobileIconOnly?: boolean | undefined;
|
|
94
|
+
}
|
|
95
|
+
interface TapTargetButtonSolidProps extends TapTargetButtonProps {
|
|
96
|
+
bgColor?: string | undefined;
|
|
97
|
+
iconColor?: string | undefined;
|
|
98
|
+
hoverBgColor?: string | undefined;
|
|
99
|
+
/**
|
|
100
|
+
* Press-state background. Defaults to `active:brightness-90` which works on
|
|
101
|
+
* any color. Override when using a custom `bgColor` that should darken to a
|
|
102
|
+
* specific shade on press (e.g. `active:bg-primary/60`).
|
|
103
|
+
*/
|
|
104
|
+
activeBgColor?: string | undefined;
|
|
105
|
+
}
|
|
106
|
+
declare const TapTargetButton: React$1.ForwardRefExoticComponent<TapTargetButtonProps & ButtonHTMLAttributes<HTMLButtonElement> & React$1.RefAttributes<HTMLButtonElement>>;
|
|
107
|
+
declare const TapTargetButtonTransparent: React$1.ForwardRefExoticComponent<TapTargetButtonProps & ButtonHTMLAttributes<HTMLButtonElement> & React$1.RefAttributes<HTMLButtonElement>>;
|
|
108
|
+
declare const TapTargetButtonSolid: React$1.ForwardRefExoticComponent<TapTargetButtonSolidProps & ButtonHTMLAttributes<HTMLButtonElement> & React$1.RefAttributes<HTMLButtonElement>>;
|
|
109
|
+
/** Solid destructive pill — delete/remove actions. White-on-red like the
|
|
110
|
+
* primary solid is white-on-blue. Use THIS, never hand-pass bg-destructive
|
|
111
|
+
* with the default (dark) icon color. */
|
|
112
|
+
declare const TapTargetButtonDestructive: React$1.ForwardRefExoticComponent<TapTargetButtonSolidProps & ButtonHTMLAttributes<HTMLButtonElement> & React$1.RefAttributes<HTMLButtonElement>>;
|
|
113
|
+
declare const TapTargetButtonForGroup: React$1.ForwardRefExoticComponent<TapTargetButtonProps & ButtonHTMLAttributes<HTMLButtonElement> & React$1.RefAttributes<HTMLButtonElement>>;
|
|
114
|
+
declare function TapTargetButtonGroup({ children, className, }: {
|
|
115
|
+
children: React.ReactNode;
|
|
116
|
+
className?: string | undefined;
|
|
117
|
+
}): React$1.JSX.Element;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Wraps a TapTargetButton (or any tap control) like the button-demo page:
|
|
121
|
+
* no extra padding on the control — only `gap-0.5` before the caption.
|
|
122
|
+
* Tooltip shows the full `label`; the caption truncates at max-w-[52px].
|
|
123
|
+
*/
|
|
124
|
+
declare function TapTargetLabeled({ label, children, hideLabel, toolTipSide, }: {
|
|
125
|
+
label: string;
|
|
126
|
+
children: React.ReactNode;
|
|
127
|
+
hideLabel?: boolean | undefined;
|
|
128
|
+
toolTipSide?: "top" | "bottom" | "left" | "right" | undefined;
|
|
129
|
+
}): React$1.JSX.Element;
|
|
130
|
+
|
|
131
|
+
export { TapTargetButton, TapTargetButtonDestructive, TapTargetButtonForGroup, TapTargetButtonGroup, type TapTargetButtonProps, TapTargetButtonSolid, type TapTargetButtonSolidProps, TapTargetButtonTransparent, TapTargetLabeled, type TapTargetLinkComponent, type TapTargetLinkProps, getTapTargetLinkComponent, setTapTargetLinkComponent };
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import * as React$1 from 'react';
|
|
2
|
+
import { ComponentType, ReactNode, ButtonHTMLAttributes } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The injectable link seam — the package's replacement for the original
|
|
6
|
+
* hard `next/link` import.
|
|
7
|
+
*
|
|
8
|
+
* Internal hrefs (anything NOT matching `http(s):`, `mailto:`, `tel:`) render
|
|
9
|
+
* through the link component resolved here; external hrefs always render a
|
|
10
|
+
* plain `<a target="_blank" rel="noopener noreferrer">`, exactly like the
|
|
11
|
+
* original. When nothing is registered and no per-instance `linkComponent`
|
|
12
|
+
* prop is given, internal hrefs fall back to a plain `<a>` (no prefetch, no
|
|
13
|
+
* client-side routing — still a working link).
|
|
14
|
+
*/
|
|
15
|
+
interface TapTargetLinkProps {
|
|
16
|
+
href: string;
|
|
17
|
+
target?: "_blank" | "_self" | "_parent" | "_top" | undefined;
|
|
18
|
+
rel?: string | undefined;
|
|
19
|
+
/** Router prefetch hint (next/link semantics). Plain `<a>` fallback ignores it. */
|
|
20
|
+
prefetch?: boolean | null | undefined;
|
|
21
|
+
"aria-label"?: string | undefined;
|
|
22
|
+
className?: string | undefined;
|
|
23
|
+
children?: ReactNode;
|
|
24
|
+
}
|
|
25
|
+
type TapTargetLinkComponent = ComponentType<TapTargetLinkProps>;
|
|
26
|
+
/**
|
|
27
|
+
* Register the app's link component once at startup (e.g. `next/link`):
|
|
28
|
+
*
|
|
29
|
+
* ```tsx
|
|
30
|
+
* import Link from "next/link";
|
|
31
|
+
* import { setTapTargetLinkComponent } from "@ai-matrx/tap-target";
|
|
32
|
+
* setTapTargetLinkComponent(Link);
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* Pass `null` to unregister (plain `<a>` fallback resumes).
|
|
36
|
+
*/
|
|
37
|
+
declare function setTapTargetLinkComponent(component: TapTargetLinkComponent | null): void;
|
|
38
|
+
/** The currently registered link component, or `null` when none is set. */
|
|
39
|
+
declare function getTapTargetLinkComponent(): TapTargetLinkComponent | null;
|
|
40
|
+
|
|
41
|
+
interface TapTargetButtonProps {
|
|
42
|
+
icon?: React.ReactNode;
|
|
43
|
+
children?: React.ReactNode;
|
|
44
|
+
strokeWidth?: number | undefined;
|
|
45
|
+
onClick?: (() => void) | undefined;
|
|
46
|
+
className?: string | undefined;
|
|
47
|
+
as?: "button" | "label" | undefined;
|
|
48
|
+
htmlFor?: string | undefined;
|
|
49
|
+
ariaLabel?: string | undefined;
|
|
50
|
+
disabled?: boolean | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* When set, the tap button renders as a link instead of a button.
|
|
53
|
+
* - Internal hrefs (e.g. "/tasks") render via the injected link component
|
|
54
|
+
* (`setTapTargetLinkComponent` / the `linkComponent` prop), falling back
|
|
55
|
+
* to a plain `<a>` when none is registered.
|
|
56
|
+
* - External hrefs (http://, https://, mailto:, tel:) render as `<a>`
|
|
57
|
+
* with `target="_blank"` and `rel="noopener noreferrer"` by default.
|
|
58
|
+
* - When combined with `disabled`, the trigger renders as a non-navigable
|
|
59
|
+
* `<span aria-disabled="true">` with the same visual styling.
|
|
60
|
+
*/
|
|
61
|
+
href?: string | undefined;
|
|
62
|
+
/** Override target. Works on both internal links and external anchors. */
|
|
63
|
+
target?: "_blank" | "_self" | "_parent" | "_top" | undefined;
|
|
64
|
+
/** Override rel. Works on both internal links and external anchors. */
|
|
65
|
+
rel?: string | undefined;
|
|
66
|
+
/** Forwarded to the injected link component. Pass `false` to disable prefetching. */
|
|
67
|
+
prefetch?: boolean | null | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* Per-instance link component for internal hrefs — overrides the
|
|
70
|
+
* module-level `setTapTargetLinkComponent` registration.
|
|
71
|
+
*/
|
|
72
|
+
linkComponent?: TapTargetLinkComponent | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Tooltip text. Defaults to `ariaLabel` when omitted.
|
|
75
|
+
* Pass `false` to explicitly disable the tooltip.
|
|
76
|
+
*/
|
|
77
|
+
tooltip?: string | false | undefined;
|
|
78
|
+
/** Tooltip placement. Defaults to "top". */
|
|
79
|
+
tooltipSide?: "top" | "right" | "bottom" | "left" | undefined;
|
|
80
|
+
/** Tooltip alignment along its side. Defaults to "center". */
|
|
81
|
+
tooltipAlign?: "start" | "center" | "end" | undefined;
|
|
82
|
+
/**
|
|
83
|
+
* Visible caption rendered inline after the icon (`[icon Label]`).
|
|
84
|
+
* Widens the pill automatically. Tooltip defaults to off when set — the
|
|
85
|
+
* label is self-describing. Visible text becomes the accessible name.
|
|
86
|
+
*/
|
|
87
|
+
label?: string | undefined;
|
|
88
|
+
/**
|
|
89
|
+
* Collapse an icon + caption pill to its icon-only 44px tap target below
|
|
90
|
+
* the `sm` breakpoint. The caption and inline geometry return at `sm+`;
|
|
91
|
+
* `ariaLabel` (falling back to `label`) remains the accessible name.
|
|
92
|
+
*/
|
|
93
|
+
mobileIconOnly?: boolean | undefined;
|
|
94
|
+
}
|
|
95
|
+
interface TapTargetButtonSolidProps extends TapTargetButtonProps {
|
|
96
|
+
bgColor?: string | undefined;
|
|
97
|
+
iconColor?: string | undefined;
|
|
98
|
+
hoverBgColor?: string | undefined;
|
|
99
|
+
/**
|
|
100
|
+
* Press-state background. Defaults to `active:brightness-90` which works on
|
|
101
|
+
* any color. Override when using a custom `bgColor` that should darken to a
|
|
102
|
+
* specific shade on press (e.g. `active:bg-primary/60`).
|
|
103
|
+
*/
|
|
104
|
+
activeBgColor?: string | undefined;
|
|
105
|
+
}
|
|
106
|
+
declare const TapTargetButton: React$1.ForwardRefExoticComponent<TapTargetButtonProps & ButtonHTMLAttributes<HTMLButtonElement> & React$1.RefAttributes<HTMLButtonElement>>;
|
|
107
|
+
declare const TapTargetButtonTransparent: React$1.ForwardRefExoticComponent<TapTargetButtonProps & ButtonHTMLAttributes<HTMLButtonElement> & React$1.RefAttributes<HTMLButtonElement>>;
|
|
108
|
+
declare const TapTargetButtonSolid: React$1.ForwardRefExoticComponent<TapTargetButtonSolidProps & ButtonHTMLAttributes<HTMLButtonElement> & React$1.RefAttributes<HTMLButtonElement>>;
|
|
109
|
+
/** Solid destructive pill — delete/remove actions. White-on-red like the
|
|
110
|
+
* primary solid is white-on-blue. Use THIS, never hand-pass bg-destructive
|
|
111
|
+
* with the default (dark) icon color. */
|
|
112
|
+
declare const TapTargetButtonDestructive: React$1.ForwardRefExoticComponent<TapTargetButtonSolidProps & ButtonHTMLAttributes<HTMLButtonElement> & React$1.RefAttributes<HTMLButtonElement>>;
|
|
113
|
+
declare const TapTargetButtonForGroup: React$1.ForwardRefExoticComponent<TapTargetButtonProps & ButtonHTMLAttributes<HTMLButtonElement> & React$1.RefAttributes<HTMLButtonElement>>;
|
|
114
|
+
declare function TapTargetButtonGroup({ children, className, }: {
|
|
115
|
+
children: React.ReactNode;
|
|
116
|
+
className?: string | undefined;
|
|
117
|
+
}): React$1.JSX.Element;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Wraps a TapTargetButton (or any tap control) like the button-demo page:
|
|
121
|
+
* no extra padding on the control — only `gap-0.5` before the caption.
|
|
122
|
+
* Tooltip shows the full `label`; the caption truncates at max-w-[52px].
|
|
123
|
+
*/
|
|
124
|
+
declare function TapTargetLabeled({ label, children, hideLabel, toolTipSide, }: {
|
|
125
|
+
label: string;
|
|
126
|
+
children: React.ReactNode;
|
|
127
|
+
hideLabel?: boolean | undefined;
|
|
128
|
+
toolTipSide?: "top" | "bottom" | "left" | "right" | undefined;
|
|
129
|
+
}): React$1.JSX.Element;
|
|
130
|
+
|
|
131
|
+
export { TapTargetButton, TapTargetButtonDestructive, TapTargetButtonForGroup, TapTargetButtonGroup, type TapTargetButtonProps, TapTargetButtonSolid, type TapTargetButtonSolidProps, TapTargetButtonTransparent, TapTargetLabeled, type TapTargetLinkComponent, type TapTargetLinkProps, getTapTargetLinkComponent, setTapTargetLinkComponent };
|