@supersoniks/concorde 4.6.0 → 4.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/.gitlab-ci.yml +23 -0
  2. package/README.md +106 -55
  3. package/ai/AGENTS.md +52 -0
  4. package/ai/README.md +30 -0
  5. package/ai/cursor/rules/concorde-menu.mdc +15 -0
  6. package/ai/cursor/rules/concorde-scope.mdc +14 -0
  7. package/ai/cursor/rules/concorde-theme.mdc +13 -0
  8. package/ai/cursor/rules/concorde.mdc +49 -0
  9. package/ai/jetbrains/rules/concorde.md +39 -0
  10. package/ai/skills/concorde/SKILL.md +220 -0
  11. package/ai/skills/concorde-get-set-dp/SKILL.md +194 -0
  12. package/ai/skills/concorde-imports/SKILL.md +78 -0
  13. package/ai/skills/concorde-menu/SKILL.md +74 -0
  14. package/ai/skills/concorde-scope/SKILL.md +70 -0
  15. package/ai/skills/concorde-theme/SKILL.md +46 -0
  16. package/build-infos.json +1 -1
  17. package/concorde-core.bundle.js +127 -127
  18. package/concorde-core.es.js +1435 -1364
  19. package/dist/altcha-widget.js +2662 -0
  20. package/dist/concorde-core.bundle.js +127 -127
  21. package/dist/concorde-core.es.js +1435 -1364
  22. package/dist/docs-mock-api-sw.js +589 -0
  23. package/dist/docs-mock-api-sw.js.map +7 -0
  24. package/docs/altcha-widget.js +2662 -0
  25. package/docs/assets/index-D9pxaQYK.js +7508 -0
  26. package/docs/assets/index-t0-i22oI.css +1 -0
  27. package/docs/docs-mock-api-sw.js +589 -0
  28. package/docs/docs-mock-api-sw.js.map +7 -0
  29. package/docs/index.html +2 -2
  30. package/docs/src/core/components/functional/fetch/fetch.md +13 -11
  31. package/docs/src/core/components/functional/if/if.md +4 -11
  32. package/docs/src/core/components/functional/list/list.md +60 -194
  33. package/docs/src/core/components/functional/queue/queue.md +70 -85
  34. package/docs/src/core/components/functional/router/router.md +62 -97
  35. package/docs/src/core/components/functional/states/states.md +2 -2
  36. package/docs/src/core/components/functional/submit/submit.md +86 -55
  37. package/docs/src/core/components/ui/captcha/captcha.md +2 -2
  38. package/docs/src/core/components/ui/card/card.md +1 -1
  39. package/docs/src/core/components/ui/form/checkbox/checkbox.md +5 -32
  40. package/docs/src/core/components/ui/form/input/input.md +5 -30
  41. package/docs/src/core/components/ui/form/input-autocomplete/input-autocomplete.md +6 -4
  42. package/docs/src/core/components/ui/form/radio/radio.md +5 -32
  43. package/docs/src/core/components/ui/form/select/select.md +5 -31
  44. package/docs/src/core/components/ui/form/switch/switch.md +5 -32
  45. package/docs/src/core/components/ui/loader/loader.md +1 -13
  46. package/docs/src/core/components/ui/table/table.md +3 -3
  47. package/docs/src/docs/_core-concept/dataFlow.md +73 -0
  48. package/docs/src/docs/_core-concept/subscriber.md +9 -10
  49. package/docs/src/docs/_decorators/ancestor-attribute.md +4 -3
  50. package/docs/src/docs/_decorators/auto-subscribe.md +19 -16
  51. package/docs/src/docs/_decorators/bind.md +20 -17
  52. package/docs/src/docs/_decorators/get.md +7 -4
  53. package/docs/src/docs/_decorators/handle.md +171 -0
  54. package/docs/src/docs/_decorators/on-assign.md +99 -73
  55. package/docs/src/docs/_decorators/publish.md +2 -1
  56. package/docs/src/docs/_decorators/subscribe.md +70 -9
  57. package/docs/src/docs/_decorators/wait-for-ancestors.md +13 -10
  58. package/docs/src/docs/_directives/sub.md +91 -0
  59. package/docs/src/docs/_getting-started/ai-agents.md +56 -0
  60. package/docs/src/docs/_getting-started/concorde-manual-install.md +133 -0
  61. package/docs/src/docs/_getting-started/concorde-outside.md +13 -123
  62. package/docs/src/docs/_getting-started/create-a-component.md +2 -0
  63. package/docs/src/docs/_getting-started/my-first-component.md +236 -0
  64. package/docs/src/docs/_getting-started/my-first-subscriber.md +29 -83
  65. package/docs/src/docs/_getting-started/pubsub.md +21 -134
  66. package/docs/src/docs/_getting-started/start.md +26 -18
  67. package/docs/src/docs/_misc/api-configuration.md +79 -0
  68. package/docs/src/docs/_misc/dataProviderKey.md +38 -5
  69. package/docs/src/docs/_misc/docs-mock-api.md +60 -0
  70. package/docs/src/docs/_misc/endpoint.md +2 -1
  71. package/docs/src/docs/_misc/html-integration.md +13 -0
  72. package/docs/src/docs/search/docs-search.json +4163 -873
  73. package/docs/src/tsconfig.json +380 -317
  74. package/gitlab/job_tests.sh +55 -0
  75. package/package.json +34 -3
  76. package/public/altcha-widget.js +2662 -0
  77. package/public/docs-mock-api-sw.js +589 -0
  78. package/public/docs-mock-api-sw.js.map +7 -0
  79. package/scripts/ai-init.mjs +167 -0
  80. package/scripts/docs-mock-api-vite-plugin.ts +116 -0
  81. package/scripts/docs-open-in-editor-plugin.ts +130 -0
  82. package/scripts/pre-publish.mjs +2 -1
  83. package/src/core/components/functional/example/example.ts +1 -1
  84. package/src/core/components/functional/fetch/fetch.md +13 -11
  85. package/src/core/components/functional/if/if.md +4 -11
  86. package/src/core/components/functional/list/list.demo.ts +4 -4
  87. package/src/core/components/functional/list/list.md +60 -194
  88. package/src/core/components/functional/list/list.ts +8 -7
  89. package/src/core/components/functional/queue/queue.demo.ts +1 -1
  90. package/src/core/components/functional/queue/queue.md +70 -85
  91. package/src/core/components/functional/queue/queue.ts +4 -4
  92. package/src/core/components/functional/router/router.md +62 -97
  93. package/src/core/components/functional/router/router.ts +1 -1
  94. package/src/core/components/functional/states/states.md +2 -2
  95. package/src/core/components/functional/submit/submit.md +86 -55
  96. package/src/core/components/functional/submit/submit.ts +10 -3
  97. package/src/core/components/ui/captcha/captcha.md +2 -2
  98. package/src/core/components/ui/card/card.md +1 -1
  99. package/src/core/components/ui/form/checkbox/checkbox.md +5 -32
  100. package/src/core/components/ui/form/input/input.md +5 -30
  101. package/src/core/components/ui/form/input-autocomplete/input-autocomplete.md +6 -4
  102. package/src/core/components/ui/form/radio/radio.md +5 -32
  103. package/src/core/components/ui/form/select/select.md +5 -31
  104. package/src/core/components/ui/form/switch/switch.md +5 -32
  105. package/src/core/components/ui/loader/loader.md +1 -13
  106. package/src/core/components/ui/table/table.md +3 -3
  107. package/src/core/directives/DataProvider.sub.spec.ts +96 -0
  108. package/src/core/directives/DataProvider.ts +109 -40
  109. package/src/core/utils/PublisherProxy.ts +33 -18
  110. package/src/core/utils/dataProviderKey.ts +23 -0
  111. package/src/core/utils/publisherPathKey.spec.ts +58 -0
  112. package/src/docs/_core-concept/dataFlow.md +73 -0
  113. package/src/docs/_core-concept/subscriber.md +9 -10
  114. package/src/docs/_decorators/ancestor-attribute.md +4 -3
  115. package/src/docs/_decorators/auto-subscribe.md +19 -16
  116. package/src/docs/_decorators/bind.md +19 -16
  117. package/src/docs/_decorators/get.md +7 -4
  118. package/src/docs/_decorators/handle.md +15 -13
  119. package/src/docs/_decorators/on-assign.md +53 -53
  120. package/src/docs/_decorators/publish.md +2 -1
  121. package/src/docs/_decorators/subscribe.md +70 -9
  122. package/src/docs/_decorators/wait-for-ancestors.md +13 -10
  123. package/src/docs/_directives/sub.md +91 -0
  124. package/src/docs/_getting-started/ai-agents.md +56 -0
  125. package/src/docs/_getting-started/concorde-manual-install.md +133 -0
  126. package/src/docs/_getting-started/concorde-outside.md +13 -123
  127. package/src/docs/_getting-started/create-a-component.md +2 -0
  128. package/src/docs/_getting-started/my-first-component.md +236 -0
  129. package/src/docs/_getting-started/my-first-subscriber.md +29 -83
  130. package/src/docs/_getting-started/pubsub.md +21 -134
  131. package/src/docs/_getting-started/start.md +26 -18
  132. package/src/docs/_misc/api-configuration.md +79 -0
  133. package/src/docs/_misc/dataProviderKey.md +34 -1
  134. package/src/docs/_misc/docs-mock-api.md +60 -0
  135. package/src/docs/_misc/endpoint.md +2 -1
  136. package/src/docs/_misc/html-integration.md +13 -0
  137. package/src/docs/code.ts +58 -12
  138. package/src/docs/components/docs-demo-sources.ts +397 -0
  139. package/src/docs/components/docs-lit-demo-raw.ts +28 -0
  140. package/src/docs/components/docs-lit-demo.ts +166 -0
  141. package/src/docs/components/docs-source-link.ts +72 -0
  142. package/src/docs/docs-location.ts +54 -0
  143. package/src/docs/docs.ts +12 -0
  144. package/src/docs/example/decorators-demo-bind-demos.ts +41 -46
  145. package/src/docs/example/decorators-demo-geo.ts +16 -11
  146. package/src/docs/example/decorators-demo-init.ts +2 -228
  147. package/src/docs/example/decorators-demo-subscribe-publish-get-demos.ts +54 -14
  148. package/src/docs/example/decorators-demo.ts +71 -70
  149. package/src/docs/example/docs-api-config-demos.ts +234 -0
  150. package/src/docs/example/docs-joke-demos.ts +297 -0
  151. package/src/docs/example/docs-list-demos.ts +179 -0
  152. package/src/docs/example/docs-provider-keys.ts +315 -0
  153. package/src/docs/example/docs-queue-demos.ts +114 -0
  154. package/src/docs/example/docs-router-demos.ts +89 -0
  155. package/src/docs/example/docs-submit-demos.ts +455 -0
  156. package/src/docs/example/docs-toggle-demos.ts +73 -0
  157. package/src/docs/example/docs-user-two-scopes.ts +37 -0
  158. package/src/docs/example/docs-users-list.ts +71 -0
  159. package/src/docs/example/users.ts +41 -24
  160. package/src/docs/mock-api/api-config-mock.ts +152 -0
  161. package/src/docs/mock-api/fixtures.ts +377 -0
  162. package/src/docs/mock-api/register.ts +25 -0
  163. package/src/docs/mock-api/router.ts +234 -0
  164. package/src/docs/mock-api/service-worker.ts +23 -0
  165. package/src/docs/mock-api/urls.ts +11 -0
  166. package/src/docs/navigation/navigation.ts +39 -7
  167. package/src/docs/search/docs-search.json +4021 -936
  168. package/src/docs/search/markdown-renderer.ts +7 -3
  169. package/src/docs/search/page.ts +11 -14
  170. package/src/docs/search/sonic-code-markdown.spec.ts +29 -0
  171. package/src/docs/search/sonic-code-markdown.ts +28 -0
  172. package/src/docs.ts +4 -0
  173. package/src/tsconfig.json +87 -0
  174. package/src/tsconfig.tsbuildinfo +1 -1
  175. package/vite.config.mts +8 -0
  176. package/docs/assets/index-CaysOMFz.js +0 -5046
  177. package/docs/assets/index-D8mGoXzF.css +0 -1
  178. package/docs/src/docs/_misc/templates-demo.md +0 -19
  179. package/src/docs/_misc/templates-demo.md +0 -19
