@lmvz-ds/components 0.19.0 → 0.20.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 (103) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/assets/icons/checkmark.svg +4 -0
  3. package/cjs/{aria-loader-CfFuAbJn.js → aria-loader-Cec1zR2g.js} +1 -1
  4. package/cjs/icons-BQASWgk-.js +80 -0
  5. package/cjs/{index--7IqZZqn.js → index-3g9Z9sfF.js} +765 -2854
  6. package/cjs/index.cjs.js +4 -3
  7. package/cjs/lmvz-button.cjs.entry.js +3 -3
  8. package/cjs/lmvz-card.cjs.entry.js +1 -1
  9. package/cjs/lmvz-checkbox.cjs.entry.js +113 -0
  10. package/cjs/lmvz-chip.cjs.entry.js +3 -3
  11. package/cjs/lmvz-components.cjs.js +1 -1
  12. package/cjs/lmvz-header_2.cjs.entry.js +3 -3
  13. package/cjs/lmvz-icon.cjs.entry.js +9 -7
  14. package/cjs/lmvz-input.cjs.entry.js +4 -4
  15. package/cjs/lmvz-menuitem.cjs.entry.js +4 -4
  16. package/cjs/lmvz-select.cjs.entry.js +3 -3
  17. package/cjs/loader.cjs.js +1 -1
  18. package/cjs/{logger-Bn2yoZGP.js → logger-DsM6xg6V.js} +3063 -833
  19. package/cjs/{reactive-controller-host-Bi9eu2bV.js → reactive-controller-host-BA4ZhjKA.js} +1 -1
  20. package/cjs/{icons-Tg7ySOh-.js → svg-BMBduILB.js} +31 -85
  21. package/collection/assets/icons/checkmark.svg +4 -0
  22. package/collection/collection-manifest.json +1 -0
  23. package/collection/components/lmvz-button/lmvz-button.css +1 -2
  24. package/collection/components/lmvz-card/lmvz-card.css +1 -2
  25. package/collection/components/lmvz-checkbox/lmvz-checkbox.css +207 -0
  26. package/collection/components/lmvz-checkbox/lmvz-checkbox.js +424 -0
  27. package/collection/components/lmvz-chip/lmvz-chip.js +1 -1
  28. package/collection/components/lmvz-header/lmvz-header.js +1 -1
  29. package/collection/components/lmvz-icon/lmvz-icon.js +5 -5
  30. package/collection/components/lmvz-input/lmvz-input.js +2 -2
  31. package/collection/components/lmvz-menuitem/lmvz-menuitem.css +1 -1
  32. package/collection/components/lmvz-menuitem/lmvz-menuitem.js +1 -1
  33. package/collection/components/lmvz-select/lmvz-select.js +1 -1
  34. package/collection/integration/header-integration/header-integration.js +1 -1
  35. package/collection/utils/icons/icons.js +2 -13
  36. package/collection/utils/icons/icons.unit.js +3 -15
  37. package/components/index.d.ts +2 -0
  38. package/components/index.d.ts.bak +2 -0
  39. package/components/index.js +1 -1
  40. package/components/lmvz-button.js +1 -1
  41. package/components/lmvz-card.js +1 -1
  42. package/components/lmvz-checkbox.d.ts +11 -0
  43. package/components/lmvz-checkbox.d.ts.bak +11 -0
  44. package/components/lmvz-checkbox.js +1 -0
  45. package/components/lmvz-chip.js +1 -1
  46. package/components/lmvz-header.js +1 -1
  47. package/components/lmvz-icon.js +1 -1
  48. package/components/lmvz-input.js +1 -1
  49. package/components/lmvz-menuitem.js +1 -1
  50. package/components/lmvz-select.js +1 -1
  51. package/components/p-0s99QfRy.js +12 -0
  52. package/components/{p-DbeHBSOe.js → p-BuFx0tTm.js} +1 -1
  53. package/components/p-CGmJG63p.js +1 -0
  54. package/components/p-CcxjkCOx.js +1 -0
  55. package/esm/{aria-loader-CES8Ae1e.js → aria-loader-BVolm0lC.js} +1 -1
  56. package/esm/icons-CmuFKDRz.js +75 -0
  57. package/esm/{index-BvxaUA12.js → index-Dh_9sN0q.js} +389 -2478
  58. package/esm/index.js +4 -3
  59. package/esm/lmvz-button.entry.js +3 -3
  60. package/esm/lmvz-card.entry.js +1 -1
  61. package/esm/lmvz-checkbox.entry.js +111 -0
  62. package/esm/lmvz-chip.entry.js +3 -3
  63. package/esm/lmvz-components.js +1 -1
  64. package/esm/lmvz-header_2.entry.js +3 -3
  65. package/esm/lmvz-icon.entry.js +9 -7
  66. package/esm/lmvz-input.entry.js +4 -4
  67. package/esm/lmvz-menuitem.entry.js +4 -4
  68. package/esm/lmvz-select.entry.js +3 -3
  69. package/esm/loader.js +1 -1
  70. package/esm/{logger-0bL3pydp.js → logger-CGmJG63p.js} +2870 -765
  71. package/esm/{reactive-controller-host-J2thAxVH.js → reactive-controller-host-DHcPpJW7.js} +1 -1
  72. package/esm/{icons-Bj4dF1-I.js → svg-B2YoIRuh.js} +29 -80
  73. package/hydrate/index.js +2441 -165
  74. package/hydrate/index.mjs +2441 -165
  75. package/lmvz-components/index.esm.js +1 -1
  76. package/lmvz-components/lmvz-components.esm.js +1 -1
  77. package/lmvz-components/{p-ec96c6b6.entry.js → p-0f7a4236.entry.js} +1 -1
  78. package/lmvz-components/p-0s99QfRy.js +12 -0
  79. package/lmvz-components/p-2f83d7a2.entry.js +1 -0
  80. package/lmvz-components/{p-6e8acbd9.entry.js → p-32171f4f.entry.js} +1 -1
  81. package/lmvz-components/{p-9212bd23.entry.js → p-400b2318.entry.js} +1 -1
  82. package/lmvz-components/{p-9626e951.entry.js → p-851969bd.entry.js} +1 -1
  83. package/lmvz-components/p-9f9d845d.entry.js +1 -0
  84. package/lmvz-components/p-CFsC37ww.js +1 -0
  85. package/lmvz-components/p-CGmJG63p.js +1 -0
  86. package/lmvz-components/p-CcxjkCOx.js +1 -0
  87. package/lmvz-components/{p-BxHnZA0M.js → p-GdMr6Qlp.js} +1 -1
  88. package/lmvz-components/p-a12f95da.entry.js +1 -0
  89. package/lmvz-components/{p-e1b847d2.entry.js → p-ab4437dc.entry.js} +1 -1
  90. package/lmvz-components/{p-7a6bec13.entry.js → p-d0a0e206.entry.js} +1 -1
  91. package/lmvz-components/{p-DYaffOLo.js → p-dhVSUYqd.js} +1 -1
  92. package/manifest.json +410 -1
  93. package/package.json +5 -1
  94. package/types/components/lmvz-checkbox/lmvz-checkbox.d.ts +39 -0
  95. package/types/components.d.ts +151 -0
  96. package/types/utils/icons/icons.d.ts +0 -1
  97. package/components/p-DXOTa5VF.js +0 -12
  98. package/components/p-fiRXhuXK.js +0 -1
  99. package/lmvz-components/p-0bL3pydp.js +0 -1
  100. package/lmvz-components/p-40569208.entry.js +0 -1
  101. package/lmvz-components/p-49ab22bd.entry.js +0 -1
  102. package/lmvz-components/p-Bu4Z_PMf.js +0 -1
  103. package/lmvz-components/p-DHZwxmLb.js +0 -12
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var ariaLoader = require('./aria-loader-CfFuAbJn.js');
3
+ var ariaLoader = require('./aria-loader-Cec1zR2g.js');
4
4
  var index = require('./index-C2yDXRqP.js');
