@teambit/react.ui.component-highlighter 0.0.485 → 0.0.489
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/component-highlighter.docs.md +86 -31
- package/dist/component-highlighter.docs.md +86 -31
- package/dist/{component-highlighter/hover-highlighter → hover-highlighter}/hover-highlighter.compositions.d.ts +0 -0
- package/dist/{component-highlighter/hover-highlighter → hover-highlighter}/hover-highlighter.compositions.js +6 -3
- package/dist/hover-highlighter/hover-highlighter.compositions.js.map +1 -0
- package/dist/hover-highlighter/hover-highlighter.d.ts +3 -0
- package/dist/hover-highlighter/hover-highlighter.js +25 -0
- package/dist/hover-highlighter/hover-highlighter.js.map +1 -0
- package/dist/{component-highlighter/hover-highlighter → hover-highlighter}/hover-highlighter.spec.d.ts +0 -0
- package/dist/{component-highlighter/hover-highlighter → hover-highlighter}/hover-highlighter.spec.js +0 -0
- package/dist/hover-highlighter/hover-highlighter.spec.js.map +1 -0
- package/dist/hover-highlighter/index.d.ts +4 -0
- package/dist/hover-highlighter/index.js +8 -0
- package/dist/hover-highlighter/index.js.map +1 -0
- package/dist/hover-highlighter/use-hover-highlighter.d.ts +17 -0
- package/dist/hover-highlighter/use-hover-highlighter.js +66 -0
- package/dist/hover-highlighter/use-hover-highlighter.js.map +1 -0
- package/dist/hybrid-highligher/hybrid-highlighter.d.ts +34 -0
- package/dist/hybrid-highligher/hybrid-highlighter.js +74 -0
- package/dist/hybrid-highligher/hybrid-highlighter.js.map +1 -0
- package/dist/hybrid-highligher/index.d.ts +2 -0
- package/dist/hybrid-highligher/index.js +6 -0
- package/dist/hybrid-highligher/index.js.map +1 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/multi-highlighter/multi-highlighter.composition.d.ts +2 -0
- package/dist/multi-highlighter/multi-highlighter.composition.js +34 -3
- package/dist/multi-highlighter/multi-highlighter.composition.js.map +1 -1
- package/dist/multi-highlighter/multi-highlighter.d.ts +3 -15
- package/dist/multi-highlighter/multi-highlighter.js +4 -63
- package/dist/multi-highlighter/multi-highlighter.js.map +1 -1
- package/dist/multi-highlighter/use-multi-highlighter.d.ts +13 -0
- package/dist/multi-highlighter/use-multi-highlighter.js +51 -0
- package/dist/multi-highlighter/use-multi-highlighter.js.map +1 -0
- package/dist/rule-matcher.d.ts +2 -0
- package/dist/rule-matcher.js +15 -0
- package/dist/rule-matcher.js.map +1 -0
- package/{component-highlighter/hover-highlighter → hover-highlighter}/hover-highlighter.compositions.tsx +4 -2
- package/{component-highlighter/hover-highlighter → hover-highlighter}/hover-highlighter.spec.tsx +0 -0
- package/hover-highlighter/hover-highlighter.tsx +8 -0
- package/hover-highlighter/index.ts +5 -0
- package/hover-highlighter/use-hover-highlighter.tsx +93 -0
- package/hybrid-highligher/hybrid-highlighter.tsx +126 -0
- package/hybrid-highligher/index.ts +2 -0
- package/index.ts +7 -2
- package/multi-highlighter/multi-highlighter.composition.tsx +40 -2
- package/multi-highlighter/multi-highlighter.tsx +5 -81
- package/multi-highlighter/use-multi-highlighter.tsx +70 -0
- package/package-tar/teambit-react.ui.component-highlighter-0.0.489.tgz +0 -0
- package/package.json +14 -12
- package/rule-matcher.tsx +15 -0
- package/component-highlighter/hover-highlighter/hover-highlighter.module.scss +0 -13
- package/component-highlighter/hover-highlighter/hover-highlighter.tsx +0 -120
- package/component-highlighter/hover-highlighter/index.ts +0 -1
- package/component-highlighter/index.ts +0 -2
- package/dist/component-highlighter/hover-highlighter/hover-highlighter.compositions.js.map +0 -1
- package/dist/component-highlighter/hover-highlighter/hover-highlighter.d.ts +0 -21
- package/dist/component-highlighter/hover-highlighter/hover-highlighter.js +0 -100
- package/dist/component-highlighter/hover-highlighter/hover-highlighter.js.map +0 -1
- package/dist/component-highlighter/hover-highlighter/hover-highlighter.module.scss +0 -13
- package/dist/component-highlighter/hover-highlighter/hover-highlighter.spec.js.map +0 -1
- package/dist/component-highlighter/hover-highlighter/index.d.ts +0 -1
- package/dist/component-highlighter/hover-highlighter/index.js +0 -6
- package/dist/component-highlighter/hover-highlighter/index.js.map +0 -1
- package/dist/component-highlighter/index.d.ts +0 -2
- package/dist/component-highlighter/index.js +0 -6
- package/dist/component-highlighter/index.js.map +0 -1
- package/package-tar/teambit-react.ui.component-highlighter-0.0.485.tgz +0 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import React, { useState, useEffect, useMemo, useRef, createRef, CSSProperties } from 'react';
|
|
2
|
+
import classnames from 'classnames';
|
|
3
|
+
import { v4 } from 'uuid';
|
|
4
|
+
|
|
5
|
+
import { useHoverHighlighter } from '../hover-highlighter';
|
|
6
|
+
import { ElementHighlighter, HighlightTarget, Placement, HighlightClasses } from '../element-highlighter';
|
|
7
|
+
import { useMultiHighlighter } from '../multi-highlighter/use-multi-highlighter';
|
|
8
|
+
import type { MatchRule } from '../rule-matcher';
|
|
9
|
+
|
|
10
|
+
export interface HybridHighlighterProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
11
|
+
/** stop all highlighting and drop listeners */
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
/** default pop location for the label */
|
|
14
|
+
placement?: Placement;
|
|
15
|
+
/** customize styles */
|
|
16
|
+
classes?: HighlightClasses;
|
|
17
|
+
/** customize highlighter */
|
|
18
|
+
highlightStyle?: CSSProperties;
|
|
19
|
+
/** debounces element hover selection.
|
|
20
|
+
* A higher value will reduce element lookups as well as "keep" the highlight on the current element for longer.
|
|
21
|
+
* Initial selection (when no element is currently selected) will always happen immediately to improve the user experience.
|
|
22
|
+
* @default 80ms
|
|
23
|
+
*/
|
|
24
|
+
debounceSelection?: number;
|
|
25
|
+
/** continually update frame position to match moving elements */
|
|
26
|
+
watchMotion?: boolean;
|
|
27
|
+
|
|
28
|
+
/** filter highlighter targets by this query selector. (May be a more complex object in the future) */
|
|
29
|
+
rule?: MatchRule;
|
|
30
|
+
|
|
31
|
+
/** set the behavior of the highlighter.
|
|
32
|
+
* `disabled` - stops highlighting.
|
|
33
|
+
* `allChildren` - highlights all components rendered under children
|
|
34
|
+
* `hover` - highlighters the component immediately under the mouse cursor
|
|
35
|
+
* */
|
|
36
|
+
mode?: 'allChildren' | 'hover';
|
|
37
|
+
bgColor?: string;
|
|
38
|
+
bgColorHover?: string;
|
|
39
|
+
bgColorActive?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** automatically highlight components on hover */
|
|
43
|
+
export function HybridHighlighter({
|
|
44
|
+
disabled,
|
|
45
|
+
mode = 'hover',
|
|
46
|
+
debounceSelection = 80,
|
|
47
|
+
watchMotion = true,
|
|
48
|
+
placement,
|
|
49
|
+
rule,
|
|
50
|
+
|
|
51
|
+
classes,
|
|
52
|
+
highlightStyle,
|
|
53
|
+
className,
|
|
54
|
+
style,
|
|
55
|
+
bgColor,
|
|
56
|
+
bgColorHover,
|
|
57
|
+
bgColorActive,
|
|
58
|
+
children,
|
|
59
|
+
...rest
|
|
60
|
+
}: HybridHighlighterProps) {
|
|
61
|
+
const ref = createRef<HTMLDivElement>();
|
|
62
|
+
const [targets, setTarget] = useState<Record<string, HighlightTarget>>({});
|
|
63
|
+
const scopeClass = useRef(`hl-scope-${v4()}`).current;
|
|
64
|
+
const hasTargets = Object.entries(targets).length > 0;
|
|
65
|
+
|
|
66
|
+
// clear targets when disabled
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (disabled) setTarget({});
|
|
69
|
+
}, [disabled]);
|
|
70
|
+
|
|
71
|
+
const handlers = useHoverHighlighter(
|
|
72
|
+
(nextTarget) => setTarget(nextTarget ? { 'hover-target': nextTarget } : {}),
|
|
73
|
+
rest,
|
|
74
|
+
{
|
|
75
|
+
debounceDuration: hasTargets ? debounceSelection : 0,
|
|
76
|
+
scopeClass,
|
|
77
|
+
disabled: disabled || mode !== 'hover',
|
|
78
|
+
rule,
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
useMultiHighlighter({
|
|
83
|
+
onChange: setTarget,
|
|
84
|
+
scopeRef: ref,
|
|
85
|
+
scopeClass,
|
|
86
|
+
disabled: disabled || mode !== 'allChildren',
|
|
87
|
+
rule,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const _styles = useMemo(
|
|
91
|
+
() => ({
|
|
92
|
+
'--bit-highlighter-color': bgColor,
|
|
93
|
+
'--bit-highlighter-color-hover': bgColorHover,
|
|
94
|
+
'--bit-highlighter-color-active': bgColorActive,
|
|
95
|
+
...style,
|
|
96
|
+
}),
|
|
97
|
+
[bgColor, bgColorHover, bgColorActive, style]
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<div
|
|
102
|
+
ref={ref}
|
|
103
|
+
{...rest}
|
|
104
|
+
{...handlers}
|
|
105
|
+
style={_styles}
|
|
106
|
+
className={classnames(className, scopeClass)}
|
|
107
|
+
data-nullify-component-highlight
|
|
108
|
+
>
|
|
109
|
+
{children}
|
|
110
|
+
{/*
|
|
111
|
+
* keep the highlighter inside of the hover selector, or it could disappear when switching between elements
|
|
112
|
+
* the excludeHighlighterAtt will ensure it doesn't turn into a recursion.
|
|
113
|
+
*/}
|
|
114
|
+
{Object.entries(targets).map(([key, target]) => (
|
|
115
|
+
<ElementHighlighter
|
|
116
|
+
key={key}
|
|
117
|
+
target={target}
|
|
118
|
+
classes={classes}
|
|
119
|
+
style={highlightStyle}
|
|
120
|
+
placement={placement}
|
|
121
|
+
watchMotion={watchMotion}
|
|
122
|
+
/>
|
|
123
|
+
))}
|
|
124
|
+
</div>
|
|
125
|
+
);
|
|
126
|
+
}
|
package/index.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export type {
|
|
1
|
+
export { HybridHighlighter as ComponentHighlighter } from './hybrid-highligher';
|
|
2
|
+
export type { HybridHighlighterProps as ComponentHighlightProps } from './hybrid-highligher';
|
|
3
|
+
|
|
4
|
+
export { HoverHighlighter } from './hover-highlighter';
|
|
5
|
+
export type { HoverHighlighterProps } from './hover-highlighter';
|
|
3
6
|
|
|
4
7
|
export { MultiHighlighter } from './multi-highlighter';
|
|
5
8
|
export type { MultiHighlighterProps } from './multi-highlighter';
|
|
@@ -13,3 +16,5 @@ export {
|
|
|
13
16
|
excludeHighlighterSelector,
|
|
14
17
|
excludeHighlighterAttrName,
|
|
15
18
|
} from './ignore-highlighter';
|
|
19
|
+
|
|
20
|
+
export type { MatchRule } from './rule-matcher';
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
// import { EnterpriseOffering } from '@teambit/evangelist.pages.enterprise-offering';
|
|
3
3
|
import { MockedComponentWithMeta } from '@teambit/react.ui.highlighter.component-metadata.bit-component-meta';
|
|
4
|
+
import { ExcludeHighlighter } from '../ignore-highlighter';
|
|
4
5
|
import { MultiHighlighter } from './multi-highlighter';
|
|
5
6
|
|
|
6
7
|
export const MultiHighlighterPreview = () => {
|
|
7
8
|
return (
|
|
8
|
-
<MultiHighlighter style={{ padding: 40 }}>
|
|
9
|
+
<MultiHighlighter style={{ padding: 40, minWidth: 200 }}>
|
|
9
10
|
<MockedComponentWithMeta>hover here</MockedComponentWithMeta>
|
|
10
11
|
<br />
|
|
11
12
|
<br />
|
|
@@ -18,7 +19,7 @@ export const MultiHighlighterPreview = () => {
|
|
|
18
19
|
export const MultiHighlighterWithCustomColors = () => {
|
|
19
20
|
return (
|
|
20
21
|
<MultiHighlighter
|
|
21
|
-
style={{ padding: 40, color: 'yellow' }}
|
|
22
|
+
style={{ padding: 40, minWidth: 200, color: 'yellow' }}
|
|
22
23
|
bgColor="cornflowerblue"
|
|
23
24
|
bgColorHover="blue"
|
|
24
25
|
bgColorActive="DarkSlateBlue"
|
|
@@ -32,6 +33,43 @@ export const MultiHighlighterWithCustomColors = () => {
|
|
|
32
33
|
);
|
|
33
34
|
};
|
|
34
35
|
|
|
36
|
+
export const MultiHighlighterInsideIgnore = () => {
|
|
37
|
+
return (
|
|
38
|
+
<ExcludeHighlighter>
|
|
39
|
+
<MultiHighlighter>
|
|
40
|
+
Multi Highlighter should still work when inside <code>{'<ExcludeHighlighter>'}</code>
|
|
41
|
+
<br />
|
|
42
|
+
It should only skip exclusion zones inside of it.
|
|
43
|
+
<br />
|
|
44
|
+
<br />
|
|
45
|
+
<br />
|
|
46
|
+
<MockedComponentWithMeta>hover here</MockedComponentWithMeta>
|
|
47
|
+
<br />
|
|
48
|
+
<br />
|
|
49
|
+
<br />
|
|
50
|
+
<MockedComponentWithMeta>also here</MockedComponentWithMeta>
|
|
51
|
+
</MultiHighlighter>
|
|
52
|
+
</ExcludeHighlighter>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const MultiHighlighterWithRule = () => {
|
|
57
|
+
return (
|
|
58
|
+
<MultiHighlighter rule="#someSubTree *">
|
|
59
|
+
<br />
|
|
60
|
+
<br />
|
|
61
|
+
<br />
|
|
62
|
+
<MockedComponentWithMeta>no highlighter</MockedComponentWithMeta>
|
|
63
|
+
<br />
|
|
64
|
+
<br />
|
|
65
|
+
<br />
|
|
66
|
+
<div id="someSubTree">
|
|
67
|
+
<MockedComponentWithMeta>this will be highlighted</MockedComponentWithMeta>
|
|
68
|
+
</div>
|
|
69
|
+
</MultiHighlighter>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
35
73
|
// export const HighlightingAllElementsInTheEnterprisePage = () => {
|
|
36
74
|
// return (
|
|
37
75
|
// <MultiHighlighter>
|
|
@@ -1,85 +1,9 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import getXPath from 'get-xpath';
|
|
3
|
-
import { ElementHighlighter, ElementHighlighterProps, HighlightTarget } from '@teambit/react.ui.component-highlighter';
|
|
4
|
-
import { domToReact, toRootElement } from '@teambit/react.modules.dom-to-react';
|
|
5
|
-
import { hasComponentMeta } from '@teambit/react.ui.highlighter.component-metadata.bit-component-meta';
|
|
6
|
-
import { excludeHighlighterSelector } from '../ignore-highlighter';
|
|
1
|
+
import React from 'react';
|
|
7
2
|
|
|
8
|
-
|
|
9
|
-
const allExceptHighlighterQuery = `:not(${excludeHighlighterSelector}, ${excludeHighlighterSelector} *)`;
|
|
3
|
+
import { HybridHighlighter, HybridHighlighterProps } from '../hybrid-highligher';
|
|
10
4
|
|
|
11
|
-
export
|
|
12
|
-
disabled?: boolean;
|
|
13
|
-
// /** automatically update when children update. Use with caution, might be slow */
|
|
14
|
-
// watchDom?: boolean;
|
|
15
|
-
/**
|
|
16
|
-
* continually update highlighter position to match dom elements as they move. Use with caution, might be slow
|
|
17
|
-
* @default false
|
|
18
|
-
*/
|
|
19
|
-
watchMotion?: boolean;
|
|
5
|
+
export type MultiHighlighterProps = Omit<HybridHighlighterProps, 'mode'>;
|
|
20
6
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
bgColorActive?: string;
|
|
24
|
-
highlighterOptions?: ElementHighlighterProps;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function MultiHighlighter({
|
|
28
|
-
children,
|
|
29
|
-
disabled,
|
|
30
|
-
watchMotion = false,
|
|
31
|
-
style,
|
|
32
|
-
bgColor,
|
|
33
|
-
bgColorActive,
|
|
34
|
-
bgColorHover,
|
|
35
|
-
highlighterOptions,
|
|
36
|
-
...rest
|
|
37
|
-
}: MultiHighlighterProps) {
|
|
38
|
-
const ref = createRef<HTMLDivElement>();
|
|
39
|
-
const [targets, setTargets] = useState<Record<string, HighlightTarget>>({});
|
|
40
|
-
|
|
41
|
-
useEffect(() => {
|
|
42
|
-
if (disabled) {
|
|
43
|
-
setTargets({});
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const { current } = ref;
|
|
48
|
-
if (!current) return;
|
|
49
|
-
|
|
50
|
-
// select all non-highlighter elements
|
|
51
|
-
const allElements = Array.from(current.querySelectorAll<HTMLElement>(allExceptHighlighterQuery));
|
|
52
|
-
|
|
53
|
-
// converge on the root element of components
|
|
54
|
-
const rootElements = allElements.map(toRootElement).filter((x) => !!x);
|
|
55
|
-
// deduplicate
|
|
56
|
-
const uniqueRoots = new Set(rootElements);
|
|
57
|
-
|
|
58
|
-
const nextTargets: Record<string, HighlightTarget> = {};
|
|
59
|
-
uniqueRoots.forEach((element) => {
|
|
60
|
-
const comp = domToReact(element);
|
|
61
|
-
if (!element || !hasComponentMeta(comp)) return;
|
|
62
|
-
|
|
63
|
-
const key = getXPath(element);
|
|
64
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
65
|
-
nextTargets[key] = { element, id: comp.__bit_component.id };
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
setTargets(nextTargets);
|
|
69
|
-
}, [disabled]);
|
|
70
|
-
|
|
71
|
-
const colors = {
|
|
72
|
-
'--bit-highlighter-color': bgColor,
|
|
73
|
-
'--bit-highlighter-color-hover': bgColorHover,
|
|
74
|
-
'--bit-highlighter-color-active': bgColorActive,
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
return (
|
|
78
|
-
<div ref={ref} {...rest} style={{ ...colors, ...style }}>
|
|
79
|
-
{children}
|
|
80
|
-
{Object.entries(targets).map(([key, target]) => (
|
|
81
|
-
<ElementHighlighter key={key} target={target} watchMotion={watchMotion} {...highlighterOptions} />
|
|
82
|
-
))}
|
|
83
|
-
</div>
|
|
84
|
-
);
|
|
7
|
+
export function MultiHighlighter({ watchMotion = false, ...props }: MultiHighlighterProps) {
|
|
8
|
+
return <HybridHighlighter {...props} mode={'allChildren'} watchMotion={watchMotion} />;
|
|
85
9
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { useEffect, RefObject } from 'react';
|
|
2
|
+
import getXPath from 'get-xpath';
|
|
3
|
+
import { domToReact, toRootElement } from '@teambit/react.modules.dom-to-react';
|
|
4
|
+
import {
|
|
5
|
+
hasComponentMeta,
|
|
6
|
+
componentMetaField,
|
|
7
|
+
componentMetaProperties,
|
|
8
|
+
} from '@teambit/react.ui.highlighter.component-metadata.bit-component-meta';
|
|
9
|
+
import { HighlightTarget } from '../element-highlighter';
|
|
10
|
+
import { excludeHighlighterSelector } from '../ignore-highlighter';
|
|
11
|
+
import { ruleMatcher, MatchRule } from '../rule-matcher';
|
|
12
|
+
|
|
13
|
+
type useMultiHighlighterProps = {
|
|
14
|
+
onChange: (highlighterTargets: Record<string, HighlightTarget>) => void;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
scopeRef: RefObject<HTMLElement>;
|
|
17
|
+
scopeClass?: string;
|
|
18
|
+
/** filter highlighter targets by this query selector. (May be a more complex object in the future) */
|
|
19
|
+
rule?: MatchRule;
|
|
20
|
+
|
|
21
|
+
// /** automatically update when children update. Use with caution, might be slow */
|
|
22
|
+
// watchDom?: boolean;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export function useMultiHighlighter({
|
|
26
|
+
onChange,
|
|
27
|
+
disabled,
|
|
28
|
+
scopeRef,
|
|
29
|
+
scopeClass: scopeSelector = '',
|
|
30
|
+
rule,
|
|
31
|
+
}: useMultiHighlighterProps) {
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
const nextTargets: Record<string, HighlightTarget> = {};
|
|
34
|
+
const scopeElement = scopeRef.current;
|
|
35
|
+
if (!scopeElement || disabled) return;
|
|
36
|
+
|
|
37
|
+
// select all elements (except excluded)
|
|
38
|
+
let allElements = Array.from(scopeElement.querySelectorAll<HTMLElement>(targetsSelector(`.${scopeSelector}`)));
|
|
39
|
+
// apply rule filtering
|
|
40
|
+
if (rule) allElements = allElements.filter((elem) => ruleMatcher(elem, rule));
|
|
41
|
+
// seek the root element:
|
|
42
|
+
const rootElements = allElements.map(toRootElement).filter((x) => !!x);
|
|
43
|
+
// deduplicate
|
|
44
|
+
const uniqueRoots = new Set(rootElements);
|
|
45
|
+
|
|
46
|
+
uniqueRoots.forEach((element) => {
|
|
47
|
+
const comp = domToReact(element);
|
|
48
|
+
if (!element || !hasComponentMeta(comp)) return;
|
|
49
|
+
|
|
50
|
+
const key = getXPath(element);
|
|
51
|
+
const meta = comp[componentMetaField];
|
|
52
|
+
const compId = meta[componentMetaProperties.componentId];
|
|
53
|
+
const link = meta[componentMetaProperties.homepageUrl];
|
|
54
|
+
const local = meta[componentMetaProperties.isExported] === false;
|
|
55
|
+
nextTargets[key] = { element, id: compId, link, local };
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
onChange(nextTargets);
|
|
59
|
+
}, [disabled, scopeSelector]);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function targetsSelector(
|
|
63
|
+
/**
|
|
64
|
+
* the scope in which to consider the exclude selector.
|
|
65
|
+
* The `:scope` modifier is appropriate, but is not supported in older browsers.
|
|
66
|
+
*/
|
|
67
|
+
scopeSelector = ':scope'
|
|
68
|
+
) {
|
|
69
|
+
return `:not(${scopeSelector} ${excludeHighlighterSelector}, ${scopeSelector} ${excludeHighlighterSelector} *)`;
|
|
70
|
+
}
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,37 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teambit/react.ui.component-highlighter",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.489",
|
|
4
4
|
"homepage": "https://bit.dev/teambit/react/ui/component-highlighter",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"componentId": {
|
|
7
7
|
"scope": "teambit.react",
|
|
8
8
|
"name": "ui/component-highlighter",
|
|
9
|
-
"version": "0.0.
|
|
9
|
+
"version": "0.0.489"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"classnames": "2.2.6",
|
|
13
12
|
"@popperjs/core": "2.6.0",
|
|
13
|
+
"classnames": "2.2.6",
|
|
14
14
|
"react-popper": "2.2.4",
|
|
15
|
-
"get-xpath": "3.0.1",
|
|
16
15
|
"use-debounce": "6.0.1",
|
|
16
|
+
"uuid": "3.4.0",
|
|
17
|
+
"get-xpath": "3.0.1",
|
|
17
18
|
"url-join": "4.0.1",
|
|
18
19
|
"core-js": "^3.0.0",
|
|
19
20
|
"@teambit/base-ui.utils.popper-js.ignore-popper-size": "1.0.0",
|
|
20
21
|
"@teambit/base-ui.utils.popper-js.resize-to-match-reference": "1.0.0",
|
|
21
22
|
"@teambit/base-ui.surfaces.card": "1.0.1",
|
|
22
23
|
"@teambit/base-ui.routing.native-link": "1.0.0",
|
|
23
|
-
"@teambit/
|
|
24
|
-
"@teambit/react.
|
|
25
|
-
"@teambit/react.ui.
|
|
26
|
-
"@teambit/
|
|
27
|
-
"@teambit/
|
|
28
|
-
"@teambit/component.modules.component-url": "0.0.
|
|
24
|
+
"@teambit/react.modules.dom-to-react": "0.0.476",
|
|
25
|
+
"@teambit/react.ui.highlighter.component-metadata.bit-component-meta": "0.0.9",
|
|
26
|
+
"@teambit/react.ui.hover-selector": "0.0.154",
|
|
27
|
+
"@teambit/ui-foundation.ui.constants.z-indexes": "0.0.476",
|
|
28
|
+
"@teambit/component-id": "0.0.388",
|
|
29
|
+
"@teambit/component.modules.component-url": "0.0.109"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
32
|
"@types/react": "^17.0.8",
|
|
32
33
|
"@types/classnames": "2.2.11",
|
|
33
34
|
"@testing-library/react": "11.2.6",
|
|
34
35
|
"@types/react-dom": "^17.0.5",
|
|
36
|
+
"@types/uuid": "3.4.9",
|
|
35
37
|
"@types/url-join": "4.0.0",
|
|
36
38
|
"@types/mocha": "5.2.7",
|
|
37
39
|
"@types/testing-library__jest-dom": "5.9.5",
|
|
@@ -41,7 +43,7 @@
|
|
|
41
43
|
"@teambit/design.ui.icon-button": "1.0.10"
|
|
42
44
|
},
|
|
43
45
|
"peerDependencies": {
|
|
44
|
-
"@teambit/legacy": "1.0.
|
|
46
|
+
"@teambit/legacy": "1.0.184",
|
|
45
47
|
"react-dom": "^16.8.0 || ^17.0.0",
|
|
46
48
|
"react": "^16.8.0 || ^17.0.0"
|
|
47
49
|
},
|
|
@@ -69,7 +71,7 @@
|
|
|
69
71
|
"react": "-"
|
|
70
72
|
},
|
|
71
73
|
"peerDependencies": {
|
|
72
|
-
"@teambit/legacy": "1.0.
|
|
74
|
+
"@teambit/legacy": "1.0.184",
|
|
73
75
|
"react-dom": "^16.8.0 || ^17.0.0",
|
|
74
76
|
"react": "^16.8.0 || ^17.0.0"
|
|
75
77
|
}
|
package/rule-matcher.tsx
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// in the future, we will add more options here, like include / exclude objects.
|
|
2
|
+
|
|
3
|
+
export type MatchRule = undefined | string | ((element: HTMLElement) => boolean);
|
|
4
|
+
|
|
5
|
+
export function ruleMatcher(element: HTMLElement, rule: MatchRule) {
|
|
6
|
+
if (typeof rule === 'string') {
|
|
7
|
+
return element.matches(rule);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (typeof rule === 'function') {
|
|
11
|
+
return rule(element);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import React, { useState, useCallback, useEffect, CSSProperties } from 'react';
|
|
2
|
-
import classnames from 'classnames';
|
|
3
|
-
import { useDebouncedCallback } from 'use-debounce';
|
|
4
|
-
import { domToReact, toRootElement } from '@teambit/react.modules.dom-to-react';
|
|
5
|
-
import { HoverSelector } from '@teambit/react.ui.hover-selector';
|
|
6
|
-
import { hasComponentMeta } from '@teambit/react.ui.highlighter.component-metadata.bit-component-meta';
|
|
7
|
-
|
|
8
|
-
import styles from './hover-highlighter.module.scss';
|
|
9
|
-
import { excludeHighlighterSelector } from '../../ignore-highlighter';
|
|
10
|
-
import { ElementHighlighter, HighlightTarget, Placement, HighlightClasses } from '../../element-highlighter';
|
|
11
|
-
|
|
12
|
-
export interface HoverHighlighterProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
13
|
-
disabled?: boolean;
|
|
14
|
-
/** default pop location for the label */
|
|
15
|
-
placement?: Placement;
|
|
16
|
-
/** customize styles */
|
|
17
|
-
classes?: HighlightClasses;
|
|
18
|
-
/** customize highlighter */
|
|
19
|
-
highlightStyle?: CSSProperties;
|
|
20
|
-
/** debounces element hover selection.
|
|
21
|
-
* A higher value will reduce element lookups as well as "keep" the highlight on the current element for longer.
|
|
22
|
-
* Initial selection (when no element is currently selected) will always happen immediately to improve the user experience.
|
|
23
|
-
* @default 80ms
|
|
24
|
-
*/
|
|
25
|
-
debounceSelection?: number;
|
|
26
|
-
/** continually update frame position to match moving elements */
|
|
27
|
-
watchMotion?: boolean;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** automatically highlight components on hover */
|
|
31
|
-
export function HoverHighlighter({
|
|
32
|
-
children,
|
|
33
|
-
disabled,
|
|
34
|
-
classes,
|
|
35
|
-
highlightStyle,
|
|
36
|
-
placement,
|
|
37
|
-
debounceSelection = 80,
|
|
38
|
-
watchMotion = true,
|
|
39
|
-
...rest
|
|
40
|
-
}: HoverHighlighterProps) {
|
|
41
|
-
const [target, setTarget] = useState<HighlightTarget | undefined>();
|
|
42
|
-
|
|
43
|
-
const _handleElement = useCallback((element: HTMLElement | null) => {
|
|
44
|
-
// clear highlighter at the edges:
|
|
45
|
-
if (!element || element.hasAttribute('data-nullify-component-highlight')) {
|
|
46
|
-
setTarget(undefined);
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// skip DOM trees having 'data-ignore-component-highlight'
|
|
51
|
-
if (element.closest(excludeHighlighterSelector)) return;
|
|
52
|
-
|
|
53
|
-
const result = bubbleToBitComponent(element);
|
|
54
|
-
if (!result) return;
|
|
55
|
-
|
|
56
|
-
setTarget({
|
|
57
|
-
element: result.element,
|
|
58
|
-
id: result.meta.id,
|
|
59
|
-
scopeLink: undefined,
|
|
60
|
-
link: result.meta.homepage,
|
|
61
|
-
local: result.meta.exported === false,
|
|
62
|
-
});
|
|
63
|
-
}, []);
|
|
64
|
-
|
|
65
|
-
const handleElement = useDebouncedCallback(_handleElement, target ? debounceSelection : 0);
|
|
66
|
-
|
|
67
|
-
// clear target when disabled
|
|
68
|
-
useEffect(() => {
|
|
69
|
-
if (disabled) {
|
|
70
|
-
setTarget(undefined);
|
|
71
|
-
}
|
|
72
|
-
}, [disabled]);
|
|
73
|
-
|
|
74
|
-
return (
|
|
75
|
-
<HoverSelector
|
|
76
|
-
{...rest}
|
|
77
|
-
className={classnames(styles.highlighter, !disabled && styles.active)}
|
|
78
|
-
onElementChange={handleElement}
|
|
79
|
-
disabled={disabled}
|
|
80
|
-
data-nullify-component-highlight
|
|
81
|
-
>
|
|
82
|
-
{children}
|
|
83
|
-
{/*
|
|
84
|
-
* keep the highlighter inside of the hover selector, or it could disappear when switching between elements
|
|
85
|
-
* the excludeHighlighterAtt will ensure it doesn't turn into a recursion.
|
|
86
|
-
*/}
|
|
87
|
-
{target && (
|
|
88
|
-
<ElementHighlighter
|
|
89
|
-
target={target}
|
|
90
|
-
classes={classes}
|
|
91
|
-
style={highlightStyle}
|
|
92
|
-
placement={placement}
|
|
93
|
-
watchMotion={watchMotion}
|
|
94
|
-
/>
|
|
95
|
-
)}
|
|
96
|
-
</HoverSelector>
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/** go up the dom tree until reaching a react bit component */
|
|
101
|
-
function bubbleToBitComponent(element: HTMLElement | null, filter?: (elem: Element) => boolean) {
|
|
102
|
-
for (let current = element; current; current = current.parentElement) {
|
|
103
|
-
current = toRootElement(current);
|
|
104
|
-
if (!current || filter?.(current) === false) return undefined;
|
|
105
|
-
|
|
106
|
-
const component = domToReact(current);
|
|
107
|
-
|
|
108
|
-
if (hasComponentMeta(component)) {
|
|
109
|
-
const meta = component.__bit_component;
|
|
110
|
-
|
|
111
|
-
return {
|
|
112
|
-
element: current,
|
|
113
|
-
component,
|
|
114
|
-
meta,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return undefined;
|
|
120
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { HoverHighlighterProps, HoverHighlighter } from './hover-highlighter';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hover-highlighter.compositions.js","sourceRoot":"","sources":["../../../component-highlighter/hover-highlighter/hover-highlighter.compositions.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAwC;AACxC,0EAA4D;AAC5D,2DAAuD;AAEhD,MAAM,gBAAgB,GAAG,GAAG,EAAE;IACnC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,IAAA,gBAAQ,EAAU,KAAK,CAAC,CAAC;IAEzD,OAAO,CACL,uCAAK,KAAK,EAAE,EAAE,OAAO,EAAE,qBAAqB,EAAE;QAC5C,8BAAC,oCAAgB,IAAC,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,QAAQ;YAC1D;;gBAEE,yCAAM;gBACN;oBACE,8BAAC,kCAAU,IAAC,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,iBAAyB,CACtE,CACF,CACW,CACf,CACP,CAAC;AACJ,CAAC,CAAC;AAhBW,QAAA,gBAAgB,oBAgB3B"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import React, { CSSProperties } from 'react';
|
|
2
|
-
import { Placement, HighlightClasses } from '../../element-highlighter';
|
|
3
|
-
export interface HoverHighlighterProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
4
|
-
disabled?: boolean;
|
|
5
|
-
/** default pop location for the label */
|
|
6
|
-
placement?: Placement;
|
|
7
|
-
/** customize styles */
|
|
8
|
-
classes?: HighlightClasses;
|
|
9
|
-
/** customize highlighter */
|
|
10
|
-
highlightStyle?: CSSProperties;
|
|
11
|
-
/** debounces element hover selection.
|
|
12
|
-
* A higher value will reduce element lookups as well as "keep" the highlight on the current element for longer.
|
|
13
|
-
* Initial selection (when no element is currently selected) will always happen immediately to improve the user experience.
|
|
14
|
-
* @default 80ms
|
|
15
|
-
*/
|
|
16
|
-
debounceSelection?: number;
|
|
17
|
-
/** continually update frame position to match moving elements */
|
|
18
|
-
watchMotion?: boolean;
|
|
19
|
-
}
|
|
20
|
-
/** automatically highlight components on hover */
|
|
21
|
-
export declare function HoverHighlighter({ children, disabled, classes, highlightStyle, placement, debounceSelection, watchMotion, ...rest }: HoverHighlighterProps): JSX.Element;
|