fix field input
This commit is contained in:
parent
cf6b8b0728
commit
285051b571
|
|
@ -85,7 +85,7 @@ export const FieldInput: FC<{
|
||||||
<div
|
<div
|
||||||
className={cx(
|
className={cx(
|
||||||
!["toogle", "button", "radio","checkbox"].includes(arg.sub_type)
|
!["toogle", "button", "radio","checkbox"].includes(arg.sub_type)
|
||||||
? "field-outer c-flex c-flex-1 c-flex-row c-rounded c-border c-text-sm"
|
? "field-outer c-flex c-flex-1 c-flex-row c-rounded c-border c-text-sm c-flex-wrap"
|
||||||
: "",
|
: "",
|
||||||
fm.status === "loading"
|
fm.status === "loading"
|
||||||
? css`
|
? css`
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,172 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||||
|
import {mergeRegister} from '@lexical/utils';
|
||||||
|
import {
|
||||||
|
$getSelection,
|
||||||
|
$isRangeSelection,
|
||||||
|
CAN_REDO_COMMAND,
|
||||||
|
CAN_UNDO_COMMAND,
|
||||||
|
FORMAT_ELEMENT_COMMAND,
|
||||||
|
FORMAT_TEXT_COMMAND,
|
||||||
|
REDO_COMMAND,
|
||||||
|
SELECTION_CHANGE_COMMAND,
|
||||||
|
UNDO_COMMAND,
|
||||||
|
} from 'lexical';
|
||||||
|
import {useCallback, useEffect, useRef, useState} from 'react';
|
||||||
|
|
||||||
|
const LowPriority = 1;
|
||||||
|
|
||||||
|
function Divider() {
|
||||||
|
return <div className="divider" />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ToolbarPlugin() {
|
||||||
|
const [editor] = useLexicalComposerContext();
|
||||||
|
const toolbarRef = useRef(null);
|
||||||
|
const [canUndo, setCanUndo] = useState(false);
|
||||||
|
const [canRedo, setCanRedo] = useState(false);
|
||||||
|
const [isBold, setIsBold] = useState(false);
|
||||||
|
const [isItalic, setIsItalic] = useState(false);
|
||||||
|
const [isUnderline, setIsUnderline] = useState(false);
|
||||||
|
const [isStrikethrough, setIsStrikethrough] = useState(false);
|
||||||
|
|
||||||
|
const $updateToolbar = useCallback(() => {
|
||||||
|
const selection = $getSelection();
|
||||||
|
if ($isRangeSelection(selection)) {
|
||||||
|
// Update text format
|
||||||
|
setIsBold(selection.hasFormat('bold'));
|
||||||
|
setIsItalic(selection.hasFormat('italic'));
|
||||||
|
setIsUnderline(selection.hasFormat('underline'));
|
||||||
|
setIsStrikethrough(selection.hasFormat('strikethrough'));
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return mergeRegister(
|
||||||
|
editor.registerUpdateListener(({editorState}) => {
|
||||||
|
editorState.read(() => {
|
||||||
|
$updateToolbar();
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
editor.registerCommand(
|
||||||
|
SELECTION_CHANGE_COMMAND,
|
||||||
|
(_payload, _newEditor) => {
|
||||||
|
$updateToolbar();
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
LowPriority,
|
||||||
|
),
|
||||||
|
editor.registerCommand(
|
||||||
|
CAN_UNDO_COMMAND,
|
||||||
|
(payload) => {
|
||||||
|
setCanUndo(payload);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
LowPriority,
|
||||||
|
),
|
||||||
|
editor.registerCommand(
|
||||||
|
CAN_REDO_COMMAND,
|
||||||
|
(payload) => {
|
||||||
|
setCanRedo(payload);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
LowPriority,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}, [editor, $updateToolbar]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="toolbar" ref={toolbarRef}>
|
||||||
|
<button
|
||||||
|
disabled={!canUndo}
|
||||||
|
onClick={() => {
|
||||||
|
editor.dispatchCommand(UNDO_COMMAND, undefined);
|
||||||
|
}}
|
||||||
|
className="toolbar-item spaced"
|
||||||
|
aria-label="Undo">
|
||||||
|
<i className="format undo" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
disabled={!canRedo}
|
||||||
|
onClick={() => {
|
||||||
|
editor.dispatchCommand(REDO_COMMAND, undefined);
|
||||||
|
}}
|
||||||
|
className="toolbar-item"
|
||||||
|
aria-label="Redo">
|
||||||
|
<i className="format redo" />
|
||||||
|
</button>
|
||||||
|
<Divider />
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'bold');
|
||||||
|
}}
|
||||||
|
className={'toolbar-item spaced ' + (isBold ? 'active' : '')}
|
||||||
|
aria-label="Format Bold">
|
||||||
|
<i className="format bold" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'italic');
|
||||||
|
}}
|
||||||
|
className={'toolbar-item spaced ' + (isItalic ? 'active' : '')}
|
||||||
|
aria-label="Format Italics">
|
||||||
|
<i className="format italic" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'underline');
|
||||||
|
}}
|
||||||
|
className={'toolbar-item spaced ' + (isUnderline ? 'active' : '')}
|
||||||
|
aria-label="Format Underline">
|
||||||
|
<i className="format underline" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'strikethrough');
|
||||||
|
}}
|
||||||
|
className={'toolbar-item spaced ' + (isStrikethrough ? 'active' : '')}
|
||||||
|
aria-label="Format Strikethrough">
|
||||||
|
<i className="format strikethrough" />
|
||||||
|
</button>
|
||||||
|
<Divider />
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, 'left');
|
||||||
|
}}
|
||||||
|
className="toolbar-item spaced"
|
||||||
|
aria-label="Left Align">
|
||||||
|
<i className="format left-align" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, 'center');
|
||||||
|
}}
|
||||||
|
className="toolbar-item spaced"
|
||||||
|
aria-label="Center Align">
|
||||||
|
<i className="format center-align" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, 'right');
|
||||||
|
}}
|
||||||
|
className="toolbar-item spaced"
|
||||||
|
aria-label="Right Align">
|
||||||
|
<i className="format right-align" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, 'justify');
|
||||||
|
}}
|
||||||
|
className="toolbar-item"
|
||||||
|
aria-label="Justify Align">
|
||||||
|
<i className="format justify-align" />
|
||||||
|
</button>{' '}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||||
|
import {TreeView} from '@lexical/react/LexicalTreeView';
|
||||||
|
|
||||||
|
export default function TreeViewPlugin(): JSX.Element {
|
||||||
|
const [editor] = useLexicalComposerContext();
|
||||||
|
return (
|
||||||
|
<TreeView
|
||||||
|
viewClassName="tree-view-output"
|
||||||
|
treeTypeButtonClassName="debug-treetype-button"
|
||||||
|
timeTravelPanelClassName="debug-timetravel-panel"
|
||||||
|
timeTravelButtonClassName="debug-timetravel-button"
|
||||||
|
timeTravelPanelSliderClassName="debug-timetravel-panel-slider"
|
||||||
|
timeTravelPanelButtonClassName="debug-timetravel-panel-button"
|
||||||
|
editor={editor}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,451 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background: #eee;
|
||||||
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, '.SFNSText-Regular',
|
||||||
|
sans-serif;
|
||||||
|
font-weight: 500;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
.other h2 {
|
||||||
|
font-size: 18px;
|
||||||
|
color: #444;
|
||||||
|
margin-bottom: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.other a {
|
||||||
|
color: #777;
|
||||||
|
text-decoration: underline;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.other ul {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.App {
|
||||||
|
font-family: sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ltr {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rtl {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-container {
|
||||||
|
margin: 20px auto 20px auto;
|
||||||
|
border-radius: 2px;
|
||||||
|
max-width: 600px;
|
||||||
|
color: #000;
|
||||||
|
position: relative;
|
||||||
|
line-height: 20px;
|
||||||
|
font-weight: 400;
|
||||||
|
text-align: left;
|
||||||
|
border-top-left-radius: 10px;
|
||||||
|
border-top-right-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-inner {
|
||||||
|
background: #fff;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-input {
|
||||||
|
min-height: 150px;
|
||||||
|
resize: none;
|
||||||
|
font-size: 15px;
|
||||||
|
caret-color: rgb(5, 5, 5);
|
||||||
|
position: relative;
|
||||||
|
tab-size: 1;
|
||||||
|
outline: 0;
|
||||||
|
padding: 15px 10px;
|
||||||
|
caret-color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-placeholder {
|
||||||
|
color: #999;
|
||||||
|
overflow: hidden;
|
||||||
|
position: absolute;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
top: 15px;
|
||||||
|
left: 10px;
|
||||||
|
font-size: 15px;
|
||||||
|
user-select: none;
|
||||||
|
display: inline-block;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-text-bold {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-text-italic {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-text-underline {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-text-strikethrough {
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-text-underlineStrikethrough {
|
||||||
|
text-decoration: underline line-through;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-text-code {
|
||||||
|
background-color: rgb(240, 242, 245);
|
||||||
|
padding: 1px 0.25rem;
|
||||||
|
font-family: Menlo, Consolas, Monaco, monospace;
|
||||||
|
font-size: 94%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-link {
|
||||||
|
color: rgb(33, 111, 219);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-view-output {
|
||||||
|
display: block;
|
||||||
|
background: #222;
|
||||||
|
color: #fff;
|
||||||
|
padding: 5px;
|
||||||
|
font-size: 12px;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
margin: 1px auto 10px auto;
|
||||||
|
max-height: 250px;
|
||||||
|
position: relative;
|
||||||
|
border-bottom-left-radius: 10px;
|
||||||
|
border-bottom-right-radius: 10px;
|
||||||
|
overflow: auto;
|
||||||
|
line-height: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-code {
|
||||||
|
background-color: rgb(240, 242, 245);
|
||||||
|
font-family: Menlo, Consolas, Monaco, monospace;
|
||||||
|
display: block;
|
||||||
|
padding: 8px 8px 8px 52px;
|
||||||
|
line-height: 1.53;
|
||||||
|
font-size: 13px;
|
||||||
|
margin: 0;
|
||||||
|
margin-top: 8px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
tab-size: 2;
|
||||||
|
/* white-space: pre; */
|
||||||
|
overflow-x: auto;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-code:before {
|
||||||
|
content: attr(data-gutter);
|
||||||
|
position: absolute;
|
||||||
|
background-color: #eee;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
border-right: 1px solid #ccc;
|
||||||
|
padding: 8px;
|
||||||
|
color: #777;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
text-align: right;
|
||||||
|
min-width: 25px;
|
||||||
|
}
|
||||||
|
.editor-code:after {
|
||||||
|
content: attr(data-highlight-language);
|
||||||
|
top: 0;
|
||||||
|
right: 3px;
|
||||||
|
padding: 3px;
|
||||||
|
font-size: 10px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
position: absolute;
|
||||||
|
color: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-tokenComment {
|
||||||
|
color: slategray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-tokenPunctuation {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-tokenProperty {
|
||||||
|
color: #905;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-tokenSelector {
|
||||||
|
color: #690;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-tokenOperator {
|
||||||
|
color: #9a6e3a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-tokenAttr {
|
||||||
|
color: #07a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-tokenVariable {
|
||||||
|
color: #e90;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-tokenFunction {
|
||||||
|
color: #dd4a68;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-paragraph {
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-paragraph:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-heading-h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
color: rgb(5, 5, 5);
|
||||||
|
font-weight: 400;
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-heading-h2 {
|
||||||
|
font-size: 15px;
|
||||||
|
color: rgb(101, 103, 107);
|
||||||
|
font-weight: 700;
|
||||||
|
margin: 0;
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 0;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-quote {
|
||||||
|
margin: 0;
|
||||||
|
margin-left: 20px;
|
||||||
|
font-size: 15px;
|
||||||
|
color: rgb(101, 103, 107);
|
||||||
|
border-left-color: rgb(206, 208, 212);
|
||||||
|
border-left-width: 4px;
|
||||||
|
border-left-style: solid;
|
||||||
|
padding-left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-list-ol {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
margin-left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-list-ul {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
margin-left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-listitem {
|
||||||
|
margin: 8px 32px 8px 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-nested-listitem {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre::-webkit-scrollbar {
|
||||||
|
background: transparent;
|
||||||
|
width: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre::-webkit-scrollbar-thumb {
|
||||||
|
background: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.debug-timetravel-panel {
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0 0 10px 0;
|
||||||
|
margin: auto;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.debug-timetravel-panel-slider {
|
||||||
|
padding: 0;
|
||||||
|
flex: 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.debug-timetravel-panel-button {
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
background: none;
|
||||||
|
flex: 1;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.debug-timetravel-panel-button:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.debug-timetravel-button {
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
top: 10px;
|
||||||
|
right: 15px;
|
||||||
|
position: absolute;
|
||||||
|
background: none;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.debug-timetravel-button:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 1px;
|
||||||
|
background: #fff;
|
||||||
|
padding: 4px;
|
||||||
|
border-top-left-radius: 10px;
|
||||||
|
border-top-right-radius: 10px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar button.toolbar-item {
|
||||||
|
border: 0;
|
||||||
|
display: flex;
|
||||||
|
background: none;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar button.toolbar-item:disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar button.toolbar-item.spaced {
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar button.toolbar-item i.format {
|
||||||
|
background-size: contain;
|
||||||
|
display: inline-block;
|
||||||
|
height: 18px;
|
||||||
|
width: 18px;
|
||||||
|
margin-top: 2px;
|
||||||
|
vertical-align: -0.25em;
|
||||||
|
display: flex;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar button.toolbar-item:disabled i.format {
|
||||||
|
opacity: 0.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar button.toolbar-item.active {
|
||||||
|
background-color: rgba(223, 232, 250, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar button.toolbar-item.active i {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar .toolbar-item:hover:not([disabled]) {
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar .divider {
|
||||||
|
width: 1px;
|
||||||
|
background-color: #eee;
|
||||||
|
margin: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar .toolbar-item .text {
|
||||||
|
display: flex;
|
||||||
|
line-height: 20px;
|
||||||
|
width: 200px;
|
||||||
|
vertical-align: middle;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #777;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
width: 70px;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 20px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar .toolbar-item .icon {
|
||||||
|
display: flex;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
user-select: none;
|
||||||
|
margin-right: 8px;
|
||||||
|
line-height: 16px;
|
||||||
|
background-size: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
i.undo {
|
||||||
|
background-image: url(icons/arrow-counterclockwise.svg);
|
||||||
|
}
|
||||||
|
|
||||||
|
i.redo {
|
||||||
|
background-image: url(icons/arrow-clockwise.svg);
|
||||||
|
}
|
||||||
|
|
||||||
|
i.bold {
|
||||||
|
background-image: url(icons/type-bold.svg);
|
||||||
|
}
|
||||||
|
|
||||||
|
i.italic {
|
||||||
|
background-image: url(icons/type-italic.svg);
|
||||||
|
}
|
||||||
|
|
||||||
|
i.underline {
|
||||||
|
background-image: url(icons/type-underline.svg);
|
||||||
|
}
|
||||||
|
|
||||||
|
i.strikethrough {
|
||||||
|
background-image: url(icons/type-strikethrough.svg);
|
||||||
|
}
|
||||||
|
|
||||||
|
i.left-align {
|
||||||
|
background-image: url(icons/text-left.svg);
|
||||||
|
}
|
||||||
|
|
||||||
|
i.center-align {
|
||||||
|
background-image: url(icons/text-center.svg);
|
||||||
|
}
|
||||||
|
|
||||||
|
i.right-align {
|
||||||
|
background-image: url(icons/text-right.svg);
|
||||||
|
}
|
||||||
|
|
||||||
|
i.justify-align {
|
||||||
|
background-image: url(icons/justify.svg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -7,6 +7,7 @@ import { FieldToggle } from "./TypeToggle";
|
||||||
import { FieldButton } from "./TypeButton";
|
import { FieldButton } from "./TypeButton";
|
||||||
import { FieldRadio } from "./TypeRadio";
|
import { FieldRadio } from "./TypeRadio";
|
||||||
import { FieldCheckbox } from "./TypeCheckbox";
|
import { FieldCheckbox } from "./TypeCheckbox";
|
||||||
|
import { FieldTag } from "./TypeTag";
|
||||||
|
|
||||||
export const MultiOption: FC<{
|
export const MultiOption: FC<{
|
||||||
field: FieldLocal;
|
field: FieldLocal;
|
||||||
|
|
@ -17,10 +18,10 @@ export const MultiOption: FC<{
|
||||||
<>
|
<>
|
||||||
{arg.sub_type === "checkbox" ? (
|
{arg.sub_type === "checkbox" ? (
|
||||||
<FieldCheckbox field={field} fm={fm} arg={arg}/>
|
<FieldCheckbox field={field} fm={fm} arg={arg}/>
|
||||||
) : arg.sub_type === "tag" ? (
|
): arg.sub_type === "button" ? (
|
||||||
<>{arg.sub_type}</>
|
|
||||||
) : arg.sub_type === "button" ? (
|
|
||||||
<FieldButton arg={arg} field={field} fm={fm} />
|
<FieldButton arg={arg} field={field} fm={fm} />
|
||||||
|
): arg.sub_type === "tag" ? (
|
||||||
|
<FieldTag arg={arg} field={field} fm={fm} />
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
import { FC, useEffect } from "react";
|
||||||
|
import { FMLocal, FieldLocal, FieldProp } from "../../typings";
|
||||||
|
import { useLocal } from "@/utils/use-local";
|
||||||
|
import get from "lodash.get";
|
||||||
|
|
||||||
|
export const FieldTag: FC<{
|
||||||
|
field: FieldLocal;
|
||||||
|
fm: FMLocal;
|
||||||
|
arg: FieldProp;
|
||||||
|
}> = ({ field, fm, arg }) => {
|
||||||
|
const local = useLocal({
|
||||||
|
ref: null as any,
|
||||||
|
focus: false as boolean,
|
||||||
|
value: null as any,
|
||||||
|
});
|
||||||
|
let value: any = fm.data[field.name];
|
||||||
|
let tags: Array<string> = typeof value === "string" ? value.split(",") : [];
|
||||||
|
if(isEditor){
|
||||||
|
tags = ["sample","sample"]
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="c-flex-grow c-flex-row c-flex c-w-full c-h-full">
|
||||||
|
<div
|
||||||
|
className={cx(
|
||||||
|
"c-px-2 c-flex c-flex-row c-items-center c-flex-wrap c-flex-grow c-gap-1 c-m-1"
|
||||||
|
)}
|
||||||
|
onClick={() => {
|
||||||
|
if (local.ref) {
|
||||||
|
local.ref.focus();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{tags.map((item) => {
|
||||||
|
return (
|
||||||
|
<div className="c-cursor-text c-flex-row c-flex c-items-center c-text-xs c-font-medium c-rounded c-border c-border-black">
|
||||||
|
<span className="c-flex-grow c-px-2.5 c-py-0.5">{item}</span>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
className="c-px-1 c-border-l c-border-black c-cursor-pointer "
|
||||||
|
viewBox="0 0 40 40"
|
||||||
|
onClick={() => {
|
||||||
|
// delete tag, pakai filter
|
||||||
|
let tag: Array<string> = tags.filter((e) => e !== item) || [];
|
||||||
|
// jadiin value string
|
||||||
|
let value = tags.join(",");
|
||||||
|
fm.data[field.name] = value;
|
||||||
|
fm.render();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M21.499 19.994L32.755 8.727a1.064 1.064 0 0 0-.001-1.502c-.398-.396-1.099-.398-1.501.002L20 18.494L8.743 7.224c-.4-.395-1.101-.393-1.499.002a1.05 1.05 0 0 0-.309.751c0 .284.11.55.309.747L18.5 19.993L7.245 31.263a1.064 1.064 0 0 0 .003 1.503c.193.191.466.301.748.301h.006c.283-.001.556-.112.745-.305L20 21.495l11.257 11.27c.199.198.465.308.747.308a1.058 1.058 0 0 0 1.061-1.061c0-.283-.11-.55-.31-.747z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<input
|
||||||
|
ref={(el) => (local.ref = el)}
|
||||||
|
type={"text"}
|
||||||
|
value={local.value}
|
||||||
|
onClick={() => {}}
|
||||||
|
onChange={(ev) => {
|
||||||
|
local.value = ev.currentTarget.value;
|
||||||
|
local.render();
|
||||||
|
}}
|
||||||
|
onKeyDown={(event) => {
|
||||||
|
if (event.key === "Enter") {
|
||||||
|
event.preventDefault();
|
||||||
|
// detect string kosong
|
||||||
|
if (local.value !== "" && local.value) {
|
||||||
|
// jadiin array atau split
|
||||||
|
let tag: Array<string> = local.value.split(",") || [];
|
||||||
|
// filter tag dari value gk boleh sama
|
||||||
|
tag = tag.filter((e) => !tags.includes(e));
|
||||||
|
// concat
|
||||||
|
tags = tags.concat(tag);
|
||||||
|
// jadiin value string
|
||||||
|
let value = tags.join(",");
|
||||||
|
local.value = "";
|
||||||
|
local.render();
|
||||||
|
fm.data[field.name] = value;
|
||||||
|
fm.render();
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
disabled={field.disabled}
|
||||||
|
className={cx(
|
||||||
|
"c-flex-grow c-flex-1 c-items-center c-bg-transparent c-outline-none c-px-2 c-text-sm",
|
||||||
|
"c-max-w-full"
|
||||||
|
)}
|
||||||
|
spellCheck={false}
|
||||||
|
onFocus={() => {
|
||||||
|
console.log("focus?");
|
||||||
|
}}
|
||||||
|
onBlur={() => {
|
||||||
|
console.log("blur?");
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue