primer_view_components 0.43.5 → 0.44.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 (117) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +20 -0
  3. data/app/assets/javascripts/components/primer/alpha/tree_view/tree_view.d.ts +39 -0
  4. data/app/assets/javascripts/components/primer/alpha/tree_view/tree_view_icon_pair_element.d.ts +15 -0
  5. data/app/assets/javascripts/components/primer/alpha/tree_view/tree_view_include_fragment_element.d.ts +9 -0
  6. data/app/assets/javascripts/components/primer/alpha/tree_view/tree_view_roving_tab_index.d.ts +3 -0
  7. data/app/assets/javascripts/components/primer/alpha/tree_view/tree_view_sub_tree_node_element.d.ts +42 -0
  8. data/app/assets/javascripts/components/primer/primer.d.ts +4 -0
  9. data/app/assets/javascripts/components/primer/shared_events.d.ts +15 -0
  10. data/app/assets/javascripts/primer_view_components.js +1 -1
  11. data/app/assets/javascripts/primer_view_components.js.map +1 -1
  12. data/app/assets/styles/primer_view_components.css +1 -1
  13. data/app/assets/styles/primer_view_components.css.map +1 -1
  14. data/app/components/primer/alpha/file_tree_view/directory_node.html.erb +5 -0
  15. data/app/components/primer/alpha/file_tree_view/directory_node.rb +24 -0
  16. data/app/components/primer/alpha/file_tree_view/file_node.html.erb +2 -0
  17. data/app/components/primer/alpha/file_tree_view/file_node.rb +14 -0
  18. data/app/components/primer/alpha/file_tree_view.rb +15 -0
  19. data/app/components/primer/alpha/skeleton_box.css +1 -0
  20. data/app/components/primer/alpha/skeleton_box.css.json +6 -0
  21. data/app/components/primer/alpha/skeleton_box.css.map +1 -0
  22. data/app/components/primer/alpha/skeleton_box.html.erb +1 -0
  23. data/app/components/primer/alpha/skeleton_box.pcss +30 -0
  24. data/app/components/primer/alpha/skeleton_box.rb +29 -0
  25. data/app/components/primer/alpha/tree_view/icon.html.erb +1 -0
  26. data/app/components/primer/alpha/tree_view/icon.rb +22 -0
  27. data/app/components/primer/alpha/tree_view/icon_pair.html.erb +13 -0
  28. data/app/components/primer/alpha/tree_view/icon_pair.rb +42 -0
  29. data/app/components/primer/alpha/tree_view/leading_action.html.erb +3 -0
  30. data/app/components/primer/alpha/tree_view/leading_action.rb +18 -0
  31. data/app/components/primer/alpha/tree_view/leaf_node.html.erb +18 -0
  32. data/app/components/primer/alpha/tree_view/leaf_node.rb +96 -0
  33. data/app/components/primer/alpha/tree_view/loading_failure_message.html.erb +13 -0
  34. data/app/components/primer/alpha/tree_view/loading_failure_message.rb +31 -0
  35. data/app/components/primer/alpha/tree_view/node.html.erb +32 -0
  36. data/app/components/primer/alpha/tree_view/node.rb +194 -0
  37. data/app/components/primer/alpha/tree_view/skeleton_loader.html.erb +23 -0
  38. data/app/components/primer/alpha/tree_view/skeleton_loader.rb +36 -0
  39. data/app/components/primer/alpha/tree_view/spinner_loader.html.erb +20 -0
  40. data/app/components/primer/alpha/tree_view/spinner_loader.rb +33 -0
  41. data/app/components/primer/alpha/tree_view/sub_tree.html.erb +21 -0
  42. data/app/components/primer/alpha/tree_view/sub_tree.rb +113 -0
  43. data/app/components/primer/alpha/tree_view/sub_tree_container.html.erb +3 -0
  44. data/app/components/primer/alpha/tree_view/sub_tree_container.rb +39 -0
  45. data/app/components/primer/alpha/tree_view/sub_tree_node.html.erb +49 -0
  46. data/app/components/primer/alpha/tree_view/sub_tree_node.rb +188 -0
  47. data/app/components/primer/alpha/tree_view/tree_view.d.ts +39 -0
  48. data/app/components/primer/alpha/tree_view/tree_view.js +363 -0
  49. data/app/components/primer/alpha/tree_view/tree_view.ts +396 -0
  50. data/app/components/primer/alpha/tree_view/tree_view_icon_pair_element.d.ts +15 -0
  51. data/app/components/primer/alpha/tree_view/tree_view_icon_pair_element.js +62 -0
  52. data/app/components/primer/alpha/tree_view/tree_view_icon_pair_element.ts +56 -0
  53. data/app/components/primer/alpha/tree_view/tree_view_include_fragment_element.d.ts +9 -0
  54. data/app/components/primer/alpha/tree_view/tree_view_include_fragment_element.js +28 -0
  55. data/app/components/primer/alpha/tree_view/tree_view_include_fragment_element.ts +28 -0
  56. data/app/components/primer/alpha/tree_view/tree_view_roving_tab_index.d.ts +3 -0
  57. data/app/components/primer/alpha/tree_view/tree_view_roving_tab_index.js +130 -0
  58. data/app/components/primer/alpha/tree_view/tree_view_roving_tab_index.ts +161 -0
  59. data/app/components/primer/alpha/tree_view/tree_view_sub_tree_node_element.d.ts +42 -0
  60. data/app/components/primer/alpha/tree_view/tree_view_sub_tree_node_element.js +418 -0
  61. data/app/components/primer/alpha/tree_view/tree_view_sub_tree_node_element.ts +470 -0
  62. data/app/components/primer/alpha/tree_view/visual.html.erb +14 -0
  63. data/app/components/primer/alpha/tree_view/visual.rb +27 -0
  64. data/app/components/primer/alpha/tree_view.css +1 -0
  65. data/app/components/primer/alpha/tree_view.css.json +52 -0
  66. data/app/components/primer/alpha/tree_view.css.map +1 -0
  67. data/app/components/primer/alpha/tree_view.html.erb +12 -0
  68. data/app/components/primer/alpha/tree_view.pcss +373 -0
  69. data/app/components/primer/alpha/tree_view.rb +439 -0
  70. data/app/components/primer/beta/breadcrumbs.css +1 -1
  71. data/app/components/primer/beta/breadcrumbs.css.json +0 -1
  72. data/app/components/primer/beta/breadcrumbs.css.map +1 -1
  73. data/app/components/primer/beta/breadcrumbs.pcss +2 -8
  74. data/app/components/primer/beta/progress_bar.css +1 -1
  75. data/app/components/primer/beta/progress_bar.css.map +1 -1
  76. data/app/components/primer/beta/progress_bar.pcss +3 -2
  77. data/app/components/primer/beta/relative_time.rb +3 -0
  78. data/app/components/primer/beta/spinner.html.erb +1 -1
  79. data/app/components/primer/beta/spinner.rb +2 -0
  80. data/app/components/primer/primer.d.ts +4 -0
  81. data/app/components/primer/primer.js +4 -0
  82. data/app/components/primer/primer.pcss +2 -0
  83. data/app/components/primer/primer.ts +4 -0
  84. data/app/components/primer/shared_events.d.ts +15 -0
  85. data/app/components/primer/shared_events.ts +19 -0
  86. data/app/controllers/primer/view_components/tree_view_items.json +293 -0
  87. data/app/controllers/primer/view_components/tree_view_items_controller.rb +55 -0
  88. data/app/forms/check_box_with_nested_form.rb +10 -10
  89. data/app/forms/radio_button_with_nested_form.rb +16 -16
  90. data/app/views/primer/view_components/tree_view_items/async_alpha.html_fragment.erb +23 -0
  91. data/app/views/primer/view_components/tree_view_items/index.html_fragment.erb +24 -0
  92. data/config/routes.rb +2 -0
  93. data/lib/primer/view_components/version.rb +2 -2
  94. data/previews/primer/alpha/file_tree_view_preview/default.html.erb +16 -0
  95. data/previews/primer/alpha/file_tree_view_preview/playground.html.erb +4 -0
  96. data/previews/primer/alpha/file_tree_view_preview.rb +69 -0
  97. data/previews/primer/alpha/skeleton_box_preview.rb +20 -0
  98. data/previews/primer/alpha/tree_view_preview/async_alpha.html.erb +12 -0
  99. data/previews/primer/alpha/tree_view_preview/buttons.html.erb +10 -0
  100. data/previews/primer/alpha/tree_view_preview/default.html.erb +24 -0
  101. data/previews/primer/alpha/tree_view_preview/empty.html.erb +10 -0
  102. data/previews/primer/alpha/tree_view_preview/form_input.html.erb +14 -0
  103. data/previews/primer/alpha/tree_view_preview/leaf_node_playground.html.erb +15 -0
  104. data/previews/primer/alpha/tree_view_preview/links.html.erb +17 -0
  105. data/previews/primer/alpha/tree_view_preview/loading_failure.html.erb +36 -0
  106. data/previews/primer/alpha/tree_view_preview/loading_skeleton.html.erb +12 -0
  107. data/previews/primer/alpha/tree_view_preview/loading_spinner.html.erb +12 -0
  108. data/previews/primer/alpha/tree_view_preview/playground.html.erb +4 -0
  109. data/previews/primer/alpha/tree_view_preview.rb +208 -0
  110. data/static/arguments.json +456 -0
  111. data/static/audited_at.json +17 -0
  112. data/static/classes.json +15 -0
  113. data/static/constants.json +101 -0
  114. data/static/info_arch.json +1410 -56
  115. data/static/previews.json +232 -0
  116. data/static/statuses.json +17 -0
  117. metadata +89 -8
