Skip to content

Commit

Permalink
BREAKING CHANGE: #86
Browse files Browse the repository at this point in the history
use `useSyncExternalStore` to sync morfeo with the React render.
Removed `MorfeoProvider` / `MorfeoContext` and introduced `useMorfeo`

Closes #86
  • Loading branch information
mauroerta committed May 29, 2022
1 parent 56f77f2 commit 8db2c5c
Show file tree
Hide file tree
Showing 21 changed files with 184 additions and 266 deletions.
8 changes: 2 additions & 6 deletions devtool/src/devtool/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createRoot } from 'react-dom/client';
import browser from 'webextension-polyfill';
import { resetCss, MorfeoProvider } from '@morfeo/react';
import { resetCss } from '@morfeo/react';
import { getThemeFromAppAndInitMorfeo } from '../_shared/utils';
import { MORFEO_DEVTOOL_PANEL_NAME, ASSETS_PATHS } from '../_shared/constants';
import Devtool from './Devtool';
Expand All @@ -19,9 +19,5 @@ const container = document.getElementById('devtool');

if (container) {
const root = createRoot(container);
root.render(
<MorfeoProvider>
<Devtool />
</MorfeoProvider>,
);
root.render(<Devtool />);
}
91 changes: 67 additions & 24 deletions docs/docs/Packages/hooks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ description: morfeo's hooks package

**@morfeo/hooks** expose a set of hooks to easily use morfeo inside a `react` context.

:::info React v18
To properly use Morfeo in a React environment, you need to have a version of `react >= 18`
:::

## Installation

```bash
Expand All @@ -17,7 +21,6 @@ npm i @morfeo/hooks
yarn add @morfeo/hooks
```

