@seedgrid/fe-components 2026.11.2 → 2026.11.3

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 (156) hide show
  1. package/dist/ai/seedgrid-components.manifest.json +323 -65
  2. package/dist/buttons/SgButton.d.ts +6 -2
  3. package/dist/buttons/SgButton.d.ts.map +1 -1
  4. package/dist/buttons/SgButton.js +2 -2
  5. package/dist/buttons/SgButton.meta.js +3 -3
  6. package/dist/buttons/SgFloatActionButton.d.ts +2 -2
  7. package/dist/buttons/SgFloatActionButton.d.ts.map +1 -1
  8. package/dist/buttons/SgFloatActionButton.js +7 -7
  9. package/dist/buttons/SgFloatActionButton.meta.js +2 -2
  10. package/dist/buttons/SgSplitButton.d.ts +2 -2
  11. package/dist/buttons/SgSplitButton.d.ts.map +1 -1
  12. package/dist/buttons/SgSplitButton.js +4 -4
  13. package/dist/buttons/SgSplitButton.meta.js +3 -3
  14. package/dist/commons/SgAvatar.d.ts +2 -2
  15. package/dist/commons/SgAvatar.d.ts.map +1 -1
  16. package/dist/commons/SgAvatar.js +3 -3
  17. package/dist/commons/SgBadge.d.ts +1 -1
  18. package/dist/commons/SgBadge.d.ts.map +1 -1
  19. package/dist/commons/SgBadge.js +3 -3
  20. package/dist/generated/compiledStyles.d.ts +1 -1
  21. package/dist/generated/compiledStyles.d.ts.map +1 -1
  22. package/dist/generated/compiledStyles.js +1 -1
  23. package/dist/i18n/en-US.d.ts.map +1 -1
  24. package/dist/i18n/en-US.js +26 -0
  25. package/dist/i18n/es.d.ts.map +1 -1
  26. package/dist/i18n/es.js +26 -0
  27. package/dist/i18n/fr.d.ts.map +1 -1
  28. package/dist/i18n/fr.js +26 -0
  29. package/dist/i18n/pt-BR.d.ts.map +1 -1
  30. package/dist/i18n/pt-BR.js +26 -0
  31. package/dist/i18n/pt-PT.d.ts.map +1 -1
  32. package/dist/i18n/pt-PT.js +26 -0
  33. package/dist/index.d.ts +3 -1
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +2 -1
  36. package/dist/inputs/SgAutocomplete.d.ts +1 -1
  37. package/dist/inputs/SgAutocomplete.d.ts.map +1 -1
  38. package/dist/inputs/SgAutocomplete.js +3 -3
  39. package/dist/inputs/SgCameraCapture.d.ts +1 -1
  40. package/dist/inputs/SgCameraCapture.d.ts.map +1 -1
  41. package/dist/inputs/SgCameraCapture.js +4 -4
  42. package/dist/inputs/SgCameraCapture.meta.js +1 -1
  43. package/dist/inputs/SgCheckboxGroup.d.ts +2 -2
  44. package/dist/inputs/SgCheckboxGroup.d.ts.map +1 -1
  45. package/dist/inputs/SgCheckboxGroup.js +12 -12
  46. package/dist/inputs/SgCombobox.js +5 -5
  47. package/dist/inputs/SgDatatable.js +11 -11
  48. package/dist/inputs/SgDatatable.meta.d.ts.map +1 -1
  49. package/dist/inputs/SgDatatable.meta.js +4 -1
  50. package/dist/inputs/SgFileUpload.d.ts +1 -1
  51. package/dist/inputs/SgFileUpload.d.ts.map +1 -1
  52. package/dist/inputs/SgFileUpload.js +2 -2
  53. package/dist/inputs/SgFileUpload.meta.js +1 -1
  54. package/dist/inputs/SgImageUpload.meta.js +1 -1
  55. package/dist/inputs/SgInputCurrency.d.ts.map +1 -1
  56. package/dist/inputs/SgInputCurrency.js +6 -4
  57. package/dist/inputs/SgInputDate.d.ts.map +1 -1
  58. package/dist/inputs/SgInputDate.js +3 -4
  59. package/dist/inputs/SgInputDateTime.d.ts.map +1 -1
  60. package/dist/inputs/SgInputDateTime.js +11 -0
  61. package/dist/inputs/SgInputNumber.d.ts.map +1 -1
  62. package/dist/inputs/SgInputNumber.js +6 -4
  63. package/dist/inputs/SgInputText.d.ts.map +1 -1
  64. package/dist/inputs/SgInputText.js +6 -4
  65. package/dist/inputs/SgInputTextArea.d.ts.map +1 -1
  66. package/dist/inputs/SgInputTextArea.js +4 -2
  67. package/dist/inputs/SgMultiSelect.meta.js +1 -1
  68. package/dist/inputs/SgMultiSelectChips.meta.js +1 -1
  69. package/dist/inputs/SgMultiSelectDropdown.js +1 -1
  70. package/dist/inputs/SgOrderList.d.ts +3 -3
  71. package/dist/inputs/SgOrderList.d.ts.map +1 -1
  72. package/dist/inputs/SgOrderList.js +13 -13
  73. package/dist/inputs/SgOrderList.meta.js +1 -1
  74. package/dist/inputs/SgPeriodSelector.d.ts +1 -1
  75. package/dist/inputs/SgPeriodSelector.d.ts.map +1 -1
  76. package/dist/inputs/SgPeriodSelector.js +3 -3
  77. package/dist/inputs/SgPickList.d.ts +3 -3
  78. package/dist/inputs/SgPickList.d.ts.map +1 -1
  79. package/dist/inputs/SgPickList.js +28 -28
  80. package/dist/inputs/SgPickList.meta.js +1 -1
  81. package/dist/inputs/SgRadioGroup.d.ts +2 -2
  82. package/dist/inputs/SgRadioGroup.d.ts.map +1 -1
  83. package/dist/inputs/SgRadioGroup.js +5 -5
  84. package/dist/inputs/SgRating.d.ts +1 -1
  85. package/dist/inputs/SgRating.d.ts.map +1 -1
  86. package/dist/inputs/SgRating.js +7 -7
  87. package/dist/inputs/SgRating.meta.js +1 -1
  88. package/dist/inputs/SgSlider.d.ts +1 -1
  89. package/dist/inputs/SgSlider.d.ts.map +1 -1
  90. package/dist/inputs/SgSlider.js +3 -3
  91. package/dist/inputs/SgSlider.meta.js +1 -1
  92. package/dist/inputs/SgStepperInput.d.ts +2 -2
  93. package/dist/inputs/SgStepperInput.d.ts.map +1 -1
  94. package/dist/inputs/SgStepperInput.js +4 -4
  95. package/dist/inputs/SgStepperInput.meta.js +1 -1
  96. package/dist/inputs/SgTextEditor.d.ts +1 -1
  97. package/dist/inputs/SgTextEditor.d.ts.map +1 -1
  98. package/dist/inputs/SgTextEditor.js +14 -14
  99. package/dist/inputs/SgToggleSwitch.meta.js +1 -1
  100. package/dist/inputs/SgYearPartSelector.d.ts +1 -1
  101. package/dist/inputs/SgYearPartSelector.d.ts.map +1 -1
  102. package/dist/inputs/SgYearPartSelector.js +1 -2
  103. package/dist/inputs/SgYearPartSelector.meta.js +2 -2
  104. package/dist/inputs/dateTimeLogic.d.ts +7 -1
  105. package/dist/inputs/dateTimeLogic.d.ts.map +1 -1
  106. package/dist/inputs/dateTimeLogic.js +17 -4
  107. package/dist/inputs/useSgMultiSelect.d.ts +1 -1
  108. package/dist/inputs/useSgMultiSelect.d.ts.map +1 -1
  109. package/dist/inputs/useSgMultiSelect.js +1 -1
  110. package/dist/layout/SgAccordion.d.ts +1 -1
  111. package/dist/layout/SgAccordion.d.ts.map +1 -1
  112. package/dist/layout/SgAccordion.js +3 -3
  113. package/dist/layout/SgBreadcrumb.d.ts +1 -1
  114. package/dist/layout/SgBreadcrumb.d.ts.map +1 -1
  115. package/dist/layout/SgBreadcrumb.js +1 -1
  116. package/dist/layout/SgCard.d.ts +1 -1
  117. package/dist/layout/SgCard.d.ts.map +1 -1
  118. package/dist/layout/SgCard.js +14 -14
  119. package/dist/layout/SgMenu.d.ts +1 -1
  120. package/dist/layout/SgMenu.d.ts.map +1 -1
  121. package/dist/layout/SgMenu.js +15 -15
  122. package/dist/layout/SgPageControl.d.ts +1 -1
  123. package/dist/layout/SgPageControl.d.ts.map +1 -1
  124. package/dist/layout/SgPageControl.js +4 -4
  125. package/dist/layout/SgPageControlPage.meta.js +2 -2
  126. package/dist/layout/SgToolBar.d.ts +1 -1
  127. package/dist/layout/SgToolBar.d.ts.map +1 -1
  128. package/dist/layout/SgToolBar.js +4 -4
  129. package/dist/layout/SgToolbarIconButton.meta.js +2 -2
  130. package/dist/layout/SgTreeView.d.ts +4 -4
  131. package/dist/layout/SgTreeView.d.ts.map +1 -1
  132. package/dist/layout/SgTreeView.js +6 -6
  133. package/dist/menus/SgDockMenu.d.ts +1 -1
  134. package/dist/menus/SgDockMenu.d.ts.map +1 -1
  135. package/dist/menus/SgDockMenu.js +4 -4
  136. package/dist/notifications/SgNotificationBell.d.ts +51 -0
  137. package/dist/notifications/SgNotificationBell.d.ts.map +1 -0
  138. package/dist/notifications/SgNotificationBell.js +348 -0
  139. package/dist/notifications/SgNotificationBell.meta.d.ts +4 -0
  140. package/dist/notifications/SgNotificationBell.meta.d.ts.map +1 -0
  141. package/dist/notifications/SgNotificationBell.meta.js +75 -0
  142. package/dist/notifications/notificationBellLogic.d.ts +148 -0
  143. package/dist/notifications/notificationBellLogic.d.ts.map +1 -0
  144. package/dist/notifications/notificationBellLogic.js +244 -0
  145. package/dist/overlay/SgConfirmationDialog.d.ts +1 -1
  146. package/dist/overlay/SgConfirmationDialog.d.ts.map +1 -1
  147. package/dist/overlay/SgConfirmationDialog.js +1 -1
  148. package/dist/overlay/SgPopup.d.ts +1 -1
  149. package/dist/overlay/SgPopup.d.ts.map +1 -1
  150. package/dist/overlay/SgPopup.js +1 -1
  151. package/dist/realtime/SgRealtimeProvider.d.ts +5 -0
  152. package/dist/realtime/SgRealtimeProvider.d.ts.map +1 -1
  153. package/dist/realtime/SgRealtimeProvider.js +31 -8
  154. package/dist/sandbox.cjs +62 -62
  155. package/dist/style.css +1 -1
  156. package/package.json +3 -3
