openproject-primer_view_components 0.84.5 → 0.86.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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/app/assets/javascripts/components/primer/open_project/sub_header_element.d.ts +1 -1
  4. data/app/assets/javascripts/primer_view_components.js +1 -1
  5. data/app/assets/javascripts/primer_view_components.js.map +1 -1
  6. data/app/assets/styles/primer_view_components.css +1 -1
  7. data/app/assets/styles/primer_view_components.css.map +1 -1
  8. data/app/components/primer/alpha/select_panel_element.js +2 -2
  9. data/app/components/primer/alpha/select_panel_element.ts +2 -2
  10. data/app/components/primer/alpha/tree_view/leaf_node.html.erb +5 -0
  11. data/app/components/primer/alpha/tree_view/leaf_node.rb +18 -0
  12. data/app/components/primer/alpha/tree_view/node.html.erb +3 -0
  13. data/app/components/primer/alpha/tree_view/node.rb +10 -0
  14. data/app/components/primer/alpha/tree_view/sub_tree_node.html.erb +5 -0
  15. data/app/components/primer/alpha/tree_view/sub_tree_node.rb +18 -0
  16. data/app/components/primer/alpha/tree_view/trailing_action.html.erb +3 -0
  17. data/app/components/primer/alpha/tree_view/trailing_action.rb +18 -0
  18. data/app/components/primer/alpha/tree_view.css +1 -1
  19. data/app/components/primer/alpha/tree_view.css.json +4 -1
  20. data/app/components/primer/alpha/tree_view.css.map +1 -1
  21. data/app/components/primer/alpha/tree_view.pcss +22 -6
  22. data/app/components/primer/open_project/filterable_tree_view/sub_tree.rb +6 -6
  23. data/app/components/primer/open_project/filterable_tree_view.css +1 -0
  24. data/app/components/primer/open_project/filterable_tree_view.css.json +14 -0
  25. data/app/components/primer/open_project/filterable_tree_view.css.map +1 -0
  26. data/app/components/primer/open_project/filterable_tree_view.html.erb +26 -14
  27. data/app/components/primer/open_project/filterable_tree_view.js +294 -5
  28. data/app/components/primer/open_project/filterable_tree_view.pcss +57 -0
  29. data/app/components/primer/open_project/filterable_tree_view.rb +58 -10
  30. data/app/components/primer/open_project/filterable_tree_view.ts +316 -4
  31. data/app/components/primer/open_project/sub_header.css +1 -1
  32. data/app/components/primer/open_project/sub_header.css.json +2 -1
  33. data/app/components/primer/open_project/sub_header.css.map +1 -1
  34. data/app/components/primer/open_project/sub_header.html.erb +11 -8
  35. data/app/components/primer/open_project/sub_header.pcss +14 -7
  36. data/app/components/primer/open_project/sub_header.rb +46 -25
  37. data/app/components/primer/open_project/sub_header_element.d.ts +1 -1
  38. data/app/components/primer/open_project/sub_header_element.js +6 -6
  39. data/app/components/primer/open_project/sub_header_element.ts +5 -10
  40. data/app/components/primer/primer.pcss +1 -0
  41. data/app/controllers/primer/view_components/filterable_tree_view_items_controller.rb +192 -0
  42. data/app/views/primer/view_components/filterable_tree_view_items/_node.html.erb +38 -0
  43. data/app/views/primer/view_components/filterable_tree_view_items/async_form_tree.html.erb +9 -0
  44. data/app/views/primer/view_components/filterable_tree_view_items/index.html.erb +6 -0
  45. data/config/routes.rb +4 -0
  46. data/lib/primer/view_components/version.rb +2 -2
  47. data/previews/primer/alpha/select_panel_preview.rb +0 -27
  48. data/previews/primer/alpha/text_area_preview.rb +0 -1
  49. data/previews/primer/alpha/text_field_preview.rb +0 -1
  50. data/previews/primer/alpha/tree_view_preview/leaf_node_playground.html.erb +4 -0
  51. data/previews/primer/alpha/tree_view_preview.rb +3 -0
  52. data/previews/primer/open_project/filterable_tree_view_preview/async.html.erb +3 -0
  53. data/previews/primer/open_project/filterable_tree_view_preview/async_form_input.html.erb +9 -0
  54. data/previews/primer/open_project/filterable_tree_view_preview/link_nodes.html.erb +18 -0
  55. data/previews/primer/open_project/filterable_tree_view_preview.rb +23 -2
  56. data/previews/primer/open_project/sub_header_preview/quick_filters.html.erb +47 -0
  57. data/previews/primer/open_project/sub_header_preview.rb +23 -1
  58. data/static/arguments.json +28 -0
  59. data/static/audited_at.json +1 -0
  60. data/static/classes.json +9 -0
  61. data/static/constants.json +10 -1
  62. data/static/info_arch.json +189 -30
  63. data/static/previews.json +94 -29
  64. data/static/statuses.json +1 -0
  65. metadata +18 -10
