@exxatdesignux/ui 0.0.5

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 (59) hide show
  1. package/package.json +72 -0
  2. package/src/components/ui/avatar.tsx +384 -0
  3. package/src/components/ui/badge.tsx +49 -0
  4. package/src/components/ui/banner.tsx +364 -0
  5. package/src/components/ui/breadcrumb.tsx +120 -0
  6. package/src/components/ui/button.tsx +66 -0
  7. package/src/components/ui/calendar.tsx +220 -0
  8. package/src/components/ui/card.tsx +136 -0
  9. package/src/components/ui/chart.tsx +378 -0
  10. package/src/components/ui/checkbox.tsx +160 -0
  11. package/src/components/ui/coach-mark.tsx +361 -0
  12. package/src/components/ui/collapsible.tsx +33 -0
  13. package/src/components/ui/command.tsx +232 -0
  14. package/src/components/ui/date-picker-field.tsx +186 -0
  15. package/src/components/ui/dialog.tsx +171 -0
  16. package/src/components/ui/drag-handle-grip.tsx +10 -0
  17. package/src/components/ui/drawer.tsx +134 -0
  18. package/src/components/ui/dropdown-menu.tsx +422 -0
  19. package/src/components/ui/field.tsx +238 -0
  20. package/src/components/ui/form.tsx +137 -0
  21. package/src/components/ui/input-group.tsx +156 -0
  22. package/src/components/ui/input-mask.tsx +135 -0
  23. package/src/components/ui/input.tsx +22 -0
  24. package/src/components/ui/kbd.tsx +55 -0
  25. package/src/components/ui/label.tsx +25 -0
  26. package/src/components/ui/payment-card-fields.tsx +65 -0
  27. package/src/components/ui/popover.tsx +46 -0
  28. package/src/components/ui/radio-group.tsx +217 -0
  29. package/src/components/ui/select.tsx +191 -0
  30. package/src/components/ui/selection-tile-grid.tsx +246 -0
  31. package/src/components/ui/separator.tsx +28 -0
  32. package/src/components/ui/sheet.tsx +147 -0
  33. package/src/components/ui/sidebar.tsx +716 -0
  34. package/src/components/ui/skeleton.tsx +13 -0
  35. package/src/components/ui/sonner.tsx +39 -0
  36. package/src/components/ui/status-badge.tsx +109 -0
  37. package/src/components/ui/table.tsx +117 -0
  38. package/src/components/ui/tabs.tsx +90 -0
  39. package/src/components/ui/textarea.tsx +18 -0
  40. package/src/components/ui/tip.tsx +21 -0
  41. package/src/components/ui/toggle-group.tsx +89 -0
  42. package/src/components/ui/toggle-switch.tsx +31 -0
  43. package/src/components/ui/toggle.tsx +48 -0
  44. package/src/components/ui/tooltip.tsx +59 -0
  45. package/src/components/ui/view-segmented-control.tsx +160 -0
  46. package/src/globals.css +1795 -0
  47. package/src/hooks/.gitkeep +0 -0
  48. package/src/hooks/use-app-theme.ts +172 -0
  49. package/src/hooks/use-coach-mark.ts +342 -0
  50. package/src/hooks/use-mobile.ts +31 -0
  51. package/src/hooks/use-mod-key-label.ts +29 -0
  52. package/src/index.ts +55 -0
  53. package/src/lib/compose-refs.ts +15 -0
  54. package/src/lib/date-filter.ts +67 -0
  55. package/src/lib/utils.ts +6 -0
  56. package/src/theme/apply-windows-contrast-theme.ts +29 -0
  57. package/src/theme/windows-contrast-theme.json +147 -0
  58. package/src/theme.css +1130 -0
  59. package/src/types/react-payment-inputs.d.ts +20 -0
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Format any date string (ISO, MM/DD/YYYY, "Mar 15 2026", etc.) into the
3
+ * app-wide display format: MM/DD/YYYY.
4
+ * Returns "—" for empty / unparseable values.
5
+ */
6
+ export function formatDateUS(raw: string | null | undefined): string {
7
+ if (!raw || raw.trim() === "—" || raw.trim() === "-") return "—"
8
+ // Already MM/DD/YYYY — return as-is
9
+ if (/^\d{2}\/\d{2}\/\d{4}$/.test(raw.trim())) return raw.trim()
10
+ const d = new Date(raw)
11
+ if (Number.isNaN(d.getTime())) return raw
12
+ const m = String(d.getMonth() + 1).padStart(2, "0")
13
+ const day = String(d.getDate()).padStart(2, "0")
14
+ const y = d.getFullYear()
15
+ return `${m}/${day}/${y}`
16
+ }
17
+
18
+ /**
19
+ * Format a Date (or ISO string) into "MM/DD/YYYY hh:mm AM/PM EST".
20
+ * Time zone label is always appended as the literal string "EST" (display only).
21
+ */
22
+ export function formatDateTimeUS(raw: Date | string | null | undefined): string {
23
+ if (!raw) return "—"
24
+ const d = raw instanceof Date ? raw : new Date(raw)
25
+ if (Number.isNaN(d.getTime())) return String(raw)
26
+ const m = String(d.getMonth() + 1).padStart(2, "0")
27
+ const day = String(d.getDate()).padStart(2, "0")
28
+ const y = d.getFullYear()
29
+ let h = d.getHours()
30
+ const min = String(d.getMinutes()).padStart(2, "0")
31
+ const ampm = h >= 12 ? "PM" : "AM"
32
+ h = h % 12 || 12
33
+ return `${m}/${day}/${y} ${String(h).padStart(2, "0")}:${min} ${ampm} EST`
34
+ }
35
+
36
+ /** Parse a human-readable date string into YYYY-MM-DD for comparison (local timezone). */
37
+ export function parseRowDateToYmd(raw: string): string | null {
38
+ const t = raw.trim()
39
+ if (!t || t === "—" || t === "-") return null
40
+ const d = new Date(t)
41
+ if (Number.isNaN(d.getTime())) return null
42
+ const y = d.getFullYear()
43
+ const m = String(d.getMonth() + 1).padStart(2, "0")
44
+ const day = String(d.getDate()).padStart(2, "0")
45
+ return `${y}-${m}-${day}`
46
+ }
47
+
48
+ /** Format YYYY-MM-DD for compact filter chip label. */
49
+ export function formatYmdForDisplay(ymd: string): string {
50
+ const d = new Date(`${ymd}T12:00:00`)
51
+ if (Number.isNaN(d.getTime())) return ymd
52
+ return d.toLocaleDateString(undefined, { month: "short", day: "numeric", year: "numeric" })
53
+ }
54
+
55
+ /** Local noon to avoid timezone shifting the calendar day. */
56
+ export function ymdToLocalDate(ymd: string | undefined): Date | undefined {
57
+ if (!ymd || !/^\d{4}-\d{2}-\d{2}$/.test(ymd)) return undefined
58
+ const [y, m, d] = ymd.split("-").map(Number)
59
+ return new Date(y, m - 1, d, 12, 0, 0, 0)
60
+ }
61
+
62
+ export function localDateToYmd(d: Date): string {
63
+ const y = d.getFullYear()
64
+ const m = String(d.getMonth() + 1).padStart(2, "0")
65
+ const day = String(d.getDate()).padStart(2, "0")
66
+ return `${y}-${m}-${day}`
67
+ }
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
@@ -0,0 +1,29 @@
1
+ import windowsContrastTheme from "./windows-contrast-theme.json"
2
+
3
+ type WindowsContrastFile = {
4
+ light: Record<string, string>
5
+ dark: Record<string, string>
6
+ }
7
+
8
+ const file = windowsContrastTheme as WindowsContrastFile
9
+
10
+ const WINDOWS_VAR_KEYS = new Set([
11
+ ...Object.keys(file.light),
12
+ ...Object.keys(file.dark),
13
+ ])
14
+
15
+ export function applyWindowsContrastTheme() {
16
+ const el = document.documentElement
17
+ const isDark = el.classList.contains("dark")
18
+ const map = isDark ? file.dark : file.light
19
+ for (const [prop, val] of Object.entries(map)) {
20
+ el.style.setProperty(prop, val)
21
+ }
22
+ }
23
+
24
+ export function clearWindowsContrastTheme() {
25
+ const el = document.documentElement
26
+ for (const key of WINDOWS_VAR_KEYS) {
27
+ el.style.removeProperty(key)
28
+ }
29
+ }
@@ -0,0 +1,147 @@
1
+ {
2
+ "$comment": "In-app “Windows (JSON)” contrast mode. Edit hex or oklch() strings to match a Windows Contrast theme (Settings → Accessibility → Contrast themes) or an exported .theme file. Keys are Exxat semantic CSS variables on <html>. Light/dark follow the app’s light/dark mode (next-themes).",
3
+ "windowsSettingsLabels": {
4
+ "Background": "Canvas — maps to --background, surfaces, sidebar base",
5
+ "Text": "Text — maps to --foreground and readable copy tokens",
6
+ "Hyperlink": "Hyperlinks — mapped to --primary / focus via --ring where useful",
7
+ "Selected text": "Selected text — maps to --accent and --accent-foreground",
8
+ "Button text": "Button text — maps to --primary / --primary-foreground pair",
9
+ "Disabled text": "Disabled text — maps to --muted / --muted-foreground"
10
+ },
11
+ "light": {
12
+ "--hc-highlight": "#0000ff",
13
+ "--hc-highlight-text": "#ffffff",
14
+ "--background": "#ffffff",
15
+ "--foreground": "#000000",
16
+ "--card": "#ffffff",
17
+ "--card-foreground": "#000000",
18
+ "--popover": "#ffffff",
19
+ "--popover-foreground": "#000000",
20
+ "--primary": "#0000ff",
21
+ "--primary-foreground": "#ffffff",
22
+ "--secondary": "#ffffff",
23
+ "--secondary-foreground": "#000000",
24
+ "--muted": "#e8e8e8",
25
+ "--muted-foreground": "#3b3b3b",
26
+ "--accent": "#0000ff",
27
+ "--accent-foreground": "#ffffff",
28
+ "--destructive": "#b5200d",
29
+ "--destructive-foreground": "#ffffff",
30
+ "--border": "#000000",
31
+ "--border-control": "#000000",
32
+ "--border-control-3": "#000000",
33
+ "--border-control-35": "#000000",
34
+ "--control-border": "#000000",
35
+ "--input": "#000000",
36
+ "--input-background": "#ffffff",
37
+ "--ring": "#0000ff",
38
+ "--sidebar": "#ffffff",
39
+ "--sidebar-foreground": "#000000",
40
+ "--sidebar-primary": "#000000",
41
+ "--sidebar-primary-foreground": "#ffffff",
42
+ "--sidebar-accent": "#d9d9d9",
43
+ "--sidebar-accent-foreground": "#000000",
44
+ "--sidebar-border": "#000000",
45
+ "--sidebar-ring": "#0000ff",
46
+ "--sidebar-section-label-foreground": "#515151",
47
+ "--brand-tint": "#f0f0f0",
48
+ "--brand-tint-light": "#f7f7f7",
49
+ "--brand-tint-subtle": "#fafafa",
50
+ "--chart-1": "#000000",
51
+ "--chart-2": "#3b3b3b",
52
+ "--chart-3": "#6e6e6e",
53
+ "--chart-4": "#a0a0a0",
54
+ "--chart-5": "#d1d1d1",
55
+ "--chip-1": "#000000",
56
+ "--chip-2": "#000000",
57
+ "--chip-3": "#000000",
58
+ "--chip-4": "#000000",
59
+ "--chip-5": "#000000",
60
+ "--chip-destructive": "#b5200d",
61
+ "--interactive-hover": "#e0e0e0",
62
+ "--interactive-hover-foreground": "#000000",
63
+ "--interactive-hover-subtle": "#ebebeb",
64
+ "--interactive-hover-soft": "#ebebeb",
65
+ "--interactive-hover-medium": "#d5d5d5",
66
+ "--interactive-hover-strong": "#cccccc",
67
+ "--interactive-hover-row": "#e0e0e0",
68
+ "--overlay": "color-mix(in srgb, #000000 18%, transparent)",
69
+ "--dt-row-bg": "#ffffff",
70
+ "--dt-row-hover": "#ebebeb",
71
+ "--dt-row-selected": "#0000ff",
72
+ "--dt-row-selected-fg": "#ffffff",
73
+ "--dt-header-bg": "#ffffff",
74
+ "--dt-group-bg": "#ebebeb",
75
+ "--dt-new-row-bg": "#ffffff",
76
+ "--dt-new-row-border": "#000000",
77
+ "--theme-color-chrome": "#ffffff"
78
+ },
79
+ "dark": {
80
+ "--hc-highlight": "#ffff00",
81
+ "--hc-highlight-text": "#000000",
82
+ "--background": "#000000",
83
+ "--foreground": "#ffffff",
84
+ "--card": "#000000",
85
+ "--card-foreground": "#ffffff",
86
+ "--popover": "#0a0a0a",
87
+ "--popover-foreground": "#ffffff",
88
+ "--primary": "#00ffff",
89
+ "--primary-foreground": "#000000",
90
+ "--secondary": "#000000",
91
+ "--secondary-foreground": "#ffffff",
92
+ "--muted": "#1a1a1a",
93
+ "--muted-foreground": "#ffffff",
94
+ "--accent": "#ffff00",
95
+ "--accent-foreground": "#000000",
96
+ "--destructive": "#ff8080",
97
+ "--destructive-foreground": "#000000",
98
+ "--border": "#ffffff",
99
+ "--border-control": "#ffffff",
100
+ "--border-control-3": "#ffffff",
101
+ "--border-control-35": "#ffffff",
102
+ "--control-border": "#ffffff",
103
+ "--input": "#ffffff",
104
+ "--input-background": "#000000",
105
+ "--ring": "#ffff00",
106
+ "--sidebar": "#000000",
107
+ "--sidebar-foreground": "#ffffff",
108
+ "--sidebar-primary": "#ffffff",
109
+ "--sidebar-primary-foreground": "#000000",
110
+ "--sidebar-accent": "#1a1a1a",
111
+ "--sidebar-accent-foreground": "#ffffff",
112
+ "--sidebar-border": "#ffffff",
113
+ "--sidebar-ring": "#ffff00",
114
+ "--sidebar-section-label-foreground": "#c8c8c8",
115
+ "--brand-tint": "#1a1a1a",
116
+ "--brand-tint-light": "#141414",
117
+ "--brand-tint-subtle": "#101010",
118
+ "--chart-1": "#ffffff",
119
+ "--chart-2": "#c8c8c8",
120
+ "--chart-3": "#8e8e8e",
121
+ "--chart-4": "#5a5a5a",
122
+ "--chart-5": "#2e2e2e",
123
+ "--chip-1": "#ffffff",
124
+ "--chip-2": "#ffffff",
125
+ "--chip-3": "#ffffff",
126
+ "--chip-4": "#ffffff",
127
+ "--chip-5": "#ffffff",
128
+ "--chip-destructive": "#ff8080",
129
+ "--interactive-hover": "#262626",
130
+ "--interactive-hover-foreground": "#ffffff",
131
+ "--interactive-hover-subtle": "#1f1f1f",
132
+ "--interactive-hover-soft": "#1f1f1f",
133
+ "--interactive-hover-medium": "#2e2e2e",
134
+ "--interactive-hover-strong": "#383838",
135
+ "--interactive-hover-row": "#262626",
136
+ "--overlay": "color-mix(in srgb, #ffffff 22%, transparent)",
137
+ "--dt-row-bg": "#000000",
138
+ "--dt-row-hover": "#1a1a1a",
139
+ "--dt-row-selected": "#ffff00",
140
+ "--dt-row-selected-fg": "#000000",
141
+ "--dt-header-bg": "#000000",
142
+ "--dt-group-bg": "#1a1a1a",
143
+ "--dt-new-row-bg": "#000000",
144
+ "--dt-new-row-border": "#ffffff",
145
+ "--theme-color-chrome": "#000000"
146
+ }
147
+ }