native-document 1.0.290 → 1.0.292
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 +1 -1
- package/src/components/breadcrumb/types/BreadCrumb.d.ts +0 -2
- package/src/components/button/Button.js +18 -0
- package/src/components/button/types/Button.d.ts +2 -0
- package/src/components/form/field/Field.js +4 -3
- package/src/router/Route.js +3 -0
- package/src/router/RouteGroupHelper.js +5 -0
- package/src/router/Router.js +16 -0
- package/src/router/RouterComponent.js +50 -23
- package/src/ui/components/button/ButtonRender.js +4 -1
- package/src/ui/components/button/CopyButtonRender.js +1 -1
- package/src/ui/components/dropdown/dropdown.css +5 -2
- package/src/ui/components/form/FormControlRender.js +12 -0
- package/src/ui/components/popover/PopoverRender.js +22 -7
- package/src/ui/components/popover/popover.css +21 -0
- package/src/ui/components/tooltip/tooltip.css +0 -32
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "native-document",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.292",
|
|
4
4
|
"description": "A reactive JavaScript framework that preserves native DOM simplicity without sacrificing modern features",
|
|
5
5
|
"author": "AfroCodeur <https://github.com/afrocodeur>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,10 +33,8 @@ export interface BreadCrumbInterface extends BaseComponent {
|
|
|
33
33
|
export declare function BreadCrumb(props?: Record<string, unknown>): BreadCrumbInterface;
|
|
34
34
|
export declare namespace BreadCrumb {
|
|
35
35
|
|
|
36
|
-
|
|
37
36
|
function use(template: (description: BreadCrumbDescription, instance: BreadCrumbInterface) => ValidChild): void;
|
|
38
37
|
function preset(name: string, callback: (instance: BreadCrumbInterface) => BreadCrumbInterface): void;
|
|
39
38
|
function presets(presets: Record<string, (instance: BreadCrumbInterface) => BreadCrumbInterface>): void;
|
|
40
39
|
|
|
41
|
-
|
|
42
40
|
}
|
|
@@ -319,3 +319,21 @@ Button.prototype.block = function() {
|
|
|
319
319
|
this.$description.block = true;
|
|
320
320
|
return this;
|
|
321
321
|
};
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
// /**
|
|
325
|
+
// * @param {{name: string, params?: *}} route
|
|
326
|
+
// */
|
|
327
|
+
// Button.prototype.linkTo = function(route) {
|
|
328
|
+
// this.$description.linkTo = route;
|
|
329
|
+
// return this;
|
|
330
|
+
// };
|
|
331
|
+
//
|
|
332
|
+
// /**
|
|
333
|
+
// * @param {string} url
|
|
334
|
+
// */
|
|
335
|
+
// Button.prototype.link = function(url, target = null) {
|
|
336
|
+
// this.$description.link = url;
|
|
337
|
+
// this.$description.linkTarget = target;
|
|
338
|
+
// return this;
|
|
339
|
+
// };
|
|
@@ -35,11 +35,11 @@ export default function Field(name, type, props) {
|
|
|
35
35
|
type: type,
|
|
36
36
|
key: name,
|
|
37
37
|
label: null,
|
|
38
|
-
placeholder: null,
|
|
38
|
+
placeholder: props?.placeholder ?? null,
|
|
39
39
|
help: null,
|
|
40
40
|
defaultValue: null,
|
|
41
|
-
disabled:
|
|
42
|
-
readonly:
|
|
41
|
+
disabled: props?.disabled ?? null,
|
|
42
|
+
readonly: props?.readonly ?? null,
|
|
43
43
|
rules: [],
|
|
44
44
|
clearErrorOn: 'focus',
|
|
45
45
|
validateOn: 'blur',
|
|
@@ -75,6 +75,7 @@ BaseComponent.extends(Field);
|
|
|
75
75
|
BaseComponent.use(Field, HasEventEmitter);
|
|
76
76
|
BaseComponent.use(Field, HasValidation);
|
|
77
77
|
|
|
78
|
+
|
|
78
79
|
/**
|
|
79
80
|
* Registers the render template for Field.
|
|
80
81
|
* @param {(description: {
|
package/src/router/Route.js
CHANGED
|
@@ -34,6 +34,7 @@ export const RouteParamPatterns = {
|
|
|
34
34
|
* @param {boolean} [$options.shouldRebuild] - Whether to rebuild component on each navigation
|
|
35
35
|
* @param {Object} [$options.with] - Custom parameter validation patterns
|
|
36
36
|
* @param {Function} [$options.layout] - Layout component wrapper function
|
|
37
|
+
* @param {Function[]} [$options.layouts] - All prent Layouts component wrapper function
|
|
37
38
|
*/
|
|
38
39
|
export function Route($path, $component, $options = {}) {
|
|
39
40
|
|
|
@@ -46,6 +47,7 @@ export function Route($path, $component, $options = {}) {
|
|
|
46
47
|
const $shouldRebuild = $options.shouldRebuild || false;
|
|
47
48
|
const $paramsValidators = $options.with || {};
|
|
48
49
|
const $layout = $options.layout || null;
|
|
50
|
+
const $layouts = $options.layouts || null;
|
|
49
51
|
|
|
50
52
|
const $params = {};
|
|
51
53
|
const $paramsNames = [];
|
|
@@ -91,6 +93,7 @@ export function Route($path, $component, $options = {}) {
|
|
|
91
93
|
this.shouldRebuild = () => $shouldRebuild;
|
|
92
94
|
this.path = () => $path;
|
|
93
95
|
this.layout = () => $layout;
|
|
96
|
+
this.layouts = () => $layouts;
|
|
94
97
|
|
|
95
98
|
/**
|
|
96
99
|
*
|
package/src/router/Router.js
CHANGED
|
@@ -63,6 +63,10 @@ export default function Router($options = {}) {
|
|
|
63
63
|
middlewares: RouteGroupHelper.fullMiddlewares($groupTree, options?.middlewares || []),
|
|
64
64
|
name: options?.name ? RouteGroupHelper.fullName($groupTree, options.name) : null,
|
|
65
65
|
layout: options?.layout || RouteGroupHelper.layout($groupTree),
|
|
66
|
+
layouts: [
|
|
67
|
+
...RouteGroupHelper.layouts($groupTree),
|
|
68
|
+
...(options?.layout ? [options.layout] : []),
|
|
69
|
+
],
|
|
66
70
|
});
|
|
67
71
|
$routes.push(route);
|
|
68
72
|
if(route.name()) {
|
|
@@ -219,6 +223,10 @@ export default function Router($options = {}) {
|
|
|
219
223
|
return middlewares[currentIndex](request, next);
|
|
220
224
|
};
|
|
221
225
|
|
|
226
|
+
this.currentRouteName = function() {
|
|
227
|
+
return $currentState.route.name();
|
|
228
|
+
};
|
|
229
|
+
|
|
222
230
|
}
|
|
223
231
|
|
|
224
232
|
Router.routers = {};
|
|
@@ -267,6 +275,10 @@ Router.create = function(options, callback) {
|
|
|
267
275
|
return router;
|
|
268
276
|
};
|
|
269
277
|
|
|
278
|
+
Router.currentRouteName = function(name = null) {
|
|
279
|
+
return Router.get(name).currentRouteName();
|
|
280
|
+
};
|
|
281
|
+
|
|
270
282
|
Router.get = function(name) {
|
|
271
283
|
const router = Router.routers[name || DEFAULT_ROUTER_NAME];
|
|
272
284
|
if(!router) {
|
|
@@ -275,6 +287,10 @@ Router.get = function(name) {
|
|
|
275
287
|
return router;
|
|
276
288
|
};
|
|
277
289
|
|
|
290
|
+
Router.currentRoute = function(name = null) {
|
|
291
|
+
return Router.get(name).currentState().route;
|
|
292
|
+
}
|
|
293
|
+
|
|
278
294
|
Router.push = function(target, name = null) {
|
|
279
295
|
return Router.get(name).push(target);
|
|
280
296
|
};
|
|
@@ -18,6 +18,7 @@ export function RouterComponent(router, container) {
|
|
|
18
18
|
|
|
19
19
|
const $lifecycles = new Map();
|
|
20
20
|
let $currentPath = null;
|
|
21
|
+
let $mountedChain = [];
|
|
21
22
|
|
|
22
23
|
const getNodeAnchorForLayout = (node, path) => {
|
|
23
24
|
const existingAnchor = $routeInstanceAnchors.get(node);
|
|
@@ -55,39 +56,65 @@ export function RouterComponent(router, container) {
|
|
|
55
56
|
return nodeToInsert;
|
|
56
57
|
};
|
|
57
58
|
|
|
58
|
-
const updateContainerByLayout = (
|
|
59
|
+
const updateContainerByLayout = (layouts, node, route, path) => {
|
|
60
|
+
|
|
59
61
|
const nodeToInsert = getNodeToInsert(node);
|
|
62
|
+
let matchDepth = 0;
|
|
60
63
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
layoutAnchor.replaceContent(nodeToInsert);
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
cleanContainer();
|
|
64
|
+
while (matchDepth < $mountedChain.length && matchDepth < layouts.length && $mountedChain[matchDepth].layoutFn === layouts[matchDepth]) {
|
|
65
|
+
matchDepth++;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (matchDepth === layouts.length && matchDepth === $mountedChain.length) {
|
|
69
|
+
removeLastNodeInserted();
|
|
71
70
|
$lastNodeInserted = nodeToInsert;
|
|
72
|
-
$
|
|
73
|
-
const layoutAnchor = getNodeAnchorForLayout(nodeToInsert, path);
|
|
74
|
-
layoutAnchor.replaceContent(nodeToInsert);
|
|
75
|
-
container.appendChild($currentLayout);
|
|
71
|
+
$mountedChain[matchDepth - 1]?.anchor?.replaceContent(nodeToInsert);
|
|
76
72
|
return;
|
|
77
73
|
}
|
|
78
|
-
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
if ($mountedChain[matchDepth]) {
|
|
77
|
+
$mountedChain[matchDepth].element.remove();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const $mountedChainKeep = $mountedChain.slice(0, matchDepth);
|
|
81
|
+
const newLayers = [];
|
|
82
|
+
let slot = nodeToInsert;
|
|
79
83
|
$lastNodeInserted = nodeToInsert;
|
|
80
|
-
const anchor = getNodeAnchorForLayout(nodeToInsert, path);
|
|
81
84
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
for(let i = layouts.length - 1; i >= matchDepth; i -= 1) {
|
|
86
|
+
const layout = layouts[i];
|
|
87
|
+
let cached = $layoutCache.get(layout);
|
|
88
|
+
if(!cached) {
|
|
89
|
+
const anchor = getNodeAnchorForLayout(slot, `${path}:layout:${i}`);
|
|
90
|
+
const element = ElementCreator.getChild(layout(anchor));
|
|
91
|
+
cached = { element, anchor };
|
|
92
|
+
$layoutCache.set(layout, cached);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
cached.anchor.replaceContent(slot);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
newLayers.unshift({ layoutFn: layout, anchor: cached.anchor, element: cached.element });
|
|
99
|
+
slot = cached.element;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
$mountedChain = [...$mountedChainKeep, ...newLayers];
|
|
103
|
+
|
|
104
|
+
if (matchDepth === 0) {
|
|
105
|
+
container.appendChild(newLayers[0].element);
|
|
106
|
+
} else {
|
|
107
|
+
$mountedChainKeep[matchDepth - 1].anchor.replaceContent(newLayers[0].element);
|
|
108
|
+
}
|
|
109
|
+
|
|
85
110
|
};
|
|
86
111
|
|
|
87
112
|
const updateContainer = function(node, route, path) {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
113
|
+
const layouts = route.layouts();
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
if(layouts.length) {
|
|
117
|
+
updateContainerByLayout(layouts, node, route, path);
|
|
91
118
|
return;
|
|
92
119
|
}
|
|
93
120
|
const nodeToInsert = getNodeToInsert(node);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {Button as NativeButton, ShowIf, Span} from '../../../core/elements';
|
|
2
2
|
import {Spinner} from '../../../components/spinner';
|
|
3
|
+
import {Router} from '../../../../router';
|
|
3
4
|
|
|
4
5
|
import './button.css';
|
|
5
6
|
|
|
@@ -32,7 +33,7 @@ export default function ButtonRender($desc, instance) {
|
|
|
32
33
|
|
|
33
34
|
const content = buildContent($desc);
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
const button = NativeButton({
|
|
36
37
|
...instance.resolveProps(),
|
|
37
38
|
type: $desc.type || 'button',
|
|
38
39
|
disabled: $desc.disabled,
|
|
@@ -40,6 +41,8 @@ export default function ButtonRender($desc, instance) {
|
|
|
40
41
|
...($desc.loading ? { 'aria-busy': $desc.loading } : {}),
|
|
41
42
|
...($desc.disabled ? { 'aria-disabled': $desc.disabled } : {}),
|
|
42
43
|
}, content);
|
|
44
|
+
|
|
45
|
+
return button;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
function buildContent($desc) {
|
|
@@ -35,18 +35,21 @@
|
|
|
35
35
|
border-radius: var(--dropdown-radius);
|
|
36
36
|
box-shadow: var(--dropdown-shadow);
|
|
37
37
|
min-width: var(--dropdown-min-width);
|
|
38
|
-
max-width: var(--dropdown-max-width);
|
|
39
38
|
font-size: var(--dropdown-font-size);
|
|
40
39
|
box-sizing: border-box;
|
|
41
40
|
margin: 0;
|
|
42
41
|
padding: var(--space-cozy) 0;
|
|
43
|
-
inset: unset
|
|
42
|
+
/*inset: unset;*/
|
|
44
43
|
overflow: hidden;
|
|
45
44
|
|
|
46
45
|
&:popover-open {
|
|
47
46
|
animation: dropdown-in var(--dropdown-animation-duration) ease forwards;
|
|
48
47
|
}
|
|
49
48
|
|
|
49
|
+
&.has-max-width {
|
|
50
|
+
max-width: var(--dropdown-max-width);
|
|
51
|
+
}
|
|
52
|
+
|
|
50
53
|
&.has-max-height {
|
|
51
54
|
overflow-y: auto;
|
|
52
55
|
}
|
|
@@ -29,6 +29,7 @@ export default function FormControlRender($desc, instance) {
|
|
|
29
29
|
fields: fieldsObject,
|
|
30
30
|
errors: errorsSummary,
|
|
31
31
|
form: instance,
|
|
32
|
+
data: dataProxy(fieldsObject),
|
|
32
33
|
}, instance);
|
|
33
34
|
|
|
34
35
|
if(!((form instanceof HTMLFormElement) || form?.$element instanceof HTMLFormElement)) {
|
|
@@ -44,6 +45,17 @@ export default function FormControlRender($desc, instance) {
|
|
|
44
45
|
return form;
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
const dataProxy = (fieldsObject) => {
|
|
49
|
+
const data = {};
|
|
50
|
+
for(const name in fieldsObject) {
|
|
51
|
+
if(!fieldsObject[name]?.$model) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
data[name] = fieldsObject[name].$model();
|
|
55
|
+
}
|
|
56
|
+
return data;
|
|
57
|
+
};
|
|
58
|
+
|
|
47
59
|
const buildDefaultLayout = ({ fields, errors, form }) => {
|
|
48
60
|
return Form({ class: 'form-control-default', ...form.resolveProps() }, [
|
|
49
61
|
...Object.values(fields),
|
|
@@ -35,17 +35,20 @@ export default function PopoverRender($desc, instance, classPrefix = 'popover')
|
|
|
35
35
|
: $desc.trigger).toNdElement();
|
|
36
36
|
|
|
37
37
|
const editableProps = instance.getEditableProps();
|
|
38
|
-
const toUnit = v => v + 'px';
|
|
39
38
|
|
|
40
39
|
const popoverId = classPrefix+'-nd-' + (++$popoverId);
|
|
40
|
+
const toUnit = v => v + 'px';
|
|
41
41
|
const $x = Observable(10).intercept(toUnit);
|
|
42
42
|
const $y = Observable(0).intercept(toUnit);
|
|
43
43
|
|
|
44
|
-
const popoverArrow = $desc.arrow ? Span({class: classPrefix+'-arrow'}) : null;
|
|
44
|
+
const popoverArrow = $desc.arrow ? Span({class: classPrefix+'-arrow popover-arrow'}) : null;
|
|
45
45
|
|
|
46
|
-
editableProps.class.add(
|
|
46
|
+
editableProps.class.add('popover');
|
|
47
|
+
if(classPrefix !== 'popover') {
|
|
48
|
+
editableProps.class.add(classPrefix);
|
|
49
|
+
}
|
|
47
50
|
editableProps.class.add('is-'+$desc.variant);
|
|
48
|
-
editableProps.style.add({left: $x, top: $y});
|
|
51
|
+
editableProps.style.add({ '--popover-left-position': $x, '--popover-top-position': $y});
|
|
49
52
|
|
|
50
53
|
const popover = Div({
|
|
51
54
|
popover: 'manual',
|
|
@@ -62,12 +65,23 @@ export default function PopoverRender($desc, instance, classPrefix = 'popover')
|
|
|
62
65
|
|
|
63
66
|
let position;
|
|
64
67
|
const isSupportsPopover = supportsPopover();
|
|
68
|
+
|
|
69
|
+
let targetElement = trigger;
|
|
70
|
+
if($desc.matchTargetWidth) {
|
|
71
|
+
if($desc.matchTargetWidth.$element) {
|
|
72
|
+
targetElement = $desc.matchTargetWidth.$element;
|
|
73
|
+
}
|
|
74
|
+
else if($desc.matchTargetWidth.tagName) {
|
|
75
|
+
targetElement = $desc.matchTargetWidth;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
65
79
|
const updatePosition = (state) => {
|
|
66
80
|
if(!state) {
|
|
67
81
|
return;
|
|
68
82
|
}
|
|
69
83
|
|
|
70
|
-
|
|
84
|
+
targetElement = trigger;
|
|
71
85
|
if($desc.matchTargetWidth) {
|
|
72
86
|
if($desc.matchTargetWidth.$element) {
|
|
73
87
|
targetElement = $desc.matchTargetWidth.$element;
|
|
@@ -111,12 +125,13 @@ export default function PopoverRender($desc, instance, classPrefix = 'popover')
|
|
|
111
125
|
}
|
|
112
126
|
|
|
113
127
|
const arrowData = middlewareData.arrow;
|
|
128
|
+
const side = placement.split('-')[0];
|
|
114
129
|
const staticSide = {
|
|
115
130
|
top: 'bottom',
|
|
116
131
|
right: 'left',
|
|
117
132
|
bottom: 'top',
|
|
118
133
|
left: 'right',
|
|
119
|
-
}[
|
|
134
|
+
}[side];
|
|
120
135
|
|
|
121
136
|
Object.assign(popoverArrow.style, {
|
|
122
137
|
left: arrowData.x != null ? arrowData.x + 'px' : '',
|
|
@@ -148,7 +163,7 @@ export default function PopoverRender($desc, instance, classPrefix = 'popover')
|
|
|
148
163
|
|
|
149
164
|
const observer = new ResizeObserver(updatePositionHandler);
|
|
150
165
|
|
|
151
|
-
observer.observe(
|
|
166
|
+
observer.observe(targetElement);
|
|
152
167
|
window.addEventListener('resize', updatePositionHandler);
|
|
153
168
|
window.addEventListener('scroll', updatePositionHandler);
|
|
154
169
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
:root {
|
|
2
2
|
--popover-bg: var(--background);
|
|
3
|
+
--popover-color: var(--text-color, black);
|
|
3
4
|
--popover-border: var(--gray-lite-3);
|
|
4
5
|
--popover-radius: var(--radius-card);
|
|
5
6
|
--popover-shadow: var(--shadow-lg);
|
|
@@ -12,6 +13,24 @@
|
|
|
12
13
|
--popover-header-weight: 600;
|
|
13
14
|
--popover-arrow-size: 8px;
|
|
14
15
|
--popover-animation-duration: 0.15s;
|
|
16
|
+
|
|
17
|
+
--popover-left-offset: 0px;
|
|
18
|
+
--popover-top-offset: 0px;
|
|
19
|
+
|
|
20
|
+
--popover-top-position: 0px;
|
|
21
|
+
--popover-left-position: 0px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
.popover-arrow {
|
|
26
|
+
position: absolute;
|
|
27
|
+
width: var(--popover-arrow-size);
|
|
28
|
+
height: var(--popover-arrow-size);
|
|
29
|
+
background: var(--popover-bg);
|
|
30
|
+
color: var(--popover-color);
|
|
31
|
+
transform: rotate(45deg);
|
|
32
|
+
pointer-events: none;
|
|
33
|
+
z-index: -1;
|
|
15
34
|
}
|
|
16
35
|
|
|
17
36
|
.popover {
|
|
@@ -29,6 +48,8 @@
|
|
|
29
48
|
padding: 0;
|
|
30
49
|
inset: unset;
|
|
31
50
|
overflow: initial;
|
|
51
|
+
top: calc(var(--popover-top-position) + var(--popover-top-offset));
|
|
52
|
+
left: calc(var(--popover-left-position) + var(--popover-left-offset));
|
|
32
53
|
|
|
33
54
|
&.is-primary {
|
|
34
55
|
--popover-bg: var(--color-primary);
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
padding: var(--tooltip-padding);
|
|
28
28
|
box-sizing: border-box;
|
|
29
29
|
margin: 0;
|
|
30
|
-
inset: unset;
|
|
31
30
|
overflow: initial;
|
|
32
31
|
line-height: 1.5;
|
|
33
32
|
pointer-events: none;
|
|
@@ -68,37 +67,6 @@
|
|
|
68
67
|
width: var(--tooltip-arrow-size);
|
|
69
68
|
height: var(--tooltip-arrow-size);
|
|
70
69
|
background: var(--tooltip-bg);
|
|
71
|
-
transform: rotate(45deg);
|
|
72
|
-
pointer-events: none;
|
|
73
|
-
z-index: -1;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
.tooltip[data-placement^='top'] {
|
|
77
|
-
.tooltip-arrow {
|
|
78
|
-
border-top: none;
|
|
79
|
-
border-left: none;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
.tooltip[data-placement^='bottom'] {
|
|
84
|
-
.tooltip-arrow {
|
|
85
|
-
border-bottom: none;
|
|
86
|
-
border-right: none;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
.tooltip[data-placement^='left'] {
|
|
91
|
-
.tooltip-arrow {
|
|
92
|
-
border-left: none;
|
|
93
|
-
border-bottom: none;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
.tooltip[data-placement^='right'] {
|
|
98
|
-
.tooltip-arrow {
|
|
99
|
-
border-right: none;
|
|
100
|
-
border-top: none;
|
|
101
|
-
}
|
|
102
70
|
}
|
|
103
71
|
|
|
104
72
|
@keyframes tooltip-in {
|