primer_view_components 0.18.1 → 0.19.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -0
- data/app/assets/javascripts/primer_view_components.js +1 -1
- data/app/assets/javascripts/primer_view_components.js.map +1 -1
- data/app/assets/styles/primer_view_components.css +1 -1
- data/app/assets/styles/primer_view_components.css.map +1 -1
- data/app/components/primer/alpha/action_bar_element.js +16 -10
- data/app/components/primer/alpha/action_bar_element.ts +10 -4
- data/app/components/primer/alpha/action_menu/action_menu_element.js +16 -20
- data/app/components/primer/alpha/action_menu/action_menu_element.ts +4 -1
- data/app/components/primer/alpha/banner.html.erb +1 -2
- data/app/components/primer/alpha/banner.rb +21 -0
- data/app/components/primer/alpha/dialog.rb +0 -1
- data/app/components/primer/alpha/modal_dialog.js +11 -10
- data/app/components/primer/alpha/modal_dialog.ts +3 -0
- data/app/components/primer/alpha/segmented_control.js +2 -3
- data/app/components/primer/alpha/toggle_switch.js +2 -2
- data/app/components/primer/alpha/toggle_switch.ts +2 -2
- data/app/components/primer/alpha/tool_tip.js +6 -7
- data/app/components/primer/alpha/tool_tip.ts +1 -0
- data/app/components/primer/beta/button.css +1 -1
- data/app/components/primer/beta/button.css.json +0 -1
- data/app/components/primer/beta/button.css.map +1 -1
- data/app/components/primer/beta/button.pcss +1 -5
- data/app/components/primer/beta/button_group.rb +53 -1
- data/app/components/primer/beta/clipboard_copy.ts +1 -1
- data/app/components/primer/beta/flash.rb +3 -1
- data/app/components/primer/beta/nav_list.js +8 -10
- data/app/components/primer/beta/nav_list.ts +2 -0
- data/app/components/primer/beta/nav_list_group_element.js +2 -3
- data/app/components/primer/dialog_helper.js +39 -20
- data/app/components/primer/dialog_helper.ts +40 -14
- data/app/components/primer/focus_group.js +9 -12
- data/app/components/primer/focus_group.ts +1 -1
- data/lib/primer/deprecations.yml +5 -0
- data/lib/primer/forms/primer_multi_input.js +2 -3
- data/lib/primer/forms/primer_text_field.js +2 -4
- data/lib/primer/view_components/version.rb +2 -2
- data/previews/primer/alpha/dialog_preview/dialog_inside_overlay.html.erb +13 -2
- data/previews/primer/alpha/dialog_preview.rb +1 -0
- data/previews/primer/beta/button_group_preview/with_menu_button.html.erb +7 -0
- data/previews/primer/beta/button_group_preview.rb +6 -0
- data/static/arguments.json +23 -1
- data/static/audited_at.json +1 -0
- data/static/constants.json +3 -0
- data/static/info_arch.json +69 -5
- data/static/previews.json +15 -2
- data/static/statuses.json +2 -1
- metadata +4 -4
- data/previews/primer/beta/button_group_preview/action_menus.html.erb +0 -8
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["button.pcss","<no source>","../../../../lib/postcss_mixins/focusOutlineOnEmphasis.pcss"],"names":[],"mappings":"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","file":"button.css","sourcesContent":["/* CSS for Button */\n\n/* temporary, pre primitives release */\n:root {\n --duration-fast: 80ms;\n --easing-easeInOut: cubic-bezier(0.65, 0, 0.35, 1);\n}\n\n/* base button */\n.Button {\n position: relative;\n font-size: var(--text-body-size-medium);\n font-weight: var(--base-text-weight-medium);\n cursor: pointer;\n user-select: none;\n background-color: transparent;\n border: var(--borderWidth-thin) solid;\n border-color: transparent;\n border-radius: var(--borderRadius-medium);\n color: var(--button-default-fgColor-rest);\n transition: var(--duration-fast) var(--easing-easeInOut);\n transition-property: color, fill, background-color, border-color;\n text-align: center;\n height: var(--control-medium-size);\n padding: 0 var(--control-medium-paddingInline-normal);\n display: inline-flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n gap: var(--base-size-4);\n min-width: max-content;\n\n /* mobile friendly sizing */\n @media (pointer: coarse) {\n &::before {\n @mixin minTouchTarget 48px, 48px;\n }\n }\n\n /* base states */\n\n &:hover {\n transition-duration: var(--duration-fast);\n }\n\n &:active {\n transition: none;\n }\n\n &:disabled,\n &[aria-disabled='true'] {\n cursor: not-allowed;\n box-shadow: none;\n }\n}\n\na.Button,\nsummary.Button {\n &:hover {\n text-decoration: none;\n }\n}\n\n/* wrap grid content to allow trailingAction to lock-right */\n.Button-content {\n flex: 1 0 auto;\n display: grid;\n grid-template-areas: 'leadingVisual text trailingVisual';\n grid-template-columns: min-content minmax(0, auto) min-content;\n align-items: center;\n place-content: center;\n\n /* padding-bottom: 1px; optical alignment for firefox */\n\n & > :not(:last-child) {\n margin-right: var(--control-medium-gap);\n }\n}\n\n/* center child elements for fullWidth */\n.Button-content--alignStart {\n justify-content: start;\n}\n\n/* button child elements */\n\n/* align svg */\n.Button-visual {\n display: flex;\n pointer-events: none; /* allow click handler to work, avoiding visuals */\n\n & .Counter {\n color: inherit;\n background-color: var(--buttonCounter-default-bgColor-rest);\n }\n}\n\n.Button-label {\n grid-area: text;\n white-space: nowrap;\n line-height: var(--text-body-lineHeight-medium);\n}\n\n.Button-leadingVisual {\n grid-area: leadingVisual;\n}\n\n.Button-leadingVisual svg {\n fill: currentcolor;\n}\n\n.Button-trailingVisual {\n grid-area: trailingVisual;\n}\n\n.Button-trailingAction {\n margin-right: calc(var(--base-size-4) * -1);\n}\n\n/* sizes */\n\n.Button--small {\n font-size: var(--text-body-size-small);\n height: var(--control-small-size);\n padding: 0 var(--control-small-paddingInline-condensed);\n gap: var(--control-small-gap);\n\n & .Button-label {\n line-height: var(--text-body-lineHeight-small);\n }\n\n & .Button-content {\n & > :not(:last-child) {\n margin-right: var(--control-small-gap);\n }\n }\n}\n\n.Button--large {\n height: var(--control-large-size);\n padding: 0 var(--control-large-paddingInline-spacious);\n gap: var(--control-large-gap);\n\n & .Button-label {\n line-height: var(--text-body-lineHeight-large);\n }\n\n & .Button-content {\n & > :not(:last-child) {\n margin-right: var(--control-large-gap);\n }\n }\n}\n\n.Button--fullWidth {\n width: 100%;\n}\n\n/* variants */\n\n/* primary */\n.Button--primary {\n color: var(--button-primary-fgColor-rest);\n fill: var(--button-primary-iconColor-rest);\n background-color: var(--button-primary-bgColor-rest);\n border-color: var(--button-primary-borderColor-rest);\n box-shadow: var(--shadow-resting-small, var(--color-btn-primary-shadow));\n\n &:hover:not(:disabled, .Button--inactive) {\n background-color: var(--button-primary-bgColor-hover);\n border-color: var(--button-primary-borderColor-hover);\n }\n\n /* fallback :focus state */\n &:focus {\n @mixin focusOutlineOnEmphasis;\n\n /* remove fallback :focus if :focus-visible is supported */\n &:not(:focus-visible) {\n outline: solid 1px transparent;\n box-shadow: none;\n }\n }\n\n /* default focus state */\n &:focus-visible {\n @mixin focusOutlineOnEmphasis;\n }\n\n &:active:not(:disabled),\n &[aria-pressed='true'] {\n background-color: var(--button-primary-bgColor-active);\n box-shadow: var(--button-primary-shadow-selected);\n }\n\n &:disabled,\n &[aria-disabled='true'] {\n color: var(--button-primary-fgColor-disabled);\n background-color: var(--button-primary-bgColor-disabled);\n border-color: var(--button-primary-borderColor-disabled);\n fill: var(--button-primary-fgColor-disabled);\n }\n\n & .Counter {\n color: inherit;\n background-color: var(--buttonCounter-primary-bgColor-rest);\n }\n}\n\n/* default (secondary) */\n.Button--secondary {\n color: var(--button-default-fgColor-rest);\n fill: var(--fgColor-muted); /* help this */\n background-color: var(--button-default-bgColor-rest);\n border-color: var(--button-default-borderColor-rest);\n box-shadow: var(--button-default-shadow-resting), var(--button-default-shadow-inset);\n\n &:hover:not(:disabled, .Button--inactive) {\n background-color: var(--button-default-bgColor-hover);\n border-color: var(--button-default-borderColor-hover);\n }\n\n &:active:not(:disabled) {\n background-color: var(--button-default-bgColor-active);\n border-color: var(--button-default-borderColor-active);\n }\n\n &[aria-pressed='true'] {\n background-color: var(--button-default-bgColor-selected);\n box-shadow: var(--shadow-inset);\n }\n\n &:disabled,\n &[aria-disabled='true'] {\n color: var(--control-fgColor-disabled);\n background-color: var(--button-default-bgColor-disabled);\n border-color: var(--button-default-borderColor-disabled);\n fill: var(--control-fgColor-disabled);\n }\n}\n\n.Button--invisible {\n color: var(--button-default-fgColor-rest);\n\n &.Button--iconOnly {\n color: var(--button-invisible-iconColor-rest, var(--color-fg-muted));\n }\n\n &:hover:not(:disabled, .Button--inactive) {\n background-color: var(--button-invisible-bgColor-hover);\n\n & .Button-visual {\n color: var(--button-invisible-iconColor-hover, var(--color-fg-default));\n }\n }\n\n &[aria-pressed='true'],\n &:active:not(:disabled) {\n background-color: var(--button-invisible-bgColor-active);\n }\n\n &:disabled,\n &[aria-disabled='true'] {\n color: var(--button-invisible-fgColor-disabled);\n background-color: var(--button-invisible-bgColor-disabled);\n border-color: var(--button-invisible-borderColor-disabled);\n fill: var(--button-invisible-fgColor-disabled);\n }\n\n /* if button has no visuals, use link blue for text */\n &.Button--invisible-noVisuals .Button-label {\n color: var(--button-invisible-fgColor-rest);\n }\n\n & .Button-visual {\n color: var(--button-invisible-iconColor-rest, var(--color-fg-muted));\n\n & .Counter {\n color: var(--fgColor-default);\n }\n }\n}\n\n.Button--link {\n color: var(--fgColor-link);\n fill: var(--fgColor-link);\n display: inline-block;\n font-size: inherit;\n border: none;\n height: unset;\n padding: 0;\n\n &:hover:not(:disabled, .Button--inactive) {\n text-decoration: underline;\n }\n\n &:focus-visible,\n &:focus {\n outline-offset: 2px;\n }\n\n &:disabled,\n &[aria-disabled='true'] {\n color: var(--control-fgColor-disabled);\n background-color: transparent;\n border-color: transparent;\n fill: var(--control-fgColor-disabled);\n }\n}\n\n/* danger */\n.Button--danger {\n color: var(--button-danger-fgColor-rest);\n fill: var(--button-danger-iconColor-rest);\n background-color: var(--button-danger-bgColor-rest);\n border-color: var(--button-danger-borderColor-rest);\n box-shadow: var(--button-default-shadow-resting), var(--button-default-shadow-inset);\n\n &:hover:not(:disabled, .Button--inactive) {\n color: var(--button-danger-fgColor-hover);\n fill: var(--button-danger-fgColor-hover);\n background-color: var(--button-danger-bgColor-hover);\n border-color: var(--button-danger-borderColor-hover);\n box-shadow: var(--shadow-resting-small);\n\n & .Counter {\n color: var(--buttonCounter-danger-fgColor-hover);\n background-color: var(--buttonCounter-danger-bgColor-hover);\n }\n }\n\n &:active:not(:disabled),\n &[aria-pressed='true'] {\n color: var(--button-danger-fgColor-active);\n fill: var(--button-danger-fgColor-active);\n background-color: var(--button-danger-bgColor-active);\n border-color: var(--button-danger-borderColor-active);\n box-shadow: var(--button-danger-shadow-selected);\n }\n\n &:disabled,\n &[aria-disabled='true'] {\n color: var(--button-danger-fgColor-disabled);\n fill: var(--button-danger-fgColor-disabled);\n background-color: var(--button-danger-bgColor-disabled);\n border-color: var(--button-default-borderColor-disabled);\n\n & .Counter {\n color: var(--buttonCounter-danger-fgColor-disabled);\n background-color: var(--buttonCounter-danger-bgColor-disabled);\n }\n }\n\n & .Counter {\n color: var(--buttonCounter-danger-fgColor-rest);\n background-color: var(--buttonCounter-danger-bgColor-rest);\n }\n}\n\n.Button--iconOnly {\n display: inline-grid;\n place-content: center;\n padding: unset;\n width: var(--control-medium-size);\n\n &.Button--small {\n width: var(--control-small-size);\n }\n\n &.Button--large {\n width: var(--control-large-size);\n }\n}\n\n/* `disabled` takes precedence over `inactive` */\n.Button--inactive:not([aria-disabled='true'], :disabled) {\n background-color: var(--button-inactive-bgColor);\n border: 0;\n color: var(--button-inactive-fgColor);\n cursor: default;\n}\n",null,"/* outline with fg box-shadow for buttons */\n@define-mixin focusOutlineOnEmphasis $outlineOffset: -2px, $outlineColor: var(--focus-outlineColor) {\n outline: 2px solid $outlineColor;\n outline-offset: $outlineOffset;\n box-shadow: inset 0 0 0 3px var(--fgColor-onEmphasis);\n}\n"]}
|
1
|
+
{"version":3,"sources":["button.pcss","<no source>","../../../../lib/postcss_mixins/focusOutlineOnEmphasis.pcss"],"names":[],"mappings":"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","file":"button.css","sourcesContent":["/* CSS for Button */\n\n/* temporary, pre primitives release */\n:root {\n --duration-fast: 80ms;\n --easing-easeInOut: cubic-bezier(0.65, 0, 0.35, 1);\n}\n\n/* base button */\n.Button {\n position: relative;\n font-size: var(--text-body-size-medium);\n font-weight: var(--base-text-weight-medium);\n cursor: pointer;\n user-select: none;\n background-color: transparent;\n border: var(--borderWidth-thin) solid;\n border-color: transparent;\n border-radius: var(--borderRadius-medium);\n color: var(--button-default-fgColor-rest);\n transition: var(--duration-fast) var(--easing-easeInOut);\n transition-property: color, fill, background-color, border-color;\n text-align: center;\n height: var(--control-medium-size);\n padding: 0 var(--control-medium-paddingInline-normal);\n display: inline-flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n gap: var(--base-size-4);\n min-width: max-content;\n\n /* mobile friendly sizing */\n @media (pointer: coarse) {\n &::before {\n @mixin minTouchTarget 48px, 48px;\n }\n }\n\n /* base states */\n\n &:hover {\n transition-duration: var(--duration-fast);\n }\n\n &:active {\n transition: none;\n }\n\n &:disabled,\n &[aria-disabled='true'] {\n cursor: not-allowed;\n box-shadow: none;\n }\n}\n\na.Button,\nsummary.Button {\n &:hover {\n text-decoration: none;\n }\n}\n\n/* wrap grid content to allow trailingAction to lock-right */\n.Button-content {\n flex: 1 0 auto;\n display: grid;\n grid-template-areas: 'leadingVisual text trailingVisual';\n grid-template-columns: min-content minmax(0, auto) min-content;\n align-items: center;\n place-content: center;\n\n /* padding-bottom: 1px; optical alignment for firefox */\n\n & > :not(:last-child) {\n margin-right: var(--control-medium-gap);\n }\n}\n\n/* center child elements for fullWidth */\n.Button-content--alignStart {\n justify-content: start;\n}\n\n/* button child elements */\n\n/* align svg */\n.Button-visual {\n display: flex;\n pointer-events: none; /* allow click handler to work, avoiding visuals */\n\n & .Counter {\n color: inherit;\n background-color: var(--buttonCounter-default-bgColor-rest);\n }\n}\n\n.Button-label {\n grid-area: text;\n white-space: nowrap;\n line-height: var(--text-body-lineHeight-medium);\n}\n\n.Button-leadingVisual {\n grid-area: leadingVisual;\n}\n\n.Button-leadingVisual svg {\n fill: currentcolor;\n}\n\n.Button-trailingVisual {\n grid-area: trailingVisual;\n}\n\n.Button-trailingAction {\n margin-right: calc(var(--base-size-4) * -1);\n}\n\n/* sizes */\n\n.Button--small {\n font-size: var(--text-body-size-small);\n height: var(--control-small-size);\n padding: 0 var(--control-small-paddingInline-condensed);\n gap: var(--control-small-gap);\n\n & .Button-label {\n line-height: var(--text-body-lineHeight-small);\n }\n\n & .Button-content {\n & > :not(:last-child) {\n margin-right: var(--control-small-gap);\n }\n }\n}\n\n.Button--large {\n height: var(--control-large-size);\n padding: 0 var(--control-large-paddingInline-spacious);\n gap: var(--control-large-gap);\n\n & .Button-label {\n line-height: var(--text-body-lineHeight-large);\n }\n\n & .Button-content {\n & > :not(:last-child) {\n margin-right: var(--control-large-gap);\n }\n }\n}\n\n.Button--fullWidth {\n width: 100%;\n}\n\n/* variants */\n\n/* primary */\n.Button--primary {\n color: var(--button-primary-fgColor-rest);\n fill: var(--button-primary-iconColor-rest);\n background-color: var(--button-primary-bgColor-rest);\n border-color: var(--button-primary-borderColor-rest);\n box-shadow: var(--shadow-resting-small, var(--color-btn-primary-shadow));\n\n &:hover:not(:disabled, .Button--inactive) {\n background-color: var(--button-primary-bgColor-hover);\n border-color: var(--button-primary-borderColor-hover);\n }\n\n /* fallback :focus state */\n &:focus {\n @mixin focusOutlineOnEmphasis;\n\n /* remove fallback :focus if :focus-visible is supported */\n &:not(:focus-visible) {\n outline: solid 1px transparent;\n box-shadow: none;\n }\n }\n\n /* default focus state */\n &:focus-visible {\n @mixin focusOutlineOnEmphasis;\n }\n\n &:active:not(:disabled),\n &[aria-pressed='true'] {\n background-color: var(--button-primary-bgColor-active);\n box-shadow: var(--button-primary-shadow-selected);\n }\n\n &:disabled,\n &[aria-disabled='true'] {\n color: var(--button-primary-fgColor-disabled);\n background-color: var(--button-primary-bgColor-disabled);\n border-color: var(--button-primary-borderColor-disabled);\n fill: var(--button-primary-fgColor-disabled);\n }\n\n & .Counter {\n color: inherit;\n background-color: var(--buttonCounter-primary-bgColor-rest);\n }\n}\n\n/* default (secondary) */\n.Button--secondary {\n color: var(--button-default-fgColor-rest);\n fill: var(--fgColor-muted); /* help this */\n background-color: var(--button-default-bgColor-rest);\n border-color: var(--button-default-borderColor-rest);\n box-shadow: var(--button-default-shadow-resting), var(--button-default-shadow-inset);\n\n &:hover:not(:disabled, .Button--inactive) {\n background-color: var(--button-default-bgColor-hover);\n border-color: var(--button-default-borderColor-hover);\n }\n\n &:active:not(:disabled) {\n background-color: var(--button-default-bgColor-active);\n border-color: var(--button-default-borderColor-active);\n }\n\n &[aria-pressed='true'] {\n background-color: var(--button-default-bgColor-selected);\n box-shadow: var(--shadow-inset);\n }\n\n &:disabled,\n &[aria-disabled='true'] {\n color: var(--control-fgColor-disabled);\n background-color: var(--button-default-bgColor-disabled);\n border-color: var(--button-default-borderColor-disabled);\n fill: var(--control-fgColor-disabled);\n }\n}\n\n.Button--invisible {\n color: var(--button-default-fgColor-rest);\n\n &.Button--iconOnly {\n color: var(--button-invisible-iconColor-rest, var(--color-fg-muted));\n }\n\n &:hover:not(:disabled, .Button--inactive) {\n background-color: var(--control-transparent-bgColor-hover, var(--color-action-list-item-default-hover-bg));\n }\n\n &[aria-pressed='true'],\n &:active:not(:disabled) {\n background-color: var(--button-invisible-bgColor-active);\n }\n\n &:disabled,\n &[aria-disabled='true'] {\n color: var(--button-invisible-fgColor-disabled);\n background-color: var(--button-invisible-bgColor-disabled);\n border-color: var(--button-invisible-borderColor-disabled);\n fill: var(--button-invisible-fgColor-disabled);\n }\n\n /* if button has no visuals, use link blue for text */\n &.Button--invisible-noVisuals .Button-label {\n color: var(--button-invisible-fgColor-rest);\n }\n\n & .Button-visual {\n color: var(--button-invisible-iconColor-rest, var(--color-fg-muted));\n\n & .Counter {\n color: var(--fgColor-default);\n }\n }\n}\n\n.Button--link {\n color: var(--fgColor-link);\n fill: var(--fgColor-link);\n display: inline-block;\n font-size: inherit;\n border: none;\n height: unset;\n padding: 0;\n\n &:hover:not(:disabled, .Button--inactive) {\n text-decoration: underline;\n }\n\n &:focus-visible,\n &:focus {\n outline-offset: 2px;\n }\n\n &:disabled,\n &[aria-disabled='true'] {\n color: var(--control-fgColor-disabled);\n background-color: transparent;\n border-color: transparent;\n fill: var(--control-fgColor-disabled);\n }\n}\n\n/* danger */\n.Button--danger {\n color: var(--button-danger-fgColor-rest);\n fill: var(--button-danger-iconColor-rest);\n background-color: var(--button-danger-bgColor-rest);\n border-color: var(--button-danger-borderColor-rest);\n box-shadow: var(--button-default-shadow-resting), var(--button-default-shadow-inset);\n\n &:hover:not(:disabled, .Button--inactive) {\n color: var(--button-danger-fgColor-hover);\n fill: var(--button-danger-fgColor-hover);\n background-color: var(--button-danger-bgColor-hover);\n border-color: var(--button-danger-borderColor-hover);\n box-shadow: var(--shadow-resting-small);\n\n & .Counter {\n color: var(--buttonCounter-danger-fgColor-hover);\n background-color: var(--buttonCounter-danger-bgColor-hover);\n }\n }\n\n &:active:not(:disabled),\n &[aria-pressed='true'] {\n color: var(--button-danger-fgColor-active);\n fill: var(--button-danger-fgColor-active);\n background-color: var(--button-danger-bgColor-active);\n border-color: var(--button-danger-borderColor-active);\n box-shadow: var(--button-danger-shadow-selected);\n }\n\n &:disabled,\n &[aria-disabled='true'] {\n color: var(--button-danger-fgColor-disabled);\n fill: var(--button-danger-fgColor-disabled);\n background-color: var(--button-danger-bgColor-disabled);\n border-color: var(--button-default-borderColor-disabled);\n\n & .Counter {\n color: var(--buttonCounter-danger-fgColor-disabled);\n background-color: var(--buttonCounter-danger-bgColor-disabled);\n }\n }\n\n & .Counter {\n color: var(--buttonCounter-danger-fgColor-rest);\n background-color: var(--buttonCounter-danger-bgColor-rest);\n }\n}\n\n.Button--iconOnly {\n display: inline-grid;\n place-content: center;\n padding: unset;\n width: var(--control-medium-size);\n\n &.Button--small {\n width: var(--control-small-size);\n }\n\n &.Button--large {\n width: var(--control-large-size);\n }\n}\n\n/* `disabled` takes precedence over `inactive` */\n.Button--inactive:not([aria-disabled='true'], :disabled) {\n background-color: var(--button-inactive-bgColor);\n border: 0;\n color: var(--button-inactive-fgColor);\n cursor: default;\n}\n",null,"/* outline with fg box-shadow for buttons */\n@define-mixin focusOutlineOnEmphasis $outlineOffset: -2px, $outlineColor: var(--focus-outlineColor) {\n outline: 2px solid $outlineColor;\n outline-offset: $outlineOffset;\n box-shadow: inset 0 0 0 3px var(--fgColor-onEmphasis);\n}\n"]}
|
@@ -247,11 +247,7 @@ summary.Button {
|
|
247
247
|
}
|
248
248
|
|
249
249
|
&:hover:not(:disabled, .Button--inactive) {
|
250
|
-
background-color: var(--
|
251
|
-
|
252
|
-
& .Button-visual {
|
253
|
-
color: var(--button-invisible-iconColor-hover, var(--color-fg-default));
|
254
|
-
}
|
250
|
+
background-color: var(--control-transparent-bgColor-hover, var(--color-action-list-item-default-hover-bg));
|
255
251
|
}
|
256
252
|
|
257
253
|
&[aria-pressed='true'],
|
@@ -14,6 +14,13 @@ module Primer
|
|
14
14
|
# def with_button(icon: nil, **system_arguments)
|
15
15
|
# end
|
16
16
|
|
17
|
+
# @!parse
|
18
|
+
# # Adds a button that activates a menu when clicked.
|
19
|
+
# #
|
20
|
+
# # @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Beta::ButtonGroup::MenuButton) %>.
|
21
|
+
# def with_menu_button(**system_arguments)
|
22
|
+
# end
|
23
|
+
|
17
24
|
# @!parse
|
18
25
|
# # Adds a <%= link_to_component(Primer::Beta::ClipboardCopyButton) %>.
|
19
26
|
# #
|
@@ -21,7 +28,7 @@ module Primer
|
|
21
28
|
# def with_clipboard_copy_button(**system_arguments)
|
22
29
|
# end
|
23
30
|
|
24
|
-
# List of buttons to be rendered. Add buttons via the `#with_button
|
31
|
+
# List of buttons to be rendered. Add buttons via the `#with_button`, `#with_menu_button`, and `#with_clipboard_copy_button` methods (see below).
|
25
32
|
renders_many :buttons, types: {
|
26
33
|
button: {
|
27
34
|
renders: lambda { |icon: nil, **kwargs|
|
@@ -38,6 +45,14 @@ module Primer
|
|
38
45
|
as: :button
|
39
46
|
},
|
40
47
|
|
48
|
+
menu_button: {
|
49
|
+
renders: lambda { |**system_arguments|
|
50
|
+
MenuButton.new(**system_arguments)
|
51
|
+
},
|
52
|
+
|
53
|
+
as: :menu_button
|
54
|
+
},
|
55
|
+
|
41
56
|
clipboard_copy_button: {
|
42
57
|
renders: lambda { |**kwargs|
|
43
58
|
kwargs[:size] = @size
|
@@ -67,6 +82,43 @@ module Primer
|
|
67
82
|
def render?
|
68
83
|
buttons.any?
|
69
84
|
end
|
85
|
+
|
86
|
+
# Renders a button in a <%= link_to_component(Primer::Beta::ButtonGroup) %> that displays an <%= link_to_component(Primer::Alpha::ActionMenu) %> when clicked.
|
87
|
+
# This component should not be used outside of a `ButtonGroup` context.
|
88
|
+
#
|
89
|
+
# This component yields both the button and the list to the block when rendered.
|
90
|
+
#
|
91
|
+
# ```erb
|
92
|
+
# <%= render(Primer::Beta::ButtonGroup.new) do |group| %>
|
93
|
+
# <% group.with_menu_button do |menu, button| %>
|
94
|
+
# <% menu.with_item(label: "Item 1") %>
|
95
|
+
# <% button.with_trailing_visual_icon(icon: "triangle-down") %>
|
96
|
+
# <% end %>
|
97
|
+
# <% end %>
|
98
|
+
# ```
|
99
|
+
#
|
100
|
+
class MenuButton < Primer::Component
|
101
|
+
# @param menu_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Alpha::ActionMenu) %>.
|
102
|
+
# @param button_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Beta::Button) %> or <%= link_to_component(Primer::Beta::IconButton) %>, depending on the value of the `icon:` argument.
|
103
|
+
def initialize(menu_arguments: {}, button_arguments: {})
|
104
|
+
@menu = Primer::Alpha::ActionMenu.new(**menu_arguments)
|
105
|
+
@button = @menu.with_show_button(icon: "triangle-down", **button_arguments)
|
106
|
+
end
|
107
|
+
|
108
|
+
def render_in(view_context, &block)
|
109
|
+
super(view_context) do
|
110
|
+
block.call(@menu, @button)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def before_render
|
115
|
+
content
|
116
|
+
end
|
117
|
+
|
118
|
+
def call
|
119
|
+
render(@menu)
|
120
|
+
end
|
121
|
+
end
|
70
122
|
end
|
71
123
|
end
|
72
124
|
end
|
@@ -2,9 +2,11 @@
|
|
2
2
|
|
3
3
|
module Primer
|
4
4
|
module Beta
|
5
|
+
# This component has been deprecated. Use [Banner](<%= link_to_component(Primer::Alpha::Banner) %>) instead.
|
6
|
+
#
|
5
7
|
# Use `Flash` to inform users of successful or pending actions.
|
6
8
|
class Flash < Primer::Component
|
7
|
-
status :
|
9
|
+
status :deprecated
|
8
10
|
|
9
11
|
# Optional action content showed on the right side of the component.
|
10
12
|
#
|
@@ -47,21 +47,19 @@ let NavListElement = class NavListElement extends HTMLElement {
|
|
47
47
|
}
|
48
48
|
// expand collapsible item onClick
|
49
49
|
expandItem(item) {
|
50
|
-
|
51
|
-
(_a = item.nextElementSibling) === null || _a === void 0 ? void 0 : _a.removeAttribute('data-hidden');
|
50
|
+
item.nextElementSibling?.removeAttribute('data-hidden');
|
52
51
|
item.setAttribute('aria-expanded', 'true');
|
53
52
|
}
|
54
53
|
collapseItem(item) {
|
55
|
-
|
56
|
-
(_a = item.nextElementSibling) === null || _a === void 0 ? void 0 : _a.setAttribute('data-hidden', '');
|
54
|
+
item.nextElementSibling?.setAttribute('data-hidden', '');
|
57
55
|
item.setAttribute('aria-expanded', 'false');
|
58
56
|
item.focus();
|
59
57
|
}
|
60
58
|
itemIsExpanded(item) {
|
61
|
-
if (
|
59
|
+
if (item?.tagName === 'A') {
|
62
60
|
return true;
|
63
61
|
}
|
64
|
-
return
|
62
|
+
return item?.getAttribute('aria-expanded') === 'true';
|
65
63
|
}
|
66
64
|
// expand/collapse item
|
67
65
|
handleItemWithSubItemClick(e) {
|
@@ -77,6 +75,7 @@ let NavListElement = class NavListElement extends HTMLElement {
|
|
77
75
|
else {
|
78
76
|
this.expandItem(button);
|
79
77
|
}
|
78
|
+
/* eslint-disable-next-line no-restricted-syntax */
|
80
79
|
e.stopPropagation();
|
81
80
|
}
|
82
81
|
// collapse item
|
@@ -97,18 +96,18 @@ let NavListElement = class NavListElement extends HTMLElement {
|
|
97
96
|
if (this.itemIsExpanded(button) && e.key === 'Escape') {
|
98
97
|
this.collapseItem(button);
|
99
98
|
}
|
99
|
+
/* eslint-disable-next-line no-restricted-syntax */
|
100
100
|
e.stopPropagation();
|
101
101
|
}
|
102
102
|
};
|
103
103
|
_NavListElement_instances = new WeakSet();
|
104
104
|
_NavListElement_findSelectedNavItemById = function _NavListElement_findSelectedNavItemById(itemId) {
|
105
|
-
var _a;
|
106
105
|
// First we compare the selected link to data-item-id for each nav item
|
107
106
|
for (const navItem of this.items) {
|
108
107
|
if (navItem.classList.contains('ActionListItem--hasSubItem')) {
|
109
108
|
continue;
|
110
109
|
}
|
111
|
-
const keys =
|
110
|
+
const keys = navItem.getAttribute('data-item-id')?.split(' ') || [];
|
112
111
|
if (keys.includes(itemId)) {
|
113
112
|
return navItem;
|
114
113
|
}
|
@@ -152,10 +151,9 @@ _NavListElement_deselect = function _NavListElement_deselect(navItem) {
|
|
152
151
|
}
|
153
152
|
};
|
154
153
|
_NavListElement_findParentMenu = function _NavListElement_findParentMenu(navItem) {
|
155
|
-
var _a;
|
156
154
|
if (!navItem.classList.contains('ActionListItem--subItem'))
|
157
155
|
return null;
|
158
|
-
const parent =
|
156
|
+
const parent = navItem.closest('li.ActionListItem--hasSubItem')?.querySelector('button.ActionListContent');
|
159
157
|
if (parent) {
|
160
158
|
return parent;
|
161
159
|
}
|
@@ -74,6 +74,7 @@ export class NavListElement extends HTMLElement {
|
|
74
74
|
this.expandItem(button)
|
75
75
|
}
|
76
76
|
|
77
|
+
/* eslint-disable-next-line no-restricted-syntax */
|
77
78
|
e.stopPropagation()
|
78
79
|
}
|
79
80
|
|
@@ -96,6 +97,7 @@ export class NavListElement extends HTMLElement {
|
|
96
97
|
this.collapseItem(button)
|
97
98
|
}
|
98
99
|
|
100
|
+
/* eslint-disable-next-line no-restricted-syntax */
|
99
101
|
e.stopPropagation()
|
100
102
|
}
|
101
103
|
|
@@ -44,7 +44,6 @@ let NavListGroupElement = class NavListGroupElement extends HTMLElement {
|
|
44
44
|
return this.showMoreItem.getAttribute('src') || '';
|
45
45
|
}
|
46
46
|
async showMore(e) {
|
47
|
-
var _a, _b;
|
48
47
|
e.preventDefault();
|
49
48
|
if (this.showMoreDisabled)
|
50
49
|
return;
|
@@ -69,11 +68,11 @@ let NavListGroupElement = class NavListGroupElement extends HTMLElement {
|
|
69
68
|
return;
|
70
69
|
}
|
71
70
|
const fragment = __classPrivateFieldGet(this, _NavListGroupElement_instances, "m", _NavListGroupElement_parseHTML).call(this, document, html);
|
72
|
-
|
71
|
+
fragment?.querySelector('li > a')?.setAttribute('data-targets', 'nav-list-group.focusMarkers');
|
73
72
|
const listId = e.target.closest('button').getAttribute('data-list-id');
|
74
73
|
const list = document.getElementById(listId);
|
75
74
|
list.append(fragment);
|
76
|
-
|
75
|
+
this.focusMarkers.pop()?.focus();
|
77
76
|
this.showMoreDisabled = false;
|
78
77
|
}
|
79
78
|
setShowMoreItemState() {
|
@@ -12,11 +12,11 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
12
12
|
var _DialogHelperElement_abortController;
|
13
13
|
function dialogInvokerButtonHandler(event) {
|
14
14
|
const target = event.target;
|
15
|
-
const button = target
|
15
|
+
const button = target?.closest('button');
|
16
16
|
if (!button || button.hasAttribute('disabled') || button.getAttribute('aria-disabled') === 'true')
|
17
17
|
return;
|
18
18
|
// If the user is clicking a valid dialog trigger
|
19
|
-
let dialogId = button
|
19
|
+
let dialogId = button?.getAttribute('data-show-dialog-id');
|
20
20
|
if (dialogId) {
|
21
21
|
const dialog = document.getElementById(dialogId);
|
22
22
|
if (dialog instanceof HTMLDialogElement) {
|
@@ -25,6 +25,41 @@ function dialogInvokerButtonHandler(event) {
|
|
25
25
|
// If the behaviour is allowed through the dialog will be shown but then
|
26
26
|
// quickly hidden- as if it were never shown. This prevents that.
|
27
27
|
event.preventDefault();
|
28
|
+
// In some older browsers, such as Chrome 122, when a top layer element (such as a dialog)
|
29
|
+
// opens from within a popover, the "hide all popovers" internal algorithm runs, hiding
|
30
|
+
// any popover that is currently open, regardless of whether or not another top layer element,
|
31
|
+
// such as a <dialog> is nested inside.
|
32
|
+
// See https://github.com/whatwg/html/issues/9998.
|
33
|
+
// This is fixed by https://github.com/whatwg/html/pull/10116, but while we still support browsers
|
34
|
+
// that present this bug, we must undo the work they did to hide ancestral popovers of the dialog:
|
35
|
+
let node = button;
|
36
|
+
let fixed = false;
|
37
|
+
while (node) {
|
38
|
+
node = node.parentElement?.closest('[popover]:not(:popover-open)');
|
39
|
+
if (node && node.popover === 'auto') {
|
40
|
+
node.classList.add('dialog-inside-popover-fix');
|
41
|
+
node.popover = 'manual';
|
42
|
+
node.showPopover();
|
43
|
+
fixed = true;
|
44
|
+
}
|
45
|
+
}
|
46
|
+
if (fixed) {
|
47
|
+
// We need to re-open the dialog as modal, and also ensure no close event listeners
|
48
|
+
// are trying to act on the close
|
49
|
+
/* eslint-disable-next-line no-restricted-syntax */
|
50
|
+
dialog.addEventListener('close', e => e.stopImmediatePropagation(), { once: true });
|
51
|
+
dialog.close();
|
52
|
+
dialog.showModal();
|
53
|
+
dialog.addEventListener('close', () => {
|
54
|
+
for (const el of dialog.ownerDocument.querySelectorAll('.dialog-inside-popover-fix')) {
|
55
|
+
if (el.contains(dialog)) {
|
56
|
+
el.classList.remove('dialog-inside-popover-fix');
|
57
|
+
el.popover = 'auto';
|
58
|
+
el.showPopover();
|
59
|
+
}
|
60
|
+
}
|
61
|
+
}, { once: true });
|
62
|
+
}
|
28
63
|
}
|
29
64
|
}
|
30
65
|
dialogId = button.getAttribute('data-close-dialog-id') || button.getAttribute('data-submit-dialog-id');
|
@@ -52,34 +87,18 @@ export class DialogHelperElement extends HTMLElement {
|
|
52
87
|
for (const record of records) {
|
53
88
|
if (record.target === this.dialog) {
|
54
89
|
this.ownerDocument.body.classList.toggle('has-modal', this.dialog.hasAttribute('open'));
|
55
|
-
// In some older browsers, such as Chrome 122, when a top layer element (such as a dialog)
|
56
|
-
// opens from within a popover, the "hide all popovers" internal algorithm runs, hiding
|
57
|
-
// any popover that is currently open, regardless of whether or not another top layer element,
|
58
|
-
// such as a <dialog> is nested inside.
|
59
|
-
// See https://github.com/whatwg/html/issues/9998.
|
60
|
-
// This is fixed by https://github.com/whatwg/html/pull/10116, but while we still support browsers that present this bug,
|
61
|
-
// we must undo the work they did to hide ancestral popovers of the dialog:
|
62
|
-
if (this.dialog.hasAttribute('open')) {
|
63
|
-
let node = this.dialog;
|
64
|
-
while (node) {
|
65
|
-
node = node.closest('[popover]:not(:popover-open)');
|
66
|
-
if (node)
|
67
|
-
node.showPopover();
|
68
|
-
}
|
69
|
-
}
|
70
90
|
}
|
71
91
|
}
|
72
92
|
}).observe(this, { subtree: true, attributeFilter: ['open'] });
|
73
93
|
}
|
74
94
|
disconnectedCallback() {
|
75
|
-
|
76
|
-
(_a = __classPrivateFieldGet(this, _DialogHelperElement_abortController, "f")) === null || _a === void 0 ? void 0 : _a.abort();
|
95
|
+
__classPrivateFieldGet(this, _DialogHelperElement_abortController, "f")?.abort();
|
77
96
|
}
|
78
97
|
handleEvent(event) {
|
79
98
|
const target = event.target;
|
80
99
|
const dialog = this.dialog;
|
81
100
|
// The click target _must_ be the dialog element itself, and not elements underneath or inside.
|
82
|
-
if (target !== dialog || !
|
101
|
+
if (target !== dialog || !dialog?.open)
|
83
102
|
return;
|
84
103
|
const rect = dialog.getBoundingClientRect();
|
85
104
|
const clickWasInsideDialog = rect.top <= event.clientY &&
|
@@ -14,6 +14,46 @@ function dialogInvokerButtonHandler(event: Event) {
|
|
14
14
|
// If the behaviour is allowed through the dialog will be shown but then
|
15
15
|
// quickly hidden- as if it were never shown. This prevents that.
|
16
16
|
event.preventDefault()
|
17
|
+
|
18
|
+
// In some older browsers, such as Chrome 122, when a top layer element (such as a dialog)
|
19
|
+
// opens from within a popover, the "hide all popovers" internal algorithm runs, hiding
|
20
|
+
// any popover that is currently open, regardless of whether or not another top layer element,
|
21
|
+
// such as a <dialog> is nested inside.
|
22
|
+
// See https://github.com/whatwg/html/issues/9998.
|
23
|
+
// This is fixed by https://github.com/whatwg/html/pull/10116, but while we still support browsers
|
24
|
+
// that present this bug, we must undo the work they did to hide ancestral popovers of the dialog:
|
25
|
+
let node: HTMLElement | null | undefined = button
|
26
|
+
let fixed = false
|
27
|
+
while (node) {
|
28
|
+
node = node.parentElement?.closest('[popover]:not(:popover-open)')
|
29
|
+
if (node && node.popover === 'auto') {
|
30
|
+
node.classList.add('dialog-inside-popover-fix')
|
31
|
+
node.popover = 'manual'
|
32
|
+
node.showPopover()
|
33
|
+
fixed = true
|
34
|
+
}
|
35
|
+
}
|
36
|
+
if (fixed) {
|
37
|
+
// We need to re-open the dialog as modal, and also ensure no close event listeners
|
38
|
+
// are trying to act on the close
|
39
|
+
/* eslint-disable-next-line no-restricted-syntax */
|
40
|
+
dialog.addEventListener('close', e => e.stopImmediatePropagation(), {once: true})
|
41
|
+
dialog.close()
|
42
|
+
dialog.showModal()
|
43
|
+
dialog.addEventListener(
|
44
|
+
'close',
|
45
|
+
() => {
|
46
|
+
for (const el of dialog.ownerDocument.querySelectorAll<HTMLElement>('.dialog-inside-popover-fix')) {
|
47
|
+
if (el.contains(dialog)) {
|
48
|
+
el.classList.remove('dialog-inside-popover-fix')
|
49
|
+
el.popover = 'auto'
|
50
|
+
el.showPopover()
|
51
|
+
}
|
52
|
+
}
|
53
|
+
},
|
54
|
+
{once: true},
|
55
|
+
)
|
56
|
+
}
|
17
57
|
}
|
18
58
|
}
|
19
59
|
|
@@ -44,20 +84,6 @@ export class DialogHelperElement extends HTMLElement {
|
|
44
84
|
for (const record of records) {
|
45
85
|
if (record.target === this.dialog) {
|
46
86
|
this.ownerDocument.body.classList.toggle('has-modal', this.dialog.hasAttribute('open'))
|
47
|
-
// In some older browsers, such as Chrome 122, when a top layer element (such as a dialog)
|
48
|
-
// opens from within a popover, the "hide all popovers" internal algorithm runs, hiding
|
49
|
-
// any popover that is currently open, regardless of whether or not another top layer element,
|
50
|
-
// such as a <dialog> is nested inside.
|
51
|
-
// See https://github.com/whatwg/html/issues/9998.
|
52
|
-
// This is fixed by https://github.com/whatwg/html/pull/10116, but while we still support browsers that present this bug,
|
53
|
-
// we must undo the work they did to hide ancestral popovers of the dialog:
|
54
|
-
if (this.dialog.hasAttribute('open')) {
|
55
|
-
let node: HTMLElement | null = this.dialog
|
56
|
-
while (node) {
|
57
|
-
node = node.closest('[popover]:not(:popover-open)')
|
58
|
-
if (node) node.showPopover()
|
59
|
-
}
|
60
|
-
}
|
61
87
|
}
|
62
88
|
}
|
63
89
|
}).observe(this, {subtree: true, attributeFilter: ['open']})
|
@@ -13,7 +13,7 @@ var _FocusGroupElement_instances, _FocusGroupElement_retainSignal, _FocusGroupEl
|
|
13
13
|
import '@oddbird/popover-polyfill';
|
14
14
|
const validSelectors = ['[role="menuitem"]', '[role="menuitemcheckbox"]', '[role="menuitemradio"]'];
|
15
15
|
const menuItemSelector = validSelectors.map(selector => `:not([hidden]) > ${selector}`).join(', ');
|
16
|
-
const getMnemonicFor = (item) =>
|
16
|
+
const getMnemonicFor = (item) => item.textContent?.trim()[0].toLowerCase();
|
17
17
|
const printable = /^\S$/;
|
18
18
|
class FocusGroupElement extends HTMLElement {
|
19
19
|
constructor() {
|
@@ -54,26 +54,23 @@ class FocusGroupElement extends HTMLElement {
|
|
54
54
|
this.addEventListener('focusin', this, { signal });
|
55
55
|
}
|
56
56
|
disconnectedCallback() {
|
57
|
-
|
58
|
-
(_a = __classPrivateFieldGet(this, _FocusGroupElement_abortController, "f")) === null || _a === void 0 ? void 0 : _a.abort();
|
57
|
+
__classPrivateFieldGet(this, _FocusGroupElement_abortController, "f")?.abort();
|
59
58
|
}
|
60
59
|
handleEvent(event) {
|
61
|
-
var _a;
|
62
60
|
const { direction, nowrap } = this;
|
63
61
|
if (event.type === 'focusin') {
|
64
62
|
if (this.retain && event.target instanceof Element && event.target.matches(menuItemSelector)) {
|
65
|
-
|
63
|
+
__classPrivateFieldGet(this, _FocusGroupElement_retainSignal, "f")?.abort();
|
66
64
|
const { signal } = (__classPrivateFieldSet(this, _FocusGroupElement_retainSignal, new AbortController(), "f"));
|
67
65
|
for (const item of __classPrivateFieldGet(this, _FocusGroupElement_instances, "a", _FocusGroupElement_items_get)) {
|
68
66
|
item.setAttribute('tabindex', item === event.target ? '0' : '-1');
|
69
67
|
const popover = event.target.closest('[popover]');
|
70
|
-
if (item === event.target &&
|
68
|
+
if (item === event.target && popover?.popover === 'auto' && popover.closest('focus-group') === this) {
|
71
69
|
popover.addEventListener('toggle', (toggleEvent) => {
|
72
|
-
var _a, _b;
|
73
70
|
if (!(toggleEvent.target instanceof Element))
|
74
71
|
return;
|
75
72
|
if (toggleEvent.newState === 'closed') {
|
76
|
-
|
73
|
+
__classPrivateFieldGet(this, _FocusGroupElement_retainSignal, "f")?.abort();
|
77
74
|
item.setAttribute('tabindex', '-1');
|
78
75
|
if (popover.id) {
|
79
76
|
const invoker = this.querySelector(`[popovertarget="${popover.id}"]`);
|
@@ -81,7 +78,7 @@ class FocusGroupElement extends HTMLElement {
|
|
81
78
|
invoker.setAttribute('tabindex', '0');
|
82
79
|
}
|
83
80
|
else {
|
84
|
-
|
81
|
+
__classPrivateFieldGet(this, _FocusGroupElement_instances, "a", _FocusGroupElement_items_get)[0]?.setAttribute('tabindex', '0');
|
85
82
|
}
|
86
83
|
}
|
87
84
|
}
|
@@ -146,13 +143,13 @@ class FocusGroupElement extends HTMLElement {
|
|
146
143
|
let el = focusEl;
|
147
144
|
do {
|
148
145
|
el = el.closest(`[popover]:not(:popover-open)`);
|
149
|
-
if (
|
146
|
+
if (el?.popover === 'auto' && !['ArrowRight', 'ArrowLeft'].includes(event.key)) {
|
150
147
|
el.showPopover();
|
151
148
|
}
|
152
|
-
el =
|
149
|
+
el = el?.parentElement || null;
|
153
150
|
} while (el);
|
154
151
|
}
|
155
|
-
focusEl
|
152
|
+
focusEl?.focus();
|
156
153
|
}
|
157
154
|
}
|
158
155
|
}
|
data/lib/primer/deprecations.yml
CHANGED
@@ -33,6 +33,11 @@ deprecations:
|
|
33
33
|
autocorrect: true
|
34
34
|
replacement: "Primer::Beta::AutoComplete::Item"
|
35
35
|
|
36
|
+
- component: "Primer::Beta::Flash"
|
37
|
+
autocorrect: false
|
38
|
+
replacement: "Primer::Alpha::Banner"
|
39
|
+
guide: "https://primer.style/components/banner/rails/alpha"
|
40
|
+
|
36
41
|
- component: "Primer::BlankslateComponent"
|
37
42
|
autocorrect: true
|
38
43
|
replacement: "Primer::Beta::Blankslate"
|
@@ -8,7 +8,6 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
8
8
|
import { controller, targets } from '@github/catalyst';
|
9
9
|
let PrimerMultiInputElement = class PrimerMultiInputElement extends HTMLElement {
|
10
10
|
activateField(name) {
|
11
|
-
var _a, _b;
|
12
11
|
const fieldWithName = this.findField(name);
|
13
12
|
if (!fieldWithName)
|
14
13
|
return;
|
@@ -17,11 +16,11 @@ let PrimerMultiInputElement = class PrimerMultiInputElement extends HTMLElement
|
|
17
16
|
continue;
|
18
17
|
field.setAttribute('disabled', 'disabled');
|
19
18
|
field.setAttribute('hidden', 'hidden');
|
20
|
-
|
19
|
+
field.parentElement?.setAttribute('hidden', 'hidden');
|
21
20
|
}
|
22
21
|
fieldWithName.removeAttribute('disabled');
|
23
22
|
fieldWithName.removeAttribute('hidden');
|
24
|
-
|
23
|
+
fieldWithName.parentElement?.removeAttribute('hidden');
|
25
24
|
}
|
26
25
|
findField(name) {
|
27
26
|
for (const field of this.fields) {
|
@@ -27,8 +27,7 @@ class PrimerTextFieldElement extends HTMLElement {
|
|
27
27
|
_PrimerTextFieldElement_abortController.set(this, void 0);
|
28
28
|
}
|
29
29
|
connectedCallback() {
|
30
|
-
|
31
|
-
(_a = __classPrivateFieldGet(this, _PrimerTextFieldElement_abortController, "f")) === null || _a === void 0 ? void 0 : _a.abort();
|
30
|
+
__classPrivateFieldGet(this, _PrimerTextFieldElement_abortController, "f")?.abort();
|
32
31
|
const { signal } = (__classPrivateFieldSet(this, _PrimerTextFieldElement_abortController, new AbortController(), "f"));
|
33
32
|
this.inputElement.addEventListener('auto-check-success', async (event) => {
|
34
33
|
const message = await event.detail.response.text();
|
@@ -45,8 +44,7 @@ class PrimerTextFieldElement extends HTMLElement {
|
|
45
44
|
}, { signal });
|
46
45
|
}
|
47
46
|
disconnectedCallback() {
|
48
|
-
|
49
|
-
(_a = __classPrivateFieldGet(this, _PrimerTextFieldElement_abortController, "f")) === null || _a === void 0 ? void 0 : _a.abort();
|
47
|
+
__classPrivateFieldGet(this, _PrimerTextFieldElement_abortController, "f")?.abort();
|
50
48
|
}
|
51
49
|
clearContents() {
|
52
50
|
this.inputElement.value = '';
|
@@ -1,9 +1,20 @@
|
|
1
|
-
<%= render(Primer::Alpha::Overlay.new(title: "An overlay")) do |o| %>
|
1
|
+
<%= render(Primer::Alpha::Overlay.new(title: "An overlay", id: "first-overlay")) do |o| %>
|
2
2
|
<% o.with_show_button() { "Show overlay" } %>
|
3
3
|
<% o.with_body() do %>
|
4
4
|
<%= render(Primer::Alpha::Dialog.new(id: "dialog-one", title: title, position: position, subtitle: subtitle, visually_hide_title: false)) do |d| %>
|
5
5
|
<% d.with_show_button { button_text } %>
|
6
|
-
<% d.with_body { body_text} %>
|
6
|
+
<% d.with_body { body_text } %>
|
7
|
+
<% d.with_footer(show_divider: true) do %>
|
8
|
+
<%= render(Primer::ButtonComponent.new(data: { "close-dialog-id": "dialog-one" })) { "Cancel" } %>
|
9
|
+
<% end %>
|
7
10
|
<% end %>
|
8
11
|
<% end %>
|
9
12
|
<% end %>
|
13
|
+
|
14
|
+
<script type="module">
|
15
|
+
document.getElementById('overlay-show-first-overlay')?.addEventListener('click', e => {
|
16
|
+
setTimeout(() => {
|
17
|
+
document.getElementById('first-overlay').querySelector('button')?.click()
|
18
|
+
});
|
19
|
+
});
|
20
|
+
</script>
|
@@ -259,6 +259,7 @@ module Primer
|
|
259
259
|
# @param visually_hide_title [Boolean] toggle
|
260
260
|
# @param button_text [String] text
|
261
261
|
# @param body_text [String] text
|
262
|
+
# @snapshot interactive
|
262
263
|
def dialog_inside_overlay(title: "Test Dialog", subtitle: nil, position: :center, size: :medium, button_text: "Show Dialog", body_text: "Content", position_narrow: :fullscreen, visually_hide_title: false)
|
263
264
|
render_with_template(locals: {
|
264
265
|
title: title,
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<%= render(Primer::Beta::ButtonGroup.new) do |component| %>
|
2
|
+
<% component.with_button { "Main menu" } %>
|
3
|
+
<% component.with_menu_button(button_arguments: { "aria-label": "secondary menu" }, menu_arguments: { anchor_align: :end }) do |menu, button| %>
|
4
|
+
<% menu.with_item(label: "Item 1", item_id: :item1) %>
|
5
|
+
<% menu.with_item(label: "Item 2", item_id: :item2) %>
|
6
|
+
<% end %>
|
7
|
+
<% end %>
|