openproject-primer_view_components 0.89.1 → 0.89.2

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 (173) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -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 +1 -1
  8. data/app/components/primer/alpha/action_bar.css.map +1 -1
  9. data/app/components/primer/alpha/action_list.css +1 -1
  10. data/app/components/primer/alpha/action_list.css.json +4 -10
  11. data/app/components/primer/alpha/action_list.css.map +1 -1
  12. data/app/components/primer/alpha/auto_complete.css +1 -1
  13. data/app/components/primer/alpha/auto_complete.css.map +1 -1
  14. data/app/components/primer/alpha/banner.css +1 -1
  15. data/app/components/primer/alpha/banner.css.map +1 -1
  16. data/app/components/primer/alpha/button_marketing.css +1 -1
  17. data/app/components/primer/alpha/button_marketing.css.map +1 -1
  18. data/app/components/primer/alpha/dialog.css +1 -1
  19. data/app/components/primer/alpha/dialog.css.json +2 -1
  20. data/app/components/primer/alpha/dialog.css.map +1 -1
  21. data/app/components/primer/alpha/dialog.pcss +4 -1
  22. data/app/components/primer/alpha/dropdown.css +1 -1
  23. data/app/components/primer/alpha/dropdown.css.map +1 -1
  24. data/app/components/primer/alpha/layout.css +1 -1
  25. data/app/components/primer/alpha/layout.css.json +10 -14
  26. data/app/components/primer/alpha/layout.css.map +1 -1
  27. data/app/components/primer/alpha/menu.css +1 -1
  28. data/app/components/primer/alpha/menu.css.map +1 -1
  29. data/app/components/primer/alpha/overlay.css +1 -1
  30. data/app/components/primer/alpha/overlay.css.map +1 -1
  31. data/app/components/primer/alpha/segmented_control.css +1 -1
  32. data/app/components/primer/alpha/segmented_control.css.json +1 -2
  33. data/app/components/primer/alpha/segmented_control.css.map +1 -1
  34. data/app/components/primer/alpha/select_panel.css +1 -1
  35. data/app/components/primer/alpha/select_panel.css.map +1 -1
  36. data/app/components/primer/alpha/select_panel_element.ts +1 -1
  37. data/app/components/primer/alpha/skeleton_box.css +1 -1
  38. data/app/components/primer/alpha/skeleton_box.css.map +1 -1
  39. data/app/components/primer/alpha/stack.css +1 -1
  40. data/app/components/primer/alpha/stack.css.map +1 -1
  41. data/app/components/primer/alpha/tab_nav.css +1 -1
  42. data/app/components/primer/alpha/tab_nav.css.map +1 -1
  43. data/app/components/primer/alpha/text_field.css +1 -1
  44. data/app/components/primer/alpha/text_field.css.json +1 -2
  45. data/app/components/primer/alpha/text_field.css.map +1 -1
  46. data/app/components/primer/alpha/toggle_switch.css +1 -1
  47. data/app/components/primer/alpha/toggle_switch.css.map +1 -1
  48. data/app/components/primer/alpha/tree_view/sub_tree_node.rb +1 -1
  49. data/app/components/primer/alpha/tree_view/tree_view_icon_pair_element.js +1 -1
  50. data/app/components/primer/alpha/tree_view/tree_view_icon_pair_element.ts +1 -1
  51. data/app/components/primer/alpha/tree_view/visual.rb +1 -1
  52. data/app/components/primer/alpha/tree_view.css +1 -1
  53. data/app/components/primer/alpha/tree_view.css.json +2 -2
  54. data/app/components/primer/alpha/tree_view.css.map +1 -1
  55. data/app/components/primer/alpha/underline_nav.css +1 -1
  56. data/app/components/primer/alpha/underline_nav.css.map +1 -1
  57. data/app/components/primer/beta/avatar.css +1 -1
  58. data/app/components/primer/beta/avatar.css.map +1 -1
  59. data/app/components/primer/beta/avatar_stack.css +1 -1
  60. data/app/components/primer/beta/avatar_stack.css.map +1 -1
  61. data/app/components/primer/beta/blankslate.css +1 -1
  62. data/app/components/primer/beta/blankslate.css.map +1 -1
  63. data/app/components/primer/beta/border_box.css +1 -1
  64. data/app/components/primer/beta/border_box.css.map +1 -1
  65. data/app/components/primer/beta/border_box.rb +18 -7
  66. data/app/components/primer/beta/breadcrumbs.css +1 -1
  67. data/app/components/primer/beta/breadcrumbs.css.map +1 -1
  68. data/app/components/primer/beta/button.css +1 -1
  69. data/app/components/primer/beta/button.css.map +1 -1
  70. data/app/components/primer/beta/button_group.css +1 -1
  71. data/app/components/primer/beta/button_group.css.map +1 -1
  72. data/app/components/primer/beta/button_group.rb +1 -1
  73. data/app/components/primer/beta/counter.css +1 -1
  74. data/app/components/primer/beta/counter.css.map +1 -1
  75. data/app/components/primer/beta/flash.css +1 -1
  76. data/app/components/primer/beta/flash.css.map +1 -1
  77. data/app/components/primer/beta/label.css +1 -1
  78. data/app/components/primer/beta/label.css.map +1 -1
  79. data/app/components/primer/beta/link.css +1 -1
  80. data/app/components/primer/beta/link.css.map +1 -1
  81. data/app/components/primer/beta/popover.css +1 -1
  82. data/app/components/primer/beta/popover.css.map +1 -1
  83. data/app/components/primer/beta/progress_bar.css +1 -1
  84. data/app/components/primer/beta/progress_bar.css.map +1 -1
  85. data/app/components/primer/beta/state.css +1 -1
  86. data/app/components/primer/beta/state.css.map +1 -1
  87. data/app/components/primer/beta/subhead.css +1 -1
  88. data/app/components/primer/beta/subhead.css.map +1 -1
  89. data/app/components/primer/beta/timeline_item.css +1 -1
  90. data/app/components/primer/beta/timeline_item.css.map +1 -1
  91. data/app/components/primer/beta/truncate.css +1 -1
  92. data/app/components/primer/beta/truncate.css.map +1 -1
  93. data/app/components/primer/dialog_helper.js +10 -1
  94. data/app/components/primer/dialog_helper.ts +16 -1
  95. data/app/components/primer/open_project/border_box/collapsible_header.css +1 -1
  96. data/app/components/primer/open_project/border_box/collapsible_header.css.json +1 -3
  97. data/app/components/primer/open_project/border_box/collapsible_header.css.map +1 -1
  98. data/app/components/primer/open_project/border_grid.css +1 -1
  99. data/app/components/primer/open_project/border_grid.css.map +1 -1
  100. data/app/components/primer/open_project/drag_handle.css +1 -1
  101. data/app/components/primer/open_project/drag_handle.css.map +1 -1
  102. data/app/components/primer/open_project/filterable_tree_view.css +1 -1
  103. data/app/components/primer/open_project/filterable_tree_view.css.map +1 -1
  104. data/app/components/primer/open_project/filterable_tree_view.html.erb +9 -5
  105. data/app/components/primer/open_project/filterable_tree_view.rb +9 -1
  106. data/app/components/primer/open_project/inline_message.css +1 -1
  107. data/app/components/primer/open_project/inline_message.css.map +1 -1
  108. data/app/components/primer/open_project/page_header/dialog.rb +1 -1
  109. data/app/components/primer/open_project/page_header/menu.rb +1 -1
  110. data/app/components/primer/open_project/page_header.css +1 -1
  111. data/app/components/primer/open_project/page_header.css.map +1 -1
  112. data/app/components/primer/open_project/pagination.css +1 -1
  113. data/app/components/primer/open_project/pagination.css.map +1 -1
  114. data/app/components/primer/open_project/side_panel/section.css +1 -1
  115. data/app/components/primer/open_project/side_panel/section.css.map +1 -1
  116. data/app/components/primer/open_project/sub_header.css +1 -1
  117. data/app/components/primer/open_project/sub_header.css.map +1 -1
  118. data/app/lib/primer/forms/acts_as_component.rb +1 -1
  119. data/app/lib/primer/forms/toggle_switch_form.rb +1 -1
  120. data/lib/primer/form_components.rb +1 -1
  121. data/lib/primer/view_components/version.rb +1 -1
  122. data/previews/primer/beta/border_box_preview.rb +3 -3
  123. data/previews/primer/open_project/filterable_tree_view_preview/async_custom_loading_indicator.html.erb +9 -0
  124. data/previews/primer/open_project/filterable_tree_view_preview.rb +7 -0
  125. data/static/arguments.json +12 -0
  126. data/static/info_arch.json +33 -2
  127. data/static/previews.json +13 -0
  128. metadata +2 -46
  129. data/app/assets/javascripts/components/primer/alpha/action_bar_element.d.ts +0 -17
  130. data/app/assets/javascripts/components/primer/alpha/action_list.d.ts +0 -16
  131. data/app/assets/javascripts/components/primer/alpha/action_menu/action_menu_element.d.ts +0 -49
  132. data/app/assets/javascripts/components/primer/alpha/action_menu/action_menu_focus_zone_stack.d.ts +0 -17
  133. data/app/assets/javascripts/components/primer/alpha/dropdown/menu.d.ts +0 -1
  134. data/app/assets/javascripts/components/primer/alpha/dropdown.d.ts +0 -1
  135. data/app/assets/javascripts/components/primer/alpha/modal_dialog.d.ts +0 -18
  136. data/app/assets/javascripts/components/primer/alpha/segmented_control.d.ts +0 -12
  137. data/app/assets/javascripts/components/primer/alpha/select_panel_element.d.ts +0 -65
  138. data/app/assets/javascripts/components/primer/alpha/tab_container.d.ts +0 -1
  139. data/app/assets/javascripts/components/primer/alpha/toggle_switch.d.ts +0 -34
  140. data/app/assets/javascripts/components/primer/alpha/tool_tip.d.ts +0 -27
  141. data/app/assets/javascripts/components/primer/alpha/tree_view/tree_view.d.ts +0 -47
  142. data/app/assets/javascripts/components/primer/alpha/tree_view/tree_view_icon_pair_element.d.ts +0 -15
  143. data/app/assets/javascripts/components/primer/alpha/tree_view/tree_view_include_fragment_element.d.ts +0 -9
  144. data/app/assets/javascripts/components/primer/alpha/tree_view/tree_view_roving_tab_index.d.ts +0 -3
  145. data/app/assets/javascripts/components/primer/alpha/tree_view/tree_view_sub_tree_node_element.d.ts +0 -47
  146. data/app/assets/javascripts/components/primer/alpha/x_banner.d.ts +0 -18
  147. data/app/assets/javascripts/components/primer/anchored_position.d.ts +0 -27
  148. data/app/assets/javascripts/components/primer/beta/auto_complete/auto_complete.d.ts +0 -1
  149. data/app/assets/javascripts/components/primer/beta/clipboard_copy.d.ts +0 -1
  150. data/app/assets/javascripts/components/primer/beta/details_toggle_element.d.ts +0 -40
  151. data/app/assets/javascripts/components/primer/beta/nav_list.d.ts +0 -20
  152. data/app/assets/javascripts/components/primer/beta/nav_list_group_element.d.ts +0 -19
  153. data/app/assets/javascripts/components/primer/beta/relative_time.d.ts +0 -1
  154. data/app/assets/javascripts/components/primer/dialog_helper.d.ts +0 -15
  155. data/app/assets/javascripts/components/primer/focus_group.d.ts +0 -19
  156. data/app/assets/javascripts/components/primer/open_project/avatar_fallback.d.ts +0 -28
  157. data/app/assets/javascripts/components/primer/open_project/border_box/collapsible_header.d.ts +0 -11
  158. data/app/assets/javascripts/components/primer/open_project/collapsible.d.ts +0 -13
  159. data/app/assets/javascripts/components/primer/open_project/collapsible_section.d.ts +0 -10
  160. data/app/assets/javascripts/components/primer/open_project/danger_dialog_form_helper.d.ts +0 -18
  161. data/app/assets/javascripts/components/primer/open_project/filterable_tree_view.d.ts +0 -29
  162. data/app/assets/javascripts/components/primer/open_project/page_header_element.d.ts +0 -9
  163. data/app/assets/javascripts/components/primer/open_project/sub_header_element.d.ts +0 -17
  164. data/app/assets/javascripts/components/primer/open_project/zen_mode_button.d.ts +0 -18
  165. data/app/assets/javascripts/components/primer/primer.d.ts +0 -42
  166. data/app/assets/javascripts/components/primer/scrollable_region.d.ts +0 -13
  167. data/app/assets/javascripts/components/primer/shared_events.d.ts +0 -26
  168. data/app/assets/javascripts/components/primer/utils.d.ts +0 -1
  169. data/app/assets/javascripts/lib/primer/forms/character_counter.d.ts +0 -41
  170. data/app/assets/javascripts/lib/primer/forms/primer_multi_input.d.ts +0 -10
  171. data/app/assets/javascripts/lib/primer/forms/primer_text_area.d.ts +0 -13
  172. data/app/assets/javascripts/lib/primer/forms/primer_text_field.d.ts +0 -30
  173. data/app/assets/javascripts/lib/primer/forms/toggle_switch_input.d.ts +0 -5
