Skip to content

Commit ef92bac

Browse files
author
Tomasz John
committed
update: popper update try, error with ver. 2.1:
Komponent { } użycie CPopperContent Arrow, Popper CDropdownCustom, CPopperTargetHelper, CTooltipPopoverWrapper <ReactPopper modifiers={extendedModifiers} {...attributes} component={tag} className={popperClassName} x-placement={placement || attributes.placement} > {children} {!hideArrow && <Arrow className={arrowClassName} />} </ReactPopper> // modifiers = { offset: { offset }, flip: { enabled: flip, behavior: fallbackPlacement }, preventOverflow: { boundariesElement }, update: { enabled: true, order: 950, fn: handlePlacementChange, }, ...modifiers, }; CDropdownCustom Manager CDropdown, CDropdownItem, CDopdownMenu, CDropdownToggle, CToggler <Manager {...attributes} className={classes} onKeyDown={handleKeyDown} ref={reference} /> CDropdownMenu Popper CWidgetSimple <Tag tabIndex="-1" role="menu" {...attributes} aria-hidden={!context.isOpen} className={classes} x-placement={attributes.placement} ref={innerRef} /> CDropdownToggle Target CWidgetSimple <Target {...attributes} className={classes} component={Tag} onClick={onClick} aria-expanded={context.isOpen} ref={innerRef} > {children} </Target> --
1 parent 3e9994a commit ef92bac

7 files changed

