@airoom/nextmin-react 2.0.1 → 2.0.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 (54) hide show
  1. package/README.md +57 -0
  2. package/dist/components/AddressAutocomplete.d.ts +4 -1
  3. package/dist/components/AddressAutocomplete.js +2 -2
  4. package/dist/components/AdminApp.js +86 -1
  5. package/dist/components/FileUploader.d.ts +3 -0
  6. package/dist/components/FileUploader.js +84 -28
  7. package/dist/components/PasswordInput.d.ts +2 -0
  8. package/dist/components/PasswordInput.js +2 -2
  9. package/dist/components/PhoneInput.d.ts +2 -0
  10. package/dist/components/PhoneInput.js +2 -2
  11. package/dist/components/QRCodeModal.d.ts +10 -0
  12. package/dist/components/QRCodeModal.js +153 -0
  13. package/dist/components/RefSelect.d.ts +4 -1
  14. package/dist/components/RefSelect.js +163 -65
  15. package/dist/components/SchemaForm.d.ts +2 -1
  16. package/dist/components/SchemaForm.js +132 -55
  17. package/dist/components/Sidebar.js +96 -7
  18. package/dist/components/TableFilters.js +1 -1
  19. package/dist/components/editor/TiptapEditor.js +46 -13
  20. package/dist/components/editor/Toolbar.js +195 -62
  21. package/dist/components/editor/components/CustomFontSizeModal.d.ts +13 -0
  22. package/dist/components/editor/components/CustomFontSizeModal.js +81 -0
  23. package/dist/components/editor/components/DistrictGridModal.js +1 -1
  24. package/dist/components/editor/components/SchemaInsertionModal.js +1 -1
  25. package/dist/components/editor/editor.css +2 -0
  26. package/dist/components/editor/extensions/FontSize.d.ts +19 -0
  27. package/dist/components/editor/extensions/FontSize.js +41 -0
  28. package/dist/components/viewer/DynamicViewer.js +50 -15
  29. package/dist/components/viewer/useViewDrawer.js +42 -2
  30. package/dist/hooks/useAppNavigation.d.ts +3 -0
  31. package/dist/hooks/useAppNavigation.js +37 -0
  32. package/dist/index.d.ts +2 -0
  33. package/dist/index.js +1 -0
  34. package/dist/lib/QueryBuilder.d.ts +3 -1
  35. package/dist/lib/QueryBuilder.js +10 -0
  36. package/dist/lib/api.d.ts +6 -0
  37. package/dist/lib/api.js +45 -24
  38. package/dist/lib/schemaUtils.js +1 -1
  39. package/dist/lib/types.d.ts +6 -1
  40. package/dist/nextmin.css +1 -1
  41. package/dist/providers/NextMinProvider.d.ts +5 -1
  42. package/dist/providers/NextMinProvider.js +12 -2
  43. package/dist/providers/themeResolver.d.ts +25 -0
  44. package/dist/providers/themeResolver.js +174 -0
  45. package/dist/router/NextMinRouter.d.ts +0 -1
  46. package/dist/router/NextMinRouter.js +0 -1
  47. package/dist/views/CreateEditPage.js +20 -11
  48. package/dist/views/DashboardPage.js +1 -1
  49. package/dist/views/ListPage.js +37 -6
  50. package/dist/views/SettingsEdit.js +1 -1
  51. package/dist/views/list/DataTableHero.d.ts +5 -5
  52. package/dist/views/list/DataTableHero.js +154 -41
  53. package/dist/views/list/ListHeader.js +9 -1
  54. package/package.json +5 -2
@@ -248,7 +248,7 @@ function toJsonString(v) {
248
248
  return typeof v === 'string' ? v : JSON.stringify(v);
249
249
  }
250
250
  /** --------------------------------------------------------------------------------------- **/
