@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
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# AI agents (skills & AGENTS.md)
|
|
2
|
+
|
|
3
|
+
Concorde ships **skills**, **rules**, and a root **`AGENTS.md`** so Cursor, JetBrains AI Assistant, and other coding agents follow framework patterns (DataProvider, decorators, short imports, scope, theme, migrations).
|
|
4
|
+
|
|
5
|
+
On a [starter](#docs/_getting-started/concorde-outside.md/concorde-outside) project, run `yarn ai:sync` after install. On a [manual / brownfield](#docs/_getting-started/concorde-manual-install.md/concorde-manual-install) project, install Concorde first, then use `ai-init` below.
|
|
6
|
+
|
|
7
|
+
## Dedicated commands
|
|
8
|
+
|
|
9
|
+
| Context | Command |
|
|
10
|
+
|---------|---------|
|
|
11
|
+
| [create-concorde-ts-starter](https://www.npmjs.com/package/@supersoniks/create-concorde-ts-starter) project | `yarn ai:sync` |
|
|
12
|
+
| Any consumer app (after `yarn add @supersoniks/concorde`) | `node node_modules/@supersoniks/concorde/scripts/ai-init.mjs` |
|
|
13
|
+
| Concorde repo (contributors) | `yarn ai-init` |
|
|
14
|
+
|
|
15
|
+
<sonic-code language="shell">
|
|
16
|
+
<template>
|
|
17
|
+
# Starter (from project root)
|
|
18
|
+
yarn ai:sync
|
|
19
|
+
|
|
20
|
+
# Manual / existing project
|
|
21
|
+
node node_modules/@supersoniks/concorde/scripts/ai-init.mjs
|
|
22
|
+
</template>
|
|
23
|
+
</sonic-code>
|
|
24
|
+
|
|
25
|
+
## Useful flags
|
|
26
|
+
|
|
27
|
+
| Flag | Effect |
|
|
28
|
+
|------|--------|
|
|
29
|
+
| `--merge-agents` | Append to an existing `AGENTS.md` instead of replacing it |
|
|
30
|
+
| `--overlay <dir>` | Copy extra rules/skills from another layer (e.g. starter kit) |
|
|
31
|
+
| `--cursor-only` | Install only `.cursor/skills` and `.cursor/rules` |
|
|
32
|
+
| `--jetbrains-only` | Install only `.aiassistant/rules/` |
|
|
33
|
+
|
|
34
|
+
## What gets installed
|
|
35
|
+
|
|
36
|
+
| Path | Role |
|
|
37
|
+
|------|------|
|
|
38
|
+
| `AGENTS.md` | Project-level guide for agents (Concorde conventions) |
|
|
39
|
+
| `.cursor/skills/concorde/` | Core Lit + DataProvider patterns |
|
|
40
|
+
| `.cursor/skills/concorde-imports/` | Short `@supersoniks/concorde/…` import paths |
|
|
41
|
+
| `.cursor/skills/concorde-scope/` | `serviceURL`, `formDataProvider`, API configuration |
|
|
42
|
+
| `.cursor/skills/concorde-theme/` | `sonic-theme` and `--sc-*` tokens |
|
|
43
|
+
| `.cursor/skills/concorde-menu/` | `sonic-menu` navigation |
|
|
44
|
+
| `.cursor/skills/concorde-get-set-dp/` | `get` / `set` / `dp` and `DataProviderKey` migration |
|
|
45
|
+
| `.cursor/rules/concorde.mdc` | Cursor rules (always-on patterns) |
|
|
46
|
+
| `.aiassistant/rules/concorde.md` | JetBrains AI Assistant rules |
|
|
47
|
+
|
|
48
|
+
## Workflow
|
|
49
|
+
|
|
50
|
+
1. **Starter project:** [Installation](#docs/_getting-started/concorde-outside.md/concorde-outside) — `yarn ai:sync` is wired in the kit.
|
|
51
|
+
2. **Existing / manual Vite project:** [Manual installation](#docs/_getting-started/concorde-manual-install.md/concorde-manual-install), then **`ai-init`** after `yarn add @supersoniks/concorde`.
|
|
52
|
+
3. Commit `AGENTS.md`, `.cursor/`, and `.aiassistant/` if your team shares agent settings.
|
|
53
|
+
4. Re-run the same command when you bump `@supersoniks/concorde` to refresh skills from `node_modules/@supersoniks/concorde/ai/`.
|
|
54
|
+
5. In Cursor, skills under `.cursor/skills/` are picked up automatically; mention a skill in chat for focused tasks (e.g. migration → `concorde-get-set-dp`).
|
|
55
|
+
|
|
56
|
+
Source files in the npm package: `node_modules/@supersoniks/concorde/ai/` (see also `ai/README.md` in the [Concorde repository](https://github.com/supersoniks/concorde)).
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Manual installation (Vite)
|
|
2
|
+
|
|
3
|
+
> **Legacy** — for brownfield apps or custom stacks. New projects should use the [starter](#docs/_getting-started/concorde-outside.md/concorde-outside).
|
|
4
|
+
|
|
5
|
+
## Brand New Vite Project
|
|
6
|
+
|
|
7
|
+
Tailwind configuration is not covered here yet.
|
|
8
|
+
|
|
9
|
+
### Creating the Project
|
|
10
|
+
|
|
11
|
+
<sonic-code language="shell">
|
|
12
|
+
<template>
|
|
13
|
+
# Pure JavaScript project
|
|
14
|
+
yarn create vite --template vanilla-js
|
|
15
|
+
# TypeScript project
|
|
16
|
+
# (it is recommended to use this approach, which installs Lit separately if needed, via "yarn add lit")
|
|
17
|
+
yarn create vite --template vanilla-ts
|
|
18
|
+
# TypeScript + Lit project
|
|
19
|
+
# (creating new web components, for example, to extend the fetch or subscriber mixins)
|
|
20
|
+
yarn create vite --template lit-ts
|
|
21
|
+
</template>
|
|
22
|
+
</sonic-code>
|
|
23
|
+
|
|
24
|
+
Using Lit with TypeScript requires the following configuration in the "compilerOptions" section of the `tsconfig.json` file:
|
|
25
|
+
|
|
26
|
+
<sonic-code language="json">
|
|
27
|
+
<template>
|
|
28
|
+
"experimentalDecorators": true,
|
|
29
|
+
"useDefineForClassFields": false
|
|
30
|
+
</template>
|
|
31
|
+
</sonic-code>
|
|
32
|
+
|
|
33
|
+
### Installing Concorde
|
|
34
|
+
|
|
35
|
+
Navigate to the project folder created and perform the installation:
|
|
36
|
+
|
|
37
|
+
<sonic-code language="shell">
|
|
38
|
+
<template>
|
|
39
|
+
yarn add @supersoniks/concorde
|
|
40
|
+
</template>
|
|
41
|
+
</sonic-code>
|
|
42
|
+
|
|
43
|
+
Agent skills (`AGENTS.md`, Cursor / JetBrains): see [AI agents](#docs/_getting-started/ai-agents.md/ai-agents) — run `node node_modules/@supersoniks/concorde/scripts/ai-init.mjs` after install.
|
|
44
|
+
|
|
45
|
+
### Development / Build
|
|
46
|
+
|
|
47
|
+
<sonic-code language="shell">
|
|
48
|
+
<template>
|
|
49
|
+
# Development (you can add `--host` after the command chain in package.json's dev script instead of typing it each time as shown below)
|
|
50
|
+
yarn dev --host
|
|
51
|
+
# Build
|
|
52
|
+
yarn build
|
|
53
|
+
</template>
|
|
54
|
+
</sonic-code>
|
|
55
|
+
|
|
56
|
+
## Shortcut Imports
|
|
57
|
+
|
|
58
|
+
Shortcut imports work by default in JavaScript, but in TypeScript, they are activated by choice as they inject data into *tsconfig.json*. Here is the command:
|
|
59
|
+
|
|
60
|
+
<sonic-code language="shell">
|
|
61
|
+
<template>
|
|
62
|
+
npx concorde enable-short-paths
|
|
63
|
+
</template>
|
|
64
|
+
</sonic-code>
|
|
65
|
+
|
|
66
|
+
Shortcut imports replace the actual paths with aliases as follows:
|
|
67
|
+
|
|
68
|
+
* `@supersoniks/concorde/core/components/functional_or_ui/component/component` becomes `@supersoniks/concorde/functional_or_ui/component`
|
|
69
|
+
* `@supersoniks/concorde/core/mixins_or_utils/class_name` becomes `@supersoniks/concorde/mixins_or_utils/class_name`
|
|
70
|
+
|
|
71
|
+
The original paths remain accessible. Shortcut imports are used for the examples later in this documentation.
|
|
72
|
+
|
|
73
|
+
## Usage
|
|
74
|
+
|
|
75
|
+
### Simple Integration in HTML
|
|
76
|
+
|
|
77
|
+
Import needed component in `main.ts` or wherever you want to use it:
|
|
78
|
+
|
|
79
|
+
<sonic-code language="typescript">
|
|
80
|
+
<template>
|
|
81
|
+
import "@supersoniks/concorde/ui/button";
|
|
82
|
+
</template>
|
|
83
|
+
</sonic-code>
|
|
84
|
+
|
|
85
|
+
Then in the render function ofyour component or in the HTML of the web page that includes the compiled JS, use the component as follows:
|
|
86
|
+
|
|
87
|
+
<sonic-code>
|
|
88
|
+
<template>
|
|
89
|
+
<sonic-button variant="outline">My button</sonic-button>
|
|
90
|
+
</template>
|
|
91
|
+
</sonic-code>
|
|
92
|
+
|
|
93
|
+
### Using a Mixin to Create a New Lit Component
|
|
94
|
+
|
|
95
|
+
For example, create a file `my-element.ts` at the root:
|
|
96
|
+
|
|
97
|
+
<sonic-code language="typescript">
|
|
98
|
+
<template>
|
|
99
|
+
import { html, LitElement } from "lit";
|
|
100
|
+
import { customElement, property } from "lit/decorators.js";
|
|
101
|
+
import Fetcher from "@supersoniks/concorde/mixins/Fetcher";
|
|
102
|
+
import Subscriber from "@supersoniks/concorde/mixins/Subscriber";
|
|
103
|
+
|
|
104
|
+
@customElement("my-element")
|
|
105
|
+
export class SonicComponent extends Fetcher(Subscriber(LitElement)) {
|
|
106
|
+
@property() email = "";
|
|
107
|
+
@property() first_name = "";
|
|
108
|
+
@property() last_name = "";
|
|
109
|
+
|
|
110
|
+
render() {
|
|
111
|
+
return html`<div>
|
|
112
|
+
${this.first_name} ${this.last_name} : ${this.email}
|
|
113
|
+
</div>`;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
</template>
|
|
117
|
+
</sonic-code>
|
|
118
|
+
|
|
119
|
+
Import component `main.ts` or `main.js` or any other component that uses it to be compiled
|
|
120
|
+
|
|
121
|
+
<sonic-code language="typescript">
|
|
122
|
+
<template>
|
|
123
|
+
import "./my-element";
|
|
124
|
+
</template>
|
|
125
|
+
</sonic-code>
|
|
126
|
+
|
|
127
|
+
In the HTML of a JS or TS component or in the HTML of the web page containing the compiled JS:
|
|
128
|
+
|
|
129
|
+
<sonic-code language="html">
|
|
130
|
+
<template>
|
|
131
|
+
<my-element serviceURL="/docs-mock-api" dataProvider="api/users/2" key="data"></my-element>
|
|
132
|
+
</template>
|
|
133
|
+
</sonic-code>
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
# Installation
|
|
2
2
|
|
|
3
|
+
<sonic-alert status="success" label="Recommended — use the starter" size="xl" background>
|
|
4
|
+
<p><strong>For almost all new projects, use <a href="https://www.npmjs.com/package/@supersoniks/create-concorde-ts-starter">create-concorde-ts-starter</a>.</strong></p>
|
|
5
|
+
<p>You get Vite + TypeScript + Lit + Tailwind, an example component, <code>npx concorde enable-short-paths</code> ready to run, and <code>yarn ai:sync</code> for <a href="#docs/_getting-started/ai-agents.md/ai-agents">AI agent skills</a> (<code>AGENTS.md</code>, Cursor / JetBrains rules) without extra setup.</p>
|
|
6
|
+
</sonic-alert>
|
|
7
|
+
|
|
3
8
|
## Starter
|
|
4
9
|
|
|
5
|
-
The easiest way to use Concorde is by using the Concorde starter.
|
|
6
10
|
The following command creates a new Vite project in TypeScript mode with Tailwind and an example component to get started.
|
|
7
11
|
|
|
8
12
|
<sonic-code language="shell">
|
|
@@ -11,133 +15,19 @@ npx @supersoniks/create-concorde-ts-starter "project_name"
|
|
|
11
15
|
</template>
|
|
12
16
|
</sonic-code>
|
|
13
17
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
For a more manual configuration, you can refer to the following sections. <br/>
|
|
18
|
-
However, the Tailwind configuration is not mentioned at the moment.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
### Creating the Project
|
|
18
|
+
Then, from the project folder:
|
|
22
19
|
|
|
23
20
|
<sonic-code language="shell">
|
|
24
21
|
<template>
|
|
25
|
-
|
|
26
|
-
yarn create vite --template vanilla-js
|
|
27
|
-
# TypeScript project
|
|
28
|
-
# (it is recommended to use this approach, which installs Lit separately if needed, via "yarn add lit")
|
|
29
|
-
yarn create vite --template vanilla-ts
|
|
30
|
-
# TypeScript + Lit project
|
|
31
|
-
# (creating new web components, for example, to extend the fetch or subscriber mixins)
|
|
32
|
-
yarn create vite --template lit-ts
|
|
33
|
-
</template>
|
|
34
|
-
</sonic-code>
|
|
35
|
-
|
|
36
|
-
Using Lit with TypeScript requires the following configuration in the "compilerOptions" section of the `tsconfig.json` file:
|
|
37
|
-
|
|
38
|
-
<sonic-code language="json">
|
|
39
|
-
<template>
|
|
40
|
-
"experimentalDecorators": true,
|
|
41
|
-
"useDefineForClassFields": false
|
|
42
|
-
</template>
|
|
43
|
-
</sonic-code>
|
|
44
|
-
|
|
45
|
-
### Installing Concorde
|
|
46
|
-
|
|
47
|
-
Navigate to the project folder created and perform the installation:
|
|
48
|
-
|
|
49
|
-
<sonic-code language="shell">
|
|
50
|
-
<template>
|
|
51
|
-
yarn add @supersoniks/concorde
|
|
52
|
-
</template>
|
|
53
|
-
</sonic-code>
|
|
54
|
-
|
|
55
|
-
### Development / Build
|
|
56
|
-
|
|
57
|
-
<sonic-code language="shell">
|
|
58
|
-
<template>
|
|
59
|
-
# Development (you can add `--host` after the command chain in package.json's dev script instead of typing it each time as shown below)
|
|
22
|
+
yarn install
|
|
60
23
|
yarn dev --host
|
|
61
|
-
# Build
|
|
62
|
-
yarn build
|
|
63
24
|
</template>
|
|
64
25
|
</sonic-code>
|
|
65
26
|
|
|
66
|
-
##
|
|
67
|
-
|
|
68
|
-
Shortcut imports work by default in JavaScript, but in TypeScript, they are activated by choice as they inject data into *tsconfig.json*. Here is the command:
|
|
69
|
-
|
|
70
|
-
<sonic-code language="shell">
|
|
71
|
-
<template>
|
|
72
|
-
npx concorde enable-short-paths
|
|
73
|
-
</template>
|
|
74
|
-
</sonic-code>
|
|
75
|
-
|
|
76
|
-
Shortcut imports replace the actual paths with aliases as follows:
|
|
77
|
-
|
|
78
|
-
* `@supersoniks/concorde/core/components/functional_or_ui/component/component` becomes `@supersoniks/concorde/functional_or_ui/component`
|
|
79
|
-
* `@supersoniks/concorde/core/mixins_or_utils/class_name` becomes `@supersoniks/concorde/mixins_or_utils/class_name`
|
|
27
|
+
## Next steps
|
|
80
28
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
Import needed component in `main.ts` or wherever you want to use it:
|
|
88
|
-
|
|
89
|
-
<sonic-code language="typescript">
|
|
90
|
-
<template>
|
|
91
|
-
import "@supersoniks/concorde/ui/button";
|
|
92
|
-
</template>
|
|
93
|
-
</sonic-code>
|
|
94
|
-
|
|
95
|
-
Then in the render function ofyour component or in the HTML of the web page that includes the compiled JS, use the component as follows:
|
|
96
|
-
|
|
97
|
-
<sonic-code>
|
|
98
|
-
<template>
|
|
99
|
-
<sonic-button variant="outline">My button</sonic-button>
|
|
100
|
-
</template>
|
|
101
|
-
</sonic-code>
|
|
102
|
-
|
|
103
|
-
### Using a Mixin to Create a New Lit Component
|
|
104
|
-
|
|
105
|
-
For example, create a file `my-element.ts` at the root:
|
|
106
|
-
|
|
107
|
-
<sonic-code language="typescript">
|
|
108
|
-
<template>
|
|
109
|
-
import { html, LitElement } from "lit";
|
|
110
|
-
import { customElement, property } from "lit/decorators.js";
|
|
111
|
-
import Fetcher from "@supersoniks/concorde/mixins/Fetcher";
|
|
112
|
-
import Subscriber from "@supersoniks/concorde/mixins/Subscriber";
|
|
113
|
-
|
|
114
|
-
@customElement("my-element")
|
|
115
|
-
export class SonicComponent extends Fetcher(Subscriber(LitElement)) {
|
|
116
|
-
@property() email = "";
|
|
117
|
-
@property() first_name = "";
|
|
118
|
-
@property() last_name = "";
|
|
119
|
-
|
|
120
|
-
render() {
|
|
121
|
-
return html`<div>
|
|
122
|
-
${this.first_name} ${this.last_name} : ${this.email}
|
|
123
|
-
</div>`;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
</template>
|
|
127
|
-
</sonic-code>
|
|
128
|
-
|
|
129
|
-
Import component `main.ts` or `main.js` or any other component that uses it to be compiled
|
|
130
|
-
|
|
131
|
-
<sonic-code language="typescript">
|
|
132
|
-
<template>
|
|
133
|
-
import "./my-element";
|
|
134
|
-
</template>
|
|
135
|
-
</sonic-code>
|
|
136
|
-
|
|
137
|
-
In the HTML of a JS or TS component or in the HTML of the web page containing the compiled JS:
|
|
138
|
-
|
|
139
|
-
<sonic-code language="html">
|
|
140
|
-
<template>
|
|
141
|
-
<my-element serviceURL="https://reqres.in" dataProvider="api/users/2" key="data"></my-element>
|
|
142
|
-
</template>
|
|
143
|
-
</sonic-code>
|
|
29
|
+
| Step | Page |
|
|
30
|
+
|------|------|
|
|
31
|
+
| Learn patterns | [My first component](#docs/_getting-started/my-first-component.md/my-first-component) |
|
|
32
|
+
| Agent skills | [AI agents (skills)](#docs/_getting-started/ai-agents.md/ai-agents) — `yarn ai:sync` on the starter |
|
|
33
|
+
| Brownfield / manual Vite | [Legacy: Manual installation](#docs/_getting-started/concorde-manual-install.md/concorde-manual-install) |
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Creating components
|
|
2
2
|
|
|
3
|
+
> **New app components:** start with [My first component](#docs/_getting-started/my-first-component.md/my-first-component) and [Data flow](#docs/_core-concept/dataFlow.md/dataFlow). The `Subscriber` mixin below is [legacy](#docs/_core-concept/subscriber.md/subscriber).
|
|
4
|
+
|
|
3
5
|
## Where to put it?
|
|
4
6
|
|
|
5
7
|
In this document, we consider the src directory of the project as the root.<br>
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# My first component
|
|
2
|
+
|
|
3
|
+
Build a **Lit** user card with Tailwind and Concorde UI, then connect it to the **DataProvider** store: declare the **data configuration** (type, key, scope), and let **`@subscribe`** keep the card in sync.
|
|
4
|
+
|
|
5
|
+
> Legacy approach with the **Subscriber mixin**: [Legacy: My first subscriber](#docs/_getting-started/my-first-subscriber.md/my-first-subscriber).
|
|
6
|
+
|
|
7
|
+
## 1. Lit component + Tailwind
|
|
8
|
+
|
|
9
|
+
Export Tailwind once (e.g. `src/docs/tailwind.ts` in this repo):
|
|
10
|
+
|
|
11
|
+
<sonic-code language="typescript">
|
|
12
|
+
<template>
|
|
13
|
+
import { css, unsafeCSS } from "lit";
|
|
14
|
+
import tailwindImport from "./css/tailwind.css?inline";
|
|
15
|
+
|
|
16
|
+
export const tailwind = css`${unsafeCSS(tailwindImport)}`;
|
|
17
|
+
</template>
|
|
18
|
+
</sonic-code>
|
|
19
|
+
|
|
20
|
+
User card — plain Lit properties and UI components (no store yet):
|
|
21
|
+
|
|
22
|
+
<sonic-code language="typescript">
|
|
23
|
+
<template>
|
|
24
|
+
import { html, LitElement } from "lit";
|
|
25
|
+
import { customElement, property } from "lit/decorators.js";
|
|
26
|
+
import { tailwind } from "../tailwind";
|
|
27
|
+
|
|
28
|
+
@customElement("docs-user")
|
|
29
|
+
export class DocsUser extends LitElement {
|
|
30
|
+
static styles = [tailwind];
|
|
31
|
+
|
|
32
|
+
@property({ type: String }) first_name = "";
|
|
33
|
+
@property({ type: String }) last_name = "";
|
|
34
|
+
@property({ type: String }) email = "";
|
|
35
|
+
@property({ type: String }) avatar = "";
|
|
36
|
+
|
|
37
|
+
render() {
|
|
38
|
+
return html`<div class="flex items-center gap-3 rounded-md p-2">
|
|
39
|
+
<sonic-image src=${this.avatar} rounded="md" ratio="1/1" class="w-16"></sonic-image>
|
|
40
|
+
<div>
|
|
41
|
+
<div>${this.first_name} <span class="font-bold">${this.last_name}</span></div>
|
|
42
|
+
<div class="text-sm text-neutral-400">${this.email}</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
</template>
|
|
48
|
+
</sonic-code>
|
|
49
|
+
|
|
50
|
+
## 2. Data configuration
|
|
51
|
+
|
|
52
|
+
The card does not hard-code user fields anymore. You declare **what** is stored, **where** it lives, and **which ancestor scope** applies — then `@subscribe` mirrors that object on the component.
|
|
53
|
+
|
|
54
|
+
### Type — shape of the data
|
|
55
|
+
|
|
56
|
+
`DocsUserData` documents the fields you expect at this scope (first name, email, avatar, …). TypeScript checks that `user` matches that shape.
|
|
57
|
+
|
|
58
|
+
<sonic-code language="typescript">
|
|
59
|
+
<template>
|
|
60
|
+
export type DocsUserData = {
|
|
61
|
+
first_name: string;
|
|
62
|
+
last_name: string;
|
|
63
|
+
email: string;
|
|
64
|
+
avatar: string;
|
|
65
|
+
};
|
|
66
|
+
</template>
|
|
67
|
+
</sonic-code>
|
|
68
|
+
|
|
69
|
+
### Key — path in the DataProvider
|
|
70
|
+
|
|
71
|
+
`docsUserRowKey` points at the store segment to read. The path `"${dataProvider}"` is resolved at runtime from a property on the component (see scope below).
|
|
72
|
+
|
|
73
|
+
<sonic-code language="typescript">
|
|
74
|
+
<template>
|
|
75
|
+
import { DataProviderKey } from "@supersoniks/concorde/core/utils/dataProviderKey";
|
|
76
|
+
|
|
77
|
+
export const docsUserRowKey = new DataProviderKey<
|
|
78
|
+
DocsUserData,
|
|
79
|
+
{ dataProvider: string | null }
|
|
80
|
+
>("${dataProvider}");
|
|
81
|
+
</template>
|
|
82
|
+
</sonic-code>
|
|
83
|
+
|
|
84
|
+
The second generic (`{ dataProvider: string | null }`) lists what the host must expose so `"${dataProvider}"` can be resolved. See [DataProviderKey](#docs/_misc/dataProviderKey.md/dataProviderKey).
|
|
85
|
+
|
|
86
|
+
### Scope — which store segment applies
|
|
87
|
+
|
|
88
|
+
A parent sets `dataProvider=${docsUserScopeAKey.path}` (or a list row sets `…/list-item/0`). [`@ancestorAttribute`](#docs/_decorators/ancestor-attribute.md/ancestor-attribute) copies that attribute onto `this.dataProvider`, so the key resolves to the correct branch.
|
|
89
|
+
|
|
90
|
+
<sonic-code language="typescript">
|
|
91
|
+
<template>
|
|
92
|
+
@ancestorAttribute("dataProvider")
|
|
93
|
+
dataProvider: string | null = null;
|
|
94
|
+
</template>
|
|
95
|
+
</sonic-code>
|
|
96
|
+
|
|
97
|
+
### Subscribe — keep the card in sync
|
|
98
|
+
|
|
99
|
+
[`@subscribe`](#docs/_decorators/subscribe.md/subscribe) watches `docsUserRowKey` and updates `user` when the store changes. Use `@state()` so Lit re-renders. The template reads `this.user` like any other property.
|
|
100
|
+
|
|
101
|
+
<sonic-code language="typescript">
|
|
102
|
+
<template>
|
|
103
|
+
import { html, LitElement, nothing } from "lit";
|
|
104
|
+
import { customElement, state } from "lit/decorators.js";
|
|
105
|
+
import {
|
|
106
|
+
ancestorAttribute,
|
|
107
|
+
subscribe,
|
|
108
|
+
} from "@supersoniks/concorde/core/decorators/Subscriber";
|
|
109
|
+
import { docsUserRowKey, type DocsUserData } from "./users";
|
|
110
|
+
import { tailwind } from "../tailwind";
|
|
111
|
+
|
|
112
|
+
@customElement("docs-user")
|
|
113
|
+
export class DocsUser extends LitElement {
|
|
114
|
+
static styles = [tailwind];
|
|
115
|
+
|
|
116
|
+
@ancestorAttribute("dataProvider")
|
|
117
|
+
dataProvider: string | null = null;
|
|
118
|
+
|
|
119
|
+
@subscribe(docsUserRowKey)
|
|
120
|
+
@state()
|
|
121
|
+
user: DocsUserData | null = null;
|
|
122
|
+
|
|
123
|
+
render() {
|
|
124
|
+
const u = this.user;
|
|
125
|
+
if (!u) return nothing;
|
|
126
|
+
return html`<div class="flex items-center gap-3 rounded-md p-2">
|
|
127
|
+
<sonic-image src=${u.avatar} rounded="md" ratio="1/1" class="w-16"></sonic-image>
|
|
128
|
+
<div>
|
|
129
|
+
<div>${u.first_name} <span class="font-bold">${u.last_name}</span></div>
|
|
130
|
+
<div class="text-sm text-neutral-400">${u.email}</div>
|
|
131
|
+
</div>
|
|
132
|
+
</div>`;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
</template>
|
|
136
|
+
</sonic-code>
|
|
137
|
+
|
|
138
|
+
Live code: `src/docs/example/users.ts`. In this repo, imports use **`core/…` paths** (short `@supersoniks/concorde/…` exports apply in **consumer apps** only).
|
|
139
|
+
|
|
140
|
+
### Two scopes, one component
|
|
141
|
+
|
|
142
|
+
The same `docs-user` is mounted twice. Each copy inherits a **different** nearest `dataProvider` — that is the row/list **scope**:
|
|
143
|
+
|
|
144
|
+
<sonic-code>
|
|
145
|
+
<template>
|
|
146
|
+
<docs-demo-sources for="docs-user-two-scopes"></docs-demo-sources>
|
|
147
|
+
<docs-user-two-scopes></docs-user-two-scopes>
|
|
148
|
+
</template>
|
|
149
|
+
</sonic-code>
|
|
150
|
+
|
|
151
|
+
Markup (two isolated stores; keys from `docs-provider-keys.ts`):
|
|
152
|
+
|
|
153
|
+
<sonic-code language="markup">
|
|
154
|
+
<template>
|
|
155
|
+
<div class="grid md:grid-cols-2 gap-6">
|
|
156
|
+
<div dataProvider="${docsUserScopeAKey.path}">
|
|
157
|
+
<docs-user></docs-user>
|
|
158
|
+
</div>
|
|
159
|
+
<div dataProvider="${docsUserScopeBKey.path}">
|
|
160
|
+
<docs-user></docs-user>
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
</template>
|
|
164
|
+
</sonic-code>
|
|
165
|
+
|
|
166
|
+
Seeded in `docs-provider-keys.ts` (`set(docsUserScopeAKey, …)`): **Paul** / **Marie**. Without `@ancestorAttribute`, both cards would not know which store to read.
|
|
167
|
+
|
|
168
|
+
## 3. Fetch users — `sonic-list` with `.items`
|
|
169
|
+
|
|
170
|
+
Use a Lit parent and the **`items`** renderer (not HTML `<template>` children). The callback receives each row object from fetch — render fields directly (`${item.first_name}`, …), like porting a template that used `data-bind` / `<sonic-value>`.
|
|
171
|
+
|
|
172
|
+
<sonic-code>
|
|
173
|
+
<template>
|
|
174
|
+
<docs-lit-demo for="docs-users-list"></docs-lit-demo>
|
|
175
|
+
</template>
|
|
176
|
+
</sonic-code>
|
|
177
|
+
|
|
178
|
+
Wrapper (`docs-users-list.ts`):
|
|
179
|
+
|
|
180
|
+
<sonic-code language="typescript">
|
|
181
|
+
<template>
|
|
182
|
+
import { html, LitElement } from "lit";
|
|
183
|
+
import { customElement } from "lit/decorators.js";
|
|
184
|
+
import "../../core/components/functional/list/list";
|
|
185
|
+
import "./users";
|
|
186
|
+
|
|
187
|
+
@customElement("docs-users-list")
|
|
188
|
+
export class DocsUsersList extends LitElement {
|
|
189
|
+
private items = ({ first_name, last_name, email, avatar }) => html`
|
|
190
|
+
<div class="flex gap-3">
|
|
191
|
+
<sonic-image src=${avatar} ...></sonic-image>
|
|
192
|
+
<div>${first_name} <b>${last_name}</b></div>
|
|
193
|
+
<div class="text-sm text-neutral-400">${email}</div>
|
|
194
|
+
</div>
|
|
195
|
+
`;
|
|
196
|
+
|
|
197
|
+
render() {
|
|
198
|
+
return html`
|
|
199
|
+
<sonic-list fetch dataProvider=${usersListEndpoint.path} key="data" .items=${this.items}></sonic-list>
|
|
200
|
+
`;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
</template>
|
|
204
|
+
</sonic-code>
|
|
205
|
+
|
|
206
|
+
See [Local API demos](#docs/_misc/docs-mock-api.md/docs-mock-api) for `serviceURL="/docs-mock-api"`.
|
|
207
|
+
|
|
208
|
+
## 4. Form preview with `formDataProvider`
|
|
209
|
+
|
|
210
|
+
Edit fields in a form; the card follows the same `docsUserRowKey` when the preview host sets `dataProvider="userPreview"`.
|
|
211
|
+
|
|
212
|
+
<sonic-code>
|
|
213
|
+
<template>
|
|
214
|
+
<div class="grid grid-cols-1 gap-4 max-w-xl">
|
|
215
|
+
<form formDataProvider="${docsUserPreviewKey.path}" class="grid grid-cols-2 gap-3">
|
|
216
|
+
<sonic-input label="First name" name="first_name" value="Paul" size="sm"></sonic-input>
|
|
217
|
+
<sonic-input label="Last name" name="last_name" value="Metrand" size="sm"></sonic-input>
|
|
218
|
+
<sonic-input class="col-span-2" label="Email" name="email" value="paul@example.com" size="sm"></sonic-input>
|
|
219
|
+
<sonic-input class="col-span-2" label="Avatar URL" name="avatar" value="https://i.pravatar.cc/150?u=paul" size="sm"></sonic-input>
|
|
220
|
+
</form>
|
|
221
|
+
<sonic-divider align="left">Preview</sonic-divider>
|
|
222
|
+
<div dataProvider="${docsUserPreviewKey.path}">
|
|
223
|
+
<docs-user></docs-user>
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
</template>
|
|
227
|
+
</sonic-code>
|
|
228
|
+
|
|
229
|
+
Use `formDataProvider` + `name` on inputs — no manual `@input` handlers ([Data flow](#docs/_core-concept/dataFlow.md/dataFlow)).
|
|
230
|
+
|
|
231
|
+
## Next steps
|
|
232
|
+
|
|
233
|
+
- [Data flow](#docs/_core-concept/dataFlow.md/dataFlow) — full map
|
|
234
|
+
- [DataProviderKey](#docs/_misc/dataProviderKey.md/dataProviderKey) — typed paths and host constraints
|
|
235
|
+
- [@subscribe](#docs/_decorators/subscribe.md/subscribe) / [sub()](#docs/_directives/sub.md/sub) — read-only in templates
|
|
236
|
+
- [List](#core/components/functional/list/list.md/list) — `.items`, `.noItems`, `.skeleton`
|