@netlify/spark-ui 1.10.0 → 1.11.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.
@@ -1,7 +1,8 @@
1
1
  interface AskNetlifyProps {
2
- setModalState?: (state?: {
2
+ kapaIntegrationId?: string;
3
+ setModalState?: (e: {
3
4
  current: string;
4
5
  }) => void;
5
6
  }
6
- export default function AskNetlify(props: AskNetlifyProps): import("preact").JSX.Element;
7
+ export default function AskNetlify(props: AskNetlifyProps): import("preact").JSX.Element | undefined;
7
8
  export {};
@@ -1,35 +1,36 @@
1
- import { u as t } from "../../../chunks/jsxRuntime.module.Bzuv3cXw.js";
2
- import { A as a } from "../../../chunks/hooks.module.DGkdD5n9.js";
3
- import { C as s, K as i } from "../../../chunks/ChatInterface.EQAPs01R.js";
4
- import { A as c } from "../../../chunks/analytics.Ch1vuuOl.js";
5
- import '../../../assets/AskNetlify.css';function k(o) {
6
- const e = a(new c());
7
- return /* @__PURE__ */ t(
8
- i,
9
- {
10
- integrationId: "3c0789a6-c6a8-4fbc-b0cc-235f9e4a6351",
11
- callbacks: {
12
- askAI: {
13
- onQuerySubmit: (r) => {
14
- var n;
15
- (n = e == null ? void 0 : e.current) == null || n.track("ask:new_query", {
16
- question: r.question,
17
- thread_id: r.threadId
18
- });
19
- },
20
- onAnswerGenerationCompleted: (r) => {
21
- var n;
22
- (n = e == null ? void 0 : e.current) == null || n.track("ask:answer_generated", {
23
- question_id: r.questionAnswerId,
24
- answer_length: r.answer.length
25
- });
1
+ import { u as o } from "../../../chunks/jsxRuntime.module.Bzuv3cXw.js";
2
+ import { A as i } from "../../../chunks/hooks.module.DGkdD5n9.js";
3
+ import { C as s, K as a } from "../../../chunks/ChatInterface.EQAPs01R.js";
4
+ import { A as u } from "../../../chunks/analytics.Ch1vuuOl.js";
5
+ import '../../../assets/AskNetlify.css';function w(n) {
6
+ const r = i(new u());
7
+ if (n.kapaIntegrationId)
8
+ return /* @__PURE__ */ o(
9
+ a,
10
+ {
11
+ integrationId: n.kapaIntegrationId,
12
+ callbacks: {
13
+ askAI: {
14
+ onQuerySubmit: (e) => {
15
+ var t;
16
+ !e.question || !e.threadId || (t = r == null ? void 0 : r.current) == null || t.track("ask:new_query", {
17
+ question: e.question,
18
+ thread_id: e.threadId
19
+ });
20
+ },
21
+ onAnswerGenerationCompleted: (e) => {
22
+ var t;
23
+ !e.questionAnswerId || !e.answer || (t = r == null ? void 0 : r.current) == null || t.track("ask:answer_generated", {
24
+ question_id: e.questionAnswerId,
25
+ answer_length: e.answer.length
26
+ });
27
+ }
26
28
  }
27
- }
28
- },
29
- children: /* @__PURE__ */ t(s, { ...o })
30
- }
31
- );
29
+ },
30
+ children: /* @__PURE__ */ o(s, { setModalState: n.setModalState })
31
+ }
32
+ );
32
33
  }
33
34
  export {
34
- k as default
35
+ w as default
35
36
  };
@@ -1,5 +1,5 @@
1
1
  interface Props {
2
- setModalState?: (state?: {
2
+ setModalState?: (e: {
3
3
  current: string;
4
4
  }) => void;
5
5
  }
@@ -3,6 +3,7 @@ interface Props {
3
3
  children: ComponentChildren;
4
4
  className?: string;
5
5
  debug?: boolean;
6
+ kapaIntegrationId?: string;
6
7
  }
7
8
  declare function SearchModal(props?: Props): import("preact").JSX.Element;
8
9
  export default SearchModal;
@@ -1,67 +1,80 @@
1
1
  import { u as e } from "../../../../../chunks/jsxRuntime.module.Bzuv3cXw.js";
2
- import { A as N, y as l, d as h } from "../../../../../chunks/hooks.module.DGkdD5n9.js";
3
- import w from "../../../Modal/Modal.js";
2
+ import { A as v, y as m, d as h } from "../../../../../chunks/hooks.module.DGkdD5n9.js";
3
+ import b from "../../../Modal/Modal.js";
4
4
  import p from "../../../KeyboardKey/KeyboardKey.js";
5
- import I from "../SearchWindow.js";
6
- import b from "../SearchInput.js";
7
- import { useSearch as M } from "../../hooks/useSearch.js";
8
- import { useSearchLogger as O } from "../../hooks/useSearchLogger.js";
9
- import { useKeyboardNav as P } from "../../hooks/useKeyboardNav.js";
5
+ import w from "../SearchWindow.js";
6
+ import A from "../SearchInput.js";
7
+ import M from "../SearchLink/SearchLink.js";
8
+ import { useSearch as O } from "../../hooks/useSearch.js";
9
+ import { useSearchLogger as P } from "../../hooks/useSearchLogger.js";
10
+ import { useKeyboardNav as C } from "../../hooks/useKeyboardNav.js";
10
11
  import { useSearchHotkeys as E } from "../../hooks/useSearchHotkeys.js";
11
12
  import { useSearchParams as K } from "../../hooks/useSearchParams.js";
12
- import { useSearchToggles as A } from "../../hooks/useSearchToggles.js";
13
- import C from "../../../AskNetlify/AskNetlify.js";
14
- import { Fragment as F } from "preact";
15
- import '../../../../../assets/SearchModal.css';function R(c) {
16
- const r = N(null);
17
- return l(() => {
13
+ import { useSearchToggles as F } from "../../hooks/useSearchToggles.js";
14
+ import R from "../../../AskNetlify/AskNetlify.js";
15
+ import { Fragment as I } from "preact";
16
+ import '../../../../../assets/SearchModal.css';function q(s) {
17
+ const r = v(null);
18
+ return m(() => {
18
19
  function i(t) {
19
- r.current && !r.current.contains(t.target) && c();
20
+ r.current && !r.current.contains(t.target) && s();
20
21
  }
21
22
  return document.addEventListener("mousedown", i), () => {
22
23
  document.removeEventListener("mousedown", i);
23
24
  };
24
- }, [c]), r;
25
+ }, [s]), r;
25
26
  }
26
- function X(c = { className: "", children: null, debug: !1 }) {
27
- const [r, i] = h(!1), [t, u] = h({ current: "search" });
28
- l(() => {
29
- let s;
30
- const o = () => {
31
- window.pagefind && (i(!0), s && clearInterval(s));
27
+ function Z(s = { className: "", children: void 0, debug: !1, kapaIntegrationId: void 0 }) {
28
+ const [r, i] = h(!1), [t, d] = h({ current: "search" });
29
+ m(() => {
30
+ let n;
31
+ const c = () => {
32
+ window.pagefind && (i(!0), n && clearInterval(n));
32
33
  };
33
- return o(), s = setInterval(o, 100), () => clearInterval(s);
34
+ return c(), n = setInterval(c, 100), () => clearInterval(n);
34
35
  }, []);
35
- const { children: k, className: S, debug: y, ...T } = c, { state: n, actions: g } = M(), [m, v] = h(!1), d = () => v(!0), f = () => v(!1), a = N(null), L = R(f);
36
- return O(n, y), A(r, d, u), K(r, g.setSearchTerm, d), E(r, m, d, f), P(r, a, m, f), l(() => {
37
- a.current && (m ? a.current.showModal() : a.current.close());
38
- }, [m]), l(() => {
39
- var o;
40
- const s = (o = a.current) == null ? void 0 : o.querySelector("input");
41
- s && s.focus(), t.current === "ask" ? setTimeout(() => {
36
+ const { children: N, className: k, debug: y, ...L } = s, { state: o, actions: g } = O(), [l, S] = h(!1), u = () => S(!0), f = () => S(!1), a = v(null), T = q(f);
37
+ return P(o, y), F(r, u, d), K(r, g.setSearchTerm, u), E(r, l, u, f), C(r, a, l, f), m(() => {
38
+ a.current && (l ? a.current.showModal() : a.current.close());
39
+ }, [l]), m(() => {
40
+ var c;
41
+ const n = (c = a.current) == null ? void 0 : c.querySelector("input");
42
+ n && n.focus(), t.current === "ask" ? setTimeout(() => {
42
43
  a.current.classList.add("n-search-modal-ask");
43
44
  }, 150) : t.current === "search" && setTimeout(() => {
44
45
  a.current.classList.remove("n-search-modal-ask");
45
46
  }, 150);
46
47
  }, [t.current]), /* @__PURE__ */ e(
47
- w,
48
+ b,
48
49
  {
49
50
  ref: a,
50
- className: `n-search-modal ${S || ""}`,
51
+ className: `n-search-modal ${k || ""}`,
51
52
  "data-state": t.current,
52
- ...T,
53
- children: /* @__PURE__ */ e("div", { ref: L, className: "n-search-container", children: [
54
- t.current === "ask" && /* @__PURE__ */ e(C, { setModalState: u }),
55
- t.current === "search" && /* @__PURE__ */ e(F, { children: [
56
- /* @__PURE__ */ e(b, { setSearchTerm: g.setSearchTerm, initialValue: n.searchTerm }),
53
+ ...L,
54
+ children: /* @__PURE__ */ e("div", { ref: T, className: "n-search-container", children: [
55
+ t.current === "ask" && /* @__PURE__ */ e(R, { setModalState: d, kapaIntegrationId: s.kapaIntegrationId }),
56
+ t.current === "search" && /* @__PURE__ */ e(I, { children: [
57
+ /* @__PURE__ */ e(A, { setSearchTerm: g.setSearchTerm, initialValue: o.searchTerm }),
57
58
  /* @__PURE__ */ e(
58
- I,
59
+ w,
59
60
  {
60
- setModalState: u,
61
- searchLoading: n.isLoading,
62
- searchTerm: n.searchTerm,
63
- results: n.results,
64
- children: k
61
+ searchLoading: o.isLoading,
62
+ searchTerm: o.searchTerm,
63
+ results: o.results,
64
+ children: /* @__PURE__ */ e(I, { children: [
65
+ s.kapaIntegrationId && /* @__PURE__ */ e(
66
+ M,
67
+ {
68
+ as: "button",
69
+ icon: "askNetlify",
70
+ label: "Ask Netlify AI",
71
+ onClick: () => {
72
+ d({ current: "ask" });
73
+ }
74
+ }
75
+ ),
76
+ N
77
+ ] })
65
78
  }
66
79
  ),
67
80
  /* @__PURE__ */ e("div", { className: "n-search-footer", children: [
@@ -82,5 +95,5 @@ function X(c = { className: "", children: null, debug: !1 }) {
82
95
  );
83
96
  }
84
97
  export {
85
- X as default
98
+ Z as default
86
99
  };
@@ -1,2 +1,2 @@
1
1
  import { SearchWindowProps } from '../types/search.types';
2
- export default function SearchWindow({ setModalState, searchLoading, searchTerm, results, children: DefaultWindow, }: SearchWindowProps): import("preact").JSX.Element;
2
+ export default function SearchWindow({ searchLoading, searchTerm, results, children: DefaultWindow, }: SearchWindowProps): import("preact").JSX.Element;
@@ -1,54 +1,42 @@
1
1
  import { u as e } from "../../../../chunks/jsxRuntime.module.Bzuv3cXw.js";
2
- import { T as h } from "../../../../chunks/hooks.module.DGkdD5n9.js";
3
- import s from "./SearchHeading/SearchHeading.js";
2
+ import { T as o } from "../../../../chunks/hooks.module.DGkdD5n9.js";
3
+ import m from "./SearchHeading/SearchHeading.js";
4
4
  import a from "./SearchLink/SearchLink.js";
5
- import { Fragment as d } from "preact";
6
- const u = {
5
+ import { Fragment as h } from "preact";
6
+ const d = {
7
7
  light: "dark",
8
8
  dark: "light"
9
- }, g = (n) => {
10
- const r = document.getElementById("site-theme-select");
11
- r && (r.value = n), document.documentElement.setAttribute("data-theme", n), localStorage.setItem("theme", n);
12
- }, f = ({
9
+ }, u = (n) => {
10
+ const t = document.getElementById("site-theme-select");
11
+ t && (t.value = n), document.documentElement.setAttribute("data-theme", n), localStorage.setItem("theme", n);
12
+ }, g = ({
13
13
  searchLoading: n,
14
- searchTerm: r,
15
- results: t
14
+ searchTerm: t,
15
+ results: r
16
16
  }) => {
17
17
  if (n)
18
- return /* @__PURE__ */ e(s, { children: [
18
+ return /* @__PURE__ */ e(m, { children: [
19
19
  "Searching for ",
20
- /* @__PURE__ */ e("span", { className: "n-search-term", children: r }),
20
+ /* @__PURE__ */ e("span", { className: "n-search-term", children: t }),
21
21
  " ..."
22
22
  ] });
23
- if (!t || t.length === 0)
24
- return /* @__PURE__ */ e(s, { children: [
23
+ if (!r || r.length === 0)
24
+ return /* @__PURE__ */ e(m, { children: [
25
25
  "0 results for ",
26
- /* @__PURE__ */ e("span", { className: "n-search-term", children: r })
26
+ /* @__PURE__ */ e("span", { className: "n-search-term", children: t })
27
27
  ] });
28
- const c = h(() => t.map((l, i) => /* @__PURE__ */ e("li", { className: "n-results-list-item", children: /* @__PURE__ */ e(a, { ...l }) }, i)), [t]);
28
+ const c = o(() => r.map((i, l) => /* @__PURE__ */ e("li", { className: "n-results-list-item", children: /* @__PURE__ */ e(a, { ...i }) }, l)), [r]);
29
29
  return /* @__PURE__ */ e("ul", { className: "n-results-list", role: "list", children: c });
30
30
  };
31
- function A({
32
- setModalState: n,
33
- searchLoading: r,
31
+ function N({
32
+ searchLoading: n,
34
33
  searchTerm: t,
35
- results: c,
36
- children: l
34
+ results: r,
35
+ children: c
37
36
  }) {
38
- return /* @__PURE__ */ e("div", { className: "n-search-window", children: /* @__PURE__ */ e("div", { className: "n-search-links", children: t && t.length > 1 ? /* @__PURE__ */ e(f, { searchLoading: r, searchTerm: t, results: c }) : l ? /* @__PURE__ */ e(d, { children: [
39
- /* @__PURE__ */ e(
40
- a,
41
- {
42
- as: "button",
43
- icon: "askNetlify",
44
- label: "Ask Netlify AI",
45
- onClick: () => {
46
- n({ current: "ask" });
47
- }
48
- }
49
- ),
50
- l,
51
- /* @__PURE__ */ e(s, { children: "Actions" }),
37
+ return /* @__PURE__ */ e("div", { className: "n-search-window", children: /* @__PURE__ */ e("div", { className: "n-search-links", children: t && t.length > 1 ? /* @__PURE__ */ e(g, { searchLoading: n, searchTerm: t, results: r }) : c ? /* @__PURE__ */ e(h, { children: [
38
+ c,
39
+ /* @__PURE__ */ e(m, { children: "Actions" }),
52
40
  /* @__PURE__ */ e(
53
41
  a,
54
42
  {
@@ -56,13 +44,13 @@ function A({
56
44
  icon: "lightbulb",
57
45
  label: "Toggle theme",
58
46
  onClick: () => {
59
- const i = window.matchMedia("(prefers-color-scheme: dark)").matches, m = document.documentElement.getAttribute("data-theme"), o = i ? "dark" : m || "light";
60
- o && g(u[o]);
47
+ const i = window.matchMedia("(prefers-color-scheme: dark)").matches, l = document.documentElement.getAttribute("data-theme"), s = i ? "dark" : l || "light";
48
+ s && u(d[s]);
61
49
  }
62
50
  }
63
51
  )
64
52
  ] }) : null }) });
65
53
  }
66
54
  export {
67
- A as default
55
+ N as default
68
56
  };
@@ -10,9 +10,6 @@ export interface SearchLinkProps {
10
10
  onClick?: () => void;
11
11
  }
12
12
  export interface SearchWindowProps {
13
- setModalState: (e: {
14
- current: string;
15
- }) => void;
16
13
  searchLoading: boolean;
17
14
  searchTerm?: string;
18
15
  results?: SearchLinkProps[];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@netlify/spark-ui",
3
3
  "description": "Assets, design tokens, components, and utilities",
4
- "version": "1.10.0",
4
+ "version": "1.11.0",
5
5
  "type": "module",
6
6
  "main": "dist/components/preact/index.js",
7
7
  "types": "dist/components/preact/index.d.ts",
@@ -5,23 +5,31 @@ import ChatInterface from './components/ChatInterface';
5
5
  import './AskNetlify.css';
6
6
 
7
7
  interface AskNetlifyProps {
8
- setModalState?: (state?: { current: string }) => void;
8
+ kapaIntegrationId?: string;
9
+ setModalState?: (e: { current: string }) => void;
9
10
  }
10
11
 
11
12
  export default function AskNetlify(props: AskNetlifyProps) {
12
13
  const analyticsRef = useRef<Analytics>(new Analytics());
14
+
15
+ if (!props.kapaIntegrationId) return;
16
+
13
17
  return (
14
18
  <KapaProvider
15
- integrationId="3c0789a6-c6a8-4fbc-b0cc-235f9e4a6351"
19
+ integrationId={props.kapaIntegrationId}
16
20
  callbacks={{
17
21
  askAI: {
18
22
  onQuerySubmit: data => {
23
+ if (!data.question || !data.threadId) return;
24
+
19
25
  analyticsRef?.current?.track('ask:new_query', {
20
26
  question: data.question,
21
27
  thread_id: data.threadId,
22
28
  });
23
29
  },
24
30
  onAnswerGenerationCompleted: data => {
31
+ if (!data.questionAnswerId || !data.answer) return;
32
+
25
33
  analyticsRef?.current?.track('ask:answer_generated', {
26
34
  question_id: data.questionAnswerId,
27
35
  answer_length: data.answer.length,
@@ -30,7 +38,7 @@ export default function AskNetlify(props: AskNetlifyProps) {
30
38
  },
31
39
  }}
32
40
  >
33
- <ChatInterface {...props} />
41
+ <ChatInterface setModalState={props.setModalState} />
34
42
  </KapaProvider>
35
43
  );
36
44
  }
@@ -6,7 +6,7 @@ import { BackButton } from './BackButton';
6
6
  import { ChatMessages } from './ChatMessages';
7
7
 
8
8
  interface Props {
9
- setModalState?: (state?: { current: string }) => void;
9
+ setModalState?: (e: { current: string }) => void;
10
10
  }
11
11
 
12
12
  export default function ChatInterface({ setModalState }: Props) {
@@ -5,6 +5,7 @@ import Modal from '../../../../preact/Modal/Modal';
5
5
  import KeyboardKey from '../../../../preact/KeyboardKey/KeyboardKey';
6
6
  import SearchWindow from '../../components/SearchWindow';
7
7
  import SearchInput from '../../components/SearchInput';
8
+ import SearchLink from '../../components/SearchLink/SearchLink';
8
9
  import { useClickOutside } from '../../../../../utils/useClickOutside';
9
10
  import {
10
11
  useSearch,
@@ -23,9 +24,12 @@ interface Props {
23
24
  children: ComponentChildren;
24
25
  className?: string;
25
26
  debug?: boolean;
27
+ kapaIntegrationId?: string;
26
28
  }
27
29
 
28
- function SearchModal(props: Props = { className: '', children: null, debug: false }) {
30
+ function SearchModal(
31
+ props: Props = { className: '', children: undefined, debug: false, kapaIntegrationId: undefined }
32
+ ) {
29
33
  const [isPagefindLoaded, setIsPagefindLoaded] = useState(false);
30
34
  const [modalState, setModalState] = useState({ current: 'search' });
31
35
 
@@ -93,18 +97,31 @@ function SearchModal(props: Props = { className: '', children: null, debug: fals
93
97
  {...rest}
94
98
  >
95
99
  <div ref={containerRef} className="n-search-container">
96
- {modalState.current === 'ask' && <AskNetlify setModalState={setModalState} />}
100
+ {modalState.current === 'ask' && (
101
+ <AskNetlify setModalState={setModalState} kapaIntegrationId={props.kapaIntegrationId} />
102
+ )}
97
103
  {modalState.current === 'search' && (
98
104
  <>
99
105
  <SearchInput setSearchTerm={actions.setSearchTerm} initialValue={state.searchTerm} />
100
106
 
101
107
  <SearchWindow
102
- setModalState={setModalState}
103
108
  searchLoading={state.isLoading}
104
109
  searchTerm={state.searchTerm}
105
110
  results={state.results}
106
111
  >
107
- {children}
112
+ <>
113
+ {props.kapaIntegrationId && (
114
+ <SearchLink
115
+ as="button"
116
+ icon="askNetlify"
117
+ label="Ask Netlify AI"
118
+ onClick={() => {
119
+ setModalState({ current: 'ask' });
120
+ }}
121
+ />
122
+ )}
123
+ {children}
124
+ </>
108
125
  </SearchWindow>
109
126
 
110
127
  <div className="n-search-footer">
@@ -45,7 +45,6 @@ const SearchResults: FunctionComponent<SearchResultsProps> = ({
45
45
 
46
46
  /* --- Main Search Results Component --- */
47
47
  export default function SearchWindow({
48
- setModalState,
49
48
  searchLoading,
50
49
  searchTerm,
51
50
  results,
@@ -58,15 +57,6 @@ export default function SearchWindow({
58
57
  <SearchResults searchLoading={searchLoading} searchTerm={searchTerm} results={results} />
59
58
  ) : DefaultWindow ? (
60
59
  <>
61
- <SearchLink
62
- as="button"
63
- icon="askNetlify"
64
- label="Ask Netlify AI"
65
- onClick={() => {
66
- setModalState({ current: 'ask' });
67
- }}
68
- />
69
-
70
60
  {DefaultWindow}
71
61
 
72
62
  <SearchHeading>Actions</SearchHeading>
@@ -12,7 +12,6 @@ export interface SearchLinkProps {
12
12
  }
13
13
 
14
14
  export interface SearchWindowProps {
15
- setModalState: (e: { current: string }) => void;
16
15
  searchLoading: boolean;
17
16
  searchTerm?: string;
18
17
  results?: SearchLinkProps[];