@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.
- 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 +220 -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 +127 -127
- package/concorde-core.es.js +1435 -1364
- package/dist/altcha-widget.js +2662 -0
- package/dist/concorde-core.bundle.js +127 -127
- package/dist/concorde-core.es.js +1435 -1364
- 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/directives/DataProvider.sub.spec.ts +96 -0
- package/src/core/directives/DataProvider.ts +109 -40
- 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
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { html, LitElement, nothing } from "lit";
|
|
2
|
+
import { customElement, state } from "lit/decorators.js";
|
|
3
|
+
import { get } from "@supersoniks/concorde/core/decorators/api";
|
|
4
|
+
import type { ApiGetResult } from "@supersoniks/concorde/core/utils/api";
|
|
5
|
+
import { Endpoint } from "@supersoniks/concorde/core/utils/endpoint";
|
|
6
|
+
import { set } from "@supersoniks/concorde/core/utils/PublisherProxy";
|
|
7
|
+
import { wording } from "@supersoniks/concorde/core/directives/Wording";
|
|
8
|
+
import { DOCS_MOCK_API_BASE } from "../mock-api/urls";
|
|
9
|
+
import {
|
|
10
|
+
DOCS_MOCK_EVENTS_API_TOKEN,
|
|
11
|
+
DOCS_MOCK_TOKEN_FRESH,
|
|
12
|
+
DOCS_MOCK_TOKEN_STALE,
|
|
13
|
+
DOCS_MOCK_TOKEN_VALID,
|
|
14
|
+
} from "../mock-api/api-config-mock";
|
|
15
|
+
import {
|
|
16
|
+
docsApiConfBearerKey,
|
|
17
|
+
docsApiConfStaleTokenKey,
|
|
18
|
+
docsApiConfTokenProviderKey,
|
|
19
|
+
docsApiConfWordingVersionKey,
|
|
20
|
+
} from "./docs-provider-keys";
|
|
21
|
+
import { tailwind } from "../tailwind";
|
|
22
|
+
|
|
23
|
+
import "../../core/components/functional/fetch/fetch";
|
|
24
|
+
import "../../core/components/functional/sonic-scope/sonic-scope";
|
|
25
|
+
import "../../core/components/ui/button/button";
|
|
26
|
+
|
|
27
|
+
type ProtectedResult = {
|
|
28
|
+
ok?: boolean;
|
|
29
|
+
message?: string;
|
|
30
|
+
tokenUsed?: string | null;
|
|
31
|
+
error?: string;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const protectedEndpoint = new Endpoint<ProtectedResult>("api/config/protected");
|
|
35
|
+
|
|
36
|
+
function resultPanel(payload: ApiGetResult<ProtectedResult> | null | undefined) {
|
|
37
|
+
const status = payload?.response?.status;
|
|
38
|
+
const r = payload?.result;
|
|
39
|
+
if (payload === null) {
|
|
40
|
+
return html`<p class="text-sm text-neutral-500">Loading…</p>`;
|
|
41
|
+
}
|
|
42
|
+
if (!payload?.response) {
|
|
43
|
+
return html`<p class="text-sm text-neutral-500">Waiting for request…</p>`;
|
|
44
|
+
}
|
|
45
|
+
return html`
|
|
46
|
+
<p class="text-sm">
|
|
47
|
+
HTTP <span class="font-mono">${status}</span>
|
|
48
|
+
${r?.message
|
|
49
|
+
? html` — <span class="font-medium">${r.message}</span>`
|
|
50
|
+
: r?.error
|
|
51
|
+
? html` — <span class="text-red-600">${r.error}</span>`
|
|
52
|
+
: nothing}
|
|
53
|
+
${r?.tokenUsed
|
|
54
|
+
? html`<span class="block text-xs text-neutral-500 mt-1"
|
|
55
|
+
>token: ${r.tokenUsed}</span
|
|
56
|
+
>`
|
|
57
|
+
: nothing}
|
|
58
|
+
</p>
|
|
59
|
+
`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Static Bearer token on APIConfiguration (`token` attribute / publisher). */
|
|
63
|
+
@customElement("docs-api-config-bearer-demo")
|
|
64
|
+
export class DocsApiConfigBearerDemo extends LitElement {
|
|
65
|
+
static styles = [tailwind];
|
|
66
|
+
|
|
67
|
+
@get(protectedEndpoint, docsApiConfBearerKey)
|
|
68
|
+
@state()
|
|
69
|
+
private payload: ApiGetResult<ProtectedResult> | null = null;
|
|
70
|
+
|
|
71
|
+
render() {
|
|
72
|
+
return html`
|
|
73
|
+
<p class="mb-2 text-sm text-neutral-600">
|
|
74
|
+
Config <code>${docsApiConfBearerKey.path}</code> —
|
|
75
|
+
<code>token="${DOCS_MOCK_TOKEN_VALID}"</code>
|
|
76
|
+
</p>
|
|
77
|
+
${resultPanel(this.payload)}
|
|
78
|
+
`;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Basic auth + <code>tokenProvider</code> → GET <code>/auth/token</code> then Bearer. */
|
|
83
|
+
@customElement("docs-api-config-token-provider-demo")
|
|
84
|
+
export class DocsApiConfigTokenProviderDemo extends LitElement {
|
|
85
|
+
static styles = [tailwind];
|
|
86
|
+
|
|
87
|
+
@get(protectedEndpoint, docsApiConfTokenProviderKey)
|
|
88
|
+
@state()
|
|
89
|
+
private payload: ApiGetResult<ProtectedResult> | null = null;
|
|
90
|
+
|
|
91
|
+
render() {
|
|
92
|
+
return html`
|
|
93
|
+
<p class="mb-2 text-sm text-neutral-600">
|
|
94
|
+
<code>userName</code> / <code>password</code> +
|
|
95
|
+
<code>tokenProvider="auth/token"</code> (no static
|
|
96
|
+
<code>token</code>)
|
|
97
|
+
</p>
|
|
98
|
+
${resultPanel(this.payload)}
|
|
99
|
+
`;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Stale Bearer → HTTP 498 → refresh via <code>tokenProvider</code> → retry. */
|
|
104
|
+
@customElement("docs-api-config-stale-token-demo")
|
|
105
|
+
export class DocsApiConfigStaleTokenDemo extends LitElement {
|
|
106
|
+
static styles = [tailwind];
|
|
107
|
+
|
|
108
|
+
@get(protectedEndpoint, docsApiConfStaleTokenKey)
|
|
109
|
+
@state()
|
|
110
|
+
private payload: ApiGetResult<ProtectedResult> | null = null;
|
|
111
|
+
|
|
112
|
+
render() {
|
|
113
|
+
const refreshed =
|
|
114
|
+
this.payload?.result?.tokenUsed === DOCS_MOCK_TOKEN_FRESH;
|
|
115
|
+
return html`
|
|
116
|
+
<p class="mb-2 text-sm text-neutral-600">
|
|
117
|
+
Starts with <code>token="${DOCS_MOCK_TOKEN_STALE}"</code> (mock returns
|
|
118
|
+
498), then <code>auth()</code> fetches
|
|
119
|
+
<code>${DOCS_MOCK_TOKEN_FRESH}</code>.
|
|
120
|
+
</p>
|
|
121
|
+
${resultPanel(this.payload)}
|
|
122
|
+
${refreshed
|
|
123
|
+
? html`<p class="mt-1 text-xs text-green-700">
|
|
124
|
+
Retry succeeded with refreshed token.
|
|
125
|
+
</p>`
|
|
126
|
+
: nothing}
|
|
127
|
+
`;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Ancestor attributes: <code>wordingProvider</code> + directive <code>wording()</code>. */
|
|
132
|
+
@customElement("docs-api-config-wording-demo")
|
|
133
|
+
export class DocsApiConfigWordingDemo extends LitElement {
|
|
134
|
+
static styles = [tailwind];
|
|
135
|
+
|
|
136
|
+
render() {
|
|
137
|
+
return html`
|
|
138
|
+
<div
|
|
139
|
+
serviceURL=${DOCS_MOCK_API_BASE}
|
|
140
|
+
wordingProvider="wording/labels?lang=fr"
|
|
141
|
+
wordingVersionProvider=${docsApiConfWordingVersionKey.path}
|
|
142
|
+
>
|
|
143
|
+
<p class="text-sm space-y-2">
|
|
144
|
+
<span class="block">${wording("api-config.greeting")}</span>
|
|
145
|
+
<span class="block">${wording("api-config.farewell")}</span>
|
|
146
|
+
<span class="block text-neutral-500"
|
|
147
|
+
>${wording("api-config.hint")}</span
|
|
148
|
+
>
|
|
149
|
+
</p>
|
|
150
|
+
<sonic-button
|
|
151
|
+
size="sm"
|
|
152
|
+
class="mt-3"
|
|
153
|
+
@click=${() => set(docsApiConfWordingVersionKey, Date.now())}
|
|
154
|
+
>Bump wording version (reload)</sonic-button
|
|
155
|
+
>
|
|
156
|
+
</div>
|
|
157
|
+
`;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Scoped attributes on <code>sonic-scope</code> (read by <code>HTML.getApiConfiguration</code>). */
|
|
162
|
+
@customElement("docs-api-config-scoped-attrs-demo")
|
|
163
|
+
export class DocsApiConfigScopedAttrsDemo extends LitElement {
|
|
164
|
+
static styles = [tailwind];
|
|
165
|
+
|
|
166
|
+
render() {
|
|
167
|
+
return html`
|
|
168
|
+
<sonic-scope
|
|
169
|
+
serviceURL=${DOCS_MOCK_API_BASE}
|
|
170
|
+
token=${DOCS_MOCK_TOKEN_VALID}
|
|
171
|
+
credentials="same-origin"
|
|
172
|
+
addHTTPResponse
|
|
173
|
+
class="text-sm space-y-2 block"
|
|
174
|
+
>
|
|
175
|
+
<p>
|
|
176
|
+
Descendant components inherit
|
|
177
|
+
<code>serviceURL</code>, <code>token</code>,
|
|
178
|
+
<code>credentials</code>, <code>addHTTPResponse</code> from this
|
|
179
|
+
scope (see table above).
|
|
180
|
+
</p>
|
|
181
|
+
<sonic-fetch dataProvider=${protectedEndpoint.path}></sonic-fetch>
|
|
182
|
+
<sonic-button dataProvider=${protectedEndpoint.path} debug
|
|
183
|
+
>Hover — protected fetch payload</sonic-button
|
|
184
|
+
>
|
|
185
|
+
</sonic-scope>
|
|
186
|
+
`;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** <code>eventsApiToken</code> → Bearer on <code>/auth/token</code> (no Basic). */
|
|
191
|
+
@customElement("docs-api-config-events-token-demo")
|
|
192
|
+
export class DocsApiConfigEventsTokenDemo extends LitElement {
|
|
193
|
+
static styles = [tailwind];
|
|
194
|
+
|
|
195
|
+
@state()
|
|
196
|
+
private token: string | null = null;
|
|
197
|
+
|
|
198
|
+
@state()
|
|
199
|
+
private error: string | null = null;
|
|
200
|
+
|
|
201
|
+
async connectedCallback() {
|
|
202
|
+
super.connectedCallback();
|
|
203
|
+
try {
|
|
204
|
+
const res = await fetch(
|
|
205
|
+
`${DOCS_MOCK_API_BASE}/auth/token?serviceHost=${encodeURIComponent(window.location.origin)}`,
|
|
206
|
+
{
|
|
207
|
+
headers: {
|
|
208
|
+
Authorization: `Bearer ${DOCS_MOCK_EVENTS_API_TOKEN}`,
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
);
|
|
212
|
+
const data = (await res.json()) as { token?: string; error?: string };
|
|
213
|
+
if (res.ok && data.token) this.token = data.token;
|
|
214
|
+
else this.error = data.error ?? `HTTP ${res.status}`;
|
|
215
|
+
} catch (e) {
|
|
216
|
+
this.error = String(e);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
render() {
|
|
221
|
+
return html`
|
|
222
|
+
<p class="text-sm text-neutral-600 mb-2">
|
|
223
|
+
Ancêtre <code>eventsApiToken</code> (mapped to
|
|
224
|
+
<code>authToken</code> in config) — utilisé par
|
|
225
|
+
<code>API.auth()</code> pour appeler <code>tokenProvider</code>.
|
|
226
|
+
</p>
|
|
227
|
+
${this.token
|
|
228
|
+
? html`<p class="font-mono text-sm">token: ${this.token}</p>`
|
|
229
|
+
: this.error
|
|
230
|
+
? html`<p class="text-red-600 text-sm">${this.error}</p>`
|
|
231
|
+
: html`<p class="text-sm text-neutral-500">Loading…</p>`}
|
|
232
|
+
`;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { html, LitElement, nothing } from "lit";
|
|
2
|
+
import { customElement, property, state } from "lit/decorators.js";
|
|
3
|
+
import {
|
|
4
|
+
ancestorAttribute,
|
|
5
|
+
subscribe,
|
|
6
|
+
} from "@supersoniks/concorde/core/decorators/Subscriber";
|
|
7
|
+
import { DataProviderKey } from "@supersoniks/concorde/core/utils/dataProviderKey";
|
|
8
|
+
import { DOCS_MOCK_JOKES_SERVICE } from "../mock-api/urls";
|
|
9
|
+
import {
|
|
10
|
+
docsJokeCheckboxFilterKey,
|
|
11
|
+
docsJokeInputFilterKey,
|
|
12
|
+
docsJokeRadioFilterKey,
|
|
13
|
+
docsJokeSelectFilterKey,
|
|
14
|
+
docsJokeSwitchFilterKey,
|
|
15
|
+
} from "./docs-provider-keys";
|
|
16
|
+
import { tailwind } from "../tailwind";
|
|
17
|
+
|
|
18
|
+
import "../../core/components/functional/queue/queue";
|
|
19
|
+
import "../../core/components/ui/form/input/input";
|
|
20
|
+
import "../../core/components/ui/form/select/select";
|
|
21
|
+
import "../../core/components/ui/form/checkbox/checkbox";
|
|
22
|
+
import "../../core/components/ui/form/radio/radio";
|
|
23
|
+
import "../../core/components/ui/form/switch/switch";
|
|
24
|
+
|
|
25
|
+
type JokeRow = {
|
|
26
|
+
joke: string;
|
|
27
|
+
setup?: string;
|
|
28
|
+
delivery?: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const jokeRowKey = new DataProviderKey<
|
|
32
|
+
JokeRow,
|
|
33
|
+
{ dataProvider: string | null }
|
|
34
|
+
>("${dataProvider}");
|
|
35
|
+
|
|
36
|
+
const filterFieldKey = new DataProviderKey<
|
|
37
|
+
string,
|
|
38
|
+
{ filterProvider: string; field: string }
|
|
39
|
+
>("${filterProvider}.${field}");
|
|
40
|
+
|
|
41
|
+
@customElement("docs-joke-item")
|
|
42
|
+
export class DocsJokeItem extends LitElement {
|
|
43
|
+
static styles = [tailwind];
|
|
44
|
+
|
|
45
|
+
@ancestorAttribute("dataProvider")
|
|
46
|
+
dataProvider: string | null = null;
|
|
47
|
+
|
|
48
|
+
@subscribe(jokeRowKey)
|
|
49
|
+
@state()
|
|
50
|
+
row: JokeRow | null = null;
|
|
51
|
+
|
|
52
|
+
render() {
|
|
53
|
+
const r = this.row;
|
|
54
|
+
if (!r) return nothing;
|
|
55
|
+
return html`
|
|
56
|
+
<div
|
|
57
|
+
class="space-y-1 border-0 border-b border-dotted border-neutral-300 py-3"
|
|
58
|
+
>
|
|
59
|
+
<div>${r.joke}</div>
|
|
60
|
+
${r.setup
|
|
61
|
+
? html`<div class="text-sm text-neutral-500">${r.setup}</div>`
|
|
62
|
+
: nothing}
|
|
63
|
+
${r.delivery
|
|
64
|
+
? html`<div class="text-sm text-neutral-500">${r.delivery}</div>`
|
|
65
|
+
: nothing}
|
|
66
|
+
</div>
|
|
67
|
+
`;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@customElement("docs-joke-filter-caption")
|
|
72
|
+
export class DocsJokeFilterCaption extends LitElement {
|
|
73
|
+
@property() filterProvider = "";
|
|
74
|
+
@property() field = "";
|
|
75
|
+
@property() label = "";
|
|
76
|
+
|
|
77
|
+
@subscribe(filterFieldKey)
|
|
78
|
+
@state()
|
|
79
|
+
value = "";
|
|
80
|
+
|
|
81
|
+
render() {
|
|
82
|
+
return html`
|
|
83
|
+
<p class="my-4 block text-xl font-bold">
|
|
84
|
+
${this.label} « <span class="text-info">${this.value || "…"}</span> » :
|
|
85
|
+
</p>
|
|
86
|
+
`;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@customElement("docs-joke-queue")
|
|
91
|
+
export class DocsJokeQueue extends LitElement {
|
|
92
|
+
@property() filterProvider = "";
|
|
93
|
+
@property() expression = "joke/Any?amount=10&lang=fr";
|
|
94
|
+
|
|
95
|
+
private jokeItem = () => html`<docs-joke-item></docs-joke-item>`;
|
|
96
|
+
|
|
97
|
+
render() {
|
|
98
|
+
return html`
|
|
99
|
+
<sonic-queue
|
|
100
|
+
lazyload
|
|
101
|
+
dataProviderExpression=${this.expression}
|
|
102
|
+
dataFilterProvider=${this.filterProvider}
|
|
103
|
+
serviceURL=${DOCS_MOCK_JOKES_SERVICE}
|
|
104
|
+
key="jokes"
|
|
105
|
+
.items=${this.jokeItem}
|
|
106
|
+
></sonic-queue>
|
|
107
|
+
`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@customElement("docs-joke-search-demo")
|
|
112
|
+
export class DocsJokeSearchDemo extends LitElement {
|
|
113
|
+
static styles = [tailwind];
|
|
114
|
+
|
|
115
|
+
render() {
|
|
116
|
+
return html`
|
|
117
|
+
<sonic-input
|
|
118
|
+
formDataProvider=${docsJokeInputFilterKey.path}
|
|
119
|
+
name="contains"
|
|
120
|
+
value="chien"
|
|
121
|
+
class="mb-4"
|
|
122
|
+
></sonic-input>
|
|
123
|
+
<docs-joke-filter-caption
|
|
124
|
+
filterProvider=${docsJokeInputFilterKey.path}
|
|
125
|
+
field="contains"
|
|
126
|
+
label="Blagues trouvées pour"
|
|
127
|
+
></docs-joke-filter-caption>
|
|
128
|
+
<docs-joke-queue
|
|
129
|
+
filterProvider=${docsJokeInputFilterKey.path}
|
|
130
|
+
expression="joke/Any?amount=10&lang=fr"
|
|
131
|
+
></docs-joke-queue>
|
|
132
|
+
`;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
@customElement("docs-joke-lang-demo")
|
|
137
|
+
export class DocsJokeLangDemo extends LitElement {
|
|
138
|
+
static styles = [tailwind];
|
|
139
|
+
|
|
140
|
+
render() {
|
|
141
|
+
return html`
|
|
142
|
+
<sonic-select
|
|
143
|
+
formDataProvider=${docsJokeSelectFilterKey.path}
|
|
144
|
+
name="lang"
|
|
145
|
+
value="fr"
|
|
146
|
+
>
|
|
147
|
+
<option value="fr">fr</option>
|
|
148
|
+
<option value="en">en</option>
|
|
149
|
+
</sonic-select>
|
|
150
|
+
<docs-joke-filter-caption
|
|
151
|
+
filterProvider=${docsJokeSelectFilterKey.path}
|
|
152
|
+
field="lang"
|
|
153
|
+
label="Blagues pour la langue"
|
|
154
|
+
></docs-joke-filter-caption>
|
|
155
|
+
<docs-joke-queue
|
|
156
|
+
filterProvider=${docsJokeSelectFilterKey.path}
|
|
157
|
+
expression="joke/Any?amount=10"
|
|
158
|
+
></docs-joke-queue>
|
|
159
|
+
`;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const jokeQueueRow = (row: JokeRow) => html`
|
|
164
|
+
<div class="border-0 border-b border-neutral-300 py-3 leading-tight">
|
|
165
|
+
<div>${row.joke}</div>
|
|
166
|
+
${row.setup ? html`<div class="font-bold">${row.setup}</div>` : nothing}
|
|
167
|
+
${row.delivery ? html`<div>${row.delivery}</div>` : nothing}
|
|
168
|
+
</div>
|
|
169
|
+
`;
|
|
170
|
+
|
|
171
|
+
const BLACKLIST_CONTROLS = html`
|
|
172
|
+
<sonic-checkbox name="blacklistFlags" value="nsfw">nsfw</sonic-checkbox>
|
|
173
|
+
<sonic-checkbox name="blacklistFlags" value="religious">religious</sonic-checkbox>
|
|
174
|
+
<sonic-checkbox name="blacklistFlags" value="political">political</sonic-checkbox>
|
|
175
|
+
<sonic-checkbox name="blacklistFlags" value="racist" checked>racist</sonic-checkbox>
|
|
176
|
+
<sonic-checkbox name="blacklistFlags" value="sexist" checked>sexist</sonic-checkbox>
|
|
177
|
+
<sonic-checkbox name="blacklistFlags" value="explicit">explicit</sonic-checkbox>
|
|
178
|
+
`;
|
|
179
|
+
|
|
180
|
+
/** Checkbox — « Remove following jokes » (blacklistFlags → mock API). */
|
|
181
|
+
@customElement("docs-joke-blacklist-demo")
|
|
182
|
+
export class DocsJokeBlacklistDemo extends LitElement {
|
|
183
|
+
static styles = [tailwind];
|
|
184
|
+
|
|
185
|
+
private items = jokeQueueRow;
|
|
186
|
+
|
|
187
|
+
render() {
|
|
188
|
+
return html`
|
|
189
|
+
<p class="my-4 block text-xl font-bold">Remove following jokes :</p>
|
|
190
|
+
<div
|
|
191
|
+
formDataProvider=${docsJokeCheckboxFilterKey.path}
|
|
192
|
+
class="mb-3 grid grid-cols-2 gap-x-6 gap-y-2 lg:grid-cols-3"
|
|
193
|
+
>
|
|
194
|
+
${BLACKLIST_CONTROLS}
|
|
195
|
+
</div>
|
|
196
|
+
<sonic-queue
|
|
197
|
+
lazyload
|
|
198
|
+
dataProviderExpression="joke/Any?offset=$offset&limit=$limit&lang=en"
|
|
199
|
+
dataFilterProvider=${docsJokeCheckboxFilterKey.path}
|
|
200
|
+
serviceURL=${DOCS_MOCK_JOKES_SERVICE}
|
|
201
|
+
key="jokes"
|
|
202
|
+
limit="5"
|
|
203
|
+
class="grid max-h-96 overflow-y-auto"
|
|
204
|
+
.items=${this.items}
|
|
205
|
+
debug
|
|
206
|
+
></sonic-queue>
|
|
207
|
+
`;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** Radio group — same API, single `blacklistFlags` value. */
|
|
212
|
+
@customElement("docs-joke-blacklist-radio-demo")
|
|
213
|
+
export class DocsJokeBlacklistRadioDemo extends LitElement {
|
|
214
|
+
static styles = [tailwind];
|
|
215
|
+
|
|
216
|
+
private items = jokeQueueRow;
|
|
217
|
+
|
|
218
|
+
render() {
|
|
219
|
+
return html`
|
|
220
|
+
<p class="my-4 block text-xl font-bold">Remove following jokes :</p>
|
|
221
|
+
<div
|
|
222
|
+
formDataProvider=${docsJokeRadioFilterKey.path}
|
|
223
|
+
class="mb-3 grid grid-cols-2 gap-x-6 gap-y-2 lg:grid-cols-3"
|
|
224
|
+
>
|
|
225
|
+
<sonic-radio name="blacklistFlags" value="nsfw">nsfw</sonic-radio>
|
|
226
|
+
<sonic-radio name="blacklistFlags" value="religious"
|
|
227
|
+
>religious</sonic-radio
|
|
228
|
+
>
|
|
229
|
+
<sonic-radio name="blacklistFlags" value="political"
|
|
230
|
+
>political</sonic-radio
|
|
231
|
+
>
|
|
232
|
+
<sonic-radio name="blacklistFlags" value="racist" checked
|
|
233
|
+
>racist</sonic-radio
|
|
234
|
+
>
|
|
235
|
+
<sonic-radio name="blacklistFlags" value="sexist">sexist</sonic-radio>
|
|
236
|
+
<sonic-radio name="blacklistFlags" value="explicit"
|
|
237
|
+
>explicit</sonic-radio
|
|
238
|
+
>
|
|
239
|
+
</div>
|
|
240
|
+
<sonic-queue
|
|
241
|
+
lazyload
|
|
242
|
+
dataProviderExpression="joke/Any?offset=$offset&limit=$limit&lang=en"
|
|
243
|
+
dataFilterProvider="jokeFilterRadio"
|
|
244
|
+
serviceURL=${DOCS_MOCK_JOKES_SERVICE}
|
|
245
|
+
key="jokes"
|
|
246
|
+
limit="5"
|
|
247
|
+
class="grid max-h-96 overflow-y-auto"
|
|
248
|
+
.items=${this.items}
|
|
249
|
+
debug
|
|
250
|
+
></sonic-queue>
|
|
251
|
+
`;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/** Switch — same blacklist filter. */
|
|
256
|
+
@customElement("docs-joke-blacklist-switch-demo")
|
|
257
|
+
export class DocsJokeBlacklistSwitchDemo extends LitElement {
|
|
258
|
+
static styles = [tailwind];
|
|
259
|
+
|
|
260
|
+
private items = jokeQueueRow;
|
|
261
|
+
|
|
262
|
+
render() {
|
|
263
|
+
return html`
|
|
264
|
+
<p class="my-4 block text-xl font-bold">Remove following jokes :</p>
|
|
265
|
+
<div
|
|
266
|
+
formDataProvider=${docsJokeSwitchFilterKey.path}
|
|
267
|
+
class="mb-3 grid grid-cols-2 gap-x-6 gap-y-2 lg:grid-cols-3"
|
|
268
|
+
>
|
|
269
|
+
<sonic-switch name="blacklistFlags" value="nsfw">nsfw</sonic-switch>
|
|
270
|
+
<sonic-switch name="blacklistFlags" value="religious"
|
|
271
|
+
>religious</sonic-switch
|
|
272
|
+
>
|
|
273
|
+
<sonic-switch name="blacklistFlags" value="political"
|
|
274
|
+
>political</sonic-switch
|
|
275
|
+
>
|
|
276
|
+
<sonic-switch name="blacklistFlags" value="racist" checked
|
|
277
|
+
>racist</sonic-switch
|
|
278
|
+
>
|
|
279
|
+
<sonic-switch name="blacklistFlags" value="sexist">sexist</sonic-switch>
|
|
280
|
+
<sonic-switch name="blacklistFlags" value="explicit"
|
|
281
|
+
>explicit</sonic-switch
|
|
282
|
+
>
|
|
283
|
+
</div>
|
|
284
|
+
<sonic-queue
|
|
285
|
+
lazyload
|
|
286
|
+
dataProviderExpression="joke/Any?offset=$offset&limit=$limit&lang=en"
|
|
287
|
+
dataFilterProvider=${docsJokeSwitchFilterKey.path}
|
|
288
|
+
serviceURL=${DOCS_MOCK_JOKES_SERVICE}
|
|
289
|
+
key="jokes"
|
|
290
|
+
limit="5"
|
|
291
|
+
class="grid max-h-96 overflow-y-auto"
|
|
292
|
+
.items=${this.items}
|
|
293
|
+
debug
|
|
294
|
+
></sonic-queue>
|
|
295
|
+
`;
|
|
296
|
+
}
|
|
297
|
+
}
|