openproject-primer_view_components 0.41.1 → 0.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -0
  3. data/app/assets/javascripts/app/components/primer/alpha/select_panel_element.d.ts +0 -1
  4. data/app/assets/javascripts/primer_view_components.js +1 -1
  5. data/app/assets/javascripts/primer_view_components.js.map +1 -1
  6. data/app/assets/styles/primer_view_components.css +1 -1
  7. data/app/assets/styles/primer_view_components.css.map +1 -1
  8. data/app/components/primer/alpha/action_list/item.html.erb +1 -5
  9. data/app/components/primer/alpha/action_list/item.rb +10 -3
  10. data/app/components/primer/alpha/segmented_control.css +1 -1
  11. data/app/components/primer/alpha/segmented_control.css.map +1 -1
  12. data/app/components/primer/alpha/segmented_control.pcss +1 -0
  13. data/app/components/primer/alpha/select_panel.rb +2 -1
  14. data/app/components/primer/alpha/select_panel_element.d.ts +0 -1
  15. data/app/components/primer/alpha/select_panel_element.js +38 -19
  16. data/app/components/primer/alpha/select_panel_element.ts +36 -22
  17. data/app/components/primer/alpha/tool_tip.js +2 -2
  18. data/app/components/primer/alpha/tool_tip.ts +2 -2
  19. data/app/components/primer/beta/relative_time.rb +4 -4
  20. data/app/components/primer/beta/state.css +1 -1
  21. data/app/components/primer/beta/state.css.map +1 -1
  22. data/app/components/primer/beta/state.pcss +4 -0
  23. data/lib/primer/view_components/linters/details_menu_migration.rb +30 -1
  24. data/lib/primer/view_components/linters/tooltipped_migration.rb +1 -1
  25. data/lib/primer/view_components/version.rb +2 -2
  26. data/previews/primer/alpha/action_list_preview.rb +1 -1
  27. data/previews/primer/alpha/select_panel_preview/list_of_links.html.erb +16 -0
  28. data/previews/primer/alpha/select_panel_preview/playground.html.erb +2 -1
  29. data/previews/primer/alpha/select_panel_preview.rb +12 -1
  30. data/static/arguments.json +5 -5
  31. data/static/info_arch.json +57 -11
  32. data/static/previews.json +13 -0
  33. metadata +3 -2
@@ -28,11 +28,7 @@
28
28
  <%= render(Primer::BaseComponent.new(tag: :span, **@label_arguments)) do %>
29
29
  <%= @label || content %>
30
30
  <% end %>
31
- <% if description? %>
32
- <span class="ActionListItem-description">
33
- <%= description %>
34
- </span>
35
- <% end %>
31
+ <%= description if description? %>
36
32
  <% end %>
37
33
  <% if trailing_visual %>
38
34
  <span class="ActionListItem-visual ActionListItem-visual--trailing">
@@ -38,9 +38,16 @@ module Primer
38
38
  }
39
39
  TRUNCATION_BEHAVIOR_OPTIONS = TRUNCATION_BEHAVIOR_MAPPINGS.keys.freeze
40
40
 
41
- # Description content that complements the item's label. See `ActionList`'s `description_scheme` argument
42
- # for layout options.
43
- renders_one :description
41
+ # Description content that complements the item's label, with optional test_selector.
42
+ # See `ActionList`'s `description_scheme` argument for layout options.
43
+ #
44
+ # @param legacy_content [String] Slot content, provided for backwards-compatibility. Pass a content block instead, or call `with_content`, eg. `component.with_description { "My description" }` or `component.with_description.with_content("My description")`.
45
+ # @param test_selector [String] The value of this argument is set as the value of a `data-test-selector` HTML attribute on the description element.
46
+ renders_one :description, -> (legacy_content = nil, test_selector: nil) do
47
+ Primer::BaseComponent.new(tag: "span", classes: "ActionListItem-description", test_selector: test_selector).tap do |desc|
48
+ desc.with_content(legacy_content) if legacy_content
49
+ end
50
+ end
44
51
 
45
52
  # An icon, avatar, SVG, or custom content that will render to the left of the label.
46
53
  #
