@omniloy/sofia-sdk 1.0.3 → 1.0.5

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.
@@ -646,6 +646,74 @@
646
646
  color: var(--color-gray-600, #4b5563);
647
647
  }
648
648
 
649
+ /* Connection status pill - inline banner replacing toasts.
650
+ Three states: reconnecting (neutral), disconnected (red), restored (dark). */
651
+ .omniscribe_connection-pill {
652
+ display: inline-flex;
653
+ align-items: center;
654
+ gap: 6px;
655
+ padding: 4px 10px;
656
+ border-radius: 9999px;
657
+ white-space: nowrap;
658
+ flex-shrink: 0;
659
+ font-weight: 500;
660
+ margin-inline: 8px;
661
+ }
662
+
663
+ .omniscribe_connection-pill-icon {
664
+ display: inline-flex;
665
+ align-items: center;
666
+ justify-content: center;
667
+ }
668
+
669
+ .omniscribe_connection-pill-icon--spin {
670
+ animation: omniscribe-connection-spin 1s linear infinite;
671
+ }
672
+
673
+ @keyframes omniscribe-connection-spin {
674
+ from {
675
+ transform: rotate(0deg);
676
+ }
677
+ to {
678
+ transform: rotate(360deg);
679
+ }
680
+ }
681
+
682
+ .omniscribe_connection-pill--reconnecting {
683
+ background-color: var(--color-gray-50, #f9fafb);
684
+ border: 1px solid var(--color-gray-200, #e5e7eb);
685
+ color: var(--color-gray-700, #374151);
686
+ }
687
+
688
+ .omniscribe_connection-pill--disconnected {
689
+ background-color: #fdecec;
690
+ border: 1px solid #f8c7c7;
691
+ color: #b42318;
692
+ padding-right: 4px;
693
+ }
694
+
695
+ .omniscribe_connection-pill--restored {
696
+ background-color: #1f2937;
697
+ border: 1px solid #1f2937;
698
+ color: #ffffff;
699
+ }
700
+
701
+ .omniscribe_connection-pill-retry {
702
+ border-radius: 9999px !important;
703
+ gap: 4px;
704
+ padding-block: 3px !important;
705
+ padding-inline: 8px !important;
706
+ height: auto !important;
707
+ background-color: #d92d20 !important;
708
+ color: #ffffff !important;
709
+ border: none !important;
710
+ margin-left: 2px;
711
+ }
712
+
713
+ .omniscribe_connection-pill-retry:hover:not(:disabled) {
714
+ background-color: #b42318 !important;
715
+ }
716
+
649
717
  /* Generate Report Button - Figma style */
650
718
  .omniscribe_transcribe-generate-btn {
651
719
  border-radius: 12px !important;
@@ -900,6 +968,236 @@
900
968
  background-color: color-mix(in oklab, var(--report) 60%, transparent);
901
969
  }
902
970
  }
971
+ .omniscribe_modal-overlay {
972
+ position: absolute;
973
+ background-color: color-mix(in oklab, var(--black) 50%, transparent);
974
+ display: flex;
975
+ justify-content: center;
976
+ align-items: center;
977
+ z-index: 50;
978
+ height: 100vh;
979
+ width: 100vw;
980
+ right: 0;
981
+ bottom: calc(var(--spacing) * -5.2);
982
+ }
983
+
984
+ .omniscribe_modal-container {
985
+ position: relative;
986
+ background-color: var(--white);
987
+ z-index: 100;
988
+ border-radius: 12px;
989
+ border: solid 1px var(--light-border);
990
+ box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);
991
+ padding: calc(var(--spacing) * 5);
992
+ transition-duration: 300ms;
993
+ transition-property: opacity;
994
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
995
+ max-width: 90vw;
996
+ max-height: 90vh;
997
+ }
998
+ .omniscribe_modal-container-scroll {
999
+ overflow: auto;
1000
+ }
1001
+
1002
+ .omniscribe_modal-container-show {
1003
+ opacity: 100%;
1004
+ }
1005
+
1006
+ .omniscribe_modal-container-hide {
1007
+ opacity: 0%;
1008
+ }
1009
+
1010
+ .omniscribe_modal-subcontainer {
1011
+ display: flex;
1012
+ flex-direction: column;
1013
+ }
1014
+
1015
+ .omniscribe_modal-title-container {
1016
+ display: flex;
1017
+ flex-direction: row;
1018
+ align-items: center;
1019
+ justify-content: space-between;
1020
+ margin-bottom: calc(var(--spacing) * 2);
1021
+ }
1022
+
1023
+ .omniscribe_modal-title {
1024
+ font-size: var(--text-3xl); /* 1.875rem = 30px */
1025
+ line-height: var(--text-xl--line-height);
1026
+ font-weight: var(--font-weight-bold);
1027
+ margin: 0;
1028
+ }
1029
+
1030
+ .omniscribe_modal-button {
1031
+ border: none;
1032
+ background: transparent;
1033
+ line-height: var(--text-2xl--line-height);
1034
+ cursor: pointer;
1035
+ color: var(--black);
1036
+ }
1037
+
1038
+ @media (min-width: 768px) {
1039
+ .omniscribe_modal-container {
1040
+ max-width: 60vw;
1041
+ }
1042
+ }
1043
+
1044
+ /* Large screens: desktop */
1045
+ @media (min-width: 1024px) {
1046
+ .omniscribe_modal-container {
1047
+ max-width: 50vw;
1048
+ }
1049
+ }
1050
+
1051
+ /* Very large screens: large desktop and ultra-wide */
1052
+ @media (min-width: 1440px) {
1053
+ .omniscribe_modal-container {
1054
+ max-width: 40vw;
1055
+ }
1056
+ }
1057
+
1058
+ /* Intermediate breakpoint: large tablets */
1059
+ @media (min-width: 640px) and (max-width: 767px) {
1060
+ .omniscribe_modal-container {
1061
+ max-width: 70vw;
1062
+ }
1063
+ }
1064
+ /* The shared Modal overlay uses position: absolute anchored to its
1065
+ nearest positioned ancestor — which in our case is the chat footer,
1066
+ not the widget root. That puts the modal at the bottom of the widget.
1067
+ Override to position: fixed so the overlay covers the full viewport
1068
+ and the modal truly centers regardless of where in the React tree it
1069
+ was rendered. */
1070
+ .omniscribe_modal-overlay:has(.omniscribe_audio-cuts-modal) {
1071
+ position: fixed;
1072
+ inset: 0;
1073
+ width: 100%;
1074
+ height: 100%;
1075
+ top: 0;
1076
+ left: 0;
1077
+ bottom: 0;
1078
+ right: 0;
1079
+ }
1080
+
1081
+ .omniscribe_audio-cuts-modal {
1082
+ width: 480px;
1083
+ max-width: 90vw;
1084
+ padding: 24px !important;
1085
+ }
1086
+
1087
+ /* Override Modal's giant default h2 size for this dialog. */
1088
+ .omniscribe_audio-cuts-modal .omniscribe_modal-title-container {
1089
+ margin-bottom: 16px;
1090
+ align-items: flex-start;
1091
+ }
1092
+
1093
+ .omniscribe_audio-cuts-modal .omniscribe_modal-title {
1094
+ font-size: 18px;
1095
+ line-height: 1.3;
1096
+ font-weight: 700;
1097
+ letter-spacing: -0.01em;
1098
+ color: var(--color-gray-900, #0f172a);
1099
+ }
1100
+
1101
+ .omniscribe_audio-cuts-body {
1102
+ display: flex;
1103
+ flex-direction: column;
1104
+ gap: 16px;
1105
+ }
1106
+
1107
+ /* Summary card: warning icon + paragraph in a soft container. */
1108
+ .omniscribe_audio-cuts-summary {
1109
+ display: flex;
1110
+ align-items: flex-start;
1111
+ gap: 12px;
1112
+ }
1113
+
1114
+ .omniscribe_audio-cuts-summary-icon {
1115
+ display: inline-flex;
1116
+ align-items: center;
1117
+ justify-content: center;
1118
+ flex-shrink: 0;
1119
+ width: 32px;
1120
+ height: 32px;
1121
+ border-radius: 9999px;
1122
+ background-color: #fef3c7;
1123
+ color: #b45309;
1124
+ }
1125
+
1126
+ .omniscribe_audio-cuts-summary-text {
1127
+ margin: 0;
1128
+ font-size: 14px;
1129
+ line-height: 1.5;
1130
+ color: var(--color-gray-800, #1f2937);
1131
+ flex: 1;
1132
+ }
1133
+
1134
+ /* Cut list: rounded gray container, clock icon per row, no bullets. */
1135
+ .omniscribe_audio-cuts-list {
1136
+ margin: 0;
1137
+ padding: 12px 14px;
1138
+ border-radius: 12px;
1139
+ background-color: var(--color-gray-50, #f9fafb);
1140
+ border: 1px solid var(--color-gray-200, #e5e7eb);
1141
+ list-style: none;
1142
+ max-height: 240px;
1143
+ overflow-y: auto;
1144
+ display: flex;
1145
+ flex-direction: column;
1146
+ gap: 8px;
1147
+ }
1148
+
1149
+ .omniscribe_audio-cuts-item {
1150
+ display: flex;
1151
+ align-items: center;
1152
+ gap: 8px;
1153
+ color: var(--color-gray-700, #374151);
1154
+ font-variant-numeric: tabular-nums;
1155
+ font-size: 13px;
1156
+ line-height: 1.4;
1157
+ }
1158
+
1159
+ .omniscribe_audio-cuts-item-icon {
1160
+ display: inline-flex;
1161
+ align-items: center;
1162
+ justify-content: center;
1163
+ flex-shrink: 0;
1164
+ color: var(--color-gray-500, #6b7280);
1165
+ }
1166
+
1167
+ /* Action row: right-aligned, secondary as text-link, primary as blue pill. */
1168
+ .omniscribe_audio-cuts-actions {
1169
+ display: flex;
1170
+ justify-content: flex-end;
1171
+ align-items: center;
1172
+ gap: 16px;
1173
+ margin-top: 4px;
1174
+ }
1175
+
1176
+ .omniscribe_audio-cuts-secondary {
1177
+ background: transparent;
1178
+ border: none;
1179
+ cursor: pointer;
1180
+ padding: 8px 12px;
1181
+ font-size: 14px;
1182
+ font-weight: 500;
1183
+ color: var(--color-gray-700, #374151);
1184
+ border-radius: 9999px;
1185
+ transition: background-color 0.15s ease;
1186
+ }
1187
+
1188
+ .omniscribe_audio-cuts-secondary:hover {
1189
+ background-color: var(--color-gray-100, #f3f4f6);
1190
+ color: var(--color-gray-900, #0f172a);
1191
+ }
1192
+
1193
+ .omniscribe_audio-cuts-primary {
1194
+ border-radius: 9999px !important;
1195
+ gap: 8px;
1196
+ padding-block: 10px !important;
1197
+ padding-inline: 18px !important;
1198
+ height: auto !important;
1199
+ font-weight: 600;
1200
+ }
903
1201
  /* Draggable Collapsed Container */
904
1202
  .omniscribe_draggable-collapsed {
905
1203
  position: fixed;
@@ -3755,6 +4053,34 @@
3755
4053
  line-height: 1.7 !important;
3756
4054
  }
3757
4055
 
4056
+ /* Audio-loss divider rendered between segments where a recording cut
4057
+ occurred. Visually separates captured speech from the gap so the doctor
4058
+ can spot lost portions while reviewing the transcription. */
4059
+ .omniscribe_transcription-panel-cut {
4060
+ display: flex;
4061
+ align-items: center;
4062
+ gap: 8px;
4063
+ margin-block: 10px;
4064
+ padding-inline: 4px;
4065
+ }
4066
+
4067
+ .omniscribe_transcription-panel-cut-line {
4068
+ flex: 1;
4069
+ height: 1px;
4070
+ background-color: #fed7aa;
4071
+ }
4072
+
4073
+ .omniscribe_transcription-panel-cut-label {
4074
+ flex-shrink: 0;
4075
+ padding: 2px 10px;
4076
+ border-radius: 9999px;
4077
+ background-color: #fff7ed;
4078
+ border: 1px solid #fed7aa;
4079
+ color: #c2410c;
4080
+ font-weight: 600;
4081
+ font-variant-numeric: tabular-nums;
4082
+ }
4083
+
3758
4084
  /* Scrollbar styles */
3759
4085
  .omniscribe_transcription-panel-content::-webkit-scrollbar {
3760
4086
  width: 6px;
@@ -3927,29 +4253,42 @@
3927
4253
  cursor: pointer;
3928
4254
  display: inline-block;
3929
4255
  }
3930
- .omniscribe_toast-container {
4256
+ .omniscribe_toast-stack {
3931
4257
  position: fixed;
3932
- bottom: calc(var(--spacing) * 5);
3933
- top: calc(var(--spacing) * -30);
4258
+ top: calc(var(--spacing) * 4);
4259
+ right: calc(var(--spacing) * 4);
4260
+ display: flex;
4261
+ flex-direction: column;
4262
+ gap: calc(var(--spacing) * 2);
4263
+ z-index: 9999;
4264
+ pointer-events: none;
4265
+ }
4266
+
4267
+ .omniscribe_toast-item {
3934
4268
  border-radius: var(--radius);
3935
4269
  padding: calc(var(--spacing) * 4);
3936
- height: fit-content;
3937
- transition-duration: 500ms;
3938
- transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
3939
4270
  width: calc(var(--spacing) * 120);
4271
+ display: flex;
4272
+ align-items: flex-start;
4273
+ transition:
4274
+ transform 300ms cubic-bezier(0.4, 0, 0.2, 1),
4275
+ opacity 300ms cubic-bezier(0.4, 0, 0.2, 1);
4276
+ pointer-events: auto;
3940
4277
  }
3941
4278
 
3942
- .omniscribe_toast-container-danger {
4279
+ .omniscribe_toast-item-danger {
3943
4280
  background-color: var(--color-red-500);
3944
4281
  }
3945
- .omniscribe_toast-container-black {
4282
+ .omniscribe_toast-item-black {
3946
4283
  background-color: var(--black);
3947
4284
  }
3948
- .omniscribe_toast-container-show {
3949
- right: calc(var(--spacing) * 10);
4285
+ .omniscribe_toast-item-show {
4286
+ transform: translateX(0);
4287
+ opacity: 1;
3950
4288
  }
3951
- .omniscribe_toast-container-hide {
3952
- right: -100%;
4289
+ .omniscribe_toast-item-hide {
4290
+ transform: translateX(120%);
4291
+ opacity: 0;
3953
4292
  }
3954
4293
  .omniscribe_toast-subcontainer {
3955
4294
  transition-property: opacity;
@@ -3958,6 +4297,7 @@
3958
4297
  display: flex;
3959
4298
  flex-direction: column;
3960
4299
  color: var(--white);
4300
+ flex: 1;
3961
4301
  }
3962
4302
  .omniscribe_toast-title {
3963
4303
  font-size: 18px;
@@ -3966,6 +4306,19 @@
3966
4306
  .omniscribe_toast-msg {
3967
4307
  font-size: 16px;
3968
4308
  }
4309
+ .omniscribe_toast-close {
4310
+ background: none;
4311
+ border: none;
4312
+ color: var(--white);
4313
+ font-size: 18px;
4314
+ cursor: pointer;
4315
+ padding: calc(var(--spacing) * 1) calc(var(--spacing) * 2);
4316
+ align-self: flex-start;
4317
+ opacity: 0.8;
4318
+ }
4319
+ .omniscribe_toast-close:hover {
4320
+ opacity: 1;
4321
+ }
3969
4322
  .omniscribe_select-container {
3970
4323
  position: relative;
3971
4324
  width: 100%;
@@ -3,7 +3,7 @@ import { JSX } from 'react/jsx-runtime';
3
3
  import * as React_2 from 'react';
4
4
  import { VariantProps } from 'class-variance-authority';
5
5
 
6
- export declare function Button({ className, variant, size, asChild, isDisabled, isLoading, text, whitespace, rounded, ...props }: ButtonProps): JSX.Element;
6
+ export declare function Button({ className, variant, size, asChild, isDisabled, isLoading, text, whitespace, rounded, type, ...props }: ButtonProps): JSX.Element;
7
7
 
8
8
  declare type ButtonProps = React_2.ComponentProps<'button'> & VariantProps<typeof buttonVariants> & {
9
9
  asChild?: boolean;
@@ -143,7 +143,23 @@ declare type TDayData = {
143
143
  patientId: string;
144
144
  doctorId: string;
145
145
  date: string;
146
- report: object;
146
+ report: object | undefined;
147
+ /** Last incremental extraction result (not the final report).
148
+ * Used as previous_extraction context when Generate fallback is triggered. */
149
+ lastExtraction?: object;
150
+ /** Auto-generated report sitting in storage waiting for the user to
151
+ * click Generate. Cleared (set to undefined) once the user consumes it
152
+ * via deliverReport, at which point the same payload is promoted to
153
+ * the `report` field. Stored separately so a reload doesn't make the
154
+ * UI think the user has already consumed it (which would switch the
155
+ * button to Regenerate). */
156
+ autoPendingReport?: object;
157
+ /** ISO timestamp set when the user clicks Generate. Cleared once the
158
+ * report is delivered. Persisted so a page reload mid-generation can
159
+ * restore the loading-state UI ("Generating..." while waiting for
160
+ * pendingReport / storage / API to resolve) without the user needing
161
+ * to click again. */
162
+ pendingClickAt?: string;
147
163
  transcript: TProcessedSegment[];
148
164
  transcriptionId?: string;
149
165
  clinicalNoteId?: string;
@@ -170,9 +186,8 @@ declare type TProcessedSegment = {
170
186
  declare type TRenderReport = (report: object, selected: string) => React_2.JSX.Element[] | React_2.JSX.Element;
171
187
 
172
188
  declare type TSegmentText = {
173
- speaker: string;
189
+ speaker?: string;
174
190
  text: string;
175
- speaker_id: string;
176
191
  }[];
177
192
 
178
193
  export declare type TToastState = {