@hegemonart/get-design-done 1.15.0 → 1.16.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,201 @@
1
+ # Tooltip — Benchmark Spec
2
+
3
+ **Harvested from**: WAI-ARIA APG, Radix UI, Material 3, Carbon, Mantine, Fluent 2, Atlassian, Apple HIG
4
+ **Wave**: 2 · **Category**: Containers
5
+
6
+ ---
7
+
8
+ ## Purpose
9
+
10
+ A tooltip is a small, non-interactive label that appears on hover or keyboard focus to provide supplemental context for an element (typically an icon button or truncated text). It disappears on mouse-out, blur, or Escape. Tooltips MUST NOT contain interactive content (buttons, links, form elements). For interactive overlay content, use Popover. *(WAI-ARIA APG, Radix, Carbon all enforce this boundary)*
11
+
12
+ ---
13
+
14
+ ## Anatomy
15
+
16
+ ```
17
+ [Icon button] ← hover or focus triggers tooltip
18
+
19
+ ▼ (after 300ms delay)
20
+ ┌────────────┐
21
+ │ Label │ ← role="tooltip"; 12px; no interactive content
22
+ └────────────┘
23
+ ▲ (optional 6px arrow caret)
24
+ ```
25
+
26
+ | Part | Required | Notes |
27
+ |------|----------|-------|
28
+ | Trigger | Yes | Usually a button or interactive element |
29
+ | Tooltip container | Yes | `role="tooltip"` + unique `id` |
30
+ | Label text | Yes | Short (≤60 chars), descriptive |
31
+ | Arrow | No | 6–8px caret indicating anchor |
32
+
33
+ ---
34
+
35
+ ## Variants
36
+
37
+ | Variant | Description | Systems |
38
+ |---------|-------------|---------|
39
+ | Default | Hover + focus triggered | All |
40
+ | Delayed | 300ms show delay; 0ms hide | All (WAI-ARIA APG recommended) |
41
+ | Instant | No delay (icon toolbars, dense UIs) | Material 3, Carbon |
42
+ | Dark | Dark background regardless of theme | Most systems |
43
+ | Light | Light background | Mantine (inverted) |
44
+
45
+ **Norm** (≥7/18): 300ms show delay, 0ms hide; max-width 240px; never interactive content.
46
+ **Diverge**: delay duration — Carbon recommends 100ms for toolbars; WAI-ARIA APG recommends ≤500ms. 300ms is the safe default.
47
+
48
+ ---
49
+
50
+ ## States
51
+
52
+ | State | Trigger | ARIA |
53
+ |-------|---------|------|
54
+ | hidden | default | `role="tooltip"` hidden (not in tab order) |
55
+ | visible (hover) | `mouseenter` (after delay) | `aria-describedby` on trigger points to tooltip id |
56
+ | visible (focus) | `focusin` on trigger | same |
57
+ | dismissed | `mouseleave`, `blur`, Escape | Tooltip hidden |
58
+
59
+ ---
60
+
61
+ ## Sizing & Spacing
62
+
63
+ | Property | Value | Notes |
64
+ |----------|-------|-------|
65
+ | Max width | 240px | *(Material 3: 200px, Carbon: 288px, Fluent: 240px)* |
66
+ | Padding | 6px 12px | |
67
+ | Font size | 12px/400 | Smaller than body to signal supplemental role |
68
+ | Border radius | 4–6px | Tight radius vs. card; feels like label |
69
+ | Offset from trigger | 6–8px | |
70
+
71
+ ---
72
+
73
+ ## Typography
74
+
75
+ - 12px/400 — tooltip text is supplemental; smaller weight and size distinguish it from primary content
76
+ - No bold, no headings inside tooltip — it is a single line of text (≤60 chars preferred)
77
+ - Multi-line: allowed if content genuinely requires it; still no interactive elements
78
+
79
+ ---
80
+
81
+ ## Keyboard & Accessibility
82
+
83
+ > **WAI-ARIA role**: `tooltip`
84
+ > **Trigger attributes**: `aria-describedby="tooltip-id"` — links the supplemental label
85
+
86
+ ### Keyboard Contract
87
+
88
+ *Quoted verbatim from WAI-ARIA APG — https://www.w3.org/WAI/ARIA/apg/patterns/tooltip/ — W3C — 2024*
89
+
90
+ | Key | Action |
91
+ |-----|--------|
92
+ | Tab | (on trigger) Shows tooltip when trigger receives focus |
93
+ | Escape | Hides the tooltip |
94
+ | Tab / Shift+Tab | Hides tooltip when focus leaves the trigger |
95
+
96
+ Tooltip does NOT receive focus. It is purely a visual label attached to the trigger.
97
+
98
+ ### Accessibility Rules
99
+
100
+ - Trigger MUST have `aria-describedby` pointing to the tooltip's `id` — screen readers read tooltip content as supplemental description
101
+ - Tooltip is `role="tooltip"` — NOT `role="dialog"` (no interactivity, no focus trap)
102
+ - Tooltip MUST appear on keyboard focus, not only on hover — keyboard-only users need access too *(WCAG 1.3.3, 2.1.1)*
103
+ - Do NOT put interactive content inside a tooltip — use Popover (`reference/components/popover.md`)
104
+ - Do NOT use tooltip as the only accessible name for a control — use `aria-label` on the trigger instead; tooltip supplements, not replaces, the accessible name
105
+ - Escape MUST dismiss the tooltip without removing focus from the trigger *(WAI-ARIA APG)*
106
+
107
+ ---
108
+
109
+ ## Motion
110
+
111
+ | Transition | Duration | Easing | Notes |
112
+ |------------|----------|--------|-------|
113
+ | Show | 100ms | ease-out | Fade only; no scale (too flashy for a label) |
114
+ | Hide | 80ms | ease | Fade only; immediate on Escape |
115
+ | Delay | 300ms | — | CSS `transition-delay` or JS timeout |
116
+
117
+ Cross-link: `reference/motion.md` — `prefers-reduced-motion`: skip fade, instant show/hide
118
+
119
+ ---
120
+
121
+ ## Do / Don't
122
+
123
+ ### Do
124
+ - Show on keyboard focus AND hover — not hover-only *(WAI-ARIA APG, WCAG 2.1.1)*
125
+ - Use `aria-describedby` to link trigger to tooltip *(WAI-ARIA APG)*
126
+ - Limit tooltip content to ≤60 chars — longer content belongs in a popover *(Carbon, Material 3)*
127
+ - Apply 300ms show delay to prevent accidental triggers while cursor passes *(WAI-ARIA APG, Carbon)*
128
+
129
+ ### Don't
130
+ - Don't put interactive elements inside a tooltip *(WAI-ARIA APG — this makes it a popover)*
131
+ - Don't use tooltip as the only accessible name — `aria-describedby` supplements, not replaces, `aria-label` *(WAI-ARIA APG)*
132
+ - Don't trigger tooltip on click — use a popover *(Radix, WAI-ARIA APG)*
133
+ - Don't use tooltip for critical information — it's supplemental; users on touch devices may miss it *(Material 3, Polaris)*
134
+
135
+ ---
136
+
137
+ ## Anti-patterns Cross-links
138
+
139
+ | Anti-pattern | Entry |
140
+ |--------------|-------|
141
+ | Interactive content inside tooltip | `reference/anti-patterns.md` |
142
+ | Hover-only tooltip (not focus-triggered) | `reference/anti-patterns.md` |
143
+
144
+ ---
145
+
146
+ ## Benchmark Citations
147
+
148
+ | Claim | Sources |
149
+ |-------|---------|
150
+ | role="tooltip" not role="dialog" | WAI-ARIA APG |
151
+ | Show on focus AND hover | WAI-ARIA APG, WCAG 2.1.1 |
152
+ | Escape dismisses without removing focus | WAI-ARIA APG §3.2 |
153
+ | 300ms delay | WAI-ARIA APG, Carbon |
154
+ | 240px max-width | Material 3, Fluent 2 |
155
+ | No interactive content | WAI-ARIA APG (all systems agree) |
156
+
157
+ Full system URLs: `connections/design-corpora.md`
158
+
159
+ ---
160
+
161
+ ## Grep Signatures
162
+
163
+ ```bash
164
+ # Tooltip triggered only on hover (not focus) — missing focusin handler
165
+ grep -rn 'tooltip\|Tooltip' src/ | grep 'mouseenter\|onHover' | grep -v 'focus\|onFocus'
166
+
167
+ # Interactive content inside tooltip
168
+ grep -rn 'role="tooltip"' src/ | xargs grep -l 'button\|<a \|input' 2>/dev/null
169
+
170
+ # Trigger missing aria-describedby
171
+ grep -rn 'role="tooltip"' src/ | grep -v 'aria-describedby'
172
+
173
+ # Tooltip without id (aria-describedby target requires id)
174
+ grep -rn 'role="tooltip"' src/ | grep -v ' id='
175
+ ```
176
+
177
+ ---
178
+
179
+ ## Failing Example
180
+
181
+ ```html
182
+ <!-- BAD: tooltip shows on hover only, no focus trigger, no ARIA linkage -->
183
+ <button class="icon-btn" onmouseenter="showTooltip()" onmouseleave="hideTooltip()">
184
+ <svg><!-- settings icon --></svg>
185
+ </button>
186
+ <div class="tooltip">Settings</div>
187
+ ```
188
+
189
+ **Why it fails**: Keyboard users never see the tooltip. Screen readers receive no supplemental description. The `<div>` has no `role="tooltip"` and no `id`, so `aria-describedby` cannot link to it.
190
+ **Grep detection**: `grep -rn 'mouseenter\|onHover' src/ | grep -i 'tooltip' | grep -v 'focus'`
191
+ **Fix**:
192
+ ```html
193
+ <button aria-describedby="settings-tip"
194
+ onmouseenter="show()" onmouseleave="hide()"
195
+ onfocusin="show()" onfocusout="hide()"
196
+ onkeydown="e.key==='Escape'&&hide()">
197
+ <svg aria-hidden="true"><!-- icon --></svg>
198
+ <span class="sr-only">Settings</span>
199
+ </button>
200
+ <div role="tooltip" id="settings-tip">Manage account settings</div>
201
+ ```
@@ -259,6 +259,108 @@
259
259
  "path": "reference/data/google-fonts.csv",
