diff --git a/.eslintignore b/.eslintignore index 34b2959a..b88a9113 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,5 @@ dist lib/nile/src/generated -node_modules \ No newline at end of file +node_modules +!.storybook +storybook-static \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5e8238af..5620f091 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ node_modules !.yarn/cache #.pnp.* package-lock.json + +storybook-static \ No newline at end of file diff --git a/package.json b/package.json index 11d1b242..3cf1844c 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "build:react": "yarn workspace @theniledev/react build", "build:events-example": "yarn workspace @theniledev/events-example build", "build:examples": "yarn workspace @theniledev/examples build", + "build:react-storybook": "yarn workspace @theniledev/react build-storybook", "lint": "yarn eslint . --max-warnings=0", "buildDocs": "yarn workspace @theniledev/js typedoc --plugin typedoc-plugin-markdown --hideBreadcrumbs true src/index.ts", "publish": "yarn lerna publish" @@ -38,7 +39,7 @@ "typescript": "^4.7.2" }, "lint-staged": { - "packages/**/**/*.{mjs,js,ts,jsx,tsx}": "yarn lint --cache --fix --ignore-pattern '!packages/react/.storybook' --resolve-plugins-relative-to .", - "lib/nile/src/*.{mjs,js,ts,jsx,tsx}": "yarn lint --cache --fix --resolve-plugins-relative-to ." + "packages/**/**/*.{mjs,js,ts,jsx,tsx}": "yarn lint --cache --fix .", + "lib/nile/src/*.{mjs,js,ts,jsx,tsx}": "yarn lint --cache --fix ." } } diff --git a/packages/examples/pages/_app.tsx b/packages/examples/pages/_app.tsx index c0b09734..6644cbf2 100644 --- a/packages/examples/pages/_app.tsx +++ b/packages/examples/pages/_app.tsx @@ -2,16 +2,12 @@ import React from 'react'; import '../styles/globals.css'; import type { AppProps } from 'next/app'; import { NileProvider } from '@theniledev/react'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -const queryClient = new QueryClient(); function MyApp({ Component, pageProps }: AppProps) { return ( - - - - - + + + ); } diff --git a/packages/examples/pages/org.tsx b/packages/examples/pages/org.tsx index 32ad8f53..6d9b13f9 100644 --- a/packages/examples/pages/org.tsx +++ b/packages/examples/pages/org.tsx @@ -39,7 +39,7 @@ function Org() { <>

🤩 InstaExpense 🤩