@@ -23,17 +23,17 @@ let SubHeaderElement = class SubHeaderElement extends HTMLElement {
23
23
  }
24
24
  }
25
25
  expandFilterInput() {
26
- for (const item of this.hiddenItemsOnExpandedFilter) {
27
- item.classList.add('d-none');
28
- }
29
26
  for (const item of this.shownItemsOnExpandedFilter) {
30
27
  item.classList.remove('d-none');
31
28
  }
29
+ for (const item of this.filterExpandButton) {
30
+ item.classList.add('d-none');
31
+ }
32
32
  this.classList.add('SubHeader--expandedSearch');
33
33
  this.filterInput.focus();
34
34
  }
35
35
  collapseFilterInput() {
36
- for (const item of this.hiddenItemsOnExpandedFilter) {
36
+ for (const item of this.filterExpandButton) {
37
37
  item.classList.remove('d-none');
38
38
  }
39
39
  for (const item of this.shownItemsOnExpandedFilter) {
@@ -63,10 +63,10 @@ __decorate([
63
63
  ], SubHeaderElement.prototype, "filterInput", void 0);
64
64
  __decorate([
65
65
  targets
66
- ], SubHeaderElement.prototype, "hiddenItemsOnExpandedFilter", void 0);
66
+ ], SubHeaderElement.prototype, "shownItemsOnExpandedFilter", void 0);
67
67
  __decorate([
68
68
  targets
69
- ], SubHeaderElement.prototype, "shownItemsOnExpandedFilter", void 0);
69
+ ], SubHeaderElement.prototype, "filterExpandButton", void 0);
70
70
  SubHeaderElement = __decorate([
71
71
  controller
72
72
  ], SubHeaderElement);
@@ -3,8 +3,8 @@ import {controller, target, targets} from '@github/catalyst'
3
3
  @controller
