openproject-primer_view_components 0.66.1 → 0.67.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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/app/assets/javascripts/components/primer/open_project/tree_view/tree_view.d.ts +2 -0
  4. data/app/assets/javascripts/components/primer/open_project/tree_view/tree_view_sub_tree_node_element.d.ts +4 -2
  5. data/app/assets/javascripts/primer_view_components.js +1 -1
  6. data/app/assets/javascripts/primer_view_components.js.map +1 -1
  7. data/app/assets/styles/primer_view_components.css +1 -1
  8. data/app/assets/styles/primer_view_components.css.map +1 -1
  9. data/app/components/primer/open_project/border_box/collapsible_header.rb +3 -0
  10. data/app/components/primer/open_project/collapsible_section.rb +7 -1
  11. data/app/components/primer/open_project/tree_view/node.html.erb +2 -2
  12. data/app/components/primer/open_project/tree_view/node.rb +49 -26
  13. data/app/components/primer/open_project/tree_view/skeleton_loader.html.erb +1 -1
  14. data/app/components/primer/open_project/tree_view/spinner_loader.html.erb +2 -2
  15. data/app/components/primer/open_project/tree_view/sub_tree.html.erb +1 -1
  16. data/app/components/primer/open_project/tree_view/sub_tree.rb +8 -1
  17. data/app/components/primer/open_project/tree_view/sub_tree_node.rb +9 -3
  18. data/app/components/primer/open_project/tree_view/tree_view.d.ts +2 -0
  19. data/app/components/primer/open_project/tree_view/tree_view.js +29 -9
  20. data/app/components/primer/open_project/tree_view/tree_view.ts +31 -10
  21. data/app/components/primer/open_project/tree_view/tree_view_roving_tab_index.js +11 -7
  22. data/app/components/primer/open_project/tree_view/tree_view_roving_tab_index.ts +13 -8
  23. data/app/components/primer/open_project/tree_view/tree_view_sub_tree_node_element.d.ts +4 -2
  24. data/app/components/primer/open_project/tree_view/tree_view_sub_tree_node_element.js +60 -30
  25. data/app/components/primer/open_project/tree_view/tree_view_sub_tree_node_element.ts +66 -33
  26. data/app/components/primer/open_project/tree_view.css +1 -1
  27. data/app/components/primer/open_project/tree_view.css.json +9 -6
  28. data/app/components/primer/open_project/tree_view.css.map +1 -1
  29. data/app/components/primer/open_project/tree_view.pcss +53 -38
  30. data/app/components/primer/open_project/tree_view.rb +88 -24
  31. data/lib/primer/view_components/version.rb +2 -2
  32. data/previews/primer/open_project/border_box/collapsible_header_preview/playground.html.erb +1 -1
  33. data/previews/primer/open_project/tree_view_preview/buttons.html.erb +10 -0
  34. data/previews/primer/open_project/tree_view_preview/links.html.erb +17 -0
  35. data/previews/primer/open_project/tree_view_preview.rb +29 -3
  36. data/static/arguments.json +38 -2
  37. data/static/constants.json +17 -0
  38. data/static/info_arch.json +95 -3
  39. data/static/previews.json +26 -0
  40. metadata +4 -2
@@ -46,7 +46,6 @@
46
46
  width: 100%;
47
47
  font-size: var(--text-body-size-medium);
48
48
  color: var(--fgColor-default);
49
- cursor: pointer;
50
49
  border-radius: var(--borderRadius-medium);
51
50
  grid-template-columns: var(--spacer-width) var(--leading-action-width) var(--toggle-width) 1fr;
52
51
  grid-template-areas: 'spacer leadingAction toggle content';
@@ -76,13 +75,18 @@
76
75
  outline: none;
77
76
  }
78
77
  }
78
+
79
+ &:has([role='treeitem']:focus-visible) {
80
+ box-shadow: var(--boxShadow-thick) var(--fgColor-accent);
81
+ }
79
82
  }
80
83
 
81
84
  &:where([data-omit-spacer='true']) .TreeViewItemContainer {
82
85
  grid-template-columns: 0 0 0 1fr;
83
86
  }
