@trypattern/sdk 0.1.37 → 0.1.38

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.
@@ -1,3 +1,4 @@
1
+ import type { WeekStart } from './calendarDates.ts';
1
2
  import type { Placement } from './Placement.ts';
2
3
  export type CalendarDay = {
3
4
  date: string;
@@ -14,7 +15,8 @@ type CalendarProps = {
14
15
  lastMonth?: string;
15
16
  today?: string;
16
17
  locale?: string;
18
+ weekStart?: WeekStart;
17
19
  style?: Placement;
18
20
  };
19
- export declare function Calendar({ label, month, onMonthChange, days, value, onPick, firstMonth, lastMonth, today, locale, style }: CalendarProps): import("react").JSX.Element;
21
+ export declare function Calendar({ label, month, onMonthChange, days, value, onPick, firstMonth, lastMonth, today, locale, weekStart, style }: CalendarProps): import("react").JSX.Element;
20
22
  export {};
@@ -7,7 +7,7 @@ import { addDays, addMonths, dayLabel, dayNumber, localToday, monthOf, monthTitl
7
7
  import { focusRing } from "./controlLook.js";
8
8
  import { Icon } from "./Icon.js";
9
9
  import { interact } from "./interaction.js";
10
- export function Calendar({ label, month, onMonthChange, days, value, onPick, firstMonth, lastMonth, today = localToday(), locale, style }) {
10
+ export function Calendar({ label, month, onMonthChange, days, value, onPick, firstMonth, lastMonth, today = localToday(), locale, weekStart = 'monday', style }) {
11
11
  const states = new Map(days.map((day) => [day.date, day.state]));
12
12
  const [moved, setMoved] = useState(null);
13
13
  const grid = useRef(null);
@@ -46,7 +46,7 @@ export function Calendar({ label, month, onMonthChange, days, value, onPick, fir
46
46
  if (step === undefined)
47
47
  return;
48
48
  event.preventDefault();
49
- const target = step(date);
49
+ const target = step(date, weekStart);
50
50
  const targetMonth = monthOf(target);
51
51
  if (firstMonth !== undefined && targetMonth < firstMonth)
52
52
  return;
@@ -57,7 +57,7 @@ export function Calendar({ label, month, onMonthChange, days, value, onPick, fir
57
57
  if (targetMonth !== month)
58
58
  goTo(targetMonth);
59
59
  };
60
- return (_jsxs("div", { ...stylex.props(styles.calendar, style), children: [_jsxs("div", { ...stylex.props(styles.header), children: [_jsx("span", { ...stylex.props(styles.title), "aria-live": "polite", children: monthTitle(month, locale) }), _jsxs("span", { ...stylex.props(styles.nav), children: [_jsx(BaseButton, { "aria-label": monthTitle(previous, locale), disabled: !canGoBack, onClick: () => goTo(previous), className: stylex.props(styles.navButton, canGoBack ? styles.navEnabled : styles.navDisabled, focusRing.visible).className, children: _jsx(Icon, { name: "previous" }) }), _jsx(BaseButton, { "aria-label": monthTitle(next, locale), disabled: !canGoOn, onClick: () => goTo(next), className: stylex.props(styles.navButton, canGoOn ? styles.navEnabled : styles.navDisabled, focusRing.visible).className, children: _jsx(Icon, { name: "next" }) })] })] }), _jsxs("div", { ref: grid, role: "grid", "aria-label": `${label}, ${monthTitle(month, locale)}`, ...stylex.props(styles.grid), children: [_jsx("div", { role: "row", ...stylex.props(styles.row), children: weekdayNames(locale).map((weekday) => (_jsx("span", { role: "columnheader", "aria-label": weekday.long, ...stylex.props(styles.weekday), children: weekday.short }, weekday.long))) }), weeksOf(month).map((week, index) => (_jsx("div", { role: "row", ...stylex.props(styles.row), children: week.map((date, column) => {
60
+ return (_jsxs("div", { ...stylex.props(styles.calendar, style), children: [_jsxs("div", { ...stylex.props(styles.header), children: [_jsx("span", { ...stylex.props(styles.title), "aria-live": "polite", children: monthTitle(month, locale) }), _jsxs("span", { ...stylex.props(styles.nav), children: [_jsx(BaseButton, { "aria-label": monthTitle(previous, locale), disabled: !canGoBack, onClick: () => goTo(previous), className: stylex.props(styles.navButton, canGoBack ? styles.navEnabled : styles.navDisabled, focusRing.visible).className, children: _jsx(Icon, { name: "previous" }) }), _jsx(BaseButton, { "aria-label": monthTitle(next, locale), disabled: !canGoOn, onClick: () => goTo(next), className: stylex.props(styles.navButton, canGoOn ? styles.navEnabled : styles.navDisabled, focusRing.visible).className, children: _jsx(Icon, { name: "next" }) })] })] }), _jsxs("div", { ref: grid, role: "grid", "aria-label": `${label}, ${monthTitle(month, locale)}`, ...stylex.props(styles.grid), children: [_jsx("div", { role: "row", ...stylex.props(styles.row), children: weekdayNames(locale, weekStart).map((weekday) => (_jsx("span", { role: "columnheader", "aria-label": weekday.long, ...stylex.props(styles.weekday), children: weekday.short }, weekday.long))) }), weeksOf(month, weekStart).map((week, index) => (_jsx("div", { role: "row", ...stylex.props(styles.row), children: week.map((date, column) => {
61
61
  if (date === null) {
62
62
  return (_jsx("span", { role: "gridcell", ...stylex.props(styles.cell) }, `blank-${column}`));
63
63
  }
@@ -72,8 +72,8 @@ const MOVES = {
72
72
  ArrowRight: (date) => addDays(date, 1),
73
73
  ArrowUp: (date) => addDays(date, -7),
74
74
  ArrowDown: (date) => addDays(date, 7),
75
- Home: (date) => addDays(date, -weekdayIndex(date)),
76
- End: (date) => addDays(date, 6 - weekdayIndex(date)),
75
+ Home: (date, weekStart) => addDays(date, -weekdayIndex(date, weekStart)),
76
+ End: (date, weekStart) => addDays(date, 6 - weekdayIndex(date, weekStart)),
77
77
  PageUp: (date) => addMonths(date, -1),
78
78
  PageDown: (date) => addMonths(date, 1)
79
79
  };
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Checkbox as BaseCheckbox } from '@base-ui/react/checkbox';
3
3
  import * as stylex from '@stylexjs/stylex';
4
- import { borders, colors, iconSizes, motion, radii, space } from "../theme/tokens.stylex.js";
4
+ import { borders, colors, corners, iconSizes, motion, radii, space } from "../theme/tokens.stylex.js";
5
5
  import { focusRing } from "./controlLook.js";
6
6
  import { interact } from "./interaction.js";
7
7
  export function Checkbox({ label, checked, disabled = false, shape = 'round', onChange, style }) {
@@ -33,7 +33,7 @@ const styles = stylex.create({
33
33
  }
34
34
  },
35
35
  square: {
36
- borderRadius: radii.sm
36
+ borderRadius: corners.checkbox
37
37
  },
38
38
  off: {
39
39
  backgroundColor: 'transparent',
@@ -55,7 +55,7 @@ export function Dialog({ label, isOpen, onOpenChange, placement = 'center', size
55
55
  onOpenChange(next);
56
56
  }, children: _jsxs(BaseDialog.Portal, { children: [placement === 'center' || isSheet ? (_jsx(BaseDialog.Backdrop, { className: (state) => stylex.props(styles.backdrop, (!state.open || state.transitionStatus === 'starting') &&
57
57
  styles.backdropHidden).className })) : null, _jsx(BaseDialog.Popup, { "aria-label": label, className: (state) => stylex.props(styles.popup, placements[placement], isSheet ? sheetWidths[size] : widths[size], (!state.open || state.transitionStatus === 'starting') &&
58
- hiddenPlacements[placement], !state.open && styles.exiting, isSheet && drag > 0 && styles.dragged(drag)).className, children: _jsxs("div", { ...stylex.props(styles.frame, isSheet && styles.sheetFrame), children: [isSheet ? (_jsx("div", { "aria-hidden": "true", ref: handle, ...stylex.props(styles.handle), children: _jsx("span", { ...stylex.props(styles.grip) }) })) : null, children] }) })] }) }));
58
+ hiddenPlacements[placement], !state.open && styles.exiting, isSheet && drag > 0 && styles.dragged(drag)).className, children: _jsxs("div", { ...stylex.props(styles.frame, isSheet && styles.sheetFrame), children: [isSheet ? (_jsx("div", { "aria-hidden": "true", ref: handle, ...stylex.props(styles.handle), children: _jsx("span", { ...stylex.props(styles.grip) }) })) : null, _jsx("div", { ...stylex.props(styles.content), children: children })] }) })] }) }));
59
59
  }
60
60
  const styles = stylex.create({
61
61
  backdrop: {
@@ -120,6 +120,15 @@ const styles = stylex.create({
120
120
  backgroundColor: colors.borderStrong,
121
121
  borderRadius: radii.full
122
122
  },
123
+ content: {
124
+ display: 'flex',
125
+ flexGrow: 1,
126
+ flexShrink: 1,
127
+ flexDirection: 'column',
128
+ minHeight: 0,
129
+ overflowY: 'auto',
130
+ overscrollBehaviorY: 'contain'
131
+ },
123
132
  frame: {
124
133
  display: 'flex',
125
134
  flexDirection: 'column',
@@ -13,11 +13,13 @@ const styles = stylex.create({
13
13
  height: '100%',
14
14
  minHeight: 0,
15
15
  overflowY: 'auto',
16
- overscrollBehavior: 'contain'
16
+ overscrollBehaviorX: 'contain',
17
+ overscrollBehaviorY: 'contain'
17
18
  },
18
19
  horizontal: {
19
20
  height: 'auto',
20
21
  overflowX: 'auto',
21
- overflowY: 'hidden'
22
+ overflowY: 'hidden',
23
+ overscrollBehaviorY: 'auto'
22
24
  }
23
25
  });
@@ -6,6 +6,7 @@ export type SelectOption<Value extends string> = {
6
6
  };
7
7
  type SelectProps<Value extends string> = {
8
8
  label: string;
9
+ isLabelHidden?: boolean;
9
10
  value: Value;
10
11
  options: readonly SelectOption<Value>[];
11
12
  size?: Size;
@@ -13,5 +14,5 @@ type SelectProps<Value extends string> = {
13
14
  onChange: (value: Value) => void;
14
15
  style?: Placement;
15
16
  };
16
- export declare function Select<Value extends string>({ label, value, options, size, disabled, onChange, style }: SelectProps<Value>): import("react").JSX.Element;
17
+ export declare function Select<Value extends string>({ label, isLabelHidden, value, options, size, disabled, onChange, style }: SelectProps<Value>): import("react").JSX.Element;
17
18
  export {};
@@ -1,22 +1,33 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Select as BaseSelect } from '@base-ui/react/select';
3
3
  import * as stylex from '@stylexjs/stylex';
4
- import { borders, colors, controls, iconSizes, layers, motion, radii, shadows, space } from "../theme/tokens.stylex.js";
4
+ import { borders, colors, controls, fontWeights, iconSizes, layers, motion, radii, shadows, space } from "../theme/tokens.stylex.js";
5
5
  import { fieldCorners, controlSizes } from "./controlLook.js";
6
6
  import { Icon } from "./Icon.js";
7
7
  import { interact } from "./interaction.js";
8
8
  import { Popup } from "./Popup.js";
9
9
  import { PopupItem } from "./PopupItem.js";
10
- export function Select({ label, value, options, size = 'md', disabled = false, onChange, style }) {
10
+ export function Select({ label, isLabelHidden = true, value, options, size = 'md', disabled = false, onChange, style }) {
11
+ const trigger = (_jsxs(BaseSelect.Trigger, { "aria-label": isLabelHidden ? label : undefined, className: (state) => stylex.props(styles.trigger, controlSizes[size], fieldCorners[size], triggerPaddings[size], styles.triggerLook, !disabled && styles.hoverable, state.open && styles.triggerOpen, disabled && styles.disabled, isLabelHidden && style).className, children: [_jsx("span", { ...stylex.props(styles.values), children: options.map((option) => (_jsx("span", { "aria-hidden": option.value !== value, ...stylex.props(styles.value, option.value !== value && styles.valueHidden), children: option.label }, option.value))) }), _jsx(BaseSelect.Icon, { className: stylex.props(styles.chevron).className, children: _jsx(Icon, { name: "chevronUpDown", size: size }) })] }));
11
12
  return (_jsxs(BaseSelect.Root, { items: options, value: value, disabled: disabled, onValueChange: (next) => {
12
13
  if (next === null)
13
14
  return;
14
15
  interact({ primitive: 'Select', event: 'change', label });
15
16
  onChange(next);
16
- }, children: [_jsxs(BaseSelect.Trigger, { "aria-label": label, className: (state) => stylex.props(styles.trigger, controlSizes[size], fieldCorners[size], triggerPaddings[size], styles.triggerLook, !disabled && styles.hoverable, state.open && styles.triggerOpen, disabled && styles.disabled, style).className, children: [_jsx("span", { ...stylex.props(styles.values), children: options.map((option) => (_jsx("span", { "aria-hidden": option.value !== value, ...stylex.props(styles.value, option.value !== value && styles.valueHidden), children: option.label }, option.value))) }), _jsx(BaseSelect.Icon, { className: stylex.props(styles.chevron).className, children: _jsx(Icon, { name: "chevronUpDown", size: size }) })] }), _jsx(BaseSelect.Portal, { children: _jsx(BaseSelect.Positioner, { alignItemWithTrigger: false, side: "bottom", align: "start", sideOffset: 4, className: stylex.props(styles.positioner).className, children: _jsx(BaseSelect.Popup, { render: (props, state) => (_jsx(Popup, { ...props, kind: "select", isOpen: state.open, transitionStatus: state.transitionStatus })), children: options.map((option) => (_jsxs(BaseSelect.Item, { value: option.value, render: (props, state) => (_jsx(PopupItem, { ...props, kind: "select", isHighlighted: state.highlighted })), children: [_jsx("span", { ...stylex.props(styles.indicator), children: _jsx(BaseSelect.ItemIndicator, { className: stylex.props(styles.check).className, children: _jsx(Icon, { name: "check" }) }) }), _jsx(BaseSelect.ItemText, { children: option.label })] }, option.value))) }) }) })] }));
17
+ }, children: [isLabelHidden ? (trigger) : (_jsxs("div", { ...stylex.props(styles.field, style), children: [_jsx(BaseSelect.Label, { className: stylex.props(styles.label).className, children: label }), trigger] })), _jsx(BaseSelect.Portal, { children: _jsx(BaseSelect.Positioner, { alignItemWithTrigger: false, side: "bottom", align: "start", sideOffset: 4, className: stylex.props(styles.positioner).className, children: _jsx(BaseSelect.Popup, { render: (props, state) => (_jsx(Popup, { ...props, kind: "select", isOpen: state.open, transitionStatus: state.transitionStatus })), children: options.map((option) => (_jsxs(BaseSelect.Item, { value: option.value, render: (props, state) => (_jsx(PopupItem, { ...props, kind: "select", isHighlighted: state.highlighted })), children: [_jsx("span", { ...stylex.props(styles.indicator), children: _jsx(BaseSelect.ItemIndicator, { className: stylex.props(styles.check).className, children: _jsx(Icon, { name: "check" }) }) }), _jsx(BaseSelect.ItemText, { children: option.label })] }, option.value))) }) }) })] }));
17
18
  }
18
19
  const focusRing = `inset 0 0 0 ${borders.hairline} ${colors.brandBorderFocus}, 0 0 0 ${borders.thin} ${colors.brandBorderFocus}, ${shadows.default}`;
19
20
  const styles = stylex.create({
21
+ field: {
22
+ display: 'flex',
23
+ flexDirection: 'column',
24
+ gap: space.xs,
25
+ minWidth: 0
26
+ },
27
+ label: {
28
+ fontWeight: fontWeights.medium,
29
+ color: colors.primaryForeground
30
+ },
20
31
  trigger: {
21
32
  display: 'flex',
22
33
  flexShrink: 0,
@@ -2,13 +2,14 @@ export declare function monthOf(date: string): string;
2
2
  export declare function addDays(date: string, days: number): string;
3
3
  export declare function addMonths(date: string, months: number): string;
4
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)[])[];
5
+ export type WeekStart = 'monday' | 'sunday';
6
+ export declare function weekdayIndex(date: string, weekStart?: WeekStart): number;
7
+ export declare function weeksOf(month: string, weekStart?: WeekStart): readonly (readonly (string | null)[])[];
7
8
  export declare function localToday(): string;
8
9
  export declare function monthTitle(month: string, locale: string | undefined): string;
9
10
  export declare function dayLabel(date: string, locale: string | undefined): string;
10
11
  export declare function dayNumber(date: string, locale: string | undefined): string;
11
- export declare function weekdayNames(locale: string | undefined): readonly {
12
+ export declare function weekdayNames(locale: string | undefined, weekStart?: WeekStart): readonly {
12
13
  short: string;
13
14
  long: string;
14
15
  }[];
@@ -22,13 +22,14 @@ export function daysIn(month) {
22
22
  const start = utc(`${month}-01`);
23
23
  return new Date(Date.UTC(start.getUTCFullYear(), start.getUTCMonth() + 1, 0)).getUTCDate();
24
24
  }
25
- export function weekdayIndex(date) {
26
- return (utc(date).getUTCDay() + 6) % 7;
25
+ const SHIFTS = { monday: 6, sunday: 0 };
26
+ export function weekdayIndex(date, weekStart = 'monday') {
27
+ return (utc(date).getUTCDay() + SHIFTS[weekStart]) % 7;
27
28
  }
28
- export function weeksOf(month) {
29
+ export function weeksOf(month, weekStart = 'monday') {
29
30
  const first = `${month}-01`;
30
31
  const cells = [
31
- ...Array.from({ length: weekdayIndex(first) }, () => null),
32
+ ...Array.from({ length: weekdayIndex(first, weekStart) }, () => null),
32
33
  ...Array.from({ length: daysIn(month) }, (_, index) => addDays(first, index))
33
34
  ];
34
35
  const weeks = [];
@@ -64,8 +65,8 @@ export function dayNumber(date, locale) {
64
65
  timeZone: 'UTC'
65
66
  }).format(utc(date));
66
67
  }
67
- export function weekdayNames(locale) {
68
- const monday = '2024-01-01';
68
+ export function weekdayNames(locale, weekStart = 'monday') {
69
+ const first = weekStart === 'sunday' ? '2023-12-31' : '2024-01-01';
69
70
  const short = new Intl.DateTimeFormat(locale, {
70
71
  weekday: 'short',
71
72
  timeZone: 'UTC'
@@ -75,7 +76,7 @@ export function weekdayNames(locale) {
75
76
  timeZone: 'UTC'
76
77
  });
77
78
  return Array.from({ length: 7 }, (_, index) => {
78
- const day = utc(addDays(monday, index));
79
+ const day = utc(addDays(first, index));
79
80
  return {
80
81
  short: [...short.format(day)].slice(0, 2).join(''),
81
82
  long: long.format(day)
@@ -4,6 +4,7 @@ const APP_THEME_FILE = 'src/theme/theme.ts';
4
4
  const APP_COLORS_FILE = 'src/theme/colors.stylex.ts';
5
5
  const SCROLL_AREA_FILE = 'src/components/ScrollArea.tsx';
6
6
  const GALLERY_FILE = 'src/components/Gallery.tsx';
7
+ const DIALOG_FILE = 'src/components/Dialog.tsx';
7
8
  const SELECTABLE_FILE = 'src/components/Text.tsx';
8
9
  const PRIMITIVE_ELEMENTS = new Set([
9
10
  'button',
@@ -382,7 +383,9 @@ const hoverUsesHighlight = styleRule((declarations) => declarations
382
383
  message: HOVER_USES_HIGHLIGHT_MESSAGE
383
384
  })));
384
385
  const scrollViewOnly = styleRule((declarations, context) => {
385
- if (inFile(context, SCROLL_AREA_FILE) || inFile(context, GALLERY_FILE)) {
386
+ if (inFile(context, SCROLL_AREA_FILE) ||
387
+ inFile(context, GALLERY_FILE) ||
388
+ inFile(context, DIALOG_FILE)) {
386
389
  return [];
387
390
  }
388
391
  return declarations
package/dist/start.js CHANGED
@@ -55,6 +55,8 @@ function readInlineData() {
55
55
  }
56
56
  export function startApp(App, { theme = [], icons = {}, onInteraction } = {}) {
57
57
  setAppIcons(icons);
58
+ const rooted = stylex.props(theme, cornersFollowRadii).className ?? '';
59
+ document.documentElement.classList.add(...rooted.split(' ').filter(Boolean));
58
60
  document.body.className = stylex.props(base.body, theme).className ?? '';
59
61
  const hot = import.meta.hot;
60
62
  const testParams = new URLSearchParams(hot ? location.search : '');
@@ -163,6 +165,18 @@ function exposeToDevTools(app, gate, hot, world) {
163
165
  });
164
166
  });
165
167
  }
168
+ const cornersFollowRadii = stylex.createTheme(corners, {
169
+ buttonXs: radii.sm,
170
+ buttonSm: radii.md,
171
+ buttonMd: radii.md,
172
+ buttonLg: radii.lg,
173
+ buttonXl: radii.lg,
174
+ fieldXs: radii.sm,
175
+ fieldSm: radii.md,
176
+ fieldMd: radii.md,
177
+ fieldLg: radii.lg,
178
+ fieldXl: radii.lg
179
+ });
166
180
  const base = stylex.create({
167
181
  body: {
168
182
  fontFamily: fonts.sans,
@@ -183,6 +183,7 @@ export declare const corners: stylex.VarGroup<Readonly<{
183
183
  fieldMd: string;
184
184
  fieldLg: string;
185
185
  fieldXl: string;
186
+ checkbox: string;
186
187
  }>, symbol>;
187
188
  export declare const fontSizes: stylex.VarGroup<Readonly<{
188
189
  captionXs: string;
@@ -180,7 +180,8 @@ export const corners = stylex.defineVars({
180
180
  fieldSm: radii.md,
181
181
  fieldMd: radii.md,
182
182
  fieldLg: radii.lg,
183
- fieldXl: radii.lg
183
+ fieldXl: radii.lg,
184
+ checkbox: '4px'
184
185
  });
185
186
  export const fontSizes = stylex.defineVars({
186
187
  captionXs: '8px',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trypattern/sdk",
3
- "version": "0.1.37",
3
+ "version": "0.1.38",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",