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 - - Hover on me to open Popover - Popover - + + Hover on me to open Popover + Use any html code here like e.g. a button: + + ``` diff --git a/packages/components/src/components/popover/docs/HTML.md b/packages/components/src/components/popover/docs/HTML.md index 02fc358634e..7375467dab7 100644 --- a/packages/components/src/components/popover/docs/HTML.md +++ b/packages/components/src/components/popover/docs/HTML.md @@ -8,9 +8,14 @@ For general installation and configuration take a look at the [components](https ... - +
+ +
+ Use any html code here like e.g. a button: + +
+
``` diff --git a/packages/components/src/components/popover/docs/React.md b/packages/components/src/components/popover/docs/React.md index 25e2f300f1a..1dc89a91485 100644 --- a/packages/components/src/components/popover/docs/React.md +++ b/packages/components/src/components/popover/docs/React.md @@ -9,10 +9,10 @@ For general installation and configuration take a look at the [react-components] import { DBPopover, DBButton } from "@db-ui/react-components"; const App = () => ( - - Hover on me to open Popover - Popover - + Hover on me to open Popover}> + Use any html code here like e.g. a button: + + ); export default App; diff --git a/packages/components/src/components/popover/docs/Vue.md b/packages/components/src/components/popover/docs/Vue.md index b24a792bbb6..bf2a12ac621 100644 --- a/packages/components/src/components/popover/docs/Vue.md +++ b/packages/components/src/components/popover/docs/Vue.md @@ -11,9 +11,12 @@ import { DBPopover, DBButton } from "@db-ui/v-components"; ``` diff --git a/packages/components/src/components/popover/model.ts b/packages/components/src/components/popover/model.ts index 7587aeb83d4..0a2f6709c86 100644 --- a/packages/components/src/components/popover/model.ts +++ b/packages/components/src/components/popover/model.ts @@ -3,8 +3,10 @@ import { GapProps, GlobalProps, GlobalState, + InitializedState, PlacementProps, PopoverProps, + PopoverState, SpacingProps } from '../../shared/model'; @@ -13,6 +15,11 @@ export interface DBPopoverDefaultProps { * Use open to disable the default hover/focus behaviour to use it on click or other trigger. */ open?: boolean; + + /** + * The trigger to open the popover e.g. a button + */ + slotTrigger?: any; } export type DBPopoverProps = DBPopoverDefaultProps & @@ -26,4 +33,5 @@ export interface DBPopoverDefaultState {} export type DBPopoverState = DBPopoverDefaultState & GlobalState & - ClickEventState; + PopoverState & + InitializedState; diff --git a/packages/components/src/components/popover/popover.lite.tsx b/packages/components/src/components/popover/popover.lite.tsx index 60ba32dc5b7..d315eff3d6d 100644 --- a/packages/components/src/components/popover/popover.lite.tsx +++ b/packages/components/src/components/popover/popover.lite.tsx @@ -1,7 +1,13 @@ -import { useMetadata, useRef, useStore } from '@builder.io/mitosis'; +import { + onMount, + onUpdate, + Slot, + useMetadata, + useRef, + useStore +} from '@builder.io/mitosis'; import { DBPopoverProps, DBPopoverState } from './model'; -import { cls } from '../../utils'; -import { ClickEvent } from '../../shared/model'; +import { cls, handleDataOutside } from '../../utils'; useMetadata({ isAttachedToShadowDom: true @@ -11,29 +17,50 @@ export default function DBPopover(props: DBPopoverProps) { const ref = useRef(null); // jscpd:ignore-start const state = useStore({ - handleClick: (event: ClickEvent) => { - event.stopPropagation(); + initialized: false, + handleAutoPlacement: () => { + if (!ref) return; + const article = ref.querySelector('article'); + if (!article) return; + handleDataOutside(article); } }); + onMount(() => { + state.initialized = true; + }); + + onUpdate(() => { + if (ref && state.initialized) { + const children: Element[] = Array.from(ref.children); + if (children.length >= 2) { + children[0].ariaHasPopup = 'true'; + } + state.initialized = false; + } + }, [ref, state.initialized]); + // jscpd:ignore-end return ( - ) => - state.handleClick(event) - }> - {props.children} - + onFocus={() => state.handleAutoPlacement()} + onMouseEnter={() => state.handleAutoPlacement()}> + +
+ {props.children} +
+ ); } diff --git a/packages/components/src/components/popover/popover.scss b/packages/components/src/components/popover/popover.scss index 4578610fac5..63873879637 100644 --- a/packages/components/src/components/popover/popover.scss +++ b/packages/components/src/components/popover/popover.scss @@ -2,22 +2,34 @@ @use "../../styles/popover-component"; .db-popover { - @extend %default-popover; + position: relative; - &, - &[data-spacing="small"] { - padding: variables.$db-spacing-fixed-sm; + &:hover, + &:focus-within { + & > article { + @extend %show-popover; + } } - &[data-spacing="medium"] { - padding: variables.$db-spacing-fixed-md; - } + & > article { + @extend %popover-center; + @extend %default-popover; - &[data-spacing="none"] { - padding: 0; - } + &, + &[data-spacing="small"] { + padding: variables.$db-spacing-fixed-sm; + } + + &[data-spacing="medium"] { + padding: variables.$db-spacing-fixed-md; + } + + &[data-spacing="none"] { + padding: 0; + } - &[data-open="true"] { - @extend %show-popover; + &[data-open="true"] { + @extend %show-popover; + } } } diff --git a/packages/components/src/components/popover/popover.spec.tsx b/packages/components/src/components/popover/popover.spec.tsx index bc9587f2574..10783be9946 100644 --- a/packages/components/src/components/popover/popover.spec.tsx +++ b/packages/components/src/components/popover/popover.spec.tsx @@ -6,13 +6,19 @@ import { DBPopover } from './index'; import { DEFAULT_VIEWPORT } from '../../shared/constants.ts'; import { DBButton } from '../button'; -const comp = ( - - Button - +// template v-slot is used for vue component tests +const comp: any = ( +
+ Button}> + {/**/} Test - +
); const testComponent = () => { @@ -25,6 +31,18 @@ const testComponent = () => { const component = await mount(comp); await expect(component).toHaveScreenshot(); }); + + test('should open', async ({ mount }) => { + const component = await mount(comp); + await component.getByTestId('button').focus(); + await expect(component.getByTestId('popover')).toBeVisible(); + }); + + test('after open should match screenshot', async ({ mount }) => { + const component = await mount(comp); + await component.getByTestId('button').focus(); + await expect(component).toHaveScreenshot(); + }); }; test.describe('DBPopover', () => { diff --git a/packages/components/src/components/tooltip/model.ts b/packages/components/src/components/tooltip/model.ts index f6e41926e54..6a02f48251a 100644 --- a/packages/components/src/components/tooltip/model.ts +++ b/packages/components/src/components/tooltip/model.ts @@ -3,8 +3,10 @@ import { EmphasisProps, GlobalProps, GlobalState, + InitializedState, PlacementProps, - PopoverProps + PopoverProps, + PopoverState } from '../../shared/model'; export interface DBTooltipDefaultProps { @@ -21,4 +23,6 @@ export interface DBTooltipDefaultState {} export type DBTooltipState = DBTooltipDefaultState & GlobalState & - ClickEventState; + ClickEventState & + PopoverState & + InitializedState; diff --git a/packages/components/src/components/tooltip/tooltip.lite.tsx b/packages/components/src/components/tooltip/tooltip.lite.tsx index 541238a6c37..e8c3bb6d3e0 100644 --- a/packages/components/src/components/tooltip/tooltip.lite.tsx +++ b/packages/components/src/components/tooltip/tooltip.lite.tsx @@ -1,6 +1,12 @@ -import { useMetadata, useRef, useStore } from '@builder.io/mitosis'; +import { + onMount, + onUpdate, + useMetadata, + useRef, + useStore +} from '@builder.io/mitosis'; import { DBTooltipProps, DBTooltipState } from './model'; -import { cls } from '../../utils'; +import { cls, handleDataOutside } from '../../utils'; import { ClickEvent } from '../../shared/model'; useMetadata({ @@ -11,10 +17,34 @@ export default function DBTooltip(props: DBTooltipProps) { const ref = useRef(null); // jscpd:ignore-start const state = useStore({ + initialized: false, handleClick: (event: ClickEvent) => { event.stopPropagation(); + }, + handleAutoPlacement: () => { + if (ref) handleDataOutside(ref); } }); + + onMount(() => { + state.initialized = true; + }); + + onUpdate(() => { + if (ref && state.initialized) { + const parent = ref.parentElement; + if (parent) { + ['mouseenter', 'focus'].forEach((event) => { + parent.addEventListener(event, () => + state.handleAutoPlacement() + ); + }); + } + + state.initialized = false; + } + }, [ref, state.initialized]); + // jscpd:ignore-end // TODO: Shall we check if only ,

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" > - - {{ exampleName }} - + + + {{ exampleName }} + + @if (exampleProps.content) { {{ exampleProps.content }} - - + } @else { +

    +
  • Popover Custom Item 1
  • +
  • Popover Custom Item 2
  • +
+ Popover Custom Item 3 + } + diff --git a/showcases/react-showcase/src/components/form/index.tsx b/showcases/react-showcase/src/components/form/index.tsx index eda76c9459a..964151b2de4 100644 --- a/showcases/react-showcase/src/components/form/index.tsx +++ b/showcases/react-showcase/src/components/form/index.tsx @@ -1,16 +1,16 @@ import { useEffect, useState } from 'react'; import { DBTabList, DBTabPanel, DBTabs } from '@db-ui/react-components/src'; import { + DBAccordion, + DBAccordionItem, DBButton, DBCheckbox, DBInput, DBRadio, DBSelect, + DBTab, DBTag, - DBTextarea, - DBAccordion, - DBAccordionItem, - DBTab + DBTextarea } from '../../../../../output/react/src'; import type { ChangeEvent, diff --git a/showcases/react-showcase/src/components/popover/index.tsx b/showcases/react-showcase/src/components/popover/index.tsx index c04e865e2c9..6e688a1251e 100644 --- a/showcases/react-showcase/src/components/popover/index.tsx +++ b/showcases/react-showcase/src/components/popover/index.tsx @@ -15,19 +15,25 @@ const getPopover = ({ content, animation }: DBPopoverProps & { content: string }) => ( - - {children} - - {content} - - + {children}
} + width={width} + gap={gap} + spacing={spacing} + placement={placement} + animation={animation} + delay={delay} + id={id}> + {content ?? ( + <> +
    +
  • Popover Custom Item 1
  • +
  • Popover Custom Item 2
  • +
+ Popover Custom Item 3 + + )} + ); const PopoverComponent = () => { diff --git a/showcases/shared/popover.json b/showcases/shared/popover.json index 839bc65943e..1e332cf5131 100644 --- a/showcases/shared/popover.json +++ b/showcases/shared/popover.json @@ -6,7 +6,6 @@ "name": "functional", "className": "db-ui-functional", "props": { - "content": "Popover", "id": "popover-01" } }, @@ -14,7 +13,6 @@ "name": "regular (Default)", "className": "db-ui-regular", "props": { - "content": "Popover", "id": "popover-02" } }, @@ -22,7 +20,6 @@ "name": "expressive", "className": "db-ui-expressive", "props": { - "content": "Popover", "id": "popover-03" } } @@ -34,7 +31,6 @@ { "name": "Small (Default)", "props": { - "content": "Popover", "spacing": "small", "id": "popover-04" } @@ -42,7 +38,6 @@ { "name": "Medium", "props": { - "content": "Popover", "spacing": "medium", "id": "popover-05" } @@ -50,7 +45,6 @@ { "name": "None", "props": { - "content": "Popover", "spacing": "none", "id": "popover-06" } @@ -63,7 +57,6 @@ { "name": "bottom-start", "props": { - "content": "Popover", "placement": "bottom-start", "id": "popover-07-start" } @@ -71,7 +64,6 @@ { "name": "bottom (Default)", "props": { - "content": "Popover", "placement": "bottom", "id": "popover-07" } @@ -79,7 +71,6 @@ { "name": "bottom-end", "props": { - "content": "Popover", "placement": "bottom-end", "id": "popover-07-end" } @@ -87,7 +78,6 @@ { "name": "left-start", "props": { - "content": "Popover", "placement": "left-start", "id": "popover-09-start" } @@ -95,7 +85,6 @@ { "name": "left", "props": { - "content": "Popover", "placement": "left", "id": "popover-09" } @@ -103,7 +92,6 @@ { "name": "left-end", "props": { - "content": "Popover", "placement": "left-end", "id": "popover-09-end" } @@ -111,7 +99,6 @@ { "name": "right-start", "props": { - "content": "Popover", "placement": "right-start", "id": "popover-10-start" } @@ -119,7 +106,6 @@ { "name": "right", "props": { - "content": "Popover", "placement": "right", "id": "popover-10" } @@ -127,7 +113,6 @@ { "name": "right-end", "props": { - "content": "Popover", "placement": "right-end", "id": "popover-10-end" } @@ -135,7 +120,6 @@ { "name": "top-start", "props": { - "content": "Popover", "placement": "top-start", "id": "popover-08-start" } @@ -143,7 +127,6 @@ { "name": "top", "props": { - "content": "Popover", "placement": "top", "id": "popover-08" } @@ -151,7 +134,6 @@ { "name": "top-end", "props": { - "content": "Popover", "placement": "top-end", "id": "popover-08-end" } @@ -164,14 +146,12 @@ { "name": "No gap (Default)", "props": { - "content": "Popover", "id": "popover-11" } }, { "name": "With gap", "props": { - "content": "Popover", "gap": true, "id": "popover-12" } @@ -184,14 +164,12 @@ { "name": "Animation no delay (Default)", "props": { - "content": "Popover", "id": "popover-13" } }, { "name": "Delay slow", "props": { - "content": "Popover", "delay": "slow", "id": "popover-14" } @@ -199,7 +177,6 @@ { "name": "Delay fast", "props": { - "content": "Popover", "delay": "fast", "id": "popover-15" } @@ -207,7 +184,6 @@ { "name": "No animation", "props": { - "content": "Popover", "animation": "disabled", "id": "popover-16" } diff --git a/showcases/showcase-styles.css b/showcases/showcase-styles.css index aeab9e8561b..a92595372c2 100644 --- a/showcases/showcase-styles.css +++ b/showcases/showcase-styles.css @@ -127,3 +127,7 @@ .tab-hide-article article { display: none !important; } + +.db-page.fixed-header-footer main { + overflow-x: hidden; +} diff --git a/showcases/vue-showcase/src/components/popover/Popover.vue b/showcases/vue-showcase/src/components/popover/Popover.vue index 3135bae034e..5135668674e 100644 --- a/showcases/vue-showcase/src/components/popover/Popover.vue +++ b/showcases/vue-showcase/src/components/popover/Popover.vue @@ -9,20 +9,29 @@ import { DBButton, DBPopover } from "../../../../../output/vue/vue3/src";