mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-07-06 09:51:29 +02:00
#513 - support for custom field + panel view
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
import * as React from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { CustomPanelViewResult } from '../../../models';
|
||||
import { Collapsible } from '../Collapsible';
|
||||
|
||||
export interface ICustomViewProps {
|
||||
metadata: any;
|
||||
}
|
||||
|
||||
export const CustomView: React.FunctionComponent<ICustomViewProps> = ({ metadata }: React.PropsWithChildren<ICustomViewProps>) => {
|
||||
const [customViewTitle, setCustomViewTitle] = useState<string | undefined>(undefined);
|
||||
const [customHtml, setCustomHtml] = useState<string | undefined>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
console.log(window.fmExternal)
|
||||
if (window.fmExternal && window.fmExternal.getPanelView) {
|
||||
window.fmExternal.getPanelView(metadata).then((viewDetails: CustomPanelViewResult | undefined) => {
|
||||
if (viewDetails && viewDetails.title && viewDetails.content) {
|
||||
setCustomViewTitle(viewDetails.title);
|
||||
setCustomHtml(viewDetails.content);
|
||||
} else {
|
||||
setCustomViewTitle(undefined);
|
||||
setCustomHtml(undefined);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (!customHtml || !customViewTitle) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<Collapsible
|
||||
id={`custom-view`}
|
||||
className={`base__actions`}
|
||||
title={customViewTitle}
|
||||
>
|
||||
<div dangerouslySetInnerHTML={{ __html: customHtml }} />
|
||||
</Collapsible>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from './CustomView';
|
||||
@@ -0,0 +1,58 @@
|
||||
import { CodeIcon } from '@heroicons/react/outline';
|
||||
import * as React from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { BaseFieldProps, CustomPanelViewResult } from '../../../models';
|
||||
import { FieldMessage } from './FieldMessage';
|
||||
import { FieldTitle } from './FieldTitle';
|
||||
|
||||
export interface ICustomFieldProps extends BaseFieldProps<any> {
|
||||
fieldData: {
|
||||
name: string,
|
||||
html: (data: any, onChange: (value: any) => void) => Promise<CustomPanelViewResult | undefined>,
|
||||
};
|
||||
onChange: (value: any) => void;
|
||||
}
|
||||
|
||||
export const CustomField: React.FunctionComponent<ICustomFieldProps> = ({ label, value, required, description, fieldData, onChange }: React.PropsWithChildren<ICustomFieldProps>) => {
|
||||
const [customHtml, setCustomHtml] = useState<any>(null);
|
||||
|
||||
const internalChange = (newValue: any) => {
|
||||
onChange(newValue);
|
||||
};
|
||||
|
||||
const showRequiredState = useMemo(() => {
|
||||
return required && !value;
|
||||
}, [required, value]);
|
||||
|
||||
useEffect(() => {
|
||||
if (fieldData.html) {
|
||||
fieldData.html(value, internalChange).then((data) => {
|
||||
if (data) {
|
||||
setCustomHtml(data);
|
||||
} else {
|
||||
setCustomHtml(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [fieldData, value]);
|
||||
|
||||
if (!customHtml) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`metadata_field`}>
|
||||
<FieldTitle label={label} icon={<CodeIcon />} required={required} />
|
||||
|
||||
<div className="metadata_field">
|
||||
<div dangerouslySetInnerHTML={{ __html: customHtml }} />
|
||||
</div>
|
||||
|
||||
<FieldMessage
|
||||
name={label.toLowerCase()}
|
||||
description={description}
|
||||
showRequired={showRequiredState}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -2,7 +2,7 @@ import { Messenger } from '@estruyf/vscode/dist/client';
|
||||
import * as React from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { DateHelper } from '../../../helpers/DateHelper';
|
||||
import { BlockFieldData, Field, PanelSettings, WhenOperator } from '../../../models';
|
||||
import { BlockFieldData, CustomPanelViewResult, Field, PanelSettings, WhenOperator } from '../../../models';
|
||||
import { Command } from '../../Command';
|
||||
import { CommandToCode } from '../../CommandToCode';
|
||||
import { TagType } from '../../TagType';
|
||||
@@ -26,7 +26,8 @@ import {
|
||||
SlugField,
|
||||
PreviewImageField,
|
||||
PreviewImageValue,
|
||||
NumberField
|
||||
NumberField,
|
||||
CustomField
|
||||
} from '.';
|
||||
import { fieldWhenClause } from '../../../utils/fieldWhenClause';
|
||||
|
||||
@@ -65,6 +66,10 @@ export const WrapperField: React.FunctionComponent<IWrapperFieldProps> = ({
|
||||
renderFields
|
||||
}: React.PropsWithChildren<IWrapperFieldProps>) => {
|
||||
const [fieldValue, setFieldValue] = useState<any | undefined>(undefined);
|
||||
const [customFields, setCustomFields] = useState<{
|
||||
name: string;
|
||||
html: (data: any, onChange: (value: any) => void) => Promise<CustomPanelViewResult | undefined>;
|
||||
}[]>([]);
|
||||
|
||||
const listener = useCallback(
|
||||
(event: any) => {
|
||||
@@ -132,6 +137,14 @@ export const WrapperField: React.FunctionComponent<IWrapperFieldProps> = ({
|
||||
};
|
||||
}, [field, parent]);
|
||||
|
||||
useEffect(() => {
|
||||
if (window.fmExternal && window.fmExternal.getCustomFields) {
|
||||
setCustomFields(window.fmExternal.getCustomFields || []);
|
||||
} else {
|
||||
setCustomFields([]);
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (field.hidden || fieldValue === undefined) {
|
||||
return null;
|
||||
}
|
||||
@@ -470,6 +483,22 @@ export const WrapperField: React.FunctionComponent<IWrapperFieldProps> = ({
|
||||
/>
|
||||
</FieldBoundary>
|
||||
);
|
||||
} else if (customFields.find(f => f.name === field.type)) {
|
||||
const fieldData = customFields.find(f => f.name === field.type);
|
||||
if (fieldData) {
|
||||
return (
|
||||
<CustomField
|
||||
key={field.name}
|
||||
label={field.title || field.name}
|
||||
description={field.description}
|
||||
value={fieldValue}
|
||||
required={!!field.required}
|
||||
onChange={(value: any) => onSendUpdate(field.name, value, parentFields)}
|
||||
fieldData={fieldData} />
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
console.warn(`Unknown field type: ${field.type}`);
|
||||
return null;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
export * from './ChoiceButton';
|
||||
export * from './ChoiceField';
|
||||
export * from './CustomField';
|
||||
export * from './DataFileField';
|
||||
export * from './DateTimeField';
|
||||
export * from './DraftField';
|
||||
export * from './FieldMessage';
|
||||
export * from './FieldTitle';
|
||||
export * from './FileField';
|
||||
export * from './ImageFallback';
|
||||
@@ -11,7 +13,6 @@ export * from './NumberField';
|
||||
export * from './PreviewImage';
|
||||
export * from './PreviewImageField';
|
||||
export * from './RequiredAsterix';
|
||||
export * from './FieldMessage';
|
||||
export * from './SlugField';
|
||||
export * from './TextField';
|
||||
export * from './Toggle';
|
||||
|
||||
Reference in New Issue
Block a user