@open-mercato/ui 0.5.1-develop.2949.009dcdd2d5 → 0.5.1-develop.2954.610bab2d08

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 (96) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +8 -0
  3. package/dist/backend/CrudForm.js +57 -29
  4. package/dist/backend/CrudForm.js.map +2 -2
  5. package/dist/backend/DataTable.js +32 -14
  6. package/dist/backend/DataTable.js.map +2 -2
  7. package/dist/backend/FilterOverlay.js +23 -17
  8. package/dist/backend/FilterOverlay.js.map +2 -2
  9. package/dist/backend/JsonBuilder.js +32 -18
  10. package/dist/backend/JsonBuilder.js.map +2 -2
  11. package/dist/backend/columns/ColumnChooserPanel.js +12 -13
  12. package/dist/backend/columns/ColumnChooserPanel.js.map +2 -2
  13. package/dist/backend/custom-fields/FieldDefinitionsEditor.js +71 -62
  14. package/dist/backend/custom-fields/FieldDefinitionsEditor.js.map +2 -2
  15. package/dist/backend/date-range/DateRangeSelect.js +11 -10
  16. package/dist/backend/date-range/DateRangeSelect.js.map +2 -2
  17. package/dist/backend/date-range/InlineDateRangeSelect.js +10 -22
  18. package/dist/backend/date-range/InlineDateRangeSelect.js.map +2 -2
  19. package/dist/backend/detail/ActivitiesSection.js +20 -12
  20. package/dist/backend/detail/ActivitiesSection.js.map +2 -2
  21. package/dist/backend/detail/AddressEditor.js +24 -7
  22. package/dist/backend/detail/AddressEditor.js.map +2 -2
  23. package/dist/backend/detail/InlineEditors.js +12 -6
  24. package/dist/backend/detail/InlineEditors.js.map +2 -2
  25. package/dist/backend/detail/NotesSection.js +20 -14
  26. package/dist/backend/detail/NotesSection.js.map +2 -2
  27. package/dist/backend/filters/AdvancedFilterBuilder.js +52 -24
  28. package/dist/backend/filters/AdvancedFilterBuilder.js.map +2 -2
  29. package/dist/backend/injection/InjectedField.js +12 -7
  30. package/dist/backend/injection/InjectedField.js.map +2 -2
  31. package/dist/backend/inputs/ComboboxInput.js.map +2 -2
  32. package/dist/backend/inputs/EventSelect.js +22 -6
  33. package/dist/backend/inputs/EventSelect.js.map +2 -2
  34. package/dist/backend/inputs/PhoneNumberField.js +2 -2
  35. package/dist/backend/inputs/PhoneNumberField.js.map +2 -2
  36. package/dist/backend/inputs/TimeInput.js +9 -10
  37. package/dist/backend/inputs/TimeInput.js.map +2 -2
  38. package/dist/backend/messages/message-compose-form-groups.js +12 -7
  39. package/dist/backend/messages/message-compose-form-groups.js.map +2 -2
  40. package/dist/backend/messages/useMessageCompose.js +7 -1
  41. package/dist/backend/messages/useMessageCompose.js.map +2 -2
  42. package/dist/frontend/LanguageSwitcher.js +19 -14
  43. package/dist/frontend/LanguageSwitcher.js.map +2 -2
  44. package/dist/index.js +5 -0
  45. package/dist/index.js.map +2 -2
  46. package/dist/primitives/checkbox-field.js +17 -5
  47. package/dist/primitives/checkbox-field.js.map +2 -2
  48. package/dist/primitives/input.js +71 -14
  49. package/dist/primitives/input.js.map +2 -2
  50. package/dist/primitives/radio-field.js +74 -0
  51. package/dist/primitives/radio-field.js.map +7 -0
  52. package/dist/primitives/radio.js +37 -0
  53. package/dist/primitives/radio.js.map +7 -0
  54. package/dist/primitives/select.js +155 -0
  55. package/dist/primitives/select.js.map +7 -0
  56. package/dist/primitives/switch-field.js +76 -0
  57. package/dist/primitives/switch-field.js.map +7 -0
  58. package/dist/primitives/switch.js +17 -3
  59. package/dist/primitives/switch.js.map +2 -2
  60. package/dist/primitives/textarea.js +48 -12
  61. package/dist/primitives/textarea.js.map +2 -2
  62. package/dist/primitives/tooltip.js +44 -15
  63. package/dist/primitives/tooltip.js.map +2 -2
  64. package/package.json +5 -3
  65. package/src/backend/CrudForm.tsx +104 -37
  66. package/src/backend/DataTable.tsx +38 -20
  67. package/src/backend/FilterOverlay.tsx +35 -21
  68. package/src/backend/JsonBuilder.tsx +38 -20
  69. package/src/backend/__tests__/FieldDefinitionsEditor.test.tsx +23 -6
  70. package/src/backend/columns/ColumnChooserPanel.tsx +9 -10
  71. package/src/backend/custom-fields/FieldDefinitionsEditor.tsx +120 -87
  72. package/src/backend/date-range/DateRangeSelect.tsx +19 -12
  73. package/src/backend/date-range/InlineDateRangeSelect.tsx +16 -20
  74. package/src/backend/detail/ActivitiesSection.tsx +35 -23
  75. package/src/backend/detail/AddressEditor.tsx +30 -16
  76. package/src/backend/detail/InlineEditors.tsx +21 -11
  77. package/src/backend/detail/NotesSection.tsx +35 -25
  78. package/src/backend/filters/AdvancedFilterBuilder.tsx +60 -34
  79. package/src/backend/injection/InjectedField.tsx +21 -12
  80. package/src/backend/inputs/ComboboxInput.tsx +4 -0
  81. package/src/backend/inputs/EventSelect.tsx +30 -17
  82. package/src/backend/inputs/PhoneNumberField.tsx +2 -2
  83. package/src/backend/inputs/TimeInput.tsx +9 -10
  84. package/src/backend/messages/message-compose-form-groups.tsx +21 -12
  85. package/src/backend/messages/useMessageCompose.ts +20 -1
  86. package/src/frontend/LanguageSwitcher.tsx +20 -17
  87. package/src/index.ts +5 -0
  88. package/src/primitives/checkbox-field.tsx +10 -2
  89. package/src/primitives/input.tsx +73 -12
  90. package/src/primitives/radio-field.tsx +92 -0
  91. package/src/primitives/radio.tsx +42 -0
  92. package/src/primitives/select.tsx +200 -0
  93. package/src/primitives/switch-field.tsx +100 -0
  94. package/src/primitives/switch.tsx +17 -4
  95. package/src/primitives/textarea.tsx +67 -11
  96. package/src/primitives/tooltip.tsx +68 -24
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/backend/messages/message-compose-form-groups.tsx"],
4
- "sourcesContent": ["import * as React from 'react'\nimport { FileCode, Globe, Lock } from 'lucide-react'\nimport { type CrudField } from '../CrudForm'\nimport { IconButton } from '../../primitives/icon-button'\nimport { Input } from '../../primitives/input'\nimport { Label } from '../../primitives/label'\nimport { Switch } from '../../primitives/switch'\nimport { AttachmentsSection } from '../detail/AttachmentsSection'\nimport { SwitchableMarkdownInput } from '../inputs/SwitchableMarkdownInput'\nimport { TagsInput } from '../inputs/TagsInput'\nimport { MessagePrioritySelector } from './MessagePrioritySelector'\nimport type { UseMessageComposeResult } from './useMessageCompose'\n\ntype ComposeProps = {\n compose: UseMessageComposeResult\n}\n\nfunction RecipientTagsInput({ compose }: ComposeProps) {\n return (\n <TagsInput\n value={compose.recipientIds}\n onChange={compose.setRecipientIds}\n selectedOptions={compose.selectedRecipientOptions}\n resolveLabel={compose.resolveRecipientLabel}\n loadSuggestions={compose.loadRecipientSuggestions}\n placeholder={compose.t('messages.placeholders.recipients', 'Search recipients...')}\n allowCustomValues={false}\n showSuggestionsOnFocus={false}\n />\n )\n}\n\nfunction VisibilitySelector({ compose }: ComposeProps) {\n return (\n <>\n <Label>{compose.t('messages.visibility', 'Visibility')}</Label>\n <div\n className=\"inline-flex items-center gap-1 rounded-md border bg-background p-1\"\n role=\"radiogroup\"\n aria-label={compose.t('messages.visibility', 'Visibility')}\n >\n <IconButton\n type=\"button\"\n size=\"xs\"\n variant={compose.visibility === 'internal' ? 'outline' : 'ghost'}\n role=\"radio\"\n aria-checked={compose.visibility === 'internal'}\n aria-label={compose.t('messages.visibilityInternal', 'Internal')}\n title={compose.t('messages.visibilityInternal', 'Internal')}\n className=\"h-7 w-7\"\n onClick={() => compose.setVisibility('internal')}\n >\n <Lock className=\"h-3.5 w-3.5\" />\n </IconButton>\n <IconButton\n type=\"button\"\n size=\"xs\"\n variant={compose.visibility === 'public' ? 'outline' : 'ghost'}\n role=\"radio\"\n aria-checked={compose.visibility === 'public'}\n aria-label={compose.t('messages.visibilityPublic', 'Public')}\n title={compose.t('messages.visibilityPublic', 'Public')}\n className=\"h-7 w-7\"\n onClick={() => compose.setVisibility('public')}\n >\n <Globe className=\"h-3.5 w-3.5\" />\n </IconButton>\n </div>\n <p className=\"text-xs text-muted-foreground\">\n {compose.visibility === 'public'\n ? compose.t('messages.visibilityPublicHint', 'Public messages are sent to external email only.')\n : compose.t('messages.visibilityInternalHint', 'Internal messages are sent to selected system users.')}\n </p>\n </>\n )\n}\n\nfunction ContextActionsSection({ compose }: ComposeProps) {\n if (!compose.shouldShowContextActions) return null\n\n return (\n <div className=\"grid gap-3 sm:grid-cols-2\">\n {compose.normalizedRequiredActionMode === 'optional' ? (\n <div className=\"flex items-center justify-between rounded border px-3 py-2 sm:col-span-2\">\n <div>\n <p className=\"text-sm font-medium\">\n {compose.t('messages.composer.objectPicker.actionRequiredLabel', 'Action required')}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {compose.t('messages.composer.objectPicker.actionRequiredHint', 'Mark this object as requiring recipient action.')}\n </p>\n </div>\n <Switch checked={compose.contextActionRequired} onCheckedChange={compose.setContextActionRequired} />\n </div>\n ) : null}\n {compose.normalizedRequiredActionMode === 'required' || compose.contextActionRequired ? (\n <div className=\"space-y-2 sm:col-span-2\">\n <Label htmlFor=\"messages-compose-context-action-type\">\n {compose.t('messages.composer.objectPicker.actionTypeLabel', 'Action type')}\n </Label>\n <select\n id=\"messages-compose-context-action-type\"\n value={compose.contextActionType}\n onChange={(event) => compose.setContextActionType(event.target.value)}\n className=\"h-9 w-full rounded-md border bg-background px-3 text-sm\"\n >\n <option value=\"\">{compose.t('messages.composer.objectPicker.actionTypePlaceholder', 'Select action')}</option>\n {compose.contextActionOptions.map((option) => (\n <option key={option.id} value={option.id}>\n {option.label}\n </option>\n ))}\n </select>\n </div>\n ) : null}\n </div>\n )\n}\n\nfunction PrioritySelector({ compose }: ComposeProps) {\n return (\n <>\n <Label>{compose.t('messages.priority', 'Priority')}</Label>\n <MessagePrioritySelector\n value={compose.priority}\n onChange={compose.setPriority}\n t={compose.t}\n />\n </>\n )\n}\n\nfunction MarkdownBodySection({\n compose,\n label,\n placeholder,\n inputId,\n rows,\n textareaClassName,\n}: ComposeProps & {\n label: string\n placeholder: string\n inputId: string\n rows: number\n textareaClassName: string\n}) {\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between gap-2\">\n <Label htmlFor={inputId}>{label}</Label>\n <IconButton\n type=\"button\"\n size=\"sm\"\n variant={compose.bodyFormat === 'markdown' ? 'outline' : 'ghost'}\n aria-pressed={compose.bodyFormat === 'markdown'}\n onClick={() => compose.setBodyFormat((previousValue) => (previousValue === 'markdown' ? 'text' : 'markdown'))}\n title={compose.t('messages.bodyFormat.toggle', 'Toggle markdown')}\n >\n <FileCode className=\"h-4 w-4\" />\n </IconButton>\n </div>\n <div id={inputId}>\n <SwitchableMarkdownInput\n value={compose.body}\n onChange={compose.setBody}\n isMarkdownEnabled={compose.bodyFormat === 'markdown'}\n rows={rows}\n placeholder={placeholder}\n textareaClassName={textareaClassName}\n />\n </div>\n </div>\n )\n}\n\nfunction ComposeModeFields({ compose }: ComposeProps) {\n return (\n <>\n <div className=\"space-y-3\">\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <div className=\"space-y-2\">\n {compose.visibility === 'public' ? (\n <>\n <Label htmlFor=\"messages-compose-external-email\">{compose.t('messages.externalEmail', 'External email')}</Label>\n <Input\n id=\"messages-compose-external-email\"\n type=\"email\"\n value={compose.externalEmail}\n onChange={(event) => compose.setExternalEmail(event.target.value)}\n placeholder={compose.t('messages.placeholders.externalEmail', 'name@example.com')}\n />\n </>\n ) : (\n <>\n <Label htmlFor=\"messages-compose-recipients\">{compose.t('messages.to', 'To')}</Label>\n <RecipientTagsInput compose={compose} />\n </>\n )}\n </div>\n\n <div className=\"space-y-2\">\n <VisibilitySelector compose={compose} />\n </div>\n </div>\n\n <ContextActionsSection compose={compose} />\n </div>\n\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"messages-compose-subject\">{compose.t('messages.subject', 'Subject')}</Label>\n <Input\n id=\"messages-compose-subject\"\n value={compose.subject}\n onChange={(event) => compose.setSubject(event.target.value)}\n placeholder={compose.t('messages.placeholders.subject', 'Enter subject...')}\n />\n </div>\n\n <div className=\"space-y-2\">\n <PrioritySelector compose={compose} />\n </div>\n </div>\n\n <MarkdownBodySection\n compose={compose}\n label={compose.t('messages.body', 'Message')}\n placeholder={compose.t('messages.placeholders.body', 'Write your message...')}\n inputId=\"messages-compose-body\"\n rows={8}\n textareaClassName=\"min-h-[180px] w-full rounded-md border bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n />\n\n <div className=\"space-y-2\">\n <Label>{compose.t('messages.attachedFiles', 'Attachments')}</Label>\n <AttachmentsSection\n entityId={compose.attachmentEntityId}\n recordId={compose.attachmentRecordId}\n showHeader={false}\n compact\n onChanged={() => {\n void compose.loadAttachmentIds().catch(() => null)\n }}\n />\n </div>\n </>\n )\n}\n\nfunction ReplyModeFields({ compose }: ComposeProps) {\n return (\n <>\n <MarkdownBodySection\n compose={compose}\n label={compose.t('messages.replyBody', 'Reply')}\n placeholder={compose.t('messages.placeholders.replyBody', 'Write your reply...')}\n inputId=\"messages-compose-body\"\n rows={8}\n textareaClassName=\"min-h-[180px] w-full rounded-md border bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n />\n\n <div className=\"space-y-2\">\n <Label>{compose.t('messages.attachedFiles', 'Attachments')}</Label>\n <AttachmentsSection\n entityId={compose.attachmentEntityId}\n recordId={compose.attachmentRecordId}\n showHeader={false}\n compact\n onChanged={() => {\n void compose.loadAttachmentIds().catch(() => null)\n }}\n />\n </div>\n </>\n )\n}\n\nfunction ForwardModeFields({ compose }: ComposeProps) {\n return (\n <>\n <div className=\"space-y-2\">\n <Label htmlFor=\"messages-compose-recipients\">{compose.t('messages.to', 'To')}</Label>\n <RecipientTagsInput compose={compose} />\n </div>\n\n <MarkdownBodySection\n compose={compose}\n label={compose.t('messages.forwardContent', 'Forwarded content')}\n placeholder={compose.t('messages.placeholders.forwardContent', 'Review and edit forwarded content...')}\n inputId=\"messages-forward-note\"\n rows={6}\n textareaClassName=\"min-h-[140px] w-full rounded-md border bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n />\n </>\n )\n}\n\nfunction EmailDeliverySection({ compose }: ComposeProps) {\n if (compose.variant === 'reply' || compose.variant === 'forward') {\n return null\n }\n\n if (compose.isComposePublicVisibility) {\n return (\n <div className=\"rounded border px-3 py-2\">\n <p className=\"text-sm font-medium\">{compose.t('messages.sendViaEmail', 'Also send via email')}</p>\n <p className=\"text-xs text-muted-foreground\">{compose.t('messages.sendViaEmailForcedPublic', 'For public visibility, email delivery is always enabled.')}</p>\n </div>\n )\n }\n\n return (\n <div className=\"flex items-center justify-between rounded border px-3 py-2\">\n <div>\n <p className=\"text-sm font-medium\">{compose.t('messages.sendViaEmail', 'Also send via email')}</p>\n <p className=\"text-xs text-muted-foreground\">{compose.t('messages.sendViaEmailHint', 'Recipients will receive an email copy with a secure link.')}</p>\n </div>\n <Switch checked={compose.sendViaEmail} onCheckedChange={compose.setSendViaEmail} />\n </div>\n )\n}\n\nfunction ReplyForwardOptionsRow({ compose }: ComposeProps) {\n if (compose.variant !== 'reply' && compose.variant !== 'forward') {\n return null\n }\n\n return (\n <div className=\"grid gap-3 sm:grid-cols-2\">\n {compose.variant === 'forward' ? (\n <div className=\"flex items-center justify-between rounded border px-3 py-2\">\n <div>\n <p className=\"text-sm font-medium\">{compose.t('messages.includeAttachments', 'Include attachments')}</p>\n <p className=\"text-xs text-muted-foreground\">{compose.t('messages.includeAttachmentsHint', 'Carry over attachments from the original message.')}</p>\n </div>\n <Switch checked={compose.includeAttachments} onCheckedChange={compose.setIncludeAttachments} />\n </div>\n ) : (\n <div className=\"flex items-center justify-between rounded border px-3 py-2\">\n <div>\n <p className=\"text-sm font-medium\">{compose.t('messages.replyAll', 'Reply all')}</p>\n <p className=\"text-xs text-muted-foreground\">{compose.t('messages.replyAllHint', 'Include all original recipients.')}</p>\n </div>\n <Switch checked={compose.replyAll} onCheckedChange={compose.setReplyAll} />\n </div>\n )}\n <div className=\"flex items-center justify-between rounded border px-3 py-2\">\n <div>\n <p className=\"text-sm font-medium\">{compose.t('messages.sendViaEmail', 'Also send via email')}</p>\n <p className=\"text-xs text-muted-foreground\">{compose.t('messages.sendViaEmailHint', 'Recipients will receive an email copy with a secure link.')}</p>\n </div>\n <Switch checked={compose.sendViaEmail} onCheckedChange={compose.setSendViaEmail} />\n </div>\n </div>\n )\n}\n\nfunction MessageComposeFormBody({ compose }: ComposeProps) {\n return (\n <div className=\"space-y-4\" onKeyDown={compose.handleKeyDown}>\n {compose.contextPreview ? (\n <div className=\"rounded border bg-muted/30 p-3 text-sm\">\n {compose.contextPreview}\n </div>\n ) : null}\n {compose.variant === 'compose' ? <ComposeModeFields compose={compose} /> : null}\n {compose.variant === 'reply' ? <ReplyModeFields compose={compose} /> : null}\n {compose.variant === 'forward' ? <ForwardModeFields compose={compose} /> : null}\n <ReplyForwardOptionsRow compose={compose} />\n <EmailDeliverySection compose={compose} />\n {compose.submitError ? <p className=\"text-sm text-destructive\">{compose.submitError}</p> : null}\n </div>\n )\n}\n\nexport function createMessageComposeFormGroups(compose: UseMessageComposeResult): CrudField[] {\n return [{\n id: 'composer',\n label: '',\n type: 'custom',\n component: () => <MessageComposeFormBody compose={compose} />,\n }]\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import * as React from 'react'\nimport { FileCode, Globe, Lock } from 'lucide-react'\nimport { type CrudField } from '../CrudForm'\nimport { IconButton } from '../../primitives/icon-button'\nimport { Input } from '../../primitives/input'\nimport { Label } from '../../primitives/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '../../primitives/select'\nimport { Switch } from '../../primitives/switch'\nimport { AttachmentsSection } from '../detail/AttachmentsSection'\nimport { SwitchableMarkdownInput } from '../inputs/SwitchableMarkdownInput'\nimport { TagsInput } from '../inputs/TagsInput'\nimport { MessagePrioritySelector } from './MessagePrioritySelector'\nimport type { UseMessageComposeResult } from './useMessageCompose'\n\ntype ComposeProps = {\n compose: UseMessageComposeResult\n}\n\nfunction RecipientTagsInput({ compose }: ComposeProps) {\n return (\n <TagsInput\n value={compose.recipientIds}\n onChange={compose.setRecipientIds}\n selectedOptions={compose.selectedRecipientOptions}\n resolveLabel={compose.resolveRecipientLabel}\n loadSuggestions={compose.loadRecipientSuggestions}\n placeholder={compose.t('messages.placeholders.recipients', 'Search recipients...')}\n allowCustomValues={false}\n showSuggestionsOnFocus={false}\n />\n )\n}\n\nfunction VisibilitySelector({ compose }: ComposeProps) {\n return (\n <>\n <Label>{compose.t('messages.visibility', 'Visibility')}</Label>\n <div\n className=\"inline-flex items-center gap-1 rounded-md border bg-background p-1\"\n role=\"radiogroup\"\n aria-label={compose.t('messages.visibility', 'Visibility')}\n >\n <IconButton\n type=\"button\"\n size=\"xs\"\n variant={compose.visibility === 'internal' ? 'outline' : 'ghost'}\n role=\"radio\"\n aria-checked={compose.visibility === 'internal'}\n aria-label={compose.t('messages.visibilityInternal', 'Internal')}\n title={compose.t('messages.visibilityInternal', 'Internal')}\n className=\"h-7 w-7\"\n onClick={() => compose.setVisibility('internal')}\n >\n <Lock className=\"h-3.5 w-3.5\" />\n </IconButton>\n <IconButton\n type=\"button\"\n size=\"xs\"\n variant={compose.visibility === 'public' ? 'outline' : 'ghost'}\n role=\"radio\"\n aria-checked={compose.visibility === 'public'}\n aria-label={compose.t('messages.visibilityPublic', 'Public')}\n title={compose.t('messages.visibilityPublic', 'Public')}\n className=\"h-7 w-7\"\n onClick={() => compose.setVisibility('public')}\n >\n <Globe className=\"h-3.5 w-3.5\" />\n </IconButton>\n </div>\n <p className=\"text-xs text-muted-foreground\">\n {compose.visibility === 'public'\n ? compose.t('messages.visibilityPublicHint', 'Public messages are sent to external email only.')\n : compose.t('messages.visibilityInternalHint', 'Internal messages are sent to selected system users.')}\n </p>\n </>\n )\n}\n\nfunction ContextActionsSection({ compose }: ComposeProps) {\n if (!compose.shouldShowContextActions) return null\n\n return (\n <div className=\"grid gap-3 sm:grid-cols-2\">\n {compose.normalizedRequiredActionMode === 'optional' ? (\n <div className=\"flex items-center justify-between rounded border px-3 py-2 sm:col-span-2\">\n <div>\n <p className=\"text-sm font-medium\">\n {compose.t('messages.composer.objectPicker.actionRequiredLabel', 'Action required')}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {compose.t('messages.composer.objectPicker.actionRequiredHint', 'Mark this object as requiring recipient action.')}\n </p>\n </div>\n <Switch checked={compose.contextActionRequired} onCheckedChange={compose.setContextActionRequired} />\n </div>\n ) : null}\n {compose.normalizedRequiredActionMode === 'required' || compose.contextActionRequired ? (\n <div className=\"space-y-2 sm:col-span-2\">\n <Label htmlFor=\"messages-compose-context-action-type\">\n {compose.t('messages.composer.objectPicker.actionTypeLabel', 'Action type')}\n </Label>\n <Select\n value={compose.contextActionType || undefined}\n onValueChange={(value) => compose.setContextActionType(value || '')}\n >\n <SelectTrigger id=\"messages-compose-context-action-type\">\n <SelectValue placeholder={compose.t('messages.composer.objectPicker.actionTypePlaceholder', 'Select action')} />\n </SelectTrigger>\n <SelectContent>\n {compose.contextActionOptions.map((option) => (\n <SelectItem key={option.id} value={option.id}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n ) : null}\n </div>\n )\n}\n\nfunction PrioritySelector({ compose }: ComposeProps) {\n return (\n <>\n <Label>{compose.t('messages.priority', 'Priority')}</Label>\n <MessagePrioritySelector\n value={compose.priority}\n onChange={compose.setPriority}\n t={compose.t}\n />\n </>\n )\n}\n\nfunction MarkdownBodySection({\n compose,\n label,\n placeholder,\n inputId,\n rows,\n textareaClassName,\n}: ComposeProps & {\n label: string\n placeholder: string\n inputId: string\n rows: number\n textareaClassName: string\n}) {\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between gap-2\">\n <Label htmlFor={inputId}>{label}</Label>\n <IconButton\n type=\"button\"\n size=\"sm\"\n variant={compose.bodyFormat === 'markdown' ? 'outline' : 'ghost'}\n aria-pressed={compose.bodyFormat === 'markdown'}\n onClick={() => compose.setBodyFormat((previousValue) => (previousValue === 'markdown' ? 'text' : 'markdown'))}\n title={compose.t('messages.bodyFormat.toggle', 'Toggle markdown')}\n >\n <FileCode className=\"h-4 w-4\" />\n </IconButton>\n </div>\n <div id={inputId}>\n <SwitchableMarkdownInput\n value={compose.body}\n onChange={compose.setBody}\n isMarkdownEnabled={compose.bodyFormat === 'markdown'}\n rows={rows}\n placeholder={placeholder}\n textareaClassName={textareaClassName}\n />\n </div>\n </div>\n )\n}\n\nfunction ComposeModeFields({ compose }: ComposeProps) {\n return (\n <>\n <div className=\"space-y-3\">\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <div className=\"space-y-2\">\n {compose.visibility === 'public' ? (\n <>\n <Label htmlFor=\"messages-compose-external-email\">{compose.t('messages.externalEmail', 'External email')}</Label>\n <Input\n id=\"messages-compose-external-email\"\n type=\"email\"\n value={compose.externalEmail}\n onChange={(event) => compose.setExternalEmail(event.target.value)}\n placeholder={compose.t('messages.placeholders.externalEmail', 'name@example.com')}\n />\n </>\n ) : (\n <>\n <Label htmlFor=\"messages-compose-recipients\">{compose.t('messages.to', 'To')}</Label>\n <RecipientTagsInput compose={compose} />\n </>\n )}\n </div>\n\n <div className=\"space-y-2\">\n <VisibilitySelector compose={compose} />\n </div>\n </div>\n\n <ContextActionsSection compose={compose} />\n </div>\n\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"messages-compose-subject\">{compose.t('messages.subject', 'Subject')}</Label>\n <Input\n id=\"messages-compose-subject\"\n value={compose.subject}\n onChange={(event) => compose.setSubject(event.target.value)}\n placeholder={compose.t('messages.placeholders.subject', 'Enter subject...')}\n />\n </div>\n\n <div className=\"space-y-2\">\n <PrioritySelector compose={compose} />\n </div>\n </div>\n\n <MarkdownBodySection\n compose={compose}\n label={compose.t('messages.body', 'Message')}\n placeholder={compose.t('messages.placeholders.body', 'Write your message...')}\n inputId=\"messages-compose-body\"\n rows={8}\n textareaClassName=\"min-h-[180px] w-full rounded-md border bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n />\n\n <div className=\"space-y-2\">\n <Label>{compose.t('messages.attachedFiles', 'Attachments')}</Label>\n <AttachmentsSection\n entityId={compose.attachmentEntityId}\n recordId={compose.attachmentRecordId}\n showHeader={false}\n compact\n onChanged={() => {\n void compose.loadAttachmentIds().catch(() => null)\n }}\n />\n </div>\n </>\n )\n}\n\nfunction ReplyModeFields({ compose }: ComposeProps) {\n return (\n <>\n <MarkdownBodySection\n compose={compose}\n label={compose.t('messages.replyBody', 'Reply')}\n placeholder={compose.t('messages.placeholders.replyBody', 'Write your reply...')}\n inputId=\"messages-compose-body\"\n rows={8}\n textareaClassName=\"min-h-[180px] w-full rounded-md border bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n />\n\n <div className=\"space-y-2\">\n <Label>{compose.t('messages.attachedFiles', 'Attachments')}</Label>\n <AttachmentsSection\n entityId={compose.attachmentEntityId}\n recordId={compose.attachmentRecordId}\n showHeader={false}\n compact\n onChanged={() => {\n void compose.loadAttachmentIds().catch(() => null)\n }}\n />\n </div>\n </>\n )\n}\n\nfunction ForwardModeFields({ compose }: ComposeProps) {\n return (\n <>\n <div className=\"space-y-2\">\n <Label htmlFor=\"messages-compose-recipients\">{compose.t('messages.to', 'To')}</Label>\n <RecipientTagsInput compose={compose} />\n </div>\n\n <MarkdownBodySection\n compose={compose}\n label={compose.t('messages.forwardContent', 'Forwarded content')}\n placeholder={compose.t('messages.placeholders.forwardContent', 'Review and edit forwarded content...')}\n inputId=\"messages-forward-note\"\n rows={6}\n textareaClassName=\"min-h-[140px] w-full rounded-md border bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n />\n </>\n )\n}\n\nfunction EmailDeliverySection({ compose }: ComposeProps) {\n if (compose.variant === 'reply' || compose.variant === 'forward') {\n return null\n }\n\n if (compose.isComposePublicVisibility) {\n return (\n <div className=\"rounded border px-3 py-2\">\n <p className=\"text-sm font-medium\">{compose.t('messages.sendViaEmail', 'Also send via email')}</p>\n <p className=\"text-xs text-muted-foreground\">{compose.t('messages.sendViaEmailForcedPublic', 'For public visibility, email delivery is always enabled.')}</p>\n </div>\n )\n }\n\n return (\n <div className=\"flex items-center justify-between rounded border px-3 py-2\">\n <div>\n <p className=\"text-sm font-medium\">{compose.t('messages.sendViaEmail', 'Also send via email')}</p>\n <p className=\"text-xs text-muted-foreground\">{compose.t('messages.sendViaEmailHint', 'Recipients will receive an email copy with a secure link.')}</p>\n </div>\n <Switch checked={compose.sendViaEmail} onCheckedChange={compose.setSendViaEmail} />\n </div>\n )\n}\n\nfunction ReplyForwardOptionsRow({ compose }: ComposeProps) {\n if (compose.variant !== 'reply' && compose.variant !== 'forward') {\n return null\n }\n\n return (\n <div className=\"grid gap-3 sm:grid-cols-2\">\n {compose.variant === 'forward' ? (\n <div className=\"flex items-center justify-between rounded border px-3 py-2\">\n <div>\n <p className=\"text-sm font-medium\">{compose.t('messages.includeAttachments', 'Include attachments')}</p>\n <p className=\"text-xs text-muted-foreground\">{compose.t('messages.includeAttachmentsHint', 'Carry over attachments from the original message.')}</p>\n </div>\n <Switch checked={compose.includeAttachments} onCheckedChange={compose.setIncludeAttachments} />\n </div>\n ) : (\n <div className=\"flex items-center justify-between rounded border px-3 py-2\">\n <div>\n <p className=\"text-sm font-medium\">{compose.t('messages.replyAll', 'Reply all')}</p>\n <p className=\"text-xs text-muted-foreground\">{compose.t('messages.replyAllHint', 'Include all original recipients.')}</p>\n </div>\n <Switch checked={compose.replyAll} onCheckedChange={compose.setReplyAll} />\n </div>\n )}\n <div className=\"flex items-center justify-between rounded border px-3 py-2\">\n <div>\n <p className=\"text-sm font-medium\">{compose.t('messages.sendViaEmail', 'Also send via email')}</p>\n <p className=\"text-xs text-muted-foreground\">{compose.t('messages.sendViaEmailHint', 'Recipients will receive an email copy with a secure link.')}</p>\n </div>\n <Switch checked={compose.sendViaEmail} onCheckedChange={compose.setSendViaEmail} />\n </div>\n </div>\n )\n}\n\nfunction MessageComposeFormBody({ compose }: ComposeProps) {\n return (\n <div className=\"space-y-4\" onKeyDown={compose.handleKeyDown}>\n {compose.contextPreview ? (\n <div className=\"rounded border bg-muted/30 p-3 text-sm\">\n {compose.contextPreview}\n </div>\n ) : null}\n {compose.variant === 'compose' ? <ComposeModeFields compose={compose} /> : null}\n {compose.variant === 'reply' ? <ReplyModeFields compose={compose} /> : null}\n {compose.variant === 'forward' ? <ForwardModeFields compose={compose} /> : null}\n <ReplyForwardOptionsRow compose={compose} />\n <EmailDeliverySection compose={compose} />\n {compose.submitError ? <p className=\"text-sm text-destructive\">{compose.submitError}</p> : null}\n </div>\n )\n}\n\nexport function createMessageComposeFormGroups(compose: UseMessageComposeResult): CrudField[] {\n return [{\n id: 'composer',\n label: '',\n type: 'custom',\n component: () => <MessageComposeFormBody compose={compose} />,\n }]\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -68,6 +68,7 @@ function useMessageCompose({
68
68
  const [submitting, setSubmitting] = React.useState(false);
69
69
  const [submitMode, setSubmitMode] = React.useState("send");
70
70
  const [submitError, setSubmitError] = React.useState(null);
71
+ const isOpenRef = React.useRef(false);
71
72
  const messageTypesQuery = useQuery({
72
73
  queryKey: ["messages", "types"],
73
74
  enabled: variant === "compose" && isOpen,
@@ -115,7 +116,12 @@ function useMessageCompose({
115
116
  return nextIds;
116
117
  }, [attachmentEntityId, attachmentRecordId, t]);
117
118
  React.useEffect(() => {
118
- if (!isOpen) return;
119
+ if (!isOpen) {
120
+ isOpenRef.current = false;
121
+ return;
122
+ }
123
+ if (isOpenRef.current) return;
124
+ isOpenRef.current = true;
119
125
  const nextRecipients = defaultValues?.recipients?.filter((value) => typeof value === "string" && value.trim().length > 0) ?? [];
120
126
  const dedupedRecipients = Array.from(new Set(nextRecipients));
121
127
  setRecipientIds(dedupedRecipients);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/backend/messages/useMessageCompose.ts"],
4
- "sourcesContent": ["import * as React from 'react'\nimport { useQuery } from '@tanstack/react-query'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { flash } from '../FlashMessages'\nimport { apiCall } from '../utils/apiCall'\nimport type {\n AttachmentListResponse,\n MessageComposerProps,\n MessageTypeItem,\n UserListItem,\n} from './message-composer.types'\nimport type { MessagePriority } from './message-priority'\nimport type { TagsInputOption } from '../inputs/TagsInput'\nimport {\n useComposeDraftOperation,\n useComposeSendOperation,\n useForwardSubmitOperation,\n useReplySubmitOperation,\n} from './useMessageComposeOperations'\n\nfunction toErrorMessage(payload: unknown): string | null {\n if (!payload) return null\n if (typeof payload === 'string') return payload\n if (Array.isArray(payload)) {\n for (const item of payload) {\n const nested = toErrorMessage(item)\n if (nested) return nested\n }\n return null\n }\n if (typeof payload === 'object') {\n const record = payload as Record<string, unknown>\n return (\n toErrorMessage(record.error)\n ?? toErrorMessage(record.message)\n ?? toErrorMessage(record.detail)\n ?? toErrorMessage(record.details)\n ?? null\n )\n }\n return null\n}\n\nfunction createTemporaryAttachmentRecordId(): string {\n const randomPart =\n typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n ? crypto.randomUUID()\n : `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`\n return `messages-composer:${randomPart}`\n}\n\nexport type UseMessageComposeParams = MessageComposerProps\n\nexport type UseMessageComposeResult = {\n t: ReturnType<typeof useT>\n variant: NonNullable<MessageComposerProps['variant']>\n messageId?: string\n open?: boolean\n inline: boolean\n contextPreview: React.ReactNode\n isOpen: boolean\n messageTypes: MessageTypeItem[]\n createableMessageTypes: MessageTypeItem[]\n normalizedRequiredActionMode: 'none' | 'optional' | 'required'\n contextActionOptions: Array<{ id: string; label: string }>\n shouldShowContextActions: boolean\n isComposePublicVisibility: boolean\n attachmentEntityId: string\n attachmentRecordId: string\n recipientIds: string[]\n setRecipientIds: React.Dispatch<React.SetStateAction<string[]>>\n messageType: string\n setMessageType: React.Dispatch<React.SetStateAction<string>>\n subject: string\n setSubject: React.Dispatch<React.SetStateAction<string>>\n body: string\n setBody: React.Dispatch<React.SetStateAction<string>>\n bodyFormat: 'text' | 'markdown'\n setBodyFormat: React.Dispatch<React.SetStateAction<'text' | 'markdown'>>\n priority: MessagePriority\n setPriority: React.Dispatch<React.SetStateAction<MessagePriority>>\n visibility: 'public' | 'internal'\n setVisibility: React.Dispatch<React.SetStateAction<'public' | 'internal'>>\n externalEmail: string\n setExternalEmail: React.Dispatch<React.SetStateAction<string>>\n sendViaEmail: boolean\n setSendViaEmail: React.Dispatch<React.SetStateAction<boolean>>\n contextActionRequired: boolean\n setContextActionRequired: React.Dispatch<React.SetStateAction<boolean>>\n contextActionType: string\n setContextActionType: React.Dispatch<React.SetStateAction<string>>\n replyAll: boolean\n setReplyAll: React.Dispatch<React.SetStateAction<boolean>>\n includeAttachments: boolean\n setIncludeAttachments: React.Dispatch<React.SetStateAction<boolean>>\n submitting: boolean\n submitMode: 'send' | 'draft'\n submitError: string | null\n composerTitle: string\n submitLabel: string\n selectedRecipientOptions: TagsInputOption[]\n resolveRecipientLabel: (id: string) => string\n loadRecipientSuggestions: (query?: string) => Promise<TagsInputOption[]>\n loadAttachmentIds: () => Promise<string[]>\n handleSaveDraft: () => void\n handleBack: () => void\n handleSubmit: ({ saveAsDraft }?: { saveAsDraft?: boolean }) => Promise<boolean>\n handleDialogOpenChange: (nextOpen: boolean) => void\n handleKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => void\n}\n\ntype ForwardPreviewResponse = {\n subject?: string\n body?: string\n}\n\nexport function useMessageCompose({\n variant: variantProp = 'compose',\n messageId,\n open,\n onOpenChange,\n inline = false,\n lockedType = null,\n contextObject = null,\n requiredActionConfig = null,\n contextPreview = null,\n defaultValues,\n onSuccess,\n onCancel,\n}: UseMessageComposeParams): UseMessageComposeResult {\n const t = useT()\n const variant = variantProp\n const isOpen = inline ? true : Boolean(open)\n const recipientSuggestionsCacheRef = React.useRef<TagsInputOption[] | null>(null)\n\n const [recipientIds, setRecipientIds] = React.useState<string[]>([])\n const [recipientMap, setRecipientMap] = React.useState<Record<string, TagsInputOption>>({})\n const [messageType, setMessageType] = React.useState(lockedType ?? 'default')\n const [subject, setSubject] = React.useState('')\n const [body, setBody] = React.useState('')\n const [bodyFormat, setBodyFormat] = React.useState<'text' | 'markdown'>('text')\n const [priority, setPriority] = React.useState<MessagePriority>('normal')\n const [visibility, setVisibility] = React.useState<'public' | 'internal'>('internal')\n const [externalEmail, setExternalEmail] = React.useState('')\n const [attachmentIds, setAttachmentIds] = React.useState<string[]>([])\n const [sendViaEmail, setSendViaEmail] = React.useState(false)\n const [contextActionRequired, setContextActionRequired] = React.useState(false)\n const [contextActionType, setContextActionType] = React.useState('')\n const [replyAll, setReplyAll] = React.useState(false)\n const [includeAttachments, setIncludeAttachments] = React.useState(true)\n const [temporaryAttachmentRecordId, setTemporaryAttachmentRecordId] = React.useState<string>(() =>\n createTemporaryAttachmentRecordId(),\n )\n const [submitting, setSubmitting] = React.useState(false)\n const [submitMode, setSubmitMode] = React.useState<'send' | 'draft'>('send')\n const [submitError, setSubmitError] = React.useState<string | null>(null)\n\n const messageTypesQuery = useQuery({\n queryKey: ['messages', 'types'],\n enabled: variant === 'compose' && isOpen,\n staleTime: 5 * 60 * 1000,\n queryFn: async () => {\n const call = await apiCall<{ items?: MessageTypeItem[] }>('/api/messages/types')\n if (!call.ok) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.loadTypesFailed', 'Failed to load message types.'),\n )\n }\n return Array.isArray(call.result?.items) ? call.result?.items ?? [] : []\n },\n })\n\n const messageTypes = React.useMemo(\n () => messageTypesQuery.data ?? [],\n [messageTypesQuery.data],\n )\n const createableMessageTypes = React.useMemo(\n () => messageTypes.filter((item) => item.isCreateableByUser !== false),\n [messageTypes],\n )\n const normalizedRequiredActionMode = requiredActionConfig?.mode ?? 'none'\n const contextActionOptions = React.useMemo(\n () => (requiredActionConfig?.options ?? []).filter((option) => option.id.trim().length > 0),\n [requiredActionConfig?.options],\n )\n const shouldShowContextActions = (\n variant === 'compose'\n && Boolean(contextObject)\n && normalizedRequiredActionMode !== 'none'\n && contextActionOptions.length > 0\n )\n\n const isComposePublicVisibility = variant === 'compose' && visibility === 'public'\n\n const attachmentEntityId = variant === 'compose' && messageId ? 'messages:message' : 'attachments:library'\n const attachmentRecordId = variant === 'compose' && messageId ? messageId : temporaryAttachmentRecordId\n\n const loadAttachmentIds = React.useCallback(async (): Promise<string[]> => {\n const params = new URLSearchParams()\n params.set('entityId', attachmentEntityId)\n params.set('recordId', attachmentRecordId)\n\n const call = await apiCall<AttachmentListResponse>(`/api/attachments?${params.toString()}`)\n if (!call.ok) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.loadAttachmentOptionsFailed', 'Failed to load attachments.'),\n )\n }\n\n const items = Array.isArray(call.result?.items) ? call.result.items : []\n const nextIds = items\n .map((item) => (typeof item?.id === 'string' ? item.id : ''))\n .filter((id) => id.length > 0)\n\n setAttachmentIds(nextIds)\n return nextIds\n }, [attachmentEntityId, attachmentRecordId, t])\n\n React.useEffect(() => {\n if (!isOpen) return\n\n const nextRecipients = defaultValues?.recipients?.filter((value) => typeof value === 'string' && value.trim().length > 0) ?? []\n const dedupedRecipients = Array.from(new Set(nextRecipients))\n\n setRecipientIds(dedupedRecipients)\n setMessageType(lockedType ?? defaultValues?.type ?? 'default')\n setSubject(defaultValues?.subject ?? '')\n setBody(defaultValues?.body ?? '')\n setBodyFormat(defaultValues?.bodyFormat ?? 'text')\n setPriority(defaultValues?.priority ?? 'normal')\n setVisibility(defaultValues?.visibility ?? 'internal')\n setExternalEmail(defaultValues?.externalEmail ?? '')\n setAttachmentIds(\n Array.isArray(defaultValues?.attachmentIds)\n ? defaultValues.attachmentIds.filter((id): id is string => typeof id === 'string' && id.trim().length > 0)\n : [],\n )\n setSendViaEmail(Boolean(defaultValues?.sendViaEmail))\n if (contextObject) {\n const defaultContextActionType = requiredActionConfig?.defaultActionType?.trim() ?? ''\n const fallbackContextActionType = contextObject.actionType?.trim() ?? ''\n const selectedActionType = defaultContextActionType || fallbackContextActionType\n const selectedActionAllowed = contextActionOptions.some((option) => option.id === selectedActionType)\n const nextActionType = selectedActionAllowed ? selectedActionType : ''\n setContextActionType(nextActionType)\n if (normalizedRequiredActionMode === 'required') {\n setContextActionRequired(true)\n } else if (normalizedRequiredActionMode === 'optional') {\n setContextActionRequired(Boolean(nextActionType) || Boolean(contextObject.actionRequired))\n } else {\n setContextActionRequired(Boolean(contextObject.actionRequired))\n }\n } else {\n setContextActionType('')\n setContextActionRequired(false)\n }\n setReplyAll(Boolean(defaultValues?.replyAll))\n setIncludeAttachments(defaultValues?.includeAttachments !== false)\n setTemporaryAttachmentRecordId(createTemporaryAttachmentRecordId())\n setSubmitError(null)\n }, [\n contextActionOptions,\n contextObject,\n defaultValues,\n isOpen,\n lockedType,\n normalizedRequiredActionMode,\n requiredActionConfig?.defaultActionType,\n ])\n\n React.useEffect(() => {\n if (!isOpen) return\n if (variant !== 'forward') return\n if (!messageId) return\n\n let isActive = true\n\n void (async () => {\n const call = await apiCall<ForwardPreviewResponse>(`/api/messages/${encodeURIComponent(messageId)}/forward-preview`)\n if (!isActive) return\n\n if (!call.ok) {\n const message = toErrorMessage(call.result)\n ?? t('messages.errors.forwardPreviewFailed', 'Failed to load forward preview.')\n setSubmitError(message)\n flash(message, 'error')\n return\n }\n\n if (typeof call.result?.subject === 'string') {\n setSubject((previousValue) => (previousValue.trim().length > 0 ? previousValue : call.result?.subject ?? ''))\n }\n if (typeof call.result?.body === 'string') {\n setBody((previousValue) => (previousValue.trim().length > 0 ? previousValue : call.result?.body ?? ''))\n }\n setBodyFormat('text')\n })().catch((error) => {\n if (!isActive) return\n const message = error instanceof Error\n ? error.message\n : t('messages.errors.forwardPreviewFailed', 'Failed to load forward preview.')\n setSubmitError(message)\n flash(message, 'error')\n })\n\n return () => {\n isActive = false\n }\n }, [isOpen, messageId, t, variant])\n\n React.useEffect(() => {\n if (!isOpen) return\n if (variant !== 'compose' && variant !== 'reply') return\n void loadAttachmentIds().catch(() => null)\n }, [isOpen, loadAttachmentIds, variant])\n\n React.useEffect(() => {\n if (variant !== 'compose') return\n if (!createableMessageTypes.length) return\n\n if (lockedType) {\n if (createableMessageTypes.some((item) => item.type === lockedType)) {\n setMessageType(lockedType)\n return\n }\n const defaultType = createableMessageTypes.find((item) => item.type === 'default')\n setMessageType(defaultType?.type ?? createableMessageTypes[0]?.type ?? 'default')\n return\n }\n\n if (createableMessageTypes.some((item) => item.type === messageType)) return\n\n const defaultType = createableMessageTypes.find((item) => item.type === 'default')\n setMessageType(defaultType?.type ?? createableMessageTypes[0]?.type ?? 'default')\n }, [createableMessageTypes, lockedType, messageType, variant])\n\n React.useEffect(() => {\n if (variant !== 'compose') return\n if (visibility !== 'public') return\n setSendViaEmail(true)\n setRecipientIds([])\n }, [variant, visibility])\n\n React.useEffect(() => {\n if (isOpen) return\n recipientSuggestionsCacheRef.current = null\n }, [isOpen])\n\n const resolveRecipientLabel = React.useCallback((id: string) => {\n return recipientMap[id]?.label ?? id\n }, [recipientMap])\n\n const selectedRecipientOptions = React.useMemo(() => {\n return recipientIds.map((id) => recipientMap[id] ?? { value: id, label: id })\n }, [recipientIds, recipientMap])\n\n const loadRecipientSuggestions = React.useCallback(async (_query?: string) => {\n const cachedOptions = recipientSuggestionsCacheRef.current\n if (cachedOptions) {\n return cachedOptions\n }\n\n const params = new URLSearchParams()\n params.set('page', '1')\n params.set('pageSize', '100')\n // Recipient lookup is filtered in TagsInput because incremental auth user search is unreliable.\n\n const call = await apiCall<{ items?: UserListItem[] }>(`/api/auth/users?${params.toString()}`)\n if (!call.ok) {\n return []\n }\n\n const rawItems = Array.isArray(call.result?.items) ? call.result?.items ?? [] : []\n const options: TagsInputOption[] = []\n for (const item of rawItems) {\n if (!item || typeof item !== 'object') continue\n const id = typeof item.id === 'string' ? item.id : ''\n if (!id) continue\n\n const email = typeof item.email === 'string' && item.email.trim().length ? item.email.trim() : id\n const name = typeof item.name === 'string' && item.name.trim().length ? item.name.trim() : undefined\n\n options.push({\n value: id,\n label: email,\n description: name,\n })\n }\n\n if (options.length) {\n setRecipientMap((prev) => {\n const next = { ...prev }\n for (const option of options) {\n next[option.value] = option\n }\n return next\n })\n }\n\n recipientSuggestionsCacheRef.current = options\n return options\n }, [])\n\n const handleCancel = React.useCallback(() => {\n if (submitting) return\n if (!inline) {\n onOpenChange?.(false)\n }\n onCancel?.()\n }, [inline, onCancel, onOpenChange, submitting])\n\n const composeSendOperation = useComposeSendOperation({\n t,\n messageType,\n createableMessageTypes,\n priority,\n visibility,\n externalEmail,\n recipientIds,\n subject,\n body,\n bodyFormat,\n sendViaEmail,\n contextObject,\n defaultValues,\n contextActionOptions,\n normalizedRequiredActionMode,\n shouldShowContextActions,\n contextActionRequired,\n contextActionType,\n })\n\n const composeDraftOperation = useComposeDraftOperation({\n t,\n messageType,\n priority,\n visibility,\n externalEmail,\n recipientIds,\n subject,\n body,\n bodyFormat,\n sendViaEmail,\n contextObject,\n defaultValues,\n contextActionOptions,\n normalizedRequiredActionMode,\n shouldShowContextActions,\n contextActionRequired,\n contextActionType,\n })\n\n const replyOperation = useReplySubmitOperation({\n t,\n messageId,\n body,\n bodyFormat,\n replyAll,\n recipientIds,\n sendViaEmail,\n })\n\n const forwardOperation = useForwardSubmitOperation({\n t,\n messageId,\n recipientIds,\n body,\n includeAttachments,\n sendViaEmail,\n })\n\n const handleSubmit = React.useCallback(async ({ saveAsDraft = false }: { saveAsDraft?: boolean } = {}) => {\n if (submitting) return false\n\n setSubmitError(null)\n\n const isComposeDraftSubmit = saveAsDraft && variant === 'compose'\n const operation = isComposeDraftSubmit\n ? composeDraftOperation\n : variant === 'compose'\n ? composeSendOperation\n : variant === 'reply'\n ? replyOperation\n : forwardOperation\n\n const validationMessage = operation.validate()\n if (validationMessage) {\n setSubmitError(validationMessage)\n flash(validationMessage, 'error')\n return false\n }\n\n setSubmitMode(isComposeDraftSubmit ? 'draft' : 'send')\n setSubmitting(true)\n\n try {\n let nextAttachmentIds = attachmentIds\n if (operation.requiresAttachmentRefresh) {\n try {\n nextAttachmentIds = await loadAttachmentIds()\n } catch (error) {\n const message = error instanceof Error\n ? error.message\n : t('messages.errors.loadAttachmentOptionsFailed', 'Failed to load attachments.')\n setSubmitError(message)\n flash(message, 'error')\n return false\n }\n }\n\n const { endpoint, payload } = operation.buildRequest({ attachmentIds: nextAttachmentIds })\n\n const call = await apiCall<{ id?: string }>(endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n\n if (!call.ok) {\n const message = toErrorMessage(call.result) ?? t('messages.errors.sendFailed', 'Failed to send message.')\n setSubmitError(message)\n flash(message, 'error')\n return false\n }\n\n flash(operation.successMessage, 'success')\n\n onSuccess?.({ id: call.result?.id })\n\n if (!inline) {\n onOpenChange?.(false)\n }\n return true\n } catch (error) {\n const message = error instanceof Error\n ? error.message\n : t('messages.errors.sendFailed', 'Failed to send message.')\n setSubmitError(message)\n flash(message, 'error')\n return false\n } finally {\n setSubmitting(false)\n setSubmitMode('send')\n }\n }, [\n attachmentIds,\n composeDraftOperation,\n composeSendOperation,\n forwardOperation,\n inline,\n loadAttachmentIds,\n onOpenChange,\n onSuccess,\n replyOperation,\n submitting,\n t,\n variant,\n ])\n\n const handleSaveDraft = React.useCallback(() => {\n if (variant !== 'compose') return\n void handleSubmit({ saveAsDraft: true })\n }, [handleSubmit, variant])\n\n const handleBack = React.useCallback(() => {\n if (submitting) return\n handleCancel()\n }, [handleCancel, submitting])\n\n const handleDialogOpenChange = React.useCallback((nextOpen: boolean) => {\n if (nextOpen) {\n onOpenChange?.(true)\n return\n }\n void handleBack()\n }, [handleBack, onOpenChange])\n\n const handleKeyDown = React.useCallback((event: React.KeyboardEvent<HTMLDivElement>) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n void handleSubmit()\n return\n }\n\n if (event.key === 'Escape') {\n event.preventDefault()\n handleCancel()\n }\n }, [handleCancel, handleSubmit])\n\n const composerTitle = variant === 'reply'\n ? t('messages.reply', 'Reply')\n : variant === 'forward'\n ? t('messages.forward', 'Forward')\n : t('messages.compose', 'Compose message')\n\n const submitLabel = submitting\n ? submitMode === 'draft'\n ? t('messages.savingDraft', 'Saving draft...')\n : t('messages.sending', 'Sending...')\n : variant === 'reply'\n ? t('messages.reply', 'Reply')\n : variant === 'forward'\n ? t('messages.forward', 'Forward')\n : t('messages.send', 'Send')\n\n return {\n t,\n variant,\n messageId,\n open,\n inline,\n contextPreview,\n isOpen,\n messageTypes,\n createableMessageTypes,\n normalizedRequiredActionMode,\n contextActionOptions,\n shouldShowContextActions,\n isComposePublicVisibility,\n attachmentEntityId,\n attachmentRecordId,\n recipientIds,\n setRecipientIds,\n messageType,\n setMessageType,\n subject,\n setSubject,\n body,\n setBody,\n bodyFormat,\n setBodyFormat,\n priority,\n setPriority,\n visibility,\n setVisibility,\n externalEmail,\n setExternalEmail,\n sendViaEmail,\n setSendViaEmail,\n contextActionRequired,\n setContextActionRequired,\n contextActionType,\n setContextActionType,\n replyAll,\n setReplyAll,\n includeAttachments,\n setIncludeAttachments,\n submitting,\n submitMode,\n submitError,\n composerTitle,\n submitLabel,\n selectedRecipientOptions,\n resolveRecipientLabel,\n loadRecipientSuggestions,\n loadAttachmentIds,\n handleSaveDraft,\n handleBack,\n handleSubmit,\n handleDialogOpenChange,\n handleKeyDown,\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import * as React from 'react'\nimport { useQuery } from '@tanstack/react-query'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { flash } from '../FlashMessages'\nimport { apiCall } from '../utils/apiCall'\nimport type {\n AttachmentListResponse,\n MessageComposerProps,\n MessageTypeItem,\n UserListItem,\n} from './message-composer.types'\nimport type { MessagePriority } from './message-priority'\nimport type { TagsInputOption } from '../inputs/TagsInput'\nimport {\n useComposeDraftOperation,\n useComposeSendOperation,\n useForwardSubmitOperation,\n useReplySubmitOperation,\n} from './useMessageComposeOperations'\n\nfunction toErrorMessage(payload: unknown): string | null {\n if (!payload) return null\n if (typeof payload === 'string') return payload\n if (Array.isArray(payload)) {\n for (const item of payload) {\n const nested = toErrorMessage(item)\n if (nested) return nested\n }\n return null\n }\n if (typeof payload === 'object') {\n const record = payload as Record<string, unknown>\n return (\n toErrorMessage(record.error)\n ?? toErrorMessage(record.message)\n ?? toErrorMessage(record.detail)\n ?? toErrorMessage(record.details)\n ?? null\n )\n }\n return null\n}\n\nfunction createTemporaryAttachmentRecordId(): string {\n const randomPart =\n typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n ? crypto.randomUUID()\n : `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`\n return `messages-composer:${randomPart}`\n}\n\nexport type UseMessageComposeParams = MessageComposerProps\n\nexport type UseMessageComposeResult = {\n t: ReturnType<typeof useT>\n variant: NonNullable<MessageComposerProps['variant']>\n messageId?: string\n open?: boolean\n inline: boolean\n contextPreview: React.ReactNode\n isOpen: boolean\n messageTypes: MessageTypeItem[]\n createableMessageTypes: MessageTypeItem[]\n normalizedRequiredActionMode: 'none' | 'optional' | 'required'\n contextActionOptions: Array<{ id: string; label: string }>\n shouldShowContextActions: boolean\n isComposePublicVisibility: boolean\n attachmentEntityId: string\n attachmentRecordId: string\n recipientIds: string[]\n setRecipientIds: React.Dispatch<React.SetStateAction<string[]>>\n messageType: string\n setMessageType: React.Dispatch<React.SetStateAction<string>>\n subject: string\n setSubject: React.Dispatch<React.SetStateAction<string>>\n body: string\n setBody: React.Dispatch<React.SetStateAction<string>>\n bodyFormat: 'text' | 'markdown'\n setBodyFormat: React.Dispatch<React.SetStateAction<'text' | 'markdown'>>\n priority: MessagePriority\n setPriority: React.Dispatch<React.SetStateAction<MessagePriority>>\n visibility: 'public' | 'internal'\n setVisibility: React.Dispatch<React.SetStateAction<'public' | 'internal'>>\n externalEmail: string\n setExternalEmail: React.Dispatch<React.SetStateAction<string>>\n sendViaEmail: boolean\n setSendViaEmail: React.Dispatch<React.SetStateAction<boolean>>\n contextActionRequired: boolean\n setContextActionRequired: React.Dispatch<React.SetStateAction<boolean>>\n contextActionType: string\n setContextActionType: React.Dispatch<React.SetStateAction<string>>\n replyAll: boolean\n setReplyAll: React.Dispatch<React.SetStateAction<boolean>>\n includeAttachments: boolean\n setIncludeAttachments: React.Dispatch<React.SetStateAction<boolean>>\n submitting: boolean\n submitMode: 'send' | 'draft'\n submitError: string | null\n composerTitle: string\n submitLabel: string\n selectedRecipientOptions: TagsInputOption[]\n resolveRecipientLabel: (id: string) => string\n loadRecipientSuggestions: (query?: string) => Promise<TagsInputOption[]>\n loadAttachmentIds: () => Promise<string[]>\n handleSaveDraft: () => void\n handleBack: () => void\n handleSubmit: ({ saveAsDraft }?: { saveAsDraft?: boolean }) => Promise<boolean>\n handleDialogOpenChange: (nextOpen: boolean) => void\n handleKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => void\n}\n\ntype ForwardPreviewResponse = {\n subject?: string\n body?: string\n}\n\nexport function useMessageCompose({\n variant: variantProp = 'compose',\n messageId,\n open,\n onOpenChange,\n inline = false,\n lockedType = null,\n contextObject = null,\n requiredActionConfig = null,\n contextPreview = null,\n defaultValues,\n onSuccess,\n onCancel,\n}: UseMessageComposeParams): UseMessageComposeResult {\n const t = useT()\n const variant = variantProp\n const isOpen = inline ? true : Boolean(open)\n const recipientSuggestionsCacheRef = React.useRef<TagsInputOption[] | null>(null)\n\n const [recipientIds, setRecipientIds] = React.useState<string[]>([])\n const [recipientMap, setRecipientMap] = React.useState<Record<string, TagsInputOption>>({})\n const [messageType, setMessageType] = React.useState(lockedType ?? 'default')\n const [subject, setSubject] = React.useState('')\n const [body, setBody] = React.useState('')\n const [bodyFormat, setBodyFormat] = React.useState<'text' | 'markdown'>('text')\n const [priority, setPriority] = React.useState<MessagePriority>('normal')\n const [visibility, setVisibility] = React.useState<'public' | 'internal'>('internal')\n const [externalEmail, setExternalEmail] = React.useState('')\n const [attachmentIds, setAttachmentIds] = React.useState<string[]>([])\n const [sendViaEmail, setSendViaEmail] = React.useState(false)\n const [contextActionRequired, setContextActionRequired] = React.useState(false)\n const [contextActionType, setContextActionType] = React.useState('')\n const [replyAll, setReplyAll] = React.useState(false)\n const [includeAttachments, setIncludeAttachments] = React.useState(true)\n const [temporaryAttachmentRecordId, setTemporaryAttachmentRecordId] = React.useState<string>(() =>\n createTemporaryAttachmentRecordId(),\n )\n const [submitting, setSubmitting] = React.useState(false)\n const [submitMode, setSubmitMode] = React.useState<'send' | 'draft'>('send')\n const [submitError, setSubmitError] = React.useState<string | null>(null)\n // Tracks whether the composer is currently in the \"open\" lifecycle so the init\n // effect below only runs on the closed \u2192 open transition, not on every parent\n // re-render that produces a new `defaultValues` / `contextObject` reference\n // while the user is typing. Without this guard, an inline literal\n // `defaultValues={{...}}` in a re-rendering parent (e.g. message detail page\n // with live notification badges or queue progress) would clear the body /\n // subject mid-keystroke. CI shard 9 surfaced this as TC-MSG-009 timing out\n // because `keyboard.type` characters appeared to \"type nowhere\" \u2014 they were\n // typed correctly, then immediately wiped by the next effect run.\n const isOpenRef = React.useRef(false)\n\n const messageTypesQuery = useQuery({\n queryKey: ['messages', 'types'],\n enabled: variant === 'compose' && isOpen,\n staleTime: 5 * 60 * 1000,\n queryFn: async () => {\n const call = await apiCall<{ items?: MessageTypeItem[] }>('/api/messages/types')\n if (!call.ok) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.loadTypesFailed', 'Failed to load message types.'),\n )\n }\n return Array.isArray(call.result?.items) ? call.result?.items ?? [] : []\n },\n })\n\n const messageTypes = React.useMemo(\n () => messageTypesQuery.data ?? [],\n [messageTypesQuery.data],\n )\n const createableMessageTypes = React.useMemo(\n () => messageTypes.filter((item) => item.isCreateableByUser !== false),\n [messageTypes],\n )\n const normalizedRequiredActionMode = requiredActionConfig?.mode ?? 'none'\n const contextActionOptions = React.useMemo(\n () => (requiredActionConfig?.options ?? []).filter((option) => option.id.trim().length > 0),\n [requiredActionConfig?.options],\n )\n const shouldShowContextActions = (\n variant === 'compose'\n && Boolean(contextObject)\n && normalizedRequiredActionMode !== 'none'\n && contextActionOptions.length > 0\n )\n\n const isComposePublicVisibility = variant === 'compose' && visibility === 'public'\n\n const attachmentEntityId = variant === 'compose' && messageId ? 'messages:message' : 'attachments:library'\n const attachmentRecordId = variant === 'compose' && messageId ? messageId : temporaryAttachmentRecordId\n\n const loadAttachmentIds = React.useCallback(async (): Promise<string[]> => {\n const params = new URLSearchParams()\n params.set('entityId', attachmentEntityId)\n params.set('recordId', attachmentRecordId)\n\n const call = await apiCall<AttachmentListResponse>(`/api/attachments?${params.toString()}`)\n if (!call.ok) {\n throw new Error(\n toErrorMessage(call.result)\n ?? t('messages.errors.loadAttachmentOptionsFailed', 'Failed to load attachments.'),\n )\n }\n\n const items = Array.isArray(call.result?.items) ? call.result.items : []\n const nextIds = items\n .map((item) => (typeof item?.id === 'string' ? item.id : ''))\n .filter((id) => id.length > 0)\n\n setAttachmentIds(nextIds)\n return nextIds\n }, [attachmentEntityId, attachmentRecordId, t])\n\n React.useEffect(() => {\n if (!isOpen) {\n isOpenRef.current = false\n return\n }\n // Only initialize on the closed \u2192 open transition. Subsequent parent\n // re-renders that change `defaultValues` / `contextObject` references\n // (inline object literals are a new reference on every render) MUST NOT\n // overwrite state the user has typed in.\n if (isOpenRef.current) return\n isOpenRef.current = true\n\n const nextRecipients = defaultValues?.recipients?.filter((value) => typeof value === 'string' && value.trim().length > 0) ?? []\n const dedupedRecipients = Array.from(new Set(nextRecipients))\n\n setRecipientIds(dedupedRecipients)\n setMessageType(lockedType ?? defaultValues?.type ?? 'default')\n setSubject(defaultValues?.subject ?? '')\n setBody(defaultValues?.body ?? '')\n setBodyFormat(defaultValues?.bodyFormat ?? 'text')\n setPriority(defaultValues?.priority ?? 'normal')\n setVisibility(defaultValues?.visibility ?? 'internal')\n setExternalEmail(defaultValues?.externalEmail ?? '')\n setAttachmentIds(\n Array.isArray(defaultValues?.attachmentIds)\n ? defaultValues.attachmentIds.filter((id): id is string => typeof id === 'string' && id.trim().length > 0)\n : [],\n )\n setSendViaEmail(Boolean(defaultValues?.sendViaEmail))\n if (contextObject) {\n const defaultContextActionType = requiredActionConfig?.defaultActionType?.trim() ?? ''\n const fallbackContextActionType = contextObject.actionType?.trim() ?? ''\n const selectedActionType = defaultContextActionType || fallbackContextActionType\n const selectedActionAllowed = contextActionOptions.some((option) => option.id === selectedActionType)\n const nextActionType = selectedActionAllowed ? selectedActionType : ''\n setContextActionType(nextActionType)\n if (normalizedRequiredActionMode === 'required') {\n setContextActionRequired(true)\n } else if (normalizedRequiredActionMode === 'optional') {\n setContextActionRequired(Boolean(nextActionType) || Boolean(contextObject.actionRequired))\n } else {\n setContextActionRequired(Boolean(contextObject.actionRequired))\n }\n } else {\n setContextActionType('')\n setContextActionRequired(false)\n }\n setReplyAll(Boolean(defaultValues?.replyAll))\n setIncludeAttachments(defaultValues?.includeAttachments !== false)\n setTemporaryAttachmentRecordId(createTemporaryAttachmentRecordId())\n setSubmitError(null)\n }, [\n contextActionOptions,\n contextObject,\n defaultValues,\n isOpen,\n lockedType,\n normalizedRequiredActionMode,\n requiredActionConfig?.defaultActionType,\n ])\n\n React.useEffect(() => {\n if (!isOpen) return\n if (variant !== 'forward') return\n if (!messageId) return\n\n let isActive = true\n\n void (async () => {\n const call = await apiCall<ForwardPreviewResponse>(`/api/messages/${encodeURIComponent(messageId)}/forward-preview`)\n if (!isActive) return\n\n if (!call.ok) {\n const message = toErrorMessage(call.result)\n ?? t('messages.errors.forwardPreviewFailed', 'Failed to load forward preview.')\n setSubmitError(message)\n flash(message, 'error')\n return\n }\n\n if (typeof call.result?.subject === 'string') {\n setSubject((previousValue) => (previousValue.trim().length > 0 ? previousValue : call.result?.subject ?? ''))\n }\n if (typeof call.result?.body === 'string') {\n setBody((previousValue) => (previousValue.trim().length > 0 ? previousValue : call.result?.body ?? ''))\n }\n setBodyFormat('text')\n })().catch((error) => {\n if (!isActive) return\n const message = error instanceof Error\n ? error.message\n : t('messages.errors.forwardPreviewFailed', 'Failed to load forward preview.')\n setSubmitError(message)\n flash(message, 'error')\n })\n\n return () => {\n isActive = false\n }\n }, [isOpen, messageId, t, variant])\n\n React.useEffect(() => {\n if (!isOpen) return\n if (variant !== 'compose' && variant !== 'reply') return\n void loadAttachmentIds().catch(() => null)\n }, [isOpen, loadAttachmentIds, variant])\n\n React.useEffect(() => {\n if (variant !== 'compose') return\n if (!createableMessageTypes.length) return\n\n if (lockedType) {\n if (createableMessageTypes.some((item) => item.type === lockedType)) {\n setMessageType(lockedType)\n return\n }\n const defaultType = createableMessageTypes.find((item) => item.type === 'default')\n setMessageType(defaultType?.type ?? createableMessageTypes[0]?.type ?? 'default')\n return\n }\n\n if (createableMessageTypes.some((item) => item.type === messageType)) return\n\n const defaultType = createableMessageTypes.find((item) => item.type === 'default')\n setMessageType(defaultType?.type ?? createableMessageTypes[0]?.type ?? 'default')\n }, [createableMessageTypes, lockedType, messageType, variant])\n\n React.useEffect(() => {\n if (variant !== 'compose') return\n if (visibility !== 'public') return\n setSendViaEmail(true)\n setRecipientIds([])\n }, [variant, visibility])\n\n React.useEffect(() => {\n if (isOpen) return\n recipientSuggestionsCacheRef.current = null\n }, [isOpen])\n\n const resolveRecipientLabel = React.useCallback((id: string) => {\n return recipientMap[id]?.label ?? id\n }, [recipientMap])\n\n const selectedRecipientOptions = React.useMemo(() => {\n return recipientIds.map((id) => recipientMap[id] ?? { value: id, label: id })\n }, [recipientIds, recipientMap])\n\n const loadRecipientSuggestions = React.useCallback(async (_query?: string) => {\n const cachedOptions = recipientSuggestionsCacheRef.current\n if (cachedOptions) {\n return cachedOptions\n }\n\n const params = new URLSearchParams()\n params.set('page', '1')\n params.set('pageSize', '100')\n // Recipient lookup is filtered in TagsInput because incremental auth user search is unreliable.\n\n const call = await apiCall<{ items?: UserListItem[] }>(`/api/auth/users?${params.toString()}`)\n if (!call.ok) {\n return []\n }\n\n const rawItems = Array.isArray(call.result?.items) ? call.result?.items ?? [] : []\n const options: TagsInputOption[] = []\n for (const item of rawItems) {\n if (!item || typeof item !== 'object') continue\n const id = typeof item.id === 'string' ? item.id : ''\n if (!id) continue\n\n const email = typeof item.email === 'string' && item.email.trim().length ? item.email.trim() : id\n const name = typeof item.name === 'string' && item.name.trim().length ? item.name.trim() : undefined\n\n options.push({\n value: id,\n label: email,\n description: name,\n })\n }\n\n if (options.length) {\n setRecipientMap((prev) => {\n const next = { ...prev }\n for (const option of options) {\n next[option.value] = option\n }\n return next\n })\n }\n\n recipientSuggestionsCacheRef.current = options\n return options\n }, [])\n\n const handleCancel = React.useCallback(() => {\n if (submitting) return\n if (!inline) {\n onOpenChange?.(false)\n }\n onCancel?.()\n }, [inline, onCancel, onOpenChange, submitting])\n\n const composeSendOperation = useComposeSendOperation({\n t,\n messageType,\n createableMessageTypes,\n priority,\n visibility,\n externalEmail,\n recipientIds,\n subject,\n body,\n bodyFormat,\n sendViaEmail,\n contextObject,\n defaultValues,\n contextActionOptions,\n normalizedRequiredActionMode,\n shouldShowContextActions,\n contextActionRequired,\n contextActionType,\n })\n\n const composeDraftOperation = useComposeDraftOperation({\n t,\n messageType,\n priority,\n visibility,\n externalEmail,\n recipientIds,\n subject,\n body,\n bodyFormat,\n sendViaEmail,\n contextObject,\n defaultValues,\n contextActionOptions,\n normalizedRequiredActionMode,\n shouldShowContextActions,\n contextActionRequired,\n contextActionType,\n })\n\n const replyOperation = useReplySubmitOperation({\n t,\n messageId,\n body,\n bodyFormat,\n replyAll,\n recipientIds,\n sendViaEmail,\n })\n\n const forwardOperation = useForwardSubmitOperation({\n t,\n messageId,\n recipientIds,\n body,\n includeAttachments,\n sendViaEmail,\n })\n\n const handleSubmit = React.useCallback(async ({ saveAsDraft = false }: { saveAsDraft?: boolean } = {}) => {\n if (submitting) return false\n\n setSubmitError(null)\n\n const isComposeDraftSubmit = saveAsDraft && variant === 'compose'\n const operation = isComposeDraftSubmit\n ? composeDraftOperation\n : variant === 'compose'\n ? composeSendOperation\n : variant === 'reply'\n ? replyOperation\n : forwardOperation\n\n const validationMessage = operation.validate()\n if (validationMessage) {\n setSubmitError(validationMessage)\n flash(validationMessage, 'error')\n return false\n }\n\n setSubmitMode(isComposeDraftSubmit ? 'draft' : 'send')\n setSubmitting(true)\n\n try {\n let nextAttachmentIds = attachmentIds\n if (operation.requiresAttachmentRefresh) {\n try {\n nextAttachmentIds = await loadAttachmentIds()\n } catch (error) {\n const message = error instanceof Error\n ? error.message\n : t('messages.errors.loadAttachmentOptionsFailed', 'Failed to load attachments.')\n setSubmitError(message)\n flash(message, 'error')\n return false\n }\n }\n\n const { endpoint, payload } = operation.buildRequest({ attachmentIds: nextAttachmentIds })\n\n const call = await apiCall<{ id?: string }>(endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n\n if (!call.ok) {\n const message = toErrorMessage(call.result) ?? t('messages.errors.sendFailed', 'Failed to send message.')\n setSubmitError(message)\n flash(message, 'error')\n return false\n }\n\n flash(operation.successMessage, 'success')\n\n onSuccess?.({ id: call.result?.id })\n\n if (!inline) {\n onOpenChange?.(false)\n }\n return true\n } catch (error) {\n const message = error instanceof Error\n ? error.message\n : t('messages.errors.sendFailed', 'Failed to send message.')\n setSubmitError(message)\n flash(message, 'error')\n return false\n } finally {\n setSubmitting(false)\n setSubmitMode('send')\n }\n }, [\n attachmentIds,\n composeDraftOperation,\n composeSendOperation,\n forwardOperation,\n inline,\n loadAttachmentIds,\n onOpenChange,\n onSuccess,\n replyOperation,\n submitting,\n t,\n variant,\n ])\n\n const handleSaveDraft = React.useCallback(() => {\n if (variant !== 'compose') return\n void handleSubmit({ saveAsDraft: true })\n }, [handleSubmit, variant])\n\n const handleBack = React.useCallback(() => {\n if (submitting) return\n handleCancel()\n }, [handleCancel, submitting])\n\n const handleDialogOpenChange = React.useCallback((nextOpen: boolean) => {\n if (nextOpen) {\n onOpenChange?.(true)\n return\n }\n void handleBack()\n }, [handleBack, onOpenChange])\n\n const handleKeyDown = React.useCallback((event: React.KeyboardEvent<HTMLDivElement>) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n void handleSubmit()\n return\n }\n\n if (event.key === 'Escape') {\n event.preventDefault()\n handleCancel()\n }\n }, [handleCancel, handleSubmit])\n\n const composerTitle = variant === 'reply'\n ? t('messages.reply', 'Reply')\n : variant === 'forward'\n ? t('messages.forward', 'Forward')\n : t('messages.compose', 'Compose message')\n\n const submitLabel = submitting\n ? submitMode === 'draft'\n ? t('messages.savingDraft', 'Saving draft...')\n : t('messages.sending', 'Sending...')\n : variant === 'reply'\n ? t('messages.reply', 'Reply')\n : variant === 'forward'\n ? t('messages.forward', 'Forward')\n : t('messages.send', 'Send')\n\n return {\n t,\n variant,\n messageId,\n open,\n inline,\n contextPreview,\n isOpen,\n messageTypes,\n createableMessageTypes,\n normalizedRequiredActionMode,\n contextActionOptions,\n shouldShowContextActions,\n isComposePublicVisibility,\n attachmentEntityId,\n attachmentRecordId,\n recipientIds,\n setRecipientIds,\n messageType,\n setMessageType,\n subject,\n setSubject,\n body,\n setBody,\n bodyFormat,\n setBodyFormat,\n priority,\n setPriority,\n visibility,\n setVisibility,\n externalEmail,\n setExternalEmail,\n sendViaEmail,\n setSendViaEmail,\n contextActionRequired,\n setContextActionRequired,\n contextActionType,\n setContextActionType,\n replyAll,\n setReplyAll,\n includeAttachments,\n setIncludeAttachments,\n submitting,\n submitMode,\n submitError,\n composerTitle,\n submitLabel,\n selectedRecipientOptions,\n resolveRecipientLabel,\n loadRecipientSuggestions,\n loadAttachmentIds,\n handleSaveDraft,\n handleBack,\n handleSubmit,\n handleDialogOpenChange,\n handleKeyDown,\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["defaultType"]
7
7
  }
@@ -4,6 +4,13 @@ import { useId, useTransition } from "react";
4
4
  import { useLocale, useT } from "@open-mercato/shared/lib/i18n/context";
5
5
  import { useRouter } from "next/navigation";
6
6
  import { locales } from "@open-mercato/shared/lib/i18n/config";
7
+ import {
8
+ Select,
9
+ SelectContent,
10
+ SelectItem,
11
+ SelectTrigger,
12
+ SelectValue
13
+ } from "@open-mercato/ui/primitives/select";
7
14
  function LanguageSwitcher() {
8
15
  const current = useLocale();
9
16
  const t = useT();
@@ -35,20 +42,18 @@ function LanguageSwitcher() {
35
42
  }
36
43
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
37
44
  /* @__PURE__ */ jsx("label", { htmlFor: selectId, children: t("common.language") }),
38
- /* @__PURE__ */ jsxs("div", { className: "relative", children: [
39
- /* @__PURE__ */ jsx(
40
- "select",
41
- {
42
- id: selectId,
43
- className: "appearance-none rounded-md border bg-background px-3 py-1 pr-8 text-xs focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 disabled:opacity-50",
44
- value: current,
45
- onChange: (event) => setLocale(event.target.value),
46
- disabled: pending,
47
- children: locales.map((locale) => /* @__PURE__ */ jsx("option", { value: locale, children: languageLabels[locale] }, locale))
48
- }
49
- ),
50
- /* @__PURE__ */ jsx("span", { className: "pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground", children: /* @__PURE__ */ jsx("svg", { width: "10", height: "10", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx("path", { d: "M6 9l6 6 6-6" }) }) })
51
- ] })
45
+ /* @__PURE__ */ jsxs(
46
+ Select,
47
+ {
48
+ value: current,
49
+ onValueChange: (value) => setLocale(value),
50
+ disabled: pending,
51
+ children: [
52
+ /* @__PURE__ */ jsx(SelectTrigger, { id: selectId, size: "sm", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
53
+ /* @__PURE__ */ jsx(SelectContent, { children: locales.map((locale) => /* @__PURE__ */ jsx(SelectItem, { value: locale, children: languageLabels[locale] }, locale)) })
54
+ ]
55
+ }
56
+ )
52
57
  ] });
53
58
  }
54
59
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/frontend/LanguageSwitcher.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport { useId, useTransition } from 'react'\nimport { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useRouter } from 'next/navigation'\nimport { locales, type Locale } from '@open-mercato/shared/lib/i18n/config'\n\nexport function LanguageSwitcher() {\n const current = useLocale()\n const t = useT()\n const router = useRouter()\n const [pending, startTransition] = useTransition()\n const selectId = useId()\n\n const languageLabels: Record<Locale, string> = {\n en: t('common.languages.english', 'English'),\n pl: t('common.languages.polish', 'Polski'),\n es: t('common.languages.spanish', 'Espa\u00F1ol'),\n de: t('common.languages.german', 'Deutsch'),\n }\n\n async function setLocale(locale: Locale) {\n if (locale === current) return\n try {\n const res = await fetch('/api/auth/locale', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ locale }),\n })\n if (!res.ok) return\n startTransition(() => router.refresh())\n try {\n window.dispatchEvent(new Event('om:refresh-sidebar'))\n } catch {\n // Ignore if window is unavailable\n }\n } catch {\n // Ignore network errors; UX fallback keeps previous locale\n }\n }\n\n return (\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <label htmlFor={selectId}>{t('common.language')}</label>\n <div className=\"relative\">\n <select\n id={selectId}\n className=\"appearance-none rounded-md border bg-background px-3 py-1 pr-8 text-xs focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 disabled:opacity-50\"\n value={current}\n onChange={(event) => setLocale(event.target.value as Locale)}\n disabled={pending}\n >\n {locales.map((locale) => (\n <option key={locale} value={locale}>\n {languageLabels[locale]}\n </option>\n ))}\n </select>\n <span className=\"pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground\">\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M6 9l6 6 6-6\" />\n </svg>\n </span>\n </div>\n </div>\n )\n}\n"],
5
- "mappings": ";AA0CM,cACA,YADA;AAzCN,SAAS,OAAO,qBAAqB;AACrC,SAAS,WAAW,YAAY;AAChC,SAAS,iBAAiB;AAC1B,SAAS,eAA4B;AAE9B,SAAS,mBAAmB;AACjC,QAAM,UAAU,UAAU;AAC1B,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,UAAU;AACzB,QAAM,CAAC,SAAS,eAAe,IAAI,cAAc;AACjD,QAAM,WAAW,MAAM;AAEvB,QAAM,iBAAyC;AAAA,IAC7C,IAAI,EAAE,4BAA4B,SAAS;AAAA,IAC3C,IAAI,EAAE,2BAA2B,QAAQ;AAAA,IACzC,IAAI,EAAE,4BAA4B,YAAS;AAAA,IAC3C,IAAI,EAAE,2BAA2B,SAAS;AAAA,EAC5C;AAEA,iBAAe,UAAU,QAAgB;AACvC,QAAI,WAAW,QAAS;AACxB,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,oBAAoB;AAAA,QAC1C,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,OAAO,CAAC;AAAA,MACjC,CAAC;AACD,UAAI,CAAC,IAAI,GAAI;AACb,sBAAgB,MAAM,OAAO,QAAQ,CAAC;AACtC,UAAI;AACF,eAAO,cAAc,IAAI,MAAM,oBAAoB,CAAC;AAAA,MACtD,QAAQ;AAAA,MAER;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SACE,qBAAC,SAAI,WAAU,yDACb;AAAA,wBAAC,WAAM,SAAS,UAAW,YAAE,iBAAiB,GAAE;AAAA,IAChD,qBAAC,SAAI,WAAU,YACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,IAAI;AAAA,UACJ,WAAU;AAAA,UACV,OAAO;AAAA,UACP,UAAU,CAAC,UAAU,UAAU,MAAM,OAAO,KAAe;AAAA,UAC3D,UAAU;AAAA,UAET,kBAAQ,IAAI,CAAC,WACZ,oBAAC,YAAoB,OAAO,QACzB,yBAAe,MAAM,KADX,MAEb,CACD;AAAA;AAAA,MACH;AAAA,MACA,oBAAC,UAAK,WAAU,uFACd,8BAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAC5F,8BAAC,UAAK,GAAE,gBAAe,GACzB,GACF;AAAA,OACF;AAAA,KACF;AAEJ;",
4
+ "sourcesContent": ["\"use client\"\nimport { useId, useTransition } from 'react'\nimport { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useRouter } from 'next/navigation'\nimport { locales, type Locale } from '@open-mercato/shared/lib/i18n/config'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\n\nexport function LanguageSwitcher() {\n const current = useLocale()\n const t = useT()\n const router = useRouter()\n const [pending, startTransition] = useTransition()\n const selectId = useId()\n\n const languageLabels: Record<Locale, string> = {\n en: t('common.languages.english', 'English'),\n pl: t('common.languages.polish', 'Polski'),\n es: t('common.languages.spanish', 'Espa\u00F1ol'),\n de: t('common.languages.german', 'Deutsch'),\n }\n\n async function setLocale(locale: Locale) {\n if (locale === current) return\n try {\n const res = await fetch('/api/auth/locale', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ locale }),\n })\n if (!res.ok) return\n startTransition(() => router.refresh())\n try {\n window.dispatchEvent(new Event('om:refresh-sidebar'))\n } catch {\n // Ignore if window is unavailable\n }\n } catch {\n // Ignore network errors; UX fallback keeps previous locale\n }\n }\n\n return (\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <label htmlFor={selectId}>{t('common.language')}</label>\n <Select\n value={current}\n onValueChange={(value) => setLocale(value as Locale)}\n disabled={pending}\n >\n <SelectTrigger id={selectId} size=\"sm\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {locales.map((locale) => (\n <SelectItem key={locale} value={locale}>\n {languageLabels[locale]}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n )\n}\n"],
5
+ "mappings": ";AAiDM,cACA,YADA;AAhDN,SAAS,OAAO,qBAAqB;AACrC,SAAS,WAAW,YAAY;AAChC,SAAS,iBAAiB;AAC1B,SAAS,eAA4B;AACrC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEA,SAAS,mBAAmB;AACjC,QAAM,UAAU,UAAU;AAC1B,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,UAAU;AACzB,QAAM,CAAC,SAAS,eAAe,IAAI,cAAc;AACjD,QAAM,WAAW,MAAM;AAEvB,QAAM,iBAAyC;AAAA,IAC7C,IAAI,EAAE,4BAA4B,SAAS;AAAA,IAC3C,IAAI,EAAE,2BAA2B,QAAQ;AAAA,IACzC,IAAI,EAAE,4BAA4B,YAAS;AAAA,IAC3C,IAAI,EAAE,2BAA2B,SAAS;AAAA,EAC5C;AAEA,iBAAe,UAAU,QAAgB;AACvC,QAAI,WAAW,QAAS;AACxB,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,oBAAoB;AAAA,QAC1C,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,OAAO,CAAC;AAAA,MACjC,CAAC;AACD,UAAI,CAAC,IAAI,GAAI;AACb,sBAAgB,MAAM,OAAO,QAAQ,CAAC;AACtC,UAAI;AACF,eAAO,cAAc,IAAI,MAAM,oBAAoB,CAAC;AAAA,MACtD,QAAQ;AAAA,MAER;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SACE,qBAAC,SAAI,WAAU,yDACb;AAAA,wBAAC,WAAM,SAAS,UAAW,YAAE,iBAAiB,GAAE;AAAA,IAChD;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP,eAAe,CAAC,UAAU,UAAU,KAAe;AAAA,QACnD,UAAU;AAAA,QAEV;AAAA,8BAAC,iBAAc,IAAI,UAAU,MAAK,MAChC,8BAAC,eAAY,GACf;AAAA,UACA,oBAAC,iBACE,kBAAQ,IAAI,CAAC,WACZ,oBAAC,cAAwB,OAAO,QAC7B,yBAAe,MAAM,KADP,MAEjB,CACD,GACH;AAAA;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;",
6
6
  "names": []
7
7
  }
package/dist/index.js CHANGED
@@ -31,6 +31,11 @@ export * from "./primitives/social-button.js";
31
31
  export * from "./primitives/fancy-button.js";
32
32
  export * from "./primitives/checkbox.js";
33
33
  export * from "./primitives/checkbox-field.js";
34
+ export * from "./primitives/select.js";
35
+ export * from "./primitives/switch.js";
36
+ export * from "./primitives/switch-field.js";
37
+ export * from "./primitives/radio.js";
38
+ export * from "./primitives/radio-field.js";
34
39
  export * from "./primitives/label.js";
35
40
  export * from "./primitives/separator.js";
36
41
  export * from "./primitives/spinner.js";
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["export * from './theme/ThemeProvider'\nexport * from './theme/ThemeToggle'\nexport * from './theme/QueryProvider'\nexport * from './backend/AppShell'\nexport * from './backend/Page'\nexport * from './backend/DataTable'\nexport * from './backend/filters/AdvancedFilterBuilder'\nexport * from './backend/columns/ColumnChooserPanel'\nexport * from './backend/FilterBar'\nexport * from './backend/ValueIcons'\nexport * from './backend/confirm-dialog'\nexport * from './backend/UserMenu'\nexport * from './backend/RowActions'\nexport * from './backend/utils/nav'\nexport * from './backend/CrudForm'\nexport * from './backend/JsonBuilder'\nexport * from './backend/detail'\nexport * from './backend/TruncatedCell'\nexport * from './backend/schedule'\n\nexport * from './backend/inputs'\nexport * from './backend/ContextHelp'\nexport * from './backend/dashboard'\nexport * from './backend/messages'\nexport * from './frontend/Layout'\nexport * from './frontend/AuthFooter'\nexport * from './frontend/LanguageSwitcher'\nexport * from './primitives/button'\nexport * from './primitives/icon-button'\nexport * from './primitives/link-button'\nexport * from './primitives/social-button'\nexport * from './primitives/fancy-button'\nexport * from './primitives/checkbox'\nexport * from './primitives/checkbox-field'\nexport * from './primitives/label'\nexport * from './primitives/separator'\nexport * from './primitives/spinner'\nexport * from './primitives/tabs'\nexport * from './primitives/DataLoader'\nexport * from './primitives/table'\nexport * from './primitives/Notice'\nexport * from './primitives/ErrorNotice'\nexport * from './primitives/dialog'\nexport * from './primitives/progress'\n"],
5
- "mappings": "AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAEd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
4
+ "sourcesContent": ["export * from './theme/ThemeProvider'\nexport * from './theme/ThemeToggle'\nexport * from './theme/QueryProvider'\nexport * from './backend/AppShell'\nexport * from './backend/Page'\nexport * from './backend/DataTable'\nexport * from './backend/filters/AdvancedFilterBuilder'\nexport * from './backend/columns/ColumnChooserPanel'\nexport * from './backend/FilterBar'\nexport * from './backend/ValueIcons'\nexport * from './backend/confirm-dialog'\nexport * from './backend/UserMenu'\nexport * from './backend/RowActions'\nexport * from './backend/utils/nav'\nexport * from './backend/CrudForm'\nexport * from './backend/JsonBuilder'\nexport * from './backend/detail'\nexport * from './backend/TruncatedCell'\nexport * from './backend/schedule'\n\nexport * from './backend/inputs'\nexport * from './backend/ContextHelp'\nexport * from './backend/dashboard'\nexport * from './backend/messages'\nexport * from './frontend/Layout'\nexport * from './frontend/AuthFooter'\nexport * from './frontend/LanguageSwitcher'\nexport * from './primitives/button'\nexport * from './primitives/icon-button'\nexport * from './primitives/link-button'\nexport * from './primitives/social-button'\nexport * from './primitives/fancy-button'\nexport * from './primitives/checkbox'\nexport * from './primitives/checkbox-field'\nexport * from './primitives/select'\nexport * from './primitives/switch'\nexport * from './primitives/switch-field'\nexport * from './primitives/radio'\nexport * from './primitives/radio-field'\nexport * from './primitives/label'\nexport * from './primitives/separator'\nexport * from './primitives/spinner'\nexport * from './primitives/tabs'\nexport * from './primitives/DataLoader'\nexport * from './primitives/table'\nexport * from './primitives/Notice'\nexport * from './primitives/ErrorNotice'\nexport * from './primitives/dialog'\nexport * from './primitives/progress'\n"],
5
+ "mappings": "AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAEd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
6
6
  "names": []
7
7
  }
@@ -19,6 +19,7 @@ const CheckboxField = React.forwardRef(({
19
19
  }, ref) => {
20
20
  const reactId = React.useId();
21
21
  const id = idProp ?? `checkbox-field-${reactId}`;
22
+ const hasMultiLine = Boolean(description || sublabel || link);
22
23
  const checkbox = /* @__PURE__ */ jsx(
23
24
  Checkbox,
24
25
  {
@@ -26,7 +27,7 @@ const CheckboxField = React.forwardRef(({
26
27
  id,
27
28
  size,
28
29
  disabled,
29
- className: cn("mt-0.5", className),
30
+ className: cn(hasMultiLine && "mt-0.5", className),
30
31
  ...checkboxProps
31
32
  }
32
33
  );
@@ -51,10 +52,21 @@ const CheckboxField = React.forwardRef(({
51
52
  ] }),
52
53
  link ? /* @__PURE__ */ jsx("div", { className: "flex", children: link }) : null
53
54
  ] });
54
- return /* @__PURE__ */ jsxs("div", { className: cn("flex items-start gap-2", flip && "flex-row-reverse", containerClassName), children: [
55
- flip ? content : checkbox,
56
- flip ? checkbox : content
57
- ] });
55
+ return /* @__PURE__ */ jsxs(
56
+ "div",
57
+ {
58
+ className: cn(
59
+ "flex gap-2",
60
+ hasMultiLine ? "items-start" : "items-center",
61
+ flip && "flex-row-reverse",
62
+ containerClassName
63
+ ),
64
+ children: [
65
+ flip ? content : checkbox,
66
+ flip ? checkbox : content
67
+ ]
68
+ }
69
+ );
58
70
  });
59
71
  CheckboxField.displayName = "CheckboxField";
60
72
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/primitives/checkbox-field.tsx"],
4
- "sourcesContent": ["import * as React from \"react\"\nimport { cn } from \"@open-mercato/shared/lib/utils\"\nimport { Checkbox, type CheckboxProps } from \"./checkbox\"\n\nexport type CheckboxFieldProps = Omit<CheckboxProps, \"id\"> & {\n id?: string\n label: React.ReactNode\n sublabel?: React.ReactNode\n description?: React.ReactNode\n badge?: React.ReactNode\n link?: React.ReactNode\n /** When true, renders the checkbox on the right of the label content. */\n flip?: boolean\n /** Additional className for the outer wrapper. */\n containerClassName?: string\n /** Additional className for the right-side content stack. */\n contentClassName?: string\n}\n\nexport const CheckboxField = React.forwardRef<\n React.ElementRef<typeof Checkbox>,\n CheckboxFieldProps\n>(({\n id: idProp,\n label,\n sublabel,\n description,\n badge,\n link,\n flip = false,\n containerClassName,\n contentClassName,\n size = \"md\",\n className,\n disabled,\n ...checkboxProps\n}, ref) => {\n const reactId = React.useId()\n const id = idProp ?? `checkbox-field-${reactId}`\n\n const checkbox = (\n <Checkbox\n ref={ref}\n id={id}\n size={size}\n disabled={disabled}\n className={cn(\"mt-0.5\", className)}\n {...checkboxProps}\n />\n )\n\n const content = (\n <div className={cn(\"flex flex-1 min-w-0 flex-col gap-2.5\", contentClassName)}>\n <div className=\"flex flex-col gap-1\">\n <div className=\"flex flex-wrap items-center gap-1\">\n <label\n htmlFor={id}\n className={cn(\n \"text-sm font-medium leading-5 text-foreground select-none\",\n disabled ? \"cursor-not-allowed opacity-60\" : \"cursor-pointer\"\n )}\n >\n {label}\n </label>\n {sublabel ? (\n <span className=\"text-xs leading-4 text-muted-foreground select-none\">{sublabel}</span>\n ) : null}\n {badge ? <span className=\"inline-flex shrink-0\">{badge}</span> : null}\n </div>\n {description ? (\n <p className=\"text-xs leading-4 text-muted-foreground\">{description}</p>\n ) : null}\n </div>\n {link ? <div className=\"flex\">{link}</div> : null}\n </div>\n )\n\n return (\n <div className={cn(\"flex items-start gap-2\", flip && \"flex-row-reverse\", containerClassName)}>\n {flip ? content : checkbox}\n {flip ? checkbox : content}\n </div>\n )\n})\nCheckboxField.displayName = \"CheckboxField\"\n"],
5
- "mappings": "AAyCI,cAaI,YAbJ;AAzCJ,YAAY,WAAW;AACvB,SAAS,UAAU;AACnB,SAAS,gBAAoC;AAiBtC,MAAM,gBAAgB,MAAM,WAGjC,CAAC;AAAA,EACD,IAAI;AAAA,EACJ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAG,QAAQ;AACT,QAAM,UAAU,MAAM,MAAM;AAC5B,QAAM,KAAK,UAAU,kBAAkB,OAAO;AAE9C,QAAM,WACJ;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,GAAG,UAAU,SAAS;AAAA,MAChC,GAAG;AAAA;AAAA,EACN;AAGF,QAAM,UACJ,qBAAC,SAAI,WAAW,GAAG,wCAAwC,gBAAgB,GACzE;AAAA,yBAAC,SAAI,WAAU,uBACb;AAAA,2BAAC,SAAI,WAAU,qCACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT,WAAW;AAAA,cACT;AAAA,cACA,WAAW,kCAAkC;AAAA,YAC/C;AAAA,YAEC;AAAA;AAAA,QACH;AAAA,QACC,WACC,oBAAC,UAAK,WAAU,uDAAuD,oBAAS,IAC9E;AAAA,QACH,QAAQ,oBAAC,UAAK,WAAU,wBAAwB,iBAAM,IAAU;AAAA,SACnE;AAAA,MACC,cACC,oBAAC,OAAE,WAAU,2CAA2C,uBAAY,IAClE;AAAA,OACN;AAAA,IACC,OAAO,oBAAC,SAAI,WAAU,QAAQ,gBAAK,IAAS;AAAA,KAC/C;AAGF,SACE,qBAAC,SAAI,WAAW,GAAG,0BAA0B,QAAQ,oBAAoB,kBAAkB,GACxF;AAAA,WAAO,UAAU;AAAA,IACjB,OAAO,WAAW;AAAA,KACrB;AAEJ,CAAC;AACD,cAAc,cAAc;",
4
+ "sourcesContent": ["import * as React from \"react\"\nimport { cn } from \"@open-mercato/shared/lib/utils\"\nimport { Checkbox, type CheckboxProps } from \"./checkbox\"\n\nexport type CheckboxFieldProps = Omit<CheckboxProps, \"id\"> & {\n id?: string\n label: React.ReactNode\n sublabel?: React.ReactNode\n description?: React.ReactNode\n badge?: React.ReactNode\n link?: React.ReactNode\n /** When true, renders the checkbox on the right of the label content. */\n flip?: boolean\n /** Additional className for the outer wrapper. */\n containerClassName?: string\n /** Additional className for the right-side content stack. */\n contentClassName?: string\n}\n\nexport const CheckboxField = React.forwardRef<\n React.ElementRef<typeof Checkbox>,\n CheckboxFieldProps\n>(({\n id: idProp,\n label,\n sublabel,\n description,\n badge,\n link,\n flip = false,\n containerClassName,\n contentClassName,\n size = \"md\",\n className,\n disabled,\n ...checkboxProps\n}, ref) => {\n const reactId = React.useId()\n const id = idProp ?? `checkbox-field-${reactId}`\n\n const hasMultiLine = Boolean(description || sublabel || link)\n const checkbox = (\n <Checkbox\n ref={ref}\n id={id}\n size={size}\n disabled={disabled}\n className={cn(hasMultiLine && \"mt-0.5\", className)}\n {...checkboxProps}\n />\n )\n\n const content = (\n <div className={cn(\"flex flex-1 min-w-0 flex-col gap-2.5\", contentClassName)}>\n <div className=\"flex flex-col gap-1\">\n <div className=\"flex flex-wrap items-center gap-1\">\n <label\n htmlFor={id}\n className={cn(\n \"text-sm font-medium leading-5 text-foreground select-none\",\n disabled ? \"cursor-not-allowed opacity-60\" : \"cursor-pointer\"\n )}\n >\n {label}\n </label>\n {sublabel ? (\n <span className=\"text-xs leading-4 text-muted-foreground select-none\">{sublabel}</span>\n ) : null}\n {badge ? <span className=\"inline-flex shrink-0\">{badge}</span> : null}\n </div>\n {description ? (\n <p className=\"text-xs leading-4 text-muted-foreground\">{description}</p>\n ) : null}\n </div>\n {link ? <div className=\"flex\">{link}</div> : null}\n </div>\n )\n\n return (\n <div\n className={cn(\n \"flex gap-2\",\n hasMultiLine ? \"items-start\" : \"items-center\",\n flip && \"flex-row-reverse\",\n containerClassName\n )}\n >\n {flip ? content : checkbox}\n {flip ? checkbox : content}\n </div>\n )\n})\nCheckboxField.displayName = \"CheckboxField\"\n"],
5
+ "mappings": "AA0CI,cAaI,YAbJ;AA1CJ,YAAY,WAAW;AACvB,SAAS,UAAU;AACnB,SAAS,gBAAoC;AAiBtC,MAAM,gBAAgB,MAAM,WAGjC,CAAC;AAAA,EACD,IAAI;AAAA,EACJ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAG,QAAQ;AACT,QAAM,UAAU,MAAM,MAAM;AAC5B,QAAM,KAAK,UAAU,kBAAkB,OAAO;AAE9C,QAAM,eAAe,QAAQ,eAAe,YAAY,IAAI;AAC5D,QAAM,WACJ;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,GAAG,gBAAgB,UAAU,SAAS;AAAA,MAChD,GAAG;AAAA;AAAA,EACN;AAGF,QAAM,UACJ,qBAAC,SAAI,WAAW,GAAG,wCAAwC,gBAAgB,GACzE;AAAA,yBAAC,SAAI,WAAU,uBACb;AAAA,2BAAC,SAAI,WAAU,qCACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT,WAAW;AAAA,cACT;AAAA,cACA,WAAW,kCAAkC;AAAA,YAC/C;AAAA,YAEC;AAAA;AAAA,QACH;AAAA,QACC,WACC,oBAAC,UAAK,WAAU,uDAAuD,oBAAS,IAC9E;AAAA,QACH,QAAQ,oBAAC,UAAK,WAAU,wBAAwB,iBAAM,IAAU;AAAA,SACnE;AAAA,MACC,cACC,oBAAC,OAAE,WAAU,2CAA2C,uBAAY,IAClE;AAAA,OACN;AAAA,IACC,OAAO,oBAAC,SAAI,WAAU,QAAQ,gBAAK,IAAS;AAAA,KAC/C;AAGF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,eAAe,gBAAgB;AAAA,QAC/B,QAAQ;AAAA,QACR;AAAA,MACF;AAAA,MAEC;AAAA,eAAO,UAAU;AAAA,QACjB,OAAO,WAAW;AAAA;AAAA;AAAA,EACrB;AAEJ,CAAC;AACD,cAAc,cAAc;",
6
6
  "names": []
7
7
  }
@@ -1,22 +1,79 @@
1
- import { jsx } from "react/jsx-runtime";
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
+ import { cva } from "class-variance-authority";
3
4
  import { cn } from "@open-mercato/shared/lib/utils";
4
- const Input = React.forwardRef(
5
- ({ className, type = "text", ...props }, ref) => /* @__PURE__ */ jsx(
6
- "input",
7
- {
8
- ref,
9
- type,
10
- className: cn(
11
- "flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
12
- className
13
- ),
14
- ...props
5
+ const inputWrapperVariants = cva(
6
+ "inline-flex w-full items-center gap-2 rounded-md border border-input bg-background shadow-xs transition-colors focus-within:outline-none focus-within:shadow-focus focus-within:border-foreground hover:bg-muted/40 has-[input:disabled]:bg-bg-disabled has-[input:disabled]:border-border-disabled has-[input:disabled]:shadow-none has-[input:disabled]:hover:bg-bg-disabled has-[input[aria-invalid=true]]:border-destructive has-[input[aria-invalid=true]]:focus-within:border-destructive",
7
+ {
8
+ variants: {
9
+ size: {
10
+ sm: "h-8 px-2.5",
11
+ default: "h-9 px-3",
12
+ lg: "h-10 px-3"
13
+ }
14
+ },
15
+ defaultVariants: {
16
+ size: "default"
17
+ }
18
+ }
19
+ );
20
+ const inputElementVariants = cva(
21
+ "flex-1 min-w-0 bg-transparent border-0 outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:bg-transparent",
22
+ {
23
+ variants: {
24
+ size: {
25
+ sm: "text-xs",
26
+ default: "text-sm",
27
+ lg: "text-sm"
28
+ }
29
+ },
30
+ defaultVariants: {
31
+ size: "default"
15
32
  }
16
- )
33
+ }
34
+ );
35
+ const Input = React.forwardRef(
36
+ ({ className, inputClassName, type = "text", size, leftIcon, rightIcon, ...props }, ref) => {
37
+ return /* @__PURE__ */ jsxs(
38
+ "div",
39
+ {
40
+ className: cn(inputWrapperVariants({ size }), className),
41
+ "data-slot": "input-wrapper",
42
+ children: [
43
+ leftIcon ? /* @__PURE__ */ jsx(
44
+ "span",
45
+ {
46
+ className: "flex shrink-0 items-center text-muted-foreground [&_svg]:size-4",
47
+ "aria-hidden": "true",
48
+ children: leftIcon
49
+ }
50
+ ) : null,
51
+ /* @__PURE__ */ jsx(
52
+ "input",
53
+ {
54
+ ref,
55
+ type,
56
+ className: cn(inputElementVariants({ size }), inputClassName),
57
+ ...props
58
+ }
59
+ ),
60
+ rightIcon ? /* @__PURE__ */ jsx(
61
+ "span",
62
+ {
63
+ className: "flex shrink-0 items-center text-muted-foreground [&_svg]:size-4",
64
+ "aria-hidden": "true",
65
+ children: rightIcon
66
+ }
67
+ ) : null
68
+ ]
69
+ }
70
+ );
71
+ }
17
72
  );
18
73
  Input.displayName = "Input";
19
74
  export {
20
- Input
75
+ Input,
76
+ inputElementVariants,
77
+ inputWrapperVariants
21
78
  };
22
79
  //# sourceMappingURL=input.js.map