@visns-studio/visns-components 6.31.0 → 6.31.2
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/README.md
CHANGED
|
@@ -9,6 +9,19 @@ A comprehensive React component library used by the VISNS Studio team for CRM an
|
|
|
9
9
|
|
|
10
10
|
VISNS Components is a React-based UI component library that provides a set of reusable, consistent, and customizable components for building web applications. It includes components for authentication, data grids, forms, navigation, and more, designed to work seamlessly together.
|
|
11
11
|
|
|
12
|
+
## Recent Updates (v6.31.2)
|
|
13
|
+
|
|
14
|
+
### `MergeEntity` compares the two records it is actually merging
|
|
15
|
+
|
|
16
|
+
`processTemplate` substituted `{dataId}` with the current (source) entity
|
|
17
|
+
before applying the caller's own values, so `loadTargetEntity(entityId)`
|
|
18
|
+
fetched the source a second time. Step 3 then diffed the source against
|
|
19
|
+
itself, always reported "no conflicts", and sent an empty `field_overrides`
|
|
20
|
+
map with the merge. Explicit template values now win and `{dataId}` only
|
|
21
|
+
falls back to the current entity when nothing was supplied. Every consumer's
|
|
22
|
+
merge tab (contacts, clients, …) gets a real conflict step without a config
|
|
23
|
+
change.
|
|
24
|
+
|
|
12
25
|
## Recent Updates (v6.31.0)
|
|
13
26
|
|
|
14
27
|
### The header badge self-heals too, and the pop takes its timings from the server
|
package/package.json
CHANGED
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
|
94
94
|
},
|
|
95
95
|
"name": "@visns-studio/visns-components",
|
|
96
|
-
"version": "6.31.
|
|
96
|
+
"version": "6.31.2",
|
|
97
97
|
"description": "Various packages to assist in the development of our Custom Applications.",
|
|
98
98
|
"main": "src/index.js",
|
|
99
99
|
"files": [
|
|
@@ -174,13 +174,16 @@ const MergeEntity = ({ endpoints, config, dataId, onUpdate = () => {} }) => {
|
|
|
174
174
|
const [showAdvanced, setShowAdvanced] = useState(false);
|
|
175
175
|
|
|
176
176
|
// Replace placeholders in URLs
|
|
177
|
+
// Explicit values win: `{dataId}` only falls back to the current entity
|
|
178
|
+
// when the caller did not supply one (loadTargetEntity passes the target's
|
|
179
|
+
// id, and must not be given the source again).
|
|
177
180
|
const processTemplate = (template, data = {}) => {
|
|
178
181
|
let processed = template;
|
|
179
|
-
processed = processed.replace(/\{dataId\}/g, dataId);
|
|
180
182
|
Object.keys(data).forEach((key) => {
|
|
181
183
|
const placeholder = new RegExp(`\\{${key}\\}`, 'g');
|
|
182
184
|
processed = processed.replace(placeholder, data[key]);
|
|
183
185
|
});
|
|
186
|
+
processed = processed.replace(/\{dataId\}/g, dataId);
|
|
184
187
|
return processed;
|
|
185
188
|
};
|
|
186
189
|
|
|
@@ -766,6 +766,8 @@ body.tablet-mode .InovuaReactDataGrid__cell.cell-word-wrap > div {
|
|
|
766
766
|
|
|
767
767
|
/* -- column filter row ---------------------------------------------------- */
|
|
768
768
|
|
|
769
|
+
/* Native controls in the filter row (the <select> filters, and any bare
|
|
770
|
+
<input> that is not one of the toolkit's composite fields below). */
|
|
769
771
|
.InovuaReactDataGrid__column-header__filter input,
|
|
770
772
|
.InovuaReactDataGrid__column-header__filter select {
|
|
771
773
|
height: 28px !important;
|
|
@@ -778,18 +780,130 @@ body.tablet-mode .InovuaReactDataGrid__cell.cell-word-wrap > div {
|
|
|
778
780
|
font-size: 0.75rem !important;
|
|
779
781
|
}
|
|
780
782
|
|
|
781
|
-
/*
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
783
|
+
/* TEXT and NUMERIC filters are composite fields: the toolkit renders a
|
|
784
|
+
wrapper holding the <input> AND, once there is a value, a clear cross (and
|
|
785
|
+
for numbers a pair of spin arrows) as siblings of it. An earlier version of
|
|
786
|
+
this file put the edge on the <input> and stripped the wrapper, which
|
|
787
|
+
looked right only while the field was empty — the moment a value went in,
|
|
788
|
+
the cross appeared OUTSIDE the bordered box, floating beside a shrunken
|
|
789
|
+
input.
|
|
790
|
+
|
|
791
|
+
So they are built the same way as the combo box below: the wrapper is the
|
|
792
|
+
28px bordered field, and everything inside it — input, cross, arrows — is
|
|
793
|
+
borderless furniture laid out along its 26px content box. */
|
|
787
794
|
.InovuaReactDataGrid__column-header__filter.inovua-react-toolkit-text-input,
|
|
788
795
|
.InovuaReactDataGrid__column-header__filter.inovua-react-toolkit-numeric-input {
|
|
796
|
+
display: inline-flex !important;
|
|
797
|
+
align-items: center !important;
|
|
798
|
+
height: 28px !important;
|
|
799
|
+
min-height: 28px !important;
|
|
800
|
+
max-height: 28px !important;
|
|
801
|
+
padding: 0 !important;
|
|
802
|
+
border: 1px solid var(--dgx-line) !important;
|
|
803
|
+
border-radius: 6px !important;
|
|
804
|
+
background: var(--dgx-surface) !important;
|
|
805
|
+
box-shadow: none !important;
|
|
806
|
+
overflow: hidden !important;
|
|
807
|
+
transition:
|
|
808
|
+
border-color 0.15s ease,
|
|
809
|
+
box-shadow 0.15s ease !important;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
/* Same focus treatment as the native date filter beside it. */
|
|
813
|
+
.InovuaReactDataGrid__column-header__filter.inovua-react-toolkit-text-input--focused,
|
|
814
|
+
.InovuaReactDataGrid__column-header__filter.inovua-react-toolkit-numeric-input--focused {
|
|
815
|
+
border-color: #7986cb !important;
|
|
816
|
+
box-shadow: 0 0 0 2px rgba(121, 134, 203, 0.4) !important;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
/* The inner <input> gives up the edge the generic rule above hands every
|
|
820
|
+
filter input: it is the typing area of the field, not a field of its own. */
|
|
821
|
+
.InovuaReactDataGrid__column-header__filter.inovua-react-toolkit-text-input
|
|
822
|
+
.inovua-react-toolkit-text-input__input,
|
|
823
|
+
.InovuaReactDataGrid__column-header__filter.inovua-react-toolkit-numeric-input
|
|
824
|
+
.inovua-react-toolkit-numeric-input__input {
|
|
825
|
+
flex: 1 1 auto !important;
|
|
826
|
+
min-width: 0 !important;
|
|
827
|
+
height: 100% !important;
|
|
828
|
+
min-height: 0 !important;
|
|
829
|
+
margin: 0 !important;
|
|
830
|
+
padding: 0 0.5rem !important;
|
|
789
831
|
border: 0 !important;
|
|
790
832
|
border-radius: 0 !important;
|
|
791
833
|
background: none !important;
|
|
792
834
|
box-shadow: none !important;
|
|
835
|
+
outline: none !important;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
/* The numeric wrapper wraps its input in one more box; let it fill. */
|
|
839
|
+
.InovuaReactDataGrid__column-header__filter.inovua-react-toolkit-numeric-input
|
|
840
|
+
.inovua-react-toolkit-numeric-input__number-input {
|
|
841
|
+
flex: 1 1 auto !important;
|
|
842
|
+
min-width: 0 !important;
|
|
843
|
+
height: 100% !important;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
/* The clear cross: a fixed-width tool at the trailing edge, inside the box.
|
|
847
|
+
The vendored `flex: 1` would have let it grow to half the field. */
|
|
848
|
+
.InovuaReactDataGrid__column-header__filter.inovua-react-toolkit-text-input
|
|
849
|
+
.inovua-react-toolkit-text-input__clear-button-wrapper,
|
|
850
|
+
.InovuaReactDataGrid__column-header__filter.inovua-react-toolkit-numeric-input
|
|
851
|
+
.inovua-react-toolkit-numeric-input__clear-button-wrapper {
|
|
852
|
+
flex: 0 0 auto !important;
|
|
853
|
+
display: flex !important;
|
|
854
|
+
align-items: center !important;
|
|
855
|
+
height: 100% !important;
|
|
856
|
+
margin: 0 !important;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
.InovuaReactDataGrid__column-header__filter.inovua-react-toolkit-text-input
|
|
860
|
+
.inovua-react-toolkit-text-input__clear-button,
|
|
861
|
+
.InovuaReactDataGrid__column-header__filter.inovua-react-toolkit-numeric-input
|
|
862
|
+
.inovua-react-toolkit-numeric-input__clear-button {
|
|
863
|
+
flex: 0 0 auto !important;
|
|
864
|
+
width: 22px !important;
|
|
865
|
+
height: 100% !important;
|
|
866
|
+
margin: 0 2px 0 0 !important;
|
|
867
|
+
padding: 0 !important;
|
|
868
|
+
stroke: var(--dgx-muted) !important;
|
|
869
|
+
border-radius: 4px !important;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
.InovuaReactDataGrid__column-header__filter.inovua-react-toolkit-text-input
|
|
873
|
+
.inovua-react-toolkit-text-input__clear-button:hover,
|
|
874
|
+
.InovuaReactDataGrid__column-header__filter.inovua-react-toolkit-numeric-input
|
|
875
|
+
.inovua-react-toolkit-numeric-input__clear-button:hover {
|
|
876
|
+
stroke: var(--dgx-ink) !important;
|
|
877
|
+
background: var(--dgx-hover) !important;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
/* The number spinner: the vendored 30px column overflowed the 26px content
|
|
881
|
+
box and its arrows were painted outside the field. Pin it to the field's
|
|
882
|
+
height, at the trailing edge, and let the hidden variant take no room. */
|
|
883
|
+
.InovuaReactDataGrid__column-header__filter.inovua-react-toolkit-numeric-input
|
|
884
|
+
.inovua-react-toolkit-numeric-input__spinner-wrapper {
|
|
885
|
+
flex: 0 0 auto !important;
|
|
886
|
+
width: 18px !important;
|
|
887
|
+
height: 100% !important;
|
|
888
|
+
min-height: 0 !important;
|
|
889
|
+
margin: 0 !important;
|
|
890
|
+
fill: var(--dgx-muted) !important;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
.InovuaReactDataGrid__column-header__filter.inovua-react-toolkit-numeric-input
|
|
894
|
+
.inovua-react-toolkit-numeric-input__spinner-wrapper-hidden {
|
|
895
|
+
display: none !important;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
.InovuaReactDataGrid__column-header__filter.inovua-react-toolkit-numeric-input
|
|
899
|
+
.inovua-react-toolkit-numeric-input__spinner-arrow {
|
|
900
|
+
padding: 0 3px !important;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
.InovuaReactDataGrid__column-header__filter.inovua-react-toolkit-numeric-input
|
|
904
|
+
.inovua-react-toolkit-numeric-input__spinner-arrow:hover {
|
|
905
|
+
fill: var(--dgx-ink) !important;
|
|
906
|
+
background: var(--dgx-hover) !important;
|
|
793
907
|
}
|
|
794
908
|
|
|
795
909
|
/* A COMBO BOX is built the other way round, and it matters.
|
|
@@ -308,10 +308,33 @@ input[type]:not([type='search']):not([type='url']):not([type='hidden']):not(
|
|
|
308
308
|
width: 100%;
|
|
309
309
|
line-height: 1;
|
|
310
310
|
font-size: 0.85rem;
|
|
311
|
+
}
|
|
311
312
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
313
|
+
/* The focus border, as its own rule and NOT nested under the list above.
|
|
314
|
+
|
|
315
|
+
Nested `&:focus` is `:is(<the whole list>):focus`, and `:is()` takes the
|
|
316
|
+
specificity of its MOST specific argument — the twenty-clause `input` chain.
|
|
317
|
+
So the focus border on a plain `<select>` carried a specificity no consumer
|
|
318
|
+
stylesheet could reach without `!important`: a select styled as a borderless
|
|
319
|
+
segment of a custom control grew a full navy box the moment it was focused.
|
|
320
|
+
Stated per element, `select:focus` is (0,1,1) again and a consumer's own
|
|
321
|
+
rule wins as it should. The input chain keeps the specificity it always had. */
|
|
322
|
+
textarea:focus,
|
|
323
|
+
select:focus,
|
|
324
|
+
input[type]:not([type='search']):not([type='url']):not([type='hidden']):not(
|
|
325
|
+
[type='checkbox']
|
|
326
|
+
):not([type='radio']):not(.inovua-react-toolkit-numeric-input__input):not(
|
|
327
|
+
.inovua-react-toolkit-combo-box__input
|
|
328
|
+
):not(.inovua-react-toolkit-date-input__input):not(
|
|
329
|
+
.inovua-react-toolkit-text-input__input
|
|
330
|
+
):not(.inovua-react-toolkit-numeric-input__input):not(
|
|
331
|
+
.variable-inserter-search-input
|
|
332
|
+
):not(.react-datepicker__month-select):not(
|
|
333
|
+
.react-datepicker__year-select
|
|
334
|
+
):not(.visns-native-date-filter__input):not([type='date']):not(
|
|
335
|
+
[type='datetime-local']
|
|
336
|
+
):not([type='time']):not([class*='searchInput']):not([class*='filterInput']):not([class*='rowActionPickerSearch']):focus {
|
|
337
|
+
border: 1px solid var(--primary-color);
|
|
315
338
|
}
|
|
316
339
|
|
|
317
340
|
/* THE DROPDOWN ARROW, restored. The rule further up gives `select` its
|