@supersoniks/concorde 4.9.4 → 4.9.6

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.
@@ -24,6 +24,20 @@ class HTML {
24
24
  }, {});
25
25
  }
26
26
 
27
+ /**
28
+ * Ancêtre suivant dans l'arbre composé : slot de projection, sinon parentNode / shadow host.
29
+ * Nécessaire pour trouver un scroller/clipper dans le shadow d'un ancêtre (ex. #modal.custom-scroll).
30
+ */
31
+ static nextComposedAncestor(
32
+ node: SearchableDomElement,
33
+ ): SearchableDomElement | null {
34
+ if (node instanceof Element && node.assignedSlot) {
35
+ return node.assignedSlot;
36
+ }
37
+ const parent = node.parentNode || (node as ShadowRoot).host;
38
+ return (parent as SearchableDomElement) || null;
39
+ }
40
+
27
41
  static everyAncestors(
28
42
  node: SearchableDomElement,
29
43
  callback: (node: SearchableDomElement) => /*continue ?*/ boolean
@@ -36,29 +50,50 @@ class HTML {
36
50
  }
37
51
  }
38
52
 
39
- static getScrollableAncestor(node: SearchableDomElement) {
40
- //Based on overflow-y: auto, overflow-y: scroll, overflow-y: hidden
41
- while (node) {
42
- const htmlNode = node as HTMLElement;
43
- if (htmlNode.nodeType === 1) {
44
- const style = window.getComputedStyle(htmlNode);
45
- if (
46
- style?.overflowY === "auto" ||
47
- style?.overflowY === "scroll" ||
48
- style?.overflowY === "hidden" ||
49
- style?.overflowX === "auto" ||
50
- style?.overflowX === "scroll" ||
51
- style?.overflowX === "hidden"
52
- ) {
53
- return node;
53
+ private static overflowMatches(
54
+ style: CSSStyleDeclaration,
55
+ values: readonly string[],
56
+ ): boolean {
57
+ return values.includes(style.overflowY) || values.includes(style.overflowX);
58
+ }
59
+
60
+ private static findAncestorByOverflow(
61
+ node: SearchableDomElement,
62
+ overflowValues: readonly string[],
63
+ ): SearchableDomElement | null {
64
+ let current: SearchableDomElement | null = node;
65
+ while (current) {
66
+ if (current instanceof Element && current.nodeType === 1) {
67
+ const style = window.getComputedStyle(current);
68
+ if (HTML.overflowMatches(style, overflowValues)) {
69
+ return current;
54
70
  }
55
71
  }
56
- node = (node.parentNode ||
57
- (node as ShadowRoot).host) as SearchableDomElement;
72
+ current = HTML.nextComposedAncestor(current);
58
73
  }
59
74
  return null;
60
75
  }
61
76
 
77
+ /**
78
+ * Ancêtre qui clippe (inclut overflow:hidden) — ex. clamp de sonic-pop.
79
+ * Reconnaît aussi overflow:overlay (.custom-scroll) et traverse les slots.
80
+ */
81
+ static getScrollableAncestor(node: SearchableDomElement) {
82
+ return HTML.findAncestorByOverflow(node, [
83
+ "auto",
84
+ "scroll",
85
+ "hidden",
86
+ "overlay",
87
+ ]);
88
+ }
89
+
90
+ /**
91
+ * Ancêtre réellement scrollable (pas overflow:hidden) — ex. restore scroll Safari de sonic-queue.
92
+ */
93
+ static getScrollingAncestor(node: SearchableDomElement) {
94
+ return HTML.findAncestorByOverflow(node, ["auto", "scroll", "overlay"]);
95
+ }
96
+
62
97
  /** Noms d'attribut DOM à tester (Lit reflect → minuscules, ex. serviceURL → serviceurl). */
63
98
  static scopeAttributeNames(attributeName: string): string[] {
64
99
  const lower = attributeName.toLowerCase();
@@ -29,7 +29,7 @@ node node_modules/@supersoniks/concorde/scripts/ai-init.mjs
29
29
  | `--skip-agents` | Never write `AGENTS.md` (skills / rules only) |
30
30
  | `--merge-agents` | Opt-in: keep the project preamble and append / refresh the Concorde block |
31
31
  | `--force-agents` | Opt-in: **replace** the whole `AGENTS.md` (destructive) |
32
- | `--overlay <dir>` | Extra rules/skills + optional `AGENTS.starter.md` for project-only agent notes |
32
+ | `--overlay <dir>` | Extra rules/skills + optional `AGENTS.concorde.md` for project-only Concorde agent notes |
33
33
  | `--cursor-only` | Install only `.cursor/skills` and `.cursor/rules` |
34
34
  | `--jetbrains-only` | Install only `.aiassistant/rules/` |
35
35
 
@@ -46,10 +46,10 @@ node node_modules/@supersoniks/concorde/scripts/ai-init.mjs
46
46
  [optional project preamble — short, project-only]
47
47
  <!-- concorde-ai -->
48
48
  <package ai/AGENTS.md>
49
- [--- + overlay AGENTS.starter.md]
49
+ [--- + overlay AGENTS.concorde.md]
50
50
  ```
51
51
 
52
- Everything **after** `<!-- concorde-ai -->` is replaced on each `ai-init` run (idempotent). Do not paste a full copy of the Concorde guide above the marker — put project-specific notes in `AGENTS.starter.md` (overlay). If the preamble duplicates package `AGENTS.md`, `ai-init` slims or drops it and prints a warning.
52
+ Everything **after** `<!-- concorde-ai -->` is replaced on each `ai-init` run (idempotent). Do not paste a full copy of the Concorde guide above the marker — put project-specific notes in `AGENTS.concorde.md` (overlay). If the preamble duplicates package `AGENTS.md`, `ai-init` slims or drops it and prints a warning. Legacy filenames `AGENTS.overlay.md` / `AGENTS.starter.md` are still accepted with a deprecation warning.
53
53
 
54
54
  ## What gets installed
55
55
 
package/src/docs/code.ts CHANGED
File without changes
@@ -350,14 +350,19 @@
350
350
  "core/components/functional/queue/queue.md": {
351
351
  "title": "Queue",
352
352
  "hashes": {
353
- "lazy-load--offset-and-limit": {
353
+ "lazy-load": {
354
354
  "count": 1,
355
- "title": "Lazy load — `$offset` and `$limit`",
355
+ "title": "Lazy load",
356
356
  "type": "paragraph"
357
357
  },
358
- "simple-batch-no-lazy-scroll": {
358
+ "manual-next-signal--supplement": {
359
359
  "count": 1,
360
- "title": "Simple batch (no lazy scroll)",
360
+ "title": "Manual next (signal) — supplement",
361
+ "type": "paragraph"
362
+ },
363
+ "simple-batch-no-pagination": {
364
+ "count": 1,
365
+ "title": "Simple batch (no pagination)",
361
366
  "type": "paragraph"
362
367
  }
363
368
  }
@@ -820,14 +825,14 @@
820
825
  }
821
826
  },
822
827
  {
823
- "search": "When the expression contains $offset and $limit, the queue:\n",
828
+ "search": "In Lit apps, use defineQueue + .config on &lt;sonic-queue&gt; — typed Endpoint, DataProviderKey, enums. See src/docs/example/docs-queue-demos.ts.\n",
824
829
  "files": {
825
830
  "core/components/functional/queue/queue.md": {
826
831
  "title": "Queue",
827
832
  "hashes": {
828
- "lazy-load--offset-and-limit": {
833
+ "queue": {
829
834
  "count": 1,
830
- "title": "Lazy load — `$offset` and `$limit`",
835
+ "title": "",
831
836
  "type": "paragraph"
832
837
  }
833
838
  }
@@ -835,14 +840,29 @@
835
840
  }
836
841
  },
837
842
  {
838
- "search": "The doc mock implements this on GET /docs-mock-api/api/users?offset=…&amp;per_page=… (paginateUsers in src/docs/mock-api/router.ts).\n",
843
+ "search": "Required: endpoint + items. Add rowsAt when rows live in a nested property. Everything else has sensible defaults (strategy: Lazy, pageSize: 10, offset/limit query names).\n",
839
844
  "files": {
840
845
  "core/components/functional/queue/queue.md": {
841
846
  "title": "Queue",
842
847
  "hashes": {
843
- "lazy-load--offset-and-limit": {
848
+ "queue": {
844
849
  "count": 1,
845
- "title": "Lazy load — `$offset` and `$limit`",
850
+ "title": "",
851
+ "type": "paragraph"
852
+ }
853
+ }
854
+ }
855
+ }
856
+ },
857
+ {
858
+ "search": "Layout (class, id, …) stays on &lt;sonic-queue&gt; — not inside .config.\n",
859
+ "files": {
860
+ "core/components/functional/queue/queue.md": {
861
+ "title": "Queue",
862
+ "hashes": {
863
+ "queue": {
864
+ "count": 1,
865
+ "title": "",
846
866
  "type": "paragraph"
847
867
  }
848
868
  }
@@ -850,14 +870,14 @@
850
870
  }
851
871
  },
852
872
  {
853
- "search": "Wrap the queue in a fixed height with overflow-y-auto so lazy load triggers when scrolling inside the box (same layout as the TS starter demo-queue-templates).\n",
873
+ "search": "When pagination is enabled (default QueueLoadStrategy.Lazy), the queue:\n",
854
874
  "files": {
855
875
  "core/components/functional/queue/queue.md": {
856
876
  "title": "Queue",
857
877
  "hashes": {
858
- "lazy-load--offset-and-limit": {
878
+ "lazy-load": {
859
879
  "count": 1,
860
- "title": "Lazy load — `$offset` and `$limit`",
880
+ "title": "Lazy load",
861
881
  "type": "paragraph"
862
882
  }
863
883
  }
@@ -865,14 +885,14 @@
865
885
  }
866
886
  },
867
887
  {
868
- "search": "Try scrolling after load — batches of 4 users. Search e.g. George, Bluth, or zzz for empty results.\n",
888
+ "search": "Mock: GET /docs-mock-api/api/users?offset=…&amp;limit=… (paginateUsers in src/docs/mock-api/router.ts).\n",
869
889
  "files": {
870
890
  "core/components/functional/queue/queue.md": {
871
891
  "title": "Queue",
872
892
  "hashes": {
873
- "lazy-load--offset-and-limit": {
893
+ "lazy-load": {
874
894
  "count": 1,
875
- "title": "Lazy load — `$offset` and `$limit`",
895
+ "title": "Lazy load",
876
896
  "type": "paragraph"
877
897
  }
878
898
  }
@@ -880,14 +900,14 @@
880
900
  }
881
901
  },
882
902
  {
883
- "search": "Without $offset in the expression, the queue behaves like a single list (one batch), e.g. geo communes below.\n",
903
+ "search": "Wrap the queue in a fixed height with overflow-y-auto so lazy load triggers when scrolling inside the box.\n",
884
904
  "files": {
885
905
  "core/components/functional/queue/queue.md": {
886
906
  "title": "Queue",
887
907
  "hashes": {
888
- "expression-example": {
908
+ "lazy-load": {
889
909
  "count": 1,
890
- "title": "Expression example",
910
+ "title": "Lazy load",
891
911
  "type": "paragraph"
892
912
  }
893
913
  }
@@ -895,7 +915,22 @@
895
915
  }
896
916
  },
897
917
  {
898
- "search": "One search field (name=&quot;q&quot;) on formDataProvider=&quot;filter&quot;. The queue listens via dataFilterProvider=&quot;filter&quot; and, on change:\n",
918
+ "search": "Without pagination offset ( $offset not generated), the queue behaves as a single batch — see geo communes below.\n",
919
+ "files": {
920
+ "core/components/functional/queue/queue.md": {
921
+ "title": "Queue",
922
+ "hashes": {
923
+ "lazy-load": {
924
+ "count": 1,
925
+ "title": "Lazy load",
926
+ "type": "paragraph"
927
+ }
928
+ }
929
+ }
930
+ }
931
+ },
932
+ {
933
+ "search": "Pass a filter DataProviderKey in defineQueue (same publisher as formDataProvider on the search form). On change, the queue:\n",
899
934
  "files": {
900
935
  "core/components/functional/queue/queue.md": {
901
936
  "title": "Queue",
@@ -910,7 +945,7 @@
910
945
  }
911
946
  },
912
947
  {
913
- "search": "Use filteredFields only when the form has extra fields that must not be sent to the API (e.g. filteredFields=&quot;rememberMe internalId&quot;).\n",
948
+ "search": "Use filteredFields in the config only when the form has fields that must not be sent to the API.\n",
914
949
  "files": {
915
950
  "core/components/functional/queue/queue.md": {
916
951
  "title": "Queue",
@@ -925,7 +960,7 @@
925
960
  }
926
961
  },
927
962
  {
928
- "search": "The mock API filters before pagination — same haystack logic as the starter (filterDocsUsers in src/docs/mock-api/fixtures.ts, used by paginateUsers in router.ts / Service Worker):\n",
963
+ "search": "The users demo above wires docsQueueUsersFilterKey + sonic-input name=&quot;q&quot;. Mock filter: filterDocsUsers in src/docs/mock-api/fixtures.ts.\n",
929
964
  "files": {
930
965
  "core/components/functional/queue/queue.md": {
931
966
  "title": "Queue",
@@ -940,14 +975,14 @@
940
975
  }
941
976
  },
942
977
  {
943
- "search": "Geo communes: expression uses $limit only (no $offset) — one request, one batch.\n",
978
+ "search": "Default lazy scroll loads the next batch automatically. For a button that triggers the next batch via publishers — without touching the queue instance — use QueueLoadStrategy.Signal and a void next key (invalidate(), same idea as triggerKey on @get).\n",
944
979
  "files": {
945
980
  "core/components/functional/queue/queue.md": {
946
981
  "title": "Queue",
947
982
  "hashes": {
948
- "simple-batch-no-lazy-scroll": {
983
+ "manual-next-signal--supplement": {
949
984
  "count": 1,
950
- "title": "Simple batch (no lazy scroll)",
985
+ "title": "Manual next (signal) — supplement",
951
986
  "type": "paragraph"
952
987
  }
953
988
  }
@@ -955,14 +990,44 @@
955
990
  }
956
991
  },
957
992
  {
958
- "search": "Optional for hosts without Lit — see HTML integration.\n",
993
+ "search": "state exposes QueuePublisherState on the queue dataProvider: meta (e.g. total), loadedCount, hasMore. Wire sonic-button invalidate to the same next key.\n",
959
994
  "files": {
960
995
  "core/components/functional/queue/queue.md": {
961
996
  "title": "Queue",
962
997
  "hashes": {
963
- "html-template-children": {
998
+ "manual-next-signal--supplement": {
964
999
  "count": 1,
965
- "title": "HTML `<template>` children",
1000
+ "title": "Manual next (signal) — supplement",
1001
+ "type": "paragraph"
1002
+ }
1003
+ }
1004
+ }
1005
+ }
1006
+ },
1007
+ {
1008
+ "search": "Elsewhere: dp(usersNextKey).invalidate().\n",
1009
+ "files": {
1010
+ "core/components/functional/queue/queue.md": {
1011
+ "title": "Queue",
1012
+ "hashes": {
1013
+ "manual-next-signal--supplement": {
1014
+ "count": 1,
1015
+ "title": "Manual next (signal) — supplement",
1016
+ "type": "paragraph"
1017
+ }
1018
+ }
1019
+ }
1020
+ }
1021
+ },
1022
+ {
1023
+ "search": "Geo communes: one request, one batch ($limit only).\n",
1024
+ "files": {
1025
+ "core/components/functional/queue/queue.md": {
1026
+ "title": "Queue",
1027
+ "hashes": {
1028
+ "simple-batch-no-pagination": {
1029
+ "count": 1,
1030
+ "title": "Simple batch (no pagination)",
966
1031
  "type": "paragraph"
967
1032
  }
968
1033
  }
@@ -2269,6 +2334,21 @@
2269
2334
  }
2270
2335
  }
2271
2336
  },
2337
+ {
2338
+ "search": "Emit a publisher signal on click (same idea as triggerKey on @get, or dataNextProvider on sonic-queue). Value is the publisher path.\n",
2339
+ "files": {
2340
+ "core/components/ui/button/button.md": {
2341
+ "title": "Button",
2342
+ "hashes": {
2343
+ "invalidate": {
2344
+ "count": 1,
2345
+ "title": "Invalidate",
2346
+ "type": "paragraph"
2347
+ }
2348
+ }
2349
+ }
2350
+ }
2351
+ },
2272
2352
  {
2273
2353
  "search": "Captcha",
2274
2354
  "files": {
@@ -6934,6 +7014,21 @@
6934
7014
  }
6935
7015
  }
6936
7016
  },
7017
+ {
7018
+ "search": "Everything after &lt;!-- concorde-ai --&gt; is replaced on each ai-init run (idempotent). Do not paste a full copy of the Concorde guide above the marker — put project-specific notes in AGENTS.concorde.md (overlay). If the preamble duplicates package AGENTS.md, ai-init slims or drops it and prints a warning. Legacy filenames AGENTS.overlay.md / AGENTS.starter.md are still accepted with a deprecation warning.\n",
7019
+ "files": {
7020
+ "docs/_getting-started/ai-agents.md": {
7021
+ "title": "AI agents (skills & AGENTS.md)",
7022
+ "hashes": {
7023
+ "agentsmd-policy-non-invasive": {
7024
+ "count": 1,
7025
+ "title": "`AGENTS.md` policy (non-invasive)",
7026
+ "type": "paragraph"
7027
+ }
7028
+ }
7029
+ }
7030
+ }
7031
+ },
6937
7032
  {
6938
7033
  "search": "Source files in the npm package: node_modules/@supersoniks/concorde/ai/ (see also ai/README.md in the Concorde repository).\n",
6939
7034
  "files": {
File without changes