@@ -1 +1 @@
1
- .Truncate{display:inline-flex;max-width:100%;min-width:0}.Truncate>.Truncate-text{max-width:fit-content;min-width:1ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:is(.Truncate>.Truncate-text)+.Truncate-text{margin-left:var(--control-small-gap)}.Truncate-text--primary:is(.Truncate>.Truncate-text){flex-basis:200%}.Truncate-text--expandable:is(.Truncate>.Truncate-text):active,.Truncate-text--expandable:is(.Truncate>.Truncate-text):focus,.Truncate-text--expandable:is(.Truncate>.Truncate-text):hover{cursor:pointer;flex-shrink:0;max-width:100%!important}
1
+ .Truncate{display:inline-flex;min-width:0;max-width:100%}.Truncate>.Truncate-text{min-width:1ch;max-width:fit-content;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:is(.Truncate>.Truncate-text)+.Truncate-text{margin-left:var(--control-small-gap)}.Truncate-text--primary:is(.Truncate>.Truncate-text){flex-basis:200%}.Truncate-text--expandable:is(.Truncate>.Truncate-text):active,.Truncate-text--expandable:is(.Truncate>.Truncate-text):focus,.Truncate-text--expandable:is(.Truncate>.Truncate-text):hover{max-width:100%!important;flex-shrink:0;cursor:pointer}
@@ -1 +1 @@
1
- {"version":3,"sources":["truncate.pcss"],"names":[],"mappings":"AAEA,UACE,mBAAoB,CAEpB,cAAe,CADf,WA2BF,CAxBE,yBAEE,qBAAsB,CADtB,aAAc,CAEd,eAAgB,CAChB,sBAAuB,CACvB,kBAkBF,CAhBE,6CAEE,oCACF,CAEA,qDACE,eACF,CAEA,2LAKE,cAAe,CADf,aAAc,CADd,wBAGF","file":"truncate.css","sourcesContent":["/* Truncate */\n\n.Truncate {\n display: inline-flex;\n min-width: 0;\n max-width: 100%;\n\n & > .Truncate-text {\n min-width: 1ch;\n max-width: fit-content;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n\n & + .Truncate-text {\n /* stylelint-disable-next-line primer/spacing */\n margin-left: var(--control-small-gap);\n }\n\n &.Truncate-text--primary {\n flex-basis: 200%;\n }\n\n &.Truncate-text--expandable:hover,\n &.Truncate-text--expandable:focus,\n &.Truncate-text--expandable:active {\n max-width: 100% !important;\n flex-shrink: 0;\n cursor: pointer;\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["truncate.pcss"],"names":[],"mappings":"AAEA,UACE,mBAAoB,CACpB,WAAY,CACZ,cA0BF,CAxBE,yBACE,aAAc,CACd,qBAAsB,CACtB,eAAgB,CAChB,sBAAuB,CACvB,kBAkBF,CAhBE,6CAEE,oCACF,CAEA,qDACE,eACF,CAEA,2LAGE,wBAA0B,CAC1B,aAAc,CACd,cACF","file":"truncate.css","sourcesContent":["/* Truncate */\n\n.Truncate {\n display: inline-flex;\n min-width: 0;\n max-width: 100%;\n\n & > .Truncate-text {\n min-width: 1ch;\n max-width: fit-content;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n\n & + .Truncate-text {\n /* stylelint-disable-next-line primer/spacing */\n margin-left: var(--control-small-gap);\n }\n\n &.Truncate-text--primary {\n flex-basis: 200%;\n }\n\n &.Truncate-text--expandable:hover,\n &.Truncate-text--expandable:focus,\n &.Truncate-text--expandable:active {\n max-width: 100% !important;\n flex-shrink: 0;\n cursor: pointer;\n }\n }\n}\n"]}
@@ -15,6 +15,10 @@ function setScrollGutter(doc) {
15
15
  return;
16
16
  doc.body.style.setProperty('--dialog-scrollgutter', `${window.innerWidth - doc.body.clientWidth}px`);
17
17
  }
18
+ function updateBodyModalClasses(doc) {
19
+ doc.body.classList.toggle('has-modal', Boolean(doc.querySelector('dialog[open]')));
20
+ doc.body.classList.toggle('has-modal-disable-scroll', Boolean(doc.querySelector('dialog[open].Overlay--disableScroll')));
21
+ }
18
22
  function dialogInvokerButtonHandler(event) {
19
23
  const target = event.target;
20
24
  const button = target?.closest('button');
@@ -75,6 +79,7 @@ function dialogInvokerButtonHandler(event) {
75
79
  }
76
80
  }, { once: true });
77
81
  }
82
+ updateBodyModalClasses(dialog.ownerDocument);
78
83
  }
79
84
  }
80
85
  dialogId = button.getAttribute('data-close-dialog-id') || button.getAttribute('data-submit-dialog-id');
@@ -82,6 +87,7 @@ function dialogInvokerButtonHandler(event) {
82
87
  const dialog = document.getElementById(dialogId);
83
88
  if (dialog instanceof HTMLDialogElement && dialog.open) {
84
89
  dialog.close();
90
+ updateBodyModalClasses(dialog.ownerDocument);
85
91
  }
86
92
  }
87
93
  }