84
87
 
85
- & .TreeViewItem[aria-current='true'] > .TreeViewItemContainer {
88
+ /* stylelint-disable-next-line selector-max-specificity */
89
+ & .TreeViewItem > .TreeViewItemContainer:has(.TreeViewItemContent[aria-current='true']) {
86
90
  background-color: var(--control-transparent-bgColor-selected);
87
91
 
88
92
  /* Current item indicator */
@@ -109,42 +113,6 @@
109
113
  }
110
114
  }
111
115
 
112
- /* stylelint-disable-next-line no-duplicate-selectors -- Copied from primer/react */
113
- & .TreeViewItem {
114
- &[aria-checked='true'] {
115
- /* stylelint-disable-next-line selector-max-compound-selectors, selector-max-specificity -- Copied from primer/react */
116
- & > .TreeViewItemContainer .FormControl-checkbox {
117
- background: var(--control-checked-bgColor-rest);
118
- border-color: var(--control-checked-borderColor-rest);
119
- transition: background-color, border-color 80ms cubic-bezier(0.32, 0, 0.67, 0) 0ms; /* unchecked -> checked */
120
-
121
- /* stylelint-disable-next-line max-nesting-depth, selector-max-compound-selectors, selector-max-specificity -- Copied from primer/react */
122
- &::before {
123
- visibility: visible;
124
- transition: visibility 0s linear 0s;
125
- animation: checkmarkIn 80ms cubic-bezier(0.65, 0, 0.35, 1) forwards 80ms;
126
- }
127
- }
128
- }
129
-
130
- &[aria-checked='mixed'] {
131
- /* stylelint-disable-next-line selector-max-compound-selectors, selector-max-specificity -- Copied from primer/react */
132
- & > .TreeViewItemContainer .FormControl-checkbox {
133
- background: var(--control-checked-bgColor-rest);
134
- border-color: var(--control-checked-borderColor-rest);
135
- transition: background-color, border-color 80ms cubic-bezier(0.32, 0, 0.67, 0) 0ms; /* unchecked -> checked */
136
-
137
- /* stylelint-disable-next-line max-nesting-depth, selector-max-compound-selectors, selector-max-specificity -- Copied from primer/react */
138
- &::before {
139
- visibility: visible;
140
- mask-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAiIGhlaWdodD0iMiIgdmlld0JveD0iMCAwIDEwIDIiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMCAxQzAgMC40NDc3MTUgMC40NDc3MTUgMCAxIDBIOUM5LjU1MjI5IDAgMTAgMC40NDc3MTUgMTAgMUMxMCAxLjU1MjI4IDkuNTUyMjkgMiA5IDJIMUMwLjQ0NzcxNSAyIDAgMS41NTIyOCAwIDFaIiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K');
141
- animation: checkmarkIn 80ms cubic-bezier(0.65, 0, 0.35, 1) forwards 80ms;
142
- clip-path: none;
143
- }
144
- }
145
- }
146
- }
147
-
148
116
  & .TreeViewItemToggle {
149
117
  display: flex;
150
118
  height: 100%;
@@ -157,6 +125,7 @@
157
125
  grid-area: toggle;
158
126
  justify-content: center;
159
127
  align-items: flex-start;
128
+ cursor: pointer;
160
129
  }
161
130
 
162
131
  & .TreeViewItemToggleHover:hover {
@@ -168,10 +137,24 @@
168
137
  border-bottom-left-radius: var(--borderRadius-medium);
169
138
  }
170
139
 
