@xjur-ui/react 2.1.1 → 2.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 (108) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/components/steps/index.js +1 -1
  3. package/package.json +7 -4
  4. package/.turbo/turbo-build.log +0 -419
  5. package/eslint.config.js +0 -10
  6. package/postcss.config.js +0 -5
  7. package/prettier.config.js +0 -7
  8. package/src/components/avatar-group.tsx +0 -76
  9. package/src/components/avatar.tsx +0 -54
  10. package/src/components/badge.tsx +0 -40
  11. package/src/components/breadcrumb.tsx +0 -119
  12. package/src/components/chip.tsx +0 -117
  13. package/src/components/collapsible.tsx +0 -35
  14. package/src/components/controls/button.tsx +0 -107
  15. package/src/components/controls/calendar.tsx +0 -124
  16. package/src/components/controls/checkbox.tsx +0 -57
  17. package/src/components/controls/context/field.context.ts +0 -27
  18. package/src/components/controls/date-picker.tsx +0 -199
  19. package/src/components/controls/floating-label.tsx +0 -60
  20. package/src/components/controls/input.tsx +0 -237
  21. package/src/components/controls/otp-input.tsx +0 -45
  22. package/src/components/controls/radio.tsx +0 -74
  23. package/src/components/controls/rich-editor.tsx +0 -372
  24. package/src/components/controls/search-input.tsx +0 -154
  25. package/src/components/controls/search-selector.tsx +0 -98
  26. package/src/components/controls/select.tsx +0 -274
  27. package/src/components/controls/switch.tsx +0 -31
  28. package/src/components/custom/pessoa/index.ts +0 -9
  29. package/src/components/custom/pessoa/pessoa-add-button.tsx +0 -35
  30. package/src/components/custom/pessoa/pessoa-body.tsx +0 -22
  31. package/src/components/custom/pessoa/pessoa-close-button.tsx +0 -13
  32. package/src/components/custom/pessoa/pessoa-content.tsx +0 -25
  33. package/src/components/custom/pessoa/pessoa-footer.tsx +0 -15
  34. package/src/components/custom/pessoa/pessoa-header.tsx +0 -35
  35. package/src/components/custom/pessoa/pessoa-trigger.tsx +0 -25
  36. package/src/components/custom/pessoa/pessoa.context.tsx +0 -73
  37. package/src/components/custom/pessoa/pessoa.tsx +0 -35
  38. package/src/components/dialog.tsx +0 -242
  39. package/src/components/divider.tsx +0 -24
  40. package/src/components/drag-and-drop/drag-handle.tsx +0 -46
  41. package/src/components/drag-and-drop/drag-list-item.tsx +0 -91
  42. package/src/components/drag-and-drop/drag-list.tsx +0 -47
  43. package/src/components/drag-and-drop/drag-root.tsx +0 -30
  44. package/src/components/drag-and-drop/index.ts +0 -39
  45. package/src/components/drag-and-drop/types/drag-item.ts +0 -7
  46. package/src/components/dropdown-menu.tsx +0 -101
  47. package/src/components/full-calendar/calendar-add-event.tsx +0 -15
  48. package/src/components/full-calendar/calendar-body.tsx +0 -12
  49. package/src/components/full-calendar/calendar-cell.tsx +0 -120
  50. package/src/components/full-calendar/calendar-day-view.tsx +0 -76
  51. package/src/components/full-calendar/calendar-event.tsx +0 -178
  52. package/src/components/full-calendar/calendar-header.tsx +0 -14
  53. package/src/components/full-calendar/calendar-month-view.tsx +0 -69
  54. package/src/components/full-calendar/calendar-more-events-dropdown.tsx +0 -39
  55. package/src/components/full-calendar/calendar-navigator.tsx +0 -86
  56. package/src/components/full-calendar/calendar-root.tsx +0 -165
  57. package/src/components/full-calendar/calendar-today-button.tsx +0 -21
  58. package/src/components/full-calendar/calendar-toggle-view.tsx +0 -61
  59. package/src/components/full-calendar/calendar-view-renderer.tsx +0 -19
  60. package/src/components/full-calendar/calendar-week-day.tsx +0 -49
  61. package/src/components/full-calendar/calendar-week-view.tsx +0 -88
  62. package/src/components/full-calendar/helpers/calendar.ts +0 -158
  63. package/src/components/full-calendar/index.ts +0 -16
  64. package/src/components/full-calendar/types/calendar-cell.ts +0 -4
  65. package/src/components/full-calendar/types/calendar-event.ts +0 -7
  66. package/src/components/full-calendar/types/calendar-view.ts +0 -1
  67. package/src/components/full-calendar/types/calendar-week-hour.ts +0 -4
  68. package/src/components/horizontal-scroll.tsx +0 -159
  69. package/src/components/icon.tsx +0 -29
  70. package/src/components/list.tsx +0 -111
  71. package/src/components/logo.tsx +0 -44
  72. package/src/components/selection-bar.tsx +0 -273
  73. package/src/components/sheet.tsx +0 -150
  74. package/src/components/skeleton.tsx +0 -12
  75. package/src/components/status.tsx +0 -43
  76. package/src/components/steps/index.ts +0 -6
  77. package/src/components/steps/step.tsx +0 -23
  78. package/src/components/steps/steps-action.tsx +0 -65
  79. package/src/components/steps/steps-content.tsx +0 -12
  80. package/src/components/steps/steps-context.tsx +0 -121
  81. package/src/components/steps/steps-navigation.tsx +0 -80
  82. package/src/components/steps/steps-root.tsx +0 -9
  83. package/src/components/table/index.ts +0 -8
  84. package/src/components/table/table-body.tsx +0 -17
  85. package/src/components/table/table-cell.tsx +0 -14
  86. package/src/components/table/table-footer.tsx +0 -17
  87. package/src/components/table/table-head.tsx +0 -31
  88. package/src/components/table/table-header.tsx +0 -17
  89. package/src/components/table/table-row.tsx +0 -21
  90. package/src/components/table/table-sort.tsx +0 -34
  91. package/src/components/table/table.tsx +0 -16
  92. package/src/components/tabs.tsx +0 -72
  93. package/src/components/tag.tsx +0 -99
  94. package/src/components/tooltip.tsx +0 -63
  95. package/src/components/typography.tsx +0 -85
  96. package/src/components/upload.tsx +0 -647
  97. package/src/hooks/index.ts +0 -1
  98. package/src/hooks/use-os.ts +0 -32
  99. package/src/index.css +0 -5
  100. package/src/resources/icons.ts +0 -154
  101. package/src/resources/input-mask.ts +0 -91
  102. package/src/resources/logo/horizontal.tsx +0 -70
  103. package/src/resources/logo/icon.tsx +0 -54
  104. package/src/resources/logo/index.tsx +0 -33
  105. package/src/resources/logo/vertical.tsx +0 -70
  106. package/src/types.d.ts +0 -4
  107. package/tsconfig.json +0 -4
  108. package/tsup.config.ts +0 -30
