@potok-web-framework/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/bun.lock +25 -0
- package/package.json +39 -0
- package/src/block.ts +102 -0
- package/src/bootstrap-app.ts +115 -0
- package/src/client-only.ts +17 -0
- package/src/constants.ts +27 -0
- package/src/context.ts +85 -0
- package/src/detect-child.ts +21 -0
- package/src/error-boundary.ts +51 -0
- package/src/exports/client.ts +1 -0
- package/src/exports/hmr.ts +1 -0
- package/src/exports/index.ts +21 -0
- package/src/exports/jsx-runtime.ts +4 -0
- package/src/exports/server.ts +1 -0
- package/src/fragment.ts +28 -0
- package/src/global.dev.d.ts +12 -0
- package/src/hmr/hmr-dev.ts +10 -0
- package/src/hmr/register-component.ts +109 -0
- package/src/hmr/registered-component.ts +59 -0
- package/src/hmr/registry.ts +78 -0
- package/src/hmr/types.ts +6 -0
- package/src/hmr/utils.ts +20 -0
- package/src/html-element.ts +95 -0
- package/src/jsx-types.ts +13 -0
- package/src/lazy.ts +44 -0
- package/src/lib-context-reader.ts +33 -0
- package/src/lib-scripts.ts +8 -0
- package/src/lifecycle.ts +44 -0
- package/src/list.ts +175 -0
- package/src/portal.ts +101 -0
- package/src/prop-types.ts +1165 -0
- package/src/ref.ts +11 -0
- package/src/render-to-dom.ts +325 -0
- package/src/render-to-string.ts +65 -0
- package/src/server-node.ts +98 -0
- package/src/show.ts +46 -0
- package/src/signals.ts +323 -0
- package/src/store.ts +68 -0
- package/src/text.ts +35 -0
- package/src/types.ts +69 -0
- package/src/utils.ts +118 -0
- package/tests/signals.test.ts +403 -0
- package/tsconfig.json +17 -0
- package/vite.config.ts +21 -0
package/CHANGELOG.md
ADDED
package/bun.lock
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lockfileVersion": 1,
|
|
3
|
+
"workspaces": {
|
|
4
|
+
"": {
|
|
5
|
+
"name": "web-framework",
|
|
6
|
+
"devDependencies": {
|
|
7
|
+
"@types/bun": "latest",
|
|
8
|
+
},
|
|
9
|
+
"peerDependencies": {
|
|
10
|
+
"typescript": "^5",
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
"packages": {
|
|
15
|
+
"@types/bun": ["@types/bun@1.2.17", "", { "dependencies": { "bun-types": "1.2.17" } }, "sha512-l/BYs/JYt+cXA/0+wUhulYJB6a6p//GTPiJ7nV+QHa8iiId4HZmnu/3J/SowP5g0rTiERY2kfGKXEK5Ehltx4Q=="],
|
|
16
|
+
|
|
17
|
+
"@types/node": ["@types/node@24.0.3", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-R4I/kzCYAdRLzfiCabn9hxWfbuHS573x+r0dJMkkzThEa7pbrcDWK+9zu3e7aBOouf+rQAciqPFMnxwr0aWgKg=="],
|
|
18
|
+
|
|
19
|
+
"bun-types": ["bun-types@1.2.17", "", { "dependencies": { "@types/node": "*" } }, "sha512-ElC7ItwT3SCQwYZDYoAH+q6KT4Fxjl8DtZ6qDulUFBmXA8YB4xo+l54J9ZJN+k2pphfn9vk7kfubeSd5QfTVJQ=="],
|
|
20
|
+
|
|
21
|
+
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
|
|
22
|
+
|
|
23
|
+
"undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
|
|
24
|
+
}
|
|
25
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@potok-web-framework/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"exports": {
|
|
5
|
+
".": {
|
|
6
|
+
"import": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/exports/index.d.ts"
|
|
8
|
+
},
|
|
9
|
+
"./server": {
|
|
10
|
+
"import": "./dist/server.mjs",
|
|
11
|
+
"types": "./dist/exports/server.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./client": {
|
|
14
|
+
"import": "./dist/client.mjs",
|
|
15
|
+
"types": "./dist/exports/client.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"./jsx-runtime": {
|
|
18
|
+
"import": "./dist/jsx-runtime.mjs"
|
|
19
|
+
},
|
|
20
|
+
"./hmr": {
|
|
21
|
+
"import": "./dist/hmr.mjs"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "vite build",
|
|
26
|
+
"build:watch": "vite build --watch"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/bun": "catalog:",
|
|
30
|
+
"fast-deep-equal": "^3.1.3",
|
|
31
|
+
"fetch-to-node": "^2.1.0",
|
|
32
|
+
"klona": "^2.0.6",
|
|
33
|
+
"vite": "catalog:",
|
|
34
|
+
"vite-plugin-dts": "catalog:"
|
|
35
|
+
},
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"typescript": "catalog:"
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/block.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { Effect } from './signals'
|
|
2
|
+
import type { LibContext, LibHtmlElementNode, LibNode, LibProps } from './types'
|
|
3
|
+
|
|
4
|
+
export abstract class LibBlock {
|
|
5
|
+
node: LibNode | null = null
|
|
6
|
+
abstract context: LibContext
|
|
7
|
+
abstract props: LibProps
|
|
8
|
+
effects: Effect[] = []
|
|
9
|
+
children: (LibBlock | null)[] = []
|
|
10
|
+
|
|
11
|
+
get nearestParentElement(): LibHtmlElementNode | null {
|
|
12
|
+
return (
|
|
13
|
+
(this.node as LibHtmlElementNode) ??
|
|
14
|
+
this.context.parentBlock?.nearestParentElement ??
|
|
15
|
+
null
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get previousBlock(): LibBlock | null {
|
|
20
|
+
const parentBlock = this.context.parentBlock
|
|
21
|
+
|
|
22
|
+
if (!parentBlock) {
|
|
23
|
+
return null
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const previousBlock = parentBlock.children[this.context.index - 1]
|
|
27
|
+
|
|
28
|
+
if (previousBlock) {
|
|
29
|
+
return previousBlock
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!parentBlock.node) {
|
|
33
|
+
return parentBlock.previousBlock
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return null
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get nearestPreviousNode(): LibNode | null {
|
|
40
|
+
if (this.node) {
|
|
41
|
+
return this.node
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const lastChild = this.children[this.children.length - 1]
|
|
45
|
+
if (lastChild) {
|
|
46
|
+
return lastChild.nearestPreviousNode
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const previousBlock = this.previousBlock
|
|
50
|
+
if (previousBlock) {
|
|
51
|
+
return previousBlock.nearestPreviousNode
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return null
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get previousNode(): LibNode | null {
|
|
58
|
+
const previousBlock = this.previousBlock
|
|
59
|
+
|
|
60
|
+
if (previousBlock) {
|
|
61
|
+
return previousBlock.nearestPreviousNode
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return null
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
addEffect(effect: Effect) {
|
|
68
|
+
this.effects.push(effect)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
unmountChildren() {
|
|
72
|
+
this.children.forEach((childBlock) => {
|
|
73
|
+
childBlock?.unmount()
|
|
74
|
+
})
|
|
75
|
+
this.children = []
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
insertNode() {
|
|
79
|
+
if (!this.node) {
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this.context.insertNode(
|
|
84
|
+
this.context.parentBlock?.nearestParentElement ?? null,
|
|
85
|
+
this.node,
|
|
86
|
+
this.previousNode,
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
unmount() {
|
|
91
|
+
if (this.node) {
|
|
92
|
+
this.context.removeNode(this.node)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
this.unmountChildren()
|
|
96
|
+
|
|
97
|
+
this.effects.forEach((effect) => {
|
|
98
|
+
effect.dispose()
|
|
99
|
+
})
|
|
100
|
+
this.effects = []
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { CLIENT_ENTRY_FILE_NAME } from './constants'
|
|
2
|
+
import { PortalIn } from './portal'
|
|
3
|
+
import { renderToString } from './render-to-string'
|
|
4
|
+
import path from 'path'
|
|
5
|
+
import type { PotokElement } from './types'
|
|
6
|
+
import { toFetchResponse, toReqRes } from 'fetch-to-node'
|
|
7
|
+
import { fragment } from './fragment'
|
|
8
|
+
import { htmlElement } from './html-element'
|
|
9
|
+
|
|
10
|
+
type App = (request: Request) => PotokElement
|
|
11
|
+
type BootstrapAppOptions = {
|
|
12
|
+
app: App
|
|
13
|
+
port?: number
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let serverStarted = false
|
|
17
|
+
let setApp: (app: App) => void = () => {}
|
|
18
|
+
|
|
19
|
+
export function bootstrapApp(options: BootstrapAppOptions) {
|
|
20
|
+
const port = options.port ?? 3000
|
|
21
|
+
|
|
22
|
+
if (!serverStarted) {
|
|
23
|
+
let currentApp = options.app
|
|
24
|
+
|
|
25
|
+
setApp = (app: App) => {
|
|
26
|
+
currentApp = app
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
Bun.serve({
|
|
30
|
+
async fetch(request) {
|
|
31
|
+
const url = new URL(request.url)
|
|
32
|
+
const pathname = decodeURIComponent(url.pathname)
|
|
33
|
+
|
|
34
|
+
if (process.env.NODE_ENV === 'development') {
|
|
35
|
+
const viteServer = __POTOK_DEV__?.vite
|
|
36
|
+
|
|
37
|
+
if (viteServer) {
|
|
38
|
+
const response = await new Promise<Response | undefined>(
|
|
39
|
+
(resolve) => {
|
|
40
|
+
const { req, res } = toReqRes(request)
|
|
41
|
+
|
|
42
|
+
const originalEnd = res.end.bind(res)
|
|
43
|
+
|
|
44
|
+
res.end = (...args: any[]) => {
|
|
45
|
+
const response = originalEnd(...args)
|
|
46
|
+
resolve(toFetchResponse(response))
|
|
47
|
+
return response
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
viteServer.middlewares(req, res, () => {
|
|
51
|
+
resolve(undefined)
|
|
52
|
+
})
|
|
53
|
+
},
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
if (response) {
|
|
57
|
+
return response
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (/\.[a-z0-9]+$/i.test(pathname)) {
|
|
63
|
+
const file = Bun.file(path.join(process.cwd(), 'dist', pathname))
|
|
64
|
+
if (await file.exists()) {
|
|
65
|
+
return new Response(file, {
|
|
66
|
+
headers: { 'Content-Type': file.type },
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const html = await renderToString(
|
|
72
|
+
fragment({
|
|
73
|
+
children: [
|
|
74
|
+
currentApp(request),
|
|
75
|
+
PortalIn({
|
|
76
|
+
name: 'lib-scripts',
|
|
77
|
+
children: __POTOK_DEV__
|
|
78
|
+
? fragment({
|
|
79
|
+
children: [
|
|
80
|
+
htmlElement({
|
|
81
|
+
tag: 'script',
|
|
82
|
+
type: 'module',
|
|
83
|
+
src: '/@vite/client',
|
|
84
|
+
}),
|
|
85
|
+
htmlElement({
|
|
86
|
+
tag: 'script',
|
|
87
|
+
type: 'module',
|
|
88
|
+
src: '/src/client.ts',
|
|
89
|
+
}),
|
|
90
|
+
],
|
|
91
|
+
})
|
|
92
|
+
: htmlElement({
|
|
93
|
+
tag: 'script',
|
|
94
|
+
type: 'module',
|
|
95
|
+
src: `/${CLIENT_ENTRY_FILE_NAME}.js`,
|
|
96
|
+
}),
|
|
97
|
+
}),
|
|
98
|
+
],
|
|
99
|
+
}),
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
return new Response(html, {
|
|
103
|
+
headers: { 'Content-Type': 'text/html; charset=utf-8' },
|
|
104
|
+
})
|
|
105
|
+
},
|
|
106
|
+
port,
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
serverStarted = true
|
|
110
|
+
|
|
111
|
+
console.log(`Приложение запущено на порте ${port}`)
|
|
112
|
+
} else {
|
|
113
|
+
setApp(options.app)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { LibContextReader } from './lib-context-reader'
|
|
2
|
+
import { Show } from './show'
|
|
3
|
+
import { PotokElement, WithChildren } from './types'
|
|
4
|
+
|
|
5
|
+
export type ClientOnlyProps = WithChildren<{}>
|
|
6
|
+
|
|
7
|
+
export function ClientOnly(props: ClientOnlyProps): PotokElement {
|
|
8
|
+
return LibContextReader({
|
|
9
|
+
children: (context) =>
|
|
10
|
+
Show({
|
|
11
|
+
get when() {
|
|
12
|
+
return !context.isServer && !context.isHydrating
|
|
13
|
+
},
|
|
14
|
+
children: props.children,
|
|
15
|
+
}),
|
|
16
|
+
})
|
|
17
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const HTML_ELEMENT_STYLE_PX_PROPERTIES = new Set([
|
|
2
|
+
'width',
|
|
3
|
+
'height',
|
|
4
|
+
'top',
|
|
5
|
+
'left',
|
|
6
|
+
'right',
|
|
7
|
+
'bottom',
|
|
8
|
+
'margin',
|
|
9
|
+
'marginTop',
|
|
10
|
+
'marginBottom',
|
|
11
|
+
'marginLeft',
|
|
12
|
+
'marginRight',
|
|
13
|
+
'padding',
|
|
14
|
+
'paddingTop',
|
|
15
|
+
'paddingBottom',
|
|
16
|
+
'paddingLeft',
|
|
17
|
+
'paddingRight',
|
|
18
|
+
'fontSize',
|
|
19
|
+
'borderWidth',
|
|
20
|
+
'borderRadius',
|
|
21
|
+
'maxWidth',
|
|
22
|
+
'minWidth',
|
|
23
|
+
'maxHeight',
|
|
24
|
+
'minHeight',
|
|
25
|
+
])
|
|
26
|
+
|
|
27
|
+
export const CLIENT_ENTRY_FILE_NAME = 'client'
|
package/src/context.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { LibBlock } from './block'
|
|
2
|
+
import type {
|
|
3
|
+
LibContext,
|
|
4
|
+
MaybeArray,
|
|
5
|
+
PotokElement,
|
|
6
|
+
WithChildren,
|
|
7
|
+
} from './types'
|
|
8
|
+
import { mergeContext, normalizeArray, normalizeChildren } from './utils'
|
|
9
|
+
|
|
10
|
+
type ContextProviderProps<Value extends Record<string, unknown>> =
|
|
11
|
+
WithChildren<{
|
|
12
|
+
value: Value
|
|
13
|
+
}>
|
|
14
|
+
|
|
15
|
+
class ContextProvider<Value extends Record<string, unknown>> extends LibBlock {
|
|
16
|
+
constructor(
|
|
17
|
+
readonly props: ContextProviderProps<Value>,
|
|
18
|
+
key: symbol,
|
|
19
|
+
readonly context: LibContext
|
|
20
|
+
) {
|
|
21
|
+
super()
|
|
22
|
+
|
|
23
|
+
normalizeChildren(props.children).forEach((childCreator, index) => {
|
|
24
|
+
this.children.push(
|
|
25
|
+
childCreator(
|
|
26
|
+
mergeContext(context, {
|
|
27
|
+
parentBlock: this,
|
|
28
|
+
index,
|
|
29
|
+
contexts: {
|
|
30
|
+
[key]: props.value,
|
|
31
|
+
},
|
|
32
|
+
})
|
|
33
|
+
)
|
|
34
|
+
)
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
type ContextConsumerProps<Value extends Record<string, unknown>> = {
|
|
40
|
+
children: MaybeArray<(value: Value) => PotokElement>
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
class ContextConsumer<Value extends Record<string, unknown>> extends LibBlock {
|
|
44
|
+
constructor(
|
|
45
|
+
readonly props: ContextConsumerProps<Value>,
|
|
46
|
+
key: symbol,
|
|
47
|
+
readonly context: LibContext
|
|
48
|
+
) {
|
|
49
|
+
super()
|
|
50
|
+
|
|
51
|
+
const value = context.contexts[key]
|
|
52
|
+
|
|
53
|
+
if (!value) {
|
|
54
|
+
throw new Error(`Контекст не найден`)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
normalizeArray(props.children).forEach((childCreator, index) => {
|
|
58
|
+
this.children.push(
|
|
59
|
+
childCreator(value as Value)(
|
|
60
|
+
mergeContext(context, {
|
|
61
|
+
parentBlock: this,
|
|
62
|
+
index,
|
|
63
|
+
})
|
|
64
|
+
)
|
|
65
|
+
)
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function createContext<Value extends Record<string, unknown>>() {
|
|
71
|
+
const key = Symbol('context')
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
provider(props: ContextProviderProps<Value>): PotokElement {
|
|
75
|
+
return function (context: LibContext) {
|
|
76
|
+
return new ContextProvider(props, key, context)
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
reader(props: ContextConsumerProps<Value>): PotokElement {
|
|
80
|
+
return function (context: LibContext) {
|
|
81
|
+
return new ContextConsumer(props, key, context)
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { text } from './text'
|
|
2
|
+
import { Child } from './types'
|
|
3
|
+
|
|
4
|
+
type DetectChildProps = {
|
|
5
|
+
readonly value: Child
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function detectChild(props: DetectChildProps): Child {
|
|
9
|
+
const value = props.value
|
|
10
|
+
const type = typeof value
|
|
11
|
+
|
|
12
|
+
if (type === 'string' || type === 'number' || type === 'boolean') {
|
|
13
|
+
return text({
|
|
14
|
+
get text() {
|
|
15
|
+
return props.value
|
|
16
|
+
},
|
|
17
|
+
})
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return value
|
|
21
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { LibBlock } from './block'
|
|
2
|
+
import type { LibContext, PotokElement, WithChildren } from './types'
|
|
3
|
+
import { mergeContext, normalizeChildren } from './utils'
|
|
4
|
+
|
|
5
|
+
export type ErrorBoundaryProps = WithChildren<{
|
|
6
|
+
onError?: (error: Error) => void
|
|
7
|
+
}>
|
|
8
|
+
|
|
9
|
+
class ErrorBoundaryClass extends LibBlock {
|
|
10
|
+
constructor(
|
|
11
|
+
readonly props: ErrorBoundaryProps,
|
|
12
|
+
readonly context: LibContext
|
|
13
|
+
) {
|
|
14
|
+
super()
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
normalizeChildren(props.children).forEach((childCreator, index) => {
|
|
18
|
+
this.children.push(
|
|
19
|
+
childCreator(
|
|
20
|
+
mergeContext(context, {
|
|
21
|
+
parentBlock: this,
|
|
22
|
+
index,
|
|
23
|
+
})
|
|
24
|
+
)
|
|
25
|
+
)
|
|
26
|
+
})
|
|
27
|
+
} catch (error) {
|
|
28
|
+
props.onError?.(this.buildError(error))
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
override unmount() {
|
|
33
|
+
try {
|
|
34
|
+
super.unmount()
|
|
35
|
+
} catch (error) {
|
|
36
|
+
this.props.onError?.(this.buildError(error))
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private buildError(error: unknown) {
|
|
41
|
+
return error instanceof Error
|
|
42
|
+
? error
|
|
43
|
+
: new Error(typeof error === 'string' ? error : 'Unknown error')
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function ErrorBoundary(props: ErrorBoundaryProps): PotokElement {
|
|
48
|
+
return function (context: LibContext) {
|
|
49
|
+
return new ErrorBoundaryClass(props, context)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { renderToDOM } from '../render-to-dom'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { registerComponent } from '../hmr/register-component'
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export { ClientOnly } from '../client-only'
|
|
2
|
+
export { ErrorBoundary } from '../error-boundary'
|
|
3
|
+
export { Lazy } from '../lazy'
|
|
4
|
+
export { LibContextReader } from '../lib-context-reader'
|
|
5
|
+
export { LibScripts } from '../lib-scripts'
|
|
6
|
+
export { Lifecycle } from '../lifecycle'
|
|
7
|
+
export { List } from '../list'
|
|
8
|
+
export { PortalIn, PortalOut } from '../portal'
|
|
9
|
+
export { createElementReference } from '../ref'
|
|
10
|
+
export { Show } from '../show'
|
|
11
|
+
export {
|
|
12
|
+
createSignal,
|
|
13
|
+
createEffect,
|
|
14
|
+
batch,
|
|
15
|
+
untrack,
|
|
16
|
+
deepTrack,
|
|
17
|
+
getSignal,
|
|
18
|
+
} from '../signals'
|
|
19
|
+
export { createStore } from '../store'
|
|
20
|
+
export type { PotokElement, WithChildren } from '../types'
|
|
21
|
+
export type * from '../jsx-types.ts'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { bootstrapApp } from '../bootstrap-app'
|
package/src/fragment.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { LibBlock } from './block'
|
|
2
|
+
import type { LibContext, PotokElement, WithChildren } from './types'
|
|
3
|
+
import { mergeContext, normalizeChildren } from './utils'
|
|
4
|
+
|
|
5
|
+
type FragmentProps = WithChildren<{}>
|
|
6
|
+
|
|
7
|
+
class FragmentClass extends LibBlock {
|
|
8
|
+
constructor(readonly props: FragmentProps, readonly context: LibContext) {
|
|
9
|
+
super()
|
|
10
|
+
|
|
11
|
+
normalizeChildren(props.children).forEach((childCreator, index) => {
|
|
12
|
+
this.children.push(
|
|
13
|
+
childCreator(
|
|
14
|
+
mergeContext(context, {
|
|
15
|
+
parentBlock: this,
|
|
16
|
+
index,
|
|
17
|
+
})
|
|
18
|
+
)
|
|
19
|
+
)
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function fragment(props: FragmentProps): PotokElement {
|
|
25
|
+
return function (context: LibContext) {
|
|
26
|
+
return new FragmentClass(props, context)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CachedInstanceState } from './registered-component'
|
|
2
|
+
import { HMRRegistry } from './registry'
|
|
3
|
+
|
|
4
|
+
export const HMR_DEV = {
|
|
5
|
+
registry: new HMRRegistry(),
|
|
6
|
+
currentInstance: null as {
|
|
7
|
+
states: CachedInstanceState[]
|
|
8
|
+
stateIndex: number
|
|
9
|
+
} | null,
|
|
10
|
+
}
|