openproject-primer_view_components 0.77.0 → 0.78.1

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.
@@ -38,6 +38,7 @@ export declare class TreeViewElement extends HTMLElement {
38
38
  changeSelectStrategy(newStrategy: SelectStrategy): void;
39
39
  infoFromNode(node: Element, newCheckedValue?: TreeViewCheckedValue): TreeViewNodeInfo | null;
40
40
  selectVariant(node: Element): SelectVariant;
41
+ updateHiddenFormInputs(): void;
41
42
  }
42
43
  declare global {
43
44
  interface Window {
@@ -56,28 +56,17 @@ let TreeViewElement = class TreeViewElement extends HTMLElement {
56
56
  });
57
57
  if (!somethingChanged)
58
58
  return;
59
- const newInputs = [];
60
- // eslint-disable-next-line custom-elements/no-dom-traversal-in-connectedcallback
61
- for (const node of this.querySelectorAll('[role=treeitem][aria-checked=true]')) {
62
- const newInput = this.formInputPrototype.cloneNode();
63
- newInput.removeAttribute('data-target');
64
- newInput.removeAttribute('form');
65
- const payload = {
66
- path: this.getNodePath(node),
67
- };
68
- const inputValue = this.getFormInputValueForNode(node);
69
- if (inputValue)
70
- payload.value = inputValue;
71
- newInput.value = JSON.stringify(payload);
72
- newInputs.push(newInput);
73
- }
74
- this.formInputContainer.replaceChildren(...newInputs);
59
+ this.updateHiddenFormInputs();
75
60
  });
76
61
  updateInputsObserver.observe(this, {
77
62
  childList: true,
78
63
  subtree: true,
79
64
  attributeFilter: ['aria-checked'],
80
65
  });
66
+ // Correctly initialize the form
67
+ if (this.formInputContainer) {
68
+ this.updateHiddenFormInputs();
69
+ }
81
70
  // eslint-disable-next-line github/no-then -- We don't want to wait for this to resolve, just get on with it
82
71
  customElements.whenDefined('tree-view-sub-tree-node').then(() => {
83
72
  // depends on TreeViewSubTreeNodeElement#eachAncestorSubTreeNode, which may not be defined yet
@@ -287,6 +276,24 @@ let TreeViewElement = class TreeViewElement extends HTMLElement {
287
276
  selectVariant(node) {
288
277
  return (node.getAttribute('data-select-variant') || 'none');
289
278
  }
279
+ updateHiddenFormInputs() {
280
+ const newInputs = [];
281
+ // eslint-disable-next-line custom-elements/no-dom-traversal-in-connectedcallback
282
+ for (const node of this.querySelectorAll('[role=treeitem][aria-checked=true]')) {
283
+ const newInput = this.formInputPrototype.cloneNode();
284
+ newInput.removeAttribute('data-target');
285
+ newInput.removeAttribute('form');
286
+ const payload = {
287
+ path: this.getNodePath(node),
288
+ };
289
+ const inputValue = this.getFormInputValueForNode(node);
290
+ if (inputValue)
291
+ payload.value = inputValue;
292
+ newInput.value = JSON.stringify(payload);
293
+ newInputs.push(newInput);
294
+ }
295
+ this.formInputContainer.replaceChildren(...newInputs);
296
+ }
290
297
  };
291
298
  _TreeViewElement_abortController = new WeakMap();
292
299
  _TreeViewElement_instances = new WeakSet();
@@ -45,26 +45,7 @@ export class TreeViewElement extends HTMLElement {
45
45
 
46
46
  if (!somethingChanged) return
47
47
 
48
- const newInputs = []
49
-
50
- // eslint-disable-next-line custom-elements/no-dom-traversal-in-connectedcallback
51
- for (const node of this.querySelectorAll('[role=treeitem][aria-checked=true]')) {
52
- const newInput = this.formInputPrototype.cloneNode() as HTMLInputElement
53
- newInput.removeAttribute('data-target')
54
- newInput.removeAttribute('form')
55
-
56
- const payload: {path: string[]; value?: string} = {
57
- path: this.getNodePath(node),
58
- }
59
-
60
- const inputValue = this.getFormInputValueForNode(node)
61
- if (inputValue) payload.value = inputValue
62
-
63
- newInput.value = JSON.stringify(payload)
64
- newInputs.push(newInput)
65
- }
66
-
67
- this.formInputContainer.replaceChildren(...newInputs)
48
+ this.updateHiddenFormInputs()
68
49
  })
69
50
 
70
51
  updateInputsObserver.observe(this, {
@@ -73,6 +54,11 @@ export class TreeViewElement extends HTMLElement {
73
54
  attributeFilter: ['aria-checked'],
74
55
  })
75
56
 
57
+ // Correctly initialize the form
58
+ if (this.formInputContainer) {
59
+ this.updateHiddenFormInputs()
60
+ }
61
+
76
62
  // eslint-disable-next-line github/no-then -- We don't want to wait for this to resolve, just get on with it
77
63
  customElements.whenDefined('tree-view-sub-tree-node').then(() => {
78
64
  // depends on TreeViewSubTreeNodeElement#eachAncestorSubTreeNode, which may not be defined yet
@@ -483,6 +469,29 @@ export class TreeViewElement extends HTMLElement {
483
469
  selectVariant(node: Element): SelectVariant {
484
470
  return (node.getAttribute('data-select-variant') || 'none') as SelectVariant
485
471
  }
472
+
473
+ updateHiddenFormInputs() {
474
+ const newInputs = []
475
+
476
+ // eslint-disable-next-line custom-elements/no-dom-traversal-in-connectedcallback
477
+ for (const node of this.querySelectorAll('[role=treeitem][aria-checked=true]')) {
478
+ const newInput = this.formInputPrototype.cloneNode() as HTMLInputElement
479
+ newInput.removeAttribute('data-target')
480
+ newInput.removeAttribute('form')
481
+
482
+ const payload: {path: string[]; value?: string} = {
483
+ path: this.getNodePath(node),
484
+ }
485
+
486
+ const inputValue = this.getFormInputValueForNode(node)
487
+ if (inputValue) payload.value = inputValue
488
+
489
+ newInput.value = JSON.stringify(payload)
490
+ newInputs.push(newInput)
491
+ }
492
+
493
+ this.formInputContainer.replaceChildren(...newInputs)
494
+ }
486
495
  }
487
496
 
488
497
  if (!window.customElements.get('tree-view')) {
@@ -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{height:var(--control-small-size)}
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)}
@@ -17,6 +17,7 @@
17
17
  ".PageHeader-leadingAction",
18
18
  ".PageHeader-parentLink",
19
19
  ".PageHeader--noBreadcrumb .PageHeader-contextBar",
20
- ".PageHeader--noBreadcrumb .PageHeader-titleBar"
20
+ ".PageHeader--noBreadcrumb .PageHeader-titleBar",
21
+ ".PageHeader--noBreadcrumb .PageHeader-actions"
21
22
  ]
22
23
  }
@@ -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,CAGA,+CACE,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 height with the toggle menu button for proper vertical alignment */\n.PageHeader--noBreadcrumb .PageHeader-titleBar {\n height: var(--control-small-size);\n}"]}
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}"]}
@@ -91,7 +91,13 @@
91
91
  }
