@tony-ui-library/core 0.0.1
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/README.md +188 -0
- package/fesm2022/tony-ui-library-core.mjs +8756 -0
- package/fesm2022/tony-ui-library-core.mjs.map +1 -0
- package/package.json +55 -0
- package/schematics/collection.json +16 -0
- package/schematics/ng-add/index.d.ts +5 -0
- package/schematics/ng-add/index.js +53 -0
- package/schematics/ng-add/schema.json +19 -0
- package/schematics/ng-generate/component/index.d.ts +9 -0
- package/schematics/ng-generate/component/index.js +439 -0
- package/schematics/ng-generate/component/schema.json +32 -0
- package/src/lib/accordion/accordion.directives.spec.ts +173 -0
- package/src/lib/accordion/accordion.directives.ts +143 -0
- package/src/lib/accordion/index.ts +8 -0
- package/src/lib/alert/alert.directives.spec.ts +154 -0
- package/src/lib/alert/alert.directives.ts +67 -0
- package/src/lib/alert/alert.variants.ts +25 -0
- package/src/lib/alert/index.ts +6 -0
- package/src/lib/avatar/avatar.component.spec.ts +75 -0
- package/src/lib/avatar/avatar.component.ts +43 -0
- package/src/lib/avatar/avatar.variants.ts +26 -0
- package/src/lib/avatar/index.ts +2 -0
- package/src/lib/avatar-group/avatar-group.component.spec.ts +74 -0
- package/src/lib/avatar-group/avatar-group.component.ts +88 -0
- package/src/lib/avatar-group/index.ts +1 -0
- package/src/lib/badge/badge.directive.spec.ts +74 -0
- package/src/lib/badge/badge.directive.ts +17 -0
- package/src/lib/badge/badge.variants.ts +29 -0
- package/src/lib/badge/index.ts +2 -0
- package/src/lib/breadcrumb/breadcrumb.directives.spec.ts +80 -0
- package/src/lib/breadcrumb/breadcrumb.directives.ts +78 -0
- package/src/lib/breadcrumb/index.ts +8 -0
- package/src/lib/button/button.directive.spec.ts +92 -0
- package/src/lib/button/button.directive.ts +28 -0
- package/src/lib/button/button.variants.ts +30 -0
- package/src/lib/button/index.ts +2 -0
- package/src/lib/button-group/button-group.directive.spec.ts +46 -0
- package/src/lib/button-group/button-group.directive.ts +19 -0
- package/src/lib/button-group/button-group.variants.ts +18 -0
- package/src/lib/button-group/index.ts +2 -0
- package/src/lib/calendar/calendar.component.spec.ts +192 -0
- package/src/lib/calendar/calendar.component.ts +342 -0
- package/src/lib/calendar/calendar.types.ts +24 -0
- package/src/lib/calendar/index.ts +7 -0
- package/src/lib/card/card.directives.spec.ts +104 -0
- package/src/lib/card/card.directives.ts +72 -0
- package/src/lib/card/card.variants.ts +28 -0
- package/src/lib/card/index.ts +9 -0
- package/src/lib/carousel/carousel.directives.spec.ts +85 -0
- package/src/lib/carousel/carousel.directives.ts +159 -0
- package/src/lib/carousel/index.ts +8 -0
- package/src/lib/chat-bubble/chat-bubble.directives.spec.ts +52 -0
- package/src/lib/chat-bubble/chat-bubble.directives.ts +96 -0
- package/src/lib/chat-bubble/index.ts +11 -0
- package/src/lib/checkbox/checkbox.directive.spec.ts +57 -0
- package/src/lib/checkbox/checkbox.directive.ts +16 -0
- package/src/lib/checkbox/checkbox.variants.ts +19 -0
- package/src/lib/checkbox/index.ts +2 -0
- package/src/lib/color-picker/color-picker.component.spec.ts +328 -0
- package/src/lib/color-picker/color-picker.component.ts +537 -0
- package/src/lib/color-picker/color-picker.types.ts +24 -0
- package/src/lib/color-picker/color-picker.utils.ts +183 -0
- package/src/lib/color-picker/color-picker.variants.ts +17 -0
- package/src/lib/color-picker/index.ts +20 -0
- package/src/lib/combobox/combobox.component.spec.ts +151 -0
- package/src/lib/combobox/combobox.component.ts +264 -0
- package/src/lib/combobox/combobox.variants.ts +19 -0
- package/src/lib/combobox/index.ts +2 -0
- package/src/lib/command-palette/command-palette.component.spec.ts +178 -0
- package/src/lib/command-palette/command-palette.component.ts +194 -0
- package/src/lib/command-palette/command-palette.service.ts +36 -0
- package/src/lib/command-palette/command-palette.types.ts +23 -0
- package/src/lib/command-palette/index.ts +7 -0
- package/src/lib/data-table/data-table.component.spec.ts +443 -0
- package/src/lib/data-table/data-table.component.ts +622 -0
- package/src/lib/data-table/data-table.directives.ts +31 -0
- package/src/lib/data-table/data-table.types.ts +26 -0
- package/src/lib/data-table/index.ts +14 -0
- package/src/lib/date-picker/date-picker.component.spec.ts +131 -0
- package/src/lib/date-picker/date-picker.component.ts +220 -0
- package/src/lib/date-picker/date-picker.variants.ts +17 -0
- package/src/lib/date-picker/index.ts +2 -0
- package/src/lib/date-range-picker/date-range-picker.component.spec.ts +151 -0
- package/src/lib/date-range-picker/date-range-picker.component.ts +340 -0
- package/src/lib/date-range-picker/index.ts +1 -0
- package/src/lib/diff/diff.component.spec.ts +47 -0
- package/src/lib/diff/diff.component.ts +82 -0
- package/src/lib/diff/index.ts +1 -0
- package/src/lib/divider/divider.component.spec.ts +48 -0
- package/src/lib/divider/divider.component.ts +51 -0
- package/src/lib/divider/divider.variants.ts +22 -0
- package/src/lib/divider/index.ts +2 -0
- package/src/lib/dock/dock.directives.spec.ts +85 -0
- package/src/lib/dock/dock.directives.ts +81 -0
- package/src/lib/dock/index.ts +1 -0
- package/src/lib/drawer/drawer.directives.spec.ts +62 -0
- package/src/lib/drawer/drawer.directives.ts +80 -0
- package/src/lib/drawer/index.ts +8 -0
- package/src/lib/dropdown/dropdown.directives.spec.ts +106 -0
- package/src/lib/dropdown/dropdown.directives.ts +136 -0
- package/src/lib/dropdown/dropdown.variants.ts +27 -0
- package/src/lib/dropdown/index.ts +15 -0
- package/src/lib/fab/fab.directives.spec.ts +60 -0
- package/src/lib/fab/fab.directives.ts +77 -0
- package/src/lib/fab/index.ts +8 -0
- package/src/lib/fieldset/fieldset.directives.spec.ts +74 -0
- package/src/lib/fieldset/fieldset.directives.ts +49 -0
- package/src/lib/fieldset/fieldset.variants.ts +15 -0
- package/src/lib/fieldset/index.ts +6 -0
- package/src/lib/file-input/file-input.component.spec.ts +114 -0
- package/src/lib/file-input/file-input.component.ts +155 -0
- package/src/lib/file-input/file-input.variants.ts +25 -0
- package/src/lib/file-input/index.ts +6 -0
- package/src/lib/indicator/index.ts +6 -0
- package/src/lib/indicator/indicator.directives.spec.ts +64 -0
- package/src/lib/indicator/indicator.directives.ts +59 -0
- package/src/lib/input/index.ts +3 -0
- package/src/lib/input/input.directive.spec.ts +103 -0
- package/src/lib/input/input.directive.ts +25 -0
- package/src/lib/input/input.variants.ts +42 -0
- package/src/lib/input/label.directive.ts +16 -0
- package/src/lib/kbd/index.ts +2 -0
- package/src/lib/kbd/kbd.directive.spec.ts +42 -0
- package/src/lib/kbd/kbd.directive.ts +18 -0
- package/src/lib/kbd/kbd.variants.ts +19 -0
- package/src/lib/link/index.ts +2 -0
- package/src/lib/link/link.directive.spec.ts +41 -0
- package/src/lib/link/link.directive.ts +18 -0
- package/src/lib/link/link.variants.ts +20 -0
- package/src/lib/list/index.ts +8 -0
- package/src/lib/list/list.directives.spec.ts +65 -0
- package/src/lib/list/list.directives.ts +81 -0
- package/src/lib/loader/index.ts +2 -0
- package/src/lib/loader/loader.component.spec.ts +58 -0
- package/src/lib/loader/loader.component.ts +47 -0
- package/src/lib/loader/loader.variants.ts +21 -0
- package/src/lib/modal/dialog-ref.ts +19 -0
- package/src/lib/modal/dialog.directives.ts +84 -0
- package/src/lib/modal/dialog.service.spec.ts +52 -0
- package/src/lib/modal/dialog.service.ts +61 -0
- package/src/lib/modal/dialog.types.ts +16 -0
- package/src/lib/modal/index.ts +11 -0
- package/src/lib/navbar/index.ts +7 -0
- package/src/lib/navbar/navbar.directives.spec.ts +59 -0
- package/src/lib/navbar/navbar.directives.ts +57 -0
- package/src/lib/number-input/index.ts +2 -0
- package/src/lib/number-input/number-input.component.spec.ts +151 -0
- package/src/lib/number-input/number-input.component.ts +152 -0
- package/src/lib/number-input/number-input.variants.ts +17 -0
- package/src/lib/otp-input/index.ts +2 -0
- package/src/lib/otp-input/otp-input.component.spec.ts +252 -0
- package/src/lib/otp-input/otp-input.component.ts +274 -0
- package/src/lib/otp-input/otp-input.variants.ts +18 -0
- package/src/lib/pagination/index.ts +6 -0
- package/src/lib/pagination/pagination.component.spec.ts +59 -0
- package/src/lib/pagination/pagination.component.ts +143 -0
- package/src/lib/pagination/pagination.variants.ts +31 -0
- package/src/lib/popover/index.ts +6 -0
- package/src/lib/popover/popover.directives.spec.ts +147 -0
- package/src/lib/popover/popover.directives.ts +151 -0
- package/src/lib/progress/index.ts +7 -0
- package/src/lib/progress/progress.component.spec.ts +117 -0
- package/src/lib/progress/progress.component.ts +64 -0
- package/src/lib/progress/progress.variants.ts +43 -0
- package/src/lib/radial-progress/index.ts +5 -0
- package/src/lib/radial-progress/radial-progress.component.spec.ts +41 -0
- package/src/lib/radial-progress/radial-progress.component.ts +70 -0
- package/src/lib/radio/index.ts +2 -0
- package/src/lib/radio/radio.directive.spec.ts +46 -0
- package/src/lib/radio/radio.directive.ts +16 -0
- package/src/lib/radio/radio.variants.ts +19 -0
- package/src/lib/rating/index.ts +2 -0
- package/src/lib/rating/rating.component.spec.ts +157 -0
- package/src/lib/rating/rating.component.ts +163 -0
- package/src/lib/rating/rating.variants.ts +20 -0
- package/src/lib/select/index.ts +2 -0
- package/src/lib/select/select.component.spec.ts +112 -0
- package/src/lib/select/select.component.ts +235 -0
- package/src/lib/select/select.variants.ts +19 -0
- package/src/lib/sheet/index.ts +10 -0
- package/src/lib/sheet/sheet-ref.ts +18 -0
- package/src/lib/sheet/sheet.component.spec.ts +67 -0
- package/src/lib/sheet/sheet.directives.ts +70 -0
- package/src/lib/sheet/sheet.service.ts +100 -0
- package/src/lib/sheet/sheet.types.ts +23 -0
- package/src/lib/skeleton/index.ts +2 -0
- package/src/lib/skeleton/skeleton.directive.spec.ts +63 -0
- package/src/lib/skeleton/skeleton.directive.ts +21 -0
- package/src/lib/skeleton/skeleton.variants.ts +27 -0
- package/src/lib/slider/index.ts +2 -0
- package/src/lib/slider/slider.component.spec.ts +104 -0
- package/src/lib/slider/slider.component.ts +181 -0
- package/src/lib/slider/slider.variants.ts +25 -0
- package/src/lib/stat/index.ts +8 -0
- package/src/lib/stat/stat.directives.spec.ts +60 -0
- package/src/lib/stat/stat.directives.ts +79 -0
- package/src/lib/status/index.ts +2 -0
- package/src/lib/status/status.directive.spec.ts +43 -0
- package/src/lib/status/status.directive.ts +37 -0
- package/src/lib/status/status.variants.ts +26 -0
- package/src/lib/steps/index.ts +8 -0
- package/src/lib/steps/steps.directives.spec.ts +52 -0
- package/src/lib/steps/steps.directives.ts +78 -0
- package/src/lib/switch/index.ts +2 -0
- package/src/lib/switch/switch.component.spec.ts +98 -0
- package/src/lib/switch/switch.component.ts +76 -0
- package/src/lib/switch/switch.variants.ts +31 -0
- package/src/lib/table/index.ts +12 -0
- package/src/lib/table/table.directives.spec.ts +111 -0
- package/src/lib/table/table.directives.ts +126 -0
- package/src/lib/table/table.variants.ts +36 -0
- package/src/lib/tabs/index.ts +8 -0
- package/src/lib/tabs/tabs.directives.spec.ts +136 -0
- package/src/lib/tabs/tabs.directives.ts +126 -0
- package/src/lib/tabs/tabs.variants.ts +17 -0
- package/src/lib/tag-input/index.ts +2 -0
- package/src/lib/tag-input/tag-input.component.spec.ts +190 -0
- package/src/lib/tag-input/tag-input.component.ts +172 -0
- package/src/lib/tag-input/tag-input.variants.ts +31 -0
- package/src/lib/textarea/index.ts +7 -0
- package/src/lib/textarea/textarea.directive.spec.ts +84 -0
- package/src/lib/textarea/textarea.directive.ts +71 -0
- package/src/lib/textarea/textarea.variants.ts +34 -0
- package/src/lib/timeline/index.ts +11 -0
- package/src/lib/timeline/timeline.directives.spec.ts +55 -0
- package/src/lib/timeline/timeline.directives.ts +85 -0
- package/src/lib/toast/index.ts +3 -0
- package/src/lib/toast/toast.service.spec.ts +71 -0
- package/src/lib/toast/toast.service.ts +60 -0
- package/src/lib/toast/toast.variants.ts +38 -0
- package/src/lib/toast/toaster.component.spec.ts +38 -0
- package/src/lib/toast/toaster.component.ts +81 -0
- package/src/lib/toggle/index.ts +2 -0
- package/src/lib/toggle/toggle.directive.spec.ts +100 -0
- package/src/lib/toggle/toggle.directive.ts +61 -0
- package/src/lib/toggle/toggle.variants.ts +25 -0
- package/src/lib/tooltip/index.ts +2 -0
- package/src/lib/tooltip/tooltip.directive.spec.ts +113 -0
- package/src/lib/tooltip/tooltip.directive.ts +130 -0
- package/src/lib/tooltip/tooltip.variants.ts +20 -0
- package/src/lib/validator/index.ts +5 -0
- package/src/lib/validator/validator.directives.spec.ts +47 -0
- package/src/lib/validator/validator.directives.ts +50 -0
- package/src/styles/sonny-theme.css +171 -0
- package/types/tony-ui-library-core.d.ts +2179 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { cva } from 'class-variance-authority';
|
|
2
|
+
|
|
3
|
+
export const statusVariants = cva('inline-block rounded-full', {
|
|
4
|
+
variants: {
|
|
5
|
+
variant: {
|
|
6
|
+
default: 'bg-primary',
|
|
7
|
+
success: 'bg-green-500',
|
|
8
|
+
warning: 'bg-yellow-500',
|
|
9
|
+
error: 'bg-destructive',
|
|
10
|
+
info: 'bg-blue-500',
|
|
11
|
+
neutral: 'bg-muted-foreground',
|
|
12
|
+
},
|
|
13
|
+
size: {
|
|
14
|
+
xs: 'h-1.5 w-1.5',
|
|
15
|
+
sm: 'h-2 w-2',
|
|
16
|
+
md: 'h-2.5 w-2.5',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
defaultVariants: {
|
|
20
|
+
variant: 'default',
|
|
21
|
+
size: 'md',
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export type StatusVariant = 'default' | 'success' | 'warning' | 'error' | 'info' | 'neutral';
|
|
26
|
+
export type StatusSize = 'xs' | 'sm' | 'md';
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Component, signal } from '@angular/core';
|
|
2
|
+
import { TestBed, type ComponentFixture } from '@angular/core/testing';
|
|
3
|
+
import { TonStepsDirective, TonStepDirective, type StepStatus } from './steps.directives';
|
|
4
|
+
|
|
5
|
+
@Component({
|
|
6
|
+
standalone: true,
|
|
7
|
+
imports: [TonStepsDirective, TonStepDirective],
|
|
8
|
+
template: `
|
|
9
|
+
<div tonSteps>
|
|
10
|
+
<div tonStep status="completed">Register</div>
|
|
11
|
+
<div tonStep [status]="activeStatus()">Payment</div>
|
|
12
|
+
<div tonStep status="default">Confirm</div>
|
|
13
|
+
</div>
|
|
14
|
+
`,
|
|
15
|
+
})
|
|
16
|
+
class TestHostComponent {
|
|
17
|
+
activeStatus = signal<StepStatus>('active');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe('TonStepsDirective', () => {
|
|
21
|
+
let fixture: ComponentFixture<TestHostComponent>;
|
|
22
|
+
|
|
23
|
+
beforeEach(async () => {
|
|
24
|
+
await TestBed.configureTestingModule({ imports: [TestHostComponent] }).compileComponents();
|
|
25
|
+
fixture = TestBed.createComponent(TestHostComponent);
|
|
26
|
+
fixture.detectChanges();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should render with list role', () => {
|
|
30
|
+
const steps = fixture.nativeElement.querySelector('[tonSteps]');
|
|
31
|
+
expect(steps.getAttribute('role')).toBe('list');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should render steps with listitem role', () => {
|
|
35
|
+
const items = fixture.nativeElement.querySelectorAll('[tonStep]');
|
|
36
|
+
expect(items.length).toBe(3);
|
|
37
|
+
items.forEach((item: HTMLElement) => {
|
|
38
|
+
expect(item.getAttribute('role')).toBe('listitem');
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should mark active step with aria-current', () => {
|
|
43
|
+
const items = fixture.nativeElement.querySelectorAll('[tonStep]');
|
|
44
|
+
expect(items[1].getAttribute('aria-current')).toBe('step');
|
|
45
|
+
expect(items[0].getAttribute('aria-current')).toBeNull();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should apply completed styling', () => {
|
|
49
|
+
const items = fixture.nativeElement.querySelectorAll('[tonStep]');
|
|
50
|
+
expect(items[0].className).toContain('text-primary');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Directive, InjectionToken, computed, contentChildren, inject, input } from '@angular/core';
|
|
2
|
+
import { cn } from '../core/utils/cn';
|
|
3
|
+
|
|
4
|
+
export const TON_STEPS = new InjectionToken<TonStepsDirective>('TonSteps');
|
|
5
|
+
|
|
6
|
+
export type StepStatus = 'default' | 'active' | 'completed' | 'error';
|
|
7
|
+
export type StepsOrientation = 'horizontal' | 'vertical';
|
|
8
|
+
export type StepsSize = 'sm' | 'md' | 'lg';
|
|
9
|
+
|
|
10
|
+
@Directive({
|
|
11
|
+
selector: '[tonStep]',
|
|
12
|
+
host: {
|
|
13
|
+
'role': 'listitem',
|
|
14
|
+
'[class]': 'computedClass()',
|
|
15
|
+
'[attr.aria-current]': 'status() === "active" ? "step" : null',
|
|
16
|
+
},
|
|
17
|
+
})
|
|
18
|
+
export class TonStepDirective {
|
|
19
|
+
readonly status = input<StepStatus>('default');
|
|
20
|
+
readonly icon = input<string>('');
|
|
21
|
+
readonly class = input<string>('');
|
|
22
|
+
|
|
23
|
+
protected readonly computedClass = computed(() => {
|
|
24
|
+
const s = this.status();
|
|
25
|
+
const base = 'flex items-center gap-2';
|
|
26
|
+
|
|
27
|
+
// Step indicator via before: pseudo-element
|
|
28
|
+
const indicatorBase = 'before:flex before:items-center before:justify-center before:w-8 before:h-8 before:rounded-full before:border-2 before:text-xs before:shrink-0';
|
|
29
|
+
|
|
30
|
+
const statusIndicator =
|
|
31
|
+
s === 'completed' ? 'before:bg-primary before:border-primary before:text-primary-foreground before:content-["✓"]' :
|
|
32
|
+
s === 'active' ? 'before:border-primary before:text-primary before:content-["●"]' :
|
|
33
|
+
s === 'error' ? 'before:border-destructive before:text-destructive before:content-["!"]' :
|
|
34
|
+
'before:border-muted-foreground/30 before:text-muted-foreground before:content-["○"]';
|
|
35
|
+
|
|
36
|
+
const statusClass =
|
|
37
|
+
s === 'completed' ? 'text-primary' :
|
|
38
|
+
s === 'active' ? 'text-primary font-medium' :
|
|
39
|
+
s === 'error' ? 'text-destructive' :
|
|
40
|
+
'text-muted-foreground';
|
|
41
|
+
|
|
42
|
+
return cn(base, indicatorBase, statusIndicator, statusClass, this.class());
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@Directive({
|
|
47
|
+
selector: '[tonSteps]',
|
|
48
|
+
exportAs: 'tonSteps',
|
|
49
|
+
providers: [{ provide: TON_STEPS, useExisting: TonStepsDirective }],
|
|
50
|
+
host: {
|
|
51
|
+
'role': 'list',
|
|
52
|
+
'aria-label': 'Progress steps',
|
|
53
|
+
'[class]': 'computedClass()',
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
export class TonStepsDirective {
|
|
57
|
+
readonly orientation = input<StepsOrientation>('horizontal');
|
|
58
|
+
readonly size = input<StepsSize>('md');
|
|
59
|
+
readonly class = input<string>('');
|
|
60
|
+
|
|
61
|
+
readonly steps = contentChildren(TonStepDirective);
|
|
62
|
+
|
|
63
|
+
readonly activeIndex = computed(() => {
|
|
64
|
+
const s = this.steps();
|
|
65
|
+
return s.findIndex((step) => step.status() === 'active');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
protected readonly computedClass = computed(() => {
|
|
69
|
+
const o = this.orientation();
|
|
70
|
+
const s = this.size();
|
|
71
|
+
const base = 'flex';
|
|
72
|
+
const orientationClass = o === 'horizontal'
|
|
73
|
+
? 'flex-row items-center gap-2 [&>*+*]:before:content-[""] [&>*+*]:before:flex-1 [&>*+*]:before:h-px [&>*+*]:before:bg-border [&>*+*]:before:mx-2 [&>*+*]:before:min-w-[2rem]'
|
|
74
|
+
: 'flex-col gap-2 [&>*+*]:before:content-[""] [&>*+*]:before:w-px [&>*+*]:before:h-4 [&>*+*]:before:bg-border [&>*+*]:before:ml-4';
|
|
75
|
+
const sizeClass = s === 'sm' ? 'text-xs' : s === 'lg' ? 'text-base' : 'text-sm';
|
|
76
|
+
return cn(base, orientationClass, sizeClass, this.class());
|
|
77
|
+
});
|
|
78
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Component, signal } from '@angular/core';
|
|
2
|
+
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
|
3
|
+
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
|
4
|
+
import { TonSwitchComponent } from './switch.component';
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
standalone: true,
|
|
8
|
+
imports: [TonSwitchComponent],
|
|
9
|
+
template: `<ton-switch [(checked)]="checked" [disabled]="disabled()" />`,
|
|
10
|
+
})
|
|
11
|
+
class TestHostComponent {
|
|
12
|
+
checked = signal(false);
|
|
13
|
+
disabled = signal(false);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
describe('TonSwitchComponent', () => {
|
|
17
|
+
let fixture: ComponentFixture<TestHostComponent>;
|
|
18
|
+
let button: HTMLButtonElement;
|
|
19
|
+
|
|
20
|
+
beforeEach(async () => {
|
|
21
|
+
await TestBed.configureTestingModule({
|
|
22
|
+
imports: [TestHostComponent],
|
|
23
|
+
}).compileComponents();
|
|
24
|
+
|
|
25
|
+
fixture = TestBed.createComponent(TestHostComponent);
|
|
26
|
+
fixture.detectChanges();
|
|
27
|
+
button = fixture.nativeElement.querySelector('button');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should have switch role', () => {
|
|
31
|
+
expect(button.getAttribute('role')).toBe('switch');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should be unchecked by default', () => {
|
|
35
|
+
expect(button.getAttribute('aria-checked')).toBe('false');
|
|
36
|
+
expect(button.className).toContain('bg-input');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should toggle on click', () => {
|
|
40
|
+
button.click();
|
|
41
|
+
fixture.detectChanges();
|
|
42
|
+
expect(button.getAttribute('aria-checked')).toBe('true');
|
|
43
|
+
expect(button.className).toContain('bg-primary');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should not toggle when disabled', () => {
|
|
47
|
+
fixture.componentInstance.disabled.set(true);
|
|
48
|
+
fixture.detectChanges();
|
|
49
|
+
expect(button.disabled).toBe(true);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
@Component({
|
|
54
|
+
standalone: true,
|
|
55
|
+
imports: [ReactiveFormsModule, TonSwitchComponent],
|
|
56
|
+
template: `<ton-switch [formControl]="ctrl" />`,
|
|
57
|
+
})
|
|
58
|
+
class ReactiveFormHost {
|
|
59
|
+
ctrl = new FormControl(false);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
describe('TonSwitchComponent — Reactive Forms', () => {
|
|
63
|
+
let fixture: ComponentFixture<ReactiveFormHost>;
|
|
64
|
+
let button: HTMLButtonElement;
|
|
65
|
+
|
|
66
|
+
beforeEach(async () => {
|
|
67
|
+
await TestBed.configureTestingModule({
|
|
68
|
+
imports: [ReactiveFormHost],
|
|
69
|
+
}).compileComponents();
|
|
70
|
+
fixture = TestBed.createComponent(ReactiveFormHost);
|
|
71
|
+
fixture.detectChanges();
|
|
72
|
+
button = fixture.nativeElement.querySelector('button');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should update view when FormControl value changes (writeValue)', () => {
|
|
76
|
+
fixture.componentInstance.ctrl.setValue(true);
|
|
77
|
+
fixture.detectChanges();
|
|
78
|
+
expect(button.getAttribute('aria-checked')).toBe('true');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should update FormControl when user interacts (onChange)', () => {
|
|
82
|
+
button.click();
|
|
83
|
+
fixture.detectChanges();
|
|
84
|
+
expect(fixture.componentInstance.ctrl.value).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should disable via FormControl.disable() (setDisabledState)', () => {
|
|
88
|
+
fixture.componentInstance.ctrl.disable();
|
|
89
|
+
fixture.detectChanges();
|
|
90
|
+
expect(button.disabled).toBe(true);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should mark as touched on blur (onTouched)', () => {
|
|
94
|
+
expect(fixture.componentInstance.ctrl.touched).toBe(false);
|
|
95
|
+
button.dispatchEvent(new Event('blur'));
|
|
96
|
+
expect(fixture.componentInstance.ctrl.touched).toBe(true);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, computed, forwardRef, input, model, signal } from '@angular/core';
|
|
2
|
+
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
3
|
+
import { cn } from '../core/utils/cn';
|
|
4
|
+
import { switchTrackVariants, switchThumbSize, switchThumbTranslate, type SwitchSize } from './switch.variants';
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
selector: 'ton-switch',
|
|
8
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
9
|
+
host: { class: 'inline-flex' },
|
|
10
|
+
providers: [
|
|
11
|
+
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TonSwitchComponent), multi: true },
|
|
12
|
+
],
|
|
13
|
+
template: `
|
|
14
|
+
<button
|
|
15
|
+
type="button"
|
|
16
|
+
role="switch"
|
|
17
|
+
[attr.aria-checked]="checked()"
|
|
18
|
+
[disabled]="isDisabled()"
|
|
19
|
+
[class]="trackClass()"
|
|
20
|
+
(click)="toggle()"
|
|
21
|
+
(blur)="onTouched()"
|
|
22
|
+
>
|
|
23
|
+
<span [class]="thumbClass()"></span>
|
|
24
|
+
</button>
|
|
25
|
+
`,
|
|
26
|
+
})
|
|
27
|
+
export class TonSwitchComponent implements ControlValueAccessor {
|
|
28
|
+
readonly checked = model(false);
|
|
29
|
+
readonly disabled = input(false);
|
|
30
|
+
readonly size = input<SwitchSize>('md');
|
|
31
|
+
readonly class = input<string>('');
|
|
32
|
+
|
|
33
|
+
private readonly _disabledByCva = signal(false);
|
|
34
|
+
protected readonly isDisabled = computed(() => this.disabled() || this._disabledByCva());
|
|
35
|
+
|
|
36
|
+
private _onChange: (value: boolean) => void = () => {};
|
|
37
|
+
protected onTouched: () => void = () => {};
|
|
38
|
+
|
|
39
|
+
writeValue(val: boolean): void {
|
|
40
|
+
this.checked.set(val ?? false);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
registerOnChange(fn: (value: boolean) => void): void {
|
|
44
|
+
this._onChange = fn;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
registerOnTouched(fn: () => void): void {
|
|
48
|
+
this.onTouched = fn;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
setDisabledState(isDisabled: boolean): void {
|
|
52
|
+
this._disabledByCva.set(isDisabled);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
toggle(): void {
|
|
56
|
+
const newVal = !this.checked();
|
|
57
|
+
this.checked.set(newVal);
|
|
58
|
+
this._onChange(newVal);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
protected readonly trackClass = computed(() =>
|
|
62
|
+
cn(
|
|
63
|
+
switchTrackVariants({ size: this.size() }),
|
|
64
|
+
this.checked() ? 'bg-primary' : 'bg-input',
|
|
65
|
+
this.class()
|
|
66
|
+
)
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
protected readonly thumbClass = computed(() =>
|
|
70
|
+
cn(
|
|
71
|
+
'pointer-events-none block rounded-full bg-background shadow-lg ring-0 transition-transform',
|
|
72
|
+
switchThumbSize[this.size()],
|
|
73
|
+
this.checked() ? switchThumbTranslate[this.size()] : 'translate-x-0'
|
|
74
|
+
)
|
|
75
|
+
);
|
|
76
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { cva } from 'class-variance-authority';
|
|
2
|
+
|
|
3
|
+
export const switchTrackVariants = cva(
|
|
4
|
+
'peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
|
5
|
+
{
|
|
6
|
+
variants: {
|
|
7
|
+
size: {
|
|
8
|
+
sm: 'h-5 w-9',
|
|
9
|
+
md: 'h-6 w-11',
|
|
10
|
+
lg: 'h-7 w-14',
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
defaultVariants: {
|
|
14
|
+
size: 'md',
|
|
15
|
+
},
|
|
16
|
+
}
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
export const switchThumbSize: Record<string, string> = {
|
|
20
|
+
sm: 'h-4 w-4',
|
|
21
|
+
md: 'h-5 w-5',
|
|
22
|
+
lg: 'h-6 w-6',
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const switchThumbTranslate: Record<string, string> = {
|
|
26
|
+
sm: 'translate-x-4',
|
|
27
|
+
md: 'translate-x-5',
|
|
28
|
+
lg: 'translate-x-7',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type SwitchSize = 'sm' | 'md' | 'lg';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export {
|
|
2
|
+
TonTableDirective,
|
|
3
|
+
TonTableHeaderDirective,
|
|
4
|
+
TonTableBodyDirective,
|
|
5
|
+
TonTableRowDirective,
|
|
6
|
+
TonTableHeadDirective,
|
|
7
|
+
TonTableCellDirective,
|
|
8
|
+
TonTableFooterDirective,
|
|
9
|
+
TonTableCaptionDirective,
|
|
10
|
+
TON_TABLE,
|
|
11
|
+
} from './table.directives';
|
|
12
|
+
export { tableVariants, tableCellVariants, type TableVariant, type TableDensity } from './table.variants';
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Component, signal } from '@angular/core';
|
|
2
|
+
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
|
3
|
+
import {
|
|
4
|
+
TonTableDirective,
|
|
5
|
+
TonTableHeaderDirective,
|
|
6
|
+
TonTableBodyDirective,
|
|
7
|
+
TonTableRowDirective,
|
|
8
|
+
TonTableHeadDirective,
|
|
9
|
+
TonTableCellDirective,
|
|
10
|
+
TonTableFooterDirective,
|
|
11
|
+
TonTableCaptionDirective,
|
|
12
|
+
} from './table.directives';
|
|
13
|
+
import type { TableVariant, TableDensity } from './table.variants';
|
|
14
|
+
|
|
15
|
+
@Component({
|
|
16
|
+
standalone: true,
|
|
17
|
+
imports: [
|
|
18
|
+
TonTableDirective, TonTableHeaderDirective, TonTableBodyDirective,
|
|
19
|
+
TonTableRowDirective, TonTableHeadDirective, TonTableCellDirective,
|
|
20
|
+
TonTableFooterDirective, TonTableCaptionDirective,
|
|
21
|
+
],
|
|
22
|
+
template: `
|
|
23
|
+
<table tonTable [variant]="variant()" [density]="density()" [hoverable]="hoverable()" [stickyHeader]="stickyHeader()">
|
|
24
|
+
<caption tonTableCaption>Test table</caption>
|
|
25
|
+
<thead tonTableHeader>
|
|
26
|
+
<tr tonTableRow>
|
|
27
|
+
<th tonTableHead>Name</th>
|
|
28
|
+
<th tonTableHead>Value</th>
|
|
29
|
+
</tr>
|
|
30
|
+
</thead>
|
|
31
|
+
<tbody tonTableBody>
|
|
32
|
+
<tr tonTableRow>
|
|
33
|
+
<td tonTableCell>A</td>
|
|
34
|
+
<td tonTableCell>1</td>
|
|
35
|
+
</tr>
|
|
36
|
+
</tbody>
|
|
37
|
+
<tfoot tonTableFooter>
|
|
38
|
+
<tr tonTableRow>
|
|
39
|
+
<td tonTableCell>Total</td>
|
|
40
|
+
<td tonTableCell>1</td>
|
|
41
|
+
</tr>
|
|
42
|
+
</tfoot>
|
|
43
|
+
</table>
|
|
44
|
+
`,
|
|
45
|
+
})
|
|
46
|
+
class TestHostComponent {
|
|
47
|
+
variant = signal<TableVariant>('default');
|
|
48
|
+
density = signal<TableDensity>('normal');
|
|
49
|
+
hoverable = signal(false);
|
|
50
|
+
stickyHeader = signal(false);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
describe('Table Directives', () => {
|
|
54
|
+
let fixture: ComponentFixture<TestHostComponent>;
|
|
55
|
+
let table: HTMLTableElement;
|
|
56
|
+
|
|
57
|
+
beforeEach(async () => {
|
|
58
|
+
await TestBed.configureTestingModule({
|
|
59
|
+
imports: [TestHostComponent],
|
|
60
|
+
}).compileComponents();
|
|
61
|
+
|
|
62
|
+
fixture = TestBed.createComponent(TestHostComponent);
|
|
63
|
+
fixture.detectChanges();
|
|
64
|
+
table = fixture.nativeElement.querySelector('table');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should apply base table classes', () => {
|
|
68
|
+
expect(table.className).toContain('w-full');
|
|
69
|
+
expect(table.className).toContain('caption-bottom');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should apply striped variant', () => {
|
|
73
|
+
fixture.componentInstance.variant.set('striped');
|
|
74
|
+
fixture.detectChanges();
|
|
75
|
+
expect(table.className).toContain('nth-child');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should apply bordered variant', () => {
|
|
79
|
+
fixture.componentInstance.variant.set('bordered');
|
|
80
|
+
fixture.detectChanges();
|
|
81
|
+
expect(table.className).toContain('border');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should apply compact density to cells', () => {
|
|
85
|
+
fixture.componentInstance.density.set('compact');
|
|
86
|
+
fixture.detectChanges();
|
|
87
|
+
const th = fixture.nativeElement.querySelector('th');
|
|
88
|
+
expect(th.className).toContain('px-2');
|
|
89
|
+
expect(th.className).toContain('text-xs');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should apply hoverable to rows', () => {
|
|
93
|
+
fixture.componentInstance.hoverable.set(true);
|
|
94
|
+
fixture.detectChanges();
|
|
95
|
+
const row = fixture.nativeElement.querySelector('tbody tr');
|
|
96
|
+
expect(row.className).toContain('hover:bg-muted/50');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should apply sticky header', () => {
|
|
100
|
+
fixture.componentInstance.stickyHeader.set(true);
|
|
101
|
+
fixture.detectChanges();
|
|
102
|
+
const thead = fixture.nativeElement.querySelector('thead');
|
|
103
|
+
expect(thead.className).toContain('sticky');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should render caption', () => {
|
|
107
|
+
const caption = fixture.nativeElement.querySelector('caption');
|
|
108
|
+
expect(caption.className).toContain('text-muted-foreground');
|
|
109
|
+
expect(caption.textContent).toContain('Test table');
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { Directive, computed, inject, input, InjectionToken } from '@angular/core';
|
|
2
|
+
import { cn } from '../core/utils/cn';
|
|
3
|
+
import { tableVariants, tableCellVariants, type TableVariant, type TableDensity } from './table.variants';
|
|
4
|
+
|
|
5
|
+
export const TON_TABLE = new InjectionToken<TonTableDirective>('TonTable');
|
|
6
|
+
|
|
7
|
+
@Directive({
|
|
8
|
+
selector: 'table[tonTable]',
|
|
9
|
+
providers: [{ provide: TON_TABLE, useExisting: TonTableDirective }],
|
|
10
|
+
host: { '[class]': 'computedClass()' },
|
|
11
|
+
})
|
|
12
|
+
export class TonTableDirective {
|
|
13
|
+
readonly variant = input<TableVariant>('default');
|
|
14
|
+
readonly density = input<TableDensity>('normal');
|
|
15
|
+
readonly hoverable = input(false);
|
|
16
|
+
readonly stickyHeader = input(false);
|
|
17
|
+
readonly class = input<string>('');
|
|
18
|
+
|
|
19
|
+
protected readonly computedClass = computed(() =>
|
|
20
|
+
cn(tableVariants({ variant: this.variant() }), this.class())
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@Directive({
|
|
25
|
+
selector: 'thead[tonTableHeader]',
|
|
26
|
+
host: { '[class]': 'computedClass()' },
|
|
27
|
+
})
|
|
28
|
+
export class TonTableHeaderDirective {
|
|
29
|
+
readonly class = input<string>('');
|
|
30
|
+
private readonly table = inject(TON_TABLE, { optional: true });
|
|
31
|
+
|
|
32
|
+
protected readonly computedClass = computed(() =>
|
|
33
|
+
cn(
|
|
34
|
+
'[&_tr]:border-b',
|
|
35
|
+
this.table?.stickyHeader() ? 'sticky top-0 z-10 bg-background' : '',
|
|
36
|
+
this.class()
|
|
37
|
+
)
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@Directive({
|
|
42
|
+
selector: 'tbody[tonTableBody]',
|
|
43
|
+
host: { '[class]': 'computedClass()' },
|
|
44
|
+
})
|
|
45
|
+
export class TonTableBodyDirective {
|
|
46
|
+
readonly class = input<string>('');
|
|
47
|
+
|
|
48
|
+
protected readonly computedClass = computed(() =>
|
|
49
|
+
cn('[&_tr:last-child]:border-0', this.class())
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@Directive({
|
|
54
|
+
selector: 'tr[tonTableRow]',
|
|
55
|
+
host: { '[class]': 'computedClass()' },
|
|
56
|
+
})
|
|
57
|
+
export class TonTableRowDirective {
|
|
58
|
+
readonly class = input<string>('');
|
|
59
|
+
private readonly table = inject(TON_TABLE, { optional: true });
|
|
60
|
+
|
|
61
|
+
protected readonly computedClass = computed(() =>
|
|
62
|
+
cn(
|
|
63
|
+
'border-b border-border transition-colors data-[state=selected]:bg-muted',
|
|
64
|
+
this.table?.hoverable() ? 'hover:bg-muted/50' : '',
|
|
65
|
+
this.class()
|
|
66
|
+
)
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@Directive({
|
|
71
|
+
selector: 'th[tonTableHead]',
|
|
72
|
+
host: { '[class]': 'computedClass()' },
|
|
73
|
+
})
|
|
74
|
+
export class TonTableHeadDirective {
|
|
75
|
+
readonly class = input<string>('');
|
|
76
|
+
private readonly table = inject(TON_TABLE, { optional: true });
|
|
77
|
+
|
|
78
|
+
protected readonly computedClass = computed(() =>
|
|
79
|
+
cn(
|
|
80
|
+
'text-left font-medium text-muted-foreground [&[align=center]]:text-center [&[align=right]]:text-right',
|
|
81
|
+
tableCellVariants({ density: this.table?.density() ?? 'normal' }),
|
|
82
|
+
this.class()
|
|
83
|
+
)
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@Directive({
|
|
88
|
+
selector: 'td[tonTableCell]',
|
|
89
|
+
host: { '[class]': 'computedClass()' },
|
|
90
|
+
})
|
|
91
|
+
export class TonTableCellDirective {
|
|
92
|
+
readonly class = input<string>('');
|
|
93
|
+
private readonly table = inject(TON_TABLE, { optional: true });
|
|
94
|
+
|
|
95
|
+
protected readonly computedClass = computed(() =>
|
|
96
|
+
cn(
|
|
97
|
+
'[&[align=center]]:text-center [&[align=right]]:text-right',
|
|
98
|
+
tableCellVariants({ density: this.table?.density() ?? 'normal' }),
|
|
99
|
+
this.class()
|
|
100
|
+
)
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@Directive({
|
|
105
|
+
selector: 'tfoot[tonTableFooter]',
|
|
106
|
+
host: { '[class]': 'computedClass()' },
|
|
107
|
+
})
|
|
108
|
+
export class TonTableFooterDirective {
|
|
109
|
+
readonly class = input<string>('');
|
|
110
|
+
|
|
111
|
+
protected readonly computedClass = computed(() =>
|
|
112
|
+
cn('border-t border-border font-medium [&>tr]:last:border-b-0', this.class())
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@Directive({
|
|
117
|
+
selector: 'caption[tonTableCaption]',
|
|
118
|
+
host: { '[class]': 'computedClass()' },
|
|
119
|
+
})
|
|
120
|
+
export class TonTableCaptionDirective {
|
|
121
|
+
readonly class = input<string>('');
|
|
122
|
+
|
|
123
|
+
protected readonly computedClass = computed(() =>
|
|
124
|
+
cn('mt-4 text-sm text-muted-foreground', this.class())
|
|
125
|
+
);
|
|
126
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { cva } from 'class-variance-authority';
|
|
2
|
+
|
|
3
|
+
export const tableVariants = cva(
|
|
4
|
+
'w-full caption-bottom text-sm border-collapse',
|
|
5
|
+
{
|
|
6
|
+
variants: {
|
|
7
|
+
variant: {
|
|
8
|
+
default: '',
|
|
9
|
+
striped: '[&_tbody_tr:nth-child(even)]:bg-muted/50',
|
|
10
|
+
bordered: 'border border-border [&_th]:border [&_th]:border-border [&_td]:border [&_td]:border-border',
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
defaultVariants: {
|
|
14
|
+
variant: 'default',
|
|
15
|
+
},
|
|
16
|
+
}
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
export const tableCellVariants = cva(
|
|
20
|
+
'',
|
|
21
|
+
{
|
|
22
|
+
variants: {
|
|
23
|
+
density: {
|
|
24
|
+
compact: 'px-2 py-1 text-xs',
|
|
25
|
+
normal: 'px-4 py-3 text-sm',
|
|
26
|
+
comfortable: 'px-6 py-4 text-base',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: {
|
|
30
|
+
density: 'normal',
|
|
31
|
+
},
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
export type TableVariant = 'default' | 'striped' | 'bordered';
|
|
36
|
+
export type TableDensity = 'compact' | 'normal' | 'comfortable';
|