@@ -16,11 +16,29 @@ const defaultSettings = {
1616 // [`position1', 'position2'] - only use specific fallback positions
1717 fallbackStrategy : 'adjacent' ,
1818
19+ // whether to add a pointing arrow
20+ arrow : true ,
21+
22+ offset : 0 , // distance offset from calculated position
23+ distance : 14 , // distance away from pointing to
24+
25+ alwaysShow : false , // always show element regardless of whether it fits
26+ anchorName : 'anchor-{count}' , // name of anchor
27+
28+ moveElement : true , // whether to move element to same positioning context
29+
30+ observeChanges : true , // whether to observe changes and move element if it no longer fits
31+ containToScroll : true , // whether to contain element to its scroll container
32+ } ;
33+
34+ const createBehavior = ( { $, $el, el, self, cache, settings, classNames, error, debug, index, warn } ) => ( {
35+ anchorName : null ,
36+
1937 // X X X
2038 // X X X
2139 // X X X
2240 // list of positions permitted to try
23- positions : [
41+ allPositions : [
2442 'top left' ,
2543 'top' ,
2644 'top right' , // TOP SIDE
@@ -33,85 +51,66 @@ const defaultSettings = {
3351 'left bottom' ,
3452 'left' ,
3553 'left top' , // LEFT SIDE
36- 'center' , // INSIDE
3754 ] ,
3855
39- // whether to add a pointing arrow
40- arrow : true ,
41-
42- offset : 0 , // distance offset from calculated position
43- distance : 14 , // distance away from pointing to
44-
45- alwaysShow : false , // always show element regardless of whether it fits
46- anchorName : 'anchor-{count}' , // name of anchor
47-
48- moveElement : true , // whether to move element to same positioning context
49-
50- observeChanges : true , // whether to observe changes and move element if it no longer fits
51- containToScroll : true , // whether to contain element to its scroll container
52- } ;
53-
54- const createBehavior = ( { $, $el, el, self, cache, settings, classNames, error, debug, index, warn } ) => ( {
55- anchorName : null ,
56+ // map of starting position to fallbacks using index of 'allPositions'
57+ // to make this less confusing it is 1-indexed.
58+
59+ /* 1 | 2 | 3
60+ -----------
61+ 12 | | 4
62+ | |
63+ 11 | | 5
64+ | |
65+ 10 | | 6
66+ -----------
67+ 9 | 8 | 7
68+ */
69+ adjacentFallbacks : {
70+ 'top left' : [ 2 , 3 , 12 , 4 , 11 , 5 , 10 , 6 , 9 , 8 , 7 ] ,
71+ 'top' : [ 1 , 3 , 11 , 5 , 12 , 4 , 10 , 6 , 8 , 9 , 7 ] ,
72+ 'top right' : [ 2 , 1 , 4 , 12 , 5 , 11 , 6 , 10 , 7 , 8 , 9 ] ,
73+ 'right top' : [ 5 , 6 , 3 , 7 , 2 , 8 , 1 , 9 , 12 , 11 , 10 ] ,
74+ 'right' : [ 4 , 6 , 2 , 8 , 3 , 7 , 1 , 9 , 11 , 12 , 10 ] ,
75+ 'right bottom' : [ 5 , 4 , 7 , 3 , 8 , 2 , 9 , 1 , 10 , 11 , 12 ] ,
76+ 'bottom right' : [ 8 , 9 , 6 , 10 , 5 , 11 , 4 , 12 , 3 , 2 , 1 ] ,
77+ 'bottom' : [ 7 , 9 , 5 , 11 , 6 , 10 , 4 , 12 , 2 , 3 , 1 ] ,
78+ 'bottom left' : [ 8 , 7 , 10 , 6 , 11 , 5 , 12 , 4 , 1 , 2 , 3 ] ,
79+ 'left bottom' : [ 11 , 12 , 9 , 1 , 8 , 2 , 7 , 3 , 6 , 4 , 4 ] ,
80+ 'left' : [ 10 , 12 , 8 , 2 , 9 , 1 , 7 , 3 , 5 , 4 , 6 ] ,
81+ 'left top' : [ 11 , 10 , 1 , 9 , 2 , 8 , 3 , 7 , 4 , 5 , 6 ] ,
82+ } ,
83+ oppositeFallbacks : {
84+ 'top left' : [ 9 , 2 , 8 , 3 , 7 , 12 , 4 , 11 , 5 , 10 , 6 ] ,
85+ 'top' : [ 8 , 1 , 9 , 3 , 7 , 11 , 5 , 12 , 4 , 10 , 6 ] ,
86+ 'top right' : [ 7 , 2 , 8 , 1 , 9 , 4 , 12 , 5 , 11 , 6 , 10 ] ,
87+ 'right top' : [ 12 , 5 , 11 , 6 , 10 , 3 , 7 , 2 , 8 , 1 , 9 ] ,
88+ 'right' : [ 11 , 4 , 12 , 6 , 10 , 2 , 8 , 3 , 7 , 1 , 9 ] ,
89+ 'right bottom' : [ 10 , 5 , 11 , 4 , 12 , 7 , 3 , 8 , 2 , 9 , 1 ] ,
90+ 'bottom right' : [ 3 , 8 , 2 , 9 , 1 , 6 , 10 , 5 , 11 , 4 , 12 ] ,
91+ 'bottom' : [ 2 , 7 , 3 , 9 , 1 , 5 , 11 , 6 , 10 , 4 , 12 ] ,
92+ 'bottom left' : [ 1 , 8 , 2 , 7 , 3 , 10 , 6 , 11 , 5 , 12 , 4 ] ,
93+ 'left bottom' : [ 6 , 11 , 5 , 12 , 4 , 9 , 1 , 8 , 2 , 7 , 3 ] ,
94+ 'left' : [ 5 , 10 , 6 , 12 , 4 , 2 , 8 , 9 , 1 , 7 , 3 ] ,
95+ 'left top' : [ 4 , 11 , 5 , 10 , 6 , 1 , 9 , 2 , 8 , 3 , 7 ] ,
96+ } ,
5697
98+ // mapping of position name to css using shorthand
99+ // see <decodeCSSShorthand>
57100 positionMapping : {
58- 'top left' : {
59- 'inset-block-end' : 'anchor(top)' ,
60- 'inset-inline-start' : 'anchor(left)' ,
61- } ,
62- 'top' : {
63- 'inset-block-end' : 'anchor(top)' ,
64- 'inset-inline-start' : 'anchor(center)' ,
65- 'translate' : '-50% 0' ,
66- } ,
67- 'top right' : {
68- 'inset-block-end' : 'anchor(top)' ,
69- 'inset-inline-end' : 'anchor(right)' ,
70- } ,
71- 'right bottom' : {
72- 'inset-inline-start' : 'anchor(right)' ,
73- 'inset-block-end' : 'anchor(bottom)' ,
74- } ,
75- 'right' : {
76- 'inset-inline-start' : 'anchor(right)' ,
77- 'inset-block-start' : 'anchor(center)' ,
78- 'translate' : '0 -50%' ,
79- } ,
80- 'right top' : {
81- 'inset-inline-start' : 'anchor(right)' ,
82- 'inset-block-start' : 'anchor(top)' ,
83- } ,
84- 'bottom right' : {
85- 'inset-block-start' : 'anchor(bottom)' ,
86- 'inset-inline-end' : 'anchor(right)' ,
87- } ,
88- 'bottom' : {
89- 'inset-block-start' : 'anchor(bottom)' ,
90- 'inset-inline-start' : 'anchor(center)' ,
91- 'translate' : '-50% 0' ,
92- } ,
93- 'bottom left' : {
94- 'inset-block-start' : 'anchor(bottom)' ,
95- 'inset-inline-start' : 'anchor(left)' ,
96- } ,
97- 'left bottom' : {
98- 'inset-inline-end' : 'anchor(left)' ,
99- 'inset-block-end' : 'anchor(bottom)' ,
100- } ,
101- 'left' : {
102- 'inset-inline-end' : 'anchor(left)' ,
103- 'inset-block-start' : 'anchor(center)' ,
104- 'translate' : '0 -50%' ,
105- } ,
106- 'left top' : {
107- 'inset-inline-end' : 'anchor(left)' ,
108- 'inset-block-start' : 'anchor(top)' ,
109- } ,
110- 'center' : {
111- 'inset-block-start' : 'anchor(center)' ,
112- 'inset-inline-start' : 'anchor(center)' ,
113- 'translate' : '-50% -50%' ,
114- } ,
101+ 'top left' : { ibe : 't' , iis : 'l' } ,
102+ 'top' : { ibe : 't' , iis : 'c' , tr : 'ox' } ,
103+ 'top right' : { ibe : 't' , iie : 'r' } ,
104+ 'right top' : { iis : 'r' , ibs : 't' } ,
105+ 'right' : { iis : 'r' , ibs : 'c' , tr : 'oy' } ,
106+ 'right bottom' : { iis : 'r' , ibe : 'b' } ,
107+ 'bottom right' : { ibs : 'b' , iie : 'r' } ,
108+ 'bottom' : { ibs : 'b' , iis : 'c' , tr : 'ox' } ,
109+ 'bottom left' : { ibs : 'b' , iis : 'l' } ,
110+ 'left bottom' : { iie : 'l' , ibe : 'b' } ,
111+ 'left' : { iie : 'l' , ibs : 'c' , tr : 'oy' } ,
112+ 'left top' : { iie : 'l' , ibs : 't' } ,
113+ 'center' : { ibs : 'c' , iis : 'c' , tr : 'o' } ,
115114 } ,
116115
117116 initialize ( ) {
@@ -139,7 +138,7 @@ const createBehavior = ({ $, $el, el, self, cache, settings, classNames, error,
139138 } ,
140139
141140 getPositioningCSS ( position = settings . position ) {
142- const positionCSS = self . positionMapping [ position ] || { } ;
141+ const positionCSS = self . getDecodedPositionCSS ( position ) ;
143142 const positionReset = {
144143 'inset-block-start' : null ,
145144 'inset-block-end' : null ,
@@ -153,6 +152,33 @@ const createBehavior = ({ $, $el, el, self, cache, settings, classNames, error,
153152 } ;
154153 } ,
155154
155+ // save some filesize on string literals
156+ getDecodedPositionCSS ( position ) {
157+ const shorthands = {
158+ ibs : 'inset-block-start' ,
159+ ibe : 'inset-block-end' ,
160+ iis : 'inset-inline-start' ,
161+ iie : 'inset-inline-end' ,
162+ t : 'anchor(top)' ,
163+ l : 'anchor(left)' ,
164+ b : 'anchor(bottom)' ,
165+ r : 'anchor(right)' ,
166+ c : 'anchor(center)' ,
167+ tr : 'translate' ,
168+ ox : '-50% 0' , // offset x
169+ oy : '0 -50%' , // offset y
170+ o : '-50% -50%' , // offset
171+ } ;
172+ let css = self . positionMapping [ position ] || { } ;
173+ let outputCSS = { } ;
174+ each ( css , ( thisValue , thisProp ) => {
175+ const prop = shorthands [ thisProp ] || thisProp ;
176+ const value = shorthands [ thisValue ] || thisValue ;
177+ outputCSS [ prop ] = value ;
178+ } ) ;
179+ return outputCSS ;
180+ } ,
181+
156182 setAnchorName ( ) {
157183 const $anchor = self . getAnchor ( ) ;
158184 if ( ! $anchor . exists ( ) ) {
@@ -176,25 +202,12 @@ const createBehavior = ({ $, $el, el, self, cache, settings, classNames, error,
176202 }
177203 } ,
178204
205+ // fallback order is implemented as a lookup table
206+ // as the algorithm can get fairly complex for 'adjacent' / 'opposite'
179207 getFallbackOrder ( ) {
180208 if ( settings . fallbackStrategy ) {
181209 return settings . fallbackStrategy ;
182210 }
183- const positions = position . split ( ' ' ) ;
184- const verticalPosition = positions [ 0 ] ;
185- const horizontalPosition = positions [ 1 ] || 'center' ;
186- const opposite = {
187- top : 'bottom' ,
188- bottom : 'top' ,
189- left : 'right' ,
190- right : 'left' ,
191- } ;
192- const adjacent = {
193- left : 'center' ,
194- center : 'right' ,
195- right : 'left' ,
196- } ;
197- // get positions sorted by respected strategy
198211 } ,
199212
200213 getNextPosition ( position = settings . position ) {
0 commit comments