@@ -0,0 +1,244 @@
1
+ // Logica pura do SgNotificationBell (P129). Sem React, sem rede, sem relogio: tudo recebe o que precisa por
2
+ // parametro, para que o Flutter (notification_bell_logic.dart) produza exatamente o mesmo resultado. Os vetores de
3
+ // paridade sao gerados DESTE arquivo (seedgrid-fe-flutter/.../notification_bell_vectors/generate.mjs).
4
+ //
5
+ // Contrato das rotas: extension `user-notifications` (P130). O aviso do Pulse so traz identificadores; o historico
6
+ // (fonte de verdade) vem da API.
7
+ export const NOTIFICATIONS_CHANNEL = "user-notifications";
8
+ export const DEFAULT_EVENT_PATTERN = "user-notification.*";
9
+ export const DEFAULT_MAX_VISIBLE = 100;
10
+ export const BADGE_MAX = 99;
11
+ export const DEFAULT_POLL_INTERVAL_MS = 45000;
12
+ export const MIN_POLL_INTERVAL_MS = 30000;
13
+ export const MAX_POLL_INTERVAL_MS = 60000;
14
+ export const MAX_POLL_BACKOFF_MS = 300000;
15
+ /** ISO-8601 em ms. Frações além de 3 dígitos (microssegundos do servidor) são truncadas, igual nas duas plataformas. */
16
+ function time(iso) {
17
+ const t = Date.parse(iso.replace(/(\.\d{3})\d+/, "$1"));
18
+ return Number.isNaN(t) ? 0 : t;
19
+ }
20
+ /** Mais nova primeiro; empate pelo `publicId` decrescente (como o servidor: ORDER BY created_at DESC, id DESC). */
21
+ export function sortNotifications(items) {
22
+ return [...items].sort((a, b) => {
23
+ const d = time(b.createdAt) - time(a.createdAt);
24
+ if (d !== 0)
25
+ return d;
26
+ return a.publicId < b.publicId ? 1 : a.publicId > b.publicId ? -1 : 0;
27
+ });
28
+ }
29
+ /** Teto da lista: de 1 a 100 (uma pagina da rota); sem valor ou invalido, 100. */
30
+ export function clampMaxVisible(value) {
31
+ if (typeof value !== "number" || !Number.isFinite(value))
32
+ return DEFAULT_MAX_VISIBLE;
33
+ return Math.min(DEFAULT_MAX_VISIBLE, Math.max(1, Math.trunc(value)));
34
+ }
35
+ /** Vencida (`expiresAt` ate agora): o servidor nao as lista, o sino tambem nao as mostra. */
36
+ export function isExpired(item, now) {
37
+ return !!item.expiresAt && time(item.expiresAt) <= time(now);
38
+ }
39
+ /** Lista que o sino mostra: sem repetidos (vale o ultimo), sem vencidas (se `now` vier), ordenada, no maximo `max` itens. */
40
+ export function normalizeList(items, max = DEFAULT_MAX_VISIBLE, now) {
41
+ const byId = new Map();
42
+ for (const item of items)
43
+ if (!now || !isExpired(item, now))
44
+ byId.set(item.publicId, item);
45
+ return sortNotifications([...byId.values()]).slice(0, Math.max(0, max));
46
+ }
47
+ /** Contador mostrado: o do servidor (`GET /unread-count`) quando se sabe, senao as nao lidas da lista local. */
48
+ export function displayUnread(serverCount, items) {
49
+ return typeof serverCount === "number" && serverCount >= 0 ? Math.trunc(serverCount) : unreadCount(items);
50
+ }
51
+ /** So conta as nao lidas. */
52
+ export function unreadCount(items) {
53
+ return items.reduce((n, item) => (item.read ? n : n + 1), 0);
54
+ }
55
+ /** Texto do contador: vazio com zero, `99+` acima de 99. */
56
+ export function badgeText(count) {
57
+ const n = Math.trunc(count);
58
+ if (!Number.isFinite(n) || n < 1)
59
+ return "";
60
+ return n > BADGE_MAX ? `${BADGE_MAX}+` : String(n);
61
+ }
62
+ export function markRead(items, publicId, readAt) {
63
+ return items.map((item) => (item.publicId === publicId && !item.read ? { ...item, read: true, readAt } : item));
64
+ }
65
+ export function markAllRead(items, readAt) {
66
+ return items.map((item) => (item.read ? item : { ...item, read: true, readAt }));
67
+ }
68
+ export function removeNotification(items, publicId) {
69
+ return items.filter((item) => item.publicId !== publicId);
70
+ }
71
+ /**
72
+ * Itens nao lidos que chegaram de verdade: desconhecidos e mais novos que o mais novo da lista anterior (uma nao lida
73
+ * antiga que so apareceu agora, por teto ou por reler, nao e noticia). Sao eles que fazem o sino animar.
74
+ */
75
+ export function newUnread(previous, next) {
76
+ const known = new Set(previous.map((item) => item.publicId));
77
+ const newest = previous.reduce((max, item) => Math.max(max, time(item.createdAt)), Number.NEGATIVE_INFINITY);
78
+ return next.filter((item) => !item.read && !known.has(item.publicId) && time(item.createdAt) >= newest);
79
+ }
80
+ /** `user-notification.*` casa `user-notification.created` e `user-notification.changed`. */
81
+ export function matchesEventPattern(pattern, event) {
82
+ if (pattern === "*" || pattern === event)
83
+ return true;
84
+ if (pattern.endsWith(".*"))
85
+ return event.startsWith(pattern.slice(0, -1));
86
+ return false;
87
+ }
88
+ /**
89
+ * `created` com o identificador: busca so a nova. `created` sem identificador e `changed` (ler, excluir, limpar em
90
+ * outra aba): le a lista de novo. Outro canal ou evento fora do padrao: ignora.
91
+ */
92
+ export function planEvent(pattern, channel, event, data) {
93
+ if (channel !== NOTIFICATIONS_CHANNEL || !matchesEventPattern(pattern, event))
94
+ return { action: "ignore" };
95
+ if (event === "user-notification.created") {
96
+ const id = data && typeof data === "object" ? data.notificationPublicId : undefined;
97
+ if (typeof id === "string" && id.length > 0)
98
+ return { action: "fetch", publicId: id };
99
+ }
100
+ return { action: "refresh" };
101
+ }
102
+ /**
103
+ * Polling so quando nao ha tempo real nem esperanca de ter logo: `disabled` (enabled:false) e `unavailable` /
104
+ * `auth-error` (Pulse fora do ar). Conectando ou reconectando, o SDK resolve sozinho.
105
+ */
106
+ export function pollingReason(status) {
107
+ if (status === "disabled")
108
+ return "disabled";
109
+ if (status === "unavailable" || status === "auth-error")
110
+ return "unavailable";
111
+ return null;
112
+ }
113
+ /** Ao (re)conectar, le a lista uma vez para recuperar o que passou enquanto estava fora. */
114
+ export function shouldRefreshOnStatus(previous, next) {
115
+ return next === "connected" && previous !== "connected";
116
+ }
117
+ /** Intervalo pedido, preso entre 30 e 60 s (padrao 45 s). */
118
+ export function clampPollInterval(ms) {
119
+ if (typeof ms !== "number" || !Number.isFinite(ms))
120
+ return DEFAULT_POLL_INTERVAL_MS;
121
+ return Math.min(MAX_POLL_INTERVAL_MS, Math.max(MIN_POLL_INTERVAL_MS, Math.round(ms)));
122
+ }
123
+ /**
124
+ * Espera ate a proxima consulta: intervalo, dobrado a cada falha seguida (ate 5 min), com jitter de -10% a +10%, e nunca acima de 5 min (o teto vale depois do jitter).
125
+ * `random` entra de fora (0 a 1) para o resultado ser testavel.
126
+ */
127
+ export function nextPollDelay(baseMs, failures, random) {
128
+ const base = clampPollInterval(baseMs);
129
+ const doublings = Number.isFinite(failures) ? Math.min(Math.max(0, Math.trunc(failures)), 6) : 0;
130
+ const backoff = Math.min(base * 2 ** doublings, MAX_POLL_BACKOFF_MS);
131
+ const r = Number.isFinite(random) ? Math.min(1, Math.max(0, random)) : 0.5;
132
+ return Math.min(MAX_POLL_BACKOFF_MS, Math.round(backoff * (0.9 + 0.2 * r)));
133
+ }
134
+ export const EMPTY_POLLING_STATS = { count: 0, lastAt: null, reason: null };
135
+ export function recordPollingTick(stats, at, reason) {
136
+ return { count: stats.count + 1, lastAt: at, reason };
137
+ }
138
+ /**
139
+ * Qual das telas mostrar. Com erro e lista ja carregada, a lista continua (a falha vira aviso); sem nada para
140
+ * mostrar, erro vence vazio.
141
+ */
142
+ export function viewState(input) {
143
+ if (input.count > 0)
144
+ return "list";
145
+ if (input.failed)
146
+ return "error";
147
+ if (!input.loaded)
148
+ return "loading";
149
+ return input.unreadOnly ? "caughtUp" : "empty";
150
+ }
151
+ /** O que a lista mostra: em "Nao lidas" so as ainda nao clicadas; em "Todas", tudo. */
152
+ export function visibleItems(items, unreadOnly) {
153
+ return unreadOnly ? items.filter((n) => !n.read) : [...items];
154
+ }
155
+ /** Query da lista: em "Nao lidas" pede so as nao lidas ao servidor (`unreadOnly=true`, que ja entra na ETag). */
156
+ export function listQuery(page, size, unreadOnly) {
157
+ return `?page=${page}&size=${size}${unreadOnly ? "&unreadOnly=true" : ""}`;
158
+ }
159
+ /** Clicou numa notificacao: em "Nao lidas" ela sai da lista; em "Todas" so perde o destaque. */
160
+ export function afterOpen(items, publicId, unreadOnly, readAt) {
161
+ return unreadOnly ? removeNotification(items, publicId) : markRead(items, publicId, readAt);
162
+ }
163
+ /** Valor inicial do interruptor: sem interruptor, o painel mostra tudo; com ele, vale `defaultUnreadOnly` (padrao true). */
164
+ export function initialUnreadOnly(showUnreadToggle, defaultUnreadOnly) {
165
+ if (showUnreadToggle === false)
166
+ return false;
167
+ return defaultUnreadOnly ?? true;
168
+ }
169
+ /** Idade da notificacao em partes; o texto ("ha 5 min") e do i18n de cada plataforma. */
170
+ /** Data que da para mostrar (um `createdAt` invalido nao vira 1970 na tela). */
171
+ export function isValidInstant(iso) {
172
+ return !Number.isNaN(Date.parse(iso.replace(/(.d{3})d+/, "$1")));
173
+ }
174
+ export function relativeTime(createdAt, now) {
175
+ if (!isValidInstant(createdAt) || !isValidInstant(now))
176
+ return { unit: "date" };
177
+ const seconds = Math.floor((time(now) - time(createdAt)) / 1000);
178
+ if (seconds < 60)
179
+ return { unit: "now" };
180
+ const minutes = Math.floor(seconds / 60);
181
+ if (minutes < 60)
182
+ return { unit: "minute", value: minutes };
183
+ const hours = Math.floor(minutes / 60);
184
+ if (hours < 24)
185
+ return { unit: "hour", value: hours };
186
+ const days = Math.floor(hours / 24);
187
+ if (days < 7)
188
+ return { unit: "day", value: days };
189
+ return { unit: "date" };
190
+ }
191
+ /** Largura do painel (26rem) e altura maxima (32rem), em px. */
192
+ export const PANEL_WIDTH = 416;
193
+ export const PANEL_MAX_HEIGHT = 512;
194
+ function clampNumber(value, min, max) {
195
+ return Math.max(min, Math.min(value, Math.max(min, max)));
196
+ }
197
+ /**
198
+ * Onde o painel fica, em coordenadas da janela, sem sair dela. `auto` tenta embaixo, em cima, a direita e a esquerda
199
+ * (nessa ordem) e fica com o primeiro lado em que o painel cabe inteiro; se nenhum couber, usa embaixo ou em cima,
200
+ * o que tiver mais espaco. O lado forcado (`top`, `right`...) e respeitado. O painel se alinha ao fim do sino e e
201
+ * empurrado para dentro da janela. `panelHeight` e a altura real do painel (ate PANEL_MAX_HEIGHT).
202
+ */
203
+ export function panelPosition(anchor, panel, viewport, placement = "auto", offset = 8, padding = 8) {
204
+ const width = Math.min(panel.width, viewport.width - padding * 2);
205
+ const height = Math.min(panel.height, PANEL_MAX_HEIGHT, viewport.height - padding * 2);
206
+ const space = {
207
+ top: anchor.top - padding,
208
+ bottom: viewport.height - anchor.bottom - padding,
209
+ left: anchor.left - padding,
210
+ right: viewport.width - anchor.right - padding
211
+ };
212
+ const fits = {
213
+ bottom: space.bottom >= height + offset,
214
+ top: space.top >= height + offset,
215
+ right: space.right >= width + offset,
216
+ left: space.left >= width + offset
217
+ };
218
+ let side;
219
+ if (placement !== "auto")
220
+ side = placement;
221
+ else if (fits.bottom)
222
+ side = "bottom";
223
+ else if (fits.top)
224
+ side = "top";
225
+ else if (fits.right)
226
+ side = "right";
227
+ else if (fits.left)
228
+ side = "left";
229
+ else
230
+ side = space.bottom >= space.top ? "bottom" : "top";
231
+ let top;
232
+ let left;
233
+ if (side === "bottom" || side === "top") {
234
+ left = clampNumber(anchor.right - width, padding, viewport.width - width - padding);
235
+ top = side === "bottom" ? anchor.bottom + offset : anchor.top - offset - height;
236
+ }
237
+ else {
238
+ top = clampNumber(anchor.top, padding, viewport.height - height - padding);
239
+ left = side === "right" ? anchor.right + offset : anchor.left - offset - width;
240
+ }
241
+ top = clampNumber(top, padding, viewport.height - height - padding);
242
+ left = clampNumber(left, padding, viewport.width - width - padding);
243
+ return { top: Math.round(top), left: Math.round(left), side, maxHeight: Math.round(height) };
244
+ }
@@ -7,7 +7,7 @@ export type SgConfirmationDialogButtonConfig = {
7
7
  severity?: SgButtonProps["severity"];
8
8
  appearance?: SgButtonProps["appearance"];
9
9
  shape?: SgButtonProps["shape"];
10
- disabled?: boolean;
10
+ enabled?: boolean;
11
11
  className?: string;
12
12
  onClick?: () => void;
13
13
  };
