diff --git a/packages/uui-box/lib/uui-box.element.ts b/packages/uui-box/lib/uui-box.element.ts index 74777d2c0..21acf747e 100644 --- a/packages/uui-box/lib/uui-box.element.ts +++ b/packages/uui-box/lib/uui-box.element.ts @@ -5,11 +5,18 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import type { InterfaceHeading } from '@umbraco-ui/uui-base/lib'; import { StaticValue, html, literal, unsafeStatic } from 'lit/static-html.js'; +function slotHasContent(target: EventTarget | null): boolean { + return target + ? (target as HTMLSlotElement).assignedNodes({ flatten: true }).length > 0 + : false; +} + /** - * A box for grouping elements + * A layout box for grouping elements, as well its possible to append a header, with a headline or other elements to the box. * @element uui-box * @slot headline - headline area, this area is placed within the headline tag which is located inside the header. Use this to ensure the right headline styling. - * @slot header - header area, use this for things that is not the headline but located in the header. + * @slot header - header area, use this for things that are not the headline but are located in the header. + * @slot header-actions - right-side of the box header, use this to append some actions that are general for the topic of this box. * @slot - area for the content of the box * @cssprop --uui-box-default-padding - overwrite the box padding * @@ -17,7 +24,7 @@ import { StaticValue, html, literal, unsafeStatic } from 'lit/static-html.js'; @defineElement('uui-box') export class UUIBoxElement extends LitElement { /** - * Headline for this box, can also be set via the 'box' slot. + * Headline for this box, can also be set via the `headline` slot. * @type string * @attr * @default null @@ -27,7 +34,7 @@ export class UUIBoxElement extends LitElement { /** * Changes the headline variant for accessibility for this box. - * Notice this does not change the visual representation of the headline. (Umbraco does only recommend displaying a h5 sizes headline in the UUI-BOX) + * Notice this does not change the visual representation of the headline. (Umbraco recommends displaying a h5 size headline in the UUI-BOX) * @type {"h1" | "h2" | "h3" | "h4" | "h5" | "h6"} * @attr * @default "h5" @@ -47,19 +54,23 @@ export class UUIBoxElement extends LitElement { @state() private _headlineSlotHasContent = false; private _headlineSlotChanged = (e: Event) => { - this._headlineSlotHasContent = - (e.target as HTMLSlotElement).assignedNodes({ flatten: true }).length > 0; + this._headlineSlotHasContent = slotHasContent(e.target); }; @state() private _headerSlotHasContent = false; private _headerSlotChanged = (e: Event) => { - this._headerSlotHasContent = - (e.target as HTMLSlotElement).assignedNodes({ flatten: true }).length > 0; + this._headerSlotHasContent = slotHasContent(e.target); + }; + + @state() + private _headerActionsSlotHasContent = false; + private _headerActionsSlotChanged = (e: Event) => { + this._headerActionsSlotHasContent = slotHasContent(e.target); }; /** - * Renders a header with the header-slot, headline and headline-slot within + * Renders a header with the `header`-slot, `header-actions`-slot, headline and `headline`-slot within * @returns {TemplateResult} * @protected * @method @@ -72,6 +83,7 @@ export class UUIBoxElement extends LitElement { style=${ this._headerSlotHasContent || this._headlineSlotHasContent || + this._headerActionsSlotHasContent || this.headline !== null ? '' : 'display: none' @@ -88,6 +100,9 @@ export class UUIBoxElement extends LitElement { + `; /* eslint-enable lit/no-invalid-html, lit/binding-positions */ } @@ -110,7 +125,8 @@ export class UUIBoxElement extends LitElement { } #header { - display: block; + display: flex; + column-gap: var(--uui-size-space-5); border-bottom: 1px solid var(--uui-color-divider-standalone); padding: var(--uui-size-space-4) var(--uui-size-space-5); } @@ -119,6 +135,11 @@ export class UUIBoxElement extends LitElement { display: block; padding: var(--uui-box-default-padding, var(--uui-size-space-5)); } + + slot[name='header-actions'] { + display: block; + margin-left: auto; + } `, ]; } diff --git a/packages/uui-box/lib/uui-box.story.ts b/packages/uui-box/lib/uui-box.story.ts index cb6687743..dc17deaaf 100644 --- a/packages/uui-box/lib/uui-box.story.ts +++ b/packages/uui-box/lib/uui-box.story.ts @@ -56,6 +56,9 @@ export const Slots: Story = () => html` >Headline slot Header slot + Header actions slot Default slot `; diff --git a/packages/uui-box/lib/uui-box.test.ts b/packages/uui-box/lib/uui-box.test.ts index 74f60f09f..2c96ca1a8 100644 --- a/packages/uui-box/lib/uui-box.test.ts +++ b/packages/uui-box/lib/uui-box.test.ts @@ -72,6 +72,13 @@ describe('UUIBox', () => { expect(slot).to.exist; }); + it('renders a header-actions slot', () => { + const slot = element.shadowRoot!.querySelector( + 'slot[name=header-actions' + )!; + expect(slot).to.exist; + }); + it('renders specified headline tag when headlineVariant is set', async () => { element = await fixture( html` Main`