@teambit/react.ui.component-highlighter 0.0.479 → 0.0.483

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 (58) hide show
  1. package/component-highlighter/hover-highlighter/hover-highlighter.spec.tsx +38 -11
  2. package/component-highlighter/hover-highlighter/hover-highlighter.tsx +18 -15
  3. package/component-highlighter.docs.md +34 -7
  4. package/dist/component-highlighter/hover-highlighter/hover-highlighter.d.ts +3 -1
  5. package/dist/component-highlighter/hover-highlighter/hover-highlighter.js +6 -9
  6. package/dist/component-highlighter/hover-highlighter/hover-highlighter.js.map +1 -1
  7. package/dist/component-highlighter/hover-highlighter/hover-highlighter.spec.js +30 -12
  8. package/dist/component-highlighter/hover-highlighter/hover-highlighter.spec.js.map +1 -1
  9. package/dist/component-highlighter.docs.md +34 -7
  10. package/dist/element-highlighter/element-highlighter.compositions.d.ts +9 -3
  11. package/dist/element-highlighter/element-highlighter.compositions.js +21 -16
  12. package/dist/element-highlighter/element-highlighter.compositions.js.map +1 -1
  13. package/dist/element-highlighter/element-highlighter.d.ts +3 -1
  14. package/dist/element-highlighter/element-highlighter.js +3 -3
  15. package/dist/element-highlighter/element-highlighter.js.map +1 -1
  16. package/dist/element-highlighter/element-highlighter.module.scss +7 -0
  17. package/dist/frame/frame.d.ts +3 -2
  18. package/dist/frame/frame.js +3 -18
  19. package/dist/frame/frame.js.map +1 -1
  20. package/dist/index.d.ts +3 -1
  21. package/dist/index.js +5 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/label/label.d.ts +3 -1
  24. package/dist/label/label.js +4 -7
  25. package/dist/label/label.js.map +1 -1
  26. package/dist/multi-highlighter/index.d.ts +2 -0
  27. package/dist/multi-highlighter/index.js +6 -0
  28. package/dist/multi-highlighter/index.js.map +1 -0
  29. package/dist/multi-highlighter/multi-highlighter.composition.d.ts +2 -0
  30. package/dist/multi-highlighter/multi-highlighter.composition.js +36 -0
  31. package/dist/multi-highlighter/multi-highlighter.composition.js.map +1 -0
  32. package/dist/multi-highlighter/multi-highlighter.d.ts +15 -0
  33. package/dist/multi-highlighter/multi-highlighter.js +84 -0
  34. package/dist/multi-highlighter/multi-highlighter.js.map +1 -0
  35. package/dist/multi-highlighter/multi-highlighter.spec.d.ts +1 -0
  36. package/dist/multi-highlighter/multi-highlighter.spec.js +22 -0
  37. package/dist/multi-highlighter/multi-highlighter.spec.js.map +1 -0
  38. package/dist/use-animation-frame.d.ts +1 -0
  39. package/dist/use-animation-frame.js +23 -0
  40. package/dist/use-animation-frame.js.map +1 -0
  41. package/element-highlighter/element-highlighter.compositions.tsx +37 -22
  42. package/element-highlighter/element-highlighter.module.scss +7 -0
  43. package/element-highlighter/element-highlighter.tsx +14 -2
  44. package/frame/frame.tsx +6 -21
  45. package/index.ts +9 -1
  46. package/label/label.tsx +14 -12
  47. package/multi-highlighter/index.ts +2 -0
  48. package/multi-highlighter/multi-highlighter.composition.tsx +41 -0
  49. package/multi-highlighter/multi-highlighter.spec.tsx +22 -0
  50. package/multi-highlighter/multi-highlighter.tsx +85 -0
  51. package/package-tar/teambit-react.ui.component-highlighter-0.0.483.tgz +0 -0
  52. package/package.json +12 -11
  53. package/use-animation-frame.tsx +20 -0
  54. package/component-highlighter/bit-react-component.ts +0 -5
  55. package/dist/component-highlighter/bit-react-component.d.ts +0 -2
  56. package/dist/component-highlighter/bit-react-component.js +0 -8
  57. package/dist/component-highlighter/bit-react-component.js.map +0 -1
  58. package/package-tar/teambit-react.ui.component-highlighter-0.0.479.tgz +0 -0
package/label/label.tsx CHANGED
@@ -2,24 +2,34 @@ import React, { useMemo, useState } from 'react';
2
2
  import { usePopper } from 'react-popper';
3
3
  import { ComponentID } from '@teambit/component-id';
4
4
  import type { CardProps } from '@teambit/base-ui.surfaces.card';
5
- import useAnimationFrame from 'use-animation-frame';
6
5
  import type { Placement, Modifier } from '@popperjs/core';
7
6
  import '@popperjs/core';
8
7
 
9
8
  import { DefaultLabel } from './default-label';
