@rhds/elements
Version:
Red Hat Design System Elements
284 lines • 18.6 kB
JavaScript
var _RhTile_instances, _RhTile_internals, _RhTile_logger, _RhTile_slots, _RhTile_isCheckable_get, _RhTile_input_get, _RhTile_setValidityFromInput, _RhTile_onClick, _RhTile_requestSelect, _RhTile_onKeydown, _RhTile_onKeyup;
import { __classPrivateFieldGet, __decorate } from "tslib";
import { LitElement, html } from 'lit';
import { classMap } from 'lit/directives/class-map.js';
import { customElement } from 'lit/decorators/custom-element.js';
import { property } from 'lit/decorators/property.js';
import { state } from 'lit/decorators/state.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js';
import { SlotController } from '@patternfly/pfe-core/controllers/slot-controller.js';
import { Logger } from '@patternfly/pfe-core/controllers/logger.js';
import '@patternfly/elements/pf-icon/pf-icon.js';
import { colorContextConsumer } from '../../lib/context/color/consumer.js';
import { colorContextProvider } from '../../lib/context/color/provider.js';
import { css } from "lit";
const styles = css `:host{font-family:var(--rh-font-family-body-text, RedHatText, "Red Hat Text", "Noto Sans Arabic", "Noto Sans Hebrew", "Noto Sans JP", "Noto Sans KR", "Noto Sans Malayalam", "Noto Sans SC", "Noto Sans TC", "Noto Sans Thai", Helvetica, Arial, sans-serif);font-size:var(--rh-font-size-body-text-md, 1rem);font-weight:var(--rh-font-weight-heading-regular,300);line-height:var(--rh-line-height-body-text, 1.5)}:host([hidden]),[hidden]{display:none!important}:host(:focus),:host(:focus-within){outline:0!important}#content,#inner,#outer,:host{display:flex;flex-flow:column}#inner,#outer{flex:1 0 0}#content{height:100%}#outer{position:relative;padding:var(--_padding);font-weight:var(--rh-font-weight-heading-medium,500);border-radius:var(--rh-border-radius-default,3px);border:var(--rh-border-width-sm,1px) solid var(--rh-tile-border-color);background-color:var(--rh-tile-background-color);color:var(--rh-tile-text-color);--rh-tile-interactive-color:var(--rh-color-border-interactive-on-light, #0066cc);--rh-tile-focus-interactive-color:var(--rh-color-interactive-blue-darkest, #003366);--rh-tile-text-color:var(--rh-color-text-primary-on-light, #151515);--rh-tile-text-color-secondary:var(--rh-color-text-secondary-on-light, #4d4d4d);--rh-tile-background-color:var(--rh-color-surface-lightest, #ffffff);--rh-tile-focus-background-color:var(--rh-color-surface-lighter, #f2f2f2);--rh-tile-disabled-background-color:var(--rh-color-surface-light, #e0e0e0);--rh-tile-border-color:var(--rh-color-border-subtle-on-light, #c7c7c7);--rh-tile-link-color:var(--_interactive-color);--_padding:var(--rh-space-2xl, 32px);--_margin:var(--rh-space-lg, 16px);--_interactive-color:var(--rh-tile-interactive-color)}#outer.dark{--rh-tile-interactive-color:var(--rh-color-border-interactive-on-dark, #92c5f9);--rh-tile-focus-interactive-color:var(--rh-color-interactive-blue-lightest, #b9dafc);--rh-tile-text-color:var(--rh-color-text-primary-on-dark, #ffffff);--rh-tile-text-color-secondary:var(--rh-color-text-secondary-on-dark, #c7c7c7);--rh-tile-background-color:var(--rh-color-surface-darkest, #151515);--rh-tile-focus-background-color:var(--rh-color-surface-darker, #1f1f1f);--rh-tile-disabled-background-color:var(--rh-color-surface-dark, #383838);--rh-tile-border-color:var(--rh-color-border-subtle-on-dark, #707070)}#outer:active,#outer:focus,#outer:focus-within,#outer:hover{--_interactive-color:var(--rh-tile-focus-interactive-color)}#outer:is(.desaturated,.checkable){--rh-tile-link-color:var(--rh-tile-text-color)}#outer.checkable{--rh-tile-link-after-display:none}#outer:is(.compact,.checkable){--_padding:var(--rh-space-xl, 24px)}:host(:focus-within) #outer{outline:3px solid var(--rh-tile-interactive-color);outline-offset:2px}:host(:is(:hover,:focus-within)) #outer{background-color:var(--rh-tile-focus-background-color)}#body,#footer-text,#headline,#icon,#image,#title{display:block}#outer.disabled{pointer-events:none!important;color:var(--rh-tile-text-color-secondary)!important;background-color:var(--rh-tile-disabled-background-color)!important;--_interactive-color:var(--rh-tile-text-color-secondary)!important}#outer:is(.compact,.checkable) #inner{display:flex;align-items:flex-start;justify-content:space-between}#image{--_bleed:calc(0px - var(--_padding))}#outer.bleed #image{margin:var(--_bleed) var(--_bleed) 0}#outer:is(.compact,.checkable) #icon{flex:0 0 auto}#outer:is(.compact,.checkable) #content{flex:1 1 auto;width:100%}#outer.checkable #header{display:grid;grid-template-columns:auto auto;grid-template-rows:auto auto}#footer{display:flex;justify-content:space-between;align-items:flex-end;margin-block-start:auto}#outer.checkable #title{grid-column:1/2;grid-row:1/2}#outer.checkable #headline{grid-column:1/2;grid-row:2/3}#input-outer{grid-column:2/3;grid-row:1/3;align-self:flex-start;justify-self:flex-end;margin-bottom:var(--_margin);margin-inline-start:var(--_margin);accent-color:var(--_interactive-color)}input[type=radio]{flex:0 0 auto}pf-icon[icon=arrow-right]{color:var(--_interactive-color);width:var(--rh-space-xl,24px);height:var(--rh-space-xl,24px);pointer-events:none;translate:0 0;transition:translate var(--_trans);--_trans:var(--rh-animation-speed, 0.3s) var(--rh-animation-timing, cubic-bezier(0.465, 0.183, 0.153, 0.946))}:host(:hover) #footer pf-icon{translate:3px 0} not (translate:0 0){:host(:hover) #footer pf-icon{transform:translate(3px,0)}}svg{fill:var(--rh-tile-text-color-secondary);width:var(--rh-space-xl,24px);height:var(--rh-space-xl,24px)}#body{margin:0 0 var(--_margin)}::slotted(*){margin-top:0;margin-bottom:var(--_margin)}#body ::slotted(:last-of-type),::slotted(:last-child){margin-bottom:0}#body ::slotted(:first-of-type),::slotted(:first-child){margin-top:0}::slotted(a){color:var(--rh-tile-link-color)!important}::slotted([slot=image]){display:block;max-width:100%;margin-top:0;margin-bottom:var(--_padding)}::slotted([slot=icon]){width:100%;margin:0 0 var(--_padding);max-width:var(--rh-size-icon-05,48px)}::slotted([slot=title]){text-transform:uppercase}#outer:is(.compact,.checkable) ::slotted([slot=icon]){margin-inline-end:var(--_margin);max-width:var(--rh-size-icon-03,32px);max-height:var(--rh-size-icon-03,32px)}#body,#outer:is(.compact,.checkable) ::slotted([slot=headline]){font-size:var(--rh-font-size-body-text-lg, 1.125rem)}#outer:is(.compact,.checkable) #body,::slotted([slot=footer]){font-size:var(--rh-font-size-body-text-sm, .875rem)}#outer:is(.compact,.checkable) ::slotted([slot=footer]){font-size:var(--rh-font-size-body-text-xs, .75rem)}:is(#image,#tile,#headline,#body,#footer){z-index:2}`;
export class TileSelectEvent extends Event {
constructor(force) {
super('select', { bubbles: true, cancelable: true });
this.force = force;
}
}
/**
* A tile is a flexible layout with a clickable and contained surface.
*
* @summary Creates a clickable, contained surface
*
* @fires {TileSelectEvent} select - when tile is clicked
* @slot image - optional image on top of tile
* @slot icon - optional icon
* @slot title - optional title
* @slot headline - optional headline / link title
* @slot - optional body content
* @slot footer - optional footer
* @cssprop --rh-tile-text-color - color of text - {@default var(--rh-color-text-primary-on-light, #151515)}
* @cssprop --rh-tile-text-color-secondary - disabled text and icons - {@default var(--rh-color-text-secondary-on-light, #4d4d4d)}
* @cssprop --rh-tile-interactive-color - color of interactive elements - {@default var(--rh-color-border-interactive-on-light, #0066cc)}
* @cssprop --rh-tile-link-color - color of tile link - {@default var(--rh-tile-interactive-color)}
* @cssprop --rh-tile-link-text-decoration - tile link text decoration - {@default none}
* @cssprop --rh-tile-background-color - color tile surface - {@default var(--rh-color-surface-lightest, #ffffff)}
* @cssprop --rh-tile-focus-background-color - color tile surface on focus/hover - {@default var(--rh-color-surface-lighter, #f2f2f2)}
* @cssprop --rh-tile-disabled-background-color - color tile surface when disabled - {@default var(--rh-color-surface-light, #e0e0e0)}
* @cssprop --rh-tile-border-color - color of tile border - {@default var(--rh-color-border-subtle-on-light, #c7c7c7)}
*/
let RhTile = class RhTile extends LitElement {
constructor() {
super();
_RhTile_instances.add(this);
/**
* Whether image is full-width (i.e. bleeds into the padding)
*/
this.bleed = false;
/**
* Whether headline link text is a desaturated color instead of blue;
* `true` sets headline color to white on dark tiles or black on light tiles
*/
this.desaturated = false;
/**
* Reduces tile padding for more compact spaces
*/
this.compact = false;
/**
* When true, tile behaves like a checkbox unless it is part of an
* `<rh-tile-group radio>`, in which case it behaves like a radio button
*/
this.checkable = false;
/**
* If tile is checkable, whether it is currently checked
*/
this.checked = false;
/**
* Whether tile interaction is disabled
*/
this.disabled = false;
// TODO(bennyp): https://lit.dev/docs/data/context/#content
this.disabledGroup = false;
// TODO(bennyp): https://lit.dev/docs/data/context/#content
this.radioGroup = false;
_RhTile_internals.set(this, InternalsController.of(this));
_RhTile_logger.set(this, new Logger(this));
_RhTile_slots.set(this, new SlotController(this, { slots: ['icon'] }));
this.addEventListener('keydown', __classPrivateFieldGet(this, _RhTile_instances, "m", _RhTile_onKeydown));
this.addEventListener('keyup', __classPrivateFieldGet(this, _RhTile_instances, "m", _RhTile_onKeyup));
this.addEventListener('click', __classPrivateFieldGet(this, _RhTile_instances, "m", _RhTile_onClick));
}
/**
* Update the internal accessible representation of the element's state
* @param changed - the reactive properties which changed this cycle, and their old values
*/
async willUpdate(changed) {
__classPrivateFieldGet(this, _RhTile_internals, "f").role = this.radioGroup ? 'radio' : this.checkable ? 'checkbox' : null;
__classPrivateFieldGet(this, _RhTile_internals, "f").ariaChecked = !__classPrivateFieldGet(this, _RhTile_instances, "a", _RhTile_isCheckable_get) ? null : String(!!this.checked);
__classPrivateFieldGet(this, _RhTile_internals, "f").ariaDisabled = !__classPrivateFieldGet(this, _RhTile_instances, "a", _RhTile_isCheckable_get) ? null : String(!!this.disabled);
__classPrivateFieldGet(this, _RhTile_internals, "f").ariaLabel =
!(__classPrivateFieldGet(this, _RhTile_instances, "a", _RhTile_isCheckable_get) && this.accessibleLabel) ? null : this.accessibleLabel;
if (changed.has('value') || changed.has('checked')) {
const formValue = __classPrivateFieldGet(this, _RhTile_instances, "a", _RhTile_isCheckable_get) && this.checked ? this.value ?? null : null;
__classPrivateFieldGet(this, _RhTile_internals, "f").setFormValue(formValue);
}
if (this.checkable && !this.radioGroup) {
this.setAttribute('tabindex', '0');
}
else if (!this.radioGroup) {
this.removeAttribute('tabindex');
}
}
render() {
const { bleed, compact, checkable, checked, desaturated, on = '' } = this;
const disabled = this.disabledGroup || this.disabled || __classPrivateFieldGet(this, _RhTile_internals, "f").formDisabled;
const hasSlottedIcon = __classPrivateFieldGet(this, _RhTile_slots, "f").hasSlotted('icon');
return html `
<div id="outer" class="${classMap({
bleed,
checkable,
compact,
checked,
desaturated,
disabled,
[on]: !!on,
})}">
<slot id="image"
name="image"
?hidden="${this.checkable}"
></slot>
<div id="inner">
<slot id="icon" name="icon" ?hidden="${this.icon === undefined && !hasSlottedIcon}">
${this.icon !== undefined ?
html `<pf-icon icon="${ifDefined(this.icon)}" size="md" set="far"></pf-icon>`
: html ``}
</slot>
<div id="content">
<div id="header">
<slot id="title"
name="title"
?hidden="${this.checkable || this.compact}"></slot>
<slot id="headline" name="headline"></slot>
<div id="input-outer" aria-hidden="true" ?hidden="${!__classPrivateFieldGet(this, _RhTile_instances, "a", _RhTile_isCheckable_get)}" ?inert="${!__classPrivateFieldGet(this, _RhTile_instances, "a", _RhTile_isCheckable_get)}">
<input id="input"
type="${this.radioGroup ? 'radio' : 'checkbox'}"
tabindex="-1"
?checked="${checked}"
?disabled="${disabled}"></input>
</div>
</div>
<slot id="body"></slot>
<div id="footer">
<slot id="footer-text" name="footer"></slot>${!this.checkable && !this.disabled ? html `
<pf-icon icon="arrow-right" size="md" set="fas"></pf-icon>` : !this.checkable ? html `
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><g id="uuid-0fd9e805-a455-40ef-9171-f2f334832bf2"><rect width="48" height="48" fill="none"/></g><g id="uuid-48f9e284-0601-4fcd-bbe7-8b444234ac6c"><path d="m24,7c-9.37,0-17,7.63-17,17s7.63,17,17,17,17-7.63,17-17S33.37,7,24,7Zm15,17c0,3.52-1.23,6.76-3.27,9.32L14.68,12.27c2.56-2.04,5.8-3.27,9.32-3.27,8.27,0,15,6.73,15,15Zm-30,0c0-4.03,1.61-7.69,4.2-10.38l21.18,21.18c-2.7,2.6-6.35,4.2-10.38,4.2-8.27,0-15-6.73-15-15Z"/></g></svg>` : ''}
</div>
</div>
</div>
</div>
`;
}
async formDisabledCallback() {
await this.updateComplete;
this.requestUpdate();
}
async formStateRestoreCallback(state, mode) {
if (this.checkable && mode === 'restore') {
const [maybeControlMode, maybeValue] = state.split('/');
if (maybeValue ?? maybeControlMode === this.value) {
__classPrivateFieldGet(this, _RhTile_instances, "m", _RhTile_requestSelect).call(this, !!this.radioGroup);
}
}
}
setCustomValidity(message) {
__classPrivateFieldGet(this, _RhTile_internals, "f").setValidity({}, message);
}
checkValidity() {
__classPrivateFieldGet(this, _RhTile_instances, "m", _RhTile_setValidityFromInput).call(this);
return __classPrivateFieldGet(this, _RhTile_internals, "f").checkValidity();
}
reportValidity() {
__classPrivateFieldGet(this, _RhTile_instances, "m", _RhTile_setValidityFromInput).call(this);
return __classPrivateFieldGet(this, _RhTile_internals, "f").reportValidity();
}
};
_RhTile_internals = new WeakMap();
_RhTile_logger = new WeakMap();
_RhTile_slots = new WeakMap();
_RhTile_instances = new WeakSet();
_RhTile_isCheckable_get = function _RhTile_isCheckable_get() {
return !!this.radioGroup || this.checkable;
};
_RhTile_input_get = function _RhTile_input_get() {
return this.shadowRoot.getElementById('input');
};
_RhTile_setValidityFromInput = function _RhTile_setValidityFromInput() {
if (!__classPrivateFieldGet(this, _RhTile_instances, "a", _RhTile_input_get)) {
__classPrivateFieldGet(this, _RhTile_logger, "f").warn('await updateComplete before validating');
}
else {
__classPrivateFieldGet(this, _RhTile_internals, "f").setValidity(__classPrivateFieldGet(this, _RhTile_instances, "a", _RhTile_input_get).validity, __classPrivateFieldGet(this, _RhTile_instances, "a", _RhTile_input_get).validationMessage);
}
};
_RhTile_onClick = function _RhTile_onClick(event) {
if (event.target === this) {
__classPrivateFieldGet(this, _RhTile_instances, "m", _RhTile_requestSelect).call(this);
}
};
_RhTile_requestSelect = function _RhTile_requestSelect(force) {
if (this.checkable
&& !this.disabled
&& !this.disabledGroup) {
if (this.radioGroup) {
this.dispatchEvent(new TileSelectEvent(force));
}
else {
this.checked = !this.checked;
}
}
};
_RhTile_onKeydown = function _RhTile_onKeydown(event) {
switch (event.key) {
case ' ':
if (event.target === this && this.checkable) {
event.preventDefault();
event.stopImmediatePropagation();
}
break;
}
};
_RhTile_onKeyup = function _RhTile_onKeyup(event) {
switch (event.key) {
case 'Enter':
case ' ':
if (event.target === this) {
__classPrivateFieldGet(this, _RhTile_instances, "m", _RhTile_requestSelect).call(this);
}
break;
}
};
RhTile.styles = [styles];
RhTile.formAssociated = true;
__decorate([
property({ type: Boolean })
], RhTile.prototype, "bleed", void 0);
__decorate([
property({ type: Boolean })
], RhTile.prototype, "desaturated", void 0);
__decorate([
property({ type: Boolean })
], RhTile.prototype, "compact", void 0);
__decorate([
property()
], RhTile.prototype, "icon", void 0);
__decorate([
property({ attribute: 'accessible-label' })
], RhTile.prototype, "accessibleLabel", void 0);
__decorate([
property()
], RhTile.prototype, "name", void 0);
__decorate([
property()
], RhTile.prototype, "value", void 0);
__decorate([
property({ type: Boolean })
], RhTile.prototype, "checkable", void 0);
__decorate([
property({ type: Boolean, reflect: true })
], RhTile.prototype, "checked", void 0);
__decorate([
property({ type: Boolean, reflect: true })
], RhTile.prototype, "disabled", void 0);
__decorate([
colorContextProvider(),
property({ reflect: true, attribute: 'color-palette' })
], RhTile.prototype, "colorPalette", void 0);
__decorate([
colorContextConsumer()
], RhTile.prototype, "on", void 0);
__decorate([
state()
], RhTile.prototype, "disabledGroup", void 0);
__decorate([
state()
], RhTile.prototype, "radioGroup", void 0);
RhTile = __decorate([
customElement('rh-tile')
], RhTile);
export { RhTile };
//# sourceMappingURL=rh-tile.js.map