|
@@ -6,7 +6,6 @@ import { useRect } from '@growi/ui/dist/utils';
|
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
import AutosizeInput from 'react-input-autosize';
|
|
import AutosizeInput from 'react-input-autosize';
|
|
|
|
|
|
|
|
-
|
|
|
|
|
import { getAdjustedMaxWidthForAutosizeInput } from '~/client/components/Common/SubmittableInput';
|
|
import { getAdjustedMaxWidthForAutosizeInput } from '~/client/components/Common/SubmittableInput';
|
|
|
|
|
|
|
|
import { type SelectablePage } from '../../../../interfaces/selectable-page';
|
|
import { type SelectablePage } from '../../../../interfaces/selectable-page';
|
|
@@ -50,26 +49,14 @@ const MethodButton = memo((props: MethodButtonProps) => {
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
-type SelectablePagePageListProps = {
|
|
|
|
|
- pages: SelectablePage[],
|
|
|
|
|
- method: 'add' | 'remove' | 'delete'
|
|
|
|
|
- methodButtonPosition?: 'left' | 'right',
|
|
|
|
|
- disablePagePaths?: string[],
|
|
|
|
|
- isEditable?: boolean,
|
|
|
|
|
- onClickMethodButton: (page: SelectablePage) => void,
|
|
|
|
|
|
|
+type EditablePagePathProps = {
|
|
|
|
|
+ isEditable?: boolean;
|
|
|
|
|
+ page: SelectablePage;
|
|
|
|
|
+ methodButtonPosition?: 'left' | 'right';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export const SelectablePagePageList = (props: SelectablePagePageListProps): JSX.Element => {
|
|
|
|
|
- const {
|
|
|
|
|
- pages,
|
|
|
|
|
- method,
|
|
|
|
|
- methodButtonPosition = 'left',
|
|
|
|
|
- disablePagePaths = [],
|
|
|
|
|
- isEditable,
|
|
|
|
|
- onClickMethodButton,
|
|
|
|
|
- } = props;
|
|
|
|
|
-
|
|
|
|
|
- const { t } = useTranslation();
|
|
|
|
|
|
|
+const EditablePagePath = memo((props: EditablePagePathProps): JSX.Element => {
|
|
|
|
|
+ const { page, isEditable, methodButtonPosition = 'left' } = props;
|
|
|
|
|
|
|
|
const [editingPagePath, setEditingPagePath] = useState<string | null>(null);
|
|
const [editingPagePath, setEditingPagePath] = useState<string | null>(null);
|
|
|
const [inputValue, setInputValue] = useState('');
|
|
const [inputValue, setInputValue] = useState('');
|
|
@@ -78,14 +65,15 @@ export const SelectablePagePageList = (props: SelectablePagePageListProps): JSX.
|
|
|
const editingContainerRef = useRef<HTMLDivElement>(null);
|
|
const editingContainerRef = useRef<HTMLDivElement>(null);
|
|
|
const [editingContainerRect] = useRect(editingContainerRef);
|
|
const [editingContainerRect] = useRect(editingContainerRef);
|
|
|
|
|
|
|
|
- const maxInputWidth = useMemo(() => {
|
|
|
|
|
|
|
+ const isEditing = isEditable && editingPagePath === page.path;
|
|
|
|
|
+
|
|
|
|
|
+ const maxWidth = useMemo(() => {
|
|
|
if (editingContainerRect == null) {
|
|
if (editingContainerRect == null) {
|
|
|
return undefined;
|
|
return undefined;
|
|
|
}
|
|
}
|
|
|
return getAdjustedMaxWidthForAutosizeInput(editingContainerRect.width, 'sm', true);
|
|
return getAdjustedMaxWidthForAutosizeInput(editingContainerRect.width, 'sm', true);
|
|
|
}, [editingContainerRect]);
|
|
}, [editingContainerRect]);
|
|
|
|
|
|
|
|
-
|
|
|
|
|
const handlePagePathClick = useCallback((page: SelectablePage) => {
|
|
const handlePagePathClick = useCallback((page: SelectablePage) => {
|
|
|
if (!isEditable) {
|
|
if (!isEditable) {
|
|
|
return;
|
|
return;
|
|
@@ -104,6 +92,68 @@ export const SelectablePagePageList = (props: SelectablePagePageListProps): JSX.
|
|
|
}
|
|
}
|
|
|
}, [handleInputBlur]);
|
|
}, [handleInputBlur]);
|
|
|
|
|
|
|
|
|
|
+ // Autofocus
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ if (editingPagePath != null && inputRef.current != null) {
|
|
|
|
|
+ inputRef.current.focus();
|
|
|
|
|
+ }
|
|
|
|
|
+ }, [editingPagePath]);
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div
|
|
|
|
|
+ ref={editingContainerRef}
|
|
|
|
|
+ className={`flex-grow-1 ${methodButtonPosition === 'left' ? 'me-2' : 'mx-2'}`}
|
|
|
|
|
+ style={{ minWidth: 0 }}
|
|
|
|
|
+ >
|
|
|
|
|
+ {isEditing
|
|
|
|
|
+ ? (
|
|
|
|
|
+ <AutosizeInput
|
|
|
|
|
+ id="page-path-input"
|
|
|
|
|
+ inputClassName="page-path-input"
|
|
|
|
|
+ type="text"
|
|
|
|
|
+ ref={inputRef}
|
|
|
|
|
+ value={inputValue}
|
|
|
|
|
+ onBlur={handleInputBlur}
|
|
|
|
|
+ onChange={e => setInputValue(e.target.value)}
|
|
|
|
|
+ onKeyDown={handleInputKeyDown}
|
|
|
|
|
+ inputStyle={{ maxWidth }}
|
|
|
|
|
+ />
|
|
|
|
|
+ )
|
|
|
|
|
+ : (
|
|
|
|
|
+ <span
|
|
|
|
|
+ className={`page-path ${isEditable ? 'page-path-editable' : ''}`}
|
|
|
|
|
+ onClick={() => handlePagePathClick(page)}
|
|
|
|
|
+ title={page.path}
|
|
|
|
|
+ >
|
|
|
|
|
+ {page.path}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ );
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+type SelectablePagePageListProps = {
|
|
|
|
|
+ pages: SelectablePage[],
|
|
|
|
|
+ method: 'add' | 'remove' | 'delete'
|
|
|
|
|
+ methodButtonPosition?: 'left' | 'right',
|
|
|
|
|
+ disablePagePaths?: string[],
|
|
|
|
|
+ isEditable?: boolean,
|
|
|
|
|
+ onClickMethodButton: (page: SelectablePage) => void,
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export const SelectablePagePageList = (props: SelectablePagePageListProps): JSX.Element => {
|
|
|
|
|
+ const {
|
|
|
|
|
+ pages,
|
|
|
|
|
+ method,
|
|
|
|
|
+ methodButtonPosition = 'left',
|
|
|
|
|
+ disablePagePaths = [],
|
|
|
|
|
+ isEditable,
|
|
|
|
|
+ onClickMethodButton,
|
|
|
|
|
+ } = props;
|
|
|
|
|
+
|
|
|
|
|
+ const { t } = useTranslation();
|
|
|
|
|
+
|
|
|
const methodButtonIconName = useMemo(() => {
|
|
const methodButtonIconName = useMemo(() => {
|
|
|
switch (method) {
|
|
switch (method) {
|
|
|
case 'add':
|
|
case 'add':
|
|
@@ -130,13 +180,6 @@ export const SelectablePagePageList = (props: SelectablePagePageListProps): JSX.
|
|
|
}
|
|
}
|
|
|
}, [method]);
|
|
}, [method]);
|
|
|
|
|
|
|
|
- // Autofocus
|
|
|
|
|
- useEffect(() => {
|
|
|
|
|
- if (editingPagePath != null && inputRef.current != null) {
|
|
|
|
|
- inputRef.current.focus();
|
|
|
|
|
- }
|
|
|
|
|
- }, [editingPagePath]);
|
|
|
|
|
-
|
|
|
|
|
if (pages.length === 0) {
|
|
if (pages.length === 0) {
|
|
|
return (
|
|
return (
|
|
|
<div className={moduleClass}>
|
|
<div className={moduleClass}>
|
|
@@ -150,7 +193,6 @@ export const SelectablePagePageList = (props: SelectablePagePageListProps): JSX.
|
|
|
return (
|
|
return (
|
|
|
<div className={`list-group ${moduleClass}`}>
|
|
<div className={`list-group ${moduleClass}`}>
|
|
|
{pages.map((page) => {
|
|
{pages.map((page) => {
|
|
|
- const isEditing = isEditable && editingPagePath === page.path;
|
|
|
|
|
return (
|
|
return (
|
|
|
<div
|
|
<div
|
|
|
key={page.path}
|
|
key={page.path}
|
|
@@ -169,35 +211,11 @@ export const SelectablePagePageList = (props: SelectablePagePageListProps): JSX.
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- <div
|
|
|
|
|
- ref={editingContainerRef}
|
|
|
|
|
- className={`flex-grow-1 ${methodButtonPosition === 'left' ? 'me-2' : 'mx-2'}`}
|
|
|
|
|
- style={{ minWidth: 0 }}
|
|
|
|
|
- >
|
|
|
|
|
- {isEditing
|
|
|
|
|
- ? (
|
|
|
|
|
- <AutosizeInput
|
|
|
|
|
- id="page-path-input"
|
|
|
|
|
- inputClassName="page-path-input"
|
|
|
|
|
- type="text"
|
|
|
|
|
- ref={inputRef}
|
|
|
|
|
- value={inputValue}
|
|
|
|
|
- onBlur={handleInputBlur}
|
|
|
|
|
- onChange={e => setInputValue(e.target.value)}
|
|
|
|
|
- onKeyDown={handleInputKeyDown}
|
|
|
|
|
- inputStyle={{ maxWidth: maxInputWidth }}
|
|
|
|
|
- />
|
|
|
|
|
- )
|
|
|
|
|
- : (
|
|
|
|
|
- <span
|
|
|
|
|
- className={`page-path ${isEditable ? 'page-path-editable' : ''}`}
|
|
|
|
|
- onClick={() => handlePagePathClick(page)}
|
|
|
|
|
- title={page.path}
|
|
|
|
|
- >
|
|
|
|
|
- {page.path}
|
|
|
|
|
- </span>
|
|
|
|
|
- )}
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <EditablePagePath
|
|
|
|
|
+ page={page}
|
|
|
|
|
+ isEditable={isEditable}
|
|
|
|
|
+ methodButtonPosition={methodButtonPosition}
|
|
|
|
|
+ />
|
|
|
|
|
|
|
|
<span className={`badge bg-body-secondary rounded-pill ${methodButtonPosition === 'left' ? 'me-2' : ''}`}>
|
|
<span className={`badge bg-body-secondary rounded-pill ${methodButtonPosition === 'left' ? 'me-2' : ''}`}>
|
|
|
<span className="text-body-tertiary">
|
|
<span className="text-body-tertiary">
|