diff --git a/src/components/cc-block/cc-block.js b/src/components/cc-block/cc-block.js index 35f51b13a..1b5330915 100644 --- a/src/components/cc-block/cc-block.js +++ b/src/components/cc-block/cc-block.js @@ -1,7 +1,10 @@ import { css, html, LitElement } from 'lit'; import { classMap } from 'lit/directives/class-map.js'; -import { iconRemixArrowDownSFill as iconDown, iconRemixArrowUpSFill as iconUp } from '../../assets/cc-remix.icons.js'; -import { i18n } from '../../translations/translation.js'; +import { iconRemixArrowRightSLine as iconArrowRight } from '../../assets/cc-remix.icons.js'; +import { hasSlottedChildren } from '../../directives/hasSlottedChildren.js'; +import { dispatchCustomEvent } from '../../lib/events.js'; +import { isStringEmpty } from '../../lib/utils.js'; +import { linkStyles } from '../../templates/cc-link/cc-link.js'; import '../cc-button/cc-button.js'; import '../cc-expand/cc-expand.js'; import '../cc-icon/cc-icon.js'; @@ -9,32 +12,40 @@ import '../cc-img/cc-img.js'; /** * @typedef {import('../common.types.js').IconModel} IconModel - * @typedef {import('../common.types.js').ToggleStateType} ToggleStateType + * @typedef {import('./cc-block.types.js').BlockToggleState} BlockToggleState */ /** - * A display component with mostly HTML+CSS and a open/close toggle feature. + * A display component with mostly HTML+CSS and an open/close toggle feature organized with slots. * * ## Details * - * * The main section is wrapped in a `<cc-expand>` so variation of this section height will be animated. + * * The content-body section is wrapped in a `<cc-expand>` so variation of this section height will be animated. * - * @cssdisplay grid + * @cssdisplay block * - * @slot - The main content of the block. The direct children of this will be spaced in a 1 column CSS grid. - * @slot button - A zone dedicated for a button/toggle in the to right corner. - * @slot overlay - The content to display on top of the main content. - * @slot title - The title of the block. Try to only use text. Use the `icon` property/attribute. + * @fires {CustomEvent<'open'|'close'>} cc-block:toggle-change - Fires toggle state whenever it changes. + * + * @slot ribbon - The ribbon in the top left corner. + * @slot header - A zone dedicated to header content. + * @slot header-icon - The icon in the header. + * @slot header-title - The title of the header. Try to only use text. Use the `icon` property/attribute. + * @slot header-right - A zone dedicated to header content on the top right side. + * @slot content - A zone dedicated to main content. + * @slot content-header - A zone dedicated to content header content. + * @slot content-body - A zone dedicated to content body content. + * @slot content-footer - A zone dedicated to content footer content. + * @slot footer - A zone dedicated to footer content. + * @slot footer-left - A zone dedicated to footer left side content. + * @slot footer-right - A zone dedicated to footer right side content. */ export class CcBlock extends LitElement { static get properties() { return { icon: { type: Object }, image: { type: String }, - noHead: { type: Boolean, attribute: 'no-head', reflect: true }, ribbon: { type: String, reflect: true }, - state: { type: String, reflect: true }, - _overlay: { type: Boolean, state: true }, + toggle: { type: String, reflect: true }, }; } @@ -47,196 +58,337 @@ export class CcBlock extends LitElement { /** @type {string|null} Sets the icon before the title using a `<cc-img>`. Icon is hidden if nullish. Property will be ignored if `icon` property is already set. */ this.image = null; - /** @type {boolean} Hides the head section. */ - this.noHead = false; - - /** @type {string|null} Adds a ribbon on the top left corner if it is not empty. */ + /** @type {string|null} Adds a ribbon in the top left corner if it is not empty. */ this.ribbon = null; - /** @type {ToggleStateType} Sets the state of the toggle behaviour. */ - this.state = 'off'; - - /** @type {boolean} */ - this._overlay = false; + /** @type {BlockToggleState} Sets the state of the toggle behaviour. */ + this.toggle = 'off'; } - _clickToggle() { - if (this.state === 'close') { - this.state = 'open'; - } else if (this.state === 'open') { - this.state = 'close'; + _onClickToggle() { + if (this.toggle === 'close') { + this.toggle = 'open'; + } else if (this.toggle === 'open') { + this.toggle = 'close'; } + dispatchCustomEvent(this, 'toggle-change', this.toggle); } render() { - const isToggleEnabled = this.state === 'open' || this.state === 'close'; - const isOpen = this.state !== 'close'; + const isToggleEnabled = this.toggle === 'open' || this.toggle === 'close'; + const isToggleOpen = this.toggle === 'open'; + const areContentAndFooterHidden = isToggleEnabled && !isToggleOpen; - /* TODO when reworking the component, check this a11y issue https://github.com/CleverCloud/clever-components/issues/225#issuecomment-1239462826 */ - /* eslint-disable lit-a11y/click-events-have-key-events */ return html` - ${this.ribbon != null && this.ribbon !== '' ? html` <div class="info-ribbon">${this.ribbon}</div> ` : ''} - ${!this.noHead - ? html` - <div class="head" @click=${this._clickToggle}> - ${this.image != null && this.icon == null ? html` <cc-img src="${this.image}"></cc-img> ` : ''} - ${this.icon != null ? html` <cc-icon size="lg" .icon=${this.icon}></cc-icon> ` : ''} - <slot name="title"></slot> - ${isToggleEnabled - ? html` - <cc-button - class="toggle_button" - .icon=${isOpen ? iconUp : iconDown} - hide-text - outlined - primary - @cc-button:click=${this._clickToggle} - >${isOpen ? i18n('cc-block.toggle.close') : i18n('cc-block.toggle.open')} - </cc-button> - ` - : ''} - <slot name="button"></slot> - </div> - ` - : ''} - - <cc-expand class="main-wrapper ${classMap({ 'main-wrapper--overlay': this._overlay })}"> - ${!isToggleEnabled || isOpen + <div class="container" ${hasSlottedChildren()}> + <div class="ribbon"> + <slot name="ribbon"> + ${!isStringEmpty(this.ribbon) ? html` <div class="info-ribbon">${this.ribbon}</div> ` : ''} + </slot> + </div> + + ${isToggleEnabled ? html` - <div class="main"> - <slot></slot> - </div> + <button + class="toggle-button" + aria-expanded=${isToggleOpen} + aria-controls="content-and-footer" + @click=${this._onClickToggle} + > + ${this._renderHeader()} + <cc-icon class="toggle-icon" .icon=${iconArrowRight} size="xl"></cc-icon> + </button> ` - : ''} - </cc-expand> + : this._renderHeader()} + <div id="content-and-footer" class="${classMap({ hidden: areContentAndFooterHidden })}"> + <slot name="content"> + <div class="content"> + <div class="content-header"> + <slot name="content-header"></slot> + </div> + <cc-expand class="content-body"> + <slot name="content-body"></slot> + </cc-expand> + <div class="content-footer"> + <slot name="content-footer"></slot> + </div> + </div> + </slot> - <slot name="overlay"></slot> + <slot name="footer"> + <div class="footer"> + <div class="footer-left"> + <slot name="footer-left"></slot> + </div> + <div class="footer-right"> + <slot name="footer-right"></slot> + </div> + </div> + </slot> + </div> + </div> `; } - firstUpdated() { - /** @type {HTMLSlotElement|undefined} */ - const $overlay = this.shadowRoot.querySelector('slot[name="overlay"]'); - $overlay.addEventListener('slotchange', () => { - const oldVal = this._overlay; - this._overlay = $overlay.assignedNodes().length > 0; - this.requestUpdate('_overlay', oldVal); - }); + _renderHeader() { + const hasImageOrIcon = this.image != null || this.icon != null; + return html` + <slot name="header"> + <div class="header"> + <div class="header-icon ${classMap({ 'has-image-or-icon': hasImageOrIcon })}"> + ${this.image == null && this.icon == null ? html` <slot name="header-icon"></slot> ` : ''} + ${this.image != null && this.icon == null + ? html` <cc-img class="header-img" src="${this.image}"></cc-img> ` + : ''} + ${this.icon != null ? html` <cc-icon size="lg" .icon="${this.icon}"></cc-icon> ` : ''} + </div> + <div class="header-title"> + <slot name="header-title"></slot> + </div> + <div class="header-right"> + <slot name="header-right"></slot> + </div> + </div> + </slot> + `; } static get styles() { return [ // language=CSS + linkStyles, css` :host { background-color: var(--cc-color-bg-default, #fff); border: 1px solid var(--cc-color-border-neutral, #aaa); border-radius: var(--cc-border-radius-default, 0.25em); box-sizing: border-box; - display: grid; + display: block; + margin-bottom: 1em; overflow: hidden; position: relative; } - .head { + .container { + display: grid; + gap: 0.5em; + padding-block: 1em; + + --left-space: 1em; + } + + .container[ribbon-is-slotted], + :host([ribbon]:not([ribbon=''])) .container { + --left-space: 3.5em; + } + + .ribbon { + display: none; + } + + .container[ribbon-is-slotted] .ribbon, + :host([ribbon]:not([ribbon=''])) .ribbon { + background: var(--cc-color-bg-strong); + color: white; + display: inherit; + font-size: 0.9em; + font-weight: bold; + height: var(--height); + left: calc(var(--width) / -2); + line-height: var(--height); + position: absolute; + text-align: center; + top: calc(var(--height) / -2); + transform: rotate(var(--r)) translateY(var(--translate)); + width: var(--width); + z-index: 2; + + --height: 1.5em; + --width: 8em; + --r: -45deg; + --translate: 1.6em; + } + + /* region header */ + + .header { align-items: center; color: var(--cc-color-text-primary-strongest); + display: none; + padding: 1em 1em 1em var(--left-space); + } + + .container[header-is-slotted] .header, + .container[header-title-is-slotted] .header, + .container[header-right-is-slotted] .header, + .container[header-icon-is-slotted] .header { display: flex; - padding: 1em; + flex-wrap: wrap; + gap: 0.5em; } - :host([ribbon]) .head { - padding-left: 3.5em; + .container[header-is-slotted], + .container[header-title-is-slotted], + .container[header-right-is-slotted] { + padding-top: 0; } - :host([state='open']) .head:hover, - :host([state='close']) .head:hover { - background-color: var(--cc-color-bg-neutral-hovered); - cursor: pointer; + ::slotted([slot='header']) { + padding: 1em 1em 1em var(--left-space); } - cc-img { - align-self: flex-start; - border-radius: var(--cc-border-radius-default, 0.25em); - height: 1.5em; - margin-right: 1em; - width: 1.5em; + .header-icon { + display: none; } - cc-icon { - align-self: flex-start; - margin-right: 1em; + .container[header-icon-is-slotted] .header-icon, + .has-image-or-icon.header-icon { + display: flex; } - .toggle_button { - --cc-icon-size: 1.5em; + .header-img, + ::slotted([slot='header-icon']) { + border-radius: var(--cc-border-radius-default, 0.25em); + height: 1.5em; + width: 1.5em; } - ::slotted([slot='title']) { + .header-title { flex: 1 1 0; + } + + ::slotted([slot='header-title']) { + color: var(--cc-color-text-primary-strongest); font-size: 1.2em; font-weight: bold; } - .info-ribbon { - --height: 1.5em; - --width: 8em; - --r: -45deg; - --translate: 1.6em; + .container[header-right-is-slotted] .header-right { + display: inline-block; + } - background: var(--cc-color-bg-strong); - color: white; - font-size: 0.9em; - font-weight: bold; - height: var(--height); - left: calc(var(--width) / -2); - line-height: var(--height); - position: absolute; - text-align: center; - top: calc(var(--height) / -2); - transform: rotate(var(--r)) translateY(var(--translate)); - width: var(--width); - z-index: 2; + .toggle-button { + --cc-icon-color: var(--cc-color-text-primary-strongest); + + align-items: center; + background-color: transparent; + border: 0; + display: flex; + font-family: inherit; + font-size: 1em; + justify-content: space-between; + padding: 0 1em 0 0; + text-align: start; } - .main { - display: grid; - grid-gap: 1em; - padding: 0.5em 1em 1em; + .toggle-icon { + transition: transform 0.3s ease-out; + } + + .toggle-button[aria-expanded='true'] .toggle-icon { + transform: rotate(0.25turn); + } + + .toggle-button:hover { + background-color: var(--cc-color-bg-neutral-hovered); } - :host([no-head]) .main { - padding: 1em; + /* endregion */ + + /* region content */ + + .content { + display: none; + gap: 1em; } - .main-wrapper--overlay { - filter: blur(0.3em); - opacity: 0.35; + ::slotted([slot='content']) { + padding-left: var(--left-space); + padding-right: 1em; + } + + .container[content-is-slotted] .content, + .container[content-header-is-slotted] .content, + .container[content-body-is-slotted] .content, + .container[content-footer-is-slotted] .content { + display: grid; + gap: 1em; } - /* superpose main and overlay */ + .content-header, + .content-body, + .content-footer { + display: none; + padding: 0 1em 0 var(--left-space); + } - .main-wrapper, - ::slotted([slot='overlay']) { - grid-area: 2 / 1 / auto / auto; + .container[content-header-is-slotted] .content-header, + .container[content-body-is-slotted] .content-body, + .container[content-footer-is-slotted] .content-footer { + display: block; } - :host([ribbon]) .main-wrapper { - padding-left: 2.5em; + .content-body { + margin-block: -0.5em; + padding-block: 0.5em; } - ::slotted([slot='overlay']) { - align-content: center; + #content-and-footer { display: grid; - justify-items: center; - /* we have a few z-index:2 on atoms */ - z-index: 10; + gap: 1em; } - ::slotted(.cc-block_empty-msg) { - color: var(--cc-color-text-weak); - font-style: italic; + #content-and-footer.hidden { + display: none; } + + /* endregion */ + + /* region footer */ + + .footer { + background-color: var(--cc-color-bg-neutral); + box-shadow: inset 0 6px 6px -6px rgb(0 0 0 / 40%); + display: none; + flex-wrap: wrap; + gap: 1em; + /* TODO doc */ + justify-content: flex-end; + padding: 0.5em 1em; + } + + .footer-left { + flex: 1 1 0; + } + + .footer-left, + .footer-right { + display: none; + } + + .container[footer-is-slotted], + .container[footer-left-is-slotted], + .container[footer-right-is-slotted], + :host([toggle='close']) .container { + padding-bottom: 0; + } + + .container[footer-is-slotted] .footer, + .container[footer-left-is-slotted] .footer, + .container[footer-right-is-slotted] .footer { + display: flex; + } + + .container[footer-left-is-slotted] .footer-left, + .container[footer-right-is-slotted] .footer-right { + display: block; + } + + ::slotted([slot='footer']) { + padding: 0.5em 1em; + } + + /* endregion */ `, ]; } diff --git a/src/components/cc-block/cc-block.stories.js b/src/components/cc-block/cc-block.stories.js index ba6f29ce2..c3a9533b4 100644 --- a/src/components/cc-block/cc-block.stories.js +++ b/src/components/cc-block/cc-block.stories.js @@ -11,10 +11,14 @@ export default { component: 'cc-block', }; +/** + * @typedef {import('./cc-block.js').CcBlock} CcBlock + */ + const htmlExample = ` - <div slot="title">This is my block</div> - <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> - <div>Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> + <div slot="header-title">This is my block</div> + <div slot="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> + <div slot="content">Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> `; const conf = { @@ -22,6 +26,7 @@ const conf = { }; export const defaultStory = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ items: [ { innerHTML: htmlExample, @@ -29,30 +34,32 @@ export const defaultStory = makeStory(conf, { ], }); -export const overlayWithLoader = makeStory(conf, { +export const image = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ items: [ { - // language=HTML - innerHTML: ` - <div slot="title">This is my block</div> - <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> - <div>Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> - <cc-loader slot="overlay"></cc-loader> - `, + image: 'https://assets.clever-cloud.com/logos/nodejs.svg', + innerHTML: htmlExample, }, ], }); -export const image = makeStory(conf, { +export const imageSlotted = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ items: [ { - image: 'https://assets.clever-cloud.com/logos/nodejs.svg', - innerHTML: htmlExample, + innerHTML: ` + <img slot="header-icon" src="https://assets.clever-cloud.com/logos/nodejs.svg" alt="Nodejs logo"> + <div slot="header-title">This is my block</div> + <div slot="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> + <div slot="content">Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> + `, }, ], }); export const icon = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ items: [ { icon: iconInfo, @@ -61,10 +68,25 @@ export const icon = makeStory(conf, { ], }); +export const iconSlotted = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ + items: [ + { + innerHTML: ` + <svg slot="header-icon" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-11v6h2v-6h-2zm0-4v2h2V7h-2z"/></svg> + <div slot="header-title">This is my block</div> + <div slot="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> + <div slot="content">Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> + `, + }, + ], +}); + export const imageAndIcon = makeStory(conf, { docs: ` If you set both \`image\` and \`icon\` properties, the \`image\` property will be ignored: `, + /** @type {Array<Partial<CcBlock>>} */ items: [ { image: 'https://assets.clever-cloud.com/logos/nodejs.svg', @@ -74,118 +96,263 @@ If you set both \`image\` and \`icon\` properties, the \`image\` property will b ], }); -export const button = makeStory(conf, { +export const ribbon = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ items: [ { + ribbon: 'info', innerHTML: ` - <div slot="title">This is my block</div> - <cc-button slot="button">A button</cc-button> - <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> - <div>Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> + <div slot="header-title">This is my block</div> + <div slot="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> + <div slot="content">Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> `, }, ], }); -export const noHead = makeStory(conf, { +export const ribbonSlotted = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ items: [ { - noHead: true, innerHTML: ` - <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> - <div>Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> + <div slot="ribbon">info</div> + <div slot="header-title">This is my block</div> + <div slot="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> + <div slot="content">Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> `, }, ], }); -export const ribbon = makeStory(conf, { +export const ribbonWithToggle = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ items: [ { - ribbon: 'info', + toggle: 'open', innerHTML: ` - <div slot="title">This is my block</div> - <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> - <div>Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> + <div slot="ribbon">info</div> + <div slot="header-title">This is my block</div> + <div slot="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> + <div slot="content">Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> `, }, ], }); -export const ribbonWithState = makeStory(conf, { +export const toggleOpen = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ items: [ { - ribbon: 'info', - state: 'open', innerHTML: ` - <div slot="title">This is my block</div> - <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> - <div>Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> - `, + <div slot="header-title">This is my block</div> + <div slot="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> + <div slot="content">Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> + <div slot="footer-right">Some content in the right footer side.</div> + `, + toggle: 'open', }, ], }); -export const ribbonWithNoHead = makeStory(conf, { +export const toggleClose = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ items: [ { - ribbon: 'info', - noHead: true, innerHTML: ` - <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> - <div>Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> - `, + <div slot="header-title">This is my block</div> + <div slot="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> + <div slot="content">Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> + <div slot="footer-right">Some content in the right footer side.</div> + `, + toggle: 'close', }, ], }); -export const stateWithOpen = makeStory(conf, { +export const imageAndOpen = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ items: [ { + image: 'https://assets.clever-cloud.com/logos/nodejs.svg', innerHTML: htmlExample, - state: 'open', + toggle: 'open', }, ], }); -export const stateWithClose = makeStory(conf, { +export const iconAndOpen = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ items: [ { + icon: iconInfo, innerHTML: htmlExample, - state: 'close', + toggle: 'open', }, ], }); -export const stateWithOverflow = makeStory(conf, { +export const headerRightContent = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ items: [ { innerHTML: ` - <div slot="title">This is my block</div> - <div style="box-shadow: 0 0 10px 0 blue">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> - <div style="box-shadow: 0 0 10px 0 red">Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> + <div slot="header-title">This is my block</div> + <cc-button slot="header-right">A button</cc-button> + <div slot="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> + <div slot="content">Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> `, - state: 'open', }, ], }); -export const imageAndOpen = makeStory(conf, { +export const header = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ items: [ { - image: 'https://assets.clever-cloud.com/logos/nodejs.svg', - innerHTML: htmlExample, - state: 'open', + innerHTML: ` + <div slot="header" style="font-size: large; color: white; background-color: #3a3871; padding: 2em;">Some custom content in the header.</div> + <div slot="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> + <div slot="content">Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> + `, }, ], }); -export const iconAndOpen = makeStory(conf, { +export const contentHeader = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ items: [ { - icon: iconInfo, - innerHTML: htmlExample, - state: 'open', + innerHTML: ` + <div slot="header-title">This is my block</div> + <div slot="content-header" style="color: var(--cc-color-text-weak); display: block; font-style: italic; line-height: 1.5;">Some content in my content header.</div> + <div slot="content-body">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> + <div slot="content-body">Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> +`, + }, + ], +}); + +export const contentBodyWithOverflow = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ + items: [ + { + innerHTML: ` + <div slot="header-title">This is my block</div> + <div slot="content-body" style="box-shadow: 0 0 10px 0 blue">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> + <div slot="content-body" style="box-shadow: 0 0 10px 0 red; margin-top: 1em;">Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> + `, + }, + ], +}); + +export const contentFooterAndHeader = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ + items: [ + { + innerHTML: ` + <div slot="header-title">This is my block</div> + <div slot="content-header" style="color: var(--cc-color-text-weak); display: block; font-style: italic; line-height: 1.5;">Some content in my content header.</div> + <div slot="content-body"> + <input type="checkbox" id="text"><label for="text">Show text</label> + <p class="text">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi beatae culpa eaque eum ex explicabo iusto laudantium magni odio possimus quaerat, qui sit tenetur totam velit veritatis vitae. Magni, nemo!</p> + <p class="text">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi beatae culpa eaque eum ex explicabo iusto laudantium magni odio possimus quaerat, qui sit tenetur totam velit veritatis vitae. Magni, nemo!</p> + <p class="text">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi beatae culpa eaque eum ex explicabo iusto laudantium magni odio possimus quaerat, qui sit tenetur totam velit veritatis vitae. Magni, nemo!</p> + </div> + <div slot="content-footer" style="color: var(--cc-color-text-weak); display: block; font-style: italic; line-height: 1.5;">Some content in my content footer.</div> + +`, + }, + ], + css: ` + p.text { + display: none; + } + + input:checked ~ p.text { + display: block; + } + `, +}); + +export const contentFooter = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ + items: [ + { + innerHTML: ` + <div slot="header-title">This is my block</div> + <div slot="content-body">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> + <div slot="content-body">Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> + <div slot="content-footer" style="color: var(--cc-color-text-weak); display: block; font-style: italic; line-height: 1.5;">Some content in my content footer.</div> +`, + }, + ], +}); + +export const content = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ + items: [ + { + innerHTML: ` + <div slot="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> + <div slot="content">Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> + `, + }, + ], +}); + +export const footerLeft = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ + items: [ + { + innerHTML: ` + <div slot="header-title">This is my block</div> + <div slot="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> + <div slot="content">Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> + <div slot="footer-left">Some content in the left footer side.</div> +`, + }, + ], +}); + +export const footerRight = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ + items: [ + { + innerHTML: ` + <div slot="header-title">This is my block</div> + <div slot="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> + <div slot="content">Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> + <div slot="footer-right">Some content in the right footer side.</div> +`, + }, + ], +}); + +export const footerLeftAndRight = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ + items: [ + { + innerHTML: ` + <div slot="header-title">This is my block</div> + <div slot="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> + <div slot="content">Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> + <div slot="footer-left">Some content in the left footer side.</div> + <div slot="footer-right">Some content in the right footer side.</div> +`, + }, + ], +}); + +export const footer = makeStory(conf, { + /** @type {Array<Partial<CcBlock>>} */ + items: [ + { + innerHTML: ` + <div slot="header-title">This is my block</div> + <div slot="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat dui at leo porta dignissim. Etiam ut purus ultrices, pulvinar tellus quis, cursus massa. Mauris dignissim accumsan ex, at vestibulum lectus fermentum id. Quisque nec magna arcu. Quisque in metus sed erat sodales euismod eget id purus. Sed sagittis rhoncus mauris. Ut sit amet urna ac nunc semper porta. Nam ut felis eu velit luctus rutrum. Nam leo nisl, molestie a varius non, ullamcorper sit amet tortor. Donec in convallis ex. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent hendrerit venenatis erat, eu malesuada nulla viverra eu. Curabitur porta risus augue, non rutrum lectus hendrerit a.</div> + <div slot="content">Sed volutpat dolor nec rutrum vulputate. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer rhoncus turpis orci, at tempor tortor scelerisque varius. Integer nec fermentum dui. Integer vitae dolor sit amet erat ullamcorper elementum. Donec blandit lacinia erat, vitae blandit libero ornare id. In luctus odio a lacus dignissim, id posuere tortor lacinia. Pellentesque sed massa ac tellus tincidunt rutrum. Praesent commodo enim nibh, ut consectetur tortor consequat non. Aliquam mi enim, mattis eu velit quis, sollicitudin fringilla ex. Donec at augue ultrices, porta justo in, mattis tortor. Nunc sollicitudin nisi eget urna condimentum semper. Pellentesque sagittis quam eu mollis viverra. Proin tincidunt auctor nibh quis suscipit.</div> + <div slot="footer" style="font-size: large; color: white; background-color: #3a3871;">Some custom content in the footer.</div> +`, }, ], }); diff --git a/src/components/cc-block/cc-block.types.d.ts b/src/components/cc-block/cc-block.types.d.ts new file mode 100644 index 000000000..5abf3dd16 --- /dev/null +++ b/src/components/cc-block/cc-block.types.d.ts @@ -0,0 +1 @@ +export type BlockToggleState = 'off' | 'open' | 'close'; diff --git a/src/components/common.types.d.ts b/src/components/common.types.d.ts index 982b63b6b..44e39c249 100644 --- a/src/components/common.types.d.ts +++ b/src/components/common.types.d.ts @@ -188,8 +188,6 @@ interface Zone { lon: number; // Longitude } -type ToggleStateType = 'off' | 'open' | 'close'; - type AppStatus = | 'restart-failed' | 'restarting' diff --git a/src/directives/hasSlottedChildren.js b/src/directives/hasSlottedChildren.js new file mode 100644 index 000000000..d01ab9878 --- /dev/null +++ b/src/directives/hasSlottedChildren.js @@ -0,0 +1,76 @@ +import { nothing } from 'lit'; +import { AsyncDirective, directive, PartType } from 'lit/async-directive.js'; +import { EventHandler } from '../lib/events.js'; + +/** + * @typedef {import('lit/directive.js').Part} Part + * @typedef {import('lit/directive.js').PartInfo} PartInfo + * @typedef {import('../lib/events.types.js').EventWithTarget<HTMLSlotElement>} SlotEventWithTarget + */ + +/** + * A Lit directive that checks if an element has slotted children. + * If it is the case, the directive adds an `${changedSlot.name}-is-slotted` attribute to the element. + * If it is the default slot, the directive adds 'is-slotted' attribute to the element. + * If not, the `${changedSlot.name}-is-slotted` (or 'is-slotted' in case of default slot) attribute is removed. + */ + +class HasSlottedChildrenDirective extends AsyncDirective { + /** + * @param {PartInfo} partInfo + */ + constructor(partInfo) { + super(partInfo); + /** @type {HTMLElement} element */ + this.element = null; + this.eventHandler = null; + } + + disconnected() { + super.disconnected(); + this.eventHandler?.disconnect(); + } + + /** + * @param {Part} part + * @returns {unknown} + */ + update(part) { + if (part.type !== PartType.ELEMENT) { + throw new Error('This directive must be set as on Element.'); + } + if (!(part.element instanceof HTMLElement)) { + throw new Error('This directive must be set on a HTMLElement.'); + } + if (part.element !== this.element) { + this.eventHandler?.disconnect(); + this.element = part.element; + this.eventHandler = new EventHandler( + this.element, + 'slotchange', + /** @param {SlotEventWithTarget} e */ + (e) => { + const container = e.currentTarget; + const changedSlot = e.target; + const slotName = changedSlot.name; + const attributeName = slotName === '' ? 'is-slotted' : `${slotName}-is-slotted`; + + if (changedSlot.assignedNodes().length > 0) { + container.setAttribute(attributeName, ''); + } else { + container.removeAttribute(attributeName); + } + }, + ); + this.eventHandler.connect(); + } + + return this.render(); + } + + render() { + return nothing; + } +} + +export const hasSlottedChildren = directive(HasSlottedChildrenDirective); diff --git a/src/directives/hasSlottedChildren.test.js b/src/directives/hasSlottedChildren.test.js new file mode 100644 index 000000000..15292bccf --- /dev/null +++ b/src/directives/hasSlottedChildren.test.js @@ -0,0 +1,108 @@ +/* eslint-env node, mocha */ + +import { defineCE, elementUpdated, expect } from '@open-wc/testing'; +import { LitElement, html } from 'lit'; +import { getElement } from '../../test/helpers/element-helper.js'; +import { hasSlottedChildren } from './hasSlottedChildren.js'; + +describe('hasSlottedChildrenDirective', () => { + it('Should set the right attribute when slot is used', async () => { + const slot = defineCE( + class extends LitElement { + hasIsSlottedAttribute(name) { + return this.shadowRoot.querySelector('.main').hasAttribute(`${name}-is-slotted`); + } + + render() { + return html`<div class="main" ${hasSlottedChildren()}><slot name="slotName"></slot></div>`; + } + }, + ); + + const element = await getElement(`<${slot}><div slot="slotName">toto</div></${slot}>`); + + expect(element.hasIsSlottedAttribute('slotName')).equal(true); + }); + + it('Should not set the attribute when slot is not used', async () => { + const slot = defineCE( + class extends LitElement { + hasIsSlottedAttribute(name) { + return this.shadowRoot.querySelector('.main').hasAttribute(`${name}-is-slotted`); + } + + render() { + return html`<div class="main" ${hasSlottedChildren()}><slot name="slotName"></slot></div>`; + } + }, + ); + + const element = await getElement(`<${slot}><div>toto</div></${slot}>`); + + expect(element.hasIsSlottedAttribute('slotName')).equal(false); + }); + + it('Should set the right attribute when stack slot is used', async () => { + const slot = defineCE( + class extends LitElement { + hasIsSlottedAttribute(name) { + return this.shadowRoot.querySelector('.main').hasAttribute(`${name}-is-slotted`); + } + + render() { + return html`<div class="main" ${hasSlottedChildren()}> + <slot name="slotName"><slot name="innerSlotName"></slot></slot> + </div>`; + } + }, + ); + + const element = await getElement(`<${slot}><div slot="innerSlotName">toto</div></${slot}>`); + + expect(element.hasIsSlottedAttribute('slotName')).equal(false); + expect(element.hasIsSlottedAttribute('innerSlotName')).equal(true); + }); + + it('Should set the default attribute when default slot is used', async () => { + const slot = defineCE( + class extends LitElement { + hasDefaultIsSlottedAttribute() { + return this.shadowRoot.querySelector('.main').hasAttribute(`is-slotted`); + } + + render() { + return html`<div class="main" ${hasSlottedChildren()}> + <slot></slot> + </div>`; + } + }, + ); + + const element = await getElement(`<${slot}><div>toto</div></${slot}>`); + + expect(element.hasDefaultIsSlottedAttribute()).equal(true); + }); + + it('Should remove the attribute when slot is not used anymore', async () => { + const slot = defineCE( + class extends LitElement { + hasIsSlottedAttribute(name) { + return this.shadowRoot.querySelector('.main').hasAttribute(`${name}-is-slotted`); + } + + render() { + return html`<div class="main" ${hasSlottedChildren()}><slot name="slotName"></slot></div>`; + } + }, + ); + + const element = await getElement(`<${slot}><div slot="slotName">toto</div></${slot}>`); + + expect(element.hasIsSlottedAttribute('slotName')).equal(true); + + element.innerHTML = 'toto'; + await elementUpdated(element); + + expect(element.hasIsSlottedAttribute('slotName')).equal(false); + }); +}); diff --git a/src/lib/events.types.d.ts b/src/lib/events.types.d.ts index f2494edac..8a72d6e6d 100644 --- a/src/lib/events.types.d.ts +++ b/src/lib/events.types.d.ts @@ -1,3 +1,14 @@ -export type EventWithTarget<T extends EventTarget> = GenericEventWithTarget<Event, T>; +export type EventWithTarget<T extends EventTarget, U extends EventTarget = null | Element> = GenericEventWithTarget< + Event, + T, + U +>; -export type GenericEventWithTarget<E extends Event, T extends EventTarget> = E & { target: T }; +export type GenericEventWithTarget< + E extends Event, + T extends EventTarget, + U extends EventTarget = null | Element, +> = E & { + target: T; + currentTarget: U; +}; diff --git a/src/translations/translations.en.js b/src/translations/translations.en.js index ecb554d2a..ec40d3abe 100644 --- a/src/translations/translations.en.js +++ b/src/translations/translations.en.js @@ -238,10 +238,6 @@ export const translations = { //#region cc-beta 'cc-beta.label': `beta`, //#endregion - //#region cc-block - 'cc-block.toggle.close': `Close`, - 'cc-block.toggle.open': `Open`, - //#endregion //#region cc-button 'cc-button.cancel': `Click to cancel`, //#endregion diff --git a/src/translations/translations.fr.js b/src/translations/translations.fr.js index 41b38eee9..acddf7f49 100644 --- a/src/translations/translations.fr.js +++ b/src/translations/translations.fr.js @@ -249,10 +249,6 @@ export const translations = { //#region cc-beta 'cc-beta.label': `bĂȘta`, //#endregion - //#region cc-block - 'cc-block.toggle.close': `Fermer`, - 'cc-block.toggle.open': `Ouvrir`, - //#endregion //#region cc-button 'cc-button.cancel': `Cliquez pour annuler`, //#endregion