@shortlink-org/portolan 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/LICENSE +21 -0
- package/README.md +387 -0
- package/catalog/enum_test.go +46 -0
- package/catalog/model.go +932 -0
- package/catalog/roundtrip_test.go +185 -0
- package/catalog/via_test.go +38 -0
- package/cli/portolan.mjs +368 -0
- package/go.mod +14 -0
- package/go.sum +14 -0
- package/index.html +13 -0
- package/internal/commands/cargo.go +154 -0
- package/internal/commands/commands.go +143 -0
- package/internal/commands/commands_test.go +323 -0
- package/internal/commands/gradle.go +77 -0
- package/internal/commands/justfile.go +82 -0
- package/internal/commands/makefile.go +106 -0
- package/internal/commands/maven.go +93 -0
- package/internal/commands/packagejson.go +159 -0
- package/internal/commands/pyproject.go +169 -0
- package/internal/commands/taskfile.go +101 -0
- package/internal/commands/testdata/estate/.cargo/config.toml +7 -0
- package/internal/commands/testdata/estate/Makefile +33 -0
- package/internal/commands/testdata/estate/Taskfile.yml +21 -0
- package/internal/commands/testdata/estate/build.gradle.kts +21 -0
- package/internal/commands/testdata/estate/justfile +20 -0
- package/internal/commands/testdata/estate/package.json +13 -0
- package/internal/commands/testdata/estate/pom.xml +29 -0
- package/internal/commands/testdata/estate/pyproject.toml +27 -0
- package/internal/commands/testdata/estate/xtask/src/main.rs +27 -0
- package/internal/commands/testdata/golden/commands.json +305 -0
- package/internal/gohttp/analyze.go +2500 -0
- package/internal/gohttp/endpoints.go +1067 -0
- package/internal/gohttp/roots.go +320 -0
- package/internal/gohttp/typed.go +143 -0
- package/internal/goscan/constants.go +85 -0
- package/internal/goscan/goscan_test.go +227 -0
- package/internal/goscan/names.go +52 -0
- package/internal/goscan/parse_test.go +11 -0
- package/internal/goscan/source.go +36 -0
- package/internal/goscan/tree.go +155 -0
- package/internal/goscan/types.go +99 -0
- package/internal/wsdl/ids.go +127 -0
- package/internal/wsdl/ids_test.go +21 -0
- package/internal/wsdl/model.go +62 -0
- package/internal/wsdl/parse.go +920 -0
- package/internal/wsdl/parse_test.go +133 -0
- package/package.json +117 -0
- package/plugin/describe.go +107 -0
- package/plugin/describe_test.go +114 -0
- package/plugin/protocol.go +117 -0
- package/plugin/schematest/schematest.go +126 -0
- package/plugins/README.md +1160 -0
- package/plugins/extract-adr/describe.go +19 -0
- package/plugins/extract-adr/describe_test.go +11 -0
- package/plugins/extract-adr/extract.go +153 -0
- package/plugins/extract-adr/extract_test.go +350 -0
- package/plugins/extract-adr/history.go +99 -0
- package/plugins/extract-adr/main.go +65 -0
- package/plugins/extract-adr/options.schema.json +26 -0
- package/plugins/extract-adr/parse.go +642 -0
- package/plugins/extract-adr/parse_test.go +405 -0
- package/plugins/extract-asyncapi/describe.go +19 -0
- package/plugins/extract-asyncapi/describe_test.go +11 -0
- package/plugins/extract-asyncapi/extract.go +315 -0
- package/plugins/extract-asyncapi/extract_test.go +197 -0
- package/plugins/extract-asyncapi/main.go +48 -0
- package/plugins/extract-asyncapi/options.schema.json +26 -0
- package/plugins/extract-asyncapi/spec.go +151 -0
- package/plugins/extract-celery/README.md +169 -0
- package/plugins/extract-celery/extract.py +346 -0
- package/plugins/extract-celery/extract_test.py +192 -0
- package/plugins/extract-celery/main.py +66 -0
- package/plugins/extract-celery/options.py +31 -0
- package/plugins/extract-celery/options.schema.json +31 -0
- package/plugins/extract-celery/producers.py +156 -0
- package/plugins/extract-celery/routes_test.py +106 -0
- package/plugins/extract-commands/describe.go +19 -0
- package/plugins/extract-commands/describe_test.go +11 -0
- package/plugins/extract-commands/extract.go +79 -0
- package/plugins/extract-commands/extract_test.go +92 -0
- package/plugins/extract-commands/main.go +55 -0
- package/plugins/extract-commands/options.schema.json +20 -0
- package/plugins/extract-csr/avro.go +258 -0
- package/plugins/extract-csr/describe.go +19 -0
- package/plugins/extract-csr/describe_test.go +11 -0
- package/plugins/extract-csr/extract.go +338 -0
- package/plugins/extract-csr/extract_test.go +374 -0
- package/plugins/extract-csr/jsonschema.go +343 -0
- package/plugins/extract-csr/lock.go +25 -0
- package/plugins/extract-csr/main.go +84 -0
- package/plugins/extract-csr/options.schema.json +43 -0
- package/plugins/extract-csr/subject.go +102 -0
- package/plugins/extract-django/README.md +386 -0
- package/plugins/extract-django/apps.py +100 -0
- package/plugins/extract-django/auth.py +302 -0
- package/plugins/extract-django/auth_test.py +188 -0
- package/plugins/extract-django/clients.py +121 -0
- package/plugins/extract-django/contracts.py +458 -0
- package/plugins/extract-django/database.py +119 -0
- package/plugins/extract-django/domain.py +318 -0
- package/plugins/extract-django/events.py +86 -0
- package/plugins/extract-django/extract.py +601 -0
- package/plugins/extract-django/extract_test.py +397 -0
- package/plugins/extract-django/flows.py +1278 -0
- package/plugins/extract-django/flows_test.py +338 -0
- package/plugins/extract-django/ids.py +42 -0
- package/plugins/extract-django/ids_test.py +30 -0
- package/plugins/extract-django/lifecycle.py +222 -0
- package/plugins/extract-django/lifecycle_test.py +76 -0
- package/plugins/extract-django/main.py +66 -0
- package/plugins/extract-django/openapi.py +229 -0
- package/plugins/extract-django/openapi_test.py +60 -0
- package/plugins/extract-django/operations.py +96 -0
- package/plugins/extract-django/options.py +61 -0
- package/plugins/extract-django/options.schema.json +126 -0
- package/plugins/extract-django/routing.py +214 -0
- package/plugins/extract-django/routing_test.py +198 -0
- package/plugins/extract-django/serializers.py +558 -0
- package/plugins/extract-django/store.py +434 -0
- package/plugins/extract-django/transport.py +242 -0
- package/plugins/extract-flows/describe.go +19 -0
- package/plugins/extract-flows/describe_test.go +11 -0
- package/plugins/extract-flows/extract.go +91 -0
- package/plugins/extract-flows/main.go +45 -0
- package/plugins/extract-flows/options.schema.json +16 -0
- package/plugins/extract-flows/parse.go +593 -0
- package/plugins/extract-flows/parse_test.go +204 -0
- package/plugins/extract-glossary/describe.go +19 -0
- package/plugins/extract-glossary/describe_test.go +11 -0
- package/plugins/extract-glossary/extract.go +115 -0
- package/plugins/extract-glossary/extract_test.go +220 -0
- package/plugins/extract-glossary/main.go +59 -0
- package/plugins/extract-glossary/options.schema.json +21 -0
- package/plugins/extract-glossary/parse.go +214 -0
- package/plugins/extract-glossary/parse_test.go +203 -0
- package/plugins/extract-go/aggregate.go +214 -0
- package/plugins/extract-go/client.go +409 -0
- package/plugins/extract-go/client_test.go +266 -0
- package/plugins/extract-go/describe.go +19 -0
- package/plugins/extract-go/describe_test.go +11 -0
- package/plugins/extract-go/enum.go +195 -0
- package/plugins/extract-go/enum_test.go +82 -0
- package/plugins/extract-go/event.go +99 -0
- package/plugins/extract-go/extract.go +191 -0
- package/plugins/extract-go/extract_test.go +261 -0
- package/plugins/extract-go/flow.go +1441 -0
- package/plugins/extract-go/flow_test.go +609 -0
- package/plugins/extract-go/httpclient.go +174 -0
- package/plugins/extract-go/httpclient_test.go +296 -0
- package/plugins/extract-go/ids.go +92 -0
- package/plugins/extract-go/layout.go +225 -0
- package/plugins/extract-go/layout_test.go +125 -0
- package/plugins/extract-go/lifecycle.go +324 -0
- package/plugins/extract-go/lifecycle_test.go +108 -0
- package/plugins/extract-go/main.go +79 -0
- package/plugins/extract-go/operation.go +157 -0
- package/plugins/extract-go/options.schema.json +66 -0
- package/plugins/extract-go/source.go +316 -0
- package/plugins/extract-go/transport.go +321 -0
- package/plugins/extract-go/transport_test.go +145 -0
- package/plugins/extract-go/wiring.go +434 -0
- package/plugins/extract-go-nats/describe.go +19 -0
- package/plugins/extract-go-nats/describe_test.go +11 -0
- package/plugins/extract-go-nats/extract.go +177 -0
- package/plugins/extract-go-nats/extract_test.go +389 -0
- package/plugins/extract-go-nats/index.go +379 -0
- package/plugins/extract-go-nats/main.go +42 -0
- package/plugins/extract-go-nats/options.schema.json +21 -0
- package/plugins/extract-go-nats/resolve.go +161 -0
- package/plugins/extract-go-nats/sites.go +224 -0
- package/plugins/extract-graphql/describe.go +19 -0
- package/plugins/extract-graphql/describe_test.go +11 -0
- package/plugins/extract-graphql/extract.go +433 -0
- package/plugins/extract-graphql/extract_test.go +256 -0
- package/plugins/extract-graphql/ids.go +49 -0
- package/plugins/extract-graphql/lex.go +237 -0
- package/plugins/extract-graphql/main.go +51 -0
- package/plugins/extract-graphql/options.schema.json +31 -0
- package/plugins/extract-graphql/parse.go +621 -0
- package/plugins/extract-graphql/parse_test.go +122 -0
- package/plugins/extract-http-clients/describe.go +19 -0
- package/plugins/extract-http-clients/describe_test.go +11 -0
- package/plugins/extract-http-clients/extract.go +705 -0
- package/plugins/extract-http-clients/extract_test.go +1263 -0
- package/plugins/extract-http-clients/main.go +42 -0
- package/plugins/extract-http-clients/options.schema.json +33 -0
- package/plugins/extract-java/README.md +190 -0
- package/plugins/extract-java/build/org/portolan/extract/Catalog.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients$1.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients$2.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients$Call.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients$Client.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients$Route.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Domain$Aggregate.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Domain.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Events$Found.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Events.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Extract.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows$1.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows$Binding.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows$Draft.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows$Frame.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows$Options.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Ids.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Json$Reader.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Json.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Lifecycle$1.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Lifecycle$Move.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Lifecycle.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Main.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/OpenApi$Operation.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/OpenApi$Spec.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/OpenApi.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Operations$1.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Operations$UseCase.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Operations.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Proto$Rpc.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Proto$Service.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Proto.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Protocol$Builder.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Protocol$Input.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Protocol$Options.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Protocol.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Source$Project.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Source$Unit.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Source.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Transport$Endpoint.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Transport.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Yaml$Line.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Yaml$Reader.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Yaml.class +0 -0
- package/plugins/extract-java/options.schema.json +70 -0
- package/plugins/extract-openapi/describe.go +19 -0
- package/plugins/extract-openapi/describe_test.go +11 -0
- package/plugins/extract-openapi/discover.go +243 -0
- package/plugins/extract-openapi/extract.go +526 -0
- package/plugins/extract-openapi/extract_test.go +545 -0
- package/plugins/extract-openapi/main.go +75 -0
- package/plugins/extract-openapi/options.schema.json +62 -0
- package/plugins/extract-openapi/spec.go +350 -0
- package/plugins/extract-project/README.md +22 -0
- package/plugins/extract-project/describe.go +19 -0
- package/plugins/extract-project/describe_test.go +11 -0
- package/plugins/extract-project/extract.go +221 -0
- package/plugins/extract-project/extract_test.go +109 -0
- package/plugins/extract-project/main.go +41 -0
- package/plugins/extract-project/options.schema.json +48 -0
- package/plugins/extract-proto/ast.go +125 -0
- package/plugins/extract-proto/consumes.go +77 -0
- package/plugins/extract-proto/describe.go +19 -0
- package/plugins/extract-proto/extract.go +293 -0
- package/plugins/extract-proto/extract_test.go +459 -0
- package/plugins/extract-proto/ids.go +89 -0
- package/plugins/extract-proto/ids_test.go +57 -0
- package/plugins/extract-proto/lex.go +285 -0
- package/plugins/extract-proto/main.go +100 -0
- package/plugins/extract-proto/module.go +120 -0
- package/plugins/extract-proto/options.schema.json +51 -0
- package/plugins/extract-proto/parse.go +720 -0
- package/plugins/extract-proto/parse_test.go +307 -0
- package/plugins/extract-proto/provides.go +236 -0
- package/plugins/extract-proto/resolve.go +222 -0
- package/plugins/extract-proto/resolve_test.go +119 -0
- package/plugins/extract-python-kafka/README.md +36 -0
- package/plugins/extract-python-kafka/extract.py +211 -0
- package/plugins/extract-python-kafka/extract_test.py +68 -0
- package/plugins/extract-python-kafka/main.py +59 -0
- package/plugins/extract-python-kafka/options.py +29 -0
- package/plugins/extract-python-kafka/options.schema.json +31 -0
- package/plugins/extract-redis/README.md +11 -0
- package/plugins/extract-redis/describe.go +19 -0
- package/plugins/extract-redis/describe_test.go +11 -0
- package/plugins/extract-redis/extract.go +183 -0
- package/plugins/extract-redis/extract_test.go +168 -0
- package/plugins/extract-redis/keyspaces.go +469 -0
- package/plugins/extract-redis/main.go +44 -0
- package/plugins/extract-redis/options.schema.json +30 -0
- package/plugins/extract-river/describe.go +19 -0
- package/plugins/extract-river/describe_test.go +11 -0
- package/plugins/extract-river/extract.go +507 -0
- package/plugins/extract-river/extract_test.go +132 -0
- package/plugins/extract-river/main.go +42 -0
- package/plugins/extract-river/options.schema.json +21 -0
- package/plugins/extract-rust/Cargo.lock +133 -0
- package/plugins/extract-rust/Cargo.toml +23 -0
- package/plugins/extract-rust/README.md +204 -0
- package/plugins/extract-rust/options.schema.json +65 -0
- package/plugins/extract-rust/rustfmt.toml +1 -0
- package/plugins/extract-sql/ddl.go +893 -0
- package/plugins/extract-sql/ddl_test.go +401 -0
- package/plugins/extract-sql/describe.go +19 -0
- package/plugins/extract-sql/describe_test.go +11 -0
- package/plugins/extract-sql/layout.go +221 -0
- package/plugins/extract-sql/layout_test.go +55 -0
- package/plugins/extract-sql/lineage.go +107 -0
- package/plugins/extract-sql/main.go +141 -0
- package/plugins/extract-sql/maps.go +564 -0
- package/plugins/extract-sql/maps_java.go +117 -0
- package/plugins/extract-sql/maps_rust.go +333 -0
- package/plugins/extract-sql/maps_rust_test.go +70 -0
- package/plugins/extract-sql/maps_test.go +204 -0
- package/plugins/extract-sql/maps_ts.go +398 -0
- package/plugins/extract-sql/maps_ts_test.go +136 -0
- package/plugins/extract-sql/options.schema.json +53 -0
- package/plugins/extract-sql/projection.go +70 -0
- package/plugins/extract-sql/projection_test.go +50 -0
- package/plugins/extract-sql/store.go +420 -0
- package/plugins/extract-sql/store_test.go +233 -0
- package/plugins/extract-sql/view.go +295 -0
- package/plugins/extract-ts/README.md +306 -0
- package/plugins/extract-ts/ast.test.ts +178 -0
- package/plugins/extract-ts/ast.ts +648 -0
- package/plugins/extract-ts/clients.ts +185 -0
- package/plugins/extract-ts/domain.ts +164 -0
- package/plugins/extract-ts/extract.test.ts +208 -0
- package/plugins/extract-ts/extract.ts +200 -0
- package/plugins/extract-ts/flows.ts +783 -0
- package/plugins/extract-ts/graphql.test.ts +73 -0
- package/plugins/extract-ts/graphql.ts +181 -0
- package/plugins/extract-ts/ids.test.ts +21 -0
- package/plugins/extract-ts/ids.ts +52 -0
- package/plugins/extract-ts/lifecycle.ts +138 -0
- package/plugins/extract-ts/main.ts +48 -0
- package/plugins/extract-ts/openapi.test.ts +64 -0
- package/plugins/extract-ts/openapi.ts +99 -0
- package/plugins/extract-ts/operations.ts +93 -0
- package/plugins/extract-ts/options.schema.json +96 -0
- package/plugins/extract-ts/source.test.ts +174 -0
- package/plugins/extract-ts/source.ts +465 -0
- package/plugins/extract-ts/transport.ts +147 -0
- package/plugins/extract-ts/tsconfig.json +13 -0
- package/plugins/extract-ts/wiring.ts +190 -0
- package/plugins/extract-watermill/describe.go +19 -0
- package/plugins/extract-watermill/describe_test.go +11 -0
- package/plugins/extract-watermill/extract.go +1228 -0
- package/plugins/extract-watermill/extract_test.go +234 -0
- package/plugins/extract-watermill/main.go +41 -0
- package/plugins/extract-watermill/options.schema.json +21 -0
- package/plugins/extract-wsdl/describe.go +19 -0
- package/plugins/extract-wsdl/describe_test.go +11 -0
- package/plugins/extract-wsdl/extract.go +148 -0
- package/plugins/extract-wsdl/extract_test.go +45 -0
- package/plugins/extract-wsdl/main.go +53 -0
- package/plugins/extract-wsdl/options.schema.json +59 -0
- package/plugins/fetch-bsr/auth.go +114 -0
- package/plugins/fetch-bsr/bsr.go +240 -0
- package/plugins/fetch-bsr/cache.go +66 -0
- package/plugins/fetch-bsr/describe.go +19 -0
- package/plugins/fetch-bsr/fetch.go +192 -0
- package/plugins/fetch-bsr/fetch_test.go +465 -0
- package/plugins/fetch-bsr/lock.go +71 -0
- package/plugins/fetch-bsr/main.go +117 -0
- package/plugins/fetch-bsr/options.schema.json +42 -0
- package/plugins/fetch-csr/auth.go +95 -0
- package/plugins/fetch-csr/cache.go +69 -0
- package/plugins/fetch-csr/describe.go +19 -0
- package/plugins/fetch-csr/describe_test.go +11 -0
- package/plugins/fetch-csr/fetch.go +254 -0
- package/plugins/fetch-csr/fetch_test.go +494 -0
- package/plugins/fetch-csr/lock.go +95 -0
- package/plugins/fetch-csr/main.go +122 -0
- package/plugins/fetch-csr/options.schema.json +42 -0
- package/plugins/fetch-csr/registry.go +209 -0
- package/plugins/fetch-git/cache.go +65 -0
- package/plugins/fetch-git/describe.go +19 -0
- package/plugins/fetch-git/describe_test.go +11 -0
- package/plugins/fetch-git/fetch.go +181 -0
- package/plugins/fetch-git/fetch_test.go +332 -0
- package/plugins/fetch-git/git.go +169 -0
- package/plugins/fetch-git/lock.go +72 -0
- package/plugins/fetch-git/main.go +127 -0
- package/plugins/fetch-git/offline.go +39 -0
- package/plugins/fetch-git/options.schema.json +42 -0
- package/plugins/fetch-git/pin.go +90 -0
- package/plugins/fetch-git/pin_test.go +74 -0
- package/plugins/gen-backstage/describe.go +17 -0
- package/plugins/gen-backstage/main.go +22 -0
- package/plugins/gen-backstage/options.schema.json +30 -0
- package/plugins/gen-backstage/plugin.go +473 -0
- package/plugins/gen-backstage/plugin_test.go +145 -0
- package/plugins/gen-backstage.wasm +0 -0
- package/plugins/gen-markdown/adr.go +162 -0
- package/plugins/gen-markdown/aggregate.go +362 -0
- package/plugins/gen-markdown/canonical.go +93 -0
- package/plugins/gen-markdown/context.go +90 -0
- package/plugins/gen-markdown/coverage_test.go +89 -0
- package/plugins/gen-markdown/describe.go +19 -0
- package/plugins/gen-markdown/describe_test.go +11 -0
- package/plugins/gen-markdown/external.go +71 -0
- package/plugins/gen-markdown/flow.go +277 -0
- package/plugins/gen-markdown/glossary.go +76 -0
- package/plugins/gen-markdown/glossary_test.go +148 -0
- package/plugins/gen-markdown/llms.go +302 -0
- package/plugins/gen-markdown/main.go +22 -0
- package/plugins/gen-markdown/markdown.go +254 -0
- package/plugins/gen-markdown/markdown_test.go +100 -0
- package/plugins/gen-markdown/module.go +107 -0
- package/plugins/gen-markdown/options.schema.json +16 -0
- package/plugins/gen-markdown/plugin.go +39 -0
- package/plugins/gen-markdown/quality_test.go +176 -0
- package/plugins/gen-markdown/redis_test.go +38 -0
- package/plugins/gen-markdown/render.go +344 -0
- package/plugins/gen-markdown/render_test.go +186 -0
- package/plugins/gen-markdown/service.go +456 -0
- package/plugins/gen-markdown/source.go +177 -0
- package/plugins/gen-markdown/store.go +201 -0
- package/plugins/gen-markdown.wasm +0 -0
- package/plugins/gen-mermaid/describe.go +17 -0
- package/plugins/gen-mermaid/main.go +22 -0
- package/plugins/gen-mermaid/options.schema.json +10 -0
- package/plugins/gen-mermaid/plugin.go +104 -0
- package/plugins/gen-mermaid/plugin_test.go +33 -0
- package/plugins/gen-mermaid.wasm +0 -0
- package/plugins/openapi/ids.go +261 -0
- package/plugins/openapi/ids_test.go +98 -0
- package/plugins/pyplugin/catalog.py +209 -0
- package/plugins/pyplugin/celery_conf.py +436 -0
- package/plugins/pyplugin/celery_tasks.py +76 -0
- package/plugins/pyplugin/kafka.py +570 -0
- package/plugins/pyplugin/names.py +38 -0
- package/plugins/pyplugin/protocol.py +79 -0
- package/plugins/pyplugin/source.py +285 -0
- package/plugins/verify-codeowners/describe.go +19 -0
- package/plugins/verify-codeowners/describe_test.go +11 -0
- package/plugins/verify-codeowners/main.go +75 -0
- package/plugins/verify-codeowners/match.go +85 -0
- package/plugins/verify-codeowners/match_test.go +47 -0
- package/plugins/verify-codeowners/options.schema.json +15 -0
- package/plugins/verify-codeowners/owners.go +164 -0
- package/plugins/verify-codeowners/owners_test.go +225 -0
- package/plugins/verify-codeowners/parse.go +90 -0
- package/plugins/verify-codeowners/parse_test.go +62 -0
- package/plugins/verify-otel/describe.go +19 -0
- package/plugins/verify-otel/describe_test.go +11 -0
- package/plugins/verify-otel/main.go +53 -0
- package/plugins/verify-otel/match.go +336 -0
- package/plugins/verify-otel/options.schema.json +30 -0
- package/plugins/verify-otel/otlp.go +200 -0
- package/plugins/verify-otel/verify.go +734 -0
- package/plugins/verify-otel/verify_test.go +460 -0
- package/portolan.json +1073 -0
- package/public/favicon.svg +12 -0
- package/schema/portolan.schema.json +2558 -0
- package/scripts/README.md +53 -0
- package/scripts/build-report.mjs +60 -0
- package/scripts/build-report.test.mjs +44 -0
- package/scripts/builtin-plugins.mjs +49 -0
- package/scripts/catalog-sources.mjs +67 -0
- package/scripts/diff.mjs +315 -0
- package/scripts/diff.test.mjs +151 -0
- package/scripts/forge-comment.mjs +144 -0
- package/scripts/forge-comment.test.mjs +151 -0
- package/scripts/forge-release.mjs +138 -0
- package/scripts/forge-release.test.mjs +106 -0
- package/scripts/forge.mjs +61 -0
- package/scripts/gen-likec4.mjs +854 -0
- package/scripts/gen-likec4.test.mjs +258 -0
- package/scripts/gen.mjs +603 -0
- package/scripts/generated-docs.test.mjs +66 -0
- package/scripts/local-api.mjs +1192 -0
- package/scripts/local-api.test.mjs +387 -0
- package/scripts/manifest.mjs +214 -0
- package/scripts/manifest.test.mjs +148 -0
- package/scripts/output-path.mjs +79 -0
- package/scripts/output-path.test.mjs +45 -0
- package/scripts/package-smoke.mjs +37 -0
- package/scripts/plugin-host.mjs +419 -0
- package/scripts/plugin-host.test.mjs +109 -0
- package/scripts/plugin-wasm-worker.mjs +34 -0
- package/scripts/run-builtin.mjs +81 -0
- package/scripts/schema.mjs +357 -0
- package/scripts/site-docs.mjs +295 -0
- package/scripts/site-docs.test.mjs +181 -0
- package/scripts/vendor-lock.mjs +58 -0
- package/scripts/vendor-lock.test.mjs +69 -0
- package/src/README.md +38 -0
- package/src/app/App.tsx +448 -0
- package/src/app/BranchPicker.test.ts +46 -0
- package/src/app/BranchPicker.tsx +153 -0
- package/src/app/Breadcrumbs.test.ts +38 -0
- package/src/app/Breadcrumbs.tsx +223 -0
- package/src/app/BuildStamp.tsx +146 -0
- package/src/app/CommandPalette.tsx +292 -0
- package/src/app/HashScroll.tsx +45 -0
- package/src/app/Sidebar.tsx +1742 -0
- package/src/app/TopBar.tsx +393 -0
- package/src/app/density.tsx +64 -0
- package/src/app/forge-access.test.ts +27 -0
- package/src/app/forge-access.tsx +80 -0
- package/src/app/panels.tsx +141 -0
- package/src/app/pins.tsx +242 -0
- package/src/app/query-client.ts +24 -0
- package/src/app/responsive.ts +55 -0
- package/src/app/shortcuts.test.ts +39 -0
- package/src/app/shortcuts.tsx +282 -0
- package/src/app/theme.tsx +51 -0
- package/src/app/title.test.ts +14 -0
- package/src/app/title.ts +30 -0
- package/src/app/toast.tsx +59 -0
- package/src/app/tree-keys.test.ts +80 -0
- package/src/app/tree-keys.ts +87 -0
- package/src/app/ui-store.ts +52 -0
- package/src/catalog-error.test.ts +105 -0
- package/src/catalog-profile.test.ts +59 -0
- package/src/catalog-profile.ts +101 -0
- package/src/catalog-stores.test.ts +431 -0
- package/src/catalog.test.ts +1215 -0
- package/src/catalog.ts +3125 -0
- package/src/chat/Cards.tsx +408 -0
- package/src/chat/ChatPanel.tsx +79 -0
- package/src/chat/ChatSettings.tsx +219 -0
- package/src/chat/Composer.tsx +99 -0
- package/src/chat/Conversation.tsx +281 -0
- package/src/chat/Header.tsx +46 -0
- package/src/chat/Message.tsx +49 -0
- package/src/chat/Notice.tsx +195 -0
- package/src/chat/Starter.tsx +67 -0
- package/src/chat/Steps.tsx +45 -0
- package/src/chat/Waiting.tsx +87 -0
- package/src/chat/flags.test.ts +59 -0
- package/src/chat/flags.ts +155 -0
- package/src/chat/linkify.test.ts +30 -0
- package/src/chat/linkify.ts +45 -0
- package/src/chat/prefs.ts +56 -0
- package/src/chat/prompt.test.ts +43 -0
- package/src/chat/prompt.ts +157 -0
- package/src/chat/store.ts +35 -0
- package/src/chat/tools.ts +58 -0
- package/src/chat/transport.ts +70 -0
- package/src/components/AdrRow.tsx +29 -0
- package/src/components/AnchorLink.tsx +67 -0
- package/src/components/ApiReference.tsx +134 -0
- package/src/components/AsyncApiReference.tsx +120 -0
- package/src/components/CatalogStamp.tsx +155 -0
- package/src/components/ChannelRows.tsx +132 -0
- package/src/components/CommandRows.tsx +139 -0
- package/src/components/DiagramSkeleton.tsx +71 -0
- package/src/components/EditorLink.tsx +85 -0
- package/src/components/FieldTree.tsx +305 -0
- package/src/components/FlowTrigger.tsx +34 -0
- package/src/components/Ident.tsx +89 -0
- package/src/components/Integrations.tsx +243 -0
- package/src/components/LifecycleDiagram.tsx +110 -0
- package/src/components/MachineDocs.tsx +42 -0
- package/src/components/Markdown.tsx +173 -0
- package/src/components/MarkdownTable.tsx +206 -0
- package/src/components/Mermaid.tsx +211 -0
- package/src/components/MethodRows.tsx +309 -0
- package/src/components/Overlay.tsx +125 -0
- package/src/components/PageHeader.tsx +189 -0
- package/src/components/RowActions.tsx +97 -0
- package/src/components/SchemaDocument.tsx +89 -0
- package/src/components/Select.tsx +126 -0
- package/src/components/ShapeRows.tsx +118 -0
- package/src/components/SourceDoc.tsx +82 -0
- package/src/components/SourcePreview.tsx +441 -0
- package/src/components/TabRow.tsx +182 -0
- package/src/components/TechIcon.tsx +34 -0
- package/src/components/Toc.tsx +132 -0
- package/src/components/WhatLinksHere.tsx +273 -0
- package/src/components/WsdlReference.tsx +84 -0
- package/src/components/ddd-icons.tsx +107 -0
- package/src/components/kind.tsx +157 -0
- package/src/components/logo.tsx +61 -0
- package/src/components/primitives.tsx +264 -0
- package/src/data.test.ts +18 -0
- package/src/data.ts +202 -0
- package/src/enrich.test.ts +1150 -0
- package/src/enrich.ts +672 -0
- package/src/er/ErCanvas.tsx +533 -0
- package/src/er/RedisSchema.tsx +74 -0
- package/src/er/RelationCard.tsx +267 -0
- package/src/er/StoreHeader.tsx +155 -0
- package/src/er/TableNode.tsx +84 -0
- package/src/er/ViewNode.tsx +83 -0
- package/src/er/layout.test.ts +115 -0
- package/src/er/layout.ts +77 -0
- package/src/er/lineage.test.ts +140 -0
- package/src/er/lineage.ts +107 -0
- package/src/er/markers.tsx +79 -0
- package/src/er/spec.test.ts +344 -0
- package/src/er/spec.ts +426 -0
- package/src/flow/ChainList.tsx +162 -0
- package/src/flow/FlowTable.tsx +123 -0
- package/src/flow/FlowToolbar.tsx +372 -0
- package/src/flow/StepDetail.tsx +380 -0
- package/src/flow/StepRail.tsx +428 -0
- package/src/flow/answers.test.ts +50 -0
- package/src/flow/answers.ts +58 -0
- package/src/flow/chain.test.ts +383 -0
- package/src/flow/chain.ts +353 -0
- package/src/flow/chapters.test.ts +185 -0
- package/src/flow/chapters.ts +225 -0
- package/src/flow/continues.test.ts +102 -0
- package/src/flow/continues.ts +65 -0
- package/src/flow/cross-context.test.ts +97 -0
- package/src/flow/cross-context.ts +35 -0
- package/src/flow/mermaid.test.ts +22 -0
- package/src/flow/mermaid.ts +141 -0
- package/src/flow/outline.test.ts +212 -0
- package/src/flow/outline.ts +170 -0
- package/src/flow/paths.test.ts +129 -0
- package/src/flow/paths.ts +147 -0
- package/src/flow/prefs.test.ts +80 -0
- package/src/flow/prefs.ts +104 -0
- package/src/graph/DependencyGraph.tsx +283 -0
- package/src/graph/DependencyNodes.tsx +162 -0
- package/src/graph/EdgeLabel.tsx +61 -0
- package/src/graph/FocusedEventGraph.tsx +211 -0
- package/src/graph/GraphToolbar.tsx +187 -0
- package/src/graph/RoutedEdge.tsx +80 -0
- package/src/graph/dependency-layout.test.ts +360 -0
- package/src/graph/dependency-layout.ts +444 -0
- package/src/graph/elk.test.ts +70 -0
- package/src/graph/elk.ts +287 -0
- package/src/graph/nodes.tsx +97 -0
- package/src/graph/theme.ts +81 -0
- package/src/graph/useElkFlow.ts +125 -0
- package/src/index.css +1547 -0
- package/src/language/InLanguage.tsx +40 -0
- package/src/language/TermCard.tsx +132 -0
- package/src/language/cards.test.ts +114 -0
- package/src/language/cards.ts +111 -0
- package/src/lib/admonition.test.ts +49 -0
- package/src/lib/admonition.ts +48 -0
- package/src/lib/adr.test.ts +131 -0
- package/src/lib/adr.ts +68 -0
- package/src/lib/api.test.ts +122 -0
- package/src/lib/api.ts +135 -0
- package/src/lib/backlinks.test.ts +330 -0
- package/src/lib/backlinks.ts +567 -0
- package/src/lib/branch-compare.ts +16 -0
- package/src/lib/build-info.test.ts +76 -0
- package/src/lib/build-info.ts +80 -0
- package/src/lib/catalog-diff.test.ts +275 -0
- package/src/lib/catalog-diff.ts +655 -0
- package/src/lib/clipboard.ts +43 -0
- package/src/lib/comparison-memory.test.ts +40 -0
- package/src/lib/comparison-memory.ts +39 -0
- package/src/lib/context-color.ts +27 -0
- package/src/lib/context-map.test.ts +148 -0
- package/src/lib/context-map.ts +399 -0
- package/src/lib/data-model.test.ts +245 -0
- package/src/lib/data-model.ts +399 -0
- package/src/lib/data-problems.test.ts +178 -0
- package/src/lib/data-problems.ts +314 -0
- package/src/lib/derive.test.ts +251 -0
- package/src/lib/derive.ts +515 -0
- package/src/lib/editor-link.test.ts +125 -0
- package/src/lib/editor-link.ts +96 -0
- package/src/lib/editor-prefs.ts +27 -0
- package/src/lib/event-graph.test.ts +237 -0
- package/src/lib/event-graph.ts +327 -0
- package/src/lib/export-canvas.ts +37 -0
- package/src/lib/export-file.test.ts +30 -0
- package/src/lib/export-file.ts +20 -0
- package/src/lib/flow-tree.test.ts +177 -0
- package/src/lib/flow-tree.ts +160 -0
- package/src/lib/forge-refs.test.ts +50 -0
- package/src/lib/forge-refs.ts +60 -0
- package/src/lib/format.test.ts +35 -0
- package/src/lib/format.ts +64 -0
- package/src/lib/github-catalog.test.ts +301 -0
- package/src/lib/github-catalog.ts +610 -0
- package/src/lib/integrations.test.ts +119 -0
- package/src/lib/integrations.ts +133 -0
- package/src/lib/kinds.test.ts +91 -0
- package/src/lib/kinds.ts +204 -0
- package/src/lib/lifecycle.test.ts +93 -0
- package/src/lib/lifecycle.ts +165 -0
- package/src/lib/local-api.ts +194 -0
- package/src/lib/motion-features.ts +11 -0
- package/src/lib/motion.test.ts +120 -0
- package/src/lib/motion.tsx +269 -0
- package/src/lib/palette-recent.test.ts +80 -0
- package/src/lib/palette-recent.ts +90 -0
- package/src/lib/palette.test.ts +365 -0
- package/src/lib/palette.ts +593 -0
- package/src/lib/pins.test.ts +139 -0
- package/src/lib/pins.ts +130 -0
- package/src/lib/problems.test.ts +112 -0
- package/src/lib/project-preview.ts +5 -0
- package/src/lib/proto-problems.test.ts +121 -0
- package/src/lib/proto-problems.ts +65 -0
- package/src/lib/queries.test.ts +113 -0
- package/src/lib/queries.ts +131 -0
- package/src/lib/registry.test.ts +219 -0
- package/src/lib/registry.ts +208 -0
- package/src/lib/scenarios.ts +547 -0
- package/src/lib/setup-info.test.ts +199 -0
- package/src/lib/setup-info.ts +415 -0
- package/src/lib/shape.test.ts +289 -0
- package/src/lib/shape.ts +454 -0
- package/src/lib/sidebar-prefs.test.ts +32 -0
- package/src/lib/sidebar-prefs.ts +75 -0
- package/src/lib/source-code.test.ts +159 -0
- package/src/lib/source-code.ts +286 -0
- package/src/lib/source-doc.test.ts +131 -0
- package/src/lib/source-doc.ts +103 -0
- package/src/lib/source-highlight.test.ts +29 -0
- package/src/lib/source-highlight.ts +24 -0
- package/src/lib/source-link.test.ts +153 -0
- package/src/lib/source-link.ts +201 -0
- package/src/lib/spec-files.test.ts +24 -0
- package/src/lib/spec-files.ts +23 -0
- package/src/lib/table-directive.test.ts +139 -0
- package/src/lib/table-directive.ts +106 -0
- package/src/lib/tech.test.ts +120 -0
- package/src/lib/tech.ts +421 -0
- package/src/lib/terms.test.ts +67 -0
- package/src/lib/terms.ts +179 -0
- package/src/lib/wire-problems.test.ts +263 -0
- package/src/lib/wire-problems.ts +281 -0
- package/src/likec4/C4View.tsx +55 -0
- package/src/likec4/CanvasBridge.tsx +187 -0
- package/src/likec4/FlowView.tsx +235 -0
- package/src/likec4/InteractiveView.tsx +144 -0
- package/src/likec4/canvas-viewport.test.ts +149 -0
- package/src/likec4/canvas-viewport.ts +135 -0
- package/src/likec4/flow-edges.test.ts +51 -0
- package/src/likec4/flow-edges.ts +89 -0
- package/src/likec4/frame-theme.test.ts +76 -0
- package/src/likec4/frame-theme.ts +101 -0
- package/src/likec4/highlight-css.test.ts +49 -0
- package/src/likec4/highlight-css.ts +52 -0
- package/src/likec4/ids.test.ts +151 -0
- package/src/likec4/ids.ts +115 -0
- package/src/likec4/levels.tsx +70 -0
- package/src/likec4/mapping.test.ts +66 -0
- package/src/likec4/mapping.ts +54 -0
- package/src/likec4/reserved.json +141 -0
- package/src/likec4/view-index.ts +78 -0
- package/src/main.tsx +13 -0
- package/src/map/ContextMapGraph.tsx +274 -0
- package/src/map/ContextNode.tsx +70 -0
- package/src/map/FloatingEdge.tsx +86 -0
- package/src/merge.test.ts +1038 -0
- package/src/merge.ts +1004 -0
- package/src/pages/AdrDetail.tsx +242 -0
- package/src/pages/AdrIndex.tsx +114 -0
- package/src/pages/AggregatePage.tsx +727 -0
- package/src/pages/BlockPage.tsx +478 -0
- package/src/pages/CatalogFailure.tsx +111 -0
- package/src/pages/Changes.tsx +313 -0
- package/src/pages/ContextMap.tsx +534 -0
- package/src/pages/ContextPage.tsx +346 -0
- package/src/pages/EnumPage.tsx +282 -0
- package/src/pages/EventPage.tsx +686 -0
- package/src/pages/ExternalPage.tsx +204 -0
- package/src/pages/FlowDetail.tsx +663 -0
- package/src/pages/FlowIndex.tsx +303 -0
- package/src/pages/GraphPage.tsx +217 -0
- package/src/pages/Language.tsx +257 -0
- package/src/pages/ModulePage.tsx +366 -0
- package/src/pages/NotFound.tsx +54 -0
- package/src/pages/Overview.tsx +344 -0
- package/src/pages/Problems.tsx +360 -0
- package/src/pages/RegistryIndex.tsx +118 -0
- package/src/pages/ServicePage.tsx +746 -0
- package/src/pages/Settings.tsx +975 -0
- package/src/pages/StorePage.tsx +114 -0
- package/src/peek/PeekCard.test.ts +35 -0
- package/src/peek/PeekCard.tsx +118 -0
- package/src/peek/PeekLayer.tsx +147 -0
- package/src/peek/model.test.ts +156 -0
- package/src/peek/model.ts +253 -0
- package/src/routes.test.ts +222 -0
- package/src/routes.ts +449 -0
- package/src/selection/DetailPanel.tsx +1407 -0
- package/src/selection/hash.test.ts +73 -0
- package/src/selection/hash.ts +58 -0
- package/src/selection/model.test.ts +199 -0
- package/src/selection/model.ts +473 -0
- package/src/selection/pages.test.ts +115 -0
- package/src/selection/pages.ts +268 -0
- package/src/selection/store.test.ts +62 -0
- package/src/selection/store.ts +46 -0
- package/src/selection/sync.tsx +99 -0
- package/src/table/ColumnsMenu.tsx +72 -0
- package/src/table/DataTable.tsx +780 -0
- package/src/table/Facets.tsx +54 -0
- package/src/table/GroupMenu.tsx +69 -0
- package/src/table/Toolbar.tsx +190 -0
- package/src/table/cells.tsx +117 -0
- package/src/table/compare.test.ts +117 -0
- package/src/table/compare.ts +196 -0
- package/src/table/export.test.ts +88 -0
- package/src/table/export.ts +66 -0
- package/src/table/facet-groups.test.ts +74 -0
- package/src/table/facet-groups.ts +56 -0
- package/src/table/grouping.test.ts +84 -0
- package/src/table/grouping.ts +82 -0
- package/src/table/infer.test.ts +57 -0
- package/src/table/infer.ts +50 -0
- package/src/table/persist.test.ts +76 -0
- package/src/table/persist.ts +112 -0
- package/src/table/sort-url.test.ts +75 -0
- package/src/table/sort-url.ts +52 -0
- package/src/table/types.ts +80 -0
- package/src/table/useTableState.ts +220 -0
- package/src/test-catalog.ts +7 -0
- package/src/testing/estate/data__catalog.json +2847 -0
- package/src/testing/estate/data__flows.json +1724 -0
- package/src/testing/estate/examples__auth__portolan__api.json +212 -0
- package/src/testing/estate/examples__auth__portolan__domain.json +1204 -0
- package/src/testing/estate/examples__auth__portolan__glossary.json +226 -0
- package/src/testing/estate/examples__auth__portolan__observed.json +757 -0
- package/src/testing/estate/examples__auth__portolan__stores.json +195 -0
- package/src/testing/estate/examples__shop__cart__portolan__api.json +234 -0
- package/src/testing/estate/examples__shop__cart__portolan__commands.json +86 -0
- package/src/testing/estate/examples__shop__cart__portolan__domain.json +966 -0
- package/src/testing/estate/examples__shop__cart__portolan__observed.json +498 -0
- package/src/testing/estate/examples__shop__cart__portolan__stores.json +208 -0
- package/src/testing/estate/examples__shop__oms__portolan__glossary.json +98 -0
- package/src/testing/estate/examples__shop__oms__portolan__proto.json +186 -0
- package/src/testing/estate.ts +49 -0
- package/src/trail/Trail.tsx +81 -0
- package/src/trail/model.test.ts +157 -0
- package/src/trail/model.ts +189 -0
- package/src/trail/record.tsx +32 -0
- package/src/trail/store.test.ts +66 -0
- package/src/trail/store.ts +102 -0
- package/tsconfig.json +35 -0
- package/vite.config.ts +171 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { Check, Copy } from "lucide-react";
|
|
3
|
+
import { useTheme } from "../app/theme";
|
|
4
|
+
import { toClipboard } from "../lib/clipboard";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Renders one mermaid fence. The library is ~500kB and is wanted on the pages
|
|
8
|
+
* that carry somebody's writing - a decision record, a service or aggregate
|
|
9
|
+
* readme - so it is imported on first render and never from the app entry.
|
|
10
|
+
*
|
|
11
|
+
* A diagram in a readme is a quotation, not a measurement. It is drawn exactly
|
|
12
|
+
* as written, even when the current catalog disagrees with it - but it is
|
|
13
|
+
* drawn in this app's colours, because a picture in the estate's own palette
|
|
14
|
+
* reads as part of the page and a picture in mermaid's reads as a screenshot
|
|
15
|
+
* somebody pasted.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
let seq = 0;
|
|
19
|
+
|
|
20
|
+
type Phase = "loading" | "drawn" | { error: string };
|
|
21
|
+
|
|
22
|
+
const SHOWN_MS = 1000;
|
|
23
|
+
|
|
24
|
+
/** One custom property's value, resolved. Mermaid wants colours, not `var()`. */
|
|
25
|
+
function token(name: string): string {
|
|
26
|
+
return getComputedStyle(document.documentElement)
|
|
27
|
+
.getPropertyValue(name)
|
|
28
|
+
.trim();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The theme mermaid is given, in this app's tokens.
|
|
33
|
+
*
|
|
34
|
+
* `base` is the only theme whose variables are honoured in full; every other
|
|
35
|
+
* one computes its own and ignores most of what is passed. The mapping follows
|
|
36
|
+
* LifecycleDiagram, which draws the catalog's own state machines: a node is
|
|
37
|
+
* the page's background inside a `--border-strong` box, and an edge is
|
|
38
|
+
* `--fg-muted` - so a quoted diagram and a measured one sit in the same family.
|
|
39
|
+
*
|
|
40
|
+
* Read after the palette is on the document, never before: the theme class is
|
|
41
|
+
* set by ThemeProvider's effect, and a child's effect runs first.
|
|
42
|
+
*/
|
|
43
|
+
function themeVariables(dark: boolean) {
|
|
44
|
+
const bg = token("--bg");
|
|
45
|
+
const surface = token("--surface");
|
|
46
|
+
const surface2 = token("--surface-2");
|
|
47
|
+
const border = token("--border");
|
|
48
|
+
const borderStrong = token("--border-strong");
|
|
49
|
+
const fg = token("--fg");
|
|
50
|
+
const muted = token("--fg-muted");
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
darkMode: dark,
|
|
54
|
+
background: surface,
|
|
55
|
+
fontFamily: token("--font-mono"),
|
|
56
|
+
fontSize: token("--text-sm"),
|
|
57
|
+
|
|
58
|
+
primaryColor: bg,
|
|
59
|
+
primaryBorderColor: borderStrong,
|
|
60
|
+
primaryTextColor: fg,
|
|
61
|
+
secondaryColor: surface2,
|
|
62
|
+
tertiaryColor: surface,
|
|
63
|
+
lineColor: muted,
|
|
64
|
+
textColor: fg,
|
|
65
|
+
mainBkg: bg,
|
|
66
|
+
nodeBorder: borderStrong,
|
|
67
|
+
nodeTextColor: fg,
|
|
68
|
+
titleColor: fg,
|
|
69
|
+
|
|
70
|
+
// The chip a label sits on. Painted as the sheet it lies on, so what the
|
|
71
|
+
// reader sees is the word and not the box around it.
|
|
72
|
+
edgeLabelBackground: surface,
|
|
73
|
+
labelBackground: surface,
|
|
74
|
+
labelBackgroundColor: surface,
|
|
75
|
+
labelColor: fg,
|
|
76
|
+
|
|
77
|
+
// State diagrams.
|
|
78
|
+
stateBkg: bg,
|
|
79
|
+
stateBorder: borderStrong,
|
|
80
|
+
transitionColor: muted,
|
|
81
|
+
transitionLabelColor: fg,
|
|
82
|
+
specialStateColor: fg,
|
|
83
|
+
innerEndBackground: bg,
|
|
84
|
+
compositeBackground: surface,
|
|
85
|
+
compositeTitleBackground: surface2,
|
|
86
|
+
compositeBorder: border,
|
|
87
|
+
altBackground: surface2,
|
|
88
|
+
|
|
89
|
+
// Sequence diagrams.
|
|
90
|
+
actorBkg: bg,
|
|
91
|
+
actorBorder: borderStrong,
|
|
92
|
+
actorTextColor: fg,
|
|
93
|
+
actorLineColor: border,
|
|
94
|
+
signalColor: muted,
|
|
95
|
+
signalTextColor: fg,
|
|
96
|
+
noteBkgColor: surface2,
|
|
97
|
+
noteBorderColor: border,
|
|
98
|
+
noteTextColor: fg,
|
|
99
|
+
activationBkgColor: surface2,
|
|
100
|
+
activationBorderColor: border,
|
|
101
|
+
sequenceNumberColor: bg,
|
|
102
|
+
loopTextColor: fg,
|
|
103
|
+
labelBoxBkgColor: surface,
|
|
104
|
+
labelBoxBorderColor: border,
|
|
105
|
+
labelTextColor: fg,
|
|
106
|
+
|
|
107
|
+
// Flowcharts.
|
|
108
|
+
clusterBkg: surface,
|
|
109
|
+
clusterBorder: border,
|
|
110
|
+
defaultLinkColor: muted,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function Mermaid({ code }: { code: string }) {
|
|
115
|
+
const { theme } = useTheme();
|
|
116
|
+
const host = useRef<HTMLDivElement>(null);
|
|
117
|
+
const [phase, setPhase] = useState<Phase>("loading");
|
|
118
|
+
const [copied, setCopied] = useState(false);
|
|
119
|
+
const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
120
|
+
|
|
121
|
+
useEffect(
|
|
122
|
+
() => () => {
|
|
123
|
+
if (timer.current) clearTimeout(timer.current);
|
|
124
|
+
},
|
|
125
|
+
[],
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
let cancelled = false;
|
|
130
|
+
setPhase("loading");
|
|
131
|
+
|
|
132
|
+
void (async () => {
|
|
133
|
+
try {
|
|
134
|
+
const mermaid = (await import("mermaid")).default;
|
|
135
|
+
mermaid.initialize({
|
|
136
|
+
startOnLoad: false,
|
|
137
|
+
securityLevel: "strict",
|
|
138
|
+
theme: "base",
|
|
139
|
+
themeVariables: themeVariables(theme === "dark"),
|
|
140
|
+
fontFamily: "var(--font-mono)",
|
|
141
|
+
// A diagram wider than the prose column belongs scaled down, not
|
|
142
|
+
// behind a scrollbar. Every kind that can outgrow the column says so
|
|
143
|
+
// for itself; the ones that cannot have nothing to say.
|
|
144
|
+
sequence: { useMaxWidth: true },
|
|
145
|
+
flowchart: { useMaxWidth: true },
|
|
146
|
+
state: { useMaxWidth: true },
|
|
147
|
+
class: { useMaxWidth: true },
|
|
148
|
+
er: { useMaxWidth: true },
|
|
149
|
+
});
|
|
150
|
+
seq += 1;
|
|
151
|
+
const { svg } = await mermaid.render(`mermaid-${seq}`, code);
|
|
152
|
+
if (cancelled) return;
|
|
153
|
+
if (host.current) host.current.innerHTML = svg;
|
|
154
|
+
setPhase("drawn");
|
|
155
|
+
} catch (err) {
|
|
156
|
+
if (cancelled) return;
|
|
157
|
+
setPhase({ error: err instanceof Error ? err.message : String(err) });
|
|
158
|
+
}
|
|
159
|
+
})();
|
|
160
|
+
|
|
161
|
+
return () => {
|
|
162
|
+
cancelled = true;
|
|
163
|
+
};
|
|
164
|
+
}, [code, theme]);
|
|
165
|
+
|
|
166
|
+
// The way out of the page with the diagram in hand, on the same terms as a
|
|
167
|
+
// flow's toolbar: the source, for a wiki or a pull request. Selecting text
|
|
168
|
+
// inside an SVG gets you nothing.
|
|
169
|
+
const copy = useCallback(() => {
|
|
170
|
+
void toClipboard(code).then((ok) => {
|
|
171
|
+
setCopied(ok);
|
|
172
|
+
if (timer.current) clearTimeout(timer.current);
|
|
173
|
+
timer.current = setTimeout(() => setCopied(false), SHOWN_MS);
|
|
174
|
+
});
|
|
175
|
+
}, [code]);
|
|
176
|
+
|
|
177
|
+
// A diagram that will not parse is still evidence: show the source it was
|
|
178
|
+
// written as, rather than an empty box.
|
|
179
|
+
if (typeof phase === "object") {
|
|
180
|
+
return (
|
|
181
|
+
<figure className="my-3">
|
|
182
|
+
<div className="mono border border-dashed px-2 py-1 status-unresolved">
|
|
183
|
+
this diagram does not parse — {phase.error}
|
|
184
|
+
</div>
|
|
185
|
+
<pre className="mt-1">{code}</pre>
|
|
186
|
+
</figure>
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return (
|
|
191
|
+
<figure className="group relative my-3 border border-line bg-surface p-3">
|
|
192
|
+
<button
|
|
193
|
+
type="button"
|
|
194
|
+
onClick={copy}
|
|
195
|
+
title={copied ? "copied" : "Copy the diagram as Mermaid"}
|
|
196
|
+
aria-label="Copy the diagram as Mermaid"
|
|
197
|
+
className="absolute right-1.5 top-1.5 inline-flex items-center rounded-[4px] p-1 text-muted opacity-0 t-micro transition-opacity hover:text-ink focus-visible:opacity-100 group-hover:opacity-100"
|
|
198
|
+
>
|
|
199
|
+
{copied ? (
|
|
200
|
+
<Check size={12} aria-hidden />
|
|
201
|
+
) : (
|
|
202
|
+
<Copy size={12} aria-hidden />
|
|
203
|
+
)}
|
|
204
|
+
</button>
|
|
205
|
+
<div ref={host} className="mermaid-figure overflow-x-auto" />
|
|
206
|
+
{phase === "loading" ? (
|
|
207
|
+
<div className="mono text-muted">drawing…</div>
|
|
208
|
+
) : null}
|
|
209
|
+
</figure>
|
|
210
|
+
);
|
|
211
|
+
}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
// One method of one interface, drawn the same way wherever it appears.
|
|
2
|
+
//
|
|
3
|
+
// The service page's `provides` tab and the module page both list methods, and
|
|
4
|
+
// a method that reads differently in the two places is a method a reader has to
|
|
5
|
+
// re-learn. So the row lives here, and both pages hand it the same thing.
|
|
6
|
+
//
|
|
7
|
+
// What a method carries beyond its name — the shapes on either side and how it
|
|
8
|
+
// streams — is the whole reason `RpcService.methods` stopped being a list of
|
|
9
|
+
// strings. Unary draws nothing at all: it is the common case, and a marker on
|
|
10
|
+
// every row would say only that most methods are ordinary.
|
|
11
|
+
|
|
12
|
+
import { ChevronDown, ChevronRight } from "lucide-react";
|
|
13
|
+
import type { ReactNode } from "react";
|
|
14
|
+
import type {
|
|
15
|
+
Field,
|
|
16
|
+
RpcDiscriminator,
|
|
17
|
+
RpcMethod,
|
|
18
|
+
RpcService,
|
|
19
|
+
} from "../catalog";
|
|
20
|
+
import { catalog } from "../data";
|
|
21
|
+
import { streamingKind } from "../lib/api";
|
|
22
|
+
import { Ident } from "./Ident";
|
|
23
|
+
import { RowActions } from "./RowActions";
|
|
24
|
+
import { ShapeRows } from "./ShapeRows";
|
|
25
|
+
|
|
26
|
+
const STREAM_LABEL: Record<"client" | "server" | "bidi", string> = {
|
|
27
|
+
client: "client stream",
|
|
28
|
+
server: "server stream",
|
|
29
|
+
bidi: "bidi stream",
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The fields of a message a method names.
|
|
34
|
+
*
|
|
35
|
+
* Resolution order matters and is one rule: a `ref` into `catalog.defs` wins,
|
|
36
|
+
* because a shared type is the same type wherever it turns up; otherwise the
|
|
37
|
+
* name is looked up among the messages the interface itself lists. A name that
|
|
38
|
+
* resolves to neither is still shown — the catalog knows what the method sends
|
|
39
|
+
* even when it could not read the shape.
|
|
40
|
+
*/
|
|
41
|
+
export function shapeFor(
|
|
42
|
+
provided: RpcService,
|
|
43
|
+
name: string | undefined,
|
|
44
|
+
ref: string | undefined,
|
|
45
|
+
): Field[] | null {
|
|
46
|
+
if (ref) {
|
|
47
|
+
const def = catalog.defs[ref];
|
|
48
|
+
if (def) return def.fields;
|
|
49
|
+
}
|
|
50
|
+
if (!name) return null;
|
|
51
|
+
|
|
52
|
+
return provided.messages?.find((m) => m.name === name)?.fields ?? null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function discriminatorFor(
|
|
56
|
+
provided: RpcService,
|
|
57
|
+
name: string | undefined,
|
|
58
|
+
): RpcDiscriminator | undefined {
|
|
59
|
+
if (!name) return undefined;
|
|
60
|
+
return provided.messages?.find((message) => message.name === name)
|
|
61
|
+
?.discriminator;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function DiscriminatorRows({
|
|
65
|
+
discriminator,
|
|
66
|
+
}: {
|
|
67
|
+
discriminator: RpcDiscriminator | undefined;
|
|
68
|
+
}) {
|
|
69
|
+
if (!discriminator) return null;
|
|
70
|
+
return (
|
|
71
|
+
<div className="mono mb-2 border-l-2 border-line pl-2 text-muted">
|
|
72
|
+
<div>
|
|
73
|
+
discriminator <span className="text-ink">{discriminator.property}</span>
|
|
74
|
+
</div>
|
|
75
|
+
{discriminator.variants.map((variant) => (
|
|
76
|
+
<div key={`${variant.value}:${variant.message}`}>
|
|
77
|
+
{variant.value} → <span className="text-ink">{variant.message}</span>
|
|
78
|
+
</div>
|
|
79
|
+
))}
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function Shape({
|
|
85
|
+
provided,
|
|
86
|
+
label,
|
|
87
|
+
name,
|
|
88
|
+
refKey,
|
|
89
|
+
open,
|
|
90
|
+
onToggle,
|
|
91
|
+
}: {
|
|
92
|
+
provided: RpcService;
|
|
93
|
+
label: string;
|
|
94
|
+
name: string | undefined;
|
|
95
|
+
refKey: string | undefined;
|
|
96
|
+
open: boolean;
|
|
97
|
+
onToggle: () => void;
|
|
98
|
+
}) {
|
|
99
|
+
if (!name) return null;
|
|
100
|
+
|
|
101
|
+
const fields = shapeFor(provided, name, refKey);
|
|
102
|
+
|
|
103
|
+
// Nothing to expand into: the shape is named but was never read, which is
|
|
104
|
+
// ordinary for an interface described by an OpenAPI document.
|
|
105
|
+
if (!fields) {
|
|
106
|
+
return (
|
|
107
|
+
<span className="mono text-muted" title={`${label} ${name}`}>
|
|
108
|
+
{name}
|
|
109
|
+
</span>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<button
|
|
115
|
+
type="button"
|
|
116
|
+
onClick={onToggle}
|
|
117
|
+
aria-expanded={open}
|
|
118
|
+
className="mono rounded-control text-left text-muted hover:text-ink"
|
|
119
|
+
title={`${label} ${name}`}
|
|
120
|
+
>
|
|
121
|
+
{name}
|
|
122
|
+
</button>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function MethodRows({
|
|
127
|
+
provided,
|
|
128
|
+
open,
|
|
129
|
+
onToggle,
|
|
130
|
+
runs,
|
|
131
|
+
}: {
|
|
132
|
+
provided: RpcService;
|
|
133
|
+
/** Which shapes are expanded, keyed `<interface>/<method>/req|res`. */
|
|
134
|
+
open: ReadonlySet<string>;
|
|
135
|
+
onToggle: (key: string) => void;
|
|
136
|
+
/** What the method runs, when the page knows — the service page does. */
|
|
137
|
+
runs?: (method: RpcMethod) => ReactNode;
|
|
138
|
+
}) {
|
|
139
|
+
return (
|
|
140
|
+
<ul data-nav-list>
|
|
141
|
+
{provided.methods.map((method) => {
|
|
142
|
+
const id = `${provided.id}/${method.name}`;
|
|
143
|
+
const reqKey = `${id}/req`;
|
|
144
|
+
const resKey = `${id}/res`;
|
|
145
|
+
const streaming = streamingKind(method);
|
|
146
|
+
const reqFields = shapeFor(provided, method.request, method.requestRef);
|
|
147
|
+
const resFields = shapeFor(
|
|
148
|
+
provided,
|
|
149
|
+
method.response,
|
|
150
|
+
method.responseRef,
|
|
151
|
+
);
|
|
152
|
+
const reqDiscriminator = discriminatorFor(provided, method.request);
|
|
153
|
+
const resDiscriminator = discriminatorFor(provided, method.response);
|
|
154
|
+
|
|
155
|
+
return (
|
|
156
|
+
<li
|
|
157
|
+
key={method.name}
|
|
158
|
+
className="row rounded-none border-x-0 border-t-0 last:border-b-0"
|
|
159
|
+
>
|
|
160
|
+
<div className="min-w-0 flex-1">
|
|
161
|
+
<div className="flex flex-wrap items-center gap-x-2">
|
|
162
|
+
<Ident
|
|
163
|
+
value={id}
|
|
164
|
+
className={method.deprecated ? "line-through" : undefined}
|
|
165
|
+
/>
|
|
166
|
+
{method.http ? (
|
|
167
|
+
<span className="chip mono" title="the route this operation answers on">
|
|
168
|
+
{method.http.method} {method.http.path}
|
|
169
|
+
</span>
|
|
170
|
+
) : null}
|
|
171
|
+
{method.soap ? (
|
|
172
|
+
<span
|
|
173
|
+
className="chip mono"
|
|
174
|
+
title={method.soap.endpoint || "SOAP operation"}
|
|
175
|
+
>
|
|
176
|
+
SOAP{method.soap.version ? ` ${method.soap.version}` : ""}
|
|
177
|
+
{method.soap.action ? ` · ${method.soap.action}` : ""}
|
|
178
|
+
</span>
|
|
179
|
+
) : null}
|
|
180
|
+
{method.deprecated ? (
|
|
181
|
+
<span className="chip">deprecated</span>
|
|
182
|
+
) : null}
|
|
183
|
+
{streaming !== "unary" ? (
|
|
184
|
+
<span className="chip">{STREAM_LABEL[streaming]}</span>
|
|
185
|
+
) : null}
|
|
186
|
+
</div>
|
|
187
|
+
|
|
188
|
+
{method.request || method.response ? (
|
|
189
|
+
<p className="mono mt-0.5 flex flex-wrap items-center gap-x-1.5 text-muted">
|
|
190
|
+
<Shape
|
|
191
|
+
provided={provided}
|
|
192
|
+
label="sends"
|
|
193
|
+
name={method.request}
|
|
194
|
+
refKey={method.requestRef}
|
|
195
|
+
open={open.has(reqKey)}
|
|
196
|
+
onToggle={() => onToggle(reqKey)}
|
|
197
|
+
/>
|
|
198
|
+
<span aria-hidden>→</span>
|
|
199
|
+
<Shape
|
|
200
|
+
provided={provided}
|
|
201
|
+
label="returns"
|
|
202
|
+
name={method.response}
|
|
203
|
+
refKey={method.responseRef}
|
|
204
|
+
open={open.has(resKey)}
|
|
205
|
+
onToggle={() => onToggle(resKey)}
|
|
206
|
+
/>
|
|
207
|
+
</p>
|
|
208
|
+
) : null}
|
|
209
|
+
|
|
210
|
+
{method.doc ? (
|
|
211
|
+
<p className="mt-0.5 text-muted">{method.doc}</p>
|
|
212
|
+
) : null}
|
|
213
|
+
|
|
214
|
+
{method.soap?.faults?.length || method.soap?.headers?.length ? (
|
|
215
|
+
<p className="mono mt-0.5 text-muted">
|
|
216
|
+
{method.soap.headers?.length
|
|
217
|
+
? `headers ${method.soap.headers.join(", ")}`
|
|
218
|
+
: null}
|
|
219
|
+
{method.soap.headers?.length && method.soap.faults?.length
|
|
220
|
+
? " · "
|
|
221
|
+
: null}
|
|
222
|
+
{method.soap.faults?.length
|
|
223
|
+
? `faults ${method.soap.faults.join(", ")}`
|
|
224
|
+
: null}
|
|
225
|
+
</p>
|
|
226
|
+
) : null}
|
|
227
|
+
|
|
228
|
+
{runs?.(method)}
|
|
229
|
+
|
|
230
|
+
{open.has(reqKey) && reqFields ? (
|
|
231
|
+
<div className="mt-2">
|
|
232
|
+
<DiscriminatorRows discriminator={reqDiscriminator} />
|
|
233
|
+
<ShapeRows fields={reqFields} enums={provided.enums} />
|
|
234
|
+
</div>
|
|
235
|
+
) : null}
|
|
236
|
+
{open.has(resKey) && resFields ? (
|
|
237
|
+
<div className="mt-2">
|
|
238
|
+
<DiscriminatorRows discriminator={resDiscriminator} />
|
|
239
|
+
<ShapeRows fields={resFields} enums={provided.enums} />
|
|
240
|
+
</div>
|
|
241
|
+
) : null}
|
|
242
|
+
</div>
|
|
243
|
+
<RowActions copy={id} />
|
|
244
|
+
</li>
|
|
245
|
+
);
|
|
246
|
+
})}
|
|
247
|
+
</ul>
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* The messages an interface moves, collapsed.
|
|
253
|
+
*
|
|
254
|
+
* Extracted from the service page so the module page lists them identically.
|
|
255
|
+
* Collapsed by default for the reason the service page always had: the question
|
|
256
|
+
* a reader opens with is "what can I call", and a page that opens with six
|
|
257
|
+
* schemas answers a question nobody asked yet.
|
|
258
|
+
*/
|
|
259
|
+
export function MessageList({
|
|
260
|
+
provided,
|
|
261
|
+
open,
|
|
262
|
+
onToggle,
|
|
263
|
+
}: {
|
|
264
|
+
provided: RpcService;
|
|
265
|
+
open: ReadonlySet<string>;
|
|
266
|
+
onToggle: (key: string) => void;
|
|
267
|
+
}) {
|
|
268
|
+
if (!provided.messages?.length) return null;
|
|
269
|
+
|
|
270
|
+
return (
|
|
271
|
+
<div className="border-t border-line">
|
|
272
|
+
<div className="mono px-3 py-1 text-muted">
|
|
273
|
+
<span className="tnum">{provided.messages.length}</span> message
|
|
274
|
+
{provided.messages.length === 1 ? "" : "s"}
|
|
275
|
+
</div>
|
|
276
|
+
{provided.messages.map((message) => {
|
|
277
|
+
const id = `${provided.id}/${message.name}`;
|
|
278
|
+
const shown = open.has(id);
|
|
279
|
+
|
|
280
|
+
return (
|
|
281
|
+
<div key={id} className="border-t border-line last:border-b-0">
|
|
282
|
+
<button
|
|
283
|
+
type="button"
|
|
284
|
+
onClick={() => onToggle(id)}
|
|
285
|
+
aria-expanded={shown}
|
|
286
|
+
className="mono flex w-full items-center gap-1.5 px-3 py-1.5 text-left"
|
|
287
|
+
>
|
|
288
|
+
{shown ? (
|
|
289
|
+
<ChevronDown size={11} aria-hidden className="text-muted" />
|
|
290
|
+
) : (
|
|
291
|
+
<ChevronRight size={11} aria-hidden className="text-muted" />
|
|
292
|
+
)}
|
|
293
|
+
<span className="truncate">{message.name}</span>
|
|
294
|
+
<span className="tnum ml-auto text-muted">
|
|
295
|
+
{message.fields.length}
|
|
296
|
+
</span>
|
|
297
|
+
</button>
|
|
298
|
+
{shown ? (
|
|
299
|
+
<div className="px-3 pb-3">
|
|
300
|
+
<DiscriminatorRows discriminator={message.discriminator} />
|
|
301
|
+
<ShapeRows fields={message.fields} enums={provided.enums} />
|
|
302
|
+
</div>
|
|
303
|
+
) : null}
|
|
304
|
+
</div>
|
|
305
|
+
);
|
|
306
|
+
})}
|
|
307
|
+
</div>
|
|
308
|
+
);
|
|
309
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// The two shapes anything in this app can take when it covers the page.
|
|
2
|
+
//
|
|
3
|
+
// There were four hand-rolled overlays before this file: the palette, the
|
|
4
|
+
// shortcuts sheet, the catalog drawer and the detail sheet. All four wrote the
|
|
5
|
+
// same fixed box, the same 45% scrim, the same "mousedown on the scrim closes
|
|
6
|
+
// me", and each one had a different half of a modal's real job. None trapped
|
|
7
|
+
// focus, so Tab walked out of the palette into the page behind it; none gave
|
|
8
|
+
// focus back to whatever opened them; two listened for Escape on `window` with
|
|
9
|
+
// capture and two did not.
|
|
10
|
+
//
|
|
11
|
+
// So the behaviour is Headless UI's Dialog - focus trap, focus restore, scroll
|
|
12
|
+
// lock, `aria-modal`, outside click, Escape - and what is left here is the two
|
|
13
|
+
// paints this app actually has: a MODAL, which arrives in the middle and is
|
|
14
|
+
// about a task, and a SIDE PANEL, which arrives from an edge and is a pane that
|
|
15
|
+
// ran out of room to be one.
|
|
16
|
+
//
|
|
17
|
+
// Both leave the way they came. Headless UI unmounts a closed Dialog on the
|
|
18
|
+
// spot, so the exit is Motion's: `static` hands the mounting to us, an
|
|
19
|
+
// <AnimatePresence> keeps the node alive for the exit, and the backdrop and
|
|
20
|
+
// panel are `m.div`s wearing the presets from lib/motion - the scrim fades,
|
|
21
|
+
// the modal shrinks its two percent, the side panel slides back off its edge.
|
|
22
|
+
//
|
|
23
|
+
// Escape closes, and Headless UI marks the event handled. That matters: the
|
|
24
|
+
// shell clears the catalog selection on an unhandled Escape, and a reader
|
|
25
|
+
// dismissing a sheet was closing a sheet, not deselecting anything.
|
|
26
|
+
|
|
27
|
+
import { Dialog, DialogBackdrop, DialogPanel } from "@headlessui/react";
|
|
28
|
+
import type { ReactNode } from "react";
|
|
29
|
+
import { AnimatePresence, fade, m, scaleIn, slideFrom } from "../lib/motion";
|
|
30
|
+
|
|
31
|
+
const SCRIM = "color-mix(in srgb, #000 45%, transparent)";
|
|
32
|
+
|
|
33
|
+
export function Modal({
|
|
34
|
+
open,
|
|
35
|
+
onClose,
|
|
36
|
+
label,
|
|
37
|
+
children,
|
|
38
|
+
width = "min(680px,92vw)",
|
|
39
|
+
}: {
|
|
40
|
+
open: boolean;
|
|
41
|
+
onClose: () => void;
|
|
42
|
+
/** Accessible name for the dialog. */
|
|
43
|
+
label: string;
|
|
44
|
+
children: ReactNode;
|
|
45
|
+
/** Any CSS width; the default is the palette's. */
|
|
46
|
+
width?: string;
|
|
47
|
+
}) {
|
|
48
|
+
return (
|
|
49
|
+
<AnimatePresence>
|
|
50
|
+
{open && (
|
|
51
|
+
<Dialog static open={open} onClose={onClose} className="relative z-50">
|
|
52
|
+
<DialogBackdrop
|
|
53
|
+
as={m.div}
|
|
54
|
+
{...fade}
|
|
55
|
+
className="fixed inset-0"
|
|
56
|
+
style={{ background: SCRIM }}
|
|
57
|
+
/>
|
|
58
|
+
{/* The scrim is a sibling of the panel and both are fixed, so the
|
|
59
|
+
click that lands outside the panel lands on this box - which is
|
|
60
|
+
what Headless UI watches to close. */}
|
|
61
|
+
<div className="fixed inset-0 flex items-start justify-center pt-[12vh]">
|
|
62
|
+
<DialogPanel
|
|
63
|
+
as={m.div}
|
|
64
|
+
{...scaleIn}
|
|
65
|
+
aria-label={label}
|
|
66
|
+
className="flex max-h-[70vh] flex-col overflow-hidden rounded-modal border bg-canvas border-line-strong shadow-md"
|
|
67
|
+
style={{ width }}
|
|
68
|
+
>
|
|
69
|
+
{children}
|
|
70
|
+
</DialogPanel>
|
|
71
|
+
</div>
|
|
72
|
+
</Dialog>
|
|
73
|
+
)}
|
|
74
|
+
</AnimatePresence>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function SidePanel({
|
|
79
|
+
open,
|
|
80
|
+
onClose,
|
|
81
|
+
side,
|
|
82
|
+
label,
|
|
83
|
+
children,
|
|
84
|
+
width,
|
|
85
|
+
}: {
|
|
86
|
+
open: boolean;
|
|
87
|
+
onClose: () => void;
|
|
88
|
+
side: "left" | "right";
|
|
89
|
+
label: string;
|
|
90
|
+
children: ReactNode;
|
|
91
|
+
/** Any CSS width. */
|
|
92
|
+
width: string;
|
|
93
|
+
}) {
|
|
94
|
+
const left = side === "left";
|
|
95
|
+
return (
|
|
96
|
+
<AnimatePresence>
|
|
97
|
+
{open && (
|
|
98
|
+
<Dialog static open={open} onClose={onClose} className="relative z-40">
|
|
99
|
+
<DialogBackdrop
|
|
100
|
+
as={m.div}
|
|
101
|
+
{...fade}
|
|
102
|
+
className="fixed inset-0"
|
|
103
|
+
style={{ background: SCRIM }}
|
|
104
|
+
/>
|
|
105
|
+
<div
|
|
106
|
+
className={`fixed inset-0 flex ${left ? "justify-start" : "justify-end"}`}
|
|
107
|
+
>
|
|
108
|
+
{/* Arrives from the edge it belongs to, at the panel duration, and
|
|
109
|
+
leaves by the same edge: it is a panel, it has just run out of
|
|
110
|
+
room to be one. */}
|
|
111
|
+
<DialogPanel
|
|
112
|
+
as={m.div}
|
|
113
|
+
{...slideFrom(left ? "-100%" : "100%")}
|
|
114
|
+
aria-label={label}
|
|
115
|
+
className={`${left ? "bg-canvas " : ""}h-full shadow-md`}
|
|
116
|
+
style={{ width }}
|
|
117
|
+
>
|
|
118
|
+
{children}
|
|
119
|
+
</DialogPanel>
|
|
120
|
+
</div>
|
|
121
|
+
</Dialog>
|
|
122
|
+
)}
|
|
123
|
+
</AnimatePresence>
|
|
124
|
+
);
|
|
125
|
+
}
|