@xjur-ui/react 2.1.1 → 2.2.1

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 (147) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/{chunk-DT44JTXB.js → chunk-4M3WR2KJ.js} +2 -2
  3. package/dist/{chunk-DT44JTXB.js.map → chunk-4M3WR2KJ.js.map} +1 -1
  4. package/dist/{chunk-7HG6Y3VV.js → chunk-BYXTOSM6.js} +2 -2
  5. package/dist/{chunk-7HG6Y3VV.js.map → chunk-BYXTOSM6.js.map} +1 -1
  6. package/dist/{chunk-4PTFZTVU.js → chunk-HLWHETF5.js} +2 -2
  7. package/dist/{chunk-4PTFZTVU.js.map → chunk-HLWHETF5.js.map} +1 -1
  8. package/dist/{chunk-ASZAHSU5.js → chunk-SLMHDBWO.js} +2 -2
  9. package/dist/{chunk-ASZAHSU5.js.map → chunk-SLMHDBWO.js.map} +1 -1
  10. package/dist/{chunk-MQ7YTZBI.js → chunk-TTKENFBF.js} +2 -2
  11. package/dist/{chunk-MQ7YTZBI.js.map → chunk-TTKENFBF.js.map} +1 -1
  12. package/dist/components/accordion.d.ts +54 -0
  13. package/dist/components/accordion.js +2 -0
  14. package/dist/components/accordion.js.map +1 -0
  15. package/dist/components/badge.d.ts +1 -1
  16. package/dist/components/controls/rating.d.ts +137 -0
  17. package/dist/components/controls/rating.js +2 -0
  18. package/dist/components/controls/rating.js.map +1 -0
  19. package/dist/components/controls/rich-editor.js +1 -1
  20. package/dist/components/controls/slider.d.ts +172 -0
  21. package/dist/components/controls/slider.js +2 -0
  22. package/dist/components/controls/slider.js.map +1 -0
  23. package/dist/components/custom/pessoa/index.js +1 -1
  24. package/dist/components/drag-and-drop/index.js +1 -1
  25. package/dist/components/full-calendar/calendar-cell.js +1 -1
  26. package/dist/components/full-calendar/calendar-day-view.js +1 -1
  27. package/dist/components/full-calendar/calendar-month-view.js +1 -1
  28. package/dist/components/full-calendar/calendar-view-renderer.js +1 -1
  29. package/dist/components/full-calendar/calendar-week-view.js +1 -1
  30. package/dist/components/full-calendar/index.js +1 -1
  31. package/dist/components/selection-bar.d.ts +1 -1
  32. package/dist/components/status.d.ts +1 -1
  33. package/dist/components/steps/index.js +1 -1
  34. package/dist/components/table/index.js +1 -1
  35. package/dist/components/toast.d.ts +27 -0
  36. package/dist/components/toast.js +2 -0
  37. package/dist/components/toast.js.map +1 -0
  38. package/dist/components/typography.d.ts +1 -1
  39. package/dist/components/upload.js +1 -1
  40. package/dist/index.css +1 -1
  41. package/dist/index.css.map +1 -1
  42. package/package.json +25 -16
  43. package/.turbo/turbo-build.log +0 -419
  44. package/eslint.config.js +0 -10
  45. package/postcss.config.js +0 -5
  46. package/prettier.config.js +0 -7
  47. package/src/components/avatar-group.tsx +0 -76
  48. package/src/components/avatar.tsx +0 -54
  49. package/src/components/badge.tsx +0 -40
  50. package/src/components/breadcrumb.tsx +0 -119
  51. package/src/components/chip.tsx +0 -117
  52. package/src/components/collapsible.tsx +0 -35
  53. package/src/components/controls/button.tsx +0 -107
  54. package/src/components/controls/calendar.tsx +0 -124
  55. package/src/components/controls/checkbox.tsx +0 -57
  56. package/src/components/controls/context/field.context.ts +0 -27
  57. package/src/components/controls/date-picker.tsx +0 -199
  58. package/src/components/controls/floating-label.tsx +0 -60
  59. package/src/components/controls/input.tsx +0 -237
  60. package/src/components/controls/otp-input.tsx +0 -45
  61. package/src/components/controls/radio.tsx +0 -74
  62. package/src/components/controls/rich-editor.tsx +0 -372
  63. package/src/components/controls/search-input.tsx +0 -154
  64. package/src/components/controls/search-selector.tsx +0 -98
  65. package/src/components/controls/select.tsx +0 -274
  66. package/src/components/controls/switch.tsx +0 -31
  67. package/src/components/custom/pessoa/index.ts +0 -9
  68. package/src/components/custom/pessoa/pessoa-add-button.tsx +0 -35
  69. package/src/components/custom/pessoa/pessoa-body.tsx +0 -22
  70. package/src/components/custom/pessoa/pessoa-close-button.tsx +0 -13
  71. package/src/components/custom/pessoa/pessoa-content.tsx +0 -25
  72. package/src/components/custom/pessoa/pessoa-footer.tsx +0 -15
  73. package/src/components/custom/pessoa/pessoa-header.tsx +0 -35
  74. package/src/components/custom/pessoa/pessoa-trigger.tsx +0 -25
  75. package/src/components/custom/pessoa/pessoa.context.tsx +0 -73
  76. package/src/components/custom/pessoa/pessoa.tsx +0 -35
  77. package/src/components/dialog.tsx +0 -242
  78. package/src/components/divider.tsx +0 -24
  79. package/src/components/drag-and-drop/drag-handle.tsx +0 -46
  80. package/src/components/drag-and-drop/drag-list-item.tsx +0 -91
  81. package/src/components/drag-and-drop/drag-list.tsx +0 -47
  82. package/src/components/drag-and-drop/drag-root.tsx +0 -30
  83. package/src/components/drag-and-drop/index.ts +0 -39
  84. package/src/components/drag-and-drop/types/drag-item.ts +0 -7
  85. package/src/components/dropdown-menu.tsx +0 -101
  86. package/src/components/full-calendar/calendar-add-event.tsx +0 -15
  87. package/src/components/full-calendar/calendar-body.tsx +0 -12
  88. package/src/components/full-calendar/calendar-cell.tsx +0 -120
  89. package/src/components/full-calendar/calendar-day-view.tsx +0 -76
  90. package/src/components/full-calendar/calendar-event.tsx +0 -178
  91. package/src/components/full-calendar/calendar-header.tsx +0 -14
  92. package/src/components/full-calendar/calendar-month-view.tsx +0 -69
  93. package/src/components/full-calendar/calendar-more-events-dropdown.tsx +0 -39
  94. package/src/components/full-calendar/calendar-navigator.tsx +0 -86
  95. package/src/components/full-calendar/calendar-root.tsx +0 -165
  96. package/src/components/full-calendar/calendar-today-button.tsx +0 -21
  97. package/src/components/full-calendar/calendar-toggle-view.tsx +0 -61
  98. package/src/components/full-calendar/calendar-view-renderer.tsx +0 -19
  99. package/src/components/full-calendar/calendar-week-day.tsx +0 -49
  100. package/src/components/full-calendar/calendar-week-view.tsx +0 -88
  101. package/src/components/full-calendar/helpers/calendar.ts +0 -158
  102. package/src/components/full-calendar/index.ts +0 -16
  103. package/src/components/full-calendar/types/calendar-cell.ts +0 -4
  104. package/src/components/full-calendar/types/calendar-event.ts +0 -7
  105. package/src/components/full-calendar/types/calendar-view.ts +0 -1
  106. package/src/components/full-calendar/types/calendar-week-hour.ts +0 -4
  107. package/src/components/horizontal-scroll.tsx +0 -159
  108. package/src/components/icon.tsx +0 -29
  109. package/src/components/list.tsx +0 -111
  110. package/src/components/logo.tsx +0 -44
  111. package/src/components/selection-bar.tsx +0 -273
  112. package/src/components/sheet.tsx +0 -150
  113. package/src/components/skeleton.tsx +0 -12
  114. package/src/components/status.tsx +0 -43
  115. package/src/components/steps/index.ts +0 -6
  116. package/src/components/steps/step.tsx +0 -23
  117. package/src/components/steps/steps-action.tsx +0 -65
  118. package/src/components/steps/steps-content.tsx +0 -12
  119. package/src/components/steps/steps-context.tsx +0 -121
  120. package/src/components/steps/steps-navigation.tsx +0 -80
  121. package/src/components/steps/steps-root.tsx +0 -9
  122. package/src/components/table/index.ts +0 -8
  123. package/src/components/table/table-body.tsx +0 -17
  124. package/src/components/table/table-cell.tsx +0 -14
  125. package/src/components/table/table-footer.tsx +0 -17
  126. package/src/components/table/table-head.tsx +0 -31
  127. package/src/components/table/table-header.tsx +0 -17
  128. package/src/components/table/table-row.tsx +0 -21
  129. package/src/components/table/table-sort.tsx +0 -34
  130. package/src/components/table/table.tsx +0 -16
  131. package/src/components/tabs.tsx +0 -72
  132. package/src/components/tag.tsx +0 -99
  133. package/src/components/tooltip.tsx +0 -63
  134. package/src/components/typography.tsx +0 -85
  135. package/src/components/upload.tsx +0 -647
  136. package/src/hooks/index.ts +0 -1
  137. package/src/hooks/use-os.ts +0 -32
  138. package/src/index.css +0 -5
  139. package/src/resources/icons.ts +0 -154
  140. package/src/resources/input-mask.ts +0 -91
  141. package/src/resources/logo/horizontal.tsx +0 -70
  142. package/src/resources/logo/icon.tsx +0 -54
  143. package/src/resources/logo/index.tsx +0 -33
  144. package/src/resources/logo/vertical.tsx +0 -70
  145. package/src/types.d.ts +0 -4
  146. package/tsconfig.json +0 -4
  147. package/tsup.config.ts +0 -30
