@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.
Files changed (150) hide show
  1. package/dist/styles.css +1 -1
  2. package/package.json +1 -1
  3. package/src/__tests__/cn.test.ts +0 -3
  4. package/src/__tests__/component-slots.test.tsx +0 -4
  5. package/src/__tests__/components.smoke.test.tsx +3 -11
  6. package/src/__tests__/money.test.tsx +0 -3
  7. package/src/__tests__/productivity-components.test.tsx +135 -0
  8. package/src/__tests__/styles.contract.test.ts +0 -13
  9. package/src/domain/tokens/index.ts +0 -7
  10. package/src/domain/tokens/responsive-map.tokens.ts +18 -107
  11. package/src/domain/types/breakpoint.types.ts +9 -13
  12. package/src/domain/types/component.types.ts +0 -4
  13. package/src/domain/types/index.ts +0 -5
  14. package/src/global.d.ts +0 -4
  15. package/src/index.ts +82 -29
  16. package/src/infrastructure/constants/breakpoint.constants.ts +0 -31
  17. package/src/infrastructure/constants/component.constants.ts +0 -4
  18. package/src/infrastructure/constants/index.ts +0 -5
  19. package/src/infrastructure/constants/size-variant.constants.ts +0 -33
  20. package/src/infrastructure/constants/spacing.constants.ts +34 -63
  21. package/src/infrastructure/constants/timing.constants.ts +0 -18
  22. package/src/infrastructure/constants/typography.constants.ts +22 -54
  23. package/src/infrastructure/utils/calculation.utils.ts +0 -9
  24. package/src/infrastructure/utils/cn.util.ts +0 -18
  25. package/src/infrastructure/utils/hash.util.ts +0 -5
  26. package/src/infrastructure/utils/index.ts +0 -5
  27. package/src/infrastructure/utils/money.utils.ts +0 -7
  28. package/src/infrastructure/utils/responsive.utils.ts +0 -66
  29. package/src/presentation/atoms/AspectRatio.tsx +0 -10
  30. package/src/presentation/atoms/Badge.tsx +0 -5
  31. package/src/presentation/atoms/BatteryPill.tsx +0 -5
  32. package/src/presentation/atoms/Button.tsx +0 -2
  33. package/src/presentation/atoms/Checkbox.tsx +0 -4
  34. package/src/presentation/atoms/CopyButton.tsx +93 -0
  35. package/src/presentation/atoms/Divider.tsx +0 -4
  36. package/src/presentation/atoms/HeatmapStrip.tsx +0 -10
  37. package/src/presentation/atoms/Hide.tsx +0 -24
  38. package/src/presentation/atoms/Icon.tsx +0 -4
  39. package/src/presentation/atoms/IconButton.tsx +0 -4
  40. package/src/presentation/atoms/Input.tsx +0 -4
  41. package/src/presentation/atoms/Kbd.tsx +0 -4
  42. package/src/presentation/atoms/Label.tsx +0 -4
  43. package/src/presentation/atoms/Link.tsx +0 -4
  44. package/src/presentation/atoms/Money.tsx +0 -6
  45. package/src/presentation/atoms/Progress.tsx +0 -6
  46. package/src/presentation/atoms/Radio.tsx +0 -4
  47. package/src/presentation/atoms/Separator.tsx +0 -4
  48. package/src/presentation/atoms/Show.tsx +0 -24
  49. package/src/presentation/atoms/Skeleton.tsx +0 -4
  50. package/src/presentation/atoms/Slider.tsx +0 -4
  51. package/src/presentation/atoms/Sparkline.tsx +0 -4
  52. package/src/presentation/atoms/Spinner.tsx +0 -4
  53. package/src/presentation/atoms/StatusDot.tsx +79 -0
  54. package/src/presentation/atoms/Switch.tsx +0 -4
  55. package/src/presentation/atoms/Text.tsx +0 -4
  56. package/src/presentation/atoms/Textarea.tsx +0 -4
  57. package/src/presentation/atoms/Toggle.tsx +0 -4
  58. package/src/presentation/atoms/Tooltip.tsx +0 -4
  59. package/src/presentation/atoms/index.ts +9 -9
  60. package/src/presentation/hooks/index.ts +0 -5
  61. package/src/presentation/hooks/useClickOutside.ts +0 -6
  62. package/src/presentation/hooks/useClipboard.ts +0 -4
  63. package/src/presentation/hooks/useDebounce.ts +0 -8
  64. package/src/presentation/hooks/useKeyboard.ts +0 -6
  65. package/src/presentation/hooks/useLocalStorage.ts +0 -4
  66. package/src/presentation/hooks/useMediaQuery.ts +0 -37
  67. package/src/presentation/hooks/useScrollLock.ts +0 -5
  68. package/src/presentation/hooks/useTheme.ts +9 -13
  69. package/src/presentation/hooks/useToggle.ts +0 -4
  70. package/src/presentation/molecules/ActiveFilterTags.tsx +0 -4
  71. package/src/presentation/molecules/Avatar.tsx +0 -5
  72. package/src/presentation/molecules/BookmarkButton.tsx +0 -15
  73. package/src/presentation/molecules/CheckboxGroup.tsx +0 -4
  74. package/src/presentation/molecules/Chip.tsx +0 -5
  75. package/src/presentation/molecules/CodeBlock.tsx +0 -5
  76. package/src/presentation/molecules/ConfirmButton.tsx +125 -0
  77. package/src/presentation/molecules/Field.tsx +0 -7
  78. package/src/presentation/molecules/FormField.tsx +1 -5
  79. package/src/presentation/molecules/InputGroup.tsx +0 -4
  80. package/src/presentation/molecules/ListItem.tsx +0 -4
  81. package/src/presentation/molecules/OptionTile.tsx +0 -10
  82. package/src/presentation/molecules/PasswordInput.tsx +43 -0
  83. package/src/presentation/molecules/RadioGroup.tsx +0 -4
  84. package/src/presentation/molecules/RatingStars.tsx +0 -8
  85. package/src/presentation/molecules/ScrollArea.tsx +0 -4
  86. package/src/presentation/molecules/SearchBox.tsx +0 -4
  87. package/src/presentation/molecules/SearchInput.tsx +110 -0
  88. package/src/presentation/molecules/Select.tsx +0 -4
  89. package/src/presentation/molecules/StatPill.tsx +0 -5
  90. package/src/presentation/molecules/TagInput.tsx +0 -7
  91. package/src/presentation/molecules/Textarea.tsx +0 -4
  92. package/src/presentation/molecules/Toggle.tsx +0 -4
  93. package/src/presentation/molecules/Toolbar.tsx +36 -0
  94. package/src/presentation/molecules/index.ts +25 -8
  95. package/src/presentation/organisms/Accordion.tsx +0 -4
  96. package/src/presentation/organisms/Alert.tsx +0 -4
  97. package/src/presentation/organisms/AvatarStack.tsx +0 -5
  98. package/src/presentation/organisms/Breadcrumb.tsx +0 -7
  99. package/src/presentation/organisms/Card.tsx +0 -6
  100. package/src/presentation/organisms/Checklist.tsx +0 -4
  101. package/src/presentation/organisms/Collapsible.tsx +0 -4
  102. package/src/presentation/organisms/ConfirmDialog.tsx +0 -8
  103. package/src/presentation/organisms/CoverArt.tsx +0 -9
  104. package/src/presentation/organisms/DataTable.tsx +0 -8
  105. package/src/presentation/organisms/DateRangePicker.tsx +0 -9
  106. package/src/presentation/organisms/DescriptionList.tsx +113 -0
  107. package/src/presentation/organisms/Dialog.tsx +0 -4
  108. package/src/presentation/organisms/Drawer.tsx +0 -6
  109. package/src/presentation/organisms/DropdownMenu.tsx +0 -4
  110. package/src/presentation/organisms/ErrorBoundary.tsx +0 -12
  111. package/src/presentation/organisms/FileUploader.tsx +0 -9
  112. package/src/presentation/organisms/FilterPopover.tsx +0 -8
  113. package/src/presentation/organisms/FormModal.tsx +0 -5
  114. package/src/presentation/organisms/HoverCard.tsx +0 -4
  115. package/src/presentation/organisms/KeyValueList.tsx +0 -4
  116. package/src/presentation/organisms/KpiCard.tsx +0 -6
  117. package/src/presentation/organisms/Lightbox.tsx +0 -7
  118. package/src/presentation/organisms/LoadingState.tsx +0 -4
  119. package/src/presentation/organisms/MapPreview.tsx +0 -9
  120. package/src/presentation/organisms/MetricCard.tsx +1 -5
  121. package/src/presentation/organisms/Modal.tsx +0 -4
  122. package/src/presentation/organisms/PhotoGallery.tsx +0 -9
  123. package/src/presentation/organisms/PlanPicker.tsx +0 -5
  124. package/src/presentation/organisms/Popover.tsx +0 -4
  125. package/src/presentation/organisms/Sheet.tsx +0 -4
  126. package/src/presentation/organisms/StatCard.tsx +0 -5
  127. package/src/presentation/organisms/StatsGrid.tsx +110 -0
  128. package/src/presentation/organisms/StatusBadge.tsx +0 -12
  129. package/src/presentation/organisms/Stepper.tsx +0 -5
  130. package/src/presentation/organisms/Table.tsx +0 -4
  131. package/src/presentation/organisms/Tabs.tsx +0 -7
  132. package/src/presentation/organisms/Timeline.tsx +0 -8
  133. package/src/presentation/organisms/Toaster.tsx +0 -9
  134. package/src/presentation/organisms/ToggleGroup.tsx +0 -4
  135. package/src/presentation/organisms/index.ts +10 -11
  136. package/src/presentation/templates/CrudPageTemplate.tsx +69 -0
  137. package/src/presentation/templates/Form.tsx +0 -4
  138. package/src/presentation/templates/List.tsx +0 -4
  139. package/src/presentation/templates/PageHeader.tsx +0 -4
  140. package/src/presentation/templates/PageLayout.tsx +0 -4
  141. package/src/presentation/templates/ProjectSkeleton.tsx +0 -4
  142. package/src/presentation/templates/ResponsiveContainer.tsx +0 -43
  143. package/src/presentation/templates/Section.tsx +0 -4
  144. package/src/presentation/templates/SettingsLayout.tsx +102 -0
  145. package/src/presentation/templates/index.ts +7 -6
  146. package/src/styles/app.css +0 -18
  147. package/src/styles/bridge.css +0 -34
  148. package/src/styles/compile.css +0 -13
  149. package/src/styles/source.css +0 -12
  150. 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,7 +1,3 @@