140
+ /* stylelint-disable-next-line selector-no-qualifying-type */
141
+ & a.TreeViewItemContent:hover, button.TreeViewItemContent:hover {
142
+ text-decoration: underline;
143
+ text-decoration-color: var(--control-fgColor-rest);
144
+ }
145
+
171
146
  & .TreeViewItemContent {
172
147
  display: flex;
173
148
  height: 100%;
174
149
  padding: 0 var(--base-size-8);
150
+ outline: none;
151
+ text-align: left;
152
+ user-select: none;
153
+ background-color: transparent;
154
+ border: none;
155
+ touch-action: manipulation;
156
+ -webkit-tap-highlight-color: transparent;
157
+ cursor: pointer;
175
158
 
176
159
  /* The dynamic top and bottom padding to maintain the minimum item height for single line items */
177
160
  /* stylelint-disable-next-line primer/spacing */
@@ -194,9 +177,41 @@
194
177
  touch-action: manipulation;
195
178
  -webkit-tap-highlight-color: transparent;
196
179
  }
180
+
181
+ &[aria-checked='true'] {
182
+ & .FormControl-checkbox {
183
+ background: var(--control-checked-bgColor-rest);
184
+ border-color: var(--control-checked-borderColor-rest);
185
+ transition: background-color, border-color 80ms cubic-bezier(0.32, 0, 0.67, 0) 0ms; /* unchecked -> checked */
186
+
187
+ /* stylelint-disable-next-line max-nesting-depth, selector-max-specificity -- Copied from primer/react */
188
+ &::before {
189
+ visibility: visible;
190
+ transition: visibility 0s linear 0s;
191
+ animation: checkmarkIn 80ms cubic-bezier(0.65, 0, 0.35, 1) forwards 80ms;
192
+ }
193
+ }
194
+ }
195
+
196
+ &[aria-checked='mixed'] {
197
+ & .FormControl-checkbox {
198
+ background: var(--control-checked-bgColor-rest);
199
+ border-color: var(--control-checked-borderColor-rest);
200
+ transition: background-color, border-color 80ms cubic-bezier(0.32, 0, 0.67, 0) 0ms; /* unchecked -> checked */
201
+
202
+ /* stylelint-disable-next-line max-nesting-depth, selector-max-specificity -- Copied from primer/react */
203
+ &::before {
204
+ visibility: visible;
205
+ mask-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAiIGhlaWdodD0iMiIgdmlld0JveD0iMCAwIDEwIDIiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMCAxQzAgMC40NDc3MTUgMC40NDc3MTUgMCAxIDBIOUM5LjU1MjI5IDAgMTAgMC40NDc3MTUgMTAgMUMxMCAxLjU1MjI4IDkuNTUyMjkgMiA5IDJIMUMwLjQ0NzcxNSAyIDAgMS41NTIyOCAwIDFaIiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K');
206
+ animation: checkmarkIn 80ms cubic-bezier(0.65, 0, 0.35, 1) forwards 80ms;
207
+ clip-path: none;
208
+ }
209
+ }
210
+ }
197
211
  }
198
212
 
199
213
  & .TreeViewItemContentText {
214
+ color: var(--control-fgColor-rest);
200
215
  flex: 1 1 auto;
201
216
  width: 0;
202
217
  }
@@ -17,23 +17,27 @@
17
17
  # <ul role="tree">
18
18
  # <LeafNode>
19
19
  # <Node>
20
- # <li role="treeitem">
21
- # ...
20
+ # <li role="none">
21
+ # <div role="treeitem">
22
+ # ...
23
+ # </div>
22
24
  # </li>
23
25
  # </Node>
24
26
  # </LeafNode>
25
27
  #
26
28
  # <SubTreeNode>
27
29
  # <tree-view-sub-tree-node>
28
- # <li role="treeitem">
30
+ # <li role="none">
29
31
  #
30
32
  # <SubTreeContainer>
31
33
  # <ul role="group">
32
34
  # <SubTree>
33
35
  # <LeafNode>
34
36
  # <Node>
35
- # <li role="treeitem">
36
- # ...
37
+ # <li role="none">
38
+ # <div role="treeitem">
39
+ # ...
40
+ # </div>
37
41
  # </li>
38
42
  # </Node>
39
43
  # </LeafNode>
@@ -41,8 +45,10 @@
41
45
  # <SubTreeNode>
42
46
  # <tree-view-sub-tree-node>
43
47
  # <Node>
