diff --git a/packages/dnb-design-system-portal/src/docs/brand/development.mdx b/packages/dnb-design-system-portal/src/docs/brand/development.mdx index a6808bbb215..37328ec108e 100644 --- a/packages/dnb-design-system-portal/src/docs/brand/development.mdx +++ b/packages/dnb-design-system-portal/src/docs/brand/development.mdx @@ -6,10 +6,10 @@ title: 'Sbanken Development' ## Write dedicated documentation -If you need to show some documentation only for when the Sbanken theme is choose, you can do so: +If you need to show some documentation only for when the Sbanken theme is selected, you can do so: ```md - + ## Sbanken examples @@ -17,5 +17,7 @@ Text - + ``` + +More details in the [Theme docs](/uilib/usage/customisation/theming). diff --git a/packages/dnb-design-system-portal/src/docs/contribute/style-guides/documentation.mdx b/packages/dnb-design-system-portal/src/docs/contribute/style-guides/documentation.mdx index 269b7d3402c..340fb6ef57b 100644 --- a/packages/dnb-design-system-portal/src/docs/contribute/style-guides/documentation.mdx +++ b/packages/dnb-design-system-portal/src/docs/contribute/style-guides/documentation.mdx @@ -10,10 +10,10 @@ The documentation is written in enhanced Markdown, called MDX. It allows us to i ## Handling themes -If you need to show some documentation only for when a certain theme is choose, you can do so: +If you need to show some documentation only for when a certain theme is selected, you can do so: ```md - + ## Eiendom examples @@ -21,5 +21,5 @@ Text - + ``` diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/button/info.mdx b/packages/dnb-design-system-portal/src/docs/uilib/components/button/info.mdx index eb695491d14..cfa95612b5e 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/components/button/info.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/button/info.mdx @@ -33,10 +33,14 @@ It is **not** recommended to use the tertiary button without an icon. Looking fo + + Icon buttons come in all sizes. diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/logo/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/components/logo/demos.mdx index c1231dbf96e..5ddcbe644b3 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/components/logo/demos.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/logo/demos.mdx @@ -34,10 +34,10 @@ The color will be set based on the parent, inherited `color` by using `currentCo - + ### Logo with compact variant - + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/usage/customisation/theming.mdx b/packages/dnb-design-system-portal/src/docs/uilib/usage/customisation/theming.mdx index b1d7ce8e4a0..9e01e02b66f 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/usage/customisation/theming.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/usage/customisation/theming.mdx @@ -27,7 +27,7 @@ Eufemia supports theming right inside where all the style-sources lives. Having Themes are independent style packages, which should not be imported in parallel. But rather either – or. -## Theme Component and useTheme Hook +### Theme Component and useTheme Hook Eufemia has a theming helper, that lets us create nested theming solutions. As of now, it does not deliver any extra features beside the principle. @@ -46,11 +46,47 @@ render( ) ``` +In addition, you can use this helper function to show/hide content based on the theme. + +```tsx +import { Theme, VisibilityByTheme } from '@dnb/eufemia/shared' + +render( + + + Only shown in Sbanken theme + + + + + + Only shown in Sbanken or Eiendom theme + + + + Only shown in Sbanken or Eiendom theme + + + + Only shown in Sbanken then or Eiendom theme – that also includes the + fictive variant="blue". + + +) +``` + `` Will create a `div` wrapper by default, when no custom element is defined (`element="span"`). It sets these CSS classes: - `eufemia-theme__{theme-name}` - `eufemia-theme__{theme-name}--{theme-variant}` + ### Brand theming Eufemia is a design system that aims to help DNB brands unleash their power. diff --git a/packages/dnb-design-system-portal/src/shared/tags/FilterByTheme.tsx b/packages/dnb-design-system-portal/src/shared/tags/FilterByTheme.tsx deleted file mode 100644 index 49df2704f2a..00000000000 --- a/packages/dnb-design-system-portal/src/shared/tags/FilterByTheme.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { useTheme } from '@dnb/eufemia/src/shared' - -export default function FilterByTheme({ children, name }) { - const themeName = useTheme()?.name - - if (themeName === name) { - return children - } - - return null -} diff --git a/packages/dnb-design-system-portal/src/shared/tags/index.js b/packages/dnb-design-system-portal/src/shared/tags/index.js index 481f5b36abe..9d6927e1fe4 100644 --- a/packages/dnb-design-system-portal/src/shared/tags/index.js +++ b/packages/dnb-design-system-portal/src/shared/tags/index.js @@ -11,11 +11,11 @@ import Table from './Table' import Anchor from './Anchor' import Header from './AutoLinkHeader' import Copy from './Copy' -import FilterByTheme from './FilterByTheme' +import VisibilityByTheme from '@dnb/eufemia/src/shared/VisibilityByTheme' export default { Copy, - FilterByTheme, + VisibilityByTheme, // img: Img, // ->
cannot appear as a descendant of

h1: (props) =>

