cisse-vue-ui 0.9.0 → 0.10.1

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.
Files changed (46) hide show
  1. package/dist/{ConfirmDialog.vue_vue_type_script_setup_true_lang-C5KHLMvx.js → ConfirmDialog.vue_vue_type_script_setup_true_lang-DhPNxKgF.js} +40 -94
  2. package/dist/ConfirmDialog.vue_vue_type_script_setup_true_lang-DhPNxKgF.js.map +1 -0
  3. package/dist/{ConfirmDialog.vue_vue_type_script_setup_true_lang-CLfy0-Wb.cjs → ConfirmDialog.vue_vue_type_script_setup_true_lang-DwW3MT85.cjs} +37 -91
  4. package/dist/ConfirmDialog.vue_vue_type_script_setup_true_lang-DwW3MT85.cjs.map +1 -0
  5. package/dist/{FilterTabs.vue_vue_type_script_setup_true_lang-COkZbeGG.cjs → FilterTabs.vue_vue_type_script_setup_true_lang-CwcJkw3D.cjs} +499 -165
  6. package/dist/FilterTabs.vue_vue_type_script_setup_true_lang-CwcJkw3D.cjs.map +1 -0
  7. package/dist/{FilterTabs.vue_vue_type_script_setup_true_lang-CzpYHtc5.js → FilterTabs.vue_vue_type_script_setup_true_lang-aPs8YGWB.js} +494 -160
  8. package/dist/FilterTabs.vue_vue_type_script_setup_true_lang-aPs8YGWB.js.map +1 -0
  9. package/dist/{ListSkeleton.vue_vue_type_script_setup_true_lang-Bo3HqgX0.cjs → Skeleton.vue_vue_type_script_setup_true_lang-ahmyY81P.cjs} +70 -16
  10. package/dist/Skeleton.vue_vue_type_script_setup_true_lang-ahmyY81P.cjs.map +1 -0
  11. package/dist/{ListSkeleton.vue_vue_type_script_setup_true_lang-BHopJ9RG.js → Skeleton.vue_vue_type_script_setup_true_lang-mcD2ZqKf.js} +70 -16
  12. package/dist/Skeleton.vue_vue_type_script_setup_true_lang-mcD2ZqKf.js.map +1 -0
  13. package/dist/components/core/StatItem.stories.d.ts +44 -0
  14. package/dist/components/core/StatItem.vue.d.ts +135 -0
  15. package/dist/components/core/Stats.stories.d.ts +45 -0
  16. package/dist/components/core/Stats.vue.d.ts +97 -0
  17. package/dist/components/core/index.cjs +3 -1
  18. package/dist/components/core/index.cjs.map +1 -1
  19. package/dist/components/core/index.d.ts +6 -3
  20. package/dist/components/core/index.js +5 -3
  21. package/dist/components/feedback/index.cjs +8 -8
  22. package/dist/components/feedback/index.js +7 -7
  23. package/dist/components/index.cjs +11 -9
  24. package/dist/components/index.cjs.map +1 -1
  25. package/dist/components/index.js +12 -10
  26. package/dist/{index-BMSH4AOz.cjs → index-CKd33NtQ.cjs} +12 -10
  27. package/dist/{index-BMSH4AOz.cjs.map → index-CKd33NtQ.cjs.map} +1 -1
  28. package/dist/{index-0kwQORZJ.js → index-D-VE0o-l.js} +6 -4
  29. package/dist/{index-0kwQORZJ.js.map → index-D-VE0o-l.js.map} +1 -1
  30. package/dist/index.cjs +12 -10
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.js +16 -14
  33. package/dist/style.css +1 -1
  34. package/package.json +1 -1
  35. package/dist/ConfirmDialog.vue_vue_type_script_setup_true_lang-C5KHLMvx.js.map +0 -1
  36. package/dist/ConfirmDialog.vue_vue_type_script_setup_true_lang-CLfy0-Wb.cjs.map +0 -1
  37. package/dist/FilterTabs.vue_vue_type_script_setup_true_lang-COkZbeGG.cjs.map +0 -1
  38. package/dist/FilterTabs.vue_vue_type_script_setup_true_lang-CzpYHtc5.js.map +0 -1
  39. package/dist/ListSkeleton.vue_vue_type_script_setup_true_lang-BHopJ9RG.js.map +0 -1
  40. package/dist/ListSkeleton.vue_vue_type_script_setup_true_lang-Bo3HqgX0.cjs.map +0 -1
  41. package/dist/components/core/StatsCard.stories.d.ts +0 -15
  42. package/dist/components/core/StatsCard.vue.d.ts +0 -44
  43. package/dist/components/core/StatsGrid.stories.d.ts +0 -12
  44. package/dist/components/core/StatsGrid.vue.d.ts +0 -16
  45. /package/dist/components/core/{StatsCard.test.d.ts → StatItem.test.d.ts} +0 -0
  46. /package/dist/components/core/{StatsGrid.test.d.ts → Stats.test.d.ts} +0 -0
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  const vue = require("vue");
3
3
  const vue$1 = require("@iconify/vue");
