@helpway/react 0.1.1 → 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helpway/react",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "Official React SDK for Helpway — drop-in AI chat support widget with headless hooks for custom UIs.",
5
5
  "keywords": [
6
6
  "helpway",
@@ -21,13 +21,15 @@
21
21
  "url": "https://github.com/better-i18n/helpway/issues"
22
22
  },
23
23
  "type": "module",
24
- "sideEffects": [
25
- "**/*.css"
26
- ],
27
- "main": "./src/index.ts",
28
- "types": "./src/index.ts",
24
+ "//sideEffects": "tsup injectStyle bundles CSS into JS as a runtime styleInject() call. Must be true (not an array) because some bundlers — notably Vite's esbuild pre-bundler — don't honor path-scoped sideEffects entries for npm deps. Widget bundle is tiny (~240KB), cost of losing tree-shaking is negligible.",
25
+ "sideEffects": true,
26
+ "main": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
29
28
  "exports": {
30
- ".": "./src/index.ts",
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.js"
32
+ },
31
33
  "./styles.css": "./src/themed/styles.css"
32
34
  },
33
35
  "files": [
@@ -38,22 +40,11 @@
38
40
  "scripts": {
39
41
  "build": "tsup",
40
42
  "typecheck": "tsc --noEmit",
41
- "prepublishOnly": "bun run build"
43
+ "prepublishOnly": "bun run build",
44
+ "prepack": "bun run build && bun scripts/apply-publish-config.ts",
45
+ "postpack": "bun scripts/apply-publish-config.ts --restore"
42
46
  },
43
47
  "//": "publishConfig swaps main/types/exports to the built dist on publish. Workspace consumers get raw src (fast HMR, no build step); npm consumers get compiled dist with .d.ts. Standard monorepo pattern.",
44
- "publishConfig": {
45
- "access": "public",
46
- "main": "./dist/index.js",
47
- "module": "./dist/index.js",
48
- "types": "./dist/index.d.ts",
49
- "exports": {
50
- ".": {
51
- "types": "./dist/index.d.ts",
52
- "import": "./dist/index.js"
53
- },
54
- "./styles.css": "./src/themed/styles.css"
55
- }
56
- },
57
48
  "dependencies": {
58
49
  "@trpc/client": "^11.5.1",
59
50
  "zustand": "^5.0.11",
@@ -70,5 +61,7 @@
70
61
  "peerDependencies": {
71
62
  "react": "^18.0.0 || ^19.0.0",
72
63
  "react-dom": "^18.0.0 || ^19.0.0"
73
- }
64
+ },
65
+ "access": "public",
66
+ "module": "./dist/index.js"
74
67
  }
@@ -1,8 +1,12 @@
1
1
  /* ═══ Helpway Widget — Premium Intercom-Style ═══
2
- Vanilla CSS for Shadow DOM. Gradient hero, card-based actions,
2
+ Vanilla CSS. Works in both Shadow DOM (script embed) and regular
3
+ DOM (React native render). Gradient hero, card-based actions,
3
4
  avatar-first conversation rows, bottom tab navigation. */
4
5
 
5
6
  /* ── Reset ─────────────────────────────────────── */
7
+ /* Shadow DOM root — matches when the widget is mounted under a
8
+ <helpway-widget> custom element with shadow root. Regular-DOM
9
+ consumers ignore :host (selector never matches). */
6
10
  :host {
7
11
  all: initial;
8
12
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
@@ -14,6 +18,21 @@
14
18
  -moz-osx-font-smoothing: grayscale;
15
19
  }
16
20
 
21
+ /* Regular-DOM reset — applies the same typography baseline on the
22
+ `.hw-widget` root when there is no shadow DOM. Scoped so the
23
+ consumer's host page styles can't leak in and so we don't touch
24
+ anything outside `.hw-widget`. Don't use `all: initial` here —
25
+ it would wipe out `.hw-widget { position: fixed; z-index: ... }`. */
26
+ .hw-widget {
27
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
28
+ sans-serif;
29
+ font-size: 14px;
30
+ line-height: 1.5;
31
+ color: #1a1a1a;
32
+ -webkit-font-smoothing: antialiased;
33
+ -moz-osx-font-smoothing: grayscale;
34
+ }
35
+
17
36
  .hw-widget *,
18
37
  .hw-widget *::before,
19
38
  .hw-widget *::after {
@@ -45,7 +64,12 @@
45
64
  --hw-radius: 16px;
46
65
  --hw-visitor-bubble-bg: #f0f0f0;
47
66
  --hw-visitor-bubble-text: #1a1a1a;
48
- --hw-font: inherit;
67
+ /* Widget font stack. Consumers can override by setting --hw-font
68
+ on the `.hw-widget` element. Was `inherit` previously, which
69
+ meant "use host page font" — but in non-shadow-DOM that inherits
70
+ from <body>, often an unstyled fallback (Times New Roman). */
71
+ --hw-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
72
+ sans-serif;
49
73
  }
50
74
 
51
75
  /* ── Agent Avatar Image / Icon ────────────────── */
@@ -510,6 +534,20 @@
510
534
  width: 24px;
511
535
  height: 24px;
512
536
  }
537
+ .hw-header-bot-icon--team {
538
+ background: var(--hw-brand, #0a0a0a);
539
+ color: #fff;
540
+ }
541
+ .hw-header-agent-img {
542
+ width: 100%;
543
+ height: 100%;
544
+ object-fit: cover;
545
+ }
546
+ .hw-header-agent-initials {
547
+ font-size: 11px;
548
+ font-weight: 600;
549
+ line-height: 1;
550
+ }
513
551
 
514
552
  .hw-header-info {
515
553
  flex: 1;
@@ -862,6 +900,21 @@
862
900
  width: 20px;
863
901
  height: 20px;
864
902
  }
903
+ .hw-conv-card-avatar-img {
904
+ width: 100%;
905
+ height: 100%;
906
+ object-fit: cover;
907
+ }
908
+ .hw-conv-card-avatar--team {
909
+ background: var(--hw-brand, #0a0a0a);
910
+ color: #fff;
911
+ }
912
+ .hw-conv-card-avatar-initials {
913
+ font-size: 12px;
914
+ font-weight: 600;
915
+ line-height: 1;
916
+ letter-spacing: 0.02em;
917
+ }
865
918
 
866
919
  .hw-conv-card-content {
867
920
  flex: 1;
@@ -1062,6 +1115,43 @@
1062
1115
  /* Flex column with constrained children — min-width:0 allows children to
1063
1116
  honor their own max-width rather than inflating to content width. */
1064
1117
  min-width: 0;
1118
+ scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
1119
+ scrollbar-width: thin;
1120
+ }
1121
+
1122
+ .hw-messages::-webkit-scrollbar {
1123
+ width: 10px;
1124
+ height: 10px;
1125
+ }
1126
+
1127
+ .hw-messages::-webkit-scrollbar-track {
1128
+ background: transparent;
1129
+ }
1130
+
1131
+ .hw-messages::-webkit-scrollbar-thumb {
1132
+ background: rgba(0, 0, 0, 0.16);
1133
+ background-clip: content-box;
1134
+ border: 3px solid transparent;
1135
+ border-radius: 999px;
1136
+ }
1137
+
1138
+ .hw-messages::-webkit-scrollbar-thumb:hover {
1139
+ background: rgba(0, 0, 0, 0.28);
1140
+ background-clip: content-box;
1141
+ }
1142
+
1143
+ .hw-widget[data-theme="dark"] .hw-messages {
1144
+ scrollbar-color: rgba(255, 255, 255, 0.26) transparent;
1145
+ }
1146
+
1147
+ .hw-widget[data-theme="dark"] .hw-messages::-webkit-scrollbar-thumb {
1148
+ background: rgba(255, 255, 255, 0.2);
1149
+ background-clip: content-box;
1150
+ }
1151
+
1152
+ .hw-widget[data-theme="dark"] .hw-messages::-webkit-scrollbar-thumb:hover {
1153
+ background: rgba(255, 255, 255, 0.32);
1154
+ background-clip: content-box;
1065
1155
  }
1066
1156
 
1067
1157
  /* ── Empty Messages ─────────────────────────── */
@@ -1140,6 +1230,11 @@
1140
1230
  align-self: flex-start;
1141
1231
  }
1142
1232
 
1233
+ .hw-msg--ai {
1234
+ width: 100%;
1235
+ max-width: 100%;
1236
+ }
1237
+
1143
1238
  .hw-msg-body {
1144
1239
  display: flex;
1145
1240
  flex-direction: column;
@@ -1182,21 +1277,54 @@
1182
1277
  color: var(--hw-text);
1183
1278
  border-bottom-left-radius: 4px;
1184
1279
  white-space: normal; /* AI messages use HTML rendering (markdown), not pre-wrap */
1280
+ max-width: min(100%, 640px);
1185
1281
  }
1186
1282
 
1187
- /* Meta (time + sender label) — hidden, show on hover */
1283
+ .hw-msg--ai .hw-msg-body {
1284
+ width: 100%;
1285
+ }
1286
+
1287
+ .hw-msg--ai .hw-msg-bubble:has(.hw-code),
1288
+ .hw-msg--ai .hw-msg-bubble:has(pre) {
1289
+ width: 100%;
1290
+ }
1291
+
1292
+ .hw-msg--ai .hw-code {
1293
+ width: 100%;
1294
+ box-sizing: border-box;
1295
+ }
1296
+
1297
+ /* Meta (clock always visible; sender/copy reveal on hover) */
1188
1298
  .hw-msg-meta {
1299
+ display: inline-flex;
1300
+ align-items: center;
1301
+ gap: 4px;
1189
1302
  font-size: 11px;
1190
1303
  color: var(--hw-text-3);
1191
1304
  margin-top: 3px;
1192
1305
  padding: 0 4px;
1193
- opacity: 0;
1194
- transition: opacity 0.15s;
1306
+ opacity: 1;
1195
1307
  font-variant-numeric: tabular-nums;
1308
+ min-height: 20px;
1309
+ }
1310
+
1311
+ .hw-msg-time {
1312
+ opacity: 0.72;
1313
+ }
1314
+
1315
+ .hw-msg-hover-meta {
1316
+ max-width: 0;
1317
+ opacity: 0;
1318
+ overflow: hidden;
1319
+ white-space: nowrap;
1320
+ transition:
1321
+ max-width 180ms ease,
1322
+ opacity 140ms ease;
1196
1323
  }
1197
1324
 
1198
- .hw-msg:hover .hw-msg-meta,
1199
- .hw-msg:focus-within .hw-msg-meta {
1325
+ .hw-msg:hover .hw-msg-hover-meta,
1326
+ .hw-msg:focus-within .hw-msg-hover-meta {
1327
+ max-width: 180px;
1200
1328
  opacity: 1;
1201
1329
  }
1202
1330
 
@@ -2236,6 +2364,9 @@
2236
2364
  .hw-msg {
2237
2365
  max-width: 82%;
2238
2366
  }
2367
+ .hw-msg--ai {
2368
+ max-width: 100%;
2369
+ }
2239
2370
  }
2240
2371
 
2241
2372
  /* ════════════════════════════════════════════════
@@ -2611,7 +2742,8 @@
2611
2742
  display: flex;
2612
2743
  align-items: center;
2613
2744
  justify-content: space-between;
2614
- padding: 6px 12px;
2745
+ gap: 10px;
2746
+ padding: 7px 8px 7px 12px;
2615
2747
  font-size: 11px;
2616
2748
  color: var(--hw-text-2, #6b7280);
2617
2749
  background: rgba(0, 0, 0, 0.03);
@@ -2624,24 +2756,85 @@
2624
2756
  font-weight: 500;
2625
2757
  }
2626
2758
 
2627
- .hw-code-copy {
2759
+ .hw-code-actions {
2628
2760
  display: inline-flex;
2629
2761
  align-items: center;
2630
- gap: 4px;
2631
- padding: 2px 8px;
2632
- font-size: 11px;
2762
+ gap: 1px;
2763
+ }
2764
+
2765
+ .hw-code-action {
2766
+ position: relative;
2767
+ display: inline-flex;
2768
+ align-items: center;
2769
+ justify-content: center;
2770
+ width: 22px;
2771
+ height: 22px;
2772
+ padding: 0;
2633
2773
  font-family: inherit;
2634
2774
  color: var(--hw-text-2, #6b7280);
2635
2775
  background: transparent;
2636
2776
  border: 1px solid transparent;
2637
- border-radius: 5px;
2777
+ border-radius: 6px;
2638
2778
  cursor: pointer;
2639
- transition: background 120ms ease, color 120ms ease;
2779
+ opacity: 0.62;
2780
+ transition:
2781
+ background 120ms ease,
2782
+ color 120ms ease,
2783
+ opacity 120ms ease,
2784
+ scale 120ms ease;
2640
2785
  }
2641
2786
 
2642
- .hw-code-copy:hover {
2787
+ .hw-code-action:hover {
2643
2788
  color: var(--hw-text, #111);
2644
2789
  background: rgba(0, 0, 0, 0.06);
2790
+ opacity: 1;
2791
+ }
2792
+
2793
+ .hw-code-action:active {
2794
+ scale: 0.96;
2795
+ }
2796
+
2797
+ .hw-code-action svg {
2798
+ width: 13px;
2799
+ height: 13px;
2800
+ }
2801
+
2802
+ .hw-code-copy-icon,
2803
+ .hw-code-check-icon {
2804
+ position: absolute;
2805
+ inset: 50% auto auto 50%;
2806
+ transition:
2807
+ opacity 180ms cubic-bezier(0.2, 0, 0, 1),
2808
+ scale 180ms cubic-bezier(0.2, 0, 0, 1),
2809
+ filter 180ms cubic-bezier(0.2, 0, 0, 1);
2810
+ translate: -50% -50%;
2811
+ }
2812
+
2813
+ .hw-code-check-icon {
2814
+ filter: blur(4px);
2815
+ opacity: 0;
2816
+ scale: 0.25;
2817
+ }
2818
+
2819
+ .hw-code-copy--copied .hw-code-copy-icon {
2820
+ filter: blur(4px);
2821
+ opacity: 0;
2822
+ scale: 0.25;
2823
+ }
2824
+
2825
+ .hw-code-copy--copied .hw-code-check-icon {
2826
+ filter: blur(0);
2827
+ opacity: 1;
2828
+ scale: 1;
2829
+ }
2830
+
2831
+ .hw-code-copy-label {
2832
+ position: absolute;
2833
+ width: 1px;
2834
+ height: 1px;
2835
+ overflow: hidden;
2836
+ clip: rect(0, 0, 0, 0);
2837
+ white-space: nowrap;
2645
2838
  }
2646
2839
 
2647
2840
  .hw-code-copy--copied {
@@ -2659,6 +2852,30 @@
2659
2852
  border-radius: 0;
2660
2853
  overflow-x: auto;
2661
2854
  max-width: 100%;
2855
+ max-height: 320px;
2856
+ scrollbar-color: rgba(0, 0, 0, 0.22) transparent;
2857
+ scrollbar-width: thin;
2858
+ }
2859
+
2860
+ .hw-code pre::-webkit-scrollbar {
2861
+ width: 10px;
2862
+ height: 10px;
2863
+ }
2864
+
2865
+ .hw-code pre::-webkit-scrollbar-track {
2866
+ background: transparent;
2867
+ }
2868
+
2869
+ .hw-code pre::-webkit-scrollbar-thumb {
2870
+ background: rgba(0, 0, 0, 0.18);
2871
+ background-clip: content-box;
2872
+ border: 3px solid transparent;
2873
+ border-radius: 999px;
2874
+ }
2875
+
2876
+ .hw-code pre::-webkit-scrollbar-thumb:hover {
2877
+ background: rgba(0, 0, 0, 0.28);
2878
+ background-clip: content-box;
2662
2879
  }
2663
2880
 
2664
2881
  .hw-code pre code {
@@ -2683,9 +2900,21 @@
2683
2900
  background: rgba(255, 255, 255, 0.03);
2684
2901
  border-bottom-color: rgba(255, 255, 255, 0.06);
2685
2902
  }
2686
- .hw-code-copy:hover {
2903
+ .hw-code-action:hover,
2904
+ .hw-code-action:focus-visible {
2687
2905
  background: rgba(255, 255, 255, 0.08);
2688
2906
  }
2907
+ .hw-code pre {
2908
+ scrollbar-color: rgba(255, 255, 255, 0.26) transparent;
2909
+ }
2910
+ .hw-code pre::-webkit-scrollbar-thumb {
2911
+ background: rgba(255, 255, 255, 0.22);
2912
+ background-clip: content-box;
2913
+ }
2914
+ .hw-code pre::-webkit-scrollbar-thumb:hover {
2915
+ background: rgba(255, 255, 255, 0.32);
2916
+ background-clip: content-box;
2917
+ }
2689
2918
  }
2690
2919
 
2691
2920
  /* Legacy bare <pre> fallback (rendered by old CMS bodyHtml content that may
@@ -2731,6 +2960,20 @@
2731
2960
  white-space: pre;
2732
2961
  }
2733
2962
 
2963
+ .hw-msg-bubble .hw-code pre {
2964
+ margin: 0;
2965
+ padding: 10px 12px;
2966
+ background: transparent;
2967
+ border-radius: 0;
2968
+ }
2969
+
2970
+ .hw-msg-bubble .hw-code pre code {
2971
+ background: transparent;
2972
+ padding: 0;
2973
+ font-size: 12px;
2974
+ line-height: 1.55;
2975
+ }
2976
+
2734
2977
  .hw-msg--team .hw-msg-bubble pre,
2735
2978
  .hw-msg--visitor .hw-msg-bubble pre {
2736
2979
  background: rgba(255, 255, 255, 0.12);
@@ -2827,6 +3070,9 @@
2827
3070
  .hw-msg-meta {
2828
3071
  opacity: 1;
2829
3072
  }
3073
+ .hw-msg-copy {
3074
+ opacity: 1;
3075
+ }
2830
3076
  }
2831
3077
 
2832
3078
  /* ════════════════════════════════════════════════
@@ -2885,11 +3131,20 @@
2885
3131
  color: var(--hw-text-4);
2886
3132
  cursor: pointer;
2887
3133
  vertical-align: middle;
2888
- transition: color 0.15s, background 0.15s;
3134
+ opacity: 0;
3135
+ transition:
3136
+ color 0.15s,
3137
+ background 0.15s,
3138
+ opacity 0.15s;
2889
3139
  padding: 0;
2890
3140
  flex-shrink: 0;
2891
3141
  }
2892
3142
 
3143
+ .hw-msg:hover .hw-msg-copy,
3144
+ .hw-msg:focus-within .hw-msg-copy {
3145
+ opacity: 1;
3146
+ }
3147
+
2893
3148
  .hw-msg-copy:hover {
2894
3149
  background: var(--hw-bg-hover);
2895
3150
  color: var(--hw-text-2);
@@ -3272,6 +3527,20 @@
3272
3527
  }
3273
3528
 
3274
3529
  @media (prefers-color-scheme: dark) {
3530
+ .hw-widget:not([data-theme="light"]) .hw-messages {
3531
+ scrollbar-color: rgba(255, 255, 255, 0.26) transparent;
3532
+ }
3533
+
3534
+ .hw-widget:not([data-theme="light"]) .hw-messages::-webkit-scrollbar-thumb {
3535
+ background: rgba(255, 255, 255, 0.2);
3536
+ background-clip: content-box;
3537
+ }
3538
+
3539
+ .hw-widget:not([data-theme="light"]) .hw-messages::-webkit-scrollbar-thumb:hover {
3540
+ background: rgba(255, 255, 255, 0.32);
3541
+ background-clip: content-box;
3542
+ }
3543
+
3275
3544
  .hw-widget:not([data-theme="light"]) {
3276
3545
  --hw-bg: #1c1c1e;
3277
3546
  --hw-bg-subtle: #161618;