251
- export function SchemaForm({ model, schemaOverride, initialValues, submitLabel = 'Save', busy = false, showReset = true, onSubmit, fieldErrors, }) {
251
+ export function SchemaForm({ model, schemaOverride, initialValues, submitLabel = 'Save', busy = false, showReset = true, onSubmit, fieldErrors, isEdit: isEditProp, }) {
252
252
  const mapsKey = useGoogleMapsKey();
253
253
  const formUid = useId();
254
254
  const { items } = useSelector((s) => s.schemas);
@@ -286,6 +286,16 @@ export function SchemaForm({ model, schemaOverride, initialValues, submitLabel =
286
286
  // For auto-slugging
287
287
  const [manuallyEditedSlugs, setManuallyEditedSlugs] = useState(new Set());
288
288
  const [pendingSlugChecks, setPendingSlugChecks] = useState({});
289
+ const [internalFieldErrors, setInternalFieldErrors] = useState(fieldErrors ?? []);
290
+ useEffect(() => {
291
+ setInternalFieldErrors(fieldErrors ?? []);
292
+ }, [fieldErrors]);
293
+ const getFieldError = (fieldName) => {
294
+ const match = internalFieldErrors.find((fe) => fe &&
295
+ (fe.field === fieldName ||
296
+ fe.field.toLowerCase() === fieldName.toLowerCase()));
297
+ return match?.message;
298
+ };
289
299
  useEffect(() => {
290
300
  const timer = setTimeout(async () => {
291
301
  const entries = Object.entries(pendingSlugChecks);
@@ -308,8 +318,9 @@ export function SchemaForm({ model, schemaOverride, initialValues, submitLabel =
308
318
  return () => clearTimeout(timer);
309
319
  }, [pendingSlugChecks, model, form.id, form._id, form]);
310
320
  const [error, setError] = useState();
311
- const isEdit = useMemo(() => !!(initialValues &&
312
- (initialValues.id || initialValues._id)), [initialValues]);
321
+ const isEdit = useMemo(() => isEditProp ??
322
+ !!(initialValues &&
323
+ (initialValues.id || initialValues._id)), [initialValues, isEditProp]);
313
324
  useEffect(() => {
314
325
  const next = { ...(initialValues ?? {}) };
315
326
  if ('password' in next)
@@ -333,13 +344,19 @@ export function SchemaForm({ model, schemaOverride, initialValues, submitLabel =
333
344
  .map(toName)
334
345
  .filter((s) => !!s)
335
346
  .map((s) => s.toLowerCase());
336
- const result = configured.length > 0 ? configured : ['admin', 'superadmin'];
347
+ const result = configured.length > 0 ? configured : ['admin', 'superadmin', 'super-admin', 'super admin', 'developer'];
337
348
  return result;
338
349
  }, [schema]);
339
350
  const canBypassPrivacy = useMemo(() => {
340
- const userRolesLC = sessionRole.map((r) => r.toLowerCase());
341
- const result = userRolesLC.some((r) => bypassRoles.includes(r));
342
- return result;
351
+ const userRolesLC = sessionRole.map((r) => r.toLowerCase().replace(/[\s\-_]+/g, ''));
352
+ const normalizedBypass = bypassRoles.map(r => r.toLowerCase().replace(/[\s\-_]+/g, ''));
353
+ if (userRolesLC.some((r) => normalizedBypass.includes(r))) {
354
+ return true;
355
+ }
356
+ if (userRolesLC.some(r => r.includes('admin') || r.includes('developer') || r.includes('owner') || r.includes('super'))) {
357
+ return true;
358
+ }
359
+ return false;
343
360
  }, [sessionRole, bypassRoles]);
344
361
  const fields = useMemo(() => {
345
362
  const allFields = Object.entries(schema.attributes);
@@ -401,6 +418,8 @@ export function SchemaForm({ model, schemaOverride, initialValues, submitLabel =
401
418
  }, [schema, canBypassPrivacy, isEdit]);
402
419
  const gridClass = 'grid gap-4 grid-cols-2';
403
420
  const handleChange = (name, value) => {
421
+ setInternalFieldErrors((prev) => prev.filter((fe) => fe.field !== name &&
422
+ fe.field.toLowerCase() !== name.toLowerCase()));
404
423
  setForm((f) => {
405
424
  const next = { ...f, [name]: value };
406
425
  if (schema) {
@@ -493,7 +512,7 @@ export function SchemaForm({ model, schemaOverride, initialValues, submitLabel =
493
512
  [fieldName]: fieldValue,
494
513
  };
495
514
  handleChange(name, next);
496
- }, disabled: busy, inputClassNames: inputClassNames, selectClassNames: selectClassNames, mapsKey: mapsKey, availableSchemas: items, formState: it }) }, `${name}-${idx}-${k}`));
515
+ }, disabled: busy, inputClassNames: inputClassNames, selectClassNames: selectClassNames, mapsKey: mapsKey, availableSchemas: items, formState: it, isEdit: isEdit, canBypassPrivacy: canBypassPrivacy, isInvalid: Boolean(getFieldError(`${name}.${idx}.${k}`) || getFieldError(`${name}.${k}`) || getFieldError(k)), errorMessage: getFieldError(`${name}.${idx}.${k}`) || getFieldError(`${name}.${k}`) || getFieldError(k) }) }, `${name}-${idx}-${k}`));
497
516
  }), _jsx("div", { className: "col-span-2 flex justify-between", children: _jsx(Button, { size: "sm", variant: "flat", color: "danger", isDisabled: !canRemove, onPress: () => {
498
517
  const next = items.slice();
499
518
  next.splice(idx, 1);
@@ -513,7 +532,7 @@ export function SchemaForm({ model, schemaOverride, initialValues, submitLabel =
513
532
  return (_jsx("div", { className: isRich ? 'col-span-2' : 'col-span-1', children: _jsx(SchemaField, { uid: `${formUid}-${name}`, name: k, attr: a, value: obj?.[k], onChange: (fieldName, fieldValue) => {
514
533
  const next = { ...(obj || {}), [fieldName]: fieldValue };
515
534
  handleChange(name, next);
516
- }, disabled: busy, inputClassNames: inputClassNames, selectClassNames: selectClassNames, mapsKey: mapsKey, availableSchemas: items, formState: obj }) }, `${name}-${k}`));
535
+ }, disabled: busy, inputClassNames: inputClassNames, selectClassNames: selectClassNames, mapsKey: mapsKey, availableSchemas: items, formState: obj, isEdit: isEdit, canBypassPrivacy: canBypassPrivacy, isInvalid: Boolean(getFieldError(`${name}.${k}`) || getFieldError(k)), errorMessage: getFieldError(`${name}.${k}`) || getFieldError(k) }) }, `${name}-${k}`));
517
536
  }) })] }, name));
518
537
  }
519
538
  // let password reflect local state, but never prefill
@@ -525,58 +544,94 @@ export function SchemaForm({ model, schemaOverride, initialValues, submitLabel =
525
544
  // If it's a rich text field, force full width
526
545
  const isRich = attr?.rich === true;
527
546
  const dynamicColClass = isRich ? 'col-span-2' : colClass;
547
+ const fieldErr = getFieldError(name);
528
548
  return (_jsx("div", { className: dynamicColClass, children: _jsx(SchemaField, { uid: formUid, name: name, attr: attr, inputClassNames: inputClassNames, selectClassNames: selectClassNames, value: baseValue, onChange: handleChange, disabled: busy,
529
549
  // pass schemas for slash cmd
530
- availableSchemas: items, mapsKey: mapsKey, formState: form }) }, name));
550
+ availableSchemas: items, mapsKey: mapsKey, formState: form, isEdit: isEdit, canBypassPrivacy: canBypassPrivacy, isInvalid: Boolean(fieldErr), errorMessage: fieldErr }) }, name));
531
551
  }), error && (_jsx("div", { className: "col-span-2", children: _jsx("div", { className: "text-danger text-sm", children: error }) })), _jsxs("div", { className: "flex gap-2 col-span-2", children: [_jsx(Button, { type: "submit", color: "primary", isLoading: busy, children: submitLabel }), showReset && (_jsx(Button, { type: "reset", variant: "flat", isDisabled: busy, children: "Reset" }))] })] }));
532
552
  }
