edvoyui-component-library-test-flight 0.0.168 → 0.0.170

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 (69) hide show
  1. package/package.json +10 -3
  2. package/src/App.vue +0 -16
  3. package/src/assets/svg/CheckTick.vue +0 -21
  4. package/src/assets/svg/ChevronBigDown.vue +0 -22
  5. package/src/assets/svg/ChevronDownSolid.vue +0 -19
  6. package/src/assets/svg/ChevronDownStroke.vue +0 -22
  7. package/src/assets/svg/ChevronDownStrokeSolid.vue +0 -19
  8. package/src/assets/svg/SearchBigZoomIn.vue +0 -21
  9. package/src/assets/svg/SortArrow.vue +0 -24
  10. package/src/assets/svg/Student.vue +0 -30
  11. package/src/assets/svg/partner.vue +0 -33
  12. package/src/assets/svg/people.vue +0 -25
  13. package/src/components/HelloWorld.vue +0 -1974
  14. package/src/components/accordion/EUIAccordion.vue +0 -152
  15. package/src/components/alerts/EUIAlerts.vue +0 -194
  16. package/src/components/avatar/EUIAvatar.vue +0 -96
  17. package/src/components/breadcrumb/EUIBreadcrumb.vue +0 -59
  18. package/src/components/button/EUIButton.vue +0 -154
  19. package/src/components/button/EUIButtonGroup.vue +0 -287
  20. package/src/components/button/buttonAnimateTab.vue +0 -74
  21. package/src/components/checkbox/EUICheckbox.vue +0 -110
  22. package/src/components/datepicker/EUIDatepicker.vue +0 -295
  23. package/src/components/delete.vue +0 -262
  24. package/src/components/dragModal/EUIDrag.vue +0 -179
  25. package/src/components/dropdown/EUIMultiDropdown.vue +0 -174
  26. package/src/components/errorMessage/EUIErrorMessage.vue +0 -25
  27. package/src/components/input/EUIInput.vue +0 -223
  28. package/src/components/input/EUINumberInput.vue +0 -250
  29. package/src/components/loader/EUICircleLoader.vue +0 -31
  30. package/src/components/loader/EUICubeLoader.vue +0 -237
  31. package/src/components/loader/EUILoader.vue +0 -17
  32. package/src/components/loader/EUISquareLoader.vue +0 -47
  33. package/src/components/modal/EUIModal.vue +0 -224
  34. package/src/components/pillSelect/EUIPillSelect.vue +0 -149
  35. package/src/components/popover/EUIPopover.vue +0 -297
  36. package/src/components/radio/EUIRadio.vue +0 -75
  37. package/src/components/searchInput/EUISearch.vue +0 -223
  38. package/src/components/searchTagSelect/EUISearchTagSelect.vue +0 -642
  39. package/src/components/searchTagSelect/SearchInput.vue +0 -167
  40. package/src/components/searchexpand/EUISearchExpand.vue +0 -148
  41. package/src/components/searchexpand/EUISearchToggle.vue +0 -86
  42. package/src/components/select/EUISelect.vue +0 -1092
  43. package/src/components/selectSearch/EUISelectSearch.vue +0 -23
  44. package/src/components/slideover/EUISlideover.vue +0 -207
  45. package/src/components/stepperTimeline/EUIStepperHorizontal.vue +0 -242
  46. package/src/components/stepperTimeline/EUIStepperTimeline.vue +0 -16
  47. package/src/components/stepperTimeline/EUIStepperVertical.vue +0 -112
  48. package/src/components/table/ColumnResizeTable.vue +0 -740
  49. package/src/components/table/EUIDashboardTable.vue +0 -514
  50. package/src/components/table/EUIPageLimit.vue +0 -66
  51. package/src/components/table/EUIPagination.vue +0 -175
  52. package/src/components/table/EUIStudentPagination.vue +0 -172
  53. package/src/components/table/EUITable.vue +0 -559
  54. package/src/components/table/EUITableCheckbox.vue +0 -98
  55. package/src/components/table/GrowthTable.vue +0 -575
  56. package/src/components/table/GrowthTableView.vue +0 -108
  57. package/src/components/table/ResizeTableview.vue +0 -198
  58. package/src/components/table/UCheckbox.vue +0 -169
  59. package/src/components/table/UTable.vue +0 -611
  60. package/src/components/table/UTableview.vue +0 -189
  61. package/src/components/tabs/EUITabOutline.vue +0 -263
  62. package/src/components/tabs/EUITabs.vue +0 -226
  63. package/src/components/tag/EUITag.vue +0 -88
  64. package/src/components/telephone/EUITelephone.vue +0 -299
  65. package/src/components/textArea/EUITextArea.vue +0 -155
  66. package/src/components/timeLine/EUITimeLine.vue +0 -148
  67. package/src/components/toggle/EUIToggle.vue +0 -101
  68. package/src/components/tooltip/EUITooltip.vue +0 -111
  69. package/src/components/uidemo/select-com.vue +0 -120
