Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .eslintignore

This file was deleted.

3 changes: 0 additions & 3 deletions .eslintrc.cjs

This file was deleted.

3 changes: 0 additions & 3 deletions .prettierrc.cjs

This file was deleted.

17 changes: 17 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$schema": "http://json.schemastore.org/prettierrc",
"trailingComma": "es5",
"printWidth": 120,
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"endOfLine": "auto",
"overrides": [
{
"files": ["public/locales/*.json"],
"options": {
"tabWidth": 4
}
}
]
}
229 changes: 229 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
import js from '@eslint/js';
import typescriptEslint from '@typescript-eslint/eslint-plugin';
import typescriptParser from '@typescript-eslint/parser';
import pluginI18Next from 'eslint-plugin-i18next';
import pluginImport from 'eslint-plugin-import';
import pluginPath from 'eslint-plugin-path';
import pluginReact from 'eslint-plugin-react';
import pluginReactHooks from 'eslint-plugin-react-hooks';
import pluginReactRefresh from 'eslint-plugin-react-refresh';
import pluginSimpleImportSort from 'eslint-plugin-simple-import-sort';
import pluginStorybook from 'eslint-plugin-storybook';
import pluginUnusedImports from 'eslint-plugin-unused-imports';
import globals from 'globals';

export default [
js.configs.recommended,

{
languageOptions: {
parser: typescriptParser,
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
globals: {
...globals.browser,
...globals.node,
GlobalCompositeOperation: 'readonly',
RequestInit: 'readonly',
},
},

files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],

plugins: {
react: pluginReact,
'@typescript-eslint': typescriptEslint,
'react-hooks': pluginReactHooks,
import: pluginImport,
'unused-imports': pluginUnusedImports,
'simple-import-sort': pluginSimpleImportSort,
'react-refresh': pluginReactRefresh.configs.vite,
path: pluginPath,
i18next: pluginI18Next,
storybook: pluginStorybook,
},

rules: {
...typescriptEslint.configs.recommended.rules,
...pluginReact.configs.recommended.rules,
...pluginReact.configs['jsx-runtime'].rules,
...pluginReactHooks.configs.recommended.rules,
...pluginStorybook.configs.recommended.rules,

'react/jsx-no-bind': [
'error',
{
allowBind: true,
},
],

'react/jsx-curly-brace-presence': [
'error',
{
props: 'never',
children: 'never',
},
],

'react-hooks/exhaustive-deps': 'error',

curly: 'error',
'no-var': 'error',
'brace-style': 'error',
'prefer-template': 'error',
radix: 'error',
'space-before-blocks': 'error',
eqeqeq: 'error',
'one-var': ['error', 'never'],
'no-eval': 'error',
'no-extend-native': 'error',
'no-implied-eval': 'error',
'no-label-var': 'error',
'no-return-assign': 'error',
'no-sequences': 'error',
'no-template-curly-in-string': 'error',
'no-throw-literal': 'error',
'no-unmodified-loop-condition': 'error',
'import/no-duplicates': 'error',
'import/prefer-default-export': 'off',
'unused-imports/no-unused-imports': 'error',

'unused-imports/no-unused-vars': [
'error',
{
vars: 'all',
varsIgnorePattern: '^_',
args: 'after-used',
argsIgnorePattern: '^_',
},
],

'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
'@typescript-eslint/no-unused-vars': 'off',

'@typescript-eslint/ban-ts-comment': [
'error',
{
'ts-expect-error': 'allow-with-description',
'ts-ignore': true,
'ts-nocheck': true,
'ts-check': false,
minimumDescriptionLength: 10,
},
],

'@typescript-eslint/no-empty-interface': [
'error',
{
allowSingleExtends: true,
},
],

'@typescript-eslint/consistent-type-imports': [
'error',
{
prefer: 'type-imports',
fixStyle: 'separate-type-imports',
disallowTypeAnnotations: true,
},
],

'@typescript-eslint/no-import-type-side-effects': 'error',

'@typescript-eslint/consistent-type-assertions': [
'error',
{
assertionStyle: 'as',
},
],

'path/no-relative-imports': [
'error',
{
maxDepth: 0,
},
],

'no-console': 'warn',
'no-promise-executor-return': 'error',
'require-await': 'error',

'no-restricted-properties': [
'error',
{
object: 'crypto',
property: 'randomUUID',
message: 'Use of crypto.randomUUID is not allowed as it is not available in all browsers.',
},
{
object: 'navigator',
property: 'clipboard',
message:
'The Clipboard API is not available by default in Firefox. Use the `useClipboard` hook instead, which wraps clipboard access to prevent errors.',
},
],

// Typescript handles this for us: https://eslint.org/docs/latest/rules/no-redeclare#handled_by_typescript
'no-redeclare': 'off',

'no-restricted-imports': [
'error',
{
paths: [
{
name: 'lodash-es',
importNames: ['isEqual'],
message: 'Please use objectEquals from @observ33r/object-equals instead.',
},
{
name: 'lodash-es',
message: 'Please use es-toolkit instead.',
},
{
name: 'es-toolkit',
importNames: ['isEqual'],
message: 'Please use objectEquals from @observ33r/object-equals instead.',
},
{
name: 'zod/v3',
message: 'Import from zod instead.',
},
],
},
],
},

settings: {
react: {
version: 'detect',
},
},
},

