@rozaqi02/reusable-dashboard 1.0.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -91,28 +91,32 @@ var cidikaWidgetConfig = {
91
91
  label: "confirmedBookings",
92
92
  icon: "TrendingUp",
93
93
  valueKey: "bookingsConfirm",
94
- format: "number"
94
+ format: "number",
95
+ accentColor: "blue"
95
96
  },
96
97
  {
97
98
  id: "revenueConfirm",
98
99
  label: "confirmedRevenue",
99
100
  icon: "DollarSign",
100
101
  valueKey: "revenueConfirm",
101
- format: "currency"
102
+ format: "currency",
103
+ accentColor: "green"
102
104
  },
103
105
  {
104
106
  id: "avgRevenue",
105
107
  label: "avgRevenue",
106
108
  icon: "Users",
107
109
  valueKey: "avgRevenue",
108
- format: "currency"
110
+ format: "currency",
111
+ accentColor: "violet"
109
112
  },
110
113
  {
111
114
  id: "conversionRate",
112
115
  label: "conversionRate",
113
116
  icon: "PieChart",
114
117
  valueKey: "conversionRate",
115
- format: "percent"
118
+ format: "percent",
119
+ accentColor: "orange"
116
120
  }
117
121
  ],
118
122
  charts: [
@@ -238,28 +242,32 @@ var tokoSepatuWidgetConfig = {
238
242
  label: "confirmedBookings",
239
243
  icon: "TrendingUp",
240
244
  valueKey: "bookingsConfirm",
241
- format: "number"
245
+ format: "number",
246
+ accentColor: "sky"
242
247
  },
243
248
  {
244
249
  id: "totalRevenue",
245
250
  label: "confirmedRevenue",
246
251
  icon: "DollarSign",
247
252
  valueKey: "revenueConfirm",
248
- format: "currency"
253
+ format: "currency",
254
+ accentColor: "green"
249
255
  },
250
256
  {
251
257
  id: "avgOrderValue",
252
258
  label: "avgRevenue",
253
259
  icon: "BarChart3",
254
260
  valueKey: "avgRevenue",
255
- format: "currency"
261
+ format: "currency",
262
+ accentColor: "violet"
256
263
  },
257
264
  {
258
265
  id: "totalProducts",
259
266
  label: "totalProducts",
260
267
  icon: "PieChart",
261
268
  valueKey: "packages",
262
- format: "number"
269
+ format: "number",
270
+ accentColor: "orange"
263
271
  }
264
272
  ],
