feedly-widget 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # feedly-widget
2
+
3
+ Visual feedback annotation widget. Drop into any web app and let testers annotate live.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install feedly-widget
9
+ ```
10
+
11
+ ## Use
12
+
13
+ ```ts
14
+ import Feedly from 'feedly-widget'
15
+
16
+ Feedly.init({ projectId: 'YOUR_PROJECT_ID' })
17
+ ```
18
+
19
+ That's it. The widget renders nothing until an admin enables the session for your project from the Feedly dashboard. When enabled, a small floating "F" button appears at the bottom right. Click it → name → annotate.
20
+
21
+ ### Custom Supabase endpoint
22
+
23
+ The widget is preconfigured with the Feedly hosted Supabase endpoint at build time. To point it at your own:
24
+
25
+ ```ts
26
+ Feedly.init({
27
+ projectId: 'YOUR_PROJECT_ID',
28
+ supabaseUrl: 'https://YOUR-PROJECT.supabase.co',
29
+ supabaseAnonKey: 'YOUR-ANON-KEY',
30
+ })
31
+ ```
32
+
33
+ ### Tear down
34
+
35
+ ```ts
36
+ Feedly.destroy()
37
+ ```
38
+
39
+ ## How it works
40
+
41
+ - Mounts a Shadow DOM root on `document.body` so its CSS can't bleed into your app and vice versa.
42
+ - Subscribes to Supabase Realtime — the widget appears/disappears instantly when the admin toggles the session, no polling.
43
+ - Annotations are stored against the full `window.location.href` so they restore correctly when the tester revisits the page.
44
+ - Testers are identified by a `device_id` UUID in `localStorage`; no signup, no auth.
package/dist/App.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ type Props = {
2
+ projectId: string;
3
+ supabaseUrl: string;
4
+ supabaseAnonKey: string;
5
+ requireInvite: boolean;
6
+ shadowRoot: ShadowRoot;
7
+ pinsContainer: Element;
8
+ };
9
+ export default function App({ projectId, supabaseUrl, supabaseAnonKey, requireInvite, pinsContainer, }: Props): import("react/jsx-runtime").JSX.Element | null;
10
+ export {};
@@ -0,0 +1,13 @@
1
+ import type { Annotation } from '../types';
2
+ import type { AnnotationsByPage } from '../hooks/useAnnotationsList';
3
+ type Props = {
4
+ grouped: AnnotationsByPage;
5
+ loading: boolean;
6
+ fallbackColor: string;
7
+ fallbackName: string;
8
+ currentPageUrl: string;
9
+ onPick: (annotation: Annotation) => void;
10
+ onClose: () => void;
11
+ };
12
+ export declare function CommentList({ grouped, loading, fallbackColor, fallbackName, currentPageUrl, onPick, onClose, }: Props): import("react/jsx-runtime").JSX.Element;
13
+ export {};
@@ -0,0 +1,36 @@
1
+ import type { SupabaseClient } from '@supabase/supabase-js';
2
+ import type { Anchor, Annotation, AnnotationStatus, AnnotationType, ShapeData } from '../types';
3
+ type Props = {
4
+ tool: AnnotationType | null;
5
+ testerColor: string;
6
+ testerName: string;
7
+ currentTesterId: string | null;
8
+ isAdmin: boolean;
9
+ annotations: Annotation[];
10
+ onComplete: (type: AnnotationType, shape: ShapeData, comment: string, anchor: Anchor | null, noteOffset: {
11
+ x: number;
12
+ y: number;
13
+ } | null) => Promise<boolean>;
14
+ onMove: (id: string, newShape: ShapeData) => Promise<boolean>;
15
+ onSetStatus: (id: string, status: AnnotationStatus, comment?: string) => Promise<{
16
+ ok: true;
17
+ } | {
18
+ ok: false;
19
+ error: string;
20
+ }>;
21
+ onOpenDetails: (id: string) => void;
22
+ onEditComment: (id: string, newComment: string, noteOffset: {
23
+ x: number;
24
+ y: number;
25
+ } | null) => Promise<boolean>;
26
+ onDelete: (id: string) => Promise<boolean>;
27
+ pinRequest: {
28
+ id: string;
29
+ ts: number;
30
+ } | null;
31
+ pinsContainer: Element;
32
+ onDiscardDraft: () => void;
33
+ supabase: SupabaseClient;
34
+ };
35
+ export declare function DrawingOverlay({ tool, testerColor, testerName, currentTesterId, isAdmin, annotations, onComplete, onMove, onSetStatus, onOpenDetails, onEditComment, onDelete, pinRequest, pinsContainer, onDiscardDraft, supabase, }: Props): import("react/jsx-runtime").JSX.Element;
36
+ export {};
@@ -0,0 +1,13 @@
1
+ import type { FlowStep } from '../types';
2
+ type Props = {
3
+ recording: boolean;
4
+ onStepsChange: (steps: FlowStep[]) => void;
5
+ steps: FlowStep[];
6
+ };
7
+ export declare function FlowRecorder({ recording, steps, onStepsChange }: Props): null;
8
+ export declare function FlowNoteEntry({ onSubmit, onCancel, disabled, }: {
9
+ onSubmit: (note: string) => void;
10
+ onCancel: () => void;
11
+ disabled?: boolean;
12
+ }): import("react/jsx-runtime").JSX.Element;
13
+ export {};
@@ -0,0 +1,12 @@
1
+ import type { Flow } from '../types';
2
+ type Props = {
3
+ flow: Flow;
4
+ stepIndex: number;
5
+ preStart: boolean;
6
+ onStart: () => void;
7
+ onAdvance: () => void;
8
+ onClose: () => void;
9
+ ringColor: string;
10
+ };
11
+ export declare function FlowReplayer({ flow, stepIndex, preStart, onStart, onAdvance, onClose, ringColor, }: Props): import("react/jsx-runtime").JSX.Element;
12
+ export {};
@@ -0,0 +1,13 @@
1
+ type Props = {
2
+ onSubmit: (name: string, email?: string) => Promise<boolean>;
3
+ onSendMagicLink: (email: string) => Promise<{
4
+ ok: true;
5
+ } | {
6
+ ok: false;
7
+ error: string;
8
+ }>;
9
+ onDone: () => void;
10
+ onCancel: () => void;
11
+ };
12
+ export declare function NameEntry({ onSubmit, onSendMagicLink, onDone, onCancel, }: Props): import("react/jsx-runtime").JSX.Element;
13
+ export {};
@@ -0,0 +1,10 @@
1
+ import type { SupabaseClient } from '@supabase/supabase-js';
2
+ import type { Annotation, ShapeData } from '../types';
3
+ type Props = {
4
+ supabase: SupabaseClient;
5
+ annotation: Annotation;
6
+ currentShape: ShapeData;
7
+ onClose: () => void;
8
+ };
9
+ export declare function SnapshotPortal({ supabase, annotation, currentShape, onClose, }: Props): import("react/jsx-runtime").JSX.Element | null;
10
+ export {};
@@ -0,0 +1,41 @@
1
+ import type { AnnotationStatus, Point } from '../types';
2
+ type Props = {
3
+ anchor: Point;
4
+ anchorFixed?: boolean;
5
+ color: string;
6
+ testerName: string;
7
+ existingComment?: string | null;
8
+ createdAt?: string;
9
+ noteOffset?: {
10
+ x: number;
11
+ y: number;
12
+ } | null;
13
+ editable?: boolean;
14
+ onSave?: (comment: string, offset: {
15
+ x: number;
16
+ y: number;
17
+ } | null) => Promise<void> | void;
18
+ onCancel?: () => void;
19
+ status?: AnnotationStatus;
20
+ canMarkFixed?: boolean;
21
+ canVerify?: boolean;
22
+ jiraTicket?: string | null;
23
+ onMarkFixed?: () => Promise<void> | void;
24
+ onConfirmFixed?: () => Promise<void> | void;
25
+ onStillBroken?: (comment: string) => Promise<{
26
+ ok: boolean;
27
+ } | void>;
28
+ onOpenDetails?: () => void;
29
+ canEdit?: boolean;
30
+ canDelete?: boolean;
31
+ onEdit?: (newComment: string, offset: {
32
+ x: number;
33
+ y: number;
34
+ } | null) => Promise<boolean | void>;
35
+ onDelete?: () => Promise<boolean | void>;
36
+ hasSnapshot?: boolean;
37
+ snapshotShown?: boolean;
38
+ onToggleSnapshot?: () => void;
39
+ };
40
+ export declare function StickyNote({ anchor, anchorFixed, color, testerName, existingComment, createdAt, noteOffset, editable, onSave, onCancel, status, canMarkFixed, canVerify, jiraTicket, onMarkFixed, onConfirmFixed, onStillBroken, onOpenDetails, canEdit, canDelete, onEdit, onDelete, hasSnapshot, snapshotShown, onToggleSnapshot, }: Props): import("react/jsx-runtime").JSX.Element;
41
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { Annotation } from '../types';
2
+ type Props = {
3
+ annotation: Annotation;
4
+ fallbackName: string;
5
+ fallbackColor: string;
6
+ onClose: () => void;
7
+ };
8
+ export declare function TechDetailsPanel({ annotation, fallbackName, fallbackColor, onClose, }: Props): import("react/jsx-runtime").JSX.Element;
9
+ export {};
@@ -0,0 +1,33 @@
1
+ import type { AnnotationType, Flow, FlowStep, TesterRef } from '../types';
2
+ type Props = {
3
+ active: AnnotationType | null;
4
+ testerName: string;
5
+ testerColor: string;
6
+ onSelect: (tool: AnnotationType) => void;
7
+ annotationsHidden: boolean;
8
+ onToggleAnnotations: () => void;
9
+ listOpen: boolean;
10
+ onToggleList: () => void;
11
+ flowsEnabled?: boolean;
12
+ recording: boolean;
13
+ recordingSteps: FlowStep[];
14
+ onStartRecording: () => void;
15
+ onStopRecording: () => void;
16
+ onAttachNote: (note: string) => void;
17
+ flows: Flow[];
18
+ flowsLoading: boolean;
19
+ flowsOpen: boolean;
20
+ onToggleFlows: () => void;
21
+ onPickFlow: (flow: Flow) => void;
22
+ onDeleteFlow: (id: string) => Promise<unknown>;
23
+ currentTesterId: string | null;
24
+ isAdmin?: boolean;
25
+ testers?: TesterRef[];
26
+ hiddenTesterIds?: Set<string>;
27
+ onToggleTester?: (id: string) => void;
28
+ onShowAll?: () => void;
29
+ onHideAll?: () => void;
30
+ pageCount?: number;
31
+ };
32
+ export declare function Toolbar({ active, testerName, testerColor, onSelect, annotationsHidden, onToggleAnnotations, listOpen, onToggleList, flowsEnabled, recording, recordingSteps, onStartRecording, onStopRecording, onAttachNote, flows, flowsLoading, flowsOpen, onToggleFlows, onPickFlow, onDeleteFlow, currentTesterId, isAdmin, testers, hiddenTesterIds, onToggleTester, onShowAll, onHideAll, pageCount, }: Props): import("react/jsx-runtime").JSX.Element;
33
+ export {};
@@ -0,0 +1,7 @@
1
+ type Props = {
2
+ open: boolean;
3
+ hasUnseen?: boolean;
4
+ onClick: () => void;
5
+ };
6
+ export declare function TriggerButton({ open, hasUnseen, onClick }: Props): import("react/jsx-runtime").JSX.Element;
7
+ export {};