openproject-primer_view_components 0.89.2 → 0.91.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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -0
  3. data/app/assets/javascripts/primer_view_components.js +1 -1
  4. data/app/assets/javascripts/primer_view_components.js.map +1 -1
  5. data/app/assets/styles/primer_view_components.css +1 -1
  6. data/app/assets/styles/primer_view_components.css.map +1 -1
  7. data/app/components/primer/alpha/action_bar.css.map +1 -1
  8. data/app/components/primer/alpha/action_bar.pcss +0 -3
  9. data/app/components/primer/alpha/action_list.css.map +1 -1
  10. data/app/components/primer/alpha/action_list.pcss +0 -2
  11. data/app/components/primer/alpha/auto_complete.css +1 -1
  12. data/app/components/primer/alpha/auto_complete.css.json +2 -4
  13. data/app/components/primer/alpha/auto_complete.css.map +1 -1
  14. data/app/components/primer/alpha/auto_complete.pcss +3 -10
  15. data/app/components/primer/alpha/banner.css.map +1 -1
  16. data/app/components/primer/alpha/banner.pcss +0 -1
  17. data/app/components/primer/alpha/button_marketing.css.map +1 -1
  18. data/app/components/primer/alpha/button_marketing.pcss +4 -4
  19. data/app/components/primer/alpha/layout.css +1 -1
  20. data/app/components/primer/alpha/layout.css.map +1 -1
  21. data/app/components/primer/alpha/layout.pcss +3 -1
  22. data/app/components/primer/alpha/menu.css.map +1 -1
  23. data/app/components/primer/alpha/menu.pcss +0 -6
  24. data/app/components/primer/alpha/segmented_control.css.map +1 -1
  25. data/app/components/primer/alpha/segmented_control.pcss +0 -2
  26. data/app/components/primer/alpha/tab_nav.css.map +1 -1
  27. data/app/components/primer/alpha/tab_nav.pcss +0 -5
  28. data/app/components/primer/alpha/text_field.css +1 -1
  29. data/app/components/primer/alpha/text_field.css.json +2 -1
  30. data/app/components/primer/alpha/text_field.css.map +1 -1
  31. data/app/components/primer/alpha/text_field.pcss +14 -7
  32. data/app/components/primer/alpha/toggle_switch.css +1 -1
  33. data/app/components/primer/alpha/toggle_switch.css.map +1 -1
  34. data/app/components/primer/alpha/toggle_switch.pcss +8 -6
  35. data/app/components/primer/alpha/tree_view/sub_tree_node.rb +2 -2
  36. data/app/components/primer/alpha/tree_view.css.map +1 -1
  37. data/app/components/primer/alpha/tree_view.pcss +1 -0
  38. data/app/components/primer/alpha/underline_nav.css.map +1 -1
  39. data/app/components/primer/alpha/underline_nav.pcss +0 -3
  40. data/app/components/primer/base_component.rb +1 -0
  41. data/app/components/primer/beta/blankslate.css +1 -1
  42. data/app/components/primer/beta/blankslate.css.map +1 -1
  43. data/app/components/primer/beta/blankslate.pcss +2 -53
  44. data/app/components/primer/beta/breadcrumbs.css +1 -1
  45. data/app/components/primer/beta/breadcrumbs.css.json +2 -1
  46. data/app/components/primer/beta/breadcrumbs.css.map +1 -1
  47. data/app/components/primer/beta/breadcrumbs.pcss +6 -5
  48. data/app/components/primer/beta/button.css.map +1 -1
  49. data/app/components/primer/beta/button.pcss +0 -1
  50. data/app/components/primer/beta/popover.css +1 -1
  51. data/app/components/primer/beta/popover.css.json +22 -16
  52. data/app/components/primer/beta/popover.css.map +1 -1
  53. data/app/components/primer/beta/popover.pcss +132 -101
  54. data/app/components/primer/beta/state.css.map +1 -1
  55. data/app/components/primer/beta/state.pcss +0 -1
  56. data/app/components/primer/beta/subhead.css.map +1 -1
  57. data/app/components/primer/beta/subhead.pcss +0 -2
  58. data/app/components/primer/beta/timeline_item.css.map +1 -1
  59. data/app/components/primer/beta/timeline_item.pcss +0 -5
  60. data/app/components/primer/beta/truncate.css.map +1 -1
  61. data/app/components/primer/beta/truncate.pcss +0 -1
  62. data/app/components/primer/component.rb +16 -0
  63. data/app/components/primer/open_project/border_box/collapsible_header.css.map +1 -1
  64. data/app/components/primer/open_project/border_box/collapsible_header.html.erb +1 -1
  65. data/app/components/primer/open_project/border_box/collapsible_header.pcss +3 -1
  66. data/app/components/primer/open_project/border_box/collapsible_header.rb +10 -9
  67. data/app/components/primer/open_project/border_grid.css +1 -1
  68. data/app/components/primer/open_project/border_grid.css.map +1 -1
  69. data/app/components/primer/open_project/border_grid.pcss +11 -9
  70. data/app/components/primer/open_project/collapsible.d.ts +1 -1
  71. data/app/components/primer/open_project/collapsible.js +8 -4
  72. data/app/components/primer/open_project/collapsible.ts +10 -4
  73. data/app/components/primer/open_project/collapsible_section.html.erb +6 -10
  74. data/app/components/primer/open_project/collapsible_section.rb +8 -0
  75. data/app/components/primer/open_project/filterable_tree_view.css.map +1 -1
  76. data/app/components/primer/open_project/filterable_tree_view.pcss +2 -0
  77. data/app/components/primer/open_project/page_header.css.map +1 -1
  78. data/app/components/primer/open_project/page_header.pcss +2 -0
  79. data/app/components/primer/open_project/pagination.css +1 -1
  80. data/app/components/primer/open_project/pagination.css.map +1 -1
  81. data/app/components/primer/open_project/pagination.pcss +4 -1
  82. data/app/components/primer/open_project/side_panel/section.css +1 -1
  83. data/app/components/primer/open_project/side_panel/section.css.map +1 -1
  84. data/app/components/primer/open_project/side_panel/section.pcss +3 -3
  85. data/app/controllers/primer/view_components/tree_view_items_controller.rb +2 -1
  86. data/app/lib/primer/forms/dsl/input.rb +5 -1
  87. data/app/lib/primer/safe_href_helper.rb +36 -0
  88. data/app/views/primer/view_components/tree_view_items/async_alpha.html_fragment.erb +4 -4
  89. data/lib/primer/static/generate_previews.rb +1 -1
  90. data/lib/primer/view_components/version.rb +2 -2
  91. data/previews/primer/alpha/tree_view_preview/async_alpha.html.erb +2 -2
  92. data/previews/primer/alpha/tree_view_preview/async_form_input.html.erb +16 -0
  93. data/previews/primer/alpha/tree_view_preview.rb +13 -2
  94. data/previews/primer/open_project/collapsible_section_preview/with_link_in_title.html.erb +6 -0
  95. data/previews/primer/open_project/collapsible_section_preview.rb +9 -0
  96. data/static/classes.json +21 -0
  97. data/static/classnames.cjs +507 -0
  98. data/static/classnames.d.ts +2 -0
  99. data/static/classnames.js +509 -0
  100. data/static/info_arch.json +26 -0
  101. data/static/previews.json +2404 -2378
  102. metadata +9 -3
