elliots / vuesearchpal

Search 'palette' component for React, loosely based on MacOS Spotlight Search. Styled to look great out-of-box - pass through your own theme & elements. Autocomplete, search previews & more. Set to find exact and/or fuzzy matches.
https://searchpal.elijahharry.com/
0 stars 0 forks source link

Sweep: Port this react component to vue3 #2

Open elliots opened 3 months ago

elliots commented 3 months ago

Change as little as possible, just port it so it can be imported in a vue project

sweep-ai[bot] commented 3 months ago

🚀 Here's the PR! #3

💎 Sweep Pro: You have unlimited Sweep issues

Actions

Relevant files (click to expand). Mentioned files will always appear here. https://github.com/elliots/vuesearchpal/blob/0a707afc821ffe2dccfe84d681ecd61b1776a181/lib/src/hooks/useAnimatedRender.ts#L1-L38 https://github.com/elliots/vuesearchpal/blob/0a707afc821ffe2dccfe84d681ecd61b1776a181/lib/types/components.ts#L1-L31 https://github.com/elliots/vuesearchpal/blob/0a707afc821ffe2dccfe84d681ecd61b1776a181/lib/src/hooks/useChildComponents.ts#L1-L49 https://github.com/elliots/vuesearchpal/blob/0a707afc821ffe2dccfe84d681ecd61b1776a181/demo/src/components/Demos/Demos.tsx#L1-L120 https://github.com/elliots/vuesearchpal/blob/0a707afc821ffe2dccfe84d681ecd61b1776a181/README.md#L1-L1390

Step 2: ⌨️ Coding

lib/src/hooks/useAnimatedRender.ts

Convert the `useAnimatedRender` hook to a Vue 3 composition function. 1.
--- 
+++ 
@@ -1,39 +1,36 @@
-import { useEffect, useRef, useState } from "react";
+import { ref, watch } from "vue";

