@invopop/popui 0.1.14 → 0.1.16

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 (103) hide show
  1. package/dist/BaseButton.svelte +25 -103
  2. package/dist/BaseCard.svelte +35 -30
  3. package/dist/BaseCounter.svelte +11 -8
  4. package/dist/BaseDropdown.svelte +3 -3
  5. package/dist/BaseTable.svelte +8 -12
  6. package/dist/BaseTableActions.svelte +4 -6
  7. package/dist/BaseTableCellContent.svelte +4 -6
  8. package/dist/BaseTableCheckbox.svelte +8 -10
  9. package/dist/BaseTableHeaderContent.svelte +4 -4
  10. package/dist/BaseTableRow.svelte +12 -10
  11. package/dist/Breadcrumb.svelte +40 -0
  12. package/dist/Breadcrumb.svelte.d.ts +4 -0
  13. package/dist/Breadcrumbs.svelte +5 -30
  14. package/dist/ButtonFile.svelte +35 -30
  15. package/dist/ButtonUuidCopy.svelte +3 -2
  16. package/dist/CardCheckbox.svelte +25 -21
  17. package/dist/CardRelation.svelte +12 -16
  18. package/dist/CompanySelector.svelte +35 -7
  19. package/dist/DataListItem.svelte +14 -10
  20. package/dist/DatePicker.svelte +14 -12
  21. package/dist/DrawerContext.svelte +111 -8
  22. package/dist/DrawerContextItem.svelte +18 -30
  23. package/dist/DrawerContextSeparator.svelte +1 -1
  24. package/dist/DrawerContextWorkspace.svelte +7 -7
  25. package/dist/DropdownSelect.svelte +38 -16
  26. package/dist/EmptyState.svelte +42 -0
  27. package/dist/EmptyState.svelte.d.ts +4 -0
  28. package/dist/EmptyStateIllustration.svelte.d.ts +0 -1
  29. package/dist/FeedEvents.svelte +9 -5
  30. package/dist/FeedIconEvent.svelte +1 -1
  31. package/dist/FeedIconStatus.svelte +1 -1
  32. package/dist/FeedItem.svelte +8 -8
  33. package/dist/FeedItemDetail.svelte +15 -6
  34. package/dist/GlobalSearch.svelte +13 -12
  35. package/dist/InputCheckbox.svelte +2 -5
  36. package/dist/InputError.svelte +4 -9
  37. package/dist/InputLabel.svelte +3 -1
  38. package/dist/InputRadio.svelte +26 -11
  39. package/dist/InputSearch.svelte +8 -8
  40. package/dist/InputSelect.svelte +32 -31
  41. package/dist/InputText.svelte +32 -24
  42. package/dist/InputTextarea.svelte +25 -19
  43. package/dist/InputToggle.svelte +24 -18
  44. package/dist/MenuItem.svelte +9 -8
  45. package/dist/MenuItemCollapsible.svelte +4 -4
  46. package/dist/Notification.svelte +59 -24
  47. package/dist/ProfileAvatar.svelte +43 -14
  48. package/dist/SeparatorHorizontal.svelte +2 -2
  49. package/dist/ShortcutWrapper.svelte +14 -5
  50. package/dist/StatusLabel.svelte +4 -5
  51. package/dist/StepIconList.svelte +11 -9
  52. package/dist/TagBeta.svelte +26 -14
  53. package/dist/TagStatus.svelte +37 -49
  54. package/dist/TitleMain.svelte +1 -1
  55. package/dist/TitleSection.svelte +1 -1
  56. package/dist/UuidCopy.svelte +4 -4
  57. package/dist/alert-dialog/alert-dialog-action.svelte +5 -3
  58. package/dist/alert-dialog/alert-dialog-cancel.svelte +4 -2
  59. package/dist/alert-dialog/alert-dialog-content.svelte +1 -1
  60. package/dist/alert-dialog/alert-dialog-description.svelte +1 -1
  61. package/dist/alert-dialog/alert-dialog-footer.svelte +1 -1
  62. package/dist/alert-dialog/alert-dialog-header.svelte +1 -1
  63. package/dist/alert-dialog/alert-dialog-title.svelte +1 -1
  64. package/dist/button/button.svelte +198 -24
  65. package/dist/button/button.svelte.d.ts +48 -26
  66. package/dist/index.d.ts +5 -10
  67. package/dist/index.js +3 -13
  68. package/dist/range-calendar/range-calendar-cell.svelte +1 -1
  69. package/dist/range-calendar/range-calendar-day.svelte +10 -8
  70. package/dist/range-calendar/range-calendar-head-cell.svelte +1 -1
  71. package/dist/range-calendar/range-calendar-next-button.svelte +3 -3
  72. package/dist/range-calendar/range-calendar-prev-button.svelte +3 -3
  73. package/dist/range-calendar/range-calendar.svelte +1 -1
  74. package/dist/sonner/sonner.svelte +7 -9
  75. package/dist/svg/CheckBadge.svelte +18 -0
  76. package/dist/svg/CheckBadge.svelte.d.ts +26 -0
  77. package/dist/svg/IconEmpty.svelte +78 -106
  78. package/dist/table/table-body.svelte +1 -1
  79. package/dist/table/table-cell.svelte +1 -1
  80. package/dist/table/table-footer.svelte +1 -1
  81. package/dist/table/table-head.svelte +1 -1
  82. package/dist/table/table-header.svelte +1 -1
  83. package/dist/table/table-row.svelte +1 -1
  84. package/dist/tabs/tabs-list.svelte +8 -2
  85. package/dist/tabs/tabs-list.svelte.d.ts +4 -1
  86. package/dist/tabs/tabs-trigger.svelte +5 -3
  87. package/dist/tabs/tabs-trigger.svelte.d.ts +4 -1
  88. package/dist/tailwind.theme.css +981 -0
  89. package/dist/tooltip/tooltip-content.svelte +2 -2
  90. package/dist/types.d.ts +36 -42
  91. package/package.json +2 -2
  92. package/dist/CounterWorkflow.svelte +0 -19
  93. package/dist/CounterWorkflow.svelte.d.ts +0 -4
  94. package/dist/EmptyStateIcon.svelte +0 -52
  95. package/dist/EmptyStateIcon.svelte.d.ts +0 -4
  96. package/dist/FormLayoutModal.svelte +0 -14
  97. package/dist/FormLayoutModal.svelte.d.ts +0 -4
  98. package/dist/ProfileSelector.svelte +0 -41
  99. package/dist/ProfileSelector.svelte.d.ts +0 -4
  100. package/dist/SectionLayout.svelte +0 -13
  101. package/dist/SectionLayout.svelte.d.ts +0 -4
  102. package/dist/tw.theme.d.ts +0 -171
  103. package/dist/tw.theme.js +0 -188
