primer_view_components 0.19.0 → 0.20.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -0
  3. data/app/assets/javascripts/app/components/primer/alpha/action_list.d.ts +16 -0
  4. data/app/assets/javascripts/app/components/primer/beta/nav_list.d.ts +3 -0
  5. data/app/assets/javascripts/app/components/primer/primer.d.ts +1 -0
  6. data/app/assets/javascripts/primer_view_components.js +1 -1
  7. data/app/assets/javascripts/primer_view_components.js.map +1 -1
  8. data/app/assets/styles/primer_view_components.css +1 -1
  9. data/app/assets/styles/primer_view_components.css.map +1 -1
  10. data/app/components/primer/alpha/action_list/item.rb +19 -6
  11. data/app/components/primer/alpha/action_list.css +1 -1
  12. data/app/components/primer/alpha/action_list.css.json +2 -0
  13. data/app/components/primer/alpha/action_list.css.map +1 -1
  14. data/app/components/primer/alpha/action_list.d.ts +16 -0
  15. data/app/components/primer/alpha/action_list.html.erb +19 -17
  16. data/app/components/primer/alpha/action_list.js +69 -0
  17. data/app/components/primer/alpha/action_list.pcss +8 -0
  18. data/app/components/primer/alpha/action_list.ts +58 -0
  19. data/app/components/primer/alpha/banner.css +1 -1
  20. data/app/components/primer/alpha/banner.css.map +1 -1
  21. data/app/components/primer/alpha/banner.pcss +4 -4
  22. data/app/components/primer/alpha/dialog.css +1 -1
  23. data/app/components/primer/alpha/dialog.css.json +2 -0
  24. data/app/components/primer/alpha/dialog.css.map +1 -1
  25. data/app/components/primer/alpha/dialog.pcss +9 -0
  26. data/app/components/primer/alpha/text_field.css +1 -1
  27. data/app/components/primer/alpha/text_field.css.json +2 -0
  28. data/app/components/primer/alpha/text_field.css.map +1 -1
  29. data/app/components/primer/alpha/text_field.pcss +10 -0
  30. data/app/components/primer/alpha/toggle_switch.rb +2 -2
  31. data/app/components/primer/beta/auto_complete/auto_complete.html.erb +9 -9
  32. data/app/components/primer/beta/breadcrumbs.css +1 -1
  33. data/app/components/primer/beta/breadcrumbs.css.map +1 -1
  34. data/app/components/primer/beta/breadcrumbs.pcss +3 -1
  35. data/app/components/primer/beta/button.css +1 -1
  36. data/app/components/primer/beta/button.css.json +1 -0
  37. data/app/components/primer/beta/button.css.map +1 -1
  38. data/app/components/primer/beta/button.pcss +4 -0
  39. data/app/components/primer/beta/flash.css +1 -1
  40. data/app/components/primer/beta/flash.css.map +1 -1
  41. data/app/components/primer/beta/flash.pcss +4 -4
  42. data/app/components/primer/beta/nav_list.d.ts +3 -0
  43. data/app/components/primer/beta/nav_list.html.erb +1 -1
  44. data/app/components/primer/beta/nav_list.js +25 -2
  45. data/app/components/primer/beta/nav_list.ts +18 -1
  46. data/app/components/primer/beta/nav_list_group_element.js +4 -1
  47. data/app/components/primer/beta/nav_list_group_element.ts +3 -0
  48. data/app/components/primer/primer.d.ts +1 -0
  49. data/app/components/primer/primer.js +1 -0
  50. data/app/components/primer/primer.ts +1 -0
  51. data/app/forms/auto_complete_form.rb +18 -0
  52. data/app/forms/select_form.rb +10 -0
  53. data/lib/primer/forms/auto_complete.html.erb +6 -0
  54. data/lib/primer/forms/auto_complete.rb +56 -0
  55. data/lib/primer/forms/builder.rb +19 -0
  56. data/lib/primer/forms/check_box_group.html.erb +4 -4
  57. data/lib/primer/forms/check_box_group.rb +0 -3
  58. data/lib/primer/forms/dsl/auto_complete_input.rb +33 -0
  59. data/lib/primer/forms/dsl/check_box_group_input.rb +8 -0
  60. data/lib/primer/forms/dsl/input.rb +8 -2
  61. data/lib/primer/forms/dsl/input_methods.rb +9 -0
  62. data/lib/primer/forms/dsl/radio_button_group_input.rb +8 -0
  63. data/lib/primer/forms/dsl/select_input.rb +5 -1
  64. data/lib/primer/forms/form_control.rb +1 -2
  65. data/lib/primer/forms/primer_text_field.js +2 -2
  66. data/lib/primer/forms/primer_text_field.ts +2 -2
  67. data/lib/primer/forms/radio_button_group.html.erb +4 -4
  68. data/lib/primer/forms/radio_button_group.rb +0 -3
  69. data/lib/primer/forms/select.html.erb +1 -0
  70. data/lib/primer/forms/select.rb +9 -5
  71. data/lib/primer/view_components/version.rb +2 -2
  72. data/previews/primer/alpha/action_list_preview.rb +42 -0
  73. data/previews/primer/alpha/select_preview.rb +12 -1
  74. data/previews/primer/alpha/text_area_preview.rb +7 -1
  75. data/previews/primer/alpha/text_field_preview.rb +7 -1
  76. data/previews/primer/beta/nav_list_preview.rb +43 -0
  77. data/previews/primer/forms_preview/auto_complete_form.html.erb +3 -0
  78. data/previews/primer/forms_preview/select_form.html.erb +1 -1
  79. data/previews/primer/forms_preview.rb +2 -0
  80. data/static/arguments.json +7 -7
  81. data/static/constants.json +15 -0
  82. data/static/info_arch.json +150 -7
  83. data/static/previews.json +143 -0
  84. metadata +11 -2
