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

Enhance ColorPickerWidget (#5585) #5610

Merged
merged 1 commit into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
99 changes: 68 additions & 31 deletions .storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,80 +48,117 @@ const defaultRazzleOptions = {
staticCssInDev: false,
emitOnErrors: false,
disableWebpackbar: false,
browserslist: ['>1%', 'last 4 versions', 'Firefox ESR', 'not ie 11', 'not dead']
browserslist: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie 11',
'not dead',
],
};
module.exports = {
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
addons: ['@storybook/addon-links', '@storybook/addon-essentials'],
staticDirs: ['./static'],
webpackFinal: async (config, {
configType
}) => {
webpackFinal: async (config, { configType }) => {
// `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
// You can change the configuration based on that.
// 'PRODUCTION' is used when building the static version of storybook.

// Make whatever fine-grained changes you need
let baseConfig;
baseConfig = await createConfig('web', 'dev', {
// clearConsole: false,
modifyWebpackConfig: razzleConfig.modifyWebpackConfig,
plugins: razzleConfig.plugins
}, webpack, false, undefined, [], defaultRazzleOptions);
baseConfig = await createConfig(
'web',
'dev',
{
// clearConsole: false,
modifyWebpackConfig: razzleConfig.modifyWebpackConfig,
plugins: razzleConfig.plugins,
},
webpack,
false,
undefined,
[],
defaultRazzleOptions,
);
const AddonConfigurationRegistry = require('../addon-registry');
const registry = new AddonConfigurationRegistry(projectRootPath);
config = lessPlugin({
registry
registry,
}).modifyWebpackConfig({
env: {
target: 'web',
dev: 'dev'
dev: 'dev',
},
webpackConfig: config,
webpackObject: webpack,
options: {}
options: {},
});

// Put the SVG loader on top and prevent the asset/resource rule
// from processing the app's SVGs
config.module.rules.unshift(SVGLOADER);
const fileLoaderRule = config.module.rules.find(rule => rule.test.test('.svg'));
const fileLoaderRule = config.module.rules.find((rule) =>
rule.test.test('.svg'),
);
fileLoaderRule.exclude = /icons\/.*\.svg$/;
config.plugins.unshift(new webpack.DefinePlugin({
__DEVELOPMENT__: true,
__CLIENT__: true,
__SERVER__: false
}));
config.plugins.unshift(
new webpack.DefinePlugin({
__DEVELOPMENT__: true,
__CLIENT__: true,
__SERVER__: false,
}),
);
const resultConfig = {
...config,
resolve: {
...config.resolve,
alias: {
...config.resolve.alias,
...baseConfig.resolve.alias
}
}
...baseConfig.resolve.alias,
},
},
};

// Addons have to be loaded with babel
const addonPaths = registry.addonNames.map(addon => fs.realpathSync(registry.packages[addon].modulePath));
resultConfig.module.rules[1].exclude = input =>
const addonPaths = registry.addonNames.map((addon) =>
fs.realpathSync(registry.packages[addon].modulePath),
);
resultConfig.module.rules[1].exclude = (input) =>
// exclude every input from node_modules except from @plone/volto
/node_modules\/(?!(@plone\/volto)\/)/.test(input) &&
// If input is in an addon, DON'T exclude it
!addonPaths.some(p => input.includes(p));
!addonPaths.some((p) => input.includes(p));
return resultConfig;
},
babel: async options => {
babel: async (options) => {
return {
...options,
plugins: [...options.plugins, ['./node_modules/babel-plugin-root-import/build/index.js', {
rootPathSuffix: './src'
}]]
plugins: [
...options.plugins,
[
'./node_modules/babel-plugin-root-import/build/index.js',
{
rootPathSuffix: './src',
},
],
],
// any extra options you want to set
};
},
core: {
builder: 'webpack5'
}
};
builder: 'webpack5',
},
typescript: {
check: false,
checkOptions: {},
reactDocgen: 'react-docgen-typescript-plugin',
reactDocgenTypescriptOptions: {
compilerOptions: {
allowSyntheticDefaultImports: false,
esModuleInterop: false,
},
propFilter: () => true,
},
},
};
164 changes: 164 additions & 0 deletions docs/source/recipes/color-picker-widget.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
---
myst:
html_meta:
"description": "How to use the color picker widget in blocks settings and forms"
"property=og:description": "How to use the color picker widget in blocks settings and forms"
"property=og:title": "How to use the color picker widget"
"keywords": "Volto, Plone, frontend, React, blocks, forms, widget, color, picker"
---

# Color picker widget

