@duro-app/ui 5.26.0 → 5.28.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/dist/components/CodeBlock/CodeBlock.d.ts +1 -1
- package/dist/components/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/components/CodeBlock/CodeBlock.meta.d.ts.map +1 -1
- package/dist/components/CodeBlock/CodeBlock.stories.d.ts +8 -0
- package/dist/components/CodeBlock/CodeBlock.stories.d.ts.map +1 -1
- package/dist/components/CodeBlock/DiffRows.d.ts +15 -0
- package/dist/components/CodeBlock/DiffRows.d.ts.map +1 -0
- package/dist/components/CodeBlock/diffRoles.d.ts +18 -0
- package/dist/components/CodeBlock/diffRoles.d.ts.map +1 -1
- package/dist/components/CodeBlock/styles.css.d.ts +43 -0
- package/dist/components/CodeBlock/styles.css.d.ts.map +1 -1
- package/dist/components/CodeBlock/types.d.ts +22 -0
- package/dist/components/CodeBlock/types.d.ts.map +1 -1
- package/dist/components/Select/Select.d.ts +6 -2
- package/dist/components/Select/Select.d.ts.map +1 -1
- package/dist/components/Select/Select.stories.d.ts +6 -0
- package/dist/components/Select/Select.stories.d.ts.map +1 -1
- package/dist/components/Select/SelectContext.d.ts +1 -1
- package/dist/components/Select/SelectContext.d.ts.map +1 -1
- package/dist/components/Select/selectState.d.ts +7 -1
- package/dist/components/Select/selectState.d.ts.map +1 -1
- package/dist/components/Select/styles.css.d.ts +4 -0
- package/dist/components/Select/styles.css.d.ts.map +1 -1
- package/dist/components/Select/useSelectRoot.d.ts.map +1 -1
- package/dist/components/Textarea/Textarea.d.ts +7 -1
- package/dist/components/Textarea/Textarea.d.ts.map +1 -1
- package/dist/components/Textarea/Textarea.stories.d.ts +6 -0
- package/dist/components/Textarea/Textarea.stories.d.ts.map +1 -1
- package/dist/components/Textarea/styles.css.d.ts +3 -0
- package/dist/components/Textarea/styles.css.d.ts.map +1 -1
- package/dist/components/Textarea/useFileDrop.d.ts +9 -0
- package/dist/components/Textarea/useFileDrop.d.ts.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3266 -3090
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/CodeBlock/CodeBlock.meta.ts +2 -1
- package/src/components/CodeBlock/CodeBlock.native.tsx +12 -1
- package/src/components/CodeBlock/CodeBlock.stories.tsx +98 -0
- package/src/components/CodeBlock/CodeBlock.tsx +28 -10
- package/src/components/CodeBlock/DiffRows.tsx +101 -0
- package/src/components/CodeBlock/diffRoles.ts +42 -0
- package/src/components/CodeBlock/styles.css.ts +41 -0
- package/src/components/CodeBlock/types.ts +24 -0
- package/src/components/Select/Select.meta.ts +1 -1
- package/src/components/Select/Select.native.tsx +15 -4
- package/src/components/Select/Select.stories.tsx +52 -0
- package/src/components/Select/Select.tsx +27 -6
- package/src/components/Select/SelectContext.ts +1 -1
- package/src/components/Select/selectState.ts +17 -1
- package/src/components/Select/styles.css.ts +4 -0
- package/src/components/Select/useSelectRoot.ts +32 -22
- package/src/components/Textarea/Textarea.meta.ts +1 -1
- package/src/components/Textarea/Textarea.stories.tsx +41 -0
- package/src/components/Textarea/Textarea.tsx +21 -0
- package/src/components/Textarea/styles.css.ts +3 -0
- package/src/components/Textarea/useFileDrop.native.ts +6 -0
- package/src/components/Textarea/useFileDrop.ts +46 -0
- package/src/index.native.ts +1 -0
- package/src/index.ts +1 -0
|
@@ -11,7 +11,7 @@ export interface SelectContextValue {
|
|
|
11
11
|
listboxId: string
|
|
12
12
|
highlightedId: string | null
|
|
13
13
|
setHighlightedId: (id: string | null) => void
|
|
14
|
-
registerItem: (id: string, value: string, element: HTMLElement) => () => void
|
|
14
|
+
registerItem: (id: string, value: string, element: HTMLElement, disabled?: boolean) => () => void
|
|
15
15
|
triggerRef: React.RefObject<HTMLButtonElement | null>
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {useCallback, useState} from 'react'
|
|
1
|
+
import {useCallback, useEffect, useRef, useState} from 'react'
|
|
2
2
|
import {useControllableValue} from '../../hooks/useControllableValue'
|
|
3
3
|
|
|
4
4
|
export interface SelectStateOptions {
|
|
@@ -6,6 +6,12 @@ export interface SelectStateOptions {
|
|
|
6
6
|
value?: string
|
|
7
7
|
onValueChange?: (value: string | null) => void
|
|
8
8
|
initialLabels?: Record<string, string>
|
|
9
|
+
/**
|
|
10
|
+
* Called when the list opens or closes, by any means (a press, a key, a pick,
|
|
11
|
+
* Escape, a press outside): for work that should start only once someone is
|
|
12
|
+
* choosing, such as checking which options are available.
|
|
13
|
+
*/
|
|
14
|
+
onOpenChange?: (open: boolean) => void
|
|
9
15
|
}
|
|
10
16
|
|
|
11
17
|
/**
|
|
@@ -19,6 +25,7 @@ export function useSelectState({
|
|
|
19
25
|
value: controlledValue,
|
|
20
26
|
onValueChange,
|
|
21
27
|
initialLabels,
|
|
28
|
+
onOpenChange,
|
|
22
29
|
}: SelectStateOptions) {
|
|
23
30
|
const [value, setValue] = useControllableValue<string | null>(
|
|
24
31
|
controlledValue,
|
|
@@ -26,6 +33,15 @@ export function useSelectState({
|
|
|
26
33
|
onValueChange,
|
|
27
34
|
)
|
|
28
35
|
const [open, setOpen] = useState(false)
|
|
36
|
+
// Reported after the change commits, once per transition; never for the first render.
|
|
37
|
+
const onOpenChangeRef = useRef(onOpenChange)
|
|
38
|
+
onOpenChangeRef.current = onOpenChange
|
|
39
|
+
const reportedOpenRef = useRef(open)
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (reportedOpenRef.current === open) return
|
|
42
|
+
reportedOpenRef.current = open
|
|
43
|
+
onOpenChangeRef.current?.(open)
|
|
44
|
+
}, [open])
|
|
29
45
|
const [labels, setLabels] = useState<Record<string, string>>(initialLabels ?? {})
|
|
30
46
|
|
|
31
47
|
const registerLabel = useCallback((v: string, label: string) => {
|
|
@@ -12,8 +12,15 @@ export function useSelectRoot(options: SelectStateOptions) {
|
|
|
12
12
|
const listboxId = useId()
|
|
13
13
|
const rootRef = useRef<HTMLDivElement>(null)
|
|
14
14
|
const triggerRef = useRef<HTMLButtonElement | null>(null)
|
|
15
|
-
const itemsRef = useRef(
|
|
15
|
+
const itemsRef = useRef(
|
|
16
|
+
new Map<string, {value: string; element: HTMLElement; disabled: boolean}>(),
|
|
17
|
+
)
|
|
16
18
|
const orderRef = useRef<string[]>([])
|
|
19
|
+
// What the keys move through: the options in document order, without the disabled ones.
|
|
20
|
+
const enabledOrder = useCallback(
|
|
21
|
+
() => orderRef.current.filter((id) => !itemsRef.current.get(id)?.disabled),
|
|
22
|
+
[],
|
|
23
|
+
)
|
|
17
24
|
|
|
18
25
|
const close = useCallback(() => {
|
|
19
26
|
setOpen(false)
|
|
@@ -25,7 +32,7 @@ export function useSelectRoot(options: SelectStateOptions) {
|
|
|
25
32
|
setOpen((prev) => {
|
|
26
33
|
if (!prev) {
|
|
27
34
|
const items = itemsRef.current
|
|
28
|
-
const order =
|
|
35
|
+
const order = enabledOrder()
|
|
29
36
|
let found: string | null = null
|
|
30
37
|
for (const id of order) {
|
|
31
38
|
const item = items.get(id)
|
|
@@ -40,24 +47,27 @@ export function useSelectRoot(options: SelectStateOptions) {
|
|
|
40
47
|
}
|
|
41
48
|
return !prev
|
|
42
49
|
})
|
|
43
|
-
}, [value, setOpen])
|
|
50
|
+
}, [value, setOpen, enabledOrder])
|
|
44
51
|
|
|
45
|
-
const registerItem = useCallback(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
52
|
+
const registerItem = useCallback(
|
|
53
|
+
(id: string, itemValue: string, element: HTMLElement, disabled = false) => {
|
|
54
|
+
itemsRef.current.set(id, {value: itemValue, element, disabled})
|
|
55
|
+
const map = itemsRef.current
|
|
56
|
+
const ids = [...map.keys()]
|
|
57
|
+
ids.sort((a, b) => {
|
|
58
|
+
const elA = map.get(a)?.element
|
|
59
|
+
const elB = map.get(b)?.element
|
|
60
|
+
if (!elA || !elB) return 0
|
|
61
|
+
return elA.compareDocumentPosition(elB) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1
|
|
62
|
+
})
|
|
63
|
+
orderRef.current = ids
|
|
64
|
+
return () => {
|
|
65
|
+
itemsRef.current.delete(id)
|
|
66
|
+
orderRef.current = orderRef.current.filter((i) => i !== id)
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
[],
|
|
70
|
+
)
|
|
61
71
|
|
|
62
72
|
// Closed: ArrowDown/ArrowUp on the trigger open the listbox (the APG
|
|
63
73
|
// select-only combobox), on the selected option or the first. In a Toolbar
|
|
@@ -82,7 +92,7 @@ export function useSelectRoot(options: SelectStateOptions) {
|
|
|
82
92
|
if (!root || !open) return
|
|
83
93
|
|
|
84
94
|
function handleKeyDown(e: KeyboardEvent) {
|
|
85
|
-
const order =
|
|
95
|
+
const order = enabledOrder()
|
|
86
96
|
const items = itemsRef.current
|
|
87
97
|
if (e.key === 'Escape') {
|
|
88
98
|
e.preventDefault()
|
|
@@ -124,7 +134,7 @@ export function useSelectRoot(options: SelectStateOptions) {
|
|
|
124
134
|
setHighlightedId((prev) => {
|
|
125
135
|
if (prev) {
|
|
126
136
|
const item = items.get(prev)
|
|
127
|
-
if (item) {
|
|
137
|
+
if (item && !item.disabled) {
|
|
128
138
|
setValue(item.value)
|
|
129
139
|
close()
|
|
130
140
|
}
|
|
@@ -142,7 +152,7 @@ export function useSelectRoot(options: SelectStateOptions) {
|
|
|
142
152
|
|
|
143
153
|
root.addEventListener('keydown', handleKeyDown)
|
|
144
154
|
return () => root.removeEventListener('keydown', handleKeyDown)
|
|
145
|
-
}, [open, close, setValue])
|
|
155
|
+
}, [open, close, setValue, enabledOrder])
|
|
146
156
|
|
|
147
157
|
const ctx: SelectContextValue = useMemo(
|
|
148
158
|
() => ({
|
|
@@ -2,7 +2,7 @@ import type {ComponentMeta} from '../component-meta'
|
|
|
2
2
|
|
|
3
3
|
export const meta: ComponentMeta = {
|
|
4
4
|
description:
|
|
5
|
-
'Multi-line text input with automatic Field/Form integration. Same Field binding behavior as Input. autoGrow makes the height follow the content from rows up to maxRows, then it scrolls (CSS field-sizing, with a scrollHeight fallback; native grows with the content and caps at maxRows). The anchor props of Listbox.getAnchorProps() (role combobox, aria-controls, aria-expanded, aria-activedescendant) are forwarded as ARIA attributes on web and as the matching accessibility props on native, so a Listbox can be anchored to it while the editor keeps focus.',
|
|
5
|
+
'Multi-line text input with automatic Field/Form integration. Same Field binding behavior as Input. autoGrow makes the height follow the content from rows up to maxRows, then it scrolls (CSS field-sizing, with a scrollHeight fallback; native grows with the content and caps at maxRows). The anchor props of Listbox.getAnchorProps() (role combobox, aria-controls, aria-expanded, aria-activedescendant) are forwarded as ARIA attributes on web and as the matching accessibility props on native, so a Listbox can be anchored to it while the editor keeps focus. On the web, onFiles receives files pasted into the field or dropped on it (the drop ring shows while files are dragged over it); text pastes stay text.',
|
|
6
6
|
whenToUse: [
|
|
7
7
|
'Multi-line text entry (comments, messages, descriptions)',
|
|
8
8
|
'A composer that grows with its text (autoGrow, maxRows)',
|
|
@@ -231,3 +231,44 @@ export const AnchoredListbox: Story = {
|
|
|
231
231
|
await expect(editor).toHaveFocus()
|
|
232
232
|
},
|
|
233
233
|
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* `onFiles` (web): a file pasted into the field or dropped on it goes to
|
|
237
|
+
* `onFiles`; while files are dragged over it the field shows the drop ring.
|
|
238
|
+
* Pasted text stays text.
|
|
239
|
+
*/
|
|
240
|
+
export const PasteAndDropFiles: Story = {
|
|
241
|
+
args: {placeholder: 'Paste or drop a screenshot', onFiles: fn()},
|
|
242
|
+
play: async ({canvas, args}) => {
|
|
243
|
+
const field = canvas.getByPlaceholderText('Paste or drop a screenshot')
|
|
244
|
+
const withFile = () => {
|
|
245
|
+
const transfer = new DataTransfer()
|
|
246
|
+
transfer.items.add(new File(['png'], 'shot.png', {type: 'image/png'}))
|
|
247
|
+
return transfer
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
field.dispatchEvent(
|
|
251
|
+
new ClipboardEvent('paste', {clipboardData: withFile(), bubbles: true, cancelable: true}),
|
|
252
|
+
)
|
|
253
|
+
await expect(args.onFiles).toHaveBeenCalledTimes(1)
|
|
254
|
+
await expect((args.onFiles as ReturnType<typeof fn>).mock.calls[0][0][0].name).toBe('shot.png')
|
|
255
|
+
|
|
256
|
+
const text = new DataTransfer()
|
|
257
|
+
text.setData('text/plain', 'hello')
|
|
258
|
+
field.dispatchEvent(
|
|
259
|
+
new ClipboardEvent('paste', {clipboardData: text, bubbles: true, cancelable: true}),
|
|
260
|
+
)
|
|
261
|
+
await expect(args.onFiles).toHaveBeenCalledTimes(1)
|
|
262
|
+
|
|
263
|
+
const ringBefore = getComputedStyle(field).boxShadow
|
|
264
|
+
field.dispatchEvent(
|
|
265
|
+
new DragEvent('dragenter', {dataTransfer: withFile(), bubbles: true, cancelable: true}),
|
|
266
|
+
)
|
|
267
|
+
await waitFor(() => expect(getComputedStyle(field).boxShadow).not.toBe(ringBefore))
|
|
268
|
+
const drop = new DragEvent('drop', {dataTransfer: withFile(), bubbles: true, cancelable: true})
|
|
269
|
+
field.dispatchEvent(drop)
|
|
270
|
+
await expect(drop.defaultPrevented).toBe(true)
|
|
271
|
+
await expect(args.onFiles).toHaveBeenCalledTimes(2)
|
|
272
|
+
await waitFor(() => expect(getComputedStyle(field).boxShadow).toBe(ringBefore))
|
|
273
|
+
},
|
|
274
|
+
}
|
|
@@ -3,6 +3,7 @@ import {html} from 'react-strict-dom'
|
|
|
3
3
|
import {useFieldContext} from '../Field/FieldContext'
|
|
4
4
|
import type {ListboxAnchorProps} from '../Listbox/Listbox'
|
|
5
5
|
import {useAutoGrowFallback} from './useAutoGrowFallback'
|
|
6
|
+
import {useFileDrop} from './useFileDrop'
|
|
6
7
|
import {grow} from './grow'
|
|
7
8
|
import {styles} from './styles.css'
|
|
8
9
|
|
|
@@ -39,6 +40,12 @@ interface TextareaBaseProps {
|
|
|
39
40
|
* navigation of a list driven by this field. */
|
|
40
41
|
onKeyDown?: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void
|
|
41
42
|
onKeyUp?: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void
|
|
43
|
+
/**
|
|
44
|
+
* Web: files pasted into the field or dropped on it (a screenshot, a log).
|
|
45
|
+
* The field shows the drop ring while files are dragged over it. Text
|
|
46
|
+
* pastes and drops stay text. Native: never called; attach with FileTrigger.
|
|
47
|
+
*/
|
|
48
|
+
onFiles?: (files: readonly File[]) => void
|
|
42
49
|
ref?: React.Ref<HTMLTextAreaElement>
|
|
43
50
|
}
|
|
44
51
|
|
|
@@ -65,6 +72,7 @@ export function Textarea({
|
|
|
65
72
|
onFocus,
|
|
66
73
|
onKeyDown,
|
|
67
74
|
onKeyUp,
|
|
75
|
+
onFiles,
|
|
68
76
|
ref,
|
|
69
77
|
}: TextareaProps) {
|
|
70
78
|
const ctx = useFieldContext()
|
|
@@ -92,6 +100,17 @@ export function Textarea({
|
|
|
92
100
|
[effectiveRef],
|
|
93
101
|
)
|
|
94
102
|
useAutoGrowFallback(innerRef, autoGrow ? 'content' : 'fixed')
|
|
103
|
+
const dropOver = useFileDrop(innerRef, onFiles)
|
|
104
|
+
const onPaste = onFiles
|
|
105
|
+
? // Structural: the native build (no DOM lib) types this file too; only the web pastes files.
|
|
106
|
+
(event: {clipboardData?: {files?: ArrayLike<File>} | null; preventDefault: () => void}) => {
|
|
107
|
+
const files = Array.from(event.clipboardData?.files ?? [])
|
|
108
|
+
if (files.length === 0) return
|
|
109
|
+
// Files only: the field keeps no file name as text.
|
|
110
|
+
event.preventDefault()
|
|
111
|
+
onFiles(files)
|
|
112
|
+
}
|
|
113
|
+
: undefined
|
|
95
114
|
|
|
96
115
|
return (
|
|
97
116
|
<html.textarea
|
|
@@ -112,6 +131,7 @@ export function Textarea({
|
|
|
112
131
|
onFocus={onFocus as StrictTextareaProps['onFocus']}
|
|
113
132
|
onKeyDown={onKeyDown as StrictTextareaProps['onKeyDown']}
|
|
114
133
|
onKeyUp={onKeyUp as StrictTextareaProps['onKeyUp']}
|
|
134
|
+
onPaste={onPaste as StrictTextareaProps['onPaste']}
|
|
115
135
|
role={role}
|
|
116
136
|
aria-controls={ariaControls}
|
|
117
137
|
aria-expanded={ariaExpanded}
|
|
@@ -124,6 +144,7 @@ export function Textarea({
|
|
|
124
144
|
styles[effectiveVariant],
|
|
125
145
|
autoGrow && grow.autoGrow,
|
|
126
146
|
autoGrow && maxRows !== undefined && grow.maxRows(maxRows),
|
|
147
|
+
dropOver && styles.dropOver,
|
|
127
148
|
]}
|
|
128
149
|
{...extraProps}
|
|
129
150
|
/>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {css} from 'react-strict-dom'
|
|
2
|
+
import {shadows} from '@duro-app/tokens/tokens/shadows.css'
|
|
2
3
|
import {colors} from '@duro-app/tokens/tokens/colors.css'
|
|
3
4
|
import {spacing, radii} from '@duro-app/tokens/tokens/spacing.css'
|
|
4
5
|
import {typography} from '@duro-app/tokens/tokens/typography.css'
|
|
@@ -56,4 +57,6 @@ export const styles = css.create({
|
|
|
56
57
|
':focus': colors.error,
|
|
57
58
|
},
|
|
58
59
|
},
|
|
60
|
+
// Files dragged over the field: the same ring as a DragDrop zone under the pointer.
|
|
61
|
+
dropOver: {boxShadow: shadows.dropOver},
|
|
59
62
|
})
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {useEffect, useState, type RefObject} from 'react'
|
|
2
|
+
|
|
3
|
+
const carriesFiles = (event: DragEvent) =>
|
|
4
|
+
Array.from(event.dataTransfer?.types ?? []).includes('Files')
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Files dropped on the field go to `onFiles`, and `over` says files are
|
|
8
|
+
* being dragged over it (for the drop ring). A listener on the element:
|
|
9
|
+
* react-strict-dom passes no drag events through. Text drags stay the
|
|
10
|
+
* browser's.
|
|
11
|
+
*/
|
|
12
|
+
export function useFileDrop(
|
|
13
|
+
ref: RefObject<HTMLTextAreaElement | null>,
|
|
14
|
+
onFiles: ((files: readonly File[]) => void) | undefined,
|
|
15
|
+
): boolean {
|
|
16
|
+
const [over, setOver] = useState(false)
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
const field = ref.current
|
|
19
|
+
if (!field || !onFiles) return
|
|
20
|
+
const enter = (event: DragEvent) => {
|
|
21
|
+
if (!carriesFiles(event)) return
|
|
22
|
+
// Claimed, or the browser opens the file instead of dropping it here.
|
|
23
|
+
event.preventDefault()
|
|
24
|
+
setOver(true)
|
|
25
|
+
}
|
|
26
|
+
const leave = () => setOver(false)
|
|
27
|
+
const drop = (event: DragEvent) => {
|
|
28
|
+
if (!carriesFiles(event)) return
|
|
29
|
+
event.preventDefault()
|
|
30
|
+
setOver(false)
|
|
31
|
+
const files = Array.from(event.dataTransfer?.files ?? [])
|
|
32
|
+
if (files.length > 0) onFiles(files)
|
|
33
|
+
}
|
|
34
|
+
field.addEventListener('dragenter', enter)
|
|
35
|
+
field.addEventListener('dragover', enter)
|
|
36
|
+
field.addEventListener('dragleave', leave)
|
|
37
|
+
field.addEventListener('drop', drop)
|
|
38
|
+
return () => {
|
|
39
|
+
field.removeEventListener('dragenter', enter)
|
|
40
|
+
field.removeEventListener('dragover', enter)
|
|
41
|
+
field.removeEventListener('dragleave', leave)
|
|
42
|
+
field.removeEventListener('drop', drop)
|
|
43
|
+
}
|
|
44
|
+
}, [onFiles, ref])
|
|
45
|
+
return over
|
|
46
|
+
}
|
package/src/index.native.ts
CHANGED
|
@@ -29,6 +29,7 @@ export {Textarea, type TextareaVariant} from './components/Textarea/Textarea'
|
|
|
29
29
|
|
|
30
30
|
// Text and layout
|
|
31
31
|
export {CodeBlock, type CodeBlockProps} from './components/CodeBlock/CodeBlock'
|
|
32
|
+
export type {CodeBlockLineAction, DiffLineInfo} from './components/CodeBlock/types'
|
|
32
33
|
export {Prose} from './components/Prose/Prose'
|
|
33
34
|
export {Toolbar, type ToolbarProps} from './components/Toolbar/Toolbar'
|
|
34
35
|
|
package/src/index.ts
CHANGED
|
@@ -32,6 +32,7 @@ export {Callout, type CalloutVariant} from './components/Callout/Callout'
|
|
|
32
32
|
export {Card, type CardVariant, type CardSize} from './components/Card/Card'
|
|
33
33
|
export {Checkbox} from './components/Checkbox/Checkbox'
|
|
34
34
|
export {CodeBlock} from './components/CodeBlock/CodeBlock'
|
|
35
|
+
export type {CodeBlockLineAction, DiffLineInfo} from './components/CodeBlock/types'
|
|
35
36
|
export {CheckboxGroup} from './components/CheckboxGroup/CheckboxGroup'
|
|
36
37
|
export {ColorInput} from './components/ColorInput/ColorInput'
|
|
37
38
|
export {ConfirmDialog} from './components/ConfirmDialog/ConfirmDialog'
|