feat(json-schema-2020-12): add support for deep expandable behavior

Refs #8513
This commit is contained in:
Vladimir Gorej
2023-04-14 13:26:57 +02:00
committed by Vladimír Gorej
parent ddedb57dc0
commit 7cfc5e3656
10 changed files with 122 additions and 25 deletions

View File

@@ -18,7 +18,11 @@ const Accordion = ({ expanded, children, onChange }) => {
) )
return ( return (
<button className="json-schema-2020-12-accordion" onClick={handleExpansion}> <button
type="button"
className="json-schema-2020-12-accordion"
onClick={handleExpansion}
>
<div className="json-schema-2020-12-accordion__children">{children}</div> <div className="json-schema-2020-12-accordion__children">{children}</div>
<span <span
className={classNames("json-schema-2020-12-accordion__icon", { className={classNames("json-schema-2020-12-accordion__icon", {

View File

@@ -0,0 +1,31 @@
/**
* @prettier
*/
import React, { useCallback } from "react"
import PropTypes from "prop-types"
const ExpandDeepButton = ({ expanded, onClick }) => {
const handleExpansion = useCallback(
(event) => {
onClick(event, !expanded)
},
[expanded, onClick]
)
return (
<button
type="button"
className="json-schema-2020-12-expand-deep-button"
onClick={handleExpansion}
>
{expanded ? "Collapse all" : "Expand all"}
</button>
)
}
ExpandDeepButton.propTypes = {
expanded: PropTypes.bool.isRequired,
onClick: PropTypes.func.isRequired,
}
export default ExpandDeepButton

View File

@@ -0,0 +1,6 @@
.json-schema-2020-12-expand-deep-button {
@include text_headline($section-models-model-title-font-color);
font-size: 12px;
color: #6b6b6b;
border: none;
}

View File

@@ -1,34 +1,67 @@
/** /**
* @prettier * @prettier
*/ */
import React, { useState, useCallback } from "react" import React, { useState, useCallback, useEffect } from "react"
import PropTypes from "prop-types" import PropTypes from "prop-types"
import classNames from "classnames" import classNames from "classnames"
import * as propTypes from "../../prop-types" import * as propTypes from "../../prop-types"
import { useComponent, useFn, useLevel, useIsEmbedded } from "../../hooks" import {
import { JSONSchemaLevelContext } from "../../context" useComponent,
useFn,
useLevel,
useIsEmbedded,
useIsExpandedDeeply,
} from "../../hooks"
import {
JSONSchemaLevelContext,
JSONSchemaDeepExpansionContext,
} from "../../context"
const JSONSchema = ({ schema, name }) => { const JSONSchema = ({ schema, name }) => {
const [expanded, setExpanded] = useState(false) const isExpandedDeeply = useIsExpandedDeeply()
const [expanded, setExpanded] = useState(isExpandedDeeply)
const [expandedDeeply, setExpandedDeeply] = useState(false)
const fn = useFn() const fn = useFn()
const [level, nextLevel] = useLevel() const [level, nextLevel] = useLevel()
const isEmbedded = useIsEmbedded() const isEmbedded = useIsEmbedded()
const BooleanJSONSchema = useComponent("BooleanJSONSchema") const BooleanJSONSchema = useComponent("BooleanJSONSchema")
const Accordion = useComponent("Accordion") const Accordion = useComponent("Accordion")
const KeywordProperties = useComponent("KeywordProperties") const KeywordProperties = useComponent("KeywordProperties")
const ExpandDeepButton = useComponent("ExpandDeepButton")
/**
* Event handlers.
*/
const handleExpansion = useCallback(() => { const handleExpansion = useCallback(() => {
setExpanded((prev) => !prev) setExpanded((prev) => !prev)
}, []) }, [])
const handleExpansionDeep = useCallback(() => {
setExpanded((prev) => !prev)
setExpandedDeeply((prev) => !prev)
}, [])
/**
* Effects handlers.
*/
useEffect(() => {
setExpandedDeeply(isExpandedDeeply)
}, [isExpandedDeeply])
useEffect(() => {
setExpandedDeeply(expandedDeeply)
}, [expandedDeeply])
/**
* Rendering handlers.
*/
if (fn.isBooleanJSONSchema(schema)) { if (fn.isBooleanJSONSchema(schema)) {
return <BooleanJSONSchema schema={schema} name={name} /> return <BooleanJSONSchema schema={schema} name={name} />
} }
return ( return (
<JSONSchemaLevelContext.Provider value={nextLevel}> <JSONSchemaLevelContext.Provider value={nextLevel}>
<JSONSchemaDeepExpansionContext.Provider value={expandedDeeply}>
<article <article
data-json-schema-level={level} data-json-schema-level={level}
className={classNames("json-schema-2020-12", { className={classNames("json-schema-2020-12", {
@@ -41,6 +74,10 @@ const JSONSchema = ({ schema, name }) => {
{name || fn.getTitle(schema)} {name || fn.getTitle(schema)}
</div> </div>
</Accordion> </Accordion>
<ExpandDeepButton
expanded={expanded}
onClick={handleExpansionDeep}
/>
</div> </div>
{expanded && ( {expanded && (
<div className="json-schema-2020-12-body"> <div className="json-schema-2020-12-body">
@@ -48,6 +85,7 @@ const JSONSchema = ({ schema, name }) => {
</div> </div>
)} )}
</article> </article>
</JSONSchemaDeepExpansionContext.Provider>
</JSONSchemaLevelContext.Provider> </JSONSchemaLevelContext.Provider>
) )
} }

View File

@@ -1,3 +1,4 @@
@import './BooleanJSONSchema/boolean-json-schema'; @import './BooleanJSONSchema/boolean-json-schema';
@import './JSONSchema/json-schema'; @import './JSONSchema/json-schema';
@import './Accordion/accordion'; @import './Accordion/accordion';
@import './ExpandDeepButton/expand-deep-button';

View File

@@ -8,3 +8,6 @@ JSONSchemaContext.displayName = "JSONSchemaContext"
export const JSONSchemaLevelContext = createContext(0) export const JSONSchemaLevelContext = createContext(0)
JSONSchemaLevelContext.displayName = "JSONSchemaLevelContext" JSONSchemaLevelContext.displayName = "JSONSchemaLevelContext"
export const JSONSchemaDeepExpansionContext = createContext(false)
JSONSchemaDeepExpansionContext.displayName = "JSONSchemaDeepExpansionContext"

View File

@@ -7,6 +7,7 @@ import JSONSchema from "./components/JSONSchema/JSONSchema"
import BooleanJSONSchema from "./components/BooleanJSONSchema/BooleanJSONSchema" import BooleanJSONSchema from "./components/BooleanJSONSchema/BooleanJSONSchema"
import KeywordProperties from "./components/keywords/Properties" import KeywordProperties from "./components/keywords/Properties"
import Accordion from "./components/Accordion/Accordion" import Accordion from "./components/Accordion/Accordion"
import ExpandDeepButton from "./components/ExpandDeepButton/ExpandDeepButton"
import ChevronRightIcon from "./components/icons/ChevronRight" import ChevronRightIcon from "./components/icons/ChevronRight"
import { JSONSchemaContext } from "./context" import { JSONSchemaContext } from "./context"
import { getTitle, isBooleanJSONSchema, upperFirst } from "./fn" import { getTitle, isBooleanJSONSchema, upperFirst } from "./fn"
@@ -18,6 +19,7 @@ export const withJSONSchemaContext = (Component, overrides = {}) => {
BooleanJSONSchema, BooleanJSONSchema,
KeywordProperties, KeywordProperties,
Accordion, Accordion,
ExpandDeepButton,
ChevronRightIcon, ChevronRightIcon,
...overrides.components, ...overrides.components,
}, },

View File

@@ -3,7 +3,11 @@
*/ */
import { useContext } from "react" import { useContext } from "react"
import { JSONSchemaContext, JSONSchemaLevelContext } from "./context" import {
JSONSchemaContext,
JSONSchemaLevelContext,
JSONSchemaDeepExpansionContext,
} from "./context"
export const useConfig = () => { export const useConfig = () => {
const { config } = useContext(JSONSchemaContext) const { config } = useContext(JSONSchemaContext)
@@ -32,3 +36,7 @@ export const useIsEmbedded = () => {
return level > 0 return level > 0
} }
export const useIsExpandedDeeply = () => {
return useContext(JSONSchemaDeepExpansionContext)
}

View File

@@ -5,6 +5,7 @@ import JSONSchema from "./components/JSONSchema/JSONSchema"
import BooleanJSONSchema from "./components/BooleanJSONSchema/BooleanJSONSchema" import BooleanJSONSchema from "./components/BooleanJSONSchema/BooleanJSONSchema"
import JSONSchemaKeywordProperties from "./components/keywords/Properties" import JSONSchemaKeywordProperties from "./components/keywords/Properties"
import Accordion from "./components/Accordion/Accordion" import Accordion from "./components/Accordion/Accordion"
import ExpandDeepButton from "./components/ExpandDeepButton/ExpandDeepButton"
import ChevronRightIcon from "./components/icons/ChevronRight" import ChevronRightIcon from "./components/icons/ChevronRight"
import { upperFirst } from "./fn" import { upperFirst } from "./fn"
import { withJSONSchemaContext } from "./hoc" import { withJSONSchemaContext } from "./hoc"
@@ -15,6 +16,7 @@ const JSONSchema202012Plugin = () => ({
BooleanJSONSchema202012: BooleanJSONSchema, BooleanJSONSchema202012: BooleanJSONSchema,
JSONSchema202012KeywordProperties: JSONSchemaKeywordProperties, JSONSchema202012KeywordProperties: JSONSchemaKeywordProperties,
JSONSchema202012Accordion: Accordion, JSONSchema202012Accordion: Accordion,
JSONSchema202012ExpandDeepButton: ExpandDeepButton,
JSONSchema202012ChevronRightIcon: ChevronRightIcon, JSONSchema202012ChevronRightIcon: ChevronRightIcon,
withJSONSchema202012Context: withJSONSchemaContext, withJSONSchema202012Context: withJSONSchemaContext,
}, },

View File

@@ -12,6 +12,7 @@ const ModelsWrapper = createOnlyOAS31ComponentWrapper(({ getSystem }) => {
const BooleanJSONSchema = getComponent("BooleanJSONSchema202012") const BooleanJSONSchema = getComponent("BooleanJSONSchema202012")
const KeywordProperties = getComponent("JSONSchema202012KeywordProperties") const KeywordProperties = getComponent("JSONSchema202012KeywordProperties")
const Accordion = getComponent("JSONSchema202012Accordion") const Accordion = getComponent("JSONSchema202012Accordion")
const ExpandDeepButton = getComponent("JSONSchema202012ExpandDeepButton")
const ChevronRightIcon = getComponent("JSONSchema202012ChevronRightIcon") const ChevronRightIcon = getComponent("JSONSchema202012ChevronRightIcon")
const withSchemaContext = getComponent("withJSONSchema202012Context") const withSchemaContext = getComponent("withJSONSchema202012Context")
const ModelsWithJSONContext = withSchemaContext(Models, { const ModelsWithJSONContext = withSchemaContext(Models, {
@@ -23,6 +24,7 @@ const ModelsWrapper = createOnlyOAS31ComponentWrapper(({ getSystem }) => {
BooleanJSONSchema, BooleanJSONSchema,
KeywordProperties, KeywordProperties,
Accordion, Accordion,
ExpandDeepButton,
ChevronRightIcon, ChevronRightIcon,
}, },
fn: { fn: {