@@ -1 +1 @@
1
- {"version":3,"sources":["flash.pcss"],"names":[],"mappings":"AAGA,oBASE,+IAA2F,CAC3F,sEAA6C,CAL7C,gDAAyC,CAFzC,kBAAmB,CACnB,sDAAqC,CAIrC,oDAA6B,CAN7B,qFAAyE,CADzE,iBAmBF,CARE,6BACE,kDAA4B,CAC5B,uCACF,CAEA,iCACE,eACF,CAIF,gBACE,8CACF,CAGA,gCASE,uBAAgB,CAAhB,eAAgB,CAFhB,eAAgB,CAChB,QAAS,CAJT,cAAe,CAHf,WAAY,CACZ,6CAAyC,CACzC,iBAmBF,CAXE,sCACE,UACF,CAEA,uCACE,UACF,CAEA,yCACE,cACF,CAIF,mCAIE,2BAA4B,CAH5B,WAAY,CAEZ,4CAAsC,CADtC,eAgBF,CAZE,gDAEE,gDAA2B,CAD3B,4CAEF,CAEA,+CACE,uBAKF,CAHE,wDACE,aACF,CAMJ,yBAEE,2JAAiG,CACjG,4EAAgD,CAFhD,oDAOF,CAHE,kCACE,wDACF,CAGF,0BAEE,+IAA2F,CAC3F,sEAA6C,CAF7C,oDAOF,CAHE,mCACE,kDACF,CAGF,4BAEE,mJAA6F,CAC7F,wEAA8C,CAF9C,oDAOF,CAHE,qCACE,oDACF,CAKF,yBAGE,eAAgB,CADhB,wDAAuC,CADvC,8DAGF,CAGA,cAOE,aAAc,CACd,eAAgB,CAFhB,cAAe,CADf,YAAa,CAJb,cAAe,CACf,KAAM,CAEN,UAAW,CADX,UAMF,CAGA,0BAEE,mEACF,CAGA,SAIE,6EAAgD,CADhD,gDAA6C,CAD7C,kBAAoB,CADpB,YAIF","file":"flash.css","sourcesContent":["/* flash */\n\n/* Default flash */\n.flash:not(.Banner) {\n position: relative;\n padding: var(--base-size-20) var(--control-medium-paddingInline-spacious);\n border-style: solid;\n border-width: var(--borderWidth-thin);\n border-radius: var(--borderRadius-medium);\n\n /* Default color */\n color: var(--fgColor-default);\n background-image: linear-gradient(var(--bgColor-accent-muted), var(--bgColor-accent-muted));\n border-color: var(--borderColor-accent-muted);\n\n & .octicon {\n color: var(--fgColor-accent);\n margin-right: var(--base-size-12);\n }\n\n & p:last-child {\n margin-bottom: 0;\n }\n}\n\n/* Contain the flash messages */\n.flash-messages {\n margin-bottom: var(--stack-gap-spacious);\n}\n\n/* Close button */\n.flash-close:not(.Banner-close) {\n float: right;\n margin-top: calc(var(--base-size-4) * -1);\n text-align: center;\n cursor: pointer;\n\n /* Undo `<button>` styles */\n background: none;\n border: 0;\n appearance: none;\n\n &:hover {\n opacity: 0.7;\n }\n\n &:active {\n opacity: 0.5;\n }\n\n & .octicon {\n margin-right: 0;\n }\n}\n\n/* Action button */\n.flash-action:not(.Banner-actions) {\n float: right;\n margin-top: -3px;\n margin-left: var(--stack-gap-spacious);\n background-clip: padding-box;\n\n &.btn .octicon {\n margin-right: var(--control-small-gap);\n color: var(--fgColor-muted);\n }\n\n &.btn-primary {\n background-clip: border-box;\n\n & .octicon {\n color: inherit;\n }\n }\n}\n\n/* Color variations */\n\n.flash-warn:not(.Banner) {\n color: var(--fgColor-default);\n background-image: linear-gradient(var(--bgColor-attention-muted), var(--bgColor-attention-muted));\n border-color: var(--borderColor-attention-muted);\n\n & .octicon {\n color: var(--fgColor-attention);\n }\n}\n\n.flash-error:not(.Banner) {\n color: var(--fgColor-default);\n background-image: linear-gradient(var(--bgColor-danger-muted), var(--bgColor-danger-muted));\n border-color: var(--borderColor-danger-muted);\n\n & .octicon {\n color: var(--fgColor-danger);\n }\n}\n\n.flash-success:not(.Banner) {\n color: var(--fgColor-default);\n background-image: linear-gradient(var(--bgColor-success-muted), var(--bgColor-success-muted));\n border-color: var(--borderColor-success-muted);\n\n & .octicon {\n color: var(--fgColor-success);\n }\n}\n\n/* Layout variations */\n\n.flash-full:not(.Banner) {\n margin-top: calc(var(--borderWidth-thin) * -1);\n border-width: var(--borderWidth-thin) 0;\n border-radius: 0;\n}\n\n/* A banner rendered at the top of the page. */\n.flash-banner {\n position: fixed;\n top: 0;\n z-index: 90;\n width: 100%;\n border-top: 0;\n border-right: 0;\n border-left: 0;\n border-radius: 0;\n}\n\n/* Makes sure the background is opaque to cover any content underneath */\n.flash-full,\n.flash-banner {\n background-color: var(--bgColor-default);\n}\n\n/* FIXME deprecate this */\n.warning {\n padding: 0.5em;\n margin-bottom: 0.8em;\n font-weight: var(--base-text-weight-semibold);\n background-color: var(--bgColor-attention-muted);\n}\n"]}
1
+ {"version":3,"sources":["flash.pcss"],"names":[],"mappings":"AAGA,oBASE,uEAA6C,CAC7C,sEAA6C,CAL7C,gDAAyC,CAFzC,kBAAmB,CACnB,sDAAqC,CAIrC,oDAA6B,CAN7B,qFAAyE,CADzE,iBAmBF,CARE,6BACE,kDAA4B,CAC5B,uCACF,CAEA,iCACE,eACF,CAIF,gBACE,8CACF,CAGA,gCASE,uBAAgB,CAAhB,eAAgB,CAFhB,eAAgB,CAChB,QAAS,CAJT,cAAe,CAHf,WAAY,CACZ,6CAAyC,CACzC,iBAmBF,CAXE,sCACE,UACF,CAEA,uCACE,UACF,CAEA,yCACE,cACF,CAIF,mCAIE,2BAA4B,CAH5B,WAAY,CAEZ,4CAAsC,CADtC,eAgBF,CAZE,gDAEE,gDAA2B,CAD3B,4CAEF,CAEA,+CACE,uBAKF,CAHE,wDACE,aACF,CAMJ,yBAEE,6EAAgD,CAChD,4EAAgD,CAFhD,oDAOF,CAHE,kCACE,wDACF,CAGF,0BAEE,uEAA6C,CAC7C,sEAA6C,CAF7C,oDAOF,CAHE,mCACE,kDACF,CAGF,4BAEE,yEAA8C,CAC9C,wEAA8C,CAF9C,oDAOF,CAHE,qCACE,oDACF,CAKF,yBAGE,eAAgB,CADhB,wDAAuC,CADvC,8DAGF,CAGA,cAOE,aAAc,CACd,eAAgB,CAFhB,cAAe,CADf,YAAa,CAJb,cAAe,CACf,KAAM,CAEN,UAAW,CADX,UAMF,CAGA,0BAEE,mEACF,CAGA,SAIE,6EAAgD,CADhD,gDAA6C,CAD7C,kBAAoB,CADpB,YAIF","file":"flash.css","sourcesContent":["/* flash */\n\n/* Default flash */\n.flash:not(.Banner) {\n position: relative;\n padding: var(--base-size-20) var(--control-medium-paddingInline-spacious);\n border-style: solid;\n border-width: var(--borderWidth-thin);\n border-radius: var(--borderRadius-medium);\n\n /* Default color */\n color: var(--fgColor-default);\n background-color: var(--bgColor-accent-muted);\n border-color: var(--borderColor-accent-muted);\n\n & .octicon {\n color: var(--fgColor-accent);\n margin-right: var(--base-size-12);\n }\n\n & p:last-child {\n margin-bottom: 0;\n }\n}\n\n/* Contain the flash messages */\n.flash-messages {\n margin-bottom: var(--stack-gap-spacious);\n}\n\n/* Close button */\n.flash-close:not(.Banner-close) {\n float: right;\n margin-top: calc(var(--base-size-4) * -1);\n text-align: center;\n cursor: pointer;\n\n /* Undo `<button>` styles */\n background: none;\n border: 0;\n appearance: none;\n\n &:hover {\n opacity: 0.7;\n }\n\n &:active {\n opacity: 0.5;\n }\n\n & .octicon {\n margin-right: 0;\n }\n}\n\n/* Action button */\n.flash-action:not(.Banner-actions) {\n float: right;\n margin-top: -3px;\n margin-left: var(--stack-gap-spacious);\n background-clip: padding-box;\n\n &.btn .octicon {\n margin-right: var(--control-small-gap);\n color: var(--fgColor-muted);\n }\n\n &.btn-primary {\n background-clip: border-box;\n\n & .octicon {\n color: inherit;\n }\n }\n}\n\n/* Color variations */\n\n.flash-warn:not(.Banner) {\n color: var(--fgColor-default);\n background-color: var(--bgColor-attention-muted);\n border-color: var(--borderColor-attention-muted);\n\n & .octicon {\n color: var(--fgColor-attention);\n }\n}\n\n.flash-error:not(.Banner) {\n color: var(--fgColor-default);\n background-color: var(--bgColor-danger-muted);\n border-color: var(--borderColor-danger-muted);\n\n & .octicon {\n color: var(--fgColor-danger);\n }\n}\n\n.flash-success:not(.Banner) {\n color: var(--fgColor-default);\n background-color: var(--bgColor-success-muted);\n border-color: var(--borderColor-success-muted);\n\n & .octicon {\n color: var(--fgColor-success);\n }\n}\n\n/* Layout variations */\n\n.flash-full:not(.Banner) {\n margin-top: calc(var(--borderWidth-thin) * -1);\n border-width: var(--borderWidth-thin) 0;\n border-radius: 0;\n}\n\n/* A banner rendered at the top of the page. */\n.flash-banner {\n position: fixed;\n top: 0;\n z-index: 90;\n width: 100%;\n border-top: 0;\n border-right: 0;\n border-left: 0;\n border-radius: 0;\n}\n\n/* Makes sure the background is opaque to cover any content underneath */\n.flash-full,\n.flash-banner {\n background-color: var(--bgColor-default);\n}\n\n/* FIXME deprecate this */\n.warning {\n padding: 0.5em;\n margin-bottom: 0.8em;\n font-weight: var(--base-text-weight-semibold);\n background-color: var(--bgColor-attention-muted);\n}\n"]}
@@ -10,7 +10,7 @@
10
10
 
