@tallyui/components 1.0.0 → 2.0.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 (136) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.d.ts +1076 -76
  3. package/dist/index.js +4662 -355
  4. package/package.json +27 -5
  5. package/src/cart/cart-line-actions.tsx +40 -0
  6. package/src/cart/cart-line.tsx +18 -32
  7. package/src/cart/cart-note-input.tsx +46 -0
  8. package/src/cart/cart-panel.tsx +39 -26
  9. package/src/cart/cart-total.tsx +43 -47
  10. package/src/cart/discount-badge.tsx +19 -0
  11. package/src/cart/index.ts +4 -1
  12. package/src/checkout/cash-tendered.tsx +101 -0
  13. package/src/checkout/change-display.tsx +19 -0
  14. package/src/checkout/index.ts +3 -0
  15. package/src/checkout/order-summary-line.tsx +7 -8
  16. package/src/checkout/order-summary.tsx +8 -7
  17. package/src/checkout/payment-method-card.tsx +10 -9
  18. package/src/checkout/payment-selector.tsx +5 -5
  19. package/src/checkout/receipt-preview.tsx +78 -0
  20. package/src/customer/customer-card.tsx +8 -9
  21. package/src/customer/customer-form.tsx +70 -0
  22. package/src/customer/customer-order-history.tsx +34 -0
  23. package/src/customer/customer-select.tsx +63 -24
  24. package/src/customer/index.ts +2 -0
  25. package/src/index.ts +112 -1
  26. package/src/input/filter-chip.tsx +85 -27
  27. package/src/input/index.ts +1 -0
  28. package/src/input/quantity-stepper.tsx +64 -0
  29. package/src/input/search-input.tsx +30 -7
  30. package/src/layout/checkout-layout.tsx +46 -0
  31. package/src/layout/index.ts +5 -0
  32. package/src/layout/live-tab-screen.tsx +54 -0
  33. package/src/layout/pos-layout.tsx +64 -0
  34. package/src/layout/settings-layout.tsx +58 -0
  35. package/src/layout/store-settings-choice-screen.tsx +142 -0
  36. package/src/order/index.ts +4 -0
  37. package/src/order/order-card.tsx +48 -0
  38. package/src/order/order-detail.tsx +82 -0
  39. package/src/order/order-list.tsx +39 -0
  40. package/src/order/order-status-badge.tsx +32 -0
  41. package/src/product/category-nav.tsx +70 -0
  42. package/src/product/index.ts +3 -0
  43. package/src/product/product-card.tsx +36 -8
  44. package/src/product/product-grid.tsx +25 -6
  45. package/src/product/product-image.tsx +28 -7
  46. package/src/product/product-list.tsx +44 -0
  47. package/src/product/product-price.tsx +77 -22
  48. package/src/product/product-sku.tsx +5 -5
  49. package/src/product/product-stock-badge.tsx +41 -28
  50. package/src/product/product-title.tsx +2 -3
  51. package/src/product/product-variant-picker.tsx +61 -0
  52. package/src/register/cash-count-input.tsx +85 -0
  53. package/src/register/closure-sheet.tsx +155 -0
  54. package/src/register/index.ts +12 -0
  55. package/src/register/movement-sheet.tsx +118 -0
  56. package/src/register/open-register-card.tsx +109 -0
  57. package/src/register/register-bar.helpers.ts +57 -0
  58. package/src/register/register-bar.tsx +85 -0
  59. package/src/register/register-column.tsx +117 -0
  60. package/src/register/register-count.tsx +330 -0
  61. package/src/register/register-open-close.tsx +52 -0
  62. package/src/register/register-panel.tsx +151 -0
  63. package/src/register/register-picker.tsx +60 -0
  64. package/src/register/register-summary.tsx +72 -0
  65. package/src/sale/cart-bar.tsx +18 -0
  66. package/src/sale/cart.tsx +66 -0
  67. package/src/sale/catalogue.tsx +131 -0
  68. package/src/sale/discount-form.tsx +85 -0
  69. package/src/sale/index.ts +9 -0
  70. package/src/sale/orders-list.tsx +66 -0
  71. package/src/sale/print-style.ts +11 -0
  72. package/src/sale/receipt.tsx +61 -0
  73. package/src/sale/sync-status.tsx +20 -0
  74. package/src/sale/tender.tsx +35 -0
  75. package/src/settings/connector-status.tsx +65 -0
  76. package/src/settings/index.ts +3 -0
  77. package/src/settings/settings-group.tsx +23 -0
  78. package/src/settings/settings-row.tsx +23 -0
  79. package/src/ui/accordion/index.tsx +59 -0
  80. package/src/ui/alert-dialog/index.tsx +91 -0
  81. package/src/ui/avatar/index.tsx +50 -0
  82. package/src/ui/badge/index.tsx +60 -0
  83. package/src/ui/button/index.tsx +90 -0
  84. package/src/ui/card/index.tsx +60 -0
  85. package/src/ui/checkbox/index.tsx +29 -0
  86. package/src/ui/collapsible/index.tsx +24 -0
  87. package/src/ui/combobox/index.tsx +98 -0
  88. package/src/ui/context-menu/index.tsx +159 -0
  89. package/src/ui/dialog/index.tsx +92 -0
  90. package/src/ui/dropdown-menu/index.tsx +161 -0
  91. package/src/ui/hover-card/index.tsx +31 -0
  92. package/src/ui/hstack/index.tsx +43 -0
  93. package/src/ui/icon/index.tsx +44 -0
  94. package/src/ui/icon/search-icon.tsx +9 -0
  95. package/src/ui/icon/svg-icon.tsx +36 -0
  96. package/src/ui/icon-button/index.tsx +58 -0
  97. package/src/ui/index.ts +99 -0
  98. package/src/ui/input/index.tsx +100 -0
  99. package/src/ui/label/index.tsx +26 -0
  100. package/src/ui/loader/index.tsx +37 -0
  101. package/src/ui/popover/index.tsx +31 -0
  102. package/src/ui/progress/index.tsx +28 -0
  103. package/src/ui/radio-group/index.tsx +38 -0
  104. package/src/ui/select/index.tsx +96 -0
  105. package/src/ui/separator/index.tsx +29 -0
  106. package/src/ui/slider/index.tsx +28 -0
  107. package/src/ui/switch/index.tsx +31 -0
  108. package/src/ui/table/index.tsx +59 -0
  109. package/src/ui/tabs/index.tsx +53 -0
  110. package/src/ui/text/index.tsx +36 -0
  111. package/src/ui/textarea/index.tsx +29 -0
  112. package/src/ui/toast/index.tsx +52 -0
  113. package/src/ui/toggle/index.tsx +69 -0
  114. package/src/ui/toggle-group/index.tsx +66 -0
  115. package/src/ui/tooltip/index.tsx +30 -0
  116. package/src/ui/vstack/index.tsx +43 -0
  117. package/src/uniwind-env.d.ts +9 -1
  118. package/src/__tests__/cart-line.test.tsx +0 -53
  119. package/src/__tests__/cart-panel.test.tsx +0 -55
  120. package/src/__tests__/cart-total.test.tsx +0 -60
  121. package/src/__tests__/customer-card.test.tsx +0 -47
  122. package/src/__tests__/customer-select.test.tsx +0 -33
  123. package/src/__tests__/filter-chip.test.tsx +0 -40
  124. package/src/__tests__/helpers.ts +0 -111
  125. package/src/__tests__/order-summary-line.test.tsx +0 -18
  126. package/src/__tests__/order-summary.test.tsx +0 -32
  127. package/src/__tests__/payment-method-card.test.tsx +0 -24
  128. package/src/__tests__/payment-selector.test.tsx +0 -23
  129. package/src/__tests__/product-card.test.tsx +0 -31
  130. package/src/__tests__/product-grid.test.tsx +0 -37
  131. package/src/__tests__/product-image.test.tsx +0 -54
  132. package/src/__tests__/product-price.test.tsx +0 -68
  133. package/src/__tests__/product-sku.test.tsx +0 -47
  134. package/src/__tests__/product-stock-badge.test.tsx +0 -58
  135. package/src/__tests__/product-title.test.tsx +0 -38
  136. package/src/__tests__/search-input.test.tsx +0 -22
@@ -0,0 +1,159 @@
1
+ import * as React from 'react';
2
+ import { ContextMenu as ContextMenuPrimitive, TextClassContext } from '@tallyui/primitives';
3
+ import { cn } from '@tallyui/theme';
4
+
5
+ const ContextMenu = ContextMenuPrimitive.Root;
6
+ const ContextMenuTrigger = ContextMenuPrimitive.Trigger;
7
+ const ContextMenuGroup = ContextMenuPrimitive.Group;
8
+ const ContextMenuPortal = ContextMenuPrimitive.Portal;
9
+ const ContextMenuSub = ContextMenuPrimitive.Sub;
10
+ const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;
11
+
12
+ const ContextMenuContent = React.forwardRef<
13
+ React.ComponentRef<typeof ContextMenuPrimitive.Content>,
14
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>
15
+ >(function ContextMenuContent({ className, ...props }, ref) {
16
+ return (
17
+ <ContextMenuPrimitive.Portal>
18
+ <ContextMenuPrimitive.Content
19
+ ref={ref}
20
+ className={cn(
21
+ 'z-50 min-w-[8rem] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md',
22
+ className,
23
+ )}
24
+ {...props}
25
+ />
26
+ </ContextMenuPrimitive.Portal>
27
+ );
28
+ });
29
+ ContextMenuContent.displayName = 'ContextMenuContent';
30
+
31
+ const ContextMenuItem = React.forwardRef<
32
+ React.ComponentRef<typeof ContextMenuPrimitive.Item>,
33
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & { inset?: boolean }
34
+ >(function ContextMenuItem({ className, inset, ...props }, ref) {
35
+ return (
36
+ <TextClassContext.Provider value="select-none text-sm">
37
+ <ContextMenuPrimitive.Item
38
+ ref={ref}
39
+ className={cn(
40
+ 'relative flex cursor-default select-none flex-row items-center rounded-sm px-2 py-1.5 text-sm outline-none web:focus:bg-accent web:focus:text-accent-foreground',
41
+ inset && 'pl-8',
42
+ className,
43
+ )}
44
+ {...props}
45
+ />
46
+ </TextClassContext.Provider>
47
+ );
48
+ });
49
+ ContextMenuItem.displayName = 'ContextMenuItem';
50
+
51
+ const ContextMenuCheckboxItem = React.forwardRef<
52
+ React.ComponentRef<typeof ContextMenuPrimitive.CheckboxItem>,
53
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>
54
+ >(function ContextMenuCheckboxItem({ className, children, checked, ...props }, ref) {
55
+ return (
56
+ <ContextMenuPrimitive.CheckboxItem
57
+ ref={ref}
58
+ checked={checked}
59
+ className={cn(
60
+ 'relative flex cursor-default select-none flex-row items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none web:focus:bg-accent web:focus:text-accent-foreground',
61
+ className,
62
+ )}
63
+ {...props}
64
+ >
65
+ {children}
66
+ </ContextMenuPrimitive.CheckboxItem>
67
+ );
68
+ });
69
+ ContextMenuCheckboxItem.displayName = 'ContextMenuCheckboxItem';
70
+
71
+ const ContextMenuRadioItem = React.forwardRef<
72
+ React.ComponentRef<typeof ContextMenuPrimitive.RadioItem>,
73
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>
74
+ >(function ContextMenuRadioItem({ className, children, ...props }, ref) {
75
+ return (
76
+ <ContextMenuPrimitive.RadioItem
77
+ ref={ref}
78
+ className={cn(
79
+ 'relative flex cursor-default select-none flex-row items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none web:focus:bg-accent web:focus:text-accent-foreground',
80
+ className,
81
+ )}
82
+ {...props}
83
+ >
84
+ {children}
85
+ </ContextMenuPrimitive.RadioItem>
86
+ );
87
+ });
88
+ ContextMenuRadioItem.displayName = 'ContextMenuRadioItem';
89
+
90
+ const ContextMenuLabel = React.forwardRef<
91
+ React.ComponentRef<typeof ContextMenuPrimitive.Label>,
92
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & { inset?: boolean }
93
+ >(function ContextMenuLabel({ className, inset, ...props }, ref) {
94
+ return (
95
+ <ContextMenuPrimitive.Label
96
+ ref={ref}
97
+ className={cn('px-2 py-1.5 text-sm font-semibold', inset && 'pl-8', className)}
98
+ {...props}
99
+ />
100
+ );
101
+ });
102
+ ContextMenuLabel.displayName = 'ContextMenuLabel';
103
+
104
+ const ContextMenuSeparator = React.forwardRef<
105
+ React.ComponentRef<typeof ContextMenuPrimitive.Separator>,
106
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>
107
+ >(function ContextMenuSeparator({ className, ...props }, ref) {
108
+ return (
109
+ <ContextMenuPrimitive.Separator ref={ref} className={cn('-mx-1 my-1 h-px bg-muted', className)} {...props} />
110
+ );
111
+ });
112
+ ContextMenuSeparator.displayName = 'ContextMenuSeparator';
113
+
114
+ const ContextMenuSubTrigger = React.forwardRef<
115
+ React.ComponentRef<typeof ContextMenuPrimitive.SubTrigger>,
116
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & { inset?: boolean }
117
+ >(function ContextMenuSubTrigger({ className, inset, children, ...props }, ref) {
118
+ return (
119
+ <TextClassContext.Provider value="select-none text-sm">
120
+ <ContextMenuPrimitive.SubTrigger
121
+ ref={ref}
122
+ className={cn(
123
+ 'flex cursor-default select-none flex-row items-center rounded-sm px-2 py-1.5 text-sm outline-none web:focus:bg-accent',
124
+ inset && 'pl-8',
125
+ className,
126
+ )}
127
+ {...props}
128
+ >
129
+ {children}
130
+ </ContextMenuPrimitive.SubTrigger>
131
+ </TextClassContext.Provider>
132
+ );
133
+ });
134
+ ContextMenuSubTrigger.displayName = 'ContextMenuSubTrigger';
135
+
136
+ const ContextMenuSubContent = React.forwardRef<
137
+ React.ComponentRef<typeof ContextMenuPrimitive.SubContent>,
138
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>
139
+ >(function ContextMenuSubContent({ className, ...props }, ref) {
140
+ return (
141
+ <ContextMenuPrimitive.SubContent
142
+ ref={ref}
143
+ className={cn(
144
+ 'z-50 min-w-[8rem] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-lg',
145
+ className,
146
+ )}
147
+ {...props}
148
+ />
149
+ );
150
+ });
151
+ ContextMenuSubContent.displayName = 'ContextMenuSubContent';
152
+
153
+ export {
154
+ ContextMenu, ContextMenuTrigger, ContextMenuContent, ContextMenuItem,
155
+ ContextMenuCheckboxItem, ContextMenuRadioItem, ContextMenuLabel,
156
+ ContextMenuSeparator, ContextMenuGroup, ContextMenuPortal,
157
+ ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger,
158
+ ContextMenuRadioGroup,
159
+ };
@@ -0,0 +1,92 @@
1
+ import * as React from 'react';
2
+ import { View, Text, Pressable } from 'react-native';
3
+ import { Dialog as DialogPrimitive, TextClassContext } from '@tallyui/primitives';
4
+ import { cn } from '@tallyui/theme';
5
+
6
+ const Dialog = DialogPrimitive.Root;
7
+ const DialogTrigger = DialogPrimitive.Trigger;
8
+ const DialogPortal = DialogPrimitive.Portal;
9
+ const DialogClose = DialogPrimitive.Close;
10
+
11
+ const DialogOverlay = React.forwardRef<
12
+ React.ComponentRef<typeof DialogPrimitive.Overlay>,
13
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
14
+ >(function DialogOverlay({ className, ...props }, ref) {
15
+ return (
16
+ <DialogPrimitive.Overlay
17
+ ref={ref}
18
+ className={cn('fixed inset-0 z-50 bg-black/80', className)}
19
+ {...props}
20
+ />
21
+ );
22
+ });
23
+ DialogOverlay.displayName = 'DialogOverlay';
24
+
25
+ const DialogContent = React.forwardRef<
26
+ React.ComponentRef<typeof DialogPrimitive.Content>,
27
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
28
+ >(function DialogContent({ className, children, ...props }, ref) {
29
+ return (
30
+ <DialogPortal>
31
+ <DialogOverlay />
32
+ <DialogPrimitive.Content
33
+ ref={ref}
34
+ className={cn(
35
+ 'fixed left-1/2 top-1/2 z-50 w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 rounded-lg border border-border bg-background p-6 shadow-lg',
36
+ className,
37
+ )}
38
+ {...props}
39
+ >
40
+ {children}
41
+ </DialogPrimitive.Content>
42
+ </DialogPortal>
43
+ );
44
+ });
45
+ DialogContent.displayName = 'DialogContent';
46
+
47
+ function DialogHeader({ className, ...props }: React.ComponentPropsWithoutRef<typeof View>) {
48
+ return (
49
+ <View className={cn('flex flex-col gap-1.5 text-center sm:text-left', className)} {...props} />
50
+ );
51
+ }
52
+
53
+ function DialogFooter({ className, ...props }: React.ComponentPropsWithoutRef<typeof View>) {
54
+ return (
55
+ <View className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:gap-2', className)} {...props} />
56
+ );
57
+ }
58
+
59
+ const DialogTitle = React.forwardRef<
60
+ React.ComponentRef<typeof DialogPrimitive.Title>,
61
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
62
+ >(function DialogTitle({ className, ...props }, ref) {
63
+ return (
64
+ <TextClassContext.Provider value="text-lg font-semibold leading-none text-foreground">
65
+ <DialogPrimitive.Title ref={ref} className={cn('text-lg font-semibold leading-none text-foreground', className)} {...props} />
66
+ </TextClassContext.Provider>
67
+ );
68
+ });
69
+ DialogTitle.displayName = 'DialogTitle';
70
+
71
+ const DialogDescription = React.forwardRef<
72
+ React.ComponentRef<typeof DialogPrimitive.Description>,
73
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
74
+ >(function DialogDescription({ className, ...props }, ref) {
75
+ return (
76
+ <DialogPrimitive.Description ref={ref} className={cn('text-sm text-muted-foreground', className)} {...props} />
77
+ );
78
+ });
79
+ DialogDescription.displayName = 'DialogDescription';
80
+
81
+ export {
82
+ Dialog,
83
+ DialogTrigger,
84
+ DialogPortal,
85
+ DialogOverlay,
86
+ DialogContent,
87
+ DialogHeader,
88
+ DialogFooter,
89
+ DialogTitle,
90
+ DialogDescription,
91
+ DialogClose,
92
+ };
@@ -0,0 +1,161 @@
1
+ import * as React from 'react';
2
+ import { View } from 'react-native';
3
+ import { DropdownMenu as DropdownMenuPrimitive, TextClassContext } from '@tallyui/primitives';
4
+ import { cn } from '@tallyui/theme';
5
+
6
+ const DropdownMenu = DropdownMenuPrimitive.Root;
7
+ const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
8
+ const DropdownMenuGroup = DropdownMenuPrimitive.Group;
9
+ const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
10
+ const DropdownMenuSub = DropdownMenuPrimitive.Sub;
11
+ const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
12
+
13
+ const DropdownMenuContent = React.forwardRef<
14
+ React.ComponentRef<typeof DropdownMenuPrimitive.Content>,
15
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
16
+ >(function DropdownMenuContent({ className, sideOffset = 4, ...props }, ref) {
17
+ return (
18
+ <DropdownMenuPrimitive.Portal>
19
+ <DropdownMenuPrimitive.Content
20
+ ref={ref}
21
+ sideOffset={sideOffset}
22
+ className={cn(
23
+ 'z-50 min-w-[8rem] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md',
24
+ className,
25
+ )}
26
+ {...props}
27
+ />
28
+ </DropdownMenuPrimitive.Portal>
29
+ );
30
+ });
31
+ DropdownMenuContent.displayName = 'DropdownMenuContent';
32
+
33
+ const DropdownMenuItem = React.forwardRef<
34
+ React.ComponentRef<typeof DropdownMenuPrimitive.Item>,
35
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { inset?: boolean }
36
+ >(function DropdownMenuItem({ className, inset, ...props }, ref) {
37
+ return (
38
+ <TextClassContext.Provider value="select-none text-sm">
39
+ <DropdownMenuPrimitive.Item
40
+ ref={ref}
41
+ className={cn(
42
+ 'relative flex cursor-default select-none flex-row items-center rounded-sm px-2 py-1.5 text-sm outline-none web:focus:bg-accent web:focus:text-accent-foreground',
43
+ inset && 'pl-8',
44
+ className,
45
+ )}
46
+ {...props}
47
+ />
48
+ </TextClassContext.Provider>
49
+ );
50
+ });
51
+ DropdownMenuItem.displayName = 'DropdownMenuItem';
52
+
53
+ const DropdownMenuCheckboxItem = React.forwardRef<
54
+ React.ComponentRef<typeof DropdownMenuPrimitive.CheckboxItem>,
55
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
56
+ >(function DropdownMenuCheckboxItem({ className, children, checked, ...props }, ref) {
57
+ return (
58
+ <DropdownMenuPrimitive.CheckboxItem
59
+ ref={ref}
60
+ checked={checked}
61
+ className={cn(
62
+ 'relative flex cursor-default select-none flex-row items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none web:focus:bg-accent web:focus:text-accent-foreground',
63
+ className,
64
+ )}
65
+ {...props}
66
+ >
67
+ {children}
68
+ </DropdownMenuPrimitive.CheckboxItem>
69
+ );
70
+ });
71
+ DropdownMenuCheckboxItem.displayName = 'DropdownMenuCheckboxItem';
72
+
73
+ const DropdownMenuRadioItem = React.forwardRef<
74
+ React.ComponentRef<typeof DropdownMenuPrimitive.RadioItem>,
75
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
76
+ >(function DropdownMenuRadioItem({ className, children, ...props }, ref) {
77
+ return (
78
+ <DropdownMenuPrimitive.RadioItem
79
+ ref={ref}
80
+ className={cn(
81
+ 'relative flex cursor-default select-none flex-row items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none web:focus:bg-accent web:focus:text-accent-foreground',
82
+ className,
83
+ )}
84
+ {...props}
85
+ >
86
+ {children}
87
+ </DropdownMenuPrimitive.RadioItem>
88
+ );
89
+ });
90
+ DropdownMenuRadioItem.displayName = 'DropdownMenuRadioItem';
91
+
92
+ const DropdownMenuLabel = React.forwardRef<
93
+ React.ComponentRef<typeof DropdownMenuPrimitive.Label>,
94
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & { inset?: boolean }
95
+ >(function DropdownMenuLabel({ className, inset, ...props }, ref) {
96
+ return (
97
+ <DropdownMenuPrimitive.Label
98
+ ref={ref}
99
+ className={cn('px-2 py-1.5 text-sm font-semibold', inset && 'pl-8', className)}
100
+ {...props}
101
+ />
102
+ );
103
+ });
104
+ DropdownMenuLabel.displayName = 'DropdownMenuLabel';
105
+
106
+ const DropdownMenuSeparator = React.forwardRef<
107
+ React.ComponentRef<typeof DropdownMenuPrimitive.Separator>,
108
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
109
+ >(function DropdownMenuSeparator({ className, ...props }, ref) {
110
+ return (
111
+ <DropdownMenuPrimitive.Separator ref={ref} className={cn('-mx-1 my-1 h-px bg-muted', className)} {...props} />
112
+ );
113
+ });
114
+ DropdownMenuSeparator.displayName = 'DropdownMenuSeparator';
115
+
116
+ const DropdownMenuSubTrigger = React.forwardRef<
117
+ React.ComponentRef<typeof DropdownMenuPrimitive.SubTrigger>,
118
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & { inset?: boolean }
119
+ >(function DropdownMenuSubTrigger({ className, inset, children, ...props }, ref) {
120
+ return (
121
+ <TextClassContext.Provider value="select-none text-sm">
122
+ <DropdownMenuPrimitive.SubTrigger
123
+ ref={ref}
124
+ className={cn(
125
+ 'flex cursor-default select-none flex-row items-center rounded-sm px-2 py-1.5 text-sm outline-none web:focus:bg-accent',
126
+ inset && 'pl-8',
127
+ className,
128
+ )}
129
+ {...props}
130
+ >
131
+ {children}
132
+ </DropdownMenuPrimitive.SubTrigger>
133
+ </TextClassContext.Provider>
134
+ );
135
+ });
136
+ DropdownMenuSubTrigger.displayName = 'DropdownMenuSubTrigger';
137
+
138
+ const DropdownMenuSubContent = React.forwardRef<
139
+ React.ComponentRef<typeof DropdownMenuPrimitive.SubContent>,
140
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
141
+ >(function DropdownMenuSubContent({ className, ...props }, ref) {
142
+ return (
143
+ <DropdownMenuPrimitive.SubContent
144
+ ref={ref}
145
+ className={cn(
146
+ 'z-50 min-w-[8rem] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-lg',
147
+ className,
148
+ )}
149
+ {...props}
150
+ />
151
+ );
152
+ });
153
+ DropdownMenuSubContent.displayName = 'DropdownMenuSubContent';
154
+
155
+ export {
156
+ DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem,
157
+ DropdownMenuCheckboxItem, DropdownMenuRadioItem, DropdownMenuLabel,
158
+ DropdownMenuSeparator, DropdownMenuGroup, DropdownMenuPortal,
159
+ DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger,
160
+ DropdownMenuRadioGroup,
161
+ };
@@ -0,0 +1,31 @@
1
+ import * as React from 'react';
2
+ import { HoverCard as HoverCardPrimitive, TextClassContext } from '@tallyui/primitives';
3
+ import { cn } from '@tallyui/theme';
4
+
5
+ const HoverCard = HoverCardPrimitive.Root;
6
+ const HoverCardTrigger = HoverCardPrimitive.Trigger;
7
+
8
+ const HoverCardContent = React.forwardRef<
9
+ React.ComponentRef<typeof HoverCardPrimitive.Content>,
10
+ React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>
11
+ >(function HoverCardContent({ className, align = 'center', sideOffset = 4, ...props }, ref) {
12
+ return (
13
+ <HoverCardPrimitive.Portal>
14
+ <TextClassContext.Provider value="text-popover-foreground">
15
+ <HoverCardPrimitive.Content
16
+ ref={ref}
17
+ align={align}
18
+ sideOffset={sideOffset}
19
+ className={cn(
20
+ 'z-50 w-64 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md outline-none',
21
+ className,
22
+ )}
23
+ {...props}
24
+ />
25
+ </TextClassContext.Provider>
26
+ </HoverCardPrimitive.Portal>
27
+ );
28
+ });
29
+ HoverCardContent.displayName = 'HoverCardContent';
30
+
31
+ export { HoverCard, HoverCardTrigger, HoverCardContent };
@@ -0,0 +1,43 @@
1
+ import * as React from 'react';
2
+ import { View, type ViewProps } from 'react-native';
3
+ import { cn } from '@tallyui/theme';
4
+ import { cva, type VariantProps } from 'class-variance-authority';
5
+
6
+ const hstackVariants = cva('flex-row items-center', {
7
+ variants: {
8
+ space: {
9
+ none: 'gap-0',
10
+ xs: 'gap-1',
11
+ sm: 'gap-2',
12
+ md: 'gap-3',
13
+ lg: 'gap-4',
14
+ xl: 'gap-6',
15
+ },
16
+ reversed: {
17
+ true: 'flex-row-reverse',
18
+ },
19
+ },
20
+ defaultVariants: {
21
+ space: 'md',
22
+ },
23
+ });
24
+
25
+ type HStackProps = ViewProps & VariantProps<typeof hstackVariants>;
26
+
27
+ const HStack = React.forwardRef<View, HStackProps>(function HStack(
28
+ { className, space, reversed, ...props },
29
+ ref
30
+ ) {
31
+ return (
32
+ <View
33
+ ref={ref}
34
+ className={cn(hstackVariants({ space, reversed }), className)}
35
+ {...props}
36
+ />
37
+ );
38
+ });
39
+
40
+ HStack.displayName = 'HStack';
41
+
42
+ export { HStack, hstackVariants };
43
+ export type { HStackProps };
@@ -0,0 +1,44 @@
1
+ import * as React from 'react';
2
+ import { View, type ViewProps } from 'react-native';
3
+ import { TextClassContext } from '@tallyui/primitives';
4
+ import { cn } from '@tallyui/theme';
5
+ import { cva, type VariantProps } from 'class-variance-authority';
6
+
7
+ const iconVariants = cva('items-center justify-center', {
8
+ variants: {
9
+ size: {
10
+ xs: 'h-3 w-3',
11
+ sm: 'h-4 w-4',
12
+ md: 'h-5 w-5',
13
+ lg: 'h-6 w-6',
14
+ xl: 'h-8 w-8',
15
+ },
16
+ },
17
+ defaultVariants: {
18
+ size: 'md',
19
+ },
20
+ });
21
+
22
+ type IconProps = ViewProps & VariantProps<typeof iconVariants>;
23
+
24
+ const Icon = React.forwardRef<View, IconProps>(function Icon(
25
+ { className, size, children, ...props },
26
+ ref
27
+ ) {
28
+ const textClass = React.useContext(TextClassContext);
29
+
30
+ return (
31
+ <View
32
+ ref={ref}
33
+ className={cn(iconVariants({ size }), textClass, className)}
34
+ {...props}
35
+ >
36
+ {children}
37
+ </View>
38
+ );
39
+ });
40
+
41
+ Icon.displayName = 'Icon';
42
+
43
+ export { Icon, iconVariants };
44
+ export type { IconProps };
@@ -0,0 +1,9 @@
1
+ import { Circle, Line } from 'react-native-svg';
2
+ import { createSvgIcon } from './svg-icon';
3
+
4
+ export const SearchIcon = createSvgIcon('SearchIcon', () => (
5
+ <>
6
+ <Circle cx={11} cy={11} r={7} />
7
+ <Line x1={16.5} y1={16.5} x2={21} y2={21} />
8
+ </>
9
+ ));
@@ -0,0 +1,36 @@
1
+ import * as React from 'react';
2
+ import Svg, { type SvgProps } from 'react-native-svg';
3
+
4
+ export type SvgIconProps = {
5
+ size?: number;
6
+ color?: string;
7
+ strokeWidth?: number;
8
+ accessibilityLabel?: string;
9
+ } & Omit<SvgProps, 'width' | 'height' | 'color'>;
10
+
11
+ export function createSvgIcon(name: string, render: (props: { strokeWidth: number }) => React.ReactNode) {
12
+ function SvgIcon({ size = 16, color, strokeWidth = 2, accessibilityLabel, ...props }: SvgIconProps) {
13
+ return (
14
+ <Svg
15
+ {...props}
16
+ viewBox="0 0 24 24"
17
+ width={size}
18
+ height={size}
19
+ fill="none"
20
+ stroke={color ?? 'currentColor'}
21
+ strokeWidth={strokeWidth}
22
+ strokeLinecap="round"
23
+ strokeLinejoin="round"
24
+ color={color}
25
+ aria-hidden={accessibilityLabel === undefined}
26
+ role={accessibilityLabel === undefined ? undefined : 'img'}
27
+ aria-label={accessibilityLabel}
28
+ >
29
+ {render({ strokeWidth })}
30
+ </Svg>
31
+ );
32
+ }
33
+
34
+ SvgIcon.displayName = name;
35
+ return SvgIcon;
36
+ }
@@ -0,0 +1,58 @@
1
+ import * as React from 'react';
2
+ import { Pressable, type PressableProps } from 'react-native';
3
+ import { Slot } from '@tallyui/primitives';
4
+ import { cn } from '@tallyui/theme';
5
+ import { cva, type VariantProps } from 'class-variance-authority';
6
+
7
+ const iconButtonVariants = cva(
8
+ 'inline-flex items-center justify-center rounded-md web:transition-colors web:focus-visible:outline-none web:focus-visible:ring-2 web:focus-visible:ring-ring',
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default: 'bg-primary active:opacity-90',
13
+ destructive: 'bg-destructive active:opacity-90',
14
+ outline: 'border border-input bg-background active:bg-accent',
15
+ secondary: 'bg-secondary active:opacity-80',
16
+ ghost: 'active:bg-accent',
17
+ },
18
+ size: {
19
+ sm: 'h-8 w-8',
20
+ md: 'h-10 w-10',
21
+ lg: 'h-12 w-12',
22
+ },
23
+ },
24
+ defaultVariants: {
25
+ variant: 'ghost',
26
+ size: 'md',
27
+ },
28
+ }
29
+ );
30
+
31
+ type IconButtonProps = PressableProps & VariantProps<typeof iconButtonVariants> & {
32
+ asChild?: boolean;
33
+ };
34
+
35
+ const IconButton = React.forwardRef<React.ComponentRef<typeof Pressable>, IconButtonProps>(
36
+ function IconButton({ className, variant, size, asChild = false, disabled, ...props }, ref) {
37
+ const Component = asChild ? Slot : Pressable;
38
+
39
+ return (
40
+ <Component
41
+ ref={ref}
42
+ role="button"
43
+ disabled={disabled}
44
+ className={cn(
45
+ iconButtonVariants({ variant, size }),
46
+ disabled && 'opacity-50 web:pointer-events-none',
47
+ className,
48
+ )}
49
+ {...props}
50
+ />
51
+ );
52
+ }
53
+ );
54
+
55
+ IconButton.displayName = 'IconButton';
56
+
57
+ export { IconButton, iconButtonVariants };
58
+ export type { IconButtonProps };