UNPKG

@freshworks/crayons

Version:
338 lines (332 loc) 12.9 kB
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 };