Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Customizable UI components #208

Merged
merged 87 commits into from
Jan 17, 2023
Merged
Show file tree
Hide file tree
Changes from 85 commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
c824e44
feat!: integrate new ucanto and upload-client (#119)
Dec 2, 2022
012a565
fix: update vanilla sign-up example (#129)
yusefnapora Dec 2, 2022
0110ae8
fix: update vue examples (#130)
travis Dec 2, 2022
9ccbe67
fix: update solid examples (#131)
travis Dec 2, 2022
8699b40
docs: update docs for new ucanto integration (#135)
yusefnapora Dec 2, 2022
034ada0
chore: update access-client version
Dec 2, 2022
18e976a
feat: introduce react-ui package
travis Dec 1, 2022
e7737c4
fix: render Uploader children rather than markup
travis Dec 1, 2022
89050e8
chore: move to typescript
travis Dec 2, 2022
c4d74e6
wip: initial version of react ui example app
travis Dec 2, 2022
7ec7c33
chore: move Uploader into react-uploader package (#137)
travis Dec 5, 2022
ec98de1
chore: add docstrings to uploader state and component
travis Dec 5, 2022
0454d94
fix: use preferred CID link
travis Dec 5, 2022
bb0e2b2
fix: correct typo
travis Dec 6, 2022
6dec856
feat: UploadsList components (#141)
travis Dec 7, 2022
ba91721
feat: Add Authenticator and SimpleAuthenticator (#152)
travis Dec 9, 2022
b9802ec
Merge branch 'main' into feat/w3ui-ui
travis Dec 15, 2022
ff0b3d4
fix: unclutter PR
travis Dec 15, 2022
27c4de7
fix: one more extraneous change
travis Dec 15, 2022
4896a4a
fix: delete unecessary dev dependencies
travis Dec 15, 2022
0932d8c
fix: clear out package-log.json and reinstall to fix build issues
travis Dec 15, 2022
560676b
chore: appease linter
travis Dec 15, 2022
fdcce6e
fix: a few more linting and compilation errors
travis Dec 15, 2022
642b68c
fix: update react uploads list example
travis Dec 15, 2022
7072602
fix: update vue examples
travis Dec 19, 2022
110907f
feat: W3Upload "drop in" component (#155)
travis Dec 19, 2022
a0220fd
Merge branch 'fix/react-uploads-list' into feat/w3ui-ui
travis Dec 19, 2022
9c5374a
Merge branch 'fix/update-vue-examples' into feat/w3ui-ui
travis Dec 19, 2022
e6a3002
fix: typo
travis Dec 19, 2022
45a605e
fix: Fix docs link from react-uploads-list to keyring page (#196)
natevw Jan 4, 2023
0e5cf4c
Merge branch 'main' into feat/w3ui-ui
travis Jan 4, 2023
7829770
fix: remove react-ui package and react/ui example
travis Jan 4, 2023
93b7ee0
fix: remove react-ui typescript and rollup configs
travis Jan 4, 2023
9b278e2
chore: add basic docs to the react keyring and uploads list
travis Jan 4, 2023
2eaff3a
chore: a bit more documentation
travis Jan 4, 2023
09c362b
fix: remove circular dependency
travis Jan 5, 2023
c7bf2bf
Revert "fix: remove react-ui typescript and rollup configs"
travis Jan 4, 2023
7882010
Revert "fix: remove react-ui package and react/ui example"
travis Jan 4, 2023
a2c206d
fix: assorted fixes for pnpm compatibility
travis Jan 5, 2023
7723cfd
Merge branch 'main' into feat/customizable-ui
travis Jan 5, 2023
4b85682
Merge branch 'main' into feat/w3ui-ui
travis Jan 5, 2023
9fc7505
Merge branch 'main' into feat/w3ui-ui
travis Jan 6, 2023
ba8b2f9
fix: don't let callers override important properties
travis Jan 9, 2023
cd140a7
fix: Cid -> CID and tweak storedDAGShards typing
travis Jan 9, 2023
9a02e03
fix: tweaks from review
travis Jan 9, 2023
cf6a576
Merge branch 'main' into feat/w3ui-ui
travis Jan 9, 2023
d7fae7c
fix: one more arrow function conversion
travis Jan 9, 2023
8a7e0ad
feat: use an enum for uploader status
travis Jan 9, 2023
5d74af8
feat: support `as` prop in uploader components
travis Jan 7, 2023
4839cdf
feat: use ariakit-react-utils to build all headless components
travis Jan 10, 2023
411c81e
Merge branch 'feat/headless-as' into feat/customizable-ui
travis Jan 10, 2023
a13231d
wip: working on getting UploadsListRoot working as expected
travis Jan 10, 2023
f3f3927
feat: get a version of UploadsListRoot working
travis Jan 10, 2023
de61dd8
feat: get a version of UploadsListRoot working
travis Jan 10, 2023
50a8f90
Merge branch 'feat/headless-as' into feat/customizable-ui
travis Jan 10, 2023
3c9493e
Apply suggestions from code review
travis Jan 10, 2023
139499b
chore: get function names in example programmatically
travis Jan 10, 2023
be83037
fix: use function name rather than the entire implementation
travis Jan 10, 2023
f4d3fda
fix: move back to preferred import style in SimpleUploader
travis Jan 11, 2023
713abcc
fix: don't smother error in authenticator
travis Jan 11, 2023
f1a46b4
fix: unfurl props first in components
travis Jan 11, 2023
0cea4b6
Merge branch 'feat/w3ui-ui' into feat/headless-as
travis Jan 11, 2023
f8ddd20
Merge branch 'feat/headless-as' into feat/customizable-ui
travis Jan 11, 2023
d333c00
fix: change type of children in a few places
travis Jan 12, 2023
85d9ea6
fix: update SimpleUploadsList headers
travis Jan 12, 2023
199e24a
fix: export W3API provider
travis Jan 12, 2023
8645fbb
Merge branch 'main' into feat/w3ui-ui
travis Jan 12, 2023
0d3d488
Merge branch 'main' into feat/headless-as
travis Jan 12, 2023
f1e19ea
Merge branch 'main' into feat/w3ui-ui
travis Jan 12, 2023
9534c29
Merge branch 'feat/w3ui-ui' into feat/headless-as
travis Jan 12, 2023
543e27c
fix: headless authenticator bugfixes
travis Jan 12, 2023
959aac3
Merge branch 'fix/headless-bugfixes' into feat/headless-as
travis Jan 12, 2023
4789aae
Merge branch 'feat/headless-as' into feat/customizable-ui
travis Jan 12, 2023
945dc3f
fix: add uploadsList to the render prop props
travis Jan 12, 2023
2d1400b
fix: automatically load the first page of results
travis Jan 12, 2023
9ba973f
Merge branch 'fix/autoload-uploads' into feat/headless-as
travis Jan 12, 2023
374da08
Merge branch 'feat/headless-as' into feat/customizable-ui
travis Jan 12, 2023
24e144e
feat: use css variable-based styles to enable customization (#240)
travis Jan 13, 2023
abeedfe
Merge branch 'main' into feat/customizable-ui
travis Jan 13, 2023
3faa2bc
fix: various updates from implementing w3console
travis Jan 13, 2023
44a8be8
fix: doublequote -> singlequot
travis Jan 13, 2023
9e017a0
Merge remote-tracking branch 'origin/main' into feat/customizable-ui
olizilla Jan 16, 2023
0247e0b
chore: react-ui -> react
olizilla Jan 16, 2023
46b66ba
chore: examples/react/ui -> examples/react/playground
olizilla Jan 16, 2023
3577117
chore: update lock
olizilla Jan 16, 2023
3a07282
fix: playground layout tweaks
olizilla Jan 17, 2023
08d2555
chore: lint
olizilla Jan 17, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/react.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# `@w3ui/react`

## Install

```sh
npm install @w3ui/react
```
24 changes: 24 additions & 0 deletions examples/react/playground/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
23 changes: 23 additions & 0 deletions examples/react/playground/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# W3UI React Playground

To run this example:

- Clone the w3ui repository and enter the `w3ui` directory

```sh
git clone https://github.com/web3-storage/w3ui
cd w3ui
```

- Install dependencies and build:

```sh
pnpm install
```

- Change to this example directory and run the example:

```sh
cd examples/react/playground
pnpm start
```
13 changes: 13 additions & 0 deletions examples/react/playground/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>W3UI React Playground</title>
</head>
<body style="background-color:#1d2027;">
<div id="root"></div>
<script type="module" src="/src/index.jsx"></script>
</body>
</html>
29 changes: 29 additions & 0 deletions examples/react/playground/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "@w3ui/example-react-playground",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"start": "vite",
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@w3ui/react-keyring": "workspace:^",
"@w3ui/react": "workspace:^",
"@w3ui/react-uploader": "workspace:^",
"@w3ui/react-uploads-list": "workspace:^",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"react-syntax-highlighter": "^15.5.0"
},
"devDependencies": {
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.9",
"@vitejs/plugin-react": "^3.0.0",
"vite": "^4.0.0"
}

}
Binary file added examples/react/playground/public/favicon.ico
Binary file not shown.
18 changes: 18 additions & 0 deletions examples/react/playground/src/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import logo from './logo.png'
import ContentPage from './ContentPage'
import { KeyringProvider } from '@w3ui/react-keyring'

function App () {
return (
<main>
<header style={{ textAlign: 'center', padding: 10 }}>
<img src={logo} width='250' alt='logo' />
</header>
<KeyringProvider>
<ContentPage />
</KeyringProvider>
</main>
)
}

export default App
178 changes: 178 additions & 0 deletions examples/react/playground/src/ContentPage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import React from 'react'
import { UploadsList, Uploader, W3Upload } from '@w3ui/react'
import '@w3ui/react/src/styles/uploader.css'
import { Uploader as UploaderCore, UploaderProvider, useUploader } from '@w3ui/react-uploader'
import { UploadsListProvider } from '@w3ui/react-uploads-list'
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
import { a11yDark } from 'react-syntax-highlighter/dist/esm/styles/prism'

function NoUIUploadComponent () {
const [{ storedDAGShards }, uploader] = useUploader()

return (
<div>
<input type='file' onChange={e => uploader.uploadFile(e.target.files[0])} />
{storedDAGShards?.map(({ cid, size }) => (
<p key={cid.toString()}>
{cid.toString()} ({size} bytes)
</p>
))}
</div>
)
}

function NoUIComponent () {
return (
<UploaderProvider>
<NoUIUploadComponent />
</UploaderProvider>
)
}

function HeadlessUIComponent () {
return (
<UploaderProvider>
<UploaderCore>
<UploaderCore.Form>
<div>
<label htmlFor='file'>File:</label>
<UploaderCore.Input id='file' />
</div>
<button type='submit'>Upload</button>
</UploaderCore.Form>
</UploaderCore>
</UploaderProvider>
)
}

function CustomizableUIComponent () {
return (
<div>
<UploaderProvider>
<Uploader />
</UploaderProvider>
<UploadsListProvider>
<UploadsList />
</UploadsListProvider>
</div>
)
}

function DropinUIComponent () {
return (
<W3Upload />
)
}

export function ContentPage () {
return (
<>
<p>
W3UI provides React components at four different levels of
abstraction, each of which builds upon the last.
</p>

<section>
<h3>1. Drop-in UI</h3>
<p>
Components designed to be dropped into a page with very little customization.
Limited styling customization may be supported:
</p>
<SyntaxHighlighter language='jsx' style={a11yDark}>
{`import { W3Upload } from '@w3ui/react'

function ${DropinUIComponent.name} () {
return (
<W3Upload />
)
}`}
</SyntaxHighlighter>
<DropinUIComponent />
</section>

<section>
<h3>2. Customizable UI</h3>
<p>
Components that work out of the box, and let you customize some aspects of
markup and most of the styling:
</p>
<SyntaxHighlighter language='jsx' style={a11yDark}>
{`import { W3Upload, UploaderProvider } from '@w3ui/react'

function ${CustomizableUIComponent.name}() {
return (
<UploaderProvider>
<Uploader />
</UploaderProvider>
)
}
`}
</SyntaxHighlighter>
<CustomizableUIComponent />
</section>
<section>
<h3>3. Headless UI</h3>
<p>
A set of components designed to work together, modeled after HeadlessUI
components like <a href='https://headlessui.com/react/combobox'>Combobox</a>.
These components don't make any markup or styling choices for you:
</p>
<SyntaxHighlighter language='jsx' style={a11yDark}>
{`import { Uploader } from '@w3ui/react-uploader'

function ${HeadlessUIComponent.name}() {
return (
<Uploader>
<Uploader.Form>
<div>
<label htmlFor='file'>File:</label>
<Uploader.Input id="file" />
</div>
<button type='submit'>Upload</button>
</Uploader.Form>
</Uploader>
)
}`}
</SyntaxHighlighter>
<HeadlessUIComponent />
</section>

<h3>4. No UI</h3>
<p>
Maximum flexibility, React Contexts and hooks only:
</p>
<SyntaxHighlighter language='jsx' style={a11yDark}>
{`import { useUploader, UploaderProvider } from '@w3ui/react-uploader'

function ${NoUIUploadComponent.name}() {
const [{ storedDAGShards }, uploader] = useUploader()

return (
<div>
<input type="file" onChange={e => uploader.uploadFile(e.target.files[0])} />
{storedDAGShards?.map(({ cid, size }) => (
<p key={cid.toString()}>
{cid.toString()} ({size} bytes)
</p>
))}
</div>
)
}

function ${NoUIComponent.name}() {
return (
<UploaderProvider>
<NoUIUploadComponent />
</UploaderProvider>
)
}
`}
</SyntaxHighlighter>
<NoUIComponent />


</>
)
}

export default ContentPage
58 changes: 58 additions & 0 deletions examples/react/playground/src/components/Authenticator.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React, { useState } from 'react'
import { useKeyring } from '@w3ui/react-keyring'

export default function Authenticator ({ children }) {
const [{ space }, { createSpace, registerSpace, cancelRegisterSpace }] = useKeyring()
const [email, setEmail] = useState('')
const [submitted, setSubmitted] = useState(false)

if (space?.registered()) {
return children
}

if (submitted) {
return (
<div>
<h1 className='near-white'>Verify your email address!</h1>
<p>Click the link in the email we sent to {email} to sign in.</p>
<form onSubmit={e => { e.preventDefault(); cancelRegisterSpace() }}>
<button type='submit' className='ph3 pv2'>Cancel</button>
</form>
</div>
)
}

const handleRegisterSubmit = async e => {
e.preventDefault()
setSubmitted(true)
try {
await createSpace()
await registerSpace(email)
} catch (err) {
throw new Error('failed to register', { cause: err })
} finally {
setSubmitted(false)
}
}

return (
<form onSubmit={handleRegisterSubmit}>
<div className='mb3'>
<label htmlFor='email' className='db mb2'>Email address:</label>
<input id='email' className='db pa2 w-100' type='email' value={email} onChange={e => setEmail(e.target.value)} required />
</div>
<button type='submit' className='ph3 pv2' disabled={submitted}>Register</button>
</form>
)
}

/**
* Wrapping a component with this HoC ensures an identity exists.
*/
export function withIdentity (Component) {
return props => (
<Authenticator>
<Component {...props} />
</Authenticator>
)
}
30 changes: 30 additions & 0 deletions examples/react/playground/src/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: white;
}

code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

main {
padding: 96px;
}

.title {
display: flex;
justify-content: center;
}

section::after {
display: block;
text-align: center;
padding: 64px 0;
content: '⁂';
}
Loading