@@ -1 +1 @@
1
- {"version":3,"file":"SgConfirmationDialog.d.ts","sourceRoot":"","sources":["../../src/overlay/SgConfirmationDialog.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAY,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEnE,OAAO,EAAY,KAAK,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEjF,MAAM,MAAM,gCAAgC,GAAG;IAC7C,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,QAAQ,CAAC,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IACrC,UAAU,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACzC,KAAK,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAC1C,aAAa,EACb,OAAO,GAAG,UAAU,GAAG,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,eAAe,CAC1E,GAAG;IACF,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC/B,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,WAAW,CAAC,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IAC3C,SAAS,CAAC,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IACvC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,YAAY,CAAC,EAAE,gCAAgC,CAAC;IAChD,aAAa,CAAC,EAAE,gCAAgC,CAAC;IACjD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAoEF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,yBAAyB,CAAC,2CA2J9E;yBA3Je,oBAAoB"}
1
+ {"version":3,"file":"SgConfirmationDialog.d.ts","sourceRoot":"","sources":["../../src/overlay/SgConfirmationDialog.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAY,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEnE,OAAO,EAAY,KAAK,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEjF,MAAM,MAAM,gCAAgC,GAAG;IAC7C,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,QAAQ,CAAC,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IACrC,UAAU,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACzC,KAAK,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAC1C,aAAa,EACb,OAAO,GAAG,UAAU,GAAG,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,eAAe,CAC1E,GAAG;IACF,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC/B,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,WAAW,CAAC,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IAC3C,SAAS,CAAC,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IACvC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,YAAY,CAAC,EAAE,gCAAgC,CAAC;IAChD,aAAa,CAAC,EAAE,gCAAgC,CAAC;IACjD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAoEF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,yBAAyB,CAAC,2CA2J9E;yBA3Je,oBAAoB"}
@@ -90,6 +90,6 @@ export function SgConfirmationDialog(props) {
90
90
  }
91
91
  : undefined;
92
92
  const messageBlock = (_jsx("div", { className: "text-sm text-muted-foreground", children: message }));
93
- return (_jsx(SgDialog, { ...dialogProps, open: open, onOpenChange: handleDialogOpenChange, onClose: onClose, closeable: closeable, severity: severity, showTopAccent: showSeverityAccent, customColor: customColor, elevation: elevation, title: title, size: size, footer: (_jsxs(_Fragment, { children: [_jsx(SgButton, { size: "sm", appearance: cancelButton?.appearance ?? "outline", severity: cancelSeverity, shape: cancelButton?.shape ?? "rounded", disabled: cancelButton?.disabled, className: cancelButton?.className, customColors: resolvedCancelCustomColors, leftIcon: cancelIcon, onClick: handleCancel, children: cancelLabel }), _jsx(SgButton, { size: "sm", appearance: confirmButton?.appearance ?? "solid", severity: confirmSeverity, shape: confirmButton?.shape ?? "rounded", disabled: confirmButton?.disabled, className: confirmButton?.className, leftIcon: confirmIcon, onClick: handleConfirm, children: confirmLabel })] })), children: resolvedIcon ? (iconPlacement === "top" ? (_jsxs("div", { className: "flex flex-col items-start gap-3", children: [_jsx("div", { className: "shrink-0", children: resolvedIcon }), messageBlock] })) : (_jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "shrink-0", children: resolvedIcon }), _jsx("div", { className: "min-w-0", children: messageBlock })] }))) : (messageBlock) }));
93
+ return (_jsx(SgDialog, { ...dialogProps, open: open, onOpenChange: handleDialogOpenChange, onClose: onClose, closeable: closeable, severity: severity, showTopAccent: showSeverityAccent, customColor: customColor, elevation: elevation, title: title, size: size, footer: (_jsxs(_Fragment, { children: [_jsx(SgButton, { size: "sm", appearance: cancelButton?.appearance ?? "outline", severity: cancelSeverity, shape: cancelButton?.shape ?? "rounded", enabled: !((cancelButton?.enabled === false)), className: cancelButton?.className, customColors: resolvedCancelCustomColors, leftIcon: cancelIcon, onClick: handleCancel, children: cancelLabel }), _jsx(SgButton, { size: "sm", appearance: confirmButton?.appearance ?? "solid", severity: confirmSeverity, shape: confirmButton?.shape ?? "rounded", enabled: !((confirmButton?.enabled === false)), className: confirmButton?.className, leftIcon: confirmIcon, onClick: handleConfirm, children: confirmLabel })] })), children: resolvedIcon ? (iconPlacement === "top" ? (_jsxs("div", { className: "flex flex-col items-start gap-3", children: [_jsx("div", { className: "shrink-0", children: resolvedIcon }), messageBlock] })) : (_jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "shrink-0", children: resolvedIcon }), _jsx("div", { className: "min-w-0", children: messageBlock })] }))) : (messageBlock) }));
94
94
  }
