@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.
Files changed (87) hide show
  1. package/README.md +73 -12
  2. package/dist/access.d.ts +0 -4
  3. package/dist/access.js +0 -5
  4. package/dist/api.d.ts +3 -1
  5. package/dist/api.js +5 -17
  6. package/dist/app.d.ts +20 -5
  7. package/dist/app.js +32 -2
  8. package/dist/blocks.d.ts +18 -0
  9. package/dist/blocks.js +36 -0
  10. package/dist/bookings.d.ts +400 -0
  11. package/dist/bookings.js +300 -0
  12. package/dist/bookingsMemory.d.ts +9 -0
  13. package/dist/bookingsMemory.js +79 -0
  14. package/dist/bookingsStore.d.ts +698 -0
  15. package/dist/bookingsStore.js +129 -0
  16. package/dist/cli/app.js +143 -59
  17. package/dist/cli/publishing.d.ts +3 -1
  18. package/dist/cli/publishing.js +33 -5
  19. package/dist/cli/starter.d.ts +17 -0
  20. package/dist/cli/starter.js +140 -0
  21. package/dist/components/Button.d.ts +2 -24
  22. package/dist/components/Button.js +4 -251
  23. package/dist/components/ButtonBody.d.ts +25 -0
  24. package/dist/components/ButtonBody.js +266 -0
  25. package/dist/components/Calendar.d.ts +20 -0
  26. package/dist/components/Calendar.js +195 -0
  27. package/dist/components/Card.d.ts +1 -1
  28. package/dist/components/Card.js +7 -29
  29. package/dist/components/Choice.js +27 -13
  30. package/dist/components/ChoiceGroup.d.ts +3 -1
  31. package/dist/components/ChoiceGroup.js +3 -4
  32. package/dist/components/ContinueWithGoogle.d.ts +11 -0
  33. package/dist/components/ContinueWithGoogle.js +5 -0
  34. package/dist/components/Dialog.d.ts +1 -1
  35. package/dist/components/Dialog.js +3 -1
  36. package/dist/components/Icon.js +1 -1
  37. package/dist/components/ListRow.js +2 -1
  38. package/dist/components/RadioGroup.d.ts +2 -1
  39. package/dist/components/RadioGroup.js +10 -2
  40. package/dist/components/Text.d.ts +1 -1
  41. package/dist/components/Text.js +43 -2
  42. package/dist/components/calendarDates.d.ts +14 -0
  43. package/dist/components/calendarDates.js +84 -0
  44. package/dist/components/controlLook.js +11 -11
  45. package/dist/components/icons.d.ts +9 -0
  46. package/dist/components/icons.js +17 -1
  47. package/dist/components/interaction.d.ts +1 -1
  48. package/dist/flows/browser.d.ts +7 -1
  49. package/dist/flows/browser.js +25 -7
  50. package/dist/flows/flowBrowser.d.ts +2 -2
  51. package/dist/flows/flowBrowser.js +2 -2
  52. package/dist/flows/flows.js +8 -2
  53. package/dist/index.d.ts +4 -1
  54. package/dist/index.js +1 -0
  55. package/dist/media.d.ts +11 -1
  56. package/dist/patternAccess.d.ts +11 -2
  57. package/dist/patternAccess.js +8 -4
  58. package/dist/publishWire.d.ts +24 -2
  59. package/dist/publishWire.js +22 -2
  60. package/dist/react.d.ts +3 -0
  61. package/dist/react.js +2 -0
  62. package/dist/rules/checkAllFiles.js +16 -2
  63. package/dist/rules/lintPlugin.js +1 -0
  64. package/dist/schema.d.ts +3 -1
  65. package/dist/schema.js +1 -0
  66. package/dist/server/bookings.d.ts +12 -0
  67. package/dist/server/bookings.js +142 -0
  68. package/dist/server/createServer.d.ts +3 -2
  69. package/dist/server/createServer.js +13 -4
  70. package/dist/server/env.d.ts +8 -0
  71. package/dist/server/index.d.ts +3 -1
  72. package/dist/server/index.js +1 -0
  73. package/dist/server/media.d.ts +16 -3
  74. package/dist/server/media.js +72 -23
  75. package/dist/server/patternViewer.js +16 -10
  76. package/dist/server/tables.d.ts +2 -0
  77. package/dist/server/tables.js +17 -1
  78. package/dist/start.js +12 -0
  79. package/dist/table.js +9 -3
  80. package/dist/theme/scales.d.ts +1 -1
  81. package/dist/theme/scales.js +1 -0
  82. package/dist/theme/tokens.stylex.d.ts +18 -0
  83. package/dist/theme/tokens.stylex.js +19 -1
  84. package/dist/vite/localWorker.d.ts +2 -0
  85. package/dist/vite/localWorker.js +48 -3
  86. package/dist/vite/vite.js +5 -1
  87. package/package.json +1 -1
