@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
|
@@ -1,16 +1,20 @@
|
|
|
1
|
-
import { FormData, NodeConfig, ACTION_GROUPS,
|
|
1
|
+
import { FormData, NodeConfig, ACTION_GROUPS, FlowTypes } from '../types';
|
|
2
2
|
import { CallLLM, Node } from '../../store/flow-definition';
|
|
3
3
|
import { generateUUID, createMultiCategoryRouter } from '../../utils';
|
|
4
4
|
import { html } from 'lit';
|
|
5
5
|
import { validateWith } from '../utils';
|
|
6
6
|
import { LLMModel, hasLLMRole } from '../flow-utils';
|
|
7
|
+
import {
|
|
8
|
+
resultNameField,
|
|
9
|
+
localizeCategoriesField,
|
|
10
|
+
nodeOptionsAccordionCategoriesOnly
|
|
11
|
+
} from './shared';
|
|
7
12
|
|
|
8
13
|
export const split_by_llm_categorize: NodeConfig = {
|
|
9
14
|
type: 'split_by_llm_categorize',
|
|
10
15
|
name: 'Split by AI',
|
|
11
16
|
group: ACTION_GROUPS.services,
|
|
12
|
-
flowTypes: [],
|
|
13
|
-
features: [Features.AI],
|
|
17
|
+
flowTypes: [FlowTypes.VOICE, FlowTypes.MESSAGE, FlowTypes.BACKGROUND],
|
|
14
18
|
form: {
|
|
15
19
|
llm: {
|
|
16
20
|
type: 'select',
|
|
@@ -49,9 +53,11 @@ export const split_by_llm_categorize: NodeConfig = {
|
|
|
49
53
|
required: true
|
|
50
54
|
}
|
|
51
55
|
}
|
|
52
|
-
}
|
|
56
|
+
},
|
|
57
|
+
result_name: resultNameField,
|
|
58
|
+
localizeCategories: localizeCategoriesField
|
|
53
59
|
},
|
|
54
|
-
layout: ['llm', 'input', 'categories'],
|
|
60
|
+
layout: ['llm', 'input', 'categories', nodeOptionsAccordionCategoriesOnly],
|
|
55
61
|
validate: validateWith((formData, errors) => {
|
|
56
62
|
if (!formData.categories || !Array.isArray(formData.categories)) return;
|
|
57
63
|
|
|
@@ -91,7 +97,7 @@ export const split_by_llm_categorize: NodeConfig = {
|
|
|
91
97
|
<div class="body">Categorize with ${callLlmAction.llm.name}</div>
|
|
92
98
|
`;
|
|
93
99
|
},
|
|
94
|
-
toFormData: (node: Node) => {
|
|
100
|
+
toFormData: (node: Node, nodeUI?: any) => {
|
|
95
101
|
// Extract data from the existing node structure
|
|
96
102
|
const callLlmAction = node.actions?.find(
|
|
97
103
|
(action) => action.type === 'call_llm'
|
|
@@ -105,9 +111,18 @@ export const split_by_llm_categorize: NodeConfig = {
|
|
|
105
111
|
uuid: node.uuid,
|
|
106
112
|
llm: callLlmAction?.llm ? [callLlmAction.llm] : [],
|
|
107
113
|
input: callLlmAction?.input || '@input',
|
|
108
|
-
categories: categories
|
|
114
|
+
categories: categories,
|
|
115
|
+
result_name: node.router?.result_name || '',
|
|
116
|
+
localizeCategories: nodeUI?.config?.localizeCategories || false
|
|
109
117
|
};
|
|
110
118
|
},
|
|
119
|
+
toUIConfig: (formData: FormData) => {
|
|
120
|
+
const config: Record<string, any> = {};
|
|
121
|
+
config.localizeCategories = formData.result_name
|
|
122
|
+
? !!formData.localizeCategories
|
|
123
|
+
: false;
|
|
124
|
+
return config;
|
|
125
|
+
},
|
|
111
126
|
fromFormData: (formData: FormData, originalNode: Node): Node => {
|
|
112
127
|
// Get LLM selection
|
|
113
128
|
const llmSelection =
|
|
@@ -158,11 +173,16 @@ export const split_by_llm_categorize: NodeConfig = {
|
|
|
158
173
|
existingCases
|
|
159
174
|
);
|
|
160
175
|
|
|
176
|
+
const finalRouter: any = { ...router };
|
|
177
|
+
if (formData.result_name && formData.result_name.trim() !== '') {
|
|
178
|
+
finalRouter.result_name = formData.result_name.trim();
|
|
179
|
+
}
|
|
180
|
+
|
|
161
181
|
// Return the complete node
|
|
162
182
|
return {
|
|
163
183
|
uuid: originalNode.uuid,
|
|
164
184
|
actions: [callLlmAction],
|
|
165
|
-
router:
|
|
185
|
+
router: finalRouter,
|
|
166
186
|
exits: exits
|
|
167
187
|
};
|
|
168
188
|
},
|
package/src/flow/utils.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { html, TemplateResult } from 'lit-html';
|
|
2
|
+
import { iconToPillType } from '../styles/pillVariants';
|
|
2
3
|
import { Action, NamedObject, FlowPosition } from '../store/flow-definition';
|
|
3
|
-
import { FlowIssue
|
|
4
|
+
import { FlowIssue } from '../store/AppState';
|
|
4
5
|
import { CustomEventType } from '../interfaces';
|
|
5
6
|
import { tokenize, TokenType } from '../excellent/tokenizer';
|
|
6
7
|
import { TOKEN_COLORS } from '../excellent/token-styles';
|
|
@@ -106,25 +107,6 @@ export function resolveFromLocalizationFormData(
|
|
|
106
107
|
return undefined;
|
|
107
108
|
}
|
|
108
109
|
|
|
109
|
-
const intlLanguageNames = new Intl.DisplayNames(['en'], { type: 'language' });
|
|
110
|
-
|
|
111
|
-
export function getLanguageDisplayName(code: string): string {
|
|
112
|
-
if (code === 'und') return 'Unknown';
|
|
113
|
-
|
|
114
|
-
// Prefer names from the RapidPro languages endpoint, which supplies
|
|
115
|
-
// ISO 639-3 codes (e.g. prd, pst) that Intl.DisplayNames doesn't cover.
|
|
116
|
-
const storeName = zustand.getState().languageNames?.[code];
|
|
117
|
-
if (storeName) {
|
|
118
|
-
return storeName;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
try {
|
|
122
|
-
return intlLanguageNames.of(code) || code;
|
|
123
|
-
} catch {
|
|
124
|
-
return code;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
110
|
const IS_MAC =
|
|
129
111
|
typeof navigator !== 'undefined' &&
|
|
130
112
|
/Mac|iPod|iPhone|iPad/.test(navigator.platform);
|
|
@@ -256,6 +238,15 @@ export const renderClamped = (
|
|
|
256
238
|
</div>`;
|
|
257
239
|
};
|
|
258
240
|
|
|
241
|
+
/**
|
|
242
|
+
* Inline margin for stacked pills — the previous implementation used
|
|
243
|
+
* `class="mr-1 mb-1"` (Tailwind utility classes), but this package
|
|
244
|
+
* doesn't ship Tailwind, so the classes resolved to no-ops in any host
|
|
245
|
+
* page that didn't already include it. Inline style is predictable
|
|
246
|
+
* across hosts.
|
|
247
|
+
*/
|
|
248
|
+
const PILL_MARGIN_STYLE = 'margin: 0 4px 4px 0;';
|
|
249
|
+
|
|
259
250
|
/**
|
|
260
251
|
* Renders a single line item with optional icon.
|
|
261
252
|
* Content can be plain text or a TemplateResult (e.g. highlighted text).
|
|
@@ -265,17 +256,14 @@ export const renderLineItem = (
|
|
|
265
256
|
icon?: string,
|
|
266
257
|
content?: TemplateResult
|
|
267
258
|
) => {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
${content || name}
|
|
277
|
-
</div>
|
|
278
|
-
</div>`;
|
|
259
|
+
const pillType = iconToPillType(icon);
|
|
260
|
+
return html`<temba-label
|
|
261
|
+
icon=${icon || ''}
|
|
262
|
+
type=${pillType || 'neutral'}
|
|
263
|
+
style=${PILL_MARGIN_STYLE}
|
|
264
|
+
title="${name}"
|
|
265
|
+
>${content || name}</temba-label
|
|
266
|
+
>`;
|
|
279
267
|
};
|
|
280
268
|
|
|
281
269
|
/**
|
|
@@ -319,12 +307,9 @@ export const renderStringList = (
|
|
|
319
307
|
if (items.length > maxDisplay && items.length !== 4) {
|
|
320
308
|
const remainingCount = items.length - maxDisplay;
|
|
321
309
|
itemElements.push(
|
|
322
|
-
html`<
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
: null}
|
|
326
|
-
<div style="font-size:0.8em">+${remainingCount} more</div>
|
|
327
|
-
</div>`
|
|
310
|
+
html`<temba-label type="neutral" style=${PILL_MARGIN_STYLE}
|
|
311
|
+
>+${remainingCount} more</temba-label
|
|
312
|
+
>`
|
|
328
313
|
);
|
|
329
314
|
}
|
|
330
315
|
return itemElements;
|
|
@@ -368,17 +353,16 @@ export const renderMixedList = (items: MixedListItem[]) => {
|
|
|
368
353
|
if (items.length > maxDisplay && items.length !== 4) {
|
|
369
354
|
const remainingCount = items.length - maxDisplay;
|
|
370
355
|
itemElements.push(
|
|
371
|
-
html`<
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
</div>`
|
|
356
|
+
html`<temba-label type="neutral" style=${PILL_MARGIN_STYLE}
|
|
357
|
+
>+${remainingCount} more</temba-label
|
|
358
|
+
>`
|
|
375
359
|
);
|
|
376
360
|
}
|
|
377
361
|
return itemElements;
|
|
378
362
|
};
|
|
379
363
|
|
|
380
364
|
/**
|
|
381
|
-
* Renders a named object as a clickable
|
|
365
|
+
* Renders a named object as a clickable DS pill that fires a custom event
|
|
382
366
|
*/
|
|
383
367
|
const renderLinkedObject = (
|
|
384
368
|
obj: NamedObject,
|
|
@@ -400,18 +384,16 @@ const renderLinkedObject = (
|
|
|
400
384
|
}
|
|
401
385
|
};
|
|
402
386
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
</div>
|
|
414
|
-
</div>`;
|
|
387
|
+
const pillType = iconToPillType(icon);
|
|
388
|
+
return html`<temba-label
|
|
389
|
+
icon=${icon || ''}
|
|
390
|
+
type=${pillType || 'neutral'}
|
|
391
|
+
clickable
|
|
392
|
+
style=${PILL_MARGIN_STYLE}
|
|
393
|
+
title="${obj.name}"
|
|
394
|
+
@click=${handleClick}
|
|
395
|
+
>${obj.name}</temba-label
|
|
396
|
+
>`;
|
|
415
397
|
};
|
|
416
398
|
|
|
417
399
|
/**
|
|
@@ -436,12 +418,9 @@ const renderLinkedObjects = (
|
|
|
436
418
|
if (objects.length > maxDisplay && objects.length !== 4) {
|
|
437
419
|
const remainingCount = objects.length - maxDisplay;
|
|
438
420
|
itemElements.push(
|
|
439
|
-
html`<
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
: null}
|
|
443
|
-
<div style="font-size:0.8em">+${remainingCount} more</div>
|
|
444
|
-
</div>`
|
|
421
|
+
html`<temba-label type="neutral" style=${PILL_MARGIN_STYLE}
|
|
422
|
+
>+${remainingCount} more</temba-label
|
|
423
|
+
>`
|
|
445
424
|
);
|
|
446
425
|
}
|
|
447
426
|
return itemElements;
|
package/src/form/ArrayEditor.ts
CHANGED
|
@@ -604,12 +604,11 @@ export class TembaArrayEditor extends BaseListEditor<ListItem> {
|
|
|
604
604
|
class="remove-btn"
|
|
605
605
|
style="
|
|
606
606
|
padding: 4px;
|
|
607
|
-
border: 1px solid
|
|
608
|
-
border-radius:
|
|
609
|
-
background:
|
|
607
|
+
border: 1px solid var(--color-widget-border);
|
|
608
|
+
border-radius: var(--curvature-widget);
|
|
609
|
+
background: var(--surface);
|
|
610
610
|
cursor: pointer;
|
|
611
|
-
|
|
612
|
-
color: #999;
|
|
611
|
+
color: var(--text-3);
|
|
613
612
|
font-size: 14px;
|
|
614
613
|
"
|
|
615
614
|
?disabled=${!canRemove}
|
|
@@ -651,21 +650,20 @@ export class TembaArrayEditor extends BaseListEditor<ListItem> {
|
|
|
651
650
|
.add-btn,
|
|
652
651
|
.remove-btn {
|
|
653
652
|
padding: 4px;
|
|
654
|
-
border: 1px solid
|
|
655
|
-
border-radius:
|
|
656
|
-
background:
|
|
653
|
+
border: 1px solid var(--color-widget-border);
|
|
654
|
+
border-radius: var(--curvature-widget);
|
|
655
|
+
background: var(--surface);
|
|
657
656
|
cursor: pointer;
|
|
658
657
|
font-size: 14px;
|
|
659
658
|
}
|
|
660
659
|
|
|
661
660
|
.add-btn:hover,
|
|
662
661
|
.remove-btn:hover {
|
|
663
|
-
background:
|
|
662
|
+
background: var(--sunken);
|
|
664
663
|
}
|
|
665
664
|
|
|
666
665
|
.remove-btn {
|
|
667
|
-
|
|
668
|
-
color: #999;
|
|
666
|
+
color: var(--text-3);
|
|
669
667
|
}
|
|
670
668
|
|
|
671
669
|
.removable .remove-btn {
|
package/src/form/Checkbox.ts
CHANGED
|
@@ -25,7 +25,7 @@ export class Checkbox extends FieldElement {
|
|
|
25
25
|
width: 12px;
|
|
26
26
|
height: 12px;
|
|
27
27
|
background: var(--checkbox-background, rgba(255, 255, 255, 0.8));
|
|
28
|
-
border-radius:
|
|
28
|
+
border-radius: var(--r-xs);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
.wrapper.label {
|
|
@@ -34,7 +34,7 @@ export class Checkbox extends FieldElement {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
.wrapper.label:hover {
|
|
37
|
-
background: var(--checkbox-hover-bg,
|
|
37
|
+
background: var(--checkbox-hover-bg, var(--sunken));
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
.checkbox-container {
|
package/src/form/ColorPicker.ts
CHANGED
|
@@ -29,7 +29,6 @@ export class ColorPicker extends FieldElement {
|
|
|
29
29
|
:host {
|
|
30
30
|
color: var(--color-text);
|
|
31
31
|
display: inline-block;
|
|
32
|
-
--curvature: 0.55em;
|
|
33
32
|
width: 100%;
|
|
34
33
|
|
|
35
34
|
--temba-textinput-padding: 0.4em;
|
|
@@ -37,13 +36,16 @@ export class ColorPicker extends FieldElement {
|
|
|
37
36
|
|
|
38
37
|
temba-textinput {
|
|
39
38
|
margin-left: 0.3em;
|
|
40
|
-
width:
|
|
39
|
+
width: 7em;
|
|
40
|
+
--temba-textinput-min-height: 0;
|
|
41
|
+
--temba-textinput-padding: 4px 8px;
|
|
42
|
+
--temba-textinput-font-size: 12.5px;
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
.wrapper {
|
|
44
46
|
border: 1px solid var(--color-widget-border);
|
|
45
47
|
padding: calc(var(--curvature) / 2);
|
|
46
|
-
border-radius:
|
|
48
|
+
border-radius: var(--curvature);
|
|
47
49
|
transition: all calc(var(--transition-speed) * 2) var(--bounce);
|
|
48
50
|
|
|
49
51
|
display: flex;
|
package/src/form/Compose.ts
CHANGED
|
@@ -104,7 +104,7 @@ export class Compose extends FieldElement {
|
|
|
104
104
|
--curvature-widget: 0px;
|
|
105
105
|
--color-options-bg: #fff;
|
|
106
106
|
border: 1px solid var(--color-widget-border);
|
|
107
|
-
border-radius:
|
|
107
|
+
border-radius: var(--curvature-widget);
|
|
108
108
|
background: var(--color-widget-bg, #fff);
|
|
109
109
|
box-shadow: var(--options-shadow);
|
|
110
110
|
z-index: 1000003;
|
package/src/form/FieldElement.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { TemplateResult, html, css } from 'lit';
|
|
|
2
2
|
import { property } from 'lit/decorators.js';
|
|
3
3
|
import { RapidElement } from '../RapidElement';
|
|
4
4
|
import { renderMarkdownInline } from '../markdown';
|
|
5
|
+
import { designTokens } from '../styles/designTokens';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* FieldElement is a base class for form components that provides built-in
|
|
@@ -62,26 +63,25 @@ export abstract class FieldElement extends RapidElement {
|
|
|
62
63
|
|
|
63
64
|
static get styles() {
|
|
64
65
|
return css`
|
|
66
|
+
${designTokens}
|
|
67
|
+
|
|
65
68
|
:host {
|
|
66
69
|
font-family: var(--font-family);
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
label {
|
|
70
|
-
margin-bottom:
|
|
71
|
-
margin-left: 4px;
|
|
73
|
+
margin-bottom: 6px;
|
|
72
74
|
display: block;
|
|
73
|
-
font-weight:
|
|
74
|
-
font-size:
|
|
75
|
-
letter-spacing: 0.05em;
|
|
75
|
+
font-weight: var(--w-medium);
|
|
76
|
+
font-size: 12.5px;
|
|
76
77
|
line-height: normal;
|
|
77
|
-
color: var(--color-label
|
|
78
|
+
color: var(--color-label);
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
.help-text {
|
|
81
|
-
font-size:
|
|
82
|
+
font-size: 12px;
|
|
82
83
|
line-height: normal;
|
|
83
84
|
color: var(--color-text-help);
|
|
84
|
-
margin-left: var(--help-text-margin-left);
|
|
85
85
|
margin-top: 6px;
|
|
86
86
|
opacity: 1;
|
|
87
87
|
}
|
|
@@ -282,10 +282,10 @@ export class KeyValueEditor extends BaseListEditor<KeyValueItem> {
|
|
|
282
282
|
.remove-btn {
|
|
283
283
|
width: 32px;
|
|
284
284
|
height: 32px;
|
|
285
|
-
border: 1px solid
|
|
286
|
-
border-radius:
|
|
287
|
-
background:
|
|
288
|
-
color:
|
|
285
|
+
border: 1px solid var(--color-widget-border);
|
|
286
|
+
border-radius: var(--curvature-widget);
|
|
287
|
+
background: var(--sunken);
|
|
288
|
+
color: var(--text-2);
|
|
289
289
|
cursor: pointer;
|
|
290
290
|
display: flex;
|
|
291
291
|
align-items: center;
|
|
@@ -23,7 +23,7 @@ export class MessageEditor extends FieldElement {
|
|
|
23
23
|
.message-editor-container {
|
|
24
24
|
border: 1px solid var(--color-widget-border);
|
|
25
25
|
border-radius: var(--curvature-widget);
|
|
26
|
-
background:
|
|
26
|
+
background: var(--surface);
|
|
27
27
|
position: relative;
|
|
28
28
|
transition:
|
|
29
29
|
border-color 0.2s ease-in-out,
|
|
@@ -75,10 +75,9 @@ export class MessageEditor extends FieldElement {
|
|
|
75
75
|
|
|
76
76
|
.media-wrapper {
|
|
77
77
|
padding: 4px 8px;
|
|
78
|
-
background:
|
|
78
|
+
background: var(--sunken);
|
|
79
79
|
border-top: 1px solid var(--color-widget-border);
|
|
80
80
|
border-radius: 0 0 var(--curvature-widget) var(--curvature-widget);
|
|
81
|
-
box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.05);
|
|
82
81
|
margin-top: 3px;
|
|
83
82
|
display: none;
|
|
84
83
|
}
|
package/src/form/RangePicker.ts
CHANGED
|
@@ -16,21 +16,21 @@ export class RangePicker extends RapidElement {
|
|
|
16
16
|
cursor: pointer;
|
|
17
17
|
padding: 0.2em 0.5em;
|
|
18
18
|
margin: 0.6em 0;
|
|
19
|
-
border-radius:
|
|
19
|
+
border-radius: var(--curvature-widget);
|
|
20
20
|
border: 1px solid transparent;
|
|
21
21
|
transition: border 0.2s;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
.date-display:hover {
|
|
25
|
-
border: 1px solid var(--color-widget-border
|
|
26
|
-
background: var(--
|
|
25
|
+
border: 1px solid var(--color-widget-border);
|
|
26
|
+
background: var(--sunken);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
input[type='date'] {
|
|
30
30
|
font-size: 1em;
|
|
31
31
|
padding: 0.2em 0.5em;
|
|
32
|
-
border-radius:
|
|
33
|
-
border: 1px solid
|
|
32
|
+
border-radius: var(--curvature-widget);
|
|
33
|
+
border: 1px solid var(--color-widget-border);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
.navigation-container {
|
|
@@ -40,10 +40,10 @@ export class RangePicker extends RapidElement {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
.nav-arrow {
|
|
43
|
-
background:
|
|
44
|
-
border: 1px solid
|
|
43
|
+
background: var(--sunken);
|
|
44
|
+
border: 1px solid var(--color-widget-border);
|
|
45
45
|
|
|
46
|
-
border-radius: var(--curvature);
|
|
46
|
+
border-radius: var(--curvature-widget);
|
|
47
47
|
padding: 0em 0em;
|
|
48
48
|
cursor: pointer;
|
|
49
49
|
font-size: 0.6em;
|
|
@@ -59,14 +59,14 @@ export class RangePicker extends RapidElement {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
.nav-arrow:hover:not(:disabled) {
|
|
62
|
-
background:
|
|
63
|
-
border-color:
|
|
62
|
+
background: var(--accent-50);
|
|
63
|
+
border-color: var(--accent);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
.nav-arrow:disabled {
|
|
67
67
|
opacity: 0.5;
|
|
68
68
|
cursor: not-allowed;
|
|
69
|
-
background:
|
|
69
|
+
background: var(--sunken);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
.nav-arrow.hidden {
|
|
@@ -78,8 +78,8 @@ export class RangePicker extends RapidElement {
|
|
|
78
78
|
margin-left: 0em;
|
|
79
79
|
}
|
|
80
80
|
.range-btn {
|
|
81
|
-
background:
|
|
82
|
-
border: 1px solid
|
|
81
|
+
background: var(--sunken);
|
|
82
|
+
border: 1px solid var(--color-widget-border);
|
|
83
83
|
border-radius: 0px;
|
|
84
84
|
margin-left: -1px;
|
|
85
85
|
padding: 0.2em 0.8em;
|
|
@@ -91,17 +91,17 @@ export class RangePicker extends RapidElement {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
.button-group .range-btn:first-child {
|
|
94
|
-
border-radius:
|
|
94
|
+
border-radius: var(--curvature-widget) 0 0 var(--curvature-widget);
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
.button-group .range-btn:last-child {
|
|
98
|
-
border-radius: 0
|
|
98
|
+
border-radius: 0 var(--curvature-widget) var(--curvature-widget) 0;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
.range-btn.selected,
|
|
102
102
|
.range-btn:active {
|
|
103
|
-
background:
|
|
104
|
-
border-color:
|
|
103
|
+
background: var(--accent-50);
|
|
104
|
+
border-color: var(--accent);
|
|
105
105
|
}
|
|
106
106
|
`;
|
|
107
107
|
|
package/src/form/TembaSlider.ts
CHANGED
|
@@ -13,9 +13,9 @@ export class TembaSlider extends FieldElement {
|
|
|
13
13
|
|
|
14
14
|
.track {
|
|
15
15
|
height: 2px;
|
|
16
|
-
border-top: 0.5em solid
|
|
17
|
-
border-bottom: 0.5em solid
|
|
18
|
-
background:
|
|
16
|
+
border-top: 0.5em solid var(--surface);
|
|
17
|
+
border-bottom: 0.5em solid var(--surface);
|
|
18
|
+
background: var(--border-strong);
|
|
19
19
|
flex-grow: 1;
|
|
20
20
|
}
|
|
21
21
|
|
|
@@ -24,11 +24,11 @@ export class TembaSlider extends FieldElement {
|
|
|
24
24
|
margin-left: -0.5em;
|
|
25
25
|
width: 0.75em;
|
|
26
26
|
height: 0.75em;
|
|
27
|
-
border: 2px solid
|
|
27
|
+
border: 2px solid var(--border-strong);
|
|
28
28
|
border-radius: 999px;
|
|
29
29
|
position: relative;
|
|
30
|
-
background:
|
|
31
|
-
box-shadow: 0 0 0 4px
|
|
30
|
+
background: var(--surface);
|
|
31
|
+
box-shadow: 0 0 0 4px var(--surface);
|
|
32
32
|
transition: transform 200ms ease-in-out;
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -37,13 +37,13 @@ export class TembaSlider extends FieldElement {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
:hover .circle {
|
|
40
|
-
border-color:
|
|
40
|
+
border-color: var(--text-2);
|
|
41
41
|
cursor: pointer;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
.grabbed .circle {
|
|
45
|
-
border-color: var(--
|
|
46
|
-
background:
|
|
45
|
+
border-color: var(--accent);
|
|
46
|
+
background: var(--surface);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
.grabbed .circle {
|
|
@@ -58,7 +58,7 @@ export class TembaSlider extends FieldElement {
|
|
|
58
58
|
.pre,
|
|
59
59
|
.post {
|
|
60
60
|
font-size: 0.9em;
|
|
61
|
-
color:
|
|
61
|
+
color: var(--text-3);
|
|
62
62
|
padding: 0em 1em;
|
|
63
63
|
}
|
|
64
64
|
`;
|
|
@@ -99,9 +99,9 @@ export class TemplateEditor extends FieldElement {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
.button {
|
|
102
|
-
background:
|
|
102
|
+
background: var(--surface);
|
|
103
103
|
padding: 0.3em 1em;
|
|
104
|
-
border: 1px solid
|
|
104
|
+
border: 1px solid var(--color-widget-border);
|
|
105
105
|
border-radius: var(--curvature);
|
|
106
106
|
min-height: 23px;
|
|
107
107
|
display: flex;
|
|
@@ -118,7 +118,7 @@ export class TemplateEditor extends FieldElement {
|
|
|
118
118
|
|
|
119
119
|
.button .display {
|
|
120
120
|
margin-right: 0.5em;
|
|
121
|
-
background:
|
|
121
|
+
background: var(--sunken);
|
|
122
122
|
padding: 0.25em 1em;
|
|
123
123
|
border-radius: var(--curvature);
|
|
124
124
|
}
|
|
@@ -130,7 +130,7 @@ export class TemplateEditor extends FieldElement {
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
.template {
|
|
133
|
-
background:
|
|
133
|
+
background: var(--surface);
|
|
134
134
|
border-radius: var(--curvature);
|
|
135
135
|
border: 1px solid var(--color-widget-border);
|
|
136
136
|
padding: 1em;
|
package/src/form/TextInput.ts
CHANGED
|
@@ -26,13 +26,32 @@ export class TextInput extends FieldElement {
|
|
|
26
26
|
display: flex;
|
|
27
27
|
flex-direction: row;
|
|
28
28
|
align-items: stretch;
|
|
29
|
+
min-height: var(--temba-textinput-min-height, var(--input-h));
|
|
29
30
|
box-shadow: var(--widget-box-shadow);
|
|
30
31
|
caret-color: var(--input-caret);
|
|
32
|
+
/* Establish a stable containing block for slotted absolutely-
|
|
33
|
+
positioned children (e.g. ContactFieldEditor's embedded
|
|
34
|
+
prefix label). Setting position: relative only on
|
|
35
|
+
:focus-within would re-anchor the prefix when focused,
|
|
36
|
+
visually shifting the label. */
|
|
37
|
+
position: relative;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.input-container.textarea,
|
|
41
|
+
.input-container:has(textarea) {
|
|
42
|
+
min-height: 0;
|
|
31
43
|
}
|
|
32
44
|
|
|
33
45
|
.xsmall {
|
|
34
46
|
--temba-textinput-padding: 6px 8px;
|
|
35
47
|
--temba-textinput-font-size: 13px;
|
|
48
|
+
/* Opt out of the 34px --input-h floor so an xsmall textinput
|
|
49
|
+
lines up with RichEditor xsmall (the "evaluated" argument
|
|
50
|
+
input in rule editor rows) and with Select xsmall, neither
|
|
51
|
+
of which carry the floor. Without this, a [operator select
|
|
52
|
+
| rich-edit argument | textinput category] row renders the
|
|
53
|
+
category ~4px taller than its neighbors. */
|
|
54
|
+
--temba-textinput-min-height: 0;
|
|
36
55
|
}
|
|
37
56
|
|
|
38
57
|
.small {
|
|
@@ -66,7 +85,6 @@ export class TextInput extends FieldElement {
|
|
|
66
85
|
border-color: var(--color-focus);
|
|
67
86
|
background: var(--color-widget-bg-focused);
|
|
68
87
|
box-shadow: var(--widget-box-shadow-focused);
|
|
69
|
-
position: relative;
|
|
70
88
|
}
|
|
71
89
|
|
|
72
90
|
.input-container:hover {
|