@citewidget/vue 0.0.0-stage → 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/LICENSE +21 -0
- package/README.md +71 -2
- package/dist/CiteWidget.d.ts +99 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +108 -0
- package/dist/registry.d.ts +10 -0
- package/dist/useCiteWidget.d.ts +13 -0
- package/package.json +40 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CiteWidget
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,72 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @citewidget/vue
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The CiteWidget chat for Vue 3 and Nuxt: visitors ask questions and get answers from your
|
|
4
|
+
documents, with links to the pages they came from.
|
|
5
|
+
|
|
6
|
+
```sh
|
|
7
|
+
npm install @citewidget/vue
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
This package is ES modules only (no CommonJS build): use `import`, not `require()`. Every current bundler and Node 22+ handle that; with an older CommonJS-only setup, load the script tag version instead.
|
|
11
|
+
|
|
12
|
+
## Quick start
|
|
13
|
+
|
|
14
|
+
```vue
|
|
15
|
+
<script setup lang="ts">
|
|
16
|
+
import { CiteWidget } from "@citewidget/vue";
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<RouterView />
|
|
21
|
+
<CiteWidget workspace-key="pk_..." primary-color="#0F766E" />
|
|
22
|
+
</template>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`<CiteWidget>` renders nothing where you place it: when mounted it adds the chat as a fixed
|
|
26
|
+
overlay at the end of `<body>`. Put it once in your root component or layout.
|
|
27
|
+
|
|
28
|
+
### Nuxt
|
|
29
|
+
|
|
30
|
+
The component only mounts the widget in `onMounted`, so server rendering outputs nothing and
|
|
31
|
+
never touches the browser. Use it in `app.vue` or a layout as above; wrapping it in
|
|
32
|
+
`<ClientOnly>` is optional.
|
|
33
|
+
|
|
34
|
+
## Your own button
|
|
35
|
+
|
|
36
|
+
```vue
|
|
37
|
+
<script setup lang="ts">
|
|
38
|
+
import { useCiteWidget } from "@citewidget/vue";
|
|
39
|
+
const widget = useCiteWidget();
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<template>
|
|
43
|
+
<button type="button" @click="widget.open">Ask about this product</button>
|
|
44
|
+
</template>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`useCiteWidget()` returns `open`, `close`, `toggle` and `newChat` for the mounted `<CiteWidget>`
|
|
48
|
+
(the newest one if there are several). Combine it with `:show-launcher="false"` to hide the
|
|
49
|
+
round button. Calling them while no widget is mounted logs a warning and does nothing.
|
|
50
|
+
|
|
51
|
+
## Props and events
|
|
52
|
+
|
|
53
|
+
Every option of `createCiteWidget` from
|
|
54
|
+
[`@citewidget/widget`](https://www.npmjs.com/package/@citewidget/widget) is a prop (kebab-case in
|
|
55
|
+
templates): `workspace-key` (required), `api-url`, `server-url`, `load-dashboard-settings`,
|
|
56
|
+
`title`, `greeting`, `bot-name`, `primary-color`, `surface-color`, `color-scheme`, `position`,
|
|
57
|
+
`show-launcher`, `launcher-label`, `launcher-icon`, `launcher-icon-url`, `soft-refusal`,
|
|
58
|
+
`goodbye`, `suggestions`, `handoff`, `handoff-reply-time`, `lead-capture`,
|
|
59
|
+
`chat-duration-minutes`, `nonce`. See that package for types, limits and defaults.
|
|
60
|
+
|
|
61
|
+
Events `open`, `close` and `handoff` are emitted with no payload: nothing a visitor typed reaches
|
|
62
|
+
your code.
|
|
63
|
+
|
|
64
|
+
- Settings combine as: built-in defaults < your CiteWidget dashboard < props. A boolean prop you
|
|
65
|
+
don't set stays unset (not `false`), and clearing a prop hands it back to the dashboard.
|
|
66
|
+
- Changing props updates the widget; it is rebuilt only when something visible changed.
|
|
67
|
+
- A missing or invalid `workspace-key` is logged with `console.error` and nothing is shown; other
|
|
68
|
+
invalid values are ignored with a console warning.
|
|
69
|
+
|
|
70
|
+
## Licence
|
|
71
|
+
|
|
72
|
+
MIT. See [LICENSE](./LICENSE).
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { type PropType } from "vue";
|
|
2
|
+
import { type CiteWidgetColorScheme, type CiteWidgetLauncherIcon, type CiteWidgetPosition } from "@citewidget/widget";
|
|
3
|
+
/**
|
|
4
|
+
* The CiteWidget chat for Vue 3 / Nuxt. Renders nothing in place: the widget is a fixed overlay
|
|
5
|
+
* appended to <body> in onMounted, so server rendering (Nuxt SSR) never touches the browser.
|
|
6
|
+
* Emits open, close and handoff with no payload.
|
|
7
|
+
*/
|
|
8
|
+
export declare const CiteWidget: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
9
|
+
workspaceKey: {
|
|
10
|
+
type: StringConstructor;
|
|
11
|
+
required: true;
|
|
12
|
+
};
|
|
13
|
+
apiUrl: StringConstructor;
|
|
14
|
+
serverUrl: StringConstructor;
|
|
15
|
+
loadDashboardSettings: {
|
|
16
|
+
readonly type: BooleanConstructor;
|
|
17
|
+
readonly default: undefined;
|
|
18
|
+
};
|
|
19
|
+
title: StringConstructor;
|
|
20
|
+
greeting: StringConstructor;
|
|
21
|
+
botName: StringConstructor;
|
|
22
|
+
primaryColor: StringConstructor;
|
|
23
|
+
surfaceColor: StringConstructor;
|
|
24
|
+
colorScheme: PropType<CiteWidgetColorScheme>;
|
|
25
|
+
position: PropType<CiteWidgetPosition>;
|
|
26
|
+
showLauncher: {
|
|
27
|
+
readonly type: BooleanConstructor;
|
|
28
|
+
readonly default: undefined;
|
|
29
|
+
};
|
|
30
|
+
launcherLabel: StringConstructor;
|
|
31
|
+
launcherIcon: PropType<CiteWidgetLauncherIcon>;
|
|
32
|
+
launcherIconUrl: StringConstructor;
|
|
33
|
+
softRefusal: StringConstructor;
|
|
34
|
+
goodbye: StringConstructor;
|
|
35
|
+
suggestions: PropType<readonly string[]>;
|
|
36
|
+
handoff: {
|
|
37
|
+
readonly type: BooleanConstructor;
|
|
38
|
+
readonly default: undefined;
|
|
39
|
+
};
|
|
40
|
+
handoffReplyTime: StringConstructor;
|
|
41
|
+
leadCapture: {
|
|
42
|
+
readonly type: BooleanConstructor;
|
|
43
|
+
readonly default: undefined;
|
|
44
|
+
};
|
|
45
|
+
chatDurationMinutes: NumberConstructor;
|
|
46
|
+
nonce: StringConstructor;
|
|
47
|
+
}>, () => null, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
48
|
+
open: () => true;
|
|
49
|
+
close: () => true;
|
|
50
|
+
handoff: () => true;
|
|
51
|
+
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
52
|
+
workspaceKey: {
|
|
53
|
+
type: StringConstructor;
|
|
54
|
+
required: true;
|
|
55
|
+
};
|
|
56
|
+
apiUrl: StringConstructor;
|
|
57
|
+
serverUrl: StringConstructor;
|
|
58
|
+
loadDashboardSettings: {
|
|
59
|
+
readonly type: BooleanConstructor;
|
|
60
|
+
readonly default: undefined;
|
|
61
|
+
};
|
|
62
|
+
title: StringConstructor;
|
|
63
|
+
greeting: StringConstructor;
|
|
64
|
+
botName: StringConstructor;
|
|
65
|
+
primaryColor: StringConstructor;
|
|
66
|
+
surfaceColor: StringConstructor;
|
|
67
|
+
colorScheme: PropType<CiteWidgetColorScheme>;
|
|
68
|
+
position: PropType<CiteWidgetPosition>;
|
|
69
|
+
showLauncher: {
|
|
70
|
+
readonly type: BooleanConstructor;
|
|
71
|
+
readonly default: undefined;
|
|
72
|
+
};
|
|
73
|
+
launcherLabel: StringConstructor;
|
|
74
|
+
launcherIcon: PropType<CiteWidgetLauncherIcon>;
|
|
75
|
+
launcherIconUrl: StringConstructor;
|
|
76
|
+
softRefusal: StringConstructor;
|
|
77
|
+
goodbye: StringConstructor;
|
|
78
|
+
suggestions: PropType<readonly string[]>;
|
|
79
|
+
handoff: {
|
|
80
|
+
readonly type: BooleanConstructor;
|
|
81
|
+
readonly default: undefined;
|
|
82
|
+
};
|
|
83
|
+
handoffReplyTime: StringConstructor;
|
|
84
|
+
leadCapture: {
|
|
85
|
+
readonly type: BooleanConstructor;
|
|
86
|
+
readonly default: undefined;
|
|
87
|
+
};
|
|
88
|
+
chatDurationMinutes: NumberConstructor;
|
|
89
|
+
nonce: StringConstructor;
|
|
90
|
+
}>> & Readonly<{
|
|
91
|
+
onClose?: (() => any) | undefined;
|
|
92
|
+
onHandoff?: (() => any) | undefined;
|
|
93
|
+
onOpen?: (() => any) | undefined;
|
|
94
|
+
}>, {
|
|
95
|
+
loadDashboardSettings: boolean;
|
|
96
|
+
showLauncher: boolean;
|
|
97
|
+
handoff: boolean;
|
|
98
|
+
leadCapture: boolean;
|
|
99
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @citewidget/vue: the CiteWidget chat for Vue 3 and Nuxt. Safe in server rendering: the widget
|
|
3
|
+
* mounts in onMounted only.
|
|
4
|
+
*/
|
|
5
|
+
export { CiteWidget } from "./CiteWidget";
|
|
6
|
+
export { useCiteWidget, type CiteWidgetControls } from "./useCiteWidget";
|
|
7
|
+
export type { CiteWidgetColorScheme, CiteWidgetLauncherIcon, CiteWidgetOptions, CiteWidgetPosition, } from "@citewidget/widget";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// src/CiteWidget.ts
|
|
2
|
+
import { defineComponent, onBeforeUnmount, onMounted, watch } from "vue";
|
|
3
|
+
import {
|
|
4
|
+
createCiteWidget
|
|
5
|
+
} from "@citewidget/widget";
|
|
6
|
+
|
|
7
|
+
// src/registry.ts
|
|
8
|
+
var mounted = [];
|
|
9
|
+
function registerWidget(widget) {
|
|
10
|
+
return mounted = [...mounted, widget], () => {
|
|
11
|
+
mounted = mounted.filter((entry) => entry !== widget);
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function currentWidget() {
|
|
15
|
+
return mounted[mounted.length - 1] ?? null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// src/CiteWidget.ts
|
|
19
|
+
var optionalBoolean = { type: Boolean, default: void 0 }, CiteWidget = defineComponent({
|
|
20
|
+
name: "CiteWidget",
|
|
21
|
+
props: {
|
|
22
|
+
workspaceKey: { type: String, required: !0 },
|
|
23
|
+
apiUrl: String,
|
|
24
|
+
serverUrl: String,
|
|
25
|
+
loadDashboardSettings: optionalBoolean,
|
|
26
|
+
title: String,
|
|
27
|
+
greeting: String,
|
|
28
|
+
botName: String,
|
|
29
|
+
primaryColor: String,
|
|
30
|
+
surfaceColor: String,
|
|
31
|
+
colorScheme: String,
|
|
32
|
+
position: String,
|
|
33
|
+
showLauncher: optionalBoolean,
|
|
34
|
+
launcherLabel: String,
|
|
35
|
+
launcherIcon: String,
|
|
36
|
+
launcherIconUrl: String,
|
|
37
|
+
softRefusal: String,
|
|
38
|
+
goodbye: String,
|
|
39
|
+
suggestions: Array,
|
|
40
|
+
handoff: optionalBoolean,
|
|
41
|
+
handoffReplyTime: String,
|
|
42
|
+
leadCapture: optionalBoolean,
|
|
43
|
+
chatDurationMinutes: Number,
|
|
44
|
+
nonce: String
|
|
45
|
+
},
|
|
46
|
+
emits: {
|
|
47
|
+
open: () => !0,
|
|
48
|
+
close: () => !0,
|
|
49
|
+
handoff: () => !0
|
|
50
|
+
},
|
|
51
|
+
setup(props, { emit }) {
|
|
52
|
+
let widget = null, unregister = () => {
|
|
53
|
+
}, options = () => ({ ...props }), start = () => {
|
|
54
|
+
try {
|
|
55
|
+
widget = createCiteWidget({
|
|
56
|
+
...options(),
|
|
57
|
+
onOpen: () => emit("open"),
|
|
58
|
+
onClose: () => emit("close"),
|
|
59
|
+
onHandoff: () => emit("handoff")
|
|
60
|
+
});
|
|
61
|
+
} catch (error) {
|
|
62
|
+
console.error(error instanceof Error ? error.message : error);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
unregister = registerWidget(widget);
|
|
66
|
+
};
|
|
67
|
+
return onMounted(start), watch(
|
|
68
|
+
options,
|
|
69
|
+
(next) => {
|
|
70
|
+
if (!widget) {
|
|
71
|
+
start();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
widget.update(next);
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error(error instanceof Error ? error.message : error);
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
{ deep: !0 }
|
|
81
|
+
), onBeforeUnmount(() => {
|
|
82
|
+
unregister(), widget?.destroy(), widget = null;
|
|
83
|
+
}), () => null;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// src/useCiteWidget.ts
|
|
88
|
+
function call(method) {
|
|
89
|
+
let widget = currentWidget();
|
|
90
|
+
if (widget) {
|
|
91
|
+
widget[method]();
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
console.warn(`[CiteWidget] ${method}() was called, but no <CiteWidget> is mounted.`);
|
|
95
|
+
}
|
|
96
|
+
var controls = Object.freeze({
|
|
97
|
+
open: () => call("open"),
|
|
98
|
+
close: () => call("close"),
|
|
99
|
+
toggle: () => call("toggle"),
|
|
100
|
+
newChat: () => call("newChat")
|
|
101
|
+
});
|
|
102
|
+
function useCiteWidget() {
|
|
103
|
+
return controls;
|
|
104
|
+
}
|
|
105
|
+
export {
|
|
106
|
+
CiteWidget,
|
|
107
|
+
useCiteWidget
|
|
108
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The widgets <CiteWidget> has mounted, newest last, so useCiteWidget() can reach the current one
|
|
3
|
+
* from anywhere in the app without provide/inject. Written only in onMounted / onBeforeUnmount
|
|
4
|
+
* (browser), so server rendering never sees or shares it.
|
|
5
|
+
*/
|
|
6
|
+
import type { CiteWidgetController } from "@citewidget/widget";
|
|
7
|
+
/** Adds a widget; the returned function removes it again. */
|
|
8
|
+
export declare function registerWidget(widget: CiteWidgetController): () => void;
|
|
9
|
+
/** The most recently mounted widget, or null. */
|
|
10
|
+
export declare function currentWidget(): CiteWidgetController | null;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Controls for the mounted <CiteWidget>; plain functions, safe to bind to @click. */
|
|
2
|
+
export interface CiteWidgetControls {
|
|
3
|
+
open(): void;
|
|
4
|
+
close(): void;
|
|
5
|
+
toggle(): void;
|
|
6
|
+
/** Clears the conversation. */
|
|
7
|
+
newChat(): void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Opens, closes or resets the mounted <CiteWidget> from your own UI (for example a button with
|
|
11
|
+
* :show-launcher="false" on the widget). With several mounted, the newest one wins.
|
|
12
|
+
*/
|
|
13
|
+
export declare function useCiteWidget(): CiteWidgetControls;
|
package/package.json
CHANGED
|
@@ -1,6 +1,42 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@citewidget/vue",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CiteWidget chat for Vue 3 and Nuxt: <CiteWidget workspace-key=\"pk_...\" /> and useCiteWidget().",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./package.json": "./package.json"
|
|
13
|
+
},
|
|
14
|
+
"module": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"keywords": [
|
|
20
|
+
"citewidget",
|
|
21
|
+
"vue",
|
|
22
|
+
"nuxt",
|
|
23
|
+
"chat-widget"
|
|
24
|
+
],
|
|
25
|
+
"homepage": "https://citewidget.com",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@citewidget/widget": "0.1.0"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"vue": "^3.3.0"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "node build.mjs",
|
|
38
|
+
"prepack": "node build.mjs",
|
|
39
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
40
|
+
"test": "vitest run"
|
|
41
|
+
}
|
|
42
|
+
}
|