@kubex/zinc 1.0.25 → 1.0.99

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.
Files changed (199) hide show
  1. package/.claude/project.md +556 -0
  2. package/.github/workflows/js_build_and_deploy.yaml +9 -10
  3. package/dist/custom-elements.json +13575 -8856
  4. package/dist/vscode.html-custom-data.json +583 -48
  5. package/dist/web-types.json +1441 -181
  6. package/dist/zn.d.ts +1645 -660
  7. package/dist/zn.min.css +1 -1
  8. package/dist/zn.min.js +1412 -893
  9. package/docs/_utilities/code-previews.cjs +10 -1
  10. package/docs/assets/scripts/docs.js +42 -18
  11. package/docs/data/data-table.json +229 -66
  12. package/docs/data/empty.json +6 -0
  13. package/docs/data/products-table.json +41 -193
  14. package/docs/pages/components/action-bar.md +121 -6
  15. package/docs/pages/components/alert.md +118 -15
  16. package/docs/pages/components/animated-button.md +299 -0
  17. package/docs/pages/components/audio-select.md +534 -0
  18. package/docs/pages/components/bulk-actions.md +79 -5
  19. package/docs/pages/components/button-group.md +235 -27
  20. package/docs/pages/components/button.md +139 -1
  21. package/docs/pages/components/chart.md +365 -9
  22. package/docs/pages/components/checkbox.md +387 -58
  23. package/docs/pages/components/chip.md +253 -33
  24. package/docs/pages/components/collapsible.md +393 -46
  25. package/docs/pages/components/cols.md +152 -30
  26. package/docs/pages/components/confirm.md +182 -16
  27. package/docs/pages/components/copy-button.md +169 -6
  28. package/docs/pages/components/data-select.md +194 -15
  29. package/docs/pages/components/data-table-filter.md +96 -5
  30. package/docs/pages/components/data-table-search.md +451 -0
  31. package/docs/pages/components/data-table-sort.md +66 -5
  32. package/docs/pages/components/data-table.md +727 -66
  33. package/docs/pages/components/datepicker.md +402 -7
  34. package/docs/pages/components/defined-label.md +120 -5
  35. package/docs/pages/components/dialog.md +339 -59
  36. package/docs/pages/components/dropdown.md +366 -11
  37. package/docs/pages/components/editor.md +604 -7
  38. package/docs/pages/components/empty-state.md +315 -16
  39. package/docs/pages/components/expanding-action.md +212 -28
  40. package/docs/pages/components/file.md +421 -12
  41. package/docs/pages/components/filter-container.md +158 -5
  42. package/docs/pages/components/filter-wrapper.md +167 -6
  43. package/docs/pages/components/form-group.md +383 -6
  44. package/docs/pages/components/hover-container.md +237 -6
  45. package/docs/pages/components/icon-picker.md +121 -0
  46. package/docs/pages/components/icon.md +454 -48
  47. package/docs/pages/components/inline-edit.md +787 -19
  48. package/docs/pages/components/input-group.md +207 -13
  49. package/docs/pages/components/input.md +194 -0
  50. package/docs/pages/components/item.md +18 -0
  51. package/docs/pages/components/key-container.md +115 -0
  52. package/docs/pages/components/key.md +101 -0
  53. package/docs/pages/components/menu.md +512 -6
  54. package/docs/pages/components/note.md +239 -36
  55. package/docs/pages/components/opt-group.md +107 -0
  56. package/docs/pages/components/pagination.md +332 -6
  57. package/docs/pages/components/pane.md +222 -6
  58. package/docs/pages/components/panel.md +213 -26
  59. package/docs/pages/components/popup.md +1354 -6
  60. package/docs/pages/components/priority-list.md +233 -0
  61. package/docs/pages/components/progress-bar.md +387 -6
  62. package/docs/pages/components/radio-group.md +242 -5
  63. package/docs/pages/components/radio.md +474 -6
  64. package/docs/pages/components/rating.md +331 -7
  65. package/docs/pages/components/reveal.md +524 -6
  66. package/docs/pages/components/scroll-container.md +552 -6
  67. package/docs/pages/components/select.md +762 -160
  68. package/docs/pages/components/skeleton.md +473 -30
  69. package/docs/pages/components/slideout.md +261 -5
  70. package/docs/pages/components/sp.md +99 -41
  71. package/docs/pages/components/split-button.md +347 -9
  72. package/docs/pages/components/split-pane.md +445 -6
  73. package/docs/pages/components/stat.md +549 -9
  74. package/docs/pages/components/status-indicator.md +230 -1
  75. package/docs/pages/components/stepper.md +563 -6
  76. package/docs/pages/components/tabs.md +439 -13
  77. package/docs/pages/components/textarea.md +415 -17
  78. package/docs/pages/components/tile.md +385 -26
  79. package/docs/pages/components/toggle.md +424 -6
  80. package/docs/pages/components/tooltip.md +367 -0
  81. package/docs/pages/components/translation-group.md +210 -0
  82. package/docs/pages/components/translations.md +319 -19
  83. package/docs/pages/components/vertical-stepper.md +401 -8
  84. package/docs/pages/components/well.md +300 -3
  85. package/docs/pages/getting-started/form-controls.md +162 -0
  86. package/docs/pages/index.md +116 -15
  87. package/package.json +5 -6
  88. package/scss/_global-spacing.scss +4 -0
  89. package/scss/_root.scss +2 -2
  90. package/scss/boot.scss +19 -0
  91. package/scss/shared/layout.scss +5 -0
  92. package/scss/themes/_light.scss +3 -3
  93. package/src/components/alert/alert.scss +1 -0
  94. package/src/components/animated-button/README.md +306 -0
  95. package/src/components/animated-button/animated-button.component.ts +229 -0
  96. package/src/components/animated-button/animated-button.scss +228 -0
  97. package/src/components/animated-button/animated-button.test.ts +143 -0
  98. package/src/components/animated-button/index.ts +12 -0
  99. package/src/components/button/button.component.ts +5 -0
  100. package/src/components/button-group/button-group.component.ts +25 -13
  101. package/src/components/button-group/button-group.scss +6 -0
  102. package/src/components/checkbox/checkbox.component.ts +4 -0
  103. package/src/components/checkbox/checkbox.scss +7 -4
  104. package/src/components/checkbox-group/checkbox-group.scss +7 -0
  105. package/src/components/chip/chip.component.ts +7 -2
  106. package/src/components/chip/chip.scss +16 -2
  107. package/src/components/collapsible/collapsible.component.ts +27 -20
  108. package/src/components/cols/cols.component.ts +14 -2
  109. package/src/components/cols/cols.scss +6 -12
  110. package/src/components/confirm/confirm.component.ts +7 -0
  111. package/src/components/copy-button/copy-button.component.ts +12 -11
  112. package/src/components/data-select/data-select.component.ts +215 -44
  113. package/src/components/data-select/data-select.scss +66 -6
  114. package/src/components/data-select/providers/currency-data-provider.ts +20 -6
  115. package/src/components/data-select/providers/provider.ts +1 -0
  116. package/src/components/data-select/providers/us-state-data-provider.ts +68 -0
  117. package/src/components/data-table/data-table.component.ts +81 -22
  118. package/src/components/data-table-search/data-table-search.component.ts +184 -0
  119. package/src/components/data-table-search/data-table-search.scss +17 -0
  120. package/src/components/data-table-search/data-table-search.test.ts +11 -0
  121. package/src/components/data-table-search/index.ts +12 -0
  122. package/src/components/datepicker/datepicker.component.ts +347 -13
  123. package/src/components/dialog/dialog.component.ts +1 -1
  124. package/src/components/empty-state/empty-state.scss +6 -1
  125. package/src/components/header/header.scss +3 -3
  126. package/src/components/icon/icon.component.ts +23 -1
  127. package/src/components/icon/icon.scss +23 -0
  128. package/src/components/icon-picker/brand-icons.ts +24 -0
  129. package/src/components/icon-picker/icon-picker.component.ts +407 -0
  130. package/src/components/icon-picker/icon-picker.scss +205 -0
  131. package/src/components/icon-picker/index.ts +12 -0
  132. package/src/components/icon-picker/line-icons.ts +612 -0
  133. package/src/components/icon-picker/material-icons.ts +14543 -0
  134. package/src/components/inline-edit/inline-edit.component.ts +190 -46
  135. package/src/components/inline-edit/inline-edit.scss +29 -0
  136. package/src/components/inline-edit/inline-edit.test.ts +314 -1
  137. package/src/components/input/input.component.ts +324 -5
  138. package/src/components/input/input.scss +87 -0
  139. package/src/components/input-group/input-group.component.ts +28 -7
  140. package/src/components/input-group/input-group.scss +48 -10
  141. package/src/components/item/item.component.ts +24 -3
  142. package/src/components/item/item.scss +18 -0
  143. package/src/components/key/index.ts +12 -0
  144. package/src/components/key/key.component.ts +47 -0
  145. package/src/components/key/key.scss +38 -0
  146. package/src/components/key-container/index.ts +12 -0
  147. package/src/components/key-container/key-container.component.ts +142 -0
  148. package/src/components/key-container/key-container.scss +33 -0
  149. package/src/components/menu-item/menu-item.component.ts +20 -0
  150. package/src/components/menu-item/menu-item.scss +69 -2
  151. package/src/components/navbar/navbar.component.ts +103 -11
  152. package/src/components/navbar/navbar.scss +6 -1
  153. package/src/components/opt-group/index.ts +12 -0
  154. package/src/components/opt-group/opt-group.component.ts +74 -0
  155. package/src/components/opt-group/opt-group.scss +37 -0
  156. package/src/components/opt-group/opt-group.test.ts +27 -0
  157. package/src/components/option/option.component.ts +1 -16
  158. package/src/components/option/option.scss +4 -0
  159. package/src/components/panel/panel.component.ts +10 -8
  160. package/src/components/panel/panel.scss +20 -0
  161. package/src/components/priority-list/index.ts +12 -0
  162. package/src/components/priority-list/priority-list.component.ts +611 -0
  163. package/src/components/priority-list/priority-list.scss +185 -0
  164. package/src/components/priority-list/priority-list.test.ts +139 -0
  165. package/src/components/progress-bar/progress-bar.component.ts +22 -16
  166. package/src/components/radio/radio.scss +10 -3
  167. package/src/components/select/select.component.ts +812 -72
  168. package/src/components/select/select.scss +108 -2
  169. package/src/components/select/select.test.ts +147 -2
  170. package/src/components/settings-container/settings-container.component.ts +44 -19
  171. package/src/components/settings-container/settings-container.scss +1 -1
  172. package/src/components/skeleton/skeleton.component.ts +6 -1
  173. package/src/components/slideout/slideout.scss +8 -3
  174. package/src/components/sp/sp.component.ts +3 -1
  175. package/src/components/sp/sp.scss +19 -0
  176. package/src/components/stepper/stepper.component.ts +16 -10
  177. package/src/components/textarea/textarea.scss +0 -4
  178. package/src/components/tile/tile.component.ts +12 -3
  179. package/src/components/tile/tile.scss +1 -1
  180. package/src/components/timer/timer.component.ts +15 -2
  181. package/src/components/toggle/toggle.component.ts +29 -26
  182. package/src/components/toggle/toggle.scss +13 -1
  183. package/src/components/translation-group/index.ts +12 -0
  184. package/src/components/translation-group/translation-group.component.ts +207 -0
  185. package/src/components/translation-group/translation-group.scss +8 -0
  186. package/src/components/translations/translations.component.ts +90 -44
  187. package/src/components/translations/translations.scss +4 -0
  188. package/src/components/vertical-stepper/vertical-stepper.component.ts +14 -9
  189. package/src/events/events.ts +12 -7
  190. package/src/events/zn-language-change.ts +7 -0
  191. package/src/events/zn-purchase.ts +11 -0
  192. package/src/events/zn-redirect.ts +7 -0
  193. package/src/events/zn-reorder.ts +7 -0
  194. package/src/events/zn-search-change.ts +11 -0
  195. package/src/events/zn-submit.ts +1 -1
  196. package/src/form-control.scss +4 -0
  197. package/src/internal/form-navigation.ts +510 -0
  198. package/src/internal/form.ts +6 -0
  199. package/src/zinc.ts +91 -83
