@stackcraftmx/calcita 0.28.0 → 0.30.1
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.
- package/README.md +149 -4
- package/dist/DataTable/AuditTrailDialog.js +18 -14
- package/dist/DataTable/AuditTrailDialog.js.map +1 -1
- package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js +12 -6
- package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js.map +1 -1
- package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js +8 -3
- package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js.map +1 -1
- package/dist/DataTable/ColumnFilters/SortableFilterHeader.js +26 -18
- package/dist/DataTable/ColumnFilters/SortableFilterHeader.js.map +1 -1
- package/dist/DataTable/EmptyState.js +8 -3
- package/dist/DataTable/EmptyState.js.map +1 -1
- package/dist/DataTable/FilterChips.js +11 -5
- package/dist/DataTable/FilterChips.js.map +1 -1
- package/dist/DataTable/GoToPage.js +9 -4
- package/dist/DataTable/GoToPage.js.map +1 -1
- package/dist/DataTable/ServerTable.js +74 -61
- package/dist/DataTable/ServerTable.js.map +1 -1
- package/dist/DataTable/columns.js +1 -8
- package/dist/DataTable/columns.js.map +1 -1
- package/dist/access/PermissionMatrix.js +18 -9
- package/dist/access/PermissionMatrix.js.map +1 -1
- package/dist/account/AccountSecuritySection.js +8 -3
- package/dist/account/AccountSecuritySection.js.map +1 -1
- package/dist/account/DemoTotpCodeButton.js +8 -3
- package/dist/account/DemoTotpCodeButton.js.map +1 -1
- package/dist/account/ProfileScreen.js +19 -13
- package/dist/account/ProfileScreen.js.map +1 -1
- package/dist/account/SignInScreen.js +6 -2
- package/dist/account/SignInScreen.js.map +1 -1
- package/dist/appShell/AccountMenu.js +13 -5
- package/dist/appShell/AccountMenu.js.map +1 -1
- package/dist/appShell/AppLayout.js +100 -71
- package/dist/appShell/AppLayout.js.map +1 -1
- package/dist/appShell/AppearanceSettings.js +21 -13
- package/dist/appShell/AppearanceSettings.js.map +1 -1
- package/dist/appShell/AuthLayout.js +26 -13
- package/dist/appShell/AuthLayout.js.map +1 -1
- package/dist/appShell/BarActions.js +10 -5
- package/dist/appShell/BarActions.js.map +1 -1
- package/dist/appShell/BarCapsule.js +9 -4
- package/dist/appShell/BarCapsule.js.map +1 -1
- package/dist/appShell/BarSearch.js +7 -3
- package/dist/appShell/BarSearch.js.map +1 -1
- package/dist/appShell/HeaderTools.js +20 -15
- package/dist/appShell/HeaderTools.js.map +1 -1
- package/dist/appShell/MobileTabBar.js +25 -14
- package/dist/appShell/MobileTabBar.js.map +1 -1
- package/dist/appShell/SettingsMenu.js +7 -3
- package/dist/appShell/SettingsMenu.js.map +1 -1
- package/dist/appShell/SideMenu.js +53 -35
- package/dist/appShell/SideMenu.js.map +1 -1
- package/dist/appShell/SideMenuEntry.js +18 -9
- package/dist/appShell/SideMenuEntry.js.map +1 -1
- package/dist/appShell/SubmenuActionsMenu.js +6 -2
- package/dist/appShell/SubmenuActionsMenu.js.map +1 -1
- package/dist/appShell/TabBarEditor.js +16 -7
- package/dist/appShell/TabBarEditor.js.map +1 -1
- package/dist/appShell/TopMenu.js +12 -7
- package/dist/appShell/TopMenu.js.map +1 -1
- package/dist/appShell/Wordmark.js +23 -4
- package/dist/appShell/Wordmark.js.map +1 -1
- package/dist/auth/PasswordChecklist.js +14 -7
- package/dist/auth/PasswordChecklist.js.map +1 -1
- package/dist/calendar/EventCalendar.js +26 -19
- package/dist/calendar/EventCalendar.js.map +1 -1
- package/dist/calendar/EventDetails.js +28 -13
- package/dist/calendar/EventDetails.js.map +1 -1
- package/dist/downloads/DownloadManager.js +34 -18
- package/dist/downloads/DownloadManager.js.map +1 -1
- package/dist/feedback/ConfirmDialog.js +22 -17
- package/dist/feedback/ConfirmDialog.js.map +1 -1
- package/dist/feedback/ModalWaiting.js +12 -5
- package/dist/feedback/ModalWaiting.js.map +1 -1
- package/dist/feedback/NewBuildNotice.js +16 -8
- package/dist/feedback/NewBuildNotice.js.map +1 -1
- package/dist/filepond/FileDropzone.js +39 -31
- package/dist/filepond/FileDropzone.js.map +1 -1
- package/dist/forms/FormProblemAlert.js +4 -1
- package/dist/forms/FormProblemAlert.js.map +1 -1
- package/dist/forms/auth/SignInForm.js +6 -2
- package/dist/forms/auth/SignInForm.js.map +1 -1
- package/dist/forms/security/SecondStepForm.js +6 -2
- package/dist/forms/security/SecondStepForm.js.map +1 -1
- package/dist/forms/security/TwoStepVerificationCard.js +19 -9
- package/dist/forms/security/TwoStepVerificationCard.js.map +1 -1
- package/dist/hookForm/FormProblemAlert.js +4 -1
- package/dist/hookForm/FormProblemAlert.js.map +1 -1
- package/dist/inbox/InboxLayout.js +47 -29
- package/dist/inbox/InboxLayout.js.map +1 -1
- package/dist/inbox/MessageList.js +53 -32
- package/dist/inbox/MessageList.js.map +1 -1
- package/dist/inbox/MessageView.js +31 -15
- package/dist/inbox/MessageView.js.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/inputs/ColorInput.js +22 -17
- package/dist/inputs/ColorInput.js.map +1 -1
- package/dist/inputs/FormSection.js +64 -64
- package/dist/inputs/FormSection.js.map +1 -1
- package/dist/inputs/SelectInput.js +21 -16
- package/dist/inputs/SelectInput.js.map +1 -1
- package/dist/inputs/TextInput.js +25 -20
- package/dist/inputs/TextInput.js.map +1 -1
- package/dist/inputs/WizardLayout.js +21 -15
- package/dist/inputs/WizardLayout.js.map +1 -1
- package/dist/kanban/KanbanBoard.js +82 -50
- package/dist/kanban/KanbanBoard.js.map +1 -1
- package/dist/maps/MapView.js +19 -14
- package/dist/maps/MapView.js.map +1 -1
- package/dist/pwa/InstallAppSetting.js +4 -1
- package/dist/pwa/InstallAppSetting.js.map +1 -1
- package/dist/pwa/InstallInstructionsDialog.js +6 -2
- package/dist/pwa/InstallInstructionsDialog.js.map +1 -1
- package/dist/pwa/InstallPromptBanner.js +10 -5
- package/dist/pwa/InstallPromptBanner.js.map +1 -1
- package/dist/security/ActivityLog.js +6 -2
- package/dist/security/ActivityLog.js.map +1 -1
- package/dist/security/RecoveryCodesDialog.js +8 -3
- package/dist/security/RecoveryCodesDialog.js.map +1 -1
- package/dist/security/SessionsCard.js +12 -5
- package/dist/security/SessionsCard.js.map +1 -1
- package/dist/theme/components/glassComponents.js +19 -16
- package/dist/theme/components/glassComponents.js.map +1 -1
- package/dist/theme/components/minimalComponents.js +6 -2
- package/dist/theme/components/minimalComponents.js.map +1 -1
- package/dist/theme/createToolkitTheme.js +8 -1
- package/dist/theme/createToolkitTheme.js.map +1 -1
- package/dist/theme/cssTokens.js +23 -0
- package/dist/theme/cssTokens.js.map +1 -0
- package/dist/theme/glassSurface.js +15 -4
- package/dist/theme/glassSurface.js.map +1 -1
- package/dist/theme/glassToasterStyles.js +2 -3
- package/dist/theme/glassToasterStyles.js.map +1 -1
- package/dist/theme/themePieces.js +16 -0
- package/dist/theme/themePieces.js.map +1 -0
- package/dist/types/DataTable/AuditTrailDialog.d.ts +1 -1
- package/dist/types/DataTable/ColumnFilters/HeaderFilterPopover.d.ts +1 -1
- package/dist/types/DataTable/ColumnFilters/MultiSelectColumnFilter.d.ts +1 -1
- package/dist/types/DataTable/ColumnFilters/SortableFilterHeader.d.ts +1 -1
- package/dist/types/DataTable/EmptyState.d.ts +1 -1
- package/dist/types/DataTable/FilterChips.d.ts +1 -1
- package/dist/types/DataTable/GoToPage.d.ts +1 -1
- package/dist/types/DataTable/ServerTable.d.ts +1 -1
- package/dist/types/access/PermissionMatrix.d.ts +1 -1
- package/dist/types/account/AccountSecuritySection.d.ts +1 -1
- package/dist/types/account/DemoTotpCodeButton.d.ts +1 -1
- package/dist/types/account/ProfileScreen.d.ts +1 -1
- package/dist/types/account/SignInScreen.d.ts +1 -1
- package/dist/types/appShell/AccountMenu.d.ts +1 -1
- package/dist/types/appShell/AppLayout.d.ts +8 -4
- package/dist/types/appShell/AppearanceSettings.d.ts +1 -1
- package/dist/types/appShell/AuthLayout.d.ts +1 -1
- package/dist/types/appShell/BarActions.d.ts +1 -1
- package/dist/types/appShell/BarCapsule.d.ts +1 -1
- package/dist/types/appShell/BarSearch.d.ts +1 -1
- package/dist/types/appShell/HeaderTools.d.ts +1 -1
- package/dist/types/appShell/MobileTabBar.d.ts +1 -1
- package/dist/types/appShell/SettingsMenu.d.ts +1 -1
- package/dist/types/appShell/SideMenu.d.ts +7 -3
- package/dist/types/appShell/SideMenuEntry.d.ts +1 -1
- package/dist/types/appShell/SubmenuActionsMenu.d.ts +1 -1
- package/dist/types/appShell/TabBarEditor.d.ts +1 -1
- package/dist/types/appShell/TopMenu.d.ts +1 -1
- package/dist/types/appShell/Wordmark.d.ts +15 -3
- package/dist/types/auth/PasswordChecklist.d.ts +1 -1
- package/dist/types/calendar/EventCalendar.d.ts +1 -1
- package/dist/types/calendar/EventDetails.d.ts +1 -1
- package/dist/types/feedback/ConfirmDialog.d.ts +1 -1
- package/dist/types/feedback/ModalWaiting.d.ts +1 -1
- package/dist/types/feedback/NewBuildNotice.d.ts +1 -1
- package/dist/types/filepond/FileDropzone.d.ts +1 -1
- package/dist/types/forms/auth/SignInForm.d.ts +1 -1
- package/dist/types/forms/security/SecondStepForm.d.ts +1 -1
- package/dist/types/forms/security/TwoStepVerificationCard.d.ts +1 -1
- package/dist/types/inbox/InboxLayout.d.ts +1 -1
- package/dist/types/inbox/MessageList.d.ts +1 -1
- package/dist/types/inbox/MessageView.d.ts +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/inputs/ColorInput.d.ts +1 -1
- package/dist/types/inputs/FormSection.d.ts +2 -2
- package/dist/types/inputs/SelectInput.d.ts +1 -1
- package/dist/types/inputs/TextInput.d.ts +1 -1
- package/dist/types/inputs/WizardLayout.d.ts +1 -1
- package/dist/types/kanban/KanbanBoard.d.ts +1 -1
- package/dist/types/maps/MapView.d.ts +1 -1
- package/dist/types/pwa/InstallInstructionsDialog.d.ts +1 -1
- package/dist/types/pwa/InstallPromptBanner.d.ts +1 -1
- package/dist/types/security/ActivityLog.d.ts +1 -1
- package/dist/types/security/RecoveryCodesDialog.d.ts +1 -1
- package/dist/types/security/SessionsCard.d.ts +1 -1
- package/dist/types/theme/createToolkitTheme.d.ts +12 -1
- package/dist/types/theme/cssTokens.d.ts +46 -0
- package/dist/types/theme/glassSurface.d.ts +3 -0
- package/dist/types/theme/themePieces.d.ts +20 -0
- package/dist/types/ui/actions/ActionsMenu.d.ts +1 -1
- package/dist/types/ui/actions/DownloadMenu.d.ts +1 -1
- package/dist/types/ui/actions/SelectionActions.d.ts +1 -1
- package/dist/types/ui/filters/DateRangeFilter.d.ts +1 -1
- package/dist/types/ui/filters/PeriodRangeSelector.d.ts +1 -1
- package/dist/types/ui/filters/QuickFilters.d.ts +1 -1
- package/dist/types/ui/filters/SegmentedControl.d.ts +7 -2
- package/dist/types/ui/labels/StatusChip.d.ts +1 -1
- package/dist/types/ui/labels/Tag.d.ts +1 -1
- package/dist/types/ui/layout/CollapsibleSection.d.ts +1 -1
- package/dist/types/ui/layout/ContentDialog.d.ts +1 -1
- package/dist/types/ui/layout/DefinitionList.d.ts +1 -1
- package/dist/types/ui/layout/DetailHeader.d.ts +1 -1
- package/dist/types/ui/layout/ErrorPage.d.ts +1 -1
- package/dist/types/ui/layout/GlassPanel.d.ts +1 -1
- package/dist/types/ui/layout/PageHeader.d.ts +1 -1
- package/dist/types/ui/layout/PageHeading.d.ts +1 -1
- package/dist/types/ui/layout/ProfileHeader.d.ts +1 -1
- package/dist/types/ui/layout/ScrollableRow.d.ts +1 -1
- package/dist/types/ui/layout/SectionCard.d.ts +1 -1
- package/dist/types/ui/metrics/BarList.d.ts +1 -1
- package/dist/types/ui/metrics/CalendarHeatmap.d.ts +1 -1
- package/dist/types/ui/metrics/ChartTooltip.d.ts +1 -1
- package/dist/types/ui/metrics/ColumnChart.d.ts +1 -1
- package/dist/types/ui/metrics/LineChart.d.ts +1 -1
- package/dist/types/ui/metrics/MetricCard.d.ts +1 -1
- package/dist/types/ui/metrics/TableToggle.d.ts +1 -1
- package/dist/types/ui/navigation/ColorSchemeToggle.d.ts +1 -1
- package/dist/types/ui/navigation/FontSizeToggle.d.ts +1 -1
- package/dist/types/ui/navigation/LanguageToggle.d.ts +1 -1
- package/dist/types/ui/navigation/PageBreadcrumbs.d.ts +1 -1
- package/dist/types/ui/timeline/GroupedTimeline.d.ts +1 -1
- package/dist/types/upload/FileDropzone.d.ts +1 -1
- package/dist/ui/actions/ActionsMenu.js +9 -4
- package/dist/ui/actions/ActionsMenu.js.map +1 -1
- package/dist/ui/actions/DownloadMenu.js +21 -17
- package/dist/ui/actions/DownloadMenu.js.map +1 -1
- package/dist/ui/actions/SelectionActions.js +15 -7
- package/dist/ui/actions/SelectionActions.js.map +1 -1
- package/dist/ui/filters/DateRangeFilter.js +11 -5
- package/dist/ui/filters/DateRangeFilter.js.map +1 -1
- package/dist/ui/filters/PeriodRangeSelector.js +11 -5
- package/dist/ui/filters/PeriodRangeSelector.js.map +1 -1
- package/dist/ui/filters/QuickFilters.js +16 -8
- package/dist/ui/filters/QuickFilters.js.map +1 -1
- package/dist/ui/filters/SegmentedControl.js +12 -5
- package/dist/ui/filters/SegmentedControl.js.map +1 -1
- package/dist/ui/labels/StatusChip.js +35 -25
- package/dist/ui/labels/StatusChip.js.map +1 -1
- package/dist/ui/labels/Tag.js +8 -3
- package/dist/ui/labels/Tag.js.map +1 -1
- package/dist/ui/layout/CollapsibleSection.js +18 -8
- package/dist/ui/layout/CollapsibleSection.js.map +1 -1
- package/dist/ui/layout/ContentDialog.js +13 -6
- package/dist/ui/layout/ContentDialog.js.map +1 -1
- package/dist/ui/layout/DefinitionList.js +13 -6
- package/dist/ui/layout/DefinitionList.js.map +1 -1
- package/dist/ui/layout/DetailHeader.js +14 -6
- package/dist/ui/layout/DetailHeader.js.map +1 -1
- package/dist/ui/layout/ErrorPage.js +20 -15
- package/dist/ui/layout/ErrorPage.js.map +1 -1
- package/dist/ui/layout/FullPageLoader.js +4 -1
- package/dist/ui/layout/FullPageLoader.js.map +1 -1
- package/dist/ui/layout/GlassPanel.js +8 -4
- package/dist/ui/layout/GlassPanel.js.map +1 -1
- package/dist/ui/layout/PageHeader.js +10 -4
- package/dist/ui/layout/PageHeader.js.map +1 -1
- package/dist/ui/layout/PageHeading.js +17 -8
- package/dist/ui/layout/PageHeading.js.map +1 -1
- package/dist/ui/layout/ProfileHeader.js +21 -10
- package/dist/ui/layout/ProfileHeader.js.map +1 -1
- package/dist/ui/layout/ScrollableRow.js +19 -15
- package/dist/ui/layout/ScrollableRow.js.map +1 -1
- package/dist/ui/layout/SectionCard.js +10 -4
- package/dist/ui/layout/SectionCard.js.map +1 -1
- package/dist/ui/metrics/BarList.js +9 -4
- package/dist/ui/metrics/BarList.js.map +1 -1
- package/dist/ui/metrics/CalendarHeatmap.js +40 -21
- package/dist/ui/metrics/CalendarHeatmap.js.map +1 -1
- package/dist/ui/metrics/ChartTooltip.js +6 -2
- package/dist/ui/metrics/ChartTooltip.js.map +1 -1
- package/dist/ui/metrics/ColumnChart.js +22 -18
- package/dist/ui/metrics/ColumnChart.js.map +1 -1
- package/dist/ui/metrics/LineChart.js +20 -16
- package/dist/ui/metrics/LineChart.js.map +1 -1
- package/dist/ui/metrics/MetricCard.js +42 -24
- package/dist/ui/metrics/MetricCard.js.map +1 -1
- package/dist/ui/metrics/TableToggle.js +7 -2
- package/dist/ui/metrics/TableToggle.js.map +1 -1
- package/dist/ui/metrics/chartParts.js +14 -5
- package/dist/ui/metrics/chartParts.js.map +1 -1
- package/dist/ui/navigation/ColorSchemeToggle.js +8 -4
- package/dist/ui/navigation/ColorSchemeToggle.js.map +1 -1
- package/dist/ui/navigation/FontSizeToggle.js +6 -2
- package/dist/ui/navigation/FontSizeToggle.js.map +1 -1
- package/dist/ui/navigation/LanguageToggle.js +8 -4
- package/dist/ui/navigation/LanguageToggle.js.map +1 -1
- package/dist/ui/navigation/PageBreadcrumbs.js +12 -6
- package/dist/ui/navigation/PageBreadcrumbs.js.map +1 -1
- package/dist/ui/timeline/GroupedTimeline.js +26 -13
- package/dist/ui/timeline/GroupedTimeline.js.map +1 -1
- package/dist/upload/FileDropzone.js +35 -25
- package/dist/upload/FileDropzone.js.map +1 -1
- package/package.json +1 -1
|
@@ -27,7 +27,38 @@ import { DUE_STATUS, todayIsoDateOf, dueStatusOf } from "./kanbanCards.js";
|
|
|
27
27
|
import { cardsOfColumn, isOverLimit } from "./kanbanMoves.js";
|
|
28
28
|
import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
|
|
29
29
|
import ActionsMenu from "../ui/actions/ActionsMenu.js";
|
|
30
|
+
import { piecePart, usePieceProps } from "../theme/themePieces.js";
|
|
30
31
|
import { tagOf } from "../ui/labels/tagOf.js";
|
|
32
|
+
const THEME_NAME = "CalcitaKanbanBoard";
|
|
33
|
+
const KanbanCompleteButton = piecePart(THEME_NAME, "CompleteButton", IconButton);
|
|
34
|
+
const KanbanTags = piecePart(THEME_NAME, "Tags", Stack);
|
|
35
|
+
const KanbanTitleRow = piecePart(THEME_NAME, "TitleRow", Stack);
|
|
36
|
+
const KanbanDoneIcon = piecePart(THEME_NAME, "DoneIcon", CheckCircleRoundedIcon);
|
|
37
|
+
const KanbanCardTitle = piecePart(THEME_NAME, "CardTitle", Typography);
|
|
38
|
+
const KanbanMeta = piecePart(THEME_NAME, "Meta", Stack);
|
|
39
|
+
const KanbanDue = piecePart(THEME_NAME, "Due", Stack);
|
|
40
|
+
const KanbanDueIcon = piecePart(THEME_NAME, "DueIcon", EventOutlinedIcon);
|
|
41
|
+
const KanbanDueText = piecePart(THEME_NAME, "DueText", Typography);
|
|
42
|
+
const KanbanChecklist = piecePart(THEME_NAME, "Checklist", Stack);
|
|
43
|
+
const KanbanChecklistIcon = piecePart(THEME_NAME, "ChecklistIcon", CheckBoxOutlinedIcon);
|
|
44
|
+
const KanbanComments = piecePart(THEME_NAME, "Comments", Stack);
|
|
45
|
+
const KanbanCommentsIcon = piecePart(THEME_NAME, "CommentsIcon", ChatBubbleOutlineRoundedIcon);
|
|
46
|
+
const KanbanAttachments = piecePart(THEME_NAME, "Attachments", Stack);
|
|
47
|
+
const KanbanAttachmentsIcon = piecePart(THEME_NAME, "AttachmentsIcon", AttachFileRoundedIcon);
|
|
48
|
+
const KanbanAssignees = piecePart(THEME_NAME, "Assignees", AvatarGroup);
|
|
49
|
+
const KanbanRoot = piecePart(THEME_NAME, "Root", Box);
|
|
50
|
+
const KanbanCollapsedColumn = piecePart(THEME_NAME, "CollapsedColumn", Paper);
|
|
51
|
+
const KanbanCollapsedTitle = piecePart(THEME_NAME, "CollapsedTitle", Typography);
|
|
52
|
+
const KanbanHidden = piecePart(THEME_NAME, "Hidden", Box);
|
|
53
|
+
const KanbanColumn = piecePart(THEME_NAME, "Column", Paper);
|
|
54
|
+
const KanbanColumnHeader = piecePart(THEME_NAME, "ColumnHeader", Stack);
|
|
55
|
+
const KanbanColumnTitle = piecePart(THEME_NAME, "ColumnTitle", Typography);
|
|
56
|
+
const KanbanQuickAdd = piecePart(THEME_NAME, "QuickAdd", Box);
|
|
57
|
+
const KanbanDropZone = piecePart(THEME_NAME, "DropZone", Stack);
|
|
58
|
+
const KanbanCard = piecePart(THEME_NAME, "Card", Paper);
|
|
59
|
+
const KanbanCardActions = piecePart(THEME_NAME, "CardActions", Box);
|
|
60
|
+
const KanbanCardContent = piecePart(THEME_NAME, "CardContent", Box);
|
|
61
|
+
const KanbanEmpty = piecePart(THEME_NAME, "Empty", Typography);
|
|
31
62
|
const COLUMN_MIN_WIDTH_PIXELS = 220;
|
|
32
63
|
const EMPTY_COLUMN_MIN_HEIGHT = 96;
|
|
33
64
|
const MAX_VISIBLE_ASSIGNEES = 3;
|
|
@@ -37,12 +68,12 @@ const DUE_COLOR = Object.freeze({ [DUE_STATUS.overdue]: "error.main", [DUE_STATU
|
|
|
37
68
|
function CompleteButton({ card, t, onComplete }) {
|
|
38
69
|
const label = card.completed ? t("reopen", { title: card.title }) : t("complete", { title: card.title });
|
|
39
70
|
return /* @__PURE__ */ jsx(Tooltip, { title: label, children: /* @__PURE__ */ jsx(
|
|
40
|
-
|
|
71
|
+
KanbanCompleteButton,
|
|
41
72
|
{
|
|
42
73
|
size: "small",
|
|
43
74
|
"aria-label": label,
|
|
44
75
|
"aria-pressed": Boolean(card.completed),
|
|
45
|
-
|
|
76
|
+
ownSx: { m: -0.5, color: card.completed ? "success.main" : "text.secondary" },
|
|
46
77
|
onClick: (event) => {
|
|
47
78
|
event.stopPropagation();
|
|
48
79
|
onComplete(card, !card.completed);
|
|
@@ -66,30 +97,30 @@ function DefaultCard({ card, t, today, onComplete }) {
|
|
|
66
97
|
}
|
|
67
98
|
const hasFooter = dueStatus || card.checklist?.total > 0 || card.comments > 0 || card.attachments > 0 || card.assignees?.length > 0;
|
|
68
99
|
return /* @__PURE__ */ jsxs(Stack, { spacing: 0.75, children: [
|
|
69
|
-
card.tags?.length > 0 && /* @__PURE__ */ jsx(
|
|
100
|
+
card.tags?.length > 0 && /* @__PURE__ */ jsx(KanbanTags, { direction: "row", spacing: 0.5, useFlexGap: true, ownSx: { flexWrap: "wrap" }, children: card.tags.map((rawTag) => {
|
|
70
101
|
const tag = tagOf(rawTag);
|
|
71
102
|
return /* @__PURE__ */ jsx(Chip, { label: tag.label, size: "small", color: tag.color, variant: tag.color === "default" ? "filled" : "outlined" }, tag.label);
|
|
72
103
|
}) }),
|
|
73
|
-
/* @__PURE__ */ jsxs(
|
|
104
|
+
/* @__PURE__ */ jsxs(KanbanTitleRow, { direction: "row", spacing: 1, ownSx: { alignItems: "flex-start" }, children: [
|
|
74
105
|
onComplete && /* @__PURE__ */ jsx(CompleteButton, { card, t, onComplete }),
|
|
75
|
-
!onComplete && card.completed && /* @__PURE__ */ jsx(
|
|
76
|
-
/* @__PURE__ */ jsx(
|
|
106
|
+
!onComplete && card.completed && /* @__PURE__ */ jsx(KanbanDoneIcon, { fontSize: "small", ownSx: { color: "success.main" }, titleAccess: t("completed") }),
|
|
107
|
+
/* @__PURE__ */ jsx(KanbanCardTitle, { variant: "subtitle2", component: "p", ownSx: { color: card.completed ? "text.secondary" : void 0 }, children: card.title })
|
|
77
108
|
] }),
|
|
78
109
|
card.description && /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", children: card.description }),
|
|
79
|
-
hasFooter && /* @__PURE__ */ jsxs(
|
|
80
|
-
dueStatus && /* @__PURE__ */ jsxs(
|
|
81
|
-
/* @__PURE__ */ jsx(
|
|
82
|
-
/* @__PURE__ */ jsx(
|
|
110
|
+
hasFooter && /* @__PURE__ */ jsxs(KanbanMeta, { direction: "row", spacing: 1.25, useFlexGap: true, ownSx: { alignItems: "center", flexWrap: "wrap", color: "text.secondary" }, children: [
|
|
111
|
+
dueStatus && /* @__PURE__ */ jsxs(KanbanDue, { direction: "row", spacing: 0.5, ownSx: { alignItems: "center", color: DUE_COLOR[dueStatus] }, children: [
|
|
112
|
+
/* @__PURE__ */ jsx(KanbanDueIcon, { ownSx: { fontSize: 16 } }),
|
|
113
|
+
/* @__PURE__ */ jsx(KanbanDueText, { variant: "caption", ownSx: { fontWeight: dueStatus === DUE_STATUS.upcoming ? 400 : 600 }, children: dueText })
|
|
83
114
|
] }),
|
|
84
115
|
card.checklist?.total > 0 && /* @__PURE__ */ jsxs(
|
|
85
|
-
|
|
116
|
+
KanbanChecklist,
|
|
86
117
|
{
|
|
87
118
|
direction: "row",
|
|
88
119
|
spacing: 0.5,
|
|
89
|
-
|
|
120
|
+
ownSx: { alignItems: "center" },
|
|
90
121
|
"aria-label": t("checklist", { done: card.checklist.done, total: card.checklist.total }),
|
|
91
122
|
children: [
|
|
92
|
-
/* @__PURE__ */ jsx(
|
|
123
|
+
/* @__PURE__ */ jsx(KanbanChecklistIcon, { ownSx: { fontSize: 16 } }),
|
|
93
124
|
/* @__PURE__ */ jsxs(Typography, { variant: "caption", "aria-hidden": "true", children: [
|
|
94
125
|
card.checklist.done,
|
|
95
126
|
"/",
|
|
@@ -98,19 +129,19 @@ function DefaultCard({ card, t, today, onComplete }) {
|
|
|
98
129
|
]
|
|
99
130
|
}
|
|
100
131
|
),
|
|
101
|
-
card.comments > 0 && /* @__PURE__ */ jsxs(
|
|
102
|
-
/* @__PURE__ */ jsx(
|
|
132
|
+
card.comments > 0 && /* @__PURE__ */ jsxs(KanbanComments, { direction: "row", spacing: 0.5, ownSx: { alignItems: "center" }, "aria-label": t("comments", { count: card.comments }), children: [
|
|
133
|
+
/* @__PURE__ */ jsx(KanbanCommentsIcon, { ownSx: { fontSize: 16 } }),
|
|
103
134
|
/* @__PURE__ */ jsx(Typography, { variant: "caption", "aria-hidden": "true", children: card.comments })
|
|
104
135
|
] }),
|
|
105
|
-
card.attachments > 0 && /* @__PURE__ */ jsxs(
|
|
106
|
-
/* @__PURE__ */ jsx(
|
|
136
|
+
card.attachments > 0 && /* @__PURE__ */ jsxs(KanbanAttachments, { direction: "row", spacing: 0.5, ownSx: { alignItems: "center" }, "aria-label": t("attachments", { count: card.attachments }), children: [
|
|
137
|
+
/* @__PURE__ */ jsx(KanbanAttachmentsIcon, { ownSx: { fontSize: 16 } }),
|
|
107
138
|
/* @__PURE__ */ jsx(Typography, { variant: "caption", "aria-hidden": "true", children: card.attachments })
|
|
108
139
|
] }),
|
|
109
140
|
card.assignees?.length > 0 && /* @__PURE__ */ jsx(
|
|
110
|
-
|
|
141
|
+
KanbanAssignees,
|
|
111
142
|
{
|
|
112
143
|
max: MAX_VISIBLE_ASSIGNEES,
|
|
113
|
-
|
|
144
|
+
ownSx: { ml: "auto", "& .MuiAvatar-root": { width: ASSIGNEE_AVATAR_PIXELS, height: ASSIGNEE_AVATAR_PIXELS, fontSize: 11 } },
|
|
114
145
|
"aria-label": t("assignees", { names: card.assignees.map((person) => person.name).join(", ") }),
|
|
115
146
|
children: card.assignees.map((person) => /* @__PURE__ */ jsx(Tooltip, { title: person.name, children: /* @__PURE__ */ jsx(Avatar, { alt: person.name, src: person.avatarUrl, children: initialsOf(person.name) }) }, person.id))
|
|
116
147
|
}
|
|
@@ -148,20 +179,21 @@ function QuickAdd({ columnTitle, onAdd, onClose, t }) {
|
|
|
148
179
|
}
|
|
149
180
|
);
|
|
150
181
|
}
|
|
151
|
-
function KanbanBoard({
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
182
|
+
function KanbanBoard(props) {
|
|
183
|
+
const {
|
|
184
|
+
columns,
|
|
185
|
+
cards,
|
|
186
|
+
onMove,
|
|
187
|
+
renderCard,
|
|
188
|
+
onCardClick,
|
|
189
|
+
onAddCard,
|
|
190
|
+
cardActions,
|
|
191
|
+
columnActions,
|
|
192
|
+
onCardComplete,
|
|
193
|
+
onColumnCollapse,
|
|
194
|
+
ariaLabel,
|
|
195
|
+
texts
|
|
196
|
+
} = usePieceProps(props, THEME_NAME);
|
|
165
197
|
const { t } = useToolkitTranslation("kanban", texts);
|
|
166
198
|
const [addingColumnId, setAddingColumnId] = useState(null);
|
|
167
199
|
const [collapsedIds, setCollapsedIds] = useState(() => new Set(columns.filter((column) => column.defaultCollapsed).map((column) => column.id)));
|
|
@@ -200,7 +232,7 @@ function KanbanBoard({
|
|
|
200
232
|
provided.announce(t("dropped", { title: cardTitleOf(draggableId), column: columnTitleOf(destination.droppableId), position: destination.index + 1 }));
|
|
201
233
|
onMove({ cardId: draggableId, fromColumnId: source.droppableId, toColumnId: destination.droppableId, toIndex: destination.index });
|
|
202
234
|
};
|
|
203
|
-
return /* @__PURE__ */ jsx(DragDropContext, { onDragStart: announceStart, onDragUpdate: announceUpdate, onDragEnd: finishMove, dragHandleUsageInstructions: t("instructions"), children: /* @__PURE__ */ jsx(
|
|
235
|
+
return /* @__PURE__ */ jsx(DragDropContext, { onDragStart: announceStart, onDragUpdate: announceUpdate, onDragEnd: finishMove, dragHandleUsageInstructions: t("instructions"), children: /* @__PURE__ */ jsx(KanbanRoot, { role: "region", "aria-label": ariaLabel, ownSx: {
|
|
204
236
|
display: "flex",
|
|
205
237
|
gap: 2,
|
|
206
238
|
overflowX: "auto",
|
|
@@ -215,14 +247,14 @@ function KanbanBoard({
|
|
|
215
247
|
const isCollapsed = column.collapsible && collapsedIds.has(column.id);
|
|
216
248
|
if (isCollapsed) {
|
|
217
249
|
return /* @__PURE__ */ jsx(Droppable, { droppableId: column.id, children: (droppableProvided, droppableSnapshot) => /* @__PURE__ */ jsxs(
|
|
218
|
-
|
|
250
|
+
KanbanCollapsedColumn,
|
|
219
251
|
{
|
|
220
252
|
ref: droppableProvided.innerRef,
|
|
221
253
|
...droppableProvided.droppableProps,
|
|
222
254
|
variant: "outlined",
|
|
223
255
|
component: "section",
|
|
224
256
|
"aria-label": column.title,
|
|
225
|
-
|
|
257
|
+
ownSx: {
|
|
226
258
|
flex: "0 0 auto",
|
|
227
259
|
width: COLLAPSED_COLUMN_WIDTH_PIXELS,
|
|
228
260
|
py: 1,
|
|
@@ -246,22 +278,22 @@ function KanbanBoard({
|
|
|
246
278
|
}
|
|
247
279
|
) }),
|
|
248
280
|
/* @__PURE__ */ jsx(Chip, { size: "small", label: count, color: isOver ? "warning" : "default" }),
|
|
249
|
-
/* @__PURE__ */ jsx(
|
|
250
|
-
/* @__PURE__ */ jsx(
|
|
281
|
+
/* @__PURE__ */ jsx(KanbanCollapsedTitle, { variant: "subtitle2", component: "h3", ownSx: { writingMode: "vertical-rl", whiteSpace: "nowrap" }, children: column.title }),
|
|
282
|
+
/* @__PURE__ */ jsx(KanbanHidden, { ownSx: { display: "none" }, children: droppableProvided.placeholder })
|
|
251
283
|
]
|
|
252
284
|
}
|
|
253
285
|
) }, column.id);
|
|
254
286
|
}
|
|
255
287
|
return /* @__PURE__ */ jsxs(
|
|
256
|
-
|
|
288
|
+
KanbanColumn,
|
|
257
289
|
{
|
|
258
290
|
variant: "outlined",
|
|
259
291
|
component: "section",
|
|
260
292
|
"aria-label": column.title,
|
|
261
|
-
|
|
293
|
+
ownSx: { flex: "1 1 0", minWidth: COLUMN_MIN_WIDTH_PIXELS, p: 1.5, scrollSnapAlign: "start", borderRadius: 3 },
|
|
262
294
|
children: [
|
|
263
|
-
/* @__PURE__ */ jsxs(
|
|
264
|
-
/* @__PURE__ */ jsx(
|
|
295
|
+
/* @__PURE__ */ jsxs(KanbanColumnHeader, { direction: "row", spacing: 0.5, ownSx: { alignItems: "center", mb: 1.5, px: 0.5 }, children: [
|
|
296
|
+
/* @__PURE__ */ jsx(KanbanColumnTitle, { variant: "subtitle2", component: "h3", ownSx: { flexGrow: 1, minWidth: 0 }, children: column.title }),
|
|
265
297
|
/* @__PURE__ */ jsx(
|
|
266
298
|
Chip,
|
|
267
299
|
{
|
|
@@ -284,7 +316,7 @@ function KanbanBoard({
|
|
|
284
316
|
}
|
|
285
317
|
) })
|
|
286
318
|
] }),
|
|
287
|
-
addingColumnId === column.id && /* @__PURE__ */ jsx(
|
|
319
|
+
addingColumnId === column.id && /* @__PURE__ */ jsx(KanbanQuickAdd, { ownSx: { mb: 1 }, children: /* @__PURE__ */ jsx(
|
|
288
320
|
QuickAdd,
|
|
289
321
|
{
|
|
290
322
|
columnTitle: column.title,
|
|
@@ -294,12 +326,12 @@ function KanbanBoard({
|
|
|
294
326
|
}
|
|
295
327
|
) }),
|
|
296
328
|
/* @__PURE__ */ jsx(Droppable, { droppableId: column.id, children: (droppableProvided, droppableSnapshot) => /* @__PURE__ */ jsxs(
|
|
297
|
-
|
|
329
|
+
KanbanDropZone,
|
|
298
330
|
{
|
|
299
331
|
ref: droppableProvided.innerRef,
|
|
300
332
|
...droppableProvided.droppableProps,
|
|
301
333
|
spacing: 1,
|
|
302
|
-
|
|
334
|
+
ownSx: {
|
|
303
335
|
minHeight: EMPTY_COLUMN_MIN_HEIGHT,
|
|
304
336
|
borderRadius: 2,
|
|
305
337
|
transition: "background-color 160ms",
|
|
@@ -307,22 +339,22 @@ function KanbanBoard({
|
|
|
307
339
|
},
|
|
308
340
|
children: [
|
|
309
341
|
columnCards.map((card, index) => /* @__PURE__ */ jsx(Draggable, { draggableId: card.id, index, children: (draggableProvided, draggableSnapshot) => /* @__PURE__ */ jsxs(
|
|
310
|
-
|
|
342
|
+
KanbanCard,
|
|
311
343
|
{
|
|
312
344
|
ref: draggableProvided.innerRef,
|
|
313
345
|
...draggableProvided.draggableProps,
|
|
314
346
|
...draggableProvided.dragHandleProps,
|
|
315
347
|
elevation: draggableSnapshot.isDragging ? 8 : 1,
|
|
316
348
|
onClick: onCardClick ? () => onCardClick(card.id) : void 0,
|
|
317
|
-
|
|
349
|
+
ownSx: { p: 1.5, borderRadius: 2, cursor: "grab", position: "relative", "&:focus-visible": { outline: 2, outlineColor: "primary.main" } },
|
|
318
350
|
children: [
|
|
319
|
-
cardActions && /* @__PURE__ */ jsx(
|
|
320
|
-
/* @__PURE__ */ jsx(
|
|
351
|
+
cardActions && /* @__PURE__ */ jsx(KanbanCardActions, { ownSx: { position: "absolute", top: 4, right: 4 }, children: /* @__PURE__ */ jsx(ActionsMenu, { label: t("cardActions", { title: card.title }), actions: cardActions(card) }) }),
|
|
352
|
+
/* @__PURE__ */ jsx(KanbanCardContent, { ownSx: cardActions ? { pr: 3 } : void 0, children: renderCard ? renderCard(card) : /* @__PURE__ */ jsx(DefaultCard, { card, t, today, onComplete: onCardComplete }) })
|
|
321
353
|
]
|
|
322
354
|
}
|
|
323
355
|
) }, card.id)),
|
|
324
356
|
droppableProvided.placeholder,
|
|
325
|
-
columnCards.length === 0 && !droppableSnapshot.isDraggingOver && addingColumnId !== column.id && /* @__PURE__ */ jsx(
|
|
357
|
+
columnCards.length === 0 && !droppableSnapshot.isDraggingOver && addingColumnId !== column.id && /* @__PURE__ */ jsx(KanbanEmpty, { variant: "caption", color: "text.secondary", ownSx: { textAlign: "center", py: 3 }, children: total > 0 ? t("emptyFiltered") : t("empty") })
|
|
326
358
|
]
|
|
327
359
|
}
|
|
328
360
|
) })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KanbanBoard.js","sources":["../../src/kanban/KanbanBoard.jsx"],"sourcesContent":["// Un tablero kanban (@stackcraftmx/calcita/kanban): columnas con tarjetas que se arrastran de una a otra con el ratón, con el\n// dedo o con el teclado (espacio para levantar, flechas para mover, espacio para soltar). Con @hello-pangea/dnd por dentro.\n//\n// <KanbanBoard columns={[{id: 'todo', title: 'Por hacer'}, {id: 'doing', title: 'En proceso', limit: 3}]}\n// cards={cards} onMove={(move) => api.post('/tasks/move', move)} ariaLabel=\"Tablero de tareas\" />\n//\n// El tablero no guarda nada: avisa la movida (onMove) y quien lo usa actualiza sus tarjetas (moveCard de kanbanMoves.js lo\n// hace sin esperar al servidor). Una columna con tope (limit, el trabajo en curso) avisa en ámbar cuando lo pasa.\n//\n// Accesible: el lector de pantalla anuncia en el idioma de la app qué se levantó, a dónde va y dónde quedó.\n//\n// Lo de un producto, todo hacia afuera (el tablero no guarda nada ni llama a ningún servidor):\n// - la tarjeta por omisión pinta lo que traiga: etiquetas (texto o {label, color}), responsables con su monograma, la\n// fecha límite (roja si ya venció, ámbar si es hoy), el avance de su lista de pendientes, comentarios y adjuntos. Para\n// otra tarjeta: renderCard;\n// - «+» en cada columna para agregar escribiendo el título (onAddCard({columnId, title}));\n// - «⋯» en cada tarjeta y en cada columna con las acciones que dé la pantalla (cardActions, columnActions): editar,\n// asignarme, mover sin arrastrar, borrar…;\n// - terminar una tarea: con onCardComplete cada tarjeta lleva su círculo para marcarla (y desmarcarla); qué pasa al\n// terminarla (pasarla a «Listo», guardar la fecha) lo decide la pantalla. Una tarjeta con completed: true sale con su\n// palomita verde y su fecha límite ya no se pinta de rojo;\n// - columnas que se encogen (collapsible), como el congelador (icebox) de ideas para después: se quedan en una tira angosta\n// con su nombre y su cuenta, y se les puede soltar una tarjeta igual. defaultCollapsed la abre encogida y\n// onColumnCollapse avisa cada cambio (para guardarlo si la pantalla quiere);\n// - texts para cualquier texto (la forma de `kanban` en los textos del paquete).\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useState} from 'react';\nimport {DragDropContext, Draggable, Droppable} from '@hello-pangea/dnd';\nimport Avatar from '@mui/material/Avatar';\nimport AvatarGroup from '@mui/material/AvatarGroup';\nimport Box from '@mui/material/Box';\nimport Chip from '@mui/material/Chip';\nimport IconButton from '@mui/material/IconButton';\nimport Paper from '@mui/material/Paper';\nimport Stack from '@mui/material/Stack';\nimport TextField from '@mui/material/TextField';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport AddRoundedIcon from '@mui/icons-material/AddRounded';\nimport AttachFileRoundedIcon from '@mui/icons-material/AttachFileRounded';\nimport ChatBubbleOutlineRoundedIcon from '@mui/icons-material/ChatBubbleOutlineRounded';\nimport CheckBoxOutlinedIcon from '@mui/icons-material/CheckBoxOutlined';\nimport CheckCircleRoundedIcon from '@mui/icons-material/CheckCircleRounded';\nimport EventOutlinedIcon from '@mui/icons-material/EventOutlined';\nimport KeyboardDoubleArrowLeftRoundedIcon from '@mui/icons-material/KeyboardDoubleArrowLeftRounded';\nimport KeyboardDoubleArrowRightRoundedIcon from '@mui/icons-material/KeyboardDoubleArrowRightRounded';\nimport RadioButtonUncheckedRoundedIcon from '@mui/icons-material/RadioButtonUncheckedRounded';\n\nimport {initialsOf} from '@/appShell/menuItemText.js';\nimport {useFormatters} from '@/toolkit/useFormatters.js';\nimport {DUE_STATUS, dueStatusOf, tagOf, todayIsoDateOf} from '@/kanban/kanbanCards.js';\nimport {cardsOfColumn, isOverLimit} from '@/kanban/kanbanMoves.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport ActionsMenu from '@/ui/actions/ActionsMenu.jsx';\n\n// las columnas se reparten el ancho, sin bajar de este mínimo; si no caben, el tablero desliza de lado.\n// OJO: con el teclado, la librería solo mueve una tarjeta a columnas que se ven COMPLETAS: con columnas fijas de 300 px la\n// cuarta quedaba cortada en un escritorio y no se podía soltar ahí con el teclado\nconst COLUMN_MIN_WIDTH_PIXELS = 220;\n// lo alto que mide una columna vacía: lo justo para soltar ahí una tarjeta\nconst EMPTY_COLUMN_MIN_HEIGHT = 96;\n// cuántas caras de responsables se ven antes del «+2»\nconst MAX_VISIBLE_ASSIGNEES = 3;\nconst ASSIGNEE_AVATAR_PIXELS = 24;\n// lo ancho de una columna encogida: su nombre de lado, su cuenta y su botón para abrirla\nconst COLLAPSED_COLUMN_WIDTH_PIXELS = 52;\n// el color del texto de la fecha según cómo va\nconst DUE_COLOR = Object.freeze({[DUE_STATUS.overdue]: 'error.main', [DUE_STATUS.today]: 'warning.dark', [DUE_STATUS.upcoming]: 'text.secondary'});\n\n/**\n * El círculo para terminar una tarea (o reabrirla, si ya está terminada). El clic no levanta la tarjeta ni la abre.\n *\n * @param {{card: any, t: Function, onComplete: (card: any, completed: boolean) => void}} props\n */\nfunction CompleteButton({card, t, onComplete}) {\n const label = card.completed ? t('reopen', {title: card.title}) : t('complete', {title: card.title});\n return (\n <Tooltip title={label}>\n <IconButton size=\"small\" aria-label={label} aria-pressed={Boolean(card.completed)} sx={{m: -0.5, color: card.completed ? 'success.main' : 'text.secondary'}}\n onClick={(event) => {\n event.stopPropagation();\n onComplete(card, !card.completed);\n }}>\n {card.completed ? <CheckCircleRoundedIcon fontSize=\"small\" /> : <RadioButtonUncheckedRoundedIcon fontSize=\"small\" />}\n </IconButton>\n </Tooltip>\n );\n}\n\n/**\n * Una tarjeta por omisión: lo que traiga, sin pedir nada (título, descripción, etiquetas, responsables, fecha, pendientes,\n * comentarios y adjuntos).\n *\n * @param {{card: any, t: Function, today: string, onComplete?: (card: any, completed: boolean) => void}} props\n */\nfunction DefaultCard({card, t, today, onComplete}) {\n const {formatDate} = useFormatters();\n // terminada, su fecha ya no apura: se pinta tenue, sin rojo ni ámbar\n const dueStatus = card.completed && card.dueDate ? DUE_STATUS.upcoming : dueStatusOf(card.dueDate, today);\n let dueText = '';\n if (card.completed && card.dueDate) {\n dueText = t('dueCompleted', {date: formatDate(card.dueDate)});\n } else if (dueStatus === DUE_STATUS.overdue) {\n dueText = t('dueOverdue', {date: formatDate(card.dueDate)});\n } else if (dueStatus === DUE_STATUS.today) {\n dueText = t('dueToday');\n } else if (dueStatus) {\n dueText = t('dueOn', {date: formatDate(card.dueDate)});\n }\n const hasFooter = dueStatus || card.checklist?.total > 0 || card.comments > 0 || card.attachments > 0 || card.assignees?.length > 0;\n\n return (\n <Stack spacing={0.75}>\n {card.tags?.length > 0 && (\n <Stack direction=\"row\" spacing={0.5} useFlexGap sx={{flexWrap: 'wrap'}}>\n {card.tags.map((rawTag) => {\n const tag = tagOf(rawTag);\n return <Chip key={tag.label} label={tag.label} size=\"small\" color={tag.color} variant={tag.color === 'default' ? 'filled' : 'outlined'} />;\n })}\n </Stack>\n )}\n <Stack direction=\"row\" spacing={1} sx={{alignItems: 'flex-start'}}>\n {onComplete && <CompleteButton card={card} t={t} onComplete={onComplete} />}\n {!onComplete && card.completed && (\n <CheckCircleRoundedIcon fontSize=\"small\" sx={{color: 'success.main'}} titleAccess={t('completed')} />\n )}\n <Typography variant=\"subtitle2\" component=\"p\" sx={{color: card.completed ? 'text.secondary' : undefined}}>{card.title}</Typography>\n </Stack>\n {card.description && <Typography variant=\"body2\" color=\"text.secondary\">{card.description}</Typography>}\n {hasFooter && (\n <Stack direction=\"row\" spacing={1.25} useFlexGap sx={{alignItems: 'center', flexWrap: 'wrap', color: 'text.secondary'}}>\n {dueStatus && (\n <Stack direction=\"row\" spacing={0.5} sx={{alignItems: 'center', color: DUE_COLOR[dueStatus]}}>\n <EventOutlinedIcon sx={{fontSize: 16}} />\n <Typography variant=\"caption\" sx={{fontWeight: dueStatus === DUE_STATUS.upcoming ? 400 : 600}}>{dueText}</Typography>\n </Stack>\n )}\n {card.checklist?.total > 0 && (\n <Stack direction=\"row\" spacing={0.5} sx={{alignItems: 'center'}}\n aria-label={t('checklist', {done: card.checklist.done, total: card.checklist.total})}>\n <CheckBoxOutlinedIcon sx={{fontSize: 16}} />\n <Typography variant=\"caption\" aria-hidden=\"true\">{card.checklist.done}/{card.checklist.total}</Typography>\n </Stack>\n )}\n {card.comments > 0 && (\n <Stack direction=\"row\" spacing={0.5} sx={{alignItems: 'center'}} aria-label={t('comments', {count: card.comments})}>\n <ChatBubbleOutlineRoundedIcon sx={{fontSize: 16}} />\n <Typography variant=\"caption\" aria-hidden=\"true\">{card.comments}</Typography>\n </Stack>\n )}\n {card.attachments > 0 && (\n <Stack direction=\"row\" spacing={0.5} sx={{alignItems: 'center'}} aria-label={t('attachments', {count: card.attachments})}>\n <AttachFileRoundedIcon sx={{fontSize: 16}} />\n <Typography variant=\"caption\" aria-hidden=\"true\">{card.attachments}</Typography>\n </Stack>\n )}\n {card.assignees?.length > 0 && (\n <AvatarGroup max={MAX_VISIBLE_ASSIGNEES} sx={{ml: 'auto', '& .MuiAvatar-root': {width: ASSIGNEE_AVATAR_PIXELS, height: ASSIGNEE_AVATAR_PIXELS, fontSize: 11}}}\n aria-label={t('assignees', {names: card.assignees.map((person) => person.name).join(', ')})}>\n {card.assignees.map((person) => (\n <Tooltip key={person.id} title={person.name}>\n <Avatar alt={person.name} src={person.avatarUrl}>{initialsOf(person.name)}</Avatar>\n </Tooltip>\n ))}\n </AvatarGroup>\n )}\n </Stack>\n )}\n </Stack>\n );\n}\n\n/**\n * Agregar una tarjeta escribiendo su título: Enter la agrega (y deja el campo listo para otra), Escape cierra.\n *\n * @param {{columnTitle: string, onAdd: (title: string) => void, onClose: () => void, t: Function}} props\n */\nfunction QuickAdd({columnTitle, onAdd, onClose, t}) {\n const [title, setTitle] = useState('');\n return (\n <TextField size=\"small\" fullWidth autoFocus multiline maxRows={4} value={title} placeholder={t('addCardPlaceholder')}\n slotProps={{htmlInput: {'aria-label': t('addCard', {column: columnTitle})}}}\n onChange={(event) => setTitle(event.target.value)}\n onBlur={() => !title.trim() && onClose()}\n onKeyDown={(event) => {\n if (event.key === 'Escape') {\n onClose();\n }\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n if (title.trim()) {\n onAdd(title.trim());\n setTitle('');\n }\n }\n }} />\n );\n}\n\n/**\n * @param {object} props\n * @param {Array<{id: string, title: string, limit?: number, count?: number, collapsible?: boolean, defaultCollapsed?: boolean}>} props.columns\n * en su orden. count: cuántas tarjetas tiene de verdad cuando la pantalla le pasa solo las filtradas (el tope se cuenta\n * contra todas). collapsible: lleva su botón para encogerse (el congelador); defaultCollapsed: empieza encogida\n * @param {Array<{id: string, columnId: string, title: string, completed?: boolean, description?: string, tags?: Array<string|{label: string, color?: string}>, assignees?: Array<{id: string, name: string, avatarUrl?: string}>, dueDate?: string, checklist?: {done: number, total: number}, comments?: number, attachments?: number} & Record<string, any>>} props.cards\n * el orden de cada columna es el orden en este arreglo; cada tarjeta puede traer sus campos propios (llegan a renderCard,\n * a cardActions y a onCardClick tal cual). dueDate: AAAA-MM-DD\n * @param {(move: {cardId: string, fromColumnId: string, toColumnId: string, toIndex: number}) => void} props.onMove\n * @param {(card: any) => import('react').ReactNode} [props.renderCard] lo de adentro de cada tarjeta (recibe la tarjeta de cards)\n * @param {(cardId: string) => void} [props.onCardClick]\n * @param {(newCard: {columnId: string, title: string}) => void} [props.onAddCard] con él cada columna lleva su «+» para agregar\n * escribiendo el título\n * @param {(card: any) => Array<{key: string, label: string, icon?: import('react').ReactNode, color?: string, disabled?: boolean, onClick: () => void}>} [props.cardActions]\n * las acciones del «⋯» de cada tarjeta (editar, asignarme, borrar…); sin ellas no hay «⋯»\n * @param {(column: any) => Array<{key: string, label: string, icon?: import('react').ReactNode, color?: string, disabled?: boolean, onClick: () => void}>} [props.columnActions]\n * las acciones del «⋯» de cada columna (renombrar, limpiar…)\n * @param {(card: any, completed: boolean) => void} [props.onCardComplete] con él cada tarjeta lleva su círculo para terminarla\n * (completed true) o reabrirla (false); la pantalla decide qué más pasa (moverla a «Listo», guardar la fecha)\n * @param {(columnId: string, collapsed: boolean) => void} [props.onColumnCollapse] cada que una columna se encoge o se abre\n * @param {string} props.ariaLabel ya traducido\n * @param {object} [props.texts] los textos que cambian, con la forma de `kanban` en los textos del paquete\n */\nexport default function KanbanBoard({\n columns, cards, onMove, renderCard, onCardClick, onAddCard, cardActions, columnActions, onCardComplete, onColumnCollapse, ariaLabel, texts,\n}) {\n const {t} = useToolkitTranslation('kanban', texts);\n // la columna donde se está escribiendo una tarjeta nueva\n const [addingColumnId, setAddingColumnId] = useState(null);\n // las columnas encogidas: empiezan como dice defaultCollapsed y luego las mueve la persona\n const [collapsedIds, setCollapsedIds] = useState(() => new Set(columns.filter((column) => column.defaultCollapsed).map((column) => column.id)));\n const toggleColumn = (columnId) => {\n const collapsed = !collapsedIds.has(columnId);\n setCollapsedIds((current) => {\n const next = new Set(current);\n if (collapsed) {\n next.add(columnId);\n } else {\n next.delete(columnId);\n }\n return next;\n });\n onColumnCollapse?.(columnId, collapsed);\n };\n const today = todayIsoDateOf();\n const columnTitleOf = (columnId) => columns.find((column) => column.id === columnId)?.title ?? columnId;\n const cardTitleOf = (cardId) => cards.find((card) => card.id === cardId)?.title ?? cardId;\n\n // lo que oye quien usa lector de pantalla (posiciones desde 1, como se cuentan)\n const announceStart = (start, provided) => provided.announce(t('lifted', {\n title: cardTitleOf(start.draggableId), column: columnTitleOf(start.source.droppableId), position: start.source.index + 1,\n }));\n const announceUpdate = (update, provided) => {\n if (update.destination) {\n provided.announce(t('moving', {column: columnTitleOf(update.destination.droppableId), position: update.destination.index + 1}));\n }\n };\n const finishMove = (result, provided) => {\n const {draggableId, source, destination} = result;\n // se soltó fuera de una columna o en el mismo lugar: nada que mover\n if (!destination || (destination.droppableId === source.droppableId && destination.index === source.index)) {\n provided.announce(t('cancelled', {title: cardTitleOf(draggableId)}));\n return;\n }\n provided.announce(t('dropped', {title: cardTitleOf(draggableId), column: columnTitleOf(destination.droppableId), position: destination.index + 1}));\n onMove({cardId: draggableId, fromColumnId: source.droppableId, toColumnId: destination.droppableId, toIndex: destination.index});\n };\n\n return (\n <DragDropContext onDragStart={announceStart} onDragUpdate={announceUpdate} onDragEnd={finishMove} dragHandleUsageInstructions={t('instructions')}>\n <Box role=\"region\" aria-label={ariaLabel} sx={{\n display: 'flex', gap: 2, overflowX: 'auto', pb: 1, scrollSnapType: 'x proximity', alignItems: 'flex-start',\n }}>\n {columns.map((column) => {\n const columnCards = cardsOfColumn(cards, column.id);\n // con un filtro puesto la pantalla dice cuántas tiene de verdad: «1 / 3» mentía con la columna llena\n const total = Number.isInteger(column.count) ? column.count : columnCards.length;\n const isOver = isOverLimit(column, total);\n const count = Number.isInteger(column.limit) ? `${total} / ${column.limit}` : String(total);\n const isCollapsed = column.collapsible && collapsedIds.has(column.id);\n // encogida: una tira con su nombre de lado y su cuenta; se le puede soltar una tarjeta (queda arriba)\n if (isCollapsed) {\n return (\n <Droppable key={column.id} droppableId={column.id}>\n {(droppableProvided, droppableSnapshot) => (\n <Paper ref={droppableProvided.innerRef} {...droppableProvided.droppableProps} variant=\"outlined\" component=\"section\"\n aria-label={column.title}\n sx={{\n flex: '0 0 auto', width: COLLAPSED_COLUMN_WIDTH_PIXELS, py: 1, borderRadius: 3, display: 'flex',\n flexDirection: 'column', alignItems: 'center', gap: 1, minHeight: EMPTY_COLUMN_MIN_HEIGHT * 2,\n bgcolor: droppableSnapshot.isDraggingOver ? 'action.hover' : undefined,\n }}>\n <Tooltip title={t('expandColumn', {column: column.title})} placement=\"right\">\n <IconButton size=\"small\" aria-label={t('expandColumn', {column: column.title})} aria-expanded=\"false\"\n onClick={() => toggleColumn(column.id)}>\n <KeyboardDoubleArrowRightRoundedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Chip size=\"small\" label={count} color={isOver ? 'warning' : 'default'} />\n <Typography variant=\"subtitle2\" component=\"h3\" sx={{writingMode: 'vertical-rl', whiteSpace: 'nowrap'}}>\n {column.title}\n </Typography>\n {/* el lugar de la tarjeta que se arrastra; encogida no la enseña */}\n <Box sx={{display: 'none'}}>{droppableProvided.placeholder}</Box>\n </Paper>\n )}\n </Droppable>\n );\n }\n return (\n <Paper key={column.id} variant=\"outlined\" component=\"section\" aria-label={column.title}\n sx={{flex: '1 1 0', minWidth: COLUMN_MIN_WIDTH_PIXELS, p: 1.5, scrollSnapAlign: 'start', borderRadius: 3}}>\n <Stack direction=\"row\" spacing={0.5} sx={{alignItems: 'center', mb: 1.5, px: 0.5}}>\n <Typography variant=\"subtitle2\" component=\"h3\" sx={{flexGrow: 1, minWidth: 0}}>{column.title}</Typography>\n <Chip size=\"small\" label={count} color={isOver ? 'warning' : 'default'}\n title={isOver ? t('overLimit', {limit: column.limit}) : undefined} />\n {onAddCard && (\n <Tooltip title={t('addCard', {column: column.title})}>\n <IconButton size=\"small\" aria-label={t('addCard', {column: column.title})} onClick={() => setAddingColumnId(column.id)}>\n <AddRoundedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n <ActionsMenu label={t('columnActions', {column: column.title})} actions={columnActions?.(column)} />\n {column.collapsible && (\n <Tooltip title={t('collapseColumn', {column: column.title})}>\n <IconButton size=\"small\" aria-label={t('collapseColumn', {column: column.title})} aria-expanded=\"true\"\n onClick={() => toggleColumn(column.id)}>\n <KeyboardDoubleArrowLeftRoundedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n </Stack>\n {addingColumnId === column.id && (\n <Box sx={{mb: 1}}>\n <QuickAdd columnTitle={column.title} t={t} onClose={() => setAddingColumnId(null)}\n onAdd={(title) => onAddCard({columnId: column.id, title})} />\n </Box>\n )}\n <Droppable droppableId={column.id}>\n {(droppableProvided, droppableSnapshot) => (\n <Stack ref={droppableProvided.innerRef} {...droppableProvided.droppableProps} spacing={1}\n sx={{\n minHeight: EMPTY_COLUMN_MIN_HEIGHT, borderRadius: 2, transition: 'background-color 160ms',\n bgcolor: droppableSnapshot.isDraggingOver ? 'action.hover' : 'transparent',\n }}>\n {columnCards.map((card, index) => (\n <Draggable key={card.id} draggableId={card.id} index={index}>\n {(draggableProvided, draggableSnapshot) => (\n <Paper ref={draggableProvided.innerRef} {...draggableProvided.draggableProps} {...draggableProvided.dragHandleProps}\n elevation={draggableSnapshot.isDragging ? 8 : 1}\n onClick={onCardClick ? () => onCardClick(card.id) : undefined}\n sx={{p: 1.5, borderRadius: 2, cursor: 'grab', position: 'relative', '&:focus-visible': {outline: 2, outlineColor: 'primary.main'}}}>\n {/* el «⋯» arriba a la derecha; el contenido le deja su lugar */}\n {cardActions && (\n <Box sx={{position: 'absolute', top: 4, right: 4}}>\n <ActionsMenu label={t('cardActions', {title: card.title})} actions={cardActions(card)} />\n </Box>\n )}\n <Box sx={cardActions ? {pr: 3} : undefined}>\n {renderCard ? renderCard(card) : <DefaultCard card={card} t={t} today={today} onComplete={onCardComplete} />}\n </Box>\n </Paper>\n )}\n </Draggable>\n ))}\n {droppableProvided.placeholder}\n {/* vacía de verdad, o con tarjetas que el filtro de la pantalla esconde (no se dice «sin tarjetas») */}\n {columnCards.length === 0 && !droppableSnapshot.isDraggingOver && addingColumnId !== column.id && (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{textAlign: 'center', py: 3}}>\n {total > 0 ? t('emptyFiltered') : t('empty')}\n </Typography>\n )}\n </Stack>\n )}\n </Droppable>\n </Paper>\n );\n })}\n </Box>\n </DragDropContext>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"KanbanBoard.js","sources":["../../src/kanban/KanbanBoard.jsx"],"sourcesContent":["// Un tablero kanban (@stackcraftmx/calcita/kanban): columnas con tarjetas que se arrastran de una a otra con el ratón, con el\n// dedo o con el teclado (espacio para levantar, flechas para mover, espacio para soltar). Con @hello-pangea/dnd por dentro.\n//\n// <KanbanBoard columns={[{id: 'todo', title: 'Por hacer'}, {id: 'doing', title: 'En proceso', limit: 3}]}\n// cards={cards} onMove={(move) => api.post('/tasks/move', move)} ariaLabel=\"Tablero de tareas\" />\n//\n// El tablero no guarda nada: avisa la movida (onMove) y quien lo usa actualiza sus tarjetas (moveCard de kanbanMoves.js lo\n// hace sin esperar al servidor). Una columna con tope (limit, el trabajo en curso) avisa en ámbar cuando lo pasa.\n//\n// Accesible: el lector de pantalla anuncia en el idioma de la app qué se levantó, a dónde va y dónde quedó.\n//\n// Lo de un producto, todo hacia afuera (el tablero no guarda nada ni llama a ningún servidor):\n// - la tarjeta por omisión pinta lo que traiga: etiquetas (texto o {label, color}), responsables con su monograma, la\n// fecha límite (roja si ya venció, ámbar si es hoy), el avance de su lista de pendientes, comentarios y adjuntos. Para\n// otra tarjeta: renderCard;\n// - «+» en cada columna para agregar escribiendo el título (onAddCard({columnId, title}));\n// - «⋯» en cada tarjeta y en cada columna con las acciones que dé la pantalla (cardActions, columnActions): editar,\n// asignarme, mover sin arrastrar, borrar…;\n// - terminar una tarea: con onCardComplete cada tarjeta lleva su círculo para marcarla (y desmarcarla); qué pasa al\n// terminarla (pasarla a «Listo», guardar la fecha) lo decide la pantalla. Una tarjeta con completed: true sale con su\n// palomita verde y su fecha límite ya no se pinta de rojo;\n// - columnas que se encogen (collapsible), como el congelador (icebox) de ideas para después: se quedan en una tira angosta\n// con su nombre y su cuenta, y se les puede soltar una tarjeta igual. defaultCollapsed la abre encogida y\n// onColumnCollapse avisa cada cambio (para guardarlo si la pantalla quiere);\n// - texts para cualquier texto (la forma de `kanban` en los textos del paquete).\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaKanbanBoard con defaultProps y\n// styleOverrides de sus partes: completeButton, tags, titleRow, doneIcon, cardTitle, meta, due, dueIcon, dueText,\n// checklist, checklistIcon, comments, commentsIcon, attachments, attachmentsIcon, assignees, root, collapsedColumn,\n// collapsedTitle, hidden, column, columnHeader, columnTitle, quickAdd, dropZone, card, cardActions, cardContent, empty.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useState} from 'react';\nimport {DragDropContext, Draggable, Droppable} from '@hello-pangea/dnd';\nimport Avatar from '@mui/material/Avatar';\nimport AvatarGroup from '@mui/material/AvatarGroup';\nimport Box from '@mui/material/Box';\nimport Chip from '@mui/material/Chip';\nimport IconButton from '@mui/material/IconButton';\nimport Paper from '@mui/material/Paper';\nimport Stack from '@mui/material/Stack';\nimport TextField from '@mui/material/TextField';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport AddRoundedIcon from '@mui/icons-material/AddRounded';\nimport AttachFileRoundedIcon from '@mui/icons-material/AttachFileRounded';\nimport ChatBubbleOutlineRoundedIcon from '@mui/icons-material/ChatBubbleOutlineRounded';\nimport CheckBoxOutlinedIcon from '@mui/icons-material/CheckBoxOutlined';\nimport CheckCircleRoundedIcon from '@mui/icons-material/CheckCircleRounded';\nimport EventOutlinedIcon from '@mui/icons-material/EventOutlined';\nimport KeyboardDoubleArrowLeftRoundedIcon from '@mui/icons-material/KeyboardDoubleArrowLeftRounded';\nimport KeyboardDoubleArrowRightRoundedIcon from '@mui/icons-material/KeyboardDoubleArrowRightRounded';\nimport RadioButtonUncheckedRoundedIcon from '@mui/icons-material/RadioButtonUncheckedRounded';\n\nimport {initialsOf} from '@/appShell/menuItemText.js';\nimport {useFormatters} from '@/toolkit/useFormatters.js';\nimport {DUE_STATUS, dueStatusOf, tagOf, todayIsoDateOf} from '@/kanban/kanbanCards.js';\nimport {cardsOfColumn, isOverLimit} from '@/kanban/kanbanMoves.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport ActionsMenu from '@/ui/actions/ActionsMenu.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaKanbanBoard)\nconst THEME_NAME = 'CalcitaKanbanBoard';\nconst KanbanCompleteButton = piecePart(THEME_NAME, 'CompleteButton', IconButton);\nconst KanbanTags = piecePart(THEME_NAME, 'Tags', Stack);\nconst KanbanTitleRow = piecePart(THEME_NAME, 'TitleRow', Stack);\nconst KanbanDoneIcon = piecePart(THEME_NAME, 'DoneIcon', CheckCircleRoundedIcon);\nconst KanbanCardTitle = piecePart(THEME_NAME, 'CardTitle', Typography);\nconst KanbanMeta = piecePart(THEME_NAME, 'Meta', Stack);\nconst KanbanDue = piecePart(THEME_NAME, 'Due', Stack);\nconst KanbanDueIcon = piecePart(THEME_NAME, 'DueIcon', EventOutlinedIcon);\nconst KanbanDueText = piecePart(THEME_NAME, 'DueText', Typography);\nconst KanbanChecklist = piecePart(THEME_NAME, 'Checklist', Stack);\nconst KanbanChecklistIcon = piecePart(THEME_NAME, 'ChecklistIcon', CheckBoxOutlinedIcon);\nconst KanbanComments = piecePart(THEME_NAME, 'Comments', Stack);\nconst KanbanCommentsIcon = piecePart(THEME_NAME, 'CommentsIcon', ChatBubbleOutlineRoundedIcon);\nconst KanbanAttachments = piecePart(THEME_NAME, 'Attachments', Stack);\nconst KanbanAttachmentsIcon = piecePart(THEME_NAME, 'AttachmentsIcon', AttachFileRoundedIcon);\nconst KanbanAssignees = piecePart(THEME_NAME, 'Assignees', AvatarGroup);\nconst KanbanRoot = piecePart(THEME_NAME, 'Root', Box);\nconst KanbanCollapsedColumn = piecePart(THEME_NAME, 'CollapsedColumn', Paper);\nconst KanbanCollapsedTitle = piecePart(THEME_NAME, 'CollapsedTitle', Typography);\nconst KanbanHidden = piecePart(THEME_NAME, 'Hidden', Box);\nconst KanbanColumn = piecePart(THEME_NAME, 'Column', Paper);\nconst KanbanColumnHeader = piecePart(THEME_NAME, 'ColumnHeader', Stack);\nconst KanbanColumnTitle = piecePart(THEME_NAME, 'ColumnTitle', Typography);\nconst KanbanQuickAdd = piecePart(THEME_NAME, 'QuickAdd', Box);\nconst KanbanDropZone = piecePart(THEME_NAME, 'DropZone', Stack);\nconst KanbanCard = piecePart(THEME_NAME, 'Card', Paper);\nconst KanbanCardActions = piecePart(THEME_NAME, 'CardActions', Box);\nconst KanbanCardContent = piecePart(THEME_NAME, 'CardContent', Box);\nconst KanbanEmpty = piecePart(THEME_NAME, 'Empty', Typography);\n\n// las columnas se reparten el ancho, sin bajar de este mínimo; si no caben, el tablero desliza de lado.\n// OJO: con el teclado, la librería solo mueve una tarjeta a columnas que se ven COMPLETAS: con columnas fijas de 300 px la\n// cuarta quedaba cortada en un escritorio y no se podía soltar ahí con el teclado\nconst COLUMN_MIN_WIDTH_PIXELS = 220;\n// lo alto que mide una columna vacía: lo justo para soltar ahí una tarjeta\nconst EMPTY_COLUMN_MIN_HEIGHT = 96;\n// cuántas caras de responsables se ven antes del «+2»\nconst MAX_VISIBLE_ASSIGNEES = 3;\nconst ASSIGNEE_AVATAR_PIXELS = 24;\n// lo ancho de una columna encogida: su nombre de lado, su cuenta y su botón para abrirla\nconst COLLAPSED_COLUMN_WIDTH_PIXELS = 52;\n// el color del texto de la fecha según cómo va\nconst DUE_COLOR = Object.freeze({[DUE_STATUS.overdue]: 'error.main', [DUE_STATUS.today]: 'warning.dark', [DUE_STATUS.upcoming]: 'text.secondary'});\n\n/**\n * El círculo para terminar una tarea (o reabrirla, si ya está terminada). El clic no levanta la tarjeta ni la abre.\n *\n * @param {{card: any, t: Function, onComplete: (card: any, completed: boolean) => void}} props\n */\nfunction CompleteButton({card, t, onComplete}) {\n const label = card.completed ? t('reopen', {title: card.title}) : t('complete', {title: card.title});\n return (\n <Tooltip title={label}>\n <KanbanCompleteButton size=\"small\" aria-label={label} aria-pressed={Boolean(card.completed)} ownSx={{m: -0.5, color: card.completed ? 'success.main' : 'text.secondary'}}\n onClick={(event) => {\n event.stopPropagation();\n onComplete(card, !card.completed);\n }}>\n {card.completed ? <CheckCircleRoundedIcon fontSize=\"small\" /> : <RadioButtonUncheckedRoundedIcon fontSize=\"small\" />}\n </KanbanCompleteButton>\n </Tooltip>\n );\n}\n\n/**\n * Una tarjeta por omisión: lo que traiga, sin pedir nada (título, descripción, etiquetas, responsables, fecha, pendientes,\n * comentarios y adjuntos).\n *\n * @param {{card: any, t: Function, today: string, onComplete?: (card: any, completed: boolean) => void}} props\n */\nfunction DefaultCard({card, t, today, onComplete}) {\n const {formatDate} = useFormatters();\n // terminada, su fecha ya no apura: se pinta tenue, sin rojo ni ámbar\n const dueStatus = card.completed && card.dueDate ? DUE_STATUS.upcoming : dueStatusOf(card.dueDate, today);\n let dueText = '';\n if (card.completed && card.dueDate) {\n dueText = t('dueCompleted', {date: formatDate(card.dueDate)});\n } else if (dueStatus === DUE_STATUS.overdue) {\n dueText = t('dueOverdue', {date: formatDate(card.dueDate)});\n } else if (dueStatus === DUE_STATUS.today) {\n dueText = t('dueToday');\n } else if (dueStatus) {\n dueText = t('dueOn', {date: formatDate(card.dueDate)});\n }\n const hasFooter = dueStatus || card.checklist?.total > 0 || card.comments > 0 || card.attachments > 0 || card.assignees?.length > 0;\n\n return (\n <Stack spacing={0.75}>\n {card.tags?.length > 0 && (\n <KanbanTags direction=\"row\" spacing={0.5} useFlexGap ownSx={{flexWrap: 'wrap'}}>\n {card.tags.map((rawTag) => {\n const tag = tagOf(rawTag);\n return <Chip key={tag.label} label={tag.label} size=\"small\" color={tag.color} variant={tag.color === 'default' ? 'filled' : 'outlined'} />;\n })}\n </KanbanTags>\n )}\n <KanbanTitleRow direction=\"row\" spacing={1} ownSx={{alignItems: 'flex-start'}}>\n {onComplete && <CompleteButton card={card} t={t} onComplete={onComplete} />}\n {!onComplete && card.completed && (\n <KanbanDoneIcon fontSize=\"small\" ownSx={{color: 'success.main'}} titleAccess={t('completed')} />\n )}\n <KanbanCardTitle variant=\"subtitle2\" component=\"p\" ownSx={{color: card.completed ? 'text.secondary' : undefined}}>{card.title}</KanbanCardTitle>\n </KanbanTitleRow>\n {card.description && <Typography variant=\"body2\" color=\"text.secondary\">{card.description}</Typography>}\n {hasFooter && (\n <KanbanMeta direction=\"row\" spacing={1.25} useFlexGap ownSx={{alignItems: 'center', flexWrap: 'wrap', color: 'text.secondary'}}>\n {dueStatus && (\n <KanbanDue direction=\"row\" spacing={0.5} ownSx={{alignItems: 'center', color: DUE_COLOR[dueStatus]}}>\n <KanbanDueIcon ownSx={{fontSize: 16}} />\n <KanbanDueText variant=\"caption\" ownSx={{fontWeight: dueStatus === DUE_STATUS.upcoming ? 400 : 600}}>{dueText}</KanbanDueText>\n </KanbanDue>\n )}\n {card.checklist?.total > 0 && (\n <KanbanChecklist direction=\"row\" spacing={0.5} ownSx={{alignItems: 'center'}}\n aria-label={t('checklist', {done: card.checklist.done, total: card.checklist.total})}>\n <KanbanChecklistIcon ownSx={{fontSize: 16}} />\n <Typography variant=\"caption\" aria-hidden=\"true\">{card.checklist.done}/{card.checklist.total}</Typography>\n </KanbanChecklist>\n )}\n {card.comments > 0 && (\n <KanbanComments direction=\"row\" spacing={0.5} ownSx={{alignItems: 'center'}} aria-label={t('comments', {count: card.comments})}>\n <KanbanCommentsIcon ownSx={{fontSize: 16}} />\n <Typography variant=\"caption\" aria-hidden=\"true\">{card.comments}</Typography>\n </KanbanComments>\n )}\n {card.attachments > 0 && (\n <KanbanAttachments direction=\"row\" spacing={0.5} ownSx={{alignItems: 'center'}} aria-label={t('attachments', {count: card.attachments})}>\n <KanbanAttachmentsIcon ownSx={{fontSize: 16}} />\n <Typography variant=\"caption\" aria-hidden=\"true\">{card.attachments}</Typography>\n </KanbanAttachments>\n )}\n {card.assignees?.length > 0 && (\n <KanbanAssignees max={MAX_VISIBLE_ASSIGNEES} ownSx={{ml: 'auto', '& .MuiAvatar-root': {width: ASSIGNEE_AVATAR_PIXELS, height: ASSIGNEE_AVATAR_PIXELS, fontSize: 11}}}\n aria-label={t('assignees', {names: card.assignees.map((person) => person.name).join(', ')})}>\n {card.assignees.map((person) => (\n <Tooltip key={person.id} title={person.name}>\n <Avatar alt={person.name} src={person.avatarUrl}>{initialsOf(person.name)}</Avatar>\n </Tooltip>\n ))}\n </KanbanAssignees>\n )}\n </KanbanMeta>\n )}\n </Stack>\n );\n}\n\n/**\n * Agregar una tarjeta escribiendo su título: Enter la agrega (y deja el campo listo para otra), Escape cierra.\n *\n * @param {{columnTitle: string, onAdd: (title: string) => void, onClose: () => void, t: Function}} props\n */\nfunction QuickAdd({columnTitle, onAdd, onClose, t}) {\n const [title, setTitle] = useState('');\n return (\n <TextField size=\"small\" fullWidth autoFocus multiline maxRows={4} value={title} placeholder={t('addCardPlaceholder')}\n slotProps={{htmlInput: {'aria-label': t('addCard', {column: columnTitle})}}}\n onChange={(event) => setTitle(event.target.value)}\n onBlur={() => !title.trim() && onClose()}\n onKeyDown={(event) => {\n if (event.key === 'Escape') {\n onClose();\n }\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n if (title.trim()) {\n onAdd(title.trim());\n setTitle('');\n }\n }\n }} />\n );\n}\n\n/**\n * @param {object} props\n * @param {Array<{id: string, title: string, limit?: number, count?: number, collapsible?: boolean, defaultCollapsed?: boolean}>} props.columns\n * en su orden. count: cuántas tarjetas tiene de verdad cuando la pantalla le pasa solo las filtradas (el tope se cuenta\n * contra todas). collapsible: lleva su botón para encogerse (el congelador); defaultCollapsed: empieza encogida\n * @param {Array<{id: string, columnId: string, title: string, completed?: boolean, description?: string, tags?: Array<string|{label: string, color?: string}>, assignees?: Array<{id: string, name: string, avatarUrl?: string}>, dueDate?: string, checklist?: {done: number, total: number}, comments?: number, attachments?: number} & Record<string, any>>} props.cards\n * el orden de cada columna es el orden en este arreglo; cada tarjeta puede traer sus campos propios (llegan a renderCard,\n * a cardActions y a onCardClick tal cual). dueDate: AAAA-MM-DD\n * @param {(move: {cardId: string, fromColumnId: string, toColumnId: string, toIndex: number}) => void} props.onMove\n * @param {(card: any) => import('react').ReactNode} [props.renderCard] lo de adentro de cada tarjeta (recibe la tarjeta de cards)\n * @param {(cardId: string) => void} [props.onCardClick]\n * @param {(newCard: {columnId: string, title: string}) => void} [props.onAddCard] con él cada columna lleva su «+» para agregar\n * escribiendo el título\n * @param {(card: any) => Array<{key: string, label: string, icon?: import('react').ReactNode, color?: string, disabled?: boolean, onClick: () => void}>} [props.cardActions]\n * las acciones del «⋯» de cada tarjeta (editar, asignarme, borrar…); sin ellas no hay «⋯»\n * @param {(column: any) => Array<{key: string, label: string, icon?: import('react').ReactNode, color?: string, disabled?: boolean, onClick: () => void}>} [props.columnActions]\n * las acciones del «⋯» de cada columna (renombrar, limpiar…)\n * @param {(card: any, completed: boolean) => void} [props.onCardComplete] con él cada tarjeta lleva su círculo para terminarla\n * (completed true) o reabrirla (false); la pantalla decide qué más pasa (moverla a «Listo», guardar la fecha)\n * @param {(columnId: string, collapsed: boolean) => void} [props.onColumnCollapse] cada que una columna se encoge o se abre\n * @param {string} props.ariaLabel ya traducido\n * @param {object} [props.texts] los textos que cambian, con la forma de `kanban` en los textos del paquete\n */\nexport default function KanbanBoard(props) {\n // lo que el proyecto puso en su tema (components.CalcitaKanbanBoard.defaultProps) y encima lo que llega aquí\n const {\n columns, cards, onMove, renderCard, onCardClick, onAddCard, cardActions, columnActions, onCardComplete, onColumnCollapse, ariaLabel, texts,\n} = usePieceProps(props, THEME_NAME);\n const {t} = useToolkitTranslation('kanban', texts);\n // la columna donde se está escribiendo una tarjeta nueva\n const [addingColumnId, setAddingColumnId] = useState(null);\n // las columnas encogidas: empiezan como dice defaultCollapsed y luego las mueve la persona\n const [collapsedIds, setCollapsedIds] = useState(() => new Set(columns.filter((column) => column.defaultCollapsed).map((column) => column.id)));\n const toggleColumn = (columnId) => {\n const collapsed = !collapsedIds.has(columnId);\n setCollapsedIds((current) => {\n const next = new Set(current);\n if (collapsed) {\n next.add(columnId);\n } else {\n next.delete(columnId);\n }\n return next;\n });\n onColumnCollapse?.(columnId, collapsed);\n };\n const today = todayIsoDateOf();\n const columnTitleOf = (columnId) => columns.find((column) => column.id === columnId)?.title ?? columnId;\n const cardTitleOf = (cardId) => cards.find((card) => card.id === cardId)?.title ?? cardId;\n\n // lo que oye quien usa lector de pantalla (posiciones desde 1, como se cuentan)\n const announceStart = (start, provided) => provided.announce(t('lifted', {\n title: cardTitleOf(start.draggableId), column: columnTitleOf(start.source.droppableId), position: start.source.index + 1,\n }));\n const announceUpdate = (update, provided) => {\n if (update.destination) {\n provided.announce(t('moving', {column: columnTitleOf(update.destination.droppableId), position: update.destination.index + 1}));\n }\n };\n const finishMove = (result, provided) => {\n const {draggableId, source, destination} = result;\n // se soltó fuera de una columna o en el mismo lugar: nada que mover\n if (!destination || (destination.droppableId === source.droppableId && destination.index === source.index)) {\n provided.announce(t('cancelled', {title: cardTitleOf(draggableId)}));\n return;\n }\n provided.announce(t('dropped', {title: cardTitleOf(draggableId), column: columnTitleOf(destination.droppableId), position: destination.index + 1}));\n onMove({cardId: draggableId, fromColumnId: source.droppableId, toColumnId: destination.droppableId, toIndex: destination.index});\n };\n\n return (\n <DragDropContext onDragStart={announceStart} onDragUpdate={announceUpdate} onDragEnd={finishMove} dragHandleUsageInstructions={t('instructions')}>\n <KanbanRoot role=\"region\" aria-label={ariaLabel} ownSx={{\n display: 'flex', gap: 2, overflowX: 'auto', pb: 1, scrollSnapType: 'x proximity', alignItems: 'flex-start',\n }}>\n {columns.map((column) => {\n const columnCards = cardsOfColumn(cards, column.id);\n // con un filtro puesto la pantalla dice cuántas tiene de verdad: «1 / 3» mentía con la columna llena\n const total = Number.isInteger(column.count) ? column.count : columnCards.length;\n const isOver = isOverLimit(column, total);\n const count = Number.isInteger(column.limit) ? `${total} / ${column.limit}` : String(total);\n const isCollapsed = column.collapsible && collapsedIds.has(column.id);\n // encogida: una tira con su nombre de lado y su cuenta; se le puede soltar una tarjeta (queda arriba)\n if (isCollapsed) {\n return (\n <Droppable key={column.id} droppableId={column.id}>\n {(droppableProvided, droppableSnapshot) => (\n <KanbanCollapsedColumn ref={droppableProvided.innerRef} {...droppableProvided.droppableProps} variant=\"outlined\" component=\"section\"\n aria-label={column.title}\n ownSx={{\n flex: '0 0 auto', width: COLLAPSED_COLUMN_WIDTH_PIXELS, py: 1, borderRadius: 3, display: 'flex',\n flexDirection: 'column', alignItems: 'center', gap: 1, minHeight: EMPTY_COLUMN_MIN_HEIGHT * 2,\n bgcolor: droppableSnapshot.isDraggingOver ? 'action.hover' : undefined,\n }}>\n <Tooltip title={t('expandColumn', {column: column.title})} placement=\"right\">\n <IconButton size=\"small\" aria-label={t('expandColumn', {column: column.title})} aria-expanded=\"false\"\n onClick={() => toggleColumn(column.id)}>\n <KeyboardDoubleArrowRightRoundedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Chip size=\"small\" label={count} color={isOver ? 'warning' : 'default'} />\n <KanbanCollapsedTitle variant=\"subtitle2\" component=\"h3\" ownSx={{writingMode: 'vertical-rl', whiteSpace: 'nowrap'}}>\n {column.title}\n </KanbanCollapsedTitle>\n {/* el lugar de la tarjeta que se arrastra; encogida no la enseña */}\n <KanbanHidden ownSx={{display: 'none'}}>{droppableProvided.placeholder}</KanbanHidden>\n </KanbanCollapsedColumn>\n )}\n </Droppable>\n );\n }\n return (\n <KanbanColumn key={column.id} variant=\"outlined\" component=\"section\" aria-label={column.title}\n ownSx={{flex: '1 1 0', minWidth: COLUMN_MIN_WIDTH_PIXELS, p: 1.5, scrollSnapAlign: 'start', borderRadius: 3}}>\n <KanbanColumnHeader direction=\"row\" spacing={0.5} ownSx={{alignItems: 'center', mb: 1.5, px: 0.5}}>\n <KanbanColumnTitle variant=\"subtitle2\" component=\"h3\" ownSx={{flexGrow: 1, minWidth: 0}}>{column.title}</KanbanColumnTitle>\n <Chip size=\"small\" label={count} color={isOver ? 'warning' : 'default'}\n title={isOver ? t('overLimit', {limit: column.limit}) : undefined} />\n {onAddCard && (\n <Tooltip title={t('addCard', {column: column.title})}>\n <IconButton size=\"small\" aria-label={t('addCard', {column: column.title})} onClick={() => setAddingColumnId(column.id)}>\n <AddRoundedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n <ActionsMenu label={t('columnActions', {column: column.title})} actions={columnActions?.(column)} />\n {column.collapsible && (\n <Tooltip title={t('collapseColumn', {column: column.title})}>\n <IconButton size=\"small\" aria-label={t('collapseColumn', {column: column.title})} aria-expanded=\"true\"\n onClick={() => toggleColumn(column.id)}>\n <KeyboardDoubleArrowLeftRoundedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n )}\n </KanbanColumnHeader>\n {addingColumnId === column.id && (\n <KanbanQuickAdd ownSx={{mb: 1}}>\n <QuickAdd columnTitle={column.title} t={t} onClose={() => setAddingColumnId(null)}\n onAdd={(title) => onAddCard({columnId: column.id, title})} />\n </KanbanQuickAdd>\n )}\n <Droppable droppableId={column.id}>\n {(droppableProvided, droppableSnapshot) => (\n <KanbanDropZone ref={droppableProvided.innerRef} {...droppableProvided.droppableProps} spacing={1}\n ownSx={{\n minHeight: EMPTY_COLUMN_MIN_HEIGHT, borderRadius: 2, transition: 'background-color 160ms',\n bgcolor: droppableSnapshot.isDraggingOver ? 'action.hover' : 'transparent',\n }}>\n {columnCards.map((card, index) => (\n <Draggable key={card.id} draggableId={card.id} index={index}>\n {(draggableProvided, draggableSnapshot) => (\n <KanbanCard ref={draggableProvided.innerRef} {...draggableProvided.draggableProps} {...draggableProvided.dragHandleProps}\n elevation={draggableSnapshot.isDragging ? 8 : 1}\n onClick={onCardClick ? () => onCardClick(card.id) : undefined}\n ownSx={{p: 1.5, borderRadius: 2, cursor: 'grab', position: 'relative', '&:focus-visible': {outline: 2, outlineColor: 'primary.main'}}}>\n {/* el «⋯» arriba a la derecha; el contenido le deja su lugar */}\n {cardActions && (\n <KanbanCardActions ownSx={{position: 'absolute', top: 4, right: 4}}>\n <ActionsMenu label={t('cardActions', {title: card.title})} actions={cardActions(card)} />\n </KanbanCardActions>\n )}\n <KanbanCardContent ownSx={cardActions ? {pr: 3} : undefined}>\n {renderCard ? renderCard(card) : <DefaultCard card={card} t={t} today={today} onComplete={onCardComplete} />}\n </KanbanCardContent>\n </KanbanCard>\n )}\n </Draggable>\n ))}\n {droppableProvided.placeholder}\n {/* vacía de verdad, o con tarjetas que el filtro de la pantalla esconde (no se dice «sin tarjetas») */}\n {columnCards.length === 0 && !droppableSnapshot.isDraggingOver && addingColumnId !== column.id && (\n <KanbanEmpty variant=\"caption\" color=\"text.secondary\" ownSx={{textAlign: 'center', py: 3}}>\n {total > 0 ? t('emptyFiltered') : t('empty')}\n </KanbanEmpty>\n )}\n </KanbanDropZone>\n )}\n </Droppable>\n </KanbanColumn>\n );\n })}\n </KanbanRoot>\n </DragDropContext>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+DA,MAAM,aAAa;AACnB,MAAM,uBAAuB,UAAU,YAAY,kBAAkB,UAAU;AAC/E,MAAM,aAAa,UAAU,YAAY,QAAQ,KAAK;AACtD,MAAM,iBAAiB,UAAU,YAAY,YAAY,KAAK;AAC9D,MAAM,iBAAiB,UAAU,YAAY,YAAY,sBAAsB;AAC/E,MAAM,kBAAkB,UAAU,YAAY,aAAa,UAAU;AACrE,MAAM,aAAa,UAAU,YAAY,QAAQ,KAAK;AACtD,MAAM,YAAY,UAAU,YAAY,OAAO,KAAK;AACpD,MAAM,gBAAgB,UAAU,YAAY,WAAW,iBAAiB;AACxE,MAAM,gBAAgB,UAAU,YAAY,WAAW,UAAU;AACjE,MAAM,kBAAkB,UAAU,YAAY,aAAa,KAAK;AAChE,MAAM,sBAAsB,UAAU,YAAY,iBAAiB,oBAAoB;AACvF,MAAM,iBAAiB,UAAU,YAAY,YAAY,KAAK;AAC9D,MAAM,qBAAqB,UAAU,YAAY,gBAAgB,4BAA4B;AAC7F,MAAM,oBAAoB,UAAU,YAAY,eAAe,KAAK;AACpE,MAAM,wBAAwB,UAAU,YAAY,mBAAmB,qBAAqB;AAC5F,MAAM,kBAAkB,UAAU,YAAY,aAAa,WAAW;AACtE,MAAM,aAAa,UAAU,YAAY,QAAQ,GAAG;AACpD,MAAM,wBAAwB,UAAU,YAAY,mBAAmB,KAAK;AAC5E,MAAM,uBAAuB,UAAU,YAAY,kBAAkB,UAAU;AAC/E,MAAM,eAAe,UAAU,YAAY,UAAU,GAAG;AACxD,MAAM,eAAe,UAAU,YAAY,UAAU,KAAK;AAC1D,MAAM,qBAAqB,UAAU,YAAY,gBAAgB,KAAK;AACtE,MAAM,oBAAoB,UAAU,YAAY,eAAe,UAAU;AACzE,MAAM,iBAAiB,UAAU,YAAY,YAAY,GAAG;AAC5D,MAAM,iBAAiB,UAAU,YAAY,YAAY,KAAK;AAC9D,MAAM,aAAa,UAAU,YAAY,QAAQ,KAAK;AACtD,MAAM,oBAAoB,UAAU,YAAY,eAAe,GAAG;AAClE,MAAM,oBAAoB,UAAU,YAAY,eAAe,GAAG;AAClE,MAAM,cAAc,UAAU,YAAY,SAAS,UAAU;AAK7D,MAAM,0BAA0B;AAEhC,MAAM,0BAA0B;AAEhC,MAAM,wBAAwB;AAC9B,MAAM,yBAAyB;AAE/B,MAAM,gCAAgC;AAEtC,MAAM,YAAY,OAAO,OAAO,EAAC,CAAC,WAAW,OAAO,GAAG,cAAc,CAAC,WAAW,KAAK,GAAG,gBAAgB,CAAC,WAAW,QAAQ,GAAG,kBAAiB;AAOjJ,SAAS,eAAe,EAAC,MAAM,GAAG,cAAa;AAC3C,QAAM,QAAQ,KAAK,YAAY,EAAE,UAAU,EAAC,OAAO,KAAK,MAAA,CAAM,IAAI,EAAE,YAAY,EAAC,OAAO,KAAK,OAAM;AACnG,SACI,oBAAC,SAAA,EAAQ,OAAO,OACZ,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MAAqB,MAAK;AAAA,MAAQ,cAAY;AAAA,MAAO,gBAAc,QAAQ,KAAK,SAAS;AAAA,MAAG,OAAO,EAAC,GAAG,MAAM,OAAO,KAAK,YAAY,iBAAiB,iBAAA;AAAA,MAC3I,SAAS,CAAC,UAAU;AAChB,cAAM,gBAAA;AACN,mBAAW,MAAM,CAAC,KAAK,SAAS;AAAA,MACpC;AAAA,MACP,UAAA,KAAK,YAAY,oBAAC,wBAAA,EAAuB,UAAS,SAAQ,IAAK,oBAAC,iCAAA,EAAgC,UAAS,QAAA,CAAQ;AAAA,IAAA;AAAA,EAAA,GAE1H;AAER;AAQA,SAAS,YAAY,EAAC,MAAM,GAAG,OAAO,cAAa;AAC/C,QAAM,EAAC,WAAA,IAAc,cAAA;AAErB,QAAM,YAAY,KAAK,aAAa,KAAK,UAAU,WAAW,WAAW,YAAY,KAAK,SAAS,KAAK;AACxG,MAAI,UAAU;AACd,MAAI,KAAK,aAAa,KAAK,SAAS;AAChC,cAAU,EAAE,gBAAgB,EAAC,MAAM,WAAW,KAAK,OAAO,GAAE;AAAA,EAChE,WAAW,cAAc,WAAW,SAAS;AACzC,cAAU,EAAE,cAAc,EAAC,MAAM,WAAW,KAAK,OAAO,GAAE;AAAA,EAC9D,WAAW,cAAc,WAAW,OAAO;AACvC,cAAU,EAAE,UAAU;AAAA,EAC1B,WAAW,WAAW;AAClB,cAAU,EAAE,SAAS,EAAC,MAAM,WAAW,KAAK,OAAO,GAAE;AAAA,EACzD;AACA,QAAM,YAAY,aAAa,KAAK,WAAW,QAAQ,KAAK,KAAK,WAAW,KAAK,KAAK,cAAc,KAAK,KAAK,WAAW,SAAS;AAElI,SACI,qBAAC,OAAA,EAAM,SAAS,MACX,UAAA;AAAA,IAAA,KAAK,MAAM,SAAS,KACjB,oBAAC,cAAW,WAAU,OAAM,SAAS,KAAK,YAAU,MAAC,OAAO,EAAC,UAAU,OAAA,GAClE,eAAK,KAAK,IAAI,CAAC,WAAW;AACvB,YAAM,MAAM,MAAM,MAAM;AACxB,iCAAQ,MAAA,EAAqB,OAAO,IAAI,OAAO,MAAK,SAAQ,OAAO,IAAI,OAAO,SAAS,IAAI,UAAU,YAAY,WAAW,WAAA,GAA1G,IAAI,KAAkH;AAAA,IAC5I,CAAC,EAAA,CACL;AAAA,IAEJ,qBAAC,gBAAA,EAAe,WAAU,OAAM,SAAS,GAAG,OAAO,EAAC,YAAY,aAAA,GAC3D,UAAA;AAAA,MAAA,cAAc,oBAAC,gBAAA,EAAe,MAAY,GAAM,YAAwB;AAAA,MACxE,CAAC,cAAc,KAAK,aACjB,oBAAC,kBAAe,UAAS,SAAQ,OAAO,EAAC,OAAO,eAAA,GAAiB,aAAa,EAAE,WAAW,GAAG;AAAA,MAElG,oBAAC,iBAAA,EAAgB,SAAQ,aAAY,WAAU,KAAI,OAAO,EAAC,OAAO,KAAK,YAAY,mBAAmB,OAAA,GAAa,eAAK,MAAA,CAAM;AAAA,IAAA,GAClI;AAAA,IACC,KAAK,eAAe,oBAAC,YAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAkB,UAAA,KAAK,YAAA,CAAY;AAAA,IACzF,aACG,qBAAC,YAAA,EAAW,WAAU,OAAM,SAAS,MAAM,YAAU,MAAC,OAAO,EAAC,YAAY,UAAU,UAAU,QAAQ,OAAO,oBACxG,UAAA;AAAA,MAAA,aACG,qBAAC,WAAA,EAAU,WAAU,OAAM,SAAS,KAAK,OAAO,EAAC,YAAY,UAAU,OAAO,UAAU,SAAS,KAC7F,UAAA;AAAA,QAAA,oBAAC,eAAA,EAAc,OAAO,EAAC,UAAU,MAAK;AAAA,QACtC,oBAAC,eAAA,EAAc,SAAQ,WAAU,OAAO,EAAC,YAAY,cAAc,WAAW,WAAW,MAAM,IAAA,GAAO,UAAA,QAAA,CAAQ;AAAA,MAAA,GAClH;AAAA,MAEH,KAAK,WAAW,QAAQ,KACrB;AAAA,QAAC;AAAA,QAAA;AAAA,UAAgB,WAAU;AAAA,UAAM,SAAS;AAAA,UAAK,OAAO,EAAC,YAAY,SAAA;AAAA,UAC5D,cAAY,EAAE,aAAa,EAAC,MAAM,KAAK,UAAU,MAAM,OAAO,KAAK,UAAU,MAAA,CAAM;AAAA,UACtF,UAAA;AAAA,YAAA,oBAAC,qBAAA,EAAoB,OAAO,EAAC,UAAU,MAAK;AAAA,YAC5C,qBAAC,YAAA,EAAW,SAAQ,WAAU,eAAY,QAAQ,UAAA;AAAA,cAAA,KAAK,UAAU;AAAA,cAAK;AAAA,cAAE,KAAK,UAAU;AAAA,YAAA,EAAA,CAAM;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,MAGpG,KAAK,WAAW,KACb,qBAAC,kBAAe,WAAU,OAAM,SAAS,KAAK,OAAO,EAAC,YAAY,SAAA,GAAW,cAAY,EAAE,YAAY,EAAC,OAAO,KAAK,UAAS,GACzH,UAAA;AAAA,QAAA,oBAAC,oBAAA,EAAmB,OAAO,EAAC,UAAU,MAAK;AAAA,4BAC1C,YAAA,EAAW,SAAQ,WAAU,eAAY,QAAQ,eAAK,SAAA,CAAS;AAAA,MAAA,GACpE;AAAA,MAEH,KAAK,cAAc,KAChB,qBAAC,qBAAkB,WAAU,OAAM,SAAS,KAAK,OAAO,EAAC,YAAY,SAAA,GAAW,cAAY,EAAE,eAAe,EAAC,OAAO,KAAK,aAAY,GAClI,UAAA;AAAA,QAAA,oBAAC,uBAAA,EAAsB,OAAO,EAAC,UAAU,MAAK;AAAA,4BAC7C,YAAA,EAAW,SAAQ,WAAU,eAAY,QAAQ,eAAK,YAAA,CAAY;AAAA,MAAA,GACvE;AAAA,MAEH,KAAK,WAAW,SAAS,KACtB;AAAA,QAAC;AAAA,QAAA;AAAA,UAAgB,KAAK;AAAA,UAAuB,OAAO,EAAC,IAAI,QAAQ,qBAAqB,EAAC,OAAO,wBAAwB,QAAQ,wBAAwB,UAAU,GAAA,EAAE;AAAA,UACrJ,cAAY,EAAE,aAAa,EAAC,OAAO,KAAK,UAAU,IAAI,CAAC,WAAW,OAAO,IAAI,EAAE,KAAK,IAAI,GAAE;AAAA,UAClG,UAAA,KAAK,UAAU,IAAI,CAAC,+BAChB,SAAA,EAAwB,OAAO,OAAO,MACnC,UAAA,oBAAC,QAAA,EAAO,KAAK,OAAO,MAAM,KAAK,OAAO,WAAY,UAAA,WAAW,OAAO,IAAI,EAAA,CAAE,EAAA,GADhE,OAAO,EAErB,CACH;AAAA,QAAA;AAAA,MAAA;AAAA,IACL,EAAA,CAER;AAAA,EAAA,GAER;AAER;AAOA,SAAS,SAAS,EAAC,aAAa,OAAO,SAAS,KAAI;AAChD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AACrC,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MAAU,MAAK;AAAA,MAAQ,WAAS;AAAA,MAAC,WAAS;AAAA,MAAC,WAAS;AAAA,MAAC,SAAS;AAAA,MAAG,OAAO;AAAA,MAAO,aAAa,EAAE,oBAAoB;AAAA,MACxG,WAAW,EAAC,WAAW,EAAC,cAAc,EAAE,WAAW,EAAC,QAAQ,YAAA,CAAY,IAAC;AAAA,MACzE,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA,MAChD,QAAQ,MAAM,CAAC,MAAM,KAAA,KAAU,QAAA;AAAA,MAC/B,WAAW,CAAC,UAAU;AAClB,YAAI,MAAM,QAAQ,UAAU;AACxB,kBAAA;AAAA,QACJ;AACA,YAAI,MAAM,QAAQ,WAAW,CAAC,MAAM,UAAU;AAC1C,gBAAM,eAAA;AACN,cAAI,MAAM,QAAQ;AACd,kBAAM,MAAM,MAAM;AAClB,qBAAS,EAAE;AAAA,UACf;AAAA,QACJ;AAAA,MACJ;AAAA,IAAA;AAAA,EAAA;AAEnB;AAyBA,SAAwB,YAAY,OAAO;AAEvC,QAAM;AAAA,IACN;AAAA,IAAS;AAAA,IAAO;AAAA,IAAQ;AAAA,IAAY;AAAA,IAAa;AAAA,IAAW;AAAA,IAAa;AAAA,IAAe;AAAA,IAAgB;AAAA,IAAkB;AAAA,IAAW;AAAA,EAAA,IACrI,cAAc,OAAO,UAAU;AAC/B,QAAM,EAAC,EAAA,IAAK,sBAAsB,UAAU,KAAK;AAEjD,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAS,IAAI;AAEzD,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,MAAM,IAAI,IAAI,QAAQ,OAAO,CAAC,WAAW,OAAO,gBAAgB,EAAE,IAAI,CAAC,WAAW,OAAO,EAAE,CAAC,CAAC;AAC9I,QAAM,eAAe,CAAC,aAAa;AAC/B,UAAM,YAAY,CAAC,aAAa,IAAI,QAAQ;AAC5C,oBAAgB,CAAC,YAAY;AACzB,YAAM,OAAO,IAAI,IAAI,OAAO;AAC5B,UAAI,WAAW;AACX,aAAK,IAAI,QAAQ;AAAA,MACrB,OAAO;AACH,aAAK,OAAO,QAAQ;AAAA,MACxB;AACA,aAAO;AAAA,IACX,CAAC;AACD,uBAAmB,UAAU,SAAS;AAAA,EAC1C;AACA,QAAM,QAAQ,eAAA;AACd,QAAM,gBAAgB,CAAC,aAAa,QAAQ,KAAK,CAAC,WAAW,OAAO,OAAO,QAAQ,GAAG,SAAS;AAC/F,QAAM,cAAc,CAAC,WAAW,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,MAAM,GAAG,SAAS;AAGnF,QAAM,gBAAgB,CAAC,OAAO,aAAa,SAAS,SAAS,EAAE,UAAU;AAAA,IACrE,OAAO,YAAY,MAAM,WAAW;AAAA,IAAG,QAAQ,cAAc,MAAM,OAAO,WAAW;AAAA,IAAG,UAAU,MAAM,OAAO,QAAQ;AAAA,EAAA,CAC1H,CAAC;AACF,QAAM,iBAAiB,CAAC,QAAQ,aAAa;AACzC,QAAI,OAAO,aAAa;AACpB,eAAS,SAAS,EAAE,UAAU,EAAC,QAAQ,cAAc,OAAO,YAAY,WAAW,GAAG,UAAU,OAAO,YAAY,QAAQ,EAAA,CAAE,CAAC;AAAA,IAClI;AAAA,EACJ;AACA,QAAM,aAAa,CAAC,QAAQ,aAAa;AACrC,UAAM,EAAC,aAAa,QAAQ,YAAA,IAAe;AAE3C,QAAI,CAAC,eAAgB,YAAY,gBAAgB,OAAO,eAAe,YAAY,UAAU,OAAO,OAAQ;AACxG,eAAS,SAAS,EAAE,aAAa,EAAC,OAAO,YAAY,WAAW,EAAA,CAAE,CAAC;AACnE;AAAA,IACJ;AACA,aAAS,SAAS,EAAE,WAAW,EAAC,OAAO,YAAY,WAAW,GAAG,QAAQ,cAAc,YAAY,WAAW,GAAG,UAAU,YAAY,QAAQ,EAAA,CAAE,CAAC;AAClJ,WAAO,EAAC,QAAQ,aAAa,cAAc,OAAO,aAAa,YAAY,YAAY,aAAa,SAAS,YAAY,MAAA,CAAM;AAAA,EACnI;AAEA,6BACK,iBAAA,EAAgB,aAAa,eAAe,cAAc,gBAAgB,WAAW,YAAY,6BAA6B,EAAE,cAAc,GAC3I,UAAA,oBAAC,YAAA,EAAW,MAAK,UAAS,cAAY,WAAW,OAAO;AAAA,IACpD,SAAS;AAAA,IAAQ,KAAK;AAAA,IAAG,WAAW;AAAA,IAAQ,IAAI;AAAA,IAAG,gBAAgB;AAAA,IAAe,YAAY;AAAA,EAAA,GAE7F,UAAA,QAAQ,IAAI,CAAC,WAAW;AACrB,UAAM,cAAc,cAAc,OAAO,OAAO,EAAE;AAElD,UAAM,QAAQ,OAAO,UAAU,OAAO,KAAK,IAAI,OAAO,QAAQ,YAAY;AAC1E,UAAM,SAAS,YAAY,QAAQ,KAAK;AACxC,UAAM,QAAQ,OAAO,UAAU,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,OAAO,KAAK,KAAK,OAAO,KAAK;AAC1F,UAAM,cAAc,OAAO,eAAe,aAAa,IAAI,OAAO,EAAE;AAEpE,QAAI,aAAa;AACb,iCACK,WAAA,EAA0B,aAAa,OAAO,IAC1C,UAAA,CAAC,mBAAmB,sBACjB;AAAA,QAAC;AAAA,QAAA;AAAA,UAAsB,KAAK,kBAAkB;AAAA,UAAW,GAAG,kBAAkB;AAAA,UAAgB,SAAQ;AAAA,UAAW,WAAU;AAAA,UACpH,cAAY,OAAO;AAAA,UACnB,OAAO;AAAA,YACH,MAAM;AAAA,YAAY,OAAO;AAAA,YAA+B,IAAI;AAAA,YAAG,cAAc;AAAA,YAAG,SAAS;AAAA,YACzF,eAAe;AAAA,YAAU,YAAY;AAAA,YAAU,KAAK;AAAA,YAAG,WAAW,0BAA0B;AAAA,YAC5F,SAAS,kBAAkB,iBAAiB,iBAAiB;AAAA,UAAA;AAAA,UAEpE,UAAA;AAAA,YAAA,oBAAC,SAAA,EAAQ,OAAO,EAAE,gBAAgB,EAAC,QAAQ,OAAO,MAAA,CAAM,GAAG,WAAU,SACjE,UAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBAAW,MAAK;AAAA,gBAAQ,cAAY,EAAE,gBAAgB,EAAC,QAAQ,OAAO,OAAM;AAAA,gBAAG,iBAAc;AAAA,gBAClF,SAAS,MAAM,aAAa,OAAO,EAAE;AAAA,gBAC7C,UAAA,oBAAC,qCAAA,EAAoC,UAAS,QAAA,CAAQ;AAAA,cAAA;AAAA,YAAA,GAE9D;AAAA,YACA,oBAAC,QAAK,MAAK,SAAQ,OAAO,OAAO,OAAO,SAAS,YAAY,UAAA,CAAW;AAAA,YACxE,oBAAC,sBAAA,EAAqB,SAAQ,aAAY,WAAU,MAAK,OAAO,EAAC,aAAa,eAAe,YAAY,SAAA,GACpG,iBAAO,OACZ;AAAA,YAEA,oBAAC,gBAAa,OAAO,EAAC,SAAS,UAAU,4BAAkB,YAAA,CAAY;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA,EAC3E,GArBQ,OAAO,EAuBvB;AAAA,IAER;AACA,WACI;AAAA,MAAC;AAAA,MAAA;AAAA,QAA6B,SAAQ;AAAA,QAAW,WAAU;AAAA,QAAU,cAAY,OAAO;AAAA,QACjF,OAAO,EAAC,MAAM,SAAS,UAAU,yBAAyB,GAAG,KAAK,iBAAiB,SAAS,cAAc,EAAA;AAAA,QAC7G,UAAA;AAAA,UAAA,qBAAC,oBAAA,EAAmB,WAAU,OAAM,SAAS,KAAK,OAAO,EAAC,YAAY,UAAU,IAAI,KAAK,IAAI,OACzF,UAAA;AAAA,YAAA,oBAAC,mBAAA,EAAkB,SAAQ,aAAY,WAAU,MAAK,OAAO,EAAC,UAAU,GAAG,UAAU,EAAA,GAAK,iBAAO,OAAM;AAAA,YACvG;AAAA,cAAC;AAAA,cAAA;AAAA,gBAAK,MAAK;AAAA,gBAAQ,OAAO;AAAA,gBAAO,OAAO,SAAS,YAAY;AAAA,gBACvD,OAAO,SAAS,EAAE,aAAa,EAAC,OAAO,OAAO,MAAA,CAAM,IAAI;AAAA,cAAA;AAAA,YAAA;AAAA,YAC7D,aACG,oBAAC,SAAA,EAAQ,OAAO,EAAE,WAAW,EAAC,QAAQ,OAAO,MAAA,CAAM,GAC/C,UAAA,oBAAC,YAAA,EAAW,MAAK,SAAQ,cAAY,EAAE,WAAW,EAAC,QAAQ,OAAO,MAAA,CAAM,GAAG,SAAS,MAAM,kBAAkB,OAAO,EAAE,GACjH,UAAA,oBAAC,gBAAA,EAAe,UAAS,QAAA,CAAQ,GACrC,GACJ;AAAA,YAEJ,oBAAC,aAAA,EAAY,OAAO,EAAE,iBAAiB,EAAC,QAAQ,OAAO,MAAA,CAAM,GAAG,SAAS,gBAAgB,MAAM,EAAA,CAAG;AAAA,YACjG,OAAO,eACJ,oBAAC,SAAA,EAAQ,OAAO,EAAE,kBAAkB,EAAC,QAAQ,OAAO,MAAA,CAAM,GACtD,UAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBAAW,MAAK;AAAA,gBAAQ,cAAY,EAAE,kBAAkB,EAAC,QAAQ,OAAO,OAAM;AAAA,gBAAG,iBAAc;AAAA,gBACpF,SAAS,MAAM,aAAa,OAAO,EAAE;AAAA,gBAC7C,UAAA,oBAAC,oCAAA,EAAmC,UAAS,QAAA,CAAQ;AAAA,cAAA;AAAA,YAAA,EACzD,CACJ;AAAA,UAAA,GAER;AAAA,UACC,mBAAmB,OAAO,MACvB,oBAAC,kBAAe,OAAO,EAAC,IAAI,EAAA,GACxB,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cAAS,aAAa,OAAO;AAAA,cAAO;AAAA,cAAM,SAAS,MAAM,kBAAkB,IAAI;AAAA,cACtE,OAAO,CAAC,UAAU,UAAU,EAAC,UAAU,OAAO,IAAI,MAAA,CAAM;AAAA,YAAA;AAAA,UAAA,GACtE;AAAA,8BAEH,WAAA,EAAU,aAAa,OAAO,IAC1B,UAAA,CAAC,mBAAmB,sBACjB;AAAA,YAAC;AAAA,YAAA;AAAA,cAAe,KAAK,kBAAkB;AAAA,cAAW,GAAG,kBAAkB;AAAA,cAAgB,SAAS;AAAA,cACzF,OAAO;AAAA,gBACH,WAAW;AAAA,gBAAyB,cAAc;AAAA,gBAAG,YAAY;AAAA,gBACjE,SAAS,kBAAkB,iBAAiB,iBAAiB;AAAA,cAAA;AAAA,cAEnE,UAAA;AAAA,gBAAA,YAAY,IAAI,CAAC,MAAM,UACpB,oBAAC,WAAA,EAAwB,aAAa,KAAK,IAAI,OAC1C,UAAA,CAAC,mBAAmB,sBACjB;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBAAW,KAAK,kBAAkB;AAAA,oBAAW,GAAG,kBAAkB;AAAA,oBAAiB,GAAG,kBAAkB;AAAA,oBAClG,WAAW,kBAAkB,aAAa,IAAI;AAAA,oBAC9C,SAAS,cAAc,MAAM,YAAY,KAAK,EAAE,IAAI;AAAA,oBACpD,OAAO,EAAC,GAAG,KAAK,cAAc,GAAG,QAAQ,QAAQ,UAAU,YAAY,mBAAmB,EAAC,SAAS,GAAG,cAAc,iBAAc;AAAA,oBAErI,UAAA;AAAA,sBAAA,eACG,oBAAC,mBAAA,EAAkB,OAAO,EAAC,UAAU,YAAY,KAAK,GAAG,OAAO,EAAA,GAC5D,UAAA,oBAAC,aAAA,EAAY,OAAO,EAAE,eAAe,EAAC,OAAO,KAAK,MAAA,CAAM,GAAG,SAAS,YAAY,IAAI,EAAA,CAAG,EAAA,CAC3F;AAAA,sBAEJ,oBAAC,qBAAkB,OAAO,cAAc,EAAC,IAAI,EAAA,IAAK,QAC7C,UAAA,aAAa,WAAW,IAAI,wBAAK,aAAA,EAAY,MAAY,GAAM,OAAc,YAAY,gBAAgB,EAAA,CAC9G;AAAA,oBAAA;AAAA,kBAAA;AAAA,gBAAA,KAdI,KAAK,EAiBrB,CACH;AAAA,gBACA,kBAAkB;AAAA,gBAElB,YAAY,WAAW,KAAK,CAAC,kBAAkB,kBAAkB,mBAAmB,OAAO,MACxF,oBAAC,aAAA,EAAY,SAAQ,WAAU,OAAM,kBAAiB,OAAO,EAAC,WAAW,UAAU,IAAI,EAAA,GAClF,UAAA,QAAQ,IAAI,EAAE,eAAe,IAAI,EAAE,OAAO,EAAA,CAC/C;AAAA,cAAA;AAAA,YAAA;AAAA,UAAA,EAER,CAER;AAAA,QAAA;AAAA,MAAA;AAAA,MAjEe,OAAO;AAAA,IAAA;AAAA,EAoElC,CAAC,GACL,GACJ;AAER;"}
|
package/dist/maps/MapView.js
CHANGED
|
@@ -9,6 +9,10 @@ import Typography from "@mui/material/Typography";
|
|
|
9
9
|
import { useTheme } from "@mui/material/styles";
|
|
10
10
|
import { boundsOfMarkers, MAP_PIN_SIZE, mapPinHtmlOf } from "./mapMarkers.js";
|
|
11
11
|
import { paletteOf } from "../theme/components/paletteOf.js";
|
|
12
|
+
import { piecePart, usePieceProps } from "../theme/themePieces.js";
|
|
13
|
+
const THEME_NAME = "CalcitaMapView";
|
|
14
|
+
const MapPopupText = piecePart(THEME_NAME, "PopupText", Typography);
|
|
15
|
+
const MapRoot = piecePart(THEME_NAME, "Root", Box);
|
|
12
16
|
const OPEN_STREET_MAP_TILES = Object.freeze({
|
|
13
17
|
url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
|
14
18
|
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
|
@@ -47,21 +51,22 @@ function MapClicks({ onMapClick }) {
|
|
|
47
51
|
function DefaultPopupContent({ marker }) {
|
|
48
52
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
49
53
|
/* @__PURE__ */ jsx(Typography, { variant: "subtitle2", component: "p", children: marker.title }),
|
|
50
|
-
marker.description && /* @__PURE__ */ jsx(
|
|
54
|
+
marker.description && /* @__PURE__ */ jsx(MapPopupText, { variant: "body2", color: "text.secondary", component: "p", ownSx: { m: 0 }, children: marker.description })
|
|
51
55
|
] });
|
|
52
56
|
}
|
|
53
|
-
function MapView({
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
57
|
+
function MapView(props) {
|
|
58
|
+
const {
|
|
59
|
+
markers,
|
|
60
|
+
selectedId = null,
|
|
61
|
+
onSelect,
|
|
62
|
+
ariaLabel,
|
|
63
|
+
height = DEFAULT_HEIGHT_PIXELS,
|
|
64
|
+
tileLayer = OPEN_STREET_MAP_TILES,
|
|
65
|
+
renderPopup,
|
|
66
|
+
onMapClick,
|
|
67
|
+
children,
|
|
68
|
+
mapProps
|
|
69
|
+
} = usePieceProps(props, THEME_NAME);
|
|
65
70
|
const theme = useTheme();
|
|
66
71
|
const palette = paletteOf(theme);
|
|
67
72
|
const markerRefs = useRef(/* @__PURE__ */ new Map());
|
|
@@ -73,7 +78,7 @@ function MapView({
|
|
|
73
78
|
const color = (palette[marker.tone] ?? palette.primary).main;
|
|
74
79
|
return L.divIcon({ html: mapPinHtmlOf(color, isSelected), className: "", iconSize: [size, size], iconAnchor: [size / 2, size], popupAnchor: [0, -size] });
|
|
75
80
|
};
|
|
76
|
-
return /* @__PURE__ */ jsx(
|
|
81
|
+
return /* @__PURE__ */ jsx(MapRoot, { role: "region", "aria-label": ariaLabel, ownSx: (currentTheme) => ({
|
|
77
82
|
height,
|
|
78
83
|
borderRadius: 3,
|
|
79
84
|
overflow: "hidden",
|
package/dist/maps/MapView.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MapView.js","sources":["../../src/maps/MapView.jsx"],"sourcesContent":["// Un mapa con marcadores (@stackcraftmx/calcita/maps): Leaflet con los mosaicos de OpenStreetMap. Cada marcador es un\n// alfiler del color del tema (mapMarkers.js); el elegido va más grande, el mapa vuela a él y abre su globo. Al cambiar los\n// marcadores, el mapa se acomoda para que se vean todos.\n//\n// <MapView markers={[{id: 'gdl', position: [20.67, -103.35], title: 'Sucursal Guadalajara', tone: 'success'}]}\n// selectedId={selectedId} onSelect={setSelectedId} ariaLabel=\"Mapa de sucursales\" />\n//\n// En oscuro los mosaicos se oscurecen con un filtro (OpenStreetMap solo los da claros). Los mosaicos públicos de\n// OpenStreetMap son para poco tráfico y piden su crédito: para mucho uso, un proveedor propio en tileLayer.\n//\n// Se extiende sin tocar el framework: cualquier contenido en el globo (renderPopup: un estado, un botón, una foto, «Cómo\n// llegar»), capas propias de react-leaflet adentro (children: zonas de entrega, un radio), el clic en el mapa (onMapClick:\n// agregar un punto) y lo demás de MapContainer de Leaflet (mapProps).\n//\n// OJO, Next.js: Leaflet usa window al cargarse; en Next se importa con next/dynamic y ssr: false.\n//\n// Genérico del paquete: function (regla de la casa).\nimport 'leaflet/dist/leaflet.css';\nimport {useEffect, useMemo, useRef} from 'react';\nimport L from 'leaflet';\nimport {MapContainer, Marker, Popup, TileLayer, useMap, useMapEvents} from 'react-leaflet';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport {useTheme} from '@mui/material/styles';\n\nimport {MAP_PIN_SIZE, boundsOfMarkers, mapPinHtmlOf} from '@/maps/mapMarkers.js';\nimport {paletteOf} from '@/theme/components/paletteOf.js';\n\n/** Los mosaicos de OpenStreetMap con su crédito (lo pide su política de uso). */\nexport const OPEN_STREET_MAP_TILES = Object.freeze({\n url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',\n attribution: '© <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a>',\n});\n\n// México completo cuando no hay marcadores\nconst DEFAULT_CENTER = Object.freeze([23.6, -102.5]);\nconst DEFAULT_ZOOM = 5;\n// al volar a un marcador elegido, al menos este acercamiento\nconst SELECTED_ZOOM = 13;\n// al acomodar el mapa a los marcadores: el margen (px) y que no se acerque de más con uno solo\nconst FIT_PADDING_PIXELS = 48;\nconst FIT_MAX_ZOOM = 13;\nconst DEFAULT_HEIGHT_PIXELS = 420;\n\n/**\n * Acomoda el mapa para que se vean todos los marcadores cada vez que cambian.\n *\n * @param {{bounds: [[number, number], [number, number]]|null}} props\n */\nfunction FitToMarkers({bounds}) {\n const map = useMap();\n const boundsKey = JSON.stringify(bounds);\n useEffect(() => {\n if (bounds) {\n map.fitBounds(bounds, {padding: [FIT_PADDING_PIXELS, FIT_PADDING_PIXELS], maxZoom: FIT_MAX_ZOOM});\n }\n // OJO: depende del texto del recuadro y no del arreglo: el arreglo es nuevo en cada pintada y el mapa se movería solo\n }, [map, boundsKey]);\n return null;\n}\n\n/**\n * Vuela al marcador elegido y abre su globo.\n *\n * @param {{selectedMarker: object|undefined, markerRefs: object}} props\n */\nfunction FlyToSelected({selectedMarker, markerRefs}) {\n const map = useMap();\n useEffect(() => {\n if (!selectedMarker) {\n return;\n }\n map.flyTo(selectedMarker.position, Math.max(map.getZoom(), SELECTED_ZOOM));\n markerRefs.current.get(selectedMarker.id)?.openPopup();\n }, [map, selectedMarker, markerRefs]);\n return null;\n}\n\n/**\n * Avisa cada clic en el mapa (fuera de un marcador) con su posición.\n *\n * @param {{onMapClick: (position: [number, number]) => void}} props\n */\nfunction MapClicks({onMapClick}) {\n useMapEvents({click: (event) => onMapClick([event.latlng.lat, event.latlng.lng])});\n return null;\n}\n\n/**\n * Lo que dice el globo de un marcador cuando la pantalla no da el suyo: su título y su descripción.\n *\n * @param {{marker: {title: string, description?: string}}} props\n */\nfunction DefaultPopupContent({marker}) {\n return (\n <>\n <Typography variant=\"subtitle2\" component=\"p\">{marker.title}</Typography>\n {marker.description && <Typography variant=\"body2\" color=\"text.secondary\" component=\"p\" sx={{m: 0}}>{marker.description}</Typography>}\n </>\n );\n}\n\n/**\n * @param {object} props\n * @param {Array<{id: string, position: [number, number], title: string, description?: string, tone?: string} & Record<string, any>>} props.markers\n * tone: un color del tema (primary, success, warning, error, info…); por omisión primary\n * @param {string|null} [props.selectedId]\n * @param {(markerId: string) => void} [props.onSelect] al picar un marcador\n * @param {string} props.ariaLabel ya traducido: qué enseña el mapa\n * @param {number} [props.height] px\n * @param {{url: string, attribution: string}} [props.tileLayer] por omisión OpenStreetMap\n * @param {(marker: any) => import('react').ReactNode} [props.renderPopup] lo que dice el globo de un marcador (recibe el\n * marcador tal cual, con sus campos propios); por omisión su título y su descripción\n * @param {(position: [number, number]) => void} [props.onMapClick] al picar el mapa fuera de un marcador\n * @param {import('react').ReactNode} [props.children] capas propias de react-leaflet (Circle, Polygon, GeoJSON…)\n * @param {object} [props.mapProps] lo demás de MapContainer de react-leaflet (scrollWheelZoom, minZoom…)\n */\nexport default function MapView({\n markers, selectedId = null, onSelect, ariaLabel, height = DEFAULT_HEIGHT_PIXELS, tileLayer = OPEN_STREET_MAP_TILES, renderPopup, onMapClick,\n children, mapProps,\n}) {\n const theme = useTheme();\n const palette = paletteOf(theme);\n const markerRefs = useRef(new Map());\n const bounds = useMemo(() => boundsOfMarkers(markers), [markers]);\n const selectedMarker = markers.find((marker) => marker.id === selectedId);\n\n // el ícono de cada marcador: se arma de nuevo solo si cambia su color o si se elige\n const iconOf = (marker) => {\n const isSelected = marker.id === selectedId;\n const size = isSelected ? MAP_PIN_SIZE.selected : MAP_PIN_SIZE.normal;\n const color = (palette[marker.tone] ?? palette.primary).main;\n return L.divIcon({html: mapPinHtmlOf(color, isSelected), className: '', iconSize: [size, size], iconAnchor: [size / 2, size], popupAnchor: [0, -size]});\n };\n\n return (\n <Box role=\"region\" aria-label={ariaLabel} sx={(currentTheme) => ({\n height, borderRadius: 3, overflow: 'hidden', position: 'relative', zIndex: 0,\n '& .leaflet-container': {height: '100%', width: '100%', fontFamily: 'inherit', bgcolor: 'action.hover'},\n '& .leaflet-bar': {border: 0, borderRadius: '10px', overflow: 'hidden', boxShadow: currentTheme.shadows[2]},\n '& .leaflet-bar a': {bgcolor: 'background.paper', color: 'text.primary', borderBottomColor: 'divider'},\n '& .leaflet-popup-content-wrapper, & .leaflet-popup-tip': {bgcolor: 'background.paper', color: 'text.primary'},\n '& .leaflet-popup-content-wrapper': {borderRadius: '12px'},\n '& .leaflet-control-attribution': {bgcolor: 'background.paper', color: 'text.secondary', '& a': {color: 'inherit'}},\n // OpenStreetMap solo da mosaicos claros: en oscuro se invierten y se regresa el tono (el agua sigue azul)\n ...currentTheme.applyStyles('dark', {'& .leaflet-tile-pane': {filter: 'invert(1) hue-rotate(180deg) brightness(0.95) contrast(0.9)'}}),\n })}>\n <MapContainer center={markers[0]?.position ?? DEFAULT_CENTER} zoom={DEFAULT_ZOOM} scrollWheelZoom={false} {...mapProps}>\n <TileLayer url={tileLayer.url} attribution={tileLayer.attribution} />\n {onMapClick && <MapClicks onMapClick={onMapClick} />}\n {children}\n <FitToMarkers bounds={bounds} />\n <FlyToSelected selectedMarker={selectedMarker} markerRefs={markerRefs} />\n {markers.map((marker) => (\n <Marker key={marker.id} position={marker.position} icon={iconOf(marker)} title={marker.title} alt={marker.title}\n zIndexOffset={marker.id === selectedId ? 1000 : 0}\n ref={(leafletMarker) => (leafletMarker ? markerRefs.current.set(marker.id, leafletMarker) : markerRefs.current.delete(marker.id))}\n eventHandlers={{click: () => onSelect?.(marker.id)}}>\n <Popup>\n {renderPopup ? renderPopup(marker) : <DefaultPopupContent marker={marker} />}\n </Popup>\n </Marker>\n ))}\n </MapContainer>\n </Box>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;AA6BO,MAAM,wBAAwB,OAAO,OAAO;AAAA,EAC/C,KAAK;AAAA,EACL,aAAa;AACjB,CAAC;AAGD,MAAM,iBAAiB,OAAO,OAAO,CAAC,MAAM,MAAM,CAAC;AACnD,MAAM,eAAe;AAErB,MAAM,gBAAgB;AAEtB,MAAM,qBAAqB;AAC3B,MAAM,eAAe;AACrB,MAAM,wBAAwB;AAO9B,SAAS,aAAa,EAAC,UAAS;AAC5B,QAAM,MAAM,OAAA;AACZ,QAAM,YAAY,KAAK,UAAU,MAAM;AACvC,YAAU,MAAM;AACZ,QAAI,QAAQ;AACR,UAAI,UAAU,QAAQ,EAAC,SAAS,CAAC,oBAAoB,kBAAkB,GAAG,SAAS,cAAa;AAAA,IACpG;AAAA,EAEJ,GAAG,CAAC,KAAK,SAAS,CAAC;AACnB,SAAO;AACX;AAOA,SAAS,cAAc,EAAC,gBAAgB,cAAa;AACjD,QAAM,MAAM,OAAA;AACZ,YAAU,MAAM;AACZ,QAAI,CAAC,gBAAgB;AACjB;AAAA,IACJ;AACA,QAAI,MAAM,eAAe,UAAU,KAAK,IAAI,IAAI,WAAW,aAAa,CAAC;AACzE,eAAW,QAAQ,IAAI,eAAe,EAAE,GAAG,UAAA;AAAA,EAC/C,GAAG,CAAC,KAAK,gBAAgB,UAAU,CAAC;AACpC,SAAO;AACX;AAOA,SAAS,UAAU,EAAC,cAAa;AAC7B,eAAa,EAAC,OAAO,CAAC,UAAU,WAAW,CAAC,MAAM,OAAO,KAAK,MAAM,OAAO,GAAG,CAAC,GAAE;AACjF,SAAO;AACX;AAOA,SAAS,oBAAoB,EAAC,UAAS;AACnC,SACI,qBAAA,UAAA,EACI,UAAA;AAAA,IAAA,oBAAC,cAAW,SAAQ,aAAY,WAAU,KAAK,iBAAO,OAAM;AAAA,IAC3D,OAAO,eAAe,oBAAC,YAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,WAAU,KAAI,IAAI,EAAC,GAAG,EAAA,GAAK,iBAAO,YAAA,CAAY;AAAA,EAAA,GAC5H;AAER;AAiBA,SAAwB,QAAQ;AAAA,EAC5B;AAAA,EAAS,aAAa;AAAA,EAAM;AAAA,EAAU;AAAA,EAAW,SAAS;AAAA,EAAuB,YAAY;AAAA,EAAuB;AAAA,EAAa;AAAA,EACjI;AAAA,EAAU;AACd,GAAG;AACC,QAAM,QAAQ,SAAA;AACd,QAAM,UAAU,UAAU,KAAK;AAC/B,QAAM,aAAa,OAAO,oBAAI,KAAK;AACnC,QAAM,SAAS,QAAQ,MAAM,gBAAgB,OAAO,GAAG,CAAC,OAAO,CAAC;AAChE,QAAM,iBAAiB,QAAQ,KAAK,CAAC,WAAW,OAAO,OAAO,UAAU;AAGxE,QAAM,SAAS,CAAC,WAAW;AACvB,UAAM,aAAa,OAAO,OAAO;AACjC,UAAM,OAAO,aAAa,aAAa,WAAW,aAAa;AAC/D,UAAM,SAAS,QAAQ,OAAO,IAAI,KAAK,QAAQ,SAAS;AACxD,WAAO,EAAE,QAAQ,EAAC,MAAM,aAAa,OAAO,UAAU,GAAG,WAAW,IAAI,UAAU,CAAC,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,GAAG,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,EAAA,CAAE;AAAA,EAC1J;AAEA,SACI,oBAAC,OAAI,MAAK,UAAS,cAAY,WAAW,IAAI,CAAC,kBAAkB;AAAA,IAC7D;AAAA,IAAQ,cAAc;AAAA,IAAG,UAAU;AAAA,IAAU,UAAU;AAAA,IAAY,QAAQ;AAAA,IAC3E,wBAAwB,EAAC,QAAQ,QAAQ,OAAO,QAAQ,YAAY,WAAW,SAAS,eAAA;AAAA,IACxF,kBAAkB,EAAC,QAAQ,GAAG,cAAc,QAAQ,UAAU,UAAU,WAAW,aAAa,QAAQ,CAAC,EAAA;AAAA,IACzG,oBAAoB,EAAC,SAAS,oBAAoB,OAAO,gBAAgB,mBAAmB,UAAA;AAAA,IAC5F,0DAA0D,EAAC,SAAS,oBAAoB,OAAO,eAAA;AAAA,IAC/F,oCAAoC,EAAC,cAAc,OAAA;AAAA,IACnD,kCAAkC,EAAC,SAAS,oBAAoB,OAAO,kBAAkB,OAAO,EAAC,OAAO,YAAS;AAAA;AAAA,IAEjH,GAAG,aAAa,YAAY,QAAQ,EAAC,wBAAwB,EAAC,QAAQ,gEAA6D,CAAE;AAAA,EAAA,IAErI,UAAA,qBAAC,cAAA,EAAa,QAAQ,QAAQ,CAAC,GAAG,YAAY,gBAAgB,MAAM,cAAc,iBAAiB,OAAQ,GAAG,UAC1G,UAAA;AAAA,IAAA,oBAAC,aAAU,KAAK,UAAU,KAAK,aAAa,UAAU,aAAa;AAAA,IAClE,cAAc,oBAAC,WAAA,EAAU,WAAA,CAAwB;AAAA,IACjD;AAAA,IACD,oBAAC,gBAAa,QAAgB;AAAA,IAC9B,oBAAC,eAAA,EAAc,gBAAgC,WAAA,CAAwB;AAAA,IACtE,QAAQ,IAAI,CAAC,WACV;AAAA,MAAC;AAAA,MAAA;AAAA,QAAuB,UAAU,OAAO;AAAA,QAAU,MAAM,OAAO,MAAM;AAAA,QAAG,OAAO,OAAO;AAAA,QAAO,KAAK,OAAO;AAAA,QAClG,cAAc,OAAO,OAAO,aAAa,MAAO;AAAA,QAChD,KAAK,CAAC,kBAAmB,gBAAgB,WAAW,QAAQ,IAAI,OAAO,IAAI,aAAa,IAAI,WAAW,QAAQ,OAAO,OAAO,EAAE;AAAA,QAC/H,eAAe,EAAC,OAAO,MAAM,WAAW,OAAO,EAAE,EAAA;AAAA,QACrD,UAAA,oBAAC,SACI,UAAA,cAAc,YAAY,MAAM,IAAI,oBAAC,qBAAA,EAAoB,OAAA,CAAgB,EAAA,CAC9E;AAAA,MAAA;AAAA,MANS,OAAO;AAAA,IAAA,CAQvB;AAAA,EAAA,EAAA,CACL,EAAA,CACJ;AAER;"}
|
|
1
|
+
{"version":3,"file":"MapView.js","sources":["../../src/maps/MapView.jsx"],"sourcesContent":["// Un mapa con marcadores (@stackcraftmx/calcita/maps): Leaflet con los mosaicos de OpenStreetMap. Cada marcador es un\n// alfiler del color del tema (mapMarkers.js); el elegido va más grande, el mapa vuela a él y abre su globo. Al cambiar los\n// marcadores, el mapa se acomoda para que se vean todos.\n//\n// <MapView markers={[{id: 'gdl', position: [20.67, -103.35], title: 'Sucursal Guadalajara', tone: 'success'}]}\n// selectedId={selectedId} onSelect={setSelectedId} ariaLabel=\"Mapa de sucursales\" />\n//\n// En oscuro los mosaicos se oscurecen con un filtro (OpenStreetMap solo los da claros). Los mosaicos públicos de\n// OpenStreetMap son para poco tráfico y piden su crédito: para mucho uso, un proveedor propio en tileLayer.\n//\n// Se extiende sin tocar el framework: cualquier contenido en el globo (renderPopup: un estado, un botón, una foto, «Cómo\n// llegar»), capas propias de react-leaflet adentro (children: zonas de entrega, un radio), el clic en el mapa (onMapClick:\n// agregar un punto) y lo demás de MapContainer de Leaflet (mapProps).\n//\n// OJO, Next.js: Leaflet usa window al cargarse; en Next se importa con next/dynamic y ssr: false.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaMapView con defaultProps y\n// styleOverrides de sus partes: popupText, root.\n//\n// Genérico del paquete: function (regla de la casa).\nimport 'leaflet/dist/leaflet.css';\nimport {useEffect, useMemo, useRef} from 'react';\nimport L from 'leaflet';\nimport {MapContainer, Marker, Popup, TileLayer, useMap, useMapEvents} from 'react-leaflet';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport {useTheme} from '@mui/material/styles';\n\nimport {MAP_PIN_SIZE, boundsOfMarkers, mapPinHtmlOf} from '@/maps/mapMarkers.js';\nimport {paletteOf} from '@/theme/components/paletteOf.js';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaMapView)\nconst THEME_NAME = 'CalcitaMapView';\nconst MapPopupText = piecePart(THEME_NAME, 'PopupText', Typography);\nconst MapRoot = piecePart(THEME_NAME, 'Root', Box);\n\n/** Los mosaicos de OpenStreetMap con su crédito (lo pide su política de uso). */\nexport const OPEN_STREET_MAP_TILES = Object.freeze({\n url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',\n attribution: '© <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a>',\n});\n\n// México completo cuando no hay marcadores\nconst DEFAULT_CENTER = Object.freeze([23.6, -102.5]);\nconst DEFAULT_ZOOM = 5;\n// al volar a un marcador elegido, al menos este acercamiento\nconst SELECTED_ZOOM = 13;\n// al acomodar el mapa a los marcadores: el margen (px) y que no se acerque de más con uno solo\nconst FIT_PADDING_PIXELS = 48;\nconst FIT_MAX_ZOOM = 13;\nconst DEFAULT_HEIGHT_PIXELS = 420;\n\n/**\n * Acomoda el mapa para que se vean todos los marcadores cada vez que cambian.\n *\n * @param {{bounds: [[number, number], [number, number]]|null}} props\n */\nfunction FitToMarkers({bounds}) {\n const map = useMap();\n const boundsKey = JSON.stringify(bounds);\n useEffect(() => {\n if (bounds) {\n map.fitBounds(bounds, {padding: [FIT_PADDING_PIXELS, FIT_PADDING_PIXELS], maxZoom: FIT_MAX_ZOOM});\n }\n // OJO: depende del texto del recuadro y no del arreglo: el arreglo es nuevo en cada pintada y el mapa se movería solo\n }, [map, boundsKey]);\n return null;\n}\n\n/**\n * Vuela al marcador elegido y abre su globo.\n *\n * @param {{selectedMarker: object|undefined, markerRefs: object}} props\n */\nfunction FlyToSelected({selectedMarker, markerRefs}) {\n const map = useMap();\n useEffect(() => {\n if (!selectedMarker) {\n return;\n }\n map.flyTo(selectedMarker.position, Math.max(map.getZoom(), SELECTED_ZOOM));\n markerRefs.current.get(selectedMarker.id)?.openPopup();\n }, [map, selectedMarker, markerRefs]);\n return null;\n}\n\n/**\n * Avisa cada clic en el mapa (fuera de un marcador) con su posición.\n *\n * @param {{onMapClick: (position: [number, number]) => void}} props\n */\nfunction MapClicks({onMapClick}) {\n useMapEvents({click: (event) => onMapClick([event.latlng.lat, event.latlng.lng])});\n return null;\n}\n\n/**\n * Lo que dice el globo de un marcador cuando la pantalla no da el suyo: su título y su descripción.\n *\n * @param {{marker: {title: string, description?: string}}} props\n */\nfunction DefaultPopupContent({marker}) {\n return (\n <>\n <Typography variant=\"subtitle2\" component=\"p\">{marker.title}</Typography>\n {marker.description && <MapPopupText variant=\"body2\" color=\"text.secondary\" component=\"p\" ownSx={{m: 0}}>{marker.description}</MapPopupText>}\n </>\n );\n}\n\n/**\n * @param {object} props\n * @param {Array<{id: string, position: [number, number], title: string, description?: string, tone?: string} & Record<string, any>>} props.markers\n * tone: un color del tema (primary, success, warning, error, info…); por omisión primary\n * @param {string|null} [props.selectedId]\n * @param {(markerId: string) => void} [props.onSelect] al picar un marcador\n * @param {string} props.ariaLabel ya traducido: qué enseña el mapa\n * @param {number} [props.height] px\n * @param {{url: string, attribution: string}} [props.tileLayer] por omisión OpenStreetMap\n * @param {(marker: any) => import('react').ReactNode} [props.renderPopup] lo que dice el globo de un marcador (recibe el\n * marcador tal cual, con sus campos propios); por omisión su título y su descripción\n * @param {(position: [number, number]) => void} [props.onMapClick] al picar el mapa fuera de un marcador\n * @param {import('react').ReactNode} [props.children] capas propias de react-leaflet (Circle, Polygon, GeoJSON…)\n * @param {object} [props.mapProps] lo demás de MapContainer de react-leaflet (scrollWheelZoom, minZoom…)\n */\nexport default function MapView(props) {\n // lo que el proyecto puso en su tema (components.CalcitaMapView.defaultProps) y encima lo que llega aquí\n const {\n markers, selectedId = null, onSelect, ariaLabel, height = DEFAULT_HEIGHT_PIXELS, tileLayer = OPEN_STREET_MAP_TILES, renderPopup, onMapClick,\n children, mapProps,\n} = usePieceProps(props, THEME_NAME);\n const theme = useTheme();\n const palette = paletteOf(theme);\n const markerRefs = useRef(new Map());\n const bounds = useMemo(() => boundsOfMarkers(markers), [markers]);\n const selectedMarker = markers.find((marker) => marker.id === selectedId);\n\n // el ícono de cada marcador: se arma de nuevo solo si cambia su color o si se elige\n const iconOf = (marker) => {\n const isSelected = marker.id === selectedId;\n const size = isSelected ? MAP_PIN_SIZE.selected : MAP_PIN_SIZE.normal;\n const color = (palette[marker.tone] ?? palette.primary).main;\n return L.divIcon({html: mapPinHtmlOf(color, isSelected), className: '', iconSize: [size, size], iconAnchor: [size / 2, size], popupAnchor: [0, -size]});\n };\n\n return (\n <MapRoot role=\"region\" aria-label={ariaLabel} ownSx={(currentTheme) => ({\n height, borderRadius: 3, overflow: 'hidden', position: 'relative', zIndex: 0,\n '& .leaflet-container': {height: '100%', width: '100%', fontFamily: 'inherit', bgcolor: 'action.hover'},\n '& .leaflet-bar': {border: 0, borderRadius: '10px', overflow: 'hidden', boxShadow: currentTheme.shadows[2]},\n '& .leaflet-bar a': {bgcolor: 'background.paper', color: 'text.primary', borderBottomColor: 'divider'},\n '& .leaflet-popup-content-wrapper, & .leaflet-popup-tip': {bgcolor: 'background.paper', color: 'text.primary'},\n '& .leaflet-popup-content-wrapper': {borderRadius: '12px'},\n '& .leaflet-control-attribution': {bgcolor: 'background.paper', color: 'text.secondary', '& a': {color: 'inherit'}},\n // OpenStreetMap solo da mosaicos claros: en oscuro se invierten y se regresa el tono (el agua sigue azul)\n ...currentTheme.applyStyles('dark', {'& .leaflet-tile-pane': {filter: 'invert(1) hue-rotate(180deg) brightness(0.95) contrast(0.9)'}}),\n })}>\n <MapContainer center={markers[0]?.position ?? DEFAULT_CENTER} zoom={DEFAULT_ZOOM} scrollWheelZoom={false} {...mapProps}>\n <TileLayer url={tileLayer.url} attribution={tileLayer.attribution} />\n {onMapClick && <MapClicks onMapClick={onMapClick} />}\n {children}\n <FitToMarkers bounds={bounds} />\n <FlyToSelected selectedMarker={selectedMarker} markerRefs={markerRefs} />\n {markers.map((marker) => (\n <Marker key={marker.id} position={marker.position} icon={iconOf(marker)} title={marker.title} alt={marker.title}\n zIndexOffset={marker.id === selectedId ? 1000 : 0}\n ref={(leafletMarker) => (leafletMarker ? markerRefs.current.set(marker.id, leafletMarker) : markerRefs.current.delete(marker.id))}\n eventHandlers={{click: () => onSelect?.(marker.id)}}>\n <Popup>\n {renderPopup ? renderPopup(marker) : <DefaultPopupContent marker={marker} />}\n </Popup>\n </Marker>\n ))}\n </MapContainer>\n </MapRoot>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -9,6 +9,9 @@ import { INSTALL_VARIANT } from "./installInstructions.js";
|
|
|
9
9
|
import InstallInstructionsDialog from "./InstallInstructionsDialog.js";
|
|
10
10
|
import { useInstallPrompt } from "./useInstallPrompt.js";
|
|
11
11
|
import ComponentTexts from "../toolkit/ComponentTexts.js";
|
|
12
|
+
import { piecePart } from "../theme/themePieces.js";
|
|
13
|
+
const THEME_NAME = "CalcitaInstallAppSetting";
|
|
14
|
+
const InstallRoot = piecePart(THEME_NAME, "Root", Box);
|
|
12
15
|
function InstallAppSetting({ texts } = {}) {
|
|
13
16
|
const { t } = useToolkitTranslation("common", texts);
|
|
14
17
|
const { variant, promptInstall } = useInstallPrompt();
|
|
@@ -23,7 +26,7 @@ function InstallAppSetting({ texts } = {}) {
|
|
|
23
26
|
setStepsOpen(true);
|
|
24
27
|
}
|
|
25
28
|
};
|
|
26
|
-
return /* @__PURE__ */ jsx(ComponentTexts, { namespace: "common", texts, children: /* @__PURE__ */ jsxs(
|
|
29
|
+
return /* @__PURE__ */ jsx(ComponentTexts, { namespace: "common", texts, children: /* @__PURE__ */ jsxs(InstallRoot, { ownSx: { px: 1, py: 0.5 }, children: [
|
|
27
30
|
/* @__PURE__ */ jsx(Button, { fullWidth: true, variant: "outlined", startIcon: /* @__PURE__ */ jsx(InstallMobileRoundedIcon, {}), onClick: handleClick, children: t("install.menuLabel") }),
|
|
28
31
|
/* @__PURE__ */ jsx(InstallInstructionsDialog, { variant, open: stepsOpen, onClose: () => setStepsOpen(false) })
|
|
29
32
|
] }) });
|