{
files: ['**/*.stories.tsx'],
rules: {
'i18next/no-literal-string': 'off',
},
},

{
ignores: [
'**/dist/',
'**/static/',
'**/.husky/',
'**/node_modules/',
'**/patches/',
'**/stats.html',
'**/index.html',
'**/.yarn/',
'**/*.scss',
'.prettierrc.js',
'.storybook',
],
},
];
2 changes: 1 addition & 1 deletion lib/components/accordion/accordion-button.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { AccordionButtonProps as ChakraAccordionButtonProps, ComponentWithAs } from '@chakra-ui/react';
import { AccordionButton as ChakraAccordionButton, forwardRef } from '@chakra-ui/react';
import { truncate } from 'lodash-es';
import { truncate } from 'es-toolkit/compat';
import { useMemo } from 'react';

import { Spacer } from '../../chakra-re-exports';
Expand Down
2 changes: 1 addition & 1 deletion lib/components/alert-dialog/confirmation-alert-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const ConfirmationAlertDialog = typedMemo((props: ConfirmationAlertDialog
}, [acceptCallback, onClose]);

const handleCancel = useCallback(() => {
cancelCallback && cancelCallback();
cancelCallback?.();
onClose();
}, [cancelCallback, onClose]);

Expand Down
2 changes: 1 addition & 1 deletion lib/components/combobox/combobox.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Meta, StoryObj } from '@storybook/react';
import { omit } from 'lodash-es';
import { omit } from 'es-toolkit/compat';

import type { ComboboxProps } from './combobox';
import { Combobox } from './combobox';
Expand Down
2 changes: 1 addition & 1 deletion lib/components/combobox/combobox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type {
StylesConfig,
} from 'chakra-react-select';
import { Select as ChakraReactSelect } from 'chakra-react-select';
import { useEffect, useMemo } from 'react';
import React, { useEffect, useMemo } from 'react';
export type {} from 'react-select/base';

import type { SystemStyleObject } from '@chakra-ui/styled-system';
Expand Down
2 changes: 1 addition & 1 deletion lib/components/combobox/custom-menu-list.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { GroupBase, MenuListProps } from 'chakra-react-select';
import { chakraComponents } from 'chakra-react-select';
import { cloneDeep, merge } from 'lodash-es';
import { cloneDeep, merge } from 'es-toolkit/compat';
import type { UseOverlayScrollbarsParams } from 'overlayscrollbars-react';
import { useOverlayScrollbars } from 'overlayscrollbars-react';
import type { PropsWithChildren } from 'react';
Expand Down
8 changes: 4 additions & 4 deletions lib/components/context-menu/context-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
*/
import type { ChakraProps, MenuButtonProps, MenuProps, PortalProps } from '@chakra-ui/react';
import { useDisclosure, useEventListener } from '@chakra-ui/react';
import { useCallback, useEffect, useRef, useState } from 'react';
import React, { useCallback, useEffect, useRef, useState } from 'react';

