@shane_donnelly/dsi-internal-react-utils 0.2.0 → 1.0.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.
Files changed (34) hide show
  1. package/README.md +19 -0
  2. package/dist/BotMessage-DegH8sM-.js +255 -0
  3. package/dist/InputBar-CxSc2du6.js +201 -0
  4. package/dist/MarkdownRenderer-vU2aoyaG.js +12908 -0
  5. package/dist/SessionContainer-RrzUh_no.js +50 -0
  6. package/dist/SessionHistory-BUYwbZjE.js +67 -0
  7. package/dist/UserMessage-CkrDUpkQ.js +76 -0
  8. package/dist/bs-CmZftXMO.js +35 -0
  9. package/dist/chatbot/BotMessage/index.d.ts +148 -0
  10. package/dist/chatbot/BotMessage/index.js +2 -0
  11. package/dist/chatbot/InputBar/index.d.ts +53 -0
  12. package/dist/chatbot/InputBar/index.js +2 -0
  13. package/dist/chatbot/MarkdownRenderer/index.d.ts +19 -0
  14. package/dist/chatbot/MarkdownRenderer/index.js +2 -0
  15. package/dist/chatbot/SessionContainer/index.d.ts +26 -0
  16. package/dist/chatbot/SessionContainer/index.js +2 -0
  17. package/dist/chatbot/SessionHistory/index.d.ts +48 -0
  18. package/dist/chatbot/SessionHistory/index.js +2 -0
  19. package/dist/chatbot/UserMessage/index.d.ts +51 -0
  20. package/dist/chatbot/UserMessage/index.js +2 -0
  21. package/dist/chatbot/index.d.ts +14 -0
  22. package/dist/chatbot/index.js +10 -0
  23. package/dist/chatbot/theme/index.d.ts +3 -0
  24. package/dist/chatbot/theme/index.js +3 -0
  25. package/dist/chatbot/theme/types.d.ts +71 -0
  26. package/dist/chatbot/theme/types.js +65 -0
  27. package/dist/chatbot/theme/useTheme.d.ts +6 -0
  28. package/dist/chatbot/theme/useTheme.js +9 -0
  29. package/dist/iconBase-CDbPVA4E.js +108 -0
  30. package/dist/keycloak/react/KeycloakProvider/index.js +31 -21
  31. package/dist/main.d.ts +2 -0
  32. package/dist/main.js +13 -4
  33. package/dist/style.css +2 -0
  34. package/package.json +16 -7
package/README.md CHANGED
@@ -30,6 +30,25 @@ Wrapper de simplification pour `keycloak-js`. `KeycloakProvider` singleton à la
30
30
 
31
31
  [Documentation complète du module Keycloak](docs/keycloak.md)
32
32
 
33
+ ### Chatbot UI
34
+
35
+ Ensemble de composants React pour créer des interfaces de type chatbot modernes (style ChatGPT / Claude / Gemini). Entièrement indépendant de la logique métier — gère uniquement l'affichage.
36
+
37
+ Composants disponibles :
38
+
39
+ | Composant | Description |
40
+ |-----------|-------------|
41
+ | `MarkdownRenderer` | Rendu markdown avec bouton copier sur les blocs de code |
42
+ | `UserMessage` | Bulle de message utilisateur avec slots typés optionnels |
43
+ | `BotMessage` | Message bot full-width, extensible via registry |
44
+ | `SessionHistory` | Affichage d'une conversation complète |
45
+ | `InputBar` | Barre d'input avec bouton "+", bouton d'action configurable et slots |
46
+ | `SessionContainer` | Composant tout-en-un : SessionHistory + InputBar |
47
+
48
+ Système de thème global via `setTheme("light" | "dark" | ColorPalette)`.
49
+
50
+ [Documentation complète du module Chatbot](docs/chatbot.md)
51
+
33
52
  ---
34
53
 
35
54
  ## Exemple complet avec React Router v7 (framework mode)
