@nyaruka/temba-components 0.52.1 → 0.53.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/CHANGELOG.md +17 -0
- package/dist/{985d634a.js → 0fd963e1.js} +393 -337
- package/dist/index.js +393 -337
- package/dist/static/svg/index.svg +1 -1
- package/dist/sw.js +1 -1
- package/dist/sw.js.map +1 -1
- package/dist/templates/components-body.html +1 -1
- package/dist/templates/components-head.html +1 -1
- package/out-tsc/src/RapidElement.js +51 -0
- package/out-tsc/src/RapidElement.js.map +1 -1
- package/out-tsc/src/button/Button.js +3 -0
- package/out-tsc/src/button/Button.js.map +1 -1
- package/out-tsc/src/dialog/Dialog.js +69 -22
- package/out-tsc/src/dialog/Dialog.js.map +1 -1
- package/out-tsc/src/dialog/Modax.js +118 -21
- package/out-tsc/src/dialog/Modax.js.map +1 -1
- package/out-tsc/src/utils/index.js +1 -0
- package/out-tsc/src/utils/index.js.map +1 -1
- package/out-tsc/src/vectoricon/index.js +3 -1
- package/out-tsc/src/vectoricon/index.js.map +1 -1
- package/out-tsc/test/temba-modax.test.js +2 -2
- package/out-tsc/test/temba-modax.test.js.map +1 -1
- package/package.json +1 -1
- package/src/RapidElement.ts +82 -1
- package/src/button/Button.ts +3 -0
- package/src/dialog/Dialog.ts +81 -25
- package/src/dialog/Modax.ts +126 -22
- package/src/utils/index.ts +1 -0
- package/src/vectoricon/index.ts +3 -1
- package/static/svg/index.svg +1 -1
- package/static/svg/work/traced/alarm-clock.svg +1 -0
- package/static/svg/work/used/alarm-clock.svg +3 -0
- package/test/temba-modax.test.ts +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"temba-modax.test.js","sourceRoot":"","sources":["../../test/temba-modax.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAEtC,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"temba-modax.test.js","sourceRoot":"","sources":["../../test/temba-modax.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { fixture, expect, assert } from '@open-wc/testing';\nimport { useFakeTimers } from 'sinon';\nimport { Button } from '../src/button/Button';\nimport { Modax } from '../src/dialog/Modax';\nimport { CustomEventType } from '../src/interfaces';\nimport { assertScreenshot, getClip, mockPOST } from './utils.test';\n\nlet clock: any;\n\nconst getModaxHTML = (endpoint: string): string => {\n return `\n <temba-modax header=\"Hello Modax\" endpoint=\"${endpoint}\">\n <div>Open Me</div>\n </temba-modax>\n `;\n};\n\nconst getButtons = (modax: Modax, type: string = null) => {\n return modax.shadowRoot\n .querySelector('temba-dialog')\n .shadowRoot.querySelectorAll(\n type ? `temba-button[${type}='']` : 'temba-button'\n );\n};\n\nconst open = async (modax: Modax) => {\n return new Promise((resolve: any, reject: any) => {\n modax.addEventListener(\n CustomEventType.Loaded,\n async (event: CustomEvent) => {\n await clock.runAll();\n resolve(event.detail);\n }\n );\n\n modax.addEventListener(\n CustomEventType.Redirected,\n async (event: CustomEvent) => {\n await clock.runAll();\n resolve(event.detail);\n }\n );\n\n modax.open = true;\n });\n};\n\nconst clickPrimary = async (modax: Modax) => {\n const buttons = getButtons(modax);\n\n if (buttons.length > 0) {\n let primary = buttons[0] as Button;\n\n if (buttons.length > 1) {\n // look for our primary flag\n buttons.forEach((button: Button) => {\n if (button.primary) {\n primary = button;\n }\n });\n }\n\n expect(primary).not.equals(undefined, 'Missing primary button');\n primary.click();\n }\n};\n\nconst getDialogClip = (modax: Modax) => {\n const dialog = modax.shadowRoot.querySelector('temba-dialog');\n return getClip(\n dialog.shadowRoot.querySelector('.dialog-container') as HTMLElement\n );\n};\n\ndescribe('temba-modax', () => {\n beforeEach(function () {\n clock = useFakeTimers();\n });\n\n afterEach(function () {\n clock.restore();\n });\n\n it('can be created', async () => {\n const modax: Modax = await fixture(\n getModaxHTML('/test-assets/modax/hello.html')\n );\n assert.instanceOf(modax, Modax);\n });\n\n it('opens', async () => {\n const modax: Modax = await fixture(\n getModaxHTML('/test-assets/modax/hello.html')\n );\n\n await open(modax);\n expect(modax.open).equals(true);\n\n // Now our body should have our endpoint text\n expect(modax.getBody().innerHTML).to.contain('Hello World');\n\n await assertScreenshot('modax/simple', getDialogClip(modax));\n });\n\n it('fetches forms', async () => {\n const modax: Modax = await fixture(\n getModaxHTML('/test-assets/modax/form.html')\n );\n expect(modax.open).to.equal(false);\n await open(modax);\n\n expect(modax.open).to.equal(true);\n\n expect(modax.buttons[1].name).to.equal('Save Everything');\n expect(modax.buttons[0].name).to.equal('Cancel');\n\n await assertScreenshot('modax/form', getDialogClip(modax));\n });\n\n it('reverts primary name on reuse', async () => {\n const modax: Modax = await fixture(\n getModaxHTML('/test-assets/modax/hello.html')\n );\n\n // await click('temba-modax');\n await open(modax);\n expect(modax.open).equals(true);\n\n // should only have one button, okay\n let buttons = getButtons(modax);\n expect(buttons.length).equals(1);\n\n // close our dialog\n await clickPrimary(modax);\n expect(modax.open).equals(false);\n\n // now fetch form from the same modax\n modax.endpoint = '/test-assets/modax/form.html';\n await open(modax);\n expect(modax.open).equals(true);\n\n // now we should have two buttons, 'Save Everything' and 'Cancel'\n buttons = getButtons(modax);\n expect(buttons.length).equals(2);\n\n // secondary should be Cancel, not Ok\n const secondary = getButtons(modax, 'secondary')[0] as Button;\n expect(secondary.name).equals('Cancel');\n });\n\n it('closes after redirect', async () => {\n const modax: Modax = await fixture(\n getModaxHTML('/test-assets/modax/form.html')\n );\n\n await open(modax);\n const primary = getButtons(modax, 'primary')[0] as Button;\n expect(primary.name).equals('Save Everything');\n\n // click the submit button\n mockPOST(/\\/test-assets\\/modax\\/form\\.html/, 'arst', {\n 'Temba-Success': 'hide',\n });\n\n const hideTest = new Promise<void>(resolve => {\n modax.addEventListener(CustomEventType.Submitted, () => {\n expect(modax.open).equals(false, 'Modal still visible');\n resolve();\n });\n });\n\n await clickPrimary(modax);\n await clock.runAllAsync();\n await hideTest;\n });\n});\n"]}
|
package/package.json
CHANGED
package/src/RapidElement.ts
CHANGED
|
@@ -1,6 +1,63 @@
|
|
|
1
|
-
import { LitElement } from 'lit';
|
|
1
|
+
import { LitElement, PropertyValueMap } from 'lit';
|
|
2
2
|
import { CustomEventType } from './interfaces';
|
|
3
3
|
|
|
4
|
+
enum Color {
|
|
5
|
+
YELLOW = 33,
|
|
6
|
+
PURPLE = 35,
|
|
7
|
+
WHITE = 37,
|
|
8
|
+
BLUE = 34,
|
|
9
|
+
RED = 31,
|
|
10
|
+
CYAN = 36,
|
|
11
|
+
GREEN = 32,
|
|
12
|
+
BLACK = 30,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const colorize = (text: string, color: Color) => {
|
|
16
|
+
return `\x1b[${color}m${text}\x1b[0m`;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const tag = (ele: HTMLElement) => {
|
|
20
|
+
return colorize(ele.tagName.padEnd(30), Color.PURPLE);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const showUpdates = (
|
|
24
|
+
ele: HTMLElement,
|
|
25
|
+
changes: Map<PropertyKey, unknown>,
|
|
26
|
+
firstUpdated = false
|
|
27
|
+
) => {
|
|
28
|
+
if (ele['DEBUG_UPDATES'] || ele['DEBUG']) {
|
|
29
|
+
if (changes.size > 0) {
|
|
30
|
+
console.log(
|
|
31
|
+
tag(ele),
|
|
32
|
+
firstUpdated
|
|
33
|
+
? colorize('<updated>', Color.YELLOW)
|
|
34
|
+
: colorize('<first-updated>', Color.BLACK)
|
|
35
|
+
);
|
|
36
|
+
for (const [key, value] of changes.entries()) {
|
|
37
|
+
console.log(
|
|
38
|
+
' ' + String(key).padEnd(30),
|
|
39
|
+
value,
|
|
40
|
+
colorize('=>', Color.WHITE),
|
|
41
|
+
ele[key]
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const showEvent = (ele: HTMLElement, type: string, details = undefined) => {
|
|
49
|
+
if (ele['DEBUG_EVENTS'] || ele['DEBUG']) {
|
|
50
|
+
console.log(
|
|
51
|
+
tag(ele),
|
|
52
|
+
details !== undefined
|
|
53
|
+
? colorize('<custom-event>', Color.RED)
|
|
54
|
+
: colorize('<event> ', Color.CYAN),
|
|
55
|
+
colorize(type, Color.BLUE),
|
|
56
|
+
details !== undefined ? details : ''
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
4
61
|
export interface EventHandler {
|
|
5
62
|
event: string;
|
|
6
63
|
method: EventListener;
|
|
@@ -8,6 +65,10 @@ export interface EventHandler {
|
|
|
8
65
|
}
|
|
9
66
|
|
|
10
67
|
export class RapidElement extends LitElement {
|
|
68
|
+
DEBUG = false;
|
|
69
|
+
DEBUG_UPDATES = false;
|
|
70
|
+
DEBUG_EVENTS = false;
|
|
71
|
+
|
|
11
72
|
private eles: { [selector: string]: HTMLDivElement } = {};
|
|
12
73
|
public getEventHandlers(): EventHandler[] {
|
|
13
74
|
return [];
|
|
@@ -36,7 +97,23 @@ export class RapidElement extends LitElement {
|
|
|
36
97
|
super.disconnectedCallback();
|
|
37
98
|
}
|
|
38
99
|
|
|
100
|
+
protected firstUpdated(
|
|
101
|
+
changes: PropertyValueMap<any> | Map<PropertyKey, unknown>
|
|
102
|
+
): void {
|
|
103
|
+
super.firstUpdated(changes);
|
|
104
|
+
showUpdates(this, changes, true);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
protected updated(
|
|
108
|
+
changes: PropertyValueMap<any> | Map<PropertyKey, unknown>
|
|
109
|
+
): void {
|
|
110
|
+
super.updated(changes);
|
|
111
|
+
showUpdates(this, changes, false);
|
|
112
|
+
}
|
|
113
|
+
|
|
39
114
|
public fireEvent(type: string): any {
|
|
115
|
+
showEvent(this, type);
|
|
116
|
+
|
|
40
117
|
return this.dispatchEvent(
|
|
41
118
|
new Event(type, {
|
|
42
119
|
bubbles: true,
|
|
@@ -46,6 +123,10 @@ export class RapidElement extends LitElement {
|
|
|
46
123
|
}
|
|
47
124
|
|
|
48
125
|
public fireCustomEvent(type: CustomEventType, detail: any = {}): any {
|
|
126
|
+
if (this['DEBUG_EVENTS']) {
|
|
127
|
+
showEvent(this, type, detail);
|
|
128
|
+
}
|
|
129
|
+
|
|
49
130
|
const event = new CustomEvent(type, {
|
|
50
131
|
detail,
|
|
51
132
|
bubbles: true,
|
package/src/button/Button.ts
CHANGED
package/src/dialog/Dialog.ts
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
import { property } from 'lit/decorators.js';
|
|
2
|
-
import { TemplateResult, html, css } from 'lit';
|
|
2
|
+
import { TemplateResult, html, css, PropertyValueMap } from 'lit';
|
|
3
3
|
import { Button } from '../button/Button';
|
|
4
4
|
import { RapidElement } from '../RapidElement';
|
|
5
5
|
import { CustomEventType } from '../interfaces';
|
|
6
6
|
import { styleMap } from 'lit-html/directives/style-map.js';
|
|
7
7
|
import { getClasses } from '../utils';
|
|
8
8
|
|
|
9
|
+
export enum ButtonType {
|
|
10
|
+
PRIMARY = 'primary',
|
|
11
|
+
SECONDARY = 'secondary',
|
|
12
|
+
DESTRUCTIVE = 'destructive',
|
|
13
|
+
}
|
|
14
|
+
export class DialogButton {
|
|
15
|
+
name?: string;
|
|
16
|
+
id?: string;
|
|
17
|
+
details?: any;
|
|
18
|
+
type?: string;
|
|
19
|
+
closes?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
9
22
|
export class Dialog extends RapidElement {
|
|
10
23
|
static get widths(): { [size: string]: string } {
|
|
11
24
|
return {
|
|
@@ -24,6 +37,10 @@ export class Dialog extends RapidElement {
|
|
|
24
37
|
background: white;
|
|
25
38
|
}
|
|
26
39
|
|
|
40
|
+
.flex-grow {
|
|
41
|
+
flex-grow: 1;
|
|
42
|
+
}
|
|
43
|
+
|
|
27
44
|
.flex {
|
|
28
45
|
display: flex;
|
|
29
46
|
flex-direction: column;
|
|
@@ -99,6 +116,9 @@ export class Dialog extends RapidElement {
|
|
|
99
116
|
}
|
|
100
117
|
|
|
101
118
|
.header-text {
|
|
119
|
+
display: flex;
|
|
120
|
+
flex-direction: row;
|
|
121
|
+
align-items: center;
|
|
102
122
|
font-size: 20px;
|
|
103
123
|
padding: 12px 20px;
|
|
104
124
|
font-weight: 300;
|
|
@@ -106,11 +126,21 @@ export class Dialog extends RapidElement {
|
|
|
106
126
|
background: var(--header-bg);
|
|
107
127
|
}
|
|
108
128
|
|
|
129
|
+
.header-text .title {
|
|
130
|
+
flex-grow: 1;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.header-text .status {
|
|
134
|
+
font-size: 0.6em;
|
|
135
|
+
font-weight: bold;
|
|
136
|
+
}
|
|
137
|
+
|
|
109
138
|
.dialog-footer {
|
|
110
139
|
background: var(--color-primary-light);
|
|
111
140
|
padding: 10px;
|
|
112
141
|
display: flex;
|
|
113
|
-
flex-flow: row
|
|
142
|
+
flex-flow: row;
|
|
143
|
+
align-items: center;
|
|
114
144
|
}
|
|
115
145
|
|
|
116
146
|
temba-button {
|
|
@@ -198,6 +228,9 @@ export class Dialog extends RapidElement {
|
|
|
198
228
|
@property()
|
|
199
229
|
ready: boolean;
|
|
200
230
|
|
|
231
|
+
@property({ type: Array })
|
|
232
|
+
buttons: DialogButton[] = [];
|
|
233
|
+
|
|
201
234
|
@property({ attribute: false })
|
|
202
235
|
onButtonClicked: (button: Button) => void;
|
|
203
236
|
|
|
@@ -207,6 +240,25 @@ export class Dialog extends RapidElement {
|
|
|
207
240
|
super();
|
|
208
241
|
}
|
|
209
242
|
|
|
243
|
+
protected firstUpdated(
|
|
244
|
+
changes: PropertyValueMap<any> | Map<PropertyKey, unknown>
|
|
245
|
+
): void {
|
|
246
|
+
if (changes.has('cancelButtonName') && this.cancelButtonName) {
|
|
247
|
+
this.buttons.push({
|
|
248
|
+
name: this.cancelButtonName,
|
|
249
|
+
type: ButtonType.SECONDARY,
|
|
250
|
+
closes: true,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (changes.has('primaryButtonName') && this.primaryButtonName) {
|
|
255
|
+
this.buttons.push({
|
|
256
|
+
name: this.primaryButtonName,
|
|
257
|
+
type: ButtonType.PRIMARY,
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
210
262
|
public updated(changedProperties: Map<string, any>) {
|
|
211
263
|
if (changedProperties.has('open')) {
|
|
212
264
|
const body = document.querySelector('body');
|
|
@@ -270,8 +322,13 @@ export class Dialog extends RapidElement {
|
|
|
270
322
|
public handleClick(evt: MouseEvent) {
|
|
271
323
|
const button = evt.currentTarget as Button;
|
|
272
324
|
if (!button.disabled) {
|
|
273
|
-
|
|
274
|
-
if (button.
|
|
325
|
+
let detail: DialogButton = {};
|
|
326
|
+
if (button.index >= 0 && button.index < this.buttons.length) {
|
|
327
|
+
detail = this.buttons[button.index];
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
this.fireCustomEvent(CustomEventType.ButtonClicked, { button, detail });
|
|
331
|
+
if (button.name === this.cancelButtonName || (detail && detail.closes)) {
|
|
275
332
|
this.open = false;
|
|
276
333
|
}
|
|
277
334
|
}
|
|
@@ -343,7 +400,9 @@ export class Dialog extends RapidElement {
|
|
|
343
400
|
const header = this.header
|
|
344
401
|
? html`
|
|
345
402
|
<div class="dialog-header">
|
|
346
|
-
<div class="header-text"
|
|
403
|
+
<div class="header-text">
|
|
404
|
+
<div class="title">${this.header}</div>
|
|
405
|
+
</div>
|
|
347
406
|
</div>
|
|
348
407
|
`
|
|
349
408
|
: null;
|
|
@@ -382,26 +441,23 @@ export class Dialog extends RapidElement {
|
|
|
382
441
|
</div>
|
|
383
442
|
|
|
384
443
|
<div class="dialog-footer">
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
name=${this.cancelButtonName}
|
|
403
|
-
secondary
|
|
404
|
-
></temba-button>
|
|
444
|
+
<div class="flex-grow">
|
|
445
|
+
<slot name="gutter"></slot>
|
|
446
|
+
</div>
|
|
447
|
+
${this.buttons.map(
|
|
448
|
+
(button: DialogButton, index) => html`
|
|
449
|
+
<temba-button
|
|
450
|
+
name=${button.name}
|
|
451
|
+
?destructive=${button.type == 'primary' && this.destructive}
|
|
452
|
+
?primary=${button.type == 'primary' && !this.destructive}
|
|
453
|
+
?secondary=${button.type == 'secondary'}
|
|
454
|
+
?submitting=${this.submitting}
|
|
455
|
+
?disabled=${this.disabled}
|
|
456
|
+
index=${index}
|
|
457
|
+
@click=${this.handleClick}
|
|
458
|
+
></temba-button>
|
|
459
|
+
`
|
|
460
|
+
)}
|
|
405
461
|
</div>
|
|
406
462
|
</div>
|
|
407
463
|
<div class="grow-bottom"></div>
|
package/src/dialog/Modax.ts
CHANGED
|
@@ -3,9 +3,9 @@ import { property } from 'lit/decorators.js';
|
|
|
3
3
|
import { unsafeHTML } from 'lit-html/directives/unsafe-html.js';
|
|
4
4
|
|
|
5
5
|
import { RapidElement } from '../RapidElement';
|
|
6
|
-
import { getUrl, serialize, postUrl, WebResponse } from '../utils';
|
|
6
|
+
import { getUrl, serialize, postUrl, WebResponse, getClasses } from '../utils';
|
|
7
7
|
import { CustomEventType } from '../interfaces';
|
|
8
|
-
import { Dialog } from './Dialog';
|
|
8
|
+
import { ButtonType, Dialog, DialogButton } from './Dialog';
|
|
9
9
|
|
|
10
10
|
export class Modax extends RapidElement {
|
|
11
11
|
static get styles() {
|
|
@@ -24,6 +24,11 @@ export class Modax extends RapidElement {
|
|
|
24
24
|
display: none;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
button[type='submit'],
|
|
28
|
+
input[type='submit'] {
|
|
29
|
+
display: none;
|
|
30
|
+
}
|
|
31
|
+
|
|
27
32
|
.modax-body {
|
|
28
33
|
padding: 20px;
|
|
29
34
|
display: block;
|
|
@@ -67,6 +72,33 @@ export class Modax extends RapidElement {
|
|
|
67
72
|
border-radius: 6px;
|
|
68
73
|
font-weight: 300;
|
|
69
74
|
}
|
|
75
|
+
|
|
76
|
+
.step-ball {
|
|
77
|
+
background: rgba(var(--primary-rgb), 0.2);
|
|
78
|
+
width: 1.2em;
|
|
79
|
+
height: 1.2em;
|
|
80
|
+
border-radius: 100%;
|
|
81
|
+
margin-right: 0.5em;
|
|
82
|
+
border: 0.15em solid transparent;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.step-ball.complete {
|
|
86
|
+
background: rgba(var(--primary-rgb), 0.7);
|
|
87
|
+
cursor: pointer;
|
|
88
|
+
}
|
|
89
|
+
.step-ball.complete:hover {
|
|
90
|
+
background: rgba(var(--primary-rgb), 0.8);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.step-ball.active {
|
|
94
|
+
border: 0.15em solid var(--color-primary-dark);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.wizard-steps {
|
|
98
|
+
display: flex;
|
|
99
|
+
flex-direction: row;
|
|
100
|
+
margin-left: 0.6em;
|
|
101
|
+
}
|
|
70
102
|
`;
|
|
71
103
|
}
|
|
72
104
|
|
|
@@ -106,6 +138,15 @@ export class Modax extends RapidElement {
|
|
|
106
138
|
@property({ type: Boolean })
|
|
107
139
|
disabled = false;
|
|
108
140
|
|
|
141
|
+
@property({ type: Array })
|
|
142
|
+
buttons: DialogButton[] = [];
|
|
143
|
+
|
|
144
|
+
@property({ type: Number })
|
|
145
|
+
wizardStep = 0;
|
|
146
|
+
|
|
147
|
+
@property({ type: Number })
|
|
148
|
+
wizardStepCount = 0;
|
|
149
|
+
|
|
109
150
|
@property({ type: Boolean })
|
|
110
151
|
suspendSubmit = false;
|
|
111
152
|
// private cancelToken: CancelTokenSource;
|
|
@@ -149,18 +190,29 @@ export class Modax extends RapidElement {
|
|
|
149
190
|
}
|
|
150
191
|
|
|
151
192
|
public updatePrimaryButton(): void {
|
|
193
|
+
const wizard = this.shadowRoot.querySelector(
|
|
194
|
+
'#wizard-form'
|
|
195
|
+
) as HTMLDivElement;
|
|
196
|
+
if (wizard) {
|
|
197
|
+
this.wizardStep = parseInt(wizard.dataset.step);
|
|
198
|
+
this.wizardStepCount = parseInt(wizard.dataset.steps);
|
|
199
|
+
}
|
|
200
|
+
|
|
152
201
|
if (!this.noSubmit) {
|
|
153
202
|
this.updateComplete.then(() => {
|
|
154
203
|
const submitButton = this.shadowRoot.querySelector(
|
|
155
|
-
"input[type='submit']"
|
|
204
|
+
"input[type='submit'],button[type='submit']"
|
|
156
205
|
) as any;
|
|
157
206
|
|
|
158
207
|
if (submitButton) {
|
|
159
|
-
this.
|
|
160
|
-
|
|
208
|
+
this.buttons = [
|
|
209
|
+
{ type: ButtonType.SECONDARY, name: 'Cancel', closes: true },
|
|
210
|
+
{ type: ButtonType.PRIMARY, name: submitButton.value },
|
|
211
|
+
];
|
|
161
212
|
} else {
|
|
162
|
-
this.
|
|
163
|
-
|
|
213
|
+
this.buttons = [
|
|
214
|
+
{ type: ButtonType.SECONDARY, name: 'Ok', closes: true },
|
|
215
|
+
];
|
|
164
216
|
}
|
|
165
217
|
this.submitting = false;
|
|
166
218
|
});
|
|
@@ -229,22 +281,37 @@ export class Modax extends RapidElement {
|
|
|
229
281
|
this.body = this.getLoading();
|
|
230
282
|
getUrl(this.endpoint, null, this.getHeaders()).then(
|
|
231
283
|
(response: WebResponse) => {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
this.
|
|
237
|
-
|
|
284
|
+
// if it's a full page, breakout of the modal
|
|
285
|
+
if (response.body.indexOf('<!DOCTYPE HTML>') == 0) {
|
|
286
|
+
document.location = response.url;
|
|
287
|
+
} else {
|
|
288
|
+
this.setBody(response.body);
|
|
289
|
+
this.fetching = false;
|
|
290
|
+
this.updateComplete.then(() => {
|
|
291
|
+
this.updatePrimaryButton();
|
|
292
|
+
this.fireCustomEvent(CustomEventType.Loaded, {
|
|
293
|
+
body: this.getBody(),
|
|
294
|
+
});
|
|
238
295
|
});
|
|
239
|
-
}
|
|
296
|
+
}
|
|
240
297
|
}
|
|
241
298
|
);
|
|
242
299
|
}
|
|
243
300
|
|
|
244
|
-
public submit(): void {
|
|
301
|
+
public submit(extra = {}): void {
|
|
245
302
|
this.submitting = true;
|
|
246
303
|
const form = this.shadowRoot.querySelector('form');
|
|
247
|
-
|
|
304
|
+
|
|
305
|
+
let postData = form ? serialize(form) : '';
|
|
306
|
+
if (extra) {
|
|
307
|
+
Object.keys(extra).forEach(key => {
|
|
308
|
+
postData +=
|
|
309
|
+
(postData.length > 1 ? '&' : '') +
|
|
310
|
+
encodeURIComponent(key) +
|
|
311
|
+
'=' +
|
|
312
|
+
encodeURIComponent(extra[key]);
|
|
313
|
+
});
|
|
314
|
+
}
|
|
248
315
|
|
|
249
316
|
postUrl(
|
|
250
317
|
this.endpoint,
|
|
@@ -278,7 +345,9 @@ export class Modax extends RapidElement {
|
|
|
278
345
|
} else {
|
|
279
346
|
// if we set the body, update our submit button
|
|
280
347
|
if (this.setBody(response.body)) {
|
|
281
|
-
this.
|
|
348
|
+
this.updateComplete.then(() => {
|
|
349
|
+
this.updatePrimaryButton();
|
|
350
|
+
});
|
|
282
351
|
}
|
|
283
352
|
}
|
|
284
353
|
}, 1000);
|
|
@@ -290,15 +359,16 @@ export class Modax extends RapidElement {
|
|
|
290
359
|
|
|
291
360
|
private handleDialogClick(evt: CustomEvent) {
|
|
292
361
|
const button = evt.detail.button;
|
|
362
|
+
const detail = evt.detail.detail;
|
|
293
363
|
if (!button.disabled && !button.submitting) {
|
|
294
|
-
if (button.
|
|
364
|
+
if (button.primary || button.destructive) {
|
|
295
365
|
if (!this.suspendSubmit) {
|
|
296
366
|
this.submit();
|
|
297
367
|
}
|
|
298
368
|
}
|
|
299
369
|
}
|
|
300
370
|
|
|
301
|
-
if (
|
|
371
|
+
if (detail.closes) {
|
|
302
372
|
this.open = false;
|
|
303
373
|
this.fetching = false;
|
|
304
374
|
this.cancelName = undefined;
|
|
@@ -315,16 +385,47 @@ export class Modax extends RapidElement {
|
|
|
315
385
|
return this.endpoint && this.endpoint.indexOf('delete') > -1;
|
|
316
386
|
}
|
|
317
387
|
|
|
388
|
+
private handleGotoStep(evt: MouseEvent) {
|
|
389
|
+
const step = (evt.target as HTMLDivElement).dataset.gotoStep;
|
|
390
|
+
if (step) {
|
|
391
|
+
this.submit({ wizard_goto_step: step });
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
318
395
|
public getBody() {
|
|
319
396
|
return this.shadowRoot.querySelector('.modax-body');
|
|
320
397
|
}
|
|
321
398
|
|
|
322
399
|
public render(): TemplateResult {
|
|
400
|
+
const wizardStepBalls = [];
|
|
401
|
+
|
|
402
|
+
const wizard = this.shadowRoot.querySelector(
|
|
403
|
+
'#wizard-form'
|
|
404
|
+
) as HTMLDivElement;
|
|
405
|
+
if (wizard) {
|
|
406
|
+
const completed = (wizard.getAttribute('data-completed') || '')
|
|
407
|
+
.split(',')
|
|
408
|
+
.filter(step => step.length > 0);
|
|
409
|
+
|
|
410
|
+
for (let i = 0; i < this.wizardStepCount; i++) {
|
|
411
|
+
wizardStepBalls.push(
|
|
412
|
+
html`<div
|
|
413
|
+
data-goto-step=${completed[i]}
|
|
414
|
+
@click=${this.handleGotoStep.bind(this)}
|
|
415
|
+
class="${getClasses({
|
|
416
|
+
'step-ball': true,
|
|
417
|
+
active: this.wizardStep - 1 === i,
|
|
418
|
+
complete: i < completed.length,
|
|
419
|
+
})}"
|
|
420
|
+
></div>`
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
323
425
|
return html`
|
|
324
426
|
<temba-dialog
|
|
325
|
-
header=${this.header}
|
|
326
|
-
.
|
|
327
|
-
.cancelButtonName=${this.cancelName || 'Cancel'}
|
|
427
|
+
.header=${this.header}
|
|
428
|
+
.buttons=${this.buttons}
|
|
328
429
|
?open=${this.open}
|
|
329
430
|
?loading=${this.fetching}
|
|
330
431
|
?submitting=${this.submitting}
|
|
@@ -338,6 +439,9 @@ export class Modax extends RapidElement {
|
|
|
338
439
|
${this.body}
|
|
339
440
|
</div>
|
|
340
441
|
<div class="scripts"></div>
|
|
442
|
+
<div slot="gutter">
|
|
443
|
+
<div class="wizard-steps">${wizardStepBalls}</div>
|
|
444
|
+
</div>
|
|
341
445
|
</temba-dialog>
|
|
342
446
|
<div class="slot-wrapper" @click=${this.handleSlotClicked}>
|
|
343
447
|
<slot></slot>
|
package/src/utils/index.ts
CHANGED
package/src/vectoricon/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// for cache busting we dynamically generate a fingerprint, use yarn svg to update
|
|
2
|
-
export const SVG_FINGERPRINT = '
|
|
2
|
+
export const SVG_FINGERPRINT = '5d22cc3a5fb06da9ea0a632539b39983';
|
|
3
3
|
|
|
4
4
|
// only icons below are included in the sprite sheet
|
|
5
5
|
export enum Icon {
|
|
@@ -116,6 +116,7 @@ export enum Icon {
|
|
|
116
116
|
missing = 'maximize-02',
|
|
117
117
|
missed_call = 'phone-x',
|
|
118
118
|
new = 'plus',
|
|
119
|
+
next_schedule = 'alarm-clock',
|
|
119
120
|
notification = 'bell-01',
|
|
120
121
|
org_active = 'credit-card-02',
|
|
121
122
|
org_anonymous = 'glasses-01',
|
|
@@ -129,6 +130,7 @@ export enum Icon {
|
|
|
129
130
|
progress_spinner = 'refresh-cw-04',
|
|
130
131
|
featured = 'star-01',
|
|
131
132
|
referral = 'user-right-01',
|
|
133
|
+
resend = 'refresh-cw-05',
|
|
132
134
|
resthooks = 'share-07',
|
|
133
135
|
restore = 'play',
|
|
134
136
|
retry = 'refresh-cw-05',
|