265
273
  charts: [
@@ -1094,42 +1102,20 @@ function Button({
1094
1102
  children,
1095
1103
  ...rest
1096
1104
  }) {
1097
- const base = "inline-flex items-center justify-center font-medium rounded-xl transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed";
1098
- const variants = {
1099
- primary: "bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500",
1100
- secondary: "border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 text-slate-700 dark:text-slate-200 hover:bg-slate-50 dark:hover:bg-slate-700 focus:ring-slate-400",
1101
- ghost: "text-slate-600 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-800 focus:ring-slate-400"
1102
- };
1103
- const sizes = {
1104
- sm: "px-2.5 py-1 text-xs gap-1",
1105
- md: "px-3 py-1.5 text-sm gap-1.5",
1106
- lg: "px-4 py-2 text-base gap-2"
1107
- };
1108
- const classes = [base, variants[variant] || variants.primary, sizes[size] || sizes.md, className].filter(Boolean).join(" ");
1109
- return /* @__PURE__ */ import_react3.default.createElement(
1110
- "button",
1111
- {
1112
- type: "button",
1113
- className: classes,
1114
- disabled,
1115
- onClick,
1116
- ...rest
1117
- },
1118
- children
1119
- );
1105
+ const classes = [
1106
+ "rdb-btn",
1107
+ `rdb-btn-${variant}`,
1108
+ `rdb-btn-${size}`,
1109
+ className
1110
+ ].filter(Boolean).join(" ");
1111
+ return /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", className: classes, disabled, onClick, ...rest }, children);
1120
1112
  }
1121
1113
  Button.propTypes = {
1122
- /** Varian visual tombol. */
1123
1114
  variant: import_prop_types.default.oneOf(["primary", "secondary", "ghost"]),
1124
- /** Ukuran tombol. */
1125
1115
  size: import_prop_types.default.oneOf(["sm", "md", "lg"]),
1126
- /** Apakah tombol non-aktif. */
1127
1116
  disabled: import_prop_types.default.bool,
1128
- /** ClassName tambahan dari consumer. */
1129
1117
  className: import_prop_types.default.string,
1130
- /** Callback saat tombol diklik. */
1131
1118
  onClick: import_prop_types.default.func,
1132
- /** Konten tombol. */
1133
1119
  children: import_prop_types.default.node.isRequired
1134
1120
  };
1135
1121
 
@@ -1146,14 +1132,7 @@ function Input({
1146
1132
  className = "",
1147
1133
  ...rest
1148
1134
  }) {
1149
- const inputClasses = [
1150
- "px-3 py-2 rounded-2xl border border-slate-300 dark:border-slate-600",
1151
- "bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100",
1152
- "text-sm transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500",
1153
- "disabled:opacity-50 disabled:cursor-not-allowed",
1154
- className
1155
- ].filter(Boolean).join(" ");
1156
- return /* @__PURE__ */ import_react4.default.createElement("div", { className: "flex flex-col gap-1" }, label ? /* @__PURE__ */ import_react4.default.createElement("label", { className: "text-xs font-medium text-slate-500 dark:text-slate-400" }, label) : null, /* @__PURE__ */ import_react4.default.createElement(
1135
+ return /* @__PURE__ */ import_react4.default.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 4 } }, label ? /* @__PURE__ */ import_react4.default.createElement("label", { className: "rdb-label" }, label) : null, /* @__PURE__ */ import_react4.default.createElement(
1157
1136
  "input",
1158
1137
  {
1159
1138
  type,
@@ -1161,25 +1140,18 @@ function Input({
1161
1140
  onChange,
1162
1141
  placeholder,
1163
1142
  disabled,
1164
- className: inputClasses,
1143
+ className: ["rdb-input", className].filter(Boolean).join(" "),
1165
1144
  ...rest
1166
1145
  }
1167
1146
  ));
1168
1147
  }
1169
1148
  Input.propTypes = {
1170
- /** Tipe input. */
1171
1149
  type: import_prop_types2.default.string,
1172
- /** Nilai input. */
1173
1150
  value: import_prop_types2.default.oneOfType([import_prop_types2.default.string, import_prop_types2.default.number]),
1174
- /** Callback saat nilai berubah. */
1175
1151
  onChange: import_prop_types2.default.func,
1176
- /** Placeholder teks. */
1177
1152
  placeholder: import_prop_types2.default.string,
1178
- /** Label di atas input. */
1179
1153
  label: import_prop_types2.default.string,
1180
- /** Apakah input non-aktif. */
1181
1154
  disabled: import_prop_types2.default.bool,
1182
- /** ClassName tambahan. */
1183
1155
  className: import_prop_types2.default.string
1184
1156
  };
1185
1157
 
@@ -1222,116 +1194,108 @@ Icon.propTypes = {
1222
1194
  // src/presentation/atoms/Typography.jsx
1223
1195
  var import_react6 = __toESM(require("react"), 1);
1224
1196
  var import_prop_types4 = __toESM(require("prop-types"), 1);
1225
- var VARIANT_MAP = {
1226
- h1: { tag: "h1", className: "text-2xl sm:text-3xl font-bold" },
1227
- h2: { tag: "h2", className: "text-xl sm:text-2xl font-bold" },
1228
- h3: { tag: "h3", className: "text-lg font-semibold" },
1229
- subheading: { tag: "p", className: "text-sm font-medium text-slate-500 dark:text-slate-400" },
1230
- body: { tag: "p", className: "text-sm text-slate-700 dark:text-slate-300" },
1231
- caption: { tag: "span", className: "text-xs text-slate-500 dark:text-slate-400" },
1232
- metric: { tag: "span", className: "text-3xl font-bold text-slate-900 dark:text-slate-100" }
1197
+ var VARIANT_CLASS = {
1198
+ h1: "rdb-h1",
1199
+ h2: "rdb-h2",
1200
+ h3: "rdb-h3",
1201
+ subheading: "rdb-subheading",
1202
+ body: "rdb-body",
1203
+ caption: "rdb-caption",
1204
+ metric: "rdb-metric"
1233
1205
  };
1234
- function Typography({
1235
- variant = "body",
1236
- className = "",
1237
- children,
1238
- ...rest
1239
- }) {
1240
- const config = VARIANT_MAP[variant] || VARIANT_MAP.body;
1241
- const Tag = config.tag;
1242
- const classes = [config.className, className].filter(Boolean).join(" ");
1243
- return /* @__PURE__ */ import_react6.default.createElement(Tag, { className: classes, ...rest }, children);
1206
+ var VARIANT_TAG = {
1207
+ h1: "h1",
1208
+ h2: "h2",
1209
+ h3: "h3",
1210
+ subheading: "p",
1211
+ body: "p",
1212
+ caption: "span",
1213
+ metric: "span"
1214
+ };
1215
+ function Typography({ variant = "body", className = "", children, ...rest }) {
1216
+ const Tag = VARIANT_TAG[variant] || "p";
1217
+ const cls = [VARIANT_CLASS[variant] || "rdb-body", className].filter(Boolean).join(" ");
1218
+ return /* @__PURE__ */ import_react6.default.createElement(Tag, { className: cls, ...rest }, children);
1244
1219
  }
1245
1220
  Typography.propTypes = {
1246
- /** Varian tipografi. */
1247
1221
  variant: import_prop_types4.default.oneOf(["h1", "h2", "h3", "subheading", "body", "caption", "metric"]),
1248
- /** ClassName tambahan. */
1249
1222
  className: import_prop_types4.default.string,
1250
- /** Konten teks. */
1251
1223
  children: import_prop_types4.default.node.isRequired
1252
1224
  };
1253
1225
 
1254
1226
  // src/presentation/atoms/Badge.jsx
1255
1227
  var import_react7 = __toESM(require("react"), 1);
1256
1228
  var import_prop_types5 = __toESM(require("prop-types"), 1);
1257
- var STATUS_CLASSES = {
1258
- confirmed: "bg-green-100 text-green-800 dark:bg-green-900/50 dark:text-green-200",
1259
- pending: "bg-yellow-100 text-yellow-800 dark:bg-yellow-900/50 dark:text-yellow-200",
1260
- cancelled: "bg-red-100 text-red-800 dark:bg-red-900/50 dark:text-red-200",
1261
- default: "bg-slate-100 text-slate-800 dark:bg-slate-700 dark:text-slate-200",
1262
- success: "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300",
1263
- info: "bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300"
1229
+ var STATUS_CLASS = {
1230
+ confirmed: "rdb-badge-confirmed",
1231
+ pending: "rdb-badge-pending",
1232
+ cancelled: "rdb-badge-cancelled",
1233
+ success: "rdb-badge-success",
1234
+ info: "rdb-badge-info",
1235
+ default: "rdb-badge-default"
1264
1236
  };
1265
1237
  function Badge({ status = "default", className = "", children, ...rest }) {
1266
- const colorClass = STATUS_CLASSES[status] || STATUS_CLASSES.default;
1267
- const classes = ["px-2 py-1 rounded-full text-xs font-medium", colorClass, className].filter(Boolean).join(" ");
1268
- return /* @__PURE__ */ import_react7.default.createElement("span", { className: classes, ...rest }, children);
1238
+ const statusClass = STATUS_CLASS[status] || STATUS_CLASS.default;
1239
+ return /* @__PURE__ */ import_react7.default.createElement("span", { className: ["rdb-badge", statusClass, className].filter(Boolean).join(" "), ...rest }, children);
1269
1240
  }
1270
1241
  Badge.propTypes = {
1271
- /** Status yang menentukan warna badge. */
1272
1242
  status: import_prop_types5.default.string,
1273
- /** ClassName tambahan. */
1274
1243
  className: import_prop_types5.default.string,
1275
- /** Label teks badge. */
1276
1244
  children: import_prop_types5.default.node.isRequired
1277
1245
  };
1278
1246
 
1279
1247
  // src/presentation/atoms/SkeletonLoader.jsx
1280
1248
  var import_react8 = __toESM(require("react"), 1);
1281
1249
  var import_prop_types6 = __toESM(require("prop-types"), 1);
1282
- function SkeletonLoader({ className = "" }) {
1250
+ function SkeletonLoader({ className = "", style = {} }) {
1283
1251
  return /* @__PURE__ */ import_react8.default.createElement(
1284
1252
  "div",
1285
1253
  {
1286
- className: `animate-pulse bg-slate-200 dark:bg-slate-700 rounded-xl ${className}`,
1254
+ className: ["rdb-skeleton", className].filter(Boolean).join(" "),
1255
+ style: { minHeight: 20, ...style },
1287
1256
  role: "status",
1288
1257
  "aria-label": "Loading..."
1289
1258
  }
1290
1259
  );
1291
1260
  }
1292
1261
  SkeletonLoader.propTypes = {
1293
- /** ClassName tambahan untuk mengatur ukuran skeleton (misal: "h-28", "h-64"). */
1294
- className: import_prop_types6.default.string
1262
+ className: import_prop_types6.default.string,
1263
+ style: import_prop_types6.default.object
1295
1264
  };
1296
1265
 
1297
1266
  // src/presentation/molecules/StatCard.jsx
1298
1267
  var import_react9 = __toESM(require("react"), 1);
1299
1268
  var import_prop_types7 = __toESM(require("prop-types"), 1);
1269
+ function renderValue(format, value) {
1270
+ if (format === "currency") return `Rp ${formatIDR(value)}`;
1271
+ if (format === "percent") return `${Number(value) || 0}%`;
1272
+ return String(Number(value) || 0);
1273
+ }
1300
1274
  function StatCard({
1301
1275
  label,
1302
1276
  value,
1303
1277
  icon = "TrendingUp",
1304
1278
  format = "number",
1305
1279
  trend = null,
1280
+ accentColor = "blue",
1306
1281
  className = ""
1307
1282
  }) {
1308
- const formattedValue = renderValue(format, value);
1309
- return /* @__PURE__ */ import_react9.default.createElement("div", { className: `card p-4 flex flex-col justify-between gap-2 ${className}` }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center gap-2 text-slate-500 dark:text-slate-400" }, /* @__PURE__ */ import_react9.default.createElement(Icon, { name: icon, size: 20 }), /* @__PURE__ */ import_react9.default.createElement(Typography, { variant: "subheading" }, label)), trend ? /* @__PURE__ */ import_react9.default.createElement(
1283
+ return /* @__PURE__ */ import_react9.default.createElement("div", { className: ["rdb-card rdb-statcard", `rdb-accent-${accentColor}`, className].filter(Boolean).join(" ") }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "rdb-statcard-header" }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "rdb-statcard-label-group" }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "rdb-statcard-icon" }, /* @__PURE__ */ import_react9.default.createElement(Icon, { name: icon, size: 16 })), /* @__PURE__ */ import_react9.default.createElement("span", { className: "rdb-statcard-label" }, label)), trend ? /* @__PURE__ */ import_react9.default.createElement(
1310
1284
  Icon,
1311
1285
  {
1312
1286
  name: trend === "up" ? "TrendingUp" : "TrendingDown",
1313
1287
  size: 16,
1314
- className: trend === "up" ? "text-emerald-500" : "text-red-500"
1288
+ style: { color: trend === "up" ? "#10b981" : "#ef4444" }
1315
1289
  }
1316
- ) : null), /* @__PURE__ */ import_react9.default.createElement(Typography, { variant: "metric" }, formattedValue));
1317
- }
1318
- function renderValue(format, value) {
1319
- if (format === "currency") return `Rp ${formatIDR(value)}`;
1320
- if (format === "percent") return `${Number(value) || 0}%`;
1321
- return String(Number(value) || 0);
1290
+ ) : null), /* @__PURE__ */ import_react9.default.createElement("div", { className: "rdb-statcard-value" }, renderValue(format, value)));
1322
1291
  }
1323
1292
  StatCard.propTypes = {
1324
- /** Label deskriptif metrik. */
1325
1293
  label: import_prop_types7.default.string.isRequired,
1326
- /** Nilai metrik. */
1327
1294
  value: import_prop_types7.default.oneOfType([import_prop_types7.default.number, import_prop_types7.default.string]),
1328
- /** Nama ikon dari registry Lucide React. */
1329
1295
  icon: import_prop_types7.default.string,
1330
- /** Format tampilan nilai. */
1331
1296
  format: import_prop_types7.default.oneOf(["number", "currency", "percent"]),
1332
- /** Arah tren opsional. */
1333
1297
  trend: import_prop_types7.default.oneOf(["up", "down", null]),
1334
- /** ClassName tambahan. */
1298
+ accentColor: import_prop_types7.default.string,
1335
1299
  className: import_prop_types7.default.string
1336
1300
  };
1337
1301
 