1
- /**
2
- * Divider Component (Atom)
3
- * @description Visual separator line
4
- */
5
1
 
6
2
  import { forwardRef, type HTMLAttributes } from 'react';
7
3
  import { cn } from '../../infrastructure/utils';
@@ -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
- * Icon Component (Atom)
3
- * @description Wrapper for SVG icons
4
- */
5
1
 
6
2
  import { forwardRef, type SVGAttributes } from 'react';
7
3
  import { cn } from '../../infrastructure/utils';
@@ -1,7 +1,3 @@
1
- /**
2
- * IconButton Component (Atom)
3
- * @description Round button optimized for icon-only usage with consistent sizing
4
- */
5
1
 
6
2
  import { forwardRef, type ButtonHTMLAttributes, type ReactNode } from 'react';
7
3
  import { cn } from '../../infrastructure/utils';
@@ -1,7 +1,3 @@
1
- /**
2
- * Input Component (Atom)
3
- * @description Text input field with optional label and helper text
4
- */
5
1
 
6
2
  import { forwardRef, useId, type InputHTMLAttributes, type ReactNode } from 'react';
7
3
  import { cn } from '../../infrastructure/utils';
@@ -1,7 +1,3 @@
1
- /**
2
- * Kbd Component (Atom)
3
- * @description Keyboard key cap, e.g. for shortcut hints
4
- */
5
1
 