, h2: (props) =>
, diff --git a/packages/dnb-eufemia/src/shared/VisibilityByTheme.tsx b/packages/dnb-eufemia/src/shared/VisibilityByTheme.tsx new file mode 100644 index 00000000000..c351e1be63e --- /dev/null +++ b/packages/dnb-eufemia/src/shared/VisibilityByTheme.tsx @@ -0,0 +1,63 @@ +import React from 'react' +import useTheme from './useTheme' +import type { ThemeNames, ThemeProps } from './Theme' + +type VisibilityByThemeProps = { + /** + * A valid theme name or object. + * Will pass children on a match. + */ + visible?: ThemeParams + + /** + * A valid theme name or object. + * Will omit passing children on a match. + * NB: "visible" takes presense over "hidden" + */ + hidden?: ThemeParams + + /** + * Any kind of a React Node that should render on a match. + */ + children: React.ReactNode +} + +type ThemeItem = ThemeNames | ThemeProps +type ThemeParams = ThemeItem | Array + +export default function VisibilityByTheme({ + children, + visible, + hidden, +}: VisibilityByThemeProps) { + const theme = useTheme() + + const visibleList = Array.isArray(visible) ? visible : [visible] + const hiddenList = Array.isArray(hidden) ? hidden : [hidden] + + if (visible) { + if (!visibleList.some(match(theme))) { + return null + } + } else if (hidden) { + if (hiddenList.some(match(theme))) { + return null + } + } + + return children as JSX.Element + + function match(theme: ThemeProps) { + return (themeItem: ThemeItem) => { + return typeof themeItem === 'string' + ? theme.name === themeItem + : matchObject(theme, themeItem) + } + } + + function matchObject(theme: ThemeProps, themeItem: ThemeItem) { + return Object.keys(themeItem).every((key) => { + return theme[key] === themeItem[key] + }) + } +} diff --git a/packages/dnb-eufemia/src/shared/__tests__/VisibilityByTheme.test.tsx b/packages/dnb-eufemia/src/shared/__tests__/VisibilityByTheme.test.tsx new file mode 100644 index 00000000000..a544af88ddf --- /dev/null +++ b/packages/dnb-eufemia/src/shared/__tests__/VisibilityByTheme.test.tsx @@ -0,0 +1,159 @@ +import React from 'react' +import { render } from '@testing-library/react' +import Theme from '../Theme' +import VisibilityByTheme from '../VisibilityByTheme' + +describe('VisibilityByTheme', () => { + it('renders content if not visible or hidden was given', () => { + const Component = (props) => ( + + +

I'm visible

+
+
+ ) + + render() + + expect(document.body.textContent).toBe("I'm visible") + }) + + it('renders content on name match', () => { + const Component = (props) => ( + + +

I'm visible

+
+
+ ) + + const { rerender } = render() + + expect(document.body.textContent).toBe("I'm visible") + + rerender() + + expect(document.body.textContent).toBe('') + }) + + it('skips render when hidden matches', () => { + const Component = (props) => ( + + + + ) + + const { rerender } = render() + + expect(document.body.textContent).toBe("I'm visible") + + rerender() + + expect(document.body.textContent).toBe('') + + rerender() + + expect(document.body.textContent).toBe("I'm visible") + }) + + it('prefers visible over hidden', () => { + const Component = (props) => ( + + + + ) + + const { rerender } = render() + + expect(document.body.textContent).toBe("I'm visible") + + rerender() + + expect(document.body.textContent).toBe('') + + rerender() + + expect(document.body.textContent).toBe("I'm visible") + }) + + it('renders content on match from names in an array', () => { + const Component = (props) => ( + + +

I'm visible

+
+
+ ) + + const { rerender } = render() + + expect(document.body.textContent).toBe("I'm visible") + + rerender() + + expect(document.body.textContent).toBe("I'm visible") + + rerender() + + expect(document.body.textContent).toBe('') + }) + + it('renders content on match from names in an object inside an array', () => { + const Component = (props) => ( + + +

I'm visible

+
+
+ ) + + const { rerender } = render() + + expect(document.body.textContent).toBe("I'm visible") + + rerender() + + expect(document.body.textContent).toBe("I'm visible") + + rerender() + + expect(document.body.textContent).toBe('') + }) + + it('renders content on match by several theme criterias', () => { + const Component = (props) => ( + + +

I'm visible

+
+
+ ) + + const { rerender } = render() + + expect(document.body.textContent).toBe("I'm visible") + + rerender() + + expect(document.body.textContent).toBe('') + + rerender() + + expect(document.body.textContent).toBe("I'm visible") + + rerender() + + expect(document.body.textContent).toBe('') + }) +}) diff --git a/packages/dnb-eufemia/src/shared/index.tsx b/packages/dnb-eufemia/src/shared/index.tsx index 4616393d338..2eda151352e 100644 --- a/packages/dnb-eufemia/src/shared/index.tsx +++ b/packages/dnb-eufemia/src/shared/index.tsx @@ -7,6 +7,7 @@ import Context from './Context' import Provider from './Provider' import Theme from './Theme' import useTheme from './useTheme' +import VisibilityByTheme from './VisibilityByTheme' import MediaQuery from './MediaQuery' import useMediaQuery from './useMediaQuery' import useMedia from './useMedia' @@ -16,6 +17,7 @@ export { Provider, Theme, useTheme, + VisibilityByTheme, MediaQuery, useMediaQuery, useMedia,