@ai-matrx/tap-target 0.1.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.
@@ -0,0 +1,40 @@
1
+ import { ComponentType, ReactNode } from 'react';
2
+
3
+ /**
4
+ * The injectable link seam — the package's replacement for the original
5
+ * hard `next/link` import.
6
+ *
7
+ * Internal hrefs (anything NOT matching `http(s):`, `mailto:`, `tel:`) render
8
+ * through the link component resolved here; external hrefs always render a
9
+ * plain `<a target="_blank" rel="noopener noreferrer">`, exactly like the
10
+ * original. When nothing is registered and no per-instance `linkComponent`
11
+ * prop is given, internal hrefs fall back to a plain `<a>` (no prefetch, no
12
+ * client-side routing — still a working link).
13
+ */
14
+ interface TapTargetLinkProps {
15
+ href: string;
16
+ target?: "_blank" | "_self" | "_parent" | "_top" | undefined;
17
+ rel?: string | undefined;
18
+ /** Router prefetch hint (next/link semantics). Plain `<a>` fallback ignores it. */
19
+ prefetch?: boolean | null | undefined;
20
+ "aria-label"?: string | undefined;
21
+ className?: string | undefined;
22
+ children?: ReactNode;
23
+ }
24
+ type TapTargetLinkComponent = ComponentType<TapTargetLinkProps>;
25
+ /**
26
+ * Register the app's link component once at startup (e.g. `next/link`):
27
+ *
28
+ * ```tsx
29
+ * import Link from "next/link";
30
+ * import { setTapTargetLinkComponent } from "@ai-matrx/tap-target";
31
+ * setTapTargetLinkComponent(Link);
32
+ * ```
33
+ *
34
+ * Pass `null` to unregister (plain `<a>` fallback resumes).
35
+ */
36
+ declare function setTapTargetLinkComponent(component: TapTargetLinkComponent | null): void;
37
+ /** The currently registered link component, or `null` when none is set. */
38
+ declare function getTapTargetLinkComponent(): TapTargetLinkComponent | null;
39
+
40
+ export { type TapTargetLinkComponent as T, type TapTargetLinkProps as a, getTapTargetLinkComponent as g, setTapTargetLinkComponent as s };
@@ -0,0 +1,110 @@
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
+ /* =========================================================================
9
+ TapTargetButton — SINGLE SOURCE OF TRUTH for tap-button geometry + feedback.
10
+ This is the ONLY place these are defined (previously also duplicated in
11
+ styles/shell.css, which caused the same button to resolve differently
12
+ inside vs outside the shell). Consumed exclusively by
13
+ components/icons/TapTargetButton.tsx. To resize or retune EVERY tap button
14
+ in the app, edit HERE — nowhere else.
15
+
16
+ Structure per button:
17
+ .matrx-tap-target — outer 44px invisible touch target = the interactive
18
+ element (<button>/<a>/<label>). It owns the tap
19
+ hygiene (touch-action + tap-highlight) so it applies
20
+ to the WHOLE 44px target AND to the link variants —
21
+ the iOS gray flash paints on the anchor, not the
22
+ inner pill, so putting it on the pill never worked.
23
+ .matrx-tap-pill — inner 28px visible pill. Geometry + press feedback.
24
+ Each variant layers ONLY its decoration on top (glass
25
+ border / solid fill / hover bg) — the size is identical
26
+ across glass / transparent / solid, guaranteed here.
27
+ .matrx-tap-icon — 14px icon.
28
+ .matrx-tap-*-inline — wider auto-width geometry when `label` is set on
29
+ TapTargetButton (icon + caption on one row).
30
+ The `-sm` classes (32 / 20px) are the slimmer geometry used inside groups.
31
+ ========================================================================= */
32
+ .matrx-tap-target {
33
+ display: flex;
34
+ height: 2.75rem; /* 44px outer tap target */
35
+ width: 2.75rem;
36
+ flex-shrink: 0; /* a tap target never squishes under flex pressure —
37
+ flexible neighbors (truncating labels) absorb it */
38
+ align-items: center;
39
+ justify-content: center;
40
+ background-color: transparent;
41
+ cursor: pointer;
42
+ outline: none;
43
+ touch-action: manipulation; /* kills the 300ms mobile tap delay */
44
+ -webkit-tap-highlight-color: transparent; /* kills the iOS gray tap flash */
45
+ }
46
+ .matrx-tap-target:disabled {
47
+ opacity: 0.4;
48
+ pointer-events: none;
49
+ }
50
+ .matrx-tap-target-sm {
51
+ height: 2rem; /* 32px */
52
+ width: 2rem;
53
+ }
54
+
55
+ .matrx-tap-pill {
56
+ display: flex;
57
+ height: 1.75rem; /* 28px visible pill */
58
+ width: 1.75rem;
59
+ align-items: center;
60
+ justify-content: center;
61
+ border-radius: 9999px;
62
+ transition:
63
+ background-color 150ms ease,
64
+ transform 100ms ease;
65
+ }
66
+ .matrx-tap-pill:active {
67
+ transform: scale(0.92);
68
+ }
69
+ .matrx-tap-pill-sm {
70
+ height: 1.25rem; /* 20px */
71
+ width: 1.25rem;
72
+ }
73
+
74
+ .matrx-tap-icon {
75
+ height: 0.875rem; /* 14px */
76
+ width: 0.875rem;
77
+ flex-shrink: 0;
78
+ }
79
+
80
+ /* Inline label — icon + text on one row inside the pill */
81
+ .matrx-tap-target-inline {
82
+ width: auto;
83
+ min-width: 2.75rem;
84
+ padding-inline: 0.25rem;
85
+ }
86
+ .matrx-tap-pill-inline {
87
+ width: auto;
88
+ gap: 0.375rem;
89
+ padding-inline: 0.625rem;
90
+ }
91
+ .matrx-tap-label {
92
+ font-size: 0.75rem;
93
+ font-weight: 500;
94
+ line-height: 1;
95
+ white-space: nowrap;
96
+ }
97
+
98
+ .matrx-tap-target-inline-sm {
99
+ width: auto;
100
+ min-width: 2rem;
101
+ padding-inline: 0.125rem;
102
+ }
103
+ .matrx-tap-pill-inline-sm {
104
+ width: auto;
105
+ gap: 0.25rem;
106
+ padding-inline: 0.5rem;
107
+ }
108
+ .matrx-tap-pill-inline-sm .matrx-tap-label {
109
+ font-size: 0.625rem;
110
+ }
package/package.json ADDED
@@ -0,0 +1,96 @@
1
+ {
2
+ "name": "@ai-matrx/tap-target",
3
+ "version": "0.1.0",
4
+ "description": "The AI Matrx tap-target button system: an invisible 44x44 touch ring over a 32x32 visible pill, glass/transparent/solid/group variants with correct ref forwarding for Radix asChild triggers, inline labels, link/label/button trigger resolution with an injectable link component, tooltip wiring, and ~60 pre-composed one-tag buttons.",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "license": "MIT",
10
+ "keywords": [
11
+ "tap-target",
12
+ "touch-target",
13
+ "icon-button",
14
+ "react",
15
+ "radix",
16
+ "a11y",
17
+ "ai-matrx"
18
+ ],
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/AI-Matrix-Engine/aidream.git",
22
+ "directory": "apps/shared/tap-target"
23
+ },
24
+ "homepage": "https://github.com/AI-Matrix-Engine/aidream/tree/main/apps/shared/tap-target#readme",
25
+ "bugs": {
26
+ "url": "https://github.com/AI-Matrix-Engine/aidream/issues"
27
+ },
28
+ "files": [
29
+ "dist",
30
+ "README.md",
31
+ "LICENSE",
32
+ "CHANGELOG.md"
33
+ ],
34
+ "exports": {
35
+ ".": {
36
+ "import": {
37
+ "types": "./dist/index.d.ts",
38
+ "default": "./dist/index.js"
39
+ },
40
+ "require": {
41
+ "types": "./dist/index.d.cts",
42
+ "default": "./dist/index.cjs"
43
+ }
44
+ },
45
+ "./buttons": {
46
+ "import": {
47
+ "types": "./dist/buttons.d.ts",
48
+ "default": "./dist/buttons.js"
49
+ },
50
+ "require": {
51
+ "types": "./dist/buttons.d.cts",
52
+ "default": "./dist/buttons.cjs"
53
+ }
54
+ },
55
+ "./styles.css": "./dist/styles.css",
56
+ "./package.json": "./package.json"
57
+ },
58
+ "dependencies": {
59
+ "@radix-ui/react-tooltip": "^1.2.8"
60
+ },
61
+ "peerDependencies": {
62
+ "react": ">=18.0.0"
63
+ },
64
+ "devDependencies": {
65
+ "@arethetypeswrong/cli": "^0.18.5",
66
+ "@testing-library/react": "^16.3.0",
67
+ "@types/node": "^22.20.0",
68
+ "@types/react": "^19.1.0",
69
+ "jsdom": "^25.0.1",
70
+ "publint": "^0.3.24",
71
+ "react": "^19.1.0",
72
+ "react-dom": "^19.1.0",
73
+ "tsup": "^8.5.1",
74
+ "typescript": "^5.9.3",
75
+ "vitest": "^4.1.6"
76
+ },
77
+ "publishConfig": {
78
+ "access": "public",
79
+ "registry": "https://registry.npmjs.org/"
80
+ },
81
+ "engines": {
82
+ "node": ">=20"
83
+ },
84
+ "sideEffects": [
85
+ "*.css"
86
+ ],
87
+ "scripts": {
88
+ "build": "tsup",
89
+ "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
90
+ "check:package": "pnpm build && publint && pnpm verify:tarball",
91
+ "typecheck": "tsc -p tsconfig.json --noEmit",
92
+ "test": "vitest run",
93
+ "test:watch": "vitest",
94
+ "verify:tarball": "node ./scripts/verify-tarball.mjs"
95
+ }
96
+ }