@@ -1,30 +1,30 @@
1
- import {classMap} from "lit/directives/class-map.js";
2
- import {type CSSResultGroup, html, type PropertyValues, unsafeCSS} from 'lit';
3
- import {defaultValue} from "../../internal/default-value";
4
- import {FormControlController} from "../../internal/form";
5
- import {ifDefined} from "lit/directives/if-defined.js";
6
- import {live} from "lit/directives/live.js";
7
- import {property, query, state} from 'lit/decorators.js';
8
- import ZincElement, {type ZincFormControl} from '../../internal/zinc-element';
1
+ import { classMap } from "lit/directives/class-map.js";
2
+ import { type CSSResultGroup, html, type PropertyValues, unsafeCSS } from 'lit';
3
+ import { defaultValue } from "../../internal/default-value";
4
+ import { FormControlController } from "../../internal/form";
5
+ import { ifDefined } from "lit/directives/if-defined.js";
6
+ import { live } from "lit/directives/live.js";
7
+ import { property, query, state } from 'lit/decorators.js';
8
+ import ZincElement, { type ZincFormControl } from '../../internal/zinc-element';
9
9
 
10
10
  import styles from './toggle.scss';
11
11
 
12
12
  /**
13
- * @summary Short summary of the component's intended use.
13
+ * @summary Toggles allow the user to switch an option on or off.
14
14
  * @documentation https://zinc.style/components/toggle
15
- * @status experimental
15
+ * @status stable
16
16
  * @since 1.0
17
17
  *
18
- * @dependency zn-example
18
+ * @dependency zn-tooltip
19
19
  *
20
- * @event zn-event-name - Emitted as an example.
20
+ * @event zn-input - Emitted when the toggle receives input.
21
21
  *
22
- * @slot - The default slot.
23
- * @slot example - An example slot.
22
+ * @slot - The toggle's label.
24
23
  *
25
- * @csspart base - The component's base wrapper.
24
+ * @csspart base - The component's base wrapper containing the toggle switch.
25
+ * @csspart control - The toggle switch control (the circular button that slides).
26
26
  *
27
- * @cssproperty --example - An example CSS custom property.
27
+ * @cssproperty --zn-toggle-margin - The margin around the toggle switch. Defaults to `8px 0`.
28
28
  */