@@ -1 +1 @@
1
- .SegmentedControl{--segmentedControl-item-padding:var(--control-small-paddingBlock);--overlay-offset:0.5rem;background-color:var(--controlTrack-bgColor-rest,var(--color-segmented-control-bg));border-radius:var(--borderRadius-medium);display:inline-flex;list-style:none}.SegmentedControl--iconOnly .Button--iconOnly.Button--medium,.SegmentedControl--iconOnly .Button--iconOnly.Button--small{padding-inline:0!important;width:100%}.SegmentedControl--small{--segmentedControl-item-padding:var(--control-xsmall-paddingBlock)}.SegmentedControl--small .SegmentedControl-item{height:var(--control-small-size)}.SegmentedControl--small .SegmentedControl-item .Button{padding-inline:calc(var(--control-xsmall-paddingInline-normal) - var(--segmentedControl-item-padding))}.SegmentedControl--small.SegmentedControl--iconOnly .SegmentedControl-item{width:var(--control-small-size)}.SegmentedControl--medium .SegmentedControl-item{height:var(--control-medium-size)}.SegmentedControl--medium.SegmentedControl--iconOnly .SegmentedControl-item{width:var(--control-medium-size)}.SegmentedControl-item{border:var(--borderWidth-thin) solid #0000;border-radius:var(--borderRadius-medium);display:inline-flex;height:var(--control-medium-size);justify-content:center;padding:var(--segmentedControl-item-padding);position:relative}.SegmentedControl-item .Button--invisible:hover:not(:disabled){background-color:var(--controlTrack-bgColor-hover,var(--color-action-list-item-default-hover-bg))}.SegmentedControl-item .Button--invisible:active:not(:disabled){background-color:var(--controlTrack-bgColor-active,var(--color-action-list-item-default-active-bg))}.SegmentedControl-item.SegmentedControl-item--selected{background-color:var(--controlKnob-bgColor-rest,var(--color-segmented-control-button-bg));border-color:var(--controlKnob-borderColor-rest,var(--color-segmented-control-button-selected-border))}.SegmentedControl-item.SegmentedControl-item--selected .Button{font-weight:var(--base-text-weight-semibold)}.SegmentedControl-item.SegmentedControl-item--selected .Button:hover{background-color:initial}.SegmentedControl-item.SegmentedControl-item--selected:before{border-color:#0000!important}.SegmentedControl-item.SegmentedControl-item--selected+.SegmentedControl-item:before{border-color:#0000}.SegmentedControl-item .Button-label[data-content]:before{content:attr(data-content);display:block;font-weight:var(--base-text-weight-semibold);height:0;visibility:hidden}.SegmentedControl-item:not(:first-child):before{border-left:var(--borderWidth-thin) solid var(--borderColor-default);content:"";inset:0 0 0 -1px;margin-bottom:var(--control-medium-paddingBlock);margin-top:var(--control-medium-paddingBlock);position:absolute}.SegmentedControl-item .Button{border:0;border-radius:calc(var(--borderRadius-medium) - var(--segmentedControl-item-padding)/2);font-weight:var(--base-text-weight-normal);height:100%;min-width:-moz-fit-content;min-width:fit-content;padding-inline:calc(var(--control-medium-paddingInline-normal) - var(--segmentedControl-item-padding));width:100%}.SegmentedControl-item .Button:focus-visible{border-radius:calc(var(--borderRadius-medium) - var(--segmentedControl-item-padding)/1);outline-offset:calc(var(--segmentedControl-item-padding) - var(--borderWidth-thin))}.SegmentedControl-item .Button--invisible.Button--invisible-noVisuals .Button-label{color:var(--button-default-fgColor-rest)}.SegmentedControl-item .Button-content{align-self:stretch;flex:1 1 auto}.SegmentedControl-item .Button-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.SegmentedControl--fullWidth{display:flex}.SegmentedControl--fullWidth .SegmentedControl-item{flex:1;justify-content:center}
1
+ .SegmentedControl{--segmentedControl-item-padding:var(--control-small-paddingBlock);--overlay-offset:0.5rem;background-color:var(--controlTrack-bgColor-rest,var(--color-segmented-control-bg));border-color:var(--controlTrack-borderColor-rest,#0000);border-radius:var(--borderRadius-medium);display:inline-flex;list-style:none}.SegmentedControl--iconOnly .Button--iconOnly.Button--medium,.SegmentedControl--iconOnly .Button--iconOnly.Button--small{padding-inline:0!important;width:100%}.SegmentedControl--small{--segmentedControl-item-padding:var(--control-xsmall-paddingBlock)}.SegmentedControl--small .SegmentedControl-item{height:var(--control-small-size)}.SegmentedControl--small .SegmentedControl-item .Button{padding-inline:calc(var(--control-xsmall-paddingInline-normal) - var(--segmentedControl-item-padding))}.SegmentedControl--small.SegmentedControl--iconOnly .SegmentedControl-item{width:var(--control-small-size)}.SegmentedControl--medium .SegmentedControl-item{height:var(--control-medium-size)}.SegmentedControl--medium.SegmentedControl--iconOnly .SegmentedControl-item{width:var(--control-medium-size)}.SegmentedControl-item{border:var(--borderWidth-thin) solid #0000;border-radius:var(--borderRadius-medium);display:inline-flex;height:var(--control-medium-size);justify-content:center;padding:var(--segmentedControl-item-padding);position:relative}.SegmentedControl-item .Button--invisible:hover:not(:disabled){background-color:var(--controlTrack-bgColor-hover,var(--color-action-list-item-default-hover-bg))}.SegmentedControl-item .Button--invisible:active:not(:disabled){background-color:var(--controlTrack-bgColor-active,var(--color-action-list-item-default-active-bg))}.SegmentedControl-item.SegmentedControl-item--selected{background-color:var(--controlKnob-bgColor-rest,var(--color-segmented-control-button-bg));border-color:var(--controlKnob-borderColor-rest,var(--color-segmented-control-button-selected-border))}.SegmentedControl-item.SegmentedControl-item--selected .Button{font-weight:var(--base-text-weight-semibold)}.SegmentedControl-item.SegmentedControl-item--selected .Button:hover{background-color:initial}.SegmentedControl-item.SegmentedControl-item--selected:before{border-color:#0000!important}.SegmentedControl-item.SegmentedControl-item--selected+.SegmentedControl-item:before{border-color:#0000}.SegmentedControl-item .Button-label[data-content]:before{content:attr(data-content);display:block;font-weight:var(--base-text-weight-semibold);height:0;visibility:hidden}.SegmentedControl-item:not(:first-child):before{border-left:var(--borderWidth-thin) solid var(--borderColor-default);content:"";inset:0 0 0 -1px;margin-bottom:var(--control-medium-paddingBlock);margin-top:var(--control-medium-paddingBlock);position:absolute}.SegmentedControl-item .Button{border:0;border-radius:calc(var(--borderRadius-medium) - var(--segmentedControl-item-padding)/2);font-weight:var(--base-text-weight-normal);height:100%;min-width:-moz-fit-content;min-width:fit-content;padding-inline:calc(var(--control-medium-paddingInline-normal) - var(--segmentedControl-item-padding));width:100%}.SegmentedControl-item .Button:focus-visible{border-radius:calc(var(--borderRadius-medium) - var(--segmentedControl-item-padding)/1);outline-offset:calc(var(--segmentedControl-item-padding) - var(--borderWidth-thin))}.SegmentedControl-item .Button--invisible.Button--invisible-noVisuals .Button-label{color:var(--button-default-fgColor-rest)}.SegmentedControl-item .Button-content{align-self:stretch;flex:1 1 auto}.SegmentedControl-item .Button-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.SegmentedControl--fullWidth{display:flex}.SegmentedControl--fullWidth .SegmentedControl-item{flex:1;justify-content:center}
@@ -1 +1 @@
1
- {"version":3,"sources":["segmented_control.pcss"],"names":[],"mappings":"AAEA,kBACE,iEAAkE,CAClE,uBAAwB,CAIxB,mFAAqF,CACrF,wCAAyC,CAHzC,mBAAoB,CACpB,eAGF,CAGE,yHAGE,0BAA4B,CAD5B,UAEF,CAKF,yBACE,kEAeF,CAbE,gDACE,gCAKF,CAHE,wDACE,sGACF,CAIA,2EACE,+BACF,CAKF,iDACE,iCACF,CAGE,4EACE,gCACF,CAMJ,uBAIE,0CAAiD,CACjD,wCAAyC,CAHzC,mBAAoB,CAIpB,iCAAkC,CAHlC,sBAAuB,CAIvB,4CAA6C,CAN7C,iBA6FF,CAnFI,+DACE,iGACF,CAEA,gEACE,mGACF,CAIF,uDACE,yFAA2F,CAC3F,sGAiBF,CAfE,+DACE,4CAKF,CAHE,qEACE,wBACF,CAGF,8DACE,4BACF,CAEA,qFACE,kBACF,CAIF,0DAKE,0BAA2B,CAJ3B,aAAc,CAEd,4CAA6C,CAD7C,QAAS,CAET,iBAEF,CAIE,gDAME,oEAAqE,CADrE,UAAW,CAHX,gBAAiB,CAEjB,gDAAiD,CADjD,6CAA8C,CAF9C,iBAMF,CAIF,+BAGE,QAAS,CAET,uFAA0F,CAD1F,0CAA2C,CAH3C,WAAY,CAMZ,0BAAsB,CAAtB,qBAAsB,CADtB,sGAAuG,CAJvG,UAWF,CAJE,6CAEE,uFAA0F,CAD1F,mFAEF,CAGF,oFACE,wCACF,CAEA,uCAEE,kBAAmB,CADnB,aAEF,CAGA,qCAEE,eAAgB,CAChB,sBAAuB,CAFvB,kBAGF,CAIF,6BACE,YAMF,CAJE,oDACE,MAAO,CACP,sBACF","file":"segmented_control.css","sourcesContent":["/* SegmentedControl */\n\n.SegmentedControl {\n --segmentedControl-item-padding: var(--control-small-paddingBlock);\n --overlay-offset: 0.5rem;\n\n display: inline-flex;\n list-style: none;\n background-color: var(--controlTrack-bgColor-rest, var(--color-segmented-control-bg));\n border-radius: var(--borderRadius-medium);\n}\n\n.SegmentedControl--iconOnly {\n & .Button--iconOnly.Button--small,\n & .Button--iconOnly.Button--medium {\n width: 100%;\n padding-inline: 0 !important;\n }\n}\n\n/* sizes */\n\n.SegmentedControl--small {\n --segmentedControl-item-padding: var(--control-xsmall-paddingBlock);\n\n & .SegmentedControl-item {\n height: var(--control-small-size);\n\n & .Button {\n padding-inline: calc(var(--control-xsmall-paddingInline-normal) - var(--segmentedControl-item-padding));\n }\n }\n\n &.SegmentedControl--iconOnly {\n & .SegmentedControl-item {\n width: var(--control-small-size);\n }\n }\n}\n\n.SegmentedControl--medium {\n & .SegmentedControl-item {\n height: var(--control-medium-size);\n }\n\n &.SegmentedControl--iconOnly {\n & .SegmentedControl-item {\n width: var(--control-medium-size);\n }\n }\n}\n\n/* item */\n\n.SegmentedControl-item {\n position: relative;\n display: inline-flex;\n justify-content: center;\n border: var(--borderWidth-thin) solid transparent;\n border-radius: var(--borderRadius-medium);\n height: var(--control-medium-size);\n padding: var(--segmentedControl-item-padding);\n\n /* button color overrides */\n & .Button--invisible {\n &:hover:not(:disabled) {\n background-color: var(--controlTrack-bgColor-hover, var(--color-action-list-item-default-hover-bg));\n }\n\n &:active:not(:disabled) {\n background-color: var(--controlTrack-bgColor-active, var(--color-action-list-item-default-active-bg));\n }\n }\n\n /* Selected ---------------------------------------- */\n &.SegmentedControl-item--selected {\n background-color: var(--controlKnob-bgColor-rest, var(--color-segmented-control-button-bg));\n border-color: var(--controlKnob-borderColor-rest, var(--color-segmented-control-button-selected-border));\n\n & .Button {\n font-weight: var(--base-text-weight-semibold);\n\n &:hover {\n background-color: transparent;\n }\n }\n\n &::before {\n border-color: transparent !important;\n }\n\n & + .SegmentedControl-item::before {\n border-color: transparent;\n }\n }\n\n /* renders a visibly hidden \"copy\" of the text in bold, reserving box space for when text becomes bold on selected */\n & .Button-label[data-content]::before {\n display: block;\n height: 0;\n font-weight: var(--base-text-weight-semibold);\n visibility: hidden;\n content: attr(data-content);\n }\n\n /* Separator lines */\n &:not(:first-child) {\n &::before {\n position: absolute;\n inset: 0 0 0 -1px;\n margin-top: var(--control-medium-paddingBlock);\n margin-bottom: var(--control-medium-paddingBlock);\n content: '';\n border-left: var(--borderWidth-thin) solid var(--borderColor-default);\n }\n }\n\n /* Button ----------------------------------------- */\n & .Button {\n height: 100%;\n width: 100%;\n border: 0;\n font-weight: var(--base-text-weight-normal);\n border-radius: calc(var(--borderRadius-medium) - var(--segmentedControl-item-padding) / 2);\n padding-inline: calc(var(--control-medium-paddingInline-normal) - var(--segmentedControl-item-padding));\n min-width: fit-content;\n\n &:focus-visible {\n outline-offset: calc(var(--segmentedControl-item-padding) - var(--borderWidth-thin));\n border-radius: calc(var(--borderRadius-medium) - var(--segmentedControl-item-padding) / 1);\n }\n }\n\n & .Button--invisible.Button--invisible-noVisuals .Button-label {\n color: var(--button-default-fgColor-rest);\n }\n\n & .Button-content {\n flex: 1 1 auto;\n align-self: stretch;\n }\n\n /* use ellipsis with the assumption that icon only variant will be used when not enough space is available */\n & .Button-label {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n}\n\n/* fullWidth */\n.SegmentedControl--fullWidth {\n display: flex;\n\n & .SegmentedControl-item {\n flex: 1;\n justify-content: center;\n }\n}\n"]}
1
+ {"version":3,"sources":["segmented_control.pcss"],"names":[],"mappings":"AAEA,kBACE,iEAAkE,CAClE,uBAAwB,CAIxB,mFAAqF,CACrF,uDAA+D,CAC/D,wCAAyC,CAJzC,mBAAoB,CACpB,eAIF,CAGE,yHAGE,0BAA4B,CAD5B,UAEF,CAKF,yBACE,kEAeF,CAbE,gDACE,gCAKF,CAHE,wDACE,sGACF,CAIA,2EACE,+BACF,CAKF,iDACE,iCACF,CAGE,4EACE,gCACF,CAMJ,uBAIE,0CAAiD,CACjD,wCAAyC,CAHzC,mBAAoB,CAIpB,iCAAkC,CAHlC,sBAAuB,CAIvB,4CAA6C,CAN7C,iBA6FF,CAnFI,+DACE,iGACF,CAEA,gEACE,mGACF,CAIF,uDACE,yFAA2F,CAC3F,sGAiBF,CAfE,+DACE,4CAKF,CAHE,qEACE,wBACF,CAGF,8DACE,4BACF,CAEA,qFACE,kBACF,CAIF,0DAKE,0BAA2B,CAJ3B,aAAc,CAEd,4CAA6C,CAD7C,QAAS,CAET,iBAEF,CAIE,gDAME,oEAAqE,CADrE,UAAW,CAHX,gBAAiB,CAEjB,gDAAiD,CADjD,6CAA8C,CAF9C,iBAMF,CAIF,+BAGE,QAAS,CAET,uFAA0F,CAD1F,0CAA2C,CAH3C,WAAY,CAMZ,0BAAsB,CAAtB,qBAAsB,CADtB,sGAAuG,CAJvG,UAWF,CAJE,6CAEE,uFAA0F,CAD1F,mFAEF,CAGF,oFACE,wCACF,CAEA,uCAEE,kBAAmB,CADnB,aAEF,CAGA,qCAEE,eAAgB,CAChB,sBAAuB,CAFvB,kBAGF,CAIF,6BACE,YAMF,CAJE,oDACE,MAAO,CACP,sBACF","file":"segmented_control.css","sourcesContent":["/* SegmentedControl */\n\n.SegmentedControl {\n --segmentedControl-item-padding: var(--control-small-paddingBlock);\n --overlay-offset: 0.5rem;\n\n display: inline-flex;\n list-style: none;\n background-color: var(--controlTrack-bgColor-rest, var(--color-segmented-control-bg));\n border-color: var(--controlTrack-borderColor-rest, transparent);\n border-radius: var(--borderRadius-medium);\n}\n\n.SegmentedControl--iconOnly {\n & .Button--iconOnly.Button--small,\n & .Button--iconOnly.Button--medium {\n width: 100%;\n padding-inline: 0 !important;\n }\n}\n\n/* sizes */\n\n.SegmentedControl--small {\n --segmentedControl-item-padding: var(--control-xsmall-paddingBlock);\n\n & .SegmentedControl-item {\n height: var(--control-small-size);\n\n & .Button {\n padding-inline: calc(var(--control-xsmall-paddingInline-normal) - var(--segmentedControl-item-padding));\n }\n }\n\n &.SegmentedControl--iconOnly {\n & .SegmentedControl-item {\n width: var(--control-small-size);\n }\n }\n}\n\n.SegmentedControl--medium {\n & .SegmentedControl-item {\n height: var(--control-medium-size);\n }\n\n &.SegmentedControl--iconOnly {\n & .SegmentedControl-item {\n width: var(--control-medium-size);\n }\n }\n}\n\n/* item */\n\n.SegmentedControl-item {\n position: relative;\n display: inline-flex;\n justify-content: center;\n border: var(--borderWidth-thin) solid transparent;\n border-radius: var(--borderRadius-medium);\n height: var(--control-medium-size);\n padding: var(--segmentedControl-item-padding);\n\n /* button color overrides */\n & .Button--invisible {\n &:hover:not(:disabled) {\n background-color: var(--controlTrack-bgColor-hover, var(--color-action-list-item-default-hover-bg));\n }\n\n &:active:not(:disabled) {\n background-color: var(--controlTrack-bgColor-active, var(--color-action-list-item-default-active-bg));\n }\n }\n\n /* Selected ---------------------------------------- */\n &.SegmentedControl-item--selected {\n background-color: var(--controlKnob-bgColor-rest, var(--color-segmented-control-button-bg));\n border-color: var(--controlKnob-borderColor-rest, var(--color-segmented-control-button-selected-border));\n\n & .Button {\n font-weight: var(--base-text-weight-semibold);\n\n &:hover {\n background-color: transparent;\n }\n }\n\n &::before {\n border-color: transparent !important;\n }\n\n & + .SegmentedControl-item::before {\n border-color: transparent;\n }\n }\n\n /* renders a visibly hidden \"copy\" of the text in bold, reserving box space for when text becomes bold on selected */\n & .Button-label[data-content]::before {\n display: block;\n height: 0;\n font-weight: var(--base-text-weight-semibold);\n visibility: hidden;\n content: attr(data-content);\n }\n\n /* Separator lines */\n &:not(:first-child) {\n &::before {\n position: absolute;\n inset: 0 0 0 -1px;\n margin-top: var(--control-medium-paddingBlock);\n margin-bottom: var(--control-medium-paddingBlock);\n content: '';\n border-left: var(--borderWidth-thin) solid var(--borderColor-default);\n }\n }\n\n /* Button ----------------------------------------- */\n & .Button {\n height: 100%;\n width: 100%;\n border: 0;\n font-weight: var(--base-text-weight-normal);\n border-radius: calc(var(--borderRadius-medium) - var(--segmentedControl-item-padding) / 2);\n padding-inline: calc(var(--control-medium-paddingInline-normal) - var(--segmentedControl-item-padding));\n min-width: fit-content;\n\n &:focus-visible {\n outline-offset: calc(var(--segmentedControl-item-padding) - var(--borderWidth-thin));\n border-radius: calc(var(--borderRadius-medium) - var(--segmentedControl-item-padding) / 1);\n }\n }\n\n & .Button--invisible.Button--invisible-noVisuals .Button-label {\n color: var(--button-default-fgColor-rest);\n }\n\n & .Button-content {\n flex: 1 1 auto;\n align-self: stretch;\n }\n\n /* use ellipsis with the assumption that icon only variant will be used when not enough space is available */\n & .Button-label {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n}\n\n/* fullWidth */\n.SegmentedControl--fullWidth {\n display: flex;\n\n & .SegmentedControl-item {\n flex: 1;\n justify-content: center;\n }\n}\n"]}
@@ -7,6 +7,7 @@
7
7
  display: inline-flex;
8
8
  list-style: none;
9
9
  background-color: var(--controlTrack-bgColor-rest, var(--color-segmented-control-bg));
10
+ border-color: var(--controlTrack-borderColor-rest, transparent);
10
11
  border-radius: var(--borderRadius-medium);
11
12
  }
12
13
 
@@ -401,6 +401,7 @@ module Primer
401
401
 
402
402
  @dialog = Primer::BaseComponent.new(
403
403
  id: "#{@panel_id}-dialog",
404
+ "aria-labelledby": "#{@panel_id}-dialog-title",
404
405
  tag: :dialog,
405
406
  data: { target: "select-panel.dialog" },
406
407
  classes: class_names(
@@ -460,7 +461,7 @@ module Primer
460
461
 
461
462
  system_arguments[:aria] = merge_aria(
462
463
  system_arguments,
463
- { aria: { controls: "#{@panel_id}-dialog" } }
464
+ { aria: { controls: "#{@panel_id}-dialog", "haspopup": "dialog", "expanded": "false" } }
464
465
  )
465
466
 
466
467
  Primer::Beta::Button.new(**system_arguments)
@@ -6,7 +6,6 @@ type SelectedItem = {
6
6
  label: string | null | undefined;
7
7
  value: string | null | undefined;
8
8
  inputName: string | null | undefined;
9
- element: SelectPanelItem;
10
9
  };
11
10
  export type SelectPanelItem = HTMLLIElement;
12
11
  export type FilterFn = (item: SelectPanelItem, query: string) => boolean;
@@ -15,7 +15,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
15
15
  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");
16
16
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
17
17
  };
18
- var _SelectPanelElement_instances, _SelectPanelElement_dialogIntersectionObserver, _SelectPanelElement_abortController, _SelectPanelElement_originalLabel, _SelectPanelElement_inputName, _SelectPanelElement_selectedItems, _SelectPanelElement_loadingDelayTimeoutId, _SelectPanelElement_loadingAnnouncementTimeoutId, _SelectPanelElement_waitForCondition, _SelectPanelElement_softDisableItems, _SelectPanelElement_updateTabIndices, _SelectPanelElement_potentiallyDisallowActivation, _SelectPanelElement_isAnchorActivationViaSpace, _SelectPanelElement_isActivation, _SelectPanelElement_checkSelectedItems, _SelectPanelElement_addSelectedItem, _SelectPanelElement_removeSelectedItem, _SelectPanelElement_setTextFieldLoadingSpinnerTimer, _SelectPanelElement_handleIncludeFragmentEvent, _SelectPanelElement_toggleIncludeFragmentElements, _SelectPanelElement_handleRemoteInputEvent, _SelectPanelElement_defaultFilterFn, _SelectPanelElement_handleSearchFieldEvent, _SelectPanelElement_updateItemVisibility, _SelectPanelElement_inErrorState, _SelectPanelElement_setErrorState, _SelectPanelElement_clearErrorState, _SelectPanelElement_maybeAnnounce, _SelectPanelElement_fetchStrategy_get, _SelectPanelElement_filterInputTextFieldElement_get, _SelectPanelElement_performFilteringLocally, _SelectPanelElement_handleInvokerActivated, _SelectPanelElement_handleDialogItemActivated, _SelectPanelElement_handleItemActivated, _SelectPanelElement_setDynamicLabel, _SelectPanelElement_updateInput, _SelectPanelElement_firstItem_get, _SelectPanelElement_hideItem, _SelectPanelElement_showItem, _SelectPanelElement_getItemContent;
18
+ var _SelectPanelElement_instances, _SelectPanelElement_dialogIntersectionObserver, _SelectPanelElement_abortController, _SelectPanelElement_originalLabel, _SelectPanelElement_inputName, _SelectPanelElement_selectedItems, _SelectPanelElement_loadingDelayTimeoutId, _SelectPanelElement_loadingAnnouncementTimeoutId, _SelectPanelElement_hasLoadedData, _SelectPanelElement_waitForCondition, _SelectPanelElement_softDisableItems, _SelectPanelElement_updateTabIndices, _SelectPanelElement_potentiallyDisallowActivation, _SelectPanelElement_isAnchorActivationViaSpace, _SelectPanelElement_isActivation, _SelectPanelElement_checkSelectedItems, _SelectPanelElement_addSelectedItem, _SelectPanelElement_removeSelectedItem, _SelectPanelElement_setTextFieldLoadingSpinnerTimer, _SelectPanelElement_handleIncludeFragmentEvent, _SelectPanelElement_toggleIncludeFragmentElements, _SelectPanelElement_handleRemoteInputEvent, _SelectPanelElement_defaultFilterFn, _SelectPanelElement_handleSearchFieldEvent, _SelectPanelElement_updateItemVisibility, _SelectPanelElement_inErrorState, _SelectPanelElement_setErrorState, _SelectPanelElement_clearErrorState, _SelectPanelElement_maybeAnnounce, _SelectPanelElement_fetchStrategy_get, _SelectPanelElement_filterInputTextFieldElement_get, _SelectPanelElement_performFilteringLocally, _SelectPanelElement_handleInvokerActivated, _SelectPanelElement_handleDialogItemActivated, _SelectPanelElement_handleItemActivated, _SelectPanelElement_setDynamicLabel, _SelectPanelElement_updateInput, _SelectPanelElement_firstItem_get, _SelectPanelElement_hideItem, _SelectPanelElement_showItem, _SelectPanelElement_getItemContent;
19
19
  import { getAnchoredPosition } from '@primer/behaviors';
20
20
  import { controller, target } from '@github/catalyst';
21
21
  import { announceFromElement, announce } from '../aria_live';
@@ -55,6 +55,7 @@ const updateWhenVisible = (() => {
55
55
  }));
56
56
  resizeObserver.observe(el.ownerDocument.documentElement);
57
57
  el.addEventListener('dialog:close', () => {
58
+ el.invokerElement?.setAttribute('aria-expanded', 'false');
58
59
  anchors.delete(el);
59
60
  });
60
61
  el.addEventListener('dialog:open', () => {
@@ -73,6 +74,7 @@ let SelectPanelElement = class SelectPanelElement extends HTMLElement {
73
74
  _SelectPanelElement_selectedItems.set(this, new Map());
74
75
  _SelectPanelElement_loadingDelayTimeoutId.set(this, null);
75
76
  _SelectPanelElement_loadingAnnouncementTimeoutId.set(this, null);
77
+ _SelectPanelElement_hasLoadedData.set(this, false);
76
78
  }
77
79
  get open() {
78
80
  return this.dialog.open;
@@ -251,6 +253,7 @@ let SelectPanelElement = class SelectPanelElement extends HTMLElement {
251
253
  if (event.target === this.dialog && event.type === 'close') {
252
254
  // Remove data-ready so it can be set the next time the panel is opened
253
255
  this.dialog.removeAttribute('data-ready');
256
+ this.invokerElement?.setAttribute('aria-expanded', 'false');
254
257
  this.dispatchEvent(new CustomEvent('panelClosed', {
255
258
  detail: { panel: this },
256
259
  bubbles: true,
@@ -300,6 +303,7 @@ let SelectPanelElement = class SelectPanelElement extends HTMLElement {
300
303
  show() {
301
304
  this.updateAnchorPosition();
302
305
  this.dialog.showModal();
306
+ this.invokerElement?.setAttribute('aria-expanded', 'true');
303
307
  const event = new CustomEvent('dialog:open', {
304
308
  detail: { dialog: this.dialog },
305
309
  });
@@ -385,6 +389,7 @@ _SelectPanelElement_inputName = new WeakMap();
385
389
  _SelectPanelElement_selectedItems = new WeakMap();
386
390
  _SelectPanelElement_loadingDelayTimeoutId = new WeakMap();
387
391
  _SelectPanelElement_loadingAnnouncementTimeoutId = new WeakMap();
392
+ _SelectPanelElement_hasLoadedData = new WeakMap();
388
393
  _SelectPanelElement_instances = new WeakSet();
389
394
  _SelectPanelElement_waitForCondition = function _SelectPanelElement_waitForCondition(condition, body) {
390
395
  if (condition()) {
@@ -422,7 +427,7 @@ _SelectPanelElement_updateTabIndices = function _SelectPanelElement_updateTabInd
422
427
  itemContent.setAttribute('tabindex', '-1');
423
428
  }
424
429
  // <li> elements should not themselves be tabbable
425
- item.setAttribute('tabindex', '-1');
430
+ item.removeAttribute('tabindex');
426
431
  }
427
432
  }
428
433
  else {
@@ -437,7 +442,7 @@ _SelectPanelElement_updateTabIndices = function _SelectPanelElement_updateTabInd
437
442
  itemContent.setAttribute('tabindex', '-1');
438
443
  }
439
444
  // <li> elements should not themselves be tabbable
440
- item.setAttribute('tabindex', '-1');
445
+ item.removeAttribute('tabindex');
441
446
  }
442
447
  }
443
448
  if (!setZeroTabIndex && __classPrivateFieldGet(this, _SelectPanelElement_instances, "a", _SelectPanelElement_firstItem_get)) {
@@ -497,12 +502,14 @@ _SelectPanelElement_addSelectedItem = function _SelectPanelElement_addSelectedIt
497
502
  value,
498
503
  label: itemContent.querySelector('.ActionListItem-label')?.textContent?.trim(),
499
504
  inputName: itemContent.getAttribute('data-input-name'),
500
- element: item,
501
505
  });
502
506
  }
503
507
  };
504
508
  _SelectPanelElement_removeSelectedItem = function _SelectPanelElement_removeSelectedItem(item) {
505
- const value = item.getAttribute('data-value');
509
+ const itemContent = __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_getItemContent).call(this, item);
510
+ if (!itemContent)
511
+ return;
512
+ const value = itemContent.getAttribute('data-value');
506
513
  if (value) {
507
514
  __classPrivateFieldGet(this, _SelectPanelElement_selectedItems, "f").delete(value);
508
515
  }
@@ -604,27 +611,33 @@ _SelectPanelElement_handleSearchFieldEvent = function _SelectPanelElement_handle
604
611
  if (key === 'Enter') {
605
612
  const item = this.visibleItems[0];
606
613
  if (item) {
607
- __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_handleItemActivated).call(this, item, false);
614
+ const itemContent = __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_getItemContent).call(this, item);
615
+ if (itemContent)
616
+ itemContent.click();
608
617
  }
609
618
  }
610
619
  else if (key === 'ArrowDown') {
611
- const item = (this.focusableItem || this.visibleItems[0]);
620
+ const item = (this.focusableItem || __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_getItemContent).call(this, this.visibleItems[0]));
612
621
  if (item) {
613
- __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_getItemContent).call(this, item).focus();
622
+ item.focus();
614
623
  event.preventDefault();
615
624
  }
616
625
  }
617
626
  else if (key === 'Home') {
618
627
  const item = this.visibleItems[0];
619
628
  if (item) {
620
- __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_getItemContent).call(this, item).focus();
629
+ const itemContent = __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_getItemContent).call(this, item);
630
+ if (itemContent)
631
+ itemContent.focus();
621
632
  event.preventDefault();
622
633
  }
623
634
  }
