vueless 1.3.9-beta.8 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,5 @@
1
+ import { ref } from "vue";
2
+
1
3
  import type { Meta, StoryFn } from "@storybook/vue3-vite";
2
4
 
3
5
  import {
@@ -18,6 +20,8 @@ import UBadge from "../../ui.text-badge/UBadge.vue";
18
20
  import URow from "../../ui.container-row/URow.vue";
19
21
  import UIcon from "../../ui.image-icon/UIcon.vue";
20
22
  import ULoader from "../../ui.loader/ULoader.vue";
23
+ import UInputSearch from "../../ui.form-input-search/UInputSearch.vue";
24
+ import UText from "../../ui.text-block/UText.vue";
21
25
 
22
26
  import tooltip from "../../v.tooltip/vTooltip";
23
27
  import type { Row, Props, ColumnObject } from "../types";
@@ -971,3 +975,162 @@ FooterSlot.args = {
971
975
  </template>
972
976
  `,
973
977
  };
978
+
979
+ function generateNestedRows(count: number): Row[] {
980
+ return Array.from({ length: count }, (_, i) => {
981
+ const hasChildren = i % 10 === 0;
982
+ const row: Row = {
983
+ id: `row-${i}`,
984
+ orderId: `ORD-${String(i).padStart(5, "0")}`,
985
+ customerName: ["Alice Johnson", "Michael Smith", "Emma Brown", "James Wilson"][i % 4],
986
+ status: ["Pending", "Shipped", "Delivered", "Cancelled"][i % 4],
987
+ totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
988
+ };
989
+
990
+ if (hasChildren) {
991
+ row.row = Array.from({ length: 3 }, (_, j) => ({
992
+ id: `row-${i}-child-${j}`,
993
+ orderId: `SUB-${String(i).padStart(5, "0")}-${j + 1}`,
994
+ customerName: "",
995
+ status: ["Processing", "Packed", "Ready"][j % 3],
996
+ totalPrice: `$${(Math.random() * 100).toFixed(2)}`,
997
+ }));
998
+ }
999
+
1000
+ return row;
1001
+ });
1002
+ }
1003
+
1004
+ export const VirtualScroll: StoryFn<UTableArgs> = (args: UTableArgs) => ({
1005
+ components: { UTable, UBadge },
1006
+ setup() {
1007
+ const rows = generateNestedRows(100000);
1008
+
1009
+ return { args, rows };
1010
+ },
1011
+ template: `
1012
+ <UTable
1013
+ :columns="[
1014
+ { key: 'orderId', label: 'Order ID', thClass: 'w-1/5' },
1015
+ { key: 'customerName', label: 'Customer Name' },
1016
+ { key: 'status', label: 'Status' },
1017
+ { key: 'totalPrice', label: 'Total Price' },
1018
+ ]"
1019
+ :rows="rows"
1020
+ compact
1021
+ virtual-scroll
1022
+ :row-height="46"
1023
+ :buffer-size="10"
1024
+ >
1025
+ <template #cell-status="{ value }">
1026
+ <UBadge
1027
+ :label="value"
1028
+ variant="soft"
1029
+ :color="
1030
+ value === 'Delivered' ? 'success' :
1031
+ value === 'Cancelled' ? 'error' :
1032
+ value === 'Pending' ? 'notice' :
1033
+ value === 'Shipped' || value === 'Processing' ? 'info' :
1034
+ value === 'Packed' || value === 'Ready' ? 'primary' : ''
1035
+ "
1036
+ />
1037
+ </template>
1038
+ </UTable>
1039
+ `,
1040
+ });
1041
+ VirtualScroll.parameters = {
1042
+ docs: {
1043
+ description: {
1044
+ story:
1045
+ "Virtual scrolling enables rendering of large datasets (100,000+ rows) with optimal performance. " +
1046
+ "Only visible rows are rendered in the DOM, with collapsible nested rows fully supported. " +
1047
+ "Use `virtualScroll` prop to enable, and configure `rowHeight`, `scrollHeight`, and `bufferSize` as needed.",
1048
+ },
1049
+ },
1050
+ };
1051
+
1052
+ export const VirtualSearch: StoryFn<UTableArgs> = (args: UTableArgs) => ({
1053
+ components: { UTable, UInputSearch, UButton, URow, UText },
1054
+ setup() {
1055
+ const rows = generateNestedRows(100000);
1056
+ const search = ref("");
1057
+ const searchMatch = ref(-1);
1058
+ const totalMatches = ref(0);
1059
+
1060
+ function onPrev() {
1061
+ if (totalMatches.value === 0) return;
1062
+
1063
+ searchMatch.value = searchMatch.value <= 0 ? totalMatches.value - 1 : searchMatch.value - 1;
1064
+ }
1065
+
1066
+ function onNext() {
1067
+ if (totalMatches.value === 0) return;
1068
+
1069
+ searchMatch.value = searchMatch.value >= totalMatches.value - 1 ? 0 : searchMatch.value + 1;
1070
+ }
1071
+
1072
+ return { args, rows, search, searchMatch, totalMatches, onPrev, onNext };
1073
+ },
1074
+ template: `
1075
+ <URow align="stretch" gap="xs" class="mb-4">
1076
+ <UInputSearch
1077
+ v-model="search"
1078
+ placeholder="Search in table..."
1079
+ size="md"
1080
+ @clear="searchMatch = -1"
1081
+ >
1082
+ <template #right>
1083
+ <UText :label="searchMatch + 1 + ' / ' + totalMatches" :wrap="false" class="ml-1" />
1084
+ </template>
1085
+ </UInputSearch>
1086
+
1087
+ <UButton
1088
+ square
1089
+ size="sm"
1090
+ title="Prev"
1091
+ variant="soft"
1092
+ icon="keyboard_arrow_up"
1093
+ :disabled="totalMatches === 0"
1094
+ @click="onPrev"
1095
+ />
1096
+
1097
+ <UButton
1098
+ square
1099
+ size="sm"
1100
+ title="Next"
1101
+ variant="soft"
1102
+ icon="keyboard_arrow_down"
1103
+ :disabled="totalMatches === 0"
1104
+ @click="onNext"
1105
+ />
1106
+ </URow>
1107
+
1108
+ <UTable
1109
+ :columns="[
1110
+ { key: 'orderId', label: 'Order ID', thClass: 'w-1/5' },
1111
+ { key: 'customerName', label: 'Customer Name' },
1112
+ { key: 'status', label: 'Status' },
1113
+ { key: 'totalPrice', label: 'Total Price' },
1114
+ ]"
1115
+ :rows="rows"
1116
+ compact
1117
+ virtual-scroll
1118
+ :row-height="45"
1119
+ :buffer-size="10"
1120
+ :search="search"
1121
+ :search-match="searchMatch"
1122
+ @search="totalMatches = $event"
1123
+ />
1124
+ `,
1125
+ });
1126
+ VirtualSearch.parameters = {
1127
+ docs: {
1128
+ description: {
1129
+ story:
1130
+ "Search functionality with virtual scrolling. " +
1131
+ "Use `search` prop to pass a search string and `searchMatch` prop to highlight a specific match. " +
1132
+ "The `@search` event emits the total number of matches found. " +
1133
+ "Use Prev/Next buttons to navigate between matches.",
1134
+ },
1135
+ },
1136
+ };