29
29
  export default class ZnToggle extends ZincElement implements ZincFormControl {
30
30
  static styles: CSSResultGroup = unsafeCSS(styles);
@@ -45,30 +45,32 @@ export default class ZnToggle extends ZincElement implements ZincFormControl {
45
45
 
46
46
  @property() value: string;
47
47
 
48
- @property({attribute: 'fallback'}) fallbackValue: string = '';
48
+ @property({ attribute: 'fallback' }) fallbackValue: string = '';
49
49
 
50
- @property({reflect: true}) size: 'small' | 'medium' | 'large' = 'medium';
50
+ @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium';
51
51
 
52
- @property({type: Boolean, reflect: true}) disabled: boolean = false;
52
+ @property({ type: Boolean, reflect: true }) disabled: boolean = false;
53
53
 
54
- @property({type: Boolean, reflect: true}) checked: boolean = false;
54
+ @property({ type: Boolean, reflect: true }) checked: boolean = false;
55
55
 
56
56
  @defaultValue('checked') defaultChecked = false;
57
57
 
58
- @property({reflect: true}) form = '';
58
+ @property({ reflect: true }) form = '';
59
59
 
60
- @property({type: Boolean, reflect: true}) required = false;
60
+ @property({ type: Boolean, reflect: true }) required = false;
61
61
 
62
- @property({attribute: 'help-text'}) helpText = "";
62
+ @property({ attribute: 'help-text' }) helpText = "";
63
63
 
64
- @property({type: Boolean, attribute: 'trigger-submit'}) triggerSubmit = false;
64
+ @property({ type: Boolean, attribute: 'trigger-submit' }) triggerSubmit = false;
65
65
 
66
- @property({attribute: "on-text"}) onText: string = '';
66
+ @property({ attribute: "on-text" }) onText: string = '';
67
67
 
68
- @property({attribute: "off-text"}) offText: string = '';
68
+ @property({ attribute: "off-text" }) offText: string = '';
69
69
 
70
70
  @property() label: string = '';
71
71
 
72
+ @property({ type: Boolean }) inline: boolean = false;
73
+
72
74
  get validity() {
73
75
  return this.input?.validity;
74
76
  }
@@ -199,6 +201,7 @@ export default class ZnToggle extends ZincElement implements ZincFormControl {
199
201
  'switch__wrapper--small': this.size === 'small',
200
202
  'switch__wrapper--medium': this.size === 'medium',
201
203
  'switch__wrapper--large': this.size === 'large',
204
+ 'switch__wrapper--inline': this.inline
202
205
  })}">