- [MorfeoProvider](#morfeo-provider)
- [useTheme](#usetheme)
- [useThemeSlice](#usethemeslice)
- [useThemeValue](#usethemevalue)
Expand All @@ -27,24 +30,9 @@ yarn add @morfeo/hooks

Advanced

- [useMorfeo](#useMorfeo)
- [useProps](#useprops)

## Morfeo Provider

To sync morfeo with react you have to first of all wrap you app with the `MorfeoProvider`:

```tsx
import { MorfeoProvider } from '@morfeo/hooks';

function App() {
return (
<MorfeoProvider>
<YourApp />
</MorfeoProvider>
);
}
```

## useTheme

Use this hook to get the current theme and use it inside a components:
Expand Down Expand Up @@ -118,9 +106,7 @@ they correspond to `morfeo.getCurrentTheme` and `morfeo.setCurrentTheme` of the

```jsx live
function Button() {
// highlight-start
const [currentTheme, setCurrentTheme] = useCurrentTheme();
// highlight-end

const style = useStyle({
componentName: 'Button',
Expand All @@ -129,9 +115,7 @@ function Button() {
});

const onClick = () => {
// highlight-start
setCurrentTheme(currentTheme === 'light' ? 'dark' : 'light');
// highlight-end
};

return (
Expand Down Expand Up @@ -184,14 +168,73 @@ Just like useTheme, **useStyles** and **useStyle** are the equivalent of the [co
but they force a re-render when the theme changes.
:::
## useProps
## Advanced
### useMorfeo
This hook is used under the hood in all the others hooks, you'll probably never need to use it directly.
It returns the same `morfeo instance` that you'll get from the core API, but it's reactive, to understand
the difference just look at these 2 examples:
By using `useMorfeo` the component is subscribed to theme changes, which means that if the theme changes the component
will be re-rendered:
```tsx live
function App() {
const morfeo = useMorfeo();

const onClick = () => {
morfeo.setCurrentTheme(
morfeo.getCurrentTheme() === 'light' ? 'dark' : 'light',
);
};

return (
<p>
The current theme is: <code>{morfeo.getCurrentTheme()}</code>
<br />
<button onClick={onClick}>Toggle theme</button>
</p>
);
}
```
If instead we use directly the `morfeo` instance from the core-api, the component will not re-render when the theme changes:
```tsx live
function App() {
const onClick = () => {
morfeo.setCurrentTheme(
morfeo.getCurrentTheme() === 'light' ? 'dark' : 'light',
);
};

return (
<p>
The current theme is: <code>{morfeo.getCurrentTheme()}</code>
<br />
<button onClick={onClick}>Toggle theme</button>
</p>
);
}
```
### useProps
Use it to get the default props of a components, a common use is to merge the defaut props with the current props:
```jsx
```jsx live
function MyButton(props) {
const defaultProps = useProps('Button', 'primary');
const className = useClassName({
componentName: 'Button',
variant: 'primary',
});

return <button {...defaultProps} {...props} />;
return (
<button {...defaultProps} {...props} className={className}>
Button with default props
</button>
);
}
```
4 changes: 2 additions & 2 deletions docs/docs/Packages/native.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ title: native
description: morfeo's native package
---

@morfeo/native package is brings to `React Native` the morfeo's eco system
@morfeo/native package brings to `React Native` the morfeo's ecosystem

## Installation

Expand All @@ -23,7 +23,7 @@ yarn add @morfeo/native

## Usage

Just like @morfeo/react, the API of this package is the same as [@morfeo/hooks](./hooks.mdx), the main differences between `@morfeo/react` and `@morfeo/native` are related to how the parsers converts style objects to valid style for React Native, for example in @morfeo/native there you cannot use any pseudo element/class and shadows output is different (`shadowOffset`, `shadowColor`, `shadowOpacity` and `shadowRadius` instead of `boxShadow`)
Just like @morfeo/react, the API of this package is the same as [@morfeo/hooks](./hooks.mdx), the main differences between `@morfeo/react` and `@morfeo/native` are related to how the parsers converts style objects to valid style for React Native, for example in @morfeo/native you cannot use any pseudo element/class, and also, shadows output is different (`shadowOffset`, `shadowColor`, `shadowOpacity` and `shadowRadius` instead of `boxShadow`)

```tsx
import { View, ViewProps } from 'react-native';
Expand Down
6 changes: 2 additions & 4 deletions examples/react/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { createRoot } from 'react-dom/client';
import { initPreset } from '@morfeo/preset-default';
import { morfeo, resetCss, loadFont, MorfeoProvider } from '@morfeo/react';
import { morfeo, resetCss, loadFont } from '@morfeo/react';
import { enableMorfeoDevTool } from '@morfeo/dev-tools';
import App from './App';
import reportWebVitals from './reportWebVitals';
Expand Down Expand Up @@ -48,9 +48,7 @@ if (container) {
const root = createRoot(container);
root.render(
<React.StrictMode>
<MorfeoProvider>
<App />
</MorfeoProvider>
<App />
</React.StrictMode>,
);
}
Expand Down
6 changes: 0 additions & 6 deletions packages/cli/tests/utils/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,25 @@ import { cli } from 'cli-ux';
import { morfeoCLI } from '../../src/commands';

export function run(...args: string[]) {
const _log = console.log;
const _error = console.error;
const _info = cli.info;
const stdout: any[] = [];
const stderr: any[] = [];

cli.info = (message: any) => {
if (typeof message === 'string') {
stdout.push(message);
}
return _info(message);
};

console.log = (message: any) => {
if (typeof message === 'string') {
stdout.push(message);
}
return _log(message);
};

console.error = (message: any) => {
if (typeof message === 'string') {
stderr.push(message);
}
return _error(message);
};

morfeoCLI(args);
Expand Down
138 changes: 8 additions & 130 deletions packages/hooks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,142 +12,20 @@

**@morfeo/hooks** expose a set of hooks to easily use morfeo inside a `react` context.

> **React v18**
>
> To properly use Morfeo in a React environment, you need to have a version of `react >= 18`
## Installation

```bash
# npm
npm i @morfeo/react
npm i @morfeo/hooks

# yarn
yarn add @morfeo/react
```

- [MorfeoProvider](#morfeo-provider)
- [useTheme](#usetheme)
- [useThemeSlice](#usethemeslice)
- [useThemeValue](#usethemevalue)
- [useStyles](#usestyles)
- [useStyle](#usestyle)

Advanced

- [useProps](#useprops)

## Morfeo Provider

To sync morfeo with react you have to first of all wrap you app with the `MorfeoProvider`:

```tsx
import { MorfeoProvider } from '@morfeo/hooks';

function App() {
return (
<MorfeoProvider>
<YourApp />
</MorfeoProvider>
);
}
yarn add @morfeo/hooks
```

## useTheme

Use this hook to get the current theme and use it inside a components:

```jsx
const MyComponent: React.FC = () => {
const theme = useTheme();

return (
<div>
<p>My primary color is: {theme.colors.primary}</p>
<p>My xxl space is: {theme.spaces.xxl}</p>
</div>
);
};
```

> If you already know the [core API](./core) useTheme is the equivalent of `morfeo.getTheme()`, the main difference is that useTheme react
> to theme changes and force a re-render of the component.
Most of the time you don't need all theme, but just a slice or single value, in this cases [useThemeSlice](#useThemeSlice) and [useThemeValue](#useThemeValue) can will give you only the part of the theme you want:

### useThemeSlice

```jsx
const MyComponent: React.FC = () => {
const colors = useThemeSlice('colors');

return (
<div>
<p>My primary color is: {colors.primary}</p>
<p>My secondary color is: {colors.secondary}</p>
</div>
);
};
```

### useThemeValue

```jsx
const MyComponent: React.FC = () => {
const primaryColor = useThemeValue('colors', 'primary');

return (
<div>
<p>My primary color is: {primaryColor}</p>
</div>
);
};
```

## useStyles

If you don't need the theme, but to generate a style based on the theme; The hooks `useStyles` and `useStyle` are made for this reason:

```jsx
const MyComponent: React.FC = () => {
const { agreeStyle, disagreeStyle, textStyle } = useStyles({
agreeStyle: { componentName: 'Button', variant: 'success' },
disagreeStyle: { componentName: 'Button' },
textStyle: { fontSize: '2xl', color: 'white' },
});

return (
<div>
<p style={textStyle}>Nothing is better than a fresh beer in summer 🍺</p>
<button style={agreeStyle}>Oh yes! 🍻</button>
<button style={disagreeStyle}>What about a Coke? 🥤</button>
</div>
);
};
```
## useStyle
Use it if you need to generate just one style:
```jsx
const AgreeButton: React.FC = ({ children }) => {
const buttonStyle = useStyles({
componentName: 'Button',
variant: 'success',
});

return <button style={buttonStyle}>{children}</button>;
};
```
> Just like useTheme, **useStyles** and **useStyle** are the equivalent of the [core API's](https://morfeo.dev/docs/Packages/core) `morfeo.resolve(style)`
> but they force a re-render when the theme changes.
## useProps
Use it to get the default props of a components, a common use is to merge the default props with the current props:
```jsx
function MyButton(props) {
const defaultProps = useProps('Button', 'primary');
## Documentation

return <button {...defaultProps} {...props} />;
}
```
Check out the full [documentation here](https://morfeo.dev/docs/Packages/hooks).
4 changes: 0 additions & 4 deletions packages/hooks/src/MorfeoContext.tsx

This file was deleted.

Loading

0 comments on commit 8db2c5c

Please sign in to comment.