0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

refactor(experience): use vite

This commit is contained in:
Gao Sun 2024-07-24 13:52:44 +08:00
parent 6c1f4283a9
commit 3bf756f2b5
No known key found for this signature in database
GPG key ID: 13EBE123E4773688
107 changed files with 296 additions and 1994 deletions

View file

@ -0,0 +1,12 @@
---
"@logto/experience": minor
"@logto/demo-app": minor
"@logto/console": minor
---
use Vite for transpilation and bundling
Removed ParcelJS and replaced with Vite. No breaking changes should be expected, but use a minor version bump to catch your attention.
> [!Important]
> The browserlist configuration for `@logto/experience` and been synced with what is stated in README.md.

View file

@ -33,5 +33,4 @@ dump.rdb
.devcontainer
.github
.husky
.parcel-cache
.vscode

6
.npmrc
View file

@ -1,6 +0,0 @@
# Hoist for Parcel
public-hoist-pattern[]=@parcel/*
public-hoist-pattern[]=postcss
public-hoist-pattern[]=process
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=buffer

View file

@ -18,7 +18,7 @@ fi
# Some node packages use `src` as their dist folder, so ignore them from the rm list in the end
find \
.git .changeset .devcontainer .github .husky .parcel-cache .scripts .vscode pnpm-*.yaml *.js \
.git .changeset .devcontainer .github .husky .scripts .vscode pnpm-*.yaml *.js \
packages/**/src \
packages/**/*.config.js packages/**/*.config.ts packages/**/tsconfig*.json \
! -path '**/node_modules/**' \

View file

@ -10,7 +10,7 @@
"scope": "javascriptreact,typescriptreact",
"prefix": "isc",
"body": [
"import * as styles from './index.module.scss';",
"import styles from './index.module.scss';",
"$0"
],
"description": "Import SCSS styles from the same directory."

View file

@ -14,7 +14,6 @@ RUN apk add --no-cache python3 make g++ rsync
COPY . .
### Install dependencies and build ###
RUN node .scripts/update-parcelrc.js
RUN pnpm i
### Set if dev features enabled ###
@ -35,7 +34,7 @@ RUN rm -rf node_modules packages/**/node_modules
RUN NODE_ENV=production pnpm i
### Clean up ###
RUN rm -rf .scripts .parcel-cache pnpm-*.yaml packages/cloud
RUN rm -rf .scripts pnpm-*.yaml packages/cloud
###### [STAGE] Seal ######
FROM node:20-alpine as app

View file

@ -52,9 +52,5 @@
},
"dependencies": {
"@logto/cli": "workspace:^1.1.0"
},
"//": "@see https://parceljs.org/features/dependency-resolution/#package-exports",
"@parcel/resolver-default": {
"packageExports": true
}
}

View file

@ -52,6 +52,9 @@ Images and other assets (if any) should be placed in the `assets` directory of t
### Update metadata
> [!Note]
> This section is outdated and we should test if it's still necessary.
Since Parcel doesn't support dynamic import (see [#112](https://github.com/parcel-bundler/parcel/issues/112) [#125](https://github.com/parcel-bundler/parcel/issues/125)), we need to run `node generate-metadata.js` to update the metadata in `index.ts`, thus we can use it in the guide components with React lazy loading.
This may be fixed by replacing Parcel with something else.

View file

@ -4,6 +4,8 @@ import classNames from 'classnames';
import { memo, useRef } from 'react';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
// TODO: @charles double check if this is still needed
/**
* Workaround for the markdown crash issue in the parcel dev build. It seems parcel does
* something clever in dev mode and messing up the `hastToReact` module. Manually adding

View file

@ -45,15 +45,7 @@ export default function koaSpaProxy<StateT, ContextT extends IRouterParamContext
getConsoleLogFromContext(ctx).plain(`\tproxy --> ${target}`);
},
rewrite: (requestPath) => {
const fullPath = '/' + path.join(prefix, requestPath);
// Static files
if (requestPath.includes('.')) {
return fullPath;
}
// In-app routes
// We'll gradually migrate our single-page apps to use vite, which can directly return the full path
return packagePath === 'demo-app' || packagePath === 'console' ? fullPath : requestPath;
return '/' + path.join(prefix, requestPath);
},
});

View file

@ -0,0 +1,2 @@
// eslint-disable-next-line import/no-unassigned-import
import 'vite/client';

View file

@ -1,6 +1,4 @@
import { createRoot } from 'react-dom/client';
// eslint-disable-next-line import/no-unassigned-import
import '@logto/core-kit/declaration';
import App from './App';

View file

@ -0,0 +1,22 @@
/** @type {import('eslint').Linter.Config} */
module.exports = {
extends: '@silverhand/react',
rules: {
'jsx-a11y/no-autofocus': 'off',
'unicorn/prefer-string-replace-all': 'off',
},
overrides: [
{
files: ['*.config.js', '*.config.ts', '*.d.ts'],
rules: {
'import/no-unused-modules': 'off',
},
},
{
files: ['*.d.ts'],
rules: {
'import/no-unassigned-import': 'off',
},
},
],
};