203
206
  <label>
204
207
  ${this.label ? html`<p class="switch-label">${this.label}</p>` : ''}
@@ -81,7 +81,7 @@
81
81
  width: 35px;
82
82
  }
83
83
 
84
- :host([checked]) .switch__wrapper--small .switch__input-wrapper {
84
+ :host([checked]) .switch__wrapper--small .switch__input-wrapper {
85
85
  .switch__control {
86
86
  transform: translateX(calc(100% - 7px)) scale(0.8);
87
87
  }
@@ -91,3 +91,15 @@
91
91
  max-width: 20px;
92
92
  height: 20px;
93
93
  }
94
+
95
+ // Support inline label
96
+ .switch__wrapper--inline label {
97
+ align-items: center;
98
+ display: flex;
99
+ gap: 8px;
100
+
101
+ .switch__input {
102
+ margin-inline: 1px;
103
+ margin-inline-end: 1px;
104
+ }
105
+ }
@@ -0,0 +1,12 @@
1
+ import ZnTranslationGroup from './translation-group.component';
2
+
3
+ export * from './translation-group.component';
4
+ export default ZnTranslationGroup;
5
+
6
+ ZnTranslationGroup.define('zn-translation-group');
7
+
8
+ declare global {
9
+ interface HTMLElementTagNameMap {
10
+ 'zn-translation-group': ZnTranslationGroup;
11
+ }
12
+ }
@@ -0,0 +1,207 @@
1
+ import {classMap} from 'lit/directives/class-map.js';
2
+ import {type CSSResultGroup, html, nothing, type PropertyValues, unsafeCSS} from 'lit';
3
+ import {HasSlotController} from '../../internal/slot';
4
+ import {ifDefined} from 'lit/directives/if-defined.js';
5
+ import {property, state} from 'lit/decorators.js';
6
+ import ZnButton from '../button';
7
+ import ZnButtonGroup from '../button-group';
8
+ import ZnDropdown from '../dropdown';
9
+ import ZnHeader from '../header';
10
+ import ZnMenu from '../menu';
11
+ import ZnPanel from '../panel/panel.component';
12
+ import type {ZnMenuSelectEvent} from '../../events/zn-menu-select';
13
+ import type ZnTranslations from '../translations/translations.component';
14
+
15
+ import styles from './translation-group.scss';
16
+
17
+ /**
18
+ * @summary A panel-styled container that provides a shared language toggle for multiple zn-translations children.
19
+ *
20
+ * @dependency zn-button
21
+ * @dependency zn-button-group
22
+ * @dependency zn-dropdown
23
+ * @dependency zn-menu
24
+ *
25
+ * @event zn-language-change - Emitted when the active language changes. Detail: `{ language: string }`.
26
+ *
27
+ * @slot - Default slot for `<zn-translations>` elements.
28
+ * @slot actions - Actions displayed in the panel header alongside language buttons.
29
+ *
30
+ * @csspart base - The component's base wrapper.
31
+ */
32
+ export default class ZnTranslationGroup extends ZnPanel {
33
+ static styles: CSSResultGroup = [ZnPanel.styles, unsafeCSS(styles)];
34
+ static dependencies = {
35
+ 'zn-button': ZnButton,
36
+ 'zn-button-group': ZnButtonGroup,
37
+ 'zn-dropdown': ZnDropdown,
38
+ 'zn-header': ZnHeader,
39
+ 'zn-menu': ZnMenu
40
+ };
41
+
42
+ private readonly _slotController = new HasSlotController(this, 'actions', 'footer');
43
+
44
+ /** The group label displayed in the panel header. */
45
+ @property() label = '';
46
+
47
+ /** The available languages for the group. */
48
+ @property({type: Object}) languages: Record<string, string> = {
49
+ 'en': 'EN'
50
+ };
51
+
52
+ @state() private _activeLanguage = 'en';
53
+
54
+ /** Tracks all language codes that have been activated across children. */
55
+ @state() private _activatedLanguages: string[] = ['en'];
56
+
57
+ protected firstUpdated(_changedProperties: PropertyValues) {
58
+ super.firstUpdated(_changedProperties);
59
+ this.syncChildren();
60
+ }
61
+
62
+ protected updated(changedProperties: PropertyValues) {
63
+ super.updated(changedProperties);
64
+ if (changedProperties.has('languages')) {
65
+ this.syncChildLanguages();
66
+ }
67
+ }
68
+
69
+ private getAllTranslations(): ZnTranslations[] {
70
+ return [...this.querySelectorAll<ZnTranslations>('zn-translations')];
71
+ }
72
+
73
+ /** Sync grouped state, languages, and active language to all children. */
74
+ private syncChildren() {
75
+ const children = this.getAllTranslations();
76
+
77
+ // Collect all language codes from children's existing values
78
+ const allLanguageCodes = new Set<string>(this._activatedLanguages);
79
+ children.forEach(child => {
80
+ child.getValueLanguages().forEach(code => allLanguageCodes.add(code));
81
+ });
82
+ this._activatedLanguages = [...allLanguageCodes];
83
+
84
+ children.forEach(child => {
85
+ child.grouped = true;
86
+ child.languages = this.languages;
87
+ // Ensure every activated language exists in each child's values.
88
+ // This handles the case where one child has a language that another doesn't.
89
+ for (const code of this._activatedLanguages) {
90
+ child.addLanguageKey(code);
91
+ }
92
+ child.setActiveLanguage(this._activeLanguage);
93
+ });
94
+ }
95
+
96
+ private syncChildLanguages() {
97
+ this.getAllTranslations().forEach(child => {
98
+ child.languages = this.languages;
99
+ });
100
+ }
101
+
102
+ private handleSlotChange = () => {
103
+ this.syncChildren();
104
+ };
105
+
106
+ private switchLanguage(lang: string) {
107
+ this._activeLanguage = lang;
108
+ this.getAllTranslations().forEach(child => child.setActiveLanguage(lang));
109
+ this.emit('zn-language-change', {detail: {language: lang}});
110
+ }
111
+
112
+ private handleLanguageAdd = (e: ZnMenuSelectEvent) => {
113
+ e.stopPropagation();
114
+ const element = e.detail.element as HTMLElement;
115
+ const languageCode = element.getAttribute('data-path');
116
+ if (languageCode) {
117
+ if (!this._activatedLanguages.includes(languageCode)) {
118
+ this._activatedLanguages = [...this._activatedLanguages, languageCode];
119
+ }
120
+
121
+ // Add language key to all children first so the key exists in values
122
+ this.getAllTranslations().forEach(child => child.addLanguageKey(languageCode));
123
+ this.switchLanguage(languageCode);
124
+ }
125
+ };
126
+
127
+ render() {
128
+ const hasActionSlot = this._slotController.test('actions');
129
+ const hasFooterSlot = this._slotController.test('footer');
130
+ const headerCaption = this.caption || this.label;
131
+
132
+ const availableLanguages = Object.entries(this.languages)
133
+ .filter(([code]) => code !== 'en' && !this._activatedLanguages.includes(code))
134
+ .map(([code, name]) => ({
135
+ title: name,
136
+ type: 'dropdown',
137
+ path: code
138
+ }));
139
+
140
+ const visibleTabs = [...this._activatedLanguages];
141
+ if (!visibleTabs.includes('en')) {
142
+ visibleTabs.unshift('en');
143
+ }
144
+
145
+ const hasMultipleLanguages = Object.keys(this.languages).length > 1;
146
+ const hasHeader = headerCaption || hasMultipleLanguages || hasActionSlot;
147
+
148
+ return html`
149
+ <div class="${classMap({
150
+ panel: true,
151
+ 'panel--flush': this.flush,
152
+ 'panel--has-header': hasHeader,
153
+ 'panel--has-actions': hasMultipleLanguages || hasActionSlot,
154
+ 'panel--has-footer': hasFooterSlot,
155
+ })}">
156
+
157
+ <div class="panel__inner">
158
+ ${hasHeader ? html`
159
+ <zn-header class="panel__header"
160
+ caption="${ifDefined(headerCaption || undefined)}"
161
+ transparent>
162
+ ${hasMultipleLanguages ? html`
163
+ <div slot="actions" class="translation-group__languages">
164
+ <zn-button-group>
165
+ ${visibleTabs.map(code => html`
166
+ <zn-button
167
+ size="x-small"
168
+ color="default"
169
+ ?outline="${code !== this._activeLanguage}"
170
+ @click="${() => this.switchLanguage(code)}"
171
+ >${code.toUpperCase()}
172
+ </zn-button>
173
+ `)}
174
+ ${availableLanguages.length > 0 ? html`
175
+ <zn-dropdown placement="bottom-end">
176
+ <zn-button
177
+ slot="trigger"
178
+ size="x-small"
179
+ color="default"
180
+ outline
181
+ >+
182
+ </zn-button>
183
+ <zn-menu
184
+ .actions=${availableLanguages}
185
+ @zn-menu-select="${this.handleLanguageAdd}"
186
+ ></zn-menu>
187
+ </zn-dropdown>
188
+ ` : nothing}
189
+ </zn-button-group>
190
+ </div>
191
+ ` : nothing}
192
+ ${hasActionSlot ? html`
193
+ <slot name="actions" slot="actions"></slot>` : null}
194
+ </zn-header>` : null}
195
+
196
+ <div class="panel__content">
197
+ <div class="panel__body">
198
+ <slot @slotchange="${this.handleSlotChange}"></slot>
199
+ </div>
200
+ </div>
201
+
202
+ ${hasFooterSlot ? html`
203
+ <slot name="footer" class="panel__footer"></slot>` : null}
204
+ </div>
205
+ </div>`;
206
+ }
207
+ }
@@ -0,0 +1,8 @@
1
+ :host {
2
+ display: block;
3
+ }
4
+
5
+ .translation-group__languages {
6
+ display: flex;
7
+ align-items: center;
8
+ }
@@ -1,16 +1,18 @@
1
- import { classMap } from 'lit/directives/class-map.js';
2
- import { FormControlController, validValidityState } from '../../internal/form';
3
- import { HasSlotController } from '../../internal/slot';
4
- import type { PropertyValues } from 'lit';
5
- import { html, nothing, unsafeCSS } from 'lit';
6
- import { property, state } from 'lit/decorators.js';
7
- import type { ZincFormControl } from '../../internal/zinc-element';
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, nothing, unsafeCSS} from 'lit';
5
+ import {keyed} from 'lit/directives/keyed.js';
6
+ import {live} from 'lit/directives/live.js';
7
+ import {property, state} from 'lit/decorators.js';
8
8
  import ZincElement from '../../internal/zinc-element';