44
- # <li role="treeitem">
45
- # ...
48
+ # <li role="none">
49
+ # <div role="treeitem">
50
+ # ...
51
+ # </div>
46
52
  # </li>
47
53
  # </Node>
48
54
  # <SubTreeContainer>
@@ -72,19 +78,21 @@
72
78
  #
73
79
  # <LeafNode>
74
80
  # <Node>
75
- # <li role="treeitem">
76
- # <Visual>
77
- # <IconPair>
78
- # <tree-view-icon-pair>
79
- # <Icon slot="expanded_icon">
80
- # <Primer::Beta::Octicon />
81
- # </Icon>
82
- # <Icon slot="collapsed_icon">
83
- # <Primer::Beta::Octicon />
84
- # </Icon>
85
- # </tree-view-icon-pair>
86
- # </IconPair>
87
- # </Visual>
81
+ # <li role="none">
82
+ # <div role="treeitem">
83
+ # <Visual>
84
+ # <IconPair>
85
+ # <tree-view-icon-pair>
86
+ # <Icon slot="expanded_icon">
87
+ # <Primer::Beta::Octicon />
88
+ # </Icon>
89
+ # <Icon slot="collapsed_icon">
90
+ # <Primer::Beta::Octicon />
91
+ # </Icon>
92
+ # </tree-view-icon-pair>
93
+ # </IconPair>
94
+ # </Visual>
95
+ # </div>
88
96
  # </li>
89
97
  # </Node>
90
98
  # </LeafNode>
@@ -207,7 +215,7 @@ module Primer
207
215
  # Render a `Primer::OpenProject::TreeView::SubTree` in the action's template, tree_view_items/show.html_fragment.erb:
208
216
  #
209
217
  # ```erb
210
- # <%= render(Primer::OpenProject::TreeView::SubTree.new(path: @path)) do |tree| %>
218
+ # <%= render(Primer::OpenProject::TreeView::SubTree.new(path: @path, node_variant: :div)) do |tree| %>
211
219
  # <% tree.with_leaf(...) %>
212
220
  # <% tree.with_sub_tree(...) do |sub_tree| %>
213
221
  # ...
@@ -215,7 +223,53 @@ module Primer
215
223
  # <% end %>
216
224
  # ```
217
225
  #
218
- # ### JavaScript API
226
+ # ## Multi-select mode
227
+ #
228
+ # Passing `select_variant: :multiple` to both sub-tree and leaf nodes will add a check box to the left of the node's
229
+ # label. These check boxes behave according to the value of a second argument, `select_strategy:`.
230
+ #
231
+ # The default select strategy, `:descendants`, will cause all child nodes to be checked when the node is checked.
232
+ # This includes both sub-tree and leaf nodes. When the node is unchecked, all child nodes will also be unchecked.
233
+ # Unchecking a child node of a checked parent will cause the parent to enter a mixed or indeterminate state, which
234
+ # is represented by a horizontal line icon instead of a check mark. This icon indicates that some children are
235
+ # checked, but not all.
236
+ #
237
+ # A secondary select strategy, `:self`, is provided to allow disabling the automatic checking of child nodes. When
238
+ # `select_strategy: :self` is specified, checking sub-tree nodes does not check child nodes, and sub-tree nodes
239
+ # cannot enter a mixed or indeterminate state.
240
+ #
241
+ # Nodes can be checked via the keyboard by pressing the space key.
242
+ #
243
+ # ## Node tags
244
+ #
245
+ # `TreeView`s support three different node variants, `:anchor`, `:button`, and `:div` (the default), which controls
246
+ # which HTML tag is used to construct the nodes. The `:anchor` and `:button` variants correspond to `<a>` and
247
+ # `<button>` tags respectively, which are browser-native elements. Anchors and buttons can be activated (i.e.
248
+ # "clicked") using the mouse or keyboard via the enter or space keys. The node variant must be the same for all
249
+ # nodes in the tree, and is therefore specified at the root level, eg. `TreeView.new(node_variant: :anchor)`.
250
+ #
251
+ # Trees with node variants other than `:div` cannot have check boxes, i.e. cannot be put into multi-select mode.
252
+ #
253
+ # Trees with node variants other than `:div` do not emit the `treeViewNodeActivated` or `treeViewBeforeNodeActivated`
254
+ # events, since it is assumed any behavior associated with these variants is user- or browser-defined.
255
+ #
256
+ # ## Interaction behavior matrix
257
+ #
258
+ # |Interaction |Select variant|Tag |Result |
259
+ # |:---------------|:-------------|:------------|:--------------------------|
260
+ # |Enter/space |none |div |Expands/collapses |
261
+ # |Enter/space |none |anchor/button|Activates anchor/button |
262
+ # |Enter/space |multiple |div |Checks or unchecks |
263
+ # |Enter/space |multiple |anchor/button|N/A (not allowed) |
264
+ # |Left/right arrow|none |div |Expands/collapses |
265
+ # |Left/right arrow|none |anchor/button|Expands/collapses |
266
+ # |Left/right arrow|multiple |div |Expands/collapses |
267
+ # |Left/right arrow|multiple |anchor/button|N/A (not allowed) |
268
+ # |Click |none |div |Expands/collapses |
269
+ # |Click |multiple |div |Checks or unchecks |
270
+ # |Click |multiple |anchor/button|N/A (not allowed) |
271
+ #
272
+ # ## JavaScript API
219
273
  #