@@ -0,0 +1,255 @@
1
+ import { t as e } from "./MarkdownRenderer-vU2aoyaG.js";
2
+ import { useTheme as t } from "./chatbot/theme/useTheme.js";
3
+ import { t as n } from "./iconBase-CDbPVA4E.js";
4
+ import { n as r, t as i } from "./bs-CmZftXMO.js";
5
+ import { useEffect as a, useState as o } from "react";
6
+ import { Fragment as s, jsx as c, jsxs as l } from "react/jsx-runtime";
7
+ //#region node_modules/react-icons/tb/index.mjs
8
+ function u(e) {
9
+ return n({
10
+ tag: "svg",
11
+ attr: {
12
+ viewBox: "0 0 24 24",
13
+ fill: "none",
14
+ stroke: "currentColor",
15
+ strokeWidth: "2",
16
+ strokeLinecap: "round",
17
+ strokeLinejoin: "round"
18
+ },
19
+ child: [
20
+ {
21
+ tag: "path",
22
+ attr: { d: "M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0" },
23
+ child: []
24
+ },
25
+ {
26
+ tag: "path",
27
+ attr: { d: "M3.6 9h16.8" },
28
+ child: []
29
+ },
30
+ {
31
+ tag: "path",
32
+ attr: { d: "M3.6 15h16.8" },
33
+ child: []
34
+ },
35
+ {
36
+ tag: "path",
37
+ attr: { d: "M11.5 3a17 17 0 0 0 0 18" },
38
+ child: []
39
+ },
40
+ {
41
+ tag: "path",
42
+ attr: { d: "M12.5 3a17 17 0 0 1 0 18" },
43
+ child: []
44
+ }
45
+ ]
46
+ })(e);
47
+ }
48
+ function d(e) {
49
+ return n({
50
+ tag: "svg",
51
+ attr: {
52
+ viewBox: "0 0 24 24",
53
+ fill: "none",
54
+ stroke: "currentColor",
55
+ strokeWidth: "2",
56
+ strokeLinecap: "round",
57
+ strokeLinejoin: "round"
58
+ },
59
+ child: [{
60
+ tag: "path",
61
+ attr: { d: "M6 9l6 6l6 -6" },
62
+ child: []
63
+ }]
64
+ })(e);
65
+ }
66
+ //#endregion
67
+ //#region lib/chatbot/BotMessage/styles.module.css
68
+ var f = {
69
+ "dsi-bot-msg": "_dsi-bot-msg_9iqvz_2",
70
+ "dsi-bot-loading-dot": "_dsi-bot-loading-dot_9iqvz_15",
71
+ "dsi-bot-pulse": "_dsi-bot-pulse_9iqvz_1",
72
+ "dsi-bot-msg-footer": "_dsi-bot-msg-footer_9iqvz_28",
73
+ "dsi-bot-copy-btn": "_dsi-bot-copy-btn_9iqvz_39",
74
+ "dsi-bot-msg-time": "_dsi-bot-msg-time_9iqvz_62",
75
+ "dsi-bot-reasoning": "_dsi-bot-reasoning_9iqvz_75",
76
+ "dsi-bot-tool": "_dsi-bot-tool_9iqvz_76",
77
+ "dsi-bot-search": "_dsi-bot-search_9iqvz_77",
78
+ "dsi-bot-collapsible-header": "_dsi-bot-collapsible-header_9iqvz_84",
79
+ "dsi-bot-collapsible-header-inner": "_dsi-bot-collapsible-header-inner_9iqvz_99",
80
+ "dsi-bot-element-title": "_dsi-bot-element-title_9iqvz_108",
81
+ "dsi-bot-collapse-chevron": "_dsi-bot-collapse-chevron_9iqvz_115",
82
+ "dsi-bot-collapsible-body": "_dsi-bot-collapsible-body_9iqvz_126",
83
+ "dsi-bot-collapsible-content": "_dsi-bot-collapsible-content_9iqvz_132",
84
+ "dsi-bot-search-icon": "_dsi-bot-search-icon_9iqvz_140",
85
+ "dsi-bot-spinner": "_dsi-bot-spinner_9iqvz_146",
86
+ "dsi-spin": "_dsi-spin_9iqvz_1"
87
+ };
88
+ //#endregion
89
+ //#region lib/chatbot/BotMessage/index.tsx
90
+ function p({ markdownText: t }) {
91
+ return t ? /* @__PURE__ */ c(e, { text: t }) : null;
92
+ }
93
+ function m() {
94
+ return /* @__PURE__ */ c("svg", {
95
+ className: f["dsi-bot-loading-dot"],
96
+ width: "10",
97
+ height: "10",
98
+ viewBox: "0 0 10 10",
99
+ "aria-hidden": "true",
100
+ children: /* @__PURE__ */ c("circle", {
101
+ cx: "5",
102
+ cy: "5",
103
+ r: "4",
104
+ fill: "currentColor"
105
+ })
106
+ });
107
+ }
108
+ function h({ text: e }) {
109
+ let [t, n] = o(!1);
110
+ return /* @__PURE__ */ c("button", {
111
+ className: f["dsi-bot-copy-btn"],
112
+ onClick: () => {
113
+ navigator.clipboard.writeText(e).then(() => {
114
+ n(!0), setTimeout(() => n(!1), 2e3);
115
+ });
116
+ },
117
+ "aria-label": "Copier le message",
118
+ type: "button",
119
+ children: c(t ? i : r, {})
120
+ });
121
+ }
122
+ function g({ defaultOpen: e, closeWhen: t = !1, header: n, content: r, className: i, style: s }) {
123
+ let [u, p] = o(e);
124
+ return a(() => {
125
+ t && p(!1);
126
+ }, [t]), /* @__PURE__ */ l("div", {
127
+ className: i,
128
+ style: s,
129
+ children: [/* @__PURE__ */ l("div", {
130
+ className: f["dsi-bot-collapsible-header"],
131
+ onClick: () => p((e) => !e),
132
+ role: "button",
133
+ tabIndex: 0,
134
+ onKeyDown: (e) => {
135
+ (e.key === "Enter" || e.key === " ") && p((e) => !e);
136
+ },
137
+ "aria-expanded": u,
138
+ children: [/* @__PURE__ */ c("div", {
139
+ className: f["dsi-bot-collapsible-header-inner"],
140
+ children: n
141
+ }), /* @__PURE__ */ c(d, {
142
+ className: f["dsi-bot-collapse-chevron"],
143
+ style: { transform: u ? "rotate(0deg)" : "rotate(-90deg)" },
144
+ "aria-hidden": "true"
145
+ })]
146
+ }), u && r && /* @__PURE__ */ c("div", {
147
+ className: f["dsi-bot-collapsible-body"],
148
+ children: r
149
+ })]
150
+ });
151
+ }
152
+ function _({ title: e, content: n, isLoading: r = !1, _isLastElement: i = !1 }) {
153
+ let a = t();
154
+ return /* @__PURE__ */ c(g, {
155
+ defaultOpen: r || i,
156
+ closeWhen: !r && !i,
157
+ className: f["dsi-bot-reasoning"],
158
+ style: {
159
+ "--dsi-reasoning-border": a.reasoningBorder,
160
+ "--dsi-reasoning-text": a.reasoningText
161
+ },
162
+ header: /* @__PURE__ */ c("span", {
163
+ className: f["dsi-bot-element-title"],
164
+ children: e || "Raisonnement"
165
+ }),
166
+ content: n ? /* @__PURE__ */ c("p", {
167
+ className: f["dsi-bot-collapsible-content"],
168
+ children: n
169
+ }) : null
170
+ });
171
+ }
172
+ function v({ title: e, content: n, isLoading: r = !1, _isLastElement: i = !1 }) {
173
+ let a = t();
174
+ return /* @__PURE__ */ c(g, {
175
+ defaultOpen: r || i,
176
+ closeWhen: !r && !i,
177
+ className: f["dsi-bot-tool"],
178
+ style: {
179
+ "--dsi-tool-border": a.toolBorder,
180
+ "--dsi-text-secondary": a.textSecondary,
181
+ "--dsi-text-primary": a.textPrimary
182
+ },
183
+ header: /* @__PURE__ */ l(s, { children: [r && /* @__PURE__ */ c("span", { className: f["dsi-bot-spinner"] }), /* @__PURE__ */ c("span", {
184
+ className: f["dsi-bot-element-title"],
185
+ children: e || "Outil"
186
+ })] }),
187
+ content: n ? /* @__PURE__ */ c("p", {
188
+ className: f["dsi-bot-collapsible-content"],
189
+ children: n
190
+ }) : null
191
+ });
192
+ }
193
+ function y({ title: e, content: n, isLoading: r = !1, _isLastElement: i = !1 }) {
194
+ let a = t();
195
+ return /* @__PURE__ */ c(g, {
196
+ defaultOpen: r || i,
197
+ closeWhen: !r && !i,
198
+ className: f["dsi-bot-search"],
199
+ style: {
200
+ "--dsi-tool-border": a.toolBorder,
201
+ "--dsi-text-secondary": a.textSecondary,
202
+ "--dsi-text-primary": a.textPrimary
203
+ },
204
+ header: /* @__PURE__ */ l(s, { children: [
205
+ /* @__PURE__ */ c(u, { className: f["dsi-bot-search-icon"] }),
206
+ r && /* @__PURE__ */ c("span", { className: f["dsi-bot-spinner"] }),
207
+ /* @__PURE__ */ c("span", {
208
+ className: f["dsi-bot-element-title"],
209
+ children: e || "Recherche"
210
+ })
211
+ ] }),
212
+ content: n ? /* @__PURE__ */ c("p", {
213
+ className: f["dsi-bot-collapsible-content"],
214
+ children: n
215
+ }) : null
216
+ });
217
+ }
218
+ var b = {
219
+ text: p,
220
+ reasoning: _,
221
+ tool: v,
222
+ search: y
223
+ };
224
+ function x({ message: e, registry: n = b }) {
225
+ let r = t(), i = [...e.elements].sort((e, t) => e.index - t.index), a = [...i].reverse().find((e) => e.type === "text")?.markdownText ?? "";
226
+ return /* @__PURE__ */ l("div", {
227
+ className: f["dsi-bot-msg"],
228
+ style: {
229
+ "--dsi-text-primary": r.textPrimary,
230
+ "--dsi-text-secondary": r.textSecondary,
231
+ "--dsi-border": r.border
232
+ },
233
+ children: [
234
+ e.isLoading && /* @__PURE__ */ c(m, {}),
235
+ i.map((e, t) => {
236
+ let r = n[e.type];
237
+ if (!r) return null;
238
+ let a = t === i.length - 1;
239
+ return /* @__PURE__ */ c(r, {
240
+ ...e,
241
+ _isLastElement: a
242
+ }, `${e.type}-${e.index}-${t}`);
243
+ }),
244
+ /* @__PURE__ */ l("div", {
245
+ className: f["dsi-bot-msg-footer"],
246
+ children: [!e.isLoading && /* @__PURE__ */ c(h, { text: a }), !e.isLoading && e.timeOrDateToDisplay && /* @__PURE__ */ c("span", {
247
+ className: f["dsi-bot-msg-time"],
248
+ children: e.timeOrDateToDisplay
249
+ })]
250
+ })
251
+ ]
252
+ });
253
+ }
254
+ //#endregion
255
+ export { b as n, x as t };
@@ -0,0 +1,201 @@
1
+ import { useTheme as e } from "./chatbot/theme/useTheme.js";
2
+ import { t } from "./iconBase-CDbPVA4E.js";
3
+ import { useEffect as n, useRef as r, useState as i } from "react";
4
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
5
+ //#region node_modules/react-icons/fi/index.mjs
6
+ function s(e) {
7
+ return t({
8
+ tag: "svg",
9
+ attr: {
10
+ viewBox: "0 0 24 24",
11
+ fill: "none",
12
+ stroke: "currentColor",
13
+ strokeWidth: "2",
14
+ strokeLinecap: "round",
15
+ strokeLinejoin: "round"
16
+ },
17
+ child: [{
18
+ tag: "line",
19
+ attr: {
20
+ x1: "22",
21
+ y1: "2",
22
+ x2: "11",
23
+ y2: "13"
24
+ },
25
+ child: []
26
+ }, {
27
+ tag: "polygon",
28
+ attr: { points: "22 2 15 22 11 13 2 9 22 2" },
29
+ child: []
30
+ }]
31
+ })(e);
32
+ }
33
+ function c(e) {
34
+ return t({
35
+ tag: "svg",
36
+ attr: {
37
+ viewBox: "0 0 24 24",
38
+ fill: "none",
39
+ stroke: "currentColor",
40
+ strokeWidth: "2",
41
+ strokeLinecap: "round",
42
+ strokeLinejoin: "round"
43
+ },
44
+ child: [{
45
+ tag: "line",
46
+ attr: {
47
+ x1: "12",
48
+ y1: "5",
49
+ x2: "12",
50
+ y2: "19"
51
+ },
52
+ child: []
53
+ }, {
54
+ tag: "line",
55
+ attr: {
56
+ x1: "5",
57
+ y1: "12",
58
+ x2: "19",
59
+ y2: "12"
60
+ },
61
+ child: []
62
+ }]
63
+ })(e);
64
+ }
65
+ //#endregion
66
+ //#region node_modules/react-icons/fa/index.mjs
67
+ function l(e) {
68
+ return t({
69
+ tag: "svg",
70
+ attr: { viewBox: "0 0 448 512" },
71
+ child: [{
72
+ tag: "path",
73
+ attr: { d: "M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48z" },
74
+ child: []
75
+ }]
76
+ })(e);
77
+ }
78
+ //#endregion
79
+ //#region node_modules/react-icons/ri/index.mjs
80
+ function u(e) {
81
+ return t({
82
+ tag: "svg",
83
+ attr: {
84
+ viewBox: "0 0 24 24",
85
+ fill: "currentColor"
86
+ },
87
+ child: [{
88
+ tag: "path",
89
+ attr: { d: "M5 7H7V17H5V7ZM1 10H3V14H1V10ZM9 2H11V20H9V2ZM13 4H15V22H13V4ZM17 7H19V17H17V7ZM21 10H23V14H21V10Z" },
90
+ child: []
91
+ }]
92
+ })(e);
93
+ }
94
+ //#endregion
95
+ //#region lib/chatbot/InputBar/styles.module.css
96
+ var d = {
97
+ "dsi-inputbar": "_dsi-inputbar_1ngbl_2",
98
+ "dsi-inputbar-upper-slot": "_dsi-inputbar-upper-slot_1ngbl_12",
99
+ "dsi-inputbar-plus-slot": "_dsi-inputbar-plus-slot_1ngbl_23",
100
+ "dsi-inputbar-row": "_dsi-inputbar-row_1ngbl_38",
101
+ "dsi-inputbar-row--with-upper": "_dsi-inputbar-row--with-upper_1ngbl_55",
102
+ "dsi-inputbar-textarea": "_dsi-inputbar-textarea_1ngbl_60",
103
+ "dsi-inputbar-plus-btn": "_dsi-inputbar-plus-btn_1ngbl_81",
104
+ "dsi-inputbar-plus-btn--open": "_dsi-inputbar-plus-btn--open_1ngbl_100",
105
+ "dsi-inputbar-action-btn": "_dsi-inputbar-action-btn_1ngbl_105"
106
+ };
107
+ //#endregion
108
+ //#region lib/chatbot/InputBar/index.tsx
109
+ function f({ type: e }) {
110
+ switch (e) {
111
+ case "send": return /* @__PURE__ */ a(s, {});
112
+ case "stop": return /* @__PURE__ */ a(l, {});
113
+ case "vocal": return /* @__PURE__ */ a(u, {});
114
+ default: return null;
115
+ }
116
+ }
117
+ function p({ value: t, onChange: s, placeholder: l = "Envoyer un message…", actionButtonType: u = "send", actionButtonEnabled: p = !0, onActionButtonClick: m, plusSlot: h, upperSlot: g, messageHistory: _ }) {
118
+ let v = e(), [y, b] = i(!1), x = r(null), S = r(null), C = r(null), w = r(-1);
119
+ n(() => {
120
+ let e = x.current;
121
+ e && (e.style.height = "auto", e.style.height = `${e.scrollHeight}px`);
122
+ }, [t]), n(() => {
123
+ if (!y) return;
124
+ let e = (e) => {
125
+ !S.current?.contains(e.target) && !C.current?.contains(e.target) && b(!1);
126
+ };
127
+ return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
128
+ }, [y]);
129
+ let T = {
130
+ "--dsi-border": v.border,
131
+ "--dsi-input-bg": v.inputBg,
132
+ "--dsi-accent": v.accent,
133
+ "--dsi-text-primary": v.textPrimary,
134
+ "--dsi-text-secondary": v.textSecondary,
135
+ "--dsi-button-bg": v.buttonBg,
136
+ "--dsi-button-hover-bg": v.buttonHoverBg,
137
+ "--dsi-action-btn-bg": v.actionButtonBg,
138
+ "--dsi-action-btn-hover-bg": v.actionButtonHoverBg,
139
+ "--dsi-action-btn-icon": v.actionButtonIcon
140
+ };
141
+ return /* @__PURE__ */ o("div", {
142
+ className: d["dsi-inputbar"],
143
+ style: T,
144
+ children: [
145
+ y && h && /* @__PURE__ */ a("div", {
146
+ className: d["dsi-inputbar-plus-slot"],
147
+ ref: S,
148
+ children: h
149
+ }),
150
+ g && /* @__PURE__ */ a("div", {
151
+ className: d["dsi-inputbar-upper-slot"],
152
+ children: g
153
+ }),
154
+ /* @__PURE__ */ o("div", {
155
+ className: `${d["dsi-inputbar-row"]} ${g ? d["dsi-inputbar-row--with-upper"] : ""}`,
156
+ children: [
157
+ /* @__PURE__ */ a("button", {
158
+ ref: C,
159
+ className: `${d["dsi-inputbar-plus-btn"]} ${y ? d["dsi-inputbar-plus-btn--open"] : ""}`,
160
+ onClick: () => b((e) => !e),
161
+ "aria-label": "Options",
162
+ type: "button",
163
+ children: /* @__PURE__ */ a(c, {})
164
+ }),
165
+ /* @__PURE__ */ a("textarea", {
166
+ ref: x,
167
+ className: d["dsi-inputbar-textarea"],
168
+ value: t,
169
+ onChange: (e) => {
170
+ w.current = -1, s(e.target.value);
171
+ },
172
+ placeholder: l,
173
+ rows: 1,
174
+ onKeyDown: (e) => {
175
+ let n = _ ?? [];
176
+ if (e.key === "ArrowUp" && !e.shiftKey) {
177
+ t === "" && w.current === -1 && n.length > 0 ? (w.current = n.length - 1, s(n[w.current]), e.preventDefault()) : w.current > 0 ? (w.current--, s(n[w.current]), e.preventDefault()) : w.current === 0 && e.preventDefault();
178
+ return;
179
+ }
180
+ if (e.key === "ArrowDown" && w.current !== -1) {
181
+ w.current < n.length - 1 ? (w.current++, s(n[w.current])) : (w.current = -1, s("")), e.preventDefault();
182
+ return;
183
+ }
184
+ e.key === "Enter" && !e.shiftKey && (e.preventDefault(), w.current = -1, p && u !== "none" && m?.(u));
185
+ }
186
+ }),
187
+ u !== "none" && /* @__PURE__ */ a("button", {
188
+ className: d["dsi-inputbar-action-btn"],
189
+ disabled: !p,
190
+ onClick: () => m?.(u),
191
+ "aria-label": u,
192
+ type: "button",
193
+ children: /* @__PURE__ */ a(f, { type: u })
194
+ })
195
+ ]
196
+ })
197
+ ]
198
+ });
199
+ }
200
+ //#endregion
201
+ export { p as t };