senren-ui 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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +33 -0
- data/CONTRIBUTING.md +63 -0
- data/LICENSE +21 -0
- data/README.md +135 -0
- data/Rakefile +22 -0
- data/docs/visual_style.md +51 -0
- data/lib/generators/senren/component/component_generator.rb +62 -0
- data/lib/generators/senren/component/templates/component.html.erb.tt +3 -0
- data/lib/generators/senren/component/templates/component.rb.tt +13 -0
- data/lib/generators/senren/component/templates/component_test.rb.tt +16 -0
- data/lib/generators/senren/component/templates/controller.js.tt +23 -0
- data/lib/generators/senren/component/templates/system_test.rb.tt +7 -0
- data/lib/generators/senren/install/install_generator.rb +67 -0
- data/lib/generators/senren/install/templates/base_component.rb.tt +45 -0
- data/lib/generators/senren/install/templates/conventions.md.tt +66 -0
- data/lib/generators/senren/install/templates/installed_components.yml.tt +4 -0
- data/lib/generators/senren/install/templates/senren.css.tt +164 -0
- data/lib/senren/rails/component_copier.rb +111 -0
- data/lib/senren/rails/doctor.rb +86 -0
- data/lib/senren/rails/engine.rb +16 -0
- data/lib/senren/rails/host_paths.rb +36 -0
- data/lib/senren/rails/installer.rb +83 -0
- data/lib/senren/rails/llms_writer.rb +149 -0
- data/lib/senren/rails/registry.rb +161 -0
- data/lib/senren/rails/skill_writer.rb +166 -0
- data/lib/senren/rails/version.rb +7 -0
- data/lib/senren/rails.rb +39 -0
- data/lib/tasks/senren.rake +74 -0
- data/registry/components.yml +1053 -0
- data/registry/groups.yml +25 -0
- data/registry/recipes.yml +79 -0
- data/templates/components/accordion/accordion_component.html.erb +16 -0
- data/templates/components/accordion/accordion_component.rb +31 -0
- data/templates/components/activity_feed/activity_feed_component.html.erb +22 -0
- data/templates/components/activity_feed/activity_feed_component.rb +19 -0
- data/templates/components/alert/alert_component.html.erb +9 -0
- data/templates/components/alert/alert_component.rb +18 -0
- data/templates/components/alert_dialog/alert_dialog_component.html.erb +34 -0
- data/templates/components/alert_dialog/alert_dialog_component.rb +21 -0
- data/templates/components/api_key_field/api_key_field_component.html.erb +13 -0
- data/templates/components/api_key_field/api_key_field_component.rb +20 -0
- data/templates/components/app_shell/app_shell_component.html.erb +28 -0
- data/templates/components/app_shell/app_shell_component.rb +24 -0
- data/templates/components/aspect_ratio/aspect_ratio_component.html.erb +3 -0
- data/templates/components/aspect_ratio/aspect_ratio_component.rb +14 -0
- data/templates/components/avatar/avatar_component.html.erb +27 -0
- data/templates/components/avatar/avatar_component.rb +30 -0
- data/templates/components/badge/badge_component.html.erb +1 -0
- data/templates/components/badge/badge_component.rb +16 -0
- data/templates/components/billing_plan_card/billing_plan_card_component.html.erb +28 -0
- data/templates/components/billing_plan_card/billing_plan_card_component.rb +27 -0
- data/templates/components/breadcrumb/breadcrumb_component.html.erb +23 -0
- data/templates/components/breadcrumb/breadcrumb_component.rb +30 -0
- data/templates/components/bulk_action_bar/bulk_action_bar_component.html.erb +12 -0
- data/templates/components/bulk_action_bar/bulk_action_bar_component.rb +24 -0
- data/templates/components/button/button_component.html.erb +6 -0
- data/templates/components/button/button_component.rb +29 -0
- data/templates/components/calendar/calendar_component.html.erb +21 -0
- data/templates/components/calendar/calendar_component.rb +30 -0
- data/templates/components/card/card_component.html.erb +13 -0
- data/templates/components/card/card_component.rb +17 -0
- data/templates/components/carousel/carousel_component.html.erb +68 -0
- data/templates/components/carousel/carousel_component.rb +34 -0
- data/templates/components/checkbox/checkbox_component.html.erb +8 -0
- data/templates/components/checkbox/checkbox_component.rb +19 -0
- data/templates/components/checkbox_group/checkbox_group_component.html.erb +10 -0
- data/templates/components/checkbox_group/checkbox_group_component.rb +30 -0
- data/templates/components/clipboard/clipboard_component.html.erb +7 -0
- data/templates/components/clipboard/clipboard_component.rb +17 -0
- data/templates/components/codeblock/codeblock_component.html.erb +11 -0
- data/templates/components/codeblock/codeblock_component.rb +31 -0
- data/templates/components/collapsible/collapsible_component.html.erb +9 -0
- data/templates/components/collapsible/collapsible_component.rb +19 -0
- data/templates/components/combobox/combobox_component.html.erb +19 -0
- data/templates/components/combobox/combobox_component.rb +38 -0
- data/templates/components/command/command_component.html.erb +22 -0
- data/templates/components/command/command_component.rb +38 -0
- data/templates/components/context_menu/context_menu_component.html.erb +11 -0
- data/templates/components/context_menu/context_menu_component.rb +11 -0
- data/templates/components/data_table/data_table_component.html.erb +50 -0
- data/templates/components/data_table/data_table_component.rb +42 -0
- data/templates/components/date_picker/date_picker_component.html.erb +5 -0
- data/templates/components/date_picker/date_picker_component.rb +21 -0
- data/templates/components/dialog/dialog_component.html.erb +38 -0
- data/templates/components/dialog/dialog_component.rb +22 -0
- data/templates/components/dropdown_menu/dropdown_menu_component.html.erb +12 -0
- data/templates/components/dropdown_menu/dropdown_menu_component.rb +36 -0
- data/templates/components/empty_state/empty_state_component.html.erb +18 -0
- data/templates/components/empty_state/empty_state_component.rb +22 -0
- data/templates/components/filter_bar/filter_bar_component.html.erb +5 -0
- data/templates/components/filter_bar/filter_bar_component.rb +15 -0
- data/templates/components/form/form_component.html.erb +3 -0
- data/templates/components/form/form_component.rb +18 -0
- data/templates/components/hover_card/hover_card_component.html.erb +10 -0
- data/templates/components/hover_card/hover_card_component.rb +11 -0
- data/templates/components/input/input_component.html.erb +1 -0
- data/templates/components/input/input_component.rb +28 -0
- data/templates/components/invite_member_dialog/invite_member_dialog_component.html.erb +35 -0
- data/templates/components/invite_member_dialog/invite_member_dialog_component.rb +26 -0
- data/templates/components/label/label_component.html.erb +4 -0
- data/templates/components/label/label_component.rb +19 -0
- data/templates/components/link/link_component.html.erb +1 -0
- data/templates/components/link/link_component.rb +25 -0
- data/templates/components/masked_input/masked_input_component.html.erb +1 -0
- data/templates/components/masked_input/masked_input_component.rb +18 -0
- data/templates/components/native_select/native_select_component.html.erb +14 -0
- data/templates/components/native_select/native_select_component.rb +52 -0
- data/templates/components/page_header/page_header_component.html.erb +20 -0
- data/templates/components/page_header/page_header_component.rb +19 -0
- data/templates/components/pagination/pagination_component.html.erb +11 -0
- data/templates/components/pagination/pagination_component.rb +24 -0
- data/templates/components/popover/popover_component.html.erb +9 -0
- data/templates/components/popover/popover_component.rb +11 -0
- data/templates/components/progress/progress_component.html.erb +11 -0
- data/templates/components/progress/progress_component.rb +26 -0
- data/templates/components/radio_button/radio_button_component.html.erb +8 -0
- data/templates/components/radio_button/radio_button_component.rb +19 -0
- data/templates/components/rich_text_editor_lite/rich_text_editor_lite_component.html.erb +32 -0
- data/templates/components/rich_text_editor_lite/rich_text_editor_lite_component.rb +30 -0
- data/templates/components/search_input/search_input_component.html.erb +14 -0
- data/templates/components/search_input/search_input_component.rb +18 -0
- data/templates/components/select/select_component.html.erb +1 -0
- data/templates/components/select/select_component.rb +19 -0
- data/templates/components/separator/separator_component.html.erb +1 -0
- data/templates/components/separator/separator_component.rb +12 -0
- data/templates/components/settings_section/settings_section_component.html.erb +20 -0
- data/templates/components/settings_section/settings_section_component.rb +18 -0
- data/templates/components/sheet/sheet_component.html.erb +37 -0
- data/templates/components/sheet/sheet_component.rb +27 -0
- data/templates/components/shortcut_key/shortcut_key_component.html.erb +6 -0
- data/templates/components/shortcut_key/shortcut_key_component.rb +15 -0
- data/templates/components/sidebar/sidebar_component.html.erb +14 -0
- data/templates/components/sidebar/sidebar_component.rb +37 -0
- data/templates/components/skeleton/skeleton_component.html.erb +1 -0
- data/templates/components/skeleton/skeleton_component.rb +13 -0
- data/templates/components/stat_card/stat_card_component.html.erb +20 -0
- data/templates/components/stat_card/stat_card_component.rb +31 -0
- data/templates/components/switch/switch_component.html.erb +11 -0
- data/templates/components/switch/switch_component.rb +19 -0
- data/templates/components/table/table_component.html.erb +26 -0
- data/templates/components/table/table_component.rb +35 -0
- data/templates/components/tabs/tabs_component.html.erb +18 -0
- data/templates/components/tabs/tabs_component.rb +35 -0
- data/templates/components/team_member_list/team_member_list_component.html.erb +22 -0
- data/templates/components/team_member_list/team_member_list_component.rb +26 -0
- data/templates/components/textarea/textarea_component.html.erb +1 -0
- data/templates/components/textarea/textarea_component.rb +23 -0
- data/templates/components/theme_toggle/theme_toggle_component.html.erb +4 -0
- data/templates/components/theme_toggle/theme_toggle_component.rb +15 -0
- data/templates/components/tooltip/tooltip_component.html.erb +9 -0
- data/templates/components/tooltip/tooltip_component.rb +16 -0
- data/templates/components/top_nav/top_nav_component.html.erb +21 -0
- data/templates/components/top_nav/top_nav_component.rb +44 -0
- data/templates/components/typography/typography_component.html.erb +1 -0
- data/templates/components/typography/typography_component.rb +24 -0
- data/templates/controllers/accordion_controller.js +27 -0
- data/templates/controllers/alert_dialog_controller.js +38 -0
- data/templates/controllers/api_key_field_controller.js +36 -0
- data/templates/controllers/calendar_controller.js +16 -0
- data/templates/controllers/carousel_controller.js +50 -0
- data/templates/controllers/clipboard_controller.js +17 -0
- data/templates/controllers/collapsible_controller.js +13 -0
- data/templates/controllers/combobox_controller.js +64 -0
- data/templates/controllers/command_controller.js +80 -0
- data/templates/controllers/context_menu_controller.js +36 -0
- data/templates/controllers/data_table_controller.js +34 -0
- data/templates/controllers/date_picker_controller.js +17 -0
- data/templates/controllers/dialog_controller.js +50 -0
- data/templates/controllers/dropdown_menu_controller.js +92 -0
- data/templates/controllers/hover_card_controller.js +17 -0
- data/templates/controllers/invite_member_dialog_controller.js +28 -0
- data/templates/controllers/masked_input_controller.js +30 -0
- data/templates/controllers/popover_controller.js +42 -0
- data/templates/controllers/rich_text_editor_lite_controller.js +443 -0
- data/templates/controllers/select_controller.js +10 -0
- data/templates/controllers/sheet_controller.js +34 -0
- data/templates/controllers/sidebar_controller.js +10 -0
- data/templates/controllers/tabs_controller.js +41 -0
- data/templates/controllers/theme_toggle_controller.js +24 -0
- data/templates/controllers/tooltip_controller.js +10 -0
- metadata +257 -0
|
@@ -0,0 +1,1053 @@
|
|
|
1
|
+
# Senren UI - canonical component registry.
|
|
2
|
+
# Schema:
|
|
3
|
+
# <name>:
|
|
4
|
+
# category: actions|forms|overlays|navigation|layout|data|saas|rich
|
|
5
|
+
# client: default behavior (bool)
|
|
6
|
+
# can_have_client: whether --client is meaningful
|
|
7
|
+
# controller: Stimulus identifier (or null)
|
|
8
|
+
# stub: true => scaffolded placeholder, false/absent => full
|
|
9
|
+
# files: paths copied into host app (relative to host root)
|
|
10
|
+
# depends_on: [<name>, ...]
|
|
11
|
+
# pairs_with: [<name>, ...]
|
|
12
|
+
# variants: [<string>, ...]
|
|
13
|
+
# accessibility: [<string>, ...]
|
|
14
|
+
# ai:
|
|
15
|
+
# use_for: [<string>, ...]
|
|
16
|
+
# avoid: [<string>, ...]
|
|
17
|
+
|
|
18
|
+
components:
|
|
19
|
+
|
|
20
|
+
# ---------------------------------------------------------------- Phase 1
|
|
21
|
+
button:
|
|
22
|
+
category: actions
|
|
23
|
+
client: false
|
|
24
|
+
can_have_client: true
|
|
25
|
+
files:
|
|
26
|
+
- app/components/senren/button_component.rb
|
|
27
|
+
- app/components/senren/button_component.html.erb
|
|
28
|
+
depends_on: []
|
|
29
|
+
pairs_with: [form, dialog, dropdown_menu, alert_dialog]
|
|
30
|
+
variants: [default, primary, secondary, destructive, ghost, link]
|
|
31
|
+
accessibility:
|
|
32
|
+
- Icon-only buttons must include aria-label.
|
|
33
|
+
- Use button for actions and anchor for navigation.
|
|
34
|
+
ai:
|
|
35
|
+
use_for: [primary action, secondary action, form submit, destructive action]
|
|
36
|
+
avoid: [using destructive variant for non-destructive actions]
|
|
37
|
+
|
|
38
|
+
link:
|
|
39
|
+
category: actions
|
|
40
|
+
client: false
|
|
41
|
+
can_have_client: false
|
|
42
|
+
files:
|
|
43
|
+
- app/components/senren/link_component.rb
|
|
44
|
+
- app/components/senren/link_component.html.erb
|
|
45
|
+
depends_on: []
|
|
46
|
+
pairs_with: [button, breadcrumb]
|
|
47
|
+
variants: [default, muted, destructive]
|
|
48
|
+
accessibility: [Use real anchors for navigation, never buttons.]
|
|
49
|
+
ai:
|
|
50
|
+
use_for: [in-app navigation, external links]
|
|
51
|
+
avoid: [triggering destructive actions via a link]
|
|
52
|
+
|
|
53
|
+
badge:
|
|
54
|
+
category: data
|
|
55
|
+
client: false
|
|
56
|
+
can_have_client: false
|
|
57
|
+
files:
|
|
58
|
+
- app/components/senren/badge_component.rb
|
|
59
|
+
- app/components/senren/badge_component.html.erb
|
|
60
|
+
depends_on: []
|
|
61
|
+
pairs_with: [card, table, avatar]
|
|
62
|
+
variants: [default, secondary, success, warning, destructive, outline]
|
|
63
|
+
accessibility: [Provide sufficient color contrast; do not encode meaning by color alone.]
|
|
64
|
+
ai:
|
|
65
|
+
use_for: [status, priority, counts, tags]
|
|
66
|
+
avoid: [interactive actions disguised as badges]
|
|
67
|
+
|
|
68
|
+
typography:
|
|
69
|
+
category: layout
|
|
70
|
+
client: false
|
|
71
|
+
can_have_client: false
|
|
72
|
+
files:
|
|
73
|
+
- app/components/senren/typography_component.rb
|
|
74
|
+
- app/components/senren/typography_component.html.erb
|
|
75
|
+
depends_on: []
|
|
76
|
+
pairs_with: [card, page_header]
|
|
77
|
+
variants: [h1, h2, h3, h4, p, lead, large, small, muted]
|
|
78
|
+
accessibility: [Heading levels must be sequential; do not skip levels.]
|
|
79
|
+
ai:
|
|
80
|
+
use_for: [page titles, body copy, captions]
|
|
81
|
+
avoid: [styling without semantic tag matching]
|
|
82
|
+
|
|
83
|
+
separator:
|
|
84
|
+
category: layout
|
|
85
|
+
client: false
|
|
86
|
+
can_have_client: false
|
|
87
|
+
files:
|
|
88
|
+
- app/components/senren/separator_component.rb
|
|
89
|
+
- app/components/senren/separator_component.html.erb
|
|
90
|
+
depends_on: []
|
|
91
|
+
pairs_with: [card, settings_section]
|
|
92
|
+
variants: [horizontal, vertical]
|
|
93
|
+
accessibility: [role=separator with aria-orientation.]
|
|
94
|
+
ai:
|
|
95
|
+
use_for: [grouping content blocks]
|
|
96
|
+
avoid: [decorative-only use without semantics]
|
|
97
|
+
|
|
98
|
+
skeleton:
|
|
99
|
+
category: data
|
|
100
|
+
client: false
|
|
101
|
+
can_have_client: false
|
|
102
|
+
files:
|
|
103
|
+
- app/components/senren/skeleton_component.rb
|
|
104
|
+
- app/components/senren/skeleton_component.html.erb
|
|
105
|
+
depends_on: []
|
|
106
|
+
pairs_with: [card, table]
|
|
107
|
+
variants: [default, circle, text]
|
|
108
|
+
accessibility: [aria-hidden=true while loading; pair with aria-busy on parent.]
|
|
109
|
+
ai:
|
|
110
|
+
use_for: [loading placeholders]
|
|
111
|
+
avoid: [permanent decoration]
|
|
112
|
+
|
|
113
|
+
avatar:
|
|
114
|
+
category: data
|
|
115
|
+
client: false
|
|
116
|
+
can_have_client: false
|
|
117
|
+
files:
|
|
118
|
+
- app/components/senren/avatar_component.rb
|
|
119
|
+
- app/components/senren/avatar_component.html.erb
|
|
120
|
+
depends_on: []
|
|
121
|
+
pairs_with: [card, team_member_list, dropdown_menu]
|
|
122
|
+
variants: [sm, md, lg]
|
|
123
|
+
accessibility: [alt text required; fallback to initials with role=img and aria-label.]
|
|
124
|
+
ai:
|
|
125
|
+
use_for: [user thumbnail, team list, comments]
|
|
126
|
+
avoid: [decorative-only without alt]
|
|
127
|
+
|
|
128
|
+
alert:
|
|
129
|
+
category: data
|
|
130
|
+
client: false
|
|
131
|
+
can_have_client: false
|
|
132
|
+
files:
|
|
133
|
+
- app/components/senren/alert_component.rb
|
|
134
|
+
- app/components/senren/alert_component.html.erb
|
|
135
|
+
depends_on: []
|
|
136
|
+
pairs_with: [form, page_header]
|
|
137
|
+
variants: [default, info, success, warning, destructive]
|
|
138
|
+
accessibility: [role=alert for error states; role=status for non-urgent updates.]
|
|
139
|
+
ai:
|
|
140
|
+
use_for: [form feedback, page-level notices]
|
|
141
|
+
avoid: [transient toasts - use a toast component instead]
|
|
142
|
+
|
|
143
|
+
card:
|
|
144
|
+
category: layout
|
|
145
|
+
client: false
|
|
146
|
+
can_have_client: false
|
|
147
|
+
files:
|
|
148
|
+
- app/components/senren/card_component.rb
|
|
149
|
+
- app/components/senren/card_component.html.erb
|
|
150
|
+
depends_on: []
|
|
151
|
+
pairs_with: [button, badge, separator]
|
|
152
|
+
variants: [default, muted, outline]
|
|
153
|
+
accessibility: [Use heading inside header slot; landmark roles only when meaningful.]
|
|
154
|
+
ai:
|
|
155
|
+
use_for: [grouping related content, dashboard widgets, list items]
|
|
156
|
+
avoid: [nesting cards inside cards]
|
|
157
|
+
|
|
158
|
+
aspect_ratio:
|
|
159
|
+
category: layout
|
|
160
|
+
client: false
|
|
161
|
+
can_have_client: false
|
|
162
|
+
files:
|
|
163
|
+
- app/components/senren/aspect_ratio_component.rb
|
|
164
|
+
- app/components/senren/aspect_ratio_component.html.erb
|
|
165
|
+
depends_on: []
|
|
166
|
+
pairs_with: [card, avatar]
|
|
167
|
+
variants: [square, video, portrait, ultrawide]
|
|
168
|
+
accessibility: [Inner media must include alt or aria-label.]
|
|
169
|
+
ai:
|
|
170
|
+
use_for: [media, image placeholders, embeds]
|
|
171
|
+
avoid: [forcing aspect on text content]
|
|
172
|
+
|
|
173
|
+
# ---------------------------------------------------------------- Phase 2
|
|
174
|
+
label:
|
|
175
|
+
category: forms
|
|
176
|
+
client: false
|
|
177
|
+
can_have_client: false
|
|
178
|
+
files:
|
|
179
|
+
- app/components/senren/label_component.rb
|
|
180
|
+
- app/components/senren/label_component.html.erb
|
|
181
|
+
depends_on: []
|
|
182
|
+
pairs_with: [input, textarea, checkbox, switch, native_select]
|
|
183
|
+
variants: [default, required]
|
|
184
|
+
accessibility: [Always associate via for=field-id.]
|
|
185
|
+
ai:
|
|
186
|
+
use_for: [labeling form controls]
|
|
187
|
+
avoid: [using placeholder as the only label]
|
|
188
|
+
|
|
189
|
+
form:
|
|
190
|
+
category: forms
|
|
191
|
+
client: false
|
|
192
|
+
can_have_client: false
|
|
193
|
+
files:
|
|
194
|
+
- app/components/senren/form_component.rb
|
|
195
|
+
- app/components/senren/form_component.html.erb
|
|
196
|
+
depends_on: [button]
|
|
197
|
+
pairs_with: [input, textarea, native_select, label, alert]
|
|
198
|
+
variants: [default]
|
|
199
|
+
accessibility: [Group related fields with fieldset/legend; show errors next to fields.]
|
|
200
|
+
ai:
|
|
201
|
+
use_for: [Rails form_with wrappers]
|
|
202
|
+
avoid: [bypassing CSRF or Rails form helpers]
|
|
203
|
+
|
|
204
|
+
input:
|
|
205
|
+
category: forms
|
|
206
|
+
client: false
|
|
207
|
+
can_have_client: false
|
|
208
|
+
files:
|
|
209
|
+
- app/components/senren/input_component.rb
|
|
210
|
+
- app/components/senren/input_component.html.erb
|
|
211
|
+
depends_on: [label]
|
|
212
|
+
pairs_with: [form, label, alert]
|
|
213
|
+
variants: [default, error]
|
|
214
|
+
accessibility: [Pair with label; use aria-invalid and aria-describedby on errors.]
|
|
215
|
+
ai:
|
|
216
|
+
use_for: [text, email, password, number, search, url]
|
|
217
|
+
avoid: [storing structured data in a single text input]
|
|
218
|
+
|
|
219
|
+
textarea:
|
|
220
|
+
category: forms
|
|
221
|
+
client: false
|
|
222
|
+
can_have_client: false
|
|
223
|
+
files:
|
|
224
|
+
- app/components/senren/textarea_component.rb
|
|
225
|
+
- app/components/senren/textarea_component.html.erb
|
|
226
|
+
depends_on: [label]
|
|
227
|
+
pairs_with: [form, label, alert]
|
|
228
|
+
variants: [default, error]
|
|
229
|
+
accessibility: [Pair with label; provide visible character counter for limits.]
|
|
230
|
+
ai:
|
|
231
|
+
use_for: [multi-line text]
|
|
232
|
+
avoid: [rich-text editing - use rich_text_editor_lite]
|
|
233
|
+
|
|
234
|
+
checkbox:
|
|
235
|
+
category: forms
|
|
236
|
+
client: false
|
|
237
|
+
can_have_client: false
|
|
238
|
+
files:
|
|
239
|
+
- app/components/senren/checkbox_component.rb
|
|
240
|
+
- app/components/senren/checkbox_component.html.erb
|
|
241
|
+
depends_on: [label]
|
|
242
|
+
pairs_with: [form, label, checkbox_group]
|
|
243
|
+
variants: [default]
|
|
244
|
+
accessibility: [Always pair with label or aria-label.]
|
|
245
|
+
ai:
|
|
246
|
+
use_for: [boolean preferences, multi-select via checkbox_group]
|
|
247
|
+
avoid: [single-choice scenarios - use radio_button]
|
|
248
|
+
|
|
249
|
+
checkbox_group:
|
|
250
|
+
category: forms
|
|
251
|
+
client: false
|
|
252
|
+
can_have_client: false
|
|
253
|
+
files:
|
|
254
|
+
- app/components/senren/checkbox_group_component.rb
|
|
255
|
+
- app/components/senren/checkbox_group_component.html.erb
|
|
256
|
+
depends_on: [checkbox, label]
|
|
257
|
+
pairs_with: [form, label]
|
|
258
|
+
variants: [default]
|
|
259
|
+
accessibility: [Wrap in fieldset/legend.]
|
|
260
|
+
ai:
|
|
261
|
+
use_for: [multi-select boolean groups]
|
|
262
|
+
avoid: [single-choice groups]
|
|
263
|
+
|
|
264
|
+
radio_button:
|
|
265
|
+
category: forms
|
|
266
|
+
client: false
|
|
267
|
+
can_have_client: false
|
|
268
|
+
files:
|
|
269
|
+
- app/components/senren/radio_button_component.rb
|
|
270
|
+
- app/components/senren/radio_button_component.html.erb
|
|
271
|
+
depends_on: [label]
|
|
272
|
+
pairs_with: [form, label]
|
|
273
|
+
variants: [default]
|
|
274
|
+
accessibility: [Group via fieldset/legend; share name attribute.]
|
|
275
|
+
ai:
|
|
276
|
+
use_for: [single-choice option groups]
|
|
277
|
+
avoid: [multi-select - use checkbox_group]
|
|
278
|
+
|
|
279
|
+
native_select:
|
|
280
|
+
category: forms
|
|
281
|
+
client: false
|
|
282
|
+
can_have_client: false
|
|
283
|
+
files:
|
|
284
|
+
- app/components/senren/native_select_component.rb
|
|
285
|
+
- app/components/senren/native_select_component.html.erb
|
|
286
|
+
depends_on: [label]
|
|
287
|
+
pairs_with: [form, label]
|
|
288
|
+
variants: [default, error]
|
|
289
|
+
accessibility: [Pair with label; native option text must be meaningful.]
|
|
290
|
+
ai:
|
|
291
|
+
use_for: [short option lists, mobile-friendly selects]
|
|
292
|
+
avoid: [long lists - prefer combobox]
|
|
293
|
+
|
|
294
|
+
select:
|
|
295
|
+
category: forms
|
|
296
|
+
client: true
|
|
297
|
+
can_have_client: true
|
|
298
|
+
controller: senren--select
|
|
299
|
+
files:
|
|
300
|
+
- app/components/senren/select_component.rb
|
|
301
|
+
- app/components/senren/select_component.html.erb
|
|
302
|
+
- app/javascript/controllers/senren/select_controller.js
|
|
303
|
+
depends_on: [label, button]
|
|
304
|
+
pairs_with: [form, label]
|
|
305
|
+
variants: [default, error]
|
|
306
|
+
accessibility: [aria-haspopup=listbox; arrow keys for navigation; type-ahead.]
|
|
307
|
+
ai:
|
|
308
|
+
use_for: [styled selects with custom option rendering]
|
|
309
|
+
avoid: [very long lists - use combobox]
|
|
310
|
+
|
|
311
|
+
switch:
|
|
312
|
+
category: forms
|
|
313
|
+
client: false
|
|
314
|
+
can_have_client: false
|
|
315
|
+
files:
|
|
316
|
+
- app/components/senren/switch_component.rb
|
|
317
|
+
- app/components/senren/switch_component.html.erb
|
|
318
|
+
depends_on: [label]
|
|
319
|
+
pairs_with: [form, label, settings_section]
|
|
320
|
+
variants: [default]
|
|
321
|
+
accessibility: [role=switch with aria-checked.]
|
|
322
|
+
ai:
|
|
323
|
+
use_for: [boolean toggles, settings]
|
|
324
|
+
avoid: [actions that need confirmation - use button + dialog]
|
|
325
|
+
|
|
326
|
+
masked_input:
|
|
327
|
+
category: forms
|
|
328
|
+
client: true
|
|
329
|
+
can_have_client: true
|
|
330
|
+
controller: senren--masked-input
|
|
331
|
+
files:
|
|
332
|
+
- app/components/senren/masked_input_component.rb
|
|
333
|
+
- app/components/senren/masked_input_component.html.erb
|
|
334
|
+
- app/javascript/controllers/senren/masked_input_controller.js
|
|
335
|
+
depends_on: [input, label]
|
|
336
|
+
pairs_with: [form, label]
|
|
337
|
+
variants: [default, error]
|
|
338
|
+
accessibility: [Always include a description of expected format.]
|
|
339
|
+
ai:
|
|
340
|
+
use_for: [phone, postal code, credit card, custom formats]
|
|
341
|
+
avoid: [free text fields - use input]
|
|
342
|
+
|
|
343
|
+
# ---------------------------------------------------------------- Phase 3
|
|
344
|
+
dialog:
|
|
345
|
+
category: overlays
|
|
346
|
+
client: true
|
|
347
|
+
can_have_client: true
|
|
348
|
+
controller: senren--dialog
|
|
349
|
+
files:
|
|
350
|
+
- app/components/senren/dialog_component.rb
|
|
351
|
+
- app/components/senren/dialog_component.html.erb
|
|
352
|
+
- app/javascript/controllers/senren/dialog_controller.js
|
|
353
|
+
depends_on: [button]
|
|
354
|
+
pairs_with: [form, alert_dialog]
|
|
355
|
+
variants: [default]
|
|
356
|
+
accessibility:
|
|
357
|
+
- Must have a visible title.
|
|
358
|
+
- Must support Escape key close.
|
|
359
|
+
- Must trap focus and restore on close.
|
|
360
|
+
ai:
|
|
361
|
+
use_for: [confirmation modal, short form modal]
|
|
362
|
+
avoid: [long multi-step workflows, full page replacement]
|
|
363
|
+
|
|
364
|
+
alert_dialog:
|
|
365
|
+
category: overlays
|
|
366
|
+
client: true
|
|
367
|
+
can_have_client: true
|
|
368
|
+
controller: senren--alert-dialog
|
|
369
|
+
files:
|
|
370
|
+
- app/components/senren/alert_dialog_component.rb
|
|
371
|
+
- app/components/senren/alert_dialog_component.html.erb
|
|
372
|
+
- app/javascript/controllers/senren/alert_dialog_controller.js
|
|
373
|
+
depends_on: [button, dialog]
|
|
374
|
+
pairs_with: [button]
|
|
375
|
+
variants: [default, destructive]
|
|
376
|
+
accessibility:
|
|
377
|
+
- role=alertdialog with aria-labelledby.
|
|
378
|
+
- Confirm action receives initial focus only when non-destructive.
|
|
379
|
+
ai:
|
|
380
|
+
use_for: [destructive action confirmation, irreversible operations]
|
|
381
|
+
avoid: [routine modal forms - use dialog]
|
|
382
|
+
|
|
383
|
+
dropdown_menu:
|
|
384
|
+
category: overlays
|
|
385
|
+
client: true
|
|
386
|
+
can_have_client: true
|
|
387
|
+
controller: senren--dropdown-menu
|
|
388
|
+
files:
|
|
389
|
+
- app/components/senren/dropdown_menu_component.rb
|
|
390
|
+
- app/components/senren/dropdown_menu_component.html.erb
|
|
391
|
+
- app/javascript/controllers/senren/dropdown_menu_controller.js
|
|
392
|
+
depends_on: [button]
|
|
393
|
+
pairs_with: [button, table, top_nav]
|
|
394
|
+
variants: [default]
|
|
395
|
+
accessibility:
|
|
396
|
+
- role=menu with role=menuitem children.
|
|
397
|
+
- Arrow keys to navigate; Escape to close; type-ahead optional.
|
|
398
|
+
ai:
|
|
399
|
+
use_for: [contextual actions on rows, account menus]
|
|
400
|
+
avoid: [primary navigation - use top_nav or sidebar]
|
|
401
|
+
|
|
402
|
+
popover:
|
|
403
|
+
category: overlays
|
|
404
|
+
client: true
|
|
405
|
+
can_have_client: true
|
|
406
|
+
controller: senren--popover
|
|
407
|
+
files:
|
|
408
|
+
- app/components/senren/popover_component.rb
|
|
409
|
+
- app/components/senren/popover_component.html.erb
|
|
410
|
+
- app/javascript/controllers/senren/popover_controller.js
|
|
411
|
+
depends_on: [button]
|
|
412
|
+
pairs_with: [button, form]
|
|
413
|
+
variants: [default]
|
|
414
|
+
accessibility: [aria-expanded on trigger; manage focus on open.]
|
|
415
|
+
ai:
|
|
416
|
+
use_for: [small contextual UI like filters or color pickers]
|
|
417
|
+
avoid: [large content - use dialog or sheet]
|
|
418
|
+
|
|
419
|
+
tooltip:
|
|
420
|
+
category: overlays
|
|
421
|
+
client: true
|
|
422
|
+
can_have_client: true
|
|
423
|
+
controller: senren--tooltip
|
|
424
|
+
files:
|
|
425
|
+
- app/components/senren/tooltip_component.rb
|
|
426
|
+
- app/components/senren/tooltip_component.html.erb
|
|
427
|
+
- app/javascript/controllers/senren/tooltip_controller.js
|
|
428
|
+
depends_on: []
|
|
429
|
+
pairs_with: [button, badge, icon]
|
|
430
|
+
variants: [default]
|
|
431
|
+
accessibility:
|
|
432
|
+
- Use aria-describedby; never put critical info in tooltips alone.
|
|
433
|
+
- Keyboard focus must show the tooltip.
|
|
434
|
+
ai:
|
|
435
|
+
use_for: [supplementary hints on hover/focus]
|
|
436
|
+
avoid: [storing required information only in tooltip]
|
|
437
|
+
|
|
438
|
+
hover_card:
|
|
439
|
+
category: overlays
|
|
440
|
+
client: true
|
|
441
|
+
can_have_client: true
|
|
442
|
+
controller: senren--hover-card
|
|
443
|
+
files:
|
|
444
|
+
- app/components/senren/hover_card_component.rb
|
|
445
|
+
- app/components/senren/hover_card_component.html.erb
|
|
446
|
+
- app/javascript/controllers/senren/hover_card_controller.js
|
|
447
|
+
depends_on: []
|
|
448
|
+
pairs_with: [avatar, link]
|
|
449
|
+
variants: [default]
|
|
450
|
+
accessibility: [Provide keyboard activation; do not block touch users.]
|
|
451
|
+
ai:
|
|
452
|
+
use_for: [user hover previews, link previews]
|
|
453
|
+
avoid: [interactive forms - use popover or dialog]
|
|
454
|
+
|
|
455
|
+
sheet:
|
|
456
|
+
category: overlays
|
|
457
|
+
client: true
|
|
458
|
+
can_have_client: true
|
|
459
|
+
controller: senren--sheet
|
|
460
|
+
files:
|
|
461
|
+
- app/components/senren/sheet_component.rb
|
|
462
|
+
- app/components/senren/sheet_component.html.erb
|
|
463
|
+
- app/javascript/controllers/senren/sheet_controller.js
|
|
464
|
+
depends_on: [button]
|
|
465
|
+
pairs_with: [form]
|
|
466
|
+
variants: [right, left, top, bottom]
|
|
467
|
+
accessibility:
|
|
468
|
+
- Trap focus when open.
|
|
469
|
+
- Escape to close.
|
|
470
|
+
- aria-modal=true while open.
|
|
471
|
+
ai:
|
|
472
|
+
use_for: [side panels, mobile filters, edit panels]
|
|
473
|
+
avoid: [destructive confirmation - use alert_dialog]
|
|
474
|
+
|
|
475
|
+
context_menu:
|
|
476
|
+
category: overlays
|
|
477
|
+
client: true
|
|
478
|
+
can_have_client: true
|
|
479
|
+
controller: senren--context-menu
|
|
480
|
+
files:
|
|
481
|
+
- app/components/senren/context_menu_component.rb
|
|
482
|
+
- app/components/senren/context_menu_component.html.erb
|
|
483
|
+
- app/javascript/controllers/senren/context_menu_controller.js
|
|
484
|
+
depends_on: [dropdown_menu]
|
|
485
|
+
pairs_with: [table, data_table]
|
|
486
|
+
variants: [default]
|
|
487
|
+
accessibility:
|
|
488
|
+
- Triggered by right-click and keyboard equivalent (Shift+F10).
|
|
489
|
+
- Must be reachable without a pointer.
|
|
490
|
+
ai:
|
|
491
|
+
use_for: [right-click actions on rows or canvases]
|
|
492
|
+
avoid: [primary navigation; main page actions]
|
|
493
|
+
|
|
494
|
+
# ------------------------------------------------------ Phase 4 (stubs)
|
|
495
|
+
breadcrumb:
|
|
496
|
+
category: navigation
|
|
497
|
+
client: false
|
|
498
|
+
can_have_client: false
|
|
499
|
+
stub: false
|
|
500
|
+
files:
|
|
501
|
+
- app/components/senren/breadcrumb_component.rb
|
|
502
|
+
- app/components/senren/breadcrumb_component.html.erb
|
|
503
|
+
depends_on: [link]
|
|
504
|
+
pairs_with: [page_header]
|
|
505
|
+
variants: [default]
|
|
506
|
+
accessibility: [aria-label="Breadcrumb"; mark current page with aria-current=page.]
|
|
507
|
+
ai:
|
|
508
|
+
use_for: [hierarchical navigation context]
|
|
509
|
+
avoid: [non-hierarchical pages]
|
|
510
|
+
|
|
511
|
+
tabs:
|
|
512
|
+
category: navigation
|
|
513
|
+
client: true
|
|
514
|
+
can_have_client: true
|
|
515
|
+
controller: senren--tabs
|
|
516
|
+
stub: false
|
|
517
|
+
files:
|
|
518
|
+
- app/components/senren/tabs_component.rb
|
|
519
|
+
- app/components/senren/tabs_component.html.erb
|
|
520
|
+
- app/javascript/controllers/senren/tabs_controller.js
|
|
521
|
+
depends_on: []
|
|
522
|
+
pairs_with: [card]
|
|
523
|
+
variants: [default, underline]
|
|
524
|
+
accessibility: [role=tablist with arrow-key navigation and aria-controls.]
|
|
525
|
+
ai:
|
|
526
|
+
use_for: [switching between related views in the same context]
|
|
527
|
+
avoid: [non-related sections - use a separate page]
|
|
528
|
+
|
|
529
|
+
accordion:
|
|
530
|
+
category: navigation
|
|
531
|
+
client: true
|
|
532
|
+
can_have_client: true
|
|
533
|
+
controller: senren--accordion
|
|
534
|
+
stub: false
|
|
535
|
+
files:
|
|
536
|
+
- app/components/senren/accordion_component.rb
|
|
537
|
+
- app/components/senren/accordion_component.html.erb
|
|
538
|
+
- app/javascript/controllers/senren/accordion_controller.js
|
|
539
|
+
depends_on: []
|
|
540
|
+
pairs_with: [card]
|
|
541
|
+
variants: [single, multiple]
|
|
542
|
+
accessibility: [Buttons toggle aria-expanded; panels use aria-hidden.]
|
|
543
|
+
ai:
|
|
544
|
+
use_for: [FAQ, collapsible content sections]
|
|
545
|
+
avoid: [primary navigation]
|
|
546
|
+
|
|
547
|
+
collapsible:
|
|
548
|
+
category: navigation
|
|
549
|
+
client: true
|
|
550
|
+
can_have_client: true
|
|
551
|
+
controller: senren--collapsible
|
|
552
|
+
stub: false
|
|
553
|
+
files:
|
|
554
|
+
- app/components/senren/collapsible_component.rb
|
|
555
|
+
- app/components/senren/collapsible_component.html.erb
|
|
556
|
+
- app/javascript/controllers/senren/collapsible_controller.js
|
|
557
|
+
depends_on: []
|
|
558
|
+
pairs_with: [sidebar, settings_section]
|
|
559
|
+
variants: [default]
|
|
560
|
+
accessibility: [aria-expanded on trigger; aria-controls on panel.]
|
|
561
|
+
ai:
|
|
562
|
+
use_for: [single show/hide toggles]
|
|
563
|
+
avoid: [groups - use accordion]
|
|
564
|
+
|
|
565
|
+
sidebar:
|
|
566
|
+
category: navigation
|
|
567
|
+
client: true
|
|
568
|
+
can_have_client: true
|
|
569
|
+
controller: senren--sidebar
|
|
570
|
+
stub: false
|
|
571
|
+
files:
|
|
572
|
+
- app/components/senren/sidebar_component.rb
|
|
573
|
+
- app/components/senren/sidebar_component.html.erb
|
|
574
|
+
- app/javascript/controllers/senren/sidebar_controller.js
|
|
575
|
+
depends_on: [button]
|
|
576
|
+
pairs_with: [app_shell, top_nav]
|
|
577
|
+
variants: [default, compact]
|
|
578
|
+
accessibility: [role=navigation with aria-label; collapsed state retains tab order.]
|
|
579
|
+
ai:
|
|
580
|
+
use_for: [primary app navigation in dashboards]
|
|
581
|
+
avoid: [marketing sites - use top_nav]
|
|
582
|
+
|
|
583
|
+
theme_toggle:
|
|
584
|
+
category: navigation
|
|
585
|
+
client: true
|
|
586
|
+
can_have_client: true
|
|
587
|
+
controller: senren--theme-toggle
|
|
588
|
+
stub: false
|
|
589
|
+
files:
|
|
590
|
+
- app/components/senren/theme_toggle_component.rb
|
|
591
|
+
- app/components/senren/theme_toggle_component.html.erb
|
|
592
|
+
- app/javascript/controllers/senren/theme_toggle_controller.js
|
|
593
|
+
depends_on: [button]
|
|
594
|
+
pairs_with: [top_nav]
|
|
595
|
+
variants: [default]
|
|
596
|
+
accessibility: [Announce current theme via aria-pressed or aria-label.]
|
|
597
|
+
ai:
|
|
598
|
+
use_for: [light/dark/system theme switching]
|
|
599
|
+
avoid: [non-theme settings]
|
|
600
|
+
|
|
601
|
+
shortcut_key:
|
|
602
|
+
category: navigation
|
|
603
|
+
client: false
|
|
604
|
+
can_have_client: false
|
|
605
|
+
stub: false
|
|
606
|
+
files:
|
|
607
|
+
- app/components/senren/shortcut_key_component.rb
|
|
608
|
+
- app/components/senren/shortcut_key_component.html.erb
|
|
609
|
+
depends_on: []
|
|
610
|
+
pairs_with: [tooltip, command]
|
|
611
|
+
variants: [default]
|
|
612
|
+
accessibility: [Use kbd elements; avoid relying on key visuals alone for instructions.]
|
|
613
|
+
ai:
|
|
614
|
+
use_for: [displaying keyboard shortcuts in tooltips and menus]
|
|
615
|
+
avoid: [as a button - shortcut_key is presentational]
|
|
616
|
+
|
|
617
|
+
# ------------------------------------------------------ Phase 5 (stubs)
|
|
618
|
+
table:
|
|
619
|
+
category: data
|
|
620
|
+
client: false
|
|
621
|
+
can_have_client: false
|
|
622
|
+
stub: false
|
|
623
|
+
files:
|
|
624
|
+
- app/components/senren/table_component.rb
|
|
625
|
+
- app/components/senren/table_component.html.erb
|
|
626
|
+
depends_on: []
|
|
627
|
+
pairs_with: [pagination, dropdown_menu, badge]
|
|
628
|
+
variants: [default, compact]
|
|
629
|
+
accessibility: [Use real th/scope; caption for table summary.]
|
|
630
|
+
ai:
|
|
631
|
+
use_for: [tabular data display]
|
|
632
|
+
avoid: [layout - use grid/flex]
|
|
633
|
+
|
|
634
|
+
pagination:
|
|
635
|
+
category: data
|
|
636
|
+
client: false
|
|
637
|
+
can_have_client: false
|
|
638
|
+
stub: false
|
|
639
|
+
files:
|
|
640
|
+
- app/components/senren/pagination_component.rb
|
|
641
|
+
- app/components/senren/pagination_component.html.erb
|
|
642
|
+
depends_on: [button, link]
|
|
643
|
+
pairs_with: [table, data_table]
|
|
644
|
+
variants: [default]
|
|
645
|
+
accessibility: [aria-current=page on current; nav landmark with label.]
|
|
646
|
+
ai:
|
|
647
|
+
use_for: [paged lists and tables]
|
|
648
|
+
avoid: [infinite scroll feeds]
|
|
649
|
+
|
|
650
|
+
progress:
|
|
651
|
+
category: data
|
|
652
|
+
client: false
|
|
653
|
+
can_have_client: false
|
|
654
|
+
stub: false
|
|
655
|
+
files:
|
|
656
|
+
- app/components/senren/progress_component.rb
|
|
657
|
+
- app/components/senren/progress_component.html.erb
|
|
658
|
+
depends_on: []
|
|
659
|
+
pairs_with: [card, alert]
|
|
660
|
+
variants: [default, success, warning, destructive]
|
|
661
|
+
accessibility: [role=progressbar with aria-valuenow/min/max.]
|
|
662
|
+
ai:
|
|
663
|
+
use_for: [task progress, file upload, loading bars]
|
|
664
|
+
avoid: [decorative animation]
|
|
665
|
+
|
|
666
|
+
clipboard:
|
|
667
|
+
category: data
|
|
668
|
+
client: true
|
|
669
|
+
can_have_client: true
|
|
670
|
+
controller: senren--clipboard
|
|
671
|
+
stub: false
|
|
672
|
+
files:
|
|
673
|
+
- app/components/senren/clipboard_component.rb
|
|
674
|
+
- app/components/senren/clipboard_component.html.erb
|
|
675
|
+
- app/javascript/controllers/senren/clipboard_controller.js
|
|
676
|
+
depends_on: [button]
|
|
677
|
+
pairs_with: [api_key_field, codeblock]
|
|
678
|
+
variants: [default]
|
|
679
|
+
accessibility: [Announce copy success via aria-live region.]
|
|
680
|
+
ai:
|
|
681
|
+
use_for: [copy to clipboard buttons]
|
|
682
|
+
avoid: [non-text content]
|
|
683
|
+
|
|
684
|
+
codeblock:
|
|
685
|
+
category: rich
|
|
686
|
+
client: false
|
|
687
|
+
can_have_client: true
|
|
688
|
+
stub: false
|
|
689
|
+
files:
|
|
690
|
+
- app/components/senren/codeblock_component.rb
|
|
691
|
+
- app/components/senren/codeblock_component.html.erb
|
|
692
|
+
depends_on: []
|
|
693
|
+
pairs_with: [clipboard]
|
|
694
|
+
variants: [default]
|
|
695
|
+
accessibility: [Use pre/code; preserve whitespace.]
|
|
696
|
+
ai:
|
|
697
|
+
use_for: [displaying code samples]
|
|
698
|
+
avoid: [running code - this is read-only display]
|
|
699
|
+
|
|
700
|
+
command:
|
|
701
|
+
category: rich
|
|
702
|
+
client: true
|
|
703
|
+
can_have_client: true
|
|
704
|
+
controller: senren--command
|
|
705
|
+
stub: false
|
|
706
|
+
files:
|
|
707
|
+
- app/components/senren/command_component.rb
|
|
708
|
+
- app/components/senren/command_component.html.erb
|
|
709
|
+
- app/javascript/controllers/senren/command_controller.js
|
|
710
|
+
depends_on: [dialog, input]
|
|
711
|
+
pairs_with: [shortcut_key, dropdown_menu]
|
|
712
|
+
variants: [default]
|
|
713
|
+
accessibility: [aria-activedescendant for current option; type-ahead filtering.]
|
|
714
|
+
ai:
|
|
715
|
+
use_for: [command palettes, quick search]
|
|
716
|
+
avoid: [persistent navigation]
|
|
717
|
+
|
|
718
|
+
combobox:
|
|
719
|
+
category: forms
|
|
720
|
+
client: true
|
|
721
|
+
can_have_client: true
|
|
722
|
+
controller: senren--combobox
|
|
723
|
+
stub: false
|
|
724
|
+
files:
|
|
725
|
+
- app/components/senren/combobox_component.rb
|
|
726
|
+
- app/components/senren/combobox_component.html.erb
|
|
727
|
+
- app/javascript/controllers/senren/combobox_controller.js
|
|
728
|
+
depends_on: [input, button]
|
|
729
|
+
pairs_with: [form, label]
|
|
730
|
+
variants: [default, error]
|
|
731
|
+
accessibility: [WAI-ARIA combobox pattern; aria-expanded; aria-activedescendant.]
|
|
732
|
+
ai:
|
|
733
|
+
use_for: [searchable selects, large option lists]
|
|
734
|
+
avoid: [short, fixed lists - use native_select]
|
|
735
|
+
|
|
736
|
+
calendar:
|
|
737
|
+
category: forms
|
|
738
|
+
client: true
|
|
739
|
+
can_have_client: true
|
|
740
|
+
controller: senren--calendar
|
|
741
|
+
stub: false
|
|
742
|
+
files:
|
|
743
|
+
- app/components/senren/calendar_component.rb
|
|
744
|
+
- app/components/senren/calendar_component.html.erb
|
|
745
|
+
- app/javascript/controllers/senren/calendar_controller.js
|
|
746
|
+
depends_on: [button]
|
|
747
|
+
pairs_with: [date_picker]
|
|
748
|
+
variants: [default]
|
|
749
|
+
accessibility: [grid with row/columnheader; arrow keys to navigate days.]
|
|
750
|
+
ai:
|
|
751
|
+
use_for: [date display and selection]
|
|
752
|
+
avoid: [time-only selection]
|
|
753
|
+
|
|
754
|
+
date_picker:
|
|
755
|
+
category: forms
|
|
756
|
+
client: true
|
|
757
|
+
can_have_client: true
|
|
758
|
+
controller: senren--date-picker
|
|
759
|
+
stub: false
|
|
760
|
+
files:
|
|
761
|
+
- app/components/senren/date_picker_component.rb
|
|
762
|
+
- app/components/senren/date_picker_component.html.erb
|
|
763
|
+
- app/javascript/controllers/senren/date_picker_controller.js
|
|
764
|
+
depends_on: [calendar, popover, input]
|
|
765
|
+
pairs_with: [form, label]
|
|
766
|
+
variants: [default, error]
|
|
767
|
+
accessibility: [Pair input with hidden calendar; provide manual typing fallback.]
|
|
768
|
+
ai:
|
|
769
|
+
use_for: [date input fields]
|
|
770
|
+
avoid: [date ranges - use a range component once added]
|
|
771
|
+
|
|
772
|
+
carousel:
|
|
773
|
+
category: rich
|
|
774
|
+
client: true
|
|
775
|
+
can_have_client: true
|
|
776
|
+
controller: senren--carousel
|
|
777
|
+
stub: false
|
|
778
|
+
files:
|
|
779
|
+
- app/components/senren/carousel_component.rb
|
|
780
|
+
- app/components/senren/carousel_component.html.erb
|
|
781
|
+
- app/javascript/controllers/senren/carousel_controller.js
|
|
782
|
+
depends_on: [button]
|
|
783
|
+
pairs_with: [card]
|
|
784
|
+
variants: [default]
|
|
785
|
+
accessibility: [Provide pause/prev/next controls; respect prefers-reduced-motion.]
|
|
786
|
+
ai:
|
|
787
|
+
use_for: [media galleries, marketing highlights]
|
|
788
|
+
avoid: [primary navigation, important content gating]
|
|
789
|
+
|
|
790
|
+
# ------------------------------------------------------ Phase 6
|
|
791
|
+
app_shell:
|
|
792
|
+
category: saas
|
|
793
|
+
client: false
|
|
794
|
+
can_have_client: false
|
|
795
|
+
stub: false
|
|
796
|
+
files:
|
|
797
|
+
- app/components/senren/app_shell_component.rb
|
|
798
|
+
- app/components/senren/app_shell_component.html.erb
|
|
799
|
+
depends_on: [sidebar, top_nav]
|
|
800
|
+
pairs_with: [page_header]
|
|
801
|
+
variants: [default, compact]
|
|
802
|
+
accessibility: [Provide skip-to-content link; main landmark for page body.]
|
|
803
|
+
ai:
|
|
804
|
+
use_for: [SaaS dashboard layout root]
|
|
805
|
+
avoid: [marketing pages]
|
|
806
|
+
|
|
807
|
+
top_nav:
|
|
808
|
+
category: saas
|
|
809
|
+
client: false
|
|
810
|
+
can_have_client: false
|
|
811
|
+
stub: false
|
|
812
|
+
files:
|
|
813
|
+
- app/components/senren/top_nav_component.rb
|
|
814
|
+
- app/components/senren/top_nav_component.html.erb
|
|
815
|
+
depends_on: [link, button, dropdown_menu]
|
|
816
|
+
pairs_with: [app_shell, sidebar]
|
|
817
|
+
variants: [default]
|
|
818
|
+
accessibility: [role=banner; nav landmark with label.]
|
|
819
|
+
ai:
|
|
820
|
+
use_for: [global header with brand and account menu]
|
|
821
|
+
avoid: [primary in-app navigation - use sidebar]
|
|
822
|
+
|
|
823
|
+
page_header:
|
|
824
|
+
category: saas
|
|
825
|
+
client: false
|
|
826
|
+
can_have_client: false
|
|
827
|
+
stub: false
|
|
828
|
+
files:
|
|
829
|
+
- app/components/senren/page_header_component.rb
|
|
830
|
+
- app/components/senren/page_header_component.html.erb
|
|
831
|
+
depends_on: [typography, button]
|
|
832
|
+
pairs_with: [breadcrumb, app_shell]
|
|
833
|
+
variants: [default]
|
|
834
|
+
accessibility: [Use h1 for page title.]
|
|
835
|
+
ai:
|
|
836
|
+
use_for: [titled page header with actions]
|
|
837
|
+
avoid: [stacking multiple page_headers per page]
|
|
838
|
+
|
|
839
|
+
empty_state:
|
|
840
|
+
category: saas
|
|
841
|
+
client: false
|
|
842
|
+
can_have_client: false
|
|
843
|
+
stub: false
|
|
844
|
+
files:
|
|
845
|
+
- app/components/senren/empty_state_component.rb
|
|
846
|
+
- app/components/senren/empty_state_component.html.erb
|
|
847
|
+
depends_on: [button, typography]
|
|
848
|
+
pairs_with: [card, table]
|
|
849
|
+
variants: [default, illustrated]
|
|
850
|
+
accessibility: [Provide a meaningful heading and a primary action.]
|
|
851
|
+
ai:
|
|
852
|
+
use_for: [zero-result lists, no-data dashboards]
|
|
853
|
+
avoid: [error states - use alert]
|
|
854
|
+
|
|
855
|
+
stat_card:
|
|
856
|
+
category: saas
|
|
857
|
+
client: false
|
|
858
|
+
can_have_client: false
|
|
859
|
+
stub: false
|
|
860
|
+
files:
|
|
861
|
+
- app/components/senren/stat_card_component.rb
|
|
862
|
+
- app/components/senren/stat_card_component.html.erb
|
|
863
|
+
depends_on: [card, typography]
|
|
864
|
+
pairs_with: [badge]
|
|
865
|
+
variants: [default, success, warning, destructive]
|
|
866
|
+
accessibility: [Avoid color-only meaning; include label and value text.]
|
|
867
|
+
ai:
|
|
868
|
+
use_for: [dashboard KPI tiles]
|
|
869
|
+
avoid: [interactive widgets - use card with explicit controls]
|
|
870
|
+
|
|
871
|
+
settings_section:
|
|
872
|
+
category: saas
|
|
873
|
+
client: false
|
|
874
|
+
can_have_client: false
|
|
875
|
+
stub: false
|
|
876
|
+
files:
|
|
877
|
+
- app/components/senren/settings_section_component.rb
|
|
878
|
+
- app/components/senren/settings_section_component.html.erb
|
|
879
|
+
depends_on: [card, separator, typography]
|
|
880
|
+
pairs_with: [form, switch, button]
|
|
881
|
+
variants: [default]
|
|
882
|
+
accessibility: [Each section has a heading and consistent label/value layout.]
|
|
883
|
+
ai:
|
|
884
|
+
use_for: [grouped settings inside a settings page]
|
|
885
|
+
avoid: [unrelated content blocks]
|
|
886
|
+
|
|
887
|
+
data_table:
|
|
888
|
+
category: saas
|
|
889
|
+
client: true
|
|
890
|
+
can_have_client: true
|
|
891
|
+
controller: senren--data-table
|
|
892
|
+
stub: false
|
|
893
|
+
files:
|
|
894
|
+
- app/components/senren/data_table_component.rb
|
|
895
|
+
- app/components/senren/data_table_component.html.erb
|
|
896
|
+
- app/javascript/controllers/senren/data_table_controller.js
|
|
897
|
+
depends_on: [table, dropdown_menu, pagination]
|
|
898
|
+
pairs_with: [filter_bar, search_input]
|
|
899
|
+
variants: [default]
|
|
900
|
+
accessibility: [Inherits from table; columns must have th/scope.]
|
|
901
|
+
ai:
|
|
902
|
+
use_for: [sortable, filterable record lists]
|
|
903
|
+
avoid: [static layout grids]
|
|
904
|
+
|
|
905
|
+
filter_bar:
|
|
906
|
+
category: saas
|
|
907
|
+
client: false
|
|
908
|
+
can_have_client: false
|
|
909
|
+
stub: false
|
|
910
|
+
files:
|
|
911
|
+
- app/components/senren/filter_bar_component.rb
|
|
912
|
+
- app/components/senren/filter_bar_component.html.erb
|
|
913
|
+
depends_on: [button, dropdown_menu]
|
|
914
|
+
pairs_with: [data_table, search_input]
|
|
915
|
+
variants: [default]
|
|
916
|
+
accessibility: [Filter controls are real form controls with labels.]
|
|
917
|
+
ai:
|
|
918
|
+
use_for: [list filters above tables]
|
|
919
|
+
avoid: [primary navigation]
|
|
920
|
+
|
|
921
|
+
search_input:
|
|
922
|
+
category: saas
|
|
923
|
+
client: false
|
|
924
|
+
can_have_client: false
|
|
925
|
+
stub: false
|
|
926
|
+
files:
|
|
927
|
+
- app/components/senren/search_input_component.rb
|
|
928
|
+
- app/components/senren/search_input_component.html.erb
|
|
929
|
+
depends_on: [input, label]
|
|
930
|
+
pairs_with: [filter_bar, data_table]
|
|
931
|
+
variants: [default]
|
|
932
|
+
accessibility: [aria-label or visible label; type=search; submit on Enter.]
|
|
933
|
+
ai:
|
|
934
|
+
use_for: [search above lists or in headers]
|
|
935
|
+
avoid: [global navigation - use command]
|
|
936
|
+
|
|
937
|
+
bulk_action_bar:
|
|
938
|
+
category: saas
|
|
939
|
+
client: false
|
|
940
|
+
can_have_client: false
|
|
941
|
+
stub: false
|
|
942
|
+
files:
|
|
943
|
+
- app/components/senren/bulk_action_bar_component.rb
|
|
944
|
+
- app/components/senren/bulk_action_bar_component.html.erb
|
|
945
|
+
depends_on: [button, dropdown_menu]
|
|
946
|
+
pairs_with: [data_table, table]
|
|
947
|
+
variants: [default]
|
|
948
|
+
accessibility: [Show count of selected items in an aria-live region.]
|
|
949
|
+
ai:
|
|
950
|
+
use_for: [acting on multiple selected rows]
|
|
951
|
+
avoid: [single-row actions - use dropdown_menu]
|
|
952
|
+
|
|
953
|
+
team_member_list:
|
|
954
|
+
category: saas
|
|
955
|
+
client: false
|
|
956
|
+
can_have_client: false
|
|
957
|
+
stub: false
|
|
958
|
+
files:
|
|
959
|
+
- app/components/senren/team_member_list_component.rb
|
|
960
|
+
- app/components/senren/team_member_list_component.html.erb
|
|
961
|
+
depends_on: [avatar, badge, button, dropdown_menu]
|
|
962
|
+
pairs_with: [invite_member_dialog, search_input]
|
|
963
|
+
variants: [default]
|
|
964
|
+
accessibility: [Use semantic list markup.]
|
|
965
|
+
ai:
|
|
966
|
+
use_for: [team management pages]
|
|
967
|
+
avoid: [arbitrary user lists - compose with table or card]
|
|
968
|
+
|
|
969
|
+
invite_member_dialog:
|
|
970
|
+
category: saas
|
|
971
|
+
client: true
|
|
972
|
+
can_have_client: true
|
|
973
|
+
controller: senren--invite-member-dialog
|
|
974
|
+
stub: false
|
|
975
|
+
files:
|
|
976
|
+
- app/components/senren/invite_member_dialog_component.rb
|
|
977
|
+
- app/components/senren/invite_member_dialog_component.html.erb
|
|
978
|
+
- app/javascript/controllers/senren/invite_member_dialog_controller.js
|
|
979
|
+
depends_on: [dialog, form, input, button]
|
|
980
|
+
pairs_with: [team_member_list]
|
|
981
|
+
variants: [default]
|
|
982
|
+
accessibility: [Inherit dialog accessibility; validate email server-side.]
|
|
983
|
+
ai:
|
|
984
|
+
use_for: [team invitation flow]
|
|
985
|
+
avoid: [bulk imports - use a dedicated screen]
|
|
986
|
+
|
|
987
|
+
billing_plan_card:
|
|
988
|
+
category: saas
|
|
989
|
+
client: false
|
|
990
|
+
can_have_client: false
|
|
991
|
+
stub: false
|
|
992
|
+
files:
|
|
993
|
+
- app/components/senren/billing_plan_card_component.rb
|
|
994
|
+
- app/components/senren/billing_plan_card_component.html.erb
|
|
995
|
+
depends_on: [card, button, badge, typography]
|
|
996
|
+
pairs_with: [settings_section]
|
|
997
|
+
variants: [default, current, recommended]
|
|
998
|
+
accessibility: [Use heading; price and features must be readable.]
|
|
999
|
+
ai:
|
|
1000
|
+
use_for: [pricing page or billing settings]
|
|
1001
|
+
avoid: [feature comparison tables - use table]
|
|
1002
|
+
|
|
1003
|
+
api_key_field:
|
|
1004
|
+
category: saas
|
|
1005
|
+
client: true
|
|
1006
|
+
can_have_client: true
|
|
1007
|
+
controller: senren--api-key-field
|
|
1008
|
+
stub: false
|
|
1009
|
+
files:
|
|
1010
|
+
- app/components/senren/api_key_field_component.rb
|
|
1011
|
+
- app/components/senren/api_key_field_component.html.erb
|
|
1012
|
+
- app/javascript/controllers/senren/api_key_field_controller.js
|
|
1013
|
+
depends_on: [input, button, clipboard]
|
|
1014
|
+
pairs_with: [settings_section]
|
|
1015
|
+
variants: [default]
|
|
1016
|
+
accessibility: [Reveal/hide must be reachable by keyboard; copy via clipboard with announcement.]
|
|
1017
|
+
ai:
|
|
1018
|
+
use_for: [secret key display with reveal/copy/regenerate]
|
|
1019
|
+
avoid: [storing secrets in plain text on the server side]
|
|
1020
|
+
|
|
1021
|
+
activity_feed:
|
|
1022
|
+
category: saas
|
|
1023
|
+
client: false
|
|
1024
|
+
can_have_client: false
|
|
1025
|
+
stub: false
|
|
1026
|
+
files:
|
|
1027
|
+
- app/components/senren/activity_feed_component.rb
|
|
1028
|
+
- app/components/senren/activity_feed_component.html.erb
|
|
1029
|
+
depends_on: [avatar, badge, typography]
|
|
1030
|
+
pairs_with: [card]
|
|
1031
|
+
variants: [default]
|
|
1032
|
+
accessibility: [Use a list; each entry has a relative time element.]
|
|
1033
|
+
ai:
|
|
1034
|
+
use_for: [audit logs, comment threads, change history]
|
|
1035
|
+
avoid: [transient notifications - use alert or toast]
|
|
1036
|
+
|
|
1037
|
+
rich_text_editor_lite:
|
|
1038
|
+
category: rich
|
|
1039
|
+
client: true
|
|
1040
|
+
can_have_client: true
|
|
1041
|
+
controller: senren--rich-text-editor-lite
|
|
1042
|
+
stub: false
|
|
1043
|
+
files:
|
|
1044
|
+
- app/components/senren/rich_text_editor_lite_component.rb
|
|
1045
|
+
- app/components/senren/rich_text_editor_lite_component.html.erb
|
|
1046
|
+
- app/javascript/controllers/senren/rich_text_editor_lite_controller.js
|
|
1047
|
+
depends_on: [button]
|
|
1048
|
+
pairs_with: [form, label]
|
|
1049
|
+
variants: [default]
|
|
1050
|
+
accessibility: [Toolbar buttons must have aria-label; use contenteditable role=textbox.]
|
|
1051
|
+
ai:
|
|
1052
|
+
use_for: [light formatting (bold/italic/links/lists) only]
|
|
1053
|
+
avoid: [tables, embeds, media - out of scope for v0.1]
|