@@ -5,64 +5,52 @@
5
5
  let { label = '', status = 'grey', dot = false }: TagStatusProps = $props()
6
6
 
7
7
  let tagStyles = $derived(
8
- clsx({
9
- 'bg-positive-100 text-positive-500': status === 'green',
10
- 'border border-positive-200': status === 'green' && dot,
11
- 'bg-yellow-100 text-yellow-500': status === 'yellow',
12
- 'border border-yellow-200': status === 'yellow' && dot,
13
- 'bg-danger-100 text-danger-500': status === 'red',
14
- 'border border-danger-200': status === 'red' && dot,
15
- 'bg-warning-100 text-warning-500': status === 'orange',
16
- 'border border-warning-200': status === 'orange' && dot,
17
- 'bg-blue-100 text-blue-500': status === 'blue',
18
- 'border border-blue-200': status === 'blue' && dot,
19
- 'bg-purple-100 text-purple-500': status === 'purple',
20
- 'border border-purple-200': status === 'purple' && dot,
21
- 'bg-olive-100 text-olive-500': status === 'olive',
22
- 'border border-olive-200': status === 'olive' && dot,
23
- 'bg-teal-100 text-teal-500': status === 'teal',
24
- 'border border-teal-200': status === 'teal' && dot,
25
- 'bg-crimson-100 text-crimson-500': status === 'crimson',
26
- 'border border-crimson-200': status === 'crimson' && dot,
27
- 'bg-blue-violet-100 text-blue-violet-500': status === 'blueViolet',
28
- 'border border-blue-violet-200': status === 'blueViolet' && dot,
29
- 'bg-steel-blue-100 text-steel-blue-500': status === 'steelBlue',
30
- 'border border-steel-blue-200': status === 'steelBlue' && dot,
31
- 'border border-dashed border-neutral-200 text-neutral-400': status === 'empty',
32
- 'bg-neutral-100 text-neutral-500': status === 'grey',
33
- 'border border-neutral-200': status === 'grey' && dot,
34
- 'pl-1.5 pr-[5px] py-0.5': dot && label,
35
- 'p-0.5': dot && !label,
36
- 'px-1 py-0.5': !dot
37
- })
8
+ clsx(
9
+ 'rounded inline-flex items-center text-xs font-medium gap-1 box-border leading-4 py-0.5 h-5',
10
+ {
11
+ 'bg-background-status-paid text-foreground-status-paid': status === 'green',
12
+ 'bg-background-status-processing text-foreground-status-processing': status === 'yellow',
13
+ 'bg-background-status-error text-foreground-status-error': status === 'red',
14
+ 'bg-background-status-draft text-foreground-status-draft': status === 'orange',
15
+ 'bg-background-status-sent text-foreground-status-sent': status === 'blue',
16
+ 'bg-background-status-registered text-foreground-status-registered': status === 'purple',
17
+ 'bg-background-status-completed text-foreground-status-completed': status === 'teal',
18
+ 'bg-background-status-received text-foreground-status-received': status === 'steelBlue',
19
+ 'bg-background-status-rejected text-foreground-status-rejected': status === 'crimson',
20
+ 'bg-sherwood-alpha-10 text-sherwood-60': status === 'olive',
21
+ 'bg-background-status-void text-foreground-default-secondary': status === 'grey',
22
+ 'border border-dashed border-border-default-secondary text-foreground-default-secondary':
23
+ status === 'empty',
24
+ 'px-1.5': dot,
25
+ 'p-1!': dot && !label,
26
+ 'px-1': !dot
27
+ }
28
+ )
38
29
  )
