@fluid-app/portal-sdk 0.1.332 → 0.1.334
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/dist/{AddressAutocompleteInput-D_bu-VYW.mjs → AddressAutocompleteInput-BWtZqpOc.mjs} +2 -2
- package/dist/{AddressAutocompleteInput-D_bu-VYW.mjs.map → AddressAutocompleteInput-BWtZqpOc.mjs.map} +1 -1
- package/dist/{AddressAutocompleteInput-DzUhtj6o.cjs → AddressAutocompleteInput-CGH4Kic9.cjs} +2 -2
- package/dist/{AddressAutocompleteInput-DzUhtj6o.cjs.map → AddressAutocompleteInput-CGH4Kic9.cjs.map} +1 -1
- package/dist/{AlertWidget-Dl4ybl2d.mjs → AlertWidget-SlkfOuVu.mjs} +3 -3
- package/dist/{AlertWidget-Dl4ybl2d.mjs.map → AlertWidget-SlkfOuVu.mjs.map} +1 -1
- package/dist/{AppDownloadScreen-CUSgeG2w.mjs → AppDownloadScreen-CauIkIKI.mjs} +2 -2
- package/dist/{AppDownloadScreen-CUSgeG2w.mjs.map → AppDownloadScreen-CauIkIKI.mjs.map} +1 -1
- package/dist/{BulletListWidget-DqJDKiHh.mjs → BulletListWidget-PTWWR75z.mjs} +2 -2
- package/dist/{BulletListWidget-DqJDKiHh.mjs.map → BulletListWidget-PTWWR75z.mjs.map} +1 -1
- package/dist/{CalendarWidget-B2siaYgQ.mjs → CalendarWidget-Dogh_5TL.mjs} +2 -2
- package/dist/{CalendarWidget-B2siaYgQ.mjs.map → CalendarWidget-Dogh_5TL.mjs.map} +1 -1
- package/dist/{CardWidget-BhfED5fW.mjs → CardWidget-CgdE35EN.mjs} +2 -2
- package/dist/{CardWidget-BhfED5fW.mjs.map → CardWidget-CgdE35EN.mjs.map} +1 -1
- package/dist/{CarouselWidget-CCusUzW6.mjs → CarouselWidget-Ce0X7aS8.mjs} +2 -2
- package/dist/{CarouselWidget-CCusUzW6.mjs.map → CarouselWidget-Ce0X7aS8.mjs.map} +1 -1
- package/dist/{CatchUpWidget-CPcS9iE6.mjs → CatchUpWidget-Cr21SMIo.mjs} +2 -2
- package/dist/{CatchUpWidget-CPcS9iE6.mjs.map → CatchUpWidget-Cr21SMIo.mjs.map} +1 -1
- package/dist/{ChartWidget-Cn5-G7gy.mjs → ChartWidget-80AuzFPc.mjs} +2 -2
- package/dist/{ChartWidget-Cn5-G7gy.mjs.map → ChartWidget-80AuzFPc.mjs.map} +1 -1
- package/dist/{ContactsScreen-D3_LQj6x.mjs → ContactsScreen-DDgwD2MI.mjs} +2 -2
- package/dist/{ContactsScreen-D3_LQj6x.mjs.map → ContactsScreen-DDgwD2MI.mjs.map} +1 -1
- package/dist/{ContainerWidget-HHvEJtXb.mjs → ContainerWidget-IgR1Ao3c.mjs} +3 -3
- package/dist/{ContainerWidget-HHvEJtXb.mjs.map → ContainerWidget-IgR1Ao3c.mjs.map} +1 -1
- package/dist/{CustomersScreen-D4KRUhQz.mjs → CustomersScreen-6QY5c1N8.mjs} +2 -2
- package/dist/{CustomersScreen-D4KRUhQz.mjs.map → CustomersScreen-6QY5c1N8.mjs.map} +1 -1
- package/dist/{EmbedWidget-D2BvU6NX.mjs → EmbedWidget-CQiKblyC.mjs} +2 -2
- package/dist/{EmbedWidget-D2BvU6NX.mjs.map → EmbedWidget-CQiKblyC.mjs.map} +1 -1
- package/dist/{FluidProvider-Vox9-7PR.mjs → FluidProvider-B-6PKi1Z.mjs} +54 -54
- package/dist/{FluidProvider-Vox9-7PR.mjs.map → FluidProvider-B-6PKi1Z.mjs.map} +1 -1
- package/dist/{FluidProvider-d2xkELCP.cjs → FluidProvider-T7GATgZf.cjs} +2 -2
- package/dist/{FluidProvider-d2xkELCP.cjs.map → FluidProvider-T7GATgZf.cjs.map} +1 -1
- package/dist/{ImageWidget-XOHYmG99.mjs → ImageWidget-urRs17bw.mjs} +2 -2
- package/dist/{ImageWidget-XOHYmG99.mjs.map → ImageWidget-urRs17bw.mjs.map} +1 -1
- package/dist/{LayoutWidget-CHQ6tx8V.mjs → LayoutWidget-Ukjn-n_n.mjs} +2 -2
- package/dist/{LayoutWidget-CHQ6tx8V.mjs.map → LayoutWidget-Ukjn-n_n.mjs.map} +1 -1
- package/dist/{LinkWidget-DW90JZN_.mjs → LinkWidget-COdFwA6Q.mjs} +2 -2
- package/dist/{LinkWidget-DW90JZN_.mjs.map → LinkWidget-COdFwA6Q.mjs.map} +1 -1
- package/dist/{ListWidget-Cb6ZVDHZ.mjs → ListWidget-DNzsU6bB.mjs} +2 -2
- package/dist/{ListWidget-Cb6ZVDHZ.mjs.map → ListWidget-DNzsU6bB.mjs.map} +1 -1
- package/dist/MessagingScreen-BkOZHZtL.mjs +50 -0
- package/dist/{MessagingScreen-d4E-pPU2.mjs → MessagingScreen-CszrlhFR.mjs} +5 -5
- package/dist/{MessagingScreen-d4E-pPU2.mjs.map → MessagingScreen-CszrlhFR.mjs.map} +1 -1
- package/dist/{MessagingScreen-DSiCbDtD.cjs → MessagingScreen-DbHT2YWZ.cjs} +3 -3
- package/dist/{MessagingScreen-zlASVP2j.cjs → MessagingScreen-nng7xcyK.cjs} +3 -3
- package/dist/{MessagingScreen-zlASVP2j.cjs.map → MessagingScreen-nng7xcyK.cjs.map} +1 -1
- package/dist/{MySiteScreen-D57JrpWL.mjs → MySiteScreen-C3xnULq3.mjs} +2 -2
- package/dist/{MySiteScreen-D57JrpWL.mjs.map → MySiteScreen-C3xnULq3.mjs.map} +1 -1
- package/dist/{MySiteWidget-BDysvovd.mjs → MySiteWidget-BSyS5AyJ.mjs} +2 -2
- package/dist/{MySiteWidget-BDysvovd.mjs.map → MySiteWidget-BSyS5AyJ.mjs.map} +1 -1
- package/dist/{NestedWidget-D7e-UXsd.mjs → NestedWidget-CrCzk6-q.mjs} +2 -2
- package/dist/{NestedWidget-D7e-UXsd.mjs.map → NestedWidget-CrCzk6-q.mjs.map} +1 -1
- package/dist/{OrdersScreen-PHt6FiLK.cjs → OrdersScreen-CLgTnT2i.cjs} +28 -5
- package/dist/OrdersScreen-CLgTnT2i.cjs.map +1 -0
- package/dist/OrdersScreen-DXdMTKiy.mjs +48 -0
- package/dist/{OrdersScreen-Dfk7bBrS.cjs → OrdersScreen-H5Z_dSHK.cjs} +3 -3
- package/dist/{OrdersScreen-DDjwCYh2.mjs → OrdersScreen-ir-Lym5l.mjs} +28 -5
- package/dist/OrdersScreen-ir-Lym5l.mjs.map +1 -0
- package/dist/{PointsWidget-DapuzCqJ.mjs → PointsWidget-DB1mBhZf.mjs} +2 -2
- package/dist/{PointsWidget-DapuzCqJ.mjs.map → PointsWidget-DB1mBhZf.mjs.map} +1 -1
- package/dist/{PortalTenantClientProvider-CqW6ae2M.mjs → PortalTenantClientProvider-BmRtQAbi.mjs} +8 -9
- package/dist/PortalTenantClientProvider-BmRtQAbi.mjs.map +1 -0
- package/dist/{PortalTenantClientProvider-D-QE-YzB.cjs → PortalTenantClientProvider-Bpm-CZq1.cjs} +8 -9
- package/dist/PortalTenantClientProvider-Bpm-CZq1.cjs.map +1 -0
- package/dist/ProfileScreen-BJ3d1UA1.mjs +51 -0
- package/dist/{ProfileScreen-PKdQL4_y.mjs → ProfileScreen-Bnm5KSPm.mjs} +5 -5
- package/dist/{ProfileScreen-PKdQL4_y.mjs.map → ProfileScreen-Bnm5KSPm.mjs.map} +1 -1
- package/dist/{ProfileScreen-Bws2p2aL.cjs → ProfileScreen-F5MPDdtL.cjs} +4 -4
- package/dist/{ProfileScreen-DGgM8BT3.cjs → ProfileScreen-k4gakTSe.cjs} +5 -5
- package/dist/{ProfileScreen-DGgM8BT3.cjs.map → ProfileScreen-k4gakTSe.cjs.map} +1 -1
- package/dist/{QuickLinksWidget-CxMjqbp0.mjs → QuickLinksWidget-DEQikOd5.mjs} +2 -2
- package/dist/{QuickLinksWidget-CxMjqbp0.mjs.map → QuickLinksWidget-DEQikOd5.mjs.map} +1 -1
- package/dist/{QuickShareWidget-CTCRjdrB.mjs → QuickShareWidget-D2W9IujT.mjs} +2 -2
- package/dist/{QuickShareWidget-CTCRjdrB.mjs.map → QuickShareWidget-D2W9IujT.mjs.map} +1 -1
- package/dist/{RecentActivityWidget-CoAL8wCS.mjs → RecentActivityWidget-jD7pjQa5.mjs} +2 -2
- package/dist/{RecentActivityWidget-CoAL8wCS.mjs.map → RecentActivityWidget-jD7pjQa5.mjs.map} +1 -1
- package/dist/{SeparatorWidget-DVJZu5gP.mjs → SeparatorWidget-DG_rWVnP.mjs} +2 -2
- package/dist/{SeparatorWidget-DVJZu5gP.mjs.map → SeparatorWidget-DG_rWVnP.mjs.map} +1 -1
- package/dist/{ShareablesScreen-BFQDn8Kt.mjs → ShareablesScreen-BDHGcO4c.mjs} +5 -4
- package/dist/{ShareablesScreen-BFQDn8Kt.mjs.map → ShareablesScreen-BDHGcO4c.mjs.map} +1 -1
- package/dist/{ShareablesScreen-HHPFsN7t.cjs → ShareablesScreen-CSCdh897.cjs} +4 -3
- package/dist/{ShareablesScreen-HHPFsN7t.cjs.map → ShareablesScreen-CSCdh897.cjs.map} +1 -1
- package/dist/{ShareablesScreen-D91gLWOB.cjs → ShareablesScreen-Cvxi4Fen.cjs} +2 -2
- package/dist/{ShareablesScreen-Bex7UIm5.mjs → ShareablesScreen-DK5h1Wv1.mjs} +3 -3
- package/dist/ShopScreen-B0DwIaM6.mjs +48 -0
- package/dist/{ShopScreen-BRsb2VNB.cjs → ShopScreen-BVs1_O9d.cjs} +2 -2
- package/dist/{ShopScreen-BRsb2VNB.cjs.map → ShopScreen-BVs1_O9d.cjs.map} +1 -1
- package/dist/{ShopScreen-BlIGdmTq.mjs → ShopScreen-CGYk5jvO.mjs} +3 -3
- package/dist/{ShopScreen-BlIGdmTq.mjs.map → ShopScreen-CGYk5jvO.mjs.map} +1 -1
- package/dist/{ShopScreen-Pdsn6sDj.cjs → ShopScreen-ztfxFYt5.cjs} +3 -3
- package/dist/{ShopWidget-CfasYQGp.mjs → ShopWidget-BBNFWedL.mjs} +2 -2
- package/dist/{ShopWidget-CfasYQGp.mjs.map → ShopWidget-BBNFWedL.mjs.map} +1 -1
- package/dist/{SpacerWidget-CCpCGUjM.mjs → SpacerWidget-B0l19UqF.mjs} +2 -2
- package/dist/{SpacerWidget-CCpCGUjM.mjs.map → SpacerWidget-B0l19UqF.mjs.map} +1 -1
- package/dist/{SubscriptionsScreen-L9ewT1bv.cjs → SubscriptionsScreen-DG2qu9A9.cjs} +5 -5
- package/dist/SubscriptionsScreen-DG2qu9A9.cjs.map +1 -0
- package/dist/{SubscriptionsScreen-BnObp1Ca.mjs → SubscriptionsScreen-DzJhgb_H.mjs} +5 -5
- package/dist/SubscriptionsScreen-DzJhgb_H.mjs.map +1 -0
- package/dist/SubscriptionsScreen-Fz7WzPge.mjs +50 -0
- package/dist/{SubscriptionsScreen-Bsuz7bNO.cjs → SubscriptionsScreen-dZwLcWJi.cjs} +4 -4
- package/dist/{TableWidget-CeaAeGSw.mjs → TableWidget-D4NBSOmz.mjs} +2 -2
- package/dist/{TableWidget-CeaAeGSw.mjs.map → TableWidget-D4NBSOmz.mjs.map} +1 -1
- package/dist/{TextWidget-APrOBo5U.mjs → TextWidget-B49O04oN.mjs} +2 -2
- package/dist/{TextWidget-APrOBo5U.mjs.map → TextWidget-B49O04oN.mjs.map} +1 -1
- package/dist/{ToDoWidget-CHsQI_Qk.mjs → ToDoWidget-B3sq5pIT.mjs} +2 -2
- package/dist/{ToDoWidget-CHsQI_Qk.mjs.map → ToDoWidget-B3sq5pIT.mjs.map} +1 -1
- package/dist/{UpgradeScreen-3tMWotmq.mjs → UpgradeScreen-DGJsj2Yx.mjs} +2 -2
- package/dist/{UpgradeScreen-3tMWotmq.mjs.map → UpgradeScreen-DGJsj2Yx.mjs.map} +1 -1
- package/dist/{VideoWidget-CuEeM8ct.mjs → VideoWidget-UJH0EhF-.mjs} +2 -2
- package/dist/{VideoWidget-CuEeM8ct.mjs.map → VideoWidget-UJH0EhF-.mjs.map} +1 -1
- package/dist/{es-C5E79_gn.mjs → es-DU0BGuLZ.mjs} +2 -2
- package/dist/{es-C5E79_gn.mjs.map → es-DU0BGuLZ.mjs.map} +1 -1
- package/dist/index.cjs +34 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +76 -70
- package/dist/index.mjs.map +1 -1
- package/dist/{use-account-BS0vV-sW.cjs → use-account-BMLTwG3m.cjs} +2 -2
- package/dist/{use-account-BS0vV-sW.cjs.map → use-account-BMLTwG3m.cjs.map} +1 -1
- package/dist/{use-account-BqNRv6m6.mjs → use-account-DtQOpv3N.mjs} +2 -2
- package/dist/{use-account-BqNRv6m6.mjs.map → use-account-DtQOpv3N.mjs.map} +1 -1
- package/package.json +15 -15
- package/dist/MessagingScreen-DbLWE-lO.mjs +0 -50
- package/dist/OrdersScreen-BAaZskOQ.mjs +0 -48
- package/dist/OrdersScreen-DDjwCYh2.mjs.map +0 -1
- package/dist/OrdersScreen-PHt6FiLK.cjs.map +0 -1
- package/dist/PortalTenantClientProvider-CqW6ae2M.mjs.map +0 -1
- package/dist/PortalTenantClientProvider-D-QE-YzB.cjs.map +0 -1
- package/dist/ProfileScreen-D7Gc9fKL.mjs +0 -51
- package/dist/ShopScreen-99bJJLBt.mjs +0 -48
- package/dist/SubscriptionsScreen-BnObp1Ca.mjs.map +0 -1
- package/dist/SubscriptionsScreen-BrAgJiKL.mjs +0 -50
- package/dist/SubscriptionsScreen-L9ewT1bv.cjs.map +0 -1
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import "./PortalTenantClientProvider-BmRtQAbi.mjs";
|
|
2
|
+
import "./FluidProvider-B-6PKi1Z.mjs";
|
|
3
|
+
import "./ScreenRenderer-1ZCNOyIb.mjs";
|
|
4
|
+
import "./store-api-context-DViwxyG4.mjs";
|
|
5
|
+
import "./mysite-api-context-kUTM3GNG.mjs";
|
|
6
|
+
import "./countries-api-context-DScC_39w.mjs";
|
|
7
|
+
import "./task-composer-form-CHyQZUCo.mjs";
|
|
8
|
+
import "./registry-context-BKvTiuXB.mjs";
|
|
9
|
+
import "./WidgetInteractionContext-BWH7njU7.mjs";
|
|
10
|
+
import "./EmbedWidget-CQiKblyC.mjs";
|
|
11
|
+
import "./static-dict-adapter-Z_42w_55.mjs";
|
|
12
|
+
import "./error-state-Djgt-RGW.mjs";
|
|
13
|
+
import "./translation-api-context-factory-Cq-pFTiQ.mjs";
|
|
14
|
+
import "./LayoutWidget-Ukjn-n_n.mjs";
|
|
15
|
+
import "./registries-C-t6-veK.mjs";
|
|
16
|
+
import "./fields-B2DTFWQl.mjs";
|
|
17
|
+
import "./TextWidget-B49O04oN.mjs";
|
|
18
|
+
import "./AlertWidget-SlkfOuVu.mjs";
|
|
19
|
+
import "./BulletListWidget-PTWWR75z.mjs";
|
|
20
|
+
import "./preview-context-CDnhakni.mjs";
|
|
21
|
+
import "./CalendarWidget-Dogh_5TL.mjs";
|
|
22
|
+
import "./CardWidget-CgdE35EN.mjs";
|
|
23
|
+
import "./purify.es-Cjc3iy5J.mjs";
|
|
24
|
+
import "./MediaRenderer-CLmBOrvK.mjs";
|
|
25
|
+
import "./CarouselWidget-Ce0X7aS8.mjs";
|
|
26
|
+
import "./CatchUpWidget-Cr21SMIo.mjs";
|
|
27
|
+
import "./src-DC5QoBhR.mjs";
|
|
28
|
+
import { n as subscriptionsScreenPropertySchema, t as SubscriptionsScreen } from "./SubscriptionsScreen-DzJhgb_H.mjs";
|
|
29
|
+
import "./ChartWidget-80AuzFPc.mjs";
|
|
30
|
+
import "./ContainerWidget-IgR1Ao3c.mjs";
|
|
31
|
+
import "./ImageWidget-urRs17bw.mjs";
|
|
32
|
+
import "./LinkWidget-COdFwA6Q.mjs";
|
|
33
|
+
import "./ListWidget-DNzsU6bB.mjs";
|
|
34
|
+
import "./MySiteWidget-BSyS5AyJ.mjs";
|
|
35
|
+
import "./NestedWidget-CrCzk6-q.mjs";
|
|
36
|
+
import "./PointsWidget-DB1mBhZf.mjs";
|
|
37
|
+
import "./QuickLinksWidget-DEQikOd5.mjs";
|
|
38
|
+
import "./QuickShareWidget-D2W9IujT.mjs";
|
|
39
|
+
import "./RecentActivityWidget-jD7pjQa5.mjs";
|
|
40
|
+
import "./SeparatorWidget-DG_rWVnP.mjs";
|
|
41
|
+
import "./SpacerWidget-B0l19UqF.mjs";
|
|
42
|
+
import "./TableWidget-D4NBSOmz.mjs";
|
|
43
|
+
import "./ToDoWidget-B3sq5pIT.mjs";
|
|
44
|
+
import "./VideoWidget-UJH0EhF-.mjs";
|
|
45
|
+
import "./SearchSort-BeYMXXIi.mjs";
|
|
46
|
+
import "./ShopWidget-BBNFWedL.mjs";
|
|
47
|
+
import "./ScreenHeaderContext-Dn12BZyj.mjs";
|
|
48
|
+
import "./AddressAutocompleteInput-BWtZqpOc.mjs";
|
|
49
|
+
import "./Combobox-B-rNFLTr.mjs";
|
|
50
|
+
export { SubscriptionsScreen, subscriptionsScreenPropertySchema };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require("./chunk-9hOWP6kD.cjs");
|
|
2
|
-
require("./FluidProvider-
|
|
2
|
+
require("./FluidProvider-T7GATgZf.cjs");
|
|
3
3
|
require("./ScreenRenderer-BYiZunHL.cjs");
|
|
4
|
-
require("./PortalTenantClientProvider-
|
|
4
|
+
require("./PortalTenantClientProvider-Bpm-CZq1.cjs");
|
|
5
5
|
require("./store-api-context-D1gZn22Z.cjs");
|
|
6
6
|
require("./mysite-api-context-CilZcDS4.cjs");
|
|
7
7
|
require("./countries-api-context-G-NW4BoH.cjs");
|
|
@@ -45,8 +45,8 @@ require("./VideoWidget-5oAZXEKw.cjs");
|
|
|
45
45
|
require("./SearchSort-Bi9QWJQQ.cjs");
|
|
46
46
|
require("./ShopWidget-CGs4oaaC.cjs");
|
|
47
47
|
require("./ScreenHeaderContext-DWDN0-mb.cjs");
|
|
48
|
-
require("./AddressAutocompleteInput-
|
|
48
|
+
require("./AddressAutocompleteInput-CGH4Kic9.cjs");
|
|
49
49
|
require("./Combobox-D9lqcqeg.cjs");
|
|
50
|
-
const require_SubscriptionsScreen = require("./SubscriptionsScreen-
|
|
50
|
+
const require_SubscriptionsScreen = require("./SubscriptionsScreen-DG2qu9A9.cjs");
|
|
51
51
|
exports.SubscriptionsScreen = require_SubscriptionsScreen.SubscriptionsScreen;
|
|
52
52
|
exports.subscriptionsScreenPropertySchema = require_SubscriptionsScreen.subscriptionsScreenPropertySchema;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { vt as __exportAll } from "./PortalTenantClientProvider-
|
|
1
|
+
import { vt as __exportAll } from "./PortalTenantClientProvider-BmRtQAbi.mjs";
|
|
2
2
|
import { n as useWidgetInteraction } from "./WidgetInteractionContext-BWH7njU7.mjs";
|
|
3
3
|
import { i as getBorderColorField, l as getColorField, m as getPaddingField, n as borderWidthClasses, o as getBorderRadiusField, s as getBorderWidthField, t as borderColorClasses, u as getFontSizeField } from "./registries-C-t6-veK.mjs";
|
|
4
4
|
import { n as getMediaPropsFromShareable, t as MediaRenderer } from "./MediaRenderer-CLmBOrvK.mjs";
|
|
@@ -495,4 +495,4 @@ const tableWidgetPropertySchema = {
|
|
|
495
495
|
//#endregion
|
|
496
496
|
export { TableWidget_exports as n, tableWidgetPropertySchema as r, TableWidget as t };
|
|
497
497
|
|
|
498
|
-
//# sourceMappingURL=TableWidget-
|
|
498
|
+
//# sourceMappingURL=TableWidget-D4NBSOmz.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TableWidget-CeaAeGSw.mjs","names":[],"sources":["../../widgets/src/widgets/TableWidget.tsx"],"sourcesContent":["import { useState, useMemo, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getBorderWidthField,\n getBorderColorField,\n borderWidthClasses,\n borderColorClasses,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport { Input } from \"@fluid-app/ui-primitives\";\nimport {\n MediaRenderer,\n getMediaPropsFromShareable,\n} from \"../components/MediaRenderer\";\nimport { type ShareableItem } from \"@fluid-app/portal-core/types\";\nimport { useWidgetInteraction } from \"../contexts/WidgetInteractionContext\";\n\n/** Plain column definition provided by data sources (no render functions) */\nexport type TableColumnDef = {\n key: string;\n label: string;\n sortable: boolean;\n};\n\n// Internal column definition (includes render function)\ntype ColumnDef = TableColumnDef & {\n render?: (value: unknown, item: ShareableItem) => React.ReactNode;\n};\n\nconst DEFAULT_DATA: ShareableItem[] = [];\n\n// ---------------------------------------------------------------------------\n// Column cell renderers\n// ---------------------------------------------------------------------------\n\nfunction ImageCellRenderer(_value: unknown, item: ShareableItem) {\n return (\n <div className=\"h-10 w-10 overflow-hidden rounded\">\n <MediaRenderer {...getMediaPropsFromShareable(item)} />\n </div>\n );\n}\n\nfunction PriceCellRenderer(_value: unknown, item: ShareableItem) {\n return ((item.display_price as string) ?? item.price) || \"-\";\n}\n\nfunction StatusCellRenderer(value: unknown) {\n const status = String(value || \"unknown\").toLowerCase();\n const statusStyles: Record<string, string> = {\n active: \"bg-primary text-primary-foreground\",\n paid: \"bg-primary text-primary-foreground\",\n inactive: \"bg-secondary text-secondary-foreground\",\n paused: \"bg-secondary text-secondary-foreground\",\n unknown: \"bg-muted text-muted-foreground\",\n unpaid: \"bg-destructive text-destructive-foreground\",\n refunded: \"bg-muted text-muted-foreground\",\n cancelled: \"bg-destructive text-destructive-foreground\",\n };\n return (\n <span\n className={`inline-flex rounded-full px-2 py-1 text-xs font-medium ${statusStyles[status] || \"bg-muted text-foreground\"}`}\n >\n {String(value || \"Unknown\")}\n </span>\n );\n}\n\n/** Map of column keys to custom cell renderers */\nconst CELL_RENDERERS: Record<\n string,\n (value: unknown, item: ShareableItem) => React.ReactNode\n> = {\n imageUrl: ImageCellRenderer,\n price: PriceCellRenderer,\n display_price: PriceCellRenderer,\n status: StatusCellRenderer,\n};\n\n/** Resolve plain column definitions from a data source into full ColumnDefs with renderers */\nfunction resolveColumns(columns: TableColumnDef[]): ColumnDef[] {\n return columns.map((col) => {\n const render = CELL_RENDERERS[col.key];\n return render ? { ...col, render } : { ...col };\n });\n}\n\n// Default columns for product data\nconst defaultColumns: ColumnDef[] = [\n {\n key: \"imageUrl\",\n label: \"Image\",\n sortable: false,\n render: ImageCellRenderer,\n },\n {\n key: \"title\",\n label: \"Title\",\n sortable: true,\n },\n {\n key: \"price\",\n label: \"Price\",\n sortable: true,\n render: PriceCellRenderer,\n },\n {\n key: \"status\",\n label: \"Status\",\n sortable: true,\n render: StatusCellRenderer,\n },\n];\n\ntype TableWidgetProps = ComponentProps<\"div\"> & {\n // Title\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Styling\n background?: BackgroundValue;\n alternatingColorEnabled?: boolean;\n textColor?: ColorOptions;\n headerBackgroundColor?: ColorOptions;\n headerTextColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n\n // Data\n data?: ShareableItem[];\n /** Column definitions from a data source (plain data, renderers resolved internally) */\n columns?: TableColumnDef[];\n\n // Features\n filterEnabled?: boolean;\n sortingEnabled?: boolean;\n paginationEnabled?: boolean;\n maxRowsPerPage?: number;\n};\n\nexport function TableWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"Products\",\n titleFontSize = \"xl\",\n titleColor = \"foreground\",\n\n // Styling defaults\n background = {\n type: \"solid\",\n color: \"background\",\n },\n alternatingColorEnabled = true,\n textColor = \"foreground\",\n headerBackgroundColor = \"muted\",\n headerTextColor = \"foreground\",\n padding = 4,\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n\n // Data\n data = DEFAULT_DATA,\n columns: columnsProp,\n\n // Feature defaults\n filterEnabled = true,\n sortingEnabled = true,\n paginationEnabled = true,\n maxRowsPerPage = 5,\n\n className,\n ...props\n}: TableWidgetProps): React.JSX.Element {\n const backgroundColor = background.color || \"background\";\n const isImageBackground = background.type === \"image\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n isImageBackground\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n const pageSize = maxRowsPerPage;\n\n // When using an image or transparent background, inner elements should be\n // transparent so the image/page shows through. Otherwise use the configured colors.\n const isTransparentBg = backgroundColor === \"transparent\";\n const useTransparentInner = isImageBackground || isTransparentBg;\n const innerBg = useTransparentInner\n ? \"bg-transparent\"\n : `bg-${backgroundColor}`;\n const innerBgAlt = useTransparentInner\n ? \"bg-black/5\"\n : `bg-${backgroundColor}/40`;\n const transparentBorder = isTransparentBg\n ? \"border-black/20\"\n : \"border-white/20\";\n const innerBorder = useTransparentInner\n ? transparentBorder\n : `border-${backgroundColor}/60`;\n const headerBg = useTransparentInner\n ? \"bg-black/10\"\n : `bg-${headerBackgroundColor}/40`;\n const headerBorder = useTransparentInner\n ? transparentBorder\n : `border-${headerBackgroundColor}/60`;\n const paginationBg = useTransparentInner\n ? \"bg-black/10\"\n : `bg-${backgroundColor}/40`;\n\n // State for filtering, sorting, and pagination\n const [globalFilter, setGlobalFilter] = useState(\"\");\n const [sortConfig, setSortConfig] = useState<{\n key: string;\n direction: \"asc\" | \"desc\";\n } | null>(null);\n const [currentPage, setCurrentPage] = useState(1);\n\n // Only use columns from the data source if they look like valid column defs\n // (have a `key` string). When transformers return a plain array (e.g. toShareableProps),\n // use-widget-data maps the same array to ALL targetProps, so `columns` may\n // receive the data rows instead of column definitions.\n const firstCol = columnsProp?.[0];\n const validColumnsProp =\n firstCol && typeof firstCol.key === \"string\" && firstCol.key !== \"\"\n ? columnsProp\n : undefined;\n\n const columns = useMemo(\n () =>\n validColumnsProp ? resolveColumns(validColumnsProp) : defaultColumns,\n [validColumnsProp],\n );\n\n // Filter data\n const filteredData = useMemo(() => {\n let result = [...data];\n\n if (globalFilter) {\n const lowerFilter = globalFilter.toLowerCase();\n result = result.filter((item) =>\n columns.some((col) => {\n const value = item[col.key];\n return String(value ?? \"\")\n .toLowerCase()\n .includes(lowerFilter);\n }),\n );\n }\n\n return result;\n }, [data, globalFilter, columns]);\n\n // Sort data\n const sortedData = useMemo(() => {\n if (!sortConfig) return filteredData;\n\n return [...filteredData].sort((a, b) => {\n const aValue = a[sortConfig.key];\n const bValue = b[sortConfig.key];\n\n // Handle null/undefined\n if (aValue == null && bValue == null) return 0;\n if (aValue == null) return sortConfig.direction === \"asc\" ? 1 : -1;\n if (bValue == null) return sortConfig.direction === \"asc\" ? -1 : 1;\n\n // Compare values\n let comparison = 0;\n if (typeof aValue === \"number\" && typeof bValue === \"number\") {\n comparison = aValue - bValue;\n } else {\n comparison = String(aValue).localeCompare(String(bValue));\n }\n\n return sortConfig.direction === \"asc\" ? comparison : -comparison;\n });\n }, [filteredData, sortConfig]);\n\n // Paginate data\n const paginatedData = useMemo(() => {\n if (!paginationEnabled) return sortedData;\n\n const startIndex = (currentPage - 1) * pageSize;\n return sortedData.slice(startIndex, startIndex + pageSize);\n }, [sortedData, currentPage, pageSize, paginationEnabled]);\n\n const totalPages = Math.ceil(sortedData.length / pageSize);\n\n // Reset to page 1 when filters change\n const handleGlobalFilterChange = (value: string) => {\n setGlobalFilter(value);\n setCurrentPage(1);\n };\n\n // Handle sort\n const handleSort = (key: string) => {\n if (!sortingEnabled) return;\n\n setSortConfig((prev) => {\n if (prev?.key !== key) return { key, direction: \"asc\" };\n if (prev.direction === \"asc\") return { key, direction: \"desc\" };\n return null;\n });\n };\n\n // Get sort indicator\n const getSortIndicator = (key: string) => {\n if (sortConfig?.key !== key) return null;\n return sortConfig.direction === \"asc\" ? \" ↑\" : \" ↓\";\n };\n\n const { onItemClick } = useWidgetInteraction();\n\n return (\n <div\n className={`@container overflow-hidden ${paginationEnabled ? \"\" : \"overflow-y-auto\"} rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} bg-${backgroundColor} bg-cover bg-center text-${textColor} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n <div\n className={`flex items-center justify-between p-${padding} ${innerBg} space-x-2`}\n >\n {/* Title */}\n {titleEnabled && titleText && (\n <h2\n className={`text-${titleFontSize === \"md\" ? \"base\" : titleFontSize} font-header font-bold text-${titleColor} min-w-0 truncate`}\n >\n {titleText}\n </h2>\n )}\n\n {/* Global Search */}\n {filterEnabled && (\n <Input\n type=\"text\"\n placeholder=\"Search all columns...\"\n value={globalFilter}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n handleGlobalFilterChange(e.target.value)\n }\n className={`w-full rounded-md border ${headerBorder} ${headerBg} ring-offset-muted px-3 py-2 text-sm placeholder:text-${headerTextColor}/40 focus-visible:ring-primary focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none md:w-64`}\n />\n )}\n </div>\n\n {/* Table */}\n <div className=\"overflow-x-auto\">\n <table className=\"w-full border-collapse\">\n <thead>\n <tr className={`${headerBg} ${headerBorder} border-y`}>\n {columns.map((col) => (\n <th\n key={col.key}\n className={`px-4 py-3 text-left text-sm font-semibold text-${headerTextColor} ${col.sortable && sortingEnabled ? \"cursor-pointer select-none hover:opacity-80\" : \"\"}`}\n {...(col.sortable && sortingEnabled\n ? {\n role: \"button\" as const,\n tabIndex: 0,\n onClick: () => handleSort(col.key),\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleSort(col.key);\n }\n },\n }\n : {})}\n >\n <div className=\"flex flex-col gap-1\">\n <span>\n {col.label}\n {col.sortable &&\n sortingEnabled &&\n getSortIndicator(col.key)}\n </span>\n </div>\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.length === 0 ? (\n <tr>\n <td colSpan={columns.length}>\n <div className=\"text-muted-foreground flex min-h-[200px] flex-col items-center justify-center gap-2\">\n <div className=\"text-4xl\">📋</div>\n <p className=\"text-sm\">No data available</p>\n <p className=\"text-muted-foreground/70 text-xs\">\n Connect a data source to display table data\n </p>\n </div>\n </td>\n </tr>\n ) : paginatedData.length === 0 ? (\n <tr>\n <td colSpan={columns.length}>\n <div className=\"py-8 text-center\">\n <p className=\"text-sm\">No results found</p>\n <p className=\"text-xs\">Try adjusting your search</p>\n </div>\n </td>\n </tr>\n ) : (\n <>\n {paginatedData.map((item, index) => (\n <tr\n key={item.id ?? index}\n className={`h-17 border-b ${innerBorder} last:border-none ${innerBg} ${alternatingColorEnabled ? `even:${innerBgAlt}` : \"\"} ${onItemClick ? \"cursor-pointer hover:opacity-80\" : \"\"}`}\n {...(onItemClick\n ? {\n tabIndex: 0,\n onClick: () => onItemClick(item),\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onItemClick(item);\n }\n },\n }\n : {})}\n >\n {columns.map((col) => (\n <td key={col.key} className=\"px-4 py-3 text-sm\">\n {col.render\n ? col.render(item[col.key], item)\n : String(item[col.key] ?? \"-\")}\n </td>\n ))}\n </tr>\n ))}\n {/* Empty rows to fill the last page for consistent pagination position */}\n {paginationEnabled &&\n paginatedData.length < pageSize &&\n paginatedData.length > 0 &&\n Array.from({ length: pageSize - paginatedData.length }).map(\n (_, index) => (\n <tr\n key={`empty-${index}`}\n className={`h-17 border-b ${innerBorder} last:border-none ${innerBg} ${alternatingColorEnabled ? `even:${innerBgAlt}` : \"\"}`}\n >\n {columns.map((col) => (\n <td key={col.key} className=\"px-4 py-3 text-sm\">\n \n </td>\n ))}\n </tr>\n ),\n )}\n </>\n )}\n </tbody>\n </table>\n </div>\n\n {/* Pagination */}\n {paginationEnabled && totalPages > 1 && (\n <div\n className={`flex flex-col items-center justify-between gap-2 border-t ${innerBorder} p-${padding} @md:flex-row ${paginationBg} text-${textColor}`}\n >\n <p className=\"text-sm\">\n Showing {(currentPage - 1) * pageSize + 1}-\n {Math.min(currentPage * pageSize, sortedData.length)} of{\" \"}\n {sortedData.length} results\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}\n disabled={currentPage === 1}\n className={`rounded-md border border-${headerBackgroundColor}/60 bg-${headerBackgroundColor} ring-offset-muted placeholder:text-muted-foreground focus-visible:ring-primary px-3 py-1 text-sm transition-opacity hover:opacity-80 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50`}\n >\n Previous\n </button>\n <span className=\"text-sm\">\n Page {currentPage} of {totalPages}\n </span>\n <button\n onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))}\n disabled={currentPage === totalPages}\n className={`rounded-md border border-${headerBackgroundColor}/60 bg-${headerBackgroundColor} ring-offset-muted placeholder:text-muted-foreground focus-visible:ring-primary px-3 py-1 text-sm transition-opacity hover:opacity-80 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50`}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const tableWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"TableWidget\",\n displayName: \"Table Widget\",\n tabsConfig: [\n { id: \"styling\", label: \"Styling\" },\n { id: \"behavior\", label: \"Behavior\" },\n { id: \"data\", label: \"Data\" },\n ],\n dataSourceTargetProps: [\"data\", \"columns\"],\n fields: [\n // Content Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the table\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Title text displayed above the table\",\n defaultValue: \"Products\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n label: \"Title Font Size\",\n defaultValue: \"xl\",\n key: \"titleFontSize\",\n description: \"Font size for the widget title\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling Tab - Design Group\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the table container\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"alternatingColorEnabled\",\n label: \"Enable Alternating Colors\",\n type: \"boolean\",\n description: \"Enable alternating colors for table rows\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n key: \"headerBackgroundColor\",\n label: \"Header Background\",\n description: \"Background color for the table header\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for table content\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"headerTextColor\",\n label: \"Header Text Color\",\n description: \"Text color for the table header\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the table container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the table container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget\",\n defaultValue: \"none\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n\n // Behavior Tab - Features Group\n {\n key: \"filterEnabled\",\n label: \"Enable Filters\",\n type: \"boolean\",\n description: \"Show global search and column filters\",\n defaultValue: true,\n tab: \"behavior\",\n group: \"Features\",\n },\n {\n key: \"sortingEnabled\",\n label: \"Enable Sorting\",\n type: \"boolean\",\n description: \"Allow sorting by clicking column headers\",\n defaultValue: true,\n tab: \"behavior\",\n group: \"Features\",\n },\n {\n key: \"paginationEnabled\",\n label: \"Enable Pagination\",\n type: \"boolean\",\n description: \"Split data into pages\",\n defaultValue: true,\n tab: \"behavior\",\n group: \"Features\",\n },\n {\n key: \"maxRowsPerPage\",\n label: \"Max Rows Per Page\",\n type: \"number\",\n description: \"Maximum number of rows to display per page\",\n min: 1,\n max: 50,\n step: 1,\n defaultValue: 5,\n tab: \"behavior\",\n group: \"Features\",\n requiresKeyToBeTrue: \"paginationEnabled\",\n },\n\n // Data Tab\n {\n key: \"dataSource\",\n label: \"Data Source\",\n type: \"dataSource\",\n description: \"Configure data source for the table\",\n tab: \"data\",\n group: \"Data Configuration\",\n },\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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B;GACnB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EAGF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,KAAK;GACL,MAAM;GACN,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EAGD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACR;EACF;CACF"}
|
|
1
|
+
{"version":3,"file":"TableWidget-D4NBSOmz.mjs","names":[],"sources":["../../widgets/src/widgets/TableWidget.tsx"],"sourcesContent":["import { useState, useMemo, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getBorderWidthField,\n getBorderColorField,\n borderWidthClasses,\n borderColorClasses,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport { Input } from \"@fluid-app/ui-primitives\";\nimport {\n MediaRenderer,\n getMediaPropsFromShareable,\n} from \"../components/MediaRenderer\";\nimport { type ShareableItem } from \"@fluid-app/portal-core/types\";\nimport { useWidgetInteraction } from \"../contexts/WidgetInteractionContext\";\n\n/** Plain column definition provided by data sources (no render functions) */\nexport type TableColumnDef = {\n key: string;\n label: string;\n sortable: boolean;\n};\n\n// Internal column definition (includes render function)\ntype ColumnDef = TableColumnDef & {\n render?: (value: unknown, item: ShareableItem) => React.ReactNode;\n};\n\nconst DEFAULT_DATA: ShareableItem[] = [];\n\n// ---------------------------------------------------------------------------\n// Column cell renderers\n// ---------------------------------------------------------------------------\n\nfunction ImageCellRenderer(_value: unknown, item: ShareableItem) {\n return (\n <div className=\"h-10 w-10 overflow-hidden rounded\">\n <MediaRenderer {...getMediaPropsFromShareable(item)} />\n </div>\n );\n}\n\nfunction PriceCellRenderer(_value: unknown, item: ShareableItem) {\n return ((item.display_price as string) ?? item.price) || \"-\";\n}\n\nfunction StatusCellRenderer(value: unknown) {\n const status = String(value || \"unknown\").toLowerCase();\n const statusStyles: Record<string, string> = {\n active: \"bg-primary text-primary-foreground\",\n paid: \"bg-primary text-primary-foreground\",\n inactive: \"bg-secondary text-secondary-foreground\",\n paused: \"bg-secondary text-secondary-foreground\",\n unknown: \"bg-muted text-muted-foreground\",\n unpaid: \"bg-destructive text-destructive-foreground\",\n refunded: \"bg-muted text-muted-foreground\",\n cancelled: \"bg-destructive text-destructive-foreground\",\n };\n return (\n <span\n className={`inline-flex rounded-full px-2 py-1 text-xs font-medium ${statusStyles[status] || \"bg-muted text-foreground\"}`}\n >\n {String(value || \"Unknown\")}\n </span>\n );\n}\n\n/** Map of column keys to custom cell renderers */\nconst CELL_RENDERERS: Record<\n string,\n (value: unknown, item: ShareableItem) => React.ReactNode\n> = {\n imageUrl: ImageCellRenderer,\n price: PriceCellRenderer,\n display_price: PriceCellRenderer,\n status: StatusCellRenderer,\n};\n\n/** Resolve plain column definitions from a data source into full ColumnDefs with renderers */\nfunction resolveColumns(columns: TableColumnDef[]): ColumnDef[] {\n return columns.map((col) => {\n const render = CELL_RENDERERS[col.key];\n return render ? { ...col, render } : { ...col };\n });\n}\n\n// Default columns for product data\nconst defaultColumns: ColumnDef[] = [\n {\n key: \"imageUrl\",\n label: \"Image\",\n sortable: false,\n render: ImageCellRenderer,\n },\n {\n key: \"title\",\n label: \"Title\",\n sortable: true,\n },\n {\n key: \"price\",\n label: \"Price\",\n sortable: true,\n render: PriceCellRenderer,\n },\n {\n key: \"status\",\n label: \"Status\",\n sortable: true,\n render: StatusCellRenderer,\n },\n];\n\ntype TableWidgetProps = ComponentProps<\"div\"> & {\n // Title\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Styling\n background?: BackgroundValue;\n alternatingColorEnabled?: boolean;\n textColor?: ColorOptions;\n headerBackgroundColor?: ColorOptions;\n headerTextColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n\n // Data\n data?: ShareableItem[];\n /** Column definitions from a data source (plain data, renderers resolved internally) */\n columns?: TableColumnDef[];\n\n // Features\n filterEnabled?: boolean;\n sortingEnabled?: boolean;\n paginationEnabled?: boolean;\n maxRowsPerPage?: number;\n};\n\nexport function TableWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"Products\",\n titleFontSize = \"xl\",\n titleColor = \"foreground\",\n\n // Styling defaults\n background = {\n type: \"solid\",\n color: \"background\",\n },\n alternatingColorEnabled = true,\n textColor = \"foreground\",\n headerBackgroundColor = \"muted\",\n headerTextColor = \"foreground\",\n padding = 4,\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n\n // Data\n data = DEFAULT_DATA,\n columns: columnsProp,\n\n // Feature defaults\n filterEnabled = true,\n sortingEnabled = true,\n paginationEnabled = true,\n maxRowsPerPage = 5,\n\n className,\n ...props\n}: TableWidgetProps): React.JSX.Element {\n const backgroundColor = background.color || \"background\";\n const isImageBackground = background.type === \"image\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n isImageBackground\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n const pageSize = maxRowsPerPage;\n\n // When using an image or transparent background, inner elements should be\n // transparent so the image/page shows through. Otherwise use the configured colors.\n const isTransparentBg = backgroundColor === \"transparent\";\n const useTransparentInner = isImageBackground || isTransparentBg;\n const innerBg = useTransparentInner\n ? \"bg-transparent\"\n : `bg-${backgroundColor}`;\n const innerBgAlt = useTransparentInner\n ? \"bg-black/5\"\n : `bg-${backgroundColor}/40`;\n const transparentBorder = isTransparentBg\n ? \"border-black/20\"\n : \"border-white/20\";\n const innerBorder = useTransparentInner\n ? transparentBorder\n : `border-${backgroundColor}/60`;\n const headerBg = useTransparentInner\n ? \"bg-black/10\"\n : `bg-${headerBackgroundColor}/40`;\n const headerBorder = useTransparentInner\n ? transparentBorder\n : `border-${headerBackgroundColor}/60`;\n const paginationBg = useTransparentInner\n ? \"bg-black/10\"\n : `bg-${backgroundColor}/40`;\n\n // State for filtering, sorting, and pagination\n const [globalFilter, setGlobalFilter] = useState(\"\");\n const [sortConfig, setSortConfig] = useState<{\n key: string;\n direction: \"asc\" | \"desc\";\n } | null>(null);\n const [currentPage, setCurrentPage] = useState(1);\n\n // Only use columns from the data source if they look like valid column defs\n // (have a `key` string). When transformers return a plain array (e.g. toShareableProps),\n // use-widget-data maps the same array to ALL targetProps, so `columns` may\n // receive the data rows instead of column definitions.\n const firstCol = columnsProp?.[0];\n const validColumnsProp =\n firstCol && typeof firstCol.key === \"string\" && firstCol.key !== \"\"\n ? columnsProp\n : undefined;\n\n const columns = useMemo(\n () =>\n validColumnsProp ? resolveColumns(validColumnsProp) : defaultColumns,\n [validColumnsProp],\n );\n\n // Filter data\n const filteredData = useMemo(() => {\n let result = [...data];\n\n if (globalFilter) {\n const lowerFilter = globalFilter.toLowerCase();\n result = result.filter((item) =>\n columns.some((col) => {\n const value = item[col.key];\n return String(value ?? \"\")\n .toLowerCase()\n .includes(lowerFilter);\n }),\n );\n }\n\n return result;\n }, [data, globalFilter, columns]);\n\n // Sort data\n const sortedData = useMemo(() => {\n if (!sortConfig) return filteredData;\n\n return [...filteredData].sort((a, b) => {\n const aValue = a[sortConfig.key];\n const bValue = b[sortConfig.key];\n\n // Handle null/undefined\n if (aValue == null && bValue == null) return 0;\n if (aValue == null) return sortConfig.direction === \"asc\" ? 1 : -1;\n if (bValue == null) return sortConfig.direction === \"asc\" ? -1 : 1;\n\n // Compare values\n let comparison = 0;\n if (typeof aValue === \"number\" && typeof bValue === \"number\") {\n comparison = aValue - bValue;\n } else {\n comparison = String(aValue).localeCompare(String(bValue));\n }\n\n return sortConfig.direction === \"asc\" ? comparison : -comparison;\n });\n }, [filteredData, sortConfig]);\n\n // Paginate data\n const paginatedData = useMemo(() => {\n if (!paginationEnabled) return sortedData;\n\n const startIndex = (currentPage - 1) * pageSize;\n return sortedData.slice(startIndex, startIndex + pageSize);\n }, [sortedData, currentPage, pageSize, paginationEnabled]);\n\n const totalPages = Math.ceil(sortedData.length / pageSize);\n\n // Reset to page 1 when filters change\n const handleGlobalFilterChange = (value: string) => {\n setGlobalFilter(value);\n setCurrentPage(1);\n };\n\n // Handle sort\n const handleSort = (key: string) => {\n if (!sortingEnabled) return;\n\n setSortConfig((prev) => {\n if (prev?.key !== key) return { key, direction: \"asc\" };\n if (prev.direction === \"asc\") return { key, direction: \"desc\" };\n return null;\n });\n };\n\n // Get sort indicator\n const getSortIndicator = (key: string) => {\n if (sortConfig?.key !== key) return null;\n return sortConfig.direction === \"asc\" ? \" ↑\" : \" ↓\";\n };\n\n const { onItemClick } = useWidgetInteraction();\n\n return (\n <div\n className={`@container overflow-hidden ${paginationEnabled ? \"\" : \"overflow-y-auto\"} rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} bg-${backgroundColor} bg-cover bg-center text-${textColor} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n <div\n className={`flex items-center justify-between p-${padding} ${innerBg} space-x-2`}\n >\n {/* Title */}\n {titleEnabled && titleText && (\n <h2\n className={`text-${titleFontSize === \"md\" ? \"base\" : titleFontSize} font-header font-bold text-${titleColor} min-w-0 truncate`}\n >\n {titleText}\n </h2>\n )}\n\n {/* Global Search */}\n {filterEnabled && (\n <Input\n type=\"text\"\n placeholder=\"Search all columns...\"\n value={globalFilter}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n handleGlobalFilterChange(e.target.value)\n }\n className={`w-full rounded-md border ${headerBorder} ${headerBg} ring-offset-muted px-3 py-2 text-sm placeholder:text-${headerTextColor}/40 focus-visible:ring-primary focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none md:w-64`}\n />\n )}\n </div>\n\n {/* Table */}\n <div className=\"overflow-x-auto\">\n <table className=\"w-full border-collapse\">\n <thead>\n <tr className={`${headerBg} ${headerBorder} border-y`}>\n {columns.map((col) => (\n <th\n key={col.key}\n className={`px-4 py-3 text-left text-sm font-semibold text-${headerTextColor} ${col.sortable && sortingEnabled ? \"cursor-pointer select-none hover:opacity-80\" : \"\"}`}\n {...(col.sortable && sortingEnabled\n ? {\n role: \"button\" as const,\n tabIndex: 0,\n onClick: () => handleSort(col.key),\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleSort(col.key);\n }\n },\n }\n : {})}\n >\n <div className=\"flex flex-col gap-1\">\n <span>\n {col.label}\n {col.sortable &&\n sortingEnabled &&\n getSortIndicator(col.key)}\n </span>\n </div>\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.length === 0 ? (\n <tr>\n <td colSpan={columns.length}>\n <div className=\"text-muted-foreground flex min-h-[200px] flex-col items-center justify-center gap-2\">\n <div className=\"text-4xl\">📋</div>\n <p className=\"text-sm\">No data available</p>\n <p className=\"text-muted-foreground/70 text-xs\">\n Connect a data source to display table data\n </p>\n </div>\n </td>\n </tr>\n ) : paginatedData.length === 0 ? (\n <tr>\n <td colSpan={columns.length}>\n <div className=\"py-8 text-center\">\n <p className=\"text-sm\">No results found</p>\n <p className=\"text-xs\">Try adjusting your search</p>\n </div>\n </td>\n </tr>\n ) : (\n <>\n {paginatedData.map((item, index) => (\n <tr\n key={item.id ?? index}\n className={`h-17 border-b ${innerBorder} last:border-none ${innerBg} ${alternatingColorEnabled ? `even:${innerBgAlt}` : \"\"} ${onItemClick ? \"cursor-pointer hover:opacity-80\" : \"\"}`}\n {...(onItemClick\n ? {\n tabIndex: 0,\n onClick: () => onItemClick(item),\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onItemClick(item);\n }\n },\n }\n : {})}\n >\n {columns.map((col) => (\n <td key={col.key} className=\"px-4 py-3 text-sm\">\n {col.render\n ? col.render(item[col.key], item)\n : String(item[col.key] ?? \"-\")}\n </td>\n ))}\n </tr>\n ))}\n {/* Empty rows to fill the last page for consistent pagination position */}\n {paginationEnabled &&\n paginatedData.length < pageSize &&\n paginatedData.length > 0 &&\n Array.from({ length: pageSize - paginatedData.length }).map(\n (_, index) => (\n <tr\n key={`empty-${index}`}\n className={`h-17 border-b ${innerBorder} last:border-none ${innerBg} ${alternatingColorEnabled ? `even:${innerBgAlt}` : \"\"}`}\n >\n {columns.map((col) => (\n <td key={col.key} className=\"px-4 py-3 text-sm\">\n \n </td>\n ))}\n </tr>\n ),\n )}\n </>\n )}\n </tbody>\n </table>\n </div>\n\n {/* Pagination */}\n {paginationEnabled && totalPages > 1 && (\n <div\n className={`flex flex-col items-center justify-between gap-2 border-t ${innerBorder} p-${padding} @md:flex-row ${paginationBg} text-${textColor}`}\n >\n <p className=\"text-sm\">\n Showing {(currentPage - 1) * pageSize + 1}-\n {Math.min(currentPage * pageSize, sortedData.length)} of{\" \"}\n {sortedData.length} results\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}\n disabled={currentPage === 1}\n className={`rounded-md border border-${headerBackgroundColor}/60 bg-${headerBackgroundColor} ring-offset-muted placeholder:text-muted-foreground focus-visible:ring-primary px-3 py-1 text-sm transition-opacity hover:opacity-80 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50`}\n >\n Previous\n </button>\n <span className=\"text-sm\">\n Page {currentPage} of {totalPages}\n </span>\n <button\n onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))}\n disabled={currentPage === totalPages}\n className={`rounded-md border border-${headerBackgroundColor}/60 bg-${headerBackgroundColor} ring-offset-muted placeholder:text-muted-foreground focus-visible:ring-primary px-3 py-1 text-sm transition-opacity hover:opacity-80 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50`}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const tableWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"TableWidget\",\n displayName: \"Table Widget\",\n tabsConfig: [\n { id: \"styling\", label: \"Styling\" },\n { id: \"behavior\", label: \"Behavior\" },\n { id: \"data\", label: \"Data\" },\n ],\n dataSourceTargetProps: [\"data\", \"columns\"],\n fields: [\n // Content Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the table\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Title text displayed above the table\",\n defaultValue: \"Products\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n label: \"Title Font Size\",\n defaultValue: \"xl\",\n key: \"titleFontSize\",\n description: \"Font size for the widget title\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling Tab - Design Group\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the table container\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"alternatingColorEnabled\",\n label: \"Enable Alternating Colors\",\n type: \"boolean\",\n description: \"Enable alternating colors for table rows\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n key: \"headerBackgroundColor\",\n label: \"Header Background\",\n description: \"Background color for the table header\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for table content\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"headerTextColor\",\n label: \"Header Text Color\",\n description: \"Text color for the table header\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the table container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the table container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget\",\n defaultValue: \"none\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n\n // Behavior Tab - Features Group\n {\n key: \"filterEnabled\",\n label: \"Enable Filters\",\n type: \"boolean\",\n description: \"Show global search and column filters\",\n defaultValue: true,\n tab: \"behavior\",\n group: \"Features\",\n },\n {\n key: \"sortingEnabled\",\n label: \"Enable Sorting\",\n type: \"boolean\",\n description: \"Allow sorting by clicking column headers\",\n defaultValue: true,\n tab: \"behavior\",\n group: \"Features\",\n },\n {\n key: \"paginationEnabled\",\n label: \"Enable Pagination\",\n type: \"boolean\",\n description: \"Split data into pages\",\n defaultValue: true,\n tab: \"behavior\",\n group: \"Features\",\n },\n {\n key: \"maxRowsPerPage\",\n label: \"Max Rows Per Page\",\n type: \"number\",\n description: \"Maximum number of rows to display per page\",\n min: 1,\n max: 50,\n step: 1,\n defaultValue: 5,\n tab: \"behavior\",\n group: \"Features\",\n requiresKeyToBeTrue: \"paginationEnabled\",\n },\n\n // Data Tab\n {\n key: \"dataSource\",\n label: \"Data Source\",\n type: \"dataSource\",\n description: \"Configure data source for the table\",\n tab: \"data\",\n group: \"Data Configuration\",\n },\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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B;GACnB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EAGF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,KAAK;GACL,MAAM;GACN,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EAGD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACR;EACF;CACF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { vt as __exportAll } from "./PortalTenantClientProvider-
|
|
1
|
+
import { vt as __exportAll } from "./PortalTenantClientProvider-BmRtQAbi.mjs";
|
|
2
2
|
import { d as getFontWeightField, i as getBorderColorField, l as getColorField, m as getPaddingField, n as borderWidthClasses, o as getBorderRadiusField, s as getBorderWidthField, t as borderColorClasses, u as getFontSizeField } from "./registries-C-t6-veK.mjs";
|
|
3
3
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
import { AlignCenter, AlignLeft, AlignRight } from "lucide-react";
|
|
@@ -218,4 +218,4 @@ const textWidgetPropertySchema = {
|
|
|
218
218
|
//#endregion
|
|
219
219
|
export { TextWidget_exports as n, textWidgetPropertySchema as r, TextWidget as t };
|
|
220
220
|
|
|
221
|
-
//# sourceMappingURL=TextWidget-
|
|
221
|
+
//# sourceMappingURL=TextWidget-B49O04oN.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextWidget-APrOBo5U.mjs","names":[],"sources":["../../widgets/src/widgets/TextWidget.tsx"],"sourcesContent":["import type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport type { ComponentProps } from \"react\";\nimport type React from \"react\";\nimport {\n getBorderRadiusField,\n getBorderWidthField,\n getBorderColorField,\n getColorField,\n getFontSizeField,\n getFontWeightField,\n getPaddingField,\n borderWidthClasses,\n borderColorClasses,\n} from \"../core/fields\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n FontSizeOptions,\n FontWeightOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport { AlignCenter, AlignLeft, AlignRight } from \"lucide-react\";\n\ntype TextAlignment = \"left\" | \"center\" | \"right\";\n\nconst textAlignmentClasses: Record<TextAlignment, string> = {\n left: \"text-left\",\n center: \"text-center\",\n right: \"text-right\",\n} as const;\n\ntype TextWidgetProps = ComponentProps<\"div\"> & {\n // Title\n titleEnabled?: boolean;\n title?: string;\n titleFontSize?: FontSizeOptions;\n titleFontWeight?: FontWeightOptions;\n titleColor?: ColorOptions;\n titleAlignment?: TextAlignment;\n\n // Description\n description?: string;\n descriptionFontSize?: FontSizeOptions;\n descriptionFontWeight?: FontWeightOptions;\n descriptionColor?: ColorOptions;\n descriptionAlignment?: TextAlignment;\n\n // Styling\n background?: BackgroundValue;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n};\n\nexport function TextWidget({\n titleEnabled = true,\n title = \"Text Widget\",\n titleFontSize = \"xl\",\n titleFontWeight = \"bold\",\n titleColor = \"foreground\",\n titleAlignment = \"left\",\n description = \"This is a text widget\",\n descriptionFontSize = \"md\",\n descriptionFontWeight = \"normal\",\n descriptionColor = \"foreground\",\n descriptionAlignment = \"left\",\n background = {\n type: \"solid\",\n color: \"background\",\n },\n padding = 4,\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n className,\n ...props\n}: TextWidgetProps): React.JSX.Element {\n const backgroundColor = background.color || \"background\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n background.type === \"image\"\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n return (\n <div\n className={`bg-${backgroundColor} p-${padding} rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} ${className ?? \"\"}`}\n style={{ backgroundImage }}\n {...props}\n >\n {titleEnabled && (\n <h2\n className={`text-${titleFontSize} text-${titleColor} ${textAlignmentClasses[titleAlignment]} font-header font-${titleFontWeight}`}\n >\n {title}\n </h2>\n )}\n <p\n className={`text-${descriptionFontSize} text-${descriptionColor} ${textAlignmentClasses[descriptionAlignment]} font-${descriptionFontWeight}`}\n >\n {description}\n </p>\n </div>\n );\n}\n\nexport const textWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"TextWidget\",\n displayName: \"Text Widget\",\n tabsConfig: [{ id: \"content\", label: \"Content\" }],\n dataSourceTargetProps: [\"title\", \"description\"],\n fields: [\n // Content Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the text\",\n defaultValue: true,\n tab: \"content\",\n group: \"Title\",\n },\n {\n key: \"title\",\n label: \"Title\",\n type: \"text\",\n description: \"The title\",\n defaultValue: \"Heads up!\",\n tab: \"content\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleFontSize\",\n label: \"Title Font Size\",\n description: \"Font size for the title\",\n defaultValue: \"xl\",\n tab: \"content\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getFontWeightField({\n key: \"titleFontWeight\",\n label: \"Title Font Weight\",\n description: \"Font weight for the title\",\n defaultValue: \"bold\",\n tab: \"content\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"The color of the title\",\n defaultValue: \"foreground\",\n tab: \"content\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n {\n key: \"titleAlignment\",\n label: \"Alignment\",\n type: \"buttonGroup\",\n description: \"Text alignment for the title\",\n options: [\n { icon: AlignLeft, ariaLabel: \"Align left\", value: \"left\" },\n { icon: AlignCenter, ariaLabel: \"Align center\", value: \"center\" },\n { icon: AlignRight, ariaLabel: \"Align right\", value: \"right\" },\n ],\n defaultValue: \"left\",\n tab: \"content\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n // Content Tab - Description Group\n {\n key: \"description\",\n label: \"Description\",\n type: \"textarea\",\n description: \"The text message\",\n rows: 3,\n defaultValue:\n \"You can add components and dependencies to your app using the cli.\",\n tab: \"content\",\n group: \"Description\",\n },\n getFontSizeField({\n key: \"descriptionFontSize\",\n label: \"Description Font Size\",\n description: \"Font size for the text\",\n defaultValue: \"md\",\n tab: \"content\",\n group: \"Description\",\n }),\n getFontWeightField({\n key: \"descriptionFontWeight\",\n label: \"Description Font Weight\",\n description: \"Font weight for the text\",\n defaultValue: \"normal\",\n tab: \"content\",\n group: \"Description\",\n }),\n getColorField({\n key: \"descriptionColor\",\n label: \"Description Color\",\n description: \"The color of the text\",\n defaultValue: \"foreground\",\n tab: \"content\",\n group: \"Description\",\n }),\n {\n key: \"descriptionAlignment\",\n label: \"Alignment\",\n type: \"buttonGroup\",\n description: \"Text alignment for the description\",\n options: [\n { icon: AlignLeft, ariaLabel: \"Align left\", value: \"left\" },\n { icon: AlignCenter, ariaLabel: \"Align center\", value: \"center\" },\n { icon: AlignRight, ariaLabel: \"Align right\", value: \"right\" },\n ],\n defaultValue: \"left\",\n tab: \"content\",\n group: \"Description\",\n },\n // Content Tab - Style Group\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the text container\",\n defaultValue: \"background\",\n tab: \"content\",\n group: \"Style\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"The padding of the text container\",\n defaultValue: 4,\n tab: \"content\",\n group: \"Style\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n description: \"The border radius of the text container\",\n label: \"Border Radius\",\n tab: \"content\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"The border width of the text container\",\n defaultValue: \"none\",\n tab: \"content\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"The border color of the text container\",\n defaultValue: \"muted\",\n tab: \"content\",\n group: \"Design\",\n }),\n ],\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TextWidget-B49O04oN.mjs","names":[],"sources":["../../widgets/src/widgets/TextWidget.tsx"],"sourcesContent":["import type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport type { ComponentProps } from \"react\";\nimport type React from \"react\";\nimport {\n getBorderRadiusField,\n getBorderWidthField,\n getBorderColorField,\n getColorField,\n getFontSizeField,\n getFontWeightField,\n getPaddingField,\n borderWidthClasses,\n borderColorClasses,\n} from \"../core/fields\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n FontSizeOptions,\n FontWeightOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport { AlignCenter, AlignLeft, AlignRight } from \"lucide-react\";\n\ntype TextAlignment = \"left\" | \"center\" | \"right\";\n\nconst textAlignmentClasses: Record<TextAlignment, string> = {\n left: \"text-left\",\n center: \"text-center\",\n right: \"text-right\",\n} as const;\n\ntype TextWidgetProps = ComponentProps<\"div\"> & {\n // Title\n titleEnabled?: boolean;\n title?: string;\n titleFontSize?: FontSizeOptions;\n titleFontWeight?: FontWeightOptions;\n titleColor?: ColorOptions;\n titleAlignment?: TextAlignment;\n\n // Description\n description?: string;\n descriptionFontSize?: FontSizeOptions;\n descriptionFontWeight?: FontWeightOptions;\n descriptionColor?: ColorOptions;\n descriptionAlignment?: TextAlignment;\n\n // Styling\n background?: BackgroundValue;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n};\n\nexport function TextWidget({\n titleEnabled = true,\n title = \"Text Widget\",\n titleFontSize = \"xl\",\n titleFontWeight = \"bold\",\n titleColor = \"foreground\",\n titleAlignment = \"left\",\n description = \"This is a text widget\",\n descriptionFontSize = \"md\",\n descriptionFontWeight = \"normal\",\n descriptionColor = \"foreground\",\n descriptionAlignment = \"left\",\n background = {\n type: \"solid\",\n color: \"background\",\n },\n padding = 4,\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n className,\n ...props\n}: TextWidgetProps): React.JSX.Element {\n const backgroundColor = background.color || \"background\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n background.type === \"image\"\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n return (\n <div\n className={`bg-${backgroundColor} p-${padding} rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} ${className ?? \"\"}`}\n style={{ backgroundImage }}\n {...props}\n >\n {titleEnabled && (\n <h2\n className={`text-${titleFontSize} text-${titleColor} ${textAlignmentClasses[titleAlignment]} font-header font-${titleFontWeight}`}\n >\n {title}\n </h2>\n )}\n <p\n className={`text-${descriptionFontSize} text-${descriptionColor} ${textAlignmentClasses[descriptionAlignment]} font-${descriptionFontWeight}`}\n >\n {description}\n </p>\n </div>\n );\n}\n\nexport const textWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"TextWidget\",\n displayName: \"Text Widget\",\n tabsConfig: [{ id: \"content\", label: \"Content\" }],\n dataSourceTargetProps: [\"title\", \"description\"],\n fields: [\n // Content Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the text\",\n defaultValue: true,\n tab: \"content\",\n group: \"Title\",\n },\n {\n key: \"title\",\n label: \"Title\",\n type: \"text\",\n description: \"The title\",\n defaultValue: \"Heads up!\",\n tab: \"content\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleFontSize\",\n label: \"Title Font Size\",\n description: \"Font size for the title\",\n defaultValue: \"xl\",\n tab: \"content\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getFontWeightField({\n key: \"titleFontWeight\",\n label: \"Title Font Weight\",\n description: \"Font weight for the title\",\n defaultValue: \"bold\",\n tab: \"content\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"The color of the title\",\n defaultValue: \"foreground\",\n tab: \"content\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n {\n key: \"titleAlignment\",\n label: \"Alignment\",\n type: \"buttonGroup\",\n description: \"Text alignment for the title\",\n options: [\n { icon: AlignLeft, ariaLabel: \"Align left\", value: \"left\" },\n { icon: AlignCenter, ariaLabel: \"Align center\", value: \"center\" },\n { icon: AlignRight, ariaLabel: \"Align right\", value: \"right\" },\n ],\n defaultValue: \"left\",\n tab: \"content\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n // Content Tab - Description Group\n {\n key: \"description\",\n label: \"Description\",\n type: \"textarea\",\n description: \"The text message\",\n rows: 3,\n defaultValue:\n \"You can add components and dependencies to your app using the cli.\",\n tab: \"content\",\n group: \"Description\",\n },\n getFontSizeField({\n key: \"descriptionFontSize\",\n label: \"Description Font Size\",\n description: \"Font size for the text\",\n defaultValue: \"md\",\n tab: \"content\",\n group: \"Description\",\n }),\n getFontWeightField({\n key: \"descriptionFontWeight\",\n label: \"Description Font Weight\",\n description: \"Font weight for the text\",\n defaultValue: \"normal\",\n tab: \"content\",\n group: \"Description\",\n }),\n getColorField({\n key: \"descriptionColor\",\n label: \"Description Color\",\n description: \"The color of the text\",\n defaultValue: \"foreground\",\n tab: \"content\",\n group: \"Description\",\n }),\n {\n key: \"descriptionAlignment\",\n label: \"Alignment\",\n type: \"buttonGroup\",\n description: \"Text alignment for the description\",\n options: [\n { icon: AlignLeft, ariaLabel: \"Align left\", value: \"left\" },\n { icon: AlignCenter, ariaLabel: \"Align center\", value: \"center\" },\n { icon: AlignRight, ariaLabel: \"Align right\", value: \"right\" },\n ],\n defaultValue: \"left\",\n tab: \"content\",\n group: \"Description\",\n },\n // Content Tab - Style Group\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the text container\",\n defaultValue: \"background\",\n tab: \"content\",\n group: \"Style\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"The padding of the text container\",\n defaultValue: 4,\n tab: \"content\",\n group: \"Style\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n description: \"The border radius of the text container\",\n label: \"Border Radius\",\n tab: \"content\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"The border width of the text container\",\n defaultValue: \"none\",\n tab: \"content\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"The border color of the text container\",\n defaultValue: \"muted\",\n tab: \"content\",\n group: \"Design\",\n }),\n ],\n};\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { vt as __exportAll } from "./PortalTenantClientProvider-
|
|
1
|
+
import { vt as __exportAll } from "./PortalTenantClientProvider-BmRtQAbi.mjs";
|
|
2
2
|
import { c as useContactsTranslation, o as parseTaskBody, r as useInfiniteContacts, t as TaskComposerForm } from "./task-composer-form-CHyQZUCo.mjs";
|
|
3
3
|
import { n as useDataSourceRegistryConfig } from "./registry-context-BKvTiuXB.mjs";
|
|
4
4
|
import { r as useWidgetsApi, t as ErrorState } from "./error-state-Djgt-RGW.mjs";
|
|
@@ -541,4 +541,4 @@ const toDoWidgetPropertySchema = {
|
|
|
541
541
|
//#endregion
|
|
542
542
|
export { ToDoWidget_exports as n, toDoWidgetPropertySchema as r, ToDoWidget as t };
|
|
543
543
|
|
|
544
|
-
//# sourceMappingURL=ToDoWidget-
|
|
544
|
+
//# sourceMappingURL=ToDoWidget-B3sq5pIT.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToDoWidget-CHsQI_Qk.mjs","names":[],"sources":["../../widgets/src/hooks/use-todos.preview.ts","../../widgets/src/hooks/use-todos.ts","../../widgets/src/hooks/use-update-todo.ts","../../widgets/src/widgets/CreateTodoDialog.tsx","../../widgets/src/widgets/ToDoWidget.tsx"],"sourcesContent":["import type { Todo } from \"@fluid-app/portal-core/widgets-api-types\";\n\nconst now = new Date();\n\nfunction daysFromNow(days: number): string {\n const d = new Date(now);\n d.setDate(d.getDate() + days);\n return d.toISOString();\n}\n\nexport const PREVIEW_DATA: Todo[] = [\n {\n id: 1,\n body: \"Send follow-up email to new leads\",\n dueAt: daysFromNow(1),\n completedAt: null,\n createdAt: daysFromNow(-2),\n contactId: 101,\n contactName: \"Sarah Johnson\",\n },\n {\n id: 2,\n body: \"Prepare slides for team training\",\n dueAt: daysFromNow(3),\n completedAt: null,\n createdAt: daysFromNow(-1),\n contactId: null,\n contactName: null,\n },\n {\n id: 3,\n body: \"Review monthly sales report\",\n dueAt: daysFromNow(-1),\n completedAt: null,\n createdAt: daysFromNow(-5),\n contactId: 102,\n contactName: \"Mike Chen\",\n },\n];\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useWidgetsApi } from \"@fluid-app/portal-core/widgets-api-context\";\nimport { useWidgetPreviewContext } from \"@fluid-app/portal-react/data-sources/preview-context\";\nimport { useDataSourceRegistryConfig } from \"@fluid-app/portal-react/data-sources/registry-context\";\nimport { PREVIEW_DATA } from \"./use-todos.preview\";\nimport type { Todo } from \"@fluid-app/portal-core/widgets-api-types\";\n\nexport type { Todo } from \"@fluid-app/portal-core/widgets-api-types\";\n\n/**\n * Shared cache key for the todos list. Both useTodos (read) and\n * useUpdateTodo (write) use this — drift would silently break optimistic\n * updates.\n */\nexport function todosQueryKey(args: {\n baseUrl: string | undefined;\n isPreview: boolean;\n}) {\n return [\n \"portal-widget-use\",\n \"todos\",\n args.isPreview ? \"preview\" : args.baseUrl,\n ] as const;\n}\n\nexport function useTodos(): UseQueryResult<Todo[], Error> {\n const widgetsApi = useWidgetsApi();\n const { isPreview } = useWidgetPreviewContext();\n const { baseUrl } = useDataSourceRegistryConfig();\n\n return useQuery({\n queryKey: todosQueryKey({ baseUrl, isPreview }),\n queryFn: ({ signal }) => widgetsApi.fetchTodos(signal),\n enabled: !isPreview,\n ...(isPreview && { placeholderData: PREVIEW_DATA }),\n });\n}\n","import { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { useWidgetsApi } from \"@fluid-app/portal-core/widgets-api-context\";\nimport { useWidgetPreviewContext } from \"@fluid-app/portal-react/data-sources/preview-context\";\nimport { useDataSourceRegistryConfig } from \"@fluid-app/portal-react/data-sources/registry-context\";\nimport type { Todo } from \"@fluid-app/portal-core/widgets-api-types\";\nimport { todosQueryKey } from \"./use-todos\";\n\ntype UpdateVariables = { id: number; completed: boolean };\n\nexport function useUpdateTodo() {\n const widgetsApi = useWidgetsApi();\n const queryClient = useQueryClient();\n const { isPreview } = useWidgetPreviewContext();\n const { baseUrl } = useDataSourceRegistryConfig();\n\n const queryKey = todosQueryKey({ baseUrl, isPreview });\n\n return useMutation({\n mutationFn: ({ id, completed }: UpdateVariables) => {\n // Defense in depth: ToDoWidget already disables the checkbox in\n // preview mode, but if any other caller fires this mutation while\n // previewing we'd PATCH demo data on the real backend. Fail closed.\n if (isPreview) {\n return Promise.reject(\n new Error(\"Todo updates are disabled in preview mode\"),\n );\n }\n return widgetsApi.updateTodo(id, completed);\n },\n onMutate: async ({ id, completed }) => {\n await queryClient.cancelQueries({ queryKey });\n const previous = queryClient.getQueryData<Todo[]>(queryKey);\n queryClient.setQueryData<Todo[]>(queryKey, (current) =>\n (current ?? []).map((todo) =>\n todo.id === id\n ? {\n ...todo,\n completedAt: completed ? new Date().toISOString() : null,\n }\n : todo,\n ),\n );\n return { previous };\n },\n onSuccess: (updated, { completed }) => {\n queryClient.setQueryData<Todo[]>(queryKey, (current) =>\n (current ?? []).map((todo) =>\n todo.id === updated.id ? updated : todo,\n ),\n );\n // Match the documented test plan: completing toasts, un-completing\n // is silent. The widget today only ever fires completed=true, but\n // gating here keeps the contract honest for any future caller that\n // toggles either direction.\n if (completed) {\n fluidToast({ title: \"Todo completed\", type: \"success\" });\n }\n },\n onError: (_error, _variables, context) => {\n if (context?.previous) {\n queryClient.setQueryData(queryKey, context.previous);\n }\n fluidToast({ title: \"Failed to update todo\", type: \"error\" });\n },\n // Belt-and-suspenders refetch to reconcile any race we couldn't see\n // (e.g., a different tab mutated the same todo). Cheap — one GET per\n // toggle.\n onSettled: () => {\n queryClient.invalidateQueries({ queryKey });\n },\n });\n}\n","\"use client\";\n\nimport React, { useEffect, useMemo, useRef, useState } from \"react\";\nimport { Check, ChevronsUpDown, Search } from \"lucide-react\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport {\n cn,\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n Input,\n Popover,\n PopoverContent,\n PopoverTrigger,\n PortalContainerProvider,\n} from \"@fluid-app/ui-primitives\";\nimport { useInfiniteContacts } from \"@fluid-app/contacts-core/hooks/use-infinite-contacts\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport type { Contact } from \"@fluid-app/contacts-core/types\";\nimport { TaskComposerForm } from \"@fluid-app/contacts-ui/portal/components/tasks/task-composer-form\";\nimport { useWidgetPreviewContext } from \"@fluid-app/portal-react/data-sources/preview-context\";\nimport { useDataSourceRegistryConfig } from \"@fluid-app/portal-react/data-sources/registry-context\";\nimport { todosQueryKey } from \"../hooks/use-todos\";\n\nconst SEARCH_DEBOUNCE_MS = 200;\n\nexport interface CreateTodoDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}\n\nexport function CreateTodoDialog({\n open,\n onOpenChange,\n}: CreateTodoDialogProps): React.JSX.Element {\n const queryClient = useQueryClient();\n const { isPreview } = useWidgetPreviewContext();\n const { baseUrl } = useDataSourceRegistryConfig();\n const [selectedContact, setSelectedContact] = useState<Contact | null>(null);\n // Anchor the popover's portal inside the dialog. Dialog applies\n // pointer-events: none to the body while open, which kills clicks and\n // scroll on a body-portaled popover in WebKit. See edit-bill-date-dialog\n // for the canonical pattern.\n const [popoverContainer, setPopoverContainer] =\n useState<HTMLDivElement | null>(null);\n\n // Reset state when the dialog closes so the next open starts fresh.\n useEffect(() => {\n if (!open) setSelectedContact(null);\n }, [open]);\n\n const handleDone = () => {\n queryClient.invalidateQueries({\n queryKey: todosQueryKey({ baseUrl, isPreview }),\n });\n onOpenChange(false);\n };\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"sm:max-w-md\">\n <DialogHeader>\n <DialogTitle>Add a to-do</DialogTitle>\n </DialogHeader>\n\n <PortalContainerProvider container={popoverContainer}>\n <div className=\"mt-2 flex flex-col gap-3\">\n <ContactPicker\n value={selectedContact}\n onSelect={setSelectedContact}\n />\n\n {selectedContact && (\n <TaskComposerForm\n key={selectedContact.id}\n contactId={String(selectedContact.id)}\n onDone={handleDone}\n />\n )}\n </div>\n </PortalContainerProvider>\n {/* Portal target for the popover. Must live INSIDE DialogContent so\n it ends up in the dialog's body-level portal — otherwise it\n renders inline next to the widget, and any transformed ancestor\n (builder canvas zoom, etc.) would break `position: fixed`.\n Intentionally NOT aria-hidden — the popover content portaled\n into this container has its own listbox/option semantics that\n screen readers need to reach. `pointer-events-none` keeps the\n empty overlay from capturing clicks; the popover content sets\n `pointer-events-auto` so it remains interactive. */}\n <div\n ref={setPopoverContainer}\n className=\"pointer-events-none fixed inset-0 z-[9998]\"\n />\n </DialogContent>\n </Dialog>\n );\n}\n\ninterface ContactPickerProps {\n value: Contact | null;\n onSelect: (contact: Contact) => void;\n}\n\nfunction ContactPicker({\n value,\n onSelect,\n}: ContactPickerProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const [open, setOpen] = useState(false);\n const [searchInput, setSearchInput] = useState(\"\");\n const [debouncedSearch, setDebouncedSearch] = useState(\"\");\n const sentinelRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const handle = window.setTimeout(() => {\n setDebouncedSearch(searchInput.trim());\n }, SEARCH_DEBOUNCE_MS);\n return () => window.clearTimeout(handle);\n }, [searchInput]);\n\n const queryParams = useMemo(\n () => ({\n ...(debouncedSearch ? { search_query: debouncedSearch } : {}),\n sort_by: \"full_name\",\n sort_direction: \"asc\",\n per_page: 25,\n }),\n [debouncedSearch],\n );\n\n const {\n data,\n isLoading,\n isError,\n hasNextPage,\n isFetchingNextPage,\n fetchNextPage,\n } = useInfiniteContacts(queryParams);\n\n const contacts: Contact[] = useMemo(\n () => data?.pages.flatMap((page) => page.contacts ?? []) ?? [],\n [data],\n );\n\n // Auto-load the next page when the sentinel scrolls into view, so reps\n // with many contacts can reach all of them without typing a precise\n // search query.\n useEffect(() => {\n const sentinel = sentinelRef.current;\n if (!sentinel || !hasNextPage) return;\n\n const observer = new IntersectionObserver((entries) => {\n const entry = entries[0];\n if (entry?.isIntersecting && !isFetchingNextPage) {\n fetchNextPage();\n }\n });\n\n observer.observe(sentinel);\n return () => observer.disconnect();\n }, [hasNextPage, isFetchingNextPage, fetchNextPage]);\n\n return (\n <div className=\"flex flex-col gap-1\">\n <label className=\"text-muted-foreground text-xs font-medium\">\n {t(\"contact_label\")}\n </label>\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n className=\"border-input bg-background hover:bg-muted/40 flex w-full items-center justify-between gap-2 rounded-md border px-3 py-2 text-left text-sm transition-colors\"\n >\n <span\n className={cn(\n \"truncate\",\n !value && \"text-muted-foreground font-normal\",\n )}\n >\n {value ? value.full_name : t(\"empty_select_contact\")}\n </span>\n <ChevronsUpDown\n className=\"text-muted-foreground size-4 shrink-0\"\n aria-hidden=\"true\"\n />\n </button>\n </PopoverTrigger>\n <PopoverContent\n align=\"start\"\n className=\"bg-popover text-popover-foreground pointer-events-auto z-[9999] w-(--radix-popover-trigger-width) overflow-hidden rounded-md border p-0 shadow-md\"\n >\n <div className=\"border-border flex items-center gap-2 border-b px-3 py-2\">\n <Search\n className=\"text-muted-foreground size-4 shrink-0\"\n aria-hidden=\"true\"\n />\n <Input\n value={searchInput}\n onChange={(e) => setSearchInput(e.target.value)}\n placeholder={t(\"search_placeholder\")}\n aria-label={t(\"search_placeholder\")}\n className=\"h-7 border-0 px-0 shadow-none focus-visible:ring-0\"\n />\n </div>\n <div className=\"max-h-64 overflow-y-auto py-1\" role=\"listbox\">\n {isLoading ? (\n <div className=\"text-muted-foreground px-3 py-6 text-center text-xs\">\n {t(\"loading\")}\n </div>\n ) : isError ? (\n <div className=\"text-destructive px-3 py-6 text-center text-xs\">\n {t(\"error_loading_list\")}\n </div>\n ) : contacts.length === 0 ? (\n <div className=\"text-muted-foreground px-3 py-6 text-center text-xs\">\n {debouncedSearch\n ? t(\"no_contacts_search\", { term: debouncedSearch })\n : t(\"no_contacts_yet\")}\n </div>\n ) : (\n <>\n {contacts.map((contact) => {\n const isSelected = value?.id === contact.id;\n return (\n <button\n key={contact.id}\n type=\"button\"\n role=\"option\"\n aria-selected={isSelected}\n onClick={() => {\n onSelect(contact);\n setOpen(false);\n }}\n className=\"hover:bg-muted/50 flex w-full items-center justify-between gap-2 px-3 py-1.5 text-left text-sm transition-colors\"\n >\n <span className=\"truncate\">{contact.full_name}</span>\n {isSelected && (\n <Check\n className=\"text-primary size-4 shrink-0\"\n aria-hidden=\"true\"\n />\n )}\n </button>\n );\n })}\n {hasNextPage && (\n <div ref={sentinelRef} aria-hidden=\"true\" className=\"h-4\" />\n )}\n {isFetchingNextPage && (\n <div className=\"text-muted-foreground px-3 py-2 text-center text-xs\">\n {t(\"loading_more\")}\n </div>\n )}\n </>\n )}\n </div>\n </PopoverContent>\n </Popover>\n </div>\n );\n}\n","import { useState, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getBorderWidthField,\n getBorderColorField,\n borderWidthClasses,\n borderColorClasses,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport { ListChecks, Plus } from \"lucide-react\";\nimport { useWidgetPreviewContext } from \"@fluid-app/portal-react/data-sources/preview-context\";\nimport { parseTaskBody } from \"@fluid-app/contacts-core/parse-task-body\";\nimport { useTodos } from \"../hooks/use-todos\";\nimport { useUpdateTodo } from \"../hooks/use-update-todo\";\nimport { ErrorState } from \"../components/error-state\";\nimport { CreateTodoDialog } from \"./CreateTodoDialog\";\n\ntype ToDoWidgetProps = ComponentProps<\"div\"> & {\n // Title\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Styling\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n\n // Content\n maxItems?: number;\n};\n\nexport function ToDoWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"To-Do\",\n titleFontSize = \"lg\",\n titleColor = \"foreground\",\n\n // Styling defaults\n background = {\n type: \"solid\",\n color: \"background\",\n },\n textColor = \"foreground\",\n accentColor = \"primary\",\n padding = 4,\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n\n // Content defaults\n maxItems = 5,\n\n className,\n ...props\n}: ToDoWidgetProps): React.JSX.Element {\n const backgroundColor = background.color || \"background\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n background.type === \"image\"\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n const { data: todos = [], isLoading, isError } = useTodos();\n const updateTodo = useUpdateTodo();\n const { isPreview } = useWidgetPreviewContext();\n const [pendingIds, setPendingIds] = useState<Set<number>>(new Set());\n const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);\n\n const toggleTodo = (id: number, completed: boolean) => {\n if (isPreview || pendingIds.has(id)) return;\n setPendingIds((prev) => new Set(prev).add(id));\n updateTodo.mutate(\n { id, completed },\n {\n onSettled: () =>\n setPendingIds((prev) => {\n const next = new Set(prev);\n next.delete(id);\n return next;\n }),\n },\n );\n };\n\n const activeTodos = todos.filter((todo) => !todo.completedAt);\n const todosToShow = activeTodos.slice(0, maxItems);\n const remainingCount = activeTodos.length - todosToShow.length;\n const isEmpty = activeTodos.length === 0;\n\n // Group todos by contactId so same-named contacts stay separate.\n const groupedTodos = todosToShow.reduce<\n {\n contactId: number | null;\n contactName: string | null;\n todos: typeof todosToShow;\n }[]\n >((groups, todo) => {\n const existing = groups.find((g) => g.contactId === todo.contactId);\n if (existing) {\n existing.todos.push(todo);\n } else {\n groups.push({\n contactId: todo.contactId,\n contactName: todo.contactName,\n todos: [todo],\n });\n }\n return groups;\n }, []);\n\n return (\n <div\n className={`overflow-hidden rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} bg-${backgroundColor} text-${textColor} p-${padding} ${className ?? \"\"}`}\n style={{ backgroundImage }}\n {...props}\n >\n {/* Header */}\n <div className=\"mb-3 flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n {titleEnabled && titleText && (\n <h2\n className={`text-${titleFontSize} font-header font-bold text-${titleColor}`}\n >\n {titleText}\n </h2>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n {!isEmpty && !isLoading && (\n <span className={`text-2xl font-bold text-${accentColor}`}>\n {activeTodos.length}\n </span>\n )}\n <div\n className={`flex h-10 w-10 shrink-0 items-center justify-center`}\n >\n <ListChecks className={`h-5 w-5 text-${accentColor}-foreground`} />\n </div>\n </div>\n </div>\n\n {/* Loading state */}\n {isLoading ? (\n <div className=\"flex min-h-[120px] items-center justify-center\">\n <div className=\"h-6 w-6 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n </div>\n ) : isError ? (\n /* Error state */\n <ErrorState />\n ) : isEmpty ? (\n /* Empty state */\n <div className=\"flex flex-col items-center justify-center gap-3 py-8\">\n <p className={`text-center text-${textColor}/60`}>\n You've got nothing else To-Do!\n </p>\n {!isPreview && (\n <button\n type=\"button\"\n onClick={() => setIsCreateDialogOpen(true)}\n className={`inline-flex items-center gap-1.5 rounded-full bg-${accentColor} text-${accentColor}-foreground hover:bg-${accentColor}/90 px-4 py-1.5 text-xs font-semibold transition-colors`}\n >\n <Plus className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />\n Add to-do\n </button>\n )}\n </div>\n ) : (\n /* Todo List */\n <>\n <div className=\"flex flex-col gap-3\">\n {groupedTodos.map((group) => (\n <div\n key={group.contactId ?? \"__unassigned__\"}\n className=\"flex flex-col\"\n >\n {group.contactName && (\n <div\n className={`mb-1 text-xs font-semibold tracking-wide uppercase text-${textColor}/60`}\n >\n {group.contactName}\n </div>\n )}\n {group.todos.map((todo, index) => (\n <div\n key={todo.id}\n className={`flex items-center gap-3 py-2 ${\n index !== group.todos.length - 1\n ? `border-b border-${textColor}/10`\n : \"\"\n }`}\n >\n <input\n type=\"checkbox\"\n className={`h-5 w-5 rounded-full border-2 border-${textColor}/30 bg-transparent not-disabled:cursor-pointer disabled:cursor-not-allowed disabled:opacity-60`}\n checked={!!todo.completedAt}\n disabled={isPreview || pendingIds.has(todo.id)}\n onChange={(event) =>\n toggleTodo(todo.id, event.target.checked)\n }\n />\n <span className=\"line-clamp-1 flex-1 text-sm\">\n {parseTaskBody(todo.body).title}\n </span>\n </div>\n ))}\n </div>\n ))}\n </div>\n\n {/* Footer */}\n <div className=\"mt-2 flex items-center justify-between\">\n {remainingCount > 0 && (\n <span className={`text-sm text-${textColor}/50 underline`}>\n {remainingCount} more task{remainingCount > 1 ? \"s\" : \"\"}\n </span>\n )}\n <div className=\"ml-auto\">\n <button\n type=\"button\"\n onClick={() => setIsCreateDialogOpen(true)}\n disabled={isPreview}\n aria-label=\"Add to-do\"\n className={`flex h-8 w-8 items-center justify-center rounded-full transition-colors not-disabled:cursor-pointer hover:bg-${textColor}/10 disabled:opacity-60`}\n >\n <Plus className={`h-5 w-5 text-${textColor}/50`} />\n </button>\n </div>\n </div>\n </>\n )}\n\n {!isPreview && (\n <CreateTodoDialog\n open={isCreateDialogOpen}\n onOpenChange={setIsCreateDialogOpen}\n />\n )}\n </div>\n );\n}\n\nexport const toDoWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"ToDoWidget\",\n displayName: \"To-Do Widget\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [\n // Styling Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the todo list\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Title text displayed above the todo list\",\n defaultValue: \"To-Do\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleFontSize\",\n label: \"Title Font Size\",\n description: \"Font size for the widget title\",\n defaultValue: \"xl\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling Tab - Design Group\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the widget container\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for todo items\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description: \"Color used for count badge and icon\",\n defaultValue: \"primary\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"maxItems\",\n label: \"Max Items\",\n type: \"number\",\n description: \"Maximum number of todo items to display\",\n min: 1,\n max: 20,\n step: 1,\n defaultValue: 5,\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the widget container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the widget container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget\",\n defaultValue: \"none\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ToDoWidget-B3sq5pIT.mjs","names":[],"sources":["../../widgets/src/hooks/use-todos.preview.ts","../../widgets/src/hooks/use-todos.ts","../../widgets/src/hooks/use-update-todo.ts","../../widgets/src/widgets/CreateTodoDialog.tsx","../../widgets/src/widgets/ToDoWidget.tsx"],"sourcesContent":["import type { Todo } from \"@fluid-app/portal-core/widgets-api-types\";\n\nconst now = new Date();\n\nfunction daysFromNow(days: number): string {\n const d = new Date(now);\n d.setDate(d.getDate() + days);\n return d.toISOString();\n}\n\nexport const PREVIEW_DATA: Todo[] = [\n {\n id: 1,\n body: \"Send follow-up email to new leads\",\n dueAt: daysFromNow(1),\n completedAt: null,\n createdAt: daysFromNow(-2),\n contactId: 101,\n contactName: \"Sarah Johnson\",\n },\n {\n id: 2,\n body: \"Prepare slides for team training\",\n dueAt: daysFromNow(3),\n completedAt: null,\n createdAt: daysFromNow(-1),\n contactId: null,\n contactName: null,\n },\n {\n id: 3,\n body: \"Review monthly sales report\",\n dueAt: daysFromNow(-1),\n completedAt: null,\n createdAt: daysFromNow(-5),\n contactId: 102,\n contactName: \"Mike Chen\",\n },\n];\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useWidgetsApi } from \"@fluid-app/portal-core/widgets-api-context\";\nimport { useWidgetPreviewContext } from \"@fluid-app/portal-react/data-sources/preview-context\";\nimport { useDataSourceRegistryConfig } from \"@fluid-app/portal-react/data-sources/registry-context\";\nimport { PREVIEW_DATA } from \"./use-todos.preview\";\nimport type { Todo } from \"@fluid-app/portal-core/widgets-api-types\";\n\nexport type { Todo } from \"@fluid-app/portal-core/widgets-api-types\";\n\n/**\n * Shared cache key for the todos list. Both useTodos (read) and\n * useUpdateTodo (write) use this — drift would silently break optimistic\n * updates.\n */\nexport function todosQueryKey(args: {\n baseUrl: string | undefined;\n isPreview: boolean;\n}) {\n return [\n \"portal-widget-use\",\n \"todos\",\n args.isPreview ? \"preview\" : args.baseUrl,\n ] as const;\n}\n\nexport function useTodos(): UseQueryResult<Todo[], Error> {\n const widgetsApi = useWidgetsApi();\n const { isPreview } = useWidgetPreviewContext();\n const { baseUrl } = useDataSourceRegistryConfig();\n\n return useQuery({\n queryKey: todosQueryKey({ baseUrl, isPreview }),\n queryFn: ({ signal }) => widgetsApi.fetchTodos(signal),\n enabled: !isPreview,\n ...(isPreview && { placeholderData: PREVIEW_DATA }),\n });\n}\n","import { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { useWidgetsApi } from \"@fluid-app/portal-core/widgets-api-context\";\nimport { useWidgetPreviewContext } from \"@fluid-app/portal-react/data-sources/preview-context\";\nimport { useDataSourceRegistryConfig } from \"@fluid-app/portal-react/data-sources/registry-context\";\nimport type { Todo } from \"@fluid-app/portal-core/widgets-api-types\";\nimport { todosQueryKey } from \"./use-todos\";\n\ntype UpdateVariables = { id: number; completed: boolean };\n\nexport function useUpdateTodo() {\n const widgetsApi = useWidgetsApi();\n const queryClient = useQueryClient();\n const { isPreview } = useWidgetPreviewContext();\n const { baseUrl } = useDataSourceRegistryConfig();\n\n const queryKey = todosQueryKey({ baseUrl, isPreview });\n\n return useMutation({\n mutationFn: ({ id, completed }: UpdateVariables) => {\n // Defense in depth: ToDoWidget already disables the checkbox in\n // preview mode, but if any other caller fires this mutation while\n // previewing we'd PATCH demo data on the real backend. Fail closed.\n if (isPreview) {\n return Promise.reject(\n new Error(\"Todo updates are disabled in preview mode\"),\n );\n }\n return widgetsApi.updateTodo(id, completed);\n },\n onMutate: async ({ id, completed }) => {\n await queryClient.cancelQueries({ queryKey });\n const previous = queryClient.getQueryData<Todo[]>(queryKey);\n queryClient.setQueryData<Todo[]>(queryKey, (current) =>\n (current ?? []).map((todo) =>\n todo.id === id\n ? {\n ...todo,\n completedAt: completed ? new Date().toISOString() : null,\n }\n : todo,\n ),\n );\n return { previous };\n },\n onSuccess: (updated, { completed }) => {\n queryClient.setQueryData<Todo[]>(queryKey, (current) =>\n (current ?? []).map((todo) =>\n todo.id === updated.id ? updated : todo,\n ),\n );\n // Match the documented test plan: completing toasts, un-completing\n // is silent. The widget today only ever fires completed=true, but\n // gating here keeps the contract honest for any future caller that\n // toggles either direction.\n if (completed) {\n fluidToast({ title: \"Todo completed\", type: \"success\" });\n }\n },\n onError: (_error, _variables, context) => {\n if (context?.previous) {\n queryClient.setQueryData(queryKey, context.previous);\n }\n fluidToast({ title: \"Failed to update todo\", type: \"error\" });\n },\n // Belt-and-suspenders refetch to reconcile any race we couldn't see\n // (e.g., a different tab mutated the same todo). Cheap — one GET per\n // toggle.\n onSettled: () => {\n queryClient.invalidateQueries({ queryKey });\n },\n });\n}\n","\"use client\";\n\nimport React, { useEffect, useMemo, useRef, useState } from \"react\";\nimport { Check, ChevronsUpDown, Search } from \"lucide-react\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport {\n cn,\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n Input,\n Popover,\n PopoverContent,\n PopoverTrigger,\n PortalContainerProvider,\n} from \"@fluid-app/ui-primitives\";\nimport { useInfiniteContacts } from \"@fluid-app/contacts-core/hooks/use-infinite-contacts\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport type { Contact } from \"@fluid-app/contacts-core/types\";\nimport { TaskComposerForm } from \"@fluid-app/contacts-ui/portal/components/tasks/task-composer-form\";\nimport { useWidgetPreviewContext } from \"@fluid-app/portal-react/data-sources/preview-context\";\nimport { useDataSourceRegistryConfig } from \"@fluid-app/portal-react/data-sources/registry-context\";\nimport { todosQueryKey } from \"../hooks/use-todos\";\n\nconst SEARCH_DEBOUNCE_MS = 200;\n\nexport interface CreateTodoDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}\n\nexport function CreateTodoDialog({\n open,\n onOpenChange,\n}: CreateTodoDialogProps): React.JSX.Element {\n const queryClient = useQueryClient();\n const { isPreview } = useWidgetPreviewContext();\n const { baseUrl } = useDataSourceRegistryConfig();\n const [selectedContact, setSelectedContact] = useState<Contact | null>(null);\n // Anchor the popover's portal inside the dialog. Dialog applies\n // pointer-events: none to the body while open, which kills clicks and\n // scroll on a body-portaled popover in WebKit. See edit-bill-date-dialog\n // for the canonical pattern.\n const [popoverContainer, setPopoverContainer] =\n useState<HTMLDivElement | null>(null);\n\n // Reset state when the dialog closes so the next open starts fresh.\n useEffect(() => {\n if (!open) setSelectedContact(null);\n }, [open]);\n\n const handleDone = () => {\n queryClient.invalidateQueries({\n queryKey: todosQueryKey({ baseUrl, isPreview }),\n });\n onOpenChange(false);\n };\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"sm:max-w-md\">\n <DialogHeader>\n <DialogTitle>Add a to-do</DialogTitle>\n </DialogHeader>\n\n <PortalContainerProvider container={popoverContainer}>\n <div className=\"mt-2 flex flex-col gap-3\">\n <ContactPicker\n value={selectedContact}\n onSelect={setSelectedContact}\n />\n\n {selectedContact && (\n <TaskComposerForm\n key={selectedContact.id}\n contactId={String(selectedContact.id)}\n onDone={handleDone}\n />\n )}\n </div>\n </PortalContainerProvider>\n {/* Portal target for the popover. Must live INSIDE DialogContent so\n it ends up in the dialog's body-level portal — otherwise it\n renders inline next to the widget, and any transformed ancestor\n (builder canvas zoom, etc.) would break `position: fixed`.\n Intentionally NOT aria-hidden — the popover content portaled\n into this container has its own listbox/option semantics that\n screen readers need to reach. `pointer-events-none` keeps the\n empty overlay from capturing clicks; the popover content sets\n `pointer-events-auto` so it remains interactive. */}\n <div\n ref={setPopoverContainer}\n className=\"pointer-events-none fixed inset-0 z-[9998]\"\n />\n </DialogContent>\n </Dialog>\n );\n}\n\ninterface ContactPickerProps {\n value: Contact | null;\n onSelect: (contact: Contact) => void;\n}\n\nfunction ContactPicker({\n value,\n onSelect,\n}: ContactPickerProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const [open, setOpen] = useState(false);\n const [searchInput, setSearchInput] = useState(\"\");\n const [debouncedSearch, setDebouncedSearch] = useState(\"\");\n const sentinelRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const handle = window.setTimeout(() => {\n setDebouncedSearch(searchInput.trim());\n }, SEARCH_DEBOUNCE_MS);\n return () => window.clearTimeout(handle);\n }, [searchInput]);\n\n const queryParams = useMemo(\n () => ({\n ...(debouncedSearch ? { search_query: debouncedSearch } : {}),\n sort_by: \"full_name\",\n sort_direction: \"asc\",\n per_page: 25,\n }),\n [debouncedSearch],\n );\n\n const {\n data,\n isLoading,\n isError,\n hasNextPage,\n isFetchingNextPage,\n fetchNextPage,\n } = useInfiniteContacts(queryParams);\n\n const contacts: Contact[] = useMemo(\n () => data?.pages.flatMap((page) => page.contacts ?? []) ?? [],\n [data],\n );\n\n // Auto-load the next page when the sentinel scrolls into view, so reps\n // with many contacts can reach all of them without typing a precise\n // search query.\n useEffect(() => {\n const sentinel = sentinelRef.current;\n if (!sentinel || !hasNextPage) return;\n\n const observer = new IntersectionObserver((entries) => {\n const entry = entries[0];\n if (entry?.isIntersecting && !isFetchingNextPage) {\n fetchNextPage();\n }\n });\n\n observer.observe(sentinel);\n return () => observer.disconnect();\n }, [hasNextPage, isFetchingNextPage, fetchNextPage]);\n\n return (\n <div className=\"flex flex-col gap-1\">\n <label className=\"text-muted-foreground text-xs font-medium\">\n {t(\"contact_label\")}\n </label>\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n className=\"border-input bg-background hover:bg-muted/40 flex w-full items-center justify-between gap-2 rounded-md border px-3 py-2 text-left text-sm transition-colors\"\n >\n <span\n className={cn(\n \"truncate\",\n !value && \"text-muted-foreground font-normal\",\n )}\n >\n {value ? value.full_name : t(\"empty_select_contact\")}\n </span>\n <ChevronsUpDown\n className=\"text-muted-foreground size-4 shrink-0\"\n aria-hidden=\"true\"\n />\n </button>\n </PopoverTrigger>\n <PopoverContent\n align=\"start\"\n className=\"bg-popover text-popover-foreground pointer-events-auto z-[9999] w-(--radix-popover-trigger-width) overflow-hidden rounded-md border p-0 shadow-md\"\n >\n <div className=\"border-border flex items-center gap-2 border-b px-3 py-2\">\n <Search\n className=\"text-muted-foreground size-4 shrink-0\"\n aria-hidden=\"true\"\n />\n <Input\n value={searchInput}\n onChange={(e) => setSearchInput(e.target.value)}\n placeholder={t(\"search_placeholder\")}\n aria-label={t(\"search_placeholder\")}\n className=\"h-7 border-0 px-0 shadow-none focus-visible:ring-0\"\n />\n </div>\n <div className=\"max-h-64 overflow-y-auto py-1\" role=\"listbox\">\n {isLoading ? (\n <div className=\"text-muted-foreground px-3 py-6 text-center text-xs\">\n {t(\"loading\")}\n </div>\n ) : isError ? (\n <div className=\"text-destructive px-3 py-6 text-center text-xs\">\n {t(\"error_loading_list\")}\n </div>\n ) : contacts.length === 0 ? (\n <div className=\"text-muted-foreground px-3 py-6 text-center text-xs\">\n {debouncedSearch\n ? t(\"no_contacts_search\", { term: debouncedSearch })\n : t(\"no_contacts_yet\")}\n </div>\n ) : (\n <>\n {contacts.map((contact) => {\n const isSelected = value?.id === contact.id;\n return (\n <button\n key={contact.id}\n type=\"button\"\n role=\"option\"\n aria-selected={isSelected}\n onClick={() => {\n onSelect(contact);\n setOpen(false);\n }}\n className=\"hover:bg-muted/50 flex w-full items-center justify-between gap-2 px-3 py-1.5 text-left text-sm transition-colors\"\n >\n <span className=\"truncate\">{contact.full_name}</span>\n {isSelected && (\n <Check\n className=\"text-primary size-4 shrink-0\"\n aria-hidden=\"true\"\n />\n )}\n </button>\n );\n })}\n {hasNextPage && (\n <div ref={sentinelRef} aria-hidden=\"true\" className=\"h-4\" />\n )}\n {isFetchingNextPage && (\n <div className=\"text-muted-foreground px-3 py-2 text-center text-xs\">\n {t(\"loading_more\")}\n </div>\n )}\n </>\n )}\n </div>\n </PopoverContent>\n </Popover>\n </div>\n );\n}\n","import { useState, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getBorderWidthField,\n getBorderColorField,\n borderWidthClasses,\n borderColorClasses,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport { ListChecks, Plus } from \"lucide-react\";\nimport { useWidgetPreviewContext } from \"@fluid-app/portal-react/data-sources/preview-context\";\nimport { parseTaskBody } from \"@fluid-app/contacts-core/parse-task-body\";\nimport { useTodos } from \"../hooks/use-todos\";\nimport { useUpdateTodo } from \"../hooks/use-update-todo\";\nimport { ErrorState } from \"../components/error-state\";\nimport { CreateTodoDialog } from \"./CreateTodoDialog\";\n\ntype ToDoWidgetProps = ComponentProps<\"div\"> & {\n // Title\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Styling\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n\n // Content\n maxItems?: number;\n};\n\nexport function ToDoWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"To-Do\",\n titleFontSize = \"lg\",\n titleColor = \"foreground\",\n\n // Styling defaults\n background = {\n type: \"solid\",\n color: \"background\",\n },\n textColor = \"foreground\",\n accentColor = \"primary\",\n padding = 4,\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n\n // Content defaults\n maxItems = 5,\n\n className,\n ...props\n}: ToDoWidgetProps): React.JSX.Element {\n const backgroundColor = background.color || \"background\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n background.type === \"image\"\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n const { data: todos = [], isLoading, isError } = useTodos();\n const updateTodo = useUpdateTodo();\n const { isPreview } = useWidgetPreviewContext();\n const [pendingIds, setPendingIds] = useState<Set<number>>(new Set());\n const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);\n\n const toggleTodo = (id: number, completed: boolean) => {\n if (isPreview || pendingIds.has(id)) return;\n setPendingIds((prev) => new Set(prev).add(id));\n updateTodo.mutate(\n { id, completed },\n {\n onSettled: () =>\n setPendingIds((prev) => {\n const next = new Set(prev);\n next.delete(id);\n return next;\n }),\n },\n );\n };\n\n const activeTodos = todos.filter((todo) => !todo.completedAt);\n const todosToShow = activeTodos.slice(0, maxItems);\n const remainingCount = activeTodos.length - todosToShow.length;\n const isEmpty = activeTodos.length === 0;\n\n // Group todos by contactId so same-named contacts stay separate.\n const groupedTodos = todosToShow.reduce<\n {\n contactId: number | null;\n contactName: string | null;\n todos: typeof todosToShow;\n }[]\n >((groups, todo) => {\n const existing = groups.find((g) => g.contactId === todo.contactId);\n if (existing) {\n existing.todos.push(todo);\n } else {\n groups.push({\n contactId: todo.contactId,\n contactName: todo.contactName,\n todos: [todo],\n });\n }\n return groups;\n }, []);\n\n return (\n <div\n className={`overflow-hidden rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} bg-${backgroundColor} text-${textColor} p-${padding} ${className ?? \"\"}`}\n style={{ backgroundImage }}\n {...props}\n >\n {/* Header */}\n <div className=\"mb-3 flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n {titleEnabled && titleText && (\n <h2\n className={`text-${titleFontSize} font-header font-bold text-${titleColor}`}\n >\n {titleText}\n </h2>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n {!isEmpty && !isLoading && (\n <span className={`text-2xl font-bold text-${accentColor}`}>\n {activeTodos.length}\n </span>\n )}\n <div\n className={`flex h-10 w-10 shrink-0 items-center justify-center`}\n >\n <ListChecks className={`h-5 w-5 text-${accentColor}-foreground`} />\n </div>\n </div>\n </div>\n\n {/* Loading state */}\n {isLoading ? (\n <div className=\"flex min-h-[120px] items-center justify-center\">\n <div className=\"h-6 w-6 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n </div>\n ) : isError ? (\n /* Error state */\n <ErrorState />\n ) : isEmpty ? (\n /* Empty state */\n <div className=\"flex flex-col items-center justify-center gap-3 py-8\">\n <p className={`text-center text-${textColor}/60`}>\n You've got nothing else To-Do!\n </p>\n {!isPreview && (\n <button\n type=\"button\"\n onClick={() => setIsCreateDialogOpen(true)}\n className={`inline-flex items-center gap-1.5 rounded-full bg-${accentColor} text-${accentColor}-foreground hover:bg-${accentColor}/90 px-4 py-1.5 text-xs font-semibold transition-colors`}\n >\n <Plus className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />\n Add to-do\n </button>\n )}\n </div>\n ) : (\n /* Todo List */\n <>\n <div className=\"flex flex-col gap-3\">\n {groupedTodos.map((group) => (\n <div\n key={group.contactId ?? \"__unassigned__\"}\n className=\"flex flex-col\"\n >\n {group.contactName && (\n <div\n className={`mb-1 text-xs font-semibold tracking-wide uppercase text-${textColor}/60`}\n >\n {group.contactName}\n </div>\n )}\n {group.todos.map((todo, index) => (\n <div\n key={todo.id}\n className={`flex items-center gap-3 py-2 ${\n index !== group.todos.length - 1\n ? `border-b border-${textColor}/10`\n : \"\"\n }`}\n >\n <input\n type=\"checkbox\"\n className={`h-5 w-5 rounded-full border-2 border-${textColor}/30 bg-transparent not-disabled:cursor-pointer disabled:cursor-not-allowed disabled:opacity-60`}\n checked={!!todo.completedAt}\n disabled={isPreview || pendingIds.has(todo.id)}\n onChange={(event) =>\n toggleTodo(todo.id, event.target.checked)\n }\n />\n <span className=\"line-clamp-1 flex-1 text-sm\">\n {parseTaskBody(todo.body).title}\n </span>\n </div>\n ))}\n </div>\n ))}\n </div>\n\n {/* Footer */}\n <div className=\"mt-2 flex items-center justify-between\">\n {remainingCount > 0 && (\n <span className={`text-sm text-${textColor}/50 underline`}>\n {remainingCount} more task{remainingCount > 1 ? \"s\" : \"\"}\n </span>\n )}\n <div className=\"ml-auto\">\n <button\n type=\"button\"\n onClick={() => setIsCreateDialogOpen(true)}\n disabled={isPreview}\n aria-label=\"Add to-do\"\n className={`flex h-8 w-8 items-center justify-center rounded-full transition-colors not-disabled:cursor-pointer hover:bg-${textColor}/10 disabled:opacity-60`}\n >\n <Plus className={`h-5 w-5 text-${textColor}/50`} />\n </button>\n </div>\n </div>\n </>\n )}\n\n {!isPreview && (\n <CreateTodoDialog\n open={isCreateDialogOpen}\n onOpenChange={setIsCreateDialogOpen}\n />\n )}\n </div>\n );\n}\n\nexport const toDoWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"ToDoWidget\",\n displayName: \"To-Do Widget\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [\n // Styling Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the todo list\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Title text displayed above the todo list\",\n defaultValue: \"To-Do\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleFontSize\",\n label: \"Title Font Size\",\n description: \"Font size for the widget title\",\n defaultValue: \"xl\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling Tab - Design Group\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the widget container\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for todo items\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description: \"Color used for count badge and icon\",\n defaultValue: \"primary\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"maxItems\",\n label: \"Max Items\",\n type: \"number\",\n description: \"Maximum number of todo items to display\",\n min: 1,\n max: 20,\n step: 1,\n defaultValue: 5,\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the widget container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the widget container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget\",\n defaultValue: \"none\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { vt as __exportAll } from "./PortalTenantClientProvider-
|
|
1
|
+
import { vt as __exportAll } from "./PortalTenantClientProvider-BmRtQAbi.mjs";
|
|
2
2
|
import { a as useActiveLocale, n as createDomainTranslations, r as useDomainDict, t as createStaticDictAdapter } from "./static-dict-adapter-Z_42w_55.mjs";
|
|
3
3
|
import { t as createTranslationContext } from "./translation-api-context-factory-Cq-pFTiQ.mjs";
|
|
4
4
|
import { Dt as CardHeader, Ot as CardTitle, St as Card, Tt as CardDescription, wn as Button } from "./src-DC5QoBhR.mjs";
|
|
@@ -194,4 +194,4 @@ function UpgradeScreen() {
|
|
|
194
194
|
//#endregion
|
|
195
195
|
export { UpgradeScreen_exports as t };
|
|
196
196
|
|
|
197
|
-
//# sourceMappingURL=UpgradeScreen-
|
|
197
|
+
//# sourceMappingURL=UpgradeScreen-DGJsj2Yx.mjs.map
|