@@ -1,6 +1,5 @@
1
1
  import {attr, target, targets} from '@github/catalyst'
2
2
 
3
- // eslint-disable-next-line custom-elements/expose-class-on-global
4
3
  export abstract class CollapsibleElement extends HTMLElement {
5
4
  @target arrowDown: Element
6
5
  @target arrowUp: Element
@@ -11,12 +10,19 @@ export abstract class CollapsibleElement extends HTMLElement {
11
10
 
12
11
  toggleViaKeyboard(event: KeyboardEvent) {
13
12
  if (event.code === 'Enter' || event.code === 'Space') {
14
- event.preventDefault()
15
- this.toggle()
13
+ this.toggle(event)
16
14
  }
17
15
  }
18
16
 
19
- toggle() {
17
+ toggle(event?: Event) {
18
+ if (
19
+ event &&
20
+ event.target instanceof Element &&
21
+ !event.target.closest('[data-collapsible-toggle]') &&
22
+ event.target.closest('a, button')
23
+ )
24
+ return
25
+ event?.preventDefault()
20
26
  this.collapsed = !this.collapsed
21
27
  }
22
28
 
@@ -2,23 +2,19 @@
2
2
  <%= render(Primer::OpenProject::FlexLayout.new) do |flex| %>
3
3
  <%= flex.with_row(classes: "CollapsibleSection--triggerArea",
4
4
  id: @title_id,
5
- tabindex: 0,
6
- role: "button",
7
- data: {
8
- action: "click:collapsible-section#toggle keydown:collapsible-section#toggleViaKeyboard",
9
- target: "collapsible-section.triggerElement"
10
- },
11
- aria: { expanded: !@collapsed, controls: @content_id }) do %>
5
+ data: { action: "click:collapsible-section#toggle" }) do %>
12
6
  <%= render(Primer::OpenProject::FlexLayout.new(display: :flex, align_items: :center)) do |header| %>
13
- <%= header.with_column do %>
7
+ <%= header.with_column(id: @heading_id) do %>
14
8
  <%= title %>
15
9
  <% end %>
16
10
  <%= header.with_column do %>
17
11
  <%= caption %>
18
12
  <% end %>
19
13
  <%= header.with_column do %>
20
- <%= render(Primer::Beta::Octicon.new(icon: "chevron-up", hidden: @collapsed, data: { target: "collapsible-section.arrowUp" })) %>
21
- <%= render(Primer::Beta::Octicon.new(icon: "chevron-down", hidden: !@collapsed, data: { target: "collapsible-section.arrowDown" })) %>
14
+ <%= render(Primer::Beta::Button.new(**@toggle_button_arguments)) do %>
15
+ <%= render(Primer::Beta::Octicon.new(icon: "chevron-up", hidden: @collapsed, data: { target: "collapsible-section.arrowUp" })) %>
16
+ <%= render(Primer::Beta::Octicon.new(icon: "chevron-down", hidden: !@collapsed, data: { target: "collapsible-section.arrowDown" })) %>
17
+ <% end %>
22
18
  <% end %>
23
19
  <%= header.with_column(flex: 1, text_align: :right) do %>
24
20
  <%= additional_information %>
@@ -53,6 +53,7 @@ module Primer
53
53
  def initialize(id: self.class.generate_id, collapsed: false, **system_arguments)
54
54
  @title_id = "#{id}-title"
55
55
  @content_id = "#{id}-content"
56
+ @heading_id = "#{id}-heading"
56
57
  @collapsed = collapsed
57
58
 
58
59
  @system_arguments = deny_tag_argument(**system_arguments)
@@ -66,6 +67,13 @@ module Primer
66
67
 
67
68
  @system_arguments[:data] ||= {}
68
69
  @system_arguments[:data][:collapsed] = true if @collapsed
70
+
71
+ @toggle_button_arguments = {
72
+ scheme: :invisible,
73
+ type: :button,
74
+ data: { target: "collapsible-section.triggerElement", "collapsible-toggle": "" },
75
+ aria: { expanded: !@collapsed, controls: @content_id, labelledby: @heading_id }
76
+ }
69
77
  end
70
78
 
71
79
  private
@@ -1 +1 @@
1
- {"version":3,"sources":["filterable_tree_view.pcss"],"names":[],"mappings":"AAYA,qBACE,YAAa,CACb,qBAAsB,CACtB,eAAgB,CAChB,kBACF,CAEA,0BACE,MAAO,CACP,YACF,CAEA,iCACE,MAAO,CACP,YAAa,CACb,eACF,CAGA,wDACE,8CACF,CAIA,0BACE,8CAA+C,CAC/C,aACF,CAGA,mCACE,YACF,CAIA,sEACE,aACF,CAEA,uIAEE,YACF","file":"filterable_tree_view.css","sourcesContent":["/* CSS for FilterableTreeView */\n\n/* Scroll layout\n *\n * The filterable-tree-view element itself acts as a flex column container.\n * The toolbar (input, segmented control, checkbox) is fixed at the top.\n * Only the tree area scrolls. The consumer is responsible for setting a\n * height or max-height on the filterable-tree-view element (or its parent)\n * to activate scrolling.\n */\n\n/* stylelint-disable-next-line selector-max-type */\nfilterable-tree-view {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n max-height: inherit;\n}\n\n.FilterableTreeViewLayout {\n flex: 1;\n min-height: 0;\n}\n\n.FilterableTreeViewTreeContainer {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n}\n\n/* Highlight style for CSS Custom Highlight API */\n::highlight(primer-filterable-tree-view-search-results) {\n background-color: var(--display-yellow-scale-2);\n}\n\n/* Fallback: <mark> elements used when CSS Custom Highlight API is unavailable */\n/* stylelint-disable-next-line selector-max-type */\nfilterable-tree-view mark {\n background-color: var(--display-yellow-scale-2);\n color: inherit;\n}\n\n/* Loading skeleton */\n.FilterableTreeViewLoadingSkeleton {\n display: none;\n}\n\n/* stylelint-disable selector-no-qualifying-type */\n/* stylelint-disable selector-max-type */\nfilterable-tree-view[data-loading] .FilterableTreeViewLoadingSkeleton {\n display: block;\n}\n\nfilterable-tree-view[data-loading] tree-view,\nfilterable-tree-view[data-loading] [data-target~=\"filterable-tree-view.noResultsMessage\"] {\n display: none;\n}\n"]}
1
+ {"version":3,"sources":["filterable_tree_view.pcss"],"names":[],"mappings":"AAYA,qBACE,YAAa,CACb,qBAAsB,CACtB,eAAgB,CAChB,kBACF,CAEA,0BACE,MAAO,CACP,YACF,CAEA,iCACE,MAAO,CACP,YAAa,CACb,eACF,CAGA,wDAEE,8CACF,CAIA,0BAEE,8CAA+C,CAC/C,aACF,CAGA,mCACE,YACF,CAIA,sEACE,aACF,CAEA,uIAEE,YACF","file":"filterable_tree_view.css","sourcesContent":["/* CSS for FilterableTreeView */\n\n/* Scroll layout\n *\n * The filterable-tree-view element itself acts as a flex column container.\n * The toolbar (input, segmented control, checkbox) is fixed at the top.\n * Only the tree area scrolls. The consumer is responsible for setting a\n * height or max-height on the filterable-tree-view element (or its parent)\n * to activate scrolling.\n */\n\n/* stylelint-disable-next-line selector-max-type */\nfilterable-tree-view {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n max-height: inherit;\n}\n\n.FilterableTreeViewLayout {\n flex: 1;\n min-height: 0;\n}\n\n.FilterableTreeViewTreeContainer {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n}\n\n/* Highlight style for CSS Custom Highlight API */\n::highlight(primer-filterable-tree-view-search-results) {\n /* stylelint-disable-next-line primer/no-display-colors, primer/colors -- intentional yellow search-match highlight; no Primer semantic token exists for this */\n background-color: var(--display-yellow-scale-2);\n}\n\n/* Fallback: <mark> elements used when CSS Custom Highlight API is unavailable */\n/* stylelint-disable-next-line selector-max-type */\nfilterable-tree-view mark {\n /* stylelint-disable-next-line primer/no-display-colors, primer/colors -- intentional yellow search-match highlight; no Primer semantic token exists for this */\n background-color: var(--display-yellow-scale-2);\n color: inherit;\n}\n\n/* Loading skeleton */\n.FilterableTreeViewLoadingSkeleton {\n display: none;\n}\n\n/* stylelint-disable selector-no-qualifying-type */\n/* stylelint-disable selector-max-type */\nfilterable-tree-view[data-loading] .FilterableTreeViewLoadingSkeleton {\n display: block;\n}\n\nfilterable-tree-view[data-loading] tree-view,\nfilterable-tree-view[data-loading] [data-target~=\"filterable-tree-view.noResultsMessage\"] {\n display: none;\n}\n"]}
@@ -30,12 +30,14 @@ filterable-tree-view {
30
30
 
31
31
  /* Highlight style for CSS Custom Highlight API */
32
32
  ::highlight(primer-filterable-tree-view-search-results) {
33
+ /* stylelint-disable-next-line primer/no-display-colors, primer/colors -- intentional yellow search-match highlight; no Primer semantic token exists for this */
33
34
  background-color: var(--display-yellow-scale-2);
34
35
  }
35
36
 
36
37
  /* Fallback: <mark> elements used when CSS Custom Highlight API is unavailable */
37
38
  /* stylelint-disable-next-line selector-max-type */
38
39
  filterable-tree-view mark {
40
+ /* stylelint-disable-next-line primer/no-display-colors, primer/colors -- intentional yellow search-match highlight; no Primer semantic token exists for this */
39
41
  background-color: var(--display-yellow-scale-2);
40
42
  color: inherit;
41
43
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["page_header.pcss"],"names":[],"mappings":"AAEA,YACE,YAAa,CACb,iCAAkC,CAClC,iCAAkC,CAClC,oEAAqE,CACrE,gBACF,CAEA,wBACE,kBAAmB,CACnB,gBAAiB,CACjB,eACF,CAEA,uBAME,gCACF,CAEA,4CARE,YAAa,CACb,aAAc,CACd,wBAAyB,CACzB,kBAAmB,CACnB,gCAUF,CAEA,kBACE,uCAAwC,CACxC,aACF,CAEA,yBACE,sCACF,CAGA,wBACE,sCAAuC,CACvC,0BAA2B,CAC3B,WACF,CAEA,4CAEE,iCAA0B,CAA1B,yBACF,CAEA,sBACE,aACF,CAEA,yCACE,qBACF,CAEA,gDACE,iCACF,CAEA,oBACE,wBAAyB,CACzB,YAAa,CACb,kBACF,CAEA,wBACE,aAAc,CACd,UACF,CAEA,0BACE,6BAA8B,CAC9B,+BACF,CAEA,uBACE,aACF,CAGA,uCACE,iDACE,YACF,CACF,CAIE,+CACE,qCACF,CAEA,8CACE,gCACF","file":"page_header.css","sourcesContent":["/* OP PageHeader */\n\n.PageHeader {\n display: flex;\n padding-bottom: var(--base-size-8);\n margin-bottom: var(--base-size-16);\n border-bottom: var(--borderWidth-thin) solid var(--borderColor-muted);\n flex-flow: column;\n}\n\n.PageHeader--withTabNav {\n border-bottom: none;\n padding-bottom: 0;\n margin-bottom: 0;\n}\n\n.PageHeader-contextBar {\n display: flex;\n flex-flow: row;\n justify-content: flex-end;\n align-items: center;\n margin-bottom: var(--base-size-8);\n height: var(--control-small-size);\n}\n\n.PageHeader-titleBar {\n display: flex;\n flex-flow: row;\n justify-content: flex-end;\n align-items: center; /* Keep back button vertically aligned. */\n margin-bottom: var(--base-size-8);\n}\n\n.PageHeader-title {\n font-size: var(--text-title-size-medium);\n flex: 1 1 auto;\n}\n\n.PageHeader-title--large {\n font-size: var(--text-title-size-large);\n}\n\n/* One-liner of supporting text */\n.PageHeader-description {\n font-size: var(--text-body-size-medium);\n color: var(--fgColor-muted);\n flex: 1 auto;\n}\n\n.PageHeader-description--underlined-links a {\n /* Ensure the accessibility is met, given that the description is written in light grey */\n text-decoration: underline;\n}\n\n.PageHeader-tabNavBar {\n overflow: auto;\n}\n\n.PageHeader-tabNavBar .PageHeader-tabNav {\n min-width: max-content;\n}\n\n.PageHeader--withTabNav .PageHeader-description {\n margin-bottom: var(--base-size-16);\n}\n\n.PageHeader-actions {\n justify-content: flex-end;\n display: flex;\n align-items: center;\n}\n\n.PageHeader-breadcrumbs {\n display: block;\n width: 100%;\n}\n\n.PageHeader-leadingAction {\n margin-top: var(--base-size-2); /* to center align with label */\n margin-right: var(--base-size-4);\n}\n\n.PageHeader-parentLink {\n flex: 1 1 auto;\n}\n\n/* Hide the context bar on desktop when no breadcrumb is visible */\n@media screen and (min-width: 543.98px) {\n .PageHeader--noBreadcrumb .PageHeader-contextBar {\n display: none;\n }\n}\n\n/* Match the title bar and actions height with the toggle menu button for proper vertical alignment */\n.PageHeader--noBreadcrumb {\n & .PageHeader-titleBar {\n line-height: var(--control-small-size);\n }\n\n & .PageHeader-actions {\n height: var(--control-small-size);\n }\n}"]}
1
+ {"version":3,"sources":["page_header.pcss"],"names":[],"mappings":"AAEA,YACE,YAAa,CACb,iCAAkC,CAClC,iCAAkC,CAClC,oEAAqE,CACrE,gBACF,CAEA,wBACE,kBAAmB,CACnB,gBAAiB,CACjB,eACF,CAEA,uBAME,gCACF,CAEA,4CARE,YAAa,CACb,aAAc,CACd,wBAAyB,CACzB,kBAAmB,CACnB,gCAUF,CAEA,kBACE,uCAAwC,CACxC,aACF,CAEA,yBACE,sCACF,CAGA,wBACE,sCAAuC,CACvC,0BAA2B,CAC3B,WACF,CAGA,4CAEE,iCAA0B,CAA1B,yBACF,CAEA,sBACE,aACF,CAEA,yCACE,qBACF,CAEA,gDACE,iCACF,CAEA,oBACE,wBAAyB,CACzB,YAAa,CACb,kBACF,CAEA,wBACE,aAAc,CACd,UACF,CAEA,0BACE,6BAA8B,CAC9B,+BACF,CAEA,uBACE,aACF,CAGA,uCACE,iDACE,YACF,CACF,CAIE,+CAEE,qCACF,CAEA,8CACE,gCACF","file":"page_header.css","sourcesContent":["/* OP PageHeader */\n\n.PageHeader {\n display: flex;\n padding-bottom: var(--base-size-8);\n margin-bottom: var(--base-size-16);\n border-bottom: var(--borderWidth-thin) solid var(--borderColor-muted);\n flex-flow: column;\n}\n\n.PageHeader--withTabNav {\n border-bottom: none;\n padding-bottom: 0;\n margin-bottom: 0;\n}\n\n.PageHeader-contextBar {\n display: flex;\n flex-flow: row;\n justify-content: flex-end;\n align-items: center;\n margin-bottom: var(--base-size-8);\n height: var(--control-small-size);\n}\n\n.PageHeader-titleBar {\n display: flex;\n flex-flow: row;\n justify-content: flex-end;\n align-items: center; /* Keep back button vertically aligned. */\n margin-bottom: var(--base-size-8);\n}\n\n.PageHeader-title {\n font-size: var(--text-title-size-medium);\n flex: 1 1 auto;\n}\n\n.PageHeader-title--large {\n font-size: var(--text-title-size-large);\n}\n\n/* One-liner of supporting text */\n.PageHeader-description {\n font-size: var(--text-body-size-medium);\n color: var(--fgColor-muted);\n flex: 1 auto;\n}\n\n/* stylelint-disable-next-line selector-max-type -- description holds rich text; links can only be targeted by the `a` type selector */\n.PageHeader-description--underlined-links a {\n /* Ensure the accessibility is met, given that the description is written in light grey */\n text-decoration: underline;\n}\n\n.PageHeader-tabNavBar {\n overflow: auto;\n}\n\n.PageHeader-tabNavBar .PageHeader-tabNav {\n min-width: max-content;\n}\n\n.PageHeader--withTabNav .PageHeader-description {\n margin-bottom: var(--base-size-16);\n}\n\n.PageHeader-actions {\n justify-content: flex-end;\n display: flex;\n align-items: center;\n}\n\n.PageHeader-breadcrumbs {\n display: block;\n width: 100%;\n}\n\n.PageHeader-leadingAction {\n margin-top: var(--base-size-2); /* to center align with label */\n margin-right: var(--base-size-4);\n}\n\n.PageHeader-parentLink {\n flex: 1 1 auto;\n}\n\n/* Hide the context bar on desktop when no breadcrumb is visible */\n@media screen and (min-width: 543.98px) {\n .PageHeader--noBreadcrumb .PageHeader-contextBar {\n display: none;\n }\n}\n\n/* Match the title bar and actions height with the toggle menu button for proper vertical alignment */\n.PageHeader--noBreadcrumb {\n & .PageHeader-titleBar {\n /* stylelint-disable-next-line primer/typography -- control size var intentionally matches the toggle-menu button height for vertical alignment */\n line-height: var(--control-small-size);\n }\n\n & .PageHeader-actions {\n height: var(--control-small-size);\n }\n}"]}
@@ -47,6 +47,7 @@
47
47
  flex: 1 auto;
48
48
  }
49
49
 
50
+ /* stylelint-disable-next-line selector-max-type -- description holds rich text; links can only be targeted by the `a` type selector */
50
51
  .PageHeader-description--underlined-links a {
51
52
  /* Ensure the accessibility is met, given that the description is written in light grey */
52
53
  text-decoration: underline;
@@ -94,6 +95,7 @@
94
95
  /* Match the title bar and actions height with the toggle menu button for proper vertical alignment */
95
96
  .PageHeader--noBreadcrumb {
96
97
  & .PageHeader-titleBar {
98
+ /* stylelint-disable-next-line primer/typography -- control size var intentionally matches the toggle-menu button height for vertical alignment */
97
99
  line-height: var(--control-small-size);
98
100
  }
99
101
 
@@ -1 +1 @@
1
- .Page{min-width:var(--base-size-32);height:var(--base-size-32);padding:var(--base-size-8) var(--base-size-6);margin-right:var(--base-size-4);color:var(--fgColor-default);white-space:nowrap;vertical-align:middle;cursor:pointer;border-radius:var(--borderRadius-medium,.375rem);transition:background-color .2s cubic-bezier(.3,0,.5,1);display:inline-flex;align-items:center;justify-content:center}.Page[rel=next]>svg,.Page[rel=prev]>svg{height:var(--base-size-16);width:var(--base-size-16)}.Page[rel=prev]>svg{margin-inline-end:var(--base-size-4)}.Page[rel=next]>svg{margin-inline-start:var(--base-size-4)}.Page:last-child{margin-right:0}.Page:focus,.Page:hover{-webkit-text-decoration:none;text-decoration:none;background-color:var(--control-transparent-bgColor-hover);outline:0;transition-duration:.1s}.Page:focus-visible{outline:2px solid var(--bgColor-accent-emphasis)}.Page:active{border-color:var(--borderColor-muted)}.Page[rel=next],.Page[rel=prev]{color:var(--fgColor-accent)}.Page[aria-current],.Page[aria-current]:hover{color:var(--fgColor-onEmphasis);background-color:var(--bgColor-accent-emphasis);border-color:#0000}.Page[aria-current]:focus-visible{outline:2px solid var(--bgColor-accent-emphasis);box-shadow:inset 0 0 0 var(--base-size-2) var(--fgColor-onEmphasis)}.Page[aria-hidden],.Page[aria-hidden]:hover,.Page[role=presentation],.Page[role=presentation]:hover{color:var(--fgColor-disabled);cursor:default;background-color:initial}.PaginationContainer{margin:var(--base-size-16) 0;text-align:center}@media (max-width:543.98px){.Page:not([rel=prev]):not([rel=next]){display:none}}
1
+ .Page{min-width:var(--base-size-32);height:var(--base-size-32);padding:var(--base-size-8) var(--base-size-6);margin-right:var(--base-size-4);color:var(--fgColor-default);white-space:nowrap;vertical-align:middle;cursor:pointer;border-radius:var(--borderRadius-medium);transition:background-color .2s cubic-bezier(.3,0,.5,1);display:inline-flex;align-items:center;justify-content:center}.Page[rel=next]>svg,.Page[rel=prev]>svg{height:var(--base-size-16);width:var(--base-size-16)}.Page[rel=prev]>svg{margin-inline-end:var(--base-size-4)}.Page[rel=next]>svg{margin-inline-start:var(--base-size-4)}.Page:last-child{margin-right:0}.Page:focus,.Page:hover{-webkit-text-decoration:none;text-decoration:none;background-color:var(--control-transparent-bgColor-hover);outline:0;transition-duration:.1s}.Page:focus-visible{outline:2px solid var(--bgColor-accent-emphasis)}.Page:active{border-color:var(--borderColor-muted)}.Page[rel=next],.Page[rel=prev]{color:var(--fgColor-accent)}.Page[aria-current],.Page[aria-current]:hover{color:var(--fgColor-onEmphasis);background-color:var(--bgColor-accent-emphasis);border-color:#0000}.Page[aria-current]:focus-visible{outline:2px solid var(--bgColor-accent-emphasis);box-shadow:inset 0 0 0 var(--base-size-2) var(--fgColor-onEmphasis)}.Page[aria-hidden],.Page[aria-hidden]:hover,.Page[role=presentation],.Page[role=presentation]:hover{color:var(--fgColor-disabled);cursor:default;background-color:initial}.PaginationContainer{margin:var(--base-size-16) 0;text-align:center}@media (max-width:543.98px){.Page:not([rel=prev]):not([rel=next]){display:none}}
@@ -1 +1 @@
1
- {"version":3,"sources":["pagination.pcss"],"names":[],"mappings":"AAAA,MACE,6BAA8B,CAC9B,0BAA2B,CAC3B,6CAA8C,CAC9C,+BAAgC,CAChC,4BAA6B,CAC7B,kBAAmB,CACnB,qBAAsB,CACtB,cAAe,CACf,gDAAiD,CACjD,uDAA8D,CAC9D,mBAAoB,CACpB,kBAAmB,CACnB,sBACF,CAEA,wCAEE,0BAA2B,CAC3B,yBACF,CAEA,oBACE,oCACF,CAEA,oBACE,sCACF,CAEA,iBACE,cACF,CAEA,wBAEE,4BAAqB,CAArB,oBAAqB,CACrB,yDAA0D,CAC1D,SAAU,CACV,uBACF,CAEA,oBACE,gDACF,CAEA,aACE,qCACF,CAEA,gCAEE,2BACF,CAEA,8CAEE,+BAAgC,CAChC,+CAAgD,CAChD,kBACF,CAEA,kCACE,gDAAiD,CACjD,mEACF,CAEA,oGAIE,6BAA8B,CAC9B,cAAe,CACf,wBACF,CAEA,qBACE,4BAA6B,CAC7B,iBACF,CAEA,4BACE,sCACE,YACF,CACF","file":"pagination.css","sourcesContent":[".Page {\n min-width: var(--base-size-32);\n height: var(--base-size-32);\n padding: var(--base-size-8) var(--base-size-6);\n margin-right: var(--base-size-4);\n color: var(--fgColor-default);\n white-space: nowrap;\n vertical-align: middle;\n cursor: pointer;\n border-radius: var(--borderRadius-medium,.375rem);\n transition: background-color 0.2s cubic-bezier(0.3, 0, 0.5, 1);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.Page[rel='prev'] > svg,\n.Page[rel='next'] > svg {\n height: var(--base-size-16);\n width: var(--base-size-16);\n}\n\n.Page[rel='prev'] > svg {\n margin-inline-end: var(--base-size-4);\n}\n\n.Page[rel='next'] > svg {\n margin-inline-start: var(--base-size-4);\n}\n\n.Page:last-child {\n margin-right: 0;\n}\n\n.Page:hover,\n.Page:focus {\n text-decoration: none;\n background-color: var(--control-transparent-bgColor-hover);\n outline: 0;\n transition-duration: 0.1s;\n}\n\n.Page:focus-visible {\n outline: 2px solid var(--bgColor-accent-emphasis);\n}\n\n.Page:active {\n border-color: var(--borderColor-muted);\n}\n\n.Page[rel='prev'],\n.Page[rel='next'] {\n color: var(--fgColor-accent);\n}\n\n.Page[aria-current],\n.Page[aria-current]:hover {\n color: var(--fgColor-onEmphasis);\n background-color: var(--bgColor-accent-emphasis);\n border-color: transparent;\n}\n\n.Page[aria-current]:focus-visible {\n outline: 2px solid var(--bgColor-accent-emphasis);\n box-shadow: inset 0 0 0 var(--base-size-2) var(--fgColor-onEmphasis);\n}\n\n.Page[aria-hidden],\n.Page[aria-hidden]:hover,\n.Page[role='presentation'],\n.Page[role='presentation']:hover {\n color: var(--fgColor-disabled);\n cursor: default;\n background-color: transparent;\n}\n\n.PaginationContainer {\n margin: var(--base-size-16) 0;\n text-align: center;\n}\n\n@media (max-width: 543.98px){\n .Page:not([rel='prev']):not([rel='next']) {\n display: none;\n }\n}\n"]}
1
+ {"version":3,"sources":["pagination.pcss"],"names":[],"mappings":"AAEA,MACE,6BAA8B,CAC9B,0BAA2B,CAC3B,6CAA8C,CAC9C,+BAAgC,CAChC,4BAA6B,CAC7B,kBAAmB,CACnB,qBAAsB,CACtB,cAAe,CACf,wCAAyC,CACzC,uDAA8D,CAC9D,mBAAoB,CACpB,kBAAmB,CACnB,sBACF,CAEA,wCAEE,0BAA2B,CAC3B,yBACF,CAEA,oBACE,oCACF,CAEA,oBACE,sCACF,CAEA,iBACE,cACF,CAEA,wBAEE,4BAAqB,CAArB,oBAAqB,CACrB,yDAA0D,CAC1D,SAAU,CACV,uBACF,CAEA,oBACE,gDACF,CAEA,aACE,qCACF,CAEA,gCAEE,2BACF,CAEA,8CAEE,+BAAgC,CAChC,+CAAgD,CAChD,kBACF,CAEA,kCACE,gDAAiD,CAEjD,mEACF,CAEA,oGAIE,6BAA8B,CAC9B,cAAe,CACf,wBACF,CAEA,qBACE,4BAA6B,CAC7B,iBACF,CAEA,4BACE,sCACE,YACF,CACF","file":"pagination.css","sourcesContent":["/* stylelint-disable selector-max-type -- pagination arrows are styled via `.Page[rel] > svg`; the svg icon can only be targeted by its type selector */\n\n.Page {\n min-width: var(--base-size-32);\n height: var(--base-size-32);\n padding: var(--base-size-8) var(--base-size-6);\n margin-right: var(--base-size-4);\n color: var(--fgColor-default);\n white-space: nowrap;\n vertical-align: middle;\n cursor: pointer;\n border-radius: var(--borderRadius-medium);\n transition: background-color 0.2s cubic-bezier(0.3, 0, 0.5, 1);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.Page[rel='prev'] > svg,\n.Page[rel='next'] > svg {\n height: var(--base-size-16);\n width: var(--base-size-16);\n}\n\n.Page[rel='prev'] > svg {\n margin-inline-end: var(--base-size-4);\n}\n\n.Page[rel='next'] > svg {\n margin-inline-start: var(--base-size-4);\n}\n\n.Page:last-child {\n margin-right: 0;\n}\n\n.Page:hover,\n.Page:focus {\n text-decoration: none;\n background-color: var(--control-transparent-bgColor-hover);\n outline: 0;\n transition-duration: 0.1s;\n}\n\n.Page:focus-visible {\n outline: 2px solid var(--bgColor-accent-emphasis);\n}\n\n.Page:active {\n border-color: var(--borderColor-muted);\n}\n\n.Page[rel='prev'],\n.Page[rel='next'] {\n color: var(--fgColor-accent);\n}\n\n.Page[aria-current],\n.Page[aria-current]:hover {\n color: var(--fgColor-onEmphasis);\n background-color: var(--bgColor-accent-emphasis);\n border-color: transparent;\n}\n\n.Page[aria-current]:focus-visible {\n outline: 2px solid var(--bgColor-accent-emphasis);\n /* stylelint-disable-next-line primer/box-shadow -- custom focus-ring built from Primer size/color primitives; no single Primer box-shadow token matches */\n box-shadow: inset 0 0 0 var(--base-size-2) var(--fgColor-onEmphasis);\n}\n\n.Page[aria-hidden],\n.Page[aria-hidden]:hover,\n.Page[role='presentation'],\n.Page[role='presentation']:hover {\n color: var(--fgColor-disabled);\n cursor: default;\n background-color: transparent;\n}\n\n.PaginationContainer {\n margin: var(--base-size-16) 0;\n text-align: center;\n}\n\n@media (max-width: 543.98px){\n .Page:not([rel='prev']):not([rel='next']) {\n display: none;\n }\n}\n"]}
@@ -1,3 +1,5 @@
1
+ /* stylelint-disable selector-max-type -- pagination arrows are styled via `.Page[rel] > svg`; the svg icon can only be targeted by its type selector */
2
+
1
3
  .Page {
2
4
  min-width: var(--base-size-32);
3
5
  height: var(--base-size-32);
@@ -7,7 +9,7 @@
7
9
  white-space: nowrap;
8
10
  vertical-align: middle;
9
11
  cursor: pointer;
10
- border-radius: var(--borderRadius-medium,.375rem);
12
+ border-radius: var(--borderRadius-medium);
11
13
  transition: background-color 0.2s cubic-bezier(0.3, 0, 0.5, 1);
12
14
  display: inline-flex;
13
15
  align-items: center;
@@ -62,6 +64,7 @@
62
64
 
63
65
  .Page[aria-current]:focus-visible {
64
66
  outline: 2px solid var(--bgColor-accent-emphasis);
67
+ /* stylelint-disable-next-line primer/box-shadow -- custom focus-ring built from Primer size/color primitives; no single Primer box-shadow token matches */
65
68
  box-shadow: inset 0 0 0 var(--base-size-2) var(--fgColor-onEmphasis);
66
69
  }
67
70
 
@@ -1 +1 @@
1
- .SidePanel-sectionHeader{display:flex;align-items:center;height:32px;margin-bottom:8px}.SidePanel-sectionCounter{margin-left:8px}.SidePanel-sectionAction{justify-content:right;flex:1;display:flex}.SidePanel-sectionContent,.SidePanel-sectionDescription{margin-top:0}:is(.SidePanel-sectionContent,.SidePanel-sectionDescription):not(:last-child){margin-bottom:16px}
1
+ .SidePanel-sectionHeader{display:flex;align-items:center;height:32px;margin-bottom:var(--base-size-8)}.SidePanel-sectionCounter{margin-left:var(--base-size-8)}.SidePanel-sectionAction{justify-content:right;flex:1;display:flex}.SidePanel-sectionContent,.SidePanel-sectionDescription{margin-top:0}:is(.SidePanel-sectionContent,.SidePanel-sectionDescription):not(:last-child){margin-bottom:var(--base-size-16)}
@@ -1 +1 @@
1
- {"version":3,"sources":["section.pcss"],"names":[],"mappings":"AAEA,yBACE,YAAa,CACb,kBAAmB,CACnB,WAAY,CACZ,iBACF,CAEA,0BACE,eACF,CAEA,yBACE,qBAAsB,CACtB,MAAO,CACP,YACF,CAEA,wDAEE,YAKF,CAHE,8EACE,kBACF","file":"section.css","sourcesContent":["/* CSS for OpenProject::SidePanel::Section */\n\n.SidePanel-sectionHeader {\n display: flex;\n align-items: center;\n height: 32px;\n margin-bottom: 8px;\n}\n\n.SidePanel-sectionCounter {\n margin-left: 8px;\n}\n\n.SidePanel-sectionAction {\n justify-content: right;\n flex: 1;\n display: flex;\n}\n\n.SidePanel-sectionContent,\n.SidePanel-sectionDescription {\n margin-top: 0;\n\n &:not(:last-child) {\n margin-bottom: 16px;\n }\n}\n"]}
1
+ {"version":3,"sources":["section.pcss"],"names":[],"mappings":"AAEA,yBACE,YAAa,CACb,kBAAmB,CACnB,WAAY,CACZ,gCACF,CAEA,0BACE,8BACF,CAEA,yBACE,qBAAsB,CACtB,MAAO,CACP,YACF,CAEA,wDAEE,YAKF,CAHE,8EACE,iCACF","file":"section.css","sourcesContent":["/* CSS for OpenProject::SidePanel::Section */\n\n.SidePanel-sectionHeader {\n display: flex;\n align-items: center;\n height: 32px;\n margin-bottom: var(--base-size-8);\n}\n\n.SidePanel-sectionCounter {\n margin-left: var(--base-size-8);\n}\n\n.SidePanel-sectionAction {\n justify-content: right;\n flex: 1;\n display: flex;\n}\n\n.SidePanel-sectionContent,\n.SidePanel-sectionDescription {\n margin-top: 0;\n\n &:not(:last-child) {\n margin-bottom: var(--base-size-16);\n }\n}\n"]}
@@ -4,11 +4,11 @@
4
4
  display: flex;
5
5
  align-items: center;
6
6
  height: 32px;
7
- margin-bottom: 8px;
7
+ margin-bottom: var(--base-size-8);
8
8
  }
9
9
 
10
10
  .SidePanel-sectionCounter {
11
- margin-left: 8px;
11
+ margin-left: var(--base-size-8);
12
12
  }
13
13
 
14
14
  .SidePanel-sectionAction {
@@ -22,6 +22,6 @@
22
22
  margin-top: 0;
23
23
 
24
24
  &:not(:last-child) {
25
- margin-bottom: 16px;
25
+ margin-bottom: var(--base-size-16);
26
26
  }
27
27
  }
@@ -46,7 +46,8 @@ module Primer
46
46
 
47
47
  render(
48
48
  locals: {
49
- action_menu_expanded: params[:action_menu_expanded] == "true"
49
+ action_menu_expanded: params[:action_menu_expanded] == "true",
50
+ select_variant: (params[:select_variant] || :none).to_sym
50
51
  }
51
52
  )
52
53
  end
@@ -76,7 +76,6 @@ module Primer
76
76
  @input_arguments = system_arguments
77
77
  @input_arguments.delete(:id) unless @input_arguments[:id].present?
78
78
  @label_arguments = @input_arguments.delete(:label_arguments) || {}
79
- @label_arguments[:for] = id if id.present?
80
79
 
81
80
  @label_arguments[:class] = class_names(
82
81
  @label_arguments[:class],
@@ -121,6 +120,11 @@ module Primer
121
120
  end
122
121
  # rubocop:enable Style/IfUnlessModifier
123
122
 
123
+ # Only set `for` when the id is known. Otherwise leave it unset so
124
+ # Rails generates the scoped id for both label and input; passing
125
+ # `for: nil` would suppress that and drop the association.
126
+ @label_arguments[:for] = @input_arguments[:id] if @input_arguments[:id].present?
127
+
124
128
  # Whether or not to wrap the component in a FormControl, which renders a
125
129
  # label above and validation message beneath the input.
126
130
  @form_control = @input_arguments.delete(:form_control) { true }
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Primer::SafeHrefHelper
4
+ #
5
+ # Detects unsafe URI schemes (e.g. `javascript:`) in `href` values so they can
6
+ # be neutralized before being rendered into HTML attributes. Without this check,
7
+ # a caller that forwards untrusted input into a component's `href:` argument can
8
+ # trigger XSS when the user clicks the rendered anchor.
9
+ module Primer
10
+ # :nodoc:
11
+ module SafeHrefHelper
12
+ # URI schemes that can execute script in the browser and are never valid
13
+ # destinations for a Primer-rendered link.
14
+ DISALLOWED_HREF_SCHEMES = %w[javascript vbscript].freeze
15
+
16
+ # Returns true when `href` starts with a disallowed URI scheme.
17
+ #
18
+ # Mirrors browser URL parsing by stripping ASCII whitespace and control
19
+ # characters (including tab/CR/LF) before extracting the scheme. This
20
+ # prevents bypasses such as `j\tavascript:...`, ` JaVaScRiPt:...`, or a
21
+ # leading null byte, all of which browsers happily execute.
22
+ def self.unsafe_href?(href)
23
+ return false if href.nil?
24
+
25
+ normalized = href.to_s.gsub(/[\u0000-\u0020]/, "")
26
+ scheme = normalized[/\A([a-z][a-z0-9+\-.]*):/i, 1]
27
+ return false unless scheme
28
+
29
+ DISALLOWED_HREF_SCHEMES.include?(scheme.downcase)
30
+ end
31
+
32
+ def unsafe_href?(href)
33
+ SafeHrefHelper.unsafe_href?(href)
34
+ end
35
+ end
36
+ end
@@ -1,21 +1,21 @@
1
1
  <%= render(Primer::Alpha::TreeView::SubTree.new(path: ["primer"], node_variant: :div)) do |tree| %>
2
- <% tree.with_sub_tree(label: "alpha") do |sub_tree| %>
2
+ <% tree.with_sub_tree(label: "alpha", select_variant: select_variant, select_strategy: :self) do |sub_tree| %>
3
3
  <% sub_tree.with_leading_visual_icons do |icons| %>
4
4
  <% icons.with_expanded_icon(icon: :"file-directory-open-fill", color: :accent) %>
5
5
  <% icons.with_collapsed_icon(icon: :"file-directory-fill", color: :accent) %>
6
6
  <% end %>
7
7
 
8
- <% sub_tree.with_sub_tree(label: "action_menu", expanded: action_menu_expanded) do |sub_tree| %>
8
+ <% sub_tree.with_sub_tree(label: "action_menu", expanded: action_menu_expanded, select_variant: select_variant, select_strategy: :self) do |sub_tree| %>
9
9
  <% sub_tree.with_leading_visual_icons do |icons| %>
10
10
  <% icons.with_expanded_icon(icon: :"file-directory-open-fill", color: :accent) %>
11
11
  <% icons.with_collapsed_icon(icon: :"file-directory-fill", color: :accent) %>
12
12
  <% end %>
13
13
 
14
- <% sub_tree.with_leaf(label: "group.rb") do |item| %>
14
+ <% sub_tree.with_leaf(label: "group.rb", select_variant: select_variant) do |item| %>
15
15
  <% item.with_leading_visual_icon(icon: :file) %>
16
16
  <% end %>
17
17
 
18
- <% sub_tree.with_leaf(label: "heading.rb") do |item| %>
18
+ <% sub_tree.with_leaf(label: "heading.rb", select_variant: select_variant) do |item| %>
19
19
  <% item.with_leading_visual_icon(icon: :file) %>
20
20
  <% end %>
21
21
  <% end %>
@@ -10,7 +10,7 @@ module Primer
10
10
  module GeneratePreviews
11
11
  class << self
12
12
  def call
13
- Lookbook.previews.filter_map do |preview|
13
+ Lookbook.previews.sort_by(&:lookup_path).filter_map do |preview|
14
14
  next if preview.preview_class == Primer::FormsPreview
15
15
  next if Primer::Accessibility.ignore_preview?(preview.preview_class)
16
16
 
@@ -5,8 +5,8 @@ module Primer
5
5
  module ViewComponents
6
6
  module VERSION
7
7
  MAJOR = 0
8
- MINOR = 89
9
- PATCH = 2
8
+ MINOR = 91
9
+ PATCH = 0
10
10
 
11
11
  STRING = [MAJOR, MINOR, PATCH].join(".")
12
12
  end
@@ -1,12 +1,12 @@
1
1
  <div style="max-width: 400px">
2
2
  <%= render(Primer::Alpha::TreeView.new) do |tree_view| %>
3
- <% tree_view.with_sub_tree(label: "primer") do |sub_tree| %>
3
+ <% tree_view.with_sub_tree(label: "primer", select_variant: select_variant, select_strategy: :self) do |sub_tree| %>
4
4
  <% sub_tree.with_leading_visual_icons do |icons| %>
5
5
  <% icons.with_expanded_icon(icon: :"file-directory-open-fill", color: :accent) %>
6
6
  <% icons.with_collapsed_icon(icon: :"file-directory-fill", color: :accent) %>
7
7
  <% end %>
8
8
 
9
- <% sub_tree.with_loading_skeleton(src: primer_view_components.tree_view_items_async_alpha_path(action_menu_expanded: action_menu_expanded)) %>
9
+ <% sub_tree.with_loading_skeleton(src: primer_view_components.tree_view_items_async_alpha_path(action_menu_expanded: action_menu_expanded, select_variant: select_variant)) %>
10
10
  <% end %>
11
11
  <% end %>
12
12
  </div>
@@ -0,0 +1,16 @@
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::Alpha::TreeView.new(form_arguments: { builder: f, name: "folder_structure" })) do |tree| %>
4
+ <% tree.with_sub_tree(label: "primer", select_variant: select_variant, select_strategy: :self) do |sub_tree| %>
5
+ <% sub_tree.with_leading_visual_icons do |icons| %>
6
+ <% icons.with_expanded_icon(icon: :"file-directory-open-fill", color: :accent) %>
7
+ <% icons.with_collapsed_icon(icon: :"file-directory-fill", color: :accent) %>
8
+ <% end %>
9
+
10
+ <% sub_tree.with_loading_skeleton(src: primer_view_components.tree_view_items_async_alpha_path(select_variant: select_variant)) %>
11
+ <% end %>
12
+ <% end %>
13
+
14
+ <%= render(Primer::Alpha::SubmitButton.new(name: :submit, label: "Submit")) %>
15
+ <% end %>
16
+ <% end %>
@@ -114,9 +114,11 @@ module Primer
114
114
  # @label Async alpha
115
115
  #
116
116
  # @param action_menu_expanded [Boolean] toggle
117
- def async_alpha(action_menu_expanded: false)
117
+ # @param select_variant [Symbol] select [none, single, multiple]
118
+ def async_alpha(action_menu_expanded: false, select_variant: :none)
118
119
  render_with_template(locals: {
119
- action_menu_expanded: coerce_bool(action_menu_expanded)
120
+ action_menu_expanded: coerce_bool(action_menu_expanded),
121
+ select_variant: select_variant.to_sym
120
122
  })
121
123
  end
122
124
 
@@ -197,6 +199,15 @@ module Primer
197
199
  })
198
200
  end
199
201
 
202
+ # @label Async form input
203
+ # @hidden
204
+ # @param select_variant [Symbol] select [single, multiple]
205
+ def async_form_input(select_variant: :single)
206
+ render_with_template(locals: {
207
+ select_variant: select_variant.to_sym
208
+ })
209
+ end
210
+
200
211
  # @label Doubled paths
201
212
  # @hidden
202
213
  def doubled_path
@@ -0,0 +1,6 @@
1
+ <%= render(Primer::OpenProject::CollapsibleSection.new) do |section| %>
2
+ <% section.with_title { render(Primer::Beta::Link.new(href: "#")) { "Feedback" } } %>
3
+ <% section.with_collapsible_content do %>
4
+ <%= render(Primer::Alpha::Banner.new(mb: 3)) { "Please take one minute to answer this question" } %>
5
+ <% end %>
6
+ <% end %>
@@ -52,6 +52,15 @@ module Primer
52
52
  locals: { }
53
53
  )
54
54
  end
55
+
56
+ # @label With link in title
57
+ # @hidden
58
+ def with_link_in_title
59
+ render_with_template(
60
+ template: "primer/open_project/collapsible_section_preview/with_link_in_title",
61
+ locals: { }
62
+ )
63
+ end
55
64
  end
56
65
  end
57
66
  end
data/static/classes.json CHANGED
@@ -560,6 +560,9 @@
560
560
  "Popover-message": [
561
561
  "Primer::Beta::Popover"
562
562
  ],
563
+ "Popover-message--bottom": [
564
+ "Primer::Beta::Popover"
565
+ ],
563
566
  "Popover-message--bottom-left": [
564
567
  "Primer::Beta::Popover"
565
568
  ],
@@ -569,9 +572,27 @@
569
572
  "Popover-message--large": [
570
573
  "Primer::Beta::Popover"
571
574
  ],
575
+ "Popover-message--left": [
576
+ "Primer::Beta::Popover"
577
+ ],
578
+ "Popover-message--left-bottom": [
579
+ "Primer::Beta::Popover"
580
+ ],
581
+ "Popover-message--left-top": [
582
+ "Primer::Beta::Popover"
583
+ ],
572
584
  "Popover-message--no-caret": [
573
585
  "Primer::Beta::Popover"
574
586
  ],
587
+ "Popover-message--right": [
588
+ "Primer::Beta::Popover"
589
+ ],
590
+ "Popover-message--right-bottom": [
591
+ "Primer::Beta::Popover"
592
+ ],
593
+ "Popover-message--right-top": [
594
+ "Primer::Beta::Popover"
595
+ ],
575
596
  "Popover-message--top-left": [
576
597
  "Primer::Beta::Popover"
577
598
  ],