@trypattern/sdk 0.1.8 → 0.1.10

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 (88) hide show
  1. package/README.md +37 -8
  2. package/dist/app.d.ts +1 -0
  3. package/dist/app.js +4 -3
  4. package/dist/cli/app.js +120 -7
  5. package/dist/cli/publishing.js +3 -1
  6. package/dist/components/AppFrame.d.ts +5 -1
  7. package/dist/components/AppFrame.js +25 -7
  8. package/dist/components/Appear.d.ts +4 -1
  9. package/dist/components/Appear.js +82 -3
  10. package/dist/components/Card.d.ts +7 -2
  11. package/dist/components/Card.js +59 -3
  12. package/dist/components/Checkbox.d.ts +10 -0
  13. package/dist/components/Checkbox.js +59 -0
  14. package/dist/components/Choice.d.ts +15 -0
  15. package/dist/components/Choice.js +80 -0
  16. package/dist/components/ChoiceGroup.d.ts +11 -0
  17. package/dist/components/ChoiceGroup.js +44 -0
  18. package/dist/components/Icon.d.ts +2 -1
  19. package/dist/components/Icon.js +2 -2
  20. package/dist/components/Image.d.ts +11 -0
  21. package/dist/components/Image.js +76 -0
  22. package/dist/components/Link.js +8 -3
  23. package/dist/components/ListRow.d.ts +2 -1
  24. package/dist/components/ListRow.js +7 -4
  25. package/dist/components/PlainScreen.d.ts +16 -0
  26. package/dist/components/PlainScreen.js +80 -0
  27. package/dist/components/PlainSidebar.d.ts +15 -0
  28. package/dist/components/PlainSidebar.js +179 -0
  29. package/dist/components/Screen.d.ts +3 -1
  30. package/dist/components/Screen.js +5 -1
  31. package/dist/components/Sidebar.js +2 -1
  32. package/dist/components/TextField.d.ts +3 -1
  33. package/dist/components/TextField.js +25 -4
  34. package/dist/components/choiceContext.d.ts +4 -0
  35. package/dist/components/choiceContext.js +7 -0
  36. package/dist/components/frame.d.ts +2 -0
  37. package/dist/components/icons.d.ts +3 -0
  38. package/dist/components/icons.js +4 -1
  39. package/dist/components/interaction.d.ts +1 -1
  40. package/dist/entityStore.d.ts +1 -0
  41. package/dist/entityStore.js +1 -1
  42. package/dist/index.d.ts +2 -0
  43. package/dist/index.js +1 -0
  44. package/dist/media.d.ts +36 -0
  45. package/dist/media.js +74 -0
  46. package/dist/patternAccess.d.ts +21 -0
  47. package/dist/patternAccess.js +110 -0
  48. package/dist/publishWire.d.ts +318 -0
  49. package/dist/publishWire.js +128 -1
  50. package/dist/react.d.ts +5 -0
  51. package/dist/react.js +4 -0
  52. package/dist/rules/checkApiRouting.js +1 -1
  53. package/dist/rules/lintPlugin.js +13 -4
  54. package/dist/rules/messages.d.ts +1 -0
  55. package/dist/rules/messages.js +1 -0
  56. package/dist/schema.d.ts +2 -0
  57. package/dist/schema.js +1 -0
  58. package/dist/server/createServer.d.ts +92 -6
  59. package/dist/server/createServer.js +38 -2
  60. package/dist/server/database.d.ts +74 -0
  61. package/dist/server/database.js +93 -0
  62. package/dist/server/env.d.ts +3 -1
  63. package/dist/server/imageHeader.d.ts +10 -0
  64. package/dist/server/imageHeader.js +159 -0
  65. package/dist/server/index.d.ts +6 -1
  66. package/dist/server/index.js +3 -0
  67. package/dist/server/jsonLd.d.ts +45 -0
  68. package/dist/server/jsonLd.js +88 -0
  69. package/dist/server/keyset.d.ts +13 -0
  70. package/dist/server/keyset.js +52 -0
  71. package/dist/server/media.d.ts +16 -0
  72. package/dist/server/media.js +135 -0
  73. package/dist/server/pages.d.ts +72 -0
  74. package/dist/server/pages.js +301 -0
  75. package/dist/server/patternKeys.d.ts +1 -0
  76. package/dist/server/patternKeys.js +3 -0
  77. package/dist/server/patternViewer.d.ts +6 -0
  78. package/dist/server/patternViewer.js +27 -0
  79. package/dist/server/services.js +1 -1
  80. package/dist/server/tables.d.ts +19 -3
  81. package/dist/server/tables.js +38 -14
  82. package/dist/serviceClients.js +3 -5
  83. package/dist/start.js +26 -1
  84. package/dist/table.d.ts +1 -0
  85. package/dist/table.js +8 -1
  86. package/dist/tables.d.ts +2 -1
  87. package/dist/tables.js +10 -1
  88. package/package.json +1 -1
@@ -0,0 +1,59 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Checkbox as BaseCheckbox } from '@base-ui/react/checkbox';
3
+ import * as stylex from '@stylexjs/stylex';
4
+ import { borders, colors, iconSizes, motion, radii, space } from "../theme/tokens.stylex.js";
5
+ import { focusRing } from "./controlLook.js";
6
+ import { interact } from "./interaction.js";
7
+ export function Checkbox({ label, checked, disabled = false, onChange, style }) {
8
+ return (_jsx(BaseCheckbox.Root, { "aria-label": label, checked: checked, disabled: disabled, onCheckedChange: (next) => {
9
+ interact({ primitive: 'Checkbox', event: 'change', label });
10
+ onChange(next);
11
+ }, className: (state) => stylex.props(styles.box, state.checked ? styles.on : styles.off, disabled && styles.disabled, focusRing.visible, style).className, children: _jsx(BaseCheckbox.Indicator, { className: stylex.props(styles.indicator).className, children: _jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3.25", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", ...stylex.props(styles.tick), children: _jsx("path", { d: "M5 12.5 9.5 17 19 7.5" }) }) }) }));
12
+ }
13
+ const styles = stylex.create({
14
+ box: {
15
+ position: 'relative',
16
+ display: 'grid',
17
+ flexShrink: 0,
18
+ placeItems: 'center',
19
+ width: iconSizes.md,
20
+ height: iconSizes.md,
21
+ padding: 0,
22
+ color: colors.onInvertedForeground,
23
+ outlineOffset: borders.thin,
24
+ borderRadius: radii.full,
25
+ transitionTimingFunction: motion.easeOut,
26
+ transitionDuration: motion.fast,
27
+ transitionProperty: 'background-color, box-shadow',
28
+ '::before': {
29
+ position: 'absolute',
30
+ inset: `calc(-1 * ${space.xs})`,
31
+ content: '""',
32
+ borderRadius: radii.full
33
+ }
34
+ },
35
+ off: {
36
+ backgroundColor: 'transparent',
37
+ boxShadow: `0 0 0 ${borders.thin} ${colors.borderStrong} inset, 0 ${borders.thin} ${borders.thin} ${colors.borderSubtle}`
38
+ },
39
+ on: {
40
+ backgroundColor: colors.invertedSolid,
41
+ backgroundImage: `linear-gradient(180deg, color-mix(in oklab, ${colors.whiteFill} 15%, transparent), transparent)`,
42
+ boxShadow: `0 ${borders.thin} 0 color-mix(in oklab, ${colors.whiteFill} 15%, transparent) inset, 0 ${borders.thin} 2px color-mix(in oklab, ${colors.blackFill} 20%, transparent), 0 0 0 ${borders.hairline} color-mix(in oklab, ${colors.blackFill} 40%, transparent)`
43
+ },
44
+ disabled: {
45
+ color: colors.disabledForeground,
46
+ backgroundColor: colors.disabled,
47
+ backgroundImage: 'none',
48
+ boxShadow: 'none'
49
+ },
50
+ indicator: {
51
+ display: 'grid',
52
+ placeItems: 'center'
53
+ },
54
+ tick: {
55
+ display: 'block',
56
+ width: `calc(${iconSizes.md} * 9 / 16)`,
57
+ height: `calc(${iconSizes.md} * 9 / 16)`
58
+ }
59
+ });
@@ -0,0 +1,15 @@
1
+ import type { ReactNode } from 'react';
2
+ type ChoiceProps = {
3
+ value: string;
4
+ subline?: string;
5
+ isDisabled?: boolean;
6
+ children?: ReactNode;
7
+ } & ({
8
+ title: string;
9
+ label?: string;
10
+ } | {
11
+ title?: never;
12
+ label: string;
13
+ });
14
+ export declare function Choice({ value, title, label, subline, isDisabled, children }: ChoiceProps): import("react").JSX.Element;
15
+ export {};
@@ -0,0 +1,80 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Radio as BaseRadio } from '@base-ui/react/radio';
3
+ import * as stylex from '@stylexjs/stylex';
4
+ import { borders, colors, fontSizes, fontWeights, lineHeights, motion, radii, shadows, space } from "../theme/tokens.stylex.js";
5
+ import { useChosen } from "./choiceContext.js";
6
+ import { focusRing } from "./controlLook.js";
7
+ export function Choice({ value, title, label, subline, isDisabled = false, children }) {
8
+ const chosen = useChosen();
9
+ const isFaded = chosen !== null && chosen !== value;
10
+ const hasWords = title !== undefined || subline !== undefined;
11
+ return (_jsxs(BaseRadio.Root, { value: value, disabled: isDisabled, "aria-label": label, className: (state) => stylex.props(styles.choice, children !== undefined && !hasWords && styles.media, !state.disabled && styles.enabled, state.checked && styles.checked, isFaded && !state.checked && !state.disabled && styles.faded, state.disabled && styles.disabled, focusRing.visible).className, children: [children === undefined ? null : (_jsx("span", { ...stylex.props(styles.content), children: children })), title === undefined ? null : (_jsx("span", { ...stylex.props(styles.title), children: title })), subline === undefined ? null : (_jsx("span", { ...stylex.props(styles.subline, isDisabled && styles.sublineDisabled), children: subline }))] }));
12
+ }
13
+ const checkedRing = `inset 0 0 0 ${borders.thin} ${colors.borderInverted}, 0 0 0 ${borders.thin} ${colors.borderInverted}`;
14
+ const styles = stylex.create({
15
+ choice: {
16
+ display: 'flex',
17
+ flexDirection: 'column',
18
+ gap: space.xxs,
19
+ alignItems: 'flex-start',
20
+ minWidth: 0,
21
+ paddingBlock: space.sm,
22
+ paddingInline: space.md,
23
+ fontSize: fontSizes.bodySm,
24
+ fontWeight: fontWeights.medium,
25
+ lineHeight: lineHeights.bodySm,
26
+ color: colors.primaryForeground,
27
+ textAlign: 'start',
28
+ outlineOffset: 0,
29
+ backgroundColor: colors.componentOnContainerStrong,
30
+ borderRadius: radii.lg,
31
+ boxShadow: shadows.default,
32
+ transitionTimingFunction: motion.easeOut,
33
+ transitionDuration: motion.fast,
34
+ transitionProperty: 'background-color, box-shadow, opacity'
35
+ },
36
+ media: {
37
+ flexShrink: 0,
38
+ width: `calc(2 * ${space.xxxl})`,
39
+ padding: space.xs
40
+ },
41
+ enabled: {
42
+ backgroundColor: {
43
+ default: colors.componentOnContainerStrong,
44
+ ':hover': colors.componentOnContainerStrongHover
45
+ }
46
+ },
47
+ checked: {
48
+ boxShadow: checkedRing
49
+ },
50
+ faded: {
51
+ opacity: {
52
+ default: 0.56,
53
+ ':hover': 1
54
+ }
55
+ },
56
+ disabled: {
57
+ color: colors.disabledForeground,
58
+ backgroundColor: colors.disabled,
59
+ boxShadow: 'none'
60
+ },
61
+ content: {
62
+ display: 'block',
63
+ alignSelf: 'stretch',
64
+ minWidth: 0,
65
+ overflow: 'hidden',
66
+ borderRadius: radii.md
67
+ },
68
+ title: {
69
+ minWidth: 0
70
+ },
71
+ subline: {
72
+ fontSize: fontSizes.captionLg,
73
+ fontWeight: fontWeights.normal,
74
+ lineHeight: lineHeights.caption,
75
+ color: colors.secondaryForeground
76
+ },
77
+ sublineDisabled: {
78
+ color: colors.disabledForeground
79
+ }
80
+ });
@@ -0,0 +1,11 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { Placement } from './Placement.ts';
3
+ type ChoiceGroupProps<Value extends string> = {
4
+ label: string;
5
+ value: Value | null;
6
+ onChange: (value: Value) => void;
7
+ children: ReactNode;
8
+ style?: Placement;
9
+ };
10
+ export declare function ChoiceGroup<Value extends string>({ label, value, onChange, children, style }: ChoiceGroupProps<Value>): import("react").JSX.Element;
11
+ export {};
@@ -0,0 +1,44 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { RadioGroup as BaseRadioGroup } from '@base-ui/react/radio-group';
3
+ import * as stylex from '@stylexjs/stylex';
4
+ import { Children, isValidElement } from 'react';
5
+ import { space } from "../theme/tokens.stylex.js";
6
+ import { ChoiceContext } from "./choiceContext.js";
7
+ import { interact, textOf } from "./interaction.js";
8
+ export function ChoiceGroup({ label, value, onChange, children, style }) {
9
+ return (_jsx(ChoiceContext, { value: { value }, children: _jsx(BaseRadioGroup, { "aria-label": label, value: value, onValueChange: (next) => {
10
+ if (typeof next !== 'string')
11
+ return;
12
+ interact({
13
+ primitive: 'ChoiceGroup',
14
+ event: 'change',
15
+ label: labelOf(children, next)
16
+ });
17
+ onChange(next);
18
+ }, className: stylex.props(styles.group, style).className, children: children }) }));
19
+ }
20
+ function labelOf(children, value) {
21
+ for (const child of Children.toArray(children)) {
22
+ if (!isValidElement(child))
23
+ continue;
24
+ const { props } = child;
25
+ if (props['value'] !== value)
26
+ continue;
27
+ for (const name of ['title', 'label']) {
28
+ const text = props[name];
29
+ if (typeof text === 'string' && text !== '')
30
+ return text;
31
+ }
32
+ return textOf(props['children']) || value;
33
+ }
34
+ return value;
35
+ }
36
+ const styles = stylex.create({
37
+ group: {
38
+ display: 'flex',
39
+ flexWrap: 'wrap',
40
+ gap: space.sm,
41
+ alignItems: 'stretch',
42
+ minWidth: 0
43
+ }
44
+ });
@@ -5,6 +5,7 @@ type IconProps = {
5
5
  name: IconName;
6
6
  size?: Size;
7
7
  tone?: Tone;
8
+ weight?: 'regular' | 'light';
8
9
  };
