@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.
Files changed (69) hide show
  1. package/component-highlighter.docs.md +86 -31
  2. package/dist/component-highlighter.docs.md +86 -31
  3. package/dist/{component-highlighter/hover-highlighter → hover-highlighter}/hover-highlighter.compositions.d.ts +0 -0
  4. package/dist/{component-highlighter/hover-highlighter → hover-highlighter}/hover-highlighter.compositions.js +6 -3
  5. package/dist/hover-highlighter/hover-highlighter.compositions.js.map +1 -0
  6. package/dist/hover-highlighter/hover-highlighter.d.ts +3 -0
  7. package/dist/hover-highlighter/hover-highlighter.js +25 -0
  8. package/dist/hover-highlighter/hover-highlighter.js.map +1 -0
  9. package/dist/{component-highlighter/hover-highlighter → hover-highlighter}/hover-highlighter.spec.d.ts +0 -0
  10. package/dist/{component-highlighter/hover-highlighter → hover-highlighter}/hover-highlighter.spec.js +0 -0
  11. package/dist/hover-highlighter/hover-highlighter.spec.js.map +1 -0
  12. package/dist/hover-highlighter/index.d.ts +4 -0
  13. package/dist/hover-highlighter/index.js +8 -0
  14. package/dist/hover-highlighter/index.js.map +1 -0
  15. package/dist/hover-highlighter/use-hover-highlighter.d.ts +17 -0
  16. package/dist/hover-highlighter/use-hover-highlighter.js +66 -0
  17. package/dist/hover-highlighter/use-hover-highlighter.js.map +1 -0
  18. package/dist/hybrid-highligher/hybrid-highlighter.d.ts +34 -0
  19. package/dist/hybrid-highligher/hybrid-highlighter.js +74 -0
  20. package/dist/hybrid-highligher/hybrid-highlighter.js.map +1 -0
  21. package/dist/hybrid-highligher/index.d.ts +2 -0
  22. package/dist/hybrid-highligher/index.js +6 -0
  23. package/dist/hybrid-highligher/index.js.map +1 -0
  24. package/dist/index.d.ts +5 -2
  25. package/dist/index.js +5 -3
  26. package/dist/index.js.map +1 -1
  27. package/dist/multi-highlighter/multi-highlighter.composition.d.ts +2 -0
  28. package/dist/multi-highlighter/multi-highlighter.composition.js +34 -3
  29. package/dist/multi-highlighter/multi-highlighter.composition.js.map +1 -1
  30. package/dist/multi-highlighter/multi-highlighter.d.ts +3 -15
  31. package/dist/multi-highlighter/multi-highlighter.js +4 -63
  32. package/dist/multi-highlighter/multi-highlighter.js.map +1 -1
  33. package/dist/multi-highlighter/use-multi-highlighter.d.ts +13 -0
  34. package/dist/multi-highlighter/use-multi-highlighter.js +51 -0
  35. package/dist/multi-highlighter/use-multi-highlighter.js.map +1 -0
  36. package/dist/rule-matcher.d.ts +2 -0
  37. package/dist/rule-matcher.js +15 -0
  38. package/dist/rule-matcher.js.map +1 -0
  39. package/{component-highlighter/hover-highlighter → hover-highlighter}/hover-highlighter.compositions.tsx +4 -2
  40. package/{component-highlighter/hover-highlighter → hover-highlighter}/hover-highlighter.spec.tsx +0 -0
  41. package/hover-highlighter/hover-highlighter.tsx +8 -0
  42. package/hover-highlighter/index.ts +5 -0
  43. package/hover-highlighter/use-hover-highlighter.tsx +93 -0
  44. package/hybrid-highligher/hybrid-highlighter.tsx +126 -0
  45. package/hybrid-highligher/index.ts +2 -0
  46. package/index.ts +7 -2
  47. package/multi-highlighter/multi-highlighter.composition.tsx +40 -2
  48. package/multi-highlighter/multi-highlighter.tsx +5 -81
  49. package/multi-highlighter/use-multi-highlighter.tsx +70 -0
  50. package/package-tar/teambit-react.ui.component-highlighter-0.0.489.tgz +0 -0
  51. package/package.json +14 -12
  52. package/rule-matcher.tsx +15 -0
  53. package/component-highlighter/hover-highlighter/hover-highlighter.module.scss +0 -13
  54. package/component-highlighter/hover-highlighter/hover-highlighter.tsx +0 -120
  55. package/component-highlighter/hover-highlighter/index.ts +0 -1
  56. package/component-highlighter/index.ts +0 -2
  57. package/dist/component-highlighter/hover-highlighter/hover-highlighter.compositions.js.map +0 -1
  58. package/dist/component-highlighter/hover-highlighter/hover-highlighter.d.ts +0 -21
  59. package/dist/component-highlighter/hover-highlighter/hover-highlighter.js +0 -100
  60. package/dist/component-highlighter/hover-highlighter/hover-highlighter.js.map +0 -1
  61. package/dist/component-highlighter/hover-highlighter/hover-highlighter.module.scss +0 -13
  62. package/dist/component-highlighter/hover-highlighter/hover-highlighter.spec.js.map +0 -1
  63. package/dist/component-highlighter/hover-highlighter/index.d.ts +0 -1
  64. package/dist/component-highlighter/hover-highlighter/index.js +0 -6
  65. package/dist/component-highlighter/hover-highlighter/index.js.map +0 -1
  66. package/dist/component-highlighter/index.d.ts +0 -2
  67. package/dist/component-highlighter/index.js +0 -6
  68. package/dist/component-highlighter/index.js.map +0 -1
  69. 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
