Fix ESLint errors, add some docs (#11339)

- Fix ESLint errors
- Add documentation for *some* functions with blank documentation

# Important Notes
None
This commit is contained in:
somebody1234 2024-10-21 22:56:39 +10:00 committed by GitHub
parent 45ad3a751c
commit 5faddf52f0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
231 changed files with 2204 additions and 1726 deletions

View File

@ -26,7 +26,8 @@
"./src/types": "./src/types.d.ts"
},
"scripts": {
"test": "vitest run"
"test": "vitest run",
"lint": "eslint . --max-warnings=0"
},
"peerDependencies": {
"@tanstack/query-core": "5.54.1",

View File

@ -4,17 +4,19 @@
// === AccessToken ===
// ===================
/** Payload for the `save-access-token` event that saves an access token to a credentials file. */
/** Credentials to be saved to a credentials file. */
export interface AccessToken {
/** The JWT token to save. */
/** The user's JWT token. */
readonly accessToken: string
/** The Cognito app integration client id. */
/** The ID for the Cognito app integration. */
readonly clientId: string
/** The refresh token taken from authorization flow. */
/** The refresh token taken from the authorization flow. */
readonly refreshToken: string
/** The Cognito url to refresh the token. */
/** The Cognito URL to refresh the token. */
readonly refreshUrl: string
/** The when the token will expire.
* This is a string representation of a date in ISO 8601 format (e.g. "2021-01-01T00:00:00Z"). */
/**
* The expiry time of the token.
* This is a string representation of a date in ISO 8601 format (e.g. "2021-01-01T00:00:00Z").
*/
readonly expireAt: string
}

View File

@ -1,17 +1,21 @@
/** @file Functions for managing app configuration. */
/** Read environment variables from a file based on the `ENSO_CLOUD_ENV_FILE_NAME`
/**
* Read environment variables from a file based on the `ENSO_CLOUD_ENV_FILE_NAME`
* environment variable. Reads from `.env` if the variable is blank or absent.
* DOES NOT override existing environment variables if the variable is absent. */
* DOES NOT override existing environment variables if the variable is absent.
*/
export function readEnvironmentFromFile(): Promise<void>
/** An object containing app configuration to inject.
/**
* An object containing app configuration to inject.
*
* This includes:
* - the base URL for backend endpoints
* - the WebSocket URL for the chatbot
* - the unique identifier for the cloud environment, for use in Sentry logs
* - Stripe, Sentry and Amplify public keys */
* - Stripe, Sentry and Amplify public keys
*/
export function getDefines(serverPort?: number): Record<string, string>
/** Load test environment variables, useful for when the Cloud backend is mocked or unnecessary. */

View File

@ -1,6 +1,7 @@
/** @file Functions for managing app configuration. */
import * as fs from 'node:fs/promises'
import * as path from 'node:path'
import * as process from 'node:process'
import * as url from 'node:url'
// ===============================
@ -19,14 +20,13 @@ export async function readEnvironmentFromFile() {
const filePath = path.join(url.fileURLToPath(new URL('../..', import.meta.url)), fileName)
const buildInfo = await (async () => {
try {
return await import('../../../../build.json', { with: { type: 'json' } })
return await import('../../../build.json', { with: { type: 'json' } })
} catch {
return { commit: '', version: '', engineVersion: '', name: '' }
}
})()
try {
const file = await fs.readFile(filePath, { encoding: 'utf-8' })
// eslint-disable-next-line jsdoc/valid-types
/** @type {readonly (readonly [string, string])[]} */
let entries = file.split('\n').flatMap(line => {
if (/^\s*$|^.s*#/.test(line)) {
@ -47,14 +47,10 @@ export async function readEnvironmentFromFile() {
if (!isProduction || entries.length > 0) {
Object.assign(process.env, variables)
}
// @ts-expect-error This is the only file where `process.env` should be written to.
process.env.ENSO_CLOUD_DASHBOARD_VERSION ??= buildInfo.version
// @ts-expect-error This is the only file where `process.env` should be written to.
process.env.ENSO_CLOUD_DASHBOARD_COMMIT_HASH ??= buildInfo.commit
} catch (error) {
// @ts-expect-error This is the only file where `process.env` should be written to.
process.env.ENSO_CLOUD_DASHBOARD_VERSION ??= buildInfo.version
// @ts-expect-error This is the only file where `process.env` should be written to.
process.env.ENSO_CLOUD_DASHBOARD_COMMIT_HASH ??= buildInfo.commit
const expectedKeys = Object.keys(DUMMY_DEFINES)
.map(key => key.replace(/^process[.]env[.]/, ''))
@ -147,7 +143,6 @@ const DUMMY_DEFINES = {
/** Load test environment variables, useful for when the Cloud backend is mocked or unnecessary. */
export function loadTestEnvironmentVariables() {
for (const [k, v] of Object.entries(DUMMY_DEFINES)) {
// @ts-expect-error This is the only file where `process.env` should be written to.
process.env[k.replace(/^process[.]env[.]/, '')] = v
}
}

View File

@ -3,26 +3,34 @@
/** Indent size for stringifying JSON. */
export const INDENT_SIZE: number
/** Get the environment variable value.
/**
* Get the environment variable value.
* @param name - The name of the environment variable.
* @returns The value of the environment variable.
* @throws {Error} If the environment variable is not set. */
* @throws {Error} If the environment variable is not set.
*/
export function requireEnv(name: string): string
/** Read the path from environment variable and resolve it.
/**
* Read the path from environment variable and resolve it.
* @param name - The name of the environment variable.
* @returns The resolved path.
* @throws {Error} If the environment variable is not set. */
* @throws {Error} If the environment variable is not set.
*/
export function requireEnvResolvedPath(name: string): string
/** Read the path from environment variable and resolve it. Verify that it exists.
/**
* Read the path from environment variable and resolve it. Verify that it exists.
* @param name - The name of the environment variable.
* @returns The resolved path.
* @throws {Error} If the environment variable is not set or path does not exist. */
* @throws {Error} If the environment variable is not set or path does not exist.
*/
export function requireEnvPathExist(name: string): string
/** Get the common prefix of the two strings.
/**
* Get the common prefix of the two strings.
* @param a - the first string.
* @param b - the second string.
* @returns The common prefix. */
* @returns The common prefix.
*/
export function getCommonPrefix(a: string, b: string): string

View File

@ -23,8 +23,10 @@ export enum Platform {
android = 'Android',
}
/** The platform the app is currently running on.
* This is used to determine whether `metaKey` or `ctrlKey` is used in shortcuts. */
/**
* The platform the app is currently running on.
* This is used to determine whether `metaKey` or `ctrlKey` is used in shortcuts.
*/
export function platform() {
if (isOnWindowsPhone()) {
// MUST be before Android and Windows.
@ -96,8 +98,10 @@ export enum Browser {
opera = 'Opera',
}
/** Return the platform the app is currently running on.
* This is used to determine whether `metaKey` or `ctrlKey` is used in shortcuts. */
/**
* Return the platform the app is currently running on.
* This is used to determine whether `metaKey` or `ctrlKey` is used in shortcuts.
*/
export function browser(): Browser {
if (isOnElectron()) {
return Browser.electron
@ -117,10 +121,12 @@ export function browser(): Browser {
return Browser.unknown
}
}
/** Returns `true` if running in Electron, else `false`.
/**
* Returns `true` if running in Electron, else `false`.
* This is used to determine whether to use a `MemoryRouter` (stores history in an array)
* or a `BrowserRouter` (stores history in the path of the URL).
* It is also used to determine whether to send custom state to Amplify for a workaround. */
* It is also used to determine whether to send custom state to Amplify for a workaround.
*/
export function isOnElectron() {
return /electron/i.test(navigator.userAgent)
}

View File

@ -17,7 +17,7 @@ window.dataLayer = window.dataLayer || []
export function gtag(_action: 'config' | 'event' | 'js' | 'set', ..._args: unknown[]) {
// @ts-expect-error This is explicitly not given types as it is a mistake to acess this
// anywhere else.
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, prefer-rest-params
window.dataLayer.push(arguments)
}
@ -27,7 +27,7 @@ export function event(name: string, params?: object) {
}
gtag('js', new Date())
// eslint-disable-next-line @typescript-eslint/naming-convention
// eslint-disable-next-line @typescript-eslint/naming-convention, camelcase
gtag('set', 'linker', { accept_incoming: true })
gtag('config', GOOGLE_ANALYTICS_TAG)
if (GOOGLE_ANALYTICS_TAG === 'G-CLTBJ37MDM') {

View File

@ -1,18 +1,22 @@
/** @file This module contains metadata about the product and distribution,
/**
* @file This module contains metadata about the product and distribution,
* and various other constants that are needed in multiple sibling packages.
*
* Code in this package is used by two or more sibling packages of this package. The code is defined
* here when it is not possible for a sibling package to own that code without introducing a
* circular dependency in our packages. */
* circular dependency in our packages.
*/
// ========================
// === Product metadata ===
// ========================
/** URL protocol scheme for deep links to authentication flow pages, without the `:` suffix.
/**
* URL protocol scheme for deep links to authentication flow pages, without the `:` suffix.
*
* For example: the deep link URL
* `enso://authentication/register?code=...&state=...` uses this scheme. */
* `enso://authentication/register?code=...&state=...` uses this scheme.
*/
export const DEEP_LINK_SCHEME: string
/** Name of the product. */
@ -21,12 +25,16 @@ export const PRODUCT_NAME: string
/** Company name, used as the copyright holder. */
export const COMPANY_NAME: string
/** The domain on which the Cloud Dashboard web app is hosted.
* Excludes the protocol (`https://`). */
/**
* The domain on which the Cloud Dashboard web app is hosted.
* Excludes the protocol (`https://`).
*/
export const CLOUD_DASHBOARD_DOMAIN: string
/** COOP, COEP, and CORP headers: https://web.dev/coop-coep/
/**
* COOP, COEP, and CORP headers: https://web.dev/coop-coep/
*
* These are required to increase the resolution of `performance.now()` timers,
* making profiling a lot more accurate and consistent. */
* making profiling a lot more accurate and consistent.
*/
export const COOP_COEP_CORP_HEADERS: [header: string, value: string][]

View File

@ -10,9 +10,7 @@ import * as vueQuery from '@tanstack/vue-query'
import * as idbKeyval from 'idb-keyval'
declare module '@tanstack/query-core' {
/**
* Query client with additional methods.
*/
/** Query client with additional methods. */
interface QueryClient {
/**
* Clear the cache stored in Tanstack Query and the persister storage.
@ -20,19 +18,13 @@ declare module '@tanstack/query-core' {
* Usually you should use `queryClient.invalidateQueries` instead.
*/
readonly clearWithPersister: () => Promise<void>
/**
* Clear the cache stored in the persister storage.
*/
/** Clear the cache stored in the persister storage. */
readonly nukePersister: () => Promise<void>
}
/**
* Specifies the invalidation behavior of a mutation.
*/
/** Specifies the invalidation behavior of a mutation. */
interface Register {
readonly mutationMeta: {
/**
* List of query keys to invalidate when the mutation succeeds.
*/
/** List of query keys to invalidate when the mutation succeeds. */
readonly invalidates?: queryCore.QueryKey[]
/**
* List of query keys to await invalidation before the mutation is considered successful.
@ -71,9 +63,7 @@ const DEFAULT_QUERY_PERSIST_TIME_MS = 30 * 24 * 60 * 60 * 1000 // 30 days
const DEFAULT_BUSTER = 'v1.1'
/**
* Create a new Tanstack Query client.
*/
/** Create a new Tanstack Query client. */
export function createQueryClient(): QueryClient {
const store = idbKeyval.createStore('enso', 'query-persist-cache')
queryCore.onlineManager.setOnline(navigator.onLine)

View File

@ -29,8 +29,10 @@ export const UserGroupId = newtype.newtypeConstructor<UserGroupId>()
export type DirectoryId = newtype.Newtype<string, 'DirectoryId'>
export const DirectoryId = newtype.newtypeConstructor<DirectoryId>()
/** Unique identifier for an asset representing the items inside a directory for which the
* request to retrive the items has not yet completed. */
/**
* Unique identifier for an asset representing the items inside a directory for which the
* request to retrive the items has not yet completed.
*/
export type LoadingAssetId = newtype.Newtype<string, 'LoadingAssetId'>
export const LoadingAssetId = newtype.newtypeConstructor<LoadingAssetId>()
@ -38,8 +40,10 @@ export const LoadingAssetId = newtype.newtypeConstructor<LoadingAssetId>()
export type EmptyAssetId = newtype.Newtype<string, 'EmptyAssetId'>
export const EmptyAssetId = newtype.newtypeConstructor<EmptyAssetId>()
/** Unique identifier for an asset representing the nonexistent children of a directory
* that failed to fetch. */
/**
* Unique identifier for an asset representing the nonexistent children of a directory
* that failed to fetch.
*/
export type ErrorAssetId = newtype.Newtype<string, 'ErrorAssetId'>
export const ErrorAssetId = newtype.newtypeConstructor<ErrorAssetId>()
@ -74,9 +78,7 @@ export type AssetId = IdType[keyof IdType]
export type CheckoutSessionId = newtype.Newtype<string, 'CheckoutSessionId'>
export const CheckoutSessionId = newtype.newtypeConstructor<CheckoutSessionId>()
/**
* Unique identifier for a subscription.
*/
/** Unique identifier for a subscription. */
export type SubscriptionId = newtype.Newtype<string, 'SubscriptionId'>
export const SubscriptionId = newtype.newtypeConstructor<SubscriptionId>()
@ -129,14 +131,18 @@ export function isUserGroupId(id: string): id is UserGroupId {
const PLACEHOLDER_USER_GROUP_PREFIX = 'usergroup-placeholder-'
/** Whether a given {@link UserGroupId} represents a user group that does not yet exist on the
* server. */
/**
* Whether a given {@link UserGroupId} represents a user group that does not yet exist on the
* server.
*/
export function isPlaceholderUserGroupId(id: string) {
return id.startsWith(PLACEHOLDER_USER_GROUP_PREFIX)
}
/** Return a new {@link UserGroupId} that represents a placeholder user group that is yet to finish
* being created on the backend. */
/**
* Return a new {@link UserGroupId} that represents a placeholder user group that is yet to finish
* being created on the backend.
*/
export function newPlaceholderUserGroupId() {
return UserGroupId(`${PLACEHOLDER_USER_GROUP_PREFIX}${uniqueString.uniqueString()}`)
}
@ -153,17 +159,21 @@ export enum BackendType {
/** Metadata uniquely identifying a user inside an organization. */
export interface UserInfo {
/** The ID of the parent organization. If this is a sole user, they are implicitly in an
* organization consisting of only themselves. */
/**
* The ID of the parent organization. If this is a sole user, they are implicitly in an
* organization consisting of only themselves.
*/
readonly organizationId: OrganizationId
/** The name of the parent organization. */
readonly organizationName?: string
/** The ID of this user.
/**
* The ID of this user.
*
* The user ID is globally unique. Thus, the user ID is always sufficient to uniquely identify a
* user. The user ID is guaranteed to never change, once assigned. For these reasons, the user ID
* should be the preferred way to uniquely refer to a user. That is, when referring to a user,
* prefer this field over `name`, `email`, `subject`, or any other mechanism, where possible. */
* prefer this field over `name`, `email`, `subject`, or any other mechanism, where possible.
*/
readonly userId: UserId
readonly name: string
readonly email: EmailAddress
@ -173,8 +183,10 @@ export interface UserInfo {
/** A user in the application. These are the primary owners of a project. */
export interface User extends UserInfo {
/** If `false`, this account is awaiting acceptance from an administrator, and endpoints other than
* `usersMe` will not work. */
/**
* If `false`, this account is awaiting acceptance from an administrator, and endpoints other than
* `usersMe` will not work.
*/
readonly isEnabled: boolean
readonly isOrganizationAdmin: boolean
readonly rootDirectoryId: DirectoryId
@ -200,11 +212,15 @@ export enum ProjectState {
provisioned = 'Provisioned',
opened = 'Opened',
closed = 'Closed',
/** A frontend-specific state, representing a project that should be displayed as
* `openInProgress`, but has not yet been added to the backend. */
/**
* A frontend-specific state, representing a project that should be displayed as
* `openInProgress`, but has not yet been added to the backend.
*/
placeholder = 'Placeholder',
/** A frontend-specific state, representing a project that should be displayed as `closed`,
* but is still in the process of shutting down. */
/**
* A frontend-specific state, representing a project that should be displayed as `closed`,
* but is still in the process of shutting down.
*/
closing = 'Closing',
}
@ -374,11 +390,13 @@ export interface Label {
readonly color: LChColor
}
/** Type of application that a {@link Version} applies to.
/**
* Type of application that a {@link Version} applies to.
*
* We keep track of both backend and IDE versions, so that we can update the two independently.
* However the format of the version numbers is the same for both, so we can use the same type for
* both. We just need this enum to disambiguate. */
* both. We just need this enum to disambiguate.
*/
export enum VersionType {
backend = 'Backend',
ide = 'Ide',
@ -458,9 +476,7 @@ export interface ResourceUsage {
readonly storage: number
}
/**
* Metadata for a subscription.
*/
/** Metadata for a subscription. */
export interface Subscription {
readonly id?: SubscriptionId
readonly plan?: Plan
@ -566,7 +582,7 @@ export interface UpdatedDirectory {
}
/** The type returned from the "create directory" endpoint. */
export interface Directory extends DirectoryAsset {}
export type Directory = DirectoryAsset
/** The subset of asset fields returned by the "copy asset" endpoint. */
export interface CopiedAsset {
@ -711,8 +727,10 @@ export enum AssetType {
secret = 'secret',
datalink = 'datalink',
directory = 'directory',
/** A special {@link AssetType} representing the unknown items of a directory, before the
* request to retrieve the items completes. */
/**
* A special {@link AssetType} representing the unknown items of a directory, before the
* request to retrieve the items completes.
*/
specialLoading = 'specialLoading',
/** A special {@link AssetType} representing a directory listing that is empty. */
specialEmpty = 'specialEmpty',
@ -732,8 +750,10 @@ export interface IdType {
readonly [AssetType.specialError]: ErrorAssetId
}
/** Integers (starting from 0) corresponding to the order in which each asset type should appear
* in a directory listing. */
/**
* Integers (starting from 0) corresponding to the order in which each asset type should appear
* in a directory listing.
*/
export const ASSET_TYPE_ORDER: Readonly<Record<AssetType, number>> = {
// This is a sequence of numbers, not magic numbers. `1000` is an arbitrary number
// that are higher than the number of possible asset types.
@ -753,22 +773,28 @@ export const ASSET_TYPE_ORDER: Readonly<Record<AssetType, number>> = {
// === Asset ===
// =============
/** Metadata uniquely identifying a directory entry.
* These can be Projects, Files, Secrets, or other directories. */
/**
* Metadata uniquely identifying a directory entry.
* These can be Projects, Files, Secrets, or other directories.
*/
export interface BaseAsset {
readonly id: AssetId
readonly title: string
readonly modifiedAt: dateTime.Rfc3339DateTime
/** This is defined as a generic {@link AssetId} in the backend, however it is more convenient
* (and currently safe) to assume it is always a {@link DirectoryId}. */
/**
* This is defined as a generic {@link AssetId} in the backend, however it is more convenient
* (and currently safe) to assume it is always a {@link DirectoryId}.
*/
readonly parentId: DirectoryId
readonly permissions: readonly AssetPermission[] | null
readonly labels: readonly LabelName[] | null
readonly description: string | null
}
/** Metadata uniquely identifying a directory entry.
* These can be Projects, Files, Secrets, or other directories. */
/**
* Metadata uniquely identifying a directory entry.
* These can be Projects, Files, Secrets, or other directories.
*/
export interface Asset<Type extends AssetType = AssetType> extends BaseAsset {
readonly type: Type
readonly id: IdType[Type]
@ -776,31 +802,33 @@ export interface Asset<Type extends AssetType = AssetType> extends BaseAsset {
}
/** A convenience alias for {@link Asset}<{@link AssetType.directory}>. */
export interface DirectoryAsset extends Asset<AssetType.directory> {}
export type DirectoryAsset = Asset<AssetType.directory>
/** A convenience alias for {@link Asset}<{@link AssetType.project}>. */
export interface ProjectAsset extends Asset<AssetType.project> {}
export type ProjectAsset = Asset<AssetType.project>
/** A convenience alias for {@link Asset}<{@link AssetType.file}>. */
export interface FileAsset extends Asset<AssetType.file> {}
export type FileAsset = Asset<AssetType.file>
/** A convenience alias for {@link Asset}<{@link AssetType.datalink}>. */
export interface DatalinkAsset extends Asset<AssetType.datalink> {}
export type DatalinkAsset = Asset<AssetType.datalink>
/** A convenience alias for {@link Asset}<{@link AssetType.secret}>. */
export interface SecretAsset extends Asset<AssetType.secret> {}
export type SecretAsset = Asset<AssetType.secret>
/** A convenience alias for {@link Asset}<{@link AssetType.specialLoading}>. */
export interface SpecialLoadingAsset extends Asset<AssetType.specialLoading> {}
export type SpecialLoadingAsset = Asset<AssetType.specialLoading>
/** A convenience alias for {@link Asset}<{@link AssetType.specialEmpty}>. */
export interface SpecialEmptyAsset extends Asset<AssetType.specialEmpty> {}
export type SpecialEmptyAsset = Asset<AssetType.specialEmpty>
/** A convenience alias for {@link Asset}<{@link AssetType.specialError}>. */
export interface SpecialErrorAsset extends Asset<AssetType.specialError> {}
export type SpecialErrorAsset = Asset<AssetType.specialError>
/** Creates a {@link DirectoryAsset} representing the root directory for the organization,
* with all irrelevant fields initialized to default values. */
/**
* Creates a {@link DirectoryAsset} representing the root directory for the organization,
* with all irrelevant fields initialized to default values.
*/
export function createRootDirectoryAsset(directoryId: DirectoryId): DirectoryAsset {
return {
type: AssetType.directory,
@ -860,8 +888,10 @@ export function createPlaceholderProjectAsset(
}
}
/** Creates a {@link SpecialLoadingAsset}, with all irrelevant fields initialized to default
* values. */
/**
* Creates a {@link SpecialLoadingAsset}, with all irrelevant fields initialized to default
* values.
*/
export function createSpecialLoadingAsset(directoryId: DirectoryId): SpecialLoadingAsset {
return {
type: AssetType.specialLoading,
@ -876,8 +906,10 @@ export function createSpecialLoadingAsset(directoryId: DirectoryId): SpecialLoad
}
}
/** Creates a {@link SpecialEmptyAsset}, with all irrelevant fields initialized to default
* values. */
/**
* Creates a {@link SpecialEmptyAsset}, with all irrelevant fields initialized to default
* values.
*/
export function createSpecialEmptyAsset(directoryId: DirectoryId): SpecialEmptyAsset {
return {
type: AssetType.specialEmpty,
@ -892,8 +924,10 @@ export function createSpecialEmptyAsset(directoryId: DirectoryId): SpecialEmptyA
}
}
/** Creates a {@link SpecialErrorAsset}, with all irrelevant fields initialized to default
* values. */
/**
* Creates a {@link SpecialErrorAsset}, with all irrelevant fields initialized to default
* values.
*/
export function createSpecialErrorAsset(directoryId: DirectoryId): SpecialErrorAsset {
return {
type: AssetType.specialError,
@ -1011,8 +1045,10 @@ export interface AssetVersions {
// === compareAssetPermissions ===
// ===============================
/** Return a positive number when `a > b`, a negative number when `a < b`, and `0`
* when `a === b`. */
/**
* Return a positive number when `a > b`, a negative number when `a < b`, and `0`
* when `a === b`.
*/
export function compareAssetPermissions(a: AssetPermission, b: AssetPermission) {
const relativePermissionPrecedence =
permissions.PERMISSION_ACTION_PRECEDENCE[a.permission] -
@ -1126,8 +1162,10 @@ export interface CreateProjectRequestBody {
readonly datalinkId?: DatalinkId
}
/** HTTP request body for the "update project" endpoint.
* Only updates of the `projectName` or `ami` are allowed. */
/**
* HTTP request body for the "update project" endpoint.
* Only updates of the `projectName` or `ami` are allowed.
*/
export interface UpdateProjectRequestBody {
readonly projectName: string | null
readonly ami: Ami | null
@ -1256,8 +1294,10 @@ export function compareAssets(a: AnyAsset, b: AnyAsset) {
// === getAssetId ===
// ==================
/** A convenience function to get the `id` of an {@link Asset}.
* This is useful to avoid React re-renders as it is not re-created on each function call. */
/**
* A convenience function to get the `id` of an {@link Asset}.
* This is useful to avoid React re-renders as it is not re-created on each function call.
*/
export function getAssetId<Type extends AssetType>(asset: Asset<Type>) {
return asset.id
}
@ -1313,16 +1353,16 @@ export function stripProjectExtension(name: string) {
return name.replace(/[.](?:tar[.]gz|zip|enso-project)$/, '')
}
/** Return both the name and extension of the project file name (if any).
* Otherwise, returns the entire name as the basename. */
/**
* Return both the name and extension of the project file name (if any).
* Otherwise, returns the entire name as the basename.
*/
export function extractProjectExtension(name: string) {
const [, basename, extension] = name.match(/^(.*)[.](tar[.]gz|zip|enso-project)$/) ?? []
return { basename: basename ?? name, extension: extension ?? '' }
}
/**
* Network error class.
*/
/** Network error class. */
export class NetworkError extends Error {
/**
* Create a new instance of the {@link NetworkError} class.
@ -1336,9 +1376,7 @@ export class NetworkError extends Error {
super(message)
}
}
/**
* Error class for when the user is not authorized to access a resource.
*/
/** Error class for when the user is not authorized to access a resource. */
export class NotAuthorizedError extends NetworkError {}
// ===============

View File

@ -15,15 +15,19 @@ export function shallowEqual<T>(a: readonly T[], b: readonly T[]) {
// === includes ===
// ================
/** Returns a type predicate that returns true if and only if the value is in the array.
* The array MUST contain every element of `T`. */
/**
* Returns a type predicate that returns true if and only if the value is in the array.
* The array MUST contain every element of `T`.
*/
export function includes<T>(array: T[], item: unknown): item is T {
const arrayOfUnknown: unknown[] = array
return arrayOfUnknown.includes(item)
}
/** Returns a type predicate that returns true if and only if the value is in the iterable.
* The iterable MUST contain every element of `T`. */
/**
* Returns a type predicate that returns true if and only if the value is in the iterable.
* The iterable MUST contain every element of `T`.
*/
export function includesPredicate<T>(array: Iterable<T>) {
const set: Set<unknown> = array instanceof Set ? array : new Set<T>(array)
return (item: unknown): item is T => set.has(item)
@ -36,32 +40,40 @@ export function includesPredicate<T>(array: Iterable<T>) {
/** The value returned when {@link Array.findIndex} fails. */
const NOT_FOUND = -1
/** Insert items before the first index `i` for which `predicate(array[i])` is `true`.
* Insert the items at the end if the `predicate` never returns `true`. */
/**
* Insert items before the first index `i` for which `predicate(array[i])` is `true`.
* Insert the items at the end if the `predicate` never returns `true`.
*/
export function spliceBefore<T>(array: T[], items: T[], predicate: (value: T) => boolean) {
const index = array.findIndex(predicate)
array.splice(index === NOT_FOUND ? array.length : index, 0, ...items)
return array
}
/** Return a copy of the array, with items inserted before the first index `i` for which
/**
* Return a copy of the array, with items inserted before the first index `i` for which
* `predicate(array[i])` is `true`. The items are inserted at the end if the `predicate` never
* returns `true`. */
* returns `true`.
*/
export function splicedBefore<T>(array: T[], items: T[], predicate: (value: T) => boolean) {
return spliceBefore(Array.from(array), items, predicate)
}
/** Insert items after the first index `i` for which `predicate(array[i])` is `true`.
* Insert the items at the end if the `predicate` never returns `true`. */
/**
* Insert items after the first index `i` for which `predicate(array[i])` is `true`.
* Insert the items at the end if the `predicate` never returns `true`.
*/
export function spliceAfter<T>(array: T[], items: T[], predicate: (value: T) => boolean) {
const index = array.findIndex(predicate)
array.splice(index === NOT_FOUND ? array.length : index + 1, 0, ...items)
return array
}
/** Return a copy of the array, with items inserted after the first index `i` for which
/**
* Return a copy of the array, with items inserted after the first index `i` for which
* `predicate(array[i])` is `true`. The items are inserted at the end if the `predicate` never
* returns `true`. */
* returns `true`.
*/
export function splicedAfter<T>(array: T[], items: T[], predicate: (value: T) => boolean) {
return spliceAfter(Array.from(array), items, predicate)
}

View File

@ -35,8 +35,10 @@ export type Rfc3339DateTime = newtype.Newtype<string, 'Rfc3339DateTime'>
// eslint-disable-next-line @typescript-eslint/no-redeclare
export const Rfc3339DateTime = newtype.newtypeConstructor<Rfc3339DateTime>()
/** Return a new {@link Date} with units below days (hours, minutes, seconds and milliseconds)
* set to `0`. */
/**
* Return a new {@link Date} with units below days (hours, minutes, seconds and milliseconds)
* set to `0`.
*/
export function toDate(dateTime: Date) {
return new Date(dateTime.getFullYear(), dateTime.getMonth(), dateTime.getDate())
}

View File

@ -12,8 +12,10 @@ type NewtypeVariant<TypeName extends string> = {
readonly _$type: TypeName
}
/** An interface specifying the variant of a newtype, where the discriminator is mutable.
* This is safe, as the discriminator should be a string literal type anyway. */
/**
* An interface specifying the variant of a newtype, where the discriminator is mutable.
* This is safe, as the discriminator should be a string literal type anyway.
*/
// This is required for compatibility with the dependency `enso-chat`.
// eslint-disable-next-line no-restricted-syntax
type MutableNewtypeVariant<TypeName extends string> = {
@ -21,7 +23,8 @@ type MutableNewtypeVariant<TypeName extends string> = {
_$type: TypeName
}
/** Used to create a "branded type",
/**
* Used to create a "branded type",
* which contains a property that only exists at compile time.
*
* `Newtype<string, 'A'>` and `Newtype<string, 'B'>` are not compatible with each other,
@ -33,11 +36,14 @@ type MutableNewtypeVariant<TypeName extends string> = {
* It is similar to a `newtype` in other languages.
* Note however because TypeScript is structurally typed,
* a branded type is assignable to its base type:
* `a: string = asNewtype<Newtype<string, 'Name'>>(b)` successfully typechecks. */
* `a: string = asNewtype<Newtype<string, 'Name'>>(b)` successfully typechecks.
*/
export type Newtype<T, TypeName extends string> = NewtypeVariant<TypeName> & T
/** Extracts the original type out of a {@link Newtype}.
* Its only use is in {@link newtypeConstructor}. */
/**
* Extracts the original type out of a {@link Newtype}.
* Its only use is in {@link newtypeConstructor}.
*/
type UnNewtype<T extends Newtype<unknown, string>> =
T extends infer U & NewtypeVariant<T['_$type']> ?
U extends infer V & MutableNewtypeVariant<T['_$type']> ?
@ -51,9 +57,11 @@ type NotNewtype = {
readonly _$type?: never
}
/** Converts a value that is not a newtype, to a value that is a newtype.
/**
* Converts a value that is not a newtype, to a value that is a newtype.
* This function intentionally returns another function, to ensure that each function instance
* is only used for one type, avoiding the de-optimization caused by polymorphic functions. */
* is only used for one type, avoiding the de-optimization caused by polymorphic functions.
*/
export function newtypeConstructor<T extends Newtype<unknown, string>>() {
// This cast is unsafe.
// `T` has an extra property `_$type` which is used purely for typechecking

View File

@ -16,8 +16,10 @@ export type Mutable<T> = {
/** Prevents generic parameter inference by hiding the type parameter behind a conditional type. */
type NoInfer<T> = [T][T extends T ? 0 : never]
/** Immutably shallowly merge an object with a partial update.
* Does not preserve classes. Useful for preserving order of properties. */
/**
* Immutably shallowly merge an object with a partial update.
* Does not preserve classes. Useful for preserving order of properties.
*/
export function merge<T extends object>(object: T, update: Partial<T>): T {
for (const [key, value] of Object.entries(update)) {
// eslint-disable-next-line no-restricted-syntax
@ -57,8 +59,10 @@ export function unsafeMutable<T extends object>(object: T): { -readonly [K in ke
// === unsafeEntries ===
// =====================
/** Return the entries of an object. UNSAFE only when it is possible for an object to have
* extra keys. */
/**
* Return the entries of an object. UNSAFE only when it is possible for an object to have
* extra keys.
*/
export function unsafeEntries<T extends object>(
object: T,
): readonly { [K in keyof T]: readonly [K, T[K]] }[keyof T][] {
@ -83,8 +87,10 @@ export function unsafeRemoveUndefined<T extends object>(
// === mapEntries ===
// ==================
/** Return the entries of an object. UNSAFE only when it is possible for an object to have
* extra keys. */
/**
* Return the entries of an object. UNSAFE only when it is possible for an object to have
* extra keys.
*/
export function mapEntries<K extends PropertyKey, V, W>(
object: Record<K, V>,
map: (key: K, value: V) => W,

View File

@ -111,8 +111,10 @@ export const FROM_PERMISSION_ACTION: Readonly<Record<PermissionAction, Permissio
},
}
/** The corresponding {@link PermissionAction} for each {@link Permission}.
* Assumes no docs sub-permission and no execute sub-permission. */
/**
* The corresponding {@link PermissionAction} for each {@link Permission}.
* Assumes no docs sub-permission and no execute sub-permission.
*/
export const TYPE_TO_PERMISSION_ACTION: Readonly<Record<Permission, PermissionAction>> = {
[Permission.owner]: PermissionAction.own,
[Permission.admin]: PermissionAction.admin,
@ -123,8 +125,10 @@ export const TYPE_TO_PERMISSION_ACTION: Readonly<Record<Permission, PermissionAc
[Permission.delete]: PermissionAction.view,
}
/** The corresponding {@link text.TextId} for each {@link Permission}.
* Assumes no docs sub-permission and no execute sub-permission. */
/**
* The corresponding {@link text.TextId} for each {@link Permission}.
* Assumes no docs sub-permission and no execute sub-permission.
*/
export const TYPE_TO_TEXT_ID: Readonly<Record<Permission, text.TextId>> = {
[Permission.owner]: 'ownerPermissionType',
[Permission.admin]: 'adminPermissionType',
@ -181,13 +185,13 @@ interface BasePermissions<T extends Permission> {
}
/** Owner permissions for an asset. */
interface OwnerPermissions extends BasePermissions<Permission.owner> {}
type OwnerPermissions = BasePermissions<Permission.owner>
/** Admin permissions for an asset. */
interface AdminPermissions extends BasePermissions<Permission.admin> {}
type AdminPermissions = BasePermissions<Permission.admin>
/** Editor permissions for an asset. */
interface EditPermissions extends BasePermissions<Permission.edit> {}
type EditPermissions = BasePermissions<Permission.edit>
/** Reader permissions for an asset. */
interface ReadPermissions extends BasePermissions<Permission.read> {

View File

@ -42,7 +42,7 @@ const guiTabCases = [
v.test.each([
{ group: 'Dashboard', cases: dashboardTabCases },
{ group: 'GUI', cases: guiTabCases },
])('Tab clip path: $group', ({ group, cases }) => {
])('Tab clip path: $group', ({ cases }) => {
cases.forEach(({ input, expected }) => {
const result = tabBar.tabClipPath(input.bounds, input.radius, (input as TabClipPathInput)?.side)
v.expect(result).toBe(expected)

View File

@ -2,8 +2,8 @@
"extends": "../../tsconfig.json",
"compilerOptions": {
"lib": ["DOM", "es2023"],
"allowJs": false,
"checkJs": false,
"allowJs": true,
"checkJs": true,
"skipLibCheck": false
},
"include": ["./src/", "./src/text/english.json", "../types/"]

View File

@ -12,9 +12,7 @@ export default class EditorPageActions extends PageActions {
get goToPage(): Omit<goToPageActions.GoToPageActions, 'editor'> {
return goToPageActions.goToPageActions(this.step.bind(this))
}
/**
* Waits for the editor to load.
*/
/** Waits for the editor to load. */
waitForEditorToLoad(): EditorPageActions {
return this.step('wait for the editor to load', async () => {
await this.page.waitForSelector('[data-testid=editor]', { state: 'visible' })

View File

@ -35,9 +35,7 @@ test('Disconnect an edge from a port', async ({ page }) => {
await expect(await edgesToNodeWithBinding(page, 'sum')).toHaveCount(EDGE_PARTS)
})
/**
* Scenario: We replace the `sum` parameter in the `prod` node` with the `ten` node.
*/
/** Scenario: We replace the `sum` parameter in the `prod` node` with the `ten` node. */
test('Connect an node to a port', async ({ page }) => {
await initGraph(page)
@ -57,9 +55,7 @@ test('Connect an node to a port', async ({ page }) => {
await expect(graphNodeByBinding(page, 'prod')).toContainText('ten')
})
/**
* As above, but by dragging edge instead of clicking source and target separately.
*/
/** As above, but by dragging edge instead of clicking source and target separately. */
test('Connect an node to a port via dragging the edge', async ({ page }) => {
await initGraph(page)

View File

@ -34,9 +34,7 @@ test('Existence of edges between nodes', async ({ page }) => {
await expect(await edgesToNodeWithBinding(page, 'five')).toHaveCount(0)
})
/**
* Prepare the graph for the tests. We drag the `ten` node to the right for better access to its outgoing edge.
*/
/** Prepare the graph for the tests. We drag the `ten` node to the right for better access to its outgoing edge. */
async function initGraph(page: Page) {
await actions.goToGraph(page)
await actions.dragNodeByBinding(page, 'ten', 400, 0)

View File

@ -5,9 +5,7 @@ import { mockExpressionUpdate } from './expressionUpdates'
import * as locate from './locate'
import { graphNodeByBinding } from './locate'
/**
* Prepare the graph for the tests. We add the table type to the `aggregated` node.
*/
/** Prepare the graph for the tests. We add the table type to the `aggregated` node. */
async function initGraph(page: Page) {
await actions.goToGraph(page)
await mockExpressionUpdate(page, 'aggregated', { type: 'Standard.Table.Table.Table' })

View File

@ -21,7 +21,7 @@
"build": "vite build",
"build-cloud": "cross-env CLOUD_BUILD=true corepack pnpm run build",
"preview": "vite preview",
"lint": "cross-env eslint . --max-warnings=0",
"lint": "eslint . --max-warnings=0",
"format": "prettier --version && prettier --write src/ && eslint . --fix",
"dev:vite": "vite",
"test": "corepack pnpm run /^^^^test:.*/",

View File

@ -7,9 +7,7 @@ export const DOCUMENTS = getDocumentsPath()
const CHILD_PROCESS_TIMEOUT = 3000
/**
* Detects path of the user documents directory depending on the operating system.
*/
/** Detects path of the user documents directory depending on the operating system. */
function getDocumentsPath(): string | undefined {
if (process.platform === 'linux') {
return getLinuxDocumentsPath()
@ -22,18 +20,14 @@ function getDocumentsPath(): string | undefined {
}
}
/**
* Returns the user documents path on Linux.
*/
/** Returns the user documents path on Linux. */
function getLinuxDocumentsPath(): string {
const xdgDocumentsPath = getXdgDocumentsPath()
return xdgDocumentsPath ?? path.join(os.homedir(), 'enso')
}
/**
* Gets the documents directory from the XDG directory management system.
*/
/** Gets the documents directory from the XDG directory management system. */
function getXdgDocumentsPath(): string | undefined {
const out = childProcess.spawnSync('xdg-user-dir', ['DOCUMENTS'], {
timeout: CHILD_PROCESS_TIMEOUT,
@ -54,9 +48,7 @@ function getMacOsDocumentsPath(): string {
return path.join(os.homedir(), 'Documents')
}
/**
* Get the path to the `My Documents` Windows directory.
*/
/** Get the path to the `My Documents` Windows directory. */
function getWindowsDocumentsPath(): string | undefined {
const out = childProcess.spawnSync(
'reg',

View File

@ -45,23 +45,17 @@ export const SUPPORT_EMAIL = 'cloud@enso.org'
/** Return the `mailto:` URL for contacting support. */
export const SUPPORT_EMAIL_URL = `mailto:${SUPPORT_EMAIL}`
/**
* Build a Subscription URL for a given plan.
*/
/** Build a Subscription URL for a given plan. */
export function getUpgradeURL(plan: string): string {
return SUBSCRIBE_PATH + '?plan=' + plan
}
/**
* Return the mailto URL for contacting sales.
*/
/** Return the mailto URL for contacting sales. */
export function getSalesEmail(): string {
return 'mailto:contact@enso.org'
}
/**
* Build a Subscription URL for contacting sales.
*/
/** Build a Subscription URL for contacting sales. */
export function getContactSalesURL(): string {
return 'mailto:contact@enso.org?subject=Upgrading%20to%20Organization%20Plan'
}

View File

@ -306,16 +306,12 @@ export class Cognito {
}
}
/**
* Refresh the current user's session.
*/
/** Refresh the current user's session. */
async refreshUserSession() {
return Promise.resolve(results.Ok(null))
}
/**
* Returns MFA preference for the current user.
*/
/** Returns MFA preference for the current user. */
async getMFAPreference() {
return Promise.resolve(results.Ok('NOMFA'))
}

View File

@ -74,9 +74,7 @@ interface UserAttributes {
}
/* eslint-enable @typescript-eslint/naming-convention */
/**
* The type of multi-factor authentication (MFA) that the user has set up.
*/
/** The type of multi-factor authentication (MFA) that the user has set up. */
export type MfaType = 'NOMFA' | 'SMS_MFA' | 'SOFTWARE_TOKEN_MFA' | 'TOTP'
/**
@ -244,9 +242,7 @@ export class Cognito {
return userInfo.attributes['custom:organizationId'] ?? null
}
/**
* Gets user email from cognito
*/
/** Gets user email from cognito */
async email() {
// This `any` comes from a third-party API and cannot be avoided.
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
@ -337,9 +333,7 @@ export class Cognito {
return result.mapErr(intoAmplifyErrorOrThrow).mapErr(intoSignInWithPasswordErrorOrThrow)
}
/**
* Refresh the current user session.
*/
/** Refresh the current user session. */
async refreshUserSession() {
const result = await results.Result.wrapAsync(async () => {
const currentUser = await currentAuthenticatedUser()
@ -432,9 +426,7 @@ export class Cognito {
}
}
/**
* Start the TOTP setup process. Returns the secret and the URL to scan the QR code.
*/
/** Start the TOTP setup process. Returns the secret and the URL to scan the QR code. */
async setupTOTP() {
const email = await this.email()
const cognitoUserResult = await currentAuthenticatedUser()
@ -472,9 +464,7 @@ export class Cognito {
}
}
/**
* Set the user's preferred MFA method.
*/
/** Set the user's preferred MFA method. */
async updateMFAPreference(mfaMethod: MfaType) {
const cognitoUserResult = await currentAuthenticatedUser()
if (cognitoUserResult.ok) {
@ -488,9 +478,7 @@ export class Cognito {
}
}
/**
* Get the user's preferred MFA method.
*/
/** Get the user's preferred MFA method. */
async getMFAPreference() {
const cognitoUserResult = await currentAuthenticatedUser()
if (cognitoUserResult.ok) {
@ -523,9 +511,7 @@ export class Cognito {
}
}
/**
* Confirm the sign in with the MFA token.
*/
/** Confirm the sign in with the MFA token. */
async confirmSignIn(
user: amplify.CognitoUser,
confirmationCode: string,

View File

@ -11,9 +11,7 @@ import { createContext, useContext, useId } from 'react'
import { twJoin } from '#/utilities/tailwindMerge'
import invariant from 'tiny-invariant'
/**
* Props for {@link AnimatedBackground}.
*/
/** Props for {@link AnimatedBackground}. */
interface AnimatedBackgroundProps extends PropsWithChildren {
readonly value: string
readonly transition?: Transition
@ -37,9 +35,7 @@ const DEFAULT_TRANSITION: Transition = {
velocity: 12,
}
/**
* `<AnimatedBackground />` component visually highlights selected items by sliding a background into view when hovered over or clicked.
*/
/** `<AnimatedBackground />` component visually highlights selected items by sliding a background into view when hovered over or clicked. */
export function AnimatedBackground(props: AnimatedBackgroundProps) {
const { value, transition = DEFAULT_TRANSITION, children } = props
const layoutId = useId()
@ -51,18 +47,14 @@ export function AnimatedBackground(props: AnimatedBackgroundProps) {
)
}
/**
* Props for {@link AnimatedBackground.Item}.
*/
/** Props for {@link AnimatedBackground.Item}. */
interface AnimatedBackgroundItemProps extends PropsWithChildren {
readonly value: string
readonly className?: string
readonly animationClassName?: string
}
/**
* Item within an {@link AnimatedBackground}.
*/
/** Item within an {@link AnimatedBackground}. */
AnimatedBackground.Item = function AnimatedBackgroundItem(props: AnimatedBackgroundItemProps) {
const context = useContext(AnimatedBackgroundContext)
invariant(context, 'useAnimatedBackground must be used within an AnimatedBackgroundProvider')

View File

@ -61,9 +61,7 @@ export interface AlertProps
extends PropsWithChildren,
VariantProps<typeof ALERT_STYLES>,
HTMLAttributes<HTMLDivElement> {
/**
* The icon to display in the Alert
*/
/** The icon to display in the Alert */
readonly icon?: React.ReactElement | string | null | undefined
}

View File

@ -22,39 +22,29 @@ export type ButtonProps =
| (BaseButtonProps<aria.ButtonRenderProps> & Omit<aria.ButtonProps, 'onPress'> & PropsWithoutHref)
| (BaseButtonProps<aria.LinkRenderProps> & Omit<aria.LinkProps, 'onPress'> & PropsWithHref)
/**
* Props for a button with an href.
*/
/** Props for a button with an href. */
interface PropsWithHref {
readonly href: string
}
/**
* Props for a button without an href.
*/
/** Props for a button without an href. */
interface PropsWithoutHref {
readonly href?: never
}
/**
* Base props for a button.
*/
/** Base props for a button. */
export interface BaseButtonProps<Render>
extends Omit<VariantProps<typeof BUTTON_STYLES>, 'iconOnly'> {
/** Falls back to `aria-label`. Pass `false` to explicitly disable the tooltip. */
readonly tooltip?: React.ReactElement | string | false | null
readonly tooltipPlacement?: aria.Placement
/**
* The icon to display in the button
*/
/** The icon to display in the button */
readonly icon?:
| React.ReactElement
| string
| ((render: Render) => React.ReactElement | string | null)
| null
/**
* When `true`, icon will be shown only when hovered.
*/
/** When `true`, icon will be shown only when hovered. */
readonly showIconOnHover?: boolean
/**
* Handler that is called when the press is released over the target.

View File

@ -33,9 +33,7 @@ import type { TestIdProps } from '../types'
import { useCheckboxContext } from './CheckboxContext'
import { CheckboxGroup } from './CheckboxGroup'
/**
* Props for the {@link Checkbox} component.
*/
/** Props for the {@link Checkbox} component. */
export type CheckboxProps<Schema extends TSchema, TFieldName extends FieldPath<Schema>> = Omit<
VariantProps<typeof CHECKBOX_STYLES>,
'isDisabled' | 'isInvalid'
@ -46,18 +44,14 @@ export type CheckboxProps<Schema extends TSchema, TFieldName extends FieldPath<S
readonly checkboxRef?: MutableRefObject<HTMLInputElement>
} & (CheckboxGroupCheckboxProps | StandaloneCheckboxProps<Schema, TFieldName>)
/**
* Props for the {@link Checkbox} component when used inside a {@link CheckboxGroup}.
*/
/** Props for the {@link Checkbox} component when used inside a {@link CheckboxGroup}. */
interface CheckboxGroupCheckboxProps extends AriaCheckboxProps {
readonly value: string
readonly form?: never
readonly name?: never
}
/**
* Props for the {@link Checkbox} component when used outside of a {@link CheckboxGroup}.
*/
/** Props for the {@link Checkbox} component when used outside of a {@link CheckboxGroup}. */
type StandaloneCheckboxProps<
Schema extends TSchema,
TFieldName extends FieldPath<Schema>,
@ -123,9 +117,7 @@ export const TICK_VARIANTS: Variants = {
},
}
/**
* Checkboxes allow users to select multiple items from a list of individual items, or to mark one individual item as selected.
*/
/** Checkboxes allow users to select multiple items from a list of individual items, or to mark one individual item as selected. */
// eslint-disable-next-line no-restricted-syntax
export const Checkbox = forwardRef(function Checkbox<
Schema extends TSchema,

View File

@ -1,6 +1,4 @@
/**
* @file
*/
/** @file */
import { useEventCallback } from '#/hooks/eventCallbackHooks'
import type { PropsWithChildren } from 'react'
import { createContext, useContext, useMemo, useState } from 'react'
@ -8,9 +6,7 @@ import type { StoreApi } from 'zustand'
import { createStore } from 'zustand'
import type { TSchema, UseFormRegisterReturn } from '../Form'
/**
* Context for the checkbox.
*/
/** Context for the checkbox. */
interface CheckboxContextType {
readonly store: StoreApi<CheckGroupPropsState>
readonly addSelected: (selected: string) => void
@ -25,9 +21,7 @@ const CheckboxContext = createContext<CheckboxContextType>({
toggleSelected: () => {},
})
/**
* Gets the context for the checkbox.
*/
/** Gets the context for the checkbox. */
export function useCheckboxContext() {
return useContext(CheckboxContext)
}
@ -50,9 +44,7 @@ export function useCheckboxGroupState() {
*/
type CheckGroupPropsState = CheckBoxGroupPropsStateInsideGroup | CheckBoxGroupPropsStateOutsideGroup
/**
* Checkbox group state when the checkbox is inside a group.
*/
/** Checkbox group state when the checkbox is inside a group. */
interface CheckBoxGroupPropsStateInsideGroup {
readonly insideGroup: true
readonly selected: Set<string>
@ -60,16 +52,12 @@ interface CheckBoxGroupPropsStateInsideGroup {
readonly field: UseFormRegisterReturn<TSchema>
}
/**
* Checkbox group state when the checkbox is not inside a group.
*/
/** Checkbox group state when the checkbox is not inside a group. */
interface CheckBoxGroupPropsStateOutsideGroup {
readonly insideGroup: false
}
/**
* Props for {@link CheckboxGroupProvider}.
*/
/** Props for {@link CheckboxGroupProvider}. */
export interface CheckboxGroupProviderProps extends PropsWithChildren {
readonly name: string
readonly onChange: (selected: string[]) => void
@ -77,9 +65,7 @@ export interface CheckboxGroupProviderProps extends PropsWithChildren {
readonly defaultValue?: string[] | undefined
}
/**
* Checkbox group provider used to manage the state of a group of checkboxes.
*/
/** Checkbox group provider used to manage the state of a group of checkboxes. */
export function CheckboxGroupProvider(props: CheckboxGroupProviderProps) {
const { children, onChange, name, field, defaultValue = [] } = props

View File

@ -16,9 +16,7 @@ import { Form, type FieldPath, type FieldProps, type FieldStateProps, type TSche
import type { TestIdProps } from '../types'
import { CheckboxGroupProvider } from './CheckboxContext'
/**
* Props for the {@link CheckboxGroupProps} component.
*/
/** Props for the {@link CheckboxGroupProps} component. */
export interface CheckboxGroupProps<Schema extends TSchema, TFieldName extends FieldPath<Schema>>
extends FieldStateProps<AriaCheckboxGroupProps, Schema, TFieldName>,
FieldProps,
@ -36,9 +34,7 @@ const CHECKBOX_GROUP_STYLES = tv({
variants: { fullWidth: { true: 'w-full' } },
})
/**
* A CheckboxGroup allows users to select one or more items from a list of choices.
*/
/** A CheckboxGroup allows users to select one or more items from a list of choices. */
// eslint-disable-next-line no-restricted-syntax
export const CheckboxGroup = forwardRef(
<Schema extends TSchema, TFieldName extends FieldPath<Schema>>(

View File

@ -12,14 +12,10 @@ import * as eventCallback from '#/hooks/eventCallbackHooks'
import * as button from '../Button'
import * as dialogProvider from './DialogProvider'
/**
* Props for {@link Close} component.
*/
/** Props for {@link Close} component. */
export type CloseProps = button.ButtonProps
/**
* Close button for a dialog.
*/
/** Close button for a dialog. */
export function Close(props: CloseProps) {
const dialogContext = dialogProvider.useDialogContext()

View File

@ -23,9 +23,7 @@ import { DIALOG_BACKGROUND } from './variants'
// =================
// === Constants ===
// =================
/**
* Props for the {@link Dialog} component.
*/
/** Props for the {@link Dialog} component. */
export interface DialogProps
extends types.DialogProps,
Omit<VariantProps<typeof DIALOG_STYLES>, 'scrolledToTop'> {}
@ -177,9 +175,7 @@ export function Dialog(props: DialogProps) {
const [isScrolledToTop, setIsScrolledToTop] = React.useState(true)
/**
* Handles the scroll event on the dialog content.
*/
/** Handles the scroll event on the dialog content. */
const handleScroll = (scrollTop: number) => {
React.startTransition(() => {
if (scrollTop > 0) {

View File

@ -5,28 +5,20 @@
*/
import * as React from 'react'
/**
* The context value for a dialog.
*/
/** The context value for a dialog. */
export interface DialogContextValue {
readonly close: () => void
readonly dialogId: string
}
/**
* The context for a dialog.
*/
/** The context for a dialog. */
const DialogContext = React.createContext<DialogContextValue | null>(null)
/**
* The provider for a dialog.
*/
/** The provider for a dialog. */
// eslint-disable-next-line no-restricted-syntax
export const DialogProvider = DialogContext.Provider
/**
* Custom hook to get the dialog context.
*/
/** Custom hook to get the dialog context. */
export function useDialogContext() {
return React.useContext(DialogContext)
}

View File

@ -1,6 +1,4 @@
/**
* @file This file provides the DialogStackProvider component and related functionality.
*/
/** @file This file provides the DialogStackProvider component and related functionality. */
import * as React from 'react'
@ -8,17 +6,13 @@ import invariant from 'tiny-invariant'
import * as eventCallbackHooks from '#/hooks/eventCallbackHooks'
/**
* DialogStackItem represents an item in the dialog stack.
*/
/** DialogStackItem represents an item in the dialog stack. */
export interface DialogStackItem {
readonly id: string
readonly type: 'dialog-fullscreen' | 'dialog' | 'popover'
}
/**
* DialogStackContextType represents the context for the dialog stack.
*/
/** DialogStackContextType represents the context for the dialog stack. */
export interface DialogStackContextType {
readonly stack: DialogStackItem[]
readonly dialogsStack: DialogStackItem[]
@ -28,9 +22,7 @@ export interface DialogStackContextType {
const DialogStackContext = React.createContext<DialogStackContextType | null>(null)
/**
* DialogStackProvider is a React component that provides the dialog stack context to its children.
*/
/** DialogStackProvider is a React component that provides the dialog stack context to its children. */
export function DialogStackProvider(props: React.PropsWithChildren) {
const { children } = props
@ -72,9 +64,7 @@ updated properly.`)
return <DialogStackContext.Provider value={value}>{children}</DialogStackContext.Provider>
}
/**
* DialogStackRegistrar is a React component that registers a dialog in the dialog stack.
*/
/** DialogStackRegistrar is a React component that registers a dialog in the dialog stack. */
export function DialogStackRegistrar(props: React.PropsWithChildren<DialogStackItem>) {
const { children, id: idRaw, type: typeRaw } = props
const idRef = React.useRef(idRaw)
@ -100,16 +90,12 @@ export function DialogStackRegistrar(props: React.PropsWithChildren<DialogStackI
return children
}
/**
* Props for {@link useDialogStackState}
*/
/** Props for {@link useDialogStackState} */
export interface UseDialogStackStateProps {
readonly id: string
}
/**
* useDialogStackState is a custom hook that provides the state of the dialog stack.
*/
/** useDialogStackState is a custom hook that provides the state of the dialog stack. */
export function useDialogStackState(props: UseDialogStackStateProps) {
const ctx = React.useContext(DialogStackContext)

View File

@ -10,21 +10,15 @@ import { useOverlayTriggerState } from 'react-stately'
const PLACEHOLDER = <div />
/**
* Props passed to the render function of a {@link DialogTrigger}.
*/
/** Props passed to the render function of a {@link DialogTrigger}. */
export interface DialogTriggerRenderProps {
readonly isOpen: boolean
readonly close: () => void
readonly open: () => void
}
/**
* Props for a {@link DialogTrigger}.
*/
/** Props for a {@link DialogTrigger}. */
export interface DialogTriggerProps extends Omit<aria.DialogTriggerProps, 'children'> {
/**
* The trigger element.
*/
/** The trigger element. */
readonly children: [
React.ReactElement,
React.ReactElement | ((props: DialogTriggerRenderProps) => React.ReactElement),

View File

@ -23,16 +23,12 @@ const IGNORE_INTERACT_OUTSIDE_ELEMENTS = [
const IGNORE_INTERACT_OUTSIDE_ELEMENTS_SELECTOR = `:is(${IGNORE_INTERACT_OUTSIDE_ELEMENTS.join(', ')})`
/**
* Check if the element is a part of a component that should ignore the interact outside event
*/
/** Check if the element is a part of a component that should ignore the interact outside event */
export function shouldIgnoreInteractOutside(element: HTMLElement) {
return element.closest(IGNORE_INTERACT_OUTSIDE_ELEMENTS_SELECTOR)
}
/**
* Props for {@link useInteractOutside}
*/
/** Props for {@link useInteractOutside} */
export interface UseInteractOutsideProps {
readonly ref: React.RefObject<HTMLElement>
readonly id: string
@ -40,9 +36,7 @@ export interface UseInteractOutsideProps {
readonly isDisabled?: boolean
}
/**
* Hook that handles the interact outside event for the dialog
*/
/** Hook that handles the interact outside event for the dialog */
export function useInteractOutside(props: UseInteractOutsideProps) {
const { ref, id, onInteractOutside, isDisabled = false } = props
const shouldCloseOnInteractOutsideRef = React.useRef(false)

View File

@ -14,9 +14,7 @@ import * as text from '../../Text'
import { Form } from '../Form'
import type * as types from './types'
/**
* Props for Field component
*/
/** Props for Field component */
export interface FieldComponentProps<Schema extends types.TSchema>
extends VariantProps<typeof FIELD_STYLES>,
types.FieldProps {
@ -29,16 +27,12 @@ export interface FieldComponentProps<Schema extends types.TSchema>
readonly style?: React.CSSProperties | undefined
}
/**
* Props for Field variants
*/
/** Props for Field variants */
export interface FieldVariantProps {
readonly fieldVariants?: VariantProps<typeof FIELD_STYLES>['variants'] | undefined
}
/**
* Props for Field children
*/
/** Props for Field children */
export interface FieldChildrenRenderProps {
readonly isInvalid: boolean
readonly isDirty: boolean
@ -65,9 +59,7 @@ export const FIELD_STYLES = tv({
defaultVariants: { fullWidth: true },
})
/**
* Field component
*/
/** Field component */
// eslint-disable-next-line no-restricted-syntax
export const Field = forwardRef(function Field<Schema extends types.TSchema>(
props: FieldComponentProps<Schema>,

View File

@ -13,18 +13,14 @@ import * as reactAriaComponents from '#/components/AriaComponents'
import * as formContext from './FormProvider'
import type * as types from './types'
/**
* Props for the FormError component.
*/
/** Props for the FormError component. */
export interface FormErrorProps extends Omit<reactAriaComponents.AlertProps, 'children'> {
// We do not need to know the form fields.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
readonly form?: types.FormInstance<any>
}
/**
* Form error component.
*/
/** Form error component. */
export function FormError(props: FormErrorProps) {
const { size = 'large', variant = 'error', rounded = 'large', ...alertProps } = props
@ -33,9 +29,7 @@ export function FormError(props: FormErrorProps) {
const { errors } = formState
const { getText } = textProvider.useText()
/**
* Get the error message.
*/
/** Get the error message. */
const getSubmitError = (): string | null => {
const formErrors = errors.root

View File

@ -9,9 +9,7 @@ import invariant from 'tiny-invariant'
import type * as types from './types'
import type { FormInstance, FormInstanceValidated } from './types'
/**
* Context type for the form provider.
*/
/** Context type for the form provider. */
interface FormContextType<Schema extends types.TSchema> {
readonly form: types.UseFormReturn<Schema>
}
@ -20,9 +18,7 @@ interface FormContextType<Schema extends types.TSchema> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const FormContext = createContext<FormContextType<any> | null>(null)
/**
* Provides the form instance to the component tree.
*/
/** Provides the form instance to the component tree. */
export function FormProvider<Schema extends types.TSchema>(
props: FormContextType<Schema> & PropsWithChildren,
) {
@ -36,9 +32,7 @@ export function FormProvider<Schema extends types.TSchema>(
)
}
/**
* Returns the form instance from the context.
*/
/** Returns the form instance from the context. */
export function useFormContext<Schema extends types.TSchema>(
form?: FormInstanceValidated<Schema>,
): FormInstance<Schema> {
@ -56,9 +50,7 @@ export function useFormContext<Schema extends types.TSchema>(
}
}
/**
* Returns the form instance from the context, or null if the context is not available.
*/
/** Returns the form instance from the context, or null if the context is not available. */
export function useOptionalFormContext<
Form extends FormInstanceValidated<Schema> | undefined,
Schema extends types.TSchema,

View File

@ -11,9 +11,7 @@ import { useText } from '#/providers/TextProvider'
import * as formContext from './FormProvider'
import type * as types from './types'
/**
* Props for the Reset component.
*/
/** Props for the Reset component. */
export interface ResetProps extends Omit<ariaComponents.ButtonProps, 'loading'> {
/**
* Connects the submit button to a form.
@ -28,9 +26,7 @@ export interface ResetProps extends Omit<ariaComponents.ButtonProps, 'loading'>
readonly action?: 'cancel' | 'reset'
}
/**
* Reset button for forms.
*/
/** Reset button for forms. */
export function Reset(props: ResetProps): React.JSX.Element {
const { getText } = useText()
const {

View File

@ -11,9 +11,7 @@ import { useText } from '#/providers/TextProvider'
import { useFormContext } from './FormProvider'
import type { FormInstance } from './types'
/**
* Additional props for the Submit component.
*/
/** Additional props for the Submit component. */
interface SubmitButtonBaseProps {
readonly variant?: ButtonProps['variant']
/**
@ -29,9 +27,7 @@ interface SubmitButtonBaseProps {
readonly action?: 'cancel' | 'submit' | 'update'
}
/**
* Props for the Submit component.
*/
/** Props for the Submit component. */
export type SubmitProps = Omit<ButtonProps, 'formnovalidate' | 'href' | 'variant'> &
SubmitButtonBaseProps

View File

@ -24,17 +24,13 @@ export type TransformedValues<Schema extends TSchema | undefined> =
*/
export type FieldPath<Schema extends TSchema> = reactHookForm.FieldPath<FieldValues<Schema>>
/**
* Schema type
*/
/** Schema type */
export type TSchema =
| z.AnyZodObject
| z.ZodEffects<z.AnyZodObject>
| z.ZodEffects<z.ZodEffects<z.AnyZodObject>>
/**
* OnSubmitCallbacks type.
*/
/** OnSubmitCallbacks type. */
export interface OnSubmitCallbacks<Schema extends TSchema, SubmitResult = void> {
readonly onSubmit?:
| ((
@ -67,9 +63,7 @@ export interface OnSubmitCallbacks<Schema extends TSchema, SubmitResult = void>
| undefined
}
/**
* Props for the useForm hook.
*/
/** Props for the useForm hook. */
export interface UseFormProps<Schema extends TSchema, SubmitResult = void>
extends Omit<
reactHookForm.UseFormProps<FieldValues<Schema>>,
@ -83,16 +77,12 @@ export interface UseFormProps<Schema extends TSchema, SubmitResult = void>
*/
readonly canSubmitOffline?: boolean
/**
* Debug name for the form. Use it to identify the form in the tanstack query devtools.
*/
/** Debug name for the form. Use it to identify the form in the tanstack query devtools. */
readonly debugName?: string
readonly method?: 'dialog' | (string & {}) | undefined
}
/**
* Register function for a form field.
*/
/** Register function for a form field. */
export type UseFormRegister<Schema extends TSchema> = <
TFieldName extends FieldPath<Schema> = FieldPath<Schema>,
>(
@ -100,9 +90,7 @@ export type UseFormRegister<Schema extends TSchema> = <
options?: reactHookForm.RegisterOptions<FieldValues<Schema>, TFieldName>,
) => UseFormRegisterReturn<Schema, TFieldName>
/**
* UseFormRegister return type.
*/
/** UseFormRegister return type. */
export interface UseFormRegisterReturn<
Schema extends TSchema,
TFieldName extends FieldPath<Schema> = FieldPath<Schema>,
@ -147,9 +135,7 @@ export type FormState<Schema extends TSchema> = reactHookForm.FormState<FieldVal
*/
export type FormInstance<Schema extends TSchema> = UseFormReturn<Schema>
/**
* Form type interface that check if FieldValues type is compatible with the value type from component
*/
/** Form type interface that check if FieldValues type is compatible with the value type from component */
export interface FormWithValueValidation<
BaseValueType,
Schema extends TSchema,
@ -180,9 +166,7 @@ export type FormInstanceValidated<
// eslint-disable-next-line @typescript-eslint/no-explicit-any
> = FormInstance<Schema> | (any[] & NonNullable<unknown>)
/**
* Props for the Field component.
*/
/** Props for the Field component. */
// Readonly omitted here to avoid type mismatch with native HTML attributes
// eslint-disable-next-line no-restricted-syntax
export interface FieldProps {
@ -191,27 +175,19 @@ export interface FieldProps {
readonly description?: React.ReactNode | undefined
readonly error?: React.ReactNode | undefined
/**
* Defines a string value that labels the current element.
*/
/** Defines a string value that labels the current element. */
// eslint-disable-next-line @typescript-eslint/naming-convention
'aria-label'?: string | undefined
/**
* Identifies the element (or elements) that labels the current element.
*/
/** Identifies the element (or elements) that labels the current element. */
// eslint-disable-next-line @typescript-eslint/naming-convention
'aria-labelledby'?: string | undefined
/**
* Identifies the element (or elements) that describes the object.
*/
/** Identifies the element (or elements) that describes the object. */
// eslint-disable-next-line @typescript-eslint/naming-convention
'aria-describedby'?: string | undefined
/**
* Identifies the element (or elements) that provide a detailed, extended description for the object.
*/
/** Identifies the element (or elements) that provide a detailed, extended description for the object. */
// eslint-disable-next-line @typescript-eslint/naming-convention
'aria-details'?: string | undefined
}
@ -233,9 +209,7 @@ export interface FormFieldProps<
readonly isInvalid?: boolean | undefined
}
/**
* Field State Props
*/
/** Field State Props */
export type FieldStateProps<
// eslint-disable-next-line no-restricted-syntax
BaseProps extends { value?: unknown },

View File

@ -8,9 +8,7 @@ import * as reactHookForm from 'react-hook-form'
import * as formContext from './FormProvider'
import type * as types from './types'
/**
* Options for {@link useField} hook.
*/
/** Options for {@link useField} hook. */
export interface UseFieldOptions<
BaseValueType,
Schema extends types.TSchema,
@ -21,9 +19,7 @@ export interface UseFieldOptions<
readonly defaultValue?: types.FieldValues<Schema>[TFieldName] | undefined
}
/**
* A hook that connects a field to a form state.
*/
/** A hook that connects a field to a form state. */
export function useField<
BaseValueType,
Schema extends types.TSchema,

View File

@ -13,9 +13,7 @@ import type {
TSchema,
} from './types'
/**
* Options for the useFieldRegister hook.
*/
/** Options for the useFieldRegister hook. */
export type UseFieldRegisterOptions<
BaseValueType extends { value?: unknown },
Schema extends TSchema,
@ -31,9 +29,7 @@ export type UseFieldRegisterOptions<
setValueAs?: ((value: unknown) => unknown) | undefined
}
/**
* Registers a field in the form.
*/
/** Registers a field in the form. */
export function useFieldRegister<
BaseValueType extends { value?: unknown },
Schema extends TSchema,
@ -62,9 +58,7 @@ export function useFieldRegister<
return { fieldProps, formInstance } as const
}
/**
* Tried to extract validation details from the schema.
*/
/** Tried to extract validation details from the schema. */
// This name is intentional to highlight that this function is unsafe and should be used with caution.
// eslint-disable-next-line camelcase, @typescript-eslint/naming-convention
function unsafe__extractValidationDetailsFromSchema<

View File

@ -7,9 +7,7 @@ import { useFormState } from 'react-hook-form'
import { useFormContext } from './FormProvider'
import type { FieldPath, FormInstanceValidated, TSchema } from './types'
/**
* Options for the `useFieldState` hook.
*/
/** Options for the `useFieldState` hook. */
export interface UseFieldStateOptions<
Schema extends TSchema,
TFieldName extends FieldPath<Schema>,
@ -18,9 +16,7 @@ export interface UseFieldStateOptions<
readonly form?: FormInstanceValidated<Schema> | undefined
}
/**
* Hook to get the state of a field.
*/
/** Hook to get the state of a field. */
export function useFieldState<Schema extends TSchema, TFieldName extends FieldPath<Schema>>(
options: UseFieldStateOptions<Schema, TFieldName>,
) {

View File

@ -18,9 +18,7 @@ import { useMutation } from '@tanstack/react-query'
import * as schemaModule from './schema'
import type * as types from './types'
/**
* Maps the value to the event object.
*/
/** Maps the value to the event object. */
function mapValueOnEvent(value: unknown) {
if (typeof value === 'object' && value != null && 'target' in value && 'type' in value) {
return value
@ -241,9 +239,7 @@ export function useForm<Schema extends types.TSchema, SubmitResult = void>(
}
}
/**
* Get the type of arguments passed to the useForm hook
*/
/** Get the type of arguments passed to the useForm hook */
function getArgsType<Schema extends types.TSchema, SubmitResult = void>(
args: types.UseFormProps<Schema, SubmitResult>,
) {

View File

@ -5,9 +5,7 @@
*/
import * as twv from '#/utilities/tailwindVariants'
/**
* Props for form components.
*/
/** Props for form components. */
export type FormStyleProps = twv.VariantProps<typeof FORM_STYLES>
export const FORM_STYLES = twv.tv({
base: 'flex flex-col items-start',

View File

@ -14,18 +14,14 @@ import type * as styles from './styles'
export type * from './components'
/**
* Props for the Form component
*/
/** Props for the Form component */
export type FormProps<
Schema extends components.TSchema,
SubmitResult = void,
> = BaseFormProps<Schema> &
(FormPropsWithOptions<Schema, SubmitResult> | FormPropsWithParentForm<Schema>)
/**
* Base props for the Form component.
*/
/** Base props for the Form component. */
interface BaseFormProps<Schema extends components.TSchema>
extends Omit<
React.HTMLProps<HTMLFormElement>,
@ -48,9 +44,7 @@ interface BaseFormProps<Schema extends components.TSchema>
readonly className?: string | ((props: components.UseFormReturn<Schema>) => string)
/**
* When set to `dialog`, form submission will close the parent dialog on successful submission.
*/
/** When set to `dialog`, form submission will close the parent dialog on successful submission. */
readonly method?: 'dialog' | (NonNullable<unknown> & string)
readonly canSubmitOffline?: boolean
@ -93,9 +87,7 @@ interface FormPropsWithOptions<Schema extends components.TSchema, SubmitResult =
readonly form?: never
}
/**
* Register function for a form field.
*/
/** Register function for a form field. */
export type UseFormRegister<Schema extends components.TSchema> = <
TFieldName extends components.FieldPath<Schema> = components.FieldPath<Schema>,
>(
@ -103,9 +95,7 @@ export type UseFormRegister<Schema extends components.TSchema> = <
options?: reactHookForm.RegisterOptions<components.FieldValues<Schema>, TFieldName>,
) => UseFormRegisterReturn<Schema, TFieldName>
/**
* UseFormRegister return type.
*/
/** UseFormRegister return type. */
export interface UseFormRegisterReturn<
Schema extends components.TSchema,
TFieldName extends components.FieldPath<Schema> = components.FieldPath<Schema>,
@ -119,9 +109,7 @@ export interface UseFormRegisterReturn<
readonly isInvalid?: boolean
}
/**
* Form Render Props.
*/
/** Form Render Props. */
export type FormStateRenderProps<Schema extends components.TSchema> = Pick<
components.FormInstance<Schema>,
| 'clearErrors'

View File

@ -32,9 +32,7 @@ import type { ExtractFunction, VariantProps } from '#/utilities/tailwindVariants
import { omit } from 'enso-common/src/utilities/data/object'
import { INPUT_STYLES } from '../variants'
/**
* Props for the Input component.
*/
/** Props for the Input component. */
export interface InputProps<Schema extends TSchema, TFieldName extends FieldPath<Schema>>
extends FieldStateProps<Omit<aria.InputProps, 'children' | 'size'>, Schema, TFieldName>,
FieldProps,
@ -53,9 +51,7 @@ export interface InputProps<Schema extends TSchema, TFieldName extends FieldPath
readonly fieldVariants?: FieldComponentProps<Schema>['variants']
}
/**
* Basic input component. Input component is a component that is used to get user input in a text field.
*/
/** Basic input component. Input component is a component that is used to get user input in a text field. */
export const Input = forwardRef(function Input<
Schema extends TSchema,
TFieldName extends FieldPath<Schema>,

View File

@ -79,9 +79,7 @@ export const MULTI_SELECTOR_STYLES = tv({
},
})
/**
* A horizontal multi-selector.
*/
/** A horizontal multi-selector. */
export const MultiSelector = forwardRef(function MultiSelector<
Schema extends TSchema,
TFieldName extends FieldPath<Schema>,

View File

@ -1,6 +1,4 @@
/**
* @file
*/
/** @file */
import { mergeProps } from '#/components/aria'
import { mergeRefs } from '#/utilities/mergeRefs'
import type { VariantProps } from '#/utilities/tailwindVariants'
@ -23,9 +21,7 @@ import { Separator } from '../../Separator'
import { TEXT_STYLE } from '../../Text'
import type { TestIdProps } from '../../types'
/**
* Props for an {@link OTPInput}.
*/
/** Props for an {@link OTPInput}. */
export interface OtpInputProps<Schema extends TSchema, TFieldName extends FieldPath<Schema>>
extends FieldStateProps<Omit<OTPInputProps, 'children' | 'render'>, Schema, TFieldName>,
FieldProps,
@ -40,9 +36,7 @@ export interface OtpInputProps<Schema extends TSchema, TFieldName extends FieldP
* @default true
*/
readonly submitOnComplete?: boolean
/**
* Callback when the OTP is filled.
*/
/** Callback when the OTP is filled. */
readonly onComplete?: () => void
}
@ -82,9 +76,7 @@ const SLOT_STYLES = tv({
],
})
/**
* Accessible one-time password component with copy paste functionality.
*/
/** Accessible one-time password component with copy paste functionality. */
export const OTPInput = forwardRef(function OTPInput<
Schema extends TSchema,
TFieldName extends FieldPath<Schema>,
@ -196,9 +188,7 @@ export const OTPInput = forwardRef(function OTPInput<
)
})
/**
* Props for a single {@link Slot}.
*/
/** Props for a single {@link Slot}. */
interface SlotProps extends Omit<OTPInputSlotProps, 'isActive'>, VariantProps<typeof SLOT_STYLES> {}
/**

View File

@ -1,6 +1,4 @@
/**
* @file A resizable input that uses a content-editable div.
*/
/** @file A resizable input that uses a content-editable div. */
import {
useEffect,
useRef,
@ -31,9 +29,7 @@ const CONTENT_EDITABLE_STYLES = tv({
slots: { placeholder: 'opacity-50 absolute inset-0 pointer-events-none' },
})
/**
* Props for a {@link ResizableContentEditableInput}.
*/
/** Props for a {@link ResizableContentEditableInput}. */
export interface ResizableContentEditableInputProps<
Schema extends TSchema,
TFieldName extends FieldPath<Schema>,

View File

@ -1,6 +1,4 @@
/**
* @file A resizable input field.
*/
/** @file A resizable input field. */
import * as React from 'react'
import * as eventCallbackHooks from '#/hooks/eventCallbackHooks'
@ -12,17 +10,13 @@ import * as mergeRefs from '#/utilities/mergeRefs'
import { forwardRef } from '#/utilities/react'
import * as variants from '../variants'
/**
* Props for a {@link ResizableInput}.
*/
/** Props for a {@link ResizableInput}. */
export interface ResizableInputProps extends aria.TextFieldProps {
readonly placeholder?: string
readonly description?: React.ReactNode
}
/**
* A resizable input field.
*/
/** A resizable input field. */
export const ResizableInput = forwardRef(function ResizableInput(
props: ResizableInputProps,
ref: React.ForwardedRef<HTMLTextAreaElement>,

View File

@ -76,9 +76,7 @@ export const SELECTOR_STYLES = tv({
},
})
/**
* A horizontal selector.
*/
/** A horizontal selector. */
export const Selector = forwardRef(function Selector<
Schema extends TSchema,
TFieldName extends FieldPath<Schema>,

View File

@ -44,16 +44,12 @@ const RADIO_STYLES = twv.tv({
],
})
/**
* Props for the {@link Radio} component.
*/
/** Props for the {@link Radio} component. */
export interface RadioProps extends aria.RadioProps {
readonly label?: string
}
/**
* A radio button.
*/
/** A radio button. */
// eslint-disable-next-line no-restricted-syntax
export const Radio = forwardRef(function Radio(
props: RadioProps,

View File

@ -16,9 +16,7 @@ import type { FieldVariantProps } from '../Form'
import * as formComponent from '../Form'
import * as radioGroupContext from './RadioGroupContext'
/**
* Props for {@link RadioGroup}.
*/
/** Props for {@link RadioGroup}. */
export interface RadioGroupProps<
Schema extends formComponent.TSchema,
TFieldName extends formComponent.FieldPath<Schema>,
@ -39,9 +37,7 @@ export const RADIO_GROUP_STYLES = twv.tv({
variants: { fullWidth: { true: 'w-full' } },
})
/**
* A radio group component.
*/
/** A radio group component. */
// eslint-disable-next-line no-restricted-syntax
export const RadioGroup = forwardRef(function RadioGroup<
Schema extends formComponent.TSchema,

View File

@ -18,9 +18,7 @@ import invariant from 'tiny-invariant'
import * as eventCallback from '#/hooks/eventCallbackHooks'
/**
* Props for {@link RadioGroupContextProps}
*/
/** Props for {@link RadioGroupContextProps} */
export interface RadioGroupContextProps {
/**
* Tells if a Radio element is being pressed
@ -28,13 +26,9 @@ export interface RadioGroupContextProps {
* It's not the same as selected value, instead it stores the value user is clicking on at the moment
*/
readonly pressedRadio: string | null
/**
* Sets the pressed Radio element
*/
/** Sets the pressed Radio element */
readonly setPressedRadio: (value: string) => void
/**
* Clears the pressed Radio element
*/
/** Clears the pressed Radio element */
readonly clearPressedRadio: () => void
}
@ -68,16 +62,12 @@ export function RadioGroupProvider(props: React.PropsWithChildren) {
return <RadioGroupContext.Provider value={value}>{children}</RadioGroupContext.Provider>
}
/**
* Props for {@link useRadioGroupContext}
*/
/** Props for {@link useRadioGroupContext} */
export interface UseRadioGroupContextProps {
readonly value: string
}
/**
* Provides useful information about sibling Radio elements within a RadioGroup
*/
/** Provides useful information about sibling Radio elements within a RadioGroup */
export function useRadioGroupContext(props: UseRadioGroupContextProps) {
const { value } = props
const context = React.useContext(RadioGroupContext)

View File

@ -9,18 +9,14 @@ import * as aria from '#/components/aria'
import * as twv from '#/utilities/tailwindVariants'
/**
* The props for {@link Separator} component.
*/
/** The props for {@link Separator} component. */
export interface SeparatorProps
extends aria.SeparatorProps,
twv.VariantProps<typeof SEPARATOR_STYLES> {
readonly className?: string
}
/**
* The styles for the {@link Separator} component.
*/
/** The styles for the {@link Separator} component. */
export const SEPARATOR_STYLES = twv.tv({
base: 'rounded-full border-none',
variants: {
@ -79,9 +75,7 @@ export const SEPARATOR_STYLES = twv.tv({
],
})
/**
* A separator component.
*/
/** A separator component. */
export function Separator(props: SeparatorProps) {
const { orientation = 'horizontal', variant, className, size, ...rest } = props

View File

@ -16,9 +16,7 @@ import { tv, type VariantProps } from '#/utilities/tailwindVariants'
import { Form, type FieldPath, type FieldProps, type FieldStateProps, type TSchema } from '../Form'
import { TEXT_STYLE } from '../Text'
/**
* Props for the {@Switch} component.
*/
/** Props for the {@Switch} component. */
export interface SwitchProps<Schema extends TSchema, TFieldName extends FieldPath<Schema>>
extends FieldStateProps<
Omit<AriaSwitchProps, 'children' | 'size' | 'value'> & { value: boolean },
@ -59,9 +57,7 @@ export const SWITCH_STYLES = tv({
},
})
/**
* A switch allows a user to turn a setting on or off.
*/
/** A switch allows a user to turn a setting on or off. */
// eslint-disable-next-line no-restricted-syntax
export const Switch = forwardRef(function Switch<
Schema extends TSchema,

View File

@ -1,6 +1,4 @@
/**
* @file Text component
*/
/** @file Text component */
import * as React from 'react'
import * as aria from '#/components/aria'
@ -12,9 +10,7 @@ import { forwardRef } from '#/utilities/react'
import * as textProvider from './TextProvider'
import * as visualTooltip from './useVisualTooltip'
/**
* Props for the Text component
*/
/** Props for the Text component */
export interface TextProps
extends Omit<aria.TextProps, 'color'>,
twv.VariantProps<typeof TEXT_STYLE> {
@ -119,9 +115,7 @@ export const TEXT_STYLE = twv.tv({
},
})
/**
* Text component that supports truncation and show a tooltip on hover when text is truncated
*/
/** Text component that supports truncation and show a tooltip on hover when text is truncated */
// eslint-disable-next-line no-restricted-syntax
export const Text = forwardRef(function Text(props: TextProps, ref: React.Ref<HTMLSpanElement>) {
const {
@ -216,17 +210,13 @@ export const Text = forwardRef(function Text(props: TextProps, ref: React.Ref<HT
Group: React.FC<React.PropsWithChildren>
}
/**
* Heading props
*/
/** Heading props */
export interface HeadingProps extends Omit<TextProps, 'elementType'> {
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
readonly level?: '1' | '2' | '3' | '4' | '5' | '6' | 1 | 2 | 3 | 4 | 5 | 6
}
/**
* Heading component
*/
/** Heading component */
// eslint-disable-next-line no-restricted-syntax
const Heading = forwardRef(function Heading(
props: HeadingProps,
@ -237,9 +227,7 @@ const Heading = forwardRef(function Heading(
})
Text.Heading = Heading
/**
* Text group component. It's used to visually group text elements together
*/
/** Text group component. It's used to visually group text elements together */
Text.Group = function TextGroup(props: React.PropsWithChildren) {
return (
<textProvider.TextProvider value={{ isInsideTextComponent: true }}>

View File

@ -5,13 +5,9 @@
*/
import * as React from 'react'
/**
* Context for the Text component.
*/
/** Context for the Text component. */
export interface TextContextType {
/**
* Flag indicating whether the component is inside a Text component.
*/
/** Flag indicating whether the component is inside a Text component. */
readonly isInsideTextComponent: boolean
}
@ -19,9 +15,7 @@ const TextContext = React.createContext<TextContextType>({
isInsideTextComponent: false,
})
/**
* Hook to get the Text context.
*/
/** Hook to get the Text context. */
export function useTextContext(): TextContextType {
return React.useContext(TextContext)
}

View File

@ -12,9 +12,7 @@ import * as aria from '#/components/aria'
import * as ariaComponents from '#/components/AriaComponents'
import Portal from '#/components/Portal'
/**
* Props for {@link useVisualTooltip}.
*/
/** Props for {@link useVisualTooltip}. */
export interface VisualTooltipProps
extends Pick<ariaComponents.TooltipProps, 'maxWidth' | 'rounded' | 'size' | 'variant'> {
readonly children: React.ReactNode
@ -41,9 +39,7 @@ export interface VisualTooltipReturn {
readonly tooltip: JSX.Element | null
}
/**
* The display strategy for the tooltip.
*/
/** The display strategy for the tooltip. */
type DisplayStrategy = 'always' | 'whenOverflowing'
const DEFAULT_OFFSET = 6

View File

@ -8,16 +8,12 @@ import * as React from 'react'
import { forwardRef } from '#/utilities/react'
import * as twv from '#/utilities/tailwindVariants'
/**
* Props for the {@link VisuallyHidden} component.
*/
/** Props for the {@link VisuallyHidden} component. */
export type VisuallyHiddenProps = React.HTMLProps<HTMLElement>
export const VISUALLY_HIDDEN_STYLES = twv.tv({ base: 'sr-only' })
/**
* A component visually hides its children from the screen, but keeps them accessible to screen readers.
*/
/** A component visually hides its children from the screen, but keeps them accessible to screen readers. */
// eslint-disable-next-line no-restricted-syntax
export const VisuallyHidden = forwardRef(function VisuallyHidden(
props: VisuallyHiddenProps,

View File

@ -4,13 +4,9 @@
* Common types for ARIA components.
*/
/**
* Props for adding a test id to a component
*/
/** Props for adding a test id to a component */
export interface TestIdProps {
/**
* @deprecated Use `testid` instead
*/
/** @deprecated Use `testid` instead */
readonly 'data-testid'?: string | undefined
readonly testId?: string | undefined
}

View File

@ -8,9 +8,7 @@ import { tv } from '#/utilities/tailwindVariants'
import type { ReactNode } from 'react'
import { TEXT_STYLE } from '../AriaComponents'
/**
* Props for the {@link Badge} component.
*/
/** Props for the {@link Badge} component. */
export interface BadgeProps extends VariantProps<typeof BADGE_STYLES> {
readonly children?: ReactNode
readonly className?: string
@ -61,9 +59,7 @@ export const BADGE_STYLES = tv({
},
})
/**
* Badges are used to highlight an item's status for quick recognition.
*/
/** Badges are used to highlight an item's status for quick recognition. */
export function Badge(props: BadgeProps) {
const { children, color, rounded, className, variant } = props

View File

@ -48,9 +48,7 @@ import * as backend from '#/services/Backend'
import LocalStorage, { type LocalStorageData } from '#/utilities/LocalStorage'
import { unsafeEntries } from 'enso-common/src/utilities/data/object'
/**
* A component that provides a UI for toggling paywall features.
*/
/** A component that provides a UI for toggling paywall features. */
export function EnsoDevtools() {
const { getText } = textProvider.useText()
const { authQueryKey, session } = authProvider.useAuth()

View File

@ -5,9 +5,7 @@
import type { PaywallFeatureName } from '#/hooks/billing'
import * as zustand from 'zustand'
/**
* Configuration for a paywall feature.
*/
/** Configuration for a paywall feature. */
export interface PaywallDevtoolsFeatureConfiguration {
readonly isForceEnabled: boolean | null
}
@ -62,9 +60,7 @@ export function useSetEnableVersionChecker() {
return zustand.useStore(ensoDevtoolsStore, (state) => state.setEnableVersionChecker)
}
/**
* A hook that provides access to the paywall devtools.
*/
/** A hook that provides access to the paywall devtools. */
export function usePaywallDevtools() {
return zustand.useStore(ensoDevtoolsStore, (state) => ({
features: state.paywallFeatures,

View File

@ -1,6 +1,4 @@
/**
* @file Show the React Query Devtools.
*/
/** @file Show the React Query Devtools. */
import * as React from 'react'
import * as reactQuery from '@tanstack/react-query'

View File

@ -14,14 +14,10 @@ import * as offlineHooks from '#/hooks/offlineHooks'
import * as textProvider from '#/providers/TextProvider'
/**
* Props for {@link OfflineNotificationManager}
*/
/** Props for {@link OfflineNotificationManager} */
export type OfflineNotificationManagerProps = Readonly<React.PropsWithChildren>
/**
* Context props for {@link OfflineNotificationManager}
*/
/** Context props for {@link OfflineNotificationManager} */
interface OfflineNotificationManagerContextProps {
readonly isNested: boolean
readonly toastId?: string
@ -30,9 +26,7 @@ interface OfflineNotificationManagerContextProps {
const OfflineNotificationManagerContext =
React.createContext<OfflineNotificationManagerContextProps>({ isNested: false })
/**
* Offline Notification Manager component.
*/
/** Offline Notification Manager component. */
export function OfflineNotificationManager(props: OfflineNotificationManagerProps) {
const { children } = props
const toastId = 'offline'

View File

@ -17,17 +17,13 @@ import ContextMenuEntryBase from '#/components/ContextMenuEntry'
import * as paywallDialog from './PaywallDialog'
/**
* Props for {@link ContextMenuEntry}.
*/
/** Props for {@link ContextMenuEntry}. */
export interface ContextMenuEntryProps
extends Omit<contextMenuEntry.ContextMenuEntryProps, 'doAction' | 'isDisabled'> {
readonly feature: billingHooks.PaywallFeatureName
}
/**
* A context menu entry that opens a paywall dialog.
*/
/** A context menu entry that opens a paywall dialog. */
export function ContextMenuEntry(props: ContextMenuEntryProps) {
const { feature, ...rest } = props
const { setModal } = modalProvider.useSetModal()

View File

@ -16,9 +16,7 @@ import * as ariaComponents from '#/components/AriaComponents'
import * as paywall from '#/components/Paywall'
import SvgMask from '#/components/SvgMask'
/**
* Props for {@link PaywallAlert}.
*/
/** Props for {@link PaywallAlert}. */
export interface PaywallAlertProps extends Omit<ariaComponents.AlertProps, 'children'> {
readonly feature: billingHooks.PaywallFeatureName
readonly label: string
@ -26,9 +24,7 @@ export interface PaywallAlertProps extends Omit<ariaComponents.AlertProps, 'chil
readonly upgradeButtonProps?: Omit<paywall.UpgradeButtonProps, 'feature'>
}
/**
* A paywall alert.
*/
/** A paywall alert. */
export function PaywallAlert(props: PaywallAlertProps) {
const {
label,

View File

@ -15,16 +15,12 @@ import * as ariaComponents from '#/components/AriaComponents'
import * as components from './components'
import * as upgradeButton from './UpgradeButton'
/**
* Props for a {@link PaywallDialog}.
*/
/** Props for a {@link PaywallDialog}. */
export interface PaywallDialogProps extends ariaComponents.DialogProps {
readonly feature: billingHooks.PaywallFeatureName
}
/**
* A dialog that prompts the user to upgrade to a paid plan.
*/
/** A dialog that prompts the user to upgrade to a paid plan. */
export function PaywallDialog(props: PaywallDialogProps) {
const { feature, type = 'modal', title, ...dialogProps } = props

View File

@ -11,18 +11,14 @@ import * as ariaComponents from '#/components/AriaComponents'
import * as components from './components'
import * as paywallDialog from './PaywallDialog'
/**
* Props for a {@link PaywallDialogButton}.
*/
/** Props for a {@link PaywallDialogButton}. */
// eslint-disable-next-line no-restricted-syntax
export type PaywallDialogButtonProps = components.PaywallButtonProps & {
readonly dialogProps?: paywallDialog.PaywallDialogProps
readonly dialogTriggerProps?: ariaComponents.DialogTriggerProps
}
/**
* A button that opens a paywall dialog when clicked
*/
/** A button that opens a paywall dialog when clicked */
export function PaywallDialogButton(props: PaywallDialogButtonProps) {
const { feature, dialogProps, dialogTriggerProps, ...buttonProps } = props

View File

@ -17,17 +17,13 @@ import * as ariaComponents from '#/components/AriaComponents'
import * as components from './components'
import * as upgradeButton from './UpgradeButton'
/**
* Props for a {@link PaywallScreen}.
*/
/** Props for a {@link PaywallScreen}. */
export interface PaywallScreenProps {
readonly feature: billingHooks.PaywallFeatureName
readonly className?: string
}
/**
* A screen that shows a paywall.
*/
/** A screen that shows a paywall. */
export function PaywallScreen(props: PaywallScreenProps) {
const { feature, className } = props
const { getText } = textProvider.useText()

View File

@ -13,18 +13,14 @@ import * as textProvider from '#/providers/TextProvider'
import * as ariaComponents from '#/components/AriaComponents'
/**
* Props for an {@link UpgradeButton}.
*/
/** Props for an {@link UpgradeButton}. */
// eslint-disable-next-line no-restricted-syntax
export type UpgradeButtonProps = Omit<ariaComponents.ButtonProps, 'variant'> & {
readonly feature: billingHooks.PaywallFeatureName
readonly variant?: ariaComponents.ButtonProps['variant']
}
/**
* A button that links to the upgrade page.
*/
/** A button that links to the upgrade page. */
export function UpgradeButton(props: UpgradeButtonProps) {
const {
feature,

View File

@ -16,17 +16,13 @@ import * as textProvider from '#/providers/TextProvider'
import * as ariaComponents from '#/components/AriaComponents'
import SvgMask from '#/components/SvgMask'
/**
* Props for a {@link PaywallBulletPoints}.
*/
/** Props for a {@link PaywallBulletPoints}. */
export interface PaywallBulletPointsProps {
readonly bulletPointsTextId: text.TextId
readonly className?: string
}
/**
* A component that renders a list of bullet points for a paywall.
*/
/** A component that renders a list of bullet points for a paywall. */
export function PaywallBulletPoints(props: PaywallBulletPointsProps) {
const { bulletPointsTextId, className } = props

View File

@ -13,9 +13,7 @@ import * as textProvider from '#/providers/TextProvider'
import * as ariaComponents from '#/components/AriaComponents'
/**
* Props for {@link PaywallButton}.
*/
/** Props for {@link PaywallButton}. */
// eslint-disable-next-line no-restricted-syntax
export type PaywallButtonProps = ariaComponents.ButtonProps & {
readonly feature: billingHooks.PaywallFeatureName
@ -23,9 +21,7 @@ export type PaywallButtonProps = ariaComponents.ButtonProps & {
readonly showIcon?: boolean
}
/**
* A styled button that shows that a feature is behind a paywall
*/
/** A styled button that shows that a feature is behind a paywall */
export function PaywallButton(props: PaywallButtonProps) {
const { feature, iconOnly = false, showIcon = true, children, ...buttonProps } = props

View File

@ -1,6 +1,4 @@
/**
* @file A lock icon with a label indicating the paywall level required to access a feature.
*/
/** @file A lock icon with a label indicating the paywall level required to access a feature. */
import * as tw from 'tailwind-merge'
import LockIcon from '#/assets/lock.svg'
@ -12,17 +10,13 @@ import * as textProvider from '#/providers/TextProvider'
import * as ariaComponents from '#/components/AriaComponents'
import SvgMask from '#/components/SvgMask'
/**
* Props for a {@link PaywallLock}.
*/
/** Props for a {@link PaywallLock}. */
export interface PaywallLockProps {
readonly feature: billingHooks.PaywallFeatureName
readonly className?: string
}
/**
* A lock icon with a label indicating the paywall level required to access a feature.
*/
/** A lock icon with a label indicating the paywall level required to access a feature. */
export function PaywallLock(props: PaywallLockProps) {
const { feature, className } = props
const { getText } = textProvider.useText()

View File

@ -8,9 +8,7 @@ import invariant from 'tiny-invariant'
const PortalContext = React.createContext<Element | null>(null)
/**
* Allows to access the root element for the Portal component
*/
/** Allows to access the root element for the Portal component */
export function usePortalContext() {
const root = React.useContext(PortalContext)
@ -29,8 +27,6 @@ export function useStrictPortalContext() {
return root
}
/**
* Specifies the root element for the Portal component
*/
/** Specifies the root element for the Portal component */
// eslint-disable-next-line no-restricted-syntax
export const PortalProvider = PortalContext.Provider

View File

@ -4,9 +4,7 @@
*/
import type * as React from 'react'
/**
* The props for the Portal component
*/
/** The props for the Portal component */
export interface PortalProps {
/**
* Ref, where `<Portal />` should render its children
@ -19,9 +17,7 @@ export interface PortalProps {
* @default false
*/
readonly isDisabled?: boolean
/**
* Callback, will be called after portal's children mounted
*/
/** Callback, will be called after portal's children mounted */
readonly onMount?: () => void
readonly children?: React.ReactNode
}

View File

@ -19,9 +19,7 @@ import type * as stepperState from './useStepperState'
/** A prop with the given type, or a function to produce a value of the given type. */
type StepProp<T> = T | ((props: RenderStepProps) => T)
/**
* Props for {@link Step} component.
*/
/** Props for {@link Step} component. */
export interface StepProps extends RenderStepProps {
readonly className?: StepProp<string | null | undefined>
readonly icon?: StepProp<React.ReactElement | string | null | undefined>
@ -52,9 +50,7 @@ const STEP_STYLES = tv({
},
})
/**
* A step component is used to represent a single step in a stepper component.
*/
/** A step component is used to represent a single step in a stepper component. */
export function Step(props: StepProps) {
const {
index,

View File

@ -6,18 +6,14 @@ import type { ReactElement, ReactNode } from 'react'
import { useStepperContext } from './StepperProvider'
import type { RenderChildrenProps } from './types'
/**
* Props for {@link StepContent} component.
*/
/** Props for {@link StepContent} component. */
export interface StepContentProps {
readonly index: number
readonly children: ReactNode | ((props: RenderChildrenProps) => ReactNode)
readonly forceRender?: boolean
}
/**
* Step content component. Renders the step content if the step is current or if `forceRender` is true.
*/
/** Step content component. Renders the step content if the step is current or if `forceRender` is true. */
export function StepContent(props: StepContentProps): ReactElement | null {
const { index, children, forceRender = false } = props
const { currentStep, goToStep, nextStep, previousStep, totalSteps } = useStepperContext()

View File

@ -19,9 +19,7 @@ import * as stepperProvider from './StepperProvider'
import type { BaseRenderProps, RenderChildrenProps, RenderStepProps } from './types'
import * as stepperState from './useStepperState'
/**
* Props for {@link Stepper} component.
*/
/** Props for {@link Stepper} component. */
export interface StepperProps {
readonly state: stepperState.StepperState
readonly children: React.ReactNode | ((props: RenderChildrenProps) => React.ReactNode)
@ -48,9 +46,7 @@ const STEPPER_STYLES = tv({
const ANIMATION_OFFSET = 15
/**
* A stepper component is used to indicate progress through a multi-step process.
*/
/** A stepper component is used to indicate progress through a multi-step process. */
export function Stepper(props: StepperProps) {
const { renderStep, children, state } = props
@ -77,9 +73,7 @@ export function Stepper(props: StepperProps) {
const style = typeof props.style === 'function' ? props.style(baseRenderProps) : props.style
/**
* Render children of the stepper component.
*/
/** Render children of the stepper component. */
const renderChildren = () => {
const renderProps = {
currentStep,

View File

@ -9,9 +9,7 @@ import invariant from 'tiny-invariant'
import type { StepperState } from './useStepperState'
/**
* StepperProvider props
*/
/** StepperProvider props */
export interface StepperContextType {
readonly currentStep: number
readonly goToStep: (step: number) => void

View File

@ -4,9 +4,7 @@
* Types for the stepper component.
*/
/**
* Render props for the stepper component.
*/
/** Render props for the stepper component. */
export interface BaseRenderProps {
readonly goToStep: (step: number) => void
readonly nextStep: () => void
@ -15,21 +13,15 @@ export interface BaseRenderProps {
readonly totalSteps: number
}
/**
* Render props for rendering children of the stepper component.
*/
/** Render props for rendering children of the stepper component. */
export interface RenderChildrenProps extends BaseRenderProps {
readonly isFirst: boolean
readonly isLast: boolean
}
/**
* Render props for lazy rendering of steps.
*/
/** Render props for lazy rendering of steps. */
export interface RenderStepProps extends BaseRenderProps {
/**
* The index of the step, starting from 0.
*/
/** The index of the step, starting from 0. */
readonly index: number
readonly isCurrent: boolean
readonly isCompleted: boolean

View File

@ -9,30 +9,20 @@ import invariant from 'tiny-invariant'
import * as eventCallbackHooks from '#/hooks/eventCallbackHooks'
/**
* Direction of the stepper
*/
/** Direction of the stepper */
type Direction = 'back-none' | 'back' | 'forward-none' | 'forward' | 'initial'
/**
* Props for {@link useStepperState}
*/
/** Props for {@link useStepperState} */
export interface StepperStateProps {
/**
* The default step to start on (0-indexed)
*/
/** The default step to start on (0-indexed) */
readonly defaultStep?: number
/**
* The number of steps in the stepper (amount of steps is 1-indexed)
*/
/** The number of steps in the stepper (amount of steps is 1-indexed) */
readonly steps: number
readonly onStepChange?: (step: number, direction: 'back' | 'forward') => void
readonly onCompleted?: () => void
}
/**
* State for a stepper component
*/
/** State for a stepper component */
export interface StepperState {
readonly currentStep: number
readonly onStepChange: (step: number) => void
@ -43,9 +33,7 @@ export interface StepperState {
readonly percentComplete: number
}
/**
* Result of {@link useStepperState}
*/
/** Result of {@link useStepperState} */
export interface UseStepperStateResult {
readonly stepperState: StepperState
readonly direction: Direction

View File

@ -18,9 +18,7 @@ import * as result from '#/components/Result'
import * as loader from './Loader'
/**
* Props for {@link Suspense} component.
*/
/** Props for {@link Suspense} component. */
export interface SuspenseProps extends React.SuspenseProps {
readonly loaderProps?: loader.LoaderProps
readonly offlineFallback?: React.ReactNode

View File

@ -7,9 +7,7 @@ import { useInteractOutside } from '#/components/aria'
import { useEffect, useRef } from 'react'
import { useEventCallback } from './eventCallbackHooks'
/**
* Props for the {@link useAutoFocus} hook.
*/
/** Props for the {@link useAutoFocus} hook. */
export interface UseAutoFocusProps {
readonly ref: React.RefObject<HTMLElement>
readonly disabled?: boolean | undefined

View File

@ -8,9 +8,7 @@ import type * as text from 'enso-common/src/text'
import * as backend from '#/services/Backend'
/**
* Registered paywall features.
*/
/** Registered paywall features. */
export const PAYWALL_FEATURES = {
userGroups: 'userGroups',
userGroupsFull: 'userGroupsFull',
@ -20,14 +18,10 @@ export const PAYWALL_FEATURES = {
shareFull: 'shareFull',
} as const
/**
* Paywall features.
*/
/** Paywall features. */
export type PaywallFeatureName = keyof typeof PAYWALL_FEATURES
/**
* Paywall level names
*/
/** Paywall level names */
export type PaywallLevelName = backend.Plan | 'free'
/**
@ -42,9 +36,7 @@ export type PaywallLevelValue =
| (2 & { readonly name: PaywallLevelName; readonly label: text.TextId })
| (3 & { readonly name: PaywallLevelName; readonly label: text.TextId })
/**
* Paywall levels configuration.
*/
/** Paywall levels configuration. */
export const PAYWALL_LEVELS: Record<PaywallLevelName, PaywallLevelValue> = {
free: Object.assign(0, { name: 'free', label: 'freePlanName' } as const),
[backend.Plan.solo]: Object.assign(1, {
@ -61,14 +53,10 @@ export const PAYWALL_LEVELS: Record<PaywallLevelName, PaywallLevelValue> = {
} as const),
}
/**
*
*/
/** Possible paywall unlock states for a user account. */
export type PaywallLevel = (typeof PAYWALL_LEVELS)[keyof typeof PAYWALL_LEVELS]
/**
* Paywall feature labels.
*/
/** Paywall feature labels. */
const PAYWALL_FEATURES_LABELS: Record<PaywallFeatureName, text.TextId> = {
userGroups: 'userGroupsFeatureLabel',
userGroupsFull: 'userGroupsFullFeatureLabel',
@ -88,18 +76,14 @@ const PAYWALL_FEATURE_META = {
shareFull: undefined,
} satisfies { [K in PaywallFeatureName]: unknown }
/**
* Basic feature configuration.
*/
/** Basic feature configuration. */
interface BasicFeatureConfiguration {
readonly level: PaywallLevel
readonly bulletPointsTextId: `${PaywallFeatureName}FeatureBulletPoints`
readonly descriptionTextId: `${PaywallFeatureName}FeatureDescription`
}
/**
* Feature configuration.
*/
/** Feature configuration. */
export type FeatureConfiguration<Key extends PaywallFeatureName = PaywallFeatureName> =
BasicFeatureConfiguration & {
readonly name: Key
@ -140,23 +124,17 @@ const PAYWALL_CONFIGURATION: Record<PaywallFeatureName, BasicFeatureConfiguratio
},
}
/**
* Map a plan to a paywall level.
*/
/** Map a plan to a paywall level. */
export function mapPlanOnPaywall(plan: backend.Plan | undefined): PaywallLevel {
return plan != null ? PAYWALL_LEVELS[plan] : PAYWALL_LEVELS.free
}
/**
* Check if a given string is a valid feature name.
*/
/** Check if a given string is a valid feature name. */
export function isFeatureName(name: string): name is PaywallFeatureName {
return name in PAYWALL_FEATURES
}
/**
* Get the configuration for a given feature.
*/
/** Get the configuration for a given feature. */
export function getFeatureConfiguration<Key extends PaywallFeatureName>(
feature: Key,
): FeatureConfiguration<Key> {

View File

@ -8,9 +8,7 @@ import * as eventCallbackHooks from '#/hooks/eventCallbackHooks'
import * as paywallFeaturesConfiguration from './FeaturesConfiguration'
/**
* A hook that provides access to the paywall features configuration.
*/
/** A hook that provides access to the paywall features configuration. */
export function usePaywallFeatures() {
const getFeature = eventCallbackHooks.useEventCallback(
<Key extends paywallFeaturesConfiguration.PaywallFeatureName>(feature: Key) => {

View File

@ -12,17 +12,13 @@ import type * as backend from '#/services/Backend'
import * as paywallConfiguration from './FeaturesConfiguration'
import * as paywallFeatures from './paywallFeaturesHooks'
/**
* Props for the {@link usePaywall} hook.
*/
/** Props for the {@link usePaywall} hook. */
export interface UsePaywallProps {
// eslint-disable-next-line no-restricted-syntax
readonly plan?: backend.Plan | undefined
}
/**
* A hook that provides paywall-related functionality.
*/
/** A hook that provides paywall-related functionality. */
export function usePaywall(props: UsePaywallProps) {
const { plan } = props

View File

@ -13,9 +13,7 @@ import * as toastAndLogHooks from '#/hooks/toastAndLogHooks'
import * as textProvider from '#/providers/TextProvider'
/**
* Props for the useCopy hook.
*/
/** Props for the useCopy hook. */
export interface UseCopyProps {
readonly copyText: string
readonly onCopy?: () => void
@ -24,9 +22,7 @@ export interface UseCopyProps {
const DEFAULT_TIMEOUT = 2000
/**
* A hook for copying text to the clipboard.
*/
/** A hook for copying text to the clipboard. */
export function useCopy(props: UseCopyProps) {
const { copyText, onCopy, successToastMessage = true } = props

View File

@ -8,9 +8,7 @@ import * as React from 'react'
import * as callbackHooks from './eventCallbackHooks'
import * as unmountEffect from './unmountHooks'
/**
* Wrap a callback into debounce function
*/
/** Wrap a callback into debounce function */
export function useDebouncedCallback<Fn extends (...args: never[]) => unknown>(
callback: Fn,
deps: React.DependencyList,
@ -83,9 +81,8 @@ export function useDebouncedCallback<Fn extends (...args: never[]) => unknown>(
}, [stableCallback, delay, maxWait, ...deps])
}
/**
*
*/
export interface DebouncedFunction<Fn extends (...args: never[]) => unknown> {
(this: ThisParameterType<Fn>, ...args: Parameters<Fn>): void
}
/** The type of a wrapped function that has been debounced. */
export type DebouncedFunction<Fn extends (...args: never[]) => unknown> = (
this: ThisParameterType<Fn>,
...args: Parameters<Fn>
) => void

View File

@ -9,9 +9,7 @@ import * as React from 'react'
import * as debouncedCallback from './debounceCallbackHooks'
import * as eventCallbackHooks from './eventCallbackHooks'
/**
* A hook that returns a stateful value, and a function to update it that will debounce updates.
*/
/** A hook that returns a stateful value, and a function to update it that will debounce updates. */
export function useDebounceState<S>(
initialState: S | (() => S),
delay: number,

View File

@ -5,9 +5,7 @@
*/
import * as debounceState from './debounceStateHooks'
/**
* Debounce a value.
*/
/** Debounce a value. */
export function useDebounceValue<T>(value: T, delay: number, maxWait?: number) {
const [debouncedValue, setDebouncedValue] = debounceState.useDebounceState(value, delay, maxWait)

View File

@ -34,9 +34,7 @@ export function useMounted(callback: () => void) {
}, [stableCallback])
}
/**
* Returns a function that returns `true` if the component renders for the first time.
*/
/** Returns a function that returns `true` if the component renders for the first time. */
export function useIsFirstRender() {
const isFirstMount = useRef(true)
const stableCallbackTrue = useEventCallback(() => true)

View File

@ -9,9 +9,7 @@ import * as reactQuery from '@tanstack/react-query'
import * as eventCallback from '#/hooks/eventCallbackHooks'
/**
* Hook to get the offline status
*/
/** Hook to get the offline status */
export function useOffline() {
const isOnline = React.useSyncExternalStore(
reactQuery.onlineManager.subscribe.bind(reactQuery.onlineManager),
@ -22,17 +20,13 @@ export function useOffline() {
return { isOffline: !isOnline }
}
/**
* Props for the {@link useOfflineChange} hook
*/
/** Props for the {@link useOfflineChange} hook */
export interface UseOfflineChangeProps {
readonly triggerImmediate?: boolean | 'if-offline' | 'if-online'
readonly isDisabled?: boolean
}
/**
* Hook to subscribe to online/offline changes
*/
/** Hook to subscribe to online/offline changes */
export function useOfflineChange(
callback: (isOffline: boolean) => void,
props: UseOfflineChangeProps = {},

View File

@ -18,9 +18,7 @@ import * as safeJsonParse from '#/utilities/safeJsonParse'
// === SearchParamsStateReturnType ===
// ===================================
/**
* The return type of the `useSearchParamsState` hook.
*/
/** The return type of the `useSearchParamsState` hook. */
type SearchParamsStateReturnType<T> = Readonly<
[
value: T,
@ -29,9 +27,7 @@ type SearchParamsStateReturnType<T> = Readonly<
]
>
/**
* Set options for the `set` function.
*/
/** Set options for the `set` function. */
export interface SearchParamsSetOptions {
readonly replace?: boolean
}

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