533
- function SchemaField({ uid, name, attr, value, onChange, disabled, inputClassNames, selectClassNames, mapsKey, availableSchemas, formState, }) {
553
+ function isAttrReadOnly(attr, isEdit = false) {
554
+ if (!attr)
555
+ return false;
556
+ const a = Array.isArray(attr) ? attr[0] : attr;
557
+ if (a?.readOnly === true)
558
+ return true;
559
+ if (typeof a?.readOnly === 'object' && a?.readOnly !== null) {
560
+ return isEdit ? !!a.readOnly.edit : !!a.readOnly.create;
561
+ }
562
+ if (typeof a?.editable === 'boolean') {
563
+ return isEdit ? !a.editable : false;
564
+ }
565
+ if (typeof a?.editable === 'object' && a?.editable !== null) {
566
+ return isEdit ? !a.editable.edit : !a.editable.create;
567
+ }
568
+ return false;
569
+ }
570
+ function SchemaField({ uid, name, attr, value, onChange, disabled, inputClassNames, selectClassNames, mapsKey, availableSchemas, formState, isEdit = false, canBypassPrivacy = false, isInvalid = false, errorMessage, }) {
534
571
  const id = `${uid}-${name}`;
535
572
  const label = attr?.label ?? formatLabel(name);
536
- const required = !!attr?.required ||
573
+ const isReadOnly = isAttrReadOnly(attr, isEdit);
574
+ const isEffectiveDisabled = disabled || isReadOnly;
575
+ const isPasswordField = name.toLowerCase() === 'password' ||
576
+ attr?.format === 'password' ||
577
+ attr?.writeOnly === true;
578
+ let required = !!attr?.required ||
537
579
  name.toLowerCase() === 'slug' ||
538
580
  !!attr?.populateSlugFrom;
581
+ if (isEdit) {
582
+ if (isPasswordField) {
583
+ required = false;
584
+ }
585
+ else if (canBypassPrivacy && attr?.private === true) {
586
+ required = false;
587
+ }
588
+ }
539
589
  const description = attr?.description;
540
590
  // Prefer ref over enum. Only use enum when there is NO ref.
541
- const enumVals = attr?.ref
591
+ const enumVals = attr?.ref || attr?.refPath
542
592
  ? undefined
543
593
  : attr?.enum;
544
- const isPasswordField = name.toLowerCase() === 'password' ||
545
- attr?.format === 'password' ||
546
- attr?.writeOnly === true;
547
594
  // RICH TEXT EDITOR CHECK
548
595
  if (attr?.rich === true) {
549
596
  // Extract speciality slug from form state
550
597
  const specialitySlug = formState?.speciality?.slug || formState?.slug || '';
551
- return (_jsx(TiptapEditor, { value: value, onChange: (html) => onChange(name, html), placeholder: label, availableSchemas: availableSchemas, currentSpeciality: specialitySlug }));
598
+ return (_jsxs("div", { className: "w-full flex flex-col gap-1", children: [_jsx(TiptapEditor, { value: value, onChange: (html) => onChange(name, html), placeholder: label, availableSchemas: availableSchemas, currentSpeciality: specialitySlug, className: isInvalid ? 'border-danger ring-1 ring-danger rounded-lg' : undefined }), errorMessage && (_jsx("p", { className: "text-danger text-xs mt-1", children: errorMessage }))] }));
552
599
  }
553
600
  // --- 1) Array of references → multi select
554
- const refArray = getRefArraySpec(attr);
601
+ const refArray = getRefArraySpec(attr, formState);
555
602
  if (refArray) {
556
- return (_jsx(RefSelect, { name: name, label: attr[0]?.label ?? label, refModel: refArray.ref, showKey: refArray.show ?? 'name', description: attr?.description, value: normalizeIdsArray(value), onChange: (ids) => onChange(name, ids), multiple: true, disabled: disabled, required: attr[0]?.required, pageSize: attr[0]?.pageSize, where: attr[0]?.where || attr?.where }));
603
+ return (_jsx(RefSelect, { name: name, label: attr[0]?.label ?? label, refModel: refArray.ref, showKey: refArray.show ?? 'name', description: attr?.description, value: value, onChange: (ids) => onChange(name, ids), multiple: true, disabled: disabled || isReadOnly || !refArray.ref, required: attr[0]?.required, pageSize: attr[0]?.pageSize, where: attr[0]?.where || attr?.where, isInvalid: isInvalid, errorMessage: errorMessage }));
557
604
  }
558
605
  // --- 2) Single reference → single select
559
- const refSingle = getRefSingleSpec(attr);
606
+ const refSingle = getRefSingleSpec(attr, formState);
560
607
  if (refSingle) {
561
- return (_jsx(RefSelect, { name: name, label: label, refModel: refSingle.ref, showKey: refSingle.show ?? 'name', description: attr?.description, value: normalizeId(value), onChange: (id) => onChange(name, id), multiple: false, disabled: disabled, required: required, pageSize: attr?.pageSize, where: attr?.where }));
608
+ return (_jsx(RefSelect, { name: name, label: label, refModel: refSingle.ref, showKey: refSingle.show ?? 'name', description: attr?.description, value: value, onChange: (id) => onChange(name, id), multiple: false, disabled: disabled || isReadOnly || !refSingle.ref, required: required, pageSize: attr?.pageSize, where: attr?.where, isInvalid: isInvalid, errorMessage: errorMessage }));
562
609
  }
563
610
  const head = Array.isArray(attr) ? (attr?.[0] ?? {}) : (attr ?? {});
564
611
  const isPhoneField = isPhoneAttr(name, attr);
565
612
  const rawMask = typeof head?.mask === 'string' ? head.mask : '';
566
613
  const hasSlots = /[Xx9#_]/.test(rawMask);
567
614
  const phoneMask = hasSlots ? rawMask : 'xxx-xxxx-xxxx';
615
+ const fieldType = String(attr?.fieldType || attr?.filedType || '').toLowerCase();
568
616
  const isFileField = String(attr?.format || '').toLowerCase() === 'file' ||
569
- /^(file|image|avatar|photo|picture|logo|siteLogo|sitelogo|profilepicture|bannerImage)$/i.test(name);
617
+ fieldType === 'file' ||
618
+ fieldType === 'image' ||
619
+ /(file|image|avatar|photo|picture|logo|siteLogo|sitelogo|profilepicture|bannerImage|catalog|brochure|document|attachment|pdf|upload|floorplan|floorPlan)s?$/i.test(name);
570
620
  if (isFileField) {
571
621
  const head = Array.isArray(attr) ? attr[0] : attr;
572
- const multiple = Array.isArray(attr) || Boolean(head?.multiple);
622
+ const multiple = Array.isArray(attr) || String(head?.type || '').toLowerCase() === 'array' || Boolean(head?.multiple);
573
623
  const fileTypes = head?.fileTypes;
574
624
  const maxFileSize = typeof head?.maxFileSize === 'number' ? head.maxFileSize : undefined;
575
625
  const maxFilesCount = multiple && typeof head?.maxFilesCount === 'number'
576
626
  ? Math.max(1, head.maxFilesCount)
577
627
  : undefined;
578
- const isRequired = !!attr?.required ||
628
+ let isRequired = !!attr?.required ||
579
629
  (Array.isArray(attr) ? !!head?.required : false);
630
+ if (isEdit && canBypassPrivacy) {
631
+ if (attr?.private === true || head?.private === true) {
632
+ isRequired = false;
633
+ }
634
+ }
580
635
  const controlledValue = multiple
581
636
  ? Array.isArray(value)
582
637
  ? value
@@ -586,16 +641,16 @@ function SchemaField({ uid, name, attr, value, onChange, disabled, inputClassNam
586
641
  : typeof value === 'string'
587
642
  ? value
588
643
  : null;
589
- return (_jsx(FileUploader, { name: name, label: label, value: controlledValue, onChange: (v) => onChange(name, v), required: isRequired, disabled: disabled, accept: fileTypes, maxSizeBytes: maxFileSize, multiple: multiple, maxFilesCount: maxFilesCount, description: attr?.description, className: "w-full" }));
644
+ return (_jsx(FileUploader, { name: name, label: label, value: controlledValue, onChange: (v) => onChange(name, v), required: isRequired, disabled: disabled, accept: fileTypes, maxSizeBytes: maxFileSize, multiple: multiple, maxFilesCount: maxFilesCount, isImage: fieldType === 'image' || /(image|photo|avatar|logo|picture|thumbnail|icon)/i.test(name), description: attr?.description, className: "w-full", isInvalid: isInvalid, errorMessage: errorMessage }));
590
645
  }
591
646
  if (isPasswordField) {
592
- return (_jsx(PasswordInput, { id: id, name: name, label: label, value: typeof value === 'string' ? value : '', onChange: (v) => onChange(name, v), disabled: disabled, required: required, description: description, className: "w-full", classNames: inputClassNames, autoComplete: "new-password" }));
647
+ return (_jsx(PasswordInput, { id: id, name: name, label: label, value: typeof value === 'string' ? value : '', onChange: (v) => onChange(name, v), disabled: disabled, required: required, description: description, className: "w-full", classNames: inputClassNames, autoComplete: "new-password", isInvalid: isInvalid, errorMessage: errorMessage }));
593
648
  }
594
649
  if (isPhoneField) {
595
650
  const rawDigits = typeof value === 'string' || typeof value === 'number'
596
651
  ? String(value).replace(/\D/g, '')
597
652
  : '';
598
- return (_jsx(PhoneInput, { id: id, name: name, label: label, mask: phoneMask, value: rawDigits, onChange: (raw) => onChange(name, raw), disabled: disabled, required: required, description: description, className: "w-full", classNames: inputClassNames, minLength: head?.minLength, maxLength: head?.maxLength, regex: head?.pattern }));
653
+ return (_jsx(PhoneInput, { id: id, name: name, label: label, mask: phoneMask, value: rawDigits, onChange: (raw) => onChange(name, raw), disabled: disabled, required: required, description: description, className: "w-full", classNames: inputClassNames, minLength: head?.minLength, maxLength: head?.maxLength, regex: head?.pattern, isInvalid: isInvalid, errorMessage: errorMessage }));
599
654
  }
600
655
  const populateField = getPopulateTarget(attr);
601
656
  // Address → Autocomplete
@@ -610,7 +665,7 @@ function SchemaField({ uid, name, attr, value, onChange, disabled, inputClassNam
610
665
  if (populateField) {
611
666
  onChange(populateField, `${latlng.lat.toFixed(6)},${latlng.lng.toFixed(6)}`);
612
667
  }
613
- }, disabled: disabled, required: required, className: "w-full", classNames: inputClassNames, countryCodes: attr?.countryCodes, limit: attr?.limit ?? 8 }));
668
+ }, disabled: disabled, required: required, className: "w-full", classNames: inputClassNames, countryCodes: attr?.countryCodes, limit: attr?.limit ?? 8, isInvalid: isInvalid, errorMessage: errorMessage }));
614
669
  }
