@llumi/design-system 1.0.1 → 2.1.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 (48) hide show
  1. package/LICENSE +51 -0
  2. package/NOTICE +66 -0
  3. package/README.md +15 -205
  4. package/adopt-global-styles-D9108lqB.js +15 -0
  5. package/base.css +2 -0
  6. package/base.md +59 -0
  7. package/bpmn.md +113 -0
  8. package/bpmn.mjs +5076 -0
  9. package/copy-button.md +128 -0
  10. package/copy-button.mjs +161 -0
  11. package/custom-elements.json +1135 -18
  12. package/download-button.md +106 -0
  13. package/download-button.mjs +177 -0
  14. package/highlighter.md +45 -0
  15. package/highlighter.mjs +403 -0
  16. package/icon-button-BwB11RGC.js +5 -0
  17. package/icons-BaUbjt-v.js +42 -0
  18. package/index-BEhA78nX.js +7733 -0
  19. package/llumi-element-BWRwgzW5.js +22 -0
  20. package/mermaid.md +58 -0
  21. package/mermaid.mjs +254 -0
  22. package/package.json +16 -50
  23. package/review.md +141 -0
  24. package/review.mjs +2044 -0
  25. package/slot-text-mSWBdWBc.js +51 -0
  26. package/theme.css +2 -0
  27. package/dist/review.cjs +0 -172
  28. package/dist/review.css +0 -98
  29. package/dist/review.js +0 -172
  30. package/dist/review.mjs +0 -1710
  31. package/dist/types/components/review/comment-dialog.element.d.ts +0 -29
  32. package/dist/types/components/review/custom-target.utils.d.ts +0 -16
  33. package/dist/types/components/review/default-editor.element.d.ts +0 -19
  34. package/dist/types/components/review/highlight-manager.d.ts +0 -21
  35. package/dist/types/components/review/index.d.ts +0 -8
  36. package/dist/types/components/review/overall-comment-dialog.element.d.ts +0 -22
  37. package/dist/types/components/review/review-bar.element.d.ts +0 -26
  38. package/dist/types/components/review/review.element.d.ts +0 -60
  39. package/dist/types/components/review/review.machine.d.ts +0 -234
  40. package/dist/types/components/review/review.persistence.d.ts +0 -16
  41. package/dist/types/components/review/review.type.d.ts +0 -37
  42. package/dist/types/components/review/selection-comment-icons.element.d.ts +0 -17
  43. package/dist/types/components/review/selection-range.utils.d.ts +0 -6
  44. package/dist/types/components/review/sort-comments.utils.d.ts +0 -6
  45. package/dist/types/index.d.ts +0 -1
  46. package/dist/types/shared/cn.d.ts +0 -2
  47. package/dist/types/shared/icons.d.ts +0 -7
  48. package/dist/types/shared/tailwind-element.d.ts +0 -4