220
274
  # `TreeView`s render a `<tree-view>` custom element that exposes behavior to the client.
221
275
  #
@@ -237,7 +291,7 @@ module Primer
237
291
  # |`leafAtPath(path: string[]): HTMLLIElement | null` |Returns the leaf node at the given `path`, if it exists. |
238
292
  # |`getNodeCheckedValue(node: Element): TreeViewCheckedValue` |The same as `checkedValueAtPath`, but accepts a node instead of a path. |
239
293
  #
240
- # #### Events
294
+ # ### Events
241
295
  #
242
296
  # The events enumerated below include node information by way of the `TreeViewNodeInfo` object, which has the
243
297
  # following signature:
@@ -301,6 +355,9 @@ module Primer
301
355
  # both the `treeViewNodeChecked` and `treeViewBeforeNodeChecked` events provide an array of `TreeViewNodeInfo`
302
356
  # objects, which contain entries for every modified node in the tree.
303
357
  class TreeView < Primer::Component
358
+ DEFAULT_NODE_VARIANT = :div
359
+ NODE_VARIANT_OPTIONS = [DEFAULT_NODE_VARIANT, :anchor, :button].freeze
360
+
304
361
  # @!parse
305
362
  # # Adds an leaf node to the tree. Leaf nodes are nodes that do not have children.
306
363
  # #
@@ -322,6 +379,7 @@ module Primer
322
379
  renders: lambda { |component_klass: LeafNode, label:, **system_arguments|
323
380
  component_klass.new(
324
381
  **system_arguments,
382
+ node_variant: node_variant,
325
383
  path: [label],
326
384
  label: label
327
385
  )
@@ -334,6 +392,7 @@ module Primer
334
392
  renders: lambda { |component_klass: SubTreeNode, label:, **system_arguments|
335
393
  component_klass.new(
336
394
  **system_arguments,
395
+ node_variant: node_variant,
337
396
  path: [label],
338
397
  label: label
339
398
  )
@@ -343,10 +402,15 @@ module Primer
343
402
  }
344
403
  }
345
404
 
405
+ attr_reader :node_variant
406
+
407
+ # @param node_variant [Symbol] The variant to use for this node. <%= one_of(Primer::OpenProject::TreeView::NODE_VARIANT_OPTIONS) %>
346
408
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>.
347
- def initialize(**system_arguments)
409
+ def initialize(node_variant: DEFAULT_NODE_VARIANT, **system_arguments)
348
410
  @system_arguments = deny_tag_argument(**system_arguments)
349
411
 
412
+ @node_variant = fetch_or_fallback(NODE_VARIANT_OPTIONS, node_variant, DEFAULT_NODE_VARIANT)
413
+
350
414
  @system_arguments[:tag] = :ul
