@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.
Files changed (100) hide show
  1. package/component-highlighter.docs.md +9 -0
  2. package/dist/component-highlighter.docs.md +9 -0
  3. package/dist/element-highlighter/element-highlighter.compositions.d.ts +3 -1
  4. package/dist/element-highlighter/element-highlighter.compositions.js +15 -7
  5. package/dist/element-highlighter/element-highlighter.compositions.js.map +1 -1
  6. package/dist/element-highlighter/element-highlighter.d.ts +8 -9
  7. package/dist/element-highlighter/element-highlighter.js +3 -3
  8. package/dist/element-highlighter/element-highlighter.js.map +1 -1
  9. package/dist/element-highlighter/index.d.ts +1 -1
  10. package/dist/hover-highlighter/use-hover-highlighter.d.ts +5 -2
  11. package/dist/hover-highlighter/use-hover-highlighter.js +13 -15
  12. package/dist/hover-highlighter/use-hover-highlighter.js.map +1 -1
  13. package/dist/hybrid-highligher/hybrid-highlighter.d.ts +6 -3
  14. package/dist/hybrid-highligher/hybrid-highlighter.js +4 -2
  15. package/dist/hybrid-highligher/hybrid-highlighter.js.map +1 -1
  16. package/dist/label/component-strip.d.ts +9 -0
  17. package/dist/label/component-strip.js +49 -0
  18. package/dist/label/component-strip.js.map +1 -0
  19. package/dist/label/component-strip.module.scss +64 -0
  20. package/dist/label/index.d.ts +4 -2
  21. package/dist/label/index.js +3 -2
  22. package/dist/label/index.js.map +1 -1
  23. package/dist/label/label-container.d.ts +13 -0
  24. package/dist/label/label-container.js +53 -0
  25. package/dist/label/label-container.js.map +1 -0
  26. package/dist/label/label.d.ts +7 -19
  27. package/dist/label/label.js +20 -27
  28. package/dist/label/label.js.map +1 -1
  29. package/dist/label/label.module.scss +24 -0
  30. package/dist/label/links.d.ts +2 -0
  31. package/dist/label/links.js +17 -0
  32. package/dist/label/links.js.map +1 -0
  33. package/dist/label/other-components.d.ts +10 -0
  34. package/dist/label/other-components.js +35 -0
  35. package/dist/label/other-components.js.map +1 -0
  36. package/dist/multi-highlighter/multi-highlighter.composition.d.ts +1 -0
  37. package/dist/multi-highlighter/multi-highlighter.composition.js +20 -5
  38. package/dist/multi-highlighter/multi-highlighter.composition.js.map +1 -1
  39. package/dist/multi-highlighter/use-multi-highlighter.d.ts +3 -2
  40. package/dist/multi-highlighter/use-multi-highlighter.js +7 -8
  41. package/dist/multi-highlighter/use-multi-highlighter.js.map +1 -1
  42. package/dist/rule-matcher.d.ts +6 -0
  43. package/dist/rule-matcher.js +20 -2
  44. package/dist/rule-matcher.js.map +1 -1
  45. package/dist/use-animation-frame.d.ts +1 -1
  46. package/dist/use-animation-frame.js.map +1 -1
  47. package/element-highlighter/element-highlighter.compositions.tsx +22 -8
  48. package/element-highlighter/element-highlighter.tsx +11 -16
  49. package/element-highlighter/index.ts +7 -1
  50. package/hover-highlighter/use-hover-highlighter.tsx +36 -19
  51. package/hybrid-highligher/hybrid-highlighter.tsx +16 -2
  52. package/label/component-strip.module.scss +64 -0
  53. package/label/component-strip.tsx +49 -0
  54. package/label/index.ts +5 -2
  55. package/label/label-container.tsx +46 -0
  56. package/label/label.module.scss +24 -0
  57. package/label/label.tsx +35 -66
  58. package/label/links.tsx +9 -0
  59. package/label/other-components.tsx +53 -0
  60. package/multi-highlighter/multi-highlighter.composition.tsx +22 -4
  61. package/multi-highlighter/use-multi-highlighter.tsx +15 -11
  62. package/package-tar/teambit-react.ui.component-highlighter-0.0.493.tgz +0 -0
  63. package/package.json +13 -13
  64. package/rule-matcher.tsx +27 -0
  65. package/use-animation-frame.tsx +1 -1
  66. package/bubble/bubble.module.scss +0 -24
  67. package/bubble/index.ts +0 -3
  68. package/dist/bubble/bubble.module.scss +0 -24
  69. package/dist/bubble/index.d.ts +0 -1
  70. package/dist/bubble/index.js +0 -9
  71. package/dist/bubble/index.js.map +0 -1
  72. package/dist/label/component-label/component-bubble.d.ts +0 -7
  73. package/dist/label/component-label/component-bubble.js +0 -35
  74. package/dist/label/component-label/component-bubble.js.map +0 -1
  75. package/dist/label/component-label/component-label.d.ts +0 -9
  76. package/dist/label/component-label/component-label.js +0 -32
  77. package/dist/label/component-label/component-label.js.map +0 -1
  78. package/dist/label/component-label/duo-component-bubble.module.scss +0 -24
  79. package/dist/label/component-label/index.d.ts +0 -2
  80. package/dist/label/component-label/index.js +0 -6
  81. package/dist/label/component-label/index.js.map +0 -1
  82. package/dist/label/component-label/scope-bubble.d.ts +0 -6
  83. package/dist/label/component-label/scope-bubble.js +0 -28
  84. package/dist/label/component-label/scope-bubble.js.map +0 -1
  85. package/dist/label/default-label/default-label.d.ts +0 -5
  86. package/dist/label/default-label/default-label.js +0 -30
  87. package/dist/label/default-label/default-label.js.map +0 -1
  88. package/dist/label/default-label/default-label.module.scss +0 -12
  89. package/dist/label/default-label/index.d.ts +0 -1
  90. package/dist/label/default-label/index.js +0 -6
  91. package/dist/label/default-label/index.js.map +0 -1
  92. package/label/component-label/component-bubble.tsx +0 -30
  93. package/label/component-label/component-label.tsx +0 -31
  94. package/label/component-label/duo-component-bubble.module.scss +0 -24
  95. package/label/component-label/index.ts +0 -2
  96. package/label/component-label/scope-bubble.tsx +0 -20
  97. package/label/default-label/default-label.module.scss +0 -12
  98. package/label/default-label/default-label.tsx +0 -22
  99. package/label/default-label/index.ts +0 -1
  100. 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 { ElementHighlighter, HighlightTarget, Placement, HighlightClasses } from '../element-highlighter';
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 { LabelContainer, Label } from './label';
2
- export type { LabelContainerProps, LabelProps, Placement } from './label';
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, { useMemo, useState } from 'react';
2
- import { usePopper } from 'react-popper';
3
- import { ComponentID } from '@teambit/component-id';
4
- import type { CardProps } from '@teambit/base-ui.surfaces.card';
5
- import type { Placement, Modifier } from '@popperjs/core';
6
- import '@popperjs/core';
7
-
8
- import { DefaultLabel } from './default-label';
9
- import { ComponentLabel } from './component-label';
10
- import { useAnimationFrame } from '../use-animation-frame';
11
-
12
- export interface LabelContainerProps extends React.HTMLAttributes<HTMLDivElement> {
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 type { Placement };
22
-
23
- // TODO - replace this with TippyJS, when it supports a `targetElement={targetRef.current}` prop
24
- export function LabelContainer({
25
- targetRef,
26
- offset,
27
- placement,
28
- flip = true,
29
- watchMotion,
30
- className,
31
- ...rest
32
- }: LabelContainerProps) {
33
- const [sourceRef, setSourceRef] = useState<HTMLDivElement | null>(null);
34
-
35
- const modifiers = useMemo<Partial<Modifier<any, any>>[]>(
36
- () => [{ name: 'offset', options: { offset } }],
37
- [flip, offset]
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
  }
@@ -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
- <MockedComponentWithMeta>also here</MockedComponentWithMeta>
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
- <br />
60
- <br />
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 { domToReact, toRootElement } from '@teambit/react.modules.dom-to-react';
3
+ import { domToReacts, toRootElement } from '@teambit/react.modules.dom-to-react';
4
4
  import {
5
- hasComponentMeta,
6
5
  componentMetaField,
7
- componentMetaProperties,
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
- const comp = domToReact(element);
48
- if (!element || !hasComponentMeta(comp)) return;
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
- 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 };
58
+
59
+ nextTargets[key] = { element, components: componentsWithMeta };
56
60
  });
57
61
 
58
62
  onChange(nextTargets);
package/package.json CHANGED
@@ -1,32 +1,32 @@
1
1
  {
2
2
  "name": "@teambit/react.ui.component-highlighter",
3
- "version": "0.0.489",
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.489"
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/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"
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.184",
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.184",
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
+ }
@@ -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