View file

@ -1,16 +0,0 @@
{
"extends": "@parcel/config-default",
"transformers": {
"**/assets/icons/*.svg": [
"@parcel/transformer-svg-react"
]
},
"compressors": {
"*.{html,css,js,svg,map}": [
"...",
"@parcel/compressor-gzip",
"@parcel/compressor-brotli"
]
},
"resolvers": ["parcel-resolver-ignore", "..."]
}

View file

@ -1,20 +0,0 @@
{
"extends": "@parcel/config-default",
"optimizers": {
// Disable optimizers in arm64 arch https://github.com/parcel-bundler/parcel/issues/7402
"*.{jpg,jpeg,png}": []
},
"transformers": {
"**/assets/icons/*.svg": [
"@parcel/transformer-svg-react"
]
},
"compressors": {
"*.{html,css,js,svg,map}": [
"...",
"@parcel/compressor-gzip",
"@parcel/compressor-brotli"
]
},
"resolvers": ["parcel-resolver-ignore", "..."]
}

View file

@ -14,7 +14,7 @@
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="app"></div>
<script type="module" src="index.tsx"></script>
<script type="module" src="src/index.tsx"></script>
</body>
</html>

View file

@ -25,7 +25,7 @@ const config: Config.InitialOptions = {
'\\.(png)$': 'jest-transform-stub',
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
'^@/([^?]*)(\\?.*)?$': '<rootDir>/src/$1',
'^@logto/shared/(.*)$': '<rootDir>/../shared/lib/$1',
'\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
},

View file

@ -9,10 +9,10 @@
],
"scripts": {
"precommit": "lint-staged",
"start": "parcel src/index.html",
"dev": "cross-env PORT=5001 parcel src/index.html --no-cache --hmr-port 6001",
"start": "vite",
"dev": "vite",
"check": "tsc --noEmit",
"build": "pnpm check && rm -rf dist && parcel build src/index.html --no-autoinstall --no-cache --detailed-report",
"build": "pnpm check && vite build",
"lint": "eslint --ext .ts --ext .tsx src",
"lint:report": "pnpm lint --format json --output-file report.json",
"stylelint": "stylelint \"src/**/*.scss\"",
@ -27,11 +27,6 @@
"@logto/phrases": "workspace:^1.12.0",
"@logto/phrases-experience": "workspace:^1.7.0",
"@logto/schemas": "workspace:^1.18.0",
"@parcel/compressor-brotli": "2.9.3",
"@parcel/compressor-gzip": "2.9.3",
"@parcel/core": "2.9.3",
"@parcel/transformer-sass": "2.9.3",
"@parcel/transformer-svg-react": "2.9.3",
"@react-spring/shared": "^9.6.1",
"@react-spring/web": "^9.6.1",
"@silverhand/eslint-config": "6.0.1",
@ -52,11 +47,13 @@
"@types/react-helmet": "^6.1.6",
"@types/react-modal": "^3.13.1",
"@types/react-router-dom": "^5.3.2",
"@vitejs/plugin-react": "^4.3.1",
"browserslist": "^4.23.2",
"browserslist-to-esbuild": "^2.1.1",
"camelcase-keys": "^9.1.3",
"classnames": "^2.3.1",
"color": "^4.2.3",
"core-js": "^3.34.0",
"cross-env": "^7.0.3",
"eslint": "^8.56.0",
"i18next": "^22.4.15",
"i18next-browser-languagedetector": "^8.0.0",
@ -69,8 +66,6 @@
"ky": "^1.2.3",
"libphonenumber-js": "^1.10.51",
"lint-staged": "^15.0.0",
"parcel": "2.9.3",
"parcel-resolver-ignore": "^2.1.3",
"postcss": "^8.4.31",
"postcss-modules": "^4.3.0",
"prettier": "^3.0.0",
@ -90,42 +85,13 @@
"tiny-cookie": "^2.4.1",
"typescript": "^5.5.3",
"use-debounced-loader": "^0.1.1",
"zod": "^3.23.8"
"vite": "^5.3.4",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-svgr": "^4.2.0"
},
"engines": {
"node": "^20.9.0"
},
"//": "https://github.com/parcel-bundler/parcel/issues/7636",
"targets": {
"default": {
"engines": {
"browsers": [
"defaults",
">0.3%",
"Chrome >= 52",
"Firefox >= 55",
"Safari >= 10",
"Edge >= 13",
"iOS >= 10",
"Electron >= 0.36"
]
}
}
},
"parcelIgnore": [
"^/api/.+"
],
"alias": {
"@/*": "./src/$1",
"superstruct": "./node_modules/superstruct/dist/index.mjs"
},
"eslintConfig": {
"extends": "@silverhand/react",
"rules": {
"jsx-a11y/no-autofocus": "off",
"unicorn/prefer-string-replace-all": "off"
}
},
"stylelint": {
"extends": "@silverhand/eslint-config-react/.stylelintrc"
},