@@ -1,159 +0,0 @@
1
- import type { ComponentProps, ReactNode } from 'react'
2
- import { useCallback, useEffect, useRef, useState } from 'react'
3
- import { cx } from '@xjur-ui/util'
4
- import { Button } from './controls/button'
5
- import { Icon } from './icon'
6
-
7
- export interface HorizontalScrollProps extends ComponentProps<'div'> {
8
- children: ReactNode
9
- gap?: 'small' | 'medium' | 'large'
10
- scrollAmount?: number
11
- }
12
-
13
- export function HorizontalScroll({
14
- children,
15
- className,
16
- gap = 'small',
17
- scrollAmount = 200,
18
- ...props
19
- }: HorizontalScrollProps) {
20
- const scrollContainerRef = useRef<HTMLDivElement>(null)
21
- const [canScrollLeft, setCanScrollLeft] = useState(false)
22
- const [canScrollRight, setCanScrollRight] = useState(false)
23
- const [isScrolling, setIsScrolling] = useState(false)
24
-
25
- const checkScrollable = useCallback(() => {
26
- const container = scrollContainerRef.current
27
- if (!container) return
28
-
29
- const { scrollLeft, scrollWidth, clientWidth } = container
30
- setCanScrollLeft(scrollLeft > 0)
31
- setCanScrollRight(scrollLeft < scrollWidth - clientWidth - 1)
32
- }, [])
33
-
34
- const handleScrollLeft = useCallback(() => {
35
- const container = scrollContainerRef.current
36
- if (!container) return
37
-
38
- setIsScrolling(true)
39
- container.scrollTo({
40
- left: container.scrollLeft - scrollAmount,
41
- behavior: 'smooth'
42
- })
43
-
44
- setTimeout(() => setIsScrolling(false), 300)
45
- }, [scrollAmount])
46
-
47
- const handleScrollRight = useCallback(() => {
48
- const container = scrollContainerRef.current
49
- if (!container) return
50
-
51
- setIsScrolling(true)
52
- container.scrollTo({
53
- left: container.scrollLeft + scrollAmount,
54
- behavior: 'smooth'
55
- })
56
-
57
- setTimeout(() => setIsScrolling(false), 300)
58
- }, [scrollAmount])
59
-
60
- useEffect(() => {
61
- const container = scrollContainerRef.current
62
- if (!container) return
63
-
64
- const handleScroll = () => {
65
- checkScrollable()
66
- }
67
-
68
- const handleResize = () => {
69
- checkScrollable()
70
- }
71
-
72
- checkScrollable()
73
- container.addEventListener('scroll', handleScroll, { passive: true })
74
- window.addEventListener('resize', handleResize)
75
-
76
- let resizeObserver: ResizeObserver | null = null
77
- if (typeof ResizeObserver !== 'undefined') {
78
- resizeObserver = new ResizeObserver(() => {
79
- checkScrollable()
80
- })
81
- resizeObserver.observe(container)
82
- }
83
-
84
- return () => {
85
- container.removeEventListener('scroll', handleScroll)
86
- window.removeEventListener('resize', handleResize)
87
- if (resizeObserver) {
88
- resizeObserver.disconnect()
89
- }
90
- }
91
- }, [checkScrollable])
92
-
93
- const gapClass = {
94
- small: 'gap-small',
95
- medium: 'gap-medium',
96
- large: 'gap-large'
97
- }[gap]
98
-
99
- return (
100
- <div className={cx('relative isolate', className)} {...props}>
101
- {/* Left Arrow */}
102
- {canScrollLeft && (
103
- <div
104
- className="absolute top-1/2 left-0 z-[3] flex h-full w-[80px] -translate-y-1/2 items-center"
105
- style={{
106
- background: `linear-gradient(to right, white 40%, transparent)`
107
- }}
108
- >
109
- <Button
110
- appearance="ghost"
111
- aria-label="Scroll left"
112
- className="ml-0"
113
- disabled={isScrolling}
114
- size="icon_md"
115
- variant="secondary"
116
- onClick={handleScrollLeft}
117
- >
118
- <Icon name="chevron_left" />
119
- </Button>
120
- </div>
121
- )}
122
-
123
- {/* Right Arrow */}
124
- {canScrollRight && (
125
- <div
126
- className="absolute top-1/2 right-0 z-[2] flex h-full w-[80px] -translate-y-1/2 items-center justify-end"
127
- style={{
128
- background: `linear-gradient(to left, white 40%, transparent)`
129
- }}
130
- >
131
- <Button
132
- appearance="ghost"
133
- aria-label="Scroll right"
134
- className="mr-0"
135
- disabled={isScrolling}
136
- size="icon_md"
137
- variant="secondary"
138
- onClick={handleScrollRight}
139
- >
140
- <Icon name="chevron_right" />
141
- </Button>
142
- </div>
143
- )}
144
-
145
- {/* Scrollable Content */}
146
- <div
147
- className={cx(
148
- 'scrollbar-hide relative z-1 flex overflow-x-auto overflow-y-visible',
149
- 'min-w-0 [&>*]:flex-none [&>*]:whitespace-nowrap',
150
- gapClass,
151
- className
152
- )}
153
- ref={scrollContainerRef}
154
- >
155
- {children}
156
- </div>
157
- </div>
158
- )
159
- }
@@ -1,29 +0,0 @@
1
- import type { ComponentProps } from 'react'
2
- import { cx } from '@xjur-ui/util'
3
- import type { IconType } from '../resources/icons'
4
-
5
- export type IconProps = {
6
- name: IconType
7
- filled?: boolean
8
- } & ComponentProps<'span'>
9
-
10
- export function Icon({ className, filled = false, name, ...props }: IconProps) {
11
- return (
12
- <span
13
- {...props}
14
- className={cx(
15
- 'material-symbols-outlined',
16
- 'text-size-body-lg select-none',
17
- className
18
- )}
19
- style={{
20
- fontVariationSettings: `'FILL' ${filled ? 1 : 0}, 'wght' 600, 'GRAD' 0, 'opsz' 20`,
21
- ...props.style
22
- }}
23
- >
24
- {name}
25
- </span>
26
- )
27
- }
28
-
29
- export { icons, type IconType } from '../resources/icons'
@@ -1,111 +0,0 @@
1
- import { Slot } from '@radix-ui/react-slot'
2
- import { cx, cva, type ClassVariantProps } from '@xjur-ui/util'
3
- import type { ComponentProps } from 'react'
4
- import { type TypographyProps, Typography } from './typography'
5
-
6
- export function ListRoot({
7
- className,
8
- asChild,
9
- ...props
10
- }: ComponentProps<'div'> & {
11
- asChild?: boolean
12
- }) {
13
- const Comp = asChild ? Slot : 'div'
14
-
15
- return (
16
- <Comp
17
- {...props}
18
- className={cx(
19
- className,
20
- 'rounded-small scrollbar-hide bg-layer-2-idle border-border-layer-2 shadow-elevation-3 z-1000 max-h-[400px] list-none overflow-y-auto border'
21
- )}
22
- />
23
- )
24
- }
25
-
26
- export function ListHeader({
27
- className,
28
- asChild,
29
- ...props
30
- }: ComponentProps<'div'> & {
31
- asChild?: boolean
32
- }) {
33
- const Comp = asChild ? Slot : 'div'
34
- return <Comp {...props} className={cx(className, 'px-small pt-small-1x')} />
35
- }
36
-
37
- export function ListHeaderTitle({
38
- variant = 'label',
39
- size = 'sm',
40
- weight = 'medium',
41
- className,
42
- ...props
43
- }: TypographyProps) {
44
- return (
45
- <Typography
46
- className={cx(className, 'text-neutral-placeholder')}
47
- size={size}
48
- variant={variant}
49
- weight={weight}
50
- {...props}
51
- />
52
- )
53
- }
54
-
55
- export function ListContent({
56
- className,
57
- asChild,
58
- ...props
59
- }: ComponentProps<'ul'> & {
60
- asChild?: boolean
61
- }) {
62
- const Comp = asChild ? Slot : 'ul'
63
-
64
- return (
65
- <Comp
66
- {...props}
67
- className={cx('gap-small-1x p-small flex flex-col', className)}
68
- />
69
- )
70
- }
71
-
72
- const variants = cva(
73
- [
74
- 'py-medium px-small flex items-center gap-small rounded-small-1x',
75
- 'bg-layer-2-idle text-neutral-dark',
76
- 'hover:bg-layer-2-hover transition-colors duration-100 ease-out',
77
- 'active:bg-layer-2-pressed'
78
- ],
79
- {
80
- variants: {
81
- size: {
82
- md: 'h-large-4x',
83
- lg: 'h-large-7x'
84
- },
85
- isActive: {
86
- true: 'bg-primary-alt-active text-primary-label-active hover:bg-primary-alt-hover active:bg-primary-alt-pressed'
87
- }
88
- },
89
- defaultVariants: {
90
- size: 'md',
91
- isActive: false
92
- }
93
- }
94
- )
95
-
96
- export function ListItem({
97
- className,
98
- size,
99
- isActive,
100
- asChild,
101
- ...props
102
- }: ComponentProps<'li'> &
103
- ClassVariantProps<typeof variants> & {
104
- asChild?: boolean
105
- }) {
106
- const Comp = asChild ? Slot : 'li'
107
-
108
- return (
109
- <Comp {...props} className={cx(variants({ size, isActive }), className)} />
110
- )
111
- }
@@ -1,44 +0,0 @@
1
- import { memo, lazy, Suspense } from 'react'
2
-
3
- export interface LogoProps {
4
- mode?: 'horizontal' | 'vertical' | 'icon'
5
- variant?: 'colorful' | 'orange' | 'purple' | 'white' | 'gray'
6
- }
7
-
8
- // Lazy load logo components to reduce initial bundle size
9
- const LazyLogos = lazy(() => import('../resources/logo'))
10
-
11
- function LogoFallback({ mode }: { mode?: string }) {
12
- const dimensions =
13
- mode === 'icon' ? { width: 24, height: 24 } : { width: 95, height: 26 }
14
- return (
15
- <div
16
- aria-label="Loading logo"
17
- className="animate-pulse rounded bg-gray-200"
18
- style={dimensions}
19
- />
20
- )
21
- }
22
-
23
- export const Logo = memo(
24
- ({ mode = 'horizontal', variant = 'colorful' }: LogoProps) => {
25
- const colorToHex = {
26
- orange: '#D68600',
27
- purple: '#66127D',
28
- white: '#FFFFFF',
29
- gray: '#6B7280'
30
- }
31
-
32
- return (
33
- <Suspense fallback={<LogoFallback mode={mode} />}>
34
- <LazyLogos
35
- color={variant !== 'colorful' ? colorToHex[variant] : undefined}
36
- mode={mode}
37
- variant={variant}
38
- />
39
- </Suspense>
40
- )
41
- }
42
- )
43
-
44
- Logo.displayName = 'Logo'
@@ -1,273 +0,0 @@
1
- import type { ComponentProps, ReactNode } from 'react'
2
- import { createContext, useContext, useState, useCallback } from 'react'
3
- import { cva, cx, type ClassVariantProps } from '@xjur-ui/util'
4
- import { Icon, type IconType } from './icon'
5
- import { Button } from './controls/button'
6
-
7
- const selectionBarVariants = cva(
8
- [
9
- 'flex items-center gap-4 rounded-lg px-4 py-3 shadow-lg transition-colors duration-200 ease-in-out',
10
- 'fixed bottom-6 left-1/2 -translate-x-1/2 transform z-50',
11
- 'backdrop-blur-sm bg-white/95 border border-border-layer-2'
12
- ],
13
- {
14
- variants: {
15
- size: {
16
- sm: 'px-3 py-2 text-sm',
17
- md: 'px-4 py-3 text-base',
18
- lg: 'px-6 py-4 text-lg'
19
- },
20
- variant: {
21
- primary:
22
- 'bg-primary-idle text-neutral-label hover:bg-primary-hover rounded-circle active:bg-primary-pressed',
23
- secondary:
24
- 'bg-secondary-idle text-white border-secondary-idle hover:bg-secondary-hover rounded-circle',
25
- success:
26
- 'bg-success-idle text-white border-success-idle hover:bg-success-hover rounded-circle',
27
- warning:
28
- 'bg-warning-idle text-white border-warning-idle hover:bg-warning-hover rounded-circle',
29
- destructive:
30
- 'bg-destructive-idle text-white border-destructive-idle hover:bg-destructive-hover rounded-circle',
31
- neutral:
32
- 'bg-neutral-dark text-white border-neutral-dark hover:bg-neutral-hover rounded-circle',
33
- outline:
34
- 'bg-white text-neutral-dark border-border-layer-2 hover:bg-layer-2-hover rounded-circle'
35
- },
36
- position: {
37
- fixed: 'fixed bottom-6 left-1/2 -translate-x-1/2 transform',
38
- absolute: 'absolute bottom-6 left-1/2 -translate-x-1/2 transform',
39
- relative: 'relative',
40
- sticky: 'sticky bottom-6'
41
- }
42
- },
43
- defaultVariants: {
44
- size: 'md',
45
- variant: 'primary',
46
- position: 'fixed'
47
- }
48
- }
49
- )
50
-
51
- export interface SelectionAction {
52
- id: string
53
- label?: string
54
- icon: IconType
55
- onClick: () => void
56
- variant?: 'primary' | 'secondary' | 'destructive' | 'tertiary' | 'outlined'
57
- disabled?: boolean
58
- }
59
-
60
- interface SelectionBarProps
61
- extends Omit<ComponentProps<'div'>, 'onClose'>,
62
- ClassVariantProps<typeof selectionBarVariants> {
63
- selectedCount: number
64
- onClose: () => void
65
- actions?: SelectionAction[]
66
- showCloseButton?: boolean
67
- closeButtonText?: string
68
- selectedText?: string
69
- className?: string
70
- }
71
-
72
- function SelectionBar({
73
- selectedCount,
74
- onClose,
75
- actions = [],
76
- showCloseButton = true,
77
- selectedText,
78
- size = 'md',
79
- variant = 'primary',
80
- position = 'fixed',
81
- className,
82
- ...props
83
- }: SelectionBarProps) {
84
- if (selectedCount === 0) return null
85
-
86
- const getSelectedText = () => {
87
- if (selectedText) return selectedText
88
- return selectedCount === 1
89
- ? '1 item selecionado'
90
- : `${selectedCount} itens selecionados`
91
- }
92
-
93
- const getIconSize = () => {
94
- switch (size) {
95
- case 'sm':
96
- return 'text-sm'
97
- case 'md':
98
- return 'text-base'
99
- case 'lg':
100
- return 'text-lg'
101
- default:
102
- return 'text-base'
103
- }
104
- }
105
-
106
- return (
107
- <div
108
- className={cx(
109
- selectionBarVariants({ size, variant, position }),
110
- className
111
- )}
112
- {...props}
113
- >
114
- {showCloseButton && (
115
- <Button
116
- appearance="ghost"
117
- className="rounded-full text-current"
118
- size={size === 'lg' ? 'md' : 'sm'}
119
- variant="secondary"
120
- onClick={() => onClose()}
121
- >
122
- <Icon className={getIconSize()} name="close" />
123
- </Button>
124
- )}
125
-
126
- <span className="font-medium whitespace-nowrap">{getSelectedText()}</span>
127
-
128
- {actions.map(action => (
129
- <Button
130
- appearance="ghost"
131
- className="rounded-full text-current"
132
- disabled={action.disabled}
133
- key={action.id}
134
- size={size === 'lg' ? 'md' : 'sm'}
135
- variant={action.variant || 'secondary'}
136
- onClick={() => action.onClick()}
137
- >
138
- <Icon className={getIconSize()} name={action.icon} />
139
- {action.label && <span className="ml-2">{action.label}</span>}
140
- </Button>
141
- ))}
142
- </div>
143
- )
144
- }
145
-
146
- interface SelectionBarContextType {
147
- selectedItems: Set<string>
148
- toggleSelection: (id: string) => void
149
- clearSelection: () => void
150
- selectAll: (ids: string[]) => void
151
- isSelected: (id: string) => boolean
152
- selectedCount: number
153
- }
154
-
155
- const SelectionBarContext = createContext<SelectionBarContextType | null>(null)
156
-
157
- interface SelectionBarProviderProps {
158
- children: ReactNode
159
- onSelectionChange?: (selectedIds: string[]) => void
160
- }
161
-
162
- function SelectionBarProvider({
163
- children,
164
- onSelectionChange
165
- }: SelectionBarProviderProps) {
166
- const [selectedItems, setSelectedItems] = useState<Set<string>>(new Set())
167
-
168
- const toggleSelection = useCallback(
169
- (id: string) => {
170
- setSelectedItems(prev => {
171
- const newSet = new Set(prev)
172
- if (newSet.has(id)) {
173
- newSet.delete(id)
174
- } else {
175
- newSet.add(id)
176
- }
177
- onSelectionChange?.(Array.from(newSet))
178
- return newSet
179
- })
180
- },
181
- [onSelectionChange]
182
- )
183
-
184
- const clearSelection = useCallback(() => {
185
- setSelectedItems(new Set())
186
- onSelectionChange?.([])
187
- }, [onSelectionChange])
188
-
189
- const selectAll = useCallback(
190
- (ids: string[]) => {
191
- setSelectedItems(new Set(ids))
192
- onSelectionChange?.(ids)
193
- },
194
- [onSelectionChange]
195
- )
196
-
197
- const isSelected = useCallback(
198
- (id: string) => {
199
- return selectedItems.has(id)
200
- },
201
- [selectedItems]
202
- )
203
-
204
- const value: SelectionBarContextType = {
205
- selectedItems,
206
- toggleSelection,
207
- clearSelection,
208
- selectAll,
209
- isSelected,
210
- selectedCount: selectedItems.size
211
- }
212
-
213
- return (
214
- <SelectionBarContext.Provider value={value}>
215
- {children}
216
- </SelectionBarContext.Provider>
217
- )
218
- }
219
-
220
- function useSelectionBar() {
221
- const context = useContext(SelectionBarContext)
222
- if (!context) {
223
- throw new Error(
224
- 'useSelectionBar must be used within a SelectionBarProvider'
225
- )
226
- }
227
- return context
228
- }
229
-
230
- interface SelectionBarContainerProps
231
- extends Omit<SelectionBarProps, 'selectedCount' | 'onClose'> {
232
- showCloseButton?: boolean
233
- closeButtonText?: string
234
- selectedText?: string
235
- }
236
-
237
- function SelectionBarContainer({
238
- actions = [],
239
- showCloseButton = true,
240
- selectedText,
241
- ...props
242
- }: SelectionBarContainerProps) {
243
- const { selectedCount, clearSelection } = useSelectionBar()
244
-
245
- return (
246
- <SelectionBar
247
- actions={actions}
248
- selectedCount={selectedCount}
249
- selectedText={selectedText}
250
- showCloseButton={showCloseButton}
251
- onClose={() => clearSelection()}
252
- {...props}
253
- />
254
- )
255
- }
256
-
257
- export const SelectionBarComponents = {
258
- Root: SelectionBar,
259
- Provider: SelectionBarProvider,
260
- Container: SelectionBarContainer,
261
- useSelectionBar
262
- }
263
-
264
- export { SelectionBar }
265
- export { SelectionBarProvider }
266
- export { SelectionBarContainer }
267
- export { useSelectionBar }
268
- export { selectionBarVariants }
269
- export type {
270
- SelectionBarProps,
271
- SelectionBarProviderProps,
272
- SelectionBarContainerProps
273
- }