624
635
  else if (key === 'End') {
625
636
  if (this.visibleItems.length > 0) {
626
637
  const item = this.visibleItems[this.visibleItems.length - 1];
627
- __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_getItemContent).call(this, item).focus();
638
+ const itemContent = __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_getItemContent).call(this, item);
639
+ if (itemContent)
640
+ itemContent.focus();
628
641
  event.preventDefault();
629
642
  }
630
643
  }
@@ -672,7 +685,13 @@ _SelectPanelElement_updateItemVisibility = function _SelectPanelElement_updateIt
672
685
  if (!itemContent)
673
686
  continue;
674
687
  const value = itemContent.getAttribute('data-value');
675
- if (value && !__classPrivateFieldGet(this, _SelectPanelElement_selectedItems, "f").has(value) && this.isItemChecked(item)) {
688
+ if (__classPrivateFieldGet(this, _SelectPanelElement_hasLoadedData, "f")) {
689
+ if (value && !__classPrivateFieldGet(this, _SelectPanelElement_selectedItems, "f").has(value)) {
690
+ itemContent.setAttribute(this.ariaSelectionType, 'false');
691
+ }
692
+ }
693
+ else if (value && !__classPrivateFieldGet(this, _SelectPanelElement_selectedItems, "f").has(value) && this.isItemChecked(item)) {
694
+ __classPrivateFieldSet(this, _SelectPanelElement_hasLoadedData, true, "f");
676
695
  __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_addSelectedItem).call(this, item);
677
696
  }
