@supersoniks/concorde 4.4.2 → 4.5.1

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 (137) hide show
  1. package/build-infos.json +1 -1
  2. package/concorde-core.bundle.js +670 -584
  3. package/concorde-core.es.js +9729 -7104
  4. package/dist/concorde-core.bundle.js +670 -584
  5. package/dist/concorde-core.es.js +9729 -7104
  6. package/package.json +7 -4
  7. package/src/core/components/functional/fetch/fetch.md +0 -0
  8. package/src/core/components/ui/_css/scroll.ts +0 -0
  9. package/src/core/components/ui/_css/size.ts +0 -0
  10. package/src/core/components/ui/alert/alert.ts +0 -0
  11. package/src/core/components/ui/button/button.ts +0 -0
  12. package/src/core/components/ui/captcha/altchaStyles.ts +0 -0
  13. package/src/core/components/ui/divider/divider.ts +0 -0
  14. package/src/core/components/ui/menu/menu.md +0 -0
  15. package/src/core/components/ui/modal/modal-close.ts +0 -0
  16. package/src/core/components/ui/modal/modal-utils.ts +46 -0
  17. package/src/core/components/ui/modal/modal.md +0 -0
  18. package/src/core/components/ui/modal/modal.ts +33 -8
  19. package/src/core/components/ui/table/table-caption.ts +0 -0
  20. package/src/core/decorators/subscriber/onAssign.ts +4 -4
  21. package/src/core/utils/dataProviderKey.spec.ts +8 -0
  22. package/src/core/utils/dataProviderKey.ts +31 -12
  23. package/src/core/utils/route.ts +0 -0
  24. package/src/docs/code.ts +0 -0
  25. package/src/tsconfig.json +9 -0
  26. package/src/tsconfig.tsbuildinfo +1 -1
  27. package/vite/config.js +52 -34
  28. package/vite.config.mts +14 -12
  29. package/docs/assets/index-CW8cIYT9.js +0 -4949
  30. package/docs/assets/index-DZtxIZCW.css +0 -1
  31. package/docs/css/docs.css +0 -0
  32. package/docs/fonts/ClashGrotesk-Bold.eot +0 -0
  33. package/docs/fonts/ClashGrotesk-Bold.ttf +0 -0
  34. package/docs/fonts/ClashGrotesk-Bold.woff +0 -0
  35. package/docs/fonts/ClashGrotesk-Bold.woff2 +0 -0
  36. package/docs/fonts/ClashGrotesk-Extralight.eot +0 -0
  37. package/docs/fonts/ClashGrotesk-Extralight.ttf +0 -0
  38. package/docs/fonts/ClashGrotesk-Extralight.woff +0 -0
  39. package/docs/fonts/ClashGrotesk-Extralight.woff2 +0 -0
  40. package/docs/fonts/ClashGrotesk-Light.eot +0 -0
  41. package/docs/fonts/ClashGrotesk-Light.ttf +0 -0
  42. package/docs/fonts/ClashGrotesk-Light.woff +0 -0
  43. package/docs/fonts/ClashGrotesk-Light.woff2 +0 -0
  44. package/docs/fonts/ClashGrotesk-Medium.eot +0 -0
  45. package/docs/fonts/ClashGrotesk-Medium.ttf +0 -0
  46. package/docs/fonts/ClashGrotesk-Medium.woff +0 -0
  47. package/docs/fonts/ClashGrotesk-Medium.woff2 +0 -0
  48. package/docs/fonts/ClashGrotesk-Regular.eot +0 -0
  49. package/docs/fonts/ClashGrotesk-Regular.ttf +0 -0
  50. package/docs/fonts/ClashGrotesk-Regular.woff +0 -0
  51. package/docs/fonts/ClashGrotesk-Regular.woff2 +0 -0
  52. package/docs/fonts/ClashGrotesk-Semibold.eot +0 -0
  53. package/docs/fonts/ClashGrotesk-Semibold.ttf +0 -0
  54. package/docs/fonts/ClashGrotesk-Semibold.woff +0 -0
  55. package/docs/fonts/ClashGrotesk-Semibold.woff2 +0 -0
  56. package/docs/fonts/ClashGrotesk-Variable.eot +0 -0
  57. package/docs/fonts/ClashGrotesk-Variable.ttf +0 -0
  58. package/docs/fonts/ClashGrotesk-Variable.woff +0 -0
  59. package/docs/fonts/ClashGrotesk-Variable.woff2 +0 -0
  60. package/docs/img/concorde-icon.svg +0 -5
  61. package/docs/img/concorde-logo.svg +0 -1
  62. package/docs/img/concorde.png +0 -0
  63. package/docs/img/concorde_def.png +0 -0
  64. package/docs/img/concorde_seuil.png.webp +0 -0
  65. package/docs/img/concorde_seuil_invert.png +0 -0
  66. package/docs/img/paul_metrand.jpg +0 -0
  67. package/docs/img/paul_metrand_xs.jpg +0 -0
  68. package/docs/index.html +0 -93
  69. package/docs/src/core/components/functional/date/date.md +0 -290
  70. package/docs/src/core/components/functional/fetch/fetch.md +0 -123
  71. package/docs/src/core/components/functional/if/if.md +0 -16
  72. package/docs/src/core/components/functional/list/list.md +0 -199
  73. package/docs/src/core/components/functional/mix/mix.md +0 -41
  74. package/docs/src/core/components/functional/queue/queue.md +0 -87
  75. package/docs/src/core/components/functional/router/router.md +0 -129
  76. package/docs/src/core/components/functional/sdui/default-library.json +0 -108
  77. package/docs/src/core/components/functional/sdui/example.json +0 -99
  78. package/docs/src/core/components/functional/sdui/sdui.md +0 -356
  79. package/docs/src/core/components/functional/states/states.md +0 -87
  80. package/docs/src/core/components/functional/submit/submit.md +0 -83
  81. package/docs/src/core/components/functional/subscriber/subscriber.md +0 -91
  82. package/docs/src/core/components/functional/value/value.md +0 -35
  83. package/docs/src/core/components/ui/alert/alert.md +0 -121
  84. package/docs/src/core/components/ui/alert-messages/alert-messages.md +0 -0
  85. package/docs/src/core/components/ui/badge/badge.md +0 -127
  86. package/docs/src/core/components/ui/button/button.md +0 -182
  87. package/docs/src/core/components/ui/captcha/captcha.md +0 -24
  88. package/docs/src/core/components/ui/card/card.md +0 -97
  89. package/docs/src/core/components/ui/divider/divider.md +0 -35
  90. package/docs/src/core/components/ui/form/checkbox/checkbox.md +0 -104
  91. package/docs/src/core/components/ui/form/fieldset/fieldset.md +0 -129
  92. package/docs/src/core/components/ui/form/form-actions/form-actions.md +0 -77
  93. package/docs/src/core/components/ui/form/form-layout/form-layout.md +0 -44
  94. package/docs/src/core/components/ui/form/input/input.md +0 -167
  95. package/docs/src/core/components/ui/form/input-autocomplete/input-autocomplete.md +0 -131
  96. package/docs/src/core/components/ui/form/radio/radio.md +0 -84
  97. package/docs/src/core/components/ui/form/select/select.md +0 -97
  98. package/docs/src/core/components/ui/form/switch/switch.md +0 -84
  99. package/docs/src/core/components/ui/form/textarea/textarea.md +0 -65
  100. package/docs/src/core/components/ui/group/group.md +0 -75
  101. package/docs/src/core/components/ui/icon/icon.md +0 -125
  102. package/docs/src/core/components/ui/icon/icons.json +0 -1
  103. package/docs/src/core/components/ui/image/image.md +0 -107
  104. package/docs/src/core/components/ui/link/link.md +0 -43
  105. package/docs/src/core/components/ui/loader/loader.md +0 -67
  106. package/docs/src/core/components/ui/menu/menu.md +0 -329
  107. package/docs/src/core/components/ui/modal/modal.md +0 -119
  108. package/docs/src/core/components/ui/pop/pop.md +0 -96
  109. package/docs/src/core/components/ui/progress/progress.md +0 -63
  110. package/docs/src/core/components/ui/table/table.md +0 -455
  111. package/docs/src/core/components/ui/toast/toast.md +0 -166
  112. package/docs/src/core/components/ui/tooltip/tooltip.md +0 -82
  113. package/docs/src/docs/_core-concept/overview.md +0 -57
  114. package/docs/src/docs/_core-concept/subscriber.md +0 -76
  115. package/docs/src/docs/_decorators/ancestor-attribute.md +0 -78
  116. package/docs/src/docs/_decorators/auto-subscribe.md +0 -199
  117. package/docs/src/docs/_decorators/bind.md +0 -164
  118. package/docs/src/docs/_decorators/get.md +0 -65
  119. package/docs/src/docs/_decorators/on-assign.md +0 -336
  120. package/docs/src/docs/_decorators/publish.md +0 -54
  121. package/docs/src/docs/_decorators/subscribe.md +0 -36
  122. package/docs/src/docs/_decorators/wait-for-ancestors.md +0 -160
  123. package/docs/src/docs/_getting-started/concorde-outside.md +0 -143
  124. package/docs/src/docs/_getting-started/create-a-component.md +0 -137
  125. package/docs/src/docs/_getting-started/my-first-subscriber.md +0 -174
  126. package/docs/src/docs/_getting-started/pubsub.md +0 -150
  127. package/docs/src/docs/_getting-started/start.md +0 -39
  128. package/docs/src/docs/_getting-started/theming.md +0 -91
  129. package/docs/src/docs/_misc/dataProviderKey.md +0 -135
  130. package/docs/src/docs/_misc/endpoint.md +0 -42
  131. package/docs/src/docs/_misc/templates-demo.md +0 -19
  132. package/docs/src/docs/search/docs-search.json +0 -5197
  133. package/docs/src/tag-list.json +0 -1
  134. package/docs/src/tsconfig-model.json +0 -23
  135. package/docs/src/tsconfig.json +0 -987
  136. package/docs/svg/regular/plane.svg +0 -1
  137. package/docs/svg/solid/plane.svg +0 -1
