@bl33dz/fa814698dcde12f86a37ac31dd3aedf9 1.0.16 → 1.0.18

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.
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.0.16",
6
+ "version": "1.0.18",
7
7
  "main": "dist/perisai-ui.umd.js",
8
8
  "module": "dist/perisai-ui.es.js",
9
9
  "scripts": {
@@ -9,7 +9,7 @@ import {
9
9
  SelectViewport,
10
10
  useForwardPropsEmits,
11
11
  } from "reka-ui"
12
- import { cn } from "@/lib/utils"
12
+ import { cn } from "../../lib/utils"
13
13
  import { SelectScrollDownButton, SelectScrollUpButton } from "."
14
14
 
15
15
  defineOptions({
@@ -35,7 +35,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
35
35
  data-slot="select-content"
36
36
  v-bind="{ ...forwarded, ...$attrs }"
37
37
  :class="cn(
38
- 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--reka-select-content-available-height) min-w-[8rem] overflow-x-hidden overflow-y-auto rounded-md border shadow-md',
38
+ '!bg-neutral-800 !text-white data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--reka-select-content-available-height) min-w-[8rem] overflow-x-hidden overflow-y-auto rounded-lg shadow-md',
39
39
  position === 'popper'
40
40
  && 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
41
41
  props.class,
@@ -10,7 +10,7 @@ import {
10
10
  SelectItemText,
11
11
  useForwardProps,
12
12
  } from "reka-ui"
13
- import { cn } from "@/lib/utils"
13
+ import { cn } from "../../lib/utils"
14
14
 
15
15
  const props = defineProps<SelectItemProps & { class?: HTMLAttributes["class"] }>()
16
16
 
@@ -25,7 +25,7 @@ const forwardedProps = useForwardProps(delegatedProps)
25
25
  v-bind="forwardedProps"
26
26
  :class="
27
27
  cn(
28
- 'focus:bg-accent focus:text-accent-foreground [&_svg:not([class*=\'text-\'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2',
28
+ '!text-white hover:!bg-neutral-700 focus:!bg-neutral-700 data-[state=checked]:!bg-neutral-700 aria-selected:!bg-neutral-700 [&_svg:not([class*=\'text-\'])]:!text-white relative flex w-full cursor-pointer items-center gap-2 rounded-md py-2 pr-8 pl-3 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2',
29
29
  props.class,
30
30
  )
31
31
  "
@@ -4,7 +4,7 @@ import type { HTMLAttributes } from "vue"
4
4
  import { reactiveOmit } from "@vueuse/core"
5
5
  import { ChevronDown } from "lucide-vue-next"
6
6
  import { SelectIcon, SelectTrigger, useForwardProps } from "reka-ui"
7
- import { cn } from "@/lib/utils"
7
+ import { cn } from "../../lib/utils"
8
8
 
9
9
  const props = withDefaults(
10
10
  defineProps<SelectTriggerProps & { class?: HTMLAttributes["class"], size?: "sm" | "default" }>(),
@@ -21,7 +21,7 @@ const forwardedProps = useForwardProps(delegatedProps)
21
21
  :data-size="size"
22
22
  v-bind="forwardedProps"
23
23
  :class="cn(
24
- 'border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*=\'text-\'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4',
24
+ '!border-input !bg-input-background hover:!bg-select-hover focus-visible:!border-ring focus-visible:!ring-ring/50 data-[placeholder]:!text-gray-400 [&_svg:not([class*=\'text-\'])]:!text-gray-400 focus-visible:!ring-blue-500/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive flex w-full items-center justify-between gap-2 rounded-lg !border px-4 py-2.5 text-sm !text-white transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4',
25
25
  props.class,
26
26
  )"
27
27
  >
@@ -1,10 +1,11 @@
1
1
  <script setup lang="ts">
2
+ import type { PropType } from 'vue';
2
3
  import { cn } from './utils';
3
4
  import { PopoverContent, PopoverPortal } from 'reka-ui';
4
5
 
5
6
  const props = defineProps({
6
7
  class: String,
7
- align: { type: String, default: 'center' },
8
+ align: { type: String as PropType<'start' | 'center' | 'end'>, default: 'center' },
8
9
  sideOffset: { type: Number, default: 4 },
9
10
  });
10
11
  </script>
@@ -16,7 +17,7 @@ const props = defineProps({
16
17
  :align="props.align"
17
18
  :side-offset="props.sideOffset"
18
19
  :class="cn(
19
- 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--reka-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden',
20
+ 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--reka-popover-content-transform-origin) rounded-md border border-border p-4 shadow-md outline-hidden',
20
21
  props.class,
21
22
  )"
22
23
  v-bind="$attrs"
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { SelectContent } from '@/shadcn/select';
2
+ import { SelectContent } from '../shadcn/select';
3
3
  import { cn } from './utils';
4
4
  const props = defineProps({
5
5
  class: String,
@@ -11,7 +11,7 @@ const props = defineProps({
11
11
  <SelectContent
12
12
  data-slot="select-content"
13
13
  :class="cn(
14
- 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--reka-select-content-available-height) min-w-[8rem] origin-(--reka-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md',
14
+ 'bg-gray-800 text-white data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--reka-select-content-available-height) min-w-[8rem] origin-(--reka-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-lg border border-gray-700 shadow-md p-1',
15
15
  props.position === 'popper' &&
16
16
  'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
17
17
  props.class,
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { SelectItem } from '@/shadcn/select';
2
+ import { SelectItem } from '../shadcn/select';
3
3
  import { Check } from 'lucide-vue-next';
4
4
  import { cn } from './utils';
5
5
  const props = defineProps({
@@ -15,7 +15,7 @@ const props = defineProps({
15
15
  :value="props.value"
16
16
  data-slot="select-item"
17
17
  :class="cn(
18
- 'focus:bg-accent focus:text-accent-foreground [&_svg:not([class*=\'text-\'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2',
18
+ 'text-white hover:bg-gray-700 focus:bg-gray-700 [&_svg:not([class*=\'text-\'])]:text-gray-400 relative flex w-full cursor-pointer items-center gap-2 rounded-md py-2 pr-8 pl-3 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2',
19
19
  props.class,
20
20
  )"
21
21
  v-bind="$attrs"
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { cn } from './utils';
3
- import { SelectTrigger } from '@/shadcn/select';
3
+ import { SelectTrigger } from '../shadcn/select';
4
4
  import { ChevronDown } from 'lucide-vue-next';
5
5
  defineProps({
6
6
  class: String,
@@ -12,7 +12,7 @@ defineProps({
12
12
  data-slot="select-trigger"
13
13
  :data-size="size"
14
14
  :class="cn(
15
- 'border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*=\'text-\'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive hover:bg-select-hover flex w-full items-center justify-between gap-2 rounded-md border bg-input-background px-3 py-2 text-sm transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:min-h-9 data-[size=sm]:min-h-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 *:data-[slot=select-value]:overflow-hidden [&_[data-slot=select-value]_div]:flex [&_[data-slot=select-value]_div]:items-center [&_[data-slot=select-value]_div]:gap-2 [&_[data-slot=select-value]_.text-xs]:hidden [&_[data-slot=select-value]_svg]:shrink-0',
15
+ 'justify-between border-input bg-input-background hover:bg-select-hover focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] data-[placeholder]:text-gray-400 [&_svg:not([class*=\'text-\'])]:text-gray-400 focus-visible:ring-blue-500/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive flex w-full items-center gap-2 border px-4 py-2.5 text-sm text-white transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:min-h-9 data-[size=sm]:min-h-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 *:data-[slot=select-value]:overflow-hidden [&_[data-slot=select-value]_div]:flex [&_[data-slot=select-value]_div]:items-center [&_[data-slot=select-value]_div]:gap-2 [&_[data-slot=select-value]_.text-xs]:hidden [&_[data-slot=select-value]_svg]:shrink-0',
16
16
  $props.class,
17
17
  )"
18
18
  v-bind="$attrs"
package/src/ui/badge.vue CHANGED
@@ -28,7 +28,7 @@ const variantClasses: Record<string, string> = {
28
28
  default: 'border-transparent bg-primary text-primary-foreground hover:bg-primary/90',
29
29
  secondary: 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/90',
30
30
  destructive: 'border-transparent bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
31
- outline: 'text-foreground hover:bg-accent hover:text-accent-foreground',
31
+ outline: 'border-border bg-background text-foreground hover:bg-accent hover:text-accent-foreground',
32
32
  'soft-primary': 'border-blue-200 bg-blue-50 text-blue-700 hover:bg-blue-100 dark:border-blue-800 dark:bg-blue-950 dark:text-blue-300 dark:hover:bg-blue-900',
33
33
  'soft-secondary': 'border-gray-200 bg-gray-50 text-gray-700 hover:bg-gray-100 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 dark:hover:bg-gray-800',
34
34
  'soft-success': 'border-green-200 bg-green-50 text-green-700 hover:bg-green-100 dark:border-green-800 dark:bg-green-950 dark:text-green-300 dark:hover:bg-green-900',
package/src/ui/card.vue CHANGED
@@ -49,13 +49,13 @@ const customPaddingValue = computed(() => {
49
49
  <div v-if="props.variant === 'corner-cut'" class="relative">
50
50
  <!-- Border container -->
51
51
  <div
52
- :class="cn('absolute inset-0 bg-border rounded')"
52
+ :class="cn('absolute inset-0 bg-border/60 rounded')"
53
53
  :style="{ clipPath: clipPathValue }"
54
54
  />
55
55
  <!-- Content container -->
56
56
  <div
57
57
  data-slot="card"
58
- :class="cn('bg-card text-card-foreground flex flex-col gap-3 relative rounded', customPaddingValue, $attrs.class)"
58
+ :class="cn('bg-card text-card-foreground flex flex-col gap-3 relative rounded shadow-sm', customPaddingValue, $attrs.class as any)"
59
59
  :style="{ clipPath: clipPathValue, margin: '1px' }"
60
60
  v-bind="$attrs"
61
61
  >
@@ -65,7 +65,7 @@ const customPaddingValue = computed(() => {
65
65
  <div
66
66
  v-else
67
67
  data-slot="card"
68
- :class="cn('bg-card text-card-foreground flex flex-col gap-3 rounded-md border', $attrs.class)"
68
+ :class="cn('bg-gray-900 text-card-foreground flex flex-col gap-3 relative rounded-xl border border-gray-800 shadow-sm', $attrs.class as any)"
69
69
  v-bind="$attrs"
70
70
  >
71
71
  <slot />
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div
3
3
  data-slot="dialog-header"
4
- :class="['flex flex-col gap-2 text-center px-6 py-5 sm:text-left border-b border-border', $attrs.class]"
4
+ :class="['flex flex-col gap-2 text-center pl-4 py-4 pr-5 sm:text-left border-b', $attrs.class]"
5
5
  v-bind="$attrs"
6
6
  >
7
7
  <slot />
@@ -1,8 +1,7 @@
1
1
 
2
2
  <script setup lang="ts">
3
- import { DropdownMenuContent, DropdownMenuPortal } from '@/shadcn/dropdown-menu';
3
+ import { DropdownMenuContent, DropdownMenuPortal } from '../shadcn/dropdown-menu';
4
4
  import { cn } from './utils';
5
- import { computed } from 'vue';
6
5
  const props = defineProps({
7
6
  class: { type: String, default: '' },
8
7
  sideOffset: { type: Number, default: 4 },
@@ -15,7 +14,7 @@ const props = defineProps({
15
14
  data-slot="dropdown-menu-content"
16
15
  :sideOffset="props.sideOffset"
17
16
  v-bind="$attrs"
18
- :class="cn('bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-[--reka-dropdown-menu-content-available-height] min-w-[8rem] origin-[--reka-dropdown-menu-content-transform-origin] overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md', props.class)"
17
+ :class="cn('bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-[--reka-dropdown-menu-content-available-height] min-w-[8rem] origin-[--reka-dropdown-menu-content-transform-origin] overflow-x-hidden overflow-y-auto rounded-md border border-border p-1 shadow-md', props.class)"
19
18
  >
20
19
  <slot />
21
20
  </DropdownMenuContent>
@@ -2,7 +2,7 @@
2
2
  // Minimal stub for DropdownMenuSubContent
3
3
  </script>
4
4
  <template>
5
- <div class="absolute left-full top-0 mt-0 ml-2 min-w-[8rem] bg-popover border rounded-md shadow-md z-50" data-slot="dropdown-menu-sub-content">
5
+ <div class="absolute left-full top-0 mt-0 ml-2 min-w-[8rem] bg-popover border border-border rounded-md shadow-md z-50" data-slot="dropdown-menu-sub-content">
6
6
  <slot />
7
7
  </div>
8
8
  </template>
@@ -19,7 +19,7 @@
19
19
  </template>
20
20
  <template v-else-if="modelValue.length <= maxDisplay">
21
21
  <Badge
22
- v-for="(val, idx) in modelValue"
22
+ v-for="val in modelValue"
23
23
  :key="val"
24
24
  variant="soft-neutral"
25
25
  class="text-xs shrink-0"
@@ -47,19 +47,23 @@
47
47
  <div class="max-h-[200px] overflow-y-auto">
48
48
  <div
49
49
  v-for="option in options"
50
- :key="option.id"
50
+ :key="option.value"
51
51
  :class="[
52
52
  'relative flex w-full cursor-pointer items-center gap-2 rounded-sm py-1.5 pr-2 pl-2 text-sm outline-hidden select-none transition-colors',
53
- option.disabled ? 'opacity-50 cursor-not-allowed' : 'hover:bg-accent hover:text-accent-foreground'
53
+ option.disabled
54
+ ? 'opacity-50 cursor-not-allowed'
55
+ : 'hover:bg-accent hover:text-accent-foreground'
54
56
  ]"
55
- @click="!option.disabled && handleValueChange(option.id, !modelValue.includes(option.id))"
57
+ @click="!option.disabled && handleValueChange(option.value, !isSelected(option.value))"
56
58
  >
57
59
  <Checkbox
58
- :model-value="modelValue.includes(option.id)"
60
+ :model-value="isSelected(option.value)"
59
61
  :disabled="option.disabled"
60
62
  class="pointer-events-none"
61
63
  />
62
- <span class="flex-1 font-medium leading-none">{{ option.label }}</span>
64
+ <span class="flex-1 font-medium leading-none">
65
+ {{ option.label }}
66
+ </span>
63
67
  </div>
64
68
  </div>
65
69
  </div>
@@ -69,14 +73,14 @@
69
73
  </template>
70
74
 
71
75
  <script setup>
72
- import { ref, computed, defineProps, defineEmits, useAttrs } from 'vue';
73
- import Popover from './popover.vue';
74
- import PopoverTrigger from './PopoverTrigger.vue';
75
- import PopoverContent from './PopoverContent.vue';
76
- import Button from './button.vue';
77
- import Badge from './badge.vue';
78
- import Checkbox from './checkbox.vue';
79
- import ChevronDownIcon from 'lucide-vue-next/dist/esm/icons/chevron-down';
76
+ import { ref, computed, defineProps, defineEmits, useAttrs } from 'vue'
77
+ import Popover from './popover.vue'
78
+ import PopoverTrigger from './PopoverTrigger.vue'
79
+ import PopoverContent from './PopoverContent.vue'
80
+ import Button from './button.vue'
81
+ import Badge from './badge.vue'
82
+ import Checkbox from './checkbox.vue'
83
+ import ChevronDownIcon from 'lucide-vue-next/dist/esm/icons/chevron-down'
80
84
 
81
85
  const props = defineProps({
82
86
  modelValue: {
@@ -87,49 +91,45 @@ const props = defineProps({
87
91
  type: Array,
88
92
  default: () => [],
89
93
  },
90
- placeholder: {
91
- type: String,
92
- default: 'Select options...',
93
- },
94
- title: {
95
- type: String,
96
- default: 'Select Options',
97
- },
94
+ placeholder: String,
95
+ title: String,
98
96
  maxDisplay: {
99
97
  type: Number,
100
98
  default: 2,
101
99
  },
102
- disabled: {
103
- type: Boolean,
104
- default: false,
105
- },
100
+ disabled: Boolean,
106
101
  size: {
107
102
  type: String,
108
103
  default: 'default',
109
104
  },
110
- class: {
111
- type: String,
112
- default: '',
113
- },
114
- });
105
+ class: String,
106
+ })
107
+
108
+ const emit = defineEmits(['update:modelValue'])
109
+ const $attrs = useAttrs()
110
+ const isOpen = ref(false)
111
+
112
+ const customClass = computed(() => props.class || $attrs.class || '')
115
113
 
116
- const emit = defineEmits(['update:modelValue']);
117
- const $attrs = useAttrs();
118
- const isOpen = ref(false);
119
- const customClass = computed(() => props.class || $attrs.class || '');
114
+ function isSelected(value) {
115
+ return Array.isArray(props.modelValue) && props.modelValue.includes(value)
116
+ }
120
117
 
121
- function getLabel(val) {
122
- const found = props.options.find((o) => o.id === val);
123
- return found ? found.label : val;
118
+ function getLabel(value) {
119
+ const found = props.options.find(o => o.value === value)
120
+ return found ? found.label : value
124
121
  }
125
122
 
126
- function handleValueChange(optionId, checked) {
127
- let newValue = Array.isArray(props.modelValue) ? [...props.modelValue] : [];
128
- if (checked) {
129
- newValue.push(optionId);
130
- } else {
131
- newValue = newValue.filter((v) => v !== optionId);
123
+ function handleValueChange(value, checked) {
124
+ const current = Array.isArray(props.modelValue) ? props.modelValue : []
125
+ let next = [...current]
126
+
127
+ if (checked && !next.includes(value)) {
128
+ next.push(value)
129
+ } else if (!checked) {
130
+ next = next.filter(v => v !== value)
132
131
  }
133
- emit('update:modelValue', newValue);
132
+
133
+ emit('update:modelValue', next)
134
134
  }
135
- </script>
135
+ </script>
@@ -12,5 +12,5 @@ const props = defineProps({
12
12
  default: '',
13
13
  },
14
14
  });
15
- const footerClass = cn('bg-muted/50 border-t font-medium [&>tr]:last:border-b-0', props.class);
15
+ const footerClass = cn('bg-muted/50 border-t border-border font-medium [&>tr]:last:border-b-0', props.class);
16
16
  </script>
@@ -12,5 +12,5 @@ const props = defineProps({
12
12
  default: '',
13
13
  },
14
14
  });
15
- const rowClass = cn('hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors', props.class);
15
+ const rowClass = cn('hover:bg-muted/50 data-[state=selected]:bg-muted border-b border-border transition-colors', props.class);
16
16
  </script>
package/src/ui/table.vue CHANGED
@@ -1,11 +1,11 @@
1
1
  <template>
2
- <div data-slot="table-container" class="relative w-full overflow-x-auto">
2
+ <div data-slot="table-container" class="relative w-full overflow-x-auto rounded-md border border-border">
3
3
  <table data-slot="table" :class="tableClass">
4
4
  <!-- Table caption slot -->
5
5
  <slot name="caption" />
6
6
 
7
7
  <!-- Auto-wrap first TableRow in thead, rest in tbody -->
8
- <thead v-if="rows.length" data-slot="table-head" class="[&_tr]:border-b">
8
+ <thead v-if="rows.length" data-slot="table-head" class="[&_tr]:border-b [&_tr]:border-border">
9
9
  <component :is="rows[0]" />
10
10
  </thead>
11
11
  <tbody v-if="rows.length > 1" data-slot="table-body" class="[&_tr:last-child]:border-0">
@@ -40,7 +40,7 @@ const rows = computed(() => {
40
40
  const vnodes = slots.default ? slots.default() : [];
41
41
  // Vue SFC: TableRow is a functional component, so check type.name or type.__name
42
42
  return vnodes.filter(v => {
43
- const type = v.type;
43
+ const type = v.type as any;
44
44
  return type && (type.name === 'TableRow' || type.__name === 'TableRow');
45
45
  });
46
46
  });
@@ -8,7 +8,7 @@
8
8
  :id="id"
9
9
  data-slot="textarea"
10
10
  :class="cn(
11
- 'resize-none border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive flex field-sizing-content min-h-16 w-full rounded-md border bg-input-background text-base transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
11
+ 'resize-none border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent text-base transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
12
12
  validationState === 'error' && 'border-red-500 focus:border-red-500 focus:ring-red-500',
13
13
  validationState === 'success' && 'border-green-500 focus:border-green-500 focus:ring-green-500',
14
14
  $attrs.class
@@ -32,7 +32,7 @@
32
32
  v-else
33
33
  data-slot="textarea"
34
34
  :class="cn(
35
- 'resize-none border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive flex field-sizing-content min-h-16 w-full rounded-md border bg-input-background text-base transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
35
+ 'resize-none border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent text-base transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
36
36
  $attrs.class
37
37
  )"
38
38
  v-bind="$attrs"