615
670
  /** ----------------------- NEW: DATE / TIME / RANGE RENDERERS ----------------------- **/
616
671
  // 1) TIME-ONLY RANGE → two TimeInput fields (AM/PM UI)
@@ -630,7 +685,7 @@ function SchemaField({ uid, name, attr, value, onChange, disabled, inputClassNam
630
685
  end: serializeTime(t),
631
686
  });
632
687
  };
633
- return (_jsx("div", { className: "w-full", children: _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(TimeInput, { variant: "bordered", label: `${label} (Start)`, labelPlacement: "outside", className: "w-full", isDisabled: disabled, isRequired: required, description: description, value: startT ?? undefined, onChange: setStart, granularity: "minute", hourCycle: 12 }), _jsx(TimeInput, { variant: "bordered", label: `${label} (End)`, labelPlacement: "outside", className: "w-full", isDisabled: disabled, isRequired: required, description: description, value: endT ?? undefined, onChange: setEnd, granularity: "minute", hourCycle: 12 })] }) }));
688
+ return (_jsx("div", { className: "w-full", children: _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(TimeInput, { variant: "bordered", label: `${label} (Start)`, labelPlacement: "outside", className: "w-full", isDisabled: disabled, isRequired: required, description: description, value: startT ?? undefined, onChange: setStart, granularity: "minute", hourCycle: 12, isInvalid: isInvalid, errorMessage: errorMessage }), _jsx(TimeInput, { variant: "bordered", label: `${label} (End)`, labelPlacement: "outside", className: "w-full", isDisabled: disabled, isRequired: required, description: description, value: endT ?? undefined, onChange: setEnd, granularity: "minute", hourCycle: 12, isInvalid: isInvalid })] }) }));
634
689
  }
635
690
  // 2) DATE RANGE (default; supports withTime)
636
691
  if (isRangeType(attr)) {
@@ -643,7 +698,7 @@ function SchemaField({ uid, name, attr, value, onChange, disabled, inputClassNam
643
698
  return onChange(name, null);
644
699
  const { start, end } = val;
645
700
  onChange(name, serializeRangeOut(start, end, withTime));
646
- }, granularity: withTime ? 'minute' : 'day', hourCycle: withTime ? 24 : undefined }));
701
+ }, granularity: withTime ? 'minute' : 'day', hourCycle: withTime ? 24 : undefined, isInvalid: isInvalid, errorMessage: errorMessage }));
647
702
  }
648
703
  // 3) SINGLE DATE (supports withTime)