@@ -1,82 +0,0 @@
1
- # Tooltip
2
-
3
- <sonic-code>
4
- <template>
5
- <sonic-tooltip label="Tada : Text appears">hover me</sonic-tooltip>
6
- </template>
7
- </sonic-code>
8
-
9
- ## Placement
10
-
11
- By default, tooltip is centered next to its content
12
-
13
- <sonic-code>
14
- <template>
15
- <sonic-tooltip placement="top" label="Top text">
16
- <sonic-button>Top</sonic-button>
17
- </sonic-tooltip>
18
- <sonic-tooltip placement="bottom" label="Bottom text">
19
- <sonic-button>Bottom</sonic-button>
20
- </sonic-tooltip>
21
- <sonic-tooltip placement="right" label="Right text">
22
- <sonic-button>Right</sonic-button>
23
- </sonic-tooltip>
24
- <sonic-tooltip placement="left" label="Left text">
25
- <sonic-button>Left</sonic-button>
26
- </sonic-tooltip>
27
- </template>
28
- </sonic-code>
29
-
30
- ## More placement
31
- <sonic-code>
32
- <template>
33
- <div class="flex gap-3 flex-wrap">
34
- <sonic-tooltip placement="top-start" label="My tooltip">
35
- <sonic-button class="size-40 bg-neutral-200 rounded-lg">Top start</sonic-button>
36
- </sonic-tooltip>
37
- <sonic-tooltip placement="top-end" label="My tooltip">
38
- <sonic-button class="size-40 bg-neutral-200 rounded-lg">Top end</sonic-button>
39
- </sonic-tooltip>
40
- <sonic-tooltip placement="bottom-start" label="My tooltip">
41
- <sonic-button class="size-40 bg-neutral-200 rounded-lg">Bottom start</sonic-button>
42
- </sonic-tooltip>
43
- <sonic-tooltip placement="bottom-end" label="My tooltip">
44
- <sonic-button class="size-40 bg-neutral-200 rounded-lg">Bottom end</sonic-button>
45
- </sonic-tooltip>
46
- <sonic-tooltip placement="right-start" label="My tooltip">
47
- <sonic-button class="size-40 bg-neutral-200 rounded-lg">Right start</sonic-button>
48
- </sonic-tooltip>
49
- <sonic-tooltip placement="right-end" label="My tooltip">
50
- <sonic-button class="size-40 bg-neutral-200 rounded-lg">Right end</sonic-button>
51
- </sonic-tooltip>
52
- <sonic-tooltip placement="left-start" label="My tooltip">
53
- <sonic-button class="size-40 bg-neutral-200 rounded-lg">Left start</sonic-button>
54
- </sonic-tooltip>
55
- <sonic-tooltip placement="left-end" label="My tooltip">
56
- <sonic-button class="size-40 bg-neutral-200 rounded-lg">Left end</sonic-button>
57
- </sonic-tooltip>
58
- </div>
59
- </template>
60
- </sonic-code>
61
-
62
-
63
- ## Focusable
64
-
65
- <sonic-code>
66
- <template>
67
- <sonic-tooltip focusable label="The Concorde made its first transatlantic crossing on September 26, 1973">
68
- <sonic-icon library="iconoir" name="chat-bubble-question"></sonic-icon> Focus or hover non interactive element
69
- </sonic-tooltip>
70
- </template>
71
- </sonic-code>
72
-
73
- ## Disabled
74
-
75
- <sonic-code>
76
- <template>
77
- <sonic-tooltip disabled label="Disabled text">
78
- <sonic-button>Tooltip disabled</sonic-button>
79
- </sonic-tooltip>
80
- </template>
81
- </sonic-code>
82
-
@@ -1,57 +0,0 @@
1
- # lit + tailwind + vite
2
-
3
- **Some notes for an overview of Concorde's functioning**
4
-
5
- ## Standard Web components
6
- A web component is simply a **custom HTML element** created using web standards:
7
-
8
- **web component** = [Custom Elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) + [shadowDom](https://developer.mozilla.org/fr/docs/Web/Web_Components/Using_shadow_DOM) + [HTML templates](https://developer.mozilla.org/fr/docs/Web/HTML/Element/template)
9
-
10
- ## Lit Library
11
-
12
- Concorde components are written using the lightweight Lit library: https://lit.dev/.
13
-
14
- A good portion of the elements documented on the Lit website are standard JavaScript concepts (e.g., [mixins](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#mix-ins), [tagged template literals](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Template_literals#gabarits_%C3%A9tiquet%C3%A9s)).
15
-
16
- The **library simplifies the writing of web components** by automating certain tasks:
17
-
18
- - Creation of an **open mode shadow DOM** (the component is accessible from the outside via its shadow root property).
19
- - [Rendering function](https://lit.dev/docs/components/rendering/) based on [tagged template literals](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Template_literals#gabarits_%C3%A9tiquet%C3%A9s)
20
- - [Reactive properties](https://lit.dev/docs/components/properties/) that trigger rendering when modified.
21
-
22
- Our use of Lit rarely goes beyond this [hello world](https://lit.dev/playground/#sample=examples/hello-world)
23
-
24
- ## Typescript Language
25
-
26
- We write the components in [TypeScript](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html), which is then compiled into JS.
27
-
28
- Static and inferred typing provides stronger validation of the program's functioning during compilation.
29
- However, we often use the "any" type due to time constraints.
30
-
31
- Lit uses TypeScript to simplify development through metadata:
32
- - Simplified declaration of `custom elements` via @customElement
33
- - Generation of `reactive properties` via @property.
34
-
35
- ☢️**Warning**:
36
- - During development, we operate in interpreted mode, which is faster but allows errors that won't pass during the build.
37
- - It is important to **build a distribution before pushing the code** to ensure everything is fine.
38
-
39
- ## Compatibility with Classic JS Libraries
40
-
41
- Compatibility issues may arise when using JS libraries, particularly regarding DOM traversal.
42
- This is because these libraries are blocked from traversing the DOM due to the presence of the shadow DOM.
43
- Here are some examples of things that may cause problems:
44
-
45
- - Latest FontAwesome in SVG mode, icons are not replaced
46
- - Libraries associated with jQuery
47
- - document.getElementById
48
- - ...
49
-
50
- ## Topics to Explore for Further Learning
51
-
52
-
53
- [🧱 Creating components](#docs/_getting-started/create-a-component.md/create-a-component)
54
-
55
- [🎨 Adding styles](#docs/_getting-started/theming.md/theming)
56
-
57
- [🥨 Sharing data](#docs/_getting-started/pubsub.md/pubsub)
@@ -1,76 +0,0 @@
1
- # The subscriber mixin
2
-
3
- This is a mixin that is commonly extended by Concorde core components and destination components. Pure UI components usually don't extend it, especially those outside of form components.
4
-
5
- ## DataProvider Attribute: Automatic Filling of Subscriber Properties
6
-
7
- Upon being added to the DOM (connectedCallback), subscribers search for the first occurrence of the `dataProvider` attribute in their parent's HTML structure.
8
-
9
- The value of this attribute is used to obtain a publisher via the PublisherManager (see [🥨 Sharing Data](#docs/_getting-started/pubsub.md/pubsub)).
10
-
11
- The subscriber then subscribes to the publisher as a data template to be filled.
12
-
13
- The reactive properties of the component reflect in real-time the properties with the same name in the publisher.
14
-
15
- This functionality is commonly used in the generic components [fetch](#core/components/functional/fetch/fetch.md/fetch), [queue](#core/components/functional/queue/queue.md/queue), and [list](#core/components/functional/list/list.md/list).
16
-
17
- If the subscriber is inside another subscriber, it can subscribe to a data of its parent using the attribute `subDataProvider = 'address.of.my.data'` instead of the parent's data. This allows for dynamic behavior.
18
-
19
- ## Automated Translation
20
-
21
- In a similar manner, searching for ancestor attributes can be used to configure automatic translation for any property starting with "wording" and ending with a label identifier recognized by the wordingProvider API.
22
-
23
- Normally, this API is globally configured and not within the component. Therefore, remember to prefix translatable label identifiers present in the ticketing system, for example, with "wording".
24
-
25
- ## Reactive Property `props`
26
-
27
- The value of this property can be provided as a JSON object or any other value. This value is then assigned to the associated publisher via the `dataProvider` attribute. As a result, the reactive properties of all subscribers associated with the same `dataProvider` are filled as mentioned above.
28
-
29
- ## Disabling Automatic Filling of Reactive Properties
30
-
31
- It is possible to disable the automatic filling of reactive properties in a particular component. To do so, set the variable `noAutoFill = true` in the component's class. However, the reactive property `props` will still be updated.
32
-
33
- For example, `sonic-subscriber` and `sonic-fetch` have this attribute because they do not have reactive properties.
34
-
35
- **☢ CAUTION:** When creating an object of type Subscriber or Fetcher, make sure to use the mixins and not directly extend the concrete fetch component (`sonic-fetch`) and subscriber component (`sonic-subscriber`). This is because the `noAutofill = true` attribute is set in those components.
36
-
37
- **TIPS:**
38
- If you disable automatic filling, you will likely make the rendering dynamic by writing expressions like `this.props.my.subproperty`. If `props` is updated, the rendering will be triggered. However, if `this.props.my.subproperty` is directly modified, the rendering will not be triggered. To achieve more reactivity, you can enable rendering when any subproperty is modified. Simply set the variable `renderOnPropsInternalChange = true` in the class that implements the corresponding mixin.
39
-
40
- ## Data Binding
41
-
42
- Suppose that:
43
-
44
- - You have a subscriber subscribed to a publisher via its `dataProvider` attribute.
45
- - The published data has the following structure:
46
-
47
- <sonic-code language="javascript">
48
- <template>
49
- {"img": { "avatar": "my-avatar.jpg", "caption": "look at my smile" }, "email": "an.email@example.com" }
50
- </template>
51
- </sonic-code>
52
- - We want to keep the display of an image and its `title` attribute up to date, as well as a "contact" button to email the person in the photo. The content of the subscriber could be as follows:
53
-
54
- <sonic-code language="html">
55
- <template>
56
- <img data-bind ::src="$img.avatar" ::title="ucFirst|$img.caption" />
57
- <a data-bind ::href="mailto:$email" ::inner-html="$email"></a>
58
- </template>
59
- </sonic-code>
60
-
61
- This example also illustrates:
62
-
63
- - Binding to subproperties using dot syntax, as done for the `src` attribute of the `img` tag.
64
- - Using a simple expression to include the property within a string, as in creating a `mailto` link.
65
- - Using formatting functions, as in the `title` attribute of the `img` tag. You can find (and add) formatting functions in the `core/utils/Format.ts` file.
66
- - Writing for properties that are in camel case. Convert everything to lowercase and add hyphens. Note that `innerHTML` (or `outerHTML`) is a special case where no hyphens are added between each letter.
67
-
68
- **Note:** Data binding implies that updating the `img.src` data via the publisher will change the photo without any additional calls.
69
-
70
- **Special Variables:**
71
- - `_self_` targets the root of the data. This is useful, for example, when the data is a pure string.
72
- - `_parent_` targets the parent publisher of the current publisher, if any. For example, the subscribers of lists have the complete data of the list as their parent.
73
- - `_metadata_` is only used in the case of *sonic-list* at the moment. In a simple list, `_metadata_` see the (list)[] component for further details
74
-
75
- **Disabling this functionality:**
76
- You can disable data binding if it is not needed by calling `DataBinding.disable()`.
@@ -1,78 +0,0 @@
1
- # @ancestorAttribute
2
-
3
- The `@ancestorAttribute` decorator automatically injects the value of an ancestor's attribute into a class property at the time of `connectedCallback`.
4
-
5
- ## Principle
6
-
7
- This decorator uses `HTML.getAncestorAttributeValue` to traverse up the DOM tree from the current element and find the first ancestor that has the specified attribute. The value of this attribute is then assigned to the decorated property.
8
-
9
- ## Usage
10
-
11
- ### Import
12
-
13
- <sonic-code language="typescript">
14
- <template>
15
- import { ancestorAttribute } from "@supersoniks/concorde/decorators";
16
- </template>
17
- </sonic-code>
18
-
19
- ### Basic example
20
-
21
- The component reads `dataProvider` and `testAttribute` from its ancestor wrapper.
22
-
23
- <sonic-code language="typescript">
24
- <template>
25
- import { html, LitElement } from "lit";
26
- import { customElement } from "lit/decorators.js";
27
- import { ancestorAttribute } from "@supersoniks/concorde/decorators";
28
- //
29
- @customElement("demo-ancestor-attribute")
30
- export class DemoAncestorAttribute extends LitElement {
31
- @ancestorAttribute("dataProvider")
32
- dataProvider: string | null = null;
33
- //
34
- @ancestorAttribute("testAttribute")
35
- testAttribute: string | null = null;
36
- //
37
- render() {
38
- return html`
39
- <section>
40
- <p>dataProvider: <strong>${this.dataProvider || "null"}</strong></p>
41
- <p>testAttribute: <strong>${this.testAttribute || "null"}</strong></p>
42
- </section>
43
- `;
44
- }
45
- }
46
- </template>
47
- </sonic-code>
48
-
49
- <sonic-code>
50
- <template>
51
- <div dataProvider="demoDataProvider" testAttribute="test-value-123">
52
- <demo-ancestor-attribute></demo-ancestor-attribute>
53
- </div>
54
- </template>
55
- </sonic-code>
56
-
57
-
58
- ## Use cases
59
-
60
- This decorator is particularly useful for:
61
-
62
- - **Retrieving the `dataProvider`** from an ancestor without having to pass it explicitly
63
- - **Retrieving the `formDataProvider`** in form components
64
- - **Retrieving the `wordingProvider`** for translation
65
- - **Retrieving any other attribute** defined on an ancestor
66
-
67
- ## Behavior
68
-
69
- - The search starts from the current element and traverses up the DOM tree
70
- - If the attribute is not found, the property will be assigned `null`
71
- - The injection happens automatically at the time of `connectedCallback`
72
- - The value is not reactive: it is only updated once when the element is connected to the DOM
73
-
74
- ## Notes
75
-
76
- - This decorator works with any component that has a `connectedCallback` method (such as `LitElement` or components extending `Subscriber`)
77
- - The search also traverses Shadow DOM if necessary
78
- - If multiple ancestors have the attribute, the closest one will be used
@@ -1,199 +0,0 @@
1
- # @autoSubscribe
2
-
3
- The `@autoSubscribe` decorator automatically detects which publishers are accessed within a method and subscribes to them. When any of these publishers change, the method is automatically re-executed.
4
-
5
- ## Principle
6
-
7
- This decorator wraps a method to track which publishers are accessed during its execution. It then subscribes to all accessed publishers, and when any of them change, the method is re-executed. This provides automatic reactivity without manually managing subscriptions.
8
-
9
- ## Usage
10
-
11
- ### Import
12
-
13
- <sonic-code language="typescript">
14
- <template>
15
- import { autoSubscribe } from "@supersoniks/concorde/decorators";
16
- </template>
17
- </sonic-code>
18
-
19
- ### Basic example
20
-
21
-
22
- <sonic-code language="typescript">
23
- <template>
24
- @customElement("demo-auto-subscribe")
25
- export class DemoAutoSubscribe extends LitElement {
26
- static styles = [tailwind];
27
- //
28
- @state() displayText: string = "";
29
- @state() computedValue: number = 0;
30
- //
31
- @autoSubscribe()
32
- updateDisplay() {
33
- const value1 = PublisherManager.get("autoValue1").get() || 0;
34
- const value2 = PublisherManager.get("autoValue2").get() || 0;
35
- this.computedValue = value1 + value2;
36
- this.displayText = `${value1} + ${value2} = ${this.computedValue}`;
37
- }
38
- //
39
- render() {
40
- return html`
41
- <p><strong>${this.displayText}</strong></p>
42
- <div>
43
- <sonic-button @click=${() => this.randomizeValue("autoValue1")}>
44
- Randomize Value 1
45
- </sonic-button>
46
- <sonic-button @click=${() => this.randomizeValue("autoValue2")}>
47
- Randomize Value 2
48
- </sonic-button>
49
- </div>
50
- `;
51
- }
52
- //
53
- randomizeValue(publisherId: string) {
54
- const value = PublisherManager.get(publisherId);
55
- value.set(Math.floor(Math.random() * 100));
56
- }
57
- }
58
- </template>
59
- </sonic-code>
60
-
61
-
62
- <sonic-code >
63
- <template>
64
- <demo-auto-subscribe></demo-auto-subscribe>
65
- </template>
66
- </sonic-code>
67
-
68
- ### Example with render method
69
-
70
- <sonic-code language="typescript">
71
- <template>
72
- @customElement("reactive-view")
73
- export class ReactiveView extends LitElement {
74
- @autoSubscribe()
75
- render() {
76
- const data = PublisherManager.get("myData");
77
- const config = PublisherManager.get("config");
78
- //
79
- // This render method will be automatically re-executed
80
- // when myData or config change
81
- const value = data.get()?.value || 0;
82
- const multiplier = config.get()?.multiplier || 1;
83
- //
84
- return html`
85
- <div>
86
- <h1>Result: ${value * multiplier}</h1>
87
- <p>Value: ${value}</p>
88
- <p>Multiplier: ${multiplier}</p>
89
- </div>
90
- `;
91
- }
92
- }
93
- </template>
94
- </sonic-code>
95
-
96
- ## How it works
97
-
98
- 1. **First execution**: When the method is called, `PublisherManager.collectModifiedPublisher()` is used to track which publishers are accessed
99
- 2. **Subscription**: After execution, the decorator subscribes to all detected publishers
100
- 3. **Re-execution**: When any subscribed publisher changes, the method is automatically called again
101
- 4. **Cleanup**: On `disconnectedCallback`, all subscriptions are automatically removed
102
-
103
- ## Behavior
104
-
105
- - The method is automatically called on `connectedCallback`
106
- - The method is re-executed whenever any accessed publisher changes
107
- - Subscriptions are managed automatically (no manual cleanup needed)
108
- - Only publishers accessed during method execution are subscribed to
109
- - The decorator uses `queueMicrotask` to batch multiple updates and avoid unnecessary re-renders
110
-
111
- ## Use cases
112
-
113
- This decorator is particularly useful for:
114
-
115
- - **Reactive rendering** where the render method depends on multiple publishers
116
- - **Data transformation** that needs to update when source data changes
117
- - **Computed properties** that depend on multiple data sources
118
- - **Automatic synchronization** between publishers and component state
119
-
120
- ## Complete example
121
-
122
- <sonic-code language="typescript">
123
- <template>
124
- import { html, LitElement } from "lit";
125
- import { customElement } from "lit/decorators.js";
126
- import { autoSubscribe } from "@supersoniks/concorde/decorators";
127
- import { PublisherManager } from "@supersoniks/concorde/core/utils/PublisherProxy";
128
- //
129
- @customElement("shopping-cart")
130
- export class ShoppingCart extends LitElement {
131
- items: any[] = [];
132
- total: number = 0;
133
- discount: number = 0;
134
- //
135
- @autoSubscribe()
136
- calculateTotal() {
137
- const cart = PublisherManager.get("cart");
138
- const promo = PublisherManager.get("promo");
139
- //
140
- // Access cart items
141
- this.items = cart.items.get() || [];
142
- //
143
- // Access promo code
144
- const promoCode = promo.code.get() || "";
145
- const discountPercent = promoCode === "SAVE10" ? 0.1 : 0;
146
- //
147
- // Calculate totals
148
- const subtotal = this.items.reduce((sum, item) =>
149
- sum + (item.price * item.quantity), 0
150
- );
151
- this.discount = subtotal * discountPercent;
152
- this.total = subtotal - this.discount;
153
- //
154
- this.requestUpdate();
155
- }
156
- //
157
- connectedCallback() {
158
- super.connectedCallback();
159
- this.calculateTotal();
160
- }
161
- //
162
- render() {
163
- return html`
164
- <div class="cart">
165
- <h2>Shopping Cart</h2>
166
- ${this.items.map(item => html`
167
- <div>${item.name} x${item.quantity} - ${item.price}€</div>
168
- `)}
169
- <div class="total">
170
- <p>Subtotal: ${this.total + this.discount}€</p>
171
- <p>Discount: -${this.discount}€</p>
172
- <p><strong>Total: ${this.total}€</strong></p>
173
- </div>
174
- </div>
175
- `;
176
- }
177
- }
178
- //
179
- // When you update the publishers, calculateTotal is automatically called:
180
- const cart = PublisherManager.get("cart");
181
- cart.items.set([
182
- { name: "Product 1", price: 10, quantity: 2 },
183
- { name: "Product 2", price: 15, quantity: 1 }
184
- ]);
185
- //
186
- const promo = PublisherManager.get("promo");
187
- promo.code.set("SAVE10");
188
- // calculateTotal will be automatically called and the UI will update
189
- </template>
190
- </sonic-code>
191
-
192
- ## Notes
193
-
194
- - This decorator works with any component that has `connectedCallback` and `disconnectedCallback` methods (such as `LitElement` or components extending `Subscriber`)
195
- - The method is called automatically on `connectedCallback`
196
- - Remember to call `this.requestUpdate()` if you're updating component properties
197
- - The decorator uses debouncing via `queueMicrotask` to prevent excessive re-executions
198
- - For more information about publishers, see the documentation on [Sharing data](#docs/_getting-started/pubsub.md/pubsub)
199
-
@@ -1,164 +0,0 @@
1
- # @bind
2
-
3
- Binds a class property to a path in a publisher. The property updates when publisher data changes.
4
-
5
- For Lit re-renders, also add `@state()` on the same property.
6
-
7
- **See also:** [@subscribe](#docs/_decorators/subscribe.md/subscribe), [@publish](#docs/_decorators/publish.md/publish), [@get](#docs/_decorators/get.md/get).
8
-
9
- ## Principle
10
-
11
- The decorator subscribes via `PublisherManager` using dot notation. Publisher updates flow into the decorated property.
12
-
13
- ## Import
14
-
15
- <sonic-code language="typescript">
16
- <template>
17
- import { bind } from "@supersoniks/concorde/decorators";
18
- </template>
19
- </sonic-code>
20
-
21
- ## Example
22
-
23
- <sonic-code language="typescript">
24
- <template>
25
- @customElement("demo-bind")
26
- export class DemoBind extends LitElement {
27
- static styles = [tailwind];
28
- //
29
- @bind("demoData.firstName")
30
- @state()
31
- firstName = "";
32
- //
33
- @bind("demoData.lastName")
34
- @state()
35
- lastName: string = "";
36
- //
37
- @bind("demoData.count")
38
- @state()
39
- count: number = 0;
40
- //
41
- render() {
42
- return //......
43
- }
44
- //
45
- updateData() {
46
- const demoData = PublisherManager.get("demoData");
47
- const demoUsers = PublisherManager.get("demoUsers");
48
- const randomIndex = Math.floor(Math.random() * demoUsers.get().length);
49
- const randomUser = demoUsers.get()[randomIndex];
50
- demoData.set({
51
- firstName: randomUser.firstName,
52
- lastName: randomUser.lastName,
53
- count: (demoData.count.get() || 0) + 1,
54
- });
55
- }
56
- }
57
- //
58
- </template>
59
- </sonic-code>
60
-
61
- <sonic-code>
62
- <template>
63
- <demo-bind></demo-bind>
64
- </template>
65
- </sonic-code>
66
-
67
- ## `DataProviderKey` (strict typing)
68
-
69
- `@bind` accepts either a string path (legacy) or a `DataProviderKey<T>`. The property type must match `T`. Use `reflect: true` to push local writes back to the publisher (see below). See [DataProviderKey](#docs/_misc/dataProviderKey.md/dataProviderKey).
70
-
71
- <sonic-code language="typescript">
72
- <template>
73
- import { bind } from "@supersoniks/concorde/decorators";
74
- import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
75
- //
76
- type Data = { count: number };
77
- const dataKey = new DataProviderKey<Data>("data");
78
- //
79
- @bind(dataKey.count, { reflect: true })
80
- @state()
81
- count: number = 0;
82
- </template>
83
- </sonic-code>
84
-
85
- ## Reflect (`reflect: true`)
86
-
87
- Two-way sync: reads from the publisher and local assignments call `publisher.set(...)`. An internal guard avoids infinite loops.
88
-
89
- <sonic-code language="typescript">
90
- <template>
91
- @bind("userData.profile.avatarUrl", { reflect: true })
92
- @state()
93
- avatar: string;
94
- </template>
95
- </sonic-code>
96
-
97
- <sonic-code language="typescript">
98
- <template>
99
- @customElement("demo-bind-reflect")
100
- export class DemoBindReflect extends LitElement {
101
- static styles = [tailwind];
102
- //
103
- @bind("bindReflectDemo.count", { reflect: true })
104
- @state()
105
- withReflect: number = 0;
106
- //
107
- @bind("bindReflectDemo.count")
108
- @state()
109
- withoutReflect: number = 0;
110
- //
111
- render() {
112
- return html`
113
- <div class="mb-3">
114
- from publisher : ${sub("bindReflectDemo.count") || 0} <br />
115
- from component with reflect : ${this.withReflect || 0} <br />
116
- from component without reflect : ${this.withoutReflect || 0}
117
- </div>
118
- <sonic-button @click=${() => this.withReflect++}
119
- >Increment with reflect</sonic-button
120
- >
121
- <sonic-button @click=${() => this.withoutReflect++}
122
- >Increment without reflect</sonic-button
123
- >
124
- `;
125
- }
126
- }
127
- //
128
- </template>
129
- </sonic-code>
130
-
131
- <sonic-code toggleCode>
132
- <template>
133
- <demo-bind-reflect></demo-bind-reflect>
134
- </template>
135
- </sonic-code>
136
-
137
- ## Path syntax
138
-
139
- - First segment: data provider id.
140
- - Nested properties: dot notation.
141
- - Arrays: numeric index (`items.0`).
142
-
143
- ### Dynamic paths
144
-
145
- Use `${prop}` or `${this.prop}` inside a **normal string literal** (not a JS template literal with backticks). `@bind` re-subscribes when a reactive dependency changes.
146
-
147
- > Properties referenced in the pattern must be reactive (`@property`, etc.) or you must call `requestUpdate` manually.
148
-
149
- <sonic-code>
150
- <template>
151
- <demo-bind-dynamic></demo-bind-dynamic>
152
- </template>
153
- </sonic-code>
154
-
155
- ## Behavior
156
-
157
- - Subscribes at `connectedCallback`, unsubscribes at `disconnectedCallback`.
158
- - If the path does not exist yet, a publisher may be created with `null`.
159
-
160
- ## Notes
161
-
162
- Works with any component that has the usual DOM lifecycle (`LitElement`, `Subscriber` mixin, etc.).
163
-
164
- Shared data: [Sharing data](#docs/_getting-started/pubsub.md/pubsub).