@@ -1,372 +0,0 @@
1
- import { cx } from '@xjur-ui/util'
2
- import { useCallback, useMemo, useState, type ComponentProps } from 'react'
3
- import {
4
- EditorContent,
5
- EditorContext,
6
- useCurrentEditor as useRichTextEditor,
7
- useEditorState as useRichTextEditorState,
8
- useEditor,
9
- type EditorOptions
10
- } from '@tiptap/react'
11
- import type { Extension } from '@tiptap/core'
12
- import { StarterKit } from '@tiptap/starter-kit'
13
- import { Heading, type Level } from '@tiptap/extension-heading'
14
- // Import specific extension instead of full extensions bundle
15
- import { Placeholder } from '@tiptap/extension-placeholder'
16
- import { useOS } from '../../hooks'
17
- import { Icon, type IconType } from '../icon'
18
- import { Button, type ButtonProps } from './button'
19
- import {
20
- DropdownMenuContent,
21
- DropdownMenuItem,
22
- DropdownMenuItemText,
23
- DropdownMenuList,
24
- DropdownMenuRoot,
25
- DropdownMenuTrigger
26
- } from '../dropdown-menu'
27
- import { Tooltip, TooltipTrigger, TooltipContent } from '../tooltip'
28
- import { Typography } from '../typography'
29
-
30
- const headingClasses: Partial<Record<Level, string>> = {
31
- 1: 'text-size-body-md',
32
- 2: 'text-size-title-lg',
33
- 3: 'text-size-headline-lg'
34
- }
35
-
36
- export function RichEditorRoot({
37
- className,
38
- editorOptions,
39
- ...props
40
- }: ComponentProps<'div'> & {
41
- editorOptions?: Partial<
42
- Omit<EditorOptions, 'extensions'> & {
43
- extensions?: Extension[]
44
- }
45
- >
46
- }) {
47
- const editor = useEditor({
48
- ...editorOptions,
49
- extensions: [
50
- StarterKit.configure({
51
- bulletList: {
52
- HTMLAttributes: {
53
- class: 'list-disc list-outside pl-large-1x'
54
- }
55
- },
56
- orderedList: {
57
- HTMLAttributes: {
58
- class: 'list-decimal list-outside pl-large-1x'
59
- }
60
- },
61
- heading: false
62
- }),
63
- Placeholder.configure({
64
- placeholder: ({ node, editor }) =>
65
- node.type.name === 'paragraph' && editor.isEmpty
66
- ? 'Digite aqui…'
67
- : '',
68
- showOnlyWhenEditable: true,
69
- includeChildren: false,
70
- emptyNodeClass:
71
- 'before:content-[attr(data-placeholder)] before:absolute before:top-0 before:left-0 before:text-neutral-placeholder first:before:float-left first:before:content-[attr(data-placeholder)] first:before:pointer-events-none'
72
- }),
73
- Heading.configure({
74
- levels: [1, 2, 3]
75
- }).extend({
76
- renderHTML({ node, HTMLAttributes }) {
77
- const level: Level = node.attrs.level ?? 1
78
-
79
- return [
80
- 'h',
81
- {
82
- ...HTMLAttributes,
83
- class: headingClasses[level]
84
- },
85
- 0
86
- ]
87
- }
88
- }),
89
- ...(editorOptions?.extensions ?? [])
90
- ]
91
- })
92
-
93
- const value = useMemo(() => ({ editor }), [editor])
94
-
95
- return (
96
- <EditorContext.Provider value={value}>
97
- <div
98
- className={cx('gap-small flex w-full flex-col', className)}
99
- data-slot="text-area-root"
100
- {...props}
101
- />
102
- </EditorContext.Provider>
103
- )
104
- }
105
-
106
- export function RichEditorContent({
107
- className,
108
- ...props
109
- }: ComponentProps<'div'>) {
110
- return (
111
- <div
112
- className={cx(
113
- 'bg-layer-2-hover py-small_1x-alt px-small rounded-small-1x min-h-[116px] w-full border border-transparent',
114
- 'hover:border-border-layer-2 transition-colors duration-200',
115
- '[&_ul_ul]:list-[circle]',
116
- '[&_ul_ul_ul]:list-[square]',
117
- '[&_ol_ol]:list-[lower-alpha]',
118
- '[&_ol_ol_ol]:list-[lower-roman]',
119
- 'gap-small flex flex-col overflow-x-hidden overflow-y-auto',
120
- className
121
- )}
122
- data-slot="text-area-content"
123
- {...props}
124
- />
125
- )
126
- }
127
-
128
- export function RichEditorCaption({
129
- className,
130
- ...props
131
- }: ComponentProps<'p'>) {
132
- return (
133
- <p
134
- {...props}
135
- className={cx(
136
- 'text-size-body-sm text-neutral-dark font-normal',
137
- className
138
- )}
139
- data-slot="text-area-caption"
140
- />
141
- )
142
- }
143
-
144
- export function RichEditorAreaText({
145
- className,
146
- ...props
147
- }: Omit<ComponentProps<typeof EditorContent>, 'editor'>) {
148
- const { editor } = useRichTextEditor()
149
-
150
- return (
151
- <EditorContent
152
- className={cx(
153
- 'text-size-body-md text-neutral-dark max-h-[116px] *:h-full *:w-full *:outline-0',
154
- className
155
- )}
156
- editor={editor}
157
- {...props}
158
- />
159
- )
160
- }
161
-
162
- export function RichEditorToolbar({
163
- className,
164
- ...props
165
- }: ComponentProps<'div'>) {
166
- return (
167
- <div
168
- className={cx(
169
- 'h-large-4x gap-small-1x h-large-6px scrollbar-hide flex flex-nowrap items-center overflow-x-auto overflow-y-hidden',
170
- className
171
- )}
172
- data-slot="text-area-toolbar"
173
- {...props}
174
- />
175
- )
176
- }
177
-
178
- export function ToolbarButton({
179
- appearance = 'ghost',
180
- variant = 'secondary',
181
- onMouseDown,
182
- onPointerDown,
183
- ...props
184
- }: ButtonProps) {
185
- return (
186
- <Button
187
- appearance={appearance}
188
- size="icon_md"
189
- tabIndex={-1}
190
- type="button"
191
- variant={variant}
192
- onMouseDown={e => {
193
- e.preventDefault()
194
- onMouseDown?.(e)
195
- }}
196
- onPointerDown={e => {
197
- e.preventDefault()
198
- onPointerDown?.(e)
199
- }}
200
- {...props}
201
- />
202
- )
203
- }
204
-
205
- type ToggleButtonName =
206
- | 'bold'
207
- | 'italic'
208
- | 'underline'
209
- | 'strike'
210
- | 'bulletList'
211
- | 'orderedList'
212
- | 'undo'
213
- | 'redo'
214
-
215
- export function ToggleButton({
216
- name,
217
- ...props
218
- }: ButtonProps & { name: ToggleButtonName }) {
219
- const { editor } = useRichTextEditor()
220
- const { shortcut } = useOS()
221
-
222
- const isActive = useRichTextEditorState({
223
- editor,
224
- selector: ctx => ctx.editor?.isActive(name) ?? false
225
- })
226
-
227
- const icon = useMemo(() => {
228
- const iconsMap = new Map<ToggleButtonName, IconType>([
229
- ['bold', 'format_bold'],
230
- ['italic', 'format_italic'],
231
- ['underline', 'format_underlined'],
232
- ['strike', 'format_strikethrough'],
233
- ['bulletList', 'format_list_bulleted'],
234
- ['orderedList', 'format_list_numbered'],
235
- ['undo', 'undo'],
236
- ['redo', 'redo']
237
- ])
238
-
239
- return iconsMap.get(name)
240
- }, [name])
241
-
242
- const description = useMemo(() => {
243
- const descriptionsMap = new Map<ToggleButtonName, string>([
244
- ['bold', `Negrito (${shortcut} + B)`],
245
- ['italic', `Itálico (${shortcut} + I)`],
246
- ['underline', `Sublinhado (${shortcut} + U)`],
247
- ['strike', `Tachado (${shortcut} + S)`],
248
- ['bulletList', `Lista (${shortcut} + Shift + 7)`],
249
- ['orderedList', `Lista numerada (${shortcut} + Shift + 8)`],
250
- ['undo', `Desfazer (${shortcut} + Z)`],
251
- ['redo', `Refazer (${shortcut} + Y)`]
252
- ])
253
-
254
- return descriptionsMap.get(name)
255
- }, [name, shortcut])
256
-
257
- const handleToggle = useCallback(() => {
258
- if (!editor) throw new Error('Editor not found')
259
-
260
- const commandsMap = new Map<ToggleButtonName, () => void>([
261
- ['bold', () => editor.chain().focus().toggleBold().run()],
262
- ['italic', () => editor.chain().focus().toggleItalic().run()],
263
- ['underline', () => editor.chain().focus().toggleUnderline().run()],
264
- ['strike', () => editor.chain().focus().toggleStrike().run()],
265
- ['bulletList', () => editor.chain().focus().toggleBulletList().run()],
266
- ['orderedList', () => editor.chain().focus().toggleOrderedList().run()],
267
- ['undo', () => editor.chain().focus().undo().run()],
268
- ['redo', () => editor.chain().focus().redo().run()]
269
- ])
270
-
271
- commandsMap.get(name)?.()
272
- }, [editor, name])
273
-
274
- return (
275
- <Tooltip>
276
- <TooltipTrigger asChild={true}>
277
- <ToolbarButton
278
- onClick={handleToggle}
279
- {...(isActive && { appearance: 'solid' })}
280
- {...props}
281
- >
282
- {icon && <Icon className="text-icon-neutral-3" name={icon} />}
283
- </ToolbarButton>
284
- </TooltipTrigger>
285
-
286
- <TooltipContent>
287
- {description && <Typography size="sm">{description}</Typography>}
288
- </TooltipContent>
289
- </Tooltip>
290
- )
291
- }
292
-
293
- export function HeadingButton({
294
- appearance = 'ghost',
295
- variant = 'secondary',
296
- ...props
297
- }: ButtonProps) {
298
- const [isOpen, setIsOpen] = useState(false)
299
- const { editor } = useRichTextEditor()
300
-
301
- const isActive = useRichTextEditorState({
302
- editor,
303
- selector: ctx => ctx.editor?.isActive('heading') ?? false
304
- })
305
-
306
- const isLevelActive = useCallback(
307
- (level: Level) => {
308
- if (!editor) throw new Error('Editor not found')
309
- return editor.isActive('heading', { level })
310
- },
311
- [editor]
312
- )
313
-
314
- const toggleHeading = useCallback(
315
- (level: Level) => {
316
- if (!editor) throw new Error('Editor not found')
317
- setIsOpen(false)
318
- setTimeout(() => {
319
- editor.chain().focus().toggleHeading({ level }).run()
320
- }, 0)
321
- },
322
- [editor]
323
- )
324
-
325
- const levels: { level: Level; label: string; className?: string }[] = [
326
- { level: 1, label: 'Normal', className: headingClasses[1] },
327
- { level: 2, label: 'Grande', className: headingClasses[2] },
328
- { level: 3, label: 'Enorme', className: headingClasses[3] }
329
- ]
330
-
331
- return (
332
- <DropdownMenuRoot open={isOpen} onOpenChange={open => setIsOpen(open)}>
333
- <DropdownMenuTrigger asChild={true}>
334
- <Button
335
- appearance={isActive ? 'solid' : appearance}
336
- size="icon_md"
337
- tabIndex={-1}
338
- type="button"
339
- variant={variant}
340
- {...props}
341
- >
342
- <Tooltip>
343
- <TooltipTrigger asChild={true}>
344
- <Icon className="text-icon-neutral-3" name="format_size" />
345
- </TooltipTrigger>
346
-
347
- <TooltipContent>
348
- <Typography size="sm">Tamanho</Typography>
349
- </TooltipContent>
350
- </Tooltip>
351
- </Button>
352
- </DropdownMenuTrigger>
353
- <DropdownMenuContent>
354
- <DropdownMenuList>
355
- {levels.map(level => (
356
- <DropdownMenuItem
357
- isActive={isLevelActive(level.level)}
358
- key={level.level}
359
- onPointerDown={() => toggleHeading(level.level)}
360
- >
361
- <DropdownMenuItemText className={level.className}>
362
- {level.label}
363
- </DropdownMenuItemText>
364
- </DropdownMenuItem>
365
- ))}
366
- </DropdownMenuList>
367
- </DropdownMenuContent>
368
- </DropdownMenuRoot>
369
- )
370
- }
371
-
372
- export { useRichTextEditorState, useRichTextEditor }
@@ -1,154 +0,0 @@
1
- import { cva, cx } from '@xjur-ui/util'
2
- import { createContext, type ComponentProps } from 'react'
3
- import {
4
- InputMask as InputMaskComponent,
5
- type MaskOptions
6
- } from '@react-input/mask'
7
- import {
8
- InputNumberFormat,
9
- type InputNumberFormatProps
10
- } from '@react-input/number-format'
11
- import { Typography } from '../typography'
12
- import { inputMask, type InputMaskType } from '../../resources/input-mask'
13
- import { Button, type ButtonProps } from './button'
14
-
15
- export type SearchInputProps = {
16
- variant?: 'outlined' | 'line' | 'action'
17
- }
18
-
19
- const SearchInputRootContext = createContext<SearchInputProps>({
20
- variant: 'outlined'
21
- })
22
-
23
- export function SearchInputRoot({
24
- className,
25
- variant = 'outlined',
26
- ...props
27
- }: ComponentProps<'div'> & SearchInputProps) {
28
- return (
29
- <SearchInputRootContext.Provider value={{ variant }}>
30
- <div className={cx('relative flex', className)} {...props} />
31
- </SearchInputRootContext.Provider>
32
- )
33
- }
34
-
35
- export function SearchInputContent({
36
- className,
37
- ...props
38
- }: ComponentProps<'div'>) {
39
- const contentVarians = cva(
40
- [
41
- 'gap-small py-small_1x-alt px-small flex items-center w-full',
42
- 'h-large-4x rounded-circle',
43
- 'border-border-layer-2 placeholder:placeholder-neutral-placeholder text-size-body-md text-neutral-dark border font-normal',
44
- 'group-hover:border-border-layer-3 transition-colors duration-200',
45
- 'disabled:opacity-60',
46
- 'focus-within:border-primary-idle'
47
- ],
48
- {
49
- variants: {
50
- variant: {
51
- outlined: 'rounded-circle focus-within:border-primary-idle ',
52
- line: 'rounded-none border-t-0 border-b-1 border-x-0',
53
- action: 'rounded-tr-none rounded-br-none border-r-0'
54
- }
55
- }
56
- }
57
- )
58
-
59
- return (
60
- <SearchInputRootContext.Consumer>
61
- {({ variant }) => (
62
- <div
63
- className={cx(className, contentVarians({ variant }))}
64
- data-variant={variant}
65
- {...props}
66
- />
67
- )}
68
- </SearchInputRootContext.Consumer>
69
- )
70
- }
71
-
72
- export function SearchInputLabel({
73
- htmlFor,
74
- ...props
75
- }: ComponentProps<'label'>) {
76
- return (
77
- <Typography
78
- asChild={true}
79
- className={cx('absolute -top-[22px] left-0')}
80
- size="sm"
81
- variant="label"
82
- weight="medium"
83
- >
84
- <label htmlFor={htmlFor} {...props} />
85
- </Typography>
86
- )
87
- }
88
-
89
- export function SearchInputText({
90
- className,
91
- ...props
92
- }: ComponentProps<'input'>) {
93
- return <input className={cx(className, 'flex-1 outline-none')} {...props} />
94
- }
95
-
96
- export function SearchInputMask({
97
- className,
98
- mask,
99
- customMask,
100
- ...props
101
- }: ComponentProps<'input'> & {
102
- mask?: InputMaskType
103
- customMask?: MaskOptions
104
- }) {
105
- return (
106
- <InputMaskComponent
107
- {...(mask ? { ...inputMask(mask) } : customMask && { ...customMask })}
108
- className={cx(className, 'flex-1 outline-none')}
109
- {...props}
110
- />
111
- )
112
- }
113
-
114
- export function SearchInputNumber({
115
- className,
116
- locales = 'pt-BR',
117
- groupDisplay = false,
118
- ...props
119
- }: InputNumberFormatProps) {
120
- return (
121
- <InputNumberFormat
122
- className={cx(className, 'flex-1 outline-none')}
123
- groupDisplay={groupDisplay}
124
- locales={locales}
125
- {...props}
126
- />
127
- )
128
- }
129
-
130
- export function SearchInputSlot(props: ComponentProps<'div'>) {
131
- return <div {...props} data-slot="search-input-slot" />
132
- }
133
-
134
- export function SearchInputAction({
135
- className,
136
- appearance = 'ghost',
137
- variant = 'outlined',
138
- ...props
139
- }: ButtonProps) {
140
- return (
141
- <Button
142
- {...props}
143
- appearance={appearance}
144
- className={cx(
145
- className,
146
- 'cursor-pointer',
147
- 'h-large-4x rounded-tr-circle rounded-br-circle px-small py-small_1x-alt flex items-center justify-center rounded-none',
148
- 'text-size-body-md text-neutral-dark gap-small-1x !border-l-0'
149
- )}
150
- data-slot="search-input-action"
151
- variant={variant}
152
- />
153
- )
154
- }
@@ -1,98 +0,0 @@
1
- import { useMemo, useState, type ComponentProps } from 'react'
2
- import type { MaskOptions } from '@react-input/mask'
3
- import type { InputMaskType } from '../../resources/input-mask'
4
- import {
5
- DropdownMenuRoot,
6
- DropdownMenuList,
7
- DropdownMenuItemText,
8
- DropdownMenuContent,
9
- DropdownMenuItem,
10
- DropdownMenuTrigger
11
- } from '../dropdown-menu'
12
- import { Icon } from '../icon'
13
- import {
14
- SearchInputContent,
15
- SearchInputRoot,
16
- SearchInputSlot,
17
- SearchInputAction,
18
- SearchInputMask,
19
- SearchInputText
20
- } from './search-input'
21
-
22
- interface SelectorOption {
23
- label: string
24
- value: string
25
- }
26
-
27
- interface SearchSelectorProps extends ComponentProps<'input'> {
28
- options: SelectorOption[]
29
- selectedSearchOption?: string
30
- mask?: InputMaskType
31
- customMask?: MaskOptions
32
-
33
- onChangeSearchOption?: (option: string) => void
34
- }
35
-
36
- export function SearchSelector({
37
- options,
38
- mask,
39
- customMask,
40
- placeholder = 'Pesquisar',
41
- onChangeSearchOption,
42
- selectedSearchOption: initialSelectedSearchOption,
43
- ...props
44
- }: SearchSelectorProps) {
45
- const [selectedSearchOption, setSelectedSearchOption] = useState(
46
- initialSelectedSearchOption
47
- )
48
-
49
- const selectedSearchLabel = useMemo(
50
- () => options.find(option => option.value === selectedSearchOption)?.label,
51
- [options, selectedSearchOption]
52
- )
53
-
54
- return (
55
- <SearchInputRoot className="w-full" variant="action">
56
- <SearchInputContent>
57
- <SearchInputSlot>
58
- <Icon className="text-icon-neutral-3" name="search" />
59
- </SearchInputSlot>
60
- {mask || customMask ? (
61
- <SearchInputMask
62
- customMask={customMask}
63
- mask={mask}
64
- placeholder={placeholder}
65
- {...props}
66
- />
67
- ) : (
68
- <SearchInputText placeholder={placeholder} {...props} />
69
- )}
70
- </SearchInputContent>
71
-
72
- <DropdownMenuRoot>
73
- <DropdownMenuTrigger asChild={true}>
74
- <SearchInputAction>
75
- {selectedSearchLabel}
76
- <Icon className="text-icon-neutral-3" name="keyboard_arrow_down" />
77
- </SearchInputAction>
78
- </DropdownMenuTrigger>
79
- <DropdownMenuContent>
80
- <DropdownMenuList>
81
- {options.map(option => (
82
- <DropdownMenuItem
83
- isActive={selectedSearchOption === option.value}
84
- key={option.value}
85
- onClick={() => {
86
- setSelectedSearchOption(option.value)
87
- onChangeSearchOption?.(option.value)
88
- }}
89
- >
90
- <DropdownMenuItemText>{option.label}</DropdownMenuItemText>
91
- </DropdownMenuItem>
92
- ))}
93
- </DropdownMenuList>
94
- </DropdownMenuContent>
95
- </DropdownMenuRoot>
96
- </SearchInputRoot>
97
- )
98
- }