@@ -0,0 +1,5 @@
1
+ <% with_leading_visual_icons do |icons| %>
2
+ <% icons.with_expanded_icon(icon: :"file-directory-open-fill", **@expanded_icon_arguments) %>
3
+ <% icons.with_collapsed_icon(icon: :"file-directory-fill", **@collapsed_icon_arguments) %>
4
+ <% end %>
5
+ <%= render_parent %>
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Alpha
5
+ class FileTreeView
6
+ class DirectoryNode < TreeView::SubTreeNode
7
+ def initialize(icon_arguments: nil, expanded_icon_arguments: nil, collapsed_icon_arguments: nil, **system_arguments)
8
+ @expanded_icon_arguments = expanded_icon_arguments || icon_arguments || {}
9
+ @collapsed_icon_arguments = collapsed_icon_arguments || icon_arguments || {}
10
+
11
+ super(**system_arguments)
12
+ end
13
+
14
+ def with_file(**system_arguments, &block)
15
+ with_leaf(**system_arguments, component_klass: FileNode, &block)
16
+ end
17
+
18
+ def with_directory(**system_arguments, &block)
19
+ with_sub_tree(**system_arguments, component_klass: DirectoryNode, &block)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,2 @@
1
+ <% with_leading_visual_icon(icon: :file, **@icon_arguments) %>
2
+ <%= render_parent %>
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Alpha
5
+ class FileTreeView
6
+ class FileNode < TreeView::LeafNode
7
+ def initialize(icon_arguments: {}, **system_arguments)
8
+ @icon_arguments = icon_arguments
9
+ super(**system_arguments)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Alpha
5
+ class FileTreeView < TreeView
6
+ def with_file(**system_arguments, &block)
7
+ with_leaf(**system_arguments, component_klass: FileNode, &block)
8
+ end
9
+
10
+ def with_directory(**system_arguments, &block)
11
+ with_sub_tree(**system_arguments, component_klass: DirectoryNode, &block)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1 @@
1
+ @keyframes shimmer{0%{mask-position:200%}to{mask-position:0}}.SkeletonBox{animation:shimmer;background-color:var(--bgColor-muted);border-radius:var(--borderRadius-small);display:block;height:1rem}@media (prefers-reduced-motion:no-preference){.SkeletonBox{animation:shimmer;animation-duration:1s;animation-iteration-count:infinite;mask-image:linear-gradient(75deg,#000 30%,#000000a6 80%);mask-size:200%}}@media (forced-colors:active){.SkeletonBox{outline:1px solid #0000;outline-offset:-1px}}
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "alpha/skeleton_box",
3
+ "selectors": [
4
+ ".SkeletonBox"
5
+ ]
6
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["skeleton_box.pcss"],"names":[],"mappings":"AAAA,mBACE,GACE,kBACF,CAEA,GACE,eACF,CACF,CAEA,aAKE,iBAAkB,CAFlB,qCAAsC,CACtC,uCAAwC,CAHxC,aAAc,CACd,WAiBF,CAZE,8CAPF,aAUI,iBAAkB,CAClB,qBAAsB,CACtB,kCAAmC,CAJnC,wDAAoE,CACpE,cAUJ,CANE,CAEA,8BAfF,aAgBI,uBAA8B,CAC9B,mBAEJ,CADE","file":"skeleton_box.css","sourcesContent":["@keyframes shimmer {\n from {\n mask-position: 200%;\n }\n\n to {\n mask-position: 0%;\n }\n}\n\n.SkeletonBox {\n display: block;\n height: 1rem;\n background-color: var(--bgColor-muted);\n border-radius: var(--borderRadius-small);\n animation: shimmer;\n\n @media (prefers-reduced-motion: no-preference) {\n mask-image: linear-gradient(75deg, #000 30%, rgb(0, 0, 0, 0.65) 80%);\n mask-size: 200%;\n animation: shimmer;\n animation-duration: 1s;\n animation-iteration-count: infinite;\n }\n\n @media (forced-colors: active) {\n outline: 1px solid transparent;\n outline-offset: -1px;\n }\n}\n"]}
@@ -0,0 +1 @@
1
+ <%= render(Primer::BaseComponent.new(**@system_arguments)) %>
@@ -0,0 +1,30 @@
1
+ @keyframes shimmer {
2
+ from {
3
+ mask-position: 200%;
4
+ }
5
+
6
+ to {
7
+ mask-position: 0%;
8
+ }
9
+ }
10
+
11
+ .SkeletonBox {
12
+ display: block;
13
+ height: 1rem;
14
+ background-color: var(--bgColor-muted);
15
+ border-radius: var(--borderRadius-small);
16
+ animation: shimmer;
17
+
18
+ @media (prefers-reduced-motion: no-preference) {
19
+ mask-image: linear-gradient(75deg, #000 30%, rgb(0, 0, 0, 0.65) 80%);
20
+ mask-size: 200%;
21
+ animation: shimmer;
22
+ animation-duration: 1s;
23
+ animation-iteration-count: infinite;
24
+ }
25
+
26
+ @media (forced-colors: active) {
27
+ outline: 1px solid transparent;
28
+ outline-offset: -1px;
29
+ }
30
+ }
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Alpha
5
+ # A SkeletonBox provides a placeholder for non-text, non-Avatar elements (e.g., hero images)
6
+ # that are still loading. You can adjust width and height to match the content's dimensions.
7
+ class SkeletonBox < Primer::Component
8
+ status :alpha
9
+
10
+ # @param height [String] Any valid CSS height.
11
+ # @param width [String] Any valid CSS width.
12
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
13
+ def initialize(height: nil, width: nil, **system_arguments)
14
+ @system_arguments = deny_tag_argument(**system_arguments)
15
+
16
+ styles = []
17
+ styles << "width: #{width}" if width
18
+ styles << "height: #{height}" if height
19
+
20
+ @system_arguments[:tag] = :div
21
+ @system_arguments[:style] = styles.join("; ") if styles.present?
22
+ @system_arguments[:classes] = class_names(
23
+ @system_arguments.delete(:classes),
24
+ "SkeletonBox"
25
+ )
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1 @@
1
+ <%= render(Primer::Beta::Octicon.new(**@system_arguments)) %>
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Alpha
5
+ class TreeView
6
+ # An icon for a `TreeView` node.
7
+ #
8
+ # This component is part of the <%= link_to_component(Primer::Alpha::TreeView) %> component and should
9
+ # not be used directly.
10
+ class Icon < Primer::Component
11
+ # @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Beta::Octicon) %>.
12
+ def initialize(**system_arguments)
13
+ @system_arguments = system_arguments
14
+ @system_arguments[:focusable] = "false"
15
+ @system_arguments[:display] = :inline_block
16
+ @system_arguments[:overflow] = :visible
17
+ @system_arguments[:style] = "vertical-align: text-bottom;"
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ <%= render(Primer::BaseComponent.new(**@system_arguments)) do %>
2
+ <% if expanded_icon? %>
3
+ <div data-target="tree-view-icon-pair.expandedIcon" <%= expanded? ? "" : "hidden" %>>
4
+ <%= expanded_icon %>
5
+ </div>
6
+ <% end %>
7
+
8
+ <% if collapsed_icon? %>
9
+ <div data-target="tree-view-icon-pair.collapsedIcon" <%= expanded? ? "hidden" : "" %>>
10
+ <%= collapsed_icon %>
11
+ </div>
12
+ <% end %>
13
+ <% end %>
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Alpha
5
+ class TreeView
6
+ # A pair of icons for a `TreeView` sub-tree that displays distinct icons when the sub-tree is
7
+ # expanded and collapsed.
8
+ #
9
+ # This component is part of the <%= link_to_component(Primer::Alpha::TreeView) %> component and should
10
+ # not be used directly.
11
+ class IconPair < Primer::Component
12
+ # The expanded icon.
13
+ #
14
+ # @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Alpha::TreeView::Icon) %>.
15
+ renders_one :expanded_icon, lambda { |**system_arguments|
16
+ Icon.new(**system_arguments)
17
+ }
18
+
19
+ # The collapsed icon.
20
+ #
21
+ # @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Alpha::TreeView::Icon) %>.
22
+ renders_one :collapsed_icon, lambda { |**system_arguments|
23
+ Icon.new(**system_arguments)
24
+ }
25
+
26
+ # Whether or not this icon is expanded.
27
+ #
28
+ # @return [Boolean]
29
+ attr_reader :expanded
30
+ alias expanded? expanded
31
+
32
+ # @param expanded [Boolean] If true, the expanded icon is shown and the collapsed icon is hidden, etc.
33
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
34
+ def initialize(expanded: false, **system_arguments)
35
+ @expanded = expanded
36
+ @system_arguments = deny_tag_argument(**system_arguments)
37
+ @system_arguments[:tag] = :"tree-view-icon-pair"
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,3 @@
1
+ <div class="TreeViewItemLeadingAction" aria-hidden="true">
2
+ <%= render(@action) %>
3
+ </div>
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Alpha
5
+ class TreeView
6
+ # The leading action for `TreeView` nodes.
7
+ #
8
+ # This component is part of the <%= link_to_component(Primer::Alpha::TreeView) %> component and should
9
+ # not be used directly.
10
+ class LeadingAction < Primer::Component
11
+ # @param action [ViewComponent::Base] A component or other renderable to use as the action button etc.
12
+ def initialize(action:)
13
+ @action = action
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ <%= render(@node) do |node| %>
2
+ <% if leading_action? %>
3
+ <% node.with_leading_action do %>
4
+ <%= leading_action %>
5
+ <% end %>
6
+ <% end %>
7
+ <% if leading_visual? %>
8
+ <% node.with_leading_visual do %>
9
+ <%= leading_visual %>
10
+ <% end %>
11
+ <% end %>
12
+ <% if trailing_visual? %>
13
+ <% node.with_trailing_visual do %>
14
+ <%= trailing_visual %>
15
+ <% end %>
16
+ <% end %>
17
+ <% node.with_text_content { @label } %>
18
+ <% end %>
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Alpha
5
+ class TreeView
6
+ # A `TreeView` leaf node.
7
+ #
8
+ # This component is part of the <%= link_to_component(Primer::Alpha::TreeView) %> component and should
9
+ # not be used directly.
10
+ class LeafNode < Primer::Component
11
+ # @!parse
12
+ # # Adds a leading visual icon rendered to the left of the node's label.
13
+ # #
14
+ # # @param label [String] A label describing the visual, displayed only to screen readers.
15
+ # # @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Alpha::TreeView::Icon) %>.
16
+ # def with_leading_visual_icon(label: nil, **system_arguments, &block)
17
+ # end
18
+
19
+ renders_one :leading_visual, types: {
20
+ icon: lambda { |label: nil, **system_arguments|
21
+ merge_system_arguments!(
22
+ aria: { describedby: leading_visual_label_id }
23
+ )
24
+
25
+ Visual.new(
26
+ id: leading_visual_label_id,
27
+ visual: Icon.new(**system_arguments),
28
+ label: label
29
+ )
30
+ }
31
+ }
32
+
33
+ # @!parse
34
+ # # Adds a leading action rendered to the left of the node's label and any leading visuals or checkboxes.
35
+ # #
36
+ # # @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Beta::IconButton) %>.
37
+ # def with_leading_action_button(**system_arguments, &block)
38
+ # end
39
+
40
+ renders_one :leading_action, types: {
41
+ button: lambda { |**system_arguments|
42
+ LeadingAction.new(
43
+ action: Primer::Beta::IconButton.new(
44
+ scheme: :invisible,
45
+ **system_arguments
46
+ )
47
+ )
48
+ }
49
+ }
50
+
51
+ # @!parse
52
+ # # Adds a trailing visual icon rendered to the right of the node's label.
53
+ # #
54
+ # # @param label [String] A label describing the visual, displayed only to screen readers.
55
+ # # @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Alpha::TreeView::Icon) %>.
56
+ # def with_trailing_visual_icon(label: nil, **system_arguments, &block)
57
+ # end
58
+
59
+ renders_one :trailing_visual, types: {
60
+ icon: lambda { |label: nil, **system_arguments|
61
+ Visual.new(
62
+ id: nil,
63
+ visual: Icon.new(**system_arguments),
64
+ label: label
65
+ )
66
+ }
67
+ }
68
+
69
+ delegate :current?, :merge_system_arguments!, to: :@node
70
+
71
+ # @param label [String] The node's label, i.e. it's textual content.
72
+ # @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Alpha::TreeView::Node) %>.
73
+ def initialize(label:, **system_arguments)
74
+ @label = label
75
+ @system_arguments = system_arguments
76
+ @system_arguments[:data] = merge_data(
77
+ @system_arguments,
78
+ data: { "node-type": "leaf" }
79
+ )
80
+
81
+ @node = Primer::Alpha::TreeView::Node.new(**@system_arguments)
82
+ end
83
+
84
+ private
85
+
86
+ def base_id
87
+ @base_id ||= self.class.generate_id
88
+ end
89
+
90
+ def leading_visual_label_id
91
+ @leading_visual_id ||= "#{base_id}-leading-visual-label"
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,13 @@
1
+ <%= render(Primer::BaseComponent.new(**@system_arguments)) do %>
2
+ <%= render(Primer::Beta::Octicon.new(icon: :"alert-fill", color: :danger)) %>
3
+ <span><%= @text %></span>
4
+ <div></div> <!-- spacer -->
5
+ <%= render(Primer::Beta::Button.new(
6
+ size: :small,
7
+ scheme: :default,
8
+ style: "justify-self: start",
9
+ **@retry_button_arguments
10
+ )) do %>
11
+ <%= @retry_button_label %>
12
+ <% end %>
13
+ <% end %>
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Alpha
5
+ class TreeView
6
+ # A `TreeView` loading failure message.
7
+ #
8
+ # This component is part of the <%= link_to_component(Primer::Alpha::TreeView) %> component and should
9
+ # not be used directly.
10
+ class LoadingFailureMessage < Primer::Component
11
+ DEFAULT_TEXT = "Something went wrong"
12
+ DEFAULT_RETRY_BUTTON_LABEL = "Retry"
13
+
14
+ # @param text [String] The failure message to display.
15
+ # @param retry_button_label [String] The text shown on the retry button.
16
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
17
+ def initialize(text: DEFAULT_TEXT, retry_button_label: DEFAULT_RETRY_BUTTON_LABEL, **system_arguments)
18
+ @text = text
19
+ @retry_button_label = retry_button_label
20
+ @retry_button_arguments = system_arguments.delete(:retry_button_arguments)
21
+ @system_arguments = deny_tag_argument(**system_arguments)
22
+ @system_arguments[:tag] = :div
23
+ @system_arguments[:classes] = class_names(
24
+ @system_arguments.delete(:classes),
25
+ "TreeViewFailureMessage"
26
+ )
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,32 @@
1
+ <%= render(Primer::BaseComponent.new(**@system_arguments)) do %>
2
+ <div class="TreeViewItemContainer" style="--level: <%= level %>;">
3
+ <div style="grid-area: spacer; display: flex;">
4
+ <div style="width: 100%; display: flex;">
5
+ <% (0...(level - 1)).each do %>
6
+ <div class="TreeViewItemLevelLine"></div>
7
+ <% end %>
8
+ </div>
9
+ </div>
10
+ <% if toggle? %>
11
+ <%= toggle %>
12
+ <% end %>
13
+ <% if leading_action? %>
14
+ <%= leading_action %>
15
+ <% end %>
16
+ <%= render(Primer::BaseComponent.new(**@content_arguments)) do %>
17
+ <% if @select_variant == :multiple %>
18
+ <div aria-hidden="true" class="TreeViewItemCheckbox" tabindex="-1">
19
+ <div class="FormControl-checkbox"></div>
20
+ </div>
21
+ <% end %>
22
+ <% if leading_visual? %>
23
+ <%= leading_visual %>
24
+ <% end %>
25
+ <span class="TreeViewItemContentText"><%= text_content %></span>
26
+ <% if trailing_visual? %>
27
+ <%= trailing_visual %>
28
+ <% end %>
29
+ <% end %>
30
+ </div>
31
+ <%= content %>
32
+ <% end %>
@@ -0,0 +1,194 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Alpha
5
+ class TreeView
6
+ # A generic `TreeView` node.
7
+ #
8
+ # This component is part of the <%= link_to_component(Primer::Alpha::TreeView) %> component and should
9
+ # not be used directly.
10
+ class Node < Primer::Component
11
+ DEFAULT_NODE_VARIANT = Primer::Alpha::TreeView::DEFAULT_NODE_VARIANT
12
+ NODE_VARIANT_TAG_MAP = { DEFAULT_NODE_VARIANT => :div, :button => :button, :anchor => :a }.freeze
13
+ NODE_VARIANT_TAG_OPTIONS = NODE_VARIANT_TAG_MAP.keys.freeze
14
+
15
+ # Generic leading action slot
16
+ renders_one :leading_action
17
+
18
+ # Generic leading visual slot
19
+ renders_one :leading_visual
20
+
21
+ # Generic trailing visual slot
22
+ renders_one :trailing_visual
23
+
24
+ # Generic toggle button slot
25
+ renders_one :toggle
26
+
27
+ # Generic text content slot (for node's label)
28
+ renders_one :text_content
29
+
30
+ # Wether or not this node is the current node.
31
+ #
32
+ # @return [Boolean]
33
+ attr_reader :current
34
+ alias current? current
35
+
36
+ # This node's checked state.
37
+ #
38
+ # @return [String]
39
+ attr_reader :checked
40
+
41
+ # This node's select variant (i.e. check box variant).
42
+ #
43
+ # @return [Symbol]
44
+ attr_reader :select_variant
45
+
46
+ # This node's variant, eg. `:button`, `:div`, etc.
47
+ #
48
+ # @return [Symbol]
49
+ attr_reader :node_variant
50
+
51
+ # Whether or not this node is disabled, i.e. cannot be activated.
52
+ #
53
+ # @return [Boolean]
54
+ attr_reader :disabled
55
+ alias disabled? disabled
56
+
57
+ DEFAULT_SELECT_VARIANT = :none
58
+ SELECT_VARIANT_OPTIONS = [
59
+ :multiple,
60
+ DEFAULT_SELECT_VARIANT
61
+ ].freeze
62
+
63
+ DEFAULT_CHECKED_STATE = false
64
+ CHECKED_STATES = [
65
+ DEFAULT_CHECKED_STATE,
66
+ true,
67
+ "mixed"
68
+ ]
69
+
70
+ # @param path [Array<String>] 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.
71
+ # @param node_variant [Symbol] The node variant to use for the node's content, i.e. the `:button` or `:div`. <%= one_of(Primer::Alpha::TreeView::NODE_VARIANT_OPTIONS) %>
72
+ # @param href [String] 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`.
73
+ # @param current [Boolean] Whether or not this node is the current node. The current node is styled differently than regular nodes and is the first element that receives focus when tabbing to the `TreeView` component.
74
+ # @param select_variant [Symbol] Controls the type of checkbox that appears. <%= one_of(Primer::Alpha::TreeView::Node::SELECT_VARIANT_OPTIONS) %>
75
+ # @param checked [Boolean | String] The checked state of the node's checkbox. <%= one_of(Primer::Alpha::TreeView::Node::CHECKED_STATES) %>
76
+ # @param disabled [Boolean] Whether or not the node can be activated. Passing `false` here will cause the node to appear visually disabled but it is still keyboard-focusable.
77
+ # @param value [String] If this node is checked, this value will be sent to the server on form submission.
78
+ # @param content_arguments [Hash] Arguments attached to the node's content, i.e the `<button>` or `<a>` element. <%= link_to_system_arguments_docs %>
79
+ def initialize(
80
+ path:,
81
+ node_variant:,
82
+ href: nil,
83
+ current: false,
84
+ select_variant: DEFAULT_SELECT_VARIANT,
85
+ checked: DEFAULT_CHECKED_STATE,
86
+ disabled: false,
87
+ value: nil,
88
+ **content_arguments
89
+ )
90
+ @system_arguments = {
91
+ tag: :li,
92
+ role: :none,
93
+ classes: "TreeViewItem"
94
+ }
95
+
96
+ @content_arguments = content_arguments
97
+
98
+ @path = path
99
+ @current = current
100
+ @select_variant = fetch_or_fallback(SELECT_VARIANT_OPTIONS, select_variant, DEFAULT_SELECT_VARIANT)
101
+ @checked = fetch_or_fallback(CHECKED_STATES, checked, DEFAULT_CHECKED_STATE)
102
+ @disabled = disabled
103
+ @node_variant = fetch_or_fallback(NODE_VARIANT_TAG_OPTIONS, node_variant, DEFAULT_NODE_VARIANT)
104
+
105
+ @content_arguments[:tag] = NODE_VARIANT_TAG_MAP[@node_variant]
106
+ @content_arguments[:href] = href if href
107
+ @content_arguments[:id] = content_id
108
+ @content_arguments[:role] = :treeitem
109
+ @content_arguments[:tabindex] = current? ? 0 : -1
110
+ @content_arguments[:classes] = class_names(
111
+ @content_arguments.delete(:classes),
112
+ "TreeViewItemContent"
113
+ )
114
+
115
+ @content_arguments[:aria] = merge_aria(
116
+ @content_arguments, {
117
+ aria: {
118
+ level: level,
119
+ selected: false,
120
+ checked: checked,
121
+ labelledby: content_id,
122
+ disabled: disabled?
123
+ }
124
+ }
125
+ )
126
+
127
+ @content_arguments[:data] = merge_data(
128
+ @content_arguments, {
129
+ data: {
130
+ value: value,
131
+ path: @path.to_json
132
+ }
133
+ }
134
+ )
135
+
136
+ return unless current?
137
+
138
+ @content_arguments[:aria] = merge_aria(
139
+ @content_arguments,
140
+ { aria: { current: true } }
141
+ )
142
+ end
143
+
144
+ # The numeric depth of this node.
145
+ #
146
+ # @return [Integer] This node's depth.
147
+ def level
148
+ @level ||= @path.size
149
+ end
150
+
151
+ # Merges the given arguments into the current hash of system arguments provided when the component was
152
+ # initially constructed. This method can be used to add additional arguments just before rendering.
153
+ #
154
+ # @param other_arguments [Hash] The other hash of system arguments to merge into the current one.
155
+ def merge_system_arguments!(**other_arguments)
156
+ @content_arguments[:aria] = merge_aria(
157
+ @content_arguments,
158
+ other_arguments
159
+ )
160
+
161
+ @content_arguments[:data] = merge_data(
162
+ @content_arguments,
163
+ other_arguments
164
+ )
165
+
166
+ @content_arguments.merge!(**other_arguments)
167
+ end
168
+
169
+ private
170
+
171
+ def before_render
172
+ if leading_action?
173
+ @content_arguments[:data] = merge_data(
174
+ @content_arguments,
175
+ { data: { "has-leading-action": true } }
176
+ )
177
+ end
178
+
179
+ if select_variant != :none && node_variant != :div
180
+ raise ArgumentError, "TreeView nodes do not support select variants for tags other than :div."
181
+ end
182
+ end
183
+
184
+ def content_id
185
+ @content_id ||= "#{base_id}-content"
186
+ end
187
+
188
+ def base_id
189
+ @base_id ||= self.class.generate_id
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,23 @@
1
+ <% unless loading_failure_message? %>
2
+ <% with_loading_failure_message # set the default %>
3
+ <% end %>
4
+
5
+ <%= render(Primer::BaseComponent.new(tag: :"tree-view-include-fragment", src: @src, loading: :lazy, data: { target: "tree-view-sub-tree-node.subTree tree-view-sub-tree-node.includeFragment", path: @container.path.to_json }, hidden: @container.expanded?, accept: "text/fragment+html")) do %>
6
+ <%= render(@container) do %>
7
+ <%= render(Primer::Alpha::TreeView::Node.new(path: [*@container.path, :loader], node_variant: :div)) do |node| %>
8
+ <% node.with_text_content do %>
9
+ <div data-target="tree-view-sub-tree-node.loadingIndicator">
10
+ <% @count.times do %>
11
+ <span class="TreeViewSkeletonItemContainerStyle TreeViewItemSkeleton">
12
+ <%= render(Primer::Alpha::SkeletonBox.new(width: "16px")) %>
13
+ <%= render(Primer::Alpha::SkeletonBox.new(width: "100%", classes: "TreeItemSkeletonTextStyles")) %>
14
+ </span>
15
+ <% end %>
16
+ </div>
17
+ <div data-target="tree-view-sub-tree-node.loadingFailureMessage" hidden>
18
+ <%= loading_failure_message %>
19
+ </div>
20
+ <% end %>
21
+ <% end %>
22
+ <% end %>
23
+ <% end %>