@telekom/scale-components
Version:
Scale is the digital design system for Telekom products and experiences.
1,102 lines (1,085 loc) • 60.4 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const index = require('./index-a0ea3d79.js');
const index$1 = require('./index-53f5a5fc.js');
const utils = require('./utils-e9c3b953.js');
/**
* @license
* Scale https://github.com/telekom/scale
*
* Copyright (c) 2021 Egor Kirpichev and contributors, Deutsche Telekom AG
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
// Expected content: boolean, eg `true`
// Options
// style?: string 'switch' | 'checkbox'
// editable?: boolean = false
const CheckboxCell = {
defaults: {
sortBy: 'number',
},
getLongestContent({ rows, columnIndex }) {
// Skip check as content width is always the same
return rows[0][columnIndex];
},
render: ({ field, content, component, rowIndex, columnIndex }) => {
const { style = 'checkbox', editable = false, label } = field;
const props = {
checked: content,
disabled: !editable,
label,
};
if (editable) {
props.onScaleChange = (ev) => {
const { value } = ev.detail;
// Update rows data
component.rows[rowIndex][columnIndex] = value;
// Trigger event
component.triggerEditEvent(value, rowIndex, columnIndex);
};
}
switch (style) {
case 'switch':
return index.h("scale-switch", Object.assign({ size: "small" }, props));
default:
// 'checkbox'
return index.h("scale-checkbox", Object.assign({}, props));
}
},
};
/**
* @license
* Scale https://github.com/telekom/scale
*
* Copyright (c) 2021 Egor Kirpichev and contributors, Deutsche Telekom AG
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
// Expected: date/time string, eg '10:23:00'
// TODO: see if this is even worth it. It may help with sorting/filtering?
// work out format requirements - as date/time formatting is heavy eg moment.js
// const { inputFormat, outputFormat } = field;
// inputFormat: 'HH:mm:ss', // ['timestamp', '']
// outputFormat: 'HH:mm',
const DateCell = {
defaults: {
sortBy: 'text',
},
render: ({ content, isAutoWidthCheck }) => {
let value = content;
// Render all digits with 8s as they're the widest
if (isAutoWidthCheck) {
value = value.replace(/[0-9]/g, '8');
}
return index.h("p", { class: `scl-body` }, value);
},
};
/**
* @license
* Scale https://github.com/telekom/scale
*
* Copyright (c) 2021 Egor Kirpichev and contributors, Deutsche Telekom AG
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
// Expected content: an email string (eg: 'mailto:example@domain.com)
const EmailCell = {
defaults: {
sortBy: 'text',
},
render: ({ content }) => {
// Remove protocol (mailto:)
const emailNoProtocol = content.replace(/^mailto:/i, '');
return index.h("scale-link", { href: content }, emailNoProtocol);
},
};
/**
* @license
* Scale https://github.com/telekom/scale
*
* Copyright (c) 2021 Egor Kirpichev and contributors, Deutsche Telekom AG
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
// Expected content: number, eg 10230.32
// Options
// style?: string 'bar' | 'progress'
// min?: number 0
// max?: number 100
const GraphCell = {
defaults: {
sortBy: 'number',
},
render: ({ field, content }) => {
const { style = 'progress', min = 0, max = 100 } = field;
// Convert content to 0>100 range for progress bar
const progress = parseFloat((((content - min) / (max - min)) * 100).toPrecision(String(content).replace('.', '').length));
// I really don't know the difference between bar and progress
switch (style) {
case 'bar':
return (index.h("div", { class: `tbody__bar-cell` },
index.h("scale-progress-bar", { class: "data-grid-progress-bar", "aria-hidden": "true", percentage: progress,
// showStatus={true}
mute: true }),
index.h("p", { class: `scl-body` }, content)));
default:
// progress
return (index.h("scale-progress-bar", { class: "data-grid-progress-bar", percentage: progress, showStatus: true, mute: true }));
}
},
};
/**
* @license
* Scale https://github.com/telekom/scale
*
* Copyright (c) 2021 Egor Kirpichev and contributors, Deutsche Telekom AG
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
// Expected content: a url string (eg: 'https://sample.com')
const LinkCell = {
defaults: {
sortBy: 'text',
},
render: ({ content }) => {
// Remove protocol (http/https)
const urlNoProtocol = content.replace(/^https?\:\/\//i, '');
return (index.h("scale-link", { href: content, target: "_blank" }, urlNoProtocol));
},
};
/**
* @license
* Scale https://github.com/telekom/scale
*
* Copyright (c) 2021 Egor Kirpichev and contributors, Deutsche Telekom AG
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
// Expected content: HTMLElement
const HTMLCell = {
defaults: {},
getLongestContent({ rows, columnIndex }) {
// Skip check as content width is always the same
return rows[0][columnIndex];
},
render: ({ content, component }) => {
return (content && (index.h("scale-button", { variant: "secondary", size: "small", "icon-only": true, "inner-aria-label": `Activate to ${content.isExpanded ? 'collapse' : 'expand'} content`, onClick: () => {
content.isExpanded = !content.isExpanded;
component.forceRender++;
} }, content.isExpanded ? (index.h("scale-icon-navigation-collapse-up", { size: 14 })) : (index.h("scale-icon-navigation-collapse-down", { size: 14 })))));
},
};
/**
* @license
* Scale https://github.com/telekom/scale
*
* Copyright (c) 2021 Egor Kirpichev and contributors, Deutsche Telekom AG
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
// Expected content: number or string, eg `120.0`
// Options
// precision
// decimalSymbol
// groupSymbol
// editable?: boolean = false / removed/deprecated in 3.0.0-beta.135
const NumberCell = {
defaults: {
textAlign: 'right',
sortBy: 'number',
},
render: ({ field, content,
// component,
// rowIndex,
// columnIndex,
isAutoWidthCheck, }) => {
const { precision = Infinity, decimalSymbol = '.', groupSymbol = '', prefix = '', suffix = '', } = field;
// Input component doesn't expand with content, so need to return a fake element that simulates width
// if (isAutoWidthCheck && editable) {
// return (
// <p class={`scl-body`} style={{ paddingRight: '26px' }}>
// {content}
// </p>
// );
// }
// const step = `0.${(String(content).split('.')[1] || '')
// .split('')
// .map(() => '0')}`.replace(/,/g, '');
// if (editable) {
// const props = {
// type: 'number',
// size: 'small',
// step: step.slice(0, step.length - 1) + '1',
// value: String(content),
// styles: /* css */ `.text-field__control {
// text-align: right !important;
// }`,
// label,
// } as any;
// // TODO: use blur to reduce number of changes - but doesn't pass value
// props.onScaleChange = ({ detail }) => {
// const { value } = detail;
// // Update rows data
// component.rows[rowIndex][columnIndex] = value;
// // Trigger event
// component.triggerEditEvent(value, rowIndex, columnIndex);
// };
// return <scale-text-field {...props}></scale-text-field>;
// } else {
// }
let value = content;
// Render all digits with 8s as they're the widest
if (isAutoWidthCheck) {
value = Number(value.toString().replace(/[0-9]/g, '8'));
}
// Refine to requested decimal precision
if (precision < 100) {
value = Number(value).toFixed(precision);
}
else {
value = value.toString();
}
// Replace/add requested delimiters
if (groupSymbol || decimalSymbol !== '.') {
const parts = value.split('.');
if (groupSymbol) {
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, groupSymbol);
}
value = parts.join(decimalSymbol);
}
// Add prefix/suffix
if (prefix || suffix) {
value = prefix + value + suffix;
}
return (index.h("p", { class: `scl-body`, style: { textAlign: 'right' } }, value));
},
};
/**
* @license
* Scale https://github.com/telekom/scale
*
* Copyright (c) 2021 Egor Kirpichev and contributors, Deutsche Telekom AG
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
// Expected: string
// Options
// options: string array
// editable?: boolean = false
const SelectCell = {
defaults: {
sortBy: 'text',
},
render: ({ field, content, component, rowIndex, columnIndex, isAutoWidthCheck, }) => {
const { options, editable = false, label } = field;
// Select component doesn't expand with content, so need to return a fake element that simulates width
if (isAutoWidthCheck) {
return (index.h("p", { class: `scl-body`, style: { paddingRight: '56px' } }, content));
}
const props = {
disabled: !editable,
value: content,
label,
};
if (editable) {
props.onScaleChange = ({ detail }) => {
const { value } = detail;
// Update rows data
component.rows[rowIndex][columnIndex] = value;
// Trigger event
component.triggerEditEvent(value, rowIndex, columnIndex);
};
}
return (index.h("scale-dropdown-select", Object.assign({ floatingStrategy: "fixed" }, props), options.map((option) => {
return (index.h("scale-dropdown-select-item", { value: option }, option));
})));
},
};
/**
* @license
* Scale https://github.com/telekom/scale
*
* Copyright (c) 2021 Egor Kirpichev and contributors, Deutsche Telekom AG
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
// Expected: comma delimited string (eg 'one, two, three')
const TagsCell = {
defaults: {
sortBy: 'text',
},
render: ({ content }) => {
const tags = content.split(',').map((s) => s.trim());
return (index.h("ul", { class: `tbody__tag-list` }, tags.map((tag) => (index.h("li", null,
index.h("scale-tag", { size: "small", type: "strong" }, tag))))));
},
};
/**
* @license
* Scale https://github.com/telekom/scale
*
* Copyright (c) 2021 Egor Kirpichev and contributors, Deutsche Telekom AG
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
// Expected content: a telephone number string (eg: 'tel:+491234567')
const TelephoneCell = {
defaults: {
sortBy: 'text',
},
render: ({ content }) => {
// Remove protocol (tell:)
const telephoneNoProtocol = content.replace(/^tel:/i, '');
return index.h("scale-link", { href: content }, telephoneNoProtocol);
},
};
/**
* @license
* Scale https://github.com/telekom/scale
*
* Copyright (c) 2021 Egor Kirpichev and contributors, Deutsche Telekom AG
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
// Expected content: unformated string 'this is a string'
// Options
// variant?: string 'body' | 'h6' | 'h5' | etc
// editable?: boolean = false
// iconPrefix?: string eg 'action-download'
// iconSuffix?: string eg 'action-download'
const TextCell = {
defaults: {
sortBy: 'text',
},
render: ({ field, content, component, rowIndex, columnIndex, isAutoWidthCheck, }) => {
const { variant = 'body', editable = false, iconPrefix, iconSuffix, label, } = field;
// Input component doesn't expand with content, so need to return a fake element that simulates width
if (isAutoWidthCheck && editable) {
return (index.h("p", { class: `scl-body`, style: { paddingRight: '26px' } }, content));
}
if (editable) {
const props = {
type: 'text',
value: content,
label,
};
// TODO: use blur to reduce number of changes - but doesn't pass value
// TODO: apply variant and iconPrefix/Suffix to editable text
props.onScaleChange = ({ detail }) => {
const { value } = detail;
// Update rows data
component.rows[rowIndex][columnIndex] = value;
// Trigger event
component.triggerEditEvent(value, rowIndex, columnIndex);
};
return index.h("scale-text-field", Object.assign({}, props));
}
else {
let value = content;
// Add an extra couple of characters for the width check to avoid clipping
if (isAutoWidthCheck) {
value += 'w';
}
return (index.h("div", { class: `tbody__text-cell` },
iconPrefix && (index.h("span", { class: `tbody__text-cell-prefix` }, index.h(`scale-icon-${iconPrefix}`))),
index.h("p", { class: `scl-${variant}` }, value),
iconSuffix && (index.h("span", { class: `tbody__text-cell-suffix` }, index.h(`scale-icon-${iconSuffix}`)))));
}
},
};
/**
* @license
* Scale https://github.com/telekom/scale
*
* Copyright (c) 2021 Egor Kirpichev and contributors, Deutsche Telekom AG
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
var __rest = (undefined && undefined.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
const ActionsCell = {
defaults: {},
render: ({ content }) => {
return (index.h("div", { class: `tbody__actions` }, content.map((action) => {
const { label } = action, props = __rest(action, ["label"]);
if (typeof label === 'object' && '__html' in label) {
return (index.h("scale-button", Object.assign({ size: "small", innerHTML: label.__html }, props)));
}
return (index.h("scale-button", Object.assign({ size: "small" }, props), label));
})));
},
};
/**
* @license
* Scale https://github.com/telekom/scale
*
* Copyright (c) 2021 Egor Kirpichev and contributors, Deutsche Telekom AG
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
const CELL_TYPES = {
checkbox: CheckboxCell,
date: DateCell,
email: EmailCell,
graph: GraphCell,
html: HTMLCell,
link: LinkCell,
number: NumberCell,
select: SelectCell,
tags: TagsCell,
telephone: TelephoneCell,
text: TextCell,
actions: ActionsCell,
};
// Fallback if no type set on field
const DEFAULT_CELL_TYPE = 'text';
// Common cell defaults, can be overridden in cell type classes
const CELL_DEFAULTS = {
maxWidth: Infinity,
minWidth: 20,
resizable: true,
sortable: false,
sortBy: 'text',
textAlign: 'left',
visible: true,
width: 'auto',
};
const dataGridCss = ".scl-body{margin:0;font:var(--telekom-text-style-body)}.scl-label{margin:0;font:var(--telekom-text-style-small)}.scl-h1{margin:0;font:var(--telekom-text-style-heading-1)}.scl-h2{margin:0;font:var(--telekom-text-style-heading-2)}.scl-h3{margin:0;font:var(--telekom-text-style-heading-3)}.scl-h4{margin:0;font:var(--telekom-text-style-heading-4)}.scl-h5{margin:0;font:var(--telekom-text-style-heading-5)}.scl-h6{margin:0;font:var(--telekom-text-style-heading-6)}:host{font-family:var(--telekom-typography-font-family-sans);font-size:var(--telekom-typography-font-size-body);font-weight:var(--telekom-typography-font-weight-regular);line-height:var(--telekom-typography-line-spacing-standard);color:var(--telekom-color-text-and-icon-standard)}.data-grid input,.data-grid select{letter-spacing:inherit;font-weight:inherit;font-family:inherit;line-height:inherit}.data-grid{position:relative;display:block;background:var(--telekom-color-ui-state-fill-standard);border-radius:var(--telekom-radius-large);border:1px solid var(--telekom-color-ui-faint);overflow:hidden}.data-grid--hide-border{border:none}.data-grid__auto-width-check{opacity:0}.data-grid__title-block{display:flex;align-items:center;justify-content:flex-end;padding-right:var(--telekom-spacing-composition-space-06);padding-left:var(--telekom-spacing-composition-space-08)}.data-grid__heading{flex-grow:1}.data-grid__title-block ::slotted(*){margin-left:var(--telekom-spacing-composition-space-04)}.data-grid__settings-menu{margin-left:var(--telekom-spacing-composition-space-04)}.data-grid__scroll-container{overflow:auto;overflow-x:overlay;overflow-y:overlay;ms-overflow-style:-ms-autohiding-scrollbar;scrollbar-gutter:stable}.data-grid__table{border-spacing:0;border-collapse:collapse;overflow:hidden}.data-grid--hide-menu .data-grid__settings-menu{display:none}.data-grid:not(.data-grid--hide-menu) .data-grid__title-block{min-height:72px}.data-grid--hide-menu .data-grid__title-block{padding-right:var(--telekom-spacing-composition-space-06)}.thead{display:block;white-space:nowrap;border-bottom:1px solid var(--telekom-color-ui-faint);position:relative;background:var(--telekom-color-ui-state-fill-standard);z-index:1}.data-grid--freeze-header .thead{z-index:30;background-color:var(--telekom-color-background-canvas)}.thead-sortable{cursor:pointer}.thead-sortable:focus{box-shadow:inset 0 0 0 var(--telekom-spacing-composition-space-02)\n var(--telekom-color-functional-focus-standard)}.thead__cell{display:inline-flex;align-items:center;height:var(--telekom-spacing-composition-space-10);text-align:left;user-select:none;position:relative;padding:0 var(--telekom-spacing-composition-space-06);color:var(--telekom-color-text-and-icon-additional)}.thead__cell--numbered{text-align:right;justify-content:flex-end}.thead__cell--selection{justify-content:center;text-align:center}.thead__cell--selection xds-checkbox::part(container){justify-content:center}.thead__title{color:var(--telekom-color-text-and-icon-standard)}.thead__text{font-size:var(--telekom-typography-font-size-small);line-height:var(--telekom-typography-line-spacing-standard);position:relative}.thead__arrow-top,.thead__arrow-bottom{position:absolute;display:none !important;top:-2px;left:-16px}.thead__sort-prompt{position:absolute;top:0;left:0;width:100%;height:100%;margin:0;background:none;border:0;opacity:1;cursor:pointer}.thead__divider{position:absolute;right:calc(-1 * var(--telekom-spacing-composition-space-04));bottom:0px;height:100%;padding:19px var(--telekom-spacing-composition-space-04) 0px;box-sizing:border-box;cursor:col-resize;z-index:1}.thead__divider-line{pointer-events:none;height:100%;width:1px;background:var(--telekom-color-ui-faint)}.thead__cell:first-child{padding-left:var(--telekom-spacing-composition-space-08)}.thead__cell:focus{outline:none}.thead__cell[aria-sort='ascending'] .thead__arrow-top{display:inline-flex !important}.thead__cell[aria-sort='descending'] .thead__arrow-bottom{display:inline-flex !important}.thead__cell[aria-sort]:hover{color:var(--telekom-color-text-and-icon-primary-hovered)}.thead__cell[aria-sort='none']:hover .thead__arrow-top,.thead__cell[aria-sort='none']:hover .thead__arrow-bottom{display:none !important}.thead__cell[aria-sort='ascending']:hover .thead__arrow-top{color:var(--telekom-color-text-and-icon-primary-hovered)}.thead__cell[aria-sort='descending']:hover .thead__arrow-bottom{color:var(--telekom-color-text-and-icon-primary-hovered)}.tbody{display:block}.tbody__row{display:block;white-space:nowrap}.tbody__mobile-title{display:none}.tbody__mobile-label{display:none}.tbody__cell{display:inline-block;margin:8px;padding:8px;overflow:hidden;}.tbody__cell--numbered{text-align:right}.tbody__cell--selection{justify-content:center;text-align:center}.tbody__cell--selection scale-checkbox::part(container),.tbody__cell--selection scale-checkbox [part='container']{justify-content:center}.tbody__cell scale-checkbox{width:auto}.tbody__nested{white-space:nowrap;padding:0px;margin:0px}.tbody__nested-cell{display:block;padding:var(--telekom-spacing-composition-space-06);margin:0px}.tbody__cell:first-of-type{margin-left:var(--telekom-spacing-composition-space-06);}.tbody__nested-cell:first-child{margin-left:0px}.data-grid--shade-alternate .tbody__row:nth-of-type(even),.data-grid--shade-alternate .tbody__nested:nth-of-type(even){background:var(--telekom-color-background-surface-subtle)}.data-grid__auto-width-check .tbody__cell{padding:0}.tbody__tag-list{list-style:none;padding:0;margin:0}.tbody__tag-list li{display:inline-block;margin-right:8px}.tbody__tag-list li:last-child{margin-right:0}.data-grid input[type='checkbox']{display:block;height:14px;margin:5px 4px}.tbody__text-cell{display:flex;align-items:center}.tbody__text-cell-prefix{display:inline-flex;align-items:center;margin-right:0.5em}.tbody__text-cell-suffix{display:inline-flex;align-items:center;margin-left:0.5em}.tbody__cell p{overflow:hidden;text-overflow:ellipsis}.tbody__cell scale-link{overflow:hidden;text-overflow:ellipsis}.tbody__bar-cell{display:inline-flex;width:100%}.tbody__cell scale-progress-bar{flex-grow:1}.tbody__actions scale-button{margin-right:var(--telekom-spacing-composition-space-04)}.data-grid-progress-bar::part(progress-bar){min-width:50px;max-width:200px}.data-grid-progress-bar::part(status){padding-top:0}.info{height:44px;position:relative;border-top:var(--telekom-line-weight-standard) solid\n var(--telekom-color-ui-subtle);display:flex;justify-content:center}.info__selection{position:absolute;bottom:0;line-height:54px;left:var(--telekom-spacing-composition-space-08)}.data-grid--hide-border:not(.data-grid--mobile) .info__pagination{border-bottom:1px solid var(--telekom-color-ui-subtle);border-right:1px solid var(--telekom-color-ui-subtle)}.data-grid--mobile{border:none;background:none}.data-grid--mobile .data-grid__title-block{padding-left:0;padding-right:0}.data-grid--hide-menu.data-grid--mobile .data-grid__title-block{padding-right:0}.data-grid--mobile .data-grid__settings-menu{right:0}.data-grid--mobile .data-grid__scroll-container{height:auto !important}.data-grid--mobile .data-grid__table{display:block;height:auto !important}.data-grid--mobile .thead{display:none}.data-grid--mobile .tbody{display:block}.data-grid--mobile .tbody__row{display:block;position:relative;white-space:initial;margin:0 0 var(--telekom-spacing-composition-space-04);padding:var(--telekom-spacing-composition-space-08);border-radius:var(--telekom-radius-standard);background:var(--telekom-color-background-surface);border:1px solid var(--telekom-color-ui-faint)}.data-grid--mobile .tbody__row:hover{background:var(--telekom-color-background-surface)}.data-grid--mobile .tbody__mobile-title{display:block;margin-bottom:var(--telekom-spacing-composition-space-04)}.data-grid--mobile .tbody__mobile-label{display:block}.data-grid--mobile .tbody__cell{display:flex;align-items:center;width:auto !important;padding:5px 0;margin:0;min-height:var(--telekom-spacing-composition-space-08);line-height:var(--telekom-spacing-composition-space-08);overflow:auto;overflow-x:hidden}.data-grid--mobile .tbody__cell--used-as-mobile-title{display:none}.data-grid--mobile .tbody__mobile-label{display:block;width:100px;flex-shrink:0;color:var(--telekom-color-text-and-icon-additional);font-size:var(--telekom-typography-font-size-small);font-weight:var(--telekom-typography-font-weight-medium)}.data-grid--mobile .tbody__cell:first-child{margin-left:0px}.data-grid--mobile .tbody__cell--selection{position:absolute;top:19px;right:12px}.data-grid--mobile .tbody__cell--numbered{position:absolute;top:19px;right:56px}.data-grid--mobile .tbody__cell scale-text-field,.data-grid--mobile .tbody__cell scale-dropdown{width:100%}.data-grid--mobile .tbody__nested{width:auto !important}.data-grid--mobile .tbody__nested-cell{padding:0;margin-bottom:var(--telekom-spacing-composition-space-04)}.data-grid--mobile.data-grid--shade-alternate .tbody__row:nth-of-type(even){background:var(--telekom-color-background-surface)}.data-grid--mobile .info{height:auto;border-top:none;text-align:center}.data-grid--mobile .info__selection{position:relative;left:0}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}";
/* Reused Private Variables */
let resizeObserver;
const name = 'data-grid';
const DataGrid = class {
/* 6. Lifecycle Events (call order) */
constructor(hostRef) {
index.registerInstance(this, hostRef);
this.scaleEdit = index.createEvent(this, "scale-edit", 7);
this.scaleEditLegacy = index.createEvent(this, "scaleEdit", 7);
this.scaleSort = index.createEvent(this, "scale-sort", 7);
this.scaleSortLegacy = index.createEvent(this, "scaleSort", 7);
/* 2. State Variables (alphabetical) */
/** Used to force render after sorting/selection */
this.forceRender = 0;
/** Pagination starting index */
this.paginationStart = 0;
/** Table scroll value for frozen header */
this.scrollY = 0;
/** (optional) Freeze header row from scrolling */
this.freezeHeader = false;
/** (optional) Heading string */
this.heading = '';
/** (optional) Set to true to remove border */
this.hideBorder = false;
/** (optional) Set to true to hide header row */
this.hideHeader = false;
/** (optional) Set to true to remove info footer block including pagination and selection status */
this.hideInfo = false;
/** (optional) Set to true to hide settings menu */
this.hideMenu = false;
/** (optional) Set to true to add numbers column */
this.numbered = false;
/** (optional) Set number of rows to display per pagination page */
this.pageSize = Infinity;
/** (optional) Set to true to add selection column */
this.selectable = false;
/** Read-only selection array - populated with raw data from selected rows */
this.selection = [];
/** (optional) Shade every second row darker */
this.shadeAlternate = true;
/** (optional) Set to false to hide table, used for nested tables to re-render upon toggle */
this.visible = true;
/** Stored active sorting column index, for state removal */
this.activeSortingIndex = -1;
/** Track component width to constrict nested content, which is necessary with table layout */
this.contentWidth = 100;
/** Flag to know to check for data completeness */
this.dataNeedsCheck = true;
/** Flag to know if rendering can commence */
this.hasData = false;
/** Flag that is true when width below a certain limit */
this.isMobile = false;
/** Flag that enough data supplied to warrant pagination */
this.isPagination = false;
/** Flag that is true if any fields are sortable */
this.isSortable = false;
/** Track container width to avoid re-calculating column stretching */
this.lastContainerWidth = 100;
/** Index of field to use as mobile title, if any */
this.mobileTitleIndex = -1;
/** Determine if auto-width parsing needed */
this.needsAutoWidthParse = false;
/** Force column resize after render */
this.needsColumnResize = false;
/** Auto-calculated number column width */
this.numberColumnWidth = 0;
/** Selection column width */
this.selectionColumnWidth = 22;
this.handleMenuListClick = (event) => {
const menuItems = ['sortBy', 'toggleVisibility'];
const currentMenuItemsIndex = menuItems.indexOf(event.target.id);
if (currentMenuItemsIndex > -1) {
// check if there is already opened flyout menu list with different id, if opened, close it
const inactiveMenuItem = this.hostElement.shadowRoot.querySelector(`#${menuItems[1 - currentMenuItemsIndex]}List`);
if (inactiveMenuItem) {
inactiveMenuItem.setAttribute('opened', 'false');
}
}
};
// Bind certain callbacks to scope
this.onDividerMove = this.onDividerMove.bind(this);
this.onDividerUp = this.onDividerUp.bind(this);
this.applyResponsiveClasses = this.applyResponsiveClasses.bind(this);
this.updateColumnStretching = this.updateColumnStretching.bind(this);
}
componentWillLoad() {
this.fieldsHandler();
this.rowsHandler();
}
componentWillUpdate() { }
componentDidRender() {
if (this.needsAutoWidthParse) {
this.calculateAutoWidths();
}
// Wait a frame to avoid warning about possible infinite loop
setTimeout(() => {
if (this.needsColumnResize) {
this.updateColumnStretching();
}
});
}
componentDidLoad() {
this.addResizeObserver();
}
componentDidUpdate() { }
disconnectedCallback() {
this.removeResizeObserver();
}
/* 7. Listeners */
fieldsHandler() {
this.parseFields();
this.checkForMobileTitle();
this.checkForSortableFields();
this.dataNeedsCheck = true;
}
rowsHandler() {
// Reset pagination to the last page of the new records if new records are less than previous.
if (this.paginationStart > this.rows.length) {
this.paginationStart =
this.rows.length - (this.rows.length % this.pageSize);
}
this.parseRows();
this.setInitialRowProps();
this.resetSortingToggle();
this.dataNeedsCheck = true;
// Set flag to dirty to redo column width with new data
this.needsAutoWidthParse = true;
this.needsColumnResize = true;
if (
// when we run out of items on the current page
this.rows.length <= this.paginationStart &&
// and we are NOT on the first page
this.paginationStart - this.pageSize > -1) {
// step back one page
this.paginationStart = this.paginationStart - this.pageSize;
}
}
/* 8. Public Methods */
/* 9. Local Methods */
parseFields() {
if (this.fields && typeof this.fields === 'string') {
this.fields = JSON.parse(this.fields);
}
}
parseRows() {
if (this.rows && typeof this.rows === 'string') {
this.rows = JSON.parse(this.rows);
}
}
setInitialRowProps() {
if (!this.rows || !this.rows.length) {
return;
}
this.rows.forEach((row, i) => {
// Store indices of original order on rows for resetting sorting
row.initialIndex = i;
// Set initial selected flag
row.selected = false;
});
// Determine if pagination will be required
this.isPagination = this.pageSize <= this.rows.length - 1;
}
checkHasData() {
// Need both fields and data content in order to populate
if (!this.fields) {
return false;
}
for (let i = 0; i < this.fields.length; i++) {
// Use default type if none set
if (!this.fields[i].type) {
this.fields[i].type = DEFAULT_CELL_TYPE;
}
if (!CELL_TYPES[this.fields[i].type]) {
// tslint:disable-next-line: no-console
console.warn(`Unrecognised field type: "${this.fields[i].type}"`);
return false;
}
}
if (!this.rows || !this.rows.length) {
return false;
}
for (let i = 0; i < this.rows.length; i++) {
if (this.rows[i].length !== this.fields.length) {
// tslint:disable-next-line: no-console
console.warn(`Unable to render ${this.heading && `"${this.heading}" `}table: row data length not equal to supplied fields.`);
return false;
}
}
return true;
}
checkForMobileTitle() {
// Reset for new data
this.mobileTitleIndex = -1;
if (!this.fields) {
return;
}
this.fields.every(({ mobileTitle }, i) => {
if (mobileTitle) {
this.mobileTitleIndex = i;
return false;
}
return true;
});
}
checkForSortableFields() {
this.isSortable = false;
if (!this.fields) {
return;
}
this.fields.forEach(({ sortable }) => {
if (sortable) {
this.isSortable = true;
}
});
}
getCssClassMap() {
return index$1.classnames(name, !this.isMobile && `${name}--desktop`, this.isMobile && `${name}--mobile`, this.shadeAlternate && `${name}--shade-alternate`, this.freezeHeader && `${name}--freeze-header`, this.hideBorder && `${name}--hide-border`, this.hideMenu && `${name}--hide-menu`);
}
polyfillMousePosition(e) {
// For touch
if (e.changedTouches && e.changedTouches.length) {
e.x = e.changedTouches[0].pageX;
e.y = e.changedTouches[0].pageY;
}
// For cross browser support
if (e.x === undefined) {
e.x = e.clientX;
e.y = e.clientY;
}
}
getDefaultLongestContent({ rows, columnIndex }) {
let maxLength = 0;
let longestContent;
rows.forEach((row) => {
const length = row[columnIndex].toString().length;
if (length > maxLength) {
longestContent = row[columnIndex];
maxLength = length;
}
});
return longestContent;
}
// Selection handlers
toggleSelectAll() {
if (!this.elToggleSelectAll) {
return;
}
this.rows.forEach((row) => (row.selected = this.elToggleSelectAll.checked));
this.updateReadableSelection();
this.forceRender++;
}
toggleRowSelect({ target }, rowIndex) {
this.rows[rowIndex].selected = target.checked;
this.updateReadableSelection();
this.forceRender++;
}
updateReadableSelection() {
this.selection.length = 0;
this.rows.forEach((row) => row.selected && this.selection.push(row));
// Check header checkbox if any or none are selected
const selectAll = this.hostElement.shadowRoot.querySelector('.thead__cell--selection scale-checkbox');
selectAll.checked = !!this.selection.length;
// selectAll.indeterminate = !!this.selection.length;
}
// Sorting handlers
toggleTableSorting(sortDirection, columnIndex, type) {
// Remove sorting from previous column index
if (this.activeSortingIndex > -1 &&
this.activeSortingIndex !== columnIndex) {
this.fields[this.activeSortingIndex].sortDirection = 'none';
}
// Store new column index
this.activeSortingIndex = columnIndex;
const newSortDirection = sortDirection === 'none'
? 'ascending'
: sortDirection === 'ascending'
? 'descending'
: 'none';
this.fields[columnIndex].sortDirection = newSortDirection;
this.sortTable(newSortDirection, type, columnIndex);
}
sortTable(sortDirection, type, columnIndex) {
if (sortDirection === 'none') {
this.rows.sort((a, b) => {
return a.initialIndex - b.initialIndex;
});
}
else {
switch ((CELL_TYPES[type] &&
CELL_TYPES[type].defaults &&
CELL_TYPES[type].defaults.sortBy) ||
CELL_DEFAULTS.sortBy) {
case 'text':
if (sortDirection === 'ascending') {
this.rows.sort((a, b) => {
const textA = a[columnIndex].toLowerCase();
const textB = b[columnIndex].toLowerCase();
return textA < textB ? -1 : textA > textB ? 1 : 0;
});
}
else {
this.rows.sort((a, b) => {
const textA = a[columnIndex].toLowerCase();
const textB = b[columnIndex].toLowerCase();
return textA > textB ? -1 : textA < textB ? 1 : 0;
});
}
break;
case 'number':
if (sortDirection === 'ascending') {
this.rows.sort((a, b) => {
return Number(a[columnIndex]) - Number(b[columnIndex]);
});
}
else {
this.rows.sort((a, b) => {
return Number(b[columnIndex]) - Number(a[columnIndex]);
});
}
break;
}
}
this.forceRender++;
// Trigger event
this.triggerSortEvent(sortDirection, type, columnIndex);
}
resetSortingToggle() {
if (this.activeSortingIndex > -1) {
this.fields[this.activeSortingIndex].sortDirection = 'none';
}
this.activeSortingIndex = -1;
}
// Column resize handlers
onDividerDown(e) {
this.polyfillMousePosition(e);
// For touch - Prevent mousedown firing, and native scroll
e.preventDefault();
// Store divider elem for use in move and end events
this.activeDivider = e.target;
// Store initial value to calculate change
e.target.downX = e.x;
// Reset to avoid reapplying previous change
this.activeDivider.interactiveWidth = 0;
window.addEventListener('mousemove', this.onDividerMove);
window.addEventListener('touchmove', this.onDividerMove);
window.addEventListener('mouseup', this.onDividerUp);
window.addEventListener('touchend', this.onDividerUp);
}
onDividerMove(e) {
// TODO: calculate width stretchWidth to drop in correct location
this.polyfillMousePosition(e);
const { width, min, max } = this.activeDivider.dataset;
const diff = e.x - this.activeDivider.downX;
const newWidth = Math.min(Number(max), Math.max(Number(min), Number(width) + diff));
const adjustedDiff = newWidth - Number(width);
this.activeDivider.interactiveWidth = newWidth;
// Give immediate visual feedback
this.activeDivider.style.transform = `translateX(${adjustedDiff}px)`;
}
onDividerUp() {
const { index } = this.activeDivider.dataset;
// Store new width on the field data
if (this.activeDivider.interactiveWidth) {
this.fields[Number(index)].width = this.activeDivider.interactiveWidth;
}
// Reset visual feedback
this.activeDivider.style.transform = `translateX(0px)`;
window.removeEventListener('mousemove', this.onDividerMove);
window.removeEventListener('touchmove', this.onDividerMove);
window.removeEventListener('mouseup', this.onDividerUp);
window.removeEventListener('touchend', this.onDividerUp);
// Update column stretching before rendering
this.needsColumnResize = true;
this.updateColumnStretching();
// Render to apply change
this.forceRender++;
}
// Column visibility toggle handlers
toggleVisibilityMenu(e) {
e.preventDefault();
// TODO: replace this with contextual menu component, when available
const visibilityToggle = this.hostElement.shadowRoot.querySelector('.visibility-toggle');
const menu = visibilityToggle.children[1];
// By default
if (visibilityToggle.style.display === 'none') {
visibilityToggle.style.display = 'block';
menu.style.transform = `translate(${e.clientX}px, ${e.clientY}px)`;
}
else {
visibilityToggle.style.display = 'none';
}
}
toggleColumnVisibility(value, columnIndex) {
this.fields[columnIndex].visible = value;
this.forceRender++;
// Update column stretching
this.needsColumnResize = true;
this.updateColumnStretching();
}
// Resize handlers
addResizeObserver() {
if (!resizeObserver) {
// @ts-ignore
resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
// Skip if table not visible/attached
if (entry.target.offsetParent === null) {
return;
}
entry.target.applyResponsiveClasses(entry);
entry.target.updateColumnStretching();
}
});
}
this.elMmainContainer = this.hostElement.shadowRoot.querySelector(`.${name}`);
// Add this instance's callbacks, as resizeObserver is reused
this.elMmainContainer.applyResponsiveClasses = this.applyResponsiveClasses;
this.elMmainContainer.updateColumnStretching = this.updateColumnStretching;
resizeObserver.observe(this.elMmainContainer);
}
removeResizeObserver() {
if (this.elMmainContainer) {
resizeObserver.unobserve(this.elMmainContainer);
}
}
applyResponsiveClasses() {
// Apply container-scoped media-query-style classes
const newIsMobile = this.elMmainContainer.offsetWidth <= 500;
if (this.isMobile !== newIsMobile) {
this.forceRender++;
}
this.isMobile = newIsMobile;
}
updateColumnStretching() {
// NOTE: any styling padding/margin width changes need to be adjusted here as well
// Ignore auto-width-check content renders
if (this.needsAutoWidthParse) {
return;
}
const container = this.elMmainContainer;
// Minus 2 for border
const containerWidth = container.offsetWidth - 2;
const hasContainerWidthChanged = this.lastContainerWidth !== containerWidth;
// If width hasn't changed, don't re-calculate
if (!hasContainerWidthChanged && !this.needsColumnResize) {
return;
}
this.needsColumnResize = false;
this.lastContainerWidth = containerWidth;
// Don't calculate when mobile layout
if (container.offsetWidth <= 500) {
return;
}
// The theoretical target width - ignoring any previously applied stretching
const targetContentWidth = (() => {
let total = 0;
// Extra margin on first column
total += 8;
if (this.numbered) {
// 32 for padding+margin
total += this.numberColumnWidth + 32;
// this.selectionColumnWidth;
}
if (this.selectable) {
// 32 for padding+margin
total += this.selectionColumnWidth + 32;
// If both selectable and numbered - adjust for reduced margin between
if (this.numbered) {
total -= 16;
}
}
// Add each visible column's target width
this.fields.forEach(({ visible = true, width }) => {
if (visible) {
// 32 for padding+margin
total += width + 32;
}
});
return total;
})();
// Update value passed to nested content to overcome table display layout
this.contentWidth = Math.max(targetContentWidth, containerWidth);
const diff = containerWidth - targetContentWidth;
if (diff <= 0) {
// content larger than container (scrollbar), remove all stretching
this.fields.forEach((field) => (field.stretchWidth = 0));
}
else {
// container larger than content (gap to the right), calculate stretching
// If stretchWeight set, divide value between total to get final weight
// If stretchWeight unset, share remainder of 1 (if any) between all unset cols
let totalSetWeight = 0;
let unsetColsCount = 0;
this.fields.forEach(({ visible = true, stretchWeight }) => {
// Disregard invisible columns
if (!visible) {
return;
}
if (typeof stretchWeight === 'number') {
totalSetWeight += stretchWeight;
}
else {
unsetColsCount++;
}
});
const remainderWeight = Math.max(0, 1 - totalSetWeight);
// Set total to be divided against to be above 1 to keep total set/unset weights equal to 1
totalSetWeight = Math.max(1, totalSetWeight);
this.fields.forEach((field) => {
const { visible = true, stretchWeight } = field;
if (!visible) {
return;
}
// Actual stretch weight, out of a total 1 for all columns
let weight = 0;
if (typeof stretchWeight === 'number') {
weight = stretchWeight / totalSetWeight;
}
else if (remainderWeight > 0) {
weight = remainderWeight / unsetColsCount;
}
// Apply stretching with the weight percentage
field.stretchWidth = diff * weight;
});
}
this.forceRender++;
}
// Auto column width handlers
calculateAutoWidths() {
let isVisible = false;
const columns = this.hostElement.shadowRoot.querySelectorAll(`.${name}__auto-width-check td`);
columns.forEach((cell) => {
// Make sure table is actually rendered (eg not display:none etc)
if (!isVisible && cell.offsetParent !== null) {
isVisible = true;
}
if (!isVisible) {
return;
}
// Update field width with that of largest content
this.fields[cell.dataset.columnindex].width = cell.clientWidth;
});
if (!isVisible) {
return;
}
// Wrap in setTimeout to avoid warning about forcing render within render callback
setTimeout(() => {
this.needsAutoWidthParse = false;
this.forceRender++;
});
}
// Event triggers
triggerSortEvent(sortDirection, type, columnIndex) {
const data = {
rows: this.rows,
type,
sortDirection,
columnIndex,
};
utils.emitEvent(this, 'scaleSort', data);
}
triggerEditEvent(value, rowIndex, columnIndex) {
const data = {
rows: this.rows,
rowIndex,
columnIndex,
value,
};
utils.emitEvent(this, 'scaleEdit', data);
// Force render for checkboxes
this.forceRender++;
}
onTableScroll() {
if (!this.freezeHeader || this.hideHeader) {
return;
}
// Freeze header
const scrollY = this.elScrollContainer.scrollTop;
this.elTableHead.style.transform = `translateY(${scrollY}px)`;
}
renderSettingsMenu() {
var _a, _b, _c;
return (index.h("scale-menu-flyout", { class: `${name}__settings-menu` }, index.h("scale-button", { slot: "trigger", variant: "secondary", "icon-only": true, "data-sortable": this.isSortable }, index.h("scale-icon-service-settings", { accessibilityTitle: "Table options" })), index.h("scale-menu-flyout-list", null, this.isSortable && (index.h("scale-menu-flyout-item", { id: "sortBy", onClick: this.handleMenuListClick }, index.h("scale-icon-action-sort", { slot: "prefix" }), ((_a = this.localization) === null || _a === void 0 ? void 0 : _a.sortBy) || 'Sort By', index.h("scale-menu-flyout-list", { slot: "sublist", id: "sortByList" }, this.fields.map(({ label, type, sortable, sortDirection = 'none' }, columnIndex) => {
if (!sortable) {
return '';
}
return (index.h("scale-menu-flyout-item", { "onScale-select": () => this.toggleTableSorting(sortDirection, columnIndex, type) }, sortDirection === 'ascending' && (index.h("scale-icon-navigation-collapse-up", { size: 16, slot: "prefix" })), sortDirection === 'descending' && (index.h("scale-icon-navigation-collapse-down", { size: 16, slot: "prefix" })), sortDirection === 'none' && (index.h("scale-icon-navigation-collapse-up", { size: 16, slot: "prefix", style: { opacity: '0' } })), label || type));
})))), index.h("scale-menu-flyout-item", { id: "toggleVisibility", onClick: this.handleMenuListClick }, index.h("scale-icon-action-hide-password", { slot: "prefix" }), ((_b = this.localization) === null || _b === void 0 ? void 0 : _b.toggle) || 'Toggle Visibility', index.h("scale-menu-flyout-list", { slot: "sublist", "close-on-select": "false", id: "toggleVisibilityList" }, this.fields.map(({ label, type, visible = CELL_TYPES[type].defaults.visible !== undefined
? CELL_TYPES[type].defaults.visible
: CELL_DEFAULTS.visible, }, columnIndex) => {
return (index.h("scale-menu-flyout-item", { checkable: "checkbox", checked: !!visible, "onScale-select": () => this.toggleColumnVisibility(!visible, columnIndex) }, label || type));
}))), this.selectable && (index.h("scale-menu-flyout-item", { "onScale-select": () => {
this.elToggleSelectAll.checked =
!this.elToggleSelectAll.checked;
this.toggleSelectAll();
} }, index.h("scale-icon", { slot: "prefix", path: "M20.9328 10.6668C20.5132 10.6668 20.1731 11.0069 20.1731 11.4265V20.3269H1.5194V1.67309H16.5049C16.9245 1.67309 17.2646 1.33292 17.2646 0.913386C17.2646 0.49385 16.9245 0.153687 16.5049 0.153687H0.759699C0.340163 0.153687 0 0.49385 0 0.913386V21.0866C0 21.5062 0.340163 21.8463 0.759699 21.8463H20.9328C21.3523 21.8463 21.6925 21.5062 21.6925 21.0866V11.4265C21.6925 11.0069 21.3524 10.6668 20.9328 10.6668ZM23.7774 0.653387C23.4807 0.356739 22.9997 0.356739 22.703 0.653387L10.3293 13.0272L7.25501 9.9529C6.9583 9.65625 6.47732 9.65625 6.18061 9.9529C5.88396 10.2496 5.88396 10.7306 6.18061 11.0273L9.7921 14.6388C9.94045 14.7871 10.1349 14.8613 10.3293 14.8613C10.5237 14.8613 10.7181 14.7871 10.8665 14.6388L23.7774 1.72778C24.0741 1.43108 24.0741 0.950095 23.7774 0.653387Z" }), ((_c = this.localization) === null || _c === void 0 ? void 0 : _c.select) || 'Select / Deselect All')), index.h("slot", { name: "menu" }))));
}
renderTable() {
if (this.needsAutoWidthParse) {
return this.renderAutoWidthCheck();
}
return (index.h("div", { ref: (el) => (this.elScrollContainer = el), class: `${name}__scroll-container`, style: { height: this.height || 'auto' }, onScroll: (