@nyaruka/temba-components 0.76.0 → 0.78.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 +15 -5
- package/dist/{3c275eb2.js → 736dd89d.js} +62 -59
- package/dist/index.js +62 -59
- 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/date/TembaDate.js +10 -16
- package/out-tsc/src/date/TembaDate.js.map +1 -1
- package/out-tsc/src/templates/TemplateEditor.js +53 -89
- package/out-tsc/src/templates/TemplateEditor.js.map +1 -1
- package/out-tsc/test/temba-date.test.js +11 -1
- package/out-tsc/test/temba-date.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/date/date-inline.png +0 -0
- package/screenshots/truth/date/date.png +0 -0
- package/screenshots/truth/date/datetime.png +0 -0
- package/screenshots/truth/date/duration.png +0 -0
- package/src/date/TembaDate.ts +11 -16
- package/src/templates/TemplateEditor.ts +62 -100
- package/static/api/templates.json +104 -68
- package/test/temba-date.test.ts +16 -4
package/dist/sw.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
if(!self.define){let e,t={};const o=(o,n)=>(o=new URL(o+".js",n).href,t[o]||new Promise((t=>{if("document"in self){const e=document.createElement("script");e.src=o,e.onload=t,document.head.appendChild(e)}else e=o,importScripts(o),t()})).then((()=>{let e=t[o];if(!e)throw new Error(`Module ${o} didn’t register its module`);return e})));self.define=(n,s)=>{const i=e||("document"in self?document.currentScript.src:"")||location.href;if(t[i])return;let r={};const
|
|
1
|
+
if(!self.define){let e,t={};const o=(o,n)=>(o=new URL(o+".js",n).href,t[o]||new Promise((t=>{if("document"in self){const e=document.createElement("script");e.src=o,e.onload=t,document.head.appendChild(e)}else e=o,importScripts(o),t()})).then((()=>{let e=t[o];if(!e)throw new Error(`Module ${o} didn’t register its module`);return e})));self.define=(n,s)=>{const i=e||("document"in self?document.currentScript.src:"")||location.href;if(t[i])return;let r={};const l=e=>o(e,i),c={module:{uri:i},exports:r,require:l};t[i]=Promise.all(n.map((e=>c[e]||l(e)))).then((e=>(s(...e),r)))}}define(["./workbox-919adfb7"],(function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"736dd89d.js",revision:"5315b93c1141129c63615e9f0c3a9785"},{url:"templates/components-body.html",revision:"7d327fa077f6518e4afec37f08908225"},{url:"templates/components-head.html",revision:"8414a36f926372f37082d7cdb07cb5b6"}],{}),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("/index.html"))),e.registerRoute("polyfills/*.js",new e.CacheFirst,"GET")}));
|
|
2
2
|
//# sourceMappingURL=sw.js.map
|
package/dist/sw.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sw.js","sources":["../../tmp/
|
|
1
|
+
{"version":3,"file":"sw.js","sources":["../../tmp/418d797d859dfd53ace27b464065ddae/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from '/workspaces/temba-components/node_modules/workbox-routing/registerRoute.mjs';\nimport {CacheFirst as workbox_strategies_CacheFirst} from '/workspaces/temba-components/node_modules/workbox-strategies/CacheFirst.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from '/workspaces/temba-components/node_modules/workbox-core/clientsClaim.mjs';\nimport {precacheAndRoute as workbox_precaching_precacheAndRoute} from '/workspaces/temba-components/node_modules/workbox-precaching/precacheAndRoute.mjs';\nimport {NavigationRoute as workbox_routing_NavigationRoute} from '/workspaces/temba-components/node_modules/workbox-routing/NavigationRoute.mjs';\nimport {createHandlerBoundToURL as workbox_precaching_createHandlerBoundToURL} from '/workspaces/temba-components/node_modules/workbox-precaching/createHandlerBoundToURL.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n/**\n * The precacheAndRoute() method efficiently caches and responds to\n * requests for URLs in the manifest.\n * See https://goo.gl/S9QRab\n */\nworkbox_precaching_precacheAndRoute([\n {\n \"url\": \"736dd89d.js\",\n \"revision\": \"5315b93c1141129c63615e9f0c3a9785\"\n },\n {\n \"url\": \"templates/components-body.html\",\n \"revision\": \"7d327fa077f6518e4afec37f08908225\"\n },\n {\n \"url\": \"templates/components-head.html\",\n \"revision\": \"8414a36f926372f37082d7cdb07cb5b6\"\n }\n], {});\n\nworkbox_routing_registerRoute(new workbox_routing_NavigationRoute(workbox_precaching_createHandlerBoundToURL(\"/index.html\")));\n\n\nworkbox_routing_registerRoute(\"polyfills/*.js\", new workbox_strategies_CacheFirst(), 'GET');\n\n\n\n\n"],"names":["self","skipWaiting","workbox_core_clientsClaim","workbox_precaching_precacheAndRoute","url","revision","workbox","registerRoute","workbox_routing_NavigationRoute","workbox_precaching_createHandlerBoundToURL","workbox_strategies_CacheFirst"],"mappings":"0nBAwBAA,KAAKC,cAELC,EAAAA,eAQAC,EAAAA,iBAAoC,CAClC,CACEC,IAAO,cACPC,SAAY,oCAEd,CACED,IAAO,iCACPC,SAAY,oCAEd,CACED,IAAO,iCACPC,SAAY,qCAEb,CAAE,GAEwBC,EAAAC,cAAC,IAAIC,EAAAA,gBAAgCC,EAAAA,wBAA2C,iBAGhFH,EAAAC,cAAC,iBAAkB,IAAIG,aAAiC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<script type="module" src="{{STATIC_URL}}@nyaruka/temba-components/dist/
|
|
1
|
+
<script type="module" src="{{STATIC_URL}}@nyaruka/temba-components/dist/736dd89d.js"></script><script>window.TEMBA_COMPONENTS_VERSION="0.78.0"</script>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<script src="{{STATIC_URL}}croppie/croppie.js"></script><link rel="modulepreload" href="{{STATIC_URL}}@nyaruka/temba-components/dist/
|
|
1
|
+
<script src="{{STATIC_URL}}croppie/croppie.js"></script><link rel="modulepreload" href="{{STATIC_URL}}@nyaruka/temba-components/dist/736dd89d.js" crossorigin="anonymous">
|
|
@@ -20,10 +20,7 @@ export class TembaDate extends RapidElement {
|
|
|
20
20
|
static get styles() {
|
|
21
21
|
return css `
|
|
22
22
|
.date {
|
|
23
|
-
display:
|
|
24
|
-
overflow: hidden;
|
|
25
|
-
text-overflow: ellipsis;
|
|
26
|
-
white-space: nowrap;
|
|
23
|
+
display: inline;
|
|
27
24
|
}
|
|
28
25
|
`;
|
|
29
26
|
}
|
|
@@ -59,24 +56,22 @@ export class TembaDate extends RapidElement {
|
|
|
59
56
|
else if (this.display === Display.relative) {
|
|
60
57
|
const minutes = Math.abs(this.datetime.diffNow().milliseconds / 1000 / 60);
|
|
61
58
|
if (minutes < 1) {
|
|
62
|
-
return html `<
|
|
59
|
+
return html `<span
|
|
63
60
|
class="date"
|
|
64
61
|
title="${this.datetime.toLocaleString(Display.datetime)}"
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
</div>`;
|
|
62
|
+
>just now</span
|
|
63
|
+
>`;
|
|
68
64
|
}
|
|
69
65
|
formatted = this.store.getShortDuration(this.datetime);
|
|
70
66
|
}
|
|
71
67
|
else if (this.display === Display.duration) {
|
|
72
68
|
const minutes = Math.abs(this.datetime.diffNow().milliseconds / 1000 / 60);
|
|
73
69
|
if (minutes < 1) {
|
|
74
|
-
return html `<
|
|
70
|
+
return html `<span
|
|
75
71
|
class="date"
|
|
76
72
|
title="${this.datetime.toLocaleString(Display.datetime)}"
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
</div>`;
|
|
73
|
+
>just now</span
|
|
74
|
+
>`;
|
|
80
75
|
}
|
|
81
76
|
formatted = this.store.getShortDuration(this.datetime);
|
|
82
77
|
}
|
|
@@ -86,12 +81,11 @@ export class TembaDate extends RapidElement {
|
|
|
86
81
|
else {
|
|
87
82
|
formatted = this.datetime.toLocaleString(Display[this.display]);
|
|
88
83
|
}
|
|
89
|
-
return html `<
|
|
84
|
+
return html `<span
|
|
90
85
|
class="date"
|
|
91
86
|
title="${this.datetime.toLocaleString(Display.datetime)}"
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
</div>`;
|
|
87
|
+
>${formatted}</span
|
|
88
|
+
>`;
|
|
95
89
|
}
|
|
96
90
|
}
|
|
97
91
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TembaDate.js","sourceRoot":"","sources":["../../../src/date/TembaDate.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAoC,MAAM,KAAK,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEjC,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,IAAI,EAAE,QAAQ,CAAC,UAAU;IACzB,QAAQ,EAAE,QAAQ,CAAC,cAAc;IACjC,IAAI,EAAE,QAAQ,CAAC,WAAW;IAC1B,QAAQ,EAAE,UAAU;IACpB,QAAQ,EAAE,UAAU;IACpB,QAAQ,EAAE,UAAU;IACpB,GAAG,EAAE,OAAO;CACb,CAAC;AAEF,MAAM,OAAO,SAAU,SAAQ,YAAY;IAA3C;;
|
|
1
|
+
{"version":3,"file":"TembaDate.js","sourceRoot":"","sources":["../../../src/date/TembaDate.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, PropertyValueMap, TemplateResult } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { RapidElement } from '../RapidElement';\nimport { Store } from '../store/Store';\nimport { DateTime } from 'luxon';\n\nexport const Display = {\n date: DateTime.DATE_SHORT,\n datetime: DateTime.DATETIME_SHORT,\n time: DateTime.TIME_SIMPLE,\n timedate: 'timedate',\n duration: 'duration',\n relative: 'relative',\n day: 'LLL d',\n};\n\nexport class TembaDate extends RapidElement {\n static get styles() {\n return css`\n .date {\n display: inline;\n }\n `;\n }\n\n @property({ type: String })\n value: string;\n\n @property({ type: String })\n display = 'date';\n\n @property({ type: Object, attribute: false })\n datetime: DateTime;\n\n store: Store;\n\n protected firstUpdated(\n changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(changedProperties);\n this.store = document.querySelector('temba-store');\n }\n\n protected updated(\n changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.updated(changedProperties);\n if (changedProperties.has('value')) {\n this.datetime = DateTime.fromISO(this.value);\n }\n }\n\n public connectedCallback(): void {\n super.connectedCallback();\n }\n\n public render(): TemplateResult {\n if (this.datetime && this.store) {\n this.datetime.setLocale(this.store.getLocale());\n\n let formatted = '';\n if (this.display === Display.timedate) {\n const hours = Math.abs(\n this.datetime.diffNow().milliseconds / 1000 / 60 / 60\n );\n if (hours < 24) {\n formatted = this.datetime.toLocaleString(Display.time);\n } else if (hours < 24 * 365) {\n formatted = this.datetime.toFormat(Display.day);\n } else {\n formatted = this.datetime.toLocaleString(Display.date);\n }\n } else if (this.display === Display.relative) {\n const minutes = Math.abs(\n this.datetime.diffNow().milliseconds / 1000 / 60\n );\n if (minutes < 1) {\n return html`<span\n class=\"date\"\n title=\"${this.datetime.toLocaleString(Display.datetime)}\"\n >just now</span\n >`;\n }\n\n formatted = this.store.getShortDuration(this.datetime);\n } else if (this.display === Display.duration) {\n const minutes = Math.abs(\n this.datetime.diffNow().milliseconds / 1000 / 60\n );\n if (minutes < 1) {\n return html`<span\n class=\"date\"\n title=\"${this.datetime.toLocaleString(Display.datetime)}\"\n >just now</span\n >`;\n }\n formatted = this.store.getShortDuration(this.datetime);\n } else if (this.display === Display.day) {\n formatted = this.datetime.toLocaleString(Display.day);\n } else {\n formatted = this.datetime.toLocaleString(Display[this.display]);\n }\n\n return html`<span\n class=\"date\"\n title=\"${this.datetime.toLocaleString(Display.datetime)}\"\n >${formatted}</span\n >`;\n }\n }\n}\n"]}
|
|
@@ -3,17 +3,10 @@ import { property } from 'lit/decorators.js';
|
|
|
3
3
|
import { FormElement } from '../FormElement';
|
|
4
4
|
import { html, css } from 'lit';
|
|
5
5
|
import { CustomEventType } from '../interfaces';
|
|
6
|
-
const KEY_HEADER = 'header';
|
|
7
|
-
const KEY_BODY = 'body';
|
|
8
|
-
const KEY_FOOTER = 'footer';
|
|
9
|
-
const KEY_BUTTONS = 'button';
|
|
10
6
|
export class TemplateEditor extends FormElement {
|
|
11
7
|
constructor() {
|
|
12
8
|
super(...arguments);
|
|
13
9
|
this.lang = 'eng-US';
|
|
14
|
-
this.buttonKeys = [];
|
|
15
|
-
this.contentKeys = [];
|
|
16
|
-
this.otherKeys = [];
|
|
17
10
|
}
|
|
18
11
|
static get styles() {
|
|
19
12
|
return css `
|
|
@@ -81,9 +74,18 @@ export class TemplateEditor extends FormElement {
|
|
|
81
74
|
border-radius: var(--curvature);
|
|
82
75
|
min-height: 23px;
|
|
83
76
|
display: flex;
|
|
77
|
+
flex-direction: row;
|
|
84
78
|
align-items: center;
|
|
85
79
|
margin-right: 0.5em;
|
|
86
80
|
margin-top: 0.5em;
|
|
81
|
+
align-items: center;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.button .display {
|
|
85
|
+
margin-right: 0.5em;
|
|
86
|
+
background: #f9f9f9;
|
|
87
|
+
padding: 0.25em 1em;
|
|
88
|
+
border-radius: var(--curvature);
|
|
87
89
|
}
|
|
88
90
|
|
|
89
91
|
temba-textinput,
|
|
@@ -117,29 +119,13 @@ export class TemplateEditor extends FormElement {
|
|
|
117
119
|
if (translation.locale === this.lang ||
|
|
118
120
|
(!loc && translation.locale.split('-')[0] === lang)) {
|
|
119
121
|
this.translation = translation;
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
this.otherKeys = [];
|
|
123
|
-
const keys = Object.keys(translation.components);
|
|
124
|
-
for (const key of keys) {
|
|
125
|
-
if (key.startsWith(KEY_BUTTONS)) {
|
|
126
|
-
this.buttonKeys.push(key);
|
|
127
|
-
}
|
|
128
|
-
else if (key === KEY_HEADER ||
|
|
129
|
-
key === KEY_BODY ||
|
|
130
|
-
key === KEY_FOOTER) {
|
|
131
|
-
this.contentKeys.push(key);
|
|
132
|
-
}
|
|
133
|
-
else {
|
|
134
|
-
this.otherKeys.push(key);
|
|
135
|
-
}
|
|
136
|
-
const compParams = translation.components[key].params || [];
|
|
122
|
+
for (const comp of translation.components) {
|
|
123
|
+
const compParams = comp.params || [];
|
|
137
124
|
if (compParams.length > 0) {
|
|
138
125
|
// create an array for the length of params
|
|
139
|
-
newParams[
|
|
126
|
+
newParams[comp.name] = new Array(compParams.length).fill('');
|
|
140
127
|
}
|
|
141
128
|
}
|
|
142
|
-
this.buttonKeys.sort();
|
|
143
129
|
// if we are looking at the same template copy our params on top
|
|
144
130
|
if (this.template === this.selectedTemplate.uuid) {
|
|
145
131
|
for (const key of Object.keys(this.params || {})) {
|
|
@@ -165,95 +151,77 @@ export class TemplateEditor extends FormElement {
|
|
|
165
151
|
}
|
|
166
152
|
handleVariableChanged(event) {
|
|
167
153
|
const target = event.target;
|
|
168
|
-
const key = target.getAttribute('key');
|
|
169
154
|
const index = parseInt(target.getAttribute('index'));
|
|
170
|
-
this.params[
|
|
155
|
+
this.params[target.name][index - 1] = target.value;
|
|
171
156
|
this.fireCustomEvent(CustomEventType.ContentChanged, {
|
|
172
157
|
template: this.selectedTemplate,
|
|
173
158
|
translation: this.translation,
|
|
174
159
|
params: this.params,
|
|
175
160
|
});
|
|
176
161
|
}
|
|
177
|
-
renderVariables(
|
|
162
|
+
renderVariables(component) {
|
|
178
163
|
const parts = component.content.split(/{{(\d+)}}/g);
|
|
179
164
|
if (parts.length > 0) {
|
|
180
165
|
const variables = parts.map((part, index) => {
|
|
181
|
-
const
|
|
166
|
+
const paramIndex = Math.round(index / 2);
|
|
182
167
|
if (index % 2 === 0) {
|
|
183
168
|
return html `<span class="text">${part}</span>`;
|
|
184
169
|
}
|
|
185
170
|
return html `<temba-completion
|
|
186
171
|
class="variable"
|
|
187
172
|
type="text"
|
|
188
|
-
value=${this.params[
|
|
173
|
+
value=${this.params[component.name][paramIndex - 1]}
|
|
189
174
|
@change=${this.handleVariableChanged}
|
|
190
|
-
|
|
191
|
-
index="${
|
|
175
|
+
name="${component.name}"
|
|
176
|
+
index="${paramIndex}"
|
|
192
177
|
placeholder="variable.."
|
|
193
178
|
></temba-completion>`;
|
|
194
179
|
});
|
|
195
180
|
return html `<div class="content">${variables}</div>`;
|
|
196
181
|
}
|
|
197
182
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
${this.renderVariables(KEY_HEADER, components[KEY_HEADER])}
|
|
183
|
+
renderComponents(components) {
|
|
184
|
+
const nonButtons = components
|
|
185
|
+
.filter(comp => !comp.type.startsWith('button/'))
|
|
186
|
+
.map(component => html `<div class="${component['name']}">
|
|
187
|
+
${this.renderVariables(component)}
|
|
188
|
+
</div>`);
|
|
189
|
+
const buttonComponents = components.filter(comp => comp.type.startsWith('button/'));
|
|
190
|
+
const buttons = buttonComponents.length > 0 ? this.renderButtons(buttonComponents) : null;
|
|
191
|
+
return html `<div class="main">${nonButtons}</div>
|
|
192
|
+
<div class="buttons">
|
|
193
|
+
${buttons}
|
|
194
|
+
<div></div>
|
|
211
195
|
</div>`;
|
|
212
|
-
}
|
|
213
|
-
if (components[KEY_BODY]) {
|
|
214
|
-
body = html `<div class="body">
|
|
215
|
-
${this.renderVariables(KEY_BODY, components[KEY_BODY])}
|
|
216
|
-
</div>`;
|
|
217
|
-
}
|
|
218
|
-
if (components[KEY_FOOTER]) {
|
|
219
|
-
footer = html `<div class="footer">
|
|
220
|
-
${this.renderVariables(KEY_FOOTER, components[KEY_FOOTER])}
|
|
221
|
-
</div>`;
|
|
222
|
-
}
|
|
223
|
-
if (header || body || footer) {
|
|
224
|
-
return html `<div class="content">${header}${body}${footer}</div>`;
|
|
225
|
-
}
|
|
226
|
-
return null;
|
|
227
196
|
}
|
|
228
197
|
renderButtons(components) {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
198
|
+
const buttons = components.map(component => {
|
|
199
|
+
if (component.display) {
|
|
200
|
+
return html `
|
|
201
|
+
<div class="button">
|
|
202
|
+
<div class="display">${component.display}</div>
|
|
203
|
+
${this.renderVariables(component)}
|
|
204
|
+
</div>
|
|
205
|
+
`;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
return html `
|
|
209
|
+
<div class="button">${this.renderVariables(component)}</div>
|
|
210
|
+
`;
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
return html `<div class="button-wrapper">
|
|
214
|
+
<div class="button-header">Template Buttons</div>
|
|
215
|
+
<div class="buttons">${buttons}</div>
|
|
216
|
+
</div>`;
|
|
242
217
|
}
|
|
243
218
|
render() {
|
|
244
219
|
let content = null;
|
|
245
|
-
let buttons = null;
|
|
246
|
-
let otherComponents = null;
|
|
247
220
|
if (this.translation) {
|
|
248
|
-
content = this.
|
|
249
|
-
buttons = this.renderButtons(this.translation.components);
|
|
250
|
-
otherComponents = this.otherKeys.map(key => {
|
|
251
|
-
const component = this.translation.components[key];
|
|
252
|
-
return this.renderComponent(key, component);
|
|
253
|
-
});
|
|
221
|
+
content = this.renderComponents(this.translation.components);
|
|
254
222
|
}
|
|
255
223
|
else {
|
|
256
|
-
|
|
224
|
+
content = html `<div class="error-message">
|
|
257
225
|
No approved translation was found for current language.
|
|
258
226
|
</div>`;
|
|
259
227
|
}
|
|
@@ -266,7 +234,7 @@ export class TemplateEditor extends FormElement {
|
|
|
266
234
|
valuekey="uuid"
|
|
267
235
|
class="picker"
|
|
268
236
|
value="${this.template}"
|
|
269
|
-
endpoint
|
|
237
|
+
endpoint="${this.url}?comps_as_list=true"
|
|
270
238
|
shouldExclude=${template => template.status !== 'approved'}
|
|
271
239
|
placeholder="Select a template"
|
|
272
240
|
@temba-content-changed=${this.swallowEvent}
|
|
@@ -274,11 +242,7 @@ export class TemplateEditor extends FormElement {
|
|
|
274
242
|
>
|
|
275
243
|
</temba-select>
|
|
276
244
|
|
|
277
|
-
${this.template
|
|
278
|
-
? html ` <div class="template">
|
|
279
|
-
${content} ${buttons} ${otherComponents}
|
|
280
|
-
</div>`
|
|
281
|
-
: null}
|
|
245
|
+
${this.template ? html ` <div class="template">${content}</div>` : null}
|
|
282
246
|
</div>
|
|
283
247
|
`;
|
|
284
248
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TemplateEditor.js","sourceRoot":"","sources":["../../../src/templates/TemplateEditor.ts"],"names":[],"mappings":"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","sourcesContent":["import { property } from 'lit/decorators.js';\nimport { FormElement } from '../FormElement';\nimport { TemplateResult, html, css, PropertyValueMap } from 'lit';\nimport { CustomEventType } from '../interfaces';\n\nconst KEY_HEADER = 'header';\nconst KEY_BODY = 'body';\nconst KEY_FOOTER = 'footer';\nconst KEY_BUTTONS = 'button';\n\ninterface Component {\n content: string;\n params: { type: string }[];\n}\n\ninterface Translation {\n locale: string;\n status: string;\n channel: { uuid: string; name: string };\n components: { [key: string]: Component };\n}\n\ninterface Template {\n created_on: string;\n modified_on: string;\n name: string;\n translations: Translation[];\n uuid: string;\n}\n\nexport class TemplateEditor extends FormElement {\n static get styles() {\n return css`\n .component {\n background: #fff;\n border: 1px solid var(--color-widget-border);\n border-radius: var(--curvature);\n padding: 1em;\n margin-top: 1em;\n }\n .picker {\n margin-bottom: 0.5em;\n display: block;\n }\n .param {\n display: flex;\n margin-bottom: 0.5em;\n align-items: center;\n }\n label {\n margin-right: 0.5em;\n }\n\n .content span {\n margin-right: 0.25em;\n }\n\n .error-message {\n padding-left: 0.5em;\n }\n\n .variable {\n display: inline-block;\n margin: 0.25em 0em;\n margin-right: 0.25em;\n }\n\n .button-wrapper {\n margin-top: 1em;\n background: #f9f9f9;\n border-radius: var(--curvature);\n padding: 0.5em;\n display: flex;\n flex-direction: column;\n }\n\n .button-header {\n font-weight: normal;\n margin-left: 0.25em;\n margin-bottom: -0.5em;\n font-size: 0.9em;\n color: #777;\n }\n\n .buttons {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n }\n\n .button {\n background: #fff;\n padding: 0.3em 1em;\n border: 1px solid #e6e6e6;\n border-radius: var(--curvature);\n min-height: 23px;\n display: flex;\n align-items: center;\n margin-right: 0.5em;\n margin-top: 0.5em;\n }\n\n temba-textinput,\n temba-completion {\n --temba-textinput-padding: 5px 5px;\n --temba-textinput-font-size: 0.9em;\n line-height: initial;\n }\n\n .template {\n background: #fff;\n border-radius: var(--curvature);\n border: 1px solid var(--color-widget-border);\n padding: 1em;\n line-height: 2.2em;\n }\n `;\n }\n\n @property({ type: String })\n url: string;\n\n // initial template uuid\n @property({ type: String })\n template: string;\n\n @property({ type: Object })\n selectedTemplate: Template;\n\n @property({ type: String })\n lang = 'eng-US';\n\n // component key to array of strings for variables\n @property({ type: Object })\n params: { [key: string]: string[] };\n\n @property({ type: Object, attribute: false })\n translation: Translation;\n\n @property({ type: Boolean })\n translating: boolean;\n\n buttonKeys = [];\n contentKeys = [];\n otherKeys = [];\n\n public firstUpdated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(changes);\n }\n\n public updated(changedProperties: Map<string, any>): void {\n super.updated(changedProperties);\n }\n\n private handleTemplateChanged(event: CustomEvent) {\n this.selectedTemplate = (event.target as any).values[0] as Template;\n const [lang, loc] = this.lang.split('-');\n\n const newParams = {};\n if (this.selectedTemplate) {\n this.selectedTemplate.translations.forEach(translation => {\n if (\n translation.locale === this.lang ||\n (!loc && translation.locale.split('-')[0] === lang)\n ) {\n this.translation = translation;\n this.buttonKeys = [];\n this.contentKeys = [];\n this.otherKeys = [];\n const keys = Object.keys(translation.components);\n for (const key of keys) {\n if (key.startsWith(KEY_BUTTONS)) {\n this.buttonKeys.push(key);\n } else if (\n key === KEY_HEADER ||\n key === KEY_BODY ||\n key === KEY_FOOTER\n ) {\n this.contentKeys.push(key);\n } else {\n this.otherKeys.push(key);\n }\n\n const compParams = translation.components[key].params || [];\n if (compParams.length > 0) {\n // create an array for the length of params\n newParams[key] = new Array(compParams.length).fill('');\n }\n }\n this.buttonKeys.sort();\n\n // if we are looking at the same template copy our params on top\n if (this.template === this.selectedTemplate.uuid) {\n for (const key of Object.keys(this.params || {})) {\n if (newParams[key]) {\n for (let i = 0; i < this.params[key].length; i++) {\n newParams[key][i] = this.params[key][i];\n }\n }\n }\n }\n }\n });\n } else {\n this.translation = null;\n }\n\n this.params = newParams;\n this.fireCustomEvent(CustomEventType.ContextChanged, {\n template: this.selectedTemplate,\n translation: this.translation,\n params: this.params,\n });\n }\n\n private handleVariableChanged(event: CustomEvent) {\n const target = event.target as HTMLInputElement;\n const key = target.getAttribute('key');\n const index = parseInt(target.getAttribute('index'));\n this.params[key][index - 1] = target.value;\n this.fireCustomEvent(CustomEventType.ContentChanged, {\n template: this.selectedTemplate,\n translation: this.translation,\n params: this.params,\n });\n }\n\n private renderVariables(key: string, component: Component) {\n const parts = component.content.split(/{{(\\d+)}}/g);\n if (parts.length > 0) {\n const variables = parts.map((part, index) => {\n const keyIndex = Math.round(index / 2);\n if (index % 2 === 0) {\n return html`<span class=\"text\">${part}</span>`;\n }\n return html`<temba-completion\n class=\"variable\"\n type=\"text\"\n value=${this.params[key][keyIndex - 1]}\n @change=${this.handleVariableChanged}\n key=\"${key}\"\n index=\"${keyIndex}}\"\n placeholder=\"variable..\"\n ></temba-completion>`;\n });\n return html`<div class=\"content\">${variables}</div>`;\n }\n }\n\n private renderComponent(key: string, component: Component) {\n return html` <div class=\"component\">\n <div>${key}</div>\n ${this.renderVariables(key, component)}\n </div>`;\n }\n\n public renderContent(components: {\n [key: string]: Component;\n }): TemplateResult {\n let header = null;\n let body = null;\n let footer = null;\n\n if (components[KEY_HEADER]) {\n header = html`<div class=\"header\">\n ${this.renderVariables(KEY_HEADER, components[KEY_HEADER])}\n </div>`;\n }\n\n if (components[KEY_BODY]) {\n body = html`<div class=\"body\">\n ${this.renderVariables(KEY_BODY, components[KEY_BODY])}\n </div>`;\n }\n\n if (components[KEY_FOOTER]) {\n footer = html`<div class=\"footer\">\n ${this.renderVariables(KEY_FOOTER, components[KEY_FOOTER])}\n </div>`;\n }\n\n if (header || body || footer) {\n return html`<div class=\"content\">${header}${body}${footer}</div>`;\n }\n return null;\n }\n\n public renderButtons(components): TemplateResult {\n if (this.buttonKeys.length > 0) {\n const buttons = this.buttonKeys.map(key => {\n const component = components[key];\n return html`<div class=\"button\">\n ${this.renderVariables(key, component)}\n </div>`;\n });\n return html`<div class=\"button-wrapper\">\n <div class=\"button-header\">Template Buttons</div>\n <div class=\"buttons\">${buttons}</div>\n </div>`;\n }\n return null;\n }\n public render(): TemplateResult {\n let content = null;\n let buttons = null;\n let otherComponents = null;\n if (this.translation) {\n content = this.renderContent(this.translation.components);\n buttons = this.renderButtons(this.translation.components);\n otherComponents = this.otherKeys.map(key => {\n const component = this.translation.components[key];\n return this.renderComponent(key, component);\n });\n } else {\n otherComponents = html`<div class=\"error-message\">\n No approved translation was found for current language.\n </div>`;\n }\n\n return html`\n <div>\n <temba-select\n searchable\n ?clearable=${!this.translating}\n ?disabled=${this.translating}\n valuekey=\"uuid\"\n class=\"picker\"\n value=\"${this.template}\"\n endpoint=${this.url}\n shouldExclude=${template => template.status !== 'approved'}\n placeholder=\"Select a template\"\n @temba-content-changed=${this.swallowEvent}\n @change=${this.handleTemplateChanged}\n >\n </temba-select>\n\n ${this.template\n ? html` <div class=\"template\">\n ${content} ${buttons} ${otherComponents}\n </div>`\n : null}\n </div>\n `;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"TemplateEditor.js","sourceRoot":"","sources":["../../../src/templates/TemplateEditor.ts"],"names":[],"mappings":"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","sourcesContent":["import { property } from 'lit/decorators.js';\nimport { FormElement } from '../FormElement';\nimport { TemplateResult, html, css, PropertyValueMap } from 'lit';\nimport { CustomEventType } from '../interfaces';\n\ninterface Component {\n name: string;\n type: string;\n content: string;\n params: { type: string }[];\n}\n\ninterface Translation {\n locale: string;\n status: string;\n channel: { uuid: string; name: string };\n components: Component[];\n}\n\ninterface Template {\n created_on: string;\n modified_on: string;\n name: string;\n translations: Translation[];\n uuid: string;\n}\n\nexport class TemplateEditor extends FormElement {\n static get styles() {\n return css`\n .component {\n background: #fff;\n border: 1px solid var(--color-widget-border);\n border-radius: var(--curvature);\n padding: 1em;\n margin-top: 1em;\n }\n .picker {\n margin-bottom: 0.5em;\n display: block;\n }\n .param {\n display: flex;\n margin-bottom: 0.5em;\n align-items: center;\n }\n label {\n margin-right: 0.5em;\n }\n\n .content span {\n margin-right: 0.25em;\n }\n\n .error-message {\n padding-left: 0.5em;\n }\n\n .variable {\n display: inline-block;\n margin: 0.25em 0em;\n margin-right: 0.25em;\n }\n\n .button-wrapper {\n margin-top: 1em;\n background: #f9f9f9;\n border-radius: var(--curvature);\n padding: 0.5em;\n display: flex;\n flex-direction: column;\n }\n\n .button-header {\n font-weight: normal;\n margin-left: 0.25em;\n margin-bottom: -0.5em;\n font-size: 0.9em;\n color: #777;\n }\n\n .buttons {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n }\n\n .button {\n background: #fff;\n padding: 0.3em 1em;\n border: 1px solid #e6e6e6;\n border-radius: var(--curvature);\n min-height: 23px;\n display: flex;\n flex-direction: row;\n align-items: center;\n margin-right: 0.5em;\n margin-top: 0.5em;\n align-items: center;\n }\n\n .button .display {\n margin-right: 0.5em;\n background: #f9f9f9;\n padding: 0.25em 1em;\n border-radius: var(--curvature);\n }\n\n temba-textinput,\n temba-completion {\n --temba-textinput-padding: 5px 5px;\n --temba-textinput-font-size: 0.9em;\n line-height: initial;\n }\n\n .template {\n background: #fff;\n border-radius: var(--curvature);\n border: 1px solid var(--color-widget-border);\n padding: 1em;\n line-height: 2.2em;\n }\n `;\n }\n\n @property({ type: String })\n url: string;\n\n // initial template uuid\n @property({ type: String })\n template: string;\n\n @property({ type: Object })\n selectedTemplate: Template;\n\n @property({ type: String })\n lang = 'eng-US';\n\n // component key to array of strings for variables\n @property({ type: Object })\n params: { [key: string]: string[] };\n\n @property({ type: Object, attribute: false })\n translation: Translation;\n\n @property({ type: Boolean })\n translating: boolean;\n\n public firstUpdated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(changes);\n }\n\n public updated(changedProperties: Map<string, any>): void {\n super.updated(changedProperties);\n }\n\n private handleTemplateChanged(event: CustomEvent) {\n this.selectedTemplate = (event.target as any).values[0] as Template;\n const [lang, loc] = this.lang.split('-');\n\n const newParams = {};\n if (this.selectedTemplate) {\n this.selectedTemplate.translations.forEach(translation => {\n if (\n translation.locale === this.lang ||\n (!loc && translation.locale.split('-')[0] === lang)\n ) {\n this.translation = translation;\n for (const comp of translation.components) {\n const compParams = comp.params || [];\n if (compParams.length > 0) {\n // create an array for the length of params\n newParams[comp.name] = new Array(compParams.length).fill('');\n }\n }\n\n // if we are looking at the same template copy our params on top\n if (this.template === this.selectedTemplate.uuid) {\n for (const key of Object.keys(this.params || {})) {\n if (newParams[key]) {\n for (let i = 0; i < this.params[key].length; i++) {\n newParams[key][i] = this.params[key][i];\n }\n }\n }\n }\n }\n });\n } else {\n this.translation = null;\n }\n\n this.params = newParams;\n this.fireCustomEvent(CustomEventType.ContextChanged, {\n template: this.selectedTemplate,\n translation: this.translation,\n params: this.params,\n });\n }\n\n private handleVariableChanged(event: CustomEvent) {\n const target = event.target as HTMLInputElement;\n const index = parseInt(target.getAttribute('index'));\n this.params[target.name][index - 1] = target.value;\n this.fireCustomEvent(CustomEventType.ContentChanged, {\n template: this.selectedTemplate,\n translation: this.translation,\n params: this.params,\n });\n }\n\n private renderVariables(component: Component) {\n const parts = component.content.split(/{{(\\d+)}}/g);\n if (parts.length > 0) {\n const variables = parts.map((part, index) => {\n const paramIndex = Math.round(index / 2);\n if (index % 2 === 0) {\n return html`<span class=\"text\">${part}</span>`;\n }\n return html`<temba-completion\n class=\"variable\"\n type=\"text\"\n value=${this.params[component.name][paramIndex - 1]}\n @change=${this.handleVariableChanged}\n name=\"${component.name}\"\n index=\"${paramIndex}\"\n placeholder=\"variable..\"\n ></temba-completion>`;\n });\n return html`<div class=\"content\">${variables}</div>`;\n }\n }\n\n public renderComponents(components: Component[]): TemplateResult {\n const nonButtons = components\n .filter(comp => !comp.type.startsWith('button/'))\n .map(\n component =>\n html`<div class=\"${component['name']}\">\n ${this.renderVariables(component)}\n </div>`\n );\n const buttonComponents = components.filter(comp =>\n comp.type.startsWith('button/')\n );\n const buttons =\n buttonComponents.length > 0 ? this.renderButtons(buttonComponents) : null;\n return html`<div class=\"main\">${nonButtons}</div>\n <div class=\"buttons\">\n ${buttons}\n <div></div>\n </div>`;\n }\n\n public renderButtons(components): TemplateResult {\n const buttons = components.map(component => {\n if (component.display) {\n return html`\n <div class=\"button\">\n <div class=\"display\">${component.display}</div>\n ${this.renderVariables(component)}\n </div>\n `;\n } else {\n return html`\n <div class=\"button\">${this.renderVariables(component)}</div>\n `;\n }\n });\n return html`<div class=\"button-wrapper\">\n <div class=\"button-header\">Template Buttons</div>\n <div class=\"buttons\">${buttons}</div>\n </div>`;\n }\n\n public render(): TemplateResult {\n let content = null;\n if (this.translation) {\n content = this.renderComponents(this.translation.components);\n } else {\n content = html`<div class=\"error-message\">\n No approved translation was found for current language.\n </div>`;\n }\n\n return html`\n <div>\n <temba-select\n searchable\n ?clearable=${!this.translating}\n ?disabled=${this.translating}\n valuekey=\"uuid\"\n class=\"picker\"\n value=\"${this.template}\"\n endpoint=\"${this.url}?comps_as_list=true\"\n shouldExclude=${template => template.status !== 'approved'}\n placeholder=\"Select a template\"\n @temba-content-changed=${this.swallowEvent}\n @change=${this.handleTemplateChanged}\n >\n </temba-select>\n\n ${this.template ? html` <div class=\"template\">${content}</div>` : null}\n </div>\n `;\n }\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { html, fixture, expect } from '@open-wc/testing';
|
|
1
2
|
import { assertScreenshot, getClip, getComponent, loadStore, mockNow, } from './utils.test';
|
|
2
|
-
import { expect } from '@open-wc/testing';
|
|
3
3
|
const TAG = 'temba-date';
|
|
4
4
|
export const getDate = async (attrs = {}) => {
|
|
5
5
|
attrs['width'] = 100;
|
|
@@ -34,5 +34,15 @@ describe('temba-date', () => {
|
|
|
34
34
|
await assertScreenshot('date/datetime', getClip(date));
|
|
35
35
|
expect(dateString).to.equal('11/18/1978, 9:22 AM');
|
|
36
36
|
});
|
|
37
|
+
it('renders inline', async () => {
|
|
38
|
+
const el = await fixture(html `
|
|
39
|
+
<span
|
|
40
|
+
>Your birthday is
|
|
41
|
+
<temba-date value="1978-11-18T02:22:00.000000-07:00"></temba-date
|
|
42
|
+
>!</span
|
|
43
|
+
>
|
|
44
|
+
`);
|
|
45
|
+
await assertScreenshot('date/date-inline', getClip(el));
|
|
46
|
+
});
|
|
37
47
|
});
|
|
38
48
|
//# sourceMappingURL=temba-date.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"temba-date.test.js","sourceRoot":"","sources":["../../test/temba-date.test.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"temba-date.test.js","sourceRoot":"","sources":["../../test/temba-date.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,EACL,gBAAgB,EAChB,OAAO,EACP,YAAY,EACZ,SAAS,EACT,OAAO,GACR,MAAM,cAAc,CAAC;AAEtB,MAAM,GAAG,GAAG,YAAY,CAAC;AAEzB,MAAM,CAAC,MAAM,OAAO,GAAG,KAAK,EAAE,QAAa,EAAE,EAAE,EAAE;IAC/C,KAAK,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC;IACrB,OAAO,CAAC,MAAM,YAAY,CAAC,GAAG,EAAE,KAAK,CAAC,CAAc,CAAC;AACvD,CAAC,CAAC;AAEF,OAAO,CAAC,kCAAkC,CAAC,CAAC;AAE5C,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,UAAU,CAAC,GAAG,EAAE;QACd,SAAS,EAAE,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iBAAiB,EAAE,KAAK,IAAI,EAAE;QAC/B,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,EAAE,KAAK,EAAE,kCAAkC,EAAE,CAAC,CAAC;QAC1E,MAAM,UAAU,GACd,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,OAAO,CACtC,CAAC,SAAS,CAAC;QAEZ,MAAM,gBAAgB,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACnD,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kBAAkB,EAAE,KAAK,IAAI,EAAE;QAChC,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC;YACzB,KAAK,EAAE,kCAAkC;YACzC,OAAO,EAAE,UAAU;SACpB,CAAC,CAAC;QACH,MAAM,UAAU,GACd,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,OAAO,CACtC,CAAC,SAAS,CAAC;QAEZ,MAAM,gBAAgB,CAAC,eAAe,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kBAAkB,EAAE,KAAK,IAAI,EAAE;QAChC,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC;YACzB,KAAK,EAAE,kCAAkC;YACzC,OAAO,EAAE,UAAU;SACpB,CAAC,CAAC;QACH,MAAM,UAAU,GACd,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,OAAO,CACtC,CAAC,SAAS,CAAC;QAEZ,MAAM,gBAAgB,CAAC,eAAe,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gBAAgB,EAAE,KAAK,IAAI,EAAE;QAC9B,MAAM,EAAE,GAAgB,MAAM,OAAO,CAAC,IAAI,CAAA;;;;;;KAMzC,CAAC,CAAC;QAEH,MAAM,gBAAgB,CAAC,kBAAkB,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { html, fixture, expect } from '@open-wc/testing';\nimport { TembaDate } from '../src/date/TembaDate';\nimport {\n assertScreenshot,\n getClip,\n getComponent,\n loadStore,\n mockNow,\n} from './utils.test';\n\nconst TAG = 'temba-date';\n\nexport const getDate = async (attrs: any = {}) => {\n attrs['width'] = 100;\n return (await getComponent(TAG, attrs)) as TembaDate;\n};\n\nmockNow('2022-12-02T21:00:00.000000-07:00');\n\ndescribe('temba-date', () => {\n beforeEach(() => {\n loadStore();\n });\n\n it('renders default', async () => {\n const date = await getDate({ value: '1978-11-18T02:22:00.000000-07:00' });\n const dateString = (\n date.shadowRoot.querySelector('.date') as HTMLSpanElement\n ).innerText;\n\n await assertScreenshot('date/date', getClip(date));\n expect(dateString).to.equal('11/18/1978');\n });\n\n it('renders duration', async () => {\n const date = await getDate({\n value: '1978-11-18T02:22:00.000000-07:00',\n display: 'duration',\n });\n const dateString = (\n date.shadowRoot.querySelector('.date') as HTMLSpanElement\n ).innerText;\n\n await assertScreenshot('date/duration', getClip(date));\n expect(dateString).to.equal('44 years ago');\n });\n\n it('renders datetime', async () => {\n const date = await getDate({\n value: '1978-11-18T02:22:00.000000-07:00',\n display: 'datetime',\n });\n const dateString = (\n date.shadowRoot.querySelector('.date') as HTMLSpanElement\n ).innerText;\n\n await assertScreenshot('date/datetime', getClip(date));\n expect(dateString).to.equal('11/18/1978, 9:22 AM');\n });\n\n it('renders inline', async () => {\n const el: HTMLElement = await fixture(html`\n <span\n >Your birthday is\n <temba-date value=\"1978-11-18T02:22:00.000000-07:00\"></temba-date\n >!</span\n >\n `);\n\n await assertScreenshot('date/date-inline', getClip(el));\n });\n});\n"]}
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/src/date/TembaDate.ts
CHANGED
|
@@ -18,10 +18,7 @@ export class TembaDate extends RapidElement {
|
|
|
18
18
|
static get styles() {
|
|
19
19
|
return css`
|
|
20
20
|
.date {
|
|
21
|
-
display:
|
|
22
|
-
overflow: hidden;
|
|
23
|
-
text-overflow: ellipsis;
|
|
24
|
-
white-space: nowrap;
|
|
21
|
+
display: inline;
|
|
25
22
|
}
|
|
26
23
|
`;
|
|
27
24
|
}
|
|
@@ -78,12 +75,11 @@ export class TembaDate extends RapidElement {
|
|
|
78
75
|
this.datetime.diffNow().milliseconds / 1000 / 60
|
|
79
76
|
);
|
|
80
77
|
if (minutes < 1) {
|
|
81
|
-
return html`<
|
|
78
|
+
return html`<span
|
|
82
79
|
class="date"
|
|
83
80
|
title="${this.datetime.toLocaleString(Display.datetime)}"
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
</div>`;
|
|
81
|
+
>just now</span
|
|
82
|
+
>`;
|
|
87
83
|
}
|
|
88
84
|
|
|
89
85
|
formatted = this.store.getShortDuration(this.datetime);
|
|
@@ -92,12 +88,11 @@ export class TembaDate extends RapidElement {
|
|
|
92
88
|
this.datetime.diffNow().milliseconds / 1000 / 60
|
|
93
89
|
);
|
|
94
90
|
if (minutes < 1) {
|
|
95
|
-
return html`<
|
|
91
|
+
return html`<span
|
|
96
92
|
class="date"
|
|
97
93
|
title="${this.datetime.toLocaleString(Display.datetime)}"
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
</div>`;
|
|
94
|
+
>just now</span
|
|
95
|
+
>`;
|
|
101
96
|
}
|
|
102
97
|
formatted = this.store.getShortDuration(this.datetime);
|
|
103
98
|
} else if (this.display === Display.day) {
|
|
@@ -105,12 +100,12 @@ export class TembaDate extends RapidElement {
|
|
|
105
100
|
} else {
|
|
106
101
|
formatted = this.datetime.toLocaleString(Display[this.display]);
|
|
107
102
|
}
|
|
108
|
-
|
|
103
|
+
|
|
104
|
+
return html`<span
|
|
109
105
|
class="date"
|
|
110
106
|
title="${this.datetime.toLocaleString(Display.datetime)}"
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
</div>`;
|
|
107
|
+
>${formatted}</span
|
|
108
|
+
>`;
|
|
114
109
|
}
|
|
115
110
|
}
|
|
116
111
|
}
|