@supersoniks/concorde 5.1.1 → 5.1.3-immutable.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/.agents/skills/concorde-docs/SKILL.md +153 -0
- package/.agents/skills/{concorde-component-docs/template.md → concorde-docs/templates/component.md} +6 -2
- package/.agents/skills/concorde-docs/templates/decorator.md +43 -0
- package/.agents/skills/concorde-docs/templates/guide.md +25 -0
- package/.claude/skills +1 -0
- package/.github/workflows/ci.yml +21 -0
- package/.github-export-ignore +30 -0
- package/CONTRIBUTING.md +59 -0
- package/DEV.md +54 -0
- package/LICENSE +21 -0
- package/OPEN_SOURCE_CHECKPOINT.md +133 -0
- package/README.md +4 -4
- package/ai/README.md +29 -41
- package/ai/skills/concorde/SKILL.md +54 -324
- package/ai/skills/concorde/rules/composition.md +32 -0
- package/ai/skills/concorde/rules/data.md +47 -0
- package/ai/skills/concorde/rules/http.md +25 -0
- package/ai/skills/concorde/rules/lists-forms.md +35 -0
- package/ai/skills/concorde/rules/styling.md +46 -0
- package/ai/skills/concorde/rules/troubleshooting.md +45 -0
- package/build-infos.json +1 -1
- package/concorde-core.bundle.js +177 -177
- package/concorde-core.es.js +4993 -4833
- package/custom-elements-manifest.public.config.mjs +8 -0
- package/{.tmp-cem/custom-elements.json → custom-elements.json} +11758 -8904
- package/dist/concorde-core.bundle.js +177 -177
- package/dist/concorde-core.es.js +4993 -4833
- package/dist/docs-mock-api-sw.js +58 -223
- package/dist/docs-mock-api-sw.js.map +4 -4
- package/dist/img/concorde/plane_01.jpg +0 -0
- package/dist/img/concorde/plane_02.jpg +0 -0
- package/dist/img/concorde/plane_03.jpg +0 -0
- package/dist/img/concorde/plane_04.jpg +0 -0
- package/dist/img/concorde/plane_05.jpg +0 -0
- package/dist/img/concorde/plane_06.jpg +0 -0
- package/dist/img/concorde/plane_07.jpg +0 -0
- package/dist/img/concorde/plane_08.jpg +0 -0
- package/dist/img/concorde/plane_09.jpg +0 -0
- package/dist/img/concorde/plane_10.jpg +0 -0
- package/dist/img/concorde/plane_11.jpg +0 -0
- package/dist/img/concorde/plane_12.jpg +0 -0
- package/dist/img/concorde/plane_13.jpg +0 -0
- package/dist/img/og-concorde.jpg +0 -0
- package/dist/robots.txt +11 -10
- package/docs/assets/index-D_alEsng.js +12122 -0
- package/docs/crawl/core/components/functional/date/date.html +190 -0
- package/docs/crawl/core/components/functional/fetch/fetch.html +109 -0
- package/docs/crawl/core/components/functional/if/if.html +27 -0
- package/docs/crawl/core/components/functional/jsonata/jsonata.html +79 -0
- package/docs/crawl/core/components/functional/list/list.html +70 -0
- package/docs/crawl/core/components/functional/mix/mix.html +45 -0
- package/docs/crawl/core/components/functional/queue/queue.html +96 -0
- package/docs/crawl/core/components/functional/router/router.html +106 -0
- package/docs/crawl/core/components/functional/sdui/sdui-extension-points.html +126 -0
- package/docs/crawl/core/components/functional/sdui/sdui.html +368 -0
- package/docs/crawl/core/components/functional/states/states.html +66 -0
- package/docs/crawl/core/components/functional/submit/submit.html +160 -0
- package/docs/crawl/core/components/functional/subscriber/subscriber.html +67 -0
- package/docs/crawl/core/components/functional/value/value.html +51 -0
- package/docs/crawl/core/components/ui/alert/alert.html +211 -0
- package/docs/crawl/core/components/ui/alert-messages/alert-messages.html +131 -0
- package/docs/crawl/core/components/ui/badge/badge.html +197 -0
- package/docs/crawl/core/components/ui/button/button.html +150 -0
- package/docs/crawl/core/components/ui/captcha/captcha.html +112 -0
- package/docs/crawl/core/components/ui/card/card.html +253 -0
- package/docs/crawl/core/components/ui/divider/divider.html +144 -0
- package/docs/crawl/core/components/ui/form/checkbox/checkbox.html +73 -0
- package/docs/crawl/core/components/ui/form/fieldset/fieldset.html +266 -0
- package/docs/crawl/core/components/ui/form/form-actions/form-actions.html +122 -0
- package/docs/crawl/core/components/ui/form/form-layout/form-layout.html +121 -0
- package/docs/crawl/core/components/ui/form/input/input.html +109 -0
- package/docs/crawl/core/components/ui/form/input-autocomplete/input-autocomplete.html +38 -0
- package/docs/crawl/core/components/ui/form/radio/radio.html +56 -0
- package/docs/crawl/core/components/ui/form/select/select.html +73 -0
- package/docs/crawl/core/components/ui/form/switch/switch.html +56 -0
- package/docs/crawl/core/components/ui/form/textarea/textarea.html +59 -0
- package/docs/crawl/core/components/ui/group/group.html +104 -0
- package/docs/crawl/core/components/ui/icon/icon.html +222 -0
- package/docs/crawl/core/components/ui/image/image.html +298 -0
- package/docs/crawl/core/components/ui/link/link.html +100 -0
- package/docs/crawl/core/components/ui/loader/loader.html +124 -0
- package/docs/crawl/core/components/ui/menu/menu.html +394 -0
- package/docs/crawl/core/components/ui/modal/modal.html +342 -0
- package/docs/crawl/core/components/ui/pop/pop.html +296 -0
- package/docs/crawl/core/components/ui/progress/progress.html +131 -0
- package/docs/crawl/core/components/ui/table/table.html +545 -0
- package/docs/crawl/core/components/ui/theme/theme.html +131 -0
- package/docs/crawl/core/components/ui/toast/toast.html +233 -0
- package/docs/crawl/core/components/ui/tooltip/tooltip.html +140 -0
- package/docs/crawl/docs/_core-concept/dataFlow.html +177 -0
- package/docs/crawl/docs/_core-concept/overview.html +66 -0
- package/docs/crawl/docs/_core-concept/subscriber.html +75 -0
- package/docs/crawl/docs/_decorators/ancestor-attribute.html +117 -0
- package/docs/crawl/docs/_decorators/auto-subscribe.html +202 -0
- package/docs/crawl/docs/_decorators/bind.html +141 -0
- package/docs/crawl/docs/_decorators/get.html +149 -0
- package/docs/crawl/docs/_decorators/handle.html +165 -0
- package/docs/crawl/docs/_decorators/on-assign.html +355 -0
- package/docs/crawl/docs/_decorators/patch.html +78 -0
- package/docs/crawl/docs/_decorators/post.html +139 -0
- package/docs/crawl/docs/_decorators/publish.html +61 -0
- package/docs/crawl/docs/_decorators/put.html +78 -0
- package/docs/crawl/docs/_decorators/subscribe.html +109 -0
- package/docs/crawl/docs/_decorators/wait-for-ancestors.html +137 -0
- package/docs/crawl/docs/_directives/sub.html +93 -0
- package/docs/crawl/docs/_getting-started/ai-agents.html +173 -0
- package/docs/crawl/docs/_getting-started/concorde-manual-install.html +100 -0
- package/docs/crawl/docs/_getting-started/concorde-outside.html +58 -0
- package/docs/crawl/docs/_getting-started/create-a-component.html +111 -0
- package/docs/crawl/docs/_getting-started/my-first-component.html +189 -0
- package/docs/crawl/docs/_getting-started/my-first-subscriber.html +110 -0
- package/docs/crawl/docs/_getting-started/pubsub.html +62 -0
- package/docs/crawl/docs/_getting-started/start.html +76 -0
- package/docs/crawl/docs/_getting-started/theming.html +333 -0
- package/docs/crawl/docs/_misc/api-configuration.html +149 -0
- package/docs/crawl/docs/_misc/dataProviderKey.html +135 -0
- package/docs/crawl/docs/_misc/docs-mock-api.html +158 -0
- package/docs/crawl/docs/_misc/dynamic-path.html +180 -0
- package/docs/crawl/docs/_misc/endpoint.html +50 -0
- package/docs/crawl/docs/_misc/formelement-subscriber-removal.html +138 -0
- package/docs/crawl/docs/_misc/html-integration.html +48 -0
- package/docs/crawl/hubs/decorators.html +547 -0
- package/docs/crawl/hubs/form-components.html +381 -0
- package/docs/crawl/hubs/remote-data.html +452 -0
- package/docs/crawl/index.html +103 -0
- package/docs/index.html +1 -1
- package/docs/llms-full.txt +7174 -0
- package/docs/llms.txt +98 -0
- package/docs/sitemap.xml +243 -0
- package/docs/src/core/components/functional/date/date.md +290 -0
- package/docs/src/core/components/functional/fetch/fetch.md +125 -0
- package/docs/src/core/components/functional/if/if.md +9 -0
- package/docs/src/core/components/functional/jsonata/jsonata.md +56 -0
- package/docs/src/core/components/functional/list/list.md +65 -0
- package/docs/src/core/components/functional/mix/mix.md +41 -0
- package/docs/src/core/components/functional/queue/queue.md +72 -0
- package/docs/src/core/components/functional/router/router.md +94 -0
- package/docs/src/core/components/functional/sdui/component-catalog.gaps.json +511 -0
- package/docs/src/core/components/functional/sdui/component-catalog.json +3103 -0
- package/docs/src/core/components/functional/sdui/default-library.json +108 -0
- package/docs/src/core/components/functional/sdui/example.json +99 -0
- package/docs/src/core/components/functional/sdui/sdui-extension-points.md +94 -0
- package/docs/src/core/components/functional/sdui/sdui.md +478 -0
- package/docs/src/core/components/functional/states/states.md +87 -0
- package/docs/src/core/components/functional/submit/submit.md +114 -0
- package/docs/src/core/components/functional/subscriber/subscriber.md +91 -0
- package/docs/src/core/components/functional/value/value.md +35 -0
- package/docs/src/core/components/ui/alert/alert.md +196 -0
- package/docs/src/core/components/ui/alert-messages/alert-messages.md +85 -0
- package/docs/src/core/components/ui/badge/badge.md +188 -0
- package/docs/src/core/components/ui/button/button.md +183 -0
- package/docs/src/core/components/ui/captcha/captcha.md +71 -0
- package/docs/src/core/components/ui/card/card.md +215 -0
- package/docs/src/core/components/ui/divider/divider.md +129 -0
- package/docs/src/core/components/ui/form/checkbox/checkbox.md +77 -0
- package/docs/src/core/components/ui/form/fieldset/fieldset.md +205 -0
- package/docs/src/core/components/ui/form/form-actions/form-actions.md +100 -0
- package/docs/src/core/components/ui/form/form-layout/form-layout.md +119 -0
- package/docs/src/core/components/ui/form/input/input.md +142 -0
- package/docs/src/core/components/ui/form/radio/radio.md +57 -0
- package/docs/src/core/components/ui/form/select/select.md +71 -0
- package/docs/src/core/components/ui/form/switch/switch.md +57 -0
- package/docs/src/core/components/ui/form/textarea/textarea.md +65 -0
- package/docs/src/core/components/ui/group/group.md +75 -0
- package/docs/src/core/components/ui/icon/icon.md +214 -0
- package/docs/src/core/components/ui/icon/icons.json +1 -0
- package/docs/src/core/components/ui/image/image.md +233 -0
- package/docs/src/core/components/ui/link/link.md +81 -0
- package/docs/src/core/components/ui/loader/loader.md +112 -0
- package/docs/src/core/components/ui/menu/menu.md +370 -0
- package/docs/src/core/components/ui/modal/modal.md +235 -0
- package/docs/src/core/components/ui/pop/pop.md +294 -0
- package/docs/src/core/components/ui/progress/progress.md +109 -0
- package/docs/src/core/components/ui/table/table.md +431 -0
- package/docs/src/core/components/ui/theme/theme.md +122 -0
- package/docs/src/core/components/ui/toast/toast.md +216 -0
- package/docs/src/core/components/ui/tooltip/tooltip.md +124 -0
- package/{src → docs/src}/docs/_core-concept/subscriber.md +0 -0
- package/{src → docs/src}/docs/_getting-started/my-first-subscriber.md +0 -0
- package/{src → docs/src}/docs/_getting-started/pubsub.md +0 -0
- package/docs/src/docs/_getting-started/theming.md +253 -0
- package/docs/src/docs/search/docs-search.json +12242 -0
- package/docs/src/tag-list.json +1 -0
- package/docs/src/tsconfig-model.json +23 -0
- package/docs/src/tsconfig.declarations.json +22 -0
- package/docs/src/tsconfig.emit.json +23 -0
- package/docs/src/tsconfig.json +1332 -0
- package/gitlab/job_github_mirror.sh +39 -0
- package/index.html +157 -5
- package/package.json +22 -4
- package/public/docs-mock-api-sw.js +58 -223
- package/public/docs-mock-api-sw.js.map +4 -4
- package/public/img/concorde/plane_01.jpg +0 -0
- package/public/img/concorde/plane_02.jpg +0 -0
- package/public/img/concorde/plane_03.jpg +0 -0
- package/public/img/concorde/plane_04.jpg +0 -0
- package/public/img/concorde/plane_05.jpg +0 -0
- package/public/img/concorde/plane_06.jpg +0 -0
- package/public/img/concorde/plane_07.jpg +0 -0
- package/public/img/concorde/plane_08.jpg +0 -0
- package/public/img/concorde/plane_09.jpg +0 -0
- package/public/img/concorde/plane_10.jpg +0 -0
- package/public/img/concorde/plane_11.jpg +0 -0
- package/public/img/concorde/plane_12.jpg +0 -0
- package/public/img/concorde/plane_13.jpg +0 -0
- package/public/img/og-concorde.jpg +0 -0
- package/public/robots.txt +11 -10
- package/scripts/ai-init.mjs +104 -379
- package/scripts/ai-init.test.mjs +81 -239
- package/scripts/docs-markdown-vite-plugin.ts +43 -0
- package/scripts/docs-public-url.mjs +56 -0
- package/scripts/docs.htaccess +82 -0
- package/scripts/generate-cem.mjs +244 -0
- package/scripts/generate-cem.test.mjs +122 -0
- package/scripts/generate-crawl-docs.mjs +233 -118
- package/scripts/generate-crawl-docs.test.mjs +124 -0
- package/scripts/generate-sdui-catalog.mjs +11 -10
- package/scripts/github-export.mjs +150 -0
- package/scripts/post-build-docs.js +37 -50
- package/scripts/post-build.mjs +0 -0
- package/scripts/pre-publish.mjs +2 -1
- package/scripts/site-pages.mjs +212 -0
- package/scripts/site-pages.test.mjs +116 -0
- package/site-pages/about.md +22 -0
- package/site-pages/privacy.md +32 -0
- package/src/core/components/functional/date/date.md +91 -231
- package/src/core/components/functional/example/example.ts +3 -1
- package/src/core/components/functional/fetch/fetch.md +66 -83
- package/src/core/components/functional/if/if.md +28 -3
- package/src/core/components/functional/if/if.ts +0 -0
- package/src/core/components/functional/jsonata/jsonata.md +42 -37
- package/src/core/components/functional/list/list.demo.ts +0 -0
- package/src/core/components/functional/list/list.md +103 -43
- package/src/core/components/functional/list/list.ts +17 -4
- package/src/core/components/functional/mix/mix.md +31 -26
- package/src/core/components/functional/queue/queue.demo.ts +10 -7
- package/src/core/components/functional/queue/queue.md +40 -61
- package/src/core/components/functional/router/router.demo.ts +16 -16
- package/src/core/components/functional/router/router.md +64 -65
- package/src/core/components/functional/router/router.ts +0 -0
- package/src/core/components/functional/sdui/SDUIDescriptorTransformer.ts +0 -0
- package/src/core/components/functional/sdui/component-catalog.gaps.json +1 -1
- package/src/core/components/functional/sdui/component-catalog.json +2 -2
- package/src/core/components/functional/sdui/example.json +19 -86
- package/src/core/components/functional/sdui/sdui-extension-points.md +1 -1
- package/src/core/components/functional/sdui/sdui-immutable.spec.ts +74 -0
- package/src/core/components/functional/sdui/sdui.md +187 -358
- package/src/core/components/functional/sdui/sdui.ts +33 -8
- package/src/core/components/functional/sdui/types.ts +0 -0
- package/src/core/components/functional/states/states.demo.ts +21 -22
- package/src/core/components/functional/states/states.md +86 -61
- package/src/core/components/functional/states/states.ts +1 -1
- package/src/core/components/functional/submit/submit.md +64 -72
- package/src/core/components/functional/submit/submit.spec.ts +60 -0
- package/src/core/components/functional/submit/submit.ts +6 -3
- package/src/core/components/functional/subscriber/subscriber.ts +0 -0
- package/src/core/components/functional/translation/translation.md +38 -0
- package/src/core/components/functional/value/value.md +34 -22
- package/src/core/components/functional/value/value.ts +0 -0
- package/src/core/components/ui/_css/size.ts +0 -0
- package/src/core/components/ui/alert/alert.md +48 -58
- package/src/core/components/ui/badge/badge.md +27 -34
- package/src/core/components/ui/button/button.md +139 -106
- package/src/core/components/ui/captcha/altchaStyles.ts +0 -0
- package/src/core/components/ui/captcha/captcha.md +17 -32
- package/src/core/components/ui/card/card.md +6 -6
- package/src/core/components/ui/divider/divider.md +8 -11
- package/src/core/components/ui/form/checkbox/checkbox.md +90 -42
- package/src/core/components/ui/form/fieldset/fieldset.md +31 -75
- package/src/core/components/ui/form/form-actions/form-actions.md +14 -16
- package/src/core/components/ui/form/form-layout/form-layout.md +19 -29
- package/src/core/components/ui/form/input/input.md +108 -90
- package/src/core/components/ui/form/input/input.ts +8 -2
- package/src/core/components/ui/form/radio/radio.md +65 -30
- package/src/core/components/ui/form/select/select.md +60 -45
- package/src/core/components/ui/form/switch/switch.md +57 -34
- package/src/core/components/ui/form/textarea/textarea.md +55 -38
- package/src/core/components/ui/group/group.md +35 -33
- package/src/core/components/ui/icon/icon.md +4 -4
- package/src/core/components/ui/image/image.md +41 -107
- package/src/core/components/ui/link/link.md +6 -6
- package/src/core/components/ui/loader/loader.md +30 -55
- package/src/core/components/ui/menu/menu.md +27 -27
- package/src/core/components/ui/modal/modal.md +72 -96
- package/src/core/components/ui/pop/pop.md +80 -158
- package/src/core/components/ui/progress/progress.md +2 -2
- package/src/core/components/ui/table/table.md +91 -255
- package/src/core/components/ui/theme/theme.md +11 -36
- package/src/core/components/ui/toast/toast.md +48 -117
- package/src/core/components/ui/tooltip/tooltip.md +27 -62
- package/src/core/decorators/subscriber/bind.ts +9 -14
- package/src/core/decorators/subscriber/subscribe.ts +15 -9
- package/src/core/decorators/subscriber/subscribe.type-test.ts +14 -5
- package/src/core/mixins/Subscriber.ts +0 -0
- package/src/core/utils/DataBindObserver.ts +0 -0
- package/src/core/utils/LocationHandler.spec.ts +80 -0
- package/src/core/utils/LocationHandler.ts +5 -9
- package/src/core/utils/Objects.ts +0 -0
- package/src/core/utils/PublisherProxy.ts +166 -125
- package/src/core/utils/deepReadonly.spec.ts +66 -0
- package/src/core/utils/deepReadonly.ts +71 -0
- package/src/core/utils/immutableValue.spec.ts +54 -0
- package/src/core/utils/immutableValue.ts +102 -0
- package/src/core/utils/nestedDotForm.spec.ts +88 -0
- package/src/core/utils/publisherImmutable.spec.ts +76 -0
- package/src/core/utils/route.ts +0 -0
- package/src/core/utils/strictGet.spec.ts +61 -0
- package/src/core/utils/strictGet.ts +102 -0
- package/src/css.d.ts +19 -0
- package/src/docs/components/docs-demo-sources.ts +55 -140
- package/src/docs/components/docs-lit-demo.ts +1 -3
- package/src/docs/components/docs-source-link.ts +0 -82
- package/src/docs/decorators/ancestor-attribute.md +59 -0
- package/src/docs/decorators/auto-subscribe.md +40 -0
- package/src/docs/decorators/bind.md +76 -0
- package/src/docs/decorators/get.md +160 -0
- package/src/docs/decorators/handle.md +119 -0
- package/src/docs/decorators/on-assign.md +63 -0
- package/src/docs/decorators/patch.md +44 -0
- package/src/docs/decorators/post.md +134 -0
- package/src/docs/decorators/publish.md +56 -0
- package/src/docs/decorators/put.md +51 -0
- package/src/docs/decorators/subscribe.md +87 -0
- package/src/docs/decorators/wait-for-ancestors.md +76 -0
- package/src/docs/directives/sub.md +75 -0
- package/src/docs/directives/t.md +73 -0
- package/src/docs/docs-location.spec.ts +56 -0
- package/src/docs/docs-location.ts +133 -32
- package/src/docs/docs.ts +1 -2
- package/src/docs/example/decorators-demo-bind-demos.ts +83 -135
- package/src/docs/example/decorators-demo-geo.ts +30 -19
- package/src/docs/example/decorators-demo-post.ts +88 -186
- package/src/docs/example/decorators-demo-subscribe-publish-get-demos.ts +165 -268
- package/src/docs/example/decorators-demo.ts +85 -98
- package/src/docs/example/docs-api-config-demos.ts +19 -20
- package/src/docs/example/docs-flight-demos.ts +147 -0
- package/src/docs/example/docs-jsonata-demos.ts +52 -52
- package/src/docs/example/docs-list-demos.ts +43 -123
- package/src/docs/example/docs-provider-keys.ts +21 -28
- package/src/docs/example/docs-queue-demos.ts +37 -77
- package/src/docs/example/docs-router-demos.ts +20 -25
- package/src/docs/example/docs-submit-demos.ts +48 -48
- package/src/docs/example/docs-toggle-demos.ts +4 -3
- package/src/docs/example/users.ts +0 -0
- package/src/docs/getting-started/ai-agents.md +50 -0
- package/src/docs/getting-started/create-a-component.md +136 -0
- package/src/docs/getting-started/dataFlow.md +87 -0
- package/src/docs/getting-started/installation.md +36 -0
- package/src/docs/getting-started/my-first-component.md +227 -0
- package/src/docs/getting-started/start.md +35 -0
- package/src/docs/header/header.ts +11 -6
- package/src/docs/home/catalog.ts +1 -1
- package/src/docs/home/home.ts +20 -11
- package/src/docs/layout.ts +12 -13
- package/src/docs/misc/api-configuration.md +79 -0
- package/src/docs/misc/dataProviderKey.md +168 -0
- package/src/docs/misc/docs-mock-api.md +62 -0
- package/src/docs/misc/dynamic-path.md +71 -0
- package/src/docs/misc/endpoint.md +45 -0
- package/src/docs/misc/html-integration.md +14 -0
- package/src/docs/misc/publisher-get-immutability-docs-crawl.json +902 -0
- package/src/docs/misc/publisher-get-immutability-docs-recheck.json +13 -0
- package/src/docs/misc/publisher-get-immutability-study.md +229 -0
- package/src/docs/mock-api/api-config-mock.ts +5 -0
- package/src/docs/mock-api/fixtures.ts +0 -278
- package/src/docs/mock-api/flights.ts +89 -0
- package/src/docs/mock-api/router.ts +3 -4
- package/src/docs/mock-api/urls.ts +1 -2
- package/src/docs/navigation/navigation.ts +84 -101
- package/src/docs/navigation/toc.ts +7 -4
- package/src/docs/search/docs-search.json +3188 -5153
- package/src/docs/search/markdown-renderer.ts +31 -8
- package/src/docs/search/page.ts +9 -6
- package/src/docs/search/search.ts +154 -122
- package/src/docs/tailwind/css/docs/content.css +4 -5
- package/src/tsconfig.declarations.json +22 -0
- package/src/tsconfig.emit.json +23 -0
- package/src/tsconfig.json +53 -5
- package/src/tsconfig.tsbuildinfo +1 -1
- package/vite.config.mts +11 -2
- package/.agents/skills/concorde-component-docs/SKILL.md +0 -194
- package/.taste-skill/after/desktop-fold.jpg +0 -0
- package/.taste-skill/after/desktop-page-01.jpg +0 -0
- package/.taste-skill/after/desktop-page-02.jpg +0 -0
- package/.taste-skill/after/desktop-page-03.jpg +0 -0
- package/.taste-skill/after/mobile-fold.jpg +0 -0
- package/.taste-skill/after/mobile-page-01.jpg +0 -0
- package/.taste-skill/after/report.json +0 -4103
- package/.taste-skill/after/tablet-fold.jpg +0 -0
- package/.taste-skill/after/tablet-page-01.jpg +0 -0
- package/.taste-skill/after/tablet-page-02.jpg +0 -0
- package/.taste-skill/before/desktop-fold.jpg +0 -0
- package/.taste-skill/before/desktop-page-01.jpg +0 -0
- package/.taste-skill/before/desktop-page-02.jpg +0 -0
- package/.taste-skill/before/mobile-fold.jpg +0 -0
- package/.taste-skill/before/mobile-page-01.jpg +0 -0
- package/.taste-skill/before/report.json +0 -2556
- package/.taste-skill/before/tablet-fold.jpg +0 -0
- package/.taste-skill/before/tablet-page-01.jpg +0 -0
- package/.taste-skill/direction.json +0 -510
- package/.taste-skill/notes.md +0 -84
- package/.taste-skill/prod/desktop-fold.jpg +0 -0
- package/.taste-skill/prod/desktop-page-01.jpg +0 -0
- package/.taste-skill/prod/desktop-page-02.jpg +0 -0
- package/.taste-skill/prod/desktop-page-03.jpg +0 -0
- package/.taste-skill/prod/mobile-fold.jpg +0 -0
- package/.taste-skill/prod/mobile-page-01.jpg +0 -0
- package/.taste-skill/prod/mobile-page-02.jpg +0 -0
- package/.taste-skill/prod/report.json +0 -1973
- package/.taste-skill/prod/tablet-fold.jpg +0 -0
- package/.taste-skill/prod/tablet-page-01.jpg +0 -0
- package/.taste-skill/prod/tablet-page-02.jpg +0 -0
- package/AUDIT.md +0 -228
- package/PLAN-AMELIORATION.md +0 -220
- package/ai/AGENTS.md +0 -56
- package/ai/cursor/rules/concorde-menu.mdc +0 -15
- package/ai/cursor/rules/concorde-scope.mdc +0 -14
- package/ai/cursor/rules/concorde-theme.mdc +0 -13
- package/ai/cursor/rules/concorde.mdc +0 -66
- package/ai/jetbrains/rules/concorde.md +0 -53
- package/ai/skills/concorde-get-set-dp/SKILL.md +0 -194
- package/ai/skills/concorde-imports/SKILL.md +0 -78
- package/ai/skills/concorde-menu/SKILL.md +0 -74
- package/ai/skills/concorde-scope/SKILL.md +0 -70
- package/ai/skills/concorde-theme/SKILL.md +0 -57
- package/docs/assets/index-Bb-_LRyY.js +0 -12280
- package/src/docs/example/docs-input-autocomplete-demos.ts +0 -110
- package/src/docs/example/docs-joke-demos.ts +0 -297
- /package/{src → docs/src}/core/components/ui/form/input-autocomplete/input-autocomplete.md +0 -0
- /package/{src → docs/src}/docs/_core-concept/dataFlow.md +0 -0
- /package/{src → docs/src}/docs/_core-concept/overview.md +0 -0
- /package/{src → docs/src}/docs/_decorators/ancestor-attribute.md +0 -0
- /package/{src → docs/src}/docs/_decorators/auto-subscribe.md +0 -0
- /package/{src → docs/src}/docs/_decorators/bind.md +0 -0
- /package/{src → docs/src}/docs/_decorators/get.md +0 -0
- /package/{src → docs/src}/docs/_decorators/handle.md +0 -0
- /package/{src → docs/src}/docs/_decorators/on-assign.md +0 -0
- /package/{src → docs/src}/docs/_decorators/patch.md +0 -0
- /package/{src → docs/src}/docs/_decorators/post.md +0 -0
- /package/{src → docs/src}/docs/_decorators/publish.md +0 -0
- /package/{src → docs/src}/docs/_decorators/put.md +0 -0
- /package/{src → docs/src}/docs/_decorators/subscribe.md +0 -0
- /package/{src → docs/src}/docs/_decorators/wait-for-ancestors.md +0 -0
- /package/{src → docs/src}/docs/_directives/sub.md +0 -0
- /package/{src → docs/src}/docs/_getting-started/ai-agents.md +0 -0
- /package/{src → docs/src}/docs/_getting-started/concorde-manual-install.md +0 -0
- /package/{src → docs/src}/docs/_getting-started/concorde-outside.md +0 -0
- /package/{src → docs/src}/docs/_getting-started/create-a-component.md +0 -0
- /package/{src → docs/src}/docs/_getting-started/my-first-component.md +0 -0
- /package/{src → docs/src}/docs/_getting-started/start.md +0 -0
- /package/{src → docs/src}/docs/_misc/api-configuration.md +0 -0
- /package/{src → docs/src}/docs/_misc/dataProviderKey.md +0 -0
- /package/{src → docs/src}/docs/_misc/docs-mock-api.md +0 -0
- /package/{src → docs/src}/docs/_misc/dynamic-path.md +0 -0
- /package/{src → docs/src}/docs/_misc/endpoint.md +0 -0
- /package/{src → docs/src}/docs/_misc/formelement-subscriber-removal.md +0 -0
- /package/{src → docs/src}/docs/_misc/html-integration.md +0 -0
- /package/src/docs/{_getting-started → getting-started}/components.md +0 -0
- /package/src/docs/{_getting-started → getting-started}/theming.md +0 -0
|
@@ -69,6 +69,9 @@ export class SonicSDUI extends Fetcher(Subscriber(LitElement)) {
|
|
|
69
69
|
*/
|
|
70
70
|
@property({ type: String }) opsDataProvider?: string;
|
|
71
71
|
private sduiDescriptor: SDUIDescriptor = {};
|
|
72
|
+
/** Ref publisher/props d’origine (peut être frozen) — pour skip willUpdate. */
|
|
73
|
+
private sduiPropsRef: SDUIDescriptor | Record<string, SDUIDescriptor> | null =
|
|
74
|
+
null;
|
|
72
75
|
private nodeIndex = new Map<string, SDUINode>();
|
|
73
76
|
/** Garde-fou cycles childNodeIds. */
|
|
74
77
|
private renderingStack = new Set<string>();
|
|
@@ -78,6 +81,16 @@ export class SonicSDUI extends Fetcher(Subscriber(LitElement)) {
|
|
|
78
81
|
private incrementalActive = false;
|
|
79
82
|
private opsUnsub?: () => void;
|
|
80
83
|
|
|
84
|
+
/** Copie de travail mutable : updateContents / parseRootNodes mutent library & nodes. */
|
|
85
|
+
private cloneDescriptor(source: SDUIDescriptor | null | undefined): SDUIDescriptor {
|
|
86
|
+
if (source == null) return {};
|
|
87
|
+
try {
|
|
88
|
+
return structuredClone(source) as SDUIDescriptor;
|
|
89
|
+
} catch {
|
|
90
|
+
return JSON.parse(JSON.stringify(source)) as SDUIDescriptor;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
81
94
|
private get isSafeProfile(): boolean {
|
|
82
95
|
return this.profile === "safe";
|
|
83
96
|
}
|
|
@@ -100,21 +113,33 @@ export class SonicSDUI extends Fetcher(Subscriber(LitElement)) {
|
|
|
100
113
|
return;
|
|
101
114
|
}
|
|
102
115
|
if (this.props == null) {
|
|
103
|
-
this.sduiDescriptor
|
|
104
|
-
|
|
105
|
-
|
|
116
|
+
if (this.sduiPropsRef != null || Object.keys(this.sduiDescriptor).length) {
|
|
117
|
+
this.sduiPropsRef = null;
|
|
118
|
+
this.sduiDescriptor = {};
|
|
119
|
+
this.updateContents();
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
const propsRoot = this.props as
|
|
123
|
+
| SDUIDescriptor
|
|
124
|
+
| Record<string, SDUIDescriptor>;
|
|
106
125
|
const newSduiDescriptor = this.sduiKey
|
|
107
|
-
? (
|
|
108
|
-
: (
|
|
126
|
+
? (propsRoot as Record<string, SDUIDescriptor>)[this.sduiKey]
|
|
127
|
+
: (propsRoot as SDUIDescriptor);
|
|
109
128
|
const profileChanged = changedProperties.has("profile");
|
|
110
129
|
const partialChanged = changedProperties.has("partial");
|
|
130
|
+
// Comparer la ref d’entrée (frozen publisher), pas la copie locale mutable.
|
|
111
131
|
if (
|
|
112
|
-
this.
|
|
132
|
+
this.sduiPropsRef == newSduiDescriptor &&
|
|
113
133
|
!profileChanged &&
|
|
114
134
|
!partialChanged
|
|
115
|
-
)
|
|
135
|
+
) {
|
|
136
|
+
super.willUpdate(changedProperties);
|
|
116
137
|
return;
|
|
117
|
-
|
|
138
|
+
}
|
|
139
|
+
this.sduiPropsRef = newSduiDescriptor ?? null;
|
|
140
|
+
// Ownership locale : le store immutable freeze props ; SDUI doit muter
|
|
141
|
+
// library / nodes / toast pendant le rendu.
|
|
142
|
+
this.sduiDescriptor = this.cloneDescriptor(newSduiDescriptor);
|
|
118
143
|
this.updateContents();
|
|
119
144
|
}
|
|
120
145
|
super.willUpdate(changedProperties);
|
|
File without changes
|
|
@@ -14,43 +14,42 @@ export class SonicStatesDemo extends LitElement {
|
|
|
14
14
|
|
|
15
15
|
constructor() {
|
|
16
16
|
super();
|
|
17
|
-
// Initialisation du dataProvider
|
|
18
17
|
dp<StatesDemoProvider>("states-demo-provider").set({});
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
@state()
|
|
22
21
|
private states = {
|
|
23
|
-
|
|
22
|
+
boarding: () => html`
|
|
24
23
|
<div class="p-4 border border-gray-200 rounded-md">
|
|
25
|
-
<h1 class="text-xl font-medium mb-2">
|
|
26
|
-
<p class="text-gray-600">
|
|
24
|
+
<h1 class="text-xl font-medium mb-2">Boarding</h1>
|
|
25
|
+
<p class="text-gray-600">Please proceed to gate B12.</p>
|
|
27
26
|
</div>
|
|
28
27
|
`,
|
|
29
28
|
|
|
30
|
-
"
|
|
31
|
-
|
|
29
|
+
"flights/:code/:status": ({
|
|
30
|
+
code,
|
|
32
31
|
status,
|
|
33
32
|
}: {
|
|
34
|
-
|
|
33
|
+
code: string;
|
|
35
34
|
status: string;
|
|
36
35
|
}) => html`
|
|
37
36
|
<div class="p-4 border border-gray-200 rounded-md">
|
|
38
|
-
<h1 class="text-xl font-medium mb-2">
|
|
39
|
-
<p class="text-gray-600">
|
|
37
|
+
<h1 class="text-xl font-medium mb-2">Flight ${code}</h1>
|
|
38
|
+
<p class="text-gray-600">Status: ${status}</p>
|
|
40
39
|
</div>
|
|
41
40
|
`,
|
|
42
41
|
|
|
43
|
-
"
|
|
42
|
+
"delayed_(\\d+)": ([minutes]: [string]) => html`
|
|
44
43
|
<div class="p-4 border border-red-200 bg-red-50 rounded-md">
|
|
45
|
-
<h1 class="text-xl font-medium text-red-800 mb-2">
|
|
46
|
-
<p class="text-red-600">
|
|
44
|
+
<h1 class="text-xl font-medium text-red-800 mb-2">Delayed</h1>
|
|
45
|
+
<p class="text-red-600">New departure in ${minutes} minutes</p>
|
|
47
46
|
</div>
|
|
48
47
|
`,
|
|
49
48
|
|
|
50
49
|
fallback: () => html`
|
|
51
50
|
<div class="p-4 border border-gray-200 rounded-md">
|
|
52
|
-
<h1 class="text-xl font-medium mb-2"
|
|
53
|
-
<p class="text-gray-600">
|
|
51
|
+
<h1 class="text-xl font-medium mb-2">Unknown status</h1>
|
|
52
|
+
<p class="text-gray-600">No state matches this value</p>
|
|
54
53
|
</div>
|
|
55
54
|
`,
|
|
56
55
|
};
|
|
@@ -58,20 +57,20 @@ export class SonicStatesDemo extends LitElement {
|
|
|
58
57
|
render() {
|
|
59
58
|
return html`
|
|
60
59
|
<div class="p-4">
|
|
61
|
-
<h2 class="text-2xl font-medium mb-6">
|
|
60
|
+
<h2 class="text-2xl font-medium mb-6">States demo</h2>
|
|
62
61
|
|
|
63
62
|
<div class="flex gap-4 mb-6" formDataProvider="states-demo-provider">
|
|
64
|
-
<sonic-button radio name="status" checked value="
|
|
65
|
-
|
|
63
|
+
<sonic-button radio name="status" checked value="boarding">
|
|
64
|
+
Boarding
|
|
66
65
|
</sonic-button>
|
|
67
|
-
<sonic-button radio name="status" value="
|
|
68
|
-
|
|
66
|
+
<sonic-button radio name="status" value="flights/CN001/landed">
|
|
67
|
+
CN 001 landed
|
|
69
68
|
</sonic-button>
|
|
70
|
-
<sonic-button radio name="status" value="
|
|
71
|
-
|
|
69
|
+
<sonic-button radio name="status" value="delayed_45">
|
|
70
|
+
Delayed 45 min
|
|
72
71
|
</sonic-button>
|
|
73
72
|
<sonic-button radio name="status" value="invalid">
|
|
74
|
-
|
|
73
|
+
Unknown
|
|
75
74
|
</sonic-button>
|
|
76
75
|
</div>
|
|
77
76
|
|
|
@@ -1,87 +1,112 @@
|
|
|
1
1
|
# States
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
* The subscribers/fetch... of the template will refer to this dataProvider
|
|
9
|
-
* You can also use url-pattern expressions for the route parameters, see the examples
|
|
10
|
-
*
|
|
11
|
-
**Examples**
|
|
12
|
-
* With ma.property= 2 :
|
|
13
|
-
* RegExp data-value = (\d+) and dataproviderExpression = /user/$1 the dataProvider attribute will be "/user/2"
|
|
14
|
-
* url-pattern data-value = :id and dataproviderExpression = /user/:id the dataProvider attribute will be "/user/2
|
|
15
|
-
|
|
16
|
-
## Basic
|
|
3
|
+
**`sonic-states`** renders the child `<template>` whose `data-value` matches a value of its data provider. Use it to switch views on a status or a selection; point `data-path` at the value, or set `state` directly.
|
|
4
|
+
|
|
5
|
+
## Basic example
|
|
6
|
+
|
|
7
|
+
Each `data-value` is a RegExp tested against the value. All matching templates render; a template with `data-value=""` renders while the value is empty.
|
|
17
8
|
|
|
18
9
|
<sonic-code>
|
|
19
10
|
<template>
|
|
20
|
-
<div class="flex gap-2
|
|
21
|
-
<sonic-button radio name="
|
|
22
|
-
<sonic-button radio name="
|
|
23
|
-
<sonic-button radio name="
|
|
24
|
-
<sonic-button radio name="selection" value="#contact" size="xs">Contact</sonic-button>
|
|
11
|
+
<div class="flex flex-wrap gap-2" formDataProvider="states-flight-status">
|
|
12
|
+
<sonic-button radio name="status" value="boarding" size="xs">Boarding</sonic-button>
|
|
13
|
+
<sonic-button radio name="status" value="delayed" size="xs">Delayed</sonic-button>
|
|
14
|
+
<sonic-button radio name="status" value="landed" size="xs">Landed</sonic-button>
|
|
25
15
|
</div>
|
|
26
|
-
<div class="
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
16
|
+
<div class="my-4 rounded border p-4 text-center text-2xl text-neutral-700">
|
|
17
|
+
<sonic-states dataProvider="states-flight-status" data-path="status">
|
|
18
|
+
<template data-value="">Select a status</template>
|
|
19
|
+
<template data-value="^boarding$">CN 001 is boarding at gate B12</template>
|
|
20
|
+
<template data-value="^delayed$">CN 001 is delayed by 45 minutes</template>
|
|
21
|
+
<template data-value="^landed$">CN 001 has landed at JFK</template>
|
|
22
|
+
</sonic-states>
|
|
33
23
|
</div>
|
|
34
24
|
</template>
|
|
35
25
|
</sonic-code>
|
|
36
26
|
|
|
37
|
-
|
|
27
|
+
Templates without `data-value` are ignored, and nothing renders when no template matches.
|
|
38
28
|
|
|
39
|
-
|
|
40
|
-
|
|
29
|
+
## Captured values
|
|
30
|
+
|
|
31
|
+
Add `dataProviderExpression` to wrap the template content in an element whose `dataProvider` is built from the value: `$1` · `$2`… for RegExp groups. Children such as [sonic-fetch](/core/components/functional/fetch) then read that provider.
|
|
41
32
|
|
|
42
33
|
<sonic-code>
|
|
43
34
|
<template>
|
|
44
|
-
<div
|
|
45
|
-
<
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
<
|
|
56
|
-
|
|
35
|
+
<div serviceURL="/docs-mock-api">
|
|
36
|
+
<div class="flex flex-wrap gap-2" formDataProvider="states-flight-pick">
|
|
37
|
+
<sonic-button radio name="flight" value="flight_001" size="xs">CN 001</sonic-button>
|
|
38
|
+
<sonic-button radio name="flight" value="flight_102" size="xs">CN 102</sonic-button>
|
|
39
|
+
<sonic-button radio name="flight" value="flight_305" size="xs">CN 305</sonic-button>
|
|
40
|
+
</div>
|
|
41
|
+
<sonic-states dataProvider="states-flight-pick" data-path="flight">
|
|
42
|
+
<template data-value="flight_(\d+)" dataProviderExpression="flights?q=$1">
|
|
43
|
+
<sonic-fetch key="flights.0"></sonic-fetch>
|
|
44
|
+
<p class="my-4">
|
|
45
|
+
<sonic-value key="code"></sonic-value> to
|
|
46
|
+
<sonic-value key="city"></sonic-value>:
|
|
47
|
+
<sonic-value key="status"></sonic-value>
|
|
48
|
+
</p>
|
|
57
49
|
</template>
|
|
58
50
|
</sonic-states>
|
|
59
51
|
</div>
|
|
60
52
|
</template>
|
|
61
53
|
</sonic-code>
|
|
62
54
|
|
|
63
|
-
|
|
55
|
+
With [url-pattern](https://www.npmjs.com/package/url-pattern) syntax, name the segments instead: `data-value="flight/:code"` and `dataProviderExpression="flights?q=:code"`.
|
|
64
56
|
|
|
65
|
-
|
|
66
|
-
|
|
57
|
+
## Inverted matching
|
|
58
|
+
|
|
59
|
+
With `inverted`, the value is the RegExp and each `data-value` is the tested text. Use it to show several templates at once.
|
|
67
60
|
|
|
68
61
|
<sonic-code>
|
|
69
62
|
<template>
|
|
70
|
-
<div
|
|
71
|
-
<sonic-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
<span data-bind ::inner-html="ucFirst|$name"></span>
|
|
75
|
-
</sonic-button>
|
|
76
|
-
</template>
|
|
77
|
-
</sonic-list>
|
|
78
|
-
<sonic-states dataProvider="states-regexp-example" data-path="selection">
|
|
79
|
-
<template data-value="#couleur_:id" dataProviderExpression="api/unknown/:id">
|
|
80
|
-
<sonic-fetch>
|
|
81
|
-
<input type="color" disabled data-bind ::value="$data.color" class=" w-full h-10 my-3" />
|
|
82
|
-
</sonic-fetch>
|
|
83
|
-
</template>
|
|
84
|
-
</sonic-states>
|
|
63
|
+
<div class="flex flex-wrap gap-2" formDataProvider="states-board-filter">
|
|
64
|
+
<sonic-button radio name="filter" value=".*" size="xs">All</sonic-button>
|
|
65
|
+
<sonic-button radio name="filter" value="delayed|cancelled" size="xs">Disrupted</sonic-button>
|
|
66
|
+
<sonic-button radio name="filter" value="on-time" size="xs">On time</sonic-button>
|
|
85
67
|
</div>
|
|
68
|
+
<sonic-states inverted dataProvider="states-board-filter" data-path="filter" class="my-4 flex flex-col gap-1">
|
|
69
|
+
<template data-value="on-time"><p>CN 014 · LHR · on time</p></template>
|
|
70
|
+
<template data-value="delayed"><p>CN 102 · GIG · delayed</p></template>
|
|
71
|
+
<template data-value="cancelled"><p>CN 305 · IAD · cancelled</p></template>
|
|
72
|
+
</sonic-states>
|
|
86
73
|
</template>
|
|
87
|
-
</sonic-code>
|
|
74
|
+
</sonic-code>
|
|
75
|
+
|
|
76
|
+
While the value is empty, every template renders.
|
|
77
|
+
|
|
78
|
+
## Render functions
|
|
79
|
+
|
|
80
|
+
From Lit, pass a `.states` map instead of templates: keys are RegExp or url-pattern expressions, values are render functions. RegExp groups arrive as an array, url-pattern segments as an object, and `fallback` renders when no key matches.
|
|
81
|
+
|
|
82
|
+
<sonic-code language="typescript">
|
|
83
|
+
<template>
|
|
84
|
+
private states = {
|
|
85
|
+
boarding: () => html`<p>Boarding at gate B12</p>`,
|
|
86
|
+
"delayed_(\\d+)": ([minutes]) => html`<p>Delayed by ${minutes} min</p>`,
|
|
87
|
+
"flights/:code/:status": ({ code, status }) => html`<p>${code}: ${status}</p>`,
|
|
88
|
+
fallback: () => html`<p>Unknown status</p>`,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
html`<sonic-states dataProvider="flight" data-path="status" .states=${this.states}></sonic-states>`;
|
|
92
|
+
</template>
|
|
93
|
+
</sonic-code>
|
|
94
|
+
|
|
95
|
+
## API reference
|
|
96
|
+
|
|
97
|
+
| Attribute | Values | Description |
|
|
98
|
+
|-----------|--------|-------------|
|
|
99
|
+
| `dataProvider` | string | Provider holding the value. Inherited from the closest ancestor when omitted |
|
|
100
|
+
| `data-path` | string | Dot path of the value in the provider |
|
|
101
|
+
| `state` | string | Value to match when `data-path` is not set |
|
|
102
|
+
| `inverted` | boolean (default `false`) | Uses the value as the RegExp and each `data-value` as the tested text |
|
|
103
|
+
| `states` | object (property) | Render functions keyed by expression, plus `fallback`. Templates are used only when nothing in the map renders |
|
|
104
|
+
|
|
105
|
+
| Template attribute | Description |
|
|
106
|
+
|--------------------|-------------|
|
|
107
|
+
| `data-value` | RegExp or url-pattern matched against the value. `""` matches an empty value |
|
|
108
|
+
| `dataProviderExpression` | Builds the `dataProvider` of a wrapper around the template content from `$1`… or `:name` |
|
|
109
|
+
|
|
110
|
+
| Slot | Description |
|
|
111
|
+
|------|-------------|
|
|
112
|
+
| *(default)* | `<template data-value>` children |
|
|
@@ -1,114 +1,106 @@
|
|
|
1
1
|
# Submit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**`sonic-submit`** sends the form publisher named by `formDataProvider` to a REST endpoint and writes the response to `submitResultDataProvider`. The request is configured like [Fetch](/core/components/functional/fetch): `serviceURL` on an ancestor, path from the ancestor `dataProvider` or from `endPoint`. Form fields such as `sonic-input` fill the publisher through their `name`.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Basic example
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
| Trigger | Attribute |
|
|
10
|
-
|---------|-----------|
|
|
11
|
-
| Click inside the slot | `onClick` |
|
|
12
|
-
| Enter in a focused field inside the slot | `onEnterKey` |
|
|
13
|
-
|
|
14
|
-
| Data / API | Attribute / property | Notes |
|
|
15
|
-
|------------|----------------------|--------|
|
|
16
|
-
| Form fields | `formDataProvider` on ancestor | Filled by `sonic-input`, `sonic-select`, etc. via `name` |
|
|
17
|
-
| Result after call | `submitResultDataProvider` on ancestor | Whole result object (after optional `submit-result-key`) |
|
|
18
|
-
| Slice of JSON result | `submit-result-key` on **sonic-submit** | Dot path, e.g. `data` when the API returns `{ data: { … } }` |
|
|
19
|
-
| HTTP verb | `method` on **sonic-submit** | `post` (default), `put`, `patch`, `delete`, `get` — not inherited from `sonic-scope` |
|
|
20
|
-
| Path override | `endPoint` on **sonic-submit** | Wins over ancestor `dataProvider` |
|
|
21
|
-
| JSON vs multipart | `sendAsFormData` on **sonic-submit** | `FormData` body, still expects JSON response |
|
|
22
|
-
| Reset publishers | `clearedDataOnSuccess` on ancestor | Space-separated `DataProviderKey.path` values; runs when a **result object** is returned (including error payloads with `messages`) |
|
|
23
|
-
| Browser form POST | `native` on **sonic-submit** | See [Native HTML form](#native-html-form) |
|
|
24
|
-
| Result event | — | Bubbles `submit` `CustomEvent` with `detail` = result |
|
|
25
|
-
| Credential Management API | `usernameKey`, `passwordKey` on **sonic-submit** | After a **successful** HTTP response, stores login if those keys exist in the payload (defaults: `username`, `password`) |
|
|
26
|
-
| ALTCHA / captcha | `needsCaptchaValidation` on form/header publisher | Defers send until token is set — see [Captcha](#core/components/ui/captcha/captcha.md/captcha) |
|
|
27
|
-
|
|
28
|
-
While a REST submit runs, the slot is wrapped with `data-disabled` (faded, no pointer events). With **`native`**, validation and loader still run, then the browser performs a normal form submission.
|
|
29
|
-
|
|
30
|
-
## Form and result handling
|
|
31
|
-
|
|
32
|
-
POST to mock `api/register`; result publisher `submit-example-result`.
|
|
7
|
+
`onClick` sends on a click inside the element, `onEnterKey` on Enter in a focused field inside it. The method defaults to `post` and the body to JSON. Fields are validated first; while the request runs, the content is faded and not clickable.
|
|
33
8
|
|
|
34
9
|
<docs-lit-demo for="docs-submit-demo"></docs-lit-demo>
|
|
35
10
|
|
|
36
|
-
##
|
|
37
|
-
|
|
38
|
-
With **`native`**, Concorde does **not** call `fetch`. After form validation it:
|
|
11
|
+
## Result key
|
|
39
12
|
|
|
40
|
-
|
|
41
|
-
2. Programmatically clicks a hidden native `type="submit"` control (`name` / `value` on **sonic-submit** if you need them).
|
|
13
|
+
When the API wraps its payload (`{ data: { id, token } }`), set `submitResultKey` to a dot path so `submitResultDataProvider` receives only that part.
|
|
42
14
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
<docs-lit-demo for="docs-submit-native-demo"></docs-lit-demo>
|
|
46
|
-
|
|
47
|
-
## sendAsFormData
|
|
15
|
+
<docs-lit-demo for="docs-submit-result-key-demo"></docs-lit-demo>
|
|
48
16
|
|
|
49
|
-
|
|
17
|
+
## Reset after submit
|
|
50
18
|
|
|
51
|
-
|
|
19
|
+
`clearedDataOnSuccess` on an ancestor lists publisher ids, separated by spaces, that are set to `{}` once the API returns a result. This includes error results with `messages`.
|
|
52
20
|
|
|
53
|
-
|
|
21
|
+
<docs-lit-demo for="docs-submit-clear-demo"></docs-lit-demo>
|
|
54
22
|
|
|
55
|
-
|
|
23
|
+
## Submit event
|
|
56
24
|
|
|
57
|
-
|
|
25
|
+
After each request, `sonic-submit` dispatches a bubbling `submit` event whose `detail` is the result, the same value written to `submitResultDataProvider`.
|
|
58
26
|
|
|
59
|
-
|
|
27
|
+
<docs-lit-demo for="docs-submit-event-demo"></docs-lit-demo>
|
|
60
28
|
|
|
61
|
-
##
|
|
29
|
+
## Endpoint override
|
|
62
30
|
|
|
63
|
-
|
|
31
|
+
`endPoint` on `sonic-submit` replaces the ancestor `dataProvider` as the request path, for this element only.
|
|
64
32
|
|
|
65
|
-
<docs-lit-demo for="docs-submit-
|
|
33
|
+
<docs-lit-demo for="docs-submit-endpoint-demo"></docs-lit-demo>
|
|
66
34
|
|
|
67
|
-
##
|
|
35
|
+
## HTTP method
|
|
68
36
|
|
|
69
|
-
|
|
37
|
+
Set `method` to `put` · `patch` · `delete` · `get` (default `post`). It is read on `sonic-submit` only, never inherited. With `get`, the fields are appended to the endpoint as a query string.
|
|
70
38
|
|
|
71
|
-
<docs-lit-demo for="docs-submit-
|
|
39
|
+
<docs-lit-demo for="docs-submit-get-demo"></docs-lit-demo>
|
|
72
40
|
|
|
73
|
-
##
|
|
41
|
+
## Multipart body
|
|
74
42
|
|
|
75
|
-
|
|
43
|
+
`sendAsFormData` sends the fields as `multipart/form-data` instead of JSON. The response is still parsed as JSON.
|
|
76
44
|
|
|
77
|
-
<docs-lit-demo for="docs-submit-
|
|
45
|
+
<docs-lit-demo for="docs-submit-formdata-demo"></docs-lit-demo>
|
|
78
46
|
|
|
79
|
-
##
|
|
47
|
+
## Native form
|
|
80
48
|
|
|
81
|
-
|
|
49
|
+
With `native`, no request is made: after validation, the publisher values are copied into the matching controls of the closest `<form>` (hidden inputs are created when missing), then the browser submits the form. `name` and `value` on `sonic-submit` are sent as the submit button pair. Use a `target` iframe to stay on the page.
|
|
82
50
|
|
|
83
|
-
<docs-lit-demo for="docs-submit-
|
|
51
|
+
<docs-lit-demo for="docs-submit-native-demo"></docs-lit-demo>
|
|
84
52
|
|
|
85
|
-
##
|
|
53
|
+
## Nested fields
|
|
86
54
|
|
|
87
|
-
|
|
55
|
+
A dot in a field `name` stores a nested object in the form publisher, and the body is sent with the same shape.
|
|
88
56
|
|
|
89
57
|
<sonic-code>
|
|
90
58
|
<template>
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
<sonic-input
|
|
94
|
-
<sonic-input
|
|
59
|
+
<sonic-scope formDataProvider="submit-example-dot-notation">
|
|
60
|
+
<div class="grid grid-cols-2 gap-4">
|
|
61
|
+
<sonic-input label="Passenger" name="passenger.name" value="Ada Lindqvist"></sonic-input>
|
|
62
|
+
<sonic-input label="Seat" name="passenger.seat" value="2A"></sonic-input>
|
|
95
63
|
</div>
|
|
96
64
|
</sonic-scope>
|
|
97
65
|
</template>
|
|
98
66
|
</sonic-code>
|
|
99
67
|
|
|
100
|
-
Stored shape:
|
|
101
|
-
|
|
102
68
|
<sonic-code language="typescript">
|
|
103
69
|
<template>
|
|
104
|
-
|
|
105
|
-
email: { value: "eve.holt@reqres.in" },
|
|
106
|
-
details: { password: { value: "pistol" } }
|
|
107
|
-
}
|
|
70
|
+
{ passenger: { name: "Ada Lindqvist", seat: "2A" } }
|
|
108
71
|
</template>
|
|
109
72
|
</sonic-code>
|
|
110
73
|
|
|
111
|
-
##
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
74
|
+
## API reference
|
|
75
|
+
|
|
76
|
+
| Attribute | Values | Description |
|
|
77
|
+
|-----------|--------|-------------|
|
|
78
|
+
| `onClick` | boolean | Sends on click inside the element |
|
|
79
|
+
| `onEnterKey` | boolean | Sends on Enter in a focused field inside the element |
|
|
80
|
+
| `method` | `post` · `put` · `patch` · `delete` · `get` (default `post`) | HTTP method. `get` sends the fields as a query string |
|
|
81
|
+
| `endPoint` | string | Request path. Overrides the ancestor `dataProvider` |
|
|
82
|
+
| `submitResultKey` | string | Dot path of the response part written to `submitResultDataProvider` |
|
|
83
|
+
| `sendAsFormData` | boolean | Sends `multipart/form-data` instead of JSON |
|
|
84
|
+
| `native` | boolean | Fills and submits the closest `<form>` instead of calling the API |
|
|
85
|
+
| `name` · `value` | string | Submit button pair added to a native form submission |
|
|
86
|
+
| `disabled` | boolean | Ignores triggers. Set while a request runs |
|
|
87
|
+
| `usernameKey` · `passwordKey` | string (default `username` · `password`) | After a successful response, fields stored with the Credential Management API when both are present |
|
|
88
|
+
|
|
89
|
+
| Ancestor attribute | Description |
|
|
90
|
+
|--------------------|-------------|
|
|
91
|
+
| `serviceURL` | API base URL |
|
|
92
|
+
| `dataProvider` | Default request path |
|
|
93
|
+
| `formDataProvider` | Publisher sent as the body. Required |
|
|
94
|
+
| `submitResultDataProvider` | Publisher receiving the result |
|
|
95
|
+
| `headersDataProvider` | Publisher sent as request headers |
|
|
96
|
+
| `clearedDataOnSuccess` | Space-separated publisher ids reset to `{}` after a result |
|
|
97
|
+
|
|
98
|
+
When the form or headers publisher has `needsCaptchaValidation`, the request waits for a [Captcha](/core/components/ui/captcha) token. A network failure produces a result with an error message in `messages`.
|
|
99
|
+
|
|
100
|
+
| Event | Detail |
|
|
101
|
+
|-------|--------|
|
|
102
|
+
| `submit` | The result (after `submitResultKey`) |
|
|
103
|
+
|
|
104
|
+
| Slot | Description |
|
|
105
|
+
|------|-------------|
|
|
106
|
+
| *(default)* | Fields and buttons that trigger the submission |
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import TestUtils from "@supersoniks/concorde/test-utils/TestUtils";
|
|
3
|
+
import { PublisherManager } from "@supersoniks/concorde/core/utils/PublisherProxy";
|
|
4
|
+
import "./submit";
|
|
5
|
+
import type { Submit } from "./submit";
|
|
6
|
+
|
|
7
|
+
afterEach(() => {
|
|
8
|
+
document.body.innerHTML = "";
|
|
9
|
+
vi.restoreAllMocks();
|
|
10
|
+
PublisherManager.getInstance().delete("submit-spec-form");
|
|
11
|
+
PublisherManager.getInstance().delete("submit-spec-result");
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe("sonic-submit + immutable publisher", () => {
|
|
15
|
+
it("envoie le formulaire sans muter le get() frozen (delete isFormValid)", async () => {
|
|
16
|
+
const [elt] = TestUtils.bootstrap(`
|
|
17
|
+
<div
|
|
18
|
+
formDataProvider="submit-spec-form"
|
|
19
|
+
submitResultDataProvider="submit-spec-result"
|
|
20
|
+
serviceURL="https://example.test"
|
|
21
|
+
dataProvider="api/register"
|
|
22
|
+
>
|
|
23
|
+
<sonic-submit></sonic-submit>
|
|
24
|
+
</div>
|
|
25
|
+
`) as unknown as [HTMLElement];
|
|
26
|
+
|
|
27
|
+
const submit = elt.querySelector("sonic-submit") as Submit;
|
|
28
|
+
await submit.updateComplete;
|
|
29
|
+
|
|
30
|
+
const formPub = PublisherManager.get("submit-spec-form");
|
|
31
|
+
formPub.set({
|
|
32
|
+
email: "ada@example.com",
|
|
33
|
+
password: "secret",
|
|
34
|
+
isFormValid: true,
|
|
35
|
+
needsCaptchaValidation: false,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const frozen = formPub.get() as Record<string, unknown>;
|
|
39
|
+
expect(Object.isFrozen(frozen)).toBe(true);
|
|
40
|
+
|
|
41
|
+
const post = vi.fn(async () => ({ id: 1, token: "t" }));
|
|
42
|
+
(submit as any).api = { post, lastResult: { ok: true } };
|
|
43
|
+
|
|
44
|
+
await submit.submit();
|
|
45
|
+
|
|
46
|
+
expect(post).toHaveBeenCalledTimes(1);
|
|
47
|
+
const call = post.mock.calls[0] as unknown as [
|
|
48
|
+
unknown,
|
|
49
|
+
Record<string, unknown>,
|
|
50
|
+
];
|
|
51
|
+
const body = call[1];
|
|
52
|
+
expect(body).toMatchObject({
|
|
53
|
+
email: "ada@example.com",
|
|
54
|
+
password: "secret",
|
|
55
|
+
});
|
|
56
|
+
expect(body.isFormValid).toBeUndefined();
|
|
57
|
+
// Store still frozen and untouched for isFormValid key presence as set
|
|
58
|
+
expect(formPub.get().email).toBe("ada@example.com");
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -137,7 +137,8 @@ export class Submit extends Subscriber(LitElement) {
|
|
|
137
137
|
const method = this.getAttribute("method")?.toLocaleLowerCase() || "post";
|
|
138
138
|
|
|
139
139
|
const sendAsFormData = this.hasAttribute("sendAsFormData");
|
|
140
|
-
|
|
140
|
+
// Shallow copies: publisher get() is frozen under the immutable store.
|
|
141
|
+
const formData: Record<string, any> = { ...(formPublisher.get() as object) };
|
|
141
142
|
delete formData.isFormValid;
|
|
142
143
|
const headesDataProvider = this.getAncestorAttributeValue(
|
|
143
144
|
"headersDataProvider"
|
|
@@ -145,8 +146,10 @@ export class Submit extends Subscriber(LitElement) {
|
|
|
145
146
|
const headerPublisher = headesDataProvider
|
|
146
147
|
? PublisherManager.getInstance().get(headesDataProvider)
|
|
147
148
|
: null;
|
|
148
|
-
let headerData: any = {};
|
|
149
|
-
if (headerPublisher)
|
|
149
|
+
let headerData: Record<string, any> = {};
|
|
150
|
+
if (headerPublisher) {
|
|
151
|
+
headerData = { ...(headerPublisher.get() as object) };
|
|
152
|
+
}
|
|
150
153
|
let result: SubmitResult = null;
|
|
151
154
|
const dataProvider = this.getAncestorAttributeValue("dataProvider");
|
|
152
155
|
const endPoint = this.endPoint || dataProvider;
|
|
File without changes
|