@internetarchive/elements 0.2.2-zendesk1 → 0.2.2-zendesk2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ia-zendesk-widget.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-zendesk-widget/ia-zendesk-widget.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EACV,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAQb,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd;;;;;WAKG;QACH,EAAE,CAAC,EAAE;YACH,CACE,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE,MAAM,GAAG,OAAO,EACvB,QAAQ,EAAE,MAAM,IAAI,GACnB,IAAI,CAAC;YACR,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;SACvD,CAAC;KACH;CACF;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBACa,eAAgB,SAAQ,UAAU;IAC7C,sFAAsF;IAEtF,SAAS,SAAM;IAEf,8EAA8E;IACrE,OAAO,CAAC,aAAa,CAAQ;IAEtC,yFAAyF;IAChF,OAAO,CAAC,SAAS,CAAS;IAEnC;;;;OAIG;IACH,OAAO,CAAC,YAAY,CAAS;IAE7B;;;;;;;;OAQG;YACW,eAAe;
|
|
1
|
+
{"version":3,"file":"ia-zendesk-widget.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-zendesk-widget/ia-zendesk-widget.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EACV,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAQb,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd;;;;;WAKG;QACH,EAAE,CAAC,EAAE;YACH,CACE,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE,MAAM,GAAG,OAAO,EACvB,QAAQ,EAAE,MAAM,IAAI,GACnB,IAAI,CAAC;YACR,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;SACvD,CAAC;KACH;CACF;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBACa,eAAgB,SAAQ,UAAU;IAC7C,sFAAsF;IAEtF,SAAS,SAAM;IAEf,8EAA8E;IACrE,OAAO,CAAC,aAAa,CAAQ;IAEtC,yFAAyF;IAChF,OAAO,CAAC,SAAS,CAAS;IAEnC;;;;OAIG;IACH,OAAO,CAAC,YAAY,CAAS;IAE7B;;;;;;;;OAQG;YACW,eAAe;IAoC7B;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAezB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAgBtB,OAAO,KAAK,YAAY,GAIvB;IAED,MAAM,IAAI,cAAc;IAYxB,MAAM,KAAK,MAAM,IAAI,cAAc,CAiElC;CACF"}
|
|
@@ -54,26 +54,33 @@ let IAZendeskWidget = class IAZendeskWidget extends LitElement {
|
|
|
54
54
|
async initiateZenDesk() {
|
|
55
55
|
this.isLoading = true;
|
|
56
56
|
this.dispatchEvent(new Event('zendeskHelpButtonClicked'));
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
57
|
+
try {
|
|
58
|
+
if (!this.zendeskReady) {
|
|
59
|
+
await this.loadZendeskScript();
|
|
60
|
+
await this.waitForZendesk();
|
|
61
|
+
// Register lifecycle listeners exactly once.
|
|
62
|
+
// isLoading is cleared here (not earlier) so the spinner persists until
|
|
63
|
+
// the widget panel is actually visible to the user.
|
|
64
|
+
window.zE('messenger:on', 'open', () => {
|
|
65
|
+
this.buttonVisible = false;
|
|
66
|
+
this.isLoading = false;
|
|
67
|
+
});
|
|
68
|
+
// Delay matches the Zendesk close animation so the Help button does not
|
|
69
|
+
// reappear while the panel is still sliding out.
|
|
70
|
+
window.zE('messenger:on', 'close', () => {
|
|
71
|
+
setTimeout(() => {
|
|
72
|
+
this.buttonVisible = true;
|
|
73
|
+
}, 500);
|
|
74
|
+
});
|
|
75
|
+
this.zendeskReady = true;
|
|
76
|
+
}
|
|
77
|
+
window.zE('messenger', 'open');
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
this.isLoading = false;
|
|
81
|
+
// eslint-disable-next-line no-console
|
|
82
|
+
console.error('[ia-zendesk-widget]', err);
|
|
75
83
|
}
|
|
76
|
-
window.zE('messenger', 'open');
|
|
77
84
|
}
|
|
78
85
|
/**
|
|
79
86
|
* Appends the Zendesk snippet `<script>` to `<head>` if it has not already
|
|
@@ -100,14 +107,19 @@ let IAZendeskWidget = class IAZendeskWidget extends LitElement {
|
|
|
100
107
|
* The snippet performs its own async initialisation after loading, so
|
|
101
108
|
* `window.zE` may not be set immediately when `script.onload` fires.
|
|
102
109
|
*/
|
|
103
|
-
waitForZendesk() {
|
|
104
|
-
return new Promise((resolve) => {
|
|
110
|
+
waitForZendesk(timeoutMs = 10_000) {
|
|
111
|
+
return new Promise((resolve, reject) => {
|
|
105
112
|
const check = setInterval(() => {
|
|
106
113
|
if (window.zE) {
|
|
107
114
|
clearInterval(check);
|
|
115
|
+
clearTimeout(timeout);
|
|
108
116
|
resolve();
|
|
109
117
|
}
|
|
110
118
|
}, 100);
|
|
119
|
+
const timeout = setTimeout(() => {
|
|
120
|
+
clearInterval(check);
|
|
121
|
+
reject(new Error('Zendesk API did not initialise in time'));
|
|
122
|
+
}, timeoutMs);
|
|
111
123
|
});
|
|
112
124
|
}
|
|
113
125
|
get iconTemplate() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ia-zendesk-widget.js","sourceRoot":"","sources":["../../../../src/elements/ia-zendesk-widget/ia-zendesk-widget.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n html,\n LitElement,\n type CSSResultGroup,\n type TemplateResult,\n} from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { unsafeHTML, UnsafeHTMLDirective } from 'lit/directives/unsafe-html.js';\n\nimport loaderIconSvg from './loader-icon.svg?raw';\nimport questionIconSvg from './question-icon.svg?raw';\nimport { DirectiveResult } from 'lit/directive.js';\n\ndeclare global {\n interface Window {\n /**\n * Zendesk Messenger API injected by the ze-snippet script.\n * Overloaded to cover the two call shapes we use:\n * - `messenger:on` — subscribe to open/close lifecycle events\n * - `messenger` — imperatively open or close the widget panel\n */\n zE?: {\n (\n target: 'messenger:on',\n event: 'open' | 'close',\n callback: () => void,\n ): void;\n (target: 'messenger', action: 'open' | 'close'): void;\n };\n }\n}\n\n/**\n * A lightweight launcher button that loads and opens the Zendesk Messenger\n * widget on demand.\n *\n * The native Zendesk launcher is never shown — this button is the sole entry\n * point. The Zendesk snippet script is fetched lazily on the first click so\n * it does not affect page load performance.\n *\n * @fires zendeskHelpButtonClicked - Dispatched when the user clicks the Help\n * button, before the widget is opened.\n *\n * @cssprop --button-blue - Button background colour (default: `#194880`).\n * @cssprop --icon-fill-color - SVG icon fill colour (default: `#fff`).\n * @cssprop --link-color - Button text colour (default: `#fff`).\n *\n * @example\n * ```html\n * <ia-zendesk-widget\n * widget-src=\"https://static.zdassets.com/ekr/snippet.js?key=YOUR_KEY\"\n * ></ia-zendesk-widget>\n * ```\n */\n@customElement('ia-zendesk-widget')\nexport class IAZendeskWidget extends LitElement {\n /** URL of the Zendesk `ze-snippet` loader script, including the `key` query param. */\n @property({ type: String, attribute: 'widget-src' })\n widgetSrc = '';\n\n /** Controls Help button visibility. Hidden while the widget panel is open. */\n @state() private buttonVisible = true;\n\n /** True from the first click until Zendesk fires the `open` event. Shows the spinner. */\n @state() private isLoading = false;\n\n /**\n * Set to `true` after the snippet has loaded and the `messenger:on` listeners\n * have been registered. Prevents duplicate listener registration on\n * subsequent clicks.\n */\n private zendeskReady = false;\n\n /**\n * Click handler for the Help button.\n *\n * On the first call: injects the Zendesk script, waits for `window.zE` to\n * become available, registers open/close listeners, then opens the panel.\n *\n * On subsequent calls: the script is already present so we go straight to\n * opening the panel. The spinner stays on until Zendesk fires `'open'`.\n */\n private async initiateZenDesk(): Promise<void> {\n this.isLoading = true;\n this.dispatchEvent(new Event('zendeskHelpButtonClicked'));\n\n if (!this.zendeskReady) {\n await this.loadZendeskScript();\n await this.waitForZendesk();\n\n // Register lifecycle listeners exactly once.\n // isLoading is cleared here (not earlier) so the spinner persists until\n // the widget panel is actually visible to the user.\n window.zE!('messenger:on', 'open', () => {\n this.buttonVisible = false;\n this.isLoading = false;\n });\n\n // Delay matches the Zendesk close animation so the Help button does not\n // reappear while the panel is still sliding out.\n window.zE!('messenger:on', 'close', () => {\n setTimeout(() => {\n this.buttonVisible = true;\n }, 500);\n });\n\n this.zendeskReady = true;\n }\n\n window.zE!('messenger', 'open');\n }\n\n /**\n * Appends the Zendesk snippet `<script>` to `<head>` if it has not already\n * been added. Resolves once the script has loaded; rejects on network error.\n * Guarded by the `ze-snippet` id so multiple widget instances on the same\n * page share a single script tag.\n */\n private loadZendeskScript(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (document.getElementById('ze-snippet')) {\n resolve();\n return;\n }\n const script = document.createElement('script');\n script.id = 'ze-snippet';\n script.src = this.widgetSrc;\n script.onload = () => resolve();\n script.onerror = () => reject(new Error('Failed to load Zendesk script'));\n document.head.appendChild(script);\n });\n }\n\n /**\n * Polls `window.zE` at 100 ms intervals until the Zendesk API is available.\n * The snippet performs its own async initialisation after loading, so\n * `window.zE` may not be set immediately when `script.onload` fires.\n */\n private waitForZendesk(): Promise<void> {\n return new Promise((resolve) => {\n const check = setInterval(() => {\n if (window.zE) {\n clearInterval(check);\n resolve();\n }\n }, 100);\n });\n }\n\n private get iconTemplate(): DirectiveResult<typeof UnsafeHTMLDirective> {\n return this.isLoading\n ? unsafeHTML(loaderIconSvg)\n : unsafeHTML(questionIconSvg);\n }\n\n render(): TemplateResult {\n return html`\n <button\n class=\"help-widget ${this.buttonVisible ? '' : 'hidden'}\"\n @click=${this.initiateZenDesk}\n >\n ${this.iconTemplate}\n <span class=\"hidden-sm\">Help</span>\n </button>\n `;\n }\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n --button-blue: #194880;\n --white: #fff;\n --icon-fill-color: var(--white);\n --link-color: var(--white);\n }\n\n .help-widget {\n width: 108px;\n height: 46px;\n margin: 14px 20px;\n position: fixed;\n bottom: 0;\n right: 0;\n z-index: 999998;\n background: var(--button-blue);\n color: var(--link-color);\n letter-spacing: 0.6px;\n font-size: inherit;\n transition: opacity 0.12s linear;\n border-radius: 999rem;\n border: 0;\n outline: none;\n font-weight: 700;\n cursor: pointer;\n vertical-align: middle;\n }\n\n .fill-color {\n fill: var(--icon-fill-color);\n }\n\n .help-widget svg {\n vertical-align: middle;\n margin-right: 3px;\n pointer-events: none;\n }\n\n .help-widget .hidden-sm {\n pointer-events: none;\n }\n\n .hidden {\n opacity: 0;\n display: none;\n visibility: hidden;\n }\n\n @media (max-width: 767px) {\n .hidden-sm {\n display: none;\n }\n\n .help-widget {\n padding: 13px;\n width: initial;\n }\n\n .help-widget svg {\n margin-right: 0;\n }\n }\n `;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ia-zendesk-widget.js","sourceRoot":"","sources":["../../../../src/elements/ia-zendesk-widget/ia-zendesk-widget.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n html,\n LitElement,\n type CSSResultGroup,\n type TemplateResult,\n} from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { unsafeHTML, UnsafeHTMLDirective } from 'lit/directives/unsafe-html.js';\n\nimport loaderIconSvg from './loader-icon.svg?raw';\nimport questionIconSvg from './question-icon.svg?raw';\nimport { DirectiveResult } from 'lit/directive.js';\n\ndeclare global {\n interface Window {\n /**\n * Zendesk Messenger API injected by the ze-snippet script.\n * Overloaded to cover the two call shapes we use:\n * - `messenger:on` — subscribe to open/close lifecycle events\n * - `messenger` — imperatively open or close the widget panel\n */\n zE?: {\n (\n target: 'messenger:on',\n event: 'open' | 'close',\n callback: () => void,\n ): void;\n (target: 'messenger', action: 'open' | 'close'): void;\n };\n }\n}\n\n/**\n * A lightweight launcher button that loads and opens the Zendesk Messenger\n * widget on demand.\n *\n * The native Zendesk launcher is never shown — this button is the sole entry\n * point. The Zendesk snippet script is fetched lazily on the first click so\n * it does not affect page load performance.\n *\n * @fires zendeskHelpButtonClicked - Dispatched when the user clicks the Help\n * button, before the widget is opened.\n *\n * @cssprop --button-blue - Button background colour (default: `#194880`).\n * @cssprop --icon-fill-color - SVG icon fill colour (default: `#fff`).\n * @cssprop --link-color - Button text colour (default: `#fff`).\n *\n * @example\n * ```html\n * <ia-zendesk-widget\n * widget-src=\"https://static.zdassets.com/ekr/snippet.js?key=YOUR_KEY\"\n * ></ia-zendesk-widget>\n * ```\n */\n@customElement('ia-zendesk-widget')\nexport class IAZendeskWidget extends LitElement {\n /** URL of the Zendesk `ze-snippet` loader script, including the `key` query param. */\n @property({ type: String, attribute: 'widget-src' })\n widgetSrc = '';\n\n /** Controls Help button visibility. Hidden while the widget panel is open. */\n @state() private buttonVisible = true;\n\n /** True from the first click until Zendesk fires the `open` event. Shows the spinner. */\n @state() private isLoading = false;\n\n /**\n * Set to `true` after the snippet has loaded and the `messenger:on` listeners\n * have been registered. Prevents duplicate listener registration on\n * subsequent clicks.\n */\n private zendeskReady = false;\n\n /**\n * Click handler for the Help button.\n *\n * On the first call: injects the Zendesk script, waits for `window.zE` to\n * become available, registers open/close listeners, then opens the panel.\n *\n * On subsequent calls: the script is already present so we go straight to\n * opening the panel. The spinner stays on until Zendesk fires `'open'`.\n */\n private async initiateZenDesk(): Promise<void> {\n this.isLoading = true;\n this.dispatchEvent(new Event('zendeskHelpButtonClicked'));\n\n try {\n if (!this.zendeskReady) {\n await this.loadZendeskScript();\n await this.waitForZendesk();\n\n // Register lifecycle listeners exactly once.\n // isLoading is cleared here (not earlier) so the spinner persists until\n // the widget panel is actually visible to the user.\n window.zE!('messenger:on', 'open', () => {\n this.buttonVisible = false;\n this.isLoading = false;\n });\n\n // Delay matches the Zendesk close animation so the Help button does not\n // reappear while the panel is still sliding out.\n window.zE!('messenger:on', 'close', () => {\n setTimeout(() => {\n this.buttonVisible = true;\n }, 500);\n });\n\n this.zendeskReady = true;\n }\n\n window.zE!('messenger', 'open');\n } catch (err) {\n this.isLoading = false;\n // eslint-disable-next-line no-console\n console.error('[ia-zendesk-widget]', err);\n }\n }\n\n /**\n * Appends the Zendesk snippet `<script>` to `<head>` if it has not already\n * been added. Resolves once the script has loaded; rejects on network error.\n * Guarded by the `ze-snippet` id so multiple widget instances on the same\n * page share a single script tag.\n */\n private loadZendeskScript(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (document.getElementById('ze-snippet')) {\n resolve();\n return;\n }\n const script = document.createElement('script');\n script.id = 'ze-snippet';\n script.src = this.widgetSrc;\n script.onload = () => resolve();\n script.onerror = () => reject(new Error('Failed to load Zendesk script'));\n document.head.appendChild(script);\n });\n }\n\n /**\n * Polls `window.zE` at 100 ms intervals until the Zendesk API is available.\n * The snippet performs its own async initialisation after loading, so\n * `window.zE` may not be set immediately when `script.onload` fires.\n */\n private waitForZendesk(timeoutMs = 10_000): Promise<void> {\n return new Promise((resolve, reject) => {\n const check = setInterval(() => {\n if (window.zE) {\n clearInterval(check);\n clearTimeout(timeout);\n resolve();\n }\n }, 100);\n const timeout = setTimeout(() => {\n clearInterval(check);\n reject(new Error('Zendesk API did not initialise in time'));\n }, timeoutMs);\n });\n }\n\n private get iconTemplate(): DirectiveResult<typeof UnsafeHTMLDirective> {\n return this.isLoading\n ? unsafeHTML(loaderIconSvg)\n : unsafeHTML(questionIconSvg);\n }\n\n render(): TemplateResult {\n return html`\n <button\n class=\"help-widget ${this.buttonVisible ? '' : 'hidden'}\"\n @click=${this.initiateZenDesk}\n >\n ${this.iconTemplate}\n <span class=\"hidden-sm\">Help</span>\n </button>\n `;\n }\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n --button-blue: #194880;\n --white: #fff;\n --icon-fill-color: var(--white);\n --link-color: var(--white);\n }\n\n .help-widget {\n width: 108px;\n height: 46px;\n margin: 14px 20px;\n position: fixed;\n bottom: 0;\n right: 0;\n z-index: 999998;\n background: var(--button-blue);\n color: var(--link-color);\n letter-spacing: 0.6px;\n font-size: inherit;\n transition: opacity 0.12s linear;\n border-radius: 999rem;\n border: 0;\n outline: none;\n font-weight: 700;\n cursor: pointer;\n vertical-align: middle;\n }\n\n .fill-color {\n fill: var(--icon-fill-color);\n }\n\n .help-widget svg {\n vertical-align: middle;\n margin-right: 3px;\n pointer-events: none;\n }\n\n .help-widget .hidden-sm {\n pointer-events: none;\n }\n\n .hidden {\n opacity: 0;\n display: none;\n visibility: hidden;\n }\n\n @media (max-width: 767px) {\n .hidden-sm {\n display: none;\n }\n\n .help-widget {\n padding: 13px;\n width: initial;\n }\n\n .help-widget svg {\n margin-right: 0;\n }\n }\n `;\n }\n}\n"]}
|
package/package.json
CHANGED