@astryxdesign/cli 0.1.7 → 0.1.8-canary.0c4d8d7
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/CHANGELOG.md +40 -0
- package/README.md +115 -19
- package/docs/cli-integrations.doc.mjs +150 -0
- package/docs/elevation.doc.mjs +79 -1
- package/docs/getting-started.doc.mjs +9 -9
- package/docs/migration.doc.mjs +18 -18
- package/docs/principles.doc.dense.mjs +1 -1
- package/docs/principles.doc.mjs +6 -6
- package/docs/principles.doc.zh.mjs +1 -1
- package/docs/styling-libraries.doc.mjs +3 -3
- package/docs/styling.doc.mjs +4 -4
- package/docs/theme.doc.dense.mjs +2 -2
- package/docs/theme.doc.mjs +7 -7
- package/docs/theme.doc.zh.mjs +1 -1
- package/docs/tokens.doc.mjs +1 -1
- package/docs/working-with-ai.doc.mjs +19 -19
- package/package.json +13 -11
- package/scripts/postinstall.mjs +74 -0
- package/src/api/doctor.mjs +3 -3
- package/src/api/error.mjs +2 -2
- package/src/codemods/__tests__/registry.test.mjs +1 -0
- package/src/codemods/ensure-jscodeshift.mjs +11 -27
- package/src/codemods/registry.mjs +1 -0
- package/src/codemods/run-codemod.mjs +1 -1
- package/src/codemods/runner.mjs +2 -2
- package/src/codemods/transforms/v0.1.0/__tests__/drop-xds-prefix-imports.test.mjs +42 -7
- package/src/codemods/transforms/v0.1.0/__tests__/migrate-xds-module-specifiers.test.mjs +43 -0
- package/src/codemods/transforms/v0.1.0/drop-xds-prefix-imports.mjs +102 -3
- package/src/codemods/transforms/v0.1.0/migrate-xds-module-specifiers.mjs +72 -6
- package/src/codemods/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +161 -0
- package/src/codemods/transforms/v0.1.8/index.mjs +19 -0
- package/src/codemods/transforms/v0.1.8/rename-avatar-size-scale.mjs +234 -0
- package/src/commands/agent-docs.mjs +136 -20
- package/src/commands/agent-docs.test.mjs +123 -10
- package/src/commands/build-theme.mjs +10 -71
- package/src/commands/build.mjs +15 -15
- package/src/commands/cli-postinstall.test.mjs +42 -0
- package/src/commands/component/index.mjs +4 -4
- package/src/commands/discover.mjs +7 -5
- package/src/commands/docs.mjs +4 -4
- package/src/commands/hook/index.mjs +4 -4
- package/src/commands/init.mjs +48 -152
- package/src/commands/init.next-steps.test.mjs +1 -1
- package/src/commands/interactive-guard.test.mjs +19 -22
- package/src/commands/json-contract.test.mjs +2 -2
- package/src/commands/layout.mjs +1 -1
- package/src/commands/search.mjs +4 -4
- package/src/commands/setup-nudge.test.mjs +108 -0
- package/src/commands/swizzle.mjs +12 -35
- package/src/commands/template.mjs +11 -31
- package/src/commands/upgrade.mjs +138 -32
- package/src/commands/upgrade.test.mjs +155 -1
- package/src/index.mjs +40 -6
- package/src/lib/cli-error.mjs +2 -2
- package/src/lib/component-format.mjs +2 -1
- package/src/lib/json-shim.mjs +1 -1
- package/src/lib/json.mjs +3 -3
- package/src/lib/term-log.mjs +48 -0
- package/src/types/api.d.ts +4 -9
- package/src/types/base.d.ts +24 -3
- package/src/types/build.d.ts +23 -0
- package/src/types/index.d.ts +1 -0
- package/src/types/swizzle.d.ts +4 -0
- package/src/types/template-api.d.ts +4 -1
- package/src/types/upgrade.d.ts +39 -2
- package/src/utils/package-manager.mjs +108 -4
- package/src/utils/package-manager.test.mjs +108 -1
- package/src/utils/path-safety.mjs +0 -18
- package/src/utils/update-check.mjs +5 -4
- package/src/utils/update-check.test.mjs +3 -3
- package/templates/blocks/components/Avatar/AvatarFallbackChain.tsx +4 -4
- package/templates/blocks/components/Avatar/AvatarGroup.tsx +2 -2
- package/templates/blocks/components/Avatar/AvatarInitialsFallback.tsx +1 -1
- package/templates/blocks/components/Avatar/AvatarShowcase.tsx +4 -4
- package/templates/blocks/components/Avatar/AvatarUserCard.tsx +1 -1
- package/templates/blocks/components/Avatar/AvatarWithImage.tsx +4 -4
- package/templates/blocks/components/Avatar/AvatarWithStatus.tsx +3 -3
- package/templates/blocks/components/AvatarGroup/AvatarGroupShowcase.tsx +2 -2
- package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowCustomText.tsx +1 -1
- package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowDefault.tsx +1 -1
- package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowShowcase.tsx +2 -2
- package/templates/blocks/components/AvatarStatusDot/AvatarStatusDotShowcase.tsx +3 -3
- package/templates/blocks/components/AvatarStatusDot/AvatarStatusDotVariants.tsx +3 -3
- package/templates/blocks/components/Banner/BannerFloating.doc.mjs +14 -0
- package/templates/blocks/components/Banner/BannerFloating.tsx +16 -0
- package/templates/blocks/components/Button/ButtonFloating.doc.mjs +14 -0
- package/templates/blocks/components/Button/ButtonFloating.tsx +37 -0
- package/templates/blocks/components/ButtonGroup/ButtonGroupFloating.doc.mjs +14 -0
- package/templates/blocks/components/ButtonGroup/ButtonGroupFloating.tsx +23 -0
- package/templates/blocks/components/Card/CardElevations.doc.mjs +14 -0
- package/templates/blocks/components/Card/CardElevations.tsx +32 -0
- package/templates/blocks/components/Card/ClickableCardElevated.doc.mjs +14 -0
- package/templates/blocks/components/Card/ClickableCardElevated.tsx +21 -0
- package/templates/blocks/components/Card/SelectableCardElevated.doc.mjs +14 -0
- package/templates/blocks/components/Card/SelectableCardElevated.tsx +37 -0
- package/templates/blocks/components/Carousel/CarouselSnap.tsx +1 -1
- package/templates/blocks/components/ChatComposer/ChatComposerFlat.doc.mjs +14 -0
- package/templates/blocks/components/ChatComposer/ChatComposerFlat.tsx +75 -0
- package/templates/blocks/components/ChatMessage/ChatMessageAvatarName.tsx +2 -2
- package/templates/blocks/components/ChatMessage/ChatMessageMultiBubble.tsx +1 -1
- package/templates/blocks/components/ChatMessageBubble/ChatMessageBubbleGrouping.tsx +1 -1
- package/templates/blocks/components/ChatMessageBubble/ChatMessageBubbleMetadata.tsx +1 -1
- package/templates/blocks/components/ChatMessageList/ChatMessageListDensity.tsx +5 -9
- package/templates/blocks/components/ChatMessageList/ChatMessageListFullFeatured.tsx +1 -1
- package/templates/blocks/components/CodeBlock/CodeBlockTerminal.tsx +1 -1
- package/templates/blocks/components/HoverCard/HoverCardShowcase.tsx +1 -1
- package/templates/blocks/components/IconButton/IconButtonFloating.doc.mjs +14 -0
- package/templates/blocks/components/IconButton/IconButtonFloating.tsx +37 -0
- package/templates/blocks/components/Item/ItemWithMedia.tsx +2 -2
- package/templates/blocks/components/ListItem/ListItemWithMedia.tsx +2 -2
- package/templates/blocks/components/OverflowList/OverflowListCappedToolbar.doc.mjs +14 -0
- package/templates/blocks/components/OverflowList/OverflowListCappedToolbar.tsx +39 -0
- package/templates/blocks/components/OverflowList/OverflowListMultiRowTags.doc.mjs +14 -0
- package/templates/blocks/components/OverflowList/OverflowListMultiRowTags.tsx +44 -0
- package/templates/blocks/components/Pagination/PaginationDotsCarousel.tsx +2 -6
- package/templates/blocks/components/Stack/StackFillItem.tsx +2 -6
- package/templates/blocks/components/TabList/TabListTabsWithActions.doc.mjs +1 -1
- package/templates/blocks/components/TabList/TabListTabsWithActions.tsx +2 -7
- package/templates/blocks/components/Table/TableRowStatusTable.doc.mjs +14 -0
- package/templates/blocks/components/Table/TableRowStatusTable.tsx +59 -0
- package/templates/blocks/components/Thumbnail/ThumbnailElevated.doc.mjs +14 -0
- package/templates/blocks/components/Thumbnail/ThumbnailElevated.tsx +31 -0
- package/templates/blocks/components/TypeaheadItem/TypeaheadItemShowcase.tsx +1 -1
- package/templates/pages/ai-chat/page.tsx +4 -4
- package/templates/pages/dashboard-portfolio/page.tsx +3 -11
- package/templates/pages/detail-page/page.tsx +5 -12
- package/templates/pages/documentation-design/page.tsx +1 -1
- package/templates/pages/messaging-shell/page.tsx +6 -8
- package/templates/pages/table-grouped/page.tsx +9 -14
- package/templates/pages/table-page/page.tsx +7 -9
- package/templates/pages/table-page-heatmap-status/page.tsx +5 -13
- package/docs/integration-authoring.md +0 -105
- package/src/utils/interactive.mjs +0 -76
- package/src/utils/interactive.test.mjs +0 -70
|
@@ -337,7 +337,7 @@ function StreamMessageGroup({message}: {message: StreamMessage}) {
|
|
|
337
337
|
return (
|
|
338
338
|
<ChatMessage
|
|
339
339
|
sender={isSelf ? 'user' : 'assistant'}
|
|
340
|
-
avatar={isSelf ? undefined : <Avatar name={user.name} size="
|
|
340
|
+
avatar={isSelf ? undefined : <Avatar name={user.name} size="md" />}>
|
|
341
341
|
{message.bubbles.map((text, index) => (
|
|
342
342
|
<ChatMessageBubble
|
|
343
343
|
key={`${message.id}-${index}`}
|
|
@@ -395,7 +395,7 @@ export default function MessagingShellPage() {
|
|
|
395
395
|
|
|
396
396
|
const workspaceRail = (
|
|
397
397
|
<VStack gap={2} style={styles.rail}>
|
|
398
|
-
<Avatar name="Astryx HQ" size="
|
|
398
|
+
<Avatar name="Astryx HQ" size="md" />
|
|
399
399
|
{RAIL_ITEMS.map(item => (
|
|
400
400
|
<IconButton
|
|
401
401
|
key={item.id}
|
|
@@ -416,7 +416,7 @@ export default function MessagingShellPage() {
|
|
|
416
416
|
/>
|
|
417
417
|
<Avatar
|
|
418
418
|
name={USERS.you.name}
|
|
419
|
-
size="
|
|
419
|
+
size="md"
|
|
420
420
|
status={<AvatarStatusDot variant="success" label="Online" />}
|
|
421
421
|
/>
|
|
422
422
|
</VStack>
|
|
@@ -497,7 +497,7 @@ export default function MessagingShellPage() {
|
|
|
497
497
|
startContent={
|
|
498
498
|
<Avatar
|
|
499
499
|
name={USERS[dm.userId].name}
|
|
500
|
-
size="
|
|
500
|
+
size="sm"
|
|
501
501
|
status={
|
|
502
502
|
<AvatarStatusDot
|
|
503
503
|
variant={PRESENCE_VARIANT[dm.presence]}
|
|
@@ -600,9 +600,7 @@ export default function MessagingShellPage() {
|
|
|
600
600
|
<ChatMessageList density="compact">
|
|
601
601
|
<ChatMessage
|
|
602
602
|
sender="assistant"
|
|
603
|
-
avatar={
|
|
604
|
-
<Avatar name={USERS[THREAD_ROOT.userId].name} size="small" />
|
|
605
|
-
}>
|
|
603
|
+
avatar={<Avatar name={USERS[THREAD_ROOT.userId].name} size="md" />}>
|
|
606
604
|
<ChatMessageBubble
|
|
607
605
|
name={USERS[THREAD_ROOT.userId].name}
|
|
608
606
|
metadata={
|
|
@@ -622,7 +620,7 @@ export default function MessagingShellPage() {
|
|
|
622
620
|
<ChatMessage
|
|
623
621
|
key={reply.id}
|
|
624
622
|
sender="assistant"
|
|
625
|
-
avatar={<Avatar name={USERS[reply.userId].name} size="
|
|
623
|
+
avatar={<Avatar name={USERS[reply.userId].name} size="md" />}>
|
|
626
624
|
<ChatMessageBubble
|
|
627
625
|
name={USERS[reply.userId].name}
|
|
628
626
|
metadata={
|
|
@@ -22,7 +22,10 @@ import {Badge} from '@astryxdesign/core/Badge';
|
|
|
22
22
|
import {Avatar} from '@astryxdesign/core/Avatar';
|
|
23
23
|
import {Selector} from '@astryxdesign/core/Selector';
|
|
24
24
|
import {PowerSearch} from '@astryxdesign/core/PowerSearch';
|
|
25
|
-
import type {
|
|
25
|
+
import type {
|
|
26
|
+
PowerSearchConfig,
|
|
27
|
+
PowerSearchFilter,
|
|
28
|
+
} from '@astryxdesign/core/PowerSearch';
|
|
26
29
|
import {Dialog, DialogHeader} from '@astryxdesign/core/Dialog';
|
|
27
30
|
import {Popover} from '@astryxdesign/core/Popover';
|
|
28
31
|
import {RadioList, RadioListItem} from '@astryxdesign/core/RadioList';
|
|
@@ -798,19 +801,15 @@ function TaskDetailPanel({
|
|
|
798
801
|
</MetadataListItem>
|
|
799
802
|
<MetadataListItem label="Assignee">
|
|
800
803
|
<HStack gap={2} vAlign="center">
|
|
801
|
-
<Avatar name={task.assignee} size="
|
|
804
|
+
<Avatar name={task.assignee} size="sm" />
|
|
802
805
|
<Text type="body">{task.assignee}</Text>
|
|
803
806
|
</HStack>
|
|
804
807
|
</MetadataListItem>
|
|
805
808
|
<MetadataListItem label="Project">
|
|
806
809
|
{task.project || '\u2014'}
|
|
807
810
|
</MetadataListItem>
|
|
808
|
-
<MetadataListItem label="Created">
|
|
809
|
-
|
|
810
|
-
</MetadataListItem>
|
|
811
|
-
<MetadataListItem label="Updated">
|
|
812
|
-
{task.updated}
|
|
813
|
-
</MetadataListItem>
|
|
811
|
+
<MetadataListItem label="Created">{task.created}</MetadataListItem>
|
|
812
|
+
<MetadataListItem label="Updated">{task.updated}</MetadataListItem>
|
|
814
813
|
</MetadataList>
|
|
815
814
|
|
|
816
815
|
{task.tags.length > 0 && (
|
|
@@ -942,11 +941,7 @@ export default function DataTableTemplate() {
|
|
|
942
941
|
</RadioList>
|
|
943
942
|
</VStack>
|
|
944
943
|
}>
|
|
945
|
-
<Button
|
|
946
|
-
label="View Options"
|
|
947
|
-
variant="secondary"
|
|
948
|
-
size="md"
|
|
949
|
-
/>
|
|
944
|
+
<Button label="View Options" variant="secondary" size="md" />
|
|
950
945
|
</Popover>
|
|
951
946
|
</HStack>
|
|
952
947
|
</VStack>
|
|
@@ -1066,7 +1061,7 @@ export default function DataTableTemplate() {
|
|
|
1066
1061
|
</Text>
|
|
1067
1062
|
</TableCell>
|
|
1068
1063
|
<TableCell>
|
|
1069
|
-
<Avatar name={task.assignee} size="
|
|
1064
|
+
<Avatar name={task.assignee} size="sm" />
|
|
1070
1065
|
</TableCell>
|
|
1071
1066
|
<TableCell>
|
|
1072
1067
|
<DropdownMenu
|
|
@@ -16,7 +16,10 @@ import {Button} from '@astryxdesign/core/Button';
|
|
|
16
16
|
import {IconButton} from '@astryxdesign/core/IconButton';
|
|
17
17
|
import {Icon} from '@astryxdesign/core/Icon';
|
|
18
18
|
import {Avatar} from '@astryxdesign/core/Avatar';
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
PowerSearch,
|
|
21
|
+
usePowerSearchConfig,
|
|
22
|
+
} from '@astryxdesign/core/PowerSearch';
|
|
20
23
|
import type {PowerSearchFilter} from '@astryxdesign/core/PowerSearch';
|
|
21
24
|
import {Table, proportional, pixel} from '@astryxdesign/core/Table';
|
|
22
25
|
import type {TableColumn} from '@astryxdesign/core/Table';
|
|
@@ -353,7 +356,7 @@ const columns: TableColumn<DogRow>[] = [
|
|
|
353
356
|
width: proportional(2),
|
|
354
357
|
renderCell: (item: DogRow) => (
|
|
355
358
|
<HStack gap={3} vAlign="center">
|
|
356
|
-
<Avatar name={item.name} size="
|
|
359
|
+
<Avatar name={item.name} size="md" />
|
|
357
360
|
<VStack gap={0}>
|
|
358
361
|
<Text type="body">{item.name}</Text>
|
|
359
362
|
<Text type="supporting" color="secondary">
|
|
@@ -367,9 +370,7 @@ const columns: TableColumn<DogRow>[] = [
|
|
|
367
370
|
key: 'biography',
|
|
368
371
|
header: 'Biography',
|
|
369
372
|
width: proportional(5),
|
|
370
|
-
renderCell: (item: DogRow) =>
|
|
371
|
-
<Text type="body">{item.biography}</Text>
|
|
372
|
-
),
|
|
373
|
+
renderCell: (item: DogRow) => <Text type="body">{item.biography}</Text>,
|
|
373
374
|
},
|
|
374
375
|
{
|
|
375
376
|
key: 'age',
|
|
@@ -406,10 +407,7 @@ export default function TablePageTemplate() {
|
|
|
406
407
|
icon={<Icon icon={ArrowDownTrayIcon} size="sm" />}
|
|
407
408
|
variant="ghost"
|
|
408
409
|
/>
|
|
409
|
-
<Button
|
|
410
|
-
label="Add"
|
|
411
|
-
icon={<Icon icon={PlusIcon} size="sm" />}
|
|
412
|
-
/>
|
|
410
|
+
<Button label="Add" icon={<Icon icon={PlusIcon} size="sm" />} />
|
|
413
411
|
</HStack>
|
|
414
412
|
</LayoutHeader>
|
|
415
413
|
}
|
|
@@ -338,17 +338,13 @@ const columns: TableColumn<IncidentRow>[] = [
|
|
|
338
338
|
key: 'product',
|
|
339
339
|
header: 'Product',
|
|
340
340
|
width: proportional(2),
|
|
341
|
-
renderCell: (item: IncidentRow) =>
|
|
342
|
-
<Text type="body">{item.product}</Text>
|
|
343
|
-
),
|
|
341
|
+
renderCell: (item: IncidentRow) => <Text type="body">{item.product}</Text>,
|
|
344
342
|
},
|
|
345
343
|
{
|
|
346
344
|
key: 'title',
|
|
347
345
|
header: 'Description',
|
|
348
346
|
width: proportional(5),
|
|
349
|
-
renderCell: (item: IncidentRow) =>
|
|
350
|
-
<Text type="body">{item.title}</Text>
|
|
351
|
-
),
|
|
347
|
+
renderCell: (item: IncidentRow) => <Text type="body">{item.title}</Text>,
|
|
352
348
|
},
|
|
353
349
|
{
|
|
354
350
|
key: 'startTime',
|
|
@@ -362,9 +358,7 @@ const columns: TableColumn<IncidentRow>[] = [
|
|
|
362
358
|
key: 'duration',
|
|
363
359
|
header: 'Duration',
|
|
364
360
|
width: pixel(100),
|
|
365
|
-
renderCell: (item: IncidentRow) =>
|
|
366
|
-
<Text type="body">{item.duration}</Text>
|
|
367
|
-
),
|
|
361
|
+
renderCell: (item: IncidentRow) => <Text type="body">{item.duration}</Text>,
|
|
368
362
|
},
|
|
369
363
|
{
|
|
370
364
|
key: 'oncall',
|
|
@@ -375,7 +369,7 @@ const columns: TableColumn<IncidentRow>[] = [
|
|
|
375
369
|
<Avatar
|
|
376
370
|
name={item.oncall}
|
|
377
371
|
src={ONCALL_AVATARS[item.oncall]}
|
|
378
|
-
size="
|
|
372
|
+
size="sm"
|
|
379
373
|
/>
|
|
380
374
|
<Text type="body">{item.oncall}</Text>
|
|
381
375
|
</HStack>
|
|
@@ -396,9 +390,7 @@ const columns: TableColumn<IncidentRow>[] = [
|
|
|
396
390
|
key: 'date',
|
|
397
391
|
header: 'Date',
|
|
398
392
|
width: pixel(110),
|
|
399
|
-
renderCell: (item: IncidentRow) =>
|
|
400
|
-
<Text type="body">{item.date}</Text>
|
|
401
|
-
),
|
|
393
|
+
renderCell: (item: IncidentRow) => <Text type="body">{item.date}</Text>,
|
|
402
394
|
},
|
|
403
395
|
];
|
|
404
396
|
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
# Authoring an Astryx Integration
|
|
2
|
-
|
|
3
|
-
> **Status:** working notes. This should eventually move to the public wiki
|
|
4
|
-
> alongside the rest of the integration-authoring guidance; it lives here for
|
|
5
|
-
> now so it ships and is versioned with the CLI.
|
|
6
|
-
|
|
7
|
-
An **Integration** is an npm package that contributes components, templates, and/or
|
|
8
|
-
codemods to a consumer's design-system workflow. Consumers install the 3rd party
|
|
9
|
-
package, add a line to their astryx.config file:
|
|
10
|
-
|
|
11
|
-
```js
|
|
12
|
-
import {createConfig} from '@astryxdesign/cli/config';
|
|
13
|
-
|
|
14
|
-
export default createConfig({
|
|
15
|
-
integrations: ['@acme/astryx-widgets'],
|
|
16
|
-
...
|
|
17
|
-
});
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
Then the integration's components and templates will be surfaced alongside Astryx
|
|
21
|
-
components in the Astryx CLI.
|
|
22
|
-
|
|
23
|
-
```sh
|
|
24
|
-
astryx component AcmeCarousel --props
|
|
25
|
-
astryx component --list --package @acme/astryx-widgets
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## The Integration File
|
|
29
|
-
|
|
30
|
-
In order to register your package as an Astryx Integration, create an
|
|
31
|
-
`astryx.integration.{ts,mjs,js}` file as a sibling to your `package.json`. This file
|
|
32
|
-
tells Astryx where to find your components, templates, codemods, etc.
|
|
33
|
-
|
|
34
|
-
```js
|
|
35
|
-
// astryx.integration.{ts,mjs,js}
|
|
36
|
-
import {createIntegration} from '@astryxdesign/cli/integration';
|
|
37
|
-
|
|
38
|
-
export default createIntegration({
|
|
39
|
-
components: './components',
|
|
40
|
-
templates: './templates',
|
|
41
|
-
codemods: './codemods',
|
|
42
|
-
issuesUrl: 'https://github.com/acme/widgets/issues',
|
|
43
|
-
});
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Components
|
|
47
|
-
|
|
48
|
-
Your components themselves may be exported from your library as you see fit (consumers
|
|
49
|
-
will still import them from your package) but Astryx CLI will look for a .doc.{ts,mjs,js}
|
|
50
|
-
file with the same stem e.g. `AcmeCarousel.tsx` and `AcmeCarousel.doc.ts`.
|
|
51
|
-
|
|
52
|
-
```js
|
|
53
|
-
// AcmeCarousel.doc.ts
|
|
54
|
-
import {createComponentDoc} from '@astryxdesign/cli/doc';
|
|
55
|
-
|
|
56
|
-
export default createComponentDoc({
|
|
57
|
-
name: 'AcmeCarousel',
|
|
58
|
-
description: '...',
|
|
59
|
-
...
|
|
60
|
-
});
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Templates
|
|
64
|
-
|
|
65
|
-
Templates are typically not exported from the package directly, but instead accessed
|
|
66
|
-
via the Astryx CLI. Consumers can look through your templates and materialize them
|
|
67
|
-
into their apps.
|
|
68
|
-
|
|
69
|
-
You define a template with the `createPageTemplate` (for full pages) or `createBlockTemplate`
|
|
70
|
-
(for smaller chunks). e.g. `AcmeLandingPage.tsx`, `AcmeLandingPage.template.ts`
|
|
71
|
-
|
|
72
|
-
```js
|
|
73
|
-
// AcmeLandingPage.template.ts
|
|
74
|
-
import {createPageTemplate} from '@astryxdesign/cli/template';
|
|
75
|
-
|
|
76
|
-
export default createPageTemplate({
|
|
77
|
-
...
|
|
78
|
-
});
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
Note that, since the CLI needs access to the template source code, you need to make sure
|
|
82
|
-
that it is included in your published package. This will also allow us to render previews
|
|
83
|
-
of templates in the future by bundling your template into a doc site build.
|
|
84
|
-
|
|
85
|
-
Typically, this is done via the package.json `exports` key.
|
|
86
|
-
|
|
87
|
-
```jsonc
|
|
88
|
-
{
|
|
89
|
-
"exports": {
|
|
90
|
-
// ...
|
|
91
|
-
"./templates/*.tsx": "./templates/*.tsx",
|
|
92
|
-
},
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
In order to verify that it's working, you can test importing the template component like this:
|
|
97
|
-
|
|
98
|
-
```ts
|
|
99
|
-
import('@acme/astryx-widgets/templates/AcmeLandingPage.tsx');
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
Import **with the `.tsx` extension** — an extensionless specifier won't resolve
|
|
103
|
-
under `moduleResolution: bundler`. The extensionful `"./templates/*.tsx"` export
|
|
104
|
-
above is what lets that import type-check without consumers enabling
|
|
105
|
-
`allowImportingTsExtensions`.
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @file Interactivity contract for the CLI.
|
|
5
|
-
*
|
|
6
|
-
* A single source of truth for "can this process prompt the user?". Several
|
|
7
|
-
* commands launch @clack/prompts wizards; in a non-interactive context (CI,
|
|
8
|
-
* piped stdin/stdout, no TTY) those prompts block forever. Historically each
|
|
9
|
-
* command answered this question differently — some checked `stdout.isTTY`,
|
|
10
|
-
* one checked `stdin.isTTY`, one added `!process.env.CI`, and some had no
|
|
11
|
-
* guard at all. This module centralizes the check so every command behaves
|
|
12
|
-
* identically.
|
|
13
|
-
*
|
|
14
|
-
* Two entry points, for two situations:
|
|
15
|
-
*
|
|
16
|
-
* - `requireInteractive()` — for commands whose prompt IS the work
|
|
17
|
-
* (e.g. `astryx init`, `astryx theme`). With no TTY there is nothing to do, so
|
|
18
|
-
* fail fast (exit 1) with actionable, non-interactive guidance.
|
|
19
|
-
*
|
|
20
|
-
* - `isInteractive()` — for commands with an OPTIONAL secondary prompt
|
|
21
|
-
* that runs after the primary work has already succeeded; callers use
|
|
22
|
-
* this to skip the prompt gracefully in non-interactive contexts.
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* True when the process can safely run an interactive prompt.
|
|
27
|
-
*
|
|
28
|
-
* Requires BOTH stdin and stdout to be TTYs (clack reads stdin and renders to
|
|
29
|
-
* stdout) and that we are not in a CI environment. A CI runner may allocate a
|
|
30
|
-
* pseudo-TTY, so `process.env.CI` is an explicit override: never prompt in CI.
|
|
31
|
-
*
|
|
32
|
-
* @param {object} [env] - Override hook for tests.
|
|
33
|
-
* @param {boolean} [env.stdinTTY=process.stdin.isTTY]
|
|
34
|
-
* @param {boolean} [env.stdoutTTY=process.stdout.isTTY]
|
|
35
|
-
* @param {boolean} [env.ci=Boolean(process.env.CI)]
|
|
36
|
-
* @returns {boolean}
|
|
37
|
-
*/
|
|
38
|
-
export function isInteractive({
|
|
39
|
-
stdinTTY = Boolean(process.stdin && process.stdin.isTTY),
|
|
40
|
-
stdoutTTY = Boolean(process.stdout && process.stdout.isTTY),
|
|
41
|
-
ci = Boolean(process.env.CI),
|
|
42
|
-
} = {}) {
|
|
43
|
-
if (ci) return false;
|
|
44
|
-
return stdinTTY && stdoutTTY;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Guard for commands whose primary action is an interactive wizard. When the
|
|
49
|
-
* process is non-interactive, prints an actionable error and exits 1 instead
|
|
50
|
-
* of hanging on a prompt that will never receive input.
|
|
51
|
-
*
|
|
52
|
-
* @param {object} options
|
|
53
|
-
* @param {string} options.command - Command name for the message, e.g. 'init'.
|
|
54
|
-
* @param {string} options.hint - Concrete non-interactive invocation, e.g.
|
|
55
|
-
* '`pnpm astryx init --all` or `--features agents,theme,template`'.
|
|
56
|
-
* @param {boolean} [options.json=false] - When true, the command does not
|
|
57
|
-
* support --json; we still exit 1 but skip the human-formatted guidance.
|
|
58
|
-
* @param {object} [env] - Forwarded to isInteractive (test hook).
|
|
59
|
-
* @returns {void} Returns when interactive; otherwise calls process.exit(1).
|
|
60
|
-
*/
|
|
61
|
-
export function requireInteractive({command, hint, json = false} = {}, env) {
|
|
62
|
-
if (isInteractive(env)) return;
|
|
63
|
-
const name = command ? `astryx ${command}` : 'this command';
|
|
64
|
-
console.error(
|
|
65
|
-
`Error: \`${name}\` with no flags is interactive and requires a TTY.`,
|
|
66
|
-
);
|
|
67
|
-
if (hint) {
|
|
68
|
-
console.error(`Run non-interactively with: ${hint}`);
|
|
69
|
-
}
|
|
70
|
-
if (!json) {
|
|
71
|
-
console.error(
|
|
72
|
-
'Detected a non-interactive environment (no TTY, piped I/O, or CI=1).',
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
process.exit(1);
|
|
76
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @file Unit tests for the interactivity contract.
|
|
5
|
-
*
|
|
6
|
-
* isInteractive() is pure given its injected env, so these are fast unit
|
|
7
|
-
* tests. The "does the command actually fail fast instead of hanging" proof
|
|
8
|
-
* lives in the per-command subprocess tests (init/theme non-interactive).
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import {describe, it, expect, vi, afterEach} from 'vitest';
|
|
12
|
-
import {isInteractive, requireInteractive} from './interactive.mjs';
|
|
13
|
-
|
|
14
|
-
describe('isInteractive', () => {
|
|
15
|
-
it('is true only when stdin AND stdout are TTYs and not CI', () => {
|
|
16
|
-
expect(isInteractive({stdinTTY: true, stdoutTTY: true, ci: false})).toBe(true);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('is false when stdin is not a TTY (piped input)', () => {
|
|
20
|
-
expect(isInteractive({stdinTTY: false, stdoutTTY: true, ci: false})).toBe(false);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('is false when stdout is not a TTY (piped output)', () => {
|
|
24
|
-
expect(isInteractive({stdinTTY: true, stdoutTTY: false, ci: false})).toBe(false);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('is false in CI even with a pseudo-TTY on both streams', () => {
|
|
28
|
-
expect(isInteractive({stdinTTY: true, stdoutTTY: true, ci: true})).toBe(false);
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
describe('requireInteractive', () => {
|
|
33
|
-
afterEach(() => {
|
|
34
|
-
vi.restoreAllMocks();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('returns (does not exit) when interactive', () => {
|
|
38
|
-
const exit = vi.spyOn(process, 'exit').mockImplementation(() => {
|
|
39
|
-
throw new Error('exit should not be called');
|
|
40
|
-
});
|
|
41
|
-
expect(() =>
|
|
42
|
-
requireInteractive(
|
|
43
|
-
{command: 'init', hint: '`astryx init --all`'},
|
|
44
|
-
{stdinTTY: true, stdoutTTY: true, ci: false},
|
|
45
|
-
),
|
|
46
|
-
).not.toThrow();
|
|
47
|
-
expect(exit).not.toHaveBeenCalled();
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('exits 1 with actionable guidance when non-interactive', () => {
|
|
51
|
-
const exit = vi
|
|
52
|
-
.spyOn(process, 'exit')
|
|
53
|
-
.mockImplementation(() => {
|
|
54
|
-
throw new Error('__exit__');
|
|
55
|
-
});
|
|
56
|
-
const err = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
57
|
-
expect(() =>
|
|
58
|
-
requireInteractive(
|
|
59
|
-
{command: 'theme', hint: '`astryx theme <preset>`'},
|
|
60
|
-
{stdinTTY: false, stdoutTTY: false, ci: false},
|
|
61
|
-
),
|
|
62
|
-
).toThrow('__exit__');
|
|
63
|
-
expect(exit).toHaveBeenCalledWith(1);
|
|
64
|
-
const output = err.mock.calls.map(c => c.join(' ')).join('\n');
|
|
65
|
-
expect(output).toMatch(/requires a TTY/i);
|
|
66
|
-
expect(output).toMatch(/astryx theme <preset>/);
|
|
67
|
-
expect(output).toMatch(/`astryx theme`/);
|
|
68
|
-
expect(output).not.toMatch(/\bxds\b/);
|
|
69
|
-
});
|
|
70
|
-
});
|