@getcortexlabs/mavis-web 0.1.0-alpha.2 → 0.1.0-alpha.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.
package/README.md CHANGED
@@ -1,11 +1,11 @@
1
1
  # Mavis for Vue Web
2
2
 
3
- Vue Web implementation of the eleven Mavis components, version `0.1.0-alpha.2`. Experimental prerelease for testing in real apps; the API can change between alpha versions. Licensed under MIT.
3
+ Vue Web implementation of the twelve Mavis components, version `0.1.0-alpha.3`. Experimental prerelease for testing in real apps; the API can change between alpha versions. Licensed under MIT.
4
4
 
5
5
  In an existing Vue application:
6
6
 
7
7
  ```sh
8
- npm install @getcortexlabs/mavis-web@0.1.0-alpha.2
8
+ npm install @getcortexlabs/mavis-web@0.1.0-alpha.3
9
9
  ```
10
10
 
11
11
  ```ts
@@ -17,7 +17,7 @@ import App from './App.vue'
17
17
  createApp(App).use(createMavis()).mount('#app')
18
18
  ```
19
19
 
20
- The stylesheet supplies focus indicators, box overlays, and motion. The plugin registers Screen, Row, Column, Box, Card, Text, Icon, Button, Input, Slider and Reveal; Vue also accepts their `m-*` spellings.
20
+ The stylesheet supplies focus indicators, box overlays, and motion. The plugin registers Screen, Row, Column, Box, Card, Text, Icon, Button, Input, Slider, Sheet and Reveal; Vue also accepts their `m-*` spellings.
21
21
 