@@ -1348,45 +1312,33 @@ function SearchBar({
1348
1312
  const [internalValue, setInternalValue] = (0, import_react10.useState)("");
1349
1313
  const isControlled = controlledValue !== void 0;
1350
1314
  const currentValue = isControlled ? controlledValue : internalValue;
1351
- const handleChange = (0, import_react10.useCallback)(
1352
- (event) => {
1353
- const newValue = event.target.value;
1354
- if (!isControlled) setInternalValue(newValue);
1355
- if (onChange) onChange(newValue);
1356
- if (onSearch) onSearch(newValue);
1357
- },
1358
- [isControlled, onChange, onSearch]
1359
- );
1360
- const handleKeyDown = (0, import_react10.useCallback)(
1361
- (event) => {
1362
- if (event.key === "Enter" && onSearch) {
1363
- onSearch(currentValue);
1364
- }
1365
- },
1366
- [currentValue, onSearch]
1367
- );
1368
- return /* @__PURE__ */ import_react10.default.createElement("div", { className: `relative ${className}` }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "absolute inset-y-0 left-3 flex items-center pointer-events-none" }, /* @__PURE__ */ import_react10.default.createElement(Icon, { name: "Search", size: 16, className: "text-slate-400" })), /* @__PURE__ */ import_react10.default.createElement(
1369
- Input,
1315
+ const handleChange = (0, import_react10.useCallback)((event) => {
1316
+ const v = event.target.value;
1317
+ if (!isControlled) setInternalValue(v);
1318
+ if (onChange) onChange(v);
1319
+ if (onSearch) onSearch(v);
1320
+ }, [isControlled, onChange, onSearch]);
1321
+ const handleKeyDown = (0, import_react10.useCallback)((event) => {
1322
+ if (event.key === "Enter" && onSearch) onSearch(currentValue);
1323
+ }, [currentValue, onSearch]);
1324
+ return /* @__PURE__ */ import_react10.default.createElement("div", { className: ["rdb-searchbar", className].filter(Boolean).join(" ") }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "rdb-searchbar-icon" }, /* @__PURE__ */ import_react10.default.createElement(Icon, { name: "Search", size: 16 })), /* @__PURE__ */ import_react10.default.createElement(
1325
+ "input",
1370
1326
  {
1371
1327
  type: "search",
1372
1328
  value: currentValue,
1373
1329
  onChange: handleChange,
1374
1330
  onKeyDown: handleKeyDown,
1375
1331
  placeholder,
1376
- className: "pl-9 w-full"
1332
+ className: "rdb-input rdb-searchbar-input",
1333
+ style: { width: "100%" }
1377
1334
  }
1378
1335
  ));
1379
1336
  }
1380
1337
  SearchBar.propTypes = {
1381
- /** Nilai pencarian saat ini (controlled). */
1382
1338
  value: import_prop_types8.default.string,
1383
- /** Callback saat nilai input berubah. */
1384
1339
  onChange: import_prop_types8.default.func,
1385
- /** Callback saat pencarian disubmit. */
1386
1340
  onSearch: import_prop_types8.default.func,
1387
- /** Placeholder teks. */
1388
1341
  placeholder: import_prop_types8.default.string,
1389
- /** ClassName tambahan. */
1390
1342
  className: import_prop_types8.default.string
1391
1343
  };
1392
1344
 
@@ -1396,26 +1348,11 @@ var import_prop_types9 = __toESM(require("prop-types"), 1);
1396
1348
  var CURRENT_YEAR = (/* @__PURE__ */ new Date()).getFullYear();
1397
1349
  var MIN_YEAR2 = 2020;
1398
1350
  var MAX_YEAR = CURRENT_YEAR + 1;
1399
- var MONTHS = [
1400
- "Jan",
1401
- "Feb",
1402
- "Mar",
1403
- "Apr",
1404
- "May",
1405
- "Jun",
1406
- "Jul",
1407
- "Aug",
1408
- "Sep",
1409
- "Oct",
1410
- "Nov",
1411
- "Dec"
1412
- ];
1351
+ var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
1413
1352
  function getYears() {
1414
- const years = [];
1415
- for (let y = MAX_YEAR; y >= MIN_YEAR2; y--) {
1416
- years.push(y);
1417
- }
1418
- return years;
1353
+ const y = [];
1354
+ for (let i = MAX_YEAR; i >= MIN_YEAR2; i--) y.push(i);
1355
+ return y;
1419
1356
  }
1420
1357
  function getDaysInMonth(year, month) {
1421
1358
  return new Date(year, month, 0).getDate();
@@ -1423,68 +1360,57 @@ function getDaysInMonth(year, month) {
1423
1360
  function parseDate(value) {
1424
1361
  if (value && /^\d{4}-\d{2}-\d{2}$/.test(value)) {
1425
1362
  const [y, m, d] = value.split("-").map(Number);
1426
- if (y >= MIN_YEAR2 && y <= MAX_YEAR && m >= 1 && m <= 12) {
1363
+ if (y >= MIN_YEAR2 && y <= MAX_YEAR && m >= 1 && m <= 12)
1427
1364
  return { year: y, month: m, day: d };
1428
- }
1429
1365
  }
1430
1366
  const now = /* @__PURE__ */ new Date();
1431
1367
  return { year: now.getFullYear(), month: now.getMonth() + 1, day: now.getDate() };
1432
1368
  }
1433
- function formatDate2({ year, month, day }) {
1369
+ function fmt({ year, month, day }) {
1434
1370
  return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
1435
1371
  }
1436
1372
  function DatePicker({ value, onChange, disabled = false, label = "" }) {
1437
- const parsed = parseDate(value);
1373
+ const p = parseDate(value);
1438
1374
  const years = getYears();
1439
- const maxDay = getDaysInMonth(parsed.year, parsed.month);
1440
- const handleChange = (0, import_react11.useCallback)(
1441
- (field, newVal) => {
1442
- const updated = { ...parsed, [field]: Number(newVal) };
1443
- const maxD = getDaysInMonth(updated.year, updated.month);
1444
- if (updated.day > maxD) updated.day = maxD;
1445
- onChange(formatDate2(updated));
1446
- },
1447
- [parsed, onChange]
1448
- );
1449
- const selectClass = "px-2 py-1.5 rounded-xl border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed";
1450
- return /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex flex-col gap-1" }, label ? /* @__PURE__ */ import_react11.default.createElement(Typography, { variant: "caption", className: "font-medium" }, label) : null, /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react11.default.createElement(
1375
+ const maxDay = getDaysInMonth(p.year, p.month);
1376
+ const handleChange = (0, import_react11.useCallback)((field, val) => {
1377
+ const u = { ...p, [field]: Number(val) };
1378
+ const max = getDaysInMonth(u.year, u.month);
1379
+ if (u.day > max) u.day = max;
1380
+ onChange(fmt(u));
1381
+ }, [p, onChange]);
1382
+ return /* @__PURE__ */ import_react11.default.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 2 } }, label ? /* @__PURE__ */ import_react11.default.createElement("span", { className: "rdb-caption rdb-label" }, label) : null, /* @__PURE__ */ import_react11.default.createElement("div", { style: { display: "flex", gap: 4, alignItems: "center" } }, /* @__PURE__ */ import_react11.default.createElement(
1451
1383
  "select",
1452
1384
  {
1453
- className: selectClass,
1454
- value: parsed.day,
1385
+ className: "rdb-select",
1386
+ style: { width: 52 },
1387
+ value: p.day,
1455
1388
  onChange: (e) => handleChange("day", e.target.value),
1456
- disabled,
1457
- "aria-label": `${label} day`
1389
+ disabled
1458
1390
  },
1459
1391
  Array.from({ length: maxDay }, (_, i) => i + 1).map((d) => /* @__PURE__ */ import_react11.default.createElement("option", { key: d, value: d }, String(d).padStart(2, "0")))
1460
1392
  ), /* @__PURE__ */ import_react11.default.createElement(
1461
1393
  "select",
1462
1394
  {
1463
- className: selectClass,
1464
- value: parsed.month,
1395
+ className: "rdb-select",
1396
+ style: { width: 62 },
1397
+ value: p.month,
1465
1398
  onChange: (e) => handleChange("month", e.target.value),
1466
- disabled,
1467
- "aria-label": `${label} month`
1399
+ disabled
1468
1400
  },
1469
1401
  MONTHS.map((name, idx) => /* @__PURE__ */ import_react11.default.createElement("option", { key: idx + 1, value: idx + 1 }, name))
1470
1402
  ), /* @__PURE__ */ import_react11.default.createElement(
1471
1403
  "select",
1472
1404
  {
1473
- className: selectClass,
1474
- value: parsed.year,
1405
+ className: "rdb-select",
1406
+ style: { width: 72 },
1407
+ value: p.year,
1475
1408
  onChange: (e) => handleChange("year", e.target.value),
1476
- disabled,
1477
- "aria-label": `${label} year`
1409
+ disabled
1478
1410
  },
1479
1411
  years.map((y) => /* @__PURE__ */ import_react11.default.createElement("option", { key: y, value: y }, y))
1480
1412
  )));
1481
1413
  }