{ + onSuccess={() => { setSuccess(true); }} /> diff --git a/packages/examples/pages/signin.tsx b/packages/examples/pages/signin.tsx index f2fb9f78..375d0b18 100644 --- a/packages/examples/pages/signin.tsx +++ b/packages/examples/pages/signin.tsx @@ -13,7 +13,7 @@ function SignIn() {

🤩 InstaExpense 🤩

Sign in

{ + onSuccess={() => { if (redirect) { router.push(`/${redirect}`); } else { diff --git a/packages/examples/pages/signup.tsx b/packages/examples/pages/signup.tsx index cd492e5b..9c82a54a 100644 --- a/packages/examples/pages/signup.tsx +++ b/packages/examples/pages/signup.tsx @@ -9,7 +9,7 @@ function Signup() {

🤩 InstaExpense 🤩

Sign up

{ + onSuccess={() => { alert('user signed up!'); }} /> diff --git a/packages/react/.storybook/main.js b/packages/react/.storybook/main.js index 4bc8459f..bec91f04 100644 --- a/packages/react/.storybook/main.js +++ b/packages/react/.storybook/main.js @@ -1,3 +1,6 @@ +// eslint-disable-next-line @typescript-eslint/no-var-requires +var path = require('path'); + module.exports = { stories: ['../stories/**/*.stories.@(ts|tsx|js|jsx)'], addons: ['@storybook/addon-links', '@storybook/addon-essentials'], @@ -5,4 +8,35 @@ module.exports = { typescript: { check: true, // type-check stories during Storybook build }, + webpackFinal: async (config) => { + // Remove the existing css rule + config.module.rules = config.module.rules.filter( + (f) => f.test.toString() !== '/\\.css$/' + ); + + config.resolve.modules = [ + ...(config.resolve.modules || []), + path.resolve(__dirname, '../'), + ]; + + config.resolve.alias = { + ...config.resolve.alias, + '~/lib': path.resolve(__dirname, '../lib'), + }; + config.module.rules.push({ + test: /\.css$/, + use: [ + 'style-loader', + { + loader: 'css-loader', + options: { + modules: true, // Enable modules to help you using className + }, + }, + ], + include: path.resolve(__dirname, '../stories'), + }); + + return config; + }, }; diff --git a/packages/react/README.md b/packages/react/README.md index 6b102602..377c59a5 100644 --- a/packages/react/README.md +++ b/packages/react/README.md @@ -1,8 +1,12 @@ # @theniledev/react +## Storybook + +[Storybook](link-to-story-book) + ## Usage -In the root of your react application, add a Nile provider. +In the root of your react application, add a Nile provider. This will add a [QueryClientProvider](https://tanstack.com/query/v4/docs/quick-start) and a [CssVarsProvider](https://mui.com/joy-ui/getting-started/usage/) to your application. ```typescript import { NileProvider } from '@theniledev/react'; @@ -10,7 +14,7 @@ const API_URL = 'https://localhost:8080'; // location of nile instance function App() { return ( - +
Welcome to my great app
); @@ -21,21 +25,25 @@ Once added, there is a hook and components available for use. ### useNile -A method exposing the `@theniledev/js` instance created in ``. The methods on the instance can be found in [the client src readme](../../lib/nile/src/README.md), or found in the auto-complete of visual studio code. In this example, [react-query](https://react-query.tanstack.com/) is used to handle loading, error, and cacheing. +A method exposing the `@theniledev/js` instance created in ``. The methods on the instance can be found in [the client src readme](../../lib/nile/src/README.md), or found in the auto-complete of visual studio code. + +### Making requests + +[react-query](https://react-query.tanstack.com/) should be used used to handle loading, error, and cacheing of data. ```typescript import React, { useEffect } from 'react'; import { useNile } from '@theniledev/react'; -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; export default function UserTable() { const nile = useNile(); const [users, setUsers] = useState(); - const { data: users = [] } = useQuery(() => nile.listUsers()); + const { data: users = [] } = useQuery(['ListUsers'], () => nile.listUsers()); // with multiple requests // const [{ data: users = [] }, { data: invites = [] }] = useQueries([ - // { queryKey: 'users', queryFn: () => nile.listUsers({}) }, - // { queryKey: 'invites', queryFn: () => nile.listInvites({}) }, + // { queryKey: ['users'], queryFn: () => nile.listUsers({}) }, + // { queryKey: ['invites'], queryFn: () => nile.listInvites({}) }, // ]); return ( @@ -46,6 +54,42 @@ export default function UserTable() { } ``` +### UI customization + +For theming and display, [mui joy](https://mui.com/joy-ui/getting-started/overview/) is used. + +For details on theming, see their [theming documentation](https://mui.com/joy-ui/customization/approaches/). You can pass a custom `theme` object to the `NileProvider` and it will pass the custom theme to Mui Joy. + +```typescript +import { NileProvider } from '@theniledev/react'; +import { extendTheme } from '@mui/joy/styles'; +const customTheme = extendTheme({ + colorSchemes: { + light: { + palette: { + primary: { + solidBg: '#0078D4', + solidHoverBg: '#106EBE', + solidActiveBg: '#005A9E', + solidDisabledBg: '#F3F2F1', + solidDisabledColor: '#A19F9D', + }, + }, + }, + }, +}); + +const API_URL = 'https://localhost:8080'; // location of nile instance + +function App() { + return ( + +
Welcome to my great app
+
+ ); +} +``` + ## Available components [LoginForm](./src/components/LoginForm/README.md) diff --git a/packages/react/example/.npmignore b/packages/react/example/.npmignore deleted file mode 100644 index 587e4ec7..00000000 --- a/packages/react/example/.npmignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules -.cache -dist \ No newline at end of file diff --git a/packages/react/example/index.html b/packages/react/example/index.html deleted file mode 100644 index 547e2e04..00000000 --- a/packages/react/example/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - Playground - - - -
- - - diff --git a/packages/react/example/index.tsx b/packages/react/example/index.tsx deleted file mode 100644 index cb3529fc..00000000 --- a/packages/react/example/index.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import 'react-app-polyfill/ie11'; -import * as React from 'react'; -import * as ReactDOM from 'react-dom'; - -import { Thing } from '../.'; - -const App = () => { - return ( -
- -
- ); -}; - -ReactDOM.render(, document.getElementById('root')); diff --git a/packages/react/example/package.json b/packages/react/example/package.json deleted file mode 100644 index a50960f5..00000000 --- a/packages/react/example/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "example", - "version": "1.0.0", - "main": "index.js", - "license": "MIT", - "scripts": { - "start": "parcel index.html", - "build": "parcel build index.html" - }, - "dependencies": { - "react-app-polyfill": "^1.0.0" - }, - "alias": { - "react": "../node_modules/react", - "react-dom": "../node_modules/react-dom/profiling", - "scheduler/tracing": "../node_modules/scheduler/tracing-profiling" - }, - "devDependencies": { - "@types/react": "^16.9.11", - "@types/react-dom": "^16.8.4", - "parcel": "^1.12.3", - "typescript": "^3.4.5" - } -} diff --git a/packages/react/example/tsconfig.json b/packages/react/example/tsconfig.json deleted file mode 100644 index 1e2e4fd9..00000000 --- a/packages/react/example/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "allowSyntheticDefaultImports": false, - "target": "es5", - "module": "commonjs", - "jsx": "react", - "moduleResolution": "node", - "noImplicitAny": false, - "noUnusedLocals": false, - "noUnusedParameters": false, - "removeComments": true, - "strictNullChecks": true, - "preserveConstEnums": true, - "sourceMap": true, - "lib": ["es2015", "es2016", "dom"], - "types": ["node"] - } -} diff --git a/packages/react/package.json b/packages/react/package.json index 0af45f09..e31750ce 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -62,8 +62,8 @@ "@storybook/addon-essentials": "^6.5.10", "@storybook/addon-info": "^5.3.21", "@storybook/addon-links": "^6.5.10", - "@storybook/addons": "^6.4.21", - "@storybook/react": "^6.4.22", + "@storybook/addons": "^6.5.10", + "@storybook/react": "^6.5.10", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.3.0", "@testing-library/react-hooks": "^8.0.1", @@ -82,8 +82,14 @@ "typescript": "^4.7.4" }, "dependencies": { + "@emotion/react": "^11.10.0", + "@emotion/styled": "^11.10.0", + "@mui/joy": "^5.0.0-alpha.40", + "@tanstack/react-query": "^4.1.3", + "@theniledev/js": "^0.13.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-hook-form": "^7.34.1", "react-is": "^18.2.0" } } diff --git a/packages/react/src/components/LoginForm/README.md b/packages/react/src/components/LoginForm/README.md index db9909f6..0a3122ea 100644 --- a/packages/react/src/components/LoginForm/README.md +++ b/packages/react/src/components/LoginForm/README.md @@ -11,11 +11,11 @@ const API_URL = 'http://localhost:8080'; // location of the Nile endpoint function App() { return ( - +

🤩 My Great App🤩

Sign in

{ + onSuccess={() => { console.log('user has logged in'); }} /> @@ -26,31 +26,4 @@ function App() { ## Theming -### General theming (recommended) - -[theming](../../theme/README.md) - -### Advanced theming - -The labels and inputs of this form are customizable via props. You can pass any `React.Node` to it, but at a minimum an `id` must use the passed into the customized `` to ensure submission works properly. For completeness, spread all provided props input `` or `