@flamingo-stack/openframe-frontend-core 0.0.518-1663.4312.1 → 0.0.518

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 (119) hide show
  1. package/dist/{chunk-KW7GDLSG.cjs → chunk-262OTU4W.cjs} +14 -14
  2. package/dist/{chunk-KW7GDLSG.cjs.map → chunk-262OTU4W.cjs.map} +1 -1
  3. package/dist/{chunk-I6IWT62M.cjs → chunk-2AHSX63M.cjs} +5 -5
  4. package/dist/{chunk-I6IWT62M.cjs.map → chunk-2AHSX63M.cjs.map} +1 -1
  5. package/dist/{chunk-LQ2R7IA2.cjs → chunk-2EU3TWCW.cjs} +26 -26
  6. package/dist/{chunk-LQ2R7IA2.cjs.map → chunk-2EU3TWCW.cjs.map} +1 -1
  7. package/dist/{chunk-MVY3WDFZ.js → chunk-2ZHVOTSA.js} +2 -2
  8. package/dist/{chunk-UBTOOE55.js → chunk-5OGHZNY5.js} +10 -1
  9. package/dist/chunk-5OGHZNY5.js.map +1 -0
  10. package/dist/{chunk-PUBL2NCH.js → chunk-6EAACE7G.js} +2 -2
  11. package/dist/{chunk-IIPBTWQR.cjs → chunk-7INXXQVK.cjs} +10 -1
  12. package/dist/{chunk-IIPBTWQR.cjs.map → chunk-7INXXQVK.cjs.map} +1 -1
  13. package/dist/{chunk-IVTENGMF.js → chunk-7J4DGFHZ.js} +2 -2
  14. package/dist/{chunk-LL4C2NXG.js → chunk-7SPVAAWE.js} +109 -134
  15. package/dist/{chunk-LL4C2NXG.js.map → chunk-7SPVAAWE.js.map} +1 -1
  16. package/dist/{chunk-NJJWY7SO.js → chunk-BBI7GD2Q.js} +2 -2
  17. package/dist/{chunk-P6M5MN3L.js → chunk-CV624KM6.js} +6 -6
  18. package/dist/{chunk-WQDDSJWN.cjs → chunk-FAOL7EI2.cjs} +11 -11
  19. package/dist/{chunk-WQDDSJWN.cjs.map → chunk-FAOL7EI2.cjs.map} +1 -1
  20. package/dist/{chunk-MI7WNVWX.js → chunk-FISSR67K.js} +6 -6
  21. package/dist/{chunk-BQXHC336.cjs → chunk-IPHH3GKC.cjs} +3 -3
  22. package/dist/{chunk-BQXHC336.cjs.map → chunk-IPHH3GKC.cjs.map} +1 -1
  23. package/dist/{chunk-PV3LXEHJ.js → chunk-J2JLAW2J.js} +3 -3
  24. package/dist/{chunk-RLVJISO4.cjs → chunk-J3DRYWFP.cjs} +61 -61
  25. package/dist/{chunk-RLVJISO4.cjs.map → chunk-J3DRYWFP.cjs.map} +1 -1
  26. package/dist/{chunk-GH5YZSQQ.cjs → chunk-LY7IT5QX.cjs} +9 -9
  27. package/dist/{chunk-GH5YZSQQ.cjs.map → chunk-LY7IT5QX.cjs.map} +1 -1
  28. package/dist/{chunk-K26W23C2.cjs → chunk-MKPJYEOR.cjs} +6 -6
  29. package/dist/{chunk-K26W23C2.cjs.map → chunk-MKPJYEOR.cjs.map} +1 -1
  30. package/dist/{chunk-MOZUJ7IN.js → chunk-MY7663CW.js} +2 -2
  31. package/dist/{chunk-YH627NWE.cjs → chunk-PJ4WHNJH.cjs} +9 -9
  32. package/dist/{chunk-YH627NWE.cjs.map → chunk-PJ4WHNJH.cjs.map} +1 -1
  33. package/dist/{chunk-CHMQCXYO.cjs → chunk-QNJCZGHH.cjs} +37 -37
  34. package/dist/{chunk-CHMQCXYO.cjs.map → chunk-QNJCZGHH.cjs.map} +1 -1
  35. package/dist/{chunk-TFIPJAA5.js → chunk-QOUKB6OJ.js} +3 -3
  36. package/dist/{chunk-YUQNJXSC.js → chunk-QPCPYCU2.js} +2 -2
  37. package/dist/{chunk-DN3GKQ47.cjs → chunk-S3C4RT4O.cjs} +98 -98
  38. package/dist/{chunk-DN3GKQ47.cjs.map → chunk-S3C4RT4O.cjs.map} +1 -1
  39. package/dist/{chunk-MKN6S7SU.cjs → chunk-SYQ4KUXW.cjs} +251 -276
  40. package/dist/chunk-SYQ4KUXW.cjs.map +1 -0
  41. package/dist/{chunk-URU6YKOA.cjs → chunk-U6NODSTY.cjs} +28 -28
  42. package/dist/{chunk-URU6YKOA.cjs.map → chunk-U6NODSTY.cjs.map} +1 -1
  43. package/dist/{chunk-RJU7YCN3.js → chunk-V3K5H4I2.js} +2 -2
  44. package/dist/{chunk-KRBH3PI4.js → chunk-V76TAQ3O.js} +4 -4
  45. package/dist/{chunk-QJHBYNHI.js → chunk-VCA3HNJ2.js} +4 -4
  46. package/dist/{chunk-25JSVBPR.cjs → chunk-WBEF37M5.cjs} +12 -12
  47. package/dist/{chunk-25JSVBPR.cjs.map → chunk-WBEF37M5.cjs.map} +1 -1
  48. package/dist/{chunk-O4XLTA5G.cjs → chunk-XDADNUC5.cjs} +31 -31
  49. package/dist/{chunk-O4XLTA5G.cjs.map → chunk-XDADNUC5.cjs.map} +1 -1
  50. package/dist/{chunk-XARCNHWZ.js → chunk-YHAYMOXR.js} +3 -3
  51. package/dist/components/calendar.cjs +3 -3
  52. package/dist/components/calendar.js +2 -2
  53. package/dist/components/case-studies/index.cjs +9 -9
  54. package/dist/components/case-studies/index.js +3 -3
  55. package/dist/components/chat/hooks/use-jetstream-dialog-subscription.d.ts +1 -7
  56. package/dist/components/chat/hooks/use-jetstream-dialog-subscription.d.ts.map +1 -1
  57. package/dist/components/chat/index.cjs +3 -5
  58. package/dist/components/chat/index.cjs.map +1 -1
  59. package/dist/components/chat/index.js +2 -4
  60. package/dist/components/chat/types/api.types.d.ts +4 -22
  61. package/dist/components/chat/types/api.types.d.ts.map +1 -1
  62. package/dist/components/contact/index.cjs +4 -4
  63. package/dist/components/contact/index.js +3 -3
  64. package/dist/components/docs/index.cjs +6 -6
  65. package/dist/components/docs/index.js +5 -5
  66. package/dist/components/embeds/index.cjs +4 -4
  67. package/dist/components/embeds/index.js +3 -3
  68. package/dist/components/faq/index.cjs +4 -4
  69. package/dist/components/faq/index.js +3 -3
  70. package/dist/components/features/index.cjs +3 -3
  71. package/dist/components/features/index.js +2 -2
  72. package/dist/components/help-center-pages/index.cjs +23 -23
  73. package/dist/components/help-center-pages/index.js +14 -14
  74. package/dist/components/index.cjs +150 -152
  75. package/dist/components/index.cjs.map +1 -1
  76. package/dist/components/index.js +12 -14
  77. package/dist/components/index.js.map +1 -1
  78. package/dist/components/meeting-scheduler/index.cjs +41 -41
  79. package/dist/components/meeting-scheduler/index.js +5 -5
  80. package/dist/components/navigation/index.cjs +3 -3
  81. package/dist/components/navigation/index.js +2 -2
  82. package/dist/components/onboarding-guides/index.cjs +6 -6
  83. package/dist/components/onboarding-guides/index.js +5 -5
  84. package/dist/components/related-content/index.cjs +4 -4
  85. package/dist/components/related-content/index.js +3 -3
  86. package/dist/components/tickets/index.cjs +7 -7
  87. package/dist/components/tickets/index.js +6 -6
  88. package/dist/components/ui/button/button.d.ts +1 -1
  89. package/dist/components/ui/button/button.d.ts.map +1 -1
  90. package/dist/components/ui/file-manager/index.cjs +15 -15
  91. package/dist/components/ui/file-manager/index.js +1 -1
  92. package/dist/components/ui/index.cjs +3 -5
  93. package/dist/components/ui/index.cjs.map +1 -1
  94. package/dist/components/ui/index.js +2 -4
  95. package/dist/index.cjs +3 -5
  96. package/dist/index.cjs.map +1 -1
  97. package/dist/index.js +2 -4
  98. package/package.json +1 -1
  99. package/src/components/chat/hooks/.use-jetstream-dialog-subscription.md +4 -11
  100. package/src/components/chat/hooks/use-jetstream-dialog-subscription.ts +6 -71
  101. package/src/components/chat/types/api.types.ts +4 -22
  102. package/src/components/chat/utils/__tests__/history-merge.test.ts +0 -99
  103. package/src/components/ui/button/button.tsx +9 -0
  104. package/dist/chunk-MKN6S7SU.cjs.map +0 -1
  105. package/dist/chunk-UBTOOE55.js.map +0 -1
  106. /package/dist/{chunk-MVY3WDFZ.js.map → chunk-2ZHVOTSA.js.map} +0 -0
  107. /package/dist/{chunk-PUBL2NCH.js.map → chunk-6EAACE7G.js.map} +0 -0
  108. /package/dist/{chunk-IVTENGMF.js.map → chunk-7J4DGFHZ.js.map} +0 -0
  109. /package/dist/{chunk-NJJWY7SO.js.map → chunk-BBI7GD2Q.js.map} +0 -0
  110. /package/dist/{chunk-P6M5MN3L.js.map → chunk-CV624KM6.js.map} +0 -0
  111. /package/dist/{chunk-MI7WNVWX.js.map → chunk-FISSR67K.js.map} +0 -0
  112. /package/dist/{chunk-PV3LXEHJ.js.map → chunk-J2JLAW2J.js.map} +0 -0
  113. /package/dist/{chunk-MOZUJ7IN.js.map → chunk-MY7663CW.js.map} +0 -0
  114. /package/dist/{chunk-TFIPJAA5.js.map → chunk-QOUKB6OJ.js.map} +0 -0
  115. /package/dist/{chunk-YUQNJXSC.js.map → chunk-QPCPYCU2.js.map} +0 -0
  116. /package/dist/{chunk-RJU7YCN3.js.map → chunk-V3K5H4I2.js.map} +0 -0
  117. /package/dist/{chunk-KRBH3PI4.js.map → chunk-V76TAQ3O.js.map} +0 -0
  118. /package/dist/{chunk-QJHBYNHI.js.map → chunk-VCA3HNJ2.js.map} +0 -0
  119. /package/dist/{chunk-XARCNHWZ.js.map → chunk-YHAYMOXR.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  'use client'
2
2
 
3
- import { useCallback, useEffect, useRef, useState } from 'react'
3
+ import { useEffect, useRef, useState } from 'react'
4
4
  import {
5
5
  acquireClient as acquireSharedClient,
6
6
  releaseClient as releaseSharedClient,
@@ -20,24 +20,7 @@ const DEFAULT_STREAM_NAME = 'CHAT_CHUNKS'
20
20
  * absence worth resyncing for. Alt-tabbing must not churn the consumer; a
21
21
  * window that sat in the tray must not come back showing a stale conversation.
22
22
  */
23
- export const RESYNC_AFTER_HIDDEN_MS = 10_000
24
- /**
25
- * How long resync requests are gathered before one is acted on.
26
- *
27
- * A single reveal can be reported twice: the page sees `visibilitychange`, and
28
- * a host that knows the window was away reports it too (`resyncSignal`),
29
- * neither able to tell whether the other noticed. Both land within a frame or
30
- * two of each other, being driven by the same OS event, and acting on both
31
- * rebuilds the consumer and refetches history twice for one reveal.
32
- *
33
- * Gathered on the TRAILING edge, so a request is deferred and never dropped.
34
- * Two reports of one reveal collapse into one rebuild; two genuinely different
35
- * signals — a notification reply landing just before the user opens the window
36
- * — also collapse into one, which is correct, because a single refetch after
37
- * the last of them covers both. The cost is a second of latency on a path whose
38
- * next step is a network round trip.
39
- */
40
- const RESYNC_COALESCE_MS = 1_000
23
+ const RESYNC_AFTER_HIDDEN_MS = 10_000
41
24
  /**
42
25
  * Floor between two reported recoveries. Every recovery costs the caller a
43
26
  * history refetch, and a consumer that cannot hold its sequence — gap, reset,
@@ -77,7 +60,6 @@ export function useJetStreamDialogSubscription({
77
60
  clientConfig = {},
78
61
  reconnectionBackoff,
79
62
  inactiveThresholdMs,
80
- resyncSignal = 0,
81
63
  }: UseJetStreamDialogSubscriptionOptions): UseJetStreamDialogSubscriptionReturn {
82
64
  const [isConnected, setIsConnected] = useState(false)
83
65
  const [isSubscribed, setIsSubscribed] = useState(false)
@@ -91,8 +73,6 @@ export function useJetStreamDialogSubscription({
91
73
  const [currentStreamSeq, setCurrentStreamSeq] = useState<number | null>(null)
92
74
 
93
75
  const lastRecoveryReportRef = useRef(0)
94
- const resyncTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
95
- const lastResyncSignalRef = useRef(resyncSignal)
96
76
  const clientRef = useRef<NatsClient | null>(null)
97
77
  const subscriptionRef = useRef<JetStreamSubscriptionHandle | null>(null)
98
78
  const highestStreamSeqRef = useRef<number | null>(null)
@@ -265,26 +245,7 @@ export function useJetStreamDialogSubscription({
265
245
  // ignoring optStartSeq).
266
246
  useEffect(() => {
267
247
  highestStreamSeqRef.current = null
268
- // A host's signal counts per dialog (it can carry a per-conversation term),
269
- // so the baseline has to move with the dialog or a switch to one with a
270
- // LOWER count would swallow every later resync for it.
271
- lastResyncSignalRef.current = resyncSignal
272
248
  setCurrentStreamSeq(null)
273
- // A resync gathered for the previous dialog must not land on this one: the
274
- // counter says nothing about which conversation it meant, so callers would
275
- // refetch the wrong one. The dialog change supersedes it — the new dialog
276
- // loads its own history regardless. As cleanup, so it covers unmount too,
277
- // which is the same rule.
278
- return () => {
279
- if (resyncTimerRef.current !== null) {
280
- clearTimeout(resyncTimerRef.current)
281
- resyncTimerRef.current = null
282
- }
283
- }
284
- // `resyncSignal` is read as the new baseline, not depended on: reacting to
285
- // it here would reset the baseline on the very change meant to trigger a
286
- // resync, and the effect below owns that.
287
- // eslint-disable-next-line react-hooks/exhaustive-deps
288
249
  }, [dialogId])
289
250
 
290
251
  // Coming back into view after a real absence is treated exactly like a
@@ -295,20 +256,8 @@ export function useJetStreamDialogSubscription({
295
256
  // report that: the tail simply stays quiet, and the conversation on screen
296
257
  // stays frozen at whatever was there when the window went away (the user's
297
258
  // manual fix is a page refresh, which is exactly the history refetch this
298
- // triggers). Rebuilds the consumer from the last sequence seen AND tells
299
- // callers to refetch history.
300
- //
301
- // Every source funnels through here (see `RESYNC_COALESCE_MS`). Restarting
302
- // the timer rather than dropping is what makes that safe: a request is only
303
- // ever folded into the one that follows it, never discarded.
304
- const requestResync = useCallback(() => {
305
- if (resyncTimerRef.current !== null) clearTimeout(resyncTimerRef.current)
306
- resyncTimerRef.current = setTimeout(() => {
307
- resyncTimerRef.current = null
308
- setReconnectionCount((c) => c + 1)
309
- }, RESYNC_COALESCE_MS)
310
- }, [])
311
-
259
+ // triggers). Bumping the counter rebuilds the consumer from the last sequence
260
+ // seen AND tells callers to refetch history.
312
261
  useEffect(() => {
313
262
  if (!enabled) return
314
263
  let hiddenSince = document.visibilityState === 'hidden' ? Date.now() : 0
@@ -321,27 +270,13 @@ export function useJetStreamDialogSubscription({
321
270
  const awayMs = hiddenSince === 0 ? 0 : Date.now() - hiddenSince
322
271
  hiddenSince = 0
323
272
  if (awayMs >= RESYNC_AFTER_HIDDEN_MS) {
324
- requestResync()
273
+ setReconnectionCount((c) => c + 1)
325
274
  }
326
275
  }
327
276
 
328
277
  document.addEventListener('visibilitychange', onVisibilityChange)
329
278
  return () => document.removeEventListener('visibilitychange', onVisibilityChange)
330
- }, [enabled, requestResync])
331
-
332
- useEffect(() => {
333
- // Held, not consumed, while disabled: it fires once on enable instead.
334
- // A host reports a signal against the conversation, not against this hook's
335
- // readiness, so one arriving while the caller is still assembling the
336
- // subscription describes a gap in the history the caller is fetching right
337
- // now. Dropping it would leave that fetch's result stale with nothing left
338
- // to say so.
339
- if (!enabled) return
340
- // The mount value is a baseline, not a signal.
341
- if (resyncSignal <= lastResyncSignalRef.current) return
342
- lastResyncSignalRef.current = resyncSignal
343
- requestResync()
344
- }, [enabled, resyncSignal, requestResync])
279
+ }, [enabled])
345
280
 
346
281
  // Subscription lifecycle: (re)create the ephemeral JetStream consumer whenever
347
282
  // we transition into a connected state for a dialog, and whenever the dialog
@@ -131,22 +131,6 @@ export interface UseJetStreamDialogSubscriptionOptions {
131
131
  /** Consumer inactivity threshold in ms before NATS auto-cleans it. Defaults to the
132
132
  * client's, and applies only to the first consumer — recreations use nats.ws's. */
133
133
  inactiveThresholdMs?: number
134
- /**
135
- * A counter the host bumps when it knows, from outside the page, that the tail
136
- * may have missed something.
137
- *
138
- * The hook's own detector is `visibilitychange`, which a browser tab reports
139
- * honestly and an embedding shell may not — and which says nothing at all
140
- * about a write made on the page's behalf while it was away. A host holding
141
- * either kind of knowledge bumps this instead of hoping the page noticed.
142
- *
143
- * Treated exactly like a reconnect: the consumer is rebuilt from the highest
144
- * sequence already seen, and `reconnectionCount` moves so callers refetch
145
- * persisted history. Any increase counts; the value itself means nothing, and
146
- * an increase arriving alongside a `visibilitychange` costs one rebuild, not
147
- * two.
148
- */
149
- resyncSignal?: number
150
134
  }
151
135
 
152
136
  export interface UseJetStreamDialogSubscriptionReturn {
@@ -154,12 +138,10 @@ export interface UseJetStreamDialogSubscriptionReturn {
154
138
  isSubscribed: boolean
155
139
  /**
156
140
  * Incremented each time the live tail is re-established: a NATS reconnect, a
157
- * JetStream ordered-consumer recreation, the page returning to view after
158
- * being hidden long enough to have missed something, or a host reporting the
159
- * same via `resyncSignal`. All of them mean the same thing to the caller —
160
- * the tail may have skipped messages, so persisted history has to be
161
- * refetched. One absence counts once even when two sources report it.
162
- * Starts at 0.
141
+ * JetStream ordered-consumer recreation, or the page returning to view after
142
+ * being hidden long enough to have missed something. All three mean the same
143
+ * thing to the caller the tail may have skipped messages, so persisted
144
+ * history has to be refetched. Starts at 0.
163
145
  */
164
146
  reconnectionCount: number
165
147
  /** Highest JetStream stream sequence observed so far (null before first delivery). */
@@ -930,102 +930,3 @@ describe('mid-stream refetch (turn partially persisted)', () => {
930
930
  expect(ids(merged)).toEqual([U0.id, A0.id, PERSISTED_PARTIAL.id, unrelatedLive.id])
931
931
  })
932
932
  })
933
-
934
- describe('ordering of surviving realtime messages', () => {
935
- // The merge concatenates: all persisted history, then every realtime message
936
- // the coverage rules kept, each side in its own order. These pin that
937
- // contract, which nothing asserted before — the suite tested only WHICH
938
- // messages survive, never where they land — and which an attempt to
939
- // chronologically interleave the two sides repeatedly broke.
940
- const H_U0: TestMessage = { ...U0, streamSeq: 5 }
941
- const H_A0: TestMessage = { ...A0, streamSeq: 10 }
942
- /**
943
- * Sent from a notification while the window was away, and persisted. NO
944
- * `streamSeq`: the backend does not stamp user MESSAGE_REQUEST rows, which is
945
- * the missing signal that makes interleaving guesswork.
946
- */
947
- const AWAY_U: TestMessage = {
948
- id: 'bbbb0001',
949
- role: 'user',
950
- content: 'replied from a notification',
951
- timestamp: t(3000),
952
- }
953
- /** Mingo's answer to it. Assistant rows DO carry a sequence. */
954
- const AWAY_A: TestMessage = {
955
- id: 'bbbb0002',
956
- role: 'assistant',
957
- content: txt('answered while the window was away'),
958
- timestamp: t(3100),
959
- streamSeq: 80,
960
- }
961
-
962
- it('appends surviving realtime messages after all persisted history', () => {
963
- // A technician direct message the snapshot has not caught up with. Its own
964
- // role's persisted max (H_U0, seq 5) is below it, so coverage keeps it.
965
- const unpersistedDirect: TestMessage = {
966
- id: 'direct-1500-old',
967
- role: 'user',
968
- content: 'a direct message history has not persisted yet',
969
- timestamp: t(1500),
970
- streamSeq: 40,
971
- }
972
- const merged = mergeHistoryWithRealtime({
973
- processedHistory: [H_U0, H_A0, AWAY_U, AWAY_A],
974
- existingMessages: [H_U0, H_A0, unpersistedDirect],
975
- streamingMessageId: null,
976
- historyFetchedAt: 9000,
977
- historyMaxStreamSeq: 80,
978
- realtimeSeenStreamSeq: 40,
979
- })
980
-
981
- expect(ids(merged)).toEqual([H_U0.id, H_A0.id, AWAY_U.id, AWAY_A.id, unpersistedDirect.id])
982
- })
983
-
984
- it('keeps survivors in store order, sequence or no sequence', () => {
985
- // The guard against reordering the two kinds against each other: an
986
- // optimistic bubble carries no sequence and a replayed direct message does,
987
- // and sorting by sequence would render the user's question below the reply
988
- // that came after it.
989
- const optimistic: TestMessage = {
990
- id: 'optimistic-9400-x',
991
- role: 'user',
992
- content: 'just typed, no seq of its own',
993
- timestamp: t(9400),
994
- }
995
- const laterDirect: TestMessage = {
996
- id: 'direct-9500-x',
997
- role: 'user',
998
- content: 'and a direct message after it',
999
- timestamp: t(9500),
1000
- streamSeq: 40,
1001
- }
1002
- const merged = mergeHistoryWithRealtime({
1003
- processedHistory: [H_U0, H_A0, AWAY_U, AWAY_A],
1004
- existingMessages: [H_U0, H_A0, optimistic, laterDirect],
1005
- streamingMessageId: null,
1006
- // Before either was minted, so neither can be in the snapshot.
1007
- historyFetchedAt: 9000,
1008
- historyMaxStreamSeq: 80,
1009
- realtimeSeenStreamSeq: 40,
1010
- })
1011
-
1012
- expect(ids(merged)).toEqual([H_U0.id, H_A0.id, AWAY_U.id, AWAY_A.id, optimistic.id, laterDirect.id])
1013
- })
1014
-
1015
- it('keeps history in snapshot order even when its sequences do not climb', () => {
1016
- // The snapshot is the server's account of the conversation; the merge is
1017
- // not entitled to second-guess it from a `streamSeq` that looks out of
1018
- // order, which is what any sort of the two sides together would do.
1019
- const outOfOrder: TestMessage = { ...H_A0, id: 'aaaa0009', streamSeq: 3 }
1020
- const merged = mergeHistoryWithRealtime({
1021
- processedHistory: [H_U0, outOfOrder, AWAY_U, AWAY_A],
1022
- existingMessages: [H_U0],
1023
- streamingMessageId: null,
1024
- historyFetchedAt: 9000,
1025
- historyMaxStreamSeq: 80,
1026
- realtimeSeenStreamSeq: 0,
1027
- })
1028
-
1029
- expect(ids(merged)).toEqual([H_U0.id, outOfOrder.id, AWAY_U.id, AWAY_A.id])
1030
- })
1031
- })
@@ -55,6 +55,15 @@ const buttonVariants = cva(
55
55
  // metadata rather than CTAs — author-page social rows, share rows.
56
56
  // Pair with variant="transparent" for the ghost treatment.
57
57
  'icon-sm': 'p-[var(--spacing-system-xxs)] h-8 w-8 [&_svg]:h-4 [&_svg]:w-4',
58
+ // 20px inline glyph for affordances that sit INSIDE a line of text —
59
+ // an info hint beside a badge, a copy glyph after an id. `icon-sm`'s
60
+ // 32px target is correct for a metadata row but visually swamps a
61
+ // 10px badge or a 14px label, so hosts were reaching for className
62
+ // overrides to shrink it. Below the WCAG 2.5.8 target floor on purpose:
63
+ // this is only for glyphs whose information is ALSO available another
64
+ // way (tooltip content mirrored into an aria-describedby node), never
65
+ // for a sole means of performing an action.
66
+ 'icon-inline': 'p-0 h-5 w-5 min-h-0 min-w-0 shrink-0 [&_svg]:h-3.5 [&_svg]:w-3.5',
58
67
  // Bare 56px media glyph (play / unmute over video). A size variant so
59
68
  // hosts stop re-implementing a <button> to escape the 20px svg cap.
60
69
  'icon-glyph': 'p-0 h-14 w-14 [&_svg]:h-14 [&_svg]:w-14',