@trypattern/sdk 0.1.0 → 0.1.2
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/dist/api.d.ts +17 -7
- package/dist/api.js +34 -8
- package/dist/app.d.ts +12 -3
- package/dist/app.js +49 -7
- package/dist/appInfo.d.ts +35 -0
- package/dist/appInfo.js +67 -0
- package/dist/appTitle.d.ts +6 -0
- package/dist/appTitle.js +3 -0
- package/dist/auth/sessionApi.js +2 -1
- package/dist/builtins/AppSettings.d.ts +12 -0
- package/dist/builtins/AppSettings.js +31 -0
- package/dist/builtins/Toasts.d.ts +1 -1
- package/dist/builtins/Toasts.js +2 -1
- package/dist/cli/app.js +91 -14
- package/dist/cli/publishing.d.ts +21 -0
- package/dist/cli/publishing.js +502 -0
- package/dist/clock.d.ts +6 -0
- package/dist/clock.js +31 -0
- package/dist/components/AppFrame.js +3 -3
- package/dist/components/Button.d.ts +2 -1
- package/dist/components/Button.js +6 -3
- package/dist/components/CopyButton.d.ts +11 -0
- package/dist/components/CopyButton.js +16 -0
- package/dist/components/Divider.d.ts +2 -1
- package/dist/components/Divider.js +19 -4
- package/dist/components/IconButton.js +2 -2
- package/dist/components/Link.d.ts +8 -3
- package/dist/components/Link.js +11 -2
- package/dist/components/ListRow.js +2 -2
- package/dist/components/Menu.js +2 -2
- package/dist/components/RadioGroup.d.ts +18 -0
- package/dist/components/RadioGroup.js +85 -0
- package/dist/components/SegmentedControl.js +2 -2
- package/dist/components/Sidebar.js +2 -3
- package/dist/components/SignInScreen.js +3 -3
- package/dist/components/Switch.js +2 -1
- package/dist/components/controlLook.d.ts +10 -0
- package/dist/components/controlLook.js +14 -1
- package/dist/components/icons.d.ts +4 -3
- package/dist/components/icons.js +9 -3
- package/dist/components/interaction.d.ts +1 -1
- package/dist/flows/accessFlows.js +19 -3
- package/dist/flows/browser.d.ts +3 -1
- package/dist/flows/browser.js +6 -3
- package/dist/flows/flowBrowser.d.ts +3 -1
- package/dist/flows/flowBrowser.js +4 -2
- package/dist/flows/flows.d.ts +6 -0
- package/dist/flows/flows.js +32 -5
- package/dist/hooks/appContext.d.ts +2 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.js +4 -2
- package/dist/publishWire.d.ts +271 -0
- package/dist/publishWire.js +168 -0
- package/dist/react.d.ts +3 -0
- package/dist/react.js +2 -0
- package/dist/registered.d.ts +6 -0
- package/dist/registered.js +2 -0
- package/dist/rules/checkAllFiles.js +10 -2
- package/dist/rules/lintPlugin.js +2 -0
- package/dist/rules/messages.d.ts +2 -2
- package/dist/rules/messages.js +2 -2
- package/dist/schema.d.ts +2 -0
- package/dist/schema.js +1 -0
- package/dist/server/auth.js +8 -2
- package/dist/server/createServer.d.ts +48 -3
- package/dist/server/createServer.js +25 -5
- package/dist/server/env.d.ts +2 -2
- package/dist/server/index.d.ts +6 -1
- package/dist/server/index.js +5 -1
- package/dist/server/services.d.ts +9 -0
- package/dist/server/services.js +47 -0
- package/dist/server/session.d.ts +1 -0
- package/dist/server/session.js +11 -0
- package/dist/server/settings.d.ts +49 -0
- package/dist/server/settings.js +25 -0
- package/dist/server/signInWire.d.ts +1 -0
- package/dist/server/signInWire.js +2 -1
- package/dist/serviceClients.d.ts +5 -0
- package/dist/serviceClients.js +70 -0
- package/dist/services.d.ts +53 -0
- package/dist/services.js +30 -0
- package/dist/start.js +30 -6
- package/dist/store.d.ts +5 -3
- package/dist/store.js +13 -3
- package/dist/table.d.ts +1 -1
- package/dist/vite/localWorker.d.ts +1 -1
- package/dist/vite/localWorker.js +5 -4
- package/dist/vite/projectFile.d.ts +9 -0
- package/dist/vite/projectFile.js +17 -0
- package/dist/vite/vite.d.ts +2 -1
- package/dist/vite/vite.js +10 -3
- package/package.json +5 -1
- package/presets/register.d.ts +2 -0
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Separator } from '@base-ui/react/separator';
|
|
3
3
|
import * as stylex from '@stylexjs/stylex';
|
|
4
|
-
import { borders, colors } from "../theme/tokens.stylex.js";
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import { borders, colors, space } from "../theme/tokens.stylex.js";
|
|
5
|
+
import { Text } from "./Text.js";
|
|
6
|
+
export function Divider({ label, style }) {
|
|
7
|
+
if (label === undefined) {
|
|
8
|
+
return (_jsx(Separator, { className: stylex.props(styles.divider, style).className }));
|
|
9
|
+
}
|
|
10
|
+
return (_jsxs("div", { ...stylex.props(styles.labelled, style), children: [_jsx(Separator, { className: stylex.props(styles.divider, styles.grow).className }), _jsx(Text, { variant: "caption", tone: "tertiary", children: label }), _jsx(Separator, { className: stylex.props(styles.divider, styles.grow).className })] }));
|
|
7
11
|
}
|
|
8
12
|
const styles = stylex.create({
|
|
9
13
|
divider: {
|
|
@@ -11,5 +15,16 @@ const styles = stylex.create({
|
|
|
11
15
|
width: '100%',
|
|
12
16
|
height: borders.hairline,
|
|
13
17
|
backgroundColor: colors.divider
|
|
18
|
+
},
|
|
19
|
+
labelled: {
|
|
20
|
+
display: 'flex',
|
|
21
|
+
gap: space.md,
|
|
22
|
+
alignItems: 'center',
|
|
23
|
+
width: '100%'
|
|
24
|
+
},
|
|
25
|
+
grow: {
|
|
26
|
+
flexGrow: 1,
|
|
27
|
+
flexShrink: 1,
|
|
28
|
+
width: 'auto'
|
|
14
29
|
}
|
|
15
30
|
});
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { Button as BaseButton } from '@base-ui/react/button';
|
|
3
3
|
import * as stylex from '@stylexjs/stylex';
|
|
4
4
|
import { colors, controls, radii } from "../theme/tokens.stylex.js";
|
|
5
|
-
import { transparentLook } from "./controlLook.js";
|
|
5
|
+
import { focusRing, transparentLook } from "./controlLook.js";
|
|
6
6
|
import { Icon } from "./Icon.js";
|
|
7
7
|
import { interact } from "./interaction.js";
|
|
8
8
|
import { Tooltip } from "./Tooltip.js";
|
|
@@ -10,7 +10,7 @@ export function IconButton({ icon, label, size = 'md', shortcut, disabled = fals
|
|
|
10
10
|
return (_jsx(Tooltip, { label: label, shortcut: shortcut, children: _jsx(BaseButton, { "aria-label": label, disabled: disabled, focusableWhenDisabled: true, onClick: () => {
|
|
11
11
|
interact({ primitive: 'IconButton', event: 'click', label });
|
|
12
12
|
onClick();
|
|
13
|
-
}, className: stylex.props(styles.button, sizes[size], transparentLook.rest, !disabled && transparentLook.hoverable, disabled && styles.disabled, style).className, children: _jsx(Icon, { name: icon, size: size }) }) }));
|
|
13
|
+
}, className: stylex.props(styles.button, sizes[size], transparentLook.rest, !disabled && transparentLook.hoverable, disabled && styles.disabled, focusRing.visible, style).className, children: _jsx(Icon, { name: icon, size: size }) }) }));
|
|
14
14
|
}
|
|
15
15
|
const styles = stylex.create({
|
|
16
16
|
button: {
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import type { AppPath } from '../registered.ts';
|
|
3
3
|
type LinkProps = {
|
|
4
|
-
to: AppPath;
|
|
5
4
|
tone?: 'brand' | 'secondary';
|
|
6
5
|
children: ReactNode;
|
|
7
|
-
}
|
|
8
|
-
|
|
6
|
+
} & ({
|
|
7
|
+
to: AppPath;
|
|
8
|
+
href?: never;
|
|
9
|
+
} | {
|
|
10
|
+
href: string;
|
|
11
|
+
to?: never;
|
|
12
|
+
});
|
|
13
|
+
export declare function Link({ to, href, tone, children }: LinkProps): import("react").JSX.Element;
|
|
9
14
|
export {};
|
package/dist/components/Link.js
CHANGED
|
@@ -2,13 +2,22 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import * as stylex from '@stylexjs/stylex';
|
|
3
3
|
import { Link as RouterLink } from 'react-router';
|
|
4
4
|
import { colors, motion, radii } from "../theme/tokens.stylex.js";
|
|
5
|
+
import { focusRing } from "./controlLook.js";
|
|
5
6
|
import { interact, textOf } from "./interaction.js";
|
|
6
|
-
export function Link({ to, tone = 'brand', children }) {
|
|
7
|
+
export function Link({ to, href, tone = 'brand', children }) {
|
|
8
|
+
const className = stylex.props(styles.link, looks[tone], focusRing.visible).className;
|
|
9
|
+
if (href !== undefined) {
|
|
10
|
+
return (_jsx("a", { href: href, target: "_blank", rel: "noreferrer", onClick: () => interact({
|
|
11
|
+
primitive: 'Link',
|
|
12
|
+
event: 'open',
|
|
13
|
+
label: textOf(children) || href
|
|
14
|
+
}), className: className, children: children }));
|
|
15
|
+
}
|
|
7
16
|
return (_jsx(RouterLink, { to: to, onClick: () => interact({
|
|
8
17
|
primitive: 'Link',
|
|
9
18
|
event: 'navigate',
|
|
10
19
|
label: textOf(children) || to
|
|
11
|
-
}),
|
|
20
|
+
}), className: className, children: children }));
|
|
12
21
|
}
|
|
13
22
|
const styles = stylex.create({
|
|
14
23
|
link: {
|
|
@@ -3,10 +3,11 @@ import { Button as BaseButton } from '@base-ui/react/button';
|
|
|
3
3
|
import * as stylex from '@stylexjs/stylex';
|
|
4
4
|
import { Link as RouterLink } from 'react-router';
|
|
5
5
|
import { colors, controls, radii, space } from "../theme/tokens.stylex.js";
|
|
6
|
+
import { focusRing } from "./controlLook.js";
|
|
6
7
|
import { interact, textOf } from "./interaction.js";
|
|
7
8
|
export function ListRow({ to, onClick, isMuted = false, leading, trailing, children }) {
|
|
8
9
|
const content = (_jsxs(_Fragment, { children: [leading, _jsx("span", { ...stylex.props(styles.main), children: children }), trailing === undefined ? null : (_jsx("span", { ...stylex.props(styles.trailing), children: trailing }))] }));
|
|
9
|
-
const look = stylex.props(styles.row, (to !== undefined || onClick !== undefined) && styles.interactive, isMuted && styles.muted);
|
|
10
|
+
const look = stylex.props(styles.row, (to !== undefined || onClick !== undefined) && styles.interactive, isMuted && styles.muted, focusRing.visible, focusRing.inside);
|
|
10
11
|
const report = () => {
|
|
11
12
|
interact({
|
|
12
13
|
primitive: 'ListRow',
|
|
@@ -34,7 +35,6 @@ const styles = stylex.create({
|
|
|
34
35
|
color: colors.primaryForeground,
|
|
35
36
|
textAlign: 'start',
|
|
36
37
|
textDecoration: 'none',
|
|
37
|
-
outlineOffset: -2,
|
|
38
38
|
borderRadius: radii.md
|
|
39
39
|
},
|
|
40
40
|
interactive: {
|
package/dist/components/Menu.js
CHANGED
|
@@ -2,11 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Menu as BaseMenu } from '@base-ui/react/menu';
|
|
3
3
|
import * as stylex from '@stylexjs/stylex';
|
|
4
4
|
import { colors, controls, layers, space } from "../theme/tokens.stylex.js";
|
|
5
|
-
import { controlSizes, transparentLook } from "./controlLook.js";
|
|
5
|
+
import { controlSizes, focusRing, transparentLook } from "./controlLook.js";
|
|
6
6
|
import { MenuItems } from "./MenuItems.js";
|
|
7
7
|
import { Popup } from "./Popup.js";
|
|
8
8
|
export function Menu({ trigger, items, size = 'md', style }) {
|
|
9
|
-
return (_jsxs(BaseMenu.Root, { children: [_jsx(BaseMenu.Trigger, { className: (state) => stylex.props(styles.trigger, controlSizes[size], triggerPaddings[size], transparentLook.rest, transparentLook.hoverable, state.open && transparentLook.open, styles.triggerText, style).className, children: trigger }), _jsx(BaseMenu.Portal, { children: _jsx(BaseMenu.Positioner, { side: "bottom", align: "start", sideOffset: 4, className: stylex.props(styles.positioner).className, children: _jsx(BaseMenu.Popup, { render: (props, state) => (_jsx(Popup, { ...props, kind: "menu", isOpen: state.open, transitionStatus: state.transitionStatus })), children: _jsx(MenuItems, { items: items, primitive: "Menu" }) }) }) })] }));
|
|
9
|
+
return (_jsxs(BaseMenu.Root, { children: [_jsx(BaseMenu.Trigger, { className: (state) => stylex.props(styles.trigger, controlSizes[size], triggerPaddings[size], transparentLook.rest, transparentLook.hoverable, state.open && transparentLook.open, styles.triggerText, focusRing.visible, style).className, children: trigger }), _jsx(BaseMenu.Portal, { children: _jsx(BaseMenu.Positioner, { side: "bottom", align: "start", sideOffset: 4, className: stylex.props(styles.positioner).className, children: _jsx(BaseMenu.Popup, { render: (props, state) => (_jsx(Popup, { ...props, kind: "menu", isOpen: state.open, transitionStatus: state.transitionStatus })), children: _jsx(MenuItems, { items: items, primitive: "Menu" }) }) }) })] }));
|
|
10
10
|
}
|
|
11
11
|
const styles = stylex.create({
|
|
12
12
|
trigger: {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { Placement } from './Placement.ts';
|
|
3
|
+
export type RadioOption<Value extends string> = {
|
|
4
|
+
value: Value;
|
|
5
|
+
label: string;
|
|
6
|
+
content?: ReactNode;
|
|
7
|
+
trailing?: ReactNode;
|
|
8
|
+
isDisabled?: boolean;
|
|
9
|
+
};
|
|
10
|
+
type RadioGroupProps<Value extends string> = {
|
|
11
|
+
label: string;
|
|
12
|
+
value: Value | null;
|
|
13
|
+
options: readonly RadioOption<Value>[];
|
|
14
|
+
onChange: (value: Value) => void;
|
|
15
|
+
style?: Placement;
|
|
16
|
+
};
|
|
17
|
+
export declare function RadioGroup<Value extends string>({ label, value, options, onChange, style }: RadioGroupProps<Value>): import("react").JSX.Element;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Radio as BaseRadio } from '@base-ui/react/radio';
|
|
3
|
+
import { RadioGroup as BaseRadioGroup } from '@base-ui/react/radio-group';
|
|
4
|
+
import * as stylex from '@stylexjs/stylex';
|
|
5
|
+
import { borders, colors, iconSizes, motion, radii, shadows, space } from "../theme/tokens.stylex.js";
|
|
6
|
+
import { focusRing } from "./controlLook.js";
|
|
7
|
+
import { interact } from "./interaction.js";
|
|
8
|
+
import { Text } from "./Text.js";
|
|
9
|
+
export function RadioGroup({ label, value, options, onChange, style }) {
|
|
10
|
+
return (_jsx(BaseRadioGroup, { "aria-label": label, value: value, onValueChange: (next) => {
|
|
11
|
+
const chosen = options.find((option) => option.value === next);
|
|
12
|
+
if (chosen === undefined)
|
|
13
|
+
return;
|
|
14
|
+
interact({
|
|
15
|
+
primitive: 'RadioGroup',
|
|
16
|
+
event: 'change',
|
|
17
|
+
label: chosen.label
|
|
18
|
+
});
|
|
19
|
+
onChange(chosen.value);
|
|
20
|
+
}, className: stylex.props(styles.group, style).className, children: options.map((option) => (_jsxs("label", { ...stylex.props(styles.row, option.isDisabled === true && styles.rowDisabled), children: [_jsx(BaseRadio.Root, { value: option.value, disabled: option.isDisabled === true, "aria-label": option.label, className: (state) => stylex.props(styles.dot, state.checked ? styles.dotOn : styles.dotOff, focusRing.visible).className, children: _jsx(BaseRadio.Indicator, { className: stylex.props(styles.mark).className }) }), _jsx("span", { ...stylex.props(styles.content), children: option.content ?? (_jsx(Text, { tone: option.isDisabled === true ? 'tertiary' : 'primary', isTruncated: true, children: option.label })) }), option.trailing === undefined ? null : (_jsx("span", { ...stylex.props(styles.trailing), children: option.trailing }))] }, option.value))) }));
|
|
21
|
+
}
|
|
22
|
+
const styles = stylex.create({
|
|
23
|
+
group: {
|
|
24
|
+
display: 'flex',
|
|
25
|
+
flexDirection: 'column',
|
|
26
|
+
overflow: 'hidden',
|
|
27
|
+
backgroundColor: colors.componentOnContainerStrong,
|
|
28
|
+
borderRadius: radii.xl,
|
|
29
|
+
boxShadow: shadows.default
|
|
30
|
+
},
|
|
31
|
+
row: {
|
|
32
|
+
display: 'flex',
|
|
33
|
+
gap: space.md,
|
|
34
|
+
alignItems: 'center',
|
|
35
|
+
minWidth: 0,
|
|
36
|
+
paddingBlock: space.md,
|
|
37
|
+
paddingInline: space.md,
|
|
38
|
+
borderTopColor: colors.divider,
|
|
39
|
+
borderTopStyle: {
|
|
40
|
+
default: 'solid',
|
|
41
|
+
':first-child': 'none'
|
|
42
|
+
},
|
|
43
|
+
borderTopWidth: borders.hairline
|
|
44
|
+
},
|
|
45
|
+
rowDisabled: {
|
|
46
|
+
color: colors.tertiaryForeground
|
|
47
|
+
},
|
|
48
|
+
dot: {
|
|
49
|
+
display: 'grid',
|
|
50
|
+
flexShrink: 0,
|
|
51
|
+
placeItems: 'center',
|
|
52
|
+
width: iconSizes.md,
|
|
53
|
+
height: iconSizes.md,
|
|
54
|
+
padding: 0,
|
|
55
|
+
borderStyle: 'solid',
|
|
56
|
+
borderWidth: borders.thin,
|
|
57
|
+
borderRadius: radii.full,
|
|
58
|
+
transitionTimingFunction: motion.easeOut,
|
|
59
|
+
transitionDuration: motion.fast,
|
|
60
|
+
transitionProperty: 'background-color, border-color'
|
|
61
|
+
},
|
|
62
|
+
dotOff: {
|
|
63
|
+
backgroundColor: colors.componentOnContainerStrong,
|
|
64
|
+
borderColor: colors.borderStrong
|
|
65
|
+
},
|
|
66
|
+
dotOn: {
|
|
67
|
+
backgroundColor: colors.invertedSolid,
|
|
68
|
+
borderColor: colors.invertedSolid
|
|
69
|
+
},
|
|
70
|
+
mark: {
|
|
71
|
+
width: `calc(${iconSizes.md} / 2.5)`,
|
|
72
|
+
height: `calc(${iconSizes.md} / 2.5)`,
|
|
73
|
+
backgroundColor: colors.onInvertedForeground,
|
|
74
|
+
borderRadius: radii.full
|
|
75
|
+
},
|
|
76
|
+
content: {
|
|
77
|
+
flexGrow: 1,
|
|
78
|
+
minWidth: 0
|
|
79
|
+
},
|
|
80
|
+
trailing: {
|
|
81
|
+
display: 'flex',
|
|
82
|
+
flexShrink: 0,
|
|
83
|
+
alignItems: 'center'
|
|
84
|
+
}
|
|
85
|
+
});
|
|
@@ -4,13 +4,13 @@ import { RadioGroup } from '@base-ui/react/radio-group';
|
|
|
4
4
|
import * as stylex from '@stylexjs/stylex';
|
|
5
5
|
import { borders, colors, fontWeights, motion, radii } from "../theme/tokens.stylex.js";
|
|
6
6
|
import { interact } from "./interaction.js";
|
|
7
|
-
import { controlSizes } from "./controlLook.js";
|
|
7
|
+
import { controlSizes, focusRing } from "./controlLook.js";
|
|
8
8
|
export function SegmentedControl({ label, value, options, size = 'md', disabled = false, onChange, style }) {
|
|
9
9
|
const index = Math.max(0, options.findIndex((option) => option.value === value));
|
|
10
10
|
return (_jsxs(RadioGroup, { "aria-label": label, value: value, disabled: disabled, onValueChange: (next) => {
|
|
11
11
|
interact({ primitive: 'SegmentedControl', event: 'change', label });
|
|
12
12
|
onChange(next);
|
|
13
|
-
}, className: stylex.props(styles.group, style).className, children: [_jsx("span", { ...stylex.props(styles.indicator(index, options.length)) }), options.map((option) => (_jsx(Radio.Root, { value: option.value, className: (state) => stylex.props(styles.option, controlSizes[size], !disabled && styles.hoverable, state.checked && styles.optionChecked, disabled && styles.disabled).className, children: option.label }, option.value)))] }));
|
|
13
|
+
}, className: stylex.props(styles.group, style).className, children: [_jsx("span", { ...stylex.props(styles.indicator(index, options.length)) }), options.map((option) => (_jsx(Radio.Root, { value: option.value, className: (state) => stylex.props(styles.option, controlSizes[size], !disabled && styles.hoverable, state.checked && styles.optionChecked, disabled && styles.disabled, focusRing.visible).className, children: option.label }, option.value)))] }));
|
|
14
14
|
}
|
|
15
15
|
const styles = stylex.create({
|
|
16
16
|
group: {
|
|
@@ -3,6 +3,7 @@ import * as stylex from '@stylexjs/stylex';
|
|
|
3
3
|
import { NavLink } from 'react-router';
|
|
4
4
|
import { breakpoints, colors, controls, iconSizes, layers, motion, radii, shadows, space, widths } from "../theme/tokens.stylex.js";
|
|
5
5
|
import { Badge } from "./Badge.js";
|
|
6
|
+
import { focusRing } from "./controlLook.js";
|
|
6
7
|
import { Button } from "./Button.js";
|
|
7
8
|
import { Icon } from "./Icon.js";
|
|
8
9
|
import { interact } from "./interaction.js";
|
|
@@ -14,8 +15,7 @@ export function Sidebar({ workspace, workspaceMenu, links, isToggled, isAnimatin
|
|
|
14
15
|
interact({ primitive: 'AppFrame', event: 'navigate', label: link.label });
|
|
15
16
|
onFollowLink();
|
|
16
17
|
};
|
|
17
|
-
return (_jsxs("nav", { ...stylex.props(styles.sidebar, isToggled && styles.sidebarToggled, isAnimating && styles.sidebarAnimating), children: [_jsx("div", { ...stylex.props(styles.header), children: _jsx(Menu, { trigger: _jsxs(_Fragment, { children: [_jsx("span", { ...stylex.props(styles.logo), children: _jsx(Text, { variant: "caption", children: workspace.charAt(0) }) }), _jsx(Text, { variant: "label", isTruncated: true, children: workspace }), _jsx(Icon, { name: "chevronDown" })] }), items: workspaceMenu }) }), onSearch === undefined ? null : (_jsx(Button, { variant: "secondary", icon: "search", shortcut: ['mod', 'k'], isFullWidth: true, onClick: onSearch, children: "Search" })), _jsx("div", { ...stylex.props(styles.body), children: _jsx(ScrollArea, { children: _jsxs("div", { ...stylex.props(styles.group), children: [_jsx("span", { ...stylex.props(styles.groupLabel), children: _jsx(Text, { variant: "label", tone: "tertiary", children: "Workspace" }) }), links.map((item) => (_jsxs(NavLink, { onClick: () => followLink(item), to: item.to, end: item.to === '/', className: ({ isActive }) => stylex.props(styles.item, isActive && styles.itemCurrent)
|
|
18
|
-
.className ?? '', children: [_jsx(Icon, { name: item.icon }), _jsx(Text, { variant: "label", isTruncated: true, style: styles.itemLabel, children: item.label }), typeof item.count !== 'number' ? null : (_jsx(Badge, { variant: "transparent", children: item.count }))] }, item.to)))] }) }) })] }));
|
|
18
|
+
return (_jsxs("nav", { ...stylex.props(styles.sidebar, isToggled && styles.sidebarToggled, isAnimating && styles.sidebarAnimating), children: [_jsx("div", { ...stylex.props(styles.header), children: _jsx(Menu, { trigger: _jsxs(_Fragment, { children: [_jsx("span", { ...stylex.props(styles.logo), children: _jsx(Text, { variant: "caption", children: workspace.charAt(0) }) }), _jsx(Text, { variant: "label", isTruncated: true, children: workspace }), _jsx(Icon, { name: "chevronDown" })] }), items: workspaceMenu }) }), onSearch === undefined ? null : (_jsx(Button, { variant: "secondary", icon: "search", shortcut: ['mod', 'k'], isFullWidth: true, onClick: onSearch, children: "Search" })), _jsx("div", { ...stylex.props(styles.body), children: _jsx(ScrollArea, { children: _jsxs("div", { ...stylex.props(styles.group), children: [_jsx("span", { ...stylex.props(styles.groupLabel), children: _jsx(Text, { variant: "label", tone: "tertiary", children: "Workspace" }) }), links.map((item) => (_jsxs(NavLink, { onClick: () => followLink(item), to: item.to, end: item.to === '/', className: ({ isActive }) => stylex.props(styles.item, isActive && styles.itemCurrent, focusRing.visible, focusRing.inside).className ?? '', children: [_jsx(Icon, { name: item.icon }), _jsx(Text, { variant: "label", isTruncated: true, style: styles.itemLabel, children: item.label }), typeof item.count !== 'number' ? null : (_jsx(Badge, { variant: "transparent", children: item.count }))] }, item.to)))] }) }) })] }));
|
|
19
19
|
}
|
|
20
20
|
const styles = stylex.create({
|
|
21
21
|
sidebar: {
|
|
@@ -121,7 +121,6 @@ const styles = stylex.create({
|
|
|
121
121
|
':hover': colors.primaryForeground
|
|
122
122
|
},
|
|
123
123
|
textDecoration: 'none',
|
|
124
|
-
outlineOffset: 0,
|
|
125
124
|
backgroundColor: {
|
|
126
125
|
default: 'transparent',
|
|
127
126
|
':hover': colors.transparentHover
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import * as stylex from '@stylexjs/stylex';
|
|
3
|
-
import {
|
|
3
|
+
import { useModel } from "../hooks/appContext.js";
|
|
4
4
|
import { colors, controls, radii, space, widths } from "../theme/tokens.stylex.js";
|
|
5
5
|
import { Button } from "./Button.js";
|
|
6
6
|
import { Form } from "./Form.js";
|
|
7
7
|
import { Text } from "./Text.js";
|
|
8
8
|
import { TextField } from "./TextField.js";
|
|
9
9
|
export function SignInScreen() {
|
|
10
|
-
const
|
|
10
|
+
const appSettings = useModel('appSettings');
|
|
11
11
|
const signIn = useModel('signIn');
|
|
12
12
|
const isBusy = signIn.signingIn !== null;
|
|
13
|
-
return (_jsx("main", { ...stylex.props(styles.page), children: _jsxs("div", { ...stylex.props(styles.column), children: [_jsx("span", { ...stylex.props(styles.mark), children: _jsx(Text, { variant: "title", children:
|
|
13
|
+
return (_jsx("main", { ...stylex.props(styles.page), children: _jsxs("div", { ...stylex.props(styles.column), children: [_jsx("span", { ...stylex.props(styles.mark), children: _jsx(Text, { variant: "title", children: appSettings.title.charAt(0) }) }), _jsxs(Text, { as: "h1", variant: "title", tone: "primary", align: "center", children: ["Sign in to ", appSettings.title] }), signIn.step === 'choose' ? (_jsxs(_Fragment, { children: [_jsx(Button, { size: "lg", disabled: isBusy, isPending: signIn.signingIn === 'google', onClick: signIn.continueWithGoogle, children: "Continue with Google" }), _jsxs(Form, { onSubmit: (values) => signIn.sendEmailCode({ email: values['email'] ?? '' }), children: [_jsx(TextField, { name: "email", type: "email", required: true, autoComplete: "email", placeholder: "you@example.com", label: "Email", isLabelHidden: true, size: "lg" }), _jsx(Button, { type: "submit", variant: "secondary", size: "lg", disabled: isBusy, isPending: signIn.signingIn === 'email', children: "Email me a code" })] }), import.meta.env.DEV ? (_jsxs(Button, { variant: "tertiary", size: "lg", disabled: isBusy, isPending: signIn.signingIn === 'dev', onClick: () => signIn.signInAsDevUser({ email: DEV_USER }), children: ["Dev: sign in as ", DEV_USER] })) : null] })) : (_jsxs(_Fragment, { children: [_jsxs(Text, { as: "p", tone: "secondary", align: "center", children: ["We sent a 6-digit code to ", signIn.email, "."] }), _jsxs(Form, { onSubmit: (values) => signIn.verifyEmailCode({ code: values['code'] ?? '' }), children: [_jsx(TextField, { name: "code", required: true, autoFocus: true, inputMode: "numeric", autoComplete: "one-time-code", pattern: "[0-9]{6}", maxLength: 6, placeholder: "123456", label: "Code", isLabelHidden: true, size: "lg" }), _jsx(Button, { type: "submit", size: "lg", disabled: isBusy, isPending: signIn.signingIn === 'email', children: "Sign in" })] }), _jsx(Button, { variant: "transparent", size: "lg", disabled: isBusy, onClick: signIn.startOver, children: "Use a different email" })] })), signIn.notice === null ? null : (_jsx(Text, { as: "p", tone: "secondary", align: "center", children: signIn.notice })), _jsx(Text, { as: "p", variant: "caption", tone: "tertiary", align: "center", children: "Sign-in by Pattern" })] }) }));
|
|
14
14
|
}
|
|
15
15
|
const DEV_USER = 'ada@acme.test';
|
|
16
16
|
const styles = stylex.create({
|
|
@@ -3,11 +3,12 @@ import { Switch as BaseSwitch } from '@base-ui/react/switch';
|
|
|
3
3
|
import * as stylex from '@stylexjs/stylex';
|
|
4
4
|
import { colors, lineHeights, motion, radii, space } from "../theme/tokens.stylex.js";
|
|
5
5
|
import { interact } from "./interaction.js";
|
|
6
|
+
import { focusRing } from "./controlLook.js";
|
|
6
7
|
export function Switch({ label, checked, disabled = false, onChange, style }) {
|
|
7
8
|
return (_jsx(BaseSwitch.Root, { "aria-label": label, checked: checked, disabled: disabled, onCheckedChange: (next) => {
|
|
8
9
|
interact({ primitive: 'Switch', event: 'change', label });
|
|
9
10
|
onChange(next);
|
|
10
|
-
}, className: (state) => stylex.props(styles.track, state.checked ? styles.on : styles.off, !disabled && (state.checked ? hovers.on : hovers.off), disabled && styles.disabled, style).className, children: _jsx(BaseSwitch.Thumb, { className: stylex.props(styles.thumb, disabled && styles.thumbDisabled).className }) }));
|
|
11
|
+
}, className: (state) => stylex.props(styles.track, state.checked ? styles.on : styles.off, !disabled && (state.checked ? hovers.on : hovers.off), disabled && styles.disabled, focusRing.visible, style).className, children: _jsx(BaseSwitch.Thumb, { className: stylex.props(styles.thumb, disabled && styles.thumbDisabled).className }) }));
|
|
11
12
|
}
|
|
12
13
|
const styles = stylex.create({
|
|
13
14
|
track: {
|
|
@@ -58,3 +58,13 @@ export declare const transparentLook: Readonly<{
|
|
|
58
58
|
readonly backgroundColor: stylex.StyleXClassNameFor<"backgroundColor", string>;
|
|
59
59
|
}>;
|
|
60
60
|
}>;
|
|
61
|
+
export declare const focusRing: Readonly<{
|
|
62
|
+
readonly visible: Readonly<{
|
|
63
|
+
readonly outlineWidth: stylex.StyleXClassNameFor<"outlineWidth", `calc(${stylex.StyleXVar<string>} + ${stylex.StyleXVar<string>})`>;
|
|
64
|
+
readonly outlineStyle: stylex.StyleXClassNameFor<"outlineStyle", "none" | "solid">;
|
|
65
|
+
readonly outlineColor: stylex.StyleXClassNameFor<"outlineColor", string>;
|
|
66
|
+
}>;
|
|
67
|
+
readonly inside: Readonly<{
|
|
68
|
+
readonly outlineOffset: stylex.StyleXClassNameFor<"outlineOffset", `calc(-1 * (${stylex.StyleXVar<string>} + ${stylex.StyleXVar<string>}))`>;
|
|
69
|
+
}>;
|
|
70
|
+
}>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as stylex from '@stylexjs/stylex';
|
|
2
|
-
import { colors, controls, fontSizes, lineHeights, motion, radii } from "../theme/tokens.stylex.js";
|
|
2
|
+
import { borders, colors, controls, fontSizes, lineHeights, motion, radii } from "../theme/tokens.stylex.js";
|
|
3
3
|
export const controlSizes = stylex.create({
|
|
4
4
|
xs: {
|
|
5
5
|
gap: controls.gapXs,
|
|
@@ -65,3 +65,16 @@ export const transparentLook = stylex.create({
|
|
|
65
65
|
backgroundColor: colors.transparentHover
|
|
66
66
|
}
|
|
67
67
|
});
|
|
68
|
+
export const focusRing = stylex.create({
|
|
69
|
+
visible: {
|
|
70
|
+
outlineWidth: `calc(${borders.thin} + ${borders.hairline})`,
|
|
71
|
+
outlineStyle: {
|
|
72
|
+
default: 'none',
|
|
73
|
+
':focus-visible': 'solid'
|
|
74
|
+
},
|
|
75
|
+
outlineColor: colors.brandBorderFocus
|
|
76
|
+
},
|
|
77
|
+
inside: {
|
|
78
|
+
outlineOffset: `calc(-1 * (${borders.thin} + ${borders.hairline}))`
|
|
79
|
+
}
|
|
80
|
+
});
|
|
@@ -6,9 +6,7 @@ type FilledDrawing = {
|
|
|
6
6
|
export type IconDrawing = string | readonly string[] | FilledDrawing;
|
|
7
7
|
export type IconName = keyof typeof builtInIcons | AppIconName;
|
|
8
8
|
declare const builtInIcons: {
|
|
9
|
-
home:
|
|
10
|
-
fill: string;
|
|
11
|
-
};
|
|
9
|
+
home: string[];
|
|
12
10
|
folder: string[];
|
|
13
11
|
settings: string[];
|
|
14
12
|
sun: {
|
|
@@ -40,6 +38,9 @@ declare const builtInIcons: {
|
|
|
40
38
|
enter: string;
|
|
41
39
|
arrowLeft: string;
|
|
42
40
|
arrowUp: string;
|
|
41
|
+
arrowUpRight: string;
|
|
42
|
+
circle: string;
|
|
43
|
+
copy: string[];
|
|
43
44
|
arrowDown: string;
|
|
44
45
|
logOut: string[];
|
|
45
46
|
};
|
package/dist/components/icons.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const builtInIcons = {
|
|
2
|
-
home:
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
home: [
|
|
3
|
+
'M14.25 20.25H18.25C19.3546 20.25 20.25 19.3546 20.25 18.25V9.90496C20.25 9.32928 20.0019 8.78149 19.5702 8.40225L13.3202 2.91021C12.5644 2.24604 11.4356 2.24604 10.6798 2.91021L4.42977 8.40225C3.99813 8.78149 3.75 9.32928 3.75 9.90496V18.25C3.75 19.3546 4.64543 20.25 5.75 20.25H9.75V16.75C9.75 15.6454 10.6454 14.75 11.75 14.75H12.25C13.3546 14.75 14.25 15.6454 14.25 16.75V20.25Z'
|
|
4
|
+
],
|
|
5
5
|
folder: [
|
|
6
6
|
'M9.13202 3.75H4.75C3.64543 3.75 2.75 4.64543 2.75 5.75V17.25C2.75 18.3546 3.64543 19.25 4.75 19.25H19.25C20.3546 19.25 21.25 18.3546 21.25 17.25V7.75C21.25 6.64543 20.3546 5.75 19.25 5.75H12.8124C12.2915 5.75 11.7911 5.54674 11.4177 5.18345L10.5267 4.31655C10.1534 3.95326 9.65297 3.75 9.13202 3.75Z',
|
|
7
7
|
'M2.75 12.75V11.75C2.75 10.6454 3.64543 9.75 4.75 9.75H19.25C20.3546 9.75 21.25 10.6454 21.25 11.75V12.75'
|
|
@@ -77,6 +77,12 @@ const builtInIcons = {
|
|
|
77
77
|
enter: 'M19 5v6.5a3 3 0 0 1-3 3H5.5M9 10.5l-4 4 4 4',
|
|
78
78
|
arrowLeft: 'M19 12H5M11 6l-6 6 6 6',
|
|
79
79
|
arrowUp: 'M12 19V5M6 11l6-6 6 6',
|
|
80
|
+
arrowUpRight: 'M7 17L17 7M8 7h9v9',
|
|
81
|
+
circle: 'M3.5 12a8.5 8.5 0 1 0 17 0a8.5 8.5 0 1 0 -17 0',
|
|
82
|
+
copy: [
|
|
83
|
+
'M10 9h8.5a1.5 1.5 0 0 1 1.5 1.5V19a1.5 1.5 0 0 1-1.5 1.5H10A1.5 1.5 0 0 1 8.5 19v-8.5A1.5 1.5 0 0 1 10 9z',
|
|
84
|
+
'M15.5 9V5.5A1.5 1.5 0 0 0 14 4H5.5A1.5 1.5 0 0 0 4 5.5V14a1.5 1.5 0 0 0 1.5 1.5H8.5'
|
|
85
|
+
],
|
|
80
86
|
arrowDown: 'M12 5v14M6 13l6 6 6-6',
|
|
81
87
|
logOut: [
|
|
82
88
|
'M14 4.5H7.5a2 2 0 0 0-2 2v11a2 2 0 0 0 2 2H14',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
export type Interaction = {
|
|
3
|
-
primitive: 'AppFrame' | 'Button' | 'IconButton' | 'Link' | 'ListRow' | 'Select' | 'Switch' | 'SegmentedControl' | 'Menu' | 'ContextMenu' | 'CommandMenu' | 'TextField' | 'Form' | 'Dialog';
|
|
3
|
+
primitive: 'AppFrame' | 'Button' | 'IconButton' | 'Link' | 'ListRow' | 'Select' | 'Switch' | 'SegmentedControl' | 'Menu' | 'ContextMenu' | 'CommandMenu' | 'TextField' | 'Form' | 'Dialog' | 'RadioGroup';
|
|
4
4
|
event: 'click' | 'change' | 'select' | 'open' | 'close' | 'submit' | 'navigate';
|
|
5
5
|
label: string;
|
|
6
6
|
page: string | null;
|
|
@@ -31,16 +31,27 @@ function idsOf(rows) {
|
|
|
31
31
|
return rows.map((row) => row.id);
|
|
32
32
|
}
|
|
33
33
|
export function accessFlows({ App }) {
|
|
34
|
-
if (inject('patternVisualFlows') !== undefined)
|
|
34
|
+
if (inject('patternVisualFlows') !== undefined) {
|
|
35
|
+
test.skip('Access flows run headless, in app test', () => undefined);
|
|
35
36
|
return;
|
|
36
|
-
|
|
37
|
+
}
|
|
38
|
+
const { tables, routes, services, memory } = App.definition;
|
|
37
39
|
const seed = (inject('patternSeed') ?? {});
|
|
38
40
|
const admins = inject('patternAdmins') ?? [];
|
|
41
|
+
const title = inject('patternTitle') ?? '';
|
|
39
42
|
const [admin] = admins;
|
|
40
43
|
async function started(signedInAs) {
|
|
41
44
|
const gate = new Gate();
|
|
42
45
|
const app = new App(createMemoryRouter(routeObjects(routes), { initialEntries: ['/'] }), {
|
|
43
|
-
api: memoryApi(tables, seed, {
|
|
46
|
+
api: memoryApi(tables, seed, {
|
|
47
|
+
gate,
|
|
48
|
+
signedInAs,
|
|
49
|
+
admins,
|
|
50
|
+
title,
|
|
51
|
+
world: structuredClone(inject('patternWorld') ?? {}),
|
|
52
|
+
...(services === undefined ? {} : { services }),
|
|
53
|
+
...(memory === undefined ? {} : { memory })
|
|
54
|
+
}),
|
|
44
55
|
cache: Cache.memory(),
|
|
45
56
|
gate
|
|
46
57
|
});
|
|
@@ -63,6 +74,11 @@ export function accessFlows({ App }) {
|
|
|
63
74
|
: []
|
|
64
75
|
};
|
|
65
76
|
}
|
|
77
|
+
if (Object.keys(tables).length === 0) {
|
|
78
|
+
test('Access: schema.ts has no tables yet, so there are no rules to check', () => {
|
|
79
|
+
expect(Object.keys(tables)).toEqual([]);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
66
82
|
for (const table of Object.values(tables)) {
|
|
67
83
|
const name = table.name;
|
|
68
84
|
const rows = seededRows(seed, name);
|
package/dist/flows/browser.d.ts
CHANGED
|
@@ -24,9 +24,11 @@ export type AppPage = {
|
|
|
24
24
|
snapshot: () => Promise<unknown>;
|
|
25
25
|
hold: (call: string) => Promise<void>;
|
|
26
26
|
release: (call: string) => Promise<void>;
|
|
27
|
+
tick: () => Promise<void>;
|
|
28
|
+
world: (patch: object) => Promise<void>;
|
|
27
29
|
reload: (path: string) => Promise<void>;
|
|
28
30
|
screenshot: (file: string) => Promise<void>;
|
|
29
31
|
captureAt: (viewport: ViewportName) => Promise<string>;
|
|
30
32
|
close: () => Promise<void>;
|
|
31
33
|
};
|
|
32
|
-
export declare function openApp(browser: Browser, baseUrl: string, path: string, viewport: ViewportName, signedInAs: string | null, seed?: object, admins?: readonly string[]): Promise<AppPage>;
|
|
34
|
+
export declare function openApp(browser: Browser, baseUrl: string, path: string, viewport: ViewportName, signedInAs: string | null, seed?: object, admins?: readonly string[], world?: unknown): Promise<AppPage>;
|
package/dist/flows/browser.js
CHANGED
|
@@ -81,7 +81,7 @@ function recordProblems(page, problems) {
|
|
|
81
81
|
}
|
|
82
82
|
});
|
|
83
83
|
}
|
|
84
|
-
export async function openApp(browser, baseUrl, path, viewport, signedInAs, seed, admins = []) {
|
|
84
|
+
export async function openApp(browser, baseUrl, path, viewport, signedInAs, seed, admins = [], world = {}) {
|
|
85
85
|
const { width, height, deviceScaleFactor } = viewports[viewport];
|
|
86
86
|
const context = await browser.newContext({
|
|
87
87
|
viewport: { width, height },
|
|
@@ -99,9 +99,10 @@ export async function openApp(browser, baseUrl, path, viewport, signedInAs, seed
|
|
|
99
99
|
await context.addInitScript((value) => {
|
|
100
100
|
Object.assign(globalThis, {
|
|
101
101
|
patternSeed: value.seed,
|
|
102
|
-
patternAdmins: value.admins
|
|
102
|
+
patternAdmins: value.admins,
|
|
103
|
+
patternWorld: value.world
|
|
103
104
|
});
|
|
104
|
-
}, { seed, admins });
|
|
105
|
+
}, { seed, admins, world });
|
|
105
106
|
}
|
|
106
107
|
const page = await context.newPage();
|
|
107
108
|
const problems = [];
|
|
@@ -142,6 +143,8 @@ export async function openApp(browser, baseUrl, path, viewport, signedInAs, seed
|
|
|
142
143
|
snapshot,
|
|
143
144
|
hold: (call) => page.evaluate((held) => globalThis.pattern.hold(held), call),
|
|
144
145
|
release: (call) => page.evaluate((released) => globalThis.pattern.release(released), call),
|
|
146
|
+
tick: () => page.evaluate(() => globalThis.pattern.tick()),
|
|
147
|
+
world: (patch) => page.evaluate((changed) => globalThis.pattern.world(changed), patch),
|
|
145
148
|
reload: load,
|
|
146
149
|
screenshot: async (file) => {
|
|
147
150
|
await settle();
|
|
@@ -11,11 +11,13 @@ declare module 'vitest' {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
export declare function closeFlowBrowser(): Promise<void>;
|
|
14
|
-
export declare function openFlowPage(settings: VisualFlowSettings, viewport: ViewportName, startAt: string, signedInAs: string | null, seed: object, admins: readonly string[]): Promise<{
|
|
14
|
+
export declare function openFlowPage(settings: VisualFlowSettings, viewport: ViewportName, startAt: string, signedInAs: string | null, seed: object, admins: readonly string[], world: unknown): Promise<{
|
|
15
15
|
send: (command: unknown) => Promise<void>;
|
|
16
16
|
snapshot: () => Promise<unknown>;
|
|
17
17
|
hold: (call: string) => Promise<void>;
|
|
18
18
|
release: (call: string) => Promise<void>;
|
|
19
|
+
tick: () => Promise<void>;
|
|
20
|
+
world: (patch: object) => Promise<void>;
|
|
19
21
|
reload: (path: string) => Promise<void>;
|
|
20
22
|
screenshot: (name: string) => Promise<void>;
|
|
21
23
|
problems: string[];
|
|
@@ -5,14 +5,16 @@ export async function closeFlowBrowser() {
|
|
|
5
5
|
browser = undefined;
|
|
6
6
|
await (await connected)?.close();
|
|
7
7
|
}
|
|
8
|
-
export async function openFlowPage(settings, viewport, startAt, signedInAs, seed, admins) {
|
|
8
|
+
export async function openFlowPage(settings, viewport, startAt, signedInAs, seed, admins, world) {
|
|
9
9
|
browser ??= connectChrome(settings.wsEndpoint);
|
|
10
|
-
const app = await openApp(await browser, settings.url, startAt, viewport, signedInAs, seed, admins);
|
|
10
|
+
const app = await openApp(await browser, settings.url, startAt, viewport, signedInAs, seed, admins, world);
|
|
11
11
|
return {
|
|
12
12
|
send: app.dispatch,
|
|
13
13
|
snapshot: app.snapshot,
|
|
14
14
|
hold: app.hold,
|
|
15
15
|
release: app.release,
|
|
16
|
+
tick: app.tick,
|
|
17
|
+
world: app.world,
|
|
16
18
|
reload: app.reload,
|
|
17
19
|
screenshot: (name) => app.screenshot(`${settings.directory}/${name}-${viewport}.png`),
|
|
18
20
|
problems: app.problems,
|
package/dist/flows/flows.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ declare module 'vitest' {
|
|
|
8
8
|
interface ProvidedContext {
|
|
9
9
|
patternSeed?: Seed<Tables>;
|
|
10
10
|
patternAdmins?: readonly string[];
|
|
11
|
+
patternTitle?: string;
|
|
12
|
+
patternWorld?: unknown;
|
|
11
13
|
}
|
|
12
14
|
}
|
|
13
15
|
type Expected<Value> = Value extends readonly (infer Item)[] ? readonly Expected<Item>[] : Value extends object ? {
|
|
@@ -25,6 +27,10 @@ export type FlowStep<Command, Snapshot, Call extends string> = {
|
|
|
25
27
|
release: Call;
|
|
26
28
|
} | {
|
|
27
29
|
restart: true;
|
|
30
|
+
} | {
|
|
31
|
+
tick: true;
|
|
32
|
+
} | {
|
|
33
|
+
world: object;
|
|
28
34
|
};
|
|
29
35
|
export type FlowOptions<Call extends string> = {
|
|
30
36
|
startAt?: string;
|