@adobe/data 0.9.37 → 0.9.40

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 (210) hide show
  1. package/AGENTS.md +160 -0
  2. package/dist/ecs/database/observe-select-deep.d.ts +23 -0
  3. package/dist/ecs/database/observe-select-deep.js +15 -0
  4. package/dist/ecs/database/observe-select-deep.js.map +1 -0
  5. package/dist/ecs/database/observe-select-deep.type-test.js +111 -0
  6. package/dist/ecs/database/observe-select-deep.type-test.js.map +1 -0
  7. package/dist/ecs/persistence-service/create-storage-persistence-service.js +4 -3
  8. package/dist/ecs/persistence-service/create-storage-persistence-service.js.map +1 -1
  9. package/dist/ecs/persistence-service/create-storage-persistence-service.test.js +52 -0
  10. package/dist/ecs/persistence-service/create-storage-persistence-service.test.js.map +1 -0
  11. package/dist/service/agentic-service/action.d.ts +4 -8
  12. package/dist/service/agentic-service/create.d.ts +1 -5
  13. package/dist/service/agentic-service/create.js +1 -1
  14. package/dist/service/agentic-service/create.js.map +1 -1
  15. package/dist/service/agentic-service/create.test.js +1 -1
  16. package/dist/service/agentic-service/create.test.js.map +1 -1
  17. package/dist/service/agentic-service/create.type-test.js +0 -23
  18. package/dist/service/agentic-service/create.type-test.js.map +1 -1
  19. package/dist/service/agentic-service/link.d.ts +15 -0
  20. package/dist/service/agentic-service/link.js +3 -0
  21. package/dist/service/agentic-service/link.js.map +1 -0
  22. package/dist/service/async-data-service/is-valid.d.ts +3 -1
  23. package/dist/service/async-data-service/is-valid.type-test.d.ts +1 -0
  24. package/dist/service/async-data-service/is-valid.type-test.js +3 -0
  25. package/dist/service/async-data-service/is-valid.type-test.js.map +1 -0
  26. package/dist/service/dynamic-service/semantic-service.d.ts +19 -0
  27. package/dist/service/dynamic-service/semantic-service.js +2 -0
  28. package/dist/service/dynamic-service/semantic-service.js.map +1 -0
  29. package/dist/service/semantic-service/semantic-service.d.ts +19 -0
  30. package/dist/service/semantic-service/semantic-service.js +2 -0
  31. package/dist/service/semantic-service/semantic-service.js.map +1 -0
  32. package/dist/tsconfig.tsbuildinfo +1 -1
  33. package/package.json +3 -1
  34. package/references/data-lit/README.md +18 -0
  35. package/references/data-lit/package.json +35 -0
  36. package/references/data-lit/src/decorators/apply-decorator.ts +26 -0
  37. package/references/data-lit/src/decorators/apply-service-decorators.ts +15 -0
  38. package/references/data-lit/src/decorators/index.ts +4 -0
  39. package/references/data-lit/src/decorators/require-service.ts +20 -0
  40. package/references/data-lit/src/elements/application-element.ts +42 -0
  41. package/references/data-lit/src/elements/application-host.ts +43 -0
  42. package/references/data-lit/src/elements/database-element.ts +42 -0
  43. package/references/data-lit/src/elements/index.ts +5 -0
  44. package/references/data-lit/src/functions/index.ts +3 -0
  45. package/references/data-lit/src/functions/iterate-self-and-ancestors.ts +23 -0
  46. package/references/data-lit/src/hooks/attach-decorator.ts +32 -0
  47. package/references/data-lit/src/hooks/component/component.ts +12 -0
  48. package/references/data-lit/src/hooks/component/stack.ts +19 -0
  49. package/references/data-lit/src/hooks/index.ts +21 -0
  50. package/references/data-lit/src/hooks/use-connected.ts +41 -0
  51. package/references/data-lit/src/hooks/use-debounce.ts +26 -0
  52. package/references/data-lit/src/hooks/use-drag-observe.ts +59 -0
  53. package/references/data-lit/src/hooks/use-drag-transaction.ts +46 -0
  54. package/references/data-lit/src/hooks/use-draggable.ts +112 -0
  55. package/references/data-lit/src/hooks/use-effect.ts +19 -0
  56. package/references/data-lit/src/hooks/use-element.ts +83 -0
  57. package/references/data-lit/src/hooks/use-memo.ts +16 -0
  58. package/references/data-lit/src/hooks/use-observable-values.ts +10 -0
  59. package/references/data-lit/src/hooks/use-observable.ts +15 -0
  60. package/references/data-lit/src/hooks/use-ref.ts +8 -0
  61. package/references/data-lit/src/hooks/use-resize-observer.ts +31 -0
  62. package/references/data-lit/src/hooks/use-state.ts +19 -0
  63. package/references/data-lit/src/hooks/use-updated.ts +56 -0
  64. package/references/data-lit/src/hooks/use-window-event.ts +16 -0
  65. package/references/data-lit/src/hooks/with-hooks.ts +22 -0
  66. package/references/data-lit/src/index.ts +6 -0
  67. package/references/data-lit/tsconfig.json +11 -0
  68. package/references/data-lit-tictactoe/package.json +22 -0
  69. package/references/data-lit-tictactoe/src/elements/tictactoe-app/tictactoe-app.css.ts +11 -0
  70. package/references/data-lit-tictactoe/src/elements/tictactoe-app/tictactoe-app.ts +22 -0
  71. package/references/data-lit-tictactoe/src/elements/tictactoe-board/tictactoe-board-presentation.ts +13 -0
  72. package/references/data-lit-tictactoe/src/elements/tictactoe-board/tictactoe-board.css.ts +17 -0
  73. package/references/data-lit-tictactoe/src/elements/tictactoe-board/tictactoe-board.ts +18 -0
  74. package/references/data-lit-tictactoe/src/elements/tictactoe-cell/tictactoe-cell-presentation.ts +22 -0
  75. package/references/data-lit-tictactoe/src/elements/tictactoe-cell/tictactoe-cell.css.ts +31 -0
  76. package/references/data-lit-tictactoe/src/elements/tictactoe-cell/tictactoe-cell.ts +41 -0
  77. package/references/data-lit-tictactoe/src/elements/tictactoe-hud/tictactoe-hud-presentation.ts +16 -0
  78. package/references/data-lit-tictactoe/src/elements/tictactoe-hud/tictactoe-hud.css.ts +18 -0
  79. package/references/data-lit-tictactoe/src/elements/tictactoe-hud/tictactoe-hud.ts +44 -0
  80. package/references/data-lit-tictactoe/src/main.ts +9 -0
  81. package/references/data-lit-tictactoe/src/state/agent-plugin.ts +117 -0
  82. package/references/data-lit-tictactoe/src/state/tictactoe-plugin.ts +56 -0
  83. package/references/data-lit-tictactoe/src/tictactoe-element.ts +10 -0
  84. package/references/data-lit-tictactoe/src/types/board-cell.ts +5 -0
  85. package/references/data-lit-tictactoe/src/types/board-state/board-state.ts +7 -0
  86. package/references/data-lit-tictactoe/src/types/board-state/create-initial-board.ts +5 -0
  87. package/references/data-lit-tictactoe/src/types/board-state/current-player.ts +13 -0
  88. package/references/data-lit-tictactoe/src/types/board-state/derive-status.ts +12 -0
  89. package/references/data-lit-tictactoe/src/types/board-state/get-cell.ts +7 -0
  90. package/references/data-lit-tictactoe/src/types/board-state/get-move-count.ts +6 -0
  91. package/references/data-lit-tictactoe/src/types/board-state/get-winner.ts +14 -0
  92. package/references/data-lit-tictactoe/src/types/board-state/get-winning-line.ts +25 -0
  93. package/references/data-lit-tictactoe/src/types/board-state/is-board-full.ts +5 -0
  94. package/references/data-lit-tictactoe/src/types/board-state/is-cell-playable.ts +13 -0
  95. package/references/data-lit-tictactoe/src/types/board-state/is-cell-winning.ts +9 -0
  96. package/references/data-lit-tictactoe/src/types/board-state/is-game-over.ts +8 -0
  97. package/references/data-lit-tictactoe/src/types/board-state/public.ts +15 -0
  98. package/references/data-lit-tictactoe/src/types/board-state/schema.ts +10 -0
  99. package/references/data-lit-tictactoe/src/types/board-state/set-board-cell.ts +13 -0
  100. package/references/data-lit-tictactoe/src/types/game-status.ts +3 -0
  101. package/references/data-lit-tictactoe/src/types/move-reject-reason.ts +7 -0
  102. package/references/data-lit-tictactoe/src/types/play-move-args/can-play-move.ts +33 -0
  103. package/references/data-lit-tictactoe/src/types/play-move-args/play-move-args.ts +4 -0
  104. package/references/data-lit-tictactoe/src/types/play-move-args/public.ts +3 -0
  105. package/references/data-lit-tictactoe/src/types/player-mark/player-mark.ts +7 -0
  106. package/references/data-lit-tictactoe/src/types/player-mark/public.ts +3 -0
  107. package/references/data-lit-tictactoe/src/types/player-mark/schema.ts +9 -0
  108. package/references/data-lit-tictactoe/src/types/winning-line.ts +3 -0
  109. package/references/data-lit-tictactoe/tsconfig.json +16 -0
  110. package/references/data-lit-todo/package.json +30 -0
  111. package/references/data-lit-todo/src/elements/todo-list/todo-list-presentation.ts +22 -0
  112. package/references/data-lit-todo/src/elements/todo-list/todo-list.css.ts +12 -0
  113. package/references/data-lit-todo/src/elements/todo-list/todo-list.ts +45 -0
  114. package/references/data-lit-todo/src/elements/todo-row/index.ts +2 -0
  115. package/references/data-lit-todo/src/elements/todo-row/todo-row-presentation.ts +68 -0
  116. package/references/data-lit-todo/src/elements/todo-row/todo-row.css.ts +49 -0
  117. package/references/data-lit-todo/src/elements/todo-row/todo-row.ts +46 -0
  118. package/references/data-lit-todo/src/elements/todo-toolbar/index.ts +2 -0
  119. package/references/data-lit-todo/src/elements/todo-toolbar/todo-toolbar-presentation.ts +55 -0
  120. package/references/data-lit-todo/src/elements/todo-toolbar/todo-toolbar.css.ts +34 -0
  121. package/references/data-lit-todo/src/elements/todo-toolbar/todo-toolbar.ts +62 -0
  122. package/references/data-lit-todo/src/elements/todo-undo-redo/index.ts +3 -0
  123. package/references/data-lit-todo/src/elements/todo-undo-redo/todo-undo-redo-presentation.ts +41 -0
  124. package/references/data-lit-todo/src/elements/todo-undo-redo/todo-undo-redo.css.ts +12 -0
  125. package/references/data-lit-todo/src/elements/todo-undo-redo/todo-undo-redo.ts +37 -0
  126. package/references/data-lit-todo/src/index.ts +9 -0
  127. package/references/data-lit-todo/src/main.ts +29 -0
  128. package/references/data-lit-todo/src/sample-types.ts +14 -0
  129. package/references/data-lit-todo/src/services/dependent-state-service/create-dependent-state-service.ts +8 -0
  130. package/references/data-lit-todo/src/services/dependent-state-service/dependent-state/all-todos.ts +5 -0
  131. package/references/data-lit-todo/src/services/dependent-state-service/dependent-state/complete-todos.ts +5 -0
  132. package/references/data-lit-todo/src/services/dependent-state-service/dependent-state/incomplete-todos.ts +5 -0
  133. package/references/data-lit-todo/src/services/dependent-state-service/dependent-state/index.ts +4 -0
  134. package/references/data-lit-todo/src/services/dependent-state-service/dependent-state-service.ts +4 -0
  135. package/references/data-lit-todo/src/services/main-service/create-main-service.ts +53 -0
  136. package/references/data-lit-todo/src/services/main-service/todo-main-service.ts +20 -0
  137. package/references/data-lit-todo/src/services/state-service/create-todo-database.ts +16 -0
  138. package/references/data-lit-todo/src/services/state-service/create-todo-store.ts +28 -0
  139. package/references/data-lit-todo/src/services/state-service/todo-state-service.ts +9 -0
  140. package/references/data-lit-todo/src/services/state-service/transactions/create-bulk-todos.ts +12 -0
  141. package/references/data-lit-todo/src/services/state-service/transactions/create-todo.test.ts +17 -0
  142. package/references/data-lit-todo/src/services/state-service/transactions/create-todo.ts +15 -0
  143. package/references/data-lit-todo/src/services/state-service/transactions/delete-all-todos.ts +18 -0
  144. package/references/data-lit-todo/src/services/state-service/transactions/delete-todo.test.ts +25 -0
  145. package/references/data-lit-todo/src/services/state-service/transactions/delete-todo.ts +11 -0
  146. package/references/data-lit-todo/src/services/state-service/transactions/drag-todo.ts +19 -0
  147. package/references/data-lit-todo/src/services/state-service/transactions/index.ts +8 -0
  148. package/references/data-lit-todo/src/services/state-service/transactions/reorder-todos.ts +13 -0
  149. package/references/data-lit-todo/src/services/state-service/transactions/toggle-complete.test.ts +78 -0
  150. package/references/data-lit-todo/src/services/state-service/transactions/toggle-complete.ts +15 -0
  151. package/references/data-lit-todo/src/todo-element.ts +6 -0
  152. package/references/data-lit-todo/src/todo-host.ts +29 -0
  153. package/references/data-lit-todo/src/todo-main-element.ts +40 -0
  154. package/references/data-lit-todo/src/todo-sample.ts +21 -0
  155. package/references/data-lit-todo/tsconfig.json +10 -0
  156. package/references/data-react/README.md +47 -0
  157. package/references/data-react/package.json +36 -0
  158. package/references/data-react/src/context/database-context.tsx +41 -0
  159. package/references/data-react/src/hooks/index.ts +5 -0
  160. package/references/data-react/src/hooks/use-database.ts +13 -0
  161. package/references/data-react/src/hooks/use-observable-values.ts +15 -0
  162. package/references/data-react/src/hooks/use-observable.ts +14 -0
  163. package/references/data-react/src/index.ts +7 -0
  164. package/references/data-react/tsconfig.json +12 -0
  165. package/references/data-react-hello/package.json +25 -0
  166. package/references/data-react-hello/src/app.tsx +13 -0
  167. package/references/data-react-hello/src/components/counter/counter-presentation.tsx +13 -0
  168. package/references/data-react-hello/src/components/counter/counter.tsx +26 -0
  169. package/references/data-react-hello/src/main.tsx +9 -0
  170. package/references/data-react-hello/src/state/counter-plugin.ts +14 -0
  171. package/references/data-react-hello/src/state/use-counter-database.ts +6 -0
  172. package/references/data-react-hello/tsconfig.json +16 -0
  173. package/references/data-react-pixie/package.json +28 -0
  174. package/references/data-react-pixie/src/app.tsx +21 -0
  175. package/references/data-react-pixie/src/components/filter-selector/filter-selector-presentation.tsx +40 -0
  176. package/references/data-react-pixie/src/components/filter-selector/filter-selector.tsx +22 -0
  177. package/references/data-react-pixie/src/components/pixie-scene/pixie-filters.ts +24 -0
  178. package/references/data-react-pixie/src/components/pixie-scene/pixie-scene-presentation.tsx +18 -0
  179. package/references/data-react-pixie/src/components/pixie-scene/pixie-scene.tsx +26 -0
  180. package/references/data-react-pixie/src/components/pixie-scene/pixie-tick.tsx +12 -0
  181. package/references/data-react-pixie/src/components/sprite/sprite-presentation.tsx +39 -0
  182. package/references/data-react-pixie/src/components/sprite/sprite.tsx +37 -0
  183. package/references/data-react-pixie/src/components/sprite/use-sprite-texture.ts +24 -0
  184. package/references/data-react-pixie/src/main.tsx +14 -0
  185. package/references/data-react-pixie/src/state/pixie-plugin.ts +97 -0
  186. package/references/data-react-pixie/src/state/use-pixie-database.ts +6 -0
  187. package/references/data-react-pixie/src/types/filter-type.ts +3 -0
  188. package/references/data-react-pixie/src/types/sprite-type/bunny.png +0 -0
  189. package/references/data-react-pixie/src/types/sprite-type/fox.png +0 -0
  190. package/references/data-react-pixie/src/types/sprite-type/image.ts +14 -0
  191. package/references/data-react-pixie/src/types/sprite-type/public.ts +4 -0
  192. package/references/data-react-pixie/src/types/sprite-type/schema.ts +5 -0
  193. package/references/data-react-pixie/src/types/sprite-type/sprite-type.ts +7 -0
  194. package/references/data-react-pixie/src/vite-env.d.ts +6 -0
  195. package/references/data-react-pixie/tsconfig.json +16 -0
  196. package/dist/LICENSE +0 -21
  197. package/dist/README.md +0 -296
  198. package/dist/package.json +0 -183
  199. package/dist/service/agentic-service/create-from-config.d.ts +0 -45
  200. package/dist/service/agentic-service/create-from-config.js +0 -85
  201. package/dist/service/agentic-service/create-from-config.js.map +0 -1
  202. package/dist/service/agentic-service/create.interface-first-spike.type-test.js +0 -119
  203. package/dist/service/agentic-service/create.interface-first-spike.type-test.js.map +0 -1
  204. package/dist/service/agentic-service/index.d.ts +0 -1
  205. package/dist/service/agentic-service/index.js +0 -3
  206. package/dist/service/agentic-service/index.js.map +0 -1
  207. package/dist/service/dynamic-service/create.interface-first-spike.type-test.js +0 -118
  208. package/dist/service/dynamic-service/create.interface-first-spike.type-test.js.map +0 -1
  209. /package/dist/{service/agentic-service/create.interface-first-spike.type-test.d.ts → ecs/database/observe-select-deep.type-test.d.ts} +0 -0
  210. /package/dist/{service/dynamic-service/create.interface-first-spike.type-test.d.ts → ecs/persistence-service/create-storage-persistence-service.test.d.ts} +0 -0
