@schukai/monster 4.138.0 → 4.139.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/package.json CHANGED
@@ -1 +1 @@
1
- {"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.6"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"4.138.0"}
1
+ {"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.6"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"4.139.1"}
@@ -690,6 +690,8 @@ function rearrangeItems() {
690
690
  }
691
691
 
692
692
  setSwitchVisible.call(this, shouldShowSwitch);
693
+ updateControlSizing.call(this, layout, shouldShowSwitch);
694
+ updateJoinedBorders.call(this, layout, shouldShowSwitch);
693
695
  if (!shouldShowSwitch) {
694
696
  hide.call(this);
695
697
  }
@@ -740,6 +742,279 @@ function getComputedCssPixels(value) {
740
742
  }
741
743
  }
742
744
 
745
+ /**
746
+ * @private
747
+ * @param {Object} layout
748
+ * @param {boolean} shouldShowSwitch
749
+ * @return {void}
750
+ */
751
+ function updateControlSizing(layout, shouldShowSwitch) {
752
+ const mainItems = [...layout.visibleItemsInMainSlot];
753
+ if (
754
+ shouldShowSwitch &&
755
+ this[popperNavElementSymbol] instanceof HTMLElement
756
+ ) {
757
+ mainItems.push(this[popperNavElementSymbol]);
758
+ }
759
+
760
+ const controlItems = [
761
+ ...mainItems,
762
+ ...layout.itemsToMoveToPopper,
763
+ ];
764
+ for (const element of controlItems) {
765
+ applyControlSizing.call(this, element);
766
+ }
767
+ }
768
+
769
+ /**
770
+ * @private
771
+ * @param {HTMLElement} element
772
+ * @return {void}
773
+ */
774
+ function applyControlSizing(element) {
775
+ setStylePropertyIfChanged(element, "boxSizing", "border-box");
776
+ setStylePropertyIfChanged(
777
+ element,
778
+ "height",
779
+ "var(--monster-control-bar-height)",
780
+ );
781
+ setStylePropertyIfChanged(
782
+ element,
783
+ "minHeight",
784
+ "var(--monster-control-bar-height)",
785
+ );
786
+ if (isWrapperElement(element)) {
787
+ setStylePropertyIfChanged(element, "display", "flex");
788
+ setStylePropertyIfChanged(element, "alignItems", "stretch");
789
+ }
790
+
791
+ for (const control of getContainedControlElements(element)) {
792
+ setStylePropertyIfChanged(control, "display", "flex");
793
+ setStylePropertyIfChanged(control, "boxSizing", "border-box");
794
+ setStylePropertyIfChanged(control, "height", "100%");
795
+ setStylePropertyIfChanged(control, "minHeight", "0px");
796
+ if (control.tagName === "MONSTER-INPUT-GROUP") {
797
+ setStylePropertyIfChanged(control, "flex", "1 1 auto");
798
+ }
799
+ }
800
+ }
801
+
802
+ /**
803
+ * @private
804
+ * @param {HTMLElement} element
805
+ * @return {boolean}
806
+ */
807
+ function isWrapperElement(element) {
808
+ return ["DIV", "FORM", "SECTION"].includes(element.tagName);
809
+ }
810
+
811
+ /**
812
+ * @private
813
+ * @param {HTMLElement} element
814
+ * @return {HTMLElement[]}
815
+ */
816
+ function getContainedControlElements(element) {
817
+ if (!isWrapperElement(element)) {
818
+ return [];
819
+ }
820
+
821
+ return Array.from(
822
+ element.querySelectorAll(
823
+ [
824
+ "monster-input-group",
825
+ "monster-select",
826
+ "monster-button",
827
+ "monster-state-button",
828
+ "monster-message-state-button",
829
+ "monster-action-button",
830
+ "monster-api-button",
831
+ "monster-confirm-button",
832
+ ].join(","),
833
+ ),
834
+ ).filter((control) => control instanceof HTMLElement);
835
+ }
836
+
837
+ /**
838
+ * @private
839
+ * @param {Object} layout
840
+ * @param {boolean} shouldShowSwitch
841
+ * @return {void}
842
+ */
843
+ function updateJoinedBorders(layout, shouldShowSwitch) {
844
+ const mainItems = [...layout.visibleItemsInMainSlot];
845
+ if (
846
+ shouldShowSwitch &&
847
+ this[popperNavElementSymbol] instanceof HTMLElement &&
848
+ this[switchElementSymbol] instanceof HTMLElement
849
+ ) {
850
+ mainItems.push(this[popperNavElementSymbol]);
851
+ }
852
+
853
+ const marginLeftByElement = new Map();
854
+ const marginTopByElement = new Map();
855
+
856
+ collectInlineJoinedBorders.call(this, mainItems, marginLeftByElement);
857
+ collectBlockJoinedBorders.call(
858
+ this,
859
+ layout.itemsToMoveToPopper,
860
+ marginTopByElement,
861
+ );
862
+ applyJoinedBorderOffsets.call(this, marginLeftByElement, marginTopByElement);
863
+ }
864
+
865
+ /**
866
+ * @private
867
+ * @param {HTMLElement[]} elements
868
+ * @param {Map<HTMLElement, string>} marginLeftByElement
869
+ * @return {void}
870
+ */
871
+ function collectInlineJoinedBorders(elements, marginLeftByElement) {
872
+ for (let i = 1; i < elements.length; i++) {
873
+ const previous = elements[i - 1];
874
+ const current = elements[i];
875
+ const overlap = getBorderOverlap(
876
+ getVisualBorderWidth.call(this, previous, "right"),
877
+ getVisualBorderWidth.call(this, current, "left"),
878
+ );
879
+
880
+ if (overlap > 0) {
881
+ marginLeftByElement.set(current, `${-1 * overlap}px`);
882
+ }
883
+ }
884
+ }
885
+
886
+ /**
887
+ * @private
888
+ * @param {HTMLElement[]} elements
889
+ * @param {Map<HTMLElement, string>} marginTopByElement
890
+ * @return {void}
891
+ */
892
+ function collectBlockJoinedBorders(elements, marginTopByElement) {
893
+ for (let i = 1; i < elements.length; i++) {
894
+ const previous = elements[i - 1];
895
+ const current = elements[i];
896
+ const overlap = getBorderOverlap(
897
+ getVisualBorderWidth.call(this, previous, "bottom"),
898
+ getVisualBorderWidth.call(this, current, "top"),
899
+ );
900
+
901
+ if (overlap > 0) {
902
+ marginTopByElement.set(current, `${-1 * overlap}px`);
903
+ }
904
+ }
905
+ }
906
+
907
+ /**
908
+ * @private
909
+ * @param {Map<HTMLElement, string>} marginLeftByElement
910
+ * @param {Map<HTMLElement, string>} marginTopByElement
911
+ * @return {void}
912
+ */
913
+ function applyJoinedBorderOffsets(marginLeftByElement, marginTopByElement) {
914
+ for (const element of getJoinedBorderOffsetElements.call(this)) {
915
+ setStylePropertyIfChanged(
916
+ element,
917
+ "marginLeft",
918
+ marginLeftByElement.get(element) || "",
919
+ );
920
+ setStylePropertyIfChanged(
921
+ element,
922
+ "marginTop",
923
+ marginTopByElement.get(element) || "",
924
+ );
925
+ }
926
+ }
927
+
928
+ /**
929
+ * @private
930
+ * @return {HTMLElement[]}
931
+ */
932
+ function getJoinedBorderOffsetElements() {
933
+ const elements = Array.from(this.children).filter(
934
+ (element) => element instanceof HTMLElement,
935
+ );
936
+ if (this[popperNavElementSymbol] instanceof HTMLElement) {
937
+ elements.push(this[popperNavElementSymbol]);
938
+ }
939
+
940
+ return elements;
941
+ }
942
+
943
+ /**
944
+ * @private
945
+ * @param {HTMLElement} element
946
+ * @param {"marginLeft"|"marginTop"} property
947
+ * @param {string} value
948
+ * @return {void}
949
+ */
950
+ function setStylePropertyIfChanged(element, property, value) {
951
+ if (element.style[property] !== value) {
952
+ element.style[property] = value;
953
+ }
954
+ }
955
+
956
+ /**
957
+ * @private
958
+ * @param {number} previousBorderWidth
959
+ * @param {number} currentBorderWidth
960
+ * @return {number}
961
+ */
962
+ function getBorderOverlap(previousBorderWidth, currentBorderWidth) {
963
+ return Math.min(previousBorderWidth, currentBorderWidth);
964
+ }
965
+
966
+ /**
967
+ * @private
968
+ * @param {HTMLElement} element
969
+ * @param {"top"|"right"|"bottom"|"left"} side
970
+ * @return {number}
971
+ */
972
+ function getVisualBorderWidth(element, side) {
973
+ const visualElement = getVisualBorderElement.call(this, element, side);
974
+ const computedStyle = getComputedStyle(visualElement);
975
+ const value = computedStyle.getPropertyValue(`border-${side}-width`);
976
+
977
+ return getComputedCssPixels(value);
978
+ }
979
+
980
+ /**
981
+ * @private
982
+ * @param {HTMLElement} element
983
+ * @param {"top"|"right"|"bottom"|"left"} side
984
+ * @return {HTMLElement}
985
+ */
986
+ function getVisualBorderElement(element, side) {
987
+ if (element === this[popperNavElementSymbol]) {
988
+ return this[switchElementSymbol] || element;
989
+ }
990
+
991
+ const selector = [
992
+ "button",
993
+ "input",
994
+ "select",
995
+ "textarea",
996
+ "monster-input-group",
997
+ "monster-select",
998
+ "[data-monster-role=control]",
999
+ ].join(",");
1000
+ if (element.shadowRoot instanceof ShadowRoot) {
1001
+ return element.shadowRoot.querySelector(selector) || element;
1002
+ }
1003
+
1004
+ const candidates = Array.from(element.querySelectorAll(selector)).filter(
1005
+ (candidate) => candidate instanceof HTMLElement,
1006
+ );
1007
+ if (candidates.length === 0) {
1008
+ return element;
1009
+ }
1010
+
1011
+ if (side === "right" || side === "bottom") {
1012
+ return candidates[candidates.length - 1];
1013
+ }
1014
+
1015
+ return candidates[0];
1016
+ }
1017
+
743
1018
  /**
744
1019
  * @private
745
1020
  * @return {Object}
@@ -3531,6 +3531,12 @@ function getSelectPopperPositionOptions() {
3531
3531
  popperOptions.strategy = "fixed";
3532
3532
  }
3533
3533
 
3534
+ if (isInControlBar.call(this)) {
3535
+ // Popper content rendered outside a 40px control-bar host must be hit-testable
3536
+ // against the viewport instead of the host's compact shadow boundary.
3537
+ popperOptions.strategy = "fixed";
3538
+ }
3539
+
3534
3540
  return popperOptions;
3535
3541
  }
3536
3542
 
@@ -4873,6 +4879,15 @@ function show() {
4873
4879
  });
4874
4880
  }
4875
4881
 
4882
+ /**
4883
+ * @private
4884
+ * @return {boolean}
4885
+ */
4886
+ function isInControlBar() {
4887
+ return this.closest("monster-control-bar,monster-button-bar") instanceof
4888
+ HTMLElement;
4889
+ }
4890
+
4876
4891
  /**
4877
4892
  * @private
4878
4893
  */
