@getcortexlabs/mavis-core 0.1.0-alpha.1 → 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 +2 -2
- package/dist/icon.d.ts +15 -0
- package/dist/icon.d.ts.map +1 -0
- package/dist/icon.js +28 -0
- package/dist/icon.js.map +1 -0
- package/dist/icons.d.ts +2002 -0
- package/dist/icons.d.ts.map +1 -0
- package/dist/icons.js +2003 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/sheet.d.ts +5 -0
- package/dist/sheet.d.ts.map +1 -0
- package/dist/sheet.js +14 -0
- package/dist/sheet.js.map +1 -0
- package/dist/vue/global-components.d.ts +8 -0
- package/dist/vue/global-components.d.ts.map +1 -1
- package/dist/vue/index.d.ts +2 -2
- package/dist/vue/index.d.ts.map +1 -1
- package/dist/vue/index.js +1 -1
- package/dist/vue/index.js.map +1 -1
- package/dist/vue/props.d.ts +195 -18
- package/dist/vue/props.d.ts.map +1 -1
- package/dist/vue/props.js +62 -17
- package/dist/vue/props.js.map +1 -1
- package/dist/vue/theme.d.ts +25 -7
- package/dist/vue/theme.d.ts.map +1 -1
- package/dist/vue/theme.js +37 -2
- package/dist/vue/theme.js.map +1 -1
- package/package.json +1 -1
- package/src/icon.ts +30 -0
- package/src/icons.ts +2002 -0
- package/src/index.ts +5 -0
- package/src/sheet.ts +17 -0
- package/src/vue/global-components.ts +8 -0
- package/src/vue/index.ts +10 -1
- package/src/vue/props.ts +62 -20
- package/src/vue/theme.ts +54 -3
package/src/index.ts
CHANGED
|
@@ -16,4 +16,9 @@ export { sliderScale } from './slider.js'
|
|
|
16
16
|
export { resolveDimension, resolveRadius, nonNegative } from './layout.js'
|
|
17
17
|
export type { Dimension } from './layout.js'
|
|
18
18
|
export { validateInput } from './input.js'
|
|
19
|
+
export { icons, iconFontVersion } from './icons.js'
|
|
20
|
+
export { iconGlyph, iconFontFamily, iconSizes, resolveIconSize, checkIconOnly } from './icon.js'
|
|
21
|
+
export type { IconName, IconSize } from './icon.js'
|
|
19
22
|
export type { InputHandle } from './input.js'
|
|
23
|
+
export { checkSheetName, sheetCloseReasons } from './sheet.js'
|
|
24
|
+
export type { SheetCloseReason } from './sheet.js'
|
package/src/sheet.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Why a sheet closed: the component's own control, a platform dismissal, or `open` set to false. */
|
|
2
|
+
export type SheetCloseReason = 'button' | 'backdrop' | 'escape' | 'back' | 'swipe' | 'program'
|
|
3
|
+
|
|
4
|
+
export const sheetCloseReasons: readonly SheetCloseReason[] = [
|
|
5
|
+
'button',
|
|
6
|
+
'backdrop',
|
|
7
|
+
'escape',
|
|
8
|
+
'back',
|
|
9
|
+
'swipe',
|
|
10
|
+
'program',
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
export function checkSheetName(title: string | undefined, label: string | undefined) {
|
|
14
|
+
if (!title && !label) {
|
|
15
|
+
throw new RangeError('A sheet needs a title or an accessibilityLabel')
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { DefineComponent } from '@vue/runtime-core'
|
|
2
2
|
import type { ComponentProps } from './props.js'
|
|
3
|
+
import type { SheetCloseReason } from '../sheet.js'
|
|
3
4
|
|
|
4
5
|
type Action = { onClick?: () => void }
|
|
5
6
|
type Model = { 'onUpdate:modelValue'?: (value: number) => void }
|
|
@@ -9,6 +10,11 @@ type InputEvents = {
|
|
|
9
10
|
onBlur?: () => void
|
|
10
11
|
onSubmit?: (value: string) => void
|
|
11
12
|
}
|
|
13
|
+
type SheetEvents = {
|
|
14
|
+
'onUpdate:open'?: (value: boolean) => void
|
|
15
|
+
onClose?: (reason: SheetCloseReason) => void
|
|
16
|
+
onOpened?: () => void
|
|
17
|
+
}
|
|
12
18
|
|
|
13
19
|
/** Template props come from the same declarations used by both renderers. */
|
|
14
20
|
declare module '@vue/runtime-core' {
|
|
@@ -22,6 +28,8 @@ declare module '@vue/runtime-core' {
|
|
|
22
28
|
MButton: DefineComponent<ComponentProps['MButton'] & Action>
|
|
23
29
|
MSlider: DefineComponent<ComponentProps['MSlider'] & Model>
|
|
24
30
|
MInput: DefineComponent<ComponentProps['MInput'] & InputEvents>
|
|
31
|
+
MIcon: DefineComponent<ComponentProps['MIcon']>
|
|
25
32
|
MReveal: DefineComponent<ComponentProps['MReveal']>
|
|
33
|
+
MSheet: DefineComponent<ComponentProps['MSheet'] & SheetEvents>
|
|
26
34
|
}
|
|
27
35
|
}
|
package/src/vue/index.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
export { createThemeContext, themeKey, useMavisTheme } from './theme.js'
|
|
2
|
-
export type {
|
|
2
|
+
export type {
|
|
3
|
+
MavisThemeContext,
|
|
4
|
+
Appearance,
|
|
5
|
+
AppearanceMode,
|
|
6
|
+
AppearanceSource,
|
|
7
|
+
ThemeContextOptions,
|
|
8
|
+
} from './theme.js'
|
|
3
9
|
export { layoutDirection, useDefaultShrink } from './layout-context.js'
|
|
4
10
|
export { textContent } from './text-content.js'
|
|
5
11
|
export type {} from './global-components.js'
|
|
@@ -14,8 +20,11 @@ export {
|
|
|
14
20
|
sliderProps,
|
|
15
21
|
inputProps,
|
|
16
22
|
inputEmits,
|
|
23
|
+
iconProps,
|
|
17
24
|
screenProps,
|
|
18
25
|
revealProps,
|
|
26
|
+
sheetProps,
|
|
27
|
+
sheetEmits,
|
|
19
28
|
componentProps,
|
|
20
29
|
viewAttrs,
|
|
21
30
|
actionEmits,
|
package/src/vue/props.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { ExtractPropTypes, ExtractPublicPropTypes, PropType } from '@vue/runtime-core'
|
|
2
2
|
import type { Palette, Spacing, Radius } from '../theme/types.js'
|
|
3
3
|
import type { Dimension } from '../layout.js'
|
|
4
|
+
import { iconSizes, type IconName, type IconSize } from '../icon.js'
|
|
5
|
+
import { sheetCloseReasons, type SheetCloseReason } from '../sheet.js'
|
|
4
6
|
|
|
5
7
|
function choice<T extends string>(values: readonly T[], defaultValue: T) {
|
|
6
8
|
return {
|
|
@@ -77,32 +79,32 @@ export const buttonProps = {
|
|
|
77
79
|
disabled: Boolean,
|
|
78
80
|
loading: Boolean,
|
|
79
81
|
loadingText: { type: String, default: 'Loading…' },
|
|
82
|
+
icon: { type: String as PropType<IconName>, default: undefined },
|
|
83
|
+
trailingIcon: { type: String as PropType<IconName>, default: undefined },
|
|
80
84
|
}
|
|
85
|
+
const tones: readonly (keyof Palette)[] = [
|
|
86
|
+
'background',
|
|
87
|
+
'surface',
|
|
88
|
+
'elevated',
|
|
89
|
+
'text',
|
|
90
|
+
'muted',
|
|
91
|
+
'primary',
|
|
92
|
+
'onPrimary',
|
|
93
|
+
'primarySoft',
|
|
94
|
+
'accent',
|
|
95
|
+
'onAccent',
|
|
96
|
+
'accentSoft',
|
|
97
|
+
'border',
|
|
98
|
+
'success',
|
|
99
|
+
'danger',
|
|
100
|
+
]
|
|
81
101
|
export const textProps = {
|
|
82
102
|
...viewProps,
|
|
83
103
|
...flexProps,
|
|
84
104
|
text: { type: String, default: undefined },
|
|
85
105
|
as: choice(['p', 'span', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'] as const, 'p'),
|
|
86
106
|
variant: choice(['display', 'title', 'heading', 'body', 'caption', 'overline'] as const, 'body'),
|
|
87
|
-
tone: choice<keyof Palette>(
|
|
88
|
-
[
|
|
89
|
-
'background',
|
|
90
|
-
'surface',
|
|
91
|
-
'elevated',
|
|
92
|
-
'text',
|
|
93
|
-
'muted',
|
|
94
|
-
'primary',
|
|
95
|
-
'onPrimary',
|
|
96
|
-
'primarySoft',
|
|
97
|
-
'accent',
|
|
98
|
-
'onAccent',
|
|
99
|
-
'accentSoft',
|
|
100
|
-
'border',
|
|
101
|
-
'success',
|
|
102
|
-
'danger',
|
|
103
|
-
],
|
|
104
|
-
'text',
|
|
105
|
-
),
|
|
107
|
+
tone: choice<keyof Palette>(tones, 'text'),
|
|
106
108
|
align: choice(['left', 'center', 'right'] as const, 'left'),
|
|
107
109
|
wrap: { type: Boolean, default: true },
|
|
108
110
|
}
|
|
@@ -139,6 +141,8 @@ export const inputProps = {
|
|
|
139
141
|
},
|
|
140
142
|
autocorrect: { type: Boolean, default: undefined },
|
|
141
143
|
returnKey: choice(['done', 'next', 'go', 'search', 'send'] as const, 'done'),
|
|
144
|
+
icon: { type: String as PropType<IconName>, default: undefined },
|
|
145
|
+
trailingIcon: { type: String as PropType<IconName>, default: undefined },
|
|
142
146
|
}
|
|
143
147
|
export const inputEmits = {
|
|
144
148
|
'update:modelValue': (value: string) => typeof value === 'string',
|
|
@@ -146,8 +150,44 @@ export const inputEmits = {
|
|
|
146
150
|
blur: () => true,
|
|
147
151
|
submit: (value: string) => typeof value === 'string',
|
|
148
152
|
}
|
|
149
|
-
export const
|
|
153
|
+
export const iconProps = {
|
|
154
|
+
id: viewProps.id,
|
|
155
|
+
name: { type: String as PropType<IconName>, required: true as const },
|
|
156
|
+
size: {
|
|
157
|
+
type: [String, Number] as PropType<IconSize>,
|
|
158
|
+
default: 'md',
|
|
159
|
+
validator: (value: IconSize) => typeof value === 'number' || value in iconSizes,
|
|
160
|
+
},
|
|
161
|
+
tone: choice<keyof Palette>(tones, 'text'),
|
|
162
|
+
/** Accessible name. Without it the icon is decorative and hidden from assistive technology. */
|
|
163
|
+
label: { type: String, default: undefined },
|
|
164
|
+
}
|
|
165
|
+
export const screenProps = {
|
|
166
|
+
...viewProps,
|
|
167
|
+
scroll: Boolean,
|
|
168
|
+
/** Puts the software keyboard away on a tap outside the editor and, with `scroll`, on a drag towards it. */
|
|
169
|
+
dismissKeyboard: { type: Boolean, default: true },
|
|
170
|
+
}
|
|
150
171
|
export const revealProps = { ...columnProps, show: Boolean }
|
|
172
|
+
export const sheetProps = {
|
|
173
|
+
id: viewProps.id,
|
|
174
|
+
accessibilityLabel: viewProps.accessibilityLabel,
|
|
175
|
+
open: Boolean,
|
|
176
|
+
/** Rendered as the sheet heading and used as its accessible name. */
|
|
177
|
+
title: { type: String, default: undefined },
|
|
178
|
+
/** Allows the scrim, Escape, the back gesture, swiping down and the close button. */
|
|
179
|
+
dismissible: { type: Boolean, default: true },
|
|
180
|
+
fullscreen: Boolean,
|
|
181
|
+
closeLabel: { type: String, default: 'Close' },
|
|
182
|
+
padding: { ...spacingProp, default: 'lg' },
|
|
183
|
+
gap: spacingProp,
|
|
184
|
+
align: columnProps.align,
|
|
185
|
+
}
|
|
186
|
+
export const sheetEmits = {
|
|
187
|
+
'update:open': (value: boolean) => typeof value === 'boolean',
|
|
188
|
+
close: (reason: SheetCloseReason) => sheetCloseReasons.includes(reason),
|
|
189
|
+
opened: () => true,
|
|
190
|
+
}
|
|
151
191
|
export const actionEmits = { click: () => true }
|
|
152
192
|
export const sliderEmits = { 'update:modelValue': (value: number) => Number.isFinite(value) }
|
|
153
193
|
|
|
@@ -161,7 +201,9 @@ export const componentProps = {
|
|
|
161
201
|
MButton: buttonProps,
|
|
162
202
|
MSlider: sliderProps,
|
|
163
203
|
MInput: inputProps,
|
|
204
|
+
MIcon: iconProps,
|
|
164
205
|
MReveal: revealProps,
|
|
206
|
+
MSheet: sheetProps,
|
|
165
207
|
}
|
|
166
208
|
export type BoxProps = ExtractPropTypes<typeof boxProps>
|
|
167
209
|
export type ComponentProps = {
|
package/src/vue/theme.ts
CHANGED
|
@@ -2,17 +2,68 @@ import { inject, readonly, shallowRef, type InjectionKey } from '@vue/runtime-co
|
|
|
2
2
|
import { mavis } from '../theme/themes.js'
|
|
3
3
|
import type { MavisTheme } from '../theme/types.js'
|
|
4
4
|
|
|
5
|
-
export
|
|
5
|
+
export type Appearance = MavisTheme['appearance']
|
|
6
|
+
export type AppearanceMode = Appearance | 'system'
|
|
7
|
+
|
|
8
|
+
/** Platform access to the device appearance; `current` is undefined while it is unknown, such as during SSR. */
|
|
9
|
+
export interface AppearanceSource {
|
|
10
|
+
current(): Appearance | undefined
|
|
11
|
+
observe(listener: (appearance: Appearance) => void): () => void
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ThemeContextOptions {
|
|
15
|
+
theme?: MavisTheme
|
|
16
|
+
darkTheme?: MavisTheme
|
|
17
|
+
appearance?: AppearanceMode
|
|
18
|
+
source?: AppearanceSource
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const modes: readonly AppearanceMode[] = ['system', 'light', 'dark']
|
|
22
|
+
|
|
23
|
+
function checkMode(mode: AppearanceMode) {
|
|
24
|
+
if (!modes.includes(mode)) throw new RangeError(`Unknown appearance mode: ${String(mode)}`)
|
|
25
|
+
return mode
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function createThemeContext(options: MavisTheme | ThemeContextOptions = {}) {
|
|
29
|
+
const config: ThemeContextOptions = 'colors' in options ? { theme: options } : options
|
|
30
|
+
const initial = config.theme ?? mavis
|
|
31
|
+
const themes: Partial<Record<Appearance, MavisTheme>> = { [initial.appearance]: initial }
|
|
32
|
+
if (config.darkTheme) themes.dark = config.darkTheme
|
|
33
|
+
const appearance = shallowRef(checkMode(config.appearance ?? 'system'))
|
|
6
34
|
const theme = shallowRef(initial)
|
|
35
|
+
const resolve = () => {
|
|
36
|
+
const wanted =
|
|
37
|
+
appearance.value === 'system'
|
|
38
|
+
? (config.source?.current() ?? initial.appearance)
|
|
39
|
+
: appearance.value
|
|
40
|
+
theme.value = themes[wanted] ?? themes[wanted === 'dark' ? 'light' : 'dark'] ?? initial
|
|
41
|
+
}
|
|
42
|
+
resolve()
|
|
43
|
+
const stop = config.source?.observe(() => {
|
|
44
|
+
if (appearance.value === 'system') resolve()
|
|
45
|
+
})
|
|
7
46
|
return {
|
|
8
47
|
theme: readonly(theme),
|
|
48
|
+
/** The selection: `system` follows the device; `light` and `dark` are explicit overrides. */
|
|
49
|
+
appearance: readonly(appearance),
|
|
50
|
+
setAppearance(mode: AppearanceMode) {
|
|
51
|
+
appearance.value = checkMode(mode)
|
|
52
|
+
resolve()
|
|
53
|
+
},
|
|
54
|
+
/** Registers the theme for its own appearance and pins that appearance. */
|
|
9
55
|
setTheme(next: MavisTheme) {
|
|
10
|
-
|
|
56
|
+
themes[next.appearance] = next
|
|
57
|
+
appearance.value = next.appearance
|
|
58
|
+
resolve()
|
|
59
|
+
},
|
|
60
|
+
dispose() {
|
|
61
|
+
stop?.()
|
|
11
62
|
},
|
|
12
63
|
}
|
|
13
64
|
}
|
|
14
|
-
|
|
15
65
|
export type MavisThemeContext = ReturnType<typeof createThemeContext>
|
|
66
|
+
|
|
16
67
|
export const themeKey: InjectionKey<MavisThemeContext> = Symbol('mavis.theme')
|
|
17
68
|
|
|
18
69
|
/** Without the plugin, individually imported components use the default theme. */
|