22
22
  Themes and Vue context come from `@getcortexlabs/mavis-core`. NativeScript and Jolt are not dependencies of this package. Browser motion currently uses CSS; [Jolt #236](https://github.com/rafaelaugustos/jolt/issues/236) tracks its Web backend.
23
23
 
@@ -1,5 +1,9 @@
1
1
  export declare const MScreen: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
2
2
  scroll: BooleanConstructor;
3
+ dismissKeyboard: {
4
+ type: BooleanConstructor;
5
+ default: boolean;
6
+ };
3
7
  id: {
4
8
  type: StringConstructor;
5
9
  default: undefined;
@@ -16,6 +20,10 @@ export declare const MScreen: import("vue").DefineComponent<import("vue").Extrac
16
20
  [key: string]: any;
17
21
  }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
18
22
  scroll: BooleanConstructor;
23
+ dismissKeyboard: {
24
+ type: BooleanConstructor;
25
+ default: boolean;
26
+ };
19
27
  id: {
20
28
  type: StringConstructor;
21
29
  default: undefined;
@@ -33,5 +41,6 @@ export declare const MScreen: import("vue").DefineComponent<import("vue").Extrac
33
41
  accessibilityLabel: string;
34
42
  accessibilityHidden: boolean;
35
43
  scroll: boolean;
44
+ dismissKeyboard: boolean;
36
45
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
37
46
  //# sourceMappingURL=MScreen.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MScreen.d.ts","sourceRoot":"","sources":["../../src/components/MScreen.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4EAkClB,CAAA"}
1
+ {"version":3,"file":"MScreen.d.ts","sourceRoot":"","sources":["../../src/components/MScreen.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4EAgDlB,CAAA"}
@@ -10,10 +10,27 @@ export const MScreen = defineComponent({
10
10
  const { theme } = useMavisTheme();
11
11
  const element = useScreenViewport(() => props.scroll);
12
12
  provide(layoutDirection, 'column');
13
+ // Browsers already move focus away on a tap outside the editor; a drag keeps the keyboard.
14
+ const releaseKeyboard = (event) => {
15
+ if (!props.dismissKeyboard || !props.scroll)
16
+ return;
17
+ const screen = element.value;
18
+ const active = document.activeElement;
19
+ if (!(active instanceof HTMLElement) || !screen || active === screen)
20
+ return;
21
+ if (!screen.contains(active) || active.contains(event.target))
22
+ return;
23
+ const editor = active instanceof HTMLInputElement ||
24
+ active instanceof HTMLTextAreaElement ||
25
+ active.isContentEditable;
26
+ if (editor)
27
+ active.blur();
28
+ };
13
29
  return () => h('main', mergeProps({
14
30
  ref: element,
15
31
  class: 'm-screen',
16
32
  tabindex: props.scroll ? 0 : -1,
33
+ onTouchmovePassive: releaseKeyboard,
17
34
  style: {
18
35
  display: 'flex',
19
36
  flexDirection: 'column',
@@ -1 +1 @@
1
- {"version":3,"file":"MScreen.js","sourceRoot":"","sources":["../../src/components/MScreen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AAC7D,OAAO,EACL,WAAW,EACX,aAAa,EACb,eAAe,EACf,SAAS,GACV,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAEzD,MAAM,CAAC,MAAM,OAAO,GAAG,eAAe,CAAC;IACrC,IAAI,EAAE,SAAS;IACf,YAAY,EAAE,KAAK;IACnB,KAAK,EAAE,WAAW;IAClB,KAAK,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;QAC3B,MAAM,EAAE,KAAK,EAAE,GAAG,aAAa,EAAE,CAAA;QACjC,MAAM,OAAO,GAAG,iBAAiB,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QACrD,OAAO,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAA;QAClC,OAAO,GAAG,EAAE,CACV,CAAC,CACC,MAAM,EACN,UAAU,CACR;YACE,GAAG,EAAE,OAAO;YACZ,KAAK,EAAE,UAAU;YACjB,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/B,KAAK,EAAE;gBACL,OAAO,EAAE,MAAM;gBACf,aAAa,EAAE,QAAQ;gBACvB,SAAS,EAAE,YAAY;gBACvB,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,kCAAkC,CAAC,CAAC,CAAC,QAAQ;gBACvE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,kCAAkC,CAAC,CAAC,CAAC,SAAS;gBACrE,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;gBAC5C,eAAe,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU;gBAC9C,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI;gBAC9B,WAAW,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO;gBACvC,WAAW,EAAE,KAAK,CAAC,KAAK,CAAC,UAAU;aACpC;SACF,EACD,QAAQ,CAAC,EAAE,GAAG,KAAK,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAC5C,EACD,KAAK,CAAC,OAAO,EAAE,EAAE,CAClB,CAAA;IACL,CAAC;CACF,CAAC,CAAA"}
1
+ {"version":3,"file":"MScreen.js","sourceRoot":"","sources":["../../src/components/MScreen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AAC7D,OAAO,EACL,WAAW,EACX,aAAa,EACb,eAAe,EACf,SAAS,GACV,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAEzD,MAAM,CAAC,MAAM,OAAO,GAAG,eAAe,CAAC;IACrC,IAAI,EAAE,SAAS;IACf,YAAY,EAAE,KAAK;IACnB,KAAK,EAAE,WAAW;IAClB,KAAK,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;QAC3B,MAAM,EAAE,KAAK,EAAE,GAAG,aAAa,EAAE,CAAA;QACjC,MAAM,OAAO,GAAG,iBAAiB,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QACrD,OAAO,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAA;QAClC,2FAA2F;QAC3F,MAAM,eAAe,GAAG,CAAC,KAAiB,EAAE,EAAE;YAC5C,IAAI,CAAC,KAAK,CAAC,eAAe,IAAI,CAAC,KAAK,CAAC,MAAM;gBAAE,OAAM;YACnD,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAA;YAC5B,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAA;YACrC,IAAI,CAAC,CAAC,MAAM,YAAY,WAAW,CAAC,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,MAAM;gBAAE,OAAM;YAC5E,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAc,CAAC;gBAAE,OAAM;YAC7E,MAAM,MAAM,GACV,MAAM,YAAY,gBAAgB;gBAClC,MAAM,YAAY,mBAAmB;gBACrC,MAAM,CAAC,iBAAiB,CAAA;YAC1B,IAAI,MAAM;gBAAE,MAAM,CAAC,IAAI,EAAE,CAAA;QAC3B,CAAC,CAAA;QACD,OAAO,GAAG,EAAE,CACV,CAAC,CACC,MAAM,EACN,UAAU,CACR;YACE,GAAG,EAAE,OAAO;YACZ,KAAK,EAAE,UAAU;YACjB,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/B,kBAAkB,EAAE,eAAe;YACnC,KAAK,EAAE;gBACL,OAAO,EAAE,MAAM;gBACf,aAAa,EAAE,QAAQ;gBACvB,SAAS,EAAE,YAAY;gBACvB,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,kCAAkC,CAAC,CAAC,CAAC,QAAQ;gBACvE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,kCAAkC,CAAC,CAAC,CAAC,SAAS;gBACrE,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;gBAC5C,eAAe,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU;gBAC9C,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI;gBAC9B,WAAW,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO;gBACvC,WAAW,EAAE,KAAK,CAAC,KAAK,CAAC,UAAU;aACpC;SACF,EACD,QAAQ,CAAC,EAAE,GAAG,KAAK,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAC5C,EACD,KAAK,CAAC,OAAO,EAAE,EAAE,CAClB,CAAA;IACL,CAAC;CACF,CAAC,CAAA"}
@@ -0,0 +1,96 @@
1
+ import { type SheetCloseReason } from '@getcortexlabs/mavis-core';
2
+ export declare const MSheet: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
3
+ id: {
4
+ type: StringConstructor;
5
+ default: undefined;
6
+ };
7
+ accessibilityLabel: {
8
+ type: StringConstructor;
9
+ default: undefined;
10
+ };
11
+ open: BooleanConstructor;
12
+ title: {
13
+ type: StringConstructor;
14
+ default: undefined;
15
+ };
16
+ dismissible: {
17
+ type: BooleanConstructor;
18
+ default: boolean;
19
+ };
20
+ fullscreen: BooleanConstructor;
21
+ closeLabel: {
22
+ type: StringConstructor;
23
+ default: string;
24
+ };
25
+ padding: {
26
+ default: string;
27
+ type: import("vue").PropType<import("@getcortexlabs/mavis-core").Spacing>;
28
+ };
29
+ gap: {
30
+ type: import("vue").PropType<import("@getcortexlabs/mavis-core").Spacing>;
31
+ default: undefined;
32
+ };
33
+ align: {
34
+ type: import("vue").PropType<import("@getcortexlabs/mavis-core/vue").Align>;
35
+ default: import("@getcortexlabs/mavis-core/vue").Align;
36
+ validator: (value: import("@getcortexlabs/mavis-core/vue").Align) => boolean;
37
+ };
38
+ }>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
39
+ [key: string]: any;
40
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
41
+ 'update:open': (value: boolean) => boolean;
42
+ close: (reason: SheetCloseReason) => boolean;
43
+ opened: () => boolean;
44
+ }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
45
+ id: {
46
+ type: StringConstructor;
47
+ default: undefined;
48
+ };
49
+ accessibilityLabel: {
50
+ type: StringConstructor;
51
+ default: undefined;
52
+ };
53
+ open: BooleanConstructor;
54
+ title: {
55
+ type: StringConstructor;
56
+ default: undefined;
57
+ };
58
+ dismissible: {
59
+ type: BooleanConstructor;
60
+ default: boolean;
61
+ };
62
+ fullscreen: BooleanConstructor;
63
+ closeLabel: {
64
+ type: StringConstructor;
65
+ default: string;
66
+ };
67
+ padding: {
68
+ default: string;
69
+ type: import("vue").PropType<import("@getcortexlabs/mavis-core").Spacing>;
70
+ };
71
+ gap: {
72
+ type: import("vue").PropType<import("@getcortexlabs/mavis-core").Spacing>;
73
+ default: undefined;
74
+ };
75
+ align: {
76
+ type: import("vue").PropType<import("@getcortexlabs/mavis-core/vue").Align>;
77
+ default: import("@getcortexlabs/mavis-core/vue").Align;
78
+ validator: (value: import("@getcortexlabs/mavis-core/vue").Align) => boolean;
79
+ };
80
+ }>> & Readonly<{
81
+ onClose?: ((reason: SheetCloseReason) => any) | undefined;
82
+ "onUpdate:open"?: ((value: boolean) => any) | undefined;
83
+ onOpened?: (() => any) | undefined;
84
+ }>, {
85
+ padding: import("@getcortexlabs/mavis-core").Spacing;
86
+ id: string;
87
+ accessibilityLabel: string;
88
+ title: string;
89
+ gap: import("@getcortexlabs/mavis-core").Spacing;
90
+ align: import("@getcortexlabs/mavis-core/vue").Align;
91
+ fullscreen: boolean;
92
+ open: boolean;
93
+ dismissible: boolean;
94
+ closeLabel: string;
95
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
96
+ //# sourceMappingURL=MSheet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MSheet.d.ts","sourceRoot":"","sources":["../../src/components/MSheet.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAgC,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAkB/F,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4EAwOjB,CAAA"}
@@ -0,0 +1,238 @@
1
+ import { defineComponent, h, nextTick, onBeforeUnmount, onMounted, provide, ref, useId, watch, } from 'vue';
2
+ import { sheetProps, sheetEmits, useMavisTheme, layoutDirection, } from '@getcortexlabs/mavis-core/vue';
3
+ import { checkSheetName, resolveSpace } from '@getcortexlabs/mavis-core';
4
+ import { MRow, MColumn, MBox } from './layout.js';
5
+ import { MText } from './MText.js';
6
+ import { MButton } from './MButton.js';
7
+ /** The longest duration in a `transition-duration` list, in milliseconds. */
8
+ function longestDuration(value) {
9
+ return Math.max(0, ...value.split(',').map((part) => {
10
+ const trimmed = part.trim();
11
+ const number = Number.parseFloat(trimmed);
12
+ if (!Number.isFinite(number))
13
+ return 0;
14
+ return trimmed.endsWith('ms') ? number : number * 1000;
15
+ }));
16
+ }
17
+ export const MSheet = defineComponent({
18
+ name: 'MSheet',
19
+ inheritAttrs: false,
20
+ props: sheetProps,
21
+ emits: sheetEmits,
22
+ setup(props, { slots, emit }) {
23
+ const { theme } = useMavisTheme();
24
+ provide(layoutDirection, 'column');
25
+ const titleId = `m-sheet-${useId()}`;
26
+ const dialog = ref();
27
+ const presented = ref(false);
28
+ const shown = ref(false);
29
+ let closing;
30
+ let generation = 0;
31
+ let timer;
32
+ let outside = false;
33
+ let opener;
34
+ const announce = (reason) => {
35
+ closing = reason;
36
+ emit('update:open', false);
37
+ emit('close', reason);
38
+ };
39
+ const request = (reason) => {
40
+ if (props.open && !closing)
41
+ announce(reason);
42
+ };
43
+ const focusable = (element) => [
44
+ ...element.querySelectorAll('button:not(:disabled), [href], input:not(:disabled), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex="-1"])'),
45
+ ].filter((control) => !control.closest('[inert]'));
46
+ // Engines differ on which control a modal dialog focuses first; start at the first control,
47
+ // or the panel itself, unless the content asked for focus with `autofocus`.
48
+ function focusInitial(element) {
49
+ if (typeof document === 'undefined')
50
+ return;
51
+ const active = document.activeElement;
52
+ if (active && active !== element && element.contains(active))
53
+ return;
54
+ const panel = element.querySelector('.m-sheet-panel');
55
+ if (panel)
56
+ panel.tabIndex = -1;
57
+ (focusable(element)[0] ?? panel)?.focus({ preventScroll: true });
58
+ }
59
+ // A modal dialog makes the page inert, yet Tab can still leave for the browser's own controls.
60
+ function trapTab(event) {
61
+ const element = dialog.value;
62
+ if (event.key !== 'Tab' || !element)
63
+ return;
64
+ const controls = focusable(element);
65
+ const first = controls[0];
66
+ const last = controls[controls.length - 1];
67
+ if (!first || !last)
68
+ return;
69
+ const active = document.activeElement;
70
+ if (event.shiftKey && (active === first || active === element)) {
71
+ event.preventDefault();
72
+ last.focus();
73
+ }
74
+ else if (!event.shiftKey && active === last) {
75
+ event.preventDefault();
76
+ first.focus();
77
+ }
78
+ }
79
+ // The dialog restores focus when it closes; some engines leave it on the body instead.
80
+ function restoreFocus() {
81
+ const target = opener;
82
+ opener = undefined;
83
+ const active = typeof document === 'undefined' ? null : document.activeElement;
84
+ if (target?.isConnected && (!active || active === document.body))
85
+ target.focus({ preventScroll: true });
86
+ }
87
+ function present() {
88
+ const current = ++generation;
89
+ clearTimeout(timer);
90
+ presented.value = true;
91
+ if (typeof document !== 'undefined' && document.activeElement instanceof HTMLElement)
92
+ opener = document.activeElement;
93
+ nextTick(() => {
94
+ const element = dialog.value;
95
+ if (generation !== current || !element)
96
+ return;
97
+ if (typeof element.showModal === 'function' && !element.open)
98
+ element.showModal();
99
+ focusInitial(element);
100
+ // Resolve the offscreen position before the open class so the entrance transitions.
101
+ element.getBoundingClientRect?.();
102
+ shown.value = true;
103
+ });
104
+ }
105
+ function leave() {
106
+ const element = dialog.value;
107
+ const current = ++generation;
108
+ shown.value = false;
109
+ let release = () => { };
110
+ const finish = () => {
111
+ if (generation !== current)
112
+ return;
113
+ clearTimeout(timer);
114
+ release();
115
+ if (element?.open)
116
+ element.close();
117
+ presented.value = false;
118
+ closing = undefined;
119
+ restoreFocus();
120
+ };
121
+ const duration = element && typeof getComputedStyle === 'function'
122
+ ? longestDuration(getComputedStyle(element).transitionDuration)
123
+ : 0;
124
+ if (!duration || !element) {
125
+ finish();
126
+ return;
127
+ }
128
+ const ended = (event) => {
129
+ if (event.target === element)
130
+ finish();
131
+ };
132
+ element.addEventListener('transitionend', ended);
133
+ release = () => element.removeEventListener('transitionend', ended);
134
+ timer = setTimeout(finish, duration + 100);
135
+ }
136
+ watch(() => props.open, (open) => {
137
+ if (open) {
138
+ closing = undefined;
139
+ present();
140
+ }
141
+ else if (presented.value) {
142
+ if (!closing) {
143
+ closing = 'program';
144
+ emit('close', 'program');
145
+ }
146
+ leave();
147
+ }
148
+ });
149
+ onMounted(() => {
150
+ if (props.open)
151
+ present();
152
+ });
153
+ onBeforeUnmount(() => {
154
+ generation++;
155
+ clearTimeout(timer);
156
+ });
157
+ return () => {
158
+ checkSheetName(props.title, props.accessibilityLabel);
159
+ const { colors, radius, space } = theme.value;
160
+ const header = props.title || props.dismissible
161
+ ? h(MRow, { gap: 'sm', justify: 'between' }, {
162
+ default: () => [
163
+ props.title
164
+ ? h(MText, {
165
+ as: 'h2',
166
+ variant: 'heading',
167
+ grow: 1,
168
+ id: titleId,
169
+ text: props.title,
170
+ })
171
+ : h(MBox, { grow: 1 }),
172
+ props.dismissible
173
+ ? h(MButton, {
174
+ variant: 'ghost',
175
+ size: 'sm',
176
+ icon: 'x',
177
+ shrink: 0,
178
+ accessibilityLabel: props.closeLabel,
179
+ onClick: () => request('button'),
180
+ })
181
+ : null,
182
+ ],
183
+ })
184
+ : null;
185
+ return h('dialog', {
186
+ ref: dialog,
187
+ id: props.id,
188
+ class: ['m-sheet', { 'm-sheet-open': shown.value, 'm-sheet-full': props.fullscreen }],
189
+ 'aria-labelledby': props.title ? titleId : undefined,
190
+ 'aria-label': props.title ? undefined : props.accessibilityLabel,
191
+ style: {
192
+ '--m-sheet-surface': colors.surface,
193
+ '--m-sheet-radius': `${radius.lg}px`,
194
+ '--m-focus': colors.primary,
195
+ color: colors.text,
196
+ colorScheme: theme.value.appearance,
197
+ },
198
+ onCancel: (event) => {
199
+ // The browser would close at once; the sheet leaves through its own transition.
200
+ event.preventDefault();
201
+ if (props.dismissible)
202
+ request('escape');
203
+ },
204
+ onClose: () => {
205
+ // Closed by the browser itself: keep the bound state in step.
206
+ if (props.open && !closing)
207
+ announce('escape');
208
+ shown.value = false;
209
+ presented.value = false;
210
+ restoreFocus();
211
+ },
212
+ onKeydown: trapTab,
213
+ onPointerdown: (event) => {
214
+ outside = event.target === event.currentTarget;
215
+ },
216
+ onClick: (event) => {
217
+ if (outside && event.target === event.currentTarget && props.dismissible)
218
+ request('backdrop');
219
+ outside = false;
220
+ },
221
+ }, presented.value
222
+ ? [
223
+ h('div', {
224
+ class: 'm-sheet-panel',
225
+ style: {
226
+ padding: `${resolveSpace(theme.value, props.padding ?? 'lg')}px`,
227
+ gap: `${space.md}px`,
228
+ },
229
+ }, [
230
+ header,
231
+ h(MColumn, { class: 'm-sheet-body', shrink: 1, gap: props.gap, align: props.align }, { default: () => slots.default?.() }),
232
+ ]),
233
+ ]
234
+ : undefined);
235
+ };
236
+ },
237
+ });
238
+ //# sourceMappingURL=MSheet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MSheet.js","sourceRoot":"","sources":["../../src/components/MSheet.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -9,7 +9,8 @@ import { MSlider } from './components/MSlider.js';
9
9
  import { MInput } from './components/MInput.js';
10
10
  import { MIcon } from './components/MIcon.js';
11
11
  import { MReveal } from './components/MReveal.js';
12
- export { MScreen, MBox, MRow, MColumn, MCard, MText, MButton, MSlider, MInput, MIcon, MReveal };
12
+ import { MSheet } from './components/MSheet.js';
13
+ export { MScreen, MBox, MRow, MColumn, MCard, MText, MButton, MSlider, MInput, MIcon, MReveal, MSheet, };
13
14
  export { useMavisTheme } from '@getcortexlabs/mavis-core/vue';
14
15
  export type { MavisThemeContext, Appearance, AppearanceMode, AppearanceSource, } from '@getcortexlabs/mavis-core/vue';
15
16
  export type { Align, Justify } from './components/layout.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AAC9B,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,+BAA+B,CAAA;AAEtC,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACjD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AAEjD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAA;AAC/F,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AAC7D,YAAY,EACV,iBAAiB,EACjB,UAAU,EACV,cAAc,EACd,gBAAgB,GACjB,MAAM,+BAA+B,CAAA;AACtC,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAC5D,cAAc,2BAA2B,CAAA;AAEzC,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,mBAAmB,EAAE,QAAQ,CAAC,CAAA;AAE9D,6FAA6F;AAC7F,wBAAgB,WAAW,CAAC,OAAO,GAAE,YAAiB;iBAErC,GAAG;EAqBnB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AAC9B,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,+BAA+B,CAAA;AAEtC,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACjD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAE/C,OAAO,EACL,OAAO,EACP,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,KAAK,EACL,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,EACN,KAAK,EACL,OAAO,EACP,MAAM,GACP,CAAA;AACD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AAC7D,YAAY,EACV,iBAAiB,EACjB,UAAU,EACV,cAAc,EACd,gBAAgB,GACjB,MAAM,+BAA+B,CAAA;AACtC,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAC5D,cAAc,2BAA2B,CAAA;AAEzC,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,mBAAmB,EAAE,QAAQ,CAAC,CAAA;AAE9D,6FAA6F;AAC7F,wBAAgB,WAAW,CAAC,OAAO,GAAE,YAAiB;iBAErC,GAAG;EAsBnB"}
package/dist/index.js CHANGED
@@ -9,7 +9,8 @@ import { MSlider } from './components/MSlider.js';
9
9
  import { MInput } from './components/MInput.js';
10
10
  import { MIcon } from './components/MIcon.js';
11
11
  import { MReveal } from './components/MReveal.js';
12
- export { MScreen, MBox, MRow, MColumn, MCard, MText, MButton, MSlider, MInput, MIcon, MReveal };
12
+ import { MSheet } from './components/MSheet.js';
13
+ export { MScreen, MBox, MRow, MColumn, MCard, MText, MButton, MSlider, MInput, MIcon, MReveal, MSheet, };
13
14
  export { useMavisTheme } from '@getcortexlabs/mavis-core/vue';
14
15
  export * from '@getcortexlabs/mavis-core';
15
16
  /** Create one plugin per application; `system` appearance follows `prefers-color-scheme`. */
@@ -31,6 +32,7 @@ export function createMavis(options = {}) {
31
32
  MInput,
32
33
  MIcon,
33
34
  MReveal,
35
+ MSheet,
34
36
  })) {
35
37
  app.component(name, component);
36
38
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAClB,QAAQ,GAET,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACjD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AAEjD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAA;AAC/F,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AAQ7D,cAAc,2BAA2B,CAAA;AAIzC,6FAA6F;AAC7F,MAAM,UAAU,WAAW,CAAC,UAAwB,EAAE;IACpD,OAAO;QACL,OAAO,CAAC,GAAQ;YACd,MAAM,OAAO,GAAG,kBAAkB,CAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,EAAE,CAAC,CAAA;YAC9E,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;YAC9B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;YACtC,KAAK,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC;gBAC7C,OAAO;gBACP,IAAI;gBACJ,IAAI;gBACJ,OAAO;gBACP,KAAK;gBACL,KAAK;gBACL,OAAO;gBACP,OAAO;gBACP,MAAM;gBACN,KAAK;gBACL,OAAO;aACR,CAAC,EAAE,CAAC;gBACH,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;YAChC,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAClB,QAAQ,GAET,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACjD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAE/C,OAAO,EACL,OAAO,EACP,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,KAAK,EACL,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,EACN,KAAK,EACL,OAAO,EACP,MAAM,GACP,CAAA;AACD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AAQ7D,cAAc,2BAA2B,CAAA;AAIzC,6FAA6F;AAC7F,MAAM,UAAU,WAAW,CAAC,UAAwB,EAAE;IACpD,OAAO;QACL,OAAO,CAAC,GAAQ;YACd,MAAM,OAAO,GAAG,kBAAkB,CAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,EAAE,CAAC,CAAA;YAC9E,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;YAC9B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;YACtC,KAAK,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC;gBAC7C,OAAO;gBACP,IAAI;gBACJ,IAAI;gBACJ,OAAO;gBACP,KAAK;gBACL,KAAK;gBACL,OAAO;gBACP,OAAO;gBACP,MAAM;gBACN,KAAK;gBACL,OAAO;gBACP,MAAM;aACP,CAAC,EAAE,CAAC;gBACH,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;YAChC,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../src/style.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,UAAU,EAChB,MAAM,2BAA2B,CAAA;AAClC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAA;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,KAAK,CAAA;AAExC,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,sBAExD;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,SAAI,GAAG,aAAa,CAe7F;AAED,6EAA6E;AAC7E,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;EAUtD"}
1
+ {"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../src/style.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,UAAU,EAChB,MAAM,2BAA2B,CAAA;AAClC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAA;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,KAAK,CAAA;AAExC,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,sBAExD;AAGD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,SAAI,GAAG,aAAa,CAyB7F;AAED,6EAA6E;AAC7E,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;EAUtD"}
package/dist/style.js CHANGED
@@ -2,21 +2,36 @@ import { resolveSpace, resolveRadius, resolveDimension, nonNegative, } from '@ge
2
2
  export function length(value) {
3
3
  return typeof value === 'number' ? `${value}px` : value;
4
4
  }
5
+ // A prop that was not given leaves its style untouched, so the host's CSS keeps applying.
5
6
  export function boxStyle(theme, props, defaultShrink = 0) {
6
- const padding = resolveSpace(theme, props.padding ?? 'none');
7
- const x = props.paddingX === undefined ? padding : resolveSpace(theme, props.paddingX);
8
- const y = props.paddingY === undefined ? padding : resolveSpace(theme, props.paddingY);
9
- return {
7
+ const style = {
10
8
  boxSizing: 'border-box',
11
- padding: `${y}px ${x}px`,
12
- borderRadius: length(resolveRadius(theme, props.radius)),
13
9
  flexGrow: nonNegative(props.grow, 'grow'),
14
10
  flexShrink: nonNegative(props.shrink ?? defaultShrink, 'shrink'),
15
11
  minWidth: 0,
16
- width: length(resolveDimension(props.width)),
17
- height: length(resolveDimension(props.height)),
18
- backgroundColor: props.backgroundColor,
19
12
  };
13
+ const padding = props.padding === undefined ? undefined : resolveSpace(theme, props.padding);
14
+ const x = props.paddingX === undefined ? padding : resolveSpace(theme, props.paddingX);
15
+ const y = props.paddingY === undefined ? padding : resolveSpace(theme, props.paddingY);
16
+ if (x !== undefined) {
17
+ style.paddingLeft = `${x}px`;
18
+ style.paddingRight = `${x}px`;
19
+ }
20
+ if (y !== undefined) {
21
+ style.paddingTop = `${y}px`;
22
+ style.paddingBottom = `${y}px`;
23
+ }
24
+ if (props.radius !== undefined)
25
+ style.borderRadius = length(resolveRadius(theme, props.radius));
26
+ const width = length(resolveDimension(props.width));
27
+ if (width !== undefined)
28
+ style.width = width;
29
+ const height = length(resolveDimension(props.height));
30
+ if (height !== undefined)
31
+ style.height = height;
32
+ if (props.backgroundColor !== undefined)
33
+ style.backgroundColor = props.backgroundColor;
34
+ return style;
20
35
  }
21
36
  /** Native accessibility labels have the same meaning on the DOM renderer. */
22
37
  export function webAttrs(attrs) {
package/dist/style.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","sourceRoot":"","sources":["../src/style.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,WAAW,GAEZ,MAAM,2BAA2B,CAAA;AAIlC,MAAM,UAAU,MAAM,CAAC,KAAkC;IACvD,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAA;AACzD,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAiB,EAAE,KAAe,EAAE,aAAa,GAAG,CAAC;IAC5E,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,IAAI,MAAM,CAAC,CAAA;IAC5D,MAAM,CAAC,GAAG,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;IACtF,MAAM,CAAC,GAAG,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;IACtF,OAAO;QACL,SAAS,EAAE,YAAY;QACvB,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI;QACxB,YAAY,EAAE,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACxD,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC;QACzC,UAAU,EAAE,WAAW,CAAC,KAAK,CAAC,MAAM,IAAI,aAAa,EAAE,QAAQ,CAAC;QAChE,QAAQ,EAAE,CAAC;QACX,KAAK,EAAE,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5C,MAAM,EAAE,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC9C,eAAe,EAAE,KAAK,CAAC,eAAe;KACvC,CAAA;AACH,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,QAAQ,CAAC,KAA8B;IACrD,MAAM,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAA;IACtF,OAAO;QACL,GAAG,IAAI;QACP,GAAG,CAAC,kBAAkB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,kBAAkB,EAAE,CAAC;QACjF,GAAG,CAAC,kBAAkB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,CAAC;QACrF,GAAG,CAAC,mBAAmB,KAAK,SAAS;YACnC,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,aAAa,EAAE,mBAAmB,EAAE,KAAK,EAAE,mBAAmB,IAAI,SAAS,EAAE,CAAC;KACrF,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"style.js","sourceRoot":"","sources":["../src/style.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getcortexlabs/mavis-web",
3
- "version": "0.1.0-alpha.2",
3
+ "version": "0.1.0-alpha.3",
4
4
  "description": "Mavis components for Vue Web.",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -26,7 +26,7 @@
26
26
  "build": "tsc -p tsconfig.build.json"
27
27
  },
28
28
  "dependencies": {
29
- "@getcortexlabs/mavis-core": "0.1.0-alpha.2"
29
+ "@getcortexlabs/mavis-core": "0.1.0-alpha.3"
30
30
  },
31
31
  "peerDependencies": {
32
32
  "vue": "^3.5.42"
@@ -16,6 +16,19 @@ export const MScreen = defineComponent({
16
16
  const { theme } = useMavisTheme()
17
17
  const element = useScreenViewport(() => props.scroll)
18
18
  provide(layoutDirection, 'column')
19
+ // Browsers already move focus away on a tap outside the editor; a drag keeps the keyboard.
20
+ const releaseKeyboard = (event: TouchEvent) => {
21
+ if (!props.dismissKeyboard || !props.scroll) return
22
+ const screen = element.value
23
+ const active = document.activeElement
24
+ if (!(active instanceof HTMLElement) || !screen || active === screen) return
25
+ if (!screen.contains(active) || active.contains(event.target as Node)) return
26
+ const editor =
27
+ active instanceof HTMLInputElement ||
28
+ active instanceof HTMLTextAreaElement ||
29
+ active.isContentEditable
30
+ if (editor) active.blur()
31
+ }
19
32
  return () =>
20
33
  h(
21
34
  'main',
@@ -24,6 +37,7 @@ export const MScreen = defineComponent({
24
37
  ref: element,
25
38
  class: 'm-screen',
26
39
  tabindex: props.scroll ? 0 : -1,
40
+ onTouchmovePassive: releaseKeyboard,
27
41
  style: {
28
42
  display: 'flex',
29
43
  flexDirection: 'column',
@@ -0,0 +1,268 @@
1
+ import {
2
+ defineComponent,
3
+ h,
4
+ nextTick,
5
+ onBeforeUnmount,
6
+ onMounted,
7
+ provide,
8
+ ref,
9
+ useId,
10
+ watch,
11
+ } from 'vue'
12
+ import {
13
+ sheetProps,
14
+ sheetEmits,
15
+ useMavisTheme,
16
+ layoutDirection,
17
+ } from '@getcortexlabs/mavis-core/vue'
18
+ import { checkSheetName, resolveSpace, type SheetCloseReason } from '@getcortexlabs/mavis-core'
19
+ import { MRow, MColumn, MBox } from './layout.js'
20
+ import { MText } from './MText.js'
21
+ import { MButton } from './MButton.js'
22
+
23
+ /** The longest duration in a `transition-duration` list, in milliseconds. */
24
+ function longestDuration(value: string) {
25
+ return Math.max(
26
+ 0,
27
+ ...value.split(',').map((part) => {
28
+ const trimmed = part.trim()
29
+ const number = Number.parseFloat(trimmed)
30
+ if (!Number.isFinite(number)) return 0
31
+ return trimmed.endsWith('ms') ? number : number * 1000
32
+ }),
33
+ )
34
+ }
35
+
36
+ export const MSheet = defineComponent({
37
+ name: 'MSheet',
38
+ inheritAttrs: false,
39
+ props: sheetProps,
40
+ emits: sheetEmits,
41
+ setup(props, { slots, emit }) {
42
+ const { theme } = useMavisTheme()
43
+ provide(layoutDirection, 'column')
44
+ const titleId = `m-sheet-${useId()}`
45
+ const dialog = ref<HTMLDialogElement>()
46
+ const presented = ref(false)
47
+ const shown = ref(false)
48
+ let closing: SheetCloseReason | undefined
49
+ let generation = 0
50
+ let timer: ReturnType<typeof setTimeout> | undefined
51
+ let outside = false
52
+ let opener: HTMLElement | undefined
53
+
54
+ const announce = (reason: SheetCloseReason) => {
55
+ closing = reason
56
+ emit('update:open', false)
57
+ emit('close', reason)
58
+ }
59
+ const request = (reason: SheetCloseReason) => {
60
+ if (props.open && !closing) announce(reason)
61
+ }
62
+
63
+ const focusable = (element: HTMLElement) =>
64
+ [
65
+ ...element.querySelectorAll<HTMLElement>(
66
+ 'button:not(:disabled), [href], input:not(:disabled), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex="-1"])',
67
+ ),
68
+ ].filter((control) => !control.closest('[inert]'))
69
+ // Engines differ on which control a modal dialog focuses first; start at the first control,
70
+ // or the panel itself, unless the content asked for focus with `autofocus`.
71
+ function focusInitial(element: HTMLDialogElement) {
72
+ if (typeof document === 'undefined') return
73
+ const active = document.activeElement
74
+ if (active && active !== element && element.contains(active)) return
75
+ const panel = element.querySelector<HTMLElement>('.m-sheet-panel')
76
+ if (panel) panel.tabIndex = -1
77
+ ;(focusable(element)[0] ?? panel)?.focus({ preventScroll: true })
78
+ }
79
+ // A modal dialog makes the page inert, yet Tab can still leave for the browser's own controls.
80
+ function trapTab(event: KeyboardEvent) {
81
+ const element = dialog.value
82
+ if (event.key !== 'Tab' || !element) return
83
+ const controls = focusable(element)
84
+ const first = controls[0]
85
+ const last = controls[controls.length - 1]
86
+ if (!first || !last) return
87
+ const active = document.activeElement
88
+ if (event.shiftKey && (active === first || active === element)) {
89
+ event.preventDefault()
90
+ last.focus()
91
+ } else if (!event.shiftKey && active === last) {
92
+ event.preventDefault()
93
+ first.focus()
94
+ }
95
+ }
96
+ // The dialog restores focus when it closes; some engines leave it on the body instead.
97
+ function restoreFocus() {
98
+ const target = opener
99
+ opener = undefined
100
+ const active = typeof document === 'undefined' ? null : document.activeElement
101
+ if (target?.isConnected && (!active || active === document.body))
102
+ target.focus({ preventScroll: true })
103
+ }
104
+ function present() {
105
+ const current = ++generation
106
+ clearTimeout(timer)
107
+ presented.value = true
108
+ if (typeof document !== 'undefined' && document.activeElement instanceof HTMLElement)
109
+ opener = document.activeElement
110
+ nextTick(() => {
111
+ const element = dialog.value
112
+ if (generation !== current || !element) return
113
+ if (typeof element.showModal === 'function' && !element.open) element.showModal()
114
+ focusInitial(element)
115
+ // Resolve the offscreen position before the open class so the entrance transitions.
116
+ element.getBoundingClientRect?.()
117
+ shown.value = true
118
+ })
119
+ }
120
+ function leave() {
121
+ const element = dialog.value
122
+ const current = ++generation
123
+ shown.value = false
124
+ let release = () => {}
125
+ const finish = () => {
126
+ if (generation !== current) return
127
+ clearTimeout(timer)
128
+ release()
129
+ if (element?.open) element.close()
130
+ presented.value = false
131
+ closing = undefined
132
+ restoreFocus()
133
+ }
134
+ const duration =
135
+ element && typeof getComputedStyle === 'function'
136
+ ? longestDuration(getComputedStyle(element).transitionDuration)
137
+ : 0
138
+ if (!duration || !element) {
139
+ finish()
140
+ return
141
+ }
142
+ const ended = (event: Event) => {
143
+ if (event.target === element) finish()
144
+ }
145
+ element.addEventListener('transitionend', ended)
146
+ release = () => element.removeEventListener('transitionend', ended)
147
+ timer = setTimeout(finish, duration + 100)
148
+ }
149
+
150
+ watch(
151
+ () => props.open,
152
+ (open) => {
153
+ if (open) {
154
+ closing = undefined
155
+ present()
156
+ } else if (presented.value) {
157
+ if (!closing) {
158
+ closing = 'program'
159
+ emit('close', 'program')
160
+ }
161
+ leave()
162
+ }
163
+ },
164
+ )
165
+ onMounted(() => {
166
+ if (props.open) present()
167
+ })
168
+ onBeforeUnmount(() => {
169
+ generation++
170
+ clearTimeout(timer)
171
+ })
172
+
173
+ return () => {
174
+ checkSheetName(props.title, props.accessibilityLabel)
175
+ const { colors, radius, space } = theme.value
176
+ const header =
177
+ props.title || props.dismissible
178
+ ? h(
179
+ MRow,
180
+ { gap: 'sm', justify: 'between' },
181
+ {
182
+ default: () => [
183
+ props.title
184
+ ? h(MText, {
185
+ as: 'h2',
186
+ variant: 'heading',
187
+ grow: 1,
188
+ id: titleId,
189
+ text: props.title,
190
+ })
191
+ : h(MBox, { grow: 1 }),
192
+ props.dismissible
193
+ ? h(MButton, {
194
+ variant: 'ghost',
195
+ size: 'sm',
196
+ icon: 'x',
197
+ shrink: 0,
198
+ accessibilityLabel: props.closeLabel,
199
+ onClick: () => request('button'),
200
+ })
201
+ : null,
202
+ ],
203
+ },
204
+ )
205
+ : null
206
+ return h(
207
+ 'dialog',
208
+ {
209
+ ref: dialog,
210
+ id: props.id,
211
+ class: ['m-sheet', { 'm-sheet-open': shown.value, 'm-sheet-full': props.fullscreen }],
212
+ 'aria-labelledby': props.title ? titleId : undefined,
213
+ 'aria-label': props.title ? undefined : props.accessibilityLabel,
214
+ style: {
215
+ '--m-sheet-surface': colors.surface,
216
+ '--m-sheet-radius': `${radius.lg}px`,
217
+ '--m-focus': colors.primary,
218
+ color: colors.text,
219
+ colorScheme: theme.value.appearance,
220
+ },
221
+ onCancel: (event: Event) => {
222
+ // The browser would close at once; the sheet leaves through its own transition.
223
+ event.preventDefault()
224
+ if (props.dismissible) request('escape')
225
+ },
226
+ onClose: () => {
227
+ // Closed by the browser itself: keep the bound state in step.
228
+ if (props.open && !closing) announce('escape')
229
+ shown.value = false
230
+ presented.value = false
231
+ restoreFocus()
232
+ },
233
+ onKeydown: trapTab,
234
+ onPointerdown: (event: Event) => {
235
+ outside = event.target === event.currentTarget
236
+ },
237
+ onClick: (event: Event) => {
238
+ if (outside && event.target === event.currentTarget && props.dismissible)
239
+ request('backdrop')
240
+ outside = false
241
+ },
242
+ },
243
+ presented.value
244
+ ? [
245
+ h(
246
+ 'div',
247
+ {
248
+ class: 'm-sheet-panel',
249
+ style: {
250
+ padding: `${resolveSpace(theme.value, props.padding ?? 'lg')}px`,
251
+ gap: `${space.md}px`,
252
+ },
253
+ },
254
+ [
255
+ header,
256
+ h(
257
+ MColumn,
258
+ { class: 'm-sheet-body', shrink: 1, gap: props.gap, align: props.align },
259
+ { default: () => slots.default?.() },
260
+ ),
261
+ ],
262
+ ),
263
+ ]
264
+ : undefined,
265
+ )
266
+ }
267
+ },
268
+ })
package/src/index.ts CHANGED
@@ -14,8 +14,22 @@ import { MSlider } from './components/MSlider.js'
14
14
  import { MInput } from './components/MInput.js'
15
15
  import { MIcon } from './components/MIcon.js'
16
16
  import { MReveal } from './components/MReveal.js'
17
+ import { MSheet } from './components/MSheet.js'
17
18
 
18
- export { MScreen, MBox, MRow, MColumn, MCard, MText, MButton, MSlider, MInput, MIcon, MReveal }
19
+ export {
20
+ MScreen,
21
+ MBox,
22
+ MRow,
23
+ MColumn,
24
+ MCard,
25
+ MText,
26
+ MButton,
27
+ MSlider,
28
+ MInput,
29
+ MIcon,
30
+ MReveal,
31
+ MSheet,
32
+ }
19
33
  export { useMavisTheme } from '@getcortexlabs/mavis-core/vue'
20
34
  export type {
21
35
  MavisThemeContext,
@@ -47,6 +61,7 @@ export function createMavis(options: MavisOptions = {}) {
47
61
  MInput,
48
62
  MIcon,
49
63
  MReveal,
64
+ MSheet,
50
65
  })) {
51
66
  app.component(name, component)
52
67
  }
package/src/style.css CHANGED
@@ -154,3 +154,73 @@
154
154
  user-select: none;
155
155
  -webkit-font-smoothing: antialiased;
156
156
  }
157
+
158
+ .m-sheet {
159
+ position: fixed;
160
+ inset: auto 0 0 0;
161
+ width: 100%;
162
+ max-width: 560px;
163
+ max-height: calc(100dvh - 24px);
164
+ margin: 0 auto;
165
+ padding: 0;
166
+ border: 0;
167
+ border-radius: var(--m-sheet-radius) var(--m-sheet-radius) 0 0;
168
+ background: var(--m-sheet-surface);
169
+ overflow: hidden;
170
+ translate: 0 100%;
171
+ transition: translate 240ms cubic-bezier(0.2, 0.8, 0.2, 1);
172
+ }
173
+
174
+ .m-sheet[open] {
175
+ display: flex;
176
+ flex-direction: column;
177
+ }
178
+
179
+ .m-sheet:focus {
180
+ outline: none;
181
+ }
182
+
183
+ .m-sheet.m-sheet-open {
184
+ translate: 0 0;
185
+ }
186
+
187
+ .m-sheet::backdrop {
188
+ background: rgba(0, 0, 0, 0);
189
+ transition: background-color 240ms ease-out;
190
+ }
191
+
192
+ .m-sheet.m-sheet-open::backdrop {
193
+ background: rgba(0, 0, 0, 0.45);
194
+ }
195
+
196
+ .m-sheet-full {
197
+ max-width: none;
198
+ max-height: none;
199
+ height: 100dvh;
200
+ border-radius: 0;
201
+ }
202
+
203
+ .m-sheet-panel {
204
+ display: flex;
205
+ flex: 1;
206
+ flex-direction: column;
207
+ min-height: 0;
208
+ box-sizing: border-box;
209
+ }
210
+
211
+ .m-sheet-body {
212
+ min-height: 0;
213
+ overflow: auto;
214
+ overscroll-behavior: contain;
215
+ }
216
+
217
+ html:has(.m-sheet[open]) {
218
+ overflow: hidden;
219
+ }
220
+
221
+ @media (prefers-reduced-motion: reduce) {
222
+ .m-sheet,
223
+ .m-sheet::backdrop {
224
+ transition: none;
225
+ }
226
+ }
package/src/style.ts CHANGED
@@ -12,21 +12,32 @@ export function length(value: number | string | undefined) {
12
12
  return typeof value === 'number' ? `${value}px` : value
13
13
  }
14
14
 
15
+ // A prop that was not given leaves its style untouched, so the host's CSS keeps applying.
15
16
  export function boxStyle(theme: MavisTheme, props: BoxProps, defaultShrink = 0): CSSProperties {
16
- const padding = resolveSpace(theme, props.padding ?? 'none')
17
- const x = props.paddingX === undefined ? padding : resolveSpace(theme, props.paddingX)
18
- const y = props.paddingY === undefined ? padding : resolveSpace(theme, props.paddingY)
19
- return {
17
+ const style: CSSProperties = {
20
18
  boxSizing: 'border-box',
21
- padding: `${y}px ${x}px`,
22
- borderRadius: length(resolveRadius(theme, props.radius)),
23
19
  flexGrow: nonNegative(props.grow, 'grow'),
24
20
  flexShrink: nonNegative(props.shrink ?? defaultShrink, 'shrink'),
25
21
  minWidth: 0,
26
- width: length(resolveDimension(props.width)),
27
- height: length(resolveDimension(props.height)),
28
- backgroundColor: props.backgroundColor,
29
22
  }
23
+ const padding = props.padding === undefined ? undefined : resolveSpace(theme, props.padding)
24
+ const x = props.paddingX === undefined ? padding : resolveSpace(theme, props.paddingX)
25
+ const y = props.paddingY === undefined ? padding : resolveSpace(theme, props.paddingY)
26
+ if (x !== undefined) {
27
+ style.paddingLeft = `${x}px`
28
+ style.paddingRight = `${x}px`
29
+ }
30
+ if (y !== undefined) {
31
+ style.paddingTop = `${y}px`
32
+ style.paddingBottom = `${y}px`
33
+ }
34
+ if (props.radius !== undefined) style.borderRadius = length(resolveRadius(theme, props.radius))
35
+ const width = length(resolveDimension(props.width))
36
+ if (width !== undefined) style.width = width
37
+ const height = length(resolveDimension(props.height))
38
+ if (height !== undefined) style.height = height
39
+ if (props.backgroundColor !== undefined) style.backgroundColor = props.backgroundColor
40
+ return style
30
41
  }
31
42
 
32
43
  /** Native accessibility labels have the same meaning on the DOM renderer. */