@designfever/web-review-kit 0.1.0 → 0.3.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 (45) hide show
  1. package/README.md +77 -179
  2. package/dist/{chunk-U5K2YGGL.js → chunk-I76WEDLA.js} +2248 -2722
  3. package/dist/chunk-I76WEDLA.js.map +1 -0
  4. package/dist/index.cjs +2346 -2603
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.d.cts +10 -6
  7. package/dist/index.d.ts +10 -6
  8. package/dist/index.js +220 -7
  9. package/dist/index.js.map +1 -1
  10. package/dist/react-shell.cjs +8953 -6632
  11. package/dist/react-shell.cjs.map +1 -1
  12. package/dist/react-shell.d.cts +8 -3
  13. package/dist/react-shell.d.ts +8 -3
  14. package/dist/react-shell.js +5956 -3636
  15. package/dist/react-shell.js.map +1 -1
  16. package/dist/{types-D_mNjOHx.d.cts → types-Cf2x5ky6.d.cts} +8 -14
  17. package/dist/{types-D_mNjOHx.d.ts → types-Cf2x5ky6.d.ts} +8 -14
  18. package/dist/vite.cjs +186 -0
  19. package/dist/vite.cjs.map +1 -0
  20. package/dist/vite.d.cts +16 -0
  21. package/dist/vite.d.ts +16 -0
  22. package/dist/vite.js +161 -0
  23. package/dist/vite.js.map +1 -0
  24. package/docs/README.md +21 -30
  25. package/docs/adaptor.sample.ts +182 -0
  26. package/docs/architecture.md +125 -0
  27. package/docs/db-setup.md +253 -0
  28. package/docs/figma-overlay.md +52 -0
  29. package/docs/grid-overlay.md +38 -0
  30. package/docs/installation.md +108 -40
  31. package/package.json +22 -6
  32. package/dist/chunk-U5K2YGGL.js.map +0 -1
  33. package/docs/adapter-handoff.md +0 -146
  34. package/docs/concept.md +0 -102
  35. package/docs/df-sheet-adapter.md +0 -336
  36. package/docs/df-sheet-next.md +0 -222
  37. package/docs/initial-plan.md +0 -226
  38. package/docs/package-split-checkpoint.md +0 -79
  39. package/docs/presence-handoff.md +0 -138
  40. package/docs/review-feedback-2026-06-20.md +0 -267
  41. package/docs/smoke-baseline-2026-06-20.md +0 -41
  42. package/docs/stabilize-ui-work-guide.md +0 -243
  43. package/docs/supabase-presence.md +0 -198
  44. package/docs/supabase-review-items.md +0 -365
  45. package/docs/supabase.md +0 -205
@@ -3,7 +3,7 @@ type ReviewItemScope = 'mobile' | 'tablet' | 'desktop' | 'wide' | 'dom';
3
3
  type ReviewWorkflowStatus = 'todo' | 'doing' | 'review' | 'hold' | 'done';
4
4
  type ReviewItemStatus = 'open' | 'resolved' | ReviewWorkflowStatus;
5
5
  type ReviewMode = 'idle' | 'note' | 'element' | 'area';
6
- type ReviewSource = 'local' | 'df-sheet' | 'supabase' | (string & {});
6
+ type ReviewSource = 'local' | 'supabase' | (string & {});
7
7
  type ReviewSubmitStatus = 'idle' | 'submitting' | 'submitted' | 'failed';
8
8
  type ReviewViewportScope = Exclude<ReviewItemScope, 'dom'>;
9
9
  type DomAnchorStrategy = 'configured-attribute' | 'id' | 'class' | 'dom-path';
@@ -20,6 +20,8 @@ interface DomAnchorCandidate {
20
20
  interface DomSourceHint {
21
21
  component?: string;
22
22
  file?: string;
23
+ line?: string;
24
+ column?: string;
23
25
  sectionId?: string;
24
26
  sectionIndex?: string;
25
27
  }
@@ -62,6 +64,7 @@ interface ReviewItem {
62
64
  kind: ReviewItemKind;
63
65
  title?: string;
64
66
  comment: string;
67
+ createdBy?: string;
65
68
  status: ReviewItemStatus;
66
69
  viewport: ViewportSize;
67
70
  devicePixelRatio?: number;
@@ -98,17 +101,6 @@ interface WebReviewKitAdapter {
98
101
  interface LocalAdapterOptions {
99
102
  storageKey?: string;
100
103
  }
101
- interface DfSheetAdapterOptions {
102
- baseUrl?: string;
103
- projectId: string;
104
- pageId: string;
105
- reviewProjectId?: string;
106
- reviewPathPrefix?: string;
107
- source?: string;
108
- issueType?: string;
109
- priority?: string;
110
- token?: string;
111
- }
112
104
  interface SupabaseReviewClient {
113
105
  from(table: string): any;
114
106
  rpc?: (fn: string, args?: Record<string, unknown>) => any;
@@ -132,11 +124,12 @@ interface NumberedReviewItem {
132
124
  item: ReviewItem;
133
125
  scope: ReviewItemScope;
134
126
  label: string;
135
- number: number;
127
+ number?: number;
136
128
  displayLabel: string;
137
129
  }
138
130
  interface WebReviewKitOptions {
139
131
  projectId: string;
132
+ userId?: string;
140
133
  adapter?: WebReviewKitAdapter;
141
134
  target?: WebReviewKitTarget | (() => WebReviewKitTarget | undefined);
142
135
  viewports?: {
@@ -150,6 +143,7 @@ interface WebReviewKitOptions {
150
143
  attribute?: string;
151
144
  };
152
145
  onRestoreItem?: (item: ReviewItem) => void | Promise<void>;
146
+ onCreateItem?: (item: ReviewItem) => void | Promise<void>;
153
147
  onItemsChange?: (items: ReviewItem[]) => void;
154
148
  onModeChange?: (mode: ReviewMode) => void;
155
149
  ui?: {
@@ -180,4 +174,4 @@ interface WebReviewKitTarget {
180
174
  getOverlayRect?: () => Pick<DOMRect, 'left' | 'top' | 'width' | 'height'>;
181
175
  }
182
176
 
183
- export type { DfSheetAdapterOptions as D, LocalAdapterOptions as L, NumberedReviewItem as N, ReviewWorkflowStatus as R, SupabaseReviewAdapterOptions as S, ViewportSize as V, WebReviewKitAdapter as W, ReviewItemStatus as a, WebReviewKitOptions as b, WebReviewKitController as c, ReviewViewportPreset as d, ReviewItem as e, ReviewItemScope as f, DomAnchor as g, DomAnchorCandidate as h, DomAnchorStrategy as i, DomSourceHint as j, RelativeSelection as k, ReviewItemKind as l, ReviewItemQuery as m, ReviewMarker as n, ReviewMode as o, ReviewPoint as p, ReviewRulerConfig as q, ReviewSelection as r, ReviewSource as s, ReviewSubmitStatus as t, ReviewViewportScope as u, SupabaseReviewClient as v, WebReviewKitTarget as w };
177
+ export type { DomAnchor as D, LocalAdapterOptions as L, NumberedReviewItem as N, ReviewWorkflowStatus as R, SupabaseReviewAdapterOptions as S, ViewportSize as V, WebReviewKitAdapter as W, ReviewItemStatus as a, WebReviewKitOptions as b, WebReviewKitController as c, ReviewViewportPreset as d, ReviewItem as e, ReviewItemScope as f, DomAnchorCandidate as g, DomAnchorStrategy as h, DomSourceHint as i, RelativeSelection as j, ReviewItemKind as k, ReviewItemQuery as l, ReviewMarker as m, ReviewMode as n, ReviewPoint as o, ReviewRulerConfig as p, ReviewSelection as q, ReviewSource as r, ReviewSubmitStatus as s, ReviewViewportScope as t, SupabaseReviewClient as u, WebReviewKitTarget as v };
@@ -3,7 +3,7 @@ type ReviewItemScope = 'mobile' | 'tablet' | 'desktop' | 'wide' | 'dom';
3
3
  type ReviewWorkflowStatus = 'todo' | 'doing' | 'review' | 'hold' | 'done';
4
4
  type ReviewItemStatus = 'open' | 'resolved' | ReviewWorkflowStatus;
5
5
  type ReviewMode = 'idle' | 'note' | 'element' | 'area';
6
- type ReviewSource = 'local' | 'df-sheet' | 'supabase' | (string & {});
6
+ type ReviewSource = 'local' | 'supabase' | (string & {});
7
7
  type ReviewSubmitStatus = 'idle' | 'submitting' | 'submitted' | 'failed';
8
8
  type ReviewViewportScope = Exclude<ReviewItemScope, 'dom'>;
9
9
  type DomAnchorStrategy = 'configured-attribute' | 'id' | 'class' | 'dom-path';
@@ -20,6 +20,8 @@ interface DomAnchorCandidate {
20
20
  interface DomSourceHint {
21
21
  component?: string;
22
22
  file?: string;
23
+ line?: string;
24
+ column?: string;
23
25
  sectionId?: string;
24
26
  sectionIndex?: string;
25
27
  }
@@ -62,6 +64,7 @@ interface ReviewItem {
62
64
  kind: ReviewItemKind;
63
65
  title?: string;
64
66
  comment: string;
67
+ createdBy?: string;
65
68
  status: ReviewItemStatus;
66
69
  viewport: ViewportSize;
67
70
  devicePixelRatio?: number;
@@ -98,17 +101,6 @@ interface WebReviewKitAdapter {
98
101
  interface LocalAdapterOptions {
99
102
  storageKey?: string;
100
103
  }
101
- interface DfSheetAdapterOptions {
102
- baseUrl?: string;
103
- projectId: string;
104
- pageId: string;
105
- reviewProjectId?: string;
106
- reviewPathPrefix?: string;
107
- source?: string;
108
- issueType?: string;
109
- priority?: string;
110
- token?: string;
111
- }
112
104
  interface SupabaseReviewClient {
113
105
  from(table: string): any;
114
106
  rpc?: (fn: string, args?: Record<string, unknown>) => any;
@@ -132,11 +124,12 @@ interface NumberedReviewItem {
132
124
  item: ReviewItem;
133
125
  scope: ReviewItemScope;
134
126
  label: string;
135
- number: number;
127
+ number?: number;
136
128
  displayLabel: string;
137
129
  }
138
130
  interface WebReviewKitOptions {
139
131
  projectId: string;
132
+ userId?: string;
140
133
  adapter?: WebReviewKitAdapter;
141
134
  target?: WebReviewKitTarget | (() => WebReviewKitTarget | undefined);
142
135
  viewports?: {
@@ -150,6 +143,7 @@ interface WebReviewKitOptions {
150
143
  attribute?: string;
151
144
  };
152
145
  onRestoreItem?: (item: ReviewItem) => void | Promise<void>;
146
+ onCreateItem?: (item: ReviewItem) => void | Promise<void>;
153
147
  onItemsChange?: (items: ReviewItem[]) => void;
154
148
  onModeChange?: (mode: ReviewMode) => void;
155
149
  ui?: {
@@ -180,4 +174,4 @@ interface WebReviewKitTarget {
180
174
  getOverlayRect?: () => Pick<DOMRect, 'left' | 'top' | 'width' | 'height'>;
181
175
  }
182
176
 
183
- export type { DfSheetAdapterOptions as D, LocalAdapterOptions as L, NumberedReviewItem as N, ReviewWorkflowStatus as R, SupabaseReviewAdapterOptions as S, ViewportSize as V, WebReviewKitAdapter as W, ReviewItemStatus as a, WebReviewKitOptions as b, WebReviewKitController as c, ReviewViewportPreset as d, ReviewItem as e, ReviewItemScope as f, DomAnchor as g, DomAnchorCandidate as h, DomAnchorStrategy as i, DomSourceHint as j, RelativeSelection as k, ReviewItemKind as l, ReviewItemQuery as m, ReviewMarker as n, ReviewMode as o, ReviewPoint as p, ReviewRulerConfig as q, ReviewSelection as r, ReviewSource as s, ReviewSubmitStatus as t, ReviewViewportScope as u, SupabaseReviewClient as v, WebReviewKitTarget as w };
177
+ export type { DomAnchor as D, LocalAdapterOptions as L, NumberedReviewItem as N, ReviewWorkflowStatus as R, SupabaseReviewAdapterOptions as S, ViewportSize as V, WebReviewKitAdapter as W, ReviewItemStatus as a, WebReviewKitOptions as b, WebReviewKitController as c, ReviewViewportPreset as d, ReviewItem as e, ReviewItemScope as f, DomAnchorCandidate as g, DomAnchorStrategy as h, DomSourceHint as i, RelativeSelection as j, ReviewItemKind as k, ReviewItemQuery as l, ReviewMarker as m, ReviewMode as n, ReviewPoint as o, ReviewRulerConfig as p, ReviewSelection as q, ReviewSource as r, ReviewSubmitStatus as s, ReviewViewportScope as t, SupabaseReviewClient as u, WebReviewKitTarget as v };
package/dist/vite.cjs ADDED
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/vite.ts
21
+ var vite_exports = {};
22
+ __export(vite_exports, {
23
+ reviewSourceLocator: () => reviewSourceLocator
24
+ });
25
+ module.exports = __toCommonJS(vite_exports);
26
+ var VIRTUAL_JSX_DEV_RUNTIME_ID = "\0@designfever/web-review-kit/source-locator/jsx-dev-runtime";
27
+ var reviewSourceLocator = (options = {}) => {
28
+ let runtimeOptions = createRuntimeOptions(options);
29
+ return {
30
+ name: "df-web-review-kit-source-locator",
31
+ enforce: "pre",
32
+ configResolved(config) {
33
+ runtimeOptions = createRuntimeOptions(options, config);
34
+ },
35
+ resolveId(id, importer) {
36
+ if (!runtimeOptions.enabled) return null;
37
+ if (id !== "react/jsx-dev-runtime") return null;
38
+ if (importer === VIRTUAL_JSX_DEV_RUNTIME_ID) return null;
39
+ return VIRTUAL_JSX_DEV_RUNTIME_ID;
40
+ },
41
+ load(id) {
42
+ if (id !== VIRTUAL_JSX_DEV_RUNTIME_ID) return null;
43
+ return createJsxDevRuntime(runtimeOptions);
44
+ }
45
+ };
46
+ };
47
+ function createRuntimeOptions(options, config) {
48
+ const attributePrefix = (options.attributePrefix ?? "data-wrk-source").replace(
49
+ /-+$/,
50
+ ""
51
+ );
52
+ const root = normalizePath(options.root ?? config?.root ?? "");
53
+ const enabled = options.enabled ?? config?.command === "serve";
54
+ return {
55
+ enabled,
56
+ root,
57
+ include: (options.include ?? []).map(createRuntimeMatcher),
58
+ exclude: (options.exclude ?? ["node_modules", "dist"]).map(
59
+ createRuntimeMatcher
60
+ ),
61
+ filePath: options.filePath ?? "relative",
62
+ line: options.line ?? true,
63
+ column: options.column ?? true,
64
+ fileAttribute: `${attributePrefix}-file`,
65
+ lineAttribute: `${attributePrefix}-line`,
66
+ columnAttribute: `${attributePrefix}-column`
67
+ };
68
+ }
69
+ function createRuntimeMatcher(pattern) {
70
+ if (pattern instanceof RegExp) {
71
+ return { type: "regex", value: pattern.source, flags: pattern.flags };
72
+ }
73
+ return { type: "path", value: normalizePath(pattern).replace(/^\.\//, "") };
74
+ }
75
+ function normalizePath(value) {
76
+ return value.replace(/\\/g, "/").replace(/\/+$/, "");
77
+ }
78
+ function createJsxDevRuntime(options) {
79
+ return `
80
+ import { Fragment, jsxDEV as baseJsxDEV } from 'react/jsx-dev-runtime';
81
+
82
+ const OPTIONS = ${JSON.stringify(options)};
83
+
84
+ export { Fragment };
85
+
86
+ export function jsxDEV(type, props, key, isStaticChildren, source, self) {
87
+ return baseJsxDEV(
88
+ type,
89
+ injectSourceProps(type, props, source),
90
+ key,
91
+ isStaticChildren,
92
+ source,
93
+ self
94
+ );
95
+ }
96
+
97
+ function injectSourceProps(type, props, source) {
98
+ if (typeof type !== 'string') return props;
99
+ if (!source || typeof source.fileName !== 'string') return props;
100
+
101
+ const sourceFile = getSourceFile(source.fileName);
102
+ if (!sourceFile) return props;
103
+
104
+ const nextProps = props ? { ...props } : {};
105
+ if (nextProps[OPTIONS.fileAttribute] == null) {
106
+ nextProps[OPTIONS.fileAttribute] = sourceFile;
107
+ }
108
+ if (OPTIONS.line && source.lineNumber != null && nextProps[OPTIONS.lineAttribute] == null) {
109
+ nextProps[OPTIONS.lineAttribute] = String(source.lineNumber);
110
+ }
111
+ if (OPTIONS.column && source.columnNumber != null && nextProps[OPTIONS.columnAttribute] == null) {
112
+ nextProps[OPTIONS.columnAttribute] = String(source.columnNumber);
113
+ }
114
+
115
+ return nextProps;
116
+ }
117
+
118
+ function getSourceFile(fileName) {
119
+ const absoluteFile = normalizePath(fileName);
120
+ const relativeFile = getRelativeFile(absoluteFile);
121
+
122
+ if (OPTIONS.include.length > 0 && !matchesAny(OPTIONS.include, absoluteFile, relativeFile)) {
123
+ return null;
124
+ }
125
+ if (matchesAny(OPTIONS.exclude, absoluteFile, relativeFile)) return null;
126
+
127
+ return OPTIONS.filePath === 'absolute' ? absoluteFile : relativeFile;
128
+ }
129
+
130
+ function getRelativeFile(absoluteFile) {
131
+ if (!OPTIONS.root) return absoluteFile;
132
+ if (absoluteFile === OPTIONS.root) return '';
133
+ if (absoluteFile.startsWith(OPTIONS.root + '/')) {
134
+ return absoluteFile.slice(OPTIONS.root.length + 1);
135
+ }
136
+
137
+ return absoluteFile;
138
+ }
139
+
140
+ function matchesAny(patterns, absoluteFile, relativeFile) {
141
+ return patterns.some((pattern) =>
142
+ matchesPattern(pattern, absoluteFile, relativeFile)
143
+ );
144
+ }
145
+
146
+ function matchesPattern(pattern, absoluteFile, relativeFile) {
147
+ if (pattern.type === 'regex') {
148
+ const regex = new RegExp(pattern.value, pattern.flags);
149
+ return regex.test(absoluteFile) || regex.test(relativeFile);
150
+ }
151
+
152
+ const value = pattern.value;
153
+ const target = isAbsolutePattern(value) ? absoluteFile : relativeFile;
154
+ if (!value.includes('*')) {
155
+ return target === value || target.startsWith(value + '/');
156
+ }
157
+
158
+ return globToRegExp(value).test(target);
159
+ }
160
+
161
+ function isAbsolutePattern(value) {
162
+ return value.startsWith('/') || /^[a-zA-Z]:\\//.test(value);
163
+ }
164
+
165
+ function globToRegExp(value) {
166
+ const source = escapeRegExp(value)
167
+ .replace(/\\\\\\*\\\\\\*/g, '.*')
168
+ .replace(/\\\\\\*/g, '[^/]*');
169
+
170
+ return new RegExp('^' + source + '$');
171
+ }
172
+
173
+ function escapeRegExp(value) {
174
+ return value.replace(/[|\\\\{}()[\\]^$+*?.]/g, '\\\\$&');
175
+ }
176
+
177
+ function normalizePath(value) {
178
+ return value.replace(/\\\\/g, '/').replace(/\\/+$/, '');
179
+ }
180
+ `;
181
+ }
182
+ // Annotate the CommonJS export names for ESM import in node:
183
+ 0 && (module.exports = {
184
+ reviewSourceLocator
185
+ });
186
+ //# sourceMappingURL=vite.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/vite.ts"],"sourcesContent":["import type { Plugin, ResolvedConfig } from 'vite';\n\ntype SourceLocatorPattern = string | RegExp;\n\nexport interface ReviewSourceLocatorOptions {\n enabled?: boolean;\n root?: string;\n include?: readonly SourceLocatorPattern[];\n exclude?: readonly SourceLocatorPattern[];\n filePath?: 'relative' | 'absolute';\n line?: boolean;\n column?: boolean;\n attributePrefix?: string;\n}\n\ntype RuntimeMatcher =\n | { type: 'path'; value: string }\n | { type: 'regex'; value: string; flags: string };\n\ntype RuntimeOptions = {\n enabled: boolean;\n root: string;\n include: RuntimeMatcher[];\n exclude: RuntimeMatcher[];\n filePath: 'relative' | 'absolute';\n line: boolean;\n column: boolean;\n fileAttribute: string;\n lineAttribute: string;\n columnAttribute: string;\n};\n\nconst VIRTUAL_JSX_DEV_RUNTIME_ID =\n '\\0@designfever/web-review-kit/source-locator/jsx-dev-runtime';\n\nexport const reviewSourceLocator = (\n options: ReviewSourceLocatorOptions = {}\n): Plugin => {\n let runtimeOptions = createRuntimeOptions(options);\n\n return {\n name: 'df-web-review-kit-source-locator',\n enforce: 'pre',\n configResolved(config) {\n runtimeOptions = createRuntimeOptions(options, config);\n },\n resolveId(id, importer) {\n if (!runtimeOptions.enabled) return null;\n if (id !== 'react/jsx-dev-runtime') return null;\n if (importer === VIRTUAL_JSX_DEV_RUNTIME_ID) return null;\n\n return VIRTUAL_JSX_DEV_RUNTIME_ID;\n },\n load(id) {\n if (id !== VIRTUAL_JSX_DEV_RUNTIME_ID) return null;\n return createJsxDevRuntime(runtimeOptions);\n },\n };\n};\n\nfunction createRuntimeOptions(\n options: ReviewSourceLocatorOptions,\n config?: ResolvedConfig\n): RuntimeOptions {\n const attributePrefix = (options.attributePrefix ?? 'data-wrk-source').replace(\n /-+$/,\n ''\n );\n const root = normalizePath(options.root ?? config?.root ?? '');\n const enabled = options.enabled ?? (config?.command === 'serve');\n\n return {\n enabled,\n root,\n include: (options.include ?? []).map(createRuntimeMatcher),\n exclude: (options.exclude ?? ['node_modules', 'dist']).map(\n createRuntimeMatcher\n ),\n filePath: options.filePath ?? 'relative',\n line: options.line ?? true,\n column: options.column ?? true,\n fileAttribute: `${attributePrefix}-file`,\n lineAttribute: `${attributePrefix}-line`,\n columnAttribute: `${attributePrefix}-column`,\n };\n}\n\nfunction createRuntimeMatcher(pattern: SourceLocatorPattern): RuntimeMatcher {\n if (pattern instanceof RegExp) {\n return { type: 'regex', value: pattern.source, flags: pattern.flags };\n }\n\n return { type: 'path', value: normalizePath(pattern).replace(/^\\.\\//, '') };\n}\n\nfunction normalizePath(value: string) {\n return value.replace(/\\\\/g, '/').replace(/\\/+$/, '');\n}\n\nfunction createJsxDevRuntime(options: RuntimeOptions) {\n return `\nimport { Fragment, jsxDEV as baseJsxDEV } from 'react/jsx-dev-runtime';\n\nconst OPTIONS = ${JSON.stringify(options)};\n\nexport { Fragment };\n\nexport function jsxDEV(type, props, key, isStaticChildren, source, self) {\n return baseJsxDEV(\n type,\n injectSourceProps(type, props, source),\n key,\n isStaticChildren,\n source,\n self\n );\n}\n\nfunction injectSourceProps(type, props, source) {\n if (typeof type !== 'string') return props;\n if (!source || typeof source.fileName !== 'string') return props;\n\n const sourceFile = getSourceFile(source.fileName);\n if (!sourceFile) return props;\n\n const nextProps = props ? { ...props } : {};\n if (nextProps[OPTIONS.fileAttribute] == null) {\n nextProps[OPTIONS.fileAttribute] = sourceFile;\n }\n if (OPTIONS.line && source.lineNumber != null && nextProps[OPTIONS.lineAttribute] == null) {\n nextProps[OPTIONS.lineAttribute] = String(source.lineNumber);\n }\n if (OPTIONS.column && source.columnNumber != null && nextProps[OPTIONS.columnAttribute] == null) {\n nextProps[OPTIONS.columnAttribute] = String(source.columnNumber);\n }\n\n return nextProps;\n}\n\nfunction getSourceFile(fileName) {\n const absoluteFile = normalizePath(fileName);\n const relativeFile = getRelativeFile(absoluteFile);\n\n if (OPTIONS.include.length > 0 && !matchesAny(OPTIONS.include, absoluteFile, relativeFile)) {\n return null;\n }\n if (matchesAny(OPTIONS.exclude, absoluteFile, relativeFile)) return null;\n\n return OPTIONS.filePath === 'absolute' ? absoluteFile : relativeFile;\n}\n\nfunction getRelativeFile(absoluteFile) {\n if (!OPTIONS.root) return absoluteFile;\n if (absoluteFile === OPTIONS.root) return '';\n if (absoluteFile.startsWith(OPTIONS.root + '/')) {\n return absoluteFile.slice(OPTIONS.root.length + 1);\n }\n\n return absoluteFile;\n}\n\nfunction matchesAny(patterns, absoluteFile, relativeFile) {\n return patterns.some((pattern) =>\n matchesPattern(pattern, absoluteFile, relativeFile)\n );\n}\n\nfunction matchesPattern(pattern, absoluteFile, relativeFile) {\n if (pattern.type === 'regex') {\n const regex = new RegExp(pattern.value, pattern.flags);\n return regex.test(absoluteFile) || regex.test(relativeFile);\n }\n\n const value = pattern.value;\n const target = isAbsolutePattern(value) ? absoluteFile : relativeFile;\n if (!value.includes('*')) {\n return target === value || target.startsWith(value + '/');\n }\n\n return globToRegExp(value).test(target);\n}\n\nfunction isAbsolutePattern(value) {\n return value.startsWith('/') || /^[a-zA-Z]:\\\\//.test(value);\n}\n\nfunction globToRegExp(value) {\n const source = escapeRegExp(value)\n .replace(/\\\\\\\\\\\\*\\\\\\\\\\\\*/g, '.*')\n .replace(/\\\\\\\\\\\\*/g, '[^/]*');\n\n return new RegExp('^' + source + '$');\n}\n\nfunction escapeRegExp(value) {\n return value.replace(/[|\\\\\\\\{}()[\\\\]^$+*?.]/g, '\\\\\\\\$&');\n}\n\nfunction normalizePath(value) {\n return value.replace(/\\\\\\\\/g, '/').replace(/\\\\/+$/, '');\n}\n`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAgCA,IAAM,6BACJ;AAEK,IAAM,sBAAsB,CACjC,UAAsC,CAAC,MAC5B;AACX,MAAI,iBAAiB,qBAAqB,OAAO;AAEjD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,eAAe,QAAQ;AACrB,uBAAiB,qBAAqB,SAAS,MAAM;AAAA,IACvD;AAAA,IACA,UAAU,IAAI,UAAU;AACtB,UAAI,CAAC,eAAe,QAAS,QAAO;AACpC,UAAI,OAAO,wBAAyB,QAAO;AAC3C,UAAI,aAAa,2BAA4B,QAAO;AAEpD,aAAO;AAAA,IACT;AAAA,IACA,KAAK,IAAI;AACP,UAAI,OAAO,2BAA4B,QAAO;AAC9C,aAAO,oBAAoB,cAAc;AAAA,IAC3C;AAAA,EACF;AACF;AAEA,SAAS,qBACP,SACA,QACgB;AAChB,QAAM,mBAAmB,QAAQ,mBAAmB,mBAAmB;AAAA,IACrE;AAAA,IACA;AAAA,EACF;AACA,QAAM,OAAO,cAAc,QAAQ,QAAQ,QAAQ,QAAQ,EAAE;AAC7D,QAAM,UAAU,QAAQ,WAAY,QAAQ,YAAY;AAExD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,UAAU,QAAQ,WAAW,CAAC,GAAG,IAAI,oBAAoB;AAAA,IACzD,UAAU,QAAQ,WAAW,CAAC,gBAAgB,MAAM,GAAG;AAAA,MACrD;AAAA,IACF;AAAA,IACA,UAAU,QAAQ,YAAY;AAAA,IAC9B,MAAM,QAAQ,QAAQ;AAAA,IACtB,QAAQ,QAAQ,UAAU;AAAA,IAC1B,eAAe,GAAG,eAAe;AAAA,IACjC,eAAe,GAAG,eAAe;AAAA,IACjC,iBAAiB,GAAG,eAAe;AAAA,EACrC;AACF;AAEA,SAAS,qBAAqB,SAA+C;AAC3E,MAAI,mBAAmB,QAAQ;AAC7B,WAAO,EAAE,MAAM,SAAS,OAAO,QAAQ,QAAQ,OAAO,QAAQ,MAAM;AAAA,EACtE;AAEA,SAAO,EAAE,MAAM,QAAQ,OAAO,cAAc,OAAO,EAAE,QAAQ,SAAS,EAAE,EAAE;AAC5E;AAEA,SAAS,cAAc,OAAe;AACpC,SAAO,MAAM,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AACrD;AAEA,SAAS,oBAAoB,SAAyB;AACpD,SAAO;AAAA;AAAA;AAAA,kBAGS,KAAK,UAAU,OAAO,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmGzC;","names":[]}
@@ -0,0 +1,16 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ type SourceLocatorPattern = string | RegExp;
4
+ interface ReviewSourceLocatorOptions {
5
+ enabled?: boolean;
6
+ root?: string;
7
+ include?: readonly SourceLocatorPattern[];
8
+ exclude?: readonly SourceLocatorPattern[];
9
+ filePath?: 'relative' | 'absolute';
10
+ line?: boolean;
11
+ column?: boolean;
12
+ attributePrefix?: string;
13
+ }
14
+ declare const reviewSourceLocator: (options?: ReviewSourceLocatorOptions) => Plugin;
15
+
16
+ export { type ReviewSourceLocatorOptions, reviewSourceLocator };
package/dist/vite.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ type SourceLocatorPattern = string | RegExp;
4
+ interface ReviewSourceLocatorOptions {
5
+ enabled?: boolean;
6
+ root?: string;
7
+ include?: readonly SourceLocatorPattern[];
8
+ exclude?: readonly SourceLocatorPattern[];
9
+ filePath?: 'relative' | 'absolute';
10
+ line?: boolean;
11
+ column?: boolean;
12
+ attributePrefix?: string;
13
+ }
14
+ declare const reviewSourceLocator: (options?: ReviewSourceLocatorOptions) => Plugin;
15
+
16
+ export { type ReviewSourceLocatorOptions, reviewSourceLocator };
package/dist/vite.js ADDED
@@ -0,0 +1,161 @@
1
+ // src/vite.ts
2
+ var VIRTUAL_JSX_DEV_RUNTIME_ID = "\0@designfever/web-review-kit/source-locator/jsx-dev-runtime";
3
+ var reviewSourceLocator = (options = {}) => {
4
+ let runtimeOptions = createRuntimeOptions(options);
5
+ return {
6
+ name: "df-web-review-kit-source-locator",
7
+ enforce: "pre",
8
+ configResolved(config) {
9
+ runtimeOptions = createRuntimeOptions(options, config);
10
+ },
11
+ resolveId(id, importer) {
12
+ if (!runtimeOptions.enabled) return null;
13
+ if (id !== "react/jsx-dev-runtime") return null;
14
+ if (importer === VIRTUAL_JSX_DEV_RUNTIME_ID) return null;
15
+ return VIRTUAL_JSX_DEV_RUNTIME_ID;
16
+ },
17
+ load(id) {
18
+ if (id !== VIRTUAL_JSX_DEV_RUNTIME_ID) return null;
19
+ return createJsxDevRuntime(runtimeOptions);
20
+ }
21
+ };
22
+ };
23
+ function createRuntimeOptions(options, config) {
24
+ const attributePrefix = (options.attributePrefix ?? "data-wrk-source").replace(
25
+ /-+$/,
26
+ ""
27
+ );
28
+ const root = normalizePath(options.root ?? config?.root ?? "");
29
+ const enabled = options.enabled ?? config?.command === "serve";
30
+ return {
31
+ enabled,
32
+ root,
33
+ include: (options.include ?? []).map(createRuntimeMatcher),
34
+ exclude: (options.exclude ?? ["node_modules", "dist"]).map(
35
+ createRuntimeMatcher
36
+ ),
37
+ filePath: options.filePath ?? "relative",
38
+ line: options.line ?? true,
39
+ column: options.column ?? true,
40
+ fileAttribute: `${attributePrefix}-file`,
41
+ lineAttribute: `${attributePrefix}-line`,
42
+ columnAttribute: `${attributePrefix}-column`
43
+ };
44
+ }
45
+ function createRuntimeMatcher(pattern) {
46
+ if (pattern instanceof RegExp) {
47
+ return { type: "regex", value: pattern.source, flags: pattern.flags };
48
+ }
49
+ return { type: "path", value: normalizePath(pattern).replace(/^\.\//, "") };
50
+ }
51
+ function normalizePath(value) {
52
+ return value.replace(/\\/g, "/").replace(/\/+$/, "");
53
+ }
54
+ function createJsxDevRuntime(options) {
55
+ return `
56
+ import { Fragment, jsxDEV as baseJsxDEV } from 'react/jsx-dev-runtime';
57
+
58
+ const OPTIONS = ${JSON.stringify(options)};
59
+
60
+ export { Fragment };
61
+
62
+ export function jsxDEV(type, props, key, isStaticChildren, source, self) {
63
+ return baseJsxDEV(
64
+ type,
65
+ injectSourceProps(type, props, source),
66
+ key,
67
+ isStaticChildren,
68
+ source,
69
+ self
70
+ );
71
+ }
72
+
73
+ function injectSourceProps(type, props, source) {
74
+ if (typeof type !== 'string') return props;
75
+ if (!source || typeof source.fileName !== 'string') return props;
76
+
77
+ const sourceFile = getSourceFile(source.fileName);
78
+ if (!sourceFile) return props;
79
+
80
+ const nextProps = props ? { ...props } : {};
81
+ if (nextProps[OPTIONS.fileAttribute] == null) {
82
+ nextProps[OPTIONS.fileAttribute] = sourceFile;
83
+ }
84
+ if (OPTIONS.line && source.lineNumber != null && nextProps[OPTIONS.lineAttribute] == null) {
85
+ nextProps[OPTIONS.lineAttribute] = String(source.lineNumber);
86
+ }
87
+ if (OPTIONS.column && source.columnNumber != null && nextProps[OPTIONS.columnAttribute] == null) {
88
+ nextProps[OPTIONS.columnAttribute] = String(source.columnNumber);
89
+ }
90
+
91
+ return nextProps;
92
+ }
93
+
94
+ function getSourceFile(fileName) {
95
+ const absoluteFile = normalizePath(fileName);
96
+ const relativeFile = getRelativeFile(absoluteFile);
97
+
98
+ if (OPTIONS.include.length > 0 && !matchesAny(OPTIONS.include, absoluteFile, relativeFile)) {
99
+ return null;
100
+ }
101
+ if (matchesAny(OPTIONS.exclude, absoluteFile, relativeFile)) return null;
102
+
103
+ return OPTIONS.filePath === 'absolute' ? absoluteFile : relativeFile;
104
+ }
105
+
106
+ function getRelativeFile(absoluteFile) {
107
+ if (!OPTIONS.root) return absoluteFile;
108
+ if (absoluteFile === OPTIONS.root) return '';
109
+ if (absoluteFile.startsWith(OPTIONS.root + '/')) {
110
+ return absoluteFile.slice(OPTIONS.root.length + 1);
111
+ }
112
+
113
+ return absoluteFile;
114
+ }
115
+
116
+ function matchesAny(patterns, absoluteFile, relativeFile) {
117
+ return patterns.some((pattern) =>
118
+ matchesPattern(pattern, absoluteFile, relativeFile)
119
+ );
120
+ }
121
+
122
+ function matchesPattern(pattern, absoluteFile, relativeFile) {
123
+ if (pattern.type === 'regex') {
124
+ const regex = new RegExp(pattern.value, pattern.flags);
125
+ return regex.test(absoluteFile) || regex.test(relativeFile);
126
+ }
127
+
128
+ const value = pattern.value;
129
+ const target = isAbsolutePattern(value) ? absoluteFile : relativeFile;
130
+ if (!value.includes('*')) {
131
+ return target === value || target.startsWith(value + '/');
132
+ }
133
+
134
+ return globToRegExp(value).test(target);
135
+ }
136
+
137
+ function isAbsolutePattern(value) {
138
+ return value.startsWith('/') || /^[a-zA-Z]:\\//.test(value);
139
+ }
140
+
141
+ function globToRegExp(value) {
142
+ const source = escapeRegExp(value)
143
+ .replace(/\\\\\\*\\\\\\*/g, '.*')
144
+ .replace(/\\\\\\*/g, '[^/]*');
145
+
146
+ return new RegExp('^' + source + '$');
147
+ }
148
+
149
+ function escapeRegExp(value) {
150
+ return value.replace(/[|\\\\{}()[\\]^$+*?.]/g, '\\\\$&');
151
+ }
152
+
153
+ function normalizePath(value) {
154
+ return value.replace(/\\\\/g, '/').replace(/\\/+$/, '');
155
+ }
156
+ `;
157
+ }
158
+ export {
159
+ reviewSourceLocator
160
+ };
161
+ //# sourceMappingURL=vite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/vite.ts"],"sourcesContent":["import type { Plugin, ResolvedConfig } from 'vite';\n\ntype SourceLocatorPattern = string | RegExp;\n\nexport interface ReviewSourceLocatorOptions {\n enabled?: boolean;\n root?: string;\n include?: readonly SourceLocatorPattern[];\n exclude?: readonly SourceLocatorPattern[];\n filePath?: 'relative' | 'absolute';\n line?: boolean;\n column?: boolean;\n attributePrefix?: string;\n}\n\ntype RuntimeMatcher =\n | { type: 'path'; value: string }\n | { type: 'regex'; value: string; flags: string };\n\ntype RuntimeOptions = {\n enabled: boolean;\n root: string;\n include: RuntimeMatcher[];\n exclude: RuntimeMatcher[];\n filePath: 'relative' | 'absolute';\n line: boolean;\n column: boolean;\n fileAttribute: string;\n lineAttribute: string;\n columnAttribute: string;\n};\n\nconst VIRTUAL_JSX_DEV_RUNTIME_ID =\n '\\0@designfever/web-review-kit/source-locator/jsx-dev-runtime';\n\nexport const reviewSourceLocator = (\n options: ReviewSourceLocatorOptions = {}\n): Plugin => {\n let runtimeOptions = createRuntimeOptions(options);\n\n return {\n name: 'df-web-review-kit-source-locator',\n enforce: 'pre',\n configResolved(config) {\n runtimeOptions = createRuntimeOptions(options, config);\n },\n resolveId(id, importer) {\n if (!runtimeOptions.enabled) return null;\n if (id !== 'react/jsx-dev-runtime') return null;\n if (importer === VIRTUAL_JSX_DEV_RUNTIME_ID) return null;\n\n return VIRTUAL_JSX_DEV_RUNTIME_ID;\n },\n load(id) {\n if (id !== VIRTUAL_JSX_DEV_RUNTIME_ID) return null;\n return createJsxDevRuntime(runtimeOptions);\n },\n };\n};\n\nfunction createRuntimeOptions(\n options: ReviewSourceLocatorOptions,\n config?: ResolvedConfig\n): RuntimeOptions {\n const attributePrefix = (options.attributePrefix ?? 'data-wrk-source').replace(\n /-+$/,\n ''\n );\n const root = normalizePath(options.root ?? config?.root ?? '');\n const enabled = options.enabled ?? (config?.command === 'serve');\n\n return {\n enabled,\n root,\n include: (options.include ?? []).map(createRuntimeMatcher),\n exclude: (options.exclude ?? ['node_modules', 'dist']).map(\n createRuntimeMatcher\n ),\n filePath: options.filePath ?? 'relative',\n line: options.line ?? true,\n column: options.column ?? true,\n fileAttribute: `${attributePrefix}-file`,\n lineAttribute: `${attributePrefix}-line`,\n columnAttribute: `${attributePrefix}-column`,\n };\n}\n\nfunction createRuntimeMatcher(pattern: SourceLocatorPattern): RuntimeMatcher {\n if (pattern instanceof RegExp) {\n return { type: 'regex', value: pattern.source, flags: pattern.flags };\n }\n\n return { type: 'path', value: normalizePath(pattern).replace(/^\\.\\//, '') };\n}\n\nfunction normalizePath(value: string) {\n return value.replace(/\\\\/g, '/').replace(/\\/+$/, '');\n}\n\nfunction createJsxDevRuntime(options: RuntimeOptions) {\n return `\nimport { Fragment, jsxDEV as baseJsxDEV } from 'react/jsx-dev-runtime';\n\nconst OPTIONS = ${JSON.stringify(options)};\n\nexport { Fragment };\n\nexport function jsxDEV(type, props, key, isStaticChildren, source, self) {\n return baseJsxDEV(\n type,\n injectSourceProps(type, props, source),\n key,\n isStaticChildren,\n source,\n self\n );\n}\n\nfunction injectSourceProps(type, props, source) {\n if (typeof type !== 'string') return props;\n if (!source || typeof source.fileName !== 'string') return props;\n\n const sourceFile = getSourceFile(source.fileName);\n if (!sourceFile) return props;\n\n const nextProps = props ? { ...props } : {};\n if (nextProps[OPTIONS.fileAttribute] == null) {\n nextProps[OPTIONS.fileAttribute] = sourceFile;\n }\n if (OPTIONS.line && source.lineNumber != null && nextProps[OPTIONS.lineAttribute] == null) {\n nextProps[OPTIONS.lineAttribute] = String(source.lineNumber);\n }\n if (OPTIONS.column && source.columnNumber != null && nextProps[OPTIONS.columnAttribute] == null) {\n nextProps[OPTIONS.columnAttribute] = String(source.columnNumber);\n }\n\n return nextProps;\n}\n\nfunction getSourceFile(fileName) {\n const absoluteFile = normalizePath(fileName);\n const relativeFile = getRelativeFile(absoluteFile);\n\n if (OPTIONS.include.length > 0 && !matchesAny(OPTIONS.include, absoluteFile, relativeFile)) {\n return null;\n }\n if (matchesAny(OPTIONS.exclude, absoluteFile, relativeFile)) return null;\n\n return OPTIONS.filePath === 'absolute' ? absoluteFile : relativeFile;\n}\n\nfunction getRelativeFile(absoluteFile) {\n if (!OPTIONS.root) return absoluteFile;\n if (absoluteFile === OPTIONS.root) return '';\n if (absoluteFile.startsWith(OPTIONS.root + '/')) {\n return absoluteFile.slice(OPTIONS.root.length + 1);\n }\n\n return absoluteFile;\n}\n\nfunction matchesAny(patterns, absoluteFile, relativeFile) {\n return patterns.some((pattern) =>\n matchesPattern(pattern, absoluteFile, relativeFile)\n );\n}\n\nfunction matchesPattern(pattern, absoluteFile, relativeFile) {\n if (pattern.type === 'regex') {\n const regex = new RegExp(pattern.value, pattern.flags);\n return regex.test(absoluteFile) || regex.test(relativeFile);\n }\n\n const value = pattern.value;\n const target = isAbsolutePattern(value) ? absoluteFile : relativeFile;\n if (!value.includes('*')) {\n return target === value || target.startsWith(value + '/');\n }\n\n return globToRegExp(value).test(target);\n}\n\nfunction isAbsolutePattern(value) {\n return value.startsWith('/') || /^[a-zA-Z]:\\\\//.test(value);\n}\n\nfunction globToRegExp(value) {\n const source = escapeRegExp(value)\n .replace(/\\\\\\\\\\\\*\\\\\\\\\\\\*/g, '.*')\n .replace(/\\\\\\\\\\\\*/g, '[^/]*');\n\n return new RegExp('^' + source + '$');\n}\n\nfunction escapeRegExp(value) {\n return value.replace(/[|\\\\\\\\{}()[\\\\]^$+*?.]/g, '\\\\\\\\$&');\n}\n\nfunction normalizePath(value) {\n return value.replace(/\\\\\\\\/g, '/').replace(/\\\\/+$/, '');\n}\n`;\n}\n"],"mappings":";AAgCA,IAAM,6BACJ;AAEK,IAAM,sBAAsB,CACjC,UAAsC,CAAC,MAC5B;AACX,MAAI,iBAAiB,qBAAqB,OAAO;AAEjD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,eAAe,QAAQ;AACrB,uBAAiB,qBAAqB,SAAS,MAAM;AAAA,IACvD;AAAA,IACA,UAAU,IAAI,UAAU;AACtB,UAAI,CAAC,eAAe,QAAS,QAAO;AACpC,UAAI,OAAO,wBAAyB,QAAO;AAC3C,UAAI,aAAa,2BAA4B,QAAO;AAEpD,aAAO;AAAA,IACT;AAAA,IACA,KAAK,IAAI;AACP,UAAI,OAAO,2BAA4B,QAAO;AAC9C,aAAO,oBAAoB,cAAc;AAAA,IAC3C;AAAA,EACF;AACF;AAEA,SAAS,qBACP,SACA,QACgB;AAChB,QAAM,mBAAmB,QAAQ,mBAAmB,mBAAmB;AAAA,IACrE;AAAA,IACA;AAAA,EACF;AACA,QAAM,OAAO,cAAc,QAAQ,QAAQ,QAAQ,QAAQ,EAAE;AAC7D,QAAM,UAAU,QAAQ,WAAY,QAAQ,YAAY;AAExD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,UAAU,QAAQ,WAAW,CAAC,GAAG,IAAI,oBAAoB;AAAA,IACzD,UAAU,QAAQ,WAAW,CAAC,gBAAgB,MAAM,GAAG;AAAA,MACrD;AAAA,IACF;AAAA,IACA,UAAU,QAAQ,YAAY;AAAA,IAC9B,MAAM,QAAQ,QAAQ;AAAA,IACtB,QAAQ,QAAQ,UAAU;AAAA,IAC1B,eAAe,GAAG,eAAe;AAAA,IACjC,eAAe,GAAG,eAAe;AAAA,IACjC,iBAAiB,GAAG,eAAe;AAAA,EACrC;AACF;AAEA,SAAS,qBAAqB,SAA+C;AAC3E,MAAI,mBAAmB,QAAQ;AAC7B,WAAO,EAAE,MAAM,SAAS,OAAO,QAAQ,QAAQ,OAAO,QAAQ,MAAM;AAAA,EACtE;AAEA,SAAO,EAAE,MAAM,QAAQ,OAAO,cAAc,OAAO,EAAE,QAAQ,SAAS,EAAE,EAAE;AAC5E;AAEA,SAAS,cAAc,OAAe;AACpC,SAAO,MAAM,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AACrD;AAEA,SAAS,oBAAoB,SAAyB;AACpD,SAAO;AAAA;AAAA;AAAA,kBAGS,KAAK,UAAU,OAAO,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmGzC;","names":[]}
package/docs/README.md CHANGED
@@ -1,37 +1,28 @@
1
1
  # df-web-review-kit docs
2
2
 
3
- 현재 문서의 읽는 순서:
3
+ Public docs are intentionally small. Keep implementation history, handoff notes, and internal operator decisions out of this package documentation.
4
4
 
5
- 1. [Concept](concept.md)
6
- 2. [Installation](installation.md)
7
- 3. [Supabase setup](supabase.md)
8
- 4. [Supabase review item SQL](supabase-review-items.md)
9
- 5. [Supabase presence](supabase-presence.md)
10
- 6. [Adapter handoff](adapter-handoff.md)
11
- 7. [df-sheet next](df-sheet-next.md)
12
- 8. [Review feedback 2026-06-20](review-feedback-2026-06-20.md)
13
- 9. [Stabilize UI work guide](stabilize-ui-work-guide.md)
14
- 10. [Smoke baseline 2026-06-20](smoke-baseline-2026-06-20.md)
15
- 11. [Package split checkpoint](package-split-checkpoint.md)
5
+ ## Read This Order
16
6
 
17
- ## 문서 역할
7
+ 1. [Installation](installation.md)
8
+ 2. [Custom adapter sample](adaptor.sample.ts)
9
+ 3. [DB setup](db-setup.md)
10
+ 4. [Architecture and runtime logic](architecture.md)
11
+ 5. [Figma overlay](figma-overlay.md)
12
+ 6. [Grid overlay](grid-overlay.md)
18
13
 
19
- - `concept.md`: 왜 이 package가 있고 어떤 문제를 해결하는지.
20
- - `installation.md`: host project에 설치하고 `/review` route에 붙이는 방법.
21
- - `supabase.md`: Supabase를 remote QA 저장소와 presence backend로 연결하는 방법.
22
- - `supabase-review-items.md`: 실제 table/RPC/RLS SQL.
23
- - `supabase-presence.md`: Supabase Realtime Presence adapter 구조.
24
- - `adapter-handoff.md`: package repo로 옮길 때 필요한 adapter contract 정리.
25
- - `df-sheet-next.md`: df-sheet를 source of record로 쓸 때 필요한 제품/API 방향.
26
- - `review-feedback-2026-06-20.md`: 빵빵/팡팡/오빵 package 리뷰 메모와 우선순위.
27
- - `stabilize-ui-work-guide.md`: anchor 안정화, UI token화, package split 전 작업 순서.
28
- - `smoke-baseline-2026-06-20.md`: 761 현재 기능 smoke 기준선 결과.
29
- - `package-split-checkpoint.md`: 765 package export/file/peer dependency와 host 소비 경계.
30
- - `initial-plan.md`: 초기 계획 기록. 현재 기준 문서가 아니다.
14
+ ## Document Roles
31
15
 
32
- ## 현재 기준
16
+ - `installation.md`: install the npm package, create the `/review` route, wire adapters, and run checks.
17
+ - `adaptor.sample.ts`: copyable starting point for host-owned remote adapters.
18
+ - `db-setup.md`: optional Supabase review item table/RPC/RLS/presence setup.
19
+ - `architecture.md`: core/runtime, React shell, coordinate, anchor, and feature boundary notes.
20
+ - `figma-overlay.md`: host requirements for the Figma overlay toggle.
21
+ - `grid-overlay.md`: host requirements for the grid/helper overlay toggle.
33
22
 
34
- - `local`: 개인 draft 저장소.
35
- - `supabase`: 팀 공유 remote 저장소.
36
- - `df-sheet`: 나중에 issue workflow로 연결할 수 있는 remote destination.
37
- - local 번호는 개인 draft용이고, remote 번호는 remote source가 새로 발급하는 canonical 번호다.
23
+ ## Boundary
24
+
25
+ - `local` is the default draft storage.
26
+ - `supabase` is an optional adapter sample for users who configure their own backend.
27
+ - `presence` is temporary session state, not QA item persistence.
28
+ - `kuku` and operator keys belong to OpenClaw or a backend/admin service, not this public package.