@@ -0,0 +1,112 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { Vec2 } from '@adobe/data/math';
4
+ import { useEffect } from './use-effect.js';
5
+
6
+ function toCssUnitString(value: number): string {
7
+ return `${value}px`;
8
+ }
9
+
10
+ export interface DraggableProps {
11
+ // onDragStart should return the initial position of the element
12
+ onDragStart: (e: PointerEvent) => Vec2 | void;
13
+ onDrag: (e: PointerEvent, newPosition: Vec2, delta: Vec2) => void;
14
+ onDragEnd?: (e: PointerEvent, newPosition: Vec2, delta: Vec2) => void;
15
+ /**
16
+ * Called if this hook is destroyed before the drag is completed.
17
+ */
18
+ onDragCancel?: () => void;
19
+ minDragDistance?: number;
20
+ dragCursor?: string;
21
+ addPlaceholder?: boolean;
22
+ stopPropagation?: boolean;
23
+ }
24
+
25
+ export function useDraggable(element: HTMLElement, props: DraggableProps, dependencies: unknown[]) {
26
+ const { minDragDistance = 10, dragCursor = 'grab', addPlaceholder = false, stopPropagation = false } = props;
27
+ useEffect(() => {
28
+ let downPosition: Vec2 | null = null;
29
+ // the bounds of the element when the pointer was first pressed down.
30
+ let dragStartOffset: Vec2 | null = null;
31
+ let originalCursor = '';
32
+ let placeholder: HTMLElement | null = null;
33
+ let movePosition: Vec2 = [0, 0];
34
+ function notify(e: PointerEvent, dragListener: DraggableProps["onDrag"]) {
35
+ const delta = Vec2.subtract(movePosition, downPosition!);
36
+ dragListener(e, Vec2.add(dragStartOffset!, delta), delta);
37
+ }
38
+
39
+ function onPointerMove(e: PointerEvent) {
40
+ movePosition = [e.clientX, e.clientY];
41
+ if (Vec2.length(Vec2.subtract(movePosition, downPosition!)) >= minDragDistance) {
42
+ if (!dragStartOffset) {
43
+ dragStartOffset = [element.offsetLeft, element.offsetTop];
44
+ props.onDragStart(e);
45
+ if (dragCursor) {
46
+ originalCursor = element.style.cursor;
47
+ element.style.cursor = dragCursor;
48
+ }
49
+ // add a placeholder so the parent element doesn't change size when the element is dragged.
50
+ if (addPlaceholder) {
51
+ placeholder = document.createElement('div');
52
+ Object.assign(placeholder.style, {
53
+ position: 'absolute',
54
+ backgroundColor: 'pink',
55
+ left: toCssUnitString(element.offsetLeft),
56
+ top: toCssUnitString(element.offsetTop),
57
+ width: toCssUnitString(element.offsetWidth),
58
+ height: toCssUnitString(element.offsetHeight),
59
+ visibility: 'hidden',
60
+ });
61
+ element.parentElement?.appendChild(placeholder);
62
+ }
63
+ }
64
+ }
65
+ if (dragStartOffset) {
66
+ notify(e, props.onDrag);
67
+ }
68
+ if (stopPropagation) e.stopPropagation();
69
+ }
70
+ function cleanup() {
71
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
72
+ window.removeEventListener('pointerup', onPointerUp);
73
+ window.removeEventListener('pointermove', onPointerMove);
74
+ if (dragCursor) {
75
+ element.style.cursor = originalCursor;
76
+ }
77
+ if (placeholder) {
78
+ placeholder.remove();
79
+ placeholder = null;
80
+ }
81
+ }
82
+ function onPointerUp(e: PointerEvent) {
83
+ cleanup();
84
+ if (dragStartOffset && props.onDragEnd) {
85
+ notify(e, props.onDragEnd);
86
+ }
87
+ if (stopPropagation) e.stopPropagation();
88
+ downPosition = null;
89
+ dragStartOffset = null;
90
+ }
91
+ function onPointerDown(e: PointerEvent) {
92
+ // Only start drag transaction for left mouse button clicks
93
+ if (e.button !== 0) return;
94
+
95
+ window.addEventListener('pointermove', onPointerMove);
96
+ window.addEventListener('pointerup', onPointerUp);
97
+ downPosition = [e.clientX, e.clientY];
98
+ if (stopPropagation) e.stopPropagation();
99
+ }
100
+
101
+ element?.addEventListener('pointerdown', onPointerDown);
102
+ return () => {
103
+ element?.removeEventListener('pointerdown', onPointerDown);
104
+ if (downPosition) {
105
+ cleanup();
106
+ }
107
+ if (dragStartOffset) {
108
+ props.onDragCancel?.();
109
+ }
110
+ };
111
+ }, [element, ...(dependencies ?? [])]);
112
+ }
@@ -0,0 +1,19 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { equalsShallow } from "@adobe/data/equals-shallow";
4
+ import type { Component } from "./component/component.js"
5
+ import { Component_stack } from "./component/stack.js";
6
+
7
+ export type EffectCallback = () => (void | (() => void))
8
+ type EffectHookState = { dispose?: () => void, dependencies: unknown[] };
9
+
10
+ export function useEffect<T extends Component>(callback: EffectCallback, dependencies: unknown[] = []) {
11
+ const component = Component_stack.active() as T;
12
+ const hookIndex = component.hookIndex++;
13
+ const oldHookState = component.hooks[hookIndex] as EffectHookState | undefined;
14
+ const rerunEffect = !oldHookState || !equalsShallow(dependencies, oldHookState.dependencies);
15
+ if (rerunEffect) {
16
+ oldHookState?.dispose?.();
17
+ component.hooks[hookIndex] = { dispose: callback.call(component) ?? undefined, dependencies };
18
+ }
19
+ }
@@ -0,0 +1,83 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { Component_stack } from "./component/stack.js";
4
+ import { useEffect } from "./use-effect.js";
5
+ import { useState } from "./use-state.js";
6
+
7
+ /**
8
+ * Hook that returns the currently active component.
9
+ * If a querySelector is provided, it dynamically observes for child elements
10
+ * matching the selector and triggers rerender when found.
11
+ */
12
+ export function useElement<K extends keyof HTMLElementTagNameMap>(querySelector: K): HTMLElementTagNameMap[K] | null
13
+ export function useElement<T = HTMLElement>(): T
14
+ export function useElement<T = HTMLElement>(querySelector?: string): T | null {
15
+ const component = Component_stack.active();
16
+
17
+ // If no querySelector provided, return the active component
18
+ if (!querySelector) {
19
+ return component as unknown as T;
20
+ }
21
+
22
+ // Use state to track the found element
23
+ const [foundElement, setFoundElement] = useState<T | null>(null);
24
+
25
+ useEffect(() => {
26
+ const element = component as unknown as HTMLElement;
27
+
28
+ // Check if element already exists
29
+ const existingElement = element.querySelector(querySelector) as T | null;
30
+ if (existingElement) {
31
+ setFoundElement(existingElement);
32
+ return;
33
+ }
34
+
35
+ // Set up MutationObserver to watch for new child elements
36
+ const observer = new MutationObserver((mutations) => {
37
+ for (const mutation of mutations) {
38
+ if (mutation.type === 'childList') {
39
+ // Check if any added nodes match the selector
40
+ for (const node of mutation.addedNodes) {
41
+ if (node.nodeType === Node.ELEMENT_NODE) {
42
+ const element = node as Element;
43
+ // Check if the added node itself matches
44
+ if (element.matches(querySelector)) {
45
+ setFoundElement(element as T);
46
+ observer.disconnect();
47
+ return;
48
+ }
49
+ // Check if any descendant matches
50
+ const descendant = element.querySelector(querySelector) as T | null;
51
+ if (descendant) {
52
+ setFoundElement(descendant);
53
+ observer.disconnect();
54
+ return;
55
+ }
56
+ }
57
+ }
58
+ }
59
+ }
60
+ });
61
+
62
+ // Start observing both element and shadowRoot
63
+ for (const observe of [element.shadowRoot, element]) {
64
+ if (observe) {
65
+ observer.observe(observe, {
66
+ childList: true,
67
+ subtree: true
68
+ });
69
+ }
70
+ }
71
+ observer.observe(element.shadowRoot ?? element, {
72
+ childList: true,
73
+ subtree: true
74
+ });
75
+
76
+ // Cleanup function
77
+ return () => {
78
+ observer.disconnect();
79
+ };
80
+ }, [querySelector]);
81
+
82
+ return foundElement;
83
+ }
@@ -0,0 +1,16 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { useEffect } from "./use-effect.js";
4
+ import { useState } from "./use-state.js";
5
+
6
+ export function useMemo<T>(calculateValue: () => T, dependencies: unknown[] = []): T {
7
+ const [state, setState] = useState<T | undefined>(undefined);
8
+ let currentValue = state;
9
+
10
+ useEffect(() => {
11
+ currentValue = calculateValue();
12
+ setState(currentValue);
13
+ }, dependencies);
14
+
15
+ return currentValue!;
16
+ }
@@ -0,0 +1,10 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { Observe } from "@adobe/data/observe";
4
+ import { useMemo } from "./use-memo.js";
5
+ import { useObservable } from "./use-observable.js";
6
+
7
+ export function useObservableValues<T extends Record<string, Observe<unknown>>>(factory: () => T, deps: unknown[] = []): { [K in keyof T]: T[K] extends Observe<infer U> ? U : never } | undefined {
8
+ const observable = useMemo(() => Observe.fromProperties(factory()), deps);
9
+ return useObservable(observable);
10
+ }
@@ -0,0 +1,15 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { useState } from "./use-state.js";
4
+ import { useEffect } from "./use-effect.js";
5
+ import { Observe } from "@adobe/data/observe";
6
+
7
+ export function useObservable<T>(observable: Observe<T>): T | undefined {
8
+ let [value, setValue] = useState<T | undefined>(undefined);
9
+ useEffect(() => {
10
+ return observable(newValue => {
11
+ setValue(value = newValue);
12
+ });
13
+ }, [observable]);
14
+ return value;
15
+ }
@@ -0,0 +1,8 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { useState } from "./use-state.js";
4
+
5
+ export function useRef<T>(initialValue: T): { current: T } {
6
+ const [state] = useState({ current: initialValue });
7
+ return state;
8
+ }
@@ -0,0 +1,31 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { useEffect } from "./use-effect.js";
4
+ import { useElement } from "./use-element.js";
5
+
6
+ export interface ResizeInfo {
7
+ width: number;
8
+ height: number;
9
+ entry: ResizeObserverEntry;
10
+ }
11
+
12
+ /**
13
+ * Hook to observe element resizes. Calls callback with width, height, and the original entry
14
+ * when the element's size changes.
15
+ *
16
+ * @param onResize - Callback invoked when element size changes
17
+ */
18
+ export function useResizeObserver(onResize: (info: ResizeInfo) => void) {
19
+ const element = useElement();
20
+
21
+ useEffect(() => {
22
+ const observer = new ResizeObserver(entries => {
23
+ for (const entry of entries) {
24
+ const { width, height } = entry.contentRect;
25
+ onResize({ width, height, entry });
26
+ }
27
+ });
28
+ observer.observe(element);
29
+ return () => observer.disconnect();
30
+ }, [element, onResize]);
31
+ }
@@ -0,0 +1,19 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { Component_stack } from "./component/stack.js";
4
+
5
+ export function useState<T>(initializer: () => T): [T, (value: T) => void]
6
+ export function useState<T>(initialValue: T): [T, (value: T) => void]
7
+ export function useState<T>(initial: () => T) {
8
+ const component = Component_stack.active();
9
+ const hookIndex = component.hookIndex++;
10
+ const value = component.hooks[hookIndex] ??= (typeof initial === "function" ? initial() : initial);
11
+ return [
12
+ value,
13
+ (newValue: T) => {
14
+ component.hooks[hookIndex] = newValue;
15
+ component.requestUpdate();
16
+ }
17
+ ];
18
+
19
+ }
@@ -0,0 +1,56 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+ import { useElement } from "./use-element.js";
3
+ import { useEffect } from "./use-effect.js";
4
+
5
+ export interface UpdateEventHost {
6
+ updateListeners: Set<() => void>;
7
+ }
8
+
9
+ function hasUpdateListeners(el: unknown): el is UpdateEventHost {
10
+ return (
11
+ typeof el === 'object' &&
12
+ el !== null &&
13
+ 'updateListeners' in el &&
14
+ el['updateListeners'] instanceof Set
15
+ );
16
+ }
17
+
18
+ function makeUpdateEventHost<T extends Element>(
19
+ el: T
20
+ ): T & UpdateEventHost {
21
+ if (hasUpdateListeners(el)) return el as T & UpdateEventHost;
22
+
23
+ const updateListeners = new Set<() => void>();
24
+ Object.defineProperty(el, 'updateListeners', {
25
+ value: updateListeners,
26
+ writable: false,
27
+ enumerable: false,
28
+ });
29
+
30
+ if (!('updated' in el)) {
31
+ throw new Error('Element does not have an updated method');
32
+ }
33
+
34
+ const element = el as unknown as T & {
35
+ updated: (changedProps: Map<PropertyKey, unknown>) => void;
36
+ } & UpdateEventHost;
37
+ const orig = element.updated.bind(el);
38
+
39
+ element.updated = (changedProps) => {
40
+ orig(changedProps);
41
+ for (const fn of updateListeners) fn();
42
+ };
43
+
44
+ return element;
45
+ }
46
+
47
+
48
+ export function useUpdated(listener: () => void, dependencies: unknown[] = []) {
49
+ const element = makeUpdateEventHost(useElement());
50
+ useEffect(() => {
51
+ element.updateListeners.add(listener);
52
+ return () => {
53
+ element.updateListeners.delete(listener);
54
+ }
55
+ }, dependencies);
56
+ }
@@ -0,0 +1,16 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { useEffect } from "./use-effect.js";
4
+ import { useMemo } from "./use-memo.js";
5
+
6
+ export function useWindowEvent<K extends keyof WindowEventMap>(
7
+ event: K,
8
+ callbackFactory: () => (e: WindowEventMap[K]) => void,
9
+ deps: any[] = []
10
+ ) {
11
+ const callback = useMemo(callbackFactory, deps);
12
+ useEffect(() => {
13
+ window.addEventListener(event, callback);
14
+ return () => window.removeEventListener(event, callback);
15
+ }, [callback]);
16
+ }
@@ -0,0 +1,22 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import type { Component } from "./component/component.js";
4
+ import { Component_stack } from "./component/stack.js";
5
+
6
+ export function withHooks<This extends Component, Args extends any[], Return>(
7
+ target: object,
8
+ propertyKey: string,
9
+ descriptor: TypedPropertyDescriptor<(this: This, ...args: Args) => Return>
10
+ ): TypedPropertyDescriptor<(this: This, ...args: Args) => Return> {
11
+ const originalMethod = descriptor.value!;
12
+ descriptor.value = function (this: This, ...args: Args): Return {
13
+ Component_stack.push(this);
14
+ try {
15
+ return originalMethod.apply(this, args);
16
+ }
17
+ finally {
18
+ Component_stack.pop();
19
+ }
20
+ }
21
+ return descriptor;
22
+ }
@@ -0,0 +1,6 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ export * from "./hooks/index.js";
4
+ export * from "./elements/index.js";
5
+ export * from "./decorators/index.js";
6
+ export type { Vec2 } from "@adobe/data/math";
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "../data/tsconfig-base.json",
3
+ "compilerOptions": {
4
+ "rootDir": "src",
5
+ "outDir": "dist",
6
+ "composite": true,
7
+ "types": []
8
+ },
9
+ "include": ["src/**/*"],
10
+ "references": []
11
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "data-lit-tictactoe",
3
+ "version": "0.9.40",
4
+ "description": "Tic-Tac-Toe sample - Lit web components with @adobe/data-lit and AgenticService",
5
+ "type": "module",
6
+ "private": true,
7
+ "scripts": {
8
+ "build": "vite build",
9
+ "dev": "vite",
10
+ "publish-public": "true"
11
+ },
12
+ "dependencies": {
13
+ "@adobe/data": "workspace:*",
14
+ "@adobe/data-lit": "workspace:*",
15
+ "lit": "^3.3.1"
16
+ },
17
+ "devDependencies": {
18
+ "typescript": "^5.8.3",
19
+ "vite": "^5.1.1",
20
+ "vite-plugin-checker": "^0.12.0"
21
+ }
22
+ }
@@ -0,0 +1,11 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { css } from "lit";
4
+
5
+ export const styles = css`
6
+ :host {
7
+ display: flex;
8
+ flex-direction: column;
9
+ gap: 1rem;
10
+ }
11
+ `;
@@ -0,0 +1,22 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { customElement } from "lit/decorators.js";
4
+ import { html } from "lit";
5
+ import { TictactoeElement } from "../../tictactoe-element.js";
6
+ import { styles } from "./tictactoe-app.css.js";
7
+ import "../tictactoe-board/tictactoe-board.js";
8
+ import "../tictactoe-hud/tictactoe-hud.js";
9
+
10
+ export const tagName = "tictactoe-app";
11
+
12
+ @customElement(tagName)
13
+ export class TictactoeApp extends TictactoeElement {
14
+ static styles = styles;
15
+
16
+ render() {
17
+ return html`
18
+ <tictactoe-board></tictactoe-board>
19
+ <tictactoe-hud></tictactoe-hud>
20
+ `;
21
+ }
22
+ }
@@ -0,0 +1,13 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { html } from "lit";
4
+
5
+ export function render() {
6
+ return html`
7
+ <div class="board">
8
+ ${[0, 1, 2, 3, 4, 5, 6, 7, 8].map(
9
+ (index) => html`<tictactoe-cell .index=${index}></tictactoe-cell>`,
10
+ )}
11
+ </div>
12
+ `;
13
+ }
@@ -0,0 +1,17 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { css } from "lit";
4
+
5
+ export const styles = css`
6
+ :host {
7
+ display: block;
8
+ }
9
+
10
+ .board {
11
+ display: grid;
12
+ grid-template-columns: repeat(3, 100px);
13
+ grid-template-rows: repeat(3, 100px);
14
+ gap: 4px;
15
+ width: fit-content;
16
+ }
17
+ `;
@@ -0,0 +1,18 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { customElement } from "lit/decorators.js";
4
+ import { TictactoeElement } from "../../tictactoe-element.js";
5
+ import { styles } from "./tictactoe-board.css.js";
6
+ import * as presentation from "./tictactoe-board-presentation.js";
7
+ import "../tictactoe-cell/tictactoe-cell.js";
8
+
9
+ export const tagName = "tictactoe-board";
10
+
11
+ @customElement(tagName)
12
+ export class TictactoeBoard extends TictactoeElement {
13
+ static styles = styles;
14
+
15
+ render() {
16
+ return presentation.render();
17
+ }
18
+ }
@@ -0,0 +1,22 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { html } from "lit";
4
+
5
+ export function render(args: {
6
+ cell: string;
7
+ isWinning: boolean;
8
+ isPlayable: boolean;
9
+ playMove: () => void;
10
+ }) {
11
+ const { cell, isWinning, isPlayable, playMove } = args;
12
+ const hasMark = cell === "X" || cell === "O";
13
+
14
+ return html`
15
+ <div
16
+ class="cell ${isWinning ? "winning" : ""} ${isPlayable ? "playable" : ""}"
17
+ @click=${() => isPlayable && playMove()}
18
+ >
19
+ ${hasMark ? cell : ""}
20
+ </div>
21
+ `;
22
+ }
@@ -0,0 +1,31 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { css } from "lit";
4
+
5
+ export const styles = css`
6
+ :host {
7
+ display: block;
8
+ }
9
+
10
+ .cell {
11
+ width: 100px;
12
+ height: 100px;
13
+ display: flex;
14
+ align-items: center;
15
+ justify-content: center;
16
+ font-size: 48px;
17
+ font-weight: bold;
18
+ background: #1f2937;
19
+ border: 2px solid #6b7280;
20
+ color: #e5e7eb;
21
+ box-sizing: border-box;
22
+ }
23
+
24
+ .cell.playable {
25
+ cursor: pointer;
26
+ }
27
+
28
+ .cell.winning {
29
+ background: #2e7d32;
30
+ }
31
+ `;
@@ -0,0 +1,41 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { customElement, property } from "lit/decorators.js";
4
+ import { useObservableValues } from "@adobe/data-lit";
5
+ import { BoardState } from "../../types/board-state/board-state.js";
6
+ import { TictactoeElement } from "../../tictactoe-element.js";
7
+ import { styles } from "./tictactoe-cell.css.js";
8
+ import * as presentation from "./tictactoe-cell-presentation.js";
9
+
10
+ export const tagName = "tictactoe-cell";
11
+
12
+ @customElement(tagName)
13
+ export class TictactoeCell extends TictactoeElement {
14
+ static styles = styles;
15
+
16
+ @property({ type: Number })
17
+ declare index: number;
18
+
19
+ render() {
20
+ const values = useObservableValues(
21
+ () => ({
22
+ board: this.service.observe.resources.board,
23
+ }),
24
+ [],
25
+ );
26
+
27
+ const board = values?.board ?? " ";
28
+ const cell = BoardState.getCell(board, this.index);
29
+ const isWinning = BoardState.isCellWinning(board, this.index);
30
+ const isPlayable = BoardState.isCellPlayable(board, this.index);
31
+
32
+ return presentation.render({
33
+ cell,
34
+ isWinning,
35
+ isPlayable,
36
+ playMove: () => {
37
+ this.service.transactions.playMove({ index: this.index });
38
+ },
39
+ });
40
+ }
41
+ }
@@ -0,0 +1,16 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ import { html } from "lit";
4
+
5
+ export function render(args: {
6
+ statusText: string;
7
+ restartGame: () => void;
8
+ }) {
9
+ const { statusText, restartGame } = args;
10
+ return html`
11
+ <div class="hud">
12
+ <span>${statusText}</span>
13
+ <button type="button" @click=${restartGame}>Restart</button>
14
+ </div>
15
+ `;
16
+ }