|
1 | 1 | import type { Meta, StoryFn } from "@storybook/react"; |
2 | 2 | import { SlotFillProvider } from "@wordpress/components"; |
3 | | -import { Archive, Eye, Pencil, Trash2, UserCheck, Users, UserX } from "lucide-react"; |
| 3 | +import { Archive, Ban, CheckCircle, Eye, Mail, Pencil, Trash2, UserCheck, Users, UserX } from "lucide-react"; |
4 | 4 | import React, { useState } from "react"; |
5 | 5 | import { Badge, Input } from "../ui"; |
6 | 6 | import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/select"; |
@@ -1034,6 +1034,121 @@ export const FixedWidthColumns: StoryFn = () => { |
1034 | 1034 | ); |
1035 | 1035 | }; |
1036 | 1036 | FixedWidthColumns.storyName = "Fixed Width Columns"; |
| 1037 | +/** Demonstrates how the bulk action toolbar handles many actions with long descriptive labels. Select rows to see the toolbar. */ |
| 1038 | +export const LargeTextBulkActions: StoryFn = () => { |
| 1039 | + const [view, setView] = useState<DataViewState>(createDefaultView(["name", "email", "status", "role", "joinedAt"])); |
| 1040 | + const [selection, setSelection] = useState<string[]>([]); |
| 1041 | + const [users, setUsers] = useState(allUsers); |
| 1042 | + |
| 1043 | + const paginatedData = paginateData(users, view); |
| 1044 | + |
| 1045 | + const bulkActions: DataViewAction<User>[] = [ |
| 1046 | + { |
| 1047 | + id: "approve-selected", |
| 1048 | + label: "Approve Selected Users", |
| 1049 | + icon: <CheckCircle size={16} />, |
| 1050 | + supportsBulk: true, |
| 1051 | + callback: async (items) => { |
| 1052 | + await new Promise((resolve) => setTimeout(resolve, 1000)); |
| 1053 | + alert(`Approved: ${items.map(i => i.name).join(", ")}`); |
| 1054 | + }, |
| 1055 | + }, |
| 1056 | + { |
| 1057 | + id: "send-notification", |
| 1058 | + label: "Send Email Notification", |
| 1059 | + icon: <Mail size={16} />, |
| 1060 | + supportsBulk: true, |
| 1061 | + callback: async (items) => { |
| 1062 | + await new Promise((resolve) => setTimeout(resolve, 1000)); |
| 1063 | + alert(`Notification sent to: ${items.map(i => i.email).join(", ")}`); |
| 1064 | + }, |
| 1065 | + }, |
| 1066 | + { |
| 1067 | + id: "suspend-accounts", |
| 1068 | + label: "Suspend User Accounts", |
| 1069 | + icon: <Ban size={16} />, |
| 1070 | + isDestructive: true, |
| 1071 | + supportsBulk: true, |
| 1072 | + confirmTitle: "Suspend User Accounts", |
| 1073 | + confirmMessage: "Suspended users will lose access to their accounts immediately. You can reactivate them later.", |
| 1074 | + confirmButtonLabel: "Yes, Suspend All", |
| 1075 | + cancelButtonLabel: "Keep Active", |
| 1076 | + callback: async (items) => { |
| 1077 | + await new Promise((resolve) => setTimeout(resolve, 1500)); |
| 1078 | + alert(`Suspended: ${items.map(i => i.name).join(", ")}`); |
| 1079 | + }, |
| 1080 | + }, |
| 1081 | + { |
| 1082 | + id: "archive-permanently", |
| 1083 | + label: "Archive and Remove from List", |
| 1084 | + icon: <Archive size={16} />, |
| 1085 | + isDestructive: true, |
| 1086 | + supportsBulk: true, |
| 1087 | + confirmTitle: "Archive Users Permanently", |
| 1088 | + confirmMessage: "Archived users will be removed from all active lists and moved to the archive storage.", |
| 1089 | + confirmButtonLabel: "Archive Permanently", |
| 1090 | + callback: async (items) => { |
| 1091 | + await new Promise((resolve) => setTimeout(resolve, 1500)); |
| 1092 | + const ids = new Set(items.map(i => i.id)); |
| 1093 | + setUsers(prev => prev.filter(u => !ids.has(u.id))); |
| 1094 | + setSelection([]); |
| 1095 | + }, |
| 1096 | + }, |
| 1097 | + { |
| 1098 | + id: "delete-permanently", |
| 1099 | + label: "Delete Permanently from System", |
| 1100 | + icon: <Trash2 size={16} />, |
| 1101 | + isDestructive: true, |
| 1102 | + supportsBulk: true, |
| 1103 | + confirmTitle: "Permanently Delete Users", |
| 1104 | + confirmMessage: "This will permanently delete the selected users and all associated data. This action cannot be undone.", |
| 1105 | + confirmButtonLabel: "Delete Forever", |
| 1106 | + callback: async (items) => { |
| 1107 | + await new Promise((resolve) => setTimeout(resolve, 1500)); |
| 1108 | + const ids = new Set(items.map(i => i.id)); |
| 1109 | + setUsers(prev => prev.filter(u => !ids.has(u.id))); |
| 1110 | + setSelection([]); |
| 1111 | + }, |
| 1112 | + }, |
| 1113 | + ]; |
| 1114 | + |
| 1115 | + return ( |
| 1116 | + <div className="p-4"> |
| 1117 | + <DataViews<User> |
| 1118 | + namespace="dataviews-demo" |
| 1119 | + data={paginatedData} |
| 1120 | + fields={fields} |
| 1121 | + view={view} |
| 1122 | + onChangeView={setView} |
| 1123 | + actions={bulkActions} |
| 1124 | + selection={selection} |
| 1125 | + onChangeSelection={setSelection} |
| 1126 | + paginationInfo={{ |
| 1127 | + totalItems: users.length, |
| 1128 | + totalPages: getTotalPages(users.length, view.perPage), |
| 1129 | + }} |
| 1130 | + getItemId={(item) => item.id} |
| 1131 | + /> |
| 1132 | + </div> |
| 1133 | + ); |
| 1134 | +}; |
| 1135 | +LargeTextBulkActions.storyName = "Large Text Bulk Actions"; |
| 1136 | +LargeTextBulkActions.parameters = { |
| 1137 | + docs: { |
| 1138 | + description: { |
| 1139 | + story: `Demonstrates 5 bulk actions with long, descriptive labels to test how the bulk action toolbar handles large text. Select one or more rows to see the toolbar appear. |
| 1140 | +
|
| 1141 | +- **Approve Selected Users** — non-destructive bulk approval |
| 1142 | +- **Send Email Notification** — non-destructive bulk email |
| 1143 | +- **Suspend User Accounts** — destructive with custom confirmation dialog |
| 1144 | +- **Archive and Remove from List** — destructive, removes items from list |
| 1145 | +- **Delete Permanently from System** — destructive, permanently removes items |
| 1146 | +
|
| 1147 | +All actions support bulk selection and have async callbacks with loading states.`, |
| 1148 | + }, |
| 1149 | + }, |
| 1150 | +}; |
| 1151 | + |
1037 | 1152 | FixedWidthColumns.parameters = { |
1038 | 1153 | docs: { |
1039 | 1154 | description: { |
|
0 commit comments