diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 85a37fa887..6c4b4f543c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -20,7 +20,7 @@ jobs:
- name: Use Node.js
uses: actions/setup-node@v4.1.0
with:
- node-version: 20
+ node-version: 22
cache: "pnpm"
- run: |
pnpm install
@@ -36,12 +36,30 @@ jobs:
- name: Use Node.js
uses: actions/setup-node@v4.1.0
with:
- node-version: 20
+ node-version: 22
cache: "pnpm"
- run: |
pnpm install
pnpm typecheck
+ oxlint:
+ runs-on: ubuntu-24.04
+ env:
+ TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
+ TURBO_REMOTE_ONLY: true
+ steps:
+ - uses: actions/checkout@v4
+ - uses: pnpm/action-setup@v4.0.0
+ - name: Use Node.js
+ uses: actions/setup-node@v4.1.0
+ with:
+ node-version: 22
+ cache: "pnpm"
+ - run: |
+ pnpm install
+ pnpm build
+ pnpm oxlint -c .oxlintrc.json
+
lint:
runs-on: ubuntu-24.04
env:
@@ -53,7 +71,7 @@ jobs:
- name: Use Node.js
uses: actions/setup-node@v4.1.0
with:
- node-version: 20
+ node-version: 22
cache: "pnpm"
- run: |
pnpm install
@@ -71,7 +89,7 @@ jobs:
- name: Use Node.js
uses: actions/setup-node@v4.1.0
with:
- node-version: 20
+ node-version: 22
cache: "pnpm"
- run: |
pnpm install
@@ -115,7 +133,7 @@ jobs:
# - name: Use Node.js
# uses: actions/setup-node@v4.0.2
# with:
- # node-version: 20
+ # node-version: 22
# cache: 'pnpm'
# - run: pnpm install
# - run: pnpm run build
@@ -152,7 +170,7 @@ jobs:
- name: Use Node.js
uses: actions/setup-node@v4.1.0
with:
- node-version: 20
+ node-version: 22
cache: "pnpm"
- run: |
pnpm install
diff --git a/.github/workflows/fonts-upload.yml b/.github/workflows/fonts-upload.yml
index 68bb0f2ce2..b6a8d6ab08 100644
--- a/.github/workflows/fonts-upload.yml
+++ b/.github/workflows/fonts-upload.yml
@@ -26,7 +26,7 @@ jobs:
- uses: pnpm/action-setup@v4.0.0
- uses: actions/setup-node@v4.1.0
with:
- node-version: 20
+ node-version: 22
cache: "pnpm"
- run: pnpm install
diff --git a/.github/workflows/illustrations-update.yml b/.github/workflows/illustrations-update.yml
index 75d670f394..273d4e95ed 100644
--- a/.github/workflows/illustrations-update.yml
+++ b/.github/workflows/illustrations-update.yml
@@ -28,7 +28,7 @@ jobs:
- uses: pnpm/action-setup@v4.0.0
- uses: actions/setup-node@v4.1.0
with:
- node-version: 20
+ node-version: 22
cache: "pnpm"
- run: pnpm install
diff --git a/.github/workflows/illustrations-upload.yml b/.github/workflows/illustrations-upload.yml
index f5b792fee9..bf999b3708 100644
--- a/.github/workflows/illustrations-upload.yml
+++ b/.github/workflows/illustrations-upload.yml
@@ -26,7 +26,7 @@ jobs:
- uses: pnpm/action-setup@v4.0.0
- uses: actions/setup-node@v4.1.0
with:
- node-version: 20
+ node-version: 22
cache: "pnpm"
- run: pnpm install
diff --git a/.github/workflows/pull_request_title.yml b/.github/workflows/pull_request_title.yml
index f6294552f7..88676982a3 100644
--- a/.github/workflows/pull_request_title.yml
+++ b/.github/workflows/pull_request_title.yml
@@ -12,7 +12,7 @@ jobs:
- name: Use Node.js
uses: actions/setup-node@v4.1.0
with:
- node-version: 20
+ node-version: 22
cache: "pnpm"
- run: pnpm install --prod
- name: Check PR title
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 6dbb236948..13e235598f 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -24,7 +24,7 @@ jobs:
- name: Use Node.js
uses: actions/setup-node@v4.1.0
with:
- node-version: 20
+ node-version: 22
cache: "pnpm"
- run: pnpm install
- name: Create Release Pull Request or Publish to npm
diff --git a/.github/workflows/size-limit.yml b/.github/workflows/size-limit.yml
index 8e794cfdaf..d10fd5a238 100644
--- a/.github/workflows/size-limit.yml
+++ b/.github/workflows/size-limit.yml
@@ -6,7 +6,7 @@ jobs:
size:
strategy:
matrix:
- node: ["20"]
+ node: ["22"]
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
diff --git a/.github/workflows/sync-design-tokens.yml b/.github/workflows/sync-design-tokens.yml
index 9890c4294b..76b0a907c5 100644
--- a/.github/workflows/sync-design-tokens.yml
+++ b/.github/workflows/sync-design-tokens.yml
@@ -16,7 +16,7 @@ jobs:
- name: Use Node.js
uses: actions/setup-node@v4.1.0
with:
- node-version: 20
+ node-version: 22
cache: "pnpm"
- run: pnpm install
- name: Generate json files
diff --git a/.gitignore b/.gitignore
index e67a454539..e123c0b021 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,3 +42,7 @@ vitest.config.ts.*
examples/*/.turbo
packages/*/.turbo
tools/*/.turbo
+
+# typescript
+*.tsbuildinfo
+.tsbuildinfo
diff --git a/.npmrc b/.npmrc
new file mode 100644
index 0000000000..7fffd833cf
--- /dev/null
+++ b/.npmrc
@@ -0,0 +1,4 @@
+save-prefix=""
+engine-strict=true
+package-manager-strict-version=true
+manage-package-manager-versions=true
diff --git a/.oxlintrc.json b/.oxlintrc.json
new file mode 100644
index 0000000000..b0e543c0c9
--- /dev/null
+++ b/.oxlintrc.json
@@ -0,0 +1,160 @@
+{
+ "$schema": "./node_modules/oxlint/configuration_schema.json",
+ "categories": {
+ "correctness": "deny",
+ "style": "deny",
+ "suspicious": "deny",
+ "perf": "deny",
+ "pedantic": "deny",
+ "restriction": "deny",
+ "nursery": "off"
+ },
+ "plugins": [
+ "import",
+ "node",
+ "react",
+ "security",
+ "n",
+ "tree_shaking",
+ "typescript",
+ "unicorn",
+ "vitest"
+ ],
+ "overrides": [
+ {
+ "files": ["**/__stories__/**/*.{ts,tsx}"],
+ "rules": {
+ "react/jsx-key": "off",
+ "no-console": "off",
+ "no-alert": "off"
+ }
+ }
+ ],
+ "rules": {
+ "@typescript-eslint/ban-tslint-comment": "off",
+ "@typescript-eslint/consistent-indexed-object-style": "off",
+ "@typescript-eslint/consistent-type-definitions": ["error", "type"],
+ "@typescript-eslint/explicit-function-return-type": "off",
+ "@typescript-eslint/no-explicit-any": "warn",
+ "@typescript-eslint/no-magic-numbers": "off",
+ "@typescript-eslint/no-non-null-assertion": "off",
+ "@typescript/no-explicit-any": "warn",
+ "@typescript-eslint/prefer-enum-initializers": "off",
+ "@typescript-eslint/prefer-function-type": "off",
+ "@typescript-eslint/prefer-literal-enum-member": "off",
+ "@typescript-eslint/prefer-ts-expect-error": "off",
+ "eslint/default-param-last": "off",
+ "eslint/max-lines": "off",
+ "eslint/max-params": "off",
+ "eslint/no-await-in-loop": "off",
+ "eslint/no-duplicate-imports": "off",
+ "eslint/no-empty-function": "off",
+ "eslint/no-magic-numbers": "off",
+ "eslint/no-ternary": "off",
+ "eslint/no-undef": "off",
+ "eslint/no-undefined": "off",
+ "eslint/sort-keys": "off",
+ "eslint/react-in-jsx-scope": "off",
+ "eslint/no-unused-vars": [
+ "error",
+ {
+ "ignoreRestSiblings": true
+ }
+ ],
+ "eslint/require-await": "off",
+ "eslint/sort-imports": [
+ "error",
+ {
+ "ignoreDeclarationSort": true,
+ "memberSyntaxSortOrder": ["single", "multiple", "all", "none"]
+ }
+ ],
+ "import/export": "off",
+ "import/import-no-namespace": "off",
+ "import/max-dependencies": "off",
+ "import/namespace": "off",
+ "import/no-default-export": "off",
+ "import/no-deprecated": "warn",
+ "import/no-duplicates": "off",
+ "import/no-unused-modules": "off",
+ "import/unambiguous": "warn",
+ "jest/no-conditional-expect": "off",
+ "jest/no-confusing-set-timeout": "off",
+ "jest/no-hooks": "off",
+ "jest/no-restricted-jest-methods": "off",
+ "jest/no-restricted-matchers": "off",
+ "jest/no-standalone-expect": "off",
+ "jest/no-untyped-mock-factory": "off",
+ "jest/prefer-called-with": "off",
+ "jest/prefer-comparison-matcher": "off",
+ "jest/prefer-equality-matcher": "off",
+ "jest/prefer-expect-resolves": "off",
+ "jest/prefer-lowercase-title": "off",
+ "jest/prefer-mock-promise-shorthand": "off",
+ "jest/prefer-spy-on": "off",
+ "jest/prefer-strict-equal": "off",
+ "jest/prefer-to-be": "off",
+ "jest/prefer-to-contain": "off",
+ "jest/prefer-to-have-length": "off",
+ "jest/prefer-todo": "error",
+ "jest/require-hook": "off",
+ "jest/require-to-throw-message": "off",
+ "oxc/no-accumulating-spread": "off",
+ "oxc/no-async-await": "off",
+ "oxc/no-barrel-file": "off",
+ "oxc/no-optional-chaining": "off",
+ "oxc/no-rest-spread-properties": "off",
+ "react-perf/jsx-no-jsx-as-prop": "off",
+ "react-perf/jsx-no-new-array-as-prop": "off",
+ "react-perf/jsx-no-new-function-as-prop": "off",
+ "react-perf/jsx-no-new-object-as-prop": "off",
+ "react/jsx-no-useless-fragment": "off",
+ "react/exhaustive-deps": "warn",
+ "react/iframe-missing-sandbox": "warn",
+ "react/jsx-no-target-blank": "off",
+ "react/no-set-state": "off",
+ "react/react-in-jsx-scope": "off",
+ "unicorn/error-message": "off",
+ "unicorn/filename-case": "off",
+ "unicorn/no-anonymous-default-export": "off",
+ "unicorn/no-array-for-each": "off",
+ "unicorn/no-array-reduce": "off",
+ "unicorn/no-await-expression-member": "off",
+ "unicorn/no-await-in-promise-methods": "off",
+ "unicorn/no-lonely-if": "off",
+ "unicorn/prefer-set-has": "off",
+ "unicorn/no-document-cookie": "off",
+ "unicorn/no-invalid-remove-event-listener": "off",
+ "unicorn/no-magic-array-flat-depth": "off",
+ "unicorn/no-negated-condition": "off",
+ "unicorn/no-new-array": "off",
+ "unicorn/no-null": "off",
+ "unicorn/no-object-as-default-parameter": "off",
+ "unicorn/no-process-exit": "off",
+ "unicorn/no-single-promise-in-promise-methods": "off",
+ "unicorn/no-useless-promise-resolve-reject": "off",
+ "unicorn/no-useless-undefined": "off",
+ "unicorn/no-zero-fractions": "off",
+ "unicorn/number-literal-case": "off",
+ "unicorn/numeric-separators-style": "off",
+ "unicorn/prefer-add-event-listener": "off",
+ "unicorn/prefer-array-some": "off",
+ "unicorn/prefer-blob-reading-methods": "off",
+ "unicorn/prefer-code-point": "off",
+ "unicorn/prefer-dom-node-append": "off",
+ "unicorn/prefer-dom-node-remove": "off",
+ "unicorn/prefer-logical-operator-over-ternary": "off",
+ "unicorn/prefer-node-protocol": "off",
+ "unicorn/prefer-query-selector": "off",
+ "unicorn/prefer-string-replace-all": "off",
+ "unicorn/prefer-string-slice": "off"
+ },
+ "settings": {
+ "jsx-a11y": {
+ "components": {
+ "polymorphicPropName": "as"
+ }
+ },
+ "react": {}
+ }
+}
diff --git a/eslint.config.mjs b/eslint.config.mjs
index 216e3cd4e3..913f25dc8d 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -4,6 +4,7 @@ import { FlatCompat } from '@eslint/eslintrc'
import scwEmotion from '@scaleway/eslint-config-react/emotion'
import scwJavascript from '@scaleway/eslint-config-react/javascript'
import scwTypescript from '@scaleway/eslint-config-react/typescript'
+import oxlint from 'eslint-plugin-oxlint'
import globals from 'globals'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
@@ -148,4 +149,5 @@ export default [
'react/jsx-props-no-spreading': 'off',
},
},
+ oxlint.configs['flat/all'],
]
diff --git a/examples/next-advanced/next.config.js b/examples/next-advanced/next.config.js
index dbb306a4d5..a1cd5604ee 100644
--- a/examples/next-advanced/next.config.js
+++ b/examples/next-advanced/next.config.js
@@ -30,4 +30,4 @@ const nextConfig = () => {
return config
}
-module.exports = nextConfig()
+export default nextConfig()
diff --git a/examples/next-advanced/src/pages/_document.tsx b/examples/next-advanced/src/pages/_document.tsx
index ae15ef666c..9d110914c9 100644
--- a/examples/next-advanced/src/pages/_document.tsx
+++ b/examples/next-advanced/src/pages/_document.tsx
@@ -7,7 +7,7 @@ class MyDocument extends Document {
return (
-
+
{
return config
}
-module.exports = nextConfig()
+export default nextConfig()
diff --git a/examples/next-login/src/pages/_app.tsx b/examples/next-login/src/pages/_app.tsx
index ed6cc75180..c0244b2538 100644
--- a/examples/next-login/src/pages/_app.tsx
+++ b/examples/next-login/src/pages/_app.tsx
@@ -1,6 +1,6 @@
-import { ThemeProvider, Global, css } from '@emotion/react'
+import { Global, ThemeProvider, css } from '@emotion/react'
import { Button } from '@ultraviolet/ui'
-import { darkTheme, theme, normalize } from '@ultraviolet/ui'
+import { darkTheme, normalize, theme } from '@ultraviolet/ui'
import type { AppProps } from 'next/app'
import { useState } from 'react'
diff --git a/examples/next-login/src/pages/_document.tsx b/examples/next-login/src/pages/_document.tsx
index ae15ef666c..9d110914c9 100644
--- a/examples/next-login/src/pages/_document.tsx
+++ b/examples/next-login/src/pages/_document.tsx
@@ -7,7 +7,7 @@ class MyDocument extends Document {
return (
-
+
{
let tabLoaded = undefined
switch (props.tab) {
- case 'login':
+ case 'login': {
tabLoaded =
break
- default:
+ }
+ default: {
tabLoaded =
+ }
}
return tabLoaded
}
diff --git a/examples/next-login/src/pages/home/login.tsx b/examples/next-login/src/pages/home/login.tsx
index e4e921b794..9e2c6b63e9 100644
--- a/examples/next-login/src/pages/home/login.tsx
+++ b/examples/next-login/src/pages/home/login.tsx
@@ -1,10 +1,10 @@
-import { Text, Link, Stack } from '@ultraviolet/ui'
+import { Link, Stack, Text } from '@ultraviolet/ui'
import { IdIcon } from '@ultraviolet/icons'
import {
+ CheckboxField,
Form,
- TextInputField,
Submit,
- CheckboxField,
+ TextInputField,
useForm,
useWatch,
} from '@ultraviolet/form'
@@ -49,6 +49,8 @@ const LogIn = () => {
`,
)
setTimeout(() => setLoginText(''), 3000)
+
+ // oxlint-disable-next-line eslint/no-console
console.log('Values :', values)
}
diff --git a/examples/next-login/src/pages/home/signup.tsx b/examples/next-login/src/pages/home/signup.tsx
index 91a2b19463..ed61091c83 100644
--- a/examples/next-login/src/pages/home/signup.tsx
+++ b/examples/next-login/src/pages/home/signup.tsx
@@ -1,12 +1,12 @@
-import { Text, Stack, Alert } from '@ultraviolet/ui'
+import { Alert, Stack, Text } from '@ultraviolet/ui'
import { ProfileIcon } from '@ultraviolet/icons'
import {
+ DateField,
Form,
- TextInputFieldV2,
+ RadioGroupField,
Submit,
+ TextInputFieldV2,
useForm,
- RadioGroupField,
- DateField,
useWatch,
} from '@ultraviolet/form'
import { useState } from 'react'
diff --git a/examples/next-simple/next.config.js b/examples/next-simple/next.config.js
index 80683bf452..bdefa8a3c9 100644
--- a/examples/next-simple/next.config.js
+++ b/examples/next-simple/next.config.js
@@ -29,4 +29,4 @@ const nextConfig = () => {
return config
}
-module.exports = nextConfig()
+export default nextConfig()
diff --git a/examples/next-simple/package.json b/examples/next-simple/package.json
index ea117f28f2..9a88a5173b 100644
--- a/examples/next-simple/package.json
+++ b/examples/next-simple/package.json
@@ -8,6 +8,7 @@
"directory": "examples/next-simple"
},
"private": true,
+ "type": "module",
"scripts": {
"dev": "next dev",
"build": "next build",
diff --git a/examples/next-simple/src/pages/_document.tsx b/examples/next-simple/src/pages/_document.tsx
index ae15ef666c..9d110914c9 100644
--- a/examples/next-simple/src/pages/_document.tsx
+++ b/examples/next-simple/src/pages/_document.tsx
@@ -7,7 +7,7 @@ class MyDocument extends Document {
return (
-
+
{
+ // oxlint-disable-next-line eslint/no-console
console.log('data', data)
}}
errors={mockErrors}
diff --git a/packages/form/src/components/Form/__stories__/Playground.stories.tsx b/packages/form/src/components/Form/__stories__/Playground.stories.tsx
index b86cc53731..76add70e2b 100644
--- a/packages/form/src/components/Form/__stories__/Playground.stories.tsx
+++ b/packages/form/src/components/Form/__stories__/Playground.stories.tsx
@@ -238,6 +238,7 @@ export const Playground: StoryFn = () => {
Playground.args = {
onSubmit: values => {
+ // oxlint-disable-next-line eslint/no-console
console.log('Submit', values)
},
}
diff --git a/packages/form/src/components/KeyValueField/index.tsx b/packages/form/src/components/KeyValueField/index.tsx
index 3714e0d10f..c4baaceea1 100644
--- a/packages/form/src/components/KeyValueField/index.tsx
+++ b/packages/form/src/components/KeyValueField/index.tsx
@@ -63,7 +63,7 @@ export const KeyValueField = <
return (
- {fields.length ? (
+ {fields.length > 0 ? (
{fields.map((field, index) => (
& {
+ // oxlint-disable-next-line no-explicit-any
parse?: (value: boolean) => any
+ // oxlint-disable-next-line no-explicit-any
format?: (value: any) => boolean
}
diff --git a/packages/form/src/validators/__tests__/maxDate.test.ts b/packages/form/src/validators/__tests__/maxDate.test.ts
index f7cf4c3f22..78dd1bc11a 100644
--- a/packages/form/src/validators/__tests__/maxDate.test.ts
+++ b/packages/form/src/validators/__tests__/maxDate.test.ts
@@ -10,15 +10,15 @@ const tomorrow = new Date(today.getTime() + 24 * hourInMs)
describe('maxDate validator', () => {
test('should success', () => {
const validator = maxDateValidator(yesterday)
- expect(validator(today)).toBe(false)
- expect(validator(twoHoursLater)).toBe(false)
- expect(validator(tomorrow)).toBe(false)
+ expect(validator(today)).toBeFalsy()
+ expect(validator(twoHoursLater)).toBeFalsy()
+ expect(validator(tomorrow)).toBeFalsy()
})
test('should failed', () => {
const validator = maxDateValidator(tomorrow)
- expect(validator(yesterday)).toBe(true)
- expect(validator(today)).toBe(true)
- expect(validator(twoHoursLater)).toBe(true)
+ expect(validator(yesterday)).toBeTruthy()
+ expect(validator(today)).toBeTruthy()
+ expect(validator(twoHoursLater)).toBeTruthy()
})
})
diff --git a/packages/form/src/validators/__tests__/minDate.test.ts b/packages/form/src/validators/__tests__/minDate.test.ts
index be4f081a96..92f4414382 100644
--- a/packages/form/src/validators/__tests__/minDate.test.ts
+++ b/packages/form/src/validators/__tests__/minDate.test.ts
@@ -10,15 +10,15 @@ const tomorrow = new Date(today.getTime() + 24 * hourInMs)
describe('minDate validator', () => {
test('should invalidate the input', () => {
const validator = minDateValidator(tomorrow)
- expect(validator(today)).toBe(false)
- expect(validator(twoHoursLater)).toBe(false)
- expect(validator(yesterday)).toBe(false)
+ expect(validator(today)).toBeFalsy()
+ expect(validator(twoHoursLater)).toBeFalsy()
+ expect(validator(yesterday)).toBeFalsy()
})
test('should validate the input', () => {
const validator = minDateValidator(yesterday)
- expect(validator(today)).toBe(true)
- expect(validator(tomorrow)).toBe(true)
- expect(validator(twoHoursLater)).toBe(true)
+ expect(validator(today)).toBeTruthy()
+ expect(validator(tomorrow)).toBeTruthy()
+ expect(validator(twoHoursLater)).toBeTruthy()
})
})
diff --git a/packages/icons/src/components/CategoryIcon/__stories__/List.stories.tsx b/packages/icons/src/components/CategoryIcon/__stories__/List.stories.tsx
index 767b86d7d7..cc3d709fe0 100644
--- a/packages/icons/src/components/CategoryIcon/__stories__/List.stories.tsx
+++ b/packages/icons/src/components/CategoryIcon/__stories__/List.stories.tsx
@@ -9,7 +9,7 @@ export const List: StoryFn = props => (
CategoryIcon[IconName as keyof typeof CategoryIcon]
return (
-
+
diff --git a/packages/plus/src/components/ContentCard/__stories__/Click.stories.tsx b/packages/plus/src/components/ContentCard/__stories__/Click.stories.tsx
index f71006f223..78edb7a858 100644
--- a/packages/plus/src/components/ContentCard/__stories__/Click.stories.tsx
+++ b/packages/plus/src/components/ContentCard/__stories__/Click.stories.tsx
@@ -21,6 +21,7 @@ Click.decorators = [
Click.args = {
...Template.args,
onClick: () => {
+ // oxlint-disable-next-line eslint/no-alert
alert('Clicked!')
},
}
diff --git a/packages/plus/src/components/ContentCard/__stories__/Disabled.stories.tsx b/packages/plus/src/components/ContentCard/__stories__/Disabled.stories.tsx
index 60ca925215..c39f368ca7 100644
--- a/packages/plus/src/components/ContentCard/__stories__/Disabled.stories.tsx
+++ b/packages/plus/src/components/ContentCard/__stories__/Disabled.stories.tsx
@@ -49,7 +49,10 @@ export const Disabled: StoryFn = args => (
title="Create your first function"
description="The Scaleway Serverless Functions platform makes your functions available, executes them on demand and manages resource allocation for you."
disabled
- onClick={() => console.log('ok')}
+ onClick={
+ // oxlint-disable-next-line eslint/no-console
+ () => console.log('ok')
+ }
/>
diff --git a/packages/plus/src/components/EstimateCost/Components/UnitInput.tsx b/packages/plus/src/components/EstimateCost/Components/UnitInput.tsx
index 8302f04527..8395af2d80 100644
--- a/packages/plus/src/components/EstimateCost/Components/UnitInput.tsx
+++ b/packages/plus/src/components/EstimateCost/Components/UnitInput.tsx
@@ -130,11 +130,11 @@ export const UnitInput = ({
value={value}
placeholder={placeholder}
onChange={input => {
- const numericValue = parseInt(input, 10)
+ const numericValue = Number.parseInt(input, 10)
onChange(numericValue)
}}
onBlur={(event: FocusEvent) => {
- const numericValue = parseInt(event.target.value, 10)
+ const numericValue = Number.parseInt(event.target.value, 10)
if (Number.isNaN(numericValue) || numericValue < minValue) {
onChange(minValue)
}
diff --git a/packages/plus/src/components/EstimateCost/__stories__/NumberInput.stories.tsx b/packages/plus/src/components/EstimateCost/__stories__/NumberInput.stories.tsx
index ce0981e2bd..f74b04a0bd 100644
--- a/packages/plus/src/components/EstimateCost/__stories__/NumberInput.stories.tsx
+++ b/packages/plus/src/components/EstimateCost/__stories__/NumberInput.stories.tsx
@@ -6,6 +6,7 @@ export const NumberInput = Template.bind({})
NumberInput.args = {
children: [
,
Powerful
100 Cores
,
-
+
100 GB
,
],
diff --git a/packages/plus/src/components/EstimateCost/__tests__/helper.test.ts b/packages/plus/src/components/EstimateCost/__tests__/helper.test.ts
index 594cd06ef2..1c0451c89c 100644
--- a/packages/plus/src/components/EstimateCost/__tests__/helper.test.ts
+++ b/packages/plus/src/components/EstimateCost/__tests__/helper.test.ts
@@ -43,7 +43,7 @@ describe('EstimateCost - helper', () => {
amount: 5,
amountFree: 2,
timeUnit: 'months',
- timeAmount: NaN,
+ timeAmount: Number.NaN,
}),
).toEqual(0)
})
diff --git a/packages/plus/src/components/Navigation/Footer.tsx b/packages/plus/src/components/Navigation/Footer.tsx
index f5e666380b..1cebeb7462 100644
--- a/packages/plus/src/components/Navigation/Footer.tsx
+++ b/packages/plus/src/components/Navigation/Footer.tsx
@@ -39,6 +39,8 @@ export const Footer = ({ onToggleExpand, contentRef }: FooterProps) => {
) {
return false
}
+
+ return true
}
return true
diff --git a/packages/plus/src/components/Navigation/__stories__/Playground.stories.tsx b/packages/plus/src/components/Navigation/__stories__/Playground.stories.tsx
index 4a2fc34e07..b2ffaa0fff 100644
--- a/packages/plus/src/components/Navigation/__stories__/Playground.stories.tsx
+++ b/packages/plus/src/components/Navigation/__stories__/Playground.stories.tsx
@@ -13,6 +13,12 @@ const Image = styled.img`
animation: ${fadeOut} 250ms linear forwards;
}
`
+const onClickPinUnpin: ComponentProps<
+ typeof Navigation.Item
+>['onClickPinUnpin'] = ({ totalPinned }) => {
+ // oxlint-disable-next-line eslint/no-console
+ console.log('total pinned items:', totalPinned)
+}
const PlaygroundContent = ({ ...props }: ComponentProps) => {
const [active, setActive] = useState('Instance')
@@ -24,6 +30,7 @@ const PlaygroundContent = ({ ...props }: ComponentProps) => {
const saveExpandedInLocalStorage = useCallback((localExpanded: boolean) => {
setExpanded(localExpanded)
+ // oxlint-disable-next-line eslint/no-console
console.log(
`expanded state with value ${localExpanded} saved in local storage`,
)
@@ -31,21 +38,17 @@ const PlaygroundContent = ({ ...props }: ComponentProps) => {
}, [])
useEffect(() => {
+ // oxlint-disable-next-line eslint/no-console
console.log('pinned items:', pinnedItems)
localStorage.setItem('pinnedItems', pinnedItems.toString())
}, [pinnedItems])
const saveWidthInLocalStorage = useCallback((width: number) => {
+ // oxlint-disable-next-line eslint/no-console
console.log(`width of ${width} saved in local storage`)
localStorage.setItem('width', width.toString())
}, [])
- const onClickPinUnpin: ComponentProps<
- typeof Navigation.Item
- >['onClickPinUnpin'] = ({ totalPinned }) => {
- console.log('total pinned items:', totalPinned)
- }
-
return (
) => {
+ // eslint-disable-next-line no-param-reassign
+ event.currentTarget.style.opacity = '1'
+}
+
export const Item = memo(
({
children,
@@ -496,11 +501,6 @@ export const Item = memo(
event.currentTarget.style.opacity = '0.5'
}
- const onDragStopTrigger = (event: DragEvent) => {
- // eslint-disable-next-line no-param-reassign
- event.currentTarget.style.opacity = '1'
- }
-
const expandableAnimationDuration = useMemo(() => {
if (!shouldAnimate || animationType === 'simple') return 0
diff --git a/packages/plus/src/components/SteppedListCard/Step.tsx b/packages/plus/src/components/SteppedListCard/Step.tsx
index 31931271ca..08f8398129 100644
--- a/packages/plus/src/components/SteppedListCard/Step.tsx
+++ b/packages/plus/src/components/SteppedListCard/Step.tsx
@@ -44,33 +44,29 @@ export const SteppedList = ({
const containerData = useContext(Data)
const active = containerData.currentStep === stepNumber
- return (
- <>
- {completed ? (
- containerData.setCurrentStep(stepNumber)}
- data-testid={dataTestId}
- >
-
- {stepTitle}
-
-
- ) : (
- containerData.setCurrentStep(stepNumber)}
- data-testid={dataTestId}
- >
-
- {stepTitle}
-
-
- )}
- >
+ return completed ? (
+ containerData.setCurrentStep(stepNumber)}
+ data-testid={dataTestId}
+ >
+
+ {stepTitle}
+
+
+ ) : (
+ containerData.setCurrentStep(stepNumber)}
+ data-testid={dataTestId}
+ >
+
+ {stepTitle}
+
+
)
}
diff --git a/packages/plus/src/components/SteppedListCard/SteppedListContainer.tsx b/packages/plus/src/components/SteppedListCard/SteppedListContainer.tsx
index 157e3f11af..8ade0ec211 100644
--- a/packages/plus/src/components/SteppedListCard/SteppedListContainer.tsx
+++ b/packages/plus/src/components/SteppedListCard/SteppedListContainer.tsx
@@ -65,7 +65,7 @@ const SteppedListContainer = ({
const numberOfSteps = Children.count(children)
const [currentStep, setCurrentStep] = useState(1)
const [hidden, setHidden] = useState(false)
- const [done, setDone] = useState(Array(steps.length).fill(false))
+ const [done, setDone] = useState(new Array(steps.length).fill(false))
const values = useMemo(
() => ({
diff --git a/packages/plus/src/components/SteppedListCard/SteppedListContent.tsx b/packages/plus/src/components/SteppedListCard/SteppedListContent.tsx
index 80bbde4cd6..e1e64db675 100644
--- a/packages/plus/src/components/SteppedListCard/SteppedListContent.tsx
+++ b/packages/plus/src/components/SteppedListCard/SteppedListContent.tsx
@@ -31,36 +31,36 @@ export const SteppedListContent = ({
}: SteppedListContentProps) => {
const containerData = useContext(Data)
- return (
- <>
- {stepNumber === containerData.currentStep ? (
-
-
- {typeof subHeader === 'string' ? (
-
- {subHeader}
-
- ) : (
- subHeader
- )}
-
- {typeof children === 'function'
- ? children((completed: boolean) =>
- nextStep({
- completed,
- setCompleted: containerData.setDone,
- done: containerData.done,
- stepNumber,
- setCurrentStep: containerData.setCurrentStep,
- numberOfSteps: containerData.numberOfSteps,
- setHidden: containerData.setHidden,
- onClickHide: containerData.onClickHide,
- }),
- )
- : children}
- {image}
-
- ) : null}
- >
- )
+ if (stepNumber === containerData.currentStep) {
+ return (
+
+
+ {typeof subHeader === 'string' ? (
+
+ {subHeader}
+
+ ) : (
+ subHeader
+ )}
+
+ {typeof children === 'function'
+ ? children((completed: boolean) =>
+ nextStep({
+ completed,
+ setCompleted: containerData.setDone,
+ done: containerData.done,
+ stepNumber,
+ setCurrentStep: containerData.setCurrentStep,
+ numberOfSteps: containerData.numberOfSteps,
+ setHidden: containerData.setHidden,
+ onClickHide: containerData.onClickHide,
+ }),
+ )
+ : children}
+ {image}
+
+ )
+ }
+
+ return null
}
diff --git a/packages/plus/src/components/SteppedListCard/__stories__/Template.stories.tsx b/packages/plus/src/components/SteppedListCard/__stories__/Template.stories.tsx
index 49cab45ed1..3b6e412064 100644
--- a/packages/plus/src/components/SteppedListCard/__stories__/Template.stories.tsx
+++ b/packages/plus/src/components/SteppedListCard/__stories__/Template.stories.tsx
@@ -3,7 +3,7 @@ import styled from '@emotion/styled'
import type { StoryFn } from '@storybook/react'
import { blockStorageWire } from '@ultraviolet/illustrations/products/blockStorage'
import { Button, Stack, Text } from '@ultraviolet/ui'
-import { type ComponentProps } from 'react'
+import type { ComponentProps } from 'react'
import { SteppedListContainer } from '../SteppedListContainer'
const StyledImage = styled.img`
diff --git a/packages/plus/src/components/SteppedListCard/__tests__/index.test.tsx b/packages/plus/src/components/SteppedListCard/__tests__/index.test.tsx
index daf8bde625..d017817c13 100644
--- a/packages/plus/src/components/SteppedListCard/__tests__/index.test.tsx
+++ b/packages/plus/src/components/SteppedListCard/__tests__/index.test.tsx
@@ -38,6 +38,7 @@ describe('SteppedListCard', () => {
console.log('test')}
>
{
console.log('test')}
>
{
console.log('hide clicked')}
>
{
}, {})
/* eslint-enable no-underscore-dangle */
- const propertiesList = Object.keys(componentNameAndProperties)
- .map(key => Object.keys(componentNameAndProperties[key]))
- .flat()
+ const propertiesList = Object.keys(componentNameAndProperties).flatMap(key =>
+ Object.keys(componentNameAndProperties[key]),
+ )
const countPropertiesUsages = propertiesList.reduce>(
(acc, property) => {
@@ -172,12 +172,10 @@ const Properties = () => {
}
}
- const reversedLocalProperty = lowerCaseLocalProperty
- .split('')
+ const reversedLocalProperty = [...lowerCaseLocalProperty]
.reverse()
.join('')
- const reversedLowerCaseProperty = lowerCaseProperty
- .split('')
+ const reversedLowerCaseProperty = [...lowerCaseProperty]
.reverse()
.join('')
@@ -209,35 +207,33 @@ const Properties = () => {
...new Set(
sortedPropertiesUsagesCountAndComponentsName[
property
- ]?.components
- ?.map(component => {
- const { name, value } =
- (
- componentNameAndProperties as Record<
- string,
- Record
- >
- )[component]?.[property]?.type ?? {}
+ ]?.components?.flatMap(component => {
+ const { name, value } =
+ (
+ componentNameAndProperties as Record<
+ string,
+ Record
+ >
+ )[component]?.[property]?.type ?? {}
- if (name === 'boolean') {
- return ['true', 'false']
- }
+ if (name === 'boolean') {
+ return ['true', 'false']
+ }
- if (name === 'string') {
- return ['string']
- }
+ if (name === 'string') {
+ return ['string']
+ }
- if (name === 'enum') {
- return (
- value?.map(localValue =>
- localValue.value.replaceAll('"', ''),
- ) ?? []
- )
- }
+ if (name === 'enum') {
+ return (
+ value?.map(localValue =>
+ localValue.value.replaceAll('"', ''),
+ ) ?? []
+ )
+ }
- return []
- })
- .flat(),
+ return []
+ }),
),
]
diff --git a/packages/ui/src/__stories__/Tools/ThemeGenerator/FormContent/index.tsx b/packages/ui/src/__stories__/Tools/ThemeGenerator/FormContent/index.tsx
index 91cbf885b1..3aac4062aa 100644
--- a/packages/ui/src/__stories__/Tools/ThemeGenerator/FormContent/index.tsx
+++ b/packages/ui/src/__stories__/Tools/ThemeGenerator/FormContent/index.tsx
@@ -81,6 +81,8 @@ export const FormContent = () => {
const countRequiredSentiments = fields.filter(
({ required }) => required,
).length
+
+ // oxlint-disable-next-line eslint/no-console
console.log({ errors })
return (
diff --git a/packages/ui/src/__stories__/Tools/ThemeGenerator/helpers.ts b/packages/ui/src/__stories__/Tools/ThemeGenerator/helpers.ts
index 03f5057dec..1c8f672c4d 100644
--- a/packages/ui/src/__stories__/Tools/ThemeGenerator/helpers.ts
+++ b/packages/ui/src/__stories__/Tools/ThemeGenerator/helpers.ts
@@ -2,7 +2,7 @@
type ShadeHexColorType = (color: string, percent: number) => string
export const shadeHexColor: ShadeHexColorType = (color, percent) => {
- const f = parseInt(color.slice(1), 16)
+ const f = Number.parseInt(color.slice(1), 16)
const t = percent < 0 ? 0 : 255
const p = percent < 0 ? percent * -1 : percent
// eslint-disable-next-line no-bitwise
diff --git a/packages/ui/src/__stories__/components/Colors.tsx b/packages/ui/src/__stories__/components/Colors.tsx
index fefb1c8d97..6df491c4b4 100644
--- a/packages/ui/src/__stories__/components/Colors.tsx
+++ b/packages/ui/src/__stories__/components/Colors.tsx
@@ -63,7 +63,7 @@ const Colors = () => {
) as AvailableContexts[]
return (
-
+
{sentiment}
@@ -72,7 +72,7 @@ const Colors = () => {
{colorContextKeys
.filter(context => context.includes('background'))
.map(context => (
-
+
{
].includes(background),
)
.map(type => (
-
+
{type}
@@ -249,7 +249,7 @@ const Colors = () => {
{Object.keys(iconColors[type as keyof typeof iconColors]).map(
sentiment => (
-
+
{sentiment}
diff --git a/packages/ui/src/components/Alert/__stories__/Sentiments.stories.tsx b/packages/ui/src/components/Alert/__stories__/Sentiments.stories.tsx
index 20743bb926..ae1002116f 100644
--- a/packages/ui/src/components/Alert/__stories__/Sentiments.stories.tsx
+++ b/packages/ui/src/components/Alert/__stories__/Sentiments.stories.tsx
@@ -6,8 +6,8 @@ import { Stack } from '../../Stack'
export const Sentiments = (props: ComponentProps) =>
ALERT_SENTIMENTS.map(sentiment => (
= args => {
- const onClick = () => {}
+const onClick = () => {}
- return (
-
-
- {([...SENTIMENTS, 'white', 'black'] as const).map(sentiment => (
-
-
-
- {sentiment.toUpperCase()}
-
+export const Showcase: StoryFn = args => (
+
+
+ {([...SENTIMENTS, 'white', 'black'] as const).map(sentiment => (
+
+
+
+ {sentiment.toUpperCase()}
+
+
+ {buttonVariants.map(variant => (
+
+
+
+
- {buttonVariants.map(variant => (
-
-
-
-
-
- ))}
-
- ))}
-
-
- )
-}
+ ))}
+
+ ))}
+
+
+)
Showcase.parameters = {
docs: {
diff --git a/packages/ui/src/components/Checkbox/__tests__/index.test.tsx b/packages/ui/src/components/Checkbox/__tests__/index.test.tsx
index af9ddbadbf..639a2c7870 100644
--- a/packages/ui/src/components/Checkbox/__tests__/index.test.tsx
+++ b/packages/ui/src/components/Checkbox/__tests__/index.test.tsx
@@ -140,7 +140,7 @@ describe('Checkbox', () => {
hidden: true,
})
await userEvent.click(input)
- expect(input.checked).toBe(true)
+ expect(input.checked).toBeTruthy()
})
test('renders with click event with progress', async () => {
@@ -154,6 +154,6 @@ describe('Checkbox', () => {
hidden: true,
})
await userEvent.click(input)
- expect(input.checked).toBe(true)
+ expect(input.checked).toBeTruthy()
})
})
diff --git a/packages/ui/src/components/DateInput/__stories__/Localized.stories.tsx b/packages/ui/src/components/DateInput/__stories__/Localized.stories.tsx
index 24160a1e03..12c22aa1cd 100644
--- a/packages/ui/src/components/DateInput/__stories__/Localized.stories.tsx
+++ b/packages/ui/src/components/DateInput/__stories__/Localized.stories.tsx
@@ -13,8 +13,8 @@ const locales = [
export const Localized = (props: ComponentProps) =>
locales.map(({ label, locale }) => (
{}}
label={label}
locale={locale}
diff --git a/packages/ui/src/components/DateInput/__tests__/helper.test.ts b/packages/ui/src/components/DateInput/__tests__/helper.test.ts
index b842a41f15..aebf6c35d7 100644
--- a/packages/ui/src/components/DateInput/__tests__/helper.test.ts
+++ b/packages/ui/src/components/DateInput/__tests__/helper.test.ts
@@ -16,6 +16,8 @@ const rangeDate = {
const date = new Date('20 November 2000')
+const format = (value?: Date) => (value ? String(value.getFullYear()) : '1999')
+
describe('Helper functions dateInput', () => {
test('getMonthFirstDay should work', () => {
expect(getMonthFirstDay(1, 2000)).toBe(5)
@@ -46,19 +48,19 @@ describe('Helper functions dateInput', () => {
})
test('isSameMonth should work', () => {
- expect(isSameMonth(new Date('23 Dec 2023'), new Date('22 Dec 2023'))).toBe(
- true,
- )
- expect(isSameMonth(new Date('23 Dec 2023'), new Date('23 Oct 2023'))).toBe(
- false,
- )
+ expect(
+ isSameMonth(new Date('23 Dec 2023'), new Date('22 Dec 2023')),
+ ).toBeTruthy()
+ expect(
+ isSameMonth(new Date('23 Dec 2023'), new Date('23 Oct 2023')),
+ ).toBeFalsy()
})
test('isSameDay should work', () => {
- expect(isSameDay(new Date(), new Date('22 Dec 1999'))).toBe(false)
- expect(isSameDay(new Date('23 Dec 2023'), new Date('23 Dec 2023'))).toBe(
- true,
- )
+ expect(isSameDay(new Date(), new Date('22 Dec 1999'))).toBeFalsy()
+ expect(
+ isSameDay(new Date('23 Dec 2023'), new Date('23 Dec 2023')),
+ ).toBeTruthy()
})
test('formatValue should work with default formatting', () => {
@@ -74,9 +76,6 @@ describe('Helper functions dateInput', () => {
})
test('formatValue should work with custom formatting', () => {
- const format = (value?: Date) =>
- value ? String(value.getFullYear()) : '1999'
-
expect(formatValue(date, null, false, false, format)).toBe('2000')
expect(formatValue(date, null, true, false, format)).toBe('2000')
expect(formatValue(date, null, false, true, format)).toBe('2000')
diff --git a/packages/ui/src/components/DateInput/index.tsx b/packages/ui/src/components/DateInput/index.tsx
index 5363992076..a83bc7ef63 100644
--- a/packages/ui/src/components/DateInput/index.tsx
+++ b/packages/ui/src/components/DateInput/index.tsx
@@ -201,7 +201,7 @@ export const DateInput = ({
const [startDateInput, endDateInput] = newValue.split(' - ').map(val => {
if (showMonthYearPicker) {
// Force YYYY/MM (since MM/YYYY not recognised as a date in typescript)
- const res = val.split(/\D+/).map(aa => parseInt(aa, 10))
+ const res = val.split(/\D+/).map(aa => Number.parseInt(aa, 10))
return new Date(Math.max(...res), Math.min(...res) - 1)
}
diff --git a/packages/ui/src/components/LineChart/CustomLegend.tsx b/packages/ui/src/components/LineChart/CustomLegend.tsx
index 9a64bcc8e5..089fe4dfbc 100644
--- a/packages/ui/src/components/LineChart/CustomLegend.tsx
+++ b/packages/ui/src/components/LineChart/CustomLegend.tsx
@@ -94,21 +94,31 @@ export const CustomLegend = ({
'data-testid': dataTestId,
}: CustomLegendProps) => (
-
+
Legend
|
|
|
|
-
+
{data?.map((row, index) => {
const values = row.data.map(val => val.y as number)
const labelIndexed = `${row.id}${index}`
const id = row.id.toString()
return (
-
+
{row?.['label']}
-
+
diff --git a/packages/ui/src/components/LineChart/helpers.ts b/packages/ui/src/components/LineChart/helpers.ts
index 41d07d01cd..72d8c218f9 100644
--- a/packages/ui/src/components/LineChart/helpers.ts
+++ b/packages/ui/src/components/LineChart/helpers.ts
@@ -2,20 +2,20 @@ import type { DatumValue, Serie } from '@nivo/line'
const parse = (data?: DatumValue | null): number => {
if (typeof data === 'number') return data || 0
- if (typeof data === 'string') return parseFloat(data) || 0
+ if (typeof data === 'string') return Number.parseFloat(data) || 0
if (data instanceof Date) return data.getTime()
return 0
}
export const getMin = (values: DatumValue[] = []): number =>
- values.length ? Math.min(...values.map(parse)) : 0
+ values.length > 0 ? Math.min(...values.map(parse)) : 0
export const getMax = (values: DatumValue[] = []): number =>
- values.length ? Math.max(...values.map(parse)) : 0
+ values.length > 0 ? Math.max(...values.map(parse)) : 0
export const getAverage = (values: DatumValue[] = []): number =>
- values.length
+ values.length > 0
? Math.round(
(values.reduce
((sum, curr) => sum + parse(curr), 0) /
values.length) *
@@ -44,7 +44,7 @@ export const getMinChartValue = (preppedData?: Serie[]): number => {
}
export const getCurrent = (values: number[] = []): number =>
- values.length ? values[values.length - 1] : 0
+ values.length > 0 ? values[values.length - 1] : 0
export const getSelected = (
label: string,
@@ -54,7 +54,7 @@ export const getSelected = (
const labelIndexed = label + index.toString()
const found = selected.indexOf(labelIndexed)
- if (found > -1) {
+ if (found !== -1) {
selected.splice(found, 1)
} else {
selected.push(labelIndexed)
diff --git a/packages/ui/src/components/Link/__stories__/Size.stories.tsx b/packages/ui/src/components/Link/__stories__/Size.stories.tsx
index 1164f7ea94..c893281554 100644
--- a/packages/ui/src/components/Link/__stories__/Size.stories.tsx
+++ b/packages/ui/src/components/Link/__stories__/Size.stories.tsx
@@ -11,7 +11,7 @@ const sizes: ComponentProps['size'][] = [
export const Size = (props: ComponentProps) =>
sizes.map(size => (
-
+
{size}
))
diff --git a/packages/ui/src/components/List/__stories__/OnSelectedChange.stories.tsx b/packages/ui/src/components/List/__stories__/OnSelectedChange.stories.tsx
index f9606c1af9..860e2435e2 100644
--- a/packages/ui/src/components/List/__stories__/OnSelectedChange.stories.tsx
+++ b/packages/ui/src/components/List/__stories__/OnSelectedChange.stories.tsx
@@ -9,6 +9,7 @@ import { columns, data } from './resources'
export const OnSelectedChange: StoryFn = args => {
const [selectedRows, onSelectedChange] = useState([])
+ // oxlint-disable-next-line eslint/no-console
console.log('selected', selectedRows)
return (
@@ -18,7 +19,7 @@ export const OnSelectedChange: StoryFn = args => {
{selectedRows.length > 0 ? (
{selectedRows.map(item => (
- -
+
-
{item}
@@ -60,6 +61,7 @@ export const OnSelectedChange: StoryFn = args => {