@majoo-ui/react 2.2.0 → 2.3.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.
- package/components/editableTable/EditableMobile.esm.js +4 -6
- package/components/editableTable/EditableTable.esm.js +7 -7
- package/components/form/components/InputSelect/InputSelect.esm.js +38 -29
- package/components/form/components/InputSelectCheck/InputSelectCheck.esm.js +166 -158
- package/components/mapPicker/MapPicker.esm.js +5 -3
- package/components/mapPicker/hooks/useMapSearch.esm.js +24 -5
- package/components/popover/Popover.esm.js +12 -3
- package/components/popover/middleware.esm.js +43 -0
- package/components/table/MobileTable.esm.js +4 -6
- package/components/table/Table.esm.js +63 -95
- package/components/table/components/columns/RowMenuColumn.esm.js +0 -5
- package/components/table/locale.esm.js +91 -0
- package/config/locale/LocaleTextContext.esm.js +5 -0
- package/index.esm.css +4 -4
- package/index.esm.js +1 -0
- package/majoo-provider/MajooProvider.esm.js +16 -3
- package/package.json +2 -2
- package/src/components/editableTable/EditableMobile.d.ts +1 -0
- package/src/components/editableTable/EditableTable.d.ts +9 -18
- package/src/components/table/MobileTable.d.ts +1 -0
- package/src/components/table/index.d.ts +2 -0
- package/src/components/table/locale.d.ts +40 -0
- package/src/config/locale/LocaleTextContext.d.ts +10 -0
|
@@ -82,7 +82,19 @@ function useMapSearch({
|
|
|
82
82
|
}, abortControllerRef.current.signal);
|
|
83
83
|
// getFullAddress returns null if aborted
|
|
84
84
|
if (fullAddress) {
|
|
85
|
-
|
|
85
|
+
// Keep the chosen item's coordinates; the reverse geocode only supplies the address.
|
|
86
|
+
const {
|
|
87
|
+
display_name,
|
|
88
|
+
place_id,
|
|
89
|
+
address
|
|
90
|
+
} = fullAddress;
|
|
91
|
+
handleSelect({
|
|
92
|
+
lat: item.lat,
|
|
93
|
+
lon: item.lon,
|
|
94
|
+
display_name,
|
|
95
|
+
place_id,
|
|
96
|
+
address
|
|
97
|
+
});
|
|
86
98
|
}
|
|
87
99
|
}), [getFullAddress, handleSelect]);
|
|
88
100
|
const handleSearchLatLng = useCallback(latLng => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -90,19 +102,26 @@ function useMapSearch({
|
|
|
90
102
|
// Cancel any previous pending request
|
|
91
103
|
(_b = abortControllerRef.current) === null || _b === void 0 ? void 0 : _b.abort();
|
|
92
104
|
abortControllerRef.current = new AbortController();
|
|
105
|
+
// Move the center now, so a re-render while the address loads (or a failed lookup)
|
|
106
|
+
// does not send the map back to the previous point.
|
|
107
|
+
setCenter({
|
|
108
|
+
lat: Number(latLng.lat),
|
|
109
|
+
lng: Number(latLng.lng)
|
|
110
|
+
});
|
|
93
111
|
const fullAddress = yield getFullAddress(latLng, abortControllerRef.current.signal);
|
|
94
112
|
// getFullAddress returns null if aborted
|
|
95
113
|
if (fullAddress) {
|
|
114
|
+
// Nominatim answers with the coordinates of the OSM object it matched (for a large
|
|
115
|
+
// polygon such as a golf course, its centroid), not the point that was asked about.
|
|
116
|
+
// Keep the requested point; the reverse geocode only supplies the address.
|
|
96
117
|
const {
|
|
97
|
-
lat,
|
|
98
|
-
lon,
|
|
99
118
|
display_name,
|
|
100
119
|
place_id,
|
|
101
120
|
address
|
|
102
121
|
} = fullAddress;
|
|
103
122
|
handleSelect({
|
|
104
|
-
lat,
|
|
105
|
-
lon,
|
|
123
|
+
lat: String(latLng.lat),
|
|
124
|
+
lon: String(latLng.lng),
|
|
106
125
|
display_name,
|
|
107
126
|
place_id,
|
|
108
127
|
address
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { useFloating,
|
|
1
|
+
import { useFloating, autoUpdate, useInteractions, useClick, useDismiss, FloatingFocusManager, FloatingPortal } from '@floating-ui/react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import { useState, useEffect, useContext, cloneElement, createContext } from 'react';
|
|
4
4
|
import Flex from '../../layout/flex/Flex.esm.js';
|
|
5
5
|
import { foundations } from '@majoo-ui/core';
|
|
6
6
|
import { ConditionalWrapper } from '../../wrapper/ConditionalWrapper.esm.js';
|
|
7
|
+
import { createPopoverMiddleware } from './middleware.esm.js';
|
|
7
8
|
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
8
9
|
|
|
9
10
|
const {
|
|
@@ -17,7 +18,7 @@ const Popover = ({
|
|
|
17
18
|
placement,
|
|
18
19
|
sideOffset = 5,
|
|
19
20
|
hideOnScroll = false,
|
|
20
|
-
flip
|
|
21
|
+
flip = true,
|
|
21
22
|
onClose
|
|
22
23
|
}) => {
|
|
23
24
|
const [openState, setOpenState] = useState(false);
|
|
@@ -27,9 +28,17 @@ const Popover = ({
|
|
|
27
28
|
useEffect(() => {
|
|
28
29
|
if (onOpenChange) onOpenChange(openState);
|
|
29
30
|
}, [openState, onOpenChange]);
|
|
31
|
+
|
|
32
|
+
// floating-ui measures the element PopoverContent renders, so its children must
|
|
33
|
+
// be in-flow (see createPopoverMiddleware). autoUpdate recomputes when content
|
|
34
|
+
// height changes after mount (async options, a menu toggling display).
|
|
30
35
|
const floatingHook = useFloating({
|
|
31
36
|
open: openState,
|
|
32
|
-
|
|
37
|
+
whileElementsMounted: autoUpdate,
|
|
38
|
+
middleware: createPopoverMiddleware({
|
|
39
|
+
sideOffset,
|
|
40
|
+
flip
|
|
41
|
+
}),
|
|
33
42
|
onOpenChange: isOpen => {
|
|
34
43
|
setOpenState(isOpen);
|
|
35
44
|
!isOpen && onClose?.();
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { offset, flip, shift, size } from '@floating-ui/react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The floating-ui middleware every majoo-ui dropdown shares, so Popover and the
|
|
5
|
+
* components that drive floating-ui themselves (InputSelectCheck) place content
|
|
6
|
+
* the same way.
|
|
7
|
+
*
|
|
8
|
+
* - `flip` treats `placement` as a preference: the other side is used when the
|
|
9
|
+
* preferred one lacks room.
|
|
10
|
+
* - `size` writes two CSS variables on the floating element, which consumers opt
|
|
11
|
+
* into: `--majoo-popover-available-height` (room left on the chosen side) and
|
|
12
|
+
* `--majoo-popover-reference-width` (width of the trigger).
|
|
13
|
+
*
|
|
14
|
+
* floating-ui measures the floating element itself, so its content must be
|
|
15
|
+
* in-flow — an all-absolute child measures 0px and flip/shift never fire.
|
|
16
|
+
*/
|
|
17
|
+
// Floor for the reported available height. Without it, flip and size lock each
|
|
18
|
+
// other: a menu that opens while still `display: none` measures 0px, flip keeps a
|
|
19
|
+
// side with almost no room, size reports ~0px, the menu's max-height collapses to
|
|
20
|
+
// 0 and never changes size again — so autoUpdate never re-runs flip. With a floor
|
|
21
|
+
// the box always has real height, flip moves it to the roomier side, and size then
|
|
22
|
+
// grows it from there.
|
|
23
|
+
const MIN_AVAILABLE_HEIGHT = 120;
|
|
24
|
+
const createPopoverMiddleware = ({
|
|
25
|
+
sideOffset = 5,
|
|
26
|
+
flip: flip$1 = true
|
|
27
|
+
} = {}) => [offset(sideOffset), flip$1 && flip({
|
|
28
|
+
padding: 8
|
|
29
|
+
}), shift({
|
|
30
|
+
padding: 8
|
|
31
|
+
}), size({
|
|
32
|
+
padding: 8,
|
|
33
|
+
apply({
|
|
34
|
+
availableHeight,
|
|
35
|
+
rects,
|
|
36
|
+
elements
|
|
37
|
+
}) {
|
|
38
|
+
elements.floating.style.setProperty('--majoo-popover-available-height', `${Math.max(MIN_AVAILABLE_HEIGHT, availableHeight)}px`);
|
|
39
|
+
elements.floating.style.setProperty('--majoo-popover-reference-width', `${rects.reference.width}px`);
|
|
40
|
+
}
|
|
41
|
+
})].filter(Boolean);
|
|
42
|
+
|
|
43
|
+
export { createPopoverMiddleware };
|
|
@@ -18,7 +18,7 @@ import Text from '../text/Text.esm.js';
|
|
|
18
18
|
import { ConditionalWrapper } from '../../wrapper/ConditionalWrapper.esm.js';
|
|
19
19
|
import { ContextMenuTrigger } from '../contextMenu/ContextMenu.esm.js';
|
|
20
20
|
import Paragraph from '../paragraph/Paragraph.esm.js';
|
|
21
|
-
import {
|
|
21
|
+
import { defaultTableLocaleText } from './locale.esm.js';
|
|
22
22
|
|
|
23
23
|
const TableContainer = styled(Flex, {
|
|
24
24
|
position: 'relative',
|
|
@@ -88,12 +88,10 @@ const MobileTable = /*#__PURE__*/React__default.forwardRef(({
|
|
|
88
88
|
footerData,
|
|
89
89
|
footerColumnIds,
|
|
90
90
|
headerRowSpan,
|
|
91
|
-
keyId = 'id'
|
|
91
|
+
keyId = 'id',
|
|
92
|
+
sortColumnTitle = defaultTableLocaleText.sortColumnTitle
|
|
92
93
|
}, ref) => {
|
|
93
94
|
var _a, _b, _c, _d;
|
|
94
|
-
const {
|
|
95
|
-
t
|
|
96
|
-
} = useTranslation('MajooUI/table');
|
|
97
95
|
const {
|
|
98
96
|
getTableProps,
|
|
99
97
|
getTableBodyProps,
|
|
@@ -190,7 +188,7 @@ const MobileTable = /*#__PURE__*/React__default.forwardRef(({
|
|
|
190
188
|
children: headerGroup.headers.filter((column, index) => filterMobileHeader(column, index)).map(column => {
|
|
191
189
|
const headerRender = column.render('Header');
|
|
192
190
|
return jsx(TableHeadCell, Object.assign({}, column.getHeaderProps(isHeaderSortable(column) ? column.getSortByToggleProps({
|
|
193
|
-
title:
|
|
191
|
+
title: sortColumnTitle
|
|
194
192
|
}) : {
|
|
195
193
|
onClick: column.onToggle
|
|
196
194
|
}), {
|
|
@@ -44,8 +44,8 @@ import { alignCss, headerAlignCss, resolveCellCss } from './utils/columnStyles.e
|
|
|
44
44
|
import { footerValueOf } from './utils/footerValue.esm.js';
|
|
45
45
|
import { HeaderTooltip } from './utils/HeaderTooltip.esm.js';
|
|
46
46
|
import { isHeaderSortable, getAriaSort } from './utils/headerSort.esm.js';
|
|
47
|
+
import { useTableLocaleText, i18nTableLocaleText } from './locale.esm.js';
|
|
47
48
|
import { useSticky, getStickyValue, getMarginRight } from 'react-table-sticky';
|
|
48
|
-
import { useTranslation } from 'react-i18next';
|
|
49
49
|
import { useVirtual } from 'react-virtual';
|
|
50
50
|
import { PlusPrimitive } from '@majoo-ui/icons';
|
|
51
51
|
import '../scrollSync/ScrollSync.esm.js';
|
|
@@ -524,9 +524,9 @@ const formattingData = (rawData, rowGroup) => {
|
|
|
524
524
|
}
|
|
525
525
|
return rawData;
|
|
526
526
|
};
|
|
527
|
-
const
|
|
527
|
+
const emptyStateProps = (asset, title, description, isMobile) => ({
|
|
528
528
|
doodleImage: jsx(TableEmptyStateDoodle, {
|
|
529
|
-
asset:
|
|
529
|
+
asset: asset,
|
|
530
530
|
"aria-hidden": "true"
|
|
531
531
|
}),
|
|
532
532
|
title: jsx(Paragraph, {
|
|
@@ -536,48 +536,31 @@ const defaultEmptyDataProps = (t, isMobile) => ({
|
|
|
536
536
|
css: {
|
|
537
537
|
marginTop: isMobile ? 0 : '$spacing-05'
|
|
538
538
|
},
|
|
539
|
-
children:
|
|
539
|
+
children: title
|
|
540
540
|
}),
|
|
541
|
-
description: !isMobile ?
|
|
541
|
+
description: !isMobile ? jsx(Paragraph, {
|
|
542
542
|
paragraph: "shortContentRegular",
|
|
543
543
|
color: "secondary",
|
|
544
544
|
align: "center",
|
|
545
|
-
children:
|
|
546
|
-
}) :
|
|
545
|
+
children: description
|
|
546
|
+
}) : jsx(Text, {
|
|
547
547
|
variant: "caption",
|
|
548
548
|
color: "secondary",
|
|
549
549
|
align: "center",
|
|
550
|
-
children:
|
|
551
|
-
})
|
|
552
|
-
});
|
|
553
|
-
const defaultEmptySearchProps = (t, isMobile, query) => ({
|
|
554
|
-
doodleImage: jsx(TableEmptyStateDoodle, {
|
|
555
|
-
asset: "emptySearchData",
|
|
556
|
-
"aria-hidden": "true"
|
|
557
|
-
}),
|
|
558
|
-
title: jsx(Paragraph, {
|
|
559
|
-
paragraph: "shortContentBold",
|
|
560
|
-
color: "primary",
|
|
561
|
-
align: "center",
|
|
562
|
-
css: {
|
|
563
|
-
marginTop: isMobile ? 0 : '$spacing-05'
|
|
564
|
-
},
|
|
565
|
-
children: t('dataNotAvailableTitleSearch', `Oops... ${query} tidak ditemukan`, {
|
|
566
|
-
query
|
|
567
|
-
})
|
|
568
|
-
}),
|
|
569
|
-
description: !isMobile ? jsxs(Paragraph, {
|
|
570
|
-
paragraph: "shortContentRegular",
|
|
571
|
-
color: "secondary",
|
|
572
|
-
align: "center",
|
|
573
|
-
children: [t('dataNotAvailableDescriptionSearch_1', 'Coba lagi dengan memasukkan'), ' ', t('dataNotAvailableDescriptionSearch_2', 'kata kunci yang tepat')]
|
|
574
|
-
}) : jsxs(Text, {
|
|
575
|
-
variant: "caption",
|
|
576
|
-
color: "secondary",
|
|
577
|
-
align: "center",
|
|
578
|
-
children: [t('dataNotAvailableDescriptionSearch_1', 'Coba lagi dengan memasukkan'), jsx("br", {}), t('dataNotAvailableDescriptionSearch_2', 'kata kunci yang tepat')]
|
|
550
|
+
children: description
|
|
579
551
|
})
|
|
580
552
|
});
|
|
553
|
+
/**
|
|
554
|
+
* Builds the default empty state from resolved table texts.
|
|
555
|
+
* Passing an i18next `t` function as the first argument is deprecated.
|
|
556
|
+
*/
|
|
557
|
+
const defaultEmptyDataProps = (localeText, isMobile) => {
|
|
558
|
+
const text = typeof localeText === 'function' ? i18nTableLocaleText(localeText) : localeText;
|
|
559
|
+
return emptyStateProps('emptyData', text.emptyDataTitle, text.emptyDataDescription, isMobile);
|
|
560
|
+
};
|
|
561
|
+
const defaultEmptySearchProps = (localeText, isMobile, query) => emptyStateProps('emptySearchData', localeText.emptySearchTitle({
|
|
562
|
+
query
|
|
563
|
+
}), localeText.emptySearchDescription, isMobile);
|
|
581
564
|
function HeaderMenuOption(props) {
|
|
582
565
|
const {
|
|
583
566
|
open,
|
|
@@ -587,7 +570,8 @@ function HeaderMenuOption(props) {
|
|
|
587
570
|
headerGroups,
|
|
588
571
|
id,
|
|
589
572
|
filterHeader: items,
|
|
590
|
-
rowData
|
|
573
|
+
rowData,
|
|
574
|
+
title
|
|
591
575
|
} = props;
|
|
592
576
|
const {
|
|
593
577
|
headers = []
|
|
@@ -601,7 +585,7 @@ function HeaderMenuOption(props) {
|
|
|
601
585
|
asChild: true,
|
|
602
586
|
children: children
|
|
603
587
|
}), jsx(ModalDialogTitle, {
|
|
604
|
-
children:
|
|
588
|
+
children: title
|
|
605
589
|
}), jsx(ModalDialogContent, {
|
|
606
590
|
css: {
|
|
607
591
|
overflowY: visibleHeaders.filter(val => typeof val.Header === 'string').length > 8 ? 'scroll' : 'none'
|
|
@@ -710,8 +694,9 @@ function Table({
|
|
|
710
694
|
fetchData,
|
|
711
695
|
hideDataInfo = false,
|
|
712
696
|
rowsPerPageOptions = [10, 25, 50, 100],
|
|
713
|
-
|
|
697
|
+
localeText,
|
|
714
698
|
customEmptyDataProps: emptyDataProps,
|
|
699
|
+
customEmptySearchProps: emptySearchProps,
|
|
715
700
|
isLoading = false,
|
|
716
701
|
css,
|
|
717
702
|
headerCss,
|
|
@@ -766,11 +751,11 @@ function Table({
|
|
|
766
751
|
const [filteredHeader, setFilteredHeader] = useState([]);
|
|
767
752
|
const [hasDarkParent, setHasDarkParent] = useState(false);
|
|
768
753
|
const [hoveredRowId, setHoveredRowId] = useState(null);
|
|
769
|
-
const {
|
|
770
|
-
|
|
771
|
-
}
|
|
754
|
+
const tableLocaleText = useTableLocaleText(paginationLabel && {
|
|
755
|
+
pagination: paginationLabel
|
|
756
|
+
}, localeText);
|
|
772
757
|
const isMobile = useMediaQuery(isMobileLayout === undefined ? '(max-width: 1024px)' : isMobileLayout ? '(max-width: 8000px)' : '(max-width: 0px)');
|
|
773
|
-
const customEmptyDataProps = searchQuery ? defaultEmptySearchProps(
|
|
758
|
+
const customEmptyDataProps = searchQuery ? emptySearchProps || defaultEmptySearchProps(tableLocaleText, isMobile, searchQuery) : emptyDataProps || defaultEmptyDataProps(tableLocaleText, isMobile);
|
|
774
759
|
const getInitialState = () => {
|
|
775
760
|
const initialState = {};
|
|
776
761
|
if (fetchData) {
|
|
@@ -903,56 +888,37 @@ function Table({
|
|
|
903
888
|
});
|
|
904
889
|
if (fetchData) fetchData(fetchParams);
|
|
905
890
|
};
|
|
906
|
-
const renderFooter = () => {
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
setPageSize(selectedItem);
|
|
921
|
-
setLimit(selectedItem);
|
|
922
|
-
}
|
|
923
|
-
},
|
|
924
|
-
hideDataInfo: hideDataInfo || isExpandableTree,
|
|
925
|
-
onPageChange: page => {
|
|
926
|
-
doFetchData(page - 1, pageSize);
|
|
927
|
-
gotoPage(page - 1);
|
|
928
|
-
},
|
|
929
|
-
rowsPerPageOptions: rowsPerPageOptions,
|
|
930
|
-
showingText: (_a = paginationLabel === null || paginationLabel === void 0 ? void 0 : paginationLabel.showingText) !== null && _a !== void 0 ? _a : t('pagination.showingText', 'Tampilkan:'),
|
|
931
|
-
showingCountText: (_b = paginationLabel === null || paginationLabel === void 0 ? void 0 : paginationLabel.showingCountText) !== null && _b !== void 0 ? _b : ({
|
|
932
|
-
from,
|
|
933
|
-
to,
|
|
934
|
-
total
|
|
935
|
-
}) => t('pagination.showingCountText', `Ditampilkan ${from} - ${to} dari ${total} data`, {
|
|
936
|
-
from,
|
|
937
|
-
to,
|
|
938
|
-
total
|
|
939
|
-
}),
|
|
940
|
-
dialogShowingText: (_c = paginationLabel === null || paginationLabel === void 0 ? void 0 : paginationLabel.dialogShowingText) !== null && _c !== void 0 ? _c : t('pagination.dialogShowingText', 'Tampilkan Data'),
|
|
941
|
-
previousButton: (_d = paginationLabel === null || paginationLabel === void 0 ? void 0 : paginationLabel.previousButton) !== null && _d !== void 0 ? _d : t('pagination.previousButton', 'Sebelumnya'),
|
|
942
|
-
nextButton: (_e = paginationLabel === null || paginationLabel === void 0 ? void 0 : paginationLabel.nextButton) !== null && _e !== void 0 ? _e : t('pagination.nextButton', 'Selanjutnya'),
|
|
943
|
-
gotoPageText: (_f = paginationLabel === null || paginationLabel === void 0 ? void 0 : paginationLabel.gotoPageText) !== null && _f !== void 0 ? _f : t('pagination.gotoPageText', 'Ke Halaman'),
|
|
944
|
-
goToPagePlaceholder: (_g = paginationLabel === null || paginationLabel === void 0 ? void 0 : paginationLabel.goToPagePlaceholder) !== null && _g !== void 0 ? _g : t('pagination.goToPagePlaceholder', 'Contoh: 10'),
|
|
945
|
-
btnCancelText: (_h = paginationLabel === null || paginationLabel === void 0 ? void 0 : paginationLabel.btnCancelText) !== null && _h !== void 0 ? _h : t('pagination.btnCancelText', 'Batal'),
|
|
946
|
-
btnSubmitText: (_j = paginationLabel === null || paginationLabel === void 0 ? void 0 : paginationLabel.btnSubmitText) !== null && _j !== void 0 ? _j : t('pagination.btnSubmitText', 'Lanjutkan'),
|
|
947
|
-
css: {
|
|
948
|
-
backgroundColor: '$bgWhite',
|
|
949
|
-
padding: '$spacing-04 0',
|
|
950
|
-
'@md': {
|
|
951
|
-
padding: '$spacing-06 $spacing-03'
|
|
952
|
-
}
|
|
891
|
+
const renderFooter = () => jsx(Pagination, Object.assign({
|
|
892
|
+
hidePagination: hidePagination || isExpandableTree,
|
|
893
|
+
hideInputPageSection: false,
|
|
894
|
+
limit: pageSize,
|
|
895
|
+
currentPage: pageIndex + 1,
|
|
896
|
+
totalData: totalData,
|
|
897
|
+
totalPage: totalPage,
|
|
898
|
+
onLimitChange: selectedItem => {
|
|
899
|
+
if (selectedItem) {
|
|
900
|
+
// always reset page when limit changed
|
|
901
|
+
gotoPage(0);
|
|
902
|
+
doFetchData(0, selectedItem);
|
|
903
|
+
setPageSize(selectedItem);
|
|
904
|
+
setLimit(selectedItem);
|
|
953
905
|
}
|
|
954
|
-
}
|
|
955
|
-
|
|
906
|
+
},
|
|
907
|
+
hideDataInfo: hideDataInfo || isExpandableTree,
|
|
908
|
+
onPageChange: page => {
|
|
909
|
+
doFetchData(page - 1, pageSize);
|
|
910
|
+
gotoPage(page - 1);
|
|
911
|
+
},
|
|
912
|
+
rowsPerPageOptions: rowsPerPageOptions
|
|
913
|
+
}, tableLocaleText.pagination, {
|
|
914
|
+
css: {
|
|
915
|
+
backgroundColor: '$bgWhite',
|
|
916
|
+
padding: '$spacing-04 0',
|
|
917
|
+
'@md': {
|
|
918
|
+
padding: '$spacing-06 $spacing-03'
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
}));
|
|
956
922
|
const renderInfiniteScrollWrapper = children => jsx(ConditionalWrapper, {
|
|
957
923
|
condition: isInfiniteScroll && rawData.length > 0,
|
|
958
924
|
wrapper: children => jsx(InfiniteScroll, {
|
|
@@ -1059,7 +1025,7 @@ function Table({
|
|
|
1059
1025
|
children: visibleHeaders.map((column, index) => {
|
|
1060
1026
|
const headerRender = column.render('Header');
|
|
1061
1027
|
return jsx(TableHeadCell, Object.assign({}, column.getHeaderProps(props => [props, isHeaderSortable(column) ? column.getSortByToggleProps({
|
|
1062
|
-
title:
|
|
1028
|
+
title: tableLocaleText.sortColumnTitle
|
|
1063
1029
|
}) : {
|
|
1064
1030
|
onClick: column.onToggle
|
|
1065
1031
|
}, {
|
|
@@ -1303,7 +1269,7 @@ function Table({
|
|
|
1303
1269
|
}, index) => {
|
|
1304
1270
|
const headerRender = column.render('Header');
|
|
1305
1271
|
return jsx(TableHeadCell, Object.assign({}, column.getHeaderProps(props => [props, isHeaderSortable(column) ? column.getSortByToggleProps({
|
|
1306
|
-
title:
|
|
1272
|
+
title: tableLocaleText.sortColumnTitle
|
|
1307
1273
|
}) : {
|
|
1308
1274
|
onClick: column.onToggle
|
|
1309
1275
|
}, {
|
|
@@ -1621,6 +1587,7 @@ function Table({
|
|
|
1621
1587
|
onChange: handleFilterHeaderChange,
|
|
1622
1588
|
headerGroups: headerGroups,
|
|
1623
1589
|
filterHeader: filterHeader,
|
|
1590
|
+
title: tableLocaleText.showColumnTitle,
|
|
1624
1591
|
children: jsx(IconButton, {
|
|
1625
1592
|
css: {
|
|
1626
1593
|
zIndex: '$docked',
|
|
@@ -1695,7 +1662,8 @@ function Table({
|
|
|
1695
1662
|
footerData: footerData,
|
|
1696
1663
|
footerColumnIds: (footerData === null || footerData === void 0 ? void 0 : footerData.length) ? new Set(visibleColumns.filter(column => column.Footer !== emptyRenderer).map(column => column.id)) : undefined,
|
|
1697
1664
|
headerRowSpan: headerRowSpan,
|
|
1698
|
-
keyId: keyId
|
|
1665
|
+
keyId: keyId,
|
|
1666
|
+
sortColumnTitle: tableLocaleText.sortColumnTitle
|
|
1699
1667
|
})]
|
|
1700
1668
|
});
|
|
1701
1669
|
}
|
|
@@ -3,7 +3,6 @@ import 'core-js/modules/es.iterator.map.js';
|
|
|
3
3
|
import React__default, { useState } from 'react';
|
|
4
4
|
import { EllipsisHorizontalOutline } from '@majoo-ui/icons';
|
|
5
5
|
import Box from '../../../../layout/box/Box.esm.js';
|
|
6
|
-
import { useTranslation } from 'react-i18next';
|
|
7
6
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
8
7
|
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuPortal, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator } from '../../../dropdownMenu/DropdownMenu.esm.js';
|
|
9
8
|
import IconButton from '../../../iconButton/IconButton.esm.js';
|
|
@@ -13,11 +12,7 @@ const rowMenuColumn = (options, icon, config) => ({
|
|
|
13
12
|
options,
|
|
14
13
|
Header: () => null,
|
|
15
14
|
Cell: props => {
|
|
16
|
-
const {
|
|
17
|
-
t
|
|
18
|
-
} = useTranslation('MajooUI/table');
|
|
19
15
|
const defaultConfig = {
|
|
20
|
-
mobileTitle: t('rowMenuMobileLabel', 'Aksi'),
|
|
21
16
|
cssContent: {},
|
|
22
17
|
cssMenuItem: {},
|
|
23
18
|
align: 'end'
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import 'core-js/modules/es.iterator.constructor.js';
|
|
2
|
+
import 'core-js/modules/es.iterator.filter.js';
|
|
3
|
+
import 'core-js/modules/es.iterator.reduce.js';
|
|
4
|
+
import { useContext, useMemo } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import { LocaleTextContext } from '../../config/locale/LocaleTextContext.esm.js';
|
|
7
|
+
|
|
8
|
+
const defaultTableLocaleText = {
|
|
9
|
+
sortColumnTitle: 'Urutkan',
|
|
10
|
+
showColumnTitle: 'Tampilkan Kolom',
|
|
11
|
+
emptyDataTitle: 'Data tidak tersedia',
|
|
12
|
+
emptyDataDescription: 'Belum ada data yang dapat ditampilkan di halaman ini',
|
|
13
|
+
emptySearchTitle: ({
|
|
14
|
+
query
|
|
15
|
+
}) => `Oops... ${query} tidak ditemukan`,
|
|
16
|
+
emptySearchDescription: 'Coba lagi dengan memasukkan kata kunci yang tepat',
|
|
17
|
+
pagination: {
|
|
18
|
+
showingText: 'Tampilkan:',
|
|
19
|
+
showingCountText: ({
|
|
20
|
+
from,
|
|
21
|
+
to,
|
|
22
|
+
total
|
|
23
|
+
}) => `Ditampilkan ${from} - ${to} dari ${total} data`,
|
|
24
|
+
dialogShowingText: 'Tampilkan Data',
|
|
25
|
+
previousButton: 'Sebelumnya',
|
|
26
|
+
nextButton: 'Selanjutnya',
|
|
27
|
+
gotoPageText: 'Ke Halaman',
|
|
28
|
+
goToPagePlaceholder: 'Contoh: 10',
|
|
29
|
+
btnCancelText: 'Batal',
|
|
30
|
+
btnSubmitText: 'Lanjutkan'
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
// Transitional: keeps apps that still ship `MajooUI/table` locale files translated until they pass
|
|
34
|
+
// `localeText`. Remove together with the react-i18next dependency of the table family.
|
|
35
|
+
const i18nTableLocaleText = t => {
|
|
36
|
+
const d = defaultTableLocaleText;
|
|
37
|
+
return {
|
|
38
|
+
sortColumnTitle: t('sortColumnTitle', d.sortColumnTitle),
|
|
39
|
+
showColumnTitle: t('customColumnTitle', d.showColumnTitle),
|
|
40
|
+
emptyDataTitle: t('dataNotAvailableTitle', d.emptyDataTitle),
|
|
41
|
+
emptyDataDescription: `${t('dataNotAvailableDescription_1', 'Belum ada data yang dapat ditampilkan')} ${t('dataNotAvailableDescription_2', 'di halaman ini')}`,
|
|
42
|
+
emptySearchTitle: ({
|
|
43
|
+
query
|
|
44
|
+
}) => t('dataNotAvailableTitleSearch', `Oops... ${query} tidak ditemukan`, {
|
|
45
|
+
query
|
|
46
|
+
}),
|
|
47
|
+
emptySearchDescription: `${t('dataNotAvailableDescriptionSearch_1', 'Coba lagi dengan memasukkan')} ${t('dataNotAvailableDescriptionSearch_2', 'kata kunci yang tepat')}`,
|
|
48
|
+
pagination: {
|
|
49
|
+
showingText: t('pagination.showingText', d.pagination.showingText),
|
|
50
|
+
showingCountText: ({
|
|
51
|
+
from,
|
|
52
|
+
to,
|
|
53
|
+
total
|
|
54
|
+
}) => t('pagination.showingCountText', `Ditampilkan ${from} - ${to} dari ${total} data`, {
|
|
55
|
+
from,
|
|
56
|
+
to,
|
|
57
|
+
total
|
|
58
|
+
}),
|
|
59
|
+
dialogShowingText: t('pagination.dialogShowingText', d.pagination.dialogShowingText),
|
|
60
|
+
previousButton: t('pagination.previousButton', d.pagination.previousButton),
|
|
61
|
+
nextButton: t('pagination.nextButton', d.pagination.nextButton),
|
|
62
|
+
gotoPageText: t('pagination.gotoPageText', d.pagination.gotoPageText),
|
|
63
|
+
goToPagePlaceholder: t('pagination.goToPagePlaceholder', d.pagination.goToPagePlaceholder),
|
|
64
|
+
btnCancelText: t('pagination.btnCancelText', d.pagination.btnCancelText),
|
|
65
|
+
btnSubmitText: t('pagination.btnSubmitText', d.pagination.btnSubmitText)
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
const definedEntries = obj => obj ? Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== undefined)) : {};
|
|
70
|
+
/** Later sources win; an `undefined` value never erases an earlier one. */
|
|
71
|
+
const mergeTableLocaleText = (base, ...overrides) => overrides.reduce((merged, override) => Object.assign(Object.assign(Object.assign({}, merged), definedEntries(override)), {
|
|
72
|
+
pagination: Object.assign(Object.assign({}, merged.pagination), definedEntries(override === null || override === void 0 ? void 0 : override.pagination))
|
|
73
|
+
}), base);
|
|
74
|
+
/**
|
|
75
|
+
* Resolves the table texts. Precedence: the table's own `localeText`, then `MajooProvider`'s
|
|
76
|
+
* `localeText.table`, then the app's `MajooUI/table` translations, then the Indonesian defaults.
|
|
77
|
+
* Several table-level overrides may be passed; later ones win. Pass the same number on every render.
|
|
78
|
+
*/
|
|
79
|
+
const useTableLocaleText = (...localeTexts) => {
|
|
80
|
+
const {
|
|
81
|
+
t
|
|
82
|
+
} = useTranslation('MajooUI/table');
|
|
83
|
+
const {
|
|
84
|
+
table: appLocaleText
|
|
85
|
+
} = useContext(LocaleTextContext);
|
|
86
|
+
return useMemo(() => mergeTableLocaleText(i18nTableLocaleText(t), appLocaleText, ...localeTexts),
|
|
87
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
88
|
+
[t, appLocaleText, ...localeTexts]);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export { defaultTableLocaleText, i18nTableLocaleText, mergeTableLocaleText, useTableLocaleText };
|
package/index.esm.css
CHANGED
package/index.esm.js
CHANGED
|
@@ -42,6 +42,7 @@ export { NativeTimePicker, TimePicker } from './components/datePicker/timePicker
|
|
|
42
42
|
export { InputTimePicker } from './components/datePicker/timePicker/InputTimePicker.esm.js';
|
|
43
43
|
export { DatePickerMulti } from './components/datePicker/DatePickerMulti.esm.js';
|
|
44
44
|
export { Cell, Table, TableBody, TableCell, TableColumn, TableContent, TableFoot, TableFootCell, TableFootRow, TableHead, TableHeadCellContent, TableHeaderCellContainer, TableRow, addOnCellStyle, defaultEmptyDataProps, defaultFetchDataParams } from './components/table/Table.esm.js';
|
|
45
|
+
export { defaultTableLocaleText } from './components/table/locale.esm.js';
|
|
45
46
|
export { default as MobileTable } from './components/table/MobileTable.esm.js';
|
|
46
47
|
export { PageDialog, PageDialogContent, PageDialogFooter, PageDialogTitle, PageDialogTrigger } from './components/pageDialog/PageDialog.esm.js';
|
|
47
48
|
export { default as DevicePreview, ImageDevicePreview } from './components/devicePreview/DevicePreview.esm.js';
|
|
@@ -5,14 +5,17 @@ import { theme } from '../config/stitches.config.esm.js';
|
|
|
5
5
|
import PropTypes from 'prop-types';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
import moment from 'moment';
|
|
8
|
+
import { LocaleTextContext } from '../config/locale/LocaleTextContext.esm.js';
|
|
8
9
|
import { jsx } from 'react/jsx-runtime';
|
|
9
10
|
|
|
11
|
+
const EMPTY_LOCALE_TEXT = {};
|
|
10
12
|
function MajooProvider({
|
|
11
13
|
children,
|
|
12
14
|
name,
|
|
13
15
|
theme: theme$1 = theme,
|
|
14
16
|
extendStyle,
|
|
15
|
-
disableGlobalStyle
|
|
17
|
+
disableGlobalStyle,
|
|
18
|
+
localeText = EMPTY_LOCALE_TEXT
|
|
16
19
|
}) {
|
|
17
20
|
!disableGlobalStyle && applyGlobalStyles(extendStyle, theme$1);
|
|
18
21
|
const {
|
|
@@ -22,7 +25,10 @@ function MajooProvider({
|
|
|
22
25
|
return /*#__PURE__*/jsx(ThemeProvider, {
|
|
23
26
|
name: name,
|
|
24
27
|
theme: theme$1,
|
|
25
|
-
children:
|
|
28
|
+
children: /*#__PURE__*/jsx(LocaleTextContext.Provider, {
|
|
29
|
+
value: localeText,
|
|
30
|
+
children: children
|
|
31
|
+
})
|
|
26
32
|
});
|
|
27
33
|
}
|
|
28
34
|
MajooProvider.propTypes = {
|
|
@@ -30,7 +36,14 @@ MajooProvider.propTypes = {
|
|
|
30
36
|
theme: PropTypes.object.isRequired,
|
|
31
37
|
children: PropTypes.node.isRequired,
|
|
32
38
|
extendStyle: PropTypes.object,
|
|
33
|
-
disableGlobalStyle: PropTypes.bool
|
|
39
|
+
disableGlobalStyle: PropTypes.bool,
|
|
40
|
+
/**
|
|
41
|
+
* Component texts for the whole app, e.g. `{ table: { emptyDataTitle: 'No data' } }`.
|
|
42
|
+
* Memoize it: every new object re-renders all components that read it.
|
|
43
|
+
*/
|
|
44
|
+
localeText: PropTypes.shape({
|
|
45
|
+
table: PropTypes.object
|
|
46
|
+
})
|
|
34
47
|
};
|
|
35
48
|
MajooProvider.defaultProps = {
|
|
36
49
|
name: 'default',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@majoo-ui/react",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"main": "./index.esm.js",
|
|
5
5
|
"sideEffects": [
|
|
6
6
|
"*.css",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@floating-ui/react": "^0.19.2",
|
|
38
38
|
"@majoo-ui/core": "1.32.0",
|
|
39
39
|
"@majoo-ui/helpers": "1.30.9",
|
|
40
|
-
"@majoo-ui/icons": "1.40.
|
|
40
|
+
"@majoo-ui/icons": "1.40.4",
|
|
41
41
|
"@monsonjeremy/react-leaflet": "^3.2.2",
|
|
42
42
|
"@radix-ui/react-accordion": "^1.0.0",
|
|
43
43
|
"@radix-ui/react-alert-dialog": "^1.0.3",
|
|
@@ -18,6 +18,7 @@ interface EditableMobileProps<Data extends object> {
|
|
|
18
18
|
hiddenColumns?: string[];
|
|
19
19
|
customEmptyDataProps?: EmptyDataProps;
|
|
20
20
|
virtualized?: boolean;
|
|
21
|
+
sortColumnTitle?: string;
|
|
21
22
|
}
|
|
22
23
|
export default function EditableTableMobile(props: EditableMobileProps<any>): JSX.Element;
|
|
23
24
|
export {};
|