@flamingo-stack/openframe-frontend-core 0.0.670 → 0.0.671-snapshot.20260928023432

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 (116) hide show
  1. package/dist/chat-protocol/card-marker.d.ts +12 -0
  2. package/dist/chat-protocol/card-marker.d.ts.map +1 -1
  3. package/dist/chat-protocol/index.cjs +17 -0
  4. package/dist/chat-protocol/index.cjs.map +1 -1
  5. package/dist/chat-protocol/index.d.ts +1 -0
  6. package/dist/chat-protocol/index.d.ts.map +1 -1
  7. package/dist/chat-protocol/index.js +15 -1
  8. package/dist/chat-protocol/index.js.map +1 -1
  9. package/dist/{chunk-FUXUJSPP.cjs → chunk-3UDBK2YG.cjs} +1 -1
  10. package/dist/chunk-3UDBK2YG.cjs.map +1 -0
  11. package/dist/{chunk-X4JE3QHN.js → chunk-42OVTTOM.js} +4 -2
  12. package/dist/{chunk-X4JE3QHN.js.map → chunk-42OVTTOM.js.map} +1 -1
  13. package/dist/{chunk-BRGO4IEB.js → chunk-4AZWVS7F.js} +6 -6
  14. package/dist/{chunk-7BOZ3CRQ.js → chunk-6S2KLT7O.js} +4 -4
  15. package/dist/{chunk-R4NCUO7Y.js → chunk-7KM34VWL.js} +2 -2
  16. package/dist/{chunk-IO3EXNLR.js → chunk-AL4I5HHB.js} +5 -5
  17. package/dist/{chunk-YCEVKQHL.cjs → chunk-BODMICIH.cjs} +45 -45
  18. package/dist/{chunk-YCEVKQHL.cjs.map → chunk-BODMICIH.cjs.map} +1 -1
  19. package/dist/{chunk-4RJ5M6EJ.cjs → chunk-CBCETEB4.cjs} +10 -10
  20. package/dist/{chunk-4RJ5M6EJ.cjs.map → chunk-CBCETEB4.cjs.map} +1 -1
  21. package/dist/{chunk-U7UVD2D2.js → chunk-EKABOXNB.js} +3 -3
  22. package/dist/{chunk-6CEXIIVF.cjs → chunk-GV7R2NTS.cjs} +26 -26
  23. package/dist/{chunk-6CEXIIVF.cjs.map → chunk-GV7R2NTS.cjs.map} +1 -1
  24. package/dist/{chunk-DFM7NCZR.cjs → chunk-H54F476P.cjs} +3 -3
  25. package/dist/{chunk-DFM7NCZR.cjs.map → chunk-H54F476P.cjs.map} +1 -1
  26. package/dist/{chunk-57QY7D22.cjs → chunk-HOEVEB7N.cjs} +22 -22
  27. package/dist/{chunk-57QY7D22.cjs.map → chunk-HOEVEB7N.cjs.map} +1 -1
  28. package/dist/{chunk-BQUWZQF6.cjs → chunk-HVEX4BSC.cjs} +540 -538
  29. package/dist/chunk-HVEX4BSC.cjs.map +1 -0
  30. package/dist/{chunk-DQVEL4YO.js → chunk-IBGHJLNT.js} +2 -2
  31. package/dist/{chunk-TLLTL6LB.js → chunk-JD4U7QMG.js} +1 -1
  32. package/dist/chunk-JD4U7QMG.js.map +1 -0
  33. package/dist/{chunk-NGMOFWQL.cjs → chunk-JREG4T6K.cjs} +10 -10
  34. package/dist/{chunk-NGMOFWQL.cjs.map → chunk-JREG4T6K.cjs.map} +1 -1
  35. package/dist/{chunk-BP52HUNB.js → chunk-KSBDARII.js} +5 -5
  36. package/dist/{chunk-BUPLBCTW.cjs → chunk-NETIHUEY.cjs} +10 -10
  37. package/dist/{chunk-BUPLBCTW.cjs.map → chunk-NETIHUEY.cjs.map} +1 -1
  38. package/dist/{chunk-7A6EJEL5.js → chunk-O5PYXQ6H.js} +3 -3
  39. package/dist/{chunk-S25GQVXN.cjs → chunk-PSL2WBEO.cjs} +33 -33
  40. package/dist/{chunk-S25GQVXN.cjs.map → chunk-PSL2WBEO.cjs.map} +1 -1
  41. package/dist/{chunk-QSUYGCBR.js → chunk-PWPYCJ33.js} +2 -2
  42. package/dist/{chunk-NTZGJZZS.cjs → chunk-RD3I5PBB.cjs} +15 -15
  43. package/dist/{chunk-NTZGJZZS.cjs.map → chunk-RD3I5PBB.cjs.map} +1 -1
  44. package/dist/{chunk-P4H2NRQB.cjs → chunk-SNWAN52K.cjs} +5 -5
  45. package/dist/{chunk-P4H2NRQB.cjs.map → chunk-SNWAN52K.cjs.map} +1 -1
  46. package/dist/{chunk-QZGGA47F.js → chunk-T3KXCOB2.js} +2 -2
  47. package/dist/{chunk-RLVSORQW.js → chunk-TFSGYKWG.js} +3 -3
  48. package/dist/{chunk-BZ6RAT7K.js → chunk-TQPKNG2E.js} +3 -3
  49. package/dist/{chunk-CTVFAT6X.cjs → chunk-UOQRNZIB.cjs} +22 -22
  50. package/dist/{chunk-CTVFAT6X.cjs.map → chunk-UOQRNZIB.cjs.map} +1 -1
  51. package/dist/{chunk-K77Z3E4Y.cjs → chunk-UUOBCUHW.cjs} +3 -3
  52. package/dist/{chunk-K77Z3E4Y.cjs.map → chunk-UUOBCUHW.cjs.map} +1 -1
  53. package/dist/{chunk-LC4U5JGM.cjs → chunk-VZRVQEMT.cjs} +4 -4
  54. package/dist/{chunk-LC4U5JGM.cjs.map → chunk-VZRVQEMT.cjs.map} +1 -1
  55. package/dist/{chunk-K6WL2OWX.js → chunk-XDTU23P4.js} +3 -3
  56. package/dist/{chunk-7YZZJYJN.cjs → chunk-XLJNYTUW.cjs} +71 -71
  57. package/dist/{chunk-7YZZJYJN.cjs.map → chunk-XLJNYTUW.cjs.map} +1 -1
  58. package/dist/{chunk-JB44GMRU.js → chunk-Z6E45TJM.js} +5 -5
  59. package/dist/components/case-studies/index.cjs +14 -14
  60. package/dist/components/case-studies/index.js +3 -3
  61. package/dist/components/chat/index.cjs +2 -2
  62. package/dist/components/chat/index.js +1 -1
  63. package/dist/components/contact/index.cjs +4 -4
  64. package/dist/components/contact/index.js +3 -3
  65. package/dist/components/docs/index.cjs +7 -7
  66. package/dist/components/docs/index.js +6 -6
  67. package/dist/components/embeds/index.cjs +4 -4
  68. package/dist/components/embeds/index.js +3 -3
  69. package/dist/components/faq/index.cjs +4 -4
  70. package/dist/components/faq/index.js +3 -3
  71. package/dist/components/features/index.cjs +3 -3
  72. package/dist/components/features/index.js +2 -2
  73. package/dist/components/help-center-pages/index.cjs +73 -73
  74. package/dist/components/help-center-pages/index.js +14 -14
  75. package/dist/components/index.cjs +39 -39
  76. package/dist/components/index.js +13 -13
  77. package/dist/components/meeting-scheduler/index.cjs +24 -24
  78. package/dist/components/meeting-scheduler/index.js +2 -2
  79. package/dist/components/navigation/index.cjs +6 -6
  80. package/dist/components/navigation/index.js +5 -5
  81. package/dist/components/onboarding-guides/index.cjs +6 -6
  82. package/dist/components/onboarding-guides/index.js +5 -5
  83. package/dist/components/tickets/index.cjs +7 -7
  84. package/dist/components/tickets/index.js +6 -6
  85. package/dist/components/ui/index.cjs +3 -3
  86. package/dist/components/ui/index.js +2 -2
  87. package/dist/components/ui/search-input.d.ts +5 -1
  88. package/dist/components/ui/search-input.d.ts.map +1 -1
  89. package/dist/index.cjs +7 -7
  90. package/dist/index.js +6 -6
  91. package/dist/types/design-doc.d.ts +2 -0
  92. package/dist/types/design-doc.d.ts.map +1 -1
  93. package/package.json +1 -1
  94. package/src/__tests__/search-input-submit-on-clear.test.tsx +32 -0
  95. package/src/chat-protocol/__tests__/card-marker.test.ts +27 -1
  96. package/src/chat-protocol/card-marker.ts +24 -0
  97. package/src/chat-protocol/index.ts +3 -0
  98. package/src/components/ui/search-input.tsx +7 -1
  99. package/src/types/design-doc.ts +5 -1
  100. package/dist/chunk-BQUWZQF6.cjs.map +0 -1
  101. package/dist/chunk-FUXUJSPP.cjs.map +0 -1
  102. package/dist/chunk-TLLTL6LB.js.map +0 -1
  103. /package/dist/{chunk-BRGO4IEB.js.map → chunk-4AZWVS7F.js.map} +0 -0
  104. /package/dist/{chunk-7BOZ3CRQ.js.map → chunk-6S2KLT7O.js.map} +0 -0
  105. /package/dist/{chunk-R4NCUO7Y.js.map → chunk-7KM34VWL.js.map} +0 -0
  106. /package/dist/{chunk-IO3EXNLR.js.map → chunk-AL4I5HHB.js.map} +0 -0
  107. /package/dist/{chunk-U7UVD2D2.js.map → chunk-EKABOXNB.js.map} +0 -0
  108. /package/dist/{chunk-DQVEL4YO.js.map → chunk-IBGHJLNT.js.map} +0 -0
  109. /package/dist/{chunk-BP52HUNB.js.map → chunk-KSBDARII.js.map} +0 -0
  110. /package/dist/{chunk-7A6EJEL5.js.map → chunk-O5PYXQ6H.js.map} +0 -0
  111. /package/dist/{chunk-QSUYGCBR.js.map → chunk-PWPYCJ33.js.map} +0 -0
  112. /package/dist/{chunk-QZGGA47F.js.map → chunk-T3KXCOB2.js.map} +0 -0
  113. /package/dist/{chunk-RLVSORQW.js.map → chunk-TFSGYKWG.js.map} +0 -0
  114. /package/dist/{chunk-BZ6RAT7K.js.map → chunk-TQPKNG2E.js.map} +0 -0
  115. /package/dist/{chunk-K6WL2OWX.js.map → chunk-XDTU23P4.js.map} +0 -0
  116. /package/dist/{chunk-JB44GMRU.js.map → chunk-Z6E45TJM.js.map} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flamingo-stack/openframe-frontend-core",
