@stack-spot/portal-components 2.15.1 → 2.16.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 (110) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/components/AnimatedHeight.d.ts +0 -1
  3. package/dist/components/AnimatedHeight.d.ts.map +1 -1
  4. package/dist/components/AsyncContent.d.ts.map +1 -1
  5. package/dist/components/BannerWarning.d.ts.map +1 -1
  6. package/dist/components/Breadcrumb/index.d.ts +0 -1
  7. package/dist/components/Breadcrumb/index.d.ts.map +1 -1
  8. package/dist/components/Breadcrumb/styled.d.ts +0 -1
  9. package/dist/components/Breadcrumb/styled.d.ts.map +1 -1
  10. package/dist/components/ButtonLoading.d.ts.map +1 -1
  11. package/dist/components/FadingOverflow.d.ts +0 -1
  12. package/dist/components/FadingOverflow.d.ts.map +1 -1
  13. package/dist/components/FileTreeView/index.d.ts.map +1 -1
  14. package/dist/components/InfiniteScroll.d.ts +1 -1
  15. package/dist/components/InfiniteScroll.d.ts.map +1 -1
  16. package/dist/components/LazyMarkdown/BlockquoteMd.d.ts.map +1 -1
  17. package/dist/components/LazyMarkdown/CodeViewer.d.ts.map +1 -1
  18. package/dist/components/LazyMarkdown/Markdown.d.ts.map +1 -1
  19. package/dist/components/LazyMarkdown/MarkdownButton.d.ts.map +1 -1
  20. package/dist/components/LazyMarkdown/Video.d.ts.map +1 -1
  21. package/dist/components/LazyMarkdown/index.d.ts.map +1 -1
  22. package/dist/components/Placeholder.d.ts +0 -1
  23. package/dist/components/Placeholder.d.ts.map +1 -1
  24. package/dist/components/ScrollView.d.ts +0 -1
  25. package/dist/components/ScrollView.d.ts.map +1 -1
  26. package/dist/components/Select/BadgeItem.d.ts +3 -0
  27. package/dist/components/Select/BadgeItem.d.ts.map +1 -0
  28. package/dist/components/Select/BadgeItem.js +5 -0
  29. package/dist/components/Select/BadgeItem.js.map +1 -0
  30. package/dist/components/Select/ClearInput.d.ts +3 -0
  31. package/dist/components/Select/ClearInput.d.ts.map +1 -0
  32. package/dist/components/Select/ClearInput.js +18 -0
  33. package/dist/components/Select/ClearInput.js.map +1 -0
  34. package/dist/components/Select/CloseItem.d.ts +3 -0
  35. package/dist/components/Select/CloseItem.d.ts.map +1 -0
  36. package/dist/components/Select/CloseItem.js +26 -0
  37. package/dist/components/Select/CloseItem.js.map +1 -0
  38. package/dist/components/Select/CreatableSelect.d.ts +15 -0
  39. package/dist/components/Select/CreatableSelect.d.ts.map +1 -0
  40. package/dist/components/Select/CreatableSelect.js +155 -0
  41. package/dist/components/Select/CreatableSelect.js.map +1 -0
  42. package/dist/components/Select/LabelItem.d.ts +3 -0
  43. package/dist/components/Select/LabelItem.d.ts.map +1 -0
  44. package/dist/components/Select/LabelItem.js +4 -0
  45. package/dist/components/Select/LabelItem.js.map +1 -0
  46. package/dist/components/Select/SelectSearch.d.ts +11 -0
  47. package/dist/components/Select/SelectSearch.d.ts.map +1 -0
  48. package/dist/components/Select/SelectSearch.js +128 -0
  49. package/dist/components/Select/SelectSearch.js.map +1 -0
  50. package/dist/components/Select/index.d.ts +4 -0
  51. package/dist/components/Select/index.d.ts.map +1 -0
  52. package/dist/components/Select/index.js +4 -0
  53. package/dist/components/Select/index.js.map +1 -0
  54. package/dist/components/Select/types.d.ts +7 -0
  55. package/dist/components/Select/types.d.ts.map +1 -0
  56. package/dist/components/Select/types.js +2 -0
  57. package/dist/components/Select/types.js.map +1 -0
  58. package/dist/components/SelectionList.d.ts.map +1 -1
  59. package/dist/components/StatusCircle.d.ts +0 -1
  60. package/dist/components/StatusCircle.d.ts.map +1 -1
  61. package/dist/components/TimelineSection.d.ts +0 -1
  62. package/dist/components/TimelineSection.d.ts.map +1 -1
  63. package/dist/components/error/ErrorFeedback.d.ts +0 -1
  64. package/dist/components/error/ErrorFeedback.d.ts.map +1 -1
  65. package/dist/components/error/NotFound.d.ts.map +1 -1
  66. package/dist/components/error/UnderMaintenance.d.ts.map +1 -1
  67. package/dist/components/form/SearchInput.d.ts.map +1 -1
  68. package/dist/components/form/Select/styled.d.ts +0 -1
  69. package/dist/components/form/Select/styled.d.ts.map +1 -1
  70. package/dist/components/notification/NotificationComponent.d.ts.map +1 -1
  71. package/dist/components/notification/NotificationItem.d.ts.map +1 -1
  72. package/dist/components/notification/NotificationList.d.ts +0 -1
  73. package/dist/components/notification/NotificationList.d.ts.map +1 -1
  74. package/dist/components/notification/NotificationPlaceholder.d.ts +0 -1
  75. package/dist/components/notification/NotificationPlaceholder.d.ts.map +1 -1
  76. package/dist/context/anchor.d.ts +0 -1
  77. package/dist/context/anchor.d.ts.map +1 -1
  78. package/dist/context/loading.d.ts.map +1 -1
  79. package/dist/context/notification/context.d.ts +0 -1
  80. package/dist/context/notification/context.d.ts.map +1 -1
  81. package/dist/hooks/keyboard.d.ts +0 -1
  82. package/dist/hooks/keyboard.d.ts.map +1 -1
  83. package/dist/hooks/text.d.ts +0 -1
  84. package/dist/hooks/text.d.ts.map +1 -1
  85. package/dist/hooks/use-effect-once.d.ts.map +1 -1
  86. package/dist/index.d.ts +1 -0
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +1 -0
  89. package/dist/index.js.map +1 -1
  90. package/dist/svg/AI.d.ts.map +1 -1
  91. package/dist/svg/CS.d.ts.map +1 -1
  92. package/dist/svg/EDP.d.ts.map +1 -1
  93. package/dist/svg/Forbidden.d.ts.map +1 -1
  94. package/dist/svg/GenericPlaceholder.d.ts.map +1 -1
  95. package/dist/svg/HUB.d.ts.map +1 -1
  96. package/dist/svg/Logo.d.ts.map +1 -1
  97. package/dist/svg/MiniLogo.d.ts.map +1 -1
  98. package/dist/svg/NotFound.d.ts.map +1 -1
  99. package/dist/svg/ServerError.d.ts.map +1 -1
  100. package/dist/svg/Unauthenticated.d.ts.map +1 -1
  101. package/package.json +2 -1
  102. package/src/components/Select/BadgeItem.tsx +8 -0
  103. package/src/components/Select/ClearInput.tsx +24 -0
  104. package/src/components/Select/CloseItem.tsx +38 -0
  105. package/src/components/Select/CreatableSelect.tsx +197 -0
  106. package/src/components/Select/LabelItem.tsx +8 -0
  107. package/src/components/Select/SelectSearch.tsx +167 -0
  108. package/src/components/Select/index.tsx +5 -0
  109. package/src/components/Select/types.ts +8 -0
  110. package/src/index.ts +1 -0