351
415
  @system_arguments[:role] = :tree
352
416
  @system_arguments[:classes] = class_names(
@@ -5,8 +5,8 @@ module Primer
5
5
  module ViewComponents
6
6
  module VERSION
7
7
  MAJOR = 0
8
- MINOR = 66
9
- PATCH = 1
8
+ MINOR = 67
9
+ PATCH = 0
10
10
 
11
11
  STRING = [MAJOR, MINOR, PATCH].join(".")
12
12
  end
@@ -4,7 +4,7 @@
4
4
  collapsed: collapsed)) do |header| %>
5
5
  <% header.with_title { title } %>
6
6
  <% header.with_count(count: count) %>
7
- <% header.with_description { description } %>
7
+ <% header.with_description { description } unless description.nil? %>
8
8
  <% end %>
9
9
  <% end %>
10
10
  <% component.with_body { "Body" } %>
@@ -0,0 +1,10 @@
1
+ <div style="max-width: 400px">
2
+ <%= render(Primer::OpenProject::TreeView.new(node_variant: :button)) do |tree_view| %>
3
+ <% tree_view.with_sub_tree(label: "Secrets", expanded: expanded, onclick: "alert('Shhhh')") do |sub_tree| %>
4
+ <% sub_tree.with_leaf(label: "Life and the universe", onclick: "alert(42)") %>
5
+ <% sub_tree.with_leaf(label: "Secret ingredient", onclick: "alert('Love')") %>
6
+ <% end %>
7
+
8
+ <% tree_view.with_leaf(label: "What do you give a sick bird?", onclick: "alert('Tweetment')") %>
9
+ <% end %>
10
+ </div>
@@ -0,0 +1,17 @@
1
+ <div style="max-width: 400px">
2
+ <%= render(Primer::OpenProject::TreeView.new(node_variant: :anchor)) do |tree_view| %>
3
+ <% tree_view.with_sub_tree(label: "Cloud Services", href: "https://en.wikipedia.org/wiki/Cloud_computing", target: "blank", expanded: expanded) do |sub_tree| %>
4
+ <% sub_tree.with_leaf(label: "OpenProject", href: "https://www.openproject.org", target: "blank") do |node| %>
5
+ <% node.with_trailing_visual_icon(icon: :"link-external") %>
6
+ <% end %>
7
+
8
+ <% sub_tree.with_leaf(label: "Hetzner", href: "https://www.hetzner.com", target: "blank") do |node| %>
9
+ <% node.with_trailing_visual_icon(icon: :"link-external") %>
10
+ <% end %>
11
+ <% end %>
12
+
13
+ <% tree_view.with_leaf(label: "GitHub", href: "https://github.com", target: "blank") do |node| %>
14
+ <% node.with_trailing_visual_icon(icon: :"link-external") %>
15
+ <% end %>
16
+ <% end %>
17
+ </div>
@@ -10,7 +10,11 @@ module Primer
10
10
  # @param expanded [Boolean] toggle
11
11
  # @param select_variant [Symbol] select [multiple, none]
12
12
  # @param select_strategy [Symbol] select [self, descendants]
