@umituz/web-design-system 5.3.0 → 5.4.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/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/__tests__/cn.test.ts +0 -3
- package/src/__tests__/component-slots.test.tsx +0 -4
- package/src/__tests__/components.smoke.test.tsx +3 -11
- package/src/__tests__/money.test.tsx +0 -3
- package/src/__tests__/productivity-components.test.tsx +135 -0
- package/src/__tests__/styles.contract.test.ts +0 -13
- package/src/domain/tokens/index.ts +0 -7
- package/src/domain/tokens/responsive-map.tokens.ts +18 -107
- package/src/domain/types/breakpoint.types.ts +9 -13
- package/src/domain/types/component.types.ts +0 -4
- package/src/domain/types/index.ts +0 -5
- package/src/global.d.ts +0 -4
- package/src/index.ts +82 -29
- package/src/infrastructure/constants/breakpoint.constants.ts +0 -31
- package/src/infrastructure/constants/component.constants.ts +0 -4
- package/src/infrastructure/constants/index.ts +0 -5
- package/src/infrastructure/constants/size-variant.constants.ts +0 -33
- package/src/infrastructure/constants/spacing.constants.ts +34 -63
- package/src/infrastructure/constants/timing.constants.ts +0 -18
- package/src/infrastructure/constants/typography.constants.ts +22 -54
- package/src/infrastructure/utils/calculation.utils.ts +0 -9
- package/src/infrastructure/utils/cn.util.ts +0 -18
- package/src/infrastructure/utils/hash.util.ts +0 -5
- package/src/infrastructure/utils/index.ts +0 -5
- package/src/infrastructure/utils/money.utils.ts +0 -7
- package/src/infrastructure/utils/responsive.utils.ts +0 -66
- package/src/presentation/atoms/AspectRatio.tsx +0 -10
- package/src/presentation/atoms/Badge.tsx +0 -5
- package/src/presentation/atoms/BatteryPill.tsx +0 -5
- package/src/presentation/atoms/Button.tsx +0 -2
- package/src/presentation/atoms/Checkbox.tsx +0 -4
- package/src/presentation/atoms/CopyButton.tsx +93 -0
- package/src/presentation/atoms/Divider.tsx +0 -4
- package/src/presentation/atoms/HeatmapStrip.tsx +0 -10
- package/src/presentation/atoms/Hide.tsx +0 -24
- package/src/presentation/atoms/Icon.tsx +0 -4
- package/src/presentation/atoms/IconButton.tsx +0 -4
- package/src/presentation/atoms/Input.tsx +0 -4
- package/src/presentation/atoms/Kbd.tsx +0 -4
- package/src/presentation/atoms/Label.tsx +0 -4
- package/src/presentation/atoms/Link.tsx +0 -4
- package/src/presentation/atoms/Money.tsx +0 -6
- package/src/presentation/atoms/Progress.tsx +0 -6
- package/src/presentation/atoms/Radio.tsx +0 -4
- package/src/presentation/atoms/Separator.tsx +0 -4
- package/src/presentation/atoms/Show.tsx +0 -24
- package/src/presentation/atoms/Skeleton.tsx +0 -4
- package/src/presentation/atoms/Slider.tsx +0 -4
- package/src/presentation/atoms/Sparkline.tsx +0 -4
- package/src/presentation/atoms/Spinner.tsx +0 -4
- package/src/presentation/atoms/StatusDot.tsx +79 -0
- package/src/presentation/atoms/Switch.tsx +0 -4
- package/src/presentation/atoms/Text.tsx +0 -4
- package/src/presentation/atoms/Textarea.tsx +0 -4
- package/src/presentation/atoms/Toggle.tsx +0 -4
- package/src/presentation/atoms/Tooltip.tsx +0 -4
- package/src/presentation/atoms/index.ts +9 -9
- package/src/presentation/hooks/index.ts +0 -5
- package/src/presentation/hooks/useClickOutside.ts +0 -6
- package/src/presentation/hooks/useClipboard.ts +0 -4
- package/src/presentation/hooks/useDebounce.ts +0 -8
- package/src/presentation/hooks/useKeyboard.ts +0 -6
- package/src/presentation/hooks/useLocalStorage.ts +0 -4
- package/src/presentation/hooks/useMediaQuery.ts +0 -37
- package/src/presentation/hooks/useScrollLock.ts +0 -5
- package/src/presentation/hooks/useTheme.ts +9 -13
- package/src/presentation/hooks/useToggle.ts +0 -4
- package/src/presentation/molecules/ActiveFilterTags.tsx +0 -4
- package/src/presentation/molecules/Avatar.tsx +0 -5
- package/src/presentation/molecules/BookmarkButton.tsx +0 -15
- package/src/presentation/molecules/CheckboxGroup.tsx +0 -4
- package/src/presentation/molecules/Chip.tsx +0 -5
- package/src/presentation/molecules/CodeBlock.tsx +0 -5
- package/src/presentation/molecules/ConfirmButton.tsx +125 -0
- package/src/presentation/molecules/Field.tsx +0 -7
- package/src/presentation/molecules/FormField.tsx +1 -5
- package/src/presentation/molecules/InputGroup.tsx +0 -4
- package/src/presentation/molecules/ListItem.tsx +0 -4
- package/src/presentation/molecules/OptionTile.tsx +0 -10
- package/src/presentation/molecules/PasswordInput.tsx +43 -0
- package/src/presentation/molecules/RadioGroup.tsx +0 -4
- package/src/presentation/molecules/RatingStars.tsx +0 -8
- package/src/presentation/molecules/ScrollArea.tsx +0 -4
- package/src/presentation/molecules/SearchBox.tsx +0 -4
- package/src/presentation/molecules/SearchInput.tsx +110 -0
- package/src/presentation/molecules/Select.tsx +0 -4
- package/src/presentation/molecules/StatPill.tsx +0 -5
- package/src/presentation/molecules/TagInput.tsx +0 -7
- package/src/presentation/molecules/Textarea.tsx +0 -4
- package/src/presentation/molecules/Toggle.tsx +0 -4
- package/src/presentation/molecules/Toolbar.tsx +36 -0
- package/src/presentation/molecules/index.ts +25 -8
- package/src/presentation/organisms/Accordion.tsx +0 -4
- package/src/presentation/organisms/Alert.tsx +0 -4
- package/src/presentation/organisms/AvatarStack.tsx +0 -5
- package/src/presentation/organisms/Breadcrumb.tsx +0 -7
- package/src/presentation/organisms/Card.tsx +0 -6
- package/src/presentation/organisms/Checklist.tsx +0 -4
- package/src/presentation/organisms/Collapsible.tsx +0 -4
- package/src/presentation/organisms/ConfirmDialog.tsx +0 -8
- package/src/presentation/organisms/CoverArt.tsx +0 -9
- package/src/presentation/organisms/DataTable.tsx +0 -8
- package/src/presentation/organisms/DateRangePicker.tsx +0 -9
- package/src/presentation/organisms/DescriptionList.tsx +113 -0
- package/src/presentation/organisms/Dialog.tsx +0 -4
- package/src/presentation/organisms/Drawer.tsx +0 -6
- package/src/presentation/organisms/DropdownMenu.tsx +0 -4
- package/src/presentation/organisms/ErrorBoundary.tsx +0 -12
- package/src/presentation/organisms/FileUploader.tsx +0 -9
- package/src/presentation/organisms/FilterPopover.tsx +0 -8
- package/src/presentation/organisms/FormModal.tsx +0 -5
- package/src/presentation/organisms/HoverCard.tsx +0 -4
- package/src/presentation/organisms/KeyValueList.tsx +0 -4
- package/src/presentation/organisms/KpiCard.tsx +0 -6
- package/src/presentation/organisms/Lightbox.tsx +0 -7
- package/src/presentation/organisms/LoadingState.tsx +0 -4
- package/src/presentation/organisms/MapPreview.tsx +0 -9
- package/src/presentation/organisms/MetricCard.tsx +1 -5
- package/src/presentation/organisms/Modal.tsx +0 -4
- package/src/presentation/organisms/PhotoGallery.tsx +0 -9
- package/src/presentation/organisms/PlanPicker.tsx +0 -5
- package/src/presentation/organisms/Popover.tsx +0 -4
- package/src/presentation/organisms/Sheet.tsx +0 -4
- package/src/presentation/organisms/StatCard.tsx +0 -5
- package/src/presentation/organisms/StatsGrid.tsx +110 -0
- package/src/presentation/organisms/StatusBadge.tsx +0 -12
- package/src/presentation/organisms/Stepper.tsx +0 -5
- package/src/presentation/organisms/Table.tsx +0 -4
- package/src/presentation/organisms/Tabs.tsx +0 -7
- package/src/presentation/organisms/Timeline.tsx +0 -8
- package/src/presentation/organisms/Toaster.tsx +0 -9
- package/src/presentation/organisms/ToggleGroup.tsx +0 -4
- package/src/presentation/organisms/index.ts +10 -11
- package/src/presentation/templates/CrudPageTemplate.tsx +69 -0
- package/src/presentation/templates/Form.tsx +0 -4
- package/src/presentation/templates/List.tsx +0 -4
- package/src/presentation/templates/PageHeader.tsx +0 -4
- package/src/presentation/templates/PageLayout.tsx +0 -4
- package/src/presentation/templates/ProjectSkeleton.tsx +0 -4
- package/src/presentation/templates/ResponsiveContainer.tsx +0 -43
- package/src/presentation/templates/Section.tsx +0 -4
- package/src/presentation/templates/SettingsLayout.tsx +102 -0
- package/src/presentation/templates/index.ts +7 -6
- package/src/styles/app.css +0 -18
- package/src/styles/bridge.css +0 -34
- package/src/styles/compile.css +0 -13
- package/src/styles/source.css +0 -12
- package/src/styles/theme.css +0 -27
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Copy, Check } from 'lucide-react';
|
|
3
|
+
import { cn } from '../../infrastructure/utils';
|
|
4
|
+
import { useClipboard } from '../hooks/useClipboard';
|
|
5
|
+
|
|
6
|
+
export interface CopyButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
7
|
+
text: string;
|
|
8
|
+
label?: string;
|
|
9
|
+
copiedLabel?: string;
|
|
10
|
+
variant?: 'outline' | 'ghost' | 'secondary' | 'default';
|
|
11
|
+
size?: 'xs' | 'sm' | 'md' | 'lg';
|
|
12
|
+
showLabel?: boolean;
|
|
13
|
+
onCopySuccess?: (text: string) => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const sizeStyles = {
|
|
17
|
+
xs: 'h-6 px-2 text-xs gap-1 [&_svg]:size-3',
|
|
18
|
+
sm: 'h-8 px-2.5 text-xs gap-1.5 [&_svg]:size-3.5',
|
|
19
|
+
md: 'h-9 px-3 text-sm gap-2 [&_svg]:size-4',
|
|
20
|
+
lg: 'h-10 px-4 text-sm gap-2 [&_svg]:size-4',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const iconOnlySizeStyles = {
|
|
24
|
+
xs: 'h-6 w-6 p-0 [&_svg]:size-3',
|
|
25
|
+
sm: 'h-8 w-8 p-0 [&_svg]:size-3.5',
|
|
26
|
+
md: 'h-9 w-9 p-0 [&_svg]:size-4',
|
|
27
|
+
lg: 'h-10 w-10 p-0 [&_svg]:size-4',
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const variantStyles = {
|
|
31
|
+
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
|
32
|
+
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
|
33
|
+
outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
|
|
34
|
+
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const CopyButton = React.forwardRef<HTMLButtonElement, CopyButtonProps>(
|
|
38
|
+
(
|
|
39
|
+
{
|
|
40
|
+
text,
|
|
41
|
+
label = 'Kopyala',
|
|
42
|
+
copiedLabel = 'Kopyalandı',
|
|
43
|
+
variant = 'outline',
|
|
44
|
+
size = 'sm',
|
|
45
|
+
showLabel = false,
|
|
46
|
+
className,
|
|
47
|
+
onClick,
|
|
48
|
+
onCopySuccess,
|
|
49
|
+
...props
|
|
50
|
+
},
|
|
51
|
+
ref
|
|
52
|
+
) => {
|
|
53
|
+
const { copied, copy } = useClipboard();
|
|
54
|
+
|
|
55
|
+
const handleCopy = async (e: React.MouseEvent<HTMLButtonElement>) => {
|
|
56
|
+
onClick?.(e);
|
|
57
|
+
if (e.defaultPrevented) return;
|
|
58
|
+
const success = await copy(text);
|
|
59
|
+
if (success) {
|
|
60
|
+
onCopySuccess?.(text);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<button
|
|
66
|
+
ref={ref}
|
|
67
|
+
type="button"
|
|
68
|
+
aria-label={copied ? copiedLabel : label}
|
|
69
|
+
title={copied ? copiedLabel : label}
|
|
70
|
+
className={cn(
|
|
71
|
+
'inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 shrink-0 select-none',
|
|
72
|
+
showLabel ? sizeStyles[size] : iconOnlySizeStyles[size],
|
|
73
|
+
variantStyles[variant],
|
|
74
|
+
copied && 'text-emerald-600 dark:text-emerald-400 border-emerald-500/40 bg-emerald-500/10 hover:bg-emerald-500/20',
|
|
75
|
+
className
|
|
76
|
+
)}
|
|
77
|
+
onClick={handleCopy}
|
|
78
|
+
{...props}
|
|
79
|
+
>
|
|
80
|
+
{copied ? (
|
|
81
|
+
<Check className="shrink-0 transition-transform duration-200 scale-110" />
|
|
82
|
+
) : (
|
|
83
|
+
<Copy className="shrink-0" />
|
|
84
|
+
)}
|
|
85
|
+
{showLabel && (
|
|
86
|
+
<span>{copied ? copiedLabel : label}</span>
|
|
87
|
+
)}
|
|
88
|
+
</button>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
CopyButton.displayName = 'CopyButton';
|
|
@@ -1,28 +1,18 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HeatmapStrip Component (Atom)
|
|
3
|
-
* @description Compact threshold-toned strip of cells — percent-driven color
|
|
4
|
-
* and opacity ramps (skill coverage, streak calendars, activity strips).
|
|
5
|
-
*/
|
|
6
1
|
|
|
7
2
|
import { forwardRef } from 'react';
|
|
8
3
|
import { cn } from '../../infrastructure/utils';
|
|
9
4
|
import type { BaseProps } from '../../domain/types';
|
|
10
5
|
|
|
11
6
|
export interface HeatmapCell {
|
|
12
|
-
/** 0–100, or null for "no data". */
|
|
13
7
|
percent: number | null;
|
|
14
|
-
/** Tooltip text for the cell. */
|
|
15
8
|
label?: string;
|
|
16
9
|
}
|
|
17
10
|
|
|
18
11
|
export interface HeatmapStripProps extends BaseProps {
|
|
19
12
|
cells: readonly HeatmapCell[];
|
|
20
|
-
/** >= goodAt renders success; >= lowAt renders primary; below renders destructive. */
|
|
21
13
|
goodAt?: number;
|
|
22
14
|
lowAt?: number;
|
|
23
|
-
/** Cell height in px. */
|
|
24
15
|
height?: number;
|
|
25
|
-
/** Accessible name for the whole strip. */
|
|
26
16
|
label?: string;
|
|
27
17
|
}
|
|
28
18
|
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hide Component (Atom)
|
|
3
|
-
* @description Conditionally hide content based on screen breakpoint
|
|
4
|
-
*/
|
|
5
1
|
|
|
6
2
|
import { useBreakpoint } from '../hooks/useMediaQuery';
|
|
7
3
|
import type { HideProps } from '../../domain/types/breakpoint.types';
|
|
@@ -11,29 +7,9 @@ export interface HideComponentProps extends BaseProps, HideProps {
|
|
|
11
7
|
children: React.ReactNode;
|
|
12
8
|
}
|
|
13
9
|
|
|
14
|
-
/**
|
|
15
|
-
* Conditionally hide content based on breakpoint
|
|
16
|
-
* @param above - Hide on screens larger than this breakpoint
|
|
17
|
-
* @param below - Hide on screens smaller than this breakpoint
|
|
18
|
-
* @param at - Hide only on this specific breakpoint
|
|
19
|
-
* @param children - Content to hide
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* ```tsx
|
|
23
|
-
* // Hide on mobile (md and below)
|
|
24
|
-
* <Hide below="md"><DesktopNav /></Hide>
|
|
25
|
-
*
|
|
26
|
-
* // Hide on desktop (lg and above)
|
|
27
|
-
* <Hide above="lg"><MobileNav /></Hide>
|
|
28
|
-
*
|
|
29
|
-
* // Hide only on tablet
|
|
30
|
-
* <Hide at="md"><TabletContent /></Hide>
|
|
31
|
-
* ```
|
|
32
|
-
*/
|
|
33
10
|
export const Hide = ({ above, below, at, children, className }: HideComponentProps) => {
|
|
34
11
|
const { matches, isGreaterThan, isLessThan } = useBreakpoint();
|
|
35
12
|
|
|
36
|
-
// Determine if content should be hidden
|
|
37
13
|
let shouldHide = false;
|
|
38
14
|
|
|
39
15
|
if (above) {
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Money Component (Atom)
|
|
3
|
-
* @description Locale-aware currency amount from minor units, tabular digits
|
|
4
|
-
*/
|
|
5
1
|
|
|
6
2
|
import { forwardRef, type HTMLAttributes } from 'react';
|
|
7
3
|
import { formatMoney } from '../../infrastructure/utils';
|
|
@@ -9,9 +5,7 @@ import { cn } from '../../infrastructure/utils';
|
|
|
9
5
|
import type { BaseProps } from '../../domain/types';
|
|
10
6
|
|
|
11
7
|
export interface MoneyProps extends HTMLAttributes<HTMLSpanElement>, BaseProps {
|
|
12
|
-
/** Integer amount in minor units (e.g. cents) — never floating point. */
|
|
13
8
|
amountMinor: number;
|
|
14
|
-
/** ISO 4217 currency code; drives the fraction digits. */
|
|
15
9
|
currency: string;
|
|
16
10
|
locale?: string;
|
|
17
11
|
}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Progress Component (Atom)
|
|
3
|
-
* @description Progress indicator bar with optional percent readout and
|
|
4
|
-
* threshold-driven auto tone (>=95 success, >=70 primary, below muted)
|
|
5
|
-
*/
|
|
6
1
|
|
|
7
2
|
import { forwardRef, type HTMLAttributes } from 'react';
|
|
8
3
|
import { cn } from '../../infrastructure/utils';
|
|
@@ -15,7 +10,6 @@ export interface ProgressProps extends HTMLAttributes<HTMLDivElement>, BaseProps
|
|
|
15
10
|
size?: 'sm' | 'md' | 'lg';
|
|
16
11
|
tone?: 'primary' | 'success' | 'warning' | 'destructive' | 'info' | 'auto';
|
|
17
12
|
label?: string;
|
|
18
|
-
/** Render the rounded percentage next to the bar. */
|
|
19
13
|
showValue?: boolean;
|
|
20
14
|
}
|
|
21
15
|
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Show Component (Atom)
|
|
3
|
-
* @description Conditionally render content based on screen breakpoint
|
|
4
|
-
*/
|
|
5
1
|
|
|
6
2
|
import { useBreakpoint } from '../hooks/useMediaQuery';
|
|
7
3
|
import type { ShowProps } from '../../domain/types/breakpoint.types';
|
|
@@ -11,29 +7,9 @@ export interface ShowComponentProps extends BaseProps, ShowProps {
|
|
|
11
7
|
children: React.ReactNode;
|
|
12
8
|
}
|
|
13
9
|
|
|
14
|
-
/**
|
|
15
|
-
* Conditionally show content based on breakpoint
|
|
16
|
-
* @param above - Show on screens larger than this breakpoint
|
|
17
|
-
* @param below - Show on screens smaller than this breakpoint
|
|
18
|
-
* @param at - Show only on this specific breakpoint
|
|
19
|
-
* @param children - Content to show
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* ```tsx
|
|
23
|
-
* // Show on desktop (lg and above)
|
|
24
|
-
* <Show above="lg"><DesktopNav /></Show>
|
|
25
|
-
*
|
|
26
|
-
* // Show on mobile (sm and below)
|
|
27
|
-
* <Show below="md"><MobileNav /></Show>
|
|
28
|
-
*
|
|
29
|
-
* // Show only on tablet
|
|
30
|
-
* <Show at="md"><TabletContent /></Show>
|
|
31
|
-
* ```
|
|
32
|
-
*/
|
|
33
10
|
export const Show = ({ above, below, at, children, className }: ShowComponentProps) => {
|
|
34
11
|
const { matches, isGreaterThan, isLessThan } = useBreakpoint();
|
|
35
12
|
|
|
36
|
-
// Determine if content should be shown
|
|
37
13
|
let shouldShow = true;
|
|
38
14
|
|
|
39
15
|
if (above) {
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { cn } from '../../infrastructure/utils';
|
|
3
|
+
|
|
4
|
+
export type StatusType =
|
|
5
|
+
| 'online'
|
|
6
|
+
| 'offline'
|
|
7
|
+
| 'busy'
|
|
8
|
+
| 'away'
|
|
9
|
+
| 'pending'
|
|
10
|
+
| 'success'
|
|
11
|
+
| 'warning'
|
|
12
|
+
| 'error';
|
|
13
|
+
|
|
14
|
+
export interface StatusDotProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
15
|
+
status: StatusType;
|
|
16
|
+
ping?: boolean;
|
|
17
|
+
label?: string;
|
|
18
|
+
size?: 'xs' | 'sm' | 'md' | 'lg';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const colorMap: Record<StatusType, { dot: string; ping: string }> = {
|
|
22
|
+
online: { dot: 'bg-emerald-500', ping: 'bg-emerald-400' },
|
|
23
|
+
success: { dot: 'bg-emerald-500', ping: 'bg-emerald-400' },
|
|
24
|
+
busy: { dot: 'bg-rose-500', ping: 'bg-rose-400' },
|
|
25
|
+
error: { dot: 'bg-rose-500', ping: 'bg-rose-400' },
|
|
26
|
+
away: { dot: 'bg-amber-500', ping: 'bg-amber-400' },
|
|
27
|
+
warning: { dot: 'bg-amber-500', ping: 'bg-amber-400' },
|
|
28
|
+
pending: { dot: 'bg-sky-500', ping: 'bg-sky-400' },
|
|
29
|
+
offline: { dot: 'bg-zinc-400 dark:bg-zinc-500', ping: 'bg-zinc-300' },
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const dotSizeMap = {
|
|
33
|
+
xs: 'size-1.5',
|
|
34
|
+
sm: 'size-2',
|
|
35
|
+
md: 'size-2.5',
|
|
36
|
+
lg: 'size-3.5',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const textSizeMap = {
|
|
40
|
+
xs: 'text-xs',
|
|
41
|
+
sm: 'text-xs',
|
|
42
|
+
md: 'text-sm',
|
|
43
|
+
lg: 'text-base',
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const StatusDot = React.forwardRef<HTMLSpanElement, StatusDotProps>(
|
|
47
|
+
({ status, ping = false, label, size = 'sm', className, ...props }, ref) => {
|
|
48
|
+
const colors = colorMap[status] ?? colorMap.offline;
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<span
|
|
52
|
+
ref={ref}
|
|
53
|
+
className={cn('inline-flex items-center gap-2 select-none', textSizeMap[size], className)}
|
|
54
|
+
{...props}
|
|
55
|
+
>
|
|
56
|
+
<span className="relative flex shrink-0 items-center justify-center">
|
|
57
|
+
{ping && status !== 'offline' && (
|
|
58
|
+
<span
|
|
59
|
+
className={cn(
|
|
60
|
+
'absolute inline-flex h-full w-full animate-ping rounded-full opacity-75',
|
|
61
|
+
colors.ping
|
|
62
|
+
)}
|
|
63
|
+
/>
|
|
64
|
+
)}
|
|
65
|
+
<span
|
|
66
|
+
className={cn(
|
|
67
|
+
'relative inline-flex rounded-full',
|
|
68
|
+
dotSizeMap[size],
|
|
69
|
+
colors.dot
|
|
70
|
+
)}
|
|
71
|
+
/>
|
|
72
|
+
</span>
|
|
73
|
+
{label && <span className="text-foreground/90 font-medium">{label}</span>}
|
|
74
|
+
</span>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
StatusDot.displayName = 'StatusDot';
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Atoms Export
|
|
3
|
-
* @description Atomic components - smallest UI elements
|
|
4
|
-
* Subpath: @umituz/web-design-system/atoms
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
export { Button } from './Button';
|
|
1
|
+
export { Button, buttonVariants } from './Button';
|
|
8
2
|
export type { ButtonProps } from './Button';
|
|
9
3
|
|
|
10
4
|
export { Badge } from './Badge';
|
|
@@ -65,7 +59,6 @@ export { Toggle, toggleVariants } from './Toggle';
|
|
|
65
59
|
|
|
66
60
|
export { Show } from './Show';
|
|
67
61
|
export type { ShowComponentProps } from './Show';
|
|
68
|
-
|
|
69
62
|
export { Hide } from './Hide';
|
|
70
63
|
export type { HideComponentProps } from './Hide';
|
|
71
64
|
|
|
@@ -73,9 +66,9 @@ export { IconButton } from './IconButton';
|
|
|
73
66
|
export type { IconButtonProps } from './IconButton';
|
|
74
67
|
|
|
75
68
|
export { Sparkline } from './Sparkline';
|
|
69
|
+
export type { SparklineProps } from './Sparkline';
|
|
76
70
|
export { HeatmapStrip } from './HeatmapStrip';
|
|
77
71
|
export type { HeatmapStripProps, HeatmapCell } from './HeatmapStrip';
|
|
78
|
-
export type { SparklineProps } from './Sparkline';
|
|
79
72
|
|
|
80
73
|
export { NativeSelect } from './NativeSelect';
|
|
81
74
|
export type { NativeSelectProps, NativeSelectOption } from './NativeSelect';
|
|
@@ -91,3 +84,10 @@ export type { KbdProps } from './Kbd';
|
|
|
91
84
|
|
|
92
85
|
export { Money } from './Money';
|
|
93
86
|
export type { MoneyProps } from './Money';
|
|
87
|
+
|
|
88
|
+
// New Productivity Atoms
|
|
89
|
+
export { CopyButton } from './CopyButton';
|
|
90
|
+
export type { CopyButtonProps } from './CopyButton';
|
|
91
|
+
|
|
92
|
+
export { StatusDot } from './StatusDot';
|
|
93
|
+
export type { StatusDotProps, StatusType } from './StatusDot';
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useClickOutside Hook
|
|
3
|
-
* @description Detect clicks outside an element
|
|
4
|
-
*/
|
|
5
1
|
|
|
6
2
|
import { useEffect, useRef } from 'react';
|
|
7
3
|
|
|
@@ -10,8 +6,6 @@ export function useClickOutside<T extends HTMLElement>(
|
|
|
10
6
|
enabled: boolean = true
|
|
11
7
|
) {
|
|
12
8
|
const ref = useRef<T>(null);
|
|
13
|
-
// Use a ref to keep the latest callback without retriggering the effect
|
|
14
|
-
// on every render — callers commonly pass inline functions.
|
|
15
9
|
const callbackRef = useRef(callback);
|
|
16
10
|
useEffect(() => {
|
|
17
11
|
callbackRef.current = callback;
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useDebounce Hook
|
|
3
|
-
* @description Debounce a value with optimized performance
|
|
4
|
-
*/
|
|
5
1
|
|
|
6
2
|
import { useState, useEffect, useRef, useCallback } from 'react';
|
|
7
3
|
import { TIMING } from '../../infrastructure/constants/timing.constants';
|
|
@@ -30,10 +26,6 @@ export function useDebounce<T>(value: T, delay: number = TIMING.DEBOUNCE_DEFAULT
|
|
|
30
26
|
return debouncedValue;
|
|
31
27
|
}
|
|
32
28
|
|
|
33
|
-
/**
|
|
34
|
-
* useThrottle Hook
|
|
35
|
-
* @description Throttle a function to limit execution rate
|
|
36
|
-
*/
|
|
37
29
|
export function useThrottle<T extends (...args: unknown[]) => unknown>(
|
|
38
30
|
func: T,
|
|
39
31
|
delay: number = TIMING.THROTTLE_DEFAULT_MS
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useKeyboard Hook
|
|
3
|
-
* @description Keyboard event handling
|
|
4
|
-
*/
|
|
5
1
|
|
|
6
2
|
import { useEffect, useCallback } from 'react';
|
|
7
3
|
|
|
@@ -16,7 +12,6 @@ export interface KeyboardOptions {
|
|
|
16
12
|
enabled?: boolean;
|
|
17
13
|
}
|
|
18
14
|
|
|
19
|
-
// Helper function to check if modifiers match
|
|
20
15
|
const checkModifiers = (event: KeyboardEvent, modifiers: KeyboardModifier[]): boolean => {
|
|
21
16
|
return modifiers.every((mod) => {
|
|
22
17
|
switch (mod) {
|
|
@@ -41,7 +36,6 @@ export function useKeyboard({
|
|
|
41
36
|
onKeyUp,
|
|
42
37
|
enabled = true,
|
|
43
38
|
}: KeyboardOptions) {
|
|
44
|
-
// FIX: Create handlers once and reuse to prevent duplicate logic
|
|
45
39
|
const handleKeyDown = useCallback((event: KeyboardEvent) => {
|
|
46
40
|
const keyMatches = event.key.toLowerCase() === key.toLowerCase();
|
|
47
41
|
const modifiersMatch = checkModifiers(event, modifiers);
|