-export const useAnimatedRender: (
+export function useAnimatedRender(
   visible?: boolean | null | undefined,
   duration?: number | null
-) => [render: boolean, show: boolean, transitioning: boolean] = (
-  visible,
-  duration
-) => {
-  const [show, setShow] = useState(false);
-  const [render, setRender] = useState(visible === true ? true : false);
+) {
+  const show = ref(false);
+  const render = ref(visible === true ? true : false);

-  const delay = useRef(duration || 150);
-  useEffect(() => {
-    delay.current = duration || 150;
-  }, [duration]);
+  const delay = ref(duration || 150);
+  watch(() => duration, (newDuration) => {
+    delay.value = newDuration || 150;
+  });

-  useEffect(() => {
-    if (visible) {
-      setRender(true);
-      const timer = setTimeout(() => setShow(true), 50);
+  watch(() => visible, (newVisible) => {
+    if (newVisible) {
+      render.value = true;
+      const timer = setTimeout(() => show.value = true, 50);
       return () => clearTimeout(timer);
     } else {
-      setShow(false);
-      const timer = setTimeout(() => setRender(false), delay.current);
+      show.value = false;
+      const timer = setTimeout(() => render.value = false, delay.value);
       return () => clearTimeout(timer);
     }
-  }, [visible]);
+  });

-  const [transitioning, setTransitioning] = useState(false);
+  const transitioning = ref(false);

-  useEffect(() => {
-    setTransitioning(true);
-    const timer = setTimeout(() => setTransitioning(false), delay.current);
+  watch(show, () => {
+    transitioning.value = true;
+    const timer = setTimeout(() => transitioning.value = false, delay.value);
     return () => clearTimeout(timer);
-  }, [show]);
+  });

-  return [render, show, transitioning];
-};
+  return { render, show, transitioning };
+}

lib/src/hooks/useChildComponents.ts

Convert the `useChildComponents` hook to a Vue 3 composition function. 1.
--- 
+++ 
@@ -1,50 +1,42 @@
-import {
-  ReactNode,
-  Children,
-  useCallback,
-  ReactElement,
-  isValidElement,
-  createElement,
-  FunctionComponent,
-  ComponentProps,
-} from "react";
+import { VNode, FunctionalComponent, h } from "vue";
 import { ec } from "../../utils";

-export const useChildComponents = <P extends {} = {}>(
-  children: ReactNode,
-  component: FunctionComponent<P>
-) => {
-  type Props = ComponentProps<typeof component>;
+export function useChildComponents<P extends {} = {}>(
+  children: VNode[],
+  component: FunctionalComponent<P>
+) {
+  type Props = P;

-  const getChildren = useCallback(() => {
-    const getChildrenArr = (
-      childElements: ReactNode,
-      arr: ReactElement<Props>[]
-    ) => {
-      const isComponent = (
-        obj: ReactElement<any>
-      ): obj is ReactElement<Props> => obj.type === component;
-      Children.forEach(childElements, (child) => {
-        if (isValidElement(child)) {
-          if (isComponent(child)) arr.push(child);
-          if (hasChildren(child)) getChildrenArr(child.props.children, arr);
-        }
+  function getChildren() {
+    function getChildrenArr(
+      childElements: VNode[],
+      arr: VNode<Props>[]
+    ) {
+      function isComponent(
+        obj: VNode
+      ): obj is VNode<Props> {
+        return obj.type === component;
+      }
+      childElements.forEach((child) => {
+        if (isComponent(child)) arr.push(child);
+        if (hasChildren(child)) getChildrenArr(child.children as VNode[], arr);
       });
-    };
-    const results: ReactElement<Props>[] = [];
+    }
+    const results: VNode<Props>[] = [];
     getChildrenArr(children, results);
     return results.map((el, i) =>
-      createElement(component, {
+      h(component, {
         ...(el.props ? el.props : ({} as Props)),
         key: ec(el.key, i + 1),
       })
     );
-  }, [component, children]);
+  }

   return getChildren();
-};
+}

-const hasChildren = (
-  obj: ReactElement<any>
-): obj is ReactElement<{ children?: ReactNode }> =>
-  obj.props?.children ? true : false;
+function hasChildren(
+  obj: VNode
+): obj is VNode<{ children?: VNode[] }> {
+  return !!(obj.children && obj.children.length);
+}

lib/types/components.ts

Update the React-specific types and interfaces to use Vue 3 equivalents. 1.
--- 
+++ 
@@ -1,32 +1,32 @@
-import { FunctionComponent, PropsWithChildren, ReactElement } from "react";
+import { FunctionalComponent, AllowedComponentProps, VNode } from "vue";
 import { OptionProps, Renderable } from "./gen";

-export type LinkProps = PropsWithChildren<{
+export type LinkProps = AllowedComponentProps & {
   href: string;
   target?: string;
-}>;
-export type LinkComponent = FunctionComponent<LinkProps>;
+};
+export type LinkComponent = FunctionalComponent<LinkProps>;

 export type ArrowProps = {
   active: boolean;
   hovered: boolean;
   focused: boolean;
 };
-export type ArrowComponent = FunctionComponent<ArrowProps>;
+export type ArrowComponent = FunctionalComponent<ArrowProps>;

 export type MediaProps = Pick<OptionProps, "img" | "label"> & {
   active: boolean;
   hovered: boolean;
   focused: boolean;
 };
-export type MediaComponent = FunctionComponent<MediaProps>;
+export type MediaComponent = FunctionalComponent<MediaProps>;

 export type PreviewProps = Pick<OptionProps, "label" | "sublabel" | "img"> & {
-  media?: ReactElement<any, any>;
+  media?: VNode;
 };
-export type PreviewComponent = FunctionComponent<PreviewProps>;
+export type PreviewComponent = FunctionalComponent<PreviewProps>;

 export type ButtonProps = Pick<OptionProps, "onClick" | "label"> & {
   cta: Renderable;
 };
-export type ButtonComponent = FunctionComponent<ButtonProps>;
+export type ButtonComponent = FunctionalComponent<ButtonProps>;

Step 3: 🔄️ Validating

Your changes have been successfully made to the branch sweep/sweep_port_this_react_component_to_vue3. I have validated these changes using a syntax checker and a linter.


[!TIP] To recreate the pull request, edit the issue title or description.

This is an automated message generated by Sweep AI.