Coder Social home page Coder Social logo

toss / slash Goto Github PK

View Code? Open in Web Editor NEW
2.6K 2.6K 292.0 271.74 MB

A collection of TypeScript/JavaScript packages to build high-quality web services.

Home Page: https://slash.page

License: MIT License

JavaScript 65.97% TypeScript 33.96% Shell 0.08%
javascript react toss typescript web

slash's People

Contributors

201411108 avatar airman5573 avatar anaclumos avatar artechventure avatar changyoungoh avatar collection50 avatar d0422 avatar euijinkk avatar evan-moon avatar fronttigger avatar frorong avatar gaic4o avatar greatsumini avatar guesung avatar hhhminme avatar hoseungme avatar jayeha avatar manudeli avatar mass2527 avatar minsoo-web avatar okinawaa avatar po4tion avatar raon0211 avatar rjsdnql123 avatar ryan-dia avatar saul-atomrigs avatar seokju-na avatar seokkamoni avatar ssi02014 avatar youngjae99 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

slash's Issues

[Feature]: Is it useful to take out the `useKey` hook separately?

Package Scope

  • Add to an existing package
  • New package

Package name: @toss/react

Overview

Please see follow hooks

useResetError
useKey

I think these hooks are exactly same hook and there purpose for their own Component hook.
useKey is useful for user who use key (typed for number) and reseting that key (by increasing), But I doubt that this hook will be used often.

So, Is it useful to take out the useKey hook separately?

Describe the solution you'd like

In my opinion, rather than managing the same hook as a local file in multiple packages, it is more useful in terms of management to bring dependencies and use them.

But I doubt that this hook will be used often... 🤔

Additional context

[Feature]: Add emotion position function types

Package Scope

  • Add to an existing package
  • New package

Package name: react/emotion-utils

Overview

I want to like code like this position({top:10,bottom:8})
But position function did not support this type.

Describe the solution you'd like

I want to add this code.