92
92
  }
93
93
 
94
- /* Match the title bar height with the toggle menu button for proper vertical alignment */
95
- .PageHeader--noBreadcrumb .PageHeader-titleBar {
96
- height: var(--control-small-size);
94
+ /* Match the title bar and actions height with the toggle menu button for proper vertical alignment */
95
+ .PageHeader--noBreadcrumb {
96
+ & .PageHeader-titleBar {
97
+ line-height: var(--control-small-size);
98
+ }
99
+
100
+ & .PageHeader-actions {
101
+ height: var(--control-small-size);
102
+ }
97
103
  }
@@ -23,6 +23,7 @@ module Primer
23
23
  DEFAULT_LEADING_ACTION_DISPLAY = [:none, :flex].freeze
24
24
  DEFAULT_BREADCRUMBS_DISPLAY = [:none, :flex].freeze
25
25
  DEFAULT_PARENT_LINK_DISPLAY = [:block, :none].freeze
26
+ BREADCRUMB_TRUNCATE_AT = 200
26
27
 
27
28
  STATE_DEFAULT = :show
28
29
  STATE_EDIT = :edit
@@ -222,9 +223,17 @@ module Primer
222
223
  render(Primer::Beta::Breadcrumbs.new(**system_arguments)) do |breadcrumbs|
223
224
  items.each do |item|
224
225
  if item.is_a?(String)
225
- breadcrumbs.with_item(href: "#", font_weight: selected_item_font_weight) { item }
226
+ breadcrumbs.with_item(href: "#", font_weight: selected_item_font_weight) do
227
+ render(Primer::Beta::Truncate.new) do |truncate|
228
+ truncate.with_item(max_width: BREADCRUMB_TRUNCATE_AT) { item }
229
+ end
230
+ end
226
231
  else
227
- breadcrumbs.with_item(href: item[:href], target: "_top") { item[:text] }
232
+ breadcrumbs.with_item(href: item[:href], target: "_top") do
233
+ render(Primer::Beta::Truncate.new) do |truncate|
234
+ truncate.with_item(max_width: BREADCRUMB_TRUNCATE_AT) { item[:text] }
235
+ end
236
+ end
228
237
  end
229
238
  end
230
239
  end
@@ -5,8 +5,8 @@ module Primer
5
5
  module ViewComponents
6
6
  module VERSION
7
7
  MAJOR = 0
8
- MINOR = 77
9
- PATCH = 0
8
+ MINOR = 78
9
+ PATCH = 1
10
10
 
11
11
  STRING = [MAJOR, MINOR, PATCH].join(".")
12
12
  end
@@ -2,7 +2,7 @@
2
2
  <%= render(Primer::Alpha::Stack.new) do %>
3
3
  <%= render(Primer::Alpha::TreeView.new(form_arguments: { builder: f, name: "folder_structure" })) do |tree| %>
4
4
  <% tree.with_sub_tree(label: "src", expanded: expanded, select_variant: select_variant, value: 0) do |sub_tree| %>
5
- <% sub_tree.with_leaf(label: "button.rb", select_variant: select_variant, value: 1) %>
5
+ <% sub_tree.with_leaf(label: "button.rb", select_variant: select_variant, value: 1, checked: true) %>
6
6
  <% sub_tree.with_leaf(label: "icon_button.rb", current: true, select_variant: select_variant, value: 2) %>
7
7
  <% end %>
8
8
 
@@ -7,7 +7,7 @@
7
7
  <% end %>
8
8
 
9
9
  <% hogwarts.with_sub_tree(label: "Slytherin", select_variant: select_variant, expanded: expanded) do |hufflepuff| %>
10
- <% hufflepuff.with_leaf(label: "Draco Malfoy", select_variant: select_variant) %>
10
+ <% hufflepuff.with_leaf(label: "Draco Malfoy", select_variant: select_variant, checked: true) %>
11
11
  <% end %>
12
12
 
13
13
  <% hogwarts.with_sub_tree(label: "Hufflepuff", select_variant: select_variant, expanded: expanded) do |hufflepuff| %>
@@ -191,6 +191,19 @@ module Primer
191
191
  end
192
192
  end
193
193
 
194
+ # @label With truncated breadcrumbs
195
+ # Long breadcrumb elements are truncated after 200px
196
+ def truncated_breadcrumbs
197
+ breadcrumb_items = [{ href: "/foo", text: "OpenProject" },
198
+ { href: "/bar", text: "Stream Dream team" },
199
+ { href: "/baz", text: "A very long sub project that will be truncated" },
200
+ "Hello"]
201
+ render(Primer::OpenProject::PageHeader.new) do |header|
202
+ header.with_title { "A title" }
203
+ header.with_breadcrumbs(breadcrumb_items, selected_item_font_weight: :normal)
204
+ end
205
+ end
206
+
194
207
  # @label Without breadcrumbs
195
208
  # A PageHeader example that renders without breadcrumbs.
196
209
  # This should only be done for *entry pages* (such as overview pages).
@@ -1831,6 +1831,7 @@
1831
1831
  "chevron-left",
1832
1832
  "triangle-left"
1833
1833
  ],