4
4
  class SubHeaderElement extends HTMLElement {
5
5
  @target filterInput: HTMLInputElement
6
- @targets hiddenItemsOnExpandedFilter: HTMLElement[]
7
6
  @targets shownItemsOnExpandedFilter: HTMLElement[]
7
+ @targets filterExpandButton: HTMLElement[]
8
8
 
9
9
  connectedCallback() {
10
10
  this.setupFilterInputClearButton()
@@ -28,28 +28,23 @@ class SubHeaderElement extends HTMLElement {
28
28
  }
29
29
 
30
30
  expandFilterInput() {
31
- for (const item of this.hiddenItemsOnExpandedFilter) {
32
- item.classList.add('d-none')
33
- }
34
-
35
31
  for (const item of this.shownItemsOnExpandedFilter) {
36
32
  item.classList.remove('d-none')
37
33
  }
38
-
34
+ for (const item of this.filterExpandButton) {
35
+ item.classList.add('d-none')
36
+ }
39
37
  this.classList.add('SubHeader--expandedSearch')
40
-
41
38
  this.filterInput.focus()
42
39
  }
43
40
 
44
41
  collapseFilterInput() {
45
- for (const item of this.hiddenItemsOnExpandedFilter) {
42
+ for (const item of this.filterExpandButton) {
46
43
  item.classList.remove('d-none')
47
44
  }
48
-
49
45
  for (const item of this.shownItemsOnExpandedFilter) {
50
46
  item.classList.add('d-none')
51
47
  }
52
-
53
48
  this.classList.remove('SubHeader--expandedSearch')
54
49
  }
55
50
 
@@ -56,3 +56,4 @@
56
56
  @import "./open_project/border_box/collapsible_header.pcss";
57
57
  @import "./open_project/collapsible_section.pcss";
58
58
  @import "./open_project/pagination.pcss";
59
+ @import "./open_project/filterable_tree_view.pcss";
@@ -0,0 +1,192 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module ViewComponents
5
+ # :nodoc:
6
+ # :nocov:
7
+ class FilterableTreeViewItemsController < ApplicationController
8
+ # A node in the demo tree. Leaf nodes have no children.
9
+ TreeNode = Data.define(:id, :label, :children, :all_descendant_ids) do
10
+ def leaf?
11
+ children.nil? || children.empty?
12
+ end
13
+
14
+ # Returns a filtered copy of this node. Leaf nodes are included if they match the query.
15
+ # Sub-tree nodes are included if they match OR any descendant matches. The all_descendant_ids
16
+ # field always reflects the ORIGINAL (unfiltered) descendant set, so clients can use it to
17
+ # determine which nodes to select when "include sub-items" is active on a filtered tree.
18
+ def filter(query)
19
+ return self if query.empty?
20
+
21
+ if leaf?
22
+ matches?(query) ? self : nil
23
+ else
24
+ filtered_children = children.filter_map { |child| child.filter(query) }
25
+ if matches?(query) || !filtered_children.empty?
26
+ self.class.new(
27
+ id: id,
28
+ label: label,
29
+ children: filtered_children,
30
+ all_descendant_ids: all_descendant_ids
31
+ )
32
+ end
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def matches?(query)
39
+ label.downcase.include?(query.downcase)
40
+ end
41
+ end
42
+
43
+ # Build a leaf node
44
+ def self.leaf(id:, label:)
45
+ TreeNode.new(id: id, label: label, children: [], all_descendant_ids: [])
46
+ end
47
+
48
+ # Build a branch node, computing all_descendant_ids automatically
49
+ def self.branch(id:, label:, children:)
50
+ all_ids = children.flat_map { |c| [c.id] + c.all_descendant_ids }
51
+ TreeNode.new(id: id, label: label, children: children, all_descendant_ids: all_ids)
52
+ end
53
+
54
+ TREE = [
55
+ branch(
56
+ id: "hogwarts",
57
+ label: "Hogwarts School of Witchcraft and Wizardry",
58
+ children: [
59
+ branch(
60
+ id: "hogwarts-students",
61
+ label: "Students",
62
+ children: [
63
+ branch(
64
+ id: "gryffindor",
65
+ label: "Gryffindor",
66
+ children: [
67
+ leaf(id: "harry-potter", label: "Harry Potter"),
68
+ leaf(id: "ron-weasley", label: "Ron Weasley"),
69
+ leaf(id: "hermione-granger", label: "Hermione Granger"),
70
+ leaf(id: "neville-longbottom", label: "Neville Longbottom"),
71
+ leaf(id: "ginny-weasley", label: "Ginny Weasley")
72
+ ]
73
+ ),
74
+ branch(
75
+ id: "slytherin",
76
+ label: "Slytherin",
77
+ children: [
78
+ leaf(id: "draco-malfoy", label: "Draco Malfoy"),
79
+ leaf(id: "pansy-parkinson", label: "Pansy Parkinson"),
80
+ leaf(id: "blaise-zabini", label: "Blaise Zabini")
81
+ ]
82
+ ),
83
+ branch(
84
+ id: "ravenclaw",
85
+ label: "Ravenclaw",
86
+ children: [
87
+ leaf(id: "luna-lovegood", label: "Luna Lovegood"),
88
+ leaf(id: "cho-chang", label: "Cho Chang"),
89
+ leaf(id: "terry-boot", label: "Terry Boot")
90
+ ]
91
+ ),
92
+ branch(
93
+ id: "hufflepuff",
94
+ label: "Hufflepuff",
95
+ children: [
96
+ leaf(id: "cedric-diggory", label: "Cedric Diggory"),
97
+ leaf(id: "susan-bones", label: "Susan Bones"),
98
+ leaf(id: "hannah-abbott", label: "Hannah Abbott")
99
+ ]
100
+ )
101
+ ]
102
+ ),
103
+ branch(
104
+ id: "hogwarts-teachers",
105
+ label: "Teachers",
106
+ children: [
107
+ leaf(id: "albus-dumbledore", label: "Albus Dumbledore"),
108
+ leaf(id: "minerva-mcgonagall", label: "Minerva McGonagall"),
109
+ leaf(id: "severus-snape", label: "Severus Snape"),
110
+ leaf(id: "rubeus-hagrid", label: "Rubeus Hagrid"),
111
+ leaf(id: "remus-lupin", label: "Remus Lupin"),
112
+ leaf(id: "sybill-trelawney", label: "Sybill Trelawney")
113
+ ]
114
+ )
115
+ ]
116
+ ),
117
+ branch(
118
+ id: "beauxbatons",
119
+ label: "Beauxbatons Academy of Magic",
120
+ children: [
121
+ branch(
122
+ id: "beauxbatons-students",
123
+ label: "Students",
124
+ children: [
125
+ leaf(id: "fleur-delacour", label: "Fleur Delacour"),
126
+ leaf(id: "gabrielle-delacour", label: "Gabrielle Delacour"),
127
+ leaf(id: "cecile-fontaine", label: "Cécile Fontaine")
128
+ ]
129
+ ),
130
+ branch(
131
+ id: "beauxbatons-teachers",
132
+ label: "Teachers",
133
+ children: [
134
+ leaf(id: "olympe-maxime", label: "Olympe Maxime"),
135
+ leaf(id: "sylvie-beaumont", label: "Sylvie Beaumont")
136
+ ]
137
+ )
138
+ ]
139
+ ),
140
+ branch(
141
+ id: "durmstrang",
142
+ label: "Durmstrang Institute",
143
+ children: [
144
+ branch(
145
+ id: "durmstrang-students",
146
+ label: "Students",
147
+ children: [
148
+ leaf(id: "viktor-krum", label: "Viktor Krum"),
149
+ leaf(id: "dmitri-poliakoff", label: "Dmitri Poliakoff"),
150
+ leaf(id: "gregor-tarasov", label: "Gregor Tarasov")
151
+ ]
152
+ ),
153
+ branch(
154
+ id: "durmstrang-teachers",
155
+ label: "Teachers",
156
+ children: [
157
+ leaf(id: "igor-karkaroff", label: "Igor Karkaroff"),
158
+ leaf(id: "fyodor-dolohov", label: "Fyodor Dolohov")
159
+ ]
160
+ )
161
+ ]
162
+ )
163
+ ].freeze
164
+
165
+ def index
166
+ query = params[:query].to_s.strip
167
+ select_variant = (params[:select_variant].presence || "multiple").to_sym
168
+ nodes = TREE.filter_map { |node| node.filter(query) }
169
+
170
+ render locals: {
171
+ nodes: nodes,
172
+ query: query,
173
+ select_variant: select_variant
174
+ }
175
+ end
176
+
177
+ def async_form_tree
178
+ query = params[:query].to_s.strip
179
+ name = params[:name].to_s.presence || "characters"
180
+ nodes = TREE.filter_map { |node| node.filter(query) }
181
+ builder = ActionView::Helpers::FormBuilder.new("", nil, view_context, {})
182
+
183
+ render locals: {
184
+ nodes: nodes,
185
+ query: query,
186
+ name: name,
187
+ builder: builder
188
+ }
189
+ end
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,38 @@
1
+ <% if node.leaf? %>
2
+ <% component.with_leaf(
3
+ label: node.label,
4
+ select_variant: select_variant,
5
+ data: { node_id: node.id }
6
+ ) %>
7
+ <% else %>
8
+ <%
9
+ # At the top-level TreeView we must explicitly provide sub_tree_component_klass and
10
+ # select_strategy. At nested levels, FilterableTreeView::SubTree#with_sub_tree already
11
+ # passes both via super and would raise "keyword argument duplicated" if we passed them again.
12
+ sub_tree_opts = {}
13
+ if component.is_a?(Primer::Alpha::TreeView)
14
+ sub_tree_opts[:sub_tree_component_klass] = Primer::OpenProject::FilterableTreeView::SubTree
15
+ sub_tree_opts[:select_strategy] = :self
16
+ end
17
+
18
+ # When a filter query is active, every sub-tree in the result is either a match or an ancestor
19
+ # of a match – either way it should be expanded so the user sees the results immediately.
20
+ sub_tree_opts[:expanded] = true if query.present?
21
+
22
+ hierarchy_only = query.present? && !node.label.downcase.include?(query.downcase)
23
+ %>
24
+ <% component.with_sub_tree(
25
+ label: node.label,
26
+ select_variant: select_variant,
27
+ **sub_tree_opts,
28
+ data: {
29
+ node_id: node.id,
30
+ hierarchy_only: (hierarchy_only ? true : nil)
31
+ }
32
+ ) do |sub| %>
33
+ <% node.children.each do |child| %>
34
+ <%= render partial: "primer/view_components/filterable_tree_view_items/node",
35
+ locals: { component: sub, node: child, query: query, select_variant: select_variant } %>
36
+ <% end %>
37
+ <% end %>
38
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <%= render(Primer::Alpha::TreeView.new(
2
+ data: { target: "filterable-tree-view.treeViewList" },
3
+ form_arguments: { builder: builder, name: name }
4
+ )) do |tree| %>
5
+ <% nodes.each do |node| %>
6
+ <%= render partial: "primer/view_components/filterable_tree_view_items/node",
7
+ locals: { component: tree, node: node, query: query, select_variant: :multiple } %>
8
+ <% end %>
9
+ <% end %>
@@ -0,0 +1,6 @@
1
+ <%= render(Primer::Alpha::TreeView.new(data: { target: "filterable-tree-view.treeViewList" })) do |tree| %>
2
+ <% nodes.each do |node| %>
3
+ <%= render partial: "primer/view_components/filterable_tree_view_items/node",
4
+ locals: { component: tree, node: node, query: query, select_variant: select_variant } %>
5
+ <% end %>
6
+ <% end %>
data/config/routes.rb CHANGED
@@ -12,6 +12,10 @@ Primer::ViewComponents::Engine.routes.draw do
12
12
  resources :tree_view_items, only: [:index]
13
13
  get "/tree_view_items/async_alpha", to: "tree_view_items#async_alpha", as: :tree_view_items_async_alpha
14
14
 
15
+ resources :filterable_tree_view_items, only: [:index]
16
+ get "/filterable_tree_view_items/tree", to: "filterable_tree_view_items#index", as: :filterable_tree_view_items_tree
17
+ get "/filterable_tree_view_items/async_form_tree", to: "filterable_tree_view_items#async_form_tree", as: :filterable_tree_view_items_async_form_tree
18
+
15
19
  # generic form submission path
16
20
  post "/form_handler", to: "form_handler#form_action", as: :generic_form_submission
17
21
 
@@ -5,8 +5,8 @@ module Primer
5
5
  module ViewComponents
6
6
  module VERSION
7
7
  MAJOR = 0
8
- MINOR = 84
9
- PATCH = 5
8
+ MINOR = 86
9
+ PATCH = 0
10
10
 
11
11
  STRING = [MAJOR, MINOR, PATCH].join(".")
12
12
  end
@@ -54,7 +54,6 @@ module Primer
54
54
 
55
55
  # @label Default
56
56
  #
57
- # @snapshot interactive
58
57
  # @param open_on_load toggle
59
58
  # @param show_filter toggle
60
59
  def default(open_on_load: false, show_filter: true)
@@ -66,7 +65,6 @@ module Primer
66
65
 
67
66
  # @label Local fetch
68
67
  #
69
- # @snapshot interactive
70
68
  # @param open_on_load toggle
71
69
  # @param show_filter toggle
72
70
  def local_fetch(open_on_load: false, show_filter: true)
@@ -75,7 +73,6 @@ module Primer
75
73
 
76
74
  # @label Eventually local fetch
77
75
  #
78
- # @snapshot interactive
79
76
  # @param open_on_load toggle
80
77
  # @param show_filter toggle
81
78
  def eventually_local_fetch(open_on_load: false, show_filter: true)
@@ -84,7 +81,6 @@ module Primer
84
81
 
85
82
  # @label Remote fetch
86
83
  #
87
- # @snapshot interactive
88
84
  # @param open_on_load toggle
89
85
  # @param selected_items text
90
86
  def remote_fetch(open_on_load: false, selected_items: "Phaser")
@@ -93,7 +89,6 @@ module Primer
93
89
 
94
90
  # @label Custom loading label
95
91
  #
96
- # @snapshot interactive
97
92
  # @param open_on_load toggle
98
93
  # @param selected_items text
99
94
  def custom_loading_label(open_on_load: false, selected_items: "Phaser")
@@ -102,7 +97,6 @@ module Primer
102
97
 
103
98
  # @label Custom loading description
104
99
  #
105
- # @snapshot interactive
106
100
  # @param open_on_load toggle
107
101
  # @param selected_items text
108
102
  def custom_loading_description(open_on_load: false, selected_items: "Phaser")
@@ -111,7 +105,6 @@ module Primer
111
105
 
112
106
  # @label Local fetch (no results)
113
107
  #
114
- # @snapshot interactive
115
108
  # @param open_on_load toggle
116
109
  def local_fetch_no_results(open_on_load: false)
117
110
  render_with_template(locals: { open_on_load: open_on_load })
@@ -119,7 +112,6 @@ module Primer
119
112
 
120
113
  # @label Eventually local fetch (no results)
121
114
  #
122
- # @snapshot interactive
123
115
  # @param open_on_load toggle
124
116
  def eventually_local_fetch_no_results(open_on_load: false)
125
117
  render_with_template(locals: { open_on_load: open_on_load })
@@ -127,7 +119,6 @@ module Primer
127
119
 
128
120
  # @label Remote fetch (no results)
129
121
  #
130
- # @snapshot interactive
131
122
  # @param open_on_load toggle
132
123
  def remote_fetch_no_results(open_on_load: false)
133
124
  render_with_template(locals: { open_on_load: open_on_load })
@@ -135,7 +126,6 @@ module Primer
135
126
 
136
127
  # @label Single select
137
128
  #
138
- # @snapshot interactive
139
129
  # @param dynamic_label toggle
140
130
  # @param open_on_load toggle
141
131
  def single_select(dynamic_label: false, open_on_load: false)
@@ -144,7 +134,6 @@ module Primer
144
134
 
145
135
  # @label Multiselect
146
136
  #
147
- # @snapshot interactive
148
137
  # @param open_on_load toggle
149
138
  def multiselect(open_on_load: false)
150
139
  render_with_template(locals: { open_on_load: open_on_load })
@@ -154,7 +143,6 @@ module Primer
154
143
 
155
144
  # @label With dynamic label
156
145
  #
157
- # @snapshot interactive
158
146
  # @param open_on_load toggle
159
147
  def with_dynamic_label(open_on_load: false)
160
148
  render_with_template(locals: { open_on_load: open_on_load })
@@ -162,7 +150,6 @@ module Primer
162
150
 
163
151
  # @label With dynamic label and aria prefix
164
152
  #
165
- # @snapshot interactive
166
153
  # @param open_on_load toggle
167
154
  def with_dynamic_label_and_aria_prefix(open_on_load: false)
168
155
  render_with_template(locals: { open_on_load: open_on_load })
@@ -172,7 +159,6 @@ module Primer
172
159
 
173
160
  # @label Footer buttons
174
161
  #
175
- # @snapshot interactive
176
162
  # @param open_on_load toggle
177
163
  def footer_buttons(open_on_load: false)
178
164
  render_with_template(locals: { open_on_load: open_on_load })
@@ -180,7 +166,6 @@ module Primer
180
166
 
181
167
  # @label With avatar items
182
168
  #
183
- # @snapshot interactive
184
169
  # @param open_on_load toggle
185
170
  def with_avatar_items(open_on_load: false)
186
171
  render_with_template(locals: { open_on_load: open_on_load })
@@ -188,7 +173,6 @@ module Primer
188
173
 
189
174
  # @label SelectPanel with Primer::IconButton
190
175
  #
191
- # @snapshot interactive
192
176
  # @param open_on_load toggle
193
177
  def select_panel_with_icon_button(open_on_load: false)
194
178
  render_with_template(locals: { open_on_load: open_on_load })
@@ -198,7 +182,6 @@ module Primer
198
182
 
199
183
  # @label With leading icons
200
184
  #
201
- # @snapshot interactive
202
185
  # @param open_on_load toggle
203
186
  def with_leading_icons(open_on_load: false)
204
187
  render_with_template(locals: { open_on_load: open_on_load })
@@ -206,7 +189,6 @@ module Primer
206
189
 
207
190
  # @label With trailing icons
208
191
  #
209
- # @snapshot interactive
210
192
  # @param open_on_load toggle
211
193
  def with_trailing_icons(open_on_load: false)
212
194
  render_with_template(locals: { open_on_load: open_on_load })
@@ -216,7 +198,6 @@ module Primer
216
198
 
217
199
  # @label With subtitle
218
200
  #
219
- # @snapshot interactive
220
201
  # @param open_on_load toggle
221
202
  def with_subtitle(open_on_load: false)
222
203
  render_with_template(locals: { open_on_load: open_on_load })
@@ -224,7 +205,6 @@ module Primer
224
205
 
225
206
  # @label Remote fetch initial failure
226
207
  #
227
- # @snapshot interactive
228
208
  # @param open_on_load toggle
229
209
  def remote_fetch_initial_failure(open_on_load: false)
230
210
  render_with_template(locals: { open_on_load: open_on_load })
@@ -232,7 +212,6 @@ module Primer
232
212
 
233
213
  # @label Remote fetch filter failure
234
214
  #
235
- # @snapshot interactive
236
215
  # @param open_on_load toggle
237
216
  # @param banner_scheme [Symbol] select [danger, warning]
238
217
  # @param show_results toggle
@@ -253,7 +232,6 @@ module Primer
253
232
 
254
233
  # @label Eventually local fetch initial failure
255
234
  #
256
- # @snapshot interactive
257
235
  # @param open_on_load toggle
258
236
  def eventually_local_fetch_initial_failure(open_on_load: false)
259
237
  render_with_template(locals: { open_on_load: open_on_load })
@@ -261,7 +239,6 @@ module Primer
261
239
 
262
240
  # @label Single-select form
263
241
  #
264
- # @snapshot interactive
265
242
  # @param open_on_load toggle
266
243
  def single_select_form(open_on_load: false, route_format: :html)
267
244
  render_with_template(locals: { open_on_load: open_on_load, route_format: route_format })
@@ -269,7 +246,6 @@ module Primer
269
246
 
270
247
  # @label Remote fetch form
271
248
  #
272
- # @snapshot interactive
273
249
  # @param open_on_load toggle
274
250
  # @param selected_items text
275
251
  def remote_fetch_form(open_on_load: false, selected_items: "Phaser", route_format: :html)
@@ -278,7 +254,6 @@ module Primer
278
254
 
279
255
  # @label Multi-select form
280
256
  #
281
- # @snapshot interactive
282
257
  # @param open_on_load toggle
283
258
  def multiselect_form(open_on_load: false, route_format: :html)
284
259
  render_with_template(locals: { open_on_load: open_on_load, route_format: route_format })
@@ -286,7 +261,6 @@ module Primer
286
261
 
287
262
  # @label List of links
288
263
  #
289
- # @snapshot interactive
290
264
  # @param open_on_load toggle
291
265
  def list_of_links(open_on_load: false)
292
266
  render_with_template(locals: { open_on_load: open_on_load })
@@ -294,7 +268,6 @@ module Primer
294
268
 
295
269
  # @label No values
296
270
  #
297
- # @snapshot interactive
298
271
  # @param open_on_load toggle
299
272
  def no_values(open_on_load: false)
300
273
  render_with_template(locals: { open_on_load: open_on_load })
@@ -107,7 +107,6 @@ module Primer
107
107
  end
108
108
 
109
109
  # @label With character limit, over limit
110
- # @snapshot interactive
111
110
  def with_character_limit_over_limit
112
111
  render(Primer::Alpha::TextArea.new(id: "my-text-area-with-character-limit-over-limit", name: "my-text-area-with-character-limit-over-limit", character_limit: 10, label: "Tell me about yourself", value: "This text is definitely over the limit."))
113
112
  end
@@ -236,7 +236,6 @@ module Primer
236
236
  end
237
237
 
238
238
  # @label With character limit, over limit
239
- # @snapshot interactive
240
239
  def with_character_limit_over_limit
241
240
  render(Primer::Alpha::TextField.new(character_limit: 10, name: "my-text-field-19", label: "Tell me about yourself", value: "This text is definitely over the limit."))
242
241
  end
@@ -11,5 +11,9 @@
11
11
  <% if leading_action_icon && leading_action_icon != :none %>
12
12
  <% node.with_leading_action_button(icon: leading_action_icon, aria: { label: "Leading action icon" }) %>
13
13
  <% end %>
14
+
15
+ <% if trailing_action_icon && trailing_action_icon != :none %>
16
+ <% node.with_trailing_action_button(icon: trailing_action_icon, aria: { label: "Trailing action icon" }) %>
17
+ <% end %>
14
18
  <% end %>
15
19
  <% end %>
@@ -126,6 +126,7 @@ module Primer
126
126
  # @param leading_visual_icon [Symbol] octicon
127
127
  # @param leading_action_icon [Symbol] octicon
128
128
  # @param trailing_visual_icon [Symbol] octicon
129
+ # @param trailing_action_icon [Symbol] octicon
129
130
  # @param select_variant [Symbol] select [multiple, single, none]
130
131
  # @param disabled [Boolean] toggle
131
132
  def leaf_node_playground(
@@ -133,6 +134,7 @@ module Primer
133
134
  leading_visual_icon: nil,
134
135
  leading_action_icon: nil,
135
136
  trailing_visual_icon: nil,
137
+ trailing_action_icon: nil,
136
138
  select_variant: Primer::Alpha::TreeView::Node::DEFAULT_SELECT_VARIANT,
137
139
  disabled: false
138
140
  )
@@ -141,6 +143,7 @@ module Primer
141
143
  leading_visual_icon: leading_visual_icon,
142
144
  leading_action_icon: leading_action_icon,
143
145
  trailing_visual_icon: trailing_visual_icon,
146
+ trailing_action_icon: trailing_action_icon,
144
147
  select_variant: select_variant.to_sym,
145
148
  disabled: disabled
146
149
  })
@@ -0,0 +1,3 @@
1
+ <%= render(Primer::OpenProject::FilterableTreeView.new(
2
+ src: primer_view_components.filterable_tree_view_items_tree_path(select_variant: select_variant)
3
+ )) %>
@@ -0,0 +1,9 @@
1
+ <%= form_with(url: primer_view_components.generic_form_submission_path(format: :json)) do |f| %>
2
+ <%= render(Primer::Alpha::Stack.new) do %>
3
+ <%= render(Primer::OpenProject::FilterableTreeView.new(
4
+ src: primer_view_components.filterable_tree_view_items_async_form_tree_path(name: "characters"),
5
+ form_arguments: { builder: f, name: "characters" }
6
+ )) %>
7
+ <%= render(Primer::Alpha::SubmitButton.new(name: :submit, scheme: :primary, label: "Submit")) %>
8
+ <% end %>
9
+ <% end %>
@@ -0,0 +1,18 @@
1
+ <%= render(Primer::OpenProject::FilterableTreeView.new(
2
+ tree_view_arguments: { node_variant: :anchor },
3
+ filter_mode_control_arguments: { hidden: true }
4
+ )) do |tree| %>
5
+ <% tree.with_sub_tree(label: "Cloud Services", select_variant: :none, expanded: expanded, href: "https://en.wikipedia.org/wiki/Cloud_computing", target: "_blank") do |cloud| %>
6
+ <% cloud.with_leaf(label: "OpenProject", select_variant: :none, href: "https://www.openproject.org", target: "_blank") do |node| %>
7
+ <% node.with_trailing_visual_icon(icon: :"link-external") %>
8
+ <% end %>
9
+
10
+ <% cloud.with_leaf(label: "Hetzner", select_variant: :none, href: "https://www.hetzner.com", target: "_blank") do |node| %>
11
+ <% node.with_trailing_visual_icon(icon: :"link-external") %>
12
+ <% end %>
13
+ <% end %>
14
+
15
+ <% tree.with_leaf(label: "GitHub", select_variant: :none, href: "https://github.com", target: "_blank") do |node| %>
16
+ <% node.with_trailing_visual_icon(icon: :"link-external") %>
17
+ <% end %>
18
+ <% end %>