morfeojs / morfeo Goto Github PK
View Code? Open in Web Editor NEWMorfeo is a build-time CSS-in-TS solution for the next level theming, with the minimum amount of shipped CSS.
Home Page: https://morfeo.dev
License: MIT License
Morfeo is a build-time CSS-in-TS solution for the next level theming, with the minimum amount of shipped CSS.
Home Page: https://morfeo.dev
License: MIT License
Morfeo is based in 2 singletons, theme
and parsers
, the first is used to handle and provide the theme and the second one to parse it and generate styles. Even if it's not hard to understand this concept, most of the times the only methods we need to use of these 2 singleton are:
My idea is to create another singleton morfeo
that exposes only these methods:
getCurrent
: to get the current used themeaddTheme
to add a new theme with a given name (for example "light" or "dark")useTheme
to use one of the previously added themessetTheme
same as theme.setgetTheme
same as theme.getgetThemes
to get all the added themesresolve
same as parsers.resolvemorfeo
will have an easy way to handle multi-theming and, most importantly, will expose only the API that 99% of the time we need; theme
and parsers
singletons will still be available for advanced usage for example add new parsers or easily get single slices or values from the theme.import { morfeo } from "@morfeo/core";
import { lightTheme, darkTheme } from "./themes";
morfeo.addTheme("light", lightTheme);
morfeo.addTheme("dark", darkTheme);
morfeo.useTheme("light");
const style = morfeo.resolve({
py: "m",
gradient: "primary"
});
// will be the current theme, `lightTheme` in this case
const currentTheme = morfeo.getTheme();
// optionally you can pass the name of the theme you want to get
const otherTheme = morfeo.getTheme('dark');
Originally posted by @mauroerta in https://github.com/VLK-STUDIO/morfeo/discussions/59
The provider MorfeoProvider
exported by in @morfeo/hooks
is a provider that should be applied when Morfeo is used in a React environment, but it should not be mandatory.
The provider in fact subscribe the application to theme changes, but the providing of the theme is made by Morfeo (@morfeo/core) anyway.
To Reproduce
Use hooks like useTheme
or useStyles
without wrapping the app with MorfeoProvider
useTheme
inside a component and log the given objectExpected behavior
It logs the current theme
creation of a theme preset that people can use as a starting point for building their own theme.
The current dev tool is mainly a proof of concept, now we know that it's possible to visualize the theme and the components inside it and we want to push it to a new level!
The goal is to build a tool useful for both designers and developers to easily see the design language; Other then this, the dev tool creates a way to visualize the theme and the components automatically, making the process of documenting the design system easier for the developers. For basic components (such as Buttons, Containers or Typographies) it can even replace tools like storybook.
The following are the list of features we will like to have in the first version of the dev tool:
Gabriele and Luca already start to think how the dev tool will look like, whenever the design will be ready we will start the developing process, anyway if anyone has some idea how the dev tool can be done please leave a comment or feel free to send us a message on our slack channel
As suggested by Luca it could be useful to have an additional attribute inside the ComponentConfig
with additional information of the component such as a description, a category, tags or other meta infos that can be used to document the component or by external plugins.
These information should not be used to stylize the component but only to get additional informations.
To enable this feature it's enough to only edit the type ComponentStyle
inside the file packages/spec/src/types/components.ts
and add a new attribute called meta
:
type ComponentStyle<Props extends Style = Style> = {
tag?: string;
style: Style;
props?: Props;
meta?: Meta;
};
This Meta
type could be or any object type Meta = Record<string, any>
or a more strict interface like:
interface Meta {
name?: string;
description?: string;
category?: string;
tags?: string[];
};
Is your feature request related to a problem? Please describe.
Sometimes the style of a component couldn't be enough consistent to present it in a nice way inside the web extension.
Describe the solution you'd like
In these cases, it could be needed to add an additional style to the component, in order to present it in a better way inside the web extension. We can add a devtoolConfig
property inside meta
to define these additional behaviours.
const Flex = {
tag: 'div',
style: {
display: 'flex'
},
meta: {
devtoolConfig: {
label: 'Flex Div',
style: {
size: '100px',
bg: 'gray.light'
},
background: 'white',
}
}
}
Add links and FUNDING.yml file to enable sponsorships and contributions for morfeo through Buy me a beer and Github
The discord link inside the README should point to https://discord.gg/5hbsKMBRBh
which is the invitation link to join the server.
Since morfeo has been transfer to from VLK-STUDIO
to morfeojs
, we need to update every reference to the old url.
Search & Replace all the references.
Creation of a general component to be used inside all the slices lists to uniform the UIs and behaviours.
Describe the bug
After producing a new release, the github workflow publish
starts and automatically publish the new versions of the packages.
Even if all the packages will be published, the workflow fails because inside the package @morfeo/cli a file called
packages/cli/tsconfig.tsbuildinfo and this will result in uncommited changes.
To Reproduce
Produce a new release
Expected behavior
The worflow ends without any error.
This version will include the following updates:
@morfeo/preset-default
: updates to colors
, shadows
and borders
@morfeo/hooks
: new hook useCurrentTheme
(documentation here)@morfeo/core
: breaking change the the core api:
morfeo.useTheme
renamed into morfeo.setCurrentTheme
morfeo.getCurrent
renamed into morfeo.getCurrentTheme
It could be useful to have inside the package @morfeo/preset-default
not only a default set of colors
, borders
or spacings
, but even a set of components
.
I think a good set of components should cover all the possible components that can style a MardDown page, in this way we can start to make custom themes for docusaurus or markdown renders.
Maybe it could be a god idea to first try to write components and test them inside the web-sandbox
, then we can try to use it even inside the svelte-sandbox
so we can be sure they are working fine in different frameworks / libraries.
I think we have to think about how to include the default set of components in a way that can be used even inside react-native
, I was thinking about something like styled-components
that exposes in a single package the sub-package styled-components/native
, so for example we can have:
import { lightTheme } from "@morfeo/preset-default";
// lightTheme: includes components made for the web environment, so they can include:
// media queries, pseudo classes or pseudo elements
// and the tags are related to html elements like `div`, `span`, `button` or `input`
import { lightTheme } from "@morfeo/preset-default/native";
// lightTheme: includes components made for the native environment, so they DON'T include:
// media queries, pseudo classes or pseudo elements
// and the tags are related to native components like `View`, `Pressable` or `Text`
Put the API KEY of algolia docsearch
inside docusaurus.config.js
to enable the search bar
Move apps from the folder apps
to a folder examples
and rename the apps to:
current name | rename |
---|---|
web-sandbox | react |
native-sandbox | react-native |
svelte-sandbox | svelte |
Also, move benchmarks
from apps/benchmarks
to benchmarks
.
I think in this way it will be more clear what apps
really are (examples), also these example can be probably moved in a separate repo whenever Morfeo
will be stable.
Benchmarks
, instead, it's something that we are currently using to always monitor the impact of new features.
Describe the bug
Morfeo should allow to extend a component style (or a variant component style) based on another component or component variant, for example:
const theme = {
...rest,
components: {
Component: {
style: {
color: 'text',
},
variants: {
one: {
style: {
color: 'primary',
}
},
two: {
style: {
componentName: 'Component',
variant: 'one',
}
},
},
},
}
};
In this case the style of the variant two
of the component Component
should be exactly the same as the variant one
.
This is not happening right now, this exact style will generate { color: 'text' }
instead of
{ color: 'primary' }`.
To Reproduce
Apply a theme with a component configuration as the example before
morfeo.setTheme
with this thememorfeo.resolve({ componentName: 'Component', variant: 'two' })
Expected behavior
Should return the same style as morfeo.resolve({ componentName: 'Component', variant: 'one' })
Describe the bug
Fonts-related slice have a wrong font-family, this problem is caused by the fact that the passed property to the detail is not fontFamily
but font
.
To Reproduce
Steps to reproduce the behavior:
Fonts
, Font Sizes
, Letter spacings
and so on...Expected behavior
The font family is the one read from the current website/application that the web-extension is documenting.
Morfeo is based in 2 singletons, theme
and parsers
, the first is used to handle and provide the theme and the second one to parse it and generate styles. Even if it's not hard to understand this concept, most of the times the only methods we need to use of these 2 singleton are:
My idea is to create another singleton morfeo
that exposes only 5 methods:
add
to add a new theme with a given name (for example "light" or "dark")use
to use one of the previously added themesset
same as theme.setget
same as theme.getresolve
same as parsers.resolvemorfeo
will have an easy way to handle multi-theming and, most importantly, will expose only the API that 99% of the time we need; theme
and parsers
singletons will still be available for advanced usage for example add new parsers or easily get single slices or values from the theme.import { morfeo } from "@morfeo/core";
import { lightTheme, darkTheme } from "./themes";
morfeo.add("light", lightTheme);
morfeo.add("dark", darkTheme);
morfeo.use("light");
const style = morfeo.resolve({
py: "m",
gradient: "primary"
});
// will be the current theme, `lightTheme` in this case
const currentTheme = morfeo.get();
// optionally you can pass the name of the theme you want to get
const otherTheme = morfeo.get('dark');
Another alternative could be merge parsers
and theme
singletons completely, but I think the interface of the resulted singleton will expose too many API and it will be hard to use properly.
We currently have a script that tests the performance of Morfeo
packages and compares the core-api with other popular libraries, currently we have tests for:
The results of these tests are currently available in the subfolder results
inside apps/benchmarks
as markdown files.
My idea is to update the scripts and instead of writing the results in the current folder, we can write them inside the documentation website, in this way we make performance tests available through the website morfeo.dev.
This new scripts could be run every time there is a new version of Morfeo
so benchmarks will always be aligned to new functionalities and updates.
Is your feature request related to a problem? Please describe.
Create table components for the @morfeo/preset-default package
Describe the solution you'd like
Add the morfeo theme definition for the table component
Some Morfeo's packages assumes that you already have have other packages installed, for example @morfeo/styled-components-web
assume that you already have @morfeo/react
in your dependencies; This behaviour it's simply implement by putting (in the previous example) @morfeo/react
as peerDependency
of @morfeo/styled-components-web
.
Unfortunately, lerna does not handle peerDependencies
pretty good, in fact for every package that has another Morfeo package as peerDependency we have to:
peer
but also inside the devDependencies
peerDependencies
according to the new version.This issue is caused by the process of sym-linking
of lerna that doesn't care about peerDependencies.
My idea it's to create a simple script to run post-versioning
where we syncronized the new version of the morfeo's packages in all the peerDependecies
.
To do this we can simply read what the new version is from the lerna.json
file and wherever we find Morfeo's peerDependency inside any package.json, we put this new version: ^${versionReadFromLernaJson}
.
All the custom scripts we currently have are written in .mjs
files, it could be good to convert them in Typescript
and use ts-node
to run them, I think it could be good to integrate this activity in this task.
This is a proposal to improve the default slice interfaces in order to have a more scalable system and a more intuitive theme building.
The xxs
and xxl
could become 2xs
and 2xl
in order to suggest a more scalable naming for all sizes props.
As the font slice keys could be used to define different fonts and even the same fonts with different weights and styles it could be better to leave this slice more flexible by changing regular, medium, bold
to just one default property default
.
primary
and secondary
keys seem to not work properly to define borders
. We could change them with some more appropriate like thin
and `bold.
light, soft and strong
keys seem to not work properly to define zIndices
. We could change them with some more appropriate like `lowest, lower, low, high, higher, highest.
Creation of the CLI for morfeo, this CLI will have a set of functionalities to easily use the morfeo eco-system.
In the first version I'm planning to implement 2 main functionalities:
design files
in the main theme.My idea is to use tools like style dictonary to build static style files for any platform (web
, android
, ios
, flutter
), in this way morfeo can be used inside other platforms other than JS-Oriented environments. Another reason is, since we can have static stylesheets based on the theme we can drastically increase performance but still ensure UI consinstency and a single source of truth for the styles
Right now, morfeo doesn't allow inheriting the variant style to create a different state of a component based on it. It forces us to make multiple variants with almost the same style and some little differences.
It would be great to have a states
object in the component definition to override the variant style only for specific properties:
{
...theme,
components: {
Button: {
...componentConfig,
states: {
success: {
bg: 'success'
}
}
variants: {
...variants,
outlined: {
...variant,
states: {
success: {
borderWidth: 's',
borderColor: 'success'
}
}
}
}
}
}
}
So, we can define a component in this way:
import { useStyle } from '@morfeo/react';
function Button({ children }) {
const style = useStyle({ componentName: 'Button', variant: 'outlined', state: 'success' });
return <button style={style}>{children}</button>;
}
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These updates are currently rate-limited. Click on a checkbox below to force their creation now.
@testing-library/dom
, @testing-library/jest-dom
, @testing-library/react
)nextra
, nextra-theme-docs
)react-native
, @types/react-native
)@typescript-eslint/eslint-plugin
, @typescript-eslint/parser
)@babel/core
, @babel/plugin-syntax-jsx
, @babel/preset-env
, @babel/preset-typescript
, @babel/traverse
, @babel/types
)webextension-polyfill
, @types/webextension-polyfill
)@testing-library/dom
, @testing-library/react
)@typescript-eslint/eslint-plugin
, @typescript-eslint/parser
)These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
@types/react
, @types/react-dom
, eslint-plugin-react-hooks
, react
, react-dom
)These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.
.github/actions/setup-environment/action.yml
pnpm/action-setup v2.4.0
actions/setup-node v4
.github/workflows/build-web-extension.yml
actions/checkout v4
.github/workflows/codecov.yml
actions/checkout v4
codecov/codecov-action v3.1.4
.github/workflows/deploy-web-extension.yml
actions/checkout v4
.github/workflows/publish.yml
actions/checkout v4
changesets/action v1
docs/package.json
@codesandbox/sandpack-react 2.9.0
@codesandbox/sandpack-themes 2.0.21
@lottiefiles/react-lottie-player 3.5.3
@vercel/og 0.5.20
framer-motion 10.16.4
next 14.0.0
nextra 2.13.2
nextra-theme-docs 2.13.2
react-intersection-observer 9.5.2
sharp 0.32.6
eslint-config-next 13.5.6
react 18.2.0
react-dom 18.2.0
package.json
@changesets/cli 2.26.2
csstype 3.1.2
react 18.2.0
react-dom 18.2.0
react-native 0.72.6
@testing-library/dom 9.3.3
@testing-library/jest-dom 6.1.4
@testing-library/react 14.0.0
@types/glob 8.1.0
@types/jest 29.5.6
@types/node 18.18.7
@types/react 18.2.31
@types/react-dom 18.2.14
@typescript-eslint/eslint-plugin 6.9.0
@typescript-eslint/parser 6.9.0
concurrently 8.2.2
eslint 8.52.0
eslint-plugin-import 2.29.0
eslint-plugin-jsx-a11y 6.7.1
eslint-plugin-react 7.33.2
eslint-plugin-react-hooks 4.6.0
jest 29.7.0
jest-environment-jsdom 29.7.0
prettier 3.0.3
ts-jest 29.1.1
ts-node 10.9.1
tslib 2.6.2
tsup 7.2.0
turbo 1.10.16
typescript 5.2.2
pnpm 8.9.2
packages/babel-plugin/package.json
@babel/traverse 7.23.2
@babel/types 7.23.0
@babel/preset-env 7.23.2
@babel/plugin-syntax-jsx 7.22.5
@babel/preset-typescript 7.23.2
@babel/core 7.23.2
@types/babel__core 7.20.3
@types/babel__traverse 7.20.3
@babel/core 7.23.2
packages/compiler/package.json
@babel/core 7.23.2
@inquirer/input 1.2.13
chokidar 3.5.3
commander 11.1.0
cosmiconfig 8.3.6
cosmiconfig-typescript-loader 5.0.0
glob 10.3.10
@types/babel__core 7.20.3
packages/core/package.json
packages/dev-tools/package.json
packages/hooks/package.json
react 18.2.0
react-dom 18.2.0
packages/jss/package.json
jss 10.10.0
jss-preset-default 10.10.0
packages/native/package.json
@types/react-native 0.72.5
react 18.2.0
react-native 0.72.6
packages/preset-default/package.json
packages/react/package.json
csstype 3.1.2
react 18.2.0
react-dom 18.2.0
@testing-library/jest-dom 6.1.4
@testing-library/react 14.0.0
packages/spec/package.json
packages/utils/package.json
packages/web/package.json
csstype 3.1.2
web-extension/package.json
change-case 4.1.2
clsx 2.0.0
polished 4.2.2
prismjs 1.29.0
react 18.2.0
react-dom 18.2.0
react-transition-group 4.4.5
webextension-polyfill 0.10.0
@crxjs/vite-plugin 2.0.0-beta.19
@types/chrome 0.0.248
@types/prismjs 1.26.2
@types/react-transition-group 4.4.8
@types/webextension-polyfill 0.10.5
@vitejs/plugin-react 4.1.0
chrome-webstore-upload 1.0.0
vite 4.5.0
zip-folder 1.0.0
Improve consistency and proportions to theme values for the preset-default package
Morfeo is born to work everywhere, it already works with React
, Svelte
, Angular
or any other JS framework. Anyway for any of these framework we usually write packages to make the integration as good as possible, for example with directives
for svelte or hook
for react.
React v18 introduced a new hook called useSyncExternalStore
, this hook helps to sync external states with the react state.
It seems to be the perfect solution to always be sure that the theme used (and returned) by the hooks or @morfeo/hooks
is the current used inside the morfeo
instance.
It will probably unlock even other functionalities like:
cuncurrent mode
compatibility (not sure it's not working right now)References:
Before proceeding with this issue, we need to upgrade to React 18.
The upgrade to React 18 is covered by this issue
Describe the bug
If there are no fonts in the fonts
slice, the other font slices crash.
To Reproduce
Steps to reproduce the behaviour:
Expected behaviour
The devtool should not crash and the slices should show a default font
Additional context
devtool version 0.1.0
Import and use in custom pages like the HomePage
the static style generated by @morfeo/cli
.
I think that the useTheme
method of morfeo
can result ambiguous in a react environment, for example:
const { useTheme } = morfeo;
// Can be confused with the hook `useTheme` of `@morfeo/hook`
useTheme('dark');
Also other problems can occur, for example:
const { useTheme } = morfeo;
if (condition) {
// this is completely legal, since `useTheme` is not a hook (in this case) so we are not calling
// an hook conditionally.
// but the linter will complain since it will not understand that useTheme is not a hook.
useTheme('dark');
}
Instead of useTheme
we can rename this method setCurrent
, for me it makes sense even because we have a similar method called getCurrent
that retrieves the name of the current theme:
const { setCurrent } = morfeo;
// No ambiguity with `useTheme`
setCurrent('dark');
Also. since all the other methods related to the theme contains the suffix theme
, we can this about rename not only useTheme
but also getCurrent
in this way:
morfeo.useTheme
will become morfeo.setCurrentTheme
morfeo.getCurrent
will become morfeo.getCurrentTheme
Initialization of the CLI with oclif
We think that having a strong theming system is the only way for applications to have consistent and beautiful UIs - And Morfeo is, in our opinion, one of the best choices if we talk about theming systems.
But these kinds of tools sometimes have a price to pay: performance.
Morfeo runs at run time, which means that every time you're using morfeo to create a style for your components, your device is executing some code in order to transform something like this: { componentName: 'Button' }
into some complex css
and then append this CSS into the DOM. Most of the time you'll not even notice, because we try to be as fast as we can doing it, but even with all the optimization we can provide, Morfeo will never be as fast as just simple and plain static CSS.
Not only this, there is nothing that Morfeo can do and regular static CSS cannot - so why you should use Morfeo in the first place?
The answer is pretty simple: Constraints!
Morfeo exposes a strongly typed and developer-friendly interface that ensures that every generated style is following the design language; In other words, Morfeo was built to make you do the right thing in the simplest possible way and the wrong thing in the hardest possible way.
CSS is, unfortunately, not like this. In CSS there is no difference (in terms of complexity) between doing the right thing and the wrong thing (like declaring variables and using those variables instead of random sizes/colors in every style).
Actually, I'd say that doing the right thing could be most of the time even a little bit harder, but let's say this is just speculation.
As of now, we had to make a choice between the control the tools like Morfeo can give and the performance that simple CSS has.
So the question is Slower and Consistent or Fast and Chaotic? After a lot of thought, I have to be transparent and say that Fast and Chaotic was my answer (basically, I'm going against the tool I've made) because I can work on the "chaos" and make even plain CSS organized and scalable. It's hard but not impossible.
But let's be honest... the goal is to be Fast And Consistent - the performance of plain CSS and the interface of Morfeo would be awesome in my opinion - is there a way to do it? YES, we think we found it and I can't wait to show you!
Let's look at this snippet here:
const style = morfeo.resolve({
bg: 'primary',
px: 'm'
});
I can easily predict how this will be resolved:
const style = {
backgroundColor: '<the value of the primary color>',
paddingLeft: '<the value of the size m>',
paddingRight: '<the value of the size m>',
}
And so even the equivalent CSS
.className {
background-color: var(--colors-primary);
padding-left: var(--spacings-m);
padding-right: var(--spacings-m);
}
Do you get the point? There is no need for a runtime, we can always do the job at build time! We just need a transpiler!
The idea is to expose a method called parse
from the instance of morfeo that will never executed at runtime:
// morfeo.parse exposes the same interface of the function `getStyles` from `@morfeo/web`
const getClasses = morfeo.parse({
button: {
componentName: 'Button',
variant: 'primary'
},
})
const Button = () => {
const classes = getClasses();
return <button className={classes.button} />
}
If you try to execute morfeo.parse at runtime, an Expection will be thrown:
Error: morfeo.parse is not available at runtime, be sure you transpiled your code.
This method, in fact, does not to anything, is just a placeholder for a custom babel
plugin. The object inside the function will be extracted, and resolved at build time, and the resulting code in your build will become something like this:
const getClasses = () => ({
button: 'component-name-button variant-primary'
})
const Button = () => {
const classes = getClasses();
return <button className={classes.button} />
}
Let's look at the diff:
-const getClasses = morfeo.parse({
- button: {
- componentName: 'Button',
- variant: 'primary'
- },
-})
+const getClasses = () => ({
+ button: 'component-name-Button variant-primary'
+})
const Button = () => {
const classes = getClasses();
return <button className={classes.button} />
}
The plugin will also create and include in your build real CSS that will look something like this:
.component-name-Button.variant-primary {
/* the generated css */
}
As you can see, by doing like this we can guarantee both the advantages: the consistency that a tool like Morfeo can give and the performance of simple CSS.
There are multiple other scenarios that we have to consider in order to provide the most versatile solution, for example the possibility to generate dynamic style based on some properties passed to morfeo.parse
at runtime, for example:
// morfeo.parse exposes the same interface of the function `getStyles` from `@morfeo/web`
const getClasses = morfeo.parse({
button: {
componentName: 'Button',
variant: props => props.variant
},
})
const Button = ({ variant }) => {
const classes = getClasses({ variant });
return <button className={classes.button} />
}
In this case, the resulting code will (probably) become:
const getClasses = (props) => ({
button: ((props) => `component-name-button variant-${props.variant}`)(props))
})
const Button = ({ variant }) => {
const classes = getClasses({ variant });
return <button className={classes.button} />
}
And the generated CSS has to provide all the possible styles instead of the specific one:
.component-name-Button.variant-primary {
/* the generated css */
}
.component-name-Button.variant-secondary {
/* the generated css */
}
/* all the possible variants of the button */
.component-name-Button.variant-round {
/* the generated css */
}
But we are still working and thinking about what the best solution could be.
In mobile, If you scroll until the home page feature and then open the menu you'll see that the features overlays with the menu.
Steps to reproduce the behavior:
Features are covered by the menu
Inside the page theme specification there is an overview of all the theme slices, but we are still missing a detail page
for each slice where to find infos like:
Currently, Morfeo does not give any additional utilities regarding animations
, the property animation
is accepted by the resolve
method but will be treated as a regular CSS property. Also, there is no way to generate @keyframes
.
animations
theme's sliceAnimations, just like colors
, shadows
, spacings
, and so on... are part of the Design Language
of any application, so they should be defined inside the theme.
To do it, we will need a new theme slice called animations
, I think that a good way to do it could be the following:
type KeyFrameKey = `${number}%` | 'from' | 'to';
type KeyFrames = {
[KeyFrameKey]: Style,
};
type Animation = Record<string, {
delay?: number;
fillMode?: 'none' | 'forwards' | 'backwards' | 'both' | 'initial' | 'inherit';
duration?: number;
direction?: 'normal' | 'reverse' | 'alternate' | 'alternate-reverse' | 'initial' | 'inherit';
keyframes: KeyFrames;
timingFunction?: 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'step-start' | 'step-end' | `steps(${number}, ${'start' | 'end'})` | `steps(${number})` | `cubic-bezier(${number}, ${number}, ${number}, ${number})` | 'initial' | 'inherit';
iterationCount?: number;
}>;
Then, of course, we will need a parser to parse the property animation
based on theme configuration.
This parser, and also the definition of the slice, should be added to the package @morfeo/web
.
Once defined, they can be probably easily used in the following way:
const classes = morfeo.css({
container: {
'&[aria-busy="true"]': {
animation: 'loading'
}
}
})
animations
and keyframes
as theme's slicesSimilar to the first one but:
Instead of putting the keyframes inside the Animation
type, we can create another slice called keyframes
instead:
type KeyFrameKey = `${number}%` | 'from' | 'to';
- type KeyFrames = {
+ type KeyFrameConfig = {
[KeyFrameKey]: Style,
};
+ type KeyFrames = Record<string, KeyFrameConfig>;
+ type KeyFrame = keyof KeyFrames;
type Animation = Record<string, {
delay?: number;
fillMode?: 'none' | 'forwards' | 'backwards' | 'both' | 'initial' | 'inherit';
duration?: number;
direction?: 'normal' | 'reverse' | 'alternate' | 'alternate-reverse' | 'initial' | 'inherit';
- keyframes: KeyFrames;
+ keyframes: KeyFrame;
timingFunction?: 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'step-start' | 'step-end' | `steps(${number}, ${'start' | 'end'})` | `steps(${number})` | `cubic-bezier(${number}, ${number}, ${number}, ${number})` | 'initial' | 'inherit';
iterationCount?: number;
}>;
This way we can also reuse the same keyframe in multiple animations.
We can even think to completely change the approach and create a new API like morfeo.keyframes
:
morfeo.keyframes({
loading: {
'0%': {
bg: 'gray.dark'
},
'100%': {
bg: 'gray.light'
}
}
}
});
const classes = morfeo.css({
loader: {
animation: 'loading'
}
})
Is your feature request related to a problem? Please describe.
Create a set of ready to use primitive components as a new package (@morfeo/primitives). At now the morfeo eco-system doesn't provide a way to quick start with the UI development. This feature should reduce the amount of boilerplate needed to start to develop with Morfeo.
Describe the solution you'd like
I'm not sure about what approach could be the best for this feature yet. A solution that can work fine on all frameworks could be to develop the set of primitives as web components by using a library like stenciljs (https://stenciljs.com/).
Describe alternatives you've considered
Another approach could be to develop a common set of component styles by using the theme specs of morfeo and then develop separated solutions for each of the main frameworks and libraries:
Publish automation with github actions where branches in the format release/*
are merged
Describe the bug
Morfeo except values in 2 ways, by specifying an alias that reference the theme of by passing an object that scales to breakpoints.
The bug is related to those properties that comes from the type augmentation inside @morfeo/web
, for those properties even if morfeo handle responsive values, the IDE is not suggesting the properties.
To Reproduce
Steps to reproduce the behavior:
flexDirection
this value: { sm: 'row', md: 'column' }
Expected behavior
The IDE suggest the breakpoints and for each the possible values
Currently, the deployment of a new version of the browser extension is made completely manually... ๐
Using the Chrome Web Store API it's actually possible to automate this process!
Most of morfeo's package are builded in both esm
and commonjs
module types.
Currently there are 2 separate build scripts in each of these packages:
esm
commonjs
During the bootstrap of lerna, we run the commands: lerna run build
and lerna run build:commonjs
to be sure we are aways creating the builld for each types.
Even tho is not a huge problem, what happen sometime is that you build a single package (for example by running the command lerna run build:commonjs --scope=@morfeo/{packageName}
) is that the build forcommonjs
is ready but the esm
one still refers to the old version.
I think it's just better to unify this process in a single build
script for each package instead of having 2, this build script will prepare the build for both types (in case is needed).
The package can have instead of just build
and build:commonjs
, another script: build:esm
, so we can edit the build script in this way:
{
"build": "yarn build:esm && yarn build:commonjs",
"build:esm": "rimraf build && tsc",
"build:commonjs": "rimraf commonjs && tsc --module CommonJS --outdir commonjs",
}
Extract from the web-sandbox
the generic component MorfeoComponent
and move it inside the package @morfeo/react
.
The component can be used easily render components defined inside the theme.
// Your theme
const theme = {
....,
components: {
Button: { ... }
}
};
return <MorfeoComponent componentNam="Button" />
return <MorfeoComponent componentNam="Button" variant="primary" />
return <MorfeoComponent componentNam="Button" style={{ bg: 'primary' }} />
Creation of a new hook: useClassNames
to use in react
In a React environment, the current hooks morfeo has are exposed by @morfeo/hooks
package, in particular wi the hooks:
useStyles
and useStyle
it's possible to generate style based on the theme, for example:
const styles = useStyles({
container: {
bg: 'background',
px: {
xs: 'm',
lg: 'l',
}
},
button: {
'&:hover': {
opacity: 'soft'
},
}
});
return (
<div style={styles.container}>
<button style={styles.button}>Example</button>
</div>
)
There is a problem with useStyle(s)
:
inline style can not handle pseudo classes or media queries;
so in the previous example, the stye related to &:hover
and px
will not work as expected.
To handle pseudo elements and media queries we need to generate css and give to components classNames
instead of inline styles
, for example:
const classNames = useClassNames({
container: {
bg: 'background',
px: {
xs: 'm',
lg: 'l',
}
},
button: {
'&:hover': {
opacity: 'soft'
},
}
});
return (
<div className={classNames.container}>
<button className={classNames.button}>Example</button>
</div>
)
The expected behavior of useClassNames
is more less the same as useStyles
from react-jss
:
In React we have hooks to access or get the theme object (eg .useTheme
, or useProps
) and to resolve the style (eg.useStyles
), but we don't have anything related to the current theme name or a way to change it, in other words the equivalent of the core-api: morfeo.getCurrentTheme
and morfeo.setCurrentTheme
.
Of course we can still use the core-api to retrieve this value, but we always have to care by ourself about the subscription the theme changes and keep track of this value.
My proposal is to add an hook called useCurrentTheme
.
The signature of this function would be:
export function useCurrentTheme(): [ThemeName, (name: ThemeName) => void]
And it works in this way:
function Component() {
const [currentTheme, setCurrentTheme] = useCurrentTheme();
return (
<div>
Current theme: {currentTheme}
<button onClick={() => setCurrentTheme('dark')}>Toggle</button>
</div>
);
}
React 18 is now availabe
React 18 is important for us since it introduces some functionalities that can be used to improve Morfeo in a react environment like useSyncExternalStore
.
We need to upgrade as soon as possible.
Describe the bug
If the specified tag is not related to a theme component the app crashes.
To Reproduce
Steps to reproduce the behavior:
@morfeo/styled-component-web
Expected behavior
The component is created with the specified tag
Add other colours to @morfeo/preset-default
, in particular shades for:
accent
error
success
warning
Originally posted by mauroerta July 31, 2021
Currently borders
slice is used to create aliases of borders we want to use in our application, for example:
{
"colors": {
"primary": "#F9F8F8",
"secondary": "#CDD3CE",
},
"borderWidths": {
"s": "3px",
"m": "5px",
},
"borders": {
"none": "none",
"primary": "5px solid white",
"secondary": "3px solid black",
}
}
The problem is that there is no way to reference the slice colors
to use colors from the theme or the slice borderWidths
to use mapped border widths. In the same way we cannot reference mapped border styles
, but in this case the only possible values that we can set are the ones supported by border-style property.
I wanted to improve borders
since I think currently it's a little bit useless. I'm opening this discussion to have some feedback about 2 proposals:
Make the border value an object with width, color, and style:
{
"colors": {
"primary": "#F9F8F8",
"secondary": "#CDD3CE",
},
"borderWidths": {
"s": "3px",
"m": "5px",
},
"borders": {
"none": {},
"primary": { "width": "s", "color": "primary", "style": "solid" },
"secondary": { "width": "s", "color": "secondary", "style": "dotter" },
}
}
In this way the generated border will always reference acceptable values.
The second proposal is to remove borderStyles
slice since we can only accept values described here so I don't think we need a dedicated theme slice
design files
in the main themeI think it could be useful in terms of developer experience
to write the style of the components close to the component it self, for example:
-- src
-- -- components
-- -- -- MyComponent
-- -- -- -- MyComponent.tsx
-- -- -- -- MyComponent.morfeo.ts
-- -- -- -- index.ts
The content of MyComponent.morfeo.ts
can be something like:
export default {
tag: 'button',
style: {
bg: "primary",
borderRadius: "m",
px: "l",
// ...
},
variants: {
// ...
},
}
Then, by running something like:
morfeo build-theme
The CLI will find all the {componentName}.morfeo.ts
files and merge in the main theme:
// theme.ts
export default {
colors: {....},
spacings: {....},
// ...
components: {
[componentName]: {
// ... content from {componentName}.morfeo.ts
}
},
}
When used in frameworks like NextJS, style generated at build-time
or request-time
in the server will produce css classes that they will be different from the one generated at run-time
in the client; This inconsistency will cause unexpected behaviours like un-styled elements all around the application.
Let's make an example:
function Button() {
const className = useClassName({ componentName: 'Button', variant: 'primary' });
return <Button className={className} />;
}
In the current implementation of Morfeo, we don't know what className
will be, but let's say that the first time the page is generated at request-time
will be button-0-0-1
, This will also produce a some real Css that will be appended in the head of document, like:
.button-0-0-1 {
background-color: #fff;
color: #000;
border-radius: 8px;
}
Once the page will be served to the client and rehydrated from Next, since the JSS context is different, a new className
will be generated, let's say it will be button-0-1-2
.
Since "button-0-0-1" !== "button-0-1-2"
the css generated at request time will not be applied to the component.
The issue can be solved in different ways, for example frameworks/libraries like material-ui
or styled-component
clean css generated at request-time
and force the app to re-generate CSS in client side.
I think tho that the real problem is just how we are generating class names, in fact, if the class name was the same in the server and in the client, the generated css would be applied to the component.
Technically, there is a way to always produce predictable class names, we can construct the class name from the css properties and values of our style, for example:
const style = {
componentName: 'Button',
variant: 'primary'
}
we can generate for this style a string like component-name-Button-variant-primary
, that is just a concatenation of all the {propertyName}-{propertyValue}
of the style itself.
add a new alias for the borderRadius
property called corner
:
const style = parsers.resolve({corner: 'm'}); // --> { borderRadius: '10px' }
Other then corner
it could be useful to define other radius-related props for like:
those properties should be added in the radiiMap
array inside the file packages/spec/src/properties/radii.ts
:
export const radiiMap = [
'borderRadius',
'borderEndEndRadius',
'borderTopLeftRadius',
'borderEndStartRadius',
'borderTopRightRadius',
'borderStartEndRadius',
'borderStartStartRadius',
'borderBottomLeftRadius',
'borderBottomRightRadius',
// New aliases
'corner',
'cornerEndEnd',
'cornerTopLeft',
'cornerEndStart',
'cornerTopRight',
'cornerStartEnd',
'cornerStartStart',
'cornerBottomLeft',
'cornerBottomRight',
] as const;
Then inside the parsers in @morfeo/core
should be added a new parser to handle these new properties.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.