9
9
  import ZnInlineEdit from '../inline-edit';
10
10
  import ZnInput from '../input';
11
11
  import ZnNavbar from '../navbar';
12
- import type { ZnMenuSelectEvent } from '../../events/zn-menu-select';
13
- import type { ZnSelectEvent } from "../../events/zn-select";
12
+ import type {PropertyValues} from 'lit';
13
+ import type {ZincFormControl} from '../../internal/zinc-element';
14
+ import type {ZnMenuSelectEvent} from '../../events/zn-menu-select';
15
+ import type {ZnSelectEvent} from "../../events/zn-select";
14
16
 
15
17
  import styles from './translations.scss';
16
18
 
@@ -28,14 +30,17 @@ export default class ZnTranslations extends ZincElement implements ZincFormContr
28
30
  @property() name = '';
29
31
  @property() value = '{"en":""}';
30
32
  @property() label: string = '';
31
- @property({ type: Boolean, reflect: true }) disabled = false;
32
- @property({ type: Boolean, reflect: true }) required = false;
33
- @property({ type: Boolean, reflect: true }) flush = false;
33
+ @property({type: Boolean, reflect: true}) disabled = false;
34
+ @property({type: Boolean, reflect: true}) required = false;
35
+ @property({type: Boolean, reflect: true}) flush = false;
34
36
 