678
697
  }
@@ -786,7 +805,7 @@ _SelectPanelElement_handleDialogItemActivated = function _SelectPanelElement_han
786
805
  dialog.addEventListener('close', handleDialogClose, { signal });
787
806
  dialog.addEventListener('cancel', handleDialogClose, { signal });
788
807
  };
789
- _SelectPanelElement_handleItemActivated = function _SelectPanelElement_handleItemActivated(item, shouldClose = true) {
808
+ _SelectPanelElement_handleItemActivated = function _SelectPanelElement_handleItemActivated(item) {
790
809
  // Hide popover after current event loop to prevent changes in focus from
791
810
  // altering the target of the event. Not doing this specifically affects
792
811
  // <a> tags. It causes the event to be sent to the currently focused element
@@ -795,7 +814,7 @@ _SelectPanelElement_handleItemActivated = function _SelectPanelElement_handleIte
795
814
  // works fine.
796
815
  if (this.selectVariant !== 'multiple') {
797
816
  setTimeout(() => {
798
- if (this.open && shouldClose) {
817
+ if (this.open) {
799
818
  this.hide();
800
819
  }
801
820
  });
@@ -814,17 +833,17 @@ _SelectPanelElement_handleItemActivated = function _SelectPanelElement_handleIte
814
833
  return;
815
834
  const itemContent = __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_getItemContent).call(this, item);
816
835
  if (this.selectVariant === 'single') {
836
+ const value = this.selectedItems[0]?.value;
837
+ const element = this.visibleItems.find(el => __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_getItemContent).call(this, el)?.getAttribute('data-value') === value);
838
+ if (element) {
839
+ __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_getItemContent).call(this, element)?.setAttribute(this.ariaSelectionType, 'false');
840
+ }
841
+ __classPrivateFieldGet(this, _SelectPanelElement_selectedItems, "f").clear();
817
842
  // Only check, never uncheck here. Single-select mode does not allow unchecking a checked item.
818
843
  if (checked) {
819
844
  __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_addSelectedItem).call(this, item);
820
845
  itemContent?.setAttribute(this.ariaSelectionType, 'true');
821
846
  }
822
- for (const checkedItem of this.querySelectorAll(`[${this.ariaSelectionType}]`)) {
823
- if (checkedItem !== itemContent) {
824
- __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_removeSelectedItem).call(this, checkedItem);
825
- checkedItem.setAttribute(this.ariaSelectionType, 'false');
826
- }
827
- }
828
847
  __classPrivateFieldGet(this, _SelectPanelElement_instances, "m", _SelectPanelElement_setDynamicLabel).call(this);
