Skip to content

Theming #1188

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

Draft
wants to merge 32 commits into
base: master
Choose a base branch
from
Draft

Theming #1188

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Changelog
- 6.7.0
- Added `price` widget based on `react-number-format` (PR #1206) (issue #1025)
- Theming improved (PR #1188) (issues #892 #970)
- Dropped `compact_styles.scss`, use class `.qb-compact` for RAQB container instead
- 6.6.15
- Fixed support of AntDesign 4.x DatePicker (PR #1239) (issue #1238)
- Prevent potential prototype pollution in `OtherUtils.mergeIn` and `OtherUtils.setIn` (PR #1240)
Expand Down
54 changes: 37 additions & 17 deletions CONFIG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -411,12 +411,33 @@ canRegroup: false,
----


Theme settings:

[cols="1m,1,3a",options="header",]
|===
|key |default |meaning
|themeMode |`light` |`light` or `dark`
|compactMode |false |
|theme.material |{} |Options for https://v4.mui.com/customization/theming/[createTheme]
|theme.mui |{} |Options for https://mui.com/material-ui/customization/theming/[createTheme]
|renderSize |`small` |Size of components - `small`, `middle` or `large`
|dropdownPlacement |`bottomLeft` |Placement of antdesign's https://ant.design/components/dropdown/[dropdown] pop-up menu
|groupActionsPosition |`topRight` |You can change the position of the group actions to the following: +
`topLeft, topCenter, topRight, bottomLeft, bottomCenter, bottomRight`
|defaultSliderWidth |`200px` |Width for `slider`
|defaultSelectWidth |`200px` |Width for `select`
|defaultSearchWidth |`100px` |Width for search in autocomplete inputs
|defaultMaxRows |5 | Max rows for `textarea` widget
|maxLabelsLength |100 |To shorten long labels of fields/values (by length, i.e. number of chars)
|showLabels |false |Show labels above all fields?
|===


Render settings:

[cols="1m,1,3a",options="header",]
|===
|key |default |meaning
|renderSize |`small` |Size of AntDesign components - `small` or `large`
|renderField |`(props) => <FieldSelect {...props} />` |Render fields list +
Available widgets for AntDesign: `FieldSelect`, `FieldDropdown`, `FieldCascader`, `FieldTreeSelect`
|renderOperator |`(props) => <FieldSelect {...props} />` |Render operators list +
Expand All @@ -425,37 +446,23 @@ Render settings:
Available widgets for AntDesign: `FieldSelect`, `FieldDropdown`
|renderConjs, renderButton, renderIcon, renderButtonGroup, renderSwitch, renderProvider, renderValueSources, renderConfirm, useConfirm, renderRuleError | |Other internal render functions you can override if using another UI framework ({renderConjs}[example])
|renderItem | |Able to {renderItem}[customize] render behavior for rule/group items.
|showLabels |false |Show labels above all fields?
|maxLabelsLength |100 |To shorten long labels of fields/values (by length, i.e. number of chars)
|dropdownPlacement |`bottomLeft` |Placement of antdesign's https://ant.design/components/dropdown/[dropdown] pop-up menu
|customFieldSelectProps |`{}` |You can pass props to the field select widget. Example: `{showSearch: true}`
|customOperatorSelectProps |`{}` |You can pass props to the operator select widget. Example: `{showSearch: true}`
|groupActionsPosition |`topRight` |You can change the position of the group actions to the following: +
`topLeft, topCenter, topRight, bottomLeft, bottomCenter, bottomRight`
|renderBeforeWidget | |
|renderAfterWidget | |
|renderBeforeActions | |
|renderAfterActions | |
|renderSwitchPrefix |`IF` | For ternary mode - render on top of all confitions
|renderBeforeCaseValue |`<span>then</span>` | For ternary mode - render before case value (except default case), after case condition tree
|renderAfterCaseValue | | For ternary mode - render after case value (except default case)
|defaultSliderWidth |`200px` |Width for `slider`
|defaultSelectWidth |`200px` |Width for `select`
|defaultSearchWidth |`100px` |Width for search in autocomplete inputs
|defaultMaxRows |5 | Max rows for `textarea` widget
|===


Other settings:

[cols="1m,1,3a",options="header",]
|===
|key |default |meaning
|locale.moment |`en` |Locale (string or array of strings) used for https://momentjs.com/docs/#/i18n/[moment]
|locale.antd |`en_US` |Locale object used for https://ant.design/docs/react/i18n[AntDesign] widgets
|locale.material |`enUS` |Locale object used for https://v4.mui.com/getting-started/installation/[MaterialUI v4] widgets
|locale.mui |`enUS` |Locale object used for https://mui.com/material-ui/guides/localization/[MUI] widgets
|theme.material |{} |Options for https://v4.mui.com/customization/theming/[createTheme]
|theme.mui |{} |Options for https://mui.com/material-ui/customization/theming/[createTheme]
|formatReverse | |Function for formatting query string, used to format rule with reverse operator which haven't `formatOp`. +
`(string q, string operator, string reversedOp, Object operatorDefinition, Object revOperatorDefinition, bool isForDisplay) => string` +
`q` - already formatted rule for opposite operator (which have `formatOp`) +
Expand All @@ -480,7 +487,20 @@ Other settings:
|sqlDialect | |Affects import/export to SQL. Possible values: `BigQuery`, `PostgreSQL`, `MySQL`.
|===

Localization:

Localization settings:

[cols="1m,1,3a",options="header",]
|===
|key |default |meaning
|locale.moment |`en` |Locale (string or array of strings) used for https://momentjs.com/docs/#/i18n/[moment]
|locale.antd |`en_US` |Locale object used for https://ant.design/docs/react/i18n[AntDesign] widgets
|locale.material |`enUS` |Locale object used for https://v4.mui.com/getting-started/installation/[MaterialUI v4] widgets
|locale.mui |`enUS` |Locale object used for https://mui.com/material-ui/guides/localization/[MUI] widgets
|===


Localization strings:

[cols="1m,1a",options="header",]
|===
Expand Down
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ import React, {Component} from 'react';
// >>>
import { Utils as QbUtils, Query, Builder, BasicConfig } from '@react-awesome-query-builder/ui';
import '@react-awesome-query-builder/ui/css/styles.css';
// or import '@react-awesome-query-builder/ui/css/compact_styles.css';
const InitialConfig = BasicConfig;
// <<<

Expand Down Expand Up @@ -264,7 +263,6 @@ import React, { useState, useCallback } from "react";
import type { JsonGroup, Config, ImmutableTree, BuilderProps } from '@react-awesome-query-builder/ui';
import { Utils as QbUtils, Query, Builder, BasicConfig } from '@react-awesome-query-builder/ui';
import '@react-awesome-query-builder/ui/css/styles.css';
// or import '@react-awesome-query-builder/ui/css/compact_styles.css';
const InitialConfig = BasicConfig;
// <<<

Expand Down
3 changes: 2 additions & 1 deletion packages/antd/modules/widgets/core/Conjs.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ export default class ConjsButtons extends PureComponent {
&& <Button
key={"group-not"}
onClick={this.setNot}
type={not ? "primary" : null}
type={not ? "primary" : "text"}
disabled={readonly}
danger
>{notLabel}</Button>
}
{showConj && map(conjunctionOptions, (item, _index) => (readonly || disabled) && !item.checked ? null : (
Expand Down
30 changes: 14 additions & 16 deletions packages/antd/modules/widgets/core/FieldSelect.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,23 +63,21 @@ const FieldSelect = (props) => {
if (items) {
const simpleItems = items.filter(it => !it.items);
const complexItems = items.filter(it => !!it.items);
let gr;
if (simpleItems.length) {
let groupLabel = groupPrefix+label;
if (tooltip) {
groupLabel = <Tooltip title={tooltip}>{groupLabel}</Tooltip>;
}
gr = (
<OptGroup
key={pathKey}
label={groupLabel}
>
{renderSelectItems(simpleItems, level+1)}
</OptGroup>
);
const complexList = complexItems.length ? renderSelectItems(complexItems, level+1) : [];
const simpleList = simpleItems.length ? renderSelectItems(simpleItems, level+1) : [];
let groupLabel = groupPrefix+label;
if (tooltip) {
groupLabel = <Tooltip title={tooltip}>{groupLabel}</Tooltip>;
}
const list = complexItems.length ? renderSelectItems(complexItems, level+1) : [];
return [...(gr ? [gr] : []), ...list];
const grp = (
<OptGroup
key={pathKey}
label={groupLabel}
>
{simpleList}
</OptGroup>
);
return [grp, ...complexList];
} else {
const optionText = matchesType ? <b>{prefix+label}</b> : prefix+label;
const option = tooltip ? <Tooltip title={tooltip}>{optionText}</Tooltip> : optionText;
Expand Down
3 changes: 3 additions & 0 deletions packages/antd/modules/widgets/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
FieldProps, ConjsProps, SwitchProps, ButtonProps, ButtonGroupProps, ProviderProps, ValueSourcesProps, ConfirmFunc,
BooleanWidgetProps, TextWidgetProps, DateTimeWidgetProps, SelectWidgetProps, NumberWidgetProps, PriceWidgetProps, RangeSliderWidgetProps, TreeSelectWidgetProps
} from "@react-awesome-query-builder/ui";
import type { GlobalToken } from "antd";

export interface AntdWidgets {
// antd core widgets
Expand Down Expand Up @@ -33,6 +34,8 @@ export interface AntdWidgets {
TimeWidget: ElementType<DateTimeWidgetProps>,
DateTimeWidget: ElementType<DateTimeWidgetProps>,
BooleanWidget: ElementType<BooleanWidgetProps>,

themeToCssVars: (palette: GlobalToken, darkMode: boolean) => Record<string, string>,
}

export declare const AntdWidgets: AntdWidgets;
Expand Down
78 changes: 76 additions & 2 deletions packages/antd/modules/widgets/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,81 @@ import Switch from "./core/Switch";
import ValueSources from "./core/ValueSources";
import confirm from "./core/confirm";

import { ConfigProvider } from "antd";
const Provider = ({ config, children }) => <ConfigProvider locale={config.settings.locale.antd}>{children}</ConfigProvider>;
import { ConfigProvider, theme } from "antd";

const Provider = ({ config, children }) => {
const darkMode = config.settings.themeMode === "dark";
const compactMode = config.settings.compactMode;
const ref = React.createRef();
const algorithms = [
darkMode && theme.darkAlgorithm,
compactMode && theme.compactAlgorithm,
!compactMode && !darkMode && theme.defaultAlgorithm,
].filter(a => !!a);
const palette = algorithms.reduce((tkns, algo, i) => i === 0 ? algo(tkns) : algo({}, tkns), theme.defaultSeed);
React.useEffect(() => {
const cssVarsTarget = ref.current;
const cssVars = themeToCssVars(palette, darkMode);
for (const k in cssVars) {
if (cssVars[k] != undefined) {
cssVarsTarget.style.setProperty(k, cssVars[k]);
}
}
return () => {
for (const k in cssVars) {
cssVarsTarget.style.removeProperty(k);
}
};
}, [darkMode, compactMode]);

const base = (<div ref={ref} className={`qb-antd ${compactMode ? "qb-compact" : ""}`}>{children}</div>);
const withProviders = (
<ConfigProvider
locale={config.settings.locale.antd}
theme={{
// https://ant.design/docs/react/customize-theme
// todo: allow overrides
algorithm: algorithms
}}
>{base}</ConfigProvider>
);

return withProviders;
};

const themeToCssVars = (palette, darkMode) => {
// console.log('antd palette', palette);
return {
"--main-background": palette.colorBgBase,
"--rule-background": palette.colorBgElevated,
"--group-background": darkMode ? palette.colorBgMask : palette.colorFillQuaternary,
"--rulegroup-background": darkMode ? palette.colorBgSpotlight : palette.colorSecondaryBg,
"--rulegroupext-background": darkMode ? palette.colorBgSpotlight : palette.colorSecondaryBg,
"--switch-background": darkMode ? palette.colorBgMask : palette.colorFillQuaternary,
"--case-background": darkMode ? palette.colorBgMask : palette.colorFillQuaternary,

"--rule-border-color": palette.colorBorderSecondary,
"--group-border-color": palette.colorBorder,
"--rulegroup-border-color": palette.colorBorder,
"--rulegroupext-border-color": palette.colorBorder,
"--switch-border-color": palette.colorBorderSecondary,
"--case-border-color": palette.colorBorder,

"--treeline-color": darkMode ? palette.colorPrimaryHover : palette.colorPrimaryHover,
"--treeline-switch-color": darkMode ? palette.colorInfo : palette.colorInfo,
"--treeline-disabled-color": palette.colorFillSecondary,

"--main-text-color": palette.colorText,
"--main-font-family": palette.fontFamily,
"--main-font-size": palette.fontSize + "px",
"--item-radius": palette.borderRadius + "px",

"--rule-border-left-hover": "2px",
"--group-border-left-hover": "2px",
"--rulegroup-border-left-hover": "2px",
"--rulegroupext-border-left-hover": "2px",
};
};

export default {
DateWidget,
Expand Down Expand Up @@ -64,4 +137,5 @@ export default {
confirm,

Provider,
themeToCssVars,
};
4 changes: 3 additions & 1 deletion packages/antd/modules/widgets/value/Boolean.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ export default class BooleanWidget extends PureComponent {
};

render() {
const {customProps, value, labelYes, labelNo, readonly} = this.props;
const {customProps, value, labelYes, labelNo, readonly, config} = this.props;
const {renderSize} = config.settings;

return (
<Switch
Expand All @@ -34,6 +35,7 @@ export default class BooleanWidget extends PureComponent {
checked={value || null}
onChange={this.handleChange}
disabled={readonly}
size={renderSize}
{...customProps}
/>
);
Expand Down
4 changes: 1 addition & 3 deletions packages/antd/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@
},
"./package.json": "./package.json",
"./css/styles.css": "./css/styles.css",
"./css/compact_styles.css": "./css/compact_styles.css",
"./css/styles.scss": "./css/styles.scss",
"./css/compact_styles.scss": "./css/compact_styles.scss"
"./css/styles.scss": "./css/styles.scss"
},
"main": "./cjs/index.js",
"module": "./esm/index.js",
Expand Down
3 changes: 0 additions & 3 deletions packages/antd/styles/compact_styles.scss

This file was deleted.

1 change: 0 additions & 1 deletion packages/antd/styles/denormalize.scss

This file was deleted.

23 changes: 21 additions & 2 deletions packages/antd/styles/fixes.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
$custom-select-option-color: lightcoral !default;
@import '@react-awesome-query-builder/ui/css/vars.scss';

/* don't trigger tooltips during drag-n-drop */
body.qb-dragging {
Expand All @@ -12,6 +12,13 @@ body.qb-dragging {
}
}

.query-builder {
.group--conjunctions > .ant-btn-group {
border-radius: $conjunctions-radius;
overflow: hidden;
}
}

/* slider */
.query-builder {
/* v4 fix */
Expand All @@ -24,7 +31,7 @@ body.qb-dragging {
margin-bottom: 4px !important;
margin-top: 4px;
}
.ant-slider.ant-slider-with-marks {
.ant-slider.ant-slider-horizontal.ant-slider-with-marks {
margin-bottom: 10px !important;
margin-left: 10px;
margin-top: 4px;
Expand All @@ -35,6 +42,10 @@ body.qb-dragging {
}
}

.qb-compact {
/* todo */
}

/* tree v4 ? */
.query-builder {
.ant-select-tree-dropdown > div[role="listbox"] {
Expand All @@ -59,6 +70,7 @@ body.qb-dragging {

.query-builder {
.widget--valuesrc, .rule--fieldsrc {
vertical-align: middle;
.anticon {
height: 100%;
svg {
Expand All @@ -82,4 +94,11 @@ body.qb-dragging {
margin-right: 3px;
margin-bottom: 4px;
}
.rule--widget--BOOLEAN {
height: 100%;
display: flex;
.widget--widget {
align-self: center;
}
}
}
1 change: 0 additions & 1 deletion packages/antd/styles/reset.scss

This file was deleted.

4 changes: 2 additions & 2 deletions packages/antd/styles/vars.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
$inactive_conjs: (".group--conjunctions .ant-btn:not(.ant-btn-primary)");
$active_conjs: (".group--conjunctions .ant-btn.ant-btn-primary");
$inactive_conjs: (".ant-btn:not(.ant-btn-primary)");
$active_conjs: (".ant-btn.ant-btn-primary");
$seps-offset-bottom: 6px;
Loading