diff --git a/README.md b/README.md index 8aea1923..4e6f08b1 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ # solid-panes - A set of core solid-compatible applets based on solid-ui These are a set of interlinked applications, or parts of applications, @@ -115,8 +114,11 @@ I want the menu to have a tiny button on the bottom margin left with an arrow to * Raprot mini: instead of this code (index.ts of footer), I want to make use of a new footer web component with the readme: # solid-ui-footer component -* Raptor mini: The footer created shoudl actually be part of the left side menu only. Should be displayed inside it and should collaps and expand as the menu. +* Raptor mini: The footer created should actually be part of the left side menu only. Should be displayed inside it and should collaps and expand as the menu. * Raptor mini: the footer should completely dissapear when menu folded up. * Raptor mini: Please always keep the footer at the bottom of the menu + +* GPT-5.4 Model: Add a compatibility shim in the form pane for mixed `ui:Group` plus field typing. + diff --git a/dev/dev-mash-utilities.css b/dev/dev-mash-utilities.css index 96036e6b..fae3b9b7 100644 --- a/dev/dev-mash-utilities.css +++ b/dev/dev-mash-utilities.css @@ -23,6 +23,29 @@ border: 0; } +.loading-spinner { + display: inline-block; + width: 1.25rem; + height: 1.25rem; + border: 0.15rem solid color-mix(in srgb, var(--slate-300, #CBD5E1) 85%, transparent); + border-top-color: var(--color-primary, #7C4DFF); + border-radius: 50%; + animation: loading-spinner-rotate 0.8s linear infinite; +} + +@keyframes loading-spinner-rotate { + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: reduce) { + .loading-spinner { + animation: none; + border-top-color: color-mix(in srgb, var(--color-primary, #7C4DFF) 70%, var(--slate-300, #CBD5E1)); + } +} + /* Visually hidden but can become visible on focus */ .visually-hidden { position: absolute !important; diff --git a/dev/dev-mash.css b/dev/dev-mash.css index 0169a71e..5da8bc02 100644 --- a/dev/dev-mash.css +++ b/dev/dev-mash.css @@ -682,10 +682,6 @@ div.exceptionPane pre { display: none; } -.active { - /* display: visible; */ -} - .submitRow { clear: both; height: 5em; @@ -704,119 +700,17 @@ div.exceptionPane pre { display: inline; } -/******************* CV Pane *****************/ - -.CVclass { - background-color: var(--color-cv-pane-bg); -} - -/******************* Data Content Pane *****************/ - -div.dataContentPane { - border-top: solid 1px var(--color-data-pane-border-top); - border-left: solid 1px var(--color-data-pane-border-top); - border-bottom: solid 1px var(--color-data-pane-border-side); - border-right: solid 1px var(--color-data-pane-border-side); - padding: 0.5em; /* color: #404; */ - margin-top: 0.5em; - margin-bottom: 0.5em; -} - -.nestedFormula { - border-top: solid 1px var(--color-data-pane-border-top); - border-left: solid 1px var(--color-data-pane-border-top); - border-bottom: solid 1px var(--color-data-pane-border-side); - border-right: solid 1px var(--color-data-pane-border-side); - padding: 0.5em; - border-radius: 0.5em; -} - -div.dataContentPane td { - padding-left: 0.2em; - padding-top: 0.1em; - padding-right: 0.2em; - padding-bottom: 0.05em; - /* vertical-align: middle; /*@@ Lalana's request*/ - vertical-align: top; /*@@ Tims's request*/ - /* With middel, you can't tell what is with what */ - /* background-color: white; */ -} - -div.dataContentPane tr { - margin-bottom: 0.6em; - padding-top: 1em; - padding-bottom: 1em; -} - -.dataContentPane a { - color: var(--color-text-link); - text-decoration: none; - font-weight: bold; -} -.dataContentPane a:link { - color: var(--color-text-link); - text-decoration: none; - font-weight: bold; -} -.dataContentPane a:visited { - color: var(--color-text-link-visited); - text-decoration: none; - font-weight: bold; -} -.dataContentPane a:hover { - color: var(--color-text-link-hover); - text-decoration: underline; - font-weight: bold; -} -.dataContentPane a:active { - color: var(--color-text-link-active); - text-decoration: none; -} - -.dataContentPane.embeddedText { - white-space: pre-wrap; -} - -/* div.dataContentPane a { text-decoration: none; color: #006} /* Only very slightly blue */ -div.dataContentPane td.pred { - min-width: 12em; -} /* Keep aligned with others better */ div.dataContentPane td.pred a { color: var(--color-text-muted); } /* Greyish as form field names have less info value */ /* .collectionAsTables {border-right: green 1px; margin: 0.2em;} */ -div.n3Pane { - padding: 1em; - border-top: solid 1px var(--color-data-pane-border-top); - border-left: solid 1px var(--color-data-pane-border-top); - border-bottom: solid 1px var(--color-data-pane-border-side); - border-right: solid 1px var(--color-data-pane-border-side); - color: var(--color-text-blue); -} - .imageView { border: 1em var(--color-background); margin: 1em; } -.n3Pane pre { - font-size: 120%; -} - -.RDFXMLPane pre { - font-size: 120%; -} - -div.RDFXMLPane { - padding: 1em; - border-top: solid 2px var(--color-data-pane-border-top); - border-left: solid 2px var(--color-data-pane-border-top); - border-bottom: solid 2px var(--color-data-pane-border-side); - border-right: solid 2px var(--color-data-pane-border-side); - color: var(--color-text-brown); -} /* Generic things useful anywhere */ @@ -1685,28 +1579,6 @@ button:disabled, [role="button"][aria-disabled="true"] { cursor: not-allowed; pointer-events: none; } - -/* Loading indicator accessibility */ -.loading-spinner { - width: 40px; - height: 40px; - border: 3px solid var(--color-border-pale); - border-top: 3px solid var(--color-primary); - border-radius: 50%; - animation: spin 1s linear infinite; -} - -@keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - -@media (prefers-reduced-motion: reduce) { - .loading-spinner { - animation: none; - border-top-color: var(--color-primary); - } -} /* copied from profile-pane */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { diff --git a/dev/loader.ts b/dev/loader.ts index 71984bfc..6636a2f5 100644 --- a/dev/loader.ts +++ b/dev/loader.ts @@ -128,7 +128,8 @@ function createIconElement (Pane: { icon: string }) { window.onload = async () => { console.log('document ready') // registerPanes((cjsOrEsModule: any) => paneRegistry.register(cjsOrEsModule.default || cjsOrEsModule)) - paneRegistry.register(require('contacts-pane')) + const contactsPane = await import('contacts-pane') + paneRegistry.register((contactsPane as any).default || contactsPane) await authSession.handleIncomingRedirect({ restorePreviousSession: true }) diff --git a/package-lock.json b/package-lock.json index eedd24a7..571f2e2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "solid-panes", - "version": "4.4.0", + "version": "4.4.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "solid-panes", - "version": "4.4.0", + "version": "4.4.1", "license": "MIT", "dependencies": { "@solid/better-simple-slideshow": "^0.1.0", @@ -16,13 +16,14 @@ "dompurify": "^3.4.4", "folder-pane": "^3.1.0", "issue-pane": "^3.0.2", + "lit-html": "^3.3.2", "marked": "^18.0.3", "meeting-pane": "^3.0.2", "mime-types": "^3.0.2", "pane-registry": "^3.1.1", - "profile-pane": "^3.2.1", + "profile-pane": "^3.2.2", "solid-namespace": "^0.5.4", - "solid-ui": "^3.1.0", + "solid-ui": "^3.1.1", "source-pane": "^3.1.0" }, "devDependencies": { @@ -53,7 +54,7 @@ "node-polyfill-webpack-plugin": "^4.1.0", "path-browserify": "^1.0.1", "raw-loader": "^4.0.2", - "rdflib": "^2.3.8", + "rdflib": "^2.3.9", "react": "^19.2.6", "react-dom": "^19.2.6", "solid-logic": "^4.0.7", @@ -68,9 +69,9 @@ } }, "node_modules/@adobe/css-tools": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", - "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.5.0.tgz", + "integrity": "sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==", "dev": true, "license": "MIT" }, @@ -96,9 +97,9 @@ "license": "ISC" }, "node_modules/@babel/cli": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.28.6.tgz", - "integrity": "sha512-6EUNcuBbNkj08Oj4gAZ+BUU8yLCgKzgVX4gaTh09Ya2C8ICM4P+G30g4m3akRxSYAp3A/gnWchrNst7px4/nUQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.29.7.tgz", + "integrity": "sha512-/75HwRbAYPqXv/Ax1h7Fg3IZfXgdU98jnA8H93/m/QBaPV3Hp5ICoLqzGYye1yHBCgpmXvtqgSUN8oOKX5tojQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1873,9 +1874,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", - "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -2188,9 +2189,9 @@ "license": "MIT" }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -2276,9 +2277,9 @@ "license": "MIT" }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -2749,19 +2750,6 @@ } } }, - "node_modules/@jest/core/node_modules/@jest/schemas": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", - "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.34.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, "node_modules/@jest/core/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -2991,9 +2979,9 @@ "license": "MIT" }, "node_modules/@jest/reporters/node_modules/brace-expansion": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", - "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", "dev": true, "license": "MIT", "dependencies": { @@ -3049,9 +3037,9 @@ } }, "node_modules/@jest/schemas": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", - "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", + "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", "dev": true, "license": "MIT", "dependencies": { @@ -3189,19 +3177,6 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/types/node_modules/@jest/schemas": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", - "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.34.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -3701,9 +3676,9 @@ "license": "MIT" }, "node_modules/@lit-labs/ssr-dom-shim": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.5.1.tgz", - "integrity": "sha512-Aou5UdlSpr5whQe8AA/bZG0jMj96CoJIWbGfZ91qieWu5AWUMKw8VR/pAkQkJYvBNhmCcWnZlyyk5oze8JIqYA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.6.0.tgz", + "integrity": "sha512-VHb0ALPMTlgKjM6yIxxoQNnpKyUKLD04VzeQdsiXkMqkvYlAHxq9glGLmgbb889/1GsohSOAjvQYoiBppXFqrQ==", "license": "BSD-3-Clause" }, "node_modules/@lit/reactive-element": { @@ -3716,16 +3691,22 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", - "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.10.0" + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" } }, "node_modules/@nicolo-ribaudo/chokidar-2": { @@ -3751,7 +3732,7 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@noble/hashes": { + "node_modules/@noble/curves/node_modules/@noble/hashes": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", @@ -3763,142 +3744,165 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@peculiar/asn1-cms": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.6.1.tgz", - "integrity": "sha512-vdG4fBF6Lkirkcl53q6eOdn3XYKt+kJTG59edgRZORlg/3atWWEReRCx5rYE1ZzTTX6vLK5zDMjHh7vbrcXGtw==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.7.0.tgz", + "integrity": "sha512-hew63shtzzvBcSHbhm+cyAmKe6AIfinT9hzEqSPjDC6opTTMKmTkQ0gHuN2KsWlvqiKw1S/fS94fhag/FJkioQ==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", - "@peculiar/asn1-x509-attr": "^2.6.1", + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", + "@peculiar/asn1-x509-attr": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-csr": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.6.1.tgz", - "integrity": "sha512-WRWnKfIocHyzFYQTka8O/tXCiBquAPSrRjXbOkHbO4qdmS6loffCEGs+rby6WxxGdJCuunnhS2duHURhjyio6w==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.7.0.tgz", + "integrity": "sha512-VVsAyGqErT9D1SY4aEqozThXMVI+ssVRiv2DDeYuvpBKLIgZ3hYs3Ay3u/VSoKq6ESFi9cf6rf3IOOzfwh7oMA==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-ecc": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.6.1.tgz", - "integrity": "sha512-+Vqw8WFxrtDIN5ehUdvlN2m73exS2JVG0UAyfVB31gIfor3zWEAQPD+K9ydCxaj3MLen9k0JhKpu9LqviuCE1g==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.7.0.tgz", + "integrity": "sha512-n7KEs/Q/wrB415cxy4fHOBhegp4NdJ15fkJPwcB/3/8iNBQC2L/N7SChJPKDJPZGYH0jD4Tg4/0vnHmwghnbKw==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-pfx": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.6.1.tgz", - "integrity": "sha512-nB5jVQy3MAAWvq0KY0R2JUZG8bO/bTLpnwyOzXyEh/e54ynGTatAR+csOnXkkVD9AFZ2uL8Z7EV918+qB1qDvw==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.7.0.tgz", + "integrity": "sha512-V/nrlQVmhg7lYAsM7E13UDL5erAwFv6kCIVFqNaMIHSVi7dngcT839JkRTkQBqznMG98l2XjxYk74ZztAohZzA==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-cms": "^2.6.1", - "@peculiar/asn1-pkcs8": "^2.6.1", - "@peculiar/asn1-rsa": "^2.6.1", - "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-cms": "^2.7.0", + "@peculiar/asn1-pkcs8": "^2.7.0", + "@peculiar/asn1-rsa": "^2.7.0", + "@peculiar/asn1-schema": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-pkcs8": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.6.1.tgz", - "integrity": "sha512-JB5iQ9Izn5yGMw3ZG4Nw3Xn/hb/G38GYF3lf7WmJb8JZUydhVGEjK/ZlFSWhnlB7K/4oqEs8HnfFIKklhR58Tw==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.7.0.tgz", + "integrity": "sha512-9GTl1nE8Mx1kTZ+7QyYatDyKsm34QcWRBFkY1iPvWC3X4Dona5s/tlLiQsx5WzVdZqiMBZNYT0buyw4/vbhnjw==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-pkcs9": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.6.1.tgz", - "integrity": "sha512-5EV8nZoMSxeWmcxWmmcolg22ojZRgJg+Y9MX2fnE2bGRo5KQLqV5IL9kdSQDZxlHz95tHvIq9F//bvL1OeNILw==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.7.0.tgz", + "integrity": "sha512-Bh7m+OuIaSEllPQcSd9OSp93F4ROWH7sbITWV8MI+8dwsjE5111/87VxiWVvYFKyww3vp39geLv9ENqhwWHcew==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-cms": "^2.6.1", - "@peculiar/asn1-pfx": "^2.6.1", - "@peculiar/asn1-pkcs8": "^2.6.1", - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", - "@peculiar/asn1-x509-attr": "^2.6.1", + "@peculiar/asn1-cms": "^2.7.0", + "@peculiar/asn1-pfx": "^2.7.0", + "@peculiar/asn1-pkcs8": "^2.7.0", + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", + "@peculiar/asn1-x509-attr": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-rsa": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.6.1.tgz", - "integrity": "sha512-1nVMEh46SElUt5CB3RUTV4EG/z7iYc7EoaDY5ECwganibQPkZ/Y2eMsTKB/LeyrUJ+W/tKoD9WUqIy8vB+CEdA==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.7.0.tgz", + "integrity": "sha512-/qvENQrXyTZURjMqSeofHul0JJt2sNSzSwk36pl2olkHbaioMQgrASDZAlHXl0xUlnVbHj0uGgOrBMTb5x2aJQ==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-schema": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.6.0.tgz", - "integrity": "sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.7.0.tgz", + "integrity": "sha512-W8ZfWzLmQnrcky+eh3tni4IozMdqBDiHWU0N+vve/UGjMaUs8c0L7A2oEdkBXS8rTpWDpK/aoI3DG/L/hxmxPg==", "dev": true, "license": "MIT", "dependencies": { + "@peculiar/utils": "^2.0.2", "asn1js": "^3.0.6", - "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-x509": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.6.1.tgz", - "integrity": "sha512-O9jT5F1A2+t3r7C4VT7LYGXqkGLK7Kj1xFpz7U0isPrubwU5PbDoyYtx6MiGst29yq7pXN5vZbQFKRCP+lLZlA==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.7.0.tgz", + "integrity": "sha512-mUn9RRrkGDnG4ALfunDmzyRW5dg+sWCj/pfnCCqEHYbkGxEpvUt6iVJv8Yw1cyp6SWZ26ZE5oSmI5SqEaen15g==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/utils": "^2.0.2", "asn1js": "^3.0.6", - "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-x509-attr": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.6.1.tgz", - "integrity": "sha512-tlW6cxoHwgcQghnJwv3YS+9OO1737zgPogZ+CgWRUK4roEwIPzRH4JEiG770xe5HX2ATfCpmX60gurfWIF9dcQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.7.0.tgz", + "integrity": "sha512-NS8e7SOgXipkzUPLF/sce7ukpMpWjhxYsH0n6Y+bHYo4TTxOb95Zv7hqwSuL212mj5YxovjdOKQOgH1As3E94w==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, + "node_modules/@peculiar/utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@peculiar/utils/-/utils-2.0.3.tgz", + "integrity": "sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, "node_modules/@peculiar/x509": { "version": "1.14.3", "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.3.tgz", @@ -3982,6 +3986,30 @@ "@sinonjs/commons": "^3.0.1" } }, + "node_modules/@solid-data-modules/contacts-rdflib": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@solid-data-modules/contacts-rdflib/-/contacts-rdflib-0.7.1.tgz", + "integrity": "sha512-jjSVCyXjOdMlPEdTysboLg1Tc8E3jDFlbEIv7mjnNkFK61UdI/BfnNPT5XnNSUSiZYBZklUwsniJhclFhoZmBw==", + "license": "MIT", + "dependencies": { + "@solid-data-modules/rdflib-utils": "^0.2.0" + }, + "peerDependencies": { + "rdflib": "2.x" + } + }, + "node_modules/@solid-data-modules/rdflib-utils": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@solid-data-modules/rdflib-utils/-/rdflib-utils-0.2.0.tgz", + "integrity": "sha512-WXpyiMmgmeeTHUz/jFGGBy02GxClxT2uew3eUWh/XOQQQeOxlzYFRO0tOa3Nv9/3Y1qcAyS7tSaW5x42Q8WPLQ==", + "license": "MIT", + "dependencies": { + "short-unique-id": "^5.2.0" + }, + "peerDependencies": { + "rdflib": "2.x" + } + }, "node_modules/@solid/better-simple-slideshow": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@solid/better-simple-slideshow/-/better-simple-slideshow-0.1.0.tgz", @@ -4186,9 +4214,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "dev": true, "license": "MIT" }, @@ -4294,27 +4322,21 @@ } }, "node_modules/@types/jest/node_modules/pretty-format": { - "version": "30.3.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.3.0.tgz", - "integrity": "sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==", + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.4.1.tgz", + "integrity": "sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/schemas": "30.0.5", + "@jest/schemas": "30.4.1", "ansi-styles": "^5.2.0", - "react-is": "^18.3.1" + "react-is-18": "npm:react-is@^18.3.1", + "react-is-19": "npm:react-is@^19.2.5" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@types/jest/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/jsdom": { "version": "21.1.7", "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.7.tgz", @@ -4342,18 +4364,18 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.6.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", - "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", + "version": "25.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", + "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", "license": "MIT", "dependencies": { - "undici-types": "~7.19.0" + "undici-types": ">=7.24.0 <7.24.7" } }, "node_modules/@types/qs": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.0.tgz", - "integrity": "sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==", + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", "dev": true, "license": "MIT" }, @@ -4479,17 +4501,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.58.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.2.tgz", - "integrity": "sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw==", + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.60.0.tgz", + "integrity": "sha512-QYb/sa74/s7OKMbACMjrYnGspj9Hs5YI5aaffSL65UfeBUzVzBJfVo3oWSpbzPurvm7yaCCo2Lk7lVj610HqKw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.58.2", - "@typescript-eslint/type-utils": "8.58.2", - "@typescript-eslint/utils": "8.58.2", - "@typescript-eslint/visitor-keys": "8.58.2", + "@typescript-eslint/scope-manager": "8.60.0", + "@typescript-eslint/type-utils": "8.60.0", + "@typescript-eslint/utils": "8.60.0", + "@typescript-eslint/visitor-keys": "8.60.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -4502,7 +4524,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.58.2", + "@typescript-eslint/parser": "^8.60.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } @@ -4542,7 +4564,7 @@ "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/project-service": { + "node_modules/@typescript-eslint/project-service": { "version": "8.60.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.0.tgz", "integrity": "sha512-aZu74NNKJeUWqCjDddzdiKaS82dgYgV/vmf+Ui3ZdZejmgfXR/q+pRumgobnQ2cCJTgGTWp4ypiwsuofFubavg==", @@ -4564,7 +4586,7 @@ "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "node_modules/@typescript-eslint/scope-manager": { "version": "8.60.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.0.tgz", "integrity": "sha512-pFzqhllJMs+jghLQWzV00ds39xLzuyqPSev5pd8f4Ir0rtKR3ZLUB4/4dhjOFighWb9larvtfJvqL+4yKDI3Xw==", @@ -4582,7 +4604,7 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/tsconfig-utils": { + "node_modules/@typescript-eslint/tsconfig-utils": { "version": "8.60.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.0.tgz", "integrity": "sha512-BZPR3RGYlAXnly6ymAxfkVn5rCbZzQNou0rxv3GfWZ8cTQp+hhVd73khbGLAd8k1TlAPLISH337M+tAgAnaJDQ==", @@ -4599,146 +4621,16 @@ "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "8.60.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.0.tgz", - "integrity": "sha512-AsE7x2XaAK+CVbeih0Fvbn+r1qHxtpLDJ3XUuFcIinT318T90yHMJC+Zgv+jUuDjQQd06HKwxnDu6sz1IcTilA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.60.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.0.tgz", - "integrity": "sha512-3AcZNBGMClm6CXDyo8kYvVGT/sx29sS0oBsIb9oZI2gunA4Vm2M3YHzRLPvsUBBsl+yB5FPtltq7gGH0iTlp9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.60.0", - "@typescript-eslint/tsconfig-utils": "8.60.0", - "@typescript-eslint/types": "8.60.0", - "@typescript-eslint/visitor-keys": "8.60.0", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { + "node_modules/@typescript-eslint/type-utils": { "version": "8.60.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.0.tgz", - "integrity": "sha512-9WI52t8ZGLVGrPMBet25yAftqY/n95+zmoUUtJBBQTKDSKUu7OsPTroT2op7U9JatkoRccL0YkWDNMFfC4Sjxg==", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.60.0.tgz", + "integrity": "sha512-SX46wEUtitCpq7AN38HkUU/+zvUpdKf7ephtWAFgckH8O7PQIyL5gvrhQgBLuEYgLfuKWOVvWVskMbuFHAz5xg==", "dev": true, "license": "MIT", "dependencies": { "@typescript-eslint/types": "8.60.0", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/semver": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", - "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.58.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.58.2.tgz", - "integrity": "sha512-Cq6UfpZZk15+r87BkIh5rDpi38W4b+Sjnb8wQCPPDDweS/LRCFjCyViEbzHk5Ck3f2QDfgmlxqSa7S7clDtlfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.58.2", - "@typescript-eslint/types": "^8.58.2", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.58.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.58.2.tgz", - "integrity": "sha512-SgmyvDPexWETQek+qzZnrG6844IaO02UVyOLhI4wpo82dpZJY9+6YZCKAMFzXb7qhx37mFK1QcPQ18tud+vo6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.58.2", - "@typescript-eslint/visitor-keys": "8.58.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.58.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.2.tgz", - "integrity": "sha512-3SR+RukipDvkkKp/d0jP0dyzuls3DbGmwDpVEc5wqk5f38KFThakqAAO0XMirWAE+kT00oTauTbzMFGPoAzB0A==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.58.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.58.2.tgz", - "integrity": "sha512-Z7EloNR/B389FvabdGeTo2XMs4W9TjtPiO9DAsmT0yom0bwlPyRjkJ1uCdW1DvrrrYP50AJZ9Xc3sByZA9+dcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.58.2", - "@typescript-eslint/typescript-estree": "8.58.2", - "@typescript-eslint/utils": "8.58.2", + "@typescript-eslint/typescript-estree": "8.60.0", + "@typescript-eslint/utils": "8.60.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -4755,9 +4647,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.58.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.58.2.tgz", - "integrity": "sha512-9TukXyATBQf/Jq9AMQXfvurk+G5R2MwfqQGDR2GzGz28HvY/lXNKGhkY+6IOubwcquikWk5cjlgPvD2uAA7htQ==", + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.0.tgz", + "integrity": "sha512-AsE7x2XaAK+CVbeih0Fvbn+r1qHxtpLDJ3XUuFcIinT318T90yHMJC+Zgv+jUuDjQQd06HKwxnDu6sz1IcTilA==", "dev": true, "license": "MIT", "engines": { @@ -4769,16 +4661,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.58.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.2.tgz", - "integrity": "sha512-ELGuoofuhhoCvNbQjFFiobFcGgcDCEm0ThWdmO4Z0UzLqPXS3KFvnEZ+SHewwOYHjM09tkzOWXNTv9u6Gqtyuw==", + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.0.tgz", + "integrity": "sha512-3AcZNBGMClm6CXDyo8kYvVGT/sx29sS0oBsIb9oZI2gunA4Vm2M3YHzRLPvsUBBsl+yB5FPtltq7gGH0iTlp9g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.58.2", - "@typescript-eslint/tsconfig-utils": "8.58.2", - "@typescript-eslint/types": "8.58.2", - "@typescript-eslint/visitor-keys": "8.58.2", + "@typescript-eslint/project-service": "8.60.0", + "@typescript-eslint/tsconfig-utils": "8.60.0", + "@typescript-eslint/types": "8.60.0", + "@typescript-eslint/visitor-keys": "8.60.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -4797,9 +4689,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", "dev": true, "license": "ISC", "bin": { @@ -4810,16 +4702,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.58.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.2.tgz", - "integrity": "sha512-QZfjHNEzPY8+l0+fIXMvuQ2sJlplB4zgDZvA+NmvZsZv3EQwOcc1DuIU1VJUTWZ/RKouBMhDyNaBMx4sWvrzRA==", + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.0.tgz", + "integrity": "sha512-HtXuPfrHTyBDkameWpl+vJb1Uevu2tznAyahM1Oc4AENidCLTPiZDWIo4GfcxNdC/RcfGcadzzkqbRG87dUrQA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.58.2", - "@typescript-eslint/types": "8.58.2", - "@typescript-eslint/typescript-estree": "8.58.2" + "@typescript-eslint/scope-manager": "8.60.0", + "@typescript-eslint/types": "8.60.0", + "@typescript-eslint/typescript-estree": "8.60.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4834,13 +4726,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.58.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.2.tgz", - "integrity": "sha512-f1WO2Lx8a9t8DARmcWAUPJbu0G20bJlj8L4z72K00TMeJAoyLr/tHhI/pzYBLrR4dXWkcxO1cWYZEOX8DKHTqA==", + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.0.tgz", + "integrity": "sha512-9WI52t8ZGLVGrPMBet25yAftqY/n95+zmoUUtJBBQTKDSKUu7OsPTroT2op7U9JatkoRccL0YkWDNMFfC4Sjxg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/types": "8.60.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -4859,9 +4751,9 @@ "license": "ISC" }, "node_modules/@unrs/resolver-binding-android-arm-eabi": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", - "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.12.2.tgz", + "integrity": "sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==", "cpu": [ "arm" ], @@ -4873,9 +4765,9 @@ ] }, "node_modules/@unrs/resolver-binding-android-arm64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", - "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.12.2.tgz", + "integrity": "sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==", "cpu": [ "arm64" ], @@ -4887,9 +4779,9 @@ ] }, "node_modules/@unrs/resolver-binding-darwin-arm64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", - "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.12.2.tgz", + "integrity": "sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==", "cpu": [ "arm64" ], @@ -4901,9 +4793,9 @@ ] }, "node_modules/@unrs/resolver-binding-darwin-x64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", - "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.12.2.tgz", + "integrity": "sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==", "cpu": [ "x64" ], @@ -4915,9 +4807,9 @@ ] }, "node_modules/@unrs/resolver-binding-freebsd-x64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", - "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.12.2.tgz", + "integrity": "sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==", "cpu": [ "x64" ], @@ -4929,9 +4821,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", - "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.12.2.tgz", + "integrity": "sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==", "cpu": [ "arm" ], @@ -4943,9 +4835,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", - "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.12.2.tgz", + "integrity": "sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==", "cpu": [ "arm" ], @@ -4957,9 +4849,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", - "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.12.2.tgz", + "integrity": "sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==", "cpu": [ "arm64" ], @@ -4971,9 +4863,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", - "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.12.2.tgz", + "integrity": "sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==", "cpu": [ "arm64" ], @@ -4984,10 +4876,38 @@ "linux" ] }, + "node_modules/@unrs/resolver-binding-linux-loong64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-gnu/-/resolver-binding-linux-loong64-gnu-1.12.2.tgz", + "integrity": "sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-musl/-/resolver-binding-linux-loong64-musl-1.12.2.tgz", + "integrity": "sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", - "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.12.2.tgz", + "integrity": "sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==", "cpu": [ "ppc64" ], @@ -4999,9 +4919,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", - "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.12.2.tgz", + "integrity": "sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==", "cpu": [ "riscv64" ], @@ -5013,9 +4933,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", - "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.12.2.tgz", + "integrity": "sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==", "cpu": [ "riscv64" ], @@ -5027,9 +4947,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", - "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.12.2.tgz", + "integrity": "sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==", "cpu": [ "s390x" ], @@ -5041,9 +4961,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", - "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.12.2.tgz", + "integrity": "sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==", "cpu": [ "x64" ], @@ -5055,9 +4975,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-x64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", - "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.12.2.tgz", + "integrity": "sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==", "cpu": [ "x64" ], @@ -5068,10 +4988,24 @@ "linux" ] }, + "node_modules/@unrs/resolver-binding-openharmony-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-openharmony-arm64/-/resolver-binding-openharmony-arm64-1.12.2.tgz", + "integrity": "sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, "node_modules/@unrs/resolver-binding-wasm32-wasi": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", - "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.12.2.tgz", + "integrity": "sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==", "cpu": [ "wasm32" ], @@ -5079,16 +5013,18 @@ "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.11" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", - "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz", + "integrity": "sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==", "cpu": [ "arm64" ], @@ -5100,9 +5036,9 @@ ] }, "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", - "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.12.2.tgz", + "integrity": "sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==", "cpu": [ "ia32" ], @@ -5114,9 +5050,9 @@ ] }, "node_modules/@unrs/resolver-binding-win32-x64-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", - "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.12.2.tgz", + "integrity": "sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==", "cpu": [ "x64" ], @@ -5491,9 +5427,9 @@ } }, "node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -5526,9 +5462,9 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -5811,14 +5747,14 @@ "license": "MIT" }, "node_modules/asn1js": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.7.tgz", - "integrity": "sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==", + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.10.tgz", + "integrity": "sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { "pvtsutils": "^1.3.6", - "pvutils": "^1.1.3", + "pvutils": "^1.1.5", "tslib": "^2.8.1" }, "engines": { @@ -6083,9 +6019,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.10.20", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.20.tgz", - "integrity": "sha512-1AaXxEPfXT+GvTBJFuy4yXVHWJBXa4OdbIebGN/wX5DlsIkU0+wzGnd2lOzokSk51d5LUmqjgBLRLlypLUqInQ==", + "version": "2.10.32", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.32.tgz", + "integrity": "sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -6175,9 +6111,9 @@ "license": "MIT" }, "node_modules/bonjour-service": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", - "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.4.0.tgz", + "integrity": "sha512-fGQtj1qdR9vIKjFiWPQd52qIqwjaYqhcI40JEiDuvlZ86E7ZBPBwY9fPgHy9r2rYGIjiRfctNPYz6OQU73ww2w==", "dev": true, "license": "MIT", "dependencies": { @@ -6193,9 +6129,9 @@ "license": "ISC" }, "node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, "license": "MIT", "dependencies": { @@ -6291,13 +6227,13 @@ } }, "node_modules/browserify-sign": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", - "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.6.tgz", + "integrity": "sha512-sd+Q65fjlWCYWtZKXiKfrUc8d+4jtp/8f0W2NkwzLtoW4bI6UDnWusLWIurHnmurW0XShIRxpwiOX4EoPtXUAg==", "dev": true, "license": "ISC", "dependencies": { - "bn.js": "^5.2.2", + "bn.js": "^5.2.3", "browserify-rsa": "^4.1.1", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", @@ -6587,9 +6523,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001788", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001788.tgz", - "integrity": "sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==", + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", "dev": true, "funding": [ { @@ -7236,9 +7172,9 @@ } }, "node_modules/css-loader/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", "dev": true, "license": "ISC", "bin": { @@ -7754,9 +7690,9 @@ } }, "node_modules/dompurify": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.5.tgz", - "integrity": "sha512-OrwIBKsdNSVEeubdJ1HBv/wNENRM9ytAVCv7YXt//A3vPdVMNuACRqK9mXCGCBW2ln7BT/A4X0jXHo2Gu89miA==", + "version": "3.4.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.6.tgz", + "integrity": "sha512-+7gzEI8trIIQkVCvQ3ucGtNfH3nOmDgVTzc62rAAOlMxLth78pwpPoZCPc7CyRzAQF89MqcfPdEWkDwnjgqktg==", "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" @@ -7863,9 +7799,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.340", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.340.tgz", - "integrity": "sha512-908qahOGocRMinT2nM3ajCEM99H4iPdv84eagPP3FfZy/1ZGeOy2CZYzjhms81ckOPCXPlW7LkY4XpxD8r1DrA==", + "version": "1.5.361", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.361.tgz", + "integrity": "sha512-Q6Hts7N9FnJc5LeGRINFvLhCI9xZmNtTDe5ZbcVezQz7cU4a8Aua3GH1b8J2XY8Al9PF+OCwYqhgsOOheMdvkA==", "dev": true, "license": "ISC" }, @@ -8113,9 +8049,9 @@ "license": "MIT" }, "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", "dev": true, "license": "MIT", "dependencies": { @@ -8278,9 +8214,9 @@ } }, "node_modules/eslint-compat-utils/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", "dev": true, "license": "ISC", "bin": { @@ -8353,9 +8289,9 @@ } }, "node_modules/eslint-plugin-n/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", "dev": true, "license": "ISC", "bin": { @@ -8366,9 +8302,9 @@ } }, "node_modules/eslint-plugin-promise": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-7.2.1.tgz", - "integrity": "sha512-SWKjd+EuvWkYaS+uN2csvj0KoP43YTu7+phKQ5v+xw6+A0gutVX2yqCeCkC3uLCJFiPfR2dD8Es5L7yUsmvEaA==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-7.3.0.tgz", + "integrity": "sha512-6uGiOR0INuujr6PEQmeSSP7GbIMJ/ebEXXiEzb/nOj68LknH5Pxzb/AbZivmr6VE6TkTE8rTjRK9zhKpK6HsRA==", "dev": true, "license": "ISC", "dependencies": { @@ -8381,7 +8317,7 @@ "url": "https://opencollective.com/eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0" } }, "node_modules/eslint-plugin-react": { @@ -8425,9 +8361,9 @@ "license": "MIT" }, "node_modules/eslint-plugin-react/node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -8449,14 +8385,14 @@ } }, "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.6", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.6.tgz", - "integrity": "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==", + "version": "2.0.0-next.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz", + "integrity": "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "is-core-module": "^2.16.1", + "is-core-module": "^2.16.2", "node-exports-info": "^1.6.0", "object-keys": "^1.1.1", "path-parse": "^1.0.7", @@ -8510,9 +8446,9 @@ "license": "MIT" }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -9414,9 +9350,9 @@ "license": "MIT" }, "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -9514,15 +9450,6 @@ "node": ">=0.10.0" } }, - "node_modules/got/node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/got/node_modules/is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -10046,6 +9973,19 @@ } } }, + "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/https-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", @@ -10266,9 +10206,9 @@ } }, "node_modules/ipaddr.js": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz", - "integrity": "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.4.0.tgz", + "integrity": "sha512-9VGk3HGanVE6JoZXHiCpnGy5X0jYDnN4EA4lntFPj+1vIWlFhIylq2CrrCOJH9EAhc5CYhq18F2Av2tgoAPsYQ==", "dev": true, "license": "MIT", "engines": { @@ -10396,12 +10336,12 @@ } }, "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "hasown": "^2.0.3" }, "engines": { "node": ">= 0.4" @@ -10608,9 +10548,9 @@ } }, "node_modules/is-network-error": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.1.tgz", - "integrity": "sha512-6QCxa49rQbmUWLfk0nuGqzql9U8uaV2H6279bRErPBHe/109hCzsLUBUHfbEtvLIHBd6hyXbgedBSHevm43Edw==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.2.tgz", + "integrity": "sha512-PhBY86zaxNZUuWP6h13Vu5oFe0XY6/UlKzQnYFELzGVHygP3MxmvTfYSG7GN3aIab/iWudSMgjSnG9Dq+nHrgA==", "dev": true, "license": "MIT", "engines": { @@ -10648,16 +10588,12 @@ } }, "node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "dev": true, + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, "node_modules/is-plain-object": { @@ -10957,9 +10893,9 @@ } }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", "dev": true, "license": "ISC", "bin": { @@ -11001,9 +10937,9 @@ } }, "node_modules/istanbul-lib-report/node_modules/semver": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", - "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", "dev": true, "license": "ISC", "bin": { @@ -11156,19 +11092,6 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-circus/node_modules/@jest/schemas": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", - "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.34.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, "node_modules/jest-circus/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -11292,19 +11215,6 @@ } } }, - "node_modules/jest-config/node_modules/@jest/schemas": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", - "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.34.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, "node_modules/jest-config/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -11326,9 +11236,9 @@ "license": "MIT" }, "node_modules/jest-config/node_modules/brace-expansion": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", - "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", "dev": true, "license": "MIT", "dependencies": { @@ -11415,19 +11325,6 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-diff/node_modules/@jest/schemas": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", - "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.34.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, "node_modules/jest-diff/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -11487,19 +11384,6 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-each/node_modules/@jest/schemas": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", - "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.34.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, "node_modules/jest-each/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -11634,19 +11518,6 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-leak-detector/node_modules/@jest/schemas": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", - "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.34.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, "node_modules/jest-leak-detector/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -11692,19 +11563,6 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-matcher-utils/node_modules/@jest/schemas": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", - "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.34.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, "node_modules/jest-matcher-utils/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -11756,19 +11614,6 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-message-util/node_modules/@jest/schemas": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", - "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.34.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, "node_modules/jest-message-util/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -11984,9 +11829,9 @@ "license": "MIT" }, "node_modules/jest-runtime/node_modules/brace-expansion": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", - "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", "dev": true, "license": "MIT", "dependencies": { @@ -12074,19 +11919,6 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-snapshot/node_modules/@jest/schemas": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", - "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.34.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, "node_modules/jest-snapshot/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -12117,9 +11949,9 @@ } }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", - "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", "dev": true, "license": "ISC", "bin": { @@ -12178,19 +12010,6 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-validate/node_modules/@jest/schemas": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", - "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.34.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, "node_modules/jest-validate/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -12717,9 +12536,9 @@ "license": "MIT" }, "node_modules/lit": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/lit/-/lit-3.3.2.tgz", - "integrity": "sha512-NF9zbsP79l4ao2SNrH3NkfmFgN/hBYSQo90saIVI1o5GpjAdCPVstVzO1MrLOakHoEhYkrtRjPK6Ob521aoYWQ==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.3.3.tgz", + "integrity": "sha512-fycuvZg/hkpozL00lm1pEJH5nN/lr9ZXd6mJI2HSN4+Bzc+LDNdEApJ6HFbPkdFNHLvOplIIuJvxkS4XUxqirw==", "license": "BSD-3-Clause", "dependencies": { "@lit/reactive-element": "^2.1.0", @@ -12739,9 +12558,9 @@ } }, "node_modules/lit-html": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.2.tgz", - "integrity": "sha512-Qy9hU88zcmaxBXcc10ZpdK7cOLXvXpRoBxERdtqV9QOrfpMZZ6pSYP91LhpPtap3sFMUiL7Tw2RImbe0Al2/kw==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.3.tgz", + "integrity": "sha512-el8M6jK2o3RXBnrSHX3ZKrsN8zEV63pSExTO1wYJz7QndGYZ8353e2a5PPX+qHe2aGayfnchQmkAojaWAREOIA==", "license": "BSD-3-Clause", "dependencies": { "@types/trusted-types": "^2.0.2" @@ -13217,9 +13036,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", "dev": true, "funding": [ { @@ -13490,11 +13309,14 @@ } }, "node_modules/node-releases": { - "version": "2.0.37", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", - "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", + "version": "2.0.46", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz", + "integrity": "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/node-status-codes": { "version": "1.0.0", @@ -14444,19 +14266,6 @@ "node": ">=16.0.0" } }, - "node_modules/pkijs/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/pngjs": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", @@ -14477,9 +14286,9 @@ } }, "node_modules/postcss": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", - "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "dev": true, "funding": [ { @@ -14497,7 +14306,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -14663,20 +14472,21 @@ "license": "MIT" }, "node_modules/profile-pane": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/profile-pane/-/profile-pane-3.2.1.tgz", - "integrity": "sha512-8dvNWU5IZEL1lDtPJERPJaxzbZuknZARwE9WZiqUR+Pa6k5CFoKdusPS7s4id6QSrAdU9y/XJ72xKX5WiEbmaA==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/profile-pane/-/profile-pane-3.2.2.tgz", + "integrity": "sha512-3Uswk6wOIaL3jG2lfm5npbBR7+UNQtieewCArH1IKOb12vK3/93GUomLFnpxE9nRe+MbRmwMxk1TNoAeZU8kHg==", "license": "MIT", "dependencies": { - "lit-html": "^3.3.2", - "pane-registry": "^3.1.0", + "@solid-data-modules/contacts-rdflib": "^0.7.1", + "lit-html": "^3.3.3", + "pane-registry": "^3.1.1", "qrcode": "^1.5.4", "validate-color": "^2.2.4" }, "peerDependencies": { "rdflib": "^2.3.6", "solid-logic": "^4.0.6", - "solid-ui": "^3.1.0" + "solid-ui": "^3.1.1" } }, "node_modules/promise-polyfill": { @@ -15102,9 +14912,9 @@ } }, "node_modules/rdflib": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/rdflib/-/rdflib-2.3.8.tgz", - "integrity": "sha512-moogxjqUHqZt+l6qbb0xZm7Cy+iwBwHhBev0N8/zkrCX+Q1iuMLrflUNxbeJO/f5E0XZ7AhyJjPrQkB9smYqIA==", + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/rdflib/-/rdflib-2.3.9.tgz", + "integrity": "sha512-6HnEQ22QzgqPW2/R8y5IaeQoXnho6U+ovU1q/ZF556zEnSK4buwhw8/CDdRDwIHZQh5+PAncQxUhluO3JmguJQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.29.2", @@ -15673,15 +15483,15 @@ } }, "node_modules/safe-array-concat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", - "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", "has-symbols": "^1.1.0", "isarray": "^2.0.5" }, @@ -15794,9 +15604,9 @@ } }, "node_modules/schema-utils/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -16173,6 +15983,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/short-unique-id": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/short-unique-id/-/short-unique-id-5.3.2.tgz", + "integrity": "sha512-KRT/hufMSxXKEDSQujfVE0Faa/kZ51ihUcZQAcmP04t00DvPj7Ox5anHke1sJYUtzSuiT/Y5uyzg/W7bBEGhCg==", + "license": "Apache-2.0", + "bin": { + "short-unique-id": "bin/short-unique-id", + "suid": "bin/short-unique-id" + } + }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -16289,6 +16109,7 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", "dev": true, "license": "MIT", "bin": { @@ -16318,32 +16139,44 @@ "license": "MIT" }, "node_modules/solid-ui": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/solid-ui/-/solid-ui-3.1.0.tgz", - "integrity": "sha512-IKNooyEcJ3IduJqGCw24UC0xPpCCQZVFXzlPC8jcicO7R2FM9GHgwVhpeDTRDl5E/KpoC+h6HCVxGqd/qkfMag==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/solid-ui/-/solid-ui-3.1.1.tgz", + "integrity": "sha512-J2ST8rKH1tMNdPI80X5C6JrJ/I4vr7l0uRXKQRNkQw3ogK/ajgJ66H+bkaHiFH8N83SchCovGsZ5hl2uq7mFPA==", "license": "MIT", "dependencies": { - "@noble/curves": "^2.0.1", - "@noble/hashes": "^2.0.1", + "@noble/curves": "^2.2.0", + "@noble/hashes": "^2.2.0", "escape-html": "^1.0.3", - "lit": "^3.3.2", + "lit": "^3.3.3", "mime-types": "^3.0.2", - "pane-registry": "^3.1.0", + "pane-registry": "^3.1.1", "solid-namespace": "^0.5.4", - "uuid": "^13.0.0" + "uuid": "^14.0.0" }, "optionalDependencies": { "fsevents": "*" }, "peerDependencies": { - "rdflib": "^2.3.6", - "solid-logic": "^4.0.6" + "rdflib": "^2.3.8", + "solid-logic": "^4.0.7" + } + }, + "node_modules/solid-ui/node_modules/@noble/hashes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", + "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, "node_modules/solid-ui/node_modules/uuid": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.2.tgz", - "integrity": "sha512-vzi9uRZ926x4XV73S/4qQaTwPXM2JBj6/6lI/byHH1jOpCzb0zDbfytgA9LcN/hzb2l7WQSQnxITOVx5un/wGw==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz", + "integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" @@ -16849,9 +16682,9 @@ } }, "node_modules/terser": { - "version": "5.46.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.1.tgz", - "integrity": "sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz", + "integrity": "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -17000,9 +16833,9 @@ "license": "MIT" }, "node_modules/test-exclude/node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -17437,9 +17270,9 @@ } }, "node_modules/ts-loader/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", "dev": true, "license": "ISC", "bin": { @@ -17659,41 +17492,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.58.2", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.58.2.tgz", - "integrity": "sha512-V8iSng9mRbdZjl54VJ9NKr6ZB+dW0J3TzRXRGcSbLIej9jV86ZRtlYeTKDR/QLxXykocJ5icNzbsl2+5TzIvcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.58.2", - "@typescript-eslint/parser": "8.58.2", - "@typescript-eslint/typescript-estree": "8.58.2", - "@typescript-eslint/utils": "8.58.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { - "version": "8.58.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.58.2.tgz", - "integrity": "sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==", + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.60.0.tgz", + "integrity": "sha512-9f65qWLZdAW9m1JaxBDUHcqRUfL8bkxxXL7XxEfI+F09q56PkBvIfCjLF3yInsDM/BBmwkqmCQdCZe/RYlIWEw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.58.2", - "@typescript-eslint/types": "8.58.2", - "@typescript-eslint/typescript-estree": "8.58.2", - "@typescript-eslint/visitor-keys": "8.58.2", - "debug": "^4.4.3" + "@typescript-eslint/eslint-plugin": "8.60.0", + "@typescript-eslint/parser": "8.60.0", + "@typescript-eslint/typescript-estree": "8.60.0", + "@typescript-eslint/utils": "8.60.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -17760,18 +17568,18 @@ } }, "node_modules/undici": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.25.0.tgz", - "integrity": "sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg==", + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.26.0.tgz", + "integrity": "sha512-4yqz8a3n5HmGTlsbADNtr/dJlhkh/55Rq798G6ibiULcXbDtaLpTl1pvdqcbFfeoj3iSi52lePFM7h9H21cw/A==", "license": "MIT", "engines": { "node": ">=18.17" } }, "node_modules/undici-types": { - "version": "7.19.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", - "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -17842,38 +17650,41 @@ } }, "node_modules/unrs-resolver": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", - "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.12.2.tgz", + "integrity": "sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==", "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { - "napi-postinstall": "^0.3.0" + "napi-postinstall": "^0.3.4" }, "funding": { "url": "https://opencollective.com/unrs-resolver" }, "optionalDependencies": { - "@unrs/resolver-binding-android-arm-eabi": "1.11.1", - "@unrs/resolver-binding-android-arm64": "1.11.1", - "@unrs/resolver-binding-darwin-arm64": "1.11.1", - "@unrs/resolver-binding-darwin-x64": "1.11.1", - "@unrs/resolver-binding-freebsd-x64": "1.11.1", - "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", - "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", - "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", - "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", - "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", - "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-x64-musl": "1.11.1", - "@unrs/resolver-binding-wasm32-wasi": "1.11.1", - "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", - "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", - "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + "@unrs/resolver-binding-android-arm-eabi": "1.12.2", + "@unrs/resolver-binding-android-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-x64": "1.12.2", + "@unrs/resolver-binding-freebsd-x64": "1.12.2", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-arm64-musl": "1.12.2", + "@unrs/resolver-binding-linux-loong64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-loong64-musl": "1.12.2", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-musl": "1.12.2", + "@unrs/resolver-binding-linux-s390x-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-musl": "1.12.2", + "@unrs/resolver-binding-openharmony-arm64": "1.12.2", + "@unrs/resolver-binding-wasm32-wasi": "1.12.2", + "@unrs/resolver-binding-win32-arm64-msvc": "1.12.2", + "@unrs/resolver-binding-win32-ia32-msvc": "1.12.2", + "@unrs/resolver-binding-win32-x64-msvc": "1.12.2" } }, "node_modules/unzip-response": { @@ -18643,9 +18454,9 @@ } }, "node_modules/ws": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", - "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index 7fe6029d..e7e42490 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "solid-panes", - "version": "4.4.0", + "version": "4.4.1", "description": "Solid-compatible Panes: applets and views for the mashlib and databrowser", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -67,13 +67,14 @@ "dompurify": "^3.4.4", "folder-pane": "^3.1.0", "issue-pane": "^3.0.2", + "lit-html": "^3.3.2", "marked": "^18.0.3", "meeting-pane": "^3.0.2", "mime-types": "^3.0.2", "pane-registry": "^3.1.1", - "profile-pane": "^3.2.1", + "profile-pane": "^3.2.2", "solid-namespace": "^0.5.4", - "solid-ui": "^3.1.0", + "solid-ui": "^3.1.1", "source-pane": "^3.1.0" }, "overrides": { @@ -110,7 +111,7 @@ "node-polyfill-webpack-plugin": "^4.1.0", "path-browserify": "^1.0.1", "raw-loader": "^4.0.2", - "rdflib": "^2.3.8", + "rdflib": "^2.3.9", "react": "^19.2.6", "react-dom": "^19.2.6", "solid-logic": "^4.0.7", diff --git a/src/RDFXMLPane.css b/src/RDFXMLPane.css new file mode 100644 index 00000000..eb60c4e6 --- /dev/null +++ b/src/RDFXMLPane.css @@ -0,0 +1,70 @@ +.rdfxml-pane { + padding: 1rem; + border-top: solid 2px var(--color-data-pane-border-top, black); + border-left: solid 2px var(--color-data-pane-border-top, black); + border-bottom: solid 2px var(--color-data-pane-border-side, #777); + border-right: solid 2px var(--color-data-pane-border-side, #777); + color: var(--color-text-brown, #440); + box-sizing: border-box; +} + +.rdfxml-pane__source { + overflow-x: auto; + max-width: 100%; + box-sizing: border-box; + font-family: monospace; + font-size: 120%; + margin: 0; + white-space: pre; +} + +.rdfxml-pane__line { + display: grid; + grid-template-columns: var(--rdfxml-indent, 0) minmax(max-content, auto); + align-items: start; +} + +.rdfxml-pane__line-indent { + display: block; + width: var(--rdfxml-indent, 0); +} + +.rdfxml-pane__line-content { + white-space: pre; +} + +.rdfxml-pane[data-layout='mobile'] .rdfxml-pane__source { + overflow-wrap: anywhere; + word-break: break-word; + white-space: normal; +} + +.rdfxml-pane[data-layout='mobile'] .rdfxml-pane__line { + grid-template-columns: var(--rdfxml-indent, 0) minmax(0, 1fr); +} + +.rdfxml-pane[data-layout='mobile'] .rdfxml-pane__line-content { + white-space: pre-wrap; + overflow-wrap: anywhere; + word-break: break-word; + min-width: 0; +} + +@media (max-width: 576px) { + .rdfxml-pane__source { + overflow-wrap: anywhere; + word-break: break-word; + white-space: normal; + } + + .rdfxml-pane__line { + grid-template-columns: var(--rdfxml-indent, 0) minmax(0, 1fr); + } + + .rdfxml-pane__line-content { + white-space: pre-wrap; + overflow-wrap: anywhere; + word-break: break-word; + min-width: 0; + } +} diff --git a/src/RDFXMLPane.js b/src/RDFXMLPane.js deleted file mode 100644 index 877d2ec2..00000000 --- a/src/RDFXMLPane.js +++ /dev/null @@ -1,63 +0,0 @@ -/* RDF/XML content Pane - ** - ** This pane shows the content of a particular RDF resource - ** or at least the RDF semantics we attribute to that resource, - ** in generated N3 syntax. - */ - -import * as UI from 'solid-ui' -import * as $rdf from 'rdflib' - -const ns = UI.ns - -export const RDFXMLPane = { - icon: UI.icons.originalIconBase + '22-text-xml4.png', - - name: 'RDFXML', - - audience: [ns.solid('Developer')], - - label: function (subject, context) { - const store = context.session.store - if ( - 'http://www.w3.org/2007/ont/link#ProtocolEvent' in - store.findTypeURIs(subject) - ) { - return null - } - - const n = store.statementsMatching(undefined, undefined, undefined, subject) - .length - if (n === 0) return null - return 'As RDF/XML (' + n + ')' - }, - - render: function (subject, context) { - const myDocument = context.dom - const kb = context.session.store - const div = myDocument.createElement('div') - div.setAttribute('class', 'RDFXMLPane') - // Because of smushing etc, this will not be a copy of the original source - // We could instead either fetch and re-parse the source, - // or we could keep all the pre-smushed triples. - const sts = kb.statementsMatching(undefined, undefined, undefined, subject) // @@ slow with current store! - /* - var kludge = kb.formula([]) // No features - for (var i=0; i< sts.length; i++) { - s = sts[i] - kludge.add(s.subject, s.predicate, s.object) - } - */ - const sz = $rdf.Serializer(kb) - sz.suggestNamespaces(kb.namespaces) - sz.setBase(subject.uri) - const str = sz.statementsToXML(sts) - const pre = myDocument.createElement('PRE') - pre.setAttribute('style', 'overflow-x: auto; max-width: 100%; box-sizing: border-box;') - pre.appendChild(myDocument.createTextNode(str)) - div.appendChild(pre) - return div - } -} - -// ends diff --git a/src/RDFXMLPane.ts b/src/RDFXMLPane.ts new file mode 100644 index 00000000..cee48c77 --- /dev/null +++ b/src/RDFXMLPane.ts @@ -0,0 +1,133 @@ +/* RDF/XML content Pane + ** + ** This pane shows the content of a particular RDF resource + ** or at least the RDF semantics we attribute to that resource, + ** in generated N3 syntax. + */ + +import * as UI from 'solid-ui' +import * as $rdf from 'rdflib' +import type { DataBrowserContext, RenderEnvironment } from 'pane-registry' +import type { NamedNode, Statement } from 'rdflib' +import './RDFXMLPane.css' + +const ns = UI.ns + +type RDFXMLPaneDefinition = { + icon: string + name: string + audience: NamedNode[] + label: (subject: NamedNode, context: DataBrowserContext) => string | null + render: (subject: NamedNode, context: DataBrowserContext) => HTMLDivElement +} + +function leadingIndentWidth (line: string): number { + if (line.trim().length === 0) { + return 0 + } + + let width = 0 + for (const character of line) { + if (character === ' ') { + width += 1 + continue + } + if (character === '\t') { + width += 2 + continue + } + break + } + return Math.max(width, 2) +} + +function trimLeadingIndent (line: string): string { + return line.replace(/^[ \t]+/, '') +} + +export const RDFXMLPane: RDFXMLPaneDefinition = { + icon: UI.icons.originalIconBase + '22-text-xml4.png', + + name: 'RDFXML', + + audience: [ns.solid('Developer')], + + label: function (subject: NamedNode, context: DataBrowserContext): string | null { + const store = context.session.store + if ( + 'http://www.w3.org/2007/ont/link#ProtocolEvent' in + store.findTypeURIs(subject) + ) { + return null + } + + const n = store.statementsMatching(undefined, undefined, undefined, subject) + .length + if (n === 0) return null + return 'As RDF/XML (' + n + ')' + }, + + render: function ( + subject: NamedNode, + context: DataBrowserContext + ): HTMLDivElement { + const myDocument = context.dom + const kb = context.session.store + + function applyEnvironmentAttributes (element: HTMLDivElement): void { + const environment = (context.environment ?? {}) as Partial + element.dataset.layout = environment.layout ?? 'desktop' + } + + const div = myDocument.createElement('div') + div.setAttribute('class', 'rdfxml-pane') + applyEnvironmentAttributes(div) + // Because of smushing etc, this will not be a copy of the original source + // We could instead either fetch and re-parse the source, + // or we could keep all the pre-smushed triples. + const sts = kb.statementsMatching( + undefined, + undefined, + undefined, + subject + ) as Statement[] // @@ slow with current store! + /* + var kludge = kb.formula([]) // No features + for (var i=0; i< sts.length; i++) { + s = sts[i] + kludge.add(s.subject, s.predicate, s.object) + } + */ + const sz = $rdf.Serializer(kb) + sz.suggestNamespaces(kb.namespaces) + sz.setBase(subject.uri) + const str = sz.statementsToXML(sts) + const source = myDocument.createElement('div') + source.classList.add('rdfxml-pane__source') + + str.split('\n').forEach(line => { + const lineElement = myDocument.createElement('div') + const indentElement = myDocument.createElement('span') + const contentElement = myDocument.createElement('span') + const indentWidth = leadingIndentWidth(line) + + lineElement.classList.add('rdfxml-pane__line') + lineElement.style.setProperty('--rdfxml-indent', `${indentWidth}ch`) + + indentElement.classList.add('rdfxml-pane__line-indent') + indentElement.setAttribute('aria-hidden', 'true') + + contentElement.classList.add('rdfxml-pane__line-content') + contentElement.textContent = line.length > 0 ? trimLeadingIndent(line) : ' ' + + lineElement.appendChild(indentElement) + lineElement.appendChild(contentElement) + source.appendChild(lineElement) + }) + + div.appendChild(source) + return div + } +} + +// ends diff --git a/src/dataContentPane.css b/src/dataContentPane.css new file mode 100644 index 00000000..928d66fe --- /dev/null +++ b/src/dataContentPane.css @@ -0,0 +1,271 @@ +.data-content-pane__literal { + white-space: pre-wrap; +} + +div.data-content-pane { + border-top: solid 1px var(--color-data-pane-border-top, black); + border-left: solid 1px var(--color-data-pane-border-top, black); + border-bottom: solid 1px var(--color-data-pane-border-side, #777); + border-right: solid 1px var(--color-data-pane-border-side, #777); + padding: var(--spacing-base, 0.5rem); + margin-top: var(--spacing-base, 0.5rem); + margin-bottom: var(--spacing-base, 0.5rem); +} + +div.data-content-pane table.data-content-pane__table { + width: 100%; + border-collapse: separate; + border-spacing: 0; +} + +div.data-content-pane table.data-content-pane__table--root { + table-layout: auto; +} + +div.data-content-pane .data-content-pane__row--root { + display: flex; + align-items: flex-start; +} + +div.data-content-pane .data-content-pane__row--root > td { + vertical-align: top; +} + +div.data-content-pane .data-content-pane__subject-cell { + flex: 0 0 auto; + width: clamp(7rem, 12%, 10rem); + padding-right: 0.8rem; +} + +div.data-content-pane .data-content-pane__details-cell { + flex: 0 1 auto; + min-width: 0; +} + +div.data-content-pane .data-content-pane__subject-cell, +div.data-content-pane td.data-content-pane__predicate-cell, +div.data-content-pane .data-content-pane__row--top-aligned > td:not(.data-content-pane__predicate-cell), +div.data-content-pane .data-content-pane__subject-cell a, +div.data-content-pane td.data-content-pane__predicate-cell a, +div.data-content-pane .data-content-pane__row--top-aligned > td:not(.data-content-pane__predicate-cell) a { + white-space: normal; + overflow-wrap: anywhere; + word-break: break-word; +} + +div.data-content-pane table.data-content-pane__table--property { + table-layout: auto; + width: auto; + max-width: 100%; +} + +.data-content-pane__nested-formula { + border-top: solid 1px var(--color-data-pane-border-top, black); + border-left: solid 1px var(--color-data-pane-border-top, black); + border-bottom: solid 1px var(--color-data-pane-border-side, #777); + border-right: solid 1px var(--color-data-pane-border-side, #777); + padding: var(--spacing-base, 0.5rem); + border-radius: var(--border-radius-md, 0.5rem); +} + +div.data-content-pane td { + padding-left: var(--spacing-xxxs, 0.2rem); + padding-top: var(--spacing-small, 0.1rem); + padding-right: var(--spacing-xxxs, 0.2rem); + padding-bottom: 0.05rem; + vertical-align: top; +} + +div.data-content-pane table.data-content-pane__table--property td { + padding-top: 0.3rem; + padding-bottom: 0.3rem; +} + +div.data-content-pane tr { + margin-bottom: var(--spacing-2xs, 0.625rem); + padding-top: var(--spacing-small, 0.1rem); + padding-bottom: var(--spacing-small, 0.1rem); +} + +.data-content-pane a { + color: var(--color-text-link, #3b5998); + text-decoration: none; + font-weight: bold; +} + +.data-content-pane a:link { + color: var(--color-text-link, #3b5998); + text-decoration: none; + font-weight: bold; +} + +.data-content-pane a:visited { + color: var(--color-text-link-visited, #3b5998); + text-decoration: none; + font-weight: bold; +} + +.data-content-pane a:hover { + color: var(--color-text-link-hover, #3b5998); + text-decoration: underline; + font-weight: bold; +} + +.data-content-pane a:active { + color: var(--color-text-link-active, #888); + text-decoration: none; +} + +.data-content-pane.embeddedText { + white-space: pre-wrap; +} + +div.data-content-pane td.data-content-pane__predicate-cell { + min-width: 8.5rem; + width: clamp(8.5rem, 18vw, 12rem); + max-width: 12rem; + padding-right: var(--spacing-base, 0.5rem); +} + +div.data-content-pane .data-content-pane__row--top-aligned > td:not(.data-content-pane__predicate-cell) { + padding-left: var(--spacing-xxs, 0.3125rem); +} + +div.data-content-pane td.data-content-pane__predicate-cell a { + color: var(--color-text-muted, #444); +} + +.data-content-pane__row--even { + background-color: var(--color-background-row-alternate, #f0f0f0); +} + +.data-content-pane__row--odd { + background-color: var(--color-background-row-default, white); +} + +.data-content-pane__row--top-aligned { + vertical-align: top; + margin-top: 0; + margin-bottom: 0; + padding-top: 0; + padding-bottom: 0; +} + +.data-content-pane__nested-table--light { + background-color: var(--color-background-row-default, white); +} + +.data-content-pane__nested-table--dark { + background-color: var(--color-background-row-alternate, #f0f0f0); +} + +div.data-content-pane[data-layout='mobile'] .data-content-pane__row--root { + display: flex; + align-items: flex-start; + padding-bottom: var(--spacing-xs, 0.75rem); +} + +div.data-content-pane[data-layout='mobile'] .data-content-pane__subject-cell { + flex: 0 0 40%; + width: 40%; + max-width: 40%; + box-sizing: border-box; + padding-right: var(--spacing-xs, 0.75rem); + padding-bottom: 0; +} + +div.data-content-pane[data-layout='mobile'] .data-content-pane__details-cell { + flex: 0 0 60%; + width: 60%; + max-width: 60%; + min-width: 0; + box-sizing: border-box; +} + +div.data-content-pane[data-layout='mobile'] table.data-content-pane__table--property > tbody > tr, +div.data-content-pane[data-layout='mobile'] table.data-content-pane__table--property > tr { + margin-bottom: 0; +} + +div.data-content-pane[data-layout='mobile'] .data-content-pane__row--top-aligned + .data-content-pane__row--top-aligned { + margin-top: 0; +} + +div.data-content-pane[data-layout='mobile'] .data-content-pane__row--top-aligned { + display: block; + margin-bottom: 0; + padding-top: 0; + padding-bottom: 0; +} + +div.data-content-pane[data-layout='mobile'] table.data-content-pane__table--property, +div.data-content-pane[data-layout='mobile'] table.data-content-pane__table--property > tbody { + display: block; + width: 100%; +} + +div.data-content-pane[data-layout='mobile'] table.data-content-pane__table--property td { + display: block; + width: 100%; + box-sizing: border-box; +} + +div.data-content-pane[data-layout='mobile'] table.data-content-pane__table--property td.data-content-pane__predicate-cell { + width: 100%; + min-width: 0; + padding-bottom: 0.1rem; +} + +div.data-content-pane[data-layout='mobile'] table.data-content-pane__table--property td:not(.data-content-pane__predicate-cell) { + padding-top: 0; + padding-left: 0.85rem; +} + +@media (max-width: 700px) { + div.data-content-pane .data-content-pane__row--root { + display: flex; + align-items: flex-start; + } + + div.data-content-pane .data-content-pane__subject-cell { + flex: 0 0 40%; + width: 40%; + max-width: 40%; + padding-right: var(--spacing-xs, 0.75rem); + padding-bottom: 0; + box-sizing: border-box; + } + + div.data-content-pane .data-content-pane__details-cell { + flex: 0 0 60%; + width: 60%; + max-width: 60%; + box-sizing: border-box; + } + + div.data-content-pane .data-content-pane__row--top-aligned { + display: block; + margin-top: 0; + margin-bottom: 0; + padding-top: 0; + padding-bottom: 0; + } + + div.data-content-pane .data-content-pane__row--top-aligned > td { + display: block; + width: 100%; + box-sizing: border-box; + } + + div.data-content-pane .data-content-pane__row--top-aligned > td.data-content-pane__predicate-cell { + min-width: 0; + max-width: none; + width: 100%; + padding-bottom: var(--spacing-small, 0.1rem); + } + + div.data-content-pane .data-content-pane__row--top-aligned > td:not(.data-content-pane__predicate-cell) { + padding-top: 0; + padding-left: 0.85rem; + } +} diff --git a/src/dataContentPane.js b/src/dataContentPane.ts similarity index 51% rename from src/dataContentPane.js rename to src/dataContentPane.ts index 749ebc75..085df2f2 100644 --- a/src/dataContentPane.js +++ b/src/dataContentPane.ts @@ -11,9 +11,35 @@ import * as UI from 'solid-ui' import * as $rdf from 'rdflib' +import DOMPurify from 'dompurify' +import type { DataBrowserContext, RenderEnvironment } from 'pane-registry' +import type { + BlankNode, + Formula, + NamedNode, + Statement +} from 'rdflib' +import './dataContentPane.css' const ns = UI.ns +type SubjectTerm = NamedNode | BlankNode +type ObjectTerm = Statement['object'] | Formula + +type RootSubjectsResult = { + roots: SubjectTerm[] + subjects: Record + loopBreakers?: Record +} + +type DataContentPaneLike = { + statementsAsTables: ( + sts: Statement[], + context: DataBrowserContext, + initialRoots?: SubjectTerm[] + ) => HTMLTableElement +} + export const dataContentPane = { icon: UI.icons.originalIconBase + 'rdf_flyer.24.gif', @@ -21,7 +47,7 @@ export const dataContentPane = { audience: [ns.solid('Developer')], - label: function (subject, context) { + label: function (subject: NamedNode, context: DataBrowserContext) { if ( 'http://www.w3.org/2007/ont/link#ProtocolEvent' in context.session.store.findTypeURIs(subject) @@ -42,44 +68,52 @@ export const dataContentPane = { return store.whether(subject, UI.ns.rdf('type'), UI.ns.link('RDFDocument')) }, */ - statementsAsTables: function statementsAsTables (sts, context, initialRoots) { + statementsAsTables: function statementsAsTables ( + sts: Statement[], + context: DataBrowserContext, + initialRoots?: SubjectTerm[] + ): HTMLTableElement { const myDocument = context.dom // const outliner = context.getOutliner(myDocument) const rep = myDocument.createElement('table') + rep.classList.add('data-content-pane__table', 'data-content-pane__table--root') + const isMobileLayout = context.environment?.layout === 'mobile' const sz = $rdf.Serializer(context.session.store) - const res = sz.rootSubjects(sts) + const res = sz.rootSubjects(sts) as RootSubjectsResult let roots = res.roots const subjects = res.subjects - const loopBreakers = res.loopBreakers + const loopBreakers = res.loopBreakers ?? {} for (const x in loopBreakers) { console.log('\tdataContentPane: loopbreaker:' + x) } - const doneBnodes = {} // For preventing looping - const referencedBnodes = {} // Bnodes which need to be named alas + const doneBnodes: Record = {} + const referencedBnodes: Record = {} - // The property tree for a single subject or anonymous node - function propertyTree (subject) { - // print('Proprty tree for '+subject) + function propertyTree ( + subject: SubjectTerm, + nestingLevel = 0 + ): HTMLTableElement { const rep = myDocument.createElement('table') - let lastPred = null - const sts = subjects[sz.toStr(subject)] // relevant statements - if (!sts) { - // No statements in tree - rep.appendChild(myDocument.createTextNode('...')) // just empty bnode as object + rep.classList.add('data-content-pane__table', 'data-content-pane__table--property') + let lastPred: string | null = null + const subjectStatements = subjects[sz.toStr(subject)] + if (!subjectStatements) { + rep.appendChild(myDocument.createTextNode('...')) return rep } - sts.sort() + subjectStatements.sort() let same = 0 - let predicateTD // The cell which holds the predicate - for (let i = 0; i < sts.length; i++) { - const st = sts[i] + let predicateTD: HTMLTableCellElement | undefined + for (let i = 0; i < subjectStatements.length; i++) { + const st = subjectStatements[i] const tr = myDocument.createElement('tr') - if (st.predicate.uri !== lastPred) { - if (lastPred && same > 1) { - predicateTD.setAttribute('rowspan', '' + same) + tr.classList.add('data-content-pane__row--top-aligned', 'data-content-pane__row--property') + if (st.predicate.uri !== lastPred || isMobileLayout) { + if (!isMobileLayout && lastPred && same > 1) { + predicateTD?.setAttribute('rowspan', '' + same) } predicateTD = myDocument.createElement('td') - predicateTD.setAttribute('class', 'pred') + predicateTD.setAttribute('class', 'data-content-pane__predicate-cell') const anchor = myDocument.createElement('a') anchor.setAttribute('href', st.predicate.uri) anchor.addEventListener( @@ -99,17 +133,20 @@ export const dataContentPane = { } same++ const objectTD = myDocument.createElement('td') - objectTD.appendChild(objectTree(st.object)) + objectTD.classList.add('data-content-pane__value-cell') + objectTD.appendChild(objectTree(st.object, nestingLevel + 1)) tr.appendChild(objectTD) rep.appendChild(tr) } - if (lastPred && same > 1) predicateTD.setAttribute('rowspan', '' + same) + if (!isMobileLayout && lastPred && same > 1) { + predicateTD?.setAttribute('rowspan', '' + same) + } return rep } - // Convert a set of statements into a nested tree of tables - function objectTree (obj) { - let res, anchor + function objectTree (obj: ObjectTerm, nestingLevel = 0): Node { + let res: HTMLElement | HTMLTableElement | Text + let anchor: HTMLAnchorElement switch (obj.termType) { case 'NamedNode': anchor = myDocument.createElement('a') @@ -125,7 +162,7 @@ export const dataContentPane = { case 'Literal': if (!obj.datatype || !obj.datatype.uri) { res = myDocument.createElement('div') - res.setAttribute('style', 'white-space: pre-wrap;') + res.classList.add('data-content-pane__literal') res.textContent = obj.value return res } else if ( @@ -133,65 +170,59 @@ export const dataContentPane = { 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral' ) { res = myDocument.createElement('div') - res.setAttribute('class', 'embeddedXHTML') - res.innerHTML = obj.value // Try that @@@ beware embedded dangerous code + res.classList.add('embeddedXHTML') + res.innerHTML = DOMPurify.sanitize(obj.value) return res } - return myDocument.createTextNode(obj.value) // placeholder - could be smarter, + return myDocument.createTextNode(obj.value) case 'BlankNode': { if (obj.toNT() in doneBnodes) { - // Break infinite recursion referencedBnodes[obj.toNT()] = true - const anchor = myDocument.createElement('a') - anchor.setAttribute('href', '#' + obj.toNT().slice(2)) - anchor.setAttribute('class', 'bnodeRef') - anchor.textContent = '*' + obj.toNT().slice(3) - return anchor + const referenceAnchor = myDocument.createElement('a') + referenceAnchor.setAttribute('href', '#' + obj.toNT().slice(2)) + referenceAnchor.setAttribute('class', 'bnodeRef') + referenceAnchor.textContent = '*' + obj.toNT().slice(3) + return referenceAnchor } - doneBnodes[obj.toNT()] = true // Flag to prevent infinite recursion in propertyTree - const newTable = propertyTree(obj) - doneBnodes[obj.toNT()] = newTable // Track where we mentioned it first - if ( - UI.utils.ancestor(newTable, 'TABLE') && - UI.utils.ancestor(newTable, 'TABLE').style.backgroundColor === - 'white' - ) { - newTable.style.backgroundColor = '#eee' + doneBnodes[obj.toNT()] = true + const newTable = propertyTree(obj, nestingLevel) + doneBnodes[obj.toNT()] = newTable + if (nestingLevel % 2 === 1) { + newTable.classList.add('data-content-pane__nested-table--light') } else { - newTable.style.backgroundColor = 'white' + newTable.classList.add('data-content-pane__nested-table--dark') } return newTable } + case 'Collection': res = myDocument.createElement('table') res.setAttribute('class', 'collectionAsTables') for (let i = 0; i < obj.elements.length; i++) { const tr = myDocument.createElement('tr') res.appendChild(tr) - tr.appendChild(objectTree(obj.elements[i])) + tr.appendChild(objectTree(obj.elements[i] as ObjectTerm, nestingLevel + 1)) } return res + case 'Graph': - res = context.session.paneRegistry - .byName('dataContents') + res = (context.session.paneRegistry + .byName('dataContents') as DataContentPaneLike) .statementsAsTables(obj.statements, context) - res.setAttribute('class', 'nestedFormula') + res.setAttribute('class', 'data-content-pane__nested-formula') return res + case 'Variable': - res = myDocument.createTextNode('?' + obj.uri) - return res + return myDocument.createTextNode('?' + obj.uri) } throw new Error('Unhandled node type: ' + obj.termType) } - // roots.sort() - if (initialRoots) { roots = initialRoots.concat( - roots.filter(function (x) { + roots.filter(function (x: SubjectTerm) { for (let i = 0; i < initialRoots.length; i++) { - // Max 2 if (x.sameTerm(initialRoots[i])) return false } return true @@ -200,24 +231,28 @@ export const dataContentPane = { } for (let i = 0; i < roots.length; i++) { const tr = myDocument.createElement('tr') - tr.setAttribute('style', `background-color: ${i % 2 === 0 ? '#f0f0f0' : 'white'};`) + tr.classList.add( + i % 2 === 0 ? 'data-content-pane__row--even' : 'data-content-pane__row--odd', + 'data-content-pane__row--root' + ) rep.appendChild(tr) const subjectTD = myDocument.createElement('td') + subjectTD.classList.add('data-content-pane__subject-cell') tr.appendChild(subjectTD) const TDTree = myDocument.createElement('td') + TDTree.classList.add('data-content-pane__details-cell') tr.appendChild(TDTree) const root = roots[i] if (root.termType === 'BlankNode') { - subjectTD.appendChild(myDocument.createTextNode(UI.utils.label(root))) // Don't recurse! + subjectTD.appendChild(myDocument.createTextNode(UI.utils.label(root))) } else { - subjectTD.appendChild(objectTree(root)) // won't have tree + subjectTD.appendChild(objectTree(root, 0)) } - TDTree.appendChild(propertyTree(root)) + TDTree.appendChild(propertyTree(root, 0)) } for (const bNT in referencedBnodes) { - // Add number to refer to const table = doneBnodes[bNT] - // let tr = myDocument.createElement('tr') + if (table === true) continue const anchor = myDocument.createElement('a') anchor.setAttribute('id', bNT.slice(2)) anchor.setAttribute('class', 'bnodeDef') @@ -225,47 +260,33 @@ export const dataContentPane = { table.insertBefore(anchor, table.firstChild) } return rep - }, // statementsAsTables - // View the data in a file in user-friendly way - render: function (subject, context) { + }, + + render: function ( + subject: NamedNode, + context: DataBrowserContext + ): HTMLDivElement { const myDocument = context.dom - function alternativeRendering () { - const sz = $rdf.Serializer(context.session.store) - const res = sz.rootSubjects(sts) - const roots = res.roots - const p = {} - p.render = function (s2) { - const div = myDocument.createElement('div') - div.setAttribute('class', 'withinDocumentPane') - const plist = kb.statementsMatching(s2, undefined, undefined, subject) - outliner.appendPropertyTRs(div, plist, false, function ( - _pred, - _inverse - ) { - return true - }) - return div - } - for (let i = 0; i < roots.length; i++) { - const tr = myDocument.createElement('TR') - const root = roots[i] - tr.style.verticalAlign = 'top' - const td = outliner.outlineObjectTD(root, undefined, tr) - tr.appendChild(td) - div.appendChild(tr) - outliner.outlineExpand(td, root, { pane: p }) - } + function applyEnvironmentAttributes (element: HTMLDivElement): void { + const environment = (context.environment ?? {}) as Partial + element.dataset.layout = environment.layout ?? 'desktop' + element.dataset.theme = environment.theme ?? 'light' + element.dataset.inputMode = environment.inputMode ?? 'pointer' } function mainRendering () { - const initialRoots = [] // Ordering: start with stuff about this doc + const kb = context.session.store + const sts = kb.statementsMatching(undefined, undefined, undefined, subject) + const initialRoots: SubjectTerm[] = [] if (kb.holds(subject, undefined, undefined, subject)) { initialRoots.push(subject) } - // Then about the primary topic of the document if any const ps = kb.any(subject, UI.ns.foaf('primaryTopic'), undefined, subject) - if (ps) initialRoots.push(ps) + if (ps && (ps.termType === 'NamedNode' || ps.termType === 'BlankNode')) { + initialRoots.push(ps as SubjectTerm) + } + div.appendChild( context.session.paneRegistry .byName('dataContents') @@ -273,21 +294,11 @@ export const dataContentPane = { ) } - const outliner = context.getOutliner(myDocument) - const kb = context.session.store const div = myDocument.createElement('div') - div.setAttribute('class', 'dataContentPane') - // Because of smushing etc, this will not be a copy of the original source - // We could instead either fetch and re-parse the source, - // or we could keep all the pre-smushed triples. - const sts = kb.statementsMatching(undefined, undefined, undefined, subject) // @@ slow with current store! + div.classList.add('dataContentPane', 'data-content-pane') + applyEnvironmentAttributes(div) - // eslint-disable-next-line no-constant-condition - if (false) { // keep code - alternativeRendering() - } else { - mainRendering() - } + mainRendering() return div } } diff --git a/src/defaultPane.css b/src/defaultPane.css new file mode 100644 index 00000000..2b9a8762 --- /dev/null +++ b/src/defaultPane.css @@ -0,0 +1,97 @@ +.defaultPane .bottom-border { + border: 0.2rem solid transparent; + width: 100%; +} + +.defaultPane .bottom-border-active { + cursor: copy; + border: 0.2rem solid; + border-color: var(--color-bottom-border-highlight, rgb(100%, 65%, 0%)); +} + +.defaultPane { + --default-pane-predicate-column: 16rem; + --default-pane-object-indent: 1.75rem; +} + +.defaultPane > tr { + display: grid; + grid-template-columns: minmax(0, var(--default-pane-predicate-column)) minmax(0, 1fr); + align-items: flex-start; +} + +.defaultPane > tr > td.pred { + grid-column: 1; + display: flex; + align-items: flex-start; + padding-left: 0 !important; + box-sizing: border-box; + min-width: 0; +} + +.defaultPane > tr > td.pred > .labelTD { + flex: 1 1 auto; + min-width: 0; + margin: 0; + padding-top: 0; + padding-bottom: 0; +} + +.defaultPane > tr > td.pred > .iconTD { + flex: 0 0 auto; + width: auto; + margin: 0; +} + +.defaultPane > tr > td.obj { + grid-column: 2; + min-width: 0; + box-sizing: border-box; + align-self: start; +} + +.defaultPane > tr > td[colspan='2'] { + grid-column: 1 / -1; +} + +.defaultPane[data-layout='mobile'] > tr { + grid-template-columns: minmax(0, 1fr); +} + +.defaultPane[data-layout='mobile'] > tr > td.pred, +.defaultPane[data-layout='mobile'] > tr > td.obj { + display: block; + grid-column: 1; + width: 100%; + box-sizing: border-box; +} + +.defaultPane[data-layout='mobile'] > tr > td.pred { + padding-bottom: var(--spacing-small, 0.1rem); +} + +.defaultPane[data-layout='mobile'] > tr > td.obj { + padding-left: var(--default-pane-object-indent) !important; +} + +@media (max-width: 700px) { + .defaultPane > tr { + grid-template-columns: minmax(0, 1fr); + } + + .defaultPane > tr > td.pred, + .defaultPane > tr > td.obj { + display: block; + grid-column: 1; + width: 100%; + box-sizing: border-box; + } + + .defaultPane > tr > td.pred { + padding-bottom: var(--spacing-small, 0.1rem); + } + + .defaultPane > tr > td.obj { + padding-left: var(--default-pane-object-indent) !important; + } +} diff --git a/src/defaultPane.js b/src/defaultPane.ts similarity index 59% rename from src/defaultPane.js rename to src/defaultPane.ts index e243f262..da365030 100644 --- a/src/defaultPane.js +++ b/src/defaultPane.ts @@ -7,24 +7,56 @@ import * as UI from 'solid-ui' import * as $rdf from 'rdflib' +import type { DataBrowserContext, RenderEnvironment } from 'pane-registry' +import type { BlankNode, Literal, NamedNode, Statement } from 'rdflib' +import './defaultPane.css' const ns = UI.ns +type DefaultPaneSubject = NamedNode | BlankNode | Literal -export const defaultPane = { +type DefaultPaneDefinition = { + icon: string + name: string + audience: NamedNode[] + label: (subject: DefaultPaneSubject) => string + render: (subject: DefaultPaneSubject, context: DataBrowserContext) => HTMLDivElement +} + +type DefaultPaneOutliner = { + appendPropertyTRs: ( + parent: HTMLElement, + statements: Statement[], + inverse: boolean, + filter: (pred: NamedNode, inverse: boolean) => boolean + ) => void + UserInput: { + addNewPredicateObject: (event: Event) => void + } +} + +export const defaultPane: DefaultPaneDefinition = { icon: UI.icons.originalIconBase + 'about.png', name: 'default', audience: [ns.solid('Developer')], - label: function (_subject) { + label: function (_subject: DefaultPaneSubject): string { return 'about ' }, - render: function (subject, context) { + render: function ( + subject: DefaultPaneSubject, + context: DataBrowserContext + ): HTMLDivElement { const dom = context.dom - const filter = function (pred, inverse) { + function applyEnvironmentAttributes (element: HTMLDivElement): void { + const environment = (context.environment ?? {}) as Partial + element.dataset.layout = environment.layout ?? 'desktop' + } + + const filter = function (pred: NamedNode, inverse: boolean): boolean { if ( typeof context.session.paneRegistry.byName('internal').predicates[ pred.uri @@ -41,19 +73,23 @@ export const defaultPane = { return true } - const outliner = context.getOutliner(dom) + const outliner = context.getOutliner(dom) as DefaultPaneOutliner const kb = context.session.store // var outline = outliner; // @@ UI.log.info('@defaultPane.render, dom is now ' + dom.location) - subject = kb.canon(subject) + subject = kb.canon(subject) as DefaultPaneSubject const div = dom.createElement('div') div.setAttribute('class', 'defaultPane') + applyEnvironmentAttributes(div) // appendRemoveIcon(div, subject, div) - let plist = kb.statementsMatching(subject) + let plist = subject.termType === 'Literal' ? [] : kb.statementsMatching(subject) outliner.appendPropertyTRs(div, plist, false, filter) plist = kb.statementsMatching(undefined, undefined, subject) outliner.appendPropertyTRs(div, plist, true, filter) + const subjectStatement = subject.termType === 'BlankNode' + ? kb.anyStatementMatching(subject) + : undefined if ( subject.termType === 'Literal' && subject.value.slice(0, 7) === 'http://' @@ -69,10 +105,11 @@ export const defaultPane = { (subject.termType === 'NamedNode' && kb.updater.editable($rdf.Util.uri.docpart(subject.uri), kb)) || (subject.termType === 'BlankNode' && - kb.anyStatementMatching(subject) && - kb.anyStatementMatching(subject).why && - kb.anyStatementMatching(subject).why.uri && - kb.updater.editable(kb.anyStatementMatching(subject).why.uri)) + subjectStatement && + subjectStatement.why && + 'uri' in subjectStatement.why && + typeof subjectStatement.why.uri === 'string' && + kb.updater.editable(subjectStatement.why.uri)) // check the document containing something about of the bnode @@ what about as object? /* ! && HCIoptions["bottom insert highlights"].enabled */ ) { diff --git a/src/form/formPane.css b/src/form/formPane.css new file mode 100644 index 00000000..fe372ed4 --- /dev/null +++ b/src/form/formPane.css @@ -0,0 +1,120 @@ +.formPane a { + color: var(--color-text-link, #3b5998); + text-decoration: none; +} + +.formPane a:link { + color: var(--color-text-link, #3b5998); + text-decoration: none; +} + +.formPane a:visited { + color: var(--color-text-link-visited, #3b5998); + text-decoration: none; +} + +.formPane a:hover { + color: var(--color-text-link-hover, #3b5998); + font-weight: bold; +} + +.formPane a:active { + color: var(--color-text-link-active, #888); + text-decoration: none; +} + +.formPane__message, +.formPaneMessage { + color: #666; + margin: var(--spacing-xs, 0.5em) 0; + padding: var(--spacing-xs, 0.35em) var(--spacing-xs, 0.5em); +} + +.formPane__message--info { + background-color: var(--color-main-block-bg, #eee); +} + +.formPane__message--error { + background-color: var(--color-log-error-bg, #fee); +} + +.formPane__editButton { + margin-left: auto; + align-self: center; + padding: var(--spacing-xs, 0.5rem); + border: .5rem solid white; + font-size: 100%; + float: none; +} + +.formPane .formPane__mobileTextareaValue > div { + display: block; + min-width: 0; + position: relative; +} + +.formPane .formPane__mobileTextareaValue > div > textarea { + box-sizing: border-box; + max-width: 100%; + min-width: 0; + width: 100%; +} + +.formPane .formPane__mobileTextareaValue > div > button[type='button'] { + float: none !important; + position: absolute; + right: 0; + top: 0; +} + +.formPane[data-layout='mobile'] .formPane__mobileTextareaRow { + flex-direction: column !important; + align-items: stretch; +} + +.formPane[data-layout='mobile'] .formPane__mobileTextareaLabel { + width: auto !important; + padding-bottom: 0; +} + +.formPane[data-layout='mobile'] .formPane__mobileTextareaValue { + box-sizing: border-box; + min-width: 0; + padding-right: var(--spacing-sm, 0.75rem); + width: 100%; +} + +.formPane[data-layout='mobile'] .formPane__mobileTextareaValue textarea { + box-sizing: border-box; + margin-left: 0 !important; + margin-right: 0 !important; + max-width: 100%; + width: 100%; +} + +@media (max-width: 960px) { + .formPane .formPane__mobileTextareaRow { + flex-direction: column !important; + align-items: stretch; + } + + .formPane .formPane__mobileTextareaLabel { + width: auto !important; + padding-bottom: 0; + } + + .formPane .formPane__mobileTextareaValue { + box-sizing: border-box; + min-width: 0; + padding-right: var(--spacing-sm, 0.75rem); + width: 100%; + } + + .formPane .formPane__mobileTextareaValue textarea { + box-sizing: border-box; + margin-left: 0 !important; + margin-right: 0 !important; + max-width: 100%; + width: 100%; + } +} diff --git a/src/form/pane.js b/src/form/pane.js deleted file mode 100644 index 9c655615..00000000 --- a/src/form/pane.js +++ /dev/null @@ -1,217 +0,0 @@ -/* - ** Pane for running existing forms for any object - ** - */ - -import * as UI from 'solid-ui' -import { authn } from 'solid-logic' -import * as $rdf from 'rdflib' -const ns = UI.ns - -export const formPane = { - icon: UI.icons.iconBase + 'noun_122196.svg', - - name: 'form', - - audience: [ns.solid('PowerUser')], - - // Does the subject deserve this pane? - label: function (subject) { - const n = UI.widgets.formsFor(subject).length - UI.log.debug('Form pane: forms for ' + subject + ': ' + n) - if (!n) return null - return '' + n + ' forms' - }, - - render: function (subject, context) { - const kb = context.session.store - const dom = context.dom - - const mention = function complain (message, style) { - const pre = dom.createElement('p') - pre.setAttribute('style', style || 'color: grey; background-color: white') - box.appendChild(pre).textContent = message - return pre - } - - const complain = function complain (message, style) { - mention(message, 'style', style || 'color: grey; background-color: #fdd;') - } - - const complainIfBad = function (ok, body) { - if (ok) { - // setModifiedDate(store, kb, store); - // rerender(box); // Deleted forms at the moment - } else complain('Sorry, failed to save your change:\n' + body) - } - - // The question of where to store this data about subject - // This in general needs a whole lot more thought - // and it connects to the discoverbility through links - - // const t = kb.findTypeURIs(subject) - - const me = authn.currentUser() - - const box = dom.createElement('div') - box.setAttribute('class', 'formPane') - - if (!me) { - mention( - 'You are not logged in. If you log in and have ' + - 'workspaces then you would be able to select workspace in which ' + - 'to put this new information' - ) - } else { - const ws = kb.each(me, ns.ui('workspace')) - if (ws.length === 0) { - mention( - 'You don\'t seem to have any workspaces defined. ' + - 'A workspace is a place on the web (http://..) or in ' + - 'the file system (file:///) to store application data.\n' - ) - } else { - // @@ - } - } - - // Render forms using a given store - - const renderFormsFor = function (store, subject) { - kb.fetcher.nowOrWhenFetched(store.uri, subject, function (ok, body) { - if (!ok) return complain('Cannot load store ' + store.uri + ': ' + body) - - // Render the forms - - const forms = UI.widgets.formsFor(subject) - - // complain('Form for editing this form:'); - for (let i = 0; i < forms.length; i++) { - const form = forms[i] - const heading = dom.createElement('h4') - box.appendChild(heading) - if (form.uri) { - const formStore = $rdf.Util.uri.document(form.uri) - if (formStore.uri !== form.uri) { - // The form is a hash-type URI - const e = box.appendChild( - UI.widgets.editFormButton( - dom, - box, - form, - formStore, - complainIfBad - ) - ) - e.setAttribute('style', 'margin-left: auto; display: block;') - } - } - const anchor = dom.createElement('a') - anchor.setAttribute('href', form.uri) - heading.appendChild(anchor) - anchor.textContent = UI.utils.label(form, true) - - /* Keep tis as a reminder to let a New one have its URI given by user - mention("Where will this information be stored?") - const ele = dom.createElement('input'); - box.appendChild(ele); - ele.setAttribute('type', 'text'); - ele.setAttribute('size', '72'); - ele.setAttribute('maxlength', '1024'); - ele.setAttribute('style', 'font-size: 80%; color:#222;'); - ele.value = store.uri - */ - - UI.widgets.appendForm( - dom, - box, - {}, - subject, - form, - store, - complainIfBad - ) - } - }) // end: when store loded - } // renderFormsFor - - // Figure out what store - - // Which places are editable and have stuff about the subject? - - let store = null - - // 1. The document URI of the subject itself - const docuri = $rdf.Util.uri.docpart(subject.uri) - if (subject.uri !== docuri && kb.updater.editable(docuri, kb)) { - store = subject.doc() - } // an editable data file with hash - - store = store || kb.any(kb.sym(docuri), ns.link('annotationStore')) - - // 2. where stuff is already stored - if (!store) { - const docs = {} - const docList = [] - store.statementsMatching(subject).forEach(function (st) { - docs[st.why.uri] = 1 - }) - store - .statementsMatching(undefined, undefined, subject) - .forEach(function (st) { - docs[st.why.uri] = 2 - }) - for (const d in docs) docList.push(docs[d], d) - docList.sort() - for (let i = 0; i < docList.length; i++) { - const uri = docList[i][1] - if (uri && store.updater.editable(uri)) { - store = store.sym(uri) - break - } - } - } - - // 3. In a workspace store - // @@ TODO: Can probably remove _followeach (not done this time because the commit is a very safe refactor) - const _followeach = function (kb, subject, path) { - if (path.length === 0) return [subject] - const oo = kb.each(subject, path[0]) - let res = [] - for (let i = 0; i < oo.length; i++) { - res = res.concat(_followeach(kb, oo[i], path.slice(1))) - } - return res - } - - const date = '2014' // @@@@@@@@@@@@ pass as parameter - - if (store) { - // mention("@@ Ok, we have a store <" + store.uri + ">."); - renderFormsFor(store, subject) - } else { - complain('No suitable store is known, to edit <' + subject.uri + '>.') - const foobarbaz = UI.login.selectWorkspace(dom, function (ws) { - mention('Workspace selected OK: ' + ws) - - const activities = store.each(undefined, ns.space('workspace'), ws) - for (let j = 0; j < activities.length; j++) { - const act = activities[j] - - const subjectDoc2 = store.any(ws, ns.space('store')) - const start = store.any(ws, ns.cal('dtstart')).value() - const end = store.any(ws, ns.cal('dtend')).value() - if (subjectDoc2 && start && end && start <= date && end > date) { - renderFormsFor(subjectDoc2, subject) - break - } else { - complain('Note no suitable annotation store in activity: ' + act) - } - } - }) - box.appendChild(foobarbaz) - } - - return box - } -} diff --git a/src/form/pane.ts b/src/form/pane.ts new file mode 100644 index 00000000..d79d67a1 --- /dev/null +++ b/src/form/pane.ts @@ -0,0 +1,311 @@ +/* + ** Pane for running existing forms for any object + ** + */ + +import * as UI from 'solid-ui' +import { authn } from 'solid-logic' +import * as $rdf from 'rdflib' +import type { DataBrowserContext, PaneDefinition } from 'pane-registry' +import type { RenderEnvironment } from 'pane-registry' +import type { NamedNode, Statement } from 'rdflib' +import './formPane.css' +const ns = UI.ns + +type WorkspaceSelectionDetails = { + noun: string + appPathSegment: string +} + +function isNamedNode (term: { termType?: string } | null | undefined): term is NamedNode { + return term?.termType === 'NamedNode' +} + +/* The following helper was generated by AI GPT-5.4 Model */ +/* Prompt: Add a compatibility shim in the form pane for mixed `ui:Group` plus field typing. */ +function normalizeAmbiguousFieldTypes (store: typeof $rdf.graph extends () => infer T ? T : never, form: NamedNode): void { + const formDoc = form.doc ? form.doc() : undefined + const types = store.each(form, ns.rdf('type'), undefined, formDoc).filter(isNamedNode) + const hasGroupType = types.some(type => type.sameTerm(ns.ui('Group'))) + const hasOtherFieldType = types.some(type => !type.sameTerm(ns.ui('Group')) && !type.sameTerm(ns.ui('Form'))) + const hasProperty = !!store.any(form, ns.ui('property'), undefined, formDoc) + const partsList = store.any(form, ns.ui('parts'), undefined, formDoc) as { elements?: unknown[] } | null + const hasParts = !!partsList?.elements?.length || store.each(form, ns.ui('part'), undefined, formDoc).length > 0 + + // Some legacy forms mark a leaf field as both ui:Group and a concrete input type. + // solid-ui may then choose the Group renderer and produce an empty nested box. + if (hasGroupType && hasOtherFieldType && hasProperty && !hasParts) { + store.removeMany(form, ns.rdf('type'), ns.ui('Group'), formDoc) + } + + const listParts = partsList?.elements ?? [] + for (const part of listParts) { + if (isNamedNode(part as { termType?: string })) { + normalizeAmbiguousFieldTypes(store, part as NamedNode) + } + } + + const unorderedParts = store.each(form, ns.ui('part'), undefined, formDoc) + for (const part of unorderedParts) { + if (isNamedNode(part)) { + normalizeAmbiguousFieldTypes(store, part) + } + } +} + +function tagMobileTextareaRows (renderedForm: HTMLElement): void { + const textareas = Array.from(renderedForm.querySelectorAll('textarea')) + + for (const textarea of textareas) { + let row: HTMLDivElement | null = textarea.parentElement as HTMLDivElement | null + + while (row) { + const firstChild = row.firstElementChild as HTMLElement | null + const hasLabelColumn = !!firstChild && ( + firstChild.classList.contains('formFieldName') || + firstChild.querySelector('a') !== null + ) + + if (hasLabelColumn && row.children.length >= 2) { + row.classList.add('formPane__mobileTextareaRow') + firstChild.classList.add('formPane__mobileTextareaLabel') + const valueColumn = row.children[1] as HTMLElement + valueColumn.classList.add('formPane__mobileTextareaValue') + break + } + + row = row.parentElement as HTMLDivElement | null + } + } +} + +export const formPane: PaneDefinition = { + icon: UI.icons.iconBase + 'noun_122196.svg', + + name: 'form', + + audience: [ns.solid('PowerUser')], + + // Does the subject deserve this pane? + label: function (subject: NamedNode, _context: DataBrowserContext): string | null { + const n = UI.widgets.formsFor(subject).length + UI.log.debug('Form pane: forms for ' + subject + ': ' + n) + if (!n) return null + return '' + n + ' forms' + }, + + render: function (subject: NamedNode, context: DataBrowserContext): HTMLDivElement { + const kb = context.session.store + const dom = context.dom + const box = dom.createElement('div') + box.setAttribute('class', 'formPane') + + function applyEnvironmentAttributes (element: HTMLDivElement): void { + const environment = (context.environment ?? {}) as Partial + element.dataset.layout = environment.layout ?? 'desktop' + } + + applyEnvironmentAttributes(box) + + const mention = function ( + message: string, + modifier: 'info' | 'error' = 'info' + ): HTMLParagraphElement { + const pre = dom.createElement('p') + pre.className = `formPane__message formPane__message--${modifier}` + box.appendChild(pre).textContent = message + return pre + } + + const complain = function (message: string): HTMLParagraphElement { + return mention(message, 'error') + } + + const complainIfBad = function (ok: boolean, body: string): void { + if (ok) { + // setModifiedDate(store, kb, store); + // rerender(box); // Deleted forms at the moment + } else complain('Sorry, failed to save your change:\n' + body) + } + + // The question of where to store this data about subject + // This in general needs a whole lot more thought + // and it connects to the discoverbility through links + + // const t = kb.findTypeURIs(subject) + + const me = authn.currentUser() + + if (!me) { + mention( + 'You are not logged in. If you log in and have ' + + 'workspaces then you would be able to select workspace in which ' + + 'to put this new information' + ) + } else { + const ws = kb.each(me, ns.ui('workspace')) + if (ws.length === 0) { + mention( + 'You don\'t seem to have any workspaces defined. ' + + 'A workspace is a place on the web (http://..) or in ' + + 'the file system (file:///) to store application data.\n' + ) + } else { + // @@ + } + } + + // Render forms using a given store + + const renderFormsFor = function (storeNode: NamedNode, targetSubject: NamedNode): void { + kb.fetcher.nowOrWhenFetched( + storeNode.uri, + targetSubject as unknown as Parameters[1], + function (ok, body) { + if (!ok) return complain('Cannot load store ' + storeNode.uri + ': ' + body) + + // Render the forms + + const forms = UI.widgets.formsFor(targetSubject) as NamedNode[] + + // complain('Form for editing this form:'); + for (const form of forms) { + normalizeAmbiguousFieldTypes(kb as never, form) + + const heading = dom.createElement('h4') + heading.classList.add('formPane__heading') + box.appendChild(heading) + /* The edit Form is not working in the local environment. it does not find + the ui FormForm ontology. Need to research further and check in production. */ + if (form.uri) { + const formStore = $rdf.Util.uri.document(form.uri) + if (formStore.uri !== form.uri) { + const editButton = box.appendChild( + UI.widgets.editFormButton( + dom, + box, + form, + formStore, + complainIfBad + ) + ) + editButton.classList.add('formPane__editButton') + } + } + + const anchor = dom.createElement('a') + anchor.classList.add('formPane__headingLink') + anchor.setAttribute('href', form.uri) + heading.insertBefore(anchor, heading.firstChild) + anchor.textContent = UI.utils.label(form, true) + + /* Keep tis as a reminder to let a New one have its URI given by user + mention("Where will this information be stored?") + const ele = dom.createElement('input'); + box.appendChild(ele); + ele.setAttribute('type', 'text'); + ele.setAttribute('size', '72'); + ele.setAttribute('maxlength', '1024'); + ele.setAttribute('style', 'font-size: 80%; color:#222;'); + ele.value = store.uri + */ + + UI.widgets.appendForm( + dom, + box, + {}, + targetSubject, + form, + storeNode, + complainIfBad + ) + tagMobileTextareaRows(box) + } + } + ) // end: when store loded + } // renderFormsFor + + // Figure out what store + + // Which places are editable and have stuff about the subject? + + let targetStore: NamedNode | null = null + + // 1. The document URI of the subject itself + const docuri = $rdf.Util.uri.docpart(subject.uri) + if (kb.updater.editable(docuri, kb)) { + targetStore = subject.doc() + } // an editable data file with hash + + const annotationStore = kb.any(kb.sym(docuri), ns.link('annotationStore')) + if (!targetStore && isNamedNode(annotationStore)) { + targetStore = annotationStore + } + + // 2. where stuff is already stored + if (!targetStore) { + const docs = new Map() + kb.statementsMatching(subject).forEach(function (st: Statement) { + if (st.why.value) { + docs.set(st.why.value, 1) + } + }) + kb + .statementsMatching(undefined, undefined, subject) + .forEach(function (st: Statement) { + if (st.why.value) { + docs.set(st.why.value, 2) + } + }) + const docList = Array.from(docs.entries()).sort(function ([uriA, scoreA], [uriB, scoreB]) { + return scoreA - scoreB || uriA.localeCompare(uriB) + }) + for (const [uri] of docList) { + if (uri && kb.updater.editable(uri, kb)) { + targetStore = kb.sym(uri) + break + } + } + } + + // 3. In a workspace store + const date = '2014' // @@@@@@@@@@@@ pass as parameter + + if (targetStore) { + // mention("@@ Ok, we have a store <" + store.uri + ">."); + renderFormsFor(targetStore, subject) + } else { + complain('No suitable store is known, to edit <' + subject.uri + '>.') + const workspaceDetails: WorkspaceSelectionDetails = { + noun: 'form', + appPathSegment: 'form' + } + const foobarbaz = UI.login.selectWorkspace(dom, workspaceDetails, function (workspaceUri: string | null) { + const workspace = workspaceUri ? kb.sym(workspaceUri) : null + if (!workspace) { + complain('Workspace selection was cancelled.') + return + } + mention('Workspace selected OK: ' + workspace.uri) + + const activities = kb.each(undefined, ns.space('workspace'), workspace).filter(isNamedNode) + for (let j = 0; j < activities.length; j++) { + const act = activities[j] + + const subjectDoc2 = kb.any(act, ns.space('store')) + const start = kb.any(act, ns.cal('dtstart'))?.value + const end = kb.any(act, ns.cal('dtend'))?.value + if (isNamedNode(subjectDoc2) && start && end && start <= date && end > date) { + renderFormsFor(subjectDoc2, subject) + break + } else { + complain('Note no suitable annotation store in activity: ' + act) + } + } + }) + box.appendChild(foobarbaz) + } + + return box + } +} diff --git a/src/humanReadablePane.css b/src/humanReadablePane.css new file mode 100644 index 00000000..888b85ed --- /dev/null +++ b/src/humanReadablePane.css @@ -0,0 +1,129 @@ +.human-readable-pane { + display: block; + min-width: 0; + width: 100%; + max-width: 100%; + box-sizing: border-box; +} + +.human-readable-pane__container { + display: block; + min-width: 0; + width: 100%; + max-width: 100%; + box-sizing: border-box; + overflow-x: hidden; +} + +.human-readable-pane__frame { + display: block; + border: 1px solid; + padding: 1rem; + height: var(--human-readable-pane-height, 30rem); + min-width: 0; + max-width: 100%; + width: 100%; + box-sizing: border-box; + resize: both; + overflow: auto; +} + +.human-readable-pane__frame--iframe { + padding: 0; + overflow: hidden; + width: 100%; + max-width: 100%; + min-height: 18rem; + background: var(--color-background, white); +} + +.human-readable-pane__frame--markdown { + overflow-wrap: anywhere; + word-break: break-word; +} + +.human-readable-pane__frame--plain-text { + font-family: monospace; + white-space: pre-wrap; + overflow-wrap: anywhere; + word-break: break-word; +} + +.human-readable-pane__frame--markdown > * { + max-width: 100%; + box-sizing: border-box; +} + +.human-readable-pane__frame--markdown img, +.human-readable-pane__frame--markdown video, +.human-readable-pane__frame--markdown canvas, +.human-readable-pane__frame--markdown iframe { + max-width: 100%; + height: auto; +} + +.human-readable-pane__frame--markdown pre, +.human-readable-pane__frame--markdown code { + max-width: 100%; + overflow-wrap: anywhere; + word-break: break-word; +} + +.human-readable-pane__frame--markdown pre { + white-space: pre-wrap; +} + +.human-readable-pane__frame--markdown table { + display: block; + width: 100%; + max-width: 100%; + overflow-x: auto; + box-sizing: border-box; +} + +.human-readable-pane__frame--markdown th, +.human-readable-pane__frame--markdown td { + white-space: normal; + overflow-wrap: anywhere; + word-break: break-word; +} + +.human-readable-pane[data-layout='mobile'] .human-readable-pane__frame { + padding: 0.75rem; + resize: none; + min-width: 0; +} + +.human-readable-pane[data-layout='mobile'] .human-readable-pane__frame--markdown, +.human-readable-pane[data-layout='mobile'] .human-readable-pane__frame--plain-text { + overflow-wrap: anywhere; + word-break: break-word; +} + +.human-readable-pane[data-layout='mobile'] .human-readable-pane__frame--iframe { + width: 100%; + max-width: 100%; + min-height: 16rem; + height: min(var(--human-readable-pane-height, 30rem), 75vh); +} + +@media (max-width: 576px) { + .human-readable-pane__frame { + padding: 0.75rem; + resize: none; + min-width: 0; + } + + .human-readable-pane__frame--markdown, + .human-readable-pane__frame--plain-text { + overflow-wrap: anywhere; + word-break: break-word; + } + + .human-readable-pane__frame--iframe { + width: 100%; + max-width: 100%; + min-height: 16rem; + height: min(var(--human-readable-pane-height, 30rem), 75vh); + } +} diff --git a/src/humanReadablePane.js b/src/humanReadablePane.ts similarity index 74% rename from src/humanReadablePane.js rename to src/humanReadablePane.ts index 76109a75..2e4bbd23 100644 --- a/src/humanReadablePane.js +++ b/src/humanReadablePane.ts @@ -7,19 +7,44 @@ import { icons, ns } from 'solid-ui' import { Util } from 'rdflib' import { marked } from 'marked' import DOMPurify from 'dompurify' +import type { DataBrowserContext, RenderEnvironment } from 'pane-registry' +import type { NamedNode } from 'rdflib' +import './humanReadablePane.css' // Helper function to check if a URI has a markdown file extension -const isMarkdownFile = (uri) => { +type DokieliCacheValue = 'dokieli' | 'html' + +type HumanReadableIcon = string | Promise + +type HumanReadablePaneDefinition = { + icon: (subject: NamedNode, context: DataBrowserContext) => HumanReadableIcon + name: string + label: (subject: NamedNode, context: DataBrowserContext) => 'view' | 'View' | null + render: (subject: NamedNode, context: DataBrowserContext) => HTMLDivElement +} + +const isMarkdownFile = (uri?: string | null): boolean => { if (!uri) return false const path = uri.split('?')[0].split('#')[0] // Remove query string and fragment return /\.(md|markdown|mdown|mkd|mkdn)$/i.test(path) } // Cache for dokieli detection results (keyed by subject URI) -const dokieliCache = new Map() +const dokieliCache = new Map() + +function applyFrameClasses ( + frame: HTMLElement, + modifier: 'markdown' | 'plain-text' | 'iframe', + lines: number +): void { + frame.className = '' + frame.classList.add('human-readable-pane__frame') + frame.classList.add(`human-readable-pane__frame--${modifier}`) + frame.style.setProperty('--human-readable-pane-height', `${lines}em`) +} -const humanReadablePane = { - icon: function (subject, context) { +const humanReadablePane: HumanReadablePaneDefinition = { + icon: function (subject: NamedNode, context: DataBrowserContext): HumanReadableIcon { // Markdown files detected by extension if (subject && isMarkdownFile(subject.uri)) { return icons.iconBase + 'markdown.svg' @@ -77,7 +102,10 @@ const humanReadablePane = { name: 'humanReadable', - label: function (subject, context) { + label: function ( + subject: NamedNode, + context: DataBrowserContext + ): 'view' | 'View' | null { const kb = context.session.store // See also the source pane, which has lower precedence. @@ -93,7 +121,11 @@ const humanReadablePane = { 'video/mp4' ] - const hasContentTypeIn = function (kb, x, displayables) { + const hasContentTypeIn = function ( + kb: typeof context.session.store, + x: NamedNode, + displayables: string[] + ): boolean { const cts = kb.fetcher.getHeader(x, 'content-type') if (cts) { for (let j = 0; j < cts.length; j++) { @@ -108,7 +140,11 @@ const humanReadablePane = { } // This data could come from a fetch OR from ldp container - const hasContentTypeIn2 = function (kb, x, displayables) { + const hasContentTypeIn2 = function ( + kb: typeof context.session.store, + x: NamedNode, + displayables: string[] + ): boolean { const t = kb.findTypeURIs(x) for (let k = 0; k < displayables.length; k++) { if (Util.mediaTypeClass(displayables[k]).uri in t) { @@ -156,11 +192,19 @@ const humanReadablePane = { return null }, - render: function (subject, context) { + render: function ( + subject: NamedNode, + context: DataBrowserContext + ): HTMLDivElement { const myDocument = context.dom const div = myDocument.createElement('div') const kb = context.session.store + function applyEnvironmentAttributes (element: HTMLDivElement): void { + const environment = (context.environment ?? {}) as Partial + element.dataset.layout = environment.layout ?? 'desktop' + } + const cts = kb.fetcher.getHeader(subject.doc(), 'content-type') const ct = cts ? cts[0].split(';', 1)[0].trim() : null // remove content-type parameters @@ -175,19 +219,18 @@ const humanReadablePane = { } // @@ When we can, use CSP to turn off scripts within the iframe - div.setAttribute('class', 'docView') - div.setAttribute('style', 'display: block; width: 100%; max-width: 100%; box-sizing: border-box;') + div.classList.add('human-readable-pane') + applyEnvironmentAttributes(div) // render markdown to html in a DIV element - const renderMarkdownContent = function (frame) { + const renderMarkdownContent = function (frame: HTMLDivElement) { kb.fetcher.webOperation('GET', subject.uri).then(response => { - const markdownText = response.responseText + const markdownText = response.responseText ?? '' const lines = Math.min(30, markdownText.split(/\n/).length + 5) - const res = marked.parse(markdownText) + const res = marked.parse(markdownText, { async: false }) const clean = DOMPurify.sanitize(res) frame.innerHTML = clean - frame.setAttribute('class', 'doc') - frame.setAttribute('style', `display: block; border: 1px solid; padding: 1em; height: ${lines}em; max-width: 100%; width: 100%; box-sizing: border-box; resize: both; overflow: auto;`) + applyFrameClasses(frame, 'markdown', lines) }).catch(error => { console.error('Error fetching markdown content:', error) frame.innerHTML = '

Error loading content

' @@ -195,44 +238,42 @@ const humanReadablePane = { } // render plain text in a PRE element - const renderPlainTextContent = function (frame) { + const renderPlainTextContent = function (frame: HTMLPreElement) { kb.fetcher.webOperation('GET', subject.uri).then(response => { - const plainText = response.responseText + const plainText = response.responseText ?? '' const lines = Math.min(30, plainText.split(/\n/).length + 5) frame.textContent = plainText - frame.setAttribute('class', 'doc') - frame.setAttribute('style', `display: block; border: 1px solid; padding: 1em; height: ${lines}em; max-width: 100%; width: 100%; box-sizing: border-box; resize: both; overflow: auto; font-family: monospace; white-space: pre-wrap; word-wrap: break-word;`) + applyFrameClasses(frame, 'plain-text', lines) }).catch(error => { console.error('Error fetching plain text content:', error) frame.textContent = 'Error loading content' }) } - const setIframeAttributes = (frame, lines) => { + const setIframeAttributes = (frame: HTMLIFrameElement, lines: number) => { frame.setAttribute('src', subject.uri) - frame.setAttribute('class', 'doc') - frame.setAttribute('style', `display: block; border: 1px solid; padding: 1em; height: ${lines}em; max-width: 100%; width: 100%; box-sizing: border-box; resize: both; overflow: auto;`) + applyFrameClasses(frame, 'iframe', lines) } if (isMarkdown) { // For markdown, use a DIV element and render the content - const frame = myDocument.createElement('DIV') + const frame = myDocument.createElement('div') renderMarkdownContent(frame) const frameContainer = myDocument.createElement('div') - frameContainer.setAttribute('style', 'display: block; width: 100%; max-width: 100%; box-sizing: border-box;') + frameContainer.classList.add('human-readable-pane__container') frameContainer.appendChild(frame) div.appendChild(frameContainer) } else if (isPlainText) { // For plain text, use a PRE element and render the content - const frame = myDocument.createElement('PRE') + const frame = myDocument.createElement('pre') renderPlainTextContent(frame) const frameContainer = myDocument.createElement('div') - frameContainer.setAttribute('style', 'display: block; width: 100%; max-width: 100%; box-sizing: border-box;') + frameContainer.classList.add('human-readable-pane__container') frameContainer.appendChild(frame) div.appendChild(frameContainer) } else { // For other content types, use IFRAME - const frame = myDocument.createElement('IFRAME') + const frame = myDocument.createElement('iframe') // Apply sandbox for HTML/XHTML if (ct === 'text/html' || ct === 'application/xhtml+xml') { @@ -241,7 +282,7 @@ const humanReadablePane = { // Fetch content to calculate lines dynamically kb.fetcher.webOperation('GET', subject.uri).then(response => { - const blobText = response.responseText + const blobText = response.responseText ?? '' const newLines = blobText.includes('