import { Portal } from '../../chakra-re-exports';
import { useGlobalMenuClose } from '../../hooks';
import { typedMemo } from '../../util';
import { Menu, MenuButton } from '../menu';

export interface ContextMenuProps<T extends HTMLElement = HTMLDivElement> {
renderMenu: () => JSX.Element | null;
children: (ref: React.MutableRefObject<T | null>) => JSX.Element | null;
renderMenu: () => React.ReactElement | null;
children: (ref: React.MutableRefObject<T | null>) => React.ReactElement | null;
menuProps?: Omit<MenuProps, 'children'> & { children?: React.ReactNode };
portalProps?: Omit<PortalProps, 'children'> & { children?: React.ReactNode };
menuButtonProps?: MenuButtonProps;
Expand Down Expand Up @@ -52,7 +52,7 @@ export const ContextMenu = typedMemo(
return;
}
// `contains()` requires the arg to be Node. Technically it can be any EventTarget, but it won't cause an error.
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */

if (targetRef.current?.contains(e.target as Node) || e.target === targetRef.current) {
if (stopImmediatePropagation) {
e.stopImmediatePropagation();
Expand Down
2 changes: 1 addition & 1 deletion lib/components/number-input/composite-number-input.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ChevronDownIcon, ChevronUpIcon } from '@chakra-ui/icons';
import type { ComponentWithAs } from '@chakra-ui/react';
import { forwardRef } from '@chakra-ui/react';
import { clamp, isNumber } from 'lodash-es';
import { clamp, isNumber } from 'es-toolkit/compat';
import type { KeyboardEvent } from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';

Expand Down
4 changes: 2 additions & 2 deletions lib/components/slider/composite-slider.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { ComponentWithAs } from '@chakra-ui/react';
import { forwardRef, useFormControl } from '@chakra-ui/react';
import { isNil } from 'es-toolkit/compat';
import { AnimatePresence } from 'framer-motion';
import { isNil } from 'lodash-es';
import { useCallback, useMemo, useState } from 'react';

import { useShiftModifier } from '../../hooks/use-global-modifiers';
Expand Down Expand Up @@ -87,7 +87,7 @@ export const CompositeSlider: ComponentWithAs<ComponentWithAs<'div', SliderProps
const [isChanging, setIsChanging] = useState(false);

const shift = useShiftModifier();
const step = useMemo(() => (shift ? _fineStep ?? _step : _step), [shift, _fineStep, _step]);
const step = useMemo(() => (shift ? (_fineStep ?? _step) : _step), [shift, _fineStep, _step]);
const controlProps = useFormControl({});

const label = useMemo(() => formatValue(value), [formatValue, value]);
Expand Down
3 changes: 0 additions & 3 deletions lib/theme/util/generateColorPalette.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,17 @@ export function generateColorPalette(H: string | number, S: string | number, alp

const p = colorSteps.reduce((palette, step, index) => {
// We know this is a number.
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
const A = alpha ? (lightnessSteps[index] as number) / 100 : 1;

// Lightness should be 50% for alpha colors
const L = alpha ? 50 : lightnessSteps[colorSteps.length - 1 - index];

// We know this is a key of PaletteSteps.
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
palette[step as keyof PaletteSteps] = `hsl(${H} ${S}% ${L}% / ${A})`;

return palette;

// We know this will eventually be a valid PaletteSteps object.
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
}, {} as PaletteSteps);

return p;
Expand Down
2 changes: 1 addition & 1 deletion lib/util/typed-memo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { memo } from 'react';
/**
* A typed version of React.memo, useful for components that take generics.
*/
export const typedMemo: <T extends keyof JSX.IntrinsicElements | React.JSXElementConstructor<any>>(
export const typedMemo: <T extends keyof React.JSX.IntrinsicElements | React.JSXElementConstructor<any>>(
component: T,
propsAreEqual?: (prevProps: React.ComponentProps<T>, nextProps: React.ComponentProps<T>) => boolean
) => T & { displayName?: string } = memo;
Loading