1834
+ "BREADCRUMB_TRUNCATE_AT": 200,
1834
1835
  "DEFAULT_ACTION_SCHEME": "default",
1835
1836
  "DEFAULT_BACK_BUTTON_ICON": "arrow-left",
1836
1837
  "DEFAULT_BREADCRUMBS_DISPLAY": [
@@ -20563,6 +20563,19 @@
20563
20563
  ]
20564
20564
  }
20565
20565
  },
20566
+ {
20567
+ "preview_path": "primer/open_project/page_header/truncated_breadcrumbs",
20568
+ "name": "truncated_breadcrumbs",
20569
+ "snapshot": "false",
20570
+ "skip_rules": {
20571
+ "wont_fix": [
20572
+ "region"
20573
+ ],
20574
+ "will_fix": [
20575
+ "color-contrast"
20576
+ ]
20577
+ }
20578
+ },
20566
20579
  {
20567
20580
  "preview_path": "primer/open_project/page_header/without_breadcrumbs",
20568
20581
  "name": "without_breadcrumbs",
data/static/previews.json CHANGED
@@ -6183,6 +6183,19 @@
6183
6183
  ]
6184
6184
  }
6185
6185
  },
6186
+ {
6187
+ "preview_path": "primer/open_project/page_header/truncated_breadcrumbs",
6188
+ "name": "truncated_breadcrumbs",
6189
+ "snapshot": "false",
6190
+ "skip_rules": {
6191
+ "wont_fix": [
6192
+ "region"
6193
+ ],
6194
+ "will_fix": [
6195
+ "color-contrast"
6196
+ ]
6197
+ }
6198
+ },
6186
6199
  {
6187
6200
  "preview_path": "primer/open_project/page_header/without_breadcrumbs",
6188
6201
  "name": "without_breadcrumbs",
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openproject-primer_view_components
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.77.0
4
+ version: 0.78.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub Open Source
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2025-11-05 00:00:00.000000000 Z
12
+ date: 2025-12-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionview