@astryxdesign/cli 0.1.8-canary.0db5dfd → 0.1.8-canary.17d83c9

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.
@@ -6,6 +6,12 @@ import {findShowcase, findRelatedBlocks} from '../../api/template/template.mjs';
6
6
 
7
7
  const CWD = {cwd: '.'};
8
8
 
9
+ // These cases resolve components by walking the source tree and importing
10
+ // every `.doc.mjs`, which takes several seconds and gets slower under the
11
+ // full-suite parallel load — enough to cross the default 5s per-test limit.
12
+ // Give the filesystem scans the same generous budget the spawned-CLI cases use.
13
+ const SCAN_TIMEOUT = 30_000;
14
+
9
15
  // ─── Bug: sub-component doc resolution ──────────────────────────
10
16
  // When asking for a sub-component (Code, HStack, Heading, SideNavItem),
11
17
  // the API should scope the response to that specific sub-component,
@@ -68,7 +74,7 @@ describe('component() sub-component scoping', () => {
68
74
  const result = await component('SideNav', CWD);
69
75
  expect(result.data.name).toBe('SideNav');
70
76
  });
71
- });
77
+ }, SCAN_TIMEOUT);
72
78
 
73
79
  // ─── Bug: findShowcase priority ─────────────────────────────────
74
80
  // findShowcase should prioritize exact directory matches over
@@ -111,7 +117,7 @@ describe('findShowcase() priority', () => {
111
117
  const result = await findShowcase('NonExistentWidget');
112
118
  expect(result).toBeNull();
113
119
  });
114
- });
120
+ }, SCAN_TIMEOUT);
115
121
 
116
122
  // ─── Feature: component() → blocks (showcase, examples, related) ─
117
123
  // The blocks API returns three separate lists so consumers can use
@@ -174,4 +180,4 @@ describe('component() blocks integration', () => {
174
180
  expect(result.data.showcase.name).toBe('ThemeShowcase');
175
181
  expect(result.data.showcase.isShowcase).toBe(true);
176
182
  });
177
- });
183
+ }, SCAN_TIMEOUT);
@@ -22,6 +22,13 @@ const CLI_BIN = path.resolve(__dirname, '../../bin/astryx.mjs');
22
22
  const REPO_ROOT = path.resolve(__dirname, '../../../..');
23
23
  const OPTS = {cwd: REPO_ROOT};
24
24
 
25
+ // The API-level search walks the source tree and imports every `.doc.mjs` to
26
+ // build its index; that takes several seconds and gets slower under the
27
+ // full-suite parallel load — enough to cross the default 5s per-test limit.
28
+ // The CLI-level cases spawn a subprocess (its own 30s cap) but still run under
29
+ // the vitest per-test timeout. Give both the same generous scan budget.
30
+ const SCAN_TIMEOUT = 30_000;
31
+
25
32
  function runCli(args) {
26
33
  const res = spawnSync('node', [CLI_BIN, ...args], {
27
34
  cwd: REPO_ROOT,
@@ -52,7 +59,7 @@ describe('search() API — ranking', () => {
52
59
  expect(iconButton.score).toBeGreaterThanOrEqual(70);
53
60
  expect(iconButton.reason.toLowerCase()).toContain('keyword');
54
61
  });
55
- });
62
+ }, SCAN_TIMEOUT);
56
63
 
57
64
  describe('search() API — cross-domain', () => {
58
65
  it('returns results from more than one domain for a broad query', async () => {
@@ -74,7 +81,7 @@ describe('search() API — cross-domain', () => {
74
81
  expect(r.command.length).toBeGreaterThan(0);
75
82
  }
76
83
  });
77
- });
84
+ }, SCAN_TIMEOUT);
78
85
 
