mtrl 0.0.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 (121) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +251 -0
  3. package/index.js +10 -0
  4. package/package.json +17 -0
  5. package/src/components/button/api.js +54 -0
  6. package/src/components/button/button.js +81 -0
  7. package/src/components/button/config.js +8 -0
  8. package/src/components/button/constants.js +63 -0
  9. package/src/components/button/index.js +2 -0
  10. package/src/components/button/styles.scss +231 -0
  11. package/src/components/checkbox/api.js +45 -0
  12. package/src/components/checkbox/checkbox.js +95 -0
  13. package/src/components/checkbox/constants.js +88 -0
  14. package/src/components/checkbox/index.js +2 -0
  15. package/src/components/checkbox/styles.scss +183 -0
  16. package/src/components/container/api.js +42 -0
  17. package/src/components/container/container.js +45 -0
  18. package/src/components/container/index.js +2 -0
  19. package/src/components/container/styles.scss +59 -0
  20. package/src/components/list/constants.js +89 -0
  21. package/src/components/list/index.js +2 -0
  22. package/src/components/list/list-item.js +147 -0
  23. package/src/components/list/list.js +267 -0
  24. package/src/components/list/styles/_list-item.scss +142 -0
  25. package/src/components/list/styles/_list.scss +89 -0
  26. package/src/components/list/styles/_variables.scss +13 -0
  27. package/src/components/list/styles.scss +19 -0
  28. package/src/components/navigation/api.js +43 -0
  29. package/src/components/navigation/constants.js +235 -0
  30. package/src/components/navigation/features/items.js +192 -0
  31. package/src/components/navigation/index.js +2 -0
  32. package/src/components/navigation/nav-item.js +137 -0
  33. package/src/components/navigation/navigation.js +55 -0
  34. package/src/components/navigation/styles/_bar.scss +51 -0
  35. package/src/components/navigation/styles/_base.scss +129 -0
  36. package/src/components/navigation/styles/_drawer.scss +169 -0
  37. package/src/components/navigation/styles/_rail.scss +65 -0
  38. package/src/components/navigation/styles.scss +6 -0
  39. package/src/components/snackbar/api.js +125 -0
  40. package/src/components/snackbar/constants.js +41 -0
  41. package/src/components/snackbar/features.js +69 -0
  42. package/src/components/snackbar/index.js +2 -0
  43. package/src/components/snackbar/position.js +63 -0
  44. package/src/components/snackbar/queue.js +74 -0
  45. package/src/components/snackbar/snackbar.js +70 -0
  46. package/src/components/snackbar/styles.scss +182 -0
  47. package/src/components/switch/api.js +44 -0
  48. package/src/components/switch/constants.js +80 -0
  49. package/src/components/switch/index.js +2 -0
  50. package/src/components/switch/styles.scss +172 -0
  51. package/src/components/switch/switch.js +71 -0
  52. package/src/components/textfield/api.js +49 -0
  53. package/src/components/textfield/constants.js +81 -0
  54. package/src/components/textfield/index.js +2 -0
  55. package/src/components/textfield/styles/base.scss +107 -0
  56. package/src/components/textfield/styles/filled.scss +58 -0
  57. package/src/components/textfield/styles/outlined.scss +66 -0
  58. package/src/components/textfield/styles.scss +6 -0
  59. package/src/components/textfield/textfield.js +68 -0
  60. package/src/core/build/constants.js +51 -0
  61. package/src/core/build/icon.js +78 -0
  62. package/src/core/build/ripple.js +92 -0
  63. package/src/core/build/text.js +54 -0
  64. package/src/core/collection/adapters/base.js +26 -0
  65. package/src/core/collection/adapters/mongodb.js +232 -0
  66. package/src/core/collection/adapters/route.js +201 -0
  67. package/src/core/collection/collection.js +259 -0
  68. package/src/core/collection/list-manager.js +157 -0
  69. package/src/core/compose/base.js +8 -0
  70. package/src/core/compose/component.js +225 -0
  71. package/src/core/compose/features/checkable.js +114 -0
  72. package/src/core/compose/features/disabled.js +25 -0
  73. package/src/core/compose/features/events.js +48 -0
  74. package/src/core/compose/features/icon.js +33 -0
  75. package/src/core/compose/features/index.js +20 -0
  76. package/src/core/compose/features/input.js +92 -0
  77. package/src/core/compose/features/lifecycle.js +69 -0
  78. package/src/core/compose/features/position.js +60 -0
  79. package/src/core/compose/features/ripple.js +32 -0
  80. package/src/core/compose/features/size.js +9 -0
  81. package/src/core/compose/features/style.js +12 -0
  82. package/src/core/compose/features/text.js +17 -0
  83. package/src/core/compose/features/textinput.js +118 -0
  84. package/src/core/compose/features/textlabel.js +28 -0
  85. package/src/core/compose/features/track.js +49 -0
  86. package/src/core/compose/features/variant.js +9 -0
  87. package/src/core/compose/features/withEvents.js +67 -0
  88. package/src/core/compose/index.js +16 -0
  89. package/src/core/compose/pipe.js +69 -0
  90. package/src/core/config.js +140 -0
  91. package/src/core/dom/attributes.js +33 -0
  92. package/src/core/dom/classes.js +70 -0
  93. package/src/core/dom/create.js +133 -0
  94. package/src/core/dom/events.js +175 -0
  95. package/src/core/dom/index.js +5 -0
  96. package/src/core/dom/utils.js +22 -0
  97. package/src/core/index.js +23 -0
  98. package/src/core/layout/index.js +93 -0
  99. package/src/core/state/disabled.js +14 -0
  100. package/src/core/state/emitter.js +63 -0
  101. package/src/core/state/events.js +29 -0
  102. package/src/core/state/index.js +6 -0
  103. package/src/core/state/lifecycle.js +64 -0
  104. package/src/core/state/store.js +112 -0
  105. package/src/core/utils/index.js +39 -0
  106. package/src/core/utils/mobile.js +74 -0
  107. package/src/core/utils/object.js +22 -0
  108. package/src/core/utils/validate.js +37 -0
  109. package/src/index.js +11 -0
  110. package/src/styles/abstract/_base.scss +2 -0
  111. package/src/styles/abstract/_config.scss +28 -0
  112. package/src/styles/abstract/_functions.scss +124 -0
  113. package/src/styles/abstract/_mixins.scss +261 -0
  114. package/src/styles/abstract/_variables.scss +158 -0
  115. package/src/styles/main.scss +78 -0
  116. package/src/styles/themes/_base-theme.scss +49 -0
  117. package/src/styles/themes/_baseline.scss +90 -0
  118. package/src/styles/themes/_forest.scss +71 -0
  119. package/src/styles/themes/_index.scss +6 -0
  120. package/src/styles/themes/_ocean.scss +71 -0
  121. package/src/styles/themes/_sunset.scss +55 -0