3
- "version": "0.0.670",
3
+ "version": "0.0.671-snapshot.20260928023432",
4
4
  "description": "Shared design system and components for all Flamingo platforms",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -0,0 +1,32 @@
1
+ import { fireEvent, render, screen } from '@testing-library/react';
2
+ import { useState } from 'react';
3
+ import { describe, expect, it, vi } from 'vitest';
4
+ import { SearchInput } from '../components/ui/search-input';
5
+
6
+ // An enter-to-search host: a submitted search must not stay applied once its text is gone.
7
+ function Host({ onSubmit }: { onSubmit: (v: string) => void }) {
8
+ const [value, setValue] = useState('sso');
9
+ return (
10
+ <SearchInput value={value} onChange={setValue} onSubmit={onSubmit} showDropdown={false} placeholder="Search" />
11
+ );
12
+ }
13
+
14
+ describe('SearchInput submits the empty search when the box is emptied', () => {
15
+ it('by the clear button', () => {
16
+ const onSubmit = vi.fn();
17
+ render(<Host onSubmit={onSubmit} />);
18
+ fireEvent.click(screen.getByLabelText('Clear search'));
19
+ expect(onSubmit).toHaveBeenCalledWith('');
20
+ });
21
+
22
+ it('by deleting the text, once (not on every keystroke, and not when it was already empty)', () => {
23
+ const onSubmit = vi.fn();
24
+ render(<Host onSubmit={onSubmit} />);
25
+ const input = screen.getByPlaceholderText('Search');
26
+ fireEvent.change(input, { target: { value: 'ss' } });
27
+ expect(onSubmit).not.toHaveBeenCalled();
28
+ fireEvent.change(input, { target: { value: '' } });
29
+ expect(onSubmit).toHaveBeenCalledTimes(1);
30
+ expect(onSubmit).toHaveBeenCalledWith('');
31
+ });
32
+ });
@@ -16,7 +16,7 @@
16
16
  */