39
30
 
40
31
  let dotStyles = $derived(
41
- clsx({
42
- 'bg-positive-500': status === 'green',
43
- 'bg-yellow-500': status === 'yellow',
44
- 'bg-danger-500': status === 'red',
45
- 'bg-warning-500': status === 'orange',
46
- 'bg-blue-500': status === 'blue',
47
- 'bg-purple-500': status === 'purple',
48
- 'bg-olive-500': status === 'olive',
49
- 'bg-teal-500': status === 'teal',
50
- 'bg-crimson-500': status === 'crimson',
51
- 'bg-blue-violet-500': status === 'blueViolet',
52
- 'bg-neutral-300': status === 'empty',
53
- 'bg-neutral-500': status === 'grey'
32
+ clsx('rounded-[2px] shrink-0', {
33
+ 'bg-icon-status-paid': status === 'green',
34
+ 'bg-icon-status-processing': status === 'yellow',
35
+ 'bg-icon-status-error': status === 'red',
36
+ 'bg-icon-status-draft': status === 'orange',
37
+ 'bg-icon-status-sent': status === 'blue',
38
+ 'bg-icon-status-registered': status === 'purple',
39
+ 'bg-icon-status-completed': status === 'teal',
40
+ 'bg-icon-status-received': status === 'steelBlue',
41
+ 'bg-icon-status-rejected': status === 'crimson',
42
+ 'bg-sherwood-50': status === 'olive',
43
+ 'bg-icon-status-void': status === 'grey',
44
+ 'bg-icon-default-secondary': status === 'empty'
54
45
  })
55
46
  )
56
47
  </script>
57
48
 
58
- <span
59
- class:h-5={Boolean(label)}
60
- class="{tagStyles} rounded text-sm inline-flex items-center font-medium gap-1 box-border"
61
- >
49
+ <span class={tagStyles}>
62
50
  {#if dot}
63
- <span class="{dotStyles} w-2 h-2 rounded-sm"></span>
51
+ <span class="{dotStyles} size-2"></span>
64
52
  {/if}
65
53
  {#if label}
66
- <span>{label}</span>
54
+ <span class="whitespace-nowrap">{label}</span>
67
55
  {/if}
68
56
  </span>
@@ -4,7 +4,7 @@
4
4
  let { title = '', children }: TitleMainProps = $props()
5
5
  </script>
6
6
 
7
- <h1 class="text-neutral-800 font-medium text-lg font-sans tracking-tightest">
7
+ <h1 class="text-foreground font-medium text-lg">
8
8
  {#if children}
9
9
  {@render children()}
10
10
  {:else}
@@ -4,7 +4,7 @@
4
4
  let { title = '', children }: TitleSectionProps = $props()
5
5
  </script>
6
6
 
7
- <h1 class="text-neutral-800 font-medium text-lg font-sans tracking-tighter">
7
+ <h1 class="text-foreground font-medium text-lg">
8
8
  {#if children}
9
9
  {@render children()}
10
10
  {:else}
@@ -35,11 +35,11 @@
35
35
  'justify-end': rightAlign,
36
36
  'text-sm': small,
37
37
  'text-base': !small,
38
- 'text-neutral-800': dark,
39
- 'text-neutral-500': !dark,
38
+ 'text-foreground': dark,
39
+ 'text-foreground-default-secondary': !dark,
40
40
  'justify-between': !compact,
41
41
  'w-full': full,
42
- 'border border-neutral-800/10 rounded-md pl-2.5 pr-2 py-[5px]': !full
42
+ 'border border-border rounded-md pl-2.5 pr-2 py-[5px]': !full
43
43
  })
44
44
  )
45
45
 
@@ -65,6 +65,6 @@
65
65
  {formattedUuid}
66
66
  </button>
67
67
  <button class="p-1 cursor-pointer" onclick={handleIconClick}>
68
- <Icon src={link ? ExternalLink : Duplicate} class="w-4 h-4 text-neutral-500" />
68
+ <Icon src={link ? ExternalLink : Duplicate} class="w-4 h-4 text-foreground-default-secondary" />
69
69
  </button>
70
70
  </div>
@@ -10,14 +10,16 @@
10
10
  ...restProps
11
11
  }: AlertDialogPrimitive.ActionProps & { destructive: boolean } = $props()
12
12
 
13
- let variant = $derived((destructive ? 'destructive' : 'primary') as ButtonVariant)
13
+ let variant = $derived((destructive ? 'danger' : 'primary') as ButtonVariant)
14
14
  </script>
15
15
 
16
16
  <AlertDialogPrimitive.Action
17
17
  bind:ref
18
18
  data-slot="alert-dialog-action"
19
- class={cn(buttonVariants({ variant }), className)}
19
+ class={cn(buttonVariants({ variant }), 'group', className)}
20
20
  {...restProps}
21
21
  >
22
- {@render children?.()}
22
+ <div class="inline-flex items-center transition-transform group-active:translate-y-px">
23
+ {@render children?.()}
24
+ </div>
23
25
  </AlertDialogPrimitive.Action>
@@ -13,9 +13,11 @@
13
13
  <AlertDialogPrimitive.Cancel
14
14
  bind:ref
15
15
  data-slot="alert-dialog-cancel"
16
- class={cn(buttonVariants({ variant: 'secondary' }), 'mt-2 sm:mt-0', className)}
16
+ class={cn(buttonVariants({ variant: 'secondary' }), 'group mt-2 sm:mt-0', className)}
17
17
  {onkeydown}
18
18
  {...restProps}
19
19
  >
20
- {@render children?.()}
20
+ <div class="inline-flex items-center transition-transform group-active:translate-y-px">
21
+ {@render children?.()}
22
+ </div>
21
23
  </AlertDialogPrimitive.Cancel>
@@ -18,7 +18,7 @@
18
18
  bind:ref
19
19
  data-slot="alert-dialog-content"
20
20
  class={cn(
21
- 'bg-white fixed left-[50%] top-[50%] z-[1002] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-5 pt-3 px-4 pb-4 sm:rounded-lg md:w-full',
21
+ 'bg-background fixed left-1/2 top-1/2 z-[1002] flex flex-col w-full max-w-lg -translate-x-1/2 -translate-y-1/2 rounded-xl overflow-clip',
22
22
  className
23
23
  )}
24
24
  >
@@ -12,7 +12,7 @@
12
12
  bind:ref
13
13
  data-slot="alert-dialog-description"
14
14
  class={cn(
15
- 'text-neutral-500 text-base flex flex-col space-y-2 justify-start items-start !mt-2',
15
+ 'text-base font-normal leading-5 tracking-tight text-foreground-default-secondary',
16
16
  className
17
17
  )}
18
18
  >
@@ -11,7 +11,7 @@
11
11
  <div
12
12
  bind:this={ref}
13
13
  data-slot="alert-dialog-footer"
14
- class={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-3', className)}
14
+ class={cn('flex gap-3 justify-end px-3 pb-3', className)}
15
15
  >
16
16
  {@render children?.()}
17
17
  </div>
@@ -11,7 +11,7 @@
11
11
  <div
12
12
  bind:this={ref}
13
13
  data-slot="alert-dialog-header"
14
- class={cn('flex flex-col space-y-1 text-center sm:text-left', className)}
14
+ class={cn('flex flex-col gap-1 px-4 py-3', className)}
15
15
  >
16
16
  {@render children?.()}
17
17
  </div>
@@ -11,7 +11,7 @@
11
11
  <AlertDialogPrimitive.Title
12
12
  bind:ref
13
13
  data-slot="alert-dialog-title"
14
- class={cn('text-lg font-semibold text-neutral-800', className)}
14
+ class={cn('text-lg font-semibold leading-6 tracking-tight text-foreground', className)}
15
15
  >
16
16
  {@render children?.()}
17
17
  </AlertDialogPrimitive.Title>
@@ -2,77 +2,251 @@
2
2
  import { cn, type WithElementRef } from '../utils.js'
3
3
  import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements'
4
4
  import { type VariantProps, tv } from 'tailwind-variants'
5
+ import type { IconSource } from '@steeze-ui/svelte-icon'
6
+
5
7
  export const buttonVariants = tv({
6
- base: 'cursor-pointer ring-workspace-accent-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 flex items-center justify-center font-medium font-sans relative group tracking-tight rounded-md text-base text-neutral-800 box-border',
8
+ base: 'inline-flex items-center justify-center font-medium text-base whitespace-nowrap focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-workspace-accent focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-30 relative overflow-hidden box-border cursor-pointer',
7
9
  variants: {
8
10
  variant: {
9
- default: 'bg-white text-neutral-800 hover:bg-primary/90',
10
- destructive:
11
- 'ring-danger-200 bg-danger-500 border border-danger-500 hover:bg-danger-600 hover:border-danger-600 active:bg-danger-700 active:border-danger-700 text-white',
12
- outline:
13
- 'border-neutral-200 bg-white hover:border-neutral-300 border shadow-button active:shadow-button-active',
14
11
  primary:
15
- 'bg-workspace-accent-500 hover:bg-workspace-accent-600 active:bg-workspace-accent-700 text-white',
12
+ 'bg-background-accent text-foreground-inverse border border-border shadow-button-primary hover:bg-background-accent-hover active:bg-background-accent-hover active:shadow-button-pressed [&_svg]:text-icon-inverse',
13
+ danger:
14
+ 'bg-background-default-tertiary text-foreground-critical border border-border shadow-button-default hover:bg-background-critical-bold hover:text-foreground-inverse hover:border-background-critical-bold active:bg-background-critical-bold active:text-foreground-inverse active:border-background-critical-bold active:shadow-[0px_4px_4px_-1px_inset_rgba(11,11,16,0.16)] [&_svg]:text-icon-critical hover:[&_svg]:text-icon-inverse active:[&_svg]:text-icon-inverse',
15
+ outline:
16
+ 'bg-background text-foreground border border-border-default-secondary shadow-button-default hover:border-border-default-secondary-hover active:shadow-button-pressed [&_svg]:text-icon',
17
+ ghost:
18
+ 'bg-transparent text-foreground hover:shadow-button-default active:shadow-button-pressed hover:bg-background-default-tertiary-hover active:bg-background-default-tertiary-hover [&_svg]:text-icon',
16
19
  secondary:
17
- 'bg-neutral-100 border border-neutral-100 hover:bg-neutral-200 hover:border-neutral-200 active:bg-neutral-300 active:border-neutral-300',
18
- ghost: 'hover:bg-accent hover:text-accent-foreground',
19
- link: 'text-primary underline-offset-4 hover:underline'
20
+ 'bg-background-default-tertiary text-foreground shadow-button-default hover:bg-background-default-tertiary-hover active:bg-background-default-tertiary-hover active:shadow-button-pressed [&_svg]:text-icon',
21
+ default:
22
+ 'bg-background text-foreground border border-border shadow-button-default hover:bg-background-default-secondary active:bg-background-default-tertiary active:shadow-button-pressed [&_svg]:text-icon',
23
+ dark: 'bg-transparent text-foreground-inverse border border-border-inverse-secondary hover:bg-background-selected-inverse active:bg-background-inverse-tertiary active:shadow-button-dark-pressed [&_svg]:text-icon-inverse'
20
24
  },
21
25
  size: {
22
- default: 'h-7 px-2 py-1',
23
- sm: 'h-9 rounded-md px-3',
24
- lg: 'h-11 rounded-md px-8',
25
- icon: 'h-7 p-1.5',
26
- 'icon-sm': 'size-6 p-1 active:pt-[5px] active:pb-[3px]'
26
+ sm: 'h-6 rounded-sm',
27
+ md: 'h-7 rounded-md',
28
+ lg: 'h-8 rounded-lg'
29
+ },
30
+ iconOnly: {
31
+ true: '',
32
+ false: ''
33
+ },
34
+ hasIcon: {
35
+ true: '',
36
+ false: ''
27
37
  }
28
38
  },
39
+ compoundVariants: [
40
+ // Icon-only padding (varies by size) - must come first to avoid conflicts
41
+ {
42
+ size: 'sm',
43
+ iconOnly: true,
44
+ class: '!p-1'
45
+ },
46
+ {
47
+ size: 'md',
48
+ iconOnly: true,
49
+ class: '!p-1.5'
50
+ },
51
+ {
52
+ size: 'lg',
53
+ iconOnly: true,
54
+ class: '!p-2'
55
+ },
56
+ // Vertical padding for buttons with text
57
+ {
58
+ size: ['sm', 'md'],
59
+ iconOnly: false,
60
+ class: 'py-1'
61
+ },
62
+ {
63
+ size: 'lg',
64
+ iconOnly: false,
65
+ class: 'py-1.5'
66
+ },
67
+ // No icon - symmetric padding
68
+ {
69
+ size: ['sm', 'md'],
70
+ iconOnly: false,
71
+ hasIcon: false,
72
+ class: 'px-2'
73
+ },
74
+ {
75
+ size: 'lg',
76
+ iconOnly: false,
77
+ hasIcon: false,
78
+ class: 'px-3'
79
+ },
80
+ // Icon-left - asymmetric padding (less on icon side)
81
+ {
82
+ size: ['sm', 'md'],
83
+ iconOnly: false,
84
+ hasIcon: true,
85
+ class: 'pl-1.5 pr-2'
86
+ },
87
+ {
88
+ size: 'lg',
89
+ iconOnly: false,
90
+ hasIcon: true,
91
+ class: 'pl-2 pr-3'
92
+ },
93
+ // Icon-only uses bold icon variants
94
+ {
95
+ variant: ['secondary', 'default', 'outline', 'ghost'],
96
+ iconOnly: true,
97
+ class: '[&_svg]:!text-icon-default-bold'
98
+ },
99
+ {
100
+ variant: 'primary',
101
+ iconOnly: true,
102
+ class: '[&_svg]:!text-icon-inverse-bold'
103
+ },
104
+ {
105
+ variant: 'dark',
106
+ iconOnly: true,
107
+ class: '[&_svg]:!text-icon-inverse-bold'
108
+ },
109
+ {
110
+ size: 'sm',
111
+ iconOnly: true,
112
+ class: 'w-6'
113
+ },
114
+ {
115
+ size: 'md',
116
+ iconOnly: true,
117
+ class: 'w-7'
118
+ },
119
+ {
120
+ size: 'lg',
121
+ iconOnly: true,
122
+ class: 'w-8'
123
+ }
124
+ ],
29
125
  defaultVariants: {
30
- variant: 'default',
31
- size: 'default'
126
+ variant: 'primary',
127
+ size: 'md',
128
+ iconOnly: false,
129
+ hasIcon: false
32
130
  }
33
131
  })
132
+
34
133
  export type ButtonVariant = VariantProps<typeof buttonVariants>['variant']
35
134
  export type ButtonSize = VariantProps<typeof buttonVariants>['size']
36
135
  export type ButtonProps = WithElementRef<HTMLButtonAttributes> &
37
136
  WithElementRef<HTMLAnchorAttributes> & {
38
137
  variant?: ButtonVariant
39
138
  size?: ButtonSize
139
+ icon?: IconSource
140
+ iconPosition?: 'left' | 'right'
141
+ iconClass?: string
40
142
  }
41
143
  </script>
42
144
 
43
145
  <script lang="ts">
146
+ import { Icon } from '@steeze-ui/svelte-icon'
147
+
44
148
  let {
45
149
  class: className,
46
- variant = 'default',
47
- size = 'default',
150
+ variant = 'primary',
151
+ size = 'lg',
152
+ icon,
153
+ iconPosition = 'left',
154
+ iconClass = '',
48
155
  ref = $bindable(null),
49
156
  href = undefined,
50
157
  type = 'button',
51
158
  disabled,
52
- children
159
+ children,
160
+ onclick,
161
+ ...rest
53
162
  }: ButtonProps = $props()
163
+
164
+ let iconOnly = $derived(!children)
165
+ let hasIcon = $derived(!!icon && !iconOnly)
166
+
167
+ let iconSize = $derived(
168
+ {
169
+ sm: 'size-3',
170
+ md: 'size-4',
171
+ lg: 'size-4'
172
+ }[size]
173
+ )
174
+
175
+ // For icon-right, we need to reverse the padding
176
+ let paddingClass = $derived(
177
+ iconPosition === 'right' && hasIcon ? (size === 'lg' ? 'pl-3 pr-2' : 'pl-2 pr-1.5') : ''
178
+ )
54
179
  </script>
55
180
 
181
+ {#snippet iconContent()}
182
+ {#if icon}
183
+ <div class={cn('relative z-10', iconClass && `[&_svg]:${iconClass}`)}>
184
+ <Icon src={icon} class={iconSize} />
185
+ </div>
186
+ {/if}
187
+ {/snippet}
188
+
189
+ {#snippet buttonContent()}
190
+ <div
191
+ class={cn(
192
+ 'inline-flex items-center transition-transform group-active:translate-y-px',
193
+ !iconOnly && 'gap-1'
194
+ )}
195
+ >
196
+ {#if icon && !children}
197
+ {@render iconContent()}
198
+ {:else if iconPosition === 'right'}
199
+ {#if children}
200
+ <span class="z-10">{@render children()}</span>
201
+ {/if}
202
+ {#if icon}
203
+ {@render iconContent()}
204
+ {/if}
205
+ {:else}
206
+ {#if icon}
207
+ {@render iconContent()}
208
+ {/if}
209
+ {#if children}
210
+ <span class="z-10">{@render children()}</span>
211
+ {/if}
212
+ {/if}
213
+ </div>
214
+ {/snippet}
215
+
56
216
  {#if href}
57
217
  <a
58
218
  bind:this={ref}
59
219
  data-slot="button"
60
- class={cn(buttonVariants({ variant, size }), className)}
220
+ class={cn(
221
+ buttonVariants({ variant, size, iconOnly, hasIcon }),
222
+ iconPosition === 'right' && 'flex-row-reverse',
223
+ paddingClass,
224
+ className
225
+ )}
61
226
  href={disabled ? undefined : href}
62
227
  aria-disabled={disabled}
63
228
  role={disabled ? 'link' : undefined}
64
229
  tabindex={disabled ? -1 : undefined}
230
+ {...rest}
65
231
  >
66
- {@render children?.()}
232
+ {@render buttonContent()}
67
233
  </a>
68
234
  {:else}
69
235
  <button
70
236
  bind:this={ref}
71
237
  data-slot="button"
72
- class={cn(buttonVariants({ variant, size }), className)}
238
+ class={cn(
239
+ buttonVariants({ variant, size, iconOnly, hasIcon }),
240
+ 'group',
241
+ iconPosition === 'right' && 'flex-row-reverse',
242
+ paddingClass,
243
+ className
244
+ )}
73
245
  {type}
74
246
  {disabled}
247
+ {onclick}
248
+ {...rest}
75
249
  >
76
- {@render children?.()}
250
+ {@render buttonContent()}
77
251
  </button>
78
252
  {/if}
@@ -1,63 +1,85 @@
1
1
  import { type WithElementRef } from '../utils.js';
2
2
  import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
3
3
  import { type VariantProps } from 'tailwind-variants';
4
+ import type { IconSource } from '@steeze-ui/svelte-icon';
4
5
  export declare const buttonVariants: import("tailwind-variants").TVReturnType<{
5
6
  variant: {
6
- default: string;
7
- destructive: string;
8
- outline: string;
9
7
  primary: string;
10
- secondary: string;
8
+ danger: string;
9
+ outline: string;
11
10
  ghost: string;
12
- link: string;
11
+ secondary: string;
12
+ default: string;
13
+ dark: string;
13
14
  };
14
15
  size: {
15
- default: string;
16
16
  sm: string;
17
+ md: string;
17
18
  lg: string;
18
- icon: string;
19
- 'icon-sm': string;
20
19
  };
21
- }, undefined, "cursor-pointer ring-workspace-accent-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 flex items-center justify-center font-medium font-sans relative group tracking-tight rounded-md text-base text-neutral-800 box-border", {
20
+ iconOnly: {
21
+ true: string;
22
+ false: string;
23
+ };
24
+ hasIcon: {
25
+ true: string;
26
+ false: string;
27
+ };
28
+ }, undefined, "inline-flex items-center justify-center font-medium text-base whitespace-nowrap focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-workspace-accent focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-30 relative overflow-hidden box-border cursor-pointer", {
22
29
  variant: {
23
- default: string;
24
- destructive: string;
25
- outline: string;
26
30
  primary: string;
27
- secondary: string;
31
+ danger: string;
32
+ outline: string;
28
33
  ghost: string;
29
- link: string;
34
+ secondary: string;
35
+ default: string;
36
+ dark: string;
30
37
  };
31
38
  size: {
32
- default: string;
33
39
  sm: string;
40
+ md: string;
34
41
  lg: string;
35
- icon: string;
36
- 'icon-sm': string;
42
+ };
43
+ iconOnly: {
44
+ true: string;
45
+ false: string;
46
+ };
47
+ hasIcon: {
48
+ true: string;
49
+ false: string;
37
50
  };
38
51
  }, undefined, import("tailwind-variants").TVReturnType<{
39
52
  variant: {
40
- default: string;
41
- destructive: string;
42
- outline: string;
43
53
  primary: string;
44
- secondary: string;
54
+ danger: string;
55
+ outline: string;
45
56
  ghost: string;
46
- link: string;
57
+ secondary: string;
58
+ default: string;
59
+ dark: string;
47
60
  };
48
61
  size: {
49
- default: string;
50
62
  sm: string;
63
+ md: string;
51
64
  lg: string;
52
- icon: string;
53
- 'icon-sm': string;
54
65
  };
55
- }, undefined, "cursor-pointer ring-workspace-accent-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 flex items-center justify-center font-medium font-sans relative group tracking-tight rounded-md text-base text-neutral-800 box-border", unknown, unknown, undefined>>;
66
+ iconOnly: {
67
+ true: string;
68
+ false: string;
69
+ };
70
+ hasIcon: {
71
+ true: string;
72
+ false: string;
73
+ };
74
+ }, undefined, "inline-flex items-center justify-center font-medium text-base whitespace-nowrap focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-workspace-accent focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-30 relative overflow-hidden box-border cursor-pointer", unknown, unknown, undefined>>;
56
75
  export type ButtonVariant = VariantProps<typeof buttonVariants>['variant'];
57
76
  export type ButtonSize = VariantProps<typeof buttonVariants>['size'];
58
77
  export type ButtonProps = WithElementRef<HTMLButtonAttributes> & WithElementRef<HTMLAnchorAttributes> & {
59
78
  variant?: ButtonVariant;
60
79
  size?: ButtonSize;
80
+ icon?: IconSource;
81
+ iconPosition?: 'left' | 'right';
82
+ iconClass?: string;
61
83
  };
62
84
  declare const Button: import("svelte").Component<ButtonProps, {}, "ref">;
63
85
  type Button = ReturnType<typeof Button>;