+ }
@@ -0,0 +1,2 @@
1
+ export { HybridHighlighter } from './hybrid-highlighter';
2
+ export type { HybridHighlighterProps } from './hybrid-highlighter';
package/index.ts CHANGED
@@ -1,5 +1,8 @@
1
- export { HoverHighlighter as ComponentHighlighter } from './component-highlighter';
2
- export type { HoverHighlighterProps as ComponentHighlightProps } from './component-highlighter';
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, { useEffect, useState, createRef } from '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
- // TODO - reuse selector from @teambit/react.ui.component-highlighter
9
- const allExceptHighlighterQuery = `:not(${excludeHighlighterSelector}, ${excludeHighlighterSelector} *)`;
3
+ import { HybridHighlighter, HybridHighlighterProps } from '../hybrid-highligher';
10
4
 
11
- export interface MultiHighlighterProps extends React.HTMLAttributes<HTMLDivElement> {
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
- bgColor?: string;
22
- bgColorHover?: string;
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
+ }
package/package.json CHANGED
@@ -1,37 +1,39 @@
1
1
  {
2
2
  "name": "@teambit/react.ui.component-highlighter",
3
- "version": "0.0.485",
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.485"
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/ui-foundation.ui.constants.z-indexes": "0.0.473",
24
- "@teambit/react.modules.dom-to-react": "0.0.472",
25
- "@teambit/react.ui.highlighter.component-metadata.bit-component-meta": "0.0.6",
26
- "@teambit/component-id": "0.0.385",
27
- "@teambit/react.ui.hover-selector": "0.0.150",
28
- "@teambit/component.modules.component-url": "0.0.106"
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.181",
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.181",
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
  }
@@ -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,13 +0,0 @@
1
- .highlighter {
2
- border: solid var(--bit-border-color-lightest, #ededed);
3
- border-width: 0px;
4
- box-sizing: border-box;
5
- height: 100%;
6
-
7
- transition: border 300ms;
8
-
9
- &.active {
10
- border-width: 8px;
11
- overflow: auto;
12
- }
13
- }
@@ -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,2 +0,0 @@
1
- export { HoverHighlighter } from './hover-highlighter';
2
- export type { HoverHighlighterProps } 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;