chell-ai 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,62 @@
1
+ # chell-ai
2
+
3
+ Widget chat customer-facing untuk [Chell AI](https://chell-ai.app) — Voice of Customer Platform. Pasang chat bot di website Anda secepat install library biasa.
4
+
5
+ ## Instalasi
6
+
7
+ ```bash
8
+ npm install chell-ai
9
+ ```
10
+
11
+ ## Pemakaian
12
+
13
+ Tambahkan ke layout utama situs Anda (Next.js, atau React project apapun):
14
+
15
+ ```tsx
16
+ import { ChellWidget } from "chell-ai";
17
+
18
+ export default function RootLayout({ children }) {
19
+ return (
20
+ <html>
21
+ <body>
22
+ {children}
23
+ <ChellWidget businessId="chell_pk_xxxxxxxxxxxx" />
24
+ </body>
25
+ </html>
26
+ );
27
+ }
28
+ ```
29
+
30
+ Widget akan muncul sebagai bubble chat mengambang di pojok kanan bawah halaman.
31
+
32
+ Dapatkan `businessId` (widget key publik) dari dashboard Chell AI Anda — menu **Widget Chat**.
33
+
34
+ > Catatan untuk pengguna Next.js App Router: komponen ini sudah otomatis di-tandai `"use client"` saat di-build, jadi Anda TIDAK perlu menambahkan `"use client"` sendiri di file layout Anda, walaupun layout tersebut adalah Server Component.
35
+
36
+ ## Props
37
+
38
+ | Prop | Tipe | Wajib | Default | Keterangan |
39
+ |---|---|---|---|---|
40
+ | `businessId` | `string` | Ya | — | Widget key publik dari dashboard Chell AI (bukan business_id internal) |
41
+ | `baseUrl` | `string` | Tidak | `https://chell-ai.app` | Override domain backend, jarang perlu diubah |
42
+ | `position` | `"bottom-right" \| "bottom-left"` | Tidak | `"bottom-right"` | Posisi bubble di layar |
43
+
44
+ ### Konfigurasi via environment variable (opsional)
45
+
46
+ Kalau Anda lebih suka menyimpan `businessId` di `.env` daripada hardcode di JSX:
47
+
48
+ ```tsx
49
+ <ChellWidget businessId={process.env.NEXT_PUBLIC_CHELL_BUSINESS_ID!} />
50
+ ```
51
+
52
+ ## Cara Kerja
53
+
54
+ Widget ini SENGAJA sangat ringan — cuma tombol bubble yang menampilkan/menyembunyikan sebuah `<iframe>` yang me-load halaman chat dari domain Chell AI. Keuntungan pendekatan ini:
55
+
56
+ - **Isolasi CSS total** — style situs Anda (Tailwind, Bootstrap, CSS custom apapun) tidak akan bentrok dengan widget, dan sebaliknya.
57
+ - **Tidak ada masalah CORS** — semua request API terjadi dari dalam iframe (domain Chell AI), bukan dari domain situs Anda.
58
+ - **Update otomatis** — perbaikan/fitur baru di sisi chat di-deploy di backend Chell AI; instalasi widget Anda otomatis dapat update tanpa perlu `npm update`.
59
+
60
+ ## Lisensi
61
+
62
+ MIT
@@ -0,0 +1,40 @@
1
+ import * as react from 'react';
2
+
3
+ interface ChellWidgetProps {
4
+ /**
5
+ * Widget key PUBLIK dari dashboard Chell AI (menu "Widget Chat").
6
+ * BUKAN business_id internal — bentuknya seperti "chell_pk_xxxxx".
7
+ */
8
+ businessId: string;
9
+ /**
10
+ * Override base URL chat-bot (jarang perlu diubah). Default mengarah ke
11
+ * domain Chell AI resmi.
12
+ */
13
+ baseUrl?: string;
14
+ /** Posisi bubble di layar. Default: "bottom-right". */
15
+ position?: "bottom-right" | "bottom-left";
16
+ }
17
+ /**
18
+ * Widget chat customer-facing Chell AI.
19
+ *
20
+ * Cara pakai:
21
+ * import { ChellWidget } from "chell-ai";
22
+ * <ChellWidget businessId="chell_pk_xxxxx" />
23
+ *
24
+ * Komponen ini SENGAJA sangat tipis — cuma tombol bubble yang nge-toggle
25
+ * sebuah <iframe>. Seluruh logic percakapan (FAQ matching, nudge feedback,
26
+ * dll) ada di halaman yang di-load iframe (chat-bot/[widgetKey] di backend
27
+ * Chell AI), BUKAN di package ini. Keuntungan pendekatan ini:
28
+ *
29
+ * 1. ISOLASI CSS TOTAL — apapun yang terjadi di dalam iframe tidak akan
30
+ * bentrok dengan style situs Anda (font reset, z-index, dark mode, dll),
31
+ * dan sebaliknya.
32
+ * 2. TIDAK ADA MASALAH CORS — karena permintaan API terjadi dari DALAM
33
+ * iframe (origin domain Chell AI), bukan dari domain situs Anda.
34
+ * 3. Package ini jadi sangat kecil dan jarang perlu update — perbaikan/
35
+ * fitur baru di sisi chat cukup di-deploy di backend Chell AI, semua
36
+ * instalasi widget otomatis dapat update tanpa perlu `npm update`.
37
+ */
38
+ declare function ChellWidget({ businessId, baseUrl, position, }: ChellWidgetProps): react.JSX.Element | null;
39
+
40
+ export { ChellWidget, type ChellWidgetProps };
@@ -0,0 +1,40 @@
1
+ import * as react from 'react';
2
+
3
+ interface ChellWidgetProps {
4
+ /**
5
+ * Widget key PUBLIK dari dashboard Chell AI (menu "Widget Chat").
6
+ * BUKAN business_id internal — bentuknya seperti "chell_pk_xxxxx".
7
+ */
8
+ businessId: string;
9
+ /**
10
+ * Override base URL chat-bot (jarang perlu diubah). Default mengarah ke
11
+ * domain Chell AI resmi.
12
+ */
13
+ baseUrl?: string;
14
+ /** Posisi bubble di layar. Default: "bottom-right". */
15
+ position?: "bottom-right" | "bottom-left";
16
+ }
17
+ /**
18
+ * Widget chat customer-facing Chell AI.
19
+ *
20
+ * Cara pakai:
21
+ * import { ChellWidget } from "chell-ai";
22
+ * <ChellWidget businessId="chell_pk_xxxxx" />
23
+ *
24
+ * Komponen ini SENGAJA sangat tipis — cuma tombol bubble yang nge-toggle
25
+ * sebuah <iframe>. Seluruh logic percakapan (FAQ matching, nudge feedback,
26
+ * dll) ada di halaman yang di-load iframe (chat-bot/[widgetKey] di backend
27
+ * Chell AI), BUKAN di package ini. Keuntungan pendekatan ini:
28
+ *
29
+ * 1. ISOLASI CSS TOTAL — apapun yang terjadi di dalam iframe tidak akan
30
+ * bentrok dengan style situs Anda (font reset, z-index, dark mode, dll),
31
+ * dan sebaliknya.
32
+ * 2. TIDAK ADA MASALAH CORS — karena permintaan API terjadi dari DALAM
33
+ * iframe (origin domain Chell AI), bukan dari domain situs Anda.
34
+ * 3. Package ini jadi sangat kecil dan jarang perlu update — perbaikan/
35
+ * fitur baru di sisi chat cukup di-deploy di backend Chell AI, semua
36
+ * instalasi widget otomatis dapat update tanpa perlu `npm update`.
37
+ */
38
+ declare function ChellWidget({ businessId, baseUrl, position, }: ChellWidgetProps): react.JSX.Element | null;
39
+
40
+ export { ChellWidget, type ChellWidgetProps };
package/dist/index.js ADDED
@@ -0,0 +1,148 @@
1
+ "use client";
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/index.ts
22
+ var index_exports = {};
23
+ __export(index_exports, {
24
+ ChellWidget: () => ChellWidget
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/ChellWidget.tsx
29
+ var import_react = require("react");
30
+ var import_jsx_runtime = require("react/jsx-runtime");
31
+ var DEFAULT_BASE_URL = "https://chell-ai.my.id";
32
+ function ChellWidget({
33
+ businessId,
34
+ baseUrl = DEFAULT_BASE_URL,
35
+ position = "bottom-right"
36
+ }) {
37
+ const [open, setOpen] = (0, import_react.useState)(false);
38
+ if (!businessId) {
39
+ if (process.env.NODE_ENV !== "production") {
40
+ console.error(
41
+ '[ChellWidget] Prop "businessId" wajib diisi dengan widget key dari dashboard Chell AI (menu "Widget Chat"). Contoh: <ChellWidget businessId="chell_pk_xxxxx" />'
42
+ );
43
+ }
44
+ return null;
45
+ }
46
+ const sideStyle = position === "bottom-left" ? { left: 20 } : { right: 20 };
47
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { position: "fixed", bottom: 20, zIndex: 999999, ...sideStyle }, children: [
48
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { dangerouslySetInnerHTML: {
49
+ __html: `
50
+ @keyframes chell-panel-slide-up {
51
+ from { opacity: 0; transform: translateY(16px); }
52
+ to { opacity: 1; transform: translateY(0); }
53
+ }
54
+ @keyframes chell-icon-pop {
55
+ from { opacity: 0; transform: rotate(-45deg) scale(0.5); }
56
+ to { opacity: 1; transform: rotate(0) scale(1); }
57
+ }
58
+ .chell-widget-btn {
59
+ transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.25s ease !important;
60
+ }
61
+ .chell-widget-btn:hover {
62
+ transform: scale(1.1);
63
+ box-shadow: 0 8px 24px rgba(76, 67, 201, 0.4) !important;
64
+ }
65
+ .chell-widget-btn:active {
66
+ transform: scale(0.95);
67
+ }
68
+ .chell-widget-panel {
69
+ animation: chell-panel-slide-up 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
70
+ box-shadow: 0 12px 40px rgba(0,0,0,0.15) !important;
71
+ }
72
+ .chell-widget-icon {
73
+ animation: chell-icon-pop 0.3s cubic-bezier(0.16, 1, 0.3, 1) forwards;
74
+ display: flex;
75
+ }
76
+ `
77
+ } }),
78
+ open && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "chell-widget-panel", style: { ...panelStyle, ...sideStyle }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
79
+ "iframe",
80
+ {
81
+ src: `${baseUrl}/chat-bot/${encodeURIComponent(businessId)}?embed=true`,
82
+ title: "ChellAI Chat",
83
+ style: iframeStyle
84
+ }
85
+ ) }),
86
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
87
+ "button",
88
+ {
89
+ type: "button",
90
+ className: "chell-widget-btn",
91
+ onClick: () => setOpen((v) => !v),
92
+ "aria-label": open ? "Tutup chat" : "Buka chat",
93
+ style: bubbleStyle,
94
+ children: open ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "chell-widget-icon", style: { fontSize: 24, lineHeight: 1 }, children: "\u2715" }) : (
95
+ // Simbol Chell "Aperture" — C terbuka memeluk mutiara (mono putih)
96
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { className: "chell-widget-icon", viewBox: "0 0 100 100", width: 30, height: 30, fill: "none", "aria-hidden": "true", children: [
97
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
98
+ "path",
99
+ {
100
+ d: "M73.1 22.4 A36 36 0 1 0 73.1 77.6",
101
+ stroke: "#F5F1E8",
102
+ strokeWidth: 13,
103
+ strokeLinecap: "round"
104
+ }
105
+ ),
106
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: 50, cy: 50, r: 8, fill: "#F5F1E8" })
107
+ ] })
108
+ )
109
+ }
110
+ )
111
+ ] });
112
+ }
113
+ var bubbleStyle = {
114
+ width: 56,
115
+ height: 56,
116
+ borderRadius: "50%",
117
+ border: "none",
118
+ backgroundColor: "#4C43C9",
119
+ color: "#F5F1E8",
120
+ cursor: "pointer",
121
+ boxShadow: "0 4px 14px rgba(22,21,26,0.3)",
122
+ display: "flex",
123
+ alignItems: "center",
124
+ justifyContent: "center"
125
+ };
126
+ var panelStyle = {
127
+ position: "absolute",
128
+ bottom: 72,
129
+ width: 360,
130
+ height: 520,
131
+ maxWidth: "90vw",
132
+ maxHeight: "75vh",
133
+ borderRadius: 16,
134
+ overflow: "hidden",
135
+ boxShadow: "0 8px 30px rgba(0,0,0,0.3)",
136
+ backgroundColor: "#fff"
137
+ };
138
+ var iframeStyle = {
139
+ width: "100%",
140
+ height: "100%",
141
+ border: "none",
142
+ display: "block"
143
+ };
144
+ // Annotate the CommonJS export names for ESM import in node:
145
+ 0 && (module.exports = {
146
+ ChellWidget
147
+ });
148
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/ChellWidget.tsx"],"sourcesContent":["export { ChellWidget } from \"./ChellWidget\";\nexport type { ChellWidgetProps } from \"./ChellWidget\";\n","\"use client\";\n\nimport { useState, type CSSProperties } from \"react\";\n\nexport interface ChellWidgetProps {\n /**\n * Widget key PUBLIK dari dashboard Chell AI (menu \"Widget Chat\").\n * BUKAN business_id internal — bentuknya seperti \"chell_pk_xxxxx\".\n */\n businessId: string;\n /**\n * Override base URL chat-bot (jarang perlu diubah). Default mengarah ke\n * domain Chell AI resmi.\n */\n baseUrl?: string;\n /** Posisi bubble di layar. Default: \"bottom-right\". */\n position?: \"bottom-right\" | \"bottom-left\";\n}\n\nconst DEFAULT_BASE_URL = \"https://chell-ai.my.id\";\n\n/**\n * Widget chat customer-facing Chell AI.\n *\n * Cara pakai:\n * import { ChellWidget } from \"chell-ai\";\n * <ChellWidget businessId=\"chell_pk_xxxxx\" />\n *\n * Komponen ini SENGAJA sangat tipis — cuma tombol bubble yang nge-toggle\n * sebuah <iframe>. Seluruh logic percakapan (FAQ matching, nudge feedback,\n * dll) ada di halaman yang di-load iframe (chat-bot/[widgetKey] di backend\n * Chell AI), BUKAN di package ini. Keuntungan pendekatan ini:\n *\n * 1. ISOLASI CSS TOTAL — apapun yang terjadi di dalam iframe tidak akan\n * bentrok dengan style situs Anda (font reset, z-index, dark mode, dll),\n * dan sebaliknya.\n * 2. TIDAK ADA MASALAH CORS — karena permintaan API terjadi dari DALAM\n * iframe (origin domain Chell AI), bukan dari domain situs Anda.\n * 3. Package ini jadi sangat kecil dan jarang perlu update — perbaikan/\n * fitur baru di sisi chat cukup di-deploy di backend Chell AI, semua\n * instalasi widget otomatis dapat update tanpa perlu `npm update`.\n */\nexport function ChellWidget({\n businessId,\n baseUrl = DEFAULT_BASE_URL,\n position = \"bottom-right\",\n}: ChellWidgetProps) {\n const [open, setOpen] = useState(false);\n\n if (!businessId) {\n if (process.env.NODE_ENV !== \"production\") {\n // eslint-disable-next-line no-console\n console.error(\n '[ChellWidget] Prop \"businessId\" wajib diisi dengan widget key dari dashboard Chell AI ' +\n '(menu \"Widget Chat\"). Contoh: <ChellWidget businessId=\"chell_pk_xxxxx\" />'\n );\n }\n return null;\n }\n\n const sideStyle: CSSProperties = position === \"bottom-left\" ? { left: 20 } : { right: 20 };\n\n return (\n <div style={{ position: \"fixed\", bottom: 20, zIndex: 999999, ...sideStyle }}>\n <style dangerouslySetInnerHTML={{\n __html: `\n @keyframes chell-panel-slide-up {\n from { opacity: 0; transform: translateY(16px); }\n to { opacity: 1; transform: translateY(0); }\n }\n @keyframes chell-icon-pop {\n from { opacity: 0; transform: rotate(-45deg) scale(0.5); }\n to { opacity: 1; transform: rotate(0) scale(1); }\n }\n .chell-widget-btn {\n transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.25s ease !important;\n }\n .chell-widget-btn:hover {\n transform: scale(1.1);\n box-shadow: 0 8px 24px rgba(76, 67, 201, 0.4) !important;\n }\n .chell-widget-btn:active {\n transform: scale(0.95);\n }\n .chell-widget-panel {\n animation: chell-panel-slide-up 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;\n box-shadow: 0 12px 40px rgba(0,0,0,0.15) !important;\n }\n .chell-widget-icon {\n animation: chell-icon-pop 0.3s cubic-bezier(0.16, 1, 0.3, 1) forwards;\n display: flex;\n }\n `}} />\n\n {open && (\n <div className=\"chell-widget-panel\" style={{ ...panelStyle, ...sideStyle }}>\n <iframe\n src={`${baseUrl}/chat-bot/${encodeURIComponent(businessId)}?embed=true`}\n title=\"ChellAI Chat\"\n style={iframeStyle}\n />\n </div>\n )}\n\n <button\n type=\"button\"\n className=\"chell-widget-btn\"\n onClick={() => setOpen((v) => !v)}\n aria-label={open ? \"Tutup chat\" : \"Buka chat\"}\n style={bubbleStyle}\n >\n {open ? (\n <span className=\"chell-widget-icon\" style={{ fontSize: 24, lineHeight: 1 }}>✕</span>\n ) : (\n // Simbol Chell \"Aperture\" — C terbuka memeluk mutiara (mono putih)\n <svg className=\"chell-widget-icon\" viewBox=\"0 0 100 100\" width={30} height={30} fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M73.1 22.4 A36 36 0 1 0 73.1 77.6\"\n stroke=\"#F5F1E8\"\n strokeWidth={13}\n strokeLinecap=\"round\"\n />\n <circle cx={50} cy={50} r={8} fill=\"#F5F1E8\" />\n </svg>\n )}\n </button>\n </div>\n );\n}\n\n// Iris #4C43C9 — warna signature ChellAI (Chell Brand System v1.0)\nconst bubbleStyle: CSSProperties = {\n width: 56,\n height: 56,\n borderRadius: \"50%\",\n border: \"none\",\n backgroundColor: \"#4C43C9\",\n color: \"#F5F1E8\",\n cursor: \"pointer\",\n boxShadow: \"0 4px 14px rgba(22,21,26,0.3)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n};\n\nconst panelStyle: CSSProperties = {\n position: \"absolute\",\n bottom: 72,\n width: 360,\n height: 520,\n maxWidth: \"90vw\",\n maxHeight: \"75vh\",\n borderRadius: 16,\n overflow: \"hidden\",\n boxShadow: \"0 8px 30px rgba(0,0,0,0.3)\",\n backgroundColor: \"#fff\",\n};\n\nconst iframeStyle: CSSProperties = {\n width: \"100%\",\n height: \"100%\",\n border: \"none\",\n display: \"block\",\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,mBAA6C;AA8DvC;AA7CN,IAAM,mBAAmB;AAuBlB,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,UAAU;AAAA,EACV,WAAW;AACb,GAAqB;AACnB,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAS,KAAK;AAEtC,MAAI,CAAC,YAAY;AACf,QAAI,QAAQ,IAAI,aAAa,cAAc;AAEzC,cAAQ;AAAA,QACN;AAAA,MAEF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,YAA2B,aAAa,gBAAgB,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,GAAG;AAEzF,SACE,6CAAC,SAAI,OAAO,EAAE,UAAU,SAAS,QAAQ,IAAI,QAAQ,QAAQ,GAAG,UAAU,GACxE;AAAA,gDAAC,WAAM,yBAAyB;AAAA,MAC9B,QAAQ;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,IA2BT,GAAG;AAAA,IAEH,QACC,4CAAC,SAAI,WAAU,sBAAqB,OAAO,EAAE,GAAG,YAAY,GAAG,UAAU,GACvE;AAAA,MAAC;AAAA;AAAA,QACC,KAAK,GAAG,OAAO,aAAa,mBAAmB,UAAU,CAAC;AAAA,QAC1D,OAAM;AAAA,QACN,OAAO;AAAA;AAAA,IACT,GACF;AAAA,IAGF;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;AAAA,QAChC,cAAY,OAAO,eAAe;AAAA,QAClC,OAAO;AAAA,QAEN,iBACC,4CAAC,UAAK,WAAU,qBAAoB,OAAO,EAAE,UAAU,IAAI,YAAY,EAAE,GAAG,oBAAC;AAAA;AAAA,UAG7E,6CAAC,SAAI,WAAU,qBAAoB,SAAQ,eAAc,OAAO,IAAI,QAAQ,IAAI,MAAK,QAAO,eAAY,QACtG;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,GAAE;AAAA,gBACF,QAAO;AAAA,gBACP,aAAa;AAAA,gBACb,eAAc;AAAA;AAAA,YAChB;AAAA,YACA,4CAAC,YAAO,IAAI,IAAI,IAAI,IAAI,GAAG,GAAG,MAAK,WAAU;AAAA,aAC/C;AAAA;AAAA;AAAA,IAEJ;AAAA,KACF;AAEJ;AAGA,IAAM,cAA6B;AAAA,EACjC,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,iBAAiB;AAAA,EACjB,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,gBAAgB;AAClB;AAEA,IAAM,aAA4B;AAAA,EAChC,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,WAAW;AAAA,EACX,cAAc;AAAA,EACd,UAAU;AAAA,EACV,WAAW;AAAA,EACX,iBAAiB;AACnB;AAEA,IAAM,cAA6B;AAAA,EACjC,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AACX;","names":[]}
package/dist/index.mjs ADDED
@@ -0,0 +1,122 @@
1
+ "use client";
2
+
3
+ // src/ChellWidget.tsx
4
+ import { useState } from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ var DEFAULT_BASE_URL = "https://chell-ai.my.id";
7
+ function ChellWidget({
8
+ businessId,
9
+ baseUrl = DEFAULT_BASE_URL,
10
+ position = "bottom-right"
11
+ }) {
12
+ const [open, setOpen] = useState(false);
13
+ if (!businessId) {
14
+ if (process.env.NODE_ENV !== "production") {
15
+ console.error(
16
+ '[ChellWidget] Prop "businessId" wajib diisi dengan widget key dari dashboard Chell AI (menu "Widget Chat"). Contoh: <ChellWidget businessId="chell_pk_xxxxx" />'
17
+ );
18
+ }
19
+ return null;
20
+ }
21
+ const sideStyle = position === "bottom-left" ? { left: 20 } : { right: 20 };
22
+ return /* @__PURE__ */ jsxs("div", { style: { position: "fixed", bottom: 20, zIndex: 999999, ...sideStyle }, children: [
23
+ /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: {
24
+ __html: `
25
+ @keyframes chell-panel-slide-up {
26
+ from { opacity: 0; transform: translateY(16px); }
27
+ to { opacity: 1; transform: translateY(0); }
28
+ }
29
+ @keyframes chell-icon-pop {
30
+ from { opacity: 0; transform: rotate(-45deg) scale(0.5); }
31
+ to { opacity: 1; transform: rotate(0) scale(1); }
32
+ }
33
+ .chell-widget-btn {
34
+ transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.25s ease !important;
35
+ }
36
+ .chell-widget-btn:hover {
37
+ transform: scale(1.1);
38
+ box-shadow: 0 8px 24px rgba(76, 67, 201, 0.4) !important;
39
+ }
40
+ .chell-widget-btn:active {
41
+ transform: scale(0.95);
42
+ }
43
+ .chell-widget-panel {
44
+ animation: chell-panel-slide-up 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
45
+ box-shadow: 0 12px 40px rgba(0,0,0,0.15) !important;
46
+ }
47
+ .chell-widget-icon {
48
+ animation: chell-icon-pop 0.3s cubic-bezier(0.16, 1, 0.3, 1) forwards;
49
+ display: flex;
50
+ }
51
+ `
52
+ } }),
53
+ open && /* @__PURE__ */ jsx("div", { className: "chell-widget-panel", style: { ...panelStyle, ...sideStyle }, children: /* @__PURE__ */ jsx(
54
+ "iframe",
55
+ {
56
+ src: `${baseUrl}/chat-bot/${encodeURIComponent(businessId)}?embed=true`,
57
+ title: "ChellAI Chat",
58
+ style: iframeStyle
59
+ }
60
+ ) }),
61
+ /* @__PURE__ */ jsx(
62
+ "button",
63
+ {
64
+ type: "button",
65
+ className: "chell-widget-btn",
66
+ onClick: () => setOpen((v) => !v),
67
+ "aria-label": open ? "Tutup chat" : "Buka chat",
68
+ style: bubbleStyle,
69
+ children: open ? /* @__PURE__ */ jsx("span", { className: "chell-widget-icon", style: { fontSize: 24, lineHeight: 1 }, children: "\u2715" }) : (
70
+ // Simbol Chell "Aperture" — C terbuka memeluk mutiara (mono putih)
71
+ /* @__PURE__ */ jsxs("svg", { className: "chell-widget-icon", viewBox: "0 0 100 100", width: 30, height: 30, fill: "none", "aria-hidden": "true", children: [
72
+ /* @__PURE__ */ jsx(
73
+ "path",
74
+ {
75
+ d: "M73.1 22.4 A36 36 0 1 0 73.1 77.6",
76
+ stroke: "#F5F1E8",
77
+ strokeWidth: 13,
78
+ strokeLinecap: "round"
79
+ }
80
+ ),
81
+ /* @__PURE__ */ jsx("circle", { cx: 50, cy: 50, r: 8, fill: "#F5F1E8" })
82
+ ] })
83
+ )
84
+ }
85
+ )
86
+ ] });
87
+ }
88
+ var bubbleStyle = {
89
+ width: 56,
90
+ height: 56,
91
+ borderRadius: "50%",
92
+ border: "none",
93
+ backgroundColor: "#4C43C9",
94
+ color: "#F5F1E8",
95
+ cursor: "pointer",
96
+ boxShadow: "0 4px 14px rgba(22,21,26,0.3)",
97
+ display: "flex",
98
+ alignItems: "center",
99
+ justifyContent: "center"
100
+ };
101
+ var panelStyle = {
102
+ position: "absolute",
103
+ bottom: 72,
104
+ width: 360,
105
+ height: 520,
106
+ maxWidth: "90vw",
107
+ maxHeight: "75vh",
108
+ borderRadius: 16,
109
+ overflow: "hidden",
110
+ boxShadow: "0 8px 30px rgba(0,0,0,0.3)",
111
+ backgroundColor: "#fff"
112
+ };
113
+ var iframeStyle = {
114
+ width: "100%",
115
+ height: "100%",
116
+ border: "none",
117
+ display: "block"
118
+ };
119
+ export {
120
+ ChellWidget
121
+ };
122
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ChellWidget.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, type CSSProperties } from \"react\";\n\nexport interface ChellWidgetProps {\n /**\n * Widget key PUBLIK dari dashboard Chell AI (menu \"Widget Chat\").\n * BUKAN business_id internal — bentuknya seperti \"chell_pk_xxxxx\".\n */\n businessId: string;\n /**\n * Override base URL chat-bot (jarang perlu diubah). Default mengarah ke\n * domain Chell AI resmi.\n */\n baseUrl?: string;\n /** Posisi bubble di layar. Default: \"bottom-right\". */\n position?: \"bottom-right\" | \"bottom-left\";\n}\n\nconst DEFAULT_BASE_URL = \"https://chell-ai.my.id\";\n\n/**\n * Widget chat customer-facing Chell AI.\n *\n * Cara pakai:\n * import { ChellWidget } from \"chell-ai\";\n * <ChellWidget businessId=\"chell_pk_xxxxx\" />\n *\n * Komponen ini SENGAJA sangat tipis — cuma tombol bubble yang nge-toggle\n * sebuah <iframe>. Seluruh logic percakapan (FAQ matching, nudge feedback,\n * dll) ada di halaman yang di-load iframe (chat-bot/[widgetKey] di backend\n * Chell AI), BUKAN di package ini. Keuntungan pendekatan ini:\n *\n * 1. ISOLASI CSS TOTAL — apapun yang terjadi di dalam iframe tidak akan\n * bentrok dengan style situs Anda (font reset, z-index, dark mode, dll),\n * dan sebaliknya.\n * 2. TIDAK ADA MASALAH CORS — karena permintaan API terjadi dari DALAM\n * iframe (origin domain Chell AI), bukan dari domain situs Anda.\n * 3. Package ini jadi sangat kecil dan jarang perlu update — perbaikan/\n * fitur baru di sisi chat cukup di-deploy di backend Chell AI, semua\n * instalasi widget otomatis dapat update tanpa perlu `npm update`.\n */\nexport function ChellWidget({\n businessId,\n baseUrl = DEFAULT_BASE_URL,\n position = \"bottom-right\",\n}: ChellWidgetProps) {\n const [open, setOpen] = useState(false);\n\n if (!businessId) {\n if (process.env.NODE_ENV !== \"production\") {\n // eslint-disable-next-line no-console\n console.error(\n '[ChellWidget] Prop \"businessId\" wajib diisi dengan widget key dari dashboard Chell AI ' +\n '(menu \"Widget Chat\"). Contoh: <ChellWidget businessId=\"chell_pk_xxxxx\" />'\n );\n }\n return null;\n }\n\n const sideStyle: CSSProperties = position === \"bottom-left\" ? { left: 20 } : { right: 20 };\n\n return (\n <div style={{ position: \"fixed\", bottom: 20, zIndex: 999999, ...sideStyle }}>\n <style dangerouslySetInnerHTML={{\n __html: `\n @keyframes chell-panel-slide-up {\n from { opacity: 0; transform: translateY(16px); }\n to { opacity: 1; transform: translateY(0); }\n }\n @keyframes chell-icon-pop {\n from { opacity: 0; transform: rotate(-45deg) scale(0.5); }\n to { opacity: 1; transform: rotate(0) scale(1); }\n }\n .chell-widget-btn {\n transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.25s ease !important;\n }\n .chell-widget-btn:hover {\n transform: scale(1.1);\n box-shadow: 0 8px 24px rgba(76, 67, 201, 0.4) !important;\n }\n .chell-widget-btn:active {\n transform: scale(0.95);\n }\n .chell-widget-panel {\n animation: chell-panel-slide-up 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;\n box-shadow: 0 12px 40px rgba(0,0,0,0.15) !important;\n }\n .chell-widget-icon {\n animation: chell-icon-pop 0.3s cubic-bezier(0.16, 1, 0.3, 1) forwards;\n display: flex;\n }\n `}} />\n\n {open && (\n <div className=\"chell-widget-panel\" style={{ ...panelStyle, ...sideStyle }}>\n <iframe\n src={`${baseUrl}/chat-bot/${encodeURIComponent(businessId)}?embed=true`}\n title=\"ChellAI Chat\"\n style={iframeStyle}\n />\n </div>\n )}\n\n <button\n type=\"button\"\n className=\"chell-widget-btn\"\n onClick={() => setOpen((v) => !v)}\n aria-label={open ? \"Tutup chat\" : \"Buka chat\"}\n style={bubbleStyle}\n >\n {open ? (\n <span className=\"chell-widget-icon\" style={{ fontSize: 24, lineHeight: 1 }}>✕</span>\n ) : (\n // Simbol Chell \"Aperture\" — C terbuka memeluk mutiara (mono putih)\n <svg className=\"chell-widget-icon\" viewBox=\"0 0 100 100\" width={30} height={30} fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M73.1 22.4 A36 36 0 1 0 73.1 77.6\"\n stroke=\"#F5F1E8\"\n strokeWidth={13}\n strokeLinecap=\"round\"\n />\n <circle cx={50} cy={50} r={8} fill=\"#F5F1E8\" />\n </svg>\n )}\n </button>\n </div>\n );\n}\n\n// Iris #4C43C9 — warna signature ChellAI (Chell Brand System v1.0)\nconst bubbleStyle: CSSProperties = {\n width: 56,\n height: 56,\n borderRadius: \"50%\",\n border: \"none\",\n backgroundColor: \"#4C43C9\",\n color: \"#F5F1E8\",\n cursor: \"pointer\",\n boxShadow: \"0 4px 14px rgba(22,21,26,0.3)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n};\n\nconst panelStyle: CSSProperties = {\n position: \"absolute\",\n bottom: 72,\n width: 360,\n height: 520,\n maxWidth: \"90vw\",\n maxHeight: \"75vh\",\n borderRadius: 16,\n overflow: \"hidden\",\n boxShadow: \"0 8px 30px rgba(0,0,0,0.3)\",\n backgroundColor: \"#fff\",\n};\n\nconst iframeStyle: CSSProperties = {\n width: \"100%\",\n height: \"100%\",\n border: \"none\",\n display: \"block\",\n};\n"],"mappings":";;;AAEA,SAAS,gBAAoC;AA8DvC,cAmDI,YAnDJ;AA7CN,IAAM,mBAAmB;AAuBlB,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,UAAU;AAAA,EACV,WAAW;AACb,GAAqB;AACnB,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AAEtC,MAAI,CAAC,YAAY;AACf,QAAI,QAAQ,IAAI,aAAa,cAAc;AAEzC,cAAQ;AAAA,QACN;AAAA,MAEF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,YAA2B,aAAa,gBAAgB,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,GAAG;AAEzF,SACE,qBAAC,SAAI,OAAO,EAAE,UAAU,SAAS,QAAQ,IAAI,QAAQ,QAAQ,GAAG,UAAU,GACxE;AAAA,wBAAC,WAAM,yBAAyB;AAAA,MAC9B,QAAQ;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,IA2BT,GAAG;AAAA,IAEH,QACC,oBAAC,SAAI,WAAU,sBAAqB,OAAO,EAAE,GAAG,YAAY,GAAG,UAAU,GACvE;AAAA,MAAC;AAAA;AAAA,QACC,KAAK,GAAG,OAAO,aAAa,mBAAmB,UAAU,CAAC;AAAA,QAC1D,OAAM;AAAA,QACN,OAAO;AAAA;AAAA,IACT,GACF;AAAA,IAGF;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;AAAA,QAChC,cAAY,OAAO,eAAe;AAAA,QAClC,OAAO;AAAA,QAEN,iBACC,oBAAC,UAAK,WAAU,qBAAoB,OAAO,EAAE,UAAU,IAAI,YAAY,EAAE,GAAG,oBAAC;AAAA;AAAA,UAG7E,qBAAC,SAAI,WAAU,qBAAoB,SAAQ,eAAc,OAAO,IAAI,QAAQ,IAAI,MAAK,QAAO,eAAY,QACtG;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,GAAE;AAAA,gBACF,QAAO;AAAA,gBACP,aAAa;AAAA,gBACb,eAAc;AAAA;AAAA,YAChB;AAAA,YACA,oBAAC,YAAO,IAAI,IAAI,IAAI,IAAI,GAAG,GAAG,MAAK,WAAU;AAAA,aAC/C;AAAA;AAAA;AAAA,IAEJ;AAAA,KACF;AAEJ;AAGA,IAAM,cAA6B;AAAA,EACjC,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,iBAAiB;AAAA,EACjB,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,gBAAgB;AAClB;AAEA,IAAM,aAA4B;AAAA,EAChC,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,WAAW;AAAA,EACX,cAAc;AAAA,EACd,UAAU;AAAA,EACV,WAAW;AAAA,EACX,iBAAiB;AACnB;AAEA,IAAM,cAA6B;AAAA,EACjC,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AACX;","names":[]}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "chell-ai",
3
+ "version": "0.1.0",
4
+ "description": "Widget chat customer-facing untuk Chell AI — Voice of Customer Platform. Pasang chat bot di website Anda dengan satu komponen React.",
5
+ "main": "./dist/index.cjs",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "require": "./dist/index.cjs",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsup",
20
+ "dev": "tsup --watch"
21
+ },
22
+ "keywords": [
23
+ "chell-ai",
24
+ "chatbot",
25
+ "customer-feedback",
26
+ "voice-of-customer",
27
+ "widget"
28
+ ],
29
+ "license": "MIT",
30
+ "peerDependencies": {
31
+ "react": ">=18.0.0",
32
+ "react-dom": ">=18.0.0"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^26.1.0",
36
+ "@types/react": "^18.3.3",
37
+ "@types/react-dom": "^18.3.0",
38
+ "react": "^18.3.1",
39
+ "react-dom": "^18.3.1",
40
+ "tsup": "^8.0.2",
41
+ "typescript": "^5.5.3"
42
+ }
43
+ }