button
:
+
+ diff --git a/__snapshots__/popover/component/chromium/DBPopover-after-open-should-match-screenshot.png b/__snapshots__/popover/component/chromium/DBPopover-after-open-should-match-screenshot.png
new file mode 100644
index 00000000000..22c31b9bbb6
Binary files /dev/null and b/__snapshots__/popover/component/chromium/DBPopover-after-open-should-match-screenshot.png differ
diff --git a/__snapshots__/popover/component/chromium/DBPopover-should-match-screenshot.png b/__snapshots__/popover/component/chromium/DBPopover-should-match-screenshot.png
index 7de0ef938a4..141f715418a 100644
Binary files a/__snapshots__/popover/component/chromium/DBPopover-should-match-screenshot.png and b/__snapshots__/popover/component/chromium/DBPopover-should-match-screenshot.png differ
diff --git a/__snapshots__/popover/component/firefox/DBPopover-after-open-should-match-screenshot.png b/__snapshots__/popover/component/firefox/DBPopover-after-open-should-match-screenshot.png
new file mode 100644
index 00000000000..d6c67f64ed7
Binary files /dev/null and b/__snapshots__/popover/component/firefox/DBPopover-after-open-should-match-screenshot.png differ
diff --git a/__snapshots__/popover/component/firefox/DBPopover-should-match-screenshot.png b/__snapshots__/popover/component/firefox/DBPopover-should-match-screenshot.png
index 626a0c3d4ec..8a356c8b4ec 100644
Binary files a/__snapshots__/popover/component/firefox/DBPopover-should-match-screenshot.png and b/__snapshots__/popover/component/firefox/DBPopover-should-match-screenshot.png differ
diff --git a/__snapshots__/popover/component/mobile-chrome/DBPopover-after-open-should-match-screenshot.png b/__snapshots__/popover/component/mobile-chrome/DBPopover-after-open-should-match-screenshot.png
new file mode 100644
index 00000000000..22c31b9bbb6
Binary files /dev/null and b/__snapshots__/popover/component/mobile-chrome/DBPopover-after-open-should-match-screenshot.png differ
diff --git a/__snapshots__/popover/component/mobile-chrome/DBPopover-should-match-screenshot.png b/__snapshots__/popover/component/mobile-chrome/DBPopover-should-match-screenshot.png
index 7de0ef938a4..141f715418a 100644
Binary files a/__snapshots__/popover/component/mobile-chrome/DBPopover-should-match-screenshot.png and b/__snapshots__/popover/component/mobile-chrome/DBPopover-should-match-screenshot.png differ
diff --git a/packages/components/scripts/post-build/components.js b/packages/components/scripts/post-build/components.js
index b9f01c5fed9..95be7fc22ca 100644
--- a/packages/components/scripts/post-build/components.js
+++ b/packages/components/scripts/post-build/components.js
@@ -69,7 +69,8 @@ const getComponents = () => [
},
{
- name: 'popover'
+ name: 'popover',
+ overwrites: { angular: [{ from: 'mouseEnter', to: 'mouseenter' }] }
},
{
diff --git a/packages/components/scripts/post-build/copy-files.js b/packages/components/scripts/post-build/copy-files.js
index 035a200ad7d..088e1225cd9 100644
--- a/packages/components/scripts/post-build/copy-files.js
+++ b/packages/components/scripts/post-build/copy-files.js
@@ -19,6 +19,13 @@ module.exports = () => {
`./src/components/${name}/${name}.spec.tsx`,
`../../output/${resolvedFramework}/src/components/${name}/${name}.spec.tsx`
);
+ if (framework === 'vue') {
+ Replace({
+ files: `../../output/${resolvedFramework}/src/components/${name}/${name}.spec.tsx`,
+ from: ['{/*', '*/}'],
+ to: ''
+ });
+ }
}
Fse.copySync(
`./test/playwright/boilerplate`,
diff --git a/packages/components/src/components/popover/docs/Angular.md b/packages/components/src/components/popover/docs/Angular.md
index 97df4f6dc3b..9654493b61a 100644
--- a/packages/components/src/components/popover/docs/Angular.md
+++ b/packages/components/src/components/popover/docs/Angular.md
@@ -20,8 +20,9 @@ import { DBPopover } from '@db-ui/ngx-components';
```html app.component.html
-button
:
+
+
button
:
+
+ button
:
+
+ button
:
+
+ or direct text was passed as children? diff --git a/packages/components/src/components/tooltip/tooltip.scss b/packages/components/src/components/tooltip/tooltip.scss index 3d9973679dc..2a0ed0d0358 100644 --- a/packages/components/src/components/tooltip/tooltip.scss +++ b/packages/components/src/components/tooltip/tooltip.scss @@ -13,6 +13,9 @@ $tooltip-arrow-shadow-size: variables.$db-sizing-2xs; @extend %db-overwrite-font-size-sm; @extend %default-popover; + // i HTML tags browsers default styling reset + font-style: normal; + // surrounding tags styling reset font-weight: initial; @@ -41,8 +44,9 @@ $tooltip-arrow-shadow-size: variables.$db-sizing-2xs; } } - &:not([data-placement]), - &[data-placement^="bottom"] { + &:not([data-placement]):not([data-outside-vy]), + &[data-placement^="bottom"]:not([data-outside-vy]), + &[data-outside-vy="top"]:not([data-outside-vx]) { &::after { inset-inline-start: 50%; inset-block-start: 0; @@ -51,7 +55,8 @@ $tooltip-arrow-shadow-size: variables.$db-sizing-2xs; } } - &[data-placement^="top"] { + &[data-placement^="top"]:not([data-outside-vy]), + &[data-outside-vy="bottom"]:not([data-outside-vx]) { &::after { inset-inline-start: 50%; inset-block-end: 0; @@ -60,7 +65,8 @@ $tooltip-arrow-shadow-size: variables.$db-sizing-2xs; } } - &[data-placement^="right"] { + &[data-placement^="right"]:not([data-outside-vx]), + &[data-outside-vx="left"] { &::after { inset-block-start: 50%; inset-inline-start: 0; @@ -69,7 +75,8 @@ $tooltip-arrow-shadow-size: variables.$db-sizing-2xs; } } - &[data-placement^="left"] { + &[data-placement^="left"]:not([data-outside-vx]), + &[data-outside-vx="right"] { &::after { inset-block-start: 50%; inset-inline-end: 0; diff --git a/packages/components/src/shared/model.ts b/packages/components/src/shared/model.ts index a49dbc39cb3..8a727eb3940 100644 --- a/packages/components/src/shared/model.ts +++ b/packages/components/src/shared/model.ts @@ -136,6 +136,10 @@ export type PopoverProps = { width?: 'auto' | 'fixed'; }; +export type PopoverState = { + handleAutoPlacement: () => void; +}; + export type SizeProps = { /** * The size attribute changes the font-size and other related sizes of the component. diff --git a/packages/components/src/styles/_popover-component.scss b/packages/components/src/styles/_popover-component.scss index 6b5fc373977..dc18029beeb 100644 --- a/packages/components/src/styles/_popover-component.scss +++ b/packages/components/src/styles/_popover-component.scss @@ -3,113 +3,137 @@ @use "@db-ui/foundations/build/scss/animation"; @use "component"; -@mixin get-popover-placements($placement) { - --db-popover-distance: #{variables.$db-spacing-fixed-md}; - - $direction: start; - $primary: block; - $secondary: inline; - @if ( - $placement == - "top" or - $placement == - "top-start" or - $placement == - "top-end" or - $placement == - "left" or - $placement == - "left-start" or - $placement == - "left-end" - ) { - $direction: end; - } - @if ( - $placement == - "left" or - $placement == - "left-start" or - $placement == - "left-end" or - $placement == - "right" or - $placement == - "right-start" or - $placement == - "right-end" - ) { - $primary: inline; - $secondary: block; +// 2px for shadows +$popover-inset: calc( + 100% + 2px + var(--db-popover-distance) * var(--db-popover-gap, 0) +); + +$popover-gap-size: calc(2px + var(--db-popover-distance)); +$popover-gap-inset: calc(-1 * var(--db-popover-distance) - 2px); + +// use this for popover but not for tooltip +%popover-center { + &:not([data-placement]), + &[data-placement="bottom"]:not([data-outside-vy]), + &[data-placement="top"]:not([data-outside-vy]), + &[data-outside-vy="bottom"]:not([data-outside-vx]):not( + [data-placement$="end"] + ):not([data-placement$="start"]), + &[data-outside-vy="top"]:not([data-outside-vx]):not( + [data-placement$="end"] + ):not([data-placement$="start"]) { + --db-popover-center-x: -50%; + inset-inline-start: 50%; + } + + &[data-placement="left"]:not([data-outside-vx]), + &[data-placement="right"]:not([data-outside-vx]), + &[data-outside-vx="left"]:not([data-placement$="end"]):not( + [data-placement$="start"] + ), + &[data-outside-vx="right"]:not([data-placement$="end"]):not( + [data-placement$="start"] + ) { + --db-popover-center-y: -50%; + inset-block-start: 50%; + } +} + +%popover-placement { + --db-popover-distance: #{variables.$db-spacing-fixed-2xs}; + + // This pseudo-content is used to bridge the visible vertical offset in between the element that it triggering the tooltip and the tooltip itself + &::before { + content: ""; + position: absolute; + } + + &[data-gap="true"] { + --db-popover-gap: 1; + --db-popover-distance: #{variables.$db-spacing-fixed-md}; } &:is(.db-tooltip) { --db-popover-distance: #{variables.$db-spacing-fixed-xs}; } - // 2px for shadows - inset-#{$primary}-#{$direction}: calc( - 100% + 2px + var(--db-popover-distance) * var(--db-popover-gap, 0) - ); + &[data-placement^="bottom"]:not([data-outside-vy]), + &[data-placement^="top"]:not([data-outside-vy]), + &[data-outside-vy="bottom"]:not([data-outside-vx]), + &[data-outside-vy="top"]:not([data-outside-vx]) { + &[data-placement$="end"] { + inset-inline-end: 0; + } - &[data-placement$="end"] { - inset-#{$secondary}-end: 0; + &[data-placement$="start"] { + inset-inline-start: 0; + } } - &[data-placement$="start"] { - inset-#{$secondary}-start: 0; + &[data-placement^="left"]:not([data-outside-vx]), + &[data-placement^="right"]:not([data-outside-vx]), + &[data-outside-vx="left"], + &[data-outside-vx="right"] { + &[data-placement$="end"] { + inset-block-end: 0; + } + + &[data-placement$="start"] { + inset-block-start: 0; + } } - &[data-gap="true"], - &:is(.db-tooltip) { - --db-popover-gap: 1; + &:not([data-placement]):not([data-outside-vy]), + &[data-placement^="bottom"]:not([data-outside-vy]), + &[data-outside-vy="top"]:not([data-outside-vx]) { + inset-block-start: $popover-inset; &::before { - content: ""; - position: absolute; - inset-#{$secondary}-#{$direction}: 0; - #{$secondary}-size: 100%; - #{$primary}-size: calc(2px + var(--db-popover-distance)); - inset-#{$primary}-#{$direction}: calc( - -1 * var(--db-popover-distance) - 2px - ); + inset-inline-start: 0; + inline-size: 100%; + block-size: $popover-gap-size; + inset-block-start: $popover-gap-inset; } } -} -%popover-placement { - &:not([data-placement]), - &[data-placement^="bottom"] { - @include get-popover-placements("bottom"); - } + &[data-placement^="top"]:not([data-outside-vy]), + &[data-outside-vy="bottom"]:not([data-outside-vx]) { + inset-block-end: $popover-inset; - &[data-placement^="right"] { - @include get-popover-placements("right"); + &::before { + inset-inline-end: 0; + inline-size: 100%; + block-size: $popover-gap-size; + inset-block-end: $popover-gap-inset; + } } - &[data-placement^="left"] { - @include get-popover-placements("left"); - } + &[data-placement^="left"]:not([data-outside-vx]), + &[data-outside-vx="right"] { + inset-inline-end: $popover-inset; - &[data-placement^="top"] { - @include get-popover-placements("top"); + &::before { + inset-block-end: 0; + block-size: 100%; + inline-size: $popover-gap-size; + inset-inline-end: $popover-gap-inset; + } } -} -@mixin get-popover-show($placement: bottom) { - @if ($placement == bottom) { - --db-popover-translate-y: -25%; - } - @if ($placement == top) { - --db-popover-translate-y: 25%; - } - @if ($placement == right) { - --db-popover-translate-x: -25%; - } - @if ($placement == left) { - --db-popover-translate-x: 25%; + &[data-placement^="right"]:not([data-outside-vx]), + &[data-outside-vx="left"] { + inset-inline-start: $popover-inset; + + &::before { + inset-block-start: 0; + block-size: 100%; + inline-size: $popover-gap-size; + inset-inline-start: $popover-gap-inset; + } } +} +@mixin get-popover-show() { &[data-animation="disabled"] { opacity: 1; } @@ -133,21 +157,29 @@ %show-popover { visibility: visible; - &:not([data-placement]), - &[data-placement^="bottom"] { - @include get-popover-show("bottom"); + &:not([data-placement]):not([data-outside-vy]), + &[data-placement^="bottom"]:not([data-outside-vy]), + &[data-outside-vy="top"]:not([data-outside-vx]) { + --db-popover-translate-y: -25%; + @include get-popover-show(); } - &[data-placement^="right"] { - @include get-popover-show("right"); + &[data-placement^="top"]:not([data-outside-vy]), + &[data-outside-vy="bottom"]:not([data-outside-vx]) { + --db-popover-translate-y: 25%; + @include get-popover-show(); } - &[data-placement^="left"] { - @include get-popover-show("left"); + &[data-placement^="right"]:not([data-outside-vx]), + &[data-outside-vx="left"] { + --db-popover-translate-x: -25%; + @include get-popover-show(); } - &[data-placement^="top"] { - @include get-popover-show("top"); + &[data-placement^="left"]:not([data-outside-vx]), + &[data-outside-vx="right"] { + --db-popover-translate-x: 25%; + @include get-popover-show(); } } @@ -161,8 +193,7 @@ background-color: colors.$db-base-bg; visibility: hidden; z-index: 1; - // i HTML tags browsers default styling reset - font-style: normal; + white-space: nowrap; &[data-width="fixed"] { inline-size: max-content; diff --git a/packages/components/src/styles/db-ui-components.scss b/packages/components/src/styles/db-ui-components.scss index d1521e96b5b..7be4d27790e 100644 --- a/packages/components/src/styles/db-ui-components.scss +++ b/packages/components/src/styles/db-ui-components.scss @@ -113,34 +113,29 @@ dbalert { inline-size: inherit; } -// for db-badge - -:has(.db-badge[data-placement^="corner"]) { +:has(> .db-badge[data-placement^="corner"]) { position: relative; } -$popover-components: "popover", "tooltip"; -$popover-states: "hover", "focus"; - -@mixin show-popover($component, $state) { - :has(> db-#{$component} > .db-#{$component}:not([data-open])):#{$state}, - :has(> db#{$component} > .db-#{$component}:not([data-open])):#{$state}, - :has(> .db-#{$component}:not([data-open])):#{$state} { - /* TODO: We need to disable hover and active effects if popover is visible */ - .db-#{$component}:first-of-type { - @extend %show-popover; +@mixin show-popover($state) { + :has( + > db-tooltip > .db-tooltip:not([data-open]), + > dbtooltip > .db-tooltip:not([data-open]), + > .db-tooltip:not([data-open]) + ) { + &:#{$state} { + .db-tooltip:first-of-type { + @extend %show-popover; + } } } } -@each $component in $popover-components { - :has(> db-#{$component}), - :has(> db#{$component}), - :has(> .db-#{$component}) { - position: relative; - } +:has(> db-tooltip, > dbtooltip, > .db-tooltip) { + position: relative; +} - @each $state in $popover-states { - @include show-popover($component, $state); - } +$popover-states: "hover", "focus"; +@each $state in $popover-states { + @include show-popover($state); } diff --git a/packages/components/src/utils/index.ts b/packages/components/src/utils/index.ts index eaf2d364f67..101b3d451f4 100644 --- a/packages/components/src/utils/index.ts +++ b/packages/components/src/utils/index.ts @@ -90,6 +90,65 @@ export const visibleInVY = (el: Element) => { return top >= 0 && bottom <= innerHeight; }; +export const isInView = (el: Element) => { + const { top, bottom, left, right, height, width } = + el.getBoundingClientRect(); + const { innerHeight, innerWidth } = window; + + let outTop = top < 0; + let outBottom = bottom > innerHeight; + let outLeft = left < 0; + let outRight = right > innerWidth; + + // We need to check if it was already outside + const outsideY = el.hasAttribute('data-outside-vy'); + const outsideX = el.hasAttribute('data-outside-vx'); + const parentRect = el?.parentElement?.getBoundingClientRect(); + + if (parentRect) { + if (outsideY) { + const position = el.getAttribute('data-outside-vy'); + if (position === 'top') { + outTop = parentRect.top - (bottom - parentRect.bottom) < 0; + } else { + outBottom = + parentRect.bottom + (parentRect.top - top) > innerHeight; + } + } + + if (outsideX) { + const position = el.getAttribute('data-outside-vx'); + if (position === 'left') { + outLeft = parentRect.left - (right - parentRect.right) < 0; + } else { + outRight = + parentRect.right + (parentRect.left - left) > innerWidth; + } + } + } + + return { + outTop, + outBottom, + outLeft, + outRight + }; +}; + +export const handleDataOutside = (el: Element) => { + const { outTop, outBottom, outLeft, outRight } = isInView(el); + if (outTop || outBottom) { + el.setAttribute('data-outside-vy', outTop ? 'top' : 'bottom'); + } else { + el.removeAttribute('data-outside-vy'); + } + if (outLeft || outRight) { + el.setAttribute('data-outside-vx', outRight ? 'right' : 'left'); + } else { + el.removeAttribute('data-outside-vx'); + } +}; + export default { filterPassingProps, getMessageIcon, @@ -97,5 +156,7 @@ export default { addAttributeToChildren, uuid, visibleInVX, - visibleInVY + visibleInVY, + isInView, + handleDataOutside }; diff --git a/packages/components/test/playwright/boilerplate/index.html b/packages/components/test/playwright/boilerplate/index.html index 6bf5be550a2..b1ab10a7957 100644 --- a/packages/components/test/playwright/boilerplate/index.html +++ b/packages/components/test/playwright/boilerplate/index.html @@ -15,6 +15,9 @@ caret-color: transparent !important; transition: none !important; } + .padding-box { + padding: var(--db-spacing-fixed-3xl); + }
diff --git a/packages/foundations/scss/_init.scss b/packages/foundations/scss/_init.scss index fdafce00dcd..6a54d95160e 100644 --- a/packages/foundations/scss/_init.scss +++ b/packages/foundations/scss/_init.scss @@ -120,7 +120,8 @@ iframe { // List style / https://marketingportal.extranet.deutschebahn.com/marketingportal/Marke-und-Design/Basiselemente/Typografie#Aufzaehlungszeichen-9693110 :where(ul) { - list-style-type: "\2022"+ " "; + padding-inline-start: variables.$db-spacing-fixed-md; + list-style-type: "\2022"+ " "; li::marker { color: #{colors.$db-brand}; diff --git a/packages/foundations/scss/animation/_animations.scss b/packages/foundations/scss/animation/_animations.scss index e520922f56f..581b5f4c80b 100644 --- a/packages/foundations/scss/animation/_animations.scss +++ b/packages/foundations/scss/animation/_animations.scss @@ -94,13 +94,16 @@ 0% { opacity: 0; transform: translate( - var(--db-popover-translate-x, 0%), - var(--db-popover-translate-y, 0%) + var(--db-popover-center-x, var(--db-popover-translate-x, 0%)), + var(--db-popover-center-y, var(--db-popover-translate-y, 0%)) ); } 100% { opacity: 1; - transform: translate(0%, 0%); + transform: translate( + var(--db-popover-center-x, 0%), + var(--db-popover-center-y, 0%) + ); } } diff --git a/showcases/angular-showcase/src/app/components/popover/popover.component.html b/showcases/angular-showcase/src/app/components/popover/popover.component.html index 80c6a153040..54435e8cbda 100644 --- a/showcases/angular-showcase/src/app/components/popover/popover.component.html +++ b/showcases/angular-showcase/src/app/components/popover/popover.component.html @@ -10,19 +10,27 @@ let-exampleIndex="exampleIndex" let-variantIndex="variantIndex" > -