Skip to content

Commit

Permalink
fix(array-x): upgrade sortable related function & fix array-items
Browse files Browse the repository at this point in the history
  • Loading branch information
prgrmrwy committed Jul 19, 2024
1 parent 146215a commit cdd93a5
Show file tree
Hide file tree
Showing 11 changed files with 476 additions and 218 deletions.
7 changes: 4 additions & 3 deletions packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@
"typings": "lib/index.d.ts",
"scripts": {
"build": "formily-tpl build",
"start": "dumi dev",
"release": "npm run build && npm version patch -m 'chore: publish release [patch]' && npm publish"
"release": "npm run build && npm version patch -m 'chore: publish release [patch]' && npm publish",
"start": "dumi dev"
},
"dependencies": {
"@dnd-kit/core": "^6.0.0",
"@dnd-kit/sortable": "^7.0.0",
"dayjs": "^1.10.7",
"react-sortable-hoc": "^2.0.0",
"react-sticky-box": "^0.9.3"
},
"devDependencies": {
Expand Down
1 change: 1 addition & 0 deletions packages/components/src/__builtins__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from "./moment";
export * from "./pickDataProps";
export * from "./portal";
export * from "./loading";
export * from "./sort";
143 changes: 143 additions & 0 deletions packages/components/src/__builtins__/sort.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { DndContext, DragEndEvent, DragStartEvent } from "@dnd-kit/core";
import {
SortableContext,
useSortable,
verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import { ReactFC } from "@formily/reactive-react";
import React, { createContext, useContext, useMemo } from "react";

export interface ISortableContainerProps {
list: any[];
start?: number;
accessibility?: {
container?: Element;
};
onSortStart?: (event: DragStartEvent) => void;
onSortEnd?: (event: { oldIndex: number; newIndex: number }) => void;
}

export function SortableContainer<T extends React.HTMLAttributes<HTMLElement>>(
Component: ReactFC<T>
): ReactFC<ISortableContainerProps & T> {
return ({
list,
start = 0,
accessibility,
onSortStart,
onSortEnd,
...props
}) => {
const _onSortEnd = (event: DragEndEvent) => {
const { active, over } = event;
const oldIndex = (active.id as number) - 1;
const newIndex = (over?.id as number) - 1;
onSortEnd?.({
oldIndex,
newIndex,
});
};

return (
<DndContext
accessibility={accessibility}
onDragStart={onSortStart}
onDragEnd={_onSortEnd}
>
<SortableContext
items={list.map((_, index) => index + start + 1)}
strategy={verticalListSortingStrategy}
>
<Component {...(props as unknown as T)}>{props.children}</Component>
</SortableContext>
</DndContext>
);
};
}

export const useSortableItem = () => {
return useContext(SortableItemContext);
};

export const SortableItemContext = createContext<
Partial<ReturnType<typeof useSortable>>
>({});

export interface ISortableElementProps {
index?: number;
lockAxis?: "x" | "y";
}

export function SortableElement<T extends React.HTMLAttributes<HTMLElement>>(
Component: ReactFC<T>
): ReactFC<T & ISortableElementProps> {
return ({ index = 0, lockAxis, ...props }) => {
const sortable = useSortable({
id: index + 1,
});
const { setNodeRef, transform, transition, isDragging } = sortable;
if (transform) {
switch (lockAxis) {
case "x":
transform.y = 0;
break;
case "y":
transform.x = 0;
break;
default:
break;
}
}

const style = useMemo(() => {
const itemStyle: React.CSSProperties = {
position: "relative",
touchAction: "none",
zIndex: 1,
transform: `translate3d(${transform?.x || 0}px, ${
transform?.y || 0
}px, 0)`,
transition: `${transform ? "all 200ms ease" : ""}`,
};
const dragStyle: React.CSSProperties = {
transition,
opacity: "0.8",
transform: `translate3d(${transform?.x || 0}px, ${
transform?.y || 0
}px, 0)`,
};

const computedStyle = isDragging
? {
...itemStyle,
...dragStyle,
...props.style,
}
: {
...itemStyle,
...props.style,
};

return computedStyle;
}, [isDragging, transform, transition, props.style]);

return (
<SortableItemContext.Provider value={sortable}>
{Component({
...props,
style,
ref: setNodeRef,
} as unknown as T)}
</SortableItemContext.Provider>
);
};
}

export function SortableHandle<T extends React.HTMLAttributes<HTMLElement>>(
Component: ReactFC<T>
): ReactFC<T> {
return (props: T) => {
const { attributes, listeners } = useSortableItem();
return <Component {...props} {...attributes} {...listeners} />;
};
}
15 changes: 7 additions & 8 deletions packages/components/src/array-base/index.scss
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
@import '../__styles__/theme.scss';

$array-base-prefix-cls: '#{$semi-form-prefix}-array-base';
@import "../__styles__/theme.scss";

$array-base-prefix-cls: "#{$semi-form-prefix}-array-base";

.#{$array-base-prefix-cls}-remove {
transition: all .25s ease-in-out;
transition: all 0.25s ease-in-out;
font-size: 16px;
cursor: pointer;

Expand All @@ -13,17 +12,17 @@ $array-base-prefix-cls: '#{$semi-form-prefix}-array-base';
}
}

