@mtdt/observeops-ds-spec 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.
Files changed (79) hide show
  1. package/AGENTS.md +102 -0
  2. package/README.md +73 -0
  3. package/components/index.json +1270 -0
  4. package/components/recipes/README.md +41 -0
  5. package/components/recipes/recipes.json +922 -0
  6. package/components/registry/README.md +44 -0
  7. package/components/registry/_schema.json +47 -0
  8. package/components/registry/button.json +368 -0
  9. package/components/registry/checkbox.json +177 -0
  10. package/components/registry/data-viz-tooltips.json +409 -0
  11. package/components/registry/date-time-pickers.json +296 -0
  12. package/components/registry/drawer.json +222 -0
  13. package/components/registry/dropdown-picker.json +388 -0
  14. package/components/registry/filters.json +155 -0
  15. package/components/registry/form-item.json +281 -0
  16. package/components/registry/input.json +277 -0
  17. package/components/registry/link.json +186 -0
  18. package/components/registry/loose-tags.json +196 -0
  19. package/components/registry/menu.json +145 -0
  20. package/components/registry/modal.json +265 -0
  21. package/components/registry/navigation.json +425 -0
  22. package/components/registry/popover.json +216 -0
  23. package/components/registry/radio.json +238 -0
  24. package/components/registry/scheduler.json +188 -0
  25. package/components/registry/select.json +247 -0
  26. package/components/registry/severity.json +179 -0
  27. package/components/registry/switch.json +177 -0
  28. package/components/registry/table.json +275 -0
  29. package/components/registry/tabs.json +264 -0
  30. package/components/registry/tag.json +345 -0
  31. package/components/registry/tags-list.json +115 -0
  32. package/components/registry/toolbars.json +240 -0
  33. package/components/registry/tooltip.json +175 -0
  34. package/components/specs/README.md +72 -0
  35. package/components/specs/button.md +230 -0
  36. package/components/specs/checkbox.md +162 -0
  37. package/components/specs/data-viz-tooltips.md +93 -0
  38. package/components/specs/date-time-pickers.md +161 -0
  39. package/components/specs/drawer.md +162 -0
  40. package/components/specs/dropdown-picker.md +161 -0
  41. package/components/specs/filters.md +118 -0
  42. package/components/specs/form-item.md +130 -0
  43. package/components/specs/input.md +130 -0
  44. package/components/specs/link.md +131 -0
  45. package/components/specs/loose-tags.md +139 -0
  46. package/components/specs/menu.md +88 -0
  47. package/components/specs/modal.md +176 -0
  48. package/components/specs/navigation.md +181 -0
  49. package/components/specs/popover.md +118 -0
  50. package/components/specs/radio.md +144 -0
  51. package/components/specs/scheduler.md +133 -0
  52. package/components/specs/select.md +118 -0
  53. package/components/specs/switch.md +124 -0
  54. package/components/specs/table.md +115 -0
  55. package/components/specs/tabs.md +136 -0
  56. package/components/specs/tag.md +196 -0
  57. package/components/specs/tags-list.md +105 -0
  58. package/components/specs/toolbars.md +108 -0
  59. package/components/specs/tooltip.md +112 -0
  60. package/foundation/README.md +39 -0
  61. package/foundation/layout-shells.md +67 -0
  62. package/foundation/page-templates.md +69 -0
  63. package/foundation/panel-behaviours.md +61 -0
  64. package/foundation/screen-regions.md +62 -0
  65. package/index.js +75 -0
  66. package/layout/grid.json +34 -0
  67. package/layout/layouts.json +310 -0
  68. package/llms.txt +60 -0
  69. package/package.json +42 -0
  70. package/spec.manifest.json +407 -0
  71. package/tokens/README.md +125 -0
  72. package/tokens/component.json +34 -0
  73. package/tokens/kit-accents.json +14 -0
  74. package/tokens/primitive.json +130 -0
  75. package/tokens/purpose-map.json +67 -0
  76. package/tokens/semantic.dark.json +90 -0
  77. package/tokens/semantic.light.json +90 -0
  78. package/tokens/structural.json +35 -0
  79. package/tokens/variables.json +2018 -0