35
- @property({ type: Object }) languages: Record<string, string> = {
37
+ /** When true, hides the individual language navbar and defers language control to a parent zn-translation-group. */
38
+ @property({type: Boolean, reflect: true}) grouped = false;
39
+
40
+ @property({type: Object}) languages: Record<string, string> = {
36
41
  'en': 'EN'
37
42
  };
38
- @property({ type: Object }) values: Record<string, string> = {};
43
+ @property({type: Object}) values: Record<string, string> = {};
39
44
 
40
45
  @state() private _activeLanguage = 'en';
41
46
 
@@ -63,6 +68,31 @@ export default class ZnTranslations extends ZincElement implements ZincFormContr
63
68
  // no-op
64
69
  }
65
70
 
71
+ /** Sets the active language externally. Used by zn-translation-group. */
72
+ public setActiveLanguage(language: string) {
73
+ this.addLanguageKey(language);
74
+ this._activeLanguage = language;
75
+ this.requestUpdate();
76
+ }
77
+
78
+ /** Returns the currently active language. */
79
+ public getActiveLanguage(): string {
80
+ return this._activeLanguage;
81
+ }
82
+
83
+ /** Adds a language key to this component's values if not already present. Used by zn-translation-group. */
84
+ public addLanguageKey(languageCode: string) {
85
+ if (!Object.prototype.hasOwnProperty.call(this.values, languageCode)) {
86
+ this.values = {...this.values, [languageCode]: ''};
87
+ this.updateValue();
88
+ }
89
+ }
90
+
91
+ /** Returns all language codes that have values. */
92
+ public getValueLanguages(): string[] {
93
+ return Object.keys(this.values);
94
+ }
95
+
66
96
  protected firstUpdated() {
67
97
  this.formControlController.updateValidity();
68
98
  }
