@sakoa/ui 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/cli/index.js +8 -0
  2. package/dist/components/ui/SAlert.d.ts +3 -2
  3. package/dist/components/ui/SButton.d.ts +6 -5
  4. package/dist/components/ui/SCheckbox.d.ts +4 -3
  5. package/dist/components/ui/SDatePicker.d.ts +3 -3
  6. package/dist/components/ui/SGlassButton.d.ts +6 -5
  7. package/dist/components/ui/SInput.d.ts +6 -5
  8. package/dist/components/ui/SSelect.d.ts +5 -4
  9. package/dist/components/ui/SSwitch.d.ts +6 -5
  10. package/dist/components/ui/accordion/SAccordionItem.d.ts +7 -6
  11. package/dist/components/ui/card/SCardHeader.d.ts +4 -3
  12. package/dist/components/ui/dropdown/SDropdownGroup.d.ts +3 -2
  13. package/dist/components/ui/dropdown/SDropdownItem.d.ts +7 -6
  14. package/dist/components/ui/option/SOption.d.ts +3 -2
  15. package/dist/components/ui/otp/SOTP.d.ts +1 -1
  16. package/dist/components/ui/pagination/SPagination.d.ts +1 -1
  17. package/dist/components/ui/progress/SProgress.d.ts +1 -1
  18. package/dist/components/ui/progress/SProgressRange.d.ts +1 -1
  19. package/dist/components/ui/radio/SRadio.d.ts +4 -3
  20. package/dist/components/ui/radio/SRadioGroup.d.ts +1 -1
  21. package/dist/components/ui/stepper/SStepper.d.ts +1 -1
  22. package/dist/index.d.ts +1 -0
  23. package/dist/lib/icon.d.ts +10 -0
  24. package/dist/saka-ui.css +1 -1
  25. package/dist/saka-ui.js +5355 -5252
  26. package/dist/saka-ui.umd.cjs +11 -11
  27. package/dist/views/docs/CLIView.d.ts +2 -0
  28. package/dist/views/docs/GettingStartedView.d.ts +2 -0
  29. package/dist/views/docs/IconsGuideView.d.ts +2 -0
  30. package/dist/views/docs/UseClickOutsideView.d.ts +9 -9
  31. package/dist/views/docs/UseHotkeyView.d.ts +10 -10
  32. package/dist/views/ui/OTPView.d.ts +3 -3
  33. package/package.json +1 -1
  34. package/registry/source/components/ui/SAlert.vue +9 -5
  35. package/registry/source/components/ui/SButton.vue +12 -10
  36. package/registry/source/components/ui/SCheckbox.vue +4 -2
  37. package/registry/source/components/ui/SGlassButton.vue +11 -10
  38. package/registry/source/components/ui/SInput.vue +12 -4
  39. package/registry/source/components/ui/SSelect.vue +30 -8
  40. package/registry/source/components/ui/SSwitch.vue +7 -4
  41. package/registry/source/components/ui/accordion/SAccordionItem.vue +19 -5
  42. package/registry/source/components/ui/card/SCardHeader.vue +8 -5
  43. package/registry/source/components/ui/drawer/SDrawerClose.vue +4 -2
  44. package/registry/source/components/ui/dropdown/SDropdown.vue +11 -7
  45. package/registry/source/components/ui/dropdown/SDropdownGroup.vue +4 -2
  46. package/registry/source/components/ui/dropdown/SDropdownItem.vue +10 -7
  47. package/registry/source/components/ui/option/SOption.vue +9 -2
  48. package/registry/source/components/ui/radio/SRadio.vue +11 -3
  49. package/registry/source/components/ui/tabs/STabs.vue +5 -2
@@ -9,6 +9,7 @@ defineOptions({ inheritAttrs: false })
9
9
 
10
10
  import { inject } from 'vue'
11
11
  import { cn } from '../../../lib/utils'
12
+ import { type IconProp, isIconComponent } from '../../../lib/icon'
12
13
  import { SDrawerContextKey, type SDrawerContext } from './SDrawer.vue'
13
14
 