829
848
  }
830
849
  else {
@@ -11,7 +11,6 @@ type SelectedItem = {
11
11
  label: string | null | undefined
12
12
  value: string | null | undefined
13
13
  inputName: string | null | undefined
14
- element: SelectPanelItem
15
14
  }
16
15
 
17
16
  const validSelectors = ['[role="option"]']
@@ -54,6 +53,7 @@ const updateWhenVisible = (() => {
54
53
  })
55
54
  resizeObserver.observe(el.ownerDocument.documentElement)
56
55
  el.addEventListener('dialog:close', () => {
56
+ el.invokerElement?.setAttribute('aria-expanded', 'false')
57
57
  anchors.delete(el)
58
58
  })
59
59
  el.addEventListener('dialog:open', () => {
@@ -84,6 +84,7 @@ export class SelectPanelElement extends HTMLElement {
84
84
  #selectedItems: Map<string, SelectedItem> = new Map()
85
85
  #loadingDelayTimeoutId: number | null = null
86
86
  #loadingAnnouncementTimeoutId: number | null = null
87
+ #hasLoadedData = false
87
88
 
88
89
  get open(): boolean {
89
90
  return this.dialog.open
@@ -306,7 +307,7 @@ export class SelectPanelElement extends HTMLElement {
306
307
  }
307
308
 
308
309
  // <li> elements should not themselves be tabbable
309
- item.setAttribute('tabindex', '-1')
310
+ item.removeAttribute('tabindex')
310
311
  }
311
312
  } else {
312
313
  for (const item of this.items) {
@@ -320,7 +321,7 @@ export class SelectPanelElement extends HTMLElement {
320
321
  }
321
322
 
322
323
  // <li> elements should not themselves be tabbable
323
- item.setAttribute('tabindex', '-1')
324
+ item.removeAttribute('tabindex')
324
325
  }
325
326
  }
326
327
 
@@ -380,6 +381,7 @@ export class SelectPanelElement extends HTMLElement {
380
381
  }
381
382
  }
382
383
  }
384
+
383
385
  this.#updateInput()
384
386
  }