@@ -100,13 +130,17 @@ export default class ZnTranslations extends ZincElement implements ZincFormContr
100
130
  if (processValues) {
101
131
  this.value = JSON.stringify(this.values);
102
132
 
103
- // Ensure active language is valid
104
- if (!this._activeLanguage || (!Object.prototype.hasOwnProperty.call(this.values, this._activeLanguage) && this._activeLanguage !== 'en')) {
105
- const keys = Object.keys(this.values);
106
- if (keys.length > 0) {
107
- this._activeLanguage = keys[0];
108
- } else {
109
- this._activeLanguage = 'en';
133
+ // Ensure active language is valid, but only when NOT grouped.
134
+ // In grouped mode the parent zn-translation-group manages the active language,
135
+ // so we must not override what it set via setActiveLanguage().
136
+ if (!this.grouped) {
137
+ if (!this._activeLanguage || (!Object.prototype.hasOwnProperty.call(this.values, this._activeLanguage) && this._activeLanguage !== 'en')) {
138
+ const keys = Object.keys(this.values);
139
+ if (keys.length > 0) {
140
+ this._activeLanguage = keys[0];
141
+ } else {
142
+ this._activeLanguage = 'en';
143
+ }
110
144
  }
111
145
  }
112
146
  }
@@ -117,7 +151,7 @@ export default class ZnTranslations extends ZincElement implements ZincFormContr
117
151
  const languageCode = element.getAttribute('data-path');
118
152
  if (languageCode) {
119
153
  // Add new language with empty string
120
- this.values = { ...this.values, [languageCode]: '' };
154
+ this.values = {...this.values, [languageCode]: ''};
121
155
  this._activeLanguage = languageCode;
122
156
  this.updateValue();
123
157
  }
@@ -140,7 +174,7 @@ export default class ZnTranslations extends ZincElement implements ZincFormContr
140
174
  if (this._activeLanguage) {
141
175
  const newValue: string = target.value as string;
142
176
  if (newValue !== this.values[this._activeLanguage]) {
143
- this.values = { ...this.values, [this._activeLanguage]: newValue };
177
+ this.values = {...this.values, [this._activeLanguage]: newValue};
144
178
  this.updateValue();
145
179
  }
146
180
  }
@@ -170,6 +204,11 @@ export default class ZnTranslations extends ZincElement implements ZincFormContr
170
204
  this.formControlController.submit();
171
205
  };
172
206
 
207
+ private isRTLLanguage(languageCode: string): boolean {
208
+ // Check if language is Arabic or Hebrew (including variants)
209
+ return languageCode.startsWith('ar') || languageCode === 'he' || languageCode === 'iw';
210
+ }
211
+
173
212
  render() {
174
213
  const availableLanguages = Object.entries(this.languages)
175
214
  .filter(([code]) => code !== 'en' && !Object.prototype.hasOwnProperty.call(this.values, code))
@@ -190,7 +229,8 @@ export default class ZnTranslations extends ZincElement implements ZincFormContr
190
229
  tab: code
191
230
  }));
192
231
 
193
- const currentTranslation = this.values[this._activeLanguage];
232
+ const currentTranslation = this.values[this._activeLanguage] ?? '';
233
+ const isRTL = this.isRTLLanguage(this._activeLanguage);
194
234
 
195
235
  const hasLabelSlot = this.hasSlotController.test('label');
196
236
  const hasLabel = this.label ? true : hasLabelSlot;
@@ -199,6 +239,7 @@ export default class ZnTranslations extends ZincElement implements ZincFormContr
199
239
  <div part="form-control"
200
240
  class="${classMap({
201
241
  'translations': true,
242
+ 'translations--grouped': this.grouped,
202
243
  'form-control': true,
203
244
  'form-control--medium': true,
204
245
  'form-control--has-label': hasLabel,
@@ -209,27 +250,32 @@ export default class ZnTranslations extends ZincElement implements ZincFormContr
209
250
  <slot name="label">${this.label}</slot>
210
251
  </label>
211
252
 
212
- <zn-navbar
213
- .navigation="${navigation}"
214
- .dropdown="${availableLanguages}"
215
- name="${this.name}-translations-navbar"
216
- @zn-select="${this.handleNavbarClick}"
217
- @zn-menu-select="${this.handleLanguageAdd}"
218
- flush=${this.flush || nothing}
219
- isolated
220
- manual-add-items
221
- >
222
- <slot name="expand" slot="expand"></slot>
223
- </zn-navbar>
253
+ ${!this.grouped ? html`
254
+ <zn-navbar
255
+ .navigation="${navigation}"
256
+ .dropdown="${availableLanguages}"
257
+ name="${this.name}-translations-navbar"
258
+ @zn-select="${this.handleNavbarClick}"
259
+ @zn-menu-select="${this.handleLanguageAdd}"
260
+ flush=${this.flush || nothing}
261
+ isolated
262
+ manual-add-items
263
+ >
264
+ <slot name="expand" slot="expand"></slot>
265
+ </zn-navbar>
266
+ ` : nothing}
224
267
  <div class="input-container">
225
- <zn-inline-edit
226
- .value=${currentTranslation}
227
- name="${this.name}"
228
- placeholder="Enter translation..."
229
- @zn-change="${this.handleValueUpdate}"
230
- @zn-input="${this.handleValueUpdate}"
231
- @zn-submit="${this.handleSubmit}"
232
- ></zn-inline-edit>
268
+ ${keyed(this._activeLanguage, html`
269
+ <zn-inline-edit
270
+ .value=${live(currentTranslation)}
271
+ name="${this.name}"
272
+ placeholder="Enter translation..."
273
+ dir="${isRTL ? 'rtl' : 'ltr'}"
274
+ @zn-change="${this.handleValueUpdate}"
275
+ @zn-input="${this.handleValueUpdate}"
276
+ @zn-submit="${this.handleSubmit}"
277
+ ></zn-inline-edit>
278
+ `)}
233
279
  </div>
234
280
  </div>
235
281
  `;
@@ -11,6 +11,10 @@
11
11
  gap: var(--zn-spacing-3x-small);
12
12
  }
13
13
 
14
+ .translations--grouped {
15
+ padding: 0;
16
+ }
17
+
14
18
  .input-container {
15
19
  padding: var(--zn-spacing-small) 0;
16
20
  }
@@ -5,21 +5,26 @@ import ZincElement from '../../internal/zinc-element';
5
5
  import styles from './vertical-stepper.scss';
6
6
 
7
7
  /**
8
- * @summary Short summary of the component's intended use.
8
+ * @summary Vertical steppers display a sequence of steps in a vertical layout with descriptions and optional icons.
9
9
  * @documentation https://zinc.style/components/vertical-stepper
10
10
  * @status experimental
11
11
  * @since 1.0
12
12
  *
13
- * @dependency zn-example
13
+ * @property {boolean} last - When true, removes the connecting line below this step (use for the final step in a sequence).
14
+ * @property {boolean} first - When true, indicates this is the first step in the sequence (affects visual styling).
15
+ * @property {boolean} active - When true, highlights this step as the current active step in the process.
16
+ * @property {string} description - A descriptive text explaining what happens in this step or its current status.
17
+ * @property {string} caption - The main label/title for this step.
14
18
  *
15
- * @event zn-event-name - Emitted as an example.
19
+ * @slot icon - Optional slot for adding an icon or indicator before the step content.
16
20
  *
17
- * @slot - The default slot.
18
- * @slot example - An example slot.
19
- *
20
- * @csspart base - The component's base wrapper.
21
- *
22
- * @cssproperty --example - An example CSS custom property.
21
+ * @csspart vs - The main container for the vertical stepper.
22
+ * @csspart vs__left - The left section containing the icon and connecting line.
23
+ * @csspart vs__icon - The icon container.
24
+ * @csspart vs__line - The vertical connecting line between steps.
25
+ * @csspart vs__right - The right section containing caption and description text.
26
+ * @csspart vs__caption - The caption/title text element.
27
+ * @csspart vs__description - The description text element.
23
28
  */
24
29
  export default class ZnVerticalStepper extends ZincElement {
25
30
  static styles: CSSResultGroup = unsafeCSS(styles);
@@ -1,7 +1,12 @@
1
- export type { ZnAfterHideEvent } from './zn-after-hide';
2
- export type { ZnAfterShowEvent } from './zn-after-show';
3
- export type { ZnHideEvent } from './zn-hide';
4
- export type { ZnBlurEvent } from './zn-blur';
5
- export type { ZnFocusEvent } from './zn-focus';
6
- export type { ZnInputEvent } from './zn-input';
7
- export type { ZnShowEvent } from './zn-show';
1
+ export type {ZnAfterHideEvent} from './zn-after-hide';
2
+ export type {ZnAfterShowEvent} from './zn-after-show';
3
+ export type {ZnHideEvent} from './zn-hide';
4
+ export type {ZnBlurEvent} from './zn-blur';
5
+ export type {ZnFocusEvent} from './zn-focus';
6
+ export type {ZnInputEvent} from './zn-input';
7
+ export type {ZnShowEvent} from './zn-show';
8
+ export type {ZnPurchaseEvent} from './zn-purchase';
9
+ export type {ZnRedirectEvent} from './zn-redirect';
10
+ export type {ZnSearchChangeEvent} from './zn-search-change';
11
+ export type {ZnLanguageChangeEvent} from './zn-language-change';
12
+ export type {ZnReorderEvent} from './zn-reorder';
@@ -0,0 +1,7 @@
1
+ export type ZnLanguageChangeEvent = CustomEvent<{ language: string }>;
2
+
3
+ declare global {
4
+ interface GlobalEventHandlersEventMap {
5
+ 'zn-language-change': ZnLanguageChangeEvent;
6
+ }
7
+ }
@@ -0,0 +1,11 @@
1
+ export type ZnPurchaseEvent = CustomEvent<{
2
+ value: string;
3
+ setSuccess: () => void;
4
+ setFailure: (message?: string) => void;
5
+ }>;
6
+
7
+ declare global {
8
+ interface GlobalEventHandlersEventMap {
9
+ 'zn-purchase': ZnPurchaseEvent;
10
+ }
11
+ }
@@ -0,0 +1,7 @@
1
+ export type ZnRedirectEvent = CustomEvent<{ url: string }>;
2
+
3
+ declare global {
4
+ interface GlobalEventHandlersEventMap {
5
+ 'zn-redirect': ZnRedirectEvent;
6
+ }
7
+ }