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,192 @@
1
+ // src/components/navigation/features/items.js
2
+ import { createNavItem, getAllNestedItems } from '../nav-item'
3
+
4
+ export const withNavItems = (config) => (component) => {
5
+ const items = new Map()
6
+ let activeItem = null
7
+
8
+ /**
9
+ * Recursively stores items in the items Map
10
+ * @param {Object} itemConfig - Item configuration
11
+ * @param {HTMLElement} item - Created item element
12
+ */
13
+ const storeItem = (itemConfig, item) => {
14
+ items.set(itemConfig.id, { element: item, config: itemConfig })
15
+
16
+ if (itemConfig.items?.length) {
17
+ itemConfig.items.forEach(nestedConfig => {
18
+ const container = item.closest(`.${config.prefix}-nav-item-container`)
19
+ const nestedContainer = container.querySelector(`.${config.prefix}-nav-nested-container`)
20
+ const nestedItem = nestedContainer.querySelector(`[data-id="${nestedConfig.id}"]`)
21
+ storeItem(nestedConfig, nestedItem)
22
+ })
23
+ }
24
+ }
25
+
26
+ // Create initial items
27
+ if (config.items) {
28
+ config.items.forEach(itemConfig => {
29
+ const item = createNavItem(itemConfig, component.element, config.prefix)
30
+ storeItem(itemConfig, item)
31
+
32
+ if (itemConfig.active) {
33
+ activeItem = { element: item, config: itemConfig }
34
+ item.classList.add(`${config.prefix}-nav-item--active`)
35
+ item.setAttribute('aria-selected', 'true')
36
+ }
37
+ })
38
+ }
39
+
40
+ // Handle item clicks
41
+ component.element.addEventListener('click', (event) => {
42
+ const item = event.target.closest(`.${config.prefix}-nav-item`)
43
+ if (!item || item.disabled || item.getAttribute('aria-haspopup') === 'true') return
44
+
45
+ const id = item.dataset.id
46
+ const itemData = items.get(id)
47
+ if (!itemData) return
48
+
49
+ // Store previous item before updating
50
+ const previousItem = activeItem
51
+
52
+ // Update active state
53
+ if (activeItem) {
54
+ activeItem.element.classList.remove(`${config.prefix}-nav-item--active`)
55
+ activeItem.element.setAttribute('aria-selected', 'false')
56
+ }
57
+
58
+ item.classList.add(`${config.prefix}-nav-item--active`)
59
+ item.setAttribute('aria-selected', 'true')
60
+ activeItem = itemData
61
+
62
+ // Emit change event with item data
63
+ component.emit('change', {
64
+ id,
65
+ item: itemData,
66
+ previousItem,
67
+ path: getItemPath(id)
68
+ })
69
+ })
70
+
71
+ /**
72
+ * Gets the path to an item (parent IDs)
73
+ * @param {string} id - Item ID to get path for
74
+ * @returns {Array<string>} Array of parent item IDs
75
+ */
76
+ const getItemPath = (id) => {
77
+ const path = []
78
+ let currentItem = items.get(id)
79
+
80
+ while (currentItem) {
81
+ const parentContainer = currentItem.element.closest(`.${config.prefix}-nav-nested-container`)
82
+ if (!parentContainer) break
83
+
84
+ const parentItem = parentContainer.previousElementSibling
85
+ if (!parentItem) break
86
+
87
+ const parentId = parentItem.dataset.id
88
+ if (!parentId) break
89
+
90
+ path.unshift(parentId)
91
+ currentItem = items.get(parentId)
92
+ }
93
+
94
+ return path
95
+ }
96
+
97
+ // Clean up when component is destroyed
98
+ if (component.lifecycle) {
99
+ const originalDestroy = component.lifecycle.destroy
100
+ component.lifecycle.destroy = () => {
101
+ items.clear()
102
+ originalDestroy?.()
103
+ }
104
+ }
105
+
106
+ return {
107
+ ...component,
108
+ items,
109
+
110
+ addItem (itemConfig) {
111
+ if (items.has(itemConfig.id)) return this
112
+
113
+ const item = createNavItem(itemConfig, component.element, config.prefix)
114
+ storeItem(itemConfig, item)
115
+
116
+ if (itemConfig.active) {
117
+ this.setActive(itemConfig.id)
118
+ }
119
+
120
+ component.emit('itemAdded', {
121
+ id: itemConfig.id,
122
+ item: { element: item, config: itemConfig }
123
+ })
124
+ return this
125
+ },
126
+
127
+ removeItem (id) {
128
+ const item = items.get(id)
129
+ if (!item) return this
130
+
131
+ // Remove all nested items first
132
+ const nestedItems = getAllNestedItems(item.element, config.prefix)
133
+ nestedItems.forEach(nestedItem => {
134
+ const nestedId = nestedItem.dataset.id
135
+ if (nestedId) items.delete(nestedId)
136
+ })
137
+
138
+ if (activeItem?.config.id === id) {
139
+ activeItem = null
140
+ }
141
+
142
+ // Remove the entire item container
143
+ const container = item.element.closest(`.${config.prefix}-nav-item-container`)
144
+ container?.remove()
145
+ items.delete(id)
146
+
147
+ component.emit('itemRemoved', { id, item })
148
+ return this
149
+ },
150
+
151
+ getItem: (id) => items.get(id),
152
+ getAllItems: () => Array.from(items.values()),
153
+ getActive: () => activeItem,
154
+ getItemPath: (id) => getItemPath(id),
155
+
156
+ setActive (id) {
157
+ const item = items.get(id)
158
+ if (!item || item.config.disabled) return this
159
+
160
+ if (activeItem) {
161
+ activeItem.element.classList.remove(`${config.prefix}-nav-item--active`)
162
+ activeItem.element.setAttribute('aria-selected', 'false')
163
+ }
164
+
165
+ item.element.classList.add(`${config.prefix}-nav-item--active`)
166
+ item.element.setAttribute('aria-selected', 'true')
167
+ activeItem = item
168
+
169
+ // Ensure all parent items are expanded
170
+ const path = getItemPath(id)
171
+ path.forEach(parentId => {
172
+ const parentItem = items.get(parentId)
173
+ if (parentItem) {
174
+ const parentButton = parentItem.element
175
+ const nestedContainer = parentButton.closest(`.${config.prefix}-nav-item-container`)
176
+ .querySelector(`.${config.prefix}-nav-nested-container`)
177
+
178
+ parentButton.setAttribute('aria-expanded', 'true')
179
+ nestedContainer.hidden = false
180
+ }
181
+ })
182
+
183
+ component.emit('activeChanged', {
184
+ id,
185
+ item,
186
+ previousItem: activeItem,
187
+ path: getItemPath(id)
188
+ })
189
+ return this
190
+ }
191
+ }
192
+ }
@@ -0,0 +1,2 @@
1
+ // src/components/navigation/index.js
2
+ export { default } from './navigation.js'
@@ -0,0 +1,137 @@
1
+ // src/components/navigation/nav-item.js
2
+
3
+ /**
4
+ * Creates an expand/collapse icon element
5
+ * @param {string} prefix - CSS class prefix
6
+ * @returns {HTMLElement} Expand icon element
7
+ */
8
+ const createExpandIcon = (prefix) => {
9
+ const icon = document.createElement('span')
10
+ icon.className = `${prefix}-nav-expand-icon`
11
+ icon.innerHTML = `
12
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
13
+ <polyline points="9 18 15 12 9 6"></polyline>
14
+ </svg>
15
+ `
16
+ return icon
17
+ }
18
+
19
+ /**
20
+ * Creates a nested items container
21
+ * @param {Array} items - Nested items configuration
22
+ * @param {string} prefix - CSS class prefix
23
+ * @param {Function} createItem - Item creation function
24
+ * @returns {HTMLElement} Nested items container
25
+ */
26
+ const createNestedContainer = (items, prefix, createItem) => {
27
+ const container = document.createElement('div')
28
+ container.className = `${prefix}-nav-nested-container`
29
+ container.setAttribute('role', 'group')
30
+ container.hidden = true
31
+
32
+ items.forEach(itemConfig => {
33
+ createItem(itemConfig, container, prefix)
34
+ })
35
+
36
+ return container
37
+ }
38
+
39
+ /**
40
+ * Creates a navigation item element
41
+ * @param {Object} config - Item configuration
42
+ * @param {HTMLElement} container - Container element
43
+ * @param {string} prefix - CSS class prefix
44
+ * @returns {HTMLElement} Created navigation item
45
+ */
46
+ export const createNavItem = (config, container, prefix) => {
47
+ const itemContainer = document.createElement('div')
48
+ itemContainer.className = `${prefix}-nav-item-container`
49
+
50
+ const item = document.createElement('button')
51
+ item.className = `${prefix}-nav-item`
52
+ item.setAttribute('role', config.items?.length ? 'button' : 'menuitem')
53
+ item.setAttribute('aria-selected', 'false')
54
+
55
+ if (config.id) {
56
+ item.dataset.id = config.id
57
+ }
58
+
59
+ if (config.disabled) {
60
+ item.disabled = true
61
+ item.setAttribute('aria-disabled', 'true')
62
+ }
63
+
64
+ // Add icon if provided
65
+ if (config.icon) {
66
+ const icon = document.createElement('span')
67
+ icon.className = `${prefix}-nav-item-icon`
68
+ icon.innerHTML = config.icon
69
+ item.appendChild(icon)
70
+ }
71
+
72
+ // Add label if provided
73
+ if (config.label) {
74
+ const label = document.createElement('span')
75
+ label.className = `${prefix}-nav-item-label`
76
+ label.textContent = config.label
77
+ item.appendChild(label)
78
+ item.setAttribute('aria-label', config.label)
79
+ }
80
+
81
+ // Add badge if provided
82
+ if (config.badge) {
83
+ const badge = document.createElement('span')
84
+ badge.className = `${prefix}-nav-item-badge`
85
+ badge.textContent = config.badge
86
+ badge.setAttribute('aria-label', `${config.badge} notifications`)
87
+ item.appendChild(badge)
88
+ }
89
+
90
+ itemContainer.appendChild(item)
91
+
92
+ // Handle nested items - only for drawer variant
93
+ if (config.items?.length && container.closest('.mtrl-nav--drawer, .mtrl-nav--drawer-modal, .mtrl-nav--drawer-standard')) {
94
+ const expandIcon = createExpandIcon(prefix)
95
+ item.appendChild(expandIcon)
96
+
97
+ item.setAttribute('aria-expanded', config.expanded ? 'true' : 'false')
98
+ item.setAttribute('aria-haspopup', 'true')
99
+
100
+ const nestedContainer = createNestedContainer(config.items, prefix, createNavItem)
101
+ nestedContainer.hidden = !config.expanded
102
+ itemContainer.appendChild(nestedContainer)
103
+
104
+ // Handle expand/collapse
105
+ item.addEventListener('click', (event) => {
106
+ event.stopPropagation()
107
+ const isExpanded = item.getAttribute('aria-expanded') === 'true'
108
+ item.setAttribute('aria-expanded', (!isExpanded).toString())
109
+ nestedContainer.hidden = isExpanded
110
+
111
+ // Toggle expand icon rotation
112
+ expandIcon.style.transform = isExpanded ? '' : 'rotate(90deg)'
113
+ })
114
+ }
115
+
116
+ container.appendChild(itemContainer)
117
+ return item
118
+ }
119
+
120
+ /**
121
+ * Recursively gets all nested items from a navigation item
122
+ * @param {HTMLElement} item - Navigation item element
123
+ * @param {string} prefix - CSS class prefix
124
+ * @returns {Array<HTMLElement>} Array of all nested items
125
+ */
126
+ export const getAllNestedItems = (item, prefix) => {
127
+ const container = item.closest(`.${prefix}-nav-item-container`)
128
+ if (!container) return []
129
+
130
+ const nestedContainer = container.querySelector(`.${prefix}-nav-nested-container`)
131
+ if (!nestedContainer) return []
132
+
133
+ const items = Array.from(nestedContainer.querySelectorAll(`.${prefix}-nav-item`))
134
+ return items.reduce((acc, nestedItem) => {
135
+ return [...acc, nestedItem, ...getAllNestedItems(nestedItem, prefix)]
136
+ }, [])
137
+ }
@@ -0,0 +1,55 @@
1
+ // src/components/navigation/index.js
2
+ import { PREFIX } from '../../core/config'
3
+ import { pipe } from '../../core/compose'
4
+ import { createBase, withElement } from '../../core/compose/component'
5
+ import {
6
+ withEvents,
7
+ withDisabled,
8
+ withLifecycle,
9
+ withVariant,
10
+ withPosition // Import core position feature
11
+ } from '../../core/compose/features'
12
+ import { withAPI } from './api'
13
+ import { withNavItems } from './features/items'
14
+
15
+ /**
16
+ * Creates a new Navigation component
17
+ * @param {Object} config - Navigation configuration
18
+ * @param {string} [config.variant='rail'] - Navigation type (rail/drawer/bar)
19
+ * @param {string} [config.position='left'] - Navigation position
20
+ * @param {Array} [config.items=[]] - Navigation items
21
+ * @param {boolean} [config.disabled=false] - Is navigation disabled
22
+ * @param {string} [config.class] - Additional CSS classes
23
+ */
24
+ const createNavigation = (config = {}) => {
25
+ const baseConfig = {
26
+ ...config,
27
+ componentName: 'nav',
28
+ prefix: PREFIX
29
+ }
30
+
31
+ return pipe(
32
+ createBase,
33
+ // First add events system
34
+ withEvents(),
35
+ // Then add the element and other features
36
+ withElement({
37
+ tag: 'nav',
38
+ role: 'navigation',
39
+ 'aria-label': config.ariaLabel || 'Main Navigation',
40
+ componentName: 'nav',
41
+ className: config.class
42
+ }),
43
+ withVariant(baseConfig),
44
+ withPosition(baseConfig),
45
+ withNavItems(baseConfig),
46
+ withDisabled(),
47
+ withLifecycle(),
48
+ comp => withAPI({
49
+ disabled: comp.disabled,
50
+ lifecycle: comp.lifecycle
51
+ })(comp)
52
+ )(baseConfig)
53
+ }
54
+
55
+ export default createNavigation
@@ -0,0 +1,51 @@
1
+ // src/components/navigation/styles/_bar.scss
2
+ @use 'sass:map';
3
+ @use '../../../styles/abstract/config' as c;
4
+ @use 'base';
5
+
6
+ .#{c.$prefix}-nav {
7
+ &--bar {
8
+ flex-direction: row;
9
+ width: 100%;
10
+ height: 80px;
11
+ padding: 0 12px;
12
+ justify-content: space-around;
13
+
14
+ .#{c.$prefix}-nav-item {
15
+ flex: 1;
16
+ flex-direction: column;
17
+ height: 100%;
18
+ max-width: 168px;
19
+ gap: 4px;
20
+
21
+ &:hover {
22
+ .#{c.$prefix}-nav-item-icon {
23
+ @include c.state-layer(var(--mtrl-sys-color-on-surface), 'hover');
24
+ }
25
+ }
26
+
27
+ &--active {
28
+ .#{c.$prefix}-nav-item-icon {
29
+ background-color: var(--mtrl-sys-color-secondary-container);
30
+ }
31
+ }
32
+
33
+ &-icon {
34
+ margin-bottom: 4px;
35
+ padding: 16px;
36
+ @include c.motion-transition(background-color);
37
+ }
38
+
39
+ &-label {
40
+ @include c.typography('label-medium');
41
+ text-align: center;
42
+ }
43
+
44
+ &-badge {
45
+ top: 4px;
46
+ right: 50%;
47
+ transform: translateX(12px);
48
+ }
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,129 @@
1
+ // src/components/navigation/styles/_base.scss
2
+ @use 'sass:map';
3
+ @use '../../../styles/abstract/config' as c;
4
+
5
+ .#{c.$prefix}-nav {
6
+ display: flex;
7
+ position: relative;
8
+ background-color: var(--mtrl-sys-color-surface-container);
9
+
10
+ // Base nav item styles
11
+ &-item {
12
+ display: flex;
13
+ align-items: center;
14
+ justify-content: center;
15
+ position: relative;
16
+ border: none;
17
+ background: none;
18
+ cursor: pointer;
19
+ padding: 12px;
20
+ gap: 12px;
21
+ color: var(--mtrl-sys-color-on-surface-variant);
22
+ @include c.motion-transition(all);
23
+
24
+ &-icon {
25
+ display: flex;
26
+ align-items: center;
27
+ justify-content: center;
28
+ width: 24px;
29
+ height: 24px;
30
+ color: inherit;
31
+ border-radius: 50%;
32
+ padding: 8px;
33
+
34
+ svg {
35
+ width: 24px;
36
+ height: 24px;
37
+ fill: currentColor;
38
+ }
39
+ }
40
+
41
+ &--active {
42
+ color: var(--mtrl-sys-color-primary);
43
+ }
44
+
45
+ &-label {
46
+ @include c.typography('label-large');
47
+ @include c.motion-transition(opacity);
48
+ }
49
+
50
+ &-badge {
51
+ position: absolute;
52
+ top: 8px;
53
+ right: 8px;
54
+ min-width: 16px;
55
+ height: 16px;
56
+ padding: 0 4px;
57
+ border-radius: 8px;
58
+ background-color: var(--mtrl-sys-color-error);
59
+ color: var(--mtrl-sys-color-on-error);
60
+ @include c.typography('label-small');
61
+ display: flex;
62
+ align-items: center;
63
+ justify-content: center;
64
+ }
65
+ }
66
+
67
+ // Navigation positions
68
+ &--left {
69
+ left: 0;
70
+ }
71
+
72
+ &--right {
73
+ right: 0;
74
+ }
75
+
76
+ &--top {
77
+ top: 0;
78
+ }
79
+
80
+ &--bottom {
81
+ bottom: 0;
82
+ }
83
+
84
+ // States
85
+ &--disabled {
86
+ opacity: 0.38;
87
+ pointer-events: none;
88
+ }
89
+
90
+ // RTL Support
91
+ @include c.rtl {
92
+ &--left {
93
+ right: 0;
94
+ left: auto;
95
+ }
96
+
97
+ &--right {
98
+ left: 0;
99
+ right: auto;
100
+ }
101
+
102
+ .#{c.$prefix}-nav-item {
103
+ &-badge {
104
+ right: auto;
105
+ left: 8px;
106
+ }
107
+ }
108
+ }
109
+
110
+ // Motion
111
+ @include c.reduced-motion {
112
+ &-item,
113
+ &-item-label {
114
+ transition: none;
115
+ }
116
+ }
117
+
118
+ // High contrast
119
+ @include c.high-contrast {
120
+ border: 1px solid currentColor;
121
+
122
+ &-item {
123
+ &--active {
124
+ outline: 2px solid currentColor;
125
+ outline-offset: -2px;
126
+ }
127
+ }
128
+ }
129
+ }