14
15
  export interface Props {
@@ -19,7 +20,7 @@ export interface Props {
19
20
  /** Visual variant */
20
21
  variant?: 'default' | 'ghost' | 'subtle'
21
22
  /** Icon to display */
22
- icon?: string
23
+ icon?: IconProp
23
24
  }
24
25
 
25
26
  const props = withDefaults(defineProps<Props>(), {
@@ -59,6 +60,7 @@ const variantClasses = {
59
60
  aria-label="Close drawer"
60
61
  @click="handleClose"
61
62
  >
62
- <span :class="`mdi mdi-${icon} text-xl`" />
63
+ <component v-if="isIconComponent(icon)" :is="icon" class="text-xl" />
64
+ <span v-else :class="`mdi mdi-${icon} text-xl`" />
63
65
  </button>
64
66
  </template>
@@ -4,6 +4,7 @@
4
4
  * A highly customizable dropdown component for menus, actions, and navigation
5
5
  */
6
6
  import { type InjectionKey, type Ref } from 'vue'
7
+ import { type IconProp, isIconComponent } from '../../../lib/icon'
7
8
 
8
9
  // Types
9
10
  export type DropdownTrigger = 'click' | 'hover' | 'context' | 'manual'
@@ -19,8 +20,8 @@ export type DropdownAnimation = 'fade' | 'slide' | 'scale' | 'reveal'
19
20
  export interface DropdownMenuItem {
20
21
  key: string
21
22
  label: string
22
- icon?: string
23
- trailingIcon?: string
23
+ icon?: IconProp
24
+ trailingIcon?: IconProp
24
25
  description?: string
25
26
  shortcut?: string
26
27
  disabled?: boolean
@@ -98,7 +99,7 @@ export interface Props {
98
99
  /** Trigger button text */
99
100
  label?: string
100
101
  /** Trigger button icon */
101
- icon?: string
102
+ icon?: IconProp
102
103
  /** Hide the dropdown arrow on trigger */
103
104
  hideArrow?: boolean
104
105
  }
@@ -589,7 +590,8 @@ defineExpose({
589
590
  ]"
590
591
  :disabled="disabled"
591
592
  >
592
- <span v-if="icon" :class="['mdi', `mdi-${icon}`, sizeConfig.icon]" />
593
+ <component v-if="icon && isIconComponent(icon)" :is="icon" :class="[sizeConfig.icon]" />
594
+ <span v-else-if="icon" :class="['mdi', `mdi-${icon}`, sizeConfig.icon]" />
593
595
  <span v-if="label">{{ label }}</span>
594
596
  <span
595
597
  v-if="!hideArrow"
@@ -704,7 +706,8 @@ defineExpose({
704
706
  />
705
707
 
706
708
  <!-- Leading icon -->
707
- <span
709
+ <component v-else-if="item.icon && isIconComponent(item.icon)" :is="item.icon" :class="[sizeConfig.icon, 'mr-2.5', item.danger ? '' : 'text-muted-foreground']" />
710
+ <span
708
711
  v-else-if="item.icon"
709
712
  :class="['mdi', `mdi-${item.icon}`, sizeConfig.icon, 'mr-2.5', item.danger ? '' : 'text-muted-foreground']"
710
713
  />
@@ -732,8 +735,9 @@ defineExpose({
732
735
  </kbd>
733
736
 
734
737
  <!-- Trailing icon -->
735
- <span
736
- v-if="item.trailingIcon"
738
+ <component v-if="item.trailingIcon && isIconComponent(item.trailingIcon)" :is="item.trailingIcon" :class="[sizeConfig.icon, 'text-muted-foreground']" />
739
+ <span
740
+ v-else-if="item.trailingIcon"
737
741
  :class="['mdi', `mdi-${item.trailingIcon}`, sizeConfig.icon, 'text-muted-foreground']"
738
742
  />
739
743
 
@@ -3,13 +3,14 @@ defineOptions({ inheritAttrs: false })
3
3
 
4
4
  import { inject, computed } from 'vue'
5
5
  import { cn } from '../../../lib/utils'
6
+ import { type IconProp, isIconComponent } from '../../../lib/icon'
6
7
  import { SDropdownContextKey, type SDropdownContext } from './SDropdown.vue'
7
8
 
8
9
  export interface Props {
9
10
  /** Group header label */
10
11
  label: string
11
12
  /** Icon for the header */
12
- icon?: string
13
+ icon?: IconProp
13
14
  }
14
15
 
15
16
  const props = withDefaults(defineProps<Props>(), {
@@ -33,7 +34,8 @@ const sizeConfig = computed(() => ({
33
34
  class="font-semibold uppercase tracking-wider text-muted-foreground flex items-center gap-2 sticky top-0 bg-background/95 backdrop-blur-sm"
34
35
  :class="sizeConfig"
35
36
  >
36
- <span v-if="icon" :class="['mdi', `mdi-${icon}`, 'text-xs']" />
37
+ <component v-if="icon && isIconComponent(icon)" :is="icon" class="text-xs" />
38
+ <span v-else-if="icon" :class="['mdi', `mdi-${icon}`, 'text-xs']" />
37
39
  <span>{{ label }}</span>
38
40
  </div>
39
41
 
@@ -3,6 +3,7 @@ defineOptions({ inheritAttrs: false })
3
3
 
4
4
  import { inject, ref, computed, onMounted, onBeforeUnmount } from 'vue'
5
5
  import { cn } from '../../../lib/utils'
6
+ import { type IconProp, isIconComponent } from '../../../lib/icon'
6
7
  import { SDropdownContextKey, type SDropdownContext } from './SDropdown.vue'
7
8
 
8
9
  export interface Props {
@@ -10,10 +11,10 @@ export interface Props {
10
11
  itemKey: string
11
12
  /** Item label text */
12
13
  label?: string
13
- /** Leading icon (MDI icon name) */
14
- icon?: string
15
- /** Trailing icon */
16
- trailingIcon?: string
14
+ /** Leading icon (MDI icon name or Vue component) */
15
+ icon?: IconProp
16
+ /** Trailing icon (MDI icon name or Vue component) */
17
+ trailingIcon?: IconProp
17
18
  /** Description text below label */
18
19
  description?: string
19
20
  /** Keyboard shortcut display */
@@ -130,7 +131,8 @@ const handleClick = (event: MouseEvent) => {
130
131
  />
131
132
 
132
133
  <!-- Leading icon -->
133
- <span
134
+ <component v-else-if="icon && isIconComponent(icon)" :is="icon" :class="[sizeConfig.icon, 'mr-2.5', danger ? '' : 'text-muted-foreground group-hover:text-foreground']" />
135
+ <span
134
136
  v-else-if="icon"
135
137
  :class="['mdi', `mdi-${icon}`, sizeConfig.icon, 'mr-2.5', danger ? '' : 'text-muted-foreground group-hover:text-foreground']"
136
138
  />
@@ -160,8 +162,9 @@ const handleClick = (event: MouseEvent) => {
160
162
  </kbd>
161
163
 
162
164
  <!-- Trailing icon -->
163
- <span
164
- v-if="trailingIcon"
165
+ <component v-if="trailingIcon && isIconComponent(trailingIcon)" :is="trailingIcon" :class="[sizeConfig.icon, 'text-muted-foreground']" />
166
+ <span
167
+ v-else-if="trailingIcon"
165
168
  :class="['mdi', `mdi-${trailingIcon}`, sizeConfig.icon, 'text-muted-foreground']"
166
169
  />
167
170
 
@@ -3,12 +3,13 @@ defineOptions({ inheritAttrs: false })
3
3
 
4
4
  import { inject, computed, type CSSProperties } from 'vue'
5
5
  import { cn } from '../../../lib/utils'
6
+ import { type IconProp, isIconComponent } from '../../../lib/icon'
6
7
 
7
8
  export interface Props {
8
9
  value: any
9
10
  label?: string
10
11
  disabled?: boolean
11
- icon?: string
12
+ icon?: IconProp
12
13
  description?: string
13
14
  color?: string
14
15
  }
@@ -132,8 +133,14 @@ const bgClass = computed(() => {
132
133
  />
133
134
 
134
135
  <!-- Icon -->
136
+ <component
137
+ v-if="icon && isIconComponent(icon)"
138
+ :is="icon"
139
+ :class="cn('relative z-10 shrink-0', sizeConfig.icon, isSelected && !hasCustomColor ? 'text-primary' : '')"
140
+ :style="isSelected && hasCustomColor ? { color: resolvedColor } : {}"
141
+ />
135
142
  <span
136
- v-if="icon"
143
+ v-else-if="icon"
137
144
  :class="cn('relative z-10 shrink-0 mdi', `mdi-${icon}`, sizeConfig.icon, isSelected && !hasCustomColor ? 'text-primary' : '')"
138
145
  :style="isSelected && hasCustomColor ? { color: resolvedColor } : {}"
139
146
  />
@@ -1,6 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { computed, ref, inject, type CSSProperties } from 'vue'
3
3
  import { cn } from '../../../lib/utils'
4
+ import { type IconProp, isIconComponent } from '../../../lib/icon'
4
5
 
5
6
  defineOptions({ inheritAttrs: false })
6
7
 
@@ -14,7 +15,7 @@ export interface Props {
14
15
  label?: string
15
16
  labelPosition?: 'left' | 'right'
16
17
  variant?: 'default' | 'filled' | 'outlined' | 'button'
17
- icon?: string
18
+ icon?: IconProp
18
19
  required?: boolean
19
20
  name?: string
20
21
  error?: string
@@ -195,8 +196,9 @@ const buttonStyle = computed<CSSProperties>(() => {
195
196
  ></span>
196
197
 
197
198
  <!-- Icon -->
199
+ <component v-if="icon && !loading && isIconComponent(icon)" :is="icon" class="mr-2" />
198
200
  <span
199
- v-if="icon && !loading"
201
+ v-else-if="icon && !loading"
200
202
  :class="['mdi', `mdi-${icon}`, 'mr-2']"
201
203
  ></span>
202
204
 
@@ -296,8 +298,14 @@ const buttonStyle = computed<CSSProperties>(() => {
296
298
  :class="currentVariant === 'filled' ? (hasCustomColor ? 'text-white' : 'text-primary-foreground') : ''"
297
299
  >
298
300
  <slot name="icon">
301
+ <component
302
+ v-if="icon && isIconComponent(icon)"
303
+ :is="icon"
304
+ :class="cn(sizeConfig.icon, currentVariant !== 'filled' && !hasCustomColor ? 'text-primary' : '')"
305
+ :style="currentVariant !== 'filled' && hasCustomColor ? { color: currentColor } : {}"
306
+ />
299
307
  <span
300
- v-if="icon"
308
+ v-else-if="icon"
301
309
  :class="cn('mdi', `mdi-${icon}`, sizeConfig.icon, currentVariant !== 'filled' && !hasCustomColor ? 'text-primary' : '')"
302
310
  :style="currentVariant !== 'filled' && hasCustomColor ? { color: currentColor } : {}"
303
311
  />
@@ -4,6 +4,7 @@
4
4
  * Supports both simple (STabPane) and compound (STabsList + STabsTrigger + STabsContent) APIs
5
5
  */
6
6
  import { type InjectionKey, type Ref } from 'vue'
7
+ import type { IconProp } from '../../../lib/icon'
7
8
 
8
9
  // Types - exported for external use
9
10
  export type TabType = 'line' | 'card' | 'segment' | 'bar' | 'chip'
@@ -14,7 +15,7 @@ export type TabJustify = 'flex-start' | 'center' | 'flex-end' | 'space-between'
14
15
  export interface TabPaneInfo {
15
16
  name: string | number
16
17
  tab: string
17
- icon?: string
18
+ icon?: IconProp
18
19
  disabled?: boolean
19
20
  closable?: boolean
20
21
  tabClass?: string
@@ -44,6 +45,7 @@ defineOptions({ inheritAttrs: false })
44
45
 
45
46
  import { provide, ref, computed, watch, nextTick, onMounted, useSlots } from 'vue'
46
47
  import { cn } from '../../../lib/utils'
48
+ import { isIconComponent } from '../../../lib/icon'
47
49
 
48
50
  // Props
49
51
  export interface Props {
@@ -416,8 +418,9 @@ provide(STabsContextKey, {
416
418
  :close="() => emit('close', pane.name)"
417
419
  >
418
420
  <!-- Icon -->
421
+ <component v-if="pane.icon && isIconComponent(pane.icon)" :is="pane.icon" :class="[{ 'scale-110': activeTab === pane.name }]" />
419
422
  <span
420
- v-if="pane.icon"
423
+ v-else-if="pane.icon"
421
424
  class="mdi transition-transform duration-300"
422
425
  :class="[`mdi-${pane.icon}`, { 'scale-110': activeTab === pane.name }]"
423
426
  />