@@ -98,6 +104,7 @@ export class DialogHelperElement extends HTMLElement {
98
104
  const { signal } = (__classPrivateFieldSet(this, _DialogHelperElement_abortController, new AbortController(), "f"));
99
105
  document.addEventListener('click', dialogInvokerButtonHandler, true);
100
106
  document.addEventListener('click', this, { signal });
107
+ this.dialog?.addEventListener('close', () => updateBodyModalClasses(this.dialog.ownerDocument), { signal });
101
108
  new MutationObserver(records => {
102
109
  for (const record of records) {
103
110
  if (record.target === this.dialog) {
@@ -132,14 +139,16 @@ export class DialogHelperElement extends HTMLElement {
132
139
  _DialogHelperElement_abortController = new WeakMap(), _DialogHelperElement_instances = new WeakSet(), _DialogHelperElement_handleDialogOpenAttribute = function _DialogHelperElement_handleDialogOpenAttribute() {
133
140
  if (!this.dialog)
134
141
  return;
142
+ const { ownerDocument } = this.dialog;
135
143
  // We don't want to show the Dialog component as non-modal
136
144
  if (this.dialog.matches('[open]:not(:modal)')) {
137
145
  // eslint-disable-next-line no-restricted-syntax
138
146
  this.dialog.addEventListener('close', e => e.stopImmediatePropagation(), { once: true });
139
147
  this.dialog.close();
140
- setScrollGutter(this.dialog.ownerDocument);
148
+ setScrollGutter(ownerDocument);
141
149
  this.dialog.showModal();
142
150
  }
151
+ updateBodyModalClasses(ownerDocument);
143
152
  };
144
153
  if (!window.customElements.get('dialog-helper')) {
145
154
  window.DialogHelperElement = DialogHelperElement;
@@ -3,6 +3,14 @@ function setScrollGutter(doc: Document) {
3
3
  doc.body.style.setProperty('--dialog-scrollgutter', `${window.innerWidth - doc.body.clientWidth}px`)
4
4
  }
5
5
 
6
+ function updateBodyModalClasses(doc: Document) {
7
+ doc.body.classList.toggle('has-modal', Boolean(doc.querySelector('dialog[open]')))
8
+ doc.body.classList.toggle(
9
+ 'has-modal-disable-scroll',
10
+ Boolean(doc.querySelector('dialog[open].Overlay--disableScroll')),
11
+ )
12
+ }
13
+
6
14
  function dialogInvokerButtonHandler(event: Event) {
7
15
  const target = event.target as HTMLElement
8
16
  const button = target?.closest('button')
@@ -69,6 +77,8 @@ function dialogInvokerButtonHandler(event: Event) {
69
77
  {once: true},
70
78
  )
71
79
  }
80
+
81
+ updateBodyModalClasses(dialog.ownerDocument)
72
82
  }
73
83
  }
74
84
 
@@ -77,6 +87,7 @@ function dialogInvokerButtonHandler(event: Event) {
77
87
  const dialog = document.getElementById(dialogId)
78
88
  if (dialog instanceof HTMLDialogElement && dialog.open) {
79
89
  dialog.close()
90
+ updateBodyModalClasses(dialog.ownerDocument)
80
91
  }
81
92
  }
82
93
  }
@@ -91,6 +102,7 @@ export class DialogHelperElement extends HTMLElement {
91
102
  const {signal} = (this.#abortController = new AbortController())
92
103
  document.addEventListener('click', dialogInvokerButtonHandler, true)
93
104
  document.addEventListener('click', this, {signal})
105
+ this.dialog?.addEventListener('close', () => updateBodyModalClasses(this.dialog!.ownerDocument), {signal})
94
106
  new MutationObserver(records => {
95
107
  for (const record of records) {
96
108
  if (record.target === this.dialog) {
@@ -107,14 +119,17 @@ export class DialogHelperElement extends HTMLElement {
107
119
 
108
120
  #handleDialogOpenAttribute() {
109
121
  if (!this.dialog) return
122
+ const {ownerDocument} = this.dialog
110
123
  // We don't want to show the Dialog component as non-modal
111
124
  if (this.dialog.matches('[open]:not(:modal)')) {
112
125
  // eslint-disable-next-line no-restricted-syntax
113
126
  this.dialog.addEventListener('close', e => e.stopImmediatePropagation(), {once: true})
114
127
  this.dialog.close()
115
- setScrollGutter(this.dialog.ownerDocument)
128
+ setScrollGutter(ownerDocument)
116
129
  this.dialog.showModal()
117
130
  }
131
+
132
+ updateBodyModalClasses(ownerDocument)
118
133
  }
119
134
 
120
135
  handleEvent(event: MouseEvent) {
@@ -1 +1 @@
1
- .CollapsibleHeader{container-name:collapsible-header-container;container-type:inline-size;display:block}.Box:has(.CollapsibleHeader--collapsed){border-bottom-left-radius:0;border-bottom-right-radius:0;border-bottom-width:var(--borderWidth-thicker)}.Box:has(.CollapsibleHeader--collapsed) .Box-body,.Box:has(.CollapsibleHeader--collapsed) .Box-footer,.Box:has(.CollapsibleHeader--collapsed) .Box-list{display:none}.CollapsibleHeader-triggerArea{align-items:center;column-gap:var(--stack-gap-normal);cursor:pointer;display:flex;flex-wrap:nowrap;overflow:hidden;row-gap:var(--base-size-4);-webkit-user-select:none;user-select:none}.CollapsibleHeader>.CollapsibleHeader-triggerArea{flex:1}@container collapsible-header-container (width < 544px){.CollapsibleHeader-triggerArea{align-items:flex-start;flex-direction:column}.CollapsibleHeader[data-collapsed] .CollapsibleHeader-description{display:none}.CollapsibleHeader-description{width:100%}}.CollapsibleHeader--multi-line .CollapsibleHeader-triggerArea{align-items:flex-start;flex-direction:column}.CollapsibleHeader--multi-line.CollapsibleHeader[data-collapsed] .CollapsibleHeader-description{display:none}.CollapsibleHeader--multi-line .CollapsibleHeader-description{overflow:visible;text-overflow:clip;white-space:normal;width:100%}.CollapsibleHeader-title-line{align-items:center;display:flex;flex-basis:66%;gap:var(--stack-gap-condensed);max-width:100%;overflow:hidden}.CollapsibleHeader-description{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;-webkit-user-select:text;user-select:text;white-space:nowrap}
1
+ .CollapsibleHeader{display:block;container-name:collapsible-header-container;container-type:inline-size}.Box:has(.CollapsibleHeader--collapsed){border-bottom-left-radius:0;border-bottom-right-radius:0;border-bottom-width:var(--borderWidth-thicker)}.Box:has(.CollapsibleHeader--collapsed) :is(.Box-body,.Box-footer,.Box-list){display:none}.CollapsibleHeader-triggerArea{cursor:pointer;-webkit-user-select:none;user-select:none;display:flex;flex-wrap:nowrap;align-items:center;column-gap:var(--stack-gap-normal);row-gap:var(--base-size-4);overflow:hidden}.CollapsibleHeader>.CollapsibleHeader-triggerArea{flex:1}@container collapsible-header-container (width < 544px){.CollapsibleHeader-triggerArea{flex-direction:column;align-items:flex-start}.CollapsibleHeader[data-collapsed] .CollapsibleHeader-description{display:none}.CollapsibleHeader-description{width:100%}}.CollapsibleHeader--multi-line .CollapsibleHeader-triggerArea{flex-direction:column;align-items:flex-start}.CollapsibleHeader--multi-line.CollapsibleHeader[data-collapsed] .CollapsibleHeader-description{display:none}.CollapsibleHeader--multi-line .CollapsibleHeader-description{overflow:visible;text-overflow:clip;white-space:normal;width:100%}.CollapsibleHeader-title-line{flex-basis:66%;display:flex;align-items:center;gap:var(--stack-gap-condensed);overflow:hidden;max-width:100%}.CollapsibleHeader-description{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;-webkit-user-select:text;user-select:text}
@@ -3,9 +3,7 @@
3
3
  "selectors": [
4
4
  ".CollapsibleHeader",
5
5
  ".Box:has(.CollapsibleHeader--collapsed)",
6
- ".Box:has(.CollapsibleHeader--collapsed) .Box-body",
7
- ".Box:has(.CollapsibleHeader--collapsed) .Box-footer",
8
- ".Box:has(.CollapsibleHeader--collapsed) .Box-list",
6
+ ".Box:has(.CollapsibleHeader--collapsed) :is(.Box-body,.Box-footer,.Box-list)",
9
7
  ".CollapsibleHeader-triggerArea",
10
8
  ".CollapsibleHeader>.CollapsibleHeader-triggerArea",
11
9
  ".CollapsibleHeader[data-collapsed] .CollapsibleHeader-description",
@@ -1 +1 @@
1
- {"version":3,"sources":["collapsible_header.pcss"],"names":[],"mappings":"AAEA,mBAEE,2CAA4C,CAC5C,0BAA2B,CAF3B,aAGF,CAEA,wCACE,2BAA4B,CAC5B,4BAA6B,CAC7B,8CAOF,CALE,wJAGE,YACF,CAGF,+BAKE,kBAAmB,CACnB,kCAAmC,CALnC,cAAe,CAEf,YAAa,CACb,gBAAiB,CAIjB,eAAgB,CADhB,0BAA2B,CAL3B,wBAAiB,CAAjB,gBAWF,CAHE,kDACE,MACF,CAGF,wDACE,+BAEE,sBAAuB,CADvB,qBAEF,CAEA,kEACE,YACF,CAEA,+BACE,UACF,CACF,CAGE,8DAEE,sBAAuB,CADvB,qBAEF,CAEA,gGACE,YACF,CAEA,8DACE,gBAAiB,CACjB,kBAAsB,CACtB,kBAAmB,CACnB,UACF,CAGF,8BAGE,kBAAmB,CADnB,YAAa,CADb,cAAe,CAGf,8BAA+B,CAE/B,cAAe,CADf,eAEF,CAEA,+BACE,MAAO,CACP,WAAY,CACZ,eAAgB,CAChB,sBAAuB,CAEvB,wBAAiB,CAAjB,gBAAiB,CADjB,kBAEF","file":"collapsible_header.css","sourcesContent":["/* CSS for BorderBox::CollapsibleHeader */\n\n.CollapsibleHeader {\n display: block;\n container-name: collapsible-header-container;\n container-type: inline-size;\n}\n\n.Box:has(.CollapsibleHeader--collapsed) {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-width: var(--borderWidth-thicker);\n\n & .Box-list,\n & .Box-body,\n & .Box-footer {\n display: none;\n }\n}\n\n.CollapsibleHeader-triggerArea {\n cursor: pointer;\n user-select: none;\n display: flex;\n flex-wrap: nowrap;\n align-items: center;\n column-gap: var(--stack-gap-normal);\n row-gap: var(--base-size-4);\n overflow: hidden;\n\n .CollapsibleHeader > & {\n flex: 1;\n }\n}\n\n@container collapsible-header-container (width < 544px) {\n .CollapsibleHeader-triggerArea {\n flex-direction: column;\n align-items: flex-start;\n }\n\n .CollapsibleHeader[data-collapsed] .CollapsibleHeader-description {\n display: none;\n }\n\n .CollapsibleHeader-description {\n width: 100%;\n }\n}\n\n.CollapsibleHeader--multi-line {\n .CollapsibleHeader-triggerArea {\n flex-direction: column;\n align-items: flex-start;\n }\n\n &.CollapsibleHeader[data-collapsed] .CollapsibleHeader-description {\n display: none;\n }\n\n .CollapsibleHeader-description {\n overflow: visible;\n text-overflow: initial;\n white-space: normal;\n width: 100%;\n }\n}\n\n.CollapsibleHeader-title-line {\n flex-basis: 66%;\n display: flex;\n align-items: center;\n gap: var(--stack-gap-condensed);\n overflow: hidden;\n max-width: 100%;\n}\n\n.CollapsibleHeader-description {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n user-select: text;\n}\n"]}
1
+ {"version":3,"sources":["collapsible_header.pcss"],"names":[],"mappings":"AAEA,mBACE,aAAc,CACd,2CAA4C,CAC5C,0BACF,CAEA,wCACE,2BAA4B,CAC5B,4BAA6B,CAC7B,8CAOF,CALE,6EAGE,YACF,CAGF,+BACE,cAAe,CACf,wBAAiB,CAAjB,gBAAiB,CACjB,YAAa,CACb,gBAAiB,CACjB,kBAAmB,CACnB,kCAAmC,CACnC,0BAA2B,CAC3B,eAKF,CAHE,kDACE,MACF,CAGF,wDACE,+BACE,qBAAsB,CACtB,sBACF,CAEA,kEACE,YACF,CAEA,+BACE,UACF,CACF,CAGE,8DACE,qBAAsB,CACtB,sBACF,CAEA,gGACE,YACF,CAEA,8DACE,gBAAiB,CACjB,kBAAsB,CACtB,kBAAmB,CACnB,UACF,CAGF,8BACE,cAAe,CACf,YAAa,CACb,kBAAmB,CACnB,8BAA+B,CAC/B,eAAgB,CAChB,cACF,CAEA,+BACE,MAAO,CACP,WAAY,CACZ,eAAgB,CAChB,sBAAuB,CACvB,kBAAmB,CACnB,wBAAiB,CAAjB,gBACF","file":"collapsible_header.css","sourcesContent":["/* CSS for BorderBox::CollapsibleHeader */\n\n.CollapsibleHeader {\n display: block;\n container-name: collapsible-header-container;\n container-type: inline-size;\n}\n\n.Box:has(.CollapsibleHeader--collapsed) {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-width: var(--borderWidth-thicker);\n\n & .Box-list,\n & .Box-body,\n & .Box-footer {\n display: none;\n }\n}\n\n.CollapsibleHeader-triggerArea {\n cursor: pointer;\n user-select: none;\n display: flex;\n flex-wrap: nowrap;\n align-items: center;\n column-gap: var(--stack-gap-normal);\n row-gap: var(--base-size-4);\n overflow: hidden;\n\n .CollapsibleHeader > & {\n flex: 1;\n }\n}\n\n@container collapsible-header-container (width < 544px) {\n .CollapsibleHeader-triggerArea {\n flex-direction: column;\n align-items: flex-start;\n }\n\n .CollapsibleHeader[data-collapsed] .CollapsibleHeader-description {\n display: none;\n }\n\n .CollapsibleHeader-description {\n width: 100%;\n }\n}\n\n.CollapsibleHeader--multi-line {\n .CollapsibleHeader-triggerArea {\n flex-direction: column;\n align-items: flex-start;\n }\n\n &.CollapsibleHeader[data-collapsed] .CollapsibleHeader-description {\n display: none;\n }\n\n .CollapsibleHeader-description {\n overflow: visible;\n text-overflow: initial;\n white-space: normal;\n width: 100%;\n }\n}\n\n.CollapsibleHeader-title-line {\n flex-basis: 66%;\n display: flex;\n align-items: center;\n gap: var(--stack-gap-condensed);\n overflow: hidden;\n max-width: 100%;\n}\n\n.CollapsibleHeader-description {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n user-select: text;\n}\n"]}
@@ -1 +1 @@
1
- .BorderGrid{border-collapse:collapse;border-style:hidden;display:table;margin-bottom:-16px;margin-top:-16px;table-layout:fixed;width:100%}.BorderGrid .BorderGrid-cell{padding-bottom:16px;padding-top:16px}.BorderGrid--spacious{margin-bottom:-24px;margin-top:-24px}.BorderGrid--spacious .BorderGrid-cell{padding-bottom:24px;padding-top:24px}.BorderGrid-row{display:table-row}.BorderGrid-cell{border:1px solid var(--borderColor-muted);display:table-cell}
1
+ .BorderGrid{display:table;width:100%;margin-top:-16px;margin-bottom:-16px;table-layout:fixed;border-collapse:collapse;border-style:hidden}.BorderGrid .BorderGrid-cell{padding-top:16px;padding-bottom:16px}.BorderGrid--spacious{margin-top:-24px;margin-bottom:-24px}.BorderGrid--spacious .BorderGrid-cell{padding-top:24px;padding-bottom:24px}.BorderGrid-row{display:table-row}.BorderGrid-cell{display:table-cell;border:1px solid var(--borderColor-muted)}
@@ -1 +1 @@
1
- {"version":3,"sources":["border_grid.pcss"],"names":[],"mappings":"AAEA,YAMI,wBAAyB,CACzB,mBAAmB,CANnB,aAAc,CAGd,mBAAoB,CADpB,gBAAiB,CAEjB,kBAAmB,CAHnB,UAMJ,CAEA,6BAEI,mBAAmB,CADnB,gBAEJ,CAEA,sBAEI,mBAAmB,CADnB,gBAEJ,CAEA,uCAEI,mBAAmB,CADnB,gBAEJ,CAEA,gBACI,iBACJ,CAEA,iBAEI,yCAAyC,CADzC,kBAEJ","file":"border_grid.css","sourcesContent":["/* CSS for BorderGrid */\n\n.BorderGrid {\n display: table;\n width: 100%;\n margin-top: -16px;\n margin-bottom: -16px;\n table-layout: fixed;\n border-collapse: collapse;\n border-style: hidden\n}\n\n.BorderGrid .BorderGrid-cell {\n padding-top: 16px;\n padding-bottom: 16px\n}\n\n.BorderGrid--spacious {\n margin-top: -24px;\n margin-bottom: -24px\n}\n\n.BorderGrid--spacious .BorderGrid-cell {\n padding-top: 24px;\n padding-bottom: 24px\n}\n\n.BorderGrid-row {\n display: table-row\n}\n\n.BorderGrid-cell {\n display: table-cell;\n border: 1px solid var(--borderColor-muted)\n}\n"]}
1
+ {"version":3,"sources":["border_grid.pcss"],"names":[],"mappings":"AAEA,YACI,aAAc,CACd,UAAW,CACX,gBAAiB,CACjB,mBAAoB,CACpB,kBAAmB,CACnB,wBAAyB,CACzB,mBACJ,CAEA,6BACI,gBAAiB,CACjB,mBACJ,CAEA,sBACI,gBAAiB,CACjB,mBACJ,CAEA,uCACI,gBAAiB,CACjB,mBACJ,CAEA,gBACI,iBACJ,CAEA,iBACI,kBAAmB,CACnB,yCACJ","file":"border_grid.css","sourcesContent":["/* CSS for BorderGrid */\n\n.BorderGrid {\n display: table;\n width: 100%;\n margin-top: -16px;\n margin-bottom: -16px;\n table-layout: fixed;\n border-collapse: collapse;\n border-style: hidden\n}\n\n.BorderGrid .BorderGrid-cell {\n padding-top: 16px;\n padding-bottom: 16px\n}\n\n.BorderGrid--spacious {\n margin-top: -24px;\n margin-bottom: -24px\n}\n\n.BorderGrid--spacious .BorderGrid-cell {\n padding-top: 24px;\n padding-bottom: 24px\n}\n\n.BorderGrid-row {\n display: table-row\n}\n\n.BorderGrid-cell {\n display: table-cell;\n border: 1px solid var(--borderColor-muted)\n}\n"]}
@@ -1 +1 @@
1
- .DragHandle{color:var(--fgColor-muted);cursor:move}
1
+ .DragHandle{cursor:move;color:var(--fgColor-muted)}
@@ -1 +1 @@
1
- {"version":3,"sources":["drag_handle.pcss"],"names":[],"mappings":"AAEA,YAEI,0BAA2B,CAD3B,WAEJ","file":"drag_handle.css","sourcesContent":["/* CSS for DragHandle */\n\n.DragHandle {\n cursor: move;\n color: var(--fgColor-muted);\n}\n"]}
1
+ {"version":3,"sources":["drag_handle.pcss"],"names":[],"mappings":"AAEA,YACI,WAAY,CACZ,0BACJ","file":"drag_handle.css","sourcesContent":["/* CSS for DragHandle */\n\n.DragHandle {\n cursor: move;\n color: var(--fgColor-muted);\n}\n"]}
@@ -1 +1 @@
1
- filterable-tree-view{display:flex;flex-direction:column;max-height:inherit;overflow:hidden}.FilterableTreeViewLayout{flex:1;min-height:0}.FilterableTreeViewTreeContainer{flex:1;min-height:0;overflow-y:auto}::highlight(primer-filterable-tree-view-search-results){background-color:var(--display-yellow-scale-2)}filterable-tree-view mark{background-color:var(--display-yellow-scale-2);color:inherit}.FilterableTreeViewLoadingSkeleton{display:none}filterable-tree-view[data-loading] .FilterableTreeViewLoadingSkeleton{display:block}filterable-tree-view[data-loading] [data-target~="filterable-tree-view.noResultsMessage"],filterable-tree-view[data-loading] tree-view{display:none}
1
+ filterable-tree-view{display:flex;flex-direction:column;overflow:hidden;max-height:inherit}.FilterableTreeViewLayout{flex:1;min-height:0}.FilterableTreeViewTreeContainer{flex:1;min-height:0;overflow-y:auto}::highlight(primer-filterable-tree-view-search-results){background-color:var(--display-yellow-scale-2)}filterable-tree-view mark{background-color:var(--display-yellow-scale-2);color:inherit}.FilterableTreeViewLoadingSkeleton{display:none}filterable-tree-view[data-loading] .FilterableTreeViewLoadingSkeleton{display:block}filterable-tree-view[data-loading] [data-target~="filterable-tree-view.noResultsMessage"],filterable-tree-view[data-loading] tree-view{display:none}
@@ -1 +1 @@
1
- {"version":3,"sources":["filterable_tree_view.pcss"],"names":[],"mappings":"AAYA,qBACE,YAAa,CACb,qBAAsB,CAEtB,kBAAmB,CADnB,eAEF,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,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"]}
@@ -28,11 +28,15 @@
28
28
  <% end %>
29
29
  <% end %>
30
30
  <div class="FilterableTreeViewLoadingSkeleton" aria-hidden="true">
31
- <% [0, 8, 8, 16, 8, 0, 8, 8].each do |indent| %>
32
- <span class="TreeViewSkeletonItemContainerStyle" style="padding-left: <%= indent %>px">
33
- <%= render(Primer::Alpha::SkeletonBox.new(width: "16px")) %>
34
- <%= render(Primer::Alpha::SkeletonBox.new(classes: "TreeItemSkeletonTextStyles")) %>
35
- </span>
31
+ <% if loading_indicator? %>
32
+ <%= loading_indicator %>
33
+ <% else %>
34
+ <% [0, 8, 8, 16, 8, 0, 8, 8].each do |indent| %>
35
+ <span class="TreeViewSkeletonItemContainerStyle" style="padding-left: <%= indent %>px">
36
+ <%= render(Primer::Alpha::SkeletonBox.new(width: "16px")) %>
37
+ <%= render(Primer::Alpha::SkeletonBox.new(classes: "TreeItemSkeletonTextStyles")) %>
38
+ </span>
39
+ <% end %>
36
40
  <% end %>
37
41
  </div>
38
42
  <%= render(@tree_view) %>
@@ -133,11 +133,19 @@ module Primer
133
133
  # ```erb
134
134
  # <%= render(Primer::OpenProject::FilterableTreeView.new(
135
135
  # src: my_path
136
- # )) %>
136
+ # )) do |tree_view| %>
137
+ # <% tree_view.with_loading_indicator do %>
138
+ # <%= render(Primer::Beta::Spinner.new) %>
139
+ # <% end %>
140
+ # <% end %>
137
141
  # ```
138
142
  class FilterableTreeView < Primer::Component
139
143
  delegate :with_leaf, :with_sub_tree, to: :@tree_view
140
144
 
145
+ # An optional loading indicator shown while an async filter request is in progress. When omitted, a skeleton
146
+ # loader is rendered. This slot is only used when `src` is set.
147
+ renders_one :loading_indicator
148
+
141
149
  SUPPORTED_SELECT_VARIANTS = %i[multiple single none].freeze
142
150
 
143
151
  DEFAULT_FILTER_INPUT_ARGUMENTS = {
@@ -1 +1 @@
1
- .InlineMessage{align-items:start;color:var(--inline-message-fgColor);column-gap:.5rem;display:grid;font-size:var(--inline-message-fontSize);grid-template-columns:auto 1fr;line-height:var(--inline-message-lineHeight)}.InlineMessage[data-size=small]{--inline-message-fontSize:var(--text-body-size-small);--inline-message-lineHeight:var(--text-body-lineHeight-small,1.6666)}.InlineMessage[data-size=medium]{--inline-message-fontSize:var(--text-body-size-medium);--inline-message-lineHeight:var(--text-body-lineHeight-medium,1.4285)}.InlineMessage[data-variant=warning]{--inline-message-fgColor:var(--fgColor-attention)}.InlineMessage[data-variant=critical]{--inline-message-fgColor:var(--fgColor-danger)}.InlineMessage[data-variant=success]{--inline-message-fgColor:var(--fgColor-success)}.InlineMessage[data-variant=unavailable]{--inline-message-fgColor:var(--fgColor-muted)}.InlineMessageIcon{min-height:calc(var(--inline-message-lineHeight)*var(--inline-message-fontSize))}
1
+ .InlineMessage{display:grid;font-size:var(--inline-message-fontSize);line-height:var(--inline-message-lineHeight);color:var(--inline-message-fgColor);column-gap:.5rem;grid-template-columns:auto 1fr;align-items:start}.InlineMessage[data-size=small]{--inline-message-fontSize:var(--text-body-size-small);--inline-message-lineHeight:var(--text-body-lineHeight-small,1.6666)}.InlineMessage[data-size=medium]{--inline-message-fontSize:var(--text-body-size-medium);--inline-message-lineHeight:var(--text-body-lineHeight-medium,1.4285)}.InlineMessage[data-variant=warning]{--inline-message-fgColor:var(--fgColor-attention)}.InlineMessage[data-variant=critical]{--inline-message-fgColor:var(--fgColor-danger)}.InlineMessage[data-variant=success]{--inline-message-fgColor:var(--fgColor-success)}.InlineMessage[data-variant=unavailable]{--inline-message-fgColor:var(--fgColor-muted)}.InlineMessageIcon{min-height:calc(var(--inline-message-lineHeight)*var(--inline-message-fontSize))}
@@ -1 +1 @@
1
- {"version":3,"sources":["inline_message.pcss"],"names":[],"mappings":"AAAA,eAUE,iBAAkB,CAHlB,mCAAoC,CACpC,gBAAkB,CAPlB,YAAa,CAEb,wCAAyC,CAMzC,8BAA+B,CAJ/B,4CAgCF,CAzBE,gCACE,qDAAsD,CACtD,oEACF,CAEA,iCACE,sDAAuD,CACvD,qEACF,CAEA,qCACE,iDACF,CAEA,sCACE,8CACF,CAEA,qCACE,+CACF,CAEA,yCACE,6CACF,CAGF,mBACE,gFACF","file":"inline_message.css","sourcesContent":[".InlineMessage {\n display: grid;\n /* stylelint-disable-next-line primer/typography */\n font-size: var(--inline-message-fontSize);\n /* stylelint-disable-next-line primer/typography */\n line-height: var(--inline-message-lineHeight);\n /* stylelint-disable-next-line primer/colors */\n color: var(--inline-message-fgColor);\n column-gap: 0.5rem;\n grid-template-columns: auto 1fr;\n align-items: start;\n\n &[data-size='small'] {\n --inline-message-fontSize: var(--text-body-size-small);\n --inline-message-lineHeight: var(--text-body-lineHeight-small, 1.6666);\n }\n\n &[data-size='medium'] {\n --inline-message-fontSize: var(--text-body-size-medium);\n --inline-message-lineHeight: var(--text-body-lineHeight-medium, 1.4285);\n }\n\n &[data-variant='warning'] {\n --inline-message-fgColor: var(--fgColor-attention);\n }\n\n &[data-variant='critical'] {\n --inline-message-fgColor: var(--fgColor-danger);\n }\n\n &[data-variant='success'] {\n --inline-message-fgColor: var(--fgColor-success);\n }\n\n &[data-variant='unavailable'] {\n --inline-message-fgColor: var(--fgColor-muted);\n }\n}\n\n.InlineMessageIcon {\n min-height: calc(var(--inline-message-lineHeight) * var(--inline-message-fontSize));\n}"]}
1
+ {"version":3,"sources":["inline_message.pcss"],"names":[],"mappings":"AAAA,eACE,YAAa,CAEb,wCAAyC,CAEzC,4CAA6C,CAE7C,mCAAoC,CACpC,gBAAkB,CAClB,8BAA+B,CAC/B,iBA2BF,CAzBE,gCACE,qDAAsD,CACtD,oEACF,CAEA,iCACE,sDAAuD,CACvD,qEACF,CAEA,qCACE,iDACF,CAEA,sCACE,8CACF,CAEA,qCACE,+CACF,CAEA,yCACE,6CACF,CAGF,mBACE,gFACF","file":"inline_message.css","sourcesContent":[".InlineMessage {\n display: grid;\n /* stylelint-disable-next-line primer/typography */\n font-size: var(--inline-message-fontSize);\n /* stylelint-disable-next-line primer/typography */\n line-height: var(--inline-message-lineHeight);\n /* stylelint-disable-next-line primer/colors */\n color: var(--inline-message-fgColor);\n column-gap: 0.5rem;\n grid-template-columns: auto 1fr;\n align-items: start;\n\n &[data-size='small'] {\n --inline-message-fontSize: var(--text-body-size-small);\n --inline-message-lineHeight: var(--text-body-lineHeight-small, 1.6666);\n }\n\n &[data-size='medium'] {\n --inline-message-fontSize: var(--text-body-size-medium);\n --inline-message-lineHeight: var(--text-body-lineHeight-medium, 1.4285);\n }\n\n &[data-variant='warning'] {\n --inline-message-fgColor: var(--fgColor-attention);\n }\n\n &[data-variant='critical'] {\n --inline-message-fgColor: var(--fgColor-danger);\n }\n\n &[data-variant='success'] {\n --inline-message-fgColor: var(--fgColor-success);\n }\n\n &[data-variant='unavailable'] {\n --inline-message-fgColor: var(--fgColor-muted);\n }\n}\n\n.InlineMessageIcon {\n min-height: calc(var(--inline-message-lineHeight) * var(--inline-message-fontSize));\n}"]}
@@ -19,7 +19,7 @@ module Primer
19
19
  end
20
20
  end
21
21
 
22
- def render_in(view_context, &block)
22
+ def render_in(view_context, **_kwargs, &block)
23
23
  super(view_context) do
24
24
  block&.call(@dialog, @button)
25
25
  end
@@ -19,7 +19,7 @@ module Primer
19
19
  end
20
20
  end
21
21
 
22
- def render_in(view_context, &block)
22
+ def render_in(view_context, **_kwargs, &block)
23
23
  super(view_context) do
24
24
  block&.call(@menu, @button)
25
25
  end
@@ -1 +1 @@
1
- .PageHeader{border-bottom:var(--borderWidth-thin) solid var(--borderColor-muted);display:flex;flex-flow:column;margin-bottom:var(--base-size-16);padding-bottom:var(--base-size-8)}.PageHeader--withTabNav{border-bottom:none;margin-bottom:0;padding-bottom:0}.PageHeader-contextBar{height:var(--control-small-size)}.PageHeader-contextBar,.PageHeader-titleBar{align-items:center;display:flex;flex-flow:row;justify-content:flex-end;margin-bottom:var(--base-size-8)}.PageHeader-title{flex:1 1 auto;font-size:var(--text-title-size-medium)}.PageHeader-title--large{font-size:var(--text-title-size-large)}.PageHeader-description{color:var(--fgColor-muted);flex:1 auto;font-size:var(--text-body-size-medium)}.PageHeader-description--underlined-links a{-webkit-text-decoration:underline;text-decoration:underline}.PageHeader-tabNavBar{overflow:auto}.PageHeader-tabNavBar .PageHeader-tabNav{min-width:max-content}.PageHeader--withTabNav .PageHeader-description{margin-bottom:var(--base-size-16)}.PageHeader-actions{align-items:center;display:flex;justify-content:flex-end}.PageHeader-breadcrumbs{display:block;width:100%}.PageHeader-leadingAction{margin-right:var(--base-size-4);margin-top:var(--base-size-2)}.PageHeader-parentLink{flex:1 1 auto}@media screen and (min-width:543.98px){.PageHeader--noBreadcrumb .PageHeader-contextBar{display:none}}.PageHeader--noBreadcrumb .PageHeader-titleBar{line-height:var(--control-small-size)}.PageHeader--noBreadcrumb .PageHeader-actions{height:var(--control-small-size)}
1
+ .PageHeader{display:flex;padding-bottom:var(--base-size-8);margin-bottom:var(--base-size-16);border-bottom:var(--borderWidth-thin) solid var(--borderColor-muted);flex-flow:column}.PageHeader--withTabNav{border-bottom:none;padding-bottom:0;margin-bottom:0}.PageHeader-contextBar{height:var(--control-small-size)}.PageHeader-contextBar,.PageHeader-titleBar{display:flex;flex-flow:row;justify-content:flex-end;align-items:center;margin-bottom:var(--base-size-8)}.PageHeader-title{font-size:var(--text-title-size-medium);flex:1 1 auto}.PageHeader-title--large{font-size:var(--text-title-size-large)}.PageHeader-description{font-size:var(--text-body-size-medium);color:var(--fgColor-muted);flex:1 auto}.PageHeader-description--underlined-links a{-webkit-text-decoration:underline;text-decoration:underline}.PageHeader-tabNavBar{overflow:auto}.PageHeader-tabNavBar .PageHeader-tabNav{min-width:max-content}.PageHeader--withTabNav .PageHeader-description{margin-bottom:var(--base-size-16)}.PageHeader-actions{justify-content:flex-end;display:flex;align-items:center}.PageHeader-breadcrumbs{display:block;width:100%}.PageHeader-leadingAction{margin-top:var(--base-size-2);margin-right:var(--base-size-4)}.PageHeader-parentLink{flex:1 1 auto}@media screen and (min-width:543.98px){.PageHeader--noBreadcrumb .PageHeader-contextBar{display:none}}.PageHeader--noBreadcrumb .PageHeader-titleBar{line-height:var(--control-small-size)}.PageHeader--noBreadcrumb .PageHeader-actions{height:var(--control-small-size)}
@@ -1 +1 @@
1
- {"version":3,"sources":["page_header.pcss"],"names":[],"mappings":"AAEA,YAIE,oEAAqE,CAHrE,YAAa,CAIb,gBAAiB,CAFjB,iCAAkC,CADlC,iCAIF,CAEA,wBACE,kBAAmB,CAEnB,eAAgB,CADhB,gBAEF,CAEA,uBAME,gCACF,CAEA,4CALE,kBAAmB,CAHnB,YAAa,CACb,aAAc,CACd,wBAAyB,CAEzB,gCAUF,CAEA,kBAEE,aAAc,CADd,uCAEF,CAEA,yBACE,sCACF,CAGA,wBAEE,0BAA2B,CAC3B,WAAY,CAFZ,sCAGF,CAEA,4CAEE,iCAA0B,CAA1B,yBACF,CAEA,sBACE,aACF,CAEA,yCACE,qBACF,CAEA,gDACE,iCACF,CAEA,oBAGE,kBAAmB,CADnB,YAAa,CADb,wBAGF,CAEA,wBACE,aAAc,CACd,UACF,CAEA,0BAEE,+BAAgC,CADhC,6BAEF,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,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 +1 @@
1
- .Page{align-items:center;border-radius:var(--borderRadius-medium,.375rem);color:var(--fgColor-default);cursor:pointer;display:inline-flex;height:var(--base-size-32);justify-content:center;margin-right:var(--base-size-4);min-width:var(--base-size-32);padding:var(--base-size-8) var(--base-size-6);transition:background-color .2s cubic-bezier(.3,0,.5,1);vertical-align:middle;white-space:nowrap}.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{background-color:var(--control-transparent-bgColor-hover);outline:0;-webkit-text-decoration:none;text-decoration:none;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{background-color:var(--bgColor-accent-emphasis);border-color:#0000;color:var(--fgColor-onEmphasis)}.Page[aria-current]:focus-visible{box-shadow:inset 0 0 0 var(--base-size-2) var(--fgColor-onEmphasis);outline:2px solid var(--bgColor-accent-emphasis)}.Page[aria-hidden],.Page[aria-hidden]:hover,.Page[role=presentation],.Page[role=presentation]:hover{background-color:initial;color:var(--fgColor-disabled);cursor:default}.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,.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 +1 @@
1
- {"version":3,"sources":["pagination.pcss"],"names":[],"mappings":"AAAA,MAYE,kBAAmB,CAHnB,gDAAiD,CAJjD,4BAA6B,CAG7B,cAAe,CAGf,mBAAoB,CATpB,0BAA2B,CAW3B,sBAAuB,CATvB,+BAAgC,CAHhC,6BAA8B,CAE9B,6CAA8C,CAO9C,uDAA8D,CAH9D,qBAAsB,CADtB,kBAQF,CAEA,wCAEE,0BAA2B,CAC3B,yBACF,CAEA,oBACE,oCACF,CAEA,oBACE,sCACF,CAEA,iBACE,cACF,CAEA,wBAGE,yDAA0D,CAC1D,SAAU,CAFV,4BAAqB,CAArB,oBAAqB,CAGrB,uBACF,CAEA,oBACE,gDACF,CAEA,aACE,qCACF,CAEA,gCAEE,2BACF,CAEA,8CAGE,+CAAgD,CAChD,kBAAyB,CAFzB,+BAGF,CAEA,kCAEE,mEAAoE,CADpE,gDAEF,CAEA,oGAME,wBAA6B,CAF7B,6BAA8B,CAC9B,cAEF,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":"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 +1 @@
1
- .SidePanel-sectionHeader{align-items:center;display:flex;height:32px;margin-bottom:8px}.SidePanel-sectionCounter{margin-left:8px}.SidePanel-sectionAction{display:flex;flex:1;justify-content:right}.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: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 +1 @@
1
- {"version":3,"sources":["section.pcss"],"names":[],"mappings":"AAEA,yBAEE,kBAAmB,CADnB,YAAa,CAEb,WAAY,CACZ,iBACF,CAEA,0BACE,eACF,CAEA,yBAGE,YAAa,CADb,MAAO,CADP,qBAGF,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,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 +1 @@
1
- .SubHeader{align-items:baseline;display:grid;grid-template-areas:"left middle right" "bottom bottom bottom";grid-template-columns:auto 1fr auto;margin-bottom:var(--base-size-16)}.SubHeader-rightPane{align-items:center;column-gap:12px;display:flex;grid-area:right}.SubHeader-middlePane{grid-area:middle;text-align:center;white-space:nowrap}.SubHeader-bottomPane{grid-area:bottom}.SubHeader-leftPane{align-items:center;display:flex;flex-wrap:wrap;grid-area:left;row-gap:var(--base-size-16);width:100%}:is(.SubHeader-leftPane [class*=FormControl-input-width--]):not(.FormControl-input-width--auto){width:100vw}.SubHeader-filterContainer{display:flex;flex-basis:max-content;gap:8px;width:100%}.SubHeader-filterInput_hiddenClearButton+.FormControl-input-trailingAction{display:none}@media (max-width:767.98px){.SubHeader{grid-template-areas:"left right" "middle middle" "bottom bottom";grid-template-columns:1fr auto}.SubHeader--expandedSearch{grid-template-areas:"left left" "middle middle" "bottom bottom"}.SubHeader--expandedSearch .SubHeader-hiddenOnExpand{display:none!important}.SubHeader--emptyLeftPane{grid-template-areas:"middle middle right" "bottom bottom bottom";grid-template-columns:auto 1fr auto}.SubHeader--emptyLeftPane .SubHeader-middlePane{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.SubHeader-middlePane{text-align:left}.SubHeader-middlePane:has(>*){margin-top:var(--base-size-16)}}
1
+ .SubHeader{display:grid;grid-template-areas:"left middle right" "bottom bottom bottom";grid-template-columns:auto 1fr auto;align-items:baseline;margin-bottom:var(--base-size-16)}.SubHeader-rightPane{grid-area:right;display:flex;align-items:center;column-gap:12px}.SubHeader-middlePane{grid-area:middle;text-align:center;white-space:nowrap}.SubHeader-bottomPane{grid-area:bottom}.SubHeader-leftPane{grid-area:left;display:flex;align-items:center;flex-wrap:wrap;row-gap:var(--base-size-16);width:100%}:is(.SubHeader-leftPane [class*=FormControl-input-width--]):not(.FormControl-input-width--auto){width:100vw}.SubHeader-filterContainer{display:flex;flex-basis:max-content;width:100%;gap:8px}.SubHeader-filterInput_hiddenClearButton+.FormControl-input-trailingAction{display:none}@media (max-width:767.98px){.SubHeader{grid-template-areas:"left right" "middle middle" "bottom bottom";grid-template-columns:1fr auto}.SubHeader--expandedSearch{grid-template-areas:"left left" "middle middle" "bottom bottom"}.SubHeader--expandedSearch .SubHeader-hiddenOnExpand{display:none!important}.SubHeader--emptyLeftPane{grid-template-areas:"middle middle right" "bottom bottom bottom";grid-template-columns:auto 1fr auto}.SubHeader--emptyLeftPane .SubHeader-middlePane{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.SubHeader-middlePane{text-align:left}.SubHeader-middlePane:has(>*){margin-top:var(--base-size-16)}}
@@ -1 +1 @@
1
- {"version":3,"sources":["sub_header.pcss"],"names":[],"mappings":"AAEA,WAII,oBAAqB,CAHrB,YAAa,CACb,8DAA+D,CAC/D,mCAAoC,CAEpC,iCACJ,CAEA,qBAGI,kBAAmB,CACnB,eAAgB,CAFhB,YAAa,CADb,eAIJ,CAEA,sBACI,gBAAiB,CACjB,iBAAkB,CAClB,kBACJ,CAEA,sBACI,gBACJ,CAEA,oBAGI,kBAAmB,CADnB,YAAa,CAEb,cAAe,CAHf,cAAe,CAIf,2BAA4B,CAC5B,UASJ,CAJQ,gGACI,WACJ,CAIR,2BACI,YAAa,CACb,sBAAuB,CAEvB,OAAQ,CADR,UAEJ,CAEA,2EACE,YACF,CAEA,4BACI,WACI,gEAAiE,CACjE,8BACJ,CAEA,2BACI,+DACJ,CAEA,qDACI,sBACJ,CAEA,0BACI,gEAAiE,CACjE,mCACJ,CAEA,gDAGI,eAAgB,CADhB,sBAAuB,CADvB,kBAGJ,CAEA,sBACI,eACJ,CAEA,8BACI,8BACJ,CACJ","file":"sub_header.css","sourcesContent":["/* CSS for SubHeader */\n\n.SubHeader {\n display: grid;\n grid-template-areas: \"left middle right\" \"bottom bottom bottom\";\n grid-template-columns: auto 1fr auto;\n align-items: baseline;\n margin-bottom: var(--base-size-16);\n}\n\n.SubHeader-rightPane {\n grid-area: right;\n display: flex;\n align-items: center;\n column-gap: 12px;\n}\n\n.SubHeader-middlePane {\n grid-area: middle;\n text-align: center;\n white-space: nowrap;\n}\n\n.SubHeader-bottomPane {\n grid-area: bottom;\n}\n\n.SubHeader-leftPane {\n grid-area: left;\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n row-gap: var(--base-size-16);\n width: 100%;\n\n /* Since the container is not full width (due to the grid around it)\n we want it to grow, and then be limited by the max-width of the \"FormControl-input-width--xy\" class */\n & [class*='FormControl-input-width--'] {\n &:not(.FormControl-input-width--auto) {\n width: 100vw;\n }\n }\n}\n\n.SubHeader-filterContainer {\n display: flex;\n flex-basis: max-content;\n width: 100%;\n gap: 8px;\n}\n\n.SubHeader-filterInput_hiddenClearButton + .FormControl-input-trailingAction {\n display: none;\n}\n\n@media (max-width: 767.98px) {\n .SubHeader {\n grid-template-areas: \"left right\" \"middle middle\" \"bottom bottom\";\n grid-template-columns: 1fr auto;\n }\n\n .SubHeader--expandedSearch {\n grid-template-areas: \"left left\" \"middle middle\" \"bottom bottom\";\n }\n\n .SubHeader--expandedSearch .SubHeader-hiddenOnExpand {\n display: none !important;\n }\n\n .SubHeader--emptyLeftPane {\n grid-template-areas: \"middle middle right\" \"bottom bottom bottom\";\n grid-template-columns: auto 1fr auto;\n }\n\n .SubHeader--emptyLeftPane .SubHeader-middlePane {\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n }\n\n .SubHeader-middlePane {\n text-align: left;\n }\n\n .SubHeader-middlePane:has(> *) {\n margin-top: var(--base-size-16);\n }\n}\n"]}
1
+ {"version":3,"sources":["sub_header.pcss"],"names":[],"mappings":"AAEA,WACI,YAAa,CACb,8DAA+D,CAC/D,mCAAoC,CACpC,oBAAqB,CACrB,iCACJ,CAEA,qBACI,eAAgB,CAChB,YAAa,CACb,kBAAmB,CACnB,eACJ,CAEA,sBACI,gBAAiB,CACjB,iBAAkB,CAClB,kBACJ,CAEA,sBACI,gBACJ,CAEA,oBACI,cAAe,CACf,YAAa,CACb,kBAAmB,CACnB,cAAe,CACf,2BAA4B,CAC5B,UASJ,CAJQ,gGACI,WACJ,CAIR,2BACI,YAAa,CACb,sBAAuB,CACvB,UAAW,CACX,OACJ,CAEA,2EACE,YACF,CAEA,4BACI,WACI,gEAAiE,CACjE,8BACJ,CAEA,2BACI,+DACJ,CAEA,qDACI,sBACJ,CAEA,0BACI,gEAAiE,CACjE,mCACJ,CAEA,gDACI,kBAAmB,CACnB,sBAAuB,CACvB,eACJ,CAEA,sBACI,eACJ,CAEA,8BACI,8BACJ,CACJ","file":"sub_header.css","sourcesContent":["/* CSS for SubHeader */\n\n.SubHeader {\n display: grid;\n grid-template-areas: \"left middle right\" \"bottom bottom bottom\";\n grid-template-columns: auto 1fr auto;\n align-items: baseline;\n margin-bottom: var(--base-size-16);\n}\n\n.SubHeader-rightPane {\n grid-area: right;\n display: flex;\n align-items: center;\n column-gap: 12px;\n}\n\n.SubHeader-middlePane {\n grid-area: middle;\n text-align: center;\n white-space: nowrap;\n}\n\n.SubHeader-bottomPane {\n grid-area: bottom;\n}\n\n.SubHeader-leftPane {\n grid-area: left;\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n row-gap: var(--base-size-16);\n width: 100%;\n\n /* Since the container is not full width (due to the grid around it)\n we want it to grow, and then be limited by the max-width of the \"FormControl-input-width--xy\" class */\n & [class*='FormControl-input-width--'] {\n &:not(.FormControl-input-width--auto) {\n width: 100vw;\n }\n }\n}\n\n.SubHeader-filterContainer {\n display: flex;\n flex-basis: max-content;\n width: 100%;\n gap: 8px;\n}\n\n.SubHeader-filterInput_hiddenClearButton + .FormControl-input-trailingAction {\n display: none;\n}\n\n@media (max-width: 767.98px) {\n .SubHeader {\n grid-template-areas: \"left right\" \"middle middle\" \"bottom bottom\";\n grid-template-columns: 1fr auto;\n }\n\n .SubHeader--expandedSearch {\n grid-template-areas: \"left left\" \"middle middle\" \"bottom bottom\";\n }\n\n .SubHeader--expandedSearch .SubHeader-hiddenOnExpand {\n display: none !important;\n }\n\n .SubHeader--emptyLeftPane {\n grid-template-areas: \"middle middle right\" \"bottom bottom bottom\";\n grid-template-columns: auto 1fr auto;\n }\n\n .SubHeader--emptyLeftPane .SubHeader-middlePane {\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n }\n\n .SubHeader-middlePane {\n text-align: left;\n }\n\n .SubHeader-middlePane:has(> *) {\n margin-top: var(--base-size-16);\n }\n}\n"]}
@@ -10,7 +10,7 @@ module Primer
10
10
  module InstanceMethods
11
11
  delegate :render, :content_tag, :output_buffer, :capture, to: :@view_context
12
12
 
13
- def render_in(view_context, &block)
13
+ def render_in(view_context, **_kwargs, &block)
14
14
  @view_context = view_context
15
15
  before_render
16
16
  perform_render(&block)
@@ -69,7 +69,7 @@ module Primer
69
69
  # assumes the presence of a builder so we create our own here. A builder
70
70
  # cannot be constructed without a corresponding view context, which is why
71
71
  # we have to override render_in and can't create it in the initializer.
72
- def render_in(view_context, &block)
72
+ def render_in(view_context, **_kwargs, &block)
73
73
  @builder = Primer::Forms::Builder.new(
74
74
  nil, nil, view_context, {}
75
75
  )
@@ -16,7 +16,7 @@ module Primer
16
16
  @system_arguments = system_arguments
17
17
  end
18
18
 
19
- def render_in(view_context, &block)
19
+ def render_in(view_context, **_kwargs, &block)
20
20
  builder = Primer::Forms::Builder.new(
21
21
  nil, nil, view_context, {}
22
22
  )
@@ -6,7 +6,7 @@ module Primer
6
6
  module VERSION
7
7
  MAJOR = 0
8
8
  MINOR = 89
9
- PATCH = 1
9
+ PATCH = 2
10
10
 
11
11
  STRING = [MAJOR, MINOR, PATCH].join(".")
12
12
  end
@@ -6,11 +6,11 @@ module Primer
6
6
  class BorderBoxPreview < ViewComponent::Preview
7
7
  # @label Playground
8
8
  #
9
+ # @param list_id text
9
10
  # @param padding [Symbol] select [default, condensed, spacious]
10
11
  # @param scheme [Symbol] select [default, neutral, info, warning]
11
- # @param list_id [String] text
12
- def playground(padding: :default, scheme: :default, list_id: nil)
13
- render(Primer::Beta::BorderBox.new(padding: padding, list_id: list_id)) do |component|
12
+ def playground(padding: :default, scheme: :default, list_id: "my-list")
13
+ render(Primer::Beta::BorderBox.new(padding: padding, list_arguments: { id: list_id })) do |component|
14
14
  component.with_header { "Header" }
15
15
  component.with_body { "Body" }
16
16
  component.with_row(scheme: scheme) { "#{scheme.to_s.capitalize} row one" }
@@ -0,0 +1,9 @@
1
+ <%= render(Primer::OpenProject::FilterableTreeView.new(
2
+ src: primer_view_components.filterable_tree_view_items_tree_path(select_variant: :single)
3
+ )) do |tree_view| %>
4
+ <% tree_view.with_loading_indicator do %>
5
+ <%= render(Primer::Alpha::Stack.new(align: :center, p: 3)) do %>
6
+ <%= render(Primer::Beta::Spinner.new) %>
7
+ <% end %>
8
+ <% end %>
9
+ <% end %>
@@ -123,6 +123,13 @@ module Primer
123
123
  })
124
124
  end
125
125
 
126
+ # @label Async (with custom loading indicator)
127
+ #
128
+ # Demonstrates replacing the default skeleton loader with arbitrary content.
129
+ def async_custom_loading_indicator
130
+ render_with_template
131
+ end
132
+
126
133
  # @label Async (with server-side highlighting)
127
134
  #
128
135
  # Demonstrates `show_search_highlighting: false`: the client skips its own highlight logic
@@ -4250,6 +4250,18 @@
4250
4250
  "default": "`:default`",
4251
4251
  "description": "One of `:condensed`, `:default`, or `:spacious`."
4252
4252
  },
4253
+ {
4254
+ "name": "list_arguments",
4255
+ "type": "Hash",
4256
+ "default": "`{}`",
4257
+ "description": "[System arguments](/system-arguments)"
4258
+ },
4259
+ {
4260
+ "name": "list_id",
4261
+ "type": "String",
4262
+ "default": "N/A",
4263
+ "description": "Deprecated. Use <code>list_arguments: { id: ... }</code> instead."
4264
+ },
4253
4265
  {
4254
4266
  "name": "system_arguments",
4255
4267
  "type": "Hash",
@@ -13509,6 +13509,18 @@
13509
13509
  "default": "`:default`",
13510
13510
  "description": "One of `:condensed`, `:default`, or `:spacious`."
13511
13511
  },
13512
+ {
13513
+ "name": "list_arguments",
13514
+ "type": "Hash",
13515
+ "default": "`{}`",
13516
+ "description": "{{link_to_system_arguments_docs}}"
13517
+ },
13518
+ {
13519
+ "name": "list_id",
13520
+ "type": "String",
13521
+ "default": "N/A",
13522
+ "description": "Deprecated. Use <code>list_arguments: { id: ... }</code> instead."
13523
+ },
13512
13524
  {
13513
13525
  "name": "system_arguments",
13514
13526
  "type": "Hash",
@@ -20363,7 +20375,7 @@
20363
20375
  },
20364
20376
  {
20365
20377
  "fully_qualified_name": "Primer::OpenProject::FilterableTreeView",
20366
- "description": "A TreeView and associated filter controls for searching nested hierarchies.\n\n## Filter controls\n\n`FilterableTreeView`s can be filtered using two controls, both present in the toolbar above the tree:\n\n1. A free-form query string from a text input field.\n2. A `SegmentedControl` with two options (by default):\n 1. The \"Selected\" option causes the component to only show checked nodes, provided they also satisfy the other\n filter criteria described here.\n 2. The \"All\" option causes the component to show all nodes, provided they also satisfy the other filter\n criteria described here.\n\n## Custom filter modes\n\nIn addition to the default filter modes of `'all'` and `'selected'` described above, `FilterableTreeView` supports\nadding custom filter modes. Adding a filter mode will cause its label to appear in the `SegmentedControl` in the\ntoolbar, and will be passed as the third argument to the filter function (see below).\n\nHere's how to add a custom filter mode in addition to the default ones:\n\n```erb\n<%= render(Primer::OpenProject::FilterableTreeView.new) do |tree_view| %>\n <%# remove this line to prevent adding the default modes %>\n <% tree_view.with_default_filter_modes %>\n <% tree_view.with_filter_mode(name: \"Custom\", system_arguments)\n<% end %>\n```\n\n## Filter behavior\n\nBy default, matching node text is identified by looking for an exact substring match, operating on a lowercased\nversion of both the query string and the node text. For more information, and to provide a customized filter\nfunction, please see the section titled \"Customizing the filter function\" below.\n\nNodes that match the filter appear as normal; nodes that do not match are presented as follows:\n\n1. Leaf nodes are hidden.\n2. Sub-tree nodes with no matching children are hidden.\n3. Sub-tree nodes with at least one matching child are disabled but still visible.\n\n## Checking behavior\n\nBy default, checking a node in a `FilterableTreeView` checks only that node (i.e. no child nodes are checked).\nTo aide in checking children in deeply nested or highly populated hierarchies, a third control exists in the\ntoolbar: the \"Include sub-items\" check box. If this feature is turned on, checking sub-tree nodes causes all\nchildren, both leaf and sub-tree nodes, to also be checked recursively. Moreover, turning this feature on will\ncause the children of any previously checked nodes to be checked recursively. Unchecking a node while in\n\"Include sub-items\" mode will restore that sub-tree and all its children to their previously checked state, so as\nnot to permanently override a user's selections. Unchecking the \"Include sub-items\" check box has a similar effect,\ni.e. restores all previous user selections under currently checked sub-trees.\n\n## JavaScript API\n\n`FilterableTreeView` does not yet have an extensive JavaScript API, but this may change in the future as the\ncomponent is further developed to fit additional use-cases.\n\n### Customizing the filter function\n\nThe filter function can be customized by setting the value of the `filterFn` property to a function with the\nfollowing signature:\n\n```typescript\nexport type FilterFn = (node: HTMLElement, query: string, filterMode?: string) => Range[] | null\n```\n\nThis function will be called once for each node in the tree every time filter controls change (i.e. when the\nfilter mode or query string are altered). The function is called with the following arguments:\n\n|Argument |Description |\n|:-----------|:----------------------------------------------------------------|\n|`node` |The HTML node element, i.e. the element with `role=treeitem` set.|\n|`query` |The query string. |\n|`filterMode`|The filter mode, either `'all'` or `'selected'`. |\n\nThe component expects the filter function to return specific values depending on the type of match:\n\n1. No match - return `null`\n2. Match but no highlights (eg. when the query string is empty) - return an empty array\n3. Match with highlights - return a non-empty array of `Range` objects\n\nExample:\n\n```javascript\nconst filterableTreeView = document.querySelector('filterable-tree-view')\nfilterableTreeView.filterFn = (node, query, filterMode) => {\n // custom filter implementation here\n}\n```\n\nYou can read about `Range` objects here: https://developer.mozilla.org/en-US/docs/Web/API/Range.\n\nFor a complete example demonstrating how to implement a working filter function complete with range highlighting,\nsee the default filter function available in the `FilterableTreeViewElement` JavaScript class, which is part of\nthe Primer source code.\n\n### Events\n\nCurrently `FilterableTreeView` does not emit any events aside from the events already emitted by the `TreeView`\ncomponent.\n\n## Async loading strategy\n\nWhen `src` is set on the component, all filter interactions (text input, filter mode changes) trigger a debounced\nserver request instead of client-side filtering. The server is responsible for returning a filtered `<tree-view>`\nHTML fragment that replaces the current tree.\n\n### Behavior\n\n- The full tree is loaded initially from the server via `src`.\n- Each filter input event triggers a debounced (300 ms) request to the server.\n- The server returns a filtered `<tree-view>` element which replaces the existing one.\n- All matching results and their full ancestor hierarchy are expanded automatically.\n- Matching text is highlighted using the CSS Custom Highlight API (or `<mark>` fallback).\n- When the filter is cleared, the tree is replaced with the full (unfiltered) result from\n the server and the expansion state from before the search is restored.\n- Checked nodes are preserved across tree replacements using `data-node-id` attributes.\n- When \"include sub-items\" is active and the tree is filtered, clicking a parent node\n selects ALL its descendants (not just the visible filtered ones). Therefore, \"include_sub_items\" is passed\n to the server, since it holds the only truth about the data.\n\n### Server endpoint\n\nThe server endpoint must return a `<tree-view>` HTML fragment. Each node must have a stable\n`data-node-id` on its `[role=treeitem]` element.\n\n### Usage\n\n```erb\n<%= render(Primer::OpenProject::FilterableTreeView.new(\n src: my_path\n)) %>\n```",
20378
+ "description": "A TreeView and associated filter controls for searching nested hierarchies.\n\n## Filter controls\n\n`FilterableTreeView`s can be filtered using two controls, both present in the toolbar above the tree:\n\n1. A free-form query string from a text input field.\n2. A `SegmentedControl` with two options (by default):\n 1. The \"Selected\" option causes the component to only show checked nodes, provided they also satisfy the other\n filter criteria described here.\n 2. The \"All\" option causes the component to show all nodes, provided they also satisfy the other filter\n criteria described here.\n\n## Custom filter modes\n\nIn addition to the default filter modes of `'all'` and `'selected'` described above, `FilterableTreeView` supports\nadding custom filter modes. Adding a filter mode will cause its label to appear in the `SegmentedControl` in the\ntoolbar, and will be passed as the third argument to the filter function (see below).\n\nHere's how to add a custom filter mode in addition to the default ones:\n\n```erb\n<%= render(Primer::OpenProject::FilterableTreeView.new) do |tree_view| %>\n <%# remove this line to prevent adding the default modes %>\n <% tree_view.with_default_filter_modes %>\n <% tree_view.with_filter_mode(name: \"Custom\", system_arguments)\n<% end %>\n```\n\n## Filter behavior\n\nBy default, matching node text is identified by looking for an exact substring match, operating on a lowercased\nversion of both the query string and the node text. For more information, and to provide a customized filter\nfunction, please see the section titled \"Customizing the filter function\" below.\n\nNodes that match the filter appear as normal; nodes that do not match are presented as follows:\n\n1. Leaf nodes are hidden.\n2. Sub-tree nodes with no matching children are hidden.\n3. Sub-tree nodes with at least one matching child are disabled but still visible.\n\n## Checking behavior\n\nBy default, checking a node in a `FilterableTreeView` checks only that node (i.e. no child nodes are checked).\nTo aide in checking children in deeply nested or highly populated hierarchies, a third control exists in the\ntoolbar: the \"Include sub-items\" check box. If this feature is turned on, checking sub-tree nodes causes all\nchildren, both leaf and sub-tree nodes, to also be checked recursively. Moreover, turning this feature on will\ncause the children of any previously checked nodes to be checked recursively. Unchecking a node while in\n\"Include sub-items\" mode will restore that sub-tree and all its children to their previously checked state, so as\nnot to permanently override a user's selections. Unchecking the \"Include sub-items\" check box has a similar effect,\ni.e. restores all previous user selections under currently checked sub-trees.\n\n## JavaScript API\n\n`FilterableTreeView` does not yet have an extensive JavaScript API, but this may change in the future as the\ncomponent is further developed to fit additional use-cases.\n\n### Customizing the filter function\n\nThe filter function can be customized by setting the value of the `filterFn` property to a function with the\nfollowing signature:\n\n```typescript\nexport type FilterFn = (node: HTMLElement, query: string, filterMode?: string) => Range[] | null\n```\n\nThis function will be called once for each node in the tree every time filter controls change (i.e. when the\nfilter mode or query string are altered). The function is called with the following arguments:\n\n|Argument |Description |\n|:-----------|:----------------------------------------------------------------|\n|`node` |The HTML node element, i.e. the element with `role=treeitem` set.|\n|`query` |The query string. |\n|`filterMode`|The filter mode, either `'all'` or `'selected'`. |\n\nThe component expects the filter function to return specific values depending on the type of match:\n\n1. No match - return `null`\n2. Match but no highlights (eg. when the query string is empty) - return an empty array\n3. Match with highlights - return a non-empty array of `Range` objects\n\nExample:\n\n```javascript\nconst filterableTreeView = document.querySelector('filterable-tree-view')\nfilterableTreeView.filterFn = (node, query, filterMode) => {\n // custom filter implementation here\n}\n```\n\nYou can read about `Range` objects here: https://developer.mozilla.org/en-US/docs/Web/API/Range.\n\nFor a complete example demonstrating how to implement a working filter function complete with range highlighting,\nsee the default filter function available in the `FilterableTreeViewElement` JavaScript class, which is part of\nthe Primer source code.\n\n### Events\n\nCurrently `FilterableTreeView` does not emit any events aside from the events already emitted by the `TreeView`\ncomponent.\n\n## Async loading strategy\n\nWhen `src` is set on the component, all filter interactions (text input, filter mode changes) trigger a debounced\nserver request instead of client-side filtering. The server is responsible for returning a filtered `<tree-view>`\nHTML fragment that replaces the current tree.\n\n### Behavior\n\n- The full tree is loaded initially from the server via `src`.\n- Each filter input event triggers a debounced (300 ms) request to the server.\n- The server returns a filtered `<tree-view>` element which replaces the existing one.\n- All matching results and their full ancestor hierarchy are expanded automatically.\n- Matching text is highlighted using the CSS Custom Highlight API (or `<mark>` fallback).\n- When the filter is cleared, the tree is replaced with the full (unfiltered) result from\n the server and the expansion state from before the search is restored.\n- Checked nodes are preserved across tree replacements using `data-node-id` attributes.\n- When \"include sub-items\" is active and the tree is filtered, clicking a parent node\n selects ALL its descendants (not just the visible filtered ones). Therefore, \"include_sub_items\" is passed\n to the server, since it holds the only truth about the data.\n\n### Server endpoint\n\nThe server endpoint must return a `<tree-view>` HTML fragment. Each node must have a stable\n`data-node-id` on its `[role=treeitem]` element.\n\n### Usage\n\n```erb\n<%= render(Primer::OpenProject::FilterableTreeView.new(\n src: my_path\n)) do |tree_view| %>\n <% tree_view.with_loading_indicator do %>\n <%= render(Primer::Beta::Spinner.new) %>\n <% end %>\n<% end %>\n```",
20367
20379
  "accessibility_docs": null,
20368
20380
  "is_form_component": false,
20369
20381
  "is_published": true,
@@ -20424,7 +20436,13 @@
20424
20436
  "description": "Arguments that will be passed to a {{#link_to_component}}Primer::Alpha::TreeView::LeafNode{{/link_to_component}} component that appears when no items match the filter criteria."
20425
20437
  }
20426
20438
  ],
20427
- "slots": [],
20439
+ "slots": [
20440
+ {
20441
+ "name": "loading_indicator",
20442
+ "description": "An optional loading indicator shown while an async filter request is in progress. When omitted, a skeleton\nloader is rendered. This slot is only used when `src` is set.",
20443
+ "parameters": []
20444
+ }
20445
+ ],
20428
20446
  "methods": [],
20429
20447
  "previews": [
20430
20448
  {
@@ -20518,6 +20536,19 @@
20518
20536
  ]
20519
20537
  }
20520
20538
  },
20539
+ {
20540
+ "preview_path": "primer/open_project/filterable_tree_view/async_custom_loading_indicator",
20541
+ "name": "async_custom_loading_indicator",
20542
+ "snapshot": "false",
20543
+ "skip_rules": {
20544
+ "wont_fix": [
20545
+ "region"
20546
+ ],
20547
+ "will_fix": [
20548
+ "color-contrast"
20549
+ ]
20550
+ }
20551
+ },
20521
20552
  {
20522
20553
  "preview_path": "primer/open_project/filterable_tree_view/async_server_highlights",
20523
20554
  "name": "async_server_highlights",