@astryxdesign/cli 0.6.3-canary.db4e378 → 0.6.3-canary.dea6813
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/README.md +57 -57
- package/api/component/component.doc.mjs +1 -1
- package/api/component/component.mjs +3 -3
- package/api/component/component.type.d.mts +4 -5
- package/api/component/component.type.mjs +4 -5
- package/api/component/detail/blocks/blocks.d.mts +1 -2
- package/api/component/detail/blocks/blocks.mjs +3 -4
- package/api/component/list/list.d.mts +5 -0
- package/api/component/list/list.mjs +9 -37
- package/assets/codemods/transforms/v0.0.14/__tests__/rename-status-variants.test.mjs +165 -86
- package/assets/codemods/transforms/v0.0.14/rename-status-variants.mjs +210 -72
- package/assets/codemods/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +115 -83
- package/assets/codemods/transforms/v0.1.8/rename-avatar-size-scale.mjs +186 -57
- package/clients/cli/commands/component-package.test.mjs +0 -28
- package/foundation/response/response-types.doc.mjs +7 -7
- package/package.json +9 -9
- package/assets/codemods/transform-prop.mjs +0 -109
- package/assets/codemods/transform-prop.test.mjs +0 -95
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.doc.mjs +0 -14
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.tsx +0 -61
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.doc.mjs +0 -14
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.tsx +0 -126
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.doc.mjs +0 -15
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.tsx +0 -86
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.doc.mjs +0 -14
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.tsx +0 -99
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.doc.mjs +0 -14
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.tsx +0 -122
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.doc.mjs +0 -14
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.tsx +0 -95
- package/foundation/response/response-types.doc.test.mjs +0 -158
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/cli",
|
|
3
|
-
"version": "0.6.3-canary.
|
|
3
|
+
"version": "0.6.3-canary.dea6813",
|
|
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",
|
|
@@ -100,10 +100,10 @@
|
|
|
100
100
|
"zod": "^4.4.3"
|
|
101
101
|
},
|
|
102
102
|
"peerDependencies": {
|
|
103
|
-
"@astryxdesign/charts": "0.6.3-canary.
|
|
104
|
-
"@astryxdesign/core": "0.6.3-canary.
|
|
105
|
-
"@astryxdesign/lab": "0.6.3-canary.
|
|
106
|
-
"@astryxdesign/theme-neutral": "0.6.3-canary.
|
|
103
|
+
"@astryxdesign/charts": "0.6.3-canary.dea6813",
|
|
104
|
+
"@astryxdesign/core": "0.6.3-canary.dea6813",
|
|
105
|
+
"@astryxdesign/lab": "0.6.3-canary.dea6813",
|
|
106
|
+
"@astryxdesign/theme-neutral": "0.6.3-canary.dea6813"
|
|
107
107
|
},
|
|
108
108
|
"peerDependenciesMeta": {
|
|
109
109
|
"@astryxdesign/charts": {
|
|
@@ -120,10 +120,10 @@
|
|
|
120
120
|
}
|
|
121
121
|
},
|
|
122
122
|
"devDependencies": {
|
|
123
|
-
"@astryxdesign/charts": "0.6.3-canary.
|
|
124
|
-
"@astryxdesign/core": "0.6.3-canary.
|
|
125
|
-
"@astryxdesign/lab": "0.6.3-canary.
|
|
126
|
-
"@astryxdesign/theme-neutral": "0.6.3-canary.
|
|
123
|
+
"@astryxdesign/charts": "0.6.3-canary.dea6813",
|
|
124
|
+
"@astryxdesign/core": "0.6.3-canary.dea6813",
|
|
125
|
+
"@astryxdesign/lab": "0.6.3-canary.dea6813",
|
|
126
|
+
"@astryxdesign/theme-neutral": "0.6.3-canary.dea6813",
|
|
127
127
|
"@heroicons/react": "^2.2.0",
|
|
128
128
|
"@stylexjs/stylex": "^0.19.0",
|
|
129
129
|
"@types/babel__core": "^7.20.5",
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Find imported components, resolve their local JSX names (including aliases),
|
|
5
|
-
* and yield matching JSX prop paths to a visitor.
|
|
6
|
-
*
|
|
7
|
-
* This helper intentionally stops at the JSX boundary. It does not follow
|
|
8
|
-
* variables, helper calls, object spreads, wrapper components, or types.
|
|
9
|
-
*
|
|
10
|
-
* @param {any} root jscodeshift collection for one source file
|
|
11
|
-
* @param {any} j configured jscodeshift instance
|
|
12
|
-
* @param {{
|
|
13
|
-
* matchesImport: (source: string) => boolean,
|
|
14
|
-
* components: ReadonlyMap<string, ReadonlySet<string>>,
|
|
15
|
-
* normalizeComponentName?: (name: string) => string,
|
|
16
|
-
* }} options
|
|
17
|
-
* @param {(propPath: any, context: {component: string, localName: string}) => void} visit
|
|
18
|
-
*/
|
|
19
|
-
export function transformProp(root, j, options, visit) {
|
|
20
|
-
const normalize = options.normalizeComponentName ?? (name => name);
|
|
21
|
-
/** @type {Map<string, {component: string, props: ReadonlySet<string>}>} */
|
|
22
|
-
const directBindings = new Map();
|
|
23
|
-
/** @type {Set<string>} */
|
|
24
|
-
const namespaceBindings = new Set();
|
|
25
|
-
|
|
26
|
-
root.find(j.ImportDeclaration).forEach((/** @type {any} */ importPath) => {
|
|
27
|
-
const source = importPath.node.source.value;
|
|
28
|
-
if (
|
|
29
|
-
importPath.node.importKind === 'type' ||
|
|
30
|
-
typeof source !== 'string' ||
|
|
31
|
-
!options.matchesImport(source)
|
|
32
|
-
) {
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const subpathName = normalize(source.split('/').at(-1) ?? '');
|
|
37
|
-
const subpathProps = options.components.get(subpathName);
|
|
38
|
-
|
|
39
|
-
for (const specifier of importPath.node.specifiers ?? []) {
|
|
40
|
-
if (specifier.importKind === 'type') continue;
|
|
41
|
-
|
|
42
|
-
if (specifier.type === 'ImportSpecifier') {
|
|
43
|
-
const importedName =
|
|
44
|
-
specifier.imported?.name ?? specifier.imported?.value;
|
|
45
|
-
if (typeof importedName !== 'string') continue;
|
|
46
|
-
const component = normalize(importedName);
|
|
47
|
-
const props = options.components.get(component);
|
|
48
|
-
if (!props) continue;
|
|
49
|
-
directBindings.set(specifier.local?.name ?? importedName, {
|
|
50
|
-
component,
|
|
51
|
-
props,
|
|
52
|
-
});
|
|
53
|
-
} else if (specifier.type === 'ImportDefaultSpecifier' && subpathProps) {
|
|
54
|
-
directBindings.set(specifier.local.name, {
|
|
55
|
-
component: subpathName,
|
|
56
|
-
props: subpathProps,
|
|
57
|
-
});
|
|
58
|
-
} else if (specifier.type === 'ImportNamespaceSpecifier') {
|
|
59
|
-
namespaceBindings.add(specifier.local.name);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
if (directBindings.size === 0 && namespaceBindings.size === 0) return;
|
|
65
|
-
|
|
66
|
-
root.find(j.JSXOpeningElement).forEach((/** @type {any} */ jsxPath) => {
|
|
67
|
-
const name = jsxPath.node.name;
|
|
68
|
-
let localName;
|
|
69
|
-
let component;
|
|
70
|
-
let props;
|
|
71
|
-
|
|
72
|
-
if (name.type === 'JSXIdentifier') {
|
|
73
|
-
localName = name.name;
|
|
74
|
-
const binding = directBindings.get(localName);
|
|
75
|
-
if (!binding) return;
|
|
76
|
-
({component, props} = binding);
|
|
77
|
-
} else if (
|
|
78
|
-
name.type === 'JSXMemberExpression' &&
|
|
79
|
-
name.object?.type === 'JSXIdentifier' &&
|
|
80
|
-
name.property?.type === 'JSXIdentifier' &&
|
|
81
|
-
namespaceBindings.has(name.object.name)
|
|
82
|
-
) {
|
|
83
|
-
localName = name.object.name;
|
|
84
|
-
component = normalize(name.property.name);
|
|
85
|
-
props = options.components.get(component);
|
|
86
|
-
if (!props) return;
|
|
87
|
-
} else {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// A parameter or local declaration with the imported name shadows the
|
|
92
|
-
// module binding. Only JSX tags whose root binding resolves to Program are
|
|
93
|
-
// considered usages of the import discovered above.
|
|
94
|
-
const bindingScope = jsxPath.scope.lookup(localName);
|
|
95
|
-
if (!bindingScope || bindingScope.path.node.type !== 'Program') return;
|
|
96
|
-
|
|
97
|
-
for (let index = 0; index < jsxPath.node.attributes.length; index++) {
|
|
98
|
-
const attribute = jsxPath.node.attributes[index];
|
|
99
|
-
if (
|
|
100
|
-
attribute.type !== 'JSXAttribute' ||
|
|
101
|
-
attribute.name?.type !== 'JSXIdentifier' ||
|
|
102
|
-
!props.has(attribute.name.name)
|
|
103
|
-
) {
|
|
104
|
-
continue;
|
|
105
|
-
}
|
|
106
|
-
visit(jsxPath.get('attributes', index), {component, localName});
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
import {describe, expect, it} from 'vitest';
|
|
4
|
-
import jscodeshift from 'jscodeshift';
|
|
5
|
-
import {transformProp} from './transform-prop.mjs';
|
|
6
|
-
|
|
7
|
-
const j = jscodeshift.withParser('tsx');
|
|
8
|
-
const components = new Map([
|
|
9
|
-
['Widget', new Set(['tone'])],
|
|
10
|
-
['Group', new Set(['size'])],
|
|
11
|
-
]);
|
|
12
|
-
|
|
13
|
-
function apply(source) {
|
|
14
|
-
const root = j(source);
|
|
15
|
-
transformProp(
|
|
16
|
-
root,
|
|
17
|
-
j,
|
|
18
|
-
{
|
|
19
|
-
matchesImport: value => /^@example\/core(?:\/|$)/.test(value),
|
|
20
|
-
components,
|
|
21
|
-
normalizeComponentName: name =>
|
|
22
|
-
name.startsWith('XDS') ? name.slice(3) : name,
|
|
23
|
-
},
|
|
24
|
-
propPath => {
|
|
25
|
-
propPath.node.name.name = `migrated${propPath.node.name.name}`;
|
|
26
|
-
},
|
|
27
|
-
);
|
|
28
|
-
return root.toSource({quote: 'single'});
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
describe('transformProp', () => {
|
|
32
|
-
it('maps named import aliases to their JSX usages', () => {
|
|
33
|
-
const output = apply(`import {Widget as Card} from '@example/core';
|
|
34
|
-
const view = <Card tone="old" other="old" />;`);
|
|
35
|
-
|
|
36
|
-
expect(output).toContain('<Card migratedtone="old" other="old"');
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('maps default subpath imports', () => {
|
|
40
|
-
const output = apply(`import Card from '@example/core/Widget';
|
|
41
|
-
const view = <Card tone="old" />;`);
|
|
42
|
-
|
|
43
|
-
expect(output).toContain('<Card migratedtone="old"');
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('ignores declaration-level type imports', () => {
|
|
47
|
-
const output = apply(`import type {Widget} from '@example/core';
|
|
48
|
-
const Widget = props => <div {...props} />;
|
|
49
|
-
const view = <Widget tone="old" />;`);
|
|
50
|
-
|
|
51
|
-
expect(output).toContain('<Widget tone="old"');
|
|
52
|
-
expect(output).not.toContain('migratedtone');
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('ignores type specifiers in mixed imports', () => {
|
|
56
|
-
const output = apply(`import {type Widget, Group} from '@example/core';
|
|
57
|
-
const Widget = props => <div {...props} />;
|
|
58
|
-
const view = <><Widget tone="old" /><Group size="old" /></>;`);
|
|
59
|
-
|
|
60
|
-
expect(output).toContain('<Widget tone="old"');
|
|
61
|
-
expect(output).toContain('<Group migratedsize="old"');
|
|
62
|
-
expect(output).not.toContain('<Widget migratedtone');
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('maps namespace imports', () => {
|
|
66
|
-
const output = apply(`import * as Core from '@example/core';
|
|
67
|
-
const view = <Core.Group size="old" />;`);
|
|
68
|
-
|
|
69
|
-
expect(output).toContain('<Core.Group migratedsize="old"');
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('ignores same-named imports from other packages', () => {
|
|
73
|
-
const source = `import {Widget} from '@other/core';
|
|
74
|
-
const view = <Widget tone="old" />;`;
|
|
75
|
-
expect(apply(source)).toBe(source);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('ignores a local binding that shadows an imported alias', () => {
|
|
79
|
-
const output = apply(`import {Widget as Card} from '@example/core';
|
|
80
|
-
const migrated = <Card tone="old" />;
|
|
81
|
-
function Local(Card) { return <Card tone="local" />; }`);
|
|
82
|
-
|
|
83
|
-
expect(output).toContain('<Card migratedtone="old"');
|
|
84
|
-
expect(output).toContain('<Card tone="local"');
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('yields only configured props on configured components', () => {
|
|
88
|
-
const output = apply(`import {Widget, Group} from '@example/core';
|
|
89
|
-
const a = <Widget size="old" tone="old" />;
|
|
90
|
-
const b = <Group tone="old" size="old" />;`);
|
|
91
|
-
|
|
92
|
-
expect(output).toContain('<Widget size="old" migratedtone="old"');
|
|
93
|
-
expect(output).toContain('<Group tone="old" migratedsize="old"');
|
|
94
|
-
});
|
|
95
|
-
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
|
|
4
|
-
export const doc = {
|
|
5
|
-
type: 'block',
|
|
6
|
-
exampleFor: 'ScrollableArea',
|
|
7
|
-
name: 'ScrollableArea — Inline Rail',
|
|
8
|
-
displayName: 'Scrollable Area — Inline Rail',
|
|
9
|
-
description:
|
|
10
|
-
'axis="inline" scrolls the same cards sideways; isFullBleed lets the rail run to the panel edges while the content padding keeps the first card aligned with the heading.',
|
|
11
|
-
isReady: true,
|
|
12
|
-
aspectRatio: 16 / 9,
|
|
13
|
-
componentsUsed: ['ScrollableArea', 'Card', 'Link'],
|
|
14
|
-
};
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
'use client';
|
|
4
|
-
|
|
5
|
-
import {ScrollableArea} from '@astryxdesign/core/ScrollableArea';
|
|
6
|
-
import {Card} from '@astryxdesign/core/Card';
|
|
7
|
-
import {HStack, VStack} from '@astryxdesign/core/Layout';
|
|
8
|
-
import {Heading, Text} from '@astryxdesign/core/Text';
|
|
9
|
-
import {Link} from '@astryxdesign/core/Link';
|
|
10
|
-
|
|
11
|
-
const FILES = [
|
|
12
|
-
{id: 'brief', title: 'Q3 launch brief', meta: 'Edited 2 days ago'},
|
|
13
|
-
{id: 'pricing', title: 'Pricing rework', meta: 'Edited 3 days ago'},
|
|
14
|
-
{id: 'onboarding', title: 'Onboarding flow v4', meta: 'Edited 4 days ago'},
|
|
15
|
-
{id: 'macros', title: 'Support macros', meta: 'Edited last week'},
|
|
16
|
-
{id: 'brand', title: 'Brand refresh', meta: 'Priya Raman'},
|
|
17
|
-
{id: 'checkout', title: 'Checkout audit', meta: 'Tomas Lindqvist'},
|
|
18
|
-
{id: 'partner', title: 'Partner deck', meta: 'Ines Okafor'},
|
|
19
|
-
];
|
|
20
|
-
|
|
21
|
-
export default function ScrollableAreaInlineRail() {
|
|
22
|
-
return (
|
|
23
|
-
<Card width={460} padding={4}>
|
|
24
|
-
<VStack gap={3}>
|
|
25
|
-
<HStack hAlign="between" vAlign="center">
|
|
26
|
-
<VStack gap={0.5}>
|
|
27
|
-
<Heading level={3}>Workspace files</Heading>
|
|
28
|
-
<Text type="supporting">Recently opened</Text>
|
|
29
|
-
</VStack>
|
|
30
|
-
<Link href="#files">View all</Link>
|
|
31
|
-
</HStack>
|
|
32
|
-
{/* isFullBleed lets the rail reach the card's edges, while the content
|
|
33
|
-
padding keeps the first card aligned with the heading above it and
|
|
34
|
-
leaves room under the cards for the scrollbar. */}
|
|
35
|
-
<ScrollableArea
|
|
36
|
-
axis="inline"
|
|
37
|
-
role="region"
|
|
38
|
-
label="Recently opened files"
|
|
39
|
-
isFullBleed
|
|
40
|
-
paddingInline={4}
|
|
41
|
-
paddingBlockStart={0.5}
|
|
42
|
-
paddingBlockEnd={4}>
|
|
43
|
-
<HStack gap={2}>
|
|
44
|
-
{FILES.map(file => (
|
|
45
|
-
<Card key={file.id} variant="muted" padding={3} width={170}>
|
|
46
|
-
<VStack gap={1}>
|
|
47
|
-
<Text weight="medium" maxLines={1}>
|
|
48
|
-
{file.title}
|
|
49
|
-
</Text>
|
|
50
|
-
<Text type="supporting" maxLines={1}>
|
|
51
|
-
{file.meta}
|
|
52
|
-
</Text>
|
|
53
|
-
</VStack>
|
|
54
|
-
</Card>
|
|
55
|
-
))}
|
|
56
|
-
</HStack>
|
|
57
|
-
</ScrollableArea>
|
|
58
|
-
</VStack>
|
|
59
|
-
</Card>
|
|
60
|
-
);
|
|
61
|
-
}
|
package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.doc.mjs
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
|
|
4
|
-
export const doc = {
|
|
5
|
-
type: 'block',
|
|
6
|
-
exampleFor: 'ScrollableArea',
|
|
7
|
-
name: 'ScrollableArea — Overscroll',
|
|
8
|
-
displayName: 'Scrollable Area — Overscroll',
|
|
9
|
-
description:
|
|
10
|
-
'The same section, two edge policies: the default overscroll="allow" hands a gesture that reaches the end to the panel behind it, while overscroll="contain" stops it at the section edge.',
|
|
11
|
-
isReady: true,
|
|
12
|
-
aspectRatio: 1,
|
|
13
|
-
componentsUsed: ['ScrollableArea', 'Card', 'Grid'],
|
|
14
|
-
};
|
package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.tsx
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
'use client';
|
|
4
|
-
|
|
5
|
-
import * as stylex from '@stylexjs/stylex';
|
|
6
|
-
import {ScrollableArea} from '@astryxdesign/core/ScrollableArea';
|
|
7
|
-
import {Card} from '@astryxdesign/core/Card';
|
|
8
|
-
import {Grid} from '@astryxdesign/core/Grid';
|
|
9
|
-
import {VStack} from '@astryxdesign/core/Layout';
|
|
10
|
-
import {Heading, Text} from '@astryxdesign/core/Text';
|
|
11
|
-
import {
|
|
12
|
-
borderVars,
|
|
13
|
-
colorVars,
|
|
14
|
-
radiusVars,
|
|
15
|
-
} from '@astryxdesign/core/theme/tokens.stylex';
|
|
16
|
-
|
|
17
|
-
const styles = stylex.create({
|
|
18
|
-
// A hairline frame so the nested viewport's edge — the edge the gesture
|
|
19
|
-
// meets — is visible.
|
|
20
|
-
sectionFrame: {
|
|
21
|
-
borderWidth: borderVars['--border-width'],
|
|
22
|
-
borderStyle: 'solid',
|
|
23
|
-
borderColor: colorVars['--color-border'],
|
|
24
|
-
borderRadius: radiusVars['--radius-element'],
|
|
25
|
-
},
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
const SHARED = [
|
|
29
|
-
{id: 'brand', title: 'Brand refresh', meta: 'Priya Raman'},
|
|
30
|
-
{id: 'checkout', title: 'Checkout audit', meta: 'Tomas Lindqvist'},
|
|
31
|
-
{id: 'partner', title: 'Partner deck', meta: 'Ines Okafor'},
|
|
32
|
-
{id: 'research', title: 'Research synthesis', meta: 'Mei Watanabe'},
|
|
33
|
-
{id: 'tax', title: 'Tax region notes', meta: 'Hugo Bernard'},
|
|
34
|
-
{id: 'sso', title: 'SSO rollout plan', meta: 'Sofia Marchetti'},
|
|
35
|
-
];
|
|
36
|
-
|
|
37
|
-
const ARCHIVED = [
|
|
38
|
-
{id: 'roadmap', title: '2025 roadmap', meta: 'Archived in March'},
|
|
39
|
-
{id: 'legacy', title: 'Legacy pricing', meta: 'Archived in March'},
|
|
40
|
-
{id: 'kit', title: 'Old brand kit', meta: 'Archived in January'},
|
|
41
|
-
{id: 'beta', title: 'Beta feedback', meta: 'Archived in January'},
|
|
42
|
-
{id: 'survey', title: 'Q4 survey results', meta: 'Archived in January'},
|
|
43
|
-
{id: 'offsite', title: 'Offsite agenda', meta: 'Archived last year'},
|
|
44
|
-
];
|
|
45
|
-
|
|
46
|
-
function FileGrid({
|
|
47
|
-
files,
|
|
48
|
-
}: {
|
|
49
|
-
files: Array<{id: string; title: string; meta: string}>;
|
|
50
|
-
}) {
|
|
51
|
-
return (
|
|
52
|
-
<Grid columns={2} gap={2}>
|
|
53
|
-
{files.map(file => (
|
|
54
|
-
<Card key={file.id} variant="muted" padding={3}>
|
|
55
|
-
<VStack gap={1}>
|
|
56
|
-
<Text weight="medium" maxLines={1}>
|
|
57
|
-
{file.title}
|
|
58
|
-
</Text>
|
|
59
|
-
<Text type="supporting" maxLines={1}>
|
|
60
|
-
{file.meta}
|
|
61
|
-
</Text>
|
|
62
|
-
</VStack>
|
|
63
|
-
</Card>
|
|
64
|
-
))}
|
|
65
|
-
</Grid>
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export default function ScrollableAreaOverscrollChaining() {
|
|
70
|
-
return (
|
|
71
|
-
<Card width={400} padding={0}>
|
|
72
|
-
<ScrollableArea
|
|
73
|
-
axis="block"
|
|
74
|
-
role="region"
|
|
75
|
-
label="Workspace files"
|
|
76
|
-
height={300}
|
|
77
|
-
padding={4}>
|
|
78
|
-
<VStack gap={4}>
|
|
79
|
-
<VStack gap={0.5}>
|
|
80
|
-
<Heading level={3}>Workspace files</Heading>
|
|
81
|
-
<Text type="supporting">Two sections, two edge policies</Text>
|
|
82
|
-
</VStack>
|
|
83
|
-
|
|
84
|
-
<VStack gap={2}>
|
|
85
|
-
<Text type="label" color="secondary">
|
|
86
|
-
Shared with you
|
|
87
|
-
</Text>
|
|
88
|
-
{/* Default overscroll="allow": a gesture that reaches this
|
|
89
|
-
section's end carries on scrolling the panel behind it. */}
|
|
90
|
-
<ScrollableArea
|
|
91
|
-
axis="block"
|
|
92
|
-
label="Shared with you"
|
|
93
|
-
height={150}
|
|
94
|
-
padding={2}
|
|
95
|
-
xstyle={styles.sectionFrame}>
|
|
96
|
-
<FileGrid files={SHARED} />
|
|
97
|
-
</ScrollableArea>
|
|
98
|
-
<Text type="supporting">
|
|
99
|
-
Scroll past the end and the panel keeps going.
|
|
100
|
-
</Text>
|
|
101
|
-
</VStack>
|
|
102
|
-
|
|
103
|
-
<VStack gap={2}>
|
|
104
|
-
<Text type="label" color="secondary">
|
|
105
|
-
Archived
|
|
106
|
-
</Text>
|
|
107
|
-
{/* overscroll="contain" stops the gesture at this section's
|
|
108
|
-
edge, so the panel behind it stays put. */}
|
|
109
|
-
<ScrollableArea
|
|
110
|
-
axis="block"
|
|
111
|
-
label="Archived"
|
|
112
|
-
overscroll="contain"
|
|
113
|
-
height={150}
|
|
114
|
-
padding={2}
|
|
115
|
-
xstyle={styles.sectionFrame}>
|
|
116
|
-
<FileGrid files={ARCHIVED} />
|
|
117
|
-
</ScrollableArea>
|
|
118
|
-
<Text type="supporting">
|
|
119
|
-
Scroll past the end and the panel stays where it is.
|
|
120
|
-
</Text>
|
|
121
|
-
</VStack>
|
|
122
|
-
</VStack>
|
|
123
|
-
</ScrollableArea>
|
|
124
|
-
</Card>
|
|
125
|
-
);
|
|
126
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
|
|
4
|
-
export const doc = {
|
|
5
|
-
type: 'block',
|
|
6
|
-
exampleFor: 'ScrollableArea',
|
|
7
|
-
name: 'ScrollableArea',
|
|
8
|
-
displayName: 'Scrollable Area',
|
|
9
|
-
description:
|
|
10
|
-
'A fixed-height file panel that scrolls on the block axis; the heading sits inside the viewport, so it scrolls away with the content.',
|
|
11
|
-
isReady: true,
|
|
12
|
-
aspectRatio: 1,
|
|
13
|
-
isShowcase: true,
|
|
14
|
-
componentsUsed: ['ScrollableArea', 'Card', 'Grid'],
|
|
15
|
-
};
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
'use client';
|
|
4
|
-
|
|
5
|
-
import {ScrollableArea} from '@astryxdesign/core/ScrollableArea';
|
|
6
|
-
import {Card} from '@astryxdesign/core/Card';
|
|
7
|
-
import {Grid} from '@astryxdesign/core/Grid';
|
|
8
|
-
import {VStack} from '@astryxdesign/core/Layout';
|
|
9
|
-
import {Heading, Text} from '@astryxdesign/core/Text';
|
|
10
|
-
|
|
11
|
-
const SECTIONS = [
|
|
12
|
-
{
|
|
13
|
-
label: 'Recently opened',
|
|
14
|
-
files: [
|
|
15
|
-
{id: 'brief', title: 'Q3 launch brief', meta: 'Edited 2 days ago'},
|
|
16
|
-
{id: 'pricing', title: 'Pricing rework', meta: 'Edited 3 days ago'},
|
|
17
|
-
{
|
|
18
|
-
id: 'onboarding',
|
|
19
|
-
title: 'Onboarding flow v4',
|
|
20
|
-
meta: 'Edited 4 days ago',
|
|
21
|
-
},
|
|
22
|
-
{id: 'macros', title: 'Support macros', meta: 'Edited last week'},
|
|
23
|
-
],
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
label: 'Shared with you',
|
|
27
|
-
files: [
|
|
28
|
-
{id: 'brand', title: 'Brand refresh', meta: 'Priya Raman'},
|
|
29
|
-
{id: 'checkout', title: 'Checkout audit', meta: 'Tomas Lindqvist'},
|
|
30
|
-
{id: 'partner', title: 'Partner deck', meta: 'Ines Okafor'},
|
|
31
|
-
{id: 'research', title: 'Research synthesis', meta: 'Mei Watanabe'},
|
|
32
|
-
],
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
label: 'Archived',
|
|
36
|
-
files: [
|
|
37
|
-
{id: 'roadmap', title: '2025 roadmap', meta: 'Archived in March'},
|
|
38
|
-
{id: 'legacy', title: 'Legacy pricing', meta: 'Archived in March'},
|
|
39
|
-
{id: 'kit', title: 'Old brand kit', meta: 'Archived in January'},
|
|
40
|
-
{id: 'beta', title: 'Beta feedback', meta: 'Archived in January'},
|
|
41
|
-
],
|
|
42
|
-
},
|
|
43
|
-
];
|
|
44
|
-
|
|
45
|
-
export default function ScrollableAreaShowcase() {
|
|
46
|
-
return (
|
|
47
|
-
<Card width={380} padding={0}>
|
|
48
|
-
{/* The heading sits inside the viewport, so it scrolls away with the
|
|
49
|
-
content instead of staying pinned above it. */}
|
|
50
|
-
<ScrollableArea
|
|
51
|
-
axis="block"
|
|
52
|
-
role="region"
|
|
53
|
-
label="Workspace files"
|
|
54
|
-
height={300}
|
|
55
|
-
padding={4}>
|
|
56
|
-
<VStack gap={4}>
|
|
57
|
-
<VStack gap={0.5}>
|
|
58
|
-
<Heading level={3}>Workspace files</Heading>
|
|
59
|
-
<Text type="supporting">12 files across 3 sections</Text>
|
|
60
|
-
</VStack>
|
|
61
|
-
{SECTIONS.map(section => (
|
|
62
|
-
<VStack key={section.label} gap={2}>
|
|
63
|
-
<Text type="label" color="secondary">
|
|
64
|
-
{section.label}
|
|
65
|
-
</Text>
|
|
66
|
-
<Grid columns={2} gap={2}>
|
|
67
|
-
{section.files.map(file => (
|
|
68
|
-
<Card key={file.id} variant="muted" padding={3}>
|
|
69
|
-
<VStack gap={1}>
|
|
70
|
-
<Text weight="medium" maxLines={1}>
|
|
71
|
-
{file.title}
|
|
72
|
-
</Text>
|
|
73
|
-
<Text type="supporting" maxLines={1}>
|
|
74
|
-
{file.meta}
|
|
75
|
-
</Text>
|
|
76
|
-
</VStack>
|
|
77
|
-
</Card>
|
|
78
|
-
))}
|
|
79
|
-
</Grid>
|
|
80
|
-
</VStack>
|
|
81
|
-
))}
|
|
82
|
-
</VStack>
|
|
83
|
-
</ScrollableArea>
|
|
84
|
-
</Card>
|
|
85
|
-
);
|
|
86
|
-
}
|
package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.doc.mjs
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
|
|
4
|
-
export const doc = {
|
|
5
|
-
type: 'block',
|
|
6
|
-
exampleFor: 'ScrollableArea',
|
|
7
|
-
name: 'ScrollableArea — Sticky Section Labels',
|
|
8
|
-
displayName: 'Scrollable Area — Sticky Section Labels',
|
|
9
|
-
description:
|
|
10
|
-
'A scrollable viewport is the containing block for position: sticky, so section labels pin to the top edge of the list instead of the page.',
|
|
11
|
-
isReady: true,
|
|
12
|
-
aspectRatio: 1,
|
|
13
|
-
componentsUsed: ['ScrollableArea', 'Card', 'Grid'],
|
|
14
|
-
};
|
package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.tsx
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
'use client';
|
|
4
|
-
|
|
5
|
-
import * as stylex from '@stylexjs/stylex';
|
|
6
|
-
import {ScrollableArea} from '@astryxdesign/core/ScrollableArea';
|
|
7
|
-
import {Card} from '@astryxdesign/core/Card';
|
|
8
|
-
import {Grid} from '@astryxdesign/core/Grid';
|
|
9
|
-
import {VStack} from '@astryxdesign/core/Layout';
|
|
10
|
-
import {Heading, Text} from '@astryxdesign/core/Text';
|
|
11
|
-
import {colorVars, spacingVars} from '@astryxdesign/core/theme/tokens.stylex';
|
|
12
|
-
|
|
13
|
-
const styles = stylex.create({
|
|
14
|
-
sectionLabel: {
|
|
15
|
-
position: 'sticky',
|
|
16
|
-
insetBlockStart: 0,
|
|
17
|
-
zIndex: 1,
|
|
18
|
-
backgroundColor: colorVars['--color-background-card'],
|
|
19
|
-
paddingBlock: spacingVars['--spacing-2'],
|
|
20
|
-
},
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
const SECTIONS = [
|
|
24
|
-
{
|
|
25
|
-
label: 'Recently opened',
|
|
26
|
-
files: [
|
|
27
|
-
{id: 'brief', title: 'Q3 launch brief', meta: 'Edited 2 days ago'},
|
|
28
|
-
{id: 'pricing', title: 'Pricing rework', meta: 'Edited 3 days ago'},
|
|
29
|
-
{
|
|
30
|
-
id: 'onboarding',
|
|
31
|
-
title: 'Onboarding flow v4',
|
|
32
|
-
meta: 'Edited 4 days ago',
|
|
33
|
-
},
|
|
34
|
-
{id: 'macros', title: 'Support macros', meta: 'Edited last week'},
|
|
35
|
-
],
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
label: 'Shared with you',
|
|
39
|
-
files: [
|
|
40
|
-
{id: 'brand', title: 'Brand refresh', meta: 'Priya Raman'},
|
|
41
|
-
{id: 'checkout', title: 'Checkout audit', meta: 'Tomas Lindqvist'},
|
|
42
|
-
{id: 'partner', title: 'Partner deck', meta: 'Ines Okafor'},
|
|
43
|
-
{id: 'research', title: 'Research synthesis', meta: 'Mei Watanabe'},
|
|
44
|
-
],
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
label: 'Archived',
|
|
48
|
-
files: [
|
|
49
|
-
{id: 'roadmap', title: '2025 roadmap', meta: 'Archived in March'},
|
|
50
|
-
{id: 'legacy', title: 'Legacy pricing', meta: 'Archived in March'},
|
|
51
|
-
{id: 'kit', title: 'Old brand kit', meta: 'Archived in January'},
|
|
52
|
-
{id: 'beta', title: 'Beta feedback', meta: 'Archived in January'},
|
|
53
|
-
],
|
|
54
|
-
},
|
|
55
|
-
];
|
|
56
|
-
|
|
57
|
-
export default function ScrollableAreaStickyGroupHeaders() {
|
|
58
|
-
return (
|
|
59
|
-
<Card width={380} padding={0}>
|
|
60
|
-
{/* The viewport is the containing block for position: sticky. The panel
|
|
61
|
-
heading is ordinary content and scrolls away; the section labels
|
|
62
|
-
below it pin to the top of the list, not the page. */}
|
|
63
|
-
<ScrollableArea
|
|
64
|
-
axis="block"
|
|
65
|
-
role="region"
|
|
66
|
-
label="Workspace files"
|
|
67
|
-
height={300}
|
|
68
|
-
padding={4}>
|
|
69
|
-
<VStack gap={0.5} paddingBlockEnd={2}>
|
|
70
|
-
<Heading level={3}>Workspace files</Heading>
|
|
71
|
-
<Text type="supporting">12 files across 3 sections</Text>
|
|
72
|
-
</VStack>
|
|
73
|
-
{SECTIONS.map(section => (
|
|
74
|
-
<section key={section.label}>
|
|
75
|
-
<div {...stylex.props(styles.sectionLabel)}>
|
|
76
|
-
<Text type="label" color="secondary">
|
|
77
|
-
{section.label}
|
|
78
|
-
</Text>
|
|
79
|
-
</div>
|
|
80
|
-
<Grid columns={2} gap={2}>
|
|
81
|
-
{section.files.map(file => (
|
|
82
|
-
<Card key={file.id} variant="muted" padding={3}>
|
|
83
|
-
<VStack gap={1}>
|
|
84
|
-
<Text weight="medium" maxLines={1}>
|
|
85
|
-
{file.title}
|
|
86
|
-
</Text>
|
|
87
|
-
<Text type="supporting" maxLines={1}>
|
|
88
|
-
{file.meta}
|
|
89
|
-
</Text>
|
|
90
|
-
</VStack>
|
|
91
|
-
</Card>
|
|
92
|
-
))}
|
|
93
|
-
</Grid>
|
|
94
|
-
</section>
|
|
95
|
-
))}
|
|
96
|
-
</ScrollableArea>
|
|
97
|
-
</Card>
|
|
98
|
-
);
|
|
99
|
-
}
|