13
- def default(expanded: false, select_variant: :none, select_strategy: :descendants)
13
+ def default(
14
+ expanded: false,
15
+ select_variant: Primer::OpenProject::TreeView::Node::DEFAULT_SELECT_VARIANT,
16
+ select_strategy: Primer::OpenProject::TreeView::SubTreeNode::DEFAULT_SELECT_STRATEGY
17
+ )
14
18
  render_with_template(locals: {
15
19
  expanded: coerce_bool(expanded),
16
20
  select_variant: select_variant.to_sym,
@@ -23,7 +27,11 @@ module Primer
23
27
  # @param expanded [Boolean] toggle
24
28
  # @param select_variant [Symbol] select [multiple, none]
25
29
  # @param select_strategy [Symbol] select [self, descendants]
26
- def playground(expanded: false, select_variant: :none, select_strategy: :descendants)
30
+ def playground(
31
+ expanded: false,
32
+ select_variant: Primer::OpenProject::TreeView::Node::DEFAULT_SELECT_VARIANT,
33
+ select_strategy: Primer::OpenProject::TreeView::SubTreeNode::DEFAULT_SELECT_STRATEGY
34
+ )
27
35
  render_with_template(locals: {
28
36
  expanded: coerce_bool(expanded),
29
37
  select_variant: select_variant.to_sym,
@@ -80,7 +88,7 @@ module Primer
80
88
  leading_visual_icon: nil,
81
89
  leading_action_icon: nil,
82
90
  trailing_visual_icon: nil,
83
- select_variant: :none
91
+ select_variant: Primer::OpenProject::TreeView::Node::DEFAULT_SELECT_VARIANT
84
92
  )
85
93
  render_with_template(locals: {
86
94
  label: label,
@@ -91,6 +99,24 @@ module Primer
91
99
  })
92
100
  end
93
101
 
102
+ # @label Links
103
+ #
104
+ # @param expanded [Boolean] toggle
105
+ def links(expanded: false)
106
+ render_with_template(locals: {
107
+ expanded: coerce_bool(expanded)
108
+ })
109
+ end
110
+
111
+ # @label Buttons
112
+ #
113
+ # @param expanded [Boolean] toggle
114
+ def buttons(expanded: false)
115
+ render_with_template(locals: {
116
+ expanded: coerce_bool(expanded)
117
+ })
118
+ end
119
+
94
120
  private
95
121
 
96
122
  def coerce_bool(value)
@@ -5419,6 +5419,12 @@
5419
5419
  "source": "https://github.com/primer/view_components/tree/main/app/components/primer/open_project/file_tree_view.rb",
5420
5420
  "lookbook": "https://primer.style/view-components/lookbook/inspect/primer/open_project/file_tree_view/default/",
5421
5421
  "parameters": [
5422
+ {
5423
+ "name": "node_variant",
5424
+ "type": "Symbol",
5425
+ "default": "`:div`",
5426
+ "description": "The variant to use for this node. One of `:anchor`, `:button`, or `:div`."
5427
+ },
5422
5428
  {
5423
5429
  "name": "system_arguments",
5424
5430
  "type": "Hash",
@@ -5844,6 +5850,12 @@
5844
5850
  "source": "https://github.com/primer/view_components/tree/main/app/components/primer/open_project/tree_view.rb",
5845
5851
  "lookbook": "https://primer.style/view-components/lookbook/inspect/primer/open_project/tree_view/default/",
5846
5852
  "parameters": [
5853
+ {
5854
+ "name": "node_variant",
5855
+ "type": "Symbol",
5856
+ "default": "`:div`",
5857
+ "description": "The variant to use for this node. One of `:anchor`, `:button`, or `:div`."
5858
+ },
5847
5859
  {
5848
5860
  "name": "system_arguments",
5849
5861
  "type": "Hash",
@@ -5970,6 +5982,18 @@
5970
5982
  "default": "N/A",
5971
5983
  "description": "The node's \"path,\" i.e. this node's label and the labels of all its ancestors. This node should be reachable by traversing the tree following this path."
5972
5984
  },
5985
+ {
5986
+ "name": "node_variant",
5987
+ "type": "Symbol",
5988
+ "default": "N/A",
5989
+ "description": "The node variant to use for the node's content, i.e. the `:button` or `:div`. One of `:anchor`, `:button`, or `:div`."
5990
+ },
5991
+ {
5992
+ "name": "href",
5993
+ "type": "String",
5994
+ "default": "`nil`",
5995
+ "description": "The URL to use as the `href` attribute for this node. If set to a truthy value, the `tag:` parameter is ignored and assumed to be `:a`."
5996
+ },
5973
5997
  {
5974
5998
  "name": "current",
5975
5999
  "type": "Boolean",
@@ -5989,10 +6013,10 @@
5989
6013
  "description": "The checked state of the node's checkbox. One of `false`, `mixed`, or `true`."
5990
6014
  },
5991
6015
  {
5992
- "name": "system_arguments",
6016
+ "name": "content_arguments",
5993
6017
  "type": "Hash",
5994
6018
  "default": "N/A",
5995
- "description": "The arguments accepted by [ActionList](/components/alpha/actionlist)."
6019
+ "description": "Arguments attached to the node's content, i.e the `<button>` or `<a>` element. [System arguments](/system-arguments)"
5996
6020
  }
5997
6021
  ]
5998
6022
  },
@@ -6054,6 +6078,12 @@
6054
6078
  "source": "https://github.com/primer/view_components/tree/main/app/components/primer/open_project/tree_view/sub_tree.rb",
6055
6079
  "lookbook": "https://primer.style/view-components/lookbook/inspect/primer/open_project/tree_view/sub_tree/default/",
6056
6080
  "parameters": [
6081
+ {
6082
+ "name": "node_variant",
6083
+ "type": "Symbol",
6084
+ "default": "N/A",
6085
+ "description": "The variant to use for this node. One of `:anchor`, `:button`, or `:div`."
6086
+ },
6057
6087
  {
6058
6088
  "name": "system_arguments",
6059
6089
  "type": "Hash",
@@ -6110,6 +6140,12 @@
6110
6140
  "default": "N/A",
6111
6141
  "description": "The node's \"path,\" i.e. this node's label and the labels of all its ancestors. This node should be reachable by traversing the tree following this path."
6112
6142
  },
6143
+ {
6144
+ "name": "node_variant",
6145
+ "type": "Symbol",
6146
+ "default": "N/A",
6147
+ "description": "The variant to use for this node. One of `:anchor`, `:button`, or `:div`."
6148
+ },
6113
6149
  {
6114
6150
  "name": "expanded",
6115
6151
  "type": "Boolean",
@@ -1786,12 +1786,18 @@
1786
1786
  "GeneratedSlotMethods": "Primer::OpenProject::SubHeader::SegmentedControl::GeneratedSlotMethods"
1787
1787
  },
1788
1788
  "Primer::OpenProject::TreeView": {
1789
+ "DEFAULT_NODE_VARIANT": "div",
1789
1790
  "GeneratedSlotMethods": "Primer::OpenProject::TreeView::GeneratedSlotMethods",
1790
1791
  "Icon": "Primer::OpenProject::TreeView::Icon",
1791
1792
  "IconPair": "Primer::OpenProject::TreeView::IconPair",
1792
1793
  "LeadingAction": "Primer::OpenProject::TreeView::LeadingAction",
1793
1794
  "LeafNode": "Primer::OpenProject::TreeView::LeafNode",
1794
1795
  "LoadingFailureMessage": "Primer::OpenProject::TreeView::LoadingFailureMessage",
1796
+ "NODE_VARIANT_OPTIONS": [
1797
+ "div",
1798
+ "anchor",
1799
+ "button"
1800
+ ],
1795
1801
  "Node": "Primer::OpenProject::TreeView::Node",
1796
1802
  "SkeletonLoader": "Primer::OpenProject::TreeView::SkeletonLoader",
1797
1803
  "SpinnerLoader": "Primer::OpenProject::TreeView::SpinnerLoader",
@@ -1824,8 +1830,19 @@
1824
1830
  "mixed"
1825
1831
  ],
1826
1832
  "DEFAULT_CHECKED_STATE": false,
1833
+ "DEFAULT_NODE_VARIANT": "div",
1827
1834
  "DEFAULT_SELECT_VARIANT": "none",
1828
1835
  "GeneratedSlotMethods": "Primer::OpenProject::TreeView::Node::GeneratedSlotMethods",
1836
+ "NODE_VARIANT_TAG_MAP": {
1837
+ "div": "div",
1838
+ "button": "button",
1839
+ "anchor": "a"
1840
+ },
1841
+ "NODE_VARIANT_TAG_OPTIONS": [
1842
+ "div",
1843
+ "button",
1844
+ "anchor"
1845
+ ],
1829
1846
  "SELECT_VARIANT_OPTIONS": [
1830
1847
  "multiple",
1831
1848
  "none"