lark-docs-variables 1.0.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.
Files changed (49) hide show
  1. package/.vscode/launch.json +18 -0
  2. package/.vscode/settings.json +42 -0
  3. package/README.md +1 -0
  4. package/app.json +19 -0
  5. package/components.json +38 -0
  6. package/eslint.config.js +123 -0
  7. package/package.json +55 -0
  8. package/src/components/Box.tsx +10 -0
  9. package/src/components/Icon.module.css +3 -0
  10. package/src/components/Icon.tsx +26 -0
  11. package/src/components/ValueToggle.module.css +4 -0
  12. package/src/components/ValueToggle.tsx +25 -0
  13. package/src/components/base/Button.tsx +46 -0
  14. package/src/components/base/Card.tsx +74 -0
  15. package/src/components/base/Combobox.tsx +217 -0
  16. package/src/components/base/Input.tsx +17 -0
  17. package/src/components/base/InputGroup.tsx +123 -0
  18. package/src/components/base/Textarea.tsx +15 -0
  19. package/src/components/base/Toggle.tsx +24 -0
  20. package/src/entries/Panel.module.css +33 -0
  21. package/src/entries/Panel.tsx +67 -0
  22. package/src/entries/Settings.css +3 -0
  23. package/src/entries/Settings.module.css +4 -0
  24. package/src/entries/Settings.tsx +14 -0
  25. package/src/globals.d.ts +1 -0
  26. package/src/hooks/useBlockHover.ts +20 -0
  27. package/src/hooks/useDebounce.ts +16 -0
  28. package/src/hooks/useDocument.ts +8 -0
  29. package/src/hooks/useIsMounted.ts +15 -0
  30. package/src/hooks/useRecord.ts +33 -0
  31. package/src/hooks/useResizeObserver.ts +90 -0
  32. package/src/hooks/useSelection.ts +16 -0
  33. package/src/hooks/useTimeoutFn.ts +40 -0
  34. package/src/index.css +125 -0
  35. package/src/lib/utils.ts +6 -0
  36. package/src/panel.html +11 -0
  37. package/src/panel.tsx +14 -0
  38. package/src/providers/BlockProvider.context.ts +10 -0
  39. package/src/providers/BlockProvider.tsx +30 -0
  40. package/src/public/icon.png +0 -0
  41. package/src/settings.html +11 -0
  42. package/src/settings.tsx +14 -0
  43. package/src/util/app.ts +3 -0
  44. package/src/util/box.ts +27 -0
  45. package/tsconfig.app.json +35 -0
  46. package/tsconfig.json +13 -0
  47. package/tsconfig.node.json +26 -0
  48. package/vite/plugin.ts +131 -0
  49. package/vite.config.ts +55 -0