@@ -0,0 +1,140 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import { existsSync, readFileSync } from 'node:fs';
10
+ import { join } from 'node:path';
11
+ import { pathToFileURL } from 'node:url';
12
+ import { media } from "../media.js";
13
+ import { photoFacts } from "../server/media.js";
14
+ import { starterSql } from "../server/tables.js";
15
+ export const STARTER_ROWS = 'starter/rows.ts';
16
+ export const STARTER_PHOTOS = 'starter/photos';
17
+ const PHOTO_NAME = /^[\w][\w.-]*$/;
18
+ function record(value) {
19
+ return typeof value === 'object' && value !== null
20
+ ? value
21
+ : {};
22
+ }
23
+ function textOf(row, key) {
24
+ const value = row[key];
25
+ return typeof value === 'string' ? value.trim() : '';
26
+ }
27
+ async function readPhoto(root, raw) {
28
+ const id = textOf(raw, 'id');
29
+ const photo = textOf(raw, 'photo');
30
+ const alt = textOf(raw, 'alt');
31
+ const where = `${STARTER_ROWS}: the media row ${id === '' ? 'without an id' : id}`;
32
+ if (id === '')
33
+ throw new Error(`${where} needs an id`);
34
+ if (!PHOTO_NAME.test(photo)) {
35
+ throw new Error(`${where} names its photo by its file name in ${STARTER_PHOTOS}, like photo: 'peonies.jpg'`);
36
+ }
37
+ if (alt === '') {
38
+ throw new Error(`${where} needs alt: describe the photo for someone who can't see it`);
39
+ }
40
+ const path = `${STARTER_PHOTOS}/${photo}`;
41
+ if (!existsSync(join(root, path))) {
42
+ throw new Error(`${where} names ${path}, which isn't there`);
43
+ }
44
+ const bytes = readFileSync(join(root, path));
45
+ const facts = await photoFacts(bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength));
46
+ if ('problem' in facts)
47
+ throw new Error(`${path}: ${facts.problem}`);
48
+ return { ...facts, id, alt, path };
49
+ }
50
+ function readRows(name, table, rows) {
51
+ if (table.owned) {
52
+ throw new Error(`${STARTER_ROWS} can't fill ${name}: its rows belong to whoever makes them, and nobody has signed in when a site first goes live`);
53
+ }
54
+ return rows.map((raw) => {
55
+ const { id, ...fields } = record(raw);
56
+ if (typeof id !== 'string' || id === '') {
57
+ throw new Error(`${STARTER_ROWS}: every ${name} row needs an id`);
58
+ }
59
+ const parsed = table.fields.safeParse(fields);
60
+ if (!parsed.success) {
61
+ const issue = parsed.error.issues[0];
62
+ throw new Error(`${STARTER_ROWS}: the ${name} row ${id} ${issue === undefined ? 'is not valid' : `has ${issue.path.join('.') || 'a field'} wrong: ${issue.message}`}`);
63
+ }
64
+ return { id, ...parsed.data };
65
+ });
66
+ }
67
+ function refuseRepeatedIds(name, rows) {
68
+ const seen = new Set();
69
+ for (const row of rows) {
70
+ if (seen.has(row['id'])) {
71
+ throw new Error(`${name} has two rows with the id ${String(row['id'])}`);
72
+ }
73
+ seen.add(row['id']);
74
+ }
75
+ }
76
+ export async function readStarter(root, tables) {
77
+ const file = join(root, STARTER_ROWS);
78
+ if (!existsSync(file))
79
+ return undefined;
80
+ const module = await import(__rewriteRelativeImportExtension(pathToFileURL(file).href));
81
+ const starter = record(module)['starter'];
82
+ if (typeof starter !== 'object' || starter === null) {
83
+ throw new Error(`${STARTER_ROWS} must export \`starter\``);
84
+ }
85
+ const photos = [];
86
+ const rows = {};
87
+ for (const [name, list] of Object.entries(starter)) {
88
+ const table = tables[name];
89
+ if (table === undefined) {
90
+ throw new Error(`${STARTER_ROWS} has rows for ${name}, which isn't in tables in schema.ts`);
91
+ }
92
+ if (!Array.isArray(list)) {
93
+ throw new Error(`${STARTER_ROWS}: ${name} must be a list of rows`);
94
+ }
95
+ if (table.name === media.name) {
96
+ for (const raw of list)
97
+ photos.push(await readPhoto(root, record(raw)));
98
+ refuseRepeatedIds(`${STARTER_ROWS} media`, photos);
99
+ continue;
100
+ }
101
+ rows[name] = readRows(name, table, list);
102
+ refuseRepeatedIds(`${STARTER_ROWS} ${name}`, rows[name]);
103
+ }
104
+ return { photos, rows: rows };
105
+ }
106
+ export function withStarter(seed, starter) {
107
+ if (starter === undefined)
108
+ return seed;
109
+ const photoRows = starter.photos.map((photo) => ({
110
+ id: photo.id,
111
+ key: photo.key,
112
+ width: photo.width,
113
+ height: photo.height,
114
+ placeholder: null,
115
+ alt: photo.alt,
116
+ type: photo.type,
117
+ bytes: photo.bytes
118
+ }));
119
+ const added = {
120
+ ...starter.rows,
121
+ ...(photoRows.length === 0 ? {} : { media: photoRows })
122
+ };
123
+ const merged = { ...seed };
124
+ for (const [name, list] of Object.entries(added)) {
125
+ const starterRows = (list ?? []);
126
+ const starterIds = new Set(starterRows.map((row) => row['id']));
127
+ const seedRows = (merged[name] ?? []);
128
+ merged[name] = [
129
+ ...seedRows.filter((row) => !starterIds.has(row['id'])),
130
+ ...starterRows
131
+ ];
132
+ }
133
+ return merged;
134
+ }
135
+ export function starterContentOf(tables, starter) {
136
+ return {
137
+ photos: starter.photos.map(({ id, path, alt }) => ({ id, path, alt })),
138
+ sql: starterSql(tables, starter.rows)
139
+ };
140
+ }
@@ -1,24 +1,2 @@
1
- import type { AppPath } from '../registered.ts';
2
- import type { ReactNode } from 'react';
3
- import type { IconName } from './icons.ts';
4
- import type { Placement } from './Placement.ts';
5
- import type { Size } from './Size.ts';
6
- type ButtonProps = {
7
- children: ReactNode;
8
- variant?: 'primary' | 'secondary' | 'tertiary' | 'transparent';
9
- tone?: 'neutral' | 'brand' | 'danger';
10
- size?: Size;
11
- to?: AppPath;
12
- href?: string;
13
- icon?: IconName;
14
- trailingIcon?: IconName;
15
- shortcut?: readonly string[];
16
- type?: 'button' | 'submit';
17
- disabled?: boolean;
18
- isPending?: boolean;
19
- isFullWidth?: boolean;
20
- onClick?: () => void;
21
- style?: Placement;
22
- };
23
- export declare function Button({ children, variant, tone, size, to, href, icon, trailingIcon, shortcut, type, disabled, isPending, isFullWidth, onClick, style }: ButtonProps): import("react").JSX.Element;
24
- export {};
1
+ import type { ButtonProps } from './ButtonBody.tsx';
2
+ export declare function Button(props: ButtonProps): import("react").JSX.Element;
@@ -1,252 +1,5 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Button as BaseButton } from '@base-ui/react/button';
3
- import { Link as RouterLink } from 'react-router';
4
- import * as stylex from '@stylexjs/stylex';
5
- import { colors, controls, fontWeights, motion, shadows } from "../theme/tokens.stylex.js";
6
- import { controlSizes, focusRing } from "./controlLook.js";
7
- import { Icon } from "./Icon.js";
8
- import { interact, textOf } from "./interaction.js";
9
- import { Kbd } from "./Kbd.js";
10
- import { Spinner } from "./Spinner.js";
11
- export function Button({ children, variant = 'primary', tone = variant === 'primary' ? 'brand' : 'neutral', size = 'md', to, href, icon, trailingIcon, shortcut, type = 'button', disabled = false, isPending = false, isFullWidth = false, onClick, style }) {
12
- const isDisabled = disabled || isPending;
13
- const report = () => {
14
- interact({ primitive: 'Button', event: 'click', label: textOf(children) });
15
- onClick?.();
16
- };
17
- const className = stylex.props(styles.button, controlSizes[size], icon !== undefined && leadingIconSizes[size], trailingIcon !== undefined && trailingIconSizes[size], looks[`${variant}${toneKeys[tone]}`], !isDisabled && hovers[`${variant}${toneKeys[tone]}`], isDisabled && styles.disabled, isDisabled && variant === 'transparent' && styles.disabledTransparent, isFullWidth && styles.fullWidth, focusRing.visible, style).className;
18
- const content = (_jsxs("span", { ...stylex.props(styles.stack), children: [_jsxs("span", { ...stylex.props(styles.content, isPending && styles.hidden), children: [icon === undefined ? null : _jsx(Icon, { name: icon, size: size }), _jsx("span", { ...stylex.props(styles.label, shortcut !== undefined && styles.labelBeforeShortcut), children: children }), trailingIcon === undefined ? null : (_jsx(Icon, { name: trailingIcon, size: size })), shortcut === undefined ? null : _jsx(Kbd, { keys: shortcut })] }), isPending ? (_jsx("span", { "aria-hidden": "true", ...stylex.props(styles.pending), children: _jsx(Spinner, { size: size }) })) : null] }));
19
- if (href !== undefined) {
20
- return (_jsx("a", { href: href, target: "_blank", rel: "noreferrer", onClick: report, className: className, children: content }));
21
- }
22
- if (to !== undefined) {
23
- return (_jsx(RouterLink, { to: to, onClick: report, className: className, children: content }));
24
- }
25
- return (_jsx(BaseButton, { type: type, disabled: isDisabled, focusableWhenDisabled: true, "aria-busy": isPending || undefined, onClick: report, className: className, children: content }));
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { ButtonBody } from "./ButtonBody.js";
3
+ export function Button(props) {
4
+ return _jsx(ButtonBody, { ...props });
26
5
  }
27
- const toneKeys = {
28
- neutral: 'Neutral',
29
- brand: 'Brand',
30
- danger: 'Danger'
31
- };
32
- const styles = stylex.create({
33
- button: {
34
- position: 'relative',
35
- display: 'flex',
36
- flexShrink: 0,
37
- alignItems: 'center',
38
- justifyContent: 'center',
39
- minWidth: 0,
40
- fontWeight: fontWeights.medium,
41
- whiteSpace: 'nowrap',
42
- textDecoration: 'none',
43
- touchAction: 'manipulation',
44
- outlineOffset: 0,
45
- transitionTimingFunction: motion.easeOut,
46
- transitionDuration: motion.fast,
47
- transitionProperty: 'color, background-color, transform'
48
- },
49
- fullWidth: {
50
- justifyContent: 'flex-start',
51
- width: '100%'
52
- },
53
- stack: {
54
- display: 'grid',
55
- flexGrow: 1,
56
- gridTemplateColumns: 'minmax(0, 1fr)',
57
- gap: 'inherit',
58
- justifyContent: 'inherit',
59
- minWidth: 0,
60
- overflow: 'clip'
61
- },
62
- content: {
63
- display: 'flex',
64
- gridRowStart: 1,
65
- gridColumnStart: 1,
66
- gap: 'inherit',
67
- alignItems: 'center',
68
- justifyContent: 'inherit',
69
- minWidth: 0,
70
- transitionTimingFunction: motion.easeOut,
71
- transitionDuration: motion.base,
72
- transitionProperty: 'opacity, transform'
73
- },
74
- hidden: {
75
- opacity: 0,
76
- transform: 'translateY(24px)'
77
- },
78
- pending: {
79
- display: 'flex',
80
- gridRowStart: 1,
81
- gridColumnStart: 1,
82
- alignItems: 'center',
83
- justifyContent: 'center',
84
- pointerEvents: 'none'
85
- },
86
- label: {
87
- overflow: 'hidden',
88
- textOverflow: 'ellipsis'
89
- },
90
- labelBeforeShortcut: {
91
- flexGrow: 1,
92
- textAlign: 'start'
93
- },
94
- disabled: {
95
- color: colors.disabledForeground,
96
- backgroundColor: colors.disabled,
97
- boxShadow: 'none'
98
- },
99
- disabledTransparent: {
100
- backgroundColor: 'transparent'
101
- }
102
- });
103
- const leadingIconSizes = stylex.create({
104
- xs: { paddingInlineStart: `calc(${controls.paddingXs} - 2px)` },
105
- sm: { paddingInlineStart: `calc(${controls.paddingSm} - 2px)` },
106
- md: { paddingInlineStart: `calc(${controls.paddingMd} - 4px)` },
107
- lg: { paddingInlineStart: `calc(${controls.paddingLg} - 2px)` },
108
- xl: { paddingInlineStart: `calc(${controls.paddingXl} - 4px)` }
109
- });
110
- const trailingIconSizes = stylex.create({
111
- xs: { paddingInlineEnd: `calc(${controls.paddingXs} - 2px)` },
112
- sm: { paddingInlineEnd: `calc(${controls.paddingSm} - 2px)` },
113
- md: { paddingInlineEnd: `calc(${controls.paddingMd} - 4px)` },
114
- lg: { paddingInlineEnd: `calc(${controls.paddingLg} - 2px)` },
115
- xl: { paddingInlineEnd: `calc(${controls.paddingXl} - 4px)` }
116
- });
117
- const looks = stylex.create({
118
- primaryNeutral: {
119
- color: colors.onInvertedForeground,
120
- backgroundColor: colors.invertedSolid
121
- },
122
- primaryBrand: {
123
- color: colors.onBrandSolidForeground,
124
- backgroundColor: colors.brandSolid
125
- },
126
- primaryDanger: {
127
- color: colors.onDangerSolidForeground,
128
- backgroundColor: colors.dangerSolid
129
- },
130
- secondaryNeutral: {
131
- color: colors.primaryForeground,
132
- backgroundColor: colors.componentOnContainerStrong,
133
- boxShadow: shadows.default
134
- },
135
- secondaryBrand: {
136
- color: colors.brandForeground,
137
- backgroundColor: colors.componentOnContainerStrong,
138
- boxShadow: shadows.default
139
- },
140
- secondaryDanger: {
141
- color: colors.dangerForeground,
142
- backgroundColor: colors.componentOnContainerStrong,
143
- boxShadow: shadows.default
144
- },
145
- tertiaryNeutral: {
146
- color: colors.secondaryForeground,
147
- backgroundColor: colors.component
148
- },
149
- tertiaryBrand: {
150
- color: colors.onBrandSubtleForeground,
151
- backgroundColor: colors.brandSubtle
152
- },
153
- tertiaryDanger: {
154
- color: colors.dangerForeground,
155
- backgroundColor: colors.dangerSubtle
156
- },
157
- transparentNeutral: {
158
- color: colors.secondaryForeground,
159
- backgroundColor: 'transparent'
160
- },
161
- transparentBrand: {
162
- color: colors.brandForeground,
163
- backgroundColor: 'transparent'
164
- },
165
- transparentDanger: {
166
- color: colors.dangerForeground,
167
- backgroundColor: 'transparent'
168
- }
169
- });
170
- const hovers = stylex.create({
171
- primaryNeutral: {
172
- backgroundColor: {
173
- default: colors.invertedSolid,
174
- ':hover': colors.invertedSolidHover,
175
- ':active': colors.invertedSolidActive
176
- }
177
- },
178
- primaryBrand: {
179
- backgroundColor: {
180
- default: colors.brandSolid,
181
- ':hover': colors.brandSolidHover,
182
- ':active': colors.brandSolidActive
183
- }
184
- },
185
- primaryDanger: {
186
- backgroundColor: {
187
- default: colors.dangerSolid,
188
- ':hover': colors.dangerSolidHover,
189
- ':active': colors.dangerSolidActive
190
- }
191
- },
192
- secondaryNeutral: {
193
- backgroundColor: {
194
- default: colors.componentOnContainerStrong,
195
- ':hover': colors.componentOnContainerStrongHover
196
- }
197
- },
198
- secondaryBrand: {
199
- backgroundColor: {
200
- default: colors.componentOnContainerStrong,
201
- ':hover': colors.componentOnContainerStrongHover
202
- }
203
- },
204
- secondaryDanger: {
205
- backgroundColor: {
206
- default: colors.componentOnContainerStrong,
207
- ':hover': colors.componentOnContainerStrongHover
208
- }
209
- },
210
- tertiaryNeutral: {
211
- backgroundColor: {
212
- default: colors.component,
213
- ':hover': colors.componentHover,
214
- ':active': colors.componentActive
215
- }
216
- },
217
- tertiaryBrand: {
218
- backgroundColor: {
219
- default: colors.brandSubtle,
220
- ':hover': colors.brandSubtleHover
221
- }
222
- },
223
- tertiaryDanger: {
224
- backgroundColor: {
225
- default: colors.dangerSubtle,
226
- ':hover': colors.dangerSubtleHover,
227
- ':active': colors.dangerSubtleActive
228
- }
229
- },
230
- transparentNeutral: {
231
- color: {
232
- default: colors.secondaryForeground,
233
- ':hover': colors.primaryForeground
234
- },
235
- backgroundColor: {
236
- default: 'transparent',
237
- ':hover': colors.transparentHover
238
- }
239
- },
240
- transparentBrand: {
241
- backgroundColor: {
242
- default: 'transparent',
243
- ':hover': colors.transparentHover
244
- }
245
- },
246
- transparentDanger: {
247
- backgroundColor: {
248
- default: 'transparent',
249
- ':hover': colors.dangerSubtleHover
250
- }
251
- }
252
- });
@@ -0,0 +1,25 @@
1
+ import type { AppPath } from '../registered.ts';
2
+ import type { ReactNode } from 'react';
3
+ import type { IconName } from './icons.ts';
4
+ import type { Placement } from './Placement.ts';
5
+ import type { Size } from './Size.ts';
6
+ export type ButtonProps = {
7
+ children: ReactNode;
8
+ variant?: 'primary' | 'secondary' | 'tertiary' | 'transparent';
9
+ tone?: 'neutral' | 'brand' | 'danger';
10
+ size?: Size;
11
+ to?: AppPath;
12
+ href?: string;
13
+ icon?: IconName;
14
+ trailingIcon?: IconName;
15
+ shortcut?: readonly string[];
16
+ type?: 'button' | 'submit';
17
+ disabled?: boolean;
18
+ isPending?: boolean;
19
+ isFullWidth?: boolean;
20
+ onClick?: () => void;
21
+ style?: Placement;
22
+ };
23
+ export declare function ButtonBody({ children, variant, tone, size, to, href, icon, trailingIcon, shortcut, type, disabled, isPending, isFullWidth, onClick, style, isIconPinned }: ButtonProps & {
24
+ isIconPinned?: boolean;
25
+ }): import("react").JSX.Element;