@bikdotai/bik-component-library 0.0.868 → 0.0.869

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 (65) hide show
  1. package/dist/cjs/components/bik-copilot/ControlledCopilot.js +1 -1
  2. package/dist/cjs/components/bik-copilot/ControlledCopilot.js.map +1 -1
  3. package/dist/cjs/components/bik-copilot/CopilotPanel.js +1 -1
  4. package/dist/cjs/components/bik-copilot/CopilotPanel.js.map +1 -1
  5. package/dist/cjs/components/bik-copilot/CopilotPanel.styled.js +53 -12
  6. package/dist/cjs/components/bik-copilot/CopilotPanel.styled.js.map +1 -1
  7. package/dist/cjs/components/bik-copilot/copilotSelectionPrompt.js +2 -0
  8. package/dist/cjs/components/bik-copilot/copilotSelectionPrompt.js.map +1 -0
  9. package/dist/cjs/components/text-selection-ask/SelectionAskPill.js +2 -0
  10. package/dist/cjs/components/text-selection-ask/SelectionAskPill.js.map +1 -0
  11. package/dist/cjs/components/text-selection-ask/SelectionAskPill.styled.js +32 -0
  12. package/dist/cjs/components/text-selection-ask/SelectionAskPill.styled.js.map +1 -0
  13. package/dist/cjs/components/text-selection-ask/TextSelectionAsk.js +2 -0
  14. package/dist/cjs/components/text-selection-ask/TextSelectionAsk.js.map +1 -0
  15. package/dist/cjs/components/text-selection-ask/model.js +2 -0
  16. package/dist/cjs/components/text-selection-ask/model.js.map +1 -0
  17. package/dist/cjs/components/text-selection-ask/selectionText.js +2 -0
  18. package/dist/cjs/components/text-selection-ask/selectionText.js.map +1 -0
  19. package/dist/cjs/components/text-selection-ask/useTextSelectionAsk.js +2 -0
  20. package/dist/cjs/components/text-selection-ask/useTextSelectionAsk.js.map +1 -0
  21. package/dist/cjs/icons/Informational/Common UI/SquaresFour.js +2 -0
  22. package/dist/cjs/icons/Informational/Common UI/SquaresFour.js.map +1 -0
  23. package/dist/cjs/icons/index.js +1 -1
  24. package/dist/cjs/index.js +1 -1
  25. package/dist/esm/components/bik-copilot/ControlledCopilot.js +34 -30
  26. package/dist/esm/components/bik-copilot/ControlledCopilot.js.map +1 -1
  27. package/dist/esm/components/bik-copilot/CopilotPanel.js +261 -237
  28. package/dist/esm/components/bik-copilot/CopilotPanel.js.map +1 -1
  29. package/dist/esm/components/bik-copilot/CopilotPanel.styled.d.ts +8 -0
  30. package/dist/esm/components/bik-copilot/CopilotPanel.styled.js +69 -25
  31. package/dist/esm/components/bik-copilot/CopilotPanel.styled.js.map +1 -1
  32. package/dist/esm/components/bik-copilot/copilotSelectionPrompt.d.ts +13 -0
  33. package/dist/esm/components/bik-copilot/copilotSelectionPrompt.js +8 -0
  34. package/dist/esm/components/bik-copilot/copilotSelectionPrompt.js.map +1 -0
  35. package/dist/esm/components/bik-copilot/model.d.ts +19 -0
  36. package/dist/esm/components/text-selection-ask/SelectionAskPill.d.ts +22 -0
  37. package/dist/esm/components/text-selection-ask/SelectionAskPill.js +44 -0
  38. package/dist/esm/components/text-selection-ask/SelectionAskPill.js.map +1 -0
  39. package/dist/esm/components/text-selection-ask/SelectionAskPill.styled.d.ts +5 -0
  40. package/dist/esm/components/text-selection-ask/SelectionAskPill.styled.js +37 -0
  41. package/dist/esm/components/text-selection-ask/SelectionAskPill.styled.js.map +1 -0
  42. package/dist/esm/components/text-selection-ask/TextSelectionAsk.d.ts +36 -0
  43. package/dist/esm/components/text-selection-ask/TextSelectionAsk.js +69 -0
  44. package/dist/esm/components/text-selection-ask/TextSelectionAsk.js.map +1 -0
  45. package/dist/esm/components/text-selection-ask/index.d.ts +7 -0
  46. package/dist/esm/components/text-selection-ask/model.d.ts +112 -0
  47. package/dist/esm/components/text-selection-ask/model.js +7 -0
  48. package/dist/esm/components/text-selection-ask/model.js.map +1 -0
  49. package/dist/esm/components/text-selection-ask/selectionText.d.ts +18 -0
  50. package/dist/esm/components/text-selection-ask/selectionText.js +7 -0
  51. package/dist/esm/components/text-selection-ask/selectionText.js.map +1 -0
  52. package/dist/esm/components/text-selection-ask/useTextSelectionAsk.d.ts +15 -0
  53. package/dist/esm/components/text-selection-ask/useTextSelectionAsk.js +53 -0
  54. package/dist/esm/components/text-selection-ask/useTextSelectionAsk.js.map +1 -0
  55. package/dist/esm/icons/Informational/Common UI/SquaresFour.d.ts +7 -0
  56. package/dist/esm/icons/Informational/Common UI/SquaresFour.js +33 -0
  57. package/dist/esm/icons/Informational/Common UI/SquaresFour.js.map +1 -0
  58. package/dist/esm/icons/Informational/Common UI/index.d.ts +1 -0
  59. package/dist/esm/icons/index.d.ts +25 -25
  60. package/dist/esm/icons/index.js +158 -156
  61. package/dist/esm/icons/index.js.map +1 -1
  62. package/dist/esm/index.d.ts +1 -0
  63. package/dist/esm/index.js +403 -388
  64. package/dist/esm/index.js.map +1 -1
  65. package/package.json +1 -1
