@carbonid1/design-system 5.0.3 → 5.2.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 (64) hide show
  1. package/dist/Badge/Badge.d.ts +6 -0
  2. package/dist/Badge/Badge.js +23 -0
  3. package/{src/Badge/Badge.types.ts → dist/Badge/Badge.types.d.ts} +8 -11
  4. package/dist/Badge/Badge.types.js +1 -0
  5. package/dist/Button/Button.d.ts +7 -0
  6. package/dist/Button/Button.js +34 -0
  7. package/dist/Button/Button.types.d.ts +8 -0
  8. package/dist/Button/Button.types.js +1 -0
  9. package/dist/ContextMenu/ContextMenu.d.ts +56 -0
  10. package/dist/ContextMenu/ContextMenu.js +40 -0
  11. package/dist/Kbd/Kbd.d.ts +6 -0
  12. package/dist/Kbd/Kbd.js +38 -0
  13. package/dist/Kbd/Kbd.types.d.ts +8 -0
  14. package/dist/Kbd/Kbd.types.js +1 -0
  15. package/dist/ProgressRing/ProgressRing.consts.d.ts +4 -0
  16. package/dist/ProgressRing/ProgressRing.consts.js +4 -0
  17. package/dist/ProgressRing/ProgressRing.d.ts +10 -0
  18. package/dist/ProgressRing/ProgressRing.js +12 -0
  19. package/dist/Select/Select.d.ts +2 -0
  20. package/dist/Select/Select.js +85 -0
  21. package/dist/Select/Select.types.d.ts +26 -0
  22. package/dist/Select/Select.types.js +1 -0
  23. package/dist/Slider/Slider.d.ts +13 -0
  24. package/dist/Slider/Slider.js +5 -0
  25. package/dist/ThemeCycler/ThemeCycler.d.ts +1 -0
  26. package/dist/ThemeCycler/ThemeCycler.js +30 -0
  27. package/dist/ThemeProvider/ThemeProvider.d.ts +5 -0
  28. package/dist/ThemeProvider/ThemeProvider.js +4 -0
  29. package/dist/Toaster/Toaster.d.ts +2 -0
  30. package/dist/Toaster/Toaster.js +4 -0
  31. package/dist/Tooltip/Tooltip.d.ts +15 -0
  32. package/dist/Tooltip/Tooltip.js +59 -0
  33. package/dist/helpers/cn/cn.d.ts +2 -0
  34. package/dist/helpers/cn/cn.js +5 -0
  35. package/dist/helpers/getModKey/getModKey.d.ts +1 -0
  36. package/dist/helpers/getModKey/getModKey.js +1 -0
  37. package/dist/index.d.ts +21 -0
  38. package/dist/index.js +16 -0
  39. package/package.json +17 -35
  40. package/skills/design-system/SKILL.md +17 -0
  41. package/skills/design-system/references/theming.md +53 -14
  42. package/themes/dashboard.css +22 -4
  43. package/themes/reader.css +51 -6
  44. package/src/Badge/Badge.tsx +0 -53
  45. package/src/Button/Button.tsx +0 -67
  46. package/src/Button/Button.types.ts +0 -11
  47. package/src/ContextMenu/ContextMenu.tsx +0 -159
  48. package/src/Kbd/Kbd.tsx +0 -56
  49. package/src/Kbd/Kbd.types.ts +0 -10
  50. package/src/ProgressRing/ProgressRing.consts.ts +0 -4
  51. package/src/ProgressRing/ProgressRing.tsx +0 -68
  52. package/src/Select/Select.test.tsx +0 -129
  53. package/src/Select/Select.tsx +0 -156
  54. package/src/Select/Select.types.ts +0 -30
  55. package/src/Slider/Slider.test.tsx +0 -29
  56. package/src/Slider/Slider.tsx +0 -53
  57. package/src/ThemeCycler/ThemeCycler.tsx +0 -37
  58. package/src/ThemeProvider/ThemeProvider.tsx +0 -18
  59. package/src/Toaster/Toaster.tsx +0 -7
  60. package/src/Tooltip/Tooltip.tsx +0 -107
  61. package/src/helpers/cn/cn.ts +0 -6
  62. package/src/helpers/getModKey/getModKey.test.ts +0 -23
  63. package/src/helpers/getModKey/getModKey.ts +0 -2
  64. package/src/index.ts +0 -36
