@prosekit/web 0.7.3 → 0.7.5
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/{get-default-state-CIEy7xrl.js → get-default-state-BzBimBWi.js} +2 -1
- package/dist/get-default-state-BzBimBWi.js.map +1 -0
- package/dist/{get-safe-editor-view-DENm4avv.js → get-safe-editor-view-Dt9Amrcn.js} +2 -1
- package/dist/get-safe-editor-view-Dt9Amrcn.js.map +1 -0
- package/dist/{inject-style-D5jj7cme.js → inject-style-Dm6W58W3.js} +6 -9
- package/dist/inject-style-Dm6W58W3.js.map +1 -0
- package/dist/prosekit-web-autocomplete.d.ts +2 -1
- package/dist/prosekit-web-autocomplete.d.ts.map +1 -0
- package/dist/prosekit-web-autocomplete.js +9 -13
- package/dist/prosekit-web-autocomplete.js.map +1 -0
- package/dist/prosekit-web-block-handle.d.ts +2 -1
- package/dist/prosekit-web-block-handle.d.ts.map +1 -0
- package/dist/prosekit-web-block-handle.js +31 -31
- package/dist/prosekit-web-block-handle.js.map +1 -0
- package/dist/prosekit-web-drop-indicator.d.ts +2 -1
- package/dist/prosekit-web-drop-indicator.d.ts.map +1 -0
- package/dist/prosekit-web-drop-indicator.js +6 -6
- package/dist/prosekit-web-drop-indicator.js.map +1 -0
- package/dist/prosekit-web-inline-popover.d.ts +2 -1
- package/dist/prosekit-web-inline-popover.d.ts.map +1 -0
- package/dist/prosekit-web-inline-popover.js +8 -12
- package/dist/prosekit-web-inline-popover.js.map +1 -0
- package/dist/prosekit-web-popover.d.ts +2 -1
- package/dist/prosekit-web-popover.d.ts.map +1 -0
- package/dist/prosekit-web-popover.js +2 -1
- package/dist/prosekit-web-popover.js.map +1 -0
- package/dist/prosekit-web-resizable.d.ts +2 -1
- package/dist/prosekit-web-resizable.d.ts.map +1 -0
- package/dist/prosekit-web-resizable.js +5 -7
- package/dist/prosekit-web-resizable.js.map +1 -0
- package/dist/prosekit-web-table-handle.d.ts +2 -1
- package/dist/prosekit-web-table-handle.d.ts.map +1 -0
- package/dist/prosekit-web-table-handle.js +39 -72
- package/dist/prosekit-web-table-handle.js.map +1 -0
- package/dist/prosekit-web-tooltip.d.ts +2 -1
- package/dist/prosekit-web-tooltip.d.ts.map +1 -0
- package/dist/prosekit-web-tooltip.js +2 -1
- package/dist/prosekit-web-tooltip.js.map +1 -0
- package/dist/prosekit-web.js +1 -0
- package/dist/{use-editor-extension-Cc7ZG7uj.js → use-editor-extension-B2WuUfnd.js} +2 -1
- package/dist/use-editor-extension-B2WuUfnd.js.map +1 -0
- package/dist/{use-scrolling-BNfsQs3S.js → use-scrolling-BOvyjDvH.js} +2 -1
- package/dist/use-scrolling-BOvyjDvH.js.map +1 -0
- package/package.json +21 -21
- package/src/components/autocomplete/autocomplete-empty/element.gen.ts +18 -0
- package/src/components/autocomplete/autocomplete-empty/setup.ts +6 -0
- package/src/components/autocomplete/autocomplete-empty/types.ts +16 -0
- package/src/components/autocomplete/autocomplete-item/element.gen.ts +18 -0
- package/src/components/autocomplete/autocomplete-item/setup.ts +38 -0
- package/src/components/autocomplete/autocomplete-item/types.ts +31 -0
- package/src/components/autocomplete/autocomplete-list/element.gen.ts +18 -0
- package/src/components/autocomplete/autocomplete-list/setup.ts +140 -0
- package/src/components/autocomplete/autocomplete-list/types.ts +30 -0
- package/src/components/autocomplete/autocomplete-popover/element.gen.ts +18 -0
- package/src/components/autocomplete/autocomplete-popover/helpers.spec.ts +21 -0
- package/src/components/autocomplete/autocomplete-popover/helpers.ts +7 -0
- package/src/components/autocomplete/autocomplete-popover/setup.ts +185 -0
- package/src/components/autocomplete/autocomplete-popover/types.ts +103 -0
- package/src/components/autocomplete/context.ts +19 -0
- package/src/components/autocomplete/index.gen.ts +17 -0
- package/src/components/block-handle/block-handle-add/element.gen.ts +18 -0
- package/src/components/block-handle/block-handle-add/setup.ts +37 -0
- package/src/components/block-handle/block-handle-add/types.ts +26 -0
- package/src/components/block-handle/block-handle-draggable/element.gen.ts +18 -0
- package/src/components/block-handle/block-handle-draggable/set-drag-preview.ts +88 -0
- package/src/components/block-handle/block-handle-draggable/setup.ts +133 -0
- package/src/components/block-handle/block-handle-draggable/types.ts +26 -0
- package/src/components/block-handle/block-handle-popover/element.gen.ts +18 -0
- package/src/components/block-handle/block-handle-popover/pointer-move.ts +262 -0
- package/src/components/block-handle/block-handle-popover/setup.ts +88 -0
- package/src/components/block-handle/block-handle-popover/types.ts +84 -0
- package/src/components/block-handle/context.ts +34 -0
- package/src/components/block-handle/index.gen.ts +13 -0
- package/src/components/drop-indicator/drop-indicator/element.gen.ts +18 -0
- package/src/components/drop-indicator/drop-indicator/setup.ts +87 -0
- package/src/components/drop-indicator/drop-indicator/types.ts +34 -0
- package/src/components/drop-indicator/index.gen.ts +5 -0
- package/src/components/inline-popover/index.gen.ts +5 -0
- package/src/components/inline-popover/inline-popover/element.gen.ts +18 -0
- package/src/components/inline-popover/inline-popover/setup.ts +97 -0
- package/src/components/inline-popover/inline-popover/types.ts +115 -0
- package/src/components/inline-popover/inline-popover/virtual-selection-element.ts +75 -0
- package/src/components/popover/index.gen.ts +13 -0
- package/src/components/popover/popover-content/element.gen.ts +18 -0
- package/src/components/popover/popover-content/setup.ts +1 -0
- package/src/components/popover/popover-content/types.ts +12 -0
- package/src/components/popover/popover-root/element.gen.ts +18 -0
- package/src/components/popover/popover-root/setup.ts +1 -0
- package/src/components/popover/popover-root/types.ts +12 -0
- package/src/components/popover/popover-trigger/element.gen.ts +18 -0
- package/src/components/popover/popover-trigger/setup.ts +1 -0
- package/src/components/popover/popover-trigger/types.ts +12 -0
- package/src/components/resizable/context.ts +45 -0
- package/src/components/resizable/index.gen.ts +9 -0
- package/src/components/resizable/resizable-handle/calc-resize.spec.ts +280 -0
- package/src/components/resizable/resizable-handle/calc-resize.ts +121 -0
- package/src/components/resizable/resizable-handle/element.gen.ts +18 -0
- package/src/components/resizable/resizable-handle/setup.ts +112 -0
- package/src/components/resizable/resizable-handle/types.ts +32 -0
- package/src/components/resizable/resizable-root/element.gen.ts +18 -0
- package/src/components/resizable/resizable-root/setup.ts +93 -0
- package/src/components/resizable/resizable-root/types.ts +28 -0
- package/src/components/table-handle/context.ts +49 -0
- package/src/components/table-handle/dnd.ts +135 -0
- package/src/components/table-handle/hooks/use-drop.ts +94 -0
- package/src/components/table-handle/hooks/use-empty-image.ts +30 -0
- package/src/components/table-handle/index.gen.ts +37 -0
- package/src/components/table-handle/table-handle-column-root/element.gen.ts +18 -0
- package/src/components/table-handle/table-handle-column-root/setup.ts +71 -0
- package/src/components/table-handle/table-handle-column-root/types.ts +76 -0
- package/src/components/table-handle/table-handle-column-trigger/element.gen.ts +18 -0
- package/src/components/table-handle/table-handle-column-trigger/setup.ts +75 -0
- package/src/components/table-handle/table-handle-column-trigger/types.ts +23 -0
- package/src/components/table-handle/table-handle-drag-preview/element.gen.ts +18 -0
- package/src/components/table-handle/table-handle-drag-preview/render-preview.ts +80 -0
- package/src/components/table-handle/table-handle-drag-preview/setup.ts +67 -0
- package/src/components/table-handle/table-handle-drag-preview/types.ts +17 -0
- package/src/components/table-handle/table-handle-drag-preview/updater.ts +101 -0
- package/src/components/table-handle/table-handle-drop-indicator/calc-drag-over.ts +44 -0
- package/src/components/table-handle/table-handle-drop-indicator/element.gen.ts +18 -0
- package/src/components/table-handle/table-handle-drop-indicator/setup.ts +56 -0
- package/src/components/table-handle/table-handle-drop-indicator/types.ts +18 -0
- package/src/components/table-handle/table-handle-drop-indicator/updater.ts +110 -0
- package/src/components/table-handle/table-handle-popover-content/element.gen.ts +18 -0
- package/src/components/table-handle/table-handle-popover-content/setup.ts +90 -0
- package/src/components/table-handle/table-handle-popover-content/types.ts +40 -0
- package/src/components/table-handle/table-handle-popover-item/element.gen.ts +18 -0
- package/src/components/table-handle/table-handle-popover-item/setup.ts +23 -0
- package/src/components/table-handle/table-handle-popover-item/types.ts +24 -0
- package/src/components/table-handle/table-handle-root/element.gen.ts +18 -0
- package/src/components/table-handle/table-handle-root/setup.ts +93 -0
- package/src/components/table-handle/table-handle-root/types.ts +26 -0
- package/src/components/table-handle/table-handle-row-root/element.gen.ts +18 -0
- package/src/components/table-handle/table-handle-row-root/setup.ts +77 -0
- package/src/components/table-handle/table-handle-row-root/types.ts +75 -0
- package/src/components/table-handle/table-handle-row-trigger/element.gen.ts +18 -0
- package/src/components/table-handle/table-handle-row-trigger/setup.ts +74 -0
- package/src/components/table-handle/table-handle-row-trigger/types.ts +26 -0
- package/src/components/table-handle/utils.ts +107 -0
- package/src/components/tooltip/index.gen.ts +13 -0
- package/src/components/tooltip/tooltip-content/element.gen.ts +18 -0
- package/src/components/tooltip/tooltip-content/setup.ts +1 -0
- package/src/components/tooltip/tooltip-content/types.ts +12 -0
- package/src/components/tooltip/tooltip-root/element.gen.ts +18 -0
- package/src/components/tooltip/tooltip-root/setup.ts +1 -0
- package/src/components/tooltip/tooltip-root/types.ts +12 -0
- package/src/components/tooltip/tooltip-trigger/element.gen.ts +18 -0
- package/src/components/tooltip/tooltip-trigger/setup.ts +1 -0
- package/src/components/tooltip/tooltip-trigger/types.ts +12 -0
- package/src/hooks/use-editor-extension.ts +19 -0
- package/src/hooks/use-editor-focus-event.ts +23 -0
- package/src/hooks/use-editor-typing.ts +36 -0
- package/src/hooks/use-editor-update-event.ts +23 -0
- package/src/hooks/use-first-rendering.ts +20 -0
- package/src/hooks/use-keymap.ts +20 -0
- package/src/hooks/use-scrolling.ts +33 -0
- package/src/hooks/use-selecting.ts +63 -0
- package/src/index.ts +1 -0
- package/src/utils/assign-styles.ts +14 -0
- package/src/utils/clone-element.ts +110 -0
- package/src/utils/css-feature-detection.ts +9 -0
- package/src/utils/fade-color.ts +15 -0
- package/src/utils/get-box-element.ts +20 -0
- package/src/utils/get-client-rect.ts +35 -0
- package/src/utils/get-default-state.spec.ts +50 -0
- package/src/utils/get-default-state.ts +22 -0
- package/src/utils/get-effective-background-color.ts +21 -0
- package/src/utils/get-safe-editor-view.ts +10 -0
- package/src/utils/inject-style.ts +11 -0
- package/src/utils/is-finite-positive-number.ts +3 -0
- package/src/utils/max-z-index.ts +3 -0
- package/src/utils/throttle.ts +17 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineCustomElement, registerCustomElement, type BaseElementConstructor } from "@aria-ui/core"
|
|
2
|
+
|
|
3
|
+
import { useTooltipTrigger } from "./setup"
|
|
4
|
+
import { tooltipTriggerEvents, tooltipTriggerProps, type TooltipTriggerEvents, type TooltipTriggerProps } from "./types"
|
|
5
|
+
|
|
6
|
+
const TooltipTriggerElementBase: BaseElementConstructor<TooltipTriggerProps> = defineCustomElement<
|
|
7
|
+
TooltipTriggerProps,
|
|
8
|
+
TooltipTriggerEvents
|
|
9
|
+
>({
|
|
10
|
+
props: tooltipTriggerProps,
|
|
11
|
+
events: tooltipTriggerEvents,
|
|
12
|
+
setup: useTooltipTrigger,
|
|
13
|
+
})
|
|
14
|
+
class TooltipTriggerElement extends TooltipTriggerElementBase {}
|
|
15
|
+
|
|
16
|
+
registerCustomElement('prosekit-tooltip-trigger', TooltipTriggerElement)
|
|
17
|
+
|
|
18
|
+
export { TooltipTriggerElement }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useTooltipTrigger } from '@aria-ui/tooltip/elements'
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
TooltipTriggerEvents as Events,
|
|
3
|
+
TooltipTriggerProps as Props,
|
|
4
|
+
} from '@aria-ui/tooltip/elements'
|
|
5
|
+
|
|
6
|
+
export {
|
|
7
|
+
tooltipTriggerEvents,
|
|
8
|
+
tooltipTriggerProps,
|
|
9
|
+
} from '@aria-ui/tooltip/elements'
|
|
10
|
+
|
|
11
|
+
export interface TooltipTriggerProps extends Props {}
|
|
12
|
+
export interface TooltipTriggerEvents extends Events {}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useEffect,
|
|
3
|
+
type ConnectableElement,
|
|
4
|
+
type ReadonlySignal,
|
|
5
|
+
} from '@aria-ui/core'
|
|
6
|
+
import type {
|
|
7
|
+
Editor,
|
|
8
|
+
Extension,
|
|
9
|
+
} from '@prosekit/core'
|
|
10
|
+
|
|
11
|
+
export function useEditorExtension(
|
|
12
|
+
host: ConnectableElement,
|
|
13
|
+
editor: ReadonlySignal<Editor | null>,
|
|
14
|
+
extension: Extension,
|
|
15
|
+
): void {
|
|
16
|
+
useEffect(host, () => {
|
|
17
|
+
return editor.get()?.use(extension)
|
|
18
|
+
})
|
|
19
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ConnectableElement,
|
|
3
|
+
ReadonlySignal,
|
|
4
|
+
} from '@aria-ui/core'
|
|
5
|
+
import {
|
|
6
|
+
defineFocusChangeHandler,
|
|
7
|
+
type Editor,
|
|
8
|
+
type FocusChangeHandler,
|
|
9
|
+
} from '@prosekit/core'
|
|
10
|
+
|
|
11
|
+
import { useEditorExtension } from './use-editor-extension'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export function useEditorFocusChangeEvent(
|
|
17
|
+
host: ConnectableElement,
|
|
18
|
+
editor: ReadonlySignal<Editor | null>,
|
|
19
|
+
handler: FocusChangeHandler,
|
|
20
|
+
): void {
|
|
21
|
+
const extension = defineFocusChangeHandler(handler)
|
|
22
|
+
useEditorExtension(host, editor, extension)
|
|
23
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createSignal,
|
|
3
|
+
type ConnectableElement,
|
|
4
|
+
type ReadonlySignal,
|
|
5
|
+
} from '@aria-ui/core'
|
|
6
|
+
import {
|
|
7
|
+
defineDOMEventHandler,
|
|
8
|
+
union,
|
|
9
|
+
type Editor,
|
|
10
|
+
} from '@prosekit/core'
|
|
11
|
+
|
|
12
|
+
import { useEditorExtension } from './use-editor-extension'
|
|
13
|
+
|
|
14
|
+
export function useEditorTyping(
|
|
15
|
+
host: ConnectableElement,
|
|
16
|
+
editor: ReadonlySignal<Editor | null>,
|
|
17
|
+
): ReadonlySignal<boolean> {
|
|
18
|
+
const typing = createSignal(false)
|
|
19
|
+
|
|
20
|
+
const handleKeypress = () => {
|
|
21
|
+
typing.set(true)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const handlePointerMove = () => {
|
|
25
|
+
typing.set(false)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const extension = union(
|
|
29
|
+
defineDOMEventHandler('keypress', handleKeypress),
|
|
30
|
+
defineDOMEventHandler('pointermove', handlePointerMove),
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
useEditorExtension(host, editor, extension)
|
|
34
|
+
|
|
35
|
+
return typing
|
|
36
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ConnectableElement,
|
|
3
|
+
ReadonlySignal,
|
|
4
|
+
} from '@aria-ui/core'
|
|
5
|
+
import {
|
|
6
|
+
defineUpdateHandler,
|
|
7
|
+
type Editor,
|
|
8
|
+
type UpdateHandler,
|
|
9
|
+
} from '@prosekit/core'
|
|
10
|
+
|
|
11
|
+
import { useEditorExtension } from './use-editor-extension'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export function useEditorUpdateEvent(
|
|
17
|
+
host: ConnectableElement,
|
|
18
|
+
editor: ReadonlySignal<Editor | null>,
|
|
19
|
+
handler: UpdateHandler,
|
|
20
|
+
): void {
|
|
21
|
+
const extension = defineUpdateHandler(handler)
|
|
22
|
+
useEditorExtension(host, editor, extension)
|
|
23
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createSignal,
|
|
3
|
+
useEffect,
|
|
4
|
+
type ConnectableElement,
|
|
5
|
+
type ReadonlySignal,
|
|
6
|
+
} from '@aria-ui/core'
|
|
7
|
+
|
|
8
|
+
export function useFirstRendering(
|
|
9
|
+
host: ConnectableElement,
|
|
10
|
+
): ReadonlySignal<boolean> {
|
|
11
|
+
const firstRendering = createSignal(true)
|
|
12
|
+
|
|
13
|
+
useEffect(host, () => {
|
|
14
|
+
requestAnimationFrame(() => {
|
|
15
|
+
firstRendering.set(false)
|
|
16
|
+
})
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
return firstRendering
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ConnectableElement,
|
|
3
|
+
ReadonlySignal,
|
|
4
|
+
} from '@aria-ui/core'
|
|
5
|
+
import {
|
|
6
|
+
defineKeymap,
|
|
7
|
+
type Editor,
|
|
8
|
+
type Keymap,
|
|
9
|
+
} from '@prosekit/core'
|
|
10
|
+
|
|
11
|
+
import { useEditorExtension } from './use-editor-extension'
|
|
12
|
+
|
|
13
|
+
export function useKeymap(
|
|
14
|
+
host: ConnectableElement,
|
|
15
|
+
editor: ReadonlySignal<Editor | null>,
|
|
16
|
+
keymap: Keymap,
|
|
17
|
+
): void {
|
|
18
|
+
const extension = defineKeymap(keymap)
|
|
19
|
+
useEditorExtension(host, editor, extension)
|
|
20
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createSignal,
|
|
3
|
+
useEffect,
|
|
4
|
+
type ConnectableElement,
|
|
5
|
+
type ReadonlySignal,
|
|
6
|
+
} from '@aria-ui/core'
|
|
7
|
+
import { getNearestOverflowAncestor } from '@zag-js/dom-query'
|
|
8
|
+
|
|
9
|
+
export function useScrolling(host: ConnectableElement): ReadonlySignal<boolean> {
|
|
10
|
+
const scrolling = createSignal(false)
|
|
11
|
+
|
|
12
|
+
useEffect(host, () => {
|
|
13
|
+
const scrollableParent = getNearestOverflowAncestor(host)
|
|
14
|
+
|
|
15
|
+
const handleScroll = () => {
|
|
16
|
+
scrolling.set(true)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const handleMouseMove = () => {
|
|
20
|
+
scrolling.set(false)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
scrollableParent.addEventListener('scroll', handleScroll, { passive: true })
|
|
24
|
+
window.addEventListener('mousemove', handleMouseMove, { passive: true })
|
|
25
|
+
|
|
26
|
+
return () => {
|
|
27
|
+
scrollableParent.removeEventListener('scroll', handleScroll)
|
|
28
|
+
window.removeEventListener('mousemove', handleMouseMove)
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
return scrolling
|
|
33
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { ReadonlySignal } from '@aria-ui/core'
|
|
2
|
+
import {
|
|
3
|
+
createSignal,
|
|
4
|
+
useEffect,
|
|
5
|
+
type ConnectableElement,
|
|
6
|
+
} from '@aria-ui/core'
|
|
7
|
+
import type { Editor } from '@prosekit/core'
|
|
8
|
+
|
|
9
|
+
import { getSafeEditorView } from '../utils/get-safe-editor-view'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Detect if the user is selecting text inside the editor, in which case some
|
|
13
|
+
* components should be disabled or hidden.
|
|
14
|
+
*/
|
|
15
|
+
export function useSelecting(
|
|
16
|
+
host: ConnectableElement,
|
|
17
|
+
editor: ReadonlySignal<Editor | null>,
|
|
18
|
+
enabled: ReadonlySignal<boolean>,
|
|
19
|
+
): ReadonlySignal<boolean> {
|
|
20
|
+
const selecting = createSignal(false)
|
|
21
|
+
const isPointerDown = createSignal(false)
|
|
22
|
+
|
|
23
|
+
useEffect(host, () => {
|
|
24
|
+
if (!enabled.get()) {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const view = getSafeEditorView(editor.peek())
|
|
29
|
+
if (!view) return
|
|
30
|
+
|
|
31
|
+
const { dom, root } = view
|
|
32
|
+
if (!root) return
|
|
33
|
+
|
|
34
|
+
// When the user starts selecting text, we set the selecting signal to true.
|
|
35
|
+
const handlePointerDown = () => {
|
|
36
|
+
selecting.set(true)
|
|
37
|
+
isPointerDown.set(true)
|
|
38
|
+
}
|
|
39
|
+
const handlePointerUp = () => {
|
|
40
|
+
isPointerDown.set(false)
|
|
41
|
+
}
|
|
42
|
+
// When the user moves the pointer and the pointer is not down, we set the
|
|
43
|
+
// selecting signal to false again.
|
|
44
|
+
const handleMouseMove = () => {
|
|
45
|
+
if (!isPointerDown.get()) {
|
|
46
|
+
selecting.set(false)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Only listen to pointer down events on the editor
|
|
51
|
+
dom.addEventListener('pointerdown', handlePointerDown)
|
|
52
|
+
root.addEventListener('pointerup', handlePointerUp)
|
|
53
|
+
root.addEventListener('pointermove', handleMouseMove)
|
|
54
|
+
|
|
55
|
+
return () => {
|
|
56
|
+
dom.removeEventListener('pointerdown', handlePointerDown)
|
|
57
|
+
root.removeEventListener('pointerup', handlePointerUp)
|
|
58
|
+
root.removeEventListener('pointermove', handleMouseMove)
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
return selecting
|
|
63
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ConditionalPick } from 'type-fest'
|
|
2
|
+
|
|
3
|
+
// Only include CSS properties whose value type is `string`
|
|
4
|
+
type StringStyleDeclaration = Partial<ConditionalPick<CSSStyleDeclaration, string>>
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A type-safe version of `Object.assign` for `element.style`.
|
|
8
|
+
*/
|
|
9
|
+
export function assignStyles(
|
|
10
|
+
element: HTMLElement | SVGElement | MathMLElement,
|
|
11
|
+
styles: StringStyleDeclaration,
|
|
12
|
+
): void {
|
|
13
|
+
Object.assign(element.style, styles)
|
|
14
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { getId } from '@ocavue/utils'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates a deep clone of an Element, including all computed styles so that
|
|
5
|
+
* it looks almost exactly the same as the original element.
|
|
6
|
+
*/
|
|
7
|
+
export function deepCloneElement<T extends Element>(element: T, important = false): [T, string] {
|
|
8
|
+
const clonedElement = element.cloneNode(true) as T
|
|
9
|
+
const style = deepCopyStyles(element, clonedElement, important)
|
|
10
|
+
return [clonedElement, style]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Creates a clone of an Element, including all computed styles so that
|
|
15
|
+
* it looks similar enough to the original element.
|
|
16
|
+
*/
|
|
17
|
+
export function cloneElement<T extends Element>(element: T, important = false): [T, string] {
|
|
18
|
+
const clonedElement = element.cloneNode() as T
|
|
19
|
+
const style = copyStyles(element, clonedElement, important)
|
|
20
|
+
return [clonedElement, style]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function deepCopyStyles(source: Element, target: Element, important: boolean): string {
|
|
24
|
+
const sources = [source]
|
|
25
|
+
const targets = [target]
|
|
26
|
+
const styles: string[] = []
|
|
27
|
+
|
|
28
|
+
while (sources.length > 0 && sources.length === targets.length) {
|
|
29
|
+
const source = sources.pop()
|
|
30
|
+
const target = targets.pop()
|
|
31
|
+
|
|
32
|
+
if (!source || !target) {
|
|
33
|
+
break
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const style = copyStyles(source, target, important)
|
|
37
|
+
if (style) {
|
|
38
|
+
styles.push(style)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
sources.push(...source.children)
|
|
42
|
+
targets.push(...target.children)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return styles.join('\n')
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function copyStyles(source: Element, target: Element, important: boolean): string {
|
|
49
|
+
if (!source || !target) {
|
|
50
|
+
return ''
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const view = source.ownerDocument?.defaultView
|
|
54
|
+
if (!view) {
|
|
55
|
+
return ''
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Known issue: pseudo styles are not copied.
|
|
59
|
+
const sourceStyle = view.getComputedStyle(source)
|
|
60
|
+
const targetStyle = (target as HTMLElement | SVGElement | MathMLElement).style
|
|
61
|
+
|
|
62
|
+
if (!sourceStyle || !targetStyle) {
|
|
63
|
+
return ''
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
for (const key of sourceStyle) {
|
|
67
|
+
targetStyle.setProperty(
|
|
68
|
+
key,
|
|
69
|
+
sourceStyle.getPropertyValue(key),
|
|
70
|
+
// Enforce important to avoid the style being overridden when the element
|
|
71
|
+
// is connected to the page.
|
|
72
|
+
// See https://github.com/prosekit/prosekit/issues/1185 for more details.
|
|
73
|
+
important ? 'important' : (sourceStyle.getPropertyPriority(key) || ''),
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const styles: string[] = []
|
|
78
|
+
for (const pseudoSelector of [':before', ':after']) {
|
|
79
|
+
const sourcePseudoStyle = view.getComputedStyle(source, pseudoSelector)
|
|
80
|
+
const targetPseudoStyle = view.getComputedStyle(target, pseudoSelector)
|
|
81
|
+
|
|
82
|
+
if (!sourcePseudoStyle) {
|
|
83
|
+
continue
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const content = sourcePseudoStyle.getPropertyValue('content')
|
|
87
|
+
const hasPseudoElement = content && content !== 'none' && content !== 'normal'
|
|
88
|
+
|
|
89
|
+
if (!hasPseudoElement) {
|
|
90
|
+
continue
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const cssProps: string[] = []
|
|
94
|
+
for (const property of sourcePseudoStyle) {
|
|
95
|
+
const sourceValue = sourcePseudoStyle.getPropertyValue(property)
|
|
96
|
+
const sourcePriority = sourcePseudoStyle.getPropertyPriority(property)
|
|
97
|
+
const targetValue = targetPseudoStyle.getPropertyValue(property)
|
|
98
|
+
const targetPriority = targetPseudoStyle.getPropertyPriority(property)
|
|
99
|
+
if (sourceValue !== targetValue || sourcePriority !== targetPriority) {
|
|
100
|
+
cssProps.push(`${property}: ${sourceValue}${sourcePriority ? ' !important' : ''};`)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const uniqueClassName = `clone-pseudo-element-${getId()}`
|
|
105
|
+
target.classList.add(uniqueClassName)
|
|
106
|
+
styles.push(`.${uniqueClassName}${pseudoSelector} { ${cssProps.join(' ')} }`)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return styles.join('\n')
|
|
110
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { isColorMixSupported } from './css-feature-detection'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Convert a color to a color with opacity
|
|
5
|
+
* @param color - The color to convert
|
|
6
|
+
* @param opacity - The opacity to apply
|
|
7
|
+
* @returns The converted color if color-mix is supported, otherwise undefined
|
|
8
|
+
*/
|
|
9
|
+
export function fadeColor(color: CSSStyleValue, opacity: number): string | undefined {
|
|
10
|
+
if (isColorMixSupported()) {
|
|
11
|
+
const transparentWeight = (1 - opacity) * 100
|
|
12
|
+
const colorWeight = opacity * 100
|
|
13
|
+
return `color-mix(in srgb, ${color} ${colorWeight}%, transparent ${transparentWeight}%)`
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the element that has a box.
|
|
3
|
+
*/
|
|
4
|
+
export function getBoxElement(element: Element): Element | null | undefined {
|
|
5
|
+
const window = element.ownerDocument.defaultView
|
|
6
|
+
if (!window) {
|
|
7
|
+
return
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const style = window.getComputedStyle(element)
|
|
11
|
+
const display = style.display
|
|
12
|
+
|
|
13
|
+
if (display === 'contents' && element.childElementCount === 1) {
|
|
14
|
+
return element.firstElementChild
|
|
15
|
+
} else if (display === 'none') {
|
|
16
|
+
return
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return element
|
|
20
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Similar to `element.getBoundingClientRect`, but handles `display: contents` elements.
|
|
3
|
+
*/
|
|
4
|
+
export function getClientRect(element: Element): {
|
|
5
|
+
top: number
|
|
6
|
+
right: number
|
|
7
|
+
bottom: number
|
|
8
|
+
left: number
|
|
9
|
+
} {
|
|
10
|
+
const rect = element.getBoundingClientRect()
|
|
11
|
+
if (rect.width === 0 && rect.height === 0 && rect.x === 0 && rect.y === 0) {
|
|
12
|
+
// Suspiciously rect, probably an element with `display: contents`, in
|
|
13
|
+
// which case `element.getClientRects()` will return an empty array.
|
|
14
|
+
if (element.getClientRects().length === 0) {
|
|
15
|
+
const children = Array.from(element.children)
|
|
16
|
+
const rects = children.map(child => getClientRect(child))
|
|
17
|
+
if (rects.length === 0) {
|
|
18
|
+
return rect
|
|
19
|
+
}
|
|
20
|
+
if (rects.length === 1) {
|
|
21
|
+
return rects[0]
|
|
22
|
+
}
|
|
23
|
+
let { top, bottom, left, right } = rects[0]
|
|
24
|
+
for (let i = 1; i < rects.length; i++) {
|
|
25
|
+
const r = rects[i]
|
|
26
|
+
if (r.top < top) top = r.top
|
|
27
|
+
if (r.bottom > bottom) bottom = r.bottom
|
|
28
|
+
if (r.left < left) left = r.left
|
|
29
|
+
if (r.right > right) right = r.right
|
|
30
|
+
}
|
|
31
|
+
return { top, bottom, left, right }
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return rect
|
|
35
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createSignal,
|
|
3
|
+
type PropDeclarations,
|
|
4
|
+
type SignalState,
|
|
5
|
+
} from '@aria-ui/core'
|
|
6
|
+
import {
|
|
7
|
+
describe,
|
|
8
|
+
expect,
|
|
9
|
+
it,
|
|
10
|
+
} from 'vitest'
|
|
11
|
+
|
|
12
|
+
import { getStateWithDefaults } from './get-default-state'
|
|
13
|
+
|
|
14
|
+
type TestProps = {
|
|
15
|
+
bool: boolean
|
|
16
|
+
num: number
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe('getStateWithDefaults', () => {
|
|
20
|
+
it('keeps falsy signal values from state', () => {
|
|
21
|
+
const props: PropDeclarations<TestProps> = {
|
|
22
|
+
bool: { default: true },
|
|
23
|
+
num: { default: 1 },
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const state: Partial<SignalState<TestProps>> = {
|
|
27
|
+
bool: createSignal(false),
|
|
28
|
+
num: createSignal(0),
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const merged = getStateWithDefaults(state, props)
|
|
32
|
+
expect(merged.bool.get()).toBe(false)
|
|
33
|
+
expect(merged.num.get()).toBe(0)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('uses default value when state property is undefined', () => {
|
|
37
|
+
const props: PropDeclarations<TestProps> = {
|
|
38
|
+
bool: { default: true },
|
|
39
|
+
num: { default: 1 },
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const state: Partial<SignalState<TestProps>> = {
|
|
43
|
+
bool: undefined,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const merged = getStateWithDefaults(state, props)
|
|
47
|
+
expect(merged.bool.get()).toBe(true)
|
|
48
|
+
expect(merged.num.get()).toBe(1)
|
|
49
|
+
})
|
|
50
|
+
})
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createSignal,
|
|
3
|
+
type PropDeclarations,
|
|
4
|
+
type SignalState,
|
|
5
|
+
} from '@aria-ui/core'
|
|
6
|
+
|
|
7
|
+
export function getStateWithDefaults<
|
|
8
|
+
Props extends Record<string, any> = Record<string, any>,
|
|
9
|
+
>(
|
|
10
|
+
state: Partial<SignalState<Props>>,
|
|
11
|
+
props: PropDeclarations<Props>,
|
|
12
|
+
): SignalState<Props> {
|
|
13
|
+
const merged = { ...state } as SignalState<Props>
|
|
14
|
+
|
|
15
|
+
for (const key of Object.keys(props) as (keyof Props)[]) {
|
|
16
|
+
if (!merged[key]) {
|
|
17
|
+
merged[key] = createSignal(props[key].default)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return merged
|
|
22
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function getEffectiveBackgroundColor(element: HTMLElement): string | undefined {
|
|
2
|
+
let current: HTMLElement | null = element
|
|
3
|
+
|
|
4
|
+
while (current) {
|
|
5
|
+
const style = current.ownerDocument.defaultView?.getComputedStyle(current)
|
|
6
|
+
const backgroundColor = style?.backgroundColor
|
|
7
|
+
|
|
8
|
+
if (
|
|
9
|
+
backgroundColor
|
|
10
|
+
&& backgroundColor !== 'transparent'
|
|
11
|
+
// Chrome returns `rgba(0, 0, 0, 0)` for transparent colors.
|
|
12
|
+
&& backgroundColor !== 'rgba(0, 0, 0, 0)'
|
|
13
|
+
) {
|
|
14
|
+
return backgroundColor
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
current = current.parentElement
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return undefined
|
|
21
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Editor } from '@prosekit/core'
|
|
2
|
+
import type { EditorView } from '@prosekit/pm/view'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export function getSafeEditorView(editor?: Editor | null): EditorView | undefined {
|
|
8
|
+
if (!editor || !editor.mounted) return
|
|
9
|
+
return editor.view
|
|
10
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { getDocument } from '@ocavue/utils'
|
|
2
|
+
|
|
3
|
+
export function injectStyle(container: HTMLElement, styleText: string): void {
|
|
4
|
+
if (!styleText) {
|
|
5
|
+
return
|
|
6
|
+
}
|
|
7
|
+
const document = getDocument(container)
|
|
8
|
+
const style = document.createElement('style')
|
|
9
|
+
style.textContent = styleText
|
|
10
|
+
container.appendChild(style)
|
|
11
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @internal
|
|
3
|
+
*/
|
|
4
|
+
export function throttle<Args extends any[]>(
|
|
5
|
+
callback: (...args: Args) => void,
|
|
6
|
+
wait: number,
|
|
7
|
+
): (...args: Args) => void {
|
|
8
|
+
let lastTime = 0
|
|
9
|
+
|
|
10
|
+
return (...args: Args) => {
|
|
11
|
+
const now = Date.now()
|
|
12
|
+
if (now - lastTime >= wait) {
|
|
13
|
+
callback(...args)
|
|
14
|
+
lastTime = now
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|