mtrl 0.1.2 → 0.2.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 (220) hide show
  1. package/README.md +70 -22
  2. package/index.ts +33 -0
  3. package/package.json +14 -5
  4. package/src/components/button/{styles.scss → _styles.scss} +2 -2
  5. package/src/components/button/api.ts +89 -0
  6. package/src/components/button/button.ts +50 -0
  7. package/src/components/button/config.ts +75 -0
  8. package/src/components/button/constants.ts +17 -0
  9. package/src/components/button/index.ts +4 -0
  10. package/src/components/button/types.ts +118 -0
  11. package/src/components/card/_styles.scss +359 -0
  12. package/src/components/card/actions.ts +48 -0
  13. package/src/components/card/api.ts +102 -0
  14. package/src/components/card/card.ts +41 -0
  15. package/src/components/card/config.ts +99 -0
  16. package/src/components/card/constants.ts +69 -0
  17. package/src/components/card/content.ts +48 -0
  18. package/src/components/card/features.ts +228 -0
  19. package/src/components/card/header.ts +88 -0
  20. package/src/components/card/index.ts +19 -0
  21. package/src/components/card/media.ts +52 -0
  22. package/src/components/card/types.ts +174 -0
  23. package/src/components/checkbox/api.ts +82 -0
  24. package/src/components/checkbox/checkbox.ts +75 -0
  25. package/src/components/checkbox/config.ts +90 -0
  26. package/src/components/checkbox/index.ts +4 -0
  27. package/src/components/checkbox/types.ts +146 -0
  28. package/src/components/chip/_styles.scss +372 -0
  29. package/src/components/chip/api.ts +115 -0
  30. package/src/components/chip/chip-set.ts +225 -0
  31. package/src/components/chip/chip.ts +82 -0
  32. package/src/components/chip/config.ts +92 -0
  33. package/src/components/chip/constants.ts +38 -0
  34. package/src/components/chip/index.ts +4 -0
  35. package/src/components/chip/types.ts +172 -0
  36. package/src/components/list/api.ts +72 -0
  37. package/src/components/list/config.ts +43 -0
  38. package/src/components/list/{constants.js → constants.ts} +34 -7
  39. package/src/components/list/features.ts +224 -0
  40. package/src/components/list/index.ts +14 -0
  41. package/src/components/list/list-item.ts +120 -0
  42. package/src/components/list/list.ts +37 -0
  43. package/src/components/list/types.ts +179 -0
  44. package/src/components/list/utils.ts +47 -0
  45. package/src/components/menu/api.ts +119 -0
  46. package/src/components/menu/config.ts +54 -0
  47. package/src/components/menu/constants.ts +154 -0
  48. package/src/components/menu/features/items-manager.ts +457 -0
  49. package/src/components/menu/features/keyboard-navigation.ts +133 -0
  50. package/src/components/menu/features/positioning.ts +127 -0
  51. package/src/components/menu/features/{visibility.js → visibility.ts} +66 -64
  52. package/src/components/menu/index.ts +14 -0
  53. package/src/components/menu/menu-item.ts +43 -0
  54. package/src/components/menu/menu.ts +53 -0
  55. package/src/components/menu/types.ts +178 -0
  56. package/src/components/navigation/api.ts +79 -0
  57. package/src/components/navigation/config.ts +61 -0
  58. package/src/components/navigation/{constants.js → constants.ts} +10 -10
  59. package/src/components/navigation/index.ts +14 -0
  60. package/src/components/navigation/nav-item.ts +148 -0
  61. package/src/components/navigation/navigation.ts +50 -0
  62. package/src/components/navigation/types.ts +212 -0
  63. package/src/components/progress/_styles.scss +204 -0
  64. package/src/components/progress/api.ts +179 -0
  65. package/src/components/progress/config.ts +124 -0
  66. package/src/components/progress/constants.ts +43 -0
  67. package/src/components/progress/index.ts +5 -0
  68. package/src/components/progress/progress.ts +163 -0
  69. package/src/components/progress/types.ts +102 -0
  70. package/src/components/snackbar/api.ts +162 -0
  71. package/src/components/snackbar/config.ts +62 -0
  72. package/src/components/snackbar/{constants.js → constants.ts} +21 -4
  73. package/src/components/snackbar/features.ts +76 -0
  74. package/src/components/snackbar/index.ts +4 -0
  75. package/src/components/snackbar/position.ts +71 -0
  76. package/src/components/snackbar/queue.ts +76 -0
  77. package/src/components/snackbar/snackbar.ts +60 -0
  78. package/src/components/snackbar/types.ts +58 -0
  79. package/src/components/switch/api.ts +77 -0
  80. package/src/components/switch/config.ts +74 -0
  81. package/src/components/switch/index.ts +4 -0
  82. package/src/components/switch/switch.ts +52 -0
  83. package/src/components/switch/types.ts +142 -0
  84. package/src/components/textfield/api.ts +72 -0
  85. package/src/components/textfield/config.ts +54 -0
  86. package/src/components/textfield/{constants.js → constants.ts} +38 -5
  87. package/src/components/textfield/index.ts +4 -0
  88. package/src/components/textfield/textfield.ts +50 -0
  89. package/src/components/textfield/types.ts +139 -0
  90. package/src/core/compose/base.ts +43 -0
  91. package/src/core/compose/component.ts +247 -0
  92. package/src/core/compose/features/checkable.ts +155 -0
  93. package/src/core/compose/features/disabled.ts +116 -0
  94. package/src/core/compose/features/events.ts +65 -0
  95. package/src/core/compose/features/icon.ts +67 -0
  96. package/src/core/compose/features/index.ts +35 -0
  97. package/src/core/compose/features/input.ts +174 -0
  98. package/src/core/compose/features/lifecycle.ts +139 -0
  99. package/src/core/compose/features/position.ts +94 -0
  100. package/src/core/compose/features/ripple.ts +55 -0
  101. package/src/core/compose/features/size.ts +29 -0
  102. package/src/core/compose/features/style.ts +31 -0
  103. package/src/core/compose/features/text.ts +44 -0
  104. package/src/core/compose/features/textinput.ts +225 -0
  105. package/src/core/compose/features/textlabel.ts +92 -0
  106. package/src/core/compose/features/track.ts +84 -0
  107. package/src/core/compose/features/variant.ts +29 -0
  108. package/src/core/compose/features/withEvents.ts +137 -0
  109. package/src/core/compose/index.ts +54 -0
  110. package/src/core/compose/{pipe.js → pipe.ts} +16 -11
  111. package/src/core/config/component-config.ts +136 -0
  112. package/src/core/config.ts +211 -0
  113. package/src/core/dom/{attributes.js → attributes.ts} +11 -11
  114. package/src/core/dom/classes.ts +60 -0
  115. package/src/core/dom/create.ts +188 -0
  116. package/src/core/dom/events.ts +209 -0
  117. package/src/core/dom/index.ts +10 -0
  118. package/src/core/dom/utils.ts +97 -0
  119. package/src/core/index.ts +111 -0
  120. package/src/core/state/disabled.ts +81 -0
  121. package/src/core/state/emitter.ts +94 -0
  122. package/src/core/state/events.ts +88 -0
  123. package/src/core/state/index.ts +16 -0
  124. package/src/core/state/lifecycle.ts +131 -0
  125. package/src/core/state/store.ts +197 -0
  126. package/src/core/utils/index.ts +45 -0
  127. package/src/core/utils/{mobile.js → mobile.ts} +48 -24
  128. package/src/core/utils/object.ts +41 -0
  129. package/src/core/utils/validate.ts +234 -0
  130. package/src/{index.js → index.ts} +4 -2
  131. package/index.js +0 -11
  132. package/src/components/button/api.js +0 -54
  133. package/src/components/button/button.js +0 -81
  134. package/src/components/button/config.js +0 -10
  135. package/src/components/button/constants.js +0 -63
  136. package/src/components/button/index.js +0 -2
  137. package/src/components/checkbox/api.js +0 -45
  138. package/src/components/checkbox/checkbox.js +0 -96
  139. package/src/components/checkbox/index.js +0 -2
  140. package/src/components/container/api.js +0 -42
  141. package/src/components/container/container.js +0 -45
  142. package/src/components/container/index.js +0 -2
  143. package/src/components/container/styles.scss +0 -66
  144. package/src/components/list/index.js +0 -2
  145. package/src/components/list/list-item.js +0 -147
  146. package/src/components/list/list.js +0 -267
  147. package/src/components/menu/api.js +0 -117
  148. package/src/components/menu/constants.js +0 -42
  149. package/src/components/menu/features/items-manager.js +0 -375
  150. package/src/components/menu/features/keyboard-navigation.js +0 -129
  151. package/src/components/menu/features/positioning.js +0 -125
  152. package/src/components/menu/index.js +0 -2
  153. package/src/components/menu/menu-item.js +0 -41
  154. package/src/components/menu/menu.js +0 -54
  155. package/src/components/navigation/api.js +0 -43
  156. package/src/components/navigation/index.js +0 -2
  157. package/src/components/navigation/nav-item.js +0 -137
  158. package/src/components/navigation/navigation.js +0 -55
  159. package/src/components/snackbar/api.js +0 -125
  160. package/src/components/snackbar/features.js +0 -69
  161. package/src/components/snackbar/index.js +0 -2
  162. package/src/components/snackbar/position.js +0 -63
  163. package/src/components/snackbar/queue.js +0 -74
  164. package/src/components/snackbar/snackbar.js +0 -70
  165. package/src/components/switch/api.js +0 -44
  166. package/src/components/switch/index.js +0 -2
  167. package/src/components/switch/switch.js +0 -71
  168. package/src/components/textfield/api.js +0 -49
  169. package/src/components/textfield/index.js +0 -2
  170. package/src/components/textfield/textfield.js +0 -68
  171. package/src/core/build/_ripple.scss +0 -79
  172. package/src/core/build/constants.js +0 -51
  173. package/src/core/build/icon.js +0 -78
  174. package/src/core/build/ripple.js +0 -159
  175. package/src/core/build/text.js +0 -54
  176. package/src/core/compose/base.js +0 -8
  177. package/src/core/compose/component.js +0 -225
  178. package/src/core/compose/features/checkable.js +0 -114
  179. package/src/core/compose/features/disabled.js +0 -64
  180. package/src/core/compose/features/events.js +0 -48
  181. package/src/core/compose/features/icon.js +0 -33
  182. package/src/core/compose/features/index.js +0 -20
  183. package/src/core/compose/features/input.js +0 -100
  184. package/src/core/compose/features/lifecycle.js +0 -69
  185. package/src/core/compose/features/position.js +0 -60
  186. package/src/core/compose/features/ripple.js +0 -32
  187. package/src/core/compose/features/size.js +0 -9
  188. package/src/core/compose/features/style.js +0 -12
  189. package/src/core/compose/features/text.js +0 -17
  190. package/src/core/compose/features/textinput.js +0 -114
  191. package/src/core/compose/features/textlabel.js +0 -28
  192. package/src/core/compose/features/track.js +0 -49
  193. package/src/core/compose/features/variant.js +0 -9
  194. package/src/core/compose/features/withEvents.js +0 -67
  195. package/src/core/compose/index.js +0 -16
  196. package/src/core/config.js +0 -140
  197. package/src/core/dom/classes.js +0 -70
  198. package/src/core/dom/create.js +0 -132
  199. package/src/core/dom/events.js +0 -175
  200. package/src/core/dom/index.js +0 -5
  201. package/src/core/dom/utils.js +0 -22
  202. package/src/core/index.js +0 -23
  203. package/src/core/state/disabled.js +0 -51
  204. package/src/core/state/emitter.js +0 -63
  205. package/src/core/state/events.js +0 -29
  206. package/src/core/state/index.js +0 -6
  207. package/src/core/state/lifecycle.js +0 -64
  208. package/src/core/state/store.js +0 -112
  209. package/src/core/utils/index.js +0 -39
  210. package/src/core/utils/object.js +0 -22
  211. package/src/core/utils/validate.js +0 -37
  212. /package/src/components/checkbox/{styles.scss → _styles.scss} +0 -0
  213. /package/src/components/checkbox/{constants.js → constants.ts} +0 -0
  214. /package/src/components/list/{styles.scss → _styles.scss} +0 -0
  215. /package/src/components/menu/{styles.scss → _styles.scss} +0 -0
  216. /package/src/components/navigation/{styles.scss → _styles.scss} +0 -0
  217. /package/src/components/snackbar/{styles.scss → _styles.scss} +0 -0
  218. /package/src/components/switch/{styles.scss → _styles.scss} +0 -0
  219. /package/src/components/switch/{constants.js → constants.ts} +0 -0
  220. /package/src/components/textfield/{styles.scss → _styles.scss} +0 -0