@@ -1,559 +0,0 @@
1
- <template>
2
- <div>
3
- <Transition name="fade" mode="out-in">
4
- <template v-if="loading">
5
- <slot name="loader" :loading="loading" :height="tableHeight">
6
- <div
7
- :class="[
8
- 'overflow-hidden relative z-0 isolate bg-white backdrop-blur transition-colors duration-150 ease-in-out rounded-xl border border-gray-50',
9
- tableHeight
10
- ? tableHeight
11
- : 'h-[calc(100svh-9rem)] max-h-[calc(100svh-9rem)]',
12
- ]"
13
- >
14
- <div
15
- class="absolute flex items-center z-[calc(infinity)] w-full h-auto pointer-events-none inset-0"
16
- >
17
- <EUICircleLoader />
18
- </div>
19
- </div>
20
- </slot>
21
- </template>
22
-
23
- <div v-else class="relative w-full mx-auto overflow-hidden">
24
- <div
25
- id="student-table"
26
- :class="[
27
- 'scrollbar--thin overscroll-auto',
28
- computedItems.length === 0 ? 'overflow-hidden' : 'overflow-auto',
29
- tableHeight
30
- ? tableHeight
31
- : 'h-[calc(100svh-12rem)] max-h-[calc(100svh-12rem)]',
32
- ]"
33
- ref="tableContainer"
34
- @scroll="handleScroll"
35
- >
36
- <table class="eui-table">
37
- <thead
38
- class="sticky top-0 left-0 z-20 bg-gray-100 before:-bottom-px before:left-0 before:absolute before:h-px before:w-full before:bg-gray-300"
39
- >
40
- <tr>
41
- <template v-if="checkable">
42
- <th class="checkable">
43
- <EUITableCheckbox
44
- :checked="isAllChecked"
45
- :indeterminate="isIndeterminate"
46
- :disabled="isAllUncheckable"
47
- class="flex justify-center mt-0"
48
- @change="checkAll"
49
- />
50
- </th>
51
- </template>
52
- <th
53
- v-for="(header, headerIndex) in headers"
54
- :key="`item-${headerIndex}`"
55
- scope="col"
56
- :class="[
57
- 'px-3 py-2 text-gray-600 snap-start snap-always',
58
- isScrolled && headerIndex === 0 ? stickyClass.head : '',
59
- { 'cursor-pointer hover:text-gray-900': header?.sortable },
60
- ]"
61
- :style="
62
- header?.width
63
- ? `min-width:${header?.width}px;max-width:${header?.width}px;`
64
- : ``
65
- "
66
- @click="sortBy(header, $event)"
67
- >
68
- <div
69
- class="flex items-center justify-between gap-2 text-sm font-medium text-current font-inter"
70
- >
71
- <slot name="header" :header="header" :index="headerIndex">
72
- {{ capitalizeText(header?.text ?? header?.name ?? "") }}
73
- </slot>
74
- <slot name="headerOptionalItem"></slot>
75
- <div v-if="header?.sortable" class="flex-none">
76
- <svg
77
- width="24"
78
- height="24"
79
- viewBox="0 0 24 24"
80
- fill="none"
81
- xmlns="http://www.w3.org/2000/svg"
82
- class="size-6"
83
- >
84
- <path
85
- d="M8 15C9.06206 16.4619 10.3071 17.7713 11.7021 18.8942C11.8774 19.0353 12.1226 19.0353 12.2979 18.8942C13.6929 17.7713 14.9379 16.4619 16 15"
86
- :stroke="
87
- currentSortDir === 'asc' &&
88
- currentSort === header?.value
89
- ? '#111827'
90
- : '#9ca3af'
91
- "
92
- stroke-opacity="0.8"
93
- stroke-width="2"
94
- stroke-linecap="round"
95
- stroke-linejoin="round"
96
- />
97
- <path
98
- d="M8 9C9.06206 7.5381 10.3071 6.2287 11.7021 5.1058C11.8774 4.9647 12.1226 4.9647 12.2979 5.1058C13.6929 6.2287 14.9379 7.5381 16 9"
99
- :stroke="
100
- currentSortDir === 'desc' &&
101
- currentSort === header?.value
102
- ? '#111827'
103
- : '#9ca3af'
104
- "
105
- stroke-opacity="0.8"
106
- stroke-width="2"
107
- stroke-linecap="round"
108
- stroke-linejoin="round"
109
- />
110
- </svg>
111
- </div>
112
- </div>
113
- </th>
114
- </tr>
115
- </thead>
116
- <tbody>
117
- <template
118
- v-if="computedItems.length > 0"
119
- v-for="(row, rowIndex) in computedItems"
120
- :key="`table-row-${rowIndex}`"
121
- >
122
- <tr
123
- :id="`row-${rowIndex}`"
124
- :class="
125
- activeRowIndex == rowIndex
126
- ? '!bg-purple-50 !ring-1 !ring-purple-100 !ring-inset'
127
- : ''
128
- "
129
- @mouseenter="
130
- $attrs.mouseenter
131
- ? $emit('mouseenter', row, rowIndex)
132
- : null
133
- "
134
- @mouseleave="
135
- $attrs.mouseleave
136
- ? $emit('mouseleave', row, rowIndex)
137
- : null
138
- "
139
- >
140
- <template v-if="checkable">
141
- <td
142
- class="checkable"
143
- :class="
144
- activeRowIndex == rowIndex
145
- ? '!bg-purple-50 !ring-1 !ring-purple-100 !ring-inset'
146
- : ''
147
- "
148
- >
149
- <EUITableCheckbox
150
- :disabled="!isRowCheckable(row)"
151
- :checked="isRowChecked(row)"
152
- @change.prevent.stop="
153
- ($event) => checkRow(row, rowIndex, $event)
154
- "
155
- />
156
- </td>
157
- </template>
158
- <td
159
- v-for="(header, headerIndex) in headers"
160
- :key="headerIndex"
161
- :class="[
162
- isScrolled && headerIndex === 0 ? stickyClass.body : '',
163
- activeRowIndex == rowIndex
164
- ? '!bg-purple-50 !ring-1 !ring-purple-100 !ring-inset'
165
- : '',
166
- ]"
167
- >
168
- <slot
169
- :name="`item.${header?.value}`"
170
- :row="row"
171
- :rowIndex="rowIndex"
172
- :headerIndex="headerIndex"
173
- >
174
- {{ getValueByPath(row, header?.value) }}
175
- </slot>
176
- </td>
177
- </tr>
178
- <template v-if="tableExpanded">
179
- <slot name="expanded" :row="row" :rowIndex="rowIndex"></slot>
180
- </template>
181
- </template>
182
- <template v-else-if="computedItems.length === 0">
183
- <tr class="norecords">
184
- <td
185
- :colspan="
186
- checkable === true ? headers.length + 1 : headers.length
187
- "
188
- >
189
- <slot name="no-records">
190
- <div
191
- class="flex items-center justify-center text-xl font-medium text-gray-500 h-[calc(100svh-18rem)] max-w-screen-xl"
192
- >
193
- No matching records found
194
- </div>
195
- </slot>
196
- </td>
197
- </tr>
198
- </template>
199
- </tbody>
200
- </table>
201
- </div>
202
- <div
203
- class="sticky bottom-0 left-0 z-50 flex items-center justify-between px-2 py-1 bg-white border-t border-gray-300"
204
- >
205
- <slot name="tableCount">
206
- <div class="inline-flex items-center gap-x-2">
207
- <div class="text-sm font-medium text-gray-900">
208
- Total {{ total }}
209
- </div>
210
- <span class="text-gray-300">&vert;</span>
211
- <div class="inline-flex items-center">
212
- <span class="text-sm font-medium text-gray-900">Per page</span>
213
- <EUIPageLimit
214
- :page-limit="limit"
215
- @update-limit="changeLimit($event)"
216
- @refetch="searchData($event)"
217
- :iconStyle="true"
218
- />
219
- </div>
220
- </div>
221
- </slot>
222
- <template v-if="paginated && computedItems.length !== 0">
223
- <slot name="tablepagination">
224
- <EUIStudentPagination
225
- :activePage="newCurrentPage"
226
- :pageLimit="limit"
227
- :totalCount="total"
228
- @change-page="pageChanged($event)"
229
- />
230
- </slot>
231
- </template>
232
- </div>
233
- </div>
234
- </Transition>
235
- </div>
236
- </template>
237
-
238
- <script setup lang="ts">
239
- import {
240
- computed,
241
- onMounted,
242
- onUnmounted,
243
- PropType,
244
- ref,
245
- toRefs,
246
- watch,
247
- } from "vue";
248
- import EUITableCheckbox from "./EUITableCheckbox.vue";
249
- import EUIPageLimit from "./EUIPageLimit.vue";
250
- import EUIStudentPagination from "./EUIStudentPagination.vue";
251
- import { capitalizeText } from "../../utils/lodash";
252
- import EUICircleLoader from "../loader/EUICircleLoader.vue";
253
- import { indexOf, getValueByPath, defaultFilter } from "../../utils/helpers";
254
-
255
- interface Header {
256
- value: string;
257
- text?: string;
258
- name?: string;
259
- width?: number;
260
- sortable?: boolean;
261
- }
262
-
263
- const props = defineProps({
264
- checkable: {
265
- type: Boolean,
266
- default: false,
267
- },
268
- stickyColumn: { type: Boolean, default: true },
269
- paginated: { type: Boolean, default: false },
270
- tableExpanded: { type: Boolean, default: false },
271
- backendPagination: { type: Boolean, default: false },
272
- checkedRows: { type: Array, default: () => ({}), required: true },
273
- headers: {
274
- type: Array as PropType<Header[]>,
275
- default: () => ({}),
276
- required: true,
277
- },
278
- items: { type: Array, required: true, default: () => ({}) },
279
- defaultSort: { type: String, default: "" },
280
- defaultSortDirection: { type: String, default: "asc" },
281
- search: { type: String, default: "" },
282
- perPage: { type: Number, default: 5 },
283
-
284
- activeRowIndex: { type: Number, default: null },
285
- currentPage: { type: Number, default: 0 },
286
- total: { type: Number, default: 0 },
287
- customIsChecked: {
288
- type: Function as PropType<(item: any, obj: any) => boolean>,
289
- default: () => () => false,
290
- },
291
- isRowCheckable: { type: Function, default: () => true },
292
- tableHeight: {
293
- type: String,
294
- required: false,
295
- default: "",
296
- },
297
- tableLoading: { type: Boolean, default: false },
298
- });
299
-
300
- const {
301
- defaultSort,
302
- defaultSortDirection,
303
- checkedRows,
304
- currentPage,
305
- items,
306
- backendPagination,
307
- total,
308
- search,
309
- headers,
310
- paginated,
311
- isRowCheckable,
312
- activeRowIndex,
313
- } = toRefs(props);
314
-
315
- const currentSort = ref(defaultSort.value);
316
- const currentSortDir = ref(defaultSortDirection.value);
317
- const newCheckedRows = ref([...checkedRows.value]);
318
- const newCurrentPage = ref(currentPage.value);
319
- const limit = ref(props.perPage);
320
- const loading = computed(() => props.tableLoading);
321
-
322
- // Computed Property
323
- const filteredItems = computed(() => {
324
- let filteredItems = items.value.slice();
325
- if (!backendPagination.value && search.value !== "") {
326
- if (search.value.trim() === "") return filteredItems;
327
- const props = headers.value.map((h: any) => h.value);
328
- filteredItems = items.value.filter((row) =>
329
- props.some((prop) =>
330
- defaultFilter(
331
- getValueByPath(row, prop),
332
- search.value.toString().toLowerCase()
333
- )
334
- )
335
- );
336
- }
337
- return filteredItems;
338
- });
339
-
340
- const computedItems = computed(() => {
341
- let items = filteredItems.value;
342
- // Sort items before slicing for pagination
343
- items.sort((a: any, b: any) => {
344
- const modifier = currentSortDir.value === "desc" ? -1 : 1;
345
- if (a[currentSort.value] < b[currentSort.value]) return -1 * modifier;
346
- if (a[currentSort.value] > b[currentSort.value]) return 1 * modifier;
347
- return 0;
348
- });
349
- return items;
350
-
351
- // Apply pagination
352
- // const start = (newCurrentPage.value - 0) * limit.value;
353
- // const end = start + limit.value;
354
- // return items.slice(start, end);
355
- });
356
-
357
- const searchData = (_data: any) => {
358
- // console.log(_data);
359
- };
360
-
361
- const isIndeterminate = computed(() => {
362
- const validVisibleData = computedItems.value.filter((row) =>
363
- isRowCheckable.value(row)
364
- );
365
- return (
366
- newCheckedRows.value.length > 0 &&
367
- newCheckedRows.value.length < validVisibleData.length
368
- );
369
- });
370
-
371
- const isAllChecked = computed(() => {
372
- return (
373
- computedItems.value.length > 0 &&
374
- computedItems.value.every((row) => newCheckedRows.value.includes(row))
375
- );
376
- });
377
-
378
- const isAllUncheckable = computed(() => {
379
- const validVisibleData = computedItems.value?.filter((row) =>
380
- isRowCheckable.value!(row)
381
- );
382
- return validVisibleData.length === 0;
383
- });
384
-
385
- // methods
386
- const emit = defineEmits([
387
- "update:currentPage",
388
- "changePage",
389
- "sort",
390
- "check",
391
- "check-all",
392
- "update:checkedRows",
393
- "update:selectedRows",
394
- "changeLimit",
395
- "mouseenter",
396
- "mouseleave",
397
- ]);
398
-
399
- const changeLimit = (limitData: number) => {
400
- limit.value = limitData;
401
- newCurrentPage.value = 0;
402
- emit("update:currentPage", newCurrentPage.value);
403
- emit("changeLimit", limitData);
404
- };
405
-
406
- const pageChanged = (page: number) => {
407
- newCurrentPage.value = page > 0 ? page : 0;
408
- emit("update:currentPage", newCurrentPage.value);
409
- emit("changePage", page);
410
- };
411
-
412
- const sortBy = (header: any, event: any) => {
413
- if (!header || !header.sortable) return;
414
- if (header.value === currentSort.value) {
415
- currentSortDir.value = currentSortDir.value === "asc" ? "desc" : "asc";
416
- }
417
- currentSort.value = header.value;
418
- emit("sort", currentSort.value, currentSortDir.value, event);
419
- };
420
-
421
- const isRowChecked = (row: any) => {
422
- return indexOf(newCheckedRows.value, row) >= 0;
423
- };
424
-
425
- const removeCheckedRow = (row: any) => {
426
- const index = indexOf(newCheckedRows.value, row);
427
- if (index >= 0) {
428
- newCheckedRows.value.splice(index, 1);
429
- }
430
- };
431
-
432
- const checkAll = () => {
433
- if (isAllChecked.value) {
434
- // Uncheck all rows
435
- newCheckedRows.value = [];
436
- } else {
437
- // Check all rows
438
- const rowsToCheck = computedItems.value.filter(
439
- (row) => !newCheckedRows.value.includes(row)
440
- );
441
- newCheckedRows.value.push(...rowsToCheck);
442
- }
443
- emit("check", newCheckedRows.value);
444
- emit("check-all", newCheckedRows.value);
445
- emit("update:checkedRows", newCheckedRows.value);
446
- emit("update:selectedRows", newCheckedRows.value);
447
- };
448
-
449
- const checkRow = (row: any, _rowIndex: number, _event: any) => {
450
- const isChecked = newCheckedRows.value.includes(row);
451
- if (_event && isChecked) {
452
- removeCheckedRow(row);
453
- } else {
454
- newCheckedRows.value.push(row);
455
- }
456
- emit("check", newCheckedRows.value, row);
457
- emit("update:checkedRows", newCheckedRows.value);
458
- emit("update:selectedRows", newCheckedRows.value);
459
- };
460
-
461
- // watch
462
- watch(
463
- () => currentPage.value,
464
- (newVal) => {
465
- newCurrentPage.value = newVal;
466
- },
467
- { immediate: true }
468
- );
469
- watch(
470
- () => checkedRows.value,
471
- (rows) => {
472
- newCheckedRows.value = [...rows];
473
- },
474
- { immediate: true }
475
- );
476
-
477
- //shadow-[4px_0px_8px_0px_#e5e6e8]
478
- // table scroll to add class
479
- const stickyClass = computed(() => {
480
- return props.checkable && props.stickyColumn
481
- ? {
482
- head: "bg-gray-100 sticky left-16 top-0 z-20 shadow-[10px_0px_16px_-5px_#e5e6e8]",
483
- body: "bg-white sticky left-16 top-0 z-10 after:absolute after:content-[''] after:bg-inherit after:w-2 after:h-[103%] after:inset-y-0 after:-right-2 after:bg-gradient-to-r after:from-gray-200 after:from-0% after:via-gray-50 after:via-60% after:z-0 after:bg-white/10",
484
- }
485
- : {
486
- head: "bg-gray-100 sticky left-0 top-0 z-20 shadow-[10px_0px_16px_-5px_#e5e6e8]",
487
- body: "bg-white sticky left-0 top-0 z-10 after:absolute after:content-[''] after:bg-inherit after:w-2 after:h-[103%] after:inset-y-0 after:-right-2 after:bg-gradient-to-r after:from-gray-200 after:from-0% after:via-gray-50 after:via-60% after:z-0 after:bg-white/10",
488
- };
489
- });
490
-
491
- const isOverflowing = ref(false);
492
- const isScrolled = ref(false);
493
- const tableContainer = ref<HTMLElement | null>(null);
494
-
495
- const handleScroll = () => {
496
- const container = tableContainer.value;
497
- if (container) {
498
- isScrolled.value = container.scrollLeft > 0;
499
- }
500
- };
501
-
502
- const checkOverflow = () => {
503
- const container = tableContainer.value;
504
- if (container) {
505
- isOverflowing.value = container.scrollWidth > container.clientWidth;
506
- }
507
- };
508
-
509
- onMounted(() => {
510
- window.addEventListener("resize", checkOverflow);
511
- });
512
-
513
- onUnmounted(() => {
514
- window.removeEventListener("resize", checkOverflow);
515
- });
516
-
517
- // Watch for changes in the container's width to check for overflow
518
- watch(() => tableContainer.value?.clientWidth, checkOverflow);
519
- </script>
520
-
521
- <style lang="scss" scoped>
522
- #student-table {
523
- & .eui-table {
524
- @apply min-w-full text-sm font-light text-left table table-auto w-full box-border border-separate relative border-spacing-0;
525
-
526
- thead tr {
527
- @apply snap-x snap-mandatory;
528
- th {
529
- @apply snap-always snap-start;
530
- &:first-of-type.checkable {
531
- @apply min-h-11 flex items-center justify-center px-2 max-w-16 w-16 sticky left-0 top-0 z-20 bg-gray-100;
532
- }
533
- }
534
- }
535
-
536
- tbody {
537
- @apply snap-y snap-mandatory snap-always;
538
- tr:not(.norecords) {
539
- @apply text-gray-600 transition-colors duration-100 bg-white snap-start ease-in-out snap-x snap-mandatory rounded-sm h-12;
540
- &:hover {
541
- @apply bg-purple-50 ring-1 ring-purple-100 ring-inset;
542
- }
543
- td {
544
- @apply px-3 py-1 text-sm font-normal transition-transform duration-100 ease-in-out snap-start snap-always border-solid border border-l-0 border-r-0 border-white first:border-s last:border-e last-of-type:rounded-e-sm first-of-type:rounded-s-sm;
545
- &:first-of-type.checkable {
546
- @apply w-12 text-center sticky left-0 top-0 z-[11] bg-white;
547
- }
548
- }
549
- &:hover td {
550
- @apply font-medium text-gray-900 bg-purple-50 border-purple-100;
551
- &:first-of-type.checkable {
552
- @apply bg-purple-50;
553
- }
554
- }
555
- }
556
- }
557
- }
558
- }
559
- </style>
@@ -1,98 +0,0 @@
1
- <template>
2
- <label class="table-checkbox">
3
- <input v-model="selected" type="checkbox" :value="value" v-bind="mergedAttrs" @change="onChange" />
4
- <span class="check-icon">
5
- <svg
6
- xmlns="http://www.w3.org/2000/svg"
7
- class="size-4"
8
- viewBox="0 0 20 20"
9
- fill="currentColor"
10
- stroke="currentColor"
11
- stroke-width="0.6"
12
- >
13
- <path
14
- fill-rule="evenodd"
15
- d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
16
- clip-rule="evenodd"
17
- ></path>
18
- </svg>
19
- </span>
20
- </label>
21
- </template>
22
-
23
- <script setup lang="ts">
24
- import { computed, ref, useAttrs, watch } from 'vue';
25
-
26
- const props = defineProps({
27
- indeterminate: Boolean,
28
- checked: {
29
- type: Boolean,
30
- default: false
31
- },
32
- value: {
33
- default: null
34
- }
35
- })
36
-
37
- const emit = defineEmits(['change', 'update:checked'])
38
- const isIndeterminate = ref(props.indeterminate)
39
-
40
- watch(() => props.indeterminate, (val) => {
41
- isIndeterminate.value = val
42
- })
43
-
44
- const selected = computed({
45
- get() {
46
- return props.checked
47
- },
48
- set(val) {
49
- emit('update:checked', val)
50
- }
51
- })
52
-
53
- const onChange = (event: Event) => {
54
- emit('change', event);
55
- };
56
-
57
- const isActive = computed(() => {
58
- const modelIsArray = Array.isArray(props.checked) && props.checked.length !== 0
59
- const sameValue = (element: any) => element === props.value
60
- if (modelIsArray) {
61
- return props.checked.some(sameValue)
62
- }
63
- return props.checked === true
64
- })
65
-
66
- const attrs = useAttrs()
67
- const computedTabIndex = computed(() => (attrs.disabled ? -1 : 0))
68
-
69
- const mergedAttrs = computed(() => ({
70
- ...attrs,
71
- tabindex: computedTabIndex.value,
72
- role: 'checkbox',
73
- // "aria-checked": isIndeterminate.value ? "mixed" : isActive.value.toString(),
74
- // "aria-disabled": attrs.disabled || undefined,
75
- }))
76
-
77
- watch(isActive, () => {
78
- if (props.indeterminate) {
79
- isIndeterminate.value = false
80
- }
81
- })
82
- </script>
83
-
84
- <style lang="scss">
85
- .table-checkbox {
86
- @apply size-10 relative flex items-center justify-center rounded-full cursor-pointer z-10 before:content-[''] before:transform before:translate-x-1/2 before:-translate-y-1/2 before:z-[-1] before:absolute before:top-1/2 before:right-1/2 before:block before:size-10 before:rounded-full before:bg-violet-100 before:opacity-0 before:transition-opacity hover:before:opacity-75;
87
-
88
- & > input[type='checkbox'] {
89
- @apply size-5 relative border border-solid border-gray-400 cursor-pointer appearance-none rounded-md z-0 accent-violet-600 checked:border-violet-600 checked:bg-violet-600 focus-within:outline-none focus-within:border-2 focus-within:border-violet-600;
90
- }
91
- & .check-icon {
92
- @apply absolute top-1/2 right-1/2 transform translate-x-1/2 -translate-y-1/2 text-white transition-opacity opacity-0 pointer-events-none;
93
- }
94
- }
95
- .table-checkbox input[type='checkbox']:checked ~ .check-icon {
96
- @apply opacity-100;
97
- }
98
- </style>