17
17
 
18
18
  import { describe, expect, it } from 'vitest';
19
- import { CARD_REFERENCE, createCardMarkerScanner } from '../card-marker';
19
+ import { CARD_REFERENCE, createCardMarkerScanner, extractCardReferences } from '../card-marker';
20
20
 
21
21
  /** The id half as the backend validates it: anything but `]` and newlines. */
22
22
  const PUNCTUATED_IDS = [
@@ -61,3 +61,29 @@ describe('card marker grammar', () => {
61
61
  expect(CARD_REFERENCE.exec('[card://faq:a] plus a note')).toBeNull();
62
62
  });
63
63
  });
64
+
65
+ describe('extractCardReferences', () => {
66
+ it('returns each reference once, in order of first appearance', () => {
67
+ const text =
68
+ 'See [card://hubspot_ticket_self:48720777129] and [card://faq:a], ' +
69
+ 'then [card://hubspot_ticket_self:48720777129] again ([card://podcast:9b2f).';
70
+
71
+ expect(extractCardReferences(text)).toEqual([
72
+ { type: 'hubspot_ticket_self', id: '48720777129' },
73
+ { type: 'faq', id: 'a' },
74
+ { type: 'podcast', id: '9b2f' },
75
+ ]);
76
+ });
77
+
78
+ it('finds nothing in text without markers, or with a malformed one', () => {
79
+ expect(extractCardReferences('no cards here')).toEqual([]);
80
+ expect(extractCardReferences('[card://faq:]')).toEqual([]);
81
+ });
82
+
83
+ it('is served from the server-safe `chat-protocol` entry point', async () => {
84
+ const chatProtocol = await import('../index');
85
+ expect(chatProtocol.extractCardReferences).toBe(extractCardReferences);
86
+ expect(chatProtocol.createCardMarkerScanner).toBe(createCardMarkerScanner);
87
+ expect(chatProtocol.CARD_REFERENCE).toBe(CARD_REFERENCE);
88
+ });
89
+ });
@@ -38,3 +38,27 @@ export const CARD_REFERENCE = new RegExp(`^\\[card://(${CARD_TYPE}):(${CARD_ID})
38
38
  export function createCardMarkerScanner(): RegExp {
39
39
  return new RegExp(`\\[card://(${CARD_TYPE}):(${CARD_ID})[\\])]`, 'g');
40
40
  }
41
+
42
+ /** One `[card://<type>:<id>]` reference, split into its two halves. */
43
+ export interface CardReference {
44
+ type: string;
45
+ id: string;
46
+ }
47
+
48
+ /**
49
+ * Every card reference EMBEDDED in a text, in order of first appearance,
50
+ * each once. The server reads the references an answer cites through this
51
+ * (the hub's MCP `ask_guide` returns them as `cards[]`), so a host and the
52
+ * body renderer can never disagree about which markers a text carries.
53
+ */
54
+ export function extractCardReferences(text: string): CardReference[] {
55
+ const seen = new Set<string>();
56
+ const out: CardReference[] = [];
57
+ for (const match of text.matchAll(createCardMarkerScanner())) {
58
+ const key = `${match[1]}:${match[2]}`;
59
+ if (seen.has(key)) continue;
60
+ seen.add(key);
61
+ out.push({ type: match[1], id: match[2] });
62
+ }
63
+ return out;
64
+ }
@@ -23,3 +23,6 @@ export * from './ip-normalize';
23
23
  // forwarding above must be parsed IDENTICALLY on both sides of the seam.
24
24
  export * from './env-flag';
25
25
  export { isRecord, unwrapEnvelope } from './wire-narrow';
26
+ // The `[card://<type>:<id>]` grammar — the renderer's and the server's one
27
+ // definition, so a reference the hub emits is one the client expands.
28
+ export * from './card-marker';
@@ -51,7 +51,11 @@ export interface SearchInputProps {
51
51
  defaultValue?: string;
52
52
  /** Called when input value changes (raw, not debounced) */
53
53
  onChange?: (value: string) => void;
54
- /** Called when user presses Enter */
54
+ /**
55
+ * Called when the user presses Enter, AND with `''` when the box is emptied (the clear button, or deleting the
56
+ * text): a search that was submitted must not stay applied after its text is gone. Read the argument, never the
57
+ * host's own state, which has not re-rendered yet when this fires.
58
+ */
55
59
  onSubmit?: (value: string) => void;
56
60
  /** Search results to display in the dropdown */
57
61
  results?: SearchResult[];
@@ -292,6 +296,7 @@ export function SearchInput({
292
296
  } else {
293
297
  setInternalValue(newVal);
294
298
  }
299
+ if (newVal === '' && currentValue !== '') onSubmit?.('');
295
300
  if (!isOpen) setIsOpen(true);
296
301
  setHighlightedIndex(-1);
297
302
  };
@@ -304,6 +309,7 @@ export function SearchInput({
304
309
  } else {
305
310
  setInternalValue('');
306
311
  }
312
+ if (currentValue !== '') onSubmit?.('');
307
313
  inputRef.current?.focus();
308
314
  };
309
315
 
@@ -376,7 +376,11 @@ export interface DesignDocListResponse {
376
376
  count: number;
377
377
  /** Server-computed spec-mode counts over the scope, MINUS the spec-mode
378
378
  * filter itself — so a filtered row still shows what the other value holds. */
379
- facets: { spec_mode: Record<string, number> };
379
+ facets: {
380
+ spec_mode: Record<string, number>;
381
+ /** The same over readiness (`ready` / `not_ready`), MINUS the ready filter itself: the filter row's options. */
382
+ ready: Record<'ready' | 'not_ready', number>;
383
+ };
380
384
  }
381
385
 
382
386
  export interface DesignDocStats {