649
704
  if (isDateType(attr)) {
@@ -651,12 +706,12 @@ function SchemaField({ uid, name, attr, value, onChange, disabled, inputClassNam
651
706
  const parsed = parseDateString(value, withTime);
652
707
  return (_jsx(DatePicker, { variant: "bordered", label: label, labelPlacement: "outside", className: "w-full", isDisabled: disabled, isRequired: required, description: description, value: parsed ?? null, onChange: (v) => onChange(name, v
653
708
  ? serializeDate(v, withTime)
654
- : ''), granularity: withTime ? 'minute' : 'day', hourCycle: withTime ? 24 : undefined }));
709
+ : ''), granularity: withTime ? 'minute' : 'day', hourCycle: withTime ? 24 : undefined, isInvalid: isInvalid, errorMessage: errorMessage }));
655
710
  }
656
711
  // 4) SINGLE TIME (uses your existing isTimeType)
657
712
  if (isTimeType(attr)) {
658
713
  const tVal = parseTimeString(value);
659
- return (_jsx(TimeInput, { variant: "bordered", label: label, labelPlacement: "outside", className: "w-full", isDisabled: disabled, isRequired: required, description: description, value: tVal ?? undefined, onChange: (t) => onChange(name, serializeTime(t)), granularity: "minute", hourCycle: 12 }));
714
+ return (_jsx(TimeInput, { variant: "bordered", label: label, labelPlacement: "outside", className: "w-full", isDisabled: disabled, isRequired: required, description: description, value: tVal ?? undefined, onChange: (t) => onChange(name, serializeTime(t)), granularity: "minute", hourCycle: 12, isInvalid: isInvalid, errorMessage: errorMessage }));
660
715
  }
661
716
  const normalize = (s) => (s ?? '').toLowerCase().trim();
