acrylblends 0.6.2 → 0.6.4
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/README.md +5 -1
- package/docs/framework/README.md +3 -2
- package/docs/framework/UPSTREAM.md +1 -1
- package/docs/framework/cordis/acryl-in-a-cordis-app.md +6 -0
- package/docs/framework/getting-started/basic.md +1 -0
- package/docs/framework/getting-started/desktop.md +41 -0
- package/docs/framework/guides/jsx-dom.md +0 -3
- package/docs/framework/guides/jsx.md +24 -3
- package/docs/framework/helpers/css.md +0 -3
- package/docs/framework/helpers/ssg.md +3 -6
- package/docs/framework/middleware/builtin/jsx-renderer.md +0 -3
- package/docs/framework/upstream.json +3 -3
- package/lib/accepts.d.ts +1 -1
- package/lib/acryl-base.d.ts +1 -1
- package/lib/adapter.d.ts +1 -1
- package/lib/{app-BdrVHBlJ.d.ts → app-D8riatvv.d.ts} +1 -1
- package/lib/base-BpQy2Rk7.d.ts +783 -0
- package/lib/base-ddiVmiE7.js +721 -0
- package/lib/basic-auth.d.ts +1 -1
- package/lib/bearer-auth.d.ts +1 -1
- package/lib/body-limit.d.ts +1 -1
- package/lib/cache.d.ts +1 -1
- package/lib/cache.js +4 -4
- package/lib/{client-BHTr318g.js → client-DDLXwhBo.js} +2 -125
- package/lib/client.d.ts +2 -2
- package/lib/client.js +2 -1
- package/lib/combine.d.ts +1 -1
- package/lib/common-D8Z4JRCw.d.ts +46 -0
- package/lib/components-0o0CBYNv.js +268 -0
- package/lib/components-DdI7-ns7.js +24 -0
- package/lib/compress.d.ts +1 -1
- package/lib/conninfo.d.ts +2 -2
- package/lib/constants-BR9jM9BC.js +9 -0
- package/lib/{context-B5Y1lLha.d.ts → context-DS3fYyG-.d.ts} +2 -2
- package/lib/context-DxFdY_un.d.ts +250 -0
- package/lib/context-storage.d.ts +1 -1
- package/lib/{cookie-D9_nQbsM.d.ts → cookie-CCelEqky.d.ts} +1 -1
- package/lib/cookie.d.ts +3 -3
- package/lib/cors.d.ts +1 -1
- package/lib/csrf.d.ts +1 -1
- package/lib/css-D2jb7X8b.js +320 -0
- package/lib/css.d.ts +82 -0
- package/lib/css.js +134 -0
- package/lib/dev.d.ts +2 -2
- package/lib/etag.d.ts +1 -1
- package/lib/factory.d.ts +2 -2
- package/lib/hooks-BMw6BAyP.js +762 -0
- package/lib/html-SllAe0YT.d.ts +46 -0
- package/lib/html.d.ts +1 -1
- package/lib/{index-m12zcmph.d.ts → index-Bb7YJKCq.d.ts} +3 -3
- package/lib/{index-Kqou8Fjh.d.ts → index-BvFh1Gfx.d.ts} +2 -2
- package/lib/index-C850MeBA.d.ts +94 -0
- package/lib/{index-DtEoak1i.d.ts → index-CTy4N7ng.d.ts} +2 -2
- package/lib/index.d.ts +4 -4
- package/lib/ip-restriction.d.ts +2 -2
- package/lib/jsx/dom/client.d.ts +30 -0
- package/lib/jsx/dom/client.js +49 -0
- package/lib/jsx/dom/css.d.ts +84 -0
- package/lib/jsx/dom/css.js +2 -0
- package/lib/jsx/dom/jsx-dev-runtime.d.ts +3 -0
- package/lib/jsx/dom/jsx-dev-runtime.js +2 -0
- package/lib/jsx/dom/jsx-runtime.d.ts +3 -0
- package/lib/jsx/dom/jsx-runtime.js +2 -0
- package/lib/jsx/dom/server.d.ts +105 -0
- package/lib/jsx/dom/server.js +37 -0
- package/lib/jsx/dom.d.ts +5 -0
- package/lib/jsx/dom.js +74 -0
- package/lib/jsx/jsx-dev-runtime.d.ts +6 -0
- package/lib/jsx/jsx-dev-runtime.js +14 -0
- package/lib/jsx/jsx-runtime.d.ts +10 -0
- package/lib/jsx/jsx-runtime.js +30 -0
- package/lib/jsx/streaming.d.ts +2 -0
- package/lib/jsx/streaming.js +2 -0
- package/lib/jsx-dev-runtime-B22O-Npk.d.ts +7 -0
- package/lib/jsx-dev-runtime-D18Y35TI.js +354 -0
- package/lib/jsx-renderer.d.ts +75 -0
- package/lib/jsx-renderer.js +99 -0
- package/lib/jsx-runtime-BVVgDSdq.d.ts +1 -0
- package/lib/jsx.d.ts +3 -0
- package/lib/jsx.js +47 -0
- package/lib/jwk.d.ts +4 -4
- package/lib/{jwt-BA65QhnJ.d.ts → jwt-BARhotDz.d.ts} +1 -1
- package/lib/jwt.d.ts +4 -4
- package/lib/language.d.ts +1 -1
- package/lib/logger.d.ts +1 -1
- package/lib/loopback-only.d.ts +1 -1
- package/lib/method-not-allowed.d.ts +2 -2
- package/lib/method-override.d.ts +2 -2
- package/lib/mount.d.ts +1 -1
- package/lib/node-server/conninfo.d.ts +1 -1
- package/lib/node-server/serve-static.d.ts +1 -1
- package/lib/node-server/serve-static.js +1 -1
- package/lib/node-server.d.ts +1 -1
- package/lib/node-server.js +1 -1
- package/lib/powered-by.d.ts +1 -1
- package/lib/pretty-json.d.ts +1 -1
- package/lib/proxy.d.ts +1 -1
- package/lib/quick.d.ts +1 -1
- package/lib/request-id.d.ts +1 -1
- package/lib/request.d.ts +1 -1
- package/lib/route.d.ts +1 -1
- package/lib/schema-validator.d.ts +1 -1
- package/lib/secure-headers.d.ts +1 -1
- package/lib/{serve-static-Dw_m6KxR.js → serve-static-B14MF1Va.js} +2 -0
- package/lib/serve-static.d.ts +1 -1
- package/lib/ssg-BwjcA-Ge.js +389 -0
- package/lib/ssg.d.ts +156 -0
- package/lib/ssg.js +2 -0
- package/lib/streaming.d.ts +1 -1
- package/lib/testing.d.ts +4 -4
- package/lib/testing.js +1 -1
- package/lib/timeout.d.ts +1 -1
- package/lib/timing.d.ts +1 -1
- package/lib/tiny.d.ts +1 -1
- package/lib/trailing-slash.d.ts +1 -1
- package/lib/{types-ZM9gIiKh.d.ts → types-Dv_nV2cv.d.ts} +1 -1
- package/lib/{types-D9DEXMjE.d.ts → types-Lqx5BxQF.d.ts} +8 -1
- package/lib/{types-Bd29gh2o.d.ts → types-zNxyEpG2.d.ts} +3 -3
- package/lib/types.d.ts +1 -1
- package/lib/utils/body.d.ts +1 -1
- package/lib/utils/cookie.d.ts +1 -1
- package/lib/utils/crypto.d.ts +1 -1
- package/lib/utils/html.d.ts +1 -45
- package/lib/utils/ipaddr.d.ts +1 -1
- package/lib/utils/jwt.d.ts +1 -1
- package/lib/utils/types.d.ts +2 -2
- package/lib/utils-Cx61GFMC.js +125 -0
- package/lib/validator.d.ts +2 -2
- package/lib/ws.d.ts +1 -1
- package/package.json +53 -1
- package/plugins/acryl-inspect/upstream.json +1 -1
- package/plugins/acryl-node-server/upstream.json +1 -1
- package/plugins/acryl-router/src/core/helper/css/common.ts +337 -0
- package/plugins/acryl-router/src/core/helper/css/index.ts +262 -0
- package/plugins/acryl-router/src/core/helper/ssg/index.ts +14 -0
- package/plugins/acryl-router/src/core/helper/ssg/middleware.ts +83 -0
- package/plugins/acryl-router/src/core/helper/ssg/plugins.ts +72 -0
- package/plugins/acryl-router/src/core/helper/ssg/ssg.ts +471 -0
- package/plugins/acryl-router/src/core/helper/ssg/utils.ts +118 -0
- package/plugins/acryl-router/src/core/jsx/base.ts +490 -0
- package/plugins/acryl-router/src/core/jsx/children.ts +20 -0
- package/plugins/acryl-router/src/core/jsx/components.ts +257 -0
- package/plugins/acryl-router/src/core/jsx/constants.ts +6 -0
- package/plugins/acryl-router/src/core/jsx/context.ts +266 -0
- package/plugins/acryl-router/src/core/jsx/dom/client.ts +89 -0
- package/plugins/acryl-router/src/core/jsx/dom/components.ts +39 -0
- package/plugins/acryl-router/src/core/jsx/dom/context.ts +52 -0
- package/plugins/acryl-router/src/core/jsx/dom/css.ts +263 -0
- package/plugins/acryl-router/src/core/jsx/dom/hooks/index.ts +91 -0
- package/plugins/acryl-router/src/core/jsx/dom/index.ts +170 -0
- package/plugins/acryl-router/src/core/jsx/dom/intrinsic-element/components.ts +438 -0
- package/plugins/acryl-router/src/core/jsx/dom/jsx-dev-runtime.ts +23 -0
- package/plugins/acryl-router/src/core/jsx/dom/jsx-runtime.ts +8 -0
- package/plugins/acryl-router/src/core/jsx/dom/render.ts +879 -0
- package/plugins/acryl-router/src/core/jsx/dom/server.ts +76 -0
- package/plugins/acryl-router/src/core/jsx/dom/utils.ts +7 -0
- package/plugins/acryl-router/src/core/jsx/hooks/index.ts +437 -0
- package/plugins/acryl-router/src/core/jsx/index.ts +115 -0
- package/plugins/acryl-router/src/core/jsx/intrinsic-element/common.ts +23 -0
- package/plugins/acryl-router/src/core/jsx/intrinsic-element/components.ts +210 -0
- package/plugins/acryl-router/src/core/jsx/intrinsic-elements.ts +938 -0
- package/plugins/acryl-router/src/core/jsx/jsx-dev-runtime.ts +26 -0
- package/plugins/acryl-router/src/core/jsx/jsx-runtime.ts +51 -0
- package/plugins/acryl-router/src/core/jsx/streaming.ts +231 -0
- package/plugins/acryl-router/src/core/jsx/types.ts +41 -0
- package/plugins/acryl-router/src/core/jsx/utils.ts +202 -0
- package/plugins/acryl-router/src/core/middleware/cache/index.ts +4 -4
- package/plugins/acryl-router/src/core/middleware/jsx-renderer/index.ts +162 -0
- package/plugins/acryl-router/src/core/utils/types.ts +6 -0
- package/plugins/acryl-router/src/helpers/index.ts +2 -0
- package/plugins/acryl-router/src/middleware/index.ts +1 -0
- package/plugins/acryl-router/upstream.json +3 -3
- package/plugins/acryl-router-http/upstream.json +1 -1
- package/plugins/acryl-state/upstream.json +1 -1
- package/plugins/desktop/upstream.json +1 -1
- package/plugins/desktop-web/upstream.json +1 -1
- package/plugins/extensions/resolve.ts +4 -0
- package/plugins/save/plugin.json +1 -1
- package/shared/AGENTS.core.md +4 -0
- package/templates/agent/tsconfig.json +7 -1
- package/templates/todo/upstream.json +1 -1
- package/plugins/acryl-inspect/tests/report.spec.ts +0 -69
- package/plugins/acryl-inspect/tests/service.spec.ts +0 -121
- package/plugins/acryl-node-server/tests/adapter/app.ts +0 -76
- package/plugins/acryl-node-server/tests/adapter/assets/.static/plain.txt +0 -1
- package/plugins/acryl-node-server/tests/adapter/assets/favicon.ico +0 -0
- package/plugins/acryl-node-server/tests/adapter/assets/secret.txt +0 -1
- package/plugins/acryl-node-server/tests/adapter/assets/static/acryl.html +0 -1
- package/plugins/acryl-node-server/tests/adapter/assets/static/admin/secret.txt +0 -1
- package/plugins/acryl-node-server/tests/adapter/assets/static/data.json +0 -5
- package/plugins/acryl-node-server/tests/adapter/assets/static/extensionless +0 -1
- package/plugins/acryl-node-server/tests/adapter/assets/static/foo..bar.txt +0 -0
- package/plugins/acryl-node-server/tests/adapter/assets/static/index.html +0 -1
- package/plugins/acryl-node-server/tests/adapter/assets/static/plain.txt +0 -1
- package/plugins/acryl-node-server/tests/adapter/assets/static-with-context-path/plain.txt +0 -1
- package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.bin +0 -1
- package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.bin.br +0 -1
- package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt +0 -1
- package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt.br +0 -1
- package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt.zst +0 -1
- package/plugins/acryl-node-server/tests/adapter/conninfo.test.ts +0 -34
- package/plugins/acryl-node-server/tests/adapter/content-length.test.ts +0 -248
- package/plugins/acryl-node-server/tests/adapter/early-hints.test.ts +0 -457
- package/plugins/acryl-node-server/tests/adapter/fixtures/keys/agent1-cert.pem +0 -23
- package/plugins/acryl-node-server/tests/adapter/fixtures/keys/agent1-key.pem +0 -27
- package/plugins/acryl-node-server/tests/adapter/headers.test.ts +0 -252
- package/plugins/acryl-node-server/tests/adapter/helpers/request.ts +0 -190
- package/plugins/acryl-node-server/tests/adapter/listener.test.ts +0 -727
- package/plugins/acryl-node-server/tests/adapter/request-client-disconnect.test.ts +0 -189
- package/plugins/acryl-node-server/tests/adapter/request.test.ts +0 -1230
- package/plugins/acryl-node-server/tests/adapter/response.test.ts +0 -285
- package/plugins/acryl-node-server/tests/adapter/serve-static.test.ts +0 -849
- package/plugins/acryl-node-server/tests/adapter/server-socket.test.ts +0 -790
- package/plugins/acryl-node-server/tests/adapter/server.test.ts +0 -1312
- package/plugins/acryl-node-server/tests/adapter/setup.ts +0 -16
- package/plugins/acryl-node-server/tests/adapter/url.test.ts +0 -76
- package/plugins/acryl-node-server/tests/adapter/utils/response.test.ts +0 -23
- package/plugins/acryl-node-server/tests/adapter/utils/stream.test.ts +0 -75
- package/plugins/acryl-node-server/tests/adapter/utils.test.ts +0 -235
- package/plugins/acryl-node-server/tests/adapter/websocket.test.ts +0 -260
- package/plugins/acryl-node-server/tests/server.spec.ts +0 -141
- package/plugins/acryl-router/src/core/app.test.ts +0 -3833
- package/plugins/acryl-router/src/core/client/client.test.ts +0 -2313
- package/plugins/acryl-router/src/core/client/types.test.ts +0 -149
- package/plugins/acryl-router/src/core/client/utils.test.ts +0 -405
- package/plugins/acryl-router/src/core/compose.test.ts +0 -751
- package/plugins/acryl-router/src/core/context.test.ts +0 -629
- package/plugins/acryl-router/src/core/helper/accepts/accepts.test.ts +0 -344
- package/plugins/acryl-router/src/core/helper/adapter/index.test.ts +0 -55
- package/plugins/acryl-router/src/core/helper/cookie/index.test.ts +0 -510
- package/plugins/acryl-router/src/core/helper/dev/index.test.ts +0 -181
- package/plugins/acryl-router/src/core/helper/factory/index.test.ts +0 -434
- package/plugins/acryl-router/src/core/helper/html/index.test.ts +0 -78
- package/plugins/acryl-router/src/core/helper/proxy/index.test.ts +0 -356
- package/plugins/acryl-router/src/core/helper/route/index.test.ts +0 -259
- package/plugins/acryl-router/src/core/helper/streaming/stream.test.ts +0 -128
- package/plugins/acryl-router/src/core/helper/streaming/text.test.ts +0 -34
- package/plugins/acryl-router/src/core/helper/testing/index.test.ts +0 -42
- package/plugins/acryl-router/src/core/helper/websocket/index.test.ts +0 -124
- package/plugins/acryl-router/src/core/http-exception.test.ts +0 -45
- package/plugins/acryl-router/src/core/middleware/basic-auth/index.test.ts +0 -434
- package/plugins/acryl-router/src/core/middleware/bearer-auth/index.test.ts +0 -1018
- package/plugins/acryl-router/src/core/middleware/body-limit/index.test.ts +0 -273
- package/plugins/acryl-router/src/core/middleware/cache/index.test.ts +0 -1211
- package/plugins/acryl-router/src/core/middleware/combine/index.test.ts +0 -355
- package/plugins/acryl-router/src/core/middleware/compress/index.test.ts +0 -535
- package/plugins/acryl-router/src/core/middleware/context-storage/index.test.ts +0 -43
- package/plugins/acryl-router/src/core/middleware/cors/index.test.ts +0 -532
- package/plugins/acryl-router/src/core/middleware/csrf/index.test.ts +0 -534
- package/plugins/acryl-router/src/core/middleware/etag/digest.test.ts +0 -21
- package/plugins/acryl-router/src/core/middleware/etag/index.test.ts +0 -503
- package/plugins/acryl-router/src/core/middleware/ip-restriction/index.test.ts +0 -217
- package/plugins/acryl-router/src/core/middleware/jwk/index.test.ts +0 -1135
- package/plugins/acryl-router/src/core/middleware/jwk/keys.test.json +0 -48
- package/plugins/acryl-router/src/core/middleware/jwt/index.test.ts +0 -802
- package/plugins/acryl-router/src/core/middleware/language/index.test.ts +0 -552
- package/plugins/acryl-router/src/core/middleware/logger/index.test.ts +0 -204
- package/plugins/acryl-router/src/core/middleware/method-not-allowed/index.test.ts +0 -292
- package/plugins/acryl-router/src/core/middleware/method-override/index.test.ts +0 -221
- package/plugins/acryl-router/src/core/middleware/mount/index.test.ts +0 -334
- package/plugins/acryl-router/src/core/middleware/powered-by/index.test.ts +0 -37
- package/plugins/acryl-router/src/core/middleware/pretty-json/index.test.ts +0 -218
- package/plugins/acryl-router/src/core/middleware/request-id/index.test.ts +0 -168
- package/plugins/acryl-router/src/core/middleware/secure-headers/index.test.ts +0 -671
- package/plugins/acryl-router/src/core/middleware/serve-static/index.test.ts +0 -450
- package/plugins/acryl-router/src/core/middleware/serve-static/path.test.ts +0 -50
- package/plugins/acryl-router/src/core/middleware/timeout/index.test.ts +0 -70
- package/plugins/acryl-router/src/core/middleware/timing/index.test.ts +0 -310
- package/plugins/acryl-router/src/core/middleware/trailing-slash/index.test.ts +0 -381
- package/plugins/acryl-router/src/core/preset/quick.test.ts +0 -42
- package/plugins/acryl-router/src/core/preset/tiny.test.ts +0 -42
- package/plugins/acryl-router/src/core/request.test.ts +0 -751
- package/plugins/acryl-router/src/core/router/common.case.test.ts +0 -1132
- package/plugins/acryl-router/src/core/router/linear-router/router.test.ts +0 -80
- package/plugins/acryl-router/src/core/router/pattern-router/router.test.ts +0 -46
- package/plugins/acryl-router/src/core/router/reg-exp-router/prepared-router.test.ts +0 -154
- package/plugins/acryl-router/src/core/router/reg-exp-router/router.test.ts +0 -265
- package/plugins/acryl-router/src/core/router/smart-router/router.test.ts +0 -13
- package/plugins/acryl-router/src/core/router/trie-router/node.test.ts +0 -896
- package/plugins/acryl-router/src/core/router/trie-router/router.test.ts +0 -8
- package/plugins/acryl-router/src/core/types.test.ts +0 -4134
- package/plugins/acryl-router/src/core/utils/accept.test.ts +0 -299
- package/plugins/acryl-router/src/core/utils/basic-auth.test.ts +0 -56
- package/plugins/acryl-router/src/core/utils/body.test.ts +0 -496
- package/plugins/acryl-router/src/core/utils/buffer.test.ts +0 -147
- package/plugins/acryl-router/src/core/utils/color.test.ts +0 -23
- package/plugins/acryl-router/src/core/utils/concurrent.test.ts +0 -69
- package/plugins/acryl-router/src/core/utils/cookie.test.ts +0 -460
- package/plugins/acryl-router/src/core/utils/crypto.test.ts +0 -43
- package/plugins/acryl-router/src/core/utils/encode.test.ts +0 -61
- package/plugins/acryl-router/src/core/utils/filepath.test.ts +0 -78
- package/plugins/acryl-router/src/core/utils/html.test.ts +0 -16
- package/plugins/acryl-router/src/core/utils/ipaddr.test.ts +0 -149
- package/plugins/acryl-router/src/core/utils/jwt/jwa.test.ts +0 -86
- package/plugins/acryl-router/src/core/utils/jwt/jwt.test.ts +0 -1788
- package/plugins/acryl-router/src/core/utils/mime.test.ts +0 -64
- package/plugins/acryl-router/src/core/utils/stream.test.ts +0 -212
- package/plugins/acryl-router/src/core/utils/types.test.ts +0 -295
- package/plugins/acryl-router/src/core/utils/url.test.ts +0 -384
- package/plugins/acryl-router/src/core/validator/utils.test.ts +0 -82
- package/plugins/acryl-router/src/core/validator/validator.test.ts +0 -1488
- package/plugins/acryl-router/tests/docs-examples.spec.ts +0 -152
- package/plugins/acryl-router/tests/live-install.spec.ts +0 -64
- package/plugins/acryl-router/tests/loader.spec.ts +0 -72
- package/plugins/acryl-router/tests/loopback-only.spec.ts +0 -80
- package/plugins/acryl-router/tests/no-dom/consumer.ts +0 -11
- package/plugins/acryl-router/tests/no-dom/tsconfig.json +0 -13
- package/plugins/acryl-router/tests/service.spec.ts +0 -426
- package/plugins/acryl-router/tests/shadow-state.spec.ts +0 -79
- package/plugins/acryl-router-http/tests/adapter.spec.ts +0 -174
- package/plugins/acryl-router-http/tests/stream.spec.ts +0 -133
- package/plugins/acryl-router-http/tests/surfaces.spec.ts +0 -101
- package/plugins/acryl-state/src/react.ts +0 -11
- package/plugins/acryl-state/tests/cell.spec.ts +0 -71
- package/plugins/acryl-state/tests/react.spec.ts +0 -39
- package/plugins/acryl-state/tests/service.spec.ts +0 -132
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
import { raw } from '../helper/html/index.ts'
|
|
2
|
+
import { escapeToBuffer, resolveCallbackSync, stringBufferToString } from '../utils/html.ts'
|
|
3
|
+
import type { HtmlEscaped, HtmlEscapedString, StringBufferWithCallbacks } from '../utils/html.ts'
|
|
4
|
+
import { DOM_RENDERER, DOM_MEMO } from './constants.ts'
|
|
5
|
+
import {
|
|
6
|
+
captureRenderContext,
|
|
7
|
+
createContext,
|
|
8
|
+
globalContexts,
|
|
9
|
+
runWithRenderContext,
|
|
10
|
+
useContext,
|
|
11
|
+
} from './context.ts'
|
|
12
|
+
import type { Context } from './context.ts'
|
|
13
|
+
import { domRenderers } from './intrinsic-element/common.ts'
|
|
14
|
+
import * as intrinsicElementTags from './intrinsic-element/components.ts'
|
|
15
|
+
import type { JSX as AcrylJSX } from './intrinsic-elements.ts'
|
|
16
|
+
import {
|
|
17
|
+
isValidAttributeName,
|
|
18
|
+
isValidTagName,
|
|
19
|
+
normalizeIntrinsicElementKey,
|
|
20
|
+
styleObjectForEach,
|
|
21
|
+
} from './utils.ts'
|
|
22
|
+
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
24
|
+
export type Props = Record<string, any>
|
|
25
|
+
type FunctionComponentResult =
|
|
26
|
+
| HtmlEscapedString
|
|
27
|
+
| JSXNode
|
|
28
|
+
| Child[]
|
|
29
|
+
| Promise<HtmlEscapedString | JSXNode | Child[]>
|
|
30
|
+
| null
|
|
31
|
+
export type FC<P = Props> = {
|
|
32
|
+
(props: P): FunctionComponentResult
|
|
33
|
+
defaultProps?: Partial<P> | undefined
|
|
34
|
+
displayName?: string | undefined
|
|
35
|
+
}
|
|
36
|
+
export type DOMAttributes = AcrylJSX.HTMLAttributes
|
|
37
|
+
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
39
|
+
export namespace JSX {
|
|
40
|
+
export type Element = HtmlEscapedString | Promise<HtmlEscapedString>
|
|
41
|
+
export type ElementType = string | ((props: never) => FunctionComponentResult)
|
|
42
|
+
export interface ElementChildrenAttribute {
|
|
43
|
+
children: Child
|
|
44
|
+
}
|
|
45
|
+
// `AcrylJSX.IntrinsicElements`, not the top-level alias: the bundled dts emit renames the namespace
|
|
46
|
+
// import correctly but drops an import alias that collides with this member name (TS2310).
|
|
47
|
+
export interface IntrinsicElements extends AcrylJSX.IntrinsicElements {
|
|
48
|
+
[tagName: string]: Props
|
|
49
|
+
}
|
|
50
|
+
export interface IntrinsicAttributes {
|
|
51
|
+
key?: string | number | bigint | null | undefined
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let nameSpaceContext: Context<string> | undefined = undefined
|
|
56
|
+
export const getNameSpaceContext = () => nameSpaceContext
|
|
57
|
+
|
|
58
|
+
const toSVGAttributeName = (key: string): string =>
|
|
59
|
+
/[A-Z]/.test(key) &&
|
|
60
|
+
// Presentation attributes are findable in style object. "clip-path", "font-size", "stroke-width", etc.
|
|
61
|
+
// Or other un-deprecated kebab-case attributes. "overline-position", "paint-order", "strikethrough-position", etc.
|
|
62
|
+
key.match(
|
|
63
|
+
/^(?:al|basel|clip(?:Path|Rule)$|co|do|fill|fl|fo|gl|let|lig|i|marker[EMS]|o|pai|pointe|sh|st[or]|text[^L]|tr|u|ve|w)/
|
|
64
|
+
)
|
|
65
|
+
? key.replace(/([A-Z])/g, '-$1').toLowerCase()
|
|
66
|
+
: key
|
|
67
|
+
|
|
68
|
+
const emptyTags = [
|
|
69
|
+
'area',
|
|
70
|
+
'base',
|
|
71
|
+
'br',
|
|
72
|
+
'col',
|
|
73
|
+
'embed',
|
|
74
|
+
'hr',
|
|
75
|
+
'img',
|
|
76
|
+
'input',
|
|
77
|
+
'keygen',
|
|
78
|
+
'link',
|
|
79
|
+
'meta',
|
|
80
|
+
'param',
|
|
81
|
+
'source',
|
|
82
|
+
'track',
|
|
83
|
+
'wbr',
|
|
84
|
+
]
|
|
85
|
+
export const booleanAttributes = [
|
|
86
|
+
'allowfullscreen',
|
|
87
|
+
'async',
|
|
88
|
+
'autofocus',
|
|
89
|
+
'autoplay',
|
|
90
|
+
'checked',
|
|
91
|
+
'controls',
|
|
92
|
+
'default',
|
|
93
|
+
'defer',
|
|
94
|
+
'disabled',
|
|
95
|
+
'download',
|
|
96
|
+
'formnovalidate',
|
|
97
|
+
'hidden',
|
|
98
|
+
'inert',
|
|
99
|
+
'ismap',
|
|
100
|
+
'itemscope',
|
|
101
|
+
'loop',
|
|
102
|
+
'multiple',
|
|
103
|
+
'muted',
|
|
104
|
+
'nomodule',
|
|
105
|
+
'novalidate',
|
|
106
|
+
'open',
|
|
107
|
+
'playsinline',
|
|
108
|
+
'readonly',
|
|
109
|
+
'required',
|
|
110
|
+
'reversed',
|
|
111
|
+
'selected',
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
type SuspendedContext = <T>(callback: () => T) => T
|
|
115
|
+
|
|
116
|
+
const resolveFunctionComponentResult = (
|
|
117
|
+
result: Promise<string | JSXNode | Child[]>,
|
|
118
|
+
suspendedContext?: SuspendedContext
|
|
119
|
+
): Promise<string> =>
|
|
120
|
+
result.then((resolved) => {
|
|
121
|
+
if (
|
|
122
|
+
typeof resolved !== 'string' &&
|
|
123
|
+
!Array.isArray(resolved) &&
|
|
124
|
+
!(resolved instanceof JSXNode)
|
|
125
|
+
) {
|
|
126
|
+
return resolved
|
|
127
|
+
}
|
|
128
|
+
const children = Array.isArray(resolved) ? resolved : [resolved as Child]
|
|
129
|
+
const render = () => {
|
|
130
|
+
const buffer: StringBufferWithCallbacks = [''] as StringBufferWithCallbacks
|
|
131
|
+
childrenToStringToBuffer(children, buffer)
|
|
132
|
+
return buffer.length === 1
|
|
133
|
+
? raw(buffer[0], buffer.callbacks)
|
|
134
|
+
: stringBufferToString(buffer, buffer.callbacks)
|
|
135
|
+
}
|
|
136
|
+
return suspendedContext ? suspendedContext(render) : runWithRenderContext(render)
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
const childrenToStringToBuffer = (children: Child[], buffer: StringBufferWithCallbacks): void => {
|
|
140
|
+
for (let i = 0, len = children.length; i < len; i++) {
|
|
141
|
+
const child = children[i]
|
|
142
|
+
if (typeof child === 'string') {
|
|
143
|
+
escapeToBuffer(child, buffer)
|
|
144
|
+
} else if (typeof child === 'boolean' || child === null || child === undefined) {
|
|
145
|
+
continue
|
|
146
|
+
} else if (child instanceof JSXNode) {
|
|
147
|
+
child.toStringToBuffer(buffer)
|
|
148
|
+
} else if (typeof child === 'number') {
|
|
149
|
+
;(buffer[0] as string) += child
|
|
150
|
+
} else if ((child as unknown as HtmlEscaped).isEscaped) {
|
|
151
|
+
;(buffer[0] as string) += child
|
|
152
|
+
const callbacks = (child as unknown as HtmlEscapedString).callbacks
|
|
153
|
+
if (callbacks) {
|
|
154
|
+
buffer.callbacks ||= []
|
|
155
|
+
buffer.callbacks.push(...callbacks)
|
|
156
|
+
}
|
|
157
|
+
} else if (child instanceof Promise) {
|
|
158
|
+
buffer.unshift('', child)
|
|
159
|
+
} else {
|
|
160
|
+
// `child` type is `Child[]`, so stringify recursively
|
|
161
|
+
childrenToStringToBuffer(child, buffer)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export type Child =
|
|
167
|
+
| string
|
|
168
|
+
| Promise<string>
|
|
169
|
+
| number
|
|
170
|
+
| JSXNode
|
|
171
|
+
| null
|
|
172
|
+
| undefined
|
|
173
|
+
| boolean
|
|
174
|
+
| Child[]
|
|
175
|
+
|
|
176
|
+
export const renderChildren = (children: Child[]): HtmlEscapedString | Promise<HtmlEscapedString> =>
|
|
177
|
+
runWithRenderContext(() => {
|
|
178
|
+
const buffer: StringBufferWithCallbacks = [''] as StringBufferWithCallbacks
|
|
179
|
+
childrenToStringToBuffer(children, buffer)
|
|
180
|
+
return buffer.length === 1
|
|
181
|
+
? raw(buffer[0], buffer.callbacks)
|
|
182
|
+
: stringBufferToString(buffer, buffer.callbacks)
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
export const isUntrustedObject = (value: unknown): boolean =>
|
|
186
|
+
typeof value === 'object' &&
|
|
187
|
+
value !== null &&
|
|
188
|
+
!Array.isArray(value) &&
|
|
189
|
+
!(value instanceof JSXNode) &&
|
|
190
|
+
!(value instanceof Promise) &&
|
|
191
|
+
!(value as HtmlEscaped).isEscaped &&
|
|
192
|
+
typeof (value as { toString?: unknown }).toString === 'function'
|
|
193
|
+
|
|
194
|
+
export const renderUntrustedObject = (
|
|
195
|
+
value: unknown
|
|
196
|
+
): HtmlEscapedString | Promise<HtmlEscapedString> => {
|
|
197
|
+
const stringified = (value as { toString(): unknown }).toString()
|
|
198
|
+
const escape = (result: unknown) => renderChildren([String(result)])
|
|
199
|
+
return stringified instanceof Promise ? stringified.then(escape) : escape(stringified)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export class JSXNode implements HtmlEscaped {
|
|
203
|
+
tag: string | Function
|
|
204
|
+
props: Props
|
|
205
|
+
key?: string
|
|
206
|
+
children: Child[]
|
|
207
|
+
isEscaped: true = true as const
|
|
208
|
+
constructor(tag: string | Function, props: Props, children: Child[]) {
|
|
209
|
+
if (typeof tag !== 'function' && !isValidTagName(tag)) {
|
|
210
|
+
throw new Error(`Invalid JSX tag name: ${tag}`)
|
|
211
|
+
}
|
|
212
|
+
this.tag = tag
|
|
213
|
+
this.props = props
|
|
214
|
+
this.children = children
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
get type(): string | Function {
|
|
218
|
+
return this.tag as string
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Added for compatibility with libraries that rely on React's internal structure
|
|
222
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
223
|
+
get ref(): any {
|
|
224
|
+
return this.props.ref || null
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
toString(): string | Promise<string> {
|
|
228
|
+
const render = () => {
|
|
229
|
+
const buffer: StringBufferWithCallbacks = [''] as StringBufferWithCallbacks
|
|
230
|
+
this.toStringToBuffer(buffer)
|
|
231
|
+
return buffer.length === 1
|
|
232
|
+
? 'callbacks' in buffer
|
|
233
|
+
? resolveCallbackSync(raw(buffer[0], buffer.callbacks)).toString()
|
|
234
|
+
: buffer[0]
|
|
235
|
+
: stringBufferToString(buffer, buffer.callbacks)
|
|
236
|
+
}
|
|
237
|
+
return runWithRenderContext(render)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
toStringToBuffer(buffer: StringBufferWithCallbacks): void {
|
|
241
|
+
const tag = this.tag as string
|
|
242
|
+
const props = this.props
|
|
243
|
+
let { children } = this
|
|
244
|
+
|
|
245
|
+
buffer[0] += `<${tag}`
|
|
246
|
+
|
|
247
|
+
const normalizeKey: (key: string) => string =
|
|
248
|
+
tag === 'svg' || (nameSpaceContext && useContext(nameSpaceContext) === 'svg')
|
|
249
|
+
? (key) => toSVGAttributeName(normalizeIntrinsicElementKey(key))
|
|
250
|
+
: (key) => normalizeIntrinsicElementKey(key)
|
|
251
|
+
for (let [key, v] of Object.entries(props)) {
|
|
252
|
+
key = normalizeKey(key)
|
|
253
|
+
if (!isValidAttributeName(key)) {
|
|
254
|
+
continue
|
|
255
|
+
}
|
|
256
|
+
if (key === 'children') {
|
|
257
|
+
// skip children
|
|
258
|
+
} else if (key === 'style' && typeof v === 'object') {
|
|
259
|
+
// object to style strings
|
|
260
|
+
let styleStr = ''
|
|
261
|
+
styleObjectForEach(v, (property, value) => {
|
|
262
|
+
if (value != null) {
|
|
263
|
+
styleStr += `${styleStr ? ';' : ''}${property}:${value}`
|
|
264
|
+
}
|
|
265
|
+
})
|
|
266
|
+
buffer[0] += ' style="'
|
|
267
|
+
escapeToBuffer(styleStr, buffer)
|
|
268
|
+
buffer[0] += '"'
|
|
269
|
+
} else if (typeof v === 'string') {
|
|
270
|
+
buffer[0] += ` ${key}="`
|
|
271
|
+
escapeToBuffer(v, buffer)
|
|
272
|
+
buffer[0] += '"'
|
|
273
|
+
} else if (v === null || v === undefined) {
|
|
274
|
+
// Do nothing
|
|
275
|
+
} else if (typeof v === 'number' || (v as HtmlEscaped).isEscaped) {
|
|
276
|
+
buffer[0] += ` ${key}="${v}"`
|
|
277
|
+
} else if (typeof v === 'boolean' && booleanAttributes.includes(key)) {
|
|
278
|
+
if (v) {
|
|
279
|
+
buffer[0] += ` ${key}=""`
|
|
280
|
+
}
|
|
281
|
+
} else if (key === 'dangerouslySetInnerHTML') {
|
|
282
|
+
if (children.length > 0) {
|
|
283
|
+
throw new Error('Can only set one of `children` or `props.dangerouslySetInnerHTML`.')
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
children = [raw(v.__html)]
|
|
287
|
+
} else if (v instanceof Promise) {
|
|
288
|
+
buffer[0] += ` ${key}="`
|
|
289
|
+
buffer.unshift('"', v)
|
|
290
|
+
} else if (typeof v === 'function') {
|
|
291
|
+
if (!key.startsWith('on') && key !== 'ref') {
|
|
292
|
+
throw new Error(`Invalid prop '${key}' of type 'function' supplied to '${tag}'.`)
|
|
293
|
+
}
|
|
294
|
+
// maybe event handler for client components, just ignore in server components
|
|
295
|
+
} else {
|
|
296
|
+
buffer[0] += ` ${key}="`
|
|
297
|
+
escapeToBuffer(v.toString(), buffer)
|
|
298
|
+
buffer[0] += '"'
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (emptyTags.includes(tag as string) && children.length === 0) {
|
|
303
|
+
buffer[0] += '/>'
|
|
304
|
+
return
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
buffer[0] += '>'
|
|
308
|
+
|
|
309
|
+
childrenToStringToBuffer(children, buffer)
|
|
310
|
+
|
|
311
|
+
buffer[0] += `</${tag}>`
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
class JSXFunctionNode extends JSXNode {
|
|
316
|
+
override toStringToBuffer(buffer: StringBufferWithCallbacks): void {
|
|
317
|
+
const { children } = this
|
|
318
|
+
|
|
319
|
+
const props = { ...this.props }
|
|
320
|
+
if (children.length) {
|
|
321
|
+
props.children = children.length === 1 ? children[0] : children
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const res = (this.tag as Function).call(null, props)
|
|
325
|
+
|
|
326
|
+
if (typeof res === 'boolean' || res == null) {
|
|
327
|
+
// boolean or null or undefined
|
|
328
|
+
return
|
|
329
|
+
} else if (res instanceof Promise) {
|
|
330
|
+
if (globalContexts.length === 0) {
|
|
331
|
+
buffer.unshift('', resolveFunctionComponentResult(res))
|
|
332
|
+
} else {
|
|
333
|
+
// save the current context state for resuming the suspended subtree
|
|
334
|
+
buffer.unshift('', resolveFunctionComponentResult(res, captureRenderContext()))
|
|
335
|
+
}
|
|
336
|
+
} else if (res instanceof JSXNode) {
|
|
337
|
+
res.toStringToBuffer(buffer)
|
|
338
|
+
} else if (Array.isArray(res)) {
|
|
339
|
+
childrenToStringToBuffer(res, buffer)
|
|
340
|
+
} else if (typeof res === 'number' || (res as HtmlEscaped).isEscaped) {
|
|
341
|
+
buffer[0] += res
|
|
342
|
+
if (res.callbacks) {
|
|
343
|
+
buffer.callbacks ||= []
|
|
344
|
+
buffer.callbacks.push(...res.callbacks)
|
|
345
|
+
}
|
|
346
|
+
} else {
|
|
347
|
+
escapeToBuffer(res, buffer)
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export class JSXFragmentNode extends JSXNode {
|
|
353
|
+
override toStringToBuffer(buffer: StringBufferWithCallbacks): void {
|
|
354
|
+
childrenToStringToBuffer(this.children, buffer)
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export const jsx = (tag: string | Function, props: Props | null, ...children: Child[]): JSXNode => {
|
|
359
|
+
props ??= {}
|
|
360
|
+
if (children.length) {
|
|
361
|
+
props.children = children.length === 1 ? children[0] : children
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const key = props.key
|
|
365
|
+
delete props['key']
|
|
366
|
+
|
|
367
|
+
const node = jsxFn(tag, props, children)
|
|
368
|
+
node.key = key
|
|
369
|
+
return node
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
let initDomRenderer = false
|
|
373
|
+
export const jsxFn = (tag: string | Function, props: Props, children: Child[]): JSXNode => {
|
|
374
|
+
if (!initDomRenderer) {
|
|
375
|
+
for (const k in domRenderers) {
|
|
376
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
377
|
+
;(intrinsicElementTags[k as keyof typeof intrinsicElementTags] as any)[DOM_RENDERER] =
|
|
378
|
+
domRenderers[k]
|
|
379
|
+
}
|
|
380
|
+
initDomRenderer = true
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (typeof tag === 'function') {
|
|
384
|
+
return new JSXFunctionNode(tag, props, children)
|
|
385
|
+
} else if (intrinsicElementTags[tag as keyof typeof intrinsicElementTags]) {
|
|
386
|
+
return new JSXFunctionNode(
|
|
387
|
+
intrinsicElementTags[tag as keyof typeof intrinsicElementTags],
|
|
388
|
+
props,
|
|
389
|
+
children
|
|
390
|
+
)
|
|
391
|
+
} else if (tag === 'svg' || tag === 'head') {
|
|
392
|
+
nameSpaceContext ||= createContext('')
|
|
393
|
+
return new JSXNode(tag, props, [
|
|
394
|
+
new JSXFunctionNode(
|
|
395
|
+
nameSpaceContext,
|
|
396
|
+
{
|
|
397
|
+
value: tag,
|
|
398
|
+
},
|
|
399
|
+
children
|
|
400
|
+
),
|
|
401
|
+
])
|
|
402
|
+
} else {
|
|
403
|
+
return new JSXNode(tag, props, children)
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
export const shallowEqual = (a: Props, b: Props): boolean => {
|
|
408
|
+
if (a === b) {
|
|
409
|
+
return true
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const aKeys = Object.keys(a).sort()
|
|
413
|
+
const bKeys = Object.keys(b).sort()
|
|
414
|
+
if (aKeys.length !== bKeys.length) {
|
|
415
|
+
return false
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
for (let i = 0, len = aKeys.length; i < len; i++) {
|
|
419
|
+
if (
|
|
420
|
+
aKeys[i] === 'children' &&
|
|
421
|
+
bKeys[i] === 'children' &&
|
|
422
|
+
!a.children?.length &&
|
|
423
|
+
!b.children?.length
|
|
424
|
+
) {
|
|
425
|
+
continue
|
|
426
|
+
} else if (a[aKeys[i]] !== b[aKeys[i]]) {
|
|
427
|
+
return false
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
return true
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
export type MemorableFC<T> = FC<T> & {
|
|
435
|
+
[DOM_MEMO]: (prevProps: Readonly<T>, nextProps: Readonly<T>) => boolean
|
|
436
|
+
}
|
|
437
|
+
export const memo = <T>(
|
|
438
|
+
component: FC<T>,
|
|
439
|
+
propsAreEqual: (prevProps: Readonly<T>, nextProps: Readonly<T>) => boolean = shallowEqual
|
|
440
|
+
): FC<T> => {
|
|
441
|
+
const wrapper: MemorableFC<T> = ((props: T) => component(props)) as MemorableFC<T>
|
|
442
|
+
|
|
443
|
+
// This function is for toString(), but it can also be used for DOM renderer.
|
|
444
|
+
// So, set DOM_MEMO and DOM_RENDERER for DOM renderer.
|
|
445
|
+
wrapper[DOM_MEMO] = propsAreEqual
|
|
446
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
447
|
+
;(wrapper as any)[DOM_RENDERER] = component
|
|
448
|
+
|
|
449
|
+
return wrapper as FC<T>
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
export const Fragment = ({
|
|
453
|
+
children,
|
|
454
|
+
}: {
|
|
455
|
+
key?: string
|
|
456
|
+
children?: Child | HtmlEscapedString
|
|
457
|
+
}): HtmlEscapedString => {
|
|
458
|
+
return new JSXFragmentNode(
|
|
459
|
+
'',
|
|
460
|
+
{
|
|
461
|
+
children,
|
|
462
|
+
},
|
|
463
|
+
Array.isArray(children) ? children : children ? [children] : []
|
|
464
|
+
) as never
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
export const isValidElement = (element: unknown): element is JSXNode => {
|
|
468
|
+
return !!(element && typeof element === 'object' && 'tag' in element && 'props' in element)
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
export const cloneElement = <T extends JSXNode | JSX.Element>(
|
|
472
|
+
element: T,
|
|
473
|
+
props: Partial<Props>,
|
|
474
|
+
...children: Child[]
|
|
475
|
+
): T => {
|
|
476
|
+
let childrenToClone
|
|
477
|
+
if (children.length > 0) {
|
|
478
|
+
childrenToClone = children
|
|
479
|
+
} else {
|
|
480
|
+
const c = (element as JSXNode).props.children
|
|
481
|
+
childrenToClone = c !== undefined ? (Array.isArray(c) ? c : [c]) : []
|
|
482
|
+
}
|
|
483
|
+
return jsx(
|
|
484
|
+
(element as JSXNode).tag,
|
|
485
|
+
{ ...(element as JSXNode).props, ...props },
|
|
486
|
+
...childrenToClone
|
|
487
|
+
) as T
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
export const reactAPICompatVersion = '19.0.0-acryl-jsx'
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Child } from './base.ts'
|
|
2
|
+
|
|
3
|
+
export const toArray = (children: Child): Child[] =>
|
|
4
|
+
Array.isArray(children) ? children : [children]
|
|
5
|
+
export const Children = {
|
|
6
|
+
map: (children: Child[], fn: (child: Child, index: number) => Child): Child[] =>
|
|
7
|
+
toArray(children).map(fn),
|
|
8
|
+
forEach: (children: Child[], fn: (child: Child, index: number) => void): void => {
|
|
9
|
+
toArray(children).forEach(fn)
|
|
10
|
+
},
|
|
11
|
+
count: (children: Child[]): number => toArray(children).length,
|
|
12
|
+
only: (_children: Child[]): Child => {
|
|
13
|
+
const children = toArray(_children)
|
|
14
|
+
if (children.length !== 1) {
|
|
15
|
+
throw new Error('Children.only() expects only one child')
|
|
16
|
+
}
|
|
17
|
+
return children[0]
|
|
18
|
+
},
|
|
19
|
+
toArray,
|
|
20
|
+
}
|