@controleonline/ui-default 1.0.272 → 1.0.274

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.
Files changed (45) hide show
  1. package/.github/workflows/publish-npm.yml +91 -0
  2. package/AGENTS.md +1 -1
  3. package/docs/technical/DefaultTable.md +70 -1
  4. package/package.json +22 -22
  5. package/src/react/components/address/DefaultAddress.js +20 -9
  6. package/src/react/components/address/DefaultAddressCoordFields.js +59 -0
  7. package/src/react/components/address/LatLonReadonlyFields.js +2 -2
  8. package/src/react/components/address/defaultAddressStyles.js +13 -1
  9. package/src/react/components/files/DefaultFile.js +2 -2
  10. package/src/react/components/files/DefaultFileColumn.js +1 -1
  11. package/src/react/components/filters/DefaultColumnFilter.js +2 -7
  12. package/src/react/components/filters/DefaultExternalFilters.js +4 -11
  13. package/src/react/components/filters/filterValue.js +65 -0
  14. package/src/react/components/help/DefaultTooltip.js +73 -63
  15. package/src/react/components/help/DefaultTooltip.styles.js +23 -23
  16. package/src/react/components/inputs/DefaultInput.js +301 -210
  17. package/src/react/components/inputs/defaultInputUtils.js +193 -170
  18. package/src/react/components/table/DefaultColumnMenu.js +127 -109
  19. package/src/react/components/table/DefaultTable.js +43 -92
  20. package/src/react/components/table/DefaultTable.styles.js +10 -4
  21. package/src/react/components/table/DefaultTable.utils.js +38 -4
  22. package/src/react/components/table/DefaultTableRows.js +324 -153
  23. package/src/react/components/table/DefaultTableToolbar.js +17 -7
  24. package/src/react/components/table/DefaultTableView.js +118 -0
  25. package/src/react/components/upload/DefaultUpload.js +6 -36
  26. package/src/react/components/upload/DefaultUpload.styles.js +5 -5
  27. package/src/react/components/upload/DefaultUploadAttachmentsList.js +11 -3
  28. package/src/react/hooks/usePostalCodeLookup.js +15 -1
  29. package/src/react/services/addressFormUtils.js +104 -38
  30. package/src/react/services/addressGeo.js +6 -3
  31. package/src/react/utils/tableVisibleColumnsPreferences.js +84 -3
  32. package/src/tests/react/components/files/DefaultFile.test.js +16 -0
  33. package/src/tests/react/components/files/DefaultFileColumn.company.test.js +24 -0
  34. package/src/tests/react/components/help/DefaultTooltip.test.js +93 -0
  35. package/src/tests/react/components/table/DefaultTable.test.js +37 -0
  36. package/src/tests/react/components/table/DefaultTable.utils.test.js +10 -0
  37. package/src/tests/react/components/table/DefaultTableRowActions.test.js +23 -0
  38. package/src/tests/react/components/table/DefaultTableRows.rowActions.test.js +152 -0
  39. package/src/tests/react/components/table/DefaultTableToolbar.waiter.test.js +42 -0
  40. package/src/tests/react/components/upload/defaultUploadLibrary.test.js +31 -9
  41. package/src/tests/react/filters/filterValue.test.js +46 -0
  42. package/src/tests/react/hooks/usePostalCodeLookup.test.js +67 -0
  43. package/src/tests/react/inputs/defaultInputUtils.test.js +9 -1
  44. package/src/tests/react/services/addressFormUtils.test.js +6 -3
  45. package/src/tests/react/utils/tableVisibleColumnsPreferences.test.js +12 -1
@@ -1,26 +1,21 @@
1
1
  import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
- import { Modal, Text, TouchableOpacity, View, useWindowDimensions } from 'react-native';
2
+ import { useWindowDimensions } from 'react-native';
3
3
  import { NavigationRouteContext, useIsFocused } from '@react-navigation/native';
4
4
  import { useStore } from '@store';
5
5
  import { useMessage } from '@controleonline/ui-common/src/react/components/MessageService';