385
387
 
@@ -394,14 +396,15 @@ export class SelectPanelElement extends HTMLElement {
394
396
  value,
395
397
  label: itemContent.querySelector('.ActionListItem-label')?.textContent?.trim(),
396
398
  inputName: itemContent.getAttribute('data-input-name'),
397
- element: item,
398
399
  })
399
400
  }
400
401
  }
401
402
 
402
- #removeSelectedItem(item: Element) {
403
- const value = item.getAttribute('data-value')
403
+ #removeSelectedItem(item: SelectPanelItem) {
404
+ const itemContent = this.#getItemContent(item)
405
+ if (!itemContent) return
404
406
 
407
+ const value = itemContent.getAttribute('data-value')
405
408
  if (value) {
406
409
  this.#selectedItems.delete(value)
407
410
  }
@@ -463,6 +466,7 @@ export class SelectPanelElement extends HTMLElement {
463
466
  if (event.target === this.dialog && event.type === 'close') {
464
467
  // Remove data-ready so it can be set the next time the panel is opened
465
468
  this.dialog.removeAttribute('data-ready')
469
+ this.invokerElement?.setAttribute('aria-expanded', 'false')
466
470
 
467
471
  this.dispatchEvent(
468
472
  new CustomEvent('panelClosed', {
@@ -627,26 +631,29 @@ export class SelectPanelElement extends HTMLElement {
627
631
  const item = this.visibleItems[0] as HTMLLIElement | null
628
632
 
629
633
  if (item) {
630
- this.#handleItemActivated(item, false)
634
+ const itemContent = this.#getItemContent(item)
635
+ if (itemContent) itemContent.click()
631
636
  }
632
637
  } else if (key === 'ArrowDown') {
633
- const item = (this.focusableItem || this.visibleItems[0]) as HTMLLIElement
638
+ const item = (this.focusableItem || this.#getItemContent(this.visibleItems[0])) as HTMLLIElement
634
639
 
635
640
  if (item) {
636
- this.#getItemContent(item)!.focus()
641
+ item.focus()
637
642
  event.preventDefault()
638
643
  }
639
644
  } else if (key === 'Home') {
640
645
  const item = this.visibleItems[0] as HTMLLIElement | null
641
646
 
642
647
  if (item) {
643
- this.#getItemContent(item)!.focus()
648
+ const itemContent = this.#getItemContent(item)
649
+ if (itemContent) itemContent.focus()
644
650
  event.preventDefault()
645
651
  }
646
652
  } else if (key === 'End') {
647
653
  if (this.visibleItems.length > 0) {
648
654
  const item = this.visibleItems[this.visibleItems.length - 1] as HTMLLIElement
649
- this.#getItemContent(item)!.focus()
655
+ const itemContent = this.#getItemContent(item)
656
+ if (itemContent) itemContent.focus()
650
657
  event.preventDefault()
651
658
  }
652
659
  }
@@ -700,8 +707,12 @@ export class SelectPanelElement extends HTMLElement {
700
707
  if (!itemContent) continue
701
708
 
702
709
  const value = itemContent.getAttribute('data-value')
703
-
704
- if (value && !this.#selectedItems.has(value) && this.isItemChecked(item)) {
710
+ if (this.#hasLoadedData) {
711
+ if (value && !this.#selectedItems.has(value)) {
712
+ itemContent.setAttribute(this.ariaSelectionType, 'false')
713
+ }
714
+ } else if (value && !this.#selectedItems.has(value) && this.isItemChecked(item)) {
715
+ this.#hasLoadedData = true
705
716
  this.#addSelectedItem(item)
706
717
  }
707
718
  }
@@ -829,7 +840,7 @@ export class SelectPanelElement extends HTMLElement {
829
840
  dialog.addEventListener('cancel', handleDialogClose, {signal})
830
841
  }
831
842
 
832
- #handleItemActivated(item: SelectPanelItem, shouldClose: boolean = true) {
843
+ #handleItemActivated(item: SelectPanelItem) {
833
844
  // Hide popover after current event loop to prevent changes in focus from
834
845
  // altering the target of the event. Not doing this specifically affects
835
846
  // <a> tags. It causes the event to be sent to the currently focused element
@@ -838,7 +849,7 @@ export class SelectPanelElement extends HTMLElement {
838
849
  // works fine.
839
850
  if (this.selectVariant !== 'multiple') {
840
851
  setTimeout(() => {
841
- if (this.open && shouldClose) {
852
+ if (this.open) {
842
853
  this.hide()
843
854
  }
844
855
  })
@@ -863,19 +874,21 @@ export class SelectPanelElement extends HTMLElement {
863
874
  const itemContent = this.#getItemContent(item)
864
875
 
865
876
  if (this.selectVariant === 'single') {
877
+ const value = this.selectedItems[0]?.value
878
+ const element = this.visibleItems.find(el => this.#getItemContent(el)?.getAttribute('data-value') === value)
879
+
880
+ if (element) {
881
+ this.#getItemContent(element)?.setAttribute(this.ariaSelectionType, 'false')
882
+ }
883
+
884
+ this.#selectedItems.clear()
885
+
866
886
  // Only check, never uncheck here. Single-select mode does not allow unchecking a checked item.
867
887
  if (checked) {
868
888
  this.#addSelectedItem(item)
869
889
  itemContent?.setAttribute(this.ariaSelectionType, 'true')
870
890
  }
871
891
 
872
- for (const checkedItem of this.querySelectorAll(`[${this.ariaSelectionType}]`)) {
873
- if (checkedItem !== itemContent) {
874
- this.#removeSelectedItem(checkedItem)
875
- checkedItem.setAttribute(this.ariaSelectionType, 'false')
876
- }
877
- }
878
-
879
892
  this.#setDynamicLabel()
880
893
  } else {
881
894
  // multi-select mode allows unchecking a checked item
@@ -902,6 +915,7 @@ export class SelectPanelElement extends HTMLElement {
902
915
  show() {
903
916
  this.updateAnchorPosition()
904
917
  this.dialog.showModal()
918
+ this.invokerElement?.setAttribute('aria-expanded', 'true')
905
919
  const event = new CustomEvent('dialog:open', {
906
920
  detail: {dialog: this.dialog},
907
921
  })
@@ -86,7 +86,7 @@ class ToolTipElement extends HTMLElement {
86
86
  --tooltip-left: var(--tool-tip-position-left, 0);
87
87
  padding: var(--overlay-paddingBlock-condensed) var(--overlay-padding-condensed) !important;
88
88
  font: var(--text-body-shorthand-small);
89
- color: var(--fgColor-onEmphasis, var(--color-fg-on-emphasis)) !important;
89
+ color: var(--tooltip-fgColor, var(--fgColor-onEmphasis)) !important;
90
90
  text-align: center;
91
91
  text-decoration: none;
92
92
  text-shadow: none;
@@ -94,7 +94,7 @@ class ToolTipElement extends HTMLElement {
94
94
  letter-spacing: normal;
95
95
  word-wrap: break-word;
96
96
  white-space: pre;
97
- background: var(--bgColor-emphasis, var(--color-neutral-emphasis-plus)) !important;
97
+ background: var(--tooltip-bgColor, var(--bgColor-emphasis)) !important;
98
98
  border-radius: var(--borderRadius-medium);
99
99
  border: 0 !important;
100
100
  opacity: 0;
@@ -71,7 +71,7 @@ class ToolTipElement extends HTMLElement {
71
71
  --tooltip-left: var(--tool-tip-position-left, 0);
72
72
  padding: var(--overlay-paddingBlock-condensed) var(--overlay-padding-condensed) !important;
73
73
  font: var(--text-body-shorthand-small);
74
- color: var(--fgColor-onEmphasis, var(--color-fg-on-emphasis)) !important;
74
+ color: var(--tooltip-fgColor, var(--fgColor-onEmphasis)) !important;
75
75
  text-align: center;
76
76
  text-decoration: none;
77
77
  text-shadow: none;
@@ -79,7 +79,7 @@ class ToolTipElement extends HTMLElement {
79
79
  letter-spacing: normal;
80
80
  word-wrap: break-word;
81
81
  white-space: pre;
82
- background: var(--bgColor-emphasis, var(--color-neutral-emphasis-plus)) !important;
82
+ background: var(--tooltip-bgColor, var(--bgColor-emphasis)) !important;
83
83
  border-radius: var(--borderRadius-medium);
84
84
  border: 0 !important;
85
85
  opacity: 0;
@@ -86,7 +86,7 @@ module Primer
86
86
 
87
87
  # @param datetime [Time] The time to be formatted.
88
88
  # @param tense [Symbol] Which tense to use. <%= one_of(Primer::Beta::RelativeTime::TENSE_OPTIONS) %>
89
- # @param prefix [sring] What to prefix the relative ime display with.
89
+ # @param prefix [String] What to prefix the relative time display with.
90
90
  # @param second [Symbol] What format seconds should take. <%= one_of(Primer::Beta::RelativeTime::SECOND_OPTIONS) %>
91
91
  # @param minute [Symbol] What format minues should take. <%= one_of(Primer::Beta::RelativeTime::MINUTE_OPTIONS) %>
92
92
  # @param hour [Symbol] What format hours should take. <%= one_of(Primer::Beta::RelativeTime::HOUR_OPTIONS) %>
@@ -95,12 +95,12 @@ module Primer
95
95
  # @param month [Symbol] What format months should take. <%= one_of(Primer::Beta::RelativeTime::MONTH_OPTIONS) %>
96
96
  # @param year [Symbol] What format years should take. <%= one_of(Primer::Beta::RelativeTime::YEAR_OPTIONS) %>
97
97
  # @param time_zone_name [Symbol] What format the time zone should take. <%= one_of(Primer::Beta::RelativeTime::TIMEZONENAME_OPTIONS) %>
98
- # @param threshold [string] The threshold, in ISO-8601 'durations' format, at which relative time displays become absolute.
98
+ # @param threshold [String] The threshold, in ISO-8601 'durations' format, at which relative time displays become absolute.
99
99
  # @param precision [Symbol] The precision elapsed time should display. <%= one_of(Primer::Beta::RelativeTime::PRECISION_OPTIONS) %>
100
100
  # @param format [Symbol] The format the display should take. <%= one_of(Primer::Beta::RelativeTime::FORMAT_OPTIONS) %>
101
101
  # @param format_style [Symbol] The format the display should take. <%= one_of(Primer::Beta::RelativeTime::FORMAT_STYLE_OPTIONS) %>
102
- # @param lang [string] The language to use.
103
- # @param title [string] Provide a custom title to the element.
102
+ # @param lang [String] The language to use.
103
+ # @param title [String] Provide a custom title to the element.
104
104
  # @param no_title [Boolean] Removes the `title` attribute provided on the element by default.
105
105
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
106
106
  def initialize(
@@ -1 +1 @@
1
- .State,.state{border-radius:2em;display:inline-block;font-size:var(--text-body-size-medium);font-weight:var(--base-text-weight-medium);line-height:var(--control-medium-lineBoxHeight);padding:5px var(--control-medium-paddingInline-normal);text-align:center;white-space:nowrap}.State,.State--draft,.state{background-color:var(--bgColor-neutral-emphasis);border:var(--borderWidth-thin) solid #0000;color:var(--fgColor-onEmphasis)}.State--open{background-color:var(--bgColor-open-emphasis,var(--color-open-emphasis))}.State--merged,.State--open{color:var(--fgColor-onEmphasis)}.State--merged{background-color:var(--bgColor-done-emphasis,var(--color-done-emphasis))}.State--closed{background-color:var(--bgColor-closed-emphasis,var(--color-closed-emphasis));color:var(--fgColor-onEmphasis)}.State--small{font-size:var(--text-body-size-small);line-height:var(--base-size-24);padding:0 10px}.State--small .octicon{width:1em}
1
+ .State,.state{border-radius:2em;display:inline-block;font-size:var(--text-body-size-medium);font-weight:var(--base-text-weight-medium);line-height:var(--control-medium-lineBoxHeight);padding:5px var(--control-medium-paddingInline-normal);text-align:center;white-space:nowrap}.State,.State--draft,.state{background-color:var(--bgColor-neutral-emphasis);border:var(--borderWidth-thin) solid #0000;box-shadow:var(--boxShadow-thin) var(--borderColor-neutral-emphasis);color:var(--fgColor-onEmphasis)}.State--open{background-color:var(--bgColor-open-emphasis,var(--color-open-emphasis));box-shadow:var(--boxShadow-thin) var(--borderColor-open-emphasis)}.State--merged,.State--open{color:var(--fgColor-onEmphasis)}.State--merged{background-color:var(--bgColor-done-emphasis,var(--color-done-emphasis));box-shadow:var(--boxShadow-thin) var(--borderColor-done-emphasis)}.State--closed{background-color:var(--bgColor-closed-emphasis,var(--color-closed-emphasis));box-shadow:var(--boxShadow-thin) var(--borderColor-closed-emphasis);color:var(--fgColor-onEmphasis)}.State--small{font-size:var(--text-body-size-small);line-height:var(--base-size-24);padding:0 10px}.State--small .octicon{width:1em}
@@ -1 +1 @@
1
- {"version":3,"sources":["state.pcss"],"names":[],"mappings":"AAIA,cASE,iBAAkB,CAPlB,oBAAqB,CAErB,sCAAuC,CACvC,0CAA2C,CAC3C,+CAAgD,CAHhD,sDAAuD,CAIvD,iBAAkB,CAClB,kBAEF,CAEA,4BAIE,gDAAiD,CACjD,0CAAiD,CAFjD,+BAGF,CAEA,aAEE,wEACF,CAEA,4BAJE,+BAOF,CAHA,eAEE,wEACF,CAEA,eAEE,4EAA8E,CAD9E,+BAEF,CAIA,cAEE,qCAAsC,CACtC,+BAAgC,CAFhC,cAOF,CAHE,uBACE,SACF","file":"state.css","sourcesContent":["/* State */\n\n/* Default 32px */\n\n.state, /* TODO: Deprecate */\n.State {\n display: inline-block;\n padding: 5px var(--control-medium-paddingInline-normal);\n font-size: var(--text-body-size-medium);\n font-weight: var(--base-text-weight-medium);\n line-height: var(--control-medium-lineBoxHeight);\n text-align: center;\n white-space: nowrap;\n border-radius: 2em;\n}\n\n.state, /* TODO: Deprecate */\n.State,\n.State--draft {\n color: var(--fgColor-onEmphasis);\n background-color: var(--bgColor-neutral-emphasis);\n border: var(--borderWidth-thin) solid transparent;\n}\n\n.State--open {\n color: var(--fgColor-onEmphasis);\n background-color: var(--bgColor-open-emphasis, var(--color-open-emphasis));\n}\n\n.State--merged {\n color: var(--fgColor-onEmphasis);\n background-color: var(--bgColor-done-emphasis, var(--color-done-emphasis));\n}\n\n.State--closed {\n color: var(--fgColor-onEmphasis);\n background-color: var(--bgColor-closed-emphasis, var(--color-closed-emphasis));\n}\n\n/* Small 24px */\n\n.State--small {\n padding: 0 10px;\n font-size: var(--text-body-size-small);\n line-height: var(--base-size-24);\n\n & .octicon {\n width: 1em; /* Ensures different icons don't change State indicator width */\n }\n}\n"]}
1
+ {"version":3,"sources":["state.pcss"],"names":[],"mappings":"AAIA,cASE,iBAAkB,CAPlB,oBAAqB,CAErB,sCAAuC,CACvC,0CAA2C,CAC3C,+CAAgD,CAHhD,sDAAuD,CAIvD,iBAAkB,CAClB,kBAEF,CAEA,4BAIE,gDAAiD,CACjD,0CAAiD,CACjD,oEAAqE,CAHrE,+BAIF,CAEA,aAEE,wEAA0E,CAC1E,iEACF,CAEA,4BALE,+BASF,CAJA,eAEE,wEAA0E,CAC1E,iEACF,CAEA,eAEE,4EAA8E,CAC9E,mEAAoE,CAFpE,+BAGF,CAIA,cAEE,qCAAsC,CACtC,+BAAgC,CAFhC,cAOF,CAHE,uBACE,SACF","file":"state.css","sourcesContent":["/* State */\n\n/* Default 32px */\n\n.state, /* TODO: Deprecate */\n.State {\n display: inline-block;\n padding: 5px var(--control-medium-paddingInline-normal);\n font-size: var(--text-body-size-medium);\n font-weight: var(--base-text-weight-medium);\n line-height: var(--control-medium-lineBoxHeight);\n text-align: center;\n white-space: nowrap;\n border-radius: 2em;\n}\n\n.state, /* TODO: Deprecate */\n.State,\n.State--draft {\n color: var(--fgColor-onEmphasis);\n background-color: var(--bgColor-neutral-emphasis);\n border: var(--borderWidth-thin) solid transparent;\n box-shadow: var(--boxShadow-thin) var(--borderColor-neutral-emphasis);\n}\n\n.State--open {\n color: var(--fgColor-onEmphasis);\n background-color: var(--bgColor-open-emphasis, var(--color-open-emphasis));\n box-shadow: var(--boxShadow-thin) var(--borderColor-open-emphasis);\n}\n\n.State--merged {\n color: var(--fgColor-onEmphasis);\n background-color: var(--bgColor-done-emphasis, var(--color-done-emphasis));\n box-shadow: var(--boxShadow-thin) var(--borderColor-done-emphasis);\n}\n\n.State--closed {\n color: var(--fgColor-onEmphasis);\n background-color: var(--bgColor-closed-emphasis, var(--color-closed-emphasis));\n box-shadow: var(--boxShadow-thin) var(--borderColor-closed-emphasis);\n}\n\n/* Small 24px */\n\n.State--small {\n padding: 0 10px;\n font-size: var(--text-body-size-small);\n line-height: var(--base-size-24);\n\n & .octicon {\n width: 1em; /* Ensures different icons don't change State indicator width */\n }\n}\n"]}
@@ -20,21 +20,25 @@
20
20
  color: var(--fgColor-onEmphasis);
21
21
  background-color: var(--bgColor-neutral-emphasis);
22
22
  border: var(--borderWidth-thin) solid transparent;
23
+ box-shadow: var(--boxShadow-thin) var(--borderColor-neutral-emphasis);
23
24
  }
24
25
 
25
26
  .State--open {
26
27
  color: var(--fgColor-onEmphasis);
27
28
  background-color: var(--bgColor-open-emphasis, var(--color-open-emphasis));
29
+ box-shadow: var(--boxShadow-thin) var(--borderColor-open-emphasis);
28
30
  }
29
31
 
30
32
  .State--merged {
31
33
  color: var(--fgColor-onEmphasis);
32
34
  background-color: var(--bgColor-done-emphasis, var(--color-done-emphasis));
35
+ box-shadow: var(--boxShadow-thin) var(--borderColor-done-emphasis);
33
36
  }
34
37
 
35
38
  .State--closed {
36
39
  color: var(--fgColor-onEmphasis);
37
40
  background-color: var(--bgColor-closed-emphasis, var(--color-closed-emphasis));
41
+ box-shadow: var(--boxShadow-thin) var(--borderColor-closed-emphasis);
38
42
  }
39
43
 
40
44
  /* Small 24px */
@@ -14,6 +14,13 @@ module ERBLint
14
14
  " https://primer.style/design/components/action-menu/rails/alpha"
15
15
  DETAILS_MENU_RUBY_PATTERN = /tag:?\s+:"details-menu"/.freeze
16
16
 
17
+ # Allow custom pattern matching for ERB nodes
18
+ class ConfigSchema < LinterConfig
19
+ property :custom_erb_pattern, accepts: array_of?(Regexp),
20
+ default: -> { [] }
21
+ end
22
+ self.config_schema = ConfigSchema
23
+
17
24
  def run(processed_source)
18
25
  # HTML tags
19
26
  tags(processed_source).each do |tag|
@@ -25,9 +32,31 @@ module ERBLint
25
32
  # ERB nodes
26
33
  erb_nodes(processed_source).each do |node|
27
34
  code = extract_ruby_from_erb_node(node)
28
- generate_node_offense(self.class, processed_source, node, MIGRATE_FROM_DETAILS_MENU) if code.match?(DETAILS_MENU_RUBY_PATTERN)
35
+
36
+ if contains_offense?(code)
37
+ generate_node_offense(self.class, processed_source, node, MIGRATE_FROM_DETAILS_MENU)
38
+ end
29
39
  end
30
40
  end
41
+
42
+ def contains_offense?(code)
43
+ return true if code.match?(DETAILS_MENU_RUBY_PATTERN)
44
+ return code.match?(custom_erb_pattern) if custom_erb_pattern
45
+ false
46
+ end
47
+
48
+ def custom_erb_pattern
49
+ unless defined?(@custom_erb_pattern)
50
+ @custom_erb_pattern =
51
+ if @config.custom_erb_pattern.empty?
52
+ nil
53
+ else
54
+ Regexp.new(@config.custom_erb_pattern.join("|"), true)
55
+ end
56
+ end
57
+
58
+ @custom_erb_pattern
59
+ end
31
60
  end
32
61
  end
33
62
  end