@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,186 @@
1
+ {
2
+ "name": "link",
3
+ "component": "FlotoLink",
4
+ "display": "Link",
5
+ "tier": "atom",
6
+ "category": "navigation",
7
+ "source": "app",
8
+ "sourceFile": "src/components/_base-app-link.vue",
9
+ "status": "core",
10
+ "maturity": "stable",
11
+ "summary": "Navigation control. Default renders a RouterLink (<a>); as-button renders an MButton that pushes the route on click. Only own prop is asButton; everything else passes through.",
12
+ "variants": [
13
+ {
14
+ "name": "text-link",
15
+ "what": "RouterLink text (default)",
16
+ "usage": "67×"
17
+ },
18
+ {
19
+ "name": "as-button",
20
+ "what": "MButton + route push",
21
+ "usage": ""
22
+ },
23
+ {
24
+ "name": "external",
25
+ "what": "<a target=_blank>",
26
+ "usage": "147×"
27
+ },
28
+ {
29
+ "name": "k-link",
30
+ "what": "subtle grid/pagination link class",
31
+ "usage": "25×"
32
+ }
33
+ ],
34
+ "sizes": [],
35
+ "states": [
36
+ {
37
+ "name": "default",
38
+ "what": "inherits text colour"
39
+ },
40
+ {
41
+ "name": "hover",
42
+ "what": "text underline"
43
+ },
44
+ {
45
+ "name": "focus",
46
+ "what": "no visible ring (SF-001)"
47
+ },
48
+ {
49
+ "name": "active",
50
+ "what": "current route (as-button)"
51
+ }
52
+ ],
53
+ "family": "Link",
54
+ "props": {
55
+ "asButton": {
56
+ "type": "boolean",
57
+ "default": false,
58
+ "note": "button-styled navigation (MButton + $router.push) vs a plain RouterLink"
59
+ },
60
+ "to": {
61
+ "type": [
62
+ "string",
63
+ "object"
64
+ ],
65
+ "note": "via $attrs — route location / path"
66
+ },
67
+ "target": {
68
+ "type": "string",
69
+ "note": "via $attrs"
70
+ },
71
+ "(MButton props)": {
72
+ "type": "passthrough",
73
+ "note": "when asButton: variant/size/etc. pass through"
74
+ }
75
+ },
76
+ "events": [
77
+ "(passthrough via $listeners)"
78
+ ],
79
+ "slots": [
80
+ "default (link/button content)"
81
+ ],
82
+ "modes": {
83
+ "default": "RouterLink -> real <a> (middle-click / open-in-new-tab work)",
84
+ "asButton": "MButton -> navigates via $router.push on click (no href)"
85
+ },
86
+ "anatomy": [
87
+ "text link (<a>, inherits color)",
88
+ "OR button-styled link (MButton)"
89
+ ],
90
+ "accessibility": {
91
+ "default": "real anchor — correct link role + keyboard + new-tab",
92
+ "asButton": "F1 — a <button>, not an anchor: no href, no middle-click/new-tab, announced as button",
93
+ "focus": "no visible ring (SF-001)"
94
+ },
95
+ "decisionFlow": [
96
+ "Performs an action (save/delete/change state)? -> Button, not a link.",
97
+ "External URL / opens in a new tab? -> plain <a href target=_blank rel=noopener noreferrer> (FlotoLink is internal-only).",
98
+ "Internal navigation (route)? -> FlotoLink.",
99
+ "Internal navigation that should look like a prominent CTA/button? -> FlotoLink as-button (with a variant).",
100
+ "Inline internal navigation in content / menus / breadcrumbs / a clickable value? -> FlotoLink (text link).",
101
+ "A subtle clickable text inside a table/grid? -> class k-link."
102
+ ],
103
+ "usageRules": {
104
+ "text-link(default)": {
105
+ "useWhen": "inline INTERNAL navigation in content, menus, breadcrumbs, logos, a clickable value",
106
+ "dontUse": "for actions (use Button) or external URLs (use a plain anchor)",
107
+ "example": "go to <the inventory list>; a breadcrumb segment"
108
+ },
109
+ "as-button": {
110
+ "useWhen": "a prominent INTERNAL navigation call-to-action that should look like a button",
111
+ "dontUse": "where users expect open-in-new-tab/middle-click (F1 — it's a button, no href)",
112
+ "example": "Go to settings CTA"
113
+ },
114
+ "external-link": {
115
+ "useWhen": "an external/help/doc URL or anything that opens in a new tab",
116
+ "must": "plain <a href target=_blank> with rel=noopener noreferrer (FlotoLink/RouterLink can't do external; SF-004)",
117
+ "example": "documentation/help links"
118
+ },
119
+ "k-link(class)": {
120
+ "useWhen": "subtle clickable text inside a table/grid",
121
+ "note": "--page-text-color, hover -> pagination-active; not brand-colored (25x)"
122
+ }
123
+ },
124
+ "linkClasses": {
125
+ "k-link": 25,
126
+ "resource-link": "8 (mostly legacy/commented)",
127
+ "link-label": 5,
128
+ "completed-link": 3,
129
+ "admin-page-link": 1
130
+ },
131
+ "do": [
132
+ "Use for navigation (route/URL): inline links, menus, breadcrumbs, logos.",
133
+ "Use as-button for a prominent navigation CTA; pass a Button variant.",
134
+ "Name the destination in the link text; add text-primary affordance for inline links."
135
+ ],
136
+ "dont": [
137
+ "Don't use a link for an action (save/delete/apply) — use a Button.",
138
+ "Don't rely on as-button where open-in-new-tab matters (F1)."
139
+ ],
140
+ "whenToUse": "Anything that navigates the user somewhere (route, URL, anchor).",
141
+ "insteadOf": [
142
+ "raw RouterLink",
143
+ "a button styled as a link",
144
+ "an anchor for actions"
145
+ ],
146
+ "usage": {
147
+ "total": 67,
148
+ "files": 48,
149
+ "to": 9
150
+ },
151
+ "knownIssues": [
152
+ "F1 (medium, a11y/UX): as-button navigates via $router.push on an MButton (no href) — loses middle-click/open-in-new-tab and is announced as a button, not a link. Prefer a real anchor styled as a button for nav CTAs.",
153
+ "F2 (low): plain links inherit text color (no default link color/underline) — a bare link can look like text; most usages add text-primary. Consider a default link style.",
154
+ "F3 (low, security) -> SF-004: FlotoLink is internal-only (RouterLink), so external links are raw <a target=_blank> — 147x across the app, 0 with rel=noopener noreferrer (reverse tabnabbing; browser-mitigated). Add a shared external-link component + lint rule. See findings/SF-004."
155
+ ],
156
+ "related": [
157
+ "MButton",
158
+ "MDropdown",
159
+ "RouterLink"
160
+ ],
161
+ "changelog": [
162
+ "2026-06-07: added (decision-grade from the start). 67x/48 files; RouterLink default + as-button MButton route-push; only own prop asButton. Verified in SB (RouterLink + $router stubbed). F1 (as-button not a real link), F2 (no default affordance). Closes Button's navigation relative."
163
+ ],
164
+ "storybook": "Atoms/Link",
165
+ "figma": {
166
+ "status": "todo",
167
+ "component": "Link"
168
+ },
169
+ "tokensUsed": [
170
+ "--primary",
171
+ "--primary-alt",
172
+ "--page-text-color",
173
+ "--neutral-light",
174
+ "--border-color",
175
+ "--pagination-active-bg"
176
+ ],
177
+ "a11y": {
178
+ "summary": "True <a>/RouterLink — link role + keyboard focus. Use destination-naming text (not 'click here'); as-button variant announces as a button.",
179
+ "issues": [
180
+ "No visible focus ring (SF-001).",
181
+ "Plain links inherit text colour (F2) — add an affordance."
182
+ ],
183
+ "doc": "Atoms/Link/Accessibility",
184
+ "$note": "Catalogue-wide gap SF-001 = no visible :focus-visible ring; tracked in findings/."
185
+ }
186
+ }
@@ -0,0 +1,196 @@
1
+ {
2
+ "name": "loose-tags",
3
+ "component": "LooseTags",
4
+ "display": "LooseTags",
5
+ "tier": "molecule",
6
+ "category": "form-input",
7
+ "source": "app",
8
+ "sourceFile": "src/components/loose-tags.vue",
9
+ "status": "core",
10
+ "maturity": "stable",
11
+ "summary": "Free-form tag input (type to create tags) with async suggestions. The Tag family's input member; home of the teal pills.",
12
+ "variants": [
13
+ {
14
+ "name": "editable",
15
+ "what": "mode=tags + suggestions",
16
+ "usage": "default"
17
+ },
18
+ {
19
+ "name": "disabled",
20
+ "what": "SelectedItemPills (read-only)",
21
+ "usage": ""
22
+ },
23
+ {
24
+ "name": "asDropdown",
25
+ "what": "FlotoDropdownPicker searchable multi",
26
+ "usage": ""
27
+ }
28
+ ],
29
+ "sizes": [],
30
+ "states": [
31
+ {
32
+ "name": "default",
33
+ "what": "editable"
34
+ },
35
+ {
36
+ "name": "disabled",
37
+ "what": "read-only pills"
38
+ }
39
+ ],
40
+ "family": "Tag",
41
+ "model": {
42
+ "prop": "value",
43
+ "event": "change"
44
+ },
45
+ "props": {
46
+ "value": {
47
+ "type": "array",
48
+ "default": [],
49
+ "note": "v-model — array of tag strings"
50
+ },
51
+ "disabled": {
52
+ "type": "boolean",
53
+ "default": false,
54
+ "note": "read-only mode → SelectedItemPills teal pills"
55
+ },
56
+ "asDropdown": {
57
+ "type": "boolean",
58
+ "default": false,
59
+ "note": "searchable FlotoDropdownPicker mode (covered by DropdownPicker spec)"
60
+ },
61
+ "singleSelection": {
62
+ "type": "boolean",
63
+ "default": false,
64
+ "note": "caps to 1 — ONLY effective in asDropdown"
65
+ },
66
+ "counter": {
67
+ "type": "object",
68
+ "default": "undefined",
69
+ "note": "{ key } scopes suggestion fetch; watched (refetch on change)"
70
+ },
71
+ "tagType": {
72
+ "type": "string",
73
+ "note": "filters suggestion fetch"
74
+ },
75
+ "userTagOnly": {
76
+ "type": "boolean",
77
+ "default": false,
78
+ "note": "filters suggestion fetch"
79
+ },
80
+ "placeholder": {
81
+ "type": "string",
82
+ "default": " ",
83
+ "note": "ONLY used in asDropdown (F1); editable mode hardcodes 'Add Tags'"
84
+ },
85
+ "sm": {
86
+ "type": "boolean",
87
+ "default": true,
88
+ "note": "DEAD — drives size computed that is never bound (F3)"
89
+ }
90
+ },
91
+ "events": [
92
+ "change"
93
+ ],
94
+ "slots": [
95
+ "clearIcon (set to times-circle)"
96
+ ],
97
+ "modes": {
98
+ "default": "MSelect mode=tags + .loose-tags-input — type-to-create + suggestions; normalizes lowercase+trim+dedupe",
99
+ "disabled": "SelectedItemPills teal pills (read-only, no API)",
100
+ "asDropdown": "FlotoDropdownPicker as-input searchable multiple (DropdownPicker spec); trims, preserves case"
101
+ },
102
+ "anatomy": [
103
+ "teal pills (orange ×)",
104
+ "free-text input",
105
+ "suggestions dropdown (from API)"
106
+ ],
107
+ "styling": {
108
+ "pill": "--main-tags-bg-color/--main-tags-text-color teal, 22px, radius 4px",
109
+ "removeIcon": "--secondary-orange",
110
+ "font": "JetBrains Mono (.loose-tags-input)"
111
+ },
112
+ "tokensUsed": [
113
+ "--main-tags-bg-color",
114
+ "--main-tags-text-color",
115
+ "--secondary-orange"
116
+ ],
117
+ "accessibility": {
118
+ "semantics": "Ant Select mode=tags (combobox); Enter add, Backspace remove last, Arrows navigate",
119
+ "focus": "no visible ring (SF-001)",
120
+ "clear": "native clear hidden via CSS (selection__clear display:none)"
121
+ },
122
+ "do": [
123
+ "Use to capture a list of free-form or known tags (v-model an array).",
124
+ "Pass :counter to scope suggestions; use disabled for read-only display."
125
+ ],
126
+ "dont": [
127
+ "Don't rely on placeholder in editable mode (F1) or sm for sizing (F3).",
128
+ "Don't assume case is preserved — default mode lowercases (F2)."
129
+ ],
130
+ "whenToUse": "Capturing a list of tags on a form (free-form or from known suggestions).",
131
+ "decisionFlow": [
132
+ "Just displaying tags (label/count/status)? -> MTag/MStatusTag, not LooseTags.",
133
+ "Read-only display of an existing list? -> disabled.",
134
+ "Pick from a known/suggested set with search? -> asDropdown.",
135
+ "Free-type to create new tags? -> default (editable).",
136
+ "Only one tag allowed? -> singleSelection (with asDropdown)."
137
+ ],
138
+ "usageRules": {
139
+ "editable(default)": {
140
+ "useWhen": "user types values + Enter to add; suggestions offered; lowercased/trimmed/deduped",
141
+ "example": "free-form tags on a monitor"
142
+ },
143
+ "disabled": {
144
+ "useWhen": "show an existing tag list read-only (view-mode forms, detail panels)"
145
+ },
146
+ "asDropdown": {
147
+ "useWhen": "pick from known tags (searchable picker) instead of free-typing"
148
+ },
149
+ "singleSelection": {
150
+ "useWhen": "only one tag may be selected (caps asDropdown to 1)",
151
+ "note": "no effect in default editable mode"
152
+ },
153
+ "counter": {
154
+ "useWhen": "scope suggestions to a specific entity (dominant real usage)"
155
+ }
156
+ },
157
+ "usage": {
158
+ "total": 94,
159
+ "files": 80,
160
+ "counter": 69,
161
+ "asDropdown": 10,
162
+ "tagType": 24,
163
+ "userTagOnly": 4,
164
+ "singleSelection": 2
165
+ },
166
+ "knownIssues": [
167
+ "F1 (medium): placeholder prop ignored in editable mode (hardcoded 'Add Tags'); only used in asDropdown. Bind it on MSelect too.",
168
+ "F2 (low): default mode lowercases tags; asDropdown preserves case — inconsistent normalization.",
169
+ "F3 (low): sm prop + size computed are dead (size never bound) — input always default size.",
170
+ "F4 (low): getAllTagsApi().then() has no .catch — failed/offline fetch is an unhandled rejection (404 pageerror in Storybook). Add .catch → tagOptions=[]."
171
+ ],
172
+ "related": [
173
+ "MTag",
174
+ "MStatusTag",
175
+ "SelectedItemPills",
176
+ "FlotoDropdownPicker",
177
+ "MSelect"
178
+ ],
179
+ "changelog": [
180
+ "2026-06-07: added — 3 render modes mapped; teal pills + JetBrains Mono verified light+dark; F1-F4; classified as Tag family input member (D12); Option B pages."
181
+ ],
182
+ "storybook": "Molecules/LooseTags",
183
+ "figma": {
184
+ "status": "todo",
185
+ "component": "LooseTags"
186
+ },
187
+ "a11y": {
188
+ "summary": "Type + Enter to add a pill; Backspace removes the last; Arrow keys navigate suggestions, Enter selects. Exposes a combobox/listbox.",
189
+ "issues": [
190
+ "No visible focus ring (SF-001).",
191
+ "Remove × is small — ensure hit target."
192
+ ],
193
+ "doc": "Molecules/LooseTags/Accessibility",
194
+ "$note": "Catalogue-wide gap SF-001 = no visible :focus-visible ring; tracked in findings/."
195
+ }
196
+ }
@@ -0,0 +1,145 @@
1
+ {
2
+ "name": "menu",
3
+ "display": "Menu",
4
+ "tier": "molecule",
5
+ "family": "Menu",
6
+ "status": "stable",
7
+ "summary": "The MMenu primitive (a vertical list of selectable icon+label rows, with dividers and danger/positive colours) catalogued in its own right, plus its action-surface usage: the Context/Action menu (FlotoGridActions — a '...' trigger opening an MMenu of actions).",
8
+ "variants": [
9
+ {
10
+ "name": "menu-primitive",
11
+ "what": "MMenu list of rows",
12
+ "usage": "13×"
13
+ },
14
+ {
15
+ "name": "context-menu",
16
+ "what": "⋯ → MMenu of actions",
17
+ "usage": "grid rows"
18
+ }
19
+ ],
20
+ "sizes": [],
21
+ "states": [
22
+ {
23
+ "name": "hover",
24
+ "what": "--neutral-lighter"
25
+ },
26
+ {
27
+ "name": "selected",
28
+ "what": "--primary on tint"
29
+ },
30
+ {
31
+ "name": "danger",
32
+ "what": "--secondary-red"
33
+ },
34
+ {
35
+ "name": "positive",
36
+ "what": "--secondary-green"
37
+ },
38
+ {
39
+ "name": "disabled",
40
+ "what": "not interactive"
41
+ }
42
+ ],
43
+ "renders": "REFERENCE REPRODUCTIONS — the live MMenu needs Ant menu context/theme. Built with real tokens + MIcon.",
44
+ "members": {
45
+ "Menu": {
46
+ "source": "@motadata/ui MMenu / MMenuItem / MMenuDivider",
47
+ "usage": "13x",
48
+ "what": "the primitive — a vertical list of selectable rows (icon + label); states: hover (--neutral-lighter), selected (--primary on --code-tag-background-color); MMenuDivider (--border-color); danger (--secondary-red) / positive (--secondary-green) item colours",
49
+ "buildingBlockFor": [
50
+ "navigation (Primary nav, Side menu)",
51
+ "dropdownpicker",
52
+ "menu (Context/Action menu)"
53
+ ]
54
+ },
55
+ "ContextMenu": {
56
+ "source": "components/_base-grid-actions.vue (FlotoGridActions) + MDropdown (1x, rich-text editor table options)",
57
+ "usage": "grid rows + 1x MDropdown",
58
+ "what": "an action surface — an MPopover (placement bottomRight) triggered by an ellipsis-v '...' icon, opening an MMenu of ACTION items (icon + label); permission-gated (create/edit/delete keys), supports dividers, danger=red / positive=green",
59
+ "isActionSurface": true
60
+ }
61
+ },
62
+ "decisionFlow": [
63
+ "A list of items to render inside something (nav, picker, dropdown)? -> Menu primitive.",
64
+ "A '...' or button that opens a list of ACTIONS on a row/object? -> Context / Action menu.",
65
+ "Pick a VALUE from options (single/multi)? -> Dropdown picker / Select (not this family).",
66
+ "Go to a destination? -> Navigation (Primary nav / Side menu / Tabs)."
67
+ ],
68
+ "do": [
69
+ "Reuse the Menu primitive; use FlotoGridActions for row actions.",
70
+ "Colour danger actions with --secondary-red, positive with --secondary-green.",
71
+ "Gate menu items by permission (create/edit/delete keys)."
72
+ ],
73
+ "dont": [
74
+ "Don't confuse an actions menu with a value picker (use Dropdown picker / Select).",
75
+ "Don't confuse it with navigation (go somewhere).",
76
+ "Don't hand-roll a <ul> dropdown; don't rely on colour alone for danger."
77
+ ],
78
+ "knownIssues": {
79
+ "F1": {
80
+ "severity": "Low",
81
+ "issue": "Primitive reproduced (live MMenu needs Ant menu context) -> real tokens + MIcon."
82
+ },
83
+ "F2": {
84
+ "severity": "Low",
85
+ "a11y": true,
86
+ "issue": "Verify role=menu/menuitem, arrow-key + Esc, trigger aria-label, focus return, non-colour-only danger."
87
+ },
88
+ "F3": {
89
+ "severity": "Info",
90
+ "issue": "MDropdown appears only 1x (editor); the standard action menu is FlotoGridActions (MPopover + MMenu)."
91
+ }
92
+ },
93
+ "tokensUsed": [
94
+ "--page-background-color",
95
+ "--border-color",
96
+ "--neutral-lighter",
97
+ "--code-tag-background-color",
98
+ "--primary",
99
+ "--secondary-red",
100
+ "--secondary-green",
101
+ "--page-text-color"
102
+ ],
103
+ "storybook": "Molecules/Menu",
104
+ "related": [
105
+ "navigation",
106
+ "dropdownpicker",
107
+ "select",
108
+ "popover",
109
+ "toolbars",
110
+ "table"
111
+ ],
112
+ "figma": {
113
+ "status": "todo"
114
+ },
115
+ "apis": {
116
+ "ContextMenu": {
117
+ "source": "src/components/_base-grid-actions.vue (FlotoGridActions)",
118
+ "props": {
119
+ "actions": "Array<{key,name,icon?,isDanger?|redAction?,greenAction?,type?:'divider'}>",
120
+ "resource": "Object (the row, required)",
121
+ "createPermissionKeys/editPermissionKeys/deletePermissionKeys": "Array of action keys gated by the matching *PermissionName",
122
+ "createPermissionName/editPermissionName/deletePermissionName": "String permission const",
123
+ "overlayClassName": "String (default 'picker-action-dropdown')",
124
+ "textClassName": "String (default 'text-neutral-light')",
125
+ "useDelayedHide": "Boolean"
126
+ },
127
+ "events": {
128
+ "selected": "(action) on any pick",
129
+ "<actionKey>": "also emitted by the action's key (e.g. @delete)"
130
+ },
131
+ "slots": {
132
+ "trigger": "{ toggle } — default is the ⋯ ellipsis-v"
133
+ },
134
+ "actionItem": "{ key, name, icon, isDanger|redAction (red), greenAction (green), type:'divider' }"
135
+ }
136
+ },
137
+ "a11y": {
138
+ "summary": "role=menu + menuitem; ↑/↓ move, Enter/Space activate, Esc closes + restores focus (trapped while open); not colour-only (danger/positive carry icon+label).",
139
+ "issues": [
140
+ "The ellipsis-v ⋯ trigger is icon-only — needs an aria-label."
141
+ ],
142
+ "doc": "Molecules/Menu/Accessibility",
143
+ "$note": "Catalogue-wide gap SF-001 = no visible :focus-visible ring; tracked in findings/."
144
+ }
145
+ }