95
95
  SgConfirmationDialog.displayName = "SgConfirmationDialog";
@@ -8,7 +8,7 @@ export type SgPopupAction = {
8
8
  label: string;
9
9
  hint?: string;
10
10
  severity?: SgPopupSeverity;
11
- disabled?: boolean;
11
+ enabled?: boolean;
12
12
  closeOnClick?: boolean;
13
13
  onClick?: () => void;
14
14
  };
@@ -1 +1 @@
1
- {"version":3,"file":"SgPopup.d.ts","sourceRoot":"","sources":["../../src/overlay/SgPopup.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAoB/B,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAC5E,MAAM,MAAM,sBAAsB,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AACzE,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEtD,MAAM,MAAM,eAAe,GACvB,SAAS,GACT,WAAW,GACX,SAAS,GACT,MAAM,GACN,SAAS,GACT,MAAM,GACN,QAAQ,GACR,OAAO,CAAC;AAEZ,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAExC,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,eAAe,CAAC,EAAE,sBAAsB,CAAC;IACzC,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAE3B,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,CAAC;AAwHF,wBAAgB,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,YAAY,CAAC,4BA4LpD;yBA5Le,OAAO"}
1
+ {"version":3,"file":"SgPopup.d.ts","sourceRoot":"","sources":["../../src/overlay/SgPopup.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAoB/B,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAC5E,MAAM,MAAM,sBAAsB,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AACzE,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEtD,MAAM,MAAM,eAAe,GACvB,SAAS,GACT,WAAW,GACX,SAAS,GACT,MAAM,GACN,SAAS,GACT,MAAM,GACN,QAAQ,GACR,OAAO,CAAC;AAEZ,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAExC,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,eAAe,CAAC,EAAE,sBAAsB,CAAC;IACzC,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAE3B,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,CAAC;AAwHF,wBAAgB,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,YAAY,CAAC,4BA4LpD;yBA5Le,OAAO"}
@@ -210,7 +210,7 @@ export function SgPopup(props) {
210
210
  }, role: "dialog", "aria-modal": "false", "aria-label": resolvedAriaLabel, children: [title ? (_jsx("div", { className: "bg-primary px-3 py-2 text-xs font-medium text-primary-foreground", children: title })) : null, subtitle ? (_jsx("div", { className: "border-b border-border bg-background px-3 py-2 text-xs text-muted-foreground", children: subtitle })) : null, children ? _jsx("div", { className: "p-2", children: children }) : null, actions && actions.length > 0 ? (_jsx("div", { className: cn(children ? "border-t border-border" : "", "p-1"), children: actions.map((a, idx) => {
211
211
  const hasSeverity = a.severity !== undefined;
212
212
  const sev = a.severity ?? "plain";
213
- return (_jsx("button", { type: "button", disabled: a.disabled, title: a.hint, className: cn("w-full select-none rounded px-3 py-2 text-left text-sm", "transition-[filter,background-color] duration-150", "disabled:opacity-50 disabled:cursor-not-allowed", idx > 0 ? "border-t border-border" : "", hasSeverity ? ACTION_CLS[sev] : ACTION_DEFAULT_CLS), onClick: () => {
213
+ return (_jsx("button", { type: "button", disabled: a.enabled === false, title: a.hint, className: cn("w-full select-none rounded px-3 py-2 text-left text-sm", "transition-[filter,background-color] duration-150", "disabled:opacity-50 disabled:cursor-not-allowed", idx > 0 ? "border-t border-border" : "", hasSeverity ? ACTION_CLS[sev] : ACTION_DEFAULT_CLS), onClick: () => {
214
214
  a.onClick?.();
215
215
  if (a.closeOnClick ?? true)
216
216
  close();
@@ -63,6 +63,11 @@ export declare function matchesSgRealtimeEvent(pattern: string, event: string):
63
63
  * {@link SgRealtimeProvider}, não faz nada.
64
64
  */
65
65
  export declare function useSgRealtimeEvent(channel: string, events: string | string[], handler: (event: SgRealtimeEvent) => void): void;
66
+ /**
67
+ * Ha um {@link SgRealtimeProvider} acima? Com `channel`, so conta se ele assina esse channel (o sino so reaproveita a
68
+ * conexao que ouve `user-notifications`; senao ficaria surdo e abre a propria).
69
+ */
70
+ export declare function useHasSgRealtimeProvider(channel?: string): boolean;
66
71
  /** Estado do realtime. `connected` falso ⇒ a tela usa o polling de reserva. */
67
72
  export declare function useSgRealtimeStatus(): {
68
73
  status: SgRealtimeStatus;
@@ -1 +1 @@
1
- {"version":3,"file":"SgRealtimeProvider.d.ts","sourceRoot":"","sources":["../../src/realtime/SgRealtimeProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAEL,KAAK,YAAY,EAIlB,MAAM,uCAAuC,CAAC;AAE/C;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,cAAc,GAAG,aAAa,GAAG,YAAY,CAAC;AAEhI,oFAAoF;AACpF,MAAM,MAAM,yBAAyB,GAAG;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB,CAAC;AAEF,4FAA4F;AAC5F,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gGAAgG;IAChG,gBAAgB,CAAC,EAAE,WAAW,CAAC;IAC/B,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACtD,kGAAkG;IAClG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,sFAAsF;IACtF,cAAc,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,UAAU,GAAG,YAAY,GAAG,SAAS,CAAC,CAAC;CAC5E,CAAC;AAuCF;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,QAAQ,EACR,aAAsC,EACtC,gBAAgB,EAChB,UAAU,EACV,QAAQ,EACR,OAAc,EACd,cAAc,EACf,EAAE,uBAAuB,2CAkGzB;AAED,oFAAoF;AACpF,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAO9E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,EACzB,OAAO,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,GACxC,IAAI,CAeN;AAED,+EAA+E;AAC/E,wBAAgB,mBAAmB,IAAI;IAAE,MAAM,EAAE,gBAAgB,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAItF"}
1
+ {"version":3,"file":"SgRealtimeProvider.d.ts","sourceRoot":"","sources":["../../src/realtime/SgRealtimeProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAEL,KAAK,YAAY,EAIlB,MAAM,uCAAuC,CAAC;AAE/C;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,cAAc,GAAG,aAAa,GAAG,YAAY,CAAC;AAEhI,oFAAoF;AACpF,MAAM,MAAM,yBAAyB,GAAG;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB,CAAC;AAEF,4FAA4F;AAC5F,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gGAAgG;IAChG,gBAAgB,CAAC,EAAE,WAAW,CAAC;IAC/B,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACtD,kGAAkG;IAClG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,sFAAsF;IACtF,cAAc,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,UAAU,GAAG,YAAY,GAAG,SAAS,CAAC,CAAC;CAC5E,CAAC;AAyCF;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,QAAQ,EACR,aAAsC,EACtC,gBAAgB,EAChB,UAAU,EACV,QAAQ,EACR,OAAc,EACd,cAAc,EACf,EAAE,uBAAuB,2CA6GzB;AAED,oFAAoF;AACpF,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAO9E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,EACzB,OAAO,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,GACxC,IAAI,CAeN;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAIlE;AAED,+EAA+E;AAC/E,wBAAgB,mBAAmB,IAAI;IAAE,MAAM,EAAE,gBAAgB,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAItF"}
@@ -22,7 +22,7 @@ function mapState(state) {
22
22
  }
23
23
  }
24
24
  async function requestToken(endpoint, init) {
25
- const response = await fetch(endpoint, { method: "POST", credentials: "same-origin", ...init });
25
+ const response = await fetch(endpoint, { credentials: "same-origin", ...init, method: "POST" });
26
26
  if (!response.ok) {
27
27
  throw new Error(`token de realtime indisponivel (HTTP ${response.status})`);
28
28
  }
@@ -49,6 +49,7 @@ export function SgRealtimeProvider({ children, channels, tokenEndpoint = DEFAULT
49
49
  return undefined;
50
50
  }
51
51
  let cancelled = false;
52
+ let retryTimer;
52
53
  const client = new PulseSubscriberClient();
53
54
  const getConnectResponse = () => {
54
55
  const { tokenEndpoint: endpoint, tokenRequestInit: init, fetchToken: custom } = optionsRef.current;
@@ -77,14 +78,24 @@ export function SgRealtimeProvider({ children, channels, tokenEndpoint = DEFAULT
77
78
  });
78
79
  void (async () => {
79
80
  setStatus("connecting");
81
+ // Falha temporaria (503, 429, rede) nao e definitiva: fica "unavailable" (a tela usa o polling) e tenta de novo
82
+ // com espera crescente (5 s ate 60 s). So `enabled:false` e definitivo.
80
83
  let first;
81
- try {
82
- first = await getConnectResponse();
83
- }
84
- catch {
85
- if (!cancelled)
84
+ for (let attempt = 0; !first; attempt += 1) {
85
+ try {
86
+ first = await getConnectResponse();
87
+ }
88
+ catch {
89
+ if (cancelled)
90
+ return;
86
91
  setStatus("unavailable");
87
- return;
92
+ await new Promise((resolve) => {
93
+ retryTimer = setTimeout(resolve, Math.min(60000, 5000 * 2 ** attempt));
94
+ });
95
+ if (cancelled)
96
+ return;
97
+ setStatus("connecting");
98
+ }
88
99
  }
89
100
  if (cancelled)
90
101
  return;
@@ -118,6 +129,8 @@ export function SgRealtimeProvider({ children, channels, tokenEndpoint = DEFAULT
118
129
  })();
119
130
  return () => {
120
131
  cancelled = true;
132
+ if (retryTimer)
133
+ clearTimeout(retryTimer);
121
134
  offState();
122
135
  offMessage();
123
136
  void client.disconnect().catch(() => undefined);
@@ -129,7 +142,7 @@ export function SgRealtimeProvider({ children, channels, tokenEndpoint = DEFAULT
129
142
  listenersRef.current.delete(listener);
130
143
  };
131
144
  }, []);
132
- const value = React.useMemo(() => ({ status, addListener }), [status, addListener]);
145
+ const value = React.useMemo(() => ({ status, channels, addListener }), [status, channelsKey, addListener]);
133
146
  return _jsx(SgRealtimeContext.Provider, { value: value, children: children });
134
147
  }
135
148
  /** `backup.finished.*` casa `backup.finished.success` e `backup.finished.error`. */
@@ -162,6 +175,16 @@ export function useSgRealtimeEvent(channel, events, handler) {
162
175
  });
163
176
  }, [context, channel, patterns]);
164
177
  }
178
+ /**
179
+ * Ha um {@link SgRealtimeProvider} acima? Com `channel`, so conta se ele assina esse channel (o sino so reaproveita a
180
+ * conexao que ouve `user-notifications`; senao ficaria surdo e abre a propria).
181
+ */
182
+ export function useHasSgRealtimeProvider(channel) {
183
+ const context = React.useContext(SgRealtimeContext);
184
+ if (!context)
185
+ return false;
186
+ return channel === undefined || context.channels.includes(channel);
187
+ }
165
188
  /** Estado do realtime. `connected` falso ⇒ a tela usa o polling de reserva. */
166
189
  export function useSgRealtimeStatus() {
167
190
  const context = React.useContext(SgRealtimeContext);