@@ -0,0 +1,197 @@
1
+ import { theme } from '@stack-spot/portal-theme'
2
+ import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
3
+ import { FC, useEffect, useState } from 'react'
4
+ import { CSSObjectWithLabel } from 'react-select'
5
+ import Creatable from 'react-select/creatable'
6
+ import { BadgeItem } from './BadgeItem'
7
+ import { ClearInput } from './ClearInput'
8
+ import { CloseItem } from './CloseItem'
9
+ import { LabelItem } from './LabelItem'
10
+ import { CreatableSelectOptionType, CreatableValueType } from './types'
11
+
12
+ export interface CreatableSelectProps {
13
+ id?: string,
14
+ name?: string,
15
+ disabled?: boolean,
16
+ isLoading?: boolean,
17
+ isMulti?: boolean,
18
+ options?: CreatableSelectOptionType[],
19
+ className?: string,
20
+ value?: string | string[],
21
+ onChange?: (newValue: CreatableValueType) => void,
22
+ }
23
+
24
+ export const CreatableSelect: FC<CreatableSelectProps> = ({ disabled, options, value, isMulti, onChange, id, ...props }) => {
25
+ const t = useTranslate(dictionary)
26
+ const [inputOptions, setInputOptions] = useState(options || [])
27
+ const prepareValue = () => {
28
+ let startValue: CreatableValueType | undefined = undefined
29
+ if (value) {
30
+ if (isMulti) {
31
+ const typedValue = value as string[] || []
32
+ startValue = [...typedValue].map((v) => ({ label: v, value: v }))
33
+ } else {
34
+ const typedValue = value as string
35
+ startValue = { label: typedValue, value: typedValue }
36
+ }
37
+ }
38
+ return startValue
39
+ }
40
+
41
+ const [inputValue, setInputValue] = useState<CreatableValueType | undefined>(prepareValue())
42
+
43
+ useEffect(() => {
44
+ const newValue = prepareValue()
45
+ inputValue !== newValue && setInputValue(newValue)
46
+ }, [value])
47
+
48
+
49
+ const handleCreate = (newValue: string) => {
50
+ const newOption = { label: newValue, value: newValue }
51
+ setInputOptions((prev) => [...prev, newOption])
52
+ if (isMulti) {
53
+ setInputValue((prev) => {
54
+ const previousValue = Array.isArray(prev) ? prev : []
55
+ const newInputValue = [...(previousValue as CreatableSelectOptionType[]), newOption]
56
+ setTimeout(() => {
57
+ onChange && onChange(newInputValue)
58
+ }, 100)
59
+ return newInputValue
60
+ })
61
+ } else {
62
+ setInputValue(newOption)
63
+ onChange && onChange(newOption)
64
+ }
65
+ }
66
+
67
+ const handleChange = (newValue: CreatableValueType) => {
68
+ setInputValue(newValue)
69
+ onChange && onChange(newValue)
70
+ }
71
+
72
+ return (
73
+ <Creatable
74
+ placeholder={t.typeYourOption}
75
+ {...props}
76
+ inputId={id}
77
+ isClearable={true}
78
+ isDisabled={disabled}
79
+ value={inputValue}
80
+ options={inputOptions}
81
+ isMulti={isMulti}
82
+ onChange={handleChange}
83
+ onCreateOption={handleCreate}
84
+ components={{ MultiValueContainer: BadgeItem, MultiValueLabel: LabelItem, MultiValueRemove: CloseItem, ClearIndicator: ClearInput }}
85
+ noOptionsMessage={() => (t.typeYourOption)}
86
+ formatCreateLabel={(value) => (value)}
87
+ tabSelectsValue={false}
88
+ styles={{
89
+ control: (base, state) => ({
90
+ ...base,
91
+ minHeight: '2.5rem',
92
+ height: 'auto',
93
+ backgroundColor: theme.color.light[300],
94
+ border: `0.063rem solid ${theme.color.light[600]}`,
95
+ borderRadius: '0.25rem',
96
+ fontSize: '0.875rem',
97
+ fontStyle: 'normal',
98
+ fontFeatureSettings: '\'clig\' off, \'liga\' off',
99
+ display: 'flex',
100
+ alignItems: 'center',
101
+ outlineColor: theme.color.light[700],
102
+
103
+ '&:hover': {
104
+ border: `0.063rem solid ${theme.color.light[600]}`,
105
+ },
106
+
107
+ ...(state.isFocused || state.menuIsOpen ? {
108
+ borderColor: `${theme.color.primary[500]} !important`,
109
+ outline: `0.063rem solid ${theme.color.primary[500]} !important`,
110
+ } : {}),
111
+ } as CSSObjectWithLabel),
112
+ input: () => ({
113
+ color: theme.color.light.contrastText,
114
+ }),
115
+ placeholder: () => ({
116
+ display: 'none',
117
+ }),
118
+ dropdownIndicator: () => ({
119
+ display: 'none',
120
+ }),
121
+ indicatorSeparator: () => ({
122
+ display: 'none',
123
+ }),
124
+ singleValue: (base) => ({
125
+ ...base,
126
+ color: theme.color.light.contrastText,
127
+ } as CSSObjectWithLabel),
128
+ menu: (base) => ({
129
+ ...base,
130
+ backgroundColor: theme.color.light[500],
131
+ border: `0.063rem solid ${theme.color.light[400]}`,
132
+ borderRadius: '0.5rem',
133
+ boxShadow: `0 0 0 0.125rem ${theme.color.gray[600]}`,
134
+ color: theme.color.light.contrastText,
135
+ } as CSSObjectWithLabel),
136
+ multiValue: (base) => ({
137
+ ...base,
138
+ backgroundColor: 'inherit',
139
+ display: 'flex',
140
+ alignItems: 'center',
141
+ justifyItems: 'center',
142
+ }),
143
+ multiValueRemove: (base) => ({
144
+ ...base,
145
+ cursor: 'pointer',
146
+ backgroundColor: 'inherit',
147
+ paddingRight: 0,
148
+ ':hover': {
149
+ backgroundColor: 'inherit',
150
+ color: 'inherit',
151
+ },
152
+ }),
153
+ option: (styles, { isDisabled, isFocused, isSelected }) => ({
154
+ ...styles,
155
+ backgroundColor: isDisabled
156
+ ? undefined
157
+ : isSelected
158
+ ? theme.color.light[700]
159
+ : isFocused
160
+ ? theme.color.light[600]
161
+ : undefined,
162
+
163
+ color: isSelected ? theme.color.light[300] : theme.color.light.contrastText,
164
+
165
+ cursor: isDisabled ? 'not-allowed' : 'default',
166
+
167
+ ':active': {
168
+ ...styles[':active'],
169
+ backgroundColor: !isDisabled
170
+ ? isSelected
171
+ ? theme.color.light.contrastText
172
+ : theme.color.light[600]
173
+ : undefined,
174
+ },
175
+
176
+ ':hover': {
177
+ ...styles[':hover'],
178
+ backgroundColor: !isDisabled
179
+ ? isSelected
180
+ ? theme.color.light[700]
181
+ : theme.color.light[600]
182
+ : undefined,
183
+ },
184
+ } as CSSObjectWithLabel),
185
+ }}
186
+ />
187
+ )
188
+ }
189
+
190
+ const dictionary = {
191
+ en: {
192
+ typeYourOption: 'Type your option',
193
+ },
194
+ pt: {
195
+ typeYourOption: 'Insira a sua opção',
196
+ },
197
+ } satisfies Dictionary
@@ -0,0 +1,8 @@
1
+ import { Box, Text } from '@citric/core'
2
+ import { MultiValueGenericProps } from 'react-select'
3
+
4
+ export const LabelItem = (props: MultiValueGenericProps<any>) => (
5
+ <Box>
6
+ <Text>{props.data.label}</Text>
7
+ </Box>
8
+ )
@@ -0,0 +1,167 @@
1
+ import { IconBox } from '@citric/core'
2
+ import { ChevronDown } from '@citric/icons'
3
+ import { theme } from '@stack-spot/portal-theme'
4
+ import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
5
+ import { ComponentProps, ComponentType, RefCallback } from 'react'
6
+ import Select, { components, CSSObjectWithLabel, Props as SelectProps } from 'react-select'
7
+ import { BadgeItem } from './BadgeItem'
8
+ import { ClearInput } from './ClearInput'
9
+ import { CloseItem } from './CloseItem'
10
+ import { LabelItem } from './LabelItem'
11
+
12
+ export interface SelectSearchProps extends Partial<SelectProps> {
13
+ options: any[],
14
+ components?: Partial<typeof components>,
15
+ disabled?: boolean,
16
+ onChange?: (newValue?: any) => void,
17
+ ref?: RefCallback<any>,
18
+ }
19
+
20
+ const EmptyComponent = () => <></>
21
+
22
+ const DropdownIndicator: ComponentType<ComponentProps<typeof components.DropdownIndicator>> = (props) => <IconBox
23
+ aria-hidden="true"
24
+ colorIcon="gray.50"
25
+ sx={{
26
+ cursor: 'pointer',
27
+ width: '10px',
28
+ height: '6px',
29
+ marginRight: '14px',
30
+ transition: 'transform 0.3s ease-in',
31
+ transform: `rotate(${props.selectProps.menuIsOpen ? '180' : '0'}deg)`,
32
+ }}
33
+ >
34
+ <ChevronDown />
35
+ </IconBox>
36
+
37
+ export const SelectSearch = ({
38
+ options,
39
+ components: customComponents = {},
40
+ onChange,
41
+ styles: customStyles = {},
42
+ disabled,
43
+ ref,
44
+ ...props
45
+ }: SelectSearchProps) => {
46
+ const t = useTranslate(dictionary)
47
+ return (
48
+ <Select
49
+ options={options}
50
+ onChange={onChange}
51
+ isDisabled={disabled}
52
+ ref={ref}
53
+ noOptionsMessage={() => t.noOptions}
54
+ {...props}
55
+ styles={{
56
+ ...customStyles,
57
+ control: (base, state) => ({
58
+ ...base,
59
+ height: '2.5rem',
60
+ display: 'flex',
61
+ alignItems: 'center',
62
+ padding: '0px',
63
+ color: theme.color.light.contrastText,
64
+ backgroundColor: theme.color.light[300],
65
+ border: `1px solid ${theme.color.light[600]}`,
66
+ outlineColor: theme.color.light[700],
67
+ '&:hover': {
68
+ border: `0.063rem solid ${theme.color.light[600]}`,
69
+ },
70
+ fontSize: '0.875rem',
71
+ lineHeight: '1.714',
72
+ fontFamily: 'Roboto, sans-serif',
73
+ ...(state.isFocused || state.menuIsOpen
74
+ ? {
75
+ borderColor: `${theme.color.primary[500]} !important`,
76
+ outline: `0.063rem solid ${theme.color.primary[500]} !important`,
77
+ }
78
+ : {}),
79
+ ...(state.isDisabled
80
+ ? {
81
+ backgroundColor: theme.color.light[500],
82
+ borderColor: theme.color.light[600],
83
+ cursor: 'not-allowed',
84
+ }
85
+ : {}),
86
+ ...customStyles?.control?.(base, state),
87
+ } as CSSObjectWithLabel),
88
+ input: (base, state) => ({
89
+ ...base,
90
+ color: theme.color.light.contrastText,
91
+ position: 'fixed',
92
+ ...customStyles?.input?.(base, state),
93
+ }),
94
+ menu: (base, state) => ({
95
+ ...base,
96
+ marginTop: '0.25rem',
97
+ position: 'relative',
98
+ ...customStyles?.menu?.(base, state),
99
+ }),
100
+ option: (base, state) => ({
101
+ ...base,
102
+ display: 'flex',
103
+ alignItems: 'center',
104
+ backgroundColor: theme.color.light[300],
105
+ cursor: 'pointer',
106
+ '&:hover': {
107
+ backgroundColor: theme.color.light[500],
108
+ },
109
+ border: '1px solid transparent',
110
+ ...(state.isFocused
111
+ ? {
112
+ borderColor: `${theme.color.light.contrastText} !important`,
113
+ }
114
+ : {}),
115
+ ...customStyles?.option?.(base, state),
116
+ }),
117
+ menuList: (base, state) => ({
118
+ ...base,
119
+ padding: 0,
120
+ '&::-webkit-scrollbar': {
121
+ width: '0.125rem',
122
+ height: '.5rem',
123
+ backgroundColor: 'transparent',
124
+ },
125
+ '&::-webkit-scrollbar-track': {
126
+ background: `${theme.color.light[300]}`,
127
+ borderRadius: '2px',
128
+ },
129
+ '&::-webkit-scrollbar-thumb': {
130
+ background: `${theme.color.primary[500]}`,
131
+ borderRadius: '2px',
132
+ },
133
+ '&::-webkit-scrollbar-thumb:hover': {
134
+ background: `${theme.color.light[700]}`,
135
+ borderRadius: '2px',
136
+ },
137
+ '&::-webkit-scrollbar-corner': {
138
+ backgroundColor: 'transparent',
139
+ },
140
+ ...customStyles?.menuList?.(base, state),
141
+ }),
142
+ }}
143
+ components={{
144
+ ...components,
145
+ DropdownIndicator,
146
+ IndicatorSeparator: EmptyComponent,
147
+ MultiValueContainer: BadgeItem,
148
+ MultiValueLabel: LabelItem,
149
+ MultiValueRemove: CloseItem,
150
+ ClearIndicator: ClearInput,
151
+ ...customComponents,
152
+ }}
153
+ />
154
+ )
155
+ }
156
+
157
+
158
+
159
+
160
+ const dictionary = {
161
+ en: {
162
+ noOptions: 'No options',
163
+ },
164
+ pt: {
165
+ noOptions: 'Sem opções',
166
+ },
167
+ } satisfies Dictionary
@@ -0,0 +1,5 @@
1
+ import { CreatableSelect } from './CreatableSelect'
2
+ import { SelectSearch, SelectSearchProps } from './SelectSearch'
3
+
4
+ export { CreatableSelect, SelectSearch, SelectSearchProps }
5
+
@@ -0,0 +1,8 @@
1
+ import { MultiValue, SingleValue } from 'react-select'
2
+
3
+ export type CreatableValueType = SingleValue<CreatableSelectOptionType> | MultiValue<CreatableSelectOptionType>
4
+
5
+ export interface CreatableSelectOptionType {
6
+ label: string,
7
+ value: string,
8
+ }
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@ export { AsyncContent } from './components/AsyncContent'
2
2
  export { BannerWarning } from './components/BannerWarning'
3
3
  export { ButtonLoading } from './components/ButtonLoading'
4
4
  export { ChatBot } from './components/ChatBot'
5
+ export * from './components/Select'
5
6
  export { useDateFormatter } from './hooks/date'
6
7
  export { useKeyboardControls } from './hooks/keyboard'
7
8
  export { useManualRender } from './hooks/manual-render'