openproject-primer_view_components 0.41.1 → 0.42.0

Sign up to get free protection for your applications and to get access to all the features.
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