@@ -3,14 +3,22 @@
3
3
  @import "../../style/border.pcss";
4
4
  @import "../../style/typography.pcss";
5
5
 
6
- :host(monster-button){display:flex;}
6
+ :host(monster-button){
7
+ display: flex;
8
+ box-sizing: border-box;
9
+ }
7
10
 
8
11
  [data-monster-role="control"] {
9
12
  display: flex;
10
- align-items: stretch;
13
+ align-items: stretch;
14
+ box-sizing: border-box;
15
+ height: 100%;
16
+ width: 100%;
11
17
  }
12
18
 
13
19
  button {
20
+ box-sizing: border-box;
21
+ height: 100%;
14
22
  width: 100%;
15
23
  min-width: max-content;
16
24
  }
@@ -19,6 +19,7 @@ div[data-monster-role="control"] {
19
19
  flex-direction: row;
20
20
  justify-content: flex-start;
21
21
  align-items: stretch;
22
+ height: var(--monster-control-bar-height);
22
23
  min-height: var(--monster-control-bar-height);
23
24
 
24
25
  &[data-monster-layout-alignment="right"] {
@@ -32,11 +33,13 @@ div[data-monster-role="control"] {
32
33
  & [data-monster-role=popper-nav] {
33
34
  display: flex;
34
35
  align-items: stretch;
36
+ height: var(--monster-control-bar-height);
35
37
  min-height: var(--monster-control-bar-height);
36
38
  }
37
39
 
38
40
  & [data-monster-role=switch] {
39
41
  display: flex;
42
+ height: var(--monster-control-bar-height);
40
43
  min-height: var(--monster-control-bar-height);
41
44
 
42
45
  &.hidden {
@@ -45,20 +48,47 @@ div[data-monster-role="control"] {
45
48
  }
46
49
 
47
50
  & ::slotted(*) {
51
+ display: flex;
48
52
  box-sizing: border-box;
53
+ align-self: stretch;
54
+ height: var(--monster-control-bar-height);
49
55
  min-height: var(--monster-control-bar-height);
50
56
  }
51
57
 
58
+ & ::slotted(form),
59
+ & ::slotted(div),
60
+ & ::slotted(section) {
61
+ flex-direction: row;
62
+ align-items: stretch;
63
+ gap: 0;
64
+ }
65
+
52
66
  & ::slotted(input),
53
67
  & ::slotted(select),
54
68
  & ::slotted(textarea),
55
69
  & ::slotted(button) {
70
+ appearance: none;
71
+ box-sizing: border-box;
72
+ border-width: var(--monster-theme-control-border-width, var(--monster-border-width));
73
+ border-radius: var(--monster-theme-control-border-radius, var(--monster-border-radius));
74
+ border-style: var(--monster-theme-control-border-style, var(--monster-border-style));
75
+ border-color: var(--monster-theme-control-border-color, var(--monster-bg-color-primary-4));
76
+ line-height: 1.5;
56
77
  height: var(--monster-control-bar-height);
78
+ padding: var(--monster-select-control-padding, 0.4rem 0.6rem);
79
+ }
80
+
81
+ & ::slotted(monster-select) {
82
+ --monster-select-container-overflow: hidden;
83
+ --monster-select-selection-flex-wrap: nowrap;
84
+ --monster-select-selection-margin: 0;
85
+ --monster-select-control-padding: 0.4rem 0.6rem;
57
86
  }
58
87
 
59
- & ::slotted(*:not(:last-child)) {
60
- margin-right: calc(-1 * var(--monster-border-width));
88
+ & ::slotted(monster-input-group) {
89
+ width: max-content;
61
90
  }
91
+
62
92
  }
63
93
 
64
94
  & slot[name=popper] {
@@ -74,18 +104,43 @@ div[data-monster-role="control"] {
74
104
  display: flex;
75
105
  box-sizing: border-box;
76
106
  width: fill-available;
107
+ height: var(--monster-control-bar-height);
77
108
  min-height: var(--monster-control-bar-height);
78
109
  }
79
110
 
111
+ &::slotted(form),
112
+ &::slotted(div),
113
+ &::slotted(section) {
114
+ flex-direction: row;
115
+ align-items: stretch;
116
+ gap: 0;
117
+ }
118
+
80
119
  &::slotted(input),
81
120
  &::slotted(select),
82
121
  &::slotted(textarea),
83
122
  &::slotted(button) {
123
+ appearance: none;
124
+ box-sizing: border-box;
125
+ border-width: var(--monster-theme-control-border-width, var(--monster-border-width));
126
+ border-radius: var(--monster-theme-control-border-radius, var(--monster-border-radius));
127
+ border-style: var(--monster-theme-control-border-style, var(--monster-border-style));
128
+ border-color: var(--monster-theme-control-border-color, var(--monster-bg-color-primary-4));
129
+ line-height: 1.5;
84
130
  height: var(--monster-control-bar-height);
131
+ padding: var(--monster-select-control-padding, 0.4rem 0.6rem);
132
+ }
133
+
134
+ &::slotted(monster-select) {
135
+ --monster-select-container-overflow: hidden;
136
+ --monster-select-selection-flex-wrap: nowrap;
137
+ --monster-select-selection-margin: 0;
138
+ --monster-select-control-padding: 0.4rem 0.6rem;
85
139
  }
86
140
 
87
- &::slotted(*:not(:first-child)) {
88
- margin-top: calc(-1 * var(--monster-border-width));
141
+ &::slotted(monster-input-group) {
142
+ width: max-content;
89
143
  }
144
+
90
145
  }
91
146
  }
@@ -6,6 +6,9 @@
6
6
  @import "../../style/control.pcss";
7
7
 
8
8
  :host {
9
+ display: flex;
10
+ box-sizing: border-box;
11
+ height: 100%;
9
12
  border-width: var(--monster-theme-control-border-width);
10
13
  border-radius: var(--monster-theme-control-border-radius);
11
14
  border-style: var(--monster-theme-control-border-style);
@@ -18,6 +21,8 @@
18
21
  flex-wrap: nowrap;
19
22
  position: relative;
20
23
  box-sizing: border-box;
24
+ width: 100%;
25
+ height: 100%;
21
26
  }
22
27
 
23
28
 
@@ -11,10 +11,12 @@
11
11
 
12
12
  [data-monster-role=container] {
13
13
  appearance: none;
14
- min-height: 1.4em;
14
+ min-height: 0;
15
15
  flex: 4 0 90%;
16
16
  width: 100%;
17
- overflow: auto;
17
+ overflow: var(--monster-select-container-overflow, auto);
18
+ display: flex;
19
+ align-items: center;
18
20
 
19
21
  scrollbar-color: var(--monster-color-primary-1) var(--monster-bg-color-primary-1);
20
22
  scrollbar-width: thin;
@@ -62,7 +64,7 @@ div[data-monster-role="control"] {
62
64
 
63
65
  font-family: inherit;
64
66
  font-size: 100%;
65
- padding: 0.4rem 0.6rem;
67
+ padding: var(--monster-select-control-padding, 0.4rem 0.6rem);
66
68
  margin: 0;
67
69
  outline: none;
68
70
  box-sizing: border-box;
@@ -79,6 +81,8 @@ div[data-monster-role="control"] {
79
81
  color: var(--monster-color-primary-1);
80
82
 
81
83
  display: flex;
84
+ align-items: center;
85
+ overflow: hidden;
82
86
  width: fill-available;
83
87
 
84
88
  }
@@ -113,11 +117,12 @@ div[data-monster-role="control"] {
113
117
  div[data-monster-role=selection] {
114
118
  display: flex;
115
119
  gap: 5px;
116
- margin: 5px;
120
+ margin: var(--monster-select-selection-margin, 5px);
117
121
  flex-direction: row;
118
122
  justify-content: flex-start;
119
123
  align-items: center;
120
- flex-wrap: wrap;
124
+ flex-wrap: var(--monster-select-selection-flex-wrap, wrap);
125
+ min-height: 0;
121
126
  }
122
127
 
123
128
  [data-monster-role=option-control] {