10
9
  import { ComponentLabel } from './component-label';
10
+ import { useAnimationFrame } from '../use-animation-frame';
11
11
 
12
12
  export interface LabelContainerProps extends React.HTMLAttributes<HTMLDivElement> {
13
13
  targetRef: HTMLElement | null;
14
14
  offset?: [number, number];
15
15
  placement?: Placement;
16
16
  flip?: boolean;
17
+ /** continually update label position to match moving elements */
18
+ watchMotion?: boolean;
17
19
  }
18
20
 
19
21
  export type { Placement };
20
22
 
21
23
  // TODO - replace this with TippyJS, when it supports a `targetElement={targetRef.current}` prop
22
- export function LabelContainer({ targetRef, offset, placement, flip = true, className, ...rest }: LabelContainerProps) {
24
+ export function LabelContainer({
25
+ targetRef,
26
+ offset,
27
+ placement,
28
+ flip = true,
29
+ watchMotion,
30
+ className,
31
+ ...rest
32
+ }: LabelContainerProps) {
23
33
  const [sourceRef, setSourceRef] = useState<HTMLDivElement | null>(null);
24
34
 
25
35
  const modifiers = useMemo<Partial<Modifier<any, any>>[]>(
@@ -32,19 +42,11 @@ export function LabelContainer({ targetRef, offset, placement, flip = true, clas
32
42
  placement,
33
43
  });
34
44
 
35
- useAnimationFrame(() => update?.(), [update]);
45
+ useAnimationFrame(!!watchMotion && update);
36
46
 
37
47
  if (!targetRef) return null;
38
48
 
39
- return (
40
- <div
41
- {...rest}
42
- ref={setSourceRef}
43
- className={className}
44
- style={styles.popper}
45
- {...attributes.popper}
46
- />
47
- );
49
+ return <div {...rest} ref={setSourceRef} className={className} style={styles.popper} {...attributes.popper} />;
48
50
  }
49
51
 
50
52
  export interface LabelProps extends CardProps {
@@ -0,0 +1,2 @@
1
+ export { MultiHighlighter } from './multi-highlighter';
2
+ export type { MultiHighlighterProps } from './multi-highlighter';
@@ -0,0 +1,41 @@
1
+ import React from 'react';
2
+ // import { EnterpriseOffering } from '@teambit/evangelist.pages.enterprise-offering';
3
+ import { MockedComponentWithMeta } from '@teambit/react.ui.highlighter.component-metadata.bit-component-meta';
4
+ import { MultiHighlighter } from './multi-highlighter';
5
+
6
+ export const MultiHighlighterPreview = () => {
7
+ return (
8
+ <MultiHighlighter style={{ padding: 40 }}>
9
+ <MockedComponentWithMeta>hover here</MockedComponentWithMeta>
10
+ <br />
11
+ <br />
12
+ <br />
13
+ <MockedComponentWithMeta>also here</MockedComponentWithMeta>
14
+ </MultiHighlighter>
15
+ );
16
+ };
17
+
18
+ export const MultiHighlighterWithCustomColors = () => {
19
+ return (
20
+ <MultiHighlighter
21
+ style={{ padding: 40, color: 'yellow' }}
22
+ bgColor="cornflowerblue"
23
+ bgColorHover="blue"
24
+ bgColorActive="DarkSlateBlue"
25
+ >
26
+ <MockedComponentWithMeta>hover here</MockedComponentWithMeta>
27
+ <br />
28
+ <br />
29
+ <br />
30
+ <MockedComponentWithMeta>also here</MockedComponentWithMeta>
31
+ </MultiHighlighter>
32
+ );
33
+ };
34
+
35
+ // export const HighlightingAllElementsInTheEnterprisePage = () => {
36
+ // return (
37
+ // <MultiHighlighter>
38
+ // <EnterpriseOffering style={{ height: 300 }} />
39
+ // </MultiHighlighter>
40
+ // );
41
+ // };
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import { render } from '@testing-library/react';
3
+ import { MultiHighlighterPreview } from './multi-highlighter.composition';
4
+
5
+ it('should not throw when rendering the multi-highlighter', () => {
6
+ const { getByText } = render(<MultiHighlighterPreview />);
7
+
8
+ const rendered = getByText('hover here');
9
+
10
+ expect(rendered).toBeInstanceOf(HTMLElement);
11
+ });
12
+
13
+ // .querySelectorAll() is not working as expected during the test, ignoring for now :(
14
+ // it('should render highlighter for all children components', async () => {
15
+ // const { queryAllByText } = render(<Preview />);
16
+
17
+ // // allow useEffect to run
18
+ // await new Promise((res) => setTimeout(res, 200));
19
+
20
+ // const rendered = queryAllByText('input/button');
21
+ // expect(rendered).toHaveLength(2);
22
+ // });
@@ -0,0 +1,85 @@
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';
7
+
8
+ // TODO - reuse selector from @teambit/react.ui.component-highlighter
9
+ const allExceptHighlighterQuery = `:not(${excludeHighlighterSelector}, ${excludeHighlighterSelector} *)`;
10
+
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;
20
+
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
+ );
85
+ }
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@teambit/react.ui.component-highlighter",
3
- "version": "0.0.479",
3
+ "version": "0.0.483",
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.479"
9
+ "version": "0.0.483"
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
- "use-animation-frame": "0.1.0",
15
+ "get-xpath": "3.0.1",
16
16
  "use-debounce": "6.0.1",
17
17
  "url-join": "4.0.1",
18
18
  "core-js": "^3.0.0",
@@ -20,11 +20,12 @@
20
20
  "@teambit/base-ui.utils.popper-js.resize-to-match-reference": "1.0.0",
21
21
  "@teambit/base-ui.surfaces.card": "1.0.1",
22
22
  "@teambit/base-ui.routing.native-link": "1.0.0",
23
- "@teambit/react.babel.bit-react-transformer": "0.0.474",
24
- "@teambit/component-id": "0.0.380",
25
- "@teambit/react.modules.dom-to-react": "0.0.466",
26
- "@teambit/react.ui.hover-selector": "0.0.145",
27
- "@teambit/component.modules.component-url": "0.0.101"
23
+ "@teambit/ui-foundation.ui.constants.z-indexes": "0.0.471",
24
+ "@teambit/component-id": "0.0.383",
25
+ "@teambit/react.modules.dom-to-react": "0.0.470",
26
+ "@teambit/react.ui.highlighter.component-metadata.bit-component-meta": "0.0.4",
27
+ "@teambit/react.ui.hover-selector": "0.0.148",
28
+ "@teambit/component.modules.component-url": "0.0.104"
28
29
  },