6
2
  import { forwardRef, type HTMLAttributes } from 'react';
7
3
  import { cn } from '../../infrastructure/utils';
@@ -1,7 +1,3 @@
1
- /**
2
- * Label Component (Atom)
3
- * @description Form label (Shadcn/ui compatible)
4
- */
5
1
 
6
2
  import * as React from 'react';
7
3
  import * as LabelPrimitive from '@radix-ui/react-label';
@@ -1,7 +1,3 @@
1
- /**
2
- * Link Component (Atom)
3
- * @description Styled anchor/link element
4
- */
5
1
 
6
2
  import { forwardRef, type AnchorHTMLAttributes } from 'react';
7
3
  import { cn } from '../../infrastructure/utils';
@@ -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
- * Radio Component (Atom)
3
- * @description Radio input element
4
- */
5
1
 
6
2
  import { forwardRef, type InputHTMLAttributes } from 'react';
7
3
  import { cn } from '../../infrastructure/utils';
@@ -1,7 +1,3 @@
1
- /**
2
- * Separator Component (Atom) - Shadcn/ui format
3
- * @description Visual separator/divider component
4
- */
5
1
 
6
2
  import * as React from 'react';
7
3
  import * as SeparatorPrimitive from '@radix-ui/react-separator';
@@ -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) {
@@ -1,7 +1,3 @@
1
- /**
2
- * Skeleton Component (Atom)
3
- * @description Loading placeholder
4
- */
5
1
 
6
2
  import { forwardRef, type HTMLAttributes } from 'react';
7
3
  import { cn } from '../../infrastructure/utils';
@@ -1,7 +1,3 @@
1
- /**
2
- * Slider Component (Atom)
3
- * @description Range slider input
4
- */
5
1
 
6
2
  import { forwardRef, type InputHTMLAttributes } from 'react';
7
3
  import { cn } from '../../infrastructure/utils';
@@ -1,7 +1,3 @@
1
- /**
2
- * Sparkline Component (Atom)
3
- * @description Minimal inline line chart for compact trends
4
- */
5
1
 
6
2
  import { forwardRef, type SVGAttributes } from 'react';
7
3
  import { cn } from '../../infrastructure/utils';
@@ -1,7 +1,3 @@
1
- /**
2
- * Spinner Component (Atom)
3
- * @description Loading indicator
4
- */
5
1
 
6
2
  import { forwardRef, type HTMLAttributes } from 'react';
7
3
  import { cn } from '../../infrastructure/utils';
@@ -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,7 +1,3 @@
1
- /**
2
- * Switch Component (Atom) - Shadcn/ui format
3
- * @description Toggle switch component using class-variance-authority
4
- */
5
1
 
6
2
  import * as React from 'react';
7
3
  import * as SwitchPrimitives from '@radix-ui/react-switch';
@@ -1,7 +1,3 @@
1
- /**
2
- * Text Component (Atom)
3
- * @description Styled text element with polymorphic rendering
4
- */
5
1
 
6
2
  import { forwardRef, memo, type ElementType, type ComponentPropsWithoutRef } from 'react';
7
3
  import { cn } from '../../infrastructure/utils';
@@ -1,7 +1,3 @@
1
- /**
2
- * Textarea Component (Atom)
3
- * @description Multiline text field with optional label and helper text
4
- */
5
1
 
6
2
  import { forwardRef, useId, type ReactNode, type TextareaHTMLAttributes } from 'react';
7
3
  import { cn } from '../../infrastructure/utils';
@@ -1,7 +1,3 @@
1
- /**
2
- * Toggle Component (Atom) - Shadcn/ui format
3
- * @description Toggle button component with variants
4
- */
5
1
 
6
2
  import * as React from 'react';
7
3
  import * as TogglePrimitive from '@radix-ui/react-toggle';
@@ -1,7 +1,3 @@
1
- /**
2
- * Tooltip Component (Atom)
3
- * @description Popup with additional information
4
- */
5
1
 
6
2
  import { forwardRef, type HTMLAttributes, type ReactNode, useState, useRef, useEffect } from 'react';
7
3
  import { cn } from '../../infrastructure/utils';
@@ -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,8 +1,3 @@
1
- /**
2
- * Presentation Hooks Export
3
- * @description React hooks
4
- * Subpath: @umituz/web-design-system/hooks
5
- */
6
1
 
7
2
  export { useTheme } from './useTheme';
8
3
  export type { Theme, UseThemeReturn } from './useTheme';
@@ -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
- * useClipboard Hook
3
- * @description Clipboard operations with proper cleanup
4
- */
5
1
 
6
2
  import { useState, useCallback, useEffect, useRef } from 'react';
7
3
  import { TIMING } from '../../infrastructure/constants/timing.constants';
@@ -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);
@@ -1,7 +1,3 @@
1
- /**
2
- * useLocalStorage Hook
3
- * @description LocalStorage state management with safe error surfacing
4
- */
5
1
 
6
2
  import { useCallback, useEffect, useState, useRef } from 'react';
7
3