11
11
  /* Default color */
12
12
  color: var(--fgColor-default);
13
- background-image: linear-gradient(var(--bgColor-accent-muted), var(--bgColor-accent-muted));
13
+ background-color: var(--bgColor-accent-muted);
14
14
  border-color: var(--borderColor-accent-muted);
15
15
 
16
16
  & .octicon {
@@ -78,7 +78,7 @@
78
78
 
79
79
  .flash-warn:not(.Banner) {
80
80
  color: var(--fgColor-default);
81
- background-image: linear-gradient(var(--bgColor-attention-muted), var(--bgColor-attention-muted));
81
+ background-color: var(--bgColor-attention-muted);
82
82
  border-color: var(--borderColor-attention-muted);
83
83
 
84
84
  & .octicon {
@@ -88,7 +88,7 @@
88
88
 
89
89
  .flash-error:not(.Banner) {
90
90
  color: var(--fgColor-default);
91
- background-image: linear-gradient(var(--bgColor-danger-muted), var(--bgColor-danger-muted));
91
+ background-color: var(--bgColor-danger-muted);
92
92
  border-color: var(--borderColor-danger-muted);
93
93
 
94
94
  & .octicon {
@@ -98,7 +98,7 @@
98
98
 
99
99
  .flash-success:not(.Banner) {
100
100
  color: var(--fgColor-default);
101
- background-image: linear-gradient(var(--bgColor-success-muted), var(--bgColor-success-muted));
101
+ background-color: var(--bgColor-success-muted);
102
102
  border-color: var(--borderColor-success-muted);
103
103
 
104
104
  & .octicon {
@@ -1,6 +1,9 @@
1
1
  export declare class NavListElement extends HTMLElement {
2
2
  #private;
3
3
  items: HTMLElement[];
4
+ topLevelList: HTMLElement;
5
+ connectedCallback(): void;
6
+ disconnectedCallback(): void;
4
7
  selectItemById(itemId: string | null): boolean;
5
8
  selectItemByHref(href: string | null): boolean;
6
9
  selectItemByCurrentLocation(): boolean;
@@ -1,7 +1,7 @@
1
1
  <%= render(Primer::BaseComponent.new(tag: :nav, **@system_arguments)) do %>
2
2
  <%= heading %>
3
3
  <nav-list>
4
- <%= render(Primer::ConditionalWrapper.new(condition: render_outer_list?, tag: :ul, classes: "ActionListWrap")) do %>
4
+ <%= render(Primer::ConditionalWrapper.new(condition: render_outer_list?, tag: :ul, classes: "ActionListWrap", data: { target: "nav-list.topLevelList" })) do %>
5
5
  <% items.each_with_index do |item, index| %>
6
6
  <% if index > 0 && render_divider_between?(item, items[index - 1]) %>
7
7
  <%= render(Primer::Alpha::ActionList::Divider.new) %>
@@ -4,18 +4,37 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
8
+ if (kind === "m") throw new TypeError("Private method is not writable");
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
11
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
12
+ };
7
13
  var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
14
  if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
15
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
16
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
17
  };
12
- var _NavListElement_instances, _NavListElement_findSelectedNavItemById, _NavListElement_findSelectedNavItemByHref, _NavListElement_findSelectedNavItemByCurrentLocation, _NavListElement_select, _NavListElement_deselect, _NavListElement_findParentMenu;
18
+ var _NavListElement_instances, _NavListElement_truncationObserver, _NavListElement_findSelectedNavItemById, _NavListElement_findSelectedNavItemByHref, _NavListElement_findSelectedNavItemByCurrentLocation, _NavListElement_select, _NavListElement_deselect, _NavListElement_findParentMenu;
13
19
  /* eslint-disable custom-elements/expose-class-on-global */
14
- import { controller, targets } from '@github/catalyst';
20
+ import { controller, target, targets } from '@github/catalyst';
21
+ import { ActionListTruncationObserver } from '../alpha/action_list';
15
22
  let NavListElement = class NavListElement extends HTMLElement {
16
23
  constructor() {
17
24
  super(...arguments);
18
25
  _NavListElement_instances.add(this);
26
+ _NavListElement_truncationObserver.set(this, void 0);
27
+ }
28
+ connectedCallback() {
29
+ // groups are wrapped in <action-list>, which handles resizing on its own
30
+ if (this.topLevelList) {
31
+ __classPrivateFieldSet(this, _NavListElement_truncationObserver, new ActionListTruncationObserver(this.topLevelList), "f");
32
+ }
33
+ }
34
+ disconnectedCallback() {
35
+ if (this.topLevelList) {
36
+ __classPrivateFieldGet(this, _NavListElement_truncationObserver, "f").unobserve(this.topLevelList);
37
+ }
19
38
  }
20
39
  selectItemById(itemId) {
21
40
  if (!itemId)
@@ -100,6 +119,7 @@ let NavListElement = class NavListElement extends HTMLElement {
100
119
  e.stopPropagation();
101
120
  }
102
121
  };
122
+ _NavListElement_truncationObserver = new WeakMap();
103
123
  _NavListElement_instances = new WeakSet();
104
124
  _NavListElement_findSelectedNavItemById = function _NavListElement_findSelectedNavItemById(itemId) {
105
125
  // First we compare the selected link to data-item-id for each nav item
@@ -164,6 +184,9 @@ _NavListElement_findParentMenu = function _NavListElement_findParentMenu(navItem
164
184
  __decorate([
165
185
  targets
166
186
  ], NavListElement.prototype, "items", void 0);
187
+ __decorate([
188
+ target
189
+ ], NavListElement.prototype, "topLevelList", void 0);
167
190
  NavListElement = __decorate([
168
191
  controller
169
192
  ], NavListElement);
@@ -1,9 +1,26 @@
1
1
  /* eslint-disable custom-elements/expose-class-on-global */
2
- import {controller, targets} from '@github/catalyst'
2
+ import {controller, target, targets} from '@github/catalyst'
3
+ import {ActionListTruncationObserver} from '../alpha/action_list'
3
4
 
4
5
  @controller
5
6
  export class NavListElement extends HTMLElement {
6
7
  @targets items: HTMLElement[]
8
+ @target topLevelList: HTMLElement
9
+
10
+ #truncationObserver: ActionListTruncationObserver
11
+
12
+ connectedCallback() {
13
+ // groups are wrapped in <action-list>, which handles resizing on its own
14
+ if (this.topLevelList) {
15
+ this.#truncationObserver = new ActionListTruncationObserver(this.topLevelList)
16
+ }
17
+ }
18
+
19
+ disconnectedCallback() {
20
+ if (this.topLevelList) {
21
+ this.#truncationObserver.unobserve(this.topLevelList)
22
+ }
23
+ }
7
24
 
8
25
  selectItemById(itemId: string | null): boolean {
9
26
  if (!itemId) return false
@@ -9,12 +9,14 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _NavListGroupElement_instances, _NavListGroupElement_parseHTML;
12
+ var _NavListGroupElement_instances, _NavListGroupElement_parseHTML, _NavListGroupElement_truncateObserver;
13
13
  import { controller, target, targets } from '@github/catalyst';
14
+ import { ActionListTruncationObserver } from '../alpha/action_list';
14
15
  let NavListGroupElement = class NavListGroupElement extends HTMLElement {
15
16
  constructor() {
16
17
  super(...arguments);
17
18
  _NavListGroupElement_instances.add(this);
19
+ _NavListGroupElement_truncateObserver.set(this, new ActionListTruncationObserver(this));
18
20
  }
19
21
  connectedCallback() {
20
22
  this.setShowMoreItemState();
@@ -87,6 +89,7 @@ let NavListGroupElement = class NavListGroupElement extends HTMLElement {
87
89
  }
88
90
  }
89
91
  };
92
+ _NavListGroupElement_truncateObserver = new WeakMap();
90
93
  _NavListGroupElement_instances = new WeakSet();
91
94
  _NavListGroupElement_parseHTML = function _NavListGroupElement_parseHTML(document, html) {
92
95
  const template = document.createElement('template');
@@ -1,4 +1,5 @@
1
1
  import {controller, target, targets} from '@github/catalyst'
2
+ import {ActionListTruncationObserver} from '../alpha/action_list'
2
3
 
3
4
  @controller
4
5
  export class NavListGroupElement extends HTMLElement {
@@ -86,6 +87,8 @@ export class NavListGroupElement extends HTMLElement {
86
87
  template.innerHTML = html
87
88
  return document.importNode(template.content, true)
88
89
  }
90
+
91
+ #truncateObserver = new ActionListTruncationObserver(this)
89
92
  }
90
93
 
91
94
  declare global {
@@ -1,4 +1,5 @@
1
1
  import '@github/include-fragment-element';
2
+ import './alpha/action_list';
2
3
  import './alpha/action_bar_element';
3
4
  import './alpha/dropdown';
4
5
  import './anchored_position';
@@ -1,4 +1,5 @@
1
1
  import '@github/include-fragment-element';
2
+ import './alpha/action_list';
2
3
  import './alpha/action_bar_element';
3
4
  import './alpha/dropdown';
4
5
  import './anchored_position';
@@ -1,4 +1,5 @@
1
1
  import '@github/include-fragment-element'
2
+ import './alpha/action_list'
2
3
  import './alpha/action_bar_element'
3
4
  import './alpha/dropdown'
4
5
  import './anchored_position'
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../previews/primer/url_helpers"
4
+
5
+ # :nodoc:
6
+ class AutoCompleteForm < ApplicationForm
7
+ form do |auto_complete_form|
8
+ auto_complete_form.auto_complete(
9
+ name: :fruit,
10
+ label: "Fruit",
11
+ caption: "Please enter your favorite fruit",
12
+ src: Primer::UrlHelpers.autocomplete_index_path,
13
+ validation_message: "Something went wrong"
14
+ )
15
+
16
+ auto_complete_form.submit(label: "Submit", name: :submit)
17
+ end
18
+ end
@@ -8,5 +8,15 @@ class SelectForm < ApplicationForm
8
8
  city_list.option(label: "Bellevue", value: "bellevue")
9
9
  city_list.option(label: "Seattle", value: "seattle")
10
10
  end
11
+
12
+ select_form.select_list(name: "been", label: "Places you've been", caption: "Select all that apply", multiple: true, include_hidden: false) do |been_list|
13
+ been_list.option(label: "Lima, Peru", value: "lima")
14
+ been_list.option(label: "Tokyo, Japan", value: "tokyo")
15
+ been_list.option(label: "Reykjavík, Iceland", value: "reykjavik")
16
+ been_list.option(label: "Chiang Mai, Thailand", value: "chiang_mai")
17
+ been_list.option(label: "Queenstown, New Zealand", value: "queenstown")
18
+ end
19
+
20
+ select_form.submit(name: :submit, label: "Submit")
11
21
  end
12
22
  end
@@ -0,0 +1,6 @@
1
+ <%= render(Primer::Beta::AutoComplete.new(**auto_complete_arguments)) do |autocomplete| %>
2
+ <% @input.block.call(autocomplete) if @input.block %>
3
+ <% autocomplete.with_input(**input_arguments) %>
4
+ <% end %>
5
+ <%= render(ValidationMessage.new(input: @input)) %>
6
+ <%= render(Caption.new(input: @input)) %>
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Forms
5
+ # :nodoc:
6
+ class AutoComplete < BaseComponent
7
+ ARGUMENT_TYPES = %i(keyreq key).freeze
8
+
9
+ delegate :builder, :form, to: :@input
10
+
11
+ def initialize(input:)
12
+ @input = input
13
+ @input.merge_input_arguments!(text_field_attributes.deep_symbolize_keys)
14
+ end
15
+
16
+ def self.auto_complete_argument_names
17
+ @auto_complete_argument_names ||=
18
+ Primer::Beta::AutoComplete.instance_method(:initialize)
19
+ .parameters
20
+ .filter_map { |(type, param_name)| next param_name if ARGUMENT_TYPES.include?(type) }
21
+ end
22
+
23
+ private
24
+
25
+ def all_input_arguments
26
+ @all_input_arguments ||= @input.input_arguments.deep_dup.tap do |args|
27
+ # rails uses :class but PVC wants :classes
28
+ args[:classes] = class_names(
29
+ args[:classes],
30
+ args.delete(:class)
31
+ )
32
+ end
33
+ end
34
+
35
+ def auto_complete_arguments
36
+ all_args = all_input_arguments
37
+ all_args
38
+ .slice(*self.class.auto_complete_argument_names)
39
+ .merge(
40
+ input_name: all_args[:name],
41
+ input_id: all_args[:id],
42
+ label_text: @input.label,
43
+ list_id: "#{all_args[:id]}-list"
44
+ )
45
+ end
46
+
47
+ def input_arguments
48
+ all_input_arguments.except(*self.class.auto_complete_argument_names, :id, :name)
49
+ end
50
+
51
+ def text_field_attributes
52
+ builder.text_field_attributes(@input.name).except("size", "value")
53
+ end
54
+ end
55
+ end
56
+ end
@@ -27,6 +27,21 @@ ActionView::Helpers::Tags::Base.prepend(
27
27
 
28
28
  module Primer
29
29
  module Forms
30
+ module Tags
31
+ # :nodoc:
32
+ class TextField < ::ActionView::Helpers::Tags::TextField
33
+ def attributes
34
+ render
35
+ end
36
+
37
+ private
38
+
39
+ def tag(_name, options)
40
+ options
41
+ end
42
+ end
43
+ end
44
+
30
45
  # :nodoc:
31
46
  class Builder < ActionView::Helpers::FormBuilder
32
47
  alias primer_fields_for fields_for
@@ -57,6 +72,10 @@ module Primer
57
72
  super(*args, classify(options).merge(generate_error_markup: false), &block)
58
73
  end
59
74
 
75
+ def text_field_attributes(method, options = {})
76
+ Tags::TextField.new(@object_name, method, @template, options).attributes
77
+ end
78
+
60
79
  def text_area(*args, **options, &block)
61
80
  super(*args, classify(options).merge(generate_error_markup: false), &block)
62
81
  end
@@ -1,5 +1,5 @@
1
- <%= content_tag(:div, **@input.input_arguments) do %>
2
- <fieldset>
1
+ <div class="FormControl-check-group-wrap">
2
+ <%= content_tag(:fieldset, **@input.input_arguments) do %>
3
3
  <% if @input.label %>
4
4
  <%= content_tag(:legend, **@input.label_arguments) do %>
5
5
  <%= @input.label %>
@@ -10,11 +10,11 @@
10
10
  <%= render(check_box.to_component) %>
11
11
  <% end %>
12
12
  <% end %>
13
- </fieldset>
13
+ <% end %>
14
14
  <div class="mt-2">
15
15
  <%= render(ValidationMessage.new(input: @input)) %>
16
16
  </div>
17
17
  <div class="mt-2">
18
18
  <%= render(Caption.new(input: @input)) %>
19
19
  </div>
20
- <% end %>
20
+ </div>
@@ -8,10 +8,7 @@ module Primer
8
8
 
9
9
  def initialize(input:)
10
10
  @input = input
11
-
12
11
  @input.add_label_classes("FormControl-label", "mb-2")
13
- @input.add_input_classes("FormControl-check-group-wrap")
14
-
15
12
  Primer::Forms::Utils.classify(@input.input_arguments)
16
13
  end
17
14
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Forms
5
+ module Dsl
6
+ # :nodoc:
7
+ class AutoCompleteInput < Input
8
+ attr_reader :name, :label, :block
9
+
10
+ def initialize(name:, label:, **system_arguments, &block)
11
+ @name = name
12
+ @label = label
13
+ @block = block
14
+
15
+ super(**system_arguments)
16
+ end
17
+
18
+ def to_component
19
+ AutoComplete.new(input: self)
20
+ end
21
+
22
+ def type
23
+ :autocomplete
24
+ end
25
+
26
+ # The AutoComplete Primer component does not allow auto-focusing
27
+ def focusable?
28
+ false
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -25,6 +25,14 @@ module Primer
25
25
  :check_box_group
26
26
  end
27
27
 
28
+ def focusable?
29
+ true
30
+ end
31
+
32
+ def autofocus!
33
+ @check_boxes.first&.autofocus!
34
+ end
35
+
28
36
  def check_box(**system_arguments, &block)
29
37
  args = {
30
38
  name: @name,
@@ -31,7 +31,7 @@ module Primer
31
31
  # @param size [Symbol] The size of the field. <%= one_of(Primer::Forms::Dsl::Input::SIZE_OPTIONS) %>
32
32
 
33
33
  # @!macro [new] form_full_width_arguments
34
- # @param full_width [Boolean] When set to `true`, the field will take up all the horizontal space allowed by its container.
34
+ # @param full_width [Boolean] When set to `true`, the field will take up all the horizontal space allowed by its container. Defaults to `true`.
35
35
 
36
36
  # @!macro [new] form_system_arguments
37
37
  # @param system_arguments [Hash] A hash of attributes passed to the underlying Rails builder methods. These options may mean something special depending on the type of input, otherwise they are emitted as HTML attributes. See the [Rails documentation](https://guides.rubyonrails.org/form_helpers.html) for more information. In addition, the usual Primer utility arguments are accepted in system arguments. For example, passing `mt: 2` will add the `mt-2` class to the input. See the Primer system arguments docs for details.
@@ -56,7 +56,9 @@ module Primer
56
56
  @form = form
57
57
 
58
58
  @input_arguments = system_arguments
59
+ @input_arguments.delete(:id) unless @input_arguments[:id].present?
59
60
  @label_arguments = @input_arguments.delete(:label_arguments) || {}
61
+ @label_arguments[:for] = id if id.present?
60
62
 
61
63
  @label_arguments[:class] = class_names(
62
64
  @label_arguments[:class],
@@ -71,7 +73,7 @@ module Primer
71
73
  @caption = @input_arguments.delete(:caption)
72
74
  @validation_message = @input_arguments.delete(:validation_message)
73
75
  @invalid = @input_arguments.delete(:invalid)
74
- @full_width = @input_arguments.delete(:full_width)
76
+ @full_width = @input_arguments.delete(:full_width) { true }
75
77
  @size = @input_arguments.delete(:size)
76
78
 
77
79
  # If scope_name_to_model is false, the name of the input for eg. `my_field`
@@ -240,6 +242,10 @@ module Primer
240
242
  input_arguments[:autofocus] = true
241
243
  end
242
244
 
245
+ def id
246
+ @input_arguments[:id]
247
+ end
248
+
243
249
  # :nocov:
244
250
  def name
245
251
  raise_for_abstract_method!(__method__)
@@ -68,6 +68,15 @@ module Primer
68
68
  add_input TextFieldInput.new(builder: builder, form: form, **options, &block)
69
69
  end
70
70
 
71
+ # Adds an autocomplete text field to this form.
72
+ #
73
+ # @param options [Hash] The options accepted by the autocomplete input (see forms docs).
74
+ # @param block [Proc] A block that will be yielded a reference to the input object so it can be customized.
75
+ def auto_complete(**options, &block)
76
+ options = decorate_options(**options)
77
+ add_input AutoCompleteInput.new(builder: builder, form: form, **options, &block)
78
+ end
79
+
71
80
  # Adds a text area to this form.
72
81
  #
73
82
  # @param options [Hash] The options accepted by the text area input (see forms docs).
@@ -25,6 +25,14 @@ module Primer
25
25
  :radio_button_group
26
26
  end
27
27
 
28
+ def autofocus!
29
+ @radio_buttons.first&.autofocus!
30
+ end
31
+
32
+ def focusable?
33
+ true
34
+ end
35
+
28
36
  def radio_button(**system_arguments, &block)
29
37
  @radio_buttons << RadioButtonInput.new(
30
38
  builder: @builder, form: @form, name: @name, disabled: disabled?,
@@ -5,7 +5,7 @@ module Primer
5
5
  module Dsl
6
6
  # :nodoc:
7
7
  class SelectInput < Input
8
- SELECT_ARGUMENTS = %i[multiple include_blank prompt].freeze
8
+ SELECT_ARGUMENTS = %i[multiple include_blank include_hidden prompt].freeze
9
9
 
10
10
  # :nodoc:
11
11
  class Option
@@ -38,6 +38,10 @@ module Primer
38
38
  yield(self) if block_given?
39
39
  end
40
40
 
41
+ def multiple?
42
+ @select_arguments.fetch(:multiple, false)
43
+ end
44
+
41
45
  def option(**system_arguments)
42
46
  @options << Option.new(**system_arguments)
43
47
  end
@@ -16,8 +16,7 @@ module Primer
16
16
  system_arguments[:class],
17
17
  system_arguments[:classes],
18
18
  "FormControl",
19
- "width-full",
20
- "FormControl--fullWidth" => @input.full_width?
19
+ "width-full FormControl--fullWidth" => @input.full_width?
21
20
  )
22
21
  }
23
22
 
@@ -29,7 +29,7 @@ class PrimerTextFieldElement extends HTMLElement {
29
29
  connectedCallback() {
30
30
  __classPrivateFieldGet(this, _PrimerTextFieldElement_abortController, "f")?.abort();
31
31
  const { signal } = (__classPrivateFieldSet(this, _PrimerTextFieldElement_abortController, new AbortController(), "f"));
32
- this.inputElement.addEventListener('auto-check-success', async (event) => {
32
+ this.addEventListener('auto-check-success', async (event) => {
33
33
  const message = await event.detail.response.text();
34
34
  if (message && message.length > 0) {
35
35
  this.setSuccess(message);
@@ -38,7 +38,7 @@ class PrimerTextFieldElement extends HTMLElement {
38
38
  this.clearError();
39
39
  }
40
40
  }, { signal });
41
- this.inputElement.addEventListener('auto-check-error', async (event) => {
41
+ this.addEventListener('auto-check-error', async (event) => {
42
42
  const errorMessage = await event.detail.response.text();
43
43
  this.setError(errorMessage);
44
44
  }, { signal });
@@ -17,7 +17,7 @@ class PrimerTextFieldElement extends HTMLElement {
17
17
  this.#abortController?.abort()
18
18
  const {signal} = (this.#abortController = new AbortController())
19
19
 
20
- this.inputElement.addEventListener(
20
+ this.addEventListener(
21
21
  'auto-check-success',
22
22
  async (event: any) => {
23
23
  const message = await event.detail.response.text()
@@ -30,7 +30,7 @@ class PrimerTextFieldElement extends HTMLElement {
30
30
  {signal},
31
31
  )
32
32
 
33
- this.inputElement.addEventListener(
33
+ this.addEventListener(
34
34
  'auto-check-error',
35
35
  async (event: any) => {
36
36
  const errorMessage = await event.detail.response.text()
@@ -1,5 +1,5 @@
1
- <%= content_tag(:div, **@input.input_arguments) do %>
2
- <fieldset>
1
+ <div class="FormControl-radio-group-wrap">
2
+ <%= content_tag(:fieldset, **@input.input_arguments) do %>
3
3
  <% if @input.label %>
4
4
  <%= content_tag(:legend, **@input.label_arguments) do %>
5
5
  <%= @input.label %>
@@ -10,11 +10,11 @@
10
10
  <%= render(radio_button.to_component) %>
11
11
  <% end %>
12
12
  <% end %>
13
- </fieldset>
13
+ <% end %>
14
14
  <div class="mt-2">
15
15
  <%= render(ValidationMessage.new(input: @input)) %>
16
16
  </div>
17
17
  <div class="mt-2">
18
18
  <%= render(Caption.new(input: @input)) %>
19
19
  </div>
20
- <% end %>
20
+ </div>
@@ -8,10 +8,7 @@ module Primer
8
8
 
9
9
  def initialize(input:)
10
10
  @input = input
11
-
12
11
  @input.add_label_classes("FormControl-label", "mb-2")
13
- @input.add_input_classes("FormControl-radio-group-wrap")
14
-
15
12
  Primer::Forms::Utils.classify(@input.input_arguments)
16
13
  end
17
14
  end
@@ -3,3 +3,4 @@
3
3
  <%= builder.select(@input.name, options, @input.select_arguments, **@input.input_arguments) %>
4
4
  <% end %>
5
5
  <% end %>
6
+
@@ -8,14 +8,18 @@ module Primer
8
8
 
9
9
  def initialize(input:)
10
10
  @input = input
11
- @input.add_input_classes(
12
- "FormControl-select",
13
- Primer::Forms::Dsl::Input::SIZE_MAPPINGS[@input.size]
14
- )
11
+ @input.add_input_classes("FormControl-select")
12
+
13
+ if !input.multiple?
14
+ @input.add_input_classes(
15
+ Primer::Forms::Dsl::Input::SIZE_MAPPINGS[@input.size]
16
+ )
17
+ end
15
18
 
16
19
  @field_wrap_arguments = {
17
20
  class: "FormControl-select-wrap",
18
- hidden: @input.hidden?
21
+ hidden: @input.hidden?,
22
+ data: { multiple: input.multiple? }
19
23
  }
20
24
  end
21
25