@@ -0,0 +1,90 @@
1
+ /* eslint-disable react-hooks/refs */
2
+ import type { RefObject } from 'react'
3
+ import { useEffect, useRef, useState } from 'react'
4
+ import { useIsMounted } from './useIsMounted'
5
+
6
+ interface Size {
7
+ width: number | undefined
8
+ height: number | undefined
9
+ }
10
+
11
+ interface UseResizeObserverOptions<T extends HTMLElement = HTMLElement> {
12
+ ref: RefObject<T>
13
+ onResize?: (size: Size) => void
14
+ box?: 'border-box' | 'content-box' | 'device-pixel-content-box'
15
+ }
16
+
17
+ const initialSize: Size = {
18
+ width: undefined,
19
+ height: undefined
20
+ }
21
+
22
+ export function useResizeObserver<T extends HTMLElement = HTMLElement>(options: UseResizeObserverOptions<T>): Size {
23
+ const { ref, box = 'content-box' } = options
24
+ const [{ width, height }, setSize] = useState<Size>(initialSize)
25
+ const isMounted = useIsMounted()
26
+ const previousSize = useRef<Size>({ ...initialSize })
27
+ const onResize = useRef<((size: Size) => void) | undefined>(undefined)
28
+ onResize.current = options.onResize
29
+
30
+ useEffect(() => {
31
+ if (!ref.current) return
32
+
33
+ if (typeof window === 'undefined' || !('ResizeObserver' in window)) { return }
34
+
35
+ const observer = new ResizeObserver(([entry]) => {
36
+ const boxProp = box === 'border-box'
37
+ ? 'borderBoxSize'
38
+ : box === 'device-pixel-content-box'
39
+ ? 'devicePixelContentBoxSize'
40
+ : 'contentBoxSize'
41
+
42
+ const newWidth = extractSize(entry, boxProp, 'inlineSize')
43
+ const newHeight = extractSize(entry, boxProp, 'blockSize')
44
+
45
+ const hasChanged =
46
+ previousSize.current.width !== newWidth ||
47
+ previousSize.current.height !== newHeight
48
+
49
+ if (hasChanged) {
50
+ const newSize: Size = { width: newWidth, height: newHeight }
51
+ previousSize.current.width = newWidth
52
+ previousSize.current.height = newHeight
53
+
54
+ if (onResize.current) {
55
+ onResize.current(newSize)
56
+ } else {
57
+ if (isMounted()) {
58
+ setSize(newSize)
59
+ }
60
+ }
61
+ }
62
+ })
63
+
64
+ observer.observe(ref.current, { box })
65
+
66
+ return () => { observer.disconnect() }
67
+ }, [box, ref, isMounted])
68
+
69
+ return { width, height }
70
+ }
71
+
72
+ type BoxSizesKey = keyof Pick<ResizeObserverEntry, 'borderBoxSize' | 'contentBoxSize' | 'devicePixelContentBoxSize'>
73
+
74
+ function extractSize(
75
+ entry: ResizeObserverEntry,
76
+ box: BoxSizesKey,
77
+ sizeType: keyof ResizeObserverSize
78
+ ): number | undefined {
79
+ if (!entry[box]) {
80
+ if (box === 'contentBoxSize') {
81
+ return entry.contentRect[sizeType === 'inlineSize' ? 'width' : 'height']
82
+ }
83
+ return undefined
84
+ }
85
+
86
+ return Array.isArray(entry[box])
87
+ ? entry[box][0][sizeType]
88
+ : // @ts-expect-error Support Firefox's non-standard behavior
89
+ (entry[box][sizeType] as number)
90
+ }
@@ -0,0 +1,16 @@
1
+ import { type BlockSnapshot } from '@lark-opdev/block-docs-addon-api'
2
+ import { useEffect, useState } from 'react'
3
+ import { app } from '../util/app'
4
+ import { useBlock } from './useDocument'
5
+
6
+ export function useSelection() {
7
+ const { docRef } = useBlock()
8
+ const [selection, setSelection] = useState<BlockSnapshot[]>([])
9
+
10
+ useEffect(() => {
11
+ app.Selection.onSelectionChange(docRef, setSelection)
12
+ return () => { app.Selection.offSelectionChange(docRef, setSelection) }
13
+ }, [])
14
+
15
+ return selection
16
+ }
@@ -0,0 +1,40 @@
1
+ import { useCallback, useEffect, useRef } from 'react'
2
+
3
+ export type UseTimeoutFnReturn = [() => boolean | null, () => void, () => void]
4
+
5
+ export default function useTimeoutFn(fn: Function, ms = 0): UseTimeoutFnReturn {
6
+ const ready = useRef<boolean | null>(false)
7
+ const timeout = useRef<ReturnType<typeof setTimeout>>(undefined)
8
+ const callback = useRef(fn)
9
+
10
+ const isReady = useCallback(() => ready.current, [])
11
+
12
+ const set = useCallback(() => {
13
+ ready.current = false
14
+ if (timeout.current) { clearTimeout(timeout.current) }
15
+
16
+ timeout.current = setTimeout(() => {
17
+ ready.current = true
18
+ callback.current()
19
+ }, ms)
20
+ }, [ms])
21
+
22
+ const clear = useCallback(() => {
23
+ ready.current = null
24
+ if (timeout.current) { clearTimeout(timeout.current) }
25
+ }, [])
26
+
27
+ // update ref when function changes
28
+ useEffect(() => {
29
+ callback.current = fn
30
+ }, [fn])
31
+
32
+ // set on mount, clear on unmount
33
+ useEffect(() => {
34
+ set()
35
+
36
+ return clear
37
+ }, [ms])
38
+
39
+ return [isReady, clear, set]
40
+ }
package/src/index.css ADDED
@@ -0,0 +1,125 @@
1
+ @import "tailwindcss";
2
+
3
+ @custom-variant dark (&:is(.dark *));
4
+
5
+ @theme inline {
6
+ --radius-sm: calc(var(--radius) - 4px);
7
+ --radius-md: calc(var(--radius) - 2px);
8
+ --radius-lg: var(--radius);
9
+ --radius-xl: calc(var(--radius) + 4px);
10
+ --radius-2xl: calc(var(--radius) + 8px);
11
+ --radius-3xl: calc(var(--radius) + 12px);
12
+ --radius-4xl: calc(var(--radius) + 16px);
13
+ --color-background: var(--background);
14
+ --color-foreground: var(--foreground);
15
+ --color-card: var(--card);
16
+ --color-card-foreground: var(--card-foreground);
17
+ --color-popover: var(--popover);
18
+ --color-popover-foreground: var(--popover-foreground);
19
+ --color-primary: var(--primary);
20
+ --color-primary-foreground: var(--primary-foreground);
21
+ --color-secondary: var(--secondary);
22
+ --color-secondary-foreground: var(--secondary-foreground);
23
+ --color-muted: var(--muted);
24
+ --color-muted-foreground: var(--muted-foreground);
25
+ --color-accent: var(--accent);
26
+ --color-accent-foreground: var(--accent-foreground);
27
+ --color-destructive: var(--destructive);
28
+ --color-border: var(--border);
29
+ --color-input: var(--input);
30
+ --color-ring: var(--ring);
31
+ }
32
+
33
+ :root {
34
+ --radius: 0.625rem;
35
+ --background: oklch(1 0 0);
36
+ --foreground: oklch(0.145 0 0);
37
+ --card: oklch(1 0 0);
38
+ --card-foreground: oklch(0.145 0 0);
39
+ --popover: oklch(1 0 0);
40
+ --popover-foreground: oklch(0.145 0 0);
41
+ --primary: oklch(0.6 0.13 163);
42
+ --primary-foreground: oklch(0.98 0.02 166);
43
+ --secondary: oklch(0.97 0 0);
44
+ --secondary-foreground: oklch(0.205 0 0);
45
+ --muted: oklch(0.97 0 0);
46
+ --muted-foreground: oklch(0.556 0 0);
47
+ --accent: oklch(0.97 0 0);
48
+ --accent-foreground: oklch(0.205 0 0);
49
+ --destructive: oklch(0.577 0.245 27.325);
50
+ --border: oklch(0.922 0 0);
51
+ --input: oklch(0.922 0 0);
52
+ --ring: oklch(0.708 0 0);
53
+ --chart-1: oklch(0.646 0.222 41.116);
54
+ --chart-2: oklch(0.6 0.118 184.704);
55
+ --chart-3: oklch(0.398 0.07 227.392);
56
+ --chart-4: oklch(0.828 0.189 84.429);
57
+ --chart-5: oklch(0.769 0.188 70.08);
58
+ }
59
+
60
+ .dark {
61
+ --bg-float: rgb(41, 41, 41);
62
+ --background: #1a1a1a;
63
+ --foreground: oklch(0.985 0 0);
64
+ --card: var(--color-gray-800);
65
+ --card-foreground: oklch(0.985 0 0);
66
+ --popover: oklch(0.205 0 0);
67
+ --popover-foreground: oklch(0.985 0 0);
68
+ --primary: oklch(0.7 0.15 162);
69
+ --primary-foreground: oklch(0.26 0.05 173);
70
+ --secondary: oklch(0.269 0 0);
71
+ --secondary-foreground: oklch(0.985 0 0);
72
+ --muted: oklch(0.269 0 0);
73
+ --muted-foreground: oklch(0.708 0 0);
74
+ --accent: oklch(0.269 0 0);
75
+ --accent-foreground: oklch(0.985 0 0);
76
+ --destructive: oklch(0.704 0.191 22.216);
77
+ --border: #505050;
78
+ --input: oklch(1 0 0 / 15%);
79
+ --ring: rgb(25, 66, 148);
80
+ }
81
+
82
+
83
+ html, body {
84
+ overflow-y: hidden;
85
+ position: relative;
86
+ height: 100%;
87
+ }
88
+
89
+ body {
90
+ margin: 0;
91
+ background-color: var(--background);
92
+ color: #f0f0f0;
93
+ font-family: LarkHackSafariFont, LarkEmojiFont, LarkChineseQuote, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Tahoma, "PingFang SC", "Microsoft Yahei", Arial, "Hiragino Sans GB", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
94
+ }
95
+
96
+ @font-face {
97
+ font-family: LarkHackSafariFont;
98
+ src: local("Helvetica Neue");
99
+ unicode-range: u+0000;
100
+ }
101
+
102
+ @font-face {
103
+ font-family: SourceCodeProMac;
104
+ font-style: normal;
105
+ font-weight: 400;
106
+ src: url(data:application/font-woff2;charset=utf-8;base64,d09GMgABAAAAACGAAA4AAAAAUOAAACEoAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGnAbIBwqBmAAhWgRCArzCN1CC4RgAAE2AiQDhGQEIAWEXAeVQxvIQjVj3G0MzgMIoda9WhTVm0OiqBiksv//c1I7wiZOUsUbAxGFmDPHKM1RqrFqz/hmkVwxw18oC3ZYcgzHsAcYvPKcX549qYQbRC1YRHy239PvgovCRwrcpg4OUah5i1pcIgql6BXT2c77woO+mkQWE5goLhFkhsFRBblW27Wz6XV4ceGfWr9OjtDYJ7nwPT/27czcr7JxEfOkFl0bFY8bsQTNPXTIrln8DfHb/EOeVYBioUSESkiXFWDPYDMWUS7SVZeu8qfLcg193242hUqTftI5XPBuBwu47QUKKYljyjRO/f5vzvqvIZ5My/NnkhSmzeJ0s3sE6hRHmAM0ghSR7Tuj7p2yLAxB3dHA6YBkRvfdQs4aPAfM4wmNMPrR6X/ptL9S8H1pUh5RDVQCtUC7+23rbhSE8oDs1m6DAG3GJQBIwZz+JXTAFkJU6A7qOd1PjTSFlIHf5vMvm7ly5l2368j/hMQntIsTyhTNlUIZ8yv+yUIf4YIDq+YMdTeofAGFjzE33wsDaGvy1B1MSDUVmzzV8ieq3KjTdnx+R8B42aP+vE5z/V/Sa+SyDrlI+4+KI9FENGUSOdLXt5JzXCVx7CMfELmHQJMPkKcSwXTD2PLafWuXBYd5Lfw/f6icnGzKvhyyo5phE0enYDT48IMWsABWwqrIJknLCtzHzSZF/No761tuwplTY1JmY5QQIvrxcyZQMlzdmygWaEN3Tk6DgAqmomlgBQnGlBNhzFd30jp+ab9R9BAkGMckGMelIE5KMM5KQdyQgrh37iDuuwLGU/UlffWK/gGGbS2U6JQONmOW1QvCyACkP+4NrnB/VEEzFrNzXVszSEqBWXM4XzMKBneNAgDz1Vet1fCHBbgcHA6H4EFBEBaQ4fawTr3UOqAc6Pk13qQcxCPFrwXY4QDolecE6AkOGEA7AhMkyDef7wsoBVMRVya5VK3hGqnDLCts91BP9dKplljTPTa9F46wxL14DCsxgOOQQwk1dPEvkIhFJioxikWc/4XQWFnlVZ2lxS23zRX16IWTVpsXld4ThzjDbTyCRdiII5FFccX/cIoHfJi395zQSXO72///r5fs9Zt7CAHKfHHjxIoWJSIwFtjc7eJc6yxuIDomM5GsH5FLWGwuX2n3R1PpYR4AHYv++htsNoY5WObhWIBrIb5FeDoJLCa2TKYVsqyUbRWp1SSWk1lDbi2FdXKsp7aJzlZ62xhsZ7SDxS4mVnvY7LWP3X5Ohzgc4HJQrmPynVDolAInnVPqvDIXlLuo0lXVrqnSpd5NfdzS6I4Gt7V4qJ8H+vvbAP8Y6F+D/Gew/4300lhvTfDBRNN81eGb6Xr5XDbKK0xzme1U4ZIhegz11DDPDPfcCC8obeB3RZO7Wj0itITIUiobaWymtYXbYR5HeB2V57gipxU7o8RZNbrVuq7ODc3uCbivzWPtnhjttTHeGOedST6a4bvx3pvskyk+m+oLgFJiAI0AgFcDuAtUrgUaD4DCxUD2EQDILhJMN3LqkA2OI7mIvmPpROM7JaFnFO9Ucy2H6YJ3a8qWi9aThu2Wi57wJpoh1EPkScv1znVAJto8TE7vvJnJEgQZ2aqDwPGdnOQC6eU8d0/TTNO1c8/xpe/TwERKqRNv2b08dvMwb4fcIVtxO0iyNqXp2qCZM9cdBE4n1ykPaTamZTkNAotVYcBDvu3wvm8GXdKk2ZSOh62pa00qUzf1gWm29Ig5hpmVFseRrhe07XZH1ynxpSjyDVO6nxDYuqbQuEe2asaupJG44O/9cKAC6/iujloLrQMRGFNmZ1kDuskVbaAR8jcECX6MgaPtL0fzSNKcCFLlqwC//GqdWAz0fcEPJtPRyb+lQRi6jNAnjx68uUd0FInYZTMZQUGxM2yjQcd3OQOu57Sn4kwonyoxeTJxrEbhPOU7cVJMSO9pDC5jHUVME95ohtQactSwBJmLJpaPMbzQGtaiZbEJAWAyehks3Iol/D002AUOHRiaj/qfK5Aq8Cosj8yWsljuNVeppooYHGRWcrnKvqhs0MOL3pSjLXYwndyF7BUKqqnv5ShDzlzKRiTSbAbOEjvA6xX2V0HlETIQshOniTPWk0lxOA4qvcygLS3aQau5i9cKm83DGfBXxFqXPGhecEVQFGMzQS/yFL8sHCFIlad8KvfJk4TFebB1bjONJJ2P1jOZE2wgAItlgkwnd4NxSdrH8QFl/ZyqwY7FjCtypaOERLbpLqs4A7fR8CEad5QMqtW0Zj3ViTqtEXDC5nXs5PJn6XkYDn5OsJpIfLvK5NgbHtuCpNElDxzLqi9h9ajBTcieoEbNpquhmQkjOyG4nSWO2lqWwTPcw7BeTPa6udeADIsqSN8z6S0eou0epxYtHG9zMDy4IsE2EM/hnj/UThmDwSHgW3iqYLb/0cilaFr8glKzPTNssX1Z94pphG0Mom2NEZ9ph/ZdvLfw/WY9eIAkPgeycqCFfLXAIstv+oTvqlkTJ0DqX9EoeFNZdwAlwsQEii9uRHAnrQ+1N2s3GfxgMTS6a2zayoG7HByeKgLbyWrWS6o0TMMqrnL5xiuOtngqpV0PFWkRKRtBuDhKAGsoqQ8j85B5RXHCYlBhXgcldVuLOkJPznX5SZKpSS2noMSdJtho94EMKqM/LM78vNi68+6vl+KCV5YOCZzep+68eSomXzGxBlwMh038TiOWgDrylA4yU46QpqLebWqwYRIs3tiIKrrjm3u6FINMOQr+qINpGVTx9YviRLiWo6D4uErAr3ds3VervPRm5AxnQeaS6Ue3g53Y9QyY6v0/OdYrYFgcSTP4RzusKmpNQujAvmtE7QT2uiC75lCwQM8lgqVjRZhFR8adfnqad1IbE8nLBidrCXXKbXX4VuSnHYd67Vb/m/9UuRs3UWYT9XhYGROhOAFouIEWiV6YZqHBi+LleJi65bjqj6gU3H6tgJZTk2SJ6UjQtQ+NY6agfGdY/+tVI0wmISlcAoy/9h1IIs25oBBfnTo0t4UV1I5OSl2xNd5Yj75pl1zTTlF4ZPqzvfcBsCkShA2k0XrenFGTmJ9WnIu+HIGevTGffsdeEdTB863smSWwYX8Pb8+Mt5agYjpNm/dy+u60PF49wsW2luHwvXENGVZnXDcxQbf7P+PAcQeZxnlQoITvcAVGigZuhl+L/Lc9Oc26gb6CdfJAQ36p46KXVTIorI02c1EDkfa3jbIjslQQujtyxuH7nWDjlOPqb53zscI8S3oqpxcDzrqZ0DBph3LTSSeVKdy142vIsH0EcQlYtiigD/ywo/ZL+lqAzViLSUGKN4Jc4l7mqQntJEuQcq6ur4xqFimaixt9yaWRgLSD62h4PGjJoEzqWfv4XWxZ0zhkzAEyqeCfcpONNoyCX21MANf8fe9/NOvnunMfQR0O8gI9VkwLtP3tChPntKueKvW3LOvkwSrTLRlLBeE7FoxqJpyT0btpUJzijZ4S7mTolC9LnFttDUvL5IqP7Y5q7cLPtNPXCoZs8Dt3FYTVlz4f8MlxethlHSzpeG5cI7frSLlBZB2qkmvyGjNEFz46cVVa9Svetub3TPjNhBqjm3MebjFSDa8r005unlHDv5yMEv6UNyAxuheVF4qiGIrkCL9PykhB0hVF3EpvnTg4pOQM3KB0gKLWdCImy6wyZYPF/tT/HDJStCRBeVRAufjZyqwhnD/TN5nYsPW752y7BQn7Px5cProYPmy6HspA5Jb7n/nBauR5T6Itm06BMYYJ2uEofYTizJyAnZ1iPlLS17+GDn3iL2tt0GgnaIFddR39Vnvob1v1bWtQK970VR0m7UDGTlqvaaeg5BFHYspnP5zz8LhnxNOrhVeHP3UlG8cIaiBRjWnMGCO3VNX/ZYzNKwVTI9IrQzIae6FeixmSXnlX/UZxLvdhRxlenwVAZXDQh9nyG9hKWSHn2n+d7+gcK1GkTfPJFWl+kc5K4rB0pA8fGn28HEUdy5rHGA68Hcvndq5bYicPtngDTNPqTk3f5knDhjWP6WsMAy0dc/Wqq7GG2DcWwzIgNDjow615fdhKXOlZxuP/BnVz2ebfPuQpfr7OQuISduM2jdF1of5UCkpFLcuSRxsO7B1eJALpneEVIUReUKZfBV+l7zx5aho6wfhZlww0skFpdrUg9TXH2AlOhhsvz6wTJAFfh9cERxrLrn7rGS094u03tssLxnW4TTrDfODsKClJxNZDGfXFiSUzDP1QCWQiEk6fUviTxT1gTIHDheIEVD89cHfk3lyiGhcUF9ZH6HXMeLSDiLAaQb4DMCIziznqAuJwh4M4VJ1XzMqUlLDVeWrZD9bw1P9zUMIRG0m36Hq0XyFH++iamyTyaboG7ZMr0H66/gzYW9BkcyqUKqfA1oSwLkG1J3hmXOZ7EJdwOoHNUayOW4sBbdO1PqZYb8nmJiN6V00upU5KnTCPSPoz3Z7MUdQyBXt+WrE8mY7PSlKGzTQWUx7Y62qIlAzNztw0sXGg4DKAme7qIf1dsxfYO7ydApTejExPRxah9IJO1wID1rfUmcrlulK3Yn0GED7DI1yUHGanwtejHAu076Xa9xNQzvUQNdRB5S1yVMwoMSMaD1nhJYeGGhBFAPb8wZoC/0kSwSyBJCQLqexE3oM1L7xAyWtOcuj38APodsN94BxGa/QyxqWWhoY96IITuPlE1NfUsMqH2KqKxmK6JkQF7/CzhPidJ2c5yAlpJ+sS6E7irJG24LqEN/OA472cXmZS+XESWR7t4dh7SgyZrkuBpWrp9BQN0KbQWWb8c2GrnyLOqsAZlJQyIH0vJZbJVA4Cg6XBpQUVHnKf1wbgj91MFteKkygxpV55gdmnNSqNH2KeY7F9RqI1QPteRivTqgrwHKELOwXjEUSHJQ0NuRKpRlMZejTqjLgYJxWX4fVKaumESpPFpk2v3HtHA6Y7yU6Ona6J+zEGSajNLE9Qf8Kv16dhJtRA2bcy0F07odFsJvWtTJtEof64MDAatgtLuULXJlKQ6zPzsRgzt6msSKDAl+pYlamKhjbd/T4cpVyUnPxoJBo98lFyskglByXn3CfhLXX5oqx8p9/HdhN0ArUs0Sxy6jxuUH/O/Q8U/Ge1cfwBsWTnh5bmsW7gPNfLELOZVLEtcgbV7szP/2ctkP6vDMDjw+nmeE+unCYQW00ljtw8UYqXVKHOzZOkCEkVDlDyvzbEDRUEWZH0vZxcplLl4bjcPJxKJX65TECJlLG8UnqCZuRkAmHyyJtF59HaUdYo/DmAmf9rQ1rgRc0aberdPgj9AgpGUqVgWDBuEGifVkpQq39g07SMgoQCdTLiXgpmFtGK4ktqiZltX2ypLPz9nQdi0l1kVZw/qSwnM31XrTNRaBzIvAquLE1STIEiJmgnvtW8fYrbvuMdgTBkYWqkI44qMqStRphY4JsmxAuZ80RZBdkgz+9NvlpO19Cnu9wg9H9vdpI/UqWCfNHqftk/9NIfLdGqfpAvQuXOTrLX/1+Z9dkfqW2DyiM1kySf/MAzblZlpOB72r//9Hj6Rz1JN/0DnUwxbq+Pst+KviFPUybTiAfilEDPsPanapYybf0LNFeIXe+0k/e7UNQGBuqWY8N5pPwcuL+NrMtY9Nl4NAuQFLmlar2qWJrfUN3B6WiRF3lNkkyxjWMtu/XaEOFw6PgEo5JbhJZc3GGjW6Hth/ju+DWRdK7EvPVogyBY0NRPKPRZRBR5Xsn9LhRlCIO+XewOM9j9EhFALGjWvdJow690dC3U7m1HjO3rSF3Cqq/IDPRtBDq6Md0NYyxq3wfS9Ib5/zrpGiej3q36e4A2juppwJDpbamoc1uOIVmjLh7kTCzWYQclujwyc+zVw9IjW+vBwn0vjqOoQxi47LlKWEmWrCxtkIrUz/a48lV2XOZd5vRo9O34RFbeOVqfKPs2fmre9HyC1O7zJOra5uejXD4jBa0+/pIqdFOWf5pKT2f+5qOfe16G69oXdHcwtZaCsuW5ksTZmQnmhHprtK11hp+pZuopflMSjktrJjbB+owZBkgfk7ccQyYj7wW8bZx2aAG3EULbd0KmH6tIaaGbIeyKOZ3rlizp3DJzjvnT5mEHp+MXGEoJqXe1q7V5A0LrbOK3udTsrEK2Ig831OEgDFMWFHMkkgKOvAA3xBocCc0OaveMcdKU2EnUfjfPOIhB70UkphXcf4IkZ9NRNwMHnzXh+8zZ2o+tT05ReiryrDklJqwRnwvT4PIoDJ4Fx0zOF8sIpTKlA8cgOPFseLVaamIYoVJ36U3uTRNYXx7zPAM7aBpaSfGYS06qLzxigKQqXlrGcEyhNItYdM2BE3Up9Vbu1pmbYAQQE31+1fI49F5kJHmu8f61NJtC7sqpW5+PRCHc6TKuu0nZS3TqxuF0Zk9xx3af44503tKV/2iEPbdImHAbbKajdrIKOpEZJowKg1Fj0twYjAsU/u9ZmnvVP6D+fzfAhvyGN8fblqbRblIcuCU3DNHr47k+rtX0Rq4sMrB7HH8fg4Rp34R24p4YbA2W0ImlZmRZLO1qfJSU6OCLHJbyMqGHpn4ipJyvLXL3aEMsgCGRKaNL9h2LYG65hmT2O+hkVWk0nCTT9DdWHLxnOiayrR48/4Jc/lPU/28PQa4kFGdrvBFBkvXi9xEciSvCUeRxW71UMEfm/X8788s/k0L7+SXESex7SdG85BoS/WFBBnRWxLUmEX7gI9sKLf1j+MBCmntsGCnZgLiyefG0NOL7Hcsz9vwD4KbbTxOTSa2Pqc3Tc+amvCpNNLc/YqZ09vy6eRInZNrDrej7dVIdnJYfVemo9ab8CAXp+sYgeeRMfGRwmLL2pnJslZXQgiXFUjwcT6SfHOn/a/eNqEZyzBAN3rao3+T2jTXxkTXkSF8squr2T4Dofp3XgmI2+s9JfxD9SwBCbzjDfykrywoeysyD0hWb7T6WA+5qQ9IxmoA1mavw0q/9rtlCV2uVQqTfdZV31DaNvYW3LkRE1JVBYIkspYhl09Il8jXQnK7BMGMwGV4tVe+AhA9kRobxnbfibd93qndmsgmSmUkm6Jeu/tnwS/XLSAd/WJQta+DtVnTj7cE2ro62SmkhKg9YUSzdZ8cKi8AMrZnDssWvtVuVYCB3MG8wcuCak+noUW9TkhWZWmFa5qI5A5g2aEt2EVTziGItqiihpalinuEohrlwN34Rb5HGoAGdK4KjQsNjQ29Ls1v7Ys2XLeicCzB9mphWqwqNDQ+NDlbSjDNH9tXFUnSfHYMsRDMktZDM8IFz7C1ilNIMomVqeX5YlawqwcOTerCtRn1GS7bXw5dUyypv2BlbozuXk5lqIluD9skUaB9ToyTSsXN/b2jTHQMmrSHaOqmxr3WKIepOUrCdQ6wSVQpzuXIPrt1kwLbKPHkCvU9U8Y+dfjSmJv1jLMq9GERal8SsbjHxDJClJN8YfS2o7OyPQo3DU55lCWVaoP1HSkhWh3Y5+KhS2hKU1KmUMMimjVfSo3OySqvlE9PssPhajqiWY6zlCGu557xL9+SK9uQa9+QK9+S9Avu7igpn54CI2fyy/IAO0GQ5hbOLgPyELj9QBsK69BWzc9R+SO3PAatOlAec5QGNWgOpNWCJ2rGZiuga0zcqYxzHvqXHY9c8ngNqz6L+rFoWE1OYxbYfJm49N4oy2bYjYPvML1lfAIYjerN6gaDAPf3yGy3IcZMQR8hHMgTo31+eAsap9J2PvhL5hkQ8PtHAJ359tAsYpjQXBuNOg6gGxoWk6CR0PDEpGt0AuPQ86Qka/eSr6Fs00AaM1l/EArfSiZsSEjcmJhyEeGi+8mIH9zZsEwix9/+IpLiDOlQwA5WcmN4z1PN7MU9iMDA0Pp3Oo9F4l3Pxx6KOpCQfQcVKTjkCGAdpCho1J+6Eg0qztyIPJqMPIVGH0MkHQewFU/50yb3pRjQIjp5QBWzuwCqtyxOQgnVdJk6vYrYepGr4RnbH+Du/XYjhUK7jE0e0W3cMaINQqOvaBJAUJBo7gJPxSo6dA9tCZgi6AxBB4s0dfwoYV7A9N38GC2QKAkEhEyS8utkD1m78mv0V0OeohchYIwo1CYWctKCnyF59XyVy4f9dXzlfAYZP6WX3kmZ+aC3oM01EoVTRN94rCwFqtsRRU5ONHfMH7yGQQNhbHGjW4of8+D0X8a9E/hZ6Ky+q0fPXeuVW+rgC5kV5szN6/ZtqnhXXsmtqHC0vsrXr8eL+CBI+GrSB5uIhL3LX41b/DQgnwG9Iw6I7gSGNcgOXOKJdtnNgFYREnfImAEtqkNEBcrCYnQmIEXcd+0YoZhAI/6EzfA+BF1gN9oBjEyi2fRPTiD4Otm3jND7AnALXoWMTU/DkodvEn4j+BI37DFnd/XIlhnvOw1Ju9W4c8p/9Kz4c25JhDUMgalwTxgggNAfhAENixyYegCRxDTBGdOjzfTBkXxmGJ2KpeMK+MXkVIkoQWoYJL5EGAecRAnOG0ITAsYl7Hhg9tvSMFZq27dqnRcu2fbdMzd0hpB03AqPphJfpJArBCYxunBJ7ZqSj3rznYasGB0clRwzph9XBkRNSBvEscOLUa2ZERzZlN/7/Ggb32K0GmBRVXiTYwJETGL/xKi5q8Hf3wxP7JnnnNsbTsXS83+ntap9es69899uAiv6/p41vwRAx4VmyOASziCrU1GR+HII8EXDiPowizoyIEyrDkE/7V/Qa2xFDhnE0sGeWrAYRJUgacOR0HjU6t06jnGWBiFiMOcMDNs30HpTxd/AHOHLirvtmHnniKSWTWMCOPZrIWDrYG6bPeRjnOZCxaReJgGnjUDJz+s6bblUpOclv/2mFel73YFr0XGf3EPk2Q909AWcGUXHqjh1x6VmwovYgkgJR9PgxXxeMA8zArVkRoYCASlhF5dLNULhCskdemGokHAeHU6EoehqPeXXWctC3mAMBBdVpFSdd6kvFs0ofnYPG+42hTqJfqSlgOo4ROY0/yCdfYxe1cE8ecLCmRKUpaEUeFfB13VyXlkGEvLrVeTBNVHr8mEBPEFaDauagbssIlR4veGkQrnisQAfMpkLR0uPHIAH5mjpQzNHmAAIKrskpuCf/8oGJAGwPJa0yvjp+KFhFlSi6fqw7lyHNOXx1qaFQJYopXZdndnlZw4NmAc5I3TgvWap0AcHCvO5FFuqHzzd8beua0nU3YBacuegFjAmL3Q1n4AKchW42K/Qay/ASSkN4gs7z6oxFgL54e+aHnpX5hc+c8ZW7kTSp2CdphZe5uthXQzncCyOgryYkdRDoib6sBpZVYuoDpT50E9RNYtIkeuGTRwV8XbespdM8S8AZuFi5m1lAE9ltrtP0QacToMJQtXlWtmpQ4xwU0zJCpc4xCQP4AkMd64J49xKXuBkkINRomSOU2PLqm7fDLDgDd+Ci0H1cYOQlD0wYeIm7E3YwXuumuBtfQLmrHjh3kLDtGQB3uBtdEEPVuzswQJmircsiG2Ge7JsdDn8GgAfH8uto/IyHP/e6r5OmgkUMsQTx6P9bgJcWRI8NABi3pwkXoKAKBs+vntRytRJxKOfiN56LB1cVDTqHCPpTcXGS0TEq1YeLTCmZWYx0bMIYxQB7lzWVms/NHqeVFPGO7BGs8To3QTXCRL5EEcklq+JrsjvQL4kDIuL3B9VJcRRcWVGcmQVkcTrSKEWw6sooRZJEH+zKzuC6kkzpjfuILDhLm9EJuKqNkdRdEhuEkaPAQCWvh6eCHQdDEwavCo0yHbDBS9+st9pSi+yw3UY7vPDRPGu8Ar4WuugYH3zhDs553VbbrbdXi01YCPgIBhpBnjhNQmQAFr/KaBfwq4wCmzdNZcIBdAHyJNHd5JNMjbMnBQvsbTfDn5Tl4IJOyjF4Y3e2xpxtTSOgr0Fa1KtVpw0WHxdvTGYS5YeGVaoE+FXjtB6DtGqjTdvFY5mA3axSQIu+EfOZQ1XYeYKNGiXZbZ21arSatNrn9I+oZxZtN7vSuu4Tq9oEnVoMuxdfq10jnxY8bJIkpBW11HSMzm1GRtQhFowczCFZngfBVvWe/pth7U6KkweWVU8qaq8T0KbSmNxfhtgksvYmPg2qeVojNTeq58cHEz2wLAttxme94Wpu01c2zokfUILN1ymM7UWwCWdHB3lwNWvMjX2MHdGmRyCI24S5jw9Q7GWNCJTNgr7IKKjoGJhY2DiD4T8QImISmbLJyGnpGRiZWdg5OLm45cqTr0CREqW7WKw2e/+ElyAcTpfb4xUPAQlVrwSJ0JIkS5EqDUa6jL7DwsEjICIho6CiofcPARMLGwcXD5+AkIiYRKYs2aRk5BRy+s8dGByBRKExWByeQCSRKVQancEEWCCbw+V1CCAQisT1+Cjtuc9yhVKl7rd6B23X6Q2OfpPZYrX1TRvk6ubu4enl7ePr9xiWAUAQGAKFwRHIJhCNweLwBCKJTKHS6Awmi83h8vgtkFAklkhlcoVSpdZodXqD0WS2WG12h9Pl9nh9fOE2BMVwgqRohsXmcHl8gVAklkhlcoVSpdZodXqD0WS2WG12h9Pl9nh9fpfb8Hh9sPvq2UGaOoRObBAz9R2wdNJNicbyyrGJTXnfaa2PL1UL8e3VEn8lZK0hkfeLmBcplwKZyUQtRdlbUiia/xS1pCBQDlU8T6WFVNYHSd10GzGW4xijJMOKAEPDCBX23Bt3qlqTfbGpTOD2svkrOZfeIpwIyzopr0OCN8wVtIOY/JRZFKIzw1CHf4l5vxTvalcwBStTBeRspOzWxjiVoPc3L6VkFWreSm1N5TKtbSNr0OmbvxNuP/Fl0qBbJ3WnWXObKYhQgpGyh5ERYKAlucLldztBkGFXgnmh/jOSgkGEE0ATO6BreZByAa8a71kCQnFUQYMBK+wE7ZJyASF3D/iF9sMKWAkCjh/AvNSvOh2Aw/cwcobDsTPd81TwDn3BtdVN6PYyI2SjklV5nisJpr1kRGRPJlqSfqlkILJ4OezwgeKQU9j1FROBKKAgK9nqKgrV1XOpoWXyr1po4jfCzrvpauTb0PjtXuju/Rtfwgb9wON71+vHg+pxAjCcpQQvUxXGbO2N4wI6NBiRVcbkdfWKjT8UymmMXNO5pyvL95TZsXpvrPFuODQEOOwsBzb5DQ4s4P4U9rEBCg7bd5BnDUCABMSji0NQocMEyxpEPBJuwo28xd2Eh/wDDrzgk+UHT9mnt7KOTtz+ltz/9IDVRkurap1Or28mkQ3dyTrMxZyo4uVTl0euswKBBouzk65KVMq+/p8BwCSDkAJKKlSyQic7DHLAJCcscoGRBk46BBGuKKAfN0o0L2Sqsi9aKO3+7bR00WaS5ZgMuSCJo6TAV/f58TDl9QAAAAA=) format("woff2");
107
+ unicode-range: u+0100-024f,u+0259,u+1e??,u+2020,u+20a0-20ab,u+20ad-20cf,u+2113,u+2c60-2c7f,u+a720-a7ff
108
+ }
109
+
110
+ @font-face {
111
+ font-family: SourceCodeProMac;
112
+ font-style: normal;
113
+ font-weight: 400;
114
+ src: url(data:application/font-woff2;charset=utf-8;base64,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) format("woff2");
115
+ unicode-range: u+00??,u+0131,u+0152-0153,u+02bb-02bc,u+02c6,u+02da,u+02dc,u+2000-206f,u+2074,u+20ac,u+2122,u+2191,u+2193,u+2212,u+2215,u+feff,u+fffd
116
+ }
117
+
118
+ @layer base {
119
+ * {
120
+ @apply border-border outline-ring/50;
121
+ }
122
+ body {
123
+ @apply bg-background text-foreground;
124
+ }
125
+ }
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from 'clsx'
2
+ import { twMerge } from 'tailwind-merge'
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
package/src/panel.html ADDED
@@ -0,0 +1,11 @@
1
+ <!doctype html>
2
+ <html lang="en" class="dark">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
6
+ </head>
7
+ <body>
8
+ <div id="root"></div>
9
+ <script type="module" src="/panel.tsx"></script>
10
+ </body>
11
+ </html>
package/src/panel.tsx ADDED
@@ -0,0 +1,14 @@
1
+ import './index.css'
2
+
3
+ import { StrictMode } from 'react'
4
+ import { createRoot } from 'react-dom/client'
5
+ import { Panel } from './entries/Panel.tsx'
6
+ import { BlockProvider } from './providers/BlockProvider.tsx'
7
+
8
+ createRoot(document.getElementById('root')!).render(
9
+ <StrictMode>
10
+ <BlockProvider>
11
+ <Panel />
12
+ </BlockProvider>
13
+ </StrictMode>
14
+ )
@@ -0,0 +1,10 @@
1
+ import { BlockRef, DocumentRef } from '@lark-opdev/block-docs-addon-api'
2
+ import { createContext } from 'react'
3
+
4
+ export interface BlockContextValue {
5
+ docRef: DocumentRef
6
+ blockRef: BlockRef
7
+ initData: unknown
8
+ }
9
+
10
+ export const BlockContext = createContext<BlockContextValue>(null!)
@@ -0,0 +1,30 @@
1
+ import type { BlockRef, DocumentRef } from '@lark-opdev/block-docs-addon-api'
2
+ import { type FunctionComponent, type PropsWithChildren, useEffect, useRef, useState } from 'react'
3
+ import { useResizeObserver } from '../hooks/useResizeObserver'
4
+ import { app } from '../util/app'
5
+ import { BlockContext } from './BlockProvider.context'
6
+
7
+ export const BlockProvider: FunctionComponent<PropsWithChildren> = ({ children }) => {
8
+ const ref = useRef<HTMLDivElement>(null!)
9
+ const [docRef, setDocRef] = useState<DocumentRef>()
10
+ const [blockRef, setBlockRef] = useState<BlockRef>()
11
+ const [initData, setInitData] = useState<unknown>()
12
+
13
+ useResizeObserver({ ref, box: 'border-box', onResize: (size) => { app.Bridge.updateHeight(size.height) } })
14
+
15
+ useEffect(() => {
16
+ app.getActiveBlockRef().then(setBlockRef)
17
+ app.getActiveDocumentRef().then(setDocRef)
18
+ app.Bridge.getInitData().then(setInitData)
19
+ }, [])
20
+
21
+ return (
22
+ <div ref={ref}>
23
+ {(docRef && blockRef) && (
24
+ <BlockContext.Provider value={{ blockRef, docRef, initData }}>
25
+ {children}
26
+ </BlockContext.Provider>
27
+ )}
28
+ </div>
29
+ )
30
+ }
Binary file
@@ -0,0 +1,11 @@
1
+ <!doctype html>
2
+ <html lang="en" class="dark">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
6
+ </head>
7
+ <body>
8
+ <div id="root"></div>
9
+ <script type="module" src="/settings.tsx"></script>
10
+ </body>
11
+ </html>
@@ -0,0 +1,14 @@
1
+ import './index.css'
2
+
3
+ import { StrictMode } from 'react'
4
+ import { createRoot } from 'react-dom/client'
5
+ import { Settings } from './entries/Settings'
6
+ import { BlockProvider } from './providers/BlockProvider'
7
+
8
+ createRoot(document.getElementById('root')!).render(
9
+ <StrictMode>
10
+ <BlockProvider>
11
+ <Settings />
12
+ </BlockProvider>
13
+ </StrictMode>
14
+ )
@@ -0,0 +1,3 @@
1
+ import { BlockitClient } from '@lark-opdev/block-docs-addon-api'
2
+
3
+ export const app = new BlockitClient().initAPI()
@@ -0,0 +1,27 @@
1
+ import { type CSSProperties } from 'react'
2
+
3
+ function makeUnits(value: number | number[]) {
4
+ const values = Array.isArray(value) ? value : [value]
5
+ return values.map((v) => `${v * 4}px`).join(' ')
6
+ }
7
+
8
+ export interface BoxProps {
9
+ flex?: 'row' | 'column' | number
10
+ gap?: number
11
+ p?: number | number[]
12
+ m?: number | number[]
13
+ }
14
+
15
+ export function box({ flex, gap, p, m }: BoxProps, rest?: CSSProperties): CSSProperties {
16
+ const result: CSSProperties = { ...rest }
17
+ if (typeof flex === 'string' && ['row', 'column'].includes(flex)) {
18
+ result.display = 'flex'
19
+ result.flexDirection = flex
20
+ } else if (typeof flex === 'number') {
21
+ result.flex = flex
22
+ }
23
+ if (gap) { result.gap = gap * 4 }
24
+ if (p) { result.padding = makeUnits(p) }
25
+ if (m) { result.margin = makeUnits(m) }
26
+ return result
27
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4
+ "target": "ES2022",
5
+ "useDefineForClassFields": true,
6
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
+ "module": "ESNext",
8
+ "types": ["vite/client"],
9
+ "skipLibCheck": true,
10
+
11
+ /* Bundler mode */
12
+ "moduleResolution": "bundler",
13
+ "allowImportingTsExtensions": true,
14
+ "verbatimModuleSyntax": false,
15
+ "moduleDetection": "force",
16
+ "noEmit": true,
17
+ "jsx": "react-jsx",
18
+
19
+ /* Linting */
20
+ "strict": true,
21
+ "noUnusedLocals": true,
22
+ "noUnusedParameters": true,
23
+ "erasableSyntaxOnly": true,
24
+ "noFallthroughCasesInSwitch": true,
25
+ "noUncheckedSideEffectImports": true,
26
+
27
+ "baseUrl": ".",
28
+ "paths": {
29
+ "@/*": [
30
+ "./src/*"
31
+ ]
32
+ }
33
+ },
34
+ "include": ["src"]
35
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "files": [],
3
+ "references": [
4
+ { "path": "./tsconfig.app.json" },
5
+ { "path": "./tsconfig.node.json" }
6
+ ],
7
+ "compilerOptions": {
8
+ "baseUrl": ".",
9
+ "paths": {
10
+ "@/*": ["./src/*"]
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
+ "target": "ES2023",
5
+ "lib": ["ES2023"],
6
+ "module": "ESNext",
7
+ "types": ["node"],
8
+ "skipLibCheck": true,
9
+
10
+ /* Bundler mode */
11
+ "moduleResolution": "bundler",
12
+ "allowImportingTsExtensions": true,
13
+ "verbatimModuleSyntax": false,
14
+ "moduleDetection": "force",
15
+ "noEmit": true,
16
+
17
+ /* Linting */
18
+ "strict": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "erasableSyntaxOnly": true,
22
+ "noFallthroughCasesInSwitch": true,
23
+ "noUncheckedSideEffectImports": true
24
+ },
25
+ "include": ["vite.config.ts", "vite"]
26
+ }