add arrayState Trait

This commit is contained in:
Bowen Tan 2021-09-02 14:37:11 +08:00
parent a2860b1ea9
commit 16f07c20f9
6 changed files with 128 additions and 7 deletions

View File

@ -58,7 +58,7 @@
},
},
{
type: 'core/v1/state',
type: 'core/v1/arrayState',
properties: {
key: 'listData',
initialValue: listdata,
@ -208,10 +208,11 @@
event: 'click',
componentId: 'root',
method: {
name: 'setValue',
name: 'deleteItemById',
parameters: {
key: 'listData',
value: `{{ (root.listData || []).filter((item) => item.id !== $listItem.id)}}`,
itemIdKey: 'id',
itemId: '{{ $listItem.id }}',
},
},
wait: {},

View File

@ -12,7 +12,7 @@ import { ImplWrapper, resolveAppComponents } from '../../App';
import { mapValuesDeep, maskedEval } from '../../store';
import { values } from 'lodash';
import { parseType } from '../../util-methods';
import { LIST_ITEM_EXP } from '../../constants';
import { LIST_ITEM_EXP, LIST_ITEM_INDEX_EXP } from '../../constants';
export function parseTypeComponents(
c: Application['spec']['components'][0]
@ -52,7 +52,10 @@ const List: ComponentImplementation<{
{ parsedtemplete },
({ value, key }) => {
if (typeof value === 'string') {
return maskedEval(value, true, { [LIST_ITEM_EXP]: listItem });
return maskedEval(value, true, {
[LIST_ITEM_EXP]: listItem,
[LIST_ITEM_INDEX_EXP]: i,
});
}
return value;
}

View File

@ -1 +1,2 @@
export const LIST_ITEM_EXP = '$listItem';
export const LIST_ITEM_INDEX_EXP = '$i';

View File

@ -29,6 +29,7 @@ import ChakraUIVStack from './components/chakra-ui/VStack';
/* --- lab --- */
import LabEditor from './components/lab/Editor';
// traits
import CoreArrayState from './traits/core/arrayState';
import CoreState from './traits/core/state';
import CoreEvent from './traits/core/event';
import CoreSlot from './traits/core/slot';
@ -150,6 +151,7 @@ registry.registerComponent(LabEditor);
registry.registerComponent(CoreRouter);
registry.registerTrait(CoreState);
registry.registerTrait(CoreArrayState);
registry.registerTrait(CoreEvent);
registry.registerTrait(CoreSlot);
registry.registerTrait(CoreHidden);

View File

@ -3,7 +3,7 @@ import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import { reactive } from '@vue/reactivity';
import { watch } from '@vue-reactivity/watch';
import { LIST_ITEM_EXP } from './constants';
import { LIST_ITEM_EXP, LIST_ITEM_INDEX_EXP } from './constants';
dayjs.extend(relativeTime);
@ -50,7 +50,11 @@ function parseExpression(str: string, parseListItem = false): ExpChunk[] {
};
// $listItem cannot be evaled in stateStore, so don't mark it as dynamic
// unless explicitly pass parseListItem as true
if (!parseListItem && substr.includes(LIST_ITEM_EXP)) {
if (
(substr.includes(LIST_ITEM_EXP) ||
substr.includes(LIST_ITEM_INDEX_EXP)) &&
!parseListItem
) {
chunk.expression = `{{${substr}}}`;
chunk.isDynamic = false;
}

View File

@ -0,0 +1,110 @@
import { createTrait } from '@meta-ui/core';
import { Static, Type } from '@sinclair/typebox';
import { TraitImplementation } from '../../registry';
import { stateStore } from '../../store';
const HasInitializedMap = new Map<string, boolean>();
type KeyValue = { key: string; value: unknown };
const ArrayStateTrait: TraitImplementation<{
key: Static<typeof KeyPropertySchema>;
initialValue: Static<typeof InitialValuePropertySchema>;
}> = ({ key, initialValue, componentId, mergeState, subscribeMethods }) => {
const hashId = `#${componentId}@${key}`;
let hasInitialized = HasInitializedMap.get(hashId);
if (!hasInitialized) {
mergeState({ [key]: initialValue });
const upperCaseKey = capitalizeFirstLetter(key);
const methods = {
setArray({ key, value }: KeyValue) {
mergeState({ [key]: value });
},
deleteItemByIndex({ key, index }: { key: string; index: number }) {
const _arr = [...stateStore[componentId][key]];
_arr.splice(index, 1);
mergeState({ [key]: _arr });
},
deleteItemById({
key,
itemIdKey,
itemId,
}: {
key: string;
itemIdKey: string;
itemId: string;
}) {
const _arr = [...stateStore[componentId][key]].filter(item => {
return item[itemIdKey] !== itemId;
});
mergeState({ [key]: _arr });
},
};
subscribeMethods(methods);
HasInitializedMap.set(hashId, true);
}
return {
props: null,
};
};
function capitalizeFirstLetter(str: string) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
const KeyPropertySchema = Type.String();
const InitialValuePropertySchema = Type.Array(Type.Any());
export default {
...createTrait({
version: 'core/v1',
metadata: {
name: 'arrayState',
description: 'add array state to component',
},
spec: {
properties: [
{
name: 'key',
...KeyPropertySchema,
},
{
name: 'initialValue',
...InitialValuePropertySchema,
},
],
state: Type.Any(),
methods: [
{
name: 'setArray',
parameters: Type.Object({
key: Type.String(),
value: Type.Array(Type.Any()),
}),
},
{
name: 'deleteItemByIndex',
parameters: Type.Object({
key: Type.String(),
index: Type.Integer(),
}),
},
{
name: 'deleteItemById',
parameters: Type.Object({
key: Type.String(),
itemIdKey: Type.String(),
itemId: Type.String(),
}),
},
{
name: 'reset',
},
],
},
}),
impl: ArrayStateTrait,
};