Skip to content

Commit f4f8a44

Browse files
sarbullCezar Sirbusnowystingeryihuiliao
authored
docs: add a new S2 example app using typescript (#8012)
* Add typescript build support for s2 * rename package.json * remove pm details * update webpack config * fix typescript * add empty yarn lock --------- Co-authored-by: Cezar Sirbu <[email protected]> Co-authored-by: Robert Snow <[email protected]> Co-authored-by: Yihui Liao <[email protected]>
1 parent 06dca5b commit f4f8a44

File tree

13 files changed

+1246
-0
lines changed

13 files changed

+1246
-0
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
node_modules
2+
build
3+
.DS_Store
4+
npm-debug.log
5+
yarn-error.log
6+
.yarnclean
7+
.vscode
8+
.idea
9+
dist
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Webpack 5 example
2+
3+
This is a [Webpack](https://webpack.js.org/) project with a minimal React configuration.
4+
5+
## Getting Started
6+
7+
First, run the development server:
8+
9+
```bash
10+
yarn install
11+
yarn dev
12+
```
13+
14+
Open [http://localhost:8080](http://localhost:8080) with your browser to see the result.
15+
16+
style-macro and React Spectrum - Spectrum 2 have been added to `src/App.js` to show an example of a Spectrum 2 styled component. This file does client side rendering. The page auto-updates as you edit the file.
17+
18+
## Macros config
19+
20+
Edit the webpack.config.js to add an import for the plugin and add a webpack config that adds the webpack version of the macros plugin. An empty config file would be updated to look like the following.
21+
22+
```
23+
const macros = require("unplugin-parcel-macros");
24+
25+
module.exports = {
26+
// ...
27+
plugins: [
28+
// ...
29+
macros.webpack(),
30+
// ...
31+
],
32+
};
33+
```
34+
35+
To use the spectrum-theme via macros, pass your styles object to the style() macro and set the result as a new function. This new function or style() should be used within a `className` prop to style your html elements. Use the `styles` prop on React Spectrum components.
36+
37+
```jsx
38+
<div className={style({marginStart: 16})}>
39+
Hello Spectrum 2!
40+
</div>
41+
```
42+
43+
```jsx
44+
<Button styles={style({marginStart: 16})}>
45+
Hello Spectrum 2!
46+
</Button>
47+
```
48+
49+
## Application setup
50+
51+
Please include the page level CSS in the root of your application to configure and support the light and dark themes.
52+
53+
```
54+
import "@react-spectrum/s2/page.css";
55+
```
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"name": "webpack-5-typescript-example",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "./src/index.tsx",
6+
"packageManager": "[email protected]",
7+
"scripts": {
8+
"dev": "webpack serve",
9+
"build": "webpack --mode production"
10+
},
11+
"dependencies": {
12+
"@react-spectrum/s2": "latest",
13+
"react": "^18.2.0",
14+
"react-dom": "^18.2.0"
15+
},
16+
"devDependencies": {
17+
"@swc/core": "^1.11.13",
18+
"@types/react": "^19.0.12",
19+
"@types/react-dom": "^19.0.4",
20+
"css-loader": "^6.10.0",
21+
"css-minimizer-webpack-plugin": "^7.0.0",
22+
"html-webpack-plugin": "^5.6.0",
23+
"lightningcss": "^1.27.0",
24+
"mini-css-extract-plugin": "^2.9.1",
25+
"style-loader": "^3.3.4",
26+
"swc-loader": "^0.2.6",
27+
"swc-minify-webpack-plugin": "^2.1.3",
28+
"typescript": "^5.8.2",
29+
"unplugin-parcel-macros": "0.0.3",
30+
"webpack": "^5.91.0",
31+
"webpack-cli": "^5.1.4",
32+
"webpack-dev-server": "^5.0.4"
33+
}
34+
}
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
/*
2+
* Copyright 2024 Adobe. All rights reserved.
3+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License. You may obtain a copy
5+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software distributed under
8+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9+
* OF ANY KIND, either express or implied. See the License for the specific language
10+
* governing permissions and limitations under the License.
11+
*/
12+
13+
import "@react-spectrum/s2/page.css";
14+
import {
15+
ActionButton,
16+
ActionButtonGroup,
17+
ActionMenu,
18+
Button,
19+
ButtonGroup,
20+
Cell,
21+
Column,
22+
Divider,
23+
Heading,
24+
LinkButton,
25+
Menu,
26+
MenuItem,
27+
MenuTrigger,
28+
Picker,
29+
PickerItem,
30+
Row,
31+
SubmenuTrigger,
32+
TableBody,
33+
TableHeader,
34+
TableView,
35+
Text,
36+
ToggleButton,
37+
ToggleButtonGroup,
38+
TreeView,
39+
TreeViewItem,
40+
TreeViewItemContent
41+
} from "@react-spectrum/s2";
42+
import {CardViewExample} from "./components/CardViewExample";
43+
import {CollectionCardsExample} from "./components/CollectionCardsExample";
44+
import Edit from "@react-spectrum/s2/icons/Edit";
45+
import FileTxt from "@react-spectrum/s2/icons/FileText";
46+
import Folder from "@react-spectrum/s2/icons/Folder";
47+
import {LoadingState} from '@react-types/shared'
48+
import React, {useState} from "react";
49+
import Section from "./components/Section";
50+
import {style} from "@react-spectrum/s2/style" with { type: "macro" };
51+
52+
const Lazy = React.lazy(() => import('./Lazy'));
53+
54+
function App() {
55+
let [isLazyLoaded, setLazyLoaded] = useState(false);
56+
let [cardViewState, setCardViewState] = useState<{layout?: 'grid' | 'waterfall' , loadingState: LoadingState}>({
57+
layout: 'grid',
58+
loadingState: 'idle',
59+
});
60+
let cardViewLoadingOptions = [
61+
{id: 'idle', label: 'Idle'},
62+
{id: 'loading', label: 'Loading'},
63+
{id: 'sorting', label: 'Sorting'},
64+
{id: 'loadingMore', label: 'Loading More'},
65+
{id: 'error', label: 'Error'},
66+
];
67+
let cardViewLayoutOptions = [
68+
{id: 'grid', label: 'Grid'},
69+
{id: 'waterfall', label: 'Waterfall'}
70+
];
71+
return (
72+
<main>
73+
<Heading
74+
styles={style({ font: "heading-xl", textAlign: "center" })}
75+
level={1}
76+
>
77+
Spectrum 2 + Webpack + Typescript
78+
</Heading>
79+
<div
80+
className={style({
81+
maxWidth: 288,
82+
margin: "auto",
83+
})}
84+
>
85+
<Divider />
86+
</div>
87+
<div
88+
className={style({
89+
display: "flex",
90+
flexDirection: "column",
91+
gap: 16,
92+
alignItems: "center"
93+
})}
94+
>
95+
<Section title="Buttons">
96+
<ButtonGroup align="center" styles={style({maxWidth: '[100vw]'})}>
97+
<Button variant="primary">Primary</Button>
98+
<Button variant="secondary">Secondary</Button>
99+
<ActionButton>
100+
<Edit />
101+
<Text>Action Button</Text>
102+
</ActionButton>
103+
<ToggleButton>Toggle Button</ToggleButton>
104+
<LinkButton
105+
variant="primary"
106+
href="https://adobe.com"
107+
target="_blank"
108+
>
109+
Link Button
110+
</LinkButton>
111+
<ActionButtonGroup density="compact">
112+
<ActionButton>Cut</ActionButton>
113+
<ActionButton>Copy</ActionButton>
114+
<ActionButton>Paste</ActionButton>
115+
</ActionButtonGroup>
116+
<ToggleButtonGroup density="compact" selectionMode="multiple">
117+
<ToggleButton id="bold">Bold</ToggleButton>
118+
<ToggleButton id="italic">Italic</ToggleButton>
119+
<ToggleButton id="underline">Underline</ToggleButton>
120+
</ToggleButtonGroup>
121+
</ButtonGroup>
122+
</Section>
123+
124+
<Section title="Collections">
125+
<ActionMenu>
126+
<MenuItem>Action Menu Item 1</MenuItem>
127+
<MenuItem>Action Menu Item 2</MenuItem>
128+
<MenuItem>Action Menu Item 3</MenuItem>
129+
</ActionMenu>
130+
<Picker
131+
label="CardView Loading State"
132+
items={cardViewLoadingOptions}
133+
selectedKey={cardViewState.loadingState}
134+
onSelectionChange={loadingState => setCardViewState({...cardViewState, loadingState} as any)}>
135+
{item => <PickerItem id={item.id}>{item.label}</PickerItem>}
136+
</Picker>
137+
<Picker
138+
label="CardView Layout"
139+
items={cardViewLayoutOptions}
140+
selectedKey={cardViewState.layout}
141+
onSelectionChange={layout => setCardViewState({...cardViewState, layout} as any)}>
142+
{item => <PickerItem id={item.id}>{item.label}</PickerItem>}
143+
</Picker>
144+
<CardViewExample {...cardViewState} />
145+
<Divider styles={style({maxWidth: 320, width: 'full', marginX: 'auto'})} />
146+
<CollectionCardsExample loadingState={cardViewState.loadingState} />
147+
<MenuTrigger>
148+
<ActionButton>Menu</ActionButton>
149+
<Menu onAction={(key) => alert(key.toString())}>
150+
<MenuItem id="cut">Cut</MenuItem>
151+
<MenuItem id="copy">Copy</MenuItem>
152+
<MenuItem id="paste">Paste</MenuItem>
153+
<MenuItem id="replace">Replace</MenuItem>
154+
<SubmenuTrigger>
155+
<MenuItem id="share">Share</MenuItem>
156+
<Menu onAction={(key) => alert(key.toString())}>
157+
<MenuItem id="copy-ink">Copy Link</MenuItem>
158+
<SubmenuTrigger>
159+
<MenuItem id="email">Email</MenuItem>
160+
<Menu onAction={(key) => alert(key.toString())}>
161+
<MenuItem id="attachment">Email as Attachment</MenuItem>
162+
<MenuItem id="link">Email as Link</MenuItem>
163+
</Menu>
164+
</SubmenuTrigger>
165+
<MenuItem id="sms">SMS</MenuItem>
166+
</Menu>
167+
</SubmenuTrigger>
168+
<MenuItem id="delete">Delete</MenuItem>
169+
</Menu>
170+
</MenuTrigger>
171+
<MenuTrigger>
172+
<ActionButton>Menu Trigger</ActionButton>
173+
<Menu>
174+
<MenuItem href="/foo" routerOptions={{ scroll: false } as any}>
175+
Link to /foo
176+
</MenuItem>
177+
<MenuItem>Cut</MenuItem>
178+
<MenuItem>Copy</MenuItem>
179+
<MenuItem>Paste</MenuItem>
180+
</Menu>
181+
</MenuTrigger>
182+
<TableView aria-label="Files" styles={style({width: 320, height: 320})}>
183+
<TableHeader>
184+
<Column isRowHeader>Name</Column>
185+
<Column>Type</Column>
186+
<Column>Date Modified</Column>
187+
<Column>A</Column>
188+
<Column>B</Column>
189+
</TableHeader>
190+
<TableBody>
191+
<Row id="1">
192+
<Cell>Games</Cell>
193+
<Cell>File folder</Cell>
194+
<Cell>6/7/2020</Cell>
195+
<Cell>Dummy content</Cell>
196+
<Cell>Long long long long long long long cell</Cell>
197+
</Row>
198+
<Row id="2">
199+
<Cell>Program Files</Cell>
200+
<Cell>File folder</Cell>
201+
<Cell>4/7/2021</Cell>
202+
<Cell>Dummy content</Cell>
203+
<Cell>Long long long long long long long cell</Cell>
204+
</Row>
205+
<Row id="3">
206+
<Cell>bootmgr</Cell>
207+
<Cell>System file</Cell>
208+
<Cell>11/20/2010</Cell>
209+
<Cell>Dummy content</Cell>
210+
<Cell>Long long long long long long long cell</Cell>
211+
</Row>
212+
</TableBody>
213+
</TableView>
214+
<TreeView disabledKeys={['projects-1']} aria-label="test static tree">
215+
<TreeViewItem id="Photos" textValue="Photos">
216+
<TreeViewItemContent>
217+
<Text>Photos</Text>
218+
<Folder />
219+
</TreeViewItemContent>
220+
</TreeViewItem>
221+
<TreeViewItem id="projects" textValue="Projects">
222+
<TreeViewItemContent>
223+
<Text>Projects</Text>
224+
<Folder />
225+
</TreeViewItemContent>
226+
<TreeViewItem id="projects-1" textValue="Projects-1">
227+
<TreeViewItemContent>
228+
<Text>Projects-1</Text>
229+
<Folder />
230+
</TreeViewItemContent>
231+
<TreeViewItem id="projects-1A" textValue="Projects-1A">
232+
<TreeViewItemContent>
233+
<Text>Projects-1A</Text>
234+
<FileTxt />
235+
</TreeViewItemContent>
236+
</TreeViewItem>
237+
</TreeViewItem>
238+
<TreeViewItem id="projects-2" textValue="Projects-2">
239+
<TreeViewItemContent>
240+
<Text>Projects-2</Text>
241+
<FileTxt />
242+
</TreeViewItemContent>
243+
</TreeViewItem>
244+
<TreeViewItem id="projects-3" textValue="Projects-3">
245+
<TreeViewItemContent>
246+
<Text>Projects-3</Text>
247+
<FileTxt />
248+
</TreeViewItemContent>
249+
</TreeViewItem>
250+
</TreeViewItem>
251+
</TreeView>
252+
</Section>
253+
254+
{!isLazyLoaded && <ActionButton onPress={() => setLazyLoaded(true)}>Load more</ActionButton>}
255+
{isLazyLoaded && <React.Suspense fallback={<>Loading</>}>
256+
<Lazy />
257+
</React.Suspense>}
258+
</div>
259+
</main>
260+
);
261+
}
262+
263+
export default App;

0 commit comments

Comments
 (0)