Volto comes with a color picker widget that can be used in any Volto form.
It allows to pick a color from a preset list of colors.
This preset list of colors is passed using the `colors` prop.
You can [try a demo of the default color picker](https://6.docs.plone.org/storybook/?path=/story/edit-widgets-colorpicker--default).
You can combine the color picker widget with the {doc}`../blocks/block-style-wrapper` to have a powerful, yet simple way to manage color properties in your blocks.
You can use it either in your custom block's styles schema or enhance an existing block as follows:

```{code-block} js
:emphasize-lines: 13-16, 31-42
import { addStyling } from '@plone/volto/helpers/Extensions/withBlockSchemaEnhancer';
import { defineMessages } from 'react-intl';
import config from '@plone/volto/registry';

const messages = defineMessages({
backgroundColor: {
id: 'Background color',
defaultMessage: 'Background color',
},
});

export const defaultStylingSchema = ({ schema, formData, intl }) => {
const BG_COLORS = [
{ name: 'transparent', label: 'Transparent' },
{ name: 'grey', label: 'Grey' },
];

// You could allow passing the color definition from the config or from the default
// defined above
const colors =
config.blocks?.blocksConfig?.[formData['@type']]?.colors || BG_COLORS;

// Same for the default used (or undefined)
const defaultBGColor =
config.blocks?.blocksConfig?.[formData['@type']]?.defaultBGColor;

// This adds the StyleWrapper support to your block
addStyling({ schema, intl });

// Then we add the field to the fieldset inside the StyleWrapper `styles` field schema fieldset array
schema.properties.styles.schema.fieldsets[0].fields = [
...schema.properties.styles.schema.fieldsets[0].fields,
'backGroundColor',
];

// and finally, we add the field to the StyleWrapper `styles` object field schema properties
schema.properties.styles.schema.properties['backGroundColor'] = {
widget: 'color_picker',
title: intl.formatMessage(messages.backgroundColor),
colors,
default: defaultBGColor,
};

return schema;
};
```

The color picker widget's discriminator is `color_picker`.

## Color definitions

```{versionchanged} 17.9.0
Enhanced `ColorPickerWidget` with additional color definitions, saving it as an object instead of a string.
```

The `colors` property of the widget controls which colors are available to choose in the widget.
This is the signature of the object along with an example:

```ts
type Color =
| {
name: string;
label: string;
style: Record<`--${string}`, string>;
}
| {
name: string;
label: string;
style: undefined;
};

const colors: Color[] = [
{
name: 'red',
label: 'red',
style: { '--background-color': 'red' } },
{
name: 'yellow',
label: 'yellow',
style: { '--background-color': 'yellow' },
},
{
name: 'green',
label: 'green'
},
]
```

### Basic color definition

The basic color definition is the one that saves a string as the widget value.
This string is the one defined by the `name` key.
You can use it on your own code by reading it from the resultant data and use it according your designed solution.

When combined with the `StyleWrapper`, the value will be injected as a class name of the form `has--PROPERTY_NAME--PROPERTY_VALUE`:

```html
<div class="has--backgroundColor--green">
...
</div>
```

Then you should create the CSS rules according to these injected class names.

### Custom CSS properties as color definitions

The `style` key defines a set of custom CSS properties to be added as the value to the HTML attribute `style`.
They will be injected by the `StyleWrapper` as style definitions, so you can use them in your CSS rules.

```html
<div class="block teaser" style="--background-color: red">
...
</div>
```

```css
.block.teaser {
background-color: var(--background-color, transparent);
}
```

The `name` key is mandatory in order to generate proper markup in the resultant HTML in both forms.

You can also use this selector, where an element with class names `block` and `teaser` with a child element whose HTML attribute `style` contains the value of `--background-color`:

```css
.block.teaser {
&[style*='--background-color'] {
padding: 20px 0;
}
```

```{seealso}
See the MDN CSS Reference for selectors.

- [Attribute selectors](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors)
- [`&` nesting selector](https://developer.mozilla.org/en-US/docs/Web/CSS/Nesting_selector)
```


## Use both basic and custom CSS properties definitions

You can combine both basic and custom CSS properties definitions.
It's up to you how to mix and match them.
2 changes: 2 additions & 0 deletions docs/source/recipes/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,7 @@ appextras
contextnavigation
pluggables
widget
how-to-restrict-blocks
color-picker-widget
ie11compat
```
1 change: 1 addition & 0 deletions news/5585.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Enhanced `ColorPickerWidget` with additional color definitions, saving it as an object instead of a string. @sneridagh
1 change: 1 addition & 0 deletions packages/scripts/news/5585.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added support for TS/TSX files in i18n machinery. @sneridagh
30 changes: 0 additions & 30 deletions src/components/manage/Widgets/ColorPickerWidget.stories.jsx

This file was deleted.

Loading
Loading