@open-mercato/ui 0.4.2-canary-c02407ff85
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/build.mjs +62 -0
- package/dist/backend/AppShell.js +902 -0
- package/dist/backend/AppShell.js.map +7 -0
- package/dist/backend/ConfirmDialog.js +17 -0
- package/dist/backend/ConfirmDialog.js.map +7 -0
- package/dist/backend/ContextHelp.js +31 -0
- package/dist/backend/ContextHelp.js.map +7 -0
- package/dist/backend/CrudForm.js +2028 -0
- package/dist/backend/CrudForm.js.map +7 -0
- package/dist/backend/DataTable.js +1363 -0
- package/dist/backend/DataTable.js.map +7 -0
- package/dist/backend/EmptyState.js +52 -0
- package/dist/backend/EmptyState.js.map +7 -0
- package/dist/backend/FilterBar.js +140 -0
- package/dist/backend/FilterBar.js.map +7 -0
- package/dist/backend/FilterOverlay.js +279 -0
- package/dist/backend/FilterOverlay.js.map +7 -0
- package/dist/backend/FlashMessages.js +66 -0
- package/dist/backend/FlashMessages.js.map +7 -0
- package/dist/backend/JsonBuilder.js +322 -0
- package/dist/backend/JsonBuilder.js.map +7 -0
- package/dist/backend/JsonDisplay.js +203 -0
- package/dist/backend/JsonDisplay.js.map +7 -0
- package/dist/backend/Page.js +27 -0
- package/dist/backend/Page.js.map +7 -0
- package/dist/backend/PerspectiveSidebar.js +282 -0
- package/dist/backend/PerspectiveSidebar.js.map +7 -0
- package/dist/backend/RowActions.js +148 -0
- package/dist/backend/RowActions.js.map +7 -0
- package/dist/backend/TruncatedCell.js +92 -0
- package/dist/backend/TruncatedCell.js.map +7 -0
- package/dist/backend/UserMenu.js +107 -0
- package/dist/backend/UserMenu.js.map +7 -0
- package/dist/backend/ValueIcons.js +34 -0
- package/dist/backend/ValueIcons.js.map +7 -0
- package/dist/backend/custom-fields/FieldDefinitionsEditor.js +1264 -0
- package/dist/backend/custom-fields/FieldDefinitionsEditor.js.map +7 -0
- package/dist/backend/custom-fields/FieldDefinitionsManager.js +332 -0
- package/dist/backend/custom-fields/FieldDefinitionsManager.js.map +7 -0
- package/dist/backend/dashboard/DashboardScreen.js +578 -0
- package/dist/backend/dashboard/DashboardScreen.js.map +7 -0
- package/dist/backend/dashboard/index.js +5 -0
- package/dist/backend/dashboard/index.js.map +7 -0
- package/dist/backend/dashboard/widgetRegistry.js +55 -0
- package/dist/backend/dashboard/widgetRegistry.js.map +7 -0
- package/dist/backend/detail/ActivitiesSection.js +962 -0
- package/dist/backend/detail/ActivitiesSection.js.map +7 -0
- package/dist/backend/detail/AddressEditor.js +413 -0
- package/dist/backend/detail/AddressEditor.js.map +7 -0
- package/dist/backend/detail/AddressTiles.js +437 -0
- package/dist/backend/detail/AddressTiles.js.map +7 -0
- package/dist/backend/detail/AddressesSection.js +264 -0
- package/dist/backend/detail/AddressesSection.js.map +7 -0
- package/dist/backend/detail/AttachmentDeleteDialog.js +41 -0
- package/dist/backend/detail/AttachmentDeleteDialog.js.map +7 -0
- package/dist/backend/detail/AttachmentMetadataDialog.js +517 -0
- package/dist/backend/detail/AttachmentMetadataDialog.js.map +7 -0
- package/dist/backend/detail/AttachmentsSection.js +367 -0
- package/dist/backend/detail/AttachmentsSection.js.map +7 -0
- package/dist/backend/detail/CustomDataSection.js +433 -0
- package/dist/backend/detail/CustomDataSection.js.map +7 -0
- package/dist/backend/detail/DetailFieldsSection.js +75 -0
- package/dist/backend/detail/DetailFieldsSection.js.map +7 -0
- package/dist/backend/detail/ErrorMessage.js +28 -0
- package/dist/backend/detail/ErrorMessage.js.map +7 -0
- package/dist/backend/detail/InlineEditors.js +681 -0
- package/dist/backend/detail/InlineEditors.js.map +7 -0
- package/dist/backend/detail/LoadingMessage.js +14 -0
- package/dist/backend/detail/LoadingMessage.js.map +7 -0
- package/dist/backend/detail/NotesSection.js +1032 -0
- package/dist/backend/detail/NotesSection.js.map +7 -0
- package/dist/backend/detail/TabEmptyState.js +25 -0
- package/dist/backend/detail/TabEmptyState.js.map +7 -0
- package/dist/backend/detail/TagsSection.js +254 -0
- package/dist/backend/detail/TagsSection.js.map +7 -0
- package/dist/backend/detail/addressFormat.js +77 -0
- package/dist/backend/detail/addressFormat.js.map +7 -0
- package/dist/backend/detail/index.js +34 -0
- package/dist/backend/detail/index.js.map +7 -0
- package/dist/backend/fields/registry.generated.js +8 -0
- package/dist/backend/fields/registry.generated.js.map +7 -0
- package/dist/backend/fields/registry.js +29 -0
- package/dist/backend/fields/registry.js.map +7 -0
- package/dist/backend/indexes/PartialIndexBanner.js +58 -0
- package/dist/backend/indexes/PartialIndexBanner.js.map +7 -0
- package/dist/backend/indexes/store.js +62 -0
- package/dist/backend/indexes/store.js.map +7 -0
- package/dist/backend/injection/InjectionSpot.js +179 -0
- package/dist/backend/injection/InjectionSpot.js.map +7 -0
- package/dist/backend/injection/PageInjectionBoundary.js +26 -0
- package/dist/backend/injection/PageInjectionBoundary.js.map +7 -0
- package/dist/backend/injection/helpers.js +26 -0
- package/dist/backend/injection/helpers.js.map +7 -0
- package/dist/backend/injection/widgetRegistry.js +55 -0
- package/dist/backend/injection/widgetRegistry.js.map +7 -0
- package/dist/backend/inputs/ComboboxInput.js +225 -0
- package/dist/backend/inputs/ComboboxInput.js.map +7 -0
- package/dist/backend/inputs/LookupSelect.js +191 -0
- package/dist/backend/inputs/LookupSelect.js.map +7 -0
- package/dist/backend/inputs/PhoneNumberField.js +100 -0
- package/dist/backend/inputs/PhoneNumberField.js.map +7 -0
- package/dist/backend/inputs/SwitchableMarkdownInput.js +92 -0
- package/dist/backend/inputs/SwitchableMarkdownInput.js.map +7 -0
- package/dist/backend/inputs/TagsInput.js +222 -0
- package/dist/backend/inputs/TagsInput.js.map +7 -0
- package/dist/backend/inputs/index.js +6 -0
- package/dist/backend/inputs/index.js.map +7 -0
- package/dist/backend/operations/LastOperationBanner.js +80 -0
- package/dist/backend/operations/LastOperationBanner.js.map +7 -0
- package/dist/backend/operations/store.js +183 -0
- package/dist/backend/operations/store.js.map +7 -0
- package/dist/backend/schedule/ScheduleAgenda.js +107 -0
- package/dist/backend/schedule/ScheduleAgenda.js.map +7 -0
- package/dist/backend/schedule/ScheduleGrid.js +107 -0
- package/dist/backend/schedule/ScheduleGrid.js.map +7 -0
- package/dist/backend/schedule/ScheduleToolbar.js +166 -0
- package/dist/backend/schedule/ScheduleToolbar.js.map +7 -0
- package/dist/backend/schedule/ScheduleView.js +165 -0
- package/dist/backend/schedule/ScheduleView.js.map +7 -0
- package/dist/backend/schedule/index.js +6 -0
- package/dist/backend/schedule/index.js.map +7 -0
- package/dist/backend/schedule/recurrence.js +83 -0
- package/dist/backend/schedule/recurrence.js.map +7 -0
- package/dist/backend/schedule/types.js +1 -0
- package/dist/backend/schedule/types.js.map +7 -0
- package/dist/backend/upgrades/UpgradeActionBanner.js +91 -0
- package/dist/backend/upgrades/UpgradeActionBanner.js.map +7 -0
- package/dist/backend/utils/api.js +127 -0
- package/dist/backend/utils/api.js.map +7 -0
- package/dist/backend/utils/apiCall.js +48 -0
- package/dist/backend/utils/apiCall.js.map +7 -0
- package/dist/backend/utils/crud.js +126 -0
- package/dist/backend/utils/crud.js.map +7 -0
- package/dist/backend/utils/customFieldColumns.js +56 -0
- package/dist/backend/utils/customFieldColumns.js.map +7 -0
- package/dist/backend/utils/customFieldDefs.js +143 -0
- package/dist/backend/utils/customFieldDefs.js.map +7 -0
- package/dist/backend/utils/customFieldFilters.js +126 -0
- package/dist/backend/utils/customFieldFilters.js.map +7 -0
- package/dist/backend/utils/customFieldForms.js +162 -0
- package/dist/backend/utils/customFieldForms.js.map +7 -0
- package/dist/backend/utils/customFieldValues.js +26 -0
- package/dist/backend/utils/customFieldValues.js.map +7 -0
- package/dist/backend/utils/flash.js +16 -0
- package/dist/backend/utils/flash.js.map +7 -0
- package/dist/backend/utils/nav.js +185 -0
- package/dist/backend/utils/nav.js.map +7 -0
- package/dist/backend/utils/serverErrors.js +230 -0
- package/dist/backend/utils/serverErrors.js.map +7 -0
- package/dist/frontend/AuthFooter.js +23 -0
- package/dist/frontend/AuthFooter.js.map +7 -0
- package/dist/frontend/LanguageSwitcher.js +57 -0
- package/dist/frontend/LanguageSwitcher.js.map +7 -0
- package/dist/frontend/Layout.js +14 -0
- package/dist/frontend/Layout.js.map +7 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +7 -0
- package/dist/primitives/DataLoader.js +67 -0
- package/dist/primitives/DataLoader.js.map +7 -0
- package/dist/primitives/ErrorNotice.js +20 -0
- package/dist/primitives/ErrorNotice.js.map +7 -0
- package/dist/primitives/alert.js +38 -0
- package/dist/primitives/alert.js.map +7 -0
- package/dist/primitives/badge.js +28 -0
- package/dist/primitives/badge.js.map +7 -0
- package/dist/primitives/button.js +44 -0
- package/dist/primitives/button.js.map +7 -0
- package/dist/primitives/card.js +91 -0
- package/dist/primitives/card.js.map +7 -0
- package/dist/primitives/checkbox.js +28 -0
- package/dist/primitives/checkbox.js.map +7 -0
- package/dist/primitives/dialog.js +90 -0
- package/dist/primitives/dialog.js.map +7 -0
- package/dist/primitives/input.js +22 -0
- package/dist/primitives/input.js.map +7 -0
- package/dist/primitives/label.js +21 -0
- package/dist/primitives/label.js.map +7 -0
- package/dist/primitives/separator.js +9 -0
- package/dist/primitives/separator.js.map +7 -0
- package/dist/primitives/spinner.js +24 -0
- package/dist/primitives/spinner.js.map +7 -0
- package/dist/primitives/switch.js +80 -0
- package/dist/primitives/switch.js.map +7 -0
- package/dist/primitives/table.js +29 -0
- package/dist/primitives/table.js.map +7 -0
- package/dist/primitives/tabs.js +87 -0
- package/dist/primitives/tabs.js.map +7 -0
- package/dist/primitives/textarea.js +21 -0
- package/dist/primitives/textarea.js.map +7 -0
- package/dist/primitives/tooltip.js +60 -0
- package/dist/primitives/tooltip.js.map +7 -0
- package/dist/theme/QueryProvider.js +44 -0
- package/dist/theme/QueryProvider.js.map +7 -0
- package/dist/theme/ThemeProvider.js +95 -0
- package/dist/theme/ThemeProvider.js.map +7 -0
- package/dist/theme/ThemeToggle.js +88 -0
- package/dist/theme/ThemeToggle.js.map +7 -0
- package/dist/theme/index.js +10 -0
- package/dist/theme/index.js.map +7 -0
- package/dist/types/react-big-calendar.d.js +1 -0
- package/dist/types/react-big-calendar.d.js.map +7 -0
- package/jest.config.cjs +23 -0
- package/jest.setup.ts +55 -0
- package/package.json +105 -0
- package/src/backend/AppShell.tsx +1096 -0
- package/src/backend/ConfirmDialog.tsx +19 -0
- package/src/backend/ContextHelp.tsx +38 -0
- package/src/backend/CrudForm.tsx +2503 -0
- package/src/backend/DataTable.tsx +1730 -0
- package/src/backend/EmptyState.tsx +65 -0
- package/src/backend/FilterBar.tsx +161 -0
- package/src/backend/FilterOverlay.tsx +328 -0
- package/src/backend/FlashMessages.tsx +82 -0
- package/src/backend/JsonBuilder.tsx +362 -0
- package/src/backend/JsonDisplay.tsx +254 -0
- package/src/backend/Page.tsx +30 -0
- package/src/backend/PerspectiveSidebar.tsx +337 -0
- package/src/backend/RowActions.tsx +151 -0
- package/src/backend/TruncatedCell.tsx +133 -0
- package/src/backend/UserMenu.tsx +118 -0
- package/src/backend/ValueIcons.tsx +48 -0
- package/src/backend/__tests__/AppShell.test.tsx +115 -0
- package/src/backend/__tests__/CrudForm.render.test.tsx +30 -0
- package/src/backend/__tests__/DataTable.render.test.tsx +48 -0
- package/src/backend/__tests__/custom-field-filters.test.ts +72 -0
- package/src/backend/__tests__/custom-field-forms.test.ts +54 -0
- package/src/backend/__tests__/serverErrors.test.ts +83 -0
- package/src/backend/custom-fields/FieldDefinitionsEditor.tsx +1292 -0
- package/src/backend/custom-fields/FieldDefinitionsManager.tsx +381 -0
- package/src/backend/dashboard/DashboardScreen.tsx +684 -0
- package/src/backend/dashboard/__tests__/DashboardScreen.test.tsx +112 -0
- package/src/backend/dashboard/index.ts +1 -0
- package/src/backend/dashboard/widgetRegistry.ts +68 -0
- package/src/backend/detail/ActivitiesSection.tsx +1284 -0
- package/src/backend/detail/AddressEditor.tsx +472 -0
- package/src/backend/detail/AddressTiles.tsx +587 -0
- package/src/backend/detail/AddressesSection.tsx +346 -0
- package/src/backend/detail/AttachmentDeleteDialog.tsx +56 -0
- package/src/backend/detail/AttachmentMetadataDialog.tsx +672 -0
- package/src/backend/detail/AttachmentsSection.tsx +414 -0
- package/src/backend/detail/CustomDataSection.tsx +530 -0
- package/src/backend/detail/DetailFieldsSection.tsx +147 -0
- package/src/backend/detail/ErrorMessage.tsx +32 -0
- package/src/backend/detail/InlineEditors.tsx +877 -0
- package/src/backend/detail/LoadingMessage.tsx +14 -0
- package/src/backend/detail/NotesSection.tsx +1275 -0
- package/src/backend/detail/TabEmptyState.tsx +48 -0
- package/src/backend/detail/TagsSection.tsx +314 -0
- package/src/backend/detail/addressFormat.tsx +121 -0
- package/src/backend/detail/index.ts +44 -0
- package/src/backend/fields/registry.generated.ts +8 -0
- package/src/backend/fields/registry.ts +38 -0
- package/src/backend/indexes/PartialIndexBanner.tsx +68 -0
- package/src/backend/indexes/store.ts +88 -0
- package/src/backend/injection/InjectionSpot.tsx +236 -0
- package/src/backend/injection/PageInjectionBoundary.tsx +31 -0
- package/src/backend/injection/helpers.ts +35 -0
- package/src/backend/injection/widgetRegistry.ts +68 -0
- package/src/backend/inputs/ComboboxInput.tsx +269 -0
- package/src/backend/inputs/LookupSelect.tsx +247 -0
- package/src/backend/inputs/PhoneNumberField.tsx +129 -0
- package/src/backend/inputs/SwitchableMarkdownInput.tsx +128 -0
- package/src/backend/inputs/TagsInput.tsx +259 -0
- package/src/backend/inputs/index.ts +5 -0
- package/src/backend/operations/LastOperationBanner.tsx +85 -0
- package/src/backend/operations/__tests__/LastOperationBanner.test.tsx +99 -0
- package/src/backend/operations/store.ts +230 -0
- package/src/backend/schedule/ScheduleAgenda.tsx +136 -0
- package/src/backend/schedule/ScheduleGrid.tsx +136 -0
- package/src/backend/schedule/ScheduleToolbar.tsx +178 -0
- package/src/backend/schedule/ScheduleView.tsx +198 -0
- package/src/backend/schedule/index.ts +5 -0
- package/src/backend/schedule/recurrence.ts +99 -0
- package/src/backend/schedule/types.ts +26 -0
- package/src/backend/upgrades/UpgradeActionBanner.tsx +128 -0
- package/src/backend/utils/__tests__/apiCall.test.ts +109 -0
- package/src/backend/utils/__tests__/crud.test.ts +87 -0
- package/src/backend/utils/__tests__/customFieldDefs.test.ts +25 -0
- package/src/backend/utils/__tests__/customFieldValues.test.ts +35 -0
- package/src/backend/utils/api.ts +149 -0
- package/src/backend/utils/apiCall.ts +96 -0
- package/src/backend/utils/crud.ts +174 -0
- package/src/backend/utils/customFieldColumns.ts +71 -0
- package/src/backend/utils/customFieldDefs.ts +245 -0
- package/src/backend/utils/customFieldFilters.ts +145 -0
- package/src/backend/utils/customFieldForms.ts +196 -0
- package/src/backend/utils/customFieldValues.ts +41 -0
- package/src/backend/utils/flash.ts +17 -0
- package/src/backend/utils/nav.ts +238 -0
- package/src/backend/utils/serverErrors.ts +302 -0
- package/src/frontend/AuthFooter.tsx +29 -0
- package/src/frontend/LanguageSwitcher.tsx +66 -0
- package/src/frontend/Layout.tsx +13 -0
- package/src/index.ts +32 -0
- package/src/primitives/DataLoader.tsx +92 -0
- package/src/primitives/ErrorNotice.tsx +26 -0
- package/src/primitives/alert.tsx +52 -0
- package/src/primitives/badge.tsx +31 -0
- package/src/primitives/button.tsx +47 -0
- package/src/primitives/card.tsx +92 -0
- package/src/primitives/checkbox.tsx +28 -0
- package/src/primitives/dialog.tsx +110 -0
- package/src/primitives/input.tsx +20 -0
- package/src/primitives/label.tsx +18 -0
- package/src/primitives/separator.tsx +7 -0
- package/src/primitives/spinner.tsx +27 -0
- package/src/primitives/switch.tsx +86 -0
- package/src/primitives/table.tsx +27 -0
- package/src/primitives/tabs.tsx +128 -0
- package/src/primitives/textarea.tsx +20 -0
- package/src/primitives/tooltip.tsx +85 -0
- package/src/theme/QueryProvider.tsx +46 -0
- package/src/theme/ThemeProvider.tsx +120 -0
- package/src/theme/ThemeToggle.tsx +88 -0
- package/src/theme/index.ts +3 -0
- package/src/types/react-big-calendar.d.ts +16 -0
- package/tsconfig.build.json +11 -0
- package/tsconfig.json +9 -0
- package/watch.mjs +6 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cn } from "@open-mercato/shared/lib/utils";
|
|
5
|
+
const TabsContext = React.createContext(void 0);
|
|
6
|
+
function useTabsContext() {
|
|
7
|
+
const context = React.useContext(TabsContext);
|
|
8
|
+
if (!context) {
|
|
9
|
+
throw new Error("Tabs components must be used within a Tabs provider");
|
|
10
|
+
}
|
|
11
|
+
return context;
|
|
12
|
+
}
|
|
13
|
+
function Tabs({
|
|
14
|
+
value: controlledValue,
|
|
15
|
+
defaultValue,
|
|
16
|
+
onValueChange,
|
|
17
|
+
children,
|
|
18
|
+
className
|
|
19
|
+
}) {
|
|
20
|
+
const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue ?? "");
|
|
21
|
+
const isControlled = controlledValue !== void 0;
|
|
22
|
+
const value = isControlled ? controlledValue : uncontrolledValue;
|
|
23
|
+
const handleValueChange = React.useCallback(
|
|
24
|
+
(newValue) => {
|
|
25
|
+
if (!isControlled) {
|
|
26
|
+
setUncontrolledValue(newValue);
|
|
27
|
+
}
|
|
28
|
+
onValueChange?.(newValue);
|
|
29
|
+
},
|
|
30
|
+
[isControlled, onValueChange]
|
|
31
|
+
);
|
|
32
|
+
return /* @__PURE__ */ jsx(TabsContext.Provider, { value: { value, onValueChange: handleValueChange }, children: /* @__PURE__ */ jsx("div", { className, children }) });
|
|
33
|
+
}
|
|
34
|
+
function TabsList({ children, className }) {
|
|
35
|
+
return /* @__PURE__ */ jsx(
|
|
36
|
+
"div",
|
|
37
|
+
{
|
|
38
|
+
className: cn(
|
|
39
|
+
"inline-flex h-9 items-center justify-start rounded-lg bg-muted p-1 text-muted-foreground",
|
|
40
|
+
className
|
|
41
|
+
),
|
|
42
|
+
role: "tablist",
|
|
43
|
+
children
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
function TabsTrigger({ value, children, className, disabled }) {
|
|
48
|
+
const { value: selectedValue, onValueChange } = useTabsContext();
|
|
49
|
+
const isSelected = selectedValue === value;
|
|
50
|
+
return /* @__PURE__ */ jsx(
|
|
51
|
+
"button",
|
|
52
|
+
{
|
|
53
|
+
type: "button",
|
|
54
|
+
role: "tab",
|
|
55
|
+
"aria-selected": isSelected,
|
|
56
|
+
disabled,
|
|
57
|
+
onClick: () => onValueChange(value),
|
|
58
|
+
className: cn(
|
|
59
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
|
60
|
+
isSelected ? "bg-background text-foreground shadow" : "hover:bg-background/50 hover:text-foreground",
|
|
61
|
+
className
|
|
62
|
+
),
|
|
63
|
+
children
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
function TabsContent({ value, children, className }) {
|
|
68
|
+
const { value: selectedValue } = useTabsContext();
|
|
69
|
+
if (selectedValue !== value) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
return /* @__PURE__ */ jsx(
|
|
73
|
+
"div",
|
|
74
|
+
{
|
|
75
|
+
role: "tabpanel",
|
|
76
|
+
className: cn("mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", className),
|
|
77
|
+
children
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
export {
|
|
82
|
+
Tabs,
|
|
83
|
+
TabsContent,
|
|
84
|
+
TabsList,
|
|
85
|
+
TabsTrigger
|
|
86
|
+
};
|
|
87
|
+
//# sourceMappingURL=tabs.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/primitives/tabs.tsx"],
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { cn } from '@open-mercato/shared/lib/utils'\n\ntype TabsContextValue = {\n value: string\n onValueChange: (value: string) => void\n}\n\nconst TabsContext = React.createContext<TabsContextValue | undefined>(undefined)\n\nfunction useTabsContext() {\n const context = React.useContext(TabsContext)\n if (!context) {\n throw new Error('Tabs components must be used within a Tabs provider')\n }\n return context\n}\n\nexport type TabsProps = {\n value?: string\n defaultValue?: string\n onValueChange?: (value: string) => void\n children: React.ReactNode\n className?: string\n}\n\nexport function Tabs({\n value: controlledValue,\n defaultValue,\n onValueChange,\n children,\n className,\n}: TabsProps) {\n const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue ?? '')\n const isControlled = controlledValue !== undefined\n const value = isControlled ? controlledValue : uncontrolledValue\n\n const handleValueChange = React.useCallback(\n (newValue: string) => {\n if (!isControlled) {\n setUncontrolledValue(newValue)\n }\n onValueChange?.(newValue)\n },\n [isControlled, onValueChange],\n )\n\n return (\n <TabsContext.Provider value={{ value, onValueChange: handleValueChange }}>\n <div className={className}>{children}</div>\n </TabsContext.Provider>\n )\n}\n\nexport type TabsListProps = {\n children: React.ReactNode\n className?: string\n}\n\nexport function TabsList({ children, className }: TabsListProps) {\n return (\n <div\n className={cn(\n 'inline-flex h-9 items-center justify-start rounded-lg bg-muted p-1 text-muted-foreground',\n className,\n )}\n role=\"tablist\"\n >\n {children}\n </div>\n )\n}\n\nexport type TabsTriggerProps = {\n value: string\n children: React.ReactNode\n className?: string\n disabled?: boolean\n}\n\nexport function TabsTrigger({ value, children, className, disabled }: TabsTriggerProps) {\n const { value: selectedValue, onValueChange } = useTabsContext()\n const isSelected = selectedValue === value\n\n return (\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={isSelected}\n disabled={disabled}\n onClick={() => onValueChange(value)}\n className={cn(\n 'inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',\n isSelected\n ? 'bg-background text-foreground shadow'\n : 'hover:bg-background/50 hover:text-foreground',\n className,\n )}\n >\n {children}\n </button>\n )\n}\n\nexport type TabsContentProps = {\n value: string\n children: React.ReactNode\n className?: string\n}\n\nexport function TabsContent({ value, children, className }: TabsContentProps) {\n const { value: selectedValue } = useTabsContext()\n\n if (selectedValue !== value) {\n return null\n }\n\n return (\n <div\n role=\"tabpanel\"\n className={cn('mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2', className)}\n >\n {children}\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAmDM;AAjDN,YAAY,WAAW;AACvB,SAAS,UAAU;AAOnB,MAAM,cAAc,MAAM,cAA4C,MAAS;AAE/E,SAAS,iBAAiB;AACxB,QAAM,UAAU,MAAM,WAAW,WAAW;AAC5C,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AACA,SAAO;AACT;AAUO,SAAS,KAAK;AAAA,EACnB,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAc;AACZ,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,MAAM,SAAS,gBAAgB,EAAE;AACnF,QAAM,eAAe,oBAAoB;AACzC,QAAM,QAAQ,eAAe,kBAAkB;AAE/C,QAAM,oBAAoB,MAAM;AAAA,IAC9B,CAAC,aAAqB;AACpB,UAAI,CAAC,cAAc;AACjB,6BAAqB,QAAQ;AAAA,MAC/B;AACA,sBAAgB,QAAQ;AAAA,IAC1B;AAAA,IACA,CAAC,cAAc,aAAa;AAAA,EAC9B;AAEA,SACE,oBAAC,YAAY,UAAZ,EAAqB,OAAO,EAAE,OAAO,eAAe,kBAAkB,GACrE,8BAAC,SAAI,WAAuB,UAAS,GACvC;AAEJ;AAOO,SAAS,SAAS,EAAE,UAAU,UAAU,GAAkB;AAC/D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACA,MAAK;AAAA,MAEJ;AAAA;AAAA,EACH;AAEJ;AASO,SAAS,YAAY,EAAE,OAAO,UAAU,WAAW,SAAS,GAAqB;AACtF,QAAM,EAAE,OAAO,eAAe,cAAc,IAAI,eAAe;AAC/D,QAAM,aAAa,kBAAkB;AAErC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,MAAK;AAAA,MACL,iBAAe;AAAA,MACf;AAAA,MACA,SAAS,MAAM,cAAc,KAAK;AAAA,MAClC,WAAW;AAAA,QACT;AAAA,QACA,aACI,yCACA;AAAA,QACJ;AAAA,MACF;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;AAQO,SAAS,YAAY,EAAE,OAAO,UAAU,UAAU,GAAqB;AAC5E,QAAM,EAAE,OAAO,cAAc,IAAI,eAAe;AAEhD,MAAI,kBAAkB,OAAO;AAC3B,WAAO;AAAA,EACT;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,WAAW,GAAG,mIAAmI,SAAS;AAAA,MAEzJ;AAAA;AAAA,EACH;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "@open-mercato/shared/lib/utils";
|
|
4
|
+
const Textarea = React.forwardRef(
|
|
5
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
6
|
+
"textarea",
|
|
7
|
+
{
|
|
8
|
+
ref,
|
|
9
|
+
className: cn(
|
|
10
|
+
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
11
|
+
className
|
|
12
|
+
),
|
|
13
|
+
...props
|
|
14
|
+
}
|
|
15
|
+
)
|
|
16
|
+
);
|
|
17
|
+
Textarea.displayName = "Textarea";
|
|
18
|
+
export {
|
|
19
|
+
Textarea
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=textarea.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/primitives/textarea.tsx"],
|
|
4
|
+
"sourcesContent": ["import * as React from 'react'\n\nimport { cn } from '@open-mercato/shared/lib/utils'\n\ntype TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>\n\nexport const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n ({ className, ...props }, ref) => (\n <textarea\n ref={ref}\n className={cn(\n 'flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',\n className\n )}\n {...props}\n />\n )\n)\n\nTextarea.displayName = 'Textarea'\n"],
|
|
5
|
+
"mappings": "AAQI;AARJ,YAAY,WAAW;AAEvB,SAAS,UAAU;AAIZ,MAAM,WAAW,MAAM;AAAA,EAC5B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QACxB;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,SAAS,cAAc;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
5
|
+
import { cn } from "@open-mercato/shared/lib/utils";
|
|
6
|
+
const TooltipProvider = TooltipPrimitive.Provider;
|
|
7
|
+
const Tooltip = TooltipPrimitive.Root;
|
|
8
|
+
const TooltipTrigger = TooltipPrimitive.Trigger;
|
|
9
|
+
const TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx(
|
|
10
|
+
TooltipPrimitive.Content,
|
|
11
|
+
{
|
|
12
|
+
ref,
|
|
13
|
+
sideOffset,
|
|
14
|
+
className: cn(
|
|
15
|
+
"z-50 overflow-hidden rounded-md bg-slate-900 px-3 py-1.5 text-xs text-slate-50 animate-in fade-in-0 zoom-in-95",
|
|
16
|
+
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
|
|
17
|
+
"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2",
|
|
18
|
+
"data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
19
|
+
"max-w-xs break-words",
|
|
20
|
+
className
|
|
21
|
+
),
|
|
22
|
+
...props
|
|
23
|
+
}
|
|
24
|
+
) }));
|
|
25
|
+
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
26
|
+
function SimpleTooltip({
|
|
27
|
+
content,
|
|
28
|
+
children,
|
|
29
|
+
delayDuration = 300,
|
|
30
|
+
side = "top",
|
|
31
|
+
align = "center",
|
|
32
|
+
open,
|
|
33
|
+
onOpenChange,
|
|
34
|
+
disabled = false
|
|
35
|
+
}) {
|
|
36
|
+
const isDisabled = disabled || !content;
|
|
37
|
+
if (isDisabled) {
|
|
38
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
39
|
+
}
|
|
40
|
+
return /* @__PURE__ */ jsxs(
|
|
41
|
+
Tooltip,
|
|
42
|
+
{
|
|
43
|
+
open,
|
|
44
|
+
onOpenChange,
|
|
45
|
+
delayDuration,
|
|
46
|
+
children: [
|
|
47
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children }),
|
|
48
|
+
/* @__PURE__ */ jsx(TooltipContent, { side, align, children: content })
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
SimpleTooltip,
|
|
55
|
+
Tooltip,
|
|
56
|
+
TooltipContent,
|
|
57
|
+
TooltipProvider,
|
|
58
|
+
TooltipTrigger
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=tooltip.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/primitives/tooltip.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport * as TooltipPrimitive from '@radix-ui/react-tooltip'\nimport { cn } from '@open-mercato/shared/lib/utils'\n\nexport const TooltipProvider = TooltipPrimitive.Provider\n\nexport const Tooltip = TooltipPrimitive.Root\n\nexport const TooltipTrigger = TooltipPrimitive.Trigger\n\nexport const TooltipContent = React.forwardRef<\n React.ElementRef<typeof TooltipPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n 'z-50 overflow-hidden rounded-md bg-slate-900 px-3 py-1.5 text-xs text-slate-50 animate-in fade-in-0 zoom-in-95',\n 'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',\n 'data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2',\n 'data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',\n 'max-w-xs break-words',\n className\n )}\n {...props}\n />\n </TooltipPrimitive.Portal>\n))\nTooltipContent.displayName = TooltipPrimitive.Content.displayName\n\nexport type TooltipProps = {\n content: React.ReactNode\n children: React.ReactNode\n delayDuration?: number\n side?: 'top' | 'right' | 'bottom' | 'left'\n align?: 'start' | 'center' | 'end'\n open?: boolean\n onOpenChange?: (open: boolean) => void\n disabled?: boolean\n}\n\n/**\n * Simple tooltip wrapper component for common use cases.\n *\n * @example\n * <SimpleTooltip content=\"Full text here\">\n * <span>Truncated...</span>\n * </SimpleTooltip>\n */\nexport function SimpleTooltip({\n content,\n children,\n delayDuration = 300,\n side = 'top',\n align = 'center',\n open,\n onOpenChange,\n disabled = false,\n}: TooltipProps) {\n // If disabled or no content, just render children without tooltip\n const isDisabled = disabled || !content\n\n if (isDisabled) {\n return <>{children}</>\n }\n\n return (\n <Tooltip\n open={open}\n onOpenChange={onOpenChange}\n delayDuration={delayDuration}\n >\n <TooltipTrigger asChild>\n {children}\n </TooltipTrigger>\n <TooltipContent side={side} align={align}>\n {content}\n </TooltipContent>\n </Tooltip>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAiBI,SAkDO,UAlDP,KAsDA,YAtDA;AAfJ,YAAY,WAAW;AACvB,YAAY,sBAAsB;AAClC,SAAS,UAAU;AAEZ,MAAM,kBAAkB,iBAAiB;AAEzC,MAAM,UAAU,iBAAiB;AAEjC,MAAM,iBAAiB,iBAAiB;AAExC,MAAM,iBAAiB,MAAM,WAGlC,CAAC,EAAE,WAAW,aAAa,GAAG,GAAG,MAAM,GAAG,QAC1C,oBAAC,iBAAiB,QAAjB,EACC;AAAA,EAAC,iBAAiB;AAAA,EAAjB;AAAA,IACC;AAAA,IACA;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN,GACF,CACD;AACD,eAAe,cAAc,iBAAiB,QAAQ;AAqB/C,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB,OAAO;AAAA,EACP,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA,WAAW;AACb,GAAiB;AAEf,QAAM,aAAa,YAAY,CAAC;AAEhC,MAAI,YAAY;AACd,WAAO,gCAAG,UAAS;AAAA,EACrB;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MAEA;AAAA,4BAAC,kBAAe,SAAO,MACpB,UACH;AAAA,QACA,oBAAC,kBAAe,MAAY,OACzB,mBACH;AAAA;AAAA;AAAA,EACF;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { MutationCache, QueryCache, QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
5
|
+
import { redirectToSessionRefresh, redirectToForbiddenLogin, UnauthorizedError, ForbiddenError, apiFetch, setAuthRedirectConfig } from "../backend/utils/api.js";
|
|
6
|
+
function ensureGlobalFetchInterception() {
|
|
7
|
+
if (typeof window === "undefined") return;
|
|
8
|
+
const w = window;
|
|
9
|
+
if (w.__omFetchPatched) return;
|
|
10
|
+
w.__omFetchPatched = true;
|
|
11
|
+
w.__omOriginalFetch = window.fetch;
|
|
12
|
+
window.fetch = ((input, init) => apiFetch(input, init));
|
|
13
|
+
}
|
|
14
|
+
const client = new QueryClient({
|
|
15
|
+
queryCache: new QueryCache({
|
|
16
|
+
onError: (error) => {
|
|
17
|
+
if (error instanceof UnauthorizedError) redirectToSessionRefresh();
|
|
18
|
+
else if (error instanceof ForbiddenError) redirectToForbiddenLogin();
|
|
19
|
+
else if (error?.status === 401) redirectToSessionRefresh();
|
|
20
|
+
else if (error?.status === 403) redirectToForbiddenLogin();
|
|
21
|
+
}
|
|
22
|
+
}),
|
|
23
|
+
mutationCache: new MutationCache({
|
|
24
|
+
onError: (error) => {
|
|
25
|
+
if (error instanceof UnauthorizedError) redirectToSessionRefresh();
|
|
26
|
+
else if (error instanceof ForbiddenError) redirectToForbiddenLogin();
|
|
27
|
+
else if (error?.status === 401) redirectToSessionRefresh();
|
|
28
|
+
else if (error?.status === 403) redirectToForbiddenLogin();
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
});
|
|
32
|
+
function QueryProvider({ children, defaultForbiddenRoles }) {
|
|
33
|
+
React.useEffect(() => {
|
|
34
|
+
ensureGlobalFetchInterception();
|
|
35
|
+
if (defaultForbiddenRoles && defaultForbiddenRoles.length) {
|
|
36
|
+
setAuthRedirectConfig({ defaultForbiddenRoles });
|
|
37
|
+
}
|
|
38
|
+
}, []);
|
|
39
|
+
return /* @__PURE__ */ jsx(QueryClientProvider, { client, children });
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
QueryProvider
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=QueryProvider.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/theme/QueryProvider.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { MutationCache, QueryCache, QueryClient, QueryClientProvider } from '@tanstack/react-query'\nimport { redirectToSessionRefresh, redirectToForbiddenLogin, UnauthorizedError, ForbiddenError, apiFetch, setAuthRedirectConfig } from '../backend/utils/api'\n\n// Ensure global fetch calls also respect our redirect-on-401/403 policy.\nfunction ensureGlobalFetchInterception() {\n if (typeof window === 'undefined') return\n const w = window as any\n if (w.__omFetchPatched) return\n w.__omFetchPatched = true\n w.__omOriginalFetch = window.fetch\n window.fetch = ((input: RequestInfo | URL, init?: RequestInit) => apiFetch(input, init)) as any\n}\n\nconst client = new QueryClient({\n queryCache: new QueryCache({\n onError: (error) => {\n if (error instanceof UnauthorizedError) redirectToSessionRefresh()\n else if (error instanceof ForbiddenError) redirectToForbiddenLogin()\n // As a fallback, try to detect common cases\n else if ((error as any)?.status === 401) redirectToSessionRefresh()\n else if ((error as any)?.status === 403) redirectToForbiddenLogin()\n },\n }),\n mutationCache: new MutationCache({\n onError: (error) => {\n if (error instanceof UnauthorizedError) redirectToSessionRefresh()\n else if (error instanceof ForbiddenError) redirectToForbiddenLogin()\n else if ((error as any)?.status === 401) redirectToSessionRefresh()\n else if ((error as any)?.status === 403) redirectToForbiddenLogin()\n },\n }),\n})\n\ntype QueryProviderProps = { children: React.ReactNode; defaultForbiddenRoles?: string[] }\n\nexport function QueryProvider({ children, defaultForbiddenRoles }: QueryProviderProps) {\n React.useEffect(() => {\n ensureGlobalFetchInterception()\n if (defaultForbiddenRoles && defaultForbiddenRoles.length) {\n setAuthRedirectConfig({ defaultForbiddenRoles })\n }\n }, [])\n return <QueryClientProvider client={client}>{children}</QueryClientProvider>\n}\n"],
|
|
5
|
+
"mappings": ";AA4CS;AA3CT,YAAY,WAAW;AACvB,SAAS,eAAe,YAAY,aAAa,2BAA2B;AAC5E,SAAS,0BAA0B,0BAA0B,mBAAmB,gBAAgB,UAAU,6BAA6B;AAGvI,SAAS,gCAAgC;AACvC,MAAI,OAAO,WAAW,YAAa;AACnC,QAAM,IAAI;AACV,MAAI,EAAE,iBAAkB;AACxB,IAAE,mBAAmB;AACrB,IAAE,oBAAoB,OAAO;AAC7B,SAAO,SAAS,CAAC,OAA0B,SAAuB,SAAS,OAAO,IAAI;AACxF;AAEA,MAAM,SAAS,IAAI,YAAY;AAAA,EAC7B,YAAY,IAAI,WAAW;AAAA,IACzB,SAAS,CAAC,UAAU;AAClB,UAAI,iBAAiB,kBAAmB,0BAAyB;AAAA,eACxD,iBAAiB,eAAgB,0BAAyB;AAAA,eAEzD,OAAe,WAAW,IAAK,0BAAyB;AAAA,eACxD,OAAe,WAAW,IAAK,0BAAyB;AAAA,IACpE;AAAA,EACF,CAAC;AAAA,EACD,eAAe,IAAI,cAAc;AAAA,IAC/B,SAAS,CAAC,UAAU;AAClB,UAAI,iBAAiB,kBAAmB,0BAAyB;AAAA,eACxD,iBAAiB,eAAgB,0BAAyB;AAAA,eACzD,OAAe,WAAW,IAAK,0BAAyB;AAAA,eACxD,OAAe,WAAW,IAAK,0BAAyB;AAAA,IACpE;AAAA,EACF,CAAC;AACH,CAAC;AAIM,SAAS,cAAc,EAAE,UAAU,sBAAsB,GAAuB;AACrF,QAAM,UAAU,MAAM;AACpB,kCAA8B;AAC9B,QAAI,yBAAyB,sBAAsB,QAAQ;AACzD,4BAAsB,EAAE,sBAAsB,CAAC;AAAA,IACjD;AAAA,EACF,GAAG,CAAC,CAAC;AACL,SAAO,oBAAC,uBAAoB,QAAiB,UAAS;AACxD;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
const ThemeContext = React.createContext(void 0);
|
|
5
|
+
const THEME_STORAGE_KEY = "om-theme";
|
|
6
|
+
function getSystemTheme() {
|
|
7
|
+
if (typeof window === "undefined") return "light";
|
|
8
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
9
|
+
}
|
|
10
|
+
function getStoredTheme() {
|
|
11
|
+
if (typeof window === "undefined") return "system";
|
|
12
|
+
try {
|
|
13
|
+
const stored = localStorage.getItem(THEME_STORAGE_KEY);
|
|
14
|
+
if (stored === "light" || stored === "dark" || stored === "system") {
|
|
15
|
+
return stored;
|
|
16
|
+
}
|
|
17
|
+
} catch (error) {
|
|
18
|
+
if (process.env.NODE_ENV === "development") {
|
|
19
|
+
console.warn("[ThemeProvider] localStorage read failed:", error);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return "system";
|
|
23
|
+
}
|
|
24
|
+
function applyTheme(resolvedTheme) {
|
|
25
|
+
const root = document.documentElement;
|
|
26
|
+
if (resolvedTheme === "dark") {
|
|
27
|
+
root.classList.add("dark");
|
|
28
|
+
} else {
|
|
29
|
+
root.classList.remove("dark");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function ThemeProvider({ children }) {
|
|
33
|
+
const [theme, setThemeState] = React.useState("system");
|
|
34
|
+
const [resolvedTheme, setResolvedTheme] = React.useState("light");
|
|
35
|
+
const [mounted, setMounted] = React.useState(false);
|
|
36
|
+
React.useEffect(() => {
|
|
37
|
+
const stored = getStoredTheme();
|
|
38
|
+
setThemeState(stored);
|
|
39
|
+
const resolved = stored === "system" ? getSystemTheme() : stored;
|
|
40
|
+
setResolvedTheme(resolved);
|
|
41
|
+
applyTheme(resolved);
|
|
42
|
+
setMounted(true);
|
|
43
|
+
}, []);
|
|
44
|
+
React.useEffect(() => {
|
|
45
|
+
if (typeof window === "undefined") return;
|
|
46
|
+
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
47
|
+
const handleChange = () => {
|
|
48
|
+
if (theme === "system") {
|
|
49
|
+
const newResolved = getSystemTheme();
|
|
50
|
+
setResolvedTheme(newResolved);
|
|
51
|
+
applyTheme(newResolved);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
mediaQuery.addEventListener("change", handleChange);
|
|
55
|
+
return () => mediaQuery.removeEventListener("change", handleChange);
|
|
56
|
+
}, [theme]);
|
|
57
|
+
const setTheme = React.useCallback((newTheme) => {
|
|
58
|
+
setThemeState(newTheme);
|
|
59
|
+
try {
|
|
60
|
+
localStorage.setItem(THEME_STORAGE_KEY, newTheme);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
if (process.env.NODE_ENV === "development") {
|
|
63
|
+
console.warn("[ThemeProvider] localStorage write failed:", error);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const resolved = newTheme === "system" ? getSystemTheme() : newTheme;
|
|
67
|
+
setResolvedTheme(resolved);
|
|
68
|
+
applyTheme(resolved);
|
|
69
|
+
}, []);
|
|
70
|
+
const value = React.useMemo(
|
|
71
|
+
() => ({ theme, resolvedTheme, setTheme }),
|
|
72
|
+
[theme, resolvedTheme, setTheme]
|
|
73
|
+
);
|
|
74
|
+
if (!mounted) {
|
|
75
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
76
|
+
}
|
|
77
|
+
return /* @__PURE__ */ jsx(ThemeContext.Provider, { value, children });
|
|
78
|
+
}
|
|
79
|
+
function useTheme() {
|
|
80
|
+
const context = React.useContext(ThemeContext);
|
|
81
|
+
if (context === void 0) {
|
|
82
|
+
return {
|
|
83
|
+
theme: "system",
|
|
84
|
+
resolvedTheme: "light",
|
|
85
|
+
setTheme: () => {
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
return context;
|
|
90
|
+
}
|
|
91
|
+
export {
|
|
92
|
+
ThemeProvider,
|
|
93
|
+
useTheme
|
|
94
|
+
};
|
|
95
|
+
//# sourceMappingURL=ThemeProvider.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/theme/ThemeProvider.tsx"],
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\n\nexport type Theme = 'light' | 'dark' | 'system'\n\ntype ThemeContextValue = {\n theme: Theme\n resolvedTheme: 'light' | 'dark'\n setTheme: (theme: Theme) => void\n}\n\nconst ThemeContext = React.createContext<ThemeContextValue | undefined>(undefined)\n\nconst THEME_STORAGE_KEY = 'om-theme'\n\nfunction getSystemTheme(): 'light' | 'dark' {\n if (typeof window === 'undefined') return 'light'\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'\n}\n\nfunction getStoredTheme(): Theme {\n if (typeof window === 'undefined') return 'system'\n try {\n const stored = localStorage.getItem(THEME_STORAGE_KEY)\n if (stored === 'light' || stored === 'dark' || stored === 'system') {\n return stored\n }\n } catch (error) {\n // localStorage may be unavailable in private browsing, iframes, or restricted contexts\n // Theme will default to system preference - this is expected graceful degradation\n if (process.env.NODE_ENV === 'development') {\n console.warn('[ThemeProvider] localStorage read failed:', error)\n }\n }\n return 'system'\n}\n\nfunction applyTheme(resolvedTheme: 'light' | 'dark') {\n const root = document.documentElement\n if (resolvedTheme === 'dark') {\n root.classList.add('dark')\n } else {\n root.classList.remove('dark')\n }\n}\n\nexport function ThemeProvider({ children }: { children: React.ReactNode }) {\n const [theme, setThemeState] = React.useState<Theme>('system')\n const [resolvedTheme, setResolvedTheme] = React.useState<'light' | 'dark'>('light')\n const [mounted, setMounted] = React.useState(false)\n\n // Initialize theme from localStorage on mount\n React.useEffect(() => {\n const stored = getStoredTheme()\n setThemeState(stored)\n const resolved = stored === 'system' ? getSystemTheme() : stored\n setResolvedTheme(resolved)\n applyTheme(resolved)\n setMounted(true)\n }, [])\n\n // Listen for system theme changes\n React.useEffect(() => {\n if (typeof window === 'undefined') return\n\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')\n const handleChange = () => {\n if (theme === 'system') {\n const newResolved = getSystemTheme()\n setResolvedTheme(newResolved)\n applyTheme(newResolved)\n }\n }\n\n mediaQuery.addEventListener('change', handleChange)\n return () => mediaQuery.removeEventListener('change', handleChange)\n }, [theme])\n\n const setTheme = React.useCallback((newTheme: Theme) => {\n setThemeState(newTheme)\n try {\n localStorage.setItem(THEME_STORAGE_KEY, newTheme)\n } catch (error) {\n // localStorage may be unavailable - theme still works for this session, just won't persist\n if (process.env.NODE_ENV === 'development') {\n console.warn('[ThemeProvider] localStorage write failed:', error)\n }\n }\n const resolved = newTheme === 'system' ? getSystemTheme() : newTheme\n setResolvedTheme(resolved)\n applyTheme(resolved)\n }, [])\n\n const value = React.useMemo(\n () => ({ theme, resolvedTheme, setTheme }),\n [theme, resolvedTheme, setTheme]\n )\n\n // Prevent flash of wrong theme during hydration\n if (!mounted) {\n return <>{children}</>\n }\n\n return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>\n}\n\nexport function useTheme(): ThemeContextValue {\n const context = React.useContext(ThemeContext)\n if (context === undefined) {\n // Return safe defaults when not in provider (e.g., server render)\n return {\n theme: 'system',\n resolvedTheme: 'light',\n setTheme: () => {},\n }\n }\n return context\n}\n\n"],
|
|
5
|
+
"mappings": ";AAqGW;AAnGX,YAAY,WAAW;AAUvB,MAAM,eAAe,MAAM,cAA6C,MAAS;AAEjF,MAAM,oBAAoB;AAE1B,SAAS,iBAAmC;AAC1C,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,SAAO,OAAO,WAAW,8BAA8B,EAAE,UAAU,SAAS;AAC9E;AAEA,SAAS,iBAAwB;AAC/B,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,MAAI;AACF,UAAM,SAAS,aAAa,QAAQ,iBAAiB;AACrD,QAAI,WAAW,WAAW,WAAW,UAAU,WAAW,UAAU;AAClE,aAAO;AAAA,IACT;AAAA,EACF,SAAS,OAAO;AAGd,QAAI,QAAQ,IAAI,aAAa,eAAe;AAC1C,cAAQ,KAAK,6CAA6C,KAAK;AAAA,IACjE;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,WAAW,eAAiC;AACnD,QAAM,OAAO,SAAS;AACtB,MAAI,kBAAkB,QAAQ;AAC5B,SAAK,UAAU,IAAI,MAAM;AAAA,EAC3B,OAAO;AACL,SAAK,UAAU,OAAO,MAAM;AAAA,EAC9B;AACF;AAEO,SAAS,cAAc,EAAE,SAAS,GAAkC;AACzE,QAAM,CAAC,OAAO,aAAa,IAAI,MAAM,SAAgB,QAAQ;AAC7D,QAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAA2B,OAAO;AAClF,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAS,KAAK;AAGlD,QAAM,UAAU,MAAM;AACpB,UAAM,SAAS,eAAe;AAC9B,kBAAc,MAAM;AACpB,UAAM,WAAW,WAAW,WAAW,eAAe,IAAI;AAC1D,qBAAiB,QAAQ;AACzB,eAAW,QAAQ;AACnB,eAAW,IAAI;AAAA,EACjB,GAAG,CAAC,CAAC;AAGL,QAAM,UAAU,MAAM;AACpB,QAAI,OAAO,WAAW,YAAa;AAEnC,UAAM,aAAa,OAAO,WAAW,8BAA8B;AACnE,UAAM,eAAe,MAAM;AACzB,UAAI,UAAU,UAAU;AACtB,cAAM,cAAc,eAAe;AACnC,yBAAiB,WAAW;AAC5B,mBAAW,WAAW;AAAA,MACxB;AAAA,IACF;AAEA,eAAW,iBAAiB,UAAU,YAAY;AAClD,WAAO,MAAM,WAAW,oBAAoB,UAAU,YAAY;AAAA,EACpE,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,WAAW,MAAM,YAAY,CAAC,aAAoB;AACtD,kBAAc,QAAQ;AACtB,QAAI;AACF,mBAAa,QAAQ,mBAAmB,QAAQ;AAAA,IAClD,SAAS,OAAO;AAEd,UAAI,QAAQ,IAAI,aAAa,eAAe;AAC1C,gBAAQ,KAAK,8CAA8C,KAAK;AAAA,MAClE;AAAA,IACF;AACA,UAAM,WAAW,aAAa,WAAW,eAAe,IAAI;AAC5D,qBAAiB,QAAQ;AACzB,eAAW,QAAQ;AAAA,EACrB,GAAG,CAAC,CAAC;AAEL,QAAM,QAAQ,MAAM;AAAA,IAClB,OAAO,EAAE,OAAO,eAAe,SAAS;AAAA,IACxC,CAAC,OAAO,eAAe,QAAQ;AAAA,EACjC;AAGA,MAAI,CAAC,SAAS;AACZ,WAAO,gCAAG,UAAS;AAAA,EACrB;AAEA,SAAO,oBAAC,aAAa,UAAb,EAAsB,OAAe,UAAS;AACxD;AAEO,SAAS,WAA8B;AAC5C,QAAM,UAAU,MAAM,WAAW,YAAY;AAC7C,MAAI,YAAY,QAAW;AAEzB,WAAO;AAAA,MACL,OAAO;AAAA,MACP,eAAe;AAAA,MACf,UAAU,MAAM;AAAA,MAAC;AAAA,IACnB;AAAA,EACF;AACA,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Moon, Sun } from "lucide-react";
|
|
5
|
+
import { useTheme } from "./ThemeProvider.js";
|
|
6
|
+
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
7
|
+
import { cn } from "@open-mercato/shared/lib/utils";
|
|
8
|
+
function ThemeToggle({ className }) {
|
|
9
|
+
const { resolvedTheme, setTheme } = useTheme();
|
|
10
|
+
const t = useT();
|
|
11
|
+
const [mounted, setMounted] = React.useState(false);
|
|
12
|
+
React.useEffect(() => {
|
|
13
|
+
setMounted(true);
|
|
14
|
+
}, []);
|
|
15
|
+
const isDark = resolvedTheme === "dark";
|
|
16
|
+
const toggleLabel = t("common.theme.toggle", "Toggle theme");
|
|
17
|
+
const toggle = () => {
|
|
18
|
+
setTheme(isDark ? "light" : "dark");
|
|
19
|
+
};
|
|
20
|
+
if (!mounted) {
|
|
21
|
+
return /* @__PURE__ */ jsx(
|
|
22
|
+
"div",
|
|
23
|
+
{
|
|
24
|
+
className: cn(
|
|
25
|
+
"relative flex h-7 w-14 items-center rounded-full bg-muted p-1",
|
|
26
|
+
className
|
|
27
|
+
),
|
|
28
|
+
"aria-hidden": "true",
|
|
29
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex w-full justify-between px-1", children: [
|
|
30
|
+
/* @__PURE__ */ jsx(Sun, { className: "size-3.5 text-muted-foreground" }),
|
|
31
|
+
/* @__PURE__ */ jsx(Moon, { className: "size-3.5 text-muted-foreground" })
|
|
32
|
+
] })
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
return /* @__PURE__ */ jsxs(
|
|
37
|
+
"button",
|
|
38
|
+
{
|
|
39
|
+
type: "button",
|
|
40
|
+
role: "switch",
|
|
41
|
+
"aria-checked": isDark,
|
|
42
|
+
"aria-label": toggleLabel,
|
|
43
|
+
onClick: toggle,
|
|
44
|
+
className: cn(
|
|
45
|
+
"relative flex h-7 w-14 cursor-pointer items-center rounded-full p-1 transition-colors",
|
|
46
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
47
|
+
isDark ? "bg-primary" : "bg-muted",
|
|
48
|
+
className
|
|
49
|
+
),
|
|
50
|
+
children: [
|
|
51
|
+
/* @__PURE__ */ jsx(
|
|
52
|
+
"span",
|
|
53
|
+
{
|
|
54
|
+
className: cn(
|
|
55
|
+
"absolute size-5 rounded-full bg-background shadow-sm transition-transform duration-200 motion-reduce:transition-none",
|
|
56
|
+
isDark ? "translate-x-7" : "translate-x-0"
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
),
|
|
60
|
+
/* @__PURE__ */ jsxs("span", { className: "relative flex w-full justify-between px-0.5", children: [
|
|
61
|
+
/* @__PURE__ */ jsx(
|
|
62
|
+
Sun,
|
|
63
|
+
{
|
|
64
|
+
className: cn(
|
|
65
|
+
"size-3.5 transition-colors motion-reduce:transition-none",
|
|
66
|
+
isDark ? "text-muted-foreground" : "text-amber-500"
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
),
|
|
70
|
+
/* @__PURE__ */ jsx(
|
|
71
|
+
Moon,
|
|
72
|
+
{
|
|
73
|
+
className: cn(
|
|
74
|
+
"size-3.5 transition-colors motion-reduce:transition-none",
|
|
75
|
+
isDark ? "text-primary-foreground" : "text-muted-foreground"
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
] }),
|
|
80
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: isDark ? t("common.theme.dark", "Dark") : t("common.theme.light", "Light") })
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
export {
|
|
86
|
+
ThemeToggle
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=ThemeToggle.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/theme/ThemeToggle.tsx"],
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { Moon, Sun } from 'lucide-react'\nimport { useTheme } from './ThemeProvider'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { cn } from '@open-mercato/shared/lib/utils'\n\ntype ThemeToggleProps = {\n className?: string\n}\n\nexport function ThemeToggle({ className }: ThemeToggleProps) {\n const { resolvedTheme, setTheme } = useTheme()\n const t = useT()\n const [mounted, setMounted] = React.useState(false)\n\n React.useEffect(() => {\n setMounted(true)\n }, [])\n\n const isDark = resolvedTheme === 'dark'\n const toggleLabel = t('common.theme.toggle', 'Toggle theme')\n\n const toggle = () => {\n setTheme(isDark ? 'light' : 'dark')\n }\n\n // Render placeholder during SSR to prevent hydration mismatch\n if (!mounted) {\n return (\n <div\n className={cn(\n 'relative flex h-7 w-14 items-center rounded-full bg-muted p-1',\n className\n )}\n aria-hidden=\"true\"\n >\n <div className=\"flex w-full justify-between px-1\">\n <Sun className=\"size-3.5 text-muted-foreground\" />\n <Moon className=\"size-3.5 text-muted-foreground\" />\n </div>\n </div>\n )\n }\n\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={isDark}\n aria-label={toggleLabel}\n onClick={toggle}\n className={cn(\n 'relative flex h-7 w-14 cursor-pointer items-center rounded-full p-1 transition-colors',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n isDark ? 'bg-primary' : 'bg-muted',\n className\n )}\n >\n {/* Sliding indicator */}\n <span\n className={cn(\n 'absolute size-5 rounded-full bg-background shadow-sm transition-transform duration-200 motion-reduce:transition-none',\n isDark ? 'translate-x-7' : 'translate-x-0'\n )}\n />\n {/* Icons */}\n <span className=\"relative flex w-full justify-between px-0.5\">\n <Sun\n className={cn(\n 'size-3.5 transition-colors motion-reduce:transition-none',\n isDark ? 'text-muted-foreground' : 'text-amber-500'\n )}\n />\n <Moon\n className={cn(\n 'size-3.5 transition-colors motion-reduce:transition-none',\n isDark ? 'text-primary-foreground' : 'text-muted-foreground'\n )}\n />\n </span>\n <span className=\"sr-only\">\n {isDark ? t('common.theme.dark', 'Dark') : t('common.theme.light', 'Light')}\n </span>\n </button>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAsCQ,SACE,KADF;AApCR,YAAY,WAAW;AACvB,SAAS,MAAM,WAAW;AAC1B,SAAS,gBAAgB;AACzB,SAAS,YAAY;AACrB,SAAS,UAAU;AAMZ,SAAS,YAAY,EAAE,UAAU,GAAqB;AAC3D,QAAM,EAAE,eAAe,SAAS,IAAI,SAAS;AAC7C,QAAM,IAAI,KAAK;AACf,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAS,KAAK;AAElD,QAAM,UAAU,MAAM;AACpB,eAAW,IAAI;AAAA,EACjB,GAAG,CAAC,CAAC;AAEL,QAAM,SAAS,kBAAkB;AACjC,QAAM,cAAc,EAAE,uBAAuB,cAAc;AAE3D,QAAM,SAAS,MAAM;AACnB,aAAS,SAAS,UAAU,MAAM;AAAA,EACpC;AAGA,MAAI,CAAC,SAAS;AACZ,WACE;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,QACA,eAAY;AAAA,QAEZ,+BAAC,SAAI,WAAU,oCACb;AAAA,8BAAC,OAAI,WAAU,kCAAiC;AAAA,UAChD,oBAAC,QAAK,WAAU,kCAAiC;AAAA,WACnD;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,MAAK;AAAA,MACL,gBAAc;AAAA,MACd,cAAY;AAAA,MACZ,SAAS;AAAA,MACT,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA,SAAS,eAAe;AAAA,QACxB;AAAA,MACF;AAAA,MAGA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA,SAAS,kBAAkB;AAAA,YAC7B;AAAA;AAAA,QACF;AAAA,QAEA,qBAAC,UAAK,WAAU,+CACd;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW;AAAA,gBACT;AAAA,gBACA,SAAS,0BAA0B;AAAA,cACrC;AAAA;AAAA,UACF;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW;AAAA,gBACT;AAAA,gBACA,SAAS,4BAA4B;AAAA,cACvC;AAAA;AAAA,UACF;AAAA,WACF;AAAA,QACA,oBAAC,UAAK,WAAU,WACb,mBAAS,EAAE,qBAAqB,MAAM,IAAI,EAAE,sBAAsB,OAAO,GAC5E;AAAA;AAAA;AAAA,EACF;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ThemeProvider, useTheme } from "./ThemeProvider.js";
|
|
2
|
+
import { ThemeToggle } from "./ThemeToggle.js";
|
|
3
|
+
import { QueryProvider } from "./QueryProvider.js";
|
|
4
|
+
export {
|
|
5
|
+
QueryProvider,
|
|
6
|
+
ThemeProvider,
|
|
7
|
+
ThemeToggle,
|
|
8
|
+
useTheme
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/theme/index.ts"],
|
|
4
|
+
"sourcesContent": ["export { ThemeProvider, useTheme } from './ThemeProvider'\nexport { ThemeToggle } from './ThemeToggle'\nexport { QueryProvider } from './QueryProvider'\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,eAAe,gBAAgB;AACxC,SAAS,mBAAmB;AAC5B,SAAS,qBAAqB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=react-big-calendar.d.js.map
|
package/jest.config.cjs
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** @type {import('jest').Config} */
|
|
2
|
+
module.exports = {
|
|
3
|
+
preset: 'ts-jest',
|
|
4
|
+
testEnvironment: 'jsdom',
|
|
5
|
+
rootDir: '.',
|
|
6
|
+
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
|
|
7
|
+
moduleNameMapper: {
|
|
8
|
+
'^@open-mercato/ui/(.*)$': '<rootDir>/src/$1',
|
|
9
|
+
},
|
|
10
|
+
transform: {
|
|
11
|
+
'^.+\\.(t|j)sx?$': [
|
|
12
|
+
'ts-jest',
|
|
13
|
+
{
|
|
14
|
+
tsconfig: {
|
|
15
|
+
jsx: 'react-jsx',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
|
|
21
|
+
testMatch: ['<rootDir>/src/**/__tests__/**/*.test.(ts|tsx)'],
|
|
22
|
+
passWithNoTests: true,
|
|
23
|
+
}
|
package/jest.setup.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import '@testing-library/jest-dom'
|
|
2
|
+
|
|
3
|
+
// Mock Response/Request/Headers for tests that need them in jsdom environment
|
|
4
|
+
// These are available natively in Node 18+ but jsdom doesn't expose them
|
|
5
|
+
class MockResponse {
|
|
6
|
+
body: string
|
|
7
|
+
status: number
|
|
8
|
+
ok: boolean
|
|
9
|
+
headers: Map<string, string>
|
|
10
|
+
|
|
11
|
+
constructor(body: string = '', init: { status?: number; headers?: Record<string, string> } = {}) {
|
|
12
|
+
this.body = body
|
|
13
|
+
this.status = init.status ?? 200
|
|
14
|
+
this.ok = this.status >= 200 && this.status < 300
|
|
15
|
+
this.headers = new Map(Object.entries(init.headers ?? {}))
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async json() {
|
|
19
|
+
return JSON.parse(this.body)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async text() {
|
|
23
|
+
return this.body
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (typeof globalThis.Response === 'undefined') {
|
|
28
|
+
(globalThis as any).Response = MockResponse
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Mock window.location.reload globally for all tests
|
|
32
|
+
if (typeof window !== 'undefined' && window.location) {
|
|
33
|
+
try {
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
35
|
+
delete (window.location as any).reload
|
|
36
|
+
} catch (e) {
|
|
37
|
+
// Ignore if property can't be deleted
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
Object.defineProperty(window.location, 'reload', {
|
|
42
|
+
configurable: true,
|
|
43
|
+
writable: true,
|
|
44
|
+
value: jest.fn(),
|
|
45
|
+
})
|
|
46
|
+
} catch (e) {
|
|
47
|
+
// If we still can't define it, try direct assignment
|
|
48
|
+
try {
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
|
+
(window.location as any).reload = jest.fn()
|
|
51
|
+
} catch (innerError) {
|
|
52
|
+
// If all else fails, silently ignore - window.location.reload is completely locked
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|