View file

@ -7,7 +7,7 @@ import usePlatform from '@/hooks/use-platform';
import { layoutClassNames } from '@/utils/consts';
import CustomContent from './CustomContent';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
const AppLayout = () => {
const { isMobile } = usePlatform();

View file

@ -10,7 +10,7 @@ import PageMeta from '@/components/PageMeta';
import { layoutClassNames } from '@/utils/consts';
import { getBrandingLogoUrl } from '@/utils/logo';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type ThirdPartyBranding = ConsentInfoResponse['application']['branding'];

View file

@ -8,7 +8,7 @@ import usePlatform from '@/hooks/use-platform';
import { InlineNotification } from '../../components/Notification';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly title: TFuncKey;

View file

@ -3,7 +3,7 @@ import { type ReactNode } from 'react';
import DynamicT from '@/components/DynamicT';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly title: TFuncKey;

View file

@ -1,4 +1,4 @@
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly children: React.ReactNode;

View file

@ -10,7 +10,7 @@ import defaultAppleTouchLogo from '@/assets/apple-touch-icon.png';
import defaultFavicon from '@/assets/favicon.png';
import { type SignInExperienceResponse } from '@/types';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
const themeToFavicon = Object.freeze({
[Theme.Light]: 'favicon',

View file

@ -6,7 +6,7 @@ import LoadingBar from 'react-top-loading-bar';
import NavBar from '@/components/NavBar';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type ModalProps = {
readonly className?: string;

View file

@ -2,11 +2,11 @@ import type { Nullable } from '@silverhand/essentials';
import classNames from 'classnames';
import type { TFuncKey } from 'i18next';
import ConnectIcon from '@/assets/icons/connect-icon.svg';
import ConnectIcon from '@/assets/icons/connect-icon.svg?react';
import DynamicT from '../DynamicT';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
export type Props = {
readonly className?: string;

View file

@ -2,7 +2,7 @@ import classNames from 'classnames';
import type { HTMLProps, Ref } from 'react';
import { forwardRef } from 'react';
import * as styles from './IconButton.module.scss';
import styles from './IconButton.module.scss';
export type Props = Omit<HTMLProps<HTMLButtonElement>, 'type'>;

View file

@ -2,15 +2,15 @@ import { MfaFactor } from '@logto/schemas';
import classNames from 'classnames';
import { type TFuncKey } from 'i18next';
import ArrowNext from '@/assets/icons/arrow-next.svg';
import FactorBackupCode from '@/assets/icons/factor-backup-code.svg';
import FactorTotp from '@/assets/icons/factor-totp.svg';
import FactorWebAuthn from '@/assets/icons/factor-webauthn.svg';
import ArrowNext from '@/assets/icons/arrow-next.svg?react';
import FactorBackupCode from '@/assets/icons/factor-backup-code.svg?react';
import FactorTotp from '@/assets/icons/factor-totp.svg?react';
import FactorWebAuthn from '@/assets/icons/factor-webauthn.svg?react';
import DynamicT from '../DynamicT';
import * as mfaFactorButtonStyles from './MfaFactorButton.module.scss';
import * as styles from './index.module.scss';
import mfaFactorButtonStyles from './MfaFactorButton.module.scss';
import styles from './index.module.scss';
export type Props = {
readonly factor: MfaFactor;

View file

@ -1,6 +1,6 @@
import Ring from '@/assets/icons/loading-ring.svg';
import Ring from '@/assets/icons/loading-ring.svg?react';
import * as RotatingRingIconStyles from './RotatingRingIcon.module.scss';
import RotatingRingIconStyles from './RotatingRingIcon.module.scss';
const RotatingRingIcon = () => <Ring className={RotatingRingIconStyles.icon} />;

View file

@ -3,8 +3,8 @@ import { useTranslation } from 'react-i18next';
import { useDebouncedLoader } from 'use-debounced-loader';
import RotatingRingIcon from './RotatingRingIcon';
import * as socialLinkButtonStyles from './SocialLinkButton.module.scss';
import * as styles from './index.module.scss';
import socialLinkButtonStyles from './SocialLinkButton.module.scss';
import styles from './index.module.scss';
export type Props = {
readonly isDisabled?: boolean;

View file

@ -6,7 +6,7 @@ import { useDebouncedLoader } from 'use-debounced-loader';
import DynamicT from '../DynamicT';
import RotatingRingIcon from './RotatingRingIcon';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
export type ButtonType = 'primary' | 'secondary';

View file

@ -2,9 +2,9 @@ import classNames from 'classnames';
import type { InputHTMLAttributes, Ref } from 'react';
import { forwardRef } from 'react';
import CheckBox from '@/assets/icons/checkbox-icon.svg';
import CheckBox from '@/assets/icons/checkbox-icon.svg?react';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly size?: 'small' | 'default';

View file

@ -3,14 +3,14 @@ import { useRef } from 'react';
import { useTranslation } from 'react-i18next';
import ReactModal from 'react-modal';
import CloseIcon from '@/assets/icons/close-icon.svg';
import CloseIcon from '@/assets/icons/close-icon.svg?react';
import Button from '@/components/Button';
import IconButton from '@/components/Button/IconButton';
import { onKeyDownHandler } from '@/utils/a11y';
import * as modalStyles from '../../scss/modal.module.scss';
import modalStyles from '../../scss/modal.module.scss';
import * as styles from './Acmodal.module.scss';
import styles from './Acmodal.module.scss';
import type { ModalProps } from './type';
const AcModal = ({

View file

@ -3,9 +3,9 @@ import ReactModal from 'react-modal';
import Button from '@/components/Button';
import * as modalStyles from '../../scss/modal.module.scss';
import modalStyles from '../../scss/modal.module.scss';
import * as styles from './MobileModal.module.scss';
import styles from './MobileModal.module.scss';
import type { ModalProps } from './type';
const MobileModal = ({

View file

@ -3,7 +3,7 @@ import type { TFuncKey } from 'i18next';
import DynamicT from '../DynamicT';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly className?: string;

View file

@ -3,7 +3,7 @@ import type { TFuncKey } from 'i18next';
import type { ReactNode } from 'react';
import { useTranslation } from 'react-i18next';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type RemovePrefix<T extends string, Prefix extends T> = T extends `${Prefix}${string}` ? never : T;

View file

@ -1,6 +1,6 @@
import classNames from 'classnames';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly label: string;

View file

@ -14,7 +14,7 @@ import {
import ErrorMessage from '@/components/ErrorMessage';
import NotchedBorder from './NotchedBorder';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
export type Props = Omit<HTMLProps<HTMLInputElement>, 'prefix'> & {
readonly className?: string;

View file

@ -2,8 +2,8 @@ import type { Nullable } from '@silverhand/essentials';
import type { Ref } from 'react';
import { forwardRef, useRef, useImperativeHandle } from 'react';
import PasswordHideIcon from '@/assets/icons/password-hide-icon.svg';
import PasswordShowIcon from '@/assets/icons/password-show-icon.svg';
import PasswordHideIcon from '@/assets/icons/password-hide-icon.svg?react';
import PasswordShowIcon from '@/assets/icons/password-show-icon.svg?react';
import IconButton from '@/components/Button/IconButton';
import useToggle from '@/hooks/use-toggle';

View file

@ -3,7 +3,7 @@ import { useSpring, animated, config } from '@react-spring/web';
import type { Nullable } from '@silverhand/essentials';
import { cloneElement, useCallback, useRef, useState } from 'react';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly children: JSX.Element; // Limit to one element

View file

@ -6,8 +6,8 @@ import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import ReactModal from 'react-modal';
import CheckMark from '@/assets/icons/check-mark.svg';
import SearchIcon from '@/assets/icons/search-icon.svg';
import CheckMark from '@/assets/icons/check-mark.svg?react';
import SearchIcon from '@/assets/icons/search-icon.svg?react';
import InputField from '@/components/InputFields/InputField';
import NavBar from '@/components/NavBar';
import useDebounce from '@/hooks/use-debounce';
@ -15,7 +15,7 @@ import usePlatform from '@/hooks/use-platform';
import { onKeyDownHandler } from '@/utils/a11y';
import type { CountryMetaData } from '@/utils/country-code';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly isOpen: boolean;

View file

@ -3,12 +3,12 @@ import classNames from 'classnames';
import type { ForwardedRef } from 'react';
import { useState, useMemo, forwardRef } from 'react';
import DownArrowIcon from '@/assets/icons/arrow-down.svg';
import DownArrowIcon from '@/assets/icons/arrow-down.svg?react';
import { onKeyDownHandler } from '@/utils/a11y';
import { getCountryList, getDefaultCountryCallingCode } from '@/utils/country-code';
import CountryCodeDropdown from './CountryCodeDropdown';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly className?: string;

View file

@ -4,7 +4,7 @@ import type { Nullable } from '@silverhand/essentials';
import type { HTMLProps, Ref } from 'react';
import { useEffect, useImperativeHandle, useRef, forwardRef } from 'react';
import ClearIcon from '@/assets/icons/clear-icon.svg';
import ClearIcon from '@/assets/icons/clear-icon.svg?react';
import IconButton from '@/components/Button/IconButton';
import InputField from '../InputField';

View file

@ -1,8 +1,8 @@
import classNames from 'classnames';
import LoadingSvg from '@/assets/icons/loading-icon.svg';
import LoadingSvg from '@/assets/icons/loading-icon.svg?react';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly className?: string;

View file

@ -1,7 +1,7 @@
import LoadingMask from '../LoadingMask';
import LoadingIcon from './LoadingIcon';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
export { default as LoadingIcon } from './LoadingIcon';

View file

@ -1,6 +1,6 @@
import { type ReactNode } from 'react';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly children?: ReactNode;

View file

@ -2,11 +2,11 @@ import { Theme } from '@logto/schemas';
import { useContext } from 'react';
import PageContext from '@/Providers/PageContextProvider/PageContext';
import LogtoLogtoDark from '@/assets/icons/logto-logo-dark.svg';
import LogtoLogoLight from '@/assets/icons/logto-logo-light.svg';
import LogtoLogoShadow from '@/assets/icons/logto-logo-shadow.svg';
import LogtoLogtoDark from '@/assets/icons/logto-logo-dark.svg?react';
import LogtoLogoLight from '@/assets/icons/logto-logo-light.svg?react';
import LogtoLogoShadow from '@/assets/icons/logto-logo-shadow.svg?react';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
const logtoUrl = `https://logto.io/?${new URLSearchParams({
utm_source: 'sign_in',

View file

@ -3,11 +3,11 @@ import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import ArrowPrev from '@/assets/icons/arrow-prev.svg';
import NavClose from '@/assets/icons/nav-close.svg';
import ArrowPrev from '@/assets/icons/arrow-prev.svg?react';
import NavClose from '@/assets/icons/nav-close.svg?react';
import { onKeyDownHandler } from '@/utils/a11y';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly title?: string;

View file

@ -2,10 +2,10 @@ import classNames from 'classnames';
import type { CSSProperties, ForwardedRef, ReactNode } from 'react';
import { forwardRef } from 'react';
import InfoIcon from '@/assets/icons/info-icon.svg';
import InfoIcon from '@/assets/icons/info-icon.svg?react';
import TextLink from '@/components/TextLink';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
/* eslint-disable react/require-default-props */
type Props = {

View file

@ -3,7 +3,7 @@ import type { TFuncKey } from 'i18next';
import DynamicT from '@/components/DynamicT';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly className?: string;

View file

@ -1,4 +1,4 @@
import SwitchIcon from '@/assets/icons/switch-icon.svg';
import SwitchIcon from '@/assets/icons/switch-icon.svg?react';
import { UserMfaFlow } from '@/types';
import { type MfaFlowState } from '@/types/guard';

View file

@ -2,7 +2,7 @@ import { useTranslation } from 'react-i18next';
import TextLink, { type Props as TextLinkProps } from '@/components/TextLink';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly linkType?: TextLinkProps['type'];

View file

@ -11,7 +11,7 @@ import usePlatform from '@/hooks/use-platform';
import DynamicT from '../DynamicT';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
export type Props = AnchorHTMLAttributes<HTMLAnchorElement> & {
readonly className?: string;

View file

@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
import ReactModal from 'react-modal';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly message: string;

View file

@ -3,7 +3,7 @@ import { useMemo, useRef, useCallback, useEffect } from 'react';
import ErrorMessage from '@/components/ErrorMessage';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
export const defaultLength = 6;

View file

@ -1,4 +0,0 @@
import { yes } from '@silverhand/essentials';
export const isDevFeaturesEnabled =
process.env.NODE_ENV !== 'production' || yes(process.env.DEV_FEATURES_ENABLED);

View file

@ -2,7 +2,7 @@ import { useContext, useEffect, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import PageContext from '@/Providers/PageContextProvider/PageContext';
import DevIcon from '@/assets/icons/dev-icon.svg';
import DevIcon from '@/assets/icons/dev-icon.svg?react';
import usePlatform from '@/hooks/use-platform';
/**

View file

@ -8,7 +8,7 @@ import useStartWebAuthnProcessing from '@/hooks/use-start-webauthn-processing';
import { UserMfaFlow } from '@/types';
import { type MfaFlowState } from '@/types/guard';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly flow: UserMfaFlow;

View file

@ -8,7 +8,7 @@ import ErrorMessage from '@/components/ErrorMessage';
import { PasswordInputField } from '@/components/InputFields';
import HiddenIdentifierInput from './HiddenIdentifierInput';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly className?: string;

View file

@ -3,7 +3,7 @@ import { useCallback, useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import ClearIcon from '@/assets/icons/clear-icon.svg';
import ClearIcon from '@/assets/icons/clear-icon.svg?react';
import Button from '@/components/Button';
import IconButton from '@/components/Button/IconButton';
import ErrorMessage from '@/components/ErrorMessage';
@ -11,7 +11,7 @@ import { InputField } from '@/components/InputFields';
import HiddenIdentifierInput from './HiddenIdentifierInput';
import TogglePassword from './TogglePassword';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly className?: string;

View file

@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
import Checkbox from '@/components/Checkbox';
import { onKeyDownHandler } from '@/utils/a11y';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly isChecked?: boolean;

View file

@ -3,7 +3,7 @@ import classNames from 'classnames';
import { LoadingIcon } from '@/components/LoadingLayer';
import useConnectors from '@/hooks/use-connectors';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly className?: string;

View file

@ -11,7 +11,7 @@ import useSocialRegister from '@/hooks/use-social-register';
import type { SocialRelatedUserInfo } from '@/types/guard';
import { maskEmail, maskPhone } from '@/utils/format';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
import useBindSocialRelatedUser from './use-social-link-related-user';
type Props = {

View file

@ -6,7 +6,7 @@ import SocialLinkButton from '@/components/Button/SocialLinkButton';
import useNativeMessageListener from '@/hooks/use-native-message-listener';
import { getLogoUrl } from '@/utils/logo';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
import useSocial from './use-social';
type Props = {

View file

@ -7,7 +7,7 @@ import TermsLinks from '@/components/TermsLinks';
import useTerms from '@/hooks/use-terms';
import { onKeyDownHandler } from '@/utils/a11y';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly className?: string;

View file

@ -5,7 +5,7 @@ import Button from '@/components/Button';
import VerificationCodeInput from '@/components/VerificationCode';
import { type UserMfaFlow } from '@/types';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
import useTotpCodeVerification from './use-totp-code-verification';
const totpCodeLength = 6;

View file

@ -1,4 +1,4 @@
import SwitchIcon from '@/assets/icons/switch-icon.svg';
import SwitchIcon from '@/assets/icons/switch-icon.svg?react';
import TextLink from '@/components/TextLink';
import { UserFlow } from '@/types';

View file

@ -9,7 +9,7 @@ import VerificationCodeInput, { defaultLength } from '@/components/VerificationC
import { UserFlow } from '@/types';
import PasswordSignInLink from './PasswordSignInLink';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
import useResendVerificationCode from './use-resend-verification-code';
import { getCodeVerificationHookByFlow } from './utils';

View file

@ -1,65 +0,0 @@
// Copied from react-scripts/lib/react-app.d.ts
declare module '*.avif' {
const src: string;
export default src;
}
declare module '*.bmp' {
const src: string;
export default src;
}
declare module '*.gif' {
const src: string;
export default src;
}
declare module '*.jpg' {
const src: string;
export default src;
}
declare module '*.jpeg' {
const src: string;
export default src;
}
declare module '*.png' {
const src: string;
export default src;
}
declare module '*.webp' {
const src: string;
export default src;
}
declare module '*.svg' {
import type * as React from 'react';
export const ReactComponent: React.FunctionComponent<
React.SVGProps<SVGSVGElement> & { title?: string }
>;
const src: string;
export default src;
}
declare module '*.module.css' {
const classes: Readonly<Record<string, string>>;
export default classes;
export = classes;
}
declare module '*.module.scss' {
const classes: Readonly<Record<string, string>>;
export default classes;
export = classes;
}
declare module '*.module.sass' {
const classes: Readonly<Record<string, string>>;
export default classes;
export = classes;
}

View file

@ -6,7 +6,6 @@
* Reference: https://github.com/remix-run/react-router/issues/10241
*/
// eslint-disable-next-line import/no-unassigned-import
import 'react-router-dom';
declare module 'react-router-dom' {

View file

@ -0,0 +1,2 @@
import 'vite/client';
import 'vite-plugin-svgr/client';

View file

@ -4,7 +4,7 @@ import { useParams } from 'react-router-dom';
import StaticPageLayout from '@/Layout/StaticPageLayout';
import SocialLanding from '@/containers/SocialLanding';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
import useSocialCallbackHandler from './use-social-callback-handler';
type Parameters = {

View file

@ -2,11 +2,11 @@ import { type ConsentInfoResponse } from '@logto/schemas';
import classNames from 'classnames';
import { type ReactNode } from 'react';
import CheckMark from '@/assets/icons/check-mark.svg';
import OrganizationIcon from '@/assets/icons/organization-icon.svg';
import CheckMark from '@/assets/icons/check-mark.svg?react';
import OrganizationIcon from '@/assets/icons/organization-icon.svg?react';
import { onKeyDownHandler } from '@/utils/a11y';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
export type Organization = Exclude<ConsentInfoResponse['organizations'], undefined>[number];

View file

@ -6,7 +6,7 @@ import usePlatform from '@/hooks/use-platform';
import OrganizationItem from '../OrganizationItem';
import { type Organization } from '../OrganizationItem';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly isOpen: boolean;

View file

@ -3,13 +3,13 @@ import classNames from 'classnames';
import { useState, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import ExpandableIcon from '@/assets/icons/expandable-icon.svg';
import ExpandableIcon from '@/assets/icons/expandable-icon.svg?react';
import ScopeGroup from '../ScopeGroup';
import OrganizationItem, { type Organization } from './OrganizationItem';
import OrganizationSelectorModal from './OrganizationSelectorModal';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
export { type Organization } from './OrganizationItem';

View file

@ -2,11 +2,11 @@ import { type Nullable } from '@silverhand/essentials';
import classNames from 'classnames';
import { useState, useCallback } from 'react';
import DownArrowIcon from '@/assets/icons/arrow-down.svg';
import CheckMark from '@/assets/icons/check-mark.svg';
import DownArrowIcon from '@/assets/icons/arrow-down.svg?react';
import CheckMark from '@/assets/icons/check-mark.svg?react';
import { onKeyDownHandler } from '@/utils/a11y';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type ScopeGroupProps = {
readonly groupName: string;

View file

@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next';
import ScopeGroup from '../ScopeGroup';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
const isUserScope = (scope: string): scope is UserScope =>
Object.values<string>(UserScope).includes(scope);

View file

@ -2,9 +2,9 @@ import { type ConsentInfoResponse } from '@logto/schemas';
import classNames from 'classnames';
import { useTranslation } from 'react-i18next';
import UserAvatar from '@/assets/icons/default-user-avatar.svg';
import UserAvatar from '@/assets/icons/default-user-avatar.svg?react';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly user: ConsentInfoResponse['user'];

View file

@ -15,7 +15,7 @@ import useGlobalRedirectTo from '@/hooks/use-global-redirect-to';
import OrganizationSelector, { type Organization } from './OrganizationSelector';
import ScopesListCard from './ScopesListCard';
import UserProfile from './UserProfile';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
import { getRedirectUriOrigin } from './util';
const Consent = () => {

View file

@ -12,7 +12,7 @@ import type {
} from '@/components/InputFields/SmartInputField';
import { getGeneralIdentifierErrorMessage, validateIdentifierField } from '@/utils/form';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly className?: string;

View file

@ -7,7 +7,7 @@ import type { VerificationCodeIdentifier } from '@/types';
import { registeredSocialIdentityStateGuard } from '@/types/guard';
import { maskEmail } from '@/utils/format';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
const SocialIdentityNotification = ({
missingProfileTypes,

View file

@ -4,13 +4,13 @@ import { useContext } from 'react';
import StaticPageLayout from '@/Layout/StaticPageLayout';
import PageContext from '@/Providers/PageContextProvider/PageContext';
import EmptyStateDark from '@/assets/icons/empty-state-dark.svg';
import EmptyState from '@/assets/icons/empty-state.svg';
import EmptyStateDark from '@/assets/icons/empty-state-dark.svg?react';
import EmptyState from '@/assets/icons/empty-state.svg?react';
import DynamicT from '@/components/DynamicT';
import NavBar from '@/components/NavBar';
import PageMeta from '@/components/PageMeta';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly title?: TFuncKey;

View file

@ -12,7 +12,7 @@ import type { VerificationCodeIdentifier } from '@/types';
import { UserFlow } from '@/types';
import { getGeneralIdentifierErrorMessage, validateIdentifierField } from '@/utils/form';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly className?: string;

View file

@ -14,7 +14,7 @@ import { UserMfaFlow } from '@/types';
import { backupCodeBindingStateGuard } from '@/types/guard';
import { isNativeWebview } from '@/utils/native-sdk';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
const BackupCodeBinding = () => {
const { copyText, downloadText } = useTextHandler();

View file

@ -8,7 +8,7 @@ import usePlatform from '@/hooks/use-platform';
import useTextHandler from '@/hooks/use-text-handler';
import { type TotpBindingState } from '@/types/guard';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
const SecretSection = ({ secret, secretQrCode }: TotpBindingState) => {
const { t } = useTranslation();

View file

@ -12,7 +12,7 @@ import { totpBindingStateGuard } from '@/types/guard';
import SecretSection from './SecretSection';
import VerificationSection from './VerificationSection';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
const TotpBinding = () => {
const { state } = useLocation();

View file

@ -13,7 +13,7 @@ import { UserMfaFlow } from '@/types';
import { webAuthnStateGuard } from '@/types/guard';
import { isWebAuthnOptions } from '@/utils/webauthn';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
const WebAuthnBinding = () => {
const { state } = useLocation();

View file

@ -13,7 +13,7 @@ import useSendMfaPayload from '@/hooks/use-send-mfa-payload';
import ErrorPage from '@/pages/ErrorPage';
import { UserMfaFlow } from '@/types';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type FormState = {
code: string;

View file

@ -6,7 +6,7 @@ import useMfaFlowState from '@/hooks/use-mfa-factors-state';
import ErrorPage from '@/pages/ErrorPage';
import { UserMfaFlow } from '@/types';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
const TotpVerification = () => {
const flowState = useMfaFlowState();

View file

@ -12,7 +12,7 @@ import { UserMfaFlow } from '@/types';
import { webAuthnStateGuard } from '@/types/guard';
import { isWebAuthnOptions } from '@/utils/webauthn';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
const WebAuthnVerification = () => {
const { state } = useLocation();

View file

@ -5,7 +5,7 @@ import { Controller, useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import UserInteractionContext from '@/Providers/UserInteractionContextProvider/UserInteractionContext';
import LockIcon from '@/assets/icons/lock.svg';
import LockIcon from '@/assets/icons/lock.svg?react';
import Button from '@/components/Button';
import ErrorMessage from '@/components/ErrorMessage';
import { SmartInputField } from '@/components/InputFields';
@ -15,7 +15,7 @@ import useSingleSignOnWatch from '@/hooks/use-single-sign-on-watch';
import useTerms from '@/hooks/use-terms';
import { getGeneralIdentifierErrorMessage, validateIdentifierField } from '@/utils/form';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
import useOnSubmit from './use-on-submit';
type Props = {

View file

@ -18,7 +18,7 @@ import useTerms from '@/hooks/use-terms';
import ErrorPage from '../ErrorPage';
import IdentifierRegisterForm from './IdentifierRegisterForm';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
const RegisterFooter = () => {
const { t } = useTranslation();

View file

@ -5,7 +5,7 @@ import { useForm, Controller } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import UserInteractionContext from '@/Providers/UserInteractionContextProvider/UserInteractionContext';
import LockIcon from '@/assets/icons/lock.svg';
import LockIcon from '@/assets/icons/lock.svg?react';
import Button from '@/components/Button';
import ErrorMessage from '@/components/ErrorMessage';
import { SmartInputField } from '@/components/InputFields';
@ -15,7 +15,7 @@ import useSingleSignOnWatch from '@/hooks/use-single-sign-on-watch';
import useTerms from '@/hooks/use-terms';
import { getGeneralIdentifierErrorMessage, validateIdentifierField } from '@/utils/form';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
import useOnSubmit from './use-on-submit';
type Props = {

View file

@ -6,7 +6,7 @@ import useTerms from '@/hooks/use-terms';
import IdentifierSignInForm from './IdentifierSignInForm';
import PasswordSignInForm from './PasswordSignInForm';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly signInMethods: SignIn['methods'];

View file

@ -5,7 +5,7 @@ import { useForm, Controller } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import UserInteractionContext from '@/Providers/UserInteractionContextProvider/UserInteractionContext';
import LockIcon from '@/assets/icons/lock.svg';
import LockIcon from '@/assets/icons/lock.svg?react';
import Button from '@/components/Button';
import ErrorMessage from '@/components/ErrorMessage';
import { SmartInputField, PasswordInputField } from '@/components/InputFields';
@ -18,7 +18,7 @@ import useSingleSignOnWatch from '@/hooks/use-single-sign-on-watch';
import useTerms from '@/hooks/use-terms';
import { getGeneralIdentifierErrorMessage, validateIdentifierField } from '@/utils/form';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type Props = {
readonly className?: string;

View file

@ -18,7 +18,7 @@ import useTerms from '@/hooks/use-terms';
import ErrorPage from '../ErrorPage';
import Main from './Main';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
const SignInFooters = () => {
const { t } = useTranslation();

View file

@ -1,6 +1,6 @@
import { useEffect } from 'react';
import SwitchIcon from '@/assets/icons/switch-icon.svg';
import SwitchIcon from '@/assets/icons/switch-icon.svg?react';
import TextLink from '@/components/TextLink';
import useSendVerificationCode from '@/hooks/use-send-verification-code';
import useToast from '@/hooks/use-toast';

View file

@ -13,7 +13,7 @@ import ForgotPasswordLink from '@/containers/ForgotPasswordLink';
import usePasswordSignIn from '@/hooks/use-password-sign-in';
import { useForgotPasswordSettings } from '@/hooks/use-sie';
import * as styles from '../index.module.scss';
import styles from '../index.module.scss';
import VerificationCodeLink from './VerificationCodeLink';

View file

@ -9,7 +9,7 @@ import useNativeMessageListener from '@/hooks/use-native-message-listener';
import useSingleSignOn from '@/hooks/use-single-sign-on';
import { getLogoUrl } from '@/utils/logo';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
const SingleSignOnConnectors = () => {
const { theme } = useContext(PageContext);

View file

@ -4,7 +4,7 @@ import { Controller, useForm } from 'react-hook-form';
import SecondaryPageLayout from '@/Layout/SecondaryPageLayout';
import UserInteractionContext from '@/Providers/UserInteractionContextProvider/UserInteractionContext';
import LockIcon from '@/assets/icons/lock.svg';
import LockIcon from '@/assets/icons/lock.svg?react';
import Button from '@/components/Button';
import ErrorMessage from '@/components/ErrorMessage';
import SmartInputField, {
@ -13,7 +13,7 @@ import SmartInputField, {
import useOnSubmit from '@/hooks/use-check-single-sign-on';
import { getGeneralIdentifierErrorMessage, validateIdentifierField } from '@/utils/form';
import * as styles from './index.module.scss';
import styles from './index.module.scss';
type FormState = {
identifier: IdentifierInputValue;

Some files were not shown because too many files have changed in this diff Show more