@@ -1,53 +0,0 @@
1
- 'use client'
2
-
3
- import { cn } from '../helpers/cn/cn'
4
- import { Slider as SliderPrimitive } from '@base-ui/react/slider'
5
-
6
- type SliderProps = {
7
- value: number
8
- onChange: (value: number) => void
9
- onCommit?: (value: number) => void
10
- min: number
11
- max: number
12
- step?: number
13
- disabled?: boolean
14
- 'aria-label'?: string
15
- className?: string
16
- }
17
-
18
- export const Slider = ({
19
- value,
20
- onChange,
21
- onCommit,
22
- min,
23
- max,
24
- step = 1,
25
- disabled,
26
- 'aria-label': ariaLabel,
27
- className,
28
- }: SliderProps) => (
29
- <SliderPrimitive.Root
30
- value={value}
31
- onValueChange={v => onChange(v as number)}
32
- onValueCommitted={v => onCommit?.(v as number)}
33
- min={min}
34
- max={max}
35
- step={step}
36
- disabled={disabled}
37
- aria-label={ariaLabel}
38
- className={cn('relative flex w-full touch-none items-center py-2', className)}
39
- >
40
- <SliderPrimitive.Control className="relative flex h-1.5 w-full items-center">
41
- <SliderPrimitive.Track className="bg-input h-full w-full overflow-hidden rounded-full">
42
- <SliderPrimitive.Indicator className="bg-primary h-full rounded-full" />
43
- </SliderPrimitive.Track>
44
- <SliderPrimitive.Thumb
45
- className={cn(
46
- 'bg-primary border-background block size-4 rounded-full border-2 shadow-sm',
47
- 'focus-visible:ring-ring/50 focus-visible:ring-3 focus-visible:outline-hidden',
48
- disabled && 'pointer-events-none opacity-50',
49
- )}
50
- />
51
- </SliderPrimitive.Control>
52
- </SliderPrimitive.Root>
53
- )
@@ -1,37 +0,0 @@
1
- 'use client'
2
-
3
- import { useTheme } from 'next-themes'
4
- import { useCallback, useSyncExternalStore } from 'react'
5
- import { useHotkeys } from 'react-hotkeys-hook'
6
- import { toast } from 'sonner'
7
-
8
- const THEME_CYCLE = ['system', 'light', 'dark'] as const
9
-
10
- const THEME_LABELS: Record<string, string> = {
11
- system: 'System',
12
- light: 'Light',
13
- dark: 'Dark',
14
- }
15
-
16
- const emptySubscribe = () => () => {}
17
- const getSnapshot = () => true
18
- const getServerSnapshot = () => false
19
-
20
- export const ThemeCycler = () => {
21
- const { theme, setTheme } = useTheme()
22
- const mounted = useSyncExternalStore(emptySubscribe, getSnapshot, getServerSnapshot)
23
-
24
- const cycleTheme = useCallback(() => {
25
- if (!mounted) return
26
- const current = theme ?? 'system'
27
- const currentIndex = THEME_CYCLE.indexOf(current as (typeof THEME_CYCLE)[number])
28
- const nextIndex = (currentIndex + 1) % THEME_CYCLE.length
29
- const next = THEME_CYCLE[nextIndex] ?? 'system'
30
- setTheme(next)
31
- toast(`Theme: ${THEME_LABELS[next]}`, { duration: 2000 })
32
- }, [theme, setTheme, mounted])
33
-
34
- useHotkeys('shift+t', cycleTheme, { preventDefault: true })
35
-
36
- return null
37
- }
@@ -1,18 +0,0 @@
1
- 'use client'
2
-
3
- import { ThemeProvider as NextThemesProvider } from 'next-themes'
4
-
5
- type Props = {
6
- children: React.ReactNode
7
- }
8
-
9
- export const ThemeProvider = ({ children }: Props) => (
10
- <NextThemesProvider
11
- attribute="class"
12
- defaultTheme="system"
13
- enableSystem
14
- disableTransitionOnChange
15
- >
16
- {children}
17
- </NextThemesProvider>
18
- )
@@ -1,7 +0,0 @@
1
- 'use client'
2
-
3
- import { Toaster as Sonner, type ToasterProps } from 'sonner'
4
-
5
- export const Toaster = (props: ToasterProps) => (
6
- <Sonner theme="system" className="toaster group" position="bottom-right" {...props} />
7
- )
@@ -1,107 +0,0 @@
1
- 'use client'
2
-
3
- import { Kbd } from '../Kbd/Kbd'
4
- import { type ReactElement, cloneElement, useCallback, useEffect, useRef, useState } from 'react'
5
-
6
- type TooltipProps = {
7
- label: string
8
- shortcut?: string | string[]
9
- position?: 'top' | 'bottom'
10
- delay?: number
11
- maxWidth?: number
12
- disabled?: boolean
13
- className?: string
14
- children: ReactElement<{ 'aria-label'?: string }>
15
- }
16
-
17
- const DEFAULT_DELAY = 200
18
-
19
- export const Tooltip = ({
20
- label,
21
- shortcut,
22
- position = 'top',
23
- delay = DEFAULT_DELAY,
24
- maxWidth,
25
- disabled,
26
- className,
27
- children,
28
- }: TooltipProps) => {
29
- const [visible, setVisible] = useState(false)
30
- const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
31
- const wrapperRef = useRef<HTMLDivElement>(null)
32
-
33
- const show = useCallback(() => {
34
- if (disabled) return
35
- timeoutRef.current = setTimeout(() => setVisible(true), delay)
36
- }, [disabled, delay])
37
-
38
- const hide = useCallback(() => {
39
- if (timeoutRef.current) {
40
- clearTimeout(timeoutRef.current)
41
- timeoutRef.current = null
42
- }
43
- setVisible(false)
44
- }, [])
45
-
46
- useEffect(() => {
47
- if (disabled && timeoutRef.current) {
48
- clearTimeout(timeoutRef.current)
49
- timeoutRef.current = null
50
- }
51
- }, [disabled])
52
-
53
- useEffect(() => {
54
- return () => {
55
- if (timeoutRef.current) clearTimeout(timeoutRef.current)
56
- }
57
- }, [])
58
-
59
- useEffect(() => {
60
- if (!visible) return
61
- let lastCheck = 0
62
- const handlePointerMove = (e: PointerEvent) => {
63
- if (e.timeStamp - lastCheck < 100) return
64
- lastCheck = e.timeStamp
65
- const rect = wrapperRef.current?.getBoundingClientRect()
66
- if (!rect) return
67
- const inside =
68
- e.clientX >= rect.left &&
69
- e.clientX <= rect.right &&
70
- e.clientY >= rect.top &&
71
- e.clientY <= rect.bottom
72
- if (!inside) hide()
73
- }
74
- document.addEventListener('pointermove', handlePointerMove, { passive: true })
75
- return () => document.removeEventListener('pointermove', handlePointerMove)
76
- }, [visible, hide])
77
-
78
- const positionClasses = position === 'top' ? 'bottom-full mb-2' : 'top-full mt-2'
79
-
80
- return (
81
- <div
82
- ref={wrapperRef}
83
- className={`relative inline-flex${className ? ` ${className}` : ''}`}
84
- onMouseEnter={show}
85
- onMouseLeave={hide}
86
- onPointerDown={hide}
87
- onFocus={show}
88
- onBlur={hide}
89
- >
90
- {cloneElement(children, {
91
- 'aria-label': children.props['aria-label'] ?? label,
92
- })}
93
- {visible && !disabled && (
94
- <div
95
- role="tooltip"
96
- style={maxWidth ? { maxWidth } : undefined}
97
- className={`absolute left-1/2 z-50 -translate-x-1/2 ${maxWidth ? 'w-max whitespace-normal' : 'whitespace-nowrap'} bg-foreground text-background pointer-events-none flex items-center gap-1.5 rounded-lg px-2.5 py-1.5 text-xs shadow-lg ${positionClasses}`}
98
- >
99
- {label}
100
- {shortcut && (
101
- <Kbd keys={shortcut} size="sm" className="bg-background/15 border-transparent" />
102
- )}
103
- </div>
104
- )}
105
- </div>
106
- )
107
- }
@@ -1,6 +0,0 @@
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
- }
@@ -1,23 +0,0 @@
1
- import { afterEach, describe, expect, it, vi } from 'vitest'
2
- import { getModKey } from './getModKey'
3
-
4
- describe('getModKey', () => {
5
- afterEach(() => {
6
- vi.unstubAllGlobals()
7
- })
8
-
9
- it('returns "Cmd" on Mac', () => {
10
- vi.stubGlobal('navigator', { userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)' })
11
- expect(getModKey()).toBe('Cmd')
12
- })
13
-
14
- it('returns "Ctrl" on Windows', () => {
15
- vi.stubGlobal('navigator', { userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)' })
16
- expect(getModKey()).toBe('Ctrl')
17
- })
18
-
19
- it('returns "Ctrl" when navigator is undefined', () => {
20
- vi.stubGlobal('navigator', undefined)
21
- expect(getModKey()).toBe('Ctrl')
22
- })
23
- })
@@ -1,2 +0,0 @@
1
- export const getModKey = (): string =>
2
- typeof navigator !== 'undefined' && /Mac|iPhone|iPad/.test(navigator.userAgent) ? 'Cmd' : 'Ctrl'
package/src/index.ts DELETED
@@ -1,36 +0,0 @@
1
- export { Badge, badgeVariants } from './Badge/Badge'
2
- export type { BadgeProps } from './Badge/Badge.types'
3
-
4
- export { Button, buttonVariants } from './Button/Button'
5
- export type { ButtonProps } from './Button/Button.types'
6
-
7
- export { Kbd, kbdVariants } from './Kbd/Kbd'
8
- export type { KbdProps } from './Kbd/Kbd.types'
9
-
10
- export { ProgressRing } from './ProgressRing/ProgressRing'
11
-
12
- export { Slider } from './Slider/Slider'
13
-
14
- export { ContextMenu } from './ContextMenu/ContextMenu'
15
-
16
- export { Select } from './Select/Select'
17
- export type {
18
- SelectOption,
19
- SelectGroup,
20
- SelectOptionState,
21
- SelectProps,
22
- } from './Select/Select.types'
23
-
24
- export { Tooltip } from './Tooltip/Tooltip'
25
-
26
- export { ThemeProvider } from './ThemeProvider/ThemeProvider'
27
-
28
- export { ThemeCycler } from './ThemeCycler/ThemeCycler'
29
-
30
- export { Toaster } from './Toaster/Toaster'
31
- export { toast } from 'sonner'
32
-
33
- export { useTheme } from 'next-themes'
34
-
35
- export { cn } from './helpers/cn/cn'
36
- export { getModKey } from './helpers/getModKey/getModKey'