9
- export declare function Icon({ name, size, tone }: IconProps): import("react").JSX.Element;
10
+ export declare function Icon({ name, size, tone, weight }: IconProps): import("react").JSX.Element;
10
11
  export {};
@@ -3,9 +3,9 @@ import * as stylex from '@stylexjs/stylex';
3
3
  import { iconSizes } from "../theme/tokens.stylex.js";
4
4
  import { shapeOf } from "./icons.js";
5
5
  import { tones } from "./tones.js";
6
- export function Icon({ name, size = 'md', tone = 'inherit' }) {
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: "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) => (_jsx("path", { d: path }, path))) }));
9
9
  }
10
10
  const styles = stylex.create({
11
11
  icon: {
@@ -0,0 +1,11 @@
1
+ import type { MediaImage } from '../media.ts';
2
+ import type { Placement } from './Placement.ts';
3
+ type ImageProps = {
4
+ image: MediaImage | null | undefined;
5
+ sizes: string;
6
+ priority?: boolean;
7
+ aspect?: number;
8
+ style?: Placement;
9
+ };
10
+ export declare function Image({ image, sizes, priority, aspect, style }: ImageProps): import("react").JSX.Element;
11
+ export {};
@@ -0,0 +1,76 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as stylex from '@stylexjs/stylex';
3
+ import { useState } from 'react';
4
+ import { imageSources, transformsOn } from "../media.js";
5
+ import { colors, motion } from "../theme/tokens.stylex.js";
6
+ export function Image({ image, sizes, priority = false, aspect, style }) {
7
+ const key = image?.key ?? null;
8
+ const [seen, setSeen] = useState({
9
+ key,
10
+ status: 'loading'
11
+ });
12
+ const status = seen.key === key ? seen.status : 'loading';
13
+ if (image === null || image === undefined) {
14
+ return (_jsx("span", { "aria-hidden": "true", ...stylex.props(styles.frame, styles.ratio(aspect ?? MISSING_ASPECT), style) }));
15
+ }
16
+ const ratio = aspect ?? image.width / image.height;
17
+ if (status === 'failed') {
18
+ return (_jsx("span", { role: "img", "aria-label": image.alt, ...stylex.props(styles.frame, styles.ratio(ratio), style) }));
19
+ }
20
+ const sources = imageSources(image, {
21
+ aspect,
22
+ transforms: servedWithTransforms()
23
+ });
24
+ return (_jsxs("span", { ...stylex.props(styles.frame, styles.ratio(ratio), style), children: [image.placeholder === null ? null : (_jsx("span", { "aria-hidden": "true", ...stylex.props(styles.placeholder(image.placeholder)) })), _jsx("img", { ref: (element) => {
25
+ if (status === 'loading' &&
26
+ element !== null &&
27
+ element.complete &&
28
+ element.naturalWidth > 0) {
29
+ setSeen({ key, status: 'shown' });
30
+ }
31
+ }, alt: image.alt, width: sources.width, height: sources.height, loading: priority ? 'eager' : 'lazy', decoding: priority ? 'auto' : 'async', fetchPriority: priority ? 'high' : 'auto', sizes: sizes, srcSet: sources.srcSet, src: sources.src, onLoad: () => setSeen((current) => current.key === key && current.status === 'shown'
32
+ ? current
33
+ : { key, status: 'fading' }), onError: () => setSeen({ key, status: 'failed' }), ...stylex.props(styles.image, status === 'fading' && styles.fading, status === 'shown' && styles.shown) })] }));
34
+ }
35
+ const MISSING_ASPECT = 4 / 3;
36
+ function servedWithTransforms() {
37
+ return typeof location !== 'undefined' && transformsOn(location.hostname);
38
+ }
39
+ const styles = stylex.create({
40
+ frame: {
41
+ position: 'relative',
42
+ display: 'block',
43
+ width: '100%',
44
+ overflow: 'hidden',
45
+ backgroundColor: colors.component
46
+ },
47
+ ratio: (ratio) => ({
48
+ aspectRatio: String(ratio)
49
+ }),
50
+ placeholder: (url) => ({
51
+ position: 'absolute',
52
+ inset: 0,
53
+ backgroundImage: `url("${url}")`,
54
+ backgroundPosition: 'center',
55
+ backgroundSize: 'cover',
56
+ filter: 'blur(16px)',
57
+ transform: 'scale(1.1)'
58
+ }),
59
+ image: {
60
+ position: 'relative',
61
+ display: 'block',
62
+ width: '100%',
63
+ height: '100%',
64
+ objectFit: 'cover',
65
+ opacity: 0
66
+ },
67
+ fading: {
68
+ opacity: 1,
69
+ transitionTimingFunction: motion.easeOut,
70
+ transitionDuration: motion.base,
71
+ transitionProperty: 'opacity'
72
+ },
73
+ shown: {
74
+ opacity: 1
75
+ }
76
+ });
@@ -1,11 +1,11 @@
1
1
  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
- import { colors, motion, radii } from "../theme/tokens.stylex.js";
4
+ import { borders, colors, motion, radii } from "../theme/tokens.stylex.js";
5
5
  import { focusRing } from "./controlLook.js";
6
6
  import { interact, textOf } from "./interaction.js";
7
7
  export function Link({ to, href, tone = 'brand', children }) {
8
- const className = stylex.props(styles.link, looks[tone], focusRing.visible).className;
8
+ const className = stylex.props(styles.link, looks[tone], href !== undefined && styles.leaves, focusRing.visible).className;
9
9
  if (href !== undefined) {
10
10
  return (_jsx("a", { href: href, target: "_blank", rel: "noreferrer", onClick: () => interact({
11
11
  primitive: 'Link',
@@ -21,11 +21,16 @@ export function Link({ to, href, tone = 'brand', children }) {
21
21
  }
22
22
  const styles = stylex.create({
23
23
  link: {
24
- textDecoration: 'none',
24
+ textDecorationLine: 'none',
25
25
  borderRadius: radii.xs,
26
26
  transitionTimingFunction: motion.easeOut,
27
27
  transitionDuration: motion.fast,
28
28
  transitionProperty: 'color'
29
+ },
30
+ leaves: {
31
+ textDecorationLine: 'underline',
32
+ textDecorationThickness: borders.thin,
33
+ textUnderlineOffset: '0.25em'
29
34
  }
30
35
  });
31
36
  const looks = stylex.create({
@@ -4,9 +4,10 @@ type ListRowProps = {
4
4
  to?: AppPath;
5
5
  onClick?: () => void;
6
6
  isMuted?: boolean;
7
+ isCurrent?: boolean;
7
8
  leading?: ReactNode;
8
9
  trailing?: ReactNode;
9
10
  children: ReactNode;
10
11
  };
11
- export declare function ListRow({ to, onClick, isMuted, leading, trailing, children }: ListRowProps): import("react").JSX.Element;
12
+ export declare function ListRow({ to, onClick, isMuted, isCurrent, leading, trailing, children }: ListRowProps): import("react").JSX.Element;
12
13
  export {};
@@ -5,9 +5,9 @@ import { Link as RouterLink } from 'react-router';
5
5
  import { colors, controls, radii, space } from "../theme/tokens.stylex.js";
6
6
  import { focusRing } from "./controlLook.js";
7
7
  import { interact, textOf } from "./interaction.js";
8
- export function ListRow({ to, onClick, isMuted = false, leading, trailing, children }) {
8
+ export function ListRow({ to, onClick, isMuted = false, isCurrent = false, 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, (to !== undefined || onClick !== undefined) && styles.interactive, isMuted && styles.muted, focusRing.visible, focusRing.inside);
10
+ const look = stylex.props(styles.row, (to !== undefined || onClick !== undefined) && styles.interactive, isMuted && styles.muted, isCurrent && styles.current, focusRing.visible, focusRing.inside);
11
11
  const report = () => {
12
12
  interact({
13
13
  primitive: 'ListRow',
@@ -17,10 +17,10 @@ export function ListRow({ to, onClick, isMuted = false, leading, trailing, child
17
17
  onClick?.();
18
18
  };
19
19
  if (to !== undefined) {
20
- return (_jsx(RouterLink, { to: to, onClick: report, ...look, children: content }));
20
+ return (_jsx(RouterLink, { to: to, onClick: report, "aria-current": isCurrent ? 'page' : undefined, ...look, children: content }));
21
21
  }
22
22
  if (onClick !== undefined) {
23
- return (_jsx(BaseButton, { onClick: report, className: look.className, children: content }));
23
+ return (_jsx(BaseButton, { onClick: report, "aria-pressed": isCurrent, className: look.className, children: content }));
24
24
  }
25
25
  return _jsx("div", { ...look, children: content });
26
26
  }
@@ -46,6 +46,9 @@ const styles = stylex.create({
46
46
  muted: {
47
47
  color: colors.tertiaryForeground
48
48
  },
49
+ current: {
50
+ backgroundColor: colors.transparentHover
51
+ },
49
52
  main: {
50
53
  display: 'flex',
51
54
  flexGrow: 1,
@@ -0,0 +1,16 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { AppPath } from '../registered.ts';
3
+ type PlainScreenProps = {
4
+ title: string;
5
+ eyebrow: string | undefined;
6
+ parent: {
7
+ label: string;
8
+ to: AppPath;
9
+ } | undefined;
10
+ actions: ReactNode;
11
+ width: 'xs' | 'sm' | 'md' | 'lg' | 'full';
12
+ onToggleSidebar: () => void;
13
+ children: ReactNode;
14
+ };
15
+ export declare function PlainScreen({ title, eyebrow, parent, actions, width, onToggleSidebar, children }: PlainScreenProps): import("react").JSX.Element;
16
+ export {};
@@ -0,0 +1,80 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as stylex from '@stylexjs/stylex';
3
+ import { breakpoints, controls, space, widths } from "../theme/tokens.stylex.js";
4
+ import { Icon } from "./Icon.js";
5
+ import { IconButton } from "./IconButton.js";
6
+ import { Link } from "./Link.js";
7
+ import { ScrollArea } from "./ScrollArea.js";
8
+ import { Text } from "./Text.js";
9
+ export function PlainScreen({ title, eyebrow, parent, actions, width, onToggleSidebar, children }) {
10
+ return (_jsxs("div", { ...stylex.props(styles.screen), children: [_jsx("div", { ...stylex.props(styles.bar), children: _jsx(IconButton, { icon: "panelLeft", label: "Toggle sidebar", onClick: onToggleSidebar }) }), _jsx(ScrollArea, { style: styles.body, children: _jsx("div", { ...stylex.props(styles.page), children: _jsxs("div", { ...stylex.props(styles.column, columnWidths[width]), children: [_jsxs("header", { ...stylex.props(styles.header), children: [_jsxs("div", { ...stylex.props(styles.heading), children: [parent === undefined ? null : (_jsxs("span", { ...stylex.props(styles.parent), children: [_jsx(Link, { to: parent.to, tone: "secondary", children: parent.label }), _jsx(Icon, { name: "chevronRight", tone: "tertiary" })] })), parent !== undefined || eyebrow === undefined ? null : (_jsx(Text, { tone: "secondary", children: eyebrow })), _jsx(Text, { as: "h1", variant: "heading", tone: "primary", isSelectable: true, children: title })] }), actions === undefined || actions === null ? null : (_jsx("div", { ...stylex.props(styles.actions), children: actions }))] }), children] }) }) })] }));
11
+ }
12
+ const styles = stylex.create({
13
+ screen: {
14
+ display: 'flex',
15
+ flexDirection: 'column',
16
+ height: '100%'
17
+ },
18
+ bar: {
19
+ display: {
20
+ default: 'none',
21
+ [breakpoints.compact]: 'flex'
22
+ },
23
+ flexShrink: 0,
24
+ alignItems: 'center',
25
+ height: `calc(${controls.heightXl} + ${space.sm})`,
26
+ paddingInline: space.sm
27
+ },
28
+ body: {
29
+ flexGrow: 1,
30
+ height: 'auto'
31
+ },
32
+ page: {
33
+ paddingInline: {
34
+ default: space.xxxl,
35
+ [breakpoints.compact]: space.lg
36
+ },
37
+ paddingTop: {
38
+ default: `calc(${space.xxxl} + ${space.sm})`,
39
+ [breakpoints.compact]: space.sm
40
+ },
41
+ paddingBottom: `calc(${space.xxxl} * 2)`
42
+ },
43
+ column: {
44
+ display: 'flex',
45
+ flexDirection: 'column',
46
+ gap: space.xl,
47
+ width: '100%',
48
+ marginInline: 'auto'
49
+ },
50
+ header: {
51
+ display: 'flex',
52
+ gap: space.md,
53
+ alignItems: 'flex-end',
54
+ justifyContent: 'space-between'
55
+ },
56
+ heading: {
57
+ display: 'flex',
58
+ flexDirection: 'column',
59
+ gap: space.xxs,
60
+ minWidth: 0
61
+ },
62
+ parent: {
63
+ display: 'flex',
64
+ gap: space.xs,
65
+ alignItems: 'center'
66
+ },
67
+ actions: {
68
+ display: 'flex',
69
+ flexShrink: 0,
70
+ gap: space.sm,
71
+ alignItems: 'center'
72
+ }
73
+ });
74
+ const columnWidths = stylex.create({
75
+ xs: { maxWidth: widths.contentXs },
76
+ sm: { maxWidth: widths.contentSm },
77
+ md: { maxWidth: widths.contentMd },
78
+ lg: { maxWidth: widths.contentLg },
79
+ full: { maxWidth: 'none' }
80
+ });
@@ -0,0 +1,15 @@
1
+ import type { User } from '../auth/user.ts';
2
+ import type { MenuEntry } from './MenuItems.tsx';
3
+ import type { SidebarLink } from './Sidebar.tsx';
4
+ type PlainSidebarProps = {
5
+ title: string;
6
+ user: User | null;
7
+ accountMenu: readonly MenuEntry[];
8
+ links: readonly SidebarLink[];
9
+ isToggled: boolean;
10
+ isAnimating: boolean;
11
+ onFollowLink: () => void;
12
+ onSearch: (() => void) | undefined;
13
+ };
14
+ export declare function PlainSidebar({ title, user, accountMenu, links, isToggled, isAnimating, onFollowLink, onSearch }: PlainSidebarProps): import("react").JSX.Element;
15
+ export {};