1482
- DatePicker.propTypes = {
1483
- value: import_prop_types9.default.string.isRequired,
1484
- onChange: import_prop_types9.default.func.isRequired,
1485
- disabled: import_prop_types9.default.bool,
1486
- label: import_prop_types9.default.string
1487
- };
1488
1414
  function DateRangeFilter({
1489
1415
  dateFrom,
1490
1416
  dateTo,
@@ -1494,31 +1420,9 @@ function DateRangeFilter({
1494
1420
  labelTo = "To",
1495
1421
  className = ""
1496
1422
  }) {
1497
- const handleFromChange = (0, import_react11.useCallback)(
1498
- (newDate) => onRangeChange == null ? void 0 : onRangeChange({ dateFrom: newDate, dateTo }),
1499
- [dateTo, onRangeChange]
1500
- );
1501
- const handleToChange = (0, import_react11.useCallback)(
1502
- (newDate) => onRangeChange == null ? void 0 : onRangeChange({ dateFrom, dateTo: newDate }),
1503
- [dateFrom, onRangeChange]
1504
- );
1505
- return /* @__PURE__ */ import_react11.default.createElement("div", { className: `flex flex-wrap items-end gap-3 ${className}` }, /* @__PURE__ */ import_react11.default.createElement(
1506
- DatePicker,
1507
- {
1508
- value: dateFrom,
1509
- onChange: handleFromChange,
1510
- disabled,
1511
- label: labelFrom
1512
- }
1513
- ), /* @__PURE__ */ import_react11.default.createElement(
1514
- DatePicker,
1515
- {
1516
- value: dateTo,
1517
- onChange: handleToChange,
1518
- disabled,
1519
- label: labelTo
1520
- }
1521
- ));
1423
+ const handleFrom = (0, import_react11.useCallback)((v) => onRangeChange == null ? void 0 : onRangeChange({ dateFrom: v, dateTo }), [dateTo, onRangeChange]);
1424
+ const handleTo = (0, import_react11.useCallback)((v) => onRangeChange == null ? void 0 : onRangeChange({ dateFrom, dateTo: v }), [dateFrom, onRangeChange]);
1425
+ return /* @__PURE__ */ import_react11.default.createElement("div", { className: ["rdb-daterange", className].filter(Boolean).join(" ") }, /* @__PURE__ */ import_react11.default.createElement(DatePicker, { value: dateFrom, onChange: handleFrom, disabled, label: labelFrom }), /* @__PURE__ */ import_react11.default.createElement(DatePicker, { value: dateTo, onChange: handleTo, disabled, label: labelTo }));
1522
1426
  }
1523
1427
  DateRangeFilter.propTypes = {
1524
1428
  dateFrom: import_prop_types9.default.string.isRequired,
@@ -1533,22 +1437,13 @@ DateRangeFilter.propTypes = {
1533
1437
  // src/presentation/molecules/ChartHeader.jsx
1534
1438
  var import_react12 = __toESM(require("react"), 1);
1535
1439
  var import_prop_types10 = __toESM(require("prop-types"), 1);
1536
- function ChartHeader({
1537
- title,
1538
- icon = "BarChart3",
1539
- actions = null,
1540
- className = ""
1541
- }) {
1542
- return /* @__PURE__ */ import_react12.default.createElement("div", { className: `flex items-center justify-between mb-2 ${className}` }, /* @__PURE__ */ import_react12.default.createElement(Typography, { variant: "h3", className: "flex items-center gap-2" }, /* @__PURE__ */ import_react12.default.createElement(Icon, { name: icon, size: 18 }), title), actions);
1440
+ function ChartHeader({ title, icon = "BarChart3", actions = null, className = "" }) {
1441
+ return /* @__PURE__ */ import_react12.default.createElement("div", { className: ["rdb-chart-title-wrap", className].filter(Boolean).join(" ") }, /* @__PURE__ */ import_react12.default.createElement("div", { className: "rdb-chart-title" }, /* @__PURE__ */ import_react12.default.createElement(Icon, { name: icon, size: 18 }), title), actions);
1543
1442
  }
1544
1443
  ChartHeader.propTypes = {
1545
- /** Judul grafik. */
1546
1444
  title: import_prop_types10.default.string.isRequired,
1547
- /** Nama ikon header. */
1548
1445
  icon: import_prop_types10.default.string,
1549
- /** Elemen aksi tambahan di sisi kanan. */
1550
1446
  actions: import_prop_types10.default.node,
1551
- /** ClassName tambahan. */
1552
1447
  className: import_prop_types10.default.string
1553
1448
  };
1554
1449
 
@@ -1573,28 +1468,24 @@ function DataTable({
1573
1468
  const [currentPage, setCurrentPage] = (0, import_react13.useState)(1);
1574
1469
  const filteredData = (0, import_react13.useMemo)(() => {
1575
1470
  if (!searchQuery.trim()) return data;
1576
- const query = searchQuery.toLowerCase();
1471
+ const q = searchQuery.toLowerCase();
1577
1472
  return data.filter(
1578
1473
  (row) => columns.some((col) => {
1579
- const value = row[col.accessor];
1580
- return value != null && String(value).toLowerCase().includes(query);
1474
+ const v = row[col.accessor];
1475
+ return v != null && String(v).toLowerCase().includes(q);
1581
1476
  })
1582
1477
  );
1583
1478
  }, [data, searchQuery, columns]);
1584
1479
  const sortedData = (0, import_react13.useMemo)(() => {
1585
1480
  if (!sortField) return filteredData;
1586
- const sorted = [...filteredData].sort((a, b) => {
1587
- const aVal = a[sortField] ?? "";
1588
- const bVal = b[sortField] ?? "";
1589
- if (typeof aVal === "number" && typeof bVal === "number") {
1590
- return sortDirection === "asc" ? aVal - bVal : bVal - aVal;
1591
- }
1592
- const comparison = String(aVal).localeCompare(String(bVal), void 0, {
1593
- numeric: true
1594
- });
1595
- return sortDirection === "asc" ? comparison : -comparison;
1481
+ return [...filteredData].sort((a, b) => {
1482
+ const aV = a[sortField] ?? "";
1483
+ const bV = b[sortField] ?? "";
1484
+ if (typeof aV === "number" && typeof bV === "number")
1485
+ return sortDirection === "asc" ? aV - bV : bV - aV;
1486
+ const cmp = String(aV).localeCompare(String(bV), void 0, { numeric: true });
1487
+ return sortDirection === "asc" ? cmp : -cmp;
1596
1488
  });
1597
- return sorted;
1598
1489
  }, [filteredData, sortField, sortDirection]);
1599
1490
  const totalPages = Math.max(1, Math.ceil(sortedData.length / pageSize));
1600
1491
  const safePage = Math.min(currentPage, totalPages);
@@ -1602,90 +1493,29 @@ function DataTable({
1602
1493
  const start = (safePage - 1) * pageSize;
1603
1494
  return sortedData.slice(start, start + pageSize);
1604
1495
  }, [sortedData, safePage, pageSize]);
1605
- const handleSearch = (0, import_react13.useCallback)((value) => {
1606
- setSearchQuery(value);
1496
+ const handleSearch = (0, import_react13.useCallback)((v) => {
1497
+ setSearchQuery(v);
1607
1498
  setCurrentPage(1);
1608
1499
  }, []);
1609
- const handleSort = (0, import_react13.useCallback)(
1610
- (accessor) => {
1611
- if (!sortable) return;
1612
- if (sortField === accessor) {
1613
- setSortDirection((prev) => prev === "asc" ? "desc" : "asc");
1614
- } else {
1615
- setSortField(accessor);
1616
- setSortDirection("asc");
1617
- }
1618
- setCurrentPage(1);
1619
- },
1620
- [sortable, sortField]
1621
- );
1622
- const handlePrevPage = (0, import_react13.useCallback)(() => {
1623
- setCurrentPage((prev) => Math.max(1, prev - 1));
1624
- }, []);
1625
- const handleNextPage = (0, import_react13.useCallback)(() => {
1626
- setCurrentPage((prev) => Math.min(totalPages, prev + 1));
1627
- }, [totalPages]);
1628
- return /* @__PURE__ */ import_react13.default.createElement("div", { className: `space-y-3 ${className}` }, searchable ? /* @__PURE__ */ import_react13.default.createElement(
1629
- SearchBar,
1630
- {
1631
- value: searchQuery,
1632
- onSearch: handleSearch,
1633
- placeholder: searchPlaceholder,
1634
- className: "max-w-sm"
1500
+ const handleSort = (0, import_react13.useCallback)((acc) => {
1501
+ if (!sortable) return;
1502
+ if (sortField === acc) setSortDirection((p) => p === "asc" ? "desc" : "asc");
1503
+ else {
1504
+ setSortField(acc);
1505
+ setSortDirection("asc");
1635
1506
  }
1636
- ) : null, /* @__PURE__ */ import_react13.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ import_react13.default.createElement("table", { className: "min-w-full text-sm border-collapse" }, /* @__PURE__ */ import_react13.default.createElement("thead", null, /* @__PURE__ */ import_react13.default.createElement("tr", { className: "bg-slate-100 dark:bg-slate-800 text-left" }, columns.map((column) => /* @__PURE__ */ import_react13.default.createElement(
1637
- "th",
1638
- {
1639
- key: column.id,
1640
- className: [
1641
- "p-3",
1642
- sortable ? "cursor-pointer select-none hover:bg-slate-200 dark:hover:bg-slate-700 transition-colors" : ""
1643
- ].join(" "),
1644
- onClick: () => handleSort(column.accessor)
1645
- },
1646
- /* @__PURE__ */ import_react13.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react13.default.createElement("span", null, labels[column.label] || column.label), sortable && sortField === column.accessor ? /* @__PURE__ */ import_react13.default.createElement(
1647
- Icon,
1648
- {
1649
- name: sortDirection === "asc" ? "ArrowUp" : "ArrowDown",
1650
- size: 14,
1651
- className: "text-blue-500"
1652
- }
1653
- ) : null)
1654
- )))), /* @__PURE__ */ import_react13.default.createElement("tbody", null, paginatedData.map((row) => /* @__PURE__ */ import_react13.default.createElement(
1655
- "tr",
1656
- {
1657
- key: row.id,
1658
- className: "border-b border-slate-200 dark:border-slate-700 hover:bg-slate-50 dark:hover:bg-slate-800/50"
1659
- },
1660
- columns.map((column) => /* @__PURE__ */ import_react13.default.createElement("td", { key: `${row.id}-${column.id}`, className: "p-3" }, renderCell(column, row, dateLocale)))
1661
- )), paginatedData.length === 0 ? /* @__PURE__ */ import_react13.default.createElement("tr", null, /* @__PURE__ */ import_react13.default.createElement(
1662
- "td",
1663
- {
1664
- className: "p-6 text-center text-slate-500",
1665
- colSpan: columns.length
1666
- },
1667
- emptyLabel
1668
- )) : null))), sortedData.length > pageSize ? /* @__PURE__ */ import_react13.default.createElement("div", { className: "flex items-center justify-between px-1" }, /* @__PURE__ */ import_react13.default.createElement("span", { className: "text-xs text-slate-500" }, (safePage - 1) * pageSize + 1, "\u2013", Math.min(safePage * pageSize, sortedData.length), " of", " ", sortedData.length), /* @__PURE__ */ import_react13.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react13.default.createElement(
1669
- "button",
1670
- {
1671
- type: "button",
1672
- className: "p-1.5 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 disabled:opacity-40 disabled:cursor-not-allowed transition-colors",
1673
- onClick: handlePrevPage,
1674
- disabled: safePage <= 1,
1675
- "aria-label": "Previous page"
1676
- },
1677
- /* @__PURE__ */ import_react13.default.createElement(Icon, { name: "ChevronLeft", size: 16 })
1678
- ), /* @__PURE__ */ import_react13.default.createElement("span", { className: "text-xs text-slate-600 dark:text-slate-300 min-w-[60px] text-center" }, safePage, " / ", totalPages), /* @__PURE__ */ import_react13.default.createElement(
1679
- "button",
1507
+ setCurrentPage(1);
1508
+ }, [sortable, sortField]);
1509
+ const handlePrev = (0, import_react13.useCallback)(() => setCurrentPage((p) => Math.max(1, p - 1)), []);
1510
+ const handleNext = (0, import_react13.useCallback)(() => setCurrentPage((p) => Math.min(totalPages, p + 1)), [totalPages]);
1511
+ return /* @__PURE__ */ import_react13.default.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, className }, searchable ? /* @__PURE__ */ import_react13.default.createElement(SearchBar, { value: searchQuery, onSearch: handleSearch, placeholder: searchPlaceholder }) : null, /* @__PURE__ */ import_react13.default.createElement("div", { className: "rdb-table-wrapper" }, /* @__PURE__ */ import_react13.default.createElement("table", { className: "rdb-table" }, /* @__PURE__ */ import_react13.default.createElement("thead", null, /* @__PURE__ */ import_react13.default.createElement("tr", null, columns.map((col) => /* @__PURE__ */ import_react13.default.createElement("th", { key: col.id, onClick: () => handleSort(col.accessor) }, /* @__PURE__ */ import_react13.default.createElement("div", { style: { display: "flex", alignItems: "center", gap: 4 } }, /* @__PURE__ */ import_react13.default.createElement("span", null, labels[col.label] || col.label), sortable && sortField === col.accessor ? /* @__PURE__ */ import_react13.default.createElement(
1512
+ Icon,
1680
1513
  {
1681
- type: "button",
1682
- className: "p-1.5 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 disabled:opacity-40 disabled:cursor-not-allowed transition-colors",
1683
- onClick: handleNextPage,
1684
- disabled: safePage >= totalPages,
1685
- "aria-label": "Next page"
1686
- },
1687
- /* @__PURE__ */ import_react13.default.createElement(Icon, { name: "ChevronRight", size: 16 })
1688
- ))) : null);
1514
+ name: sortDirection === "asc" ? "ArrowUp" : "ArrowDown",
1515
+ size: 13,
1516
+ style: { color: "var(--rdb-blue-500)" }
1517
+ }
1518
+ ) : null))))), /* @__PURE__ */ import_react13.default.createElement("tbody", null, paginatedData.map((row) => /* @__PURE__ */ import_react13.default.createElement("tr", { key: row.id }, columns.map((col) => /* @__PURE__ */ import_react13.default.createElement("td", { key: `${row.id}-${col.id}` }, renderCell(col, row, dateLocale))))), paginatedData.length === 0 ? /* @__PURE__ */ import_react13.default.createElement("tr", null, /* @__PURE__ */ import_react13.default.createElement("td", { className: "rdb-table-empty", colSpan: columns.length }, emptyLabel)) : null))), sortedData.length > pageSize ? /* @__PURE__ */ import_react13.default.createElement("div", { className: "rdb-pagination" }, /* @__PURE__ */ import_react13.default.createElement("span", { className: "rdb-pagination-info" }, (safePage - 1) * pageSize + 1, "\u2013", Math.min(safePage * pageSize, sortedData.length), " of ", sortedData.length), /* @__PURE__ */ import_react13.default.createElement("div", { className: "rdb-pagination-controls" }, /* @__PURE__ */ import_react13.default.createElement("button", { type: "button", className: "rdb-page-btn", onClick: handlePrev, disabled: safePage <= 1, "aria-label": "Previous" }, /* @__PURE__ */ import_react13.default.createElement(Icon, { name: "ChevronLeft", size: 16 })), /* @__PURE__ */ import_react13.default.createElement("span", { className: "rdb-pagination-page" }, safePage, " / ", totalPages), /* @__PURE__ */ import_react13.default.createElement("button", { type: "button", className: "rdb-page-btn", onClick: handleNext, disabled: safePage >= totalPages, "aria-label": "Next" }, /* @__PURE__ */ import_react13.default.createElement(Icon, { name: "ChevronRight", size: 16 })))) : null);
1689
1519
  }
1690
1520
  function renderCell(column, row, dateLocale) {
1691
1521
  const value = row[column.accessor];
@@ -1698,33 +1528,21 @@ function renderCell(column, row, dateLocale) {
1698
1528
  return value || "-";
1699
1529
  }
1700
1530
  DataTable.propTypes = {
1701
- /** Definisi kolom tabel. */
1702
- columns: import_prop_types11.default.arrayOf(
1703
- import_prop_types11.default.shape({
1704
- id: import_prop_types11.default.string.isRequired,
1705
- label: import_prop_types11.default.string.isRequired,
1706
- accessor: import_prop_types11.default.string.isRequired,
1707
- type: import_prop_types11.default.oneOf(["date", "currency", "statusBadge"]),
1708
- statusAccessor: import_prop_types11.default.string
1709
- })
1710
- ).isRequired,
1711
- /** Array data baris. */
1531
+ columns: import_prop_types11.default.arrayOf(import_prop_types11.default.shape({
1532
+ id: import_prop_types11.default.string.isRequired,
1533
+ label: import_prop_types11.default.string.isRequired,
1534
+ accessor: import_prop_types11.default.string.isRequired,
1535
+ type: import_prop_types11.default.oneOf(["date", "currency", "statusBadge"]),
1536
+ statusAccessor: import_prop_types11.default.string
1537
+ })).isRequired,
1712
1538
  data: import_prop_types11.default.arrayOf(import_prop_types11.default.object),
1713
- /** Objek label i18n. */
1714
1539
  labels: import_prop_types11.default.object,
1715
- /** Locale untuk format tanggal. */
1716
1540
  dateLocale: import_prop_types11.default.string,
1717
- /** Apakah tabel mendukung pencarian. */
1718
1541
  searchable: import_prop_types11.default.bool,
1719
- /** Apakah tabel mendukung pengurutan. */
1720
1542
  sortable: import_prop_types11.default.bool,
1721
- /** Jumlah baris per halaman. */
1722
1543
  pageSize: import_prop_types11.default.number,
1723
- /** Label saat data kosong. */
1724
1544
  emptyLabel: import_prop_types11.default.string,
1725
- /** Placeholder pencarian. */
1726
1545
  searchPlaceholder: import_prop_types11.default.string,
1727
- /** ClassName tambahan. */
1728
1546
  className: import_prop_types11.default.string
1729
1547
  };
1730
1548
 
@@ -1878,44 +1696,38 @@ var AUDIENCE_OPTIONS = ["", "domestic", "foreign"];
1878
1696
  var DAY_PRESETS = [7, 30, 90, 0];
1879
1697
  var SORT_BY_OPTIONS = ["bookings", "revenue"];
1880
1698
  var SORT_DIR_OPTIONS = ["desc", "asc"];
1881
- function FilterPanel({
1882
- filters,
1883
- labels,
1884
- onFilterChange,
1885
- onResetFilters,
1886
- className = ""
1887
- }) {
1888
- return /* @__PURE__ */ import_react15.default.createElement("div", { className: `flex flex-col gap-2 ${className}` }, /* @__PURE__ */ import_react15.default.createElement("div", { className: "grid grid-cols-1 lg:grid-cols-6 gap-2" }, /* @__PURE__ */ import_react15.default.createElement(
1699
+ function FilterPanel({ filters, labels, onFilterChange, onResetFilters, className = "" }) {
1700
+ return /* @__PURE__ */ import_react15.default.createElement("div", { className: ["rdb-filter-panel", className].filter(Boolean).join(" ") }, /* @__PURE__ */ import_react15.default.createElement("div", { className: "rdb-filter-row" }, /* @__PURE__ */ import_react15.default.createElement(
1889
1701
  "select",
1890
1702
  {
1891
- className: "px-3 py-2 rounded-2xl border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 text-sm",
1703
+ className: "rdb-select",
1892
1704
  value: filters.statusScope,
1893
- onChange: (event) => onFilterChange("statusScope", event.target.value)
1705
+ onChange: (e) => onFilterChange("statusScope", e.target.value)
1894
1706
  },
1895
- STATUS_OPTIONS.map((status) => /* @__PURE__ */ import_react15.default.createElement("option", { key: status, value: status }, status === "confirmed" ? labels.confirmedOnly : status === "pending" ? labels.pendingOnly : labels.allStatus))
1896
- ), /* @__PURE__ */ import_react15.default.createElement("label", { className: "inline-flex items-center gap-2 px-3 py-2 rounded-2xl border border-slate-300 dark:border-slate-600" }, /* @__PURE__ */ import_react15.default.createElement(
1897
- Input,
1707
+ STATUS_OPTIONS.map((s) => /* @__PURE__ */ import_react15.default.createElement("option", { key: s, value: s }, s === "confirmed" ? labels.confirmedOnly : s === "pending" ? labels.pendingOnly : labels.allStatus))
1708
+ ), /* @__PURE__ */ import_react15.default.createElement("label", { className: "rdb-filter-overlay-label" }, /* @__PURE__ */ import_react15.default.createElement(
1709
+ "input",
1898
1710
  {
1899
1711
  type: "checkbox",
1900
1712
  checked: filters.includePendingOverlay,
1901
- onChange: (event) => onFilterChange("includePendingOverlay", event.target.checked)
1713
+ onChange: (e) => onFilterChange("includePendingOverlay", e.target.checked)
1902
1714
  }
1903
- ), /* @__PURE__ */ import_react15.default.createElement(Typography, { variant: "body" }, labels.showPendingOverlay)), /* @__PURE__ */ import_react15.default.createElement(
1715
+ ), /* @__PURE__ */ import_react15.default.createElement("span", { className: "rdb-body" }, labels.showPendingOverlay)), /* @__PURE__ */ import_react15.default.createElement(
1904
1716
  "select",
1905
1717
  {
1906
- className: "px-3 py-2 rounded-2xl border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 text-sm",
1718
+ className: "rdb-select",
1907
1719
  value: filters.audience,
1908
- onChange: (event) => onFilterChange("audience", event.target.value)
1720
+ onChange: (e) => onFilterChange("audience", e.target.value)
1909
1721
  },
1910
- AUDIENCE_OPTIONS.map((audience) => /* @__PURE__ */ import_react15.default.createElement("option", { key: audience || "all", value: audience }, audience === "domestic" ? labels.audienceDomestic : audience === "foreign" ? labels.audienceForeign : labels.allAudience))
1722
+ AUDIENCE_OPTIONS.map((a) => /* @__PURE__ */ import_react15.default.createElement("option", { key: a || "all", value: a }, a === "domestic" ? labels.audienceDomestic : a === "foreign" ? labels.audienceForeign : labels.allAudience))
1911
1723
  ), /* @__PURE__ */ import_react15.default.createElement(
1912
1724
  "select",
1913
1725
  {
1914
- className: "px-3 py-2 rounded-2xl border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 text-sm",
1726
+ className: "rdb-select",
1915
1727
  value: String(filters.daysPreset),
1916
- onChange: (event) => onFilterChange("daysPreset", Number(event.target.value))
1728
+ onChange: (e) => onFilterChange("daysPreset", Number(e.target.value))
1917
1729
  },
1918
- DAY_PRESETS.map((days) => /* @__PURE__ */ import_react15.default.createElement("option", { key: String(days), value: String(days) }, days === 0 ? labels.customDate : labels.dayLabel(days)))
1730
+ DAY_PRESETS.map((d) => /* @__PURE__ */ import_react15.default.createElement("option", { key: String(d), value: String(d) }, d === 0 ? labels.customDate : labels.dayLabel(d)))
1919
1731
  ), /* @__PURE__ */ import_react15.default.createElement(
1920
1732
  DateRangeFilter,
1921
1733
  {
@@ -1926,160 +1738,95 @@ function FilterPanel({
1926
1738
  if (dateTo !== filters.dateTo) onFilterChange("dateTo", dateTo);
1927
1739
  },
1928
1740
  disabled: filters.daysPreset !== 0,
1929
- className: "lg:col-span-2"
1741
+ className: "rdb-filter-date"
1930
1742
  }
1931
- )), /* @__PURE__ */ import_react15.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ import_react15.default.createElement(Button, { variant: "secondary", size: "sm", onClick: onResetFilters }, labels.reset), /* @__PURE__ */ import_react15.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react15.default.createElement(Typography, { variant: "caption" }, labels.topSort, ":"), /* @__PURE__ */ import_react15.default.createElement(
1743
+ )), /* @__PURE__ */ import_react15.default.createElement("div", { className: "rdb-filter-actions" }, /* @__PURE__ */ import_react15.default.createElement(Button, { variant: "secondary", size: "sm", onClick: onResetFilters }, labels.reset), /* @__PURE__ */ import_react15.default.createElement("div", { className: "rdb-filter-sort" }, /* @__PURE__ */ import_react15.default.createElement("span", { className: "rdb-caption" }, labels.topSort, ":"), /* @__PURE__ */ import_react15.default.createElement(
1932
1744
  "select",
1933
1745
  {
1934
- className: "px-2 py-1.5 rounded-xl border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 text-sm",
1746
+ className: "rdb-select",
1747
+ style: { width: "auto" },
1935
1748
  value: filters.sortPkgBy,
1936
- onChange: (event) => onFilterChange("sortPkgBy", event.target.value)
1749
+ onChange: (e) => onFilterChange("sortPkgBy", e.target.value)
1937
1750
  },
1938
- SORT_BY_OPTIONS.map((sortBy) => /* @__PURE__ */ import_react15.default.createElement("option", { key: sortBy, value: sortBy }, sortBy === "bookings" ? labels.sortBookings : labels.sortRevenue))
1751
+ SORT_BY_OPTIONS.map((s) => /* @__PURE__ */ import_react15.default.createElement("option", { key: s, value: s }, s === "bookings" ? labels.sortBookings : labels.sortRevenue))
1939
1752
  ), /* @__PURE__ */ import_react15.default.createElement(
1940
1753
  "select",
1941
1754
  {
1942
- className: "px-2 py-1.5 rounded-xl border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 text-sm",
1755
+ className: "rdb-select",
1756
+ style: { width: "auto" },
1943
1757
  value: filters.sortPkgDir,
1944
- onChange: (event) => onFilterChange("sortPkgDir", event.target.value)
1758
+ onChange: (e) => onFilterChange("sortPkgDir", e.target.value)
1945
1759
  },
1946
- SORT_DIR_OPTIONS.map((direction) => /* @__PURE__ */ import_react15.default.createElement("option", { key: direction, value: direction }, direction === "desc" ? labels.sortDesc : labels.sortAsc))
1760
+ SORT_DIR_OPTIONS.map((d) => /* @__PURE__ */ import_react15.default.createElement("option", { key: d, value: d }, d === "desc" ? labels.sortDesc : labels.sortAsc))
1947
1761
  ))));
1948
1762
  }
1949
1763
  FilterPanel.propTypes = {
1950
- /** State filter saat ini. */
1951
- filters: import_prop_types13.default.shape({
1952
- statusScope: import_prop_types13.default.string,
1953
- includePendingOverlay: import_prop_types13.default.bool,
1954
- audience: import_prop_types13.default.string,
1955
- daysPreset: import_prop_types13.default.number,
1956
- dateFrom: import_prop_types13.default.string,
1957
- dateTo: import_prop_types13.default.string,
1958
- sortPkgBy: import_prop_types13.default.string,
1959
- sortPkgDir: import_prop_types13.default.string
1960
- }).isRequired,
1961
- /** Objek label i18n. */
1764
+ filters: import_prop_types13.default.object.isRequired,
1962
1765
  labels: import_prop_types13.default.object.isRequired,
1963
- /** Callback saat filter berubah (field, value). */
1964
1766
  onFilterChange: import_prop_types13.default.func.isRequired,
1965
- /** Callback saat filter di-reset. */
1966
1767
  onResetFilters: import_prop_types13.default.func.isRequired,
1967
- /** ClassName tambahan. */
1968
1768
  className: import_prop_types13.default.string
1969
1769
  };
1970
1770
 
1971
1771
  // src/presentation/organisms/SidebarNavigation.jsx
1972
1772
  var import_react16 = __toESM(require("react"), 1);
1973
1773
  var import_prop_types14 = __toESM(require("prop-types"), 1);
1974
- function SidebarNavigation({
1975
- items = [],
1976
- activeItem = "",
1977
- onItemClick,
1978
- logo = null,
1979
- className = ""
1980
- }) {
1981
- return /* @__PURE__ */ import_react16.default.createElement(
1982
- "aside",
1983
- {
1984
- className: `flex flex-col w-60 min-h-screen bg-white dark:bg-slate-900 border-r border-slate-200 dark:border-slate-800 ${className}`
1985
- },
1986
- logo ? /* @__PURE__ */ import_react16.default.createElement("div", { className: "px-4 py-4 border-b border-slate-100 dark:border-slate-800" }, logo) : null,
1987
- /* @__PURE__ */ import_react16.default.createElement("nav", { className: "flex-1 px-2 py-3 space-y-0.5", "aria-label": "Sidebar navigation" }, items.map((item) => {
1988
- const isActive = item.id === activeItem;
1989
- return /* @__PURE__ */ import_react16.default.createElement(
1990
- "button",
1774
+ function SidebarNavigation({ items = [], activeItem = "", onItemClick, logo = null, className = "" }) {
1775
+ return /* @__PURE__ */ import_react16.default.createElement("aside", { className: ["rdb-sidebar", className].filter(Boolean).join(" ") }, logo ? /* @__PURE__ */ import_react16.default.createElement("div", { className: "rdb-sidebar-logo" }, logo) : null, /* @__PURE__ */ import_react16.default.createElement("nav", { className: "rdb-sidebar-nav", "aria-label": "Sidebar navigation" }, items.map((item) => {
1776
+ const isActive = item.id === activeItem;
1777
+ return /* @__PURE__ */ import_react16.default.createElement(
1778
+ "button",
1779
+ {
1780
+ key: item.id,
1781
+ type: "button",
1782
+ onClick: () => onItemClick == null ? void 0 : onItemClick(item.id),
1783
+ "aria-current": isActive ? "page" : void 0,
1784
+ className: ["rdb-nav-item", isActive ? "rdb-nav-item-active" : ""].filter(Boolean).join(" ")
1785
+ },
1786
+ item.icon ? /* @__PURE__ */ import_react16.default.createElement(
1787
+ Icon,
1991
1788
  {
1992
- key: item.id,
1993
- type: "button",
1994
- id: `sidebar-nav-${item.id}`,
1995
- onClick: () => onItemClick == null ? void 0 : onItemClick(item.id),
1996
- "aria-current": isActive ? "page" : void 0,
1997
- className: [
1998
- "w-full flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm font-medium transition-colors text-left",
1999
- isActive ? "bg-blue-50 dark:bg-blue-950/60 text-blue-700 dark:text-blue-300" : "text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 hover:text-slate-900 dark:hover:text-slate-100"
2000
- ].join(" ")
2001
- },
2002
- item.icon ? /* @__PURE__ */ import_react16.default.createElement(
2003
- Icon,
2004
- {
2005
- name: item.icon,
2006
- size: 18,
2007
- className: isActive ? "text-blue-600 dark:text-blue-400" : "text-slate-400 dark:text-slate-500"
2008
- }
2009
- ) : null,
2010
- /* @__PURE__ */ import_react16.default.createElement("span", null, item.label),
2011
- isActive ? /* @__PURE__ */ import_react16.default.createElement("span", { className: "ml-auto w-1.5 h-1.5 rounded-full bg-blue-500" }) : null
2012
- );
2013
- }))
2014
- );
1789
+ name: item.icon,
1790
+ size: 18,
1791
+ style: { color: isActive ? "var(--rdb-blue-600)" : "var(--rdb-text-subtle)" }
1792
+ }
1793
+ ) : null,
1794
+ /* @__PURE__ */ import_react16.default.createElement("span", null, item.label),
1795
+ isActive ? /* @__PURE__ */ import_react16.default.createElement("span", { className: "rdb-nav-dot" }) : null
1796
+ );
1797
+ })));
2015
1798
  }
2016
1799
  SidebarNavigation.propTypes = {
2017
- /** Daftar item menu navigasi. */
2018
- items: import_prop_types14.default.arrayOf(
2019
- import_prop_types14.default.shape({
2020
- id: import_prop_types14.default.string.isRequired,
2021
- label: import_prop_types14.default.string.isRequired,
2022
- icon: import_prop_types14.default.string
2023
- })
2024
- ),
2025
- /** ID item yang sedang aktif. */
1800
+ items: import_prop_types14.default.arrayOf(import_prop_types14.default.shape({ id: import_prop_types14.default.string.isRequired, label: import_prop_types14.default.string.isRequired, icon: import_prop_types14.default.string })),
2026
1801
  activeItem: import_prop_types14.default.string,
2027
- /** Callback saat item diklik, menerima id item sebagai argumen. */
2028
1802
  onItemClick: import_prop_types14.default.func,
2029
- /** Konten logo/brand di atas sidebar. */
2030
1803
  logo: import_prop_types14.default.node,
2031
- /** ClassName tambahan. */
2032
1804
  className: import_prop_types14.default.string
2033
1805
  };
2034
1806
 
2035
1807
  // src/presentation/organisms/TopbarHeader.jsx
2036
1808
  var import_react17 = __toESM(require("react"), 1);
2037
1809
  var import_prop_types15 = __toESM(require("prop-types"), 1);
2038
- function TopbarHeader({
2039
- title = "",
2040
- actions = null,
2041
- leading = null,
2042
- className = ""
2043
- }) {
2044
- return /* @__PURE__ */ import_react17.default.createElement(
2045
- "header",
2046
- {
2047
- className: `sticky top-0 z-30 flex items-center justify-between h-14 px-4 bg-white/80 dark:bg-slate-900/80 backdrop-blur-md border-b border-slate-200 dark:border-slate-800 ${className}`
2048
- },
2049
- /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex items-center gap-3" }, leading, title ? /* @__PURE__ */ import_react17.default.createElement(Typography, { variant: "h2", className: "truncate" }, title) : null),
2050
- actions ? /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex items-center gap-2" }, actions) : null
2051
- );
1810
+ function TopbarHeader({ title = "", actions = null, leading = null, className = "" }) {
1811
+ return /* @__PURE__ */ import_react17.default.createElement("header", { className: ["rdb-topbar", className].filter(Boolean).join(" ") }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "rdb-topbar-left" }, leading, title ? /* @__PURE__ */ import_react17.default.createElement("span", { className: "rdb-h2", style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, title) : null), actions ? /* @__PURE__ */ import_react17.default.createElement("div", { className: "rdb-topbar-right" }, actions) : null);
2052
1812
  }
2053
1813
  TopbarHeader.propTypes = {
2054
- /** Judul halaman yang ditampilkan. */
2055
1814
  title: import_prop_types15.default.string,
2056
- /** Elemen aksi di sisi kanan (tombol, avatar, dsb.). */
2057
1815
  actions: import_prop_types15.default.node,
2058
- /** Elemen di sisi kiri sebelum judul (misal: hamburger menu). */
2059
1816
  leading: import_prop_types15.default.node,
2060
- /** ClassName tambahan. */
2061
1817
  className: import_prop_types15.default.string
2062
1818
  };
2063
1819
 
2064
1820
  // src/presentation/templates/DashboardLayout.jsx
2065
1821
  var import_react18 = __toESM(require("react"), 1);
2066
1822
  var import_prop_types16 = __toESM(require("prop-types"), 1);
2067
- function DashboardLayout({
2068
- header = null,
2069
- sidebar = null,
2070
- children,
2071
- className = ""
2072
- }) {
2073
- return /* @__PURE__ */ import_react18.default.createElement("div", { className: `min-h-screen bg-slate-50 dark:bg-slate-900 ${className}` }, header, /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex" }, sidebar, /* @__PURE__ */ import_react18.default.createElement("main", { className: "flex-1 container mx-auto px-4 py-3 space-y-4" }, children)));
1823
+ function DashboardLayout({ header = null, sidebar = null, children, className = "" }) {
1824
+ return /* @__PURE__ */ import_react18.default.createElement("div", { className: ["rdb-layout", className].filter(Boolean).join(" ") }, header, /* @__PURE__ */ import_react18.default.createElement("div", { className: "rdb-layout-body" }, sidebar, /* @__PURE__ */ import_react18.default.createElement("main", { className: "rdb-layout-main" }, children)));
2074
1825
  }
2075
1826
  DashboardLayout.propTypes = {
2076
- /** Konten header atas. */
2077
1827
  header: import_prop_types16.default.node,
2078
- /** Konten sidebar. */
2079
1828
  sidebar: import_prop_types16.default.node,
2080
- /** Konten utama dashboard. */
2081
1829
  children: import_prop_types16.default.node.isRequired,
2082
- /** ClassName tambahan. */
2083
1830
  className: import_prop_types16.default.string
2084
1831
  };
2085
1832
 
@@ -2099,16 +1846,7 @@ function ReusableDashboardView({
2099
1846
  dateLocale,
2100
1847
  liveUpdateEnabled
2101
1848
  }) {
2102
- return /* @__PURE__ */ import_react19.default.createElement("div", { className: "container mt-3 space-y-4" }, /* @__PURE__ */ import_react19.default.createElement("div", null, /* @__PURE__ */ import_react19.default.createElement("div", { className: "rounded-2xl border border-slate-200/60 dark:border-slate-800/60 backdrop-blur-md px-3 sm:px-4 py-2 glass shadow-smooth" }, /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex flex-col gap-2" }, /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex flex-wrap items-center justify-between gap-2" }, /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex items-center gap-3" }, /* @__PURE__ */ import_react19.default.createElement(Typography, { variant: "h1" }, labels.title), liveUpdateEnabled ? /* @__PURE__ */ import_react19.default.createElement(Badge, { status: "success" }, labels.liveUpdate) : null), /* @__PURE__ */ import_react19.default.createElement(
2103
- Button,
2104
- {
2105
- variant: "secondary",
2106
- size: "sm",
2107
- onClick: () => onRefresh(),
2108
- title: labels.refresh
2109
- },
2110
- /* @__PURE__ */ import_react19.default.createElement(Icon, { name: "RotateCcw", size: 16 })
2111
- )), error ? /* @__PURE__ */ import_react19.default.createElement("div", { className: "rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-300" }, /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex items-center justify-between gap-3" }, /* @__PURE__ */ import_react19.default.createElement("span", null, error), /* @__PURE__ */ import_react19.default.createElement(Button, { variant: "secondary", size: "sm", onClick: () => onRefresh() }, labels.retry))) : null, /* @__PURE__ */ import_react19.default.createElement(
1849
+ return /* @__PURE__ */ import_react19.default.createElement("div", { className: "rdb-view" }, /* @__PURE__ */ import_react19.default.createElement("div", { className: "rdb-view-container" }, /* @__PURE__ */ import_react19.default.createElement("div", { className: "rdb-header-panel" }, /* @__PURE__ */ import_react19.default.createElement("div", { className: "rdb-header-top" }, /* @__PURE__ */ import_react19.default.createElement("div", { className: "rdb-header-title-group" }, /* @__PURE__ */ import_react19.default.createElement("span", { className: "rdb-h1" }, labels.title), liveUpdateEnabled ? /* @__PURE__ */ import_react19.default.createElement(Badge, { status: "success" }, labels.liveUpdate) : null), /* @__PURE__ */ import_react19.default.createElement(Button, { variant: "secondary", size: "sm", onClick: () => onRefresh(), title: labels.refresh }, /* @__PURE__ */ import_react19.default.createElement(Icon, { name: "RotateCcw", size: 16 }))), error ? /* @__PURE__ */ import_react19.default.createElement("div", { className: "rdb-error-banner" }, /* @__PURE__ */ import_react19.default.createElement("span", null, error), /* @__PURE__ */ import_react19.default.createElement(Button, { variant: "secondary", size: "sm", onClick: () => onRefresh() }, labels.retry)) : null, /* @__PURE__ */ import_react19.default.createElement(
2112
1850
  FilterPanel,
2113
1851
  {
2114
1852
  filters,
@@ -2116,16 +1854,17 @@ function ReusableDashboardView({
2116
1854
  onFilterChange,
2117
1855
  onResetFilters
2118
1856
  }
2119
- )))), /* @__PURE__ */ import_react19.default.createElement("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4" }, loading ? Array.from({ length: 4 }).map((_, index) => /* @__PURE__ */ import_react19.default.createElement(SkeletonLoader, { key: `stat-skeleton-${index}`, className: "h-28" })) : config.widgets.stats.map((widget) => /* @__PURE__ */ import_react19.default.createElement(
1857
+ )), /* @__PURE__ */ import_react19.default.createElement("div", { className: "rdb-stats-grid" }, loading ? Array.from({ length: 4 }).map((_, i) => /* @__PURE__ */ import_react19.default.createElement(SkeletonLoader, { key: i, style: { height: 112 } })) : config.widgets.stats.map((widget) => /* @__PURE__ */ import_react19.default.createElement(
2120
1858
  StatCard,
2121
1859
  {
2122
1860
  key: widget.id,
2123
1861
  label: labels[widget.label] || widget.label,
2124
1862
  value: data.stats[widget.valueKey],
2125
1863
  icon: widget.icon,
2126
- format: widget.format
1864
+ format: widget.format,
1865
+ accentColor: widget.accentColor
2127
1866
  }
2128
- ))), /* @__PURE__ */ import_react19.default.createElement("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-4" }, config.widgets.charts.map((widget) => /* @__PURE__ */ import_react19.default.createElement(
1867
+ ))), /* @__PURE__ */ import_react19.default.createElement("div", { className: "rdb-charts-grid" }, config.widgets.charts.map((widget) => /* @__PURE__ */ import_react19.default.createElement(
2129
1868
  ChartCard,
2130
1869
  {
2131
1870
  key: widget.id,
@@ -2135,7 +1874,15 @@ function ReusableDashboardView({
2135
1874
  filters,
2136
1875
  chartData: data.charts
2137
1876
  }
2138
- ))), /* @__PURE__ */ import_react19.default.createElement("div", { className: "card p-4" }, /* @__PURE__ */ import_react19.default.createElement(Typography, { variant: "h3", className: "flex items-center gap-2 mb-3" }, /* @__PURE__ */ import_react19.default.createElement(Icon, { name: config.widgets.table.icon, size: 18 }), labels[config.widgets.table.label] || config.widgets.table.label), loading ? /* @__PURE__ */ import_react19.default.createElement(SkeletonLoader, { className: "h-48" }) : /* @__PURE__ */ import_react19.default.createElement(
1877
+ ))), /* @__PURE__ */ import_react19.default.createElement("div", { className: "rdb-card", style: { padding: 16 } }, /* @__PURE__ */ import_react19.default.createElement(
1878
+ "div",
1879
+ {
1880
+ style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 12 },
1881
+ className: "rdb-h3"
1882
+ },
1883
+ /* @__PURE__ */ import_react19.default.createElement(Icon, { name: config.widgets.table.icon, size: 18 }),
1884
+ labels[config.widgets.table.label] || config.widgets.table.label
1885
+ ), loading ? /* @__PURE__ */ import_react19.default.createElement(SkeletonLoader, { style: { height: 192 } }) : /* @__PURE__ */ import_react19.default.createElement(
2139
1886
  DataTable,
2140
1887
  {
2141
1888
  columns: config.widgets.table.columns,
@@ -2147,30 +1894,19 @@ function ReusableDashboardView({
2147
1894
  sortable: true,
2148
1895
  pageSize: 10
2149
1896
  }
2150
- )));
1897
+ ))));
2151
1898
  }
2152
1899
  ReusableDashboardView.propTypes = {
2153
- /** Konfigurasi widget dashboard. */
2154
1900
  config: import_prop_types17.default.object.isRequired,
2155
- /** Objek label i18n. */
2156
1901
  labels: import_prop_types17.default.object.isRequired,
2157
- /** Status loading data. */
2158
1902
  loading: import_prop_types17.default.bool,
2159
- /** Pesan error jika ada. */
2160
1903
  error: import_prop_types17.default.string,
2161
- /** State filter dashboard. */
2162
1904
  filters: import_prop_types17.default.object,
2163
- /** Callback perubahan filter. */
2164
1905
  onFilterChange: import_prop_types17.default.func.isRequired,
2165
- /** Callback reset filter. */
2166
1906
  onResetFilters: import_prop_types17.default.func.isRequired,
2167
- /** Callback refresh data. */
2168
1907
  onRefresh: import_prop_types17.default.func.isRequired,
2169
- /** Data dashboard. */
2170
1908
  data: import_prop_types17.default.object,
2171
- /** Locale untuk format tanggal. */
2172
1909
  dateLocale: import_prop_types17.default.string,
2173
- /** Apakah live update aktif. */
2174
1910
  liveUpdateEnabled: import_prop_types17.default.bool
2175
1911
  };
2176
1912