igniteui-webcomponents
Version:
Ignite UI for Web Components is a complete library of UI components, giving you the ability to build modern web applications using encapsulation and the concept of reusable components in a dependency-free approach.
456 lines (455 loc) • 16.7 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var IgcTileComponent_1;
import { LitElement, html, nothing } from 'lit';
import { property, query, queryAssignedElements, state, } from 'lit/decorators.js';
import { createRef, ref } from 'lit/directives/ref.js';
import { startViewTransition } from '../../animations/player.js';
import { themes } from '../../theming/theming-decorator.js';
import IgcIconButtonComponent from '../button/icon-button.js';
import { tileManagerContext, } from '../common/context.js';
import { createAsyncContext } from '../common/controllers/async-consumer.js';
import { addDragController, } from '../common/controllers/drag.js';
import { addFullscreenController } from '../common/controllers/fullscreen.js';
import { registerComponent } from '../common/definitions/register.js';
import { EventEmitterMixin } from '../common/mixins/event-emitter.js';
import { asNumber, createCounter, findElementFromEventPath, getCenterPoint, isEmpty, partNameMap, } from '../common/util.js';
import IgcDividerComponent from '../divider/divider.js';
import IgcResizeContainerComponent from '../resize-container/resize-container.js';
import { createTileDragStack, swapTiles } from './position.js';
import { createTileResizeState } from './resize-state.js';
import { styles as shared } from './themes/shared/tile/tile.common.css.js';
import { styles } from './themes/tile.base.css.js';
import { all } from './themes/tile.js';
import { createTileDragGhost, createTileGhost } from './tile-ghost-util.js';
let IgcTileComponent = IgcTileComponent_1 = class IgcTileComponent extends EventEmitterMixin(LitElement) {
constructor() {
super(...arguments);
this._dragController = addDragController(this, {
skip: this._skipDrag,
matchTarget: this._match,
ghost: this._createDragGhost,
start: this._handleDragStart,
over: this._handleDragOver,
end: this._handleDragEnd,
cancel: this._handleDragCancel,
});
this._fullscreenController = addFullscreenController(this, {
enter: this._emitFullScreenEvent,
exit: this._emitFullScreenEvent,
});
this._colSpan = 1;
this._rowSpan = 1;
this._colStart = null;
this._rowStart = null;
this._position = -1;
this._resizeState = createTileResizeState();
this._dragStack = createTileDragStack();
this._customAdorners = new Map(Object.entries({
side: false,
corner: false,
bottom: false,
}));
this._setDragConfiguration = ({ instance: { dragMode }, }) => {
this._dragController.set({
enabled: dragMode !== 'none',
trigger: dragMode === 'tile-header' ? () => this._headerRef.value : undefined,
});
};
this._context = createAsyncContext(this, tileManagerContext, this._setDragConfiguration);
this._headerRef = createRef();
this._maximized = false;
this._isDragging = false;
this._isResizing = false;
this.disableResize = false;
this.disableFullscreen = false;
this.disableMaximize = false;
this._createResizeGhost = () => {
return createTileGhost(this);
};
}
static register() {
registerComponent(IgcTileComponent_1, IgcIconButtonComponent, IgcDividerComponent, IgcResizeContainerComponent);
}
get _tileManagerCtx() {
return this._context.value;
}
get _tileManager() {
return this._tileManagerCtx?.instance;
}
get _cssContainer() {
return this._tileManagerCtx?.grid.value;
}
get _resizeMode() {
return this._tileManager?.resizeMode ?? 'none';
}
get _resizeDisabled() {
return (this.disableResize ||
this.maximized ||
this.fullscreen ||
this._resizeMode === 'none');
}
set colSpan(value) {
this._colSpan = Math.max(1, asNumber(value));
this.style.setProperty('--ig-col-span', this._colSpan.toString());
}
get colSpan() {
return this._colSpan;
}
set rowSpan(value) {
this._rowSpan = Math.max(1, asNumber(value));
this.style.setProperty('--ig-row-span', this._rowSpan.toString());
}
get rowSpan() {
return this._rowSpan;
}
set colStart(value) {
this._colStart = Math.max(0, asNumber(value)) || null;
this.style.setProperty('--ig-col-start', this._colStart ? this._colStart.toString() : null);
}
get colStart() {
return this._colStart;
}
set rowStart(value) {
this._rowStart = Math.max(0, asNumber(value)) || null;
this.style.setProperty('--ig-row-start', this._rowStart ? this._rowStart.toString() : null);
}
get rowStart() {
return this._rowStart;
}
get fullscreen() {
return this._fullscreenController.fullscreen;
}
set maximized(value) {
this._maximized = value;
if (this._tileManagerCtx) {
this._tileManagerCtx.instance.requestUpdate();
}
}
get maximized() {
return this._maximized;
}
set position(value) {
this._position = asNumber(value);
this.style.order = this._position.toString();
}
get position() {
return this._position;
}
connectedCallback() {
super.connectedCallback();
this.id = this.id || `tile-${IgcTileComponent_1.increment()}`;
this.style.viewTransitionName =
this.style.viewTransitionName || `tile-transition-${this.id}`;
}
createRenderRoot() {
const root = super.createRenderRoot();
root.addEventListener('slotchange', () => this.requestUpdate());
return root;
}
_setDragState(state = true) {
this._isDragging = state;
this._tileContent.style.opacity = state ? '0' : '';
this.style.pointerEvents = state ? 'none' : '';
this.part.toggle('dragging', state);
}
_handleDragStart() {
if (!this._emitTileDragStart()) {
return false;
}
this._setDragState();
this._dragStack.push(this);
return true;
}
_handleDragOver(parameters) {
const match = parameters.state.element;
const { clientX, clientY } = parameters.event;
if (this._dragStack.peek() === match) {
const { x, y } = getCenterPoint(match);
const shouldSwap = this.position <= match.position
? clientX > x || clientY > y
: clientX < x || clientY < y;
if (shouldSwap) {
this._dragStack.pop();
this._dragStack.push(match);
startViewTransition(() => {
swapTiles(this, match);
});
}
return;
}
this._dragStack.push(match);
startViewTransition(() => {
swapTiles(this, match);
});
}
_handleDragCancel() {
startViewTransition(() => {
this._dragStack.restore();
this._dragStack.reset();
});
this._dragController.dispose();
this._setDragState(false);
this.emitEvent('igcTileDragCancel', { detail: this });
}
_handleDragEnd() {
this._setDragState(false);
this._dragStack.reset();
this.emitEvent('igcTileDragEnd', { detail: this });
}
_skipDrag(event) {
if (this._maximized || this.fullscreen) {
return true;
}
return Boolean(findElementFromEventPath((e) => e.matches('[part*=trigger]') || e.matches('#tile-actions'), event));
}
_match(element) {
return element !== this && IgcTileComponent_1.tagName === element.localName;
}
_createDragGhost() {
return createTileDragGhost(this);
}
_setResizeState(state = true) {
this._isResizing = state;
this.style.zIndex = state ? '1' : '';
this.part.toggle('resizing', state);
}
_handleResizeStart(event) {
if (!this._emitTileResizeStart()) {
event.preventDefault();
return;
}
this._resizeState.updateState(event.detail.state.initial, this, this._cssContainer);
this._setResizeState();
}
_handleResize({ detail: { state }, }) {
const trigger = state.trigger;
const isWidthResize = trigger.matches('[part*="side"], [part="trigger"]');
const isHeightResize = trigger.matches('[part*="bottom"], [part="trigger"]');
if (isWidthResize) {
state.current.width = this._resizeState.calculateSnappedWidth(state);
}
if (isHeightResize) {
state.current.height = this._resizeState.calculateSnappedHeight(state);
}
}
_handleResizeEnd({ detail: { state }, }) {
const { colSpan, rowSpan } = this._resizeState.calculateResizedGridPosition(state.current);
state.commit = async () => {
await startViewTransition(() => {
this.colSpan = colSpan;
this.rowSpan = rowSpan;
}).transition?.updateCallbackDone;
this._setResizeState(false);
this.emitEvent('igcTileResizeEnd', { detail: this });
};
}
_handleResizeCancel() {
this._setResizeState(false);
this.emitEvent('igcTileResizeCancel', { detail: this });
}
_handleFullscreen() {
this._fullscreenController.setState(!this.fullscreen);
}
_handleMaximize() {
if (!this._emitMaximizedEvent()) {
return;
}
this.maximized = !this.maximized;
}
_emitFullScreenEvent(state) {
this.requestUpdate();
return this.emitEvent('igcTileFullscreen', {
detail: { tile: this, state },
cancelable: true,
});
}
_emitMaximizedEvent() {
return this.emitEvent('igcTileMaximize', {
detail: { tile: this, state: !this.maximized },
cancelable: true,
});
}
_emitTileDragStart() {
return this.emitEvent('igcTileDragStart', {
detail: this,
cancelable: true,
});
}
_emitTileResizeStart() {
return this.emitEvent('igcTileResizeStart', {
detail: this,
cancelable: true,
});
}
_renderDefaultAction(type) {
const [icon, listener] = type === 'fullscreen'
? [
this.fullscreen ? 'fullscreen_exit' : 'fullscreen',
this._handleFullscreen,
]
: [
this._maximized ? 'collapse_content' : 'expand_content',
this._handleMaximize,
];
return html `
<igc-icon-button
variant="flat"
collection="default"
exportparts="icon"
name=${icon}
aria-label=${icon}
=${listener}
></igc-icon-button>
`;
}
_renderHeader() {
const hideHeader = isEmpty(this._titleElements) &&
isEmpty(this._actionsElements) &&
this.disableMaximize &&
this.disableFullscreen;
const hasMaximizeSlot = !(this.disableMaximize || this.fullscreen);
const hasFullscreenSlot = !this.disableFullscreen;
return html `
<section part="header" ?hidden=${hideHeader} ${ref(this._headerRef)}>
<header part="title">
<slot name="title"></slot>
</header>
<section id="tile-actions" part="actions">
${hasMaximizeSlot
? html `
<slot name="maximize-action">
${this._renderDefaultAction('maximize')}
</slot>
`
: nothing}
${hasFullscreenSlot
? html `
<slot name="fullscreen-action">
${this._renderDefaultAction('fullscreen')}
</slot>
`
: nothing}
<slot name="actions"></slot>
</section>
</section>
<igc-divider></igc-divider>
`;
}
_renderContent() {
const parts = partNameMap({
base: true,
draggable: this._tileManager?.dragMode !== 'none',
fullscreen: this.fullscreen,
dragging: this._isDragging,
resizable: !this.disableResize && this._tileManager?.resizeMode !== 'none',
resizing: this._isResizing,
maximized: this.maximized,
});
return html `
<div part=${parts}>
${this._renderHeader()}
<div part="content-container">
<slot></slot>
</div>
</div>
`;
}
_renderAdornerSlot(name) {
return html `
<slot
=${() => this._customAdorners.set(name, true)}
name="${name}-adorner"
slot="${name}-adorner"
>
</slot>
`;
}
render() {
const isActive = this._resizeMode === 'always';
return this._resizeDisabled
? this._renderContent()
: html `
<igc-resize
part=${partNameMap({
resize: true,
'side-adorner': this._customAdorners.get('side'),
'corner-adorner': this._customAdorners.get('corner'),
'bottom-adorner': this._customAdorners.get('bottom'),
})}
exportparts="trigger-side, trigger, trigger-bottom"
mode="deferred"
?active=${isActive}
.ghostFactory=${this._createResizeGhost}
=${this._handleResizeStart}
=${this._handleResize}
=${this._handleResizeEnd}
=${this._handleResizeCancel}
>
${this._renderContent()} ${this._renderAdornerSlot('side')}
${this._renderAdornerSlot('corner')}
${this._renderAdornerSlot('bottom')}
</igc-resize>
`;
}
};
IgcTileComponent.tagName = 'igc-tile';
IgcTileComponent.styles = [styles, shared];
IgcTileComponent.increment = createCounter();
__decorate([
queryAssignedElements({ slot: 'title' })
], IgcTileComponent.prototype, "_titleElements", void 0);
__decorate([
queryAssignedElements({ slot: 'actions' })
], IgcTileComponent.prototype, "_actionsElements", void 0);
__decorate([
query(IgcResizeContainerComponent.tagName)
], IgcTileComponent.prototype, "_resizeContainer", void 0);
__decorate([
query('[part~="base"]', true)
], IgcTileComponent.prototype, "_tileContent", void 0);
__decorate([
state()
], IgcTileComponent.prototype, "_maximized", void 0);
__decorate([
state()
], IgcTileComponent.prototype, "_isDragging", void 0);
__decorate([
state()
], IgcTileComponent.prototype, "_isResizing", void 0);
__decorate([
property({ type: Number, attribute: 'col-span' })
], IgcTileComponent.prototype, "colSpan", null);
__decorate([
property({ type: Number, attribute: 'row-span' })
], IgcTileComponent.prototype, "rowSpan", null);
__decorate([
property({ type: Number, attribute: 'col-start' })
], IgcTileComponent.prototype, "colStart", null);
__decorate([
property({ type: Number, attribute: 'row-start' })
], IgcTileComponent.prototype, "rowStart", null);
__decorate([
property({ type: Boolean, reflect: true })
], IgcTileComponent.prototype, "maximized", null);
__decorate([
property({ type: Boolean, reflect: true, attribute: 'disable-resize' })
], IgcTileComponent.prototype, "disableResize", void 0);
__decorate([
property({ type: Boolean, reflect: true, attribute: 'disable-fullscreen' })
], IgcTileComponent.prototype, "disableFullscreen", void 0);
__decorate([
property({ type: Boolean, reflect: true, attribute: 'disable-maximize' })
], IgcTileComponent.prototype, "disableMaximize", void 0);
__decorate([
property({ type: Number })
], IgcTileComponent.prototype, "position", null);
IgcTileComponent = IgcTileComponent_1 = __decorate([
themes(all)
], IgcTileComponent);
export default IgcTileComponent;
//# sourceMappingURL=tile.js.map