4
- const _hoisted_1$3 = {
4
+ const _hoisted_1$4 = {
5
5
  class: "bg-white dark:bg-gray-900 rounded-lg shadow-md p-4 space-y-4",
6
6
  "aria-hidden": "true"
7
7
  };
@@ -14,7 +14,7 @@ const _hoisted_4$2 = {
14
14
  key: 1,
15
15
  class: "flex justify-end gap-2 pt-2"
16
16
  };
17
- const _sfc_main$3 = /* @__PURE__ */ vue.defineComponent({
17
+ const _sfc_main$4 = /* @__PURE__ */ vue.defineComponent({
18
18
  __name: "CardSkeleton",
19
19
  props: {
20
20
  showAvatar: { type: Boolean, default: false },
@@ -23,7 +23,7 @@ const _sfc_main$3 = /* @__PURE__ */ vue.defineComponent({
23
23
  },
24
24
  setup(__props) {
25
25
  return (_ctx, _cache) => {
26
- return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$3, [
26
+ return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$4, [
27
27
  __props.showAvatar ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_2$3, [..._cache[0] || (_cache[0] = [
28
28
  vue.createElementVNode("div", { class: "size-10 rounded-full bg-gray-200 dark:bg-gray-700 animate-pulse" }, null, -1),
29
29
  vue.createElementVNode("div", { class: "flex-1 space-y-2" }, [
@@ -48,7 +48,7 @@ const _sfc_main$3 = /* @__PURE__ */ vue.defineComponent({
48
48
  };
49
49
  }
50
50
  });
51
- const _hoisted_1$2 = {
51
+ const _hoisted_1$3 = {
52
52
  class: "w-full",
53
53
  "aria-hidden": "true"
54
54
  };
@@ -56,7 +56,7 @@ const _hoisted_2$2 = {
56
56
  key: 0,
57
57
  class: "flex gap-4 px-4 py-3 border-b border-gray-200 dark:border-gray-700"
58
58
  };
59
- const _sfc_main$2 = /* @__PURE__ */ vue.defineComponent({
59
+ const _sfc_main$3 = /* @__PURE__ */ vue.defineComponent({
60
60
  __name: "TableSkeleton",
61
61
  props: {
62
62
  rows: { default: 5 },
@@ -65,7 +65,7 @@ const _sfc_main$2 = /* @__PURE__ */ vue.defineComponent({
65
65
  },
66
66
  setup(__props) {
67
67
  return (_ctx, _cache) => {
68
- return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$2, [
68
+ return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$3, [
69
69
  __props.showHeader ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_2$2, [
70
70
  (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(__props.columns, (col) => {
71
71
  return vue.openBlock(), vue.createElementBlock("div", {
@@ -96,7 +96,7 @@ const _sfc_main$2 = /* @__PURE__ */ vue.defineComponent({
96
96
  };
97
97
  }
98
98
  });
99
- const _hoisted_1$1 = {
99
+ const _hoisted_1$2 = {
100
100
  key: 0,
101
101
  class: "flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 border-t border-gray-200 px-4 sm:px-6 py-4 dark:border-gray-700"
102
102
  };
@@ -122,7 +122,7 @@ const _hoisted_11 = {
122
122
  const _hoisted_12 = ["disabled", "onClick"];
123
123
  const _hoisted_13 = ["disabled"];
124
124
  const _hoisted_14 = { class: "hidden sm:inline" };
125
- const _sfc_main$1 = /* @__PURE__ */ vue.defineComponent({
125
+ const _sfc_main$2 = /* @__PURE__ */ vue.defineComponent({
126
126
  __name: "PaginationControls",
127
127
  props: {
128
128
  currentPage: {},
@@ -180,7 +180,7 @@ const _sfc_main$1 = /* @__PURE__ */ vue.defineComponent({
180
180
  emit("update:pageSize", Number(target.value));
181
181
  };
182
182
  return (_ctx, _cache) => {
183
- return __props.totalPages > 1 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$1, [
183
+ return __props.totalPages > 1 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$2, [
184
184
  vue.createElementVNode("div", _hoisted_2$1, [
185
185
  vue.createElementVNode("div", _hoisted_3$1, vue.toDisplayString(__props.pageLabel) + " " + vue.toDisplayString(__props.currentPage) + " " + vue.toDisplayString(__props.ofLabel) + " " + vue.toDisplayString(__props.totalPages), 1),
186
186
  __props.showPageSize ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_4$1, [
@@ -242,7 +242,7 @@ const _sfc_main$1 = /* @__PURE__ */ vue.defineComponent({
242
242
  };
243
243
  }
244
244
  });
245
- const _hoisted_1 = {
245
+ const _hoisted_1$1 = {
246
246
  class: "divide-y divide-gray-200 dark:divide-gray-700",
247
247
  "aria-hidden": "true"
248
248
  };
@@ -255,7 +255,7 @@ const _hoisted_4 = {
255
255
  key: 1,
256
256
  class: "shrink-0 size-8 rounded bg-gray-200 dark:bg-gray-700 animate-pulse"
257
257
  };
258
- const _sfc_main = /* @__PURE__ */ vue.defineComponent({
258
+ const _sfc_main$1 = /* @__PURE__ */ vue.defineComponent({
259
259
  __name: "ListSkeleton",
260
260
  props: {
261
261
  items: { default: 5 },
@@ -265,7 +265,7 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
265
265
  },
266
266
  setup(__props) {
267
267
  return (_ctx, _cache) => {
268
- return vue.openBlock(), vue.createElementBlock("div", _hoisted_1, [
268
+ return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$1, [
269
269
  (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(__props.items, (item) => {
270
270
  return vue.openBlock(), vue.createElementBlock("div", {
271
271
  key: item,
@@ -290,8 +290,62 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
290
290
  };
291
291
  }
292
292
  });
293
- exports._sfc_main = _sfc_main$1;
294
- exports._sfc_main$1 = _sfc_main$2;
293
+ const _hoisted_1 = {
294
+ key: 0,
295
+ class: "space-y-2",
296
+ "aria-hidden": "true"
297
+ };
298
+ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
299
+ __name: "Skeleton",
300
+ props: {
301
+ variant: { default: "text" },
302
+ width: {},
303
+ height: {},
304
+ lines: { default: 1 },
305
+ animate: { type: Boolean, default: true }
306
+ },
307
+ setup(__props) {
308
+ const variantClasses = {
309
+ text: "h-4 rounded",
310
+ circular: "rounded-full",
311
+ rectangular: "",
312
+ rounded: "rounded-lg"
313
+ };
314
+ return (_ctx, _cache) => {
315
+ return __props.variant === "text" && __props.lines > 1 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1, [
316
+ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(__props.lines, (i) => {
317
+ return vue.openBlock(), vue.createElementBlock("div", {
318
+ key: i,
319
+ class: vue.normalizeClass([
320
+ "bg-gray-200 dark:bg-gray-700",
321
+ variantClasses[__props.variant],
322
+ __props.animate && "animate-pulse"
323
+ ]),
324
+ style: vue.normalizeStyle({
325
+ width: i === __props.lines ? "75%" : __props.width || "100%",
326
+ height: __props.height
327
+ })
328
+ }, null, 6);
329
+ }), 128))
330
+ ])) : (vue.openBlock(), vue.createElementBlock("div", {
331
+ key: 1,
332
+ class: vue.normalizeClass([
333
+ "bg-gray-200 dark:bg-gray-700",
334
+ variantClasses[__props.variant],
335
+ __props.animate && "animate-pulse"
336
+ ]),
337
+ style: vue.normalizeStyle({
338
+ width: __props.width || (__props.variant === "circular" ? "3rem" : "100%"),
339
+ height: __props.height || (__props.variant === "circular" ? "3rem" : __props.variant === "text" ? "1rem" : "6rem")
340
+ }),
341
+ "aria-hidden": "true"
342
+ }, null, 6));
343
+ };
344
+ }
345
+ });
346
+ exports._sfc_main = _sfc_main$2;
347
+ exports._sfc_main$1 = _sfc_main;
295
348
  exports._sfc_main$2 = _sfc_main$3;
296
- exports._sfc_main$3 = _sfc_main;
297
- //# sourceMappingURL=ListSkeleton.vue_vue_type_script_setup_true_lang-Bo3HqgX0.cjs.map
349
+ exports._sfc_main$3 = _sfc_main$4;
350
+ exports._sfc_main$4 = _sfc_main$1;
351
+ //# sourceMappingURL=Skeleton.vue_vue_type_script_setup_true_lang-ahmyY81P.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Skeleton.vue_vue_type_script_setup_true_lang-ahmyY81P.cjs","sources":["../src/components/feedback/CardSkeleton.vue","../src/components/feedback/TableSkeleton.vue","../src/components/feedback/PaginationControls.vue","../src/components/feedback/ListSkeleton.vue","../src/components/feedback/Skeleton.vue"],"sourcesContent":["<script lang=\"ts\" setup>\r\nwithDefaults(\r\n defineProps<{\r\n /** Show avatar/icon placeholder */\r\n showAvatar?: boolean\r\n /** Number of text lines */\r\n lines?: number\r\n /** Show action buttons */\r\n showActions?: boolean\r\n }>(),\r\n {\r\n showAvatar: false,\r\n lines: 3,\r\n showActions: false,\r\n },\r\n)\r\n</script>\r\n\r\n<template>\r\n <div class=\"bg-white dark:bg-gray-900 rounded-lg shadow-md p-4 space-y-4\" aria-hidden=\"true\">\r\n <!-- Header with avatar -->\r\n <div v-if=\"showAvatar\" class=\"flex items-center gap-3\">\r\n <div class=\"size-10 rounded-full bg-gray-200 dark:bg-gray-700 animate-pulse\" />\r\n <div class=\"flex-1 space-y-2\">\r\n <div class=\"h-4 bg-gray-200 dark:bg-gray-700 rounded animate-pulse w-1/2\" />\r\n <div class=\"h-3 bg-gray-200 dark:bg-gray-700 rounded animate-pulse w-1/3\" />\r\n </div>\r\n </div>\r\n\r\n <!-- Content lines -->\r\n <div class=\"space-y-2\">\r\n <div\r\n v-for=\"line in lines\"\r\n :key=\"line\"\r\n class=\"h-4 bg-gray-200 dark:bg-gray-700 rounded animate-pulse\"\r\n :style=\"{ width: line === lines ? '60%' : '100%' }\"\r\n />\r\n </div>\r\n\r\n <!-- Actions -->\r\n <div v-if=\"showActions\" class=\"flex justify-end gap-2 pt-2\">\r\n <div class=\"h-8 w-20 bg-gray-200 dark:bg-gray-700 rounded animate-pulse\" />\r\n <div class=\"h-8 w-20 bg-gray-200 dark:bg-gray-700 rounded animate-pulse\" />\r\n </div>\r\n </div>\r\n</template>\r\n","<script lang=\"ts\" setup>\r\nwithDefaults(\r\n defineProps<{\r\n /** Number of rows */\r\n rows?: number\r\n /** Number of columns */\r\n columns?: number\r\n /** Show header */\r\n showHeader?: boolean\r\n }>(),\r\n {\r\n rows: 5,\r\n columns: 4,\r\n showHeader: true,\r\n },\r\n)\r\n</script>\r\n\r\n<template>\r\n <div class=\"w-full\" aria-hidden=\"true\">\r\n <!-- Header -->\r\n <div\r\n v-if=\"showHeader\"\r\n class=\"flex gap-4 px-4 py-3 border-b border-gray-200 dark:border-gray-700\"\r\n >\r\n <div\r\n v-for=\"col in columns\"\r\n :key=\"`header-${col}`\"\r\n class=\"flex-1 h-4 bg-gray-200 dark:bg-gray-700 rounded animate-pulse\"\r\n :style=\"{ maxWidth: col === 1 ? '30%' : '20%' }\"\r\n />\r\n </div>\r\n <!-- Rows -->\r\n <div\r\n v-for=\"row in rows\"\r\n :key=\"`row-${row}`\"\r\n class=\"flex items-center gap-4 px-4 py-4 border-b border-gray-100 dark:border-gray-800\"\r\n >\r\n <div\r\n v-for=\"col in columns\"\r\n :key=\"`cell-${row}-${col}`\"\r\n class=\"flex-1 h-4 bg-gray-200 dark:bg-gray-700 rounded animate-pulse\"\r\n :style=\"{\r\n maxWidth: col === 1 ? '40%' : col === columns ? '15%' : '25%',\r\n opacity: 1 - (row * 0.1)\r\n }\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n","<script lang=\"ts\" setup>\r\nimport { computed } from 'vue'\r\nimport { Icon } from '@iconify/vue'\r\n\r\nconst {\r\n currentPage,\r\n totalPages,\r\n loading = false,\r\n pageSize = 10,\r\n pageSizeOptions = [10, 20, 50, 100],\r\n showPageSize = true,\r\n showPageNumbers = true,\r\n maxVisiblePages = 7,\r\n pageLabel = 'Page',\r\n ofLabel = 'of',\r\n itemsPerPageLabel = 'Items per page:',\r\n previousLabel = 'Previous',\r\n nextLabel = 'Next',\r\n} = defineProps<{\r\n currentPage: number\r\n totalPages: number\r\n loading?: boolean\r\n pageSize?: number\r\n pageSizeOptions?: number[]\r\n showPageSize?: boolean\r\n showPageNumbers?: boolean\r\n maxVisiblePages?: number\r\n pageLabel?: string\r\n ofLabel?: string\r\n itemsPerPageLabel?: string\r\n previousLabel?: string\r\n nextLabel?: string\r\n}>()\r\n\r\ntype PageItem = number | 'ellipsis-start' | 'ellipsis-end'\r\n\r\nconst visiblePages = computed<PageItem[]>(() => {\r\n if (totalPages <= maxVisiblePages) {\r\n return Array.from({ length: totalPages }, (_, i) => i + 1)\r\n }\r\n\r\n const pages: PageItem[] = []\r\n const sidePages = Math.floor((maxVisiblePages - 3) / 2)\r\n\r\n // Always show first page\r\n pages.push(1)\r\n\r\n // Calculate range around current page\r\n let rangeStart = Math.max(2, currentPage - sidePages)\r\n let rangeEnd = Math.min(totalPages - 1, currentPage + sidePages)\r\n\r\n // Adjust range to show more pages on one side if near edges\r\n if (currentPage <= sidePages + 2) {\r\n rangeEnd = Math.min(totalPages - 1, maxVisiblePages - 2)\r\n } else if (currentPage >= totalPages - sidePages - 1) {\r\n rangeStart = Math.max(2, totalPages - maxVisiblePages + 3)\r\n }\r\n\r\n // Add ellipsis or pages after first page\r\n if (rangeStart > 2) {\r\n pages.push('ellipsis-start')\r\n }\r\n\r\n // Add range pages\r\n for (let i = rangeStart; i <= rangeEnd; i++) {\r\n pages.push(i)\r\n }\r\n\r\n // Add ellipsis or pages before last page\r\n if (rangeEnd < totalPages - 1) {\r\n pages.push('ellipsis-end')\r\n }\r\n\r\n // Always show last page\r\n if (totalPages > 1) {\r\n pages.push(totalPages)\r\n }\r\n\r\n return pages\r\n})\r\n\r\nconst emit = defineEmits<{\r\n 'update:page': [page: number]\r\n 'update:pageSize': [size: number]\r\n}>()\r\n\r\nconst changePage = (page: number) => {\r\n if (page >= 1 && page <= totalPages && !loading) {\r\n emit('update:page', page)\r\n }\r\n}\r\n\r\nconst changePageSize = (event: Event) => {\r\n const target = event.target as HTMLSelectElement\r\n emit('update:pageSize', Number(target.value))\r\n}\r\n</script>\r\n\r\n<template>\r\n <div\r\n v-if=\"totalPages > 1\"\r\n class=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 border-t border-gray-200 px-4 sm:px-6 py-4 dark:border-gray-700\"\r\n >\r\n <!-- Info and page size -->\r\n <div class=\"flex flex-col sm:flex-row sm:items-center gap-3 sm:gap-4\">\r\n <div class=\"text-sm text-gray-700 dark:text-gray-300 text-center sm:text-left\">\r\n {{ pageLabel }} {{ currentPage }} {{ ofLabel }} {{ totalPages }}\r\n </div>\r\n <div\r\n v-if=\"showPageSize\"\r\n class=\"flex items-center justify-center sm:justify-start gap-2\"\r\n >\r\n <label\r\n class=\"text-sm text-gray-600 dark:text-gray-400 hidden sm:inline\"\r\n for=\"page-size\"\r\n >\r\n {{ itemsPerPageLabel }}\r\n </label>\r\n <select\r\n id=\"page-size\"\r\n :value=\"pageSize\"\r\n class=\"focus:border-primary focus:ring-primary rounded border border-gray-300 bg-white px-2 py-1 text-sm text-gray-900 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100\"\r\n @change=\"changePageSize\"\r\n >\r\n <option\r\n v-for=\"size in pageSizeOptions\"\r\n :key=\"size\"\r\n :value=\"size\"\r\n >\r\n {{ size }}\r\n </option>\r\n </select>\r\n </div>\r\n </div>\r\n\r\n <!-- Navigation buttons -->\r\n <div class=\"flex justify-center sm:justify-end items-center gap-1\">\r\n <!-- Previous button -->\r\n <button\r\n :disabled=\"currentPage === 1 || loading\"\r\n class=\"focus:ring-primary inline-flex items-center gap-1 rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700\"\r\n @click=\"changePage(currentPage - 1)\"\r\n >\r\n <Icon\r\n class=\"size-4\"\r\n icon=\"lucide:chevron-left\"\r\n />\r\n <span class=\"hidden sm:inline\">{{ previousLabel }}</span>\r\n </button>\r\n\r\n <!-- Page numbers -->\r\n <template v-if=\"showPageNumbers\">\r\n <template\r\n v-for=\"page in visiblePages\"\r\n :key=\"page\"\r\n >\r\n <!-- Ellipsis -->\r\n <span\r\n v-if=\"page === 'ellipsis-start' || page === 'ellipsis-end'\"\r\n class=\"px-2 py-2 text-sm text-gray-500 dark:text-gray-400\"\r\n >\r\n …\r\n </span>\r\n <!-- Page number button -->\r\n <button\r\n v-else\r\n :disabled=\"loading\"\r\n :class=\"[\r\n 'min-w-[40px] px-3 py-2 text-sm font-medium rounded-lg border transition-colors',\r\n page === currentPage\r\n ? 'bg-primary-600 text-white border-primary-600 dark:bg-primary-500 dark:border-primary-500'\r\n : 'bg-white text-gray-700 border-gray-300 hover:bg-gray-50 dark:bg-gray-800 dark:text-gray-200 dark:border-gray-600 dark:hover:bg-gray-700',\r\n loading ? 'cursor-not-allowed opacity-50' : ''\r\n ]\"\r\n @click=\"changePage(page)\"\r\n >\r\n {{ page }}\r\n </button>\r\n </template>\r\n </template>\r\n\r\n <!-- Next button -->\r\n <button\r\n :disabled=\"currentPage === totalPages || loading\"\r\n class=\"focus:ring-primary inline-flex items-center gap-1 rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700\"\r\n @click=\"changePage(currentPage + 1)\"\r\n >\r\n <span class=\"hidden sm:inline\">{{ nextLabel }}</span>\r\n <Icon\r\n class=\"size-4\"\r\n icon=\"lucide:chevron-right\"\r\n />\r\n </button>\r\n </div>\r\n </div>\r\n</template>\r\n","<script lang=\"ts\" setup>\r\nwithDefaults(\r\n defineProps<{\r\n /** Number of items */\r\n items?: number\r\n /** Show avatar/icon placeholder */\r\n showAvatar?: boolean\r\n /** Show secondary text */\r\n showSecondary?: boolean\r\n /** Show action button */\r\n showAction?: boolean\r\n }>(),\r\n {\r\n items: 5,\r\n showAvatar: true,\r\n showSecondary: true,\r\n showAction: false,\r\n },\r\n)\r\n</script>\r\n\r\n<template>\r\n <div class=\"divide-y divide-gray-200 dark:divide-gray-700\" aria-hidden=\"true\">\r\n <div\r\n v-for=\"item in items\"\r\n :key=\"item\"\r\n class=\"flex items-center gap-4 py-4 px-4\"\r\n >\r\n <!-- Avatar -->\r\n <div\r\n v-if=\"showAvatar\"\r\n class=\"shrink-0 size-10 rounded-full bg-gray-200 dark:bg-gray-700 animate-pulse\"\r\n />\r\n\r\n <!-- Content -->\r\n <div class=\"flex-1 min-w-0 space-y-2\">\r\n <div\r\n class=\"h-4 bg-gray-200 dark:bg-gray-700 rounded animate-pulse\"\r\n :style=\"{ width: `${60 + Math.random() * 30}%` }\"\r\n />\r\n <div\r\n v-if=\"showSecondary\"\r\n class=\"h-3 bg-gray-200 dark:bg-gray-700 rounded animate-pulse\"\r\n :style=\"{ width: `${40 + Math.random() * 20}%` }\"\r\n />\r\n </div>\r\n\r\n <!-- Action -->\r\n <div\r\n v-if=\"showAction\"\r\n class=\"shrink-0 size-8 rounded bg-gray-200 dark:bg-gray-700 animate-pulse\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n","<script lang=\"ts\" setup>\r\nexport type SkeletonVariant = 'text' | 'circular' | 'rectangular' | 'rounded'\r\n\r\nwithDefaults(\r\n defineProps<{\r\n /** Variant style */\r\n variant?: SkeletonVariant\r\n /** Width (CSS value) */\r\n width?: string\r\n /** Height (CSS value) */\r\n height?: string\r\n /** Number of lines (for text variant) */\r\n lines?: number\r\n /** Animate the skeleton */\r\n animate?: boolean\r\n }>(),\r\n {\r\n variant: 'text',\r\n animate: true,\r\n lines: 1,\r\n },\r\n)\r\n\r\nconst variantClasses: Record<SkeletonVariant, string> = {\r\n text: 'h-4 rounded',\r\n circular: 'rounded-full',\r\n rectangular: '',\r\n rounded: 'rounded-lg',\r\n}\r\n</script>\r\n\r\n<template>\r\n <div\r\n v-if=\"variant === 'text' && lines > 1\"\r\n class=\"space-y-2\"\r\n aria-hidden=\"true\"\r\n >\r\n <div\r\n v-for=\"i in lines\"\r\n :key=\"i\"\r\n :class=\"[\r\n 'bg-gray-200 dark:bg-gray-700',\r\n variantClasses[variant],\r\n animate && 'animate-pulse',\r\n ]\"\r\n :style=\"{\r\n width: i === lines ? '75%' : width || '100%',\r\n height: height,\r\n }\"\r\n />\r\n </div>\r\n <div\r\n v-else\r\n :class=\"[\r\n 'bg-gray-200 dark:bg-gray-700',\r\n variantClasses[variant],\r\n animate && 'animate-pulse',\r\n ]\"\r\n :style=\"{\r\n width: width || (variant === 'circular' ? '3rem' : '100%'),\r\n height: height || (variant === 'circular' ? '3rem' : variant === 'text' ? '1rem' : '6rem'),\r\n }\"\r\n aria-hidden=\"true\"\r\n />\r\n</template>\r\n"],"names":["_openBlock","_createElementBlock","_hoisted_1","_hoisted_2","_createElementVNode","_hoisted_3","_Fragment","_renderList","_normalizeStyle","_hoisted_4","computed","_toDisplayString","_createVNode","_unref","Icon","_normalizeClass"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { defineComponent, createElementBlock, openBlock, createCommentVNode, createElementVNode, Fragment, renderList, normalizeStyle, computed, toDisplayString, createVNode, unref, normalizeClass } from "vue";
2
2
  import { Icon } from "@iconify/vue";
3
- const _hoisted_1$3 = {
3
+ const _hoisted_1$4 = {
4
4
  class: "bg-white dark:bg-gray-900 rounded-lg shadow-md p-4 space-y-4",
5
5
  "aria-hidden": "true"
6
6
  };
@@ -13,7 +13,7 @@ const _hoisted_4$2 = {
13
13
  key: 1,
14
14
  class: "flex justify-end gap-2 pt-2"
15
15
  };
16
- const _sfc_main$3 = /* @__PURE__ */ defineComponent({
16
+ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
17
17
  __name: "CardSkeleton",
18
18
  props: {
19
19
  showAvatar: { type: Boolean, default: false },
@@ -22,7 +22,7 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
22
22
  },
23
23
  setup(__props) {
24
24
  return (_ctx, _cache) => {
25
- return openBlock(), createElementBlock("div", _hoisted_1$3, [
25
+ return openBlock(), createElementBlock("div", _hoisted_1$4, [
26
26
  __props.showAvatar ? (openBlock(), createElementBlock("div", _hoisted_2$3, [..._cache[0] || (_cache[0] = [
27
27
  createElementVNode("div", { class: "size-10 rounded-full bg-gray-200 dark:bg-gray-700 animate-pulse" }, null, -1),
28
28
  createElementVNode("div", { class: "flex-1 space-y-2" }, [
@@ -47,7 +47,7 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
47
47
  };
48
48
  }
49
49
  });
50
- const _hoisted_1$2 = {
50
+ const _hoisted_1$3 = {
51
51
  class: "w-full",
52
52
  "aria-hidden": "true"
53
53
  };
@@ -55,7 +55,7 @@ const _hoisted_2$2 = {
55
55
  key: 0,
56
56
  class: "flex gap-4 px-4 py-3 border-b border-gray-200 dark:border-gray-700"
57
57
  };
58
- const _sfc_main$2 = /* @__PURE__ */ defineComponent({
58
+ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
59
59
  __name: "TableSkeleton",
60
60
  props: {
61
61
  rows: { default: 5 },
@@ -64,7 +64,7 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
64
64
  },
65
65
  setup(__props) {
66
66
  return (_ctx, _cache) => {
67
- return openBlock(), createElementBlock("div", _hoisted_1$2, [
67
+ return openBlock(), createElementBlock("div", _hoisted_1$3, [
68
68
  __props.showHeader ? (openBlock(), createElementBlock("div", _hoisted_2$2, [
69
69
  (openBlock(true), createElementBlock(Fragment, null, renderList(__props.columns, (col) => {
70
70
  return openBlock(), createElementBlock("div", {
@@ -95,7 +95,7 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
95
95
  };
96
96
  }
97
97
  });
98
- const _hoisted_1$1 = {
98
+ const _hoisted_1$2 = {
99
99
  key: 0,
100
100
  class: "flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 border-t border-gray-200 px-4 sm:px-6 py-4 dark:border-gray-700"
101
101
  };
@@ -121,7 +121,7 @@ const _hoisted_11 = {
121
121
  const _hoisted_12 = ["disabled", "onClick"];
122
122
  const _hoisted_13 = ["disabled"];
123
123
  const _hoisted_14 = { class: "hidden sm:inline" };
124
- const _sfc_main$1 = /* @__PURE__ */ defineComponent({
124
+ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
125
125
  __name: "PaginationControls",
126
126
  props: {
127
127
  currentPage: {},
@@ -179,7 +179,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
179
179
  emit("update:pageSize", Number(target.value));
180
180
  };
181
181
  return (_ctx, _cache) => {
182
- return __props.totalPages > 1 ? (openBlock(), createElementBlock("div", _hoisted_1$1, [
182
+ return __props.totalPages > 1 ? (openBlock(), createElementBlock("div", _hoisted_1$2, [
183
183
  createElementVNode("div", _hoisted_2$1, [
184
184
  createElementVNode("div", _hoisted_3$1, toDisplayString(__props.pageLabel) + " " + toDisplayString(__props.currentPage) + " " + toDisplayString(__props.ofLabel) + " " + toDisplayString(__props.totalPages), 1),
185
185
  __props.showPageSize ? (openBlock(), createElementBlock("div", _hoisted_4$1, [
@@ -241,7 +241,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
241
241
  };
242
242
  }
243
243
  });
244
- const _hoisted_1 = {
244
+ const _hoisted_1$1 = {
245
245
  class: "divide-y divide-gray-200 dark:divide-gray-700",
246
246
  "aria-hidden": "true"
247
247
  };
@@ -254,7 +254,7 @@ const _hoisted_4 = {
254
254
  key: 1,
255
255
  class: "shrink-0 size-8 rounded bg-gray-200 dark:bg-gray-700 animate-pulse"
256
256
  };
257
- const _sfc_main = /* @__PURE__ */ defineComponent({
257
+ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
258
258
  __name: "ListSkeleton",
259
259
  props: {
260
260
  items: { default: 5 },
@@ -264,7 +264,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
264
264
  },
265
265
  setup(__props) {
266
266
  return (_ctx, _cache) => {
267
- return openBlock(), createElementBlock("div", _hoisted_1, [
267
+ return openBlock(), createElementBlock("div", _hoisted_1$1, [
268
268
  (openBlock(true), createElementBlock(Fragment, null, renderList(__props.items, (item) => {
269
269
  return openBlock(), createElementBlock("div", {
270
270
  key: item,
@@ -289,10 +289,64 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
289
289
  };
290
290
  }
291
291
  });
292
+ const _hoisted_1 = {
293
+ key: 0,
294
+ class: "space-y-2",
295
+ "aria-hidden": "true"
296
+ };
297
+ const _sfc_main = /* @__PURE__ */ defineComponent({
298
+ __name: "Skeleton",
299
+ props: {
300
+ variant: { default: "text" },
301
+ width: {},
302
+ height: {},
303
+ lines: { default: 1 },
304
+ animate: { type: Boolean, default: true }
305
+ },
306
+ setup(__props) {
307
+ const variantClasses = {
308
+ text: "h-4 rounded",
309
+ circular: "rounded-full",
310
+ rectangular: "",
311
+ rounded: "rounded-lg"
312
+ };
313
+ return (_ctx, _cache) => {
314
+ return __props.variant === "text" && __props.lines > 1 ? (openBlock(), createElementBlock("div", _hoisted_1, [
315
+ (openBlock(true), createElementBlock(Fragment, null, renderList(__props.lines, (i) => {
316
+ return openBlock(), createElementBlock("div", {
317
+ key: i,
318
+ class: normalizeClass([
319
+ "bg-gray-200 dark:bg-gray-700",
320
+ variantClasses[__props.variant],
321
+ __props.animate && "animate-pulse"
322
+ ]),
323
+ style: normalizeStyle({
324
+ width: i === __props.lines ? "75%" : __props.width || "100%",
325
+ height: __props.height
326
+ })
327
+ }, null, 6);
328
+ }), 128))
329
+ ])) : (openBlock(), createElementBlock("div", {
330
+ key: 1,
331
+ class: normalizeClass([
332
+ "bg-gray-200 dark:bg-gray-700",
333
+ variantClasses[__props.variant],
334
+ __props.animate && "animate-pulse"
335
+ ]),
336
+ style: normalizeStyle({
337
+ width: __props.width || (__props.variant === "circular" ? "3rem" : "100%"),
338
+ height: __props.height || (__props.variant === "circular" ? "3rem" : __props.variant === "text" ? "1rem" : "6rem")
339
+ }),
340
+ "aria-hidden": "true"
341
+ }, null, 6));
342
+ };
343
+ }
344
+ });
292
345
  export {
293
- _sfc_main$1 as _,
294
- _sfc_main$2 as a,
346
+ _sfc_main$2 as _,
347
+ _sfc_main as a,
295
348
  _sfc_main$3 as b,
296
- _sfc_main as c
349
+ _sfc_main$4 as c,
350
+ _sfc_main$1 as d
297
351
  };
298
- //# sourceMappingURL=ListSkeleton.vue_vue_type_script_setup_true_lang-BHopJ9RG.js.map
352
+ //# sourceMappingURL=Skeleton.vue_vue_type_script_setup_true_lang-mcD2ZqKf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Skeleton.vue_vue_type_script_setup_true_lang-mcD2ZqKf.js","sources":["../src/components/feedback/CardSkeleton.vue","../src/components/feedback/TableSkeleton.vue","../src/components/feedback/PaginationControls.vue","../src/components/feedback/ListSkeleton.vue","../src/components/feedback/Skeleton.vue"],"sourcesContent":["<script lang=\"ts\" setup>\r\nwithDefaults(\r\n defineProps<{\r\n /** Show avatar/icon placeholder */\r\n showAvatar?: boolean\r\n /** Number of text lines */\r\n lines?: number\r\n /** Show action buttons */\r\n showActions?: boolean\r\n }>(),\r\n {\r\n showAvatar: false,\r\n lines: 3,\r\n showActions: false,\r\n },\r\n)\r\n</script>\r\n\r\n<template>\r\n <div class=\"bg-white dark:bg-gray-900 rounded-lg shadow-md p-4 space-y-4\" aria-hidden=\"true\">\r\n <!-- Header with avatar -->\r\n <div v-if=\"showAvatar\" class=\"flex items-center gap-3\">\r\n <div class=\"size-10 rounded-full bg-gray-200 dark:bg-gray-700 animate-pulse\" />\r\n <div class=\"flex-1 space-y-2\">\r\n <div class=\"h-4 bg-gray-200 dark:bg-gray-700 rounded animate-pulse w-1/2\" />\r\n <div class=\"h-3 bg-gray-200 dark:bg-gray-700 rounded animate-pulse w-1/3\" />\r\n </div>\r\n </div>\r\n\r\n <!-- Content lines -->\r\n <div class=\"space-y-2\">\r\n <div\r\n v-for=\"line in lines\"\r\n :key=\"line\"\r\n class=\"h-4 bg-gray-200 dark:bg-gray-700 rounded animate-pulse\"\r\n :style=\"{ width: line === lines ? '60%' : '100%' }\"\r\n />\r\n </div>\r\n\r\n <!-- Actions -->\r\n <div v-if=\"showActions\" class=\"flex justify-end gap-2 pt-2\">\r\n <div class=\"h-8 w-20 bg-gray-200 dark:bg-gray-700 rounded animate-pulse\" />\r\n <div class=\"h-8 w-20 bg-gray-200 dark:bg-gray-700 rounded animate-pulse\" />\r\n </div>\r\n </div>\r\n</template>\r\n","<script lang=\"ts\" setup>\r\nwithDefaults(\r\n defineProps<{\r\n /** Number of rows */\r\n rows?: number\r\n /** Number of columns */\r\n columns?: number\r\n /** Show header */\r\n showHeader?: boolean\r\n }>(),\r\n {\r\n rows: 5,\r\n columns: 4,\r\n showHeader: true,\r\n },\r\n)\r\n</script>\r\n\r\n<template>\r\n <div class=\"w-full\" aria-hidden=\"true\">\r\n <!-- Header -->\r\n <div\r\n v-if=\"showHeader\"\r\n class=\"flex gap-4 px-4 py-3 border-b border-gray-200 dark:border-gray-700\"\r\n >\r\n <div\r\n v-for=\"col in columns\"\r\n :key=\"`header-${col}`\"\r\n class=\"flex-1 h-4 bg-gray-200 dark:bg-gray-700 rounded animate-pulse\"\r\n :style=\"{ maxWidth: col === 1 ? '30%' : '20%' }\"\r\n />\r\n </div>\r\n <!-- Rows -->\r\n <div\r\n v-for=\"row in rows\"\r\n :key=\"`row-${row}`\"\r\n class=\"flex items-center gap-4 px-4 py-4 border-b border-gray-100 dark:border-gray-800\"\r\n >\r\n <div\r\n v-for=\"col in columns\"\r\n :key=\"`cell-${row}-${col}`\"\r\n class=\"flex-1 h-4 bg-gray-200 dark:bg-gray-700 rounded animate-pulse\"\r\n :style=\"{\r\n maxWidth: col === 1 ? '40%' : col === columns ? '15%' : '25%',\r\n opacity: 1 - (row * 0.1)\r\n }\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n","<script lang=\"ts\" setup>\r\nimport { computed } from 'vue'\r\nimport { Icon } from '@iconify/vue'\r\n\r\nconst {\r\n currentPage,\r\n totalPages,\r\n loading = false,\r\n pageSize = 10,\r\n pageSizeOptions = [10, 20, 50, 100],\r\n showPageSize = true,\r\n showPageNumbers = true,\r\n maxVisiblePages = 7,\r\n pageLabel = 'Page',\r\n ofLabel = 'of',\r\n itemsPerPageLabel = 'Items per page:',\r\n previousLabel = 'Previous',\r\n nextLabel = 'Next',\r\n} = defineProps<{\r\n currentPage: number\r\n totalPages: number\r\n loading?: boolean\r\n pageSize?: number\r\n pageSizeOptions?: number[]\r\n showPageSize?: boolean\r\n showPageNumbers?: boolean\r\n maxVisiblePages?: number\r\n pageLabel?: string\r\n ofLabel?: string\r\n itemsPerPageLabel?: string\r\n previousLabel?: string\r\n nextLabel?: string\r\n}>()\r\n\r\ntype PageItem = number | 'ellipsis-start' | 'ellipsis-end'\r\n\r\nconst visiblePages = computed<PageItem[]>(() => {\r\n if (totalPages <= maxVisiblePages) {\r\n return Array.from({ length: totalPages }, (_, i) => i + 1)\r\n }\r\n\r\n const pages: PageItem[] = []\r\n const sidePages = Math.floor((maxVisiblePages - 3) / 2)\r\n\r\n // Always show first page\r\n pages.push(1)\r\n\r\n // Calculate range around current page\r\n let rangeStart = Math.max(2, currentPage - sidePages)\r\n let rangeEnd = Math.min(totalPages - 1, currentPage + sidePages)\r\n\r\n // Adjust range to show more pages on one side if near edges\r\n if (currentPage <= sidePages + 2) {\r\n rangeEnd = Math.min(totalPages - 1, maxVisiblePages - 2)\r\n } else if (currentPage >= totalPages - sidePages - 1) {\r\n rangeStart = Math.max(2, totalPages - maxVisiblePages + 3)\r\n }\r\n\r\n // Add ellipsis or pages after first page\r\n if (rangeStart > 2) {\r\n pages.push('ellipsis-start')\r\n }\r\n\r\n // Add range pages\r\n for (let i = rangeStart; i <= rangeEnd; i++) {\r\n pages.push(i)\r\n }\r\n\r\n // Add ellipsis or pages before last page\r\n if (rangeEnd < totalPages - 1) {\r\n pages.push('ellipsis-end')\r\n }\r\n\r\n // Always show last page\r\n if (totalPages > 1) {\r\n pages.push(totalPages)\r\n }\r\n\r\n return pages\r\n})\r\n\r\nconst emit = defineEmits<{\r\n 'update:page': [page: number]\r\n 'update:pageSize': [size: number]\r\n}>()\r\n\r\nconst changePage = (page: number) => {\r\n if (page >= 1 && page <= totalPages && !loading) {\r\n emit('update:page', page)\r\n }\r\n}\r\n\r\nconst changePageSize = (event: Event) => {\r\n const target = event.target as HTMLSelectElement\r\n emit('update:pageSize', Number(target.value))\r\n}\r\n</script>\r\n\r\n<template>\r\n <div\r\n v-if=\"totalPages > 1\"\r\n class=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 border-t border-gray-200 px-4 sm:px-6 py-4 dark:border-gray-700\"\r\n >\r\n <!-- Info and page size -->\r\n <div class=\"flex flex-col sm:flex-row sm:items-center gap-3 sm:gap-4\">\r\n <div class=\"text-sm text-gray-700 dark:text-gray-300 text-center sm:text-left\">\r\n {{ pageLabel }} {{ currentPage }} {{ ofLabel }} {{ totalPages }}\r\n </div>\r\n <div\r\n v-if=\"showPageSize\"\r\n class=\"flex items-center justify-center sm:justify-start gap-2\"\r\n >\r\n <label\r\n class=\"text-sm text-gray-600 dark:text-gray-400 hidden sm:inline\"\r\n for=\"page-size\"\r\n >\r\n {{ itemsPerPageLabel }}\r\n </label>\r\n <select\r\n id=\"page-size\"\r\n :value=\"pageSize\"\r\n class=\"focus:border-primary focus:ring-primary rounded border border-gray-300 bg-white px-2 py-1 text-sm text-gray-900 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100\"\r\n @change=\"changePageSize\"\r\n >\r\n <option\r\n v-for=\"size in pageSizeOptions\"\r\n :key=\"size\"\r\n :value=\"size\"\r\n >\r\n {{ size }}\r\n </option>\r\n </select>\r\n </div>\r\n </div>\r\n\r\n <!-- Navigation buttons -->\r\n <div class=\"flex justify-center sm:justify-end items-center gap-1\">\r\n <!-- Previous button -->\r\n <button\r\n :disabled=\"currentPage === 1 || loading\"\r\n class=\"focus:ring-primary inline-flex items-center gap-1 rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700\"\r\n @click=\"changePage(currentPage - 1)\"\r\n >\r\n <Icon\r\n class=\"size-4\"\r\n icon=\"lucide:chevron-left\"\r\n />\r\n <span class=\"hidden sm:inline\">{{ previousLabel }}</span>\r\n </button>\r\n\r\n <!-- Page numbers -->\r\n <template v-if=\"showPageNumbers\">\r\n <template\r\n v-for=\"page in visiblePages\"\r\n :key=\"page\"\r\n >\r\n <!-- Ellipsis -->\r\n <span\r\n v-if=\"page === 'ellipsis-start' || page === 'ellipsis-end'\"\r\n class=\"px-2 py-2 text-sm text-gray-500 dark:text-gray-400\"\r\n >\r\n …\r\n </span>\r\n <!-- Page number button -->\r\n <button\r\n v-else\r\n :disabled=\"loading\"\r\n :class=\"[\r\n 'min-w-[40px] px-3 py-2 text-sm font-medium rounded-lg border transition-colors',\r\n page === currentPage\r\n ? 'bg-primary-600 text-white border-primary-600 dark:bg-primary-500 dark:border-primary-500'\r\n : 'bg-white text-gray-700 border-gray-300 hover:bg-gray-50 dark:bg-gray-800 dark:text-gray-200 dark:border-gray-600 dark:hover:bg-gray-700',\r\n loading ? 'cursor-not-allowed opacity-50' : ''\r\n ]\"\r\n @click=\"changePage(page)\"\r\n >\r\n {{ page }}\r\n </button>\r\n </template>\r\n </template>\r\n\r\n <!-- Next button -->\r\n <button\r\n :disabled=\"currentPage === totalPages || loading\"\r\n class=\"focus:ring-primary inline-flex items-center gap-1 rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700\"\r\n @click=\"changePage(currentPage + 1)\"\r\n >\r\n <span class=\"hidden sm:inline\">{{ nextLabel }}</span>\r\n <Icon\r\n class=\"size-4\"\r\n icon=\"lucide:chevron-right\"\r\n />\r\n </button>\r\n </div>\r\n </div>\r\n</template>\r\n","<script lang=\"ts\" setup>\r\nwithDefaults(\r\n defineProps<{\r\n /** Number of items */\r\n items?: number\r\n /** Show avatar/icon placeholder */\r\n showAvatar?: boolean\r\n /** Show secondary text */\r\n showSecondary?: boolean\r\n /** Show action button */\r\n showAction?: boolean\r\n }>(),\r\n {\r\n items: 5,\r\n showAvatar: true,\r\n showSecondary: true,\r\n showAction: false,\r\n },\r\n)\r\n</script>\r\n\r\n<template>\r\n <div class=\"divide-y divide-gray-200 dark:divide-gray-700\" aria-hidden=\"true\">\r\n <div\r\n v-for=\"item in items\"\r\n :key=\"item\"\r\n class=\"flex items-center gap-4 py-4 px-4\"\r\n >\r\n <!-- Avatar -->\r\n <div\r\n v-if=\"showAvatar\"\r\n class=\"shrink-0 size-10 rounded-full bg-gray-200 dark:bg-gray-700 animate-pulse\"\r\n />\r\n\r\n <!-- Content -->\r\n <div class=\"flex-1 min-w-0 space-y-2\">\r\n <div\r\n class=\"h-4 bg-gray-200 dark:bg-gray-700 rounded animate-pulse\"\r\n :style=\"{ width: `${60 + Math.random() * 30}%` }\"\r\n />\r\n <div\r\n v-if=\"showSecondary\"\r\n class=\"h-3 bg-gray-200 dark:bg-gray-700 rounded animate-pulse\"\r\n :style=\"{ width: `${40 + Math.random() * 20}%` }\"\r\n />\r\n </div>\r\n\r\n <!-- Action -->\r\n <div\r\n v-if=\"showAction\"\r\n class=\"shrink-0 size-8 rounded bg-gray-200 dark:bg-gray-700 animate-pulse\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n","<script lang=\"ts\" setup>\r\nexport type SkeletonVariant = 'text' | 'circular' | 'rectangular' | 'rounded'\r\n\r\nwithDefaults(\r\n defineProps<{\r\n /** Variant style */\r\n variant?: SkeletonVariant\r\n /** Width (CSS value) */\r\n width?: string\r\n /** Height (CSS value) */\r\n height?: string\r\n /** Number of lines (for text variant) */\r\n lines?: number\r\n /** Animate the skeleton */\r\n animate?: boolean\r\n }>(),\r\n {\r\n variant: 'text',\r\n animate: true,\r\n lines: 1,\r\n },\r\n)\r\n\r\nconst variantClasses: Record<SkeletonVariant, string> = {\r\n text: 'h-4 rounded',\r\n circular: 'rounded-full',\r\n rectangular: '',\r\n rounded: 'rounded-lg',\r\n}\r\n</script>\r\n\r\n<template>\r\n <div\r\n v-if=\"variant === 'text' && lines > 1\"\r\n class=\"space-y-2\"\r\n aria-hidden=\"true\"\r\n >\r\n <div\r\n v-for=\"i in lines\"\r\n :key=\"i\"\r\n :class=\"[\r\n 'bg-gray-200 dark:bg-gray-700',\r\n variantClasses[variant],\r\n animate && 'animate-pulse',\r\n ]\"\r\n :style=\"{\r\n width: i === lines ? '75%' : width || '100%',\r\n height: height,\r\n }\"\r\n />\r\n </div>\r\n <div\r\n v-else\r\n :class=\"[\r\n 'bg-gray-200 dark:bg-gray-700',\r\n variantClasses[variant],\r\n animate && 'animate-pulse',\r\n ]\"\r\n :style=\"{\r\n width: width || (variant === 'circular' ? '3rem' : '100%'),\r\n height: height || (variant === 'circular' ? '3rem' : variant === 'text' ? '1rem' : '6rem'),\r\n }\"\r\n aria-hidden=\"true\"\r\n />\r\n</template>\r\n"],"names":["_openBlock","_createElementBlock","_hoisted_1","_hoisted_2","_createElementVNode","_hoisted_3","_Fragment","_renderList","_normalizeStyle","_hoisted_4","_toDisplayString","_createVNode","_unref","_normalizeClass"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAmBE,aAAAA,UAAA,GAAAC,mBAyBM,OAzBNC,cAyBM;AAAA,QAvBO,QAAA,cAAXF,aAAAC,mBAMM,OANNE,cAMM,CAAA,GAAA,OAAA,CAAA,MAAA,OAAA,CAAA,IAAA;AAAA,UALJC,mBAA+E,OAAA,EAA1E,OAAM,kEAAA,GAAiE,MAAA,EAAA;AAAA,UAC5EA,mBAGM,OAAA,EAHD,OAAM,sBAAkB;AAAA,YAC3BA,mBAA4E,OAAA,EAAvE,OAAM,gEAA8D;AAAA,YACzEA,mBAA4E,OAAA,EAAvE,OAAM,gEAA8D;AAAA,UAAA;;QAK7EA,mBAOM,OAPNC,cAOM;AAAA,4BANJJ,mBAKEK,UAAA,MAAAC,WAJe,QAAA,OAAK,CAAb,SAAI;gCADbN,mBAKE,OAAA;AAAA,cAHC,KAAK;AAAA,cACN,OAAM;AAAA,cACL,OAAKO,eAAA,EAAA,OAAW,SAAS,QAAA,QAAK,QAAA,OAAA,CAAA;AAAA,YAAA;;;QAKxB,QAAA,eAAXR,aAAAC,mBAGM,OAHNQ,cAGM,CAAA,GAAA,OAAA,CAAA,MAAA,OAAA,CAAA,IAAA;AAAA,UAFJL,mBAA2E,OAAA,EAAtE,OAAM,8DAAA,GAA6D,MAAA,EAAA;AAAA,UACxEA,mBAA2E,OAAA,EAAtE,OAAM,8DAAA,GAA6D,MAAA,EAAA;AAAA,QAAA;;;;;;;;;;;;;;;;;;;;;;ACvB5E,aAAAJ,UAAA,GAAAC,mBA6BM,OA7BNC,cA6BM;AAAA,QA1BI,QAAA,cADRF,UAAA,GAAAC,mBAUM,OAVNE,cAUM;AAAA,4BANJF,mBAKEK,UAAA,MAAAC,WAJc,QAAA,SAAO,CAAd,QAAG;gCADZN,mBAKE,OAAA;AAAA,cAHC,eAAe,GAAG;AAAA,cACnB,OAAM;AAAA,cACL,kCAAmB,QAAG,IAAA,QAAA,OAAA;AAAA,YAAA;;;0BAI3BA,mBAcMK,UAAA,MAAAC,WAbU,QAAA,MAAI,CAAX,QAAG;8BADZN,mBAcM,OAAA;AAAA,YAZH,YAAY,GAAG;AAAA,YAChB,OAAM;AAAA,UAAA;8BAENA,mBAQEK,UAAA,MAAAC,WAPc,QAAA,SAAO,CAAd,QAAG;kCADZN,mBAQE,OAAA;AAAA,gBANC,KAAG,QAAU,GAAG,IAAI,GAAG;AAAA,gBACxB,OAAM;AAAA,gBACL,OAAKO,eAAA;AAAA,4BAAyB,QAAG,IAAA,QAAiB,QAAQ,QAAA,UAAO,QAAA;AAAA,+BAA2C,MAAG;AAAA,gBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACNxH,UAAM,eAAe,SAAqB,MAAM;AAC9C,UAAI,QAAA,cAAc,QAAA,iBAAiB;AACjC,eAAO,MAAM,KAAK,EAAE,QAAQ,QAAA,WAAA,GAAc,CAAC,GAAG,MAAM,IAAI,CAAC;AAAA,MAC3D;AAEA,YAAM,QAAoB,CAAA;AAC1B,YAAM,YAAY,KAAK,OAAO,0BAAkB,KAAK,CAAC;AAGtD,YAAM,KAAK,CAAC;AAGZ,UAAI,aAAa,KAAK,IAAI,GAAG,sBAAc,SAAS;AACpD,UAAI,WAAW,KAAK,IAAI,qBAAa,GAAG,QAAA,cAAc,SAAS;AAG/D,UAAI,uBAAe,YAAY,GAAG;AAChC,mBAAW,KAAK,IAAI,QAAA,aAAa,GAAG,QAAA,kBAAkB,CAAC;AAAA,MACzD,WAAW,QAAA,eAAe,QAAA,aAAa,YAAY,GAAG;AACpD,qBAAa,KAAK,IAAI,GAAG,QAAA,aAAa,QAAA,kBAAkB,CAAC;AAAA,MAC3D;AAGA,UAAI,aAAa,GAAG;AAClB,cAAM,KAAK,gBAAgB;AAAA,MAC7B;AAGA,eAAS,IAAI,YAAY,KAAK,UAAU,KAAK;AAC3C,cAAM,KAAK,CAAC;AAAA,MACd;AAGA,UAAI,WAAW,QAAA,aAAa,GAAG;AAC7B,cAAM,KAAK,cAAc;AAAA,MAC3B;AAGA,UAAI,QAAA,aAAa,GAAG;AAClB,cAAM,KAAK,kBAAU;AAAA,MACvB;AAEA,aAAO;AAAA,IACT,CAAC;AAED,UAAM,OAAO;AAKb,UAAM,aAAa,CAAC,SAAiB;AACnC,UAAI,QAAQ,KAAK,QAAQ,QAAA,cAAc,CAAC,QAAA,SAAS;AAC/C,aAAK,eAAe,IAAI;AAAA,MAC1B;AAAA,IACF;AAEA,UAAM,iBAAiB,CAAC,UAAiB;AACvC,YAAM,SAAS,MAAM;AACrB,WAAK,mBAAmB,OAAO,OAAO,KAAK,CAAC;AAAA,IAC9C;;aAKU,QAAA,aAAU,KADlBR,aAAAC,mBA+FM,OA/FNC,cA+FM;AAAA,QA1FJE,mBA6BM,OA7BND,cA6BM;AAAA,UA5BJC,mBAEM,OAFNC,cAEMK,gBADD,QAAA,SAAS,IAAG,MAACA,gBAAG,QAAA,WAAW,IAAG,MAACA,gBAAG,QAAA,OAAO,IAAG,sBAAI,QAAA,UAAU,GAAA,CAAA;AAAA,UAGvD,QAAA,gBADRV,UAAA,GAAAC,mBAwBM,OAxBNQ,cAwBM;AAAA,YApBJL,mBAKQ,SALR,YAKQM,gBADH,QAAA,iBAAiB,GAAA,CAAA;AAAA,YAEtBN,mBAaS,UAAA;AAAA,cAZP,IAAG;AAAA,cACF,OAAO,QAAA;AAAA,cACR,OAAM;AAAA,cACL,UAAQ;AAAA,YAAA;gCAETH,mBAMSK,UAAA,MAAAC,WALQ,QAAA,iBAAe,CAAvB,SAAI;oCADbN,mBAMS,UAAA;AAAA,kBAJN,KAAK;AAAA,kBACL,OAAO;AAAA,gBAAA,mBAEL,IAAI,GAAA,GAAA,UAAA;AAAA;;;;QAOfG,mBAyDM,OAzDN,YAyDM;AAAA,UAvDJA,mBAUS,UAAA;AAAA,YATN,UAAU,QAAA,gBAAW,KAAU,QAAA;AAAA,YAChC,OAAM;AAAA,YACL,SAAK,OAAA,CAAA,MAAA,OAAA,CAAA,IAAA,CAAA,WAAE,WAAW,QAAA,cAAW,CAAA;AAAA,UAAA;YAE9BO,YAGEC,MAAA,IAAA,GAAA;AAAA,cAFA,OAAM;AAAA,cACN,MAAK;AAAA,YAAA;YAEPR,mBAAyD,QAAzD,aAAyDM,gBAAvB,QAAA,aAAa,GAAA,CAAA;AAAA,UAAA;UAIjC,QAAA,oCACdT,mBA0BWK,UAAA,EAAA,KAAA,KAAAC,WAzBM,aAAA,OAAY,CAApB,SAAI;oEACL,QAAI;AAAA,cAIF,6BAA6B,SAAI,+BADzCN,mBAKO,QALP,aAGC,KAED,mBAEAA,mBAaS,UAAA;AAAA;gBAXN,UAAU,QAAA;AAAA,gBACV,OAAKY,eAAA;AAAA;kBAAoH,SAAS,QAAA;kBAAuS,QAAA,UAAO,kCAAA;AAAA,gBAAA;gBAOhb,SAAK,CAAA,WAAE,WAAW,IAAI;AAAA,cAAA,mBAEpB,IAAI,GAAA,IAAA,WAAA;AAAA,YAAA;;UAMbT,mBAUS,UAAA;AAAA,YATN,UAAU,QAAA,gBAAgB,QAAA,cAAc,QAAA;AAAA,YACzC,OAAM;AAAA,YACL,SAAK,OAAA,CAAA,MAAA,OAAA,CAAA,IAAA,CAAA,WAAE,WAAW,QAAA,cAAW,CAAA;AAAA,UAAA;YAE9BA,mBAAqD,QAArD,aAAqDM,gBAAnB,QAAA,SAAS,GAAA,CAAA;AAAA,YAC3CC,YAGEC,MAAA,IAAA,GAAA;AAAA,cAFA,OAAM;AAAA,cACN,MAAK;AAAA,YAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxKb,aAAAZ,UAAA,GAAAC,mBA+BM,OA/BNC,cA+BM;AAAA,0BA9BJD,mBA6BMK,UAAA,MAAAC,WA5BW,QAAA,OAAK,CAAb,SAAI;8BADbN,mBA6BM,OAAA;AAAA,YA3BH,KAAK;AAAA,YACN,OAAM;AAAA,UAAA;YAIE,QAAA,cADRD,UAAA,GAAAC,mBAGE,OAHF,UAGE;YAGFG,mBAUM,OAVN,YAUM;AAAA,cATJA,mBAGE,OAAA;AAAA,gBAFA,OAAM;AAAA,gBACL,OAAKI,eAAA,EAAA,OAAA,GAAA,KAAmB,KAAK,OAAA,IAAM,EAAA,IAAA,CAAA;AAAA,cAAA;cAG9B,QAAA,8BADRP,mBAIE,OAAA;AAAA;gBAFA,OAAM;AAAA,gBACL,OAAKO,eAAA,EAAA,OAAA,GAAA,KAAmB,KAAK,OAAA,IAAM,EAAA,IAAA,CAAA;AAAA,cAAA;;YAMhC,QAAA,cADRR,UAAA,GAAAC,mBAGE,OAHF,UAGE;;;;;;;;;;;;;;;;;;;;;;AC5BR,UAAM,iBAAkD;AAAA,MACtD,MAAM;AAAA,MACN,UAAU;AAAA,MACV,aAAa;AAAA,MACb,SAAS;AAAA,IAAA;;AAMD,aAAA,QAAA,sBAAsB,QAAA,QAAK,KADnCD,UAAA,GAAAC,mBAkBM,OAlBN,YAkBM;AAAA,0BAbJA,mBAYEK,UAAA,MAAAC,WAXY,QAAA,OAAK,CAAV,MAAC;8BADVN,mBAYE,OAAA;AAAA,YAVC,KAAK;AAAA,YACL,OAAKY,eAAA;AAAA;cAAsD,eAAe,QAAA,OAAO;AAAA,cAAY,QAAA,WAAO;AAAA,YAAA;YAKpG,OAAKL,eAAA;AAAA,qBAAoB,MAAM,QAAA,QAAK,QAAW,QAAA,SAAK;AAAA,sBAA6B,QAAA;AAAA,YAAA;;;0BAMtFP,mBAYE,OAAA;AAAA;QAVC,OAAKY,eAAA;AAAA;UAAkD,eAAe,QAAA,OAAO;AAAA,UAAU,QAAA,WAAO;AAAA,QAAA;QAK9F,OAAKL,eAAA;AAAA,UAAkB,OAAA,QAAA,UAAU,QAAA,YAAO,aAAA,SAAA;AAAA,kBAAmD,QAAA,WAAW,QAAA,YAAO,aAAA,SAA2B,QAAA,YAAO,SAAA,SAAA;AAAA,QAAA;QAIhJ,eAAY;AAAA,MAAA;;;;"}
@@ -0,0 +1,44 @@
1
+ import { Meta, StoryObj } from '@storybook/vue3-vite';
2
+ import { default as StatItem } from './StatItem.vue';
3
+ declare const meta: Meta<typeof StatItem>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof meta>;
6
+ export declare const Default: Story;
7
+ export declare const WithPrefixAndSuffix: Story;
8
+ export declare const WithDescription: Story;
9
+ export declare const WithChange: Story;
10
+ export declare const NegativeChange: Story;
11
+ export declare const InvertedTrendColors: Story;
12
+ export declare const IconLeft: Story;
13
+ export declare const IconRight: Story;
14
+ export declare const IconBottom: Story;
15
+ export declare const RoundIcon: Story;
16
+ export declare const NoIconBackground: Story;
17
+ export declare const LabelFirst: Story;
18
+ export declare const XSmallSize: Story;
19
+ export declare const SmallSize: Story;
20
+ export declare const LargeSize: Story;
21
+ export declare const XLargeSize: Story;
22
+ export declare const CompactMode: Story;
23
+ export declare const TrendOnly: Story;
24
+ export declare const HideTrendIcon: Story;
25
+ export declare const GlassVariant: Story;
26
+ export declare const OutlineVariant: Story;
27
+ export declare const FlatVariant: Story;
28
+ export declare const SolidVariant: Story;
29
+ export declare const SolidSuccess: Story;
30
+ export declare const SolidDanger: Story;
31
+ export declare const WithAccent: Story;
32
+ export declare const SuccessColor: Story;
33
+ export declare const WarningColor: Story;
34
+ export declare const DangerColor: Story;
35
+ export declare const InfoColor: Story;
36
+ export declare const NoIcon: Story;
37
+ export declare const Clickable: Story;
38
+ export declare const Loading: Story;
39
+ export declare const AllSizes: Story;
40
+ export declare const AllIconPositions: Story;
41
+ export declare const AllColors: Story;
42
+ export declare const AllVariants: Story;
43
+ export declare const AllIconRounded: Story;
44
+ export declare const DashboardMetrics: Story;
@@ -0,0 +1,135 @@
1
+ import { CardShadow, CardRounded, CardBorder, CardAccent } from './CardWrapper.vue';
2
+ export type StatItemSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
3
+ export type StatItemIconPosition = 'top' | 'left' | 'right' | 'bottom';
4
+ export type StatItemVariant = 'default' | 'glass' | 'outline' | 'flat' | 'solid';
5
+ export type StatItemColor = 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info';
6
+ export type StatItemTrend = 'up' | 'down' | 'neutral';
7
+ export type StatItemIconRounded = 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full';
8
+ export interface StatItemData {
9
+ label: string;
10
+ value: string | number;
11
+ icon?: string;
12
+ change?: number;
13
+ changeLabel?: string;
14
+ trend?: StatItemTrend;
15
+ color?: StatItemColor;
16
+ description?: string;
17
+ prefix?: string;
18
+ suffix?: string;
19
+ }
20
+ type __VLS_Props = {
21
+ /** Stat label */
22
+ label: string;
23
+ /** Stat value */
24
+ value: string | number;
25
+ /** Description text below label */
26
+ description?: string;
27
+ /** Prefix for value (e.g., "$") */
28
+ prefix?: string;
29
+ /** Suffix for value (e.g., "%", "users") */
30
+ suffix?: string;
31
+ /** Icon name (iconify format) */
32
+ icon?: string;
33
+ /** Icon position */
34
+ iconPosition?: StatItemIconPosition;
35
+ /** Icon border radius */
36
+ iconRounded?: StatItemIconRounded;
37
+ /** Hide icon background */
38
+ hideIconBg?: boolean;
39
+ /** Percentage change (positive or negative) */
40
+ change?: number;
41
+ /** Change label (e.g., "vs last month") */
42
+ changeLabel?: string;
43
+ /** Explicit trend direction (overrides change-based calculation) */
44
+ trend?: StatItemTrend;
45
+ /** Show only trend arrow without percentage */
46
+ trendOnly?: boolean;
47
+ /** Hide trend icon, show only text */
48
+ hideTrendIcon?: boolean;
49
+ /** Invert trend colors (green for down, red for up) */
50
+ invertTrendColors?: boolean;
51
+ /** Size variant */
52
+ size?: StatItemSize;
53
+ /** Visual variant */
54
+ variant?: StatItemVariant;
55
+ /** Color scheme */
56
+ color?: StatItemColor;
57
+ /** Make the stat clickable */
58
+ clickable?: boolean;
59
+ /** Center content (default: true for top/bottom icon, false for left/right) */
60
+ centered?: boolean;
61
+ /** Show label before value */
62
+ labelFirst?: boolean;
63
+ /** Compact mode (reduced padding) */
64
+ compact?: boolean;
65
+ /** Loading state */
66
+ loading?: boolean;
67
+ /** Card shadow level */
68
+ shadow?: CardShadow;
69
+ /** Card border radius */
70
+ rounded?: CardRounded;
71
+ /** Card border style */
72
+ border?: CardBorder;
73
+ /** Card accent color */
74
+ accent?: CardAccent;
75
+ /** Custom class for the card */
76
+ cardClass?: string;
77
+ /** Custom class for the icon wrapper */
78
+ iconWrapperClass?: string;
79
+ /** Custom class for the icon element */
80
+ iconClass?: string;
81
+ /** Custom class for the value */
82
+ valueClass?: string;
83
+ /** Custom class for the label */
84
+ labelClass?: string;
85
+ /** Custom class for the description */
86
+ descriptionClass?: string;
87
+ /** Custom class for the trend indicator */
88
+ trendClass?: string;
89
+ /** Custom class for the content wrapper */
90
+ contentClass?: string;
91
+ };
92
+ declare function __VLS_template(): {
93
+ attrs: Partial<{}>;
94
+ slots: {
95
+ icon?(_: {}): any;
96
+ label?(_: {}): any;
97
+ label?(_: {}): any;
98
+ value?(_: {}): any;
99
+ description?(_: {}): any;
100
+ extra?(_: {}): any;
101
+ };
102
+ refs: {};
103
+ rootEl: any;
104
+ };
105
+ type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
106
+ declare const __VLS_component: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
107
+ click: (event: MouseEvent) => any;
108
+ }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
109
+ onClick?: ((event: MouseEvent) => any) | undefined;
110
+ }>, {
111
+ rounded: CardRounded;
112
+ loading: boolean;
113
+ shadow: CardShadow;
114
+ border: CardBorder;
115
+ variant: StatItemVariant;
116
+ accent: CardAccent;
117
+ clickable: boolean;
118
+ color: StatItemColor;
119
+ compact: boolean;
120
+ size: StatItemSize;
121
+ iconPosition: StatItemIconPosition;
122
+ iconRounded: StatItemIconRounded;
123
+ hideIconBg: boolean;
124
+ trendOnly: boolean;
125
+ hideTrendIcon: boolean;
126
+ invertTrendColors: boolean;
127
+ labelFirst: boolean;
128
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
129
+ declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
130
+ export default _default;
131
+ type __VLS_WithTemplateSlots<T, S> = T & {
132
+ new (): {
133
+ $slots: S;
134
+ };
135
+ };