Skip to content

Commit

Permalink
feat(QueryBuilder): custom renderers
Browse files Browse the repository at this point in the history
  • Loading branch information
MEsteves22 authored and zettca committed Nov 27, 2023
1 parent 8c92d6b commit ffe4ba1
Show file tree
Hide file tree
Showing 19 changed files with 601 additions and 287 deletions.
8 changes: 7 additions & 1 deletion packages/core/src/components/QueryBuilder/Context.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createContext } from "react";
import { createContext, useContext } from "react";

import {
AskAction,
Expand All @@ -7,6 +7,7 @@ import {
HvQueryBuilderLabels,
HvQueryBuilderQueryCombinator,
HvQueryBuilderQueryOperator,
HvQueryBuilderRenderers,
} from "./types";

export const defaultOperators = {
Expand Down Expand Up @@ -322,6 +323,7 @@ export interface HvQueryBuilderContextValue {
labels: HvQueryBuilderLabels;
initialTouched: boolean;
readOnly: boolean;
renderers?: HvQueryBuilderRenderers;
}

export const HvQueryBuilderContext = createContext<HvQueryBuilderContextValue>({
Expand Down Expand Up @@ -352,3 +354,7 @@ export const HvQueryBuilderProvider = ({
</HvQueryBuilderContext.Provider>
);
};

export const useQueryBuilderContext = () => {
return useContext(HvQueryBuilderContext);
};
6 changes: 6 additions & 0 deletions packages/core/src/components/QueryBuilder/QueryBuilder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
HvQueryBuilderQueryCombinator,
HvQueryBuilderQueryOperator,
HvQueryBuilderChangedQuery,
HvQueryBuilderRenderers,
} from "./types";
import { clearNodeIds, emptyGroup } from "./utils";
import reducer from "./utils/reducer";
Expand All @@ -47,6 +48,8 @@ export interface HvQueryBuilderProps {
labels?: HvQueryBuilderLabels;
/** Whether the query builder is in read-only mode. */
readOnly?: boolean;
/** Renderers for custom attribute types. */
renderers?: HvQueryBuilderRenderers;
/** A Jss Object used to override or extend the styles applied. */
classes?: HvQueryBuilderClasses;
}
Expand All @@ -63,6 +66,7 @@ export interface HvQueryBuilderProps {
export const HvQueryBuilder = (props: HvQueryBuilderProps) => {
const {
attributes,
renderers,
query,
onChange,
operators = defaultOperators,
Expand Down Expand Up @@ -102,6 +106,7 @@ export const HvQueryBuilder = (props: HvQueryBuilderProps) => {
labels,
initialTouched: initialState,
readOnly,
renderers,
}),
[
attributes,
Expand All @@ -111,6 +116,7 @@ export const HvQueryBuilder = (props: HvQueryBuilderProps) => {
labels,
readOnly,
initialState,
renderers,
]
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useMemo, useContext, memo } from "react";
import { useMemo, memo } from "react";

import { HvDropdown } from "@core/components/Dropdown";

import { HvQueryBuilderContext } from "../../Context";
import { isBigList } from "../../utils";
import { useQueryBuilderContext } from "../../Context";

export interface AttributeProps {
id: React.Key;
Expand All @@ -18,7 +18,8 @@ export const Attribute = ({
disabled,
isInvalid,
}: AttributeProps) => {
const context = useContext(HvQueryBuilderContext);
const context = useQueryBuilderContext();

const { dispatchAction, attributes, operators, labels, readOnly } = context;

const values = useMemo(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { memo, useContext, useMemo } from "react";
import { memo, useMemo } from "react";

import { HvDropdown } from "@core/components/Dropdown";

import { HvQueryBuilderContext } from "../../Context";
import { useQueryBuilderContext } from "../../Context";
import { isBigList } from "../../utils";

export interface OperatorProps {
Expand All @@ -18,7 +18,7 @@ export const Operator = ({
attribute,
operator,
}: OperatorProps) => {
const context = useContext(HvQueryBuilderContext);
const context = useQueryBuilderContext();

const { dispatchAction, attributes, operators, labels, readOnly } = context;

Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/components/QueryBuilder/Rule/Rule.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useContext, useMemo } from "react";
import { useMemo } from "react";
import { Delete } from "@hitachivantara/uikit-react-icons";
import { useMediaQuery, useTheme } from "@mui/material";

Expand All @@ -8,7 +8,7 @@ import { withTooltip } from "@core/hocs/withTooltip";
import { useDefaultProps } from "@core/hooks";
import { ExtractNames } from "@core/utils";

import { HvQueryBuilderContext } from "../Context";
import { useQueryBuilderContext } from "../Context";
import { Attribute } from "./Attribute";
import { Operator } from "./Operator";
import { Value } from "./Value";
Expand Down Expand Up @@ -42,7 +42,7 @@ export const Rule = (props: RuleProps) => {
} = useDefaultProps("HvQueryBuilderRule", props);
const { classes, cx } = useClasses(classesProp);

const context = useContext(HvQueryBuilderContext);
const context = useQueryBuilderContext();

const theme = useTheme();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { memo, useContext } from "react";
import { memo } from "react";

import { HvDropdown } from "@core/components/Dropdown";

import { HvQueryBuilderContext } from "../../../Context";
import { useQueryBuilderContext } from "../../../Context";
import { isBigList } from "../../../utils";

export interface BooleanValueProps {
Expand All @@ -11,7 +11,7 @@ export interface BooleanValueProps {
}

export const BooleanValue = ({ id, value = true }: BooleanValueProps) => {
const context = useContext(HvQueryBuilderContext);
const context = useQueryBuilderContext();
const { labels, dispatchAction, readOnly } = context;

const values = ["true", "false"].map((v) => ({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { memo, useCallback, useContext, useMemo, useState } from "react";
import { memo, useCallback, useMemo, useState } from "react";
import uniqueId from "lodash/uniqueId";
import dayjs from "dayjs";
import { useMediaQuery, useTheme } from "@mui/material";
Expand All @@ -7,7 +7,7 @@ import { HvWarningText } from "@core/components/Forms";
import { HvTimePicker, HvTimePickerValue } from "@core/components/TimePicker";
import { HvDatePicker } from "@core/components/DatePicker";

import { HvQueryBuilderContext } from "../../../Context";
import { useQueryBuilderContext } from "../../../Context";
import { padTime, parseDate, parseTime } from "./utils";
import { useClasses } from "./DateTimeValue.styles";

Expand Down Expand Up @@ -35,7 +35,7 @@ export const DateTimeValue = ({

const isRange = valueIsRange(operator);

const context = useContext(HvQueryBuilderContext);
const context = useQueryBuilderContext();
const { labels, dispatchAction, readOnly } = context;

const elementId = uniqueId(`datetime${id}`);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { memo, useCallback, useContext, useState } from "react";
import { memo, useCallback, useState } from "react";
import uniqueId from "lodash/uniqueId";
import isEmpty from "lodash/isEmpty";
import { useMediaQuery, useTheme } from "@mui/material";

import { HvInput } from "@core/components/Input";

import { HvQueryBuilderContext } from "../../../Context";
import { useQueryBuilderContext } from "../../../Context";
import { useClasses } from "./Numeric.styles";
import { HvQueryBuilderNumericRange } from "../../../types";

Expand All @@ -25,7 +25,7 @@ export const NumericValue = ({
const { classes, cx } = useClasses();

const isRange = operator === "range";
const context = useContext(HvQueryBuilderContext);
const context = useQueryBuilderContext();
const { labels, dispatchAction, readOnly } = context;

const theme = useTheme();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { memo, useContext, useState } from "react";
import { memo, useState } from "react";

import { HvFormStatus } from "@core/components/Forms";
import { HvInput } from "@core/components/Input";

import { HvQueryBuilderContext } from "../../../Context";
import { useQueryBuilderContext } from "../../../Context";
import { useClasses } from "./TextValue.styles";

export interface TextValueProps {
Expand All @@ -19,7 +19,7 @@ export const TextValue = ({
}: TextValueProps) => {
const { classes } = useClasses();

const context = useContext(HvQueryBuilderContext);
const context = useQueryBuilderContext();
const { labels, dispatchAction, readOnly } = context;
const [touched, setTouched] = useState(initialTouched);
const isValid = value != null && value.toString().trim() !== "";
Expand Down
25 changes: 21 additions & 4 deletions packages/core/src/components/QueryBuilder/Rule/Value/Value.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { memo, useContext } from "react";
import { memo } from "react";

import { HvQueryBuilderContext } from "../../Context";
import { useQueryBuilderContext } from "../../Context";
import { BooleanValue } from "./BooleanValue";
import { NumericValue } from "./NumericValue";
import { TextValue } from "./TextValue";
Expand All @@ -19,8 +19,9 @@ export const Value = ({
operator,
value: valueProp,
}: ValueProps) => {
const context = useContext(HvQueryBuilderContext);
const { attributes, initialTouched } = context;
const context = useQueryBuilderContext();
const { attributes, initialTouched, renderers } = context;

const value =
attribute && attributes ? { ...attributes[attribute] } : { type: null };
const { type } = value;
Expand Down Expand Up @@ -51,7 +52,23 @@ export const Value = ({
}
case "text":
case "textarea":
return (
<TextValue id={id} value={valueProp} initialTouched={initialTouched} />
);
default: {
if (type && renderers?.[type]) {
const Renderer = renderers[type];

return (
<Renderer
id={id}
attribute={attribute}
operator={operator}
value={valueProp}
/>
);
}

return (
<TextValue id={id} value={valueProp} initialTouched={initialTouched} />
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useContext } from "react";
import { useCallback } from "react";
import { Add, Delete, Info } from "@hitachivantara/uikit-react-icons";

import { HvButton } from "@core/components/Button";
Expand All @@ -10,7 +10,7 @@ import { withTooltip } from "@core/hocs/withTooltip";
import { ExtractNames } from "@core/utils/classes";

import { Rule } from "../Rule";
import { HvQueryBuilderContext } from "../Context";
import { useQueryBuilderContext } from "../Context";
import { useClasses } from "../QueryBuilder.styles";
import { HvQueryBuilderQuery, HvQueryBuilderQueryCombinator } from "../types";

Expand All @@ -31,7 +31,7 @@ export const RuleGroup = ({
}: RuleGroupProps) => {
const { classes, cx } = useClasses(classesProp);

const context = useContext(HvQueryBuilderContext);
const context = useQueryBuilderContext();

const { dispatchAction, askAction, maxDepth, combinators, labels, readOnly } =
context;
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/components/QueryBuilder/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export {
defaultCombinators as hvQueryBuilderDefaultCombinators,
defaultLabels as hvQueryBuilderDefaultLabels,
defaultOperators as hvQueryBuilderDefaultOperators,
useQueryBuilderContext,
} from "./Context";
export type {
HvQueryBuilderAttribute,
Expand All @@ -15,4 +16,6 @@ export type {
HvQueryBuilderQueryCombinator,
HvQueryBuilderQueryOperator,
HvQueryBuilderLabels,
HvQueryBuilderRendererProps,
HvQueryBuilderRenderers,
} from "./types";

0 comments on commit ffe4ba1

Please sign in to comment.