79
86
  describe('search() API — filters', () => {
80
87
  it('--type component returns only components', async () => {
@@ -100,7 +107,7 @@ describe('search() API — filters', () => {
100
107
  it('rejects an unknown --type', async () => {
101
108
  await expect(search('x', {...OPTS, type: 'bogus'})).rejects.toThrow(/Unknown --type/);
102
109
  });
103
- });
110
+ }, SCAN_TIMEOUT);
104
111
 
105
112
  describe('search() API — fuzzy / typo tolerance', () => {
106
113
  it('finds Button for the typo "buton"', async () => {
@@ -109,7 +116,7 @@ describe('search() API — fuzzy / typo tolerance', () => {
109
116
  expect(button).toBeTruthy();
110
117
  expect(button.domain).toBe('component');
111
118
  });
112
- });
119
+ }, SCAN_TIMEOUT);
113
120
 
114
121
  describe('search() API — empty + envelope', () => {
115
122
  it('returns an empty result set (not an error) for a no-match query', async () => {
@@ -135,7 +142,7 @@ describe('search() API — empty + envelope', () => {
135
142
  expect(top).toHaveProperty('description');
136
143
  expect(top).toHaveProperty('command');
137
144
  });
138
- });
145
+ }, SCAN_TIMEOUT);
139
146
 
140
147
  describe('scoreCandidate()', () => {
141
148
  it('scores an exact name match at 100', () => {
@@ -199,4 +206,4 @@ describe('search CLI — exit codes + JSON contract', () => {
199
206
  expect(r.stdout).toContain('astryx component Button');
200
207
  expect(r.stdout).toContain('[component]');
201
208
  });
202
- });
209
+ }, SCAN_TIMEOUT);
@@ -56,7 +56,7 @@ export const docs = {
56
56
  [
57
57
  'low',
58
58
  'The component is in the normal page flow but should read as distinct from the background. Use for emphasis or to separate the component from the surface behind it — the component still sits on the page, it is not floating over other content.',
59
- 'A raised Card that needs emphasis, a ChatComposer, a resting Thumbnail',
59
+ 'A raised Card that needs emphasis, a ChatComposer',
60
60
  ],
61
61
  [
62
62
  'med',
@@ -82,11 +82,11 @@ export const docs = {
82
82
  content: [
83
83
  {
84
84
  type: 'prose',
85
- text: 'Configurable surfaces expose a single `elevation` prop instead of asking consumers to hand-write a box-shadow. It takes the graded enum `none | low | med | high`, narrowed per component to the steps that surface needs: Card, ClickableCard, SelectableCard, Button, IconButton, ButtonGroup, Thumbnail, and Banner expose the full scale, while ChatComposer exposes only `none | low`. `none` is a flat literal (`box-shadow: none`); the other levels map to the `--shadow-*` tokens above, so a surface stays theme-agnostic.',
85
+ text: 'Configurable surfaces expose a single `elevation` prop instead of asking consumers to hand-write a box-shadow. It takes the graded enum `none | low | med | high`, narrowed per component to the steps that surface needs: Card, ClickableCard, SelectableCard, Button, IconButton, ButtonGroup, and Banner expose the full scale, while ChatComposer exposes only `none | low`. `none` is a flat literal (`box-shadow: none`); the other levels map to the `--shadow-*` tokens above, so a surface stays theme-agnostic.',
86
86
  },
87
87
  {
88
88
  type: 'prose',
89
- text: 'Prop defaults preserve current appearance: every surface defaults to `none` except ChatComposer, which defaults to `low` to keep its raised look. Set `elevation="none"` to flatten it — the flat composer draws a border with the same rest / hover / focus treatment as a text input. Thumbnail keeps its existing hover-only shadow at the `none` default.',
89
+ text: 'Prop defaults preserve current appearance: every surface defaults to `none` except ChatComposer, which defaults to `low` to keep its raised look. Set `elevation="none"` to flatten it — the flat composer draws a border with the same rest / hover / focus treatment as a text input.',
90
90
  },
91
91
  {
92
92
  type: 'code',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/cli",
3
- "version": "0.1.8-canary.0db5dfd",
3
+ "version": "0.1.8-canary.17d83c9",
4
4
  "displayName": "CLI",
5
5
  "description": "Scaffold projects, browse templates, generate themes, and get agent-ready docs from the command line.",
6
6
  "author": "Meta Open Source",
@@ -86,10 +86,10 @@
86
86
  "zod": "^4.4.3"
87
87
  },
88
88
  "peerDependencies": {
89
- "@astryxdesign/charts": "0.1.8-canary.0db5dfd",
90
- "@astryxdesign/core": "0.1.8-canary.0db5dfd",
91
- "@astryxdesign/lab": "0.1.8-canary.0db5dfd",
92
- "@astryxdesign/theme-neutral": "0.1.8-canary.0db5dfd",
89
+ "@astryxdesign/charts": "0.1.8-canary.17d83c9",
90
+ "@astryxdesign/core": "0.1.8-canary.17d83c9",
91
+ "@astryxdesign/lab": "0.1.8-canary.17d83c9",
92
+ "@astryxdesign/theme-neutral": "0.1.8-canary.17d83c9",
93
93
  "gpt-tokenizer": "^3.4.0"
94
94
  },
95
95
  "peerDependenciesMeta": {
@@ -107,10 +107,10 @@
107
107
  }
108
108
  },
109
109
  "devDependencies": {
110
- "@astryxdesign/charts": "0.1.8-canary.0db5dfd",
111
- "@astryxdesign/core": "0.1.8-canary.0db5dfd",
112
- "@astryxdesign/lab": "0.1.8-canary.0db5dfd",
113
- "@astryxdesign/theme-neutral": "0.1.8-canary.0db5dfd",
110
+ "@astryxdesign/charts": "0.1.8-canary.17d83c9",
111
+ "@astryxdesign/core": "0.1.8-canary.17d83c9",
112
+ "@astryxdesign/lab": "0.1.8-canary.17d83c9",
113
+ "@astryxdesign/theme-neutral": "0.1.8-canary.17d83c9",
114
114
  "gpt-tokenizer": "^3.4.0"
115
115
  },
116
116
  "scripts": {
@@ -0,0 +1,14 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /** @type {import('../../../../../core/src/docs-types').TemplateDoc} */
4
+ export const doc = {
5
+ type: 'block',
6
+ exampleFor: 'Avatar',
7
+ name: 'Avatar — Tooltip',
8
+ displayName: 'Avatar — Tooltip',
9
+ description:
10
+ "By default an avatar shows its name in a tooltip on hover and keyboard focus. Pass a string to show custom text instead, or false to turn the tooltip off.",
11
+ isReady: true,
12
+ aspectRatio: 16 / 9,
13
+ componentsUsed: ['Avatar', 'Layout', 'Text'],
14
+ };
@@ -0,0 +1,47 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ import {Avatar} from '@astryxdesign/core/Avatar';
6
+ import {Stack} from '@astryxdesign/core/Layout';
7
+ import {Text} from '@astryxdesign/core/Text';
8
+
9
+ export default function AvatarTooltip() {
10
+ return (
11
+ <Stack direction="vertical" gap={5}>
12
+ <Stack direction="vertical" gap={2}>
13
+ <Text type="supporting" color="secondary">
14
+ Hover or focus to reveal each name
15
+ </Text>
16
+ <Stack direction="horizontal" gap={4} vAlign="center">
17
+ <Avatar
18
+ src="https://lookaside.facebook.com/assets/astryx/DATA-Ana-Thomas.png"
19
+ name="Ana Thomas"
20
+ size="xl"
21
+ />
22
+ <Avatar
23
+ src="https://lookaside.facebook.com/assets/astryx/DATA-Drew-Young.png"
24
+ name="Drew Young"
25
+ size="xl"
26
+ />
27
+ <Avatar
28
+ src="https://lookaside.facebook.com/assets/astryx/DATA-Jihoo-Song.png"
29
+ name="Jihoo Song"
30
+ size="xl"
31
+ />
32
+ </Stack>
33
+ </Stack>
34
+ <Stack direction="vertical" gap={2}>
35
+ <Text type="supporting" color="secondary">
36
+ Custom tooltip text
37
+ </Text>
38
+ <Avatar
39
+ src="https://lookaside.facebook.com/assets/astryx/DATA-Itai-Jordaan.png"
40
+ name="Itai Jordaan"
41
+ size="xl"
42
+ tooltip="Itai Jordaan · Engineering Lead"
43
+ />
44
+ </Stack>
45
+ </Stack>
46
+ );
47
+ }
@@ -0,0 +1,14 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /** @type {import('../../../../../core/src/docs-types').TemplateDoc} */
4
+ export const doc = {
5
+ type: 'block',
6
+ exampleFor: 'Breadcrumbs',
7
+ name: 'Breadcrumbs — Menu item',
8
+ displayName: 'Breadcrumbs — Menu item',
9
+ description:
10
+ 'Give a mid-trail crumb a `menu` prop to turn it into a menu trigger for switching between sibling destinations. It reuses the same item API as DropdownMenu, so an existing option array (or composed item children) drops in verbatim.',
11
+ isReady: true,
12
+ aspectRatio: 16 / 9,
13
+ componentsUsed: ['Breadcrumbs'],
14
+ };
@@ -0,0 +1,26 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ import {
6
+ Breadcrumbs,
7
+ BreadcrumbItem,
8
+ type BreadcrumbMenuOption,
9
+ } from '@astryxdesign/core/Breadcrumbs';
10
+
11
+ const teamMenu: BreadcrumbMenuOption[] = [
12
+ {label: 'Design', onClick: () => {}},
13
+ {label: 'Engineering', onClick: () => {}},
14
+ {type: 'divider'},
15
+ {label: 'Data', onClick: () => {}},
16
+ ];
17
+
18
+ export default function BreadcrumbsMenuItem() {
19
+ return (
20
+ <Breadcrumbs>
21
+ <BreadcrumbItem href="/">Home</BreadcrumbItem>
22
+ <BreadcrumbItem menu={teamMenu}>Teams</BreadcrumbItem>
23
+ <BreadcrumbItem isCurrent>Overview</BreadcrumbItem>
24
+ </Breadcrumbs>
25
+ );
26
+ }
@@ -0,0 +1,14 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /** @type {import('../../../../../core/src/docs-types').TemplateDoc} */
4
+ export const doc = {
5
+ type: 'block',
6
+ exampleFor: 'DateInput',
7
+ name: 'DateInput — Formats',
8
+ displayName: 'DateInput — Formats',
9
+ description:
10
+ "The format prop reuses Timestamp's format vocabulary to control how the committed value is displayed — date, date_long (default), date_weekday, and system_date — or a function for a fully custom string. Formatting applies only to the committed value, never to text the user is actively typing.",
11
+ isReady: true,
12
+ aspectRatio: 16 / 9,
13
+ componentsUsed: ['DateInput', 'Layout', 'Text'],
14
+ };
@@ -0,0 +1,55 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ import {useState} from 'react';
6
+ import {DateInput} from '@astryxdesign/core/DateInput';
7
+ import {Stack} from '@astryxdesign/core/Layout';
8
+ import {Text} from '@astryxdesign/core/Text';
9
+
10
+ type DateString =
11
+ `${number}${number}${number}${number}-${number}${number}-${number}${number}`;
12
+
13
+ export default function DateInputFormats() {
14
+ const [value, setValue] = useState<DateString | undefined>(
15
+ '2026-03-21' as DateString,
16
+ );
17
+
18
+ return (
19
+ <Stack direction="vertical" gap={4} width="100%" style={{maxWidth: 400}}>
20
+ <Text type="supporting" color="secondary">
21
+ The same committed date, displayed with different formats.
22
+ </Text>
23
+ <DateInput
24
+ label="Short month (date)"
25
+ value={value}
26
+ onChange={setValue}
27
+ format="date"
28
+ />
29
+ <DateInput
30
+ label="Long month (date_long, default)"
31
+ value={value}
32
+ onChange={setValue}
33
+ format="date_long"
34
+ />
35
+ <DateInput
36
+ label="With weekday (date_weekday)"
37
+ value={value}
38
+ onChange={setValue}
39
+ format="date_weekday"
40
+ />
41
+ <DateInput
42
+ label="ISO 8601 (system_date)"
43
+ value={value}
44
+ onChange={setValue}
45
+ format="system_date"
46
+ />
47
+ <DateInput
48
+ label="Custom function"
49
+ value={value}
50
+ onChange={setValue}
51
+ format={iso => `Ship by ${iso}`}
52
+ />
53
+ </Stack>
54
+ );
55
+ }
@@ -23,9 +23,14 @@ export default function ThumbnailDisabled() {
23
23
  src={GOLDEN_SUNSET}
24
24
  alt="Golden sunset over mountains"
25
25
  label="golden-sunset.jpg"
26
+ showRemoveOn="always"
27
+ onRemove={() => {}}
28
+ />
29
+ <Thumbnail
30
+ label="document.pdf"
31
+ showRemoveOn="always"
26
32
  onRemove={() => {}}
27
33
  />
28
- <Thumbnail label="document.pdf" onRemove={() => {}} />
29
34
  </Stack>
30
35
  </Stack>
31
36
  <Stack direction="vertical" gap={1}>
@@ -66,6 +66,7 @@ export default function ThumbnailGallery() {
66
66
  src={item.src}
67
67
  alt={item.alt}
68
68
  label={item.label}
69
+ showRemoveOn="always"
69
70
  onClick={() => setSelected(item.label)}
70
71
  onRemove={() =>
71
72
  setItems(prev => prev.filter(i => i.id !== item.id))
@@ -65,6 +65,7 @@ export default function ThumbnailRemovable() {
65
65
  src={item.src}
66
66
  alt={item.alt}
67
67
  label={item.label}
68
+ showRemoveOn="always"
68
69
  onRemove={() =>
69
70
  setItems(prev => prev.filter(i => i.id !== item.id))
70
71
  }
@@ -17,6 +17,8 @@ export default function TimestampFormats() {
17
17
  </Text>
18
18
  <Stack direction="horizontal" gap={4} vAlign="center">
19
19
  <Timestamp value={DATE} format="date" color="primary" />
20
+ <Timestamp value={DATE} format="date_long" color="primary" />
21
+ <Timestamp value={DATE} format="date_weekday" color="primary" />
20
22
  <Timestamp value={DATE} format="date_time" color="primary" />
21
23
  <Timestamp value={DATE} format="time" color="primary" />
22
24
  </Stack>
@@ -26,9 +28,24 @@ export default function TimestampFormats() {
26
28
  System formats (logs and dev tools)
27
29
  </Text>
28
30
  <Stack direction="horizontal" gap={4} vAlign="center">
29
- <Timestamp value={DATE} format="system_date" type="code" color="primary" />
30
- <Timestamp value={DATE} format="system_date_time" type="code" color="primary" />
31
- <Timestamp value={DATE} format="system_time" type="code" color="primary" />
31
+ <Timestamp
32
+ value={DATE}
33
+ format="system_date"
34
+ type="code"
35
+ color="primary"
36
+ />
37
+ <Timestamp
38
+ value={DATE}
39
+ format="system_date_time"
40
+ type="code"
41
+ color="primary"
42
+ />
43
+ <Timestamp
44
+ value={DATE}
45
+ format="system_time"
46
+ type="code"
47
+ color="primary"
48
+ />
32
49
  </Stack>
33
50
  </Stack>
34
51
  </Stack>
@@ -1,14 +0,0 @@
1
- // Copyright (c) Meta Platforms, Inc. and affiliates.
2
-
3
- /** @type {import('../../../../../core/src/docs-types').TemplateDoc} */
4
- export const doc = {
5
- type: 'block',
6
- exampleFor: 'Thumbnail',
7
- name: 'Thumbnail — Elevated',
8
- displayName: 'Thumbnail — Elevated',
9
- description:
10
- 'Image tiles raised at rest with `elevation`. The default keeps the existing hover-only shadow; a set level lifts the tile off the page.',
11
- isReady: true,
12
- aspectRatio: 16 / 9,
13
- componentsUsed: ['Thumbnail', 'Layout', 'Text'],
14
- };
@@ -1,31 +0,0 @@
1
- // Copyright (c) Meta Platforms, Inc. and affiliates.
2
-
3
- 'use client';
4
-
5
- import {Thumbnail} from '@astryxdesign/core/Thumbnail';
6
- import {Stack} from '@astryxdesign/core/Layout';
7
- import {Text} from '@astryxdesign/core/Text';
8
-
9
- // Demo imagery is inlined as same-origin data URIs so the example is
10
- // self-contained. Thumbnail's remove-button overlay uses useImageMode, which
11
- // FETCHES the image to sample pixels (APCA) for contrast — a cross-origin CDN
12
- // URL without CORS headers cannot be sampled, so contrast detection fails
13
- // silently in hosted previews.
14
- const NIGHT_FOREST =
15
- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAwFBMVEX18+H08uDy8d/y8N/v7t/m5NXl49Tk4tPc3NDX1cnW1cnW1cjW1MjV1MjV1MfR0cXIyLzEw7m8vLC3t68wM0QvM0MvM0IvMkIuMkEtMEErLz8iJjkhJTggJTcgJDcfJDYfIzYeIjUcITMbHzIWHiwYGzIXGjEWGjAWGTAVGS8VGC8UGC4UGC0UFy4TFy0TFywTFi0SFiwRFSsQFSkNFR4QFCoPFCkPFCgPEykOEygOEigNEicNEScMESYIDw8ECgr+gzZIAAABqElEQVR42uWQ61aCQBRGD5GylNBMKS9FZgNdNE0cyUvB+79VM8MoF9Fgplau2j/8nO8c9hqAD0ngDwjeJYH1lrfBWoCtYDboNu/Zv7qQYNap1bpCN1gxFh1dNe5WAsCScWqoWttbChAKvHZZ0W6XQoIFpW8ooFmLCG2Rl1BgaZAU5Ac8yg0RlC9nngCRQDFuhQRzinWmkCuYk3lxQoFrlskVqlcTMcEFvYIKoFbNfmEFuIypWaGGkt66tqZuEbjAHZl6SQVF1WqNvpDAHVktXTvR9JbgDZii1+tZI7cYMJXkCASvksB4L5VxHmAsibzgRRIYbjgfCgFDSeBZkh8W1HMIniSBR0mOQPCQA3RgBk4M5DhNZwdEcbKgLXy5iDiZg5gApRYbqTql2FZgMxAKeEWSNUFYx3s2SfU28HPWItrpySSwE2cEdqrYtxgmxgHGScFmHrAGk8SxczIxZnNC1McFOGshShyb4yxB9sI3CXDGnH0MLsD7F5LvvptEgH12Zg1Pn2WuHsjvrwt8308t+nwxT38sgiAE8/RTeagH+vx/F8SeF0Ja8Ak14ia/LgmpZQAAAABJRU5ErkJggg==';
16
- const GOLDEN_SUNSET =
17
- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAkFBMVEX/+uv/7sj6tFr3sVn1r1nzrVjxq1jvqVftp1frpVbpo1bnoVXln1XjnVThm1TfmVPdl1PblVLZk1LXkVLVj1HTjVHRi1DPiVDNh0/LhU/Jg07HgU7Ff03DfU3Be0y/eUy9d0u7dUu5c0u2cEq0bkqybEmwakmuaEisZkiqZEeoYkemYEakXkaiXEVgLjQ8HCjaJlMkAAABI0lEQVR42u3Mx3qDMBSE0Z/03nsvdhxjcnn/twsYjISR5MUkO5+V9N2ZYUPEpogtEdsidkTsitgTsS/iQMShiCMRxyJORJyKOBNxLuJCxKWIKxHXIm5E3Iq4E3Ev4kHEo4gnEc8iXkS8inhLymrJBO8J2UIiw0dc5sRDfEbVRWr1o/pbMMWox9yz6zcLIzMbBTD2VaHu7fr1gjXGA3w5baj5+H0w6x09TDpdaP7rDZhn0sd3y89Y9fcHbPnoYdroZ2w6dQNmg6OHfG4QyrsBC8gdZpVQxtqF4M1mjepFURThTLNgMYsePxaX2WqY6D8GSm2grK2slbGBciHZ9hOE2smNpTuxenhieCdeH06E7qTqvYnImWTbbUSPlKL1wHrgTwZ+AWq+3H5MpRkwAAAAAElFTkSuQmCC';
18
-
19
- export default function ThumbnailElevated() {
20
- return (
21
- <Stack direction="vertical" gap={3}>
22
- <Text type="supporting" color="secondary">
23
- Raised tiles — `elevation` lifts an image off the page at rest
24
- </Text>
25
- <Stack direction="horizontal" gap={3} vAlign="center">
26
- <Thumbnail src={NIGHT_FOREST} alt="Forest at night" elevation="low" />
27
- <Thumbnail src={GOLDEN_SUNSET} alt="Golden sunset" elevation="high" />
28
- </Stack>
29
- </Stack>
30
- );
31
- }