5
5
 
6
6
  class AriaValidationController {
@@ -1,41 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var logger = require('./logger-Bn2yoZGP.js');
4
-
5
- const IconProviderRegistryKey = Symbol.for('LMVZ__iconProviderRegistry');
6
- const inMemoryRegistry = {};
7
- function getRegistry() {
8
- if (typeof window === 'undefined') {
9
- return inMemoryRegistry;
10
- }
11
- return window[IconProviderRegistryKey] ?? (window[IconProviderRegistryKey] = {});
12
- }
13
- function registerIconProvider(id, provider) {
14
- const registry = getRegistry();
15
- const providerName = id;
16
- if (Object.prototype.hasOwnProperty.call(registry, providerName)) {
17
- console.warn(`Icon provider with name "${providerName}" is already registered. Overwriting existing provider.`);
18
- }
19
- registry[providerName] = provider;
20
- }
21
- function getRegisteredIconProvider(id) {
22
- const registry = getRegistry();
23
- if (id) {
24
- return registry[id];
25
- }
26
- const providerNames = Object.keys(registry);
27
- if (providerNames.length === 0) {
28
- return undefined;
29
- }
30
- if (providerNames.length > 1) {
31
- console.warn(`Multiple icon providers registered (${providerNames.join(', ')}). Using the first one: "${providerNames[0]}".`);
32
- }
33
- const firstProviderName = providerNames[0];
34
- if (!firstProviderName) {
35
- return undefined;
36
- }
37
- return registry[firstProviderName];
38
- }
3
+ var logger = require('./logger-DsM6xg6V.js');
39
4
 
40
5
  /**
41
6
  * This module provides types and utility functions to create and work with branded types,
@@ -92,11 +57,11 @@ class BrandValidationError extends logger.TaggedError('BrandValidationError') {
92
57
  }
93
58
  }
94
59
  /**
95
- * Validates an SVG string against the branded `SVGString` type and returns the result effect.
60
+ * Creates a synchronous Micro effect that validates a string against the branded `SVGString` type.
96
61
  *
97
62
  * @param svg Raw SVG markup to validate.
98
63
  */
99
- const createValidSVGString = (svg) => logger.try_({
64
+ const validateSvg = (svg) => logger.try_({
100
65
  try: () => SVGString(sanitizeSvg(svg)),
101
66
  catch: (error) => new BrandValidationError(error, 'SVGString'),
102
67
  });
@@ -108,10 +73,9 @@ const createValidSVGString = (svg) => logger.try_({
108
73
  function isValidSVG(svg) {
109
74
  if (typeof svg !== 'string')
110
75
  return false;
111
- const sanitizedSvg = sanitizeSvg(svg);
112
76
  try {
113
77
  const parser = new DOMParser();
114
- const doc = parser.parseFromString(sanitizedSvg, 'image/svg+xml');
78
+ const doc = parser.parseFromString(svg, 'image/svg+xml');
115
79
  return doc.documentElement.nodeName === 'svg';
116
80
  }
117
81
  catch {
@@ -120,60 +84,42 @@ function isValidSVG(svg) {
120
84
  }
121
85
  function sanitizeSvg(svg) {
122
86
  const dataUriPrefix = 'data:image/svg+xml,';
87
+ const dataUriPrefixWithEncoding = 'data:image/svg+xml;base64,';
123
88
  const base = svg.trim();
89
+ if (base.startsWith(dataUriPrefixWithEncoding)) {
90
+ return atob(base.slice(dataUriPrefixWithEncoding.length));
91
+ }
124
92
  return !base.startsWith(dataUriPrefix) ? base : decodeURIComponent(base.slice(dataUriPrefix.length));
125
93
  }
126
-
94
+ /**
95
+ * Returns a valid, empty SVG.
96
+ */
127
97
  const emptyDefaultSvg = () => SVGString(`<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"></svg>`);
128
- async function toValidSvgStringWithFallback(value) {
98
+ /**
99
+ * Returns a valid SVG string, or a fallback empty SVG if the input is invalid.
100
+ *
101
+ * @param value The SVG string to validate.
102
+ */
103
+ function toValidSvgStringWithFallback(value) {
129
104
  try {
130
- return await logger.runPromise(createValidSVGString(value));
105
+ return logger.runSync(validateSvg(value));
131
106
  }
132
107
  catch {
133
- console.error('Invalid SVG string:', value);
108
+ console.warn('Invalid SVG string:', value);
134
109
  return emptyDefaultSvg();
135
110
  }
136
111
  }
137
- async function resolveIconSvg(options) {
138
- const { icon, iconset } = options;
139
- const iconSvg = await (async () => {
140
- const provider = getRegisteredIconProvider(iconset);
141
- if (!provider) {
142
- console.warn(`No icon provider registered. Unable to resolve icon "${icon}"${iconset ? ` from set "${iconset}"` : ''}. Using default icon.`);
143
- return;
144
- }
145
- try {
146
- const resolved = await Promise.resolve(provider.resolve(icon));
147
- if (!resolved?.svg) {
148
- console.warn(`Icon "${icon}"${iconset ? ` from set "${iconset}"` : ''} not found in provider. Using default icon.`);
149
- return;
150
- }
151
- const validated = await toValidSvgStringWithFallback(resolved.svg);
152
- if (validated) {
153
- return validated;
154
- }
155
- }
156
- catch (error) {
157
- console.error(`Error resolving icon "${icon}" with provider:`, error);
158
- return;
159
- }
160
- return;
161
- })();
162
- if (iconSvg)
163
- return iconSvg;
164
- console.error(`Icon "${icon}" not found${iconset ? ` in set "${iconset}"` : ''}. Using default icon.`);
165
- return emptyDefaultSvg();
166
- }
167
- function typedIconFromSet(iconset, icon) {
168
- return {
169
- iconset,
170
- icon,
171
- };
112
+ function parseSvgString(value) {
113
+ try {
114
+ return logger.runSync(validateSvg(value));
115
+ }
116
+ catch {
117
+ // this will be called by lmvz-icon, which might pass an icon name instead of an SVG string, so we log this at debug level to avoid spamming the console with warnings
118
+ console.debug('Invalid SVG string:', value);
119
+ return undefined;
120
+ }
172
121
  }
173
122
 
174
- exports.createValidSVGString = createValidSVGString;
175
- exports.getRegisteredIconProvider = getRegisteredIconProvider;
176
- exports.isValidSVG = isValidSVG;
177
- exports.registerIconProvider = registerIconProvider;
178
- exports.resolveIconSvg = resolveIconSvg;
179
- exports.typedIconFromSet = typedIconFromSet;
123
+ exports.emptyDefaultSvg = emptyDefaultSvg;
124
+ exports.parseSvgString = parseSvgString;
125
+ exports.toValidSvgStringWithFallback = toValidSvgStringWithFallback;
@@ -0,0 +1,4 @@
1
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none"
2
+ xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false">
3
+ <path d="M3.75 12.5625L8.83079 17.625L20.4375 6.375" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
4
+ </svg>
@@ -3,6 +3,7 @@
3
3
  "components/lmvz-action/lmvz-action.js",
4
4
  "components/lmvz-button/lmvz-button.js",
5
5
  "components/lmvz-card/lmvz-card.js",
6
+ "components/lmvz-checkbox/lmvz-checkbox.js",
6
7
  "components/lmvz-chip/lmvz-chip.js",
7
8
  "components/lmvz-header/lmvz-header.js",
8
9
  "components/lmvz-icon/lmvz-icon.js",
@@ -91,8 +91,7 @@ button > * {
91
91
  }
92
92
 
93
93
  button:focus-visible {
94
- /* outline: var(--lmvz-semantic-border-width-default) solid var(--lmvz-semantic-color-status-active-950); */
95
- outline: var(--lmvz-semantic-border-width-default, 1px) solid var(--lmvz-semantic-color-status-active, #f1f9fe);
94
+ outline: var(--lmvz-semantic-border-width-default, 1px) solid var(--lmvz-semantic-color-status-on-active, #0e7ab4);
96
95
  outline-offset: var(--lmvz-component-input-sm-padding-x, clamp(0.5rem, 0.44rem + 0.26vw, 0.75rem));
97
96
  }
98
97
 
@@ -92,8 +92,7 @@ button > * {
92
92
  }
93
93
 
94
94
  button:focus-visible {
95
- /* outline: var(--lmvz-semantic-border-width-default) solid var(--lmvz-semantic-color-status-active-950); */
96
- outline: var(--lmvz-semantic-border-width-default, 1px) solid var(--lmvz-semantic-color-status-active, #f1f9fe);
95
+ outline: var(--lmvz-semantic-border-width-default, 1px) solid var(--lmvz-semantic-color-status-on-active, #0e7ab4);
97
96
  outline-offset: var(--lmvz-component-input-sm-padding-x, clamp(0.5rem, 0.44rem + 0.26vw, 0.75rem));
98
97
  }
99
98
 
@@ -0,0 +1,207 @@
1
+
2
+ @layer lmvz-ds.reset, lmvz-ds.theme, lmvz-ds.components, lmvz-ds.overrides;
3
+ /**
4
+ * This defines the order of our lmvz-ds' CSS layers. See readme.md for details.
5
+ * Important: Always import this file _before_ layering your own styles!
6
+ */
7
+ @layer lmvz-ds.theme {
8
+ @font-face {
9
+ font-family: Router;
10
+ src:
11
+ local('Router-Book'),
12
+ url('/assets/fonts/Router-Book.woff') format('woff'),
13
+ local('Router');
14
+ font-weight: 400 normal;
15
+ }
16
+
17
+ @font-face {
18
+ font-family: Router;
19
+ src:
20
+ local('Router-Medium'),
21
+ url('/assets/fonts/Router-Medium.woff') format('woff'),
22
+ local('Router');
23
+ font-weight: 500;
24
+ }
25
+
26
+ @font-face {
27
+ font-family: Router;
28
+ src:
29
+ local('Router-Bold'),
30
+ url('/assets/fonts/Router-Bold.woff') format('woff'),
31
+ local('Router');
32
+ font-weight: 700 bold;
33
+ }
34
+
35
+ }
36
+ :host {
37
+ display: inline-block;
38
+
39
+ --checkbox-box-size: var(--lmvz-global-s18, 18px); /* TODO: confirm this generic dimension token is intentional for checkbox box sizing */
40
+ --checkbox-border-radius: var(--lmvz-global-s4, 4px); /* TODO: consider component-specific token for border-radius */
41
+
42
+ --checkbox-bg: var(--lmvz-semantic-color-surface-input-primary, #ffffff);
43
+ --checkbox-border-color: var(--lmvz-semantic-color-border-default, #e0e0e0);
44
+ --checkbox-border-color-hover: var(--lmvz-semantic-color-border-hover, #c7c7c7);
45
+ --checkbox-border-color-checked: var(--lmvz-semantic-color-border-active, #0f8acc);
46
+ --checkbox-border-color-error: var(--lmvz-semantic-color-status-on-danger, #e52a31);
47
+
48
+ --checkbox-wrapper-bg-hover: var(--lmvz-semantic-color-int-tertiary-hover, #f0f0f0);
49
+ --checkbox-wrapper-bg-checked: var(--lmvz-semantic-color-status-active, #f1f9fe);
50
+
51
+ --checkbox-ripple-bg: var(--lmvz-semantic-color-int-secondary-hover, #e0e0e0);
52
+
53
+ --checkbox-checkmark-color: var(--lmvz-semantic-color-border-active, #0f8acc);
54
+
55
+ --checkbox-label-color: var(--lmvz-semantic-color-on-surface-primary, #000000);
56
+ --checkbox-label-color-checked: var(--lmvz-semantic-color-status-on-active, #0e7ab4);
57
+ --checkbox-helper-color: var(--lmvz-semantic-color-on-surface-secondary, #7a7a7a);
58
+ --checkbox-error-color: var(--lmvz-semantic-color-status-on-danger, #e52a31);
59
+ --checkbox-focus-color: var(--lmvz-semantic-color-status-on-active, #0e7ab4);
60
+
61
+ --checkbox-easing: var(--lmvz-global-easing-default, ease);
62
+ --checkbox-duration: 0.2s;
63
+ }
64
+ .pill {
65
+ display: flex;
66
+ align-items: center;
67
+ gap: var(--lmvz-component-input-md-gap-x, clamp(0.25rem, 0.16rem + 0.39vw, 0.63rem));
68
+ padding-block: var(--lmvz-dimension-2-8, clamp(0.13rem, 0.03rem + 0.39vw, 0.5rem));
69
+ padding-inline: var(--lmvz-dimension-4-10, clamp(0.25rem, 0.16rem + 0.39vw, 0.63rem));
70
+ border-radius: var(--lmvz-semantic-border-radius-round, 999px);
71
+ cursor: pointer;
72
+ /* WCAG 2.5.5 AAA: 44px minimum touch target */
73
+ /* min-block-size: 44px; */
74
+ text-decoration: none;
75
+ background-color: transparent;
76
+ transition: background-color var(--checkbox-duration) var(--checkbox-easing);
77
+ }
78
+ input {
79
+ position: absolute;
80
+ opacity: 0;
81
+ width: var(--checkbox-box-size);
82
+ height: var(--checkbox-box-size);
83
+ margin: 0;
84
+ cursor: pointer;
85
+ z-index: 1;
86
+ }
87
+ .box {
88
+ display: flex;
89
+ align-items: center;
90
+ justify-content: center;
91
+ width: var(--checkbox-box-size);
92
+ height: var(--checkbox-box-size);
93
+ background-color: var(--checkbox-bg);
94
+ border: var(--lmvz-semantic-border-width-default, 1px) solid var(--checkbox-border-color);
95
+ border-radius: var(--checkbox-border-radius);
96
+ color: var(--checkbox-checkmark-color);
97
+ transition:
98
+ border-color var(--checkbox-duration) var(--checkbox-easing),
99
+ background-color var(--checkbox-duration) var(--checkbox-easing);
100
+ pointer-events: none;
101
+ flex-shrink: 0;
102
+ }
103
+ .indicator {
104
+ display: flex;
105
+ align-items: center;
106
+ justify-content: center;
107
+ line-height: 0;
108
+ }
109
+ .content {
110
+ display: flex;
111
+ flex-direction: column;
112
+ overflow-wrap: break-word;
113
+ min-width: 0;
114
+ }
115
+ label {
116
+ font: var(--lmvz-typography-body-md, 400 clamp(0.88rem, 0.84rem + 0.13vw, 1rem) / 1.4
117
+ Router);
118
+ color: var(--checkbox-label-color);
119
+ transition: color var(--checkbox-duration) var(--checkbox-easing);
120
+ }
121
+ .helper-text {
122
+ font: var(--lmvz-typography-body-sm, 400 clamp(0.75rem, 0.73rem + 0.06vw, 0.81rem) / 1.4
123
+ Router);
124
+ /* font-weight: 400 per DS token standard (body-sm). Note: lmvz-input.css [role='status'] incorrectly uses font-weight: 500 — DS inconsistency, see lmvz-input.css line ~153 */
125
+ color: var(--checkbox-helper-color);
126
+ margin-block-start: 2px;
127
+ }
128
+ .error-text {
129
+ font: var(--lmvz-typography-body-sm, 400 clamp(0.75rem, 0.73rem + 0.06vw, 0.81rem) / 1.4
130
+ Router);
131
+ color: var(--checkbox-error-color);
132
+ display: block;
133
+ margin-block-start: 4px;
134
+ padding-inline: 10px;
135
+ }
136
+ /* Hover state, guarded to prevent sticky hover on touch devices */
137
+ @media (hover: hover) {
138
+ .pill:hover {
139
+ background-color: var(--checkbox-wrapper-bg-hover);
140
+ }
141
+
142
+ .pill:hover .box {
143
+ border-color: var(--checkbox-border-color-hover);
144
+ }
145
+ }
146
+ /* Checked state */
147
+ :host([checked]) .pill {
148
+ background-color: var(--checkbox-wrapper-bg-checked);
149
+ }
150
+ :host([checked]) .box {
151
+ border-color: var(--checkbox-border-color-checked);
152
+ }
153
+ :host([checked]) label {
154
+ color: var(--checkbox-label-color-checked);
155
+ /* Contrast ~4.4:1 on checked wrapper background (#f1f9fe) — exception accepted per DS decision 5.3; approximately at WCAG AA threshold; pending design review for formal verification */
156
+ }
157
+ /* Error state. MUST appear AFTER checked state rules (error takes visual precedence) */
158
+ :host([error]) .box {
159
+ border-color: var(--checkbox-border-color-error);
160
+ }
161
+ :host([error]) .helper-text {
162
+ color: var(--checkbox-error-color);
163
+ }
164
+ /* Disabled state */
165
+ :host([disabled]) {
166
+ opacity: var(--lmvz-component-input-disabled-opacity, 40%);
167
+ pointer-events: none;
168
+ }
169
+ :host([disabled]) .pill {
170
+ cursor: not-allowed;
171
+ }
172
+ :host([disabled]) input {
173
+ cursor: not-allowed;
174
+ }
175
+ /* Focus ring, applied via sibling combinator on the native input */
176
+ input:focus-visible ~ .box {
177
+ outline: 2px solid var(--checkbox-focus-color);
178
+ outline-offset: 2px;
179
+ /* box-shadow: 0 0 0 3px rgba(15, 138, 204, 0.2); TODO: no design token available for focus shadow color/spread */
180
+ box-shadow: 0 var(--lmvz-semantic-shadow-l1-1-position-y, 2px) 0 var(--lmvz-semantic-shadow-l1-1-blur, 4px) var(--lmvz-semantic-color-shadow-l1-colored, rgba(175, 223, 249, 0.42));
181
+ }
182
+ /* Forced Colors / Windows High Contrast */
183
+ @media (forced-colors: active) {
184
+ .box {
185
+ forced-color-adjust: auto;
186
+ border-color: ButtonText;
187
+ background-color: Field;
188
+ }
189
+
190
+ :host([checked]) .box {
191
+ border-color: Highlight;
192
+ background-color: Field;
193
+ }
194
+
195
+ .indicator {
196
+ color: ButtonText;
197
+ }
198
+
199
+ :host([checked]) .indicator {
200
+ color: HighlightText;
201
+ }
202
+
203
+ input:focus-visible ~ .box {
204
+ outline-color: Highlight;
205
+ box-shadow: none;
206
+ }
207
+ }