mtrl 0.2.2 → 0.2.3

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 (92) hide show
  1. package/.typedocignore +11 -0
  2. package/DOCS.md +153 -0
  3. package/index.ts +18 -3
  4. package/package.json +7 -2
  5. package/src/components/badge/_styles.scss +174 -0
  6. package/src/components/badge/api.ts +292 -0
  7. package/src/components/badge/badge.ts +52 -0
  8. package/src/components/badge/config.ts +68 -0
  9. package/src/components/badge/constants.ts +30 -0
  10. package/src/components/badge/features.ts +185 -0
  11. package/src/components/badge/index.ts +4 -0
  12. package/src/components/badge/types.ts +105 -0
  13. package/src/components/button/types.ts +174 -29
  14. package/src/components/carousel/_styles.scss +645 -0
  15. package/src/components/carousel/api.ts +147 -0
  16. package/src/components/carousel/carousel.ts +178 -0
  17. package/src/components/carousel/config.ts +91 -0
  18. package/src/components/carousel/constants.ts +95 -0
  19. package/src/components/carousel/features/drag.ts +388 -0
  20. package/src/components/carousel/features/index.ts +8 -0
  21. package/src/components/carousel/features/slides.ts +682 -0
  22. package/src/components/carousel/index.ts +38 -0
  23. package/src/components/carousel/types.ts +327 -0
  24. package/src/components/dialog/_styles.scss +213 -0
  25. package/src/components/dialog/api.ts +283 -0
  26. package/src/components/dialog/config.ts +113 -0
  27. package/src/components/dialog/constants.ts +32 -0
  28. package/src/components/dialog/dialog.ts +56 -0
  29. package/src/components/dialog/features.ts +713 -0
  30. package/src/components/dialog/index.ts +15 -0
  31. package/src/components/dialog/types.ts +221 -0
  32. package/src/components/progress/_styles.scss +13 -1
  33. package/src/components/progress/api.ts +2 -2
  34. package/src/components/progress/progress.ts +2 -2
  35. package/src/components/progress/types.ts +3 -0
  36. package/src/components/radios/_styles.scss +232 -0
  37. package/src/components/radios/api.ts +100 -0
  38. package/src/components/radios/config.ts +60 -0
  39. package/src/components/radios/constants.ts +28 -0
  40. package/src/components/radios/index.ts +4 -0
  41. package/src/components/radios/radio.ts +269 -0
  42. package/src/components/radios/radios.ts +42 -0
  43. package/src/components/radios/types.ts +232 -0
  44. package/src/components/sheet/_styles.scss +236 -0
  45. package/src/components/sheet/api.ts +96 -0
  46. package/src/components/sheet/config.ts +66 -0
  47. package/src/components/sheet/constants.ts +20 -0
  48. package/src/components/sheet/features/content.ts +51 -0
  49. package/src/components/sheet/features/gestures.ts +177 -0
  50. package/src/components/sheet/features/index.ts +6 -0
  51. package/src/components/sheet/features/position.ts +42 -0
  52. package/src/components/sheet/features/state.ts +116 -0
  53. package/src/components/sheet/features/title.ts +86 -0
  54. package/src/components/sheet/index.ts +4 -0
  55. package/src/components/sheet/sheet.ts +57 -0
  56. package/src/components/sheet/types.ts +266 -0
  57. package/src/components/slider/_styles.scss +518 -0
  58. package/src/components/slider/api.ts +336 -0
  59. package/src/components/slider/config.ts +145 -0
  60. package/src/components/slider/constants.ts +28 -0
  61. package/src/components/slider/features/appearance.ts +140 -0
  62. package/src/components/slider/features/disabled.ts +43 -0
  63. package/src/components/slider/features/events.ts +164 -0
  64. package/src/components/slider/features/index.ts +5 -0
  65. package/src/components/slider/features/interactions.ts +256 -0
  66. package/src/components/slider/features/keyboard.ts +114 -0
  67. package/src/components/slider/features/slider.ts +336 -0
  68. package/src/components/slider/features/structure.ts +264 -0
  69. package/src/components/slider/features/ui.ts +518 -0
  70. package/src/components/slider/index.ts +9 -0
  71. package/src/components/slider/slider.ts +58 -0
  72. package/src/components/slider/types.ts +166 -0
  73. package/src/components/tabs/_styles.scss +224 -0
  74. package/src/components/tabs/api.ts +443 -0
  75. package/src/components/tabs/config.ts +80 -0
  76. package/src/components/tabs/constants.ts +12 -0
  77. package/src/components/tabs/index.ts +4 -0
  78. package/src/components/tabs/tabs.ts +52 -0
  79. package/src/components/tabs/types.ts +247 -0
  80. package/src/components/textfield/_styles.scss +97 -4
  81. package/src/components/tooltip/_styles.scss +241 -0
  82. package/src/components/tooltip/api.ts +411 -0
  83. package/src/components/tooltip/config.ts +78 -0
  84. package/src/components/tooltip/constants.ts +27 -0
  85. package/src/components/tooltip/index.ts +4 -0
  86. package/src/components/tooltip/tooltip.ts +60 -0
  87. package/src/components/tooltip/types.ts +178 -0
  88. package/src/index.ts +9 -1
  89. package/src/styles/abstract/_variables.scss +24 -12
  90. package/tsconfig.json +22 -0
  91. package/typedoc.json +28 -0
  92. package/typedoc.simple.json +14 -0
