@freshworks/crayons
Version:
Crayons Web Components library
338 lines (332 loc) • 12.9 kB
JavaScript
import { attachShadow, createEvent, h, Host, proxyCustomElement, Build } from '@stencil/core/internal/client';
import { w as watchIcon, a as waitUntilVisible, b as unwatchIcon, g as getSVGElement, f as fetchIcon, c as getIconLibrary } from './crayons.js';
import { d as defineCustomElement$2 } from './spinner.js';
import { h as handleKeyDown } from './index2.js';
const toastMessageCss = ":host{font-family:var(--fw-font-family, -apple-system, blinkmacsystemfont, \"Segoe UI\", roboto, oxygen, ubuntu, cantarell, \"Open Sans\", \"Helvetica Neue\", sans-serif);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-box-sizing:border-box;box-sizing:border-box}@media screen and (prefers-reduced-motion: reduce){.toast.is-open{-webkit-animation:none;animation:none}}.toast.is-open{display:block;-webkit-animation-duration:0.5s;animation-duration:0.5s;-webkit-animation-name:fadeIn;animation-name:fadeIn;z-index:999}.toast{display:none;position:relative;top:10px;width:400px;padding:0px 0px 16px 0px;border:1px solid #ebeff3;border-radius:4px;background-color:#fff;margin-bottom:16px;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-box-shadow:0px 2px 4px rgba(18, 52, 77, 0.06), 0px 2px 16px rgba(18, 52, 77, 0.16);box-shadow:0px 2px 4px rgba(18, 52, 77, 0.06), 0px 2px 16px rgba(18, 52, 77, 0.16);overflow-wrap:anywhere;word-break:break-word;white-space:normal}.toast.success{border-top:5px solid #00a886}.toast.error{border-top:5px solid #d72d30}.toast.warning{border-top:5px solid #f8ab59}.toast.inprogress{border-top:5px solid #2c5cc5}.toast-container{margin-top:16px;display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start;place-content:center}.toast-container .content{color:#12344d;line-height:20px;-ms-flex:1 1 auto;flex:1 1 auto;font-size:14px;font-weight:500;vertical-align:top}.toast-container .icon{margin:5px 16px 0px 16px}.toast-container .remove{margin:5px 12px 0px 12px}.action-link{color:#2c5cc5;line-height:14px;cursor:pointer;font-size:12px;font-weight:600;padding:8px 0px}@-webkit-keyframes fadeOut{100%{top:-600px}}@keyframes fadeOut{100%{top:-600px}}@-webkit-keyframes fadeIn{0%{top:-600px}100%{top:10px}}@keyframes fadeIn{0%{top:-600px}100%{top:10px}}@media screen and (prefers-reduced-motion: reduce){.toast.fade-out{-webkit-animation:none;animation:none}}.toast.fade-out{-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-name:fadeOut;animation-name:fadeOut}";
const iconColorMap = {
error: '#e43538',
warning: '#c7502f',
info: '#264966',
success: '#00795b',
};
let ToastMessage = class extends HTMLElement {
constructor() {
super();
this.__registerHost();
attachShadow(this);
this.fwLinkClick = createEvent(this, "fwLinkClick", 7);
this.fwRemoveToast = createEvent(this, "fwRemoveToast", 7);
/**
* visibility prop of toast message
*/
this.open = false;
/**
* To indicate toast close timeout
*/
this.isTimedOut = false;
/**
* To add close animation class to toast
*/
this.fadeOut = false;
/**
* State icon size
*/
this.iconSize = 16;
/**
* Type of the toast - success,failure, warning, inprogress
*/
this.type = 'warning';
/**
* Time duration of the toast visibility
*/
this.timeout = 4000;
/**
* The Content of the action link
*/
this.actionLinkText = '';
/**
* won't close automatically
*/
this.sticky = false;
}
openChanged(open) {
if (open)
this.setUpToast();
}
async componentWillLoad() {
if (this.open)
this.setUpToast();
}
async setUpToast() {
this.fadeOut = false;
this.isTimedOut = false;
this.timerId = setTimeout(async () => {
if (!this.sticky) {
if (!this.pauseOnHover || (this.pauseOnHover && !this.isMouseHovered)) {
await this.closeToast();
}
this.isTimedOut = true;
}
}, this.timeout);
}
async mouseHover(value = false) {
this.isMouseHovered = value;
if (this.isTimedOut && !this.isMouseHovered) {
await this.closeToast();
}
}
closingAnimation() {
this.fadeOut = true;
return new Promise((resolve) => setTimeout(() => {
this.open = false;
this.fwRemoveToast.emit(this.controllerEl);
resolve();
}, 500));
}
async closeToast() {
if (this.timerId) {
clearTimeout(this.timerId);
}
await this.closingAnimation();
}
disconnectedCallback() {
this.fwRemoveToast.emit(this.controllerEl);
if (this.timerId)
clearTimeout(this.timerId);
}
render() {
return (h(Host, { onmouseover: () => this.mouseHover(true), onmouseout: () => this.mouseHover(false), "aria-hidden": this.open ? 'false' : 'true' }, h("div", { class: `toast ${this.type} ${this.open ? 'is-open' : ''} ${this.fadeOut ? 'fade-out' : ''}`, "aria-hidden": this.open ? 'false' : 'true' }, h("div", { class: 'toast-container' }, this.type === 'inprogress' ? (h("fw-spinner", { class: 'icon' })) : (h("fw-icon", { class: 'icon', size: this.iconSize, name: this.type, color: iconColorMap[this.type] })), h("div", { class: 'content' }, h("slot", null), this.content, this.actionLinkText.length > 0 ? (h("div", { class: 'action-link', role: 'button', tabindex: '0', onClick: () => this.fwLinkClick.emit(), onKeyDown: handleKeyDown(() => this.fwLinkClick.emit()) }, this.actionLinkText)) : ('')), h("fw-icon", { size: 10, name: 'cross', class: 'remove', color: '#183247', onClick: () => this.closeToast(), library: 'system' })))));
}
get controllerEl() { return this; }
static get watchers() { return {
"open": ["openChanged"]
}; }
static get style() { return toastMessageCss; }
};
ToastMessage = /*@__PURE__*/ proxyCustomElement(ToastMessage, [1, "fw-toast-message", {
"open": [1540],
"type": [1],
"timeout": [2],
"content": [1],
"actionLinkText": [1, "action-link-text"],
"sticky": [4],
"pauseOnHover": [4, "pause-on-hover"],
"isMouseHovered": [32],
"isTimedOut": [32],
"timerId": [32],
"fadeOut": [32],
"iconSize": [32]
}]);
function defineCustomElement$1() {
const components = ["fw-toast-message", "fw-icon", "fw-spinner", "fw-toast-message"];
components.forEach(tagName => { switch (tagName) {
case "fw-toast-message":
if (!customElements.get(tagName)) {
customElements.define(tagName, ToastMessage);
}
break;
case "fw-icon":
if (!customElements.get(tagName)) {
defineCustomElement();
}
break;
case "fw-spinner":
if (!customElements.get(tagName)) {
defineCustomElement$2();
}
break;
case "fw-toast-message":
if (!customElements.get(tagName)) {
defineCustomElement$1();
}
break;
} });
}
const iconCss = ":host{font-family:var(--fw-font-family, -apple-system, blinkmacsystemfont, \"Segoe UI\", roboto, oxygen, ubuntu, cantarell, \"Open Sans\", \"Helvetica Neue\", sans-serif);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-box-sizing:border-box;box-sizing:border-box}:host{display:inline-block}.icon{display:block;color:var(--fw-icon-color, #12344d);height:var(--fw-icon-size, 12px);width:var(--fw-icon-size, 12px)}.icon svg{display:block;width:100%;height:100%}";
let Icon = class extends HTMLElement {
constructor() {
super();
this.__registerHost();
attachShadow(this);
/**
* Identifier of the icon. The attribute’s value must be a valid JS Import Name of the svg in the named export from @freshworks/crayons-icon.
*/
this.dataSvg = '';
/**
* Root Margin in px or percentage for Intersection-Observer. This means from ref to bottom of loaded view , the item loads when it crosses above the negative y margin.
*/
this.xRootMargin = '50px';
/**
* Color in which the icon is displayed, specified as a standard CSS color or as a HEX code.
*/
this.color = '';
/**
* Name of External Library to be used
*/
this.library = 'crayons';
/**
* Enable Intersection Observer. Default is false.
*/
this.lazy = false;
this.setElVisible = false;
this.visible = false;
}
async componentWillLoad() {
if (!this.lazy)
this.visible = true;
else
this.visible = this.setElVisible;
if (!Build.isBrowser || !this.visible) {
return;
}
this.applyIconPropstoState();
}
connectedCallback() {
watchIcon(this);
this.lazy &&
waitUntilVisible(this.intersectionObserver, this.xRootMargin, this.el, () => {
this.setElVisible = true;
this.applyIconPropstoState();
});
}
nameChangeHandler() {
this.applyIconPropstoState();
}
disconnectedCallback() {
unwatchIcon(this);
if (this.intersectionObserver) {
this.intersectionObserver.disconnect();
this.intersectionObserver = undefined;
}
}
async applyIconPropstoState() {
const { name, dataSvg, library } = this;
try {
if (!name && dataSvg) {
this.svg = dataSvg;
}
else if (name) {
const url = this.getIconUrl(name, library);
this.svg = await this.drawIcon(url);
}
else {
console.error("Please provide valid props either 'name' or 'data-svg'.Check the usage docs.");
throw '-invalid props-';
}
}
catch (e) {
console.error(e.message);
this.loadFallbackImage();
}
}
async drawIcon(url) {
const { name, library } = this;
try {
const svgEl = await getSVGElement(url);
this.applySVGMutation(library, name, svgEl);
return svgEl.outerHTML;
}
catch (ex) {
throw new Error(`Exception occured while drawing Icon- ${name} : ${ex.message}`);
}
}
/** Fetches the icon and redraws it. Used to handle library registrations. */
redrawIcon() {
this.applyIconPropstoState();
}
async loadFallbackImage() {
this.svg = await fetchIcon(this.getIconUrlfromlib('image', 'system'));
}
getIconUrl(icon, lib) {
let url = '';
if (!this.src) {
url = this.getIconUrlfromlib(icon, lib);
if (url === undefined) {
console.error(`Error while resolving url for ${this.name}|${this.library}. Please check the lib registration/resolver function.`);
return;
}
}
else
url = `${this.src}/${this.name}.svg`;
return url;
}
getIconUrlfromlib(icon, lib) {
const library = getIconLibrary(lib);
if (icon && library) {
return library.resolver(icon);
}
else {
console.error(`Icon ${icon}/${lib} not registered.Check the Implementation.`);
return;
}
}
applySVGMutation(library, icon, svgEl) {
const iconlibrary = getIconLibrary(library);
if (iconlibrary && iconlibrary.mutator) {
iconlibrary.mutator(svgEl, icon);
}
}
render() {
const style = {};
const accessibilityProps = { 'aria-hidden': true };
const hasLabel = typeof this.label === 'string' && this.label.length > 0;
if (hasLabel) {
accessibilityProps['role'] = 'img';
accessibilityProps['aria-label'] = this.label;
}
if (this.size !== undefined)
style['--fw-icon-size'] = `${this.size}px`;
if (this.color !== undefined)
style['--fw-icon-color'] = this.color;
return (h("div", Object.assign({ class: 'icon' }, accessibilityProps, { style: Object.assign({ height: ` ${this.height}px`, width: `${this.width}px` }, style), innerHTML: this.svg })));
}
static get assetsDirs() { return ["icon-assets"]; }
get el() { return this; }
static get watchers() { return {
"name": ["nameChangeHandler"]
}; }
static get style() { return iconCss; }
};
Icon = /*@__PURE__*/ proxyCustomElement(Icon, [1, "fw-icon", {
"name": [513],
"label": [1],
"dataSvg": [1, "data-svg"],
"src": [1],
"size": [2],
"xRootMargin": [1, "x-root-margin"],
"width": [2],
"height": [2],
"color": [1],
"library": [1],
"lazy": [4],
"setElVisible": [32],
"visible": [32],
"intersectionObserver": [32],
"svg": [32]
}]);
function defineCustomElement() {
const components = ["fw-icon", "fw-icon", "fw-spinner", "fw-toast-message"];
components.forEach(tagName => { switch (tagName) {
case "fw-icon":
if (!customElements.get(tagName)) {
customElements.define(tagName, Icon);
}
break;
case "fw-icon":
if (!customElements.get(tagName)) {
defineCustomElement();
}
break;
case "fw-spinner":
if (!customElements.get(tagName)) {
defineCustomElement$2();
}
break;
case "fw-toast-message":
if (!customElements.get(tagName)) {
defineCustomElement$1();
}
break;
} });
}
export { Icon as I, ToastMessage as T, defineCustomElement as a, defineCustomElement$1 as d };