@trypattern/sdk 0.1.11 → 0.1.13
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 +73 -12
- package/dist/access.d.ts +0 -4
- package/dist/access.js +0 -5
- package/dist/api.d.ts +3 -1
- package/dist/api.js +5 -17
- package/dist/app.d.ts +20 -5
- package/dist/app.js +32 -2
- package/dist/blocks.d.ts +18 -0
- package/dist/blocks.js +36 -0
- package/dist/bookings.d.ts +400 -0
- package/dist/bookings.js +300 -0
- package/dist/bookingsMemory.d.ts +9 -0
- package/dist/bookingsMemory.js +79 -0
- package/dist/bookingsStore.d.ts +698 -0
- package/dist/bookingsStore.js +129 -0
- package/dist/cli/app.js +143 -59
- package/dist/cli/publishing.d.ts +3 -1
- package/dist/cli/publishing.js +33 -5
- package/dist/cli/starter.d.ts +17 -0
- package/dist/cli/starter.js +140 -0
- package/dist/components/Button.d.ts +2 -24
- package/dist/components/Button.js +4 -251
- package/dist/components/ButtonBody.d.ts +25 -0
- package/dist/components/ButtonBody.js +266 -0
- package/dist/components/Calendar.d.ts +20 -0
- package/dist/components/Calendar.js +195 -0
- package/dist/components/Card.d.ts +1 -1
- package/dist/components/Card.js +7 -29
- package/dist/components/Choice.js +27 -13
- package/dist/components/ChoiceGroup.d.ts +3 -1
- package/dist/components/ChoiceGroup.js +3 -4
- package/dist/components/ContinueWithGoogle.d.ts +11 -0
- package/dist/components/ContinueWithGoogle.js +5 -0
- package/dist/components/Dialog.d.ts +1 -1
- package/dist/components/Dialog.js +3 -1
- package/dist/components/Icon.js +1 -1
- package/dist/components/ListRow.js +2 -1
- package/dist/components/RadioGroup.d.ts +2 -1
- package/dist/components/RadioGroup.js +10 -2
- package/dist/components/Text.d.ts +1 -1
- package/dist/components/Text.js +43 -2
- package/dist/components/calendarDates.d.ts +14 -0
- package/dist/components/calendarDates.js +84 -0
- package/dist/components/controlLook.js +11 -11
- package/dist/components/icons.d.ts +9 -0
- package/dist/components/icons.js +17 -1
- package/dist/components/interaction.d.ts +1 -1
- package/dist/flows/browser.d.ts +7 -1
- package/dist/flows/browser.js +25 -7
- package/dist/flows/flowBrowser.d.ts +2 -2
- package/dist/flows/flowBrowser.js +2 -2
- package/dist/flows/flows.js +8 -2
- package/dist/index.d.ts +4 -1
- package/dist/index.js +1 -0
- package/dist/media.d.ts +11 -1
- package/dist/patternAccess.d.ts +11 -2
- package/dist/patternAccess.js +8 -4
- package/dist/publishWire.d.ts +24 -2
- package/dist/publishWire.js +22 -2
- package/dist/react.d.ts +3 -0
- package/dist/react.js +2 -0
- package/dist/rules/checkAllFiles.js +16 -2
- package/dist/rules/lintPlugin.js +1 -0
- package/dist/schema.d.ts +3 -1
- package/dist/schema.js +1 -0
- package/dist/server/bookings.d.ts +12 -0
- package/dist/server/bookings.js +142 -0
- package/dist/server/createServer.d.ts +3 -2
- package/dist/server/createServer.js +13 -4
- package/dist/server/env.d.ts +8 -0
- package/dist/server/index.d.ts +3 -1
- package/dist/server/index.js +1 -0
- package/dist/server/media.d.ts +16 -3
- package/dist/server/media.js +72 -23
- package/dist/server/patternViewer.js +16 -10
- package/dist/server/tables.d.ts +2 -0
- package/dist/server/tables.js +17 -1
- package/dist/start.js +12 -0
- package/dist/table.js +9 -3
- package/dist/theme/scales.d.ts +1 -1
- package/dist/theme/scales.js +1 -0
- package/dist/theme/tokens.stylex.d.ts +18 -0
- package/dist/theme/tokens.stylex.js +19 -1
- package/dist/vite/localWorker.d.ts +2 -0
- package/dist/vite/localWorker.js +48 -3
- package/dist/vite/vite.js +5 -1
- package/package.json +1 -1
|
@@ -2,10 +2,10 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { RadioGroup as BaseRadioGroup } from '@base-ui/react/radio-group';
|
|
3
3
|
import * as stylex from '@stylexjs/stylex';
|
|
4
4
|
import { Children, isValidElement } from 'react';
|
|
5
|
-
import { space } from "../theme/tokens.stylex.js";
|
|
6
5
|
import { ChoiceContext } from "./choiceContext.js";
|
|
7
6
|
import { interact, textOf } from "./interaction.js";
|
|
8
|
-
|
|
7
|
+
import { gaps } from "./spacing.js";
|
|
8
|
+
export function ChoiceGroup({ label, value, onChange, children, gap = 'sm', style }) {
|
|
9
9
|
return (_jsx(ChoiceContext, { value: { value }, children: _jsx(BaseRadioGroup, { "aria-label": label, value: value, onValueChange: (next) => {
|
|
10
10
|
if (typeof next !== 'string')
|
|
11
11
|
return;
|
|
@@ -15,7 +15,7 @@ export function ChoiceGroup({ label, value, onChange, children, style }) {
|
|
|
15
15
|
label: labelOf(children, next)
|
|
16
16
|
});
|
|
17
17
|
onChange(next);
|
|
18
|
-
}, className: stylex.props(styles.group, style).className, children: children }) }));
|
|
18
|
+
}, className: stylex.props(styles.group, gaps[gap], style).className, children: children }) }));
|
|
19
19
|
}
|
|
20
20
|
function labelOf(children, value) {
|
|
21
21
|
for (const child of Children.toArray(children)) {
|
|
@@ -37,7 +37,6 @@ const styles = stylex.create({
|
|
|
37
37
|
group: {
|
|
38
38
|
display: 'flex',
|
|
39
39
|
flexWrap: 'wrap',
|
|
40
|
-
gap: space.sm,
|
|
41
40
|
alignItems: 'stretch',
|
|
42
41
|
minWidth: 0
|
|
43
42
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Placement } from './Placement.ts';
|
|
2
|
+
import type { Size } from './Size.ts';
|
|
3
|
+
type ContinueWithGoogleProps = {
|
|
4
|
+
onClick: () => void;
|
|
5
|
+
size?: Size;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
isPending?: boolean;
|
|
8
|
+
style?: Placement;
|
|
9
|
+
};
|
|
10
|
+
export declare function ContinueWithGoogle({ onClick, size, disabled, isPending, style }: ContinueWithGoogleProps): import("react").JSX.Element;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { ButtonBody } from "./ButtonBody.js";
|
|
3
|
+
export function ContinueWithGoogle({ onClick, size = 'md', disabled = false, isPending = false, style }) {
|
|
4
|
+
return (_jsx(ButtonBody, { variant: "secondary", icon: "google", isIconPinned: true, size: size, disabled: disabled, isPending: isPending, onClick: onClick, ...(style === undefined ? {} : { style }), children: "Continue with Google" }));
|
|
5
|
+
}
|
|
@@ -4,7 +4,7 @@ type DialogProps = {
|
|
|
4
4
|
isOpen: boolean;
|
|
5
5
|
onOpenChange: (isOpen: boolean) => void;
|
|
6
6
|
placement?: 'center' | 'top';
|
|
7
|
-
size?: 'sm' | 'md' | 'lg';
|
|
7
|
+
size?: 'sm' | 'md' | 'lg' | 'xl';
|
|
8
8
|
children: ReactNode;
|
|
9
9
|
};
|
|
10
10
|
export declare function Dialog({ label, isOpen, onOpenChange, placement, size, children }: DialogProps): import("react").JSX.Element;
|
|
@@ -45,6 +45,7 @@ const styles = stylex.create({
|
|
|
45
45
|
frame: {
|
|
46
46
|
display: 'flex',
|
|
47
47
|
flexDirection: 'column',
|
|
48
|
+
maxHeight: 'calc(100dvh - 2rem)',
|
|
48
49
|
overflow: 'hidden',
|
|
49
50
|
color: colors.primaryForeground,
|
|
50
51
|
backgroundColor: colors.componentOnSunken,
|
|
@@ -77,5 +78,6 @@ const hiddenPlacements = stylex.create({
|
|
|
77
78
|
const widths = stylex.create({
|
|
78
79
|
sm: { maxWidth: 'min(400px, calc(100% - 2rem))' },
|
|
79
80
|
md: { maxWidth: 'min(560px, calc(100% - 2rem))' },
|
|
80
|
-
lg: { maxWidth: 'min(720px, calc(100% - 2rem))' }
|
|
81
|
+
lg: { maxWidth: 'min(720px, calc(100% - 2rem))' },
|
|
82
|
+
xl: { maxWidth: 'min(800px, calc(100% - 2rem))' }
|
|
81
83
|
});
|
package/dist/components/Icon.js
CHANGED
|
@@ -5,7 +5,7 @@ import { shapeOf } from "./icons.js";
|
|
|
5
5
|
import { tones } from "./tones.js";
|
|
6
6
|
export function Icon({ name, size = 'md', tone = 'inherit', weight = 'regular' }) {
|
|
7
7
|
const shape = shapeOf(name);
|
|
8
|
-
return (_jsx("svg", { viewBox: "0 0 24 24", fill: shape.isFilled ? 'currentColor' : 'none', fillRule: shape.rule, stroke: shape.isFilled ? 'none' : 'currentColor', strokeWidth: weight === 'light' ? '1.5' : '2', strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", ...stylex.props(styles.icon, sizes[size], tones[tone]), children: shape.paths.map((path) => (_jsx("path", { d: path }, path))) }));
|
|
8
|
+
return (_jsx("svg", { viewBox: "0 0 24 24", fill: shape.isFilled ? 'currentColor' : 'none', fillRule: shape.rule, stroke: shape.isFilled ? 'none' : 'currentColor', strokeWidth: weight === 'light' ? '1.5' : '2', strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", ...stylex.props(styles.icon, sizes[size], tones[tone]), children: shape.paths.map((path, index) => (_jsx("path", { d: path, fill: shape.colors?.[index] }, path))) }));
|
|
9
9
|
}
|
|
10
10
|
const styles = stylex.create({
|
|
11
11
|
icon: {
|
|
@@ -7,7 +7,8 @@ import { focusRing } from "./controlLook.js";
|
|
|
7
7
|
import { interact, textOf } from "./interaction.js";
|
|
8
8
|
export function ListRow({ to, href, onClick, isMuted = false, isCurrent = false, size = 'md', leading, trailing, children }) {
|
|
9
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 }))] }));
|
|
10
|
-
const look = stylex.props(styles.row,
|
|
10
|
+
const look = stylex.props(styles.row, size === 'sm' &&
|
|
11
|
+
(to !== undefined || href !== undefined || onClick !== undefined) &&
|
|
11
12
|
styles.interactive, isMuted && styles.muted, isCurrent && styles.current, size === 'sm' && styles.small, size === 'lg' && styles.large, focusRing.visible, focusRing.inside);
|
|
12
13
|
const report = () => {
|
|
13
14
|
interact({
|
|
@@ -12,7 +12,8 @@ type RadioGroupProps<Value extends string> = {
|
|
|
12
12
|
value: Value | null;
|
|
13
13
|
options: readonly RadioOption<Value>[];
|
|
14
14
|
onChange: (value: Value) => void;
|
|
15
|
+
size?: 'md' | 'lg';
|
|
15
16
|
style?: Placement;
|
|
16
17
|
};
|
|
17
|
-
export declare function RadioGroup<Value extends string>({ label, value, options, onChange, style }: RadioGroupProps<Value>): import("react").JSX.Element;
|
|
18
|
+
export declare function RadioGroup<Value extends string>({ label, value, options, onChange, size, style }: RadioGroupProps<Value>): import("react").JSX.Element;
|
|
18
19
|
export {};
|
|
@@ -6,7 +6,7 @@ import { borders, colors, iconSizes, motion, radii, shadows, space } from "../th
|
|
|
6
6
|
import { focusRing } from "./controlLook.js";
|
|
7
7
|
import { interact } from "./interaction.js";
|
|
8
8
|
import { Text } from "./Text.js";
|
|
9
|
-
export function RadioGroup({ label, value, options, onChange, style }) {
|
|
9
|
+
export function RadioGroup({ label, value, options, onChange, size = 'md', style }) {
|
|
10
10
|
return (_jsx(BaseRadioGroup, { "aria-label": label, value: value, onValueChange: (next) => {
|
|
11
11
|
const chosen = options.find((option) => option.value === next);
|
|
12
12
|
if (chosen === undefined)
|
|
@@ -17,7 +17,8 @@ export function RadioGroup({ label, value, options, onChange, style }) {
|
|
|
17
17
|
label: chosen.label
|
|
18
18
|
});
|
|
19
19
|
onChange(chosen.value);
|
|
20
|
-
}, className: stylex.props(styles.group,
|
|
20
|
+
}, className: stylex.props(styles.group, size === 'lg' && styles.groupLarge, style)
|
|
21
|
+
.className, children: options.map((option) => (_jsxs("label", { ...stylex.props(styles.row, size === 'lg' && styles.rowLarge, 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, { variant: size === 'lg' ? 'lead' : 'body', 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
|
}
|
|
22
23
|
const styles = stylex.create({
|
|
23
24
|
group: {
|
|
@@ -42,6 +43,13 @@ const styles = stylex.create({
|
|
|
42
43
|
},
|
|
43
44
|
borderTopWidth: borders.hairline
|
|
44
45
|
},
|
|
46
|
+
groupLarge: {
|
|
47
|
+
borderRadius: radii.xxl
|
|
48
|
+
},
|
|
49
|
+
rowLarge: {
|
|
50
|
+
paddingBlock: space.lg,
|
|
51
|
+
paddingInline: `calc(${space.md} + ${space.xxs})`
|
|
52
|
+
},
|
|
45
53
|
rowDisabled: {
|
|
46
54
|
color: colors.tertiaryForeground
|
|
47
55
|
},
|
|
@@ -3,7 +3,7 @@ import type { Placement } from './Placement.ts';
|
|
|
3
3
|
import type { Tone } from './tones.ts';
|
|
4
4
|
type TextProps = {
|
|
5
5
|
children: ReactNode;
|
|
6
|
-
variant?: 'heading' | 'subheading' | 'title' | 'lead' | 'label' | 'body' | 'caption' | 'code';
|
|
6
|
+
variant?: 'hero' | 'display' | 'section' | 'heading' | 'subheading' | 'title' | 'lead' | 'intro' | 'label' | 'body' | 'caption' | 'code';
|
|
7
7
|
tone?: Tone;
|
|
8
8
|
align?: 'start' | 'center' | 'end';
|
|
9
9
|
as?: 'span' | 'p' | 'h1' | 'h2' | 'h3';
|
package/dist/components/Text.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as stylex from '@stylexjs/stylex';
|
|
2
2
|
import { createElement } from 'react';
|
|
3
|
-
import { breakpoints, fontSizes, fontWeights, fonts, lineHeights } from "../theme/tokens.stylex.js";
|
|
3
|
+
import { breakpoints, fontSizes, fontWeights, fonts, lineHeights, trackings } from "../theme/tokens.stylex.js";
|
|
4
4
|
import { tones } from "./tones.js";
|
|
5
5
|
export function Text({ children, variant = 'body', tone = 'inherit', align, as = 'span', isTruncated = false, isSelectable = false, style }) {
|
|
6
6
|
return createElement(as, stylex.props(as !== 'span' && styles.block, variants[variant], tones[tone], align !== undefined && alignments[align], isTruncated && styles.truncated, isSelectable && styles.selectable, style), children);
|
|
@@ -21,11 +21,47 @@ const styles = stylex.create({
|
|
|
21
21
|
}
|
|
22
22
|
});
|
|
23
23
|
const variants = stylex.create({
|
|
24
|
+
hero: {
|
|
25
|
+
fontSize: {
|
|
26
|
+
default: fontSizes.heading1,
|
|
27
|
+
[breakpoints.compact]: fontSizes.heading2
|
|
28
|
+
},
|
|
29
|
+
fontWeight: fontWeights.medium,
|
|
30
|
+
lineHeight: {
|
|
31
|
+
default: lineHeights.heading1,
|
|
32
|
+
[breakpoints.compact]: lineHeights.heading2
|
|
33
|
+
},
|
|
34
|
+
letterSpacing: trackings.hero
|
|
35
|
+
},
|
|
36
|
+
display: {
|
|
37
|
+
fontSize: {
|
|
38
|
+
default: fontSizes.heading2,
|
|
39
|
+
[breakpoints.compact]: fontSizes.heading3
|
|
40
|
+
},
|
|
41
|
+
fontWeight: fontWeights.medium,
|
|
42
|
+
lineHeight: {
|
|
43
|
+
default: lineHeights.heading2,
|
|
44
|
+
[breakpoints.compact]: lineHeights.heading3
|
|
45
|
+
},
|
|
46
|
+
letterSpacing: trackings.display
|
|
47
|
+
},
|
|
48
|
+
section: {
|
|
49
|
+
fontSize: {
|
|
50
|
+
default: fontSizes.heading3,
|
|
51
|
+
[breakpoints.compact]: fontSizes.heading5
|
|
52
|
+
},
|
|
53
|
+
fontWeight: fontWeights.medium,
|
|
54
|
+
lineHeight: {
|
|
55
|
+
default: lineHeights.heading3,
|
|
56
|
+
[breakpoints.compact]: lineHeights.heading5
|
|
57
|
+
},
|
|
58
|
+
letterSpacing: trackings.section
|
|
59
|
+
},
|
|
24
60
|
heading: {
|
|
25
61
|
fontSize: fontSizes.heading5,
|
|
26
62
|
fontWeight: fontWeights.medium,
|
|
27
63
|
lineHeight: lineHeights.heading5,
|
|
28
|
-
letterSpacing:
|
|
64
|
+
letterSpacing: trackings.heading
|
|
29
65
|
},
|
|
30
66
|
subheading: {
|
|
31
67
|
fontSize: fontSizes.heading6,
|
|
@@ -42,6 +78,11 @@ const variants = stylex.create({
|
|
|
42
78
|
fontWeight: fontWeights.normal,
|
|
43
79
|
lineHeight: lineHeights.body
|
|
44
80
|
},
|
|
81
|
+
intro: {
|
|
82
|
+
fontSize: fontSizes.bodyLg,
|
|
83
|
+
fontWeight: fontWeights.normal,
|
|
84
|
+
lineHeight: lineHeights.bodyLg
|
|
85
|
+
},
|
|
45
86
|
label: {
|
|
46
87
|
fontSize: {
|
|
47
88
|
default: fontSizes.bodySm,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function monthOf(date: string): string;
|
|
2
|
+
export declare function addDays(date: string, days: number): string;
|
|
3
|
+
export declare function addMonths(date: string, months: number): string;
|
|
4
|
+
export declare function daysIn(month: string): number;
|
|
5
|
+
export declare function weekdayIndex(date: string): number;
|
|
6
|
+
export declare function weeksOf(month: string): readonly (readonly (string | null)[])[];
|
|
7
|
+
export declare function localToday(): string;
|
|
8
|
+
export declare function monthTitle(month: string, locale: string | undefined): string;
|
|
9
|
+
export declare function dayLabel(date: string, locale: string | undefined): string;
|
|
10
|
+
export declare function dayNumber(date: string, locale: string | undefined): string;
|
|
11
|
+
export declare function weekdayNames(locale: string | undefined): readonly {
|
|
12
|
+
short: string;
|
|
13
|
+
long: string;
|
|
14
|
+
}[];
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
2
|
+
function utc(date) {
|
|
3
|
+
return new Date(`${date}T00:00:00Z`);
|
|
4
|
+
}
|
|
5
|
+
function isoDate(time) {
|
|
6
|
+
return new Date(time).toISOString().slice(0, 10);
|
|
7
|
+
}
|
|
8
|
+
export function monthOf(date) {
|
|
9
|
+
return date.slice(0, 7);
|
|
10
|
+
}
|
|
11
|
+
export function addDays(date, days) {
|
|
12
|
+
return isoDate(utc(date).getTime() + days * DAY_MS);
|
|
13
|
+
}
|
|
14
|
+
export function addMonths(date, months) {
|
|
15
|
+
const start = utc(date);
|
|
16
|
+
const year = start.getUTCFullYear();
|
|
17
|
+
const month = start.getUTCMonth() + months;
|
|
18
|
+
const last = new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
|
|
19
|
+
return isoDate(Date.UTC(year, month, Math.min(start.getUTCDate(), last)));
|
|
20
|
+
}
|
|
21
|
+
export function daysIn(month) {
|
|
22
|
+
const start = utc(`${month}-01`);
|
|
23
|
+
return new Date(Date.UTC(start.getUTCFullYear(), start.getUTCMonth() + 1, 0)).getUTCDate();
|
|
24
|
+
}
|
|
25
|
+
export function weekdayIndex(date) {
|
|
26
|
+
return (utc(date).getUTCDay() + 6) % 7;
|
|
27
|
+
}
|
|
28
|
+
export function weeksOf(month) {
|
|
29
|
+
const first = `${month}-01`;
|
|
30
|
+
const cells = [
|
|
31
|
+
...Array.from({ length: weekdayIndex(first) }, () => null),
|
|
32
|
+
...Array.from({ length: daysIn(month) }, (_, index) => addDays(first, index))
|
|
33
|
+
];
|
|
34
|
+
const weeks = [];
|
|
35
|
+
for (let index = 0; index < cells.length; index += 7) {
|
|
36
|
+
weeks.push(cells.slice(index, index + 7));
|
|
37
|
+
}
|
|
38
|
+
return weeks;
|
|
39
|
+
}
|
|
40
|
+
export function localToday() {
|
|
41
|
+
const now = new Date();
|
|
42
|
+
return [
|
|
43
|
+
String(now.getFullYear()).padStart(4, '0'),
|
|
44
|
+
String(now.getMonth() + 1).padStart(2, '0'),
|
|
45
|
+
String(now.getDate()).padStart(2, '0')
|
|
46
|
+
].join('-');
|
|
47
|
+
}
|
|
48
|
+
export function monthTitle(month, locale) {
|
|
49
|
+
return new Intl.DateTimeFormat(locale, {
|
|
50
|
+
month: 'long',
|
|
51
|
+
year: 'numeric',
|
|
52
|
+
timeZone: 'UTC'
|
|
53
|
+
}).format(utc(`${month}-01`));
|
|
54
|
+
}
|
|
55
|
+
export function dayLabel(date, locale) {
|
|
56
|
+
return new Intl.DateTimeFormat(locale, {
|
|
57
|
+
dateStyle: 'full',
|
|
58
|
+
timeZone: 'UTC'
|
|
59
|
+
}).format(utc(date));
|
|
60
|
+
}
|
|
61
|
+
export function dayNumber(date, locale) {
|
|
62
|
+
return new Intl.DateTimeFormat(locale, {
|
|
63
|
+
day: 'numeric',
|
|
64
|
+
timeZone: 'UTC'
|
|
65
|
+
}).format(utc(date));
|
|
66
|
+
}
|
|
67
|
+
export function weekdayNames(locale) {
|
|
68
|
+
const monday = '2024-01-01';
|
|
69
|
+
const short = new Intl.DateTimeFormat(locale, {
|
|
70
|
+
weekday: 'short',
|
|
71
|
+
timeZone: 'UTC'
|
|
72
|
+
});
|
|
73
|
+
const long = new Intl.DateTimeFormat(locale, {
|
|
74
|
+
weekday: 'long',
|
|
75
|
+
timeZone: 'UTC'
|
|
76
|
+
});
|
|
77
|
+
return Array.from({ length: 7 }, (_, index) => {
|
|
78
|
+
const day = utc(addDays(monday, index));
|
|
79
|
+
return {
|
|
80
|
+
short: [...short.format(day)].slice(0, 2).join(''),
|
|
81
|
+
long: long.format(day)
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
}
|
|
@@ -1,44 +1,44 @@
|
|
|
1
1
|
import * as stylex from '@stylexjs/stylex';
|
|
2
|
-
import { borders, colors, controls,
|
|
2
|
+
import { borders, colors, controls, motion, radii } from "../theme/tokens.stylex.js";
|
|
3
3
|
export const controlSizes = stylex.create({
|
|
4
4
|
xs: {
|
|
5
5
|
gap: controls.gapXs,
|
|
6
6
|
height: controls.heightXs,
|
|
7
7
|
paddingInline: controls.paddingXs,
|
|
8
|
-
fontSize:
|
|
9
|
-
lineHeight:
|
|
8
|
+
fontSize: controls.fontSizeXs,
|
|
9
|
+
lineHeight: controls.lineHeightXs,
|
|
10
10
|
borderRadius: radii.sm
|
|
11
11
|
},
|
|
12
12
|
sm: {
|
|
13
13
|
gap: controls.gapSm,
|
|
14
14
|
height: controls.heightSm,
|
|
15
15
|
paddingInline: controls.paddingSm,
|
|
16
|
-
fontSize:
|
|
17
|
-
lineHeight:
|
|
16
|
+
fontSize: controls.fontSizeSm,
|
|
17
|
+
lineHeight: controls.lineHeightSm,
|
|
18
18
|
borderRadius: radii.md
|
|
19
19
|
},
|
|
20
20
|
md: {
|
|
21
21
|
gap: controls.gapMd,
|
|
22
22
|
height: controls.heightMd,
|
|
23
23
|
paddingInline: controls.paddingMd,
|
|
24
|
-
fontSize:
|
|
25
|
-
lineHeight:
|
|
24
|
+
fontSize: controls.fontSizeMd,
|
|
25
|
+
lineHeight: controls.lineHeightMd,
|
|
26
26
|
borderRadius: radii.md
|
|
27
27
|
},
|
|
28
28
|
lg: {
|
|
29
29
|
gap: controls.gapLg,
|
|
30
30
|
height: controls.heightLg,
|
|
31
31
|
paddingInline: controls.paddingLg,
|
|
32
|
-
fontSize:
|
|
33
|
-
lineHeight:
|
|
32
|
+
fontSize: controls.fontSizeLg,
|
|
33
|
+
lineHeight: controls.lineHeightLg,
|
|
34
34
|
borderRadius: radii.lg
|
|
35
35
|
},
|
|
36
36
|
xl: {
|
|
37
37
|
gap: controls.gapXl,
|
|
38
38
|
height: controls.heightXl,
|
|
39
39
|
paddingInline: controls.paddingXl,
|
|
40
|
-
fontSize:
|
|
41
|
-
lineHeight:
|
|
40
|
+
fontSize: controls.fontSizeXl,
|
|
41
|
+
lineHeight: controls.lineHeightXl,
|
|
42
42
|
borderRadius: radii.lg
|
|
43
43
|
}
|
|
44
44
|
});
|
|
@@ -2,6 +2,7 @@ import type { AppIconName } from '../registered.ts';
|
|
|
2
2
|
type FilledDrawing = {
|
|
3
3
|
readonly fill: string | readonly string[];
|
|
4
4
|
readonly rule?: 'evenodd';
|
|
5
|
+
readonly colors?: readonly string[];
|
|
5
6
|
};
|
|
6
7
|
export type IconDrawing = string | readonly string[] | FilledDrawing;
|
|
7
8
|
export type IconName = keyof typeof builtInIcons | AppIconName;
|
|
@@ -12,6 +13,10 @@ declare const builtInIcons: {
|
|
|
12
13
|
sun: {
|
|
13
14
|
fill: string[];
|
|
14
15
|
};
|
|
16
|
+
google: {
|
|
17
|
+
fill: string[];
|
|
18
|
+
colors: string[];
|
|
19
|
+
};
|
|
15
20
|
moon: {
|
|
16
21
|
fill: string;
|
|
17
22
|
};
|
|
@@ -28,6 +33,8 @@ declare const builtInIcons: {
|
|
|
28
33
|
alertCircle: string[];
|
|
29
34
|
chevronDown: string;
|
|
30
35
|
chevronRight: string;
|
|
36
|
+
previous: string;
|
|
37
|
+
next: string;
|
|
31
38
|
search: string[];
|
|
32
39
|
panelLeft: string[];
|
|
33
40
|
more: {
|
|
@@ -54,9 +61,11 @@ export declare function shapeOf(name: IconName): {
|
|
|
54
61
|
paths: readonly string[];
|
|
55
62
|
isFilled: boolean;
|
|
56
63
|
rule?: never;
|
|
64
|
+
colors?: never;
|
|
57
65
|
} | {
|
|
58
66
|
paths: string[];
|
|
59
67
|
isFilled: boolean;
|
|
60
68
|
rule: "evenodd" | undefined;
|
|
69
|
+
colors: readonly string[] | undefined;
|
|
61
70
|
};
|
|
62
71
|
export {};
|
package/dist/components/icons.js
CHANGED
|
@@ -23,6 +23,15 @@ const builtInIcons = {
|
|
|
23
23
|
'M7.75736 7.75736C10.1005 5.41421 13.8995 5.41421 16.2426 7.75736C18.5858 10.1005 18.5858 13.8995 16.2426 16.2426C13.8995 18.5858 10.1005 18.5858 7.75736 16.2426C5.41421 13.8995 5.41421 10.1005 7.75736 7.75736Z'
|
|
24
24
|
]
|
|
25
25
|
},
|
|
26
|
+
google: {
|
|
27
|
+
fill: [
|
|
28
|
+
'M22.5 12.3c0-.8-.1-1.5-.2-2.2H12v4.2h5.9a5 5 0 0 1-2.2 3.3v2.7h3.5c2.1-1.9 3.3-4.7 3.3-8z',
|
|
29
|
+
'M12 23c3 0 5.5-1 7.3-2.7l-3.5-2.7c-1 .7-2.3 1.1-3.8 1.1-2.9 0-5.4-2-6.3-4.7H2.1v2.8A11 11 0 0 0 12 23z',
|
|
30
|
+
'M5.7 14c-.2-.7-.4-1.4-.4-2s.1-1.4.4-2V7.2H2.1a11 11 0 0 0 0 9.7L5.7 14z',
|
|
31
|
+
'M12 5.4c1.6 0 3.1.6 4.2 1.7l3.1-3.1A11 11 0 0 0 2.1 7.2L5.7 10c.9-2.7 3.4-4.6 6.3-4.6z'
|
|
32
|
+
],
|
|
33
|
+
colors: ['#4285F4', '#34A853', '#FBBC05', '#EA4335']
|
|
34
|
+
},
|
|
26
35
|
moon: {
|
|
27
36
|
fill: 'M12.0517 3.59971C12.2712 3.28123 12.2873 2.86472 12.0931 2.53021C11.8989 2.19569 11.5292 2.00315 11.1438 2.03581C6.0214 2.46985 2 6.76372 2 11.9979C2 17.5197 6.47632 21.996 11.9981 21.996C17.2324 21.996 21.5264 17.9745 21.9602 12.8519C21.9929 12.4664 21.8003 12.0968 21.4658 11.9026C21.1313 11.7084 20.7148 11.7246 20.3963 11.9441C19.4302 12.61 18.2602 12.9998 16.9961 12.9998C13.6824 12.9998 10.9961 10.3135 10.9961 6.99976C10.9961 5.73577 11.3858 4.56582 12.0517 3.59971Z'
|
|
28
37
|
},
|
|
@@ -53,6 +62,8 @@ const builtInIcons = {
|
|
|
53
62
|
],
|
|
54
63
|
chevronDown: 'M7 10l5 5 5-5',
|
|
55
64
|
chevronRight: 'M10 7l5 5-5 5',
|
|
65
|
+
previous: 'M15 18l-6-6 6-6',
|
|
66
|
+
next: 'M9 18l6-6-6-6',
|
|
56
67
|
search: ['M4.5 11a6.5 6.5 0 1 0 13 0a6.5 6.5 0 1 0 -13 0', 'M16 16l4 4'],
|
|
57
68
|
panelLeft: [
|
|
58
69
|
'M6.5 4.5h11a3 3 0 0 1 3 3v9a3 3 0 0 1 -3 3h-11a3 3 0 0 1 -3 -3v-9a3 3 0 0 1 3 -3Z',
|
|
@@ -107,7 +118,12 @@ export function shapeOf(name) {
|
|
|
107
118
|
return { paths: [drawing], isFilled: false };
|
|
108
119
|
if (isPathList(drawing))
|
|
109
120
|
return { paths: drawing, isFilled: false };
|
|
110
|
-
return {
|
|
121
|
+
return {
|
|
122
|
+
paths: [drawing.fill].flat(),
|
|
123
|
+
isFilled: true,
|
|
124
|
+
rule: drawing.rule,
|
|
125
|
+
colors: drawing.colors
|
|
126
|
+
};
|
|
111
127
|
}
|
|
112
128
|
function isPathList(drawing) {
|
|
113
129
|
return Array.isArray(drawing);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
export type Interaction = {
|
|
3
|
-
primitive: 'AppFrame' | 'Button' | 'Card' | 'IconButton' | 'Link' | 'ListRow' | 'Select' | 'Switch' | 'Checkbox' | 'SegmentedControl' | 'Menu' | 'ContextMenu' | 'CommandMenu' | 'TextField' | 'Form' | 'Dialog' | 'RadioGroup' | 'ChoiceGroup';
|
|
3
|
+
primitive: 'AppFrame' | 'Button' | 'Card' | 'IconButton' | 'Link' | 'ListRow' | 'Select' | 'Switch' | 'Checkbox' | 'SegmentedControl' | 'Menu' | 'ContextMenu' | 'CommandMenu' | 'TextField' | 'Form' | 'Dialog' | 'RadioGroup' | 'ChoiceGroup' | 'Calendar';
|
|
4
4
|
event: 'click' | 'change' | 'select' | 'open' | 'close' | 'submit' | 'navigate';
|
|
5
5
|
label: string;
|
|
6
6
|
page: string | null;
|
package/dist/flows/browser.d.ts
CHANGED
|
@@ -31,4 +31,10 @@ export type AppPage = {
|
|
|
31
31
|
captureAt: (viewport: ViewportName) => Promise<string>;
|
|
32
32
|
close: () => Promise<void>;
|
|
33
33
|
};
|
|
34
|
-
export
|
|
34
|
+
export type MemoryRun = {
|
|
35
|
+
seed: object;
|
|
36
|
+
admins: readonly string[];
|
|
37
|
+
title: string;
|
|
38
|
+
world: unknown;
|
|
39
|
+
};
|
|
40
|
+
export declare function openApp(browser: Browser, baseUrl: string, path: string, viewport: ViewportName, signedInAs: string | null, memory?: MemoryRun): Promise<AppPage>;
|
package/dist/flows/browser.js
CHANGED
|
@@ -59,15 +59,27 @@ function watchNetwork(page) {
|
|
|
59
59
|
}
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
|
+
function isMissingPage(response, page) {
|
|
63
|
+
const request = response.request();
|
|
64
|
+
return (request.isNavigationRequest() &&
|
|
65
|
+
request.frame() === page.mainFrame() &&
|
|
66
|
+
response.status() >= 400 &&
|
|
67
|
+
response.status() < 500);
|
|
68
|
+
}
|
|
62
69
|
function recordProblems(page, problems) {
|
|
70
|
+
const missingPages = new Set();
|
|
63
71
|
const record = (problem) => {
|
|
64
72
|
if (!problems.includes(problem))
|
|
65
73
|
problems.push(problem);
|
|
66
74
|
};
|
|
67
75
|
page.on('console', (message) => {
|
|
68
|
-
if (message.type()
|
|
69
|
-
|
|
76
|
+
if (message.type() !== 'error')
|
|
77
|
+
return;
|
|
78
|
+
if (missingPages.has(message.location().url) &&
|
|
79
|
+
message.text().startsWith('Failed to load resource')) {
|
|
80
|
+
return;
|
|
70
81
|
}
|
|
82
|
+
record(`console error: ${message.text()}`);
|
|
71
83
|
});
|
|
72
84
|
page.on('pageerror', (error) => {
|
|
73
85
|
record(`uncaught page error: ${error.message}`);
|
|
@@ -76,12 +88,16 @@ function recordProblems(page, problems) {
|
|
|
76
88
|
record(`request failed: ${request.method()} ${request.url()} (${request.failure()?.errorText ?? 'unknown'})`);
|
|
77
89
|
});
|
|
78
90
|
page.on('response', (response) => {
|
|
91
|
+
if (isMissingPage(response, page)) {
|
|
92
|
+
missingPages.add(response.url());
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
79
95
|
if (response.status() >= 400) {
|
|
80
96
|
record(`request failed: ${response.request().method()} ${response.url()} (HTTP ${response.status()})`);
|
|
81
97
|
}
|
|
82
98
|
});
|
|
83
99
|
}
|
|
84
|
-
export async function openApp(browser, baseUrl, path, viewport, signedInAs,
|
|
100
|
+
export async function openApp(browser, baseUrl, path, viewport, signedInAs, memory) {
|
|
85
101
|
const { width, height, deviceScaleFactor } = viewports[viewport];
|
|
86
102
|
const context = await browser.newContext({
|
|
87
103
|
viewport: { width, height },
|
|
@@ -89,20 +105,22 @@ export async function openApp(browser, baseUrl, path, viewport, signedInAs, seed
|
|
|
89
105
|
reducedMotion: 'reduce',
|
|
90
106
|
colorScheme: 'light'
|
|
91
107
|
});
|
|
92
|
-
if (signedInAs !== null) {
|
|
108
|
+
if (memory === undefined && signedInAs !== null) {
|
|
93
109
|
const signIn = await context.request.post(new URL('/api/auth/dev-sign-in', baseUrl).href, { data: { email: signedInAs } });
|
|
94
110
|
if (!signIn.ok()) {
|
|
95
111
|
throw new Error(`Dev sign-in as ${signedInAs} failed (HTTP ${signIn.status()}): ${await signIn.text()}`);
|
|
96
112
|
}
|
|
97
113
|
}
|
|
98
|
-
if (
|
|
114
|
+
if (memory !== undefined) {
|
|
99
115
|
await context.addInitScript((value) => {
|
|
100
116
|
Object.assign(globalThis, {
|
|
101
117
|
patternSeed: value.seed,
|
|
102
118
|
patternAdmins: value.admins,
|
|
103
|
-
|
|
119
|
+
patternTitle: value.title,
|
|
120
|
+
patternWorld: value.world,
|
|
121
|
+
patternSignedInAs: value.signedInAs
|
|
104
122
|
});
|
|
105
|
-
}, {
|
|
123
|
+
}, { ...memory, signedInAs });
|
|
106
124
|
}
|
|
107
125
|
const page = await context.newPage();
|
|
108
126
|
const problems = [];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ViewportName } from './browser.ts';
|
|
1
|
+
import type { MemoryRun, ViewportName } from './browser.ts';
|
|
2
2
|
export type VisualFlowSettings = {
|
|
3
3
|
url: string;
|
|
4
4
|
wsEndpoint: string;
|
|
@@ -11,7 +11,7 @@ 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,
|
|
14
|
+
export declare function openFlowPage(settings: VisualFlowSettings, viewport: ViewportName, startAt: string, signedInAs: string | null, memory: MemoryRun): Promise<{
|
|
15
15
|
send: (command: unknown) => Promise<void>;
|
|
16
16
|
snapshot: () => Promise<unknown>;
|
|
17
17
|
hold: (call: string) => Promise<void>;
|
|
@@ -5,9 +5,9 @@ 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,
|
|
8
|
+
export async function openFlowPage(settings, viewport, startAt, signedInAs, memory) {
|
|
9
9
|
browser ??= connectChrome(settings.wsEndpoint);
|
|
10
|
-
const app = await openApp(await browser, settings.url, startAt, viewport, signedInAs,
|
|
10
|
+
const app = await openApp(await browser, settings.url, startAt, viewport, signedInAs, memory);
|
|
11
11
|
return {
|
|
12
12
|
send: app.dispatch,
|
|
13
13
|
snapshot: app.snapshot,
|
package/dist/flows/flows.js
CHANGED
|
@@ -59,6 +59,12 @@ async function runSteps(name, steps, run) {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
+
function leadingHolds(steps) {
|
|
63
|
+
const firstOther = steps.findIndex((step) => !('hold' in step));
|
|
64
|
+
return steps
|
|
65
|
+
.slice(0, firstOther === -1 ? steps.length : firstOther)
|
|
66
|
+
.flatMap((step) => ('hold' in step ? [step.hold] : []));
|
|
67
|
+
}
|
|
62
68
|
function withTestParams(path, failing, held) {
|
|
63
69
|
const params = new URLSearchParams([
|
|
64
70
|
['memory', ''],
|
|
@@ -133,8 +139,8 @@ export function defineFlow({ App }) {
|
|
|
133
139
|
for (const viewport of visual.viewports) {
|
|
134
140
|
test(`${name} [${viewport}]`, async () => {
|
|
135
141
|
const { openFlowPage } = await import("./flowBrowser.js");
|
|
136
|
-
const held = new Set();
|
|
137
|
-
const page = await openFlowPage(visual, viewport, withTestParams(startAt, failing, held), signedInAs, seed, admins, startingWorld);
|
|
142
|
+
const held = new Set(leadingHolds(steps));
|
|
143
|
+
const page = await openFlowPage(visual, viewport, withTestParams(startAt, failing, held), signedInAs, { seed, admins, title, world: startingWorld });
|
|
138
144
|
let stepFailure;
|
|
139
145
|
try {
|
|
140
146
|
await runSteps(name, steps, {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
export { defineApp } from './app.ts';
|
|
2
|
+
export { Bookings, bookings } from './bookingsStore.ts';
|
|
3
|
+
export type { BookingsWorld } from './bookingsMemory.ts';
|
|
4
|
+
export type { AppBlock } from './blocks.ts';
|
|
2
5
|
export { ActionsStore, bindActions, rankActions } from './actions.ts';
|
|
3
6
|
export type { Action, ActionsBuilder } from './actions.ts';
|
|
4
7
|
export { startApp } from './start.ts';
|
|
@@ -16,7 +19,7 @@ export { HttpSessionApi, MemorySessionApi } from './auth/sessionApi.ts';
|
|
|
16
19
|
export type { EmailCodeOutcome, SessionApi, SessionCall } from './auth/sessionApi.ts';
|
|
17
20
|
export { userSchema } from './auth/user.ts';
|
|
18
21
|
export type { User } from './auth/user.ts';
|
|
19
|
-
export type { AppClass, AppDefinition, AppDependencies, AppSnapshotShape, DataRouter, ModelServicesOf, NavigateCommand, PressKeyCommand, PublicStores, PlainJsonModel, RunningApp, StoreClasses, StoreInstances, StoresOf, TableStores } from './app.ts';
|
|
22
|
+
export type { AppClass, AppDefinition, AppDependencies, AppSnapshotShape, BlockStores, CheckedBlocks, DataRouter, ModelServicesOf, NavigateCommand, PressKeyCommand, PublicStores, PlainJsonModel, RunningApp, StoreClasses, StoreInstances, StoresOf, TableStores } from './app.ts';
|
|
20
23
|
export { defineRoutes } from './routes.ts';
|
|
21
24
|
export { ServiceRefused, refused } from './services.ts';
|
|
22
25
|
export type { ServiceClient, ServiceMemory } from './services.ts';
|
package/dist/index.js
CHANGED