@umituz/web-design-system 4.7.0 → 4.7.2
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/web-design-system",
|
|
3
|
-
"version": "4.7.
|
|
3
|
+
"version": "4.7.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Web Design System - Tailwind v4 authored, precompiled CSS shipped. Atomic Design components (Atoms, Molecules, Organisms, Templates) for React applications.",
|
|
@@ -32,6 +32,7 @@ import { Drawer } from '../presentation/organisms/Drawer';
|
|
|
32
32
|
import { Timeline } from '../presentation/organisms/Timeline';
|
|
33
33
|
import { Checklist } from '../presentation/organisms/Checklist';
|
|
34
34
|
import { FormModal } from '../presentation/organisms/FormModal';
|
|
35
|
+
import { ConfirmDialog } from '../presentation/organisms/ConfirmDialog';
|
|
35
36
|
import { BatteryPill } from '../presentation/atoms/BatteryPill';
|
|
36
37
|
import { Kbd } from '../presentation/atoms/Kbd';
|
|
37
38
|
|
|
@@ -512,6 +513,14 @@ describe('fleet surface supersets', () => {
|
|
|
512
513
|
expect(el.className).toContain('bg-destructive');
|
|
513
514
|
});
|
|
514
515
|
|
|
516
|
+
it('KpiCard flat delta renders muted without an icon', () => {
|
|
517
|
+
const { container } = render(<KpiCard label="Renewals" value="4" delta={{ value: '4 renew ≤45d', direction: 'flat' }} />);
|
|
518
|
+
expect(container.textContent).toContain('4 renew ≤45d');
|
|
519
|
+
const delta = container.querySelector('.text-muted-foreground + span, span.inline-flex');
|
|
520
|
+
expect(container.querySelector('svg.lucide-trending-up, svg.lucide-trending-down')).toBeNull();
|
|
521
|
+
expect(delta).not.toBeNull();
|
|
522
|
+
});
|
|
523
|
+
|
|
515
524
|
it('KpiCard onClick is interactive and fires', () => {
|
|
516
525
|
const onClick = vi.fn();
|
|
517
526
|
const { container } = render(<KpiCard label="Open" value="7" onClick={onClick} />);
|
|
@@ -872,4 +881,20 @@ describe('accessia supersets', () => {
|
|
|
872
881
|
fireEvent.click(screen.getByRole('button', { name: 'Create' }));
|
|
873
882
|
expect(onSubmit).toHaveBeenCalledWith({ welcome: true });
|
|
874
883
|
});
|
|
884
|
+
|
|
885
|
+
it('ConfirmDialog confirms and closes, cancel only closes', () => {
|
|
886
|
+
const onConfirm = vi.fn();
|
|
887
|
+
const onClose = vi.fn();
|
|
888
|
+
render(
|
|
889
|
+
<ConfirmDialog title="Delete row?" body="This cannot be undone." confirmLabel="Delete" onConfirm={onConfirm} onClose={onClose} />,
|
|
890
|
+
);
|
|
891
|
+
expect(screen.getByRole('dialog')).toBeTruthy();
|
|
892
|
+
expect(screen.getByText('This cannot be undone.')).toBeTruthy();
|
|
893
|
+
fireEvent.click(screen.getByRole('button', { name: 'Cancel' }));
|
|
894
|
+
expect(onClose).toHaveBeenCalledTimes(1);
|
|
895
|
+
expect(onConfirm).not.toHaveBeenCalled();
|
|
896
|
+
fireEvent.click(screen.getByRole('button', { name: 'Delete' }));
|
|
897
|
+
expect(onConfirm).toHaveBeenCalledTimes(1);
|
|
898
|
+
expect(onClose).toHaveBeenCalledTimes(2);
|
|
899
|
+
});
|
|
875
900
|
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConfirmDialog Component (Organism)
|
|
3
|
+
* @description Destructive/primary confirmation built on Modal: title, body and
|
|
4
|
+
* Cancel + confirm actions; unmounts itself after confirming
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { ReactNode } from 'react';
|
|
8
|
+
import { Button } from '../atoms/Button';
|
|
9
|
+
import { Modal } from './Modal';
|
|
10
|
+
|
|
11
|
+
export interface ConfirmDialogProps {
|
|
12
|
+
title: ReactNode;
|
|
13
|
+
body?: ReactNode;
|
|
14
|
+
confirmLabel?: string;
|
|
15
|
+
cancelLabel?: string;
|
|
16
|
+
/** Visual weight of the confirm action; defaults to danger. */
|
|
17
|
+
tone?: 'danger' | 'primary';
|
|
18
|
+
onConfirm: () => void;
|
|
19
|
+
onClose: () => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function ConfirmDialog({ title, body, confirmLabel = 'Confirm', cancelLabel = 'Cancel', tone = 'danger', onConfirm, onClose }: ConfirmDialogProps) {
|
|
23
|
+
return (
|
|
24
|
+
<Modal
|
|
25
|
+
open
|
|
26
|
+
danger={tone === 'danger'}
|
|
27
|
+
title={title}
|
|
28
|
+
description={body}
|
|
29
|
+
onClose={onClose}
|
|
30
|
+
footer={
|
|
31
|
+
<>
|
|
32
|
+
<Button variant="secondary" size="sm" onClick={onClose}>
|
|
33
|
+
{cancelLabel}
|
|
34
|
+
</Button>
|
|
35
|
+
<Button variant={tone === 'danger' ? 'danger' : 'default'} size="sm" onClick={() => { onConfirm(); onClose(); }}>
|
|
36
|
+
{confirmLabel}
|
|
37
|
+
</Button>
|
|
38
|
+
</>
|
|
39
|
+
}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -14,7 +14,7 @@ export type KpiIconTone = 'primary' | 'success' | 'warning' | 'destructive' | 'i
|
|
|
14
14
|
|
|
15
15
|
export interface KpiDelta {
|
|
16
16
|
value: ReactNode;
|
|
17
|
-
direction?: 'up' | 'down';
|
|
17
|
+
direction?: 'up' | 'down' | 'flat';
|
|
18
18
|
good?: boolean;
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -45,8 +45,9 @@ const toneTextClasses: Record<KpiIconTone, string> = {
|
|
|
45
45
|
export const KpiCard = forwardRef<HTMLDivElement, KpiCardProps>(
|
|
46
46
|
({ className, label, value, delta, hint, icon, iconTone = 'primary', spark, sparkTone = 'primary', alert, onClick, ...props }, ref) => {
|
|
47
47
|
const deltaDirection = delta?.direction ?? (delta?.good === false ? 'down' : 'up');
|
|
48
|
+
const deltaFlat = deltaDirection === 'flat';
|
|
48
49
|
const deltaGood = delta?.good ?? deltaDirection === 'up';
|
|
49
|
-
const DeltaIcon = deltaDirection === 'up' ? TrendingUp : TrendingDown;
|
|
50
|
+
const DeltaIcon = deltaFlat ? null : deltaDirection === 'up' ? TrendingUp : TrendingDown;
|
|
50
51
|
const interactive = onClick !== undefined;
|
|
51
52
|
return (
|
|
52
53
|
<Card
|
|
@@ -81,10 +82,10 @@ export const KpiCard = forwardRef<HTMLDivElement, KpiCardProps>(
|
|
|
81
82
|
<span
|
|
82
83
|
className={cn(
|
|
83
84
|
'inline-flex items-center gap-1 font-medium',
|
|
84
|
-
deltaGood ? 'text-success' : 'text-destructive'
|
|
85
|
+
deltaFlat ? 'text-muted-foreground' : deltaGood ? 'text-success' : 'text-destructive'
|
|
85
86
|
)}
|
|
86
87
|
>
|
|
87
|
-
<DeltaIcon className="h-3.5 w-3.5" />
|
|
88
|
+
{DeltaIcon !== null && <DeltaIcon className="h-3.5 w-3.5" />}
|
|
88
89
|
{delta.value}
|
|
89
90
|
</span>
|
|
90
91
|
)}
|