hs-uix 1.4.1 → 1.5.0

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.
@@ -304,7 +304,9 @@ var DataTable = ({
304
304
  const initialSortState = useMemo(() => {
305
305
  return normalizeSortState(columns, defaultSort);
306
306
  }, [columns, defaultSort]);
307
- const [internalSearchTerm, setInternalSearchTerm] = useState("");
307
+ const [internalSearchTerm, setInternalSearchTerm] = useState(
308
+ () => serverSide && searchValue != null ? searchValue : ""
309
+ );
308
310
  const [internalFilterValues, setInternalFilterValues] = useState(() => {
309
311
  const init = {};
310
312
  filters.forEach((f) => {
@@ -315,7 +317,16 @@ var DataTable = ({
315
317
  const [internalSortState, setInternalSortState] = useState(initialSortState);
316
318
  const [currentPage, setCurrentPage] = useState(1);
317
319
  const [showMoreFilters, setShowMoreFilters] = useState(false);
320
+ const lastAppliedSearchRef = useRef(
321
+ serverSide && searchValue != null ? searchValue : ""
322
+ );
318
323
  const searchTerm = serverSide && searchValue != null ? searchValue : internalSearchTerm;
324
+ useEffect(() => {
325
+ if (!serverSide || searchValue == null) return;
326
+ if (searchValue === lastAppliedSearchRef.current) return;
327
+ lastAppliedSearchRef.current = searchValue;
328
+ setInternalSearchTerm(searchValue);
329
+ }, [serverSide, searchValue]);
319
330
  const filterValues = serverSide && externalFilterValues != null ? externalFilterValues : internalFilterValues;
320
331
  const externalSortState = useMemo(
321
332
  () => normalizeSortState(columns, externalSort),
@@ -349,15 +360,16 @@ var DataTable = ({
349
360
  const handleSearchChange = useCallback((term) => {
350
361
  setInternalSearchTerm(term);
351
362
  resetPage();
363
+ const dispatch = () => {
364
+ lastAppliedSearchRef.current = term;
365
+ fireSearchCallback(term);
366
+ fireParamsChange({ search: term, page: resetPageOnChange ? 1 : void 0 });
367
+ };
352
368
  if (searchDebounce > 0) {
353
369
  if (debounceRef.current) clearTimeout(debounceRef.current);
354
- debounceRef.current = setTimeout(() => {
355
- fireSearchCallback(term);
356
- fireParamsChange({ search: term, page: resetPageOnChange ? 1 : void 0 });
357
- }, searchDebounce);
370
+ debounceRef.current = setTimeout(dispatch, searchDebounce);
358
371
  } else {
359
- fireSearchCallback(term);
360
- fireParamsChange({ search: term, page: resetPageOnChange ? 1 : void 0 });
372
+ dispatch();
361
373
  }
362
374
  }, [searchDebounce, fireSearchCallback, fireParamsChange, resetPage, resetPageOnChange]);
363
375
  useEffect(() => () => {
@@ -439,10 +451,23 @@ var DataTable = ({
439
451
  if (serverSide) return filteredData;
440
452
  const activeField = Object.keys(sortState).find((k) => sortState[k] !== "none");
441
453
  if (!activeField) return filteredData;
454
+ const activeCol = columns.find((c) => c.field === activeField);
455
+ const sortOrder = Array.isArray(activeCol == null ? void 0 : activeCol.sortOrder) ? activeCol.sortOrder : null;
456
+ const sortOrderIndex = (val) => {
457
+ const idx = sortOrder.indexOf(val);
458
+ return idx === -1 ? sortOrder.length : idx;
459
+ };
442
460
  return [...filteredData].sort((a, b) => {
443
461
  const dir = sortState[activeField] === "ascending" ? 1 : -1;
444
462
  const aVal = a[activeField];
445
463
  const bVal = b[activeField];
464
+ if (typeof (activeCol == null ? void 0 : activeCol.sortComparator) === "function") {
465
+ return dir * activeCol.sortComparator(aVal, bVal, a, b);
466
+ }
467
+ if (sortOrder) {
468
+ const diff = sortOrderIndex(aVal) - sortOrderIndex(bVal);
469
+ if (diff !== 0) return dir * diff;
470
+ }
446
471
  if (aVal == null && bVal == null) return 0;
447
472
  if (aVal == null) return 1;
448
473
  if (bVal == null) return -1;
@@ -450,7 +475,7 @@ var DataTable = ({
450
475
  if (aVal > bVal) return dir;
451
476
  return 0;
452
477
  });
453
- }, [filteredData, sortState, serverSide]);
478
+ }, [filteredData, sortState, serverSide, columns]);
454
479
  const groupedData = useMemo(() => {
455
480
  if (!groupBy) return null;
456
481
  const source = serverSide ? data : sortedData;
@@ -974,12 +999,12 @@ var DataTable = ({
974
999
  }
975
1000
  );
976
1001
  };
977
- return /* @__PURE__ */ React.createElement(Flex, { direction: "column", gap: "xs" }, /* @__PURE__ */ React.createElement(Flex, { direction: "row", gap: "sm" }, /* @__PURE__ */ React.createElement(Box, { flex: 3 }, /* @__PURE__ */ React.createElement(Flex, { direction: "column", gap: "sm" }, /* @__PURE__ */ React.createElement(Flex, { direction: "row", align: "center", gap: "sm", wrap: "wrap" }, showSearch && searchFields.length > 0 && /* @__PURE__ */ React.createElement(
1002
+ return /* @__PURE__ */ React.createElement(Flex, { direction: "column", gap: "xs" }, /* @__PURE__ */ React.createElement(Flex, { direction: "row", gap: "sm" }, /* @__PURE__ */ React.createElement(Box, { flex: 3 }, /* @__PURE__ */ React.createElement(Flex, { direction: "column", gap: "sm" }, /* @__PURE__ */ React.createElement(Flex, { direction: "row", align: "end", gap: "sm", wrap: "wrap" }, showSearch && searchFields.length > 0 && /* @__PURE__ */ React.createElement(
978
1003
  SearchInput,
979
1004
  {
980
1005
  name: "datatable-search",
981
1006
  placeholder: searchPlaceholder,
982
- value: searchTerm,
1007
+ value: internalSearchTerm,
983
1008
  onChange: handleSearchChange
984
1009
  }
985
1010
  ), filters.slice(0, filterInlineLimit).map(renderFilterControl), filters.length > filterInlineLimit && /* @__PURE__ */ React.createElement(
package/dist/index.js CHANGED
@@ -29,8 +29,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
29
29
  // src/index.js
30
30
  var src_exports = {};
31
31
  __export(src_exports, {
32
+ AutoStatusTag: () => AutoStatusTag,
33
+ AutoTag: () => AutoTag,
32
34
  DataTable: () => DataTable,
33
35
  FormBuilder: () => FormBuilder,
36
+ createStatusTagSortComparator: () => createStatusTagSortComparator,
37
+ getAutoStatusTagVariant: () => getAutoStatusTagVariant,
38
+ getAutoTagVariant: () => getAutoTagVariant,
34
39
  useFormPrefill: () => useFormPrefill
35
40
  });
36
41
  module.exports = __toCommonJS(src_exports);
@@ -311,7 +316,9 @@ var DataTable = ({
311
316
  const initialSortState = (0, import_react.useMemo)(() => {
312
317
  return normalizeSortState(columns, defaultSort);
313
318
  }, [columns, defaultSort]);
314
- const [internalSearchTerm, setInternalSearchTerm] = (0, import_react.useState)("");
319
+ const [internalSearchTerm, setInternalSearchTerm] = (0, import_react.useState)(
320
+ () => serverSide && searchValue != null ? searchValue : ""
321
+ );
315
322
  const [internalFilterValues, setInternalFilterValues] = (0, import_react.useState)(() => {
316
323
  const init = {};
317
324
  filters.forEach((f) => {
@@ -322,7 +329,16 @@ var DataTable = ({
322
329
  const [internalSortState, setInternalSortState] = (0, import_react.useState)(initialSortState);
323
330
  const [currentPage, setCurrentPage] = (0, import_react.useState)(1);
324
331
  const [showMoreFilters, setShowMoreFilters] = (0, import_react.useState)(false);
332
+ const lastAppliedSearchRef = (0, import_react.useRef)(
333
+ serverSide && searchValue != null ? searchValue : ""
334
+ );
325
335
  const searchTerm = serverSide && searchValue != null ? searchValue : internalSearchTerm;
336
+ (0, import_react.useEffect)(() => {
337
+ if (!serverSide || searchValue == null) return;
338
+ if (searchValue === lastAppliedSearchRef.current) return;
339
+ lastAppliedSearchRef.current = searchValue;
340
+ setInternalSearchTerm(searchValue);
341
+ }, [serverSide, searchValue]);
326
342
  const filterValues = serverSide && externalFilterValues != null ? externalFilterValues : internalFilterValues;
327
343
  const externalSortState = (0, import_react.useMemo)(
328
344
  () => normalizeSortState(columns, externalSort),
@@ -356,15 +372,16 @@ var DataTable = ({
356
372
  const handleSearchChange = (0, import_react.useCallback)((term) => {
357
373
  setInternalSearchTerm(term);
358
374
  resetPage();
375
+ const dispatch = () => {
376
+ lastAppliedSearchRef.current = term;
377
+ fireSearchCallback(term);
378
+ fireParamsChange({ search: term, page: resetPageOnChange ? 1 : void 0 });
379
+ };
359
380
  if (searchDebounce > 0) {
360
381
  if (debounceRef.current) clearTimeout(debounceRef.current);
361
- debounceRef.current = setTimeout(() => {
362
- fireSearchCallback(term);
363
- fireParamsChange({ search: term, page: resetPageOnChange ? 1 : void 0 });
364
- }, searchDebounce);
382
+ debounceRef.current = setTimeout(dispatch, searchDebounce);
365
383
  } else {
366
- fireSearchCallback(term);
367
- fireParamsChange({ search: term, page: resetPageOnChange ? 1 : void 0 });
384
+ dispatch();
368
385
  }
369
386
  }, [searchDebounce, fireSearchCallback, fireParamsChange, resetPage, resetPageOnChange]);
370
387
  (0, import_react.useEffect)(() => () => {
@@ -446,10 +463,23 @@ var DataTable = ({
446
463
  if (serverSide) return filteredData;
447
464
  const activeField = Object.keys(sortState).find((k) => sortState[k] !== "none");
448
465
  if (!activeField) return filteredData;
466
+ const activeCol = columns.find((c) => c.field === activeField);
467
+ const sortOrder = Array.isArray(activeCol == null ? void 0 : activeCol.sortOrder) ? activeCol.sortOrder : null;
468
+ const sortOrderIndex = (val) => {
469
+ const idx = sortOrder.indexOf(val);
470
+ return idx === -1 ? sortOrder.length : idx;
471
+ };
449
472
  return [...filteredData].sort((a, b) => {
450
473
  const dir = sortState[activeField] === "ascending" ? 1 : -1;
451
474
  const aVal = a[activeField];
452
475
  const bVal = b[activeField];
476
+ if (typeof (activeCol == null ? void 0 : activeCol.sortComparator) === "function") {
477
+ return dir * activeCol.sortComparator(aVal, bVal, a, b);
478
+ }
479
+ if (sortOrder) {
480
+ const diff = sortOrderIndex(aVal) - sortOrderIndex(bVal);
481
+ if (diff !== 0) return dir * diff;
482
+ }
453
483
  if (aVal == null && bVal == null) return 0;
454
484
  if (aVal == null) return 1;
455
485
  if (bVal == null) return -1;
@@ -457,7 +487,7 @@ var DataTable = ({
457
487
  if (aVal > bVal) return dir;
458
488
  return 0;
459
489
  });
460
- }, [filteredData, sortState, serverSide]);
490
+ }, [filteredData, sortState, serverSide, columns]);
461
491
  const groupedData = (0, import_react.useMemo)(() => {
462
492
  if (!groupBy) return null;
463
493
  const source = serverSide ? data : sortedData;
@@ -981,12 +1011,12 @@ var DataTable = ({
981
1011
  }
982
1012
  );
983
1013
  };
984
- return /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "column", gap: "xs" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "row", gap: "sm" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Box, { flex: 3 }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "column", gap: "sm" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "row", align: "center", gap: "sm", wrap: "wrap" }, showSearch && searchFields.length > 0 && /* @__PURE__ */ import_react.default.createElement(
1014
+ return /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "column", gap: "xs" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "row", gap: "sm" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Box, { flex: 3 }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "column", gap: "sm" }, /* @__PURE__ */ import_react.default.createElement(import_ui_extensions.Flex, { direction: "row", align: "end", gap: "sm", wrap: "wrap" }, showSearch && searchFields.length > 0 && /* @__PURE__ */ import_react.default.createElement(
985
1015
  import_ui_extensions.SearchInput,
986
1016
  {
987
1017
  name: "datatable-search",
988
1018
  placeholder: searchPlaceholder,
989
- value: searchTerm,
1019
+ value: internalSearchTerm,
990
1020
  onChange: handleSearchChange
991
1021
  }
992
1022
  ), filters.slice(0, filterInlineLimit).map(renderFilterControl), filters.length > filterInlineLimit && /* @__PURE__ */ import_react.default.createElement(
@@ -3449,9 +3479,212 @@ var FormBuilder = (0, import_react2.forwardRef)(function FormBuilder2(props, ref
3449
3479
  formContent
3450
3480
  );
3451
3481
  });
3482
+
3483
+ // src/common-components/AutoTag.js
3484
+ var import_react3 = __toESM(require("react"));
3485
+ var import_ui_extensions3 = require("@hubspot/ui-extensions");
3486
+
3487
+ // src/utils/tagVariants.js
3488
+ var DEFAULT_VARIANT = "default";
3489
+ var DANGER_VARIANT = "danger";
3490
+ var ERROR_VARIANT = "error";
3491
+ var SUCCESS_MATCHERS = [
3492
+ "active",
3493
+ "success",
3494
+ "succeeded",
3495
+ "complete",
3496
+ "completed",
3497
+ "approved",
3498
+ "won",
3499
+ "healthy",
3500
+ "enabled",
3501
+ "connected",
3502
+ "paid",
3503
+ "live",
3504
+ "published",
3505
+ "available",
3506
+ "synced",
3507
+ "resolved"
3508
+ ];
3509
+ var WARNING_MATCHERS = [
3510
+ "warning",
3511
+ "at risk",
3512
+ "risky",
3513
+ "pending",
3514
+ "paused",
3515
+ "pause",
3516
+ "on hold",
3517
+ "hold",
3518
+ "review",
3519
+ "expiring",
3520
+ "trial",
3521
+ "in progress",
3522
+ "awaiting",
3523
+ "scheduled"
3524
+ ];
3525
+ var DANGER_MATCHERS = [
3526
+ "danger",
3527
+ "error",
3528
+ "failed",
3529
+ "failure",
3530
+ "inactive",
3531
+ "disabled",
3532
+ "blocked",
3533
+ "cancelled",
3534
+ "canceled",
3535
+ "rejected",
3536
+ "denied",
3537
+ "churned",
3538
+ "lost",
3539
+ "overdue",
3540
+ "expired",
3541
+ "offline",
3542
+ "deleted",
3543
+ "archived",
3544
+ "unpaid"
3545
+ ];
3546
+ var INFO_MATCHERS = [
3547
+ "info",
3548
+ "new",
3549
+ "queued",
3550
+ "processing",
3551
+ "progress",
3552
+ "upcoming",
3553
+ "draft",
3554
+ "open"
3555
+ ];
3556
+ var normalizeTagValue = (value) => {
3557
+ if (value == null) return "";
3558
+ if (typeof value === "boolean") return value ? "true" : "false";
3559
+ return String(value).trim().toLowerCase().replace(/[_-]+/g, " ").replace(/\s+/g, " ");
3560
+ };
3561
+ var matchesAny = (value, matchers) => matchers.some((matcher) => {
3562
+ if (value === matcher) return true;
3563
+ return ` ${value} `.includes(` ${matcher} `);
3564
+ });
3565
+ var getSemanticVariant = (value, options = {}) => {
3566
+ const normalized = normalizeTagValue(value);
3567
+ const fallback = options.fallback || DEFAULT_VARIANT;
3568
+ if (!normalized) return fallback;
3569
+ if (options.overrides) {
3570
+ const overrideKey = Object.keys(options.overrides).find(
3571
+ (key) => normalizeTagValue(key) === normalized
3572
+ );
3573
+ if (overrideKey) return options.overrides[overrideKey];
3574
+ }
3575
+ if (normalized === "true") return "success";
3576
+ if (normalized === "false") return fallback;
3577
+ if (matchesAny(normalized, SUCCESS_MATCHERS)) return "success";
3578
+ if (matchesAny(normalized, DANGER_MATCHERS)) return DANGER_VARIANT;
3579
+ if (matchesAny(normalized, WARNING_MATCHERS)) return "warning";
3580
+ if (matchesAny(normalized, INFO_MATCHERS)) return "info";
3581
+ return fallback;
3582
+ };
3583
+ var getAutoTagVariant = (value, options = {}) => {
3584
+ const semanticVariant = getSemanticVariant(value, options);
3585
+ return semanticVariant === DANGER_VARIANT ? ERROR_VARIANT : semanticVariant;
3586
+ };
3587
+ var getAutoStatusTagVariant = (value, options = {}) => getSemanticVariant(value, options);
3588
+ var getAutoTagDisplayValue = (value) => {
3589
+ if (typeof value === "boolean") return value ? "True" : "False";
3590
+ return value;
3591
+ };
3592
+ var DEFAULT_STATUS_TAG_COLOR_ORDER = [
3593
+ "success",
3594
+ "warning",
3595
+ "danger",
3596
+ "error",
3597
+ "info",
3598
+ "default"
3599
+ ];
3600
+ var createStatusTagSortComparator = (options = {}) => {
3601
+ const {
3602
+ variantOrder = DEFAULT_STATUS_TAG_COLOR_ORDER,
3603
+ overrides,
3604
+ fallback,
3605
+ getLabel
3606
+ } = options;
3607
+ const variantIndex = (variant) => {
3608
+ const idx = variantOrder.indexOf(variant);
3609
+ return idx === -1 ? variantOrder.length : idx;
3610
+ };
3611
+ const labelOf = (value) => {
3612
+ if (getLabel) return String(getLabel(value) ?? "");
3613
+ if (value == null) return "";
3614
+ return String(getAutoTagDisplayValue(value) ?? "");
3615
+ };
3616
+ return (aVal, bVal) => {
3617
+ const aVariant = getSemanticVariant(aVal, { overrides, fallback });
3618
+ const bVariant = getSemanticVariant(bVal, { overrides, fallback });
3619
+ const diff = variantIndex(aVariant) - variantIndex(bVariant);
3620
+ if (diff !== 0) return diff;
3621
+ return labelOf(aVal).localeCompare(labelOf(bVal));
3622
+ };
3623
+ };
3624
+
3625
+ // src/common-components/AutoTag.js
3626
+ var AutoTag = ({
3627
+ value,
3628
+ tag,
3629
+ children,
3630
+ variant,
3631
+ overrides,
3632
+ fallback,
3633
+ ...props
3634
+ }) => {
3635
+ const resolvedValue = value ?? tag ?? children;
3636
+ const displayValue = children ?? getAutoTagDisplayValue(resolvedValue);
3637
+ const resolvedVariant = variant || getAutoTagVariant(resolvedValue, {
3638
+ overrides,
3639
+ fallback
3640
+ });
3641
+ return import_react3.default.createElement(
3642
+ import_ui_extensions3.Tag,
3643
+ { variant: resolvedVariant, ...props },
3644
+ displayValue
3645
+ );
3646
+ };
3647
+
3648
+ // src/common-components/AutoStatusTag.js
3649
+ var import_react4 = __toESM(require("react"));
3650
+ var import_ui_extensions4 = require("@hubspot/ui-extensions");
3651
+ var AutoStatusTag = ({
3652
+ value,
3653
+ status,
3654
+ children,
3655
+ variant,
3656
+ overrides,
3657
+ fallback,
3658
+ ...props
3659
+ }) => {
3660
+ const resolvedValue = value ?? status ?? children;
3661
+ const displayValue = children ?? getAutoTagDisplayValue(resolvedValue);
3662
+ const resolvedVariant = variant || getAutoStatusTagVariant(resolvedValue, {
3663
+ overrides,
3664
+ fallback
3665
+ });
3666
+ return import_react4.default.createElement(
3667
+ import_ui_extensions4.StatusTag,
3668
+ { variant: resolvedVariant, ...props },
3669
+ displayValue
3670
+ );
3671
+ };
3672
+
3673
+ // src/common-components/KeyValueList.js
3674
+ var import_react5 = __toESM(require("react"));
3675
+ var import_ui_extensions5 = require("@hubspot/ui-extensions");
3676
+
3677
+ // src/common-components/SectionHeader.js
3678
+ var import_react6 = __toESM(require("react"));
3679
+ var import_ui_extensions6 = require("@hubspot/ui-extensions");
3452
3680
  // Annotate the CommonJS export names for ESM import in node:
3453
3681
  0 && (module.exports = {
3682
+ AutoStatusTag,
3683
+ AutoTag,
3454
3684
  DataTable,
3455
3685
  FormBuilder,
3686
+ createStatusTagSortComparator,
3687
+ getAutoStatusTagVariant,
3688
+ getAutoTagVariant,
3456
3689
  useFormPrefill
3457
3690
  });