@nyaruka/temba-components 0.156.18 → 0.157.1
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/temba-components.js +2119 -1617
- package/dist/temba-components.js.map +1 -1
- package/package.json +1 -1
- package/src/display/Button.ts +102 -121
- package/src/display/Chat.ts +74 -9
- package/src/display/Dropdown.ts +11 -0
- package/src/display/Label.ts +154 -2
- package/src/display/LeafletMap.ts +4 -3
- package/src/display/Options.ts +71 -16
- package/src/display/TembaUser.ts +32 -8
- package/src/events/eventRenderers.ts +243 -95
- package/src/excellent/caret-utils.ts +0 -1
- package/src/flow/AutoTranslate.ts +2 -2
- package/src/flow/Editor.ts +4 -4
- package/src/flow/NodeEditor.ts +2 -2
- package/src/flow/NodeTypeSelector.ts +0 -5
- package/src/flow/RevisionsWindow.ts +1 -3
- package/src/flow/actions/set_contact_language.ts +5 -4
- package/src/flow/nodes/shared.ts +14 -0
- package/src/flow/nodes/split_by_llm_categorize.ts +28 -8
- package/src/flow/utils.ts +39 -60
- package/src/form/ArrayEditor.ts +9 -11
- package/src/form/Checkbox.ts +2 -2
- package/src/form/ColorPicker.ts +5 -3
- package/src/form/Compose.ts +1 -1
- package/src/form/FieldElement.ts +8 -8
- package/src/form/KeyValueEditor.ts +4 -4
- package/src/form/MessageEditor.ts +2 -3
- package/src/form/RangePicker.ts +17 -17
- package/src/form/TembaSlider.ts +10 -10
- package/src/form/TemplateEditor.ts +4 -4
- package/src/form/TextInput.ts +19 -1
- package/src/form/select/Omnibox.ts +21 -20
- package/src/form/select/Select.ts +382 -173
- package/src/form/select/WorkspaceSelect.ts +7 -1
- package/src/interfaces.ts +1 -0
- package/src/languages.ts +56 -0
- package/src/layout/Accordion.ts +2 -2
- package/src/layout/Dialog.ts +1 -3
- package/src/layout/Modax.ts +1 -1
- package/src/list/ContentMenu.ts +1 -2
- package/src/list/SortableList.ts +156 -0
- package/src/list/TembaMenu.ts +159 -113
- package/src/live/ContactBadges.ts +2 -1
- package/src/live/ContactChat.ts +62 -45
- package/src/live/ContactDetails.ts +3 -1
- package/src/live/ContactFieldEditor.ts +36 -31
- package/src/live/FieldManager.ts +4 -4
- package/src/store/AppState.ts +3 -21
- package/src/store/Store.ts +0 -29
- package/src/styles/designTokens.ts +158 -0
- package/src/styles/pillVariants.ts +147 -0
- package/static/css/temba-components.css +141 -36
- package/web-dev-server.config.mjs +0 -1
- package/web-test-runner.config.mjs +98 -1
|
@@ -14,8 +14,14 @@ export class WorkspaceSelect extends Select<WorkspaceOption> {
|
|
|
14
14
|
return css`
|
|
15
15
|
${super.styles}
|
|
16
16
|
|
|
17
|
+
/* Workspace chooser is embedded in the account menu, not a
|
|
18
|
+
standalone form widget — suppress the focus border + halo
|
|
19
|
+
on both the select itself and the dropdown popup. */
|
|
17
20
|
:host {
|
|
18
|
-
border:
|
|
21
|
+
--temba-select-focus-border: transparent;
|
|
22
|
+
--temba-select-focus-halo: none;
|
|
23
|
+
--temba-options-focus-border: transparent;
|
|
24
|
+
--temba-options-focus-halo: none;
|
|
19
25
|
}
|
|
20
26
|
`;
|
|
21
27
|
}
|
package/src/interfaces.ts
CHANGED
package/src/languages.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const intlLanguageNames = new Intl.DisplayNames(['en'], {
|
|
2
|
+
type: 'language',
|
|
3
|
+
fallback: 'none'
|
|
4
|
+
});
|
|
5
|
+
|
|
6
|
+
const ADDITIONAL_LANGUAGE_NAMES: { [code: string]: string } = {
|
|
7
|
+
aab: 'Alumu-Tesu',
|
|
8
|
+
aac: 'Ari',
|
|
9
|
+
aas: 'Aasáx',
|
|
10
|
+
abp: 'Abellen Ayta',
|
|
11
|
+
acf: 'Saint Lucian Creole French',
|
|
12
|
+
aec: 'Saidi Arabic',
|
|
13
|
+
afb: 'Gulf Arabic',
|
|
14
|
+
apd: 'Sudanese Arabic',
|
|
15
|
+
ayl: 'Libyan Arabic',
|
|
16
|
+
blk: "Pa'o Karen",
|
|
17
|
+
bog: 'Bamako Sign Language',
|
|
18
|
+
bzs: 'Brazilian Sign Language',
|
|
19
|
+
csn: 'Colombian Sign Language',
|
|
20
|
+
dag: 'Dagbani',
|
|
21
|
+
ecs: 'Ecuadorian Sign Language',
|
|
22
|
+
frk: 'Frankish',
|
|
23
|
+
fsl: 'French Sign Language',
|
|
24
|
+
fuv: 'Nigerian Fulfulde',
|
|
25
|
+
gcr: 'Guianese Creole French',
|
|
26
|
+
gpe: 'Ghanaian Pidgin English',
|
|
27
|
+
gux: 'Gourmanchéma',
|
|
28
|
+
ise: 'Italian Sign Language',
|
|
29
|
+
ksw: "S'gaw Karen",
|
|
30
|
+
kun: 'Kunama',
|
|
31
|
+
kyu: 'Western Kayah',
|
|
32
|
+
laj: 'Lango',
|
|
33
|
+
nyj: 'Nyanga',
|
|
34
|
+
prd: 'Parsi-Dari',
|
|
35
|
+
prl: 'Peruvian Sign Language',
|
|
36
|
+
pst: 'Central Pashto',
|
|
37
|
+
rop: 'Kriol',
|
|
38
|
+
tdt: 'Tetun Dili',
|
|
39
|
+
toi: 'Tonga',
|
|
40
|
+
tuv: 'Turkana',
|
|
41
|
+
vsl: 'Venezuelan Sign Language'
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export function getLanguageName(code: string): string {
|
|
45
|
+
if (!code) return '';
|
|
46
|
+
if (code === 'und') return 'Unknown';
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
const name = intlLanguageNames.of(code);
|
|
50
|
+
if (name) return name;
|
|
51
|
+
} catch {
|
|
52
|
+
// fall through to additional lookup
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return ADDITIONAL_LANGUAGE_NAMES[code] || code;
|
|
56
|
+
}
|
package/src/layout/Accordion.ts
CHANGED
|
@@ -7,8 +7,8 @@ export class Accordion extends LitElement {
|
|
|
7
7
|
return css`
|
|
8
8
|
:host {
|
|
9
9
|
display: block;
|
|
10
|
-
border: 1px solid
|
|
11
|
-
border-radius:
|
|
10
|
+
border: 1px solid var(--color-widget-border);
|
|
11
|
+
border-radius: var(--curvature-widget);
|
|
12
12
|
overflow: hidden;
|
|
13
13
|
}
|
|
14
14
|
`;
|
package/src/layout/Dialog.ts
CHANGED
|
@@ -181,8 +181,6 @@ export class Dialog extends ResizeElement {
|
|
|
181
181
|
|
|
182
182
|
temba-button {
|
|
183
183
|
margin-left: 10px;
|
|
184
|
-
--button-y: 0.4em;
|
|
185
|
-
--button-x: 1em;
|
|
186
184
|
}
|
|
187
185
|
|
|
188
186
|
.dialog-body temba-loading {
|
|
@@ -555,7 +553,7 @@ export class Dialog extends ResizeElement {
|
|
|
555
553
|
?destructive=${button.type == 'primary' && this.destructive}
|
|
556
554
|
?primary=${button.type == 'primary' && !this.destructive}
|
|
557
555
|
?secondary=${button.type == 'secondary'}
|
|
558
|
-
?submitting=${this.submitting}
|
|
556
|
+
?submitting=${this.submitting && button.type == 'primary'}
|
|
559
557
|
?disabled=${this.disabled && !button.closes}
|
|
560
558
|
index=${index}
|
|
561
559
|
@click=${this.handleClick}
|
package/src/layout/Modax.ts
CHANGED
package/src/list/ContentMenu.ts
CHANGED
|
@@ -39,8 +39,6 @@ export class ContentMenu extends RapidElement {
|
|
|
39
39
|
z-index: 5000;
|
|
40
40
|
}
|
|
41
41
|
.container {
|
|
42
|
-
--button-y: 0.4em;
|
|
43
|
-
--button-x: 1em;
|
|
44
42
|
display: flex;
|
|
45
43
|
align-items: center;
|
|
46
44
|
}
|
|
@@ -52,6 +50,7 @@ export class ContentMenu extends RapidElement {
|
|
|
52
50
|
|
|
53
51
|
temba-button {
|
|
54
52
|
margin-right: 0.5rem;
|
|
53
|
+
align-self: center;
|
|
55
54
|
}
|
|
56
55
|
.toggle {
|
|
57
56
|
--icon-color: rgb(102, 102, 102);
|
package/src/list/SortableList.ts
CHANGED
|
@@ -252,9 +252,165 @@ export class SortableList extends RapidElement {
|
|
|
252
252
|
// Copy form values for the root element and all descendants
|
|
253
253
|
copyFormValues(element, clone);
|
|
254
254
|
|
|
255
|
+
// Inline computed styles onto the clone so it renders faithfully
|
|
256
|
+
// once detached from its original shadow-DOM scope. The ghost is
|
|
257
|
+
// appended to document.body (see startDrag), which means the
|
|
258
|
+
// original's shadow-root-scoped CSS rules no longer apply — chips
|
|
259
|
+
// would lose their flex layout, the X button would lose its shape,
|
|
260
|
+
// and the pill --icon-color would stop inheriting. Walk the cloned
|
|
261
|
+
// light DOM in parallel with the original and inline the layout
|
|
262
|
+
// properties + a curated set of DS custom properties.
|
|
263
|
+
this.inlineComputedStyles(element, clone);
|
|
264
|
+
|
|
255
265
|
return clone;
|
|
256
266
|
}
|
|
257
267
|
|
|
268
|
+
/** CSS properties copied from the original to the ghost. Covers
|
|
269
|
+
* layout (flex/sizing/spacing), visual (colors, borders, radii,
|
|
270
|
+
* shadows), and text (font, white-space, alignment) — enough to
|
|
271
|
+
* make a faithful free-floating clone without resolving the entire
|
|
272
|
+
* ~400 properties getComputedStyle returns.
|
|
273
|
+
*
|
|
274
|
+
* Important: `getComputedStyle` returns LONGHAND values only —
|
|
275
|
+
* asking for shorthand like `padding` / `margin` / `border` returns
|
|
276
|
+
* an empty string in most browsers. We list longhands explicitly so
|
|
277
|
+
* inlined chip padding / borders survive the move to document.body.
|
|
278
|
+
*
|
|
279
|
+
* Width/height ARE included: nested elements that depend on
|
|
280
|
+
* shadow-root class rules for sized boxes (e.g. select's
|
|
281
|
+
* `.remove-item { width: 16px; height: 16px }`) collapse to their
|
|
282
|
+
* content size without it, leaving a stray gap inside the chip. */
|
|
283
|
+
private static GHOST_COPY_PROPS = [
|
|
284
|
+
'display',
|
|
285
|
+
'flex-grow',
|
|
286
|
+
'flex-shrink',
|
|
287
|
+
'flex-basis',
|
|
288
|
+
'flex-direction',
|
|
289
|
+
'flex-wrap',
|
|
290
|
+
'align-items',
|
|
291
|
+
'align-self',
|
|
292
|
+
'justify-content',
|
|
293
|
+
'gap',
|
|
294
|
+
'column-gap',
|
|
295
|
+
'row-gap',
|
|
296
|
+
'padding-top',
|
|
297
|
+
'padding-right',
|
|
298
|
+
'padding-bottom',
|
|
299
|
+
'padding-left',
|
|
300
|
+
'margin-top',
|
|
301
|
+
'margin-right',
|
|
302
|
+
'margin-bottom',
|
|
303
|
+
'margin-left',
|
|
304
|
+
'border-top-width',
|
|
305
|
+
'border-right-width',
|
|
306
|
+
'border-bottom-width',
|
|
307
|
+
'border-left-width',
|
|
308
|
+
'border-top-style',
|
|
309
|
+
'border-right-style',
|
|
310
|
+
'border-bottom-style',
|
|
311
|
+
'border-left-style',
|
|
312
|
+
'border-top-color',
|
|
313
|
+
'border-right-color',
|
|
314
|
+
'border-bottom-color',
|
|
315
|
+
'border-left-color',
|
|
316
|
+
'border-top-left-radius',
|
|
317
|
+
'border-top-right-radius',
|
|
318
|
+
'border-bottom-right-radius',
|
|
319
|
+
'border-bottom-left-radius',
|
|
320
|
+
'background-color',
|
|
321
|
+
'background-image',
|
|
322
|
+
'color',
|
|
323
|
+
'font-family',
|
|
324
|
+
'font-size',
|
|
325
|
+
'font-weight',
|
|
326
|
+
'font-style',
|
|
327
|
+
'line-height',
|
|
328
|
+
'letter-spacing',
|
|
329
|
+
'text-align',
|
|
330
|
+
'white-space',
|
|
331
|
+
'overflow',
|
|
332
|
+
'text-overflow',
|
|
333
|
+
'box-shadow',
|
|
334
|
+
'opacity',
|
|
335
|
+
'width',
|
|
336
|
+
'min-width',
|
|
337
|
+
'max-width',
|
|
338
|
+
'height',
|
|
339
|
+
'min-height',
|
|
340
|
+
'max-height',
|
|
341
|
+
'box-sizing',
|
|
342
|
+
'cursor',
|
|
343
|
+
'user-select',
|
|
344
|
+
'vertical-align'
|
|
345
|
+
];
|
|
346
|
+
|
|
347
|
+
/** Design-system custom properties carried over to the ghost so
|
|
348
|
+
* nested custom elements (temba-icon's --icon-color, pill variants,
|
|
349
|
+
* etc.) read the correct values once detached from the original
|
|
350
|
+
* shadow-root scope. */
|
|
351
|
+
private static GHOST_COPY_CUSTOM_PROPS = [
|
|
352
|
+
'--icon-color',
|
|
353
|
+
'--color-widget-text',
|
|
354
|
+
'--color-text-help',
|
|
355
|
+
'--accent',
|
|
356
|
+
'--accent-100',
|
|
357
|
+
'--accent-200',
|
|
358
|
+
'--accent-700',
|
|
359
|
+
'--flow',
|
|
360
|
+
'--field',
|
|
361
|
+
'--channel',
|
|
362
|
+
'--text-1',
|
|
363
|
+
'--text-2',
|
|
364
|
+
'--sunken',
|
|
365
|
+
'--border',
|
|
366
|
+
'--border-strong',
|
|
367
|
+
'--font-family',
|
|
368
|
+
'--w-regular',
|
|
369
|
+
'--w-medium',
|
|
370
|
+
'--curvature',
|
|
371
|
+
'--curvature-widget'
|
|
372
|
+
];
|
|
373
|
+
|
|
374
|
+
private inlineComputedStyles(original: Element, clone: Element): void {
|
|
375
|
+
if (!(original instanceof HTMLElement) || !(clone instanceof HTMLElement)) {
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const apply = (orig: HTMLElement, cln: HTMLElement) => {
|
|
380
|
+
const cs = window.getComputedStyle(orig);
|
|
381
|
+
let inline = '';
|
|
382
|
+
for (const p of SortableList.GHOST_COPY_PROPS) {
|
|
383
|
+
const v = cs.getPropertyValue(p);
|
|
384
|
+
if (v) inline += `${p}:${v};`;
|
|
385
|
+
}
|
|
386
|
+
for (const p of SortableList.GHOST_COPY_CUSTOM_PROPS) {
|
|
387
|
+
const v = cs.getPropertyValue(p);
|
|
388
|
+
if (v) inline += `${p}:${v};`;
|
|
389
|
+
}
|
|
390
|
+
// existing inline style wins by sitting AFTER the inlined
|
|
391
|
+
// computed values — preserves anything we just authored elsewhere
|
|
392
|
+
// (e.g. .option-name's explicit display:flex).
|
|
393
|
+
cln.setAttribute('style', inline + (cln.getAttribute('style') || ''));
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
const walk = (orig: Element, cln: Element) => {
|
|
397
|
+
if (orig instanceof HTMLElement && cln instanceof HTMLElement) {
|
|
398
|
+
apply(orig, cln);
|
|
399
|
+
}
|
|
400
|
+
// Descend into both light-DOM and custom-element subtrees: the
|
|
401
|
+
// latter's slotted/light children still need styles inlined, and
|
|
402
|
+
// its own shadow DOM rebuilds itself when the clone upgrades.
|
|
403
|
+
const oc = Array.from(orig.children);
|
|
404
|
+
const cc = Array.from(cln.children);
|
|
405
|
+
const n = Math.min(oc.length, cc.length);
|
|
406
|
+
for (let i = 0; i < n; i++) {
|
|
407
|
+
walk(oc[i], cc[i]);
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
walk(original, clone);
|
|
412
|
+
}
|
|
413
|
+
|
|
258
414
|
public getIds() {
|
|
259
415
|
return this.getSortableElements().map((ele) => ele.id);
|
|
260
416
|
}
|