intable 0.0.6 → 0.0.7

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 (169) hide show
  1. package/README.md +16 -263
  2. package/docs/index-BaMALNy6.css +1 -0
  3. package/docs/index-CDN48t9E.js +3 -0
  4. package/docs/index-Cc4RNkLY.css +1 -0
  5. package/docs/index-MRnbkYmU.js +3 -0
  6. package/docs/index.html +15 -0
  7. package/docs/vite.svg +1 -0
  8. package/index.html +14 -0
  9. package/package.json +30 -38
  10. package/packages/intable/README.md +379 -0
  11. package/packages/intable/package.json +51 -0
  12. package/packages/intable/src/assets/ClearFormat.svg +3 -0
  13. package/packages/intable/src/assets/Forms.svg +4 -0
  14. package/packages/intable/src/assets/MergeCell.svg +4 -0
  15. package/packages/intable/src/assets/SplitCell.svg +4 -0
  16. package/packages/intable/src/assets/gap.svg +3 -0
  17. package/packages/intable/src/assets/loading.svg +12 -0
  18. package/packages/intable/src/assets/paint.svg +9 -0
  19. package/packages/intable/src/assets/solid.svg +1 -0
  20. package/packages/intable/src/components/Columns.tsx +86 -0
  21. package/packages/intable/src/components/DocTree.tsx +36 -0
  22. package/packages/intable/src/components/Menu.tsx +109 -0
  23. package/packages/intable/src/components/Popover.tsx +55 -0
  24. package/packages/intable/src/components/RecycleList.tsx +99 -0
  25. package/packages/intable/src/components/Render.tsx +26 -0
  26. package/packages/intable/src/components/Split.tsx +56 -0
  27. package/packages/intable/src/components/Tree.tsx +115 -0
  28. package/packages/intable/src/components/utils.tsx +12 -0
  29. package/packages/intable/src/hooks/index.ts +200 -0
  30. package/packages/intable/src/hooks/useDir.ts +78 -0
  31. package/packages/intable/src/hooks/useSelector.ts +91 -0
  32. package/packages/intable/src/hooks/useSort.tsx +118 -0
  33. package/packages/intable/src/hooks/useVirtualizer.ts +180 -0
  34. package/packages/intable/src/index.tsx +481 -0
  35. package/packages/intable/src/plugins/CellChangeHighlightPlugin.tsx +5 -0
  36. package/packages/intable/src/plugins/CellMergePlugin.tsx +153 -0
  37. package/packages/intable/src/plugins/CellSelectionPlugin.tsx +175 -0
  38. package/packages/intable/src/plugins/CommandPlugin.tsx +74 -0
  39. package/packages/intable/src/plugins/CopyPastePlugin.tsx +63 -0
  40. package/packages/intable/src/plugins/DiffPlugin.tsx +107 -0
  41. package/packages/intable/src/plugins/DragPlugin.tsx +81 -0
  42. package/packages/intable/src/plugins/EditablePlugin.tsx +252 -0
  43. package/packages/intable/src/plugins/ExpandPlugin.tsx +80 -0
  44. package/packages/intable/src/plugins/HeaderGroup.tsx +289 -0
  45. package/packages/intable/src/plugins/HistoryPlugin.tsx +49 -0
  46. package/packages/intable/src/plugins/MenuPlugin.tsx +195 -0
  47. package/packages/intable/src/plugins/RenderPlugin/components.tsx +51 -0
  48. package/packages/intable/src/plugins/RenderPlugin/index.tsx +81 -0
  49. package/packages/intable/src/plugins/ResizePlugin.tsx +122 -0
  50. package/packages/intable/src/plugins/RowGroupPlugin.tsx +122 -0
  51. package/packages/intable/src/plugins/RowSelectionPlugin.tsx +65 -0
  52. package/packages/intable/src/plugins/TreePlugin.tsx +212 -0
  53. package/packages/intable/src/plugins/VirtualScrollPlugin.tsx +190 -0
  54. package/packages/intable/src/plugins/ZodValidatorPlugin.tsx +61 -0
  55. package/packages/intable/src/style.scss +244 -0
  56. package/{dist → packages/intable/src}/theme/antd.scss +14 -5
  57. package/{dist → packages/intable/src}/theme/element-plus.scss +6 -5
  58. package/packages/intable/src/tree.ts +13 -0
  59. package/packages/intable/src/types/auto-imports.d.ts +13 -0
  60. package/packages/intable/src/utils.ts +122 -0
  61. package/packages/intable/src/wc.tsx +35 -0
  62. package/packages/intable/src/web-component.ts +1 -0
  63. package/packages/react/package.json +31 -0
  64. package/packages/react/src/index.ts +44 -0
  65. package/packages/react/src/plugins/antd.ts +94 -0
  66. package/packages/react/src/style.scss +12 -0
  67. package/packages/react/src/types/auto-imports.d.ts +10 -0
  68. package/packages/vue/package.json +34 -0
  69. package/packages/vue/src/index.ts +63 -0
  70. package/packages/vue/src/plugins/element-plus.ts +69 -0
  71. package/packages/vue/src/style.scss +12 -0
  72. package/packages/vue/src/types/auto-imports.d.ts +10 -0
  73. package/pnpm-workspace.yaml +2 -0
  74. package/public/vite.svg +1 -0
  75. package/scripts/build.js +184 -0
  76. package/scripts/publish.js +95 -0
  77. package/src/assets/ClearFormat.svg +3 -0
  78. package/src/assets/Forms.svg +4 -0
  79. package/src/assets/MergeCell.svg +4 -0
  80. package/src/assets/SplitCell.svg +4 -0
  81. package/src/assets/gap.svg +3 -0
  82. package/src/assets/loading.svg +12 -0
  83. package/src/assets/paint.svg +9 -0
  84. package/src/assets/solid.svg +1 -0
  85. package/src/demo-vue.ts +54 -0
  86. package/src/demo.tsx +107 -0
  87. package/src/index.scss +105 -0
  88. package/src/styles/index.scss +172 -0
  89. package/src/types/auto-imports.d.ts +13 -0
  90. package/stats.html +4949 -0
  91. package/tsconfig.app.json +34 -0
  92. package/tsconfig.json +7 -0
  93. package/tsconfig.node.json +26 -0
  94. package/vite.config.ts +63 -0
  95. package/dist/__uno.css +0 -1
  96. package/dist/chevron-right.js +0 -6
  97. package/dist/components/Columns.d.ts +0 -3
  98. package/dist/components/Columns.js +0 -71
  99. package/dist/components/DocTree.d.ts +0 -4
  100. package/dist/components/DocTree.js +0 -32
  101. package/dist/components/Menu.d.ts +0 -1
  102. package/dist/components/Menu.js +0 -107
  103. package/dist/components/Popover.d.ts +0 -14
  104. package/dist/components/Popover.js +0 -41
  105. package/dist/components/Render.d.ts +0 -4
  106. package/dist/components/Render.js +0 -20
  107. package/dist/components/Split.d.ts +0 -15
  108. package/dist/components/Split.js +0 -76
  109. package/dist/components/Tree.d.ts +0 -37
  110. package/dist/components/Tree.js +0 -82
  111. package/dist/components/utils.d.ts +0 -3
  112. package/dist/components/utils.js +0 -8
  113. package/dist/hooks/index.d.ts +0 -40
  114. package/dist/hooks/index.js +0 -157
  115. package/dist/hooks/useDir.d.ts +0 -11
  116. package/dist/hooks/useDir.js +0 -42
  117. package/dist/hooks/useSelector.d.ts +0 -16
  118. package/dist/hooks/useSelector.js +0 -35
  119. package/dist/hooks/useSort.d.ts +0 -18
  120. package/dist/hooks/useSort.js +0 -83
  121. package/dist/hooks/useVirtualizer.d.ts +0 -25
  122. package/dist/hooks/useVirtualizer.js +0 -67
  123. package/dist/index.d.ts +0 -130
  124. package/dist/index.js +0 -347
  125. package/dist/loading.js +0 -6
  126. package/dist/plugins/CellChangeHighlightPlugin.d.ts +0 -2
  127. package/dist/plugins/CellChangeHighlightPlugin.js +0 -4
  128. package/dist/plugins/CellMergePlugin.d.ts +0 -12
  129. package/dist/plugins/CellMergePlugin.js +0 -2
  130. package/dist/plugins/CellSelectionPlugin.d.ts +0 -15
  131. package/dist/plugins/CellSelectionPlugin.js +0 -115
  132. package/dist/plugins/CommandPlugin.d.ts +0 -14
  133. package/dist/plugins/CommandPlugin.js +0 -12
  134. package/dist/plugins/CopyPastePlugin.d.ts +0 -14
  135. package/dist/plugins/CopyPastePlugin.js +0 -42
  136. package/dist/plugins/DiffPlugin.d.ts +0 -23
  137. package/dist/plugins/DiffPlugin.js +0 -56
  138. package/dist/plugins/DragPlugin.d.ts +0 -14
  139. package/dist/plugins/DragPlugin.js +0 -47
  140. package/dist/plugins/EditablePlugin.d.ts +0 -48
  141. package/dist/plugins/EditablePlugin.js +0 -141
  142. package/dist/plugins/ExpandPlugin.d.ts +0 -18
  143. package/dist/plugins/ExpandPlugin.js +0 -50
  144. package/dist/plugins/HistoryPlugin.d.ts +0 -10
  145. package/dist/plugins/HistoryPlugin.js +0 -30
  146. package/dist/plugins/MenuPlugin.d.ts +0 -18
  147. package/dist/plugins/MenuPlugin.js +0 -107
  148. package/dist/plugins/RenderPlugin/components.d.ts +0 -5
  149. package/dist/plugins/RenderPlugin/components.js +0 -87
  150. package/dist/plugins/RenderPlugin/index.d.ts +0 -30
  151. package/dist/plugins/RenderPlugin/index.js +0 -49
  152. package/dist/plugins/ResizePlugin.d.ts +0 -27
  153. package/dist/plugins/ResizePlugin.js +0 -81
  154. package/dist/plugins/RowGroupPlugin.d.ts +0 -17
  155. package/dist/plugins/RowGroupPlugin.js +0 -83
  156. package/dist/plugins/RowSelectionPlugin.d.ts +0 -20
  157. package/dist/plugins/RowSelectionPlugin.js +0 -42
  158. package/dist/plugins/VirtualScrollPlugin.d.ts +0 -15
  159. package/dist/plugins/VirtualScrollPlugin.js +0 -96
  160. package/dist/plus.js +0 -6
  161. package/dist/style.css +0 -3
  162. package/dist/types/auto-imports.d.js +0 -0
  163. package/dist/utils.d.ts +0 -30
  164. package/dist/utils.js +0 -70
  165. package/dist/wc.d.ts +0 -1
  166. package/dist/wc.js +0 -21
  167. package/dist/web-component.d.ts +0 -1
  168. package/dist/web-component.js +0 -2
  169. package/dist/x.js +0 -6