.#{array-base-prefix-cls}-sort-handle {
.#{$array-base-prefix-cls}-sort-handle {
cursor: move;
color: #888 !important;
}

.#{$array-base-prefix-cls}-addition {
transition: all .25s ease-in-out;
transition: all 0.25s ease-in-out;
}

.#{$array-base-prefix-cls}-move-down {
transition: all .25s ease-in-out;
transition: all 0.25s ease-in-out;
font-size: 16px;
margin-left: 6px;

Expand All @@ -33,7 +32,7 @@ $array-base-prefix-cls: '#{$semi-form-prefix}-array-base';
}

.#{$array-base-prefix-cls}-move-up {
transition: all .25s ease-in-out;
transition: all 0.25s ease-in-out;
font-size: 16px;
margin-left: 6px;

Expand Down
75 changes: 37 additions & 38 deletions packages/components/src/array-base/index.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
import React, { createContext, useContext } from 'react';
import { Button } from '@douyinfe/semi-ui';
import React, { createContext, useContext } from "react";
import { Button } from "@douyinfe/semi-ui";
import { ButtonProps } from "@douyinfe/semi-ui/lib/es/button";
import {
IconPlus,
IconDelete,
IconMenu,
IconChevronDown,
IconChevronUp
} from '@douyinfe/semi-icons';
IconChevronUp,
} from "@douyinfe/semi-icons";
import { IconProps as SemiIconProps } from "@douyinfe/semi-ui/lib/es/icons";
import { useField, useFieldSchema, Schema, JSXComponent } from '@formily/react';
import { ArrayField } from '@formily/core';
import { isValid } from '@formily/shared';
import { SortableHandle } from 'react-sortable-hoc';
import cls from 'classnames';
import { useField, useFieldSchema, Schema, JSXComponent } from "@formily/react";
import { ArrayField } from "@formily/core";
import { isValid } from "@formily/shared";
import cls from "classnames";

import './index.scss';
import { usePrefixCls } from '../__builtins__';
import "./index.scss";
import { usePrefixCls, SortableHandle } from "../__builtins__";

interface IconProps extends SemiIconProps {
style?: React.CSSProperties;
Expand All @@ -25,7 +24,7 @@ interface IconProps extends SemiIconProps {

export interface IArrayBaseAdditionProps extends ButtonProps {
title?: string;
method?: 'push' | 'unshift';
method?: "push" | "unshift";
}

export interface IArrayBaseProps {
Expand Down Expand Up @@ -57,7 +56,7 @@ export type ArrayBaseMixins = {
Index?: React.FC;
useArray?: () => IArrayBaseContext;
useIndex?: () => number;
useRecord?: (record?: number) => any
useRecord?: (record?: number) => any;
};

type ComposedArrayBase = React.FC<React.PropsWithChildren<IArrayBaseProps>> &
Expand All @@ -78,21 +77,21 @@ const useIndex = (index?: number) => {
};

const useRecord = (record?: number) => {
const ctx = useContext(ItemContext)
return ctx ? ctx.record : record
}
const ctx = useContext(ItemContext);
return ctx ? ctx.record : record;
};

const getDefaultValue = (defaultValue: any, schema: Schema) => {
if (isValid(defaultValue)) return defaultValue;
if (Array.isArray(schema?.items))
return getDefaultValue(defaultValue, schema.items[0]);
if (schema?.items?.type === 'array') return [];
if (schema?.items?.type === 'boolean') return true;
if (schema?.items?.type === 'date') return '';
if (schema?.items?.type === 'datetime') return '';
if (schema?.items?.type === 'number') return 0;
if (schema?.items?.type === 'object') return {};
if (schema?.items?.type === 'string') return '';
if (schema?.items?.type === "array") return [];
if (schema?.items?.type === "boolean") return true;
if (schema?.items?.type === "date") return "";
if (schema?.items?.type === "datetime") return "";
if (schema?.items?.type === "number") return 0;
if (schema?.items?.type === "object") return {};
if (schema?.items?.type === "string") return "";
return null;
};

Expand All @@ -111,27 +110,27 @@ ArrayBase.Item = ({ children, ...props }: any) => (
);

const SortHandle = SortableHandle((props: any) => {
const prefixCls = usePrefixCls('array-base')
const prefixCls = usePrefixCls("array-base");
return (
<IconMenu
{...props}
className={cls(`${prefixCls}-sort-handle`, props.className)}
style={{ ...props.style }}
/>
)
}) as any
);
}) as any;