export function position(coordinates: Coordinates): SerializedStyles;`

  const [top, right, bottom, left] = (() => {
    // position(coordinates)
    if (typeof positionOrTopOrCoordinates === 'object') {
      return [
        positionOrTopOrCoordinates.top,
        positionOrTopOrCoordinates.right,
        positionOrTopOrCoordinates.bottom,
        positionOrTopOrCoordinates.left,
      ];
    }

and test code

  it('position({top: 0, left: 0})', () => {
    const { getByTestId } = render(<div data-testid="test" css={position({ top: 0, left: 0 })} />);

    const el = getByTestId('test');

    expect(el).toBeInTheDocument();

    expect(el).toHaveStyleRule('top', '0');
    expect(el).not.toHaveStyleRule('bottom', '0');
    expect(el).not.toHaveStyleRule('right', '0');
    expect(el).toHaveStyleRule('left', '0');
  });

Additional context

I think toss team may not agree my opinion. So I open an issue, not pr. Thank you

[Feature]: How about add `indexBy` function

Package Scope

  • Add to an existing package
  • New package

Package name: @toss/utils

Overview

A function that indexes an array of objects based on a specific key value. It is a function that makes the object a key and value pair , which makes the cost of find specific data in the future cheaper.

const foo = [
  { id: 1, name: 'park', age: 23 },
  { id: 3, name: 'kim', age: 21 },
  { id: 5, name: 'lee', age: 24 },
];

// normal approach
const result = foo.find(item => item.name === "park") // Tour all items.
const result = foo.find(item => item.name === "kim") // Tour all items.
const result = foo.find(item => item.name === "lee") // Tour all items.

// new indexBy function

const indexedObj = indexBy(foo, "name") // Tour just one tiem
const result = indexedObj["kim"] // quick search
const result = indexedObj["lee"] // quick search
const result = indexedObj["park"] // quick search

If indexed, it is a performance-friendly situation because it can be found immediately without looking for values while traveling all list.
These functions are good for those situations when they can be found quickly and easily after a just one traveling.

Describe the solution you'd like

type ElementType<T extends unknown[]> = T[number];

const indexBy = <ArrayObjectType extends Array<Record<PropertyKey, unknown>>, IndexType extends keyof ElementType<ArrayObjectType>>(
  arrayObj:ArrayObjectType, key:IndexType
) => {

  return arrayObj.reduce((acc, obj) => {
    acc[obj[key]] = obj;
     return acc
     }, {} as any);
}

Additional context

If the developer uses a key which have value that is other than a Property Key, it should be treated well.

[Feature]: FullHeight container's element could be other than just div

Package Scope

  • Add to an existing package
  • New package

Package name: @toss/emotion-utils

Overview

// FullHeight.tsx

export function FullHeight({ children, ...props }: { children: ReactNode } & HTMLAttributes<HTMLDivElement>) {

  return (
    <div> // why only div tag?
      {children}
    </div>
  );
}

If you look at the current implementation of FullHeight, it is fixed and wrapped with a div container.

However, in actual development, it is often necessary to semantically use section or main and other elements instead of div containers. In that case, it is inconvenient to use FullHeight.

I think it would be good to have better scalability!

Describe the solution you'd like

like OpenGraph

interface Props {
  container?: ComponentType<any>; // accept other tag
}

Additional context

[Feature]:특정한 overlay만 열고 닫는 방법이 있을까요?

Package Scope

  • Add to an existing package
  • New package

Package name:

Overview

Describe the solution you'd like

id값이 자동으로 생성되고 export되지 않아서 오버레이가 사용된 컴포넌트에서만 열고 닫을 수 있는 것 같은데
혹시 다른 컴포넌트에서 특정한 오버레이를 열고 다는 방법이 있을까요?

Additional context

[Feature]: Add isDefined

Package Scope

  • Add to an existing package (@toss/utils)
  • [] New package

Overview

It declaratively returns the defined value, and returns false if the value is not defined(undefined, null). The main function of isDefined is to track undefined value, and is also useful for declaratively filtering array whice elements are objects.

itemList = [
    {id: 1, isValid: true},
    {isValid: false},
    {isValid: false},
    {id: 4, isValid: true},
  ]
  
itemList.map(item => item.id).filter(isDefined)

Describe the solution you'd like

function isDefined<T>(argument: T | undefined | null): argument is T {
  return argument !== undefined && argument !== null;
}

[Feature]: How about change AsyncBoundaryProvider(@toss/async-boundary) to ResetErrorBoundaryProvider(@toss/error-boundary)?

How about change AsyncBoundaryProvider(@toss/async-boundary) to ResetErrorBoundaryProvider(@toss/error-boundary)?

Package Scope

async-boundary, error-boundary

  • Add to an existing package

Overview

Current AsyncBoundaryProvider is not scoped AsyncBoundary, I think it is just designed only for reseting resetKey ErrorBoundary

AS-IS: AsyncBoundaryProvider(@toss/async-boundary)

interface AsyncBoundaryProvider {
  resetKey: number;
  reset(): void;
}

const AsyncBoundaryContext = createContext<AsyncBoundaryProvider | null>(null);

interface Props {
  children: ReactNode;
}

export function AsyncBoundaryProvider({ children }: Props) {
  const [resetKey, reset] = useResetError();

  return <AsyncBoundaryContext.Provider value={{ resetKey, reset }}>{children}</AsyncBoundaryContext.Provider>;
}

export function useAsyncBoundaryContext() {
  return useContext(AsyncBoundaryContext) ?? { resetKey: null, reset: () => {} };
}

Describe the solution you'd like

If I can edit, I want to change AsyncBoundaryProvider to ResetErrorBoundaryProvider

TO-BE: ResetErrorBoundaryProvider(@toss/error-boundary)

const ResetErrorBoundaryContext = createContext({
  resetKey: 0,
  reset: () => {},
});
if (process.env.NODE_ENV !== 'production') {
  ResetErrorBoundaryContext.displayName = 'ResetErrorBoundaryContext';
}

interface Props {
  children: ReactNode;
}

export function ResetErrorBoundaryProvider({ children }: Props) {
  const [resetKey, reset] = useResetError();

  return <ResetErrorBoundaryContext.Provider value={{ resetKey, reset }}>{children}</ResetErrorBoundaryContext.Provider>;
}

export function useResetErrorBoundaryContext() {
  return useContext(ResetErrorBoundaryContext);
}

Additional context

1. More intuitive return type of useContext

AS-IS(ReturnType<typeof useAsyncBoundaryContext>)

union type is not intuitive.

import { expectType } from 'tsd';
expectType<AsyncBoundaryProvider | { resetKey: number; reset(): void; }>(useAsyncBoundaryContext()) // not intuitive, not essential union type 

image

TO-BE(ReturnType<typeof useResetErrorBoundaryContext>)

infer just one type like below picture

import { expectType } from 'tsd';
expectType<{ resetKey: number; reset(): void; }>(useResetErrorBoundaryContext()) // intuitive, just essential type 

image

2. add displayName Context only on development mode

we can check displayName, ResetErrorBoundaryContext.Provider on react-devtools only for development mode

const ResetErrorBoundaryContext = createContext({
  resetKey: 0,
  reset: () => {},
});
if (process.env.NODE_ENV !== 'production') {
  ResetErrorBoundaryContext.displayName = 'ResetErrorBoundaryContext';
}

3. How about ResetErrorBoundaryProvider.children can use reset easily like this

If I can't use useContext, for example in Class Component or HTML like button or div, It will be helpful

ResetErrorBoundaryProvider

export function ResetErrorBoundaryProvider({ children: Children }: Props) {
  const [resetKey, reset] = useResetError();

  const node = typeof Children === 'function' ? <Children reset={reset} /> : Children;

  return <ResetErrorBoundaryContext.Provider value={{ resetKey, reset }}>{node}</ResetErrorBoundaryContext.Provider>;
}

Use Case

<ResetErrorBoundaryProvider>
  {({ reset }) => (
	<button onClick={reset} /*  <-- error reset 해야 하는 부분 */ />
	<AsyncBoundary /* <-- suspense + error boundary로 감싸져야 하는 부분 */
	    pendingFallback={<TableSkeleton title="상세내역" row={10} />}
	    errorFallback={({ error, reset }) => (
	      <ErrorAlert theme="yellow" error={error} message="다시 시도해주세요." onResetError={reset} />
	    )}
	>
      <DataViewer />
    </AsyncBoundary>
  )}
</ResetErrorBoundaryProvider>

Can I change AsyncBoundaryProvider like this? this will be BREAKING CHANGE, so I want to check it before starting code

[BUG]: clamp returns wrong value

Package Scope

Package name: @toss/utils

Describe the bug

In docs example, clamp(3, 5) returns 5, but the actual return value is 3.
If this is not a bug, please change the docs not to be confused!

Expected behavior

Return value of clamp(3, 5) to be 5

Possible Solution

Change clamp.ts to

 if (bound2 == null) {
    return Math.max(value, bound1);
  }

[BUG]: commaize not working in RN Android

Package Scope

Package name: @toss/[email protected]

Describe the bug

commaizeNumber didn't work at Android which written by RN.

The function returns String(value).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') when input argument value's type is string, but, it's weired that convert string type variants to string.

Expected behavior

Here is my code.

const SOME_NUMBER = 1000000;

return (
    <Text>{commaizeNumber(SOME_NUMBER}/<Text>
);

I expected it works as same in Android and iOS, but it didn't work at Android.

  • iOS case
    iOS

  • Android case

Android

It works when I change code above like below.

const SOME_NUMBER = 1000000;

return (
    <Text>{commaizeNumber(String(SOME_NUMBER)}/<Text>
);

To Reproduce

Change commaizeNumber functions as below. Delete unnecessary type conversion. Converting value only when value type is number.

export function commaizeNumber(value: string | number) {
  if (typeof value === 'number') {
    return String(value).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,');
  }

  return value.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,');
}

Possible Solution

I made PR to solve this issue #104 .

Additional context

[BUG]: @toss/use-overlay change inner state of `CreateOverlayElement`'s JSX.Element

Package Scope

Package name: @toss/use-overlay

Describe the bug

If I use the open method in overlay to open overlay, the states used in the open method are remembered as the values at the time when the open method is called.
Even if the state is newly updated, overlaied component do not know the newly updated state. I think it's a closure problem, can we solve it?

Expected behavior

Allows the changed states outside of the overlaid component to be immediately reflected in the overlaid component.

To Reproduce

you can play this code sand box

import { useOverlay } from "@toss/use-overlay";
import { Dispatch, PropsWithChildren, SetStateAction, useState } from "react";
import "./styles.css";

const Dialog = ({
  caution,
  children
}: PropsWithChildren<{ caution: string }>) => {
  return (
    <div
      style={{
        width: "400px",
        height: "400px",
        backgroundColor: "blue",
        borderRadius: "8px",
        color: "red",
        margin: "30px",
        padding: "30px"
      }}
    >
      {children}
      this is {caution} // this is not updated when click button
    </div>
  );
};

const CustomDialog = ({
  setCaution
}: {
  setCaution: Dispatch<SetStateAction<string>>;
}) => {
  return (
    <button onClick={() => setCaution(new Date().toString())}>
      CLICK TO CHANGE CAUTION
    </button>
  );
};

export default function App() {
  const [caution, setCaution] = useState<string>("");
  const overlay = useOverlay();

  const onClickHandler = () => {
    overlay.open(() => (
      <Dialog caution={caution}>
        <CustomDialog setCaution={setCaution} />
      </Dialog>
    ));
  };

  return (
    <>
      <button
        onClick={onClickHandler}
        style={{
          width: "200px",
          height: "80px",
          backgroundColor: "white",
          borderRadius: "4px"
        }}
      >
        OPEN MODAL
      </button>
    </>
  );
}

Possible Solution

Additional context

[Feature]: useUnmountEffect

Package Scope

  • Add to an existing package (@toss/react)
  • New package

Overview

Declaratively enable unmounting behavior by handing over the callback that you want to cause when the component is unmounted.

Usually, I want a specific function to work when component is unmounted, but it was inconvenient.

Describe the solution you'd like

function useUnmoundEffect<F extends (...args: any[]) => void>(callback: F) {
  const preservedCallback = usePreservedCallback(callback);

  useEffect(() => {
    return () => preservedCallback();
  }, [preservedCallback]);
}

[BUG]: useStorageState hook type error

Package Scope

Package name: @toss/react

Describe the bug

tl;dr

  • In the example of useStorageState, a type error occurs. This is because defaultValue is inferred as a literal type rather than a primitive type.
  • I tried to infer the type of defaultValue without writing a generic in useStorageState, but I couldn't find a way. Please advise if there is any other way
  • If there is no other way, I will add a phrase to the document that a generic must be created if the defaultValue is a primitive type (string, boolean, number).

This is an issue about a type error occurring in the useStorageState hook.

If you try to use the example in the document of useStorageState hook as it is, the following type error occurs.

function MyComponent() {
  const [state, setState, refresh] = useStorageState('@service/some-resource', {
    defaultValue: 0,
  });

  useEffect(() => {
    setState(x => x + 1);
    // ^ type error
  }, []);

  ...
}

type-error

However, if you write a generic, type errors do not occur:

const [state, setState, refresh] = useStorageState<number>('@service/some-resource', {
  defaultValue: 0,
});

useEffect(() => {
  // No error
  setState((x) => x + 1);
}, [setState]);

I confirmed that the state among the return values of useStorageState in the example above is not inferred as number, but as literal type 0. In addition, even when the defaultValue is a primitive type such as boolean or string, it is inferred only as a literal type:

  // const state1: true
  const [state1, setState1, refresh1] = useStorageState('boolean', {
    defaultValue: true,
  });

  // const state2: "str"
  const [state2, setState2, refresh2] = useStorageState('string', {
    defaultValue: 'str',
  });

Here, I want to make type inference without writing generic like React.useState. However, because of the type constraint that prevents the symbol value from entering the devalutValue of the useStorageState argument, type inference is not possible as a primitive type like React.useState.

// const count: number
const [count, setCount] = useState(1);

// const state: number  ✅ What I want
// const state: 0  😢 Actually
const [state, setState, refresh] = useStorageState('number', {
  defaultValue: 0
})

In microsoft/TypeScript#10676, when inferring function arguments, type parameters are inferred as widened literal types only in the following situations:

During type argument inference for a call expression the type inferred for a type parameter T is widened to its widened literal type if:

  • all inferences for T were made to top-level occurrences of T within the particular parameter type, and
  • T has no constraint or its constraint does not include primitive or literal types, and
  • T was fixed during inference or T does not occur at top-level in the return type.

In other words, since the primitive type is included in the type constraint of useStorageState, the type inferred from the type parameter is a literal type:(Please check my playground)

export type Serializable<T> = T extends string | number | boolean | unknown[] | Record<string, unknown> ? T : never;

// useStorageState.ts
// A conditional type constraint contains a primitive type
export type Serializable<T> = T extends string | number | boolean | unknown[] | Record<string, unknown> ? T : never;
...

Therefore, I concluded that the type parameter T cannot be inferred as a primitive type (e.g. string, number or boolean) because of the type constraint for defaultValue in useStorageState. Is there any other way?

If there is no other way, it seems that the phrase that a generic must be created when a primitive type enters the defaultValue should be added to the official document.

Please give me some advice on the issue and I'll fix the documentation.

Expected behavior

To Reproduce

Possible Solution

Additional context

[BUG]: useless field in package.json

Package Scope

Package name: all package

Describe the bug

{
  "name": "@toss/assert",
  "version": "1.0.4",
  "sideEffects": false,
  "exports": {
    ".": {
      "require": "./src/index.ts",
      "import": "./src/index.ts"
    },
    "./package.json": "./package.json"
  },
  "main": "src/index.ts",
  "scripts": {
  },
  "dependencies": {
    "@toss/utils": "workspace:^1.0.4"
  },
  "devDependencies": {
    "typescript": "4.8.3"
  },
  "publishConfig": {
    "access": "public",
    "exports": {
      ".": {
        "require": "./dist/index.js",
        "import": "./esm/index.mjs",
        "types": "./dist/index.d.ts"
      },
      "./package.json": "./package.json"
    },
    "import": "./esm/index.mjs", // here
    "main": "dist/index.js",
    "module": "./esm/index.mjs",
    "types": "dist/index.d.ts"
  },
  "gitHead": "..."
}

I think "import": "./esm/index.mjs", field is not official field, and not used in anywhere.

I checked this in node and npm. But I couldn't find any explanation about the field.

It seems that even webpack and rollup are not using "import" field of package.json.

What's the purpose of the "import" field ?

Check please :D

[BUG] useQueryParam is not safe typely, runtimely

related #241

I have reviewed but I still think this change is not appropriate. Regardless of the intention of useQueryParam, someone may have already used it like:

const productIds = useQueryParam<string[]>('productIds');
const parsedProductIds = productIds.map((id) => parseInt(id));

I understand that you want to contribute, but It would be better to keep the previous implementation.

Even in this case, there is an error when used with parser.
If url is https://example.com?productIds=1&productIds=2

const productIds = useQueryParam<string[]>('productIds', {
  parser: (productIds) => { // productIds will be ["1", "2"], but typely this is string... then, what role is parser?
    /* we can't use productIds.map((id) => parseInt(id)) */
  }
});

You can see example typely invalid example or runtimely invalid example

typely invalid (https://example.com?productIds=1&productIds=2)

image

runtimely invalid (https://example.com?productIds=1&productIds=2)

image

Even though there are clearly edge cases in the code, It is difficult to understand why Pull Requests or other code suggestion cannot be accepted only because it is a BREAKING CHANGE. So what is BREAKING CHANGE for and why do other libraries do major bumps? If necessary, I think we should proceed with a BREAKING CHANGE.

Originally posted by @manudeli in #241 (comment)

[Question] why isServer should check `global`?

export function isServer() {
return typeof window === 'undefined' && typeof global !== 'undefined';
}

We reuse isServer many times in slash libraries, but I don't know why we should check global in isServer. could I get slash's intention why check not only window also global please?

No global checking libraries

We can see no global checking in below links

[BUG]: useOutsideClickEffect does not behave like a document

Package Scope

Package name: @toss/react

Describe the bug

useOutsideClickEffect does not behave like a document

useOutsideClickEffect Document

Example 1

const ref = useRef<HTMLElement>(null);

// doesn't work 
useOutsideClickEffect(ref, () => {
  console.log('outside clicked!');
});
스크린샷 2023-07-20 오전 8 41 33 스크린샷 2023-07-19 오후 10 45 54

Expected behavior

The useOutsideClickEffect function operates by receiving the return value RefObject of useRef

const ref = useRef<HTMLElement>(null);

// work!
useOutsideClickEffect(ref, () => {
  console.log('outside clicked!');
});

To Reproduce

"react": "^18.2.0",

Only the code generated by CRA, App.tsx, has been modified as follows

import { useRef } from "react";
import { useOutsideClickEffect } from "@toss/react";

function App() {
  const ref = useRef<HTMLDivElement>(null);

  useOutsideClickEffect(ref, () => {
    console.log("hello");
  });

  return (
    <div className="App">
      <h1 ref={ref}>hello</h1>
    </div>
  );
}

export default App;

Possible Solution

useOutsideClickEffect parameter 'container' should be as follows.

AS-IS
useOutsideClickEffect(container: OneOrMore<HTMLElement | null>, callback: () => void)

TO-BE
useOutsideClickEffect(container: OneOrMore<React.RefObject<HTMLElement> | null>, callback: () => void)

Additional context

[Feature]: reverseKeyValue when object has multiple value.

Package Scope

  • Add to an existing package
  • New package

Package name: @toss/utils reverseKeyValue

Overview

below is always correct

expect(reverseKeyValue({ jbee: 'eebj' })).toEqual({ eebj: 'jbee' });

but how about this object which is multiple same value

reverseKeyValue({ jbee: 'eebj',jbee2:'eebj' }) // { "eebj": "jbee2"} 

It is not bug,, but people can make human error I think

Describe the solution you'd like

Why don't we put the same values together in an array?

reverseKeyValue({ jbee: 'eebj',jbee2:'eebj' }) // { "eebj": ["jbee","jbee2"]} 

Additional context

In the case above, please suggest if it can be handled in another good way👍

[BUG]: typedStorage import type error

Package Scope

Package name: @toss/storage

Describe the bug

TypedStorage is subpath exported module. You should use @toss/storage/typed to use it.

when I use that import statement type error occurs.
image

because there is no typed file in node_modules
image

Expected behavior

import { TypedStorage } from "@toss/storage/typed"; // should not occur type error

To Reproduce

I'm used classic yarn not yarn berry

link

Possible Solution

  1. Using TypeScript paths option: Update the TypeScript configuration file (tsconfig.json) with the paths option to redirect module paths. By mapping @toss/storage/typed to @toss/storage/dist/typed, you can resolve the type error. Here's an example:
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@toss/storage/typed": ["./node_modules/@toss/storage/dist/typed"]
    }
  }
}

but it is not good for DX
every project it should be considered

  1. Directly move or copy files: Move or copy the contents of @toss/storage/typed to @toss/storage/dist/typed directly. By doing this, you can keep the import statement as it is without modifying it, and the type error should be resolved.

Additional context

[Feature]: useDeviceInfo

Package Scope

  • New package

Package name: useDeviceInfo

Overview

WebView를 사용하거나 모바일, PC 모두 대응할때,
사용자의 기기가 PC, Mobile(IOS/AOS)인지 확인하기 위한 커스텀 훅 입니다.

util에 getOSByUserAgent, isMobileWeb 등이 있으나 분리되어 있어 통합하기 위해 만들었습니다.

[Feature]: Why needed two RegExp in the get function?

Package Scope

  • Add to an existing package
  • New package

Package name: @toss/utils

Overview

current get function uses about two RegExp(/[,[\]]+?/, /[,[\].]+?/).

export const get = <T = any>(obj: Record<string, any>, path: string, defaultValue?: T): T => {
  // ...
  const result = travel(/[,[\]]+?/) || travel(/[,[\].]+?/);
  // ...
};

Describe the solution you'd like

I think the second RegExp can sufficiently replace the first RegExp like below.

export const get = <T = any>(obj: Record<string, any>, path: string, defaultValue?: T): T => {
  // ...
  const result = travel(/[,[\].]+?/);
  // ...
};

Additional context

If you need it because of another edge case that I don't know, could you let me know?

[BUG]: @toss/lottie stopOnExit not work

Package Scope

Package name: @toss/lottie

Describe the bug

A props called stopOnExit is only received, and the corresponding processing is not taking place in the function at all.

Expected behavior

It seems that the stopOnExit will disappear, or it will have to be implemented according to actual behavior.

To Reproduce

Even if you set this value, it will not actually be reflected.

Possible Solution

Additional context

image

image

but in docs stopOnExit is described like this

// 애니메이션이 화면 바깥으로 나갔을 때 애니메이션 재생을 잠시 일시정지하는지 여부

[Feature]: common > utils > clamp error case

Package Scope

  • Add to an existing package
  • New package

Package name: @toss/utils

Overview

In clamp.ts

Currently, the function is only supposed to work if bound1 is less than bound2. If user unaware of this rule and can put a larger value in bound1 than bound2. In that case, this function will not function normally. For example, if value=3, bound1=10, bound2=1, the return value must be 3, but the error results in 1.

Describe the solution you'd like

i think this code works well if you agree I will make Pull request

export function clamp(value: number, bound1: number, bound2?: number) {
  if (bound2 == null) {
    return Math.min(value, bound1);
  }

  if (bound1 > bound2) {
    return Math.min(Math.max(value, bound2), bound1);
  }

  return Math.min(Math.max(value, bound1), bound2);
}

Additional context

[Feature]: @toss/use-funnel 의 NextJS 13 app directory 지원

Package Scope

  • Add to an existing package

Package name: @toss/use-funnel

Overview

내부적으로 next/router에 의존하고 있어, next/navigation으로 마이그레이션이 필요한 App Directory 버전에서는 @toss/use-funnl 의 기능을 사용할 수 없습니다.

참고자료1 : https://stackoverflow.com/questions/74421327/nextrouter-was-not-mounted-next-js
참고자료2: https://nextjs.org/docs/messages/next-router-not-mounted

Describe the solution you'd like

appdirectory 경로에서 App Directory 호환 버전을 불러올 수 있도록 합니다.

[BUG]: Current, Many packages after build can contain unnecessary **.test.d.ts.

Package Scope

Package name: all

Describe the bug

Currently, Many packages (for example, @toss/emotion-utils) after build can contain unnecessary **.test.d.ts in dist directory like below picture.
image

or if other case that don't contain **.test.d.ts, test.ts / test.tsx file, thery are excluded by tsconfig.json.
but, every contributors can encounter this error like below picture. (for example @toss/error-boundary)
image

Expected behavior

exclude ["**/jest.setup.ts", "**/*.test.*", "**/*.spec.*", "**/*.stories.*", "**/__storybook__/*"] only for build.
include ["**/jest.setup.ts", "**/*.test.*", "**/*.spec.*", "**/*.stories.*", "**/__storybook__/*"] during anyone developing.

Possible Solution

During adding test after this #157 (comment) , I met this problem.
after using little time to solve this problem, first time, I thought there's no configuration to test dom. but it isn't. ;(

Just, It's about excluded test file by tsconfig.json like below.

{
  "extends": "./tsconfig.json",
  "exclude": ["**/jest.setup.ts", "**/*.test.*", "**/*.spec.*", "**/*.stories.*", "**/__storybook__/*"]
}

so, I could solve this bug by this solution: I added Solution Details below

Solution Details

  1. use tsc -p tsconfig.build.json. only when yarn build.
  2. use tsconfig.json don't exclude ["**/jest.setup.ts", "**/*.test.*", "**/*.spec.*", "**/*.stories.*", "**/__storybook__/*"] when developing.

How about adopt this solution in every packages? or Is there other way to solve this problem?

[Feature]: update useBooleanState return value Array to Object

Package Scope

  • Add to an existing package
  • New package

Package name: @toss/react

Overview

I think is more convenient return value is Object not array

Situations

Array return value is up to user remember what position it is

// In this case developer stop coding, and check docs for 
// where is it (such as where is the value, and where is the toggle function)
const [] = useBooleanState()

Array return value is inconvenient for using specific return value

// developer who wants to taking boolean value and toggle function
const [bool, _, _, toggle] = useBooleanState()

Describe the solution you'd like

I Propose change the return value array to Object value

for example (for user interface)

const { value, toggle } = useBooleanState()

reference - @chakra-ui/useDisClosure

[Feature]: ImpressionArea has Circular reference

Package Scope

  • Add to an existing package
  • New package

Package name: @toss/impression-area

Overview

A circular reference occurs between ImpressionArea and useImpressionRef.

Describe the solution you'd like

How about defining ImpressionAreaProps in useImpressionRef?

Additional context

[Feature]: How about return exit function in `useOverlay` hook

Package Scope

  • Add to an existing package

Package name: @toss/use-overlay

Overview

Currently, if I am using useOverlay, I can control isOpen to false through the close function, but if I want to unmount the overlay using return value of the useOverlay, the interface does not exist. how about make exit function to developer use that function to unmount overlay?

Describe the solution you'd like

AS-IS

 return useMemo(
    () => ({
      open: (overlayElement: CreateOverlayElement) => {
        mount(
          id,
          <OverlayController
            key={id}
            ref={overlayRef}
            overlayElement={overlayElement}
            onExit={() => {
              unmount(id);
            }}
          />
        );
      },
      close: () => {
        overlayRef.current?.close();
      }
    }),
    [id, mount, unmount]
  );

TO-BE

 return useMemo(
    () => ({
      open: (overlayElement: CreateOverlayElement) => {
        mount(
          id,
          <OverlayController
            key={id}
            ref={overlayRef}
            overlayElement={overlayElement}
            onExit={() => {
              unmount(id);
            }}
          />
        );
      },
      close: () => {
        overlayRef.current?.close();
      },
      exit: () => {
        unmount(id);
      },
    }),
    [id, mount, unmount]
  );

Usage

function App() {
  const overlay = useOverlay();
  
  const openFooConfirmDialog = () => {
    overlay.open(({ isOpen, close, exit }) => (
      <FooConfirmDialog
        open={isOpen}
        onClose={() => {
          close();
        }}
        onConfirm={() => {
          exit();
        }}
      />
    ));
  };

  return (
    <div>
      <button onClick={overlay.close}>just set isOpen to false</button>
      <button onClick={overlay.exit}>unmount</button> // you can use like this to unmount overlay
    </div>
  );
}

[Feature]: Suggestion to add test code when using '이에/에' option in `josa` function

Package Scope

  • Add to an existing package
  • New package

Package name: @toss/hangul josa

Overview

Hello there.
First of all, I've been using the useful hangul functions created by Toss, and I'd like to thank you for providing them.

I have been using the josa function, but I have noticed that the use of the '이에/에' option is a bit ambiguous.
So I read the spec file, but it was missing a test case for that option.

The reason I can't find a use case for this option is probably due to my poor Korean skills, but if proper test cases are added, people like me can easily understand the use case.

Describe the solution you'd like

Add a test case for the '이에/에' option to the test code of the josa function.

Additional context

-

[Feature]: Support interactive playground in docs(https://slash.page) by adding codesandbox

Package Scope

If slash.page can provide more interactive playground in docs for who want to learn @toss/slash, more users will dive deeply to learn these libraries easily.

And It will make users better to understand what problem each libraries solved.

  • Add to an existing package
  • New package

Package name: docs

Overview

Describe the solution you'd like

Add codesandbox like https://beta.reactjs.org

New version of React docs keynote, YouTube video

Additional context

[BUG]: `onClick` issue @ `ClickArea`

Package Scope

Package name: @toss/react

Describe the bug

When enabled was false, onClick event in ClickArea isn't disabled

Expected behavior

Now State: enabled option in ClickArea is false

Expected: onClick function have been not called
Actual: onClick function have been called

To Reproduce

  1. Go to CodeSandbox from Slash Page
  2. Change enabled to false from true.
  3. Click the component.

Possible Solution

I made PR to solve this issue #174.

Additional context

missing @description in zip function

문서에서 zip 함수에 대한 설명이 누락된 것을 확인했습니다.

image

/**
 * @name zip
 * Array의 zip 연산을 수행합니다.
 * @example
 * zip([1, 2], ['a', 'b']) --> [[1, 'a'], [2, 'b']]
 */

missing typescript syntax highlighting in code block

docs를 보며 code block의 몇가지 문제점을 발견했습니다.

  1. typescript syntax highlighting이 빠져있습니다
'''[typescript 부재]
function isRRN() {}
'''
  1. 몇몇 닫혀있지 않는 코드블럭이 있습니다
'''typescript
function isRRN() {}

[BUG]: Is it correct ReturnType<useSuspendedQuery> at options {enabled:boolean}?

Package Scope

Package name: @toss/react-query

Is it correct ReturnType at options {enabled:boolean}?

Current

const Component = () => {
  const boolean = !!(Math.random() > 0.5)

  const query = useSuspendedQuery(
    ["example"] as const,
    async () => {
      return "response" as const
    },
    { enabled: boolean }
  )

  console.log(query.data) // BaseSuspendedUseQueryResult<"response" | undefined>.data: "response" | undefined

  if (query.isSuccess) {
      console.log(query.data) // BaseSuspendedUseQueryResult<"response" | undefined>.data: "response" | undefined
  }

  return ...
}

Expected

const Component = () => {
  const boolean = !!(Math.random() > 0.5)

  const query = useSuspendedQuery(
    ["example"] as const,
    async () => {
      return "response" as const
    },
    { enabled: boolean }
  )

  console.log(query.data) // BaseSuspendedUseQueryResult<"response" | undefined>.data: "response" | undefined

  if (query.isSuccess) {
      console.log(query.data) // BaseSuspendedUseQueryResult<"response">.data: "response"
  }

  return ...
}

Describe the solution you'd like

Current

export declare function useSuspendedQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(queryKey: TQueryKey, queryFn: QueryFunction<TQueryFnData, TQueryKey>, options?: Omit<SuspendedUseQueryOptions<TQueryFnData, TError, TData, TQueryKey>, 'enabled'>): SuspendedUseQueryResultOnSuccess<TData>;
export declare function useSuspendedQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(queryKey: TQueryKey, queryFn: QueryFunction<TQueryFnData, TQueryKey>, options: Omit<SuspendedUseQueryOptions<TQueryFnData, TError, TData, TQueryKey>, 'enabled'> & {
    enabled?: true;
}): SuspendedUseQueryResultOnSuccess<TData>;
export declare function useSuspendedQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(queryKey: TQueryKey, queryFn: QueryFunction<TQueryFnData, TQueryKey>, options: Omit<SuspendedUseQueryOptions<TQueryFnData, TError, TData, TQueryKey>, 'enabled'> & {
    enabled: false;
}): SuspendedUseQueryResultOnIdle<undefined>
export declare function useSuspendedQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(queryKey: TQueryKey, queryFn: QueryFunction<TQueryFnData, TQueryKey>, options: SuspendedUseQueryOptions<TQueryFnData, TError, TData, TQueryKey>): BaseSuspendedUseQueryResult<TData | undefined>;

Expected

export declare function useSuspendedQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(queryKey: TQueryKey, queryFn: QueryFunction<TQueryFnData, TQueryKey>, options?: Omit<SuspendedUseQueryOptions<TQueryFnData, TError, TData, TQueryKey>, 'enabled'>): SuspendedUseQueryResultOnSuccess<TData>;
export declare function useSuspendedQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(queryKey: TQueryKey, queryFn: QueryFunction<TQueryFnData, TQueryKey>, options: Omit<SuspendedUseQueryOptions<TQueryFnData, TError, TData, TQueryKey>, 'enabled'> & {
    enabled?: true;
}): SuspendedUseQueryResultOnSuccess<TData>;
export declare function useSuspendedQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(queryKey: TQueryKey, queryFn: QueryFunction<TQueryFnData, TQueryKey>, options: Omit<SuspendedUseQueryOptions<TQueryFnData, TError, TData, TQueryKey>, 'enabled'> & {
    enabled: false;
}): SuspendedUseQueryResultOnIdle<undefined>
export declare function useSuspendedQuery<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(queryKey: TQueryKey, queryFn: QueryFunction<TQueryFnData, TQueryKey>, options: SuspendedUseQueryOptions<TQueryFnData, TError, TData, TQueryKey>): SuspendedUseQueryResultOnSuccess<TData> | SuspendedUseQueryResultOnIdle<undefined>;

wrong conditional export for esm in some repo.

First, Thanks to release this repo 👍

Steps to Reproduce

  1. I created sample react app using vite(using "type": "module" in package.json).
  2. I installed @toss/[email protected].
  3. added simple code with <ImpressionArea>
import "./App.css";
import { ImpressionArea } from "@toss/impression-area";

function App() {
  return (
    <div className="App">
      <ImpressionArea onImpressionStart={() => console.log("start")}>
        <div className="DummyBox" />
      </ImpressionArea>
    </div>
  );
}

export default App;
  1. and occured following issue.

issue

cannot resolve modules

image

and I found wrong esm export path in dependencies modules package.json

  • wrong path: ./esm/index.js
  • real path : ./esm/index.mjs

image
image

so, to avoid the error, I tried to something:

- "module": "./esm/index.js",
+ "module": "./esm/index.mjs", 

- "import": "./esm/index.js"
+ "import": "./esm/index.mjs"
  • @toss/impression-area/package.json
  • @toss/use-ref-effect/package.json
  • @toss/use-ref-effect/node_modules/@toss/use-preserved-callback/package.json

after fixed, works well.

image

And lastly, I think it would be a good idea to check it all over again.

Once again, Really appreciate release this repo. 😄

[BUG]: `@toss/utils`의 `commaizeNumber` 함수 에러

Package Scope

Package name: @toss/utils v1.0.4

Describe the bug

토스에러

16자리 수 넘는 순간부터 제대로 컴마가 찍히지 않는 것 같아요

Expected behavior

console.log(commaizeNumber(1234123412341234)); // 1,234,123,412,341,234
console.log(commaizeNumber(12341234123412341)); // 12,341,234,123,412,341
console.log(commaizeNumber(123412341234123412)); // 123,412,341,234,123,412
console.log(commaizeNumber(1234123412341234123)); // 1,234,123,412,341,234,123
console.log(commaizeNumber(12341234123412341234)); // 12,341,234,123,412,341,234

To Reproduce

  1. install @toss/utils
  2. Use commaizeNumber
  3. Run

Possible Solution

Additional context

[Feature]: @toss/use-funnel Idea Proposal for supporting App DIrectory(Nextjs13)

Package Scope

  • Add to an existing package
  • New package

Package name:@toss/use-funnel

Overview

Idea Proposal for Supporting the 'App' Directory in Next.js 13(It is Linked issue #228)

Describe the solution you'd like

I have attempted to make @toss/use-funnel support the Next.js's App directory.

Currently, @toss/use-funnel does not provide full support for Next.js@^13. The reason is that it does not support the App directory.

This is seem to Next.js's App directory supports routing using the AppRouter provided by next/navigation, while the Pages directory uses next/router for routing.

Initially, I thought that to enable support for the App directory of Next.js 13 in @toss/use-funnel, it might be possible to receive the useRouter hook from an external source and return the Router object. Although there were slight differences in the signatures of the push and replace methods between the two Router objects, the existence of these methods seemed to make this approach possible.

During the process of testing this approach, I discovered that the useRouter provided through next/navigation returns an AppRouterInstance that doesn't align adequately with the existing NextRouter object from next/router (notably lacking the query attribute). Furthermore, implementing this approach could lead to significant API changes and potentially impact @toss/use-query-param, which is used by @toss/use-funnel. Additionally, I couldn't find a way to inject a router object into the useRouter called within withState.

As an alternative, I propose creating a custom router package named @toss/useRouter. This approach could potentially allow both @toss/use-query-param and @toss/use-funnel to leverage a custom router, addressing these issues.

Another possible solution is temporarily segregating the implementation of useFunnel to specifically support the App directory.

Additional context

#228
next-router-not-mouted in App Dir

[BUG]: @tossteam/jest install error

Package Scope

Package name: @tossteam/jest

Describe the bug

When I clean yarn cache and I install package, error is occuried.

image

Expected behavior

I expected the installation to be successful.

To Reproduce

yarn cache clean

yarn

Possible Solution

I don't know where is @tossteam/jest package... is it private package ?

Additional context

In my opinion, thanks to zero-install, unless the user deletes the cache folder himself, it won't be reproduced, but I posted it because I'm curious.

[BUG]: @toss/date cannot be imported properly

Package Scope

Package name: @toss/date

Describe the bug

When trying to use utils from @toss/date package, it throws error below.

Module not found: Error: Can't resolve 'date-fns/locale/ko' in '/Users/chanmin/react-test/node_modules/@toss/date/esm'
Did you mean 'index.js'?
BREAKING CHANGE: The request 'date-fns/locale/ko' failed to resolve only because it was resolved as fully specified
(probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.
Add the extension to the request.

image

Expected behavior

@toss/date should be available without any tweak, but this package cannot be imported as expected.

To Reproduce

  1. install @toss/date
  2. Use any utils from @toss/date
  3. Run / Build fails.

Possible Solution

Add .js extension on date-fns locale import

AS-IS

// packages/common/date/src/date.ts

// eslint-disable-next-line import/no-duplicates
import { format as _format, isAfter, isBefore, isEqual, isValid } from 'date-fns';
import locale from 'date-fns/locale/ko';  // => This import statement should be changed (to explicitly provide extension)

TO-BE

// eslint-disable-next-line import/no-duplicates
import { format as _format, isAfter, isBefore, isEqual, isValid } from 'date-fns';
import locale from 'date-fns/locale/ko/index.js';

Additional context

Quotation

[Feature] tsd setup on @toss/react-query

    @manudeli 

I think you're right about seprating to next PR.

And yes, you can open an issue, and you can setup up tsd tests in whole monorepo.
But with bottom-up approach,
how about adopting tsd only in @tossteam/react-query first and do the whole thing later?

Originally posted by @changyoungoh in #73 (comment)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.