6
- import Icon from 'react-native-vector-icons/Feather';
7
6
  import { normalizeText } from '../inputs/defaultInputUtils';
8
7
  import { DEFAULT_COMPACT_BREAKPOINT, isObject, stableSerialize } from './DefaultTable.utils';
9
8
  import {
10
9
  resolveDefaultTablePreferenceScope,
11
10
  resolveStoredTableViewModePreference,
12
11
  } from '../../utils/tableVisibleColumnsPreferences';
13
- import DefaultTableBody from './DefaultTableBody';
14
- import DefaultTableFooter from './DefaultTableFooter';
15
- import DefaultTableToolbar from './DefaultTableToolbar';
16
- import DefaultForm from '../form/DefaultForm';
17
- import styles from './DefaultTable.styles';
18
12
  import { useDefaultTablePagination } from './useDefaultTablePagination';
19
13
  import {
20
14
  useDefaultTableSortedData,
21
15
  useDefaultTableSortState,
22
16
  } from './useDefaultTableSorting';
23
17
  import useDefaultTableTheme from './useDefaultTableTheme';
18
+ import DefaultTableView from './DefaultTableView';
24
19
 
25
20
  import {
26
21
  assignGetterValue,
@@ -80,6 +75,8 @@ const DefaultTable = ({
80
75
  showSearch = null,
81
76
  showRowActions = true,
82
77
  showToolbar = true,
78
+ showToolbarActions = null,
79
+ showToolbarControls = null,
83
80
  showTotalItemsInCompactToolbar = false,
84
81
  showTotalItemsInFooter = true,
85
82
  sort = null,
@@ -292,6 +289,14 @@ const DefaultTable = ({
292
289
  showSearch,
293
290
  showRowActions: storeDeclaredConfigs.showRowActions === false ? false : showRowActions,
294
291
  showToolbar,
292
+ showToolbarActions:
293
+ showToolbarActions === null
294
+ ? storeDeclaredConfigs.showToolbarActions !== false
295
+ : showToolbarActions !== false,
296
+ showToolbarControls:
297
+ showToolbarControls === null
298
+ ? storeDeclaredConfigs.showToolbarControls !== false
299
+ : showToolbarControls !== false,
295
300
  showTotalItemsInCompactToolbar,
296
301
  showTotalItemsInFooter,
297
302
  sortedData,
@@ -352,6 +357,8 @@ const DefaultTable = ({
352
357
  showSearch,
353
358
  showRowActions,
354
359
  showToolbar,
360
+ showToolbarActions,
361
+ showToolbarControls,
355
362
  showTotalItemsInCompactToolbar,
356
363
  showTotalItemsInFooter,
357
364
  sortedData,
@@ -391,6 +398,8 @@ const DefaultTable = ({
391
398
  showSearch,
392
399
  showRowActions,
393
400
  showToolbar,
401
+ showToolbarActions,
402
+ showToolbarControls,
394
403
  showTotalItemsInCompactToolbar,
395
404
  showTotalItemsInFooter,
396
405
  storedViewMode,
@@ -427,6 +436,8 @@ const DefaultTable = ({
427
436
  showSearch,
428
437
  showRowActions,
429
438
  showToolbar,
439
+ showToolbarActions,
440
+ showToolbarControls,
430
441
  showTotalItemsInCompactToolbar,
431
442
  showTotalItemsInFooter,
432
443
  storedViewMode,
@@ -436,10 +447,10 @@ const DefaultTable = ({
436
447
  ],
437
448
  );
438
449
 
439
- if (store?.getters) {
440
- assignGetterValue(store, 'configs', defaultTableConfigs);
441
- }
442
-
450
+ // Do not mutate store.configs during render. A new configs object is built
451
+ // every pass; writing it here retriggers subscribers and React #185 when
452
+ // opening Adicionar on DefaultTable (categories). Sync only in the hook
453
+ // when defaultTableConfigsSignature changes.
443
454
  useDefaultTableStoreSync({
444
455
  columns,
445
456
  columnsForTable,
@@ -457,87 +468,27 @@ const DefaultTable = ({
457
468
  onDataLoaded?.(sortedData);
458
469
  }, [onDataLoaded, sortedData]);
459
470
 
460
- return (
461
- <View
462
- style={[
463
- styles.wrap,
464
- {
465
- borderWidth: tablePanelBorderColor ? 1 : 0,
466
- borderColor: tablePanelBorderColor,
467
- backgroundColor: themeColors.panelBackground,
468
- },
469
- ]}
470
- >
471
- {showToolbar !== false ? <DefaultTableToolbar storeName={storeName} /> : null}
472
- <DefaultTableBody storeName={storeName} />
473
- <DefaultTableFooter storeName={storeName} />
474
- {shouldRenderBottomAddButton ? (
475
- <View style={styles.bottomAddBar}>
476
- <TouchableOpacity
477
- accessibilityRole="button"
478
- accessibilityLabel={resolvedAddLabel}
479
- activeOpacity={0.84}
480
- style={[
481
- styles.bottomAddButton,
482
- { backgroundColor: floatingAddBackgroundColor },
483
- ]}
484
- onPress={resolvedOnAdd}
485
- >
486
- <Icon name="plus" size={18} color={floatingAddIconColor} />
487
- <Text style={[styles.bottomAddText, { color: floatingAddIconColor }]}>
488
- {resolvedAddLabel}
489
- </Text>
490
- </TouchableOpacity>
491
- </View>
492
- ) : null}
493
- {shouldRenderFloatingAddButton ? (
494
- <TouchableOpacity
495
- accessibilityRole="button"
496
- accessibilityLabel={resolvedAddLabel}
497
- activeOpacity={0.84}
498
- style={[
499
- styles.floatingAddButton,
500
- { backgroundColor: floatingAddBackgroundColor },
501
- ]}
502
- onPress={resolvedOnAdd}
503
- >
504
- <Icon name="plus" size={24} color={floatingAddIconColor} />
505
- </TouchableOpacity>
506
- ) : null}
507
- <Modal
508
- animationType="fade"
509
- onRequestClose={closeCreateForm}
510
- transparent
511
- visible={isCreateFormOpen}
512
- >
513
- <View style={styles.modalOverlay}>
514
- <View style={styles.modalCard}>
515
- <View style={styles.modalHeader}>
516
- <Text style={styles.modalTitle}>{resolvedAddLabel}</Text>
517
- <TouchableOpacity
518
- accessibilityRole="button"
519
- accessibilityLabel={global.t?.t(storeName, 'button', 'cancel') || 'Cancelar'}
520
- onPress={closeCreateForm}
521
- style={styles.modalCloseButton}
522
- >
523
- <Icon name="x" size={16} color={themeColors.textPrimary || '#0F172A'} />
524
- </TouchableOpacity>
525
- </View>
526
- <DefaultForm
527
- actions={resolvedActions}
528
- columns={columnsForTable}
529
- getOptionsForColumn={getOptionsForColumn}
530
- mode="create"
531
- onCancel={closeCreateForm}
532
- onSaved={handleDefaultCreateSaved}
533
- row={requestParamsSeed}
534
- storeName={storeName}
535
- />
536
- </View>
537
- </View>
538
- </Modal>
539
- </View>
540
- );
471
+ return <DefaultTableView {...{
472
+ tablePanelBorderColor,
473
+ themeColors,
474
+ showToolbar,
475
+ storeName,
476
+ showToolbarActions,
477
+ showToolbarControls,
478
+ shouldRenderBottomAddButton,
479
+ resolvedAddLabel,
480
+ floatingAddBackgroundColor,
481
+ resolvedOnAdd,
482
+ floatingAddIconColor,
483
+ shouldRenderFloatingAddButton,
484
+ closeCreateForm,
485
+ isCreateFormOpen,
486
+ resolvedActions,
487
+ columnsForTable,
488
+ getOptionsForColumn,
489
+ handleDefaultCreateSaved,
490
+ requestParamsSeed
491
+ }} />;
541
492
  };
542
493
 
543
494
  export default DefaultTable;
@@ -470,11 +470,13 @@ const styles = StyleSheet.create({
470
470
  textTransform: 'uppercase',
471
471
  },
472
472
  actionsCell: {
473
- minWidth: 96,
473
+ minWidth: 60,
474
+ width: 60,
475
+ flexBasis: 60,
474
476
  flexGrow: 0,
475
477
  flexShrink: 0,
478
+ maxWidth: 72,
476
479
  alignItems: 'center',
477
- paddingHorizontal: 8,
478
480
  },
479
481
  rowActionsGroup: {
480
482
  flexDirection: 'row',
@@ -517,10 +519,11 @@ const styles = StyleSheet.create({
517
519
  },
518
520
  cardsGrid: {
519
521
  paddingVertical: 10,
520
- paddingHorizontal: 8,
521
- gap: 10,
522
+ paddingHorizontal: 0,
523
+ gap: 8,
522
524
  flexGrow: 1,
523
525
  width: '100%',
526
+ alignSelf: 'stretch',
524
527
  },
525
528
  cardsGridWithBottomAdd: {
526
529
  paddingBottom: 86,
@@ -539,8 +542,11 @@ const styles = StyleSheet.create({
539
542
  cardItem: {
540
543
  position: 'relative',
541
544
  flex: 1,
545
+ flexBasis: 0,
546
+ flexGrow: 1,
542
547
  minWidth: 0,
543
548
  width: '100%',
549
+ maxWidth: '100%',
544
550
  alignSelf: 'stretch',
545
551
  },
546
552
  cardItemWithActions: {
@@ -438,6 +438,42 @@ export const normalizeSortText = value =>
438
438
  .replace(/[\u0300-\u036f]/g, '')
439
439
  .toLowerCase();
440
440
 
441
+ export const parseSortNumber = value => {
442
+ if (typeof value === 'number' && Number.isFinite(value)) return value;
443
+ if (value == null) return NaN;
444
+
445
+ const raw = String(value).trim();
446
+ if (!raw || !/[0-9]/.test(raw)) return NaN;
447
+
448
+ const compact = raw.replace(/[^0-9,.-]/g, '');
449
+ if (!compact) return NaN;
450
+
451
+ const hasComma = compact.includes(',');
452
+ const hasDot = compact.includes('.');
453
+ let normalized = compact;
454
+
455
+ if (hasComma && hasDot) {
456
+ normalized = compact.lastIndexOf(',') > compact.lastIndexOf('.')
457
+ ? compact.replace(/\./g, '').replace(',', '.')
458
+ : compact.replace(/,/g, '');
459
+ } else if (hasComma) {
460
+ const parts = compact.split(',');
461
+ normalized = parts.length === 2 && parts[1].length <= 2
462
+ ? `${parts[0].replace(/\./g, '')}.${parts[1]}`
463
+ : compact.replace(/,/g, '');
464
+ } else if (hasDot) {
465
+ const parts = compact.split('.');
466
+ if (parts.length > 2) {
467
+ normalized = compact.replace(/\./g, '');
468
+ } else if (parts.length === 2 && parts[1].length === 3 && parts[0].length <= 3) {
469
+ normalized = compact.replace(/\./g, '');
470
+ }
471
+ }
472
+
473
+ const parsed = Number(normalized);
474
+ return Number.isFinite(parsed) ? parsed : NaN;
475
+ };
476
+
441
477
  export const resolveSortComparable = ({ column, row, storeName, columns }) => {
442
478
  const fieldName = getColumnKey(column);
443
479
  const sortField = getSortField(column);
@@ -472,11 +508,9 @@ export const resolveSortComparable = ({ column, row, storeName, columns }) => {
472
508
  storeName,
473
509
  }));
474
510
 
475
- const normalizedNumber = Number(
476
- String(resolvedValue).replace(/[^0-9,.-]/g, '').replace(',', '.'),
477
- );
511
+ const normalizedNumber = parseSortNumber(resolvedValue);
478
512
 
479
- if (Number.isFinite(normalizedNumber) && String(resolvedValue).match(/[0-9]/)) {
513
+ if (Number.isFinite(normalizedNumber)) {
480
514
  return normalizedNumber;
481
515
  }
482
516