ArrayBase.SortHandle = (props) => {
const array = useArray();
if (!array) return null;
if (array.field?.pattern !== 'editable') return null;
if (array.field?.pattern !== "editable") return null;
return <SortHandle {...props} />;
};

const Index = (props) => {
const { renderIndex } = props;
const index = useIndex();
const prefixCls = usePrefixCls('array-base');
const prefixCls = usePrefixCls("array-base");
return (
<span {...props} className={`${prefixCls}-index`}>
{renderIndex?.(index) ?? `#${index + 1}.`}
Expand All @@ -144,11 +143,11 @@ ArrayBase.Index = Index;
const Addition = (props) => {
const self = useField();
const array = useArray();
const prefixCls = usePrefixCls('array-base');
const prefixCls = usePrefixCls("array-base");
if (!array) return null;
if (
array?.field?.pattern !== 'editable' &&
array?.field?.pattern !== 'disabled'
array?.field?.pattern !== "editable" &&
array?.field?.pattern !== "disabled"
) {
return null;
}
Expand All @@ -161,7 +160,7 @@ const Addition = (props) => {
onClick={(e) => {
if (array.props?.disabled) return;
const defaultValue = getDefaultValue(props.defaultValue, array.schema);
if (props.method === 'unshift') {
if (props.method === "unshift") {
array?.field?.unshift(defaultValue);
array.props?.onAdd?.(0);
} else {
Expand All @@ -184,9 +183,9 @@ ArrayBase.Addition = Addition;
ArrayBase.Remove = React.forwardRef((props, ref) => {
const index = useIndex();
const array = useArray();
const prefixCls = usePrefixCls('array-base');
const prefixCls = usePrefixCls("array-base");
if (!array) return null;
if (array?.field?.pattern !== 'editable') return null;
if (array?.field?.pattern !== "editable") return null;
return (
<IconDelete
{...props}
Expand All @@ -208,8 +207,8 @@ ArrayBase.Remove = React.forwardRef((props, ref) => {
ArrayBase.MoveDown = React.forwardRef((props, ref) => {
const index = useIndex(props.index);
const array = useArray();
const prefixCls = usePrefixCls('array-base-move-down');
if (array?.field?.pattern !== 'editable') return null;
const prefixCls = usePrefixCls("array-base-move-down");
if (array?.field?.pattern !== "editable") return null;
return (
<IconChevronDown
{...props}
Expand All @@ -231,8 +230,8 @@ ArrayBase.MoveDown = React.forwardRef((props, ref) => {
ArrayBase.MoveUp = React.forwardRef((props, ref) => {
const index = useIndex(props.index);
const array = useArray();
const prefixCls = usePrefixCls('array-base-move-up');
if (array?.field?.pattern !== 'editable') return null;
const prefixCls = usePrefixCls("array-base-move-up");
if (array?.field?.pattern !== "editable") return null;
return (
<IconChevronUp
{...props}
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/array-items/index.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@import "../__styles__/theme.scss";

$semi-items-prefix-cls: "#{$semi-form-prefix}formily-array-items";
$semi-items-prefix-cls: "#{$semi-form-prefix}-formily-array-items";

.#{$semi-items-prefix-cls}-item-inner {
visibility: visible;
Expand Down
Loading

0 comments on commit cdd93a5

Please sign in to comment.