import * as React from "react"; import { CommonSelection, CommonValue, commonElement } from "./common"; import { Button } from "../ui/Button"; import type { ElementOperation } from "./ElementOperation"; import { css } from "@emotion/css"; import { normalizeSearchText } from "../../common/searchText"; import { useOneLineTextEditor } from "../ui/OneLineTextEditor"; export type ListSelection = { readonly index: number; readonly selection: CommonSelection | undefined; }; export type ListValue = { readonly items: ReadonlyArray; readonly isDirectionColumn?: boolean; readonly deleteAll?: () => void; readonly deleteAt?: (index: number) => void; readonly addInLast?: () => void; }; export type ListItem = { readonly commonValue: CommonValue; /** 検索で使用するテキスト */ readonly searchText: string; }; /** * Editor の list の1つの要素 * @param commonValue 値. 共通であつかえる * @param searchText 検索で使われるテキスト */ export const listItem = ( commonValue: CommonValue, searchText: string ): ListItem => ({ commonValue, searchText, }); const moveUp = (selection: ListSelection, value: ListValue): ListSelection => { const item = value.items[selection.index]; if (selection.selection === undefined || item === undefined) { const nextIndex = Math.min(selection.index - 1, value.items.length - 1); if (nextIndex < 0) { return { index: value.items.length - 1, selection: undefined, }; } return { index: nextIndex, selection: undefined }; } return { index: selection.index, selection: commonElement.moveUp(selection.selection, item.commonValue), }; }; const moveDown = ( selection: ListSelection, value: ListValue ): ListSelection => { const item = value.items[selection.index]; if (selection.selection === undefined || item === undefined) { const nextIndex = selection.index + 1; if (value.items.length - 1 < nextIndex) { return { index: 0, selection: undefined, }; } return { index: nextIndex, selection: undefined }; } return { index: selection.index, selection: commonElement.moveDown(selection.selection, item.commonValue), }; }; const moveFirstChild = ( selection: ListSelection | undefined, value: ListValue ): ListSelection | undefined => { if (selection === undefined) { if (value.items.length > 0) { return { index: 0, selection: undefined, }; } return undefined; } const item = value.items[selection.index]; if (item === undefined) { return undefined; } return { index: selection.index, selection: commonElement.moveFirstChild( selection.selection, item.commonValue ), }; }; const moveParent: ElementOperation["moveParent"] = ( selection, value ) => { const item = value.items[selection.index]; if (selection.selection === undefined || item === undefined) { return undefined; } return { index: selection.index, selection: commonElement.moveParent(selection.selection, item.commonValue), }; }; const ListSelectionView: ElementOperation< ListSelection, ListValue >["selectionView"] = React.memo((props) => { const { text: searchQueryText, element } = useOneLineTextEditor({ id: "search", initText: "", }); const normalizedSearchQueryText = normalizeSearchText(searchQueryText); return (
{element()}
{searchQueryText === "" ? ( <> ) : (
{normalizedSearchQueryText} でフィルター中
)}
{props.value.items.flatMap((v, index) => { if ( normalizeSearchText(v.searchText).includes( normalizedSearchQueryText ) ) { return [ , ]; } return []; })} {props.value.addInLast === undefined ? ( <> ) : ( )}
); }); ListSelectionView.displayName = "ListSelectionView"; const getListItemSelection = ( listSelection: ListSelection | undefined, index: number ): ListItemSelection => { if (listSelection === undefined || listSelection.index !== index) { return "none"; } if (listSelection.selection === undefined) { return "self"; } return listSelection.selection; }; type ListItemSelection = CommonSelection | "none" | "self"; const SelectionItem: React.VFC<{ index: number; onChangeSelection: (listSelection: ListSelection) => void; selection: ListItemSelection; value: CommonValue; deleteAt: ((index: number) => void) | undefined; }> = React.memo(({ index, onChangeSelection, selection, value, deleteAt }) => { const onFocus = React.useCallback( (event: React.FocusEvent): void => { event.stopPropagation(); event.preventDefault(); onChangeSelection({ index, selection: undefined, }); }, [index, onChangeSelection] ); const onChangeItemSelection = React.useCallback( (s: CommonSelection) => { onChangeSelection({ index, selection: s, }); }, [index, onChangeSelection] ); const onClickDelete = React.useCallback(() => { if (deleteAt !== undefined) { deleteAt(index); } }, [index, deleteAt]); return (
{deleteAt === undefined ? ( <> ) : ( )}
); }); SelectionItem.displayName = "SelectionItem"; const ListDetailView: ElementOperation["detailView"] = React.memo((props) => { if (props.selection === undefined) { return (
要素数: {props.value.items.length}
{props.value.deleteAll === undefined ? ( <> ) : ( )} {props.value.addInLast === undefined ? ( <> ) : ( )}
); } const index = props.selection.index; const item = props.value.items[index]; if (item === undefined) { return
存在しないインデックスを指定している
; } if (props.selection.selection === undefined) { return (
リストインデックス: {index}
); } return ( ); }); ListDetailView.displayName = "ListDetailView"; export const listOperation: ElementOperation = { moveUp, moveDown, moveFirstChild, moveParent, selectionView: ListSelectionView, detailView: ListDetailView, };