@synergy-design-system/mcp 2.6.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/utilities/storybook/scraper.js +14 -3
  3. package/metadata/checksum.txt +1 -1
  4. package/metadata/packages/components/components/syn-checkbox/component.angular.ts +13 -0
  5. package/metadata/packages/components/components/syn-checkbox/component.styles.ts +99 -39
  6. package/metadata/packages/components/components/syn-checkbox/component.ts +13 -10
  7. package/metadata/packages/components/components/syn-checkbox/component.vue +5 -0
  8. package/metadata/packages/components/components/syn-combobox/component.angular.ts +13 -0
  9. package/metadata/packages/components/components/syn-combobox/component.styles.ts +216 -193
  10. package/metadata/packages/components/components/syn-combobox/component.ts +68 -39
  11. package/metadata/packages/components/components/syn-combobox/component.vue +5 -0
  12. package/metadata/packages/components/components/syn-file/component.angular.ts +13 -0
  13. package/metadata/packages/components/components/syn-file/component.styles.ts +20 -3
  14. package/metadata/packages/components/components/syn-file/component.ts +19 -5
  15. package/metadata/packages/components/components/syn-file/component.vue +5 -0
  16. package/metadata/packages/components/components/syn-input/component.ts +1 -2
  17. package/metadata/packages/components/components/syn-prio-nav/component.ts +2 -1
  18. package/metadata/packages/components/components/syn-radio/component.angular.ts +13 -0
  19. package/metadata/packages/components/components/syn-radio/component.styles.ts +91 -29
  20. package/metadata/packages/components/components/syn-radio/component.ts +19 -10
  21. package/metadata/packages/components/components/syn-radio/component.vue +5 -0
  22. package/metadata/packages/components/components/syn-radio-group/component.styles.ts +30 -9
  23. package/metadata/packages/components/components/syn-radio-group/component.ts +61 -32
  24. package/metadata/packages/components/components/syn-range/component.angular.ts +13 -0
  25. package/metadata/packages/components/components/syn-range/component.styles.ts +27 -3
  26. package/metadata/packages/components/components/syn-range/component.ts +17 -5
  27. package/metadata/packages/components/components/syn-range/component.vue +5 -0
  28. package/metadata/packages/components/components/syn-select/component.angular.ts +13 -0
  29. package/metadata/packages/components/components/syn-select/component.styles.ts +222 -151
  30. package/metadata/packages/components/components/syn-select/component.ts +30 -15
  31. package/metadata/packages/components/components/syn-select/component.vue +5 -0
  32. package/metadata/packages/components/components/syn-switch/component.angular.ts +13 -0
  33. package/metadata/packages/components/components/syn-switch/component.styles.ts +145 -63
  34. package/metadata/packages/components/components/syn-switch/component.ts +16 -4
  35. package/metadata/packages/components/components/syn-switch/component.vue +5 -0
  36. package/metadata/packages/components/components/syn-textarea/component.styles.ts +55 -27
  37. package/metadata/packages/components/components/syn-textarea/component.ts +1 -3
  38. package/metadata/packages/components/static/CHANGELOG.md +38 -0
  39. package/metadata/packages/tokens/CHANGELOG.md +24 -0
  40. package/metadata/packages/tokens/dark.css +7 -1
  41. package/metadata/packages/tokens/index.js +31 -1
  42. package/metadata/packages/tokens/light.css +7 -1
  43. package/metadata/packages/tokens/sick2018_dark.css +7 -1
  44. package/metadata/packages/tokens/sick2018_light.css +7 -1
  45. package/metadata/packages/tokens/sick2025_dark.css +7 -1
  46. package/metadata/packages/tokens/sick2025_light.css +7 -1
  47. package/metadata/static/components/syn-checkbox/docs.md +36 -0
  48. package/metadata/static/components/syn-combobox/docs.md +138 -0
  49. package/metadata/static/components/syn-file/docs.md +24 -0
  50. package/metadata/static/components/syn-input/docs.md +1 -1
  51. package/metadata/static/components/syn-radio/docs.md +21 -0
  52. package/metadata/static/components/syn-radio-group/docs.md +46 -0
  53. package/metadata/static/components/syn-range/docs.md +19 -0
  54. package/metadata/static/components/syn-select/docs.md +81 -0
  55. package/metadata/static/components/syn-switch/docs.md +22 -0
  56. package/metadata/static/components/syn-textarea/docs.md +1 -1
  57. package/metadata/static/components/syn-tooltip/docs.md +73 -0
  58. package/package.json +4 -4
  59. package/metadata/packages/components/components/syn-checkbox/component.custom.styles.ts +0 -86
  60. package/metadata/packages/components/components/syn-combobox/component.custom.styles.ts +0 -122
  61. package/metadata/packages/components/components/syn-radio/component.custom.styles.ts +0 -86
  62. package/metadata/packages/components/components/syn-radio-group/component.custom.styles.ts +0 -25
  63. package/metadata/packages/components/components/syn-select/component.custom.styles.ts +0 -175
  64. package/metadata/packages/components/components/syn-switch/component.custom.styles.ts +0 -141
  65. package/metadata/packages/components/components/syn-textarea/component.custom.styles.ts +0 -48
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#1189](https://github.com/synergy-design-system/synergy-design-system/pull/1189) [`a4f49ac`](https://github.com/synergy-design-system/synergy-design-system/commit/a4f49ac79a660ef5b8d1b380fe9fcd2159dc9b78) Thanks [@schilchSICKAG](https://github.com/schilchSICKAG)! - Released on: 2026-02-26
8
+
9
+ feat: ✨ Added readonly for various form fields (#1171, #1172, #1173, #1174, #1175, #1176, #1177, #1178)
10
+
11
+ Applies to:
12
+ - `<syn-checkbox>`
13
+ - `<syn-combobox>`
14
+ - `<syn-file>`
15
+ - `<syn-radio>`
16
+ - `<syn-radio-group>`
17
+ - `<syn-range>`
18
+ - `<syn-select>`
19
+ - `<syn-switch>`
20
+
21
+ Form elements now support being displayed as `readonly` fields.
22
+
23
+ Field marked `readonly` may receive focus, but their value cannot be changed by customer inputs.
24
+
25
+ ## 2.6.1
26
+
27
+ ### Patch Changes
28
+
29
+ - [#1196](https://github.com/synergy-design-system/synergy-design-system/pull/1196) [`6a9b934`](https://github.com/synergy-design-system/synergy-design-system/commit/6a9b9349f6404a638fadd842e3f2fd8216fd81cd) Thanks [@kirchsuSICKAG](https://github.com/kirchsuSICKAG)! - Released on: 2026-02-25
30
+
31
+ fix: 🐛 prio nav with only one item (#1195)
32
+
3
33
  ## 2.6.0
4
34
 
5
35
  ### Minor Changes
@@ -65,11 +65,20 @@ export class StorybookScraper {
65
65
  // Extract the stories metadata first
66
66
  // We get basic info and identify stories that need iframe content
67
67
  const rawStoryMetadata = await page.evaluate(() => Array.from(document.querySelectorAll('.sb-anchor'))
68
+ // eslint-disable-next-line complexity
68
69
  .map((story, index) => {
69
70
  const description = story.querySelector(':scope > p')?.textContent || '';
70
- const exampleSource = story.querySelector('.sb-story #root-inner')?.innerHTML || '';
71
71
  const heading = story.querySelector('h3')?.textContent || '';
72
72
  const hasIframe = !!story.querySelector('.sb-story iframe');
73
+ let exampleSource = '';
74
+ if (!hasIframe) {
75
+ // #1152: The example source is usually in the #root-inner element.
76
+ // However, for at least one story (tag-group-template), the #root-inner container is missing.
77
+ // I am not sure why, but I think a fallback would be just to check the first element for the time being.
78
+ const exampleWithRoot = story.querySelector('.sb-story #root-inner')?.innerHTML || '';
79
+ const exampleWithoutRoot = story.querySelector('.sb-story > div')?.innerHTML || '';
80
+ exampleSource = exampleWithRoot || exampleWithoutRoot;
81
+ }
73
82
  return {
74
83
  description,
75
84
  exampleSource,
@@ -94,14 +103,16 @@ export class StorybookScraper {
94
103
  if (!exampleSource && storyMeta.hasIframe) {
95
104
  try {
96
105
  const storySection = page.locator('.sb-anchor').nth(storyMeta.index);
106
+ // Storybook uses lazy loading, so the iframe may not be loaded until we scroll it into view
107
+ await storySection.scrollIntoViewIfNeeded();
108
+ await page.waitForTimeout(1000);
97
109
  const frame = storySection.frameLocator('iframe');
98
110
  const frameContent = await frame.locator('#root-inner').innerHTML();
99
111
  exampleSource = frameContent || '';
100
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
101
112
  }
102
113
  catch (error) {
103
114
  // If iframe content extraction fails, continue with empty content
104
- console.log(`Failed to extract iframe content for story "${storyMeta.heading}"`);
115
+ console.log(`Failed to extract iframe content for story "${storyMeta.heading}"`, error);
105
116
  }
106
117
  }
107
118
  // Replace all lit internal comments
@@ -1 +1 @@
1
- b0413e89368486e50f5f493fa46fe72b
1
+ 8ed433601cf1c2dfa44ffdbdd527f2bf
@@ -154,6 +154,19 @@ export class SynCheckboxComponent {
154
154
  return this.nativeElement.disabled;
155
155
  }
156
156
 
157
+ /**
158
+ * Sets the checkbox to a readonly state.
159
+ */
160
+ @Input()
161
+ set readonly(v: '' | SynCheckbox['readonly']) {
162
+ this._ngZone.runOutsideAngular(
163
+ () => (this.nativeElement.readonly = v === '' || v),
164
+ );
165
+ }
166
+ get readonly(): SynCheckbox['readonly'] {
167
+ return this.nativeElement.readonly;
168
+ }
169
+
157
170
  /**
158
171
  * Draws the checkbox in a checked state.
159
172
  */
@@ -2,79 +2,88 @@
2
2
  import { css } from 'lit';
3
3
 
4
4
  export default css`
5
- /* stylelint-disable */
5
+ /* stylelint-disable no-descending-specificity */
6
6
  :host {
7
7
  display: inline-block;
8
8
  }
9
9
 
10
10
  .checkbox {
11
- position: relative;
12
- display: inline-flex;
13
11
  align-items: flex-start;
12
+ color: var(--syn-input-label-color);
13
+ cursor: pointer;
14
+ display: inline-flex;
14
15
  font-family: var(--syn-input-font-family);
15
16
  font-weight: var(--syn-input-font-weight);
16
- color: var(--syn-input-label-color);
17
+ padding: var(--syn-spacing-2x-small) 0; /* #1083: This adds spacing around multi-line labels */
18
+ position: relative;
17
19
  vertical-align: middle;
18
- cursor: pointer;
19
20
  }
20
21
 
21
22
  .checkbox--small {
22
23
  --toggle-size: var(--syn-toggle-size-small);
24
+
23
25
  font-size: var(--syn-input-font-size-small);
26
+ padding: var(--syn-spacing-3x-small) 0;
24
27
  }
25
28
 
26
29
  .checkbox--medium {
27
30
  --toggle-size: var(--syn-toggle-size-medium);
31
+
28
32
  font-size: var(--syn-input-font-size-medium);
29
33
  }
30
34
 
31
35
  .checkbox--large {
32
36
  --toggle-size: var(--syn-toggle-size-large);
37
+
33
38
  font-size: var(--syn-input-font-size-large);
34
39
  }
35
40
 
36
41
  .checkbox__control {
37
- flex: 0 0 auto;
38
- position: relative;
39
- display: inline-flex;
40
42
  align-items: center;
41
- justify-content: center;
42
- width: var(--toggle-size);
43
- height: var(--toggle-size);
44
- border: solid var(--syn-input-border-width) var(--syn-input-border-color);
45
- border-radius: 2px;
46
43
  background-color: var(--syn-input-background-color);
44
+ border: solid var(--syn-input-border-width) var(--syn-input-border-color);
45
+ border-radius: var(--syn-checkbox-border-radius);
47
46
  color: var(--syn-color-neutral-0);
47
+ display: inline-flex;
48
+ flex: 0 0 auto;
49
+ height: var(--toggle-size);
50
+ justify-content: center;
51
+ margin: 0.1em 0; /* #1083: This adds spacing around multi-line labels */
52
+ position: relative;
48
53
  transition:
49
54
  var(--syn-transition-fast) border-color,
50
55
  var(--syn-transition-fast) background-color,
51
56
  var(--syn-transition-fast) color,
52
57
  var(--syn-transition-fast) box-shadow;
58
+ width: var(--toggle-size);
53
59
  }
54
60
 
55
61
  .checkbox__input {
56
- position: absolute;
62
+ margin: 0;
57
63
  opacity: 0;
58
64
  padding: 0;
59
- margin: 0;
60
65
  pointer-events: none;
66
+ position: absolute;
61
67
  }
62
68
 
63
69
  .checkbox__checked-icon,
64
70
  .checkbox__indeterminate-icon {
65
71
  display: inline-flex;
66
- width: var(--toggle-size);
67
72
  height: var(--toggle-size);
73
+ width: var(--toggle-size);
68
74
  }
69
75
 
70
- /* Hover */
71
- .checkbox:not(.checkbox--checked):not(.checkbox--disabled) .checkbox__control:hover {
72
- border-color: var(--syn-input-border-color-hover);
76
+ /**
77
+ * Hover
78
+ * Applies the hover state to the whole component
79
+ */
80
+ .checkbox:not(.checkbox--checked):not(.checkbox--disabled):not(.checkbox--readonly):hover .checkbox__control {
73
81
  background-color: var(--syn-input-background-color-hover);
82
+ border-color: var(--syn-input-border-color-hover);
74
83
  }
75
84
 
76
85
  /* Focus */
77
- .checkbox:not(.checkbox--checked):not(.checkbox--disabled) .checkbox__input:focus-visible ~ .checkbox__control {
86
+ .checkbox:not(.checkbox--disabled):not(.checkbox--readonly) .checkbox__input:focus-visible ~ .checkbox__control {
78
87
  outline: var(--syn-focus-ring);
79
88
  outline-offset: var(--syn-focus-ring-offset);
80
89
  }
@@ -82,42 +91,93 @@ export default css`
82
91
  /* Checked/indeterminate */
83
92
  .checkbox--checked .checkbox__control,
84
93
  .checkbox--indeterminate .checkbox__control {
85
- border-color: var(--syn-color-primary-600);
86
- background-color: var(--syn-color-primary-600);
94
+ background-color: var(--syn-interactive-emphasis-color);
95
+ border-color: var(--syn-interactive-emphasis-color);
87
96
  }
88
97
 
89
- /* Checked/indeterminate + hover */
90
- .checkbox.checkbox--checked:not(.checkbox--disabled) .checkbox__control:hover,
91
- .checkbox.checkbox--indeterminate:not(.checkbox--disabled) .checkbox__control:hover {
92
- border-color: var(--syn-color-primary-500);
93
- background-color: var(--syn-color-primary-500);
98
+ /**
99
+ * Checked/indeterminate + hover
100
+ * Applies the hover state to the whole component
101
+ */
102
+ .checkbox.checkbox--checked:not(.checkbox--disabled):not(.checkbox--readonly):hover .checkbox__control,
103
+ .checkbox.checkbox--indeterminate:not(.checkbox--disabled):not(.checkbox--readonly):hover .checkbox__control {
104
+ background-color: var(--syn-interactive-emphasis-color-hover);
105
+ border-color: var(--syn-interactive-emphasis-color-hover);
94
106
  }
95
107
 
96
- /* Checked/indeterminate + focus */
97
- .checkbox.checkbox--checked:not(.checkbox--disabled) .checkbox__input:focus-visible ~ .checkbox__control,
98
- .checkbox.checkbox--indeterminate:not(.checkbox--disabled) .checkbox__input:focus-visible ~ .checkbox__control {
99
- outline: var(--syn-focus-ring);
100
- outline-offset: var(--syn-focus-ring-offset);
108
+ /*
109
+ * #443: Add active styles
110
+ * The checked and unchecked states have different active colors
111
+ * Note the fallback is defined to match the hover color.
112
+ * This is done to make sure no active state is shown at all if no active color is defined.
113
+ * Still better than showing one for the unchecked state but not for the checked state.
114
+ */
115
+ .checkbox:not(.checkbox--checked):not(.checkbox--disabled):not(.checkbox--readonly):active .checkbox__control {
116
+ border-color: var(--syn-input-border-color-active);
101
117
  }
102
118
 
103
- /* Disabled */
119
+ /* Checked/indeterminate */
120
+ .checkbox.checkbox--checked:not(.checkbox--disabled):not(.checkbox--readonly):active .checkbox__control,
121
+ .checkbox.checkbox--indeterminate:not(.checkbox--disabled):not(.checkbox--readonly):active .checkbox__control {
122
+ background: var(--syn-interactive-emphasis-color-active);
123
+ border-color: var(--syn-interactive-emphasis-color-active);
124
+ }
125
+
126
+ /** #429: Use token for opacity */
104
127
  .checkbox--disabled {
105
- opacity: 0.5;
106
128
  cursor: not-allowed;
129
+ opacity: var(--syn-input-disabled-opacity);
107
130
  }
108
131
 
109
132
  .checkbox__label {
110
- display: inline-block;
133
+ align-self: center;
111
134
  color: var(--syn-input-label-color);
112
- line-height: var(--toggle-size);
113
- margin-inline-start: 0.5em;
135
+ display: inline-block;
136
+ line-height: var(--syn-line-height-normal);
137
+ margin-inline-start: var(--syn-spacing-x-small);
114
138
  user-select: none;
115
- -webkit-user-select: none;
116
139
  }
117
140
 
118
141
  :host([required]) .checkbox__label::after {
119
- content: var(--syn-input-required-content);
120
142
  color: var(--syn-input-required-content-color);
143
+ content: var(--syn-input-required-content);
121
144
  margin-inline-start: var(--syn-input-required-content-offset);
122
145
  }
146
+
147
+ :host([data-user-invalid]) .checkbox__control {
148
+ background: var(--syn-input-border-color-focus-error);
149
+ border-color: var(--syn-input-border-color-focus-error);
150
+ }
151
+
152
+ /**
153
+ * #943: When invalid, use a transparent background if not checked or indeterminate
154
+ */
155
+ :host([data-user-invalid]:not([checked]):not([indeterminate])) .checkbox__control {
156
+ background: transparent;
157
+ }
158
+
159
+ /**
160
+ * #1171: Readonly state
161
+ */
162
+ .checkbox.checkbox--readonly {
163
+ cursor: default;
164
+ }
165
+
166
+ .checkbox.checkbox--readonly .checkbox__label {
167
+ /* stylelint-disable-next-line property-no-vendor-prefix */
168
+ -webkit-user-select: auto;
169
+ user-select: auto;
170
+ }
171
+
172
+ .checkbox.checkbox--readonly .checkbox__control {
173
+ background: var(--syn-input-readonly-background-color);
174
+ border-color: var(--syn-input-readonly-background-color);
175
+ color: var(--syn-readonly-indicator-color);
176
+ cursor: default;
177
+ }
178
+
179
+ .checkbox.checkbox--readonly .checkbox__input:focus ~ .checkbox__control {
180
+ outline: var(--syn-focus-ring);
181
+ outline-offset: var(--syn-focus-ring-offset);
182
+ }
123
183
  `;
@@ -6,15 +6,13 @@ import { HasSlotController } from '../../internal/slot.js';
6
6
  import { html } from 'lit';
7
7
  import { ifDefined } from 'lit/directives/if-defined.js';
8
8
  import { live } from 'lit/directives/live.js';
9
- import { property, query, state } from 'lit/decorators.js';
9
+ import { property, query } from 'lit/decorators.js';
10
10
  import { watch } from '../../internal/watch.js';
11
11
  import componentStyles from '../../styles/component.styles.js';
12
12
  import formControlStyles from '../../styles/form-control.styles.js';
13
- import formControlCustomStyles from '../../styles/form-control.custom.styles.js';
14
13
  import SynergyElement from '../../internal/synergy-element.js';
15
14
  import SynIcon from '../icon/icon.component.js';
16
15
  import styles from './checkbox.styles.js';
17
- import customStyles from './checkbox.custom.styles.js';
18
16
  import type { CSSResultGroup } from 'lit';
19
17
  import type { SynergyFormControl } from '../../internal/synergy-element.js';
20
18
  import { enableDefaultSettings } from '../../utilities/defaultSettings/decorator.js';
@@ -47,7 +45,7 @@ import { enableDefaultSettings } from '../../utilities/defaultSettings/decorator
47
45
  */
48
46
  @enableDefaultSettings('SynCheckbox')
49
47
  export default class SynCheckbox extends SynergyElement implements SynergyFormControl {
50
- static styles: CSSResultGroup = [componentStyles, formControlStyles, styles, formControlCustomStyles, customStyles];
48
+ static styles: CSSResultGroup = [componentStyles, formControlStyles, styles];
51
49
  static dependencies = { 'syn-icon': SynIcon };
52
50
 
53
51
  private readonly formControlController = new FormControlController(this, {
@@ -59,8 +57,6 @@ export default class SynCheckbox extends SynergyElement implements SynergyFormCo
59
57
 
60
58
  @query('input[type="checkbox"]') input: HTMLInputElement;
61
59
 
62
- @state() private hasFocus = false;
63
-
64
60
  @property({ reflect: true }) title = ''; // make reactive to pass through
65
61
 
66
62
  /** The name of the checkbox, submitted as a name/value pair with form data. */
@@ -75,6 +71,9 @@ export default class SynCheckbox extends SynergyElement implements SynergyFormCo
75
71
  /** Disables the checkbox. */
76
72
  @property({ type: Boolean, reflect: true }) disabled = false;
77
73
 
74
+ /** Sets the checkbox to a readonly state. */
75
+ @property({ type: Boolean, reflect: true }) readonly = false;
76
+
78
77
  /** Draws the checkbox in a checked state. */
79
78
  @property({ type: Boolean, reflect: true }) checked = false;
80
79
 
@@ -114,14 +113,18 @@ export default class SynCheckbox extends SynergyElement implements SynergyFormCo
114
113
  this.formControlController.updateValidity();
115
114
  }
116
115
 
117
- private handleClick() {
116
+ private handleClick(e: MouseEvent) {
117
+ if (this.readonly) {
118
+ e.preventDefault();
119
+ return;
120
+ }
121
+
118
122
  this.checked = !this.checked;
119
123
  this.indeterminate = false;
120
124
  this.emit('syn-change');
121
125
  }
122
126
 
123
127
  private handleBlur() {
124
- this.hasFocus = false;
125
128
  this.emit('syn-blur');
126
129
  }
127
130
 
@@ -135,7 +138,6 @@ export default class SynCheckbox extends SynergyElement implements SynergyFormCo
135
138
  }
136
139
 
137
140
  private handleFocus() {
138
- this.hasFocus = true;
139
141
  this.emit('syn-focus');
140
142
  }
141
143
 
@@ -216,7 +218,7 @@ export default class SynCheckbox extends SynergyElement implements SynergyFormCo
216
218
  checkbox: true,
217
219
  'checkbox--checked': this.checked,
218
220
  'checkbox--disabled': this.disabled,
219
- 'checkbox--focused': this.hasFocus,
221
+ 'checkbox--readonly': this.readonly,
220
222
  'checkbox--indeterminate': this.indeterminate,
221
223
  'checkbox--small': this.size === 'small',
222
224
  'checkbox--medium': this.size === 'medium',
@@ -232,6 +234,7 @@ export default class SynCheckbox extends SynergyElement implements SynergyFormCo
232
234
  .indeterminate=${live(this.indeterminate)}
233
235
  .checked=${live(this.checked)}
234
236
  .disabled=${this.disabled}
237
+ .readOnly=${this.readonly}
235
238
  .required=${this.required}
236
239
  aria-checked=${this.checked ? 'true' : 'false'}
237
240
  aria-describedby="help-text"
@@ -72,6 +72,11 @@ const props = defineProps<{
72
72
  */
73
73
  disabled?: SynCheckbox['disabled'];
74
74
 
75
+ /**
76
+ * Sets the checkbox to a readonly state.
77
+ */
78
+ readonly?: SynCheckbox['readonly'];
79
+
75
80
  /**
76
81
  * Draws the checkbox in a checked state.
77
82
  */
@@ -212,6 +212,19 @@ export class SynComboboxComponent {
212
212
  return this.nativeElement.disabled;
213
213
  }
214
214
 
215
+ /**
216
+ * Sets the combobox to a readonly state.
217
+ */
218
+ @Input()
219
+ set readonly(v: '' | SynCombobox['readonly']) {
220
+ this._ngZone.runOutsideAngular(
221
+ () => (this.nativeElement.readonly = v === '' || v),
222
+ );
223
+ }
224
+ get readonly(): SynCombobox['readonly'] {
225
+ return this.nativeElement.readonly;
226
+ }
227
+
215
228
  /**
216
229
  * Adds a clear button when the combobox is not empty.
217
230
  */