package/LICENSE ADDED
@@ -0,0 +1,51 @@
1
+ @llumi/design-system — LICENSE
2
+ Version 1.0 — Copyright (c) 2026 pAIrprog SAS.
3
+
4
+ This license governs use of the Llumi Design System: the "@llumi/design-system" package and the original web components, source code, styles, assets, build output, and documentation created by pAIrprog SAS and published under it (the "pAIrprog Works", and together with everything in the package, the "Software").
5
+ See Section 5 regarding third-party components. By installing, copying, or using the Software You accept this license; if You do not accept it, do not install or use the Software, and delete any copies in Your possession.
6
+
7
+ 1. DEFINITIONS
8
+ "You" means the individual or entity exercising rights under this license.
9
+ "Use" means to install, load, cache, execute, reproduce, and embed the Software.
10
+ "Modify" means to alter, adapt, translate, or otherwise create a derivative work of the Software's source code. The following are Use, not Modify:
11
+ (i) processing the Software with standard build tooling (bundling, minification, transpilation, tree-shaking, source-map generation, and the like) even if it changes the byte form, provided it does not deliberately alter the runtime behaviour of the components You use; and (ii) composing, wrapping, styling, configuring, or extending the components through their documented interfaces — CSS custom properties, attributes, properties, slots, and events — including using them inside Your own components.
12
+ "Distribute" means to make the Software, or any part of it, available to a third party in a form intended for reuse, further development, or redistribution — for example as a library, package, module, template, component set, or SDK. The following are Use, not Distribute: (i) delivering the Software to the users of Your own website, application, or product as part
13
+ of its normal operation, in any medium (web, desktop, mobile, or embedded); (ii) delivering an application or product into which the Software has been integrated to the customer for whom it was built, provided the Software is not separated out or offered on a standalone basis; and (iii) caching or mirroring the unmodified package on an internal or private registry, proxy, or CI/artifact system for Your own or Your customer's use.
14
+
15
+ 2. LICENSE GRANT
16
+ 2.1 Subject to this license, pAIrprog SAS grants You a worldwide, royalty-free, non-exclusive, non-transferable, non-sublicensable license to Use the unmodified Software for any purpose, including commercial purposes, and to embed it within Your own websites, applications, and products.
17
+ 2.2 End-user execution. pAIrprog additionally grants directly to each person who receives the Software incorporated into Your website, application, or product a royalty-free, non-exclusive right to load, cache, and execute the unmodified Software solely as part of using that website, application, or product. This is a direct grant from pAIrprog, not a sublicense by You, and it survives termination of Your license as to persons who received the Software in good faith before termination.
18
+ 2.3 Patents. pAIrprog grants You a royalty-free, non-exclusive license under pAIrprog's patent claims necessarily infringed by the unmodified Software, limited to Using it as permitted here. This patent license terminates if You initiate or join patent litigation alleging the Software infringes.
19
+
20
+ 3. CONDITIONS AND RESTRICTIONS
21
+ The grant in Section 2 is conditioned on the following. These are conditions on the copyright license: any act outside their scope is unlicensed and infringes pAIrprog's copyright, independent of contract formation. Without pAIrprog's prior written permission, You may NOT:
22
+ (a) Modify the Software or create derivative works of it, except as permitted by the definition of "Modify".
23
+ (b) Distribute, publish, sublicense, sell, resell, rent, or lease the Software (or any part of it) on a standalone basis or as a software-development resource, whether free of charge or for a fee, except as permitted by the definition of "Distribute".
24
+ (c) Intentionally remove, obscure, or alter pAIrprog's copyright, attribution, trademark, or license notices, or represent the Software as Your own work. You must retain the preserved ("/_! ... _/") license banner pAIrprog includes in each distributed file. Where Your build tooling removes source comments, You satisfy this condition by retaining the LICENSE and NOTICE files in Your source repository, or by crediting pAIrprog in Your application's third-party notices or credits.
25
+ (d) Trademarks. This license grants no rights in pAIrprog's trademarks, including "pAIrprog" and "llumi". You may make truthful, nominative references identifying the Software (e.g., "built with the Llumi Design System"), but may not, without prior written permission, (i) use the marks in a way likely to cause confusion as to source, sponsorship, or affiliation, (ii) use them in the name of Your product, service, company, or domain, (iii) incorporate them into Your own marks, or (iv) use them to endorse or promote Your products.
26
+
27
+ 4. OWNERSHIP
28
+ The Software is licensed, not sold. pAIrprog SAS retains all right, title, and interest in and to the pAIrprog Works, including all intellectual property rights. All rights not expressly granted are reserved, subject to Section 5.
29
+
30
+ 5. THIRD-PARTY COMPONENTS
31
+ The package includes or loads third-party open-source components, each licensed under its own terms (listed in the accompanying NOTICE file). This license applies only to the pAIrprog Works and does not modify, supersede, or restrict any rights You have in third-party components under their respective licenses. In case of conflict regarding a third-party component, that component's license governs.
32
+
33
+ 6. TERMINATION
34
+ This license terminates automatically if You breach any term and, where the breach is curable, fail to cure it within 30 days after becoming aware of it; it is automatically reinstated upon timely cure. Termination of Your license does not terminate the end-user execution rights granted under Section 2.2 to persons who received the Software in good faith before termination. Upon termination You must cease all Use of the Software. Sections 4, 5, and 7–9 survive termination.
35
+
36
+ 7. NO WARRANTY
37
+ TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. pAIrprog does not warrant that the Software, or any content-delivery network distributing it, will be available, uninterrupted, or error-free, and has no obligation to provide support, updates, or maintenance.
38
+
39
+ 8. LIMITATION OF LIABILITY
40
+ TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, AND GIVEN THAT THE SOFTWARE IS PROVIDED FREE OF CHARGE, pAIrprog SAS SHALL NOT BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES, OR FOR ANY LOSS OF PROFITS, DATA, OR GOODWILL, ARISING FROM OR RELATED TO THE SOFTWARE OR ITS USE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. NOTHING IN THIS LICENSE EXCLUDES OR LIMITS LIABILITY THAT CANNOT BE EXCLUDED OR LIMITED UNDER APPLICABLE LAW, INCLUDING LIABILITY FOR FRAUD (DOL), GROSS NEGLIGENCE (FAUTE LOURDE), OR DEATH OR PERSONAL INJURY.
41
+
42
+ 9. GENERAL
43
+ 9.1 Governing law and forum. This license is governed by the laws of France, without regard to conflict-of-law principles. The courts of Paris, France have exclusive jurisdiction over disputes, except that nothing in this Section deprives a consumer of the mandatory protections, or the courts, of their country of habitual residence; exclusive Paris jurisdiction applies only to parties acting in a professional capacity.
44
+ 9.2 Severability. If any provision is held invalid or unenforceable, it is limited or severed to the minimum extent necessary and the remaining provisions remain in full force; no single provision was a determining condition of the others.
45
+ 9.3 No waiver. No failure or delay in enforcing any term is a waiver of it.
46
+ 9.4 Assignment. You may not assign this license without pAIrprog's prior written consent, except to a successor to all or substantially all of Your business that assumes Your obligations. pAIrprog may freely assign.
47
+ 9.5 Versions. This license governs the version of the Software with which it is distributed. pAIrprog may release future versions of the Software under different terms; doing so does not revoke the rights granted for versions You have already obtained.
48
+ 9.6 Entire agreement. This license is the entire agreement regarding the Software and supersedes prior understandings.
49
+
50
+ For licensing inquiries, including permissions beyond this license:
51
+ contact@pairprog.io
package/NOTICE ADDED
@@ -0,0 +1,66 @@
1
+ @llumi/design-system — THIRD-PARTY NOTICES
2
+
3
+ The distributed build output (dist/*.mjs) bundles the third-party open-source
4
+ packages listed below. Each is licensed under the MIT License, reproduced in
5
+ full at the end of this file. Their copyright notices are retained here in
6
+ satisfaction of the MIT License's attribution requirement.
7
+
8
+ This file does NOT cover the peer dependencies that @llumi/design-system loads
9
+ at runtime from a CDN (e.g. lit, mermaid, xstate, bpmn-js, d3-selection,
10
+ d3-transition, d3-zoom, refractor, tinykeys, yay-machine, @floating-ui/dom).
11
+ Those are not redistributed by this package; they are fetched directly from
12
+ their own publishers and remain governed by their own licenses.
13
+
14
+ Bundled packages
15
+ -----------------
16
+ - bpmn-moddle@10.0.0
17
+ Copyright (c) 2014 camunda Services GmbH
18
+ https://github.com/bpmn-io/bpmn-moddle
19
+ - character-parser@4.0.0
20
+ Copyright (c) 2013 Forbes Lindesay
21
+ https://github.com/ForbesLindesay/character-parser
22
+ - graph-by-ivan-tulaev@1.0.0-alpha.14
23
+ Copyright (c) 2025 Ivan Tulaev
24
+ https://github.com/IvanTulaev/graph
25
+ - is-expression@4.0.0
26
+ Copyright (c) 2015 Tiancheng "Timothy" Gu
27
+ https://github.com/pugjs/is-expression
28
+ - min-dash@5.0.0
29
+ Copyright (c) 2017-present camunda Services GmbH
30
+ https://github.com/bpmn-io/min-dash
31
+ - acorn@7.4.1
32
+ Copyright (C) 2012-2018 by various contributors (see https://github.com/acornjs/acorn/blob/master/AUTHORS)
33
+ https://github.com/acornjs/acorn
34
+ - moddle@8.1.0
35
+ Copyright (c) 2014-present Camunda Services GmbH
36
+ https://github.com/bpmn-io/moddle
37
+ - moddle-xml@12.0.0
38
+ Copyright (c) 2014-present Camunda Services GmbH
39
+ https://github.com/bpmn-io/moddle-xml
40
+ - object-assign@4.1.1
41
+ Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
42
+ https://github.com/sindresorhus/object-assign
43
+ - saxen@11.0.2
44
+ Copyright (c) 2012 Vopilovskii Konstantin <flash.vkv@gmail.com>
45
+ https://github.com/nikku/saxen
46
+
47
+ ------------------------------------------------------------------------------
48
+ The MIT License (MIT)
49
+
50
+ Permission is hereby granted, free of charge, to any person obtaining a copy
51
+ of this software and associated documentation files (the "Software"), to deal
52
+ in the Software without restriction, including without limitation the rights
53
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
54
+ copies of the Software, and to permit persons to whom the Software is
55
+ furnished to do so, subject to the following conditions:
56
+
57
+ The above copyright notice and this permission notice shall be included in all
58
+ copies or substantial portions of the Software.
59
+
60
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
61
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
62
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
63
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
64
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
65
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
66
+ SOFTWARE.
package/README.md CHANGED
@@ -1,219 +1,29 @@
1
1
  # @llumi/design-system
2
2
 
3
- Framework-agnostic Web Components (built with [Lit](https://lit.dev)) for the llumi
4
- review experience. Wrap any content in `<llumi-review>` and let users attach comments to
5
- whole elements or to text selections, add an overall comment, and submit an approval or a
6
- set of comments.
3
+ ## Import via CDN (jsdelivr)
7
4
 
8
- - **Hybrid DOM** your content stays in the light DOM (so text selection, `Range`s, and
9
- the CSS Custom Highlight API work normally); the review chrome (toolbar, dialogs) renders
10
- in Shadow DOM with its styles encapsulated.
11
- - **Drop-in** — works in plain HTML or any framework that can render custom elements.
12
- - **Per-component** — each component is imported on its own (`@llumi/design-system/review`).
13
- - **Three builds per component** — ESM (the default import), plus single-file UMD and IIFE
14
- bundles for `<script>` / CDN use.
15
-
16
- ## Installation
17
-
18
- ```bash
19
- bun add @llumi/design-system
20
- # or: npm install @llumi/design-system
21
- ```
22
-
23
- `lit` is pulled in automatically as a dependency — no peer install required.
24
-
25
- ## Quick start (ESM)
26
-
27
- ```ts
28
- // Registers <llumi-review> and all of its chrome elements.
29
- // The light-DOM highlight styles are injected automatically on first use —
30
- // no separate CSS import is required.
31
- import "@llumi/design-system/review";
32
- ```
5
+ Each component ships as a self-contained ES module.
33
6
 
34
7
  ```html
35
- <llumi-review default-mode="annotating" bar-position="bottom-center">
36
- <article>
37
- <h1 data-review-id="title">Project Proposal</h1>
38
- <p data-review-selectable="intro">
39
- Select any of this text to leave a comment on the selection…
40
- </p>
41
- </article>
42
- </llumi-review>
43
-
44
8
  <script type="module">
45
- const review = document.querySelector("llumi-review");
46
- review.addEventListener("llumi-review-submit", (e) => {
47
- const { result, clearPersisted } = e.detail;
48
- // ...send `result` to the server, then on success:
49
- clearPersisted();
50
- });
9
+ import "https://cdn.jsdelivr.net/npm/@llumi/design-system@2/<component-name>.mjs";
51
10
  </script>
52
11
  ```
53
12
 
54
- ### `<script>` tag (no bundler)
55
-
56
- ```html
57
- <!-- unpkg / jsDelivr both resolve the IIFE subpath via the package `exports` field -->
58
- <script src="https://unpkg.com/@llumi/design-system/review.js"></script>
59
- <!-- jsDelivr can also take the explicit file path -->
60
- <script src="https://cdn.jsdelivr.net/npm/@llumi/design-system/dist/review.js"></script>
61
- ```
62
-
63
- This single file bundles Lit, registers the `<llumi-review>` element, and exposes a `Llumi`
64
- global. A `require()`-safe UMD/CJS build is also published at `@llumi/design-system/review.cjs`.
65
-
66
- ## Marking up content
13
+ `@2` resolves to the latest v2.
67
14
 
68
- Inside `<llumi-review>`, annotate the elements you want to be reviewable:
15
+ ## Available components
69
16
 
70
- | Attribute | Meaning |
71
- | --- | --- |
72
- | `data-review-id="<id>"` | A **whole-element** comment target. Clicking it (in annotate mode) opens a comment dialog and shows a badge when commented. |
73
- | `data-review-selectable="<id>"` | A region whose **text can be selected** to leave a selection-scoped comment. |
74
-
75
- An element may carry both attributes. The `<id>` values are yours; they are echoed back in
76
- each comment's `targetId`.
77
-
78
- ## Component API
79
-
80
- ### Attributes
81
-
82
- | Attribute | Type | Default | Description |
83
- | --- | --- | --- | --- |
84
- | `bar-position` | `top-left` \| `top-center` \| `top-right` \| `bottom-left` \| `bottom-center` \| `bottom-right` | `bottom-center` | Initial corner for the floating toolbar (which is also draggable). |
85
- | `shortcut` | string ([tinykeys](https://github.com/jamiebuilds/tinykeys) syntax) | `$mod+Shift+M` | Keyboard shortcut that toggles annotate mode. |
86
- | `default-mode` | `idle` \| `annotating` | `idle` | Whether annotate mode is on at mount. |
87
- | `persist` | `string` (attribute) | — | When set to a non-empty value, mirrors the review draft to `localStorage` under that key and restores it on load. A persisted draft takes precedence over `initialData`. Restored selection highlights are painted when annotate mode is active (consistent with how `initialData` behaves). |
88
-
89
- ### Properties (set in JS — complex values)
90
-
91
- | Property | Type | Description |
17
+ | Component | Import path | Docs |
92
18
  | --- | --- | --- |
93
- | `initialData` | `ReviewResult` | Pre-populate existing comments / overall comment. |
94
- | `customTargets` | `CustomTarget[]` | Resolve comment targets from arbitrary selectors (advanced). |
95
-
96
- ### Methods
19
+ | classless theme | `/base.css` | [base.md](https://cdn.jsdelivr.net/npm/@llumi/design-system@2/base.md) |
20
+ | `<llumi-review>` | `/review.mjs` | [review.md](https://cdn.jsdelivr.net/npm/@llumi/design-system@2/review.md) |
21
+ | `<llumi-bpmn>` | `/bpmn.mjs` | [bpmn.md](https://cdn.jsdelivr.net/npm/@llumi/design-system@2/bpmn.md) |
22
+ | `<llumi-mermaid>` | `/mermaid.mjs` | [mermaid.md](https://cdn.jsdelivr.net/npm/@llumi/design-system@2/mermaid.md) |
23
+ | `<llumi-highlighter>` | `/highlighter.mjs` | [highlighter.md](https://cdn.jsdelivr.net/npm/@llumi/design-system@2/highlighter.md) |
24
+ | `<llumi-copy-button>` | `/copy-button.mjs` | [copy-button.md](https://cdn.jsdelivr.net/npm/@llumi/design-system@2/copy-button.md) |
25
+ | `<llumi-download-button>` | `/download-button.mjs` | [download-button.md](https://cdn.jsdelivr.net/npm/@llumi/design-system@2/download-button.md) |
97
26
 
98
- | Method | Description |
99
- | --- | --- |
100
- | `clearPersisted()` | Clears the persisted draft for this element's `persist` key. No-op when `persist` is unset. Call after a confirmed server save. |
101
-
102
- ```ts
103
- const review = document.querySelector("llumi-review");
104
- review.initialData = {
105
- status: "commented",
106
- comments: [{ commentId: "c1", targetId: "title", content: "Tighten this", createdAt: new Date().toISOString() }],
107
- };
108
- ```
109
-
110
- ### Events
111
-
112
- Both events bubble and are composed:
113
-
114
- | Event | Detail type | Fires |
115
- | --- | --- | --- |
116
- | `llumi-review-change` | `ReviewResult` | On every edit (comment added/edited/deleted, overall comment changed). |
117
- | `llumi-review-submit` | `{ result: ReviewResult, clearPersisted: () => void }` | When the user clicks Submit / Approve. `clearPersisted` clears the localStorage draft — call it after a confirmed server save. |
27
+ ## License
118
28
 
119
- ```ts
120
- type ReviewResult =
121
- | { status: "approved" }
122
- | { status: "commented"; comments: ReviewComment[]; overallComment?: string };
123
-
124
- interface ReviewComment {
125
- commentId: string;
126
- targetId: string; // the data-review-id / data-review-selectable value
127
- content: string;
128
- createdAt: string; // ISO timestamp
129
- selection?: { // present for text-selection comments
130
- startOffset: number;
131
- endOffset: number;
132
- selectedText: string;
133
- matchIndex: number;
134
- };
135
- }
136
- ```
137
-
138
- Comments in the result are ordered by their position in the document.
139
-
140
- ### Keyboard shortcuts
141
-
142
- | Keys | Action |
143
- | --- | --- |
144
- | `$mod+Shift+M` (configurable) | Toggle annotate mode |
145
- | Hold `Alt` | Temporarily reveal all targets while held |
146
- | `Escape` / `$mod+Enter` | Close the open dialog |
147
- | `$mod+Shift+Backspace` | Delete the comment being edited |
148
-
149
- (`$mod` is ⌘ on macOS, Ctrl elsewhere.)
150
-
151
- ## Custom comment editor
152
-
153
- The default editor is an auto-growing textarea. To supply your own, slot an element into
154
- the comment dialog's `editor` slot. Your element receives the current text via a `value`
155
- property and must emit these `CustomEvent`s (bubbling + composed):
156
-
157
- - `change` — `detail` is the new string value
158
- - `cancel` — request to close the dialog
159
- - `delete` — request to delete the comment
160
-
161
- ```html
162
- <llumi-comment-dialog>
163
- <my-rich-editor slot="editor"></my-rich-editor>
164
- </llumi-comment-dialog>
165
- ```
166
-
167
- ## Styling & customization
168
-
169
- No CSS setup is required. The chrome (toolbar, dialogs) ships its Tailwind styles inside
170
- each element's Shadow DOM, and the light-DOM highlight styles are injected into the
171
- document automatically when a `<llumi-review>` connects.
172
-
173
- To theme the highlight outlines, selection colors, and z-index, override these CSS custom
174
- properties. Set them on `llumi-review` (or any ancestor of your content) so they reliably
175
- override the injected defaults via inheritance:
176
-
177
- ```css
178
- llumi-review {
179
- /* whole-element outlines */
180
- --review-highlight-commented-color: oklch(0.7 0 0 / 0.3);
181
- --review-highlight-editing-color: oklch(0.6 0 0 / 0.7);
182
- /* text-selection highlights */
183
- --review-selection-commented-color: oklch(0.85 0.08 250 / 0.4);
184
- --review-selection-editing-color: oklch(0.75 0.12 250 / 0.6);
185
- --review-selection-hover-color: oklch(0.8 0.1 250 / 0.5);
186
- /* stacking */
187
- --review-z-index: 9998;
188
- }
189
- ```
190
-
191
- All `--review-*` variables defined in the injected stylesheet are overridable this way.
192
-
193
- ## Package exports
194
-
195
- | Specifier | Build |
196
- | --- | --- |
197
- | `@llumi/design-system/review` | The review component — resolves to ESM on `import`, CJS on `require` (the default entry) |
198
- | `@llumi/design-system/review.mjs` | ESM bundle (explicit) |
199
- | `@llumi/design-system/review.cjs` | UMD / CJS bundle, `require()`-safe (Lit included) |
200
- | `@llumi/design-system/review.js` | IIFE bundle, `Llumi` global (Lit included) |
201
- | `@llumi/design-system/review.css` | Light-DOM highlight styles — optional; only needed to preload them (e.g. SSR / avoid a first-paint flash), since they're otherwise auto-injected |
202
-
203
- ## Known limitation
204
-
205
- Selection highlights use the document-global CSS Custom Highlight API with fixed names, so
206
- only one active `<llumi-review>` paints selection highlights on the page at a time (this
207
- matches the original React component). Whole-element highlights and everything else work
208
- with multiple instances.
209
-
210
- ## Development
211
-
212
- ```bash
213
- bun install
214
- bun run storybook # interactive dev/docs harness
215
- bun test # logic tests (XState machine, utilities)
216
- bun run test:browser # component/DOM tests (Vitest + Playwright)
217
- bun run build # ESM + UMD + IIFE
218
- bun run ci # full gate: lint, types, tests, manifest, build
219
- ```
29
+ Free to use and embed, including commercially; no modification, redistribution, or resale. See [LICENSE](https://cdn.jsdelivr.net/npm/@llumi/design-system@2/LICENSE). Bundled third-party components and their notices are listed in [NOTICE](https://cdn.jsdelivr.net/npm/@llumi/design-system@2/NOTICE).
@@ -0,0 +1,15 @@
1
+ /*! @llumi/design-system v2.1.0 | (c) 2026 pAIrprog SAS | license: https://cdn.jsdelivr.net/npm/@llumi/design-system@2.1.0/LICENSE | bundled third-party components under MIT, see NOTICE | @license */
2
+ const n = /* @__PURE__ */ new Set();
3
+ function r(e, a) {
4
+ if (typeof document > "u" || n.has(e)) return;
5
+ const o = `data-llumi-${e}`;
6
+ if (document.querySelector(`style[${o}]`)) {
7
+ n.add(e);
8
+ return;
9
+ }
10
+ const t = document.createElement("style");
11
+ t.setAttribute(o, ""), t.textContent = a, document.head.append(t), n.add(e);
12
+ }
13
+ export {
14
+ r as a
15
+ };
package/base.css ADDED
@@ -0,0 +1,2 @@
1
+ /*! @llumi/design-system v2.1.0 | (c) 2026 pAIrprog SAS | license: https://cdn.jsdelivr.net/npm/@llumi/design-system@2.1.0/LICENSE | bundled third-party components under MIT, see NOTICE | @license */
2
+ :root{--llumi-white:oklch(100% 0 0);--llumi-zinc-50:oklch(98.5% 0 0);--llumi-zinc-100:oklch(96.7% .001 286.375);--llumi-zinc-200:oklch(92% .004 286.32);--llumi-zinc-300:oklch(87.1% .006 286.286);--llumi-zinc-400:oklch(70.5% .015 286.067);--llumi-zinc-500:oklch(55.2% .016 285.938);--llumi-zinc-700:oklch(37% .013 285.805);--llumi-zinc-800:oklch(27.4% .006 286.033);--llumi-zinc-900:oklch(21% .006 285.885);--llumi-zinc-950:oklch(14.1% .005 285.823);--llumi-purple-100:oklch(94.6% .033 307.174);--llumi-purple-300:oklch(82.7% .119 306.383);--llumi-purple-400:oklch(71.4% .203 305.504);--llumi-purple-600:oklch(55.8% .288 302.321);--llumi-purple-700:oklch(49.6% .265 301.924);--llumi-pink-100:oklch(94.8% .028 342.258);--llumi-pink-600:oklch(59.2% .249 .584);--llumi-pink-700:oklch(52.5% .223 3.958);--llumi-green-100:oklch(96.2% .044 156.743);--llumi-green-600:oklch(62.7% .194 149.214);--llumi-red-100:oklch(93.6% .032 17.717);--llumi-red-600:oklch(57.7% .245 27.325);--llumi-amber-100:oklch(96.2% .059 95.617);--llumi-amber-600:oklch(66.6% .179 58.318);--llumi-color-bg:var(--llumi-zinc-50);--llumi-color-surface:var(--llumi-white);--llumi-color-fg:var(--llumi-zinc-900);--llumi-color-muted:var(--llumi-zinc-500);--llumi-color-border:var(--llumi-zinc-200);--llumi-color-primary:var(--llumi-purple-600);--llumi-color-primary-hover:var(--llumi-purple-700);--llumi-color-primary-subtle:var(--llumi-purple-100);--llumi-color-on-primary:var(--llumi-white);--llumi-color-accent:var(--llumi-pink-600);--llumi-color-accent-subtle:var(--llumi-pink-100);--llumi-color-on-accent:var(--llumi-white);--llumi-color-success:var(--llumi-green-600);--llumi-color-success-subtle:var(--llumi-green-100);--llumi-color-danger:var(--llumi-red-600);--llumi-color-danger-subtle:var(--llumi-red-100);--llumi-color-warning:var(--llumi-amber-600);--llumi-color-warning-subtle:var(--llumi-amber-100);--llumi-color-link:var(--llumi-purple-600);--llumi-color-link-hover:var(--llumi-purple-700);--llumi-color-ring:var(--llumi-color-primary);--llumi-radius-sm:.25rem;--llumi-radius:.5rem;--llumi-radius-lg:.75rem;--llumi-font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji";--llumi-font-mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;--llumi-text-xs:.75rem;--llumi-text-sm:.875rem;--llumi-text-base:1rem;--llumi-text-lg:1.125rem;--llumi-text-xl:1.25rem;--llumi-text-2xl:1.5rem;--llumi-text-3xl:1.875rem;--llumi-text-4xl:2.25rem;--llumi-leading:1.5;--llumi-leading-tight:1.25;--llumi-font-weight-normal:400;--llumi-font-weight-medium:500;--llumi-font-weight-semibold:600;--llumi-font-weight-bold:700;--llumi-space:1rem;--buncss-light:initial;--buncss-dark: ;color-scheme:light}[data-theme=dark]{--llumi-color-bg:var(--llumi-zinc-950);--llumi-color-surface:var(--llumi-zinc-900);--llumi-color-fg:var(--llumi-zinc-50);--llumi-color-muted:var(--llumi-zinc-400);--llumi-color-border:var(--llumi-zinc-800);--llumi-color-link:var(--llumi-purple-400);--llumi-color-link-hover:var(--llumi-purple-300);--buncss-light: ;--buncss-dark:initial;color-scheme:dark}[data-theme=light]{--llumi-color-bg:var(--llumi-zinc-50);--llumi-color-surface:var(--llumi-white);--llumi-color-fg:var(--llumi-zinc-900);--llumi-color-muted:var(--llumi-zinc-500);--llumi-color-border:var(--llumi-zinc-200);--llumi-color-link:var(--llumi-purple-600);--llumi-color-link-hover:var(--llumi-purple-700);--buncss-light:initial;--buncss-dark: ;color-scheme:light}@media (prefers-color-scheme:dark){:root:not([data-theme=light]){--llumi-color-bg:var(--llumi-zinc-950);--llumi-color-surface:var(--llumi-zinc-900);--llumi-color-fg:var(--llumi-zinc-50);--llumi-color-muted:var(--llumi-zinc-400);--llumi-color-border:var(--llumi-zinc-800);--llumi-color-link:var(--llumi-purple-400);--llumi-color-link-hover:var(--llumi-purple-300);--buncss-light: ;--buncss-dark:initial;color-scheme:dark}}:where(html){font-family:var(--llumi-font-sans);line-height:var(--llumi-leading);-webkit-text-size-adjust:100%}:where(body){background:var(--llumi-color-bg);color:var(--llumi-color-fg);font-size:var(--llumi-text-base);line-height:var(--llumi-leading);margin:0}:where(h1,h2,h3,h4,h5,h6){margin:0 0 var(--llumi-space);line-height:var(--llumi-leading-tight);font-weight:var(--llumi-font-weight-semibold);color:var(--llumi-color-fg)}:where(h1){font-size:var(--llumi-text-4xl)}:where(h2){font-size:var(--llumi-text-3xl)}:where(h3){font-size:var(--llumi-text-2xl)}:where(h4){font-size:var(--llumi-text-xl)}:where(h5){font-size:var(--llumi-text-lg)}:where(h6){font-size:var(--llumi-text-base)}:where(p,ul,ol,dl,blockquote,pre,table,figure){margin:0 0 var(--llumi-space)}:where(a){color:var(--llumi-color-link);text-decoration:underline;text-underline-offset:2px}:where(a:hover){color:var(--llumi-color-link-hover)}:where(strong,b){font-weight:var(--llumi-font-weight-semibold)}:where(small){font-size:var(--llumi-text-sm)}:where(mark){background:var(--llumi-color-warning-subtle);color:var(--llumi-color-fg);border-radius:var(--llumi-radius-sm);padding:0 .2em}:where(ul,ol){padding-left:1.5rem}:where(li){margin:.25rem 0}:where(blockquote){border-left:3px solid var(--llumi-color-border);padding-left:var(--llumi-space);color:var(--llumi-color-muted)}:where(hr){border:0;border-top:1px solid var(--llumi-color-border);margin:calc(var(--llumi-space)*1.5)0}:where(code,kbd,samp){font-family:var(--llumi-font-mono);font-size:.9em}:where(code){background:var(--llumi-color-surface);border:1px solid var(--llumi-color-border);border-radius:var(--llumi-radius-sm);padding:.1em .35em}:where(pre){background:var(--llumi-color-surface);border:1px solid var(--llumi-color-border);border-radius:var(--llumi-radius);padding:var(--llumi-space);overflow:auto}:where(pre) :where(code){background:0 0;border:0;padding:0}:where(kbd){background:var(--llumi-color-surface);border:1px solid var(--llumi-color-border);border-radius:var(--llumi-radius-sm);padding:.1em .4em}:where(table){border-collapse:collapse;width:100%}:where(caption){text-align:left;color:var(--llumi-color-muted);padding-bottom:.5rem}:where(th,td){text-align:left;border-bottom:1px solid var(--llumi-color-border);padding:.5rem .75rem}:where(th){font-weight:var(--llumi-font-weight-semibold)}:where(input,textarea,select){font:inherit;color:var(--llumi-color-fg);background:var(--llumi-color-surface);border:1px solid var(--llumi-color-border);border-radius:var(--llumi-radius);padding:.5rem .75rem}:where(input:focus-visible,textarea:focus-visible,select:focus-visible){outline:2px solid var(--llumi-color-ring);outline-offset:1px}:where(button){font:inherit;font-weight:var(--llumi-font-weight-medium);color:var(--llumi-color-on-primary);background:var(--llumi-color-primary);border-radius:var(--llumi-radius);cursor:pointer;border:1px solid #0000;padding:.5rem 1rem}:where(button:hover){background:var(--llumi-color-primary-hover)}:where(button:focus-visible){outline:2px solid var(--llumi-color-ring);outline-offset:1px}:where(button:has(>i:only-child)){box-sizing:border-box;display:inline-flex;border:1px solid var(--llumi-color-border,#e4e4e7);border-radius:var(--llumi-radius,.5rem);background:var(--llumi-color-surface,#fff);color:var(--llumi-color-fg,#18181b);cursor:pointer;appearance:none;justify-content:center;align-items: center;width:2.25rem;height:2.25rem;padding:0;transition:background-color .15s,color .15s,border-color .15s}@supports (color:color(display-p3 0 0 0)){:where(button:has(>i:only-child)){border:1px solid var(--llumi-color-border,color(display-p3 .894477 .894477 .905114));background:var(--llumi-color-surface,color(display-p3 1 1 1));color:var(--llumi-color-fg,color(display-p3 .0937957 .093793 .104806))}}@supports (color:lab(0% 0 0)){:where(button:has(>i:only-child)){border:1px solid var(--llumi-color-border,lab(90.6853% .399262 -1.45453));background:var(--llumi-color-surface,lab(100% 0 0));color:var(--llumi-color-fg,lab(8.30603% .618212 -2.16573))}}:where(button:has(>i:only-child):hover:not(:disabled)){background:color-mix(in oklab,var(--llumi-color-fg,#18181b)6%,transparent)}@supports (color:color(display-p3 0 0 0)){:where(button:has(>i:only-child):hover:not(:disabled)){background:color-mix(in oklab,var(--llumi-color-fg,color(display-p3 .0937957 .093793 .104806))6%,transparent)}}@supports (color:lab(0% 0 0)){:where(button:has(>i:only-child):hover:not(:disabled)){background:color-mix(in oklab,var(--llumi-color-fg,lab(8.30603% .618212 -2.16573))6%,transparent)}}:where(button:has(>i:only-child):focus-visible){outline:2px solid var(--llumi-color-ring,oklch(55.8% .288 302.321));outline-offset:2px}:where(button:has(>i:only-child):disabled){opacity:.6;cursor:default}:where(button:has(>i:only-child)>i){display:inline-flex;width:1rem;height:1rem}:where(button:has(>i:only-child)>i>svg){width:100%;height:100%}:where(button.is-done:has(>i:only-child)){border-color:var(--llumi-color-success,#00a544);color:var(--llumi-color-success,#00a544)}@supports (color:color(display-p3 0 0 0)){:where(button.is-done:has(>i:only-child)){border-color:var(--llumi-color-success,color(display-p3 .243883 .640824 .294808));color:var(--llumi-color-success,color(display-p3 .243883 .640824 .294808))}}@supports (color:lab(0% 0 0)){:where(button.is-done:has(>i:only-child)){border-color:var(--llumi-color-success,lab(59.0978% -58.6621 41.2579));color:var(--llumi-color-success,lab(59.0978% -58.6621 41.2579))}}:where(button.is-error:has(>i:only-child)){border-color:var(--llumi-color-danger,#e40014);color:var(--llumi-color-danger,#e40014)}@supports (color:color(display-p3 0 0 0)){:where(button.is-error:has(>i:only-child)){border-color:var(--llumi-color-danger,color(display-p3 .830323 .140383 .133196));color:var(--llumi-color-danger,color(display-p3 .830323 .140383 .133196))}}@supports (color:lab(0% 0 0)){:where(button.is-error:has(>i:only-child)){border-color:var(--llumi-color-danger,lab(48.4493% 77.4328 61.5452));color:var(--llumi-color-danger,lab(48.4493% 77.4328 61.5452))}}:where(button.is-working:has(>i:only-child)>i>svg){animation:llumi-spin 1s linear infinite}@keyframes llumi-spin{to{transform:rotate(360deg)}}:where(label){display:inline-block;font-weight:var(--llumi-font-weight-medium)}:where(fieldset){border:1px solid var(--llumi-color-border);border-radius:var(--llumi-radius);padding:var(--llumi-space)}:where(legend){padding:0 .5rem}:where(img,svg,video){max-width:100%;height:auto}:where(figure){margin-inline-start:0;margin-inline-end:0}:where(figcaption){color:var(--llumi-color-muted);font-size:var(--llumi-text-sm)}
package/base.md ADDED
@@ -0,0 +1,59 @@
1
+ # `base.css`
2
+
3
+ A classless base stylesheet that applies sensible defaults to plain HTML elements — typography, spacing, tables, forms, buttons, code blocks, blockquotes, and icon-buttons. Every rule is `:where()`-wrapped (specificity 0), so any consumer class, utility, or inline style always wins.
4
+
5
+ It imports `theme.css` automatically, so a single import gives you both the design tokens and the element defaults.
6
+
7
+ ## Import
8
+
9
+ ```html
10
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@llumi/design-system@2/base.css" />
11
+ ```
12
+
13
+ Or in JS:
14
+
15
+ ```ts
16
+ import "@llumi/design-system/base.css";
17
+ ```
18
+
19
+ ## What it covers
20
+
21
+ - **Typography** — font family, sizing, line-height for `html`, headings `h1`–`h6`, paragraphs, lists
22
+ - **Links** — color + underline offset (hover state)
23
+ - **Code** — `code`, `pre`, `kbd`, `samp` with surface background and borders
24
+ - **Tables** — full width, collapsed borders, padded cells
25
+ - **Forms** — `input`, `textarea`, `select`, `button`, `fieldset`, `legend` with focus rings
26
+ - **Icon buttons** — any `<button>` whose only child is an `<i>` icon gets square sizing + hover/focus/disabled states
27
+ - **Misc** — `blockquote`, `hr`, `mark`, `figure`/`figcaption`, responsive media
28
+
29
+ ## Overriding theme variables
30
+
31
+ All defaults consume `--llumi-*` custom properties. Override them on `:root` (or any ancestor) to retheme:
32
+
33
+ ```css
34
+ :root {
35
+ /* Brand colors */
36
+ --llumi-color-primary: oklch(55% 0.25 250);
37
+ --llumi-color-primary-hover: oklch(48% 0.22 250);
38
+
39
+ /* Surfaces */
40
+ --llumi-color-bg: oklch(98% 0 0);
41
+ --llumi-color-surface: oklch(100% 0 0);
42
+ --llumi-color-fg: oklch(20% 0 0);
43
+ --llumi-color-muted: oklch(50% 0 0);
44
+ --llumi-color-border: oklch(90% 0 0);
45
+
46
+ /* Shape */
47
+ --llumi-radius: 0.375rem;
48
+ --llumi-radius-sm: 0.25rem;
49
+
50
+ /* Typography */
51
+ --llumi-font-sans: "Inter", sans-serif;
52
+ --llumi-text-base: 1.05rem;
53
+ --llumi-leading: 1.6;
54
+ }
55
+ ```
56
+
57
+ Dark mode is handled via `[data-theme="dark"]` or `prefers-color-scheme: dark` — only neutral surfaces remap; brand and status colors stay constant. Force a mode with `data-theme="light"` or `data-theme="dark"` on `<html>`.
58
+
59
+ See [`theme.css`](./theme.css) for the full token list.
package/bpmn.md ADDED
@@ -0,0 +1,113 @@
1
+ # `<llumi-bpmn>`
2
+
3
+ Renders a [BPMN 2.0](https://www.omg.org/spec/BPMN/2.0/) diagram from a pug-syntax definition string,
4
+ with automatic layout, interactive pan/zoom, element markers (highlight, focus, errors, warnings),
5
+ and click-to-select events.
6
+
7
+ ## Usage
8
+
9
+ Pass the BPMN definition as the element's **light-DOM text content** (slot):
10
+
11
+ ```html
12
+ <llumi-bpmn>
13
+ doctype xml
14
+ definitions(id="defs1" targetNamespace="http://example.com/simple")
15
+ process(id="proc1" name="Simple Process" isExecutable="true")
16
+ startEvent(id="start1")
17
+ task(id="task1" name="Do Something")
18
+ endEvent(id="end1")
19
+ sequenceFlow(id="f1" sourceRef="start1" targetRef="task1")
20
+ sequenceFlow(id="f2" sourceRef="task1" targetRef="end1")
21
+ </llumi-bpmn>
22
+ ```
23
+
24
+ The diagram source is re-read whenever the text content changes. Whitespace is
25
+ automatically trimmed and dedented.
26
+
27
+ ## Properties / Attributes
28
+
29
+ | Name | Attribute | Type | Default | Description |
30
+ |------|-----------|------|---------|-------------|
31
+ | `autoLayout` | `auto-layout` | `boolean` | `true` | Run the built-in layout engine to assign positions. Default is **true** because the pug syntax carries no position data (no BPMNDiagram / Bounds section needed). Set to `false` only when the source already contains a `bpmndi:BPMNDiagram` section with explicit coordinates. |
32
+ | `highlight` | — | `string[]` | `[]` | IDs of elements to highlight (blue tint). |
33
+ | `focusId` | — | `string \| undefined` | `undefined` | ID of the element that receives the focus marker (strong blue border). Named `focusId` rather than `focus` because a `focus` property would shadow the native `HTMLElement.focus()` method. |
34
+ | `errors` | — | `string[]` | `[]` | IDs of elements to mark as errors (red tint). |
35
+ | `warnings` | — | `string[]` | `[]` | IDs of elements to mark as warnings (orange tint). |
36
+ | `centerOn` | — | `string \| undefined` | `undefined` | ID of the element to animate the viewport to. Animates with a smooth ease-out transition each time the value changes. |
37
+
38
+ ### `auto-layout` details
39
+
40
+ The pug syntax intentionally omits layout information. The `pugToXml` parser
41
+ auto-injects `<incoming>` / `<outgoing>` child elements from `sequenceFlow`
42
+ `sourceRef`/`targetRef` attributes so the layout engine has the graph structure it
43
+ needs. You do not need to include a `bpmndi:BPMNDiagram` section, any `Bounds`
44
+ elements, or a `collaboration` wrapper.
45
+
46
+ ## Events
47
+
48
+ | Event | Detail | Bubbles | Composed | When |
49
+ |-------|--------|---------|----------|------|
50
+ | `llumi-bpmn-select` | `{ type: string; id: string }` | yes | yes | User clicks a BPMN element (task, gateway, event, flow, etc.). |
51
+ | `llumi-bpmn-deselect` | — | yes | yes | User clicks the process or collaboration root (background click — deselects any selection). |
52
+
53
+ Both events cross shadow-DOM boundaries (`composed: true`) so parent documents
54
+ can listen on a regular ancestor element.
55
+
56
+ ```js
57
+ diagram.addEventListener("llumi-bpmn-select", (e) => {
58
+ console.log(e.detail.type, e.detail.id);
59
+ });
60
+ diagram.addEventListener("llumi-bpmn-deselect", () => {
61
+ console.log("deselected");
62
+ });
63
+ ```
64
+
65
+ ## CSS Parts
66
+
67
+ | Part | Description |
68
+ |------|-------------|
69
+ | `fit-button` | The fit-to-viewport button shown in the top-right toolbar when the diagram renders successfully. |
70
+ | `error` | The error box shown when the BPMN definition fails to parse or import. |
71
+
72
+ ## Styling
73
+
74
+ bpmn-js base CSS (`bpmn-js.css`, `diagram-js.css`) and the element-marker CSS are
75
+ **automatically injected** into the document when the component connects. No CSS
76
+ import is required from the consumer.
77
+
78
+ ## Interaction
79
+
80
+ - **Pan:** two-finger scroll (trackpad) / left-drag.
81
+ - **Zoom:** pinch (trackpad) or ctrl+wheel / scroll.
82
+ - **Fit:** the top-right button resets the viewport to fit all elements.
83
+ - **Auto-fit:** the diagram fits its container on load and re-fits when the
84
+ container resizes — until you pan or zoom, after which your view is preserved
85
+ (clicking fit re-enables auto-fit).
86
+ - **Click element:** fires `llumi-bpmn-select`.
87
+ - **Click background:** fires `llumi-bpmn-deselect`.
88
+
89
+ ## Dependencies
90
+
91
+ `bpmn-js`, `bpmn-moddle`, `character-parser`, `is-expression`, `min-dash`, `graph-by-ivan-tulaev`. The component lazy-loads the bpmn-js viewer on
92
+ first render for optimal bundle size.
93
+
94
+ Consume via:
95
+
96
+ ```js
97
+ import "@llumi/design-system/bpmn";
98
+ ```
99
+
100
+ ## Known limitations
101
+
102
+ - **Auto-layout + data objects in a collaboration.** When `auto-layout` is on,
103
+ the layout engine cannot place `dataObject`/`dataObjectReference` elements that
104
+ live inside a process belonging to a collaboration (a process with pools) — it
105
+ throws `Element <id> is not associated with any leaf in lane tree`. Data objects
106
+ in a standalone (non-collaboration) process lay out fine. To show data objects
107
+ inside pools, supply pre-computed `bpmndi:` coordinates and set `auto-layout`
108
+ off.
109
+
110
+ ## Pug schema reference
111
+
112
+ See [`bpmn-specifications.md`](./bpmn-specifications.md) for the full pug-syntax
113
+ schema covering all BPMN 2.0 element types, attributes, and nesting rules.