@@ -0,0 +1,231 @@
1
+ // src/components/button/styles.scss
2
+ @use 'sass:map';
3
+ @use '../../styles/abstract/config' as c;
4
+
5
+ .#{c.$prefix}-button {
6
+ // Base styles
7
+ @include c.typography('label-large');
8
+ @include c.flex-center;
9
+ @include c.shape('full');
10
+ @include c.motion-transition(
11
+ background-color,
12
+ box-shadow,
13
+ color,
14
+ border-color
15
+ );
16
+
17
+ min-width: 40px;
18
+ height: 40px;
19
+ padding: 0 24px;
20
+ border: none;
21
+ cursor: pointer;
22
+ user-select: none;
23
+
24
+ // Label styles
25
+ &-label {
26
+ @include c.truncate;
27
+ }
28
+
29
+ // Icon styles
30
+ &-icon {
31
+ @include c.flex-center;
32
+ margin-right: 8px;
33
+ font-size: 18px;
34
+ background-color: transparent;
35
+ @include c.rtl {
36
+ margin-right: 0;
37
+ margin-left: 8px;
38
+ }
39
+ }
40
+
41
+ // Variants
42
+ &--filled {
43
+ background-color: var(--mtrl-sys-color-primary);
44
+ color: var(--mtrl-sys-color-on-primary);
45
+ @include c.elevation(0);
46
+
47
+ &:hover {
48
+ @include c.elevation(1);
49
+ @include c.state-layer(var(--mtrl-sys-color-on-primary), 'hover');
50
+ }
51
+
52
+ &:focus {
53
+ @include c.state-layer(var(--mtrl-sys-color-on-primary), 'focus');
54
+ }
55
+
56
+ &:active {
57
+ @include c.state-layer(var(--mtrl-sys-color-on-primary), 'pressed');
58
+ }
59
+ }
60
+
61
+ &--tonal {
62
+ background-color: var(--mtrl-sys-color-secondary-container);
63
+ color: var(--mtrl-sys-color-on-secondary-container);
64
+
65
+ &:hover {
66
+ @include c.state-layer(var(--mtrl-sys-color-on-secondary-container), 'hover');
67
+ }
68
+
69
+ &:focus {
70
+ @include c.state-layer(var(--mtrl-sys-color-on-secondary-container), 'focus');
71
+ }
72
+
73
+ &:active {
74
+ @include c.state-layer(var(--mtrl-sys-color-on-secondary-container), 'pressed');
75
+ }
76
+ }
77
+
78
+ &--outlined {
79
+ border: 1px solid var(--mtrl-sys-color-outline);
80
+ color: var(--mtrl-sys-color-primary);
81
+
82
+ &:hover {
83
+ @include c.state-layer(var(--mtrl-sys-color-primary), 'hover');
84
+ }
85
+
86
+ &:focus {
87
+ @include c.state-layer(var(--mtrl-sys-color-primary), 'focus');
88
+ border-color: var(--mtrl-sys-color-primary);
89
+ }
90
+
91
+ &:active {
92
+ @include c.state-layer(var(--mtrl-sys-color-primary), 'pressed');
93
+ }
94
+ }
95
+
96
+ // Variants (adding elevated and text)
97
+ &--elevated {
98
+ background-color: var(--mtrl-sys-color-surface-container-low);
99
+ color: var(--mtrl-sys-color-primary);
100
+ // Reduced from elevation(1) to a more subtle custom shadow
101
+ box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.2),
102
+ 0px 1px 3px 1px rgba(0, 0, 0, 0.10);
103
+
104
+ &:hover {
105
+ // Slightly increased elevation on hover, but still subtle
106
+ box-shadow: 0px 1px 2px 1px rgba(0, 0, 0, 0.2),
107
+ 0px 2px 6px 2px rgba(0, 0, 0, 0.10);
108
+ @include c.state-layer(var(--mtrl-sys-color-primary), 'hover');
109
+ }
110
+
111
+ &:focus {
112
+ @include c.state-layer(var(--mtrl-sys-color-primary), 'focus');
113
+ }
114
+
115
+ &:active {
116
+ // Return to default elevation on press
117
+ box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.2),
118
+ 0px 1px 3px 1px rgba(0, 0, 0, 0.10);
119
+ @include c.state-layer(var(--mtrl-sys-color-primary), 'pressed');
120
+ }
121
+
122
+ &.#{c.$prefix}-button--disabled {
123
+ box-shadow: none;
124
+ background-color: rgba(var(--mtrl-sys-color-on-surface-rgb), 0.12);
125
+ color: rgba(var(--mtrl-sys-color-on-surface-rgb), 0.38);
126
+ }
127
+ }
128
+
129
+ &--text {
130
+ background-color: transparent;
131
+ color: var(--mtrl-sys-color-primary);
132
+ padding: 0 12px;
133
+ min-width: 48px;
134
+
135
+ &:hover {
136
+ @include c.state-layer(var(--mtrl-sys-color-primary), 'hover');
137
+ }
138
+
139
+ &:focus {
140
+ @include c.state-layer(var(--mtrl-sys-color-primary), 'focus');
141
+ }
142
+
143
+ &:active {
144
+ @include c.state-layer(var(--mtrl-sys-color-primary), 'pressed');
145
+ }
146
+
147
+ // Adjust spacing when icon is present
148
+ .#{c.$prefix}-button-icon {
149
+ margin-right: 8px;
150
+
151
+ @include c.rtl {
152
+ margin-right: 0;
153
+ margin-left: 8px;
154
+ }
155
+ }
156
+
157
+ &.#{c.$prefix}-button--disabled {
158
+ color: rgba(var(--mtrl-sys-color-on-surface-rgb), 0.38);
159
+ }
160
+ }
161
+
162
+ &--icon {
163
+ background-color: transparent;
164
+ }
165
+
166
+ &--circular {
167
+ border-radius: 50%;
168
+ padding: 8px;
169
+ min-width: unset;
170
+ width: 40px;
171
+ height: 40px;
172
+ display: inline-flex;
173
+ align-items: center;
174
+ justify-content: center;
175
+
176
+ .#{c.$prefix}-button-icon {
177
+ margin: 0;
178
+ }
179
+
180
+ &.#{c.$prefix}-button--small {
181
+ width: 32px;
182
+ height: 32px;
183
+ }
184
+
185
+ &.#{c.$prefix}-button--large {
186
+ width: 48px;
187
+ height: 48px;
188
+ }
189
+ }
190
+
191
+ // States
192
+ &--disabled {
193
+ opacity: 0.38;
194
+ pointer-events: none;
195
+ cursor: default;
196
+
197
+ &.#{c.$prefix}-button--outlined {
198
+ border-color: rgba(var(--mtrl-sys-color-on-surface-rgb), 0.12);
199
+ }
200
+ }
201
+
202
+ // Sizes
203
+ &--small {
204
+ height: 32px;
205
+ padding: 0 16px;
206
+
207
+ .#{c.$prefix}-button-icon {
208
+ font-size: 16px;
209
+ }
210
+ }
211
+
212
+ &--large {
213
+ height: 48px;
214
+ padding: 0 32px;
215
+
216
+ .#{c.$prefix}-button-icon {
217
+ font-size: 20px;
218
+ }
219
+ }
220
+
221
+ // Accessibility
222
+ @include c.focus-ring();
223
+
224
+ @include c.reduced-motion {
225
+ transition: none;
226
+ }
227
+
228
+ @include c.high-contrast {
229
+ border: 1px solid currentColor;
230
+ }
231
+ }
@@ -0,0 +1,45 @@
1
+ // src/components/checkbox/api.js
2
+
3
+ /**
4
+ * Enhances checkbox component with API methods
5
+ * @param {Object} options - API configuration
6
+ * @param {Object} options.disabled - Disabled state handlers
7
+ * @param {Object} options.lifecycle - Lifecycle handlers
8
+ * @param {Object} options.checkable - Checked state handlers
9
+ */
10
+ export const withAPI = ({ disabled, lifecycle, checkable }) => (component) => ({
11
+ ...component,
12
+ element: component.element,
13
+
14
+ // Value management
15
+ getValue: component.getValue,
16
+ setValue (value) {
17
+ component.setValue(value)
18
+ return this
19
+ },
20
+
21
+ // State management
22
+ check: checkable.check,
23
+ uncheck: checkable.uncheck,
24
+ toggle: checkable.toggle,
25
+ isChecked: checkable.isChecked,
26
+ setIndeterminate: component.setIndeterminate,
27
+
28
+ // Label management
29
+ setLabel (text) {
30
+ component.text?.setText(text)
31
+ return this
32
+ },
33
+ getLabel () {
34
+ return component.text?.getText() || ''
35
+ },
36
+
37
+ // Event handling
38
+ on: component.on,
39
+ off: component.off,
40
+
41
+ // State management
42
+ enable: disabled.enable,
43
+ disable: disabled.disable,
44
+ destroy: lifecycle.destroy
45
+ })
@@ -0,0 +1,95 @@
1
+ // src/components/checkbox/checkbox.js
2
+
3
+ import { PREFIX } from '../../core/config'
4
+ import { pipe } from '../../core/compose'
5
+ import { createBase, withElement } from '../../core/compose/component'
6
+ import {
7
+ withEvents,
8
+ withTextLabel,
9
+ withDisabled,
10
+ withLifecycle,
11
+ withInput,
12
+ withCheckable
13
+ } from '../../core/compose/features'
14
+ import { withAPI } from './api'
15
+ import { CHECKBOX_VARIANTS } from './constants'
16
+
17
+ /**
18
+ * Adds check icon to checkbox
19
+ * @param {Object} config - Component configuration
20
+ */
21
+ const withCheckIcon = (config) => (component) => {
22
+ const icon = document.createElement('span')
23
+ icon.className = `${config.prefix}-checkbox-icon`
24
+ icon.innerHTML = `
25
+ <svg viewBox="0 0 24 24" aria-hidden="true">
26
+ <path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"></path>
27
+ </svg>
28
+ `
29
+ component.element.appendChild(icon)
30
+ return component
31
+ }
32
+
33
+ /**
34
+ * Creates a new Checkbox component
35
+ * @param {Object} config - Checkbox configuration
36
+ * @param {string} [config.name] - Input name attribute
37
+ * @param {boolean} [config.checked] - Initial checked state
38
+ * @param {boolean} [config.indeterminate] - Initial indeterminate state
39
+ * @param {boolean} [config.required] - Whether input is required
40
+ * @param {boolean} [config.disabled] - Whether checkbox is disabled
41
+ * @param {string} [config.value] - Input value attribute
42
+ * @param {string} [config.label] - Label text
43
+ * @param {string} [config.labelPosition='end'] - Label position (start/end)
44
+ * @param {string} [config.variant='filled'] - Visual variant
45
+ * @param {string} [config.class] - Additional CSS classes
46
+ */
47
+ const createCheckbox = (config = {}) => {
48
+ const baseConfig = {
49
+ ...config,
50
+ componentName: 'checkbox',
51
+ prefix: PREFIX,
52
+ variant: config.variant || CHECKBOX_VARIANTS.FILLED
53
+ }
54
+
55
+ const enhancedWithCheckable = (component) => {
56
+ const enhanced = withCheckable(baseConfig)(component)
57
+
58
+ // Add indeterminate state handling
59
+ if (config.indeterminate) {
60
+ enhanced.input.indeterminate = true
61
+ }
62
+
63
+ enhanced.setIndeterminate = (state) => {
64
+ enhanced.input.indeterminate = state
65
+ enhanced.element.classList.toggle(`${PREFIX}-checkbox--indeterminate`, state)
66
+ return enhanced
67
+ }
68
+
69
+ return enhanced
70
+ }
71
+
72
+ return pipe(
73
+ createBase,
74
+ withEvents(),
75
+ withElement({
76
+ tag: 'div',
77
+ componentName: 'checkbox',
78
+ className: config.class,
79
+ interactive: true
80
+ }),
81
+ withInput(baseConfig),
82
+ withCheckIcon(baseConfig),
83
+ withTextLabel(baseConfig),
84
+ enhancedWithCheckable,
85
+ withDisabled(),
86
+ withLifecycle(),
87
+ comp => withAPI({
88
+ disabled: comp.disabled,
89
+ lifecycle: comp.lifecycle,
90
+ checkable: comp.checkable
91
+ })(comp)
92
+ )(baseConfig)
93
+ }
94
+
95
+ export default createCheckbox
@@ -0,0 +1,88 @@
1
+ // src/components/checkbox/constants.js
2
+
3
+ /**
4
+ * Visual variants for checkbox
5
+ */
6
+ export const CHECKBOX_VARIANTS = {
7
+ FILLED: 'filled',
8
+ OUTLINED: 'outlined'
9
+ }
10
+
11
+ /**
12
+ * Label position options
13
+ */
14
+ export const CHECKBOX_LABEL_POSITION = {
15
+ START: 'start',
16
+ END: 'end'
17
+ }
18
+
19
+ /**
20
+ * Validation schema for checkbox configuration
21
+ */
22
+ export const CHECKBOX_SCHEMA = {
23
+ type: 'object',
24
+ properties: {
25
+ name: {
26
+ type: 'string',
27
+ optional: true
28
+ },
29
+ checked: {
30
+ type: 'boolean',
31
+ optional: true
32
+ },
33
+ indeterminate: {
34
+ type: 'boolean',
35
+ optional: true
36
+ },
37
+ required: {
38
+ type: 'boolean',
39
+ optional: true
40
+ },
41
+ disabled: {
42
+ type: 'boolean',
43
+ optional: true
44
+ },
45
+ value: {
46
+ type: 'string',
47
+ optional: true
48
+ },
49
+ label: {
50
+ type: 'string',
51
+ optional: true
52
+ },
53
+ labelPosition: {
54
+ type: 'string',
55
+ enum: Object.values(CHECKBOX_LABEL_POSITION),
56
+ optional: true
57
+ },
58
+ variant: {
59
+ type: 'string',
60
+ enum: Object.values(CHECKBOX_VARIANTS),
61
+ optional: true
62
+ },
63
+ class: {
64
+ type: 'string',
65
+ optional: true
66
+ }
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Checkbox state classes
72
+ */
73
+ export const CHECKBOX_STATES = {
74
+ CHECKED: 'checked',
75
+ INDETERMINATE: 'indeterminate',
76
+ DISABLED: 'disabled',
77
+ FOCUSED: 'focused'
78
+ }
79
+
80
+ /**
81
+ * Checkbox element classes
82
+ */
83
+ export const CHECKBOX_CLASSES = {
84
+ ROOT: 'checkbox',
85
+ INPUT: 'checkbox-input',
86
+ ICON: 'checkbox-icon',
87
+ LABEL: 'checkbox-label'
88
+ }
@@ -0,0 +1,2 @@
1
+ // src/components/checkbox/index.js
2
+ export { default } from './checkbox.js'
@@ -0,0 +1,183 @@
1
+ // src/components/checkbox/styles.scss
2
+ @use 'sass:map';
3
+ @use '../../styles/abstract/config' as c;
4
+
5
+ .#{c.$prefix}-checkbox {
6
+ display: inline-flex;
7
+ align-items: center;
8
+ position: relative;
9
+ min-height: 40px;
10
+ padding: 4px 0;
11
+ user-select: none;
12
+
13
+ &-input {
14
+ position: absolute;
15
+ opacity: 0;
16
+ width: 100%;
17
+ height: 100%;
18
+ margin: 0;
19
+ cursor: pointer;
20
+ z-index: 1;
21
+
22
+ &:disabled {
23
+ cursor: not-allowed;
24
+ }
25
+
26
+ &:focus-visible ~ .#{c.$prefix}-checkbox-icon {
27
+ outline: 2px solid var(--mtrl-sys-color-primary);
28
+ outline-offset: 2px;
29
+ }
30
+ }
31
+
32
+ &-icon {
33
+ position: relative;
34
+ width: 18px;
35
+ height: 18px;
36
+ border-radius: 2px;
37
+ background-color: var(--mtrl-sys-color-surface-container-highest);
38
+ border: 2px solid var(--mtrl-sys-color-outline);
39
+ transition: background-color map.get(c.$motion, 'duration-short4') map.get(c.$motion, 'easing-standard'),
40
+ border-color map.get(c.$motion, 'duration-short4') map.get(c.$motion, 'easing-standard');
41
+
42
+ svg {
43
+ position: absolute;
44
+ top: 50%;
45
+ left: 50%;
46
+ width: 18px;
47
+ height: 18px;
48
+ transform: translate(-50%, -50%) scale(0);
49
+ fill: currentColor;
50
+ color: var(--mtrl-sys-color-on-primary);
51
+ transition: transform map.get(c.$motion, 'duration-short4') map.get(c.$motion, 'easing-emphasized');
52
+ }
53
+ }
54
+
55
+ &-label {
56
+ @include c.typography('body-large');
57
+ margin-left: 12px;
58
+ color: var(--mtrl-sys-color-on-surface);
59
+ }
60
+
61
+ // Label position variants
62
+ &--label-start {
63
+ flex-direction: row-reverse;
64
+
65
+ .#{c.$prefix}-checkbox-label {
66
+ margin-left: 0;
67
+ margin-right: 12px;
68
+ }
69
+ }
70
+
71
+ &--label-end {
72
+ flex-direction: row;
73
+
74
+ .#{c.$prefix}-checkbox-label {
75
+ margin-left: 12px;
76
+ margin-right: 0;
77
+ }
78
+ }
79
+
80
+ @include c.rtl {
81
+ &--label-start {
82
+ .#{c.$prefix}-checkbox-label {
83
+ margin-left: 12px;
84
+ margin-right: 0;
85
+ }
86
+ }
87
+
88
+ &--label-end {
89
+ .#{c.$prefix}-checkbox-label {
90
+ margin-left: 0;
91
+ margin-right: 12px;
92
+ }
93
+ }
94
+ }
95
+
96
+ // States
97
+ .#{c.$prefix}-checkbox-input:checked ~ .#{c.$prefix}-checkbox-icon {
98
+ background-color: var(--mtrl-sys-color-primary);
99
+ border-color: var(--mtrl-sys-color-primary);
100
+
101
+ svg {
102
+ transform: translate(-50%, -50%) scale(1);
103
+ }
104
+ }
105
+
106
+ &--indeterminate {
107
+ .#{c.$prefix}-checkbox-icon {
108
+ background-color: var(--mtrl-sys-color-primary);
109
+ border-color: var(--mtrl-sys-color-primary);
110
+
111
+ &::after {
112
+ content: '';
113
+ position: absolute;
114
+ top: 50%;
115
+ left: 50%;
116
+ transform: translate(-50%, -50%);
117
+ width: 10px;
118
+ height: 2px;
119
+ background-color: var(--mtrl-sys-color-on-primary);
120
+ }
121
+
122
+ svg {
123
+ display: none;
124
+ }
125
+ }
126
+ }
127
+
128
+ &--disabled {
129
+ opacity: .5;
130
+ }
131
+
132
+ // Variants
133
+ &--outlined {
134
+ .#{c.$prefix}-checkbox-icon {
135
+ background-color: transparent;
136
+ }
137
+
138
+ .#{c.$prefix}-checkbox-input:checked ~ .#{c.$prefix}-checkbox-icon {
139
+ background-color: transparent;
140
+ border-color: var(--mtrl-sys-color-primary);
141
+
142
+ svg {
143
+ color: var(--mtrl-sys-color-primary);
144
+ }
145
+ }
146
+
147
+ &.#{c.$prefix}-checkbox--indeterminate {
148
+ .#{c.$prefix}-checkbox-icon::after {
149
+ background-color: var(--mtrl-sys-color-primary);
150
+ }
151
+ }
152
+ }
153
+
154
+ // Hover effects
155
+ &:not(&--disabled) {
156
+ .#{c.$prefix}-checkbox-input:hover ~ .#{c.$prefix}-checkbox-icon {
157
+ &::before {
158
+ content: '';
159
+ position: absolute;
160
+ top: -8px;
161
+ left: -8px;
162
+ right: -8px;
163
+ bottom: -8px;
164
+ background-color: var(--mtrl-sys-color-on-surface);
165
+ opacity: 0.08;
166
+ border-radius: 4px;
167
+ }
168
+ }
169
+ }
170
+
171
+ @include c.reduced-motion {
172
+ .#{c.$prefix}-checkbox-icon,
173
+ .#{c.$prefix}-checkbox-icon svg {
174
+ transition: none;
175
+ }
176
+ }
177
+
178
+ @include c.high-contrast {
179
+ .#{c.$prefix}-checkbox-icon {
180
+ border-width: 2px;
181
+ }
182
+ }
183
+ }
@@ -0,0 +1,42 @@
1
+ // src/components/container/api.js
2
+
3
+ /**
4
+ * Enhances container component with API methods
5
+ * @param {Object} options - API configuration
6
+ * @param {Object} options.lifecycle - Lifecycle handlers
7
+ */
8
+ export const withAPI = ({ lifecycle }) => (component) => ({
9
+ ...component,
10
+ element: component.element,
11
+
12
+ // Attribute management
13
+ get (prop) {
14
+ return component.element.getAttribute(prop)
15
+ },
16
+ set (prop, value) {
17
+ value === null
18
+ ? component.element.removeAttribute(prop)
19
+ : component.element.setAttribute(prop, value)
20
+ return this
21
+ },
22
+
23
+ // Content management
24
+ setContent (content) {
25
+ if (content instanceof Node) {
26
+ component.element.appendChild(content)
27
+ } else {
28
+ component.element.innerHTML = content
29
+ }
30
+ return this
31
+ },
32
+ getContent () {
33
+ return component.element.innerHTML
34
+ },
35
+
36
+ // Event handling
37
+ on: component.on,
38
+ off: component.off,
39
+
40
+ // Lifecycle
41
+ destroy: lifecycle.destroy
42
+ })