@@ -1,44 +0,0 @@
1
- // src/components/switch/api.js
2
-
3
- /**
4
- * Enhances switch 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
-
27
- // Label management
28
- setLabel (text) {
29
- component.text?.setText(text)
30
- return this
31
- },
32
- getLabel () {
33
- return component.text?.getText() || ''
34
- },
35
-
36
- // Event handling
37
- on: component.on,
38
- off: component.off,
39
-
40
- // State management
41
- enable: disabled.enable,
42
- disable: disabled.disable,
43
- destroy: lifecycle.destroy
44
- })
@@ -1,2 +0,0 @@
1
- // src/components/switch/index.js
2
- export { default } from './switch.js'
@@ -1,71 +0,0 @@
1
- // src/components/switch/switch.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
- withTextLabel,
8
- withDisabled,
9
- withLifecycle,
10
- withInput,
11
- withTrack,
12
- withCheckable
13
- } from '../../core/compose/features'
14
- import { withAPI } from './api'
15
-
16
- /**
17
- * Adds label position handling to switch
18
- */
19
- const withLabelPosition = (config) => (component) => {
20
- if (!config.label) return component
21
-
22
- const position = config.labelPosition || 'end'
23
- component.element.classList.add(`${PREFIX}-switch--label-${position}`)
24
-
25
- return component
26
- }
27
-
28
- /**
29
- * Creates a new Switch component
30
- * @param {Object} config - Switch configuration
31
- * @param {string} [config.name] - Input name
32
- * @param {boolean} [config.checked] - Initial checked state
33
- * @param {boolean} [config.required] - Is input required
34
- * @param {boolean} [config.disabled] - Is switch disabled
35
- * @param {string} [config.value] - Input value
36
- * @param {string} [config.label] - Label text
37
- * @param {string} [config.labelPosition='end'] - Label position (start/end)
38
- * @param {string} [config.class] - Additional CSS classes
39
- */
40
- const createSwitch = (config = {}) => {
41
- const baseConfig = {
42
- ...config,
43
- componentName: 'switch',
44
- prefix: PREFIX
45
- }
46
-
47
- return pipe(
48
- createBase,
49
- withEvents(), // Move events first to ensure system is available
50
- withElement({
51
- tag: 'div',
52
- componentName: 'switch',
53
- className: config.class,
54
- interactive: true
55
- }),
56
- withInput(baseConfig),
57
- withTrack(baseConfig),
58
- withTextLabel(baseConfig),
59
- withLabelPosition(baseConfig),
60
- withCheckable(baseConfig),
61
- withDisabled(baseConfig), // Pass the config to ensure disabled state is properly initialized
62
- withLifecycle(),
63
- comp => withAPI({
64
- disabled: comp.disabled,
65
- lifecycle: comp.lifecycle,
66
- checkable: comp.checkable
67
- })(comp)
68
- )(baseConfig)
69
- }
70
-
71
- export default createSwitch
@@ -1,49 +0,0 @@
1
- // src/components/textfield/api.js
2
-
3
- /**
4
- * Enhances textfield 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
- */
9
- export const withAPI = ({ disabled, lifecycle }) => (component) => ({
10
- ...component,
11
- // Core element reference
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
- // Attributes API
22
- setAttribute (name, value) {
23
- component.setAttribute(name, value)
24
- return this
25
- },
26
- getAttribute: component.getAttribute,
27
- removeAttribute (name) {
28
- component.removeAttribute(name)
29
- return this
30
- },
31
-
32
- // Label management
33
- setLabel (text) {
34
- component.label?.setText(text)
35
- return this
36
- },
37
- getLabel () {
38
- return component.label?.getText() || ''
39
- },
40
-
41
- // Event handling
42
- on: component.on,
43
- off: component.off,
44
-
45
- // State management
46
- enable: disabled.enable,
47
- disable: disabled.disable,
48
- destroy: lifecycle.destroy
49
- })
@@ -1,2 +0,0 @@
1
- // src/components/textfield/index.js
2
- export { default } from './textfield.js'
@@ -1,68 +0,0 @@
1
- // src/components/textfield/textfield.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
- withSize,
11
- withTextInput,
12
- withTextLabel
13
- } from '../../core/compose/features'
14
- import { withAPI } from './api'
15
- import { TEXTFIELD_VARIANTS } from './constants'
16
-
17
- /**
18
- * Creates a new Textfield component
19
- * @param {Object} config - Textfield configuration
20
- * @param {string} [config.type] - Input type (text, password, email, etc.)
21
- * @param {string} [config.variant] - Visual variant (filled, outlined)
22
- * @param {string} [config.size] - Size variant (small, medium, large)
23
- * @param {string} [config.name] - Input name attribute
24
- * @param {string} [config.label] - Label text
25
- * @param {string} [config.placeholder] - Placeholder text
26
- * @param {string} [config.value] - Initial value
27
- * @param {boolean} [config.required] - Whether the input is required
28
- * @param {boolean} [config.disabled] - Whether the input is disabled
29
- * @param {number} [config.maxLength] - Maximum input length
30
- * @param {string} [config.pattern] - Input pattern for validation
31
- * @param {string} [config.autocomplete] - Autocomplete attribute
32
- * @param {string} [config.class] - Additional CSS classes
33
- * @returns {Object} Textfield component instance
34
- */
35
- const createTextfield = (config = {}) => {
36
- const baseConfig = {
37
- ...config,
38
- componentName: 'textfield',
39
- prefix: PREFIX,
40
- variant: config.variant || TEXTFIELD_VARIANTS.FILLED
41
- }
42
-
43
- try {
44
- return pipe(
45
- createBase,
46
- withEvents(),
47
- withElement({
48
- tag: 'div',
49
- componentName: 'textfield',
50
- className: config.class
51
- }),
52
- withVariant(baseConfig),
53
- withSize(baseConfig),
54
- withTextInput(baseConfig),
55
- withTextLabel(baseConfig),
56
- withDisabled(baseConfig),
57
- withLifecycle(),
58
- comp => withAPI({
59
- disabled: comp.disabled,
60
- lifecycle: comp.lifecycle
61
- })(comp)
62
- )(baseConfig)
63
- } catch (error) {
64
- throw new Error(`Failed to create textfield: ${error.message}`)
65
- }
66
- }
67
-
68
- export default createTextfield
@@ -1,79 +0,0 @@
1
- // src/components/ripple/_ripple.scss
2
- @use '../../styles/abstract/base' as base;
3
- @use '../../styles/abstract/variables' as v;
4
- @use '../../styles/abstract/functions' as f;
5
- @use '../../styles/abstract/mixins' as m;
6
- @use '../../styles/abstract/theme' as t;
7
-
8
- $component: '#{base.$prefix}-ripple';
9
-
10
- .#{$component} {
11
- // Ripple container
12
- position: absolute;
13
- top: 0;
14
- left: 0;
15
- right: 0;
16
- bottom: 0;
17
- overflow: hidden;
18
- border-radius: inherit;
19
- pointer-events: none;
20
- z-index: 0;
21
-
22
- // Ripple element
23
- &-wave {
24
- position: absolute;
25
- border-radius: 50%;
26
- background-color: currentColor;
27
- transform: scale(0);
28
- opacity: 0;
29
- pointer-events: none;
30
- will-change: transform, opacity;
31
-
32
- // Animation
33
- transition-property: transform, opacity;
34
- transition-duration: v.motion('duration-short4');
35
- transition-timing-function: v.motion('easing-standard');
36
-
37
- // Active ripple
38
- &.active {
39
- transform: scale(1);
40
- opacity: v.state('hover-state-layer-opacity');
41
- }
42
-
43
- &.fade-out {
44
- opacity: 0;
45
- }
46
- }
47
- }
48
-
49
- // Standalone utility for adding ripple to any element
50
- [data-ripple] {
51
- position: relative;
52
- overflow: hidden;
53
-
54
- &::after {
55
- content: '';
56
- position: absolute;
57
- top: 0;
58
- left: 0;
59
- right: 0;
60
- bottom: 0;
61
- z-index: 0;
62
- pointer-events: none;
63
- }
64
-
65
- // Handle ripple color based on data attribute
66
- &[data-ripple="light"]::after {
67
- background-color: rgba(255, 255, 255, 0.3);
68
- }
69
-
70
- &[data-ripple="dark"]::after {
71
- background-color: rgba(0, 0, 0, 0.1);
72
- }
73
-
74
- // Make content appear above ripple
75
- > * {
76
- position: relative;
77
- z-index: 1;
78
- }
79
- }
@@ -1,51 +0,0 @@
1
- // src/core/build/constants.js
2
-
3
- /**
4
- * Animation timing functions for ripple effect
5
- * @enum {string}
6
- */
7
- export const RIPPLE_TIMING = {
8
- LINEAR: 'linear',
9
- EASE: 'ease',
10
- EASE_IN: 'ease-in',
11
- EASE_OUT: 'ease-out',
12
- EASE_IN_OUT: 'ease-in-out',
13
- MATERIAL: 'cubic-bezier(0.4, 0.0, 0.2, 1)'
14
- }
15
-
16
- /**
17
- * Default configuration for ripple effect
18
- * @type {Object}
19
- */
20
- export const RIPPLE_CONFIG = {
21
- duration: 375,
22
- timing: RIPPLE_TIMING.LINEAR,
23
- opacity: ['1', '0.3']
24
- }
25
-
26
- /**
27
- * Validation schema for ripple configuration
28
- * @type {Object}
29
- */
30
- export const RIPPLE_SCHEMA = {
31
- duration: {
32
- type: 'number',
33
- minimum: 0,
34
- default: RIPPLE_CONFIG.duration
35
- },
36
- timing: {
37
- type: 'string',
38
- enum: Object.values(RIPPLE_TIMING),
39
- default: RIPPLE_CONFIG.timing
40
- },
41
- opacity: {
42
- type: 'array',
43
- items: {
44
- type: 'string',
45
- pattern: '^[0-1](\\.\\d+)?$'
46
- },
47
- minItems: 2,
48
- maxItems: 2,
49
- default: RIPPLE_CONFIG.opacity
50
- }
51
- }
@@ -1,78 +0,0 @@
1
- // src/core/build/icon.js
2
- /**
3
- * @module core/build
4
- */
5
-
6
- /**
7
- * Creates an icon DOM element
8
- * @memberof module:core/build
9
- * @private
10
- * @param {string} html - Icon HTML content
11
- * @param {Object} [options] - Icon options
12
- * @param {string} [options.prefix='mtrl'] - Class prefix
13
- * @param {string} [options.class] - Additional CSS class
14
- * @param {string} [options.size] - Icon size variant
15
- * @returns {HTMLElement} Icon element
16
- */
17
- const createIconElement = (html, options = {}) => {
18
- const PREFIX = options.prefix || 'mtrl'
19
- const element = document.createElement('span')
20
- element.className = `${PREFIX}-icon`
21
-
22
- if (options.class) {
23
- element.classList.add(options.class)
24
- }
25
- if (options.size) {
26
- element.classList.add(`${PREFIX}-icon--${options.size}`)
27
- }
28
-
29
- element.innerHTML = html
30
- return element
31
- }
32
-
33
- /**
34
- * Creates an icon manager for a component
35
- * @memberof module:core/build
36
- * @function createIcon
37
- * @param {HTMLElement} element - Parent element
38
- * @param {Object} [config] - Icon configuration
39
- * @param {string} [config.prefix='mtrl'] - Class prefix
40
- * @param {string} [config.type='component'] - Component type
41
- * @param {string} [config.position] - Icon position ('start' or 'end')
42
- * @returns {Object} Icon manager interface
43
- * @property {Function} setIcon - Sets icon content
44
- * @property {Function} getIcon - Gets current icon content
45
- * @property {Function} getElement - Gets icon element
46
- */
47
- export const createIcon = (element, config = {}) => {
48
- let iconElement = null
49
- const PREFIX = config.prefix || 'mtrl'
50
-
51
- return {
52
- setIcon (html) {
53
- if (!iconElement && html) {
54
- iconElement = createIconElement(html, {
55
- prefix: PREFIX,
56
- class: `${PREFIX}-${config.type || 'component'}-icon`,
57
- size: config.iconSize
58
- })
59
- if (config.position === 'end') {
60
- element.appendChild(iconElement)
61
- } else {
62
- element.insertBefore(iconElement, element.firstChild)
63
- }
64
- } else if (iconElement && html) {
65
- iconElement.innerHTML = html
66
- }
67
- return this
68
- },
69
-
70
- getIcon () {
71
- return iconElement ? iconElement.innerHTML : ''
72
- },
73
-
74
- getElement () {
75
- return iconElement
76
- }
77
- }
78
- }
@@ -1,159 +0,0 @@
1
- // src/core/build/ripple.js
2
-
3
- import { RIPPLE_CONFIG } from './constants'
4
-
5
- const DEFAULT_CONFIG = RIPPLE_CONFIG
6
-
7
- /**
8
- * Creates a ripple effect instance
9
- * @param {Object} [config] - Ripple configuration
10
- * @param {number} [config.duration] - Animation duration in ms
11
- * @param {string} [config.timing] - Animation timing function
12
- * @param {string[]} [config.opacity] - Start and end opacity values
13
- * @returns {Object} Ripple controller instance
14
- */
15
- export const createRipple = (config = {}) => {
16
- // Make sure we fully merge the config options
17
- const options = {
18
- ...DEFAULT_CONFIG,
19
- ...config,
20
- // Handle nested objects like opacity array
21
- opacity: config.opacity || DEFAULT_CONFIG.opacity
22
- }
23
-
24
- const getEndCoordinates = (bounds) => {
25
- const size = Math.max(bounds.width, bounds.height)
26
- const top = bounds.height > bounds.width
27
- ? -bounds.height / 2
28
- : -(bounds.width - bounds.height / 2)
29
-
30
- return {
31
- size: `${size * 2}px`,
32
- top: `${top}px`,
33
- left: `${size / -2}px`
34
- }
35
- }
36
-
37
- const createRippleElement = () => {
38
- const ripple = document.createElement('div')
39
- ripple.className = 'ripple'
40
- // Initial styles already set in CSS
41
- ripple.style.transition = `all ${options.duration}ms ${options.timing}`
42
- return ripple
43
- }
44
-
45
- // Store document event listeners for cleanup
46
- let documentListeners = []
47
-
48
- // Safe document event handling
49
- const addDocumentListener = (event, handler) => {
50
- if (typeof document.addEventListener === 'function') {
51
- document.addEventListener(event, handler)
52
- documentListeners.push({ event, handler })
53
- }
54
- }
55
-
56
- const removeDocumentListener = (event, handler) => {
57
- if (typeof document.removeEventListener === 'function') {
58
- document.removeEventListener(event, handler)
59
- documentListeners = documentListeners.filter(
60
- listener => !(listener.event === event && listener.handler === handler)
61
- )
62
- }
63
- }
64
-
65
- const animate = (event, container) => {
66
- if (!container) return
67
-
68
- const bounds = container.getBoundingClientRect()
69
- const ripple = createRippleElement()
70
-
71
- // Set initial position and state
72
- Object.assign(ripple.style, {
73
- left: `${event.offsetX || bounds.width / 2}px`,
74
- top: `${event.offsetY || bounds.height / 2}px`,
75
- transform: 'scale(0)',
76
- opacity: options.opacity[0]
77
- })
78
-
79
- container.appendChild(ripple)
80
-
81
- // Force reflow
82
- // eslint-disable-next-line no-unused-expressions
83
- ripple.offsetHeight
84
-
85
- // Animate to end position
86
- const end = getEndCoordinates(bounds)
87
- Object.assign(ripple.style, {
88
- ...end,
89
- transform: 'scale(1)',
90
- opacity: options.opacity[1]
91
- })
92
-
93
- const cleanup = () => {
94
- ripple.style.opacity = '0'
95
-
96
- // Use setTimeout to remove element after animation
97
- setTimeout(() => {
98
- if (ripple.parentNode) {
99
- ripple.parentNode.removeChild(ripple)
100
- }
101
- }, options.duration)
102
-
103
- removeDocumentListener('mouseup', cleanup)
104
- removeDocumentListener('mouseleave', cleanup)
105
- }
106
-
107
- addDocumentListener('mouseup', cleanup)
108
- addDocumentListener('mouseleave', cleanup)
109
- }
110
-
111
- return {
112
- mount: (element) => {
113
- if (!element) return
114
-
115
- // Ensure proper positioning context
116
- const currentPosition = window.getComputedStyle(element).position
117
- if (currentPosition === 'static') {
118
- element.style.position = 'relative'
119
- }
120
- element.style.overflow = 'hidden'
121
-
122
- // Store the mousedown handler to be able to remove it later
123
- const mousedownHandler = (e) => animate(e, element)
124
-
125
- // Store handler reference on the element
126
- if (!element.__rippleHandlers) {
127
- element.__rippleHandlers = []
128
- }
129
- element.__rippleHandlers.push(mousedownHandler)
130
-
131
- element.addEventListener('mousedown', mousedownHandler)
132
- },
133
-
134
- unmount: (element) => {
135
- if (!element) return
136
-
137
- // Clear document event listeners
138
- documentListeners.forEach(({ event, handler }) => {
139
- removeDocumentListener(event, handler)
140
- })
141
- documentListeners = []
142
-
143
- // Remove event listeners
144
- if (element.__rippleHandlers) {
145
- element.__rippleHandlers.forEach(handler => {
146
- element.removeEventListener('mousedown', handler)
147
- })
148
- element.__rippleHandlers = []
149
- }
150
-
151
- // Remove all ripple elements
152
- const ripples = element.querySelectorAll('.ripple')
153
- ripples.forEach(ripple => {
154
- // Call remove directly to match the test expectation
155
- ripple.remove()
156
- })
157
- }
158
- }
159
- }
@@ -1,54 +0,0 @@
1
- // src/core/build/text.js
2
- /**
3
- * @module core/build
4
- */
5
-
6
- /**
7
- * Creates a text manager for a component
8
- * @memberof module:core/build
9
- * @function createText
10
- * @param {HTMLElement} element - Parent element
11
- * @param {Object} [config] - Text configuration
12
- * @param {string} [config.prefix='mtrl'] - Class prefix
13
- * @param {string} [config.type='component'] - Component type
14
- * @param {HTMLElement} [config.beforeElement] - Element to insert before
15
- * @returns {Object} Text manager interface
16
- * @property {Function} setText - Sets text content
17
- * @property {Function} getText - Gets current text
18
- * @property {Function} getElement - Gets text element
19
- */
20
- export const createText = (element, config = {}) => {
21
- let textElement = null
22
- const PREFIX = config.prefix || 'mtrl'
23
-
24
- const createElement = (content) => {
25
- const span = document.createElement('span')
26
- span.className = `${PREFIX}-${config.type || 'component'}-text`
27
- span.textContent = content
28
- return span
29
- }
30
-
31
- return {
32
- setText (text) {
33
- if (!textElement && text) {
34
- textElement = createElement(text)
35
- if (config.beforeElement) {
36
- element.insertBefore(textElement, config.beforeElement)
37
- } else {
38
- element.appendChild(textElement)
39
- }
40
- } else if (textElement) {
41
- textElement.textContent = text
42
- }
43
- return this
44
- },
45
-
46
- getText () {
47
- return textElement ? textElement.textContent : ''
48
- },
49
-
50
- getElement () {
51
- return textElement
52
- }
53
- }
54
- }
@@ -1,8 +0,0 @@
1
- // src/core/compose/base.js
2
- export const createComponent = (config = {}) => ({
3
- element: null,
4
- config,
5
- setup () {
6
- return this
7
- }
8
- })