@teambit/react.ui.component-highlighter 0.0.489 → 0.0.493
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 +9 -0
- package/dist/component-highlighter.docs.md +9 -0
- package/dist/element-highlighter/element-highlighter.compositions.d.ts +3 -1
- package/dist/element-highlighter/element-highlighter.compositions.js +15 -7
- package/dist/element-highlighter/element-highlighter.compositions.js.map +1 -1
- package/dist/element-highlighter/element-highlighter.d.ts +8 -9
- package/dist/element-highlighter/element-highlighter.js +3 -3
- package/dist/element-highlighter/element-highlighter.js.map +1 -1
- package/dist/element-highlighter/index.d.ts +1 -1
- package/dist/hover-highlighter/use-hover-highlighter.d.ts +5 -2
- package/dist/hover-highlighter/use-hover-highlighter.js +13 -15
- package/dist/hover-highlighter/use-hover-highlighter.js.map +1 -1
- package/dist/hybrid-highligher/hybrid-highlighter.d.ts +6 -3
- package/dist/hybrid-highligher/hybrid-highlighter.js +4 -2
- package/dist/hybrid-highligher/hybrid-highlighter.js.map +1 -1
- package/dist/label/component-strip.d.ts +9 -0
- package/dist/label/component-strip.js +49 -0
- package/dist/label/component-strip.js.map +1 -0
- package/dist/label/component-strip.module.scss +64 -0
- package/dist/label/index.d.ts +4 -2
- package/dist/label/index.js +3 -2
- package/dist/label/index.js.map +1 -1
- package/dist/label/label-container.d.ts +13 -0
- package/dist/label/label-container.js +53 -0
- package/dist/label/label-container.js.map +1 -0
- package/dist/label/label.d.ts +7 -19
- package/dist/label/label.js +20 -27
- package/dist/label/label.js.map +1 -1
- package/dist/label/label.module.scss +24 -0
- package/dist/label/links.d.ts +2 -0
- package/dist/label/links.js +17 -0
- package/dist/label/links.js.map +1 -0
- package/dist/label/other-components.d.ts +10 -0
- package/dist/label/other-components.js +35 -0
- package/dist/label/other-components.js.map +1 -0
- package/dist/multi-highlighter/multi-highlighter.composition.d.ts +1 -0
- package/dist/multi-highlighter/multi-highlighter.composition.js +20 -5
- package/dist/multi-highlighter/multi-highlighter.composition.js.map +1 -1
- package/dist/multi-highlighter/use-multi-highlighter.d.ts +3 -2
- package/dist/multi-highlighter/use-multi-highlighter.js +7 -8
- package/dist/multi-highlighter/use-multi-highlighter.js.map +1 -1
- package/dist/rule-matcher.d.ts +6 -0
- package/dist/rule-matcher.js +20 -2
- package/dist/rule-matcher.js.map +1 -1
- package/dist/use-animation-frame.d.ts +1 -1
- package/dist/use-animation-frame.js.map +1 -1
- package/element-highlighter/element-highlighter.compositions.tsx +22 -8
- package/element-highlighter/element-highlighter.tsx +11 -16
- package/element-highlighter/index.ts +7 -1
- package/hover-highlighter/use-hover-highlighter.tsx +36 -19
- package/hybrid-highligher/hybrid-highlighter.tsx +16 -2
- package/label/component-strip.module.scss +64 -0
- package/label/component-strip.tsx +49 -0
- package/label/index.ts +5 -2
- package/label/label-container.tsx +46 -0
- package/label/label.module.scss +24 -0
- package/label/label.tsx +35 -66
- package/label/links.tsx +9 -0
- package/label/other-components.tsx +53 -0
- package/multi-highlighter/multi-highlighter.composition.tsx +22 -4
- package/multi-highlighter/use-multi-highlighter.tsx +15 -11
- package/package-tar/teambit-react.ui.component-highlighter-0.0.493.tgz +0 -0
- package/package.json +13 -13
- package/rule-matcher.tsx +27 -0
- package/use-animation-frame.tsx +1 -1
- package/bubble/bubble.module.scss +0 -24
- package/bubble/index.ts +0 -3
- package/dist/bubble/bubble.module.scss +0 -24
- package/dist/bubble/index.d.ts +0 -1
- package/dist/bubble/index.js +0 -9
- package/dist/bubble/index.js.map +0 -1
- package/dist/label/component-label/component-bubble.d.ts +0 -7
- package/dist/label/component-label/component-bubble.js +0 -35
- package/dist/label/component-label/component-bubble.js.map +0 -1
- package/dist/label/component-label/component-label.d.ts +0 -9
- package/dist/label/component-label/component-label.js +0 -32
- package/dist/label/component-label/component-label.js.map +0 -1
- package/dist/label/component-label/duo-component-bubble.module.scss +0 -24
- package/dist/label/component-label/index.d.ts +0 -2
- package/dist/label/component-label/index.js +0 -6
- package/dist/label/component-label/index.js.map +0 -1
- package/dist/label/component-label/scope-bubble.d.ts +0 -6
- package/dist/label/component-label/scope-bubble.js +0 -28
- package/dist/label/component-label/scope-bubble.js.map +0 -1
- package/dist/label/default-label/default-label.d.ts +0 -5
- package/dist/label/default-label/default-label.js +0 -30
- package/dist/label/default-label/default-label.js.map +0 -1
- package/dist/label/default-label/default-label.module.scss +0 -12
- package/dist/label/default-label/index.d.ts +0 -1
- package/dist/label/default-label/index.js +0 -6
- package/dist/label/default-label/index.js.map +0 -1
- package/label/component-label/component-bubble.tsx +0 -30
- package/label/component-label/component-label.tsx +0 -31
- package/label/component-label/duo-component-bubble.module.scss +0 -24
- package/label/component-label/index.ts +0 -2
- package/label/component-label/scope-bubble.tsx +0 -20
- package/label/default-label/default-label.module.scss +0 -12
- package/label/default-label/default-label.tsx +0 -22
- package/label/default-label/index.ts +0 -1
- package/package-tar/teambit-react.ui.component-highlighter-0.0.489.tgz +0 -0
|
@@ -3,9 +3,15 @@ import classnames from 'classnames';
|
|
|
3
3
|
import { v4 } from 'uuid';
|
|
4
4
|
|
|
5
5
|
import { useHoverHighlighter } from '../hover-highlighter';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
ElementHighlighter,
|
|
8
|
+
HighlightTarget,
|
|
9
|
+
Placement,
|
|
10
|
+
HighlightClasses,
|
|
11
|
+
HighlighterSize,
|
|
12
|
+
} from '../element-highlighter';
|
|
7
13
|
import { useMultiHighlighter } from '../multi-highlighter/use-multi-highlighter';
|
|
8
|
-
import type { MatchRule } from '../rule-matcher';
|
|
14
|
+
import type { MatchRule, ComponentMatchRule } from '../rule-matcher';
|
|
9
15
|
|
|
10
16
|
export interface HybridHighlighterProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
11
17
|
/** stop all highlighting and drop listeners */
|
|
@@ -27,6 +33,8 @@ export interface HybridHighlighterProps extends React.HTMLAttributes<HTMLDivElem
|
|
|
27
33
|
|
|
28
34
|
/** filter highlighter targets by this query selector. (May be a more complex object in the future) */
|
|
29
35
|
rule?: MatchRule;
|
|
36
|
+
/** filter components to match this rule. Can be id, array of ids, or a function */
|
|
37
|
+
componentRule?: ComponentMatchRule;
|
|
30
38
|
|
|
31
39
|
/** set the behavior of the highlighter.
|
|
32
40
|
* `disabled` - stops highlighting.
|
|
@@ -37,6 +45,7 @@ export interface HybridHighlighterProps extends React.HTMLAttributes<HTMLDivElem
|
|
|
37
45
|
bgColor?: string;
|
|
38
46
|
bgColorHover?: string;
|
|
39
47
|
bgColorActive?: string;
|
|
48
|
+
size?: HighlighterSize;
|
|
40
49
|
}
|
|
41
50
|
|
|
42
51
|
/** automatically highlight components on hover */
|
|
@@ -47,6 +56,7 @@ export function HybridHighlighter({
|
|
|
47
56
|
watchMotion = true,
|
|
48
57
|
placement,
|
|
49
58
|
rule,
|
|
59
|
+
componentRule,
|
|
50
60
|
|
|
51
61
|
classes,
|
|
52
62
|
highlightStyle,
|
|
@@ -55,6 +65,7 @@ export function HybridHighlighter({
|
|
|
55
65
|
bgColor,
|
|
56
66
|
bgColorHover,
|
|
57
67
|
bgColorActive,
|
|
68
|
+
size,
|
|
58
69
|
children,
|
|
59
70
|
...rest
|
|
60
71
|
}: HybridHighlighterProps) {
|
|
@@ -76,6 +87,7 @@ export function HybridHighlighter({
|
|
|
76
87
|
scopeClass,
|
|
77
88
|
disabled: disabled || mode !== 'hover',
|
|
78
89
|
rule,
|
|
90
|
+
componentRule,
|
|
79
91
|
}
|
|
80
92
|
);
|
|
81
93
|
|
|
@@ -85,6 +97,7 @@ export function HybridHighlighter({
|
|
|
85
97
|
scopeClass,
|
|
86
98
|
disabled: disabled || mode !== 'allChildren',
|
|
87
99
|
rule,
|
|
100
|
+
componentRule,
|
|
88
101
|
});
|
|
89
102
|
|
|
90
103
|
const _styles = useMemo(
|
|
@@ -119,6 +132,7 @@ export function HybridHighlighter({
|
|
|
119
132
|
style={highlightStyle}
|
|
120
133
|
placement={placement}
|
|
121
134
|
watchMotion={watchMotion}
|
|
135
|
+
size={size}
|
|
122
136
|
/>
|
|
123
137
|
))}
|
|
124
138
|
</div>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
$borderRadius: 8px;
|
|
2
|
+
$gap: 2px;
|
|
3
|
+
|
|
4
|
+
.componentStrip {
|
|
5
|
+
display: flex;
|
|
6
|
+
|
|
7
|
+
font-size: 14px;
|
|
8
|
+
line-height: 16px;
|
|
9
|
+
border-radius: $borderRadius;
|
|
10
|
+
box-shadow: 0px 11px 29px 0px rgba(0, 0, 0, 0.23);
|
|
11
|
+
|
|
12
|
+
&[data-size='s'] {
|
|
13
|
+
font-size: 12px;
|
|
14
|
+
line-height: 16px;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
&[data-size='m'] {
|
|
18
|
+
font-size: 14px;
|
|
19
|
+
line-height: 16px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
&[data-size='l'] {
|
|
23
|
+
font-size: 16px;
|
|
24
|
+
line-height: 24px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
> * {
|
|
28
|
+
padding: 4px 8px;
|
|
29
|
+
|
|
30
|
+
transition: filter 300ms, background-color 300ms;
|
|
31
|
+
transform: translateZ(0); //fix blurriness in Safari
|
|
32
|
+
|
|
33
|
+
background: var(--bit-highlighter-color, #eebcc9);
|
|
34
|
+
|
|
35
|
+
&:link,
|
|
36
|
+
&:visited {
|
|
37
|
+
text-decoration: inherit; // reset browser defaults
|
|
38
|
+
color: inherit; // reset browser defaults
|
|
39
|
+
|
|
40
|
+
&:hover {
|
|
41
|
+
background: var(--bit-highlighter-color-hover, #f6dae2);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&:active {
|
|
45
|
+
background: var(--bit-highlighter-color-active, #e79db1);
|
|
46
|
+
color: inherit;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
&:first-child {
|
|
51
|
+
border-top-left-radius: $borderRadius;
|
|
52
|
+
border-bottom-left-radius: $borderRadius;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
margin-right: $gap;
|
|
56
|
+
|
|
57
|
+
&:last-child {
|
|
58
|
+
border-top-right-radius: $borderRadius;
|
|
59
|
+
border-bottom-right-radius: $borderRadius;
|
|
60
|
+
|
|
61
|
+
margin-right: unset;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React, { useMemo, ReactNode, forwardRef, ForwardedRef } from 'react';
|
|
2
|
+
import { NativeLink } from '@teambit/base-ui.routing.native-link';
|
|
3
|
+
import { ComponentID } from '@teambit/component-id';
|
|
4
|
+
import { ScopeUrl } from '@teambit/component.modules.component-url';
|
|
5
|
+
import {
|
|
6
|
+
componentMetaField,
|
|
7
|
+
ComponentMetaHolder,
|
|
8
|
+
} from '@teambit/react.ui.highlighter.component-metadata.bit-component-meta';
|
|
9
|
+
import styles from './component-strip.module.scss';
|
|
10
|
+
import { calcComponentLink } from './links';
|
|
11
|
+
|
|
12
|
+
export type ComponentStripSize = 's' | 'm' | 'l';
|
|
13
|
+
|
|
14
|
+
interface ComponentStripProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
15
|
+
component: ComponentMetaHolder;
|
|
16
|
+
size?: ComponentStripSize;
|
|
17
|
+
}
|
|
18
|
+
export const ComponentStrip = forwardRef(function ComponentStrip(
|
|
19
|
+
{ component, size = 'm', children }: ComponentStripProps,
|
|
20
|
+
ref: ForwardedRef<HTMLDivElement>
|
|
21
|
+
) {
|
|
22
|
+
const { id, homepage, exported } = component[componentMetaField];
|
|
23
|
+
|
|
24
|
+
const parsedId = useMemo(() => ComponentID.tryFromString(id), [id]);
|
|
25
|
+
const componentLink = homepage || calcComponentLink(parsedId, exported);
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<div className={styles.componentStrip} ref={ref} data-size={size}>
|
|
29
|
+
{!parsedId && <LabelBlock link={homepage}>{id}</LabelBlock>}
|
|
30
|
+
{parsedId && <LabelBlock link={ScopeUrl.toUrl(parsedId.scope)}>{parsedId.scope}</LabelBlock>}
|
|
31
|
+
{parsedId && (
|
|
32
|
+
<LabelBlock link={componentLink}>
|
|
33
|
+
{parsedId.fullName}
|
|
34
|
+
{parsedId.version && parsedId.version !== 'latest' && `@${parsedId.version}`}
|
|
35
|
+
</LabelBlock>
|
|
36
|
+
)}
|
|
37
|
+
{children}
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
function LabelBlock({ link, children }: { link?: string; children: ReactNode }) {
|
|
43
|
+
const Comp = link ? NativeLink : 'span';
|
|
44
|
+
return (
|
|
45
|
+
<Comp href={link} external={!!link}>
|
|
46
|
+
{children}
|
|
47
|
+
</Comp>
|
|
48
|
+
);
|
|
49
|
+
}
|
package/label/index.ts
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export type {
|
|
1
|
+
export { Label } from './label';
|
|
2
|
+
export type { LabelProps, LabelSize } from './label';
|
|
3
|
+
|
|
4
|
+
export { LabelContainer } from './label-container';
|
|
5
|
+
export type { LabelContainerProps, Placement } from './label-container';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React, { useMemo, useState } from 'react';
|
|
2
|
+
import { usePopper } from 'react-popper';
|
|
3
|
+
import type { Placement, Modifier } from '@popperjs/core';
|
|
4
|
+
import '@popperjs/core';
|
|
5
|
+
|
|
6
|
+
import { useAnimationFrame } from '../use-animation-frame';
|
|
7
|
+
|
|
8
|
+
export interface LabelContainerProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
9
|
+
targetRef: HTMLElement | null;
|
|
10
|
+
offset?: [number, number];
|
|
11
|
+
placement?: Placement;
|
|
12
|
+
flip?: boolean;
|
|
13
|
+
/** continually update label position to match moving elements */
|
|
14
|
+
watchMotion?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type { Placement };
|
|
18
|
+
|
|
19
|
+
// TODO - replace this with TippyJS, when it supports a `targetElement={targetRef.current}` prop
|
|
20
|
+
export function LabelContainer({
|
|
21
|
+
targetRef,
|
|
22
|
+
offset,
|
|
23
|
+
placement,
|
|
24
|
+
flip = true,
|
|
25
|
+
watchMotion,
|
|
26
|
+
className,
|
|
27
|
+
...rest
|
|
28
|
+
}: LabelContainerProps) {
|
|
29
|
+
const [sourceRef, setSourceRef] = useState<HTMLDivElement | null>(null);
|
|
30
|
+
|
|
31
|
+
const modifiers = useMemo<Partial<Modifier<any, any>>[]>(
|
|
32
|
+
() => [{ name: 'offset', options: { offset } }],
|
|
33
|
+
[flip, offset]
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const { styles, attributes, update } = usePopper(targetRef, sourceRef, {
|
|
37
|
+
modifiers,
|
|
38
|
+
placement,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
useAnimationFrame(!!watchMotion && update);
|
|
42
|
+
|
|
43
|
+
if (!targetRef) return null;
|
|
44
|
+
|
|
45
|
+
return <div {...rest} ref={setSourceRef} className={className} style={styles.popper} {...attributes.popper} />;
|
|
46
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
.othersContainer {
|
|
2
|
+
> * {
|
|
3
|
+
margin-bottom: 8px;
|
|
4
|
+
|
|
5
|
+
&:last-child {
|
|
6
|
+
margin-bottom: unset;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.othersTooltip {
|
|
12
|
+
user-select: none;
|
|
13
|
+
cursor: pointer;
|
|
14
|
+
|
|
15
|
+
&::before {
|
|
16
|
+
display: inline-block;
|
|
17
|
+
transition: transform 300ms;
|
|
18
|
+
content: '▾';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
&.active::before {
|
|
22
|
+
transform: rotate(-180deg);
|
|
23
|
+
}
|
|
24
|
+
}
|
package/label/label.tsx
CHANGED
|
@@ -1,70 +1,39 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
import
|
|
6
|
-
import '
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
targetRef: HTMLElement | null;
|
|
14
|
-
offset?: [number, number];
|
|
15
|
-
placement?: Placement;
|
|
16
|
-
flip?: boolean;
|
|
17
|
-
/** continually update label position to match moving elements */
|
|
18
|
-
watchMotion?: boolean;
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import { ComponentMetaHolder } from '@teambit/react.ui.highlighter.component-metadata.bit-component-meta';
|
|
4
|
+
|
|
5
|
+
import styles from './label.module.scss';
|
|
6
|
+
import { ComponentStrip, ComponentStripSize } from './component-strip';
|
|
7
|
+
import { OtherComponentsPopper } from './other-components';
|
|
8
|
+
|
|
9
|
+
export type LabelSize = ComponentStripSize;
|
|
10
|
+
export interface LabelProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
11
|
+
components: ComponentMetaHolder[];
|
|
12
|
+
size?: LabelSize;
|
|
19
13
|
}
|
|
20
14
|
|
|
21
|
-
export
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
15
|
+
export function Label({ components, size, ...props }: LabelProps) {
|
|
16
|
+
const [showMore, setShowMore] = useState(false);
|
|
17
|
+
const last = components.slice(-1).pop();
|
|
18
|
+
if (!last) return null;
|
|
19
|
+
|
|
20
|
+
const hasMore = components.length > 1;
|
|
21
|
+
|
|
22
|
+
// reset when switching targets
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
setShowMore(false);
|
|
25
|
+
}, [components]);
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<OtherComponentsPopper components={components} visible={showMore} placement="bottom-start" size={size}>
|
|
29
|
+
<ComponentStrip {...props} component={last} size={size}>
|
|
30
|
+
{hasMore && (
|
|
31
|
+
<span
|
|
32
|
+
className={classNames(styles.othersTooltip, showMore && styles.active)}
|
|
33
|
+
onClick={() => setShowMore((x) => !x)}
|
|
34
|
+
/>
|
|
35
|
+
)}
|
|
36
|
+
</ComponentStrip>
|
|
37
|
+
</OtherComponentsPopper>
|
|
38
38
|
);
|
|
39
|
-
|
|
40
|
-
const { styles, attributes, update } = usePopper(targetRef, sourceRef, {
|
|
41
|
-
modifiers,
|
|
42
|
-
placement,
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
useAnimationFrame(!!watchMotion && update);
|
|
46
|
-
|
|
47
|
-
if (!targetRef) return null;
|
|
48
|
-
|
|
49
|
-
return <div {...rest} ref={setSourceRef} className={className} style={styles.popper} {...attributes.popper} />;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export interface LabelProps extends CardProps {
|
|
53
|
-
componentId: string;
|
|
54
|
-
link?: string;
|
|
55
|
-
scopeLink?: string;
|
|
56
|
-
local?: boolean;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export function Label({ componentId, link, scopeLink, local, ...rest }: LabelProps) {
|
|
60
|
-
const parsedId = useMemo(() => ComponentID.tryFromString(componentId), [componentId]);
|
|
61
|
-
|
|
62
|
-
if (!parsedId)
|
|
63
|
-
return (
|
|
64
|
-
<DefaultLabel {...rest} href={link}>
|
|
65
|
-
{componentId}
|
|
66
|
-
</DefaultLabel>
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
return <ComponentLabel {...rest} local={local} componentId={parsedId} link={link} scopeLink={scopeLink} />;
|
|
70
39
|
}
|
package/label/links.tsx
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import urlJoin from 'url-join';
|
|
2
|
+
import type { ComponentID } from '@teambit/component-id';
|
|
3
|
+
import { ComponentUrl } from '@teambit/component.modules.component-url';
|
|
4
|
+
|
|
5
|
+
export function calcComponentLink(id: ComponentID | undefined, exported: boolean | undefined) {
|
|
6
|
+
if (!id) return undefined;
|
|
7
|
+
if (exported) return ComponentUrl.toUrl(id);
|
|
8
|
+
return urlJoin('/', id.fullName);
|
|
9
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Tippy, { TippyProps } from '@tippyjs/react/headless';
|
|
3
|
+
import { ComponentMetaHolder } from '@teambit/react.ui.highlighter.component-metadata.bit-component-meta';
|
|
4
|
+
|
|
5
|
+
import { ComponentStrip, ComponentStripSize } from './component-strip';
|
|
6
|
+
import styles from './label.module.scss';
|
|
7
|
+
|
|
8
|
+
export type OtherComponentsProps = {
|
|
9
|
+
components: ComponentMetaHolder[];
|
|
10
|
+
size?: ComponentStripSize;
|
|
11
|
+
start?: number;
|
|
12
|
+
end?: number;
|
|
13
|
+
} & TippyProps;
|
|
14
|
+
|
|
15
|
+
// a popper ("tooltip") that shows the additional React Components related to this dom element
|
|
16
|
+
export function OtherComponentsPopper({
|
|
17
|
+
components,
|
|
18
|
+
children,
|
|
19
|
+
start,
|
|
20
|
+
end = -1,
|
|
21
|
+
size,
|
|
22
|
+
placement = 'bottom',
|
|
23
|
+
interactive = true,
|
|
24
|
+
...tippyProps
|
|
25
|
+
}: OtherComponentsProps) {
|
|
26
|
+
const content = (
|
|
27
|
+
<>
|
|
28
|
+
{components
|
|
29
|
+
.slice(start, end)
|
|
30
|
+
.reverse()
|
|
31
|
+
.map((comp, idx) => (
|
|
32
|
+
<ComponentStrip key={idx} component={comp} size={size} />
|
|
33
|
+
))}
|
|
34
|
+
</>
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<Tippy
|
|
39
|
+
placement={placement}
|
|
40
|
+
interactive={interactive}
|
|
41
|
+
{...tippyProps}
|
|
42
|
+
// second parameter "content" is always undefined, use content inline
|
|
43
|
+
// https://github.com/atomiks/tippyjs-react/issues/341
|
|
44
|
+
render={(attrs) => (
|
|
45
|
+
<div {...attrs} className={styles.othersContainer}>
|
|
46
|
+
{content}
|
|
47
|
+
</div>
|
|
48
|
+
)}
|
|
49
|
+
>
|
|
50
|
+
{children}
|
|
51
|
+
</Tippy>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
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 { IconButton } from '@teambit/design.ui.icon-button';
|
|
4
5
|
import { ExcludeHighlighter } from '../ignore-highlighter';
|
|
5
6
|
import { MultiHighlighter } from './multi-highlighter';
|
|
6
7
|
|
|
@@ -11,7 +12,7 @@ export const MultiHighlighterPreview = () => {
|
|
|
11
12
|
<br />
|
|
12
13
|
<br />
|
|
13
14
|
<br />
|
|
14
|
-
<
|
|
15
|
+
<IconButton>this will be highlighted with dropdown</IconButton>
|
|
15
16
|
</MultiHighlighter>
|
|
16
17
|
);
|
|
17
18
|
};
|
|
@@ -55,9 +56,10 @@ export const MultiHighlighterInsideIgnore = () => {
|
|
|
55
56
|
|
|
56
57
|
export const MultiHighlighterWithRule = () => {
|
|
57
58
|
return (
|
|
58
|
-
<MultiHighlighter rule="#someSubTree *">
|
|
59
|
-
<
|
|
60
|
-
|
|
59
|
+
<MultiHighlighter rule="#someSubTree *" style={{ minWidth: 300 }}>
|
|
60
|
+
<div>
|
|
61
|
+
element filter: <code>"#someSubTree *"</code>
|
|
62
|
+
</div>
|
|
61
63
|
<br />
|
|
62
64
|
<MockedComponentWithMeta>no highlighter</MockedComponentWithMeta>
|
|
63
65
|
<br />
|
|
@@ -70,6 +72,22 @@ export const MultiHighlighterWithRule = () => {
|
|
|
70
72
|
);
|
|
71
73
|
};
|
|
72
74
|
|
|
75
|
+
export const MultiHighlighterWithComponentRule = () => {
|
|
76
|
+
return (
|
|
77
|
+
<MultiHighlighter componentRule="teambit.design/ui/icon-button" style={{ minWidth: 300 }}>
|
|
78
|
+
<div>
|
|
79
|
+
component filter: <code>"teambit.design/ui/icon-button"</code>
|
|
80
|
+
</div>
|
|
81
|
+
<br />
|
|
82
|
+
<MockedComponentWithMeta>no highlighter</MockedComponentWithMeta>
|
|
83
|
+
<br />
|
|
84
|
+
<br />
|
|
85
|
+
<br />
|
|
86
|
+
<IconButton>this will be highlighted</IconButton>
|
|
87
|
+
</MultiHighlighter>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
|
|
73
91
|
// export const HighlightingAllElementsInTheEnterprisePage = () => {
|
|
74
92
|
// return (
|
|
75
93
|
// <MultiHighlighter>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { useEffect, RefObject } from 'react';
|
|
2
2
|
import getXPath from 'get-xpath';
|
|
3
|
-
import {
|
|
3
|
+
import { domToReacts, toRootElement } from '@teambit/react.modules.dom-to-react';
|
|
4
4
|
import {
|
|
5
|
-
hasComponentMeta,
|
|
6
5
|
componentMetaField,
|
|
7
|
-
|
|
6
|
+
hasComponentMeta,
|
|
7
|
+
ReactComponentMetaHolder,
|
|
8
8
|
} from '@teambit/react.ui.highlighter.component-metadata.bit-component-meta';
|
|
9
9
|
import { HighlightTarget } from '../element-highlighter';
|
|
10
10
|
import { excludeHighlighterSelector } from '../ignore-highlighter';
|
|
11
|
-
import { ruleMatcher, MatchRule } from '../rule-matcher';
|
|
11
|
+
import { ruleMatcher, MatchRule, ComponentMatchRule, componentRuleMatcher } from '../rule-matcher';
|
|
12
12
|
|
|
13
13
|
type useMultiHighlighterProps = {
|
|
14
14
|
onChange: (highlighterTargets: Record<string, HighlightTarget>) => void;
|
|
@@ -17,6 +17,7 @@ type useMultiHighlighterProps = {
|
|
|
17
17
|
scopeClass?: string;
|
|
18
18
|
/** filter highlighter targets by this query selector. (May be a more complex object in the future) */
|
|
19
19
|
rule?: MatchRule;
|
|
20
|
+
componentRule?: ComponentMatchRule;
|
|
20
21
|
|
|
21
22
|
// /** automatically update when children update. Use with caution, might be slow */
|
|
22
23
|
// watchDom?: boolean;
|
|
@@ -28,6 +29,7 @@ export function useMultiHighlighter({
|
|
|
28
29
|
scopeRef,
|
|
29
30
|
scopeClass: scopeSelector = '',
|
|
30
31
|
rule,
|
|
32
|
+
componentRule,
|
|
31
33
|
}: useMultiHighlighterProps) {
|
|
32
34
|
useEffect(() => {
|
|
33
35
|
const nextTargets: Record<string, HighlightTarget> = {};
|
|
@@ -44,15 +46,17 @@ export function useMultiHighlighter({
|
|
|
44
46
|
const uniqueRoots = new Set(rootElements);
|
|
45
47
|
|
|
46
48
|
uniqueRoots.forEach((element) => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
if (!element) return;
|
|
50
|
+
const comps = domToReacts(element);
|
|
51
|
+
const componentsWithMeta = comps.filter(
|
|
52
|
+
(x) => hasComponentMeta(x) && componentRuleMatcher({ meta: x[componentMetaField] }, componentRule)
|
|
53
|
+
) as ReactComponentMetaHolder[];
|
|
54
|
+
|
|
55
|
+
if (componentsWithMeta.length < 1) return;
|
|
49
56
|
|
|
50
57
|
const key = getXPath(element);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const link = meta[componentMetaProperties.homepageUrl];
|
|
54
|
-
const local = meta[componentMetaProperties.isExported] === false;
|
|
55
|
-
nextTargets[key] = { element, id: compId, link, local };
|
|
58
|
+
|
|
59
|
+
nextTargets[key] = { element, components: componentsWithMeta };
|
|
56
60
|
});
|
|
57
61
|
|
|
58
62
|
onChange(nextTargets);
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teambit/react.ui.component-highlighter",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.493",
|
|
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.493"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@popperjs/core": "2.6.0",
|
|
13
12
|
"classnames": "2.2.6",
|
|
13
|
+
"@popperjs/core": "2.6.0",
|
|
14
14
|
"react-popper": "2.2.4",
|
|
15
15
|
"use-debounce": "6.0.1",
|
|
16
16
|
"uuid": "3.4.0",
|
|
17
|
-
"get-xpath": "3.0.1",
|
|
18
17
|
"url-join": "4.0.1",
|
|
18
|
+
"@tippyjs/react": "4.2.0",
|
|
19
|
+
"get-xpath": "3.0.1",
|
|
19
20
|
"core-js": "^3.0.0",
|
|
20
21
|
"@teambit/base-ui.utils.popper-js.ignore-popper-size": "1.0.0",
|
|
21
22
|
"@teambit/base-ui.utils.popper-js.resize-to-match-reference": "1.0.0",
|
|
22
|
-
"@teambit/base-ui.surfaces.card": "1.0.1",
|
|
23
23
|
"@teambit/base-ui.routing.native-link": "1.0.0",
|
|
24
|
-
"@teambit/
|
|
25
|
-
"@teambit/react.ui.highlighter.component-metadata.bit-component-meta": "0.0.
|
|
26
|
-
"@teambit/
|
|
27
|
-
"@teambit/
|
|
28
|
-
"@teambit/
|
|
29
|
-
"@teambit/component.modules.component-url": "0.0.
|
|
24
|
+
"@teambit/component-id": "0.0.389",
|
|
25
|
+
"@teambit/react.ui.highlighter.component-metadata.bit-component-meta": "0.0.11",
|
|
26
|
+
"@teambit/ui-foundation.ui.constants.z-indexes": "0.0.477",
|
|
27
|
+
"@teambit/react.modules.dom-to-react": "0.0.477",
|
|
28
|
+
"@teambit/react.ui.hover-selector": "0.0.155",
|
|
29
|
+
"@teambit/component.modules.component-url": "0.0.110"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/react": "^17.0.8",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"@teambit/design.ui.icon-button": "1.0.10"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
|
-
"@teambit/legacy": "1.0.
|
|
46
|
+
"@teambit/legacy": "1.0.185",
|
|
47
47
|
"react-dom": "^16.8.0 || ^17.0.0",
|
|
48
48
|
"react": "^16.8.0 || ^17.0.0"
|
|
49
49
|
},
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"react": "-"
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|
|
74
|
-
"@teambit/legacy": "1.0.
|
|
74
|
+
"@teambit/legacy": "1.0.185",
|
|
75
75
|
"react-dom": "^16.8.0 || ^17.0.0",
|
|
76
76
|
"react": "^16.8.0 || ^17.0.0"
|
|
77
77
|
}
|
package/rule-matcher.tsx
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
// in the future, we will add more options here, like include / exclude objects.
|
|
2
|
+
import { ComponentID } from '@teambit/component-id';
|
|
3
|
+
import { ComponentMeta } from '@teambit/react.ui.highlighter.component-metadata.bit-component-meta';
|
|
2
4
|
|
|
3
5
|
export type MatchRule = undefined | string | ((element: HTMLElement) => boolean);
|
|
6
|
+
export type ComponentMatchRule = undefined | string | string[] | ((target: ComponentMatchTarget) => boolean);
|
|
4
7
|
|
|
5
8
|
export function ruleMatcher(element: HTMLElement, rule: MatchRule) {
|
|
6
9
|
if (typeof rule === 'string') {
|
|
@@ -13,3 +16,27 @@ export function ruleMatcher(element: HTMLElement, rule: MatchRule) {
|
|
|
13
16
|
|
|
14
17
|
return true;
|
|
15
18
|
}
|
|
19
|
+
|
|
20
|
+
export type ComponentMatchTarget = { meta: ComponentMeta };
|
|
21
|
+
|
|
22
|
+
export function componentRuleMatcher(target: ComponentMatchTarget, rule: ComponentMatchRule): boolean {
|
|
23
|
+
if (typeof rule === 'string') {
|
|
24
|
+
const targetCmpId = ComponentID.tryFromString(target.meta.id);
|
|
25
|
+
const ruleCmpId = ComponentID.tryFromString(rule);
|
|
26
|
+
|
|
27
|
+
return ComponentID.isEqual(ruleCmpId, targetCmpId, { ignoreVersion: true });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (Array.isArray(rule)) {
|
|
31
|
+
const targetCmpId = ComponentID.tryFromString(target.meta.id);
|
|
32
|
+
const ruleCmpIds = rule.map((x) => ComponentID.tryFromString(x));
|
|
33
|
+
|
|
34
|
+
return ruleCmpIds.some((cmdId) => ComponentID.isEqual(targetCmpId, cmdId, { ignoreVersion: true }));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (typeof rule === 'function') {
|
|
38
|
+
return rule(target);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return true;
|
|
42
|
+
}
|
package/use-animation-frame.tsx
CHANGED
|
@@ -2,7 +2,7 @@ import { useEffect } from 'react';
|
|
|
2
2
|
|
|
3
3
|
// TODO - extract to its own component
|
|
4
4
|
|
|
5
|
-
export function useAnimationFrame(cb?: false | null | (() => any), deps: [] = []) {
|
|
5
|
+
export function useAnimationFrame(cb?: false | null | (() => any), deps: any[] = []) {
|
|
6
6
|
useEffect(() => {
|
|
7
7
|
if (!cb) return () => {};
|
|
8
8
|
|