@driveflux/ui 1.0.0-next.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.
- package/.eslintrc.json +3 -0
- package/.swcrc +14 -0
- package/.turbo/turbo-build.log +6 -0
- package/CHANGELOG.md +12 -0
- package/dist/chakra.d.ts +2 -0
- package/dist/chakra.d.ts.map +1 -0
- package/dist/chakra.js +1 -0
- package/dist/cjs/chakra.js +18 -0
- package/dist/cjs/index.js +18 -0
- package/dist/cjs/modal/ModalProvider.js +254 -0
- package/dist/cjs/modal/components/EnhancedModalCustomWrapper.js +139 -0
- package/dist/cjs/modal/components/EnhancedModalFooter.js +167 -0
- package/dist/cjs/modal/components/MinimalModalContent.js +94 -0
- package/dist/cjs/modal/components/StandardModalContent.js +387 -0
- package/dist/cjs/modal/context.js +20 -0
- package/dist/cjs/modal/index.js +48 -0
- package/dist/cjs/modal/use-enhanced-modal.js +15 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/theme/colors.js +140 -0
- package/dist/cjs/theme/index.js +18 -0
- package/dist/cjs/toast/index.js +19 -0
- package/dist/cjs/toast/use-toast-result.js +255 -0
- package/dist/cjs/types.js +4 -0
- package/dist/cjs/utils/accessors.js +61 -0
- package/dist/cjs/utils/index.js +19 -0
- package/dist/cjs/utils/react.js +94 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/modal/ModalProvider.d.ts +4 -0
- package/dist/modal/ModalProvider.d.ts.map +1 -0
- package/dist/modal/ModalProvider.js +239 -0
- package/dist/modal/components/EnhancedModalCustomWrapper.d.ts +9 -0
- package/dist/modal/components/EnhancedModalCustomWrapper.d.ts.map +1 -0
- package/dist/modal/components/EnhancedModalCustomWrapper.js +124 -0
- package/dist/modal/components/EnhancedModalFooter.d.ts +12 -0
- package/dist/modal/components/EnhancedModalFooter.d.ts.map +1 -0
- package/dist/modal/components/EnhancedModalFooter.js +157 -0
- package/dist/modal/components/MinimalModalContent.d.ts +11 -0
- package/dist/modal/components/MinimalModalContent.d.ts.map +1 -0
- package/dist/modal/components/MinimalModalContent.js +84 -0
- package/dist/modal/components/StandardModalContent.d.ts +11 -0
- package/dist/modal/components/StandardModalContent.d.ts.map +1 -0
- package/dist/modal/components/StandardModalContent.js +377 -0
- package/dist/modal/context.d.ts +62 -0
- package/dist/modal/context.d.ts.map +1 -0
- package/dist/modal/context.js +10 -0
- package/dist/modal/index.d.ts +7 -0
- package/dist/modal/index.d.ts.map +1 -0
- package/dist/modal/index.js +6 -0
- package/dist/modal/use-enhanced-modal.d.ts +3 -0
- package/dist/modal/use-enhanced-modal.d.ts.map +1 -0
- package/dist/modal/use-enhanced-modal.js +5 -0
- package/dist/theme/colors.d.ts +148 -0
- package/dist/theme/colors.d.ts.map +1 -0
- package/dist/theme/colors.js +130 -0
- package/dist/theme/index.d.ts +2 -0
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/theme/index.js +1 -0
- package/dist/toast/index.d.ts +2 -0
- package/dist/toast/index.d.ts.map +1 -0
- package/dist/toast/index.js +1 -0
- package/dist/toast/use-toast-result.d.ts +30 -0
- package/dist/toast/use-toast-result.d.ts.map +1 -0
- package/dist/toast/use-toast-result.js +232 -0
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/utils/accessors.d.ts +24 -0
- package/dist/utils/accessors.d.ts.map +1 -0
- package/dist/utils/accessors.js +28 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/react.d.ts +5 -0
- package/dist/utils/react.d.ts.map +1 -0
- package/dist/utils/react.js +32 -0
- package/index.cjs +1 -0
- package/index.d.ts +1 -0
- package/modal.cjs +1 -0
- package/modal.d.ts +1 -0
- package/package.json +68 -0
- package/src/chakra.ts +1 -0
- package/src/index.ts +1 -0
- package/src/modal/ModalProvider.tsx +142 -0
- package/src/modal/components/EnhancedModalCustomWrapper.tsx +39 -0
- package/src/modal/components/EnhancedModalFooter.tsx +51 -0
- package/src/modal/components/MinimalModalContent.tsx +24 -0
- package/src/modal/components/StandardModalContent.tsx +65 -0
- package/src/modal/context.tsx +81 -0
- package/src/modal/index.ts +7 -0
- package/src/modal/use-enhanced-modal.ts +7 -0
- package/src/theme/colors.ts +171 -0
- package/src/theme/index.ts +1 -0
- package/src/toast/index.ts +3 -0
- package/src/toast/use-toast-result.tsx +169 -0
- package/src/types.ts +22 -0
- package/src/utils/accessors.ts +64 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/react.ts +32 -0
- package/theme.cjs +1 -0
- package/theme.d.ts +1 -0
- package/toast.cjs +1 -0
- package/toast.d.ts +1 -0
- package/tsconfig.json +14 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/utils.cjs +1 -0
- package/utils.d.ts +1 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import type { Problem, ValidationIssues } from '@driveflux/problem'
|
|
2
|
+
import type { StandardResult } from '@driveflux/result'
|
|
3
|
+
import { t } from '@lingui/macro'
|
|
4
|
+
import merge from 'lodash/merge.js'
|
|
5
|
+
import { useCallback } from 'react'
|
|
6
|
+
import {
|
|
7
|
+
Box,
|
|
8
|
+
ListItem,
|
|
9
|
+
Text,
|
|
10
|
+
UnorderedList,
|
|
11
|
+
useToast,
|
|
12
|
+
type CreateToastFnReturn,
|
|
13
|
+
type ToastId,
|
|
14
|
+
type UseToastOptions
|
|
15
|
+
} from '../chakra.js'
|
|
16
|
+
import { accessReactNode, type ReactNodeAccessor } from '../utils/accessors.js'
|
|
17
|
+
|
|
18
|
+
export type StatusFn<T> = (data?: T) => UseToastOptions['status']
|
|
19
|
+
|
|
20
|
+
const accessStatus = <D,>(s?: UseToastOptions['status'] | StatusFn<D>, data?: D): UseToastOptions['status'] => {
|
|
21
|
+
return typeof s === 'function' ? s(data) : s
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type CustomUseToastOptions<T> = Omit<UseToastOptions, 'status' | 'title' | 'description'> & {
|
|
25
|
+
status?: UseToastOptions['status'] | StatusFn<T>
|
|
26
|
+
title?: UseToastOptions['title'] | ReactNodeAccessor<T>
|
|
27
|
+
description?: UseToastOptions['description'] | ReactNodeAccessor<T>
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type ErrorUseToastOptions<E = Problem> = CustomUseToastOptions<E> & {
|
|
31
|
+
showValidationErrors?: boolean
|
|
32
|
+
defaultDescription?: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
type UseToastResultOptions<S = any | Problem, E = Problem> = {
|
|
36
|
+
defaultOptions?: CustomUseToastOptions<S>
|
|
37
|
+
success?: CustomUseToastOptions<S> | boolean | null
|
|
38
|
+
error?: ErrorUseToastOptions<E> | boolean | null
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
type UseToastResult = {
|
|
42
|
+
toastProblem: <P extends Problem>(problem: P, providedOptions?: ErrorUseToastOptions<P>) => ToastId
|
|
43
|
+
toastSuccess: <T extends any>(providedOptions?: CustomUseToastOptions<T>) => ToastId
|
|
44
|
+
toastResult: <T extends unknown, R extends StandardResult<T> = StandardResult<T>>(
|
|
45
|
+
result: R,
|
|
46
|
+
generalToastOptions?: UseToastResultOptions<T, Problem>
|
|
47
|
+
) => ToastId | undefined
|
|
48
|
+
toastError: (providedOptions?: UseToastOptions) => ToastId
|
|
49
|
+
toast: CreateToastFnReturn
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const defaultUseToastResultOptions = {
|
|
53
|
+
success: {
|
|
54
|
+
status: 'success',
|
|
55
|
+
title: t`Success`,
|
|
56
|
+
description: t`The operation was done successfully`,
|
|
57
|
+
isClosable: true
|
|
58
|
+
},
|
|
59
|
+
error: {
|
|
60
|
+
status: 'error',
|
|
61
|
+
title: t`Operation Failed`,
|
|
62
|
+
defaultDescription: t`There was a problem while performing this operation`,
|
|
63
|
+
showValidationErrors: true,
|
|
64
|
+
isClosable: true
|
|
65
|
+
}
|
|
66
|
+
} as const satisfies UseToastResultOptions
|
|
67
|
+
|
|
68
|
+
export const getValidationErrorsList = (validation: ValidationIssues) => {
|
|
69
|
+
return Object.values(validation.fieldErrors)
|
|
70
|
+
.map((v) => v.map((vd) => vd.message))
|
|
71
|
+
.flat()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const accessOptions = <S,>(options?: CustomUseToastOptions<S>, data?: S): UseToastOptions | undefined => {
|
|
75
|
+
if (!options) {
|
|
76
|
+
return options
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
...options,
|
|
81
|
+
status: accessStatus(options.status, data),
|
|
82
|
+
title: accessReactNode(options.title, data),
|
|
83
|
+
description: accessReactNode(options.description, data)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export const useToastResult = (options?: UseToastResultOptions): UseToastResult => {
|
|
88
|
+
const originalToast = useToast(accessOptions(options?.defaultOptions))
|
|
89
|
+
|
|
90
|
+
const toastProblem: UseToastResult['toastProblem'] = useCallback(
|
|
91
|
+
(problem, providedOptions) => {
|
|
92
|
+
const { description, defaultDescription, showValidationErrors, ...rest } = merge(
|
|
93
|
+
{},
|
|
94
|
+
defaultUseToastResultOptions.error,
|
|
95
|
+
providedOptions
|
|
96
|
+
)
|
|
97
|
+
const problemMessage = problem.message || defaultDescription
|
|
98
|
+
return originalToast({
|
|
99
|
+
...accessOptions(rest, problem),
|
|
100
|
+
description: accessReactNode(description, problem) || (
|
|
101
|
+
<Box>
|
|
102
|
+
<>
|
|
103
|
+
{problemMessage && <Text color={'inherit'}>{problemMessage}</Text>}
|
|
104
|
+
{problem.validation && showValidationErrors && (
|
|
105
|
+
<UnorderedList color={'inherit'}>
|
|
106
|
+
{getValidationErrorsList(problem.validation).map((message, i) => (
|
|
107
|
+
<ListItem key={i}>{message}</ListItem>
|
|
108
|
+
))}
|
|
109
|
+
</UnorderedList>
|
|
110
|
+
)}
|
|
111
|
+
</>
|
|
112
|
+
</Box>
|
|
113
|
+
)
|
|
114
|
+
})
|
|
115
|
+
},
|
|
116
|
+
[originalToast]
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
const toastError: UseToastResult['toastError'] = useCallback(
|
|
120
|
+
(providedOptions) => {
|
|
121
|
+
const options = accessOptions(merge({}, defaultUseToastResultOptions.error, providedOptions))
|
|
122
|
+
return originalToast({
|
|
123
|
+
...options
|
|
124
|
+
})
|
|
125
|
+
},
|
|
126
|
+
[originalToast]
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
const toastSuccess: UseToastResult['toastSuccess'] = useCallback(
|
|
130
|
+
(providedOptions) => {
|
|
131
|
+
const options = accessOptions(merge({}, defaultUseToastResultOptions.success, providedOptions))
|
|
132
|
+
return originalToast({
|
|
133
|
+
...options
|
|
134
|
+
})
|
|
135
|
+
},
|
|
136
|
+
[originalToast]
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
const toastResult: UseToastResult['toastResult'] = useCallback(
|
|
140
|
+
(result, generalToastOptions) => {
|
|
141
|
+
const options = merge({}, defaultUseToastResultOptions, generalToastOptions || defaultUseToastResultOptions)
|
|
142
|
+
const toastType = result.ok ? 'success' : 'error'
|
|
143
|
+
const toastOptions =
|
|
144
|
+
typeof generalToastOptions === 'undefined' || generalToastOptions[toastType] === null
|
|
145
|
+
? null
|
|
146
|
+
: options[toastType]
|
|
147
|
+
if (!toastOptions) {
|
|
148
|
+
return
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const finalToastOptions = {
|
|
152
|
+
...(accessOptions(
|
|
153
|
+
typeof toastOptions === 'boolean' ? defaultUseToastResultOptions[toastType] : toastOptions,
|
|
154
|
+
result.val
|
|
155
|
+
) as UseToastOptions | ErrorUseToastOptions)
|
|
156
|
+
} as UseToastOptions | ErrorUseToastOptions
|
|
157
|
+
return result.ok ? toastSuccess(finalToastOptions) : toastProblem(result.val, finalToastOptions)
|
|
158
|
+
},
|
|
159
|
+
[originalToast, toastProblem, toastSuccess]
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
toastProblem,
|
|
164
|
+
toastSuccess,
|
|
165
|
+
toastResult,
|
|
166
|
+
toastError,
|
|
167
|
+
toast: originalToast
|
|
168
|
+
}
|
|
169
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type LengthUnits =
|
|
2
|
+
| 'cm'
|
|
3
|
+
| 'mm'
|
|
4
|
+
| 'in'
|
|
5
|
+
| 'px'
|
|
6
|
+
| 'pt'
|
|
7
|
+
| 'pc'
|
|
8
|
+
| 'em'
|
|
9
|
+
| 'ex'
|
|
10
|
+
| 'ch'
|
|
11
|
+
| 'vw'
|
|
12
|
+
| 'vh'
|
|
13
|
+
| 'rem'
|
|
14
|
+
| 'vmin'
|
|
15
|
+
| 'vmax'
|
|
16
|
+
| '%'
|
|
17
|
+
|
|
18
|
+
export type StyleUnit = number | `${number}${LengthUnits}`
|
|
19
|
+
|
|
20
|
+
export type Sizes = 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'xs' | '3xl' | '4xl' | '5xl' | '6xl' | 'full'
|
|
21
|
+
|
|
22
|
+
export type Padding = 'base' | 'md'
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ReactNode } from 'react'
|
|
2
|
+
|
|
3
|
+
type AllowedParam = string | number | boolean | Date | undefined | null
|
|
4
|
+
type AllowedQueryParams = Record<string, AllowedParam | AllowedParam[]>
|
|
5
|
+
|
|
6
|
+
export type GenericAccessor<O, R> = (m: O) => R
|
|
7
|
+
|
|
8
|
+
export type SelfAccessor<O, R = any> = GenericAccessor<O, R>
|
|
9
|
+
export type StringAccessor<O, R extends string = string> = GenericAccessor<O, R>
|
|
10
|
+
export type StringOrNullAccessor<O, R extends string = string> = GenericAccessor<O, R | null>
|
|
11
|
+
export type SelfPartialAccessor<O> = GenericAccessor<O, Partial<O>>
|
|
12
|
+
export type QueryAccessor<O, R extends AllowedQueryParams = AllowedQueryParams> = GenericAccessor<O, R>
|
|
13
|
+
export type ReactNodeAccessor<O> = GenericAccessor<O, ReactNode>
|
|
14
|
+
export type BooleanAccessor<O> = GenericAccessor<O, boolean>
|
|
15
|
+
export interface FunctionAccessor<O, F extends (...args: any[]) => any> { generateFunction: GenericAccessor<O, F> }
|
|
16
|
+
|
|
17
|
+
export type GuaranteedAccessor<AC extends (...args: any[]) => any> = (
|
|
18
|
+
arg1: Required<Parameters<AC>>[0],
|
|
19
|
+
arg2?: Parameters<AC>[1],
|
|
20
|
+
arg3?: Parameters<AC>[2],
|
|
21
|
+
arg4?: Parameters<AC>[3],
|
|
22
|
+
arg5?: Parameters<AC>[4]
|
|
23
|
+
) => ReturnType<AC>
|
|
24
|
+
|
|
25
|
+
export const accessSelf = <D, S, DS = S>(s: S, data?: D, defaultValue?: DS) => {
|
|
26
|
+
if (!s) {
|
|
27
|
+
return defaultValue
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return typeof s === 'function' ? s(data) : s
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const accessBoolean = <D>(s: boolean | BooleanAccessor<D>, data?: D, defaultBoolean?: boolean) =>
|
|
34
|
+
accessSelf(s, data, defaultBoolean)
|
|
35
|
+
|
|
36
|
+
export const accessString = <D>(s: string | StringAccessor<D>, data?: D, defaultText?: string) =>
|
|
37
|
+
accessSelf(s, data, defaultText)
|
|
38
|
+
|
|
39
|
+
export const accessStringOrNull = <D>(
|
|
40
|
+
s: string | null | StringOrNullAccessor<D>,
|
|
41
|
+
data?: D,
|
|
42
|
+
defaultText: string | null = null
|
|
43
|
+
) => accessSelf(s, data, defaultText)
|
|
44
|
+
|
|
45
|
+
export const accessQuery = <D>(
|
|
46
|
+
s: AllowedQueryParams | QueryAccessor<D>,
|
|
47
|
+
data?: D,
|
|
48
|
+
defaultQuery?: AllowedQueryParams
|
|
49
|
+
) => accessSelf(s, data, defaultQuery)
|
|
50
|
+
|
|
51
|
+
export const accessReactNode = <D>(s: ReactNode | ReactNodeAccessor<D>, data?: D, defaultNode?: ReactNode) =>
|
|
52
|
+
accessSelf(s, data, defaultNode)
|
|
53
|
+
|
|
54
|
+
export const accessFunction = <D, F extends (...args: any[]) => any>(
|
|
55
|
+
f: FunctionAccessor<D, F> | F,
|
|
56
|
+
data?: D,
|
|
57
|
+
defaultFunction?: F
|
|
58
|
+
) => {
|
|
59
|
+
if (!f) {
|
|
60
|
+
return defaultFunction
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return typeof f === 'object' && 'generateFunction' in f ? f.generateFunction(data as D) : f
|
|
64
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { default as React, isValidElement } from 'react'
|
|
2
|
+
|
|
3
|
+
export function isReactComponent(Component: any): Component is React.ComponentType<any> {
|
|
4
|
+
return (
|
|
5
|
+
typeof Component === 'function' &&
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- React component, it's fine
|
|
7
|
+
(Component.prototype instanceof React.Component || Component.displayName !== undefined)
|
|
8
|
+
)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function isReactElement(element: any): element is React.ReactElement {
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument -- isValidElement is a validation function
|
|
13
|
+
return isValidElement(element)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function isReactNode(node: any): node is React.ReactNode {
|
|
17
|
+
if (
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument -- isValidElement is a validation function
|
|
19
|
+
isValidElement(node) || // Check if it's a React element
|
|
20
|
+
typeof node === 'string' || // Check if it's a string
|
|
21
|
+
typeof node === 'number' // Check if it's a number
|
|
22
|
+
) {
|
|
23
|
+
return true
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Check if it's an array of React nodes
|
|
27
|
+
if (Array.isArray(node) && node.every((element) => isReactNode(element))) {
|
|
28
|
+
return true
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return false
|
|
32
|
+
}
|
package/theme.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./dist/cjs/theme/index.js')
|
package/theme.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dist/theme/index'
|
package/toast.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./dist/cjs/toast/index.js')
|
package/toast.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dist/toast/index'
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
+
"extends": "@driveflux/tsconfig/nextjs.json",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"declaration": true,
|
|
6
|
+
"rootDir": "src",
|
|
7
|
+
"outDir": "./dist"
|
|
8
|
+
},
|
|
9
|
+
"include": [
|
|
10
|
+
"src/**/*.ts",
|
|
11
|
+
"src/**/*.tsx"
|
|
12
|
+
],
|
|
13
|
+
"exclude": ["node_modules"]
|
|
14
|
+
}
|