mtrl 0.2.2 → 0.2.4
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.
- package/.typedocignore +11 -0
- package/DOCS.md +153 -0
- package/index.ts +18 -3
- package/package.json +7 -2
- package/src/components/badge/_styles.scss +174 -0
- package/src/components/badge/api.ts +292 -0
- package/src/components/badge/badge.ts +52 -0
- package/src/components/badge/config.ts +68 -0
- package/src/components/badge/constants.ts +30 -0
- package/src/components/badge/features.ts +185 -0
- package/src/components/badge/index.ts +4 -0
- package/src/components/badge/types.ts +105 -0
- package/src/components/button/types.ts +174 -29
- package/src/components/carousel/_styles.scss +645 -0
- package/src/components/carousel/api.ts +147 -0
- package/src/components/carousel/carousel.ts +178 -0
- package/src/components/carousel/config.ts +91 -0
- package/src/components/carousel/constants.ts +95 -0
- package/src/components/carousel/features/drag.ts +388 -0
- package/src/components/carousel/features/index.ts +8 -0
- package/src/components/carousel/features/slides.ts +682 -0
- package/src/components/carousel/index.ts +38 -0
- package/src/components/carousel/types.ts +327 -0
- package/src/components/dialog/_styles.scss +213 -0
- package/src/components/dialog/api.ts +283 -0
- package/src/components/dialog/config.ts +113 -0
- package/src/components/dialog/constants.ts +32 -0
- package/src/components/dialog/dialog.ts +56 -0
- package/src/components/dialog/features.ts +713 -0
- package/src/components/dialog/index.ts +15 -0
- package/src/components/dialog/types.ts +221 -0
- package/src/components/progress/_styles.scss +13 -1
- package/src/components/progress/api.ts +2 -2
- package/src/components/progress/progress.ts +2 -2
- package/src/components/progress/types.ts +3 -0
- package/src/components/radios/_styles.scss +232 -0
- package/src/components/radios/api.ts +100 -0
- package/src/components/radios/config.ts +60 -0
- package/src/components/radios/constants.ts +28 -0
- package/src/components/radios/index.ts +4 -0
- package/src/components/radios/radio.ts +269 -0
- package/src/components/radios/radios.ts +42 -0
- package/src/components/radios/types.ts +232 -0
- package/src/components/sheet/_styles.scss +236 -0
- package/src/components/sheet/api.ts +96 -0
- package/src/components/sheet/config.ts +66 -0
- package/src/components/sheet/constants.ts +20 -0
- package/src/components/sheet/features/content.ts +51 -0
- package/src/components/sheet/features/gestures.ts +177 -0
- package/src/components/sheet/features/index.ts +6 -0
- package/src/components/sheet/features/position.ts +42 -0
- package/src/components/sheet/features/state.ts +116 -0
- package/src/components/sheet/features/title.ts +86 -0
- package/src/components/sheet/index.ts +4 -0
- package/src/components/sheet/sheet.ts +57 -0
- package/src/components/sheet/types.ts +266 -0
- package/src/components/slider/_styles.scss +518 -0
- package/src/components/slider/api.ts +336 -0
- package/src/components/slider/config.ts +145 -0
- package/src/components/slider/constants.ts +28 -0
- package/src/components/slider/features/appearance.ts +140 -0
- package/src/components/slider/features/disabled.ts +43 -0
- package/src/components/slider/features/events.ts +164 -0
- package/src/components/slider/features/index.ts +5 -0
- package/src/components/slider/features/interactions.ts +256 -0
- package/src/components/slider/features/keyboard.ts +114 -0
- package/src/components/slider/features/slider.ts +336 -0
- package/src/components/slider/features/structure.ts +264 -0
- package/src/components/slider/features/ui.ts +518 -0
- package/src/components/slider/index.ts +9 -0
- package/src/components/slider/slider.ts +58 -0
- package/src/components/slider/types.ts +166 -0
- package/src/components/tabs/_styles.scss +224 -0
- package/src/components/tabs/api.ts +443 -0
- package/src/components/tabs/config.ts +80 -0
- package/src/components/tabs/constants.ts +12 -0
- package/src/components/tabs/index.ts +4 -0
- package/src/components/tabs/tabs.ts +52 -0
- package/src/components/tabs/types.ts +247 -0
- package/src/components/textfield/_styles.scss +97 -4
- package/src/components/tooltip/_styles.scss +241 -0
- package/src/components/tooltip/api.ts +411 -0
- package/src/components/tooltip/config.ts +78 -0
- package/src/components/tooltip/constants.ts +27 -0
- package/src/components/tooltip/index.ts +4 -0
- package/src/components/tooltip/tooltip.ts +60 -0
- package/src/components/tooltip/types.ts +178 -0
- package/src/core/build/_ripple.scss +79 -0
- package/src/core/build/constants.ts +48 -0
- package/src/core/build/icon.ts +137 -0
- package/src/core/build/ripple.ts +216 -0
- package/src/core/build/text.ts +91 -0
- package/src/index.ts +9 -1
- package/src/styles/abstract/_variables.scss +24 -12
- package/tsconfig.json +22 -0
- package/typedoc.json +28 -0
- package/typedoc.simple.json +14 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
// src/components/sheet/_styles.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}-sheet';
|
|
9
|
+
|
|
10
|
+
.#{$component} {
|
|
11
|
+
// Base styles
|
|
12
|
+
position: fixed;
|
|
13
|
+
z-index: 1000;
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
background-color: t.color('surface');
|
|
17
|
+
transition: transform 0.3s ease-in-out, opacity 0.3s ease-in-out;
|
|
18
|
+
overflow: hidden;
|
|
19
|
+
|
|
20
|
+
// Common elevated surface styling
|
|
21
|
+
border-radius: 12px 12px 0 0;
|
|
22
|
+
box-sizing: border-box;
|
|
23
|
+
max-width: 100%;
|
|
24
|
+
max-height: 100%;
|
|
25
|
+
|
|
26
|
+
// Initially hidden
|
|
27
|
+
opacity: 0;
|
|
28
|
+
pointer-events: none;
|
|
29
|
+
|
|
30
|
+
// Typography for content
|
|
31
|
+
@include m.typography('body-medium');
|
|
32
|
+
|
|
33
|
+
// Scrim (background overlay)
|
|
34
|
+
&-scrim {
|
|
35
|
+
position: fixed;
|
|
36
|
+
top: 0;
|
|
37
|
+
left: 0;
|
|
38
|
+
right: 0;
|
|
39
|
+
bottom: 0;
|
|
40
|
+
background-color: t.alpha('scrim', 0.32);
|
|
41
|
+
z-index: 999;
|
|
42
|
+
opacity: 0;
|
|
43
|
+
transition: opacity 0.3s ease-in-out;
|
|
44
|
+
pointer-events: none;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
&--open {
|
|
48
|
+
opacity: 1;
|
|
49
|
+
pointer-events: auto;
|
|
50
|
+
|
|
51
|
+
+ .#{$component}-scrim {
|
|
52
|
+
opacity: 1;
|
|
53
|
+
pointer-events: auto;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Drag handle
|
|
58
|
+
&-handle {
|
|
59
|
+
width: 32px;
|
|
60
|
+
height: 4px;
|
|
61
|
+
border-radius: 2px;
|
|
62
|
+
background-color: t.color('outline-variant');
|
|
63
|
+
margin: 8px auto;
|
|
64
|
+
cursor: grab;
|
|
65
|
+
|
|
66
|
+
&:active {
|
|
67
|
+
cursor: grabbing;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Title area
|
|
72
|
+
&-title {
|
|
73
|
+
padding: 16px 24px 0;
|
|
74
|
+
@include m.typography('headline-small');
|
|
75
|
+
color: t.color('on-surface');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Content container
|
|
79
|
+
&-content {
|
|
80
|
+
padding: 16px 24px 24px;
|
|
81
|
+
overflow-y: auto;
|
|
82
|
+
flex: 1;
|
|
83
|
+
// Ensure a min-height for small content
|
|
84
|
+
min-height: 32px;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Position variants
|
|
88
|
+
&--bottom {
|
|
89
|
+
bottom: 0;
|
|
90
|
+
left: 0;
|
|
91
|
+
right: 0;
|
|
92
|
+
transform: translateY(100%);
|
|
93
|
+
border-radius: 28px 28px 0 0;
|
|
94
|
+
|
|
95
|
+
&.#{$component}--open {
|
|
96
|
+
transform: translateY(0);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
&--top {
|
|
101
|
+
top: 0;
|
|
102
|
+
left: 0;
|
|
103
|
+
right: 0;
|
|
104
|
+
transform: translateY(-100%);
|
|
105
|
+
border-radius: 0 0 28px 28px;
|
|
106
|
+
|
|
107
|
+
&.#{$component}--open {
|
|
108
|
+
transform: translateY(0);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.#{$component}-handle {
|
|
112
|
+
margin: 0 auto 8px;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
&--left {
|
|
117
|
+
top: 0;
|
|
118
|
+
bottom: 0;
|
|
119
|
+
left: 0;
|
|
120
|
+
transform: translateX(-100%);
|
|
121
|
+
border-radius: 0 28px 28px 0;
|
|
122
|
+
|
|
123
|
+
&.#{$component}--open {
|
|
124
|
+
transform: translateX(0);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.#{$component}-handle {
|
|
128
|
+
width: 4px;
|
|
129
|
+
height: 32px;
|
|
130
|
+
margin: auto 8px auto auto;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
&--right {
|
|
135
|
+
top: 0;
|
|
136
|
+
bottom: 0;
|
|
137
|
+
right: 0;
|
|
138
|
+
transform: translateX(100%);
|
|
139
|
+
border-radius: 28px 0 0 28px;
|
|
140
|
+
|
|
141
|
+
&.#{$component}--open {
|
|
142
|
+
transform: translateX(0);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.#{$component}-handle {
|
|
146
|
+
width: 4px;
|
|
147
|
+
height: 32px;
|
|
148
|
+
margin: auto auto auto 8px;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Variant styles
|
|
153
|
+
&--standard {
|
|
154
|
+
// Apply different elevation based on position
|
|
155
|
+
&.#{$component}--bottom,
|
|
156
|
+
&.#{$component}--top {
|
|
157
|
+
width: 100%;
|
|
158
|
+
max-width: 640px;
|
|
159
|
+
margin: 0 auto;
|
|
160
|
+
@include m.elevation(3);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
&.#{$component}--left,
|
|
164
|
+
&.#{$component}--right {
|
|
165
|
+
max-width: 360px;
|
|
166
|
+
width: 90%;
|
|
167
|
+
@include m.elevation(3);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
&--modal {
|
|
172
|
+
// Modal variant has higher elevation and a required scrim
|
|
173
|
+
@include m.elevation(5);
|
|
174
|
+
|
|
175
|
+
&.#{$component}--bottom,
|
|
176
|
+
&.#{$component}--top {
|
|
177
|
+
width: 100%;
|
|
178
|
+
max-width: 560px;
|
|
179
|
+
margin: 0 auto;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
&.#{$component}--left,
|
|
183
|
+
&.#{$component}--right {
|
|
184
|
+
max-width: 320px;
|
|
185
|
+
width: 90%;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
+ .#{$component}-scrim {
|
|
189
|
+
background-color: t.alpha('scrim', 0.5);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
&--expanded {
|
|
194
|
+
// Full screen variant
|
|
195
|
+
&.#{$component}--bottom,
|
|
196
|
+
&.#{$component}--top {
|
|
197
|
+
height: 100%;
|
|
198
|
+
max-height: calc(100% - 24px);
|
|
199
|
+
width: 100%;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
&.#{$component}--left,
|
|
203
|
+
&.#{$component}--right {
|
|
204
|
+
width: 100%;
|
|
205
|
+
max-width: 100%;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// States
|
|
210
|
+
&--dismissible {
|
|
211
|
+
.#{$component}-scrim {
|
|
212
|
+
cursor: pointer;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Elevation levels (1-5)
|
|
217
|
+
&--elevation-1 {
|
|
218
|
+
@include m.elevation(1);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
&--elevation-2 {
|
|
222
|
+
@include m.elevation(2);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
&--elevation-3 {
|
|
226
|
+
@include m.elevation(3);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
&--elevation-4 {
|
|
230
|
+
@include m.elevation(4);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
&--elevation-5 {
|
|
234
|
+
@include m.elevation(5);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// src/components/sheet/api.ts
|
|
2
|
+
import { SheetComponent } from './types';
|
|
3
|
+
|
|
4
|
+
interface ApiOptions {
|
|
5
|
+
state: {
|
|
6
|
+
open: () => void;
|
|
7
|
+
close: () => void;
|
|
8
|
+
};
|
|
9
|
+
lifecycle: {
|
|
10
|
+
destroy: () => void;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface ComponentWithElements {
|
|
15
|
+
element: HTMLElement;
|
|
16
|
+
container: HTMLElement;
|
|
17
|
+
content: {
|
|
18
|
+
setContent: (html: string) => any;
|
|
19
|
+
getContent: () => string;
|
|
20
|
+
getElement: () => HTMLElement | null;
|
|
21
|
+
};
|
|
22
|
+
title: {
|
|
23
|
+
setTitle: (text: string) => any;
|
|
24
|
+
getTitle: () => string;
|
|
25
|
+
getElement: () => HTMLElement | null;
|
|
26
|
+
};
|
|
27
|
+
getClass: (name: string) => string;
|
|
28
|
+
dragHandle?: {
|
|
29
|
+
setVisible: (visible: boolean) => any;
|
|
30
|
+
};
|
|
31
|
+
initialize?: () => void;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Enhances a sheet component with API methods
|
|
36
|
+
* @param {ApiOptions} options - API configuration options
|
|
37
|
+
* @returns {Function} Higher-order function that adds API methods to component
|
|
38
|
+
* @internal This is an internal utility for the Sheet component
|
|
39
|
+
*/
|
|
40
|
+
export const withAPI = ({ state, lifecycle }: ApiOptions) =>
|
|
41
|
+
(component: ComponentWithElements): SheetComponent => ({
|
|
42
|
+
...component as any,
|
|
43
|
+
element: component.element,
|
|
44
|
+
container: component.container,
|
|
45
|
+
|
|
46
|
+
open() {
|
|
47
|
+
state.open();
|
|
48
|
+
return this;
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
close() {
|
|
52
|
+
state.close();
|
|
53
|
+
return this;
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
setContent(html: string) {
|
|
57
|
+
component.content.setContent(html);
|
|
58
|
+
return this;
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
getContent() {
|
|
62
|
+
return component.content.getContent();
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
setTitle(text: string) {
|
|
66
|
+
component.title.setTitle(text);
|
|
67
|
+
return this;
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
getTitle() {
|
|
71
|
+
return component.title.getTitle();
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
setDragHandle(enabled: boolean) {
|
|
75
|
+
if (component.dragHandle) {
|
|
76
|
+
component.dragHandle.setVisible(enabled);
|
|
77
|
+
}
|
|
78
|
+
return this;
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
setMaxHeight(height: string) {
|
|
82
|
+
component.container.style.maxHeight = height;
|
|
83
|
+
return this;
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
destroy() {
|
|
87
|
+
lifecycle.destroy();
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
initialize() {
|
|
91
|
+
if (component.initialize) {
|
|
92
|
+
component.initialize();
|
|
93
|
+
}
|
|
94
|
+
return this;
|
|
95
|
+
}
|
|
96
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// src/components/sheet/config.ts
|
|
2
|
+
import {
|
|
3
|
+
createComponentConfig,
|
|
4
|
+
createElementConfig,
|
|
5
|
+
BaseComponentConfig
|
|
6
|
+
} from '../../core/config/component-config';
|
|
7
|
+
import { SheetConfig } from './types';
|
|
8
|
+
import { SHEET_VARIANTS, SHEET_POSITIONS } from './constants';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Default configuration for the Sheet component
|
|
12
|
+
*/
|
|
13
|
+
export const defaultConfig: SheetConfig = {
|
|
14
|
+
variant: SHEET_VARIANTS.STANDARD,
|
|
15
|
+
position: SHEET_POSITIONS.BOTTOM,
|
|
16
|
+
open: false,
|
|
17
|
+
dismissible: true,
|
|
18
|
+
dragHandle: true,
|
|
19
|
+
elevation: 3,
|
|
20
|
+
enableGestures: true
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Creates the base configuration for Sheet component
|
|
25
|
+
* @param {SheetConfig} config - User provided configuration
|
|
26
|
+
* @returns {SheetConfig} Complete configuration with defaults applied
|
|
27
|
+
*/
|
|
28
|
+
export const createBaseConfig = (config: SheetConfig = {}): SheetConfig =>
|
|
29
|
+
createComponentConfig(defaultConfig, config, 'sheet') as SheetConfig;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Generates element configuration for the Sheet component
|
|
33
|
+
* @param {SheetConfig} config - Sheet configuration
|
|
34
|
+
* @returns {Object} Element configuration object for withElement
|
|
35
|
+
*/
|
|
36
|
+
export const getElementConfig = (config: SheetConfig) => {
|
|
37
|
+
return createElementConfig(config, {
|
|
38
|
+
tag: 'div',
|
|
39
|
+
attrs: {
|
|
40
|
+
role: 'dialog',
|
|
41
|
+
'aria-modal': config.variant === SHEET_VARIANTS.MODAL ? 'true' : 'false'
|
|
42
|
+
},
|
|
43
|
+
className: config.class,
|
|
44
|
+
forwardEvents: {
|
|
45
|
+
click: true,
|
|
46
|
+
keydown: true
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Creates API configuration for the Sheet component
|
|
53
|
+
* @param {Object} comp - Component with state and lifecycle features
|
|
54
|
+
* @returns {Object} API configuration object
|
|
55
|
+
*/
|
|
56
|
+
export const getApiConfig = (comp) => ({
|
|
57
|
+
state: {
|
|
58
|
+
open: () => comp.state.open(),
|
|
59
|
+
close: () => comp.state.close()
|
|
60
|
+
},
|
|
61
|
+
lifecycle: {
|
|
62
|
+
destroy: () => comp.lifecycle.destroy()
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
export default defaultConfig;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// src/components/sheet/constants.ts
|
|
2
|
+
export const SHEET_VARIANTS = {
|
|
3
|
+
STANDARD: 'standard',
|
|
4
|
+
MODAL: 'modal',
|
|
5
|
+
EXPANDED: 'expanded'
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const SHEET_POSITIONS = {
|
|
9
|
+
BOTTOM: 'bottom',
|
|
10
|
+
TOP: 'top',
|
|
11
|
+
LEFT: 'left',
|
|
12
|
+
RIGHT: 'right'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const SHEET_EVENTS = {
|
|
16
|
+
OPEN: 'open',
|
|
17
|
+
CLOSE: 'close',
|
|
18
|
+
DRAG_START: 'dragstart',
|
|
19
|
+
DRAG_END: 'dragend'
|
|
20
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// src/components/sheet/features/content.ts
|
|
2
|
+
/**
|
|
3
|
+
* Adds content management functionality to a component
|
|
4
|
+
* @param {Object} config - Component configuration with optional content
|
|
5
|
+
* @returns {Function} Higher-order function that adds content to a component
|
|
6
|
+
*/
|
|
7
|
+
export const withContent = (config) => (component) => {
|
|
8
|
+
const { content = '' } = config;
|
|
9
|
+
|
|
10
|
+
// Create content element
|
|
11
|
+
const contentElement = document.createElement('div');
|
|
12
|
+
contentElement.className = `${component.getClass('sheet')}-content`;
|
|
13
|
+
contentElement.innerHTML = content;
|
|
14
|
+
|
|
15
|
+
// Add content element to component
|
|
16
|
+
component.container = document.createElement('div');
|
|
17
|
+
component.container.className = `${component.getClass('sheet')}-container`;
|
|
18
|
+
component.container.appendChild(contentElement);
|
|
19
|
+
component.element.appendChild(component.container);
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
...component,
|
|
23
|
+
content: {
|
|
24
|
+
/**
|
|
25
|
+
* Sets the HTML content
|
|
26
|
+
* @param {string} html - HTML content
|
|
27
|
+
* @returns {Object} Content API for chaining
|
|
28
|
+
*/
|
|
29
|
+
setContent(html: string) {
|
|
30
|
+
contentElement.innerHTML = html;
|
|
31
|
+
return this;
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Gets the current HTML content
|
|
36
|
+
* @returns {string} HTML content
|
|
37
|
+
*/
|
|
38
|
+
getContent() {
|
|
39
|
+
return contentElement.innerHTML;
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Gets the content DOM element
|
|
44
|
+
* @returns {HTMLElement} Content element
|
|
45
|
+
*/
|
|
46
|
+
getElement() {
|
|
47
|
+
return contentElement;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
};
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// src/components/sheet/features/gestures.ts
|
|
2
|
+
import { SHEET_EVENTS, SHEET_POSITIONS } from '../constants';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Adds gesture support to a component
|
|
6
|
+
* @param {Object} config - Component configuration
|
|
7
|
+
* @returns {Function} Higher-order function that adds gestures to a component
|
|
8
|
+
*/
|
|
9
|
+
export const withGestures = (config) => (component) => {
|
|
10
|
+
// Skip if gestures are disabled
|
|
11
|
+
if (config.enableGestures === false) {
|
|
12
|
+
return component;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const position = config.position || SHEET_POSITIONS.BOTTOM;
|
|
16
|
+
let startY = 0;
|
|
17
|
+
let startX = 0;
|
|
18
|
+
let startTransform = 0;
|
|
19
|
+
let isDragging = false;
|
|
20
|
+
|
|
21
|
+
// Find drag handle if exists
|
|
22
|
+
const dragHandle = component.dragHandle?.element || component.element;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Handles the start of a drag gesture
|
|
26
|
+
* @param {TouchEvent|MouseEvent} event - The event object
|
|
27
|
+
*/
|
|
28
|
+
const handleDragStart = (event) => {
|
|
29
|
+
if (!component.state.isOpen()) return;
|
|
30
|
+
|
|
31
|
+
isDragging = true;
|
|
32
|
+
document.body.style.userSelect = 'none';
|
|
33
|
+
|
|
34
|
+
// Get start position
|
|
35
|
+
if (event.type === 'touchstart') {
|
|
36
|
+
startY = event.touches[0].clientY;
|
|
37
|
+
startX = event.touches[0].clientX;
|
|
38
|
+
} else {
|
|
39
|
+
startY = event.clientY;
|
|
40
|
+
startX = event.clientX;
|
|
41
|
+
|
|
42
|
+
// Add mouse move and up listeners
|
|
43
|
+
document.addEventListener('mousemove', handleDragMove);
|
|
44
|
+
document.addEventListener('mouseup', handleDragEnd);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Emit event
|
|
48
|
+
component.events.emit(SHEET_EVENTS.DRAG_START);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Handles the drag movement
|
|
53
|
+
* @param {TouchEvent|MouseEvent} event - The event object
|
|
54
|
+
*/
|
|
55
|
+
const handleDragMove = (event) => {
|
|
56
|
+
if (!isDragging) return;
|
|
57
|
+
|
|
58
|
+
let currentY, currentX;
|
|
59
|
+
|
|
60
|
+
if (event.type === 'touchmove') {
|
|
61
|
+
currentY = event.touches[0].clientY;
|
|
62
|
+
currentX = event.touches[0].clientX;
|
|
63
|
+
} else {
|
|
64
|
+
currentY = event.clientY;
|
|
65
|
+
currentX = event.clientX;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Calculate delta based on position
|
|
69
|
+
let delta = 0;
|
|
70
|
+
|
|
71
|
+
switch (position) {
|
|
72
|
+
case SHEET_POSITIONS.BOTTOM:
|
|
73
|
+
delta = currentY - startY;
|
|
74
|
+
if (delta < 0) delta = 0; // Prevent dragging beyond fully open state
|
|
75
|
+
component.element.style.transform = `translateY(${delta}px)`;
|
|
76
|
+
break;
|
|
77
|
+
|
|
78
|
+
case SHEET_POSITIONS.TOP:
|
|
79
|
+
delta = startY - currentY;
|
|
80
|
+
if (delta < 0) delta = 0;
|
|
81
|
+
component.element.style.transform = `translateY(-${delta}px)`;
|
|
82
|
+
break;
|
|
83
|
+
|
|
84
|
+
case SHEET_POSITIONS.LEFT:
|
|
85
|
+
delta = startX - currentX;
|
|
86
|
+
if (delta < 0) delta = 0;
|
|
87
|
+
component.element.style.transform = `translateX(-${delta}px)`;
|
|
88
|
+
break;
|
|
89
|
+
|
|
90
|
+
case SHEET_POSITIONS.RIGHT:
|
|
91
|
+
delta = currentX - startX;
|
|
92
|
+
if (delta < 0) delta = 0;
|
|
93
|
+
component.element.style.transform = `translateX(${delta}px)`;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Adjust opacity based on drag progress
|
|
98
|
+
const elementSize = position === SHEET_POSITIONS.BOTTOM || position === SHEET_POSITIONS.TOP
|
|
99
|
+
? component.element.offsetHeight
|
|
100
|
+
: component.element.offsetWidth;
|
|
101
|
+
|
|
102
|
+
const dragProgress = Math.min(delta / elementSize, 1);
|
|
103
|
+
const scrimElement = component.element.nextElementSibling;
|
|
104
|
+
if (scrimElement && scrimElement.classList.contains(`${component.getClass('sheet')}-scrim`)) {
|
|
105
|
+
scrimElement.style.opacity = `${0.32 * (1 - dragProgress)}`;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Handles the end of a drag gesture
|
|
111
|
+
* @param {TouchEvent|MouseEvent} event - The event object
|
|
112
|
+
*/
|
|
113
|
+
const handleDragEnd = (event) => {
|
|
114
|
+
if (!isDragging) return;
|
|
115
|
+
|
|
116
|
+
isDragging = false;
|
|
117
|
+
document.body.style.userSelect = '';
|
|
118
|
+
|
|
119
|
+
// Remove mouse event listeners
|
|
120
|
+
document.removeEventListener('mousemove', handleDragMove);
|
|
121
|
+
document.removeEventListener('mouseup', handleDragEnd);
|
|
122
|
+
|
|
123
|
+
// Determine final position
|
|
124
|
+
const elementSize = position === SHEET_POSITIONS.BOTTOM || position === SHEET_POSITIONS.TOP
|
|
125
|
+
? component.element.offsetHeight
|
|
126
|
+
: component.element.offsetWidth;
|
|
127
|
+
|
|
128
|
+
let transform = 0;
|
|
129
|
+
if (component.element.style.transform) {
|
|
130
|
+
const match = component.element.style.transform.match(/translate[XY]\(([^p]+)px\)/);
|
|
131
|
+
transform = match ? parseFloat(match[1]) : 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Close if dragged more than 30% of the way
|
|
135
|
+
if (transform > elementSize * 0.3) {
|
|
136
|
+
component.state.close();
|
|
137
|
+
} else {
|
|
138
|
+
// Reset position and opacity
|
|
139
|
+
component.element.style.transform = '';
|
|
140
|
+
const scrimElement = component.element.nextElementSibling;
|
|
141
|
+
if (scrimElement && scrimElement.classList.contains(`${component.getClass('sheet')}-scrim`)) {
|
|
142
|
+
scrimElement.style.opacity = '';
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Emit event
|
|
147
|
+
component.events.emit(SHEET_EVENTS.DRAG_END);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// Add event listeners to drag handle
|
|
151
|
+
dragHandle.addEventListener('touchstart', handleDragStart);
|
|
152
|
+
dragHandle.addEventListener('touchmove', handleDragMove);
|
|
153
|
+
dragHandle.addEventListener('touchend', handleDragEnd);
|
|
154
|
+
dragHandle.addEventListener('mousedown', handleDragStart);
|
|
155
|
+
|
|
156
|
+
// Clean up function
|
|
157
|
+
const cleanup = () => {
|
|
158
|
+
dragHandle.removeEventListener('touchstart', handleDragStart);
|
|
159
|
+
dragHandle.removeEventListener('touchmove', handleDragMove);
|
|
160
|
+
dragHandle.removeEventListener('touchend', handleDragEnd);
|
|
161
|
+
dragHandle.removeEventListener('mousedown', handleDragStart);
|
|
162
|
+
document.removeEventListener('mousemove', handleDragMove);
|
|
163
|
+
document.removeEventListener('mouseup', handleDragEnd);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// Add cleanup to component lifecycle
|
|
167
|
+
const originalDestroy = component.lifecycle?.destroy || (() => {});
|
|
168
|
+
component.lifecycle = {
|
|
169
|
+
...component.lifecycle,
|
|
170
|
+
destroy: () => {
|
|
171
|
+
cleanup();
|
|
172
|
+
originalDestroy();
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
return component;
|
|
177
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// src/components/sheet/features/position.ts
|
|
2
|
+
import { SheetConfig } from '../types';
|
|
3
|
+
import { SHEET_POSITIONS } from '../constants';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Adds position functionality to a component
|
|
7
|
+
* @param {SheetConfig} config - Component configuration with position
|
|
8
|
+
* @returns {Function} Higher-order function that adds position to a component
|
|
9
|
+
*/
|
|
10
|
+
export const withPosition = (config: SheetConfig) => (component) => {
|
|
11
|
+
const { position = SHEET_POSITIONS.BOTTOM } = config;
|
|
12
|
+
const positionClass = `${component.getClass('sheet')}--${position.toLowerCase()}`;
|
|
13
|
+
|
|
14
|
+
// Add position class to element
|
|
15
|
+
component.element.classList.add(positionClass);
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
...component,
|
|
19
|
+
position: {
|
|
20
|
+
/**
|
|
21
|
+
* Changes the position of the component
|
|
22
|
+
* @param {string} newPosition - New position value
|
|
23
|
+
*/
|
|
24
|
+
setPosition(newPosition: string) {
|
|
25
|
+
// Remove current position class
|
|
26
|
+
component.element.classList.remove(positionClass);
|
|
27
|
+
|
|
28
|
+
// Add new position class
|
|
29
|
+
const newPositionClass = `${component.getClass('sheet')}--${newPosition.toLowerCase()}`;
|
|
30
|
+
component.element.classList.add(newPositionClass);
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Gets the current position
|
|
35
|
+
* @returns {string} Current position
|
|
36
|
+
*/
|
|
37
|
+
getPosition() {
|
|
38
|
+
return position;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
};
|