@supersoniks/concorde 4.6.0 → 4.7.3
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/.gitlab-ci.yml +23 -0
- package/README.md +106 -55
- package/ai/AGENTS.md +52 -0
- package/ai/README.md +30 -0
- package/ai/cursor/rules/concorde-menu.mdc +15 -0
- package/ai/cursor/rules/concorde-scope.mdc +14 -0
- package/ai/cursor/rules/concorde-theme.mdc +13 -0
- package/ai/cursor/rules/concorde.mdc +49 -0
- package/ai/jetbrains/rules/concorde.md +39 -0
- package/ai/skills/concorde/SKILL.md +273 -0
- package/ai/skills/concorde-get-set-dp/SKILL.md +194 -0
- package/ai/skills/concorde-imports/SKILL.md +78 -0
- package/ai/skills/concorde-menu/SKILL.md +74 -0
- package/ai/skills/concorde-scope/SKILL.md +70 -0
- package/ai/skills/concorde-theme/SKILL.md +46 -0
- package/build-infos.json +1 -1
- package/concorde-core.bundle.js +152 -152
- package/concorde-core.es.js +1853 -1689
- package/dist/altcha-widget.js +2662 -0
- package/dist/concorde-core.bundle.js +152 -152
- package/dist/concorde-core.es.js +1853 -1689
- package/dist/docs-mock-api-sw.js +589 -0
- package/dist/docs-mock-api-sw.js.map +7 -0
- package/docs/altcha-widget.js +2662 -0
- package/docs/assets/index-D9pxaQYK.js +7508 -0
- package/docs/assets/index-t0-i22oI.css +1 -0
- package/docs/docs-mock-api-sw.js +589 -0
- package/docs/docs-mock-api-sw.js.map +7 -0
- package/docs/index.html +2 -2
- package/docs/src/core/components/functional/fetch/fetch.md +13 -11
- package/docs/src/core/components/functional/if/if.md +4 -11
- package/docs/src/core/components/functional/list/list.md +60 -194
- package/docs/src/core/components/functional/queue/queue.md +70 -85
- package/docs/src/core/components/functional/router/router.md +62 -97
- package/docs/src/core/components/functional/states/states.md +2 -2
- package/docs/src/core/components/functional/submit/submit.md +86 -55
- package/docs/src/core/components/ui/captcha/captcha.md +2 -2
- package/docs/src/core/components/ui/card/card.md +1 -1
- package/docs/src/core/components/ui/form/checkbox/checkbox.md +5 -32
- package/docs/src/core/components/ui/form/input/input.md +5 -30
- package/docs/src/core/components/ui/form/input-autocomplete/input-autocomplete.md +6 -4
- package/docs/src/core/components/ui/form/radio/radio.md +5 -32
- package/docs/src/core/components/ui/form/select/select.md +5 -31
- package/docs/src/core/components/ui/form/switch/switch.md +5 -32
- package/docs/src/core/components/ui/loader/loader.md +1 -13
- package/docs/src/core/components/ui/table/table.md +3 -3
- package/docs/src/docs/_core-concept/dataFlow.md +73 -0
- package/docs/src/docs/_core-concept/subscriber.md +9 -10
- package/docs/src/docs/_decorators/ancestor-attribute.md +4 -3
- package/docs/src/docs/_decorators/auto-subscribe.md +19 -16
- package/docs/src/docs/_decorators/bind.md +20 -17
- package/docs/src/docs/_decorators/get.md +7 -4
- package/docs/src/docs/_decorators/handle.md +171 -0
- package/docs/src/docs/_decorators/on-assign.md +99 -73
- package/docs/src/docs/_decorators/publish.md +2 -1
- package/docs/src/docs/_decorators/subscribe.md +70 -9
- package/docs/src/docs/_decorators/wait-for-ancestors.md +13 -10
- package/docs/src/docs/_directives/sub.md +91 -0
- package/docs/src/docs/_getting-started/ai-agents.md +56 -0
- package/docs/src/docs/_getting-started/concorde-manual-install.md +133 -0
- package/docs/src/docs/_getting-started/concorde-outside.md +13 -123
- package/docs/src/docs/_getting-started/create-a-component.md +2 -0
- package/docs/src/docs/_getting-started/my-first-component.md +236 -0
- package/docs/src/docs/_getting-started/my-first-subscriber.md +29 -83
- package/docs/src/docs/_getting-started/pubsub.md +21 -134
- package/docs/src/docs/_getting-started/start.md +26 -18
- package/docs/src/docs/_misc/api-configuration.md +79 -0
- package/docs/src/docs/_misc/dataProviderKey.md +38 -5
- package/docs/src/docs/_misc/docs-mock-api.md +60 -0
- package/docs/src/docs/_misc/endpoint.md +2 -1
- package/docs/src/docs/_misc/html-integration.md +13 -0
- package/docs/src/docs/search/docs-search.json +4163 -873
- package/docs/src/tsconfig.json +380 -317
- package/gitlab/job_tests.sh +55 -0
- package/package.json +34 -3
- package/public/altcha-widget.js +2662 -0
- package/public/docs-mock-api-sw.js +589 -0
- package/public/docs-mock-api-sw.js.map +7 -0
- package/scripts/ai-init.mjs +167 -0
- package/scripts/docs-mock-api-vite-plugin.ts +116 -0
- package/scripts/docs-open-in-editor-plugin.ts +130 -0
- package/scripts/pre-publish.mjs +2 -1
- package/src/core/components/functional/example/example.ts +1 -1
- package/src/core/components/functional/fetch/fetch.md +13 -11
- package/src/core/components/functional/if/if.md +4 -11
- package/src/core/components/functional/list/list.demo.ts +4 -4
- package/src/core/components/functional/list/list.md +60 -194
- package/src/core/components/functional/list/list.ts +8 -7
- package/src/core/components/functional/queue/queue.demo.ts +1 -1
- package/src/core/components/functional/queue/queue.md +70 -85
- package/src/core/components/functional/queue/queue.ts +4 -4
- package/src/core/components/functional/router/router.md +62 -97
- package/src/core/components/functional/router/router.ts +1 -1
- package/src/core/components/functional/states/states.md +2 -2
- package/src/core/components/functional/submit/submit.md +86 -55
- package/src/core/components/functional/submit/submit.ts +10 -3
- package/src/core/components/ui/captcha/captcha.md +2 -2
- package/src/core/components/ui/card/card.md +1 -1
- package/src/core/components/ui/form/checkbox/checkbox.md +5 -32
- package/src/core/components/ui/form/input/input.md +5 -30
- package/src/core/components/ui/form/input-autocomplete/input-autocomplete.md +6 -4
- package/src/core/components/ui/form/radio/radio.md +5 -32
- package/src/core/components/ui/form/select/select.md +5 -31
- package/src/core/components/ui/form/switch/switch.md +5 -32
- package/src/core/components/ui/loader/loader.md +1 -13
- package/src/core/components/ui/table/table.md +3 -3
- package/src/core/decorators/api.spec.ts +8 -1
- package/src/core/decorators/api.ts +126 -15
- package/src/core/directives/DataProvider.sub.spec.ts +96 -0
- package/src/core/directives/DataProvider.ts +109 -40
- package/src/core/utils/HTML.ts +42 -10
- package/src/core/utils/PublisherProxy.ts +33 -18
- package/src/core/utils/dataProviderKey.ts +23 -0
- package/src/core/utils/publisherPathKey.spec.ts +58 -0
- package/src/docs/_core-concept/dataFlow.md +73 -0
- package/src/docs/_core-concept/subscriber.md +9 -10
- package/src/docs/_decorators/ancestor-attribute.md +4 -3
- package/src/docs/_decorators/auto-subscribe.md +19 -16
- package/src/docs/_decorators/bind.md +19 -16
- package/src/docs/_decorators/get.md +7 -4
- package/src/docs/_decorators/handle.md +15 -13
- package/src/docs/_decorators/on-assign.md +53 -53
- package/src/docs/_decorators/publish.md +2 -1
- package/src/docs/_decorators/subscribe.md +70 -9
- package/src/docs/_decorators/wait-for-ancestors.md +13 -10
- package/src/docs/_directives/sub.md +91 -0
- package/src/docs/_getting-started/ai-agents.md +56 -0
- package/src/docs/_getting-started/concorde-manual-install.md +133 -0
- package/src/docs/_getting-started/concorde-outside.md +13 -123
- package/src/docs/_getting-started/create-a-component.md +2 -0
- package/src/docs/_getting-started/my-first-component.md +236 -0
- package/src/docs/_getting-started/my-first-subscriber.md +29 -83
- package/src/docs/_getting-started/pubsub.md +21 -134
- package/src/docs/_getting-started/start.md +26 -18
- package/src/docs/_misc/api-configuration.md +79 -0
- package/src/docs/_misc/dataProviderKey.md +34 -1
- package/src/docs/_misc/docs-mock-api.md +60 -0
- package/src/docs/_misc/endpoint.md +2 -1
- package/src/docs/_misc/html-integration.md +13 -0
- package/src/docs/code.ts +58 -12
- package/src/docs/components/docs-demo-sources.ts +397 -0
- package/src/docs/components/docs-lit-demo-raw.ts +28 -0
- package/src/docs/components/docs-lit-demo.ts +166 -0
- package/src/docs/components/docs-source-link.ts +72 -0
- package/src/docs/docs-location.ts +54 -0
- package/src/docs/docs.ts +12 -0
- package/src/docs/example/decorators-demo-bind-demos.ts +41 -46
- package/src/docs/example/decorators-demo-geo.ts +16 -11
- package/src/docs/example/decorators-demo-init.ts +2 -228
- package/src/docs/example/decorators-demo-subscribe-publish-get-demos.ts +54 -14
- package/src/docs/example/decorators-demo.ts +71 -70
- package/src/docs/example/docs-api-config-demos.ts +234 -0
- package/src/docs/example/docs-joke-demos.ts +297 -0
- package/src/docs/example/docs-list-demos.ts +179 -0
- package/src/docs/example/docs-provider-keys.ts +315 -0
- package/src/docs/example/docs-queue-demos.ts +114 -0
- package/src/docs/example/docs-router-demos.ts +89 -0
- package/src/docs/example/docs-submit-demos.ts +455 -0
- package/src/docs/example/docs-toggle-demos.ts +73 -0
- package/src/docs/example/docs-user-two-scopes.ts +37 -0
- package/src/docs/example/docs-users-list.ts +71 -0
- package/src/docs/example/users.ts +41 -24
- package/src/docs/mock-api/api-config-mock.ts +152 -0
- package/src/docs/mock-api/fixtures.ts +377 -0
- package/src/docs/mock-api/register.ts +25 -0
- package/src/docs/mock-api/router.ts +234 -0
- package/src/docs/mock-api/service-worker.ts +23 -0
- package/src/docs/mock-api/urls.ts +11 -0
- package/src/docs/navigation/navigation.ts +39 -7
- package/src/docs/search/docs-search.json +4021 -936
- package/src/docs/search/markdown-renderer.ts +7 -3
- package/src/docs/search/page.ts +11 -14
- package/src/docs/search/sonic-code-markdown.spec.ts +29 -0
- package/src/docs/search/sonic-code-markdown.ts +28 -0
- package/src/docs.ts +4 -0
- package/src/tsconfig.json +87 -0
- package/src/tsconfig.tsbuildinfo +1 -1
- package/vite.config.mts +8 -0
- package/docs/assets/index-CaysOMFz.js +0 -5046
- package/docs/assets/index-D8mGoXzF.css +0 -1
- package/docs/src/docs/_misc/templates-demo.md +0 -19
- package/src/docs/_misc/templates-demo.md +0 -19
|
@@ -1,87 +1,72 @@
|
|
|
1
1
|
# Queue
|
|
2
2
|
|
|
3
|
-
**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
|
|
3
|
+
**sonic-router** watches `document.location` (pathname + hash) and renders the matching view.
|
|
4
4
|
|
|
5
|
-
|
|
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
|
-
|
|
7
|
+
Legacy HTML **`<template data-route="…">`** remains for hosts without Lit — [HTML integration](#docs/_misc/html-integration.md/html-integration).
|
|
8
8
|
|
|
9
|
-
|
|
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
|
-
|
|
11
|
+
Route keys are matched against `pathname + hash`. A simple hash route `#home` matches when the location contains that segment.
|
|
35
12
|
|
|
36
|
-
|
|
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
|
-
|
|
15
|
+
<docs-lit-demo for="docs-router-basic-demo"></docs-lit-demo>
|
|
40
16
|
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
50
|
+
### RegExp (capturing groups)
|
|
88
51
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
|
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="
|
|
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="
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
##
|
|
53
|
+
## submit-result-key
|
|
54
54
|
|
|
55
|
-
|
|
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
|
-
|
|
100
|
+
Stored shape:
|
|
69
101
|
|
|
70
|
-
|
|
102
|
+
<sonic-code language="typescript">
|
|
71
103
|
<template>
|
|
72
104
|
{
|
|
73
|
-
email: {
|
|
74
|
-
|
|
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="
|
|
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/
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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>
|