UNPKG

@spaceone/design-system

Version:
339 lines (321 loc) • 11.3 kB
import { Meta, Canvas, Story, ArgsTable } from '@storybook/addon-docs/blocks'; import PTree from './PTree.vue'; import PI from '@/foundation/icons/PI.vue' import PIconButton from '@/inputs/buttons/icon-button/PIconButton.vue' import PButton from '@/inputs/buttons/button/PButton.vue' import PTextInput from '@/inputs/input/PTextInput.vue'; import PRadio from '@/inputs/radio/PRadio.vue' import { reactive, toRefs, computed } from '@vue/composition-api'; import {getTreeList, getTreeData, getTreeNode, getRecursiveInfo, getPermissionInfo} from './mock'; import faker from 'faker'; import './PTree.stories.pcss' <Meta title='Data Display/Tree' component={PTree} argTypes={{ editOptions: { name: 'editOptions', type: {name: `object`}, description: `Options for inline edit.`, defaultValue: {}, table: { type: { summary: 'object' }, defaultValue: { summary: '{}' }, category: 'props' }, control: { type: 'object' } }, }} /> export const ExpertTemplate = (args, { argTypes }) => ({ components: { PTree, PButton, PTextInput, PI, PIconButton, PRadio }, template: ` <div class="h-full w-full p-4 overflow-auto"> <div class="mb-4"> <p-button style-type="primary1" @click="refresh">Refresh</p-button> <p-button style-type="secondary" @click="add">Add node to root</p-button> <p-button style-type="safe" @click="onClickEdit"> {{editMode ? 'Done' : 'Edit' }} </p-button> <p-button style-type="primary" @click="find">Find node</p-button> <div class="mt-4"> <p-text-input v-model="target"/> <p-button style-type="secondary1" @click="fetchAndFind">Fetch and find node</p-button> </div> <div class="mt-4"> <p-text-input v-model="editText"/> <p-button style-type="alert" @click="updateData">Update selected node</p-button> </div> </div> <p-tree :edit-options="editOptions" :drag-options="dragOptions" :select-options="selectOptions" :toggle-options="toggleOptions" :data-getter="dataGetter" :data-setter="dataSetter" :data-fetcher="dataFetcher" :get-class-names="getClassNames" @init="onInit" @change-select="onChangeSelect" @start-drag="onStartDrag" @update-drag="onUpdateDrag" @end-drag="onEndDrag" > <template #data="{node}"> {{ node.data.name }} ({{node.data.id}}) </template> <template #toggle="{node, path, selected}"> <p-radio v-if="node.data.item_type === 'PROJECT'" :selected="selected" :value="true" @click.stop="changeSelectState(node, path)" /> </template> <template #toggle-right> <p-i name="ic_bookmark" width="1rem" height="1rem" color="inherit" /> </template> <template #icon="{node}"> <template v-if="editMode"> <p-i v-if="node.data.item_type === 'PROJECT_GROUP'" :name="permissionInfo[node.data.id] ? 'ic_tree_project-group' : 'ic_tree_project-group_locked'" width="1rem" height="1rem" color="inherit" /> </template> <p-i v-else :name="node.data.item_type === 'PROJECT' ? 'ic_tree_project' : 'ic_tree_project-group'" width="1rem" height="1rem" color="inherit transparent" /> </template> <template #right-extra="{node, path}"> <p-icon-button v-if="editMode && permissionInfo[node.data.id]" name="ic_minus" color="inherit transparent" size="sm" @click.stop="deleteNode(path)" /> <p-icon-button v-else name="ic_plus" class="add-btn" size="sm" @click.stop="addNode(path, getTreeData())" /> </template> </p-tree> </div> `, setup() { const state = reactive({ editOptions: computed(() => ({ disabled: !state.editMode, editStartValidator: ({ data }) => { return !!state.permissionInfo[data.id] }, validator: (text) => (text && text.length > 2 && text.length < 40), })), dragOptions: computed(() => ({ disabled: !state.editMode, dragValidator(node, parent) { return !!state.permissionInfo[node.data.id] }, dropValidator(node, parent) { if (state.dragParentNode === parent) return true; return !!state.permissionInfo[parent?.data?.id] } })), editMode: false, permissionInfo: {}, target: '', findMode: false, lists: [], listIdx: 0, editText: '', selectedItem: {}, dragNode: null, dragParentNode: null }) const selectOptions = { validator({data}) { if (data.item_type !== 'PROJECT') return false; return state.editMode ? !!state.permissionInfo[data.id] : true }, visibleRado: true } const toggleOptions = { validator: (node) => { return node.data.has_child || node.children.length > 0 } } const getClassNames = ({ data }) => { return {'no-permission': state.editMode && !state.permissionInfo[data.id]} } const dataSetter = (text, node) => { node.data.name = text } const dataGetter = (node) => { return node.data.name } const dataFetcher = (node) => { return new Promise((resolve, reject) => { setTimeout(() => { let res; if (state.findMode) { res = state.lists[state.listIdx++] } else { res = getTreeList() } if (state.editMode) { res.forEach(d => {state.permissionInfo[d.id] = faker.random.boolean();}) } resolve(res) }, 500) }) } const refresh = async () => { if (state.root) { state.root.resetSelect() await state.root.fetchData() } } const onClickEdit = () => { const all = state.root.getAllNodes() state.permissionInfo = {} all.forEach((d) => {state.permissionInfo[d.data.id] = faker.random.boolean();}) state.editMode = !state.editMode; } const onInit = async (root) => { state.root = root } const add = () => { if (state.root) state.root.addNode(getTreeData()) } const find = () => { if (state.root) state.root.findNode((data) => data.name === state.target) } const fetchAndFind = async () => { const {lists, names} = getRecursiveInfo() state.findMode = true; state.lists = lists; state.listIdx = 0; const predicates = names.map(d => (data) => { return data.name === d }) state.target = names[names.length - 1]; if (state.root) { await state.root.fetchAndFindNode(predicates); } state.findMode = false; } const deleteNode = (path) => { state.root.deleteNodeByPath(path) } const addNode = (path, data) => { state.root.addChildNodeByPath(path, data) } const updateData = () => { if (state.root && state.selectedItem.node) { state.root.updateNodeByPath(state.selectedItem.path, { ...state.selectedItem.node.data, name: state.editText }) } } const onChangeSelect = (node, path) => { state.selectedItem = node ? {node, path} : {} state.editText = node? node.data.name : '' } const onStartDrag = (node, parent) => { console.debug('start drag', node, parent) state.dragNode = node state.dragParentNode = parent } const onUpdateDrag = (node, parent) => { console.debug('update drag', node, parent) } const onEndDrag = (node, parent) => { console.debug('end drag', node, parent) state.dragNode = null state.dragParentNode = null } const changeSelectState = (node, path) => { state.root.changeSelectState(node, path) } return { ...toRefs(state), selectOptions, toggleOptions, getClassNames, dataSetter, dataGetter, dataFetcher, refresh, onClickEdit, onInit, add, find, fetchAndFind, getTreeData, deleteNode, addNode, updateData, onChangeSelect, onStartDrag, onUpdateDrag, onEndDrag, changeSelectState } } }); export const Template = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { PTree }, template: ` <div class="h-full w-full p-4 overflow-auto"> <div class="mb-4"> </div> <p-tree :data-fetcher="treeDataFetcher"> </p-tree> </div> `, setup() { const treeDataFetcher = () => { return ['A1', 'A2', 'A3'] } return { treeDataFetcher, } } }); # Tree <br/> <br/> ## Basic <br/> <br/> <Canvas> <Story name="Basic"> {Template.bind({})} </Story> </Canvas> <br/> <br/> ## Expert <br/> <br/> <Canvas> <Story name="Expert"> {ExpertTemplate.bind({})} </Story> </Canvas> <br/> <br/> ## Playground <Canvas> <Story name="Playground"> {Template.bind({})} </Story> </Canvas> <ArgsTable story="Playground"/>