260
260
  "type": "data",
261
261
  "description": "Google Fonts catalog (representative sample of 1923-row UUPM data set)"
262
+ },
263
+ {
264
+ "name": "components-README",
265
+ "path": "reference/components/README.md",
266
+ "type": "taxonomy",
267
+ "description": "Component Benchmark Corpus index — Wave 1–5 tables, coverage summary, harvesting procedure"
268
+ },
269
+ {
270
+ "name": "components-TEMPLATE",
271
+ "path": "reference/components/TEMPLATE.md",
272
+ "type": "schema",
273
+ "description": "Locked 12-section spec shape for component benchmarks (Purpose → Failing example)"
274
+ },
275
+ {
276
+ "name": "component-accordion",
277
+ "path": "reference/components/accordion.md",
278
+ "type": "component-spec",
279
+ "description": "Accordion component spec — h2–h6 header, aria-expanded on trigger, CSS grid height animation"
280
+ },
281
+ {
282
+ "name": "component-button",
283
+ "path": "reference/components/button.md",
284
+ "type": "component-spec",
285
+ "description": "Button component spec — primary/secondary/ghost/destructive/icon-only; WAI-ARIA Enter/Space contract"
286
+ },
287
+ {
288
+ "name": "component-card",
289
+ "path": "reference/components/card.md",
290
+ "type": "component-spec",
291
+ "description": "Card component spec — stretched-link pattern, article semantics, nested interactive anti-pattern"
292
+ },
293
+ {
294
+ "name": "component-checkbox",
295
+ "path": "reference/components/checkbox.md",
296
+ "type": "component-spec",
297
+ "description": "Checkbox component spec — fieldset+legend, indeterminate state, aria-checked=mixed"
298
+ },
299
+ {
300
+ "name": "component-drawer",
301
+ "path": "reference/components/drawer.md",
302
+ "type": "component-spec",
303
+ "description": "Drawer component spec — focus trap, swipe-to-close, nav vs content role distinction"
304
+ },
305
+ {
306
+ "name": "component-input",
307
+ "path": "reference/components/input.md",
308
+ "type": "component-spec",
309
+ "description": "Input component spec — placeholder-as-label anti-pattern, aria-describedby error linking"
310
+ },
311
+ {
312
+ "name": "component-label",
313
+ "path": "reference/components/label.md",
314
+ "type": "component-spec",
315
+ "description": "Label component spec — 4 association methods, .sr-only pattern, legend for groups"
316
+ },
317
+ {
318
+ "name": "component-link",
319
+ "path": "reference/components/link.md",
320
+ "type": "component-spec",
321
+ "description": "Link component spec — a[href] vs button boundary, WCAG 1.4.1 underline, rel=noopener"
322
+ },
323
+ {
324
+ "name": "component-modal-dialog",
325
+ "path": "reference/components/modal-dialog.md",
326
+ "type": "component-spec",
327
+ "description": "Modal dialog spec — focus trap, Escape contract, aria-modal, aria-labelledby, scroll-lock"
328
+ },
329
+ {
330
+ "name": "component-popover",
331
+ "path": "reference/components/popover.md",
332
+ "type": "component-spec",
333
+ "description": "Popover spec — Floating UI middlewares, non-modal, aria-expanded+aria-controls"
334
+ },
335
+ {
336
+ "name": "component-radio",
337
+ "path": "reference/components/radio.md",
338
+ "type": "component-spec",
339
+ "description": "Radio component spec — arrow-key auto-advance, Tab-as-group-unit, single-radio anti-pattern"
340
+ },
341
+ {
342
+ "name": "component-select-combobox",
343
+ "path": "reference/components/select-combobox.md",
344
+ "type": "component-spec",
345
+ "description": "Select/combobox spec — WAI-ARIA listbox + combobox contracts, aria-activedescendant"
346
+ },
347
+ {
348
+ "name": "component-switch",
349
+ "path": "reference/components/switch.md",
350
+ "type": "component-spec",
351
+ "description": "Switch component spec — role=switch, spring thumb, pill track, immediate-action rule"
352
+ },
353
+ {
354
+ "name": "component-tabs",
355
+ "path": "reference/components/tabs.md",
356
+ "type": "component-spec",
357
+ "description": "Tabs component spec — roving tabindex, arrow-key nav, automatic vs manual activation"
358
+ },
359
+ {
360
+ "name": "component-tooltip",
361
+ "path": "reference/components/tooltip.md",
362
+ "type": "component-spec",
363
+ "description": "Tooltip spec — no interactive content, hover+focus trigger, 300ms delay, aria-describedby"
262
364
  }