@@ -0,0 +1,147 @@
1
+ // src/components/carousel/api.ts
2
+ import { CarouselComponent, CarouselSlide } from './types';
3
+
4
+ interface ApiOptions {
5
+ slides: {
6
+ addSlide: (slide: CarouselSlide, index?: number) => any;
7
+ removeSlide: (index: number) => any;
8
+ updateSlide: (index: number, slide: CarouselSlide) => any;
9
+ getCount: () => number;
10
+ getElements: () => HTMLElement[];
11
+ };
12
+ lifecycle: {
13
+ destroy: () => void;
14
+ };
15
+ }
16
+
17
+ interface ComponentWithElements {
18
+ element: HTMLElement;
19
+ getClass: (name: string) => string;
20
+ getCurrentSlide: () => number;
21
+ goTo: (index: number) => any;
22
+ next: () => any;
23
+ prev: () => any;
24
+ enableLoop: () => any;
25
+ disableLoop: () => any;
26
+ setBorderRadius?: (radius: number) => any;
27
+ setGap?: (gap: number) => any;
28
+ }
29
+
30
+ /**
31
+ * Enhances a carousel component with API methods
32
+ * @param {ApiOptions} options - API configuration options
33
+ * @returns {Function} Higher-order function that adds API methods to component
34
+ * @internal This is an internal utility for the Carousel component
35
+ */
36
+ export const withAPI = (options: ApiOptions) =>
37
+ (component: ComponentWithElements): CarouselComponent => {
38
+ // Create the API component
39
+ const apiComponent: CarouselComponent = {
40
+ element: component.element,
41
+
42
+ slides: {
43
+ addSlide: options.slides.addSlide,
44
+ removeSlide: options.slides.removeSlide,
45
+ updateSlide: options.slides.updateSlide,
46
+ getSlide: (index: number): CarouselSlide | null => {
47
+ if (component['slideData'] && index >= 0 && index < component['slideData'].length) {
48
+ return component['slideData'][index];
49
+ }
50
+ return null;
51
+ },
52
+ getCount: options.slides.getCount,
53
+ getElements: options.slides.getElements
54
+ },
55
+
56
+ lifecycle: {
57
+ destroy: options.lifecycle.destroy
58
+ },
59
+
60
+ getClass: component.getClass,
61
+
62
+ next() {
63
+ component.next();
64
+ return this;
65
+ },
66
+
67
+ prev() {
68
+ component.prev();
69
+ return this;
70
+ },
71
+
72
+ goTo(index: number) {
73
+ component.goTo(index);
74
+ return this;
75
+ },
76
+
77
+ getCurrentSlide: component.getCurrentSlide,
78
+
79
+ addSlide(slide: CarouselSlide, index?: number) {
80
+ options.slides.addSlide(slide, index);
81
+ return this;
82
+ },
83
+
84
+ removeSlide(index: number) {
85
+ options.slides.removeSlide(index);
86
+ return this;
87
+ },
88
+
89
+ enableLoop() {
90
+ component.enableLoop();
91
+ return this;
92
+ },
93
+
94
+ disableLoop() {
95
+ component.disableLoop();
96
+ return this;
97
+ },
98
+
99
+ setBorderRadius(radius: number) {
100
+ if (component.setBorderRadius) {
101
+ component.setBorderRadius(radius);
102
+ }
103
+ return this;
104
+ },
105
+
106
+ setGap(gap: number) {
107
+ if (component.setGap) {
108
+ component.setGap(gap);
109
+ }
110
+ return this;
111
+ },
112
+
113
+ destroy() {
114
+ options.lifecycle.destroy();
115
+ },
116
+
117
+ // Add event handling and class methods from component
118
+ on(event: string, handler: Function) {
119
+ if (typeof (component as any).on === 'function') {
120
+ (component as any).on(event, handler);
121
+ } else if (component.element.addEventListener) {
122
+ component.element.addEventListener(event, handler as EventListener);
123
+ }
124
+ return this;
125
+ },
126
+
127
+ off(event: string, handler: Function) {
128
+ if (typeof (component as any).off === 'function') {
129
+ (component as any).off(event, handler);
130
+ } else if (component.element.removeEventListener) {
131
+ component.element.removeEventListener(event, handler as EventListener);
132
+ }
133
+ return this;
134
+ },
135
+
136
+ addClass(...classes: string[]) {
137
+ if (typeof (component as any).addClass === 'function') {
138
+ (component as any).addClass(...classes);
139
+ } else {
140
+ classes.forEach(cls => component.element.classList.add(cls));
141
+ }
142
+ return this;
143
+ }
144
+ };
145
+
146
+ return apiComponent;
147
+ };
@@ -0,0 +1,178 @@
1
+ // src/components/carousel/factory.ts
2
+ /**
3
+ * Carousel Factory - Creates different types of carousel layouts based on Material Design 3 guidelines
4
+ *
5
+ * This factory implements four carousel layout types:
6
+ * - Multi-browse: For browsing many visual items at once (photos, event feeds)
7
+ * - Uncontained: For highly customized or text-heavy carousels (traditional behavior)
8
+ * - Hero: For spotlighting very large visual items (featured content)
9
+ * - Full-screen: For immersive vertical-scrolling experiences
10
+ *
11
+ * @module CarouselFactory
12
+ */
13
+
14
+ import { pipe } from '../../core/compose';
15
+ import { createBase, withElement } from '../../core/compose/component';
16
+ import { withEvents, withLifecycle } from '../../core/compose/features';
17
+ import { withSlides, withDrag } from './features';
18
+ import { withAPI } from './api';
19
+ import {
20
+ CarouselConfig,
21
+ CarouselComponent,
22
+ CarouselLayout,
23
+ CarouselScrollBehavior
24
+ } from './types';
25
+ import { createBaseConfig, getElementConfig } from './config';
26
+ import { CAROUSEL_DEFAULTS } from './constants';
27
+
28
+ /**
29
+ * Creates a new carousel with specified layout and scroll behavior
30
+ *
31
+ * @param {CarouselConfig} config - Carousel configuration
32
+ * @returns {CarouselComponent} The configured carousel component
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * // Create a multi-browse carousel with snap scrolling
37
+ * const carousel = createCarousel({
38
+ * layout: 'multi-browse',
39
+ * scrollBehavior: 'snap',
40
+ * slides: [
41
+ * { image: 'image1.jpg', title: 'Recent highlights', accent: '#3C4043' },
42
+ * { image: 'image2.jpg', title: 'La Familia', accent: '#7E5260' }
43
+ * ],
44
+ * showAllLink: true
45
+ * });
46
+ *
47
+ * // Add the carousel to the DOM
48
+ * document.getElementById('container').appendChild(carousel.element);
49
+ * ```
50
+ */
51
+ export const createCarousel = (config: CarouselConfig = {}): CarouselComponent => {
52
+ // Ensure layout and scrollBehavior have defaults
53
+ config.layout = config.layout || 'multi-browse';
54
+ config.scrollBehavior = config.scrollBehavior || getDefaultScrollBehavior(config.layout);
55
+
56
+ const baseConfig = createBaseConfig(config);
57
+
58
+ try {
59
+ // Create a safer composition order to avoid circular dependencies
60
+ // First build the core functionality
61
+ const coreComponent = pipe(
62
+ createBase,
63
+ withEvents(),
64
+ withElement(getElementConfig(baseConfig))
65
+ )(baseConfig);
66
+
67
+ // Define the enhanced component early to avoid circular references
68
+ const enhancedComponent = { ...coreComponent };
69
+
70
+ // Apply layout-specific adjustments
71
+ applyLayoutConfig(enhancedComponent, config);
72
+
73
+ // Then add the features that depend on the core
74
+ const slidesComponent = withSlides(baseConfig)(enhancedComponent);
75
+
76
+ // Add drag navigation
77
+ const withDragComponent = withDrag(baseConfig)(slidesComponent);
78
+ const withLifecycleComponent = withLifecycle()(withDragComponent);
79
+
80
+ // Create a simplified API config
81
+ const apiConfig = {
82
+ slides: {
83
+ addSlide: withLifecycleComponent.slides.addSlide,
84
+ removeSlide: withLifecycleComponent.slides.removeSlide,
85
+ updateSlide: withLifecycleComponent.slides.updateSlide,
86
+ getCount: withLifecycleComponent.slides.getCount,
87
+ getElements: withLifecycleComponent.slides.getElements
88
+ },
89
+ lifecycle: {
90
+ destroy: withLifecycleComponent.lifecycle.destroy
91
+ }
92
+ };
93
+
94
+ // Add the API
95
+ const carousel = withAPI(apiConfig)(withLifecycleComponent);
96
+
97
+ // Add layout data attribute for CSS targeting
98
+ carousel.element.dataset.layout = config.layout;
99
+ carousel.element.dataset.scrollBehavior = config.scrollBehavior;
100
+
101
+ return carousel;
102
+ } catch (error) {
103
+ console.error('Carousel creation error:', error);
104
+ throw new Error(`Failed to create carousel: ${(error as Error).message}`);
105
+ }
106
+ };
107
+
108
+ /**
109
+ * Get default scroll behavior based on layout type
110
+ *
111
+ * @param {CarouselLayout} layout - Carousel layout type
112
+ * @returns {CarouselScrollBehavior} Recommended scroll behavior
113
+ */
114
+ function getDefaultScrollBehavior(layout: CarouselLayout): CarouselScrollBehavior {
115
+ switch (layout) {
116
+ case 'multi-browse':
117
+ case 'hero':
118
+ case 'full-screen':
119
+ return 'snap';
120
+ case 'uncontained':
121
+ return 'default';
122
+ default:
123
+ return 'default';
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Apply layout-specific configurations to the component
129
+ *
130
+ * @param {any} component - The component to configure
131
+ * @param {CarouselConfig} config - Carousel configuration
132
+ */
133
+ function applyLayoutConfig(component: any, config: CarouselConfig): void {
134
+ // Add layout-specific class
135
+ component.element.classList.add(`${component.getClass('carousel')}-layout--${config.layout}`);
136
+
137
+ // Apply additional layout-specific styling
138
+ switch (config.layout) {
139
+ case 'multi-browse':
140
+ // Configure for browsing many items with different sizes
141
+ component.element.dataset.enableParallax = 'true';
142
+ break;
143
+
144
+ case 'uncontained':
145
+ // Configure for same-sized items that flow past edge
146
+ component.element.style.overflow = 'visible';
147
+ break;
148
+
149
+ case 'hero':
150
+ // Configure for spotlight content with preview of next item
151
+ component.element.dataset.largeItemFocus = 'true';
152
+
153
+ // Apply center alignment if specified
154
+ if (config.centered) {
155
+ component.element.dataset.centered = 'true';
156
+ }
157
+ break;
158
+
159
+ case 'full-screen':
160
+ // Configure for immersive experience
161
+ component.element.style.width = '100%';
162
+ component.element.style.height = '100%';
163
+ component.element.style.maxWidth = '100vw';
164
+ component.element.style.maxHeight = '100vh';
165
+ component.element.dataset.verticalScroll = 'true';
166
+
167
+ // Force snap scrolling for full-screen layout
168
+ config.scrollBehavior = 'snap';
169
+ break;
170
+ }
171
+
172
+ // Apply scroll behavior
173
+ if (config.scrollBehavior === 'snap') {
174
+ component.element.dataset.snapScroll = 'true';
175
+ }
176
+ }
177
+
178
+ export default createCarousel;
@@ -0,0 +1,91 @@
1
+ // src/components/carousel/config.ts
2
+ import {
3
+ createComponentConfig,
4
+ createElementConfig,
5
+ BaseComponentConfig
6
+ } from '../../core/config/component-config';
7
+ import { CarouselConfig } from './types';
8
+ import { CAROUSEL_DEFAULTS, CAROUSEL_TRANSITIONS } from './constants';
9
+
10
+ /**
11
+ * Default configuration for the Carousel component
12
+ */
13
+ export const defaultConfig: CarouselConfig = {
14
+ initialSlide: CAROUSEL_DEFAULTS.INITIAL_SLIDE,
15
+ loop: CAROUSEL_DEFAULTS.LOOP,
16
+ transition: CAROUSEL_TRANSITIONS.SLIDE as 'slide' | 'fade' | 'none',
17
+ transitionDuration: CAROUSEL_DEFAULTS.TRANSITION_DURATION,
18
+ borderRadius: CAROUSEL_DEFAULTS.BORDER_RADIUS,
19
+ gap: CAROUSEL_DEFAULTS.GAP,
20
+ prefix: 'carousel',
21
+ showAllLink: true // Show "Show all" button by default
22
+ };
23
+
24
+ /**
25
+ * Creates the base configuration for Carousel component
26
+ * @param {CarouselConfig} config - User provided configuration
27
+ * @returns {CarouselConfig} Complete configuration with defaults applied
28
+ */
29
+ export const createBaseConfig = (config: CarouselConfig = {}): CarouselConfig =>
30
+ createComponentConfig(defaultConfig, config, 'carousel') as CarouselConfig;
31
+
32
+ /**
33
+ * Generates element configuration for the Carousel component
34
+ * @param {CarouselConfig} config - Carousel configuration
35
+ * @returns {Object} Element configuration object for withElement
36
+ */
37
+ export const getElementConfig = (config: CarouselConfig) => {
38
+ // Create the attributes object
39
+ const attrs: Record<string, any> = {
40
+ role: 'region',
41
+ 'aria-roledescription': 'carousel',
42
+ 'aria-live': 'polite'
43
+ };
44
+
45
+ // Create data attributes for configuration
46
+ const dataAttrs = {
47
+ 'data-transition': config.transition,
48
+ 'data-loop': config.loop ? 'true' : 'false'
49
+ };
50
+
51
+ return createElementConfig(config, {
52
+ tag: 'div',
53
+ attrs: { ...attrs, ...dataAttrs },
54
+ className: config.class,
55
+ forwardEvents: {
56
+ keydown: true,
57
+ focus: true,
58
+ blur: true
59
+ },
60
+ style: {
61
+ position: 'relative',
62
+ overflow: 'hidden',
63
+ borderRadius: `${config.borderRadius}px`,
64
+ width: '100%',
65
+ height: 'auto',
66
+ display: 'flex',
67
+ flexDirection: 'column'
68
+ }
69
+ });
70
+ };
71
+
72
+ /**
73
+ * Creates API configuration for the Carousel component
74
+ * @param {Object} comp - Component with slides and lifecycle features
75
+ * @returns {Object} API configuration object
76
+ */
77
+ export const getApiConfig = (comp) => ({
78
+ // Empty navigation API for compatibility
79
+ slides: {
80
+ addSlide: comp.slides.addSlide,
81
+ removeSlide: comp.slides.removeSlide,
82
+ updateSlide: comp.slides.updateSlide,
83
+ getCount: comp.slides.getCount,
84
+ getElements: comp.slides.getElements
85
+ },
86
+ lifecycle: {
87
+ destroy: comp.lifecycle.destroy
88
+ }
89
+ });
90
+
91
+ export default defaultConfig;
@@ -0,0 +1,95 @@
1
+ // src/components/carousel/constants.ts
2
+
3
+ /**
4
+ * Carousel layout types as defined by Material Design 3
5
+ */
6
+ export const CAROUSEL_LAYOUTS = {
7
+ /** Best for browsing many visual items at once (photos, event feeds) */
8
+ MULTI_BROWSE: 'multi-browse',
9
+
10
+ /** For highly customized or text-heavy carousels (traditional behavior) */
11
+ UNCONTAINED: 'uncontained',
12
+
13
+ /** For spotlighting very large visual items (featured content) */
14
+ HERO: 'hero',
15
+
16
+ /** For immersive vertical-scrolling experiences */
17
+ FULL_SCREEN: 'full-screen'
18
+ } as const;
19
+
20
+ /**
21
+ * Carousel scroll behaviors
22
+ */
23
+ export const CAROUSEL_SCROLL_BEHAVIORS = {
24
+ /** Standard scrolling without snapping */
25
+ DEFAULT: 'default',
26
+
27
+ /** Items snap to carousel layout */
28
+ SNAP: 'snap'
29
+ } as const;
30
+
31
+ /**
32
+ * Carousel item sizes
33
+ */
34
+ export const CAROUSEL_ITEM_SIZES = {
35
+ LARGE: 'large',
36
+ MEDIUM: 'medium',
37
+ SMALL: 'small'
38
+ } as const;
39
+
40
+ /**
41
+ * Transition effects for carousel slides
42
+ */
43
+ export const CAROUSEL_TRANSITIONS = {
44
+ SLIDE: 'slide',
45
+ FADE: 'fade',
46
+ NONE: 'none'
47
+ } as const;
48
+
49
+ /**
50
+ * Event names for the carousel component
51
+ */
52
+ export const CAROUSEL_EVENTS = {
53
+ SLIDE_CHANGE: 'slide-change',
54
+ SLIDE_CHANGED: 'slide-changed',
55
+ RESIZE: 'resize'
56
+ } as const;
57
+
58
+ /**
59
+ * Default values for carousel configuration
60
+ */
61
+ export const CAROUSEL_DEFAULTS = {
62
+ INITIAL_SLIDE: 0,
63
+ LOOP: true,
64
+ TRANSITION: CAROUSEL_TRANSITIONS.SLIDE,
65
+ TRANSITION_DURATION: 300,
66
+ BORDER_RADIUS: 16,
67
+ GAP: 8,
68
+ LAYOUT: CAROUSEL_LAYOUTS.MULTI_BROWSE,
69
+ SCROLL_BEHAVIOR: CAROUSEL_SCROLL_BEHAVIORS.SNAP,
70
+ SMALL_ITEM_WIDTH: 48, // 40-56dp range as per MD3
71
+
72
+ // Item widths for different layouts in px
73
+ ITEM_WIDTHS: {
74
+ [CAROUSEL_LAYOUTS.MULTI_BROWSE]: {
75
+ LARGE: 240,
76
+ MEDIUM: 180,
77
+ SMALL: 48
78
+ },
79
+ [CAROUSEL_LAYOUTS.UNCONTAINED]: {
80
+ LARGE: 240,
81
+ MEDIUM: 240,
82
+ SMALL: 240 // All same size in uncontained
83
+ },
84
+ [CAROUSEL_LAYOUTS.HERO]: {
85
+ LARGE: 300,
86
+ MEDIUM: 240,
87
+ SMALL: 48
88
+ },
89
+ [CAROUSEL_LAYOUTS.FULL_SCREEN]: {
90
+ LARGE: '100%', // Full width
91
+ MEDIUM: '100%',
92
+ SMALL: '100%'
93
+ }
94
+ }
95
+ } as const;