29
30
  "devDependencies": {
30
31
  "@types/react": "^17.0.8",
@@ -40,7 +41,7 @@
40
41
  "@teambit/design.ui.icon-button": "1.0.10"
41
42
  },
42
43
  "peerDependencies": {
43
- "@teambit/legacy": "1.0.176",
44
+ "@teambit/legacy": "1.0.179",
44
45
  "react-dom": "^16.8.0 || ^17.0.0",
45
46
  "react": "^16.8.0 || ^17.0.0"
46
47
  },
@@ -68,7 +69,7 @@
68
69
  "react": "-"
69
70
  },
70
71
  "peerDependencies": {
71
- "@teambit/legacy": "1.0.176",
72
+ "@teambit/legacy": "1.0.179",
72
73
  "react-dom": "^16.8.0 || ^17.0.0",
73
74
  "react": "^16.8.0 || ^17.0.0"
74
75
  }
@@ -0,0 +1,20 @@
1
+ import { useEffect } from 'react';
2
+
3
+ // TODO - extract to its own component
4
+
5
+ export function useAnimationFrame(cb?: false | null | (() => any), deps: [] = []) {
6
+ useEffect(() => {
7
+ if (!cb) return () => {};
8
+
9
+ let animationFrameId = -1;
10
+ const animate = () => {
11
+ cb();
12
+ animationFrameId = window.requestAnimationFrame(animate);
13
+ };
14
+ animate();
15
+
16
+ return () => {
17
+ if (animationFrameId > -1) window.cancelAnimationFrame(animationFrameId);
18
+ };
19
+ }, [cb, ...deps]);
20
+ }
@@ -1,5 +0,0 @@
1
- import type { ComponentMetaHolder } from '@teambit/react.babel.bit-react-transformer';
2
-
3
- export function hasComponentMeta(component: any): component is ComponentMetaHolder {
4
- return component && typeof component.__bit_component === 'object' && typeof component.__bit_component.id === 'string';
5
- }
@@ -1,2 +0,0 @@
1
- import type { ComponentMetaHolder } from '@teambit/react.babel.bit-react-transformer';
2
- export declare function hasComponentMeta(component: any): component is ComponentMetaHolder;
@@ -1,8 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.hasComponentMeta = void 0;
4
- function hasComponentMeta(component) {
5
- return component && typeof component.__bit_component === 'object' && typeof component.__bit_component.id === 'string';
6
- }
7
- exports.hasComponentMeta = hasComponentMeta;
8
- //# sourceMappingURL=bit-react-component.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"bit-react-component.js","sourceRoot":"","sources":["../../component-highlighter/bit-react-component.ts"],"names":[],"mappings":";;;AAEA,SAAgB,gBAAgB,CAAC,SAAc;IAC7C,OAAO,SAAS,IAAI,OAAO,SAAS,CAAC,eAAe,KAAK,QAAQ,IAAI,OAAO,SAAS,CAAC,eAAe,CAAC,EAAE,KAAK,QAAQ,CAAC;AACxH,CAAC;AAFD,4CAEC"}