angular-grab-monorepo 0.1.3

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 (99) hide show
  1. package/.claude/settings.local.json +10 -0
  2. package/.playwright-mcp/console-2026-03-07T02-49-38-061Z.log +37 -0
  3. package/.playwright-mcp/console-2026-03-07T02-51-03-493Z.log +26 -0
  4. package/.playwright-mcp/console-2026-03-07T02-51-25-431Z.log +15 -0
  5. package/.playwright-mcp/console-2026-03-07T02-52-02-980Z.log +91 -0
  6. package/.playwright-mcp/page-2026-03-07T02-52-09-791Z.png +0 -0
  7. package/LICENSE +21 -0
  8. package/README.md +215 -0
  9. package/examples/angular-19-app/.editorconfig +17 -0
  10. package/examples/angular-19-app/.vscode/extensions.json +4 -0
  11. package/examples/angular-19-app/.vscode/launch.json +20 -0
  12. package/examples/angular-19-app/.vscode/mcp.json +9 -0
  13. package/examples/angular-19-app/.vscode/tasks.json +42 -0
  14. package/examples/angular-19-app/README.md +59 -0
  15. package/examples/angular-19-app/angular.json +79 -0
  16. package/examples/angular-19-app/package.json +42 -0
  17. package/examples/angular-19-app/public/favicon.ico +0 -0
  18. package/examples/angular-19-app/src/app/app.config.ts +13 -0
  19. package/examples/angular-19-app/src/app/app.css +37 -0
  20. package/examples/angular-19-app/src/app/app.html +25 -0
  21. package/examples/angular-19-app/src/app/app.routes.ts +3 -0
  22. package/examples/angular-19-app/src/app/app.spec.ts +23 -0
  23. package/examples/angular-19-app/src/app/app.ts +12 -0
  24. package/examples/angular-19-app/src/app/button/button.component.ts +25 -0
  25. package/examples/angular-19-app/src/app/card/card.component.ts +33 -0
  26. package/examples/angular-19-app/src/app/header/header.component.ts +31 -0
  27. package/examples/angular-19-app/src/app/popover/popover.component.ts +133 -0
  28. package/examples/angular-19-app/src/index.html +13 -0
  29. package/examples/angular-19-app/src/main.ts +6 -0
  30. package/examples/angular-19-app/src/styles.css +1 -0
  31. package/examples/angular-19-app/tsconfig.app.json +15 -0
  32. package/examples/angular-19-app/tsconfig.json +33 -0
  33. package/examples/angular-19-app/tsconfig.spec.json +15 -0
  34. package/package.json +22 -0
  35. package/packages/angular-grab/builders.json +14 -0
  36. package/packages/angular-grab/package.json +96 -0
  37. package/packages/angular-grab/src/angular/__tests__/context-builder.test.ts +216 -0
  38. package/packages/angular-grab/src/angular/angular-grab.service.ts +62 -0
  39. package/packages/angular-grab/src/angular/index.ts +13 -0
  40. package/packages/angular-grab/src/angular/provide-angular-grab.ts +22 -0
  41. package/packages/angular-grab/src/angular/resolvers/component-resolver.ts +71 -0
  42. package/packages/angular-grab/src/angular/resolvers/context-builder.ts +86 -0
  43. package/packages/angular-grab/src/angular/resolvers/ng-utils.ts +14 -0
  44. package/packages/angular-grab/src/angular/resolvers/source-resolver.ts +61 -0
  45. package/packages/angular-grab/src/builder/__tests__/builder.test.ts +72 -0
  46. package/packages/angular-grab/src/builder/builders/application/index.ts +13 -0
  47. package/packages/angular-grab/src/builder/builders/application/schema.json +7 -0
  48. package/packages/angular-grab/src/builder/builders/dev-server/index.ts +9 -0
  49. package/packages/angular-grab/src/builder/builders/dev-server/schema.json +7 -0
  50. package/packages/angular-grab/src/builder/index.ts +3 -0
  51. package/packages/angular-grab/src/cli/__tests__/cli.test.ts +239 -0
  52. package/packages/angular-grab/src/cli/commands/init.ts +106 -0
  53. package/packages/angular-grab/src/cli/index.ts +15 -0
  54. package/packages/angular-grab/src/cli/utils/detect-project.ts +78 -0
  55. package/packages/angular-grab/src/cli/utils/modify-angular-json.ts +42 -0
  56. package/packages/angular-grab/src/cli/utils/modify-app-config.ts +42 -0
  57. package/packages/angular-grab/src/core/__tests__/generate-snippet.test.ts +149 -0
  58. package/packages/angular-grab/src/core/__tests__/plugin-registry.test.ts +286 -0
  59. package/packages/angular-grab/src/core/__tests__/store.test.ts +118 -0
  60. package/packages/angular-grab/src/core/__tests__/utils.test.ts +85 -0
  61. package/packages/angular-grab/src/core/clipboard/copy.ts +104 -0
  62. package/packages/angular-grab/src/core/clipboard/generate-snippet.ts +38 -0
  63. package/packages/angular-grab/src/core/constants.ts +10 -0
  64. package/packages/angular-grab/src/core/grab.ts +596 -0
  65. package/packages/angular-grab/src/core/index.global.ts +13 -0
  66. package/packages/angular-grab/src/core/index.ts +19 -0
  67. package/packages/angular-grab/src/core/keyboard/keyboard-handler.ts +163 -0
  68. package/packages/angular-grab/src/core/overlay/crosshair.ts +107 -0
  69. package/packages/angular-grab/src/core/overlay/freeze-overlay.ts +239 -0
  70. package/packages/angular-grab/src/core/overlay/overlay-renderer.ts +180 -0
  71. package/packages/angular-grab/src/core/overlay/select-feedback.ts +108 -0
  72. package/packages/angular-grab/src/core/overlay/toast.ts +175 -0
  73. package/packages/angular-grab/src/core/picker/element-picker.ts +114 -0
  74. package/packages/angular-grab/src/core/plugins/plugin-registry.ts +83 -0
  75. package/packages/angular-grab/src/core/store.ts +52 -0
  76. package/packages/angular-grab/src/core/toolbar/actions-menu.ts +178 -0
  77. package/packages/angular-grab/src/core/toolbar/comment-popover.ts +235 -0
  78. package/packages/angular-grab/src/core/toolbar/copy-actions.ts +98 -0
  79. package/packages/angular-grab/src/core/toolbar/history-popover.ts +245 -0
  80. package/packages/angular-grab/src/core/toolbar/theme-manager.ts +188 -0
  81. package/packages/angular-grab/src/core/toolbar/toolbar-icons.ts +29 -0
  82. package/packages/angular-grab/src/core/toolbar/toolbar-renderer.ts +239 -0
  83. package/packages/angular-grab/src/core/types.ts +139 -0
  84. package/packages/angular-grab/src/core/utils.ts +16 -0
  85. package/packages/angular-grab/src/esbuild-plugin/__tests__/transform.test.ts +174 -0
  86. package/packages/angular-grab/src/esbuild-plugin/index.ts +3 -0
  87. package/packages/angular-grab/src/esbuild-plugin/plugin.ts +29 -0
  88. package/packages/angular-grab/src/esbuild-plugin/scan.ts +105 -0
  89. package/packages/angular-grab/src/esbuild-plugin/transform.ts +152 -0
  90. package/packages/angular-grab/src/vite-plugin/__tests__/plugin.test.ts +84 -0
  91. package/packages/angular-grab/src/vite-plugin/index.ts +19 -0
  92. package/packages/angular-grab/src/webpack-plugin/__tests__/plugin.test.ts +72 -0
  93. package/packages/angular-grab/src/webpack-plugin/index.ts +2 -0
  94. package/packages/angular-grab/src/webpack-plugin/loader.ts +15 -0
  95. package/packages/angular-grab/src/webpack-plugin/plugin.ts +20 -0
  96. package/packages/angular-grab/tsconfig.json +15 -0
  97. package/packages/angular-grab/tsup.config.ts +119 -0
  98. package/pnpm-workspace.yaml +3 -0
  99. package/turbo.json +21 -0
@@ -0,0 +1,104 @@
1
+ import type { ElementContext, ComponentStackEntry, ComponentResolver, SourceResolver } from '../types';
2
+ import type { PluginRegistry } from '../plugins/plugin-registry';
3
+ import { generateSnippet } from './generate-snippet';
4
+ import { showToast, type ToastDetail } from '../overlay/toast';
5
+ import { filterAngularClasses } from '../utils';
6
+
7
+ export interface CopyDeps {
8
+ getComponentResolver: () => ComponentResolver | null;
9
+ getSourceResolver: () => SourceResolver | null;
10
+ getMaxContextLines: () => number;
11
+ pluginRegistry: PluginRegistry;
12
+ }
13
+
14
+ function buildSelector(el: Element): string {
15
+ const tag = el.tagName.toLowerCase();
16
+ const id = el.id ? `#${el.id}` : '';
17
+ const classes = filterAngularClasses(el.classList)
18
+ .map((c) => `.${c}`)
19
+ .join('');
20
+ return `${tag}${id}${classes}`;
21
+ }
22
+
23
+ function getCssClasses(el: Element): string[] {
24
+ return filterAngularClasses(el.classList);
25
+ }
26
+
27
+ export function buildElementContext(
28
+ element: Element,
29
+ componentResolver: ComponentResolver | null,
30
+ sourceResolver: SourceResolver | null,
31
+ ): ElementContext {
32
+ const compResult = componentResolver?.(element);
33
+ const srcResult = sourceResolver?.(element);
34
+
35
+ // Build component stack from resolver result
36
+ const componentStack: ComponentStackEntry[] = [];
37
+ if (compResult?.stack) {
38
+ for (const entry of compResult.stack) {
39
+ let filePath: string | null = null;
40
+ let line: number | null = null;
41
+ let column: number | null = null;
42
+
43
+ if (entry.hostElement && sourceResolver) {
44
+ const src = sourceResolver(entry.hostElement);
45
+ if (src) {
46
+ filePath = src.filePath;
47
+ line = src.line;
48
+ column = src.column;
49
+ }
50
+ }
51
+
52
+ componentStack.push({ name: entry.name, filePath, line, column });
53
+ }
54
+ }
55
+
56
+ return {
57
+ element,
58
+ html: element.outerHTML,
59
+ componentName: compResult?.name ?? null,
60
+ filePath: srcResult?.filePath ?? null,
61
+ line: srcResult?.line ?? null,
62
+ column: srcResult?.column ?? null,
63
+ componentStack,
64
+ selector: buildSelector(element),
65
+ cssClasses: getCssClasses(element),
66
+ };
67
+ }
68
+
69
+ export interface CopyResult {
70
+ context: ElementContext;
71
+ snippet: string;
72
+ }
73
+
74
+ export async function copyElement(element: Element, deps: CopyDeps): Promise<CopyResult | null> {
75
+ const context = buildElementContext(
76
+ element,
77
+ deps.getComponentResolver(),
78
+ deps.getSourceResolver(),
79
+ );
80
+
81
+ deps.pluginRegistry.callHook('onElementSelect', context);
82
+ deps.pluginRegistry.callHook('onBeforeCopy', context);
83
+
84
+ let snippet = generateSnippet(context, deps.getMaxContextLines());
85
+ snippet = deps.pluginRegistry.callTransformHook(snippet, context);
86
+
87
+ try {
88
+ await navigator.clipboard.writeText(snippet);
89
+ const detail: ToastDetail = {
90
+ componentName: context.componentName,
91
+ filePath: context.filePath,
92
+ line: context.line,
93
+ column: context.column,
94
+ cssClasses: context.cssClasses,
95
+ };
96
+ showToast('Copied to clipboard', detail);
97
+ deps.pluginRegistry.callHook('onCopySuccess', snippet, context, undefined);
98
+ return { context, snippet };
99
+ } catch (err) {
100
+ const error = err instanceof Error ? err : new Error(String(err));
101
+ deps.pluginRegistry.callHook('onCopyError', error);
102
+ return null;
103
+ }
104
+ }
@@ -0,0 +1,38 @@
1
+ import type { ElementContext } from '../types';
2
+ import { cleanAngularAttrs } from '../utils';
3
+
4
+ function truncateHtml(html: string, maxLines: number): string {
5
+ const lines = html.split('\n');
6
+ if (lines.length <= maxLines) return html;
7
+
8
+ return lines.slice(0, maxLines).join('\n') + '\n ...';
9
+ }
10
+
11
+ function formatLocation(name: string | null, filePath: string | null, line: number | null, column: number | null): string {
12
+ let locationLine = '';
13
+ if (name) locationLine += `in ${name}`;
14
+ if (filePath) {
15
+ const loc = filePath +
16
+ (line != null ? `:${line}` : '') +
17
+ (line != null && column != null ? `:${column}` : '');
18
+ locationLine += locationLine ? ` at ${loc}` : `at ${loc}`;
19
+ }
20
+ return locationLine;
21
+ }
22
+
23
+ export function generateSnippet(context: ElementContext, maxContextLines: number): string {
24
+ const cleaned = cleanAngularAttrs(context.html);
25
+ const truncated = truncateHtml(cleaned, maxContextLines);
26
+
27
+ const parts: string[] = [truncated];
28
+
29
+ if (context.componentStack.length > 0) {
30
+ for (const entry of context.componentStack) {
31
+ parts.push(formatLocation(entry.name, entry.filePath, entry.line, entry.column));
32
+ }
33
+ } else if (context.componentName || context.filePath) {
34
+ parts.push(formatLocation(context.componentName, context.filePath, context.line, context.column));
35
+ }
36
+
37
+ return parts.join('\n');
38
+ }
@@ -0,0 +1,10 @@
1
+ export const Z_INDEX_FREEZE = 2147483644;
2
+ export const Z_INDEX_CROSSHAIR = 2147483645;
3
+ export const Z_INDEX_OVERLAY = 2147483646;
4
+ export const Z_INDEX_LABEL = 2147483647;
5
+ export const Z_INDEX_TOOLBAR = 2147483646;
6
+ export const Z_INDEX_TOAST = 2147483647;
7
+ export const Z_INDEX_POPOVER = 2147483647;
8
+
9
+ export const TOOLBAR_TOAST_OFFSET = '72px';
10
+ export const TOOLBAR_POPOVER_OFFSET = '68px';