@contember/echo 0.0.20 → 0.0.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. package/LICENSE +185 -0
  2. package/README.md +55 -70
  3. package/dist/components/Echo.d.ts +2 -2
  4. package/dist/components/atoms/Button.d.ts +0 -2
  5. package/dist/components/icons/index.d.ts +0 -1
  6. package/dist/components/molecules/LauncherButton.d.ts +2 -0
  7. package/dist/components/molecules/StoredFeedback.d.ts +2 -0
  8. package/dist/{features/feedback/components → components/organisms}/FeedbackForm.d.ts +1 -1
  9. package/dist/config/drawingConfig.d.ts +5 -10
  10. package/dist/contexts/EchoContext.d.ts +5 -8
  11. package/dist/echo.es.js +5082 -6230
  12. package/dist/echo.umd.js +11 -1095
  13. package/dist/index.d.ts +4 -3
  14. package/dist/stores/drawingStore.d.ts +6 -7
  15. package/dist/stores/echoStore.d.ts +4 -11
  16. package/dist/stores/feedbackStore.d.ts +6 -6
  17. package/dist/stores/widgetStore.d.ts +9 -8
  18. package/dist/style.css +1 -0
  19. package/dist/types.d.ts +24 -30
  20. package/dist/utils/common.d.ts +1 -0
  21. package/dist/utils/format.d.ts +1 -0
  22. package/dist/utils/index.d.ts +10 -1
  23. package/dist/utils/listeners.d.ts +22 -0
  24. package/dist/utils/screenshot.d.ts +2 -6
  25. package/dist/utils/storage.d.ts +2 -2
  26. package/dist/utils/validators.d.ts +2 -0
  27. package/package.json +4 -6
  28. package/dist/components/EchoLayout.d.ts +0 -7
  29. package/dist/components/Launcher.d.ts +0 -6
  30. package/dist/components/Overlay.d.ts +0 -4
  31. package/dist/components/icons/MessageIcon.d.ts +0 -3
  32. package/dist/features/drawing/components/index.d.ts +0 -5
  33. package/dist/features/drawing/index.d.ts +0 -2
  34. package/dist/features/drawing/styles/ColorSelector.styles.d.ts +0 -2
  35. package/dist/features/drawing/styles/DrawingLayer.styles.d.ts +0 -2
  36. package/dist/features/drawing/styles/DrawingToolbar.styles.d.ts +0 -2
  37. package/dist/features/drawing/styles/DrawingTooltip.styles.d.ts +0 -2
  38. package/dist/features/drawing/styles/ShapeActions.styles.d.ts +0 -2
  39. package/dist/features/drawing/styles/index.d.ts +0 -6
  40. package/dist/features/feedback/components/index.d.ts +0 -1
  41. package/dist/features/feedback/index.d.ts +0 -2
  42. package/dist/features/feedback/styles/FeedbackForm.styles.d.ts +0 -2
  43. package/dist/features/feedback/styles/index.d.ts +0 -1
  44. package/dist/features/launcher/components/EchoLauncherButton.d.ts +0 -2
  45. package/dist/features/launcher/components/SavedPagesDropdown.d.ts +0 -2
  46. package/dist/features/launcher/styles/EchoLauncherButton.styles.d.ts +0 -2
  47. package/dist/features/launcher/styles/Notification.styles.d.ts +0 -2
  48. package/dist/features/launcher/styles/SavedPagesDropdown.styles.d.ts +0 -2
  49. package/dist/features/launcher/styles/WelcomeMessage.styles.d.ts +0 -2
  50. package/dist/features/launcher/styles/index.d.ts +0 -4
  51. package/dist/styles/Echo.styles.d.ts +0 -2
  52. package/dist/styles/index.d.ts +0 -2
  53. package/dist/styles/zIndex.d.ts +0 -13
  54. /package/dist/{features/drawing/components → components/atoms}/Shape.d.ts +0 -0
  55. /package/dist/{features/drawing/components → components/molecules}/ColorSelector.d.ts +0 -0
  56. /package/dist/{features/drawing/components → components/molecules}/DrawingToolbar.d.ts +0 -0
  57. /package/dist/{features/drawing/components → components/molecules}/DrawingTooltip.d.ts +0 -0
  58. /package/dist/{features/launcher/components → components/molecules}/Notification.d.ts +0 -0
  59. /package/dist/{features/drawing/components → components/molecules}/ShapeActions.d.ts +0 -0
  60. /package/dist/{features/launcher/components → components/molecules}/WelcomeMessage.d.ts +0 -0
  61. /package/dist/{features/drawing/components → components/organisms}/DrawingLayer.d.ts +0 -0
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
- import { type EchoOptions, type FeedbackData, type Position } from './types';
1
+ import { type EchoConfig, type FeedbackPayload } from './types';
2
+ import './styles.css';
2
3
  /**
3
4
  * Initialize the Echo feedback widget.
4
5
  * @throws {Error} If initialization fails or invalid options are provided
5
6
  * @returns {() => void} Cleanup function to remove the widget
6
7
  */
7
- export declare function initEcho(options: EchoOptions): () => void;
8
- export type { FeedbackData, EchoOptions, Position };
8
+ export declare function initEcho(options: EchoConfig): () => void;
9
+ export type { FeedbackPayload, EchoConfig };
@@ -1,12 +1,11 @@
1
- import type { DrawingTool, Point, Shape } from '~/types';
2
- export interface DrawingState {
1
+ import type { DrawingTool, FullEchoConfig, Point, Shape } from '~/types';
2
+ export type DrawingState = {
3
3
  isDrawing: boolean;
4
4
  selectedShapeId: string | null;
5
5
  selectedTool: DrawingTool;
6
6
  selectedColor: string;
7
7
  shapes: Shape[];
8
8
  currentPoints: Point[];
9
- currentPath: string;
10
9
  showTooltip: boolean;
11
10
  mousePosition: Point;
12
11
  hasDrawn: boolean;
@@ -15,8 +14,8 @@ export interface DrawingState {
15
14
  initialClickPos: Point | null;
16
15
  dragOffset: Point | null;
17
16
  cursor: string;
18
- }
19
- export interface DrawingStore {
17
+ };
18
+ export type DrawingStore = {
20
19
  state: DrawingState;
21
20
  setState: (state: Partial<DrawingState>, isClearing?: boolean) => void;
22
21
  methods: {
@@ -36,5 +35,5 @@ export interface DrawingStore {
36
35
  points: Point[];
37
36
  }, point: Point) => void;
38
37
  };
39
- }
40
- export declare const createDrawingStore: (primaryColor: string, onStateChange?: (state: Partial<DrawingState>, isClearing?: boolean) => void) => DrawingStore;
38
+ };
39
+ export declare const createDrawingStore: (config: FullEchoConfig, currentPageKey: string, onStateChange?: (state: Partial<DrawingState>, isClearing?: boolean) => void) => DrawingStore;
@@ -1,20 +1,13 @@
1
- import type { FeedbackData, TextConfig } from '~/types';
1
+ import type { FullEchoConfig } from '~/types';
2
2
  import { type DrawingStore } from './drawingStore';
3
3
  import { type FeedbackStore } from './feedbackStore';
4
4
  import { type WidgetStore } from './widgetStore';
5
- export interface EchoStore {
5
+ export type EchoStore = {
6
6
  feedback: FeedbackStore;
7
7
  drawing: DrawingStore;
8
8
  widget: WidgetStore;
9
- text: TextConfig;
10
9
  methods: {
11
10
  reset: () => void;
12
11
  };
13
- }
14
- interface EchoStoreConfig {
15
- primaryColor: string;
16
- onSubmit: (data: FeedbackData) => Promise<void>;
17
- text: TextConfig;
18
- }
19
- export declare const createEchoStore: (config: EchoStoreConfig) => EchoStore;
20
- export {};
12
+ };
13
+ export declare const createEchoStore: (config: FullEchoConfig) => EchoStore;
@@ -1,12 +1,12 @@
1
- import type { Screenshot } from '~/types';
2
- export interface FeedbackState {
1
+ import type { FullEchoConfig, Screenshot } from '~/types';
2
+ export type FeedbackState = {
3
3
  comment: string;
4
4
  screenshot?: Screenshot;
5
5
  isCapturing: boolean;
6
6
  isMinimized: boolean;
7
- }
8
- export interface FeedbackStore {
7
+ };
8
+ export type FeedbackStore = {
9
9
  state: FeedbackState;
10
10
  setState: (state: Partial<FeedbackState>, isClearing?: boolean) => void;
11
- }
12
- export declare const createFeedbackStore: (initialComment?: string, onStateChange?: (state: Partial<FeedbackState>, isClearing?: boolean) => void) => FeedbackStore;
11
+ };
12
+ export declare const createFeedbackStore: (config: FullEchoConfig, currentPageKey: string, onStateChange?: (state: Partial<FeedbackState>, isClearing?: boolean) => void) => FeedbackStore;
@@ -1,5 +1,6 @@
1
- import type { FeedbackData, Notification } from '~/types';
2
- export interface WidgetState {
1
+ import type { FeedbackPayload, FullEchoConfig, Notification, TextConfig } from '~/types';
2
+ export type WidgetState = {
3
+ text: TextConfig;
3
4
  isOpen: boolean;
4
5
  primaryColor: string;
5
6
  notification: Notification;
@@ -7,16 +8,16 @@ export interface WidgetState {
7
8
  width: number;
8
9
  height: number;
9
10
  };
10
- isPagesDropdownOpen: boolean;
11
+ isStoredFeedbackOpen: boolean;
11
12
  pagesCount: number;
12
13
  welcomeMessageIsClosing: boolean;
13
- }
14
- export interface WidgetStore {
14
+ };
15
+ export type WidgetStore = {
15
16
  state: WidgetState;
16
17
  setState: (state: Partial<WidgetState>) => void;
17
18
  methods: {
18
19
  postSubmit: (result: Notification) => void;
19
- onSubmit: (data: FeedbackData) => Promise<void>;
20
+ onSubmit: (data: FeedbackPayload) => Promise<void>;
20
21
  };
21
- }
22
- export declare const createWidgetStore: (primaryColor: string, onSubmit: (data: FeedbackData) => Promise<void>) => WidgetStore;
22
+ };
23
+ export declare const createWidgetStore: (config: FullEchoConfig, currentPageKey: string) => WidgetStore;
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ *,*:before,*:after{box-sizing:border-box}.echo-root{position:absolute;top:0;left:0;z-index:var(--z-root);isolation:isolate;pointer-events:none;--z-root: 999999;--z-launcher: 2;--z-overlay: 1;--z-drawing-toolbar: 3;--z-drawing-tooltip: 3;--z-shape-actions: 3;--z-notification: 2;--z-welcome-message: 2;--z-widget-button: 2;--z-feedback-form: 4;--primary-color: #000;--primary-text-color: #fff;--error-color: #f44336;--success-color: var(--primary-color);--text-dark: #1a1a1a;--text-medium: #333;--text-light: #666;--text-lighter: #999;--border-color: rgba(0, 0, 0, .1);--border-color-light: rgba(0, 0, 0, .05);--border-color-medium: rgba(0, 0, 0, .08);--primary-color-lighter: color-mix(in srgb, var(--primary-color) 100%, white 40%);--primary-color-lightest: color-mix(in srgb, var(--primary-color) 7%, white 100%);--hover-color: color-mix(in srgb, var(--primary-color) 80%, #fff);--shadow-color-dark: rgba(0, 0, 0, .6);--shadow-color-light: rgba(255, 255, 255, .1);--shadow-color-medium: rgba(0, 0, 0, .2);--shadow-sm: 0 1px 3px;--shadow-md: 0 4px 10px;--shadow-lg: 0 10px 20px;--shadow-black-sm: var(--shadow-sm) rgba(0, 0, 0, .5);--shadow-black-md: var(--shadow-md) rgba(0, 0, 0, .5);--shadow-black-lg: var(--shadow-lg) rgba(0, 0, 0, .5);--shadow-black-lightened-sm: var(--shadow-sm) var(--shadow-color-medium);--shadow-black-lightened-md: var(--shadow-md) var(--shadow-color-medium);--shadow-black-lightened-lg: var(--shadow-lg) var(--shadow-color-medium);--shadow-primary-sm: var(--shadow-sm) color-mix(in srgb, var(--primary-color) 60%, transparent 80%);--shadow-primary-md: var(--shadow-md) color-mix(in srgb, var(--primary-color) 50%, transparent 80%);--shadow-primary-lg: var(--shadow-lg) color-mix(in srgb, var(--primary-color) 40%, transparent 80%);--shadow-primary-lighter-sm: var(--shadow-sm) color-mix(in srgb, var(--primary-color-lighter) 70%, transparent 80%);--shadow-primary-lighter-md: var(--shadow-md) color-mix(in srgb, var(--primary-color-lighter) 60%, transparent 80%);--shadow-primary-lighter-lg: var(--shadow-lg) color-mix(in srgb, var(--primary-color-lighter) 50%, transparent 80%);--shadow-primary-lightest-sm: var(--shadow-sm) color-mix(in srgb, var(--primary-color-lightest) 70%, transparent 80%);--shadow-primary-lightest-md: var(--shadow-md) color-mix(in srgb, var(--primary-color-lightest) 60%, transparent 80%);--shadow-primary-lightest-lg: var(--shadow-lg) color-mix(in srgb, var(--primary-color-lightest) 50%, transparent 80%);--shadow-combined-sm: var(--shadow-primary-sm), var(--shadow-black-lightened-sm);--shadow-combined-md: var(--shadow-primary-md), var(--shadow-black-lightened-md);--shadow-combined-lg: var(--shadow-primary-lg), var(--shadow-black-lightened-lg);--spacing-xs: 4px;--spacing-sm: 8px;--spacing-md: 12px;--spacing-lg: 16px;--spacing-xl: 20px;--spacing-2xl: 24px;--spacing-3xl: 32px;--radius-sm: 4px;--radius-md: 8px;--radius-lg: 12px;--radius-xl: 16px;--radius-full: 9999px;--font-xs: .8125rem;--font-sm: .875rem;--font-base: .9375rem;--font-md: 1rem;--font-lg: 1.125rem;--duration-fast: .1s;--duration-base: .2s;--duration-slow: .3s;--duration-slower: .4s;--duration-slowest: .6s;--ease-default: ease;--ease-in-out: ease-in-out;--ease-bounce: cubic-bezier(.34, 1.56, .64, 1);--ease-smooth: cubic-bezier(.4, 0, .2, 1);--ease-spring: cubic-bezier(.16, 1, .3, 1)}.echo-stored-feedback{position:absolute;display:flex;flex-direction:column;bottom:calc(100% + var(--spacing-lg));right:0;width:320px;background:#fff;border-radius:var(--radius-lg);box-shadow:var(--shadow-black-lightened-lg);animation:slideUpFade var(--duration-base) var(--ease-smooth);z-index:calc(var(--z-widget-button) + 1);transform-origin:bottom right;transition:all var(--duration-base) var(--ease-smooth)}.echo-stored-feedback-header{display:flex;align-items:center;justify-content:space-between;padding:var(--spacing-md) var(--spacing-lg)}.echo-stored-feedback-header h3{margin:0;font-size:var(--font-md);font-weight:600}.echo-stored-feedback-list{max-height:400px;overflow-y:auto;border-bottom-left-radius:var(--radius-lg);border-bottom-right-radius:var(--radius-lg)}.echo-stored-feedback-item{display:flex;align-items:center;justify-content:space-between;padding:var(--spacing-md) var(--spacing-lg);border-bottom:1px solid var(--border-color-light);transition:all var(--duration-base) var(--ease-smooth);background:#fff;position:relative}.echo-stored-feedback-item:hover{background:var(--primary-color-lightest)}.echo-stored-feedback-item-current{background:var(--primary-color-lightest);padding-left:calc(var(--spacing-lg) - 3px)}.echo-stored-feedback-item-current:before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--primary-color);border-top-left-radius:var(--radius-lg);border-bottom-left-radius:var(--radius-lg)}.echo-stored-feedback-item:last-child{border-bottom:none;border-bottom-left-radius:var(--radius-lg);border-bottom-right-radius:var(--radius-lg)}.echo-stored-feedback-item:last-child.echo-stored-feedback-item-current:before{border-bottom-left-radius:var(--radius-lg)}.echo-stored-feedback-content{flex:1;min-width:0;margin-right:var(--spacing-md)}.echo-stored-feedback-path{font-size:var(--font-sm);font-weight:500;color:var(--text-medium);margin-bottom:var(--spacing-xs);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.echo-stored-feedback-preview{font-size:var(--font-xs);color:var(--text-light);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.echo-stored-feedback-actions{display:flex;align-items:center;gap:var(--spacing-sm)}.echo-stored-feedback-link{color:var(--text-light)}.echo-stored-feedback-link:hover{color:var(--primary-color)}.echo-stored-feedback-delete{color:var(--text-light);font-size:var(--font-xs);padding:var(--spacing-xs) var(--spacing-md)}.echo-stored-feedback-delete:hover{color:var(--error-color);background:color-mix(in srgb,var(--error-color) 10%,transparent)}.echo-stored-feedback-empty{padding:var(--spacing-3xl) var(--spacing-lg);text-align:center;color:var(--text-light);font-size:var(--font-sm);border-bottom-left-radius:var(--radius-lg);border-bottom-right-radius:var(--radius-lg)}.echo-launcher{position:fixed;z-index:var(--z-launcher);bottom:var(--spacing-xl);right:var(--spacing-xl)}.echo-overlay{position:absolute;z-index:var(--z-overlay);top:0;left:0;right:0;bottom:0;border:3px solid var(--primary-color)}[data-hidden=true],[data-hidden=false]{transition:opacity var(--duration-slow) var(--ease-in-out),visibility var(--duration-slow) var(--ease-in-out)}[data-hidden=true]{opacity:0;visibility:hidden;pointer-events:none}[data-hidden=false]{opacity:1;visibility:visible;pointer-events:auto;user-select:none;-webkit-user-select:none}.echo-launcher-button{z-index:var(--z-widget-button);position:relative;display:flex;align-items:center;justify-content:center;cursor:pointer;background:radial-gradient(circle at 40% 40%,var(--primary-color) 0%,var(--primary-color-lighter) 65%,var(--primary-color-lighter) 100%);border:none;border-radius:var(--radius-full);width:48px;height:48px;box-shadow:var(--shadow-black-md);transition:all var(--duration-slow) var(--ease-default),left var(--duration-slower) var(--ease-smooth),opacity var(--duration-slow) var(--ease-in-out)}.echo-launcher-button:hover{box-shadow:var(--shadow-black-lg);transform:translateY(-2px)}.echo-launcher-button:active{transform:scale(.95)}.echo-launcher-button-count{position:absolute;top:calc(-1 * var(--spacing-xs));right:calc(-1 * var(--spacing-xs));background:var(--primary-color-lightest);color:var(--primary-color-lighter);border-radius:var(--radius-md);min-width:20px;height:20px;display:flex;align-items:center;justify-content:center;box-shadow:var(--shadow-black-sm);padding:0 var(--spacing-xs);font-weight:600;pointer-events:auto;cursor:pointer;transform-origin:center center;animation:popIn var(--duration-slow) var(--ease-bounce);transition:transform var(--duration-base) var(--ease-default)}.echo-launcher-button-count:hover{transform:scale(1.1)}.echo-feedback{position:fixed;bottom:var(--spacing-xl);right:var(--spacing-xl);width:min(calc(100vw - var(--spacing-2xl)),24rem);z-index:var(--z-feedback-form);box-shadow:var(--shadow-black-lightened-lg);display:flex;flex-direction:column;gap:var(--spacing-lg);background:#fff;border-radius:var(--radius-lg);will-change:transform;padding:var(--spacing-lg)}.echo-feedback[data-minimized=true]{transition:transform .4s var(--ease-default),box-shadow .4s var(--ease-default);transform:translate(calc(100% - 48px),calc(100% - 48px));box-shadow:0 8px 16px #0003}.echo-feedback[data-minimized=true]:hover{cursor:pointer;transform:translate(calc(100% - 48px),calc(100% - 48px)) rotate(-2deg) scale(1.1);box-shadow:0 12px 24px #00000040}.echo-feedback[data-minimized=false]{transition:transform .4s var(--ease-smooth),box-shadow .4s var(--ease-smooth);transform:translate(0)}.echo-feedback[style*=transition]{pointer-events:none}.echo-feedback-content{display:flex;flex-direction:column;gap:var(--spacing-lg)}.echo-feedback-header{display:flex;justify-content:space-between;align-items:center}.echo-feedback-title{font-size:var(--font-lg);font-weight:600;color:var(--text-dark);margin:0}.echo-feedback-header-actions{display:flex;gap:var(--spacing-xs);margin:calc(-1 * var(--spacing-sm)) calc(-1 * var(--spacing-sm)) calc(-1 * var(--spacing-sm)) 0}.echo-feedback-form-textarea{width:100%;min-height:120px;border-radius:var(--radius-md);border:1px solid var(--border-color);padding:var(--spacing-md);font-size:var(--font-base);resize:vertical;background:#fffc;font-family:inherit}.echo-feedback-form-textarea:focus{outline:none;border-color:var(--primary-color);background:#fff;box-shadow:0 0 0 3px color-mix(in srgb,var(--primary-color) 15%,transparent)}.echo-feedback-form-textarea::placeholder{color:var(--text-lighter)}[data-hide-when-drawing=true]{opacity:1;visibility:visible;transition:opacity .3s ease-in-out,visibility .3s ease-in-out}[data-drawing=true] [data-hide-when-drawing=true]{opacity:0;visibility:hidden;pointer-events:none;user-select:none;-webkit-user-select:none}.echo-drawing-layer,.echo-drawing-layer-container{position:absolute;top:0;left:0;right:0;bottom:0;pointer-events:none;user-select:none;-webkit-user-select:none}.echo-drawing-layer-container svg{pointer-events:auto}.echo-drawing-toolbar{position:fixed;top:var(--spacing-xl);left:var(--spacing-xl);display:flex;flex-direction:column;gap:var(--spacing-sm);z-index:var(--z-drawing-toolbar);opacity:1;transition:opacity var(--duration-base) var(--ease-default)}.echo-drawing-toolbar-button{width:50px;height:50px;border-radius:var(--radius-full);border:2px solid #ddd;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;padding:0;transition:all var(--duration-base) var(--ease-default);box-shadow:var(--shadow-black-sm);position:relative}.echo-drawing-toolbar-icon{width:25px;height:25px;color:var(--primary-color);transition:color var(--duration-base) var(--ease-default)}.echo-drawing-toolbar-button:hover{transform:scale(1.05);border-color:var(--hover-color)}.echo-drawing-toolbar-button[data-selected=true]{background:var(--primary-color-lightest);border-color:var(--primary-color)}.echo-color-selector{position:relative}.echo-color-selector:hover .echo-drawing-toolbar-button{border-top-right-radius:0;border-bottom-right-radius:0;transform:scale(1.05);border-right-color:transparent;background:rgba(var(--primary-color),.9);border-color:var(--hover-color)}.echo-color-swatch-wrapper{position:absolute;left:calc(100% - 2px);top:50%;transform:translateY(-50%);height:52.5px;padding-right:var(--spacing-sm);display:none}.echo-color-selector:hover .echo-color-swatch-wrapper{display:block}.echo-color-swatch{height:100%;background:#fff;border-radius:var(--radius-md);border-top-left-radius:0;border-bottom-left-radius:0;padding:var(--spacing-sm);padding-left:var(--spacing-md);box-shadow:var(--shadow-black-sm);display:flex;align-items:center;gap:var(--spacing-sm);border:2px solid #ddd;border-left:none}.echo-color-selector:hover .echo-color-swatch{border-color:var(--hover-color)}.echo-color-swatch-button{width:24px;height:24px;border-radius:var(--radius-full);border:2px solid transparent;cursor:pointer;padding:0;transition:transform var(--duration-base) var(--ease-default)}.echo-color-swatch-button:hover{transform:scale(1.1)}.echo-color-swatch-button[data-selected=true]{border-color:var(--primary-color)}.echo-drawing-tooltip{display:flex;text-wrap:nowrap;position:fixed;background:#fff;padding:var(--spacing-sm) var(--spacing-lg);border-radius:var(--radius-lg);box-shadow:var(--shadow-combined-sm);font-size:var(--font-sm);color:var(--primary-color);z-index:var(--z-drawing-tooltip);pointer-events:none;animation:slideDownFade var(--duration-slow) var(--ease-default);border:1px solid var(--primary-color);background:var(--primary-color-lightest)}.echo-shape-actions{position:fixed;z-index:var(--z-shape-actions);display:flex;gap:var(--spacing-xs);background:#fff;border-radius:var(--radius-lg);box-shadow:var(--shadow-combined-md);transform:translate(-50%,-100%) translateY(calc(-1 * var(--spacing-sm)));animation:popInSlideDown var(--duration-fast) var(--ease-default);cursor:default;pointer-events:auto;padding:var(--spacing-xs);border:1px solid var(--primary-color)}.echo-shape-actions-divider{width:1px;margin:var(--spacing-sm) 0;background:var(--border-color);pointer-events:none}.echo-shape-actions[hidden]{display:none}.echo-notification{position:absolute;z-index:var(--z-notification);bottom:70px;right:0;width:300px;padding:var(--spacing-2xl);border-radius:var(--radius-lg);font-size:var(--font-md);font-weight:500;box-shadow:var(--shadow-combined-md);background:#fff;border:1px solid var(--primary-color);transform-origin:bottom right;display:flex;flex-direction:column;align-items:center;gap:var(--spacing-xl);opacity:1;pointer-events:auto;transition:all var(--duration-base) var(--ease-smooth)}.echo-notification:not([data-empty=true]){animation:popInSlideUp var(--duration-slower) var(--ease-spring)}.echo-notification[data-empty=true]{opacity:0;pointer-events:none;transform:translateY(var(--spacing-sm)) scale(.95);transition:none}.echo-notification-hide{position:absolute;top:var(--spacing-lg);right:var(--spacing-lg);width:24px;height:24px;padding:var(--spacing-xs);border:none;background:transparent;color:var(--text-light);opacity:.7;cursor:pointer;border-radius:var(--radius-full);display:flex;align-items:center;justify-content:center;transition:all var(--duration-base) var(--ease-bounce);flex-shrink:0}.echo-notification-hide:hover{opacity:1;background:var(--primary-color-lightest);transform:scale(1.1);color:var(--primary-color)}.echo-notification-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;transform:scale(1.5);background:var(--primary-color-lightest);padding:var(--spacing-md);border-radius:var(--radius-full);margin-top:var(--spacing-md);transition:all var(--duration-base) var(--ease-bounce)}.echo-notification[data-type=success]{border-color:var(--success-color)}.echo-notification[data-type=success] .echo-notification-icon{color:var(--success-color)}.echo-notification[data-type=error]{border-color:var(--error-color)}.echo-notification[data-type=error] .echo-notification-icon{color:var(--error-color);background:color-mix(in srgb,var(--error-color) 10%,white)}.echo-notification-content{display:flex;flex-direction:column;align-items:center;gap:12px;text-align:center;padding:0 12px}.echo-notification-title{font-size:1rem;font-weight:600;color:#1a1a1a}.echo-notification-message{font-size:.875rem;font-weight:400;color:#666;line-height:1.4;max-width:100%}@media (max-width: 768px){.echo-notification{right:0;width:calc(100vw - 40px);height:auto;min-height:180px;-webkit-backdrop-filter:none;backdrop-filter:none;font-size:.9375rem;padding:20px;gap:16px;bottom:calc(100% + 20px)}.echo-notification-icon{transform:scale(1.3);padding:10px;margin-top:8px}.echo-notification-title{font-size:.9375rem}.echo-notification-message{font-size:.8125rem}}.echo-welcome-message{display:flex;align-items:center;gap:var(--spacing-xs);position:fixed;z-index:var(--z-welcome-message);background:var(--primary-color-lightest);border:1px solid var(--primary-color);color:var(--primary-color);padding:var(--spacing-md) var(--spacing-lg);border-radius:var(--radius-lg);font-size:var(--font-sm);font-weight:500;box-shadow:var(--shadow-combined-md);opacity:1;transform:translateY(0) scale(1);transition:all var(--duration-slow) var(--ease-smooth);animation:bounceIn var(--duration-slowest) var(--ease-bounce);user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;cursor:pointer;text-align:left}.echo-welcome-message:hover{transform:translateY(-2px) scale(1.02);background:var(--primary-color-lightest);box-shadow:var(--shadow-combined-lg)}.echo-welcome-message:active{transform:translateY(0) scale(.98)}.echo-welcome-message-close{width:20px;height:20px;padding:2px;margin-left:var(--spacing-xs);border:none;background:transparent;opacity:.7;cursor:pointer;border-radius:var(--radius-full);display:flex;align-items:center;justify-content:center;transition:all var(--duration-base) var(--ease-default)}.echo-welcome-message-close:hover{opacity:1;background:var(--shadow-color-light);transform:scale(1.1)}.echo-welcome-message-close:active{transform:scale(.95)}.echo-welcome-message:after{content:"";position:absolute;bottom:-4px;right:17px;width:16px;height:16px;background:inherit;transform:rotate(45deg);border-radius:var(--radius-xs);border:1px solid var(--primary-color);z-index:-2}.echo-welcome-message:before{content:"";position:absolute;top:0;left:0;width:100%;height:100%;background:var(--primary-color-lightest);z-index:-1;border-radius:var(--radius-lg)}.echo-welcome-message-pulsar{content:"";display:inline-block;width:6px;height:6px;background:var(--primary-color);border-radius:50%;margin-right:8px;animation:pulse 1.5s var(--ease-in-out) infinite}.echo-button{display:inline-flex;align-items:center;justify-content:center;border:none;border-radius:var(--radius-md);font-weight:500;cursor:pointer;transition:all var(--duration-base) var(--ease-default);line-height:1}.echo-button:focus-visible{outline:2px solid var(--primary-color);outline-offset:2px}.echo-button-primary{background:var(--primary-color);color:#fff}.echo-button-primary:hover{background:var(--hover-color);transform:translateY(-1px)}.echo-button-primary:active{transform:translateY(0)}.echo-button-secondary{background:transparent;color:var(--text-light)}.echo-button-secondary:hover{background-color:var(--primary-color-lightest);color:var(--primary-color)}.echo-button-xs{padding:var(--spacing-xs);font-size:var(--font-xs)}.echo-button-sm{padding:var(--spacing-xs);font-size:var(--font-sm)}.echo-button-md{padding:var(--spacing-md) var(--spacing-2xl);font-size:var(--font-base)}.echo-button-lg{padding:var(--spacing-md) var(--spacing-3xl);font-size:var(--font-md)}@keyframes slideUpFade{0%{opacity:0;transform:translateY(var(--spacing-sm))}to{opacity:1;transform:translateY(0)}}@keyframes slideDownFade{0%{opacity:0;transform:translateY(calc(-1 * var(--spacing-sm)))}to{opacity:1;transform:translateY(0)}}@keyframes popIn{0%{transform:scale(0);opacity:0}to{transform:scale(1);opacity:1}}@keyframes popInSlideUp{0%{opacity:0;transform:translateY(var(--spacing-sm)) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes popInSlideDown{0%{opacity:0;transform:translate(-50%,-100%) translateY(calc(-1 * var(--spacing-xs))) scale(.95)}to{opacity:1;transform:translate(-50%,-100%) translateY(calc(-1 * var(--spacing-sm))) scale(1)}}@keyframes bounceIn{0%{opacity:0;transform:translateY(var(--spacing-xl)) scale(.9)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.5);opacity:.5}to{transform:scale(1);opacity:1}}
package/dist/types.d.ts CHANGED
@@ -1,29 +1,29 @@
1
- export type Screenshot = `data:image/webp;base64,${string}` | `data:image/png;base64,${string}`;
2
- export interface BrowserInfo {
1
+ export type Screenshot = `data:image/png;base64,${string}`;
2
+ export type BrowserInfo = {
3
3
  width: number;
4
4
  height: number;
5
5
  screenWidth: number;
6
6
  screenHeight: number;
7
- }
8
- export interface Metadata {
7
+ };
8
+ export type Metadata = {
9
9
  url: string;
10
10
  userAgent: string;
11
11
  timestamp: string;
12
12
  browserInfo: BrowserInfo;
13
- }
14
- export interface ConsoleEntry {
13
+ };
14
+ export type ConsoleEntry = {
15
15
  type: 'log' | 'warn' | 'error';
16
16
  message: string;
17
17
  timestamp: string;
18
- }
19
- export interface FeedbackData {
18
+ };
19
+ export type FeedbackPayload = {
20
20
  comment: string;
21
21
  screenshot?: Screenshot;
22
22
  metadata: Metadata;
23
23
  console: ConsoleEntry[];
24
- }
24
+ };
25
25
  export type Position = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
26
- export interface TextConfig {
26
+ export type TextConfig = {
27
27
  welcomeMessage: {
28
28
  text: string;
29
29
  closeAriaLabel: string;
@@ -47,47 +47,41 @@ export interface TextConfig {
47
47
  drawingTooltip: {
48
48
  text: string;
49
49
  };
50
- }
51
- export type EchoOptions = {
52
- onSubmit: (data: FeedbackData) => Promise<void>;
50
+ };
51
+ export type EchoConfig = {
52
+ onSubmit: (data: FeedbackPayload) => Promise<void>;
53
53
  position?: Position;
54
54
  primaryColor?: `#${string}`;
55
55
  textConfig?: Partial<TextConfig>;
56
- children?: any;
56
+ };
57
+ export type FullEchoConfig = Required<EchoConfig> & {
58
+ textConfig: TextConfig;
57
59
  };
58
60
  export declare const POSITIONS: Record<Position, {
59
61
  [key: string]: string;
60
62
  }>;
61
- export interface Point {
63
+ export type Point = {
62
64
  x: number;
63
65
  y: number;
64
- }
66
+ };
65
67
  export type ShapeType = 'rectangle' | 'path';
66
68
  export type DrawingTool = 'rectangle' | 'path';
67
- export interface Shape {
69
+ export type Shape = {
68
70
  id: string;
69
71
  type: ShapeType;
70
72
  color: string;
71
73
  points: Point[];
72
- }
73
- export interface IconProps {
74
+ };
75
+ export type IconProps = {
74
76
  size?: number;
75
77
  stroke?: string;
76
78
  strokeWidth?: number;
77
79
  class?: string;
78
80
  style?: any;
79
81
  fill?: string;
80
- }
81
- export interface StylesConfig {
82
- primaryColor: string;
83
- }
84
- export interface EnrichedStylesConfig extends StylesConfig {
85
- primaryTextColor: string;
86
- primaryColorLighter: string;
87
- primaryColorLightest: string;
88
- }
89
- export interface Notification {
82
+ };
83
+ export type Notification = {
90
84
  show: boolean;
91
85
  type: 'success' | 'error' | null;
92
86
  message: string | null;
93
- }
87
+ };
@@ -0,0 +1 @@
1
+ export declare const deepMerge: (target: any, source: any) => any;
@@ -0,0 +1 @@
1
+ export declare const formatPath: (path: string) => string;
@@ -1,4 +1,13 @@
1
+ export * from './color';
2
+ export * from './common';
3
+ export * from './console';
4
+ export * from './debounce';
1
5
  export * from './device';
2
- export * from './screenshot';
6
+ export * from './events';
7
+ export * from './format';
3
8
  export * from './geometry';
9
+ export * from './listeners';
10
+ export * from './screenshot';
4
11
  export * from './storage';
12
+ export * from './svg';
13
+ export * from './validators';
@@ -0,0 +1,22 @@
1
+ export declare const registerKeyListener: (key: string, callback: () => void) => void;
2
+ export declare const registerWindowEventListener: {
3
+ <K extends keyof WindowEventMap>(props: {
4
+ event: K;
5
+ callback: (e: WindowEventMap[K]) => void;
6
+ onMount?: () => void;
7
+ onCleanup?: () => void;
8
+ }): void;
9
+ (props: {
10
+ event: string;
11
+ callback: (e: Event) => void;
12
+ onMount?: () => void;
13
+ onCleanup?: () => void;
14
+ }): void;
15
+ };
16
+ export declare const registerMutationObserver: (props: {
17
+ target: Node;
18
+ options?: MutationObserverInit;
19
+ callback: (mutations: MutationRecord[]) => void;
20
+ onMount?: () => void;
21
+ onCleanup?: () => void;
22
+ }) => void;
@@ -1,6 +1,2 @@
1
- import type { Screenshot, Shape } from '~/types';
2
- interface CaptureScreenshotConfig {
3
- annotations: Shape[];
4
- }
5
- export declare const captureScreenshot: ({ annotations }: CaptureScreenshotConfig) => Promise<Screenshot | undefined>;
6
- export {};
1
+ import type { Screenshot } from '~/types';
2
+ export declare const captureScreenshot: () => Promise<Screenshot | undefined>;
@@ -1,6 +1,6 @@
1
1
  import { DrawingState, FeedbackState } from '~/stores';
2
2
  import type { Shape } from '~/types';
3
- interface StoredPageState {
3
+ type StoredPageState = {
4
4
  feedback: {
5
5
  comment: string;
6
6
  };
@@ -8,7 +8,7 @@ interface StoredPageState {
8
8
  shapes: Shape[];
9
9
  };
10
10
  latestQuery?: string;
11
- }
11
+ };
12
12
  export declare const dispatchStorageChange: () => void;
13
13
  export declare const getStorageKey: (key: string) => string;
14
14
  export declare const getFromStorage: <T>(key: string, defaultValue: T) => T;
@@ -0,0 +1,2 @@
1
+ import type { EchoConfig } from '~/types';
2
+ export declare const validateOptions: (options: EchoConfig) => void;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@contember/echo",
3
3
  "license": "Apache-2.0",
4
- "version": "0.0.20",
4
+ "version": "0.0.22",
5
5
  "type": "module",
6
6
  "author": "neumie@neumie.dev",
7
7
  "keywords": [
@@ -16,10 +16,9 @@
16
16
  "dist"
17
17
  ],
18
18
  "scripts": {
19
- "dev": "vite",
20
- "build": "tsc && vite build && tsc --emitDeclarationOnly ",
21
- "preview": "vite preview",
22
- "watch": "concurrently \"tsc --watch\" \"vite build --watch\""
19
+ "dev": "vite build --watch",
20
+ "build": "tsc && vite build && tsc --emitDeclarationOnly",
21
+ "ts:watch": "tsc --watch"
23
22
  },
24
23
  "dependencies": {
25
24
  "html2canvas": "^1.4.1",
@@ -27,7 +26,6 @@
27
26
  },
28
27
  "devDependencies": {
29
28
  "@types/node": "^20.17.12",
30
- "concurrently": "^9.1.2",
31
29
  "typescript": "^5.0.0",
32
30
  "vite": "^5.0.0",
33
31
  "vite-plugin-solid": "^2.10.1",
@@ -1,7 +0,0 @@
1
- import type { Component } from 'solid-js';
2
- import type { Position } from '~/types';
3
- interface EchoLayoutProps {
4
- position?: Position;
5
- }
6
- export declare const EchoLayout: Component<EchoLayoutProps>;
7
- export {};
@@ -1,6 +0,0 @@
1
- import type { Component, JSXElement } from 'solid-js';
2
- interface LauncherProps {
3
- children: JSXElement;
4
- }
5
- export declare const Launcher: Component<LauncherProps>;
6
- export {};
@@ -1,4 +0,0 @@
1
- import type { Component, JSX } from 'solid-js';
2
- export declare const Overlay: Component<{
3
- children: JSX.Element;
4
- }>;
@@ -1,3 +0,0 @@
1
- import type { Component } from 'solid-js';
2
- import type { IconProps } from '~/types';
3
- export declare const MessageIcon: Component<IconProps>;
@@ -1,5 +0,0 @@
1
- export * from './DrawingLayer';
2
- export * from './DrawingTooltip';
3
- export * from './Shape';
4
- export * from './ShapeActions';
5
- export * from './DrawingToolbar';
@@ -1,2 +0,0 @@
1
- export * from './components';
2
- export * from './styles';
@@ -1,2 +0,0 @@
1
- import type { StylesConfig } from '~/types';
2
- export declare const colorSelectorStyles: (config: StylesConfig) => string;
@@ -1,2 +0,0 @@
1
- import type { EnrichedStylesConfig } from '~/types';
2
- export declare const drawingLayerStyles: (config: EnrichedStylesConfig) => string;
@@ -1,2 +0,0 @@
1
- import type { EnrichedStylesConfig } from '~/types';
2
- export declare const drawingToolbarStyles: (config: EnrichedStylesConfig) => string;
@@ -1,2 +0,0 @@
1
- import type { EnrichedStylesConfig } from '~/types';
2
- export declare const tooltipStyles: (config: EnrichedStylesConfig) => string;
@@ -1,2 +0,0 @@
1
- import type { EnrichedStylesConfig } from '~/types';
2
- export declare const shapeActionsStyles: (config: EnrichedStylesConfig) => string;
@@ -1,6 +0,0 @@
1
- export * from './DrawingLayer.styles';
2
- export * from './ShapeActions.styles';
3
- export * from './ColorSelector.styles';
4
- export * from './DrawingLayer.styles';
5
- export * from './DrawingToolbar.styles';
6
- export * from './DrawingTooltip.styles';
@@ -1 +0,0 @@
1
- export * from './FeedbackForm';
@@ -1,2 +0,0 @@
1
- export * from './components';
2
- export * from './styles';
@@ -1,2 +0,0 @@
1
- import type { EnrichedStylesConfig } from '~/types';
2
- export declare const feedbackFormStyles: (config: EnrichedStylesConfig) => string;
@@ -1 +0,0 @@
1
- export * from './FeedbackForm.styles';
@@ -1,2 +0,0 @@
1
- import type { Component } from 'solid-js';
2
- export declare const EchoLauncherButton: Component;
@@ -1,2 +0,0 @@
1
- import { type Component } from 'solid-js';
2
- export declare const SavedPagesDropdown: Component;
@@ -1,2 +0,0 @@
1
- import type { EnrichedStylesConfig } from '~/types';
2
- export declare const echoLauncherButtonStyles: (config: EnrichedStylesConfig) => string;
@@ -1,2 +0,0 @@
1
- import type { EnrichedStylesConfig } from '~/types';
2
- export declare const notificationStyles: (config: EnrichedStylesConfig) => string;
@@ -1,2 +0,0 @@
1
- import type { EnrichedStylesConfig } from '~/types';
2
- export declare const savedPagesDropdownStyles: (config: EnrichedStylesConfig) => string;
@@ -1,2 +0,0 @@
1
- import type { EnrichedStylesConfig } from '~/types';
2
- export declare const welcomeMessageStyles: (config: EnrichedStylesConfig) => string;
@@ -1,4 +0,0 @@
1
- export * from './EchoLauncherButton.styles';
2
- export * from './SavedPagesDropdown.styles';
3
- export * from './WelcomeMessage.styles';
4
- export * from './Notification.styles';
@@ -1,2 +0,0 @@
1
- import type { EnrichedStylesConfig } from '~/types';
2
- export declare const echoStyles: (config: EnrichedStylesConfig) => string;
@@ -1,2 +0,0 @@
1
- export * from './Echo.styles';
2
- export * from './zIndex';
@@ -1,13 +0,0 @@
1
- declare const zIndex: {
2
- readonly root: 999999;
3
- readonly overlay: 1;
4
- readonly launcher: 2;
5
- readonly widgetButton: 2;
6
- readonly notification: 2;
7
- readonly welcomeMessage: 2;
8
- readonly feedbackForm: 4;
9
- readonly drawingToolbar: 3;
10
- readonly shapeActions: 3;
11
- readonly drawingTooltip: 3;
12
- };
13
- export { zIndex };