@@ -1,87 +1,72 @@
1
1
  # Queue
2
2
 
3
- **sonic-queue** loads content in batches based on the expression provided in the dataProviderExpression attribute.
4
-
5
- * Each batch is loaded by a [List component](#core/components/functional/list/list.md/list) whose dataProvider is created from the dataProviderExpression attribute.
6
- * Upon initialization, it looks at the dataFilterProvider attribute, which provides the address of a publisher.
7
- If this attribute is found, Queue listens to the provided publisher and resets itself whenever the content of the publisher is modified.
8
- The values provided in this publisher are added as parameters to each request.
9
- * The key property can be used to target a specific property in the API response as fetch does.
10
-
11
- List extends the mixin [Subscriber](#docs/_core-concept/subscriber.md/subscriber)
12
-
13
-
14
- <sonic-code>
15
- <template>
16
- <sonic-queue
17
- class="grid grid-cols-3 gap-3"
18
- dataProviderExpression="communes?limit=$limit"
19
- limit="30"
20
- serviceURL="https://geo.api.gouv.fr/"
21
- debug
22
- >
23
- <template>
24
- <div data-bind ::inner-html="$nom" class="bg-neutral-100 p-2">
25
- queue
26
- </div>
27
- </template>
28
- </sonic-queue>
29
- </template>
30
- </sonic-code>
31
-
32
- <sonic-code>
33
- <template>
34
- <sonic-queue
35
- lazyload
36
- dataProviderExpression="api/users?page=$offset&per_page=$limit"
37
- offset="2"
38
- limit="5"
39
- dataFilterProvider="filter"
40
- targetRequestDuration="500"
41
- serviceURL="https://reqres.in"
42
- key="data"
43
- debug
44
- >
45
- <template>
46
- <div class="flex px-4 py-3 items-center gap-4">
47
- <sonic-image data-bind ::src="$avatar" rounded="full" ratio="1/1" class="w-20 block"></sonic-image>
48
- <div>
49
- <div class="text-bold text-2xl mb-2">
50
- <span data-bind ::inner-html="$first_name"></span>
51
- <span data-bind ::inner-html="$last_name"></span>
52
- </div>
53
- <sonic-button data-bind ::href="mailto|$email" size="xs" variant="outline"> Contact </sonic-button>
54
- </div>
55
- </div>
56
- <div class="border-0 border-t-2 border-t-neutral-200 w-full border-solid"></div>
57
- </template>
58
- </sonic-queue>
59
- </template>
60
- </sonic-code>
61
-
62
- <sonic-code>
63
- <template>
64
- <sonic-list
65
- lazyload
66
- fetch
67
- dataProvider="api/users?page=2&per_page=5"
68
- serviceURL="https://reqres.in"
69
- key="data"
70
- debug
71
- >
72
- <template>
73
- <div class="flex px-4 py-3 items-center gap-4">
74
- <sonic-image data-bind ::src="$avatar" rounded="full" ratio="1/1" class="w-20 block"></sonic-image>
75
- <div>
76
- <div class="text-bold text-2xl mb-2">
77
- <span data-bind ::inner-html="$first_name"></span>
78
- <span data-bind ::inner-html="$last_name"></span>
79
- </div>
80
- <sonic-button data-bind ::href="mailto|$email" size="xs" variant="outline"> Contact </sonic-button>
81
- </div>
82
- </div>
83
- <div class="border-0 border-t-2 border-t-neutral-200 w-full border-solid"></div>
84
- </template>
85
- </sonic-list>
86
- </template>
87
- </sonic-code>
3
+ > **Try offline:** `serviceURL="/docs-mock-api"` see [Local API demos](#docs/_misc/docs-mock-api.md/docs-mock-api). Row rendering: [Data flow](#docs/_core-concept/dataFlow.md/dataFlow) (`.items` property binding).
4
+
5
+ **sonic-queue** loads data in **batches**. Each batch is an internal [List](#core/components/functional/list/list.md/list) with its own `dataProvider` (`…/list-item/0`, `…/1`, …).
6
+
7
+ | Mechanism | Role |
8
+ |-----------|------|
9
+ | **`dataProviderExpression`** | API path template; `$offset` and `$limit` are replaced per batch |
10
+ | **`lazyload`** | Load the next batch when the user scrolls near the end |
11
+ | **`dataFilterProvider`** | Publisher id of a form (`formDataProvider`); field values are merged into the request query string |
12
+ | **`filteredFields`** | Optional list of form field names to **exclude** from the query (space-separated) — omit when every field should be sent |
13
+ | **`.items`**, **`.noItems`**, **`.separator`**, **`.skeleton`** | Lit callbacks forwarded to each batch list (use the **dot** — functions are properties, not attributes) |
14
+
15
+ ## Lazy load — `$offset` and `$limit`
16
+
17
+ When the expression contains **`$offset`** and **`$limit`**, the queue:
18
+
19
+ 1. Fetches the first batch with `offset=0` (or the initial `offset` attribute) and `per_page=$limit`.
20
+ 2. On scroll, appends a batch with `offset` increased by the previous batch size.
21
+ 3. Stops when a batch returns fewer rows than `limit` (or none).
22
+
23
+ The doc mock implements this on `GET /docs-mock-api/api/users?offset=…&per_page=…` (`paginateUsers` in `src/docs/mock-api/router.ts`).
24
+
25
+ <docs-lit-demo for="docs-queue-users-demo"></docs-lit-demo>
26
+
27
+ Wrap the queue in a **fixed height** with **`overflow-y-auto`** so lazy load triggers when scrolling inside the box (same layout as the [TS starter](https://github.com/supersoniks/create-concorde-ts-starter) `demo-queue-templates`).
28
+
29
+ Try scrolling after load — batches of 4 users. Search e.g. `George`, `Bluth`, or `zzz` for empty results.
30
+
31
+ ### Expression example
32
+
33
+ ```typescript
34
+ html`<sonic-queue
35
+ lazyload
36
+ serviceURL="/docs-mock-api"
37
+ dataProviderExpression="api/users?offset=$offset&limit=$limit"
38
+ key="data"
39
+ limit="4"
40
+ class="grid max-h-96 overflow-y-auto"
41
+ .items=${this.renderUser}
42
+ ></sonic-queue>`;
43
+ ```
44
+
45
+ Without **`$offset`** in the expression, the queue behaves like a single list (one batch), e.g. geo communes below.
46
+
47
+ ## Filter `dataFilterProvider` + `q`
48
+
49
+ One search field (`name="q"`) on `formDataProvider="filter"`. The queue listens via **`dataFilterProvider="filter"`** and, on change:
50
+
51
+ 1. Resets loaded batches.
52
+ 2. Appends each non-empty form field to the query (here only **`q`** — no `filteredFields` needed).
53
+ 3. Fetches again from offset `0`.
54
+
55
+ Use **`filteredFields`** only when the form has extra fields that must **not** be sent to the API (e.g. `filteredFields="rememberMe internalId"`).
56
+
57
+ The mock API filters before pagination — same haystack logic as the starter (`filterDocsUsers` in `src/docs/mock-api/fixtures.ts`, used by `paginateUsers` in `router.ts` / Service Worker):
58
+
59
+ ```typescript
60
+ const haystack = `${first_name} ${last_name} ${email}`.toLowerCase();
61
+ return haystack.includes(q);
62
+ ```
63
+
64
+ ## Simple batch (no lazy scroll)
65
+
66
+ Geo communes: expression uses **`$limit` only** (no `$offset`) — one request, one batch.
67
+
68
+ <docs-lit-demo for="docs-queue-geo-demo"></docs-lit-demo>
69
+
70
+ ## HTML `<template>` children
71
+
72
+ Optional for hosts without Lit — see [HTML integration](#docs/_misc/html-integration.md/html-integration).
@@ -1,94 +1,77 @@
1
1
  # Router
2
2
 
3
- The router observes the document.location changes and updates its view as follows
3
+ **sonic-router** watches `document.location` (pathname + hash) and renders the matching view.
4
4
 
5
- ## Data-route / Basic
5
+ From a **Lit** parent, pass a **`.routes`** map (property binding — same rule as [`.items` on list](#core/components/functional/list/list.md/list)): keys are path patterns, values are render functions. Use **`fallback`** when nothing matches.
6
6
 
7
- When the data-route attribute of a template matches the current url, the content of this template is rendered
7
+ Legacy HTML **`<template data-route="…">`** remains for hosts without Lit [HTML integration](#docs/_misc/html-integration.md/html-integration).
8
8
 
9
- <sonic-code>
10
- <template>
11
- <div class="flex gap-2 items-center">
12
- <sonic-button href="#core/components/functional/router/router.md/router#home" size="xs">Home</sonic-button>
13
- <sonic-button href="#core/components/functional/router/router.md/router#about" size="xs">About</sonic-button>
14
- <sonic-button href="#core/components/functional/router/router.md/router#work" size="xs">Work</sonic-button>
15
- <sonic-button href="#core/components/functional/router/router.md/router#contact" size="xs">Contact</sonic-button>
16
- </div>
17
- <sonic-router>
18
- <template data-route="#home">
19
- <div class="text-center text-neutral-700 border rounded text-4xl my-6 p-3 ">Home</div>
20
- </template>
21
- <template data-route="#about">
22
- <div class="text-center text-neutral-700 border rounded text-4xl my-6 p-3 ">About</div>
23
- </template>
24
- <template data-route="#work">
25
- <div class="text-center text-neutral-700 border rounded text-4xl my-6 p-3 ">Work</div>
26
- </template>
27
- <template data-route="#contact">
28
- <div class="text-center text-neutral-700 border rounded text-4xl my-6 p-3 ">Contact</div>
29
- </template>
30
- </sonic-router>
31
- </template>
32
- </sonic-code>
9
+ ## Static routes (no parameters)
33
10
 
34
- ## Data-route / Regexp
11
+ Route keys are matched against `pathname + hash`. A simple hash route `#home` matches when the location contains that segment.
35
12
 
36
- You can use any RegExp in the data-route attribute of your templates to match the current location and to extract variables from it using capturing groups.
37
- A dataProvider attribute is generated using the dataProviderExpression where $1, $2... are replaced with this variables.
13
+ On the **doc site**, the page URL is already a hash (`#…/router.md/router`). Demos append a **second** hash for in-page routes (`#…/router#home`), use **`href` + `autoActive="strict"`** on `sonic-button` for the active state, and `history.replaceState` on click so markdown is not reloaded (`setDocsDemoSubHash` in `src/docs/docs-location.ts`).
38
14
 
39
- **e.g.**, data-route="#couleur_<b class="text-danger">(\d+)</b>" => dataProviderExpression="api/unknown/<b class="text-danger">$1</b>"
15
+ <docs-lit-demo for="docs-router-basic-demo"></docs-lit-demo>
40
16
 
41
- The rendered content of the matching template is scoped with this **dataProvider**.
42
- You can make creative usage on this feature to generate dynamic content based on services.
17
+ ```typescript
18
+ @state()
19
+ private routes = {
20
+ "#home": () => html`<div>Home</div>`,
21
+ "#about": () => html`<div>About</div>`,
22
+ fallback: () => html`<div>Not found</div>`,
23
+ };
43
24
 
44
- <sonic-code>
45
- <template>
46
- <sonic-list fetch dataProvider="api/unknown" key="data" class="flex gap-2 items-center" >
47
- <template>
48
- <sonic-button radio size="xs" data-bind ::href="#core/components/functional/router/router.md/router#couleur_$id">
49
- <span data-bind ::inner-html="ucFirst|$name"></span>
50
- </sonic-button>
51
- </template>
52
- </sonic-list>
53
- <sonic-router>
54
- <template data-route="#couleur_(\d+)" dataProviderExpression="api/unknown/$1">
55
- <sonic-fetch>
56
- <input type="color" disabled data-bind ::value="$data.color" class=" w-full h-10 my-3" />
57
- </sonic-fetch>
58
- </template>
59
- </sonic-router>
60
- </template>
61
- </sonic-code>
25
+ html`
26
+ <sonic-button href="#home">Home</sonic-button>
27
+ <sonic-router .routes=${this.routes}></sonic-router>
28
+ `;
29
+ ```
62
30
 
63
- ## Data-route / Url-pattern
31
+ | Key | When it runs |
32
+ |-----|----------------|
33
+ | `"#home"`, `"#about"`, … | `RegExp` or [url-pattern](https://www.npmjs.com/package/url-pattern) test succeeds on current location |
34
+ | **`fallback`** | No other route matched (not an attribute — a key on the same object) |
64
35
 
65
- Same as RegExp but using <a href="https://www.npmjs.com/package/url-pattern" target="_blank">url patterns</a>
66
- **e.g.**, data-route="#couleur_<b class="text-danger">:id</b>" => dataProviderExpression="api/unknown/<b class="text-danger">:id</b>"
36
+ ## Routes with parameters
67
37
 
68
- <sonic-code>
69
- <template>
70
- <sonic-list fetch dataProvider="api/unknown" key="data" class="flex gap-2 items-center" >
71
- <template>
72
- <sonic-button radio size="xs" data-bind ::href="#core/components/functional/router/router.md/router#couleur_$id">
73
- <span data-bind ::inner-html="ucFirst|$name"></span>
74
- </sonic-button>
75
- </template>
76
- </sonic-list>
77
- <sonic-router>
78
- <template data-route="/*#couleur_:id" dataProviderExpression="api/unknown/:id">
79
- <sonic-fetch>
80
- <input type="color" disabled data-bind ::value="$data.color" class=" w-full h-10 my-3" />
81
- </sonic-fetch>
82
- </template>
83
- </sonic-router>
84
- </template>
85
- </sonic-code>
38
+ Two styles (see `router.demo.ts` and `docs-router-params-demo`):
39
+
40
+ ### Url-pattern (`:name`)
41
+
42
+ Key uses **`:param`** segments. The render function receives an **object** `{ param: string }`.
43
+
44
+ <docs-lit-demo for="docs-router-params-demo"></docs-lit-demo>
45
+
46
+ ```typescript
47
+ "#couleur/:id": ({ id }) => html`<p>Colour id: ${id}</p>`,
48
+ ```
86
49
 
87
- ## Redirect
50
+ ### RegExp (capturing groups)
88
51
 
89
- Redirect allows to redirect to a url when a data is provided.
90
- Here Redirect waits that a data is available in the property *theData* of the dataProvider *stupid-data-set-id*
91
- We are then redirected to the url *#data-is-set* which does nothing in itself.
52
+ Key is a **RegExp** string with `(\d+)` / `(\w+)` groups. The render function receives an **array** of captured strings (in order).
53
+
54
+ ```typescript
55
+ "#products/(\\d+)/(\\w+)": ([productId, slug]) =>
56
+ html`<p>Product ${productId}, slug ${slug}</p>`,
57
+ ```
58
+
59
+ With parameters you usually render data directly in Lit (`${id}`). The old **`<template data-route>` + `dataProviderExpression`** pattern scoped a `dataProvider` for `data-bind` / fetch children — prefer **`@subscribe`** or explicit props when using `.routes`.
60
+
61
+ ## `.routes` binding
62
+
63
+ Always use **`.routes=${…}`** in Lit templates: route handlers are functions and must be set as **properties**, not HTML attributes.
64
+
65
+ ## Optional attributes
66
+
67
+ | Attribute | Role |
68
+ |-----------|------|
69
+ | **`basePath`** | Prefix for pattern matching (default allows optional leading segments) |
70
+ | **`fallBackRoute`** | If set and no template/route matches, navigates to this URL (redirect). Distinct from **`routes.fallback`** which only renders content |
71
+
72
+ ## `sonic-redirect`
73
+
74
+ Separate component: redirect when data appears on a publisher (login steps, wizards). Not part of the `.routes` map.
92
75
 
93
76
  <sonic-code>
94
77
  <template>
@@ -101,29 +84,11 @@ We are then redirected to the url *#data-is-set* which does nothing in itself.
101
84
  Delete the data and do a history.back()
102
85
  </sonic-button>
103
86
  </div>
104
-
105
87
  </template>
106
88
  </sonic-code>
107
89
 
108
- Example of use : use with a router and a submit to manage the steps of login/logout, display of user info.
109
-
110
- ## Fallback
111
-
112
- The fallback route is rendered when no other route matches the current location.
113
-
114
- <sonic-code>
115
- <sonic-router>
116
- <template data-route="#home">
117
- <div>Home</div>
118
- </template>
119
- <template data-route="#fallback">
120
- <div>Fallback</div>
121
- </template>
122
- </sonic-router>
123
- </sonic-code>
124
-
125
- ## Programmatic routes
126
-
127
-
90
+ Example: combine with **`.routes`** and **submit** for login / logout / profile steps.
128
91
 
92
+ ## Package demo
129
93
 
94
+ `sonic-router-demo` (`router.demo.ts`) — home, user profile (`#user/:id/:slug`), products RegExp, **fallback** 404.
@@ -41,7 +41,7 @@ When using **capturing groups ()** the stored values are accessible via the **da
41
41
 
42
42
  <sonic-code>
43
43
  <template>
44
- <div serviceURL="https://reqres.in">
44
+ <div serviceURL="/docs-mock-api">
45
45
  <sonic-list formDataProvider="states-regexp-example" fetch dataProvider="api/unknown" key="data" class="flex gap-2 items-center" >
46
46
  <template>
47
47
  <sonic-button radio size="xs" name="selection" data-bind ::value="#couleur_$id">
@@ -67,7 +67,7 @@ Same as RegExp but using <a href="https://www.npmjs.com/package/url-pattern" tar
67
67
 
68
68
  <sonic-code>
69
69
  <template>
70
- <div serviceURL="https://reqres.in">
70
+ <div serviceURL="/docs-mock-api">
71
71
  <sonic-list formDataProvider="states-regexp-example" fetch dataProvider="api/unknown" key="data" class="flex gap-2 items-center" >
72
72
  <template>
73
73
  <sonic-button radio size="xs" name="selection" data-bind ::value="#couleur_$id">
@@ -1,58 +1,90 @@
1
1
  # Submit
2
2
 
3
- ## The submit element is used to send data to a rest service
4
- * The api is set up like a [fetcher](#core/components/functional/fetch/fetch.md/fetch).
5
- * The *formDataProvider* attribute points to the adress where the data is held by a publisher.
6
- * This attribute is also used by form elements such as *sonic-input*, or *sonic-select*, which fill this publisher with their *value* attribute according to their *name* attribute
7
- * The *method* attribute allows you to choose the sending method: *put/delete/post*, *post* being the default method.
8
- * If the *onClick* attribute is present, the data is sent when the content is clicked on
9
- * If the *onEnterKey* attribute is present, data is sent when the enter key of an element contained in the *sonic-submit* with focus is pressed
10
- * During sending, *sonic-submit* elements with the same *dataProvider* attribute have the *disabled="disabled "* property, which has the effect of disabling their content
11
- * The *clearedDataOnSuccess* attribute can be used to clear the data from the corresponding dataProvider when the call to the api has provided a result.
12
-
13
- ## Form example
14
- <sonic-code>
15
- <template>
16
- <sonic-scope
17
- serviceURL="https://reqres.in" dataProvider="api/register"
18
- formDataProvider="submit-example" submitResultDataProvider="submit-example-result"
19
- method="post"
20
- class="max-w-lg block"
21
- >
22
- <sonic-submit onEnterKey>
23
- <div class="grid grid-cols-2 gap-4 mb-4 ">
24
- <sonic-input required name="email" type="email" value="eve.holt@reqres.in"></sonic-input>
25
- <sonic-input required type="password" name="password" value="pistol"></sonic-input>
26
- </div>
27
- </sonic-submit>
28
- <sonic-submit onClick>
29
- <sonic-button type="success" class="w-full">Submit</sonic-button>
30
- </sonic-submit>
31
- </sonic-scope>
32
- </template>
33
- </sonic-code>
3
+ > **Live demos:** `<docs-lit-demo>` + `src/docs/example/docs-submit-demos.ts`. Use [Local API demos](#docs/_misc/docs-mock-api.md/docs-mock-api) (`serviceURL="/docs-mock-api"`).
34
4
 
5
+ ## Overview
35
6
 
7
+ **sonic-submit** sends the **formDataProvider** publisher to a REST endpoint (same configuration model as [fetch](#core/components/functional/fetch/fetch.md/fetch): `serviceURL` on an ancestor, path via `dataProvider` or `endPoint`).
36
8
 
9
+ | Trigger | Attribute |
10
+ |---------|-----------|
11
+ | Click inside the slot | `onClick` |
12
+ | Enter in a focused field inside the slot | `onEnterKey` |
37
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) |
38
27
 
39
- ## Result handling example
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.
40
29
 
41
- Result will show when something has been submit because the **dataprovider** used in this example is the same as the **submitResultDataProvider** used in the previous form.
42
- <sonic-code>
43
- <template>
44
- <div dataProvider="submit-example-result">
45
- <div>Id : <span data-bind ::inner-html="$id"></span></div>
46
- <div>Token : <span data-bind ::inner-html="$token"></span></div>
47
- <div data-bind ::inner-html="$error"></div>
48
- </div>
49
- </template>
50
- </sonic-code>
30
+ ## Form and result handling
31
+
32
+ POST to mock `api/register`; result publisher `submit-example-result`.
33
+
34
+ <docs-lit-demo for="docs-submit-demo"></docs-lit-demo>
35
+
36
+ ## Native HTML form
37
+
38
+ With **`native`**, Concorde does **not** call `fetch`. After form validation it:
39
+
40
+ 1. Copies **formDataProvider** values into matching `<input>` / `<select>` / `<textarea>` inside the closest **`<form>`** (creates hidden inputs if needed).
41
+ 2. Programmatically clicks a hidden native `type="submit"` control (`name` / `value` on **sonic-submit** if you need them).
42
+
43
+ Use a real `<form action="…" method="post">` ancestor. For SPAs, a named **`target`** (e.g. iframe) avoids leaving the doc page.
44
+
45
+ <docs-lit-demo for="docs-submit-native-demo"></docs-lit-demo>
46
+
47
+ ## sendAsFormData
48
+
49
+ Sends fields as **`multipart/form-data`** instead of `application/json` (response is still parsed as JSON).
51
50
 
51
+ <docs-lit-demo for="docs-submit-formdata-demo"></docs-lit-demo>
52
52
 
53
- ## dot notation
53
+ ## submit-result-key
54
54
 
55
- You can write the folowing code where the name attribute is written in dot notation.
55
+ When the API wraps the payload (e.g. `{ data: { id, token } }`), set **`submit-result-key="data"`** on **sonic-submit** so **submitResultDataProvider** receives only the inner object.
56
+
57
+ <docs-lit-demo for="docs-submit-result-key-demo"></docs-lit-demo>
58
+
59
+ Mock endpoint: `POST /docs-mock-api/api/register/nested`.
60
+
61
+ ## clearedDataOnSuccess
62
+
63
+ Lists one or more publisher ids (space-separated). After the API returns a result object, each is set to `{}` — useful to reset the form publisher.
64
+
65
+ <docs-lit-demo for="docs-submit-clear-demo"></docs-lit-demo>
66
+
67
+ ## Custom `submit` event
68
+
69
+ Listen for the bubbling **`submit`** event; **`event.detail`** is the same result written to **submitResultDataProvider** (if configured).
70
+
71
+ <docs-lit-demo for="docs-submit-event-demo"></docs-lit-demo>
72
+
73
+ ## endPoint vs dataProvider
74
+
75
+ Ancestor **`dataProvider`** is the default path; **`endPoint`** on **sonic-submit** overrides it for that button only.
76
+
77
+ <docs-lit-demo for="docs-submit-endpoint-demo"></docs-lit-demo>
78
+
79
+ ## method="get"
80
+
81
+ Appends publisher fields as a query string on the endpoint, then performs a GET. The mock route `api/register/echo` returns the query for inspection.
82
+
83
+ <docs-lit-demo for="docs-submit-get-demo"></docs-lit-demo>
84
+
85
+ ## dot notation (formDataProvider shape)
86
+
87
+ You can use dot notation in **`name`** on form controls; the publisher stores nested objects:
56
88
 
57
89
  <sonic-code>
58
90
  <template>
@@ -65,19 +97,18 @@ You can write the folowing code where the name attribute is written in dot notat
65
97
  </template>
66
98
  </sonic-code>
67
99
 
68
- The data will be stored in the following format:
100
+ Stored shape:
69
101
 
70
- <sonic-code language="typescript">
102
+ <sonic-code language="typescript">
71
103
  <template>
72
104
  {
73
- email: {
74
- value: "eve.holt@reqres.in",
75
- },
76
- details: {
77
- password: {
78
- value: "pistol",
79
- },
80
- },
105
+ email: { value: "eve.holt@reqres.in" },
106
+ details: { password: { value: "pistol" } }
81
107
  }
82
108
  </template>
83
- </sonic-code>
109
+ </sonic-code>
110
+
111
+ ## Related
112
+
113
+ - [Captcha](#core/components/ui/captcha/captcha.md/captcha) — submit waits for `captchaToken` when validation is required.
114
+ - [HTML integration](#docs/_misc/html-integration.md/html-integration) — legacy `data-bind` result blocks; prefer **submitResultDataProvider** + `@subscribe` in Lit demos.
@@ -3,7 +3,7 @@
3
3
  <sonic-code>
4
4
  <template>
5
5
  <sonic-captcha formDataProvider="captchaTestDataProvider" key="6Leq5V0iAAAAAB-41DlWN335jDlcIuXmhNtdd00t">
6
- <sonic-submit serviceURL="https://reqres.in" endPoint="api/unknown" onclick>
6
+ <sonic-submit serviceURL="/docs-mock-api" endPoint="api/unknown" onclick>
7
7
  <sonic-button class="mt-4">Submit with captcha</sonic-button>
8
8
  </sonic-submit>
9
9
  </sonic-captcha>
@@ -21,4 +21,4 @@
21
21
  </sonic-captcha>
22
22
  </template>
23
23
  </sonic-code>
24
-
24
+
@@ -51,7 +51,7 @@
51
51
  <sonic-card-main >
52
52
  <h3>Main area</h3>
53
53
  <p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Iure id dolor debitis deleniti eligendi natus dolorem a commodi sunt dicta? Ipsa asperiores magni consequuntur dolor voluptatibus. Maxime, nemo? Facere, odio.</p>
54
- <iframe width="560" height="315" src="https://www.youtube.com/embed/IZTOtyksyPs" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
54
+ <iframe width="560" height="315" src="https://www.youtube.com/embed/aqz-KE-bpKQ" title="Big Buck Bunny (Blender Foundation)" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
55
55
  </sonic-card-main>
56
56
  </sonic-card>
57
57
  </template>
@@ -70,35 +70,8 @@
70
70
  </template>
71
71
  </sonic-code>
72
72
 
73
- ## Example of use
74
- <sonic-code>
75
- <template>
76
- <sonic-subscriber dataProvider="jokeFilter" class="text-xl my-4 block font-bold">
77
- Remove following jokes :
78
- <sonic-value key="blacklistFlags" class="block text-sm"></sonic-value>
79
- </sonic-subscriber>
80
- <div formDataProvider="jokeFilter" class="grid grid-cols-2 lg:grid-cols-3 gap-x-6 gap-y-2 mt-2 mb-3">
81
- <sonic-checkbox name="blacklistFlags" value="nsfw">nsfw</sonic-checkbox>
82
- <sonic-checkbox name="blacklistFlags" value="religious">religious</sonic-checkbox>
83
- <sonic-checkbox name="blacklistFlags" value="political">political</sonic-checkbox>
84
- <sonic-checkbox name="blacklistFlags" value="racist" checked disabled>racist</sonic-checkbox>
85
- <sonic-checkbox name="blacklistFlags" value="sexist" checked disabled>sexist</sonic-checkbox>
86
- <sonic-checkbox name="blacklistFlags" value="explicit">explicit</sonic-checkbox>
87
- </div>
88
- <sonic-queue
89
- lazyload
90
- dataProviderExpression="joke/Any?amount=10&lang=en"
91
- dataFilterProvider="jokeFilter"
92
- serviceURL="https://v2.jokeapi.dev"
93
- key="jokes"
94
- >
95
- <template>
96
- <div class="border-0 border-b-[1px] border-b-neutral-300 py-3 leading-tight">
97
- <sonic-value key="joke"></sonic-value>
98
- <sonic-value key="setup" class="font-bold"></sonic-value><br>
99
- <sonic-value key="delivery"></sonic-value>
100
- </div>
101
- </template>
102
- </sonic-queue>
103
- </template>
104
- </sonic-code>
73
+ ## Example of use — blacklist + queue
74
+
75
+ Checked **`blacklistFlags`** values are sent to the mock API (`?blacklistFlags=racist,sexist,…`), which excludes jokes whose **`flags`** match (see `filterDocsJokes` in `src/docs/mock-api/fixtures.ts`).
76
+
77
+ <docs-lit-demo for="docs-joke-blacklist-demo"></docs-lit-demo>