@supersoniks/concorde 4.2.1 → 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +163 -0
- package/build-infos.json +1 -1
- package/concorde-core.bundle.js +585 -670
- package/concorde-core.es.js +7165 -9505
- package/dist/concorde-core.bundle.js +585 -670
- package/dist/concorde-core.es.js +7165 -9505
- package/docs/assets/index-DP1oMukw.js +4949 -0
- package/docs/assets/index-DZtxIZCW.css +1 -0
- package/docs/index.html +2 -2
- package/{src/docs/_misc → docs/src/docs/_decorators}/ancestor-attribute.md +15 -31
- package/docs/src/docs/_decorators/bind.md +164 -0
- package/docs/src/docs/_decorators/get.md +65 -0
- package/docs/src/docs/_decorators/publish.md +54 -0
- package/docs/src/docs/_decorators/subscribe.md +36 -0
- package/docs/src/docs/_misc/dataProviderKey.md +135 -0
- package/docs/src/docs/_misc/endpoint.md +42 -0
- package/docs/src/docs/search/docs-search.json +850 -710
- package/docs/src/tsconfig.json +43 -4
- package/package.json +25 -4
- package/php/get-challenge.php +34 -0
- package/php/some-service.php +42 -0
- package/scripts/pre-build.mjs +4 -0
- package/src/core/_types/endpoint.ts +4 -0
- package/src/core/_types/key.ts +1 -0
- package/src/core/components/functional/example/example.ts +38 -6
- package/src/core/decorators/Subscriber.ts +2 -0
- package/src/core/decorators/api.spec.ts +150 -0
- package/src/core/decorators/api.ts +244 -0
- package/src/core/decorators/subscriber/bind.ts +57 -145
- package/src/core/decorators/subscriber/dynamicPath.ts +77 -0
- package/src/core/decorators/subscriber/dynamicPropertyWatch.ts +105 -0
- package/src/core/decorators/subscriber/onAssign.ts +11 -147
- package/src/core/decorators/subscriber/publish.spec.ts +21 -0
- package/src/core/decorators/subscriber/publish.ts +148 -0
- package/src/core/decorators/subscriber/publisherPath.ts +13 -0
- package/src/core/decorators/subscriber/subscribe.spec.ts +21 -0
- package/src/core/decorators/subscriber/subscribe.ts +32 -0
- package/src/core/decorators/subscriber/subscribe.type-test.ts +32 -0
- package/src/core/utils/api.ts +83 -15
- package/src/core/utils/dataProviderKey.spec.ts +34 -0
- package/src/core/utils/dataProviderKey.ts +86 -0
- package/src/core/utils/endpoint.spec.ts +41 -0
- package/src/core/utils/endpoint.ts +87 -0
- package/src/decorators.ts +14 -0
- package/{docs/src/docs/_misc → src/docs/_decorators}/ancestor-attribute.md +15 -31
- package/src/docs/_decorators/bind.md +164 -0
- package/src/docs/_decorators/get.md +65 -0
- package/src/docs/_decorators/publish.md +54 -0
- package/src/docs/_decorators/subscribe.md +36 -0
- package/src/docs/_misc/dataProviderKey.md +135 -0
- package/src/docs/_misc/endpoint.md +42 -0
- package/src/docs/example/decorators-demo-bind-demos.ts +210 -0
- package/src/docs/example/decorators-demo-geo.ts +45 -0
- package/src/docs/example/decorators-demo-init.ts +228 -0
- package/src/docs/example/decorators-demo-subscribe-publish-get-demos.ts +324 -0
- package/src/docs/example/decorators-demo.ts +12 -459
- package/src/docs/navigation/navigation.ts +27 -10
- package/src/docs/search/docs-search.json +1059 -609
- package/src/tsconfig-model.json +1 -1
- package/src/tsconfig.json +65 -1
- package/src/tsconfig.tsbuildinfo +1 -1
- package/src/utils.ts +8 -1
- package/vite/config.js +25 -6
- package/vite.config.mts +13 -0
- package/docs/assets/index-B0IJ9I_B.js +0 -4918
- package/docs/assets/index-B3QHEJTV.css +0 -1
- package/docs/src/docs/_misc/bind.md +0 -436
- package/docs/src/docs/_misc/key.md +0 -135
- package/src/docs/_misc/bind.md +0 -362
- /package/docs/src/docs/{_misc → _decorators}/auto-subscribe.md +0 -0
- /package/docs/src/docs/{_misc → _decorators}/on-assign.md +0 -0
- /package/docs/src/docs/{_misc → _decorators}/wait-for-ancestors.md +0 -0
- /package/src/docs/{_misc → _decorators}/auto-subscribe.md +0 -0
- /package/src/docs/{_misc → _decorators}/on-assign.md +0 -0
- /package/src/docs/{_misc → _decorators}/wait-for-ancestors.md +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*,:before,:after,::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border:0 solid}:before,:after{--tw-content:""}html,:host{-webkit-text-size-adjust:100%;tab-size:4;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{line-height:inherit;margin:0}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-feature-settings:normal;font-variation-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-feature-settings:inherit;font-variation-settings:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:#0000;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{margin:0;padding:0;list-style:none}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder{opacity:1;color:#9ca3af}textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (width>=640px){.container{max-width:640px}}@media (width>=768px){.container{max-width:768px}}@media (width>=1024px){.container{max-width:1024px}}@media (width>=1280px){.container{max-width:1280px}}@media (width>=1536px){.container{max-width:1536px}}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1em;margin-bottom:1em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);margin-top:1.2em;margin-bottom:1.2em;font-size:1.25em;line-height:1.6}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);font-weight:500;text-decoration:underline}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1em;margin-bottom:1em;padding-inline-start:1.625em;list-style-type:decimal}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1em;margin-bottom:1em;padding-inline-start:1.625em;list-style-type:disc}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-counters);font-weight:400}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:1.25em;font-weight:600}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-quotes);border-inline-start-width:.25rem;border-inline-start-color:var(--tw-prose-quote-borders);quotes:"“""”""‘""’";margin-top:1.6em;margin-bottom:1.6em;padding-inline-start:1em;font-style:italic;font-weight:500}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:0;margin-bottom:.888889em;font-size:2.25em;font-weight:800;line-height:1.11111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:900}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:2em;margin-bottom:1em;font-size:1.5em;font-weight:700;line-height:1.33333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:800}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:1.6em;margin-bottom:.6em;font-size:1.25em;font-weight:600;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:1.5em;margin-bottom:.5em;font-weight:600;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em;display:block}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-kbd);box-shadow:0 0 0 1px rgb(var(--tw-prose-kbd-shadows) / 10%), 0 3px 0 rgb(var(--tw-prose-kbd-shadows) / 10%);padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;border-radius:.3125rem;padding-inline-start:.375em;font-family:inherit;font-size:.875em;font-weight:500}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-size:.875em;font-weight:600}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before,.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:var(--tw-prose-pre-bg);padding-top:.857143em;padding-inline-end:1.14286em;padding-bottom:.857143em;border-radius:.375rem;margin-top:1.71429em;margin-bottom:1.71429em;padding-inline-start:1.14286em;font-size:.875em;font-weight:400;line-height:1.71429;overflow-x:auto}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit;background-color:#0000;border-width:0;border-radius:0;padding:0}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before,.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){table-layout:auto;width:100%;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.71429}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);vertical-align:bottom;padding-inline-end:.571429em;padding-bottom:.571429em;padding-inline-start:.571429em;font-weight:600}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);margin-top:.857143em;font-size:.875em;line-height:1.42857}.prose{--tw-prose-body:var(--sc-base-content);--tw-prose-headings:var(--sc-base-900);--tw-prose-lead:var(--sc-base-content);--tw-prose-links:var(--sc-base-900);--tw-prose-bold:var(--sc-base-content);--tw-prose-counters:var(--sc-base-500);--tw-prose-bullets:var(--sc-base-300);--tw-prose-hr:var(--sc-base-200);--tw-prose-quotes:var(--sc-base-content);--tw-prose-quote-borders:var(--sc-base-200);--tw-prose-captions:var(--sc-base-500);--tw-prose-kbd:#111827;--tw-prose-kbd-shadows:17 24 39;--tw-prose-code:var(--sc-info);--tw-prose-pre-code:var(--sc-base-200);--tw-prose-pre-bg:var(--sc-base-800);--tw-prose-th-borders:var(--sc-base-300);--tw-prose-td-borders:var(--sc-base-200);--tw-prose-invert-body:var(--sc-base-300);--tw-prose-invert-headings:var(--sc-base);--tw-prose-invert-lead:var(--sc-base-400);--tw-prose-invert-links:var(--sc-base);--tw-prose-invert-bold:var(--sc-base);--tw-prose-invert-counters:var(--sc-base-400);--tw-prose-invert-bullets:var(--sc-base-600);--tw-prose-invert-hr:var(--sc-base-700);--tw-prose-invert-quotes:var(--sc-base-100);--tw-prose-invert-quote-borders:var(--sc-base-700);--tw-prose-invert-captions:var(--sc-base-400);--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:255 255 255;--tw-prose-invert-code:var(--sc-base);--tw-prose-invert-pre-code:var(--sc-base-300);--tw-prose-invert-pre-bg:var(--sc-base-900);--tw-prose-invert-th-borders:var(--sc-base-600);--tw-prose-invert-td-borders:var(--sc-base-700);font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em;list-style-type:disc}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.571429em;padding-inline-end:.571429em;padding-bottom:.571429em;padding-inline-start:.571429em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose{line-height:1.5}.prose :where(strong a):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:bolder}.prose :where(iframe[src*=youtu]):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:var(--sc-rounded-md)}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.\!relative{position:relative!important}.relative{position:relative}.sticky{position:sticky}.\!left-0{left:0!important}.\!top-0{top:0!important}.-top-1{top:-.25rem}.bottom-1{bottom:.25rem}.bottom-2{bottom:.5rem}.left-0{left:0}.right-1{right:.25rem}.right-2{right:.5rem}.top-0{top:0}.top-16{top:4rem}.top-\[4\.2rem\]{top:4.2rem}.z-10{z-index:10}.z-20{z-index:20}.z-40{z-index:40}.z-\[3000\]{z-index:3000}.col-span-2{grid-column:span 2/span 2}.col-span-full{grid-column:1/-1}.m-2{margin:.5rem}.-mx-2{margin-left:-.5rem;margin-right:-.5rem}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.mb-0{margin-bottom:0}.mb-1{margin-bottom:.25rem}.mb-10{margin-bottom:2.5rem}.mb-2{margin-bottom:.5rem}.mb-20{margin-bottom:5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-40{margin-bottom:10rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-3{margin-left:.75rem}.ml-5{margin-left:1.25rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mr-4{margin-right:1rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.mt-9{margin-top:2.25rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.size-40{width:10rem;height:10rem}.size-\[2\.4rem\]{width:2.4rem;height:2.4rem}.h-1\/2{height:50%}.h-10{height:2.5rem}.h-12{height:3rem}.h-3{height:.75rem}.h-4{height:1rem}.h-96{height:24rem}.h-full{height:100%}.max-h-\[50vh\]{max-height:50vh}.max-h-\[calc\(100vh_-_4\.2rem\)\]{max-height:calc(100vh - 4.2rem)}.min-h-\[100vh\]{min-height:100vh}.w-1\/2{width:50%}.w-1\/3{width:33.3333%}.w-12{width:3rem}.w-16{width:4rem}.w-20{width:5rem}.w-24{width:6rem}.w-64{width:16rem}.w-\[5rem\]{width:5rem}.w-full{width:100%}.min-w-\[8rem\]{min-width:8rem}.max-w-\[29ch\]{max-width:29ch}.max-w-\[40rem\]{max-width:40rem}.max-w-lg{max-width:32rem}.max-w-prose{max-width:70ch}.flex-1{flex:1}.flex-shrink{flex-shrink:1}.flex-grow{flex-grow:1}.-translate-y-1\/2{--tw-translate-y:-50%;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-1\/2{--tw-translate-x:50%;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-1\/2{--tw-translate-y:50%;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-90{--tw-rotate:90deg;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-\[55deg\]{--tw-rotate:55deg;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:2s cubic-bezier(.4,0,.6,1) infinite pulse}.resize{resize:both}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-\[minmax\(10rem\,15rem\)_minmax\(0\,1fr\)\]{grid-template-columns:minmax(10rem,15rem) minmax(0,1fr)}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.gap-x-1{-moz-column-gap:.25rem;column-gap:.25rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-x-6{-moz-column-gap:1.5rem;column-gap:1.5rem}.gap-y-2{row-gap:.5rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.rounded{border-radius:var(--sc-rounded)}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--sc-rounded-lg)}.rounded-md{border-radius:var(--sc-rounded-md)}.rounded-xl{border-radius:var(--sc-rounded-xl)}.border{border-width:var(--sc-border-width)}.border-0{border-width:0}.border-b-\[\.18rem\]{border-bottom-width:.18rem}.border-b-\[1px\]{border-bottom-width:1px}.border-t-2{border-top-width:2px}.border-solid{border-style:solid}.border-dotted{border-style:dotted}.border-current{border-color:currentColor}.border-neutral-100{border-color:var(--sc-base-100)}.border-neutral-200{border-color:var(--sc-base-200)}.border-b-neutral-300{border-bottom-color:var(--sc-base-300)}.border-t-neutral-200{border-top-color:var(--sc-base-200)}.bg-info{background-color:var(--sc-info)}.bg-neutral-0{background-color:var(--sc-base)}.bg-neutral-100{background-color:var(--sc-base-100)}.bg-neutral-200{background-color:var(--sc-base-200)}.bg-neutral-900{background-color:var(--sc-base-900)}.bg-success{background-color:var(--sc-success)}.bg-gradient-to-b{background-image:linear-gradient(to bottom, var(--tw-gradient-stops))}.from-\[rgba\(0\,0\,10\,\.2\)\]{--tw-gradient-from:#00000a33 var(--tw-gradient-from-position);--tw-gradient-to:#00000a00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-8{padding:2rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pl-5{padding-left:1.25rem}.pl-\[\.75rem\]{padding-left:.75rem}.pt-3{padding-top:.75rem}.pt-\[20vh\]{padding-top:20vh}.text-center{text-align:center}.font-headings{font-family:var(--sc-headings-font-family,var(--sc-font-family-base,sans-serif))}.text-2xl{font-size:1.5rem}.text-3xl{font-size:1.875rem}.text-4xl{font-size:2.25rem}.text-base{font-size:1rem}.text-lg{font-size:1.125rem}.text-sm{font-size:.875rem}.text-xl{font-size:1.25rem}.text-xs{font-size:.75rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.italic{font-style:italic}.leading-\[1\.5\]{line-height:1.5}.leading-none{line-height:1}.leading-tight{line-height:1.25}.text-content{color:var(--sc-base-content)}.text-contrast-content{color:var(--sc-contrast-content)}.text-danger{color:var(--sc-danger)}.text-info{color:var(--sc-info)}.text-neutral-0{color:var(--sc-base)}.text-neutral-400{color:var(--sc-base-400)}.text-neutral-500{color:var(--sc-base-500)}.text-neutral-600{color:var(--sc-base-600)}.text-neutral-700{color:var(--sc-base-700)}.text-neutral-900{color:var(--sc-base-900)}.text-success{color:var(--sc-success)}.underline{text-decoration-line:underline}.opacity-40{opacity:.4}.opacity-90{opacity:.9}.shadow{--tw-shadow:0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.outline{outline-style:solid}.blur{--tw-blur:blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.drop-shadow{--tw-drop-shadow:drop-shadow(0 1px 2px #0000001a) drop-shadow(0 1px 1px #0000000f);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.drop-shadow-lg{--tw-drop-shadow:drop-shadow(0 10px 8px #0000000a) drop-shadow(0 4px 3px #0000001a);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.invert{--tw-invert:invert(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter,backdrop-filter;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-all{transition-property:all;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}@font-face{font-family:ClashGrotesk-Variable;src:url(../fonts/ClashGrotesk-Variable.woff2)format("woff2"),url(../fonts/ClashGrotesk-Variable.woff)format("woff"),url(../fonts/ClashGrotesk-Variable.ttf)format("truetype");font-weight:200 700;font-display:swap;font-style:normal}:root{--sc-headings-font-family:"ClashGrotesk-Variable", sans-serif;--sc-font-family-base:"ClashGrotesk-Variable", sans-serif;--sc-headings-font-weight:400;--sc-rounded:.5rem;--sc-border-width:max(2px, .18rem)}[data-concorde-theme=light]{--sc-base:#fffcf0;--sc-base-content:#111;--sc-primary:#111;--sc-primary-content:#fffcf0;--sc-base-50:#f4f1e6;--sc-base-100:#e9e6dc;--sc-base-200:#ceccc3;--sc-base-300:#bcbab1;--sc-base-400:#96948e;--sc-base-500:#7d7c77;--sc-base-600:#5a5956;--sc-base-700:#393937;--sc-base-800:#252524;--sc-base-900:#111;--sc-info:#3b82f6;--sc-info-content:#fff;--sc-success:#10b981;--sc-success-content:#fff;--sc-warning:#fb923c;--sc-warning-content:#111827;--sc-danger:#dc2626;--sc-danger-content:#fff}[data-concorde-theme=dark]{--sc-base:#0a0a0a;--sc-base-content:#dadad9;--sc-primary:#ffef8a;--sc-primary-content:#111827;--sc-base-50:#141414;--sc-base-100:#1c1c1c;--sc-base-200:#2f2f2f;--sc-base-300:#3e3e3e;--sc-base-400:#5f5f5f;--sc-base-500:#767676;--sc-base-600:#9a9a9a;--sc-base-700:#c0c0bf;--sc-base-800:#dadad9;--sc-base-900:#f5f5f4;--sc-info:#3a85f7;--sc-info-content:#fff;--sc-success:#0fba7f;--sc-success-content:#fff;--sc-warning:#fc8f3b;--sc-warning-content:#111827;--sc-danger:#dd2528;--sc-danger-content:#fff}[data-concorde-theme=light],[data-concorde-theme=dark]{--sc-input-bg:var(--sc-base-100);--sc-input-border-color:var(--sc-base-100)}html{font-family:var(--sc-font-family-base,sans-serif)}h2{border-bottom:var(--sc-border-width) solid;padding-bottom:.1em}p,ul,ol{font-family:Arial,Helvetica,sans-serif}body{background:var(--sc-base);color:var(--sc-base-content)}html{scroll-behavior:smooth}.animated-text{display:block;position:relative;overflow:hidden}.animated-text span{width:100%;height:100%;animation:4.5s cubic-bezier(.17,.67,.61,1.13) infinite slideUp;display:block;position:absolute;top:0;left:0;transform:translateY(108%)}.animated-text span:nth-child(2){animation-delay:1.5s}.animated-text span:nth-child(3){animation-delay:3s}@keyframes slideUp{0%{transform:translateY(108%)}7%{transform:translateY(0)}33%{transform:translateY(0)}40%{transform:translateY(-108%)}to{transform:translateY(-108%)}}.custom-scroll{overflow:auto!important}.custom-scroll:hover::-webkit-scrollbar-thumb{box-shadow:inset 0 0 2rem 2rem var(--sc-base-900)}.custom-scroll::-webkit-scrollbar{border-radius:var(--sc-rounded);background:0 0;border:.15rem solid #0000;width:.5rem;height:.5rem}.custom-scroll::-webkit-scrollbar-thumb{opacity:0;border:.15rem solid #0000;transition:box-shadow .2s}@media (width>=1024px){.lg\:prose-lg{font-size:1.125rem;line-height:1.77778}.lg\:prose-lg :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.33333em;margin-bottom:1.33333em}.lg\:prose-lg :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.09091em;margin-bottom:1.09091em;font-size:1.22222em;line-height:1.45455}.lg\:prose-lg :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.66667em;margin-bottom:1.66667em;padding-inline-start:1em}.lg\:prose-lg :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:.833333em;font-size:2.66667em;line-height:1}.lg\:prose-lg :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.86667em;margin-bottom:1.06667em;font-size:1.66667em;line-height:1.33333}.lg\:prose-lg :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.66667em;margin-bottom:.666667em;font-size:1.33333em;line-height:1.5}.lg\:prose-lg :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.77778em;margin-bottom:.444444em;line-height:1.55556}.lg\:prose-lg :where(img):not(:where([class~=not-prose],[class~=not-prose] *)),.lg\:prose-lg :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.77778em;margin-bottom:1.77778em}.lg\:prose-lg :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.lg\:prose-lg :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.77778em;margin-bottom:1.77778em}.lg\:prose-lg :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.222222em;padding-inline-end:.444444em;padding-bottom:.222222em;border-radius:.3125rem;padding-inline-start:.444444em;font-size:.888889em}.lg\:prose-lg :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.888889em}.lg\:prose-lg :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.866667em}.lg\:prose-lg :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em}.lg\:prose-lg :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:1em;padding-inline-end:1.5em;padding-bottom:1em;border-radius:.375rem;margin-top:2em;margin-bottom:2em;padding-inline-start:1.5em;font-size:.888889em;line-height:1.75}.lg\:prose-lg :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)),.lg\:prose-lg :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.33333em;margin-bottom:1.33333em;padding-inline-start:1.55556em}.lg\:prose-lg :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.666667em;margin-bottom:.666667em}.lg\:prose-lg :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)),.lg\:prose-lg :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.444444em}.lg\:prose-lg :where(.lg\:prose-lg>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.888889em;margin-bottom:.888889em}.lg\:prose-lg :where(.lg\:prose-lg>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.33333em}.lg\:prose-lg :where(.lg\:prose-lg>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.33333em}.lg\:prose-lg :where(.lg\:prose-lg>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.33333em}.lg\:prose-lg :where(.lg\:prose-lg>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.33333em}.lg\:prose-lg :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.888889em;margin-bottom:.888889em}.lg\:prose-lg :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.33333em;margin-bottom:1.33333em}.lg\:prose-lg :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.33333em}.lg\:prose-lg :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.666667em;padding-inline-start:1.55556em}.lg\:prose-lg :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:3.11111em;margin-bottom:3.11111em}.lg\:prose-lg :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)),.lg\:prose-lg :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)),.lg\:prose-lg :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)),.lg\:prose-lg :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.lg\:prose-lg :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.888889em;line-height:1.5}.lg\:prose-lg :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:.75em;padding-bottom:.75em;padding-inline-start:.75em}.lg\:prose-lg :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.lg\:prose-lg :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.lg\:prose-lg :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.75em;padding-inline-end:.75em;padding-bottom:.75em;padding-inline-start:.75em}.lg\:prose-lg :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.lg\:prose-lg :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.lg\:prose-lg :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.77778em;margin-bottom:1.77778em}.lg\:prose-lg :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.lg\:prose-lg :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1em;font-size:.888889em;line-height:1.5}.lg\:prose-lg :where(.lg\:prose-lg>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.lg\:prose-lg :where(.lg\:prose-lg>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}}.hover\:bg-neutral-50:hover{background-color:var(--sc-base-50)}.prose-h1\:text-\[4\.2em\] :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:4.2em}.prose-h1\:font-normal :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:400}.prose-li\:my-\[\.2em\] :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.2em;margin-bottom:.2em}@media (width>=640px){.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (width>=768px){.md\:text-5xl{font-size:3rem}}@media (width>=1024px){.lg\:min-w-\[19rem\]{min-width:19rem}.lg\:max-w-\[19ch\]{max-width:19ch}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:px-20{padding-left:5rem;padding-right:5rem}.lg\:text-7xl{font-size:4.5rem}.lg\:leading-\[1\.5\]{line-height:1.5}}@media (width>=1280px){.xl\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.xl\:text-8xl{font-size:6rem}}.dark\:block:where(.dark,.dark *){display:block}.dark\:hidden:where(.dark,.dark *){display:none}.dark\:border-neutral-700:where(.dark,.dark *){border-color:var(--sc-base-700)}.dark\:bg-neutral-300:where(.dark,.dark *){background-color:var(--sc-base-300)}.dark\:text-neutral-400:where(.dark,.dark *){color:var(--sc-base-400)}.dark\:opacity-60:where(.dark,.dark *){opacity:.6}.\[\&\[active\]\]\:min-w-\[13rem\][active]{min-width:13rem}.\[\&\[active\]\]\:rounded-full[active]{border-radius:9999px}.\[\&\[active\]\]\:bg-danger[active]{background-color:var(--sc-danger)}.\[\&\[active\]\]\:font-black[active]{font-weight:900}.\[\&\[active\]\]\:text-danger-content[active]{color:var(--sc-danger-content)}.\[\&\[active\]\]\:text-success[active]{color:var(--sc-success)}[data-home] .\[\[data-home\]_\&\]\:hidden{display:none}
|
package/docs/index.html
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
<!-- <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
11
11
|
-->
|
|
12
12
|
<script src="https://cdn.jsdelivr.net/npm/marked@13.0.3"></script>
|
|
13
|
-
<script type="module" crossorigin src="./assets/index-
|
|
14
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
13
|
+
<script type="module" crossorigin src="./assets/index-DP1oMukw.js"></script>
|
|
14
|
+
<link rel="stylesheet" crossorigin href="./assets/index-DZtxIZCW.css">
|
|
15
15
|
</head>
|
|
16
16
|
<body class="px-6 lg:px-20">
|
|
17
17
|
<sonic-theme
|
|
@@ -17,45 +17,29 @@ import { ancestorAttribute } from "@supersoniks/concorde/decorators";
|
|
|
17
17
|
</sonic-code>
|
|
18
18
|
|
|
19
19
|
### Basic example
|
|
20
|
-
|
|
20
|
+
|
|
21
|
+
The component reads `dataProvider` and `testAttribute` from its ancestor wrapper.
|
|
21
22
|
|
|
22
23
|
<sonic-code language="typescript">
|
|
23
24
|
<template>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
static styles = [tailwind];
|
|
25
|
+
import { html, LitElement } from "lit";
|
|
26
|
+
import { customElement } from "lit/decorators.js";
|
|
27
|
+
import { ancestorAttribute } from "@supersoniks/concorde/decorators";
|
|
28
28
|
//
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
@customElement("demo-ancestor-attribute")
|
|
30
|
+
export class DemoAncestorAttribute extends LitElement {
|
|
31
|
+
@ancestorAttribute("dataProvider")
|
|
32
|
+
dataProvider: string | null = null;
|
|
32
33
|
//
|
|
33
|
-
@
|
|
34
|
-
|
|
35
|
-
withoutReflect: number = 0;
|
|
36
|
-
// initialize the publisher data
|
|
37
|
-
connectedCallback() {
|
|
38
|
-
super.connectedCallback();
|
|
39
|
-
this.resetData();
|
|
40
|
-
}
|
|
34
|
+
@ancestorAttribute("testAttribute")
|
|
35
|
+
testAttribute: string | null = null;
|
|
41
36
|
//
|
|
42
|
-
resetData() {
|
|
43
|
-
PublisherManager.get("bindReflectDemo").set({ count: 0 });
|
|
44
|
-
}
|
|
45
37
|
render() {
|
|
46
38
|
return html`
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
</div>
|
|
52
|
-
<sonic-button @click=${() => this.withReflect++}
|
|
53
|
-
>Increment with reflect</sonic-button
|
|
54
|
-
>
|
|
55
|
-
<sonic-button @click=${() => this.withoutReflect++}
|
|
56
|
-
>Increment without reflect</sonic-button
|
|
57
|
-
>
|
|
58
|
-
<sonic-button @click=${this.resetData}>Reset publisher data</sonic-button>
|
|
39
|
+
<section>
|
|
40
|
+
<p>dataProvider: <strong>${this.dataProvider || "null"}</strong></p>
|
|
41
|
+
<p>testAttribute: <strong>${this.testAttribute || "null"}</strong></p>
|
|
42
|
+
</section>
|
|
59
43
|
`;
|
|
60
44
|
}
|
|
61
45
|
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# @bind
|
|
2
|
+
|
|
3
|
+
Binds a class property to a path in a publisher. The property updates when publisher data changes.
|
|
4
|
+
|
|
5
|
+
For Lit re-renders, also add `@state()` on the same property.
|
|
6
|
+
|
|
7
|
+
**See also:** [@subscribe](#docs/_decorators/subscribe.md/subscribe), [@publish](#docs/_decorators/publish.md/publish), [@get](#docs/_decorators/get.md/get).
|
|
8
|
+
|
|
9
|
+
## Principle
|
|
10
|
+
|
|
11
|
+
The decorator subscribes via `PublisherManager` using dot notation. Publisher updates flow into the decorated property.
|
|
12
|
+
|
|
13
|
+
## Import
|
|
14
|
+
|
|
15
|
+
<sonic-code language="typescript">
|
|
16
|
+
<template>
|
|
17
|
+
import { bind } from "@supersoniks/concorde/decorators";
|
|
18
|
+
</template>
|
|
19
|
+
</sonic-code>
|
|
20
|
+
|
|
21
|
+
## Example
|
|
22
|
+
|
|
23
|
+
<sonic-code language="typescript">
|
|
24
|
+
<template>
|
|
25
|
+
@customElement("demo-bind")
|
|
26
|
+
export class DemoBind extends LitElement {
|
|
27
|
+
static styles = [tailwind];
|
|
28
|
+
//
|
|
29
|
+
@bind("demoData.firstName")
|
|
30
|
+
@state()
|
|
31
|
+
firstName = "";
|
|
32
|
+
//
|
|
33
|
+
@bind("demoData.lastName")
|
|
34
|
+
@state()
|
|
35
|
+
lastName: string = "";
|
|
36
|
+
//
|
|
37
|
+
@bind("demoData.count")
|
|
38
|
+
@state()
|
|
39
|
+
count: number = 0;
|
|
40
|
+
//
|
|
41
|
+
render() {
|
|
42
|
+
return //......
|
|
43
|
+
}
|
|
44
|
+
//
|
|
45
|
+
updateData() {
|
|
46
|
+
const demoData = PublisherManager.get("demoData");
|
|
47
|
+
const demoUsers = PublisherManager.get("demoUsers");
|
|
48
|
+
const randomIndex = Math.floor(Math.random() * demoUsers.get().length);
|
|
49
|
+
const randomUser = demoUsers.get()[randomIndex];
|
|
50
|
+
demoData.set({
|
|
51
|
+
firstName: randomUser.firstName,
|
|
52
|
+
lastName: randomUser.lastName,
|
|
53
|
+
count: (demoData.count.get() || 0) + 1,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//
|
|
58
|
+
</template>
|
|
59
|
+
</sonic-code>
|
|
60
|
+
|
|
61
|
+
<sonic-code>
|
|
62
|
+
<template>
|
|
63
|
+
<demo-bind></demo-bind>
|
|
64
|
+
</template>
|
|
65
|
+
</sonic-code>
|
|
66
|
+
|
|
67
|
+
## `DataProviderKey` (strict typing)
|
|
68
|
+
|
|
69
|
+
`@bind` accepts either a string path (legacy) or a `DataProviderKey<T>`. The property type must match `T`. Use `reflect: true` to push local writes back to the publisher (see below). See [DataProviderKey](#docs/_misc/dataProviderKey.md/dataProviderKey).
|
|
70
|
+
|
|
71
|
+
<sonic-code language="typescript">
|
|
72
|
+
<template>
|
|
73
|
+
import { bind } from "@supersoniks/concorde/decorators";
|
|
74
|
+
import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
|
|
75
|
+
//
|
|
76
|
+
type Data = { count: number };
|
|
77
|
+
const dataKey = new DataProviderKey<Data>("data");
|
|
78
|
+
//
|
|
79
|
+
@bind(dataKey.count, { reflect: true })
|
|
80
|
+
@state()
|
|
81
|
+
count: number = 0;
|
|
82
|
+
</template>
|
|
83
|
+
</sonic-code>
|
|
84
|
+
|
|
85
|
+
## Reflect (`reflect: true`)
|
|
86
|
+
|
|
87
|
+
Two-way sync: reads from the publisher and local assignments call `publisher.set(...)`. An internal guard avoids infinite loops.
|
|
88
|
+
|
|
89
|
+
<sonic-code language="typescript">
|
|
90
|
+
<template>
|
|
91
|
+
@bind("userData.profile.avatarUrl", { reflect: true })
|
|
92
|
+
@state()
|
|
93
|
+
avatar: string;
|
|
94
|
+
</template>
|
|
95
|
+
</sonic-code>
|
|
96
|
+
|
|
97
|
+
<sonic-code language="typescript">
|
|
98
|
+
<template>
|
|
99
|
+
@customElement("demo-bind-reflect")
|
|
100
|
+
export class DemoBindReflect extends LitElement {
|
|
101
|
+
static styles = [tailwind];
|
|
102
|
+
//
|
|
103
|
+
@bind("bindReflectDemo.count", { reflect: true })
|
|
104
|
+
@state()
|
|
105
|
+
withReflect: number = 0;
|
|
106
|
+
//
|
|
107
|
+
@bind("bindReflectDemo.count")
|
|
108
|
+
@state()
|
|
109
|
+
withoutReflect: number = 0;
|
|
110
|
+
//
|
|
111
|
+
render() {
|
|
112
|
+
return html`
|
|
113
|
+
<div class="mb-3">
|
|
114
|
+
from publisher : ${sub("bindReflectDemo.count") || 0} <br />
|
|
115
|
+
from component with reflect : ${this.withReflect || 0} <br />
|
|
116
|
+
from component without reflect : ${this.withoutReflect || 0}
|
|
117
|
+
</div>
|
|
118
|
+
<sonic-button @click=${() => this.withReflect++}
|
|
119
|
+
>Increment with reflect</sonic-button
|
|
120
|
+
>
|
|
121
|
+
<sonic-button @click=${() => this.withoutReflect++}
|
|
122
|
+
>Increment without reflect</sonic-button
|
|
123
|
+
>
|
|
124
|
+
`;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//
|
|
128
|
+
</template>
|
|
129
|
+
</sonic-code>
|
|
130
|
+
|
|
131
|
+
<sonic-code toggleCode>
|
|
132
|
+
<template>
|
|
133
|
+
<demo-bind-reflect></demo-bind-reflect>
|
|
134
|
+
</template>
|
|
135
|
+
</sonic-code>
|
|
136
|
+
|
|
137
|
+
## Path syntax
|
|
138
|
+
|
|
139
|
+
- First segment: data provider id.
|
|
140
|
+
- Nested properties: dot notation.
|
|
141
|
+
- Arrays: numeric index (`items.0`).
|
|
142
|
+
|
|
143
|
+
### Dynamic paths
|
|
144
|
+
|
|
145
|
+
Use `${prop}` or `${this.prop}` inside a **normal string literal** (not a JS template literal with backticks). `@bind` re-subscribes when a reactive dependency changes.
|
|
146
|
+
|
|
147
|
+
> Properties referenced in the pattern must be reactive (`@property`, etc.) or you must call `requestUpdate` manually.
|
|
148
|
+
|
|
149
|
+
<sonic-code>
|
|
150
|
+
<template>
|
|
151
|
+
<demo-bind-dynamic></demo-bind-dynamic>
|
|
152
|
+
</template>
|
|
153
|
+
</sonic-code>
|
|
154
|
+
|
|
155
|
+
## Behavior
|
|
156
|
+
|
|
157
|
+
- Subscribes at `connectedCallback`, unsubscribes at `disconnectedCallback`.
|
|
158
|
+
- If the path does not exist yet, a publisher may be created with `null`.
|
|
159
|
+
|
|
160
|
+
## Notes
|
|
161
|
+
|
|
162
|
+
Works with any component that has the usual DOM lifecycle (`LitElement`, `Subscriber` mixin, etc.).
|
|
163
|
+
|
|
164
|
+
Shared data: [Sharing data](#docs/_getting-started/pubsub.md/pubsub).
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# @get
|
|
2
|
+
|
|
3
|
+
Loads data through [`API.getDetailed`](../../core/utils/api.ts). The decorated property is **`ApiGetResult<T> | null`**: `request`, `response` (or `null` for `dataProvider(...)` resolution without HTTP), and typed `result`.
|
|
4
|
+
|
|
5
|
+
Pass an [`Endpoint<T>`](#docs/_misc/endpoint.md/endpoint) as the first argument. Import `get` and `ApiGetResult` from `@supersoniks/concorde/decorators`, and `Endpoint` from `@supersoniks/concorde/utils/endpoint`.
|
|
6
|
+
|
|
7
|
+
## Configuration
|
|
8
|
+
|
|
9
|
+
- **Default:** `HTML.getApiConfiguration(host)` (ancestor `serviceURL`, etc.).
|
|
10
|
+
- **Second argument:** `DataProviderKey<APIConfiguration>` — config is read from the publisher at the resolved path; internal mutations trigger another GET.
|
|
11
|
+
|
|
12
|
+
## When the GET runs again
|
|
13
|
+
|
|
14
|
+
- A referenced Lit property changes (endpoint path and/or config key contains `${...}`).
|
|
15
|
+
- `set` on the active configuration publisher (`onInternalMutation`).
|
|
16
|
+
|
|
17
|
+
## Import
|
|
18
|
+
|
|
19
|
+
<sonic-code language="typescript">
|
|
20
|
+
<template>
|
|
21
|
+
import { get, type ApiGetResult } from "@supersoniks/concorde/decorators";
|
|
22
|
+
import { Endpoint } from "@supersoniks/concorde/utils/endpoint";
|
|
23
|
+
import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
|
|
24
|
+
</template>
|
|
25
|
+
</sonic-code>
|
|
26
|
+
|
|
27
|
+
## Minimal example
|
|
28
|
+
|
|
29
|
+
Same demo service as [`sonic-queue`](../../core/components/functional/queue/queue.demo.ts) (`geo.api.gouv.fr`). Publisher setup lives in `decorators-demo-geo.ts` and `decorators-demo-subscribe-publish-get-demos.ts`.
|
|
30
|
+
|
|
31
|
+
<sonic-code language="typescript">
|
|
32
|
+
<template>
|
|
33
|
+
@get(new Endpoint<User>("users/${userId}"))
|
|
34
|
+
@state()
|
|
35
|
+
payload: ApiGetResult<User> | null = null;
|
|
36
|
+
</template>
|
|
37
|
+
</sonic-code>
|
|
38
|
+
|
|
39
|
+
## Live demos
|
|
40
|
+
|
|
41
|
+
<sonic-code>
|
|
42
|
+
<template>
|
|
43
|
+
<demo-api-get></demo-api-get>
|
|
44
|
+
</template>
|
|
45
|
+
</sonic-code>
|
|
46
|
+
|
|
47
|
+
Dynamic config and endpoint path (`demo-api-get-configuration-key` in doc sources):
|
|
48
|
+
|
|
49
|
+
<sonic-code>
|
|
50
|
+
<template>
|
|
51
|
+
<demo-api-get-configuration-key></demo-api-get-configuration-key>
|
|
52
|
+
</template>
|
|
53
|
+
</sonic-code>
|
|
54
|
+
|
|
55
|
+
Scoped `@get` with `@publish` / `@subscribe` on the payload (see [@publish](#docs/_decorators/publish.md/publish) and [@subscribe](#docs/_decorators/subscribe.md/subscribe)) — wrap under an ancestor with `serviceURL="https://geo.api.gouv.fr/"`:
|
|
56
|
+
|
|
57
|
+
<sonic-code>
|
|
58
|
+
<template>
|
|
59
|
+
<div serviceURL="https://geo.api.gouv.fr/">
|
|
60
|
+
<demo-api-get-publish-subscribe></demo-api-get-publish-subscribe>
|
|
61
|
+
</div>
|
|
62
|
+
</template>
|
|
63
|
+
</sonic-code>
|
|
64
|
+
|
|
65
|
+
Stale responses are ignored if the path or generation changed before the request finished.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# @publish
|
|
2
|
+
|
|
3
|
+
Write-only binding: assigning to the property publishes to the `DataProviderKey` path. No read subscription (inverse of [@subscribe](#docs/_decorators/subscribe.md/subscribe)).
|
|
4
|
+
|
|
5
|
+
Similar to the “reflect” half of [@bind](#docs/_decorators/bind.md/bind) without listening to the publisher.
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
<sonic-code language="typescript">
|
|
10
|
+
<template>
|
|
11
|
+
import { publish } from "@supersoniks/concorde/decorators";
|
|
12
|
+
import { sub } from "@supersoniks/concorde/directives";
|
|
13
|
+
import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
|
|
14
|
+
</template>
|
|
15
|
+
</sonic-code>
|
|
16
|
+
|
|
17
|
+
## Example
|
|
18
|
+
|
|
19
|
+
<sonic-code language="typescript">
|
|
20
|
+
<template>
|
|
21
|
+
type PublishDemoData = { email: string; message: string };
|
|
22
|
+
const publishDemoKey = new DataProviderKey<PublishDemoData>("publishDemo");
|
|
23
|
+
//
|
|
24
|
+
@customElement("demo-publish")
|
|
25
|
+
export class DemoPublish extends LitElement {
|
|
26
|
+
@publish(publishDemoKey.email)
|
|
27
|
+
@state()
|
|
28
|
+
email = "";
|
|
29
|
+
//
|
|
30
|
+
@publish(publishDemoKey.message)
|
|
31
|
+
@state()
|
|
32
|
+
message = "";
|
|
33
|
+
//
|
|
34
|
+
render() {
|
|
35
|
+
return html`
|
|
36
|
+
<sonic-input
|
|
37
|
+
.value=${this.email}
|
|
38
|
+
@input=${(e) => (this.email = (e.target as HTMLInputElement).value)}
|
|
39
|
+
label="Email"
|
|
40
|
+
></sonic-input>
|
|
41
|
+
<p>${sub("publishDemo.email")}</p>
|
|
42
|
+
`;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
</template>
|
|
46
|
+
</sonic-code>
|
|
47
|
+
|
|
48
|
+
<sonic-code>
|
|
49
|
+
<template>
|
|
50
|
+
<demo-publish></demo-publish>
|
|
51
|
+
</template>
|
|
52
|
+
</sonic-code>
|
|
53
|
+
|
|
54
|
+
Dynamic paths use the same placeholder rules as `@bind` / `@subscribe`.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# @subscribe
|
|
2
|
+
|
|
3
|
+
Read-only binding: **only** `DataProviderKey<T>` (no legacy string path). No `reflect` option — the publisher updates the property, not the other way around.
|
|
4
|
+
|
|
5
|
+
For bidirectional binding or string paths, use [@bind](#docs/_decorators/bind.md/bind).
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
<sonic-code language="typescript">
|
|
10
|
+
<template>
|
|
11
|
+
import { subscribe } from "@supersoniks/concorde/decorators";
|
|
12
|
+
import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
|
|
13
|
+
//
|
|
14
|
+
type Data = { count: number };
|
|
15
|
+
const dataKey = new DataProviderKey<Data>("data");
|
|
16
|
+
//
|
|
17
|
+
@subscribe(dataKey.count)
|
|
18
|
+
@state()
|
|
19
|
+
count = 0;
|
|
20
|
+
</template>
|
|
21
|
+
</sonic-code>
|
|
22
|
+
|
|
23
|
+
## Highlights
|
|
24
|
+
|
|
25
|
+
- Strict typing: the property type must match `T`.
|
|
26
|
+
- Dynamic paths: placeholders in `DataProviderKey`, resolved from the host component’s properties.
|
|
27
|
+
|
|
28
|
+
## Demo
|
|
29
|
+
|
|
30
|
+
<sonic-code>
|
|
31
|
+
<template>
|
|
32
|
+
<demo-subscribe-dynamic></demo-subscribe-dynamic>
|
|
33
|
+
</template>
|
|
34
|
+
</sonic-code>
|
|
35
|
+
|
|
36
|
+
See also [DataProviderKey](#docs/_misc/dataProviderKey.md/dataProviderKey).
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# DataProviderKey
|
|
2
|
+
|
|
3
|
+
The `DataProviderKey<T>` utility provides type-safe navigation through composite data structures. Each property or index access extends the path, and the final key can be retrieved via `toString()` or the `path` property.
|
|
4
|
+
|
|
5
|
+
For a **single HTTP path string** (no dot-syntax), see [Endpoint](#docs/_misc/endpoint.md/endpoint).
|
|
6
|
+
|
|
7
|
+
## Principle
|
|
8
|
+
|
|
9
|
+
`DataProviderKey` uses a Proxy to intercept property access and build a cumulative path string. TypeScript infers the nested type at each level, so `myKey.items[0]` is correctly typed as `DataProviderKey<Item>` when `items` is `Item[]`.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Import
|
|
14
|
+
|
|
15
|
+
<sonic-code language="typescript">
|
|
16
|
+
<template>
|
|
17
|
+
import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
|
|
18
|
+
</template>
|
|
19
|
+
</sonic-code>
|
|
20
|
+
|
|
21
|
+
### Basic example
|
|
22
|
+
|
|
23
|
+
<sonic-code language="typescript">
|
|
24
|
+
<template>
|
|
25
|
+
type Item = { id: string; name: string };
|
|
26
|
+
//
|
|
27
|
+
type Data = {
|
|
28
|
+
items: Item[];
|
|
29
|
+
count: number;
|
|
30
|
+
};
|
|
31
|
+
//
|
|
32
|
+
const myKey = new DataProviderKey<Data>("data").items[0];
|
|
33
|
+
// Equivalent to: new DataProviderKey<Item>("data.items.0")
|
|
34
|
+
myKey.toString(); // "data.items.0"
|
|
35
|
+
myKey.path; // same value
|
|
36
|
+
// myKey is typed as DataProviderKey<Item>
|
|
37
|
+
</template>
|
|
38
|
+
</sonic-code>
|
|
39
|
+
|
|
40
|
+
### Object property access
|
|
41
|
+
|
|
42
|
+
<sonic-code language="typescript">
|
|
43
|
+
<template>
|
|
44
|
+
const key = new DataProviderKey<Data>("data");
|
|
45
|
+
const countKey = key.count;
|
|
46
|
+
countKey.path; // "data.count"
|
|
47
|
+
countKey.toString(); // "data.count"
|
|
48
|
+
</template>
|
|
49
|
+
</sonic-code>
|
|
50
|
+
|
|
51
|
+
### Array index access
|
|
52
|
+
|
|
53
|
+
<sonic-code language="typescript">
|
|
54
|
+
<template>
|
|
55
|
+
const itemsKey = new DataProviderKey<Data>("data").items;
|
|
56
|
+
itemsKey.path; // "data.items"
|
|
57
|
+
// itemsKey is DataProviderKey<Item[]>
|
|
58
|
+
//
|
|
59
|
+
const firstItem = itemsKey[0];
|
|
60
|
+
firstItem.path; // "data.items.0"
|
|
61
|
+
// firstItem is DataProviderKey<Item>
|
|
62
|
+
</template>
|
|
63
|
+
</sonic-code>
|
|
64
|
+
|
|
65
|
+
### Dynamic paths
|
|
66
|
+
|
|
67
|
+
Use placeholders `${prop}` or `{$prop}` in the path string. The path is resolved at runtime from the component's properties. The type remains declarative:
|
|
68
|
+
|
|
69
|
+
<sonic-code language="typescript">
|
|
70
|
+
<template>
|
|
71
|
+
type User = { name: string; email: string };
|
|
72
|
+
//
|
|
73
|
+
// Path resolved from component.userIndex at runtime
|
|
74
|
+
@subscribe(new DataProviderKey<User>("users.${userIndex}"))
|
|
75
|
+
@state()
|
|
76
|
+
user: User | null = null;
|
|
77
|
+
</template>
|
|
78
|
+
</sonic-code>
|
|
79
|
+
|
|
80
|
+
## Path retrieval
|
|
81
|
+
|
|
82
|
+
The final path is built by concatenating each accessed property with a dot:
|
|
83
|
+
|
|
84
|
+
- `new DataProviderKey<T>("base")` → `"base"`
|
|
85
|
+
- `key.prop` → `"base.prop"`
|
|
86
|
+
- `key.items[0]` → `"base.items.0"`
|
|
87
|
+
|
|
88
|
+
Use `toString()` or `path` to get the full path string:
|
|
89
|
+
|
|
90
|
+
<sonic-code language="typescript">
|
|
91
|
+
<template>
|
|
92
|
+
const key = new DataProviderKey<Data>("data").count;
|
|
93
|
+
const pathString = key.toString(); // "data.count"
|
|
94
|
+
const pathProp = key.path; // "data.count"
|
|
95
|
+
</template>
|
|
96
|
+
</sonic-code>
|
|
97
|
+
|
|
98
|
+
## Use cases
|
|
99
|
+
|
|
100
|
+
- **Type-safe bindings**: paths for `@bind`, `@subscribe`, `@publish`
|
|
101
|
+
- **Dynamic paths**: reusable keys with `${...}` placeholders
|
|
102
|
+
- **Form fields**: form data paths with compile-time checking
|
|
103
|
+
|
|
104
|
+
## Integration with @subscribe and @publish
|
|
105
|
+
|
|
106
|
+
Use `DataProviderKey` with `@subscribe` (read-only) or `@publish` (write-only). The decorated property **must** match the key’s value type:
|
|
107
|
+
|
|
108
|
+
<sonic-code language="typescript">
|
|
109
|
+
<template>
|
|
110
|
+
import { subscribe } from "@supersoniks/concorde/decorators";
|
|
111
|
+
import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
|
|
112
|
+
//
|
|
113
|
+
type FormData = { email: string };
|
|
114
|
+
const formKey = new DataProviderKey<FormData>("formData");
|
|
115
|
+
//
|
|
116
|
+
@customElement("user-form")
|
|
117
|
+
export class UserForm extends LitElement {
|
|
118
|
+
@subscribe(formKey.email)
|
|
119
|
+
@state()
|
|
120
|
+
email = "";
|
|
121
|
+
//
|
|
122
|
+
render() {
|
|
123
|
+
return html`<input .value=${this.email} @input=${(e) => this.email = (e.target as HTMLInputElement).value}>`;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
</template>
|
|
127
|
+
</sonic-code>
|
|
128
|
+
|
|
129
|
+
Both decorators support dynamic paths: `"base.${prop}"` in the constructor. A wrong property type (e.g. `number` for `DataProviderKey<string>`) is a TypeScript error.
|
|
130
|
+
|
|
131
|
+
## Notes
|
|
132
|
+
|
|
133
|
+
- Function properties are excluded from navigation (no `key.method()` chaining)
|
|
134
|
+
- Primitives have no navigable properties
|
|
135
|
+
- The `path` property and `toString()` are equivalent for retrieving the key
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Endpoint
|
|
2
|
+
|
|
3
|
+
`Endpoint<T, U>` describes a single HTTP path (or a path accepted by `API.get`) and carries the expected response type `T`. Unlike [DataProviderKey](#docs/_misc/dataProviderKey.md/dataProviderKey), there is no dot-navigation: the path is one string.
|
|
4
|
+
|
|
5
|
+
The optional second generic `U` (default `any`) describes host properties used to resolve dynamic segments in the path (`${…}` / `{$…}`), for example with the [@get](#docs/_decorators/get.md/get) decorator.
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
<sonic-code language="typescript">
|
|
10
|
+
<template>
|
|
11
|
+
import { Endpoint } from "@supersoniks/concorde/utils/endpoint";
|
|
12
|
+
</template>
|
|
13
|
+
</sonic-code>
|
|
14
|
+
|
|
15
|
+
## Construction
|
|
16
|
+
|
|
17
|
+
<sonic-code language="typescript">
|
|
18
|
+
<template>
|
|
19
|
+
const users = new Endpoint<User[]>("users?limit=10");
|
|
20
|
+
users.path; // "users?limit=10"
|
|
21
|
+
//
|
|
22
|
+
const one = new Endpoint<User, { userId: string }>("users/${userId}");
|
|
23
|
+
// `userId` on the host class is observed when used with @get
|
|
24
|
+
</template>
|
|
25
|
+
</sonic-code>
|
|
26
|
+
|
|
27
|
+
## Normalization
|
|
28
|
+
|
|
29
|
+
`Endpoint.normalizePath` trims the string, rejects an empty path, strips leading slashes for paths relative to `serviceURL`, collapses duplicate slashes, and validates absolute `http(s)://` URLs.
|
|
30
|
+
|
|
31
|
+
## Publisher key for payloads
|
|
32
|
+
|
|
33
|
+
`getDataProviderKey()` returns a typed publisher key whose `path` matches the endpoint path (payload typing follows `ApiGetResult` for this endpoint). Useful when pairing `@get` with `@publish` / `@subscribe` (see [@get](#docs/_decorators/get.md/get)).
|
|
34
|
+
|
|
35
|
+
## Data-provider paths
|
|
36
|
+
|
|
37
|
+
`Endpoint.looksLikeDataProviderPath(path)` returns true for strings shaped like `dataProvider(id)…`, which `API.get` can resolve without HTTP.
|
|
38
|
+
|
|
39
|
+
## See also
|
|
40
|
+
|
|
41
|
+
- [@get](#docs/_decorators/get.md/get) — decorator that uses `Endpoint<T>`
|
|
42
|
+
- [DataProviderKey](#docs/_misc/dataProviderKey.md/dataProviderKey) — typed publisher paths (dot notation)
|