@@ -0,0 +1,109 @@
1
+ import { children, createContext, createEffect, createMemo, createResource, createSignal, mergeProps, onMount, splitProps, useContext } from "solid-js"
2
+ import { isEmpty } from 'es-toolkit/compat'
3
+ import { createRender } from "./Render"
4
+ import { autoUpdate, createFloating, offset } from "floating-ui-solid"
5
+ import { combineProps } from '@solid-primitives/props'
6
+ import { pointerHover } from "@solid-primitives/pointer"
7
+ import { createMutable } from "solid-js/store"
8
+ import { delay } from "es-toolkit"
9
+ import { log, unFn } from "../utils"
10
+ import { VDir } from "../hooks/useDir"
11
+ import { Popover } from "./Popover"
12
+ import { useSignle2 } from "../hooks"
13
+
14
+ export function Menu(props) {
15
+ const MenuCtx = createContext({ deep: 0 })
16
+
17
+ const _Li = _e => {
18
+ const ctx = useContext(MenuCtx)
19
+ const [e, attrs] = splitProps(_e, ['children', 'label', 'icon', 'isActive', 'cb', 'menu', 'popover'])
20
+
21
+ const x = createMemo(() => props.x && ctx.deep == 1)
22
+
23
+ let el!: HTMLDivElement
24
+ const [floating, setFloating] = createSignal<HTMLElement>()
25
+ const [hover, setHover] = useSignle2(false, { before: () => delay(100) })
26
+ pointerHover
27
+
28
+ const style = createMemo(() => floating() ? createFloating({
29
+ strategy: 'fixed',
30
+ placement: x() ? 'bottom-start' : 'right-start',
31
+ ...e.menu,
32
+ elements: { reference: () => el, floating },
33
+ whileElementsMounted(ref, float, update) {
34
+ return autoUpdate(ref, float, update, { ancestorResize: true, elementResize: true, layoutShift: true, ancestorScroll: true })
35
+ }
36
+ }).floatingStyles : void 0)
37
+
38
+ createEffect(() => {
39
+ floating() && Object.assign(floating()!.style, style()?.() ?? {})
40
+ })
41
+
42
+ const req = createMutable({ loading: false })
43
+
44
+ async function onClick() {
45
+ if (req.loading) return
46
+ const ret = e.cb?.()
47
+ if (ret instanceof Promise) {
48
+ try {
49
+ await ret
50
+ req.loading = true
51
+ } finally {
52
+ req.loading = false
53
+ props.onAction?.(e)
54
+ }
55
+ }
56
+ else {
57
+ props.onAction?.(e)
58
+ }
59
+ }
60
+
61
+ onMount(() => {
62
+ <Popover strategy='fixed' reference={el} portal={el} {..._e.popover} middleware={[offset({ mainAxis: 4 })]} />
63
+ })
64
+
65
+ const child = children(() => e.children)
66
+ return (
67
+ <div
68
+ ref={el}
69
+ use:pointerHover={setHover}
70
+ {...combineProps({ class: `li flex aic rd-2 ${x() ? 'my-1 p-1' : 'mx-1 pl-1 pr-4 py-1'} ${unFn(e.isActive) && 'active'}` }, attrs)}
71
+ on:click={onClick}
72
+ >
73
+ <div class={`flex aic ${x() ? '' : props.density == 'comfortable' ? 'ml-1 mr-2.5' : 'ml-.5 mr-1'} `}>
74
+ {req.loading ? <IMyLoading /> : e.icon}
75
+ </div>
76
+ {e.label}
77
+ {/* {hover() && child() && <_Menu ref={setFloating}>{child()}</_Menu>} */}
78
+ {hover() && e.children && <_Menu ref={setFloating} class='z-1'>{e.children}</_Menu>}
79
+ </div>
80
+ )
81
+ }
82
+
83
+ const Li = createRender({
84
+ is: _Li,
85
+ processProps: props => {
86
+ let i = 0
87
+ Array.isArray(props.children) && props.children.forEach((e) => !e.is && typeof e == 'object' && (e['data-index'] = i++))
88
+ return props
89
+ }
90
+ })
91
+
92
+ const _Menu = e => {
93
+ const parent = useContext(MenuCtx)
94
+ const ctx = createMutable({ deep: parent.deep + 1 })
95
+ return (
96
+ <MenuCtx.Provider value={ctx}>
97
+ <div
98
+ {...combineProps({ class: `${props.x && ctx.deep == 1 ? 'tt-menu-x flex' : 'tt-menu max-h-100'} overflow-auto` }, e)}
99
+ use:VDir={e.usedir}
100
+ on:click={e => e.stopPropagation()}
101
+ >
102
+ {(el => isEmpty(el) ? <div class='px-4 py-2 op40'>无内容</div> : el)(e.children)}
103
+ </div>
104
+ </MenuCtx.Provider>
105
+ )
106
+ }
107
+
108
+ return <Li {...combineProps({}, props)} is={_Menu} items={null} children={props.items} />
109
+ }
@@ -0,0 +1,55 @@
1
+ import { children, createEffect, createMemo, createSignal, type JSX, splitProps } from 'solid-js'
2
+ import { Portal } from 'solid-js/web'
3
+ import { autoUpdate, createFloating, type createFloatingProps, type ReferenceType } from 'floating-ui-solid'
4
+ import type { AutoUpdateOptions } from '@floating-ui/dom'
5
+ import { delay } from 'es-toolkit'
6
+ import { useClicked, useHover, useMemoAsync } from '../hooks'
7
+
8
+ export function Popover(attrs: FloatingProps) {
9
+ const [_, props] = splitProps(attrs, ['reference', 'floating'])
10
+
11
+ const show = (attrs.trigger == 'click' ? useClicked : useHover)(() => [reference(), floating()].filter(e => e))
12
+ const show2 = useMemoAsync(() => (
13
+ attrs.trigger == 'click'
14
+ ? show()
15
+ : show() ? delay(100).then(() => true) : delay(200).then(() => false)
16
+ ))
17
+
18
+ const reference = children(() => attrs.reference as HTMLElement)
19
+ const floating = children(() => show2() ? attrs.floating as HTMLElement : void 0)
20
+
21
+ return <Floating {...props} reference={reference} floating={floating} />
22
+ }
23
+
24
+ type FloatingProps = {
25
+ reference: ReferenceType
26
+ floating?: JSX.Element | (() => JSX.Element)
27
+ portal?: HTMLElement
28
+ trigger?: 'click' | 'hover'
29
+ } & createFloatingProps
30
+
31
+ export function Floating(attrs: FloatingProps & { update?: Partial<AutoUpdateOptions> }) {
32
+ const [_, props] = splitProps(attrs, ['reference', 'floating'])
33
+ const reference = children(() => attrs.reference)
34
+ const floating = children(() => attrs.floating)
35
+
36
+ const style = createMemo(() => floating() ? createFloating({
37
+ whileElementsMounted(ref, float, update) {
38
+ return autoUpdate(ref, float, update, { ancestorResize: true, elementResize: true, layoutShift: true, ancestorScroll: true, ...attrs.update })
39
+ },
40
+ ...props,
41
+ elements: { reference, floating },
42
+ }).floatingStyles : void 0)
43
+
44
+ createEffect(() => {
45
+ // console.log(props.floating)
46
+ floating() && Object.assign(floating().style, style()?.() ?? {})
47
+ })
48
+
49
+ return (
50
+ <>
51
+ {reference()}
52
+ {props.portal && floating() ? <Portal mount={props.portal}>{floating()}</Portal> : floating()}
53
+ </>
54
+ )
55
+ }
@@ -0,0 +1,99 @@
1
+ import { createMemo, type JSX, onCleanup, For, getOwner, runWithOwner, children, Show, createRoot } from 'solid-js'
2
+ import { createMutable } from 'solid-js/store'
3
+ import { log } from '../utils'
4
+
5
+ /**
6
+ * RecycleList — a keyed list component with DOM recycling.
7
+ *
8
+ * Works like SolidJS `<For>` (keyed by reference identity) but instead of
9
+ * destroying DOM when items leave the list, it hides and pools those DOM
10
+ * nodes. When new items enter, a pooled slot is reused by swapping the
11
+ * reactive signals, avoiding the cost of creating & hydrating fresh DOM.
12
+ *
13
+ * Each slot gets its own `createRoot` so that its inner reactive tree
14
+ * (memos, effects) is NOT owned by the reconciliation memo — preventing
15
+ * SolidJS from disposing child computations when the outer memo re-runs.
16
+ *
17
+ * Ideal for virtual-scroll scenarios where items constantly enter/leave
18
+ * the viewport but the DOM structure per item is identical.
19
+ *
20
+ * ```tsx
21
+ * <RecycleList each={visibleItems()}>
22
+ * {(item, index) => <div>{item().name} at {index()}</div>}
23
+ * </RecycleList>
24
+ * ```
25
+ */
26
+ export function RecycleList<T>(props: {
27
+ each: T[]
28
+ children: (item: () => T, index: () => number) => JSX.Element
29
+ }): JSX.Element {
30
+ interface Val {
31
+ v: any
32
+ i: number
33
+ active: boolean
34
+ el?: any
35
+ }
36
+
37
+ // Active slots keyed by identity reference
38
+ const active = new Map<T, Val>()
39
+ // Pool of inactive (hidden) slots ready for reuse
40
+ const pool: Val[] = []
41
+ const owner = getOwner()
42
+
43
+ function state<T extends Object>(initial: T): T {
44
+ return runWithOwner(owner, () => createMutable(initial))!
45
+ }
46
+
47
+ const list = createMemo(() => {
48
+ const items = props.each || []
49
+ const nextKeys = new Set(items)
50
+
51
+ // 1. Deactivate slots whose keys left the list → move to pool
52
+ for (const [key, val] of active) {
53
+ if (!nextKeys.has(key)) {
54
+ pool.push(val)
55
+ active.delete(key)
56
+ // val.v = null
57
+ // val.i = -1
58
+ val.active = false
59
+ }
60
+ }
61
+
62
+ // 2. For each item: reuse existing active slot, recycle from pool, or create new
63
+ const list = [] as Val[]
64
+ for (let i = 0; i < items.length; i++) {
65
+ const item = items[i]
66
+ if (active.has(item)) {
67
+ const slot = active.get(item)!
68
+ slot.i = i
69
+ slot.v = item
70
+ } else if (pool.length > 0) {
71
+ const slot = pool.pop()!
72
+ slot.i = i
73
+ slot.v = item
74
+ slot.active = true
75
+ active.set(item, slot)
76
+ } else {
77
+ active.set(item, state({ v: item, i, active: true }))
78
+ }
79
+ list.push(active.get(item)!)
80
+ }
81
+
82
+ return list.concat(...pool)
83
+ })
84
+
85
+ onCleanup(() => {
86
+ active.clear()
87
+ pool.length = 0
88
+ })
89
+
90
+ return (
91
+ <For each={list()}>{(val) => {
92
+ return <>
93
+ {val.active && runWithOwner(owner, () => (
94
+ val.el ??= props.children(() => val.v, () => val.i)
95
+ ))}
96
+ </>
97
+ }}</For>
98
+ )
99
+ }
@@ -0,0 +1,26 @@
1
+ import { splitProps } from "solid-js"
2
+ import { Dynamic } from "solid-js/web"
3
+
4
+ const unFn = (fn, ...arg) => typeof fn == 'function' ? fn(...arg) : fn
5
+
6
+ export function createRender({ is, processProps = e => e } = {}) {
7
+ const Render = (props: any) => {
8
+ const [reserve, attrs] = splitProps(processProps?.(props), ['is', 'vIf', 'children'])
9
+ return (<>
10
+ { (!('vIf' in reserve) || !!unFn(reserve.vIf)) &&
11
+ <Dynamic component={reserve.is ?? is} {...attrs}>
12
+ {List(reserve.children)}
13
+ </Dynamic>
14
+ }
15
+ </>)
16
+ }
17
+
18
+ const List = children => (
19
+ Array.isArray(children) ? children.map(e => typeof e == 'object' ? Render(e) : e) :
20
+ children
21
+ )
22
+
23
+ return Render
24
+ }
25
+
26
+ export const Render = createRender({ is: 'div' })
@@ -0,0 +1,56 @@
1
+ import { unFn } from '../utils'
2
+ import { createElementBounds } from '@solid-primitives/bounds'
3
+ import { children, createComputed, createEffect, createMemo, For, Index, mapArray, mergeProps, onMount, splitProps, type JSXElement } from 'solid-js'
4
+ import { Portal } from 'solid-js/web'
5
+
6
+ type SplitProps = {
7
+ container?: Element
8
+ cells: () => Element[]
9
+ handle?: (i: number) => JSXElement
10
+ size?: number
11
+ dir?: 'x' | 'y'
12
+ leading?: boolean
13
+ trailing?: boolean
14
+ }
15
+
16
+ export const Split = (props: SplitProps & { children?: JSXElement }) => {
17
+ let el!: Element
18
+ const child = children(() => props.children)
19
+
20
+ onMount(() => {
21
+ useSplit({
22
+ ...props,
23
+ container: el,
24
+ cells: () => props.cells ? props.cells() : child()
25
+ })
26
+ })
27
+
28
+ return <div ref={el} class='relative' {...props}>{child()}</div>
29
+ }
30
+
31
+ export const useSplit = (props: SplitProps) => {
32
+ props = mergeProps({ dir: 'x', size: 4 }, props) as SplitProps
33
+
34
+ let el!: HTMLDivElement
35
+ // const bounds = createMemo(() => props.cells().map()
36
+ const bounds = mapArray(() => props.cells(), el => createElementBounds(el))
37
+ const rect = createElementBounds(() => el)
38
+ createEffect(() => el.style.position = 'absolute')
39
+
40
+ const style = (e, bool) => props.dir == 'x'
41
+ ? `transform: translate(${(bool ? e.left + e.width : e.left) - (props.size! / 2)}px, ${e.top}px); width: ${props.size}px; height: ${e.height}px;`
42
+ : `transform: translate(${e.left}px, ${(bool ? e.top + e.height : e.top) - (props.size! / 2)}px); width: ${e.width}px; height: ${props.size}px;`
43
+
44
+ const Handle = (e) => (
45
+ <div class='absolute z-1' style={style({ ...e.e, left: e.e.left - rect.left, top: e.e.top - rect.top }, e.bool)}>{props.handle?.(e.i)}</div>
46
+ )
47
+
48
+ ; //
49
+ <Portal ref={el} mount={props.container || document.body}>
50
+ <For each={bounds().slice(0, -1)}>
51
+ {(e, i) => <Handle e={unFn(e)} bool={1} i={unFn(i)} />}
52
+ </For>
53
+ {!!bounds().length && props.leading && <Handle e={bounds()[0]} i={-1} />}
54
+ {!!bounds().length && props.trailing && <Handle e={bounds()[bounds().length - 1]} bool={1} i={bounds().length - 1} />}
55
+ </Portal>
56
+ }
@@ -0,0 +1,115 @@
1
+ import { createEffect, createMemo, createSignal, For, Index, on, onCleanup, splitProps } from 'solid-js'
2
+ import { Dynamic } from 'solid-js/web'
3
+ import { createLazyMemo } from '@solid-primitives/memo'
4
+ import { combineProps } from '@solid-primitives/props'
5
+ import { castArray } from 'es-toolkit/compat'
6
+
7
+ function define(that, key) {
8
+ const signal = createSignal()
9
+ Object.defineProperty(that, key, {
10
+ get() { return signal[0]() },
11
+ set(v) { signal[1](v) }
12
+ })
13
+ return signal
14
+ }
15
+
16
+ function memo<T>(that, key, fn: () => T) {
17
+ const signal = createLazyMemo(fn)
18
+ Object.defineProperty(that, key, {
19
+ get() { return signal() },
20
+ })
21
+ return signal
22
+ }
23
+
24
+ export abstract class $Node {
25
+ data: any
26
+ constructor(data: any) {
27
+ this.data = data
28
+
29
+ createEffect(() => {
30
+ const children = this.children
31
+ children?.map(e => e.parent = this)
32
+ onCleanup(() => children?.map(e => e.parent = undefined))
33
+ })
34
+ }
35
+
36
+ // abstract get Node(data): $Node
37
+ // abstract get id(): any
38
+ get label() { return this.data.label }
39
+ abstract getChildren(): $Node[] | undefined
40
+
41
+ declare children: $Node[] | undefined
42
+ $children = memo(this, 'children', () => this.getChildren())
43
+
44
+ declare parent: $Node | undefined
45
+ $parent = define(this, 'parent')
46
+
47
+ declare deep: number
48
+ $deep = memo(this, 'deep', () => this.parent ? this.parent.deep + 1 : 0)
49
+
50
+ declare index: number
51
+ $index = memo(this, 'index', () => this.parent?.children?.indexOf(this))
52
+
53
+ declare prev: $Node | undefined
54
+ $prev = memo(this, 'prev', () => this.parent?.children?.[this.index - 1])
55
+
56
+ declare next: $Node | undefined
57
+ $next = memo(this, 'next', () => this.parent?.children?.[this.index + 1])
58
+
59
+ declare root: $Node
60
+ $root = memo(this, 'root', () => this.parent ? this.parent.root : this)
61
+
62
+ declare path: $Node[]
63
+ $path = memo(this, 'path', () => {
64
+ const ret = [this] as $Node[]
65
+ let e: $Node = this
66
+ while (e.parent) ret.push(e = e.parent)
67
+ return ret.reverse()
68
+ })
69
+
70
+ get descendants(): $Node[] {
71
+ return this.children?.flatMap(e => [e, ...e.descendants]) || []
72
+ }
73
+
74
+ contains(node: $Node) {
75
+ return node.path.includes(this)
76
+ }
77
+
78
+ remove() {
79
+ // this.
80
+ }
81
+ }
82
+
83
+ export class $TreeItem extends $Node {
84
+ get is() { return this.data.is }
85
+ get props() { return this.data }
86
+ get id() { return this.data.id }
87
+ getChildren() { return this.data.children?.map(e => new $TreeItem(e)) }
88
+ }
89
+
90
+ export function Tree(_: { data: any; Node: { new (data: any): $TreeItem } }) {
91
+ const [props, attrs] = splitProps(_, ['data', 'Node'])
92
+
93
+ const Node = props.Node ?? $TreeItem
94
+
95
+ const root = createMemo(() => new (class extends Node {
96
+ getChildren() { return castArray(this.data || []).map(e => new Node(e)) }
97
+ })(props.data))
98
+
99
+ const flated = createMemo(() => root().descendants as $TreeItem[])
100
+
101
+ return (
102
+ <div {...combineProps({ class: 'tt-menu' }, attrs)}>
103
+ <Index each={flated()}>
104
+ {(node, index) => (
105
+ <Dynamic
106
+ component={node().is ?? 'div'}
107
+ {...combineProps({ class: 'li py-1 px-4', style: `padding-left: ${(node().deep) * 16}px` }, node().props)}
108
+ >
109
+ {node().label}
110
+ </Dynamic>
111
+ )}
112
+ </Index>
113
+ </div>
114
+ )
115
+ }
@@ -0,0 +1,12 @@
1
+ import type { JSX } from 'solid-js'
2
+
3
+ export function solidComponent<T extends (...arg) => JSX.Element>(comp: T) {
4
+ comp.__solid = 1
5
+ return comp
6
+ }
7
+
8
+ export function renderComponent(Comp: any, props: any, renderer: any) {
9
+ if (!Comp) return null
10
+ if (!Comp.__solid) Comp = renderer(Comp)
11
+ return <Comp {...props} />
12
+ }
@@ -0,0 +1,200 @@
1
+ import { $PROXY, batch, createComputed, createEffect, createMemo, createRenderEffect, createRoot, createSignal, mergeProps, on, onCleanup, untrack, type Signal } from 'solid-js'
2
+ import { $RAW, createMutable } from 'solid-js/store'
3
+ import { createEventListener, createEventListenerMap } from '@solid-primitives/event-listener'
4
+ import { createPointerListeners } from '@solid-primitives/pointer'
5
+ import { access, type Many, type MaybeAccessor, } from '@solid-primitives/utils'
6
+ import { makePersisted, storageSync } from '@solid-primitives/storage'
7
+ import { createMutationObserver } from '@solid-primitives/mutation-observer'
8
+ import { isFunction, isPromise, mapValues } from 'es-toolkit'
9
+ import { castArray } from 'es-toolkit/compat'
10
+ import { createKeybindingsHandler } from 'tinykeys'
11
+ import { unFn } from '../utils'
12
+
13
+ interface UseMoveOptions {
14
+ preventDefault?: boolean
15
+ start?(
16
+ e: PointerEvent,
17
+ move: (cb: MoveCB) => void,
18
+ end: (cb: EndCb) => void
19
+ ): void,
20
+ }
21
+
22
+ type MoveCB = (e: PointerEvent, o: { sx: number, sy: number, ox: number, oy: number }) => void
23
+ type EndCb = (e: PointerEvent) => void
24
+
25
+ export function usePointerDrag(el: MaybeAccessor<HTMLElement | undefined>, options: UseMoveOptions) {
26
+ options = mergeProps({ preventDefault: true } as UseMoveOptions, options)
27
+
28
+ createPointerListeners({
29
+ target: el,
30
+ passive: false,
31
+ onDown(e) {
32
+ options.preventDefault && e.preventDefault()
33
+ const [sx, sy] = [e.x, e.y]
34
+
35
+ let move: MoveCB | void
36
+ let end: EndCb | void
37
+ options.start?.(e, (cb) => move = cb, (cb) => end = cb)
38
+
39
+ createRoot(dispose => {
40
+ createPointerListeners({
41
+ target: document,
42
+ onMove(e) {
43
+ const [ox, oy] = [e.x - sx, e.y - sy]
44
+ move?.(e, { sx, sy, ox, oy })
45
+ },
46
+ onUp() {
47
+ end?.(e)
48
+ dispose()
49
+ move = void 0
50
+ end = void 0
51
+ }
52
+ })
53
+ // fix: does't cb onUp when drop
54
+ createEventListenerMap(document, {
55
+ drop: dispose
56
+ })
57
+ })
58
+ }
59
+ })
60
+ }
61
+
62
+ export function model(el: any, value: () => [() => string, (v: string) => any]) {
63
+ const [field, setField] = value()
64
+ createRenderEffect(() => (el.value = field()))
65
+ el.addEventListener("input", (e) => setField((e.target as HTMLInputElement).value))
66
+ }
67
+
68
+ export function toSignle<T extends Record<string, any>>(state: T, k: keyof T) {
69
+ return [() => state[k], v => state[k] = v]
70
+ }
71
+
72
+ export function useDark() {
73
+ const get = v => v == 'dark' || (prefersDark() && !v), set = v => v ? 'dark' : 'light'
74
+ const prefersDark = () => window.matchMedia("(prefers-color-scheme: dark)").matches
75
+ const dark = makePersisted(createSignal(prefersDark()), { name: 'color-schema', storage: localStorage, sync: storageSync, serialize: set, deserialize: get })
76
+ createEffect(() => document.documentElement.classList[dark[0]() ? 'add' : 'remove']('dark'))
77
+ createEffect(() => window.dispatchEvent(new StorageEvent('storage', { key: 'color-schema', newValue: set(dark[0]()) })))
78
+ return dark
79
+ }
80
+
81
+ export function useMemoAsync<T>(fn: (prev?: T) => Promise<T> | T, init?: Awaited<T>) {
82
+ const REJECT = Symbol()
83
+ const [val, setVal] = createSignal(init)
84
+ createComputed(async () => {
85
+ const ret = fn(untrack(val))
86
+ const v = ret instanceof Promise ? await new Promise((resolve) => {
87
+ ret.then(resolve)
88
+ onCleanup(() => resolve(REJECT))
89
+ }) : ret
90
+ v == REJECT || setVal(() => v)
91
+ })
92
+ return val
93
+ }
94
+
95
+ export function useSignle2<T>(v: T | (() => T), opt?: { before?: (v: T) => Promise<T | void> | T }) {
96
+ const state = createSignal(isFunction(v) ? void 0 : v)
97
+ const before = v => {
98
+ const v2 = opt?.before?.(v)
99
+ return isPromise(v2) ? v2.then(v3 => v3 === void 0 ? v : v3) : v2 ?? v
100
+ }
101
+
102
+ const val = useMemoAsync(() => before(state[0]() as T))
103
+
104
+ if (isFunction(v)) {
105
+ const fned = useMemoAsync(() => before(v()))
106
+ createComputed(() => state[1](fned()))
107
+ }
108
+
109
+ return [val, state[1]] as Signal<T>
110
+ }
111
+
112
+ const $MEMO = Symbol()
113
+
114
+ type Reactive<T extends object> = { [K in keyof T]: T[K] extends () => infer V ? V : T[K] }
115
+ export function toReactive<T extends object>(fn: (() => T) | T): Reactive<T> {
116
+ const v = () => unFn(fn)
117
+ const trueFn = () => true
118
+ const get = k => (e => typeof e == 'function' && $MEMO in e ? e() : e)(v()[k])
119
+ return new Proxy(Object.create(null), {
120
+ get: (o, k, r) => k == $PROXY ? r : k == $RAW ? r : (v => typeof v == 'function' && $MEMO in v ? v() : v)(v()[k]),
121
+ set: trueFn,
122
+ defineProperty: (o, k, attributes) => Object.defineProperty(v(), k, attributes),
123
+ deleteProperty: trueFn,
124
+ getPrototypeOf: () => Object.getPrototypeOf(v()),
125
+ has: (o, p) => p == $PROXY || p in v(),
126
+ ownKeys: (o) => Object.keys(v()),
127
+ getOwnPropertyDescriptor: (o, k) => ({ enumerable: true, configurable: true, get() { return get(k) }, set: trueFn }),
128
+ })
129
+ }
130
+
131
+ export function useMemo<T>(fn: () => T) {
132
+ const ret = createMemo(fn)
133
+ ret[$MEMO] = 1
134
+ return ret
135
+ }
136
+
137
+ export function useHover(el: MaybeAccessor<Many<HTMLElement | undefined>>) {
138
+ const [hover, setHover] = createSignal(false)
139
+ createEventListener(el, 'pointerenter', () => setHover(true))
140
+ createEventListener(el, 'pointerleave', () => setHover(false))
141
+ return hover
142
+ }
143
+
144
+ export function useMouseDown(el: MaybeAccessor<Many<HTMLElement | undefined>>) {
145
+ const [down, setDown] = createSignal(false)
146
+ createEventListener(el, 'pointerdown', () => setDown(true))
147
+ createEventListener(document.body, 'pointerup', () => setDown(false))
148
+ return down
149
+ }
150
+
151
+ export function useClicked(el: MaybeAccessor<Many<HTMLElement | undefined>>) {
152
+ const [clicked, setClicked] = createSignal(false)
153
+ const els = () => castArray(access(el))
154
+ createEventListener(() => els().map(e => e?.getRootNode()), 'click', e => setClicked(els().some(el => el?.contains(e.target))))
155
+ return clicked
156
+ }
157
+
158
+ export function useMutation<T>(initial: MaybeAccessor<Node | Node[]>, options: MutationObserverInit, cb: () => T) {
159
+ const ret = createSignal<T>(cb())
160
+ createMutationObserver(initial, options, ms => ret[1](cb() as any))
161
+ return ret[0]
162
+ }
163
+
164
+ export function useTinykeys(el: MaybeAccessor<HTMLElement | undefined>, handlers) {
165
+ createEventListener(el, 'keydown', createKeybindingsHandler({
166
+ ...mapValues(handlers, cb => e => {
167
+ e.preventDefault()
168
+ cb(e)
169
+ })
170
+ }))
171
+ }
172
+
173
+ export function useHistory([val, setVal]) {
174
+ let bool = 1
175
+ const state = createMutable({ index: -1, history: [] as any[] })
176
+ const clear = () => (state.index = 0, state.history = [val()])
177
+ const canUndo = () => state.index > 0
178
+ const canRedo = () => state.index < state.history.length - 1
179
+ const undo = () => canUndo() && ((bool = 0) || setVal(state.history[--state.index]))
180
+ const redo = () => canRedo() && ((bool = 0) || setVal(state.history[++state.index]))
181
+ createRenderEffect(on(val, ret => {
182
+ if (ret == null) return // todo
183
+ if (!bool) return bool = 1
184
+ if (canRedo()) state.history = state.history.slice(0, state.index + 1)
185
+ state.history[++state.index] = ret
186
+ }))
187
+ return { undo, redo, clear, get index() { return state.index }, get history() { return state.history } }
188
+ }
189
+
190
+ export function useMemoState(fn) {
191
+ const state = createMutable({})
192
+ createComputed(() => {
193
+ const val = fn()
194
+ untrack(() => batch(() => {
195
+ for (const k in state) k in val || (delete state[k])
196
+ Object.assign(state, val)
197
+ }))
198
+ })
199
+ return state
200
+ }