263
365
  ]
264
366
  }
@@ -37,7 +37,8 @@
37
37
  "emotional-design",
38
38
  "experience",
39
39
  "palette",
40
- "style-vocabulary"
40
+ "style-vocabulary",
41
+ "component-spec"
41
42
  ]
42
43
  },
43
44
  "tier": { "enum": ["L0", "L1", "L2"] },
@@ -0,0 +1,105 @@
1
+ ---
2
+ name: gdd-benchmark
3
+ description: Harvest and synthesize per-component design benchmarks from 18 design systems. Produces canonical specs at reference/components/<name>.md.
4
+ argument-hint: "<component> | --wave <N> | --list | --refresh <component>"
5
+ tools: Read, Write, Bash, Grep, Glob, Task, WebFetch
6
+ ---
7
+
8
+ # /gdd:benchmark
9
+
10
+ Harvest per-component design knowledge from 18 design systems and synthesize canonical
11
+ specs at `reference/components/<name>.md`.
12
+
13
+ ## Invocation Modes
14
+
15
+ | Invocation | Action |
16
+ |------------|--------|
17
+ | `/gdd:benchmark <component>` | Harvest + synthesize a single component |
18
+ | `/gdd:benchmark --wave <N>` | Run a full wave (1 = Inputs, 2 = Containers, etc.) |
19
+ | `/gdd:benchmark --list` | Show corpus coverage — which specs exist, which are pending |
20
+ | `/gdd:benchmark --refresh <component>` | Re-harvest a spec (for design-system version bumps) |
21
+
22
+ ## Single-Component Flow (`/gdd:benchmark <component>`)
23
+
24
+ 1. **Check if spec exists** — `Glob("reference/components/<component>.md")`.
25
+ If found and `--refresh` was not passed, confirm before overwriting.
26
+
27
+ 2. **Harvest** — spawn `component-benchmark-harvester` with:
28
+ ```
29
+ Task("component-benchmark-harvester", """
30
+ <required_reading>
31
+ @connections/design-corpora.md
32
+ </required_reading>
33
+
34
+ Harvest design-system excerpts for component: <component>
35
+ Emit raw harvest to: .planning/benchmarks/raw/<component>.md
36
+ Consume any relevant content from: .planning/research/impeccable-salvage/
37
+
38
+ Acceptance: .planning/benchmarks/raw/<component>.md exists with ≥4 source sections.
39
+ """)
40
+ ```
41
+
42
+ 3. **Synthesize** — spawn `component-benchmark-synthesizer` with:
43
+ ```
44
+ Task("component-benchmark-synthesizer", """
45
+ <required_reading>
46
+ @.planning/benchmarks/raw/<component>.md
47
+ @reference/components/TEMPLATE.md
48
+ @reference/anti-patterns.md
49
+ </required_reading>
50
+
51
+ Synthesize the raw harvest into a canonical spec.
52
+ Output: reference/components/<component>.md
53
+ Update: reference/components/README.md (add entry in correct category)
54
+
55
+ Acceptance: spec exists, ≤350 lines, cites ≥4 systems, has TEMPLATE.md sections,
56
+ WAI-ARIA keyboard contract present, failing-example block present.
57
+ """)
58
+ ```
59
+
60
+ 4. **Report** — print spec path, line count, systems cited.
61
+
62
+ ## Wave Mode (`/gdd:benchmark --wave <N>`)
63
+
64
+ Read the wave definition from `reference/components/README.md` and run each component
65
+ in the wave sequentially (not parallel — each harvest is network-bound and the raw files
66
+ are large).
67
+
68
+ | Wave | Components |
69
+ |------|-----------|
70
+ | 1 | button, input, select-combobox, checkbox, radio, switch, link, label |
71
+ | 2 | card, modal-dialog, drawer, popover, tooltip, accordion, tabs |
72
+
73
+ Print progress per component: `[N/total] harvesting <component>…`
74
+
75
+ ## List Mode (`/gdd:benchmark --list`)
76
+
77
+ Read `reference/components/README.md` and diff against `reference/components/*.md` files.
78
+ Print a table:
79
+
80
+ ```
81
+ Component Status Wave Lines
82
+ button ✓ 1 248
83
+ input ✓ 1 312
84
+ select-combobox ✓ 1 295
85
+ ...
86
+ toast pending 3 —
87
+ ```
88
+
89
+ ## Refresh Mode (`/gdd:benchmark --refresh <component>`)
90
+
91
+ Same as single-component flow but skips the "already exists" guard. Use when a design
92
+ system ships a breaking update to a component's spec.
93
+
94
+ ## Source List
95
+
96
+ `connections/design-corpora.md` — 18 design systems with canonical URLs, licensing, and
97
+ fallback chain (canonical → archive.org → Refero MCP → Pinterest MCP).
98
+
99
+ ## Output Artifacts
100
+
101
+ | Artifact | Purpose |
102
+ |----------|---------|
103
+ | `.planning/benchmarks/raw/<component>.md` | Raw multi-source harvest (input only) |
104
+ | `reference/components/<component>.md` | Canonical spec (distributed with plugin) |
105
+ | `reference/components/README.md` | Corpus index (updated by synthesizer) |