@astryxdesign/cli 0.1.1 → 0.1.2-canary.2149fa3
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 +50 -0
- package/docs/theme.doc.mjs +2 -2
- package/docs/working-with-ai.doc.mjs +6 -6
- package/package.json +19 -8
- package/src/api/discover.mjs +78 -26
- package/src/api/index.mjs +1 -0
- package/src/api/layout.mjs +301 -0
- package/src/api/layout.test.mjs +238 -0
- package/src/api/template.mjs +191 -50
- package/src/api/template.test.mjs +2 -0
- package/src/api/theme-add.mjs +182 -0
- package/src/codemods/__tests__/registry.test.mjs +1 -0
- package/src/codemods/registry.mjs +1 -0
- package/src/codemods/transforms/v0.1.2/__tests__/rename-text-color-active-to-accent.test.mjs +120 -0
- package/src/codemods/transforms/v0.1.2/index.mjs +19 -0
- package/src/codemods/transforms/v0.1.2/rename-text-color-active-to-accent.mjs +136 -0
- package/src/commands/build-theme.import-path.test.mjs +22 -2
- package/src/commands/build-theme.mjs +185 -16
- package/src/commands/gap-report.mjs +17 -9
- package/src/commands/gap-report.test.mjs +21 -16
- package/src/commands/init.mjs +34 -8
- package/src/commands/init.next-steps.test.mjs +46 -0
- package/src/commands/layout.mjs +139 -0
- package/src/commands/swizzle.mjs +51 -23
- package/src/commands/upgrade.mjs +2 -71
- package/src/config.mjs +31 -0
- package/src/config.test.mjs +24 -0
- package/src/index.mjs +6 -0
- package/src/lib/config-schema.mjs +119 -0
- package/src/lib/config.mjs +34 -7
- package/src/lib/config.test.mjs +51 -2
- package/src/lib/error-codes.mjs +11 -0
- package/src/lib/integrations.mjs +155 -0
- package/src/lib/integrations.test.mjs +154 -0
- package/src/lib/levenshtein.mjs +29 -0
- package/src/lib/manifest.mjs +10 -0
- package/src/lib/package-scanner.mjs +31 -7
- package/src/lib/string-utils.mjs +5 -14
- package/src/lib/xle/browser.d.ts +100 -0
- package/src/lib/xle/browser.mjs +120 -0
- package/src/lib/xle/expand.mjs +622 -0
- package/src/lib/xle/parse.mjs +581 -0
- package/src/lib/xle/print.mjs +174 -0
- package/src/lib/xle/registry-core.mjs +170 -0
- package/src/lib/xle/registry.mjs +237 -0
- package/src/lib/xle/splice.mjs +137 -0
- package/src/lib/xle/validate.mjs +356 -0
- package/src/lib/xle/xle.test.mjs +333 -0
- package/src/types/config.d.ts +99 -0
- package/src/utils/github.mjs +12 -27
- package/templates/blocks/components/Card/ClickableCardWithNestedButton.doc.mjs +1 -1
- package/templates/blocks/components/Card/SelectableCardMulti.doc.mjs +1 -1
- package/templates/blocks/components/ChatComposerDrawer/ChatComposerDrawerWithProgress.tsx +1 -1
- package/templates/blocks/components/ChatDictationButton/ChatDictationButtonShowcase.tsx +3 -3
- package/templates/blocks/components/CommandPaletteEmpty/CommandPaletteEmptyShowcase.doc.mjs +15 -0
- package/templates/blocks/components/CommandPaletteEmpty/CommandPaletteEmptyShowcase.tsx +26 -0
- package/templates/blocks/components/DateInput/DateInputDateRange.doc.mjs +2 -2
- package/templates/blocks/components/FileInput/FileInputShowcase.tsx +4 -2
- package/templates/blocks/components/LinkProvider/LinkProviderCustomLink.doc.mjs +14 -0
- package/templates/blocks/components/LinkProvider/LinkProviderCustomLink.tsx +43 -0
- package/templates/blocks/components/MultiSelector/MultiSelectorShowcase.tsx +6 -2
- package/templates/blocks/components/NumberInput/NumberInputShowcase.tsx +6 -2
- package/templates/blocks/components/Outline/OutlineShowcase.doc.mjs +15 -0
- package/templates/blocks/components/Outline/OutlineShowcase.tsx +22 -0
- package/templates/blocks/components/RadioList/RadioListShowcase.tsx +8 -1
- package/templates/blocks/components/SegmentedControl/SegmentedControlShowcase.tsx +3 -1
- package/templates/blocks/components/Selector/SelectorShowcase.tsx +4 -1
- package/templates/blocks/components/Slider/SliderShowcase.tsx +10 -1
- package/templates/blocks/components/Tab/TabShowcase.tsx +3 -1
- package/templates/blocks/components/TabList/TabListShowcase.tsx +3 -1
- package/templates/blocks/components/TabMenu/TabMenuShowcase.tsx +3 -1
- package/templates/blocks/components/Table/ColumnResizeHookUsage.doc.mjs +14 -0
- package/templates/blocks/components/Table/ColumnResizeHookUsage.tsx +59 -0
- package/templates/blocks/components/Table/StickyColumnsHookUsage.doc.mjs +14 -0
- package/templates/blocks/components/Table/StickyColumnsHookUsage.tsx +104 -0
- package/templates/blocks/components/Text/TextColors.tsx +20 -5
- package/templates/blocks/components/TextArea/TextAreaShowcase.tsx +4 -2
- package/templates/blocks/components/TextInput/TextInputShowcase.tsx +4 -2
- package/templates/blocks/components/Thumbnail/ThumbnailDisabled.tsx +11 -6
- package/templates/blocks/components/Thumbnail/ThumbnailGallery.tsx +43 -7
- package/templates/blocks/components/Thumbnail/ThumbnailRemovable.tsx +40 -3
- package/templates/blocks/components/Thumbnail/ThumbnailShowcase.tsx +6 -5
- package/templates/blocks/components/Thumbnail/ThumbnailStates.tsx +11 -6
- package/templates/blocks/components/Timestamp/TimestampColors.tsx +2 -2
- package/templates/blocks/components/ToggleButton/ToggleButtonGroup.doc.mjs +1 -1
- package/templates/blocks/components/Tokenizer/TokenizerShowcase.tsx +8 -6
- package/templates/blocks/components/Toolbar/ToolbarTableFilter.doc.mjs +2 -2
- package/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +23 -14
- package/templates/blocks/components/Typeahead/TypeaheadShowcase.tsx +6 -2
- package/templates/pages/shell-nav/page.tsx +321 -0
- package/templates/pages/shell-nav/template.doc.mjs +12 -0
- package/templates/pages/shell-side-nav/page.tsx +242 -0
- package/templates/pages/shell-side-nav/template.doc.mjs +12 -0
- package/templates/pages/shell-top-nav/page.tsx +224 -0
- package/templates/pages/shell-top-nav/template.doc.mjs +12 -0
- package/templates/pages/theme-showcase/page.tsx +8 -19
- package/templates/themes/butter/butterTheme.ts +916 -0
- package/templates/themes/butter/icons.tsx +77 -0
- package/templates/themes/chocolate/chocolateTheme.ts +230 -0
- package/templates/themes/chocolate/icons.tsx +77 -0
- package/templates/themes/gothic/gothicTheme.ts +657 -0
- package/templates/themes/gothic/icons.tsx +77 -0
- package/templates/themes/manifest.json +90 -0
- package/templates/themes/matcha/icons.tsx +67 -0
- package/templates/themes/matcha/matchaTheme.ts +247 -0
- package/templates/themes/neutral/icons.tsx +77 -0
- package/templates/themes/neutral/neutralTheme.ts +603 -0
- package/templates/themes/stone/icons.tsx +77 -0
- package/templates/themes/stone/stoneTheme.ts +652 -0
- package/templates/themes/y2k/icons.tsx +67 -0
- package/templates/themes/y2k/y2kTheme.ts +617 -0
- package/templates/blocks/components/MoreMenu/MoreMenuInToolbar.doc.mjs +0 -14
- package/templates/blocks/components/MoreMenu/MoreMenuInToolbar.tsx +0 -57
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
import type {AnchorHTMLAttributes} from 'react';
|
|
6
|
+
import {Link, LinkProvider} from '@astryxdesign/core/Link';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A stand-in for a framework router link (e.g. Next.js `Link` or React
|
|
10
|
+
* Router `Link`). Instead of letting the browser do a full-page navigation,
|
|
11
|
+
* it intercepts the click and hands the destination to a custom handler —
|
|
12
|
+
* the same hook real routers use for client-side navigation. Here it just
|
|
13
|
+
* announces the target so the behavior swap is observable in the preview.
|
|
14
|
+
*/
|
|
15
|
+
function RouterLink({
|
|
16
|
+
href,
|
|
17
|
+
onClick,
|
|
18
|
+
children,
|
|
19
|
+
...props
|
|
20
|
+
}: AnchorHTMLAttributes<HTMLAnchorElement>) {
|
|
21
|
+
return (
|
|
22
|
+
<a
|
|
23
|
+
href={href}
|
|
24
|
+
onClick={e => {
|
|
25
|
+
e.preventDefault();
|
|
26
|
+
onClick?.(e);
|
|
27
|
+
alert(`RouterLink intercepted navigation to: ${href}`);
|
|
28
|
+
}}
|
|
29
|
+
{...props}>
|
|
30
|
+
{children}
|
|
31
|
+
</a>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default function LinkProviderCustomLink() {
|
|
36
|
+
return (
|
|
37
|
+
<LinkProvider component={RouterLink}>
|
|
38
|
+
<Link href="/dashboard" isStandalone>
|
|
39
|
+
Go to dashboard
|
|
40
|
+
</Link>
|
|
41
|
+
</LinkProvider>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
import {useState} from 'react';
|
|
3
6
|
import {MultiSelector} from '@astryxdesign/core/MultiSelector';
|
|
4
7
|
|
|
5
8
|
export default function MultiSelectorShowcase() {
|
|
9
|
+
const [value, setValue] = useState<string[]>([]);
|
|
6
10
|
return (
|
|
7
11
|
<div style={{width: 300}}>
|
|
8
12
|
<MultiSelector
|
|
9
13
|
label="Columns"
|
|
10
14
|
options={['Name', 'Email', 'Role', 'Status', 'Created']}
|
|
11
|
-
value={
|
|
12
|
-
onChange={
|
|
15
|
+
value={value}
|
|
16
|
+
onChange={setValue}
|
|
13
17
|
placeholder="Select columns..."
|
|
14
18
|
/>
|
|
15
19
|
</div>
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
import {useState} from 'react';
|
|
3
6
|
import {NumberInput} from '@astryxdesign/core/NumberInput';
|
|
4
7
|
|
|
5
8
|
export default function NumberInputShowcase() {
|
|
9
|
+
const [value, setValue] = useState<number | null>(0);
|
|
6
10
|
return (
|
|
7
11
|
<div style={{width: 300}}>
|
|
8
12
|
<NumberInput
|
|
9
13
|
label="Quantity"
|
|
10
14
|
placeholder="Enter quantity"
|
|
11
|
-
value={
|
|
12
|
-
onChange={
|
|
15
|
+
value={value}
|
|
16
|
+
onChange={setValue}
|
|
13
17
|
/>
|
|
14
18
|
</div>
|
|
15
19
|
);
|
|
@@ -0,0 +1,15 @@
|
|
|
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: 'Outline',
|
|
7
|
+
name: 'Outline',
|
|
8
|
+
displayName: 'Outline',
|
|
9
|
+
description:
|
|
10
|
+
'A document outline with the active section highlighted by the sliding indicator track.',
|
|
11
|
+
isReady: true,
|
|
12
|
+
aspectRatio: 16 / 9,
|
|
13
|
+
isShowcase: true,
|
|
14
|
+
componentsUsed: ['Outline'],
|
|
15
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
import {Outline} from '@astryxdesign/core/Outline';
|
|
6
|
+
import type {OutlineItem} from '@astryxdesign/core/Outline';
|
|
7
|
+
|
|
8
|
+
const items: OutlineItem[] = [
|
|
9
|
+
{id: 'showcase-overview', label: 'Overview', level: 2},
|
|
10
|
+
{id: 'showcase-installation', label: 'Installation', level: 2},
|
|
11
|
+
{id: 'showcase-theming', label: 'Theming', level: 2},
|
|
12
|
+
{id: 'showcase-tokens', label: 'Tokens', level: 3},
|
|
13
|
+
{id: 'showcase-accessibility', label: 'Accessibility', level: 2},
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
export default function OutlineShowcase() {
|
|
17
|
+
return (
|
|
18
|
+
<div style={{width: 240}}>
|
|
19
|
+
<Outline items={items} activeId="showcase-theming" />
|
|
20
|
+
</div>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
import {useState} from 'react';
|
|
3
6
|
import {RadioList, RadioListItem} from '@astryxdesign/core/RadioList';
|
|
4
7
|
|
|
5
8
|
export default function RadioListShowcase() {
|
|
9
|
+
const [value, setValue] = useState('');
|
|
6
10
|
return (
|
|
7
|
-
<RadioList
|
|
11
|
+
<RadioList
|
|
12
|
+
label="Notification preference"
|
|
13
|
+
value={value}
|
|
14
|
+
onChange={setValue}>
|
|
8
15
|
<RadioListItem label="Email" value="email" />
|
|
9
16
|
<RadioListItem label="SMS" value="sms" />
|
|
10
17
|
<RadioListItem label="Push notification" value="push" />
|
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
'use client';
|
|
4
4
|
|
|
5
|
+
import {useState} from 'react';
|
|
5
6
|
import {
|
|
6
7
|
SegmentedControl,
|
|
7
8
|
SegmentedControlItem,
|
|
8
9
|
} from '@astryxdesign/core/SegmentedControl';
|
|
9
10
|
|
|
10
11
|
export default function SegmentedControlShowcase() {
|
|
12
|
+
const [value, setValue] = useState('grid');
|
|
11
13
|
return (
|
|
12
|
-
<SegmentedControl value=
|
|
14
|
+
<SegmentedControl value={value} onChange={setValue} label="View mode">
|
|
13
15
|
<SegmentedControlItem value="grid" label="Grid" />
|
|
14
16
|
<SegmentedControlItem value="list" label="List" />
|
|
15
17
|
<SegmentedControlItem value="table" label="Table" />
|
|
@@ -2,16 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
'use client';
|
|
4
4
|
|
|
5
|
+
import {useState} from 'react';
|
|
5
6
|
import {Selector} from '@astryxdesign/core/Selector';
|
|
6
7
|
|
|
7
8
|
export default function SelectorShowcase() {
|
|
9
|
+
const [value, setValue] = useState<string | undefined>();
|
|
8
10
|
return (
|
|
9
11
|
<Selector
|
|
10
12
|
style={{width: 300}}
|
|
11
13
|
label="Fruit"
|
|
12
14
|
options={['Apple', 'Banana', 'Orange', 'Mango', 'Pineapple']}
|
|
13
15
|
placeholder="Select a fruit..."
|
|
14
|
-
|
|
16
|
+
value={value}
|
|
17
|
+
onChange={setValue}
|
|
15
18
|
/>
|
|
16
19
|
);
|
|
17
20
|
}
|
|
@@ -2,8 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
'use client';
|
|
4
4
|
|
|
5
|
+
import {useState} from 'react';
|
|
5
6
|
import {Slider} from '@astryxdesign/core/Slider';
|
|
6
7
|
|
|
7
8
|
export default function SliderShowcase() {
|
|
8
|
-
|
|
9
|
+
const [value, setValue] = useState(50);
|
|
10
|
+
return (
|
|
11
|
+
<Slider
|
|
12
|
+
label="Volume"
|
|
13
|
+
value={value}
|
|
14
|
+
onChange={setValue}
|
|
15
|
+
style={{width: 300}}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
9
18
|
}
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
'use client';
|
|
4
4
|
|
|
5
|
+
import {useState} from 'react';
|
|
5
6
|
import {TabList, Tab} from '@astryxdesign/core/TabList';
|
|
6
7
|
import {Badge} from '@astryxdesign/core/Badge';
|
|
7
8
|
|
|
8
9
|
export default function TabShowcase() {
|
|
10
|
+
const [value, setValue] = useState('inbox');
|
|
9
11
|
return (
|
|
10
|
-
<TabList value=
|
|
12
|
+
<TabList value={value} onChange={setValue}>
|
|
11
13
|
<Tab
|
|
12
14
|
value="inbox"
|
|
13
15
|
label="Inbox"
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
'use client';
|
|
4
4
|
|
|
5
|
+
import {useState} from 'react';
|
|
5
6
|
import {TabList, Tab} from '@astryxdesign/core/TabList';
|
|
6
7
|
|
|
7
8
|
export default function TabListShowcase() {
|
|
9
|
+
const [value, setValue] = useState('home');
|
|
8
10
|
return (
|
|
9
|
-
<TabList value=
|
|
11
|
+
<TabList value={value} onChange={setValue}>
|
|
10
12
|
<Tab value="home" label="Home" />
|
|
11
13
|
<Tab value="projects" label="Projects" />
|
|
12
14
|
<Tab value="settings" label="Settings" />
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
'use client';
|
|
4
4
|
|
|
5
|
+
import {useState} from 'react';
|
|
5
6
|
import {TabList, Tab, TabMenu} from '@astryxdesign/core/TabList';
|
|
6
7
|
|
|
7
8
|
export default function TabMenuShowcase() {
|
|
9
|
+
const [value, setValue] = useState('settings');
|
|
8
10
|
return (
|
|
9
|
-
<TabList value=
|
|
11
|
+
<TabList value={value} onChange={setValue}>
|
|
10
12
|
<Tab value="overview" label="Overview" />
|
|
11
13
|
<Tab value="activity" label="Activity" />
|
|
12
14
|
<TabMenu
|
|
@@ -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: 'useTableColumnResize',
|
|
7
|
+
name: 'useTableColumnResize — Draggable Columns',
|
|
8
|
+
displayName: 'useTableColumnResize — Draggable Columns',
|
|
9
|
+
description:
|
|
10
|
+
'A Table using useTableColumnResize. Drag the right edge of any column header to resize; widths are committed on release. The last proportional column flexes to fill remaining space.',
|
|
11
|
+
isReady: true,
|
|
12
|
+
aspectRatio: 16 / 9,
|
|
13
|
+
componentsUsed: ['Table'],
|
|
14
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
import {useState} from 'react';
|
|
6
|
+
import {
|
|
7
|
+
Table,
|
|
8
|
+
useTableColumnResize,
|
|
9
|
+
proportional,
|
|
10
|
+
pixel,
|
|
11
|
+
} from '@astryxdesign/core/Table';
|
|
12
|
+
|
|
13
|
+
interface User extends Record<string, unknown> {
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
email: string;
|
|
17
|
+
role: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const users: User[] = [
|
|
21
|
+
{
|
|
22
|
+
id: '1',
|
|
23
|
+
name: 'Alice Johnson',
|
|
24
|
+
email: 'alice@example.com',
|
|
25
|
+
role: 'Engineer',
|
|
26
|
+
},
|
|
27
|
+
{id: '2', name: 'Bob Smith', email: 'bob@example.com', role: 'Designer'},
|
|
28
|
+
{id: '3', name: 'Charlie Brown', email: 'charlie@example.com', role: 'PM'},
|
|
29
|
+
{id: '4', name: 'Diana Prince', email: 'diana@example.com', role: 'Engineer'},
|
|
30
|
+
{id: '5', name: 'Eve Davis', email: 'eve@example.com', role: 'Analyst'},
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
const columns = [
|
|
34
|
+
{key: 'name', header: 'Name'},
|
|
35
|
+
{key: 'email', header: 'Email', width: proportional(2)},
|
|
36
|
+
{key: 'role', header: 'Role', width: pixel(120)},
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
export default function ColumnResizeHookUsage() {
|
|
40
|
+
const [columnWidths, setColumnWidths] = useState<Record<string, number>>({});
|
|
41
|
+
|
|
42
|
+
const columnResize = useTableColumnResize({
|
|
43
|
+
columnWidths,
|
|
44
|
+
columns,
|
|
45
|
+
onColumnResizeEnd: updates => {
|
|
46
|
+
setColumnWidths(prev => ({...prev, ...updates}));
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<Table
|
|
52
|
+
data={users}
|
|
53
|
+
columns={columns}
|
|
54
|
+
idKey="id"
|
|
55
|
+
hasHover
|
|
56
|
+
plugins={{columnResize}}
|
|
57
|
+
/>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
@@ -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: 'useTableStickyColumns',
|
|
7
|
+
name: 'useTableStickyColumns — Pinned Columns',
|
|
8
|
+
displayName: 'useTableStickyColumns — Pinned Columns',
|
|
9
|
+
description:
|
|
10
|
+
'A Table using useTableStickyColumns to pin the Name column to the start edge and Status to the end edge. Scroll horizontally; pinned columns stay in view with a soft shadow over the scrolling content.',
|
|
11
|
+
isReady: true,
|
|
12
|
+
aspectRatio: 16 / 9,
|
|
13
|
+
componentsUsed: ['Table'],
|
|
14
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
import {Table, useTableStickyColumns, pixel} from '@astryxdesign/core/Table';
|
|
6
|
+
|
|
7
|
+
interface Employee extends Record<string, unknown> {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
email: string;
|
|
11
|
+
team: string;
|
|
12
|
+
role: string;
|
|
13
|
+
location: string;
|
|
14
|
+
startDate: string;
|
|
15
|
+
status: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const employees: Employee[] = [
|
|
19
|
+
{
|
|
20
|
+
id: '1',
|
|
21
|
+
name: 'Alice Johnson',
|
|
22
|
+
email: 'alice@example.com',
|
|
23
|
+
team: 'Design Systems',
|
|
24
|
+
role: 'Staff Engineer',
|
|
25
|
+
location: 'San Francisco',
|
|
26
|
+
startDate: '2019-03-12',
|
|
27
|
+
status: 'Active',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: '2',
|
|
31
|
+
name: 'Bob Smith',
|
|
32
|
+
email: 'bob@example.com',
|
|
33
|
+
team: 'Design Systems',
|
|
34
|
+
role: 'Senior Designer',
|
|
35
|
+
location: 'New York',
|
|
36
|
+
startDate: '2020-07-01',
|
|
37
|
+
status: 'Active',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: '3',
|
|
41
|
+
name: 'Charlie Brown',
|
|
42
|
+
email: 'charlie@example.com',
|
|
43
|
+
team: 'Platform',
|
|
44
|
+
role: 'Engineering Manager',
|
|
45
|
+
location: 'London',
|
|
46
|
+
startDate: '2017-11-20',
|
|
47
|
+
status: 'On leave',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: '4',
|
|
51
|
+
name: 'Diana Prince',
|
|
52
|
+
email: 'diana@example.com',
|
|
53
|
+
team: 'Platform',
|
|
54
|
+
role: 'Staff Engineer',
|
|
55
|
+
location: 'Remote',
|
|
56
|
+
startDate: '2021-01-15',
|
|
57
|
+
status: 'Active',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: '5',
|
|
61
|
+
name: 'Eve Davis',
|
|
62
|
+
email: 'eve@example.com',
|
|
63
|
+
team: 'Growth',
|
|
64
|
+
role: 'Product Engineer',
|
|
65
|
+
location: 'Berlin',
|
|
66
|
+
startDate: '2022-05-30',
|
|
67
|
+
status: 'Active',
|
|
68
|
+
},
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
// Wide fixed-width columns so the table overflows and scrolls horizontally,
|
|
72
|
+
// keeping the pinned Name (start) and Status (end) columns in view.
|
|
73
|
+
const columns = [
|
|
74
|
+
{key: 'name', header: 'Name', width: pixel(180)},
|
|
75
|
+
{key: 'email', header: 'Email', width: pixel(220)},
|
|
76
|
+
{key: 'team', header: 'Team', width: pixel(180)},
|
|
77
|
+
{key: 'role', header: 'Role', width: pixel(200)},
|
|
78
|
+
{key: 'location', header: 'Location', width: pixel(160)},
|
|
79
|
+
{key: 'startDate', header: 'Start date', width: pixel(140)},
|
|
80
|
+
{key: 'status', header: 'Status', width: pixel(140)},
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
export default function StickyColumnsHookUsage() {
|
|
84
|
+
const stickyColumns = useTableStickyColumns<Employee>({
|
|
85
|
+
startKeys: ['name'],
|
|
86
|
+
endKeys: ['status'],
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
// Constrain the width so the Table's own horizontal scroll container is
|
|
91
|
+
// narrower than its columns — that scroll container is what sticky columns
|
|
92
|
+
// pin against. Without a width cap the table renders full-width and never
|
|
93
|
+
// scrolls internally, so nothing sticks.
|
|
94
|
+
<div style={{width: 560, maxWidth: '100%'}}>
|
|
95
|
+
<Table
|
|
96
|
+
data={employees}
|
|
97
|
+
columns={columns}
|
|
98
|
+
idKey="id"
|
|
99
|
+
hasHover
|
|
100
|
+
plugins={{stickyColumns}}
|
|
101
|
+
/>
|
|
102
|
+
</div>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
@@ -6,11 +6,26 @@ import {Text} from '@astryxdesign/core/Text';
|
|
|
6
6
|
import {Stack} from '@astryxdesign/core/Stack';
|
|
7
7
|
|
|
8
8
|
const COLORS = [
|
|
9
|
-
{
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
{
|
|
9
|
+
{
|
|
10
|
+
color: 'primary' as const,
|
|
11
|
+
description: 'Primary — Default for headings and body text',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
color: 'secondary' as const,
|
|
15
|
+
description: 'Secondary — Supporting details and metadata',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
color: 'accent' as const,
|
|
19
|
+
description: 'Accent — Links, emphasis, and accent-colored text',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
color: 'disabled' as const,
|
|
23
|
+
description: 'Disabled — Unavailable or inactive content',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
color: 'placeholder' as const,
|
|
27
|
+
description: 'Placeholder — Empty field hints',
|
|
28
|
+
},
|
|
14
29
|
];
|
|
15
30
|
|
|
16
31
|
export default function TextColors() {
|
|
@@ -2,15 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
'use client';
|
|
4
4
|
|
|
5
|
+
import {useState} from 'react';
|
|
5
6
|
import {TextArea} from '@astryxdesign/core/TextArea';
|
|
6
7
|
|
|
7
8
|
export default function TextAreaShowcase() {
|
|
9
|
+
const [value, setValue] = useState('');
|
|
8
10
|
return (
|
|
9
11
|
<div style={{width: 400}}>
|
|
10
12
|
<TextArea
|
|
11
13
|
label="Description"
|
|
12
|
-
value=
|
|
13
|
-
onChange={
|
|
14
|
+
value={value}
|
|
15
|
+
onChange={setValue}
|
|
14
16
|
placeholder="Enter a description..."
|
|
15
17
|
/>
|
|
16
18
|
</div>
|
|
@@ -2,15 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
'use client';
|
|
4
4
|
|
|
5
|
+
import {useState} from 'react';
|
|
5
6
|
import {TextInput} from '@astryxdesign/core/TextInput';
|
|
6
7
|
|
|
7
8
|
export default function TextInputShowcase() {
|
|
9
|
+
const [value, setValue] = useState('');
|
|
8
10
|
return (
|
|
9
11
|
<div style={{width: 300}}>
|
|
10
12
|
<TextInput
|
|
11
13
|
label="Name"
|
|
12
|
-
value=
|
|
13
|
-
onChange={
|
|
14
|
+
value={value}
|
|
15
|
+
onChange={setValue}
|
|
14
16
|
placeholder="Enter your name"
|
|
15
17
|
/>
|
|
16
18
|
</div>
|
|
@@ -6,6 +6,11 @@ import {Thumbnail} from '@astryxdesign/core/Thumbnail';
|
|
|
6
6
|
import {Stack} from '@astryxdesign/core/Layout';
|
|
7
7
|
import {Text} from '@astryxdesign/core/Text';
|
|
8
8
|
|
|
9
|
+
// Inline same-origin data URI so the example is self-contained — see
|
|
10
|
+
// ThumbnailRemovable for why image-backed Thumbnails avoid cross-origin URLs.
|
|
11
|
+
const GOLDEN_SUNSET =
|
|
12
|
+
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAkFBMVEX/+uv/7sj6tFr3sVn1r1nzrVjxq1jvqVftp1frpVbpo1bnoVXln1XjnVThm1TfmVPdl1PblVLZk1LXkVLVj1HTjVHRi1DPiVDNh0/LhU/Jg07HgU7Ff03DfU3Be0y/eUy9d0u7dUu5c0u2cEq0bkqybEmwakmuaEisZkiqZEeoYkemYEakXkaiXEVgLjQ8HCjaJlMkAAABI0lEQVR42u3Mx3qDMBSE0Z/03nsvdhxjcnn/twsYjISR5MUkO5+V9N2ZYUPEpogtEdsidkTsitgTsS/iQMShiCMRxyJORJyKOBNxLuJCxKWIKxHXIm5E3Iq4E3Ev4kHEo4gnEc8iXkS8inhLymrJBO8J2UIiw0dc5sRDfEbVRWr1o/pbMMWox9yz6zcLIzMbBTD2VaHu7fr1gjXGA3w5baj5+H0w6x09TDpdaP7rDZhn0sd3y89Y9fcHbPnoYdroZ2w6dQNmg6OHfG4QyrsBC8gdZpVQxtqF4M1mjepFURThTLNgMYsePxaX2WqY6D8GSm2grK2slbGBciHZ9hOE2smNpTuxenhieCdeH06E7qTqvYnImWTbbUSPlKL1wHrgTwZ+AWq+3H5MpRkwAAAAAElFTkSuQmCC';
|
|
13
|
+
|
|
9
14
|
export default function ThumbnailDisabled() {
|
|
10
15
|
return (
|
|
11
16
|
<Stack direction="vertical" gap={4}>
|
|
@@ -15,9 +20,9 @@ export default function ThumbnailDisabled() {
|
|
|
15
20
|
</Text>
|
|
16
21
|
<Stack direction="horizontal" gap={3} vAlign="center">
|
|
17
22
|
<Thumbnail
|
|
18
|
-
src=
|
|
19
|
-
alt="
|
|
20
|
-
label="
|
|
23
|
+
src={GOLDEN_SUNSET}
|
|
24
|
+
alt="Golden sunset over mountains"
|
|
25
|
+
label="golden-sunset.jpg"
|
|
21
26
|
onRemove={() => {}}
|
|
22
27
|
/>
|
|
23
28
|
<Thumbnail label="document.pdf" onRemove={() => {}} />
|
|
@@ -29,9 +34,9 @@ export default function ThumbnailDisabled() {
|
|
|
29
34
|
</Text>
|
|
30
35
|
<Stack direction="horizontal" gap={3} vAlign="center">
|
|
31
36
|
<Thumbnail
|
|
32
|
-
src=
|
|
33
|
-
alt="
|
|
34
|
-
label="
|
|
37
|
+
src={GOLDEN_SUNSET}
|
|
38
|
+
alt="Golden sunset over mountains"
|
|
39
|
+
label="golden-sunset.jpg"
|
|
35
40
|
onRemove={() => {}}
|
|
36
41
|
isDisabled
|
|
37
42
|
/>
|
|
@@ -7,11 +7,47 @@ import {Thumbnail} from '@astryxdesign/core/Thumbnail';
|
|
|
7
7
|
import {Stack} from '@astryxdesign/core/Layout';
|
|
8
8
|
import {Text} from '@astryxdesign/core/Text';
|
|
9
9
|
|
|
10
|
+
// Demo imagery is inlined as same-origin data URIs so the example is
|
|
11
|
+
// self-contained. Thumbnail's remove-button overlay uses useImageMode, which
|
|
12
|
+
// FETCHES the image to sample pixels (APCA) for contrast — a cross-origin CDN
|
|
13
|
+
// URL without CORS headers cannot be fetched/sampled, so contrast detection
|
|
14
|
+
// fails silently in hosted previews. These scenes are shared verbatim across
|
|
15
|
+
// the Thumbnail examples and span a luminance ramp (night → snow) so the
|
|
16
|
+
// overlay's contrast adaptation is visible.
|
|
17
|
+
const NIGHT_FOREST =
|
|
18
|
+
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAwFBMVEX18+H08uDy8d/y8N/v7t/m5NXl49Tk4tPc3NDX1cnW1cnW1cjW1MjV1MjV1MfR0cXIyLzEw7m8vLC3t68wM0QvM0MvM0IvMkIuMkEtMEErLz8iJjkhJTggJTcgJDcfJDYfIzYeIjUcITMbHzIWHiwYGzIXGjEWGjAWGTAVGS8VGC8UGC4UGC0UFy4TFy0TFywTFi0SFiwRFSsQFSkNFR4QFCoPFCkPFCgPEykOEygOEigNEicNEScMESYIDw8ECgr+gzZIAAABqElEQVR42uWQ61aCQBRGD5GylNBMKS9FZgNdNE0cyUvB+79VM8MoF9Fgplau2j/8nO8c9hqAD0ngDwjeJYH1lrfBWoCtYDboNu/Zv7qQYNap1bpCN1gxFh1dNe5WAsCScWqoWttbChAKvHZZ0W6XQoIFpW8ooFmLCG2Rl1BgaZAU5Ac8yg0RlC9nngCRQDFuhQRzinWmkCuYk3lxQoFrlskVqlcTMcEFvYIKoFbNfmEFuIypWaGGkt66tqZuEbjAHZl6SQVF1WqNvpDAHVktXTvR9JbgDZii1+tZI7cYMJXkCASvksB4L5VxHmAsibzgRRIYbjgfCgFDSeBZkh8W1HMIniSBR0mOQPCQA3RgBk4M5DhNZwdEcbKgLXy5iDiZg5gApRYbqTql2FZgMxAKeEWSNUFYx3s2SfU28HPWItrpySSwE2cEdqrYtxgmxgHGScFmHrAGk8SxczIxZnNC1McFOGshShyb4yxB9sI3CXDGnH0MLsD7F5LvvptEgH12Zg1Pn2WuHsjvrwt8308t+nwxT38sgiAE8/RTeagH+vx/F8SeF0Ja8Ak14ia/LgmpZQAAAABJRU5ErkJggg==';
|
|
19
|
+
const MISTY_VALLEY =
|
|
20
|
+
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAwFBMVEWPnaqJmKSIlaKHlaGGlaKGk6CEkp6Ckp+Cj5uAj51/jZp6i5h8ipd7iZZ4hpR1g5FzhpdzhJN0g5FuhZdsgpVqgZRpgJNpf5JmfpFufYxufYtlfJBpe4tke49neo1ieo5kd4tndoZidopheY1geIxfd4tmdYVddYpcdIlbc4hgcoNebn5ZcodYcYZXb4VVboRUbYNTbIJaantWaXxRa4FQaYBPaH9NZ35UZXZQY3dMZn1LZXxKZHxMYHRKXnIoOEh3WzsBAAABeElEQVR42u3T11oCQQyG4R9FEREFqVJEgh17xbZ7/3cl29gpmQGeeOh7OF+Ss8G3EL6E8CmEdyG8CeFVCC9CeBTCgxDuhXAnhFsh3AjhSgiXQrgQwtlayHrB6TqIyHzCREMTH4rpbxip5nnkRintEUNF0oc8yqnP6Oey3ueQSnlHN6P0ro0Mi4BOSu8dA1mygnbC7G0NMdKEVszuLQXx4oZmhO3NDLlEEY05R280PDGbgD0RaBeI/Bdg7weBMkDLwF4PtBOcwH0gCJZf0DPYdd8Jo8K177hgZbjW+RN2hWffusBVnMR+XE5yfMRx5MPtOOOI0Xd+9ot/rTOiVrtepuabwcDwNFgP6przSH0dqKiOUhUfvaKcO8yVncyM0sK+psSyK4qpPUvRwlUUYrusgoaviG27YMFXNz38I0nc8PNPAFtC2BFClRFWV4cDU5g4WEE0hJ4q1PU8sgmMF0LOmKN2TBOh21RjRsxms3C5WYwrCIX+D/zBgV8HCFv4gVKf1AAAAABJRU5ErkJggg==';
|
|
21
|
+
const GOLDEN_SUNSET =
|
|
22
|
+
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAkFBMVEX/+uv/7sj6tFr3sVn1r1nzrVjxq1jvqVftp1frpVbpo1bnoVXln1XjnVThm1TfmVPdl1PblVLZk1LXkVLVj1HTjVHRi1DPiVDNh0/LhU/Jg07HgU7Ff03DfU3Be0y/eUy9d0u7dUu5c0u2cEq0bkqybEmwakmuaEisZkiqZEeoYkemYEakXkaiXEVgLjQ8HCjaJlMkAAABI0lEQVR42u3Mx3qDMBSE0Z/03nsvdhxjcnn/twsYjISR5MUkO5+V9N2ZYUPEpogtEdsidkTsitgTsS/iQMShiCMRxyJORJyKOBNxLuJCxKWIKxHXIm5E3Iq4E3Ev4kHEo4gnEc8iXkS8inhLymrJBO8J2UIiw0dc5sRDfEbVRWr1o/pbMMWox9yz6zcLIzMbBTD2VaHu7fr1gjXGA3w5baj5+H0w6x09TDpdaP7rDZhn0sd3y89Y9fcHbPnoYdroZ2w6dQNmg6OHfG4QyrsBC8gdZpVQxtqF4M1mjepFURThTLNgMYsePxaX2WqY6D8GSm2grK2slbGBciHZ9hOE2smNpTuxenhieCdeH06E7qTqvYnImWTbbUSPlKL1wHrgTwZ+AWq+3H5MpRkwAAAAAElFTkSuQmCC';
|
|
23
|
+
const SNOWY_PEAKS =
|
|
24
|
+
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAwFBMVEX////6/P/4+//g7vjf7fbf7fTe7fje7fTe7PTd7Pjc7Pfd7PTc6/Xc6/Pb6/fb6/Xb6vTa6/fa6/Xa6vfZ6vfZ6vba6vTZ6fXY6vfY6vbY6ffY6fXX6fbX6fTW6fbX6PXW6PbW6PTV6PbV6PXU6PbV5/XU5/bU5/TU5vXT5/bS5/XT5vTS5vXS5vTR5vXR5fXQ5fXP5fXP5PXO5PXO5PTN5PTN4/TM4/TL4/TM4vTL4vTK4vTO3OqqvtKbrsFcfGgMVnjaAAAC7klEQVR42u2Ta3eaQBCGp0kbTbBBMWDMoiCWEOsFtV4SdcP//1edYQUWwSye9kNOT58POVlm3mdmUWG/3+9et5vVYj6bjoMgGE9n88Vqs33d7SsBcX67WmI+EKBhudpWNcBu94bzlyGO9weEj0uES9zhbVcFSPMYdxzmOKi4xACbNa0/DgY91rGIDusNgjFdY72tAKzXq0U4pTyGm80m/iXDNFys1psqApwf4nwc32x+J9DRYbhDuMRrqIF5vD+zKK0R5LBYfIvFcqUEBZPRsNex9IaW0NCtTm84mqDglxIIQ3z/uEBDqydoDVrBH4d4CyUwowUsA+fXa4I67mBYtAJeQglM4jeg0wLfBLSCLt5COFcC4xffYVZ8gVSABos5/sskVAOjYNjvWrqWxGOFplvd/jD4OZkpgSAYiA1yAtpgGIzGEyW0wYCZeqOeGer1hm6yQUXBD8+1uySofU2okaBre97zSA34nuswk74GqYC+CCZzXM9/VgO+77o2M+LPUcTpUzSYXS3/DB7m4ztomrhEjb7LeAPbdb0KgOe5fTIY6Y8B51O+Xynvgeu6js2Yaep6Q6DrpsmY7biVABthXdPEFfRj3sBTl9nl8JNzLMANSGEahm5QGuNn8/zEAE8xD0g7hrfbdHgqhxO5J/B4BEMtBOv43+M5YkHuCTxk0HwuDGfgvNAAbZljQ/sMnEOhAVoSPKFVCuYBThvgXiKdcF8GlwRZB+Tz8IEhLhca4C6F8yusH0TDXYFjPjEkj+E2gecm8NsT+IkgaQBVQ6F80gA3Ai4uANkl+I0ElYlDjNwAhXyp4Zg/Cg4FAS+dwAsLiPq7PAGuEc5LJ3B+LUjLSf2Q1aGk4V1uyJVTQdYAqgZ5v7T+nu0IuXwmkAwf1yE3IJuQjZDLkiBpAK5o4BUEV6UNh5J8SR1y9VzDoZgvqasFV2frByFQNCgFX/6Q/4J/SxDJTy84/DVBFEmlSw6fRhBFUumiw2cRRJFUuuzwG+qew9oBo+n5AAAAAElFTkSuQmCC';
|
|
25
|
+
|
|
10
26
|
const ATTACHMENTS = [
|
|
11
|
-
{
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
27
|
+
{
|
|
28
|
+
id: 1,
|
|
29
|
+
src: NIGHT_FOREST,
|
|
30
|
+
alt: 'Forest at night under a crescent moon',
|
|
31
|
+
label: 'forest-night.jpg',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: 2,
|
|
35
|
+
src: MISTY_VALLEY,
|
|
36
|
+
alt: 'Misty mountain valley',
|
|
37
|
+
label: 'misty-valley.jpg',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: 3,
|
|
41
|
+
src: GOLDEN_SUNSET,
|
|
42
|
+
alt: 'Golden sunset over mountains',
|
|
43
|
+
label: 'golden-sunset.jpg',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: 4,
|
|
47
|
+
src: SNOWY_PEAKS,
|
|
48
|
+
alt: 'Snowy mountain peaks',
|
|
49
|
+
label: 'snowy-peaks.jpg',
|
|
50
|
+
},
|
|
15
51
|
];
|
|
16
52
|
|
|
17
53
|
export default function ThumbnailGallery() {
|
|
@@ -37,9 +73,9 @@ export default function ThumbnailGallery() {
|
|
|
37
73
|
/>
|
|
38
74
|
))}
|
|
39
75
|
</Stack>
|
|
40
|
-
{selected
|
|
41
|
-
<Text type="supporting" color="
|
|
42
|
-
|
|
76
|
+
{selected && (
|
|
77
|
+
<Text type="supporting" color="secondary">
|
|
78
|
+
Selected: {selected}
|
|
43
79
|
</Text>
|
|
44
80
|
)}
|
|
45
81
|
</Stack>
|