+606
-4
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"prop-types": "^15.7.2",
4949
"react-onclickout": "^2.0.8",
5050
"react-perfect-scrollbar": "~1.5.8",
51+
"react-popper": "^2.1.0",
5152
"react-transition-group": "^4.3.0"
5253
},
5354
"peerDependencies": {
@@ -69,7 +70,6 @@
6970
"eslint-plugin-react": "^7.19.0",
7071
"nwb": "^0.24.3",
7172
"react-app-polyfill": "^1.0.6",
72-
"react-popper": "^0.10.4",
7373
"sinon": "^5.1.1"
7474
},
7575
"repository": {

src/CDropdownCustom-org.js

+270
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
import React, {useEffect, useRef} from 'react';
2+
import ReactDOM from 'react-dom';
3+
import PropTypes from 'prop-types';
4+
import classNames from 'classnames';
5+
import {tagPropType, mapToCssModules, omit, keyCodes} from './Shared/helper.js';
6+
import {Manager} from 'react-popper';
7+
8+
export const Context = React.createContext({});
9+
10+
//component - CoreUI / CPopperContentWrapper
11+
12+
class CPopperContentWrapper extends React.Component {
13+
getChildContext(){
14+
return this.context;
15+
}
16+
render(){
17+
return this.props.children;
18+
}
19+
}
20+
21+
CPopperContentWrapper.propTypes = {
22+
children: PropTypes.node
23+
};
24+
25+
CPopperContentWrapper.contextType = Context;
26+
27+
CPopperContentWrapper.childContextTypes = {
28+
toggle: PropTypes.func.isRequired,
29+
isOpen: PropTypes.bool.isRequired,
30+
direction: PropTypes.oneOf(['up', 'down', 'left', 'right']).isRequired,
31+
inNavbar: PropTypes.bool.isRequired
32+
};
33+
34+
//component - CoreUI / CDropdownCustom
35+
36+
const CDropdownCustom = props=>{
37+
38+
const {
39+
className,
40+
cssModule,
41+
//
42+
innerRef,
43+
show,
44+
group,
45+
size,
46+
inNav,
47+
setActiveFromChild,
48+
active,
49+
addonType,
50+
...attributes
51+
} = omit(props, ['toggle', 'disabled', 'inNavbar', 'direction']);
52+
53+
const fields = useRef({
54+
firstRender: true,
55+
ref: {current: null}
56+
}).current;
57+
58+
const reference = (r)=>{
59+
fields.ref.current = r;
60+
innerRef && innerRef(r);
61+
}
62+
63+
const getContainer = ()=>{
64+
if (fields._$container) return fields._$container;
65+
fields._$container = ReactDOM.findDOMNode(fields.ref.current);
66+
return fields._$container;
67+
}
68+
69+
const getMenuCtrl = ()=>{
70+
if (fields._$menuCtrl) return fields._$menuCtrl;
71+
fields._$menuCtrl = getContainer().querySelector('[aria-expanded]');
72+
return fields._$menuCtrl;
73+
}
74+
75+
const getMenuItems = ()=>{
76+
return [].slice.call(getContainer().querySelectorAll('[role="menuitem"]'));
77+
}
78+
79+
const addEvents = ()=>{
80+
['click', 'touchstart', 'keyup'].forEach(event =>
81+
document.addEventListener(event, handleDocumentClick, true)
82+
);
83+
fields.handleDocumentClick = handleDocumentClick;
84+
}
85+
86+
const removeEvents = ()=>{
87+
['click', 'touchstart', 'keyup'].forEach(event =>
88+
document.removeEventListener(event, fields.handleDocumentClick, true)
89+
);
90+
}
91+
92+
const handleDocumentClick = e=>{
93+
if (e && (e.which === 3 || (e.type === 'keyup' && e.which !== keyCodes.tab))) return;
94+
const container = getContainer();
95+
if (container.contains(e.target) && container !== e.target && (e.type !== 'keyup' || e.which === keyCodes.tab)) {
96+
return;
97+
}
98+
toggle(e);
99+
}
100+
101+
const handleKeyDown = e=>{
102+
if (
103+
/input|textarea/i.test(e.target.tagName)
104+
|| (keyCodes.tab === e.which && e.target.getAttribute('role') !== 'menuitem')
105+
) {
106+
return;
107+
}
108+
e.preventDefault();
109+
if (fields.disabled) return;
110+
if (getMenuCtrl() === e.target) {
111+
if (
112+
!fields.isOpen
113+
&& ([keyCodes.space, keyCodes.enter, keyCodes.up, keyCodes.down].indexOf(e.which) > -1)
114+
) {
115+
toggle(e);
116+
setTimeout(()=>getMenuItems()[0].focus());
117+
}
118+
}
119+
if (fields.isOpen && (e.target.getAttribute('role') === 'menuitem')) {
120+
if ([keyCodes.tab, keyCodes.esc].indexOf(e.which) > -1) {
121+
toggle(e);
122+
getMenuCtrl().focus();
123+
} else if ([keyCodes.space, keyCodes.enter].indexOf(e.which) > -1) {
124+
e.target.click();
125+
getMenuCtrl().focus();
126+
} else if (
127+
[keyCodes.down, keyCodes.up].indexOf(e.which) > -1
128+
|| ([keyCodes.n, keyCodes.p].indexOf(e.which) > -1 && e.ctrlKey)
129+
) {
130+
const $menuitems = getMenuItems();
131+
let index = $menuitems.indexOf(e.target);
132+
if (keyCodes.up === e.which || (keyCodes.p === e.which && e.ctrlKey)) {
133+
index = index !== 0 ? index - 1 : $menuitems.length - 1;
134+
} else if (keyCodes.down === e.which || (keyCodes.n === e.which && e.ctrlKey)) {
135+
index = index === $menuitems.length - 1 ? 0 : index + 1;
136+
}
137+
$menuitems[index].focus();
138+
} else if (keyCodes.end === e.which) {
139+
const $menuitems = getMenuItems();
140+
$menuitems[$menuitems.length - 1].focus();
141+
} else if (keyCodes.home === e.which) {
142+
const $menuitems = getMenuItems();
143+
$menuitems[0].focus();
144+
} else if ((e.which >= 48) && (e.which <= 90)) {
145+
const $menuitems = getMenuItems();
146+
const charPressed = String.fromCharCode(e.which).toLowerCase();
147+
for (let i = 0; i < $menuitems.length; i += 1) {
148+
const firstLetter = $menuitems[i].textContent && $menuitems[i].textContent[0].toLowerCase();
149+
if (firstLetter === charPressed) {
150+
$menuitems[i].focus();
151+
break;
152+
}
153+
}
154+
}
155+
}
156+
}
157+
158+
const handleProps = ()=>{
159+
if (props.show) {
160+
addEvents();
161+
} else {
162+
removeEvents();
163+
}
164+
}
165+
166+
const toggle = e=>{
167+
if (fields.disabled) {
168+
return e && e.preventDefault();
169+
}
170+
return props.toggle(e);
171+
}
172+
173+
//effect
174+
175+
useEffect(() => {
176+
if (fields.firstRender){
177+
return
178+
}
179+
handleProps();
180+
}, [props.show]);
181+
182+
useEffect(() => {
183+
fields.firstRender = false;
184+
handleProps();
185+
return function cleanup() {
186+
removeEvents();
187+
};
188+
}, []);
189+
190+
//render
191+
192+
fields.disabled = props.disabled;
193+
fields.isOpen = props.show;
194+
195+
const direction = props.direction; //(props.direction === 'down' && dropup) ? 'up' :
196+
197+
attributes.tag = attributes.tag || (inNav ? 'li' : 'div');
198+
199+
let subItemIsActive = false;
200+
201+
if (setActiveFromChild){
202+
React.Children.map(props.children[1].props.children,
203+
(dropdownItem) => {
204+
if (dropdownItem && dropdownItem.props.active) subItemIsActive = true;
205+
}
206+
);
207+
}
208+
209+
const classes = mapToCssModules(classNames(
210+
className,
211+
direction !== 'down' && `drop${direction}`,
212+
inNav && active ? 'active' : false,
213+
setActiveFromChild && subItemIsActive ? 'active' : false,
214+
{
215+
[`input-group-${addonType}`]: addonType,
216+
'btn-group': group,
217+
[`btn-group-${size}`]: !!size,
218+
'dropdown': !group && !addonType,
219+
'show': show,
220+
'nav-item': inNav
221+
}
222+
), cssModule);
223+
224+
return (
225+
<Context.Provider value={{
226+
toggle: props.toggle,
227+
isOpen: props.show,
228+
direction: props.direction, //(props.direction === 'down' && props.dropup) ? 'up' :
229+
inNavbar: props.inNavbar,
230+
}}>
231+
<CPopperContentWrapper>
232+
<Manager {...attributes} className={classes} onKeyDown={handleKeyDown} ref={reference} />
233+
</CPopperContentWrapper>
234+
</Context.Provider>
235+
);
236+
237+
}
238+
239+
CDropdownCustom.propTypes = {
240+
tag: tagPropType,
241+
children: PropTypes.node,
242+
className: PropTypes.string,
243+
cssModule: PropTypes.object,
244+
//
245+
innerRef: PropTypes.oneOfType([PropTypes.object, PropTypes.func, PropTypes.string]),
246+
direction: PropTypes.oneOf(['up', 'down', 'left', 'right']),
247+
group: PropTypes.bool,
248+
show: PropTypes.bool,
249+
disabled: PropTypes.bool,
250+
active: PropTypes.bool,
251+
addonType: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(['prepend', 'append'])]),
252+
size: PropTypes.string,
253+
toggle: PropTypes.func,
254+
inNav: PropTypes.bool,
255+
inNavbar: PropTypes.bool,
256+
setActiveFromChild: PropTypes.bool,
257+
};
258+
259+
CDropdownCustom.defaultProps = {
260+
show: false,
261+
direction: 'down',
262+
active: false,
263+
addonType: false,
264+
inNav: false,
265+
inNavbar: false,
266+
setActiveFromChild: false,
267+
group: true
268+
};
269+
270+
export default CDropdownCustom;

src/CDropdownCustom.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,12 @@ const CDropdownCustom = props=>{
229229
inNavbar: props.inNavbar,
230230
}}>
231231
<CPopperContentWrapper>
232-
<Manager {...attributes} className={classes} onKeyDown={handleKeyDown} ref={reference} />
232+
<Manager
233+
{...attributes}
234+
className={classes}
235+
onKeyDown={handleKeyDown}
236+
ref={reference}
237+
/>
233238
</CPopperContentWrapper>
234239
</Context.Provider>
235240
);

src/CDropdownMenu.js

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ const CDropdownMenu = props=>{
7171

7272
}
7373

74+
7475
CDropdownMenu.propTypes = {
7576
tag: tagPropType,
7677
children: PropTypes.node.isRequired,

src/CDropdownToggle.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const CDropdownToggle = props=>{
2424
togglerHtml,
2525
...attributes
2626
} = props;
27-
27+
2828
const context = useContext(Context);
2929

3030
const onClick = e=>{

0 commit comments

Comments
 (0)