@@ -0,0 +1,115 @@
1
+ {
2
+ "name": "tags-list",
3
+ "component": "TagsList",
4
+ "display": "TagsList",
5
+ "tier": "molecule",
6
+ "category": "display",
7
+ "source": "app",
8
+ "sourceFile": "src/components/tags-list.vue",
9
+ "status": "dead-code",
10
+ "maturity": "unused",
11
+ "summary": "Read-only tag overflow display: up to maxLength neutral chips, else a count chip + hover popover. UNUSED in product (0 usages) — prefer SelectedItemPills.",
12
+ "variants": [],
13
+ "sizes": [],
14
+ "states": [
15
+ {
16
+ "name": "inline",
17
+ "what": "all chips (≤ maxLength)"
18
+ },
19
+ {
20
+ "name": "overflow",
21
+ "what": "count chip + hover popover"
22
+ }
23
+ ],
24
+ "family": "Tag",
25
+ "props": {
26
+ "value": {
27
+ "type": [
28
+ "array",
29
+ "object"
30
+ ],
31
+ "default": "undefined",
32
+ "note": "tags to display"
33
+ },
34
+ "maxLength": {
35
+ "type": "number",
36
+ "default": 2,
37
+ "note": "inline threshold before collapsing to a count chip"
38
+ }
39
+ },
40
+ "events": "none — display-only.",
41
+ "slots": "none — display-only; renders tags inline and collapses to a +N count chip (with a popover listing the rest) once past `maxLength`.",
42
+ "anatomy": [
43
+ "inline neutral chips (<= maxLength)",
44
+ "count chip (> maxLength)",
45
+ "hover popover list"
46
+ ],
47
+ "behaviors": {
48
+ "empty": "renders nothing when value is empty",
49
+ "overflow": "collapses to ONLY the count (not first-N + remaining); hover (not click) opens the popover"
50
+ },
51
+ "styling": {
52
+ "chip": "tag-primary neutral (--tag-bg/--tag-color), border-radius 10px (.application-item)",
53
+ "popoverDivider": "--border-color"
54
+ },
55
+ "tokensUsed": [
56
+ "--tag-bg",
57
+ "--tag-color",
58
+ "--border-color"
59
+ ],
60
+ "accessibility": {
61
+ "chips": "read-only span text, legible both themes",
62
+ "overflow": "hover-only; count chip not focusable/click-openable (keyboard/touch can't reveal list)"
63
+ },
64
+ "do": [
65
+ "For tag overflow in the product, use SelectedItemPills (live, themed, +N), not this."
66
+ ],
67
+ "dont": [
68
+ "Don't adopt TagsList in new code (dead/unused). Don't build it in Figma."
69
+ ],
70
+ "whenToUse": "N/A — unused. Use SelectedItemPills for tag overflow.",
71
+ "decisionFlow": [
72
+ "Tag overflow display (show some, +N rest)? -> SelectedItemPills (or LooseTags :disabled), NOT TagsList.",
73
+ "Editable tags? -> LooseTags.",
74
+ "Single label/status? -> MTag/MStatusTag."
75
+ ],
76
+ "usageRules": {
77
+ "tags-list": {
78
+ "useWhen": "never — dead code (0 usages)",
79
+ "dontUse": "all cases; duplicates SelectedItemPills with count-only overflow + no keyboard support",
80
+ "example": "n/a — use SelectedItemPills"
81
+ }
82
+ },
83
+ "usage": {
84
+ "total": 0,
85
+ "files": 0,
86
+ "note": "dead code — never imported or rendered"
87
+ },
88
+ "knownIssues": [
89
+ "F1 (medium): DEAD CODE — 0 usages; duplicates SelectedItemPills. Remove tags-list.vue or fold into SelectedItemPills.",
90
+ "F2 (low): collapses to count-only (no tag preview), unlike SelectedItemPills' first-N + +N idiom. Standardize the overflow idiom."
91
+ ],
92
+ "related": [
93
+ "SelectedItemPills",
94
+ "MTag",
95
+ "MPopover",
96
+ "LooseTags"
97
+ ],
98
+ "changelog": [
99
+ "2026-06-07: added (badged UNUSED) at owner request; render verified; dead-code finding F1 + pattern inconsistency F2; recommend removal/consolidation onto SelectedItemPills."
100
+ ],
101
+ "storybook": "Molecules/TagsList",
102
+ "figma": {
103
+ "status": "n/a",
104
+ "component": "TagsList (dead code — do not build)"
105
+ },
106
+ "a11y": {
107
+ "summary": "Read-only <span> chips, legible contrast; display-only.",
108
+ "issues": [
109
+ "Overflow is hover-only — the +N count chip isn't focusable/openable.",
110
+ "No visible focus ring (SF-001)."
111
+ ],
112
+ "doc": "Molecules/TagsList/Accessibility",
113
+ "$note": "Catalogue-wide gap SF-001 = no visible :focus-visible ring; tracked in findings/."
114
+ }
115
+ }
@@ -0,0 +1,240 @@
1
+ {
2
+ "name": "toolbars",
3
+ "display": "Toolbars",
4
+ "tier": "organism",
5
+ "family": "Toolbars",
6
+ "status": "stable",
7
+ "summary": "The product's toolbar compositions, as variants of one family. A toolbar is an organism that arranges molecules/atoms (title, search, filters, actions). Variants: Page header, Widget header, Bulk action bar, Grid toolbar, Column chooser.",
8
+ "variants": [
9
+ {
10
+ "name": "app-header",
11
+ "what": "global top bar",
12
+ "usage": ""
13
+ },
14
+ {
15
+ "name": "page-header",
16
+ "what": "back + title + actions",
17
+ "usage": "54×"
18
+ },
19
+ {
20
+ "name": "widget-header",
21
+ "what": "title + time pill + kebab",
22
+ "usage": "58×"
23
+ },
24
+ {
25
+ "name": "bulk-action-bar",
26
+ "what": "N-selected + actions",
27
+ "usage": ""
28
+ },
29
+ {
30
+ "name": "grid-toolbar",
31
+ "what": "search/filter/columns/Add",
32
+ "usage": ""
33
+ },
34
+ {
35
+ "name": "column-chooser",
36
+ "what": "eye-button show/hide",
37
+ "usage": "174×"
38
+ }
39
+ ],
40
+ "sizes": [],
41
+ "states": [
42
+ {
43
+ "name": "visible",
44
+ "what": "displayed"
45
+ },
46
+ {
47
+ "name": "bulk-visible",
48
+ "what": "bulk bar when selectedCount≥min"
49
+ }
50
+ ],
51
+ "renders": "REFERENCE REPRODUCTIONS with real tokens; built from real MButton/MIcon/MStatusTag/MCheckbox.",
52
+ "decisionFlow": [
53
+ "Top of a list/detail page (title + actions)? -> Page header.",
54
+ "A dashboard widget's title + actions? -> Widget header.",
55
+ "Acting on N selected rows? -> Bulk action bar.",
56
+ "Controls above a data grid (search/filter/columns/add)? -> Grid toolbar.",
57
+ "Show/hide grid columns? -> Column chooser."
58
+ ],
59
+ "do": [
60
+ "Use the Page header for every list/detail page (title + actions).",
61
+ "Compose toolbars from the Filters molecules + search + actions — don't re-implement filters.",
62
+ "Use the Bulk action bar for multi-select operations.",
63
+ "Put destructive bulk actions in --secondary-red."
64
+ ],
65
+ "dont": [
66
+ "Don't duplicate a filter inside a toolbar — compose the Molecules/Filters component.",
67
+ "Don't create a per-screen toolbar component — use these variants.",
68
+ "Don't rely on the column chooser to reorder columns in the product (that's grid-header drag)."
69
+ ],
70
+ "knownIssues": {
71
+ "F1": {
72
+ "severity": "Low",
73
+ "issue": "Reference reproductions; the live Page/Widget headers use the router / widget store."
74
+ },
75
+ "F2": {
76
+ "severity": "Low",
77
+ "a11y": true,
78
+ "issue": "Verify focus-visible ring (SF-001) and aria-labels on icon-only toolbar buttons (export, kebab, More, ×)."
79
+ }
80
+ },
81
+ "tokensUsed": [
82
+ "--primary",
83
+ "--primary-alt",
84
+ "--border-color",
85
+ "--page-background-color",
86
+ "--page-text-color",
87
+ "--neutral-light",
88
+ "--secondary-red",
89
+ "--common-widget-bg",
90
+ "--timerange-background-color"
91
+ ],
92
+ "composedFrom": {
93
+ "FlotoGridActions": "the row action KEBAB (Edit/Clone/Delete ⋮, 88×) — the action-menu archetype, catalogued under POPOVER; it is the kebab inside the Widget header and the Bulk action bar's 'More'.",
94
+ "Filters": "the filter button/bar inside the Grid toolbar",
95
+ "Input": "the search box (search type) inside App/Page/Grid toolbars",
96
+ "DropdownPicker / Date & Time Pickers": "selects + the widget time-range pill"
97
+ },
98
+ "scopedOut": {
99
+ "Detail headers (RUM drill-down ×7, guide-header)": "Page-header VARIANTS for detail/drill-down views — title + context + actions; a usage, not a new component.",
100
+ "bulk-provision-toolbar (2×)": "a domain VARIANT of the Bulk action bar (rediscover provisioning).",
101
+ "Action footer (result-footer; modal/drawer footers)": "bottom action bars — covered by the Modal / Drawer families.",
102
+ "overlay-controls (metric-explorer)": "a feature-specific chart/explorer control strip — not a reusable toolbar.",
103
+ "rule-group-header / permission-section-header": "in-content SECTION labels, not toolbars.",
104
+ "FlotoNavBar / left menu / breadcrumb / tabs": "NAVIGATION archetypes (vertical/secondary nav), not toolbars — candidate for a future Navigation family."
105
+ },
106
+ "storybook": "Organisms/Toolbars",
107
+ "related": [
108
+ "filters",
109
+ "table",
110
+ "dropdown-picker",
111
+ "popover",
112
+ "date-time-pickers"
113
+ ],
114
+ "figma": {
115
+ "status": "todo"
116
+ },
117
+ "apis": {
118
+ "BulkActionBar": {
119
+ "source": "src/components/_base-bulk-action-bar.vue",
120
+ "props": {
121
+ "selectedCount": "Number",
122
+ "minSelection": "Number (default 2) — bar shows at >=",
123
+ "actions": "Array<{key,name,icon?,isDanger?,greenAction?,type?:'divider'}>",
124
+ "directKeys": "Array — actions rendered inline (not in More)",
125
+ "createPermissionKeys/editPermissionKeys/deletePermissionKeys": "Array",
126
+ "createPermissionName/editPermissionName/deletePermissionName": "String"
127
+ },
128
+ "events": {
129
+ "clear": "deselect all",
130
+ "selected": "(action)",
131
+ "<actionKey>": "per action key"
132
+ },
133
+ "note": "role=toolbar; inline primary/danger actions + a 'More' overflow (Menu/context-menu, picker-action-dropdown). Danger separated by a __danger-zone divider."
134
+ },
135
+ "AppHeader": {
136
+ "source": "src/components/layout/header.vue (Header)",
137
+ "what": "global top bar — a COMPOSITION, not a propful component. Comes from the layout.",
138
+ "contains": [
139
+ "logo (FlotoLink -> home, appliedIconLogo)",
140
+ "global search (MButton -> omnibox; navigation/omnibox)",
141
+ "health-monitoring + NCM approval (permission-gated icon buttons)",
142
+ "NotificationDropdown (navigation/notification-dropdown)",
143
+ "BUILD : <version> tag",
144
+ "UserDropdown (navigation/user-menu)"
145
+ ]
146
+ },
147
+ "PageHeader": {
148
+ "source": "src/components/_base-page-header.vue (FlotoPageHeader)",
149
+ "props": {
150
+ "backLink": "[String,Object] — router link/path for back",
151
+ "title": "String",
152
+ "mainHeader": "Boolean (false) — main vs inner title-panel style",
153
+ "useDivider": "Boolean (false)"
154
+ },
155
+ "events": {},
156
+ "slots": {
157
+ "back-button": "replaces default FlotoBackButton",
158
+ "before-title": "",
159
+ "title": "appended next to title",
160
+ "title-append": "below title (e.g. count)",
161
+ "after-title": "",
162
+ "default": "main content (actions)",
163
+ "additional-rows": "rows below the header"
164
+ },
165
+ "note": "slot-driven; no emits"
166
+ },
167
+ "WidgetHeader": {
168
+ "source": "src/components/widgets/views/components/widget-title.vue",
169
+ "props": {
170
+ "widget": "Object — widget meta (name/category/timeRange/type)",
171
+ "guid": "String (required)",
172
+ "title": "String — overrides widget.name",
173
+ "disabled": "Boolean",
174
+ "isPreview": "Boolean",
175
+ "isFullscreen": "Boolean",
176
+ "hideTitle": "Boolean",
177
+ "hideTimeline": "Boolean",
178
+ "headerFontSize": "String (11px)",
179
+ "backgroundColor": "String — tints time pill + text",
180
+ "excludedActions": "Array — action keys to hide",
181
+ "additionalActions": "Array — prepend custom actions"
182
+ },
183
+ "events": {
184
+ "edit": "",
185
+ "clone": "",
186
+ "remove": "",
187
+ "share": "",
188
+ "fullscreen": "",
189
+ "exit-fullscreen": "",
190
+ "csv-export": "grid",
191
+ "chart-csv-export": "{widgetName,onSuccess,onError,onNoData}"
192
+ },
193
+ "slots": {
194
+ "flip-toggle": "optional toggle control"
195
+ },
196
+ "note": "title + time pill + kebab (FlotoGridActions) + metric-analysis"
197
+ },
198
+ "ColumnChooser": {
199
+ "source": "src/components/column-selector.vue",
200
+ "props": {
201
+ "value": "Array — column objs {key,hidden?}",
202
+ "columns": "Array — all available columns",
203
+ "hideResetOption": "Boolean — hides Reset Column Preference",
204
+ "maxAllowedSelection": "Number — cap (toast on exceed)",
205
+ "errorMessage": "String"
206
+ },
207
+ "events": {
208
+ "change": "updated column array (hidden flags)"
209
+ },
210
+ "slots": {
211
+ "trigger": "{ toggle, isOpen } — replaces eye button"
212
+ },
213
+ "note": "FlotoDropdownPicker multi-select; filters out action columns; v-model=change"
214
+ },
215
+ "GridToolbar": {
216
+ "source": "COMPOSITION (default-grid.vue) — not a single component",
217
+ "props": "inherited from FlotoWidgetView/widget config; no dedicated props",
218
+ "events": "row-click, column-change, sort-change",
219
+ "slots": "sparklineHeader, defaultCell",
220
+ "composedOf": [
221
+ "MInput(search)",
222
+ "filter MButton",
223
+ "ColumnSelector (in MPersistedColumns — persists to localStorage by widget id)",
224
+ "WidgetGridFilters panel",
225
+ "VirtualTable grid"
226
+ ],
227
+ "note": "assemble from the named parts; not a propful wrapper"
228
+ }
229
+ },
230
+ "a11y": {
231
+ "summary": "Bulk-action bar = role=toolbar + aria-label; page titles are real <h4> headings.",
232
+ "issues": [
233
+ "SF-001 focus ring on toolbar buttons.",
234
+ "Icon-only buttons (export, kebab, More, ×) need aria-label.",
235
+ "Announce bulk-bar appearance; kebab needs aria-haspopup/expanded + Esc."
236
+ ],
237
+ "doc": "Organisms/Toolbars/Accessibility",
238
+ "$note": "Catalogue-wide gap SF-001 = no visible :focus-visible ring; tracked in findings/."
239
+ }
240
+ }
@@ -0,0 +1,175 @@
1
+ {
2
+ "name": "tooltip",
3
+ "display": "Tooltip",
4
+ "tier": "molecule",
5
+ "family": "Popover & Tooltip",
6
+ "source": "src/components/_base-tooltip.vue (Floto override; kit MTooltip excluded). Renders via VTippy (vue-tippy).",
7
+ "status": "stable",
8
+ "summary": "Transient hover/focus label anchored to a trigger. The kit MTooltip is excluded and this Floto override ships instead, rendering through VTippy (not a-tooltip). trigger slot = anchor, default slot = content. Non-interactive — for interactive panels use Popover.",
9
+ "variants": [
10
+ {
11
+ "name": "default",
12
+ "what": "dark bubble + info-circle idiom",
13
+ "usage": "73×"
14
+ },
15
+ {
16
+ "name": "chart-like-tooltip",
17
+ "what": "light chart-surface overlay",
18
+ "usage": "2×"
19
+ },
20
+ {
21
+ "name": "placements",
22
+ "what": "top-start/top/left/right/bottom/bottomRight/topLeft",
23
+ "usage": ""
24
+ }
25
+ ],
26
+ "sizes": [],
27
+ "states": [
28
+ {
29
+ "name": "hidden",
30
+ "what": "no tooltip"
31
+ },
32
+ {
33
+ "name": "visible",
34
+ "what": "on hover/focus"
35
+ },
36
+ {
37
+ "name": "disabled",
38
+ "what": "trigger inline, no tooltip"
39
+ }
40
+ ],
41
+ "usage": {
42
+ "total": 94,
43
+ "placementDistribution": {
44
+ "top-start (default)": 73,
45
+ "top": 11,
46
+ "left": 6,
47
+ "bottomRight": 2,
48
+ "topLeft": 1,
49
+ "right": 1
50
+ },
51
+ "overlayClassName": "chart-like-tooltip (2x, chart bg), noc-dashboard-tooltip (1x)",
52
+ "siblingMechanisms": {
53
+ "native title= attribute": "~59x (browser tooltip for plain/truncated text)",
54
+ "v-tooltip directive": "1x",
55
+ "graph/canvas tooltips": "topology/netroute/apm edge & node tooltips — domain-specific content, not MTooltip"
56
+ }
57
+ },
58
+ "props": {
59
+ "placement": {
60
+ "type": "string",
61
+ "default": "top-start",
62
+ "enum": [
63
+ "top",
64
+ "top-start",
65
+ "top-end",
66
+ "bottom",
67
+ "bottom-start",
68
+ "left",
69
+ "right"
70
+ ],
71
+ "note": "VTippy placement"
72
+ },
73
+ "disabled": {
74
+ "type": "boolean",
75
+ "default": false,
76
+ "note": "short-circuits — renders the trigger inline with no tooltip"
77
+ },
78
+ "trigger": {
79
+ "type": "string",
80
+ "default": "hover focus",
81
+ "note": "DECLARED BUT NOT WIRED to VTippy (F1) — VTippy uses its own hover default"
82
+ },
83
+ "overlayClassName": {
84
+ "type": "string",
85
+ "default": null,
86
+ "note": "e.g. chart-like-tooltip"
87
+ },
88
+ "getPopupContainer": {
89
+ "type": "function",
90
+ "default": null,
91
+ "note": "defaults to closest .__panel or document.body"
92
+ }
93
+ },
94
+ "slots": {
95
+ "trigger": "the anchor element (e.g. an info-circle icon)",
96
+ "default": "the floating tooltip content"
97
+ },
98
+ "tokensUsed": [
99
+ "--tooltip-background-color",
100
+ "--tooltip-text-color",
101
+ "--tooltip-box-shadow",
102
+ "--border-color",
103
+ "--chart-tooltip-background"
104
+ ],
105
+ "decisionFlow": [
106
+ "Is the content interactive (buttons, inputs, links)? -> use Popover, NOT a tooltip.",
107
+ "Just the full text of a truncated/plain element? -> native title='' attribute (browser tooltip, ~59x).",
108
+ "A styled/rich/positioned hint on hover/focus? -> MTooltip (the 94x default).",
109
+ "Is it a chart/series hover card? -> MTooltip with overlay-class-name='chart-like-tooltip'.",
110
+ "A topology/graph edge or node tooltip? -> domain-specific graph tooltip component, NOT MTooltip.",
111
+ "Should the hint be conditionally suppressed? -> :disabled='true'."
112
+ ],
113
+ "usageRules": {
114
+ "infoHint": {
115
+ "useWhen": "explain a field/icon with a short text hint",
116
+ "how": "info-circle in the trigger slot + text in the default slot",
117
+ "example": "Polling interval ⓘ -> 'How often the monitor is polled.'"
118
+ },
119
+ "richHover": {
120
+ "useWhen": "a small non-interactive hover card (title + a few key/values)",
121
+ "how": "structured content in the default slot",
122
+ "example": "host hover card in topology"
123
+ },
124
+ "chartTooltip": {
125
+ "useWhen": "a chart/series hover",
126
+ "how": "overlay-class-name='chart-like-tooltip'",
127
+ "example": "metric chart point"
128
+ }
129
+ },
130
+ "do": [
131
+ "Keep content brief and non-interactive",
132
+ "Use the info-circle idiom for field hints",
133
+ "Use :disabled when the hint is redundant"
134
+ ],
135
+ "dont": [
136
+ "Don't put buttons/links/inputs in a tooltip (it dismisses on mouse-out) — use Popover",
137
+ "Don't rely on the `trigger` prop to change activation (it's not wired — F1)"
138
+ ],
139
+ "knownIssues": {
140
+ "F1": {
141
+ "severity": "Low",
142
+ "issue": "`trigger` prop declared (default 'hover focus') but not passed to VTippy — changing it has no effect."
143
+ },
144
+ "F2": {
145
+ "severity": "Medium",
146
+ "a11y": true,
147
+ "issue": "No focus ring on the overlay (`:focus { outline:none }` in _base-popper) — links to SF-001."
148
+ },
149
+ "F3": {
150
+ "severity": "Medium",
151
+ "a11y": true,
152
+ "issue": "Tooltip content is not linked to the trigger via aria-describedby; icon-only triggers have no accessible name — screen-reader users may miss the hint."
153
+ }
154
+ },
155
+ "storybook": "Molecules/Tooltip",
156
+ "related": [
157
+ "popover",
158
+ "modal",
159
+ "dropdown-picker"
160
+ ],
161
+ "figma": {
162
+ "status": "todo"
163
+ },
164
+ "events": "none — VTippy (vue-tippy) driven; the wrapper emits no Vue events. Control visibility via the `disabled` / `trigger` props.",
165
+ "a11y": {
166
+ "summary": "Appears on focus + hover (keyboard-reachable if the trigger is focusable). Keep the trigger ≥24px.",
167
+ "issues": [
168
+ "Icon-only triggers often aren't focusable / have no name.",
169
+ "Bubble not linked via aria-describedby (F3).",
170
+ "Overlay removes the focus outline."
171
+ ],
172
+ "doc": "Molecules/Tooltip/Accessibility",
173
+ "$note": "Catalogue-wide gap SF-001 = no visible :focus-visible ring; tracked in findings/."
174
+ }
175
+ }
@@ -0,0 +1,72 @@
1
+ # Component Specs (one file per component)
2
+
3
+ The detailed, human-readable home for **each component** — everything we learn about it
4
+ in one place, so we don't drown in scattered notes.
5
+
6
+ Each `specs/<name>.md` follows the [enhanced standard](../documentation-standard.md)
7
+ (benchmarked vs Atlassian / Uber Base / Carbon / Spectrum / Polaris):
8
+
9
+ 1. **Header** — tier, **maturity** badge (🟢 stable / 🟡 evolving / 🔴 deprecated), source,
10
+ Storybook + registry + Figma links.
11
+ 2. **Usage analytics** *(our differentiator)* — real counts (total, per variant/size).
12
+ 3. **Overview** — what it is, how it works, when to use.
13
+ 4. **Anatomy** — labeled parts.
14
+ 5. **Options** — variants / sizes / states (with measured rendering).
15
+ 6. **Behaviors** — overflow, loading, responsive, interaction nuances.
16
+ 7. **Content & writing** — label conventions, tone.
17
+ 8. **Accessibility** — keyboard, screen-reader/ARIA, target size, contrast (both themes).
18
+ 9. **Props / API** — table (mirrors the registry).
19
+ 10. **Design tokens used**.
20
+ 11. **Findings & Inconsistencies** *(our differentiator)* — severity + status.
21
+ 12. **Recommended solutions** — concrete fix per finding (with code).
22
+ 13. **Do / Don't**.
23
+ 14. **Related components** — cross-links.
24
+ 15. **Changelog** — dated entries.
25
+
26
+ Relationship to other files:
27
+
28
+ - `specs/<name>.md` (here) = the **human source of truth** per component.
29
+ - `../registry/<name>.json` = the compact **machine/AI-readable** mirror (props, do/don't,
30
+ knownIssues). Kept in sync with the spec.
31
+ - The Storybook story renders it live; this doc explains it.
32
+
33
+ ## Index
34
+
35
+ | Component | Tier | Spec | Findings | Status |
36
+ | --- | --- | --- | --- | --- |
37
+ | [Button](./button.md) | atom | ✅ full standard | navy allow-list (F1); no focus ring (F3); target sizes (F4) | documented |
38
+ | [Checkbox](./checkbox.md) | atom | ✅ full standard | Floto override (F1); **SR state not bound (F3, a11y)**; indeterminate not exposed (F4) | documented |
39
+ | [Switch](./switch.md) | atom | ✅ full standard | `defaultChecked` no-op (F1); knob-only state (F2); no focus ring (F3); off-state `aria-checked` (F4) | documented |
40
+ | [Radio](./radio.md) | atom | ✅ full standard | standalone `MRadio`/variants dead (F1); `buttonStyle` outline unused (F2); no focus ring (F3); **segmented style context-dependent (F4)** | documented |
41
+ | [Link](./link.md) | atom | ✅ full standard | `as-button` not a real link (F1, a11y); no default affordance (F2); **external links lack `rel` — SF-004 (F3)** | documented |
42
+ | [Input](./input.md) | atom | ✅ full standard | v-model event is `update` not `input` (F1); `type=password` no show/hide (F2); no focus ring (F3) | documented |
43
+ | [Select](./select.md) | atom | ✅ full standard (⚠️ low-use) | superseded by DropdownPicker 2× vs 510× (F1); **accessible combobox while DropdownPicker isn't (F2)**; no focus ring (F3); clear × blank (F4) + overlaps chevron (F5) | documented |
44
+ | [Tag](./tag.md) | atom | ✅ full standard | **colored variants illegible (F2)**; **remove × not keyboard-accessible (F4, a11y)**; `closable` default true (F5); class typo (F3); status label inversion (F7) | documented |
45
+ | [Form Field](./form-item.md) | molecule | ✅ full standard | `required` derived from rules not a prop (F1); error message pristine-gated (F2); no focus ring (F3) | documented |
46
+ | [LooseTags](./loose-tags.md) | molecule | ✅ full standard | placeholder ignored in editable mode (F1); case differs by mode (F2); dead `sm`/`size` (F3); fetch has no `.catch` (F4) | documented |
47
+ | [TagsList](./tags-list.md) | molecule | ✅ full standard | ⚠️ **dead code, 0 usages (F1)**; count-only overflow vs live idiom (F2) | documented (badged unused) |
48
+ | [DropdownPicker](./dropdown-picker.md) | organism | ✅ full standard | **not an accessible combobox (F1, a11y, High)**; `maxAllowedSelection` dead (F2); boolean defaults true (F3); loose option schema (F4) | documented |
49
+ | [Modal](./modal.md) | organism | ✅ full standard | no × / no backdrop-close — footer/Escape only (F1, UX/a11y); no focus ring (F2); `scrollable-modal` body has no overflow (F3) | documented |
50
+ | [Drawer](./drawer.md) | organism | ✅ full standard | `@hide` delayed ~500ms (F1); no focus ring (F2) | documented |
51
+ | [Tooltip](./tooltip.md) | molecule | ✅ full standard | dead `trigger` prop (F1); no focus ring (F2); **no `aria-describedby` / icon trigger unnamed (F3, a11y)** | documented |
52
+ | [Popover](./popover.md) | molecule | ✅ full standard | one-way `visible` (F1); **no disclosure ARIA / focus trap (F2, a11y)**; no focus ring (F3) | documented |
53
+ | [Table / Grid](./table.md) | organism | ✅ full standard | heavy (Kendo + workers → reproductions) (F1); **a11y: verify roles/`aria-sort`/`aria-selected`/focus (F2)** | documented |
54
+ | [Filters](./filters.md) | molecule | ✅ full standard | reproductions (FilterCondition 500+ ln) (F1); taxonomy note (N1) | documented |
55
+ | [Toolbars](./toolbars.md) | organism | ✅ full standard | reproductions (F1); a11y: focus ring + icon-button labels (F2) | documented |
56
+ | [Date & Time Pickers](./date-time-pickers.md) | molecule | ✅ full standard | reproductions (store/moment) (F1); a11y focus ring (F2); empty-string→Invalid date (N1) | documented |
57
+ | [Scheduler](./scheduler.md) | molecule | ✅ full standard | sub-forms mis-named OnceForm (F1); lokijs → reproduction (F2) | documented |
58
+ | [Tabs](./tabs.md) | molecule | ✅ full standard | line/top/default only; focus ring (F1) | documented |
59
+
60
+ (Rows added as each component is specced. Tracking list: [`../inventory.md`](../inventory.md).)
61
+
62
+ ## Severity labels (for findings)
63
+
64
+ - **High** — visibly wrong / breaks the design intent (e.g. a used variant renders wrong).
65
+ - **Medium** — inconsistency or ambiguity that should be resolved.
66
+ - **Low** — cosmetic / nice-to-have / cleanup.
67
+
68
+ ## Finding status
69
+
70
+ `Open` (found, no decision) · `Proposed` (fix suggested, needs approval) ·
71
+ `Approved` (decided, not yet applied) · `Fixed` (applied) · `Won't fix` (accepted as-is).
72
+ </content>