@@ -205,6 +205,18 @@ export interface CopilotShellProps {
205
205
  * @default 'Loading earlier messages'
206
206
  */
207
207
  historyLoadingLabel?: string;
208
+ /**
209
+ * Text quoted above the input for the next message to carry — what
210
+ * `TextSelectionAsk` hands over when the merchant asks about something they
211
+ * selected on the page. Nothing is sent until they press send.
212
+ */
213
+ attachment?: string;
214
+ /**
215
+ * Called when the attachment should go away: the merchant removed it, or the
216
+ * message that carried it has been sent. The owner of `attachment` must clear
217
+ * it here.
218
+ */
219
+ onAttachmentRemove?: () => void;
208
220
  /**
209
221
  * Controls the panel from the outside. When set, the component stops managing
210
222
  * its own open state and `onOpenChange` must apply the change.
@@ -729,6 +741,13 @@ export interface CopilotPanelProps {
729
741
  onLoadOlderMessages?: () => void;
730
742
  historyLoadingLabel?: string;
731
743
  inputDisabled?: boolean;
744
+ /**
745
+ * Text quoted above the input — the selection the merchant asked about. Sent
746
+ * as part of the next message and cleared with it.
747
+ */
748
+ attachment?: string;
749
+ /** Called when the attachment's remove button is pressed. */
750
+ onAttachmentRemove?: () => void;
732
751
  errorMessage?: string;
733
752
  width?: number;
734
753
  height?: number;
@@ -0,0 +1,22 @@
1
+ import { default as React } from 'react';
2
+ import { SelectionAskPillProps, SelectionRect, SelectionViewport } from './model';
3
+ /**
4
+ * Marks the pill in the DOM so a host's own outside-click or selection handling
5
+ * can tell it apart from the page underneath.
6
+ */
7
+ export declare const SELECTION_ASK_PILL_ATTRIBUTE = "data-bik-selection-ask-pill";
8
+ /**
9
+ * Puts the pill above the selection, centred on it, and flips it below when the
10
+ * selection is close enough to the top of the viewport that above would be off
11
+ * screen. Exported for the tests, which have no layout engine to check against.
12
+ */
13
+ export declare const getSelectionPillPosition: (rect: SelectionRect, viewport: SelectionViewport) => {
14
+ left: number;
15
+ top: number;
16
+ };
17
+ /**
18
+ * The "Ask AI" pill that appears next to selected text. Purely presentational —
19
+ * finding the selection is `useTextSelectionAsk`'s job.
20
+ */
21
+ export declare const SelectionAskPill: React.FC<SelectionAskPillProps>;
22
+ export default SelectionAskPill;
@@ -0,0 +1,44 @@
1
+ import { jsxs as p, jsx as I } from "react/jsx-runtime";
2
+ import P from "../../assets/icons/bik_ai_stars_icon.svg.js";
3
+ import { PillButton as L } from "./SelectionAskPill.styled.js";
4
+ const _ = "data-bik-selection-ask-pill", c = 8, n = 8, r = 88, f = 28, w = (t, o) => {
5
+ const i = t.left + t.width / 2 - r / 2, s = Math.max(
6
+ n,
7
+ o.width - r - n
8
+ ), e = t.top - f - c, l = e < n ? t.top + t.height + c : e;
9
+ return {
10
+ left: Math.min(Math.max(i, n), s),
11
+ top: l
12
+ };
13
+ }, x = ({
14
+ anchor: t,
15
+ label: o = "Ask AI",
16
+ zIndex: i = 1202,
17
+ onClick: s,
18
+ viewport: e
19
+ }) => {
20
+ const l = e ?? (typeof window > "u" ? { width: 0 } : { width: window.innerWidth }), { left: d, top: a } = w(t.rect, l);
21
+ return /* @__PURE__ */ p(
22
+ L,
23
+ {
24
+ type: "button",
25
+ [_]: "true",
26
+ $left: d,
27
+ $top: a,
28
+ $zIndex: i,
29
+ onMouseDown: (h) => h.preventDefault(),
30
+ onClick: s,
31
+ "aria-label": `${o} about the selected text`,
32
+ children: [
33
+ /* @__PURE__ */ I(P, { width: 14, height: 14 }),
34
+ o
35
+ ]
36
+ }
37
+ );
38
+ };
39
+ export {
40
+ _ as SELECTION_ASK_PILL_ATTRIBUTE,
41
+ x as SelectionAskPill,
42
+ w as getSelectionPillPosition
43
+ };
44
+ //# sourceMappingURL=SelectionAskPill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectionAskPill.js","sources":["../../../../src/components/text-selection-ask/SelectionAskPill.tsx"],"sourcesContent":["import AiStarsIcon from '@src/assets/icons/bik_ai_stars_icon.svg';\nimport React from 'react';\nimport {\n\tSelectionAskPillProps,\n\tSelectionRect,\n\tSelectionViewport,\n} from './model';\nimport { PillButton } from './SelectionAskPill.styled';\n\n/**\n * Marks the pill in the DOM so a host's own outside-click or selection handling\n * can tell it apart from the page underneath.\n */\nexport const SELECTION_ASK_PILL_ATTRIBUTE = 'data-bik-selection-ask-pill';\n\n/** Gap between the selection and the pill. */\nconst PILL_GAP_PX = 8;\n\n/** Smallest distance the pill keeps from the edge of the viewport. */\nconst PILL_MARGIN_PX = 8;\n\n/**\n * The design's hug size (88 x 28). Width is used for clamping only — the pill\n * hugs its label in the DOM, and estimating is enough to keep it on screen.\n * Measuring would mean rendering it off screen first and then moving it, which\n * reads as a flicker.\n */\nconst PILL_ESTIMATED_WIDTH_PX = 88;\n\nconst PILL_HEIGHT_PX = 28;\n\n/**\n * Puts the pill above the selection, centred on it, and flips it below when the\n * selection is close enough to the top of the viewport that above would be off\n * screen. Exported for the tests, which have no layout engine to check against.\n */\nexport const getSelectionPillPosition = (\n\trect: SelectionRect,\n\tviewport: SelectionViewport,\n): { left: number; top: number } => {\n\tconst centred = rect.left + rect.width / 2 - PILL_ESTIMATED_WIDTH_PX / 2;\n\tconst maxLeft = Math.max(\n\t\tPILL_MARGIN_PX,\n\t\tviewport.width - PILL_ESTIMATED_WIDTH_PX - PILL_MARGIN_PX,\n\t);\n\n\tconst above = rect.top - PILL_HEIGHT_PX - PILL_GAP_PX;\n\tconst top =\n\t\tabove < PILL_MARGIN_PX ? rect.top + rect.height + PILL_GAP_PX : above;\n\n\treturn {\n\t\tleft: Math.min(Math.max(centred, PILL_MARGIN_PX), maxLeft),\n\t\ttop,\n\t};\n};\n\n/**\n * The \"Ask AI\" pill that appears next to selected text. Purely presentational —\n * finding the selection is `useTextSelectionAsk`'s job.\n */\nexport const SelectionAskPill: React.FC<SelectionAskPillProps> = ({\n\tanchor,\n\tlabel = 'Ask AI',\n\tzIndex = 1202,\n\tonClick,\n\tviewport,\n}) => {\n\tconst resolvedViewport =\n\t\tviewport ??\n\t\t(typeof window === 'undefined'\n\t\t\t? { width: 0, height: 0 }\n\t\t\t: { width: window.innerWidth, height: window.innerHeight });\n\tconst { left, top } = getSelectionPillPosition(anchor.rect, resolvedViewport);\n\n\treturn (\n\t\t<PillButton\n\t\t\ttype=\"button\"\n\t\t\t{...{ [SELECTION_ASK_PILL_ATTRIBUTE]: 'true' }}\n\t\t\t$left={left}\n\t\t\t$top={top}\n\t\t\t$zIndex={zIndex}\n\t\t\t/* Pressing the pill would otherwise collapse the selection before the\n\t\t\t click handler runs, and there would be nothing left to hand over. */\n\t\t\tonMouseDown={(event) => event.preventDefault()}\n\t\t\tonClick={onClick}\n\t\t\taria-label={`${label} about the selected text`}\n\t\t>\n\t\t\t<AiStarsIcon width={14} height={14} />\n\t\t\t{label}\n\t\t</PillButton>\n\t);\n};\n\nexport default SelectionAskPill;\n"],"names":["SELECTION_ASK_PILL_ATTRIBUTE","PILL_GAP_PX","PILL_MARGIN_PX","PILL_ESTIMATED_WIDTH_PX","PILL_HEIGHT_PX","getSelectionPillPosition","rect","viewport","centred","maxLeft","above","top","SelectionAskPill","anchor","label","zIndex","onClick","resolvedViewport","left","jsxs","PillButton","event","jsx","AiStarsIcon"],"mappings":";;;AAaO,MAAMA,IAA+B,+BAGtCC,IAAc,GAGdC,IAAiB,GAQjBC,IAA0B,IAE1BC,IAAiB,IAOVC,IAA2B,CACvCC,GACAC,MACmC;AACnC,QAAMC,IAAUF,EAAK,OAAOA,EAAK,QAAQ,IAAIH,IAA0B,GACjEM,IAAU,KAAK;AAAA,IACpBP;AAAA,IACAK,EAAS,QAAQJ,IAA0BD;AAAA,EAAA,GAGtCQ,IAAQJ,EAAK,MAAMF,IAAiBH,GACpCU,IACLD,IAAQR,IAAiBI,EAAK,MAAMA,EAAK,SAASL,IAAcS;AAEjE,SAAO;AAAA,IACN,MAAM,KAAK,IAAI,KAAK,IAAIF,GAASN,CAAc,GAAGO,CAAO;AAAA,IACzD,KAAAE;AAAA,EAAA;AAEF,GAMaC,IAAoD,CAAC;AAAA,EACjE,QAAAC;AAAA,EACA,OAAAC,IAAQ;AAAA,EACR,QAAAC,IAAS;AAAA,EACT,SAAAC;AAAA,EACA,UAAAT;AACD,MAAM;AACL,QAAMU,IACLV,MACC,OAAO,SAAW,MAChB,EAAE,OAAO,EAAa,IACtB,EAAE,OAAO,OAAO,WAAuC,IACrD,EAAE,MAAAW,GAAM,KAAAP,EAAA,IAAQN,EAAyBQ,EAAO,MAAMI,CAAgB;AAE5E,SACC,gBAAAE;AAAA,IAACC;AAAA,IAAA;AAAA,MACA,MAAK;AAAA,MACC,CAACpB,CAA4B,GAAG;AAAA,MACtC,OAAOkB;AAAA,MACP,MAAMP;AAAA,MACN,SAASI;AAAA,MAGT,aAAa,CAACM,MAAUA,EAAM,eAAA;AAAA,MAC9B,SAAAL;AAAA,MACA,cAAY,GAAGF,CAAK;AAAA,MAEpB,UAAA;AAAA,QAAA,gBAAAQ,EAACC,GAAA,EAAY,OAAO,IAAI,QAAQ,IAAI;AAAA,QACnCT;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGJ;"}
@@ -0,0 +1,5 @@
1
+ export declare const PillButton: import('styled-components').StyledComponent<"button", any, {
2
+ $left: number;
3
+ $top: number;
4
+ $zIndex: number;
5
+ }, never>;
@@ -0,0 +1,37 @@
1
+ import t from "styled-components";
2
+ import { COLORS as r } from "../../constants/Theme.js";
3
+ const i = t.button`
4
+ position: fixed;
5
+ left: ${(o) => o.$left}px;
6
+ top: ${(o) => o.$top}px;
7
+ z-index: ${(o) => o.$zIndex};
8
+ display: flex;
9
+ align-items: center;
10
+ gap: 4px;
11
+ box-sizing: border-box;
12
+ height: 28px;
13
+ padding: 4px 8px;
14
+ border: 1px solid ${r.stroke.brand};
15
+ border-radius: 4px;
16
+ background: ${r.surface.standard};
17
+ color: ${r.content.brand};
18
+ font-family: Inter;
19
+ font-size: 12px;
20
+ font-weight: 600;
21
+ line-height: 18px;
22
+ white-space: nowrap;
23
+ cursor: pointer;
24
+ box-shadow: 0 4px 12px rgba(40, 3, 78, 0.16);
25
+
26
+ svg {
27
+ flex-shrink: 0;
28
+ }
29
+
30
+ &:hover {
31
+ background: ${r.background.brandVeryLight};
32
+ }
33
+ `;
34
+ export {
35
+ i as PillButton
36
+ };
37
+ //# sourceMappingURL=SelectionAskPill.styled.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectionAskPill.styled.js","sources":["../../../../src/components/text-selection-ask/SelectionAskPill.styled.ts"],"sourcesContent":["import styled from 'styled-components';\nimport { COLORS } from '@src/constants/Theme';\n\nexport const PillButton = styled.button<{\n\t$left: number;\n\t$top: number;\n\t$zIndex: number;\n}>`\n\tposition: fixed;\n\tleft: ${(props) => props.$left}px;\n\ttop: ${(props) => props.$top}px;\n\tz-index: ${(props) => props.$zIndex};\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 4px;\n\tbox-sizing: border-box;\n\theight: 28px;\n\tpadding: 4px 8px;\n\tborder: 1px solid ${COLORS.stroke.brand};\n\tborder-radius: 4px;\n\tbackground: ${COLORS.surface.standard};\n\tcolor: ${COLORS.content.brand};\n\tfont-family: Inter;\n\tfont-size: 12px;\n\tfont-weight: 600;\n\tline-height: 18px;\n\twhite-space: nowrap;\n\tcursor: pointer;\n\tbox-shadow: 0 4px 12px rgba(40, 3, 78, 0.16);\n\n\tsvg {\n\t\tflex-shrink: 0;\n\t}\n\n\t&:hover {\n\t\tbackground: ${COLORS.background.brandVeryLight};\n\t}\n`;\n"],"names":["PillButton","styled","props","COLORS"],"mappings":";;AAGO,MAAMA,IAAaC,EAAO;AAAA;AAAA,SAMxB,CAACC,MAAUA,EAAM,KAAK;AAAA,QACvB,CAACA,MAAUA,EAAM,IAAI;AAAA,YACjB,CAACA,MAAUA,EAAM,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAOfC,EAAO,OAAO,KAAK;AAAA;AAAA,eAEzBA,EAAO,QAAQ,QAAQ;AAAA,UAC5BA,EAAO,QAAQ,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAcdA,EAAO,WAAW,cAAc;AAAA;AAAA;"}
@@ -0,0 +1,36 @@
1
+ import { default as React } from 'react';
2
+ import { TextSelectionAskProps } from './model';
3
+ /**
4
+ * Marks everything this component renders as its own, so a selection made
5
+ * inside the destination — reading a copilot reply, for instance — is not
6
+ * mistaken for a new question about the page.
7
+ */
8
+ export declare const SELECTION_ASK_HOST_ATTRIBUTE = "data-bik-selection-ask-host";
9
+ /**
10
+ * Offers an "Ask AI" pill whenever the user selects text on the page, and hands
11
+ * that selection to wherever it should go.
12
+ *
13
+ * Mount it once, near the root of the app. Selections inside a form field, and
14
+ * inside whatever this renders, are ignored — the rest of the page needs no
15
+ * markup of its own.
16
+ *
17
+ * With `target="COPILOT_AGENT"` it renders the BIK Copilot and attaches the
18
+ * selection above its input, so the user types their question with the text
19
+ * already quoted. Nothing is sent until they press send:
20
+ *
21
+ * ```tsx
22
+ * <TextSelectionAsk
23
+ * target={SELECTION_ASK_TARGET.COPILOT_AGENT}
24
+ * copilot={{ baseUrl, storeId, route, getAuthToken }}
25
+ * />
26
+ * ```
27
+ *
28
+ * Without a target it is just the pill, and the selection arrives in `onAsk` for
29
+ * the host to do anything else with:
30
+ *
31
+ * ```tsx
32
+ * <TextSelectionAsk onAsk={(selection) => openMyOwnAssistant(selection)} />
33
+ * ```
34
+ */
35
+ export declare const TextSelectionAsk: React.FC<TextSelectionAskProps>;
36
+ export default TextSelectionAsk;
@@ -0,0 +1,69 @@
1
+ import { jsxs as g, Fragment as B, jsx as c } from "react/jsx-runtime";
2
+ import { useState as h, useCallback as o } from "react";
3
+ import { BIKCopilot as L } from "../bik-copilot/BIKCopilot.js";
4
+ import { SELECTION_ASK_TARGET as R } from "./model.js";
5
+ import { SelectionAskPill as K } from "./SelectionAskPill.js";
6
+ import { useTextSelectionAsk as N } from "./useTextSelectionAsk.js";
7
+ const C = "data-bik-selection-ask-host", U = ({
8
+ enabled: O = !0,
9
+ target: T,
10
+ copilot: t,
11
+ onAsk: i,
12
+ label: d,
13
+ zIndex: A,
14
+ minLength: S,
15
+ shouldIgnore: m
16
+ }) => {
17
+ const [E, u] = h(null), [k, x] = h(
18
+ t?.defaultOpen ?? !1
19
+ ), r = T === R.COPILOT_AGENT && !!t, s = t?.open !== void 0, l = s ? !!t?.open : k, a = o(
20
+ (e) => {
21
+ s || x(e), t?.onOpenChange?.(e);
22
+ },
23
+ [t, s]
24
+ ), I = o(
25
+ (e) => {
26
+ const p = e instanceof HTMLElement ? e : e.parentElement;
27
+ return p ? p.closest(`[${C}]`) ? !0 : m?.(e) ?? !1 : !1;
28
+ },
29
+ [m]
30
+ ), { anchor: n, clear: f } = N({
31
+ enabled: O,
32
+ minLength: S,
33
+ shouldIgnore: I
34
+ }), _ = o(() => {
35
+ if (!n)
36
+ return;
37
+ const { text: e } = n;
38
+ f(), i?.(e), r && (u(e), l || a(!0));
39
+ }, [n, f, l, i, a, r]), v = o(() => u(null), []);
40
+ return /* @__PURE__ */ g(B, { children: [
41
+ r && t && /* A plain wrapper: the copilot's ball and panel are `position: fixed`,
42
+ and a static div is not a containing block, so their placement is
43
+ untouched. */
44
+ /* @__PURE__ */ c("div", { [C]: "true", children: /* @__PURE__ */ c(
45
+ L,
46
+ {
47
+ ...t,
48
+ open: l,
49
+ onOpenChange: a,
50
+ attachment: E ?? void 0,
51
+ onAttachmentRemove: v
52
+ }
53
+ ) }),
54
+ n && /* @__PURE__ */ c(
55
+ K,
56
+ {
57
+ anchor: n,
58
+ label: d,
59
+ zIndex: A ?? (t?.zIndex ?? 1200) + 2,
60
+ onClick: _
61
+ }
62
+ )
63
+ ] });
64
+ };
65
+ export {
66
+ C as SELECTION_ASK_HOST_ATTRIBUTE,
67
+ U as TextSelectionAsk
68
+ };
69
+ //# sourceMappingURL=TextSelectionAsk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TextSelectionAsk.js","sources":["../../../../src/components/text-selection-ask/TextSelectionAsk.tsx"],"sourcesContent":["import React, { useCallback, useState } from 'react';\nimport { BIKCopilot } from '../bik-copilot/BIKCopilot';\nimport { SELECTION_ASK_TARGET, TextSelectionAskProps } from './model';\nimport { SelectionAskPill } from './SelectionAskPill';\nimport { useTextSelectionAsk } from './useTextSelectionAsk';\n\n/**\n * Marks everything this component renders as its own, so a selection made\n * inside the destination — reading a copilot reply, for instance — is not\n * mistaken for a new question about the page.\n */\nexport const SELECTION_ASK_HOST_ATTRIBUTE = 'data-bik-selection-ask-host';\n\n/**\n * Offers an \"Ask AI\" pill whenever the user selects text on the page, and hands\n * that selection to wherever it should go.\n *\n * Mount it once, near the root of the app. Selections inside a form field, and\n * inside whatever this renders, are ignored — the rest of the page needs no\n * markup of its own.\n *\n * With `target=\"COPILOT_AGENT\"` it renders the BIK Copilot and attaches the\n * selection above its input, so the user types their question with the text\n * already quoted. Nothing is sent until they press send:\n *\n * ```tsx\n * <TextSelectionAsk\n * target={SELECTION_ASK_TARGET.COPILOT_AGENT}\n * copilot={{ baseUrl, storeId, route, getAuthToken }}\n * />\n * ```\n *\n * Without a target it is just the pill, and the selection arrives in `onAsk` for\n * the host to do anything else with:\n *\n * ```tsx\n * <TextSelectionAsk onAsk={(selection) => openMyOwnAssistant(selection)} />\n * ```\n */\nexport const TextSelectionAsk: React.FC<TextSelectionAskProps> = ({\n\tenabled = true,\n\ttarget,\n\tcopilot,\n\tonAsk,\n\tlabel,\n\tzIndex,\n\tminLength,\n\tshouldIgnore,\n}) => {\n\t// The selection handed to the copilot, quoted above its input until it is\n\t// sent or removed.\n\tconst [attachment, setAttachment] = useState<string | null>(null);\n\tconst [uncontrolledOpen, setUncontrolledOpen] = useState(\n\t\tcopilot?.defaultOpen ?? false,\n\t);\n\n\tconst usesCopilot =\n\t\ttarget === SELECTION_ASK_TARGET.COPILOT_AGENT && Boolean(copilot);\n\n\t// A host that drives the copilot's `open` itself keeps that control; asking\n\t// about a selection then goes through its `onOpenChange` like any other open.\n\tconst isCopilotControlled = copilot?.open !== undefined;\n\tconst isCopilotOpen = isCopilotControlled\n\t\t? Boolean(copilot?.open)\n\t\t: uncontrolledOpen;\n\n\tconst setCopilotOpen = useCallback(\n\t\t(next: boolean) => {\n\t\t\tif (!isCopilotControlled) {\n\t\t\t\tsetUncontrolledOpen(next);\n\t\t\t}\n\t\t\tcopilot?.onOpenChange?.(next);\n\t\t},\n\t\t[copilot, isCopilotControlled],\n\t);\n\n\tconst ignoreOwnSurfaces = useCallback(\n\t\t(node: Node) => {\n\t\t\tconst element = node instanceof HTMLElement ? node : node.parentElement;\n\t\t\tif (!element) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (element.closest(`[${SELECTION_ASK_HOST_ATTRIBUTE}]`)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn shouldIgnore?.(node) ?? false;\n\t\t},\n\t\t[shouldIgnore],\n\t);\n\n\tconst { anchor, clear } = useTextSelectionAsk({\n\t\tenabled,\n\t\tminLength,\n\t\tshouldIgnore: ignoreOwnSurfaces,\n\t});\n\n\tconst handleAsk = useCallback(() => {\n\t\tif (!anchor) {\n\t\t\treturn;\n\t\t}\n\t\tconst { text } = anchor;\n\t\t// Taking the highlight away is what dismisses the pill; the text now lives\n\t\t// wherever it was handed to.\n\t\tclear();\n\t\tonAsk?.(text);\n\t\tif (!usesCopilot) {\n\t\t\treturn;\n\t\t}\n\t\tsetAttachment(text);\n\t\tif (!isCopilotOpen) {\n\t\t\tsetCopilotOpen(true);\n\t\t}\n\t}, [anchor, clear, isCopilotOpen, onAsk, setCopilotOpen, usesCopilot]);\n\n\tconst handleAttachmentRemove = useCallback(() => setAttachment(null), []);\n\n\treturn (\n\t\t<>\n\t\t\t{usesCopilot && copilot && (\n\t\t\t\t/* A plain wrapper: the copilot's ball and panel are `position: fixed`,\n\t\t\t\t and a static div is not a containing block, so their placement is\n\t\t\t\t untouched. */\n\t\t\t\t<div {...{ [SELECTION_ASK_HOST_ATTRIBUTE]: 'true' }}>\n\t\t\t\t\t<BIKCopilot\n\t\t\t\t\t\t{...copilot}\n\t\t\t\t\t\topen={isCopilotOpen}\n\t\t\t\t\t\tonOpenChange={setCopilotOpen}\n\t\t\t\t\t\tattachment={attachment ?? undefined}\n\t\t\t\t\t\tonAttachmentRemove={handleAttachmentRemove}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{anchor && (\n\t\t\t\t<SelectionAskPill\n\t\t\t\t\tanchor={anchor}\n\t\t\t\t\tlabel={label}\n\t\t\t\t\tzIndex={zIndex ?? (copilot?.zIndex ?? 1200) + 2}\n\t\t\t\t\tonClick={handleAsk}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</>\n\t);\n};\n\nexport default TextSelectionAsk;\n"],"names":["SELECTION_ASK_HOST_ATTRIBUTE","TextSelectionAsk","enabled","target","copilot","onAsk","label","zIndex","minLength","shouldIgnore","attachment","setAttachment","useState","uncontrolledOpen","setUncontrolledOpen","usesCopilot","SELECTION_ASK_TARGET","isCopilotControlled","isCopilotOpen","setCopilotOpen","useCallback","next","ignoreOwnSurfaces","node","element","anchor","clear","useTextSelectionAsk","handleAsk","text","handleAttachmentRemove","jsxs","Fragment","jsx","BIKCopilot","SelectionAskPill"],"mappings":";;;;;;AAWO,MAAMA,IAA+B,+BA4B/BC,IAAoD,CAAC;AAAA,EACjE,SAAAC,IAAU;AAAA,EACV,QAAAC;AAAA,EACA,SAAAC;AAAA,EACA,OAAAC;AAAA,EACA,OAAAC;AAAA,EACA,QAAAC;AAAA,EACA,WAAAC;AAAA,EACA,cAAAC;AACD,MAAM;AAGL,QAAM,CAACC,GAAYC,CAAa,IAAIC,EAAwB,IAAI,GAC1D,CAACC,GAAkBC,CAAmB,IAAIF;AAAA,IAC/CR,GAAS,eAAe;AAAA,EAAA,GAGnBW,IACLZ,MAAWa,EAAqB,iBAAiB,EAAQZ,GAIpDa,IAAsBb,GAAS,SAAS,QACxCc,IAAgBD,IACnB,EAAQb,GAAS,OACjBS,GAEGM,IAAiBC;AAAA,IACtB,CAACC,MAAkB;AAClB,MAAKJ,KACJH,EAAoBO,CAAI,GAEzBjB,GAAS,eAAeiB,CAAI;AAAA,IAC7B;AAAA,IACA,CAACjB,GAASa,CAAmB;AAAA,EAAA,GAGxBK,IAAoBF;AAAA,IACzB,CAACG,MAAe;AACf,YAAMC,IAAUD,aAAgB,cAAcA,IAAOA,EAAK;AAC1D,aAAKC,IAGDA,EAAQ,QAAQ,IAAIxB,CAA4B,GAAG,IAC/C,KAEDS,IAAec,CAAI,KAAK,KALvB;AAAA,IAMT;AAAA,IACA,CAACd,CAAY;AAAA,EAAA,GAGR,EAAE,QAAAgB,GAAQ,OAAAC,EAAA,IAAUC,EAAoB;AAAA,IAC7C,SAAAzB;AAAA,IACA,WAAAM;AAAA,IACA,cAAcc;AAAA,EAAA,CACd,GAEKM,IAAYR,EAAY,MAAM;AACnC,QAAI,CAACK;AACJ;AAED,UAAM,EAAE,MAAAI,MAASJ;AAKjB,IAFAC,EAAA,GACArB,IAAQwB,CAAI,GACPd,MAGLJ,EAAckB,CAAI,GACbX,KACJC,EAAe,EAAI;AAAA,EAErB,GAAG,CAACM,GAAQC,GAAOR,GAAeb,GAAOc,GAAgBJ,CAAW,CAAC,GAE/De,IAAyBV,EAAY,MAAMT,EAAc,IAAI,GAAG,CAAA,CAAE;AAExE,SACC,gBAAAoB,EAAAC,GAAA,EACE,UAAA;AAAA,IAAAjB,KAAeX;AAAA;AAAA;AAAA,IAIf,gBAAA6B,EAAC,SAAU,CAACjC,CAA4B,GAAG,QAC1C,UAAA,gBAAAiC;AAAA,MAACC;AAAA,MAAA;AAAA,QACC,GAAG9B;AAAA,QACJ,MAAMc;AAAA,QACN,cAAcC;AAAA,QACd,YAAYT,KAAc;AAAA,QAC1B,oBAAoBoB;AAAA,MAAA;AAAA,IAAA,GAEtB;AAAA,IAGAL,KACA,gBAAAQ;AAAA,MAACE;AAAA,MAAA;AAAA,QACA,QAAAV;AAAA,QACA,OAAAnB;AAAA,QACA,QAAQC,MAAWH,GAAS,UAAU,QAAQ;AAAA,QAC9C,SAASwB;AAAA,MAAA;AAAA,IAAA;AAAA,EACV,GAEF;AAEF;"}
@@ -0,0 +1,7 @@
1
+ export { SelectionAskPill, getSelectionPillPosition } from './SelectionAskPill';
2
+ export { SELECTION_ASK_PILL_ATTRIBUTE } from './SelectionAskPill';
3
+ export { SELECTION_ASK_HOST_ATTRIBUTE, TextSelectionAsk, default as default, } from './TextSelectionAsk';
4
+ export { useTextSelectionAsk } from './useTextSelectionAsk';
5
+ export { MAX_SELECTION_LENGTH, MIN_SELECTION_LENGTH, normalizeSelection, } from './selectionText';
6
+ export { SELECTION_ASK_TARGET } from './model';
7
+ export type { SelectionAnchor, SelectionAskPillProps, SelectionAskTarget, SelectionRect, SelectionViewport, TextSelectionAskProps, UseTextSelectionAskOptions, UseTextSelectionAskResult, } from './model';
@@ -0,0 +1,112 @@
1
+ import { BIKCopilotProps } from '../bik-copilot/model';
2
+ /**
3
+ * Where an asked-about selection is sent.
4
+ *
5
+ * `COPILOT_AGENT` is the built-in destination: the component renders the BIK
6
+ * Copilot and hands the selection to it. Anything else a host wants to do with
7
+ * the text it does from `onAsk`.
8
+ */
9
+ export declare const SELECTION_ASK_TARGET: {
10
+ readonly COPILOT_AGENT: "COPILOT_AGENT";
11
+ };
12
+ export type SelectionAskTarget = (typeof SELECTION_ASK_TARGET)[keyof typeof SELECTION_ASK_TARGET];
13
+ /** Viewport the pill is clamped to. */
14
+ export interface SelectionViewport {
15
+ width: number;
16
+ height: number;
17
+ }
18
+ /**
19
+ * Where a selection sits in the viewport. Plain numbers rather than a live
20
+ * `DOMRect`, so the pill's placement can be worked out and tested without a
21
+ * layout engine.
22
+ */
23
+ export interface SelectionRect {
24
+ top: number;
25
+ left: number;
26
+ width: number;
27
+ height: number;
28
+ }
29
+ /** A selection worth offering the pill for, and where to put the pill. */
30
+ export interface SelectionAnchor {
31
+ /** The selected text, whitespace-collapsed and length-capped. */
32
+ text: string;
33
+ /** Bounding box of the selection, in viewport coordinates. */
34
+ rect: SelectionRect;
35
+ }
36
+ /** Options of `useTextSelectionAsk`. */
37
+ export interface UseTextSelectionAskOptions {
38
+ /**
39
+ * Whether selections are watched at all. `false` removes the listeners, so a
40
+ * host that does not want the pill pays nothing for it.
41
+ * @default true
42
+ */
43
+ enabled?: boolean;
44
+ /**
45
+ * Shortest selection that counts.
46
+ * @default 2
47
+ */
48
+ minLength?: number;
49
+ /**
50
+ * Selections inside a node this returns `true` for are ignored. Form fields
51
+ * are always ignored, whatever this returns.
52
+ */
53
+ shouldIgnore?: (node: Node) => boolean;
54
+ }
55
+ /** Return value of `useTextSelectionAsk`. */
56
+ export interface UseTextSelectionAskResult {
57
+ /** The current selection, or `null` when there is nothing to offer. */
58
+ anchor: SelectionAnchor | null;
59
+ /**
60
+ * Drops the anchor and collapses the DOM selection, so the highlight and the
61
+ * pill both go away. Call it once the selection has been taken somewhere.
62
+ */
63
+ clear: () => void;
64
+ }
65
+ /** Props of the pill offered next to a selection. */
66
+ export interface SelectionAskPillProps {
67
+ /** The selection the pill is offered for. */
68
+ anchor: SelectionAnchor;
69
+ /** @default 'Ask AI' */
70
+ label?: string;
71
+ /** Stacking order. Sits above whatever the destination renders. */
72
+ zIndex?: number;
73
+ /** Called when the pill is clicked. */
74
+ onClick: () => void;
75
+ /** Viewport the pill is clamped to. Defaults to the window's. */
76
+ viewport?: SelectionViewport;
77
+ }
78
+ /** Props of `TextSelectionAsk`. */
79
+ export interface TextSelectionAskProps extends Omit<UseTextSelectionAskOptions, 'enabled'> {
80
+ /**
81
+ * Watches the page for selections. `false` takes the pill away without
82
+ * unmounting the destination, so a copilot stays where it is.
83
+ * @default true
84
+ */
85
+ enabled?: boolean;
86
+ /**
87
+ * Where the selection goes. `COPILOT_AGENT` renders the BIK Copilot from
88
+ * `copilot` and attaches the selection above its input. Leave it unset to
89
+ * handle the text yourself in `onAsk`.
90
+ */
91
+ target?: SelectionAskTarget;
92
+ /**
93
+ * Props for the copilot rendered when `target` is `COPILOT_AGENT`. Passed
94
+ * through untouched, so everything `BIKCopilot` takes works here.
95
+ */
96
+ copilot?: BIKCopilotProps;
97
+ /**
98
+ * Called with the selected text whenever the pill is clicked, whatever the
99
+ * target. The only way to receive the selection when there is no target.
100
+ */
101
+ onAsk?: (selection: string) => void;
102
+ /**
103
+ * Label on the pill.
104
+ * @default 'Ask AI'
105
+ */
106
+ label?: string;
107
+ /**
108
+ * Stacking order of the pill. The copilot is rendered at its own `zIndex`,
109
+ * and the pill is placed above it.
110
+ */
111
+ zIndex?: number;
112
+ }
@@ -0,0 +1,7 @@
1
+ const T = {
2
+ COPILOT_AGENT: "COPILOT_AGENT"
3
+ };
4
+ export {
5
+ T as SELECTION_ASK_TARGET
6
+ };
7
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","sources":["../../../../src/components/text-selection-ask/model.ts"],"sourcesContent":["import { BIKCopilotProps } from '../bik-copilot/model';\n\n/**\n * Where an asked-about selection is sent.\n *\n * `COPILOT_AGENT` is the built-in destination: the component renders the BIK\n * Copilot and hands the selection to it. Anything else a host wants to do with\n * the text it does from `onAsk`.\n */\nexport const SELECTION_ASK_TARGET = {\n\tCOPILOT_AGENT: 'COPILOT_AGENT',\n} as const;\n\nexport type SelectionAskTarget =\n\t(typeof SELECTION_ASK_TARGET)[keyof typeof SELECTION_ASK_TARGET];\n\n/** Viewport the pill is clamped to. */\nexport interface SelectionViewport {\n\twidth: number;\n\theight: number;\n}\n\n/**\n * Where a selection sits in the viewport. Plain numbers rather than a live\n * `DOMRect`, so the pill's placement can be worked out and tested without a\n * layout engine.\n */\nexport interface SelectionRect {\n\ttop: number;\n\tleft: number;\n\twidth: number;\n\theight: number;\n}\n\n/** A selection worth offering the pill for, and where to put the pill. */\nexport interface SelectionAnchor {\n\t/** The selected text, whitespace-collapsed and length-capped. */\n\ttext: string;\n\t/** Bounding box of the selection, in viewport coordinates. */\n\trect: SelectionRect;\n}\n\n/** Options of `useTextSelectionAsk`. */\nexport interface UseTextSelectionAskOptions {\n\t/**\n\t * Whether selections are watched at all. `false` removes the listeners, so a\n\t * host that does not want the pill pays nothing for it.\n\t * @default true\n\t */\n\tenabled?: boolean;\n\n\t/**\n\t * Shortest selection that counts.\n\t * @default 2\n\t */\n\tminLength?: number;\n\n\t/**\n\t * Selections inside a node this returns `true` for are ignored. Form fields\n\t * are always ignored, whatever this returns.\n\t */\n\tshouldIgnore?: (node: Node) => boolean;\n}\n\n/** Return value of `useTextSelectionAsk`. */\nexport interface UseTextSelectionAskResult {\n\t/** The current selection, or `null` when there is nothing to offer. */\n\tanchor: SelectionAnchor | null;\n\n\t/**\n\t * Drops the anchor and collapses the DOM selection, so the highlight and the\n\t * pill both go away. Call it once the selection has been taken somewhere.\n\t */\n\tclear: () => void;\n}\n\n/** Props of the pill offered next to a selection. */\nexport interface SelectionAskPillProps {\n\t/** The selection the pill is offered for. */\n\tanchor: SelectionAnchor;\n\n\t/** @default 'Ask AI' */\n\tlabel?: string;\n\n\t/** Stacking order. Sits above whatever the destination renders. */\n\tzIndex?: number;\n\n\t/** Called when the pill is clicked. */\n\tonClick: () => void;\n\n\t/** Viewport the pill is clamped to. Defaults to the window's. */\n\tviewport?: SelectionViewport;\n}\n\n/** Props of `TextSelectionAsk`. */\nexport interface TextSelectionAskProps\n\textends Omit<UseTextSelectionAskOptions, 'enabled'> {\n\t/**\n\t * Watches the page for selections. `false` takes the pill away without\n\t * unmounting the destination, so a copilot stays where it is.\n\t * @default true\n\t */\n\tenabled?: boolean;\n\n\t/**\n\t * Where the selection goes. `COPILOT_AGENT` renders the BIK Copilot from\n\t * `copilot` and attaches the selection above its input. Leave it unset to\n\t * handle the text yourself in `onAsk`.\n\t */\n\ttarget?: SelectionAskTarget;\n\n\t/**\n\t * Props for the copilot rendered when `target` is `COPILOT_AGENT`. Passed\n\t * through untouched, so everything `BIKCopilot` takes works here.\n\t */\n\tcopilot?: BIKCopilotProps;\n\n\t/**\n\t * Called with the selected text whenever the pill is clicked, whatever the\n\t * target. The only way to receive the selection when there is no target.\n\t */\n\tonAsk?: (selection: string) => void;\n\n\t/**\n\t * Label on the pill.\n\t * @default 'Ask AI'\n\t */\n\tlabel?: string;\n\n\t/**\n\t * Stacking order of the pill. The copilot is rendered at its own `zIndex`,\n\t * and the pill is placed above it.\n\t */\n\tzIndex?: number;\n}\n"],"names":["SELECTION_ASK_TARGET"],"mappings":"AASO,MAAMA,IAAuB;AAAA,EACnC,eAAe;AAChB;"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Shortest selection the pill is offered for. A stray click that lands one
3
+ * character inside a word is not a question anybody meant to ask.
4
+ */
5
+ export declare const MIN_SELECTION_LENGTH = 2;
6
+ /**
7
+ * Longest selection carried out of the page. Consumers put the text into a
8
+ * prompt, so an accidental select-all must not become the whole request.
9
+ */
10
+ export declare const MAX_SELECTION_LENGTH = 1000;
11
+ /**
12
+ * Collapses the whitespace a DOM selection picks up and caps its length.
13
+ *
14
+ * Dragging across a table or a stat card pulls in the newlines and indentation
15
+ * between the cells, so the raw string is unusable both as a chip label and as
16
+ * part of a prompt.
17
+ */
18
+ export declare const normalizeSelection: (text: string) => string;
@@ -0,0 +1,7 @@
1
+ const e = 2, N = 1e3, c = (E) => E.replace(/\s+/g, " ").trim().slice(0, 1e3);
2
+ export {
3
+ N as MAX_SELECTION_LENGTH,
4
+ e as MIN_SELECTION_LENGTH,
5
+ c as normalizeSelection
6
+ };
7
+ //# sourceMappingURL=selectionText.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectionText.js","sources":["../../../../src/components/text-selection-ask/selectionText.ts"],"sourcesContent":["/**\n * Shortest selection the pill is offered for. A stray click that lands one\n * character inside a word is not a question anybody meant to ask.\n */\nexport const MIN_SELECTION_LENGTH = 2;\n\n/**\n * Longest selection carried out of the page. Consumers put the text into a\n * prompt, so an accidental select-all must not become the whole request.\n */\nexport const MAX_SELECTION_LENGTH = 1000;\n\n/**\n * Collapses the whitespace a DOM selection picks up and caps its length.\n *\n * Dragging across a table or a stat card pulls in the newlines and indentation\n * between the cells, so the raw string is unusable both as a chip label and as\n * part of a prompt.\n */\nexport const normalizeSelection = (text: string): string =>\n\ttext.replace(/\\s+/g, ' ').trim().slice(0, MAX_SELECTION_LENGTH);\n"],"names":["MIN_SELECTION_LENGTH","MAX_SELECTION_LENGTH","normalizeSelection","text"],"mappings":"AAIO,MAAMA,IAAuB,GAMvBC,IAAuB,KASvBC,IAAqB,CAACC,MAClCA,EAAK,QAAQ,QAAQ,GAAG,EAAE,KAAA,EAAO,MAAM,GAAG,GAAoB;"}
@@ -0,0 +1,15 @@
1
+ import { UseTextSelectionAskOptions, UseTextSelectionAskResult } from './model';
2
+ /**
3
+ * Watches the page for a text selection worth asking about.
4
+ *
5
+ * Selections are read on pointer and key release rather than from
6
+ * `selectionchange` alone: that event fires on every mouse move of a drag, so
7
+ * anchoring to it would have the pill chasing the cursor. `selectionchange` is
8
+ * still listened to, for the other direction — a click that collapses the
9
+ * selection has to take the pill away immediately.
10
+ *
11
+ * The anchor's rect is in viewport coordinates and is recomputed on scroll and
12
+ * resize, so a `position: fixed` pill keeps up with the text it points at.
13
+ */
14
+ export declare const useTextSelectionAsk: ({ enabled, minLength, shouldIgnore, }?: UseTextSelectionAskOptions) => UseTextSelectionAskResult;
15
+ export default useTextSelectionAsk;
@@ -0,0 +1,53 @@
1
+ import { useState as E, useCallback as g, useEffect as h } from "react";
2
+ import { MIN_SELECTION_LENGTH as v, normalizeSelection as w } from "./selectionText.js";
3
+ const p = (t) => t ? t instanceof HTMLElement ? t : t.parentElement : null, L = (t) => {
4
+ const o = p(t);
5
+ return o ? o.isContentEditable ? !0 : !!o.closest("input, textarea, select, [contenteditable]") : !1;
6
+ }, A = ({
7
+ enabled: t = !0,
8
+ minLength: o = v,
9
+ shouldIgnore: s
10
+ } = {}) => {
11
+ const [d, i] = E(null), m = g(() => {
12
+ i(null), window.getSelection()?.removeAllRanges();
13
+ }, []);
14
+ return h(() => {
15
+ if (!t) {
16
+ i(null);
17
+ return;
18
+ }
19
+ const f = () => {
20
+ const e = window.getSelection();
21
+ if (!e || e.isCollapsed || e.rangeCount === 0)
22
+ return null;
23
+ const a = w(e.toString());
24
+ if (a.length < o)
25
+ return null;
26
+ const l = e.getRangeAt(0);
27
+ if (L(l.commonAncestorContainer) || s?.(l.commonAncestorContainer))
28
+ return null;
29
+ const r = l.getBoundingClientRect();
30
+ return r.width === 0 && r.height === 0 ? null : {
31
+ text: a,
32
+ rect: {
33
+ top: r.top,
34
+ left: r.left,
35
+ width: r.width,
36
+ height: r.height
37
+ }
38
+ };
39
+ }, n = () => i(f()), c = () => {
40
+ const e = window.getSelection();
41
+ (!e || e.isCollapsed) && i(null);
42
+ }, u = (e) => {
43
+ (e.shiftKey || e.key === "Shift") && n();
44
+ };
45
+ return document.addEventListener("pointerup", n), document.addEventListener("keyup", u), document.addEventListener("selectionchange", c), window.addEventListener("scroll", n, !0), window.addEventListener("resize", n), () => {
46
+ document.removeEventListener("pointerup", n), document.removeEventListener("keyup", u), document.removeEventListener("selectionchange", c), window.removeEventListener("scroll", n, !0), window.removeEventListener("resize", n);
47
+ };
48
+ }, [t, o, s]), { anchor: d, clear: m };
49
+ };
50
+ export {
51
+ A as useTextSelectionAsk
52
+ };
53
+ //# sourceMappingURL=useTextSelectionAsk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTextSelectionAsk.js","sources":["../../../../src/components/text-selection-ask/useTextSelectionAsk.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\nimport {\n\tSelectionAnchor,\n\tUseTextSelectionAskOptions,\n\tUseTextSelectionAskResult,\n} from './model';\nimport { MIN_SELECTION_LENGTH, normalizeSelection } from './selectionText';\n\nconst asElement = (node: Node | null): HTMLElement | null => {\n\tif (!node) {\n\t\treturn null;\n\t}\n\treturn node instanceof HTMLElement ? node : node.parentElement;\n};\n\n/**\n * Whether the selection is being made inside something the user is typing in.\n * Text they are editing is not text they are asking about, and a pill over a\n * form field would fight the field's own selection handles.\n */\nconst isEditableTarget = (node: Node | null): boolean => {\n\tconst element = asElement(node);\n\tif (!element) {\n\t\treturn false;\n\t}\n\tif (element.isContentEditable) {\n\t\treturn true;\n\t}\n\treturn Boolean(element.closest('input, textarea, select, [contenteditable]'));\n};\n\n/**\n * Watches the page for a text selection worth asking about.\n *\n * Selections are read on pointer and key release rather than from\n * `selectionchange` alone: that event fires on every mouse move of a drag, so\n * anchoring to it would have the pill chasing the cursor. `selectionchange` is\n * still listened to, for the other direction — a click that collapses the\n * selection has to take the pill away immediately.\n *\n * The anchor's rect is in viewport coordinates and is recomputed on scroll and\n * resize, so a `position: fixed` pill keeps up with the text it points at.\n */\nexport const useTextSelectionAsk = ({\n\tenabled = true,\n\tminLength = MIN_SELECTION_LENGTH,\n\tshouldIgnore,\n}: UseTextSelectionAskOptions = {}): UseTextSelectionAskResult => {\n\tconst [anchor, setAnchor] = useState<SelectionAnchor | null>(null);\n\n\tconst clear = useCallback(() => {\n\t\tsetAnchor(null);\n\t\t// Collapsing the range as well is what stops the pill coming back: the\n\t\t// selection it was offered for no longer exists, so nothing re-reads it.\n\t\twindow.getSelection()?.removeAllRanges();\n\t}, []);\n\n\tuseEffect(() => {\n\t\tif (!enabled) {\n\t\t\t// Leaving a stale anchor behind would keep a pill on screen that the\n\t\t\t// host has just turned off.\n\t\t\tsetAnchor(null);\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst readSelection = (): SelectionAnchor | null => {\n\t\t\tconst selection = window.getSelection();\n\t\t\tif (!selection || selection.isCollapsed || selection.rangeCount === 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst text = normalizeSelection(selection.toString());\n\t\t\tif (text.length < minLength) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst range = selection.getRangeAt(0);\n\t\t\tif (\n\t\t\t\tisEditableTarget(range.commonAncestorContainer) ||\n\t\t\t\tshouldIgnore?.(range.commonAncestorContainer)\n\t\t\t) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst rect = range.getBoundingClientRect();\n\t\t\t// A range inside a hidden or zero-sized node has nowhere to put a pill.\n\t\t\tif (rect.width === 0 && rect.height === 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttext,\n\t\t\t\trect: {\n\t\t\t\t\ttop: rect.top,\n\t\t\t\t\tleft: rect.left,\n\t\t\t\t\twidth: rect.width,\n\t\t\t\t\theight: rect.height,\n\t\t\t\t},\n\t\t\t};\n\t\t};\n\n\t\tconst evaluate = () => setAnchor(readSelection());\n\n\t\tconst handleSelectionChange = () => {\n\t\t\tconst selection = window.getSelection();\n\t\t\tif (!selection || selection.isCollapsed) {\n\t\t\t\tsetAnchor(null);\n\t\t\t}\n\t\t};\n\n\t\tconst handleKeyUp = (event: KeyboardEvent) => {\n\t\t\t// Only the gestures that extend a selection; every other keystroke\n\t\t\t// would just re-read the same range.\n\t\t\tif (event.shiftKey || event.key === 'Shift') {\n\t\t\t\tevaluate();\n\t\t\t}\n\t\t};\n\n\t\tdocument.addEventListener('pointerup', evaluate);\n\t\tdocument.addEventListener('keyup', handleKeyUp);\n\t\tdocument.addEventListener('selectionchange', handleSelectionChange);\n\t\t// Capture, so a selection inside a scrollable table is followed too and not\n\t\t// only the page's own scrolling.\n\t\twindow.addEventListener('scroll', evaluate, true);\n\t\twindow.addEventListener('resize', evaluate);\n\n\t\treturn () => {\n\t\t\tdocument.removeEventListener('pointerup', evaluate);\n\t\t\tdocument.removeEventListener('keyup', handleKeyUp);\n\t\t\tdocument.removeEventListener('selectionchange', handleSelectionChange);\n\t\t\twindow.removeEventListener('scroll', evaluate, true);\n\t\t\twindow.removeEventListener('resize', evaluate);\n\t\t};\n\t}, [enabled, minLength, shouldIgnore]);\n\n\treturn { anchor, clear };\n};\n\nexport default useTextSelectionAsk;\n"],"names":["asElement","node","isEditableTarget","element","useTextSelectionAsk","enabled","minLength","MIN_SELECTION_LENGTH","shouldIgnore","anchor","setAnchor","useState","clear","useCallback","useEffect","readSelection","selection","text","normalizeSelection","range","rect","evaluate","handleSelectionChange","handleKeyUp","event"],"mappings":";;AAQA,MAAMA,IAAY,CAACC,MACbA,IAGEA,aAAgB,cAAcA,IAAOA,EAAK,gBAFzC,MAUHC,IAAmB,CAACD,MAA+B;AACxD,QAAME,IAAUH,EAAUC,CAAI;AAC9B,SAAKE,IAGDA,EAAQ,oBACJ,KAED,EAAQA,EAAQ,QAAQ,4CAA4C,IALnE;AAMT,GAcaC,IAAsB,CAAC;AAAA,EACnC,SAAAC,IAAU;AAAA,EACV,WAAAC,IAAYC;AAAA,EACZ,cAAAC;AACD,IAAgC,OAAkC;AACjE,QAAM,CAACC,GAAQC,CAAS,IAAIC,EAAiC,IAAI,GAE3DC,IAAQC,EAAY,MAAM;AAC/B,IAAAH,EAAU,IAAI,GAGd,OAAO,aAAA,GAAgB,gBAAA;AAAA,EACxB,GAAG,CAAA,CAAE;AAEL,SAAAI,EAAU,MAAM;AACf,QAAI,CAACT,GAAS;AAGb,MAAAK,EAAU,IAAI;AACd;AAAA,IACD;AAEA,UAAMK,IAAgB,MAA8B;AACnD,YAAMC,IAAY,OAAO,aAAA;AACzB,UAAI,CAACA,KAAaA,EAAU,eAAeA,EAAU,eAAe;AACnE,eAAO;AAGR,YAAMC,IAAOC,EAAmBF,EAAU,SAAA,CAAU;AACpD,UAAIC,EAAK,SAASX;AACjB,eAAO;AAGR,YAAMa,IAAQH,EAAU,WAAW,CAAC;AACpC,UACCd,EAAiBiB,EAAM,uBAAuB,KAC9CX,IAAeW,EAAM,uBAAuB;AAE5C,eAAO;AAGR,YAAMC,IAAOD,EAAM,sBAAA;AAEnB,aAAIC,EAAK,UAAU,KAAKA,EAAK,WAAW,IAChC,OAGD;AAAA,QACN,MAAAH;AAAA,QACA,MAAM;AAAA,UACL,KAAKG,EAAK;AAAA,UACV,MAAMA,EAAK;AAAA,UACX,OAAOA,EAAK;AAAA,UACZ,QAAQA,EAAK;AAAA,QAAA;AAAA,MACd;AAAA,IAEF,GAEMC,IAAW,MAAMX,EAAUK,GAAe,GAE1CO,IAAwB,MAAM;AACnC,YAAMN,IAAY,OAAO,aAAA;AACzB,OAAI,CAACA,KAAaA,EAAU,gBAC3BN,EAAU,IAAI;AAAA,IAEhB,GAEMa,IAAc,CAACC,MAAyB;AAG7C,OAAIA,EAAM,YAAYA,EAAM,QAAQ,YACnCH,EAAA;AAAA,IAEF;AAEA,oBAAS,iBAAiB,aAAaA,CAAQ,GAC/C,SAAS,iBAAiB,SAASE,CAAW,GAC9C,SAAS,iBAAiB,mBAAmBD,CAAqB,GAGlE,OAAO,iBAAiB,UAAUD,GAAU,EAAI,GAChD,OAAO,iBAAiB,UAAUA,CAAQ,GAEnC,MAAM;AACZ,eAAS,oBAAoB,aAAaA,CAAQ,GAClD,SAAS,oBAAoB,SAASE,CAAW,GACjD,SAAS,oBAAoB,mBAAmBD,CAAqB,GACrE,OAAO,oBAAoB,UAAUD,GAAU,EAAI,GACnD,OAAO,oBAAoB,UAAUA,CAAQ;AAAA,IAC9C;AAAA,EACD,GAAG,CAAChB,GAASC,GAAWE,CAAY,CAAC,GAE9B,EAAE,QAAAC,GAAQ,OAAAG,EAAA;AAClB;"}
@@ -0,0 +1,7 @@
1
+ import { SVGProps } from 'react';
2
+ interface Props extends SVGProps<SVGSVGElement> {
3
+ size?: number | string;
4
+ color?: string;
5
+ }
6
+ declare const SvgSquaresFour: ({ size, color, ...rest }: Props) => import("react/jsx-runtime").JSX.Element;
7
+ export default SvgSquaresFour;
@@ -0,0 +1,33 @@
1
+ import { jsx as r } from "react/jsx-runtime";
2
+ const e = ({
3
+ size: C = 24,
4
+ color: H = "currentColor",
5
+ ...V
6
+ }) => {
7
+ const o = {
8
+ width: C,
9
+ height: C,
10
+ color: H,
11
+ ...V
12
+ };
13
+ return /* @__PURE__ */ r(
14
+ "svg",
15
+ {
16
+ viewBox: "0 0 16 16",
17
+ fill: "none",
18
+ xmlns: "http://www.w3.org/2000/svg",
19
+ ...o,
20
+ children: /* @__PURE__ */ r(
21
+ "path",
22
+ {
23
+ d: "M6.36364 2H3.09091C2.80158 2 2.5241 2.11493 2.31952 2.31952C2.11493 2.5241 2 2.80158 2 3.09091V6.36364C2 6.65296 2.11493 6.93044 2.31952 7.13503C2.5241 7.33961 2.80158 7.45455 3.09091 7.45455H6.36364C6.65296 7.45455 6.93044 7.33961 7.13503 7.13503C7.33961 6.93044 7.45455 6.65296 7.45455 6.36364V3.09091C7.45455 2.80158 7.33961 2.5241 7.13503 2.31952C6.93044 2.11493 6.65296 2 6.36364 2ZM6.36364 6.36364H3.09091V3.09091H6.36364V6.36364ZM12.9091 2H9.63636C9.34704 2 9.06956 2.11493 8.86497 2.31952C8.66039 2.5241 8.54545 2.80158 8.54545 3.09091V6.36364C8.54545 6.65296 8.66039 6.93044 8.86497 7.13503C9.06956 7.33961 9.34704 7.45455 9.63636 7.45455H12.9091C13.1984 7.45455 13.4759 7.33961 13.6805 7.13503C13.8851 6.93044 14 6.65296 14 6.36364V3.09091C14 2.80158 13.8851 2.5241 13.6805 2.31952C13.4759 2.11493 13.1984 2 12.9091 2ZM12.9091 6.36364H9.63636V3.09091H12.9091V6.36364ZM6.36364 8.54545H3.09091C2.80158 8.54545 2.5241 8.66039 2.31952 8.86497C2.11493 9.06956 2 9.34704 2 9.63636V12.9091C2 13.1984 2.11493 13.4759 2.31952 13.6805C2.5241 13.8851 2.80158 14 3.09091 14H6.36364C6.65296 14 6.93044 13.8851 7.13503 13.6805C7.33961 13.4759 7.45455 13.1984 7.45455 12.9091V9.63636C7.45455 9.34704 7.33961 9.06956 7.13503 8.86497C6.93044 8.66039 6.65296 8.54545 6.36364 8.54545ZM6.36364 12.9091H3.09091V9.63636H6.36364V12.9091ZM12.9091 8.54545H9.63636C9.34704 8.54545 9.06956 8.66039 8.86497 8.86497C8.66039 9.06956 8.54545 9.34704 8.54545 9.63636V12.9091C8.54545 13.1984 8.66039 13.4759 8.86497 13.6805C9.06956 13.8851 9.34704 14 9.63636 14H12.9091C13.1984 14 13.4759 13.8851 13.6805 13.6805C13.8851 13.4759 14 13.1984 14 12.9091V9.63636C14 9.34704 13.8851 9.06956 13.6805 8.86497C13.4759 8.66039 13.1984 8.54545 12.9091 8.54545ZM12.9091 12.9091H9.63636V9.63636H12.9091V12.9091Z",
24
+ fill: "currentColor"
25
+ }
26
+ )
27
+ }
28
+ );
29
+ };
30
+ export {
31
+ e as default
32
+ };
33
+ //# sourceMappingURL=SquaresFour.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SquaresFour.js","sources":["../../../../../src/icons/Informational/Common UI/SquaresFour.tsx"],"sourcesContent":["import type { SVGProps } from 'react';\n\ninterface Props extends SVGProps<SVGSVGElement> {\n\tsize?: number | string;\n\tcolor?: string;\n}\nconst SvgSquaresFour = ({\n\tsize = 24,\n\tcolor = 'currentColor',\n\t...rest\n}: Props) => {\n\tconst props = {\n\t\twidth: size,\n\t\theight: size,\n\t\tcolor,\n\t\t...rest,\n\t};\n\treturn (\n\t\t<svg\n\t\t\tviewBox=\"0 0 16 16\"\n\t\t\tfill=\"none\"\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<path\n\t\t\t\td=\"M6.36364 2H3.09091C2.80158 2 2.5241 2.11493 2.31952 2.31952C2.11493 2.5241 2 2.80158 2 3.09091V6.36364C2 6.65296 2.11493 6.93044 2.31952 7.13503C2.5241 7.33961 2.80158 7.45455 3.09091 7.45455H6.36364C6.65296 7.45455 6.93044 7.33961 7.13503 7.13503C7.33961 6.93044 7.45455 6.65296 7.45455 6.36364V3.09091C7.45455 2.80158 7.33961 2.5241 7.13503 2.31952C6.93044 2.11493 6.65296 2 6.36364 2ZM6.36364 6.36364H3.09091V3.09091H6.36364V6.36364ZM12.9091 2H9.63636C9.34704 2 9.06956 2.11493 8.86497 2.31952C8.66039 2.5241 8.54545 2.80158 8.54545 3.09091V6.36364C8.54545 6.65296 8.66039 6.93044 8.86497 7.13503C9.06956 7.33961 9.34704 7.45455 9.63636 7.45455H12.9091C13.1984 7.45455 13.4759 7.33961 13.6805 7.13503C13.8851 6.93044 14 6.65296 14 6.36364V3.09091C14 2.80158 13.8851 2.5241 13.6805 2.31952C13.4759 2.11493 13.1984 2 12.9091 2ZM12.9091 6.36364H9.63636V3.09091H12.9091V6.36364ZM6.36364 8.54545H3.09091C2.80158 8.54545 2.5241 8.66039 2.31952 8.86497C2.11493 9.06956 2 9.34704 2 9.63636V12.9091C2 13.1984 2.11493 13.4759 2.31952 13.6805C2.5241 13.8851 2.80158 14 3.09091 14H6.36364C6.65296 14 6.93044 13.8851 7.13503 13.6805C7.33961 13.4759 7.45455 13.1984 7.45455 12.9091V9.63636C7.45455 9.34704 7.33961 9.06956 7.13503 8.86497C6.93044 8.66039 6.65296 8.54545 6.36364 8.54545ZM6.36364 12.9091H3.09091V9.63636H6.36364V12.9091ZM12.9091 8.54545H9.63636C9.34704 8.54545 9.06956 8.66039 8.86497 8.86497C8.66039 9.06956 8.54545 9.34704 8.54545 9.63636V12.9091C8.54545 13.1984 8.66039 13.4759 8.86497 13.6805C9.06956 13.8851 9.34704 14 9.63636 14H12.9091C13.1984 14 13.4759 13.8851 13.6805 13.6805C13.8851 13.4759 14 13.1984 14 12.9091V9.63636C14 9.34704 13.8851 9.06956 13.6805 8.86497C13.4759 8.66039 13.1984 8.54545 12.9091 8.54545ZM12.9091 12.9091H9.63636V9.63636H12.9091V12.9091Z\"\n\t\t\t\tfill=\"currentColor\"\n\t\t\t/>\n\t\t</svg>\n\t);\n};\nexport default SvgSquaresFour;\n"],"names":["SvgSquaresFour","size","color","rest","props","jsx"],"mappings":";AAMA,MAAMA,IAAiB,CAAC;AAAA,EACvB,MAAAC,IAAO;AAAA,EACP,OAAAC,IAAQ;AAAA,EACR,GAAGC;AACJ,MAAa;AACZ,QAAMC,IAAQ;AAAA,IACb,OAAOH;AAAA,IACP,QAAQA;AAAA,IACR,OAAAC;AAAA,IACA,GAAGC;AAAA,EAAA;AAEJ,SACC,gBAAAE;AAAA,IAAC;AAAA,IAAA;AAAA,MACA,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAM;AAAA,MACL,GAAGD;AAAA,MAEJ,UAAA,gBAAAC;AAAA,QAAC;AAAA,QAAA;AAAA,UACA,GAAE;AAAA,UACF,MAAK;AAAA,QAAA;AAAA,MAAA;AAAA,IACN;AAAA,EAAA;AAGH;"}
@@ -1,5 +1,6 @@
1
1
  export { default as Shield } from './Shield';
2
2
  export { default as ShieldOutline } from './ShieldOutline';
3
+ export { default as SquaresFour } from './SquaresFour';
3
4
  export { default as Bell } from './Bell';
4
5
  export { default as BellSync } from './BellSync';
5
6
  export { default as Bulb } from './Bulb';