fix: media library url entry (#775)
This commit is contained in:
parent
7d0a705eee
commit
a7ab1a7c0d
@ -63,5 +63,6 @@ export const isSelectionExpanded = jest.fn();
|
||||
export const isText = jest.fn();
|
||||
export const someNode = jest.fn();
|
||||
export const usePlateSelection = jest.fn();
|
||||
export const isMarkActive = jest.fn();
|
||||
|
||||
export default {};
|
||||
|
@ -157,16 +157,18 @@ const Field: FC<FieldProps> = ({
|
||||
{renderedHint}
|
||||
{renderedErrorMessage}
|
||||
</div>
|
||||
<div
|
||||
className={classNames(
|
||||
`
|
||||
{endAdornment ? (
|
||||
<div
|
||||
className={classNames(
|
||||
`
|
||||
pr-2
|
||||
`,
|
||||
!noPadding && '-mb-3',
|
||||
)}
|
||||
>
|
||||
{endAdornment}
|
||||
</div>
|
||||
!noPadding && '-mb-3',
|
||||
)}
|
||||
>
|
||||
{endAdornment}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -1,9 +1,11 @@
|
||||
import React from 'react';
|
||||
import { Image as ImageIcon } from '@styled-icons/material-outlined/Image';
|
||||
|
||||
import useMediaAsset from '@staticcms/core/lib/hooks/useMediaAsset';
|
||||
import classNames from '@staticcms/core/lib/util/classNames.util';
|
||||
import { selectEditingDraft } from '@staticcms/core/reducers/selectors/entryDraft';
|
||||
import { useAppSelector } from '@staticcms/core/store/hooks';
|
||||
import { isEmpty } from '@staticcms/core/lib/util/string.util';
|
||||
|
||||
import type { BaseField, Collection, MediaField, UnknownField } from '@staticcms/core/interface';
|
||||
|
||||
@ -28,6 +30,20 @@ const Image = <EF extends BaseField = UnknownField>({
|
||||
|
||||
const assetSource = useMediaAsset(src, collection, field, entry);
|
||||
|
||||
if (isEmpty(src)) {
|
||||
return (
|
||||
<ImageIcon
|
||||
className="
|
||||
p-10
|
||||
rounded-md
|
||||
border
|
||||
border-gray-200/75
|
||||
dark:border-slate-600/75
|
||||
"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<img
|
||||
key="image"
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
import classNames from '@staticcms/core/lib/util/classNames.util';
|
||||
import { isEmpty } from '../../../lib/util/string.util';
|
||||
import Image from '../../common/image/Image';
|
||||
import InlineEditTextField from './InlineEditTextField';
|
||||
@ -14,6 +15,7 @@ interface CurrentMediaDetailsProps {
|
||||
url?: string | string[];
|
||||
alt?: string;
|
||||
insertOptions?: MediaLibrarInsertOptions;
|
||||
forImage: boolean;
|
||||
onUrlChange: (url: string) => void;
|
||||
onAltChange: (alt: string) => void;
|
||||
}
|
||||
@ -25,54 +27,83 @@ const CurrentMediaDetails: FC<CurrentMediaDetailsProps> = ({
|
||||
url,
|
||||
alt,
|
||||
insertOptions,
|
||||
forImage,
|
||||
onUrlChange,
|
||||
onAltChange,
|
||||
}) => {
|
||||
if (!field || !canInsert || typeof url !== 'string' || isEmpty(url)) {
|
||||
if (
|
||||
!field ||
|
||||
!canInsert ||
|
||||
Array.isArray(url) ||
|
||||
(!insertOptions?.chooseUrl &&
|
||||
!insertOptions?.showAlt &&
|
||||
(typeof url !== 'string' || isEmpty(url)))
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className="
|
||||
grid
|
||||
grid-cols-media-preview
|
||||
items-center
|
||||
px-5
|
||||
py-4
|
||||
border-b
|
||||
border-gray-200/75
|
||||
dark:border-slate-500/75
|
||||
"
|
||||
>
|
||||
<Image
|
||||
src={url}
|
||||
collection={collection}
|
||||
field={field}
|
||||
className="
|
||||
w-media-preview-image
|
||||
h-media-preview-image
|
||||
rounded-md
|
||||
shadow-sm
|
||||
overflow-hidden
|
||||
group/media-card
|
||||
border
|
||||
bg-gray-50/75
|
||||
className={classNames(
|
||||
`
|
||||
items-center
|
||||
px-5
|
||||
py-4
|
||||
border-b
|
||||
border-gray-200/75
|
||||
dark:bg-slate-800
|
||||
dark:border-slate-600/75
|
||||
object-cover
|
||||
"
|
||||
/>
|
||||
dark:border-slate-500/75
|
||||
`,
|
||||
forImage
|
||||
? `
|
||||
grid
|
||||
grid-cols-media-preview
|
||||
`
|
||||
: `
|
||||
flex
|
||||
w-full
|
||||
`,
|
||||
)}
|
||||
>
|
||||
{forImage ? (
|
||||
<Image
|
||||
key="image-preview"
|
||||
src={url}
|
||||
collection={collection}
|
||||
field={field}
|
||||
className="
|
||||
w-media-preview-image
|
||||
h-media-preview-image
|
||||
rounded-md
|
||||
shadow-sm
|
||||
overflow-hidden
|
||||
group/media-card
|
||||
border
|
||||
bg-gray-50/75
|
||||
border-gray-200/75
|
||||
dark:bg-slate-800
|
||||
dark:border-slate-600/75
|
||||
object-cover
|
||||
"
|
||||
/>
|
||||
) : null}
|
||||
<div
|
||||
className="
|
||||
flex
|
||||
flex-col
|
||||
h-full
|
||||
p-0
|
||||
pl-4
|
||||
gap-2
|
||||
"
|
||||
className={classNames(
|
||||
`
|
||||
flex
|
||||
flex-col
|
||||
h-full
|
||||
p-0
|
||||
gap-2
|
||||
`,
|
||||
forImage
|
||||
? `
|
||||
pl-4
|
||||
`
|
||||
: `
|
||||
w-full
|
||||
pl-1.5
|
||||
`,
|
||||
)}
|
||||
>
|
||||
<InlineEditTextField
|
||||
label="URL"
|
||||
@ -80,7 +111,11 @@ const CurrentMediaDetails: FC<CurrentMediaDetailsProps> = ({
|
||||
onChange={insertOptions?.chooseUrl ? onUrlChange : undefined}
|
||||
/>
|
||||
{insertOptions?.showAlt ? (
|
||||
<InlineEditTextField label="Alt" value={alt} onChange={onAltChange} />
|
||||
<InlineEditTextField
|
||||
label={forImage ? 'Alt' : 'Text'}
|
||||
value={alt}
|
||||
onChange={onAltChange}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -96,6 +96,7 @@ const InlineEditTextField: FC<InlineEditTextFieldProps> = ({
|
||||
{!editing || !onChange ? (
|
||||
<div
|
||||
key="value"
|
||||
tabIndex={0}
|
||||
className={classNames(
|
||||
`
|
||||
flex
|
||||
@ -110,7 +111,6 @@ const InlineEditTextField: FC<InlineEditTextFieldProps> = ({
|
||||
rounded-md
|
||||
border
|
||||
text-slate-600
|
||||
dark:font-semibold
|
||||
dark:text-gray-100
|
||||
`,
|
||||
onChange
|
||||
@ -125,6 +125,7 @@ const InlineEditTextField: FC<InlineEditTextFieldProps> = ({
|
||||
`,
|
||||
)}
|
||||
onClick={handleValueClick}
|
||||
onFocus={handleValueClick}
|
||||
>
|
||||
{internalValue}
|
||||
</div>
|
||||
|
@ -484,6 +484,7 @@ const MediaLibrary: FC<TranslatedProps<MediaLibraryProps>> = ({
|
||||
url={url}
|
||||
alt={alt}
|
||||
insertOptions={insertOptions}
|
||||
forImage={forImage}
|
||||
onUrlChange={handleURLChange}
|
||||
onAltChange={handleAltChange}
|
||||
/>
|
||||
|
@ -253,7 +253,7 @@ const PlateEditor: FC<PlateEditorProps> = ({
|
||||
|
||||
return useMemo(
|
||||
() => (
|
||||
<div className="relative px-3 py-5 pb-0 mb-5">
|
||||
<div className="relative px-3 py-5 pb-0">
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<PlateProvider<MdValue>
|
||||
id={id}
|
||||
@ -272,7 +272,7 @@ const PlateEditor: FC<PlateEditorProps> = ({
|
||||
disabled={disabled}
|
||||
/>
|
||||
|
||||
<div key="editor-wrapper" ref={editorContainerRef} className="w-full overflow-hidden">
|
||||
<div key="editor-wrapper" ref={editorContainerRef} className="w-full">
|
||||
<Plate
|
||||
key="editor"
|
||||
id={id}
|
||||
|
@ -2,9 +2,7 @@ import PopperUnstyled from '@mui/base/PopperUnstyled';
|
||||
import {
|
||||
ELEMENT_LINK,
|
||||
ELEMENT_TD,
|
||||
findNodePath,
|
||||
getNode,
|
||||
getParentNode,
|
||||
getSelectionBoundingClientRect,
|
||||
getSelectionText,
|
||||
isElement,
|
||||
@ -20,7 +18,6 @@ import { useFocused } from 'slate-react';
|
||||
import useDebounce from '@staticcms/core/lib/hooks/useDebounce';
|
||||
import { isEmpty } from '@staticcms/core/lib/util/string.util';
|
||||
import { useMdPlateEditorState } from '@staticcms/markdown/plate/plateTypes';
|
||||
import { VOID_ELEMENTS } from '../../serialization/slate/ast-types';
|
||||
import BasicElementToolbarButtons from '../buttons/BasicElementToolbarButtons';
|
||||
import BasicMarkToolbarButtons from '../buttons/BasicMarkToolbarButtons';
|
||||
import MediaToolbarButtons from '../buttons/MediaToolbarButtons';
|
||||
@ -156,29 +153,14 @@ const BalloonToolbar: FC<BalloonToolbarProps> = ({
|
||||
!useMdx ? <ShortcodeToolbarButton key="shortcode-button" disabled={disabled} /> : null,
|
||||
].filter(Boolean);
|
||||
|
||||
// if (isInTableCell) {
|
||||
// return allButtons;
|
||||
// }
|
||||
|
||||
// Empty paragraph, not first line
|
||||
// Empty table cell
|
||||
if (
|
||||
isInTableCell &&
|
||||
editor.children.length > 1 &&
|
||||
node &&
|
||||
((isElement(node) && isElementEmpty(editor, node)) || (isText(node) && isEmpty(node.text)))
|
||||
) {
|
||||
const path = findNodePath(editor, node) ?? [];
|
||||
const parent = getParentNode(editor, path);
|
||||
if (
|
||||
path.length > 0 &&
|
||||
path[0] !== 0 &&
|
||||
parent &&
|
||||
parent.length > 0 &&
|
||||
'children' in parent[0] &&
|
||||
!VOID_ELEMENTS.includes(parent[0].type as string) &&
|
||||
parent[0].children.length === 1
|
||||
) {
|
||||
return allButtons;
|
||||
}
|
||||
return allButtons;
|
||||
}
|
||||
|
||||
return [];
|
||||
|
@ -4,6 +4,7 @@
|
||||
import '@testing-library/jest-dom';
|
||||
import { screen } from '@testing-library/react';
|
||||
import {
|
||||
ELEMENT_LINK,
|
||||
findNodePath,
|
||||
getNode,
|
||||
getParentNode,
|
||||
@ -11,6 +12,7 @@ import {
|
||||
isElementEmpty,
|
||||
someNode,
|
||||
usePlateEditorState,
|
||||
usePlateSelection,
|
||||
} from '@udecode/plate';
|
||||
import React, { useRef } from 'react';
|
||||
import { useFocused } from 'slate-react';
|
||||
@ -25,6 +27,7 @@ import BalloonToolbar from '../BalloonToolbar';
|
||||
|
||||
import type { Config, MarkdownField } from '@staticcms/core/interface';
|
||||
import type { MdEditor } from '@staticcms/markdown/plate/plateTypes';
|
||||
import type { TRange } from '@udecode/plate';
|
||||
import type { FC } from 'react';
|
||||
|
||||
interface BalloonToolbarWrapperProps {
|
||||
@ -54,6 +57,7 @@ const config = createMockConfig({
|
||||
|
||||
describe(BalloonToolbar.name, () => {
|
||||
const mockUseEditor = usePlateEditorState as jest.Mock;
|
||||
const mockUsePlateSelection = usePlateSelection as jest.Mock;
|
||||
let mockEditor: MdEditor;
|
||||
|
||||
const mockGetNode = getNode as jest.Mock;
|
||||
@ -67,26 +71,6 @@ describe(BalloonToolbar.name, () => {
|
||||
beforeEach(() => {
|
||||
store.dispatch(configLoaded(config as unknown as Config));
|
||||
|
||||
// entry = {
|
||||
// collection: 'posts',
|
||||
// slug: '2022-12-13-post-number-1',
|
||||
// path: '_posts/2022-12-13-post-number-1.md',
|
||||
// partial: false,
|
||||
// raw: '--- title: "This is post # 1" draft: false date: 2022-12-13T00:00:00.000Z --- # The post is number 1\n\nAnd some text',
|
||||
// label: '',
|
||||
// author: '',
|
||||
// mediaFiles: [],
|
||||
// isModification: null,
|
||||
// newRecord: false,
|
||||
// updatedOn: '',
|
||||
// data: {
|
||||
// title: 'This is post # 1',
|
||||
// draft: false,
|
||||
// date: '2022-12-13T00:00:00.000Z',
|
||||
// body: '# The post is number 1\n\nAnd some text',
|
||||
// },
|
||||
// };
|
||||
|
||||
mockEditor = {
|
||||
selection: undefined,
|
||||
} as unknown as MdEditor;
|
||||
@ -99,45 +83,57 @@ describe(BalloonToolbar.name, () => {
|
||||
expect(screen.queryAllByRole('button').length).toBe(0);
|
||||
});
|
||||
|
||||
describe('empty node toolbar', () => {
|
||||
describe('empty node toolbar inside table', () => {
|
||||
interface EmptyNodeToolbarSetupOptions {
|
||||
useMdx?: boolean;
|
||||
}
|
||||
|
||||
const emptyNodeToolbarSetup = ({ useMdx }: EmptyNodeToolbarSetupOptions = {}) => {
|
||||
mockEditor = {
|
||||
selection: undefined,
|
||||
selection: {
|
||||
anchor: {
|
||||
path: [1, 0],
|
||||
offset: 0,
|
||||
},
|
||||
focus: {
|
||||
path: [1, 0],
|
||||
offset: 0,
|
||||
},
|
||||
} as TRange,
|
||||
children: [
|
||||
{
|
||||
type: 'p',
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
{
|
||||
type: 'p',
|
||||
type: 'td',
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
],
|
||||
} as unknown as MdEditor;
|
||||
|
||||
mockUseEditor.mockReturnValue(mockEditor);
|
||||
mockUsePlateSelection.mockReturnValue(mockEditor.selection);
|
||||
|
||||
mockGetNode.mockReturnValue({ text: '' });
|
||||
mockIsElement.mockReturnValue(true);
|
||||
mockIsElementEmpty.mockReturnValue(true);
|
||||
mockSomeNode.mockReturnValue(false);
|
||||
mockSomeNode.mockImplementation((_editor, { match: { type } }) => type !== ELEMENT_LINK);
|
||||
mockUseFocused.mockReturnValue(true);
|
||||
|
||||
mockFindNodePath.mockReturnValue([1, 0]);
|
||||
mockGetParentNode.mockReturnValue([
|
||||
{
|
||||
type: 'p',
|
||||
type: 'td',
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
]);
|
||||
|
||||
const { rerender } = renderWithProviders(<BalloonToolbarWrapper />);
|
||||
const result = renderWithProviders(<BalloonToolbarWrapper />);
|
||||
|
||||
rerender(<BalloonToolbarWrapper useMdx={useMdx} />);
|
||||
result.rerender(<BalloonToolbarWrapper useMdx={useMdx} />);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
it('renders empty node toolbar for markdown', () => {
|
||||
@ -148,8 +144,14 @@ describe(BalloonToolbar.name, () => {
|
||||
expect(screen.queryByTestId('toolbar-button-code')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('toolbar-button-strikethrough')).toBeInTheDocument();
|
||||
|
||||
expect(screen.queryByTestId('font-type-select')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('toolbar-button-add-table')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('font-type-select')).not.toBeInTheDocument();
|
||||
|
||||
expect(screen.queryByTestId('toolbar-button-insert-row')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('toolbar-button-delete-row')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('toolbar-button-insert-column')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('toolbar-button-delete-column')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('toolbar-button-delete-table')).toBeInTheDocument();
|
||||
|
||||
expect(screen.queryByTestId('toolbar-button-insert-link')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('toolbar-button-insert-image')).toBeInTheDocument();
|
||||
|
||||
@ -165,8 +167,14 @@ describe(BalloonToolbar.name, () => {
|
||||
expect(screen.queryByTestId('toolbar-button-code')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('toolbar-button-strikethrough')).toBeInTheDocument();
|
||||
|
||||
expect(screen.queryByTestId('font-type-select')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('toolbar-button-add-table')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('font-type-select')).not.toBeInTheDocument();
|
||||
|
||||
expect(screen.queryByTestId('toolbar-button-insert-row')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('toolbar-button-delete-row')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('toolbar-button-insert-column')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('toolbar-button-delete-column')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('toolbar-button-delete-table')).toBeInTheDocument();
|
||||
|
||||
expect(screen.queryByTestId('toolbar-button-insert-link')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('toolbar-button-insert-image')).toBeInTheDocument();
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { TableAdd } from '@styled-icons/fluentui-system-regular/TableAdd';
|
||||
import { Add as AddIcon } from '@styled-icons/material/Add';
|
||||
import { Code as CodeIcon } from '@styled-icons/material/Code';
|
||||
import { FormatQuote as FormatQuoteIcon } from '@styled-icons/material/FormatQuote';
|
||||
@ -6,7 +7,9 @@ import {
|
||||
ELEMENT_CODE_BLOCK,
|
||||
ELEMENT_IMAGE,
|
||||
ELEMENT_LINK,
|
||||
ELEMENT_TABLE,
|
||||
insertEmptyCodeBlock,
|
||||
insertTable,
|
||||
toggleNodeType,
|
||||
} from '@udecode/plate';
|
||||
import React, { useCallback } from 'react';
|
||||
@ -43,6 +46,13 @@ const AddButtons: FC<AddButtonsProps> = ({ collection, field, disabled }) => {
|
||||
});
|
||||
}, [editor]);
|
||||
|
||||
const handleTableAdd = useCallback(() => {
|
||||
insertTable(editor, {
|
||||
rowCount: 2,
|
||||
colCount: 2,
|
||||
});
|
||||
}, [editor]);
|
||||
|
||||
return (
|
||||
<Menu
|
||||
label={<AddIcon className="h-5 w-5" aria-hidden="true" />}
|
||||
@ -74,6 +84,11 @@ const AddButtons: FC<AddButtonsProps> = ({ collection, field, disabled }) => {
|
||||
Code Block
|
||||
</MenuItemButton>
|
||||
</MenuGroup>
|
||||
<MenuGroup>
|
||||
<MenuItemButton key={ELEMENT_TABLE} onClick={handleTableAdd} startIcon={TableAdd}>
|
||||
Table
|
||||
</MenuItemButton>
|
||||
</MenuGroup>
|
||||
<MenuGroup>
|
||||
<ImageToolbarButton
|
||||
key={ELEMENT_IMAGE}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Image as ImageIcon } from '@styled-icons/material/Image';
|
||||
import { ELEMENT_IMAGE, insertImage } from '@udecode/plate';
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
|
||||
import MenuItemButton from '@staticcms/core/components/common/menu/MenuItemButton';
|
||||
import useMediaInsert from '@staticcms/core/lib/hooks/useMediaInsert';
|
||||
@ -36,12 +36,14 @@ const ImageToolbarButton: FC<ImageToolbarButtonProps> = ({
|
||||
[editor],
|
||||
);
|
||||
|
||||
const chooseUrl = useMemo(() => field.choose_url ?? true, [field.choose_url]);
|
||||
|
||||
const openMediaLibrary = useMediaInsert(
|
||||
{
|
||||
path: currentValue?.url ?? '',
|
||||
alt: currentValue?.alt,
|
||||
},
|
||||
{ collection, field, forImage: true },
|
||||
{ collection, field, forImage: true, insertOptions: { chooseUrl, showAlt: true } },
|
||||
handleInsert,
|
||||
);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Link as LinkIcon } from '@styled-icons/material/Link';
|
||||
import { ELEMENT_LINK, insertLink, someNode } from '@udecode/plate';
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
|
||||
import MenuItemButton from '@staticcms/core/components/common/menu/MenuItemButton';
|
||||
import useMediaInsert from '@staticcms/core/lib/hooks/useMediaInsert';
|
||||
@ -41,6 +41,8 @@ const LinkToolbarButton: FC<LinkToolbarButtonProps> = ({
|
||||
[editor],
|
||||
);
|
||||
|
||||
const chooseUrl = useMemo(() => field.choose_url ?? true, [field.choose_url]);
|
||||
|
||||
const isLink = !!editor?.selection && someNode(editor, { match: { type: ELEMENT_LINK } });
|
||||
|
||||
const controlID = useUUID();
|
||||
@ -49,7 +51,7 @@ const LinkToolbarButton: FC<LinkToolbarButtonProps> = ({
|
||||
path: currentValue?.url ?? '',
|
||||
alt: currentValue?.alt,
|
||||
},
|
||||
{ collection, field, controlID, forImage: true },
|
||||
{ collection, field, controlID, forImage: false, insertOptions: { chooseUrl, showAlt: true } },
|
||||
handleInsert,
|
||||
);
|
||||
|
||||
|
@ -45,7 +45,7 @@ const MediaPopover = <T extends FileOrImageField | MarkdownField>({
|
||||
onMediaToggle?.(false);
|
||||
});
|
||||
|
||||
const chooseUrl = useMemo(() => field.choose_url ?? false, [field.choose_url]);
|
||||
const chooseUrl = useMemo(() => field.choose_url ?? true, [field.choose_url]);
|
||||
|
||||
const handleFocus = useCallback(() => {
|
||||
onFocus?.();
|
||||
|
@ -22,7 +22,6 @@ const TableHeaderCellElement: FC<PlateRenderElementProps<MdValue, MdTableCellEle
|
||||
text-sm
|
||||
border-r
|
||||
border-gray-200
|
||||
last:border-0
|
||||
dark:bg-slate-700
|
||||
dark:border-gray-800
|
||||
"
|
||||
|
@ -27,7 +27,19 @@ const TableElement: FC<PlateRenderElementProps<MdValue, MdTableElement>> = ({
|
||||
>
|
||||
{children ? (
|
||||
<>
|
||||
<thead key="thead">{children[0]}</thead>
|
||||
<thead
|
||||
key="thead"
|
||||
className="
|
||||
border-r
|
||||
border-b
|
||||
bg-slate-300
|
||||
border-gray-200
|
||||
dark:bg-slate-700
|
||||
dark:border-gray-800
|
||||
"
|
||||
>
|
||||
{children[0]}
|
||||
</thead>
|
||||
<tbody key="tbody">{children.slice(1)}</tbody>
|
||||
</>
|
||||
) : null}
|
||||
|
@ -22,7 +22,7 @@ For common options, see [Common widget options](/docs/widgets#common-widget-opti
|
||||
| media_folder | string | | _Optional_. Specifies the folder path where uploaded files should be saved, relative to the base of the repo |
|
||||
| public_folder | string | | _Optional_. Specifies the folder path where the files uploaded by the media library will be accessed, relative to the base of the built site |
|
||||
| media_library | Media Library Options | `{}` | _Optional_. Media library settings to apply when the media library is opened by the current widget. See [Media Library](/docs/configuration-options#media-library) |
|
||||
| choose_url | boolean | `false` | _Optional_. When set to `false`, the "Insert from URL" button will be hidden |
|
||||
| choose_url | boolean | `true` | _Optional_. When set to `false`, the "Insert from URL" button will be hidden |
|
||||
|
||||
## Example
|
||||
|
||||
@ -231,9 +231,13 @@ const ImageControl = ({ src, onChange, controlProps }) => {
|
||||
onChange({ src: path });
|
||||
};
|
||||
|
||||
const handleOpenMediaLibrary = useMediaInsert(src, { collection: collection, field }, handleChange);
|
||||
const handleOpenMediaLibrary = useMediaInsert(
|
||||
src,
|
||||
{ collection: collection, field },
|
||||
handleChange,
|
||||
);
|
||||
|
||||
const assetSource = useMediaAsset(src , collection, field, entry);
|
||||
const assetSource = useMediaAsset(src, collection, field, entry);
|
||||
|
||||
return [
|
||||
h('button', { type: 'button', onClick: handleOpenMediaLibrary }, 'Upload'),
|
||||
@ -253,9 +257,13 @@ const ImageControl = ({ src, onChange, controlProps }) => {
|
||||
onChange({ src: path });
|
||||
};
|
||||
|
||||
const handleOpenMediaLibrary = useMediaInsert(src ,{ collection: collection, field }, handleChange);
|
||||
const handleOpenMediaLibrary = useMediaInsert(
|
||||
src,
|
||||
{ collection: collection, field },
|
||||
handleChange,
|
||||
);
|
||||
|
||||
const assetSource = useMediaAsset(src , collection, field, entry);
|
||||
const assetSource = useMediaAsset(src, collection, field, entry);
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -275,11 +283,7 @@ import useMediaInsert from '@staticcms/core/lib/hooks/useMediaInsert';
|
||||
import type { WidgetControlProps, MediaPath } from '@staticcms/core/interface';
|
||||
import type { FC } from 'react';
|
||||
|
||||
const FileControl: FC<WidgetControlProps<string, MyField>> = ({
|
||||
src,
|
||||
onChange,
|
||||
controlProps
|
||||
}) => {
|
||||
const FileControl: FC<WidgetControlProps<string, MyField>> = ({ src, onChange, controlProps }) => {
|
||||
const { collection, field, entry } = controlProps;
|
||||
|
||||
const handleChange = ({ path }: MediaPath) => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user