662
717
  const canSeeOption = (opt) => {
@@ -690,10 +745,10 @@ function SchemaField({ uid, name, attr, value, onChange, disabled, inputClassNam
690
745
  // Enum → RadioGroup (≤4) or Select (>4)
691
746
  if (enumVals && enumVals.length > 0) {
692
747
  if (enumVals.length <= 4) {
693
- return (_jsx(RadioGroup, { id: id, name: name, label: label, orientation: "horizontal", value: (value ?? ''), onValueChange: (v) => onChange(name, v), isDisabled: disabled, description: description, isRequired: required, className: "w-full", children: enumVals.map((opt) => {
748
+ return (_jsx(RadioGroup, { id: id, name: name, label: label, orientation: "horizontal", value: (value ?? ''), onValueChange: (v) => onChange(name, v), isDisabled: isEffectiveDisabled, description: description, isRequired: required, className: "w-full", isInvalid: isInvalid, errorMessage: errorMessage, children: enumVals.map((opt) => {
694
749
  if (!canSeeOption(opt))
695
750
  return null;
696
- return (_jsx(Radio, { value: opt, children: opt }, opt));
751
+ return (_jsx(Radio, { value: opt, isDisabled: isEffectiveDisabled, children: opt }, opt));
697
752
  }) }));
698
753
  }
699
754
  return (_jsx(Select, { isVirtualized: true, variant: "bordered", classNames: selectClassNames, labelPlacement: "outside", id: id, name: name, label: label, selectedKeys: value ? new Set([String(value)]) : new Set(), onSelectionChange: (keys) => {
@@ -701,29 +756,25 @@ function SchemaField({ uid, name, attr, value, onChange, disabled, inputClassNam
701
756
  return;
702
757
  const v = Array.from(keys)[0];
703
758
  onChange(name, v != null ? String(v) : '');
704
- }, isDisabled: disabled, description: description, className: "w-full", selectionMode: "single", isRequired: required, children: enumVals.map((opt) => (_jsx(SelectItem, { textValue: opt, children: opt }, opt))) }));
759
+ }, isDisabled: isEffectiveDisabled, description: description, className: "w-full", selectionMode: "single", isRequired: required, isInvalid: isInvalid, errorMessage: errorMessage, children: enumVals.map((opt) => (_jsx(SelectItem, { textValue: opt, children: opt }, opt))) }));
705
760
  }
706
761
  // Boolean → Checkbox
707
762
  if (inputTypeFor(attr) === 'checkbox') {
708
- return (_jsxs("div", { className: "w-full", children: [_jsx(Checkbox, { id: id, name: name, isSelected: !!value, onValueChange: (v) => onChange(name, v), isDisabled: disabled, isRequired: required, children: label }), description ? (_jsx("p", { className: "text-default-500 text-xs mt-1", children: description })) : null] }));
763
+ return (_jsxs("div", { className: "w-full", children: [_jsx(Checkbox, { id: id, name: name, isSelected: !!value, onValueChange: (v) => onChange(name, v), isDisabled: isEffectiveDisabled, isRequired: required, isInvalid: isInvalid, children: label }), errorMessage ? (_jsx("p", { className: "text-danger text-xs mt-1", children: errorMessage })) : description ? (_jsx("p", { className: "text-default-500 text-xs mt-1", children: description })) : null] }));
709
764
  }
710
765
  // Textarea
711
766
  if (inputTypeFor(attr) === 'textarea') {
712
- return (_jsx(Textarea, { variant: "bordered", classNames: inputClassNames, id: id, name: name, label: label, labelPlacement: "outside", value: value ?? '', onChange: (e) => onChange(name, e.target.value), isDisabled: disabled, minRows: 3, isReadOnly: attr.readOnly, description: description, className: "w-full", isRequired: required }));
767
+ return (_jsx(Textarea, { variant: "bordered", classNames: inputClassNames, id: id, name: name, label: label, labelPlacement: "outside", value: value ?? '', onChange: (e) => onChange(name, e.target.value), isDisabled: isEffectiveDisabled, minRows: 3, isReadOnly: isReadOnly, description: description, className: "w-full", isRequired: required, isInvalid: isInvalid, errorMessage: errorMessage }));
713
768
  }
714
769
  function attrHead(attr) {
715
770
  return Array.isArray(attr) ? attr[0] : attr;
716
771
  }
717
- function isAttrReadOnly(attr) {
718
- const a = attrHead(attr);
719
- return !!a?.readOnly;
720
- }
721
772
  // Array (non-ref) → comma-separated input
722
773
  if (Array.isArray(attr)) {
723
- return (_jsx(Input, { variant: "bordered", classNames: inputClassNames, id: id, name: name, label: label, isReadOnly: isAttrReadOnly(attr), labelPlacement: "outside-top", placeholder: "comma-separated values", value: Array.isArray(value) ? value.join(', ') : (value ?? ''), onChange: (e) => onChange(name, e.target.value
774
+ return (_jsx(Input, { variant: "bordered", classNames: inputClassNames, id: id, name: name, label: label, isReadOnly: isReadOnly, labelPlacement: "outside-top", placeholder: "comma-separated values", value: Array.isArray(value) ? value.join(', ') : (value ?? ''), onChange: (e) => onChange(name, e.target.value
724
775
  .split(',')
725
776
  .map((s) => s.trim())
726
- .filter(Boolean)), isDisabled: disabled, description: description ?? 'Enter values separated by commas.', className: "w-full", isRequired: required }));
777
+ .filter(Boolean)), isDisabled: isEffectiveDisabled, description: description ?? 'Enter values separated by commas.', className: "w-full", isRequired: required, isInvalid: isInvalid, errorMessage: errorMessage }));
727
778
  }
728
779
  function pickInputType(x, fieldName) {
729
780
  if (fieldName.toLowerCase() === 'password')
@@ -741,9 +792,9 @@ function SchemaField({ uid, name, attr, value, onChange, disabled, inputClassNam
741
792
  }
742
793
  }
743
794
  const inputType = pickInputType(inputTypeFor(attr), name);
744
- return (_jsx(Input, { variant: "bordered", classNames: inputClassNames, id: id, name: name, label: label, isReadOnly: attr.readOnly, labelPlacement: "outside-top", type: inputType, value: value ?? '', onChange: (e) => onChange(name, inputType === 'number'
795
+ return (_jsx(Input, { variant: "bordered", classNames: inputClassNames, id: id, name: name, label: label, isReadOnly: isReadOnly, labelPlacement: "outside-top", type: inputType, value: value ?? '', onChange: (e) => onChange(name, inputType === 'number'
745
796
  ? numberOrEmpty(e.target.value)
746
- : e.target.value), isDisabled: disabled, description: description, className: "w-full", isRequired: required, minLength: head?.minLength, maxLength: head?.maxLength, pattern: head?.pattern, autoComplete: name.toLowerCase() === 'password' ? 'new-password' : undefined }));
797
+ : e.target.value), isDisabled: isEffectiveDisabled, description: description, className: "w-full", isRequired: required, minLength: head?.minLength, maxLength: head?.maxLength, pattern: head?.pattern, autoComplete: name.toLowerCase() === 'password' ? 'new-password' : undefined, isInvalid: isInvalid, errorMessage: errorMessage }));
747
798
  }
748
799
  function isHiddenAttr(attr, isEdit) {
749
800
  const head = Array.isArray(attr) ? (attr?.[0] ?? {}) : (attr ?? {});
@@ -773,25 +824,51 @@ function isPasswordAttr(name, attr) {
773
824
  const byWriteOnly = attr?.writeOnly === true;
774
825
  return byName || byFormat || byWriteOnly;
775
826
  }
776
- function getRefArraySpec(attr) {
827
+ function getRefArraySpec(attr, formState) {
777
828
  if (!Array.isArray(attr) || attr.length === 0)
778
829
  return null;
779
830
  const head = attr[0];
780
- if (head &&
781
- typeof head === 'object' &&
782
- String(head.type).toLowerCase() === 'objectid' &&
783
- typeof head.ref === 'string') {
784
- return { ref: head.ref, show: head.show };
831
+ if (!head || typeof head !== 'object')
832
+ return null;
833
+ const t = String(head.type || '').toLowerCase();
834
+ const isRefType = t === 'objectid' || t === 'ref' || !!head.ref || !!head.refPath;
835
+ if (!isRefType)
836
+ return null;
837
+ let targetRef = typeof head.ref === 'string' && head.ref.trim() ? head.ref.trim() : undefined;
838
+ if (head.refPath && formState) {
839
+ const rawVal = formState[head.refPath];
840
+ if (typeof rawVal === 'string' && rawVal.trim()) {
841
+ targetRef = rawVal.trim();
842
+ }
843
+ else if (rawVal && typeof rawVal === 'object') {
844
+ targetRef = rawVal.modelName || rawVal.name || rawVal.slug || (rawVal.id || rawVal._id ? undefined : String(rawVal));
845
+ }
846
+ }
847
+ if (head.refPath || head.ref) {
848
+ return { ref: targetRef || '', show: head.show };
785
849
  }
786
850
  return null;
787
851
  }
788
- function getRefSingleSpec(attr) {
852
+ function getRefSingleSpec(attr, formState) {
789
853
  if (!attr || typeof attr !== 'object' || Array.isArray(attr))
790
854
  return null;
791
855
  const a = attr;
792
856
  const t = String(a.type || '').toLowerCase();
793
- if (t === 'objectid' && typeof a.ref === 'string' && a.ref.trim()) {
794
- return { ref: a.ref, show: a.show };
857
+ const isRefType = t === 'objectid' || t === 'ref' || !!a.ref || !!a.refPath;
858
+ if (!isRefType)
859
+ return null;
860
+ let targetRef = typeof a.ref === 'string' && a.ref.trim() ? a.ref.trim() : undefined;
861
+ if (a.refPath && formState) {
862
+ const rawVal = formState[a.refPath];
863
+ if (typeof rawVal === 'string' && rawVal.trim()) {
864
+ targetRef = rawVal.trim();
865
+ }
866
+ else if (rawVal && typeof rawVal === 'object') {
867
+ targetRef = rawVal.modelName || rawVal.name || rawVal.slug || (rawVal.id || rawVal._id ? undefined : String(rawVal));
868
+ }
869
+ }
870
+ if (a.refPath || a.ref) {
871
+ return { ref: targetRef || '', show: a.show };
795
872
  }
796
873
  return null;
797
874
  }
@@ -877,7 +954,7 @@ async function findUniqueSlug(model, baseSlug, currentId) {
877
954
  const checkSlug = attempt === 0 ? baseSlug : `${baseSlug}-${attempt}`;
878
955
  try {
879
956
  // Check if slug exists in the model
880
- const res = await api.list(model, { page: 0, limit: 1, where: { slug: checkSlug } });
957
+ const res = await api.list(model, { page: 0, limit: 1, where: { slug: checkSlug }, select: 'id,slug' });
881
958
  const existing = res.data?.[0];
882
959
  if (!existing ||
883
960
  (currentId && String(existing.id || existing._id) === String(currentId))) {
@@ -2,15 +2,21 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import React from 'react';
4
4
  import { useDispatch, useSelector } from 'react-redux';
5
- import { useRouter } from 'next/navigation';
6
- import { clearSession } from '../state/sessionSlice';
5
+ import Link from 'next/link';
6
+ import { usePathname, useRouter } from 'next/navigation';
7
7
  import { Button } from '@heroui/react';
8
+ import { clearSession } from '../state/sessionSlice';
8
9
  import { AuthClient } from '../lib/AuthClient';
9
10
  import { RealtimeClient } from '../lib/RealtimeClient';
10
- import Link from 'next/link';
11
+ import clsx from 'clsx';
12
+ import { isTailwindClass, } from '../providers/themeResolver';
13
+ import { useNextMin } from '../providers/NextMinProvider';
14
+ import { useAppNavigation } from '../hooks/useAppNavigation';
11
15
  export function Sidebar() {
12
16
  const router = useRouter();
13
17
  const dispatch = useDispatch();
18
+ const pathname = usePathname();
19
+ const navigateTo = useAppNavigation();
14
20
  const system = useSelector((s) => s.nextMin.system);
15
21
  const systemStatus = useSelector((s) => s.nextMin.status);
16
22
  const { items, status, error } = useSelector((s) => s.schemas);
@@ -68,13 +74,96 @@ export function Sidebar() {
68
74
  const first = arr.find((u) => typeof u === 'string' && u.trim().length > 0);
69
75
  return first || undefined;
70
76
  }, [system]);
71
- return (_jsxs("aside", { className: "flex h-full min-h-screen w-64 flex-col border-r", children: [_jsx(Link, { href: "/admin/dashboard", className: "h-20 px-3 border-b flex items-center justify-center", children: logoUrl ? (_jsx("img", { src: logoUrl, alt: siteName, className: "h-10 max-w-[160px] object-contain" })) : (_jsx("div", { className: "text-lg font-semibold truncate", children: siteName })) }), _jsxs("div", { className: "flex-1 overflow-y-auto p-2", children: [isLoading && _jsx("div", { children: "Loading\u2026" }), status === 'failed' && error && (_jsx("div", { className: "text-red-600", children: error })), status === 'succeeded' && (_jsxs("ul", { className: "list-none space-y-2", children: [_jsx("li", { children: _jsx(Link, { href: "/admin/dashboard", className: "w-full hover:bg-gray-200 px-3 py-2 rounded-md inline-flex items-center gap-2", children: "Dashboard" }) }, "dashboard"), orderedItems.map((s) => {
77
+ const { theme } = useNextMin();
78
+ const sidebarBgClass = theme?.sidebarColor && isTailwindClass(theme.sidebarColor)
79
+ ? theme.sidebarColor
80
+ : '';
81
+ const sidebarWidthClass = theme?.sidebarWidth && isTailwindClass(theme.sidebarWidth)
82
+ ? theme.sidebarWidth
83
+ : 'w-64';
84
+ const borderClass = theme?.sidebarPosition === 'right' ? 'border-l' : 'border-r';
85
+ // Active configurations
86
+ const activeBgClass = theme?.activeMenuBgColor && isTailwindClass(theme.activeMenuBgColor)
87
+ ? theme.activeMenuBgColor
88
+ : 'bg-primary/10 text-primary font-medium';
89
+ const activeBgStyle = theme?.activeMenuBgColor && !isTailwindClass(theme.activeMenuBgColor)
90
+ ? { backgroundColor: 'var(--nm-active-menu-bg)' }
91
+ : {};
92
+ const activeTextClass = theme?.activeMenuTextColor && isTailwindClass(theme.activeMenuTextColor)
93
+ ? theme.activeMenuTextColor
94
+ : '';
95
+ const activeTextStyle = theme?.activeMenuTextColor && !isTailwindClass(theme.activeMenuTextColor)
96
+ ? { color: 'var(--nm-active-menu-text)' }
97
+ : {};
98
+ // Inactive configurations
99
+ const inactiveTextClass = theme?.menuTextColor && isTailwindClass(theme.menuTextColor)
100
+ ? theme.menuTextColor
101
+ : 'text-gray-700';
102
+ const inactiveTextStyle = theme?.menuTextColor && !isTailwindClass(theme.menuTextColor)
103
+ ? { color: 'var(--nm-menu-text)' }
104
+ : {};
105
+ // Hover configurations
106
+ const hoverBgClass = theme?.menuHoverBgColor && isTailwindClass(theme.menuHoverBgColor)
107
+ ? theme.menuHoverBgColor
108
+ : 'hover:bg-gray-200';
109
+ const hoverTextClass = theme?.menuHoverTextColor && isTailwindClass(theme.menuHoverTextColor)
110
+ ? theme.menuHoverTextColor
111
+ : '';
112
+ const renderMenuItem = (href, label) => {
113
+ const isRootOrDashboard = href === '/admin' || href === '/admin/dashboard';
114
+ const isActive = isRootOrDashboard
115
+ ? pathname === href
116
+ : pathname === href || pathname?.startsWith(href + '/');
117
+ const handleClick = (e) => {
118
+ e.preventDefault();
119
+ if (pathname === href)
120
+ return;
121
+ navigateTo(href);
122
+ };
123
+ return (_jsx(Link, { href: href, onClick: handleClick, className: clsx("w-full px-3 py-2 rounded-md inline-flex items-center gap-2 transition-colors", isActive
124
+ ? clsx(activeBgClass, activeTextClass)
125
+ : clsx(hoverBgClass, hoverTextClass, inactiveTextClass)), style: {
126
+ ...(isActive ? { ...activeBgStyle, ...activeTextStyle } : inactiveTextStyle)
127
+ }, children: label }));
128
+ };
129
+ return (_jsxs("aside", { className: clsx("flex h-full min-h-screen flex-col flex-shrink-0", borderClass, sidebarBgClass, sidebarWidthClass), style: {
130
+ width: theme?.sidebarWidth && !isTailwindClass(theme.sidebarWidth) ? 'var(--nm-sidebar-width)' : undefined,
131
+ backgroundColor: theme?.sidebarColor && !isTailwindClass(theme.sidebarColor) ? 'var(--nm-sidebar-bg)' : undefined,
132
+ maxWidth: '100%'
133
+ }, children: [_jsx(Link, { href: "/admin/dashboard", onClick: (e) => {
134
+ e.preventDefault();
135
+ if (pathname === '/admin/dashboard')
136
+ return;
137
+ navigateTo('/admin/dashboard');
138
+ }, className: clsx("px-3 border-b flex items-center justify-center flex-shrink-0", theme?.topNavHeight && isTailwindClass(theme.topNavHeight) ? theme.topNavHeight : "h-20"), style: {
139
+ height: theme?.topNavHeight && !isTailwindClass(theme.topNavHeight) ? 'var(--nm-top-nav-height)' : undefined,
140
+ maxHeight: '100%'
141
+ }, children: logoUrl ? (_jsx("img", { src: logoUrl, alt: siteName, className: "h-10 max-w-[160px] object-contain" })) : (_jsx("div", { className: "text-lg font-semibold truncate", children: siteName })) }), _jsxs("div", { className: "flex-1 overflow-y-auto p-2", children: [isLoading && _jsx("div", { children: "Loading\u2026" }), status === 'failed' && error && (_jsx("div", { className: "text-red-600", children: error })), status === 'succeeded' && (_jsxs("ul", { className: "list-none space-y-2", children: [_jsx("li", { children: renderMenuItem("/admin/dashboard", "Dashboard") }, "dashboard"), orderedItems.map((s) => {
72
142
  const slug = String(s.modelName || '').toLowerCase();
73
143
  // Hide auto Settings model from the list; we link a fixed Settings route below
74
144
  if (slug === 'settings')
75
145
  return null;
76
- return (_jsx("li", { children: _jsx(Link, { href: `/admin/${slug}`, className: "w-full hover:bg-gray-200 px-3 py-2 rounded-md inline-flex items-center gap-2", children: s.modelName }) }, s.modelName));
77
- }), _jsx("li", { children: _jsx(Link, { href: "/admin/system/update", className: "w-full hover:bg-gray-200 px-3 py-2 rounded-md inline-flex items-center gap-2", children: "Settings" }) }, "settings"), !items.length && (_jsx("li", { className: "text-gray-500", children: "No schemas found" }))] }))] }), _jsxs("div", { className: "mt-auto border-t p-4 space-y-2", children: [_jsx(Link, { href: "/admin/profile", className: "w-full block hover:bg-gray-200 px-3 py-2 rounded-md", children: _jsxs("div", { className: "flex items-center justify-between gap-3", children: [user && (_jsxs("div", { className: "text-sm text-gray-700 text-left", children: [_jsx("div", { className: "font-semibold", children: `${user.firstName ?? ''} ${user.lastName ?? ''}`.trim() ||
146
+ return (_jsx("li", { children: renderMenuItem(`/admin/${slug}`, s.modelName) }, s.modelName));
147
+ }), _jsx("li", { children: renderMenuItem("/admin/system/update", "Settings") }, "settings"), !items.length && (_jsx("li", { className: "text-gray-500", children: "No schemas found" }))] }))] }), _jsxs("div", { className: "mt-auto border-t p-4 space-y-2 flex-shrink-0", children: [_jsx(Link, { href: "/admin/profile", onClick: (e) => {
148
+ e.preventDefault();
149
+ if (pathname === '/admin/profile')
150
+ return;
151
+ navigateTo('/admin/profile');
152
+ }, className: clsx("w-full block rounded-md transition-colors", pathname === '/admin/profile'
153
+ ? clsx(activeBgClass, activeTextClass)
154
+ : clsx(hoverBgClass, hoverTextClass, inactiveTextClass)), style: {
155
+ ...(pathname === '/admin/profile' ? { ...activeBgStyle, ...activeTextStyle } : inactiveTextStyle)
156
+ }, children: _jsxs("div", { className: "flex items-center justify-between gap-3 p-2", children: [user && (_jsxs("div", { className: clsx("text-sm text-left", pathname === '/admin/profile'
157
+ ? ""
158
+ : (theme?.sidebarTextColor && isTailwindClass(theme.sidebarTextColor) ? theme.sidebarTextColor : "text-gray-700")), style: {
159
+ color: pathname === '/admin/profile'
160
+ ? "inherit"
161
+ : (theme?.sidebarTextColor && !isTailwindClass(theme.sidebarTextColor) ? 'var(--nm-sidebar-text)' : undefined)
162
+ }, children: [_jsx("div", { className: "font-semibold", children: `${user.firstName ?? ''} ${user.lastName ?? ''}`.trim() ||
78
163
  user.name ||
79
- '' }), _jsx("div", { className: "text-gray-500", children: user.email })] })), _jsx("svg", { "aria-hidden": "true", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: "text-default-500 flex-shrink-0", children: _jsx("path", { d: "M9 6l6 6-6 6", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })] }) }), _jsx(Button, { fullWidth: true, variant: "flat", onPress: logout, children: "Log out" })] })] }));
164
+ '' }), _jsx("div", { className: clsx(pathname === '/admin/profile'
165
+ ? "opacity-75"
166
+ : (theme?.sidebarTextColor && isTailwindClass(theme.sidebarTextColor) ? "opacity-75" : "text-gray-500")), style: {
167
+ color: pathname === '/admin/profile' ? 'inherit' : undefined
168
+ }, children: user.email })] })), _jsx("svg", { "aria-hidden": "true", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: "text-default-500 flex-shrink-0", children: _jsx("path", { d: "M9 6l6 6-6 6", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })] }) }), _jsx(Button, { fullWidth: true, variant: "flat", onPress: logout, children: "Log out" })] })] }));
80
169
  }
@@ -34,7 +34,7 @@ export function TableFilters({ model, value, onChange, busy, columns, visibleCol
34
34
  setQ('');
35
35
  onChange({});
36
36
  };
37
- return (_jsxs(Form, { onSubmit: apply, onReset: clear, className: "grid gap-3 md:grid-cols-5 grid-cols-1 items-end", children: [_jsx(Select, { placeholder: "Search Field", "aria-label": "Search Field", variant: "bordered", size: "sm", selectedKeys: searchKey ? new Set([searchKey]) : new Set(), onSelectionChange: (s) => {
37
+ return (_jsxs(Form, { onSubmit: apply, onReset: clear, className: "nextmin-table-filters-form grid gap-3 md:grid-cols-5 grid-cols-1 items-end w-full", children: [_jsx(Select, { placeholder: "Search Field", "aria-label": "Search Field", variant: "bordered", size: "sm", selectedKeys: searchKey ? new Set([searchKey]) : new Set(), onSelectionChange: (s) => {
38
38
  if (s === 'all')
39
39
  return;
40
40
  const v = Array.from(s)[0];