@iblai/iblai-js 1.4.14 → 1.4.15

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.
@@ -55609,17 +55609,27 @@ var Close$1 = DialogClose$2;
55609
55609
 
55610
55610
  const Dialog$2 = Root$c;
55611
55611
  const DialogPortal$2 = Portal$7;
55612
- const DialogOverlay$2 = React.forwardRef(({ className, ...props }, ref) => (jsx(Overlay$2, { ref: ref, className: cn("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", className), ...props })));
55612
+ const DialogOverlay$2 = React.forwardRef(({ className, ...props }, ref) => (jsx(Overlay$2, { ref: ref, className: cn('fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0', className), ...props })));
55613
55613
  DialogOverlay$2.displayName = Overlay$2.displayName;
55614
- const DialogContent$2 = React.forwardRef(({ className, children, ...props }, ref) => (jsxs(DialogPortal$2, { children: [jsx(DialogOverlay$2, {}), jsxs(Content$4, { ref: ref, className: cn("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", className), ...props, children: [children, jsxs(Close$1, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [jsx(X$1, { className: "h-4 w-4" }), jsx("span", { className: "sr-only", children: "Close" })] })] })] })));
55614
+ const DialogContent$2 = React.forwardRef(({ className, children, onInteractOutside, ...props }, ref) => {
55615
+ const handleInteractOutside = (event) => {
55616
+ const target = event.target;
55617
+ if (target instanceof Element && target.closest('[data-iblai-dialog-interaction-layer]')) {
55618
+ event.preventDefault();
55619
+ return;
55620
+ }
55621
+ onInteractOutside === null || onInteractOutside === void 0 ? void 0 : onInteractOutside(event);
55622
+ };
55623
+ return (jsxs(DialogPortal$2, { children: [jsx(DialogOverlay$2, {}), jsxs(Content$4, { ref: ref, className: cn('fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg', className), onInteractOutside: handleInteractOutside, ...props, children: [children, jsxs(Close$1, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [jsx(X$1, { className: "h-4 w-4" }), jsx("span", { className: "sr-only", children: "Close" })] })] })] }));
55624
+ });
55615
55625
  DialogContent$2.displayName = Content$4.displayName;
55616
- const DialogHeader = ({ className, ...props }) => (jsx("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props }));
55617
- DialogHeader.displayName = "DialogHeader";
55618
- const DialogFooter = ({ className, ...props }) => (jsx("div", { className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className), ...props }));
55619
- DialogFooter.displayName = "DialogFooter";
55620
- const DialogTitle$2 = React.forwardRef(({ className, ...props }, ref) => (jsx(Title$1, { ref: ref, className: cn("text-lg font-semibold leading-none tracking-tight", className), ...props })));
55626
+ const DialogHeader = ({ className, ...props }) => (jsx("div", { className: cn('flex flex-col space-y-1.5 text-center sm:text-left', className), ...props }));
55627
+ DialogHeader.displayName = 'DialogHeader';
55628
+ const DialogFooter = ({ className, ...props }) => (jsx("div", { className: cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className), ...props }));
55629
+ DialogFooter.displayName = 'DialogFooter';
55630
+ const DialogTitle$2 = React.forwardRef(({ className, ...props }, ref) => (jsx(Title$1, { ref: ref, className: cn('text-lg font-semibold leading-none tracking-tight', className), ...props })));
55621
55631
  DialogTitle$2.displayName = Title$1.displayName;
55622
- const DialogDescription$2 = React.forwardRef(({ className, ...props }, ref) => (jsx(Description$1, { ref: ref, className: cn("text-sm text-muted-foreground", className), ...props })));
55632
+ const DialogDescription$2 = React.forwardRef(({ className, ...props }, ref) => (jsx(Description$1, { ref: ref, className: cn('text-sm text-muted-foreground', className), ...props })));
55623
55633
  DialogDescription$2.displayName = Description$1.displayName;
55624
55634
 
55625
55635
  const Security = ({ email, onAccountDeleted, }) => {
@@ -118413,7 +118423,13 @@ var Content2$1 = PopoverContent$1;
118413
118423
 
118414
118424
  const Popover = Root2$1;
118415
118425
  const PopoverTrigger = Trigger$1;
118416
- const PopoverContent = React.forwardRef(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (jsx(Portal$3, { children: jsx(Content2$1, { ref: ref, align: align, sideOffset: sideOffset, className: cn('bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 rounded-md border p-4 shadow-md outline-none', className), ...props }) })));
118426
+ const PopoverContent = React.forwardRef(({ className, align = 'center', sideOffset = 4, portalled = true, container, ...props }, ref) => {
118427
+ const content = (jsx(Content2$1, { ref: ref, align: align, sideOffset: sideOffset, className: cn('bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 rounded-md border p-4 shadow-md outline-none', className), ...props }));
118428
+ if (!portalled) {
118429
+ return content;
118430
+ }
118431
+ return jsx(Portal$3, { container: container, children: content });
118432
+ });
118417
118433
  PopoverContent.displayName = Content2$1.displayName;
118418
118434
 
118419
118435
  const offsetFormatCache = {};
@@ -188145,6 +188161,19 @@ const formatDateToYYYYMMDD = (date) => {
188145
188161
  return undefined;
188146
188162
  return date.toISOString().split('T')[0];
188147
188163
  };
188164
+ // Maps the integer codes the backend filter accepts to the string action
188165
+ // values it returns in the response. Used as a client-side safety net: the
188166
+ // backend's create-filter (action=0) is currently broken (the value is
188167
+ // falsy-checked server-side and skipped), so we re-filter the response to
188168
+ // drop entries whose action doesn't match what the user asked for. Update
188169
+ // (1) and Delete (2) filters work server-side, so this is a no-op for
188170
+ // those — but applying it uniformly keeps the UI consistent if any other
188171
+ // filter regresses the same way.
188172
+ const ACTION_NAME_BY_CODE = {
188173
+ 0: 'create',
188174
+ 1: 'update',
188175
+ 2: 'delete',
188176
+ };
188148
188177
  const useAuditLog = ({ tenantKey, userId, mentorId, }) => {
188149
188178
  const [page, setPage] = useState(1);
188150
188179
  const [limit] = useState(20);
@@ -188165,9 +188194,19 @@ const useAuditLog = ({ tenantKey, userId, mentorId, }) => {
188165
188194
  userId,
188166
188195
  params,
188167
188196
  });
188168
- const totalPages = data ? Math.ceil(data.count / limit) : 0;
188197
+ const filteredData = useMemo(() => {
188198
+ if (!data)
188199
+ return data;
188200
+ if (actionFilter === undefined)
188201
+ return data;
188202
+ const expectedAction = ACTION_NAME_BY_CODE[actionFilter];
188203
+ if (!expectedAction)
188204
+ return data;
188205
+ return { ...data, results: data.results.filter((e) => e.action === expectedAction) };
188206
+ }, [data, actionFilter]);
188207
+ const totalPages = filteredData ? Math.ceil(filteredData.count / limit) : 0;
188169
188208
  return {
188170
- data,
188209
+ data: filteredData,
188171
188210
  isLoading,
188172
188211
  isFetching,
188173
188212
  error,
@@ -188195,21 +188234,141 @@ const ACTION_FILTER_OPTIONS = [
188195
188234
  { label: 'Update', value: '1' },
188196
188235
  { label: 'Delete', value: '2' },
188197
188236
  ];
188198
- function summarizeChanges(entry) {
188199
- const action = ACTION_LABELS[entry.action] || entry.action;
188200
- const resourceType = entry.resource_type === 'mentorsettings' ? 'mentor settings' : entry.resource_type;
188201
- if (entry.action === 'create') {
188202
- return `${action} ${resourceType} "${entry.resource_repr}"`;
188237
+ // Backend resource_repr values end with the mentor's unique id in parens
188238
+ // (e.g. "Settings for Foo (fbac00ea-4788-4a2a-9d59-e59f64874f51)").
188239
+ // We keep the full UUID so mentors with the same name stay distinguishable.
188240
+ const TRAILING_UUID_RE = /\s*\(([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\)\s*$/i;
188241
+ const RESOURCE_TYPE_LABELS = {
188242
+ mentorsettings: 'mentor settings',
188243
+ };
188244
+ function humanizeResourceType(type) {
188245
+ var _a;
188246
+ return (_a = RESOURCE_TYPE_LABELS[type]) !== null && _a !== void 0 ? _a : type.replace(/_/g, ' ');
188247
+ }
188248
+ function splitReprAndUniqueId(repr) {
188249
+ const match = repr.match(TRAILING_UUID_RE);
188250
+ if (!match) {
188251
+ return { name: repr.trim(), uniqueId: null };
188203
188252
  }
188204
- if (entry.action === 'delete') {
188205
- return `${action} ${resourceType} "${entry.resource_repr}"`;
188253
+ return {
188254
+ name: repr.slice(0, match.index).trim(),
188255
+ uniqueId: match[1].toLowerCase(),
188256
+ };
188257
+ }
188258
+ // Labels for fields that appear in mentor / mentorsettings audit changes.
188259
+ // Raw field names like `enable_multi_query_rag` or `llm_name` read poorly
188260
+ // when just underscore-replaced, so we map the common ones explicitly.
188261
+ const FIELD_LABELS = {
188262
+ align_mentor_bubble: 'mentor bubble alignment',
188263
+ allow_anonymous: 'anonymous access',
188264
+ can_use_tools: 'tools',
188265
+ display_name: 'display name',
188266
+ embed_custom_image: 'embed image',
188267
+ enable_code_interpreter: 'code interpreter',
188268
+ enable_image_generation: 'image generation',
188269
+ enable_moderation: 'moderation',
188270
+ enable_multi_query_rag: 'multi-query RAG',
188271
+ enable_web_browsing: 'web browsing',
188272
+ forkable: 'forkable',
188273
+ is_lti_accessible: 'LTI access',
188274
+ llm_name: 'LLM model',
188275
+ llm_provider: 'LLM provider',
188276
+ mentor_bubble_color: 'mentor bubble color',
188277
+ mentor_visibility: 'visibility',
188278
+ profile_image: 'profile image',
188279
+ system_prompt: 'system prompt',
188280
+ theme: 'theme',
188281
+ uploaded_profile_image: 'uploaded profile image',
188282
+ user_message_color: 'user message color',
188283
+ };
188284
+ // Tokens we want to keep uppercase when they appear as standalone words.
188285
+ // Keeps fallbacks like `lti_access` → "LTI access" instead of "lti access".
188286
+ const FIELD_ABBREVIATIONS = new Set([
188287
+ 'ai',
188288
+ 'api',
188289
+ 'css',
188290
+ 'html',
188291
+ 'id',
188292
+ 'json',
188293
+ 'lms',
188294
+ 'lti',
188295
+ 'llm',
188296
+ 'ml',
188297
+ 'rag',
188298
+ 'sdk',
188299
+ 'sso',
188300
+ 'ui',
188301
+ 'url',
188302
+ 'uri',
188303
+ 'ux',
188304
+ ]);
188305
+ const VERB_PREFIX_RE = /^(enable_|allow_|can_|is_|has_)/i;
188306
+ // Defensive humanizer for field names not in FIELD_LABELS. Splits both
188307
+ // snake_case and camelCase, drops empty tokens, uppercases known
188308
+ // abbreviations, and falls back to a generic phrase if nothing readable
188309
+ // remains — so the user never sees "" or " flag" in the UI.
188310
+ function humanizeUnknownField(field) {
188311
+ const stripped = field.replace(VERB_PREFIX_RE, '');
188312
+ const words = stripped
188313
+ .replace(/([a-z0-9])([A-Z])/g, '$1_$2') // wordBoundary → word_Boundary
188314
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') // URLRouter → URL_Router
188315
+ .toLowerCase()
188316
+ .split(/[^a-z0-9]+/)
188317
+ .filter(Boolean);
188318
+ if (words.length === 0)
188319
+ return 'a setting';
188320
+ return words.map((w) => (FIELD_ABBREVIATIONS.has(w) ? w.toUpperCase() : w)).join(' ');
188321
+ }
188322
+ function humanizeField(field) {
188323
+ var _a;
188324
+ return (_a = FIELD_LABELS[field]) !== null && _a !== void 0 ? _a : humanizeUnknownField(field);
188325
+ }
188326
+ // Backend serializes booleans as the Python strings "True" / "False".
188327
+ const BOOL_STRINGS = new Set(['True', 'False', 'true', 'false']);
188328
+ function booleanDirection(newValue) {
188329
+ if (newValue === 'True' || newValue === 'true')
188330
+ return 'Enabled';
188331
+ if (newValue === 'False' || newValue === 'false')
188332
+ return 'Disabled';
188333
+ return null;
188334
+ }
188335
+ function formatResourceTarget(entry) {
188336
+ const { name, uniqueId } = splitReprAndUniqueId(entry.resource_repr);
188337
+ const typeLabel = humanizeResourceType(entry.resource_type);
188338
+ if (!name) {
188339
+ return `${typeLabel} #${entry.resource_id}`;
188340
+ }
188341
+ // If the repr already mentions the resource type anywhere in the string
188342
+ // (e.g. "Settings for E2E Mentor" for mentorsettings, or "E2E Mentor 123"
188343
+ // for mentor), skip the prefix so we don't repeat words like
188344
+ // `mentor "E2E Mentor 123"`.
188345
+ const reprLower = name.toLowerCase();
188346
+ const mentionsType = typeLabel
188347
+ .toLowerCase()
188348
+ .split(/\s+/)
188349
+ .some((word) => word.length > 2 && reprLower.includes(word));
188350
+ const base = mentionsType ? name : `${typeLabel} "${name}"`;
188351
+ return uniqueId ? `${base} (${uniqueId})` : base;
188352
+ }
188353
+ function summarizeChanges(entry) {
188354
+ var _a, _b;
188355
+ const action = (_a = ACTION_LABELS[entry.action]) !== null && _a !== void 0 ? _a : entry.action;
188356
+ const target = formatResourceTarget(entry);
188357
+ const changedEntries = Object.entries((_b = entry.changes) !== null && _b !== void 0 ? _b : {});
188358
+ if (entry.action === 'update' && changedEntries.length === 1) {
188359
+ const [field, change] = changedEntries[0];
188360
+ const newValue = Array.isArray(change) ? change[1] : undefined;
188361
+ if (typeof newValue === 'string' && BOOL_STRINGS.has(newValue)) {
188362
+ const verb = booleanDirection(newValue);
188363
+ if (verb)
188364
+ return `${verb} ${humanizeField(field)} on ${target}`;
188365
+ }
188206
188366
  }
188207
- const changedFields = Object.keys(entry.changes || {});
188208
- if (changedFields.length === 0) {
188209
- return `${action} ${resourceType} "${entry.resource_repr}"`;
188367
+ if (entry.action === 'update' && changedEntries.length > 0) {
188368
+ const fieldNames = changedEntries.map(([f]) => humanizeField(f)).join(', ');
188369
+ return `${action} ${fieldNames} on ${target}`;
188210
188370
  }
188211
- const fieldNames = changedFields.map((f) => f.replace(/_/g, ' ')).join(', ');
188212
- return `${action} ${fieldNames} on ${resourceType} "${entry.resource_repr}"`;
188371
+ return `${action} ${target}`;
188213
188372
  }
188214
188373
  function AnalyticsAuditLogStats({ tenantKey, mentorId, userId, selectedMentorId, }) {
188215
188374
  var _a;
@@ -188232,7 +188391,7 @@ function AnalyticsAuditLogStats({ tenantKey, mentorId, userId, selectedMentorId,
188232
188391
  if (is403) {
188233
188392
  return (jsx(Card, { className: "bg-white rounded-lg border border-gray-100 shadow-sm", children: jsx(CardContent, { className: "p-8 text-center", children: jsx("p", { className: "text-gray-500", children: "You do not have permission to view audit logs." }) }) }));
188234
188393
  }
188235
- return (jsxs("div", { className: "space-y-6", children: [jsx("div", { className: "border rounded-lg p-4 bg-white", children: jsxs("div", { className: "flex flex-col lg:flex-row gap-3", children: [jsx("div", { className: "relative flex-1 min-w-[200px]", children: jsxs(Popover, { modal: true, open: actorOpen, onOpenChange: setActorOpen, children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button$1, { variant: "outline", role: "combobox", "aria-expanded": actorOpen, "aria-label": "Search for User", className: "w-full justify-between font-normal bg-white h-9", children: [actorFilter || 'Search for User', jsx(ChevronsUpDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })] }) }), jsx(PopoverContent, { className: "w-full p-0", align: "start", children: jsxs(Command, { children: [jsx(CommandInput, { placeholder: "Search user..." }), jsxs(CommandList, { children: [jsx(CommandEmpty, { children: "No users found." }), jsxs(CommandGroup, { children: [jsxs(CommandItem, { value: "", onSelect: () => {
188394
+ return (jsxs("div", { className: "space-y-6", children: [jsx("div", { className: "border rounded-lg p-4 bg-white", children: jsxs("div", { className: "flex flex-col lg:flex-row gap-3", children: [jsx("div", { className: "relative flex-1 min-w-[200px]", children: jsxs(Popover, { open: actorOpen, onOpenChange: setActorOpen, children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button$1, { variant: "outline", role: "combobox", "aria-expanded": actorOpen, "aria-label": "Search for User", className: "w-full justify-between font-normal bg-white h-9", children: [actorFilter || 'Search for User', jsx(ChevronsUpDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })] }) }), jsx(PopoverContent, { className: "w-full p-0", align: "start", portalled: false, children: jsxs(Command, { children: [jsx(CommandInput, { placeholder: "Search user..." }), jsxs(CommandList, { children: [jsx(CommandEmpty, { children: "No users found." }), jsxs(CommandGroup, { children: [jsxs(CommandItem, { value: "", onSelect: () => {
188236
188395
  setActorFilter('');
188237
188396
  setActorOpen(false);
188238
188397
  setPage(1);
@@ -188242,7 +188401,7 @@ function AnalyticsAuditLogStats({ tenantKey, mentorId, userId, selectedMentorId,
188242
188401
  setPage(1);
188243
188402
  }, children: [jsx(Check, { className: cn('mr-2 h-4 w-4', actorFilter === actor ? 'opacity-100' : 'opacity-0') }), jsx("span", { className: "font-medium text-gray-700", children: actor })] }, actor)))] })] })] }) })] }) }), jsxs(Popover, { modal: true, children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button$1, { variant: "outline", className: "flex items-center gap-2 whitespace-nowrap font-normal bg-white w-full lg:w-auto h-9", children: [jsx(Calendar$1, { className: "h-4 w-4" }), (dateRange === null || dateRange === void 0 ? void 0 : dateRange.from) && (dateRange === null || dateRange === void 0 ? void 0 : dateRange.to)
188244
188403
  ? `${format$1(dateRange.from, 'MMM dd')} - ${format$1(dateRange.to, 'MMM dd')}`
188245
- : 'Pick a Date Range'] }) }), jsx(PopoverContent, { className: "w-auto p-0", align: "start", children: jsx(Calendar, { mode: "range", selected: dateRange, onSelect: (range) => {
188404
+ : 'Pick a Date Range'] }) }), jsx(PopoverContent, { "data-iblai-dialog-interaction-layer": true, className: "z-[60] w-auto p-0", align: "start", children: jsx(Calendar, { mode: "range", selected: dateRange, onSelect: (range) => {
188246
188405
  setDateRange(range ? { from: range.from, to: range.to } : undefined);
188247
188406
  setPage(1);
188248
188407
  }, numberOfMonths: 2 }) })] }), jsx("div", { className: "min-w-[160px]", children: jsxs(Select$1, { value: actionFilter !== undefined ? String(actionFilter) : 'all', onValueChange: (val) => {
@@ -55392,17 +55392,27 @@ var Close$1 = DialogClose$2;
55392
55392
  const Dialog$1 = Root$9;
55393
55393
  const DialogTrigger$2 = Trigger$4;
55394
55394
  const DialogPortal$2 = Portal$6;
55395
- const DialogOverlay$2 = React.forwardRef(({ className, ...props }, ref) => (jsx(Overlay$2, { ref: ref, className: cn("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", className), ...props })));
55395
+ const DialogOverlay$2 = React.forwardRef(({ className, ...props }, ref) => (jsx(Overlay$2, { ref: ref, className: cn('fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0', className), ...props })));
55396
55396
  DialogOverlay$2.displayName = Overlay$2.displayName;
55397
- const DialogContent$2 = React.forwardRef(({ className, children, ...props }, ref) => (jsxs(DialogPortal$2, { children: [jsx(DialogOverlay$2, {}), jsxs(Content$4, { ref: ref, className: cn("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", className), ...props, children: [children, jsxs(Close$1, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [jsx(X$1, { className: "h-4 w-4" }), jsx("span", { className: "sr-only", children: "Close" })] })] })] })));
55397
+ const DialogContent$2 = React.forwardRef(({ className, children, onInteractOutside, ...props }, ref) => {
55398
+ const handleInteractOutside = (event) => {
55399
+ const target = event.target;
55400
+ if (target instanceof Element && target.closest('[data-iblai-dialog-interaction-layer]')) {
55401
+ event.preventDefault();
55402
+ return;
55403
+ }
55404
+ onInteractOutside === null || onInteractOutside === void 0 ? void 0 : onInteractOutside(event);
55405
+ };
55406
+ return (jsxs(DialogPortal$2, { children: [jsx(DialogOverlay$2, {}), jsxs(Content$4, { ref: ref, className: cn('fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg', className), onInteractOutside: handleInteractOutside, ...props, children: [children, jsxs(Close$1, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [jsx(X$1, { className: "h-4 w-4" }), jsx("span", { className: "sr-only", children: "Close" })] })] })] }));
55407
+ });
55398
55408
  DialogContent$2.displayName = Content$4.displayName;
55399
- const DialogHeader = ({ className, ...props }) => (jsx("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props }));
55400
- DialogHeader.displayName = "DialogHeader";
55401
- const DialogFooter = ({ className, ...props }) => (jsx("div", { className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className), ...props }));
55402
- DialogFooter.displayName = "DialogFooter";
55403
- const DialogTitle$2 = React.forwardRef(({ className, ...props }, ref) => (jsx(Title$1, { ref: ref, className: cn("text-lg font-semibold leading-none tracking-tight", className), ...props })));
55409
+ const DialogHeader = ({ className, ...props }) => (jsx("div", { className: cn('flex flex-col space-y-1.5 text-center sm:text-left', className), ...props }));
55410
+ DialogHeader.displayName = 'DialogHeader';
55411
+ const DialogFooter = ({ className, ...props }) => (jsx("div", { className: cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className), ...props }));
55412
+ DialogFooter.displayName = 'DialogFooter';
55413
+ const DialogTitle$2 = React.forwardRef(({ className, ...props }, ref) => (jsx(Title$1, { ref: ref, className: cn('text-lg font-semibold leading-none tracking-tight', className), ...props })));
55404
55414
  DialogTitle$2.displayName = Title$1.displayName;
55405
- const DialogDescription$2 = React.forwardRef(({ className, ...props }, ref) => (jsx(Description$1, { ref: ref, className: cn("text-sm text-muted-foreground", className), ...props })));
55415
+ const DialogDescription$2 = React.forwardRef(({ className, ...props }, ref) => (jsx(Description$1, { ref: ref, className: cn('text-sm text-muted-foreground', className), ...props })));
55406
55416
  DialogDescription$2.displayName = Description$1.displayName;
55407
55417
 
55408
55418
  const Security = ({ email, onAccountDeleted, }) => {
@@ -107843,7 +107853,13 @@ var Content2$1 = PopoverContent$1;
107843
107853
 
107844
107854
  const Popover = Root2;
107845
107855
  const PopoverTrigger = Trigger$1;
107846
- const PopoverContent = React.forwardRef(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (jsx(Portal$3, { children: jsx(Content2$1, { ref: ref, align: align, sideOffset: sideOffset, className: cn('bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 rounded-md border p-4 shadow-md outline-none', className), ...props }) })));
107856
+ const PopoverContent = React.forwardRef(({ className, align = 'center', sideOffset = 4, portalled = true, container, ...props }, ref) => {
107857
+ const content = (jsx(Content2$1, { ref: ref, align: align, sideOffset: sideOffset, className: cn('bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 rounded-md border p-4 shadow-md outline-none', className), ...props }));
107858
+ if (!portalled) {
107859
+ return content;
107860
+ }
107861
+ return jsx(Portal$3, { container: container, children: content });
107862
+ });
107847
107863
  PopoverContent.displayName = Content2$1.displayName;
107848
107864
 
107849
107865
  const offsetFormatCache = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iblai/iblai-js",
3
- "version": "1.4.14",
3
+ "version": "1.4.15",
4
4
  "description": "Unified JavaScript SDK for IBL.ai — re-exports data-layer, web-containers, and web-utils under a single package",
5
5
  "type": "module",
6
6
  "engines": {
@@ -61,10 +61,10 @@
61
61
  "axios": "1.13.6",
62
62
  "dotenv": "16.6.1",
63
63
  "winston": "3.19.0",
64
- "@iblai/data-layer": "1.3.7",
64
+ "@iblai/data-layer": "1.3.8",
65
65
  "@iblai/mcp": "1.3.2",
66
- "@iblai/web-containers": "1.3.11",
67
- "@iblai/web-utils": "1.2.12"
66
+ "@iblai/web-containers": "1.3.14",
67
+ "@iblai/web-utils": "1.2.11"
68
68
  },
69
69
  "peerDependencies": {
70
70
  "@iblai/iblai-api": "4.166.0-ai",