@supersoniks/concorde 4.6.0 → 4.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/.gitlab-ci.yml +23 -0
  2. package/README.md +106 -55
  3. package/ai/AGENTS.md +52 -0
  4. package/ai/README.md +30 -0
  5. package/ai/cursor/rules/concorde-menu.mdc +15 -0
  6. package/ai/cursor/rules/concorde-scope.mdc +14 -0
  7. package/ai/cursor/rules/concorde-theme.mdc +13 -0
  8. package/ai/cursor/rules/concorde.mdc +49 -0
  9. package/ai/jetbrains/rules/concorde.md +39 -0
  10. package/ai/skills/concorde/SKILL.md +220 -0
  11. package/ai/skills/concorde-get-set-dp/SKILL.md +194 -0
  12. package/ai/skills/concorde-imports/SKILL.md +78 -0
  13. package/ai/skills/concorde-menu/SKILL.md +74 -0
  14. package/ai/skills/concorde-scope/SKILL.md +70 -0
  15. package/ai/skills/concorde-theme/SKILL.md +46 -0
  16. package/build-infos.json +1 -1
  17. package/concorde-core.bundle.js +127 -127
  18. package/concorde-core.es.js +1435 -1364
  19. package/dist/altcha-widget.js +2662 -0
  20. package/dist/concorde-core.bundle.js +127 -127
  21. package/dist/concorde-core.es.js +1435 -1364
  22. package/dist/docs-mock-api-sw.js +589 -0
  23. package/dist/docs-mock-api-sw.js.map +7 -0
  24. package/docs/altcha-widget.js +2662 -0
  25. package/docs/assets/index-D9pxaQYK.js +7508 -0
  26. package/docs/assets/index-t0-i22oI.css +1 -0
  27. package/docs/docs-mock-api-sw.js +589 -0
  28. package/docs/docs-mock-api-sw.js.map +7 -0
  29. package/docs/index.html +2 -2
  30. package/docs/src/core/components/functional/fetch/fetch.md +13 -11
  31. package/docs/src/core/components/functional/if/if.md +4 -11
  32. package/docs/src/core/components/functional/list/list.md +60 -194
  33. package/docs/src/core/components/functional/queue/queue.md +70 -85
  34. package/docs/src/core/components/functional/router/router.md +62 -97
  35. package/docs/src/core/components/functional/states/states.md +2 -2
  36. package/docs/src/core/components/functional/submit/submit.md +86 -55
  37. package/docs/src/core/components/ui/captcha/captcha.md +2 -2
  38. package/docs/src/core/components/ui/card/card.md +1 -1
  39. package/docs/src/core/components/ui/form/checkbox/checkbox.md +5 -32
  40. package/docs/src/core/components/ui/form/input/input.md +5 -30
  41. package/docs/src/core/components/ui/form/input-autocomplete/input-autocomplete.md +6 -4
  42. package/docs/src/core/components/ui/form/radio/radio.md +5 -32
  43. package/docs/src/core/components/ui/form/select/select.md +5 -31
  44. package/docs/src/core/components/ui/form/switch/switch.md +5 -32
  45. package/docs/src/core/components/ui/loader/loader.md +1 -13
  46. package/docs/src/core/components/ui/table/table.md +3 -3
  47. package/docs/src/docs/_core-concept/dataFlow.md +73 -0
  48. package/docs/src/docs/_core-concept/subscriber.md +9 -10
  49. package/docs/src/docs/_decorators/ancestor-attribute.md +4 -3
  50. package/docs/src/docs/_decorators/auto-subscribe.md +19 -16
  51. package/docs/src/docs/_decorators/bind.md +20 -17
  52. package/docs/src/docs/_decorators/get.md +7 -4
  53. package/docs/src/docs/_decorators/handle.md +171 -0
  54. package/docs/src/docs/_decorators/on-assign.md +99 -73
  55. package/docs/src/docs/_decorators/publish.md +2 -1
  56. package/docs/src/docs/_decorators/subscribe.md +70 -9
  57. package/docs/src/docs/_decorators/wait-for-ancestors.md +13 -10
  58. package/docs/src/docs/_directives/sub.md +91 -0
  59. package/docs/src/docs/_getting-started/ai-agents.md +56 -0
  60. package/docs/src/docs/_getting-started/concorde-manual-install.md +133 -0
  61. package/docs/src/docs/_getting-started/concorde-outside.md +13 -123
  62. package/docs/src/docs/_getting-started/create-a-component.md +2 -0
  63. package/docs/src/docs/_getting-started/my-first-component.md +236 -0
  64. package/docs/src/docs/_getting-started/my-first-subscriber.md +29 -83
  65. package/docs/src/docs/_getting-started/pubsub.md +21 -134
  66. package/docs/src/docs/_getting-started/start.md +26 -18
  67. package/docs/src/docs/_misc/api-configuration.md +79 -0
  68. package/docs/src/docs/_misc/dataProviderKey.md +38 -5
  69. package/docs/src/docs/_misc/docs-mock-api.md +60 -0
  70. package/docs/src/docs/_misc/endpoint.md +2 -1
  71. package/docs/src/docs/_misc/html-integration.md +13 -0
  72. package/docs/src/docs/search/docs-search.json +4163 -873
  73. package/docs/src/tsconfig.json +380 -317
  74. package/gitlab/job_tests.sh +55 -0
  75. package/package.json +34 -3
  76. package/public/altcha-widget.js +2662 -0
  77. package/public/docs-mock-api-sw.js +589 -0
  78. package/public/docs-mock-api-sw.js.map +7 -0
  79. package/scripts/ai-init.mjs +167 -0
  80. package/scripts/docs-mock-api-vite-plugin.ts +116 -0
  81. package/scripts/docs-open-in-editor-plugin.ts +130 -0
  82. package/scripts/pre-publish.mjs +2 -1
  83. package/src/core/components/functional/example/example.ts +1 -1
  84. package/src/core/components/functional/fetch/fetch.md +13 -11
  85. package/src/core/components/functional/if/if.md +4 -11
  86. package/src/core/components/functional/list/list.demo.ts +4 -4
  87. package/src/core/components/functional/list/list.md +60 -194
  88. package/src/core/components/functional/list/list.ts +8 -7
  89. package/src/core/components/functional/queue/queue.demo.ts +1 -1
  90. package/src/core/components/functional/queue/queue.md +70 -85
  91. package/src/core/components/functional/queue/queue.ts +4 -4
  92. package/src/core/components/functional/router/router.md +62 -97
  93. package/src/core/components/functional/router/router.ts +1 -1
  94. package/src/core/components/functional/states/states.md +2 -2
  95. package/src/core/components/functional/submit/submit.md +86 -55
  96. package/src/core/components/functional/submit/submit.ts +10 -3
  97. package/src/core/components/ui/captcha/captcha.md +2 -2
  98. package/src/core/components/ui/card/card.md +1 -1
  99. package/src/core/components/ui/form/checkbox/checkbox.md +5 -32
  100. package/src/core/components/ui/form/input/input.md +5 -30
  101. package/src/core/components/ui/form/input-autocomplete/input-autocomplete.md +6 -4
  102. package/src/core/components/ui/form/radio/radio.md +5 -32
  103. package/src/core/components/ui/form/select/select.md +5 -31
  104. package/src/core/components/ui/form/switch/switch.md +5 -32
  105. package/src/core/components/ui/loader/loader.md +1 -13
  106. package/src/core/components/ui/table/table.md +3 -3
  107. package/src/core/directives/DataProvider.sub.spec.ts +96 -0
  108. package/src/core/directives/DataProvider.ts +109 -40
  109. package/src/core/utils/PublisherProxy.ts +33 -18
  110. package/src/core/utils/dataProviderKey.ts +23 -0
  111. package/src/core/utils/publisherPathKey.spec.ts +58 -0
  112. package/src/docs/_core-concept/dataFlow.md +73 -0
  113. package/src/docs/_core-concept/subscriber.md +9 -10
  114. package/src/docs/_decorators/ancestor-attribute.md +4 -3
  115. package/src/docs/_decorators/auto-subscribe.md +19 -16
  116. package/src/docs/_decorators/bind.md +19 -16
  117. package/src/docs/_decorators/get.md +7 -4
  118. package/src/docs/_decorators/handle.md +15 -13
  119. package/src/docs/_decorators/on-assign.md +53 -53
  120. package/src/docs/_decorators/publish.md +2 -1
  121. package/src/docs/_decorators/subscribe.md +70 -9
  122. package/src/docs/_decorators/wait-for-ancestors.md +13 -10
  123. package/src/docs/_directives/sub.md +91 -0
  124. package/src/docs/_getting-started/ai-agents.md +56 -0
  125. package/src/docs/_getting-started/concorde-manual-install.md +133 -0
  126. package/src/docs/_getting-started/concorde-outside.md +13 -123
  127. package/src/docs/_getting-started/create-a-component.md +2 -0
  128. package/src/docs/_getting-started/my-first-component.md +236 -0
  129. package/src/docs/_getting-started/my-first-subscriber.md +29 -83
  130. package/src/docs/_getting-started/pubsub.md +21 -134
  131. package/src/docs/_getting-started/start.md +26 -18
  132. package/src/docs/_misc/api-configuration.md +79 -0
  133. package/src/docs/_misc/dataProviderKey.md +34 -1
  134. package/src/docs/_misc/docs-mock-api.md +60 -0
  135. package/src/docs/_misc/endpoint.md +2 -1
  136. package/src/docs/_misc/html-integration.md +13 -0
  137. package/src/docs/code.ts +58 -12
  138. package/src/docs/components/docs-demo-sources.ts +397 -0
  139. package/src/docs/components/docs-lit-demo-raw.ts +28 -0
  140. package/src/docs/components/docs-lit-demo.ts +166 -0
  141. package/src/docs/components/docs-source-link.ts +72 -0
  142. package/src/docs/docs-location.ts +54 -0
  143. package/src/docs/docs.ts +12 -0
  144. package/src/docs/example/decorators-demo-bind-demos.ts +41 -46
  145. package/src/docs/example/decorators-demo-geo.ts +16 -11
  146. package/src/docs/example/decorators-demo-init.ts +2 -228
  147. package/src/docs/example/decorators-demo-subscribe-publish-get-demos.ts +54 -14
  148. package/src/docs/example/decorators-demo.ts +71 -70
  149. package/src/docs/example/docs-api-config-demos.ts +234 -0
  150. package/src/docs/example/docs-joke-demos.ts +297 -0
  151. package/src/docs/example/docs-list-demos.ts +179 -0
  152. package/src/docs/example/docs-provider-keys.ts +315 -0
  153. package/src/docs/example/docs-queue-demos.ts +114 -0
  154. package/src/docs/example/docs-router-demos.ts +89 -0
  155. package/src/docs/example/docs-submit-demos.ts +455 -0
  156. package/src/docs/example/docs-toggle-demos.ts +73 -0
  157. package/src/docs/example/docs-user-two-scopes.ts +37 -0
  158. package/src/docs/example/docs-users-list.ts +71 -0
  159. package/src/docs/example/users.ts +41 -24
  160. package/src/docs/mock-api/api-config-mock.ts +152 -0
  161. package/src/docs/mock-api/fixtures.ts +377 -0
  162. package/src/docs/mock-api/register.ts +25 -0
  163. package/src/docs/mock-api/router.ts +234 -0
  164. package/src/docs/mock-api/service-worker.ts +23 -0
  165. package/src/docs/mock-api/urls.ts +11 -0
  166. package/src/docs/navigation/navigation.ts +39 -7
  167. package/src/docs/search/docs-search.json +4021 -936
  168. package/src/docs/search/markdown-renderer.ts +7 -3
  169. package/src/docs/search/page.ts +11 -14
  170. package/src/docs/search/sonic-code-markdown.spec.ts +29 -0
  171. package/src/docs/search/sonic-code-markdown.ts +28 -0
  172. package/src/docs.ts +4 -0
  173. package/src/tsconfig.json +87 -0
  174. package/src/tsconfig.tsbuildinfo +1 -1
  175. package/vite.config.mts +8 -0
  176. package/docs/assets/index-CaysOMFz.js +0 -5046
  177. package/docs/assets/index-D8mGoXzF.css +0 -1
  178. package/docs/src/docs/_misc/templates-demo.md +0 -19
  179. package/src/docs/_misc/templates-demo.md +0 -19
@@ -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
- ## Brand New Vite Project
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
- # Pure JavaScript project
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
- ## Shortcut Imports
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
- The original paths remain accessible. Shortcut imports are used for the examples later in this documentation.
82
-
83
- ## Usage
84
-
85
- ### Simple Integration in HTML
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`&lt;div class="flex items-center gap-3 rounded-md p-2"&gt;
39
+ &lt;sonic-image src=${this.avatar} rounded="md" ratio="1/1" class="w-16"&gt;&lt;/sonic-image&gt;
40
+ &lt;div&gt;
41
+ &lt;div&gt;${this.first_name} &lt;span class="font-bold"&gt;${this.last_name}&lt;/span&gt;&lt;/div&gt;
42
+ &lt;div class="text-sm text-neutral-400"&gt;${this.email}&lt;/div&gt;
43
+ &lt;/div&gt;
44
+ &lt;/div&gt;`;
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&lt;
78
+ DocsUserData,
79
+ { dataProvider: string | null }
80
+ &gt;("${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`&lt;div class="flex items-center gap-3 rounded-md p-2"&gt;
127
+ &lt;sonic-image src=${u.avatar} rounded="md" ratio="1/1" class="w-16"&gt;&lt;/sonic-image&gt;
128
+ &lt;div&gt;
129
+ &lt;div&gt;${u.first_name} &lt;span class="font-bold"&gt;${u.last_name}&lt;/span&gt;&lt;/div&gt;
130
+ &lt;div class="text-sm text-neutral-400"&gt;${u.email}&lt;/div&gt;
131
+ &lt;/div&gt;
132
+ &lt;/div&gt;`;
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
+ &lt;div class="grid md:grid-cols-2 gap-6"&gt;
156
+ &lt;div dataProvider="${docsUserScopeAKey.path}"&gt;
157
+ &lt;docs-user&gt;&lt;/docs-user&gt;
158
+ &lt;/div&gt;
159
+ &lt;div dataProvider="${docsUserScopeBKey.path}"&gt;
160
+ &lt;docs-user&gt;&lt;/docs-user&gt;
161
+ &lt;/div&gt;
162
+ &lt;/div&gt;
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
+ &lt;div class="flex gap-3"&gt;
191
+ &lt;sonic-image src=${avatar} ...&gt;&lt;/sonic-image&gt;
192
+ &lt;div&gt;${first_name} &lt;b&gt;${last_name}&lt;/b&gt;&lt;/div&gt;
193
+ &lt;div class="text-sm text-neutral-400"&gt;${email}&lt;/div&gt;
194
+ &lt;/div&gt;
195
+ `;
196
+
197
+ render() {
198
+ return html`
199
+ &lt;sonic-list fetch dataProvider=${usersListEndpoint.path} key="data" .items=${this.items}&gt;&lt;/sonic-list&gt;
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`