@tallyui/components 1.0.0 → 3.0.0-next.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.
- package/LICENSE +21 -0
- package/dist/index.d.ts +1113 -83
- package/dist/index.js +4936 -353
- package/package.json +27 -5
- package/src/cart/cart-line-actions.tsx +40 -0
- package/src/cart/cart-line.tsx +18 -32
- package/src/cart/cart-note-input.tsx +46 -0
- package/src/cart/cart-panel.tsx +39 -26
- package/src/cart/cart-total.tsx +43 -47
- package/src/cart/discount-badge.tsx +19 -0
- package/src/cart/index.ts +4 -1
- package/src/checkout/cash-tendered.tsx +101 -0
- package/src/checkout/change-display.tsx +19 -0
- package/src/checkout/index.ts +3 -0
- package/src/checkout/order-summary-line.tsx +7 -8
- package/src/checkout/order-summary.tsx +8 -7
- package/src/checkout/payment-method-card.tsx +10 -9
- package/src/checkout/payment-selector.tsx +5 -5
- package/src/checkout/receipt-preview.tsx +78 -0
- package/src/customer/customer-card.tsx +16 -12
- package/src/customer/customer-form.tsx +72 -0
- package/src/customer/customer-order-history.tsx +34 -0
- package/src/customer/customer-picker.tsx +124 -0
- package/src/customer/customer-select.tsx +80 -31
- package/src/customer/index.ts +3 -0
- package/src/index.ts +114 -1
- package/src/input/filter-chip.tsx +85 -27
- package/src/input/index.ts +1 -0
- package/src/input/quantity-stepper.tsx +64 -0
- package/src/input/search-input.tsx +30 -7
- package/src/layout/checkout-layout.tsx +46 -0
- package/src/layout/index.ts +5 -0
- package/src/layout/live-tab-screen.tsx +54 -0
- package/src/layout/pos-layout.tsx +64 -0
- package/src/layout/settings-layout.tsx +58 -0
- package/src/layout/store-settings-choice-screen.tsx +142 -0
- package/src/order/index.ts +4 -0
- package/src/order/order-card.tsx +48 -0
- package/src/order/order-detail.tsx +82 -0
- package/src/order/order-list.tsx +39 -0
- package/src/order/order-status-badge.tsx +32 -0
- package/src/product/category-nav.tsx +70 -0
- package/src/product/index.ts +3 -0
- package/src/product/product-card.tsx +36 -8
- package/src/product/product-grid.tsx +46 -13
- package/src/product/product-image.tsx +28 -7
- package/src/product/product-list.tsx +44 -0
- package/src/product/product-price.tsx +77 -22
- package/src/product/product-sku.tsx +5 -5
- package/src/product/product-stock-badge.tsx +41 -28
- package/src/product/product-title.tsx +2 -3
- package/src/product/product-variant-picker.tsx +61 -0
- package/src/register/cash-count-input.tsx +85 -0
- package/src/register/closure-sheet.tsx +161 -0
- package/src/register/index.ts +12 -0
- package/src/register/movement-sheet.tsx +118 -0
- package/src/register/open-register-card.tsx +109 -0
- package/src/register/register-bar.helpers.ts +57 -0
- package/src/register/register-bar.tsx +85 -0
- package/src/register/register-column.tsx +117 -0
- package/src/register/register-count.tsx +330 -0
- package/src/register/register-open-close.tsx +52 -0
- package/src/register/register-panel.tsx +151 -0
- package/src/register/register-picker.tsx +60 -0
- package/src/register/register-summary.tsx +72 -0
- package/src/sale/cart-bar.tsx +18 -0
- package/src/sale/cart.tsx +66 -0
- package/src/sale/catalogue.tsx +139 -0
- package/src/sale/discount-form.tsx +85 -0
- package/src/sale/index.ts +9 -0
- package/src/sale/orders-list.tsx +108 -0
- package/src/sale/print-style.ts +11 -0
- package/src/sale/receipt.tsx +62 -0
- package/src/sale/sync-status.tsx +141 -0
- package/src/sale/tender.tsx +38 -0
- package/src/settings/connector-status.tsx +65 -0
- package/src/settings/index.ts +3 -0
- package/src/settings/settings-group.tsx +23 -0
- package/src/settings/settings-row.tsx +23 -0
- package/src/ui/accordion/index.tsx +59 -0
- package/src/ui/alert-dialog/index.tsx +91 -0
- package/src/ui/avatar/index.tsx +50 -0
- package/src/ui/badge/index.tsx +60 -0
- package/src/ui/button/index.tsx +90 -0
- package/src/ui/card/index.tsx +60 -0
- package/src/ui/checkbox/index.tsx +29 -0
- package/src/ui/collapsible/index.tsx +24 -0
- package/src/ui/combobox/index.tsx +98 -0
- package/src/ui/context-menu/index.tsx +159 -0
- package/src/ui/dialog/index.tsx +92 -0
- package/src/ui/dropdown-menu/index.tsx +161 -0
- package/src/ui/hover-card/index.tsx +31 -0
- package/src/ui/hstack/index.tsx +43 -0
- package/src/ui/icon/index.tsx +44 -0
- package/src/ui/icon/search-icon.tsx +9 -0
- package/src/ui/icon/svg-icon.tsx +36 -0
- package/src/ui/icon-button/index.tsx +58 -0
- package/src/ui/index.ts +99 -0
- package/src/ui/input/index.tsx +100 -0
- package/src/ui/label/index.tsx +26 -0
- package/src/ui/loader/index.tsx +37 -0
- package/src/ui/popover/index.tsx +31 -0
- package/src/ui/progress/index.tsx +28 -0
- package/src/ui/radio-group/index.tsx +38 -0
- package/src/ui/select/index.tsx +96 -0
- package/src/ui/separator/index.tsx +29 -0
- package/src/ui/slider/index.tsx +28 -0
- package/src/ui/switch/index.tsx +31 -0
- package/src/ui/table/index.tsx +59 -0
- package/src/ui/tabs/index.tsx +53 -0
- package/src/ui/text/index.tsx +36 -0
- package/src/ui/textarea/index.tsx +29 -0
- package/src/ui/toast/index.tsx +52 -0
- package/src/ui/toggle/index.tsx +69 -0
- package/src/ui/toggle-group/index.tsx +66 -0
- package/src/ui/tooltip/index.tsx +30 -0
- package/src/ui/vstack/index.tsx +43 -0
- package/src/uniwind-env.d.ts +9 -1
- package/src/__tests__/cart-line.test.tsx +0 -53
- package/src/__tests__/cart-panel.test.tsx +0 -55
- package/src/__tests__/cart-total.test.tsx +0 -60
- package/src/__tests__/customer-card.test.tsx +0 -47
- package/src/__tests__/customer-select.test.tsx +0 -33
- package/src/__tests__/filter-chip.test.tsx +0 -40
- package/src/__tests__/helpers.ts +0 -111
- package/src/__tests__/order-summary-line.test.tsx +0 -18
- package/src/__tests__/order-summary.test.tsx +0 -32
- package/src/__tests__/payment-method-card.test.tsx +0 -24
- package/src/__tests__/payment-selector.test.tsx +0 -23
- package/src/__tests__/product-card.test.tsx +0 -31
- package/src/__tests__/product-grid.test.tsx +0 -37
- package/src/__tests__/product-image.test.tsx +0 -54
- package/src/__tests__/product-price.test.tsx +0 -68
- package/src/__tests__/product-sku.test.tsx +0 -47
- package/src/__tests__/product-stock-badge.test.tsx +0 -58
- package/src/__tests__/product-title.test.tsx +0 -38
- package/src/__tests__/search-input.test.tsx +0 -22
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import { Slider as SliderPrimitive } from '@tallyui/primitives';
|
|
4
|
+
import { cn } from '@tallyui/theme';
|
|
5
|
+
|
|
6
|
+
type SliderProps = React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>;
|
|
7
|
+
|
|
8
|
+
const Slider = React.forwardRef<
|
|
9
|
+
React.ComponentRef<typeof SliderPrimitive.Root>,
|
|
10
|
+
SliderProps
|
|
11
|
+
>(function Slider({ className, ...props }, ref) {
|
|
12
|
+
return (
|
|
13
|
+
<SliderPrimitive.Root
|
|
14
|
+
ref={ref}
|
|
15
|
+
className={cn('relative flex w-full touch-none select-none items-center', className)}
|
|
16
|
+
{...props}
|
|
17
|
+
>
|
|
18
|
+
<SliderPrimitive.Track className="relative h-2 w-full grow overflow-hidden rounded-full bg-secondary">
|
|
19
|
+
<SliderPrimitive.Range className="absolute h-full bg-primary" />
|
|
20
|
+
</SliderPrimitive.Track>
|
|
21
|
+
<SliderPrimitive.Thumb className="block h-5 w-5 rounded-full border-2 border-primary bg-background web:ring-offset-background web:transition-colors web:focus-visible:outline-none web:focus-visible:ring-2 web:focus-visible:ring-ring web:focus-visible:ring-offset-2" />
|
|
22
|
+
</SliderPrimitive.Root>
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
Slider.displayName = 'Slider';
|
|
26
|
+
|
|
27
|
+
export { Slider };
|
|
28
|
+
export type { SliderProps };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Switch as SwitchPrimitive } from '@tallyui/primitives';
|
|
3
|
+
import { cn } from '@tallyui/theme';
|
|
4
|
+
|
|
5
|
+
const Switch = React.forwardRef<
|
|
6
|
+
React.ComponentRef<typeof SwitchPrimitive.Root>,
|
|
7
|
+
React.ComponentPropsWithoutRef<typeof SwitchPrimitive.Root>
|
|
8
|
+
>(function Switch({ className, ...props }, ref) {
|
|
9
|
+
return (
|
|
10
|
+
<SwitchPrimitive.Root
|
|
11
|
+
ref={ref}
|
|
12
|
+
className={cn(
|
|
13
|
+
'web:peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent web:transition-colors web:focus-visible:outline-none web:focus-visible:ring-2 web:focus-visible:ring-ring web:focus-visible:ring-offset-2 web:focus-visible:ring-offset-background',
|
|
14
|
+
props.checked ? 'bg-primary' : 'bg-input',
|
|
15
|
+
props.disabled && 'web:cursor-not-allowed opacity-50',
|
|
16
|
+
className,
|
|
17
|
+
)}
|
|
18
|
+
{...props}
|
|
19
|
+
>
|
|
20
|
+
<SwitchPrimitive.Thumb
|
|
21
|
+
className={cn(
|
|
22
|
+
'pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 web:transition-transform',
|
|
23
|
+
props.checked ? 'translate-x-5' : 'translate-x-0',
|
|
24
|
+
)}
|
|
25
|
+
/>
|
|
26
|
+
</SwitchPrimitive.Root>
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
Switch.displayName = 'Switch';
|
|
30
|
+
|
|
31
|
+
export { Switch };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { View, Text, Pressable, type ViewProps, type TextProps } from 'react-native';
|
|
3
|
+
import { TextClassContext } from '@tallyui/primitives';
|
|
4
|
+
import { cn } from '@tallyui/theme';
|
|
5
|
+
|
|
6
|
+
const Table = React.forwardRef<View, ViewProps>(function Table({ className, ...props }, ref) {
|
|
7
|
+
return <View ref={ref} role="table" className={cn('w-full', className)} {...props} />;
|
|
8
|
+
});
|
|
9
|
+
Table.displayName = 'Table';
|
|
10
|
+
|
|
11
|
+
const TableHeader = React.forwardRef<View, ViewProps>(function TableHeader({ className, ...props }, ref) {
|
|
12
|
+
return <View ref={ref} role="rowgroup" className={cn('border-b border-border', className)} {...props} />;
|
|
13
|
+
});
|
|
14
|
+
TableHeader.displayName = 'TableHeader';
|
|
15
|
+
|
|
16
|
+
const TableBody = React.forwardRef<View, ViewProps>(function TableBody({ className, ...props }, ref) {
|
|
17
|
+
return <View ref={ref} role="rowgroup" className={cn('[&>*:last-child]:border-0', className)} {...props} />;
|
|
18
|
+
});
|
|
19
|
+
TableBody.displayName = 'TableBody';
|
|
20
|
+
|
|
21
|
+
const TableFooter = React.forwardRef<View, ViewProps>(function TableFooter({ className, ...props }, ref) {
|
|
22
|
+
return <View ref={ref} role="rowgroup" className={cn('border-t border-border bg-muted/50 font-medium', className)} {...props} />;
|
|
23
|
+
});
|
|
24
|
+
TableFooter.displayName = 'TableFooter';
|
|
25
|
+
|
|
26
|
+
const TableRow = React.forwardRef<View, ViewProps>(function TableRow({ className, ...props }, ref) {
|
|
27
|
+
return (
|
|
28
|
+
<View
|
|
29
|
+
ref={ref}
|
|
30
|
+
role="row"
|
|
31
|
+
className={cn('flex flex-row border-b border-border web:transition-colors web:hover:bg-muted/50', className)}
|
|
32
|
+
{...props}
|
|
33
|
+
/>
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
TableRow.displayName = 'TableRow';
|
|
37
|
+
|
|
38
|
+
const TableHead = React.forwardRef<View, ViewProps>(function TableHead({ className, ...props }, ref) {
|
|
39
|
+
return (
|
|
40
|
+
<TextClassContext.Provider value="text-muted-foreground text-xs uppercase text-left font-medium">
|
|
41
|
+
<View
|
|
42
|
+
ref={ref}
|
|
43
|
+
role="columnheader"
|
|
44
|
+
className={cn('flex-1 px-4 py-3 text-left font-medium text-muted-foreground', className)}
|
|
45
|
+
{...props}
|
|
46
|
+
/>
|
|
47
|
+
</TextClassContext.Provider>
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
TableHead.displayName = 'TableHead';
|
|
51
|
+
|
|
52
|
+
const TableCell = React.forwardRef<View, ViewProps>(function TableCell({ className, ...props }, ref) {
|
|
53
|
+
return (
|
|
54
|
+
<View ref={ref} role="cell" className={cn('flex-1 px-4 py-4', className)} {...props} />
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
TableCell.displayName = 'TableCell';
|
|
58
|
+
|
|
59
|
+
export { Table, TableHeader, TableBody, TableFooter, TableRow, TableHead, TableCell };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Tabs as TabsPrimitive, TextClassContext } from '@tallyui/primitives';
|
|
3
|
+
import { cn } from '@tallyui/theme';
|
|
4
|
+
|
|
5
|
+
const Tabs = TabsPrimitive.Root;
|
|
6
|
+
|
|
7
|
+
function TabsList({ className, ...props }: React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>) {
|
|
8
|
+
return (
|
|
9
|
+
<TabsPrimitive.List
|
|
10
|
+
className={cn('inline-flex h-10 items-center justify-center rounded-md bg-muted p-1', className)}
|
|
11
|
+
{...props}
|
|
12
|
+
/>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const TabsTrigger = React.forwardRef<
|
|
17
|
+
React.ComponentRef<typeof TabsPrimitive.Trigger>,
|
|
18
|
+
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
|
|
19
|
+
>(function TabsTrigger({ className, ...props }, ref) {
|
|
20
|
+
const { value } = TabsPrimitive.useRootContext();
|
|
21
|
+
const isActive = props.value === value;
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<TextClassContext.Provider
|
|
25
|
+
value={cn(
|
|
26
|
+
'text-sm font-medium',
|
|
27
|
+
isActive ? 'text-foreground' : 'text-muted-foreground'
|
|
28
|
+
)}
|
|
29
|
+
>
|
|
30
|
+
<TabsPrimitive.Trigger
|
|
31
|
+
ref={ref}
|
|
32
|
+
className={cn(
|
|
33
|
+
'inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium web:ring-offset-background web:transition-all web:focus-visible:outline-none web:focus-visible:ring-2 web:focus-visible:ring-ring web:focus-visible:ring-offset-2',
|
|
34
|
+
isActive && 'bg-background shadow-sm',
|
|
35
|
+
className,
|
|
36
|
+
)}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
</TextClassContext.Provider>
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
TabsTrigger.displayName = 'TabsTrigger';
|
|
43
|
+
|
|
44
|
+
function TabsContent({ className, ...props }: React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>) {
|
|
45
|
+
return (
|
|
46
|
+
<TabsPrimitive.Content
|
|
47
|
+
className={cn('mt-2 web:ring-offset-background web:focus-visible:outline-none web:focus-visible:ring-2 web:focus-visible:ring-ring web:focus-visible:ring-offset-2', className)}
|
|
48
|
+
{...props}
|
|
49
|
+
/>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Text as RNText } from 'react-native';
|
|
3
|
+
import { Slot, TextClassContext } from '@tallyui/primitives';
|
|
4
|
+
import { cn } from '@tallyui/theme';
|
|
5
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
6
|
+
|
|
7
|
+
const textVariants = cva('text-foreground web:select-text text-base', {
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
default: '',
|
|
11
|
+
link: 'web:hover:underline web:focus:underline web:hover:cursor-pointer group-active:underline',
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
defaultVariants: {
|
|
15
|
+
variant: 'default',
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
type TextProps = React.ComponentPropsWithoutRef<typeof RNText> &
|
|
20
|
+
VariantProps<typeof textVariants> & {
|
|
21
|
+
asChild?: boolean;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
function Text({ className, variant, asChild = false, children, ...props }: TextProps) {
|
|
25
|
+
const textClass = React.useContext(TextClassContext);
|
|
26
|
+
const Component = asChild ? Slot : RNText;
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<Component className={cn(textVariants({ variant }), textClass, className)} {...props}>
|
|
30
|
+
{children}
|
|
31
|
+
</Component>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export { Text, TextClassContext, textVariants };
|
|
36
|
+
export type { TextProps };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { TextInput, type TextInputProps } from 'react-native';
|
|
3
|
+
import { cn } from '@tallyui/theme';
|
|
4
|
+
|
|
5
|
+
type TextareaProps = TextInputProps & {
|
|
6
|
+
className?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const Textarea = React.forwardRef<TextInput, TextareaProps>(
|
|
10
|
+
function Textarea({ className, ...props }, ref) {
|
|
11
|
+
return (
|
|
12
|
+
<TextInput
|
|
13
|
+
ref={ref}
|
|
14
|
+
multiline
|
|
15
|
+
textAlignVertical="top"
|
|
16
|
+
className={cn(
|
|
17
|
+
'min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground web:outline-none web:focus-visible:ring-2 web:focus-visible:ring-ring web:focus-visible:ring-offset-2',
|
|
18
|
+
className,
|
|
19
|
+
)}
|
|
20
|
+
{...props}
|
|
21
|
+
/>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
Textarea.displayName = 'Textarea';
|
|
27
|
+
|
|
28
|
+
export { Textarea };
|
|
29
|
+
export type { TextareaProps };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { View, Text, Pressable } from 'react-native';
|
|
3
|
+
import { Toast as ToastPrimitive } from '@tallyui/primitives';
|
|
4
|
+
import { cn } from '@tallyui/theme';
|
|
5
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
6
|
+
|
|
7
|
+
const toastVariants = cva(
|
|
8
|
+
'group pointer-events-auto relative flex w-full flex-row items-center justify-between gap-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg',
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default: 'border-border bg-background text-foreground',
|
|
13
|
+
destructive: 'border-destructive bg-destructive text-destructive-foreground',
|
|
14
|
+
success: 'border-success bg-success text-success-foreground',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
defaultVariants: {
|
|
18
|
+
variant: 'default',
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
type ToastProps = React.ComponentPropsWithoutRef<typeof View> & VariantProps<typeof toastVariants>;
|
|
24
|
+
|
|
25
|
+
function Toast({ className, variant, ...props }: ToastProps) {
|
|
26
|
+
return <View className={cn(toastVariants({ variant }), className)} {...props} />;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function ToastTitle({ className, ...props }: React.ComponentPropsWithoutRef<typeof Text>) {
|
|
30
|
+
return <Text className={cn('text-sm font-semibold', className)} {...props} />;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function ToastDescription({ className, ...props }: React.ComponentPropsWithoutRef<typeof Text>) {
|
|
34
|
+
return <Text className={cn('text-sm opacity-90', className)} {...props} />;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function ToastClose({ className, ...props }: React.ComponentPropsWithoutRef<typeof Pressable>) {
|
|
38
|
+
return (
|
|
39
|
+
<Pressable
|
|
40
|
+
className={cn(
|
|
41
|
+
'absolute right-2 top-2 rounded-md p-1 opacity-0 web:transition-opacity web:hover:opacity-100 web:focus:opacity-100 web:group-hover:opacity-100',
|
|
42
|
+
className,
|
|
43
|
+
)}
|
|
44
|
+
{...props}
|
|
45
|
+
>
|
|
46
|
+
<Text className="text-sm">✕</Text>
|
|
47
|
+
</Pressable>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export { Toast, ToastTitle, ToastDescription, ToastClose, toastVariants };
|
|
52
|
+
export type { ToastProps };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Toggle as TogglePrimitive, TextClassContext } from '@tallyui/primitives';
|
|
3
|
+
import { cn } from '@tallyui/theme';
|
|
4
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
5
|
+
|
|
6
|
+
const toggleVariants = cva(
|
|
7
|
+
'inline-flex items-center justify-center rounded-md text-sm font-medium web:ring-offset-background web:transition-colors web:hover:bg-muted web:hover:text-muted-foreground web:focus-visible:outline-none web:focus-visible:ring-2 web:focus-visible:ring-ring web:focus-visible:ring-offset-2',
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: 'bg-transparent',
|
|
12
|
+
outline: 'border border-input bg-transparent web:hover:bg-accent web:hover:text-accent-foreground',
|
|
13
|
+
},
|
|
14
|
+
size: {
|
|
15
|
+
default: 'h-10 px-3',
|
|
16
|
+
sm: 'h-9 px-2.5',
|
|
17
|
+
lg: 'h-11 px-5',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: {
|
|
21
|
+
variant: 'default',
|
|
22
|
+
size: 'default',
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const toggleTextVariants = cva('text-sm font-medium', {
|
|
28
|
+
variants: {
|
|
29
|
+
variant: {
|
|
30
|
+
default: '',
|
|
31
|
+
outline: '',
|
|
32
|
+
},
|
|
33
|
+
size: {
|
|
34
|
+
default: '',
|
|
35
|
+
sm: '',
|
|
36
|
+
lg: '',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
defaultVariants: {
|
|
40
|
+
variant: 'default',
|
|
41
|
+
size: 'default',
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
type ToggleProps = React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> &
|
|
46
|
+
VariantProps<typeof toggleVariants>;
|
|
47
|
+
|
|
48
|
+
const Toggle = React.forwardRef<
|
|
49
|
+
React.ComponentRef<typeof TogglePrimitive.Root>,
|
|
50
|
+
ToggleProps
|
|
51
|
+
>(function Toggle({ className, variant, size, ...props }, ref) {
|
|
52
|
+
return (
|
|
53
|
+
<TextClassContext.Provider value={toggleTextVariants({ variant, size })}>
|
|
54
|
+
<TogglePrimitive.Root
|
|
55
|
+
ref={ref}
|
|
56
|
+
className={cn(
|
|
57
|
+
toggleVariants({ variant, size }),
|
|
58
|
+
props.pressed && 'bg-accent text-accent-foreground',
|
|
59
|
+
className,
|
|
60
|
+
)}
|
|
61
|
+
{...props}
|
|
62
|
+
/>
|
|
63
|
+
</TextClassContext.Provider>
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
Toggle.displayName = 'Toggle';
|
|
67
|
+
|
|
68
|
+
export { Toggle, toggleVariants, toggleTextVariants };
|
|
69
|
+
export type { ToggleProps };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ToggleGroup as ToggleGroupPrimitive, TextClassContext } from '@tallyui/primitives';
|
|
3
|
+
import { cn } from '@tallyui/theme';
|
|
4
|
+
import { type VariantProps } from 'class-variance-authority';
|
|
5
|
+
import { toggleVariants, toggleTextVariants } from '../toggle';
|
|
6
|
+
|
|
7
|
+
type ToggleGroupProps = React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root> &
|
|
8
|
+
VariantProps<typeof toggleVariants>;
|
|
9
|
+
|
|
10
|
+
const ToggleGroupContext = React.createContext<VariantProps<typeof toggleVariants>>({
|
|
11
|
+
size: 'default',
|
|
12
|
+
variant: 'default',
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const ToggleGroup = React.forwardRef<
|
|
16
|
+
React.ComponentRef<typeof ToggleGroupPrimitive.Root>,
|
|
17
|
+
ToggleGroupProps
|
|
18
|
+
>(function ToggleGroup({ className, variant, size, children, ...props }, ref) {
|
|
19
|
+
return (
|
|
20
|
+
<ToggleGroupPrimitive.Root
|
|
21
|
+
ref={ref}
|
|
22
|
+
className={cn('flex flex-row items-center justify-center gap-1', className)}
|
|
23
|
+
{...props}
|
|
24
|
+
>
|
|
25
|
+
<ToggleGroupContext.Provider value={{ variant, size }}>
|
|
26
|
+
{children}
|
|
27
|
+
</ToggleGroupContext.Provider>
|
|
28
|
+
</ToggleGroupPrimitive.Root>
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
ToggleGroup.displayName = 'ToggleGroup';
|
|
32
|
+
|
|
33
|
+
type ToggleGroupItemProps = React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
|
|
34
|
+
VariantProps<typeof toggleVariants>;
|
|
35
|
+
|
|
36
|
+
const ToggleGroupItem = React.forwardRef<
|
|
37
|
+
React.ComponentRef<typeof ToggleGroupPrimitive.Item>,
|
|
38
|
+
ToggleGroupItemProps
|
|
39
|
+
>(function ToggleGroupItem({ className, variant, size, ...props }, ref) {
|
|
40
|
+
const context = React.useContext(ToggleGroupContext);
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<TextClassContext.Provider
|
|
44
|
+
value={toggleTextVariants({
|
|
45
|
+
variant: variant || context.variant,
|
|
46
|
+
size: size || context.size,
|
|
47
|
+
})}
|
|
48
|
+
>
|
|
49
|
+
<ToggleGroupPrimitive.Item
|
|
50
|
+
ref={ref}
|
|
51
|
+
className={cn(
|
|
52
|
+
toggleVariants({
|
|
53
|
+
variant: variant || context.variant,
|
|
54
|
+
size: size || context.size,
|
|
55
|
+
}),
|
|
56
|
+
className,
|
|
57
|
+
)}
|
|
58
|
+
{...props}
|
|
59
|
+
/>
|
|
60
|
+
</TextClassContext.Provider>
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
ToggleGroupItem.displayName = 'ToggleGroupItem';
|
|
64
|
+
|
|
65
|
+
export { ToggleGroup, ToggleGroupItem };
|
|
66
|
+
export type { ToggleGroupProps, ToggleGroupItemProps };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Tooltip as TooltipPrimitive, TextClassContext } from '@tallyui/primitives';
|
|
3
|
+
import { cn } from '@tallyui/theme';
|
|
4
|
+
|
|
5
|
+
const Tooltip = TooltipPrimitive.Root;
|
|
6
|
+
const TooltipTrigger = TooltipPrimitive.Trigger;
|
|
7
|
+
|
|
8
|
+
const TooltipContent = React.forwardRef<
|
|
9
|
+
React.ComponentRef<typeof TooltipPrimitive.Content>,
|
|
10
|
+
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
|
|
11
|
+
>(function TooltipContent({ className, sideOffset = 4, ...props }, ref) {
|
|
12
|
+
return (
|
|
13
|
+
<TooltipPrimitive.Portal>
|
|
14
|
+
<TextClassContext.Provider value="text-sm text-popover-foreground">
|
|
15
|
+
<TooltipPrimitive.Content
|
|
16
|
+
ref={ref}
|
|
17
|
+
sideOffset={sideOffset}
|
|
18
|
+
className={cn(
|
|
19
|
+
'z-50 overflow-hidden rounded-md border border-border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md',
|
|
20
|
+
className,
|
|
21
|
+
)}
|
|
22
|
+
{...props}
|
|
23
|
+
/>
|
|
24
|
+
</TextClassContext.Provider>
|
|
25
|
+
</TooltipPrimitive.Portal>
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
TooltipContent.displayName = 'TooltipContent';
|
|
29
|
+
|
|
30
|
+
export { Tooltip, TooltipTrigger, TooltipContent };
|
|
@@ -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 vstackVariants = cva('flex-col', {
|
|
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-col-reverse',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: {
|
|
21
|
+
space: 'md',
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
type VStackProps = ViewProps & VariantProps<typeof vstackVariants>;
|
|
26
|
+
|
|
27
|
+
const VStack = React.forwardRef<View, VStackProps>(function VStack(
|
|
28
|
+
{ className, space, reversed, ...props },
|
|
29
|
+
ref
|
|
30
|
+
) {
|
|
31
|
+
return (
|
|
32
|
+
<View
|
|
33
|
+
ref={ref}
|
|
34
|
+
className={cn(vstackVariants({ space, reversed }), className)}
|
|
35
|
+
{...props}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
VStack.displayName = 'VStack';
|
|
41
|
+
|
|
42
|
+
export { VStack, vstackVariants };
|
|
43
|
+
export type { VStackProps };
|
package/src/uniwind-env.d.ts
CHANGED
|
@@ -2,17 +2,25 @@
|
|
|
2
2
|
* Type augmentations for React Native components to support className prop.
|
|
3
3
|
* Uniwind provides these at runtime — this file ensures TypeScript accepts them.
|
|
4
4
|
*/
|
|
5
|
-
|
|
5
|
+
import 'react-native';
|
|
6
6
|
|
|
7
7
|
declare module 'react-native' {
|
|
8
8
|
interface ViewProps {
|
|
9
9
|
className?: string;
|
|
10
|
+
// react-native-web turns each entry into a data-* DOM attribute (e.g. { print: 'hide' } → data-print="hide").
|
|
11
|
+
// TV6a's first use: the print-style hook (`dataSet={{ print: 'hide' }}`) that TV6b lifts.
|
|
12
|
+
dataSet?: { [key: string]: string | number };
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
interface TextProps {
|
|
13
16
|
className?: string;
|
|
14
17
|
}
|
|
15
18
|
|
|
19
|
+
interface TextInputProps {
|
|
20
|
+
// Uniwind reads an accent-* class for the placeholder colour.
|
|
21
|
+
placeholderTextColorClassName?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
16
24
|
interface ImagePropsBase {
|
|
17
25
|
className?: string;
|
|
18
26
|
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { render, screen } from '@testing-library/react';
|
|
3
|
-
import { ConnectorProvider } from '@tallyui/core';
|
|
4
|
-
import { CartLine } from '../cart/cart-line';
|
|
5
|
-
import { createTestConnector, wooDoc, medusaDoc } from './helpers';
|
|
6
|
-
|
|
7
|
-
describe('CartLine', () => {
|
|
8
|
-
it('renders product name and line total for WooCommerce', () => {
|
|
9
|
-
const connector = createTestConnector('woo');
|
|
10
|
-
render(
|
|
11
|
-
<ConnectorProvider connector={connector}>
|
|
12
|
-
<CartLine item={{ doc: wooDoc, quantity: 2 }} />
|
|
13
|
-
</ConnectorProvider>
|
|
14
|
-
);
|
|
15
|
-
expect(screen.getByText('Espresso Machine Pro')).toBeDefined();
|
|
16
|
-
expect(screen.getByText('$1299.00 × 2')).toBeDefined();
|
|
17
|
-
expect(screen.getByText('$2598.00')).toBeDefined();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('renders product name and line total for Medusa', () => {
|
|
21
|
-
const connector = createTestConnector('medusa');
|
|
22
|
-
render(
|
|
23
|
-
<ConnectorProvider connector={connector}>
|
|
24
|
-
<CartLine item={{ doc: medusaDoc, quantity: 1 }} />
|
|
25
|
-
</ConnectorProvider>
|
|
26
|
-
);
|
|
27
|
-
expect(screen.getByText('Espresso Machine Pro')).toBeDefined();
|
|
28
|
-
expect(screen.getByText('$1299.00 × 1')).toBeDefined();
|
|
29
|
-
expect(screen.getByText('$1299.00')).toBeDefined();
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('renders custom currency symbol', () => {
|
|
33
|
-
const connector = createTestConnector('woo');
|
|
34
|
-
render(
|
|
35
|
-
<ConnectorProvider connector={connector}>
|
|
36
|
-
<CartLine item={{ doc: wooDoc, quantity: 1 }} currencySymbol="€" />
|
|
37
|
-
</ConnectorProvider>
|
|
38
|
-
);
|
|
39
|
-
expect(screen.getByText('€1299.00 × 1')).toBeDefined();
|
|
40
|
-
expect(screen.getByText('€1299.00')).toBeDefined();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('handles missing price gracefully', () => {
|
|
44
|
-
const connector = createTestConnector('woo');
|
|
45
|
-
render(
|
|
46
|
-
<ConnectorProvider connector={connector}>
|
|
47
|
-
<CartLine item={{ doc: {}, quantity: 3 }} />
|
|
48
|
-
</ConnectorProvider>
|
|
49
|
-
);
|
|
50
|
-
expect(screen.getByText('× 3')).toBeDefined();
|
|
51
|
-
expect(screen.getByText('—')).toBeDefined();
|
|
52
|
-
});
|
|
53
|
-
});
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { render, screen } from '@testing-library/react';
|
|
3
|
-
import { Text } from 'react-native';
|
|
4
|
-
import { ConnectorProvider } from '@tallyui/core';
|
|
5
|
-
import { CartPanel } from '../cart/cart-panel';
|
|
6
|
-
import { CartLine } from '../cart/cart-line';
|
|
7
|
-
import { createTestConnector, wooDoc } from './helpers';
|
|
8
|
-
|
|
9
|
-
describe('CartPanel', () => {
|
|
10
|
-
const items = [
|
|
11
|
-
{ doc: wooDoc, quantity: 2 },
|
|
12
|
-
{ doc: { ...wooDoc, id: 2, name: 'Grinder', price: '199.99' }, quantity: 1 },
|
|
13
|
-
];
|
|
14
|
-
|
|
15
|
-
it('renders cart line items', () => {
|
|
16
|
-
const connector = createTestConnector('woo');
|
|
17
|
-
render(
|
|
18
|
-
<ConnectorProvider connector={connector}>
|
|
19
|
-
<CartPanel items={items} renderItem={(item) => <CartLine item={item} />} />
|
|
20
|
-
</ConnectorProvider>
|
|
21
|
-
);
|
|
22
|
-
expect(screen.getByText('Espresso Machine Pro')).toBeDefined();
|
|
23
|
-
expect(screen.getByText('Grinder')).toBeDefined();
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('renders header and footer slots', () => {
|
|
27
|
-
const connector = createTestConnector('woo');
|
|
28
|
-
render(
|
|
29
|
-
<ConnectorProvider connector={connector}>
|
|
30
|
-
<CartPanel
|
|
31
|
-
items={items}
|
|
32
|
-
renderItem={(item) => <CartLine item={item} />}
|
|
33
|
-
header={<Text>Customer: Jane</Text>}
|
|
34
|
-
footer={<Text>Total: $1399.97</Text>}
|
|
35
|
-
/>
|
|
36
|
-
</ConnectorProvider>
|
|
37
|
-
);
|
|
38
|
-
expect(screen.getByText('Customer: Jane')).toBeDefined();
|
|
39
|
-
expect(screen.getByText('Total: $1399.97')).toBeDefined();
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('renders emptyState when no items', () => {
|
|
43
|
-
const connector = createTestConnector('woo');
|
|
44
|
-
render(
|
|
45
|
-
<ConnectorProvider connector={connector}>
|
|
46
|
-
<CartPanel
|
|
47
|
-
items={[]}
|
|
48
|
-
renderItem={() => null}
|
|
49
|
-
emptyState={<Text>Cart is empty</Text>}
|
|
50
|
-
/>
|
|
51
|
-
</ConnectorProvider>
|
|
52
|
-
);
|
|
53
|
-
expect(screen.getByText('Cart is empty')).toBeDefined();
|
|
54
|
-
});
|
|
55
|
-
});
|