feedtack 1.0.1 → 1.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/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { F as FeedtackAdapter, a as FeedtackPayload, b as FeedtackReply, c as FeedtackResolution, d as FeedtackFilter, e as FeedbackItem, f as FeedtackDeviceMeta, g as FeedtackPageMeta, h as FeedtackViewportMeta, i as FeedtackPinTarget } from './theme-BdqpMipn.js';
2
- export { A as AncestorNode, j as FeedtackArchive, k as FeedtackBoundingRect, l as FeedtackPin, m as FeedtackScope, n as FeedtackSentiment, o as FeedtackTheme, p as FeedtackUser, S as SCHEMA_VERSION, t as themeToCSS } from './theme-BdqpMipn.js';
1
+ import { F as FeedtackAdapter, a as FeedtackPayload, b as FeedtackReply, c as FeedtackResolution, d as FeedtackFilter, e as FeedbackItem, f as FeedtackDeviceMeta, g as FeedtackPageMeta, h as FeedtackViewportMeta, i as FeedtackPinTarget, j as FeedtackEngineOpts, k as FeedtackEngineState, l as FeedtackStateListener } from './types-Cu4Oahg4.js';
2
+ export { A as AncestorNode, m as FeedtackArchive, n as FeedtackBoundingRect, o as FeedtackFlushEvent, p as FeedtackPin, q as FeedtackScope, r as FeedtackSentiment, s as FeedtackTheme, t as FeedtackUser, S as SCHEMA_VERSION, u as generateId, v as themeToCSS } from './types-Cu4Oahg4.js';
3
3
 
4
4
  /** Development adapter — logs all operations to the browser console */
5
5
  declare class ConsoleAdapter implements FeedtackAdapter {
@@ -10,6 +10,23 @@ declare class ConsoleAdapter implements FeedtackAdapter {
10
10
  loadFeedback(_filter?: FeedtackFilter): Promise<FeedbackItem[]>;
11
11
  }
12
12
 
13
+ interface DiskAdapterConfig {
14
+ /** Directory to store JSON files in. Default: '.feedback' */
15
+ directory?: string;
16
+ }
17
+ /** Node.js adapter — persists each feedback item as a JSON file on disk */
18
+ declare class DiskAdapter implements FeedtackAdapter {
19
+ private dir;
20
+ constructor(config?: DiskAdapterConfig);
21
+ submit(payload: FeedtackPayload): Promise<void>;
22
+ reply(feedbackId: string, reply: Omit<FeedtackReply, 'id' | 'feedbackId'>): Promise<void>;
23
+ resolve(feedbackId: string, resolution: Omit<FeedtackResolution, 'feedbackId'>): Promise<void>;
24
+ archive(feedbackId: string, userId: string): Promise<void>;
25
+ loadFeedback(filter?: FeedtackFilter): Promise<FeedbackItem[]>;
26
+ private read;
27
+ private write;
28
+ }
29
+
13
30
  interface LocalStorageAdapterConfig {
14
31
  /** localStorage key. Default: 'feedtack' */
15
32
  key?: string;
@@ -65,4 +82,49 @@ declare function getCSSSelector(element: Element): string;
65
82
  /** Capture DOM target metadata at the clicked element */
66
83
  declare function getTargetMeta(element: Element): FeedtackPinTarget;
67
84
 
68
- export { ConsoleAdapter, FeedbackItem, FeedtackAdapter, FeedtackDeviceMeta, FeedtackFilter, FeedtackPageMeta, FeedtackPayload, FeedtackPinTarget, FeedtackReply, FeedtackResolution, FeedtackViewportMeta, LocalStorageAdapter, type LocalStorageAdapterConfig, WebhookAdapter, type WebhookAdapterConfig, getCSSSelector, getDeviceMeta, getPageMeta, getPinCoords, getTargetMeta, getViewportMeta };
85
+ interface FlushController {
86
+ flushPath: (path: string) => void;
87
+ clearFlushed: (path: string) => void;
88
+ detach: () => void;
89
+ }
90
+
91
+ declare class FeedtackEngine {
92
+ private readonly opts;
93
+ private state;
94
+ private listeners;
95
+ private actionCtx;
96
+ private styleEl;
97
+ private rootEl;
98
+ private spaNav;
99
+ flushCtrl: FlushController | null;
100
+ private inputHandles;
101
+ constructor(opts: FeedtackEngineOpts);
102
+ getState(): Readonly<FeedtackEngineState>;
103
+ subscribe(listener: FeedtackStateListener): () => void;
104
+ private setState;
105
+ mount(): void;
106
+ destroy(): void;
107
+ private onNavUpdate;
108
+ activatePinMode(): void;
109
+ deactivatePinMode(): void;
110
+ setComment(v: string): void;
111
+ setSentiment(v: FeedtackEngineState['sentiment']): void;
112
+ setCommentError(v: boolean): void;
113
+ setSelectedColor(c: string): void;
114
+ setOpenThreadId(id: string | null): void;
115
+ setReplyBody(v: string): void;
116
+ setComposeScope(s: 'site' | 'page'): void;
117
+ openModal(): void;
118
+ closeModal(): void;
119
+ getCurrentScope(): "site" | "page" | "element";
120
+ isArchivedForUser(item: FeedbackItem): boolean;
121
+ hasUnread(item: FeedbackItem): boolean;
122
+ hasValidPins(item: FeedbackItem): boolean;
123
+ handleSubmit(): Promise<void>;
124
+ handleModalSubmit(): Promise<void>;
125
+ handleReply(id: string): Promise<void>;
126
+ handleResolve(id: string): Promise<void>;
127
+ handleArchive(id: string): Promise<void>;
128
+ }
129
+
130
+ export { ConsoleAdapter, DiskAdapter, type DiskAdapterConfig, FeedbackItem, FeedtackAdapter, FeedtackDeviceMeta, FeedtackEngine, FeedtackEngineOpts, FeedtackEngineState, FeedtackFilter, FeedtackPageMeta, FeedtackPayload, FeedtackPinTarget, FeedtackReply, FeedtackResolution, FeedtackStateListener, FeedtackViewportMeta, LocalStorageAdapter, type LocalStorageAdapterConfig, WebhookAdapter, type WebhookAdapterConfig, getCSSSelector, getDeviceMeta, getPageMeta, getPinCoords, getTargetMeta, getViewportMeta };
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import {
2
+ FeedtackEngine,
2
3
  SCHEMA_VERSION,
4
+ generateId,
3
5
  getCSSSelector,
4
6
  getDeviceMeta,
5
7
  getPageMeta,
@@ -7,7 +9,7 @@ import {
7
9
  getTargetMeta,
8
10
  getViewportMeta,
9
11
  themeToCSS
10
- } from "./chunk-2A5LLDLP.js";
12
+ } from "./chunk-3INDOI4N.js";
11
13
 
12
14
  // src/adapters/ConsoleAdapter.ts
13
15
  var ConsoleAdapter = class {
@@ -29,6 +31,85 @@ var ConsoleAdapter = class {
29
31
  }
30
32
  };
31
33
 
34
+ // src/adapters/DiskAdapter.ts
35
+ import { readdir, readFile, writeFile, mkdir } from "fs/promises";
36
+ import { join } from "path";
37
+ var DiskAdapter = class {
38
+ constructor(config = {}) {
39
+ this.dir = config.directory ?? ".feedback";
40
+ }
41
+ async submit(payload) {
42
+ await mkdir(this.dir, { recursive: true });
43
+ const item = {
44
+ payload,
45
+ replies: [],
46
+ resolutions: [],
47
+ archives: []
48
+ };
49
+ await this.write(payload.id, item);
50
+ }
51
+ async reply(feedbackId, reply) {
52
+ const item = await this.read(feedbackId);
53
+ item.replies.push({
54
+ id: `r_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 7)}`,
55
+ feedbackId,
56
+ ...reply
57
+ });
58
+ await this.write(feedbackId, item);
59
+ }
60
+ async resolve(feedbackId, resolution) {
61
+ const item = await this.read(feedbackId);
62
+ item.resolutions.push({ feedbackId, ...resolution });
63
+ await this.write(feedbackId, item);
64
+ }
65
+ async archive(feedbackId, userId) {
66
+ const item = await this.read(feedbackId);
67
+ item.archives.push({
68
+ feedbackId,
69
+ archivedBy: { id: userId, name: "", role: "" },
70
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
71
+ });
72
+ await this.write(feedbackId, item);
73
+ }
74
+ async loadFeedback(filter) {
75
+ let files;
76
+ try {
77
+ await mkdir(this.dir, { recursive: true });
78
+ files = (await readdir(this.dir)).filter((f) => f.endsWith(".json"));
79
+ } catch {
80
+ return [];
81
+ }
82
+ const items = await Promise.all(
83
+ files.map(
84
+ async (f) => JSON.parse(
85
+ await readFile(join(this.dir, f), "utf-8")
86
+ )
87
+ )
88
+ );
89
+ if (!filter) return items;
90
+ return items.filter((item) => {
91
+ if (filter.scope && item.payload.scope !== filter.scope) return false;
92
+ if (filter.pathname && item.payload.page.pathname !== filter.pathname)
93
+ return false;
94
+ if (filter.url && item.payload.page.url !== filter.url) return false;
95
+ if (filter.userId && item.payload.submittedBy.id !== filter.userId)
96
+ return false;
97
+ return true;
98
+ });
99
+ }
100
+ async read(id) {
101
+ return JSON.parse(
102
+ await readFile(join(this.dir, `${id}.json`), "utf-8")
103
+ );
104
+ }
105
+ async write(id, item) {
106
+ await writeFile(
107
+ join(this.dir, `${id}.json`),
108
+ JSON.stringify(item, null, 2)
109
+ );
110
+ }
111
+ };
112
+
32
113
  // src/adapters/LocalStorageAdapter.ts
33
114
  var LocalStorageAdapter = class {
34
115
  constructor(config = {}) {
@@ -135,9 +216,12 @@ var WebhookAdapter = class {
135
216
  };
136
217
  export {
137
218
  ConsoleAdapter,
219
+ DiskAdapter,
220
+ FeedtackEngine,
138
221
  LocalStorageAdapter,
139
222
  SCHEMA_VERSION,
140
223
  WebhookAdapter,
224
+ generateId,
141
225
  getCSSSelector,
142
226
  getDeviceMeta,
143
227
  getPageMeta,
@@ -1,6 +1,6 @@
1
+ import { F as FeedtackAdapter, t as FeedtackUser, s as FeedtackTheme, e as FeedbackItem, o as FeedtackFlushEvent } from '../types-Cu4Oahg4.js';
1
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
3
  import React from 'react';
3
- import { e as FeedbackItem, F as FeedtackAdapter, p as FeedtackUser, o as FeedtackTheme } from '../theme-BdqpMipn.js';
4
4
 
5
5
  /** Fixed palette of 6 colors for pin markers */
6
6
  declare const PIN_PALETTE: readonly ["#ef4444", "#3b82f6", "#22c55e", "#f59e0b", "#a855f7", "#ec4899"];
@@ -18,11 +18,6 @@ interface FeedtackContextValue {
18
18
  isModalOpen: boolean;
19
19
  }
20
20
 
21
- interface FeedtackFlushEvent {
22
- pathname: string;
23
- items: FeedbackItem[];
24
- }
25
-
26
21
  interface FeedtackClasses {
27
22
  button?: string;
28
23
  form?: string;
@@ -59,4 +54,4 @@ declare function FeedtackProvider({ children, adapter, currentUser, hotkey, admi
59
54
  /** Hook for host app to programmatically control feedtack */
60
55
  declare function useFeedtack(): FeedtackContextValue;
61
56
 
62
- export { type FeedtackClasses, type FeedtackContextValue, type FeedtackFlushEvent, FeedtackProvider, type FeedtackProviderProps, type FeedtackSentimentLabels, PIN_PALETTE, type PinColor, useFeedtack };
57
+ export { type FeedtackClasses, type FeedtackContextValue, FeedtackFlushEvent, FeedtackProvider, type FeedtackProviderProps, type FeedtackSentimentLabels, PIN_PALETTE, type PinColor, useFeedtack };