@kubex/zinc 1.0.19 → 1.0.21
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/dist/custom-elements.json +470 -13
- package/dist/vscode.html-custom-data.json +57 -1
- package/dist/web-types.json +122 -4
- package/dist/zn.d.ts +100 -5
- package/dist/zn.min.js +433 -375
- package/docs/pages/components/input-group.md +61 -0
- package/docs/pages/components/translations.md +53 -0
- package/package.json +1 -1
- package/src/components/audio-select/audio-select.component.ts +37 -34
- package/src/components/checkbox/checkbox.component.ts +12 -1
- package/src/components/data-table/data-table.component.ts +7 -0
- package/src/components/inline-edit/inline-edit.component.ts +4 -1
- package/src/components/input-group/index.ts +12 -0
- package/src/components/input-group/input-group.component.ts +73 -0
- package/src/components/input-group/input-group.scss +65 -0
- package/src/components/input-group/input-group.test.ts +98 -0
- package/src/components/item/item.component.ts +5 -1
- package/src/components/item/item.scss +4 -0
- package/src/components/navbar/navbar.component.ts +40 -8
- package/src/components/navbar/navbar.scss +17 -1
- package/src/components/tabs/tabs.component.ts +33 -24
- package/src/components/translations/index.ts +6 -0
- package/src/components/translations/translations.component.ts +239 -0
- package/src/components/translations/translations.scss +15 -0
- package/src/components/translations/translations.test.ts +39 -0
- package/src/events/zn-select.ts +1 -1
- package/src/zinc.ts +2 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {classMap} from "lit/directives/class-map.js";
|
|
2
2
|
import {type CSSResultGroup, html, type PropertyValues, unsafeCSS} from 'lit';
|
|
3
|
+
import {ifDefined} from "lit/directives/if-defined.js";
|
|
3
4
|
import {property} from 'lit/decorators.js';
|
|
4
5
|
import ZincElement from '../../internal/zinc-element';
|
|
5
6
|
import ZnDropdown from "../dropdown";
|
|
@@ -40,6 +41,8 @@ export default class ZnNavbar extends ZincElement {
|
|
|
40
41
|
@property({type: Boolean}) stacked: boolean;
|
|
41
42
|
@property({type: Array}) dropdown = [];
|
|
42
43
|
@property({attribute: "no-pad", type: Boolean}) noPad: false
|
|
44
|
+
@property({attribute: 'manual-add-items', type: Boolean}) manualAddItems = false;
|
|
45
|
+
@property({type: Boolean}) isolated = false;
|
|
43
46
|
|
|
44
47
|
private _preItems: NodeListOf<Element>;
|
|
45
48
|
private _postItems: NodeListOf<Element>;
|
|
@@ -126,16 +129,21 @@ export default class ZnNavbar extends ZincElement {
|
|
|
126
129
|
this._navItems?.classList.toggle('has-hidden', hasHidden && hideRemaining)
|
|
127
130
|
}
|
|
128
131
|
|
|
129
|
-
public addItem(item:
|
|
130
|
-
|
|
132
|
+
public addItem(item: Element): void {
|
|
133
|
+
const tabUri = item.getAttribute('tab-uri');
|
|
134
|
+
if (typeof tabUri !== 'string' || this._openedTabs.includes(tabUri)) {
|
|
131
135
|
return;
|
|
132
136
|
}
|
|
133
|
-
this._openedTabs.push(
|
|
137
|
+
this._openedTabs.push(tabUri);
|
|
134
138
|
const ul = this.shadowRoot?.querySelector('ul');
|
|
135
139
|
const dropdown = this.shadowRoot?.querySelector('[id="dropdown-item"]');
|
|
136
140
|
// @ts-expect-error
|
|
137
141
|
dropdown.querySelector('zn-dropdown').hide();
|
|
138
|
-
|
|
142
|
+
if (dropdown) {
|
|
143
|
+
ul?.insertBefore(item, dropdown);
|
|
144
|
+
} else {
|
|
145
|
+
ul?.appendChild(item);
|
|
146
|
+
}
|
|
139
147
|
}
|
|
140
148
|
|
|
141
149
|
protected firstUpdated(_changedProperties: PropertyValues) {
|
|
@@ -166,6 +174,9 @@ export default class ZnNavbar extends ZincElement {
|
|
|
166
174
|
const menu = this.shadowRoot?.querySelector('zn-menu');
|
|
167
175
|
if (menu) {
|
|
168
176
|
menu.addEventListener('zn-menu-select', (e: ZnMenuSelectEvent) => {
|
|
177
|
+
if (this.manualAddItems) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
169
180
|
const element = e.detail.element;
|
|
170
181
|
if (element.hasAttribute('data-path')) {
|
|
171
182
|
const li = document.createElement('li');
|
|
@@ -185,6 +196,17 @@ export default class ZnNavbar extends ZincElement {
|
|
|
185
196
|
//console.log("Showing More")
|
|
186
197
|
}
|
|
187
198
|
|
|
199
|
+
private handleClick = (e: MouseEvent) => {
|
|
200
|
+
const path = e.composedPath();
|
|
201
|
+
const tabAttr = this.isolated ? 'data-tab' : 'tab';
|
|
202
|
+
const li = path.find(el => el instanceof HTMLElement && el.tagName === 'LI' && (el.hasAttribute(tabAttr) || el.hasAttribute('tab-uri'))) as HTMLElement;
|
|
203
|
+
|
|
204
|
+
if (li) {
|
|
205
|
+
e.stopPropagation();
|
|
206
|
+
this.emit('zn-select', {detail: {item: li}});
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
|
|
188
210
|
render() {
|
|
189
211
|
if (!this.navigation) {
|
|
190
212
|
this.navigation = [];
|
|
@@ -197,13 +219,19 @@ export default class ZnNavbar extends ZincElement {
|
|
|
197
219
|
}
|
|
198
220
|
|
|
199
221
|
return html`
|
|
200
|
-
<div class="
|
|
201
|
-
|
|
222
|
+
<div class="${classMap({
|
|
223
|
+
'navbar__container': true,
|
|
224
|
+
'navbar__container--stacked': this.stacked,
|
|
225
|
+
'navbar__container--icon-bar': this.iconBar
|
|
226
|
+
})}">
|
|
227
|
+
<ul @click="${this.handleClick}" class="${classMap({
|
|
202
228
|
'navbar': true,
|
|
203
229
|
'navbar--slim': this.slim,
|
|
204
230
|
'navbar--border': this.border,
|
|
205
231
|
'navbar--flush': this.flush,
|
|
206
|
-
'navbar--no-pad': this.noPad
|
|
232
|
+
'navbar--no-pad': this.noPad,
|
|
233
|
+
'navbar--stacked': this.stacked,
|
|
234
|
+
'navbar--icon-bar': this.iconBar
|
|
207
235
|
})}">
|
|
208
236
|
${this._preItems}
|
|
209
237
|
${this.navigation.map((item: any) => {
|
|
@@ -217,7 +245,11 @@ export default class ZnNavbar extends ZincElement {
|
|
|
217
245
|
<li class="${classMap({'active': item.active})}" tab-uri="${item.path}">${content}</li>`;
|
|
218
246
|
}
|
|
219
247
|
return html`
|
|
220
|
-
<li class="${classMap({'active': item.active})}"
|
|
248
|
+
<li class="${classMap({'active': item.active})}"
|
|
249
|
+
tab="${ifDefined(!this.isolated ? item.tab : undefined)}"
|
|
250
|
+
data-tab="${ifDefined(this.isolated ? item.tab : undefined)}">
|
|
251
|
+
${content}
|
|
252
|
+
</li>`;
|
|
221
253
|
})}
|
|
222
254
|
<li class="more">
|
|
223
255
|
<zn-dropdown placement="bottom-end" id="extended-dropdown">
|
|
@@ -146,6 +146,22 @@ ul.navbar {
|
|
|
146
146
|
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
.navbar__container--stacked {
|
|
150
|
+
display: inline;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
ul.navbar.navbar--stacked.navbar--icon-bar {
|
|
154
|
+
flex-direction: column;
|
|
155
|
+
padding: 0;
|
|
156
|
+
gap: 0;
|
|
157
|
+
|
|
158
|
+
li {
|
|
159
|
+
border-radius: 0;
|
|
160
|
+
align-items: flex-start;
|
|
161
|
+
padding: 8px;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
149
165
|
|
|
150
166
|
:host(:not([stacked]):not([icon-bar])) {
|
|
151
167
|
ul.navbar {
|
|
@@ -236,7 +252,7 @@ ul.navbar {
|
|
|
236
252
|
height: 2px;
|
|
237
253
|
}
|
|
238
254
|
|
|
239
|
-
&:hover:before {
|
|
255
|
+
&:hover:before:not(#dropdown-item) {
|
|
240
256
|
// TODO Hover Before colors
|
|
241
257
|
left: -2px;
|
|
242
258
|
right: -2px;
|
|
@@ -254,7 +254,12 @@ export default class ZnTabs extends ZincElement {
|
|
|
254
254
|
// ts-ignore
|
|
255
255
|
const target = (event.relatedTarget ?? event.target) as HTMLElement;
|
|
256
256
|
if (target) {
|
|
257
|
-
|
|
257
|
+
if ('startViewTransition' in document) {
|
|
258
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
259
|
+
(document as any).startViewTransition(() => this.clickTab(target, event.altKey));
|
|
260
|
+
} else {
|
|
261
|
+
this.clickTab(target, event.altKey)
|
|
262
|
+
}
|
|
258
263
|
}
|
|
259
264
|
}
|
|
260
265
|
|
|
@@ -333,8 +338,9 @@ export default class ZnTabs extends ZincElement {
|
|
|
333
338
|
return false;
|
|
334
339
|
}
|
|
335
340
|
|
|
341
|
+
const sameTab = this._current === tabName;
|
|
336
342
|
// Multi click on an active tab will refresh the tab
|
|
337
|
-
if (
|
|
343
|
+
if (sameTab) {
|
|
338
344
|
this._activeClicks++;
|
|
339
345
|
if (this._activeClicks > 2) {
|
|
340
346
|
refresh = true;
|
|
@@ -345,32 +351,35 @@ export default class ZnTabs extends ZincElement {
|
|
|
345
351
|
}
|
|
346
352
|
|
|
347
353
|
let inSlot = true;
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
element.toggleAttribute('selected', isActive);
|
|
355
|
-
if (isActive && refresh) {
|
|
356
|
-
let uri = "";
|
|
357
|
-
let gaid = "";
|
|
358
|
-
if (this._activeTab && this._activeTab.hasAttribute('tab-uri')) {
|
|
359
|
-
uri = this._activeTab.getAttribute('tab-uri')!;
|
|
360
|
-
gaid = this._activeTab.getAttribute('gaid')!;
|
|
354
|
+
const updateTabs = () => {
|
|
355
|
+
this._panels.forEach((elements, key) => {
|
|
356
|
+
const isActive = key === tabName;
|
|
357
|
+
elements.forEach((element) => {
|
|
358
|
+
if (isActive && element.parentNode !== this) {
|
|
359
|
+
inSlot = false;
|
|
361
360
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
361
|
+
element.toggleAttribute('selected', isActive);
|
|
362
|
+
if (isActive && refresh) {
|
|
363
|
+
let uri = "";
|
|
364
|
+
let gaid = "";
|
|
365
|
+
if (this._activeTab && this._activeTab.hasAttribute('tab-uri')) {
|
|
366
|
+
uri = this._activeTab.getAttribute('tab-uri')!;
|
|
367
|
+
gaid = this._activeTab.getAttribute('gaid')!;
|
|
368
|
+
}
|
|
369
|
+
document.dispatchEvent(new CustomEvent('zn-refresh-element', {
|
|
370
|
+
detail: {element: element, uri: uri, gaid: gaid}
|
|
371
|
+
}));
|
|
372
|
+
}
|
|
373
|
+
});
|
|
366
374
|
});
|
|
367
|
-
});
|
|
368
375
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
376
|
+
if (this._panel) {
|
|
377
|
+
this._panel.classList.toggle('contents-slot', !inSlot);
|
|
378
|
+
}
|
|
379
|
+
this._current = tabName;
|
|
380
|
+
};
|
|
372
381
|
|
|
373
|
-
|
|
382
|
+
updateTabs();
|
|
374
383
|
|
|
375
384
|
return true;
|
|
376
385
|
}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import {classMap} from 'lit/directives/class-map.js';
|
|
2
|
+
import {FormControlController, validValidityState} from '../../internal/form';
|
|
3
|
+
import {HasSlotController} from '../../internal/slot';
|
|
4
|
+
import {html, unsafeCSS} from 'lit';
|
|
5
|
+
import {property, state} from 'lit/decorators.js';
|
|
6
|
+
import ZincElement from '../../internal/zinc-element';
|
|
7
|
+
import ZnInlineEdit from '../inline-edit';
|
|
8
|
+
import ZnInput from '../input';
|
|
9
|
+
import ZnNavbar from '../navbar';
|
|
10
|
+
import type {PropertyValues} from 'lit';
|
|
11
|
+
import type {ZincFormControl} from '../../internal/zinc-element';
|
|
12
|
+
import type {ZnMenuSelectEvent} from '../../events/zn-menu-select';
|
|
13
|
+
import type {ZnSelectEvent} from "../../events/zn-select";
|
|
14
|
+
|
|
15
|
+
import styles from './translations.scss';
|
|
16
|
+
|
|
17
|
+
export default class ZnTranslations extends ZincElement implements ZincFormControl {
|
|
18
|
+
static styles = unsafeCSS(styles);
|
|
19
|
+
static dependencies = {
|
|
20
|
+
'zn-navbar': ZnNavbar,
|
|
21
|
+
'zn-input': ZnInput,
|
|
22
|
+
'zn-inline-edit': ZnInlineEdit
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
private readonly formControlController: FormControlController = new FormControlController(this);
|
|
26
|
+
private readonly hasSlotController = new HasSlotController(this, 'label');
|
|
27
|
+
|
|
28
|
+
@property() name = '';
|
|
29
|
+
@property() value = '{"en":""}';
|
|
30
|
+
@property() label: string = '';
|
|
31
|
+
@property({type: Boolean, reflect: true}) disabled = false;
|
|
32
|
+
@property({type: Boolean, reflect: true}) required = false;
|
|
33
|
+
|
|
34
|
+
@property({type: Object}) languages: Record<string, string> = {
|
|
35
|
+
'en': 'English'
|
|
36
|
+
};
|
|
37
|
+
@property({type: Object}) values: Record<string, string> = {};
|
|
38
|
+
|
|
39
|
+
@state() private _activeLanguage = '';
|
|
40
|
+
|
|
41
|
+
get validity(): ValidityState {
|
|
42
|
+
return validValidityState;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get validationMessage() {
|
|
46
|
+
return '';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
checkValidity() {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
getForm() {
|
|
54
|
+
return this.formControlController.getForm();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
reportValidity() {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
setCustomValidity() {
|
|
62
|
+
// no-op
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
protected firstUpdated() {
|
|
66
|
+
this.formControlController.updateValidity();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
willUpdate(changedProperties: PropertyValues) {
|
|
70
|
+
let processValue = changedProperties.has('value');
|
|
71
|
+
let processValues = changedProperties.has('values');
|
|
72
|
+
|
|
73
|
+
if (processValue && processValues) {
|
|
74
|
+
const isValueDefault = this.value === '{"en":""}';
|
|
75
|
+
const isValuesEmpty = Object.keys(this.values).length === 0;
|
|
76
|
+
|
|
77
|
+
if (isValueDefault && !isValuesEmpty) {
|
|
78
|
+
processValue = false;
|
|
79
|
+
} else if (!isValueDefault && isValuesEmpty) {
|
|
80
|
+
processValues = false;
|
|
81
|
+
} else if (this.hasAttribute('values') && !this.hasAttribute('value')) {
|
|
82
|
+
processValue = false;
|
|
83
|
+
} else if (this.hasAttribute('value') && !this.hasAttribute('values')) {
|
|
84
|
+
processValues = false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (processValue) {
|
|
89
|
+
try {
|
|
90
|
+
const newValues = JSON.parse(this.value || '{}') as Record<string, string>;
|
|
91
|
+
if (JSON.stringify(newValues) !== JSON.stringify(this.values)) {
|
|
92
|
+
this.values = newValues;
|
|
93
|
+
}
|
|
94
|
+
} catch (e) {
|
|
95
|
+
// no-op
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (processValues) {
|
|
100
|
+
this.value = JSON.stringify(this.values);
|
|
101
|
+
|
|
102
|
+
// Ensure active language is valid
|
|
103
|
+
if (!this._activeLanguage || !Object.prototype.hasOwnProperty.call(this.values, this._activeLanguage)) {
|
|
104
|
+
const keys = Object.keys(this.values);
|
|
105
|
+
if (keys.length > 0) {
|
|
106
|
+
this._activeLanguage = keys[0];
|
|
107
|
+
} else {
|
|
108
|
+
this._activeLanguage = '';
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private handleLanguageAdd = (e: ZnMenuSelectEvent) => {
|
|
115
|
+
const element = e.detail.element as HTMLElement;
|
|
116
|
+
const languageCode = element.getAttribute('data-path');
|
|
117
|
+
if (languageCode) {
|
|
118
|
+
// Add new language with empty string
|
|
119
|
+
this.values = {...this.values, [languageCode]: ''};
|
|
120
|
+
this._activeLanguage = languageCode;
|
|
121
|
+
this.updateValue();
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
private handleNavbarClick = (e: ZnSelectEvent) => {
|
|
126
|
+
e.stopPropagation();
|
|
127
|
+
const li = e.detail.item as HTMLElement;
|
|
128
|
+
if (li) {
|
|
129
|
+
const tab = li.getAttribute('tab') || li.getAttribute('data-tab');
|
|
130
|
+
if (tab) {
|
|
131
|
+
this._activeLanguage = tab;
|
|
132
|
+
this.requestUpdate();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
private handleValueUpdate = (e: CustomEvent) => {
|
|
138
|
+
const target = e.target as (ZnInput | ZnInlineEdit);
|
|
139
|
+
if (this._activeLanguage) {
|
|
140
|
+
const newValue: string = target.value as string;
|
|
141
|
+
if (newValue !== this.values[this._activeLanguage]) {
|
|
142
|
+
this.values = {...this.values, [this._activeLanguage]: newValue};
|
|
143
|
+
this.updateValue();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
private updateValue() {
|
|
149
|
+
this.value = JSON.stringify(this.values);
|
|
150
|
+
this.emit('zn-change');
|
|
151
|
+
this.emit('zn-input');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
private handleKeyDown = (event: KeyboardEvent) => {
|
|
155
|
+
if (event.key === 'Enter') {
|
|
156
|
+
if (event.target instanceof ZnInlineEdit) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const hasModifier = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
161
|
+
|
|
162
|
+
if (!hasModifier && !event.defaultPrevented && !event.isComposing) {
|
|
163
|
+
this.formControlController.submit();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
private handleSubmit = () => {
|
|
169
|
+
this.formControlController.submit();
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
render() {
|
|
173
|
+
const availableLanguages = Object.entries(this.languages)
|
|
174
|
+
.filter(([code]) => !Object.prototype.hasOwnProperty.call(this.values, code))
|
|
175
|
+
.map(([code, name]) => ({
|
|
176
|
+
title: name,
|
|
177
|
+
type: 'dropdown',
|
|
178
|
+
path: code
|
|
179
|
+
}));
|
|
180
|
+
|
|
181
|
+
const navigation = Object.keys(this.values).map(code => ({
|
|
182
|
+
title: this.languages[code] || code,
|
|
183
|
+
active: code === this._activeLanguage,
|
|
184
|
+
tab: code
|
|
185
|
+
}));
|
|
186
|
+
|
|
187
|
+
const currentTranslation = this.values[this._activeLanguage];
|
|
188
|
+
const useInlineEdit = currentTranslation && currentTranslation.length > 0;
|
|
189
|
+
|
|
190
|
+
const hasLabelSlot = this.hasSlotController.test('label');
|
|
191
|
+
const hasLabel = this.label ? true : hasLabelSlot;
|
|
192
|
+
|
|
193
|
+
return html`
|
|
194
|
+
<div part="form-control"
|
|
195
|
+
class="${classMap({
|
|
196
|
+
'translations': true,
|
|
197
|
+
'form-control': true,
|
|
198
|
+
'form-control--medium': true,
|
|
199
|
+
'form-control--has-label': hasLabel,
|
|
200
|
+
})}"
|
|
201
|
+
@keydown="${this.handleKeyDown}">
|
|
202
|
+
<label part="form-control-label" class="form-control__label" for="input"
|
|
203
|
+
aria-hidden=${hasLabel ? 'false' : 'true'}>
|
|
204
|
+
<slot name="label">${this.label}</slot>
|
|
205
|
+
</label>
|
|
206
|
+
|
|
207
|
+
<zn-navbar
|
|
208
|
+
.navigation="${navigation}"
|
|
209
|
+
.dropdown="${availableLanguages}"
|
|
210
|
+
name="${this.name}-translations-navbar"
|
|
211
|
+
isolated
|
|
212
|
+
@zn-select="${this.handleNavbarClick}"
|
|
213
|
+
@zn-menu-select="${this.handleLanguageAdd}"
|
|
214
|
+
manual-add-items
|
|
215
|
+
></zn-navbar>
|
|
216
|
+
<div class="input-container">
|
|
217
|
+
${this._activeLanguage ? html`
|
|
218
|
+
${useInlineEdit ? html`
|
|
219
|
+
<zn-inline-edit
|
|
220
|
+
.value=${currentTranslation}
|
|
221
|
+
name="${this.name}"
|
|
222
|
+
@zn-change="${this.handleValueUpdate}"
|
|
223
|
+
@zn-input="${this.handleValueUpdate}"
|
|
224
|
+
@zn-submit="${this.handleSubmit}"
|
|
225
|
+
></zn-inline-edit>
|
|
226
|
+
` : html`
|
|
227
|
+
<zn-input
|
|
228
|
+
.value="${currentTranslation || ''}"
|
|
229
|
+
name="${this.name}"
|
|
230
|
+
placeholder="Enter translation..."
|
|
231
|
+
@zn-change="${this.handleValueUpdate}"
|
|
232
|
+
></zn-input>
|
|
233
|
+
`}
|
|
234
|
+
` : ''}
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
`;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import '../../../dist/zn.min.js';
|
|
2
|
+
import { expect, fixture, html } from '@open-wc/testing';
|
|
3
|
+
import type ZnTranslations from './translations.component';
|
|
4
|
+
|
|
5
|
+
describe('<zn-translations>', () => {
|
|
6
|
+
it('should render a component', async () => {
|
|
7
|
+
const el = await fixture(html` <zn-translations></zn-translations> `);
|
|
8
|
+
expect(el).to.exist;
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should have default language en', async () => {
|
|
12
|
+
const el = await fixture<ZnTranslations>(html` <zn-translations></zn-translations> `);
|
|
13
|
+
expect(el.languages).to.have.property('en');
|
|
14
|
+
// We expect values to default to en: '' if strictly following requirements,
|
|
15
|
+
// or at least the UI should show it.
|
|
16
|
+
// Based on my plan, I will implement auto-population of 'en'.
|
|
17
|
+
expect(el.values).to.have.property('en');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should update value when input changes', async () => {
|
|
21
|
+
const el = await fixture<ZnTranslations>(html` <zn-translations></zn-translations> `);
|
|
22
|
+
// Mock languages to ensure we have something to edit
|
|
23
|
+
el.languages = { 'en': 'English', 'fr': 'French' };
|
|
24
|
+
el.values = { 'en': 'Hello' };
|
|
25
|
+
await el.updateComplete;
|
|
26
|
+
|
|
27
|
+
const input = el.shadowRoot!.querySelector('zn-inline-edit');
|
|
28
|
+
expect(input).to.exist;
|
|
29
|
+
await expect(input!.getAttribute('value')).to.equal('Hello');
|
|
30
|
+
|
|
31
|
+
// Simulate change
|
|
32
|
+
input!.value = 'Hello World';
|
|
33
|
+
input!.dispatchEvent(new CustomEvent('zn-change'));
|
|
34
|
+
|
|
35
|
+
await el.updateComplete;
|
|
36
|
+
await expect(el.values['en']).to.equal('Hello World');
|
|
37
|
+
await expect(JSON.parse(el.value)).to.deep.equal({'en': 'Hello World'});
|
|
38
|
+
});
|
|
39
|
+
});
|
package/src/events/zn-select.ts
CHANGED
package/src/zinc.ts
CHANGED
|
@@ -57,6 +57,7 @@ export {default as Textarea} from './components/textarea';
|
|
|
57
57
|
export {default as Checkbox} from './components/checkbox';
|
|
58
58
|
export {default as Datepicker} from './components/datepicker';
|
|
59
59
|
export {default as FormGroup} from './components/form-group';
|
|
60
|
+
export {default as InputGroup} from './components/input-group';
|
|
60
61
|
export {default as LinkedSelect} from './components/linked-select';
|
|
61
62
|
export {default as Radio} from './components/radio';
|
|
62
63
|
export {default as Rating} from './components/rating';
|
|
@@ -83,6 +84,7 @@ export {default as SettingsContainer} from './components/settings-container';
|
|
|
83
84
|
export { default as FilterContainer } from './components/filter-container';
|
|
84
85
|
export { default as Reveal } from './components/reveal';
|
|
85
86
|
export { default as AudioSelect } from './components/audio-select';
|
|
87
|
+
export { default as Translations } from './components/translations';
|
|
86
88
|
/* plop:component */
|
|
87
89
|
|
|
88
90
|
// Base Component
|