@square/maker
Version:
Maker Design System by Square
1 lines • 15.1 kB
Source Map (JSON)
{"version":3,"file":"styles.css","mappings":"AA+GA,gBAGA,oDACA,2DACA,qDAJA,aACA,gBAUA,oBANA,0EAOA,CCHA,gBACA,8BAUA,mBALA,SAGA,aACA,sBAEA,yBALA,OAMA,eACA,6CAEA,oBAbA,eAEA,QADA,MAWA,8BAPA,SASA,CAEA,gBAEA,UADA,yBAEA,CAGA,gBACA,6BACA,sBACA,4GAKA,CAEA,2GAMA,CAOA,oCACA,gBACA,4CACA,CACA,CCoGA,gBAGA,uCAFA,sBACA,UAEA,CAGA,oCACA,gBACA,eACA,CACA,CAEA,gBACA,sDACA,CAEA,gBAEA,cACA,uBAFA,aAGA,YACA,CAEA,gCAEA,cACA,WACA,CAEA,gBAEA,mBACA,gCAFA,YAGA,CAEA,gBAGA,yBACA,eAHA,cACA,WAGA,CAEA,gBAIA,aAHA,aACA,YACA,cAEA,CAEA,gBACA,WACA,CAEA,gBAEA,aADA,YAEA,CAEA,gBACA,YACA,CAEA,gBACA,sCACA","sources":["webpack://@square/maker/./src/components/Toast/src/Bread.vue","webpack://@square/maker/./src/components/Toast/src/ToastLayer.vue","webpack://@square/maker/./src/components/Toast/src/Toast.vue"],"sourcesContent":["<template>\n\t<div\n\t\t:class=\"$s.Bread\"\n\t\tv-bind=\"$attrs\"\n\t\tv-on=\"listeners\"\n\t>\n\t\t<slot />\n\t</div>\n</template>\n\n<script>\nimport toastApi from './toast-api';\n\n/**\n * @inheritAttrs div\n * @inheritListeners div\n */\nexport default {\n\tinject: {\n\t\ttoastApi,\n\t},\n\n\tinheritAttrs: false,\n\n\tprops: {\n\t\t/**\n\t\t * make bread persistent (no auto-dismiss)\n\t\t */\n\t\tpersistent: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t\t/**\n\t\t * auto-dismiss after x milliseconds (ignored if persistent)\n\t\t */\n\t\tdismissAfter: {\n\t\t\ttype: Number,\n\t\t\tdefault: 5000,\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tmouseEnterAt: 0,\n\t\t\tmouseLeaveAt: 0,\n\t\t\tcloseQueued: false,\n\t\t};\n\t},\n\n\tcomputed: {\n\t\tlisteners() {\n\t\t\tconst listeners = {\n\t\t\t\t// apply listeners set by parent\n\t\t\t\t...this.$listeners,\n\t\t\t};\n\t\t\tif (this.persistent) {\n\t\t\t\treturn listeners;\n\t\t\t}\n\t\t\t// if this is an auto-dismiss bread then also\n\t\t\t// conditionally apply mouse event listeners\n\t\t\tlisteners['&mouseenter'] = this.onMouseEnter;\n\t\t\tlisteners['&mouseleave'] = this.onMouseLeave;\n\t\t\t// vue protip: prefixed the event name with\n\t\t\t// an & tells vue to apply the passive modifier\n\t\t\treturn listeners;\n\t\t},\n\t},\n\n\tmounted() {\n\t\tif (this.persistent) {\n\t\t\treturn;\n\t\t}\n\t\tthis.closeSelfIn(this.dismissAfter);\n\t},\n\n\tmethods: {\n\t\tonMouseEnter() {\n\t\t\tthis.mouseEnterAt = Date.now();\n\t\t},\n\t\tonMouseLeave() {\n\t\t\tthis.mouseLeaveAt = Date.now();\n\t\t\t// if toast is still within its open duration\n\t\t\t// window then don't do anything, let the\n\t\t\t// current timeout resolve the close action\n\t\t\tif (!this.closeQueued) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst ONE_SECOND = 1000;\n\t\t\tthis.closeSelfIn(ONE_SECOND);\n\t\t},\n\t\tcloseSelfIn(durationMs) {\n\t\t\tthis.closeQueued = false;\n\t\t\tsetTimeout(() => {\n\t\t\t\t// if mouse never hovered over bread, or if it\n\t\t\t\t// hovered over bread but left already then\n\t\t\t\t// close immediately\n\t\t\t\tif (this.mouseLeaveAt >= this.mouseEnterAt) {\n\t\t\t\t\tthis.toastApi.closeSelf();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// if mouse is currently hovering over bread\n\t\t\t\t// then queue up a close action which will\n\t\t\t\t// be resolved when the mouse leaves\n\t\t\t\tthis.closeQueued = true;\n\t\t\t}, durationMs);\n\t\t},\n\t},\n};\n</script>\n\n<style module=\"$s\">\n.Bread {\n\tmargin: 8px 0;\n\toverflow: hidden;\n\tbackground-color: $maker-color-background;\n\tborder-radius: $maker-shape-default-border-radius;\n\tbox-shadow: 0 8px 16px rgba(0, 0, 0, 0.1), 0 4px 32px rgba(0, 0, 0, 0.1);\n\ttransition:\n\t\ttransform 0.5s,\n\t\topacity 0.5s,\n\t\tmax-height 0.5s,\n\t\tmargin 0.5s,\n\t\tpadding 0.5s;\n\tpointer-events: auto;\n}\n</style>\n","<template>\n\t<m-transition-stack\n\t\t:class=\"[\n\t\t\t$s.FullScreenFixed,\n\t\t\t{\n\t\t\t\t[$s.ActionbarOffset]: addActionbarOffset,\n\t\t\t}\n\t\t]\"\n\t\t:before-enter-class=\"$s.fade_bottom\"\n\t>\n\t\t<toast-render-fn\n\t\t\tv-for=\"toast in toastApi.state.toasts\"\n\t\t\t:key=\"toast.key\"\n\t\t\t:render-fn=\"toast.renderFn\"\n\t\t/>\n\t</m-transition-stack>\n</template>\n\n<script>\nimport Vue from 'vue';\nimport { MTransitionStack } from '@square/maker/components/TransitionStack';\nimport ToastRenderFn from './ToastRenderFn';\nimport toastApi from './toast-api';\n\nfunction randomKey() {\n\tconst HEXADECIMAL_RADIX = 36;\n\tconst SLICE_START = 2;\n\tconst SLICE_END = 12;\n\treturn Math\n\t\t.random()\n\t\t.toString(HEXADECIMAL_RADIX)\n\t\t.slice(SLICE_START, SLICE_END);\n}\n\nfunction toastify(renderFn, options) {\n\tconst key = randomKey();\n\treturn {\n\t\t...options,\n\t\tkey,\n\t\trenderFn,\n\t};\n}\n\nconst apiMixin = {\n\tprovide() {\n\t\tconst api = {\n\t\t\tstate: Vue.observable({\n\t\t\t\ttoasts: [],\n\t\t\t}),\n\n\t\t\topen(renderFn, options = {}) {\n\t\t\t\tconst toast = toastify(renderFn, options);\n\t\t\t\tthis.state.toasts.push(toast);\n\t\t\t\t// method that only closes this specific toast\n\t\t\t\treturn () => {\n\t\t\t\t\tconst NOT_FOUND = -1;\n\t\t\t\t\tconst foundIndex = this.state.toasts.indexOf(toast);\n\t\t\t\t\tif (foundIndex !== NOT_FOUND) {\n\t\t\t\t\t\tconst REMOVE_ONE = 1;\n\t\t\t\t\t\tthis.state.toasts.splice(foundIndex, REMOVE_ONE);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t},\n\n\t\t\tclose(renderFn) {\n\t\t\t\tconst foundToast = this.state.toasts.find((toast) => toast.renderFn === renderFn);\n\t\t\t\tif (!foundToast) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst NOT_FOUND = -1;\n\t\t\t\tconst foundIndex = this.state.toasts.indexOf(foundToast);\n\t\t\t\tif (foundIndex === NOT_FOUND) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst REMOVE_ONE = 1;\n\t\t\t\tthis.state.toasts.splice(foundIndex, REMOVE_ONE);\n\t\t\t},\n\n\t\t\tcloseAll() {\n\t\t\t\twhile (this.state.toasts.length) {\n\t\t\t\t\tthis.state.toasts.pop();\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// closeSelf() is implemented in ./ToastRenderFn.js\n\t\t};\n\n\t\tif (!this.toastApi) {\n\t\t\tthis.toastApi = api;\n\t\t}\n\n\t\treturn {\n\t\t\t[toastApi]: api,\n\t\t};\n\t},\n};\n\nexport default {\n\tcomponents: {\n\t\tMTransitionStack,\n\t\tToastRenderFn,\n\t},\n\n\tinject: {\n\t\ttoastApi,\n\t},\n\n\tinheritAttrs: false,\n\n\tapiMixin,\n\n\tcomputed: {\n\t\taddActionbarOffset() {\n\t\t\treturn !!this.toastApi.state.toasts.find((toast) => toast.actionbarOffset);\n\t\t},\n\t},\n};\n</script>\n\n<style module=\"$s\">\n/* stylelint-disable length-zero-no-unit */\n.FullScreenFixed {\n\t--initial-bottom-padding: 16px;\n\n\tposition: fixed;\n\ttop: 0;\n\tright: 0;\n\tbottom: 0;\n\tleft: 0;\n\tz-index: 1;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tjustify-content: flex-end;\n\tpadding: 0 24px;\n\tpadding-bottom: var(--initial-bottom-padding);\n\ttransition: padding-bottom 0.5s;\n\tpointer-events: none;\n}\n\n.fade_bottom {\n\ttransform: translateY(50%);\n\topacity: 0;\n}\n\n/* calculations imported from ActionBarLayer */\n.ActionbarOffset {\n\t--actionbar-top-padding: 24px;\n\t--actionbar-size: 48px;\n\t--actionbar-bottom-padding:\n\t\tcalc(\n\t\t\t24px\n\t\t\t+ env(safe-area-inset-bottom, 24px)\n\t\t\t+ var(--chrome-bottom-offset, 0px)\n\t\t);\n\n\tpadding-bottom:\n\t\tcalc(\n\t\t\tvar(--actionbar-top-padding)\n\t\t\t+ var(--actionbar-size)\n\t\t\t+ var(--actionbar-bottom-padding)\n\t\t);\n}\n\n/*\n * 1) global actionbar is hidden on desktop resolutions\n * 2) inline actionbars aren't fixed to the bottom of\n * the screen on desktop resolutions\n */\n@media screen and (--for-tablet-landscape-up) {\n\t.ActionbarOffset {\n\t\tpadding-bottom: var(--initial-bottom-padding);\n\t}\n}\n</style>\n","<template>\n\t<m-bread\n\t\t:class=\"[\n\t\t\t$s.Toast,\n\t\t\t{\n\t\t\t\t[$s.EnhanceContrast]: enhanceContrast,\n\t\t\t},\n\t\t]\"\n\t\t:persistent=\"resolvedPersistent\"\n\t\t:dismiss-after=\"resolvedDismissAfter\"\n\t\t:style=\"style\"\n\t\trole=\"alert\"\n\t\taria-live=\"assertive\"\n\t\tv-bind=\"$attrs\"\n\t\tv-on=\"$listeners\"\n\t>\n\t\t<div :class=\"$s.ToastContent\">\n\t\t\t<div\n\t\t\t\tv-if=\"resolvedShowIcon\"\n\t\t\t\t:class=\"$s.IconContainer\"\n\t\t\t>\n\t\t\t\t<!-- @slot icon slot, prefer using iconName prop tho -->\n\t\t\t\t<slot name=\"icon\">\n\t\t\t\t\t<m-icon\n\t\t\t\t\t\t:name=\"resolvedIconName\"\n\t\t\t\t\t\t:size=\"iconSize\"\n\t\t\t\t\t/>\n\t\t\t\t</slot>\n\t\t\t</div>\n\t\t\t<div :class=\"$s.TextAndActions\">\n\t\t\t\t<m-text\n\t\t\t\t\telement=\"span\"\n\t\t\t\t\t:class=\"$s.Text\"\n\t\t\t\t\t:color=\"resolvedColor\"\n\t\t\t\t>\n\t\t\t\t\t{{ text }}\n\t\t\t\t</m-text>\n\t\t\t\t<div :class=\"$s.Actions\">\n\t\t\t\t\t<template\n\t\t\t\t\t\tv-for=\"(action, index) in actions\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<m-text-button\n\t\t\t\t\t\t\t:key=\"action.text + 'button'\"\n\t\t\t\t\t\t\tsize=\"large\"\n\t\t\t\t\t\t\t:color=\"resolvedColor\"\n\t\t\t\t\t\t\t@click=\"action.click\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{{ action.text }}\n\t\t\t\t\t\t</m-text-button>\n\t\t\t\t\t\t<m-vertical-divider\n\t\t\t\t\t\t\tv-if=\"index !== actions.length - 1\"\n\t\t\t\t\t\t\t:key=\"action.text + 'divider'\"\n\t\t\t\t\t\t\t:class=\"$s.ActionDivider\"\n\t\t\t\t\t\t\t:style=\"dividerStyle\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t</template>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div\n\t\t\t\t:class=\"$s.ToastClose\"\n\t\t\t\t@click=\"toastApi.closeSelf\"\n\t\t\t>\n\t\t\t\t<m-icon\n\t\t\t\t\t:class=\"$s.CloseIcon\"\n\t\t\t\t\t:size=\"iconSize\"\n\t\t\t\t\tname=\"close\"\n\t\t\t\t/>\n\t\t\t</div>\n\t\t</div>\n\t\t<m-progress-bar\n\t\t\tv-if=\"hasProgress\"\n\t\t\tshape=\"squared\"\n\t\t\tsize=\"xsmall\"\n\t\t\t:class=\"$s.ToastProgressBar\"\n\t\t\t:color=\"resolvedAccentColor\"\n\t\t\t:progress=\"progress\"\n\t\t/>\n\t</m-bread>\n</template>\n\n<script>\nimport { MThemeKey, defaultTheme, resolveThemeableProps } from '@square/maker/components/Theme';\nimport { MVerticalDivider } from '@square/maker/components/VerticalDivider';\nimport { MProgressBar } from '@square/maker/components/ProgressBar';\nimport { MTextButton } from '@square/maker/components/TextButton';\nimport { MIcon } from '@square/maker/components/Icon';\nimport { MText } from '@square/maker/components/Text';\nimport { ICON_SIZES } from '@square/maker/utils/constants';\nimport cssValidator from '@square/maker/utils/css-validator';\nimport MBread from './Bread.vue';\nimport toastApi from './toast-api';\n\n// width & height css props accept same set of values\nconst sizeValidator = cssValidator('width');\n\nconst MIN_PROGRESS = 0;\nconst MAX_PROGRESS = 100;\n\n/**\n * @inheritAttrs div\n * @inheritListeners div\n */\nexport default {\n\tcomponents: {\n\t\tMBread,\n\t\tMIcon,\n\t\tMProgressBar,\n\t\tMTextButton,\n\t\tMText,\n\t\tMVerticalDivider,\n\t},\n\n\tinject: {\n\t\ttoastApi,\n\t\ttheme: {\n\t\t\tdefault: defaultTheme(),\n\t\t\tfrom: MThemeKey,\n\t\t},\n\t},\n\n\tinheritAttrs: false,\n\n\tprops: {\n\t\t/**\n\t\t * pattern defined at theme level\n\t\t */\n\t\tpattern: {\n\t\t\ttype: String,\n\t\t\tdefault: undefined,\n\t\t},\n\t\t/**\n\t\t * make toast persistent (no auto-dismiss)\n\t\t */\n\t\tpersistent: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: undefined,\n\t\t},\n\t\t/**\n\t\t * auto-dismiss after x milliseconds (ignored if persistent)\n\t\t */\n\t\tdismissAfter: {\n\t\t\ttype: Number,\n\t\t\tdefault: undefined,\n\t\t},\n\t\t/**\n\t\t * name of icon to show\n\t\t */\n\t\ticonName: {\n\t\t\ttype: String,\n\t\t\tdefault: undefined,\n\t\t},\n\t\t/**\n\t\t * shows icon\n\t\t */\n\t\tshowIcon: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: undefined,\n\t\t},\n\t\t/**\n\t\t * changes icon size\n\t\t */\n\t\ticonSize: {\n\t\t\ttype: String,\n\t\t\tdefault: 'small',\n\t\t\tvalidator: (size) => ICON_SIZES[size] || sizeValidator(size),\n\t\t},\n\t\t/**\n\t\t * toast text content\n\t\t */\n\t\ttext: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t\t/**\n\t\t * optional toast progress (0 - 100)\n\t\t */\n\t\tprogress: {\n\t\t\ttype: Number,\n\t\t\tdefault: undefined,\n\t\t\tvalidator: (progress) => progress >= MIN_PROGRESS && progress <= MAX_PROGRESS,\n\t\t},\n\t\t/**\n\t\t * toast text & button color\n\t\t */\n\t\tcolor: {\n\t\t\ttype: String,\n\t\t\tdefault: undefined,\n\t\t\tvalidator: cssValidator('color'),\n\t\t},\n\t\t/**\n\t\t * toast icon & progress color\n\t\t */\n\t\taccentColor: {\n\t\t\ttype: String,\n\t\t\tdefault: undefined,\n\t\t\tvalidator: cssValidator('color'),\n\t\t},\n\t\t/**\n\t\t * toast background color\n\t\t */\n\t\tbgColor: {\n\t\t\ttype: String,\n\t\t\tdefault: undefined,\n\t\t\tvalidator: cssValidator('color'),\n\t\t},\n\t\t/**\n\t\t * toast actions\n\t\t */\n\t\tactions: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t\tvalidator(actions) {\n\t\t\t\tfor (const action of actions) {\n\t\t\t\t\tif (!action.text || !action.click) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t},\n\t\t},\n\t},\n\n\tcomputed: {\n\t\t...resolveThemeableProps('toast', [\n\t\t\t'pattern',\n\t\t\t'persistent',\n\t\t\t'dismissAfter',\n\t\t\t'color',\n\t\t\t'bgColor',\n\t\t\t'accentColor',\n\t\t\t'iconName',\n\t\t\t'showIcon',\n\t\t]),\n\t\t/**\n\t\t * if the toast bg color is the same as the page bg color\n\t\t * it's easy for the toast to get lost or blend into the\n\t\t * page too much so we check for this condition and if it's\n\t\t * true we enhance contrast by adding a subtle border to\n\t\t * the toast\n\t\t */\n\t\tenhanceContrast() {\n\t\t\treturn this.resolvedBgColor === this.theme.colors.background;\n\t\t},\n\t\thasProgress() {\n\t\t\treturn this.progress || this.progress === 0;\n\t\t},\n\t\tstyle() {\n\t\t\tconst styles = {};\n\t\t\tif (this.resolvedAccentColor) {\n\t\t\t\tstyles['--toast-accent-color'] = this.resolvedAccentColor;\n\t\t\t}\n\t\t\tif (this.resolvedBgColor) {\n\t\t\t\tstyles['--toast-bg-color'] = this.resolvedBgColor;\n\t\t\t}\n\t\t\tif (this.resolvedColor) {\n\t\t\t\tstyles['--toast-color'] = this.resolvedColor;\n\t\t\t}\n\t\t\treturn styles;\n\t\t},\n\t\tdividerStyle() {\n\t\t\tconst styles = {};\n\t\t\tif (this.resolvedColor) {\n\t\t\t\tstyles.backgroundColor = this.resolvedColor;\n\t\t\t\tstyles.opacity = '0.4';\n\t\t\t}\n\t\t\treturn styles;\n\t\t},\n\t},\n};\n</script>\n\n<style module=\"$s\">\n/* toasts are full-width on mobile */\n.Toast {\n\tbox-sizing: border-box;\n\twidth: 100%;\n\tbackground-color: var(--toast-bg-color);\n}\n\n/* toasts are 600px width on desktop */\n@media screen and (--for-tablet-landscape-up) {\n\t.Toast {\n\t\tmax-width: 600px;\n\t}\n}\n\n.EnhanceContrast {\n\tborder: 1px solid $maker-color-neutral-10;\n}\n\n.ToastContent {\n\tdisplay: flex;\n\tgap: 16px;\n\talign-items: flex-start;\n\tpadding: 16px;\n}\n\n.IconContainer,\n.CloseIcon {\n\tflex-shrink: 0;\n\theight: 24px;\n}\n\n.IconContainer {\n\tdisplay: flex;\n\talign-items: center;\n\tcolor: var(--toast-accent-color);\n}\n\n.ToastClose {\n\tflex-shrink: 0;\n\theight: 24px;\n\tcolor: var(--toast-color);\n\tcursor: pointer;\n}\n\n.TextAndActions {\n\tdisplay: flex;\n\tflex-grow: 1;\n\tflex-wrap: wrap;\n\tgap: 8px;\n}\n\n.Text {\n\tflex-grow: 1;\n}\n\n.Actions {\n\tdisplay: flex;\n\tgap: 4px;\n}\n\n.ActionDivider {\n\tmargin: 0 4px;\n}\n\n.ToastProgressBar {\n\tbackground-color: var(--toast-bg-color);\n}\n</style>\n"],"names":[],"sourceRoot":""}