Skip to content

Commit

Permalink
feat(form): add support for anchor links
Browse files Browse the repository at this point in the history
- Shows anchor icon on hover over field titles
- Anchor links work also with tab fields
- Can be disabled globally by passing `hideAnchors` to FormuleForm or to FormPreview
  • Loading branch information
miguelgrc authored and pamfilos committed Jun 26, 2024
1 parent 1515624 commit ecf6acb
Show file tree
Hide file tree
Showing 13 changed files with 185 additions and 113 deletions.
11 changes: 6 additions & 5 deletions src/admin/components/FormPreview.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import { Row, Empty, Space, Typography, Col } from "antd";
import { useSelector } from "react-redux";
import CustomizationContext from "../../contexts/CustomizationContext";

const FormPreview = ({liveValidate}) => {
const schema = useSelector((state) => state.schemaWizard.current.schema)
const uiSchema = useSelector((state) => state.schemaWizard.current.uiSchema)
const formData = useSelector((state) => state.schemaWizard.formData)
const FormPreview = ({ liveValidate, hideAnchors }) => {
const schema = useSelector((state) => state.schemaWizard.current.schema);
const uiSchema = useSelector((state) => state.schemaWizard.current.uiSchema);
const formData = useSelector((state) => state.schemaWizard.formData);

const customizationContext = useContext(CustomizationContext)
const customizationContext = useContext(CustomizationContext);

return (
<div
Expand Down Expand Up @@ -56,6 +56,7 @@ const FormPreview = ({liveValidate}) => {
formData={formData || {}}
onChange={() => {}}
liveValidate={liveValidate}
hideAnchors={hideAnchors}
/>
</Col>
</Row>
Expand Down
7 changes: 5 additions & 2 deletions src/admin/components/PropKeyEditorForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ const PropertyKeyEditorForm = ({
}) => {
const customizationContext = useContext(CustomizationContext);

const updatedFormData = {...formData}
const updatedFormData = { ...formData };

let type;

const cleanupSelect = () =>
schema.type === "array" ? delete updatedFormData.enum : delete updatedFormData.items;
schema.type === "array"
? delete updatedFormData.enum
: delete updatedFormData.items;

// in case we can not define the type of the element from the uiSchema,
// extract the type from the schema
Expand Down Expand Up @@ -61,6 +63,7 @@ const PropertyKeyEditorForm = ({
formData={updatedFormData}
onChange={onChange}
liveValidate
hideAnchors
/>
);
};
Expand Down
7 changes: 3 additions & 4 deletions src/admin/formComponents/SchemaTreeItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ const SchemaTreeItem = ({
const dropdownItems = [
{
key: "copy",
label: "Copy key",
label: "Copy ID",
icon: <CopyOutlined />,
},
];
Expand All @@ -108,7 +108,6 @@ const SchemaTreeItem = ({
backgroundColor: "white",
}}
data-cy="treeItem"
id="tag-jaja"
>
<Dropdown
menu={{ items: dropdownItems, onClick: handleDropdownClick }}
Expand All @@ -120,7 +119,7 @@ const SchemaTreeItem = ({
<Row
style={{
width: "100%",
marginTop: schema.title ? "-9px" : "0",
marginTop: schema.title ? "-6px" : "0",
}}
justify="space-between"
wrap={false}
Expand All @@ -137,7 +136,7 @@ const SchemaTreeItem = ({
style={{
width: "100%",
marginTop: "-9px",
marginBottom: "-9px",
marginBottom: "-5px",
}}
>
<Col>
Expand Down
5 changes: 5 additions & 0 deletions src/forms/Form.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { useContext } from "react";
import { Provider, useDispatch } from "react-redux";
import store from "../store/configureStore";
import { updateFormData } from "../store/schemaWizard";
import { RJSF_SEPARATOR } from "./templates/utils";

const RJSFForm = ({
formRef,
Expand All @@ -34,6 +35,7 @@ const RJSFForm = ({
liveValidate = false,
showErrorList = false,
transformErrors,
hideAnchors,
}) => {
const customizationContext = useContext(CustomizationContext);

Expand Down Expand Up @@ -84,7 +86,9 @@ const RJSFForm = ({
formContext={{
formRef: formRef,
...formContext,
hideAnchors: hideAnchors,
}}
idSeparator={RJSF_SEPARATOR}
>
<span />
</Form>
Expand Down Expand Up @@ -112,6 +116,7 @@ RJSFForm.propTypes = {
FieldTemplate: PropTypes.node,
ObjectFieldTemplate: PropTypes.node,
ArrayFieldTemplate: PropTypes.node,
hideAnchors: PropTypes.bool,
};

export default RJSFForm;
10 changes: 6 additions & 4 deletions src/forms/Form.less
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,13 @@
padding: 10px 0;
}
}
}

.__PublishedForm__ {
textarea {
resize: none;
.formItemTitle:not(:hover) .itemTitleAnchor {
visibility: hidden;
}

.ant-form-item-label label {
width: 100%;
}
}

Expand Down
20 changes: 13 additions & 7 deletions src/forms/fields/internal/TitleField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Markdown from "../../../partials/Markdown/Markdown";
const TitleField = ({
formContext,
id,
fieldId,
prefixCls,
required,
title,
Expand All @@ -23,6 +24,7 @@ const TitleField = ({
readonly,
titleIsMarkdown,
isObject,
hideAnchors,
}) => {
const { colon = true } = formContext;

Expand All @@ -34,6 +36,7 @@ const TitleField = ({
const labelClassName = classNames({
[`${prefixCls}-item-required`]: required,
[`${prefixCls}-item-no-colon`]: !colon,
formItemTitle: true,
});

const handleLabelClick = () => {
Expand All @@ -50,8 +53,8 @@ const TitleField = ({
if (!title) return null;

const titleText = (
<Typography.Text
style={{ fontSize: isObject && "12pt" }}
<Typography.Paragraph
style={{ fontSize: isObject && "12pt", marginBottom: 0 }}
strong
className={labelClassName}
htmlFor={id}
Expand All @@ -61,12 +64,15 @@ const TitleField = ({
>
<Markdown
text={labelChildren}
style={{
color: "#000",
}}
style={{ color: "#000" }}
renderAsHtml={titleIsMarkdown}
/>
</Typography.Text>
{!hideAnchors && (
<a href={`#${fieldId}`} className="itemTitleAnchor">
&nbsp;#
</a>
)}
</Typography.Paragraph>
);
if ((uiImport && !readonly) || uiLatex || uiEmail) {
return (
Expand Down Expand Up @@ -110,7 +116,7 @@ const TitleField = ({
</Row>
);
}
return <>{titleText}</>;
return titleText;
};

TitleField.propTypes = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const NormalArrayFieldTemplate = ({
formData,
}) => {
const { useToken } = theme;
const { rowGutter = 24 } = formContext;
const { rowGutter = 24, hideAnchors } = formContext;

const [latexData, setLatexData] = useState(null);
const [showModal, setShowModal] = useState(false);
Expand Down Expand Up @@ -250,7 +250,8 @@ const NormalArrayFieldTemplate = ({
<FieldHeader
titleField={
<TitleField
id={`${idSchema.$id}__title`}
id={`${idSchema.$id}-title`}
fieldId={idSchema.$id}
key={`array-field-title-${idSchema.$id}`}
required={required}
title={uiSchema["ui:title"] || title}
Expand All @@ -261,6 +262,7 @@ const NormalArrayFieldTemplate = ({
enableLatex={() => _enableLatex()}
enableImport={() => setImportModal(true)}
enableEmail={() => setEmailModal(true)}
hideAnchors={hideAnchors}
/>
}
description={uiSchema["ui:description"] || schema.description}
Expand Down
29 changes: 17 additions & 12 deletions src/forms/templates/Field/FieldHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,25 @@ const FieldHeader = ({
isObject,
idSchema,
titleField,
hideAnchors,
}) => {
return (
<Space direction="vertical" size={0}>
{titleField && titleField}
{uiSchema["ui:title"] !== false && label && (
<TitleField
title={label}
titleIsMarkdown={
uiSchema["ui:options"] && uiSchema["ui:options"].titleIsMarkdown
}
isObject={isObject}
id={`${idSchema.$id}-title`}
/>
)}
<Space direction="vertical" size={0} style={{ width: "100%" }}>
{titleField
? titleField
: uiSchema["ui:title"] !== false &&
label && (
<TitleField
title={label}
titleIsMarkdown={
uiSchema["ui:options"] && uiSchema["ui:options"].titleIsMarkdown
}
isObject={isObject}
id={`${idSchema.$id}-title`}
fieldId={idSchema.$id}
hideAnchors={hideAnchors}
/>
)}
{description && (
<Typography.Text type="secondary" id={`${idSchema.$id}-description`}>
<Markdown
Expand Down
32 changes: 14 additions & 18 deletions src/forms/templates/Field/FieldTemplate.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const FieldTemplate = ({
labelCol = VERTICAL_LABEL_COL,
wrapperCol = VERTICAL_WRAPPER_COL,
wrapperStyle,
hideAnchors,
} = formContext;

if (hidden) {
Expand All @@ -50,20 +51,21 @@ const FieldTemplate = ({

const shouldShowAsModal = uiOptions?.showAsModal === true;

const FieldHeaderWithProps = (
<FieldHeader
label={label}
description={rawDescription}
uiSchema={uiSchema}
idSchema={{ $id: id }}
hideAnchors={hideAnchors}
/>
);

let _children;
if (shouldShowAsModal) {
_children = (
<FieldModal
label={
label && (
<FieldHeader
label={label}
description={rawDescription}
uiSchema={uiSchema}
idSchema={{ $id: id }}
/>
)
}
label={label && FieldHeaderWithProps}
id={id}
content={children}
options={{
Expand Down Expand Up @@ -103,14 +105,8 @@ const FieldTemplate = ({
!shouldShowAsModal &&
(displayLabel ||
(uiSchema["ui:field"] && uiSchema["ui:label"] != false)) &&
label && (
<FieldHeader
label={label}
description={rawDescription}
uiSchema={uiSchema}
idSchema={{ $id: id }}
/>
)
label &&
FieldHeaderWithProps
}
labelCol={labelCol}
required={required}
Expand Down
Loading

0 comments on commit ecf6acb

Please sign in to comment.