add MkGrid.stories.impl.ts
This commit is contained in:
parent
5a2b11ec17
commit
098cf397b9
|
@ -0,0 +1,95 @@
|
|||
/**
|
||||
* AIで生成した無作為なファーストネーム
|
||||
*/
|
||||
export const firstNameDict: string = [
|
||||
'Ethan', 'Olivia', 'Jackson', 'Emma', 'Liam', 'Ava', 'Aiden', 'Sophia', 'Mason', 'Isabella',
|
||||
'Noah', 'Mia', 'Lucas', 'Harper', 'Caleb', 'Abigail', 'Samuel', 'Emily', 'Logan',
|
||||
'Madison', 'Benjamin', 'Chloe', 'Elijah', 'Grace', 'Alexander', 'Scarlett', 'William', 'Zoey', 'James', 'Lily',
|
||||
]
|
||||
|
||||
/**
|
||||
* AIで生成した無作為なラストネーム
|
||||
*/
|
||||
export const lastNameDict: string = [
|
||||
'Anderson', 'Johnson', 'Thompson', 'Davis', 'Rodriguez', 'Smith', 'Patel', 'Williams', 'Lee', 'Brown',
|
||||
'Garcia', 'Jackson', 'Martinez', 'Taylor', 'Harris', 'Nguyen', 'Miller', 'Jones', 'Wilson',
|
||||
'White', 'Thomas', 'Garcia', 'Martinez', 'Robinson', 'Turner', 'Lewis', 'Hall', 'King', 'Baker', 'Cooper',
|
||||
]
|
||||
|
||||
/**
|
||||
* AIで生成した無作為な国名
|
||||
*/
|
||||
export const countryDict: string = [
|
||||
'Japan', 'Canada', 'Brazil', 'Australia', 'Italy', 'SouthAfrica', 'Mexico', 'Sweden', 'Russia', 'India',
|
||||
'Germany', 'Argentina', 'South Korea', 'France', 'Nigeria', 'Turkey', 'Spain', 'Egypt', 'Thailand',
|
||||
'Vietnam', 'Kenya', 'Saudi Arabia', 'Netherlands', 'Colombia', 'Poland', 'Chile', 'Malaysia', 'Ukraine', 'New Zealand', 'Peru',
|
||||
]
|
||||
|
||||
export function text(length: number = 10): string {
|
||||
let result = "";
|
||||
|
||||
while (result.length < length) {
|
||||
result += Math.random().toString(36).substring(2);
|
||||
}
|
||||
|
||||
return result.substring(0, length);
|
||||
}
|
||||
|
||||
export function integer(min: number = 0, max: number = 9999): number {
|
||||
return Math.floor(Math.random() * (max - min)) + min;
|
||||
}
|
||||
|
||||
export function date(params?: {
|
||||
yearMin?: number,
|
||||
yearMax?: number,
|
||||
monthMin?: number,
|
||||
monthMax?: number,
|
||||
dayMin?: number,
|
||||
dayMax?: number,
|
||||
hourMin?: number,
|
||||
hourMax?: number,
|
||||
minuteMin?: number,
|
||||
minuteMax?: number,
|
||||
secondMin?: number,
|
||||
secondMax?: number,
|
||||
millisecondMin?: number,
|
||||
millisecondMax?: number,
|
||||
}) {
|
||||
const year = integer(params?.yearMin ?? 1970, params?.yearMax ?? (new Date()).getFullYear());
|
||||
const month = integer(params?.monthMin ?? 1, params?.monthMax ?? 12);
|
||||
let day = integer(params?.dayMin ?? 1, params?.dayMax ?? 31);
|
||||
if (month === 2) {
|
||||
day = Math.min(day, 28);
|
||||
} else if ([4, 6, 9, 11].includes(month)) {
|
||||
day = Math.min(day, 30);
|
||||
} else {
|
||||
day = Math.min(day, 31);
|
||||
}
|
||||
|
||||
const hour = integer(params?.hourMin ?? 0, params?.hourMax ?? 23);
|
||||
const minute = integer(params?.minuteMin ?? 0, params?.minuteMax ?? 59);
|
||||
const second = integer(params?.secondMin ?? 0, params?.secondMax ?? 59);
|
||||
const millisecond = integer(params?.millisecondMin ?? 0, params?.millisecondMax ?? 999);
|
||||
|
||||
return new Date(year, month - 1, day, hour, minute, second, millisecond);
|
||||
}
|
||||
|
||||
export function boolean(): boolean {
|
||||
return Math.random() < 0.5;
|
||||
}
|
||||
|
||||
export function choose<T>(array: T[]): T {
|
||||
return array[Math.floor(Math.random() * array.length)];
|
||||
}
|
||||
|
||||
export function firstName(): string {
|
||||
return firstNameDict[Math.floor(Math.random() * firstNameDict.length)];
|
||||
}
|
||||
|
||||
export function lastName(): string {
|
||||
return lastNameDict[Math.floor(Math.random() * lastNameDict.length)];
|
||||
}
|
||||
|
||||
export function country(): string {
|
||||
return countryDict[Math.floor(Math.random() * countryDict.length)];
|
||||
}
|
|
@ -411,6 +411,7 @@ function toStories(component: string): Promise<string> {
|
|||
glob('src/components/MkInviteCode.vue'),
|
||||
glob('src/components/MkTagItem.vue'),
|
||||
glob('src/components/MkRoleSelectDialog.vue'),
|
||||
glob('src/components/grid/MkGrid.vue'),
|
||||
glob('src/pages/user/home.vue'),
|
||||
]);
|
||||
const components = globs.flat();
|
||||
|
|
|
@ -22,6 +22,12 @@
|
|||
<div v-if="cellType === 'text'">
|
||||
{{ cell.value }}
|
||||
</div>
|
||||
<div v-if="cellType === 'number'">
|
||||
{{ cell.value }}
|
||||
</div>
|
||||
<div v-if="cellType === 'date'">
|
||||
{{ cell.value }}
|
||||
</div>
|
||||
<div v-else-if="cellType === 'boolean'">
|
||||
<span v-if="cell.value === true" class="ti ti-check"/>
|
||||
<span v-else class="ti"/>
|
||||
|
@ -46,6 +52,24 @@
|
|||
@mousedown.stop
|
||||
@contextmenu.stop
|
||||
/>
|
||||
<input
|
||||
v-if="cellType === 'number'"
|
||||
type="number"
|
||||
:class="$style.editingInput"
|
||||
:value="editingValue"
|
||||
@input="onInputText"
|
||||
@mousedown.stop
|
||||
@contextmenu.stop
|
||||
/>
|
||||
<input
|
||||
v-if="cellType === 'date'"
|
||||
type="date"
|
||||
:class="$style.editingInput"
|
||||
:value="editingValue"
|
||||
@input="onInputText"
|
||||
@mousedown.stop
|
||||
@contextmenu.stop
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
@ -185,6 +209,8 @@ async function beginEditing(target: HTMLElement) {
|
|||
rootEl.value?.focus();
|
||||
} else {
|
||||
switch (cellType.value) {
|
||||
case 'number':
|
||||
case 'date':
|
||||
case 'text': {
|
||||
editingValue.value = cell.value.value;
|
||||
editing.value = true;
|
||||
|
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { StoryObj } from '@storybook/vue3';
|
||||
import { ref } from 'vue';
|
||||
import { commonHandlers } from '../../../.storybook/mocks.js';
|
||||
import { boolean, choose, country, date, firstName, integer, lastName, text } from '../../../.storybook/fake-utils.js';
|
||||
import MkGrid from './MkGrid.vue';
|
||||
import { GridContext, GridEvent } from '@/components/grid/grid-event.js';
|
||||
import { DataSource, GridSetting } from '@/components/grid/grid.js';
|
||||
|
||||
function d(p: {
|
||||
check?: boolean,
|
||||
name?: string,
|
||||
email?: string,
|
||||
age?: number,
|
||||
birthday?: string,
|
||||
gender?: string,
|
||||
country?: string,
|
||||
reportCount?: number,
|
||||
createdAt?: string,
|
||||
}) {
|
||||
const prefix = text(10);
|
||||
|
||||
return {
|
||||
check: p.check ?? boolean(),
|
||||
name: p.name ?? `${firstName()} ${lastName()}`,
|
||||
email: p.email ?? `${prefix}@example.com`,
|
||||
age: p.age ?? integer(20, 80),
|
||||
birthday: date().toISOString(),
|
||||
gender: p.gender ?? choose(['male', 'female', 'other', 'unknown']),
|
||||
country: p.country ?? country(),
|
||||
reportCount: p.reportCount ?? integer(),
|
||||
createdAt: p.createdAt ?? date().toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
const defaultCols = [
|
||||
{ bindTo: 'check', icon: 'ti-check', type: 'boolean', width: 50 },
|
||||
{ bindTo: 'name', title: 'Name', type: 'text', width: 'auto' },
|
||||
{ bindTo: 'email', title: 'Email', type: 'text', width: 'auto' },
|
||||
{ bindTo: 'age', title: 'Age', type: 'number', width: 50 },
|
||||
{ bindTo: 'birthday', title: 'Birthday', type: 'date', width: 'auto' },
|
||||
{ bindTo: 'gender', title: 'Gender', type: 'text', width: 80 },
|
||||
{ bindTo: 'country', title: 'Country', type: 'text', width: 120 },
|
||||
{ bindTo: 'reportCount', title: 'ReportCount', type: 'number', width: 'auto' },
|
||||
{ bindTo: 'createdAt', title: 'CreatedAt', type: 'date', width: 'auto' },
|
||||
];
|
||||
|
||||
function createArgs(overrides?: { settings?: Partial<GridSetting>, data?: DataSource[] }) {
|
||||
const refData = ref([
|
||||
d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}),
|
||||
d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}),
|
||||
d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}),
|
||||
d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}),
|
||||
d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}),
|
||||
]);
|
||||
|
||||
return {
|
||||
settings: {
|
||||
row: overrides?.settings?.row,
|
||||
cols: [
|
||||
...defaultCols.filter(col => overrides?.settings?.cols?.every(c => c.bindTo !== col.bindTo) ?? true),
|
||||
...overrides?.settings?.cols ?? [],
|
||||
],
|
||||
cells: overrides?.settings?.cells,
|
||||
},
|
||||
data: refData.value,
|
||||
};
|
||||
}
|
||||
|
||||
function createRender(params: { settings: Partial<GridSetting>, data: DataSource[] }) {
|
||||
return {
|
||||
render(args) {
|
||||
return {
|
||||
components: {
|
||||
MkGrid,
|
||||
},
|
||||
setup() {
|
||||
return {
|
||||
args,
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
data: args.data,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
props() {
|
||||
return {
|
||||
...args,
|
||||
};
|
||||
},
|
||||
events() {
|
||||
return {
|
||||
event: (event: GridEvent, context: GridContext) => {
|
||||
switch (event.type) {
|
||||
case 'cell-value-change': {
|
||||
args.data[event.row.index][event.column.setting.bindTo] = event.newValue;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
template: '<div style="padding:20px"><MkGrid v-bind="props" v-on="events" /></div>',
|
||||
};
|
||||
},
|
||||
args: {
|
||||
...params,
|
||||
},
|
||||
parameters: {
|
||||
layout: 'fullscreen',
|
||||
msw: {
|
||||
handlers: [
|
||||
...commonHandlers,
|
||||
],
|
||||
},
|
||||
},
|
||||
} satisfies StoryObj<typeof MkGrid>;
|
||||
}
|
||||
|
||||
export const Default = createRender(createArgs());
|
||||
|
||||
export const NoNumber = createRender(createArgs({
|
||||
settings: {
|
||||
row: {
|
||||
showNumber: false,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
export const NoSelectable = createRender(createArgs({
|
||||
settings: {
|
||||
row: {
|
||||
selectable: false,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
export const Editable = createRender(createArgs({
|
||||
settings: {
|
||||
cols: defaultCols.map(col => ({ ...col, editable: true })),
|
||||
},
|
||||
}));
|
||||
|
||||
export const AdditionalRowStyle = createRender(createArgs({
|
||||
settings: {
|
||||
cols: defaultCols.map(col => ({ ...col, editable: true })),
|
||||
row: {
|
||||
styleRules: [
|
||||
{
|
||||
condition: ({ row }) => AdditionalRowStyle.args.data[row.index].check,
|
||||
applyStyle: {
|
||||
style: {
|
||||
backgroundColor: 'lightgray',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
export const ContextMenu = createRender(createArgs({
|
||||
settings: {
|
||||
cols: [
|
||||
{
|
||||
bindTo: 'check', icon: 'ti-check', type: 'boolean', width: 50, contextMenuFactory: (col, context) => [
|
||||
{
|
||||
type: 'button',
|
||||
text: 'Check All',
|
||||
action: () => {
|
||||
for (const d of ContextMenu.args.data) {
|
||||
d.check = true;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'button',
|
||||
text: 'Uncheck All',
|
||||
action: () => {
|
||||
for (const d of ContextMenu.args.data) {
|
||||
d.check = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
row: {
|
||||
contextMenuFactory: (row, context) => [
|
||||
{
|
||||
type: 'button',
|
||||
text: 'Delete',
|
||||
action: () => {
|
||||
const idxes = context.rangedRows.map(r => r.index);
|
||||
const newData = ContextMenu.args.data.filter((d, i) => !idxes.includes(i));
|
||||
|
||||
ContextMenu.args.data.splice(0);
|
||||
ContextMenu.args.data.push(...newData);
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
cells: {
|
||||
contextMenuFactory: (col, row, value, context) => [
|
||||
{
|
||||
type: 'button',
|
||||
text: 'Delete',
|
||||
action: () => {
|
||||
for (const cell of context.rangedCells) {
|
||||
ContextMenu.args.data[cell.row.index][cell.column.setting.bindTo] = undefined;
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}));
|
|
@ -67,7 +67,7 @@ type RowHolder = {
|
|||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(ev: 'event', event: GridEvent, current: GridContext): void;
|
||||
(ev: 'event', event: GridEvent, context: GridContext): void;
|
||||
}>();
|
||||
|
||||
const props = defineProps<{
|
||||
|
|
Loading…
Reference in New Issue