@supersoniks/concorde 4.3.0 → 4.4.1
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 +0 -62
- package/build-infos.json +1 -1
- package/concorde-core.bundle.js +583 -672
- package/concorde-core.es.js +7159 -9743
- package/dist/concorde-core.bundle.js +583 -672
- package/dist/concorde-core.es.js +7159 -9743
- package/docs/assets/index-DP1oMukw.js +4949 -0
- package/docs/assets/index-DZtxIZCW.css +1 -0
- package/docs/index.html +2 -2
- package/docs/src/docs/{_misc → _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 +5 -5
- package/vite/config.js +25 -6
- package/vite.config.mts +2 -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/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
|
@@ -1 +0,0 @@
|
|
|
1
|
-
*,:before,:after{--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: rgb(59 130 246 / .5);--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: }::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: rgb(59 130 246 / .5);--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-width:0;border-style:solid;border-color:currentColor}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}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;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings: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:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-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{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,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{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-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);font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);text-decoration:underline;font-weight:500}.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] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.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] *)){list-style-type:decimal;padding-inline-start:1.625em;margin-top:1em;margin-bottom:1em}.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] *)){list-style-type:disc;padding-inline-start:1.625em;margin-top:1em;margin-bottom:1em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{font-weight:400;color:var(--tw-prose-counters)}.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);font-weight:600;margin-top:1.25em}.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] *)){font-weight:500;font-style:italic;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}.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);font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:900;color:inherit}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:700;font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:800;color:inherit}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.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] *)){display:block;margin-top:2em;margin-bottom:2em}.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] *)){font-weight:500;font-family:inherit;color:var(--tw-prose-kbd);box-shadow:0 0 0 1px rgb(var(--tw-prose-kbd-shadows) / 10%),0 3px rgb(var(--tw-prose-kbd-shadows) / 10%);font-size:.875em;border-radius:.3125rem;padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;padding-inline-start:.375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-weight:600;font-size:.875em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:"`"}.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] *)){color:inherit}.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] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.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);overflow-x:auto;font-weight:400;font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding-top:.8571429em;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-inline-start:1.1428571em}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-width:0;border-radius:0;padding:0;font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.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] *)){width:100%;table-layout:auto;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.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);font-weight:600;vertical-align:bottom;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.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);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.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] *)){padding-inline-start:.375em}.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] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.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:.5714286em;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.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.333333%}.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 1 0%}.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)) skew(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)) skew(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)) skew(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)) skew(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)) skew(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)) skew(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:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.resize{resize:both}.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-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:0px}.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: rgba(0,0,10,.2) var(--tw-gradient-from-position);--tw-gradient-to: rgba(0, 0, 10, 0) 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-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.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 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--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 rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--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)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 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 rgb(0 0 0 / .1)) drop-shadow(0 1px 1px rgb(0 0 0 / .06));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 rgb(0 0 0 / .04)) drop-shadow(0 4px 3px rgb(0 0 0 / .1));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,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.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: #111111;--sc-primary: #111111;--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: #111111;--sc-info: #3b82f6;--sc-info-content: #ffffff;--sc-success: #10b981;--sc-success-content: #ffffff;--sc-warning: #fb923c;--sc-warning-content: #111827;--sc-danger: #dc2626;--sc-danger-content: #ffffff}[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: #ffffff;--sc-success: #0fba7f;--sc-success-content: #ffffff;--sc-warning: #fc8f3b;--sc-warning-content: #111827;--sc-danger: #dd2528;--sc-danger-content: #ffffff}[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{display:block;position:absolute;width:100%;height:100%;top:0;left:0;transform:translateY(108%);animation:slideUp 4.5s cubic-bezier(.17,.67,.61,1.13) infinite}.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{width:.5rem;height:.5rem;border:solid .15rem transparent;border-radius:var(--sc-rounded);background:transparent}.custom-scroll::-webkit-scrollbar-thumb{opacity:0;-webkit-transition:box-shadow .2s;transition:box-shadow .2s;border:solid .15rem transparent}@media (min-width: 1024px){.lg\:prose-lg{font-size:1.125rem;line-height:1.7777778}.lg\:prose-lg :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em;margin-bottom:1.3333333em}.lg\:prose-lg :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.2222222em;line-height:1.4545455;margin-top:1.0909091em;margin-bottom:1.0909091em}.lg\:prose-lg :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.6666667em;margin-bottom:1.6666667em;padding-inline-start:1em}.lg\:prose-lg :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:2.6666667em;margin-top:0;margin-bottom:.8333333em;line-height:1}.lg\:prose-lg :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.6666667em;margin-top:1.8666667em;margin-bottom:1.0666667em;line-height:1.3333333}.lg\:prose-lg :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.3333333em;margin-top:1.6666667em;margin-bottom:.6666667em;line-height:1.5}.lg\:prose-lg :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7777778em;margin-bottom:.4444444em;line-height:1.5555556}.lg\:prose-lg :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7777778em;margin-bottom:1.7777778em}.lg\:prose-lg :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7777778em;margin-bottom:1.7777778em}.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.7777778em;margin-bottom:1.7777778em}.lg\:prose-lg :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em;border-radius:.3125rem;padding-top:.2222222em;padding-inline-end:.4444444em;padding-bottom:.2222222em;padding-inline-start:.4444444em}.lg\:prose-lg :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em}.lg\:prose-lg :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8666667em}.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] *)){font-size:.8888889em;line-height:1.75;margin-top:2em;margin-bottom:2em;border-radius:.375rem;padding-top:1em;padding-inline-end:1.5em;padding-bottom:1em;padding-inline-start:1.5em}.lg\:prose-lg :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em;margin-bottom:1.3333333em;padding-inline-start:1.5555556em}.lg\:prose-lg :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em;margin-bottom:1.3333333em;padding-inline-start:1.5555556em}.lg\:prose-lg :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.6666667em;margin-bottom:.6666667em}.lg\:prose-lg :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4444444em}.lg\:prose-lg :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4444444em}.lg\:prose-lg :where(.lg\:prose-lg>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.8888889em;margin-bottom:.8888889em}.lg\:prose-lg :where(.lg\:prose-lg>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em}.lg\:prose-lg :where(.lg\:prose-lg>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.3333333em}.lg\:prose-lg :where(.lg\:prose-lg>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em}.lg\:prose-lg :where(.lg\:prose-lg>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.3333333em}.lg\:prose-lg :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.8888889em;margin-bottom:.8888889em}.lg\:prose-lg :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em;margin-bottom:1.3333333em}.lg\:prose-lg :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em}.lg\:prose-lg :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.6666667em;padding-inline-start:1.5555556em}.lg\:prose-lg :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:3.1111111em;margin-bottom:3.1111111em}.lg\:prose-lg :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.lg\:prose-lg :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.lg\:prose-lg :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.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:.8888889em;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.7777778em;margin-bottom:1.7777778em}.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] *)){font-size:.8888889em;line-height:1.5;margin-top:1em}.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\] :is(:where(h1):not(:where([class~=not-prose],[class~=not-prose] *))){font-size:4.2em}.prose-h1\:font-normal :is(:where(h1):not(:where([class~=not-prose],[class~=not-prose] *))){font-weight:400}.prose-li\:my-\[\.2em\] :is(:where(li):not(:where([class~=not-prose],[class~=not-prose] *))){margin-top:.2em;margin-bottom:.2em}@media (min-width: 640px){.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width: 768px){.md\:px-8{padding-left:2rem;padding-right:2rem}.md\:py-8{padding-top:2rem;padding-bottom:2rem}.md\:text-5xl{font-size:3rem}}@media (min-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 (min-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\:border-neutral-800:where(.dark,.dark *){border-color:var(--sc-base-800)}.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}
|
|
@@ -1,436 +0,0 @@
|
|
|
1
|
-
# @bind
|
|
2
|
-
|
|
3
|
-
The `@bind` decorator automatically binds a class property to a path in a publisher. The property will be automatically
|
|
4
|
-
updated when the publisher's data changes.
|
|
5
|
-
|
|
6
|
-
If you need to trigger the rendering lifecycle of a LitElement, please also add the `@state()` decorator to the property.
|
|
7
|
-
|
|
8
|
-
## Principle
|
|
9
|
-
|
|
10
|
-
This decorator subscribes to a publisher via the `PublisherManager` using a path (dot notation) to access a specific property. When this property is modified in the publisher, the decorated property is automatically updated.
|
|
11
|
-
|
|
12
|
-
## Usage
|
|
13
|
-
|
|
14
|
-
### Import
|
|
15
|
-
|
|
16
|
-
<sonic-code language="typescript">
|
|
17
|
-
<template>
|
|
18
|
-
import { bind } from "@supersoniks/concorde/decorators";
|
|
19
|
-
</template>
|
|
20
|
-
</sonic-code>
|
|
21
|
-
|
|
22
|
-
### Basic example
|
|
23
|
-
|
|
24
|
-
<sonic-code language="typescript">
|
|
25
|
-
<template>
|
|
26
|
-
@customElement("demo-bind")
|
|
27
|
-
export class DemoBind extends LitElement {
|
|
28
|
-
static styles = [tailwind];
|
|
29
|
-
//
|
|
30
|
-
@bind("demoData.firstName")
|
|
31
|
-
@state()
|
|
32
|
-
firstName = "";
|
|
33
|
-
//
|
|
34
|
-
@bind("demoData.lastName")
|
|
35
|
-
@state()
|
|
36
|
-
lastName: string = "";
|
|
37
|
-
//
|
|
38
|
-
@bind("demoData.count")
|
|
39
|
-
@state()
|
|
40
|
-
count: number = 0;
|
|
41
|
-
//
|
|
42
|
-
render() {
|
|
43
|
-
return //......
|
|
44
|
-
}
|
|
45
|
-
//
|
|
46
|
-
updateData() {
|
|
47
|
-
const demoData = PublisherManager.get("demoData");
|
|
48
|
-
const demoUsers = PublisherManager.get("demoUsers");
|
|
49
|
-
const randomIndex = Math.floor(Math.random() * demoUsers.get().length);
|
|
50
|
-
const randomUser = demoUsers.get()[randomIndex];
|
|
51
|
-
demoData.set({
|
|
52
|
-
firstName: randomUser.firstName,
|
|
53
|
-
lastName: randomUser.lastName,
|
|
54
|
-
count: (demoData.count.get() || 0) + 1,
|
|
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
|
-
## @subscribe (read-only, strictly typed with Key)
|
|
68
|
-
|
|
69
|
-
The `@subscribe` decorator is a simplified version of `@bind` without `reflect`. It accepts **only** `Key<T>` and enforces that the decorated property must be of type `T`:
|
|
70
|
-
|
|
71
|
-
<sonic-code language="typescript">
|
|
72
|
-
<template>
|
|
73
|
-
import { subscribe } from "@supersoniks/concorde/decorators";
|
|
74
|
-
import { Key } from "@supersoniks/concorde/key";
|
|
75
|
-
|
|
76
|
-
const statsKey = new Key<ControlStats>("idDonneesDeStats");
|
|
77
|
-
|
|
78
|
-
@subscribe(statsKey.gauge)
|
|
79
|
-
@state()
|
|
80
|
-
gauge: number = 0; // OK — matches Key<number>
|
|
81
|
-
|
|
82
|
-
// @subscribe(statsKey.gauge)
|
|
83
|
-
// gauge: string = ""; // Error — type 'string' is not assignable to type 'number'
|
|
84
|
-
</template>
|
|
85
|
-
</sonic-code>
|
|
86
|
-
|
|
87
|
-
- No `reflect`: read-only binding (publisher → property only)
|
|
88
|
-
- **Strict typing**: the property type MUST match the Key type — TypeScript enforces this
|
|
89
|
-
|
|
90
|
-
## @publish (write-only, inverse of @subscribe)
|
|
91
|
-
|
|
92
|
-
The `@publish` decorator is the inverse of `@subscribe`: when you write to the property, the value is published to the publisher path. No subscription (no read from publisher).
|
|
93
|
-
|
|
94
|
-
<sonic-code language="typescript">
|
|
95
|
-
<template>
|
|
96
|
-
import { publish } from "@supersoniks/concorde/decorators";
|
|
97
|
-
import { sub } from "@supersoniks/concorde/directives";
|
|
98
|
-
import { Key } from "@supersoniks/concorde/key";
|
|
99
|
-
|
|
100
|
-
type PublishDemoData = { email: string; message: string };
|
|
101
|
-
const publishDemoKey = new Key<PublishDemoData>("publishDemo");
|
|
102
|
-
|
|
103
|
-
@customElement("demo-publish")
|
|
104
|
-
export class DemoPublish extends LitElement {
|
|
105
|
-
@publish(publishDemoKey.email)
|
|
106
|
-
@state()
|
|
107
|
-
email = "";
|
|
108
|
-
|
|
109
|
-
@publish(publishDemoKey.message)
|
|
110
|
-
@state()
|
|
111
|
-
message = "";
|
|
112
|
-
|
|
113
|
-
render() {
|
|
114
|
-
return html`
|
|
115
|
-
<sonic-input
|
|
116
|
-
.value=${this.email}
|
|
117
|
-
@input=${(e) => (this.email = (e.target as HTMLInputElement).value)}
|
|
118
|
-
label="Email"
|
|
119
|
-
></sonic-input>
|
|
120
|
-
<sonic-input
|
|
121
|
-
.value=${this.message}
|
|
122
|
-
@input=${(e) => (this.message = (e.target as HTMLInputElement).value)}
|
|
123
|
-
label="Message"
|
|
124
|
-
></sonic-input>
|
|
125
|
-
<p>Published: ${sub("publishDemo.email")} / ${sub("publishDemo.message")}</p>
|
|
126
|
-
`;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
</template>
|
|
130
|
-
</sonic-code>
|
|
131
|
-
|
|
132
|
-
<sonic-code>
|
|
133
|
-
<template>
|
|
134
|
-
<demo-publish></demo-publish>
|
|
135
|
-
</template>
|
|
136
|
-
</sonic-code>
|
|
137
|
-
|
|
138
|
-
- **Write-only**: property → publisher (no subscription)
|
|
139
|
-
- **Strict typing**: the property type MUST match the Key type
|
|
140
|
-
- Equivalent to the reflect part of `@bind(path, { reflect: true })` without the subscription
|
|
141
|
-
|
|
142
|
-
## Reflect (liaison bidirectionnelle)
|
|
143
|
-
|
|
144
|
-
Lorsque vous avez besoin que les modifications locales se propagent également vers le publisher, activez l'option `reflect` :
|
|
145
|
-
|
|
146
|
-
<sonic-code language="typescript">
|
|
147
|
-
<template>
|
|
148
|
-
@bind("userData.profile.avatarUrl", { reflect: true })
|
|
149
|
-
@state()
|
|
150
|
-
avatar: string;
|
|
151
|
-
</template>
|
|
152
|
-
</sonic-code>
|
|
153
|
-
|
|
154
|
-
- `reflect: true` crée un getter/setter qui garde les descripteurs existants et synchronise la valeur avec le publisher.
|
|
155
|
-
- Les mises à jour provenant du publisher sont protégées par un flag interne afin d'éviter les boucles infinies.
|
|
156
|
-
- Toute écriture sur la propriété décorée (ex. saisie utilisateur, mise à jour durant `render`) déclenche un `publisher.set(...)`.
|
|
157
|
-
- Pratique pour implémenter des formulaires pilotés par les publishers sans écrire manuellement la logique de synchronisation.
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
<sonic-code language="typescript">
|
|
161
|
-
<template>
|
|
162
|
-
@customElement("demo-bind-reflect")
|
|
163
|
-
export class DemoBindReflect extends LitElement {
|
|
164
|
-
static styles = [tailwind];
|
|
165
|
-
//
|
|
166
|
-
@bind("bindReflectDemo.count", { reflect: true })
|
|
167
|
-
@state()
|
|
168
|
-
withReflect: number = 0;
|
|
169
|
-
//
|
|
170
|
-
@bind("bindReflectDemo.count")
|
|
171
|
-
@state()
|
|
172
|
-
withoutReflect: number = 0;
|
|
173
|
-
//
|
|
174
|
-
render() {
|
|
175
|
-
return html`
|
|
176
|
-
<div class="mb-3">
|
|
177
|
-
from publisher : ${sub("bindReflectDemo.count") || 0} <br />
|
|
178
|
-
from component with reflect : ${this.withReflect || 0} <br />
|
|
179
|
-
from component without reflect : ${this.withoutReflect || 0}
|
|
180
|
-
</div>
|
|
181
|
-
<sonic-button @click=${() => this.withReflect++}
|
|
182
|
-
>Increment with reflect</sonic-button
|
|
183
|
-
>
|
|
184
|
-
<sonic-button @click=${() => this.withoutReflect++}
|
|
185
|
-
>Increment without reflect</sonic-button
|
|
186
|
-
>
|
|
187
|
-
`;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
</template>
|
|
191
|
-
</sonic-code>
|
|
192
|
-
|
|
193
|
-
<sonic-code toggleCode>
|
|
194
|
-
<template>
|
|
195
|
-
<demo-bind-reflect></demo-bind-reflect>
|
|
196
|
-
</template>
|
|
197
|
-
</sonic-code>
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
### Complex path
|
|
201
|
-
|
|
202
|
-
<sonic-code language="typescript">
|
|
203
|
-
<template>
|
|
204
|
-
@customElement("user-profile")
|
|
205
|
-
export class UserProfile extends LitElement {
|
|
206
|
-
// Access to a simple property
|
|
207
|
-
@bind("cart")
|
|
208
|
-
@state()
|
|
209
|
-
cart: object;
|
|
210
|
-
//
|
|
211
|
-
// Access to a nested property
|
|
212
|
-
@bind("userData.profile.email")
|
|
213
|
-
@state()
|
|
214
|
-
userEmail: string;
|
|
215
|
-
//
|
|
216
|
-
// Access to an array element
|
|
217
|
-
@bind("userData.addresses.0.city")
|
|
218
|
-
@state()
|
|
219
|
-
primaryCity: string;
|
|
220
|
-
//
|
|
221
|
-
render() {
|
|
222
|
-
return html`
|
|
223
|
-
<div>
|
|
224
|
-
<p>Number of items : ${this.cart.items.length}</p>
|
|
225
|
-
<p>Email: ${this.userEmail}</p>
|
|
226
|
-
<p>City: ${this.primaryCity}</p>
|
|
227
|
-
</div>
|
|
228
|
-
`;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
</template>
|
|
232
|
-
</sonic-code>
|
|
233
|
-
|
|
234
|
-
## Path syntax
|
|
235
|
-
|
|
236
|
-
The path uses dot notation to navigate through the publisher structure:
|
|
237
|
-
|
|
238
|
-
- **First segment**: dataProvider identifier (e.g., `"myDataProvider"`)
|
|
239
|
-
- **Following segments**: nested properties (e.g., `"myDataProvider.user.profile"`)
|
|
240
|
-
- **Array access**: use numeric index (e.g., `"myDataProvider.items.0"`)
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
### Dynamic path driven by class properties
|
|
245
|
-
|
|
246
|
-
You can now build the path dynamically by referencing the host class properties inside the string passed to `@bind`. Two placeholder syntaxes are supported:
|
|
247
|
-
|
|
248
|
-
- `` ${myProperty} `` or `` ${this.myProperty} ``
|
|
249
|
-
- `` {$myProperty} ``
|
|
250
|
-
|
|
251
|
-
Each placeholder is replaced at runtime with the current value of the corresponding property. `@bind` automatically watches those properties and:
|
|
252
|
-
|
|
253
|
-
- re-evaluates the final path when one of them changes,
|
|
254
|
-
- removes the previous subscription before attaching the new one,
|
|
255
|
-
- keeps working with `reflect: true`.
|
|
256
|
-
- observe the changes inside `willUpdate(changedProperties)` so nothing touche aux getters/setters.
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
<sonic-code language="typescript">
|
|
260
|
-
<template>
|
|
261
|
-
@customElement("demo-bind-dynamic")
|
|
262
|
-
export class DemoBindDynamic extends LitElement {
|
|
263
|
-
static styles = [tailwind];
|
|
264
|
-
//
|
|
265
|
-
@property({ type: String })
|
|
266
|
-
dataProvider: "demoUsers" | "demoUsersAlt" = "demoUsers";
|
|
267
|
-
//
|
|
268
|
-
@property({ type: Number })
|
|
269
|
-
userIndex: number = 0;
|
|
270
|
-
//
|
|
271
|
-
@bind("${dataProvider}.${userIndex}")
|
|
272
|
-
@state()
|
|
273
|
-
user: any = {};
|
|
274
|
-
//
|
|
275
|
-
updateUserIndex(e: Event) {
|
|
276
|
-
this.userIndex = parseInt((e.target as HTMLInputElement).value);
|
|
277
|
-
}
|
|
278
|
-
//
|
|
279
|
-
updateDataProvider(e: Event) {
|
|
280
|
-
this.dataProvider = (e.target as HTMLSelectElement).value as
|
|
281
|
-
| "demoUsers"
|
|
282
|
-
| "demoUsersAlt";
|
|
283
|
-
}
|
|
284
|
-
//
|
|
285
|
-
updateCurrentUserData() {
|
|
286
|
-
const usersPublisher = PublisherManager.get(this.dataProvider);
|
|
287
|
-
const userPublisher = Objects.traverse(
|
|
288
|
-
usersPublisher,
|
|
289
|
-
[String(this.userIndex)]
|
|
290
|
-
) as PublisherProxy;
|
|
291
|
-
|
|
292
|
-
if (userPublisher) {
|
|
293
|
-
// Générer de nouvelles données aléatoires
|
|
294
|
-
const randomNames = [
|
|
295
|
-
{ firstName: "Alice", lastName: "Wonder" },
|
|
296
|
-
{ firstName: "Bob", lastName: "Builder" },
|
|
297
|
-
{ firstName: "Charlie", lastName: "Chaplin" },
|
|
298
|
-
];
|
|
299
|
-
|
|
300
|
-
const randomName =
|
|
301
|
-
randomNames[Math.floor(Math.random() * randomNames.length)];
|
|
302
|
-
const randomEmail = `${randomName.firstName.toLowerCase()}.${randomName.lastName.toLowerCase()}@example.com`;
|
|
303
|
-
|
|
304
|
-
// Mettre à jour l'utilisateur directement
|
|
305
|
-
const currentUser = userPublisher.get() || {};
|
|
306
|
-
userPublisher.set({
|
|
307
|
-
...currentUser,
|
|
308
|
-
firstName: randomName.firstName,
|
|
309
|
-
lastName: randomName.lastName,
|
|
310
|
-
email: randomEmail,
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
//
|
|
315
|
-
render() {
|
|
316
|
-
return html`
|
|
317
|
-
<div class="flex flex-col gap-2">
|
|
318
|
-
<sonic-select
|
|
319
|
-
.value=${this.dataProvider}
|
|
320
|
-
label="Users set"
|
|
321
|
-
@change=${this.updateDataProvider}
|
|
322
|
-
>
|
|
323
|
-
<option value="demoUsers">First set of users</option>
|
|
324
|
-
<option value="demoUsersAlt">Second set of users</option>
|
|
325
|
-
</sonic-select>
|
|
326
|
-
<sonic-input
|
|
327
|
-
type="number"
|
|
328
|
-
.value=${this.userIndex}
|
|
329
|
-
@input=${this.updateUserIndex}
|
|
330
|
-
min="0"
|
|
331
|
-
max="9"
|
|
332
|
-
label="Index"
|
|
333
|
-
class="block"
|
|
334
|
-
>
|
|
335
|
-
</sonic-input>
|
|
336
|
-
<sonic-button @click=${this.updateCurrentUserData}
|
|
337
|
-
>Update current user data</sonic-button
|
|
338
|
-
>
|
|
339
|
-
<div class="flex flex-col gap-2 border p-2">
|
|
340
|
-
<div>
|
|
341
|
-
<sonic-icon name="user" library="heroicons"></sonic-icon>
|
|
342
|
-
${this.user?.firstName} ${this.user?.lastName}
|
|
343
|
-
</div>
|
|
344
|
-
<div>
|
|
345
|
-
<sonic-icon name="envelope" library="heroicons"></sonic-icon>
|
|
346
|
-
${this.user?.email}
|
|
347
|
-
</div>
|
|
348
|
-
</div>
|
|
349
|
-
</div>
|
|
350
|
-
`;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
</template>
|
|
354
|
-
</sonic-code>
|
|
355
|
-
|
|
356
|
-
<sonic-code>
|
|
357
|
-
<template>
|
|
358
|
-
<demo-bind-dynamic></demo-bind-dynamic>
|
|
359
|
-
</template>
|
|
360
|
-
</sonic-code>
|
|
361
|
-
|
|
362
|
-
> ⚠️ Use a classic string literal: `@bind("${dataProvider}.${profileId}.info.title")`. Do **not** use a template literal (backticks), otherwise JavaScript would try to interpolate the value immediately.
|
|
363
|
-
>
|
|
364
|
-
|
|
365
|
-
Additional constraints:
|
|
366
|
-
|
|
367
|
-
- The hosting class must expose a `willUpdate(changedProperties?: Map<PropertyKey, unknown>)` method (LitElement already le fournit) so that `@bind` peut écouter les changements de dépendances.
|
|
368
|
-
- Dependencies need to be reactive (e.g. `@property()` on LitElement) or you must call `this.requestUpdate("myProp")` manually after changing them, otherwise `willUpdate` ne sera jamais notifié.
|
|
369
|
-
- If you use nested expressions like `${user.id}`, the first segment (`user`) is the one being observed: you need to reassign `this.user` (e.g. with a new object) so that the binding can detect the change.
|
|
370
|
-
|
|
371
|
-
## Behavior
|
|
372
|
-
|
|
373
|
-
- The property is automatically updated when the publisher's data changes
|
|
374
|
-
- Subscription happens at the time of `connectedCallback`
|
|
375
|
-
- Unsubscription happens automatically at the time of `disconnectedCallback`
|
|
376
|
-
- If the path doesn't exist yet, a publisher is created with the value `null`
|
|
377
|
-
- The value will be updated as soon as the data becomes available
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
## Use cases
|
|
381
|
-
|
|
382
|
-
This decorator is particularly useful for:
|
|
383
|
-
|
|
384
|
-
- **Binding properties** to specific data in a publisher
|
|
385
|
-
- **Accessing sub-properties** without having to manually write subscription logic
|
|
386
|
-
- **Simplifying code** by avoiding repetitive calls to `PublisherManager.get()` and `onAssign()`
|
|
387
|
-
|
|
388
|
-
## Complete example
|
|
389
|
-
|
|
390
|
-
<sonic-code language="typescript">
|
|
391
|
-
<template>
|
|
392
|
-
import { html, LitElement } from "lit";
|
|
393
|
-
import { customElement } from "lit/decorators.js";
|
|
394
|
-
import { bind } from "@supersoniks/concorde/decorators";
|
|
395
|
-
import { PublisherManager } from "@supersoniks/concorde/core/utils/PublisherProxy";
|
|
396
|
-
//
|
|
397
|
-
@customElement("product-card")
|
|
398
|
-
export class ProductCard extends LitElement {
|
|
399
|
-
@bind("productData.name")
|
|
400
|
-
@state()
|
|
401
|
-
productName: string;
|
|
402
|
-
//
|
|
403
|
-
@bind("productData.price")
|
|
404
|
-
@state()
|
|
405
|
-
price: number;
|
|
406
|
-
//
|
|
407
|
-
@bind("productData.description")
|
|
408
|
-
@state()
|
|
409
|
-
description: string;
|
|
410
|
-
//
|
|
411
|
-
render() {
|
|
412
|
-
return html`
|
|
413
|
-
<div class="product-card">
|
|
414
|
-
<h2>${this.productName}</h2>
|
|
415
|
-
<p class="price">${this.price}€</p>
|
|
416
|
-
<p>${this.description}</p>
|
|
417
|
-
</div>
|
|
418
|
-
`;
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
// Somewhere in your code, update the data:
|
|
422
|
-
const productPublisher = PublisherManager.get("productData");
|
|
423
|
-
productPublisher.set({
|
|
424
|
-
name: "Example product",
|
|
425
|
-
price: 29.99,
|
|
426
|
-
description: "A product description"
|
|
427
|
-
});
|
|
428
|
-
// The component properties will be automatically updated
|
|
429
|
-
</template>
|
|
430
|
-
</sonic-code>
|
|
431
|
-
|
|
432
|
-
## Notes
|
|
433
|
-
|
|
434
|
-
- This decorator works with any component that has `connectedCallback` and `disconnectedCallback` methods (such as `LitElement` or components extending `Subscriber`)
|
|
435
|
-
- Updates are reactive: any modification to the publisher triggers a property update
|
|
436
|
-
- For more information about publishers, see the documentation on [Sharing data](#docs/_getting-started/pubsub.md/pubsub)
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
# Key
|
|
2
|
-
|
|
3
|
-
The `Key<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
|
-
## Principle
|
|
6
|
-
|
|
7
|
-
`Key` uses a Proxy to intercept property access and build a cumulative path string. TypeScript infers the nested type at each level, so `myKey.checkedTickets[0]` is correctly typed as `Key<LegacyCheckedTicket>` when `checkedTickets` is `LegacyCheckedTicket[]`.
|
|
8
|
-
|
|
9
|
-
## Usage
|
|
10
|
-
|
|
11
|
-
### Import
|
|
12
|
-
|
|
13
|
-
<sonic-code language="typescript">
|
|
14
|
-
<template>
|
|
15
|
-
import { Key } from "@supersoniks/concorde/key";
|
|
16
|
-
</template>
|
|
17
|
-
</sonic-code>
|
|
18
|
-
|
|
19
|
-
### Basic example
|
|
20
|
-
|
|
21
|
-
<sonic-code language="typescript">
|
|
22
|
-
<template>
|
|
23
|
-
type LegacyCheckedTicket = { id: string };
|
|
24
|
-
type ControlRateType = "A" | "B";
|
|
25
|
-
type ControlStats = {
|
|
26
|
-
checkedTickets: LegacyCheckedTicket[];
|
|
27
|
-
gauge: number;
|
|
28
|
-
insidePeople: number;
|
|
29
|
-
soldTickets: number;
|
|
30
|
-
controlRateType: ControlRateType;
|
|
31
|
-
totalCheckedTickets: number;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
// Create a key and navigate through the structure
|
|
35
|
-
const myKey = new Key<ControlStats>("idDonneesDeStats").checkedTickets[0];
|
|
36
|
-
|
|
37
|
-
// Equivalent to: new Key<LegacyCheckedTicket>("idDonneesDeStats.checkedTickets.0")
|
|
38
|
-
myKey.toString(); // "idDonneesDeStats.checkedTickets.0"
|
|
39
|
-
myKey.path; // same value
|
|
40
|
-
// myKey is typed as Key<LegacyCheckedTicket>
|
|
41
|
-
</template>
|
|
42
|
-
</sonic-code>
|
|
43
|
-
|
|
44
|
-
### Object property access
|
|
45
|
-
|
|
46
|
-
<sonic-code language="typescript">
|
|
47
|
-
<template>
|
|
48
|
-
const key = new Key<ControlStats>("stats");
|
|
49
|
-
const gaugeKey = key.gauge;
|
|
50
|
-
gaugeKey.path; // "stats.gauge"
|
|
51
|
-
gaugeKey.toString(); // "stats.gauge"
|
|
52
|
-
</template>
|
|
53
|
-
</sonic-code>
|
|
54
|
-
|
|
55
|
-
### Array index access
|
|
56
|
-
|
|
57
|
-
<sonic-code language="typescript">
|
|
58
|
-
<template>
|
|
59
|
-
const ticketsKey = new Key<ControlStats>("data").checkedTickets;
|
|
60
|
-
ticketsKey.path; // "data.checkedTickets"
|
|
61
|
-
// ticketsKey is Key<LegacyCheckedTicket[]>
|
|
62
|
-
|
|
63
|
-
const firstTicket = ticketsKey[0];
|
|
64
|
-
firstTicket.path; // "data.checkedTickets.0"
|
|
65
|
-
// firstTicket is Key<LegacyCheckedTicket>
|
|
66
|
-
</template>
|
|
67
|
-
</sonic-code>
|
|
68
|
-
|
|
69
|
-
### Usage without `new`
|
|
70
|
-
|
|
71
|
-
<sonic-code language="typescript">
|
|
72
|
-
<template>
|
|
73
|
-
import { Key } from "@supersoniks/concorde/key";
|
|
74
|
-
|
|
75
|
-
const key = Key<ControlStats>("root");
|
|
76
|
-
key.path; // "root"
|
|
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 Key<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 Key<ControlStats>("stats").gauge;
|
|
93
|
-
const pathString = key.toString(); // "stats.gauge"
|
|
94
|
-
const pathProp = key.path; // "stats.gauge"
|
|
95
|
-
</template>
|
|
96
|
-
</sonic-code>
|
|
97
|
-
|
|
98
|
-
## Use cases
|
|
99
|
-
|
|
100
|
-
- **Type-safe bindings**: Build paths for `@bind` or similar decorators with full type inference
|
|
101
|
-
- **Dynamic paths**: Create reusable keys for nested data structures
|
|
102
|
-
- **API calls**: Pass typed paths to services that need to know the data location
|
|
103
|
-
- **Form fields**: Reference form data paths with compile-time checking
|
|
104
|
-
|
|
105
|
-
## Integration with @subscribe
|
|
106
|
-
|
|
107
|
-
Use `Key` with the `@subscribe` decorator for strictly typed, read-only bindings (no reflect). The decorated property **must** match the Key type:
|
|
108
|
-
|
|
109
|
-
<sonic-code language="typescript">
|
|
110
|
-
<template>
|
|
111
|
-
import { subscribe } from "@supersoniks/concorde/decorators";
|
|
112
|
-
import { Key } from "@supersoniks/concorde/key";
|
|
113
|
-
|
|
114
|
-
const statsKey = new Key<ControlStats>("idDonneesDeStats");
|
|
115
|
-
|
|
116
|
-
@customElement("stats-gauge")
|
|
117
|
-
export class StatsGauge extends LitElement {
|
|
118
|
-
@subscribe(statsKey.gauge)
|
|
119
|
-
@state()
|
|
120
|
-
gauge: number = 0; // Type enforced: must be number
|
|
121
|
-
|
|
122
|
-
render() {
|
|
123
|
-
return html`<span>Gauge: ${this.gauge}</span>`;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
</template>
|
|
127
|
-
</sonic-code>
|
|
128
|
-
|
|
129
|
-
If you declare `gauge: string` with `@subscribe(statsKey.gauge)` (Key<number>), TypeScript will 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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|