@nonoun/native-chat 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chat-input-element.d.ts +21 -0
- package/dist/chat-input-element.d.ts.map +1 -0
- package/dist/chat-panel-element-CYzB2qY7.js +107 -0
- package/dist/chat-panel-element.d.ts +25 -0
- package/dist/chat-panel-element.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/native-chat.css +149 -0
- package/dist/native-chat.js +2 -0
- package/dist/register.d.ts +4 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +4 -0
- package/package.json +39 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { NativeElement } from '@nonoun/native-ui';
|
|
2
|
+
/**
|
|
3
|
+
* Chat message input with textarea, submit button, and Enter-to-send behavior.
|
|
4
|
+
* @attr {boolean} disabled - Disables interaction
|
|
5
|
+
* @attr {boolean} no-enter-submit - Disables Enter key submission
|
|
6
|
+
* @attr {boolean} no-auto-clear - Prevents clearing the textarea after send
|
|
7
|
+
* @fires native:send - Fired on submit with `{ value }` detail
|
|
8
|
+
*/
|
|
9
|
+
export declare class NChatInput extends NativeElement {
|
|
10
|
+
#private;
|
|
11
|
+
static observedAttributes: string[];
|
|
12
|
+
constructor();
|
|
13
|
+
get value(): string;
|
|
14
|
+
set value(val: string);
|
|
15
|
+
get disabled(): boolean;
|
|
16
|
+
set disabled(val: boolean);
|
|
17
|
+
attributeChangedCallback(name: string, old: string | null, val: string | null): void;
|
|
18
|
+
setup(): void;
|
|
19
|
+
teardown(): void;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=chat-input-element.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-input-element.d.ts","sourceRoot":"","sources":["../src/chat-input-element.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAgC,MAAM,mBAAmB,CAAC;AAGhF;;;;;;GAMG;AACH,qBAAa,UAAW,SAAQ,aAAa;;IAC3C,MAAM,CAAC,kBAAkB,WAAgB;;IAczC,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,KAAK,CAAC,GAAG,EAAE,MAAM,EAEpB;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,IAAI,QAAQ,CAAC,GAAG,EAAE,OAAO,EAGxB;IAID,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAYpF,KAAK,IAAI,IAAI;IA6Bb,QAAQ,IAAI,IAAI;CAqFjB"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { NativeElement as e, createDisabledEffect as t, signal as n } from "@nonoun/native-ui";
|
|
2
|
+
/**
|
|
3
|
+
* Chat message input with textarea, submit button, and Enter-to-send behavior.
|
|
4
|
+
* @attr {boolean} disabled - Disables interaction
|
|
5
|
+
* @attr {boolean} no-enter-submit - Disables Enter key submission
|
|
6
|
+
* @attr {boolean} no-auto-clear - Prevents clearing the textarea after send
|
|
7
|
+
* @fires native:send - Fired on submit with `{ value }` detail
|
|
8
|
+
*/
|
|
9
|
+
var r = class extends e {
|
|
10
|
+
static observedAttributes = ["disabled"];
|
|
11
|
+
#e;
|
|
12
|
+
#t = n(!1);
|
|
13
|
+
#n = null;
|
|
14
|
+
#r = null;
|
|
15
|
+
constructor() {
|
|
16
|
+
super(), this.#e = this.attachInternals();
|
|
17
|
+
}
|
|
18
|
+
get value() {
|
|
19
|
+
return this.#n?.value ?? "";
|
|
20
|
+
}
|
|
21
|
+
set value(e) {
|
|
22
|
+
this.#n && (this.#n.value = e);
|
|
23
|
+
}
|
|
24
|
+
get disabled() {
|
|
25
|
+
return this.#t.value;
|
|
26
|
+
}
|
|
27
|
+
set disabled(e) {
|
|
28
|
+
this.#t.value = e, this.toggleAttribute("disabled", e);
|
|
29
|
+
}
|
|
30
|
+
attributeChangedCallback(e, t, n) {
|
|
31
|
+
if (t !== n) {
|
|
32
|
+
switch (e) {
|
|
33
|
+
case "disabled":
|
|
34
|
+
this.#t.value = n !== null;
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
super.attributeChangedCallback(e, t, n);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
setup() {
|
|
41
|
+
super.setup(), this.addEffect(t(this, this.#t, this.#e)), this.deferChildren(() => {
|
|
42
|
+
this.#i(), this.addEffect(() => {
|
|
43
|
+
let e = this.#t.value;
|
|
44
|
+
this.#n && this.#n.toggleAttribute("disabled", e), this.#r && (e ? this.#r.setAttribute("disabled", "") : this.#o());
|
|
45
|
+
});
|
|
46
|
+
}), this.addEventListener("native:input", this.#s), this.addEventListener("native:press", this.#c), this.addEventListener("keydown", this.#l);
|
|
47
|
+
}
|
|
48
|
+
teardown() {
|
|
49
|
+
this.removeEventListener("native:input", this.#s), this.removeEventListener("native:press", this.#c), this.removeEventListener("keydown", this.#l), this.#n = null, this.#r = null, super.teardown();
|
|
50
|
+
}
|
|
51
|
+
#i() {
|
|
52
|
+
this.#n = this.querySelector(":scope > n-textarea"), this.#r = this.querySelector("[data-submit]") ?? this.#a();
|
|
53
|
+
}
|
|
54
|
+
#a() {
|
|
55
|
+
let e = this.querySelector(":scope > n-chat-input-actions");
|
|
56
|
+
if (!e) return null;
|
|
57
|
+
let t = e.querySelectorAll("n-button[variant=\"primary\"]");
|
|
58
|
+
return t.length ? t[t.length - 1] : null;
|
|
59
|
+
}
|
|
60
|
+
#o() {
|
|
61
|
+
!this.#r || this.#t.value || (this.value.trim() ? this.#r.removeAttribute("disabled") : this.#r.setAttribute("disabled", ""));
|
|
62
|
+
}
|
|
63
|
+
#s = (e) => {
|
|
64
|
+
this.#t.value || this.#o();
|
|
65
|
+
};
|
|
66
|
+
#c = (e) => {
|
|
67
|
+
this.#t.value || e.target === this.#r && this.#u();
|
|
68
|
+
};
|
|
69
|
+
#l = (e) => {
|
|
70
|
+
if (this.#t.value || this.hasAttribute("no-enter-submit")) return;
|
|
71
|
+
let t = e;
|
|
72
|
+
if (t.isComposing) return;
|
|
73
|
+
let n = t.target;
|
|
74
|
+
!this.#n?.contains(n) && n !== this.#n || t.key === "Enter" && !t.shiftKey && !t.ctrlKey && !t.metaKey && (t.preventDefault(), this.value.trim() && this.#u());
|
|
75
|
+
};
|
|
76
|
+
#u() {
|
|
77
|
+
let e = this.value.trim();
|
|
78
|
+
e && this.dispatchEvent(new CustomEvent("native:send", {
|
|
79
|
+
bubbles: !0,
|
|
80
|
+
composed: !0,
|
|
81
|
+
cancelable: !0,
|
|
82
|
+
detail: { value: e }
|
|
83
|
+
})) && !this.hasAttribute("no-auto-clear") && (this.value = "", this.#r?.setAttribute("disabled", ""));
|
|
84
|
+
}
|
|
85
|
+
}, i = class extends e {
|
|
86
|
+
setup() {
|
|
87
|
+
super.setup();
|
|
88
|
+
let e = document.createElement("n-header");
|
|
89
|
+
e.setAttribute("dividers", "");
|
|
90
|
+
let t = document.createElement("n-icon");
|
|
91
|
+
t.setAttribute("name", "chat-dots"), t.setAttribute("slot", "leading"), e.appendChild(t);
|
|
92
|
+
let n = document.createElement("span");
|
|
93
|
+
n.setAttribute("slot", "label"), n.textContent = "Assistant", e.appendChild(n);
|
|
94
|
+
let r = document.createElement("n-body"), i = document.createElement("n-chat-content");
|
|
95
|
+
r.appendChild(i);
|
|
96
|
+
let a = document.createElement("n-footer");
|
|
97
|
+
a.setAttribute("dividers", "");
|
|
98
|
+
let o = document.createElement("n-chat-input"), s = document.createElement("n-textarea");
|
|
99
|
+
s.setAttribute("placeholder", "Ask anything"), s.setAttribute("autogrow", ""), s.setAttribute("rows", "3"), o.appendChild(s);
|
|
100
|
+
let c = document.createElement("n-chat-input-actions"), l = document.createElement("n-button");
|
|
101
|
+
l.setAttribute("variant", "primary"), l.setAttribute("intent", "accent"), l.textContent = "Send", c.appendChild(l), o.appendChild(c), a.appendChild(o), this.append(e, r, a);
|
|
102
|
+
}
|
|
103
|
+
teardown() {
|
|
104
|
+
this.innerHTML = "", super.teardown();
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
export { r as n, i as t };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { NativeElement } from '@nonoun/native-ui';
|
|
2
|
+
/**
|
|
3
|
+
* Stamped panel for the chat interface.
|
|
4
|
+
*
|
|
5
|
+
* Creates `<n-header>` (icon, title), `<n-body>` containing
|
|
6
|
+
* `<n-chat-content>`, and `<n-footer>` with `<n-chat-input>` directly
|
|
7
|
+
* as children. The host element itself is the panel surface.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* ```html
|
|
11
|
+
* <native-chat-panel></native-chat-panel>
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Listen for messages:
|
|
15
|
+
* ```js
|
|
16
|
+
* panel.addEventListener('native:send', (e) => {
|
|
17
|
+
* console.log(e.detail.value);
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare class NChatPanel extends NativeElement {
|
|
22
|
+
setup(): void;
|
|
23
|
+
teardown(): void;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=chat-panel-element.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-panel-element.d.ts","sourceRoot":"","sources":["../src/chat-panel-element.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,UAAW,SAAQ,aAAa;IAC3C,KAAK,IAAI,IAAI;IAgDb,QAAQ,IAAI,IAAI;CAIjB"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AAEvB,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
@layer ui {
|
|
2
|
+
|
|
3
|
+
:where(n-chat-input):not(:defined) { visibility: hidden; }
|
|
4
|
+
|
|
5
|
+
/* ╭──────────────────────────────────────────────────────────╮
|
|
6
|
+
│ n-chat │
|
|
7
|
+
│ Chat controller. display:contents — no visual │
|
|
8
|
+
│ presence. The inner n-panel provides structure. │
|
|
9
|
+
│ n-chat wires gateway / gen-UI framework behavior. │
|
|
10
|
+
╰──────────────────────────────────────────────────────────╯ */
|
|
11
|
+
|
|
12
|
+
:where(n-chat) {
|
|
13
|
+
display: contents;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
:where(native-chat-panel) {
|
|
17
|
+
--n-ground: var(--n-panel);
|
|
18
|
+
|
|
19
|
+
container-type: inline-size;
|
|
20
|
+
display: flex;
|
|
21
|
+
flex: 1 1 0%;
|
|
22
|
+
min-width: 0;
|
|
23
|
+
flex-direction: column;
|
|
24
|
+
background: var(--n-ground);
|
|
25
|
+
border-radius: var(--n-radius);
|
|
26
|
+
overflow: hidden;
|
|
27
|
+
|
|
28
|
+
font-size: var(--n-font-size);
|
|
29
|
+
line-height: var(--n-line-height);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* ── Sub-container integration ── */
|
|
33
|
+
|
|
34
|
+
:where(native-chat-panel) > :where(n-header) {
|
|
35
|
+
border-bottom: 1px solid var(--n-border-muted);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
:where(native-chat-panel) > :where(n-footer) {
|
|
39
|
+
border-top: 1px solid var(--n-border-muted);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* WHY: Wide padding only above 22rem — asides (280–480px) keep compact defaults. */
|
|
43
|
+
@container (min-width: 22rem) {
|
|
44
|
+
:where(native-chat-panel) > :where(n-header) {
|
|
45
|
+
padding-inline: calc(var(--n-space) * 8);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
:where(native-chat-panel) > :where(n-body) {
|
|
49
|
+
padding-inline: calc(var(--n-space) * 8);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
:where(native-chat-panel) > :where(n-footer) {
|
|
53
|
+
padding-inline: calc(var(--n-space) * 8);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* ── n-chat-content ── */
|
|
58
|
+
/* Message stream layout. Lives inside n-card-body which handles
|
|
59
|
+
scrolling, padding, and flex: 1. Content just manages message gap. */
|
|
60
|
+
|
|
61
|
+
:where(n-chat-content) {
|
|
62
|
+
display: flex;
|
|
63
|
+
flex: 1 1 0%;
|
|
64
|
+
min-width: 0;
|
|
65
|
+
min-height: 0;
|
|
66
|
+
flex-direction: column;
|
|
67
|
+
gap: calc(var(--n-space) * 2);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* ── n-chat-input ── */
|
|
71
|
+
/* Rounded surface containing textarea + actions row.
|
|
72
|
+
WHY: Single surface wraps everything — textarea fills the top,
|
|
73
|
+
actions row sits bottom-right. Compact mode lays out as a
|
|
74
|
+
single horizontal row. */
|
|
75
|
+
|
|
76
|
+
:where(n-chat-input) {
|
|
77
|
+
display: flex;
|
|
78
|
+
flex-direction: column;
|
|
79
|
+
min-width: 0;
|
|
80
|
+
background: var(--n-control);
|
|
81
|
+
border: 1px solid var(--n-border-muted);
|
|
82
|
+
border-radius: var(--n-radius);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* Compact: single row — textarea and actions side by side */
|
|
86
|
+
:where(n-chat-input[compact]) {
|
|
87
|
+
flex-direction: row;
|
|
88
|
+
align-items: center;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* Textarea inside input — transparent, borderless, fills space.
|
|
92
|
+
WHY: Override custom properties so all states (hover, filled, focus)
|
|
93
|
+
resolve to transparent. The wrapper provides the visual surface. */
|
|
94
|
+
:where(n-chat-input) > :where(n-textarea) {
|
|
95
|
+
--n-background: transparent;
|
|
96
|
+
--n-background-hover: transparent;
|
|
97
|
+
--n-background-active: transparent;
|
|
98
|
+
--n-border-color: transparent;
|
|
99
|
+
--n-border-color-hover: transparent;
|
|
100
|
+
--n-border-color-active: transparent;
|
|
101
|
+
|
|
102
|
+
border: none;
|
|
103
|
+
border-radius: 0;
|
|
104
|
+
resize: none;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
:where(n-chat-input) > :where(n-textarea):not(:state(empty)),
|
|
108
|
+
:where(n-chat-input) > :where(n-textarea):not(:state(empty)):hover {
|
|
109
|
+
background: transparent;
|
|
110
|
+
border-color: transparent;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
:where(n-chat-input) > :where(n-textarea):focus {
|
|
114
|
+
border-color: transparent;
|
|
115
|
+
outline: none;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* ── n-chat-input-attachments ── */
|
|
119
|
+
/* Optional attachment zone above the textarea. */
|
|
120
|
+
|
|
121
|
+
:where(n-chat-input-attachments) {
|
|
122
|
+
display: flex;
|
|
123
|
+
flex-wrap: wrap;
|
|
124
|
+
gap: calc(var(--n-space) * 2);
|
|
125
|
+
padding-block: var(--n-space);
|
|
126
|
+
padding-inline: calc(var(--n-space-k) * var(--n-space));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* ── n-chat-input-actions ── */
|
|
130
|
+
/* Bottom action row: [+][model][mic][submit] — right-aligned. */
|
|
131
|
+
|
|
132
|
+
:where(n-chat-input-actions) {
|
|
133
|
+
display: flex;
|
|
134
|
+
align-items: center;
|
|
135
|
+
justify-content: flex-end;
|
|
136
|
+
gap: calc(var(--n-space) * 2);
|
|
137
|
+
padding-block: var(--n-space);
|
|
138
|
+
padding-inline: calc(var(--n-space-k) * var(--n-space));
|
|
139
|
+
min-width: 0;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* In compact mode, actions shrink-wrap with no extra padding */
|
|
143
|
+
:where(n-chat-input[compact]) > :where(n-chat-input-actions) {
|
|
144
|
+
flex: none;
|
|
145
|
+
padding-block: 0;
|
|
146
|
+
padding-inline-start: 0;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAarD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC"}
|
package/dist/register.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { n as e, t } from "./chat-panel-element-CYzB2qY7.js";
|
|
2
|
+
import { NButton as n, NIcon as r, NTextarea as i, define as a, registerIcon as o } from "@nonoun/native-ui";
|
|
3
|
+
a("n-chat-input", e), a("native-chat-panel", t), a("n-textarea", i), a("n-button", n), a("n-icon", r), o("chat-dots", "<svg viewBox=\"0 0 256 256\" fill=\"currentColor\"><path d=\"M116,128a12,12,0,1,1,12,12A12,12,0,0,1,116,128ZM84,140a12,12,0,1,0-12-12A12,12,0,0,0,84,140Zm88,0a12,12,0,1,0-12-12A12,12,0,0,0,172,140Zm60-76V192a16,16,0,0,1-16,16H83l-32.6,28.16-.09.07A15.89,15.89,0,0,1,40,240a16.13,16.13,0,0,1-6.8-1.52A15.85,15.85,0,0,1,24,224V64A16,16,0,0,1,40,48H216A16,16,0,0,1,232,64ZM40,224h0ZM216,64H40V224l34.77-30A8,8,0,0,1,80,192H216Z\"/></svg>");
|
|
4
|
+
export { e as NChatInput, t as NChatPanel };
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nonoun/native-chat",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Chat input and message layout components for @nonoun/native-ui",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/native-chat.js",
|
|
8
|
+
"module": "./dist/native-chat.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/native-chat.js"
|
|
14
|
+
},
|
|
15
|
+
"./register": {
|
|
16
|
+
"types": "./dist/register.d.ts",
|
|
17
|
+
"default": "./dist/register.js"
|
|
18
|
+
},
|
|
19
|
+
"./css": "./dist/native-chat.css"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"sideEffects": [
|
|
25
|
+
"./dist/register.js"
|
|
26
|
+
],
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"@nonoun/native-ui": ">=0.6.0"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "npm run build:js && npm run build:css && npm run build:types",
|
|
32
|
+
"build:js": "vite build",
|
|
33
|
+
"build:css": "cp src/chat.css dist/native-chat.css",
|
|
34
|
+
"build:types": "tsc -p tsconfig.build.json"
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
}
|
|
39
|
+
}
|