@internetarchive/elements 0.2.2-zendesk3 → 0.2.3-alpha-webdev8378.0
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.
- package/LICENSE +661 -661
- package/README.md +320 -320
- package/dist/src/elements/ia-combo-box/caret-closed.svg +8 -8
- package/dist/src/elements/ia-combo-box/caret-open.svg +8 -8
- package/dist/src/elements/ia-combo-box/clear.svg +8 -8
- package/dist/src/elements/ia-dropdown-search-bar/ia-dropdown-search-bar.d.ts +105 -0
- package/dist/src/elements/ia-dropdown-search-bar/ia-dropdown-search-bar.d.ts.map +1 -0
- package/dist/src/elements/ia-dropdown-search-bar/ia-dropdown-search-bar.js +483 -0
- package/dist/src/elements/ia-dropdown-search-bar/ia-dropdown-search-bar.js.map +1 -0
- package/dist/src/elements/ia-dropdown-search-bar/models.d.ts +23 -0
- package/dist/src/elements/ia-dropdown-search-bar/models.d.ts.map +1 -0
- package/dist/src/elements/ia-dropdown-search-bar/models.js +2 -0
- package/dist/src/elements/ia-dropdown-search-bar/models.js.map +1 -0
- package/dist/src/elements/ia-dropdown-search-bar/search.svg +10 -0
- package/dist/src/elements/ia-otp-input/ia-otp-input.d.ts +35 -0
- package/dist/src/elements/ia-otp-input/ia-otp-input.d.ts.map +1 -0
- package/dist/src/elements/ia-otp-input/ia-otp-input.js +217 -0
- package/dist/src/elements/ia-otp-input/ia-otp-input.js.map +1 -0
- package/dist/src/elements/index.d.ts +0 -1
- package/dist/src/elements/index.d.ts.map +1 -1
- package/dist/src/elements/index.js +0 -1
- package/dist/src/elements/index.js.map +1 -1
- package/dist/src/labs/ia-snow/flake.svg +1 -1
- package/dist/src/themes/theme-styles.d.ts.map +1 -1
- package/dist/src/themes/theme-styles.js +12 -0
- package/dist/src/themes/theme-styles.js.map +1 -1
- package/package.json +120 -118
- package/dist/src/elements/ia-zendesk-widget/ia-zendesk-widget.d.ts +0 -78
- package/dist/src/elements/ia-zendesk-widget/ia-zendesk-widget.d.ts.map +0 -1
- package/dist/src/elements/ia-zendesk-widget/ia-zendesk-widget.js +0 -221
- package/dist/src/elements/ia-zendesk-widget/ia-zendesk-widget.js.map +0 -1
- package/dist/src/elements/ia-zendesk-widget/loader-icon.svg +0 -26
- package/dist/src/elements/ia-zendesk-widget/question-icon.svg +0 -27
package/package.json
CHANGED
|
@@ -1,118 +1,120 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@internetarchive/elements",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "A web component library from the Internet Archive.",
|
|
5
|
-
"license": "AGPL-3.0-only",
|
|
6
|
-
"types": "./dist/src/elements/index.d.ts",
|
|
7
|
-
"type": "module",
|
|
8
|
-
"publishConfig": {
|
|
9
|
-
"access": "public"
|
|
10
|
-
},
|
|
11
|
-
"repository": {
|
|
12
|
-
"type": "git",
|
|
13
|
-
"url": "git+https://github.com/internetarchive/elements.git"
|
|
14
|
-
},
|
|
15
|
-
"bugs": {
|
|
16
|
-
"url": "https://github.com/internetarchive/elements/issues"
|
|
17
|
-
},
|
|
18
|
-
"scripts": {
|
|
19
|
-
"dev": "wireit",
|
|
20
|
-
"build": "wireit",
|
|
21
|
-
"clean": "wireit",
|
|
22
|
-
"lint": "wireit",
|
|
23
|
-
"format": "wireit",
|
|
24
|
-
"circular": "wireit",
|
|
25
|
-
"prepare": "wireit",
|
|
26
|
-
"test": "wireit",
|
|
27
|
-
"ghpages:build": "wireit"
|
|
28
|
-
},
|
|
29
|
-
"dependencies": {
|
|
30
|
-
"@lit/localize": "^0.12.2",
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
"@
|
|
39
|
-
"@
|
|
40
|
-
"@vitest/
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"eslint
|
|
44
|
-
"eslint-
|
|
45
|
-
"eslint-plugin-
|
|
46
|
-
"eslint-plugin-
|
|
47
|
-
"eslint-plugin-
|
|
48
|
-
"eslint-plugin-
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
"
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"!dist
|
|
71
|
-
"!dist
|
|
72
|
-
"!dist
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@internetarchive/elements",
|
|
3
|
+
"version": "0.2.3-alpha-webdev8378.0",
|
|
4
|
+
"description": "A web component library from the Internet Archive.",
|
|
5
|
+
"license": "AGPL-3.0-only",
|
|
6
|
+
"types": "./dist/src/elements/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/internetarchive/elements.git"
|
|
14
|
+
},
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/internetarchive/elements/issues"
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"dev": "wireit",
|
|
20
|
+
"build": "wireit",
|
|
21
|
+
"clean": "wireit",
|
|
22
|
+
"lint": "wireit",
|
|
23
|
+
"format": "wireit",
|
|
24
|
+
"circular": "wireit",
|
|
25
|
+
"prepare": "wireit",
|
|
26
|
+
"test": "wireit",
|
|
27
|
+
"ghpages:build": "wireit"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@lit/localize": "^0.12.2",
|
|
31
|
+
"@internetarchive/ia-clearable-text-input": "^1.1.1",
|
|
32
|
+
"@internetarchive/ia-dropdown": "^2.1.0",
|
|
33
|
+
"lit": "^2.8.0 || ^3.3.2",
|
|
34
|
+
"magic-snowflakes": "^7.0.2",
|
|
35
|
+
"tslib": "^2.8.1"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@open-wc/testing-helpers": "^3.0.1",
|
|
39
|
+
"@typescript-eslint/eslint-plugin": "^8.46.4",
|
|
40
|
+
"@vitest/browser": "^4.0.8",
|
|
41
|
+
"@vitest/browser-playwright": "^4.0.8",
|
|
42
|
+
"@vitest/coverage-v8": "^4.0.8",
|
|
43
|
+
"eslint": "^9.39.1",
|
|
44
|
+
"eslint-config-prettier": "^10.1.8",
|
|
45
|
+
"eslint-plugin-html": "^8.1.3",
|
|
46
|
+
"eslint-plugin-import": "^2.32.0",
|
|
47
|
+
"eslint-plugin-lit": "^1.15.0",
|
|
48
|
+
"eslint-plugin-lit-a11y": "^4.1.4",
|
|
49
|
+
"eslint-plugin-no-only-tests": "^3.3.0",
|
|
50
|
+
"eslint-plugin-wc": "^2.2.1",
|
|
51
|
+
"highlight.js": "^11.11.1",
|
|
52
|
+
"madge": "^8.0.0",
|
|
53
|
+
"playwright": "^1.56.1",
|
|
54
|
+
"prettier": "^3.6.2",
|
|
55
|
+
"ts-lit-plugin": "^2.0.2",
|
|
56
|
+
"tsc-alias": "^1.8.16",
|
|
57
|
+
"typescript": "^5.9.3",
|
|
58
|
+
"vite": "^7.2.2",
|
|
59
|
+
"vitest": "^4.0.8",
|
|
60
|
+
"wireit": "^0.14.12"
|
|
61
|
+
},
|
|
62
|
+
"exports": {
|
|
63
|
+
".": "./dist/src/index.js",
|
|
64
|
+
"./*": "./dist/src/elements/*.js",
|
|
65
|
+
"./labs/*": "./dist/src/labs/*.js"
|
|
66
|
+
},
|
|
67
|
+
"files": [
|
|
68
|
+
"README.md",
|
|
69
|
+
"dist",
|
|
70
|
+
"!dist/**/*.test*",
|
|
71
|
+
"!dist/**/*-story*",
|
|
72
|
+
"!dist/demo",
|
|
73
|
+
"!dist/src/internal",
|
|
74
|
+
"!dist/*.tsbuildinfo"
|
|
75
|
+
],
|
|
76
|
+
"wireit": {
|
|
77
|
+
"build": {
|
|
78
|
+
"command": "tsc --build --pretty && tsc-alias && rsync -zarvm --prune-empty-dirs --include \"*/\" --include \"*.svg\" --exclude=\"*\" src dist",
|
|
79
|
+
"dependencies": [
|
|
80
|
+
"circular"
|
|
81
|
+
],
|
|
82
|
+
"files": [
|
|
83
|
+
"src/**/*.ts",
|
|
84
|
+
"tsconfig.json"
|
|
85
|
+
],
|
|
86
|
+
"output": [
|
|
87
|
+
"dist/**"
|
|
88
|
+
]
|
|
89
|
+
},
|
|
90
|
+
"circular": {
|
|
91
|
+
"command": "madge --circular --extensions ts ."
|
|
92
|
+
},
|
|
93
|
+
"clean": {
|
|
94
|
+
"command": "rm -rf dist"
|
|
95
|
+
},
|
|
96
|
+
"dev": {
|
|
97
|
+
"command": "vite"
|
|
98
|
+
},
|
|
99
|
+
"lint": {
|
|
100
|
+
"command": "eslint . && prettier \"**/*.ts\" --check"
|
|
101
|
+
},
|
|
102
|
+
"format": {
|
|
103
|
+
"command": "eslint . --fix && prettier \"**/*.ts\" --write"
|
|
104
|
+
},
|
|
105
|
+
"prepare": {
|
|
106
|
+
"dependencies": [
|
|
107
|
+
"build"
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
"test": {
|
|
111
|
+
"command": "vitest",
|
|
112
|
+
"dependencies": [
|
|
113
|
+
"circular"
|
|
114
|
+
]
|
|
115
|
+
},
|
|
116
|
+
"ghpages:build": {
|
|
117
|
+
"command": "vite build --config vite.config.ghpages.ts && touch ./ghpages/.nojekyll"
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { LitElement, type CSSResultGroup, type TemplateResult } from 'lit';
|
|
2
|
-
declare global {
|
|
3
|
-
interface Window {
|
|
4
|
-
/**
|
|
5
|
-
* Zendesk Messenger API injected by the ze-snippet script.
|
|
6
|
-
* Overloaded to cover the two call shapes we use:
|
|
7
|
-
* - `messenger:on` — subscribe to open/close lifecycle events
|
|
8
|
-
* - `messenger` — imperatively open or close the widget panel
|
|
9
|
-
*/
|
|
10
|
-
zE?: {
|
|
11
|
-
(target: 'messenger:on', event: 'open' | 'close', callback: () => void): void;
|
|
12
|
-
(target: 'messenger', action: 'open' | 'close'): void;
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* A lightweight launcher button that loads and opens the Zendesk Messenger
|
|
18
|
-
* widget on demand.
|
|
19
|
-
*
|
|
20
|
-
* The native Zendesk launcher is never shown — this button is the sole entry
|
|
21
|
-
* point. The Zendesk snippet script is fetched lazily on the first click so
|
|
22
|
-
* it does not affect page load performance.
|
|
23
|
-
*
|
|
24
|
-
* @fires zendeskHelpButtonClicked - Dispatched when the user clicks the Help
|
|
25
|
-
* button, before the widget is opened.
|
|
26
|
-
*
|
|
27
|
-
* @cssprop --button-blue - Button background colour (default: `#194880`).
|
|
28
|
-
* @cssprop --icon-fill-color - SVG icon fill colour (default: `#fff`).
|
|
29
|
-
* @cssprop --link-color - Button text colour (default: `#fff`).
|
|
30
|
-
*
|
|
31
|
-
* @example
|
|
32
|
-
* ```html
|
|
33
|
-
* <ia-zendesk-widget
|
|
34
|
-
* widget-src="https://static.zdassets.com/ekr/snippet.js?key=YOUR_KEY"
|
|
35
|
-
* ></ia-zendesk-widget>
|
|
36
|
-
* ```
|
|
37
|
-
*/
|
|
38
|
-
export declare class IAZendeskWidget extends LitElement {
|
|
39
|
-
/** URL of the Zendesk `ze-snippet` loader script, including the `key` query param. */
|
|
40
|
-
widgetSrc: string;
|
|
41
|
-
/** Controls Help button visibility. Hidden while the widget panel is open. */
|
|
42
|
-
private buttonVisible;
|
|
43
|
-
/** True from the first click until Zendesk fires the `open` event. Shows the spinner. */
|
|
44
|
-
private isLoading;
|
|
45
|
-
/**
|
|
46
|
-
* Set to `true` after the snippet has loaded and the `messenger:on` listeners
|
|
47
|
-
* have been registered. Prevents duplicate listener registration on
|
|
48
|
-
* subsequent clicks.
|
|
49
|
-
*/
|
|
50
|
-
private zendeskReady;
|
|
51
|
-
/**
|
|
52
|
-
* Click handler for the Help button.
|
|
53
|
-
*
|
|
54
|
-
* On the first call: injects the Zendesk script, waits for `window.zE` to
|
|
55
|
-
* become available, registers open/close listeners, then opens the panel.
|
|
56
|
-
*
|
|
57
|
-
* On subsequent calls: the script is already present so we go straight to
|
|
58
|
-
* opening the panel. The spinner stays on until Zendesk fires `'open'`.
|
|
59
|
-
*/
|
|
60
|
-
private initiateZenDesk;
|
|
61
|
-
/**
|
|
62
|
-
* Appends the Zendesk snippet `<script>` to `<head>` if it has not already
|
|
63
|
-
* been added. Resolves once the script has loaded; rejects on network error.
|
|
64
|
-
* Guarded by the `ze-snippet` id so multiple widget instances on the same
|
|
65
|
-
* page share a single script tag.
|
|
66
|
-
*/
|
|
67
|
-
private loadZendeskScript;
|
|
68
|
-
/**
|
|
69
|
-
* Polls `window.zE` at 100 ms intervals until the Zendesk API is available.
|
|
70
|
-
* The snippet performs its own async initialisation after loading, so
|
|
71
|
-
* `window.zE` may not be set immediately when `script.onload` fires.
|
|
72
|
-
*/
|
|
73
|
-
private waitForZendesk;
|
|
74
|
-
private get iconTemplate();
|
|
75
|
-
render(): TemplateResult;
|
|
76
|
-
static get styles(): CSSResultGroup;
|
|
77
|
-
}
|
|
78
|
-
//# sourceMappingURL=ia-zendesk-widget.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
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"}
|
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
import { __decorate } from "tslib";
|
|
2
|
-
import { css, html, LitElement, } from 'lit';
|
|
3
|
-
import { customElement, property, state } from 'lit/decorators.js';
|
|
4
|
-
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
|
5
|
-
import loaderIconSvg from './loader-icon.svg?raw';
|
|
6
|
-
import questionIconSvg from './question-icon.svg?raw';
|
|
7
|
-
/**
|
|
8
|
-
* A lightweight launcher button that loads and opens the Zendesk Messenger
|
|
9
|
-
* widget on demand.
|
|
10
|
-
*
|
|
11
|
-
* The native Zendesk launcher is never shown — this button is the sole entry
|
|
12
|
-
* point. The Zendesk snippet script is fetched lazily on the first click so
|
|
13
|
-
* it does not affect page load performance.
|
|
14
|
-
*
|
|
15
|
-
* @fires zendeskHelpButtonClicked - Dispatched when the user clicks the Help
|
|
16
|
-
* button, before the widget is opened.
|
|
17
|
-
*
|
|
18
|
-
* @cssprop --button-blue - Button background colour (default: `#194880`).
|
|
19
|
-
* @cssprop --icon-fill-color - SVG icon fill colour (default: `#fff`).
|
|
20
|
-
* @cssprop --link-color - Button text colour (default: `#fff`).
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* ```html
|
|
24
|
-
* <ia-zendesk-widget
|
|
25
|
-
* widget-src="https://static.zdassets.com/ekr/snippet.js?key=YOUR_KEY"
|
|
26
|
-
* ></ia-zendesk-widget>
|
|
27
|
-
* ```
|
|
28
|
-
*/
|
|
29
|
-
let IAZendeskWidget = class IAZendeskWidget extends LitElement {
|
|
30
|
-
constructor() {
|
|
31
|
-
super(...arguments);
|
|
32
|
-
/** URL of the Zendesk `ze-snippet` loader script, including the `key` query param. */
|
|
33
|
-
this.widgetSrc = '';
|
|
34
|
-
/** Controls Help button visibility. Hidden while the widget panel is open. */
|
|
35
|
-
this.buttonVisible = true;
|
|
36
|
-
/** True from the first click until Zendesk fires the `open` event. Shows the spinner. */
|
|
37
|
-
this.isLoading = false;
|
|
38
|
-
/**
|
|
39
|
-
* Set to `true` after the snippet has loaded and the `messenger:on` listeners
|
|
40
|
-
* have been registered. Prevents duplicate listener registration on
|
|
41
|
-
* subsequent clicks.
|
|
42
|
-
*/
|
|
43
|
-
this.zendeskReady = false;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Click handler for the Help button.
|
|
47
|
-
*
|
|
48
|
-
* On the first call: injects the Zendesk script, waits for `window.zE` to
|
|
49
|
-
* become available, registers open/close listeners, then opens the panel.
|
|
50
|
-
*
|
|
51
|
-
* On subsequent calls: the script is already present so we go straight to
|
|
52
|
-
* opening the panel. The spinner stays on until Zendesk fires `'open'`.
|
|
53
|
-
*/
|
|
54
|
-
async initiateZenDesk() {
|
|
55
|
-
this.isLoading = true;
|
|
56
|
-
this.dispatchEvent(new Event('zendeskHelpButtonClicked'));
|
|
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);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Appends the Zendesk snippet `<script>` to `<head>` if it has not already
|
|
87
|
-
* been added. Resolves once the script has loaded; rejects on network error.
|
|
88
|
-
* Guarded by the `ze-snippet` id so multiple widget instances on the same
|
|
89
|
-
* page share a single script tag.
|
|
90
|
-
*/
|
|
91
|
-
loadZendeskScript() {
|
|
92
|
-
return new Promise((resolve, reject) => {
|
|
93
|
-
if (document.getElementById('ze-snippet')) {
|
|
94
|
-
resolve();
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
const script = document.createElement('script');
|
|
98
|
-
script.id = 'ze-snippet';
|
|
99
|
-
script.src = this.widgetSrc;
|
|
100
|
-
script.onload = () => resolve();
|
|
101
|
-
script.onerror = () => reject(new Error('Failed to load Zendesk script'));
|
|
102
|
-
document.head.appendChild(script);
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Polls `window.zE` at 100 ms intervals until the Zendesk API is available.
|
|
107
|
-
* The snippet performs its own async initialisation after loading, so
|
|
108
|
-
* `window.zE` may not be set immediately when `script.onload` fires.
|
|
109
|
-
*/
|
|
110
|
-
waitForZendesk(timeoutMs = 10_000) {
|
|
111
|
-
return new Promise((resolve, reject) => {
|
|
112
|
-
const check = setInterval(() => {
|
|
113
|
-
if (window.zE) {
|
|
114
|
-
clearInterval(check);
|
|
115
|
-
clearTimeout(timeout);
|
|
116
|
-
resolve();
|
|
117
|
-
}
|
|
118
|
-
}, 100);
|
|
119
|
-
const timeout = setTimeout(() => {
|
|
120
|
-
clearInterval(check);
|
|
121
|
-
reject(new Error('Zendesk API did not initialise in time'));
|
|
122
|
-
}, timeoutMs);
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
get iconTemplate() {
|
|
126
|
-
return this.isLoading
|
|
127
|
-
? unsafeHTML(loaderIconSvg)
|
|
128
|
-
: unsafeHTML(questionIconSvg);
|
|
129
|
-
}
|
|
130
|
-
render() {
|
|
131
|
-
return html `
|
|
132
|
-
<button
|
|
133
|
-
class="help-widget ${this.buttonVisible ? '' : 'hidden'}"
|
|
134
|
-
@click=${this.initiateZenDesk}
|
|
135
|
-
>
|
|
136
|
-
${this.iconTemplate}
|
|
137
|
-
<span class="hidden-sm">Help</span>
|
|
138
|
-
</button>
|
|
139
|
-
`;
|
|
140
|
-
}
|
|
141
|
-
static get styles() {
|
|
142
|
-
return css `
|
|
143
|
-
:host {
|
|
144
|
-
--button-blue: #194880;
|
|
145
|
-
--white: #fff;
|
|
146
|
-
--icon-fill-color: var(--white);
|
|
147
|
-
--link-color: var(--white);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
.help-widget {
|
|
151
|
-
width: 108px;
|
|
152
|
-
height: 46px;
|
|
153
|
-
margin: 14px 20px;
|
|
154
|
-
position: fixed;
|
|
155
|
-
bottom: 0;
|
|
156
|
-
right: 0;
|
|
157
|
-
z-index: 999998;
|
|
158
|
-
background: var(--button-blue);
|
|
159
|
-
color: var(--link-color);
|
|
160
|
-
letter-spacing: 0.6px;
|
|
161
|
-
font-size: inherit;
|
|
162
|
-
transition: opacity 0.12s linear;
|
|
163
|
-
border-radius: 999rem;
|
|
164
|
-
border: 0;
|
|
165
|
-
outline: none;
|
|
166
|
-
font-weight: 700;
|
|
167
|
-
cursor: pointer;
|
|
168
|
-
vertical-align: middle;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
.fill-color {
|
|
172
|
-
fill: var(--icon-fill-color);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
.help-widget svg {
|
|
176
|
-
vertical-align: middle;
|
|
177
|
-
margin-right: 3px;
|
|
178
|
-
pointer-events: none;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
.help-widget .hidden-sm {
|
|
182
|
-
pointer-events: none;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
.hidden {
|
|
186
|
-
opacity: 0;
|
|
187
|
-
display: none;
|
|
188
|
-
visibility: hidden;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
@media (max-width: 767px) {
|
|
192
|
-
.hidden-sm {
|
|
193
|
-
display: none;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
.help-widget {
|
|
197
|
-
padding: 13px;
|
|
198
|
-
width: initial;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
.help-widget svg {
|
|
202
|
-
margin-right: 0;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
`;
|
|
206
|
-
}
|
|
207
|
-
};
|
|
208
|
-
__decorate([
|
|
209
|
-
property({ type: String, attribute: 'widget-src' })
|
|
210
|
-
], IAZendeskWidget.prototype, "widgetSrc", void 0);
|
|
211
|
-
__decorate([
|
|
212
|
-
state()
|
|
213
|
-
], IAZendeskWidget.prototype, "buttonVisible", void 0);
|
|
214
|
-
__decorate([
|
|
215
|
-
state()
|
|
216
|
-
], IAZendeskWidget.prototype, "isLoading", void 0);
|
|
217
|
-
IAZendeskWidget = __decorate([
|
|
218
|
-
customElement('ia-zendesk-widget')
|
|
219
|
-
], IAZendeskWidget);
|
|
220
|
-
export { IAZendeskWidget };
|
|
221
|
-
//# sourceMappingURL=ia-zendesk-widget.js.map
|
|
@@ -1 +0,0 @@
|
|
|
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"]}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
<svg
|
|
2
|
-
class="icon-loader"
|
|
3
|
-
height="20"
|
|
4
|
-
viewBox="0 0 128 128"
|
|
5
|
-
width="20"
|
|
6
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
7
|
-
>
|
|
8
|
-
<g>
|
|
9
|
-
<circle cx="16" cy="64" r="16" class="fill-color" fill-opacity="1" />
|
|
10
|
-
<circle cx="16" cy="64" r="14.344" class="fill-color" fill-opacity="1" transform="rotate(45 64 64)" />
|
|
11
|
-
<circle cx="16" cy="64" r="12.531" class="fill-color" fill-opacity="1" transform="rotate(90 64 64)" />
|
|
12
|
-
<circle cx="16" cy="64" r="10.75" class="fill-color" fill-opacity="1" transform="rotate(135 64 64)" />
|
|
13
|
-
<circle cx="16" cy="64" r="10.063" class="fill-color" fill-opacity="1" transform="rotate(180 64 64)" />
|
|
14
|
-
<circle cx="16" cy="64" r="8.063" class="fill-color" fill-opacity="1" transform="rotate(225 64 64)" />
|
|
15
|
-
<circle cx="16" cy="64" r="6.438" class="fill-color" fill-opacity="1" transform="rotate(270 64 64)" />
|
|
16
|
-
<circle cx="16" cy="64" r="5.375" class="fill-color" fill-opacity="1" transform="rotate(315 64 64)" />
|
|
17
|
-
<animateTransform
|
|
18
|
-
attributeName="transform"
|
|
19
|
-
type="rotate"
|
|
20
|
-
values="0 64 64;315 64 64;270 64 64;225 64 64;180 64 64;135 64 64;90 64 64;45 64 64"
|
|
21
|
-
calcMode="discrete"
|
|
22
|
-
dur="720ms"
|
|
23
|
-
repeatCount="indefinite"
|
|
24
|
-
/>
|
|
25
|
-
</g>
|
|
26
|
-
</svg>
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
<svg
|
|
2
|
-
class="icon-question"
|
|
3
|
-
height="20"
|
|
4
|
-
viewBox="0 0 20 20"
|
|
5
|
-
width="20"
|
|
6
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
7
|
-
>
|
|
8
|
-
<g class="fill-color" fill-rule="nonzero">
|
|
9
|
-
<path
|
|
10
|
-
d="m10.7078125 12.8359375v-.4140625c0-.765625.2890625-1.1484375 1.328125-1.75
|
|
11
|
-
1.1015625-.6484375 1.671875-1.46875 1.671875-2.6484375
|
|
12
|
-
0-1.78125-1.4765625-3.0234375-3.7109375-3.0234375
|
|
13
|
-
-2.3984375 0-3.7578125 1.34375-3.796875 3.265625h2.1171875
|
|
14
|
-
c.046875-.8828125.640625-1.453125 1.5390625-1.453125
|
|
15
|
-
.890625 0 1.484375.5390625 1.484375 1.28125s-.3046875 1.125-1.3125 1.7265625
|
|
16
|
-
c-1.078125.6328125-1.5078125 1.3359375-1.40625 2.5625l.015625.453125z"
|
|
17
|
-
/>
|
|
18
|
-
<path
|
|
19
|
-
d="m9.7 16.57c.711 0 1.281-.539 1.281-1.227s-.57-1.226-1.28-1.226
|
|
20
|
-
c-.704 0-1.274.539-1.274 1.226s.57 1.227 1.274 1.227z"
|
|
21
|
-
/>
|
|
22
|
-
<path
|
|
23
|
-
d="m10 0c-5.523 0-10 4.477-10 10s4.477 10 10 10 10-4.477 10-10-4.477-10-10-10z
|
|
24
|
-
m0 2c4.418 0 8 3.582 8 8s-3.582 8-8 8-8-3.582-8-8 3.582-8 8-8z"
|
|
25
|
-
/>
|
|
26
|
-
</g>
|
|
27
|
-
</svg>
|