diff --git a/package.json b/package.json index 6c34060f1d..acd03aefd2 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,8 @@ "build:generate-package-json-files": "node ./scripts/generate_package_json_files/index.js", "build:move-svg": "node ./scripts/copy_svg/index.js", "build:skills": "node ./scripts/skills/build_skills.mjs", + "validate:mdx": "node ./scripts/validate-mdx/index.mjs", + "test:validate-mdx": "node --test ./scripts/validate-mdx/*.test.mjs", "generate-tokens": "rimraf ./src/components/tokens-wrapper/static-tokens && node ./scripts/generate_tokens/generate_tokens.mjs --include-dark" }, "repository": { diff --git a/scripts/skills/build_skills.mjs b/scripts/skills/build_skills.mjs index 85f7c14608..83be734c6f 100644 --- a/scripts/skills/build_skills.mjs +++ b/scripts/skills/build_skills.mjs @@ -1,1278 +1,209 @@ // @ts-check import path from "node:path"; import fs from "node:fs/promises"; -import { existsSync, statSync } from "node:fs"; -import { fileURLToPath } from "node:url"; +import { existsSync } from "node:fs"; import fg from "fast-glob"; -import { JSDoc, Project, SyntaxKind } from "ts-morph"; - -/** - * @typedef {Object} ComponentCandidate - * @property {string} name - * @property {string} [displayName] - * @property {string} moduleSpecifier - */ - -/** - * @typedef {Object} PropsDefinition - * @property {string} name - * @property {import("ts-morph").InterfaceDeclaration | import("ts-morph").TypeAliasDeclaration} node - */ - -/** - * @typedef {Object} PropInfo - * @property {string} name - * @property {string} type - * @property {boolean} required - * @property {Array | null} literals - * @property {string | null} description - * @property {string | null} defaultValue - * @property {boolean} deprecated - * @property {string | null} deprecationReason - */ - -/** - * @typedef {Object} ComponentData - * @property {string} name - * @property {string} importName - * @property {string} moduleSpecifier - * @property {PropInfo[]} props - * @property {boolean} missingPropsInterface - * @property {string | null} propsInterfaceName - * @property {boolean} hasDefaultExport - * @property {boolean} deprecated - * @property {string | null} deprecationReason - */ - -/** - * @typedef {Object} StoryEntry - * @property {string} name - * @property {string | null} argsText - * @property {string | null} renderText - * @property {"csf" | "mdx"} kind - * @property {string} [source] - */ - -/** - * @typedef {Object} StoryMeta - * @property {string | null} title - * @property {string | null} componentIdentifier - * @property {string | null} componentModule - */ - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const repoRoot = path.resolve(__dirname, "../.."); -const packageName = "carbon-react"; +import { + repoRoot, + skillsRoot, + componentsOutDir, + referencesDir, + referencesExamplesDir, + docsReferenceFiles, +} from "./skills-config.mjs"; +import { discoverMdx } from "./mdx-discovery.mjs"; +import { parseMdxFile } from "./mdx-parser.mjs"; +import { getOrAddSourceFile } from "./ts-project.mjs"; +import { getStoryExampleSource } from "./story-source.mjs"; +import { resolvePropsForStories } from "./props-from-stories.mjs"; +import { parseAndRenderReferenceMdx } from "./reference-mdx.mjs"; +import { + renderSkillMd, + renderSkillRootContent, + renderIndexContent, +} from "./renderers.mjs"; +import { resolveStoriesPath } from "./utils.mjs"; const checkMode = process.argv.includes("--check"); -const buildOutputFolder = "lib"; -const indexFilePath = path.join(repoRoot, "src", "index.ts"); -const skillsRoot = path.join(repoRoot, "skills", "carbon-react"); -const componentsOutDir = path.join(skillsRoot, "components"); -const referencesDir = path.join(skillsRoot, "references", "docs"); - -/** @type {string[]} */ -const docsReferenceFiles = [ - "docs/usage.mdx", - "docs/installation.mdx", - "docs/recommended-practices.mdx", - "docs/usage-with-routing.mdx", - "docs/extending-styles-using-styled-components.mdx", - "docs/colors.mdx", - "docs/i18n.mdx", - "docs/deprecation-migration.mdx", -]; - -const docsReferenceTargets = docsReferenceFiles.map( - (relativePath) => - `references/docs/${path.basename(relativePath).replace(/\.mdx?$/, ".md")}`, -); - -const project = new Project({ - tsConfigFilePath: path.join(repoRoot, "tsconfig.json"), - skipAddingFilesFromTsConfig: true, -}); - -project.addSourceFileAtPath(indexFilePath); -project.addSourceFilesAtPaths([ - path.join(repoRoot, "src", "components", "**", "*.ts"), - path.join(repoRoot, "src", "components", "**", "*.tsx"), -]); - -const indexFile = project.getSourceFileOrThrow(indexFilePath); - -/** @type {ComponentCandidate[]} */ -const componentCandidates = []; - -// Scan __next__ directories for upcoming components -const nextComponentFiles = fg.sync( - ["src/components/**/__next__/index.{ts,tsx}", "src/components/**/__next__/*.component.{ts,tsx}"], - { - cwd: repoRoot, - absolute: true, - ignore: ["**/__internal__/**"] - } -); - -for (const filePath of nextComponentFiles) { - const sourceFile = project.addSourceFileAtPathIfExists(filePath); - if (!sourceFile) continue; - - const exported = sourceFile.getExportedDeclarations(); - for (const [exportName, declarations] of exported.entries()) { - if (exportName === "default" || exportName.endsWith("Props")) continue; - if (!/^[A-Z]/.test(exportName)) continue; - - const relativePath = "./" + path.relative(path.join(repoRoot, "src"), filePath).replace(/\\/g, "/"); - const rawModuleSpecifier = relativePath - .replace(/\/index\.(ts|tsx)$/, "") - .replace(/\.(ts|tsx)$/, ""); - const moduleSpecifier = rawModuleSpecifier.replace( - /(\/__next__)\/.*\.component$/, - "$1", - ); - - // Keep original name for props lookup, use display name for output - componentCandidates.push({ - name: exportName, // Original name for props lookup - displayName: `${exportName}Next`, // Display name for output files - moduleSpecifier, - }); - } -} - -for (const exportDecl of indexFile.getExportDeclarations()) { - const moduleSpecifier = exportDecl.getModuleSpecifierValue(); - if (!moduleSpecifier || !moduleSpecifier.startsWith("./components/")) { - continue; - } - - const namedExports = exportDecl.getNamedExports(); - if (exportDecl.isTypeOnly()) { - continue; - } - - // Only treat runtime exports from src/index.ts as components. Type-only - // exports (Props, handles) would create false component entries. - for (const namedExport of namedExports) { - const exportName = - namedExport.getAliasNode()?.getText() ?? namedExport.getName(); - if (exportName === "default" || exportName.endsWith("Props")) { - continue; - } - if (!/^[A-Z]/.test(exportName)) { - continue; - } - componentCandidates.push({ - name: exportName, - moduleSpecifier, - }); - } -} - -const uniqueComponentCandidates = dedupeComponentCandidates(componentCandidates); - -/** @type {ComponentData[]} */ -const componentData = []; - -for (const candidate of uniqueComponentCandidates) { - const modulePath = resolveModulePath( - indexFilePath, - candidate.moduleSpecifier, - ); - if (!modulePath) { - continue; - } - - const moduleDir = getModuleDir(modulePath); - const moduleFiles = fg.sync(["**/*.{ts,tsx}"], { - cwd: moduleDir, - absolute: true, - ignore: [ - "**/*.spec.*", - "**/*.test.*", - "**/*.stories.*", - "**/*.pw.*", - "**/*.mdx", - "**/__internal__/**", - "**/__next__/**", - ], - }).sort(); +const { mdxEntries, mdxToSlug, availableSlugs } = await discoverMdx(); - for (const filePath of moduleFiles) { - project.addSourceFileAtPathIfExists(filePath); - } - - const propsName = `${candidate.name}Props`; - const propsDefinition = resolvePropsDefinition( - project, - modulePath, - moduleFiles, - propsName, - ); - // Use ts-morph to follow type re-exports (e.g., AlertProps -> DialogProps) - // so deprecated components still yield accurate props. - const defaultsMap = collectDefaultProps(project, moduleFiles, candidate.name); - const hasDefaultExport = moduleHasDefaultExport(project, modulePath); - const deprecationInfo = detectDeprecation( - project, - modulePath, - moduleFiles, - candidate.name, - ); - - // Deprecation can be attached to the component export, its props interface, - // or a type alias, so we scan multiple nodes in detectDeprecation(). - - const props = propsDefinition - ? extractPropsFromDefinition(propsDefinition, defaultsMap) - : []; - - componentData.push({ - name: candidate.displayName ?? candidate.name, - importName: candidate.name, - moduleSpecifier: candidate.moduleSpecifier, - props, - missingPropsInterface: !propsDefinition, - propsInterfaceName: propsDefinition?.name ?? null, - hasDefaultExport, - deprecated: deprecationInfo.deprecated, - deprecationReason: deprecationInfo.reason, - }); -} - -const storyDataByComponent = await extractStoryData(project, repoRoot); - -/** @type {Array<{path: string, content: string}>} */ +/** @type {import("./skills-types.mjs").OutputFile[]} */ const wouldWrite = []; -/** @type {Map} */ -const lineEndingPreferences = !checkMode - ? await collectLineEndingPreferences([componentsOutDir, referencesDir, skillsRoot]) - : new Map(); - -if (!checkMode) { - await fs.rm(componentsOutDir, { recursive: true, force: true }); - await fs.rm(referencesDir, { recursive: true, force: true }); - await fs.mkdir(componentsOutDir, { recursive: true }); - await fs.mkdir(skillsRoot, { recursive: true }); - await fs.mkdir(referencesDir, { recursive: true }); -} +/** @type {Array<{title: string, slug: string, description: string, category: string, isDeprecated: boolean}>} */ +const indexEntries = []; -const skillRootContent = renderSkillRootContent(); -wouldWrite.push({ path: path.join(skillsRoot, "SKILL.md"), content: skillRootContent }); +let processedCount = 0; +let skippedCount = 0; -for (const relativePath of docsReferenceFiles) { - const sourcePath = path.join(repoRoot, relativePath); - if (!existsSync(sourcePath)) { +for (const entry of mdxEntries) { + const slug = mdxToSlug.get(entry.mdxPath); + if (!slug) { + skippedCount++; continue; } - const fileName = path.basename(sourcePath); - const targetPath = path.join(referencesDir, fileName).replace(/\.mdx?$/, ".md"); - const content = await fs.readFile(sourcePath, "utf8"); - wouldWrite.push({ path: targetPath, content: content.replace(/\r\n/g, "\n") }); -} - -const indexLines = ["# Carbon Component Catalog", "", "## Components", ""]; - -for (const component of componentData.sort((a, b) => - a.name.localeCompare(b.name), -)) { - const stories = storyDataByComponent.get(component.name) ?? []; - const fileName = `${toKebabCase(component.name)}.md`; - const filePath = path.join(componentsOutDir, fileName); - const markdown = renderComponentMarkdown(component, stories); - - wouldWrite.push({ path: filePath, content: markdown }); - const deprecatedLabel = component.deprecated ? " (deprecated)" : ""; - indexLines.push( - `- [${component.name}](components/${fileName})${deprecatedLabel}`, - ); -} - -const indexContent = indexLines.join("\n"); -wouldWrite.push({ path: path.join(skillsRoot, "index.md"), content: indexContent }); -if (checkMode) { - const { hasDiff, diffSummary } = await checkWouldWrite(wouldWrite, { - componentsOutDir, - referencesDir, + const mdxDir = path.dirname(entry.mdxPath); + const parsed = parseMdxFile(entry.content); + + // Collect for catalog index + const descOneLine = parsed.description + .replace(/\n+/g, " ") + .replace(/\[([^\]]+)\]\([^)]+\)/g, "$1") + .replace(/]*>([\s\S]*?)<\/a>/g, (_, t) => t.replace(/<[^>]+>/g, "")) + .replace(/<[^>]+>/g, "") + .trim(); + indexEntries.push({ + title: parsed.componentTitle, + slug, + description: descOneLine, + category: parsed.category ?? "", + isDeprecated: entry.isDeprecated, }); - if (hasDiff) { - // eslint-disable-next-line no-console -- CI output - console.error("Skills build check failed: files on disk differ from expected output:\n"); - // eslint-disable-next-line no-console -- CI output - console.error(diffSummary); - process.exit(1); - } - // eslint-disable-next-line no-console -- CI output - console.log( - `Check passed: ${componentData.length} component skill files are up to date.`, - ); -} else { - for (const { path: filePath, content } of wouldWrite) { - await fs.mkdir(path.dirname(filePath), { recursive: true }); - const contentToWrite = await applyExistingLineEndingPreference( - filePath, - content, - lineEndingPreferences, - ); - await fs.writeFile(filePath, contentToWrite, "utf8"); - } - // eslint-disable-next-line no-console -- Log summary of generated components and output location - console.log( - `Generated ${componentData.length} component skill files in ${path.relative( - repoRoot, - componentsOutDir, - )}`, - ); -} - -/** - * Normalize a file path for consistent key lookups across platforms. - * @param {string} filePath - * @returns {string} - */ -function normalizePathKey(filePath) { - return filePath.replace(/\\/g, "/").toLowerCase(); -} - -/** - * Collect line ending preferences from existing files in directories. - * @param {string[]} directories - * @returns {Promise>} - */ -async function collectLineEndingPreferences(directories) { - /** @type {Map} */ - const preferences = new Map(); - - for (const dir of directories) { - if (!existsSync(dir)) { - continue; - } - - const files = await fs.readdir(dir, { recursive: true, withFileTypes: true }); - - for (const file of files) { - if (!file.isFile()) { - continue; - } - - const fullPath = path.join(file.parentPath, file.name); - - try { - const content = await fs.readFile(fullPath, "utf8"); - const hasLines = content.includes("\r\n"); - const key = normalizePathKey(fullPath); - preferences.set(key, hasLines ? "crlf" : "lf"); - } catch { - // Ignore files we can't read - } - } - } - - return preferences; -} - -/** - * Apply existing line ending preference to content. - * @param {string} filePath - * @param {string} content - * @param {Map} preferences - * @returns {Promise} - */ -async function applyExistingLineEndingPreference(filePath, content, preferences) { - const key = normalizePathKey(filePath); - const preference = preferences.get(key); - - // Default to LF for new files or if no preference found - if (preference === "crlf") { - return content.replace(/\n/g, "\r\n"); - } - - return content; -} - -/** - * Resolve a module specifier from the index file to an absolute file path. - * @param {string} indexPath - * @param {string} moduleSpecifier - * @returns {string | null} - */ -function resolveModulePath(indexPath, moduleSpecifier) { - return resolveModulePathFrom(indexPath, moduleSpecifier); -} - -/** - * Resolve a module specifier relative to a base file path. - * @param {string} baseFilePath - * @param {string} moduleSpecifier - * @returns {string | null} - */ -function resolveModulePathFrom(baseFilePath, moduleSpecifier) { - const basePath = path.resolve(path.dirname(baseFilePath), moduleSpecifier); - const candidates = []; - - if (existsSync(basePath)) { - const stats = statSync(basePath); - if (stats.isFile()) { - candidates.push(basePath); - } - } - - candidates.push(`${basePath}.ts`, `${basePath}.tsx`); - candidates.push(path.join(basePath, "index.ts")); - candidates.push(path.join(basePath, "index.tsx")); - - for (const candidate of candidates) { - if (existsSync(candidate)) { - return candidate; - } - } - - return null; -} - -/** - * Return the directory for a resolved module path. - * @param {string} modulePath - * @returns {string} - */ -function getModuleDir(modulePath) { - if (existsSync(modulePath)) { - return modulePath.endsWith(".ts") || modulePath.endsWith(".tsx") - ? path.dirname(modulePath) - : modulePath; - } - return path.dirname(modulePath); -} -/** - * Find a type/interface definition by name in a list of files. - * @param {import("ts-morph").Project} projectInstance - * @param {string[]} filePaths - * @param {string} typeName - * @returns {PropsDefinition | null} - */ -function findTypeDefinitionInFiles(projectInstance, filePaths, typeName) { - for (const filePath of filePaths) { - const sourceFile = - projectInstance.getSourceFile(filePath) || - projectInstance.addSourceFileAtPathIfExists(filePath); - if (!sourceFile) { - continue; - } - const interfaceMatch = sourceFile.getInterface(typeName); - if (interfaceMatch) { - return { name: interfaceMatch.getName(), node: interfaceMatch }; - } - const aliasMatch = sourceFile.getTypeAlias(typeName); - if (aliasMatch) { - return { name: aliasMatch.getName(), node: aliasMatch }; + // Resolve stories files + /** @type {Map} alias -> absolute path */ + const resolvedStories = new Map(); + for (const [alias, relativePath] of parsed.storiesImports.entries()) { + const resolved = resolveStoriesPath(mdxDir, relativePath); + if (resolved) { + resolvedStories.set(alias, resolved); + getOrAddSourceFile(resolved); } } - return null; -} -/** - * Resolve props definition for a component, following type re-exports. - * @param {import("ts-morph").Project} projectInstance - * @param {string} modulePath - * @param {string[]} moduleFiles - * @param {string} propsName - * @returns {PropsDefinition | null} - */ -function resolvePropsDefinition( - projectInstance, - modulePath, - moduleFiles, - propsName, -) { - const directMatch = findTypeDefinitionInFiles( - projectInstance, - moduleFiles, - propsName, - ); - if (directMatch) { - return directMatch; - } + // Extract examples + /** @type {import("./skills-types.mjs").ExampleFile[]} */ + const exampleFiles = []; - // Props are sometimes re-exported from another module; follow the type-only - // export to locate the real definition. + for (const example of parsed.examples) { + for (const item of example.items) { + const { canvasRef, description } = item; - const entryFile = - projectInstance.getSourceFile(modulePath) || - projectInstance.addSourceFileAtPathIfExists(modulePath); - if (!entryFile) { - return null; - } - - for (const exportDecl of entryFile.getExportDeclarations()) { - if (!exportDecl.isTypeOnly()) { - continue; - } - const moduleSpecifier = exportDecl.getModuleSpecifierValue(); - if (!moduleSpecifier) { - continue; - } - for (const namedExport of exportDecl.getNamedExports()) { - const alias = namedExport.getAliasNode()?.getText(); - const exportedName = namedExport.getName(); - if (alias !== propsName && exportedName !== propsName) { + if (!canvasRef) { + // Prose-only item: no example file, just description + exampleFiles.push({ + heading: example.heading, + fileName: null, + description, + }); continue; } - const targetName = alias ? exportedName : propsName; - const resolved = resolveModulePathFrom(modulePath, moduleSpecifier); - if (!resolved) { + const storiesPath = resolvedStories.get(canvasRef.alias); + if (!storiesPath) { + console.warn( + `[${slug}] Cannot resolve stories alias: ${canvasRef.alias}`, + ); continue; } - const targetFiles = fg.sync(["**/*.{ts,tsx}"], { - cwd: getModuleDir(resolved), - absolute: true, - ignore: [ - "**/*.spec.*", - "**/*.test.*", - "**/*.stories.*", - "**/*.pw.*", - "**/*.mdx", - "**/__internal__/**", - "**/__next__/**", - ], - }).sort(); - - const resolvedDefinition = findTypeDefinitionInFiles( - projectInstance, - targetFiles, - targetName, + const source = await getStoryExampleSource( + storiesPath, + canvasRef.exportName, ); - if (resolvedDefinition) { - return resolvedDefinition; + if (!source) { + console.warn( + `[${slug}] Cannot find export "${canvasRef.exportName}" in ${path.basename(storiesPath)}`, + ); + continue; } - } - } - - return null; -} - -/** - * Determine if a module has a default export. - * @param {import("ts-morph").Project} projectInstance - * @param {string} modulePath - * @returns {boolean} - */ -function moduleHasDefaultExport(projectInstance, modulePath) { - const sourceFile = - projectInstance.getSourceFile(modulePath) || - projectInstance.addSourceFileAtPathIfExists(modulePath); - if (!sourceFile) { - return false; - } - if (sourceFile.getDefaultExportSymbol()) { - return true; - } - const exportAssignment = sourceFile - .getExportAssignments() - .find((assignment) => !assignment.isExportEquals()); - return Boolean(exportAssignment); -} - -/** - * Extract prop metadata from a props definition, including defaults and deprecations. - * @param {PropsDefinition} propsDefinition - * @param {Map} defaultsMap - * @returns {PropInfo[]} - */ -function extractPropsFromDefinition(propsDefinition, defaultsMap) { - const type = propsDefinition.node.getType(); - return type - .getProperties() - .filter((symbol) => !shouldExcludePropSymbol(symbol)) - .map((symbol) => { - const declaration = symbol - .getDeclarations() - .find( - (decl) => - decl.isKind(SyntaxKind.PropertySignature) || - decl.isKind(SyntaxKind.PropertyDeclaration), + const fileName = `${canvasRef.exportName}.md`; + const fileContent = "```tsx\n" + source + "\n```"; + const outputPath = path.join( + componentsOutDir, + slug, + "examples", + fileName, ); - const propType = declaration - ? declaration.getType() - : symbol.getTypeAtLocation(propsDefinition.node); - const literals = getLiteralUnionValues(propType); - const jsDocs = declaration?.getJsDocs?.() ?? []; - const description = jsDocs - .map((doc) => doc.getDescription().trim()) - .filter(Boolean) - .join(" "); - const deprecationInfo = getDeprecationFromJsDocs(jsDocs); - const required = declaration?.isKind(SyntaxKind.PropertySignature) - ? !declaration.hasQuestionToken() - : true; - - const resolvedText = propType.getText(declaration ?? propsDefinition.node); - const typeNode = declaration?.getTypeNode?.(); - const typeText = ( - resolvedText.includes("import(") && typeNode - ? typeNode.getText() - : resolvedText - ).replace(/\s+/g, " ").trim(); - - return { - name: symbol.getName(), - type: typeText, - required, - literals, - description: description || null, - defaultValue: defaultsMap.get(symbol.getName()) ?? null, - deprecated: deprecationInfo.deprecated, - deprecationReason: deprecationInfo.reason, - }; - }); -} - -/** - * Determine whether a prop symbol should be excluded from generated docs. - * @param {import("ts-morph").Symbol} symbol - * @returns {boolean} - */ -function shouldExcludePropSymbol(symbol) { - const declarations = symbol - .getDeclarations() - .filter( - (declaration) => - declaration.isKind(SyntaxKind.PropertySignature) || - declaration.isKind(SyntaxKind.PropertyDeclaration), - ); - - if (!declarations.length) { - return false; - } - - // Only exclude when every contributing declaration is explicitly internal/private. - // This avoids removing public props that share a symbol across legacy and internal types. - return declarations.every((declaration) => { - const jsDocs = getJsDocsFromNode(declaration); - return hasExcludedVisibilityTag(jsDocs); - }); -} - -/** - * Detect JSDoc visibility tags that should hide a prop from generated docs. - * @param {import("ts-morph").JSDoc[]} jsDocs - * @returns {boolean} - */ -function hasExcludedVisibilityTag(jsDocs) { - for (const doc of jsDocs) { - for (const tag of doc.getTags()) { - const tagName = tag.getTagName().toLowerCase(); - if ( - tagName === "private" || - tagName === "ignore" || - tagName === "internal" || - tagName === "hidden" - ) { - return true; - } + wouldWrite.push({ path: outputPath, content: fileContent }); + exampleFiles.push({ heading: example.heading, fileName, description }); } } - return false; -} -/** - * Return literal values for simple union types when all members are literals. - * @param {import("ts-morph").Type} type - * @returns {Array | null} - */ -function getLiteralUnionValues(type) { - if (!type.isUnion()) { - return null; - } - const unionTypes = type.getUnionTypes(); - /** @type {Array} */ - const literals = []; - - for (const unionType of unionTypes) { - if (unionType.isStringLiteral()) { - const literalValue = unionType.getLiteralValue(); - if (literalValue === undefined) { - return null; - } - literals.push(String(literalValue)); - continue; - } - if (unionType.isNumberLiteral()) { - const literalValue = unionType.getLiteralValue(); - if (literalValue === undefined) { - return null; - } - literals.push( - typeof literalValue === "number" ? literalValue : String(literalValue), + // Extract props + /** @type {Map} */ + const propsMap = new Map(); + for (const argTypeRef of parsed.argTypeRefs) { + const storiesPath = resolvedStories.get(argTypeRef.alias); + const heading = + argTypeRef.heading ?? argTypeRef.alias.replace(/Stories$/, ""); + if (!storiesPath) { + console.warn( + `[${slug}] Cannot resolve ArgTypes stories alias: ${argTypeRef.alias}`, ); + propsMap.set(heading, []); continue; } - if (unionType.isBooleanLiteral()) { - const literalValue = unionType.getLiteralValue(); - if (literalValue === undefined) { - return null; - } - literals.push(Boolean(literalValue)); - continue; - } - return null; - } - - return literals; -} - -/** - * Collect default prop values from destructured parameters and defaultProps. - * @param {import("ts-morph").Project} projectInstance - * @param {string[]} filePaths - * @param {string} componentName - * @returns {Map} - */ -function collectDefaultProps(projectInstance, filePaths, componentName) { - const defaults = new Map(); - - for (const filePath of filePaths) { - const sourceFile = - projectInstance.getSourceFile(filePath) || - projectInstance.addSourceFileAtPathIfExists(filePath); - if (!sourceFile) { - continue; - } - - const defaultExportSymbol = sourceFile.getDefaultExportSymbol(); - if (defaultExportSymbol) { - const declarations = defaultExportSymbol.getDeclarations(); - for (const declaration of declarations) { - const defaultsFromDeclaration = - extractDefaultsFromDeclaration(declaration); - for (const [key, value] of defaultsFromDeclaration.entries()) { - defaults.set(key, value); - } - } - } - - const namedFunction = sourceFile - .getFunctions() - .find((fn) => fn.getName() === componentName); - if (namedFunction) { - const defaultsFromDeclaration = - extractDefaultsFromDeclaration(namedFunction); - for (const [key, value] of defaultsFromDeclaration.entries()) { - defaults.set(key, value); - } - } - - const namedVariable = sourceFile - .getVariableDeclarations() - .find((decl) => decl.getName() === componentName); - if (namedVariable) { - const defaultsFromDeclaration = - extractDefaultsFromDeclaration(namedVariable); - for (const [key, value] of defaultsFromDeclaration.entries()) { - defaults.set(key, value); - } - } - - const assignments = sourceFile.getDescendantsOfKind( - SyntaxKind.BinaryExpression, - ); - for (const assignment of assignments) { - const left = assignment.getLeft(); - const right = assignment.getRight(); - if (!right || !right.isKind(SyntaxKind.ObjectLiteralExpression)) { - continue; - } - - if (!left.isKind(SyntaxKind.PropertyAccessExpression)) { - continue; - } - - const expressionText = left.getExpression().getText(); - const nameText = left.getName(); - if (expressionText !== componentName || nameText !== "defaultProps") { - continue; - } - - for (const prop of right.getProperties()) { - if (!prop.isKind(SyntaxKind.PropertyAssignment)) { - continue; - } - const propName = prop.getName(); - const initializer = prop.getInitializer(); - if (initializer) { - defaults.set(propName, initializer.getText()); - } - } - } - } - - return defaults; -} - -/** - * Extract defaults from a component declaration (function or variable initializer). - * @param {import("ts-morph").Node} declaration - * @returns {Map} - */ -function extractDefaultsFromDeclaration(declaration) { - const defaults = new Map(); - - if (declaration.isKind(SyntaxKind.FunctionDeclaration)) { - extractFromParameters(declaration.getParameters(), defaults); - } - - if (declaration.isKind(SyntaxKind.VariableDeclaration)) { - const initializer = declaration.getInitializer(); - if ( - initializer && - (initializer.isKind(SyntaxKind.ArrowFunction) || - initializer.isKind(SyntaxKind.FunctionExpression)) - ) { - extractFromParameters(initializer.getParameters(), defaults); - } - } - - if ( - declaration.isKind(SyntaxKind.FunctionExpression) || - declaration.isKind(SyntaxKind.ArrowFunction) - ) { - extractFromParameters(declaration.getParameters(), defaults); + const props = resolvePropsForStories(storiesPath); + propsMap.set(heading, props); } - return defaults; -} - -/** - * Extract default values from the first object parameter binding. - * @param {import("ts-morph").ParameterDeclaration[]} parameters - * @param {Map} defaults - */ -function extractFromParameters(parameters, defaults) { - if (!parameters || parameters.length === 0) { - return; - } - - const firstParam = parameters[0]; - const nameNode = firstParam.getNameNode(); - if (!nameNode || !nameNode.isKind(SyntaxKind.ObjectBindingPattern)) { - return; - } - - for (const element of nameNode.getElements()) { - const initializer = element.getInitializer(); - if (!initializer) { - continue; - } - const propName = - element.getPropertyNameNode()?.getText() ?? element.getName(); - defaults.set(propName, initializer.getText()); - } -} - -/** - * Extract story data from CSF and MDX files for usage examples. - * @param {import("ts-morph").Project} projectInstance - * @param {string} rootDir - * @returns {Promise>} - */ -async function extractStoryData(projectInstance, rootDir) { - const storyFiles = fg.sync( - ["src/**/*.stories.@(js|jsx|ts|tsx)", "docs/**/*.stories.@(js|jsx|ts|tsx)"], - { cwd: rootDir, absolute: true }, - ).sort(); - const mdxFiles = fg.sync(["src/**/*.mdx", "docs/**/*.mdx"], { - cwd: rootDir, - absolute: true, - }).sort(); - - /** @type {Map} */ - const storyMap = new Map(); - - for (const filePath of storyFiles) { - const sourceFile = - projectInstance.getSourceFile(filePath) || - projectInstance.addSourceFileAtPathIfExists(filePath); - if (!sourceFile) { - continue; - } - - const meta = extractStoryMeta(sourceFile); - const stories = extractStoryExports(sourceFile); - const componentName = inferComponentName(meta, filePath, rootDir); - - if (!componentName) { - continue; - } - - const existing = storyMap.get(componentName) ?? []; - for (const story of stories) { - existing.push({ - ...story, - source: path.relative(rootDir, filePath), - }); - } - storyMap.set(componentName, existing); - } - - for (const filePath of mdxFiles) { - if (!filePath.replace(/\\/g, "/").includes("/src/components/")) { - continue; - } - const componentName = inferComponentNameFromPath(filePath, rootDir); - if (!componentName) { - continue; - } - const content = await fs.readFile(filePath, "utf8"); - const examples = extractMdxExamples(content.replace(/\r\n/g, "\n")); - if (!examples.length) { - continue; - } - const existing = storyMap.get(componentName) ?? []; - for (const example of examples) { - existing.push({ - name: example.name, - argsText: example.code, - renderText: null, - source: path.relative(rootDir, filePath), - kind: "mdx", - }); - } - storyMap.set(componentName, existing); - } - - return storyMap; -} - -/** - * Extracts story metadata from a source file by looking for the default export and analyzing its structure to find properties like "title" and "component". It resolves any references to identifiers or imported modules to determine the associated component information. The function returns an object containing the extracted metadata. - * @param {import("ts-morph").SourceFile} sourceFile - * @returns {StoryMeta} - */ -function extractStoryMeta(sourceFile) { - const exportAssignment = sourceFile - .getExportAssignments() - .find((assignment) => !assignment.isExportEquals()); - if (!exportAssignment) { - return { title: null, componentIdentifier: null, componentModule: null }; - } - - const expression = exportAssignment.getExpression(); - const objectLiteral = resolveObjectLiteral(expression, sourceFile); - if (!objectLiteral) { - return { title: null, componentIdentifier: null, componentModule: null }; - } - - const titleProp = objectLiteral.getProperty("title"); - const title = titleProp?.isKind(SyntaxKind.PropertyAssignment) - ? getStringLiteralValue(titleProp.getInitializer()) - : null; - - const componentProp = objectLiteral.getProperty("component"); - const componentIdentifier = componentProp?.isKind( - SyntaxKind.PropertyAssignment, - ) - ? getIdentifierText(componentProp.getInitializer()) - : null; - - const componentModule = componentIdentifier - ? resolveImportModule(sourceFile, componentIdentifier) - : null; - - return { title, componentIdentifier, componentModule }; -} - -/** - * Extracts story exports from a source file by looking for exported functions and variables, as well as any associated story metadata such as story names and args. It returns an array of story entries with the extracted information. - * @param {import("ts-morph").SourceFile} sourceFile - * @returns {StoryEntry[]} - */ -function extractStoryExports(sourceFile) { - /** @type {StoryEntry[]} */ - const stories = []; - const exported = sourceFile.getExportedDeclarations(); - const storyNameOverrides = new Map(); - const storyArgsOverrides = new Map(); - - const assignments = sourceFile.getDescendantsOfKind( - SyntaxKind.BinaryExpression, + // Render component index.md + const skillContent = renderSkillMd( + parsed, + propsMap, + exampleFiles, + entry.isDeprecated, + availableSlugs, ); - for (const assignment of assignments) { - const left = assignment.getLeft(); - const right = assignment.getRight(); - if (!left.isKind(SyntaxKind.PropertyAccessExpression) || !right) { - continue; - } - const targetName = left.getExpression().getText(); - const propertyName = left.getName(); - if (propertyName === "storyName") { - const value = getStringLiteralValue(right); - if (value) { - storyNameOverrides.set(targetName, value); - } - } - if ( - propertyName === "args" && - right.isKind(SyntaxKind.ObjectLiteralExpression) - ) { - storyArgsOverrides.set(targetName, right.getText()); - } - } - - for (const [exportName, declarations] of exported.entries()) { - if (exportName === "default") { - continue; - } - - for (const declaration of declarations) { - if (declaration.isKind(SyntaxKind.FunctionDeclaration)) { - stories.push({ - name: storyNameOverrides.get(exportName) ?? exportName, - argsText: storyArgsOverrides.get(exportName) ?? null, - renderText: declaration.getText(), - kind: "csf", - }); - continue; - } - - if (!declaration.isKind(SyntaxKind.VariableDeclaration)) { - continue; - } - - const initializer = declaration.getInitializer(); - if (!initializer) { - continue; - } - - if (initializer.isKind(SyntaxKind.ObjectLiteralExpression)) { - // CSF object style: export const Story = { args, render } - const argsProperty = initializer.getProperty("args"); - const renderProperty = initializer.getProperty("render"); - const argsText = argsProperty?.isKind(SyntaxKind.PropertyAssignment) - ? (argsProperty.getInitializer()?.getText() ?? null) - : (storyArgsOverrides.get(exportName) ?? null); - const renderText = renderProperty?.isKind(SyntaxKind.PropertyAssignment) - ? (renderProperty.getInitializer()?.getText() ?? null) - : null; - - stories.push({ - name: storyNameOverrides.get(exportName) ?? exportName, - argsText, - renderText, - kind: "csf", - }); - continue; - } - - if ( - initializer.isKind(SyntaxKind.ArrowFunction) || - initializer.isKind(SyntaxKind.FunctionExpression) - ) { - // CSF function style: export const Story = () => - stories.push({ - name: storyNameOverrides.get(exportName) ?? exportName, - argsText: storyArgsOverrides.get(exportName) ?? null, - renderText: initializer.getText(), - kind: "csf", - }); - } - } - } - - return stories; -} - -/** - * Infers the component name associated with a story by checking the story's metadata for a title or component reference, and if those are not available, by analyzing the file path to find the nearest directory that likely corresponds to the component name. The function uses PascalCase formatting for the inferred component name. - * @param {StoryMeta} meta - * @param {string} filePath - * @param {string} rootDir - * @returns {string | null} - */ -function inferComponentName(meta, filePath, rootDir) { - if (meta?.title) { - // Storybook titles are often "Category/Component"; the last segment - // typically matches the component name in Carbon. - const lastSegment = meta.title.split("/").pop() ?? ""; - return toPascalCase(lastSegment); - } - - if (meta?.componentModule) { - const resolved = resolveModulePath(filePath, meta.componentModule); - if (resolved && resolved.includes(`${path.sep}components${path.sep}`)) { - return inferComponentNameFromPath(resolved, rootDir); - } - } - - return inferComponentNameFromPath(filePath, rootDir); -} - -/** - * @param {string} filePath - * @param {string} rootDir - * @returns {string | null} - */ -function inferComponentNameFromPath(filePath, rootDir) { - const relative = path.relative(rootDir, filePath); - const parts = relative.split(path.sep); - const componentsIndex = parts.indexOf("components"); - if (componentsIndex === -1 || componentsIndex === parts.length - 1) { - return null; - } - const immediateDir = path.basename(path.dirname(filePath)); - if (immediateDir && immediateDir !== "__internal__") { - return toPascalCase(immediateDir); - } - - const fallbackFolder = parts[componentsIndex + 1]; - return toPascalCase(fallbackFolder); -} - -/** - * @param {import("ts-morph").Expression | undefined} expression - * @param {import("ts-morph").SourceFile} sourceFile - * @returns {import("ts-morph").ObjectLiteralExpression | null} - */ -function resolveObjectLiteral(expression, sourceFile) { - if (!expression) { - return null; - } - if (expression.isKind(SyntaxKind.ObjectLiteralExpression)) { - return expression; - } - if (expression.isKind(SyntaxKind.Identifier)) { - const name = expression.getText(); - const variable = sourceFile.getVariableDeclaration(name); - if (variable) { - const initializer = variable.getInitializer(); - if (initializer?.isKind(SyntaxKind.ObjectLiteralExpression)) { - return initializer; - } - } - } - return null; -} - -/** - * @param {import("ts-morph").Node | undefined} node - * @returns {string | null} - */ -function getStringLiteralValue(node) { - if (!node) { - return null; - } - if (node.isKind(SyntaxKind.StringLiteral)) { - return node.getLiteralValue(); - } - if (node.isKind(SyntaxKind.NoSubstitutionTemplateLiteral)) { - return node.getLiteralValue(); - } - return null; -} + wouldWrite.push({ + path: path.join(componentsOutDir, slug, "index.md"), + content: skillContent, + }); -/** - * @param {import("ts-morph").Node | undefined} node - * @returns {string | null} - */ -function getIdentifierText(node) { - if (!node) { - return null; - } - if (node.isKind(SyntaxKind.Identifier)) { - return node.getText(); - } - if (node.isKind(SyntaxKind.AsExpression)) { - return getIdentifierText(node.getExpression()); - } - if (node.isKind(SyntaxKind.TypeAssertionExpression)) { - return getIdentifierText(node.getExpression()); - } - return null; + processedCount++; } -/** - * Normalizes a JSDoc comment by converting it to a single line and trimming whitespace. - * @param {import("ts-morph").SourceFile} sourceFile - * @param {string} identifierName - * @returns {string | null} - */ -function resolveImportModule(sourceFile, identifierName) { - for (const importDecl of sourceFile.getImportDeclarations()) { - const moduleSpecifier = importDecl.getModuleSpecifierValue(); - const defaultImport = importDecl.getDefaultImport(); - if (defaultImport?.getText() === identifierName) { - return moduleSpecifier; - } - const namedImports = importDecl.getNamedImports(); - for (const namedImport of namedImports) { - const importName = namedImport.getName(); - const alias = namedImport.getAliasNode()?.getText(); - if (importName === identifierName || alias === identifierName) { - return moduleSpecifier; - } - } - } - return null; -} - -/** - * Extracts code examples from MDX content by looking for code blocks and returns them as an array of objects containing the example name and code. - * @param {string} content - * @returns {Array<{name: string, code: string}>} - */ -function extractMdxExamples(content) { - const examples = []; - const codeBlockRegex = /```(?:tsx|jsx|ts|js)?\n([\s\S]*?)```/g; - let match; - let index = 1; +// Generate root SKILL.md, index.md, and copy references/docs +wouldWrite.push({ + path: path.join(skillsRoot, "SKILL.md"), + content: renderSkillRootContent(), +}); +wouldWrite.push({ + path: path.join(skillsRoot, "index.md"), + content: renderIndexContent(indexEntries), +}); - while ((match = codeBlockRegex.exec(content)) !== null) { - const code = match[1]?.trim(); - if (!code) { - continue; - } - examples.push({ - name: `MDX Example ${index}`, - code, - }); - index += 1; +for (const entry of docsReferenceFiles) { + const relativePath = typeof entry === "string" ? entry : entry.source; + const sourcePath = path.join(repoRoot, relativePath); + if (!existsSync(sourcePath)) { + continue; } - - return examples; + const refFileName = + typeof entry === "string" + ? path.basename(sourcePath).replace(/\.mdx?$/, ".md") + : entry.target; + const targetPath = path.join(referencesDir, refFileName); + const rawContent = await fs.readFile(sourcePath, "utf8"); + const { content: processedContent, exampleFiles } = + await parseAndRenderReferenceMdx(rawContent, sourcePath, availableSlugs); + wouldWrite.push(...exampleFiles); + wouldWrite.push({ + path: targetPath, + content: processedContent, + }); } -/** - * Renders the content for the root skill file. - * @returns {string} - */ -function renderSkillRootContent() { - const docsList = docsReferenceTargets - .map((fileName) => `- \`${fileName}\``) - .join("\n"); - return `---\nname: carbon-react\ndescription: Carbon component catalog with typed props, Storybook usage examples, and curated docs references. Use when answering questions about Carbon components, props, and usage guidance.\n---\n\n# Carbon Component Catalog\n\nUse \`index.md\` to find the component file.\nUse \`components/*.md\` to read props and examples.\nUse these docs references:\n${docsList}\nDeprecated components are marked in \`index.md\` and in each component file.\n`; -} +// ─── Write Output ─────────────────────────────────────────────────────────── -/** - * Checks that files on disk match the expected content. Returns diffs for CI. - * @param {Array<{path: string, content: string}>} wouldWrite - * @param {{componentsOutDir: string, referencesDir: string}} outputDirs - * @returns {Promise<{hasDiff: boolean, diffSummary: string}>} - */ -async function checkWouldWrite(wouldWrite, { componentsOutDir, referencesDir }) { +if (checkMode) { + const expectedPaths = new Set(wouldWrite.map((w) => w.path)); /** @type {string[]} */ const diffs = []; - const expectedPaths = new Set(wouldWrite.map((w) => w.path)); for (const { path: filePath, content } of wouldWrite) { let existing; try { existing = await fs.readFile(filePath, "utf8"); } catch (err) { - if (err && typeof err === 'object' && 'code' in err && err?.code === "ENOENT") { + if ( + err && + typeof err === "object" && + "code" in err && + err.code === "ENOENT" + ) { diffs.push(` Missing: ${path.relative(repoRoot, filePath)}`); continue; } @@ -1283,382 +214,46 @@ async function checkWouldWrite(wouldWrite, { componentsOutDir, referencesDir }) } } - for (const dir of [componentsOutDir, referencesDir]) { - if (!existsSync(dir)) { - continue; - } - const entries = await fs.readdir(dir, { withFileTypes: true }); - for (const entry of entries) { - if (!entry.isFile()) { - continue; - } - const fullPath = path.join(dir, entry.name); + // Check for stale files in components/, references/docs/, and references/docs/examples/ + for (const dir of [componentsOutDir, referencesDir, referencesExamplesDir]) { + if (!existsSync(dir)) continue; + const staleFiles = fg.sync(["**/*"], { + cwd: dir, + absolute: true, + onlyFiles: true, + }); + for (const fullPath of staleFiles) { if (!expectedPaths.has(fullPath)) { diffs.push(` Extra: ${path.relative(repoRoot, fullPath)}`); } } } - return { - hasDiff: diffs.length > 0, - diffSummary: diffs.join("\n"), - }; -} - -/** - * Detect deprecation markers on component declarations and types. - * @param {import("ts-morph").Project} projectInstance - * @param {string} modulePath - * @param {string[]} moduleFiles - * @param {string} componentName - * @returns {{deprecated: boolean, reason: string | null}} - */ -function detectDeprecation( - projectInstance, - modulePath, - moduleFiles, - componentName, -) { - /** @type {import("ts-morph").Node[]} */ - const candidates = []; - - const entryFile = - projectInstance.getSourceFile(modulePath) || - projectInstance.addSourceFileAtPathIfExists(modulePath); - if (entryFile) { - const defaultExportSymbol = entryFile.getDefaultExportSymbol(); - if (defaultExportSymbol) { - candidates.push(...defaultExportSymbol.getDeclarations()); - } - } - - for (const filePath of moduleFiles) { - const sourceFile = - projectInstance.getSourceFile(filePath) || - projectInstance.addSourceFileAtPathIfExists(filePath); - if (!sourceFile) { - continue; - } - - const namedFunction = sourceFile - .getFunctions() - .find((fn) => fn.getName() === componentName); - if (namedFunction) { - candidates.push(namedFunction); - } - - const namedClass = sourceFile - .getClasses() - .find((decl) => decl.getName() === componentName); - if (namedClass) { - candidates.push(namedClass); - } - - const namedVariable = sourceFile - .getVariableDeclarations() - .find((decl) => decl.getName() === componentName); - if (namedVariable) { - candidates.push(namedVariable); - const variableStatement = namedVariable.getVariableStatement(); - if (variableStatement) { - // Some components place @deprecated on the export const statement. - candidates.push(variableStatement); - } - } - - const namedInterface = sourceFile.getInterface(componentName); - if (namedInterface) { - candidates.push(namedInterface); - } - - const namedTypeAlias = sourceFile.getTypeAlias(componentName); - if (namedTypeAlias) { - candidates.push(namedTypeAlias); - } - - const propsInterface = sourceFile.getInterface(`${componentName}Props`); - if (propsInterface) { - candidates.push(propsInterface); - } - - const propsTypeAlias = sourceFile.getTypeAlias(`${componentName}Props`); - if (propsTypeAlias) { - candidates.push(propsTypeAlias); - } - } - - for (const candidate of candidates) { - const jsDocs = getJsDocsFromNode(candidate); - for (const doc of jsDocs) { - for (const tag of doc.getTags()) { - if (tag.getTagName() === "deprecated") { - const comment = normalizeJsDocComment(tag.getComment()); - const docComment = doc.getDescription().trim(); - return { - deprecated: true, - reason: comment || docComment || null, - }; - } - } - } - } - - return { deprecated: false, reason: null }; -} - -/** - * Safely read JSDoc arrays from arbitrary nodes. - * @param {import("ts-morph").Node} node - * @returns {import("ts-morph").JSDoc[]} - */ -function getJsDocsFromNode(node) { - if (JSDoc.isJSDocable(node)) { - return node.getJsDocs(); - } - return []; -} - -/** - * @param {ReturnType} comment - * @returns {string | null} - */ -function normalizeJsDocComment(comment) { - if (!comment) { - return null; - } - if (typeof comment === "string") { - return comment.trim() || null; - } - if (Array.isArray(comment)) { - return ( - comment - .map((part) => part?.getText() ?? "") - .join("") - .trim() || null - ); - } - return null; -} - -/** - * Extract deprecation metadata from a JSDoc array. - * @param {import("ts-morph").JSDoc[]} jsDocs - * @returns {{deprecated: boolean, reason: string | null}} - */ -function getDeprecationFromJsDocs(jsDocs) { - for (const doc of jsDocs) { - for (const tag of doc.getTags()) { - if (tag.getTagName() === "deprecated") { - const comment = normalizeJsDocComment(tag.getComment()); - const docComment = doc.getDescription().trim(); - return { - deprecated: true, - reason: comment || docComment || null, - }; - } - } - } - return { deprecated: false, reason: null }; -} - -/** - * Render a component markdown file with props and examples. - * @param {ComponentData} component - * @param {StoryEntry[]} stories - * @returns {string} - */ -function renderComponentMarkdown(component, stories) { - const frontmatter = [ - "---", - `name: carbon-component-${toKebabCase(component.name)}`, - `description: Carbon ${component.name} component props and usage examples.`, - "---", - "", - ].join("\n"); - - const lines = [frontmatter, `# ${component.name}`, ""]; - - const importPath = `${packageName}/${buildOutputFolder}/${component.moduleSpecifier.replace("./", "")}`; - const importStatement = component.hasDefaultExport - ? `import ${component.importName} from "${importPath}";` - : `import { ${component.importName} } from "${importPath}";`; - - lines.push("## Import"); - lines.push(`\`${importStatement}\`\n`); - - lines.push("## Source"); - lines.push(`- Export: \`${component.moduleSpecifier}\``); - if (component.propsInterfaceName) { - lines.push(`- Props interface: \`${component.propsInterfaceName}\``); - } else if (component.missingPropsInterface) { - lines.push("- Props interface: not found"); - } - if (component.deprecated) { - lines.push("- Deprecated: Yes"); - if (component.deprecationReason) { - lines.push(`- Deprecation reason: ${component.deprecationReason}`); - } - } - lines.push(""); - - lines.push("## Props"); - if (!component.props.length) { - lines.push("No props metadata found."); - } else { - const sortedProps = [...component.props].sort((a, b) => { - if (a.deprecated !== b.deprecated) return a.deprecated ? 1 : -1; - if (a.required !== b.required) return a.required ? -1 : 1; - const aData = a.name.startsWith("data-"); - const bData = b.name.startsWith("data-"); - const aAria = a.name.startsWith("aria-"); - const bAria = b.name.startsWith("aria-"); - const groupOrder = (/** @type {boolean} */ data, /** @type {boolean} */ aria) => (data ? 1 : aria ? 2 : 0); - const ga = groupOrder(aData, aAria); - const gb = groupOrder(bData, bAria); - if (ga !== gb) return ga - gb; - return a.name.localeCompare(b.name); - }); - const hasDeprecatedProps = sortedProps.some((prop) => prop.deprecated); - if (hasDeprecatedProps) { - lines.push( - "| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default |", - "| --- | --- | --- | --- | --- | --- | --- | --- |", - ); - } else { - lines.push( - "| Name | Type | Required | Literals | Description | Default |", - "| --- | --- | --- | --- | --- | --- |", - ); - } - for (const prop of sortedProps) { - const literals = prop.literals?.join(" | ") ?? ""; - const description = prop.description?.replace(/\s+/g, " ") ?? ""; - const defaultValue = (prop.defaultValue ?? "").replace(/\r/g, ""); - if (hasDeprecatedProps) { - const deprecated = prop.deprecated ? "Yes" : ""; - const deprecationReason = (prop.deprecationReason ?? "").replace(/\s+/g, " ").trim(); - lines.push( - `| ${prop.name} | ${escapePipes(prop.type)} | ${prop.required ? "Yes" : "No"} | ${escapePipes(literals)} | ${deprecated} | ${escapePipes(deprecationReason)} | ${escapePipes(description)} | ${escapePipes(defaultValue)} |`, - ); - } else { - lines.push( - `| ${prop.name} | ${escapePipes(prop.type)} | ${prop.required ? "Yes" : "No"} | ${escapePipes(literals)} | ${escapePipes(description)} | ${escapePipes(defaultValue)} |`, - ); - } - } - } - lines.push(""); - - lines.push("## Examples"); - if (!stories.length) { - lines.push("No Storybook examples found."); - } else { - for (const story of stories) { - lines.push(`### ${story.name}`); - lines.push(""); - if (story.argsText) { - lines.push("**Args**", "", "```tsx", story.argsText.replace(/\r\n/g, "\n"), "```", ""); - } - if (story.renderText) { - lines.push("**Render**", "", "```tsx", story.renderText.replace(/\r\n/g, "\n"), "```", ""); - } - lines.push(""); - } + if (diffs.length > 0) { + // eslint-disable-next-line no-console -- CI output + console.error("Skills build check failed:\n"); + // eslint-disable-next-line no-console -- CI output + console.error(diffs.join("\n")); + process.exit(1); } + // eslint-disable-next-line no-console -- CI output + console.log( + `Check passed: ${processedCount} component skill files are up to date.`, + ); +} else { + // Clean entire output directory then recreate structure + await fs.rm(skillsRoot, { recursive: true, force: true }); - return lines.join("\n"); -} - -/** - * Escape pipes for markdown table cells. - * @param {string} value - * @returns {string} - */ -function escapePipes(value) { - return value?.replace(/\|/g, "\\|") ?? ""; -} - -/** - * Convert a string to kebab-case. - * @param {string} value - * @returns {string} - */ -function toKebabCase(value) { - return value - .replace(/([a-z])([A-Z])/g, "$1-$2") - .replace(/\s+/g, "-") - .replace(/_/g, "-") - .toLowerCase(); -} - -/** - * Capitalize the first character of a string. - * @param {string} value - * @returns {string} - */ -function capitalizeFirstLetter(value) { - return value.charAt(0).toUpperCase() + value.slice(1); -} - -/** - * Convert a string to PascalCase. - * @param {string} value - * @returns {string | null} - */ -function toPascalCase(value) { - if (!value) { - return null; + for (const { path: filePath, content } of wouldWrite) { + await fs.mkdir(path.dirname(filePath), { recursive: true }); + await fs.writeFile(filePath, content, "utf8"); } - return value - .replace(/[_-]+/g, " ") - .replace(/\s+/g, " ") - .trim() - .split(" ") - .map((part) => capitalizeFirstLetter(part)) - .join(""); -} - -/** - * Deduplicate component candidates by their rendered output name. - * Prefers candidates that preserve original symbol names for props lookup - * and candidates whose module specifier points at an index barrel. - * @param {ComponentCandidate[]} candidates - * @returns {ComponentCandidate[]} - */ -function dedupeComponentCandidates(candidates) { - /** @type {Map} */ - const byOutputName = new Map(); - - for (const candidate of candidates) { - const outputName = candidate.displayName ?? candidate.name; - const existing = byOutputName.get(outputName); - if (!existing) { - byOutputName.set(outputName, candidate); - continue; - } - - if (scoreComponentCandidate(candidate) > scoreComponentCandidate(existing)) { - byOutputName.set(outputName, candidate); - } + // eslint-disable-next-line no-console -- Log summary + console.log( + `Generated ${processedCount} component skill files in skills/carbon-react/components/`, + ); + if (skippedCount > 0) { + // eslint-disable-next-line no-console -- Log summary + console.log(`Skipped ${skippedCount} entries (no slug mapping).`); } - - return Array.from(byOutputName.values()); } - -/** - * Score a candidate for deterministic duplicate resolution. - * @param {ComponentCandidate} candidate - * @returns {number} - */ -function scoreComponentCandidate(candidate) { - let score = 0; - if (candidate.displayName) { - // Preserves original export name for props lookup (e.g., Tab -> TabNext). - score += 2; - } - if (!candidate.moduleSpecifier.includes(".component")) { - // Prefer index/barrel paths over concrete implementation files. - score += 1; - } - return score; -} \ No newline at end of file diff --git a/scripts/skills/links.mjs b/scripts/skills/links.mjs new file mode 100644 index 0000000000..d4cb6e5d2c --- /dev/null +++ b/scripts/skills/links.mjs @@ -0,0 +1,80 @@ +// @ts-check +import { referenceSlugMap, referenceDocSelfSlugMap } from "./skills-config.mjs"; + +/** + * Transform Storybook links to skill-relative links or plain text. + * @param {string} content + * @param {Set} availableSlugs + * @returns {string} + */ +export function transformLinks(content, availableSlugs) { + // Handle markdown links: [text](../?path=/docs/slug--docs) or [text](?path=/docs/slug--docs) + let result = content.replace( + /\[([^\]]+)\]\(\.{0,2}\/?\??path=\/(?:docs|story)\/([^#)]+?)(?:--(?:docs|[^#)]*))?(?:#[^)]*)?\)/g, + (match, text, slug) => { + if (availableSlugs.has(slug)) { + return `[${text}](../${slug}/index.md)`; + } + if (referenceSlugMap.has(slug)) { + return `[${text}](${referenceSlugMap.get(slug)})`; + } + return text; + }, + ); + + // Handle HTML tags with storybook paths + result = result.replace( + /]*href="[^"]*\?path=\/(?:docs|story)\/([^#"]+?)(?:--(?:docs|[^#"]*))?(?:#[^"]*)?"[^>]*>([\s\S]*?)<\/a>/g, + (match, slug, text) => { + const cleanText = text.replace(/<[^>]+>/g, "").trim(); + if (availableSlugs.has(slug)) { + return `[${cleanText}](../${slug}/index.md)`; + } + if (referenceSlugMap.has(slug)) { + return `[${cleanText}](${referenceSlugMap.get(slug)})`; + } + return cleanText; + }, + ); + + return result; +} + +/** + * Transform Storybook links for reference doc context (references/docs/). + * Component slugs → ../../components/{slug}/index.md + * Reference doc slugs → ./filename.md + * @param {string} content + * @param {Set} availableSlugs + * @returns {string} + */ +export function transformLinksForRefDoc(content, availableSlugs) { + let result = content.replace( + /\[([^\]]+)\]\(\.{0,2}\/?\??path=\/(?:docs|story)\/([^#)]+?)(?:--(?:docs|[^#)]*))?(?:#[^)]*)?\)/g, + (match, text, slug) => { + if (availableSlugs.has(slug)) { + return `[${text}](../../components/${slug}/index.md)`; + } + if (referenceDocSelfSlugMap.has(slug)) { + return `[${text}](${referenceDocSelfSlugMap.get(slug)})`; + } + return text; + }, + ); + + result = result.replace( + /]*href="[^"]*\?path=\/(?:docs|story)\/([^#"]+?)(?:--(?:docs|[^#"]*))?(?:#[^"]*)?"[^>]*>([\s\S]*?)<\/a>/g, + (match, slug, text) => { + const cleanText = text.replace(/<[^>]+>/g, "").trim(); + if (availableSlugs.has(slug)) { + return `[${cleanText}](../../components/${slug}/index.md)`; + } + if (referenceDocSelfSlugMap.has(slug)) { + return `[${cleanText}](${referenceDocSelfSlugMap.get(slug)})`; + } + return cleanText; + }, + ); + + return result; +} diff --git a/scripts/skills/mdx-discovery.mjs b/scripts/skills/mdx-discovery.mjs new file mode 100644 index 0000000000..44bea91456 --- /dev/null +++ b/scripts/skills/mdx-discovery.mjs @@ -0,0 +1,77 @@ +// @ts-check +import path from "node:path"; +import fs from "node:fs/promises"; +import fg from "fast-glob"; +import { repoRoot } from "./skills-config.mjs"; + +/** + * Discover all component MDX files, build their output slugs (giving `__next__` + * variants priority and suffixing legacy duplicates with `-legacy`), and the + * set of slugs available for link resolution. + * @returns {Promise<{mdxEntries: import("./skills-types.mjs").MdxEntry[], mdxToSlug: Map, availableSlugs: Set}>} + */ +export async function discoverMdx() { + const allMdxFiles = fg + .sync(["src/components/**/*.mdx"], { + cwd: repoRoot, + absolute: true, + ignore: ["**/__internal__/**", "**/node_modules/**"], + }) + .sort(); + + /** @type {import("./skills-types.mjs").MdxEntry[]} */ + const mdxEntries = []; + + for (const mdxPath of allMdxFiles) { + const content = await fs.readFile(mdxPath, "utf8"); + const isDeprecated = content.includes("} slug -> mdxPath */ + const slugToMdx = new Map(); + /** @type {Map} mdxPath -> outputSlug */ + const mdxToSlug = new Map(); + + // First pass: collect all base names, __next__ gets priority + /** @type {Map} */ + const nameConflicts = new Map(); + + for (const entry of mdxEntries) { + const existing = nameConflicts.get(entry.baseName) ?? { + nextPath: null, + regularPath: null, + }; + if (entry.isNext) { + existing.nextPath = entry.mdxPath; + } else { + existing.regularPath = entry.mdxPath; + } + nameConflicts.set(entry.baseName, existing); + } + + for (const [baseName, { nextPath, regularPath }] of nameConflicts.entries()) { + if (nextPath && regularPath) { + // __next__ takes the simple name, regular gets -legacy + mdxToSlug.set(nextPath, baseName); + slugToMdx.set(baseName, nextPath); + mdxToSlug.set(regularPath, `${baseName}-legacy`); + slugToMdx.set(`${baseName}-legacy`, regularPath); + } else if (nextPath) { + mdxToSlug.set(nextPath, baseName); + slugToMdx.set(baseName, nextPath); + } else if (regularPath) { + mdxToSlug.set(regularPath, baseName); + slugToMdx.set(baseName, regularPath); + } + } + + // Build slug set for link resolution + const availableSlugs = new Set(slugToMdx.keys()); + + return { mdxEntries, mdxToSlug, availableSlugs }; +} diff --git a/scripts/skills/mdx-parser.mjs b/scripts/skills/mdx-parser.mjs new file mode 100644 index 0000000000..a52278affd --- /dev/null +++ b/scripts/skills/mdx-parser.mjs @@ -0,0 +1,353 @@ +// @ts-check +import { KNOWN_SECTIONS } from "./skills-config.mjs"; + +/** + * Extract stories imports from MDX content. + * Matches namespace imports (`import * as X from "..."`) and default imports + * (`import X from "....stories"`). + * @param {string} content + * @returns {Map} alias -> relative path + */ +export function extractStoriesImports(content) { + const storiesImports = new Map(); + const namespaceImportRegex = + /^import\s+\*\s+as\s+(\w+)\s+from\s+["']([^"']+)["']/; + const defaultImportRegex = /^import\s+(\w+)\s+from\s+["']([^"']+)["']/; + + for (const line of content.split("\n")) { + const nsMatch = line.match(namespaceImportRegex); + if (nsMatch) { + storiesImports.set(nsMatch[1], nsMatch[2]); + continue; + } + const defMatch = line.match(defaultImportRegex); + if (defMatch && defMatch[2].includes(".stories")) { + storiesImports.set(defMatch[1], defMatch[2]); + } + } + + return storiesImports; +} + +/** + * Parse an MDX file content into structured data. + * @param {string} content + * @returns {import("./skills-types.mjs").ParsedMdx} + */ +export function parseMdxFile(content) { + const normalized = content.replace(/\r\n/g, "\n"); + + // Extract imports (namespace: import * as X from "..." AND default: import X from "...") + const storiesImports = extractStoriesImports(normalized); + + // Extract component title (first H1) + const titleMatch = content.match(/^#\s+(.+)$/m); + const componentTitle = titleMatch ? titleMatch[1].trim() : "Unknown"; + + // Extract description: text between PDS link closing tag (or H1) and ## Contents + const description = extractDescription(content); + + // Extract category + const category = extractCategory(content); + + // Extract Quick Start section (heading + full content) + const quickStart = extractQuickStart(content); + + // Extract examples (Canvas refs grouped by heading) + const examples = extractExamples(content); + + // Extract ArgType refs + const argTypeRefs = extractArgTypeRefs(content); + + // Extract Designer Notes section + const designerNotes = extractSection(content, "Designer Notes"); + + // Extract Related Components section + const relatedComponents = extractSection(content, "Related Components"); + + // Extract Ref methods section + const refMethods = extractSection(content, "Ref methods"); + + // Extract other sections not in the known set + const otherSections = extractOtherSections(content); + + return { + componentTitle, + description, + category, + quickStart, + storiesImports, + examples, + argTypeRefs, + designerNotes, + relatedComponents, + refMethods, + otherSections, + }; +} + +/** + * Extract description text from MDX content. + * Skips any leading block and PDS/zeroheight link. + * @param {string} content + * @returns {string} + */ +export function extractDescription(content) { + // Start after the H1 title + const h1Match = content.match(/^#\s+.+$/m); + if (!h1Match) return ""; + let startIdx = h1Match.index + h1Match[0].length + 1; + + // Skip ... block if it immediately follows H1 + const deprecWarningStart = content.indexOf("", + deprecWarningStart, + ); + if (deprecWarningEnd !== -1) { + startIdx = deprecWarningEnd + "".length; + } + } + + // Skip PDS/zeroheight link if it immediately follows (after H1 or DeprecationWarning) + const pdsTextIdx = content.indexOf("Product Design System", startIdx); + if (pdsTextIdx !== -1) { + const pdsAStart = content.lastIndexOf("= startIdx && + content.slice(startIdx, pdsAStart).trim() === "" + ) { + const pdsAEnd = content.indexOf("", pdsAStart); + if (pdsAEnd !== -1) { + startIdx = pdsAEnd + "".length; + } + } + } + + // Find where description ends: **Category:** or first ## heading + const categoryIdx = content.indexOf("**Category:**", startIdx); + const contentsIdx = content.indexOf("## Contents", startIdx); + const nextH2Idx = content.indexOf("\n## ", startIdx); + + const candidates = [ + categoryIdx !== -1 ? categoryIdx : Infinity, + contentsIdx !== -1 ? contentsIdx : Infinity, + nextH2Idx !== -1 ? nextH2Idx : Infinity, + content.length, + ]; + const endIdx = Math.min(...candidates); + + return content.slice(startIdx, endIdx).trim(); +} + +/** + * Extract category from MDX content. + * Returns null if no category is defined. + * @param {string} content + * @returns {string | null} + */ +export function extractCategory(content) { + const categoryMatch = content.match(/\*\*Category:\*\*\s*(.+?)(?:\n|$)/); + if (!categoryMatch) return null; + return categoryMatch[1].trim(); +} + +/** + * Extract the full Quick Start section (preserving heading and all content). + * @param {string} content + * @returns {{ heading: string, content: string } | null} + */ +export function extractQuickStart(content) { + const quickStartMatch = content.match(/^(##\s+Quick\s*Start)\s*$/im); + if (!quickStartMatch) return null; + + const heading = quickStartMatch[1].trim(); + const afterQS = content.slice( + quickStartMatch.index + quickStartMatch[0].length, + ); + const nextH2 = afterQS.match(/^##\s+/m); + const sectionContent = nextH2 ? afterQS.slice(0, nextH2.index) : afterQS; + + return { heading, content: sectionContent.trim() }; +} + +/** + * Extract examples grouped by heading with their Canvas references. + * @param {string} content + * @returns {Array<{heading: string, items: Array<{description: string, canvasRef: import("./skills-types.mjs").CanvasRef | null}>}>} + */ +export function extractExamples(content) { + const examplesMatch = content.match(/^##\s+Examples\s*$/m); + if (!examplesMatch) return []; + + const afterExamples = content.slice( + examplesMatch.index + examplesMatch[0].length, + ); + // End at next ## heading (Props, Translation keys, etc.) + const nextH2 = afterExamples.match(/^##\s+/m); + const examplesSection = nextH2 + ? afterExamples.slice(0, nextH2.index) + : afterExamples; + + /** @type {Array<{heading: string, items: Array<{description: string, canvasRef: import("./skills-types.mjs").CanvasRef | null}>}>} */ + const examples = []; + + // Split by ### headings + const headingRegex = /^###\s+(.+)$/gm; + /** @type {RegExpExecArray | null} */ + let headingMatch; + const headings = []; + + while ((headingMatch = headingRegex.exec(examplesSection)) !== null) { + headings.push({ + title: headingMatch[1].trim(), + index: headingMatch.index + headingMatch[0].length, + }); + } + + for (let i = 0; i < headings.length; i++) { + if (headings[i].title.toLowerCase() === "interactive demo") continue; + + const start = headings[i].index; + const end = + i + 1 < headings.length + ? headings[i + 1].index - headings[i + 1].title.length - 4 + : examplesSection.length; + const block = examplesSection.slice(start, end); + + // Split block by elements, capturing the description before each + const canvasRegex = //g; + /** @type {Array<{description: string, canvasRef: import("./skills-types.mjs").CanvasRef | null}>} */ + const items = []; + let lastIndex = 0; + /** @type {RegExpExecArray | null} */ + let canvasMatch; + while ((canvasMatch = canvasRegex.exec(block)) !== null) { + const description = block.slice(lastIndex, canvasMatch.index).trim(); + items.push({ + description, + canvasRef: { + alias: canvasMatch[1], + exportName: canvasMatch[2], + heading: headings[i].title, + }, + }); + lastIndex = canvasMatch.index + canvasMatch[0].length; + } + + // If no Canvas found, still capture the block as a prose-only item + if (items.length === 0) { + const prose = block.trim(); + if (prose) { + items.push({ description: prose, canvasRef: null }); + } + } else { + // Capture any trailing text after the last Canvas as a prose-only item + const trailing = block.slice(lastIndex).trim(); + if (trailing) { + items.push({ description: trailing, canvasRef: null }); + } + } + + if (items.length > 0) { + examples.push({ + heading: headings[i].title, + items, + }); + } + } + + return examples; +} + +/** + * Extract ArgType references from the Props section. + * @param {string} content + * @returns {import("./skills-types.mjs").ArgTypeRef[]} + */ +export function extractArgTypeRefs(content) { + const propsMatch = content.match(/^##\s+Props\s*$/m); + if (!propsMatch) return []; + + const afterProps = content.slice(propsMatch.index + propsMatch[0].length); + const nextH2 = afterProps.match(/^##\s+/m); + const propsSection = nextH2 ? afterProps.slice(0, nextH2.index) : afterProps; + + /** @type {import("./skills-types.mjs").ArgTypeRef[]} */ + const refs = []; + const headingRegex = /^###\s+(.+)$/gm; + const argTypeOnlyRegex = //g; + + const headingsInSection = []; + let hMatch; + while ((hMatch = headingRegex.exec(propsSection)) !== null) { + headingsInSection.push({ title: hMatch[1].trim(), index: hMatch.index }); + } + + let aMatch; + while ((aMatch = argTypeOnlyRegex.exec(propsSection)) !== null) { + let heading = null; + for (const h of headingsInSection) { + if (h.index < aMatch.index) heading = h.title; + } + refs.push({ alias: aMatch[1], heading }); + } + + return refs; +} + +/** + * Extract a named section (## SectionName) content. + * @param {string} content + * @param {string} sectionName + * @returns {string | null} + */ +export function extractSection(content, sectionName) { + const regex = new RegExp(`^##\\s+${sectionName}\\s*$`, "m"); + const match = regex.exec(content); + if (!match) return null; + + const afterSection = content.slice(match.index + match[0].length); + const nextH2 = afterSection.match(/^##\s+/m); + const sectionContent = nextH2 + ? afterSection.slice(0, nextH2.index).trim() + : afterSection.trim(); + return sectionContent || null; +} + +/** + * Extract sections that are not in the known/handled set. + * @param {string} content + * @returns {Array<{title: string, content: string}>} + */ +export function extractOtherSections(content) { + const h2Regex = /^##\s+(.+)$/gm; + /** @type {Array<{title: string, index: number, endOfHeading: number}>} */ + const allH2 = []; + let m; + while ((m = h2Regex.exec(content)) !== null) { + allH2.push({ + title: m[1].trim(), + index: m.index, + endOfHeading: m.index + m[0].length, + }); + } + + /** @type {Array<{title: string, content: string}>} */ + const others = []; + for (let i = 0; i < allH2.length; i++) { + if (KNOWN_SECTIONS.has(allH2[i].title.toLowerCase())) continue; + const start = allH2[i].endOfHeading; + const end = i + 1 < allH2.length ? allH2[i + 1].index : content.length; + const sectionContent = content.slice(start, end).trim(); + if (sectionContent) { + others.push({ title: allH2[i].title, content: sectionContent }); + } + } + return others; +} diff --git a/scripts/skills/props-extractor.mjs b/scripts/skills/props-extractor.mjs new file mode 100644 index 0000000000..17fd5772e9 --- /dev/null +++ b/scripts/skills/props-extractor.mjs @@ -0,0 +1,386 @@ +// @ts-check +import path from "node:path"; +import { existsSync, statSync } from "node:fs"; +import fg from "fast-glob"; +import { SyntaxKind } from "ts-morph"; +import { getOrAddSourceFile } from "./ts-project.mjs"; + +/** + * Resolve a module specifier relative to a base file path. + * @param {string} baseFilePath + * @param {string} moduleSpecifier + * @returns {string | null} + */ +export function resolveModulePathFrom(baseFilePath, moduleSpecifier) { + const basePath = path.resolve(path.dirname(baseFilePath), moduleSpecifier); + const candidates = []; + + if (existsSync(basePath)) { + const stats = statSync(basePath); + if (stats.isFile()) { + candidates.push(basePath); + } + } + + candidates.push(`${basePath}.ts`, `${basePath}.tsx`); + candidates.push(path.join(basePath, "index.ts")); + candidates.push(path.join(basePath, "index.tsx")); + + for (const candidate of candidates) { + if (existsSync(candidate)) { + return candidate; + } + } + + return null; +} + +/** + * Return the directory for a resolved module path. + * @param {string} modulePath + * @returns {string} + */ +export function getModuleDir(modulePath) { + if (existsSync(modulePath)) { + return modulePath.endsWith(".ts") || modulePath.endsWith(".tsx") + ? path.dirname(modulePath) + : modulePath; + } + return path.dirname(modulePath); +} + +/** + * Find a type/interface definition by name in a list of files. + * @param {string[]} filePaths + * @param {string} typeName + * @returns {import("./skills-types.mjs").PropsDefinition | null} + */ +export function findTypeDefinitionInFiles(filePaths, typeName) { + for (const filePath of filePaths) { + const sourceFile = getOrAddSourceFile(filePath); + if (!sourceFile) continue; + + const interfaceMatch = sourceFile.getInterface(typeName); + if (interfaceMatch) { + return { name: interfaceMatch.getName(), node: interfaceMatch }; + } + const aliasMatch = sourceFile.getTypeAlias(typeName); + if (aliasMatch) { + return { name: aliasMatch.getName(), node: aliasMatch }; + } + } + return null; +} + +/** + * Resolve props definition for a component, following type re-exports. + * @param {string} modulePath + * @param {string[]} moduleFiles + * @param {string} propsName + * @returns {import("./skills-types.mjs").PropsDefinition | null} + */ +export function resolvePropsDefinition(modulePath, moduleFiles, propsName) { + const directMatch = findTypeDefinitionInFiles(moduleFiles, propsName); + if (directMatch) return directMatch; + + const entryFile = getOrAddSourceFile(modulePath); + if (!entryFile) return null; + + for (const exportDecl of entryFile.getExportDeclarations()) { + if (!exportDecl.isTypeOnly()) continue; + const moduleSpecifier = exportDecl.getModuleSpecifierValue(); + if (!moduleSpecifier) continue; + + for (const namedExport of exportDecl.getNamedExports()) { + const alias = namedExport.getAliasNode()?.getText(); + const exportedName = namedExport.getName(); + if (alias !== propsName && exportedName !== propsName) continue; + + const targetName = alias ? exportedName : propsName; + const resolved = resolveModulePathFrom(modulePath, moduleSpecifier); + if (!resolved) continue; + + const targetFiles = fg + .sync(["**/*.{ts,tsx}"], { + cwd: getModuleDir(resolved), + absolute: true, + ignore: [ + "**/*.spec.*", + "**/*.test.*", + "**/*.stories.*", + "**/*.pw.*", + "**/*.mdx", + ], + }) + .sort(); + + const resolvedDefinition = findTypeDefinitionInFiles( + targetFiles, + targetName, + ); + if (resolvedDefinition) return resolvedDefinition; + } + } + + return null; +} + +/** + * Extract prop metadata from a props definition. + * @param {import("./skills-types.mjs").PropsDefinition} propsDefinition + * @param {Map} defaultsMap + * @returns {import("./skills-types.mjs").PropInfo[]} + */ +export function extractPropsFromDefinition(propsDefinition, defaultsMap) { + const type = propsDefinition.node.getType(); + return type + .getProperties() + .filter((symbol) => { + // Exclude props whose declaration originates from node_modules (React HTML attrs, etc.) + const declarations = symbol.getDeclarations(); + if (declarations.length === 0) return false; + return declarations.some((decl) => { + const filePath = decl.getSourceFile().getFilePath(); + return !filePath.includes("node_modules"); + }); + }) + .map((symbol) => { + const declaration = symbol + .getDeclarations() + .find( + (decl) => + decl.isKind(SyntaxKind.PropertySignature) || + decl.isKind(SyntaxKind.PropertyDeclaration), + ); + const propType = declaration + ? declaration.getType() + : symbol.getTypeAtLocation(propsDefinition.node); + const literals = getLiteralUnionValues(propType); + const jsDocs = declaration?.getJsDocs?.() ?? []; + const description = jsDocs + .map((doc) => doc.getDescription().trim()) + .filter(Boolean) + .join(" "); + const deprecationInfo = getDeprecationFromJsDocs(jsDocs); + const required = declaration?.isKind(SyntaxKind.PropertySignature) + ? !declaration.hasQuestionToken() + : true; + + const resolvedText = propType.getText( + declaration ?? propsDefinition.node, + ); + const typeNode = declaration?.getTypeNode?.(); + const typeText = ( + resolvedText.includes("import(") && typeNode + ? typeNode.getText() + : resolvedText + ) + .replace(/\s+/g, " ") + .trim(); + + return { + name: symbol.getName(), + type: typeText, + required, + literals, + description: description || null, + defaultValue: defaultsMap.get(symbol.getName()) ?? null, + deprecated: deprecationInfo.deprecated, + deprecationReason: deprecationInfo.reason, + }; + }); +} + +/** + * Return literal values for simple union types. + * @param {import("ts-morph").Type} type + * @returns {Array | null} + */ +export function getLiteralUnionValues(type) { + if (!type.isUnion()) return null; + const unionTypes = type.getUnionTypes(); + /** @type {Array} */ + const literals = []; + + for (const unionType of unionTypes) { + if (unionType.isStringLiteral()) { + const v = unionType.getLiteralValue(); + if (v === undefined) return null; + literals.push(String(v)); + } else if (unionType.isNumberLiteral()) { + const v = unionType.getLiteralValue(); + if (v === undefined) return null; + literals.push(typeof v === "number" ? v : String(v)); + } else if (unionType.isBooleanLiteral()) { + const v = unionType.getLiteralValue(); + if (v === undefined) return null; + literals.push(Boolean(v)); + } else { + return null; + } + } + + return literals; +} + +/** + * Collect default prop values from destructured parameters and defaultProps. + * @param {string[]} filePaths + * @param {string} componentName + * @returns {Map} + */ +export function collectDefaultProps(filePaths, componentName) { + const defaults = new Map(); + + for (const filePath of filePaths) { + const sourceFile = getOrAddSourceFile(filePath); + if (!sourceFile) continue; + + const defaultExportSymbol = sourceFile.getDefaultExportSymbol(); + if (defaultExportSymbol) { + for (const declaration of defaultExportSymbol.getDeclarations()) { + for (const [key, value] of extractDefaultsFromDeclaration( + declaration, + ).entries()) { + defaults.set(key, value); + } + } + } + + const namedFunction = sourceFile + .getFunctions() + .find((fn) => fn.getName() === componentName); + if (namedFunction) { + for (const [key, value] of extractDefaultsFromDeclaration( + namedFunction, + ).entries()) { + defaults.set(key, value); + } + } + + const namedVariable = sourceFile + .getVariableDeclarations() + .find((decl) => decl.getName() === componentName); + if (namedVariable) { + for (const [key, value] of extractDefaultsFromDeclaration( + namedVariable, + ).entries()) { + defaults.set(key, value); + } + } + + const assignments = sourceFile.getDescendantsOfKind( + SyntaxKind.BinaryExpression, + ); + for (const assignment of assignments) { + const left = assignment.getLeft(); + const right = assignment.getRight(); + if (!right || !right.isKind(SyntaxKind.ObjectLiteralExpression)) continue; + if (!left.isKind(SyntaxKind.PropertyAccessExpression)) continue; + if ( + left.getExpression().getText() !== componentName || + left.getName() !== "defaultProps" + ) + continue; + + for (const prop of right.getProperties()) { + if (!prop.isKind(SyntaxKind.PropertyAssignment)) continue; + const initializer = prop.getInitializer(); + if (initializer) { + defaults.set(prop.getName(), initializer.getText()); + } + } + } + } + + return defaults; +} + +/** + * Extract defaults from a component declaration. + * @param {import("ts-morph").Node} declaration + * @returns {Map} + */ +export function extractDefaultsFromDeclaration(declaration) { + const defaults = new Map(); + + if (declaration.isKind(SyntaxKind.FunctionDeclaration)) { + extractFromParameters(declaration.getParameters(), defaults); + } + + if (declaration.isKind(SyntaxKind.VariableDeclaration)) { + const initializer = declaration.getInitializer(); + if ( + initializer && + (initializer.isKind(SyntaxKind.ArrowFunction) || + initializer.isKind(SyntaxKind.FunctionExpression)) + ) { + extractFromParameters(initializer.getParameters(), defaults); + } + } + + if ( + declaration.isKind(SyntaxKind.FunctionExpression) || + declaration.isKind(SyntaxKind.ArrowFunction) + ) { + extractFromParameters(declaration.getParameters(), defaults); + } + + return defaults; +} + +/** + * Extract default values from the first object parameter binding. + * @param {import("ts-morph").ParameterDeclaration[]} parameters + * @param {Map} defaults + */ +export function extractFromParameters(parameters, defaults) { + if (!parameters || parameters.length === 0) return; + const firstParam = parameters[0]; + const nameNode = firstParam.getNameNode(); + if (!nameNode || !nameNode.isKind(SyntaxKind.ObjectBindingPattern)) return; + + for (const element of nameNode.getElements()) { + const initializer = element.getInitializer(); + if (!initializer) continue; + const propName = + element.getPropertyNameNode()?.getText() ?? element.getName(); + defaults.set(propName, initializer.getText()); + } +} + +/** + * Extract deprecation metadata from a JSDoc array. + * @param {import("ts-morph").JSDoc[]} jsDocs + * @returns {{deprecated: boolean, reason: string | null}} + */ +export function getDeprecationFromJsDocs(jsDocs) { + for (const doc of jsDocs) { + for (const tag of doc.getTags()) { + if (tag.getTagName() === "deprecated") { + const comment = normalizeJsDocComment(tag.getComment()); + const docComment = doc.getDescription().trim(); + return { deprecated: true, reason: comment || docComment || null }; + } + } + } + return { deprecated: false, reason: null }; +} + +/** + * @param {ReturnType} comment + * @returns {string | null} + */ +export function normalizeJsDocComment(comment) { + if (!comment) return null; + if (typeof comment === "string") return comment.trim() || null; + if (Array.isArray(comment)) { + return ( + comment + .map((part) => part?.getText() ?? "") + .join("") + .trim() || null + ); + } + return null; +} diff --git a/scripts/skills/props-from-stories.mjs b/scripts/skills/props-from-stories.mjs new file mode 100644 index 0000000000..932b28e800 --- /dev/null +++ b/scripts/skills/props-from-stories.mjs @@ -0,0 +1,301 @@ +// @ts-check +import fg from "fast-glob"; +import { SyntaxKind } from "ts-morph"; +import { getOrAddSourceFile } from "./ts-project.mjs"; +import { + resolveModulePathFrom, + getModuleDir, + resolvePropsDefinition, + collectDefaultProps, + extractPropsFromDefinition, +} from "./props-extractor.mjs"; + +/** + * Resolve component name and module from a stories file's default export. + * @param {string} storiesFilePath + * @returns {{componentName: string | null, componentModule: string | null}} + */ +export function resolveComponentFromStories(storiesFilePath) { + const sourceFile = getOrAddSourceFile(storiesFilePath); + if (!sourceFile) return { componentName: null, componentModule: null }; + + // Look for default export (meta) + const defaultExport = sourceFile.getDefaultExportSymbol(); + if (!defaultExport) { + // Try export default meta pattern (export = ... or export default ...) + const exportAssignment = sourceFile + .getExportAssignments() + .find((a) => !a.isExportEquals()); + if (!exportAssignment) + return { componentName: null, componentModule: null }; + + const expression = exportAssignment.getExpression(); + const objectLiteral = resolveObjectLiteral(expression, sourceFile); + if (!objectLiteral) return { componentName: null, componentModule: null }; + + return extractComponentFromMetaObject(objectLiteral, sourceFile); + } + + // Check variable declarations for the meta + for (const decl of defaultExport.getDeclarations()) { + if (decl.isKind(SyntaxKind.ExportAssignment)) { + const expression = decl.getExpression(); + const objectLiteral = resolveObjectLiteral(expression, sourceFile); + if (objectLiteral) { + return extractComponentFromMetaObject(objectLiteral, sourceFile); + } + } + } + + return { componentName: null, componentModule: null }; +} + +/** + * @param {import("ts-morph").ObjectLiteralExpression} objectLiteral + * @param {import("ts-morph").SourceFile} sourceFile + * @returns {{componentName: string | null, componentModule: string | null}} + */ +export function extractComponentFromMetaObject(objectLiteral, sourceFile) { + const componentProp = objectLiteral.getProperty("component"); + if (!componentProp?.isKind(SyntaxKind.PropertyAssignment)) { + return { componentName: null, componentModule: null }; + } + + const initializer = componentProp.getInitializer(); + const componentName = getIdentifierText(initializer); + if (!componentName) return { componentName: null, componentModule: null }; + + const componentModule = resolveImportModule(sourceFile, componentName); + return { componentName, componentModule }; +} + +/** + * @param {import("ts-morph").Expression | undefined} expression + * @param {import("ts-morph").SourceFile} sourceFile + * @returns {import("ts-morph").ObjectLiteralExpression | null} + */ +export function resolveObjectLiteral(expression, sourceFile) { + if (!expression) return null; + if (expression.isKind(SyntaxKind.ObjectLiteralExpression)) return expression; + if (expression.isKind(SyntaxKind.Identifier)) { + const name = expression.getText(); + const variable = sourceFile.getVariableDeclaration(name); + if (variable) { + const initializer = variable.getInitializer(); + if (initializer) return resolveObjectLiteral(initializer, sourceFile); + } + } + if ( + expression.isKind(SyntaxKind.SatisfiesExpression) || + expression.isKind(SyntaxKind.AsExpression) + ) { + return resolveObjectLiteral(expression.getExpression(), sourceFile); + } + return null; +} + +/** + * @param {import("ts-morph").Node | undefined} node + * @returns {string | null} + */ +export function getIdentifierText(node) { + if (!node) return null; + if (node.isKind(SyntaxKind.Identifier)) return node.getText(); + if (node.isKind(SyntaxKind.AsExpression)) + return getIdentifierText(node.getExpression()); + if (node.isKind(SyntaxKind.TypeAssertionExpression)) + return getIdentifierText(node.getExpression()); + return null; +} + +/** + * @param {import("ts-morph").SourceFile} sourceFile + * @param {string} identifierName + * @returns {string | null} + */ +export function resolveImportModule(sourceFile, identifierName) { + for (const importDecl of sourceFile.getImportDeclarations()) { + const moduleSpecifier = importDecl.getModuleSpecifierValue(); + const defaultImport = importDecl.getDefaultImport(); + if (defaultImport?.getText() === identifierName) return moduleSpecifier; + for (const namedImport of importDecl.getNamedImports()) { + const importName = namedImport.getName(); + const alias = namedImport.getAliasNode()?.getText(); + if (importName === identifierName || alias === identifierName) + return moduleSpecifier; + } + } + return null; +} + +/** + * Resolve props for a given stories file alias. + * @param {string} storiesFilePath + * @returns {import("./skills-types.mjs").PropInfo[]} + */ +export function resolvePropsForStories(storiesFilePath) { + const { componentName, componentModule } = + resolveComponentFromStories(storiesFilePath); + if (!componentName || !componentModule) return []; + + const modulePath = resolveModulePathFrom(storiesFilePath, componentModule); + if (!modulePath) return []; + + const moduleDir = getModuleDir(modulePath); + const moduleFiles = fg + .sync(["**/*.{ts,tsx}"], { + cwd: moduleDir, + absolute: true, + ignore: [ + "**/*.spec.*", + "**/*.test.*", + "**/*.stories.*", + "**/*.pw.*", + "**/*.mdx", + "**/__internal__/**", + "**/__next__/**", + ], + }) + .sort(); + + for (const filePath of moduleFiles) { + getOrAddSourceFile(filePath); + } + + const capitalizedName = + componentName.charAt(0).toUpperCase() + componentName.slice(1); + const propsName = `${capitalizedName}Props`; + const propsDefinition = resolvePropsDefinition( + modulePath, + moduleFiles, + propsName, + ); + if (!propsDefinition) return []; + + const defaultsMap = collectDefaultProps(moduleFiles, componentName); + return extractPropsFromDefinition(propsDefinition, defaultsMap); +} + +/** + * Extract PropInfo from a stories file's meta argTypes object (fallback when no component prop). + * @param {string} storiesFilePath + * @returns {import("./skills-types.mjs").PropInfo[]} + */ +export function resolveArgTypesFromMeta(storiesFilePath) { + const sourceFile = getOrAddSourceFile(storiesFilePath); + if (!sourceFile) return []; + + let metaObject = null; + const defaultExport = sourceFile.getDefaultExportSymbol(); + if (defaultExport) { + for (const decl of defaultExport.getDeclarations()) { + if (decl.isKind(SyntaxKind.ExportAssignment)) { + metaObject = resolveObjectLiteral(decl.getExpression(), sourceFile); + if (metaObject) break; + } + } + } + if (!metaObject) { + const exportAssignment = sourceFile + .getExportAssignments() + .find((a) => !a.isExportEquals()); + if (exportAssignment) { + metaObject = resolveObjectLiteral( + exportAssignment.getExpression(), + sourceFile, + ); + } + } + if (!metaObject) return []; + + const argTypesProp = metaObject.getProperty("argTypes"); + if (!argTypesProp || !argTypesProp.isKind(SyntaxKind.PropertyAssignment)) + return []; + + const argTypesObj = argTypesProp.getInitializer(); + if (!argTypesObj || !argTypesObj.isKind(SyntaxKind.ObjectLiteralExpression)) + return []; + + /** @type {import("./skills-types.mjs").PropInfo[]} */ + const props = []; + + for (const prop of argTypesObj.getProperties()) { + if (!prop.isKind(SyntaxKind.PropertyAssignment)) continue; + const propName = prop.getName(); + const propConfig = prop.getInitializer(); + if (!propConfig || !propConfig.isKind(SyntaxKind.ObjectLiteralExpression)) + continue; + + let typeName = "any"; + let required = false; + /** @type {string | null} */ + let description = null; + /** @type {string | null} */ + let defaultValue = null; + + const typeProp = propConfig.getProperty("type"); + if (typeProp && typeProp.isKind(SyntaxKind.PropertyAssignment)) { + const typeInit = typeProp.getInitializer(); + if (typeInit && typeInit.isKind(SyntaxKind.ObjectLiteralExpression)) { + const typeNameProp = typeInit.getProperty("name"); + if ( + typeNameProp && + typeNameProp.isKind(SyntaxKind.PropertyAssignment) + ) { + const n = typeNameProp.getInitializer(); + if (n) typeName = n.getText().replace(/^['"`]|['"`]$/g, ""); + } + const typeRequiredProp = typeInit.getProperty("required"); + if ( + typeRequiredProp && + typeRequiredProp.isKind(SyntaxKind.PropertyAssignment) + ) { + const r = typeRequiredProp.getInitializer(); + if (r) required = r.getText() === "true"; + } + } else if (typeInit) { + typeName = typeInit.getText().replace(/^['"`]|['"`]$/g, ""); + } + } + + const descProp = propConfig.getProperty("description"); + if (descProp && descProp.isKind(SyntaxKind.PropertyAssignment)) { + const d = descProp.getInitializer(); + if (d) description = d.getText().replace(/^['"`]|['"`]$/g, ""); + } + + const tableProp = propConfig.getProperty("table"); + if (tableProp && tableProp.isKind(SyntaxKind.PropertyAssignment)) { + const tableInit = tableProp.getInitializer(); + if (tableInit && tableInit.isKind(SyntaxKind.ObjectLiteralExpression)) { + const dvProp = tableInit.getProperty("defaultValue"); + if (dvProp && dvProp.isKind(SyntaxKind.PropertyAssignment)) { + const dvInit = dvProp.getInitializer(); + if (dvInit && dvInit.isKind(SyntaxKind.ObjectLiteralExpression)) { + const summaryProp = dvInit.getProperty("summary"); + if ( + summaryProp && + summaryProp.isKind(SyntaxKind.PropertyAssignment) + ) { + const s = summaryProp.getInitializer(); + if (s) defaultValue = s.getText().replace(/^['"`]|['"`]$/g, ""); + } + } + } + } + } + + props.push({ + name: propName, + type: typeName, + required, + literals: null, + description, + defaultValue, + deprecated: false, + deprecationReason: null, + }); + } + + return props; +} diff --git a/scripts/skills/reference-mdx.mjs b/scripts/skills/reference-mdx.mjs new file mode 100644 index 0000000000..bd557e8463 --- /dev/null +++ b/scripts/skills/reference-mdx.mjs @@ -0,0 +1,144 @@ +// @ts-check +import path from "node:path"; +import { referencesExamplesDir } from "./skills-config.mjs"; +import { getOrAddSourceFile } from "./ts-project.mjs"; +import { extractStoriesImports } from "./mdx-parser.mjs"; +import { getStoryExampleSource } from "./story-source.mjs"; +import { + resolvePropsForStories, + resolveArgTypesFromMeta, +} from "./props-from-stories.mjs"; +import { renderPropsTable } from "./renderers.mjs"; +import { transformLinksForRefDoc } from "./links.mjs"; +import { resolveStoriesPath } from "./utils.mjs"; + +/** + * Process a reference MDX file: strip Storybook boilerplate, expand Canvas/ArgTypes, transform links. + * @param {string} rawContent + * @param {string} sourcePath + * @param {Set} availableSlugs + * @returns {Promise<{content: string, exampleFiles: import("./skills-types.mjs").OutputFile[]}>} + */ +export async function parseAndRenderReferenceMdx( + rawContent, + sourcePath, + availableSlugs, +) { + const mdxDir = path.dirname(sourcePath); + const content = rawContent.replace(/\r\n/g, "\n"); + + /** @type {import("./skills-types.mjs").OutputFile[]} */ + const exampleFiles = []; + + // Extract storiesImports before stripping import lines + const storiesImports = extractStoriesImports(content); + + // Resolve stories files to absolute paths + /** @type {Map} alias -> absolute path */ + const resolvedStories = new Map(); + for (const [alias, relativePath] of storiesImports.entries()) { + const resolved = resolveStoriesPath(mdxDir, relativePath); + if (resolved) { + resolvedStories.set(alias, resolved); + getOrAddSourceFile(resolved); + } + } + + let result = content; + + // Strip top-level import lines (those outside fenced code blocks) + // Process line by line to avoid stripping import statements inside code examples + { + const lines = result.split("\n"); + let inCodeBlock = false; + result = lines + .filter((line) => { + if (line.startsWith("```")) inCodeBlock = !inCodeBlock; + if (inCodeBlock) return true; + return !/^import\s/.test(line); + }) + .join("\n"); + } + + // Strip tags + result = result.replace(/]*\/>\s*\n?/g, ""); + + // Strip ## Contents section (heading + all content until next ## heading) + const contentsMatch = result.match(/^## Contents\s*$/m); + if (contentsMatch) { + const afterContents = result.slice( + contentsMatch.index + contentsMatch[0].length, + ); + const nextH2 = afterContents.match(/^## /m); + result = + result.slice(0, contentsMatch.index) + + (nextH2 ? afterContents.slice(nextH2.index) : ""); + } + + // Resolve example sources (async) up front, + // then replace synchronously below. + const canvasRegex = //g; + /** @type {Map} `${alias}.${exportName}` -> source */ + const canvasSources = new Map(); + for (const m of result.matchAll(canvasRegex)) { + const [, alias, exportName] = m; + const key = `${alias}.${exportName}`; + if (canvasSources.has(key)) continue; + const storiesPath = resolvedStories.get(alias); + canvasSources.set( + key, + storiesPath ? await getStoryExampleSource(storiesPath, exportName) : null, + ); + } + + // Replace with example file references + result = result.replace(canvasRegex, (match, alias, exportName) => { + const storiesPath = resolvedStories.get(alias); + if (!storiesPath) { + // eslint-disable-next-line no-console -- build warning + console.warn(`[ref] Cannot resolve stories alias: ${alias}`); + return ""; + } + const source = canvasSources.get(`${alias}.${exportName}`); + if (!source) { + // eslint-disable-next-line no-console -- build warning + console.warn( + `[ref] Cannot find export "${exportName}" in ${path.basename(storiesPath)}`, + ); + return ""; + } + const fileName = `${exportName}.md`; + const fileContent = "```tsx\n" + source + "\n```"; + exampleFiles.push({ + path: path.join(referencesExamplesDir, fileName), + content: fileContent, + }); + return `\nSee: \`examples/${fileName}\``; + }); + + // Replace with rendered props table + result = result.replace( + //g, + (match, alias) => { + const storiesPath = resolvedStories.get(alias); + if (!storiesPath) { + // eslint-disable-next-line no-console -- build warning + console.warn(`[ref] Cannot resolve ArgTypes alias: ${alias}`); + return ""; + } + let props = resolvePropsForStories(storiesPath); + if (!props.length) { + props = resolveArgTypesFromMeta(storiesPath); + } + return renderPropsTable(props); + }, + ); + + // Transform Storybook links to skill-relative paths + result = transformLinksForRefDoc(result, availableSlugs); + + // Collapse 3+ consecutive blank lines to 2 + result = result.replace(/\n{3,}/g, "\n\n"); + + return { content: result.trim() + "\n", exampleFiles }; +} diff --git a/scripts/skills/renderers.mjs b/scripts/skills/renderers.mjs new file mode 100644 index 0000000000..f7b34a2973 --- /dev/null +++ b/scripts/skills/renderers.mjs @@ -0,0 +1,240 @@ +// @ts-check +import { escapePipes } from "./utils.mjs"; +import { transformLinks } from "./links.mjs"; + +/** + * Render the props table. + * @param {import("./skills-types.mjs").PropInfo[]} props + * @returns {string} + */ +export function renderPropsTable(props) { + if (!props.length) return "No props metadata found.\n"; + + const sortedProps = [...props].sort((a, b) => { + if (a.deprecated !== b.deprecated) return a.deprecated ? 1 : -1; + if (a.required !== b.required) return a.required ? -1 : 1; + const groupOrder = (/** @type {string} */ name) => + name.startsWith("data-") ? 1 : name.startsWith("aria-") ? 2 : 0; + const ga = groupOrder(a.name); + const gb = groupOrder(b.name); + if (ga !== gb) return ga - gb; + return a.name.localeCompare(b.name); + }); + + const hasDeprecated = sortedProps.some((p) => p.deprecated); + const lines = []; + + if (hasDeprecated) { + lines.push( + "| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default |", + ); + lines.push("| --- | --- | --- | --- | --- | --- | --- | --- |"); + } else { + lines.push("| Name | Type | Required | Literals | Description | Default |"); + lines.push("| --- | --- | --- | --- | --- | --- |"); + } + + for (const prop of sortedProps) { + const literals = prop.literals?.join(" | ") ?? ""; + const description = prop.description?.replace(/\s+/g, " ") ?? ""; + const defaultValue = (prop.defaultValue ?? "").replace(/\r/g, ""); + + if (hasDeprecated) { + lines.push( + `| ${prop.name} | ${escapePipes(prop.type)} | ${prop.required ? "Yes" : "No"} | ${escapePipes(literals)} | ${prop.deprecated ? "Yes" : ""} | ${escapePipes((prop.deprecationReason ?? "").replace(/\s+/g, " ").trim())} | ${escapePipes(description)} | ${escapePipes(defaultValue)} |`, + ); + } else { + lines.push( + `| ${prop.name} | ${escapePipes(prop.type)} | ${prop.required ? "Yes" : "No"} | ${escapePipes(literals)} | ${escapePipes(description)} | ${escapePipes(defaultValue)} |`, + ); + } + } + + return lines.join("\n") + "\n"; +} + +/** + * Render the full component index.md content (no skill frontmatter). + * @param {import("./skills-types.mjs").ParsedMdx} parsed + * @param {Map} propsMap - heading -> props + * @param {import("./skills-types.mjs").ExampleFile[]} exampleFiles + * @param {boolean} isDeprecated + * @param {Set} availableSlugs + * @returns {string} + */ +export function renderSkillMd( + parsed, + propsMap, + exampleFiles, + isDeprecated, + availableSlugs, +) { + const lines = [`# ${parsed.componentTitle}`, ""]; + + if (isDeprecated) { + lines.push( + "> **Deprecated** — See [`deprecation-migration.md`](../../references/docs/deprecation-migration.md)", + "", + ); + } + + if (parsed.description) { + lines.push(transformLinks(parsed.description, availableSlugs), ""); + } + + if (parsed.category) { + lines.push(`**Category:** ${parsed.category}`, ""); + } + + if (parsed.quickStart) { + lines.push(parsed.quickStart.heading, "", parsed.quickStart.content, ""); + } + + if (parsed.designerNotes) { + lines.push( + "## Designer Notes", + "", + transformLinks(parsed.designerNotes, availableSlugs), + "", + ); + } + + if (parsed.relatedComponents) { + lines.push( + "## Related Components", + "", + transformLinks(parsed.relatedComponents, availableSlugs), + "", + ); + } + + for (const section of parsed.otherSections) { + lines.push( + `## ${section.title}`, + "", + transformLinks(section.content, availableSlugs), + "", + ); + } + + if (exampleFiles.length > 0) { + lines.push("## Examples", ""); + const byHeading = new Map(); + for (const ef of exampleFiles) { + const existing = byHeading.get(ef.heading) ?? []; + existing.push({ fileName: ef.fileName, description: ef.description }); + byHeading.set(ef.heading, existing); + } + + for (const [heading, items] of byHeading.entries()) { + lines.push(`### ${heading}`, ""); + for (const { fileName, description } of items) { + if (description) { + lines.push(transformLinks(description, availableSlugs), ""); + } + if (fileName) { + lines.push(`See: \`examples/${fileName}\``, ""); + } + } + } + } + + if (propsMap.size > 0) { + lines.push("## Props", ""); + for (const [heading, props] of propsMap.entries()) { + lines.push(`### ${heading}`, ""); + lines.push(renderPropsTable(props)); + } + } + + if (parsed.refMethods) { + lines.push("## Ref methods", "", parsed.refMethods, ""); + } + + return lines.join("\n"); +} + +/** + * Render the root SKILL.md content for the centralized carbon-react skill. + * @returns {string} + */ +export function renderSkillRootContent() { + return [ + "---", + "name: carbon-react", + "description: Carbon component catalog with typed props, Storybook usage examples, and curated docs references. Use proactively when the user asks about any Carbon component and its props, which component to use for a given UI need, migrating a deprecated component, usage guidance or when implementing or reviewing any UI built with carbon-react.", + "---", + "", + "# Carbon Component Catalog", + "", + "Use `index.md` to find a component and its description.", + "Use `components/{slug}/index.md` for a component's props and examples.", + "Use `components/{slug}/examples/*.md` for example source code.", + "", + "## Deprecated components", + "", + "Deprecated components are marked in `index.md` and in their file.", + "Prefer the non-legacy version (`button`) over the legacy one (`button-legacy`) unless explicitly asked.", + "Do not use deprecated props unless explicitly asked.", + "For migrating a deprecated component, read `references/docs/deprecation-migration.md`.", + "", + "## Reference docs", + "", + "- `references/docs/usage.md` — general usage guide", + "- `references/docs/installation.md` — installation", + "- `references/docs/recommended-practices.md` — recommended practices", + "- `references/docs/validations.md` — validation for input components", + "- `references/docs/useMediaQuery.md` — custom React hook and a JavaScript implementation of a CSS media query", + "- `references/docs/deprecation-migration.md` — deprecated components migration guide", + "- `references/docs/usage-with-routing.md` — using Carbon components with routing libraries", + "- `references/docs/i18n.md` — how localisation works in Carbon", + "", + ].join("\n"); +} + +/** + * Render the catalog index.md listing all components with descriptions, organized by category. + * @param {Array<{title: string, slug: string, description: string, category: string, isDeprecated: boolean}>} entries + * @returns {string} + */ +export function renderIndexContent(entries) { + // Group entries by category + const byCategory = new Map(); + for (const entry of entries) { + const cat = entry.category || "Other"; + if (!byCategory.has(cat)) { + byCategory.set(cat, []); + } + byCategory.get(cat).push(entry); + } + + // Sort categories, with "Other" at the end + const categories = Array.from(byCategory.keys()).sort((a, b) => { + if (a === "Other") return 1; + if (b === "Other") return -1; + return a.localeCompare(b); + }); + + const lines = ["# Carbon Component Catalog", ""]; + + for (const category of categories) { + const entries = byCategory.get(category) || []; + // Sort entries by title within each category + entries.sort((a, b) => a.title.localeCompare(b.title)); + + lines.push(`### ${category}`, ""); + lines.push("| Component | Description | Deprecated |"); + lines.push("| --- | --- | --- |"); + + for (const entry of entries) { + const deprecatedLabel = entry.isDeprecated ? "Yes" : "No"; + const link = `[${entry.title}](components/${entry.slug}/)`; + lines.push( + `| ${link} | ${entry.description || ""} | ${deprecatedLabel} |`, + ); + } + lines.push(""); + } + + return lines.join("\n"); +} diff --git a/scripts/skills/skills-config.mjs b/scripts/skills/skills-config.mjs new file mode 100644 index 0000000000..2f20ba5ab3 --- /dev/null +++ b/scripts/skills/skills-config.mjs @@ -0,0 +1,78 @@ +// @ts-check +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +export const repoRoot = path.resolve(__dirname, "../.."); + +export const skillsRoot = path.join(repoRoot, "skills", "carbon-react"); +export const componentsOutDir = path.join(skillsRoot, "components"); +export const referencesDir = path.join(skillsRoot, "references", "docs"); +export const referencesExamplesDir = path.join(referencesDir, "examples"); + +/** @type {Array} */ +export const docsReferenceFiles = [ + "docs/usage.mdx", + "docs/installation.mdx", + "docs/recommended-practices.mdx", + "docs/usage-with-routing.mdx", + "docs/i18n.mdx", + "docs/deprecation-migration.mdx", + "docs/validations.mdx", + { + source: "src/hooks/useMediaQuery/use-media-query.mdx", + target: "useMediaQuery.md", + }, +]; + +export const KNOWN_SECTIONS = new Set([ + "contents", + "quick start", + "playground", + "examples", + "props", + "translation keys", + "designer notes", + "related components", + "ref methods", + "list of icons", +]); + +/** + * Map of Storybook documentation slugs to their reference file paths (relative to a component's index.md). + * @type {Map} + */ +export const referenceSlugMap = new Map([ + ["documentation-validations", "../../references/docs/validations.md"], + ["documentation-i18n", "../../references/docs/i18n.md"], + ["documentation-usage", "../../references/docs/usage.md"], + ["documentation-installation", "../../references/docs/installation.md"], + [ + "documentation-recommended-practices", + "../../references/docs/recommended-practices.md", + ], + [ + "documentation-usage-with-routing", + "../../references/docs/usage-with-routing.md", + ], + [ + "documentation-deprecation-migration", + "../../references/docs/deprecation-migration.md", + ], +]); + +/** + * Map of Storybook documentation slugs to self-relative paths for use within references/docs/. + * @type {Map} + */ +export const referenceDocSelfSlugMap = new Map([ + ["documentation-validations", "./validations.md"], + ["documentation-i18n", "./i18n.md"], + ["documentation-usage", "./usage.md"], + ["documentation-installation", "./installation.md"], + ["documentation-recommended-practices", "./recommended-practices.md"], + ["documentation-usage-with-routing", "./usage-with-routing.md"], + ["documentation-deprecation-migration", "./deprecation-migration.md"], + ["documentation-hooks-usemediaquery", "./useMediaQuery.md"], +]); diff --git a/scripts/skills/skills-types.mjs b/scripts/skills/skills-types.mjs new file mode 100644 index 0000000000..1f9d1e39ea --- /dev/null +++ b/scripts/skills/skills-types.mjs @@ -0,0 +1,77 @@ +// @ts-check + +/** + * @typedef {Object} PropsDefinition + * @property {string} name + * @property {import("ts-morph").InterfaceDeclaration | import("ts-morph").TypeAliasDeclaration} node + */ + +/** + * @typedef {Object} PropInfo + * @property {string} name + * @property {string} type + * @property {boolean} required + * @property {Array | null} literals + * @property {string | null} description + * @property {string | null} defaultValue + * @property {boolean} deprecated + * @property {string | null} deprecationReason + */ + +/** + * @typedef {Object} CanvasRef + * @property {string} alias + * @property {string} exportName + * @property {string} heading + */ + +/** + * @typedef {Object} ArgTypeRef + * @property {string} alias + * @property {string | null} heading + */ + +/** + * @typedef {Object} MdxSection + * @property {string} title + * @property {string} content + */ + +/** + * @typedef {Object} ParsedMdx + * @property {string} componentTitle + * @property {string} description + * @property {string | null} category + * @property {{ heading: string, content: string } | null} quickStart + * @property {Map} storiesImports - alias -> relative path + * @property {Array<{heading: string, items: Array<{description: string, canvasRef: CanvasRef | null}>}>} examples + * @property {ArgTypeRef[]} argTypeRefs + * @property {string | null} designerNotes + * @property {string | null} relatedComponents + * @property {string | null} refMethods + * @property {Array<{title: string, content: string}>} otherSections + */ + +/** + * @typedef {Object} MdxEntry + * @property {string} mdxPath + * @property {string} content + * @property {boolean} isNext + * @property {string} baseName + * @property {boolean} isDeprecated + */ + +/** + * @typedef {Object} OutputFile + * @property {string} path + * @property {string} content + */ + +/** + * @typedef {Object} ExampleFile + * @property {string} heading + * @property {string | null} fileName + * @property {string} description + */ + +export {}; diff --git a/scripts/skills/story-resolver.mjs b/scripts/skills/story-resolver.mjs new file mode 100644 index 0000000000..87310e9037 --- /dev/null +++ b/scripts/skills/story-resolver.mjs @@ -0,0 +1,375 @@ +// @ts-check +import prettier from "prettier"; +import { SyntaxKind } from "ts-morph"; +import { project, getOrAddSourceFile } from "./ts-project.mjs"; + +/** + * @typedef {{ valueNode: import("ts-morph").Node | undefined }} ArgValue + */ + +/** + * Unwrap `as`, `satisfies` and parenthesized expressions to their inner node. + * @param {import("ts-morph").Node | undefined} node + * @returns {import("ts-morph").Node | undefined} + */ +function unwrap(node) { + if (!node) return node; + if ( + node.isKind(SyntaxKind.AsExpression) || + node.isKind(SyntaxKind.SatisfiesExpression) || + node.isKind(SyntaxKind.ParenthesizedExpression) + ) { + return unwrap(node.getExpression()); + } + return node; +} + +/** + * Resolve the object literal an expression ultimately points to (following + * simple variable references), or null when it cannot be resolved statically. + * @param {import("ts-morph").Node | undefined} expression + * @param {import("ts-morph").SourceFile} sourceFile + * @returns {import("ts-morph").ObjectLiteralExpression | null} + */ +function resolveObjectLiteralExpr(expression, sourceFile) { + const node = unwrap(expression); + if (!node) return null; + if (node.isKind(SyntaxKind.ObjectLiteralExpression)) return node; + if (node.isKind(SyntaxKind.Identifier)) { + const variable = sourceFile.getVariableDeclaration(node.getText()); + if (variable) { + return resolveObjectLiteralExpr(variable.getInitializer(), sourceFile); + } + } + return null; +} + +/** + * Get the render function (arrow / function expression) for a story export, + * resolving inheritance via `...OtherStory` spreads for ANY referenced story. + * @param {import("ts-morph").SourceFile} sourceFile + * @param {string} exportName + * @param {Set} visited + * @returns {import("ts-morph").ArrowFunction | import("ts-morph").FunctionExpression | null} + */ +function resolveRender(sourceFile, exportName, visited) { + if (visited.has(exportName)) return null; + visited.add(exportName); + + const decl = sourceFile.getVariableDeclaration(exportName); + if (!decl) return null; + + const init = unwrap(decl.getInitializer()); + if (!init) return null; + + if ( + init.isKind(SyntaxKind.ArrowFunction) || + init.isKind(SyntaxKind.FunctionExpression) + ) { + return init; + } + + if (init.isKind(SyntaxKind.ObjectLiteralExpression)) { + const renderProp = init.getProperty("render"); + if (renderProp && renderProp.isKind(SyntaxKind.PropertyAssignment)) { + const renderInit = unwrap(renderProp.getInitializer()); + if ( + renderInit && + (renderInit.isKind(SyntaxKind.ArrowFunction) || + renderInit.isKind(SyntaxKind.FunctionExpression)) + ) { + return renderInit; + } + } + + // Inherit render from a spread story: `{ ...OtherStory, ... }` + for (const prop of init.getProperties()) { + if (!prop.isKind(SyntaxKind.SpreadAssignment)) continue; + const spreadExpr = unwrap(prop.getExpression()); + if (spreadExpr && spreadExpr.isKind(SyntaxKind.Identifier)) { + const inherited = resolveRender( + sourceFile, + spreadExpr.getText(), + visited, + ); + if (inherited) return inherited; + } + } + } + + return null; +} + +/** + * Merge the entries of an args object literal into the ordered map, resolving + * nested spreads such as `...OtherStory.args`. + * @param {import("ts-morph").ObjectLiteralExpression} objLiteral + * @param {import("ts-morph").SourceFile} sourceFile + * @param {Map} into + * @param {Set} visited + */ +function mergeArgsFromObject(objLiteral, sourceFile, into, visited) { + for (const prop of objLiteral.getProperties()) { + if (prop.isKind(SyntaxKind.SpreadAssignment)) { + const spreadExpr = unwrap(prop.getExpression()); + if (!spreadExpr) continue; + + // `...OtherStory.args` + if (spreadExpr.isKind(SyntaxKind.PropertyAccessExpression)) { + if (spreadExpr.getName() === "args") { + const storyName = spreadExpr.getExpression().getText(); + const sub = resolveArgsMap(sourceFile, storyName, new Set(visited)); + for (const [key, value] of sub) into.set(key, value); + } + continue; + } + + // `...OtherStory` (whole story) or `...someObjectVariable` + if (spreadExpr.isKind(SyntaxKind.Identifier)) { + const name = spreadExpr.getText(); + if (sourceFile.getVariableDeclaration(name)) { + const sub = resolveArgsMap(sourceFile, name, new Set(visited)); + for (const [key, value] of sub) into.set(key, value); + } + continue; + } + + const nested = resolveObjectLiteralExpr(spreadExpr, sourceFile); + if (nested) mergeArgsFromObject(nested, sourceFile, into, visited); + continue; + } + + if (prop.isKind(SyntaxKind.PropertyAssignment)) { + into.set(prop.getName(), { valueNode: prop.getInitializer() }); + continue; + } + + if (prop.isKind(SyntaxKind.ShorthandPropertyAssignment)) { + into.set(prop.getName(), { valueNode: prop.getNameNode() }); + } + } +} + +/** + * Resolve the effective args for a story export, following inheritance via + * `...OtherStory` / `...OtherStory.args` spreads for ANY referenced story. + * Later entries win (matching JS spread semantics); the injected arg therefore + * overrides earlier explicit props at the call site. + * @param {import("ts-morph").SourceFile} sourceFile + * @param {string} exportName + * @param {Set} visited + * @returns {Map} + */ +function resolveArgsMap(sourceFile, exportName, visited) { + /** @type {Map} */ + const into = new Map(); + if (visited.has(exportName)) return into; + visited.add(exportName); + + const decl = sourceFile.getVariableDeclaration(exportName); + if (!decl) return into; + + const init = unwrap(decl.getInitializer()); + if (!init) return into; + + if (init.isKind(SyntaxKind.ObjectLiteralExpression)) { + for (const prop of init.getProperties()) { + if (prop.isKind(SyntaxKind.SpreadAssignment)) { + // Top-level `...OtherStory` brings the inherited story's args. + const spreadExpr = unwrap(prop.getExpression()); + if (spreadExpr && spreadExpr.isKind(SyntaxKind.Identifier)) { + const sub = resolveArgsMap( + sourceFile, + spreadExpr.getText(), + new Set(visited), + ); + for (const [key, value] of sub) into.set(key, value); + } + continue; + } + if ( + prop.isKind(SyntaxKind.PropertyAssignment) && + prop.getName() === "args" + ) { + const argsObj = resolveObjectLiteralExpr( + prop.getInitializer(), + sourceFile, + ); + if (argsObj) mergeArgsFromObject(argsObj, sourceFile, into, visited); + } + } + return into; + } + + // Function-style story: look for `ExportName.args = { ... }` assignments. + if ( + init.isKind(SyntaxKind.ArrowFunction) || + init.isKind(SyntaxKind.FunctionExpression) + ) { + for (const statement of sourceFile.getStatements()) { + if (!statement.isKind(SyntaxKind.ExpressionStatement)) continue; + const expr = statement.getExpression(); + if (!expr.isKind(SyntaxKind.BinaryExpression)) continue; + if (expr.getOperatorToken().getKind() !== SyntaxKind.EqualsToken) + continue; + const left = expr.getLeft(); + if (!left.isKind(SyntaxKind.PropertyAccessExpression)) continue; + if (left.getName() !== "args") continue; + if (left.getExpression().getText() !== exportName) continue; + + const argsObj = resolveObjectLiteralExpr(expr.getRight(), sourceFile); + if (argsObj) mergeArgsFromObject(argsObj, sourceFile, into, visited); + } + } + + return into; +} + +/** + * Ensure `args` is only ever referenced through `{...args}` JSX spreads, so it + * is safe to inline. Any other usage (destructuring, `args.foo`, `prop={args}`) + * means we cannot statically resolve the example and should fall back. + * @param {import("ts-morph").Node} bodyNode + * @returns {boolean} + */ +function argsUsedOnlyInSpreads(bodyNode) { + const identifiers = bodyNode + .getDescendantsOfKind(SyntaxKind.Identifier) + .filter((id) => id.getText() === "args"); + + return identifiers.every((id) => { + const parent = id.getParent(); + return ( + parent !== undefined && + parent.isKind(SyntaxKind.JsxSpreadAttribute) && + parent.getExpression() === id + ); + }); +} + +/** + * Render a single resolved arg as JSX attribute text. + * @param {string} name + * @param {ArgValue} info + * @returns {string} + */ +function renderAttribute(name, info) { + const valueNode = info.valueNode; + if (!valueNode) return name; + + if (valueNode.isKind(SyntaxKind.StringLiteral)) { + const text = valueNode.getLiteralText(); + const quoted = JSON.stringify(text); + // Double quotes inside the value break `attr="..."`, use an expression. + return text.includes('"') ? `${name}={${quoted}}` : `${name}=${quoted}`; + } + if (valueNode.isKind(SyntaxKind.TrueKeyword)) return name; + + return `${name}={${valueNode.getText()}}`; +} + +/** + * Replace every `{...args}` JSX spread with explicit attributes built from the + * resolved args map. The injected arg wins over an earlier explicit attribute + * of the same name (matching runtime spread semantics). + * @param {import("ts-morph").SourceFile} sourceFile + * @param {Map} argsMap + */ +function injectArgsIntoJsx(sourceFile, argsMap) { + for (;;) { + const spread = sourceFile + .getDescendantsOfKind(SyntaxKind.JsxSpreadAttribute) + .find((node) => node.getExpression().getText() === "args"); + if (!spread) break; + + const element = + spread.getFirstAncestorByKind(SyntaxKind.JsxOpeningElement) ?? + spread.getFirstAncestorByKind(SyntaxKind.JsxSelfClosingElement); + if (!element) { + spread.remove(); + continue; + } + + const isSelfClosing = element.isKind(SyntaxKind.JsxSelfClosingElement); + const tagName = element.getTagNameNode().getText(); + + /** @type {string[]} */ + const parts = []; + for (const attr of element.getAttributes()) { + if ( + attr.isKind(SyntaxKind.JsxSpreadAttribute) && + attr.getExpression().getText() === "args" + ) { + for (const [name, info] of argsMap) { + parts.push(renderAttribute(name, info)); + } + continue; + } + if ( + attr.isKind(SyntaxKind.JsxAttribute) && + argsMap.has(attr.getNameNode().getText()) + ) { + // Dropped: the injected arg wins over this explicit attribute. + continue; + } + parts.push(attr.getText()); + } + + const inner = [tagName, ...parts].join(" "); + element.replaceWithText(isSelfClosing ? `<${inner} />` : `<${inner}>`); + } +} + +/** + * Resolve a story export into a clean, runnable example snippet: the render + * body is normalized into `export const : Story = () => (...)`, the + * `render`/args plumbing is removed, and resolved args are inlined as explicit + * JSX props. Returns null when the story cannot be resolved statically, so the + * caller can fall back to the raw source. + * @param {string} filePath + * @param {string} exportName + * @returns {Promise} + */ +export async function resolveStoryExample(filePath, exportName) { + const sourceFile = getOrAddSourceFile(filePath); + if (!sourceFile) return null; + + const decl = sourceFile.getVariableDeclaration(exportName); + if (!decl) return null; + + const renderFn = resolveRender(sourceFile, exportName, new Set()); + if (!renderFn) return null; + + const body = renderFn.getBody(); + if (!body) return null; + + if (!argsUsedOnlyInSpreads(body)) return null; + + const argsMap = resolveArgsMap(sourceFile, exportName, new Set()); + + let bodyText; + if (body.isKind(SyntaxKind.Block)) { + bodyText = body.getText(); + } else { + const inner = body.isKind(SyntaxKind.ParenthesizedExpression) + ? body.getExpression().getText() + : body.getText(); + bodyText = `(${inner})`; + } + + const typeNode = decl.getTypeNode(); + const typeAnnotation = typeNode ? `: ${typeNode.getText()}` : ""; + const snippet = `export const ${exportName}${typeAnnotation} = () => ${bodyText};`; + + const tmpName = `__story_example_${exportName}_${Math.random().toString(36).slice(2)}.tsx`; + const tmp = project.createSourceFile(tmpName, snippet, { overwrite: true }); + try { + injectArgsIntoJsx(tmp, argsMap); + const formatted = await prettier.format(tmp.getFullText(), { + parser: "typescript", + }); + return formatted.trimEnd(); + } finally { + project.removeSourceFile(tmp); + } +} diff --git a/scripts/skills/story-source.mjs b/scripts/skills/story-source.mjs new file mode 100644 index 0000000000..e38ede4abd --- /dev/null +++ b/scripts/skills/story-source.mjs @@ -0,0 +1,53 @@ +// @ts-check +import { SyntaxKind } from "ts-morph"; +import { getOrAddSourceFile } from "./ts-project.mjs"; +import { resolveStoryExample } from "./story-resolver.mjs"; + +/** + * Get a clean, runnable example snippet for a named story export, resolving + * `render`/args plumbing and inlining args. Falls back to the raw source text + * when the story cannot be statically resolved. + * @param {string} filePath + * @param {string} exportName + * @returns {Promise} + */ +export async function getStoryExampleSource(filePath, exportName) { + try { + const resolved = await resolveStoryExample(filePath, exportName); + if (resolved) return resolved; + } catch { + // Fall back to the raw source below. + } + return getStoryExportSource(filePath, exportName); +} + +/** + * Get the full source text of a named export from a stories file. + * @param {string} filePath + * @param {string} exportName + * @returns {string | null} + */ +export function getStoryExportSource(filePath, exportName) { + const sourceFile = getOrAddSourceFile(filePath); + if (!sourceFile) return null; + + const exported = sourceFile.getExportedDeclarations(); + const declarations = exported.get(exportName); + if (!declarations || declarations.length === 0) return null; + + for (const declaration of declarations) { + if (declaration.isKind(SyntaxKind.VariableDeclaration)) { + // Get the full variable statement (export const X = ...) + const statement = declaration.getVariableStatement(); + if (statement) { + return statement.getText(); + } + return `export const ${exportName} = ${declaration.getInitializer()?.getText() ?? "undefined"};`; + } + if (declaration.isKind(SyntaxKind.FunctionDeclaration)) { + return declaration.getText(); + } + } + + return null; +} diff --git a/scripts/skills/ts-project.mjs b/scripts/skills/ts-project.mjs new file mode 100644 index 0000000000..ef433eac0f --- /dev/null +++ b/scripts/skills/ts-project.mjs @@ -0,0 +1,26 @@ +// @ts-check +import path from "node:path"; +import { Project } from "ts-morph"; +import { repoRoot } from "./skills-config.mjs"; + +export const project = new Project({ + tsConfigFilePath: path.join(repoRoot, "tsconfig.json"), + skipAddingFilesFromTsConfig: true, +}); + +project.addSourceFilesAtPaths([ + path.join(repoRoot, "src", "components", "**", "*.ts"), + path.join(repoRoot, "src", "components", "**", "*.tsx"), +]); + +/** + * Get a source file already known to the project, otherwise add it from disk. + * @param {string} filePath + * @returns {import("ts-morph").SourceFile | undefined} + */ +export function getOrAddSourceFile(filePath) { + return ( + project.getSourceFile(filePath) || + project.addSourceFileAtPathIfExists(filePath) + ); +} diff --git a/scripts/skills/utils.mjs b/scripts/skills/utils.mjs new file mode 100644 index 0000000000..e61acddd02 --- /dev/null +++ b/scripts/skills/utils.mjs @@ -0,0 +1,34 @@ +// @ts-check +import path from "node:path"; +import { existsSync } from "node:fs"; + +/** + * @param {string} value + * @returns {string} + */ +export function escapePipes(value) { + return value?.replace(/\|/g, "\\|") ?? ""; +} + +/** + * Resolve a stories import path to an absolute file path. + * @param {string} mdxDir + * @param {string} relativePath + * @returns {string | null} + */ +export function resolveStoriesPath(mdxDir, relativePath) { + const basePath = path.resolve(mdxDir, relativePath); + const extensions = [".ts", ".tsx", ".js", ".jsx"]; + + if (existsSync(basePath)) return basePath; + for (const ext of extensions) { + const candidate = basePath + ext; + if (existsSync(candidate)) return candidate; + } + // Try with /index + for (const ext of extensions) { + const candidate = path.join(basePath, `index${ext}`); + if (existsSync(candidate)) return candidate; + } + return null; +} diff --git a/scripts/validate-mdx/README.md b/scripts/validate-mdx/README.md new file mode 100644 index 0000000000..2c5684fbae --- /dev/null +++ b/scripts/validate-mdx/README.md @@ -0,0 +1,126 @@ +# MDX validator + +Validates component MDX as the source consumed by `build_skills` while checking machine-verifiable facts against Storybook and the public component modules. + +The validator never creates missing documentation. A missing section fails with an actionable diagnostic; authoring remains the responsibility of a developer or an authoring skill. + +## Commands + +### Validate every component MDX + +```sh +npm run validate:mdx +``` + +Validates all component documentation matching `src/components/**/*.mdx`. Use this before submitting MDX or Storybook changes to find inconsistencies across the complete documentation set. This global command also checks that every top-level folder in `src/components` contains at least one non-internal MDX. + +Explicit exceptions are listed in `MDX_COVERAGE_EXCLUSIONS` because they are intentionally documented elsewhere or do not require their own component MDX. + +### Validate one MDX file + +```sh +npm run validate:mdx -- src/components/pill/pill.mdx +``` + +Validates only the provided file. +Use this for quick feedback while editing one component. + +### Produce machine-readable output + +```sh +npm run validate:mdx -- --json +``` + +Runs the same validation as `npm run validate:mdx`, but prints a JSON object with the file, error and warning counts plus every diagnostic. +This format is intended for CI and other scripts. + +```sh +npm run validate:mdx -- src/components/pill/pill.mdx --json +``` + +### Test the validator + +```sh +npm run test:validate-mdx +``` + +Runs the validator's unit tests against controlled MDX fixtures. This checks that the validation rules themselves accept valid structures and report invalid ones; it does not validate the project's real MDX files. + +### Exit codes + +- `0`: validation completed without errors, or all validator tests passed; +- `1`: at least one MDX validation error exists, or a validator test failed; +- `2`: no MDX file matched the supplied paths or patterns. + +## Checks + +Each diagnostic starts with its rule name, for example `contents/broken-link` or `examples/description`. +The checks are grouped below by the part of the MDX they validate. + +### Component folder coverage + +The global `npm run validate:mdx` command requires every folder directly under `src/components` to contain at least one MDX file. +The MDX may be located in a subfolder, so a single page can document a component family; files below an `__internal__` folder do not count. + +Folders intentionally documented elsewhere or not requiring their own page are listed in `MDX_COVERAGE_EXCLUSIONS`. +This coverage check does not run when a specific file or glob is passed to the validator. + +### Component metadata + +- The document must contain exactly one H1 component title. +- A non-empty component description must appear after the H1 and before `**Category:**`. +- There is no minimum description length. +- There must be exactly one `**Category:**` declaration. +- The category must appear before `Contents` and use one of the values defined in `CATEGORIES`. + +### Sections and heading hierarchy + +- `Contents`, `Quick start`, `Examples`, and `Props` are required H2 sections and must appear in that order. +- Other H2 sections are allowed and do not need to be registered in the validator. +- H2 section names use sentence case: `Quick start`, `Validation states`, and `Related components`, not title case. +- Duplicate H2 sections are rejected, including differently capitalized names that normalize to the same section. +- Headings cannot be deeper than H4 and cannot skip a level: an H4 must be below an H3, for example. +- If an H2 between `Examples` and `Props` contains a Canvas and is absent from `Contents`, it is reported as a likely H3 example missing one `#`. + +### Contents + +- `Contents` must contain Markdown links in the form `- [Section label](#section-anchor)`. +- Every H2 section after `Contents` must be listed once, in the same order as in the document. +- Each anchor must resolve to an existing heading. +- A link label must use the canonical sentence-case form of its section title. +- The error provides the complete replacement entry. + +### Storybook blocks + +- Every namespace stories import used by the MDX must resolve to a stories file. +- The document must contain exactly one `Meta`, referencing an imported stories namespace. +- Every `Canvas` must be self-closing and use the exact `` form. +- The Canvas namespace must be imported and the referenced story must be exported by that file; the obsolete `name` prop is rejected. +- Every `ArgTypes` must be self-closing, use a valid `of={Stories}` reference, and follow the expected single-line or Prettier-style multiline formatting. +- `ArgTypes` blocks must be inside `Props`, and `Props` must contain at least one block. +- An H3 component name is required before each ArgTypes block only when the page contains multiple blocks. + +### Examples + +- Every example Canvas must belong to an H3 example or one of that example's H4 subsections. +- An H3 may contain several Canvas blocks; it needs only one explanatory text, placed before its first Canvas or H4. +- If an H3 has no explanatory text, every H4 below it must provide its own text. +- An H3 with no H4 and no text is always an error. +- An example heading must start with `(Deprecated)` when its H3 explicitly names a deprecated prop or its prose presents a deprecated prop as an inline-code identifier, such as `` `color` ``. +- A deprecated prop merely used inside the story implementation does not mark the example as deprecated. + +### Quick start imports + +- Import statements in fenced code blocks must be valid JavaScript or TypeScript syntax. +- `Quick start` must import the documented component from `carbon-react/lib/components/...`. +- The imported module must exist. +- The first component import must belong to the component family documented by the MDX. +- Every requested default or named export must exist in that public module. + +### Deprecation + +- If the documented component has an `@deprecated` annotation, or its primary Storybook title starts with `Deprecated/`, the MDX must contain one `DeprecationWarning`. +- The warning must appear after the H1 and before the description and `Contents`. +- The warning must contain meaningful migration guidance and use the standard `deprecation-warning.component` import. +- More than one warning is an error. +- A warning that cannot be confirmed by the component or Storybook metadata is reported as a warning for manual review. diff --git a/scripts/validate-mdx/component-coverage.mjs b/scripts/validate-mdx/component-coverage.mjs new file mode 100644 index 0000000000..64c086e1ce --- /dev/null +++ b/scripts/validate-mdx/component-coverage.mjs @@ -0,0 +1,55 @@ +// @ts-check +import path from "node:path"; +import { existsSync, readdirSync } from "node:fs"; +import { MDX_COVERAGE_EXCLUSIONS } from "./config.mjs"; + +/** + * @param {string[]} componentFolders + * @param {string[]} mdxFiles + * @param {string} componentsDir + * @param {Set} [exclusions] + */ +export function findMissingMdxFolders( + componentFolders, + mdxFiles, + componentsDir, + exclusions = MDX_COVERAGE_EXCLUSIONS, +) { + const coveredFolders = new Set( + mdxFiles + .map((filePath) => path.relative(componentsDir, filePath)) + .filter((relativePath) => !relativePath.startsWith(`..${path.sep}`)) + .map((relativePath) => relativePath.split(path.sep)[0]), + ); + return componentFolders + .filter((folder) => !exclusions.has(folder)) + .filter((folder) => !coveredFolders.has(folder)) + .sort(); +} + +/** @param {string} folderPath */ +function diagnosticPath(folderPath) { + for (const indexFile of ["index.ts", "index.tsx", "index.js", "index.jsx"]) { + const candidate = path.join(folderPath, indexFile); + if (existsSync(candidate)) return candidate; + } + return folderPath; +} + +/** @param {string} repoRoot @param {string[]} mdxFiles */ +export default function validateComponentCoverage(repoRoot, mdxFiles) { + const componentsDir = path.join(repoRoot, "src", "components"); + const componentFolders = readdirSync(componentsDir, { withFileTypes: true }) + .filter((entry) => entry.isDirectory()) + .map((entry) => entry.name); + return findMissingMdxFolders(componentFolders, mdxFiles, componentsDir).map( + (folder) => ({ + filePath: diagnosticPath(path.join(componentsDir, folder)), + rule: "coverage/missing-mdx", + message: `Component folder “${folder}” must contain at least one non-internal MDX file or be added to MDX_COVERAGE_EXCLUSIONS with a documented reason.`, + severity: "error", + line: 1, + column: 1, + }), + ); +} diff --git a/scripts/validate-mdx/component-coverage.test.mjs b/scripts/validate-mdx/component-coverage.test.mjs new file mode 100644 index 0000000000..15d42a234a --- /dev/null +++ b/scripts/validate-mdx/component-coverage.test.mjs @@ -0,0 +1,31 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import path from "node:path"; +import { findMissingMdxFolders } from "./component-coverage.mjs"; + +const componentsDir = path.resolve("/virtual/src/components"); + +test("requires one MDX per top-level component folder", () => { + const missing = findMissingMdxFolders( + ["button", "select", "undocumented"], + [ + path.join(componentsDir, "button", "button.mdx"), + path.join(componentsDir, "select", "simple-select", "simple-select.mdx"), + ], + componentsDir, + new Set(), + ); + + assert.deepEqual(missing, ["undocumented"]); +}); + +test("allows explicitly excluded component folders", () => { + const missing = findMissingMdxFolders( + ["documented", "covered-elsewhere"], + [path.join(componentsDir, "documented", "documented.mdx")], + componentsDir, + new Set(["covered-elsewhere"]), + ); + + assert.deepEqual(missing, []); +}); diff --git a/scripts/validate-mdx/config.mjs b/scripts/validate-mdx/config.mjs new file mode 100644 index 0000000000..8e7104587a --- /dev/null +++ b/scripts/validate-mdx/config.mjs @@ -0,0 +1,29 @@ +// @ts-check + +export const DEFAULT_MDX_GLOBS = ["src/components/**/*.mdx"]; +export const DEFAULT_MDX_IGNORES = ["**/__internal__/**", "**/node_modules/**"]; + +// These top-level component folders are intentionally documented elsewhere or +// do not require their own component MDX. +export const MDX_COVERAGE_EXCLUSIONS = new Set([ + "dialog-full-screen", + "i18n-provider", + "modal", +]); + +export const REQUIRED_SECTIONS = [ + "Contents", + "Quick start", + "Examples", + "Props", +]; + +export const CATEGORIES = new Set([ + "Actions", + "Feedback", + "Inputs", + "Modal", + "Navigation", + "Other", + "UI presentation", +]); diff --git a/scripts/validate-mdx/diagnostics.mjs b/scripts/validate-mdx/diagnostics.mjs new file mode 100644 index 0000000000..6052096c79 --- /dev/null +++ b/scripts/validate-mdx/diagnostics.mjs @@ -0,0 +1,25 @@ +// @ts-check +import { locationAt } from "./utils.mjs"; + +/** + * @param {ReturnType} document + * @param {string} rule + * @param {string} message + * @param {number} [index] + * @param {'error' | 'warning'} [severity] + */ +export default function diagnostic( + document, + rule, + message, + index = 0, + severity = "error", +) { + return { + filePath: document.filePath, + rule, + message, + severity, + ...locationAt(document.content, index), + }; +} diff --git a/scripts/validate-mdx/index.mjs b/scripts/validate-mdx/index.mjs new file mode 100644 index 0000000000..936faf04c0 --- /dev/null +++ b/scripts/validate-mdx/index.mjs @@ -0,0 +1,98 @@ +#!/usr/bin/env node +// @ts-check +import path from "node:path"; +import fs from "node:fs/promises"; +import { existsSync, statSync } from "node:fs"; +import { fileURLToPath } from "node:url"; +import fg from "fast-glob"; +import validateComponentCoverage from "./component-coverage.mjs"; +import { DEFAULT_MDX_GLOBS, DEFAULT_MDX_IGNORES } from "./config.mjs"; +import SourceInspector from "./source-inspector.mjs"; +import validateMdx from "./validator.mjs"; + +const scriptDir = path.dirname(fileURLToPath(import.meta.url)); +const repoRoot = path.resolve(scriptDir, "../.."); +const args = process.argv.slice(2); +const json = args.includes("--json"); +const help = args.includes("--help") || args.includes("-h"); +const patterns = args.filter((arg) => !arg.startsWith("--")); + +if (help) { + process.stdout.write(`Validate Carbon component MDX documentation. + +Usage: + npm run validate:mdx + npm run validate:mdx -- src/components/pill/pill.mdx + npm run validate:mdx -- 'src/components/{pill,pager}/*.mdx' + npm run validate:mdx -- --json + +Missing sections are reported but never created automatically.\n`); + process.exit(0); +} + +const directFiles = patterns + .map((entry) => path.resolve(repoRoot, entry)) + .filter((entry) => existsSync(entry) && statSync(entry).isFile()); +const globPatterns = patterns.filter( + (entry) => !directFiles.includes(path.resolve(repoRoot, entry)), +); +const discovered = fg.sync( + globPatterns.length ? globPatterns : patterns.length ? [] : DEFAULT_MDX_GLOBS, + { + cwd: repoRoot, + absolute: true, + onlyFiles: true, + ignore: patterns.length ? [] : DEFAULT_MDX_IGNORES, + }, +); +const files = [...new Set([...directFiles, ...discovered])].sort(); + +if (!files.length) { + process.stderr.write("No MDX files matched the provided paths.\n"); + process.exit(2); +} + +const inspector = new SourceInspector(repoRoot); +const diagnostics = patterns.length + ? [] + : validateComponentCoverage(repoRoot, files); +for (const filePath of files) { + const content = await fs.readFile(filePath, "utf8"); + diagnostics.push(...validateMdx(content, filePath, inspector)); +} +diagnostics.sort( + (a, b) => + a.filePath.localeCompare(b.filePath) || + a.line - b.line || + a.column - b.column || + a.rule.localeCompare(b.rule), +); + +const errors = diagnostics.filter(({ severity }) => severity === "error"); +const warnings = diagnostics.filter(({ severity }) => severity === "warning"); +if (json) { + process.stdout.write( + JSON.stringify( + { + files: files.length, + errors: errors.length, + warnings: warnings.length, + diagnostics, + }, + null, + 2, + ) + "\n", + ); +} else { + for (const item of diagnostics) { + const relative = path.relative(repoRoot, item.filePath); + process.stdout.write( + `${relative}:${item.line}:${item.column} ${item.severity} ${item.rule} ${item.message}\n`, + ); + } + process.stdout.write( + `Validated ${files.length} MDX file${files.length === 1 ? "" : "s"}: ${errors.length} error${errors.length === 1 ? "" : "s"}, ${warnings.length} warning${warnings.length === 1 ? "" : "s"}.\n`, + ); +} + +process.exitCode = errors.length ? 1 : 0; diff --git a/scripts/validate-mdx/parse-mdx.mjs b/scripts/validate-mdx/parse-mdx.mjs new file mode 100644 index 0000000000..21a0ffb48d --- /dev/null +++ b/scripts/validate-mdx/parse-mdx.mjs @@ -0,0 +1,233 @@ +// @ts-check +import ts from "typescript"; +import { + findSelfClosingTags, + headingAnchor, + maskCodeFences, + plainText, +} from "./utils.mjs"; + +/** + * @typedef {{level: number, title: string, index: number, end: number, line: number, parent: Heading | null}} Heading + * @typedef {{title: string, heading: Heading, start: number, end: number, content: string}} Section + * @typedef {{alias: string, source: string, index: number}} StoryImport + */ + +/** + * @param {string} content + * @param {string} filePath + */ +export function parseMdxDocument(content, filePath) { + const masked = maskCodeFences(content); + /** @type {Heading[]} */ + const headings = []; + /** @type {Heading[]} */ + const stack = []; + const headingRegex = /^(#{1,6})[ \t]+(.+?)[ \t]*$/gm; + let headingMatch; + while ((headingMatch = headingRegex.exec(masked)) !== null) { + const level = headingMatch[1].length; + while (stack.length && stack.at(-1).level >= level) stack.pop(); + const heading = { + level, + title: content + .slice( + headingMatch.index + headingMatch[1].length, + headingRegex.lastIndex, + ) + .trim(), + index: headingMatch.index, + end: headingRegex.lastIndex, + line: content.slice(0, headingMatch.index).split("\n").length, + parent: stack.at(-1) ?? null, + }; + headings.push(heading); + stack.push(heading); + } + + const h2s = headings.filter((heading) => heading.level === 2); + /** @type {Section[]} */ + const sections = h2s.map((heading, index) => { + const end = h2s[index + 1]?.index ?? content.length; + return { + title: heading.title, + heading, + start: heading.end, + end, + content: content.slice(heading.end, end).trim(), + }; + }); + + /** @type {StoryImport[]} */ + const storyImports = []; + const storyImportRegex = + /^import\s+\*\s+as\s+([A-Za-z_$][\w$]*)\s+from\s+["']([^"']+\.stories(?:\.[^"']+)*)["'];?/gm; + let importMatch; + while ((importMatch = storyImportRegex.exec(masked)) !== null) { + storyImports.push({ + alias: importMatch[1], + source: importMatch[2], + index: importMatch.index, + }); + } + const defaultStoryImportRegex = + /^import\s+([A-Za-z_$][\w$]*)\s+from\s+["']([^"']+\.stories(?:\.[^"']+)*)["'];?/gm; + while ((importMatch = defaultStoryImportRegex.exec(masked)) !== null) { + if (!storyImports.some(({ alias }) => alias === importMatch[1])) { + storyImports.push({ + alias: importMatch[1], + source: importMatch[2], + index: importMatch.index, + }); + } + } + + const categoryMatches = [ + ...content.matchAll(/^\*\*Category:\*\*[ \t]*(.+?)[ \t]*$/gm), + ].map((match) => ({ + value: match[1].trim(), + index: match.index, + })); + + const h1 = headings.find((heading) => heading.level === 1) ?? null; + const contentsSection = sections.find( + (section) => section.title.toLowerCase() === "contents", + ); + const descriptionRegion = h1 + ? content.slice(h1.end, contentsSection?.heading.index ?? content.length) + : ""; + const description = plainText( + descriptionRegion + .replace( + /]*>[\s\S]*?<\/DeprecationWarning>/g, + " ", + ) + .replace(/]*>[\s\S]*?Product Design System[\s\S]*?<\/a>/gi, " ") + .replace(/^\*\*Category:\*\*.*$/gm, " "), + ); + + const tocEntries = []; + if (contentsSection) { + const tocRegex = /^(\s*)-\s+\[([^\]]+)\]\(#([^)]+)\)\s*$/gm; + let tocMatch; + while ((tocMatch = tocRegex.exec(contentsSection.content)) !== null) { + const absoluteIndex = contentsSection.start + tocMatch.index; + tocEntries.push({ + indent: tocMatch[1].length, + label: tocMatch[2].trim(), + anchor: tocMatch[3].trim(), + index: absoluteIndex, + }); + } + } + + return { + filePath, + content, + masked, + headings, + sections, + storyImports, + categoryMatches, + description, + tocEntries, + canvasTags: findSelfClosingTags(masked, "Canvas"), + argTypesTags: findSelfClosingTags(masked, "ArgTypes"), + metaTags: findSelfClosingTags(masked, "Meta"), + deprecationTags: [ + ...masked.matchAll( + /]*>[\s\S]*?<\/DeprecationWarning>/g, + ), + ].map((match) => ({ + raw: content.slice(match.index, match.index + match[0].length), + index: match.index, + end: match.index + match[0].length, + })), + section(title) { + return sections.find((section) => section.title === title) ?? null; + }, + sectionAt(index) { + return ( + sections.find( + (section) => index >= section.heading.index && index < section.end, + ) ?? null + ); + }, + headingBefore(index, minimumIndex = 0) { + return ( + headings + .filter( + (heading) => heading.index >= minimumIndex && heading.index < index, + ) + .at(-1) ?? null + ); + }, + headingByAnchor(anchor) { + return headings.find( + (heading) => headingAnchor(heading.title) === anchor, + ); + }, + }; +} + +/** + * Parse imports from fenced Quick start snippets with TypeScript's parser. + * @param {string} sectionContent + */ +export function parseQuickStartImports(sectionContent) { + const imports = []; + const parseErrors = []; + const fenceRegex = /```(?:js|javascript|jsx|ts|tsx)?\s*\n([\s\S]*?)```/g; + let fenceMatch; + while ((fenceMatch = fenceRegex.exec(sectionContent)) !== null) { + const code = fenceMatch[1]; + const sourceFile = ts.createSourceFile( + "quick-start.tsx", + code, + ts.ScriptTarget.Latest, + true, + ts.ScriptKind.TSX, + ); + if (/^\s*import\s/m.test(code)) { + for (const diagnostic of sourceFile.parseDiagnostics) { + parseErrors.push({ + message: ts.flattenDiagnosticMessageText(diagnostic.messageText, " "), + index: fenceMatch.index + (diagnostic.start ?? 0), + }); + } + } + sourceFile.forEachChild((node) => { + if ( + !ts.isImportDeclaration(node) || + !ts.isStringLiteral(node.moduleSpecifier) + ) { + return; + } + const clause = node.importClause; + const named = []; + let namespace = null; + if (clause?.namedBindings && ts.isNamedImports(clause.namedBindings)) { + for (const element of clause.namedBindings.elements) { + named.push({ + imported: element.propertyName?.text ?? element.name.text, + local: element.name.text, + typeOnly: clause.isTypeOnly || element.isTypeOnly, + }); + } + } else if ( + clause?.namedBindings && + ts.isNamespaceImport(clause.namedBindings) + ) { + namespace = clause.namedBindings.name.text; + } + imports.push({ + source: node.moduleSpecifier.text, + defaultImport: clause?.name?.text ?? null, + named, + namespace, + index: fenceMatch.index + node.getStart(sourceFile), + }); + }); + } + return { imports, parseErrors }; +} diff --git a/scripts/validate-mdx/rules/contents.mjs b/scripts/validate-mdx/rules/contents.mjs new file mode 100644 index 0000000000..a5e1b64c31 --- /dev/null +++ b/scripts/validate-mdx/rules/contents.mjs @@ -0,0 +1,108 @@ +// @ts-check +import diagnostic from "../diagnostics.mjs"; +import { + findLikelyMisleveledExampleHeadings, + headingAnchor, + sectionSentenceCase, +} from "../utils.mjs"; + +/** @param {string} title */ +function canonicalLabel(title) { + return sectionSentenceCase(title); +} + +/** @param {ReturnType} document */ +export default function validateContents(document) { + const diagnostics = []; + const contents = document.section("Contents"); + if (!contents) return diagnostics; + if (!document.tocEntries.length) { + diagnostics.push( + diagnostic( + document, + "contents/empty", + "Contents must contain Markdown links to the document sections.", + contents.start, + ), + ); + return diagnostics; + } + + const seenAnchors = new Set(); + for (const entry of document.tocEntries) { + const heading = document.headingByAnchor(entry.anchor); + if (!heading) { + diagnostics.push( + diagnostic( + document, + "contents/broken-link", + `Contents entry “${entry.label}” points to missing #${entry.anchor}.`, + entry.index, + ), + ); + continue; + } + const expectedLabel = canonicalLabel(heading.title); + if (entry.label !== expectedLabel) { + diagnostics.push( + diagnostic( + document, + "contents/label", + `Contents label “${entry.label}” does not use the canonical capitalization “${expectedLabel}”. Replace it with “- [${expectedLabel}](#${entry.anchor})”.`, + entry.index, + ), + ); + } + if (seenAnchors.has(entry.anchor)) { + diagnostics.push( + diagnostic( + document, + "contents/duplicate-entry", + `Contents contains duplicate #${entry.anchor}.`, + entry.index, + ), + ); + } + seenAnchors.add(entry.anchor); + } + + const likelyMisleveledExamples = new Set( + findLikelyMisleveledExampleHeadings(document), + ); + const expectedH2 = document.sections + .filter(({ title }) => title !== "Contents") + .map(({ heading }) => heading) + .filter((heading) => !likelyMisleveledExamples.has(heading)); + for (const heading of expectedH2) { + const anchor = headingAnchor(heading.title); + if (!seenAnchors.has(anchor)) { + const label = canonicalLabel(heading.title); + diagnostics.push( + diagnostic( + document, + "contents/missing-entry", + `Add “- [${label}](#${anchor})” to Contents.`, + contents.start, + ), + ); + } + } + + const actualH2Order = document.tocEntries + .map((entry) => document.headingByAnchor(entry.anchor)) + .filter((heading) => heading?.level === 2 && heading.title !== "Contents") + .map((heading) => heading.index); + if ( + actualH2Order.some((index, position) => index < actualH2Order[position - 1]) + ) { + diagnostics.push( + diagnostic( + document, + "contents/order", + "Contents entries must follow the same order as the document sections.", + contents.start, + ), + ); + } + return diagnostics; +} diff --git a/scripts/validate-mdx/rules/deprecation.mjs b/scripts/validate-mdx/rules/deprecation.mjs new file mode 100644 index 0000000000..946cf3c3b2 --- /dev/null +++ b/scripts/validate-mdx/rules/deprecation.mjs @@ -0,0 +1,112 @@ +// @ts-check +import diagnostic from "../diagnostics.mjs"; +import { plainText } from "../utils.mjs"; + +/** + * @param {ReturnType} document + * @param {import('../source-inspector.mjs').default} inspector + * @param {Array<{source: string, defaultImport: string | null, named: Array<{imported: string, typeOnly?: boolean}>, namespace: string | null}>} componentImports + */ +export default function validateDeprecation( + document, + inspector, + componentImports, +) { + const diagnostics = []; + const primaryStoryAlias = document.metaTags[0]?.raw.match( + /\b(?:of|component)=\{([A-Za-z_$][\w$]*)\}/, + )?.[1]; + const primaryStoryImports = primaryStoryAlias + ? document.storyImports.filter(({ alias }) => alias === primaryStoryAlias) + : document.storyImports.slice(0, 1); + const deprecatedFromStories = primaryStoryImports.some((storyImport) => { + const storyPath = inspector.resolveStory( + document.filePath, + storyImport.source, + ); + return storyPath ? inspector.isDeprecatedStory(storyPath) : false; + }); + // The first component import is the documented module. Later imports are + // supporting components and must not mark the page itself as deprecated. + const deprecatedFromComponent = componentImports[0] + ? Boolean(inspector.inspectComponentImport(componentImports[0])?.deprecated) + : false; + const shouldBeDeprecated = deprecatedFromStories || deprecatedFromComponent; + const hasWarning = document.deprecationTags.length > 0; + + if (shouldBeDeprecated && !hasWarning) { + diagnostics.push( + diagnostic( + document, + "deprecation/missing-warning", + "Code marks this component as deprecated; add a DeprecationWarning after the H1.", + document.headings.find(({ level }) => level === 1)?.end ?? 0, + ), + ); + } + if (document.deprecationTags.length > 1) { + diagnostics.push( + diagnostic( + document, + "deprecation/count", + "Use exactly one DeprecationWarning block.", + document.deprecationTags[1].index, + ), + ); + } + for (const warning of document.deprecationTags) { + if (plainText(warning.raw).length < 20) { + diagnostics.push( + diagnostic( + document, + "deprecation/text", + "DeprecationWarning must explain the deprecation and recommended migration.", + warning.index, + ), + ); + } + const h1 = document.headings.find(({ level }) => level === 1); + const contents = document.section("Contents"); + if ( + (h1 && warning.index < h1.end) || + (contents && warning.index > contents.heading.index) + ) { + diagnostics.push( + diagnostic( + document, + "deprecation/position", + "Place DeprecationWarning after the H1 and before the description and Contents.", + warning.index, + ), + ); + } + } + if (hasWarning) { + const hasImport = new RegExp( + "^import\\s+DeprecationWarning\\s+from\\s+[\"'][^\"']*deprecation-warning\\.component[\"'];?$", + "m", + ).test(document.masked); + if (!hasImport) { + diagnostics.push( + diagnostic( + document, + "deprecation/import", + "Import DeprecationWarning from .storybook/utils/deprecation-warning.component.", + document.deprecationTags[0].index, + ), + ); + } + if (!shouldBeDeprecated) { + diagnostics.push( + diagnostic( + document, + "deprecation/unverified", + "DeprecationWarning is present, but no component-level @deprecated annotation or Deprecated/ story title was detected.", + document.deprecationTags[0].index, + "warning", + ), + ); + } + } + return diagnostics; +} diff --git a/scripts/validate-mdx/rules/examples.mjs b/scripts/validate-mdx/rules/examples.mjs new file mode 100644 index 0000000000..a6d1e08e4d --- /dev/null +++ b/scripts/validate-mdx/rules/examples.mjs @@ -0,0 +1,176 @@ +// @ts-check +import diagnostic from "../diagnostics.mjs"; +import { plainText } from "../utils.mjs"; + +/** @param {string} value */ +function escapeRegExp(value) { + return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} + +/** @param {string} title @param {string} prop */ +function headingMentionsProp(title, prop) { + const escaped = escapeRegExp(prop); + return new RegExp( + `(^|[^\\p{L}\\p{N}_$-])${escaped}($|[^\\p{L}\\p{N}_$-])`, + "u", + ).test(title.replace(/\(Deprecated\)/g, "")); +} + +/** @param {string} content */ +function inlineCodeIdentifiers(content) { + const identifiers = new Set(); + const withoutFences = content.replace(/```[\s\S]*?```/g, ""); + for (const match of withoutFences.matchAll(/(?} document + * @param {import('../source-inspector.mjs').default} inspector + */ +export default function validateExamples(document, inspector) { + const diagnostics = []; + const examples = document.section("Examples"); + if (!examples) return diagnostics; + + const exampleHeadings = document.headings.filter( + ({ level, index }) => + level === 3 && index >= examples.heading.end && index < examples.end, + ); + const canvases = document.canvasTags.filter( + ({ index }) => index >= examples.heading.end && index < examples.end, + ); + const storySources = new Map( + document.storyImports.map(({ alias, source }) => [ + alias, + inspector.resolveStory(document.filePath, source), + ]), + ); + + for (const [headingIndex, heading] of exampleHeadings.entries()) { + const blockEnd = exampleHeadings[headingIndex + 1]?.index ?? examples.end; + const childHeadings = document.headings.filter( + ({ level, index }) => + level === 4 && index > heading.end && index < blockEnd, + ); + const firstChild = childHeadings[0]; + const firstDirectCanvas = canvases.find( + ({ index }) => index > heading.end && index < blockEnd, + ); + const descriptionEnd = Math.min( + firstChild?.index ?? blockEnd, + firstDirectCanvas?.index ?? blockEnd, + ); + const description = plainText( + document.content.slice(heading.end, descriptionEnd), + ); + + const deprecatedProps = new Set(); + for (const canvas of canvases.filter( + ({ index }) => index > heading.end && index < blockEnd, + )) { + const alias = canvas.raw.match( + //, + )?.[1]; + const storySource = alias ? storySources.get(alias) : null; + if (!storySource) continue; + for (const prop of inspector.deprecatedPropsForStory(storySource)) { + deprecatedProps.add(prop); + } + } + const inlineIdentifiers = inlineCodeIdentifiers( + document.content.slice(heading.end, blockEnd), + ); + const presentedDeprecatedProps = [...deprecatedProps].filter( + (prop) => + inlineIdentifiers.has(prop) || headingMentionsProp(heading.title, prop), + ); + if ( + presentedDeprecatedProps.length && + !heading.title.includes("(Deprecated)") + ) { + diagnostics.push( + diagnostic( + document, + "examples/deprecated-prop", + `Example “${heading.title}” explicitly presents deprecated ${presentedDeprecatedProps.length > 1 ? "props" : "prop"} ${presentedDeprecatedProps.map((prop) => `“${prop}”`).join(", ")}. Prefix the heading with “(Deprecated)”: “### (Deprecated) ${heading.title}”.`, + heading.index, + ), + ); + } + + // A description on the H3 covers every Canvas and H4 in the example. + if (description) continue; + + if (!childHeadings.length || firstDirectCanvas?.index < firstChild?.index) { + diagnostics.push( + diagnostic( + document, + "examples/description", + `Add a short text below “### ${heading.title}” explaining when or why to use this example.`, + heading.index, + ), + ); + } + + // Without an H3 description, every H4 must provide its own text. + for (const [childIndex, childHeading] of childHeadings.entries()) { + const childBlockEnd = childHeadings[childIndex + 1]?.index ?? blockEnd; + const firstChildCanvas = canvases.find( + ({ index }) => index > childHeading.end && index < childBlockEnd, + ); + const childDescription = plainText( + document.content.slice( + childHeading.end, + firstChildCanvas?.index ?? childBlockEnd, + ), + ); + if (!childDescription) { + diagnostics.push( + diagnostic( + document, + "examples/description", + `Add a short text below “#### ${childHeading.title}” because its parent “### ${heading.title}” has no description.`, + childHeading.index, + ), + ); + } + } + } + + for (const canvas of canvases) { + const heading = document.headingBefore(canvas.index, examples.heading.end); + if (!heading || heading.level < 3 || heading.level > 4) { + diagnostics.push( + diagnostic( + document, + "examples/heading", + "Each example Canvas must belong to an H3 example or one of its H4 subsections.", + canvas.index, + ), + ); + } + const parentExample = + heading?.level === 3 + ? heading + : heading?.parent?.level === 3 + ? heading.parent + : null; + if (!parentExample) { + diagnostics.push( + diagnostic( + document, + "examples/heading", + "Each example Canvas must ultimately belong to an H3 example.", + canvas.index, + ), + ); + } + } + return diagnostics; +} diff --git a/scripts/validate-mdx/rules/metadata.mjs b/scripts/validate-mdx/rules/metadata.mjs new file mode 100644 index 0000000000..78a8c25e06 --- /dev/null +++ b/scripts/validate-mdx/rules/metadata.mjs @@ -0,0 +1,65 @@ +// @ts-check +import { CATEGORIES } from "../config.mjs"; +import { extractDescription } from "../../skills/mdx-parser.mjs"; +import diagnostic from "../diagnostics.mjs"; +import { plainText } from "../utils.mjs"; + +/** @param {ReturnType} document */ +export default function validateMetadata(document) { + const diagnostics = []; + const h1 = document.headings.find(({ level }) => level === 1); + const buildSkillsDescription = plainText( + extractDescription(document.content), + ); + if (!buildSkillsDescription) { + const categoryBeforeDescription = + document.categoryMatches.length === 1 && Boolean(document.description); + diagnostics.push( + diagnostic( + document, + categoryBeforeDescription + ? "metadata/description-order" + : "metadata/description", + categoryBeforeDescription + ? "The component description must be placed before “**Category:**”." + : "Add a component description before “**Category:**” and Contents.", + document.categoryMatches[0]?.index ?? h1?.end ?? 0, + ), + ); + } + + if (document.categoryMatches.length !== 1) { + diagnostics.push( + diagnostic( + document, + "metadata/category", + `Expected exactly one “**Category:**” declaration, found ${document.categoryMatches.length}.`, + document.categoryMatches[1]?.index ?? h1?.end ?? 0, + ), + ); + } else { + const category = document.categoryMatches[0]; + if (!CATEGORIES.has(category.value)) { + diagnostics.push( + diagnostic( + document, + "metadata/category-value", + `Unknown category “${category.value}”. Use one of: ${[...CATEGORIES].join(", ")}.`, + category.index, + ), + ); + } + const contents = document.section("Contents"); + if (contents && category.index > contents.heading.index) { + diagnostics.push( + diagnostic( + document, + "metadata/category-position", + "Place the category after the component description and before Contents.", + category.index, + ), + ); + } + } + return diagnostics; +} diff --git a/scripts/validate-mdx/rules/quick-start.mjs b/scripts/validate-mdx/rules/quick-start.mjs new file mode 100644 index 0000000000..7220a6a481 --- /dev/null +++ b/scripts/validate-mdx/rules/quick-start.mjs @@ -0,0 +1,86 @@ +// @ts-check +import path from "node:path"; +import diagnostic from "../diagnostics.mjs"; +import { parseQuickStartImports } from "../parse-mdx.mjs"; + +/** @param {string} filePath */ +function componentRootName(filePath) { + const parts = path.normalize(filePath).split(path.sep); + const componentsIndex = parts.lastIndexOf("components"); + return componentsIndex >= 0 + ? parts[componentsIndex + 1] + : path.basename(path.dirname(filePath)); +} + +/** + * @param {ReturnType} document + * @param {import('../source-inspector.mjs').default} inspector + */ +export default function validateQuickStart(document, inspector) { + const diagnostics = []; + const quickStart = document.section("Quick start"); + if (!quickStart) return { diagnostics, componentImports: [] }; + const { imports, parseErrors } = parseQuickStartImports(quickStart.content); + for (const error of parseErrors) { + diagnostics.push( + diagnostic( + document, + "quick-start/syntax", + `Quick start code cannot be parsed: ${error.message}`, + quickStart.start + error.index, + ), + ); + } + const componentImports = imports.filter(({ source }) => + source.startsWith("carbon-react/lib/components/"), + ); + if (!componentImports.length) { + diagnostics.push( + diagnostic( + document, + "quick-start/import", + "Quick start must import the documented component from carbon-react/lib/components/…", + quickStart.start, + ), + ); + } + for (const [importIndex, importInfo] of componentImports.entries()) { + const result = inspector.inspectComponentImport(importInfo); + if (!result?.sourcePath) { + diagnostics.push( + diagnostic( + document, + "quick-start/module", + `Component module “${importInfo.source}” does not resolve in src/components.`, + quickStart.start + importInfo.index, + ), + ); + continue; + } + if ( + importIndex === 0 && + componentRootName(result.sourcePath) !== + componentRootName(document.filePath) + ) { + diagnostics.push( + diagnostic( + document, + "quick-start/component-module", + `The first component import must document this component family, not “${importInfo.source}”.`, + quickStart.start + importInfo.index, + ), + ); + } + if (result.missingExports.length) { + diagnostics.push( + diagnostic( + document, + "quick-start/export", + `Import references missing public export${result.missingExports.length > 1 ? "s" : ""}: ${result.missingExports.join(", ")}.`, + quickStart.start + importInfo.index, + ), + ); + } + } + return { diagnostics, componentImports }; +} diff --git a/scripts/validate-mdx/rules/storybook.mjs b/scripts/validate-mdx/rules/storybook.mjs new file mode 100644 index 0000000000..9bb75f1a3f --- /dev/null +++ b/scripts/validate-mdx/rules/storybook.mjs @@ -0,0 +1,199 @@ +// @ts-check +import diagnostic from "../diagnostics.mjs"; + +/** + * @param {ReturnType} document + * @param {import('../source-inspector.mjs').default} inspector + */ +export default function validateStorybookBlocks(document, inspector) { + const diagnostics = []; + const aliases = new Map(); + for (const storyImport of document.storyImports) { + const sourcePath = inspector.resolveStory( + document.filePath, + storyImport.source, + ); + aliases.set(storyImport.alias, sourcePath); + if (!sourcePath) { + diagnostics.push( + diagnostic( + document, + "storybook/story-import", + `Cannot resolve stories import “${storyImport.source}”.`, + storyImport.index, + ), + ); + } + } + + const rawCanvasCount = (document.masked.match(/$/, + ); + if (!match) { + const detail = /\bname\s*=/.test(canvas.raw) + ? " Remove the name prop; the story export already identifies the example." + : ""; + diagnostics.push( + diagnostic( + document, + "storybook/canvas-format", + `Use exactly “”.${detail}`, + canvas.index, + ), + ); + continue; + } + const [, alias, exportName] = match; + const sourcePath = aliases.get(alias); + if (sourcePath === undefined) { + diagnostics.push( + diagnostic( + document, + "storybook/canvas-alias", + `Canvas references “${alias}”, which is not a namespace stories import.`, + canvas.index, + ), + ); + } else if ( + sourcePath && + !inspector.exportedNames(sourcePath).has(exportName) + ) { + diagnostics.push( + diagnostic( + document, + "storybook/canvas-story", + `Story “${alias}.${exportName}” is not exported by ${document.storyImports.find(({ alias: value }) => value === alias)?.source}.`, + canvas.index, + ), + ); + } + } + + const rawArgTypesCount = (document.masked.match(/`; + const hasExtraProps = /\b(exclude|include)=/.test(argTypes.raw); + const validFormat = hasExtraProps + ? argTypes.raw.startsWith(`") + : argTypes.raw === onlyOf; + if (!validFormat || /\bname\s*=/.test(argTypes.raw)) { + diagnostics.push( + diagnostic( + document, + "storybook/argtypes-format", + hasExtraProps + ? "Format multiline ArgTypes with Prettier-style two-space indentation and a final /> line." + : `Use exactly “${onlyOf}”.`, + argTypes.index, + ), + ); + } + if (document.sectionAt(argTypes.index)?.title !== "Props") { + diagnostics.push( + diagnostic( + document, + "storybook/argtypes-section", + "ArgTypes must be inside the Props section.", + argTypes.index, + ), + ); + } + const previousArgTypes = document.argTypesTags[argTypesIndex - 1]; + const propsStart = document.sectionAt(argTypes.index)?.heading.end ?? 0; + const heading = document.headingBefore( + argTypes.index, + previousArgTypes?.end ?? propsStart, + ); + if (document.argTypesTags.length > 1 && heading?.level !== 3) { + diagnostics.push( + diagnostic( + document, + "storybook/argtypes-heading", + "Props contains multiple ArgTypes blocks. Add an H3 component name before each block.", + argTypes.index, + ), + ); + } + } + if (document.section("Props") && !document.argTypesTags.length) { + diagnostics.push( + diagnostic( + document, + "storybook/missing-argtypes", + "Props must contain at least one ArgTypes block.", + document.section("Props").start, + ), + ); + } + + for (const meta of document.metaTags) { + const match = meta.raw.match(/\bof=\{([A-Za-z_$][\w$]*)\}/); + if (!match || !aliases.has(match[1])) { + diagnostics.push( + diagnostic( + document, + "storybook/meta", + "Meta must reference an imported stories namespace with of={Stories}.", + meta.index, + ), + ); + } + } + if (document.metaTags.length !== 1) { + diagnostics.push( + diagnostic( + document, + "storybook/meta-count", + `Expected exactly one Meta block, found ${document.metaTags.length}.`, + document.metaTags[1]?.index ?? 0, + ), + ); + } + return diagnostics; +} diff --git a/scripts/validate-mdx/rules/structure.mjs b/scripts/validate-mdx/rules/structure.mjs new file mode 100644 index 0000000000..03b71fa946 --- /dev/null +++ b/scripts/validate-mdx/rules/structure.mjs @@ -0,0 +1,121 @@ +// @ts-check +import { REQUIRED_SECTIONS } from "../config.mjs"; +import diagnostic from "../diagnostics.mjs"; +import { + findLikelyMisleveledExampleHeadings, + sectionSentenceCase, +} from "../utils.mjs"; + +/** @param {string} title */ +function canonicalSectionName(title) { + return sectionSentenceCase(title); +} + +/** @param {ReturnType} document */ +export default function validateStructure(document) { + const diagnostics = []; + const h1s = document.headings.filter(({ level }) => level === 1); + if (h1s.length !== 1) { + diagnostics.push( + diagnostic( + document, + "structure/h1", + `Expected exactly one component H1, found ${h1s.length}.`, + h1s[1]?.index ?? 0, + ), + ); + } + + for (const heading of document.headings) { + if (heading.level > 4) { + diagnostics.push( + diagnostic( + document, + "structure/heading-depth", + `Heading level H${heading.level} is not supported; use H4 or above.`, + heading.index, + ), + ); + } + if (heading.level > 1 && heading.parent?.level !== heading.level - 1) { + diagnostics.push( + diagnostic( + document, + "structure/heading-hierarchy", + `H${heading.level} “${heading.title}” must be nested below an H${heading.level - 1}.`, + heading.index, + ), + ); + } + } + + const canonicalSeen = new Map(); + for (const section of document.sections) { + const canonical = canonicalSectionName(section.title); + if (canonical && section.title !== canonical) { + diagnostics.push( + diagnostic( + document, + "structure/section-name", + `Rename section “${section.title}” to the canonical “${canonical}”.`, + section.heading.index, + ), + ); + } + if (canonicalSeen.has(canonical)) { + diagnostics.push( + diagnostic( + document, + "structure/duplicate-section", + `Section “${section.title}” is duplicated.`, + section.heading.index, + ), + ); + } + canonicalSeen.set(canonical, section); + } + + for (const required of REQUIRED_SECTIONS) { + if (!canonicalSeen.has(required)) { + diagnostics.push( + diagnostic( + document, + "structure/missing-section", + `Add the required “## ${required}” section and its content.`, + h1s[0]?.index ?? 0, + ), + ); + } + } + + for (const heading of findLikelyMisleveledExampleHeadings(document)) { + diagnostics.push( + diagnostic( + document, + "structure/example-heading-level", + `“## ${heading.title}” looks like an example heading missing one “#”. Use “### ${heading.title}”.`, + heading.index, + ), + ); + } + + let previousOrder = -1; + for (const section of document.sections) { + const canonical = canonicalSectionName(section.title); + const order = REQUIRED_SECTIONS.indexOf(canonical); + if (order === -1) continue; + if (order < previousOrder) { + diagnostics.push( + diagnostic( + document, + "structure/section-order", + `Section “${section.title}” is out of order. Follow the standard ${REQUIRED_SECTIONS.join(" → ")} flow.`, + section.heading.index, + ), + ); + } else { + previousOrder = order; + } + } + return diagnostics; +} diff --git a/scripts/validate-mdx/source-inspector.mjs b/scripts/validate-mdx/source-inspector.mjs new file mode 100644 index 0000000000..f894ebdb37 --- /dev/null +++ b/scripts/validate-mdx/source-inspector.mjs @@ -0,0 +1,217 @@ +// @ts-check +import path from "node:path"; +import { existsSync, statSync } from "node:fs"; +import { Project } from "ts-morph"; + +const SOURCE_EXTENSIONS = ["", ".ts", ".tsx", ".js", ".jsx"]; + +/** @param {string} basePath */ +function resolveSourcePath(basePath) { + for (const extension of SOURCE_EXTENSIONS) { + const candidate = basePath + extension; + if (existsSync(candidate) && statSync(candidate).isFile()) return candidate; + } + for (const extension of SOURCE_EXTENSIONS.slice(1)) { + const candidate = path.join(basePath, `index${extension}`); + if (existsSync(candidate)) return candidate; + } + return null; +} + +/** @param {import('ts-morph').Node} node */ +function hasDeprecatedJsDoc(node) { + let current = node; + while (current && !current.wasForgotten()) { + if ( + "getJsDocs" in current && + typeof current.getJsDocs === "function" && + current + .getJsDocs() + .some((doc) => + doc.getTags().some((tag) => tag.getTagName() === "deprecated"), + ) + ) { + return true; + } + const parent = current.getParent(); + if (!parent || parent.getKindName() === "SourceFile") break; + current = parent; + } + return false; +} + +/** @param {import('ts-morph').Node} node */ +function hasOwnDeprecatedJsDoc(node) { + return ( + "getJsDocs" in node && + typeof node.getJsDocs === "function" && + node + .getJsDocs() + .some((doc) => + doc.getTags().some((tag) => tag.getTagName() === "deprecated"), + ) + ); +} + +/** @param {import('ts-morph').Node | undefined} node */ +function unwrapExpression(node) { + let current = node; + while ( + current && + ["AsExpression", "ParenthesizedExpression", "SatisfiesExpression"].includes( + current.getKindName(), + ) && + "getExpression" in current && + typeof current.getExpression === "function" + ) { + current = current.getExpression(); + } + return current; +} + +/** @param {import('ts-morph').Node} component */ +function deprecatedPropsFromComponent(component) { + const deprecatedProps = new Set(); + const type = component.getType(); + const signatures = [ + ...type.getCallSignatures(), + ...type.getConstructSignatures(), + ]; + for (const signature of signatures) { + const propsParameter = signature.getParameters()[0]; + if (!propsParameter) continue; + const propsType = propsParameter.getTypeAtLocation(component); + for (const property of propsType.getProperties()) { + if ( + property + .getDeclarations() + .some((declaration) => hasOwnDeprecatedJsDoc(declaration)) + ) { + deprecatedProps.add(property.getName()); + } + } + } + return deprecatedProps; +} + +export default class SourceInspector { + /** @param {string} repoRoot */ + constructor(repoRoot) { + this.repoRoot = repoRoot; + this.project = new Project({ + tsConfigFilePath: path.join(repoRoot, "tsconfig.json"), + skipAddingFilesFromTsConfig: true, + }); + this.project.addSourceFilesAtPaths([ + path.join(repoRoot, "src", "components", "**", "*.ts"), + path.join(repoRoot, "src", "components", "**", "*.tsx"), + ]); + this.storyDeprecatedProps = new Map(); + } + + /** @param {string} mdxPath @param {string} importSource */ + resolveStory(mdxPath, importSource) { + return resolveSourcePath(path.resolve(path.dirname(mdxPath), importSource)); + } + + /** @param {string} sourcePath */ + exportedNames(sourcePath) { + const sourceFile = + this.project.getSourceFile(sourcePath) ?? + this.project.addSourceFileAtPathIfExists(sourcePath); + return new Set(sourceFile?.getExportedDeclarations().keys() ?? []); + } + + /** @param {string} sourcePath */ + isDeprecatedStory(sourcePath) { + const sourceFile = + this.project.getSourceFile(sourcePath) ?? + this.project.addSourceFileAtPathIfExists(sourcePath); + return /\btitle\s*:\s*["'`]Deprecated\//.test( + sourceFile?.getFullText() ?? "", + ); + } + + /** @param {string} sourcePath */ + deprecatedPropsForStory(sourcePath) { + const cached = this.storyDeprecatedProps.get(sourcePath); + if (cached) return cached; + + const deprecatedProps = new Set(); + const sourceFile = + this.project.getSourceFile(sourcePath) ?? + this.project.addSourceFileAtPathIfExists(sourcePath); + const metaDeclarations = + sourceFile?.getExportedDeclarations().get("default") ?? []; + for (const declaration of metaDeclarations) { + const metaExpression = unwrapExpression( + "getInitializer" in declaration && + typeof declaration.getInitializer === "function" + ? declaration.getInitializer() + : "getExpression" in declaration && + typeof declaration.getExpression === "function" + ? declaration.getExpression() + : undefined, + ); + if ( + !metaExpression || + !("getProperty" in metaExpression) || + typeof metaExpression.getProperty !== "function" + ) { + continue; + } + const componentProperty = metaExpression.getProperty("component"); + const component = unwrapExpression( + componentProperty && + "getInitializer" in componentProperty && + typeof componentProperty.getInitializer === "function" + ? componentProperty.getInitializer() + : undefined, + ); + if (!component) continue; + for (const prop of deprecatedPropsFromComponent(component)) { + deprecatedProps.add(prop); + } + } + this.storyDeprecatedProps.set(sourcePath, deprecatedProps); + return deprecatedProps; + } + + /** + * @param {{source: string, defaultImport: string | null, named: Array<{imported: string, typeOnly?: boolean}>, namespace: string | null}} importInfo + */ + inspectComponentImport(importInfo) { + const prefix = "carbon-react/lib/components/"; + if (!importInfo.source.startsWith(prefix)) return null; + const relativeModule = importInfo.source.slice(prefix.length); + const sourcePath = resolveSourcePath( + path.join(this.repoRoot, "src", "components", relativeModule), + ); + if (!sourcePath) { + return { + sourcePath: null, + missingExports: [], + deprecated: false, + }; + } + const sourceFile = + this.project.getSourceFile(sourcePath) ?? + this.project.addSourceFileAtPathIfExists(sourcePath); + const exported = sourceFile?.getExportedDeclarations() ?? new Map(); + const requested = [ + ...(importInfo.defaultImport ? ["default"] : []), + ...importInfo.named.map(({ imported }) => imported), + ]; + const runtimeRequested = [ + ...(importInfo.defaultImport ? ["default"] : []), + ...importInfo.named + .filter(({ typeOnly }) => !typeOnly) + .map(({ imported }) => imported), + ]; + const missingExports = requested.filter((name) => !exported.has(name)); + const deprecated = runtimeRequested.some((name) => + (exported.get(name) ?? []).some(hasDeprecatedJsDoc), + ); + return { sourcePath, missingExports, deprecated }; + } +} diff --git a/scripts/validate-mdx/utils.mjs b/scripts/validate-mdx/utils.mjs new file mode 100644 index 0000000000..0837986a1b --- /dev/null +++ b/scripts/validate-mdx/utils.mjs @@ -0,0 +1,129 @@ +// @ts-check + +/** @param {string} value */ +export function normalizeWhitespace(value) { + return value.replace(/\s+/g, " ").trim(); +} + +/** @param {string} value */ +export function normalizeSectionKey(value) { + return normalizeWhitespace(value) + .toLowerCase() + .replace(/[’]/g, "'") + .replace(/[:!?]+$/g, ""); +} + +/** + * Convert a section title to sentence case: only its first character is + * uppercase. Whitespace is normalized so headings and Contents labels share + * exactly the same canonical text. + * @param {string} value + */ +export function sectionSentenceCase(value) { + const normalized = normalizeWhitespace(value).toLocaleLowerCase("en"); + return normalized + ? normalized[0].toLocaleUpperCase("en") + normalized.slice(1) + : normalized; +} + +/** + * Replace fenced code with whitespace while preserving offsets and line breaks. + * @param {string} content + */ +export function maskCodeFences(content) { + return content.replace(/```[^\n]*\n[\s\S]*?```/g, (block) => + block.replace(/[^\n]/g, " "), + ); +} + +/** + * GitHub/Storybook-compatible-enough heading anchor for the headings used here. + * @param {string} heading + */ +export function headingAnchor(heading) { + return heading + .replace(/<[^>]+>/g, "") + .replace(/[`*_~]/g, "") + .replace(/&/g, "and") + .toLowerCase() + .trim() + .replace(/[^\p{L}\p{N}\s-]/gu, "") + .replace(/\s+/g, "-") + .replace(/-+/g, "-"); +} + +/** + * @param {string} content + * @param {number} index + */ +export function locationAt(content, index) { + const before = content.slice(0, Math.max(0, index)); + const lines = before.split("\n"); + return { line: lines.length, column: lines.at(-1)?.length + 1 || 1 }; +} + +/** + * Reduce MDX/Markdown to text that can count as authored prose. + * @param {string} value + */ +export function plainText(value) { + return normalizeWhitespace( + value + .replace(/```[\s\S]*?```/g, " ") + .replace(//g, " ") + .replace(//g, " ") + .replace(//g, " ") + .replace(//g, " ") + .replace(//g, " ") + .replace(/<[^>]+>/g, " ") + .replace(/^#{1,6}\s+.*$/gm, " ") + .replace(/^import\s+.*$/gm, " ") + .replace(/\[([^\]]+)\]\([^)]+\)/g, "$1") + .replace(/[`*_~]/g, "") + .replace(/\{\s*"\s*"\s*\}/g, " ") + .replace(/&[a-zA-Z#0-9]+;/g, " "), + ); +} + +/** + * @param {string} content + * @param {string} tagName + */ +export function findSelfClosingTags(content, tagName) { + const tags = []; + const regex = new RegExp(`<${tagName}\\b[\\s\\S]*?\\/>`, "g"); + let match; + while ((match = regex.exec(content)) !== null) { + tags.push({ raw: match[0], index: match.index, end: regex.lastIndex }); + } + return tags; +} + +/** + * Infer H2 headings that are probably examples missing one `#`. A candidate + * must be between Examples and Props, be absent from Contents, and contain at + * least one Canvas. These constraints avoid guessing for legitimate sections. + * @param {ReturnType} document + */ +export function findLikelyMisleveledExampleHeadings(document) { + const examples = document.section("Examples"); + const props = document.section("Props"); + if (!examples || !props || examples.heading.index >= props.heading.index) { + return []; + } + + const tocAnchors = new Set(document.tocEntries.map(({ anchor }) => anchor)); + return document.sections + .filter( + (section) => + section.heading.index > examples.heading.index && + section.heading.index < props.heading.index && + !tocAnchors.has(headingAnchor(section.title)), + ) + .filter((section) => + document.canvasTags.some( + ({ index }) => index >= section.start && index < section.end, + ), + ) + .map(({ heading }) => heading); +} diff --git a/scripts/validate-mdx/validator.mjs b/scripts/validate-mdx/validator.mjs new file mode 100644 index 0000000000..863708f1b3 --- /dev/null +++ b/scripts/validate-mdx/validator.mjs @@ -0,0 +1,28 @@ +// @ts-check +import { parseMdxDocument } from "./parse-mdx.mjs"; +import validateContents from "./rules/contents.mjs"; +import validateDeprecation from "./rules/deprecation.mjs"; +import validateExamples from "./rules/examples.mjs"; +import validateMetadata from "./rules/metadata.mjs"; +import validateQuickStart from "./rules/quick-start.mjs"; +import validateStorybookBlocks from "./rules/storybook.mjs"; +import validateStructure from "./rules/structure.mjs"; + +/** + * @param {string} content + * @param {string} filePath + * @param {import('./source-inspector.mjs').default} inspector + */ +export default function validateMdx(content, filePath, inspector) { + const document = parseMdxDocument(content, filePath); + const quickStart = validateQuickStart(document, inspector); + return [ + ...validateStructure(document), + ...validateMetadata(document), + ...validateContents(document), + ...validateStorybookBlocks(document, inspector), + ...validateExamples(document, inspector), + ...quickStart.diagnostics, + ...validateDeprecation(document, inspector, quickStart.componentImports), + ]; +} diff --git a/scripts/validate-mdx/validator.test.mjs b/scripts/validate-mdx/validator.test.mjs new file mode 100644 index 0000000000..8efe495249 --- /dev/null +++ b/scripts/validate-mdx/validator.test.mjs @@ -0,0 +1,512 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import validateMdx from "./validator.mjs"; + +class FakeInspector { + constructor({ + storyDeprecated = false, + componentDeprecated = false, + missingExports = [], + sourcePath = "/virtual/widget/index.ts", + deprecatedProps = [], + } = {}) { + this.storyDeprecated = storyDeprecated; + this.componentDeprecated = componentDeprecated; + this.missingExports = missingExports; + this.sourcePath = sourcePath; + this.deprecatedProps = deprecatedProps; + } + + resolveStory() { + return "/virtual/widget.stories.tsx"; + } + + exportedNames() { + return new Set(["Default", "Compact"]); + } + + isDeprecatedStory() { + return this.storyDeprecated; + } + + deprecatedPropsForStory() { + return new Set(this.deprecatedProps); + } + + inspectComponentImport() { + return { + sourcePath: this.sourcePath, + missingExports: this.missingExports, + deprecated: this.componentDeprecated, + }; + } +} + +const validMdx = `import { Meta, ArgTypes, Canvas } from "@storybook/addon-docs/blocks"; +import * as WidgetStories from "./widget.stories"; + + + +# Widget + +A Widget presents useful information and supports a compact presentation. + +**Category:** UI presentation + +## Contents + +- [Quick start](#quick-start) +- [Examples](#examples) +- [Props](#props) + +## Quick start + +\`\`\`javascript +import Widget from "carbon-react/lib/components/widget"; +\`\`\` + +## Examples + +### Default + +Use this example for the standard presentation. + + + +### Sizes + +Use these examples when the available space determines the size. + + + +#### Compact + + + +## Props + +### Widget + + +`; + +test("accepts one H3 description for multiple Canvas and H4 subsections", () => { + const diagnostics = validateMdx( + validMdx, + "/virtual/widget/widget.mdx", + new FakeInspector(), + ); + assert.deepEqual(diagnostics, []); +}); + +test("reports one missing description per H3 rather than per Canvas", () => { + const content = validMdx + .replace("Use this example for the standard presentation.\n\n", "") + .replace( + "", + "\n\n", + ); + const diagnostics = validateMdx( + content, + "/virtual/widget/widget.mdx", + new FakeInspector(), + ).filter(({ rule }) => rule === "examples/description"); + + assert.equal(diagnostics.length, 1); + assert.match(diagnostics[0].message, /### Default/); +}); + +test("accepts an H3 without text when every H4 has its own text", () => { + const content = validMdx + .replace( + "Use these examples when the available space determines the size.\n\n\n\n", + "", + ) + .replace( + "#### Compact\n\n rule === "examples/description"), + false, + ); +}); + +test("reports an H4 without text when its H3 also has no text", () => { + const content = validMdx.replace( + "Use these examples when the available space determines the size.\n\n\n\n", + "", + ); + const diagnostics = validateMdx( + content, + "/virtual/widget/widget.mdx", + new FakeInspector(), + ).filter(({ rule }) => rule === "examples/description"); + + assert.equal(diagnostics.length, 1); + assert.match(diagnostics[0].message, /#### Compact/); +}); + +test("lets an H3 description cover an H4 without text", () => { + const diagnostics = validateMdx( + validMdx, + "/virtual/widget/widget.mdx", + new FakeInspector(), + ); + + assert.equal( + diagnostics.some(({ rule }) => rule === "examples/description"), + false, + ); +}); + +test("requires Deprecated when an example explicitly presents a deprecated prop", () => { + const content = validMdx.replace( + "### Default\n\nUse this example for the standard presentation.", + "### Widget with oldProp\n\nUse this example for legacy layouts.", + ); + const diagnostics = validateMdx( + content, + "/virtual/widget/widget.mdx", + new FakeInspector({ deprecatedProps: ["oldProp"] }), + ); + const deprecatedDiagnostic = diagnostics.find( + ({ rule }) => rule === "examples/deprecated-prop", + ); + + assert.match(deprecatedDiagnostic?.message ?? "", /“oldProp”/); + assert.match( + deprecatedDiagnostic?.message ?? "", + /### \(Deprecated\) Widget with oldProp/, + ); +}); + +test("requires Deprecated when example text presents a deprecated inline-code prop", () => { + const content = validMdx.replace( + "### Default\n\nUse this example for the standard presentation.", + "### Legacy layout\n\nUse the `oldProp` prop for legacy layouts.", + ); + const diagnostics = validateMdx( + content, + "/virtual/widget/widget.mdx", + new FakeInspector({ deprecatedProps: ["oldProp"] }), + ); + + assert.ok( + diagnostics.some(({ rule }) => rule === "examples/deprecated-prop"), + ); +}); + +test("does not interpret ordinary prose as a prop reference", () => { + const content = validMdx.replace( + "### Default\n\nUse this example for the standard presentation.", + "### Legacy layout\n\nUse the oldProp value for legacy layouts.", + ); + const diagnostics = validateMdx( + content, + "/virtual/widget/widget.mdx", + new FakeInspector({ deprecatedProps: ["oldProp"] }), + ); + + assert.equal( + diagnostics.some(({ rule }) => rule === "examples/deprecated-prop"), + false, + ); +}); + +test("does not deprecate an example for an unmentioned deprecated prop", () => { + const diagnostics = validateMdx( + validMdx, + "/virtual/widget/widget.mdx", + new FakeInspector({ deprecatedProps: ["implementationOnly"] }), + ); + + assert.equal( + diagnostics.some(({ rule }) => rule === "examples/deprecated-prop"), + false, + ); +}); + +test("accepts Deprecated when the text presents a deprecated inline-code prop", () => { + const content = validMdx.replace( + "### Default\n\nUse this example for the standard presentation.", + "### (Deprecated) Legacy layout\n\nUse the `oldProp` prop for legacy layouts.", + ); + const diagnostics = validateMdx( + content, + "/virtual/widget/widget.mdx", + new FakeInspector({ deprecatedProps: ["oldProp"] }), + ); + + assert.equal( + diagnostics.some(({ rule }) => rule === "examples/deprecated-prop"), + false, + ); +}); + +test("suggests a missing # for an example accidentally changed from H3 to H2", () => { + const content = validMdx.replace("### Default", "## Default"); + const diagnostics = validateMdx( + content, + "/virtual/widget/widget.mdx", + new FakeInspector(), + ); + + const headingDiagnostic = diagnostics.find( + ({ rule }) => rule === "structure/example-heading-level", + ); + assert.match(headingDiagnostic?.message ?? "", /Use “### Default”/); + assert.equal( + diagnostics.some( + ({ rule, message }) => + rule === "contents/missing-entry" && message.includes("Default"), + ), + false, + ); +}); + +test("explains how to fix a Contents label capitalization mismatch", () => { + const content = validMdx.replace( + "[Quick start](#quick-start)", + "[Quick Start](#quick-start)", + ); + const diagnostics = validateMdx( + content, + "/virtual/widget/widget.mdx", + new FakeInspector(), + ); + const labelDiagnostic = diagnostics.find( + ({ rule }) => rule === "contents/label", + ); + + assert.match( + labelDiagnostic?.message ?? "", + /canonical capitalization “Quick start”/, + ); + assert.match( + labelDiagnostic?.message ?? "", + /- \[Quick start\]\(#quick-start\)/, + ); +}); + +test("uses sentence case for the Validation states Contents suggestion", () => { + const content = validMdx + .replace( + "- [Props](#props)", + "- [Validation States](#validation-states)\n- [Props](#props)", + ) + .replace( + "## Props", + "## Validation States\n\nShows validation feedback.\n\n## Props", + ); + const diagnostics = validateMdx( + content, + "/virtual/widget/widget.mdx", + new FakeInspector(), + ); + const labelDiagnostic = diagnostics.find( + ({ rule }) => rule === "contents/label", + ); + + assert.match( + labelDiagnostic?.message ?? "", + /- \[Validation states\]\(#validation-states\)/, + ); +}); + +test("uses sentence case for every multi-word section", () => { + const sections = new Map([ + ["Related Components", "Related components"], + ["Designer Notes", "Designer notes"], + ["Interactive Demo", "Interactive demo"], + ["Basic Usage", "Basic usage"], + ]); + + for (const [titleCase, sentenceCase] of sections) { + const anchor = titleCase.toLowerCase().replaceAll(" ", "-"); + const content = validMdx + .replace( + "- [Props](#props)", + `- [${titleCase}](#${anchor})\n- [Props](#props)`, + ) + .replace( + "## Props", + `## ${titleCase}\n\nAdditional guidance.\n\n## Props`, + ); + const diagnostics = validateMdx( + content, + "/virtual/widget/widget.mdx", + new FakeInspector(), + ); + const labelDiagnostic = diagnostics.find( + ({ rule }) => rule === "contents/label", + ); + + assert.match( + labelDiagnostic?.message ?? "", + new RegExp(`- \\[${sentenceCase}\\]\\(#${anchor}\\)`), + ); + } +}); + +test("requires the component description before Category", () => { + const description = + "A Widget presents useful information and supports a compact presentation."; + const content = validMdx.replace( + `${description}\n\n**Category:** UI presentation`, + `**Category:** UI presentation\n\n${description}`, + ); + const diagnostics = validateMdx( + content, + "/virtual/widget/widget.mdx", + new FakeInspector(), + ); + const orderDiagnostic = diagnostics.find( + ({ rule }) => rule === "metadata/description-order", + ); + + assert.equal( + orderDiagnostic?.message, + "The component description must be placed before “**Category:**”.", + ); +}); + +test("accepts any non-empty component description", () => { + const content = validMdx.replace( + "A Widget presents useful information and supports a compact presentation.", + "Short.", + ); + const diagnostics = validateMdx( + content, + "/virtual/widget/widget.mdx", + new FakeInspector(), + ); + + assert.equal( + diagnostics.some(({ rule }) => rule === "metadata/description"), + false, + ); +}); + +test("accepts one ArgTypes block without an H3 heading", () => { + const content = validMdx.replace("### Widget\n\n", ""); + const diagnostics = validateMdx( + content, + "/virtual/widget/widget.mdx", + new FakeInspector(), + ); + + assert.equal( + diagnostics.some(({ rule }) => rule === "storybook/argtypes-heading"), + false, + ); +}); + +test("requires an H3 before each block when Props has multiple ArgTypes", () => { + const content = validMdx.replace( + "", + "\n\n", + ); + const diagnostics = validateMdx( + content, + "/virtual/widget/widget.mdx", + new FakeInspector(), + ).filter(({ rule }) => rule === "storybook/argtypes-heading"); + + assert.equal(diagnostics.length, 1); + assert.match(diagnostics[0].message, /multiple ArgTypes blocks/); +}); + +test("reports missing metadata, sections, Contents entries, and malformed blocks", () => { + const content = `import { Meta, ArgTypes, Canvas } from "@storybook/addon-docs/blocks"; +import * as WidgetStories from "./widget.stories"; + +# Widget +## Contents +- [Quick start](#quick-start) +## Quick Start +\`\`\`javascript +import Widget from "carbon-react/lib/components/widget"; +\`\`\` +## Examples +### Default + +## Props + +`; + const rules = validateMdx( + content, + "/virtual/widget/widget.mdx", + new FakeInspector(), + ).map(({ rule }) => rule); + + for (const expected of [ + "metadata/description", + "metadata/category", + "structure/section-name", + "contents/missing-entry", + "storybook/canvas-format", + "examples/description", + "storybook/argtypes-of", + ]) { + assert.ok(rules.includes(expected), `expected ${expected}`); + } +}); + +test("requires a warning when code marks the component as deprecated", () => { + const diagnostics = validateMdx( + validMdx, + "/virtual/widget/widget.mdx", + new FakeInspector({ componentDeprecated: true }), + ); + assert.ok( + diagnostics.some(({ rule }) => rule === "deprecation/missing-warning"), + ); +}); + +test("accepts a populated DeprecationWarning for deprecated stories", () => { + const deprecated = validMdx + .replace( + 'import * as WidgetStories from "./widget.stories";', + 'import * as WidgetStories from "./widget.stories";\nimport DeprecationWarning from "../../../.storybook/utils/deprecation-warning.component";', + ) + .replace( + "# Widget\n", + "# Widget\n\nWidget is deprecated. Use the NewWidget component for new implementations.\n", + ); + const diagnostics = validateMdx( + deprecated, + "/virtual/widget/widget.mdx", + new FakeInspector({ storyDeprecated: true }), + ); + assert.equal( + diagnostics.some(({ rule }) => rule.startsWith("deprecation/")), + false, + ); +}); + +test("reports public exports missing from the Quick start import", () => { + const diagnostics = validateMdx( + validMdx, + "/virtual/widget/widget.mdx", + new FakeInspector({ missingExports: ["default"] }), + ); + assert.ok(diagnostics.some(({ rule }) => rule === "quick-start/export")); +}); + +test("reports a Quick start import from another component family", () => { + const diagnostics = validateMdx( + validMdx, + "/virtual/widget/widget.mdx", + new FakeInspector({ sourcePath: "/virtual/button/index.ts" }), + ); + assert.ok( + diagnostics.some(({ rule }) => rule === "quick-start/component-module"), + ); +}); diff --git a/skills/carbon-react/SKILL.md b/skills/carbon-react/SKILL.md index 71c6736971..21e9b8fc6c 100644 --- a/skills/carbon-react/SKILL.md +++ b/skills/carbon-react/SKILL.md @@ -1,19 +1,28 @@ --- name: carbon-react -description: Carbon component catalog with typed props, Storybook usage examples, and curated docs references. Use when answering questions about Carbon components, props, and usage guidance. +description: Carbon component catalog with typed props, Storybook usage examples, and curated docs references. Use proactively when the user asks about any Carbon component and its props, which component to use for a given UI need, migrating a deprecated component, usage guidance or when implementing or reviewing any UI built with carbon-react. --- # Carbon Component Catalog -Use `index.md` to find the component file. -Use `components/*.md` to read props and examples. -Use these docs references: -- `references/docs/usage.md` -- `references/docs/installation.md` -- `references/docs/recommended-practices.md` -- `references/docs/usage-with-routing.md` -- `references/docs/extending-styles-using-styled-components.md` -- `references/docs/colors.md` -- `references/docs/i18n.md` -- `references/docs/deprecation-migration.md` -Deprecated components are marked in `index.md` and in each component file. +Use `index.md` to find a component and its description. +Use `components/{slug}/index.md` for a component's props and examples. +Use `components/{slug}/examples/*.md` for example source code. + +## Deprecated components + +Deprecated components are marked in `index.md` and in their file. +Prefer the non-legacy version (`button`) over the legacy one (`button-legacy`) unless explicitly asked. +Do not use deprecated props unless explicitly asked. +For migrating a deprecated component, read `references/docs/deprecation-migration.md`. + +## Reference docs + +- `references/docs/usage.md` — general usage guide +- `references/docs/installation.md` — installation +- `references/docs/recommended-practices.md` — recommended practices +- `references/docs/validations.md` — validation for input components +- `references/docs/useMediaQuery.md` — custom React hook and a JavaScript implementation of a CSS media query +- `references/docs/deprecation-migration.md` — deprecated components migration guide +- `references/docs/usage-with-routing.md` — using Carbon components with routing libraries +- `references/docs/i18n.md` — how localisation works in Carbon diff --git a/skills/carbon-react/components/accordion-group.md b/skills/carbon-react/components/accordion-group.md deleted file mode 100644 index 43a3c4508d..0000000000 --- a/skills/carbon-react/components/accordion-group.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -name: carbon-component-accordion-group -description: Carbon AccordionGroup component props and usage examples. ---- - -# AccordionGroup - -## Import -`import { AccordionGroup } from "carbon-react/lib/components/accordion";` - -## Source -- Export: `./components/accordion` -- Props interface: `AccordionGroupProps` -- Deprecated: Yes -- Deprecation reason: This component is deprecated and will be removed in a future release. Wrapping a group of Accordions in AccordionGroup is no longer required. - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| children | AccordionGroupChild | No | | An Accordion or list of Accordion components to be rendered inside the AccordionGroup | | -| m | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | - -## Examples -### Default - -**Args** - -```tsx -{ - children: [], - } -``` - diff --git a/skills/carbon-react/components/accordion.md b/skills/carbon-react/components/accordion.md deleted file mode 100644 index 94602e6de5..0000000000 --- a/skills/carbon-react/components/accordion.md +++ /dev/null @@ -1,274 +0,0 @@ ---- -name: carbon-component-accordion -description: Carbon Accordion component props and usage examples. ---- - -# Accordion - -## Import -`import { Accordion } from "carbon-react/lib/components/accordion";` - -## Source -- Export: `./components/accordion` -- Props interface: `AccordionProps` - -## Props -| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | -| --- | --- | --- | --- | --- | --- | --- | --- | -| title | React.ReactNode | Yes | | | | Title of the Accordion | | -| borders | "default" \| "none" \| "full" \| undefined | No | | | | Sets Accordion borders. **Deprecation Warning:** The "full" borders are deprecated and will be removed in a future release. | | -| children | React.ReactNode | No | | | | Content of the Accordion component | | -| defaultExpanded | boolean \| undefined | No | | | | Set the default state of expansion of the Accordion if component is to be used as uncontrolled | | -| expanded | boolean \| undefined | No | | | | Sets the expansion state of the Accordion if component is to be used as controlled | | -| headerSpacing | SpaceProps | No | | | | Styled system spacing props provided to Accordion Title | | -| id | string \| undefined | No | | | | | | -| m | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| onChange | ((event: React.MouseEvent \| React.KeyboardEvent, isExpanded: boolean) => void) \| undefined | No | | | | Callback fired when expansion state changes | | -| openTitle | string \| undefined | No | | | | Title of the Accordion when it is open | | -| p | ResponsiveValue \| undefined | No | | | | Padding on top, left, bottom and right | | -| padding | ResponsiveValue \| undefined | No | | | | Padding on top, left, bottom and right | | -| paddingBottom | ResponsiveValue \| undefined | No | | | | Padding on bottom | | -| paddingLeft | ResponsiveValue \| undefined | No | | | | Padding on left | | -| paddingRight | ResponsiveValue \| undefined | No | | | | Padding on right | | -| paddingTop | ResponsiveValue \| undefined | No | | | | Padding on top | | -| paddingX | ResponsiveValue \| undefined | No | | | | Padding on left and right | | -| paddingY | ResponsiveValue \| undefined | No | | | | Padding on top and bottom | | -| pb | ResponsiveValue \| undefined | No | | | | Padding on bottom | | -| pl | ResponsiveValue \| undefined | No | | | | Padding on left | | -| pr | ResponsiveValue \| undefined | No | | | | Padding on right | | -| pt | ResponsiveValue \| undefined | No | | | | Padding on top | | -| px | ResponsiveValue \| undefined | No | | | | Padding on left and right | | -| py | ResponsiveValue \| undefined | No | | | | Padding on top and bottom | | -| size | "small" \| "medium" \| "large" \| undefined | No | | | | Sets Accordion size | | -| subTitle | string \| undefined | No | | | | Sets accordion sub title | | -| variant | "subtle" \| "standard" \| "simple" \| undefined | No | | | | Sets Accordion variant. **Deprecation Warning:** The "subtle" variant is deprecated, please use "simple" instead. | | -| width | string \| undefined | No | | | | Sets Accordion width | | -| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| disableContentPadding | boolean \| undefined | No | | Yes | Padding is no longer applied to the Accordion content by default. Any desired spacing can be applied directly to the provided content. | Disable padding for the content. | | -| error | string \| undefined | No | | Yes | Validation messages on accordions are no longer supported. | An error message to be displayed in the tooltip. | | -| iconAlign | "left" \| "right" \| undefined | No | | Yes | Icon alignment on accordions is deprecated and will be removed in a future release. Icons will now render on the left by default. | Sets icon alignment. | | -| iconType | "chevron_down" \| "chevron_down_thick" \| "dropdown" \| undefined | No | | Yes | Custom icon types on accordions are deprecated and will be removed in a future release. | Sets icon type | | -| info | string \| undefined | No | | Yes | Validation messages on accordions are no longer supported. | An info message to be displayed in the tooltip. | | -| warning | string \| undefined | No | | Yes | Validation messages on accordions are no longer supported. | A warning message to be displayed in the tooltip. | | - -## Examples -### Default - -**Args** - -```tsx -{ - title: "Title", - } -``` - -**Render** - -```tsx -(args) => ( - - Content - Content - Content - - ) -``` - - -### Subtitle - -**Args** - -```tsx -{ - ...Default.args, - subTitle: "Subtitle", - } -``` - - -### Custom Title - -**Render** - -```tsx -({ ...args }) => { - const title = ( - - - - - Custom Title - - - Custom Subtitle - - - - ); - - return ( - - Content - Content - Content - - ); -} -``` - - -### SimpleVariant - -**Args** - -```tsx -{ - ...Default.args, - title: "Accordion label", - variant: "simple", - } -``` - -**Render** - -```tsx -(args) => ( - - Content - Content - Content - - ) -``` - - -### Standard Sizes - -**Args** - -```tsx -{ - subTitle: "Subtitle", -} -``` - -**Render** - -```tsx -({ ...args }) => { - return ( - - - Content - Content - Content - - - - Content - Content - Content - - - ); -} -``` - - -### Simple Sizes - -**Args** - -```tsx -{ - variant: "simple", -} -``` - -**Render** - -```tsx -({ ...args }) => { - return ( - - - Content - Content - Content - - - - Content - Content - Content - - - - Content - Content - Content - - - ); -} -``` - - -### HeaderSpacing - -**Args** - -```tsx -{ - ...Default.args, - headerSpacing: { - padding: "24px 0", - }, - } -``` - - -### DisableBorders - -**Args** - -```tsx -{ - ...Default.args, - borders: "none", - } -``` - - -### Width - -**Args** - -```tsx -{ - ...Default.args, - width: "500px", - } -``` - diff --git a/skills/carbon-react/components/accordion/examples/Default.md b/skills/carbon-react/components/accordion/examples/Default.md new file mode 100644 index 0000000000..2bf2dbc74e --- /dev/null +++ b/skills/carbon-react/components/accordion/examples/Default.md @@ -0,0 +1,11 @@ +```tsx +export const Default: Story = () => { + return ( + + Content + Content + Content + + ); +}; +``` \ No newline at end of file diff --git a/skills/carbon-react/components/accordion/examples/DisableBorders.md b/skills/carbon-react/components/accordion/examples/DisableBorders.md new file mode 100644 index 0000000000..94e2172106 --- /dev/null +++ b/skills/carbon-react/components/accordion/examples/DisableBorders.md @@ -0,0 +1,11 @@ +```tsx +export const DisableBorders: Story = () => { + return ( + + Content + Content + Content + + ); +}; +``` \ No newline at end of file diff --git a/skills/carbon-react/components/accordion/examples/HeaderSpacing.md b/skills/carbon-react/components/accordion/examples/HeaderSpacing.md new file mode 100644 index 0000000000..25d87db027 --- /dev/null +++ b/skills/carbon-react/components/accordion/examples/HeaderSpacing.md @@ -0,0 +1,16 @@ +```tsx +export const HeaderSpacing: Story = () => { + return ( + + Content + Content + Content + + ); +}; +``` \ No newline at end of file diff --git a/skills/carbon-react/components/accordion/examples/SimpleSizes.md b/skills/carbon-react/components/accordion/examples/SimpleSizes.md new file mode 100644 index 0000000000..3fa965caf2 --- /dev/null +++ b/skills/carbon-react/components/accordion/examples/SimpleSizes.md @@ -0,0 +1,25 @@ +```tsx +export const SimpleSizes: Story = () => { + return ( + + + Content + Content + Content + + + + Content + Content + Content + + + + Content + Content + Content + + + ); +}; +``` \ No newline at end of file diff --git a/skills/carbon-react/components/accordion/examples/SimpleVariant.md b/skills/carbon-react/components/accordion/examples/SimpleVariant.md new file mode 100644 index 0000000000..e1d1be64a9 --- /dev/null +++ b/skills/carbon-react/components/accordion/examples/SimpleVariant.md @@ -0,0 +1,9 @@ +```tsx +export const SimpleVariant: Story = () => ( + + Content + Content + Content + +); +``` \ No newline at end of file diff --git a/skills/carbon-react/components/accordion/examples/StandardSizes.md b/skills/carbon-react/components/accordion/examples/StandardSizes.md new file mode 100644 index 0000000000..f7e34866cf --- /dev/null +++ b/skills/carbon-react/components/accordion/examples/StandardSizes.md @@ -0,0 +1,19 @@ +```tsx +export const StandardSizes: Story = () => { + return ( + + + Content + Content + Content + + + + Content + Content + Content + + + ); +}; +``` \ No newline at end of file diff --git a/skills/carbon-react/components/accordion/examples/Subtitle.md b/skills/carbon-react/components/accordion/examples/Subtitle.md new file mode 100644 index 0000000000..6d418a2460 --- /dev/null +++ b/skills/carbon-react/components/accordion/examples/Subtitle.md @@ -0,0 +1,11 @@ +```tsx +export const Subtitle: Story = () => { + return ( + + Content + Content + Content + + ); +}; +``` \ No newline at end of file diff --git a/skills/carbon-react/components/accordion/examples/Width.md b/skills/carbon-react/components/accordion/examples/Width.md new file mode 100644 index 0000000000..af9ae109cf --- /dev/null +++ b/skills/carbon-react/components/accordion/examples/Width.md @@ -0,0 +1,11 @@ +```tsx +export const Width: Story = () => { + return ( + + Content + Content + Content + + ); +}; +``` \ No newline at end of file diff --git a/skills/carbon-react/components/accordion/examples/WithCustomTitle.md b/skills/carbon-react/components/accordion/examples/WithCustomTitle.md new file mode 100644 index 0000000000..13833ac56f --- /dev/null +++ b/skills/carbon-react/components/accordion/examples/WithCustomTitle.md @@ -0,0 +1,30 @@ +```tsx +export const WithCustomTitle: Story = () => { + const title = ( + + + + + Custom Title + + + Custom Subtitle + + + + ); + + return ( + + Content + Content + Content + + ); +}; +``` \ No newline at end of file diff --git a/skills/carbon-react/components/accordion/index.md b/skills/carbon-react/components/accordion/index.md new file mode 100644 index 0000000000..8acb94880e --- /dev/null +++ b/skills/carbon-react/components/accordion/index.md @@ -0,0 +1,105 @@ +# Accordion + +An accordion is used to group, hide, and reveal content using progressive disclosure. When closed, an accordion shows top-level information only. A user can open the accordion and quickly access more information. + +**Category:** UI presentation + +## Quick Start + +To use accordions, import the `Accordion` component and pass the desired content as child components. + +```javascript +import { Accordion } from "carbon-react/lib/components/accordion"; +``` + +## Examples + +### Default + +To render an `Accordion`, please ensure you provide a `title` prop. + +See: `examples/Default.md` + +### Subtitle + +To add a subtitle below the title, you can pass the `subTitle` prop. + +See: `examples/Subtitle.md` + +### Custom Title + +The `title` prop supports passing a React node for custom title layouts. + +See: `examples/WithCustomTitle.md` + +### Simple Variant + +To render a simple `Accordion`, set the `variant` prop to `simple`. +**Note:** The `subTitle` prop is not supported with this variant. + +See: `examples/SimpleVariant.md` + +### Size + +The `standard` variant is available in sizes `small` and `medium`. +The `simple` variant is available in sizes `small`, `medium` and `large`. + +To set the size of the component, set the `size` prop to the desired value. + +See: `examples/StandardSizes.md` + +See: `examples/SimpleSizes.md` + +### Header Spacing + +By default, the `Accordion` has internal spacing applied to the header area. Custom spacing can be applied using the `headerSpacing` prop. + +See: `examples/HeaderSpacing.md` + +### Disable Borders + +The `borders` prop can be set to `none` to render the `Accordion` without borders. + +See: `examples/DisableBorders.md` + +### Width + +You can set the `width` prop to specify the width of the `Accordion`. + +See: `examples/Width.md` + +## Props + +### Accordion + +| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | +| --- | --- | --- | --- | --- | --- | --- | --- | +| title | React.ReactNode | Yes | | | | Title of the Accordion | | +| borders | "default" \| "none" \| "full" \| undefined | No | | | | Sets Accordion borders. **Deprecation Warning:** The "full" borders are deprecated and will be removed in a future release. | | +| children | React.ReactNode | No | | | | Content of the Accordion component | | +| defaultExpanded | boolean \| undefined | No | | | | Set the default state of expansion of the Accordion if component is to be used as uncontrolled | | +| expanded | boolean \| undefined | No | | | | Sets the expansion state of the Accordion if component is to be used as controlled | | +| headerSpacing | SpaceProps | No | | | | Styled system spacing props provided to Accordion Title | | +| id | string \| undefined | No | | | | | | +| onChange | ((event: React.MouseEvent \| React.KeyboardEvent, isExpanded: boolean) => void) \| undefined | No | | | | Callback fired when expansion state changes | | +| openTitle | string \| undefined | No | | | | Title of the Accordion when it is open | | +| size | "small" \| "medium" \| "large" \| undefined | No | | | | Sets Accordion size | | +| subTitle | string \| undefined | No | | | | Sets accordion sub title | | +| variant | "standard" \| "simple" \| "subtle" \| undefined | No | | | | Sets Accordion variant. **Deprecation Warning:** The "subtle" variant is deprecated, please use "simple" instead. | | +| width | string \| undefined | No | | | | Sets Accordion width | | +| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | +| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | +| disableContentPadding | boolean \| undefined | No | | Yes | Padding is no longer applied to the Accordion content by default. Any desired spacing can be applied directly to the provided content. | Disable padding for the content. | | +| error | string \| undefined | No | | Yes | Validation messages on accordions are no longer supported. | An error message to be displayed in the tooltip. | | +| iconAlign | "left" \| "right" \| undefined | No | | Yes | Icon alignment on accordions is deprecated and will be removed in a future release. Icons will now render on the left by default. | Sets icon alignment. | | +| iconType | "chevron_down" \| "chevron_down_thick" \| "dropdown" \| undefined | No | | Yes | Custom icon types on accordions are deprecated and will be removed in a future release. | Sets icon type | | +| info | string \| undefined | No | | Yes | Validation messages on accordions are no longer supported. | An info message to be displayed in the tooltip. | | +| warning | string \| undefined | No | | Yes | Validation messages on accordions are no longer supported. | A warning message to be displayed in the tooltip. | | + +### AccordionGroup (Deprecated) + +| Name | Type | Required | Literals | Description | Default | +| --- | --- | --- | --- | --- | --- | +| children | AccordionGroupChild | No | | An Accordion or list of Accordion components to be rendered inside the AccordionGroup | | +| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | +| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | diff --git a/skills/carbon-react/components/action-popover-divider.md b/skills/carbon-react/components/action-popover-divider.md deleted file mode 100644 index ec03f93682..0000000000 --- a/skills/carbon-react/components/action-popover-divider.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: carbon-component-action-popover-divider -description: Carbon ActionPopoverDivider component props and usage examples. ---- - -# ActionPopoverDivider - -## Import -`import { ActionPopoverDivider } from "carbon-react/lib/components/action-popover";` - -## Source -- Export: `./components/action-popover` -- Props interface: not found - -## Props -No props metadata found. - -## Examples -No Storybook examples found. \ No newline at end of file diff --git a/skills/carbon-react/components/action-popover-item.md b/skills/carbon-react/components/action-popover-item.md deleted file mode 100644 index 7ab9af8f6b..0000000000 --- a/skills/carbon-react/components/action-popover-item.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -name: carbon-component-action-popover-item -description: Carbon ActionPopoverItem component props and usage examples. ---- - -# ActionPopoverItem - -## Import -`import { ActionPopoverItem } from "carbon-react/lib/components/action-popover";` - -## Source -- Export: `./components/action-popover` -- Props interface: `ActionPopoverItemProps` - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| children | string | Yes | | The text label to display for this Item | | -| disabled | boolean \| undefined | No | | Flag to indicate if item is disabled | false | -| download | boolean \| undefined | No | | allows to provide download prop that works dependent with href | | -| href | string \| undefined | No | | allows to provide href prop | | -| icon | IconType \| undefined | No | | The name of the icon to display next to the label | | -| onClick | ((ev: React.MouseEvent \| React.KeyboardEvent) => void) \| undefined | No | | Callback to run when item is clicked | | -| submenu | React.ReactNode | No | | Submenu component for item | | - -## Examples -### Default - -**Args** - -```tsx -{} -``` - diff --git a/skills/carbon-react/components/action-popover-menu-button.md b/skills/carbon-react/components/action-popover-menu-button.md deleted file mode 100644 index b379347768..0000000000 --- a/skills/carbon-react/components/action-popover-menu-button.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -name: carbon-component-action-popover-menu-button -description: Carbon ActionPopoverMenuButton component props and usage examples. ---- - -# ActionPopoverMenuButton - -## Import -`import { ActionPopoverMenuButton } from "carbon-react/lib/components/action-popover";` - -## Source -- Export: `./components/action-popover` -- Props interface: `ActionPopoverMenuButtonProps` - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| ariaAttributes | ActionPopoverMenuButtonAria | Yes | | ARIA attributes to be applied to the button HTML element | | -| tabIndex | number | Yes | | Overrides the default tabindex of the component | | -| data-element | string | Yes | | Identifier used for testing purposes, applied to the root element of the component. | | -| buttonType | ButtonTypes \| undefined | No | | Variant of the menu button | | -| children | string \| undefined | No | | Content of the button | | -| iconPosition | ButtonIconPosition \| undefined | No | | Defines an Icon position related to the children: "before" \| "after" | | -| iconType | IconType \| undefined | No | | Defines an Icon type within the button | | -| size | SizeOptions \| undefined | No | | Assigns a size to the button: "small" \| "medium" \| "large" | | - -## Examples -### Default - -**Args** - -```tsx -{} -``` - diff --git a/skills/carbon-react/components/action-popover-menu.md b/skills/carbon-react/components/action-popover-menu.md deleted file mode 100644 index ccabd0b49f..0000000000 --- a/skills/carbon-react/components/action-popover-menu.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -name: carbon-component-action-popover-menu -description: Carbon ActionPopoverMenu component props and usage examples. ---- - -# ActionPopoverMenu - -## Import -`import { ActionPopoverMenu } from "carbon-react/lib/components/action-popover";` - -## Source -- Export: `./components/action-popover` -- Props interface: `ActionPopoverMenuProps` - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | No | | Children for the menu | | -| isOpen | boolean \| undefined | No | | Flag to indicate whether a menu should open | | -| key | Key \| null \| undefined | No | | | | -| menuID | string \| undefined | No | | A unique ID for the menu | | -| parentID | string \| undefined | No | | Unique ID for the menu's parent | | -| placement | "bottom" \| "top" \| undefined | No | | Set whether the menu should open above or below the button | | -| ref | LegacyRef \| undefined | No | | Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref). | | -| setOpen | ((args: boolean) => void) \| undefined | No | | Callback to set the isOpen flag | | - -## Examples -### Default - -**Args** - -```tsx -{ - children: [], - } -``` - diff --git a/skills/carbon-react/components/action-popover.md b/skills/carbon-react/components/action-popover.md deleted file mode 100644 index e693a98b5e..0000000000 --- a/skills/carbon-react/components/action-popover.md +++ /dev/null @@ -1,928 +0,0 @@ ---- -name: carbon-component-action-popover -description: Carbon ActionPopover component props and usage examples. ---- - -# ActionPopover - -## Import -`import { ActionPopover } from "carbon-react/lib/components/action-popover";` - -## Source -- Export: `./components/action-popover` -- Props interface: `ActionPopoverProps` - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | No | | Children for popover component | | -| horizontalAlignment | Alignment \| undefined | No | | Horizontal alignment of menu items content | | -| id | string \| undefined | No | | Unique ID | | -| m | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| onClose | (() => void) \| undefined | No | | Callback to be called on menu close | | -| onOpen | (() => void) \| undefined | No | | Callback to be called on menu open | | -| placement | "bottom" \| "top" \| undefined | No | | Set whether the menu should open above or below the button | | -| renderButton | ((buttonProps: RenderButtonProps) => React.ReactNode) \| undefined | No | | Render a custom menu button to override default ellipsis icon | | -| rightAlignMenu | boolean \| undefined | No | | Boolean to control whether menu should align to right | | -| submenuPosition | Alignment \| undefined | No | | Sets submenu position | | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| aria-describedby | string \| undefined | No | | Prop to specify an aria-describedby for the component | | -| aria-label | string \| undefined | No | | Prop to specify an aria-label for the component | | -| aria-labelledby | string \| undefined | No | | Prop to specify an aria-labelledby for the component | | - -## Examples -### Default - -**Render** - -```tsx -() => { - const submenu = ( - - {}}>Sub Menu 1 - {}}>Sub Menu 2 - {}}> - Sub Menu 3 - - - ); - const submenuWithIcons = ( - - {}}> - Sub Menu 1 - - {}}> - Sub Menu 2 - - {}}> - Sub Menu 3 - - - ); - return ( - - {}} onClose={() => {}}> - {}} - > - Business - - {}}> - Email Invoice - - {}} submenu={submenu}> - Print Invoice - - {}}> - Download PDF - - {}}> - Download CSV - - - {}}> - Delete - - - - {}}> - Download CSV - - - - {}} - > - Download CSV - - - - ); -} -``` - - -### Icons - -**Render** - -```tsx -() => { - return ( - - - {}}> - Email Invoice - - - {}} icon="delete"> - Delete - - - - ); -} -``` - - -### Disabled Items - -**Render** - -```tsx -() => { - return ( - - - {}}> - Email Invoice - - - {}} icon="delete"> - Delete - - - {}} icon="add"> - Add - - {}} icon="delete"> - Delete - - {}} icon="tick"> - Tick - - {}} icon="delete"> - Delete - - {}} icon="none"> - None - - - - ); -} -``` - - -### Menu Right Aligned - -**Render** - -```tsx -() => { - return ( - - - {}}> - Email Invoice - - - {}} icon="delete"> - Delete - - - - ); -} -``` - - -### Content Aligned Right - -**Render** - -```tsx -() => { - return ( - - - Email Invoice - - Delete - - - ); -} -``` - - -### No Icons - -**Render** - -```tsx -() => { - return ( - - - {}}>Email Invoice - - {}}>Delete - - - ); -} -``` - - -### Custom Menu Button - -**Render** - -```tsx -() => { - return ( - - ( - - More - - )} - > - {}}> - Email Invoice - - - {}} icon="delete"> - Delete - - - ( - - )} - > - {}}> - Email Invoice - - - {}} icon="delete"> - Delete - - - ( - {}} data-element={dataElement}> - More - - )} - > - {}}> - Email Invoice - - - {}} icon="delete"> - Delete - - - - ); -} -``` - - -### Submenu - -**Render** - -```tsx -() => { - return ( - - - {}} - submenu={ - - {}}> - CSV - - {}}>PDF - {}}>PDF - - } - > - Print - - - {}} icon="add"> - Add - - {}} icon="delete"> - Delete - - - - ); -} -``` - - -### Disabled Submenu - -**Render** - -```tsx -() => { - return ( - - - {}} - submenu={ - - {}}>CSV - {}}>PDF - - } - > - Print - - - {}} icon="delete"> - Delete - - - - ); -} -``` - - -### Sub Menu Positioned Right - -**Render** - -```tsx -() => { - const submenu = ( - - {}}>Sub Menu 1 - {}}>Sub Menu 2 - {}}> - Sub Menu 3 - - - ); - return ( - - - - Email Invoice - - - - Delete - - - - ); -} -``` - - -### Menu Opening Above - -**Render** - -```tsx -() => { - return ( - - - {}} - submenu={ - - {}}>CSV - {}}>PDF - - } - > - Print - - - {}} icon="delete"> - Delete - - - - ); -} -``` - - -### Keyboard Navigation - -**Render** - -```tsx -() => { - return ( - - - {}}> - Email Invoice - - {}}> - Download CSV - - {}}> - Download PDF - - - {}} icon="delete"> - Delete - - - - ); -} -``` - - -### Keyboard Navigation Left Aligned Submenu - -**Render** - -```tsx -() => { - return ( - - - {}} - submenu={ - - {}}> - CSV - - {}}> - PDF - - - } - > - Download - - {}} - submenu={ - - {}}> - CSV - - {}}> - PDF - - - } - > - Print - - - {}} icon="delete"> - Delete - - - - ); -} -``` - - -### Keyboard Navigation Right Aligned Submenu - -**Render** - -```tsx -() => { - return ( - - - {}} - submenu={ - - {}}> - CSV - - {}}> - PDF - - - } - > - Download - - {}} - submenu={ - - {}}> - CSV - - {}}> - PDF - - - } - > - Print - - - {}} icon="delete"> - Delete - - - - ); -} -``` - - -### Additional Options - -**Render** - -```tsx -() => { - return ( - - - {}}>Enroll Device - {}}>Assign Owner - - {}}>Manage Devices - - - ); -} -``` - - -### Download Button - -**Render** - -```tsx -() => { - return ( - - - - Download - - {}}> - Assign Owner - - - Download - - - - ); -} -``` - - -### In Overflow Hidden Container - -**Render** - -```tsx -() => { - return ( - - - - - {}}> - Enroll Device - - {}}> - Assign Owner - - - {}}> - Manage Devices - - - - {}}> - Enroll Device - - {}}> - Assign Owner - - - {}}> - Manage Devices - - - - {}}> - Enroll Device - - {}}> - Assign Owner - - - {}}> - Manage Devices - - - - - - ); -} -``` - - -### In Flat Table - -**Render** - -```tsx -() => { - const [highlightedRow, setHighlightedRow] = useState(""); - const handleHighlightRow = (id: string) => { - setHighlightedRow(id); - }; - return ( - - - - - Name - Location - Relationship Status - Dependents - - - - handleHighlightRow("one")} - highlighted={highlightedRow === "one"} - > - John Doe - London - Single - - handleHighlightRow("one")} - > - {}} - submenu={ - - {}}> - CSV - - {}}> - PDF - - - } - > - Print - - - {}} icon="delete"> - Delete - - - - - handleHighlightRow("two")} - highlighted={highlightedRow === "two"} - > - Jane Doe - York - Married - - handleHighlightRow("two")} - > - {}} - submenu={ - - {}}> - CSV - - {}}> - PDF - - - } - > - Print - - - {}} icon="delete"> - Delete - - - - - - - - ); -} -``` - - -### Opening a Modal - -**Render** - -```tsx -() => { - const [isConfirmOpen, setIsConfirmOpen] = useState(false); - return ( - <> - - ( - - Open Actions - - )} - > - { - setIsConfirmOpen(!isConfirmOpen); - }} - > - Open Confirm Dialog - - {}}> - Do Nothing - - - - setIsConfirmOpen(!isConfirmOpen)} - onCancel={() => setIsConfirmOpen(!isConfirmOpen)} - > - Content - - - ); -} -``` - - -### Action Popover Nested in Dialog - -**Render** - -```tsx -() => { - const [isOpen, setIsOpen] = useState(true); - return ( - setIsOpen(false)} title="Dialog"> - - {}}> - Email Invoice - - - {}} icon="delete"> - Delete - - {" "} - - ); -} -``` - - -### Focus Button Programmatically - -**Render** - -```tsx -() => { - const ref = useRef(null); - const refMore = useRef(null); - - const renderButton = (props: RenderButtonProps) => ( - - More - - ); - - return ( - <> - - - {}}> - Email Invoice - - - {}} icon="delete"> - Delete - - - - - - {}}> - Email Invoice - - - {}} icon="delete"> - Delete - - - - ); -} -``` - diff --git a/skills/carbon-react/components/adaptive-sidebar.md b/skills/carbon-react/components/adaptive-sidebar.md deleted file mode 100644 index 0aab88919f..0000000000 --- a/skills/carbon-react/components/adaptive-sidebar.md +++ /dev/null @@ -1,679 +0,0 @@ ---- -name: carbon-component-adaptive-sidebar -description: Carbon AdaptiveSidebar component props and usage examples. ---- - -# AdaptiveSidebar - -## Import -`import AdaptiveSidebar from "carbon-react/lib/components/adaptive-sidebar";` - -## Source -- Export: `./components/adaptive-sidebar` -- Props interface: `AdaptiveSidebarProps` - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| open | boolean | Yes | | Whether the sidebar is open or closed | | -| adaptiveBreakpoint | number \| undefined | No | | The breakpoint (in pixels) at which the sidebar will convert to a dialog-based sidebar | 768 | -| animationTimeout | number \| undefined | No | | The time in milliseconds for the sidebar to animate | | -| backgroundColor | "white" \| "black" \| "app" \| undefined | No | | The background color of the sidebar | "white" | -| borderColor | string \| undefined | No | | The color to use for the left-hand border of the sidebar. Should be a design token e.g. `--colorsUtilityYang100` | "none" | -| children | React.ReactNode | No | | The content of the sidebar | | -| height | string \| undefined | No | | The height of the sidebar, relative to the wrapping component | "100%" | -| hidden | boolean \| undefined | No | | Whether the sidebar is hidden from view. In this state, the adaptive sidebar will continue to receive updates, etc. but will not be visible to users | false | -| m | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| p | ResponsiveValue \| undefined | No | | Padding on top, left, bottom and right | | -| padding | ResponsiveValue \| undefined | No | | Padding on top, left, bottom and right | | -| paddingBottom | ResponsiveValue \| undefined | No | | Padding on bottom | | -| paddingLeft | ResponsiveValue \| undefined | No | | Padding on left | | -| paddingRight | ResponsiveValue \| undefined | No | | Padding on right | | -| paddingTop | ResponsiveValue \| undefined | No | | Padding on top | | -| paddingX | ResponsiveValue \| undefined | No | | Padding on left and right | | -| paddingY | ResponsiveValue \| undefined | No | | Padding on top and bottom | | -| pb | ResponsiveValue \| undefined | No | | Padding on bottom | | -| pl | ResponsiveValue \| undefined | No | | Padding on left | | -| pr | ResponsiveValue \| undefined | No | | Padding on right | | -| pt | ResponsiveValue \| undefined | No | | Padding on top | | -| px | ResponsiveValue \| undefined | No | | Padding on left and right | | -| py | ResponsiveValue \| undefined | No | | Padding on top and bottom | | -| renderAsModal | boolean \| undefined | No | | Whether to render the sidebar as a modal component instead of as an inline sidebar | false | -| restoreFocusOnClose | boolean \| undefined | No | | Enables the automatic restoration of focus to the element that invoked the modal when the modal is closed. | false | -| width | string \| undefined | No | | The width of the sidebar | "320px" | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| aria-label | string \| undefined | No | | Prop to specify the aria-label of the component, applied when the component is rendered as a modal | | -| aria-labelledby | string \| undefined | No | | Prop to specify the aria-labelledby property of the component, applied when the component is rendered as a modal | | - -## Examples -### Basic - -**Render** - -```tsx -() => { - const [adaptiveSidebarOpen, setAdaptiveSidebarOpen] = - useState(defaultOpenState); - - return ( - - - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi at odio - ultricies, luctus dolor at, fringilla elit. Nulla non nunc eu sapien - tempus porta. Nullam sodales nisi ut orci efficitur, nec ullamcorper - nunc pulvinar. Integer eleifend a augue ac accumsan. Fusce ultrices - auctor aliquam. Sed eu metus sit amet est tempor ullamcorper. Praesent - eu elit eget lacus fermentum porta at ut dui. - - - - - - Adaptive sidebar content - - - - ); -} -``` - - -### Default - -**Render** - -```tsx -() => { - const [adaptiveSidebarOpen, setAdaptiveSidebarOpen] = - useState(defaultOpenState); - - return ( - - - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi at odio - ultricies, luctus dolor at, fringilla elit. Nulla non nunc eu sapien - tempus porta. Nullam sodales nisi ut orci efficitur, nec ullamcorper - nunc pulvinar. Integer eleifend a augue ac accumsan. Fusce ultrices - auctor aliquam. Sed eu metus sit amet est tempor ullamcorper. Praesent - eu elit eget lacus fermentum porta at ut dui. - - - - - Content - - - - - - This is the main content of the adaptive sidebar - - - - - ); -} -``` - - -### Complex - -**Render** - -```tsx -() => { - const [adaptiveSidebarOpen, setAdaptiveSidebarOpen] = - useState(defaultOpenState); - - return ( - <> - - Example - - setAdaptiveSidebarOpen(!adaptiveSidebarOpen)} - > - Help - - - - - - - Content - Sub-header - - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi at - odio ultricies, luctus dolor at, fringilla elit. Nulla non nunc eu - sapien tempus porta. Nullam sodales nisi ut orci efficitur, nec - ullamcorper nunc pulvinar. Integer eleifend a augue ac accumsan. - Fusce ultrices auctor aliquam. Sed eu metus sit amet est tempor - ullamcorper. Praesent eu elit eget lacus fermentum porta at ut - dui. - - - - - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi - consequat facilisis sapien, vitae tempor nulla tempor cursus. - Mauris et efficitur urna. Sed nibh metus, suscipit vitae maximus - eu, consequat in nibh. Vivamus eu felis diam. Vestibulum est - libero, rhoncus in neque ut, posuere faucibus nunc. Praesent - porttitor sodales viverra. Curabitur ultricies varius mattis. - - - - Duis varius rutrum risus, ac tincidunt dui tristique in. Nulla - et iaculis massa. Suspendisse finibus eleifend sodales. Nulla - facilisi. Nunc eleifend risus lorem, ac dignissim libero - venenatis non. Sed tristique nunc vel arcu pharetra, sit amet - tincidunt leo dictum. Nam et mi in quam consectetur pretium. - Curabitur id tempus massa, eget lacinia nisi. Nullam quis urna - ac ante interdum scelerisque. Integer pretium cursus orci nec - malesuada. Aenean nec est in diam suscipit bibendum. Proin - viverra justo nec nulla laoreet, sit amet aliquam massa dictum. - Nam ac mauris ac elit commodo convallis. Sed in tortor lobortis - mi rhoncus congue a ut dolor. Etiam faucibus a nisl et - convallis. - - - - Ut interdum vel nulla vel posuere. Nullam a odio viverra, tempus - lorem et, commodo justo. Ut eget massa molestie, fringilla ante - et, sagittis lorem. Donec feugiat sodales dignissim. Ut auctor - eget ante a interdum. Integer sem risus, bibendum sit amet - porttitor a, ultricies non elit. Nam nunc quam, scelerisque non - mauris vel, mollis rhoncus leo. Proin in ligula sapien. - - - - Quisque sed elementum nibh, sit amet imperdiet turpis. Duis - fermentum lacus in aliquet auctor. Nam tortor mauris, elementum - nec urna ut, sollicitudin congue felis. Nunc porta, tellus ac - vestibulum malesuada, quam libero mollis augue, ac lobortis - metus quam semper lacus. Orci varius natoque penatibus et magnis - dis parturient montes, nascetur ridiculus mus. Sed erat odio, - lacinia nec urna quis, elementum tristique nisi. Donec commodo - lacinia tortor a sagittis.{" "} - - - - - - - ); -} -``` - - -### With Custom Width - -**Render** - -```tsx -() => { - const [adaptiveSidebarOpen, setAdaptiveSidebarOpen] = - useState(defaultOpenState); - - return ( - - {CommonTemplate(adaptiveSidebarOpen, setAdaptiveSidebarOpen)} - - - - - Content - - - - - - This is the main content of the adaptive sidebar - - - - - - ); -} -``` - - -### With Custom Height - -**Render** - -```tsx -() => { - const [adaptiveSidebarOpen, setAdaptiveSidebarOpen] = - useState(defaultOpenState); - - return ( - - {CommonTemplate(adaptiveSidebarOpen, setAdaptiveSidebarOpen)} - - - - - Content - - - - - - This is the main content of the adaptive sidebar - - - - - - ); -} -``` - - -### Background Variants - -**Render** - -```tsx -() => { - const [adaptiveSidebarOpen, setAdaptiveSidebarOpen] = - useState(defaultOpenState); - const [colour, setColour] = useState("white"); - - return ( - - - - - - - - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi at odio - ultricies, luctus dolor at, fringilla elit. Nulla non nunc eu sapien - tempus porta. Nullam sodales nisi ut orci efficitur, nec ullamcorper - nunc pulvinar. Integer eleifend a augue ac accumsan. Fusce ultrices - auctor aliquam. Sed eu metus sit amet est tempor ullamcorper. Praesent - eu elit eget lacus fermentum porta at ut dui. - - - - - - - - Content - - - - - - - This is the main content of the adaptive sidebar - - - - - - ); -} -``` - - -### With Adaptive Breakpoint - -**Render** - -```tsx -() => { - const [adaptiveSidebarOpen, setAdaptiveSidebarOpen] = - useState(defaultOpenState); - - return ( - - {CommonTemplate(adaptiveSidebarOpen, setAdaptiveSidebarOpen)} - - - - - Content - - - - - - This is the main content of the adaptive sidebar - - - - - - ); -} -``` - - -### Render As Dialog - -**Render** - -```tsx -() => { - const [adaptiveSidebarOpen, setAdaptiveSidebarOpen] = - useState(defaultOpenState); - - return ( - - {CommonTemplate(adaptiveSidebarOpen, setAdaptiveSidebarOpen)} - - - - - Content - - - - - - This is the main content of the adaptive sidebar - - - - - - ); -} -``` - - -### With Custom Border Color - -**Render** - -```tsx -() => { - const [adaptiveSidebarOpen, setAdaptiveSidebarOpen] = - useState(defaultOpenState); - - return ( - - - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi at odio - ultricies, luctus dolor at, fringilla elit. Nulla non nunc eu sapien - tempus porta. Nullam sodales nisi ut orci efficitur, nec ullamcorper - nunc pulvinar. Integer eleifend a augue ac accumsan. Fusce ultrices - auctor aliquam. Sed eu metus sit amet est tempor ullamcorper. Praesent - eu elit eget lacus fermentum porta at ut dui. - - - - - Content - - - - - - This is the main content of the adaptive sidebar - - - - - ); -} -``` - - -### Hidden - -**Render** - -```tsx -() => { - const [adaptiveSidebarOpen, setAdaptiveSidebarOpen] = - useState(defaultOpenState); - const [adaptiveSidebarHidden, setAdaptiveSidebarHidden] = useState(false); - const [count, setCount] = useState(0); - - useEffect(() => { - let handle: ReturnType; - if (adaptiveSidebarOpen || adaptiveSidebarHidden) { - handle = setInterval(() => { - setCount((prevCount) => prevCount + 1); - }, 1000); - } - - return () => clearTimeout(handle); - }, [adaptiveSidebarOpen, adaptiveSidebarHidden]); - - const buttonText = useMemo(() => { - if (adaptiveSidebarHidden) { - return "Show"; - } else if (adaptiveSidebarOpen) { - return "Close"; - } else { - return "Open"; - } - }, [adaptiveSidebarHidden, adaptiveSidebarOpen]); - - return ( - - - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi at odio - ultricies, luctus dolor at, fringilla elit. Nulla non nunc eu sapien - tempus porta. Nullam sodales nisi ut orci efficitur, nec ullamcorper - nunc pulvinar. Integer eleifend a augue ac accumsan. Fusce ultrices - auctor aliquam. Sed eu metus sit amet est tempor ullamcorper. Praesent - eu elit eget lacus fermentum porta at ut dui. - - - - - ); -} -``` - diff --git a/skills/carbon-react/components/advanced-color-picker.md b/skills/carbon-react/components/advanced-color-picker.md deleted file mode 100644 index b9c0a2e5a8..0000000000 --- a/skills/carbon-react/components/advanced-color-picker.md +++ /dev/null @@ -1,152 +0,0 @@ ---- -name: carbon-component-advanced-color-picker -description: Carbon AdvancedColorPicker component props and usage examples. ---- - -# AdvancedColorPicker - -## Import -`import AdvancedColorPicker from "carbon-react/lib/components/advanced-color-picker";` - -## Source -- Export: `./components/advanced-color-picker` -- Props interface: `AdvancedColorPickerProps` - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| availableColors | AdvancedColor[] | Yes | | Prop for `availableColors` containing array of objects of colors | | -| name | string | Yes | | Specifies the name prop to be applied to each color in the group | | -| onChange | (ev: React.ChangeEvent) => void | Yes | | Prop for `onChange` event | | -| selectedColor | string | Yes | | Prop for `selectedColor` containing pre-selected color for `controlled` use | | -| m | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| onBlur | ((ev: React.FocusEvent) => void) \| undefined | No | | Prop for `onBlur` event | | -| onClose | ((ev: React.MouseEvent \| React.KeyboardEvent \| KeyboardEvent) => void) \| undefined | No | | Prop for `onClose` event | | -| onOpen | ((ev: React.MouseEvent \| React.KeyboardEvent) => void) \| undefined | No | | Prop for `onOpen` event | | -| open | boolean \| undefined | No | | Prop for `open` status | false | -| restoreFocusOnClose | boolean \| undefined | No | | Enables the automatic restoration of focus to the element that invoked the modal when the modal is closed. | true | -| role | string \| undefined | No | | The ARIA role to be applied to the component container | | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| aria-describedby | string \| undefined | No | | Prop to specify the aria-describedby property of the component | | -| aria-label | string \| undefined | No | | Prop to specify the aria-label of the component. To be used only when the title prop is not defined, and the component is not labelled by any internal element. | | -| aria-labelledby | string \| undefined | No | | Prop to specify the aria-labelledby property of the component To be used when the title prop is a custom React Node, or the component is labelled by an internal element other than the title. | | - -## Examples -### Default - -**Render** - -```tsx -() => { - const [open, setOpen] = useState(defaultOpenState); - const [color, setColor] = useState("orchid"); - const onChange = ({ target }: React.ChangeEvent) => { - setColor(target.value); - }; - return ( - { - setOpen(!open); - }} - onClose={() => { - setOpen(false); - }} - onBlur={() => {}} - open={open} - /> - ); -} -``` - - -### With Restore Focus Close - -**Render** - -```tsx -() => { - const [open, setOpen] = useState(false); - const [showMessage, setShowMessage] = useState(false); - const messageRef = useRef(null); - - const [color, setColor] = useState("orchid"); - const onChange = ({ target }: React.ChangeEvent) => { - setColor(target.value); - }; - return ( - <> - { - setOpen(!open); - setShowMessage(false); - }} - onClose={() => { - setOpen(false); - setShowMessage(true); - setTimeout(() => messageRef.current?.focus(), 1); - }} - onBlur={() => {}} - open={open} - mb={showMessage ? 5 : 0} - /> - {showMessage && ( - setShowMessage(false)} - > - Some custom message - - )} - - ); -} -``` - diff --git a/skills/carbon-react/components/alert.md b/skills/carbon-react/components/alert.md deleted file mode 100644 index 41c603c48a..0000000000 --- a/skills/carbon-react/components/alert.md +++ /dev/null @@ -1,87 +0,0 @@ ---- -name: carbon-component-alert -description: Carbon Alert component props and usage examples. ---- - -# Alert - -## Import -`import Alert from "carbon-react/lib/components/alert";` - -## Source -- Export: `./components/alert` -- Props interface: `DialogProps` -- Deprecated: Yes -- Deprecation reason: Alert has been deprecated. See the Carbon documentation for migration details. - -## Props -| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | -| --- | --- | --- | --- | --- | --- | --- | --- | -| open | boolean | Yes | | | | Sets the open state of the modal | | -| ariaRole | string \| undefined | No | | | | The ARIA role to be applied to the modal | | -| children | React.ReactNode | No | | | | Child elements | | -| closeButtonDataProps | Pick \| undefined | No | | | | Data tag prop bag for close Button | | -| contentPadding | ContentPaddingInterface \| undefined | No | | | | Padding to be set on the Dialog content | | -| contentRef | React.ForwardedRef \| undefined | No | | | | Reference to the scrollable content element | | -| disableAutoFocus | boolean \| undefined | No | | | | | | -| disableEscKey | boolean \| undefined | No | | | | Determines if the Esc Key closes the modal | | -| disableFocusTrap | boolean \| undefined | No | | | | | | -| disableStickyOnSmallScreen | boolean \| undefined | No | | | | When true, header and sticky footer become unstickied for accessibility on small screen devices. On small screen devices, the dialog becomes full width and has no dimmer. | | -| enableBackgroundUI | boolean \| undefined | No | | | | Determines if the background is disabled when the modal is open | | -| focusableContainers | React.RefObject[] \| undefined | No | | | | an optional array of refs to containers whose content should also be reachable by tabbing from the dialog | | -| focusableSelectors | string \| undefined | No | | | | Optional selector to identify the focusable elements, if not provided a default selector is used | | -| focusFirstElement | HTMLElement \| React.RefObject \| null \| undefined | No | | | | Optional reference to an element meant to be focused on open | | -| footer | React.ReactNode | No | | | | Footer content to be rendered at the bottom of the dialog | | -| gradientKeyLine | boolean \| undefined | No | | | | Adds a gradient keyline to the dialog header | | -| greyBackground | boolean \| undefined | No | | | | Change the background color of the content to grey | | -| headerChildren | React.ReactNode | No | | | | Container for components to be displayed in the header | | -| height | string \| undefined | No | | | | Allows developers to specify a specific height for the dialog. | | -| help | string \| undefined | No | | | | Adds Help tooltip to Header | | -| onCancel | ((ev: React.KeyboardEvent \| KeyboardEvent \| React.MouseEvent) => void) \| undefined | No | | | | A custom close event handler | | -| restoreFocusOnClose | boolean \| undefined | No | | | | Enables the automatic restoration of focus to the element that invoked the modal when the modal is closed. | | -| role | string \| undefined | No | | | | The ARIA role to be applied to the Dialog container | | -| showCloseIcon | boolean \| undefined | No | | | | Determines if the close icon is shown | | -| size | "auto" \| "extra-small" \| "medium-small" \| "medium-large" \| "extra-large" \| "maximise" \| Size \| undefined | No | | | | Size — accepts both legacy values (extra-small, medium-small, etc.) and new values (small, medium, large, fullscreen). | "extra-small" | -| stickyFooter | boolean \| undefined | No | | | | Makes the footer stick to the bottom of the dialog when content scrolls | | -| subtitle | React.ReactNode | No | | | | Subtitle displayed at top of dialog. Its consumers' responsibility to set a suitable accessible name/description for the Dialog if they pass a node to subtitle prop. | | -| title | React.ReactNode | No | | | | Title displayed at top of dialog. Its consumers' responsibility to set a suitable accessible name/description for the Dialog if they pass a node to title prop. | | -| topModalOverride | boolean \| undefined | No | | | | Manually override the internal modal stacking order to set this as top | | -| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| aria-describedby | string \| undefined | No | | | | Prop to specify the aria-describedby property of the Dialog component | | -| aria-label | string \| undefined | No | | | | Prop to specify the aria-label of the Dialog component. To be used only when the title prop is not defined, and the component is not labelled by any internal element. | | -| aria-labelledby | string \| undefined | No | | | | Prop to specify the aria-labelledby property of the Dialog component To be used when the title prop is a custom React Node, or the component is labelled by an internal element other than the title. | | -| disableClose | boolean \| undefined | No | | Yes | Use `showCloseIcon={false}` instead. | | | -| disableContentPadding | boolean \| undefined | No | | Yes | Use `contentPadding` instead. | | | -| fullscreen | boolean \| undefined | No | | Yes | Use `size="fullscreen"` instead. | | | -| highlightVariant | string \| undefined | No | | Yes | Use `gradientKeyLine` instead. | | | -| pagesStyling | boolean \| undefined | No | | Yes | PagesStyling is now deprecated and will be removed in a future release | | | - -## Examples -### Default - -**Render** - -```tsx -() => { - const [isOpen, setIsOpen] = useState(defaultOpenState); - return ( - <> - - setIsOpen(false)} - title="Title" - disableEscKey={false} - height="" - subtitle="Subtitle" - showCloseIcon - size="extra-small" - open={isOpen} - > - This is an example of an alert - - - ); -} -``` - diff --git a/skills/carbon-react/components/anchor-navigation-item.md b/skills/carbon-react/components/anchor-navigation-item.md deleted file mode 100644 index 8e28380206..0000000000 --- a/skills/carbon-react/components/anchor-navigation-item.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -name: carbon-component-anchor-navigation-item -description: Carbon AnchorNavigationItem component props and usage examples. ---- - -# AnchorNavigationItem - -## Import -`import { AnchorNavigationItem } from "carbon-react/lib/components/anchor-navigation";` - -## Source -- Export: `./components/anchor-navigation` -- Props interface: `AnchorNavigationItemProps` - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | No | | Children elements | | -| href | string \| undefined | No | | href to be passed to the anchor element, can be linked with id passed to the scrollable section | | -| isSelected | boolean \| undefined | No | | Indicates if a component is selected | | -| onClick | ((ev: React.MouseEvent) => void) \| undefined | No | | onClick handler | | -| onKeyDown | ((ev: React.KeyboardEvent) => void) \| undefined | No | | OnKeyDown handler | | -| tabIndex | number \| undefined | No | | tabIndex passed to the anchor element | | -| target | React.RefObject \| undefined | No | | Reference to the section html element meant to be shown | | - -## Examples -### Default - -**Args** - -```tsx -{ - children: [], - } -``` - diff --git a/skills/carbon-react/components/anchor-navigation.md b/skills/carbon-react/components/anchor-navigation.md deleted file mode 100644 index df0ae02bbd..0000000000 --- a/skills/carbon-react/components/anchor-navigation.md +++ /dev/null @@ -1,181 +0,0 @@ ---- -name: carbon-component-anchor-navigation -description: Carbon AnchorNavigation component props and usage examples. ---- - -# AnchorNavigation - -## Import -`import { AnchorNavigation } from "carbon-react/lib/components/anchor-navigation";` - -## Source -- Export: `./components/anchor-navigation` -- Props interface: `AnchorNavigationProps` - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | No | | Child elements | | -| stickyNavigation | React.ReactNode | No | | The AnchorNavigationItems components to be rendered in the sticky navigation. It is important to maintain proper structure. List of AnchorNavigationItems has to be wrapped in React.Fragment | | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| aria-label | string \| undefined | No | | Defines a string value that labels the current element. | | -| aria-labelledby | string \| undefined | No | | Identifies the element (or elements) that labels the current element. | | - -## Examples -### Default - -**Render** - -```tsx -() => { - const Content = ({ title, noTextbox }: ContentProps) => ( - -

{title}

- {!noTextbox && {}} />} -

Content

-

Content

-

Content

-

Content

-

Content

-

Content

-
- ); - - const ref1 = useRef(null); - const ref2 = useRef(null); - const ref3 = useRef(null); - const ref4 = useRef(null); - const ref5 = useRef(null); - return ( - - First - Second - Third - - Navigation item with very long label - - Fifth - - } - > - - - - - - - - - - - - - - - - - - - - - ); -} -``` - - -### In Full Screen Dialog - -**Render** - -```tsx -() => { - const Content = ({ title, noTextbox }: ContentProps) => ( - -

{title}

- {!noTextbox && {}} />} -

Content

-

Content

-

Content

-

Content

-

Content

-

Content

-
- ); - - const [isOpen, setIsOpen] = useState(false); - const ref1 = useRef(null); - const ref2 = useRef(null); - const ref3 = useRef(null); - const ref4 = useRef(null); - const ref5 = useRef(null); - return ( - <> - - setIsOpen(false)} - title="Title" - subtitle="Subtitle" - > - - First - Second - Third - - Navigation item with very long label - - Fifth - - } - > - - - - - - - - - - - - - - - - - - - - - - - ); -} -``` - - -### MDX Example 1 - -**Args** - -```tsx -- Create `refs` which will be used internally in `AnchorNavigation` to measure positions of the elements. - -- Pass proper structure of `AnchorNavigationItem`'s with assigned `refs` to `stickyNavigation` prop. - -- Pass children where elements which are meant to serve as sections have `refs` assigned. - -- Keep in mind that to assign a `ref` to a component it either has to be a `Class` component or it has to be wrapped in `React.forwardRef()` in case of a function component. - -- **It is necessary to maintain the same order of navigation items and children when assigning the `refs`** - -- **It is necessary to maintain `stickyNavigation` prop structure as shown below** -``` - diff --git a/skills/carbon-react/components/anchor-section-divider.md b/skills/carbon-react/components/anchor-section-divider.md deleted file mode 100644 index 6e36c0a9ad..0000000000 --- a/skills/carbon-react/components/anchor-section-divider.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: carbon-component-anchor-section-divider -description: Carbon AnchorSectionDivider component props and usage examples. ---- - -# AnchorSectionDivider - -## Import -`import { AnchorSectionDivider } from "carbon-react/lib/components/anchor-navigation";` - -## Source -- Export: `./components/anchor-navigation` -- Props interface: not found - -## Props -No props metadata found. - -## Examples -No Storybook examples found. \ No newline at end of file diff --git a/skills/carbon-react/components/badge.md b/skills/carbon-react/components/badge.md deleted file mode 100644 index e444df0b8f..0000000000 --- a/skills/carbon-react/components/badge.md +++ /dev/null @@ -1,228 +0,0 @@ ---- -name: carbon-component-badge -description: Carbon Badge component props and usage examples. ---- - -# Badge - -## Import -`import Badge from "carbon-react/lib/components/badge";` - -## Source -- Export: `./components/badge` -- Props interface: `BadgeProps` - -## Props -| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | -| --- | --- | --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | No | | | | The badge will be positioned relative to this element | | -| counter | string \| number \| undefined | No | | | | The number rendered in the badge component | 0 | -| id | string \| undefined | No | | | | Unique identifier for the component. | | -| inverse | boolean \| undefined | No | | | | Set the style of the Badge to inverse | false | -| m | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| size | "small" \| "medium" \| "large" \| undefined | No | | | | Size of the badge | "medium" | -| variant | "subtle" \| "typical" \| undefined | No | | | | Badge variant | "typical" | -| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| color | string \| undefined | No | | Yes | Prop to specify the color of the component | | | -| onClick | ((ev: React.MouseEvent) => void) \| undefined | No | | Yes | Callback fired when badge is clicked | | | -| aria-label | string \| undefined | No | | Yes | Prop to specify an aria-label for the component | | | - -## Examples -### Default - -**Render** - -```tsx -({ ...args }) => { - return ( - <> - - - - - - ); -} -``` - - -### With Children - -**Render** - -```tsx -({ ...args }) => { - return ( - - - - ); -} -``` - - -### Sizes - -**Render** - -```tsx -({ ...args }) => { - return ( - <> - - - - - - - ); -} -``` - - -### Subtle Variant - -**Args** - -```tsx -{ - variant: "subtle", -} -``` - -**Render** - -```tsx -({ ...args }) => { - return ( - <> - - - - - - - ); -} -``` - - -### Inverse - -**Args** - -```tsx -{ - inverse: true, -} -``` - -**Render** - -```tsx -({ ...args }) => { - return ( - <> - - - - - - - - - - - - - ); -} -``` - - -### With OnClick - -**Render** - -```tsx -({ ...args }) => { - const counter = 9; - return ( - {}} - aria-label={`Remove ${counter} filters.`} - {...args} - > - - - ); -} -``` - - -### Custom Color - -**Render** - -```tsx -({ ...args }) => { - const counter = 9; - return ( - {}} - aria-label={`Remove ${counter} filters.`} - color="--colorsSemanticNegative500" - {...args} - > - - - ); -} -``` - diff --git a/skills/carbon-react/components/batch-selection.md b/skills/carbon-react/components/batch-selection.md deleted file mode 100644 index 92481b18a4..0000000000 --- a/skills/carbon-react/components/batch-selection.md +++ /dev/null @@ -1,150 +0,0 @@ ---- -name: carbon-component-batch-selection -description: Carbon BatchSelection component props and usage examples. ---- - -# BatchSelection - -## Import -`import BatchSelection from "carbon-react/lib/components/batch-selection";` - -## Source -- Export: `./components/batch-selection` -- Props interface: `BatchSelectionProps` - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | Yes | | Content to be rendered after selected count | | -| selectedCount | number | Yes | | Number of selected elements | | -| colorTheme | "white" \| "dark" \| "light" \| "transparent" \| undefined | No | | Color of the background, transparent if not defined | "transparent" | -| disabled | boolean \| undefined | No | | If true disables all user interaction | false | -| hidden | boolean \| undefined | No | | Hidden if true | | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | - -## Examples -### Default - -**Render** - -```tsx -() => { - return ( - - - {}}> - - - {}}> - - - {}}> - - - - ); -} -``` - - -### Dark - -**Render** - -```tsx -() => { - return ( - - {}}> - - - {}}> - - - {}}> - - - - ); -} -``` - - -### Light - -**Render** - -```tsx -() => { - return ( - - {}}> - - - {}}> - - - {}}> - - - - ); -} -``` - - -### White - -**Render** - -```tsx -() => { - return ( - - {}}> - - - {}}> - - - {}}> - - - - ); -} -``` - - -### Disabled - -**Render** - -```tsx -() => { - return ( - - {}}> - - - {}}> - - - {}}> - - - - This is a link - {}}> - This is actually a button but looks like a link - - - ); -} -``` - diff --git a/skills/carbon-react/components/box.md b/skills/carbon-react/components/box.md deleted file mode 100644 index 434df64914..0000000000 --- a/skills/carbon-react/components/box.md +++ /dev/null @@ -1,535 +0,0 @@ ---- -name: carbon-component-box -description: Carbon Box component props and usage examples. ---- - -# Box - -## Import -`import Box from "carbon-react/lib/components/box";` - -## Source -- Export: `./components/box` -- Props interface: `BoxProps` - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| alignContent | ResponsiveValue \| undefined | No | | The CSS align-content property sets how the browser distributes space between and around content items along the cross-axis of a flexbox container, and the main-axis of a grid container. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/align-content) | | -| alignItems | ResponsiveValue \| undefined | No | | The CSS align-items property sets the align-self value on all direct children as a group. The align-self property sets the alignment of an item within its containing block. In Flexbox it controls the alignment of items on the Cross Axis, in Grid Layout it controls the alignment of items on the Block Axis within their grid area. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/align-items) | | -| alignSelf | ResponsiveValue \| undefined | No | | The align-self CSS property aligns flex items of the current flex line overriding the align-items value. If any of the item's cross-axis margin is set to auto, then align-self is ignored. In Grid layout align-self aligns the item inside the grid area. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/align-self) | | -| as | keyof JSX.IntrinsicElements \| React.ComponentType \| undefined | No | | | | -| backgroundColor | string \| undefined | No | | Set the backgroundColor attribute of the Box component | | -| bg | string \| undefined | No | | Set the bg attribute of the Box component | | -| borderRadius | BorderRadiusType \| undefined | No | | Design Token for Border Radius. Note: please check that the border radius design token you are using is compatible with the Box component. | | -| bottom | ResponsiveValue \| undefined | No | | The bottom CSS property participates in specifying the vertical position of a positioned element. It has no effect on non-positioned elements. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/top) | | -| boxShadow | BoxShadowsType \| undefined | No | | Design Token for Box Shadow. Note: please check that the box shadow design token you are using is compatible with the Box component. | | -| boxSizing | BoxSizing \| undefined | No | | Set the box-sizing attribute of the Box component | | -| children | React.ReactNode | No | | Content to be rendered inside the Box component | | -| color | string \| undefined | No | | Set the color attribute of the Box component | | -| columnGap | Gap \| undefined | No | | Column gap, an integer multiplier of the base spacing constant (8px) or any valid CSS string." | | -| display | ResponsiveValue \| undefined | No | | The display CSS property defines the display type of an element, which consists of the two basic qualities of how an element generates boxes — the outer display type defining how the box participates in flow layout, and the inner display type defining how the children of the box are laid out. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/display) | | -| flex | ResponsiveValue \| undefined | No | | The flex CSS property specifies how a flex item will grow or shrink so as to fit the space available in its flex container. This is a shorthand property that sets flex-grow, flex-shrink, and flex-basis. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/flex) | | -| flexBasis | ResponsiveValue \| undefined | No | | | | -| flexDirection | ResponsiveValue \| undefined | No | | The flex-direction CSS property specifies how flex items are placed in the flex container defining the main axis and the direction (normal or reversed). [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction) | | -| flexGrow | ResponsiveValue \| undefined | No | | The flex-grow CSS property sets the flex grow factor of a flex item main size. It specifies how much of the remaining space in the flex container should be assigned to the item (the flex grow factor). [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/flex-grow) | | -| flexShrink | ResponsiveValue \| undefined | No | | The flex-shrink CSS property sets the flex shrink factor of a flex item. If the size of all flex items is larger than the flex container, items shrink to fit according to flex-shrink. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/flex-shrink) | | -| flexWrap | ResponsiveValue \| undefined | No | | The flex-wrap CSS property sets whether flex items are forced onto one line or can wrap onto multiple lines. If wrapping is allowed, it sets the direction that lines are stacked. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/flex-wrap) | | -| gap | Gap \| undefined | No | | Gap, an integer multiplier of the base spacing constant (8px) or any valid CSS string." | | -| gridArea | ResponsiveValue \| undefined | No | | The grid-area CSS property is a shorthand property for grid-row-start, grid-column-start, grid-row-end and grid-column-end, specifying a grid item’s size and location within the grid row by contributing a line, a span, or nothing (automatic) to its grid placement, thereby specifying the edges of its grid area. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-area) | | -| gridAutoColumns | ResponsiveValue \| undefined | No | | The grid-auto-columns CSS property specifies the size of an implicitly-created grid column track. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-columns) | | -| gridAutoFlow | ResponsiveValue \| undefined | No | | The grid-auto-flow CSS property controls how the auto-placement algorithm works, specifying exactly how auto-placed items get flowed into the grid. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow) | | -| gridAutoRows | ResponsiveValue \| undefined | No | | The grid-auto-rows CSS property specifies the size of an implicitly-created grid row track. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-rows) | | -| gridColumn | ResponsiveValue \| undefined | No | | The grid-column CSS property is a shorthand property for grid-column-start and grid-column-end specifying a grid item's size and location within the grid column by contributing a line, a span, or nothing (automatic) to its grid placement, thereby specifying the inline-start and inline-end edge of its grid area. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column) | | -| gridRow | ResponsiveValue \| undefined | No | | The grid-row CSS property is a shorthand property for grid-row-start and grid-row-end specifying a grid item’s size and location within the grid row by contributing a line, a span, or nothing (automatic) to its grid placement, thereby specifying the inline-start and inline-end edge of its grid area. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row) | | -| gridTemplateAreas | ResponsiveValue \| undefined | No | | The grid-template-areas CSS property specifies named grid areas. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-areas) | | -| gridTemplateColumns | ResponsiveValue \| undefined | No | | The grid-template-columns CSS property defines the line names and track sizing functions of the grid columns. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns) | | -| gridTemplateRows | ResponsiveValue \| undefined | No | | The grid-template-rows CSS property defines the line names and track sizing functions of the grid rows. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/row-template-rows) | | -| height | ResponsiveValue \| undefined | No | | The height CSS property specifies the height of an element. By default, the property defines the height of the content area. If box-sizing is set to border-box, however, it instead determines the height of the border area. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/height) | | -| hidden | boolean \| undefined | No | | Whether the component is hidden from view. In this state, the component will not be visible to users but will remain in the HTML document | | -| id | string \| undefined | No | | Set the ID attribute of the Box component | | -| justifyContent | ResponsiveValue \| undefined | No | | The CSS justify-content property defines how the browser distributes space between and around content items along the main-axis of a flex container, and the inline axis of a grid container. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content) | | -| justifyItems | ResponsiveValue \| undefined | No | | The CSS justify-items property defines the default justify-self for all items of the box, giving them all a default way of justifying each box along the appropriate axis. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/justify-items) | | -| justifySelf | ResponsiveValue \| undefined | No | | The CSS justify-self property set the way a box is justified inside its alignment container along the appropriate axis. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/justify-self) | | -| left | ResponsiveValue \| undefined | No | | The left CSS property participates in specifying the horizontal position of a positioned element. It has no effect on non-positioned elements. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/left) | | -| m | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| maxHeight | ResponsiveValue \| undefined | No | | The max-height CSS property sets the maximum height of an element. It prevents the used value of the height property from becoming larger than the value specified for max-height. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/max-height) | | -| maxWidth | ResponsiveValue \| undefined | No | | The max-width CSS property sets the maximum width of an element. It prevents the used value of the width property from becoming larger than the value specified by max-width. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/max-width) | | -| mb | ResponsiveValue \| undefined | No | | Margin on bottom | | -| minHeight | ResponsiveValue \| undefined | No | | The min-height CSS property sets the minimum height of an element. It prevents the used value of the height property from becoming smaller than the value specified for min-height. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/display) | | -| minWidth | ResponsiveValue \| undefined | No | | The min-width CSS property sets the minimum width of an element. It prevents the used value of the width property from becoming smaller than the value specified for min-width. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/min-width) | | -| ml | ResponsiveValue \| undefined | No | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| opacity | string \| number \| undefined | No | | Set the opacity attribute of the Box component | | -| order | ResponsiveValue \| undefined | No | | The order CSS property sets the order to lay out an item in a flex or grid container. Items in a container are sorted by ascending order value and then by their source code order. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/order) | | -| overflow | ResponsiveValue \| undefined | No | | The overflow CSS property sets what to do when an element's content is too big to fit in its block formatting context. It is a shorthand for overflow-x and overflow-y. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/overflow) | | -| overflowWrap | OverflowWrap \| undefined | No | | String to set Box content break strategy. Note "anywhere" is not supported in Safari | | -| overflowX | ResponsiveValue \| undefined | No | | The overflow-x CSS property sets what shows when content overflows a block-level element's left and right edges. This may be nothing, a scroll bar, or the overflow content. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-x) | | -| overflowY | ResponsiveValue \| undefined | No | | The overflow-y CSS property sets what shows when content overflows a block-level element's top and bottom edges. This may be nothing, a scroll bar, or the overflow content. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-y) | | -| p | ResponsiveValue \| undefined | No | | Padding on top, left, bottom and right | | -| padding | ResponsiveValue \| undefined | No | | Padding on top, left, bottom and right | | -| paddingBottom | ResponsiveValue \| undefined | No | | Padding on bottom | | -| paddingLeft | ResponsiveValue \| undefined | No | | Padding on left | | -| paddingRight | ResponsiveValue \| undefined | No | | Padding on right | | -| paddingTop | ResponsiveValue \| undefined | No | | Padding on top | | -| paddingX | ResponsiveValue \| undefined | No | | Padding on left and right | | -| paddingY | ResponsiveValue \| undefined | No | | Padding on top and bottom | | -| pb | ResponsiveValue \| undefined | No | | Padding on bottom | | -| pl | ResponsiveValue \| undefined | No | | Padding on left | | -| position | ResponsiveValue \| undefined | No | | The position CSS property specifies how an element is positioned in a document. The top, right, bottom, and left properties determine the final location of positioned elements. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/position) | | -| pr | ResponsiveValue \| undefined | No | | Padding on right | | -| pt | ResponsiveValue \| undefined | No | | Padding on top | | -| px | ResponsiveValue \| undefined | No | | Padding on left and right | | -| py | ResponsiveValue \| undefined | No | | Padding on top and bottom | | -| right | ResponsiveValue \| undefined | No | | The right CSS property participates in specifying the horizontal position of a positioned element. It has no effect on non-positioned elements. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/right) | | -| role | string \| undefined | No | | Set the Role attribute of the Box component | | -| rowGap | Gap \| undefined | No | | Row gap an integer multiplier of the base spacing constant (8px) or any valid CSS string." | | -| scrollVariant | ScrollVariant \| undefined | No | | Scroll styling attribute | | -| size | ResponsiveValue \| undefined | No | | | | -| top | ResponsiveValue \| undefined | No | | The top CSS property participates in specifying the vertical position of a positioned element. It has no effect on non-positioned elements. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/top) | | -| verticalAlign | ResponsiveValue \| undefined | No | | The vertical-align CSS property specifies sets vertical alignment of an inline or table-cell box. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align) | | -| width | ResponsiveValue \| undefined | No | | The width utility parses a component's `width` prop and converts it into a CSS width declaration. - Numbers from 0-1 are converted to percentage widths. - Numbers greater than 1 are converted to pixel values. - String values are passed as raw CSS values. - And arrays are converted to responsive width styles. | | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| aria-atomic | "true" \| "false" \| undefined | No | | Indicates whether AT will announce all, or only parts of, the changed region | | -| aria-hidden | "true" \| "false" \| undefined | No | | Set the container to be hidden from screen readers | | -| aria-live | "off" \| "assertive" \| "polite" \| undefined | No | | Make the container an aria-live region | | - -## Examples -### Spacing - -**Render** - -```tsx -() => { - return ( - - - - ); -} -``` - - -### Position - -**Render** - -```tsx -() => { - return ( - - - - This box has position sticky - - - - - This box has position sticky - - - - - - This box has position fixed - - - - ); -} -``` - - -### Color - -**Render** - -```tsx -() => { - return ( - - - This is some sample text - - - ); -} -``` - - -### Box Shadow - -**Render** - -```tsx -() => { - return ( - - ); -} -``` - - -### Flex - -**Render** - -```tsx -() => { - return ( - - - - - - - - - - - - - ); -} -``` - - -### Grid - -**Render** - -```tsx -() => { - return ( - - - - - - - - - - - - - - - - ); -} -``` - - -### Gap - -**Render** - -```tsx -() => { - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -} -``` - - -### Layout - -**Render** - -```tsx -() => { - return ( - - - - - - ); -} -``` - - -### OverflowWrap - -**Render** - -```tsx -() => { - return ( - -
- - WithOverflowWrap - -
-
- - WithoutOverflowWrap - -
-
- ); -} -``` - - -### Scroll - -**Render** - -```tsx -() => { - return ( -
- - - - - - - - - - - - -
- ); -} -``` - - -### Rounded Corners - -**Render** - -```tsx -() => { - const radiusTokens: BoxProps["borderRadius"][] = [ - "borderRadius000", - "borderRadius010", - "borderRadius025", - "borderRadius050", - "borderRadius100", - "borderRadius200", - "borderRadius400", - "borderRadiusCircle", - ]; - - return ( - - {radiusTokens.map((token) => ( - - ))} - - ); -} -``` - diff --git a/skills/carbon-react/components/breadcrumbs.md b/skills/carbon-react/components/breadcrumbs.md deleted file mode 100644 index 9b7fbcb320..0000000000 --- a/skills/carbon-react/components/breadcrumbs.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -name: carbon-component-breadcrumbs -description: Carbon Breadcrumbs component props and usage examples. ---- - -# Breadcrumbs - -## Import -`import { Breadcrumbs } from "carbon-react/lib/components/breadcrumbs";` - -## Source -- Export: `./components/breadcrumbs` -- Props interface: `BreadcrumbsProps` - -## Props -| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | -| --- | --- | --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | Yes | | | | Child crumbs to display | | -| inverse | boolean \| undefined | No | | | | Sets the colour styling when component is to be rendered with inverse styles | | -| m | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| p | ResponsiveValue \| undefined | No | | | | Padding on top, left, bottom and right | | -| padding | ResponsiveValue \| undefined | No | | | | Padding on top, left, bottom and right | | -| paddingBottom | ResponsiveValue \| undefined | No | | | | Padding on bottom | | -| paddingLeft | ResponsiveValue \| undefined | No | | | | Padding on left | | -| paddingRight | ResponsiveValue \| undefined | No | | | | Padding on right | | -| paddingTop | ResponsiveValue \| undefined | No | | | | Padding on top | | -| paddingX | ResponsiveValue \| undefined | No | | | | Padding on left and right | | -| paddingY | ResponsiveValue \| undefined | No | | | | Padding on top and bottom | | -| pb | ResponsiveValue \| undefined | No | | | | Padding on bottom | | -| pl | ResponsiveValue \| undefined | No | | | | Padding on left | | -| pr | ResponsiveValue \| undefined | No | | | | Padding on right | | -| pt | ResponsiveValue \| undefined | No | | | | Padding on top | | -| px | ResponsiveValue \| undefined | No | | | | Padding on left and right | | -| py | ResponsiveValue \| undefined | No | | | | Padding on top and bottom | | -| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| isDarkBackground | boolean \| undefined | No | | Yes | The 'isDarkBackground' prop in Breadcrumbs is deprecated and will soon be removed. Please use the 'inverse' prop instead. | Sets the colour styling when component is rendered on a dark background | | - -## Examples -### Default - -**Render** - -```tsx -({ ...args }) => { - return ( - - Breadcrumb 1 - Breadcrumb 2 - Breadcrumb 3 - - Current Page - - - ); - } -``` - - -### Inverse - -**Args** - -```tsx -{ - inverse: true, - } -``` - -**Render** - -```tsx -({ ...args }) => { - return ( - - - Breadcrumb 1 - Breadcrumb 2 - Breadcrumb 3 - - Current Page - - - - ); - } -``` - diff --git a/skills/carbon-react/components/button-bar.md b/skills/carbon-react/components/button-bar.md deleted file mode 100644 index 6ded299e9e..0000000000 --- a/skills/carbon-react/components/button-bar.md +++ /dev/null @@ -1,317 +0,0 @@ ---- -name: carbon-component-button-bar -description: Carbon ButtonBar component props and usage examples. ---- - -# ButtonBar - -## Import -`import ButtonBar from "carbon-react/lib/components/button-bar";` - -## Source -- Export: `./components/button-bar` -- Props interface: `ButtonBarProps` -- Deprecated: Yes -- Deprecation reason: `ButtonBar` has been deprecated. See the Carbon documentation for migration details. - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | Yes | | Button or IconButton Elements, to be rendered inside the component | | -| buttonType | "primary" \| "secondary" \| undefined | No | | Color variants for new business themes: "primary" \| "secondary" \| "tertiary" \| "darkBackground" | | -| fullWidth | boolean \| undefined | No | | Apply fullWidth style to the button bar | false | -| iconPosition | "before" \| "after" \| undefined | No | | Defines an Icon position for buttons: "before" \| "after" | "before" | -| m | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| p | ResponsiveValue \| undefined | No | | Padding on top, left, bottom and right | | -| padding | ResponsiveValue \| undefined | No | | Padding on top, left, bottom and right | | -| paddingBottom | ResponsiveValue \| undefined | No | | Padding on bottom | | -| paddingLeft | ResponsiveValue \| undefined | No | | Padding on left | | -| paddingRight | ResponsiveValue \| undefined | No | | Padding on right | | -| paddingTop | ResponsiveValue \| undefined | No | | Padding on top | | -| paddingX | ResponsiveValue \| undefined | No | | Padding on left and right | | -| paddingY | ResponsiveValue \| undefined | No | | Padding on top and bottom | | -| pb | ResponsiveValue \| undefined | No | | Padding on bottom | | -| pl | ResponsiveValue \| undefined | No | | Padding on left | | -| pr | ResponsiveValue \| undefined | No | | Padding on right | | -| pt | ResponsiveValue \| undefined | No | | Padding on top | | -| px | ResponsiveValue \| undefined | No | | Padding on left and right | | -| py | ResponsiveValue \| undefined | No | | Padding on top and bottom | | -| size | "small" \| "medium" \| "large" \| undefined | No | | Assigns a size to the buttons: "small" \| "medium" \| "large" | "medium" | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | - -## Examples -### Sizes - -**Render** - -```tsx -() => { - return ( - <> - - - - - - - - - - - - - - - - - - - - - - ); -} -``` - - -### Minor Sizes - -**Render** - -```tsx -() => { - return ( - <> - - Small - Small - Small - - - - Medium - Medium - Medium - - - - Large - Large - Large - - - - Large - Large - Large - - - ); -} -``` - - -### Icons - -**Render** - -```tsx -() => { - const BUTTON_BAR_SIZES = ["small", "medium", "large"] as const; - const BUTTON_BAR_ICON_POSITIONS = ["before", "after"] as const; - - return ( - <> - {BUTTON_BAR_ICON_POSITIONS.map((iconPosition) => - BUTTON_BAR_SIZES.map((size) => ( - - - - - - )), - )} - - ); -} -``` - - -### Minor Icons - -**Render** - -```tsx -() => { - const BUTTON_BAR_SIZES = ["small", "medium", "large"] as const; - const BUTTON_BAR_ICON_POSITIONS = ["before", "after"] as const; - - return ( - <> - {BUTTON_BAR_ICON_POSITIONS.map((iconPosition) => - BUTTON_BAR_SIZES.map((size) => ( - - {iconPosition} - {iconPosition} - {iconPosition} - - )), - )} - - ); -} -``` - - -### Icons Only - -**Render** - -```tsx -() => { - const BUTTON_BAR_SIZES = ["small", "medium", "large"] as const; - - return ( - <> - {BUTTON_BAR_SIZES.map((size) => ( - - - - - - - - - - - - - - - - - ); -} -``` - - -### Minor Full Width - -**Render** - -```tsx -() => { - return ( - <> - - Small full width - Small full width - Small full width - - - Medium full width - Medium full width - Medium full width - - - Large full width - Large full width - Large full width - - - ); -} -``` - diff --git a/skills/carbon-react/components/button-minor.md b/skills/carbon-react/components/button-minor.md deleted file mode 100644 index 1f2f720fce..0000000000 --- a/skills/carbon-react/components/button-minor.md +++ /dev/null @@ -1,599 +0,0 @@ ---- -name: carbon-component-button-minor -description: Carbon ButtonMinor component props and usage examples. ---- - -# ButtonMinor - -## Import -`import ButtonMinor from "carbon-react/lib/components/button-minor/button-minor.component";` - -## Source -- Export: `./components/button-minor/button-minor.component` -- Props interface: `ButtonMinorProps` -- Deprecated: Yes -- Deprecation reason: `ButtonMinor` has been deprecated. See the Carbon documentation for migration details. - -## Props -| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | -| --- | --- | --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | No | | | | The text the button displays | | -| disabled | boolean \| undefined | No | | | | Apply disabled state to the button | | -| fullWidth | boolean \| undefined | No | | | | Apply fullWidth style to the button | | -| iconPosition | ButtonIconPosition \| undefined | No | | | | Defines an Icon position related to the children: "before" \| "after" | | -| iconType | IconType \| undefined | No | | | | Defines an Icon type within the button | | -| id | string \| undefined | No | | | | id attribute | | -| m | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| name | string \| undefined | No | | | | Name attribute | | -| noWrap | boolean \| undefined | No | | | | If provided, the text inside a button will not wrap | | -| onBlur | ((ev: React.FocusEvent) => void) \| undefined | No | | | | Specify a callback triggered on blur | | -| onChange | ((ev: React.FormEvent \| React.ChangeEvent) => void) \| undefined | No | | | | Specify a callback triggered on change | | -| onClick | ((ev: React.MouseEvent \| React.MouseEvent) => void) \| undefined | No | | | | onClick handler | | -| onFocus | ((ev: React.FocusEvent) => void) \| undefined | No | | | | Specify a callback triggered on focus | | -| onKeyDown | ((ev: React.KeyboardEvent) => void) \| undefined | No | | | | Specify a callback triggered on keyDown | | -| p | ResponsiveValue \| undefined | No | | | | Padding on top, left, bottom and right | | -| padding | ResponsiveValue \| undefined | No | | | | Padding on top, left, bottom and right | | -| paddingBottom | ResponsiveValue \| undefined | No | | | | Padding on bottom | | -| paddingLeft | ResponsiveValue \| undefined | No | | | | Padding on left | | -| paddingRight | ResponsiveValue \| undefined | No | | | | Padding on right | | -| paddingTop | ResponsiveValue \| undefined | No | | | | Padding on top | | -| paddingX | ResponsiveValue \| undefined | No | | | | Padding on left and right | | -| paddingY | ResponsiveValue \| undefined | No | | | | Padding on top and bottom | | -| pb | ResponsiveValue \| undefined | No | | | | Padding on bottom | | -| pl | ResponsiveValue \| undefined | No | | | | Padding on left | | -| pr | ResponsiveValue \| undefined | No | | | | Padding on right | | -| pt | ResponsiveValue \| undefined | No | | | | Padding on top | | -| px | ResponsiveValue \| undefined | No | | | | Padding on left and right | | -| py | ResponsiveValue \| undefined | No | | | | Padding on top and bottom | | -| size | SizeOptions \| undefined | No | | | | Assigns a size to the button: "small" \| "medium" \| "large" | | -| type | string \| undefined | No | | | | HTML button type property | | -| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| aria-describedby | string \| undefined | No | | | | Identifies the element(s) offering additional information about the button the user might require. | | -| aria-label | string \| undefined | No | | | | Prop to specify the aria-label attribute of the component Defaults to the iconType, when the component has only an icon | | -| aria-labelledby | string \| undefined | No | | | | Identifies the element(s) labelling the button. | | -| buttonType | ButtonTypes \| undefined | No | | Yes | Color variants for new business themes: "primary" \| "secondary" \| "tertiary" \| "darkBackground" | | | -| destructive | boolean \| undefined | No | | Yes | Apply destructive style to the button | | | -| href | string \| undefined | No | | Yes | Used to transform button into anchor | | | -| iconTooltipMessage | string \| undefined | No | | Yes | [Legacy] Provides a tooltip message when the icon is hovered. | | | -| iconTooltipPosition | TooltipPositions \| undefined | No | | Yes | [Legacy] Provides positioning when the tooltip is displayed. | | | -| isWhite | boolean \| undefined | No | | Yes | Whether to use the white-on-dark colour variant | | | -| rel | string \| undefined | No | | Yes | HTML rel attribute | | | -| subtext | string \| undefined | No | | Yes | Second text child, renders under main text, only when size is "large" | | | -| target | string \| undefined | No | | Yes | HTML target attribute | | | - -## Examples -### Primary - -**Render** - -```tsx -() => { - return ( - <> - - Small - - - Medium - - - Large - - - ); -} -``` - - -### Primary/Destructive - -**Render** - -```tsx -() => { - return ( - <> - - Small - - - Medium - - - Large - - - ); -} -``` - - -### Primary/Disabled - -**Render** - -```tsx -() => { - return ( - <> - - Small - - - Medium - - - Large - - - ); -} -``` - - -### Primary/Icon - -**Render** - -```tsx -() => { - return ( - <> - - Medium - - - Medium - - - Medium - - - ); -} -``` - - -### Primary/Full Width - -**Render** - -```tsx -() => { - return ( - - Full Width - - ); -} -``` - - -### Primary/No Wrap - -**Render** - -```tsx -() => { - return ( - - Long button text - - ); -} -``` - - -### Secondary - -**Render** - -```tsx -() => { - return ( - <> - - Small - - - Medium - - - Large - - - ); -} -``` - - -### Secondary/Destructive - -**Render** - -```tsx -() => { - return ( - <> - - Small - - - Medium - - - Large - - - ); -} -``` - - -### Secondary/Disabled - -**Render** - -```tsx -() => { - return ( - <> - - Small - - - Medium - - - Large - - - ); -} -``` - - -### Secondary/Icon - -**Render** - -```tsx -() => { - return ( - <> - - Medium - - - Medium - - - Medium - - - ); -} -``` - - -### Secondary/Full Width - -**Render** - -```tsx -() => { - return ( - - Full Width - - ); -} -``` - - -### Secondary/No Wrap - -**Render** - -```tsx -() => { - return ( - - Long button text - - ); -} -``` - - -### Tertiary - -**Render** - -```tsx -() => { - return ( - <> - - Small - - - Medium - - - Large - - - ); -} -``` - - -### Tertiary/Destructive - -**Render** - -```tsx -() => { - return ( - <> - - Small - - - Medium - - - Large - - - ); -} -``` - - -### Tertiary/Disabled - -**Render** - -```tsx -() => { - return ( - <> - - Small - - - Medium - - - Large - - - ); -} -``` - - -### Tertiary/Icon - -**Render** - -```tsx -() => { - return ( - <> - - Medium - - - Medium - - - Medium - - - ); -} -``` - - -### Tertiary/Full Width - -**Render** - -```tsx -() => { - return ( - - Full Width - - ); -} -``` - - -### Tertiary/No Wrap - -**Render** - -```tsx -() => { - return ( - - Long button text - - ); -} -``` - - -### Icon Only - -**Render** - -```tsx -() => { - return ( - <> - - - - - ); -} -``` - diff --git a/skills/carbon-react/components/button-next.md b/skills/carbon-react/components/button-next.md deleted file mode 100644 index cbfb0f851f..0000000000 --- a/skills/carbon-react/components/button-next.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -name: carbon-component-button-next -description: Carbon ButtonNext component props and usage examples. ---- - -# ButtonNext - -## Import -`import Button from "carbon-react/lib/components/button/__next__";` - -## Source -- Export: `./components/button/__next__` -- Props interface: `ButtonProps` - -## Props -| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | -| --- | --- | --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | No | | | | The content that the button displays. | | -| disabled | boolean \| undefined | No | | | | Flag to indicate that the button is disabled. | | -| form | string \| undefined | No | | | | Associates the button with a form element; value should be the id of the form. | | -| fullWidth | boolean \| undefined | No | | | | Flag to indicate that the button can be full-width. | | -| href | string \| undefined | No | | | | Used to transform button into anchor | | -| iconPosition | ButtonIconPosition \| undefined | No | | | | Defines an Icon position related to the children: "before" \| "after" | | -| iconType | IconType \| undefined | No | | | | Defines an Icon type within the button | | -| id | string \| undefined | No | | | | The ID of the button. | | -| inverse | boolean \| undefined | No | | | | Set the button to use a dark-mode appearance. | | -| m | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| name | string \| undefined | No | | | | The name of the button. | | -| noWrap | boolean \| undefined | No | | | | Flag to indicate whether the button text can wrap over multiple lines. | | -| onBlur | ((ev: React.FocusEvent) => void) \| undefined | No | | | | Handler to fire when the button is blurred. | | -| onChange | ((ev: React.FormEvent \| React.ChangeEvent) => void) \| undefined | No | | | | Specify a callback triggered on change | | -| onClick | ((ev: React.MouseEvent \| React.MouseEvent) => void) \| undefined | No | | | | Handler to fire when the button is clicked. | | -| onFocus | ((ev: React.FocusEvent) => void) \| undefined | No | | | | Handler to fire when the button is focused. | | -| onKeyDown | ((ev: React.KeyboardEvent) => void) \| undefined | No | | | | Handler to fire when the button is activated via the Enter or Space keys. | | -| p | ResponsiveValue \| undefined | No | | | | Padding on top, left, bottom and right | | -| padding | ResponsiveValue \| undefined | No | | | | Padding on top, left, bottom and right | | -| paddingBottom | ResponsiveValue \| undefined | No | | | | Padding on bottom | | -| paddingLeft | ResponsiveValue \| undefined | No | | | | Padding on left | | -| paddingRight | ResponsiveValue \| undefined | No | | | | Padding on right | | -| paddingTop | ResponsiveValue \| undefined | No | | | | Padding on top | | -| paddingX | ResponsiveValue \| undefined | No | | | | Padding on left and right | | -| paddingY | ResponsiveValue \| undefined | No | | | | Padding on top and bottom | | -| pb | ResponsiveValue \| undefined | No | | | | Padding on bottom | | -| pl | ResponsiveValue \| undefined | No | | | | Padding on left | | -| pr | ResponsiveValue \| undefined | No | | | | Padding on right | | -| pt | ResponsiveValue \| undefined | No | | | | Padding on top | | -| px | ResponsiveValue \| undefined | No | | | | Padding on left and right | | -| py | ResponsiveValue \| undefined | No | | | | Padding on top and bottom | | -| rel | string \| undefined | No | | | | HTML rel attribute | | -| size | Size \| undefined | No | | | | The size of the button. | | -| target | string \| undefined | No | | | | HTML target attribute | | -| type | "button" \| "reset" \| "submit" \| undefined | No | | | | The HTML type that this button should use. | | -| variant | Variant \| undefined | No | | | | The variant of the button. | | -| variantType | VariantType \| undefined | No | | | | The variant type of the button. | | -| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| aria-describedby | string \| undefined | No | | | | Identifies the element(s) offering additional information about the button that the user might require. | | -| aria-label | string \| undefined | No | | | | The aria-label attribute of the button. | | -| aria-labelledby | string \| undefined | No | | | | Identifies the element(s) labelling the button. | | -| buttonType | LegacyButtonProps["buttonType"] | No | | Yes | Please use `variantType` prop instead. | | | -| destructive | boolean \| undefined | No | | Yes | Please use `variant="destructive"` instead. | | | -| isWhite | boolean \| undefined | No | | Yes | Please use `inverse` instead. | | | -| subtext | string \| undefined | No | | Yes | Second text child, renders under main text, only when size is "large" | | | - -## Examples -No Storybook examples found. \ No newline at end of file diff --git a/skills/carbon-react/components/button-toggle-group.md b/skills/carbon-react/components/button-toggle-group.md deleted file mode 100644 index 9a5758690d..0000000000 --- a/skills/carbon-react/components/button-toggle-group.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -name: carbon-component-button-toggle-group -description: Carbon ButtonToggleGroup component props and usage examples. ---- - -# ButtonToggleGroup - -## Import -`import { ButtonToggleGroup } from "carbon-react/lib/components/button-toggle";` - -## Source -- Export: `./components/button-toggle` -- Props interface: `ButtonToggleGroupProps` - -## Props -| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | -| --- | --- | --- | --- | --- | --- | --- | --- | -| id | string | Yes | | | | Unique id for the root element of the component. | | -| onChange | (ev: React.MouseEvent, value?: string) => void | Yes | | | | Callback triggered by pressing one of the child buttons. | | -| value | string | Yes | | | | Determines which child button is selected | | -| allowDeselect | boolean \| undefined | No | | | | Allow selected buttons within the group to be deselected. | false | -| children | React.ReactNode | No | | | | Toggle buttons to be rendered. Only accepts children of type ButtonToggle | | -| disabled | boolean \| undefined | No | | | | Disable the group. | false | -| fullWidth | boolean \| undefined | No | | | | If true all ButtonToggle children will flex to the full width of the ButtonToggleGroup parent | false | -| inputHint | React.ReactNode | No | | | | A hint string rendered before the input but after the label. Intended to describe the purpose or content of the input. | | -| inputWidth | string \| number \| undefined | No | | | | The percentage width of the ButtonToggleGroup. | | -| label | string \| undefined | No | | | | Visible label for the group. | | -| m | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| size | "small" \| "medium" \| "large" \| undefined | No | | | | Size of the ButtonToggleGroup | "medium" | -| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| aria-label | string \| undefined | No | | | | Sets an aria-label for the group, must be provided if there is no visible label. | | -| fieldHelp | string \| undefined | No | | Yes | `fieldHelp` is no longer supported, please use `inputHint` instead. | [Legacy] The text for the field help. | | -| fieldHelpInline | boolean \| undefined | No | | Yes | `fieldHelpInline` is no longer supported. | [Legacy] Sets the field help to inline. | | -| helpAriaLabel | string \| undefined | No | | Yes | Help tooltips are no longer supported. | [Legacy] Aria label for rendered help component. | | -| labelHelp | React.ReactNode | No | | Yes | Help tooltips are no longer supported, please use the `inputHint` prop instead. | [Legacy] Text for the label's help tooltip. | | -| labelInline | boolean \| undefined | No | | Yes | Inline labels are no longer supported. | [Legacy] Sets the label to be inline. | | -| labelSpacing | 1 \| 2 \| undefined | No | | Yes | Custom label spacing is no longer supported for this component. | [Legacy] Spacing between label and a field for inline label, given number will be multiplied by base spacing unit (8), | | -| labelWidth | number \| undefined | No | | Yes | `labelWidth` is no longer supported. | [Legacy] The percentage width of the label. | | - -## Examples -No Storybook examples found. \ No newline at end of file diff --git a/skills/carbon-react/components/button-toggle.md b/skills/carbon-react/components/button-toggle.md deleted file mode 100644 index eb2c6b4168..0000000000 --- a/skills/carbon-react/components/button-toggle.md +++ /dev/null @@ -1,498 +0,0 @@ ---- -name: carbon-component-button-toggle -description: Carbon ButtonToggle component props and usage examples. ---- - -# ButtonToggle - -## Import -`import { ButtonToggle } from "carbon-react/lib/components/button-toggle";` - -## Source -- Export: `./components/button-toggle` -- Props interface: `ButtonToggleProps` - -## Props -| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | -| --- | --- | --- | --- | --- | --- | --- | --- | -| allowDeselect | boolean \| undefined | No | | | | Allow a selected button to be deselected. | | -| buttonIcon | IconType \| undefined | No | | | | Icon rendered within the button. Will not be rendered if size is small. | | -| children | React.ReactNode | No | | | | Content to display within the button. | | -| disabled | boolean \| undefined | No | | | | Disable the ButtonToggle. | | -| onBlur | ((ev: React.FocusEvent) => void) \| undefined | No | | | | Callback triggered by blur event on the button. | | -| onClick | ((ev: React.MouseEvent) => void) \| undefined | No | | | | Callback triggered by click event on the button. | | -| onFocus | ((ev: React.FocusEvent) => void) \| undefined | No | | | | Callback triggered by focus event on the button. | | -| pressed | boolean \| undefined | No | | | | Set the pressed state of the toggle button when used outside of a group. | | -| size | "small" \| "medium" \| "large" \| undefined | No | | | | ButtonToggle size | "medium" | -| value | string \| undefined | No | | | | An optional string by which to identify the button in an onChange handler on the parent ButtonToggleGroup. | | -| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| aria-label | string \| undefined | No | | | | Prop to specify the aria-label of the component | | -| aria-labelledby | string \| undefined | No | | | | Prop to specify the aria-labelledby property of the component | | -| buttonIconSize | "small" \| "large" \| undefined | No | | Yes | `buttonIconSize` is no longer supported. | Sets the size of the buttonIcon | | - -## Examples -### Default - -**Args** - -```tsx -{ - "aria-label": "Button Toggle Group", - value: "default-2", - } -``` - -**Render** - -```tsx -ControlledButtonToggleGroup -``` - - -### WithLabelAndHint - -**Args** - -```tsx -{ - id: "with-label", - label: "Label", - inputHint: "Hint Text", - value: "with-label-2", - } -``` - - -### Single - -**Render** - -```tsx -() => { - const [isPressed, setIsPressed] = useState(true); - - const handleClick = () => { - setIsPressed(!isPressed); - }; - - return ( - - ButtonToggle - - ); -} -``` - - -### With Icon - -**Render** - -```tsx -({ ...args }: ButtonToggleGroupProps) => { - const [leftValue, setLeftValue] = useState("icon-left-1"); - const [rightValue, setRightValue] = useState("icon-right-1"); - - const handleOnChangeLeft = ( - ev: React.MouseEvent, - selectedValue?: string, - ) => { - setLeftValue(selectedValue as string); - }; - - const handleOnChangeRight = ( - ev: React.MouseEvent, - selectedValue?: string, - ) => { - setRightValue(selectedValue as string); - }; - - return ( - <> - - - - Button 1 - - - - Button 2 - - - - - Button 1 - - - - Button 2 - - - - - ); -} -``` - - -### Loading - -**Render** - -```tsx -({ ...args }: ButtonToggleGroupProps) => { - const [value, setValue] = useState(""); - - const handleOnChange = ( - ev: React.MouseEvent, - selectedValue?: string, - ) => { - if (selectedValue === "loading-2") return; - setValue(selectedValue as string); - }; - - return ( - - Button 1 - - - - Button 3 - - ); -} -``` - - -### Sizes - Grouped - -**Render** - -```tsx -({ ...args }: ButtonToggleGroupProps) => { - const [valueSmall, setValueSmall] = useState("small-2"); - const [valueMedium, setValueMedium] = useState("medium-2"); - const [valueLarge, setValueLarge] = useState("large-2"); - - const handleOnChangeSmall = ( - ev: React.MouseEvent, - selectedValue?: string, - ) => { - setValueSmall(selectedValue as string); - }; - - const handleOnChangeMedium = ( - ev: React.MouseEvent, - selectedValue?: string, - ) => { - setValueMedium(selectedValue as string); - }; - - const handleOnChangeLarge = ( - ev: React.MouseEvent, - selectedValue?: string, - ) => { - setValueLarge(selectedValue as string); - }; - - return ( - <> - - Button 1 - Button 2 - Button 3 - - - - - - Button 1 - - - - Button 2 - - - - Button 3 - - - - - - - Button 1 - - - - Button 2 - - - - Button 3 - - - - ); -} -``` - - -### Sizes - Single - -**Render** - -```tsx -() => { - const [isPressedSmall, setIsPressedSmall] = useState(true); - const [isPressedMedium, setIsPressedMedium] = useState(true); - const [isPressedLarge, setIsPressedLarge] = useState(true); - - const handleClickSmall = () => { - setIsPressedSmall(!isPressedSmall); - }; - - const handleClickMedium = () => { - setIsPressedMedium(!isPressedMedium); - }; - - const handleClickLarge = () => { - setIsPressedLarge(!isPressedLarge); - }; - - return ( - - - Small ButtonToggle - - - Medium ButtonToggle - - - Large ButtonToggle - - - ); -} -``` - - -### Icon Only - Grouped - -**Render** - -```tsx -({ ...args }: ButtonToggleGroupProps) => { - const [valueMedium, setValueMedium] = useState("medium-2"); - const [valueLarge, setValueLarge] = useState("large-2"); - - const handleOnChangeMedium = ( - ev: React.MouseEvent, - selectedValue?: string, - ) => { - setValueMedium(selectedValue as string); - }; - - const handleOnChangeLarge = ( - ev: React.MouseEvent, - selectedValue?: string, - ) => { - setValueLarge(selectedValue as string); - }; - - return ( - <> - - - - - - - - - - - - - - - - - - - - - - - - - ); -} -``` - - -### Icon Only - Single - -**Render** - -```tsx -() => { - const [isPressedSmall, setIsPressedSmall] = useState(true); - const [isPressedMedium, setIsPressedMedium] = useState(true); - const [isPressedLarge, setIsPressedLarge] = useState(true); - - const handleClickSmall = () => { - setIsPressedSmall(!isPressedSmall); - }; - - const handleClickMedium = () => { - setIsPressedMedium(!isPressedMedium); - }; - - const handleClickLarge = () => { - setIsPressedLarge(!isPressedLarge); - }; - - return ( - - - - - - - - - - - - ); -} -``` - - -### AllowDeselect - -**Args** - -```tsx -{ - id: "allow-deselect", - value: "allow-deselect-2", - allowDeselect: true, - } -``` - - -### FullWidth - -**Args** - -```tsx -{ - id: "full-width", - value: "full-width-2", - fullWidth: true, - } -``` - - -### Disabled - -**Args** - -```tsx -{ - id: "disabled", - label: "Disabled", - inputHint: "Hint Text", - value: "disabled-2", - disabled: true, - } -``` - diff --git a/skills/carbon-react/components/button.md b/skills/carbon-react/components/button.md deleted file mode 100644 index 3abb2f015e..0000000000 --- a/skills/carbon-react/components/button.md +++ /dev/null @@ -1,1348 +0,0 @@ ---- -name: carbon-component-button -description: Carbon Button component props and usage examples. ---- - -# Button - -## Import -`import Button from "carbon-react/lib/components/button";` - -## Source -- Export: `./components/button` -- Props interface: `ButtonProps` -- Deprecated: Yes -- Deprecation reason: This version of Button has been deprecated. See the Carbon documentation for migration details. - -## Props -| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | -| --- | --- | --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | No | | | | The text the button displays | | -| disabled | boolean \| undefined | No | | | | Apply disabled state to the button | | -| fullWidth | boolean \| undefined | No | | | | Apply fullWidth style to the button | | -| iconPosition | ButtonIconPosition \| undefined | No | | | | Defines an Icon position related to the children: "before" \| "after" | | -| iconType | IconType \| undefined | No | | | | Defines an Icon type within the button | | -| id | string \| undefined | No | | | | id attribute | | -| m | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| name | string \| undefined | No | | | | Name attribute | | -| noWrap | boolean \| undefined | No | | | | If provided, the text inside a button will not wrap | | -| onBlur | ((ev: React.FocusEvent) => void) \| undefined | No | | | | Specify a callback triggered on blur | | -| onChange | ((ev: React.FormEvent \| React.ChangeEvent) => void) \| undefined | No | | | | Specify a callback triggered on change | | -| onClick | ((ev: React.MouseEvent \| React.MouseEvent) => void) \| undefined | No | | | | onClick handler | | -| onFocus | ((ev: React.FocusEvent) => void) \| undefined | No | | | | Specify a callback triggered on focus | | -| onKeyDown | ((ev: React.KeyboardEvent) => void) \| undefined | No | | | | Specify a callback triggered on keyDown | | -| p | ResponsiveValue \| undefined | No | | | | Padding on top, left, bottom and right | | -| padding | ResponsiveValue \| undefined | No | | | | Padding on top, left, bottom and right | | -| paddingBottom | ResponsiveValue \| undefined | No | | | | Padding on bottom | | -| paddingLeft | ResponsiveValue \| undefined | No | | | | Padding on left | | -| paddingRight | ResponsiveValue \| undefined | No | | | | Padding on right | | -| paddingTop | ResponsiveValue \| undefined | No | | | | Padding on top | | -| paddingX | ResponsiveValue \| undefined | No | | | | Padding on left and right | | -| paddingY | ResponsiveValue \| undefined | No | | | | Padding on top and bottom | | -| pb | ResponsiveValue \| undefined | No | | | | Padding on bottom | | -| pl | ResponsiveValue \| undefined | No | | | | Padding on left | | -| pr | ResponsiveValue \| undefined | No | | | | Padding on right | | -| pt | ResponsiveValue \| undefined | No | | | | Padding on top | | -| px | ResponsiveValue \| undefined | No | | | | Padding on left and right | | -| py | ResponsiveValue \| undefined | No | | | | Padding on top and bottom | | -| size | SizeOptions \| undefined | No | | | | Assigns a size to the button: "small" \| "medium" \| "large" | | -| type | string \| undefined | No | | | | HTML button type property | | -| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| aria-describedby | string \| undefined | No | | | | Identifies the element(s) offering additional information about the button the user might require. | | -| aria-label | string \| undefined | No | | | | Prop to specify the aria-label attribute of the component Defaults to the iconType, when the component has only an icon | | -| aria-labelledby | string \| undefined | No | | | | Identifies the element(s) labelling the button. | | -| buttonType | ButtonTypes \| undefined | No | | Yes | Color variants for new business themes: "primary" \| "secondary" \| "tertiary" \| "darkBackground" | | | -| destructive | boolean \| undefined | No | | Yes | Apply destructive style to the button | | | -| href | string \| undefined | No | | Yes | Used to transform button into anchor | | | -| iconTooltipMessage | string \| undefined | No | | Yes | [Legacy] Provides a tooltip message when the icon is hovered. | | | -| iconTooltipPosition | TooltipPositions \| undefined | No | | Yes | [Legacy] Provides positioning when the tooltip is displayed. | | | -| isWhite | boolean \| undefined | No | | Yes | Whether to use the white-on-dark colour variant | | | -| rel | string \| undefined | No | | Yes | HTML rel attribute | | | -| subtext | string \| undefined | No | | Yes | Second text child, renders under main text, only when size is "large" | | | -| target | string \| undefined | No | | Yes | HTML target attribute | | | - -## Examples -### Default - -**Render** - -```tsx -(args: ButtonProps) => { - return ; -} -``` - - -### Button Content - -**Render** - -```tsx -() => { - return ( - - - - - - ); -} -``` - - -### Click Handler - -**Render** - -```tsx -() => { - const [value, setValue] = useState(0); - return ( - - ); -} -``` - - -### Variations - -**Render** - -```tsx -(args: ButtonProps) => { - return ( - - -

Default

-

Primary

- <> - - - - -
- ); -} -``` - - -### Disabled - -**Render** - -```tsx -() => { - return ; -} -``` - - -### Full-Width - -**Render** - -```tsx -() => { - return ( - - -
-
- -
- ); -} -``` - - -### Inverse - -**Render** - -```tsx -() => { - return ( - - - - - - - ); -} -``` - - -### Loading - -**Render** - -```tsx -() => { - return ( - - - - - ); -} -``` - - -### Wrapping Text - -**Render** - -```tsx -() => { - return ( - - - - - ); -} -``` - - -### HTML Button Types - -**Render** - -```tsx -() => { - return ( - - - - - - ); -} -``` - - -### As a Link - -**Render** - -```tsx -() => { - return ( - - - - - ); -} -``` - - -### Programmatic Focus - -**Render** - -```tsx -() => { - const buttonRef = useRef(null); - - return ( - - - - - ); -} -``` - - -### Primary - -**Render** - -```tsx -() => { - return ( - - - - - - ); -} -``` - - -### Primary/Destructive - -**Render** - -```tsx -() => { - return ( - - - - - - ); -} -``` - - -### Primary/Disabled - -**Render** - -```tsx -() => { - return ( - - - - - - ); -} -``` - - -### Primary/Icon - -**Render** - -```tsx -() => { - return ( - - - - - - ); -} -``` - - -### Primary/Full Width - -**Render** - -```tsx -() => { - return ( - - - - ); -} -``` - - -### Primary/No Wrap - -**Render** - -```tsx -() => { - return ( - - - - ); -} -``` - - -### Secondary - -**Render** - -```tsx -() => { - return ( - - - - - - ); -} -``` - - -### Secondary/Destructive - -**Render** - -```tsx -() => { - return ( - - - - - - ); -} -``` - - -### Secondary/Disabled - -**Render** - -```tsx -() => { - return ( - - - - - - ); -} -``` - - -### Secondary/Icon - -**Render** - -```tsx -() => { - return ( - - - - - - ); -} -``` - - -### Secondary/Full Width - -**Render** - -```tsx -() => { - return ( - - - - ); -} -``` - - -### Secondary/No Wrap - -**Render** - -```tsx -() => { - return ( - - - - ); -} -``` - - -### Secondary/White - -**Render** - -```tsx -() => { - return ( - - - - - - - - - - - - - - - - - - - - - - - ); -} -``` - - -### Tertiary - -**Render** - -```tsx -() => { - return ( - - - - - - ); -} -``` - - -### Tertiary/Destructive - -**Render** - -```tsx -() => { - return ( - - - - - - ); -} -``` - - -### Tertiary/Disabled - -**Render** - -```tsx -() => { - return ( - - - - - - ); -} -``` - - -### Tertiary/Icon - -**Render** - -```tsx -() => { - return ( - - - - - - ); -} -``` - - -### Tertiary/Full Width - -**Render** - -```tsx -() => { - return ( - - - - ); -} -``` - - -### Tertiary/No Wrap - -**Render** - -```tsx -() => { - return ( - - - - ); -} -``` - - -### Dark Background - -**Render** - -```tsx -() => { - return ( - - - - - - - - ); -} -``` - - -### Dark Background/Disabled - -**Render** - -```tsx -() => { - return ( - - - - - - - - ); -} -``` - - -### Dark Background/Icon - -**Render** - -```tsx -() => { - return ( - - - - - - - - - ); -} -``` - - -### Dark Background/Full Width - -**Render** - -```tsx -() => { - return ( - - - - - - ); -} -``` - - -### Dark Background/No Wrap - -**Render** - -```tsx -() => { - return ( - - - - ); -} -``` - - -### As a Link - -**Render** - -```tsx -() => { - return ( - - - - - ); -} -``` - - -### Icon Only Button - -**Render** - -```tsx -() => { - return ( - - - - - - ); -} -``` - - -### Gradient/White/Disabled - -**Render** - -```tsx -() => { - return ( - - - - - - ); -} -``` - - -### Gradient/White/Icon - -**Render** - -```tsx -() => { - return ( - - - - - - - ); -} -``` - - -### Gradient/White/Full Width - -**Render** - -```tsx -() => { - return ( - - - - ); -} -``` - - -### Gradient/White/No Wrap - -**Render** - -```tsx -() => { - return ( - - - - ); -} -``` - - -### Gradient/Grey - -**Render** - -```tsx -() => { - return ( - - - - - - ); -} -``` - - -### Gradient/Grey/Disabled - -**Render** - -```tsx -() => { - return ( - - - - - - ); -} -``` - - -### Gradient/Grey/Icon - -**Render** - -```tsx -() => { - return ( - - - - - - - ); -} -``` - - -### Gradient/Grey/Full Width - -**Render** - -```tsx -() => { - return ( - - - - ); -} -``` - - -### Gradient/Grey/No Wrap - -**Render** - -```tsx -() => { - return ( - - - - ); -} -``` - diff --git a/skills/carbon-react/components/carbon-provider.md b/skills/carbon-react/components/carbon-provider.md deleted file mode 100644 index ff1be9f98f..0000000000 --- a/skills/carbon-react/components/carbon-provider.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -name: carbon-component-carbon-provider -description: Carbon CarbonProvider component props and usage examples. ---- - -# CarbonProvider - -## Import -`import CarbonProvider from "carbon-react/lib/components/carbon-provider";` - -## Source -- Export: `./components/carbon-provider` -- Props interface: `CarbonProviderProps` - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | Yes | | | | -| theme | Partial \| undefined | No | | Theme which specifies styles to apply to all child components. Set to `sageTheme` by default. | sageTheme | -| validationRedesignOptIn | boolean \| undefined | No | | Feature flag for opting in to the latest validation designs for components that support it. NOTE - Will eventually be set to `true` by default in the future. | false | - -## Examples -### Using Latest Sage Theme - -**Render** - -```tsx -() => { - return ( - - - - ); -} -``` - - -### MDX Example 1 - -**Args** - -```tsx -import CarbonProvider from "carbon-react/lib/components/carbon-provider"; -import { sageTheme } from "carbon-react/lib/style/themes"; -``` - - -### MDX Example 2 - -**Args** - -```tsx - - - -``` - - -### MDX Example 3 - -**Args** - -```tsx - - This text is coloured with a design token! - -``` - - -### MDX Example 4 - -**Args** - -```tsx - - - -``` - diff --git a/skills/carbon-react/components/card-column.md b/skills/carbon-react/components/card-column.md deleted file mode 100644 index 78f58d9dc3..0000000000 --- a/skills/carbon-react/components/card-column.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -name: carbon-component-card-column -description: Carbon CardColumn component props and usage examples. ---- - -# CardColumn - -## Import -`import CardColumn from "carbon-react/lib/components/card";` - -## Source -- Export: `./components/card` -- Props interface: `CardColumnProps` -- Deprecated: Yes -- Deprecation reason: `CardColumn` has been deprecated. - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| align | "left" \| "right" \| "center" | Yes | left \| right \| center | Text alignment of the card section text | "center" | -| children | React.ReactNode | Yes | | Child elements | | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | - -## Examples -### Default - -**Args** - -```tsx -{ - children: [], - } -``` - diff --git a/skills/carbon-react/components/card-footer.md b/skills/carbon-react/components/card-footer.md deleted file mode 100644 index 95e4f11df8..0000000000 --- a/skills/carbon-react/components/card-footer.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -name: carbon-component-card-footer -description: Carbon CardFooter component props and usage examples. ---- - -# CardFooter - -## Import -`import CardFooter from "carbon-react/lib/components/card";` - -## Source -- Export: `./components/card` -- Props interface: `CardFooterProps` - -## Props -| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | -| --- | --- | --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | Yes | | | | Child nodes | | -| roundness | "large" \| "default" \| "moderate" \| "curved" | Yes | large \| default \| moderate \| curved | | | Sets the level of roundness of the corners. "moderate" is 16px and "curved" is 20px. "default" (alias for "moderate") and "large" (alias for "curved") are deprecated. Use "moderate" or "curved" instead. | | -| m | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| p | ResponsiveValue \| undefined | No | | | | Padding on top, left, bottom and right | | -| padding | ResponsiveValue \| undefined | No | | | | Padding on top, left, bottom and right | | -| paddingBottom | ResponsiveValue \| undefined | No | | | | Padding on bottom | | -| paddingLeft | ResponsiveValue \| undefined | No | | | | Padding on left | | -| paddingRight | ResponsiveValue \| undefined | No | | | | Padding on right | | -| paddingTop | ResponsiveValue \| undefined | No | | | | Padding on top | | -| paddingX | ResponsiveValue \| undefined | No | | | | Padding on left and right | | -| paddingY | ResponsiveValue \| undefined | No | | | | Padding on top and bottom | | -| pb | ResponsiveValue \| undefined | No | | | | Padding on bottom | | -| pl | ResponsiveValue \| undefined | No | | | | Padding on left | | -| pr | ResponsiveValue \| undefined | No | | | | Padding on right | | -| pt | ResponsiveValue \| undefined | No | | | | Padding on top | | -| px | ResponsiveValue \| undefined | No | | | | Padding on left and right | | -| py | ResponsiveValue \| undefined | No | | | | Padding on top and bottom | | -| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| variant | "default" \| "transparent" \| undefined | No | | Yes | Specify styling variant to render | | "default" | - -## Examples -### Default - -**Args** - -```tsx -{ - children: [], - } -``` - diff --git a/skills/carbon-react/components/card-row.md b/skills/carbon-react/components/card-row.md deleted file mode 100644 index 0a6b54974d..0000000000 --- a/skills/carbon-react/components/card-row.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -name: carbon-component-card-row -description: Carbon CardRow component props and usage examples. ---- - -# CardRow - -## Import -`import CardRow from "carbon-react/lib/components/card";` - -## Source -- Export: `./components/card` -- Props interface: `CardRowProps` -- Deprecated: Yes -- Deprecation reason: `CardRow` has been deprecated. - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | Yes | | Child nodes | | -| p | ResponsiveValue \| undefined | No | | Padding on top, left, bottom and right | | -| padding | ResponsiveValue \| undefined | No | | Padding on top, left, bottom and right | | -| paddingBottom | ResponsiveValue \| undefined | No | | Padding on bottom | | -| paddingLeft | ResponsiveValue \| undefined | No | | Padding on left | | -| paddingRight | ResponsiveValue \| undefined | No | | Padding on right | | -| paddingTop | ResponsiveValue \| undefined | No | | Padding on top | | -| paddingX | ResponsiveValue \| undefined | No | | Padding on left and right | | -| paddingY | ResponsiveValue \| undefined | No | | Padding on top and bottom | | -| pb | ResponsiveValue \| undefined | No | | Padding on bottom | | -| pl | ResponsiveValue \| undefined | No | | Padding on left | | -| pr | ResponsiveValue \| undefined | No | | Padding on right | | -| pt | ResponsiveValue \| undefined | No | | Padding on top | | -| px | ResponsiveValue \| undefined | No | | Padding on left and right | | -| py | ResponsiveValue \| undefined | No | | Padding on top and bottom | | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | - -## Examples -### Default - -**Args** - -```tsx -{ - children: [], - } -``` - diff --git a/skills/carbon-react/components/card.md b/skills/carbon-react/components/card.md deleted file mode 100644 index 09e5db076b..0000000000 --- a/skills/carbon-react/components/card.md +++ /dev/null @@ -1,1628 +0,0 @@ ---- -name: carbon-component-card -description: Carbon Card component props and usage examples. ---- - -# Card - -## Import -`import Card from "carbon-react/lib/components/card";` - -## Source -- Export: `./components/card` -- Props interface: `CardProps` - -## Props -| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | -| --- | --- | --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | Yes | | | | Child nodes | | -| draggable | boolean \| undefined | No | | | | Flag to indicate if card is draggable | | -| footer | React.ReactNode | No | | | | The footer to render underneath the Card content | | -| header | React.ReactNode | No | | | | The header to render above the Card content | | -| height | string \| undefined | No | | | | Height of the component (any valid CSS value) | | -| href | string \| undefined | No | | | | The path to navigate to. Renders an anchor element when passed and no draggable prop set | | -| m | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| onClick | ((event: React.MouseEvent \| React.MouseEvent \| React.KeyboardEvent \| React.KeyboardEvent) => void) \| undefined | No | | | | Action to be executed when card is clicked or enter pressed. Renders a button when passed and no draggable or href props set | | -| rel | string \| undefined | No | | | | String for rel property when card has an href prop set | | -| rightChildren | React.ReactNode | No | | | | Slot rendered on the opposite side of the drag handle, only visible when `draggable` is true. Intended for accessibility controls (e.g. move-up / move-down buttons) for keyboard users. | | -| roundness | "large" \| "default" \| "moderate" \| "curved" \| undefined | No | | | | Sets the level of roundness of the corners. "moderate" is 16px and "curved" is 20px. **Note:** The values "default" and "large" are deprecated. Use "moderate" or "curved" instead. | "moderate" | -| spacing | "small" \| "medium" \| "large" \| "none" \| "extra-small" \| undefined | No | | | | Size padding applied to the card. | "medium" | -| target | string \| undefined | No | | | | Target property in which link should open ie: _blank, _self, _parent, _top | | -| variant | "standard" \| "outlined" \| undefined | No | | | | Visual style variant of the card | "standard" | -| width | string \| undefined | No | | | | Style value for width of card | "500px" | -| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| aria-label | string \| undefined | No | | | | Prop to specify an aria-label for the component | | -| boxShadow | BoxShadowsType \| undefined | No | | Yes | Design token for custom Box Shadow. Note: please check that the box shadow design token you are using is compatible with the Card component. | | | -| hoverBoxShadow | BoxShadowsType \| undefined | No | | Yes | Design token for custom Box Shadow on hover. One of `onClick` or `href` props must be true. Note: please check that the box shadow design token you are using is compatible with the Card component. | | | - -## Examples -### Default - -**Render** - -```tsx -( - args: Omit, -) => { - return ( - - - - - Footer link - - - - - } - > - - - Heading - Additional text - - - - - - - - - Body text - - - More text - - Even more text - - - - ); -} -``` - - -### Draggable spacing sizes - -**Render** - -```tsx -() => { - return ( - <> - {(["none", "extra-small", "small", "medium", "large"] as const).map( - (spacing) => ( - - {}}> - Move up - - {}}> - Move down - - - } - spacing={spacing} - mb="16px" - footer={ - - - - - Footer link - - - - - } - > - - - Spacing: {spacing} - Additional text - - - - - - - ), - )} - - ); -} -``` - - -### CustomHeight - -**Render** - -```tsx -() => { - return ( - <> - {}} - footer={ - - - - - Footer link - - - - - } - > - - - Heading - Additional text - - - - - - - - - Body text - - - More text - - Even more text - - - - - - - - Footer link - - - - - } - > - - - Heading - Additional text - - - - - - - - - Body text - - - More text - - Even more text - - - - - ); -} -``` - - -### InteractiveFocusedWithFooter - -**Render** - -```tsx -() => ( - {}} - footer={ - - - - - Footer link - - - - - } - > - - - Focused Card - Card with footer in focused state - - - - - - - ) -``` - - -### InteractiveFocusedWithoutFooter - -**Render** - -```tsx -() => ( - {}}> - - - Focused Card - Card without footer in focused state - - - - - - - ) -``` - - -### DeprecatedCardRowAndColumn - -**Render** - -```tsx -() => ( - - - - Footer link - - - - } - > - - - - - Additional text - - - - - - - - - - Body text - - - Even more text - - - - ) -``` - - -### DeprecatedCardRowWithPadding - -**Render** - -```tsx -() => ( - - - - View Stripe Dashboard - - - - } - > - - - Stripe - [account name] - - user.name@sage.com - - - - - - - - - - Stripe Balance - - £ 0.00 - LAST ENTRY: 5 DAYS AGO - - - - - - Stripe Balance - - £ 0.00 - LAST ENTRY: 15 DAYS AGO - - - - ) -``` - - -### DeprecatedCardRowSpacingSizes - -**Render** - -```tsx -() => ( - <> - {(["small", "medium", "large"] as const).map((spacing) => ( - - - - Footer link - - - - } - > - - - Spacing: {spacing} - Additional text - - - - - - - - - Body text - - More text - - - - ))} - - ) -``` - - -### DeprecatedCardRowWithInteractive - -**Render** - -```tsx -() => ( - {}} - footer={ - - - - Footer link - - - - } - > - - - - - Click me! - - - - - - - - ) -``` - - -### Playground - -**Args** - -```tsx -{ - spacing: "medium", - roundness: "moderate", - width: undefined, - height: undefined, - draggable: false, - } -``` - -**Render** - -```tsx -(args) => { - return ( - - {}}>Move up - {}}> - Move down - - - {}}>Delete - {}}>Edit - - ) : undefined - } - > - - - Heading - Additional text - - - - - - - - - Body text - - - More text - - Even more text - - - - ); - } -``` - - -### Default - -**Render** - -```tsx -(args: CardProps) => { - return ( - - - - - Footer link - - - - - } - > - - - Heading - Additional text - - - - - - - - - Body text - -
- More text -
- Even more text -
-
-
- ); - } -``` - - -### Without Footer - -**Render** - -```tsx -() => { - return ( - - - - Heading - Additional text - - - - - - - - - Body text - - - More text - - Even more text - - - - ); -} -``` - - -### Without Footer - Interactive - -**Render** - -```tsx -() => { - const [clickCounter, setClickCounter] = useState(0); - return ( - - - Card has been clicked {clickCounter} times - - setClickCounter((prevCounter) => prevCounter + 1)} - aria-label="Interactive card without footer" - > - - - - Heading - - - Additional text - - - - - - - - - - Body text - - - More text - - Even more text - - - - - ); -} -``` - - -### No Spacing - -**Render** - -```tsx -() => { - return ( - - - - - Footer link - - - - - } - > - - - Heading - Additional text - - - - - - - - - Body text - -
- More text -
- Even more text -
-
-
- ); -} -``` - - -### Extra Small Spacing - -**Render** - -```tsx -() => { - return ( - - - - - Footer link - - - - - } - > - - - Heading - Additional text - - - - - - - - - Body text - -
- More text -
- Even more text -
-
-
- ); -} -``` - - -### Small Spacing - -**Render** - -```tsx -() => { - return ( - - - - - Footer link - - - - - } - > - - - Heading - Additional text - - - - - - - - - Body text - -
- More text -
- Even more text -
-
-
- ); -} -``` - - -### Medium Spacing - -**Render** - -```tsx -() => { - return ( - - - - - Footer link - - - - - } - > - - - Heading - Additional text - - - - - - - - - Body text - -
- More text -
- Even more text -
-
-
- ); -} -``` - - -### Large Spacing - -**Render** - -```tsx -() => { - return ( - - - - - Footer link - - - - - } - > - - - Heading - Additional text - - - - - - - - - Body text - -
- More text -
- Even more text -
-
-
- ); -} -``` - - -### With Width Provided - -**Render** - -```tsx -() => { - return ( - - - - - Footer link - - - - - } - > - - - Heading - Additional text - - - - - - - - - Body text - -
- More text -
- Even more text -
-
-
- ); -} -``` - - -### With Custom Height - -**Render** - -```tsx -() => { - return ( - - - - - Footer link - - - - - } - > - - - Heading - Additional text - - - - - - - - - Body text - -
- More text -
- Even more text -
-
-
- ); -} -``` - - -### With Curved Roundness - -**Render** - -```tsx -() => { - return ( - - - - - Footer link - - - - - } - > - - - Heading - Additional text - - - - - - - - - Body text - -
- More text -
- Even more text -
-
-
- ); -} -``` - - -### Interactive - -**Render** - -```tsx -() => { - const [clickCounter, setClickCounter] = useState(0); - return ( - - - Card has been clicked {clickCounter} times - - setClickCounter((prevCounter) => prevCounter + 1)} - aria-label="Card with button element" - footer={ - - - - - Footer link - - - - - } - > - - - - This Card is a button as it has an onClick prop - - - - - - - - - Footer link - - - - - } - > - - - - This Card is a link as it has an href prop - - - - - - ); -} -``` - - -### Draggable - -**Render** - -```tsx -() => { - return ( - - {}}>Move up - {}}>Move down - - {}}>Delete - {}}>Edit - - } - footer={ - - - - - Footer link - - - - - } - > - - - Heading - Additional text - - - - - - - - - Body text - - - More text - - Even more text - - - - ); -} -``` - - -### Different Card Row Padding - -**Render** - -```tsx -() => { - return ( - - - - - Footer link - - - - - } - > - - - Heading - Additional text - - - - - - - - - Body text - -
- More text -
- Even more text -
-
- - - - Body text - -
- More text -
- Even more text -
-
-
- ); -} -``` - - -### Different Card Footer Padding - -**Render** - -```tsx -() => { - return ( - - - - - - - - - - - - } - > - - - - Here is some text - - - - - - - - - - - - - - - } - > - - - - Here is some text - - - - - - - - - - - - - - - } - > - - - - Here is some text - - - - - - - - - - - - - - - } - > - - - - Here is some text - - - - - - - - - - - - - - - } - > - - - - Here is some text - - - - - - - - - - - - - - - } - > - - - - Here is some text - - - - - - ); -} -``` - - -### More Examples of Card Footer - -**Render** - -```tsx -() => { - return ( - - - - - - - - - - } - > - - - - Here is some text - - - - - - - - - - - - } - > - - - - Here is some text - - - - - - - - - - - - } - > - - - - Here is some text - - - - - - - - View Stripe Dashboard - - - - } - > - - - - Here is some text - - - - - - ); -} -``` - diff --git a/skills/carbon-react/components/checkbox-group.md b/skills/carbon-react/components/checkbox-group.md deleted file mode 100644 index 6f48a8181d..0000000000 --- a/skills/carbon-react/components/checkbox-group.md +++ /dev/null @@ -1,412 +0,0 @@ ---- -name: carbon-component-checkbox-group -description: Carbon CheckboxGroup component props and usage examples. ---- - -# CheckboxGroup - -## Import -`import { CheckboxGroup } from "carbon-react/lib/components/checkbox";` - -## Source -- Export: `./components/checkbox` -- Props interface: `CheckboxGroupProps` - -## Props -| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | -| --- | --- | --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | Yes | | | | The Checkboxes to be rendered in the group | | -| disabled | boolean \| undefined | No | | | | Flag to disable the CheckboxGroup. | | -| error | string \| undefined | No | | | | Error message to be displayed when validation fails. | | -| id | string \| undefined | No | | | | Unique identifier for the component. Will use a randomly generated GUID if none is provided. | | -| inline | boolean \| undefined | No | | | | When true, Checkbox children are inline. | | -| legend | string \| undefined | No | | | | The content for the CheckboxGroup Legend | | -| legendHint | string \| undefined | No | | | | Content for the hint text below the legend. | | -| m | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| required | boolean \| undefined | No | | | | Flag to configure CheckboxGroup as mandatory | | -| size | CheckboxSizes \| undefined | No | | | | Size of the CheckboxGroup. | "medium" | -| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| info | string \| boolean \| undefined | No | | Yes | Information validation is no longer supported on this component. | [Legacy] Indicate additional information. | | -| labelSpacing | 1 \| 2 \| undefined | No | | Yes | Custom spacing for labels is no longer supported on this component. | Spacing between label and a field for inline label, given number will be multiplied by base spacing unit (8) | | -| legendAlign | "left" \| "right" \| undefined | No | | Yes | Right legend alignment is no longer supported. | [Legacy] Alignment of the legend. | | -| legendHelp | string \| undefined | No | | Yes | The `legendHelp` prop is deprecated and will be removed in a future release. Please use the `legendHint` prop instead. | The content for the RadioButtonGroup hint text, will only be rendered when `validationRedesignOptIn` is true. | | -| legendInline | boolean \| undefined | No | | Yes | Inline legends are no longer supported on this component. | [Legacy] When true, legend is placed in line with the Checkboxes. | | -| legendSpacing | 1 \| 2 \| undefined | No | | Yes | Custom spacing for legends is no longer supported on this component. | [Legacy] Spacing between legend and field for inline legend, number multiplied by base spacing unit (8) | | -| legendWidth | number \| undefined | No | | Yes | Inline legends are no longer supported on this component. | [Legacy] Percentage width of legend (only when legend is inline) | | -| tooltipPosition | "left" \| "right" \| "bottom" \| "top" \| undefined | No | | Yes | Tooltips are no longer supported on this component. | Overrides the default tooltip position | | -| validationMessagePositionTop | boolean \| undefined | No | | Yes | The `validationMessagePositionTop` prop is deprecated and will be removed in a future release. | Render the ValidationMessage above the CheckboxGroup | true | -| warning | string \| undefined | No | | Yes | The `warning` state is deprecated and will be removed in a future release. | Warning message to be displayed when validation warning occurs. | | - -## Examples -### Chromatic - -**Args** - -```tsx -{ - mb: 2, - } -``` - -**Render** - -```tsx -(args) => ( - <> - - - - - - - - - - - - - ) -``` - - -### Validation - -**Args** - -```tsx -{ - legendHint: "Hint Text", - } -``` - -**Render** - -```tsx -(args) => ( - - - - - - - - - - - - - - - - - - - - - ) -``` - - -### ValidationInline - -**Args** - -```tsx -{ - ...Validation.args, - inline: true, - } -``` - - -### In Tabs - -**Render** - -```tsx -() => { - return ( - - - - - - - - - - - - - ); -} -``` - - -### Default - -**Render** - -```tsx -ControlledCheckboxGroup -``` - - -### WithLegend - -**Args** - -```tsx -{ - legend: "Legend", - } -``` - - -### WithLegendHint - -**Args** - -```tsx -{ - ...WithLegend.args, - legendHint: "Legend Hint", - } -``` - - -### Inline - -**Args** - -```tsx -{ - ...WithLegend.args, - inline: true, - } -``` - - -### Sizes - -**Render** - -```tsx -() => { - const [valuesBySize, setValuesBySize] = useState< - Record<"small" | "medium" | "large", string[]> - >({ - small: [], - medium: [], - large: [], - }); - - const handleChange = - (size: "small" | "medium" | "large") => - (event: React.ChangeEvent) => { - const { value, checked } = event.target; - setValuesBySize((prev) => ({ - ...prev, - [size]: checked - ? [...prev[size], value] - : prev[size].filter((val) => val !== value), - })); - }; - - const sizeConfigs: Array<{ - size: "small" | "medium" | "large"; - legend: string; - }> = [ - { size: "small", legend: "Small Checkbox Group" }, - { size: "medium", legend: "Medium Checkbox Group" }, - { size: "large", legend: "Large Checkbox Group" }, - ]; - - const options = ["1", "2", "3"]; - - return ( - - {sizeConfigs.map(({ size, legend }) => ( - - {options.map((option) => { - const value = `${size}-${option}`; - return ( - - ); - })} - - ))} - - ); -} -``` - - -### Required - -**Args** - -```tsx -{ - ...WithLegend.args, - required: true, - } -``` - - -### Disabled - -**Args** - -```tsx -{ - ...WithLegendHint.args, - required: true, - disabled: true, - } -``` - diff --git a/skills/carbon-react/components/checkbox.md b/skills/carbon-react/components/checkbox.md deleted file mode 100644 index b9ccf7b96a..0000000000 --- a/skills/carbon-react/components/checkbox.md +++ /dev/null @@ -1,756 +0,0 @@ ---- -name: carbon-component-checkbox -description: Carbon Checkbox component props and usage examples. ---- - -# Checkbox - -## Import -`import { Checkbox } from "carbon-react/lib/components/checkbox";` - -## Source -- Export: `./components/checkbox` -- Props interface: `CheckboxProps` - -## Props -| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | -| --- | --- | --- | --- | --- | --- | --- | --- | -| checked | boolean | Yes | | | | Checked state of the input. | | -| onChange | (ev: React.ChangeEvent) => void | Yes | | | | Handler for change events | | -| about | string \| undefined | No | | | | | | -| accept | string \| undefined | No | | | | | | -| accessKey | string \| undefined | No | | | | | | -| alt | string \| undefined | No | | | | | | -| autoCapitalize | (string & {}) \| "none" \| "off" \| "on" \| "sentences" \| "words" \| "characters" \| undefined | No | | | | | | -| autoComplete | HTMLInputAutoCompleteAttribute \| undefined | No | | | | | | -| autoCorrect | string \| undefined | No | | | | | | -| autoFocus | boolean \| undefined | No | | | | If true, the component will be automatically focused when rendered. | | -| autoSave | string \| undefined | No | | | | | | -| capture | boolean \| "user" \| "environment" \| undefined | No | | | | | | -| children | ReactNode | No | | | | | | -| className | string \| undefined | No | | | | | | -| color | string \| undefined | No | | | | | | -| content | string \| undefined | No | | | | | | -| contentEditable | "inherit" \| Booleanish \| "plaintext-only" \| undefined | No | | | | | | -| contextMenu | string \| undefined | No | | | | | | -| dangerouslySetInnerHTML | { __html: string \| TrustedHTML; } \| undefined | No | | | | | | -| datatype | string \| undefined | No | | | | | | -| defaultChecked | boolean \| undefined | No | | | | | | -| defaultValue | string \| number \| readonly string[] \| undefined | No | | | | | | -| dir | string \| undefined | No | | | | | | -| disabled | boolean \| undefined | No | | | | If true, the component will be disabled. | | -| draggable | Booleanish \| undefined | No | | | | | | -| enterKeyHint | "go" \| "send" \| "search" \| "enter" \| "done" \| "next" \| "previous" \| undefined | No | | | | | | -| error | string \| boolean \| undefined | No | | | | Error message to be displayed when validation fails. | | -| exportparts | string \| undefined | No | | | | | | -| form | string \| undefined | No | | | | | | -| formAction | string \| undefined | No | | | | | | -| formEncType | string \| undefined | No | | | | | | -| formMethod | string \| undefined | No | | | | | | -| formNoValidate | boolean \| undefined | No | | | | | | -| formTarget | string \| undefined | No | | | | | | -| height | string \| number \| undefined | No | | | | | | -| hidden | boolean \| undefined | No | | | | | | -| id | string \| undefined | No | | | | Unique identifier for the input. Will use a randomly generated GUID if none is provided. | | -| indeterminate | boolean \| undefined | No | | | | Indeterminate state of the input, will override checked value. | | -| inlist | any | No | | | | | | -| inputHint | React.ReactNode | No | | | | Additional hint text rendered below the label. | | -| inputMode | "email" \| "none" \| "search" \| "text" \| "tel" \| "url" \| "numeric" \| "decimal" \| undefined | No | | | | Hints at the type of data that might be entered by the user while editing the element or its contents | | -| is | string \| undefined | No | | | | Specify that a standard HTML element should behave like a defined custom built-in element | | -| itemID | string \| undefined | No | | | | | | -| itemProp | string \| undefined | No | | | | | | -| itemRef | string \| undefined | No | | | | | | -| itemScope | boolean \| undefined | No | | | | | | -| itemType | string \| undefined | No | | | | | | -| label | React.ReactNode | No | | | | Content of the label. | | -| lang | string \| undefined | No | | | | | | -| list | string \| undefined | No | | | | | | -| m | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| max | string \| number \| undefined | No | | | | | | -| maxLength | number \| undefined | No | | | | | | -| mb | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| min | string \| number \| undefined | No | | | | | | -| minLength | number \| undefined | No | | | | | | -| ml | ResponsiveValue \| undefined | No | | | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | | | Margin on top | | -| multiple | boolean \| undefined | No | | | | | | -| mx | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| name | string \| undefined | No | | | | Input name attribute. | | -| nonce | string \| undefined | No | | | | | | -| onAbort | ReactEventHandler \| undefined | No | | | | | | -| onAbortCapture | ReactEventHandler \| undefined | No | | | | | | -| onAnimationEnd | AnimationEventHandler \| undefined | No | | | | | | -| onAnimationEndCapture | AnimationEventHandler \| undefined | No | | | | | | -| onAnimationIteration | AnimationEventHandler \| undefined | No | | | | | | -| onAnimationIterationCapture | AnimationEventHandler \| undefined | No | | | | | | -| onAnimationStart | AnimationEventHandler \| undefined | No | | | | | | -| onAnimationStartCapture | AnimationEventHandler \| undefined | No | | | | | | -| onAuxClick | MouseEventHandler \| undefined | No | | | | | | -| onAuxClickCapture | MouseEventHandler \| undefined | No | | | | | | -| onBeforeInput | InputEventHandler \| undefined | No | | | | | | -| onBeforeInputCapture | FormEventHandler \| undefined | No | | | | | | -| onBlur | FocusEventHandler \| undefined | No | | | | | | -| onBlurCapture | FocusEventHandler \| undefined | No | | | | | | -| onCanPlay | ReactEventHandler \| undefined | No | | | | | | -| onCanPlayCapture | ReactEventHandler \| undefined | No | | | | | | -| onCanPlayThrough | ReactEventHandler \| undefined | No | | | | | | -| onCanPlayThroughCapture | ReactEventHandler \| undefined | No | | | | | | -| onChangeCapture | FormEventHandler \| undefined | No | | | | | | -| onClick | ((ev: React.MouseEvent) => void) \| undefined | No | | | | Accepts a callback function which is triggered on click event | | -| onClickCapture | MouseEventHandler \| undefined | No | | | | | | -| onCompositionEnd | CompositionEventHandler \| undefined | No | | | | | | -| onCompositionEndCapture | CompositionEventHandler \| undefined | No | | | | | | -| onCompositionStart | CompositionEventHandler \| undefined | No | | | | | | -| onCompositionStartCapture | CompositionEventHandler \| undefined | No | | | | | | -| onCompositionUpdate | CompositionEventHandler \| undefined | No | | | | | | -| onCompositionUpdateCapture | CompositionEventHandler \| undefined | No | | | | | | -| onContextMenu | MouseEventHandler \| undefined | No | | | | | | -| onContextMenuCapture | MouseEventHandler \| undefined | No | | | | | | -| onCopy | ClipboardEventHandler \| undefined | No | | | | | | -| onCopyCapture | ClipboardEventHandler \| undefined | No | | | | | | -| onCut | ClipboardEventHandler \| undefined | No | | | | | | -| onCutCapture | ClipboardEventHandler \| undefined | No | | | | | | -| onDoubleClick | MouseEventHandler \| undefined | No | | | | | | -| onDoubleClickCapture | MouseEventHandler \| undefined | No | | | | | | -| onDrag | DragEventHandler \| undefined | No | | | | | | -| onDragCapture | DragEventHandler \| undefined | No | | | | | | -| onDragEnd | DragEventHandler \| undefined | No | | | | | | -| onDragEndCapture | DragEventHandler \| undefined | No | | | | | | -| onDragEnter | DragEventHandler \| undefined | No | | | | | | -| onDragEnterCapture | DragEventHandler \| undefined | No | | | | | | -| onDragExit | DragEventHandler \| undefined | No | | | | | | -| onDragExitCapture | DragEventHandler \| undefined | No | | | | | | -| onDragLeave | DragEventHandler \| undefined | No | | | | | | -| onDragLeaveCapture | DragEventHandler \| undefined | No | | | | | | -| onDragOver | DragEventHandler \| undefined | No | | | | | | -| onDragOverCapture | DragEventHandler \| undefined | No | | | | | | -| onDragStart | DragEventHandler \| undefined | No | | | | | | -| onDragStartCapture | DragEventHandler \| undefined | No | | | | | | -| onDrop | DragEventHandler \| undefined | No | | | | | | -| onDropCapture | DragEventHandler \| undefined | No | | | | | | -| onDurationChange | ReactEventHandler \| undefined | No | | | | | | -| onDurationChangeCapture | ReactEventHandler \| undefined | No | | | | | | -| onEmptied | ReactEventHandler \| undefined | No | | | | | | -| onEmptiedCapture | ReactEventHandler \| undefined | No | | | | | | -| onEncrypted | ReactEventHandler \| undefined | No | | | | | | -| onEncryptedCapture | ReactEventHandler \| undefined | No | | | | | | -| onEnded | ReactEventHandler \| undefined | No | | | | | | -| onEndedCapture | ReactEventHandler \| undefined | No | | | | | | -| onError | ReactEventHandler \| undefined | No | | | | | | -| onErrorCapture | ReactEventHandler \| undefined | No | | | | | | -| onFocus | FocusEventHandler \| undefined | No | | | | | | -| onFocusCapture | FocusEventHandler \| undefined | No | | | | | | -| onGotPointerCapture | PointerEventHandler \| undefined | No | | | | | | -| onGotPointerCaptureCapture | PointerEventHandler \| undefined | No | | | | | | -| onInput | FormEventHandler \| undefined | No | | | | | | -| onInputCapture | FormEventHandler \| undefined | No | | | | | | -| onInvalid | FormEventHandler \| undefined | No | | | | | | -| onInvalidCapture | FormEventHandler \| undefined | No | | | | | | -| onKeyDown | KeyboardEventHandler \| undefined | No | | | | | | -| onKeyDownCapture | KeyboardEventHandler \| undefined | No | | | | | | -| onKeyUp | KeyboardEventHandler \| undefined | No | | | | | | -| onKeyUpCapture | KeyboardEventHandler \| undefined | No | | | | | | -| onLoad | ReactEventHandler \| undefined | No | | | | | | -| onLoadCapture | ReactEventHandler \| undefined | No | | | | | | -| onLoadedData | ReactEventHandler \| undefined | No | | | | | | -| onLoadedDataCapture | ReactEventHandler \| undefined | No | | | | | | -| onLoadedMetadata | ReactEventHandler \| undefined | No | | | | | | -| onLoadedMetadataCapture | ReactEventHandler \| undefined | No | | | | | | -| onLoadStart | ReactEventHandler \| undefined | No | | | | | | -| onLoadStartCapture | ReactEventHandler \| undefined | No | | | | | | -| onLostPointerCapture | PointerEventHandler \| undefined | No | | | | | | -| onLostPointerCaptureCapture | PointerEventHandler \| undefined | No | | | | | | -| onMouseDown | MouseEventHandler \| undefined | No | | | | | | -| onMouseDownCapture | MouseEventHandler \| undefined | No | | | | | | -| onMouseEnter | MouseEventHandler \| undefined | No | | | | | | -| onMouseLeave | MouseEventHandler \| undefined | No | | | | | | -| onMouseMove | MouseEventHandler \| undefined | No | | | | | | -| onMouseMoveCapture | MouseEventHandler \| undefined | No | | | | | | -| onMouseOut | MouseEventHandler \| undefined | No | | | | | | -| onMouseOutCapture | MouseEventHandler \| undefined | No | | | | | | -| onMouseOver | MouseEventHandler \| undefined | No | | | | | | -| onMouseOverCapture | MouseEventHandler \| undefined | No | | | | | | -| onMouseUp | MouseEventHandler \| undefined | No | | | | | | -| onMouseUpCapture | MouseEventHandler \| undefined | No | | | | | | -| onPaste | ClipboardEventHandler \| undefined | No | | | | | | -| onPasteCapture | ClipboardEventHandler \| undefined | No | | | | | | -| onPause | ReactEventHandler \| undefined | No | | | | | | -| onPauseCapture | ReactEventHandler \| undefined | No | | | | | | -| onPlay | ReactEventHandler \| undefined | No | | | | | | -| onPlayCapture | ReactEventHandler \| undefined | No | | | | | | -| onPlaying | ReactEventHandler \| undefined | No | | | | | | -| onPlayingCapture | ReactEventHandler \| undefined | No | | | | | | -| onPointerCancel | PointerEventHandler \| undefined | No | | | | | | -| onPointerCancelCapture | PointerEventHandler \| undefined | No | | | | | | -| onPointerDown | PointerEventHandler \| undefined | No | | | | | | -| onPointerDownCapture | PointerEventHandler \| undefined | No | | | | | | -| onPointerEnter | PointerEventHandler \| undefined | No | | | | | | -| onPointerLeave | PointerEventHandler \| undefined | No | | | | | | -| onPointerMove | PointerEventHandler \| undefined | No | | | | | | -| onPointerMoveCapture | PointerEventHandler \| undefined | No | | | | | | -| onPointerOut | PointerEventHandler \| undefined | No | | | | | | -| onPointerOutCapture | PointerEventHandler \| undefined | No | | | | | | -| onPointerOver | PointerEventHandler \| undefined | No | | | | | | -| onPointerOverCapture | PointerEventHandler \| undefined | No | | | | | | -| onPointerUp | PointerEventHandler \| undefined | No | | | | | | -| onPointerUpCapture | PointerEventHandler \| undefined | No | | | | | | -| onProgress | ReactEventHandler \| undefined | No | | | | | | -| onProgressCapture | ReactEventHandler \| undefined | No | | | | | | -| onRateChange | ReactEventHandler \| undefined | No | | | | | | -| onRateChangeCapture | ReactEventHandler \| undefined | No | | | | | | -| onReset | FormEventHandler \| undefined | No | | | | | | -| onResetCapture | FormEventHandler \| undefined | No | | | | | | -| onScroll | UIEventHandler \| undefined | No | | | | | | -| onScrollCapture | UIEventHandler \| undefined | No | | | | | | -| onSeeked | ReactEventHandler \| undefined | No | | | | | | -| onSeekedCapture | ReactEventHandler \| undefined | No | | | | | | -| onSeeking | ReactEventHandler \| undefined | No | | | | | | -| onSeekingCapture | ReactEventHandler \| undefined | No | | | | | | -| onSelect | ReactEventHandler \| undefined | No | | | | | | -| onSelectCapture | ReactEventHandler \| undefined | No | | | | | | -| onStalled | ReactEventHandler \| undefined | No | | | | | | -| onStalledCapture | ReactEventHandler \| undefined | No | | | | | | -| onSubmit | FormEventHandler \| undefined | No | | | | | | -| onSubmitCapture | FormEventHandler \| undefined | No | | | | | | -| onSuspend | ReactEventHandler \| undefined | No | | | | | | -| onSuspendCapture | ReactEventHandler \| undefined | No | | | | | | -| onTimeUpdate | ReactEventHandler \| undefined | No | | | | | | -| onTimeUpdateCapture | ReactEventHandler \| undefined | No | | | | | | -| onTouchCancel | TouchEventHandler \| undefined | No | | | | | | -| onTouchCancelCapture | TouchEventHandler \| undefined | No | | | | | | -| onTouchEnd | TouchEventHandler \| undefined | No | | | | | | -| onTouchEndCapture | TouchEventHandler \| undefined | No | | | | | | -| onTouchMove | TouchEventHandler \| undefined | No | | | | | | -| onTouchMoveCapture | TouchEventHandler \| undefined | No | | | | | | -| onTouchStart | TouchEventHandler \| undefined | No | | | | | | -| onTouchStartCapture | TouchEventHandler \| undefined | No | | | | | | -| onTransitionEnd | TransitionEventHandler \| undefined | No | | | | | | -| onTransitionEndCapture | TransitionEventHandler \| undefined | No | | | | | | -| onVolumeChange | ReactEventHandler \| undefined | No | | | | | | -| onVolumeChangeCapture | ReactEventHandler \| undefined | No | | | | | | -| onWaiting | ReactEventHandler \| undefined | No | | | | | | -| onWaitingCapture | ReactEventHandler \| undefined | No | | | | | | -| onWheel | WheelEventHandler \| undefined | No | | | | | | -| onWheelCapture | WheelEventHandler \| undefined | No | | | | | | -| part | string \| undefined | No | | | | | | -| pattern | string \| undefined | No | | | | | | -| placeholder | string \| undefined | No | | | | | | -| prefix | string \| undefined | No | | | | | | -| progressiveDisclosure | React.ReactNode | No | | | | Content to be rendered below the input when checked, is not supported when inputs are inline. | | -| property | string \| undefined | No | | | | | | -| radioGroup | string \| undefined | No | | | | | | -| readOnly | boolean \| undefined | No | | | | | | -| rel | string \| undefined | No | | | | | | -| required | boolean \| undefined | No | | | | Flag to configure Checkbox as mandatory. | | -| resource | string \| undefined | No | | | | | | -| results | number \| undefined | No | | | | | | -| rev | string \| undefined | No | | | | | | -| role | AriaRole \| undefined | No | | | | | | -| security | string \| undefined | No | | | | | | -| size | CheckboxSizes \| undefined | No | | | | Size of the CheckboxGroup. | | -| slot | string \| undefined | No | | | | | | -| spellCheck | Booleanish \| undefined | No | | | | | | -| src | string \| undefined | No | | | | | | -| step | string \| number \| undefined | No | | | | | | -| style | CSSProperties \| undefined | No | | | | | | -| suppressContentEditableWarning | boolean \| undefined | No | | | | | | -| suppressHydrationWarning | boolean \| undefined | No | | | | | | -| tabIndex | number \| undefined | No | | | | | | -| title | string \| undefined | No | | | | | | -| translate | "yes" \| "no" \| undefined | No | | | | | | -| typeof | string \| undefined | No | | | | | | -| unselectable | "off" \| "on" \| undefined | No | | | | | | -| value | string \| undefined | No | | | | The value of the checkbox, passed on form submit | | -| vocab | string \| undefined | No | | | | | | -| width | string \| number \| undefined | No | | | | | | -| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| aria-activedescendant | string \| undefined | No | | | | Identifies the currently active element when DOM focus is on a composite widget, textbox, group, or application. | | -| aria-atomic | Booleanish \| undefined | No | | | | Indicates whether assistive technologies will present all, or only parts of, the changed region based on the change notifications defined by the aria-relevant attribute. | | -| aria-autocomplete | "none" \| "inline" \| "list" \| "both" \| undefined | No | | | | Indicates whether inputting text could trigger display of one or more predictions of the user's intended value for an input and specifies how predictions would be presented if they are made. | | -| aria-braillelabel | string \| undefined | No | | | | Indicates an element is being modified and that assistive technologies MAY want to wait until the modifications are complete before exposing them to the user. Defines a string value that labels the current element, which is intended to be converted into Braille. | | -| aria-brailleroledescription | string \| undefined | No | | | | Defines a human-readable, author-localized abbreviated description for the role of an element, which is intended to be converted into Braille. | | -| aria-busy | Booleanish \| undefined | No | | | | | | -| aria-checked | boolean \| "true" \| "false" \| "mixed" \| undefined | No | | | | Indicates the current "checked" state of checkboxes, radio buttons, and other widgets. | | -| aria-colcount | number \| undefined | No | | | | Defines the total number of columns in a table, grid, or treegrid. | | -| aria-colindex | number \| undefined | No | | | | Defines an element's column index or position with respect to the total number of columns within a table, grid, or treegrid. | | -| aria-colindextext | string \| undefined | No | | | | Defines a human readable text alternative of aria-colindex. | | -| aria-colspan | number \| undefined | No | | | | Defines the number of columns spanned by a cell or gridcell within a table, grid, or treegrid. | | -| aria-controls | string \| undefined | No | | | | Identifies the element (or elements) whose contents or presence are controlled by the current element. | | -| aria-current | boolean \| "location" \| "page" \| "time" \| "true" \| "false" \| "step" \| "date" \| undefined | No | | | | Indicates the element that represents the current item within a container or set of related elements. | | -| aria-describedby | string \| undefined | No | | | | Identifies the element (or elements) that describes the object. | | -| aria-description | string \| undefined | No | | | | Defines a string value that describes or annotates the current element. | | -| aria-details | string \| undefined | No | | | | Identifies the element that provides a detailed, extended description for the object. | | -| aria-disabled | Booleanish \| undefined | No | | | | Indicates that the element is perceivable but disabled, so it is not editable or otherwise operable. | | -| aria-errormessage | string \| undefined | No | | | | Identifies the element that provides an error message for the object. | | -| aria-expanded | Booleanish \| undefined | No | | | | Indicates whether the element, or another grouping element it controls, is currently expanded or collapsed. | | -| aria-flowto | string \| undefined | No | | | | Identifies the next element (or elements) in an alternate reading order of content which, at the user's discretion, allows assistive technology to override the general default of reading in document source order. | | -| aria-haspopup | boolean \| "grid" \| "dialog" \| "menu" \| "true" \| "false" \| "listbox" \| "tree" \| undefined | No | | | | Indicates the availability and type of interactive popup element, such as menu or dialog, that can be triggered by an element. | | -| aria-hidden | Booleanish \| undefined | No | | | | Indicates whether the element is exposed to an accessibility API. | | -| aria-invalid | boolean \| "true" \| "false" \| "grammar" \| "spelling" \| undefined | No | | | | Indicates the entered value does not conform to the format expected by the application. | | -| aria-keyshortcuts | string \| undefined | No | | | | Indicates keyboard shortcuts that an author has implemented to activate or give focus to an element. | | -| aria-label | string \| undefined | No | | | | Defines a string value that labels the current element. | | -| aria-labelledby | string \| undefined | No | | | | Identifies the element (or elements) that labels the current element. | | -| aria-level | number \| undefined | No | | | | Defines the hierarchical level of an element within a structure. | | -| aria-live | "off" \| "assertive" \| "polite" \| undefined | No | | | | Indicates that an element will be updated, and describes the types of updates the user agents, assistive technologies, and user can expect from the live region. | | -| aria-modal | Booleanish \| undefined | No | | | | Indicates whether an element is modal when displayed. | | -| aria-multiline | Booleanish \| undefined | No | | | | Indicates whether a text box accepts multiple lines of input or only a single line. | | -| aria-multiselectable | Booleanish \| undefined | No | | | | Indicates that the user may select more than one item from the current selectable descendants. | | -| aria-orientation | "horizontal" \| "vertical" \| undefined | No | | | | Indicates whether the element's orientation is horizontal, vertical, or unknown/ambiguous. | | -| aria-owns | string \| undefined | No | | | | Identifies an element (or elements) in order to define a visual, functional, or contextual parent/child relationship between DOM elements where the DOM hierarchy cannot be used to represent the relationship. | | -| aria-placeholder | string \| undefined | No | | | | Defines a short hint (a word or short phrase) intended to aid the user with data entry when the control has no value. A hint could be a sample value or a brief description of the expected format. | | -| aria-posinset | number \| undefined | No | | | | Defines an element's number or position in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM. | | -| aria-pressed | boolean \| "true" \| "false" \| "mixed" \| undefined | No | | | | Indicates the current "pressed" state of toggle buttons. | | -| aria-readonly | Booleanish \| undefined | No | | | | Indicates that the element is not editable, but is otherwise operable. | | -| aria-relevant | "text" \| "additions" \| "additions removals" \| "additions text" \| "all" \| "removals" \| "removals additions" \| "removals text" \| "text additions" \| "text removals" \| undefined | No | | | | Indicates what notifications the user agent will trigger when the accessibility tree within a live region is modified. | | -| aria-required | Booleanish \| undefined | No | | | | Indicates that user input is required on the element before a form may be submitted. | | -| aria-roledescription | string \| undefined | No | | | | Defines a human-readable, author-localized description for the role of an element. | | -| aria-rowcount | number \| undefined | No | | | | Defines the total number of rows in a table, grid, or treegrid. | | -| aria-rowindex | number \| undefined | No | | | | Defines an element's row index or position with respect to the total number of rows within a table, grid, or treegrid. | | -| aria-rowindextext | string \| undefined | No | | | | Defines a human readable text alternative of aria-rowindex. | | -| aria-rowspan | number \| undefined | No | | | | Defines the number of rows spanned by a cell or gridcell within a table, grid, or treegrid. | | -| aria-selected | Booleanish \| undefined | No | | | | Indicates the current "selected" state of various widgets. | | -| aria-setsize | number \| undefined | No | | | | Defines the number of items in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM. | | -| aria-sort | "none" \| "ascending" \| "descending" \| "other" \| undefined | No | | | | Indicates if items in a table or grid are sorted in ascending or descending order. | | -| aria-valuemax | number \| undefined | No | | | | Defines the maximum allowed value for a range widget. | | -| aria-valuemin | number \| undefined | No | | | | Defines the minimum allowed value for a range widget. | | -| aria-valuenow | number \| undefined | No | | | | Defines the current value for a range widget. | | -| aria-valuetext | string \| undefined | No | | | | Defines the human readable text alternative of aria-valuenow for a range widget. | | -| adaptiveSpacingBreakpoint | number \| undefined | No | | Yes | Adaptive spacing is no longer supported on this component. | Breakpoint for adaptive spacing (left margin changes to 0). Enables the adaptive behaviour when set. | | -| ariaDescribedBy | string \| undefined | No | | Yes | This prop is deprecated, please use the `aria-describedby` attribute instead. | The id of the element that describe the input. | | -| ariaLabelledBy | string \| undefined | No | | Yes | This prop is deprecated, please use the `aria-labelledby` attribute instead. | Prop to specify the aria-labelledby attribute of the input. | | -| fieldHelp | React.ReactNode | No | | Yes | The `fieldHelp` prop is no longer supported, please use the `inputHint` prop instead. | Help content to be displayed under an input | | -| fieldHelpInline | boolean \| undefined | No | | Yes | The `fieldHelpInline` prop is no longer supported on this component. | If true, the FieldHelp will be displayed inline To be used with labelInline prop set to true | | -| helpAriaLabel | string \| undefined | No | | Yes | Help tooltips are no longer supported on this component. | [Legacy] Aria label for rendered help component | | -| info | string \| boolean \| undefined | No | | Yes | Information validation is no longer supported on this component. | [Legacy] Indicate additional information. | | -| inputWidth | number \| undefined | No | | Yes | Custom input widths are no longer supported on this component. | Sets percentage-based input width | | -| labelHelp | React.ReactNode | No | | Yes | The `labelHelp` prop is deprecated and will be removed in a future release. Please use the `inputHint` prop instead. | [Legacy] The content for the help tooltip, to appear next to the Label | | -| labelInline | boolean \| undefined | No | | Yes | The checkbox label always renders in line with the input. | When true label is inline. | | -| labelSpacing | 1 \| 2 \| undefined | No | | Yes | Custom spacing for labels is no longer supported on this component. | [Legacy] Spacing between label and a field for inline label, given number will be multiplied by base spacing unit (8) | | -| labelWidth | number \| undefined | No | | Yes | Custom label widths are no longer supported on this component. | [Legacy] Label width | | -| onKeyPress | KeyboardEventHandler \| undefined | No | | Yes | Use `onKeyUp` or `onKeyDown` instead | | | -| onKeyPressCapture | KeyboardEventHandler \| undefined | No | | Yes | Use `onKeyUpCapture` or `onKeyDownCapture` instead | | | -| reverse | boolean \| undefined | No | | Yes | Reversed layout is no longer supported on this component. | If true the label switches position with the input | | -| tooltipPosition | "left" \| "right" \| "bottom" \| "top" \| undefined | No | | Yes | Tooltips are no longer supported on this component. | [Legacy] Overrides the default tooltip position. | | -| validationIconId | string \| undefined | No | | Yes | Validation icons with tooltips are no longer supported on this component. | Id of the validation icon | | -| validationMessagePositionTop | boolean \| undefined | No | | Yes | The `validationMessagePositionTop` prop is deprecated and will be removed in a future release. | Render the ValidationMessage above the Checkbox | | -| warning | string \| boolean \| undefined | No | | Yes | The `warning` state is deprecated and will be removed in a future release. | Warning message to be displayed when validation warning occurs. | | -| aria-dropeffect | "copy" \| "link" \| "none" \| "execute" \| "move" \| "popup" \| undefined | No | | Yes | in ARIA 1.1 | Indicates what functions can be performed when a dragged object is released on the drop target. | | -| aria-grabbed | Booleanish \| undefined | No | | Yes | in ARIA 1.1 | Indicates an element's "grabbed" state in a drag-and-drop operation. | | - -## Examples -### Chromatic - -**Args** - -```tsx -{ - mb: 2, - } -``` - -**Render** - -```tsx -(args) => ( - <> - - - - - - } - inputHint="Checkbox with custom label" - {...args} - /> - - - ) -``` - - -### Validation - -**Args** - -```tsx -{ - inputHint: "Hint Text", - } -``` - -**Render** - -```tsx -(args) => ( - - - - - - - - - - - - - - - - - - - - - ) -``` - - -### ProgressiveDisclosure - -**Args** - -```tsx -{ - mb: 2, - checked: true, - progressiveDisclosure: , - } -``` - -**Render** - -```tsx -(args) => ( - <> - - - - - ) -``` - - -### IndeterminateSizesWithFocus - -**Args** - -```tsx -{ - mb: 2, - indeterminate: true, - } -``` - -**Render** - -```tsx -(args) => ( - <> - - - - - ) -``` - - -### WithLabel - -**Args** - -```tsx -{ - label: "Checkbox", - } -``` - -**Render** - -```tsx -ControlledCheckbox -``` - - -### WithInputHint - -**Args** - -```tsx -{ - ...WithLabel.args, - inputHint: "Input Hint", - } -``` - - -### Sizes - -**Render** - -```tsx -() => { - const [checkedSmall, setCheckedSmall] = useState(false); - const [checkedMedium, setCheckedMedium] = useState(false); - const [checkedLarge, setCheckedLarge] = useState(false); - - return ( - - { - setCheckedSmall(!checkedSmall); - }} - /> - { - setCheckedMedium(!checkedMedium); - }} - /> - { - setCheckedLarge(!checkedLarge); - }} - /> - - ); -} -``` - - -### ProgressiveDisclosure - -**Args** - -```tsx -{ - ...WithLabel.args, - checked: true, - progressiveDisclosure: , - } -``` - - -### Indeterminate State - -**Render** - -```tsx -() => { - const [items, setItems] = useState([ - { id: "checkbox-1", label: "Checkbox 1", checked: true }, - { id: "checkbox-2", label: "Checkbox 2", checked: false }, - { id: "checkbox-3", label: "Checkbox 3", checked: false }, - ]); - - const checkedCount = items.filter((item) => item.checked).length; - const allChecked = checkedCount === items.length; - const someChecked = checkedCount > 0 && checkedCount < items.length; - const controlledIds = items.map((item) => item.id).join(" "); - - const handleSelectAll = () => { - const newChecked = !allChecked; - setItems(items.map((item) => ({ ...item, checked: newChecked }))); - }; - - const handleChange = (id: string, checked: boolean) => { - setItems( - items.map((item) => (item.id === id ? { ...item, checked } : item)), - ); - }; - - return ( - <> - - - {items.map((item) => ( - handleChange(item.id, ev.target.checked)} - /> - ))} - - - ); -} -``` - - -### WithCustomLabel - -**Args** - -```tsx -{ - label: , - } -``` - -**Render** - -```tsx -ControlledCheckbox -``` - - -### Required - -**Args** - -```tsx -{ - ...WithLabel.args, - required: true, - } -``` - - -### Disabled - -**Args** - -```tsx -{ - ...WithInputHint.args, - required: true, - disabled: true, - } -``` - diff --git a/skills/carbon-react/components/confirm.md b/skills/carbon-react/components/confirm.md deleted file mode 100644 index 04dd53a0b4..0000000000 --- a/skills/carbon-react/components/confirm.md +++ /dev/null @@ -1,364 +0,0 @@ ---- -name: carbon-component-confirm -description: Carbon Confirm component props and usage examples. ---- - -# Confirm - -## Import -`import Confirm from "carbon-react/lib/components/confirm";` - -## Source -- Export: `./components/confirm` -- Props interface: `ConfirmProps` -- Deprecated: Yes -- Deprecation reason: See the Carbon documentation for migration details. - -## Props -| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | -| --- | --- | --- | --- | --- | --- | --- | --- | -| onConfirm | (ev: React.MouseEvent) => void | Yes | | | | A custom event handler when a confirmation takes place | | -| open | boolean | Yes | | | | Sets the open state of the modal | | -| cancelButtonDataProps | TagProps \| undefined | No | | | | Data tag prop bag for cancelButton | | -| cancelButtonDestructive | boolean \| undefined | No | | | | Apply destructive style to the cancel button | false | -| cancelButtonIconPosition | "before" \| "after" \| undefined | No | | | | Defines a cancel button Icon position related to the children: "before" \| "after" | | -| cancelButtonIconType | IconType \| undefined | No | | | | Defines an Icon type within the cancel button (see Icon for options) | | -| cancelButtonType | "primary" \| "secondary" \| "tertiary" \| "darkBackground" \| undefined | No | | | | Color variants for new business themes: "primary" \| "secondary" \| "tertiary" \| "darkBackground" | "secondary" | -| cancelLabel | string \| undefined | No | | | | Customise the cancel button label | | -| children | React.ReactNode | No | | | | Child elements | | -| closeButtonDataProps | Pick \| undefined | No | | | | Data tag prop bag for close Button | | -| confirmButtonDataProps | TagProps \| undefined | No | | | | Data tag prop bag for confirmButton | | -| confirmButtonDestructive | boolean \| undefined | No | | | | Apply destructive style to the confirm button | false | -| confirmButtonIconPosition | "before" \| "after" \| undefined | No | | | | Defines a cancel button Icon position related to the children: "before" \| "after" | | -| confirmButtonIconType | IconType \| undefined | No | | | | Defines an Icon type within the confirm button (see Icon for options) | | -| confirmButtonType | "primary" \| "secondary" \| "tertiary" \| "darkBackground" \| undefined | No | | | | Color variants for new business themes: "primary" \| "secondary" \| "tertiary" \| "darkBackground" | "primary" | -| confirmLabel | string \| undefined | No | | | | Customise the confirm button label | | -| contentRef | React.ForwardedRef \| undefined | No | | | | Reference to the scrollable content element | | -| disableAutoFocus | boolean \| undefined | No | | | | | | -| disableCancel | boolean \| undefined | No | | | | Makes cancel button disabled | | -| disableConfirm | boolean \| undefined | No | | | | Makes confirm button disabled | | -| disableEscKey | boolean \| undefined | No | | | | Determines if the Esc Key closes the modal | | -| disableStickyOnSmallScreen | boolean \| undefined | No | | | | When true, header and sticky footer become unstickied for accessibility on small screen devices. On small screen devices, the dialog becomes full width and has no dimmer. | | -| focusFirstElement | HTMLElement \| React.RefObject \| null \| undefined | No | | | | Optional reference to an element meant to be focused on open | | -| footer | React.ReactNode | No | | | | Footer content to be rendered at the bottom of the dialog | | -| gradientKeyLine | boolean \| undefined | No | | | | Adds a gradient keyline to the dialog header | | -| greyBackground | boolean \| undefined | No | | | | Change the background color of the content to grey | | -| headerChildren | React.ReactNode | No | | | | Container for components to be displayed in the header | | -| height | string \| undefined | No | | | | Allows developers to specify a specific height for the dialog. | | -| iconType | "error" \| "warning" \| undefined | No | | | | Defines an Icon type within the button (see Icon for options) | | -| isLoadingConfirm | boolean \| undefined | No | | | | Adds isLoading state into confirm button | | -| onCancel | ((ev: React.KeyboardEvent \| KeyboardEvent \| React.MouseEvent) => void) \| undefined | No | | | | A custom close event handler | | -| restoreFocusOnClose | boolean \| undefined | No | | | | Enables the automatic restoration of focus to the element that invoked the modal when the modal is closed. | | -| showCloseIcon | boolean \| undefined | No | | | | Determines if the close icon is shown | false | -| size | "auto" \| "extra-small" \| "medium-small" \| "medium-large" \| "extra-large" \| "maximise" \| Size \| undefined | No | | | | Size — accepts both legacy values (extra-small, medium-small, etc.) and new values (small, medium, large, fullscreen). | "extra-small" | -| stickyFooter | boolean \| undefined | No | | | | Makes the footer stick to the bottom of the dialog when content scrolls | | -| subtitle | React.ReactNode | No | | | | Subtitle displayed at top of dialog. Its consumers' responsibility to set a suitable accessible name/description for the Dialog if they pass a node to subtitle prop. | | -| title | React.ReactNode | No | | | | Title displayed at top of dialog. Its consumers' responsibility to set a suitable accessible name/description for the Dialog if they pass a node to title prop. | | -| topModalOverride | boolean \| undefined | No | | | | Manually override the internal modal stacking order to set this as top | | -| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| aria-describedby | string \| undefined | No | | | | Prop to specify the aria-describedby property of the Dialog component | | -| aria-label | string \| undefined | No | | | | Prop to specify the aria-label of the Dialog component. To be used only when the title prop is not defined, and the component is not labelled by any internal element. | | -| aria-labelledby | string \| undefined | No | | | | Prop to specify the aria-labelledby property of the Dialog component To be used when the title prop is a custom React Node, or the component is labelled by an internal element other than the title. | | -| disableContentPadding | boolean \| undefined | No | | Yes | Use `contentPadding` instead. | | | -| fullscreen | boolean \| undefined | No | | Yes | Use `size="fullscreen"` instead. | | | -| highlightVariant | string \| undefined | No | | Yes | Use `gradientKeyLine` instead. | | | -| pagesStyling | boolean \| undefined | No | | Yes | PagesStyling is now deprecated and will be removed in a future release | | | - -## Examples -### Default - -**Render** - -```tsx -() => { - const [isOpen, setIsOpen] = useState(defaultOpenState); - return ( - <> - - setIsOpen(false)} - onCancel={() => setIsOpen(false)} - > - Content - - - ); -} -``` - - -### Default with Custom Data Tags - -**Render** - -```tsx -() => { - const [isOpen, setIsOpen] = useState(defaultOpenState); - return ( - <> - - setIsOpen(false)} - onCancel={() => setIsOpen(false)} - cancelButtonDataProps={{ - "data-element": "bang", - "data-role": "wallop", - }} - confirmButtonDataProps={{ - "data-element": "bar", - "data-role": "wiz", - }} - > - Content - - - ); -} -``` - - -### Single Action - -**Render** - -```tsx -() => { - const [isOpen, setIsOpen] = useState(defaultOpenState); - return ( - <> - - setIsOpen(false)} - > - Content - - - ); -} -``` - - -### Cancel Button Destructive - -**Render** - -```tsx -() => { - const [isOpen, setIsOpen] = useState(defaultOpenState); - return ( - <> - - setIsOpen(false)} - onCancel={() => setIsOpen(false)} - > - Content - - - ); -} -``` - - -### Confirm Button Destructive - -**Render** - -```tsx -() => { - const [isOpen, setIsOpen] = useState(defaultOpenState); - return ( - <> - - setIsOpen(false)} - onCancel={() => setIsOpen(false)} - > - Content - - - ); -} -``` - - -### Disable Confirm - -**Render** - -```tsx -() => { - const [isOpen, setIsOpen] = useState(defaultOpenState); - return ( - <> - - setIsOpen(false)} - onCancel={() => setIsOpen(false)} - > - Content - - - ); -} -``` - - -### Disable Cancel - -**Render** - -```tsx -() => { - const [isOpen, setIsOpen] = useState(defaultOpenState); - return ( - <> - - setIsOpen(false)} - onCancel={() => setIsOpen(false)} - > - Content - - - ); -} -``` - - -### Cancel Button Type - -**Render** - -```tsx -() => { - const [isOpen, setIsOpen] = useState(defaultOpenState); - return ( - <> - - setIsOpen(false)} - onCancel={() => setIsOpen(false)} - > - Content - - - ); -} -``` - - -### Confirm Button Type - -**Render** - -```tsx -() => { - const [isOpen, setIsOpen] = useState(defaultOpenState); - return ( - <> - - setIsOpen(false)} - onCancel={() => setIsOpen(false)} - > - Content - - - ); -} -``` - - -### Buttons Icons - -**Render** - -```tsx -() => { - const [isOpen, setIsOpen] = useState(defaultOpenState); - return ( - <> - - setIsOpen(false)} - onCancel={() => setIsOpen(false)} - > - Content - - - ); -} -``` - - -### Is Loading Confirm - -**Render** - -```tsx -() => { - const [isOpen, setIsOpen] = useState(defaultOpenState); - return ( - <> - - setIsOpen(false)} - onCancel={() => setIsOpen(false)} - > - Content - - - ); -} -``` - diff --git a/skills/carbon-react/components/content.md b/skills/carbon-react/components/content.md deleted file mode 100644 index b79cfadbbc..0000000000 --- a/skills/carbon-react/components/content.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -name: carbon-component-content -description: Carbon Content component props and usage examples. ---- - -# Content - -## Import -`import Content from "carbon-react/lib/components/content";` - -## Source -- Export: `./components/content` -- Props interface: `ContentProps` -- Deprecated: Yes -- Deprecation reason: `Content` has been deprecated. See the Carbon documentation for migration details. - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| align | AlignOptions \| undefined | No | | Aligns the content (left, center or right) | "left" | -| bodyFullWidth | boolean \| undefined | No | | Over-rides the calculation of body width based on titleWidth. Sometimes we need the body to be full width while keeping a title width similar to other widths | false | -| children | React.ReactNode | No | | The body of the content component | | -| inline | boolean \| undefined | No | | Displays the content inline with the title | false | -| m | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| title | React.ReactNode | No | | The title of the content component | | -| titleWidth | string \| undefined | No | | Sets a custom width for the title element | | -| variant | VariantOptions \| undefined | No | | Applies a theme to the Content Value: primary, secondary | "primary" | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | - -## Examples -### DefaultStory - - -### InlineContent - -**Args** - -```tsx -{ - inline: true, - children: "This is an example of some content", - } -``` - - -### CustomTitle - -**Args** - -```tsx -{ - title: Title, - variant: "primary", - children: "This is an example of some content", - } -``` - - -### SecondaryStyling - -**Args** - -```tsx -{ - variant: "secondary", - children: "This is an example of some content", - } -``` - - -### MDX Example 1 - -**Args** - -```tsx -import Content from "carbon-react/lib/components/content"; -``` - diff --git a/skills/carbon-react/components/crumb.md b/skills/carbon-react/components/crumb.md deleted file mode 100644 index 3d496c6424..0000000000 --- a/skills/carbon-react/components/crumb.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -name: carbon-component-crumb -description: Carbon Crumb component props and usage examples. ---- - -# Crumb - -## Import -`import { Crumb } from "carbon-react/lib/components/breadcrumbs";` - -## Source -- Export: `./components/breadcrumbs` -- Props interface: `CrumbProps` - -## Props -| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | -| --- | --- | --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | No | | | | Child content to render in the link. | | -| href | string \| undefined | No | | | | An href for an anchor tag. | | -| isCurrent | boolean \| undefined | No | | | | This sets the Crumb to current, does not render Link | | -| onClick | ((ev: React.MouseEvent \| React.MouseEvent) => void) \| undefined | No | | | | Function called when the mouse is clicked. | | -| onKeyDown | ((ev: React.KeyboardEvent \| React.KeyboardEvent) => void) \| undefined | No | | | | Function called when a key is pressed. | | -| onMouseDown | ((ev: React.MouseEvent \| React.MouseEvent) => void) \| undefined | No | | | | Function called when a mouse down event triggers. | | -| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| bold | boolean \| undefined | No | | Yes | The 'bold' prop in Crumb is deprecated and will soon be removed. | Sets the link style to bold | | -| hasFocus | boolean \| undefined | No | | Yes | Intended for internal use only | | | -| linkSize | "medium" \| "large" \| undefined | No | | Yes | The 'linkSize' prop in Crumb is deprecated and will soon be removed. | Sets the correct link size | | -| underline | "always" \| "hover" \| "never" \| undefined | No | | Yes | The 'underline' prop in Crumb is deprecated and will soon be removed. | Specifies when the link underline should be displayed. | | - -## Examples -No Storybook examples found. \ No newline at end of file diff --git a/skills/carbon-react/components/date-input.md b/skills/carbon-react/components/date-input.md deleted file mode 100644 index 0e374d1488..0000000000 --- a/skills/carbon-react/components/date-input.md +++ /dev/null @@ -1,776 +0,0 @@ ---- -name: carbon-component-date-input -description: Carbon DateInput component props and usage examples. ---- - -# DateInput - -## Import -`import DateInput from "carbon-react/lib/components/date";` - -## Source -- Export: `./components/date` -- Props interface: `DateInputProps` - -## Props -| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | -| --- | --- | --- | --- | --- | --- | --- | --- | -| onChange | (ev: DateChangeEvent) => void | Yes | | | | Specify a callback triggered on change | | -| value | string | Yes | | | | The current date string | | -| about | string \| undefined | No | | | | | | -| accept | string \| undefined | No | | | | | | -| accessKey | string \| undefined | No | | | | | | -| align | "left" \| "right" \| undefined | No | | | | | | -| allowEmptyValue | boolean \| undefined | No | | | | Boolean to allow the input to have an empty value | | -| alt | string \| undefined | No | | | | | | -| as | React.ElementType \| undefined | No | | | | Override the variant component | | -| autoCapitalize | (string & {}) \| "none" \| "off" \| "on" \| "sentences" \| "words" \| "characters" \| undefined | No | | | | | | -| autoComplete | HTMLInputAutoCompleteAttribute \| undefined | No | | | | | | -| autoCorrect | string \| undefined | No | | | | | | -| autoFocus | boolean \| undefined | No | | | | If true the Component will be focused when rendered | | -| autoSave | string \| undefined | No | | | | | | -| capture | boolean \| "user" \| "environment" \| undefined | No | | | | | | -| checked | boolean \| undefined | No | | | | | | -| className | string \| undefined | No | | | | | | -| color | string \| undefined | No | | | | | | -| content | string \| undefined | No | | | | | | -| contentEditable | "inherit" \| Booleanish \| "plaintext-only" \| undefined | No | | | | | | -| contextMenu | string \| undefined | No | | | | | | -| dangerouslySetInnerHTML | { __html: string \| TrustedHTML; } \| undefined | No | | | | | | -| datatype | string \| undefined | No | | | | | | -| dateFormatOverride | string \| undefined | No | | | | Date format string to be applied to the date inputs | | -| datePickerAriaLabel | string \| undefined | No | | | | Prop to specify the aria-label attribute of the date picker | | -| datePickerAriaLabelledBy | string \| undefined | No | | | | Prop to specify the aria-labelledby attribute of the date picker | | -| defaultChecked | boolean \| undefined | No | | | | | | -| dir | string \| undefined | No | | | | | | -| disabled | boolean \| undefined | No | | | | If true, the component will be disabled | | -| disablePortal | boolean \| undefined | No | | | | Boolean to toggle where DatePicker is rendered in relation to the Date Input | | -| draggable | Booleanish \| undefined | No | | | | | | -| enterKeyHint | "go" \| "send" \| "search" \| "enter" \| "done" \| "next" \| "previous" \| undefined | No | | | | | | -| error | string \| boolean \| undefined | No | | | | Indicate that error has occurred. | | -| exportparts | string \| undefined | No | | | | | | -| form | string \| undefined | No | | | | | | -| formAction | string \| undefined | No | | | | | | -| formEncType | string \| undefined | No | | | | | | -| formMethod | string \| undefined | No | | | | | | -| formNoValidate | boolean \| undefined | No | | | | | | -| formTarget | string \| undefined | No | | | | | | -| height | string \| number \| undefined | No | | | | | | -| hidden | boolean \| undefined | No | | | | | | -| id | string \| undefined | No | | | | Unique identifier for the input. Label id will be based on it, using following pattern: [id]-label. Will use a randomly generated GUID if none is provided. | | -| inlist | any | No | | | | | | -| inputHint | string \| undefined | No | | | | A hint string rendered before the input but after the label. Intended to describe the purpose or content of the input. | | -| inputMode | "email" \| "none" \| "search" \| "text" \| "tel" \| "url" \| "numeric" \| "decimal" \| undefined | No | | | | Hints at the type of data that might be entered by the user while editing the element or its contents | | -| inputWidth | number \| undefined | No | | | | The width of the input as a percentage | | -| is | string \| undefined | No | | | | Specify that a standard HTML element should behave like a defined custom built-in element | | -| itemID | string \| undefined | No | | | | | | -| itemProp | string \| undefined | No | | | | | | -| itemRef | string \| undefined | No | | | | | | -| itemScope | boolean \| undefined | No | | | | | | -| itemType | string \| undefined | No | | | | | | -| label | string \| undefined | No | | | | Label content | | -| labelInline | boolean \| undefined | No | | | | When true label is inline. | | -| lang | string \| undefined | No | | | | | | -| list | string \| undefined | No | | | | | | -| m | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| max | string \| number \| undefined | No | | | | | | -| maxDate | string \| undefined | No | | | | Maximum possible date YYYY-MM-DD | | -| maxLength | number \| undefined | No | | | | | | -| maxWidth | string \| undefined | No | | | | Prop for specifying the max width of the input. Leaving the `maxWidth` prop with no value will default the width to '100%' | | -| mb | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| min | string \| number \| undefined | No | | | | | | -| minDate | string \| undefined | No | | | | Minimum possible date YYYY-MM-DD | | -| minLength | number \| undefined | No | | | | | | -| ml | ResponsiveValue \| undefined | No | | | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | | | Margin on top | | -| multiple | boolean \| undefined | No | | | | | | -| mx | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| name | string \| undefined | No | | | | Name of the input | | -| nonce | string \| undefined | No | | | | | | -| onAbort | ReactEventHandler \| undefined | No | | | | | | -| onAbortCapture | ReactEventHandler \| undefined | No | | | | | | -| onAnimationEnd | AnimationEventHandler \| undefined | No | | | | | | -| onAnimationEndCapture | AnimationEventHandler \| undefined | No | | | | | | -| onAnimationIteration | AnimationEventHandler \| undefined | No | | | | | | -| onAnimationIterationCapture | AnimationEventHandler \| undefined | No | | | | | | -| onAnimationStart | AnimationEventHandler \| undefined | No | | | | | | -| onAnimationStartCapture | AnimationEventHandler \| undefined | No | | | | | | -| onAuxClick | MouseEventHandler \| undefined | No | | | | | | -| onAuxClickCapture | MouseEventHandler \| undefined | No | | | | | | -| onBeforeInput | InputEventHandler \| undefined | No | | | | | | -| onBeforeInputCapture | FormEventHandler \| undefined | No | | | | | | -| onBlur | ((ev: DateChangeEvent) => void) \| undefined | No | | | | Specify a callback triggered on blur | | -| onBlurCapture | FocusEventHandler \| undefined | No | | | | | | -| onCanPlay | ReactEventHandler \| undefined | No | | | | | | -| onCanPlayCapture | ReactEventHandler \| undefined | No | | | | | | -| onCanPlayThrough | ReactEventHandler \| undefined | No | | | | | | -| onCanPlayThroughCapture | ReactEventHandler \| undefined | No | | | | | | -| onChangeCapture | FormEventHandler \| undefined | No | | | | | | -| onClick | ((ev: React.MouseEvent \| React.KeyboardEvent) => void) \| undefined | No | | | | Specify a callback triggered on click | | -| onClickCapture | MouseEventHandler \| undefined | No | | | | | | -| onCompositionEnd | CompositionEventHandler \| undefined | No | | | | | | -| onCompositionEndCapture | CompositionEventHandler \| undefined | No | | | | | | -| onCompositionStart | CompositionEventHandler \| undefined | No | | | | | | -| onCompositionStartCapture | CompositionEventHandler \| undefined | No | | | | | | -| onCompositionUpdate | CompositionEventHandler \| undefined | No | | | | | | -| onCompositionUpdateCapture | CompositionEventHandler \| undefined | No | | | | | | -| onContextMenu | MouseEventHandler \| undefined | No | | | | | | -| onContextMenuCapture | MouseEventHandler \| undefined | No | | | | | | -| onCopy | ClipboardEventHandler \| undefined | No | | | | | | -| onCopyCapture | ClipboardEventHandler \| undefined | No | | | | | | -| onCut | ClipboardEventHandler \| undefined | No | | | | | | -| onCutCapture | ClipboardEventHandler \| undefined | No | | | | | | -| onDoubleClick | MouseEventHandler \| undefined | No | | | | | | -| onDoubleClickCapture | MouseEventHandler \| undefined | No | | | | | | -| onDrag | DragEventHandler \| undefined | No | | | | | | -| onDragCapture | DragEventHandler \| undefined | No | | | | | | -| onDragEnd | DragEventHandler \| undefined | No | | | | | | -| onDragEndCapture | DragEventHandler \| undefined | No | | | | | | -| onDragEnter | DragEventHandler \| undefined | No | | | | | | -| onDragEnterCapture | DragEventHandler \| undefined | No | | | | | | -| onDragExit | DragEventHandler \| undefined | No | | | | | | -| onDragExitCapture | DragEventHandler \| undefined | No | | | | | | -| onDragLeave | DragEventHandler \| undefined | No | | | | | | -| onDragLeaveCapture | DragEventHandler \| undefined | No | | | | | | -| onDragOver | DragEventHandler \| undefined | No | | | | | | -| onDragOverCapture | DragEventHandler \| undefined | No | | | | | | -| onDragStart | DragEventHandler \| undefined | No | | | | | | -| onDragStartCapture | DragEventHandler \| undefined | No | | | | | | -| onDrop | DragEventHandler \| undefined | No | | | | | | -| onDropCapture | DragEventHandler \| undefined | No | | | | | | -| onDurationChange | ReactEventHandler \| undefined | No | | | | | | -| onDurationChangeCapture | ReactEventHandler \| undefined | No | | | | | | -| onEmptied | ReactEventHandler \| undefined | No | | | | | | -| onEmptiedCapture | ReactEventHandler \| undefined | No | | | | | | -| onEncrypted | ReactEventHandler \| undefined | No | | | | | | -| onEncryptedCapture | ReactEventHandler \| undefined | No | | | | | | -| onEnded | ReactEventHandler \| undefined | No | | | | | | -| onEndedCapture | ReactEventHandler \| undefined | No | | | | | | -| onError | ReactEventHandler \| undefined | No | | | | | | -| onErrorCapture | ReactEventHandler \| undefined | No | | | | | | -| onFocus | ((ev: React.FocusEvent) => void) \| undefined | No | | | | Event handler for the focus event | | -| onFocusCapture | FocusEventHandler \| undefined | No | | | | | | -| onGotPointerCapture | PointerEventHandler \| undefined | No | | | | | | -| onGotPointerCaptureCapture | PointerEventHandler \| undefined | No | | | | | | -| onInput | FormEventHandler \| undefined | No | | | | | | -| onInputCapture | FormEventHandler \| undefined | No | | | | | | -| onInvalid | FormEventHandler \| undefined | No | | | | | | -| onInvalidCapture | FormEventHandler \| undefined | No | | | | | | -| onKeyDown | ((ev: React.KeyboardEvent) => void) \| undefined | No | | | | Specify a callback triggered on keyDown | | -| onKeyDownCapture | KeyboardEventHandler \| undefined | No | | | | | | -| onKeyUp | KeyboardEventHandler \| undefined | No | | | | | | -| onKeyUpCapture | KeyboardEventHandler \| undefined | No | | | | | | -| onLoad | ReactEventHandler \| undefined | No | | | | | | -| onLoadCapture | ReactEventHandler \| undefined | No | | | | | | -| onLoadedData | ReactEventHandler \| undefined | No | | | | | | -| onLoadedDataCapture | ReactEventHandler \| undefined | No | | | | | | -| onLoadedMetadata | ReactEventHandler \| undefined | No | | | | | | -| onLoadedMetadataCapture | ReactEventHandler \| undefined | No | | | | | | -| onLoadStart | ReactEventHandler \| undefined | No | | | | | | -| onLoadStartCapture | ReactEventHandler \| undefined | No | | | | | | -| onLostPointerCapture | PointerEventHandler \| undefined | No | | | | | | -| onLostPointerCaptureCapture | PointerEventHandler \| undefined | No | | | | | | -| onMouseDownCapture | MouseEventHandler \| undefined | No | | | | | | -| onMouseEnter | MouseEventHandler \| undefined | No | | | | | | -| onMouseLeave | MouseEventHandler \| undefined | No | | | | | | -| onMouseMove | MouseEventHandler \| undefined | No | | | | | | -| onMouseMoveCapture | MouseEventHandler \| undefined | No | | | | | | -| onMouseOut | MouseEventHandler \| undefined | No | | | | | | -| onMouseOutCapture | MouseEventHandler \| undefined | No | | | | | | -| onMouseOver | MouseEventHandler \| undefined | No | | | | | | -| onMouseOverCapture | MouseEventHandler \| undefined | No | | | | | | -| onMouseUp | MouseEventHandler \| undefined | No | | | | | | -| onMouseUpCapture | MouseEventHandler \| undefined | No | | | | | | -| onPaste | ClipboardEventHandler \| undefined | No | | | | | | -| onPasteCapture | ClipboardEventHandler \| undefined | No | | | | | | -| onPause | ReactEventHandler \| undefined | No | | | | | | -| onPauseCapture | ReactEventHandler \| undefined | No | | | | | | -| onPickerClose | (() => void) \| undefined | No | | | | Callback triggered when the picker is closed | | -| onPickerOpen | (() => void) \| undefined | No | | | | Callback triggered when the picker is opened | | -| onPlay | ReactEventHandler \| undefined | No | | | | | | -| onPlayCapture | ReactEventHandler \| undefined | No | | | | | | -| onPlaying | ReactEventHandler \| undefined | No | | | | | | -| onPlayingCapture | ReactEventHandler \| undefined | No | | | | | | -| onPointerCancel | PointerEventHandler \| undefined | No | | | | | | -| onPointerCancelCapture | PointerEventHandler \| undefined | No | | | | | | -| onPointerDown | PointerEventHandler \| undefined | No | | | | | | -| onPointerDownCapture | PointerEventHandler \| undefined | No | | | | | | -| onPointerEnter | PointerEventHandler \| undefined | No | | | | | | -| onPointerLeave | PointerEventHandler \| undefined | No | | | | | | -| onPointerMove | PointerEventHandler \| undefined | No | | | | | | -| onPointerMoveCapture | PointerEventHandler \| undefined | No | | | | | | -| onPointerOut | PointerEventHandler \| undefined | No | | | | | | -| onPointerOutCapture | PointerEventHandler \| undefined | No | | | | | | -| onPointerOver | PointerEventHandler \| undefined | No | | | | | | -| onPointerOverCapture | PointerEventHandler \| undefined | No | | | | | | -| onPointerUp | PointerEventHandler \| undefined | No | | | | | | -| onPointerUpCapture | PointerEventHandler \| undefined | No | | | | | | -| onProgress | ReactEventHandler \| undefined | No | | | | | | -| onProgressCapture | ReactEventHandler \| undefined | No | | | | | | -| onRateChange | ReactEventHandler \| undefined | No | | | | | | -| onRateChangeCapture | ReactEventHandler \| undefined | No | | | | | | -| onReset | FormEventHandler \| undefined | No | | | | | | -| onResetCapture | FormEventHandler \| undefined | No | | | | | | -| onScroll | UIEventHandler \| undefined | No | | | | | | -| onScrollCapture | UIEventHandler \| undefined | No | | | | | | -| onSeeked | ReactEventHandler \| undefined | No | | | | | | -| onSeekedCapture | ReactEventHandler \| undefined | No | | | | | | -| onSeeking | ReactEventHandler \| undefined | No | | | | | | -| onSeekingCapture | ReactEventHandler \| undefined | No | | | | | | -| onSelect | ReactEventHandler \| undefined | No | | | | | | -| onSelectCapture | ReactEventHandler \| undefined | No | | | | | | -| onStalled | ReactEventHandler \| undefined | No | | | | | | -| onStalledCapture | ReactEventHandler \| undefined | No | | | | | | -| onSubmit | FormEventHandler \| undefined | No | | | | | | -| onSubmitCapture | FormEventHandler \| undefined | No | | | | | | -| onSuspend | ReactEventHandler \| undefined | No | | | | | | -| onSuspendCapture | ReactEventHandler \| undefined | No | | | | | | -| onTimeUpdate | ReactEventHandler \| undefined | No | | | | | | -| onTimeUpdateCapture | ReactEventHandler \| undefined | No | | | | | | -| onTouchCancel | TouchEventHandler \| undefined | No | | | | | | -| onTouchCancelCapture | TouchEventHandler \| undefined | No | | | | | | -| onTouchEnd | TouchEventHandler \| undefined | No | | | | | | -| onTouchEndCapture | TouchEventHandler \| undefined | No | | | | | | -| onTouchMove | TouchEventHandler \| undefined | No | | | | | | -| onTouchMoveCapture | TouchEventHandler \| undefined | No | | | | | | -| onTouchStart | TouchEventHandler \| undefined | No | | | | | | -| onTouchStartCapture | TouchEventHandler \| undefined | No | | | | | | -| onTransitionEnd | TransitionEventHandler \| undefined | No | | | | | | -| onTransitionEndCapture | TransitionEventHandler \| undefined | No | | | | | | -| onVolumeChange | ReactEventHandler \| undefined | No | | | | | | -| onVolumeChangeCapture | ReactEventHandler \| undefined | No | | | | | | -| onWaiting | ReactEventHandler \| undefined | No | | | | | | -| onWaitingCapture | ReactEventHandler \| undefined | No | | | | | | -| onWheel | WheelEventHandler \| undefined | No | | | | | | -| onWheelCapture | WheelEventHandler \| undefined | No | | | | | | -| part | string \| undefined | No | | | | | | -| pattern | string \| undefined | No | | | | | | -| pickerProps | PickerProps \| undefined | No | | | | Pass any props that match the DayPickerProps interface to override default behaviors See [DayPickerProps](https://daypicker.dev/api/type-aliases/DayPickerProps) for a full list of available props | | -| positionedChildren | React.ReactNode | No | | | | Container for DatePicker or SelectList components | | -| prefix | string \| undefined | No | | | | Emphasized part of the displayed text | | -| property | string \| undefined | No | | | | | | -| radioGroup | string \| undefined | No | | | | | | -| readOnly | boolean \| undefined | No | | | | If true, the component will be read-only | | -| rel | string \| undefined | No | | | | | | -| required | boolean \| undefined | No | | | | Flag to configure component as mandatory | | -| resource | string \| undefined | No | | | | | | -| results | number \| undefined | No | | | | | | -| rev | string \| undefined | No | | | | | | -| role | AriaRole \| undefined | No | | | | | | -| security | string \| undefined | No | | | | | | -| size | "small" \| "medium" \| "large" \| undefined | No | | | | Size of an input | | -| slot | string \| undefined | No | | | | | | -| spellCheck | Booleanish \| undefined | No | | | | | | -| src | string \| undefined | No | | | | | | -| step | string \| number \| undefined | No | | | | | | -| style | CSSProperties \| undefined | No | | | | | | -| suppressContentEditableWarning | boolean \| undefined | No | | | | | | -| suppressHydrationWarning | boolean \| undefined | No | | | | | | -| tabIndex | number \| undefined | No | | | | | | -| title | string \| undefined | No | | | | | | -| translate | "yes" \| "no" \| undefined | No | | | | | | -| type | HTMLInputTypeAttribute \| undefined | No | | | | | | -| typeof | string \| undefined | No | | | | | | -| unselectable | "off" \| "on" \| undefined | No | | | | | | -| validationIconId | string \| undefined | No | | | | Id of the validation icon | | -| validationMessagePositionTop | boolean \| undefined | No | | | | Render the ValidationMessage above the Textbox input when validationRedesignOptIn flag is set | | -| vocab | string \| undefined | No | | | | | | -| warning | string \| boolean \| undefined | No | | | | Indicate that warning has occurred. | | -| width | string \| number \| undefined | No | | | | | | -| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| aria-activedescendant | string \| undefined | No | | | | Identifies the currently active element when DOM focus is on a composite widget, textbox, group, or application. | | -| aria-atomic | Booleanish \| undefined | No | | | | Indicates whether assistive technologies will present all, or only parts of, the changed region based on the change notifications defined by the aria-relevant attribute. | | -| aria-autocomplete | "none" \| "inline" \| "list" \| "both" \| undefined | No | | | | Indicates whether inputting text could trigger display of one or more predictions of the user's intended value for an input and specifies how predictions would be presented if they are made. | | -| aria-braillelabel | string \| undefined | No | | | | Indicates an element is being modified and that assistive technologies MAY want to wait until the modifications are complete before exposing them to the user. Defines a string value that labels the current element, which is intended to be converted into Braille. | | -| aria-brailleroledescription | string \| undefined | No | | | | Defines a human-readable, author-localized abbreviated description for the role of an element, which is intended to be converted into Braille. | | -| aria-busy | Booleanish \| undefined | No | | | | | | -| aria-checked | boolean \| "true" \| "false" \| "mixed" \| undefined | No | | | | Indicates the current "checked" state of checkboxes, radio buttons, and other widgets. | | -| aria-colcount | number \| undefined | No | | | | Defines the total number of columns in a table, grid, or treegrid. | | -| aria-colindex | number \| undefined | No | | | | Defines an element's column index or position with respect to the total number of columns within a table, grid, or treegrid. | | -| aria-colindextext | string \| undefined | No | | | | Defines a human readable text alternative of aria-colindex. | | -| aria-colspan | number \| undefined | No | | | | Defines the number of columns spanned by a cell or gridcell within a table, grid, or treegrid. | | -| aria-controls | string \| undefined | No | | | | Identifies the element (or elements) whose contents or presence are controlled by the current element. | | -| aria-current | boolean \| "location" \| "page" \| "time" \| "true" \| "false" \| "step" \| "date" \| undefined | No | | | | Indicates the element that represents the current item within a container or set of related elements. | | -| aria-describedby | string \| undefined | No | | | | The ID of the input's description, is set along with hint text and error message. | | -| aria-description | string \| undefined | No | | | | Defines a string value that describes or annotates the current element. | | -| aria-details | string \| undefined | No | | | | Identifies the element that provides a detailed, extended description for the object. | | -| aria-disabled | Booleanish \| undefined | No | | | | Indicates that the element is perceivable but disabled, so it is not editable or otherwise operable. | | -| aria-errormessage | string \| undefined | No | | | | Identifies the element that provides an error message for the object. | | -| aria-expanded | Booleanish \| undefined | No | | | | Indicates whether the element, or another grouping element it controls, is currently expanded or collapsed. | | -| aria-flowto | string \| undefined | No | | | | Identifies the next element (or elements) in an alternate reading order of content which, at the user's discretion, allows assistive technology to override the general default of reading in document source order. | | -| aria-haspopup | boolean \| "grid" \| "dialog" \| "menu" \| "true" \| "false" \| "listbox" \| "tree" \| undefined | No | | | | Indicates the availability and type of interactive popup element, such as menu or dialog, that can be triggered by an element. | | -| aria-hidden | Booleanish \| undefined | No | | | | Indicates whether the element is exposed to an accessibility API. | | -| aria-invalid | boolean \| "true" \| "false" \| "grammar" \| "spelling" \| undefined | No | | | | Indicates the entered value does not conform to the format expected by the application. | | -| aria-keyshortcuts | string \| undefined | No | | | | Indicates keyboard shortcuts that an author has implemented to activate or give focus to an element. | | -| aria-label | string \| undefined | No | | | | Defines a string value that labels the current element. | | -| aria-labelledby | string \| undefined | No | | | | Prop to specify the aria-labelledby property of the component | | -| aria-level | number \| undefined | No | | | | Defines the hierarchical level of an element within a structure. | | -| aria-live | "off" \| "assertive" \| "polite" \| undefined | No | | | | Indicates that an element will be updated, and describes the types of updates the user agents, assistive technologies, and user can expect from the live region. | | -| aria-modal | Booleanish \| undefined | No | | | | Indicates whether an element is modal when displayed. | | -| aria-multiline | Booleanish \| undefined | No | | | | Indicates whether a text box accepts multiple lines of input or only a single line. | | -| aria-multiselectable | Booleanish \| undefined | No | | | | Indicates that the user may select more than one item from the current selectable descendants. | | -| aria-orientation | "horizontal" \| "vertical" \| undefined | No | | | | Indicates whether the element's orientation is horizontal, vertical, or unknown/ambiguous. | | -| aria-owns | string \| undefined | No | | | | Identifies an element (or elements) in order to define a visual, functional, or contextual parent/child relationship between DOM elements where the DOM hierarchy cannot be used to represent the relationship. | | -| aria-placeholder | string \| undefined | No | | | | Defines a short hint (a word or short phrase) intended to aid the user with data entry when the control has no value. A hint could be a sample value or a brief description of the expected format. | | -| aria-posinset | number \| undefined | No | | | | Defines an element's number or position in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM. | | -| aria-pressed | boolean \| "true" \| "false" \| "mixed" \| undefined | No | | | | Indicates the current "pressed" state of toggle buttons. | | -| aria-readonly | Booleanish \| undefined | No | | | | Indicates that the element is not editable, but is otherwise operable. | | -| aria-relevant | "text" \| "additions" \| "additions removals" \| "additions text" \| "all" \| "removals" \| "removals additions" \| "removals text" \| "text additions" \| "text removals" \| undefined | No | | | | Indicates what notifications the user agent will trigger when the accessibility tree within a live region is modified. | | -| aria-required | Booleanish \| undefined | No | | | | Indicates that user input is required on the element before a form may be submitted. | | -| aria-roledescription | string \| undefined | No | | | | Defines a human-readable, author-localized description for the role of an element. | | -| aria-rowcount | number \| undefined | No | | | | Defines the total number of rows in a table, grid, or treegrid. | | -| aria-rowindex | number \| undefined | No | | | | Defines an element's row index or position with respect to the total number of rows within a table, grid, or treegrid. | | -| aria-rowindextext | string \| undefined | No | | | | Defines a human readable text alternative of aria-rowindex. | | -| aria-rowspan | number \| undefined | No | | | | Defines the number of rows spanned by a cell or gridcell within a table, grid, or treegrid. | | -| aria-selected | Booleanish \| undefined | No | | | | Indicates the current "selected" state of various widgets. | | -| aria-setsize | number \| undefined | No | | | | Defines the number of items in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM. | | -| aria-sort | "none" \| "ascending" \| "descending" \| "other" \| undefined | No | | | | Indicates if items in a table or grid are sorted in ascending or descending order. | | -| aria-valuemax | number \| undefined | No | | | | Defines the maximum allowed value for a range widget. | | -| aria-valuemin | number \| undefined | No | | | | Defines the minimum allowed value for a range widget. | | -| aria-valuenow | number \| undefined | No | | | | Defines the current value for a range widget. | | -| aria-valuetext | string \| undefined | No | | | | Defines the human readable text alternative of aria-valuenow for a range widget. | | -| adaptiveLabelBreakpoint | number \| undefined | No | | Yes | `adaptiveLabelBreakpoint` has been deprecated, the functionality will no longer work. | | | -| fieldHelp | React.ReactNode | No | | Yes | `fieldHelp` has been deprecated, `inputHint` should be used instead. [Legacy] Help content to be displayed under an input. | | | -| helpAriaLabel | string \| undefined | No | | Yes | `helpAriaLabel` has been deprecated, the functionality will no longer work. | | | -| info | string \| boolean \| undefined | No | | Yes | `info` has been deprecated, the functionality will no longer work. | | | -| labelAlign | "left" \| "right" \| undefined | No | | Yes | `labelAlign` has been deprecated, the functionality will no longer work. | | | -| labelHelp | React.ReactNode | No | | Yes | `labelHelp` has been deprecated, `inputHint` should be used instead. [Legacy] Text applied to label help tooltip. When opted into new design validations string values will render as a hint above the input, unless an `inputHint` prop is also passed. | | | -| labelSpacing | 1 \| 2 \| undefined | No | | Yes | `labelSpacing` has been deprecated, the functionality will no longer work. | | | -| labelWidth | number \| undefined | No | | Yes | `labelWidth` has been deprecated, the functionality will no longer work. | | | -| onKeyPress | KeyboardEventHandler \| undefined | No | | Yes | Use `onKeyUp` or `onKeyDown` instead | | | -| onKeyPressCapture | KeyboardEventHandler \| undefined | No | | Yes | Use `onKeyUpCapture` or `onKeyDownCapture` instead | | | -| reverse | boolean \| undefined | No | | Yes | `reverse` has been deprecated, the functionality will no longer work. | | | -| tooltipId | string \| undefined | No | | Yes | `tooltipId` has been deprecated, the functionality will no longer work. | | | -| tooltipPosition | "left" \| "right" \| "bottom" \| "top" \| undefined | No | | Yes | `tooltipPosition` has been deprecated, the functionality will no longer work. | | | -| validationOnLabel | boolean \| undefined | No | | Yes | `validationOnLabel` has been deprecated, the functionality will no longer work. | | | -| aria-dropeffect | "copy" \| "link" \| "none" \| "execute" \| "move" \| "popup" \| undefined | No | | Yes | in ARIA 1.1 | Indicates what functions can be performed when a dragged object is released on the drop target. | | -| aria-grabbed | Booleanish \| undefined | No | | Yes | in ARIA 1.1 | Indicates an element's "grabbed" state in a drag-and-drop operation. | | - -## Examples -### Default - -**Render** - -```tsx -() => { - const [state, setState] = useState("04/04/2019"); - const setValue = (ev: DateChangeEvent) => { - setState(ev.target.value.formattedValue); - }; - return ( - - ); -} -``` - - -### Input Hint - -**Render** - -```tsx -() => { - const [state, setState] = useState("04/04/2019"); - const setValue = (ev: DateChangeEvent) => { - setState(ev.target.value.formattedValue); - }; - return ( - - ); -} -``` - - -### Sizes - -**Render** - -```tsx -() => { - const [state, setState] = useState("01/10/2016"); - const setValue = (ev: DateChangeEvent) => { - setState(ev.target.value.formattedValue); - }; - return ( - <> - {(["small", "medium", "large"] as const).map((size) => ( - - ))} - - ); -} -``` - - -### Disabled - -**Render** - -```tsx -() => { - const [state, setState] = useState("01/10/2016"); - const setValue = (ev: DateChangeEvent) => { - setState(ev.target.value.formattedValue); - }; - return ; -} -``` - - -### Read Only - -**Render** - -```tsx -() => { - const [state, setState] = useState("01/10/2016"); - const setValue = (ev: DateChangeEvent) => { - setState(ev.target.value.formattedValue); - }; - return ; -} -``` - - -### Empty - -**Render** - -```tsx -() => { - const [state, setState] = useState(""); - const setValue = (ev: DateChangeEvent) => { - setState(ev.target.value.formattedValue); - }; - return ( - <> - - - - - - - ); -} -``` - - -### Disabled Dates - -**Render** - -```tsx -({ onChange, ...args }: DateInputProps) => { - const [state, setState] = useState("04/04/2019"); - const setValue = (ev: DateChangeEvent) => { - setState(ev.target.value.formattedValue); - }; - return ( - { - setValue(ev); - onChange?.(ev); - }} - /> - ); -} -``` - - -### Disabled Dates using pickerProps - -**Render** - -```tsx -() => { - const [state, setState] = useState("04/04/2019"); - const setValue = (ev: DateChangeEvent) => { - setState(ev.target.value.formattedValue); - }; - - const isWeekend = (day: Date) => [0, 6].includes(day.getDay()); - - return ( - - ); -} -``` - - -### With Label Inline - -**Render** - -```tsx -() => { - const [state, setState] = useState("01/10/2016"); - const setValue = (ev: DateChangeEvent) => { - setState(ev.target.value.formattedValue); - }; - return ( - - ); -} -``` - - -### With Custom Width - -**Render** - -```tsx -() => { - const [state, setState] = useState("01/10/2016"); - const setValue = (ev: DateChangeEvent) => { - setState(ev.target.value.formattedValue); - }; - return ( - - ); -} -``` - - -### With Field Help - -**Render** - -```tsx -() => { - const [state, setState] = useState("01/10/2016"); - const setValue = (ev: DateChangeEvent) => { - setState(ev.target.value.formattedValue); - }; - return ( - - ); -} -``` - - -### With Disabled Portal - -**Render** - -```tsx -() => { - const [state, setState] = useState("01/10/2016"); - const setValue = (ev: DateChangeEvent) => { - setState(ev.target.value.formattedValue); - }; - return ( - - ); -} -``` - - -### Required - -**Render** - -```tsx -() => { - const [state, setState] = useState("01/10/2016"); - const setValue = (ev: DateChangeEvent) => { - setState(ev.target.value.formattedValue); - }; - return ; -} -``` - - -### Locale Override - -**Render** - -```tsx -() => { - const [state, setState] = useState("2022-04-05"); - const handleChange = (ev: DateChangeEvent) => { - setState(ev.target.value.formattedValue); - }; - const [state2, setState2] = useState("2022-04-05"); - const handleChange2 = (ev: DateChangeEvent) => { - setState2(ev.target.value.formattedValue); - }; - return ( - - "de-DE", - date: { - dateFnsLocale: () => de, - ariaLabels: { - previousMonthButton: () => "Vorheriger Monat", - nextMonthButton: () => "Nächster Monat", - }, - }, - }} - > - - - "zh-CN", - date: { - dateFnsLocale: () => zhCN, - ariaLabels: { - previousMonthButton: () => "上个月", - nextMonthButton: () => "下个月", - }, - }, - }} - > - - - - ); -} -``` - - -### Locale Format Override - -**Render** - -```tsx -({ - onChange, - ...args -}: DateInputProps) => { - const [stateKey, setStateKey] = useState("2019-04-05"); - const handleChangeKey = (ev: DateChangeEvent) => { - setStateKey(ev.target.value.formattedValue); - }; - - const [stateProp, setStateProp] = useState("05/04/2019"); - const handleChangeProp = (ev: DateChangeEvent) => { - setStateProp(ev.target.value.formattedValue); - }; - - return ( - - "de-DE", - date: { - dateFnsLocale: () => de, - ariaLabels: { - previousMonthButton: () => "Vorheriger Monat", - nextMonthButton: () => "Nächster Monat", - }, - dateFormatOverride: "yyyy-MM-dd", - }, - }} - > - { - handleChangeKey(ev); - onChange?.(ev); - }} - mb={2} - /> - - { - handleChangeProp(ev); - onChange?.(ev); - }} - dateFormatOverride="dd/MM/yyyy" - /> - - - ); -} -``` - diff --git a/skills/carbon-react/components/date-range.md b/skills/carbon-react/components/date-range.md deleted file mode 100644 index df6fa438cf..0000000000 --- a/skills/carbon-react/components/date-range.md +++ /dev/null @@ -1,312 +0,0 @@ ---- -name: carbon-component-date-range -description: Carbon DateRange component props and usage examples. ---- - -# DateRange - -## Import -`import DateRange from "carbon-react/lib/components/date-range";` - -## Source -- Export: `./components/date-range` -- Props interface: `DateRangeProps` - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| onChange | (ev: DateRangeChangeEvent) => void | Yes | | Specify a callback triggered on change | | -| value | string[] | Yes | | An array containing the value of startDate and endDate | | -| dateFormatOverride | string \| undefined | No | | Date format string to be applied to the date inputs | | -| datePickerEndAriaLabel | string \| undefined | No | | Prop to specify the aria-label attribute of the end date picker | | -| datePickerEndAriaLabelledBy | string \| undefined | No | | Prop to specify the aria-labelledby attribute of the end date picker | | -| datePickerStartAriaLabel | string \| undefined | No | | Prop to specify the aria-label attribute of the start date picker | | -| datePickerStartAriaLabelledBy | string \| undefined | No | | Prop to specify the aria-labelledby attribute of the start date picker | | -| endDateProps | Omit, "required"> \| undefined | No | | Props for the child end Date component | {} | -| endError | string \| boolean \| undefined | No | | Indicate that error has occurred on end date. Pass string to display icon, tooltip and red border. Pass true boolean to only display red border. | | -| endInfo | string \| boolean \| undefined | No | | [Legacy] Indicate additional information for end date. Pass string to display icon, tooltip and blue border. Pass true boolean to only display blue border. | | -| endLabel | string \| undefined | No | | Optional label for endDate field | | -| endRef | React.ForwardedRef \| undefined | No | | A React ref to pass to the second of the two Date Input fields | | -| endWarning | string \| boolean \| undefined | No | | Indicate that warning has occurred on end date. Pass string to display icon, tooltip and orange border. Pass true boolean to only display orange border. | | -| id | string \| undefined | No | | An optional string prop to provide an id to the component | | -| labelsInline | boolean \| undefined | No | | [Legacy] Display labels inline | | -| m | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| name | string \| undefined | No | | An optional string prop to provide a name to the component | | -| onBlur | ((ev: DateRangeChangeEvent) => void) \| undefined | No | | Specify a callback triggered on blur | | -| required | boolean \| undefined | No | | Flag to configure component as mandatory. | | -| startDateProps | Omit, "required"> \| undefined | No | | Props for the child start Date component | {} | -| startError | string \| boolean \| undefined | No | | Indicate that error has occurred on start date. Pass string to display icon, tooltip and red border. Pass true boolean to only display red border. | | -| startInfo | string \| boolean \| undefined | No | | [Legacy] Indicate additional information for start date. Pass string to display icon, tooltip and blue border. Pass true boolean to only display blue border. | | -| startLabel | string \| undefined | No | | Optional label for startDate field | | -| startRef | React.ForwardedRef \| undefined | No | | A React ref to pass to the first of the two Date Input fields | | -| startWarning | string \| boolean \| undefined | No | | Indicate that warning has occurred on start date. Pass string to display icon, tooltip and orange border. Pass true boolean to only display orange border. | | -| tooltipPosition | "left" \| "right" \| "bottom" \| "top" \| undefined | No | | [Legacy] Overrides the default tooltip position | | -| validationMessagePositionTop | boolean \| undefined | No | | Render the ValidationMessage above the Date inputs when validationRedesignOptIn flag is set | true | -| validationOnLabel | boolean \| undefined | No | | [Legacy] When true, validation icons will be placed on labels instead of being placed on the inputs | | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | - -## Examples -### Default - -**Render** - -```tsx -() => { - const [state, setState] = useState(["01/10/2016", "30/10/2016"]); - const handleChange = (ev: DateRangeChangeEvent) => { - const newValue = [ - ev.target.value[0].formattedValue, - ev.target.value[1].formattedValue, - ]; - setState(newValue); - }; - return ( - - ); -} -``` - - -### Labels Inline - -**Render** - -```tsx -() => { - const [state, setState] = useState(["01/10/2016", "30/10/2016"]); - const handleChange = (ev: DateRangeChangeEvent) => { - const newValue = [ - ev.target.value[0].formattedValue, - ev.target.value[1].formattedValue, - ]; - setState(newValue); - }; - return ( - - ); -} -``` - - -### Allow Empty Value - -**Render** - -```tsx -() => { - const [state, setState] = useState(["", ""]); - const handleChange = (ev: DateRangeChangeEvent) => { - const newValue = [ - ev.target.value[0].formattedValue, - ev.target.value[1].formattedValue, - ]; - setState(newValue); - }; - return ( - - ); -} -``` - - -### With Disabled Dates - -**Render** - -```tsx -() => { - const [state, setState] = useState(["2019-03-17", "2019-04-17"]); - const handleChange = (ev: DateRangeChangeEvent) => { - const newValue = [ - ev.target.value[0].formattedValue, - ev.target.value[1].formattedValue, - ]; - setState(newValue); - }; - - const isWeekend = (day: Date) => [0, 6].includes(day.getDay()); - - return ( - - ); -} -``` - - -### Locale Override Example Implementation - -**Render** - -```tsx -() => { - const [state, setState] = useState(["01/10/2016", "30/10/2016"]); - const handleChange = (ev: DateRangeChangeEvent) => { - const newValue = [ - ev.target.value[0].formattedValue, - ev.target.value[1].formattedValue, - ]; - setState(newValue); - }; - return ( -
- "fr-FR", - date: { - dateFnsLocale: () => fr, - ariaLabels: { - previousMonthButton: () => "Mois précédent", - nextMonthButton: () => "Mois prochain", - }, - }, - }} - > - - -
- ); -} -``` - - -### Required - -**Render** - -```tsx -() => { - const [state, setState] = useState(["01/10/2016", "30/10/2016"]); - const handleChange = (ev: DateRangeChangeEvent) => { - const newValue = [ - ev.target.value[0].formattedValue, - ev.target.value[1].formattedValue, - ]; - setState(newValue); - }; - return ( - - ); -} -``` - - -### Locale Format Override Example Implementation - -**Args** - -```tsx -{ - dateFormatOverride: "d-M-yyyy", -} -``` - -**Render** - -```tsx -({ - ...args -}) => { - const [state, setState] = useState(["2016-10-01", "2016-10-30"]); - const handleChange = (ev: DateRangeChangeEvent) => { - const newValue = [ - ev.target.value[0].formattedValue, - ev.target.value[1].formattedValue, - ]; - setState(newValue); - }; - - return ( -
- "de-DE", - date: { - dateFnsLocale: () => de, - ariaLabels: { - previousMonthButton: () => "Vorheriger Monat", - nextMonthButton: () => "Nächster Monat", - }, - dateFormatOverride: args.dateFormatOverride || "dd-MM-yyyy", - }, - }} - > - - -
- ); -} -``` - diff --git a/skills/carbon-react/components/dd.md b/skills/carbon-react/components/dd.md deleted file mode 100644 index 583aa80b8f..0000000000 --- a/skills/carbon-react/components/dd.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -name: carbon-component-dd -description: Carbon Dd component props and usage examples. ---- - -# Dd - -## Import -`import { Dd } from "carbon-react/lib/components/definition-list";` - -## Source -- Export: `./components/definition-list` -- Props interface: `DdProps` - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | Yes | | Prop for what will render in the `
` tags | | -| m | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| p | ResponsiveValue \| undefined | No | | Padding on top, left, bottom and right | | -| padding | ResponsiveValue \| undefined | No | | Padding on top, left, bottom and right | | -| paddingBottom | ResponsiveValue \| undefined | No | | Padding on bottom | | -| paddingLeft | ResponsiveValue \| undefined | No | | Padding on left | | -| paddingRight | ResponsiveValue \| undefined | No | | Padding on right | | -| paddingTop | ResponsiveValue \| undefined | No | | Padding on top | | -| paddingX | ResponsiveValue \| undefined | No | | Padding on left and right | | -| paddingY | ResponsiveValue \| undefined | No | | Padding on top and bottom | | -| pb | ResponsiveValue \| undefined | No | | Padding on bottom | | -| pl | ResponsiveValue \| undefined | No | | Padding on left | | -| pr | ResponsiveValue \| undefined | No | | Padding on right | | -| pt | ResponsiveValue \| undefined | No | | Padding on top | | -| px | ResponsiveValue \| undefined | No | | Padding on left and right | | -| py | ResponsiveValue \| undefined | No | | Padding on top and bottom | | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | - -## Examples -### Default - -**Args** - -```tsx -{ - children: [], - } -``` - diff --git a/skills/carbon-react/components/decimal.md b/skills/carbon-react/components/decimal.md deleted file mode 100644 index 83372d1b99..0000000000 --- a/skills/carbon-react/components/decimal.md +++ /dev/null @@ -1,369 +0,0 @@ ---- -name: carbon-component-decimal -description: Carbon Decimal component props and usage examples. ---- - -# Decimal - -## Import -`import Decimal from "carbon-react/lib/components/decimal";` - -## Source -- Export: `./components/decimal` -- Props interface: `DecimalProps` - -## Props -| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | -| --- | --- | --- | --- | --- | --- | --- | --- | -| onChange | (ev: CustomEvent) => void | Yes | | | | Handler for change event | | -| value | string | Yes | | | | The value of the input | | -| about | string \| undefined | No | | | | | | -| accept | string \| undefined | No | | | | | | -| accessKey | string \| undefined | No | | | | | | -| align | "left" \| "right" \| undefined | No | | | | Text alignment of the label | | -| allowEmptyValue | boolean \| undefined | No | | | | Allow an empty value instead of defaulting to 0.00 | | -| alt | string \| undefined | No | | | | | | -| as | React.ElementType \| undefined | No | | | | Override the variant component | | -| autoCapitalize | (string & {}) \| "none" \| "off" \| "on" \| "sentences" \| "words" \| "characters" \| undefined | No | | | | | | -| autoComplete | HTMLInputAutoCompleteAttribute \| undefined | No | | | | | | -| autoCorrect | string \| undefined | No | | | | | | -| autoFocus | boolean \| undefined | No | | | | If true the Component will be focused when rendered | | -| autoSave | string \| undefined | No | | | | | | -| capture | boolean \| "user" \| "environment" \| undefined | No | | | | | | -| checked | boolean \| undefined | No | | | | | | -| children | ReactNode | No | | | | | | -| className | string \| undefined | No | | | | | | -| color | string \| undefined | No | | | | | | -| content | string \| undefined | No | | | | | | -| contentEditable | "inherit" \| Booleanish \| "plaintext-only" \| undefined | No | | | | | | -| contextMenu | string \| undefined | No | | | | | | -| dangerouslySetInnerHTML | { __html: string \| TrustedHTML; } \| undefined | No | | | | | | -| datatype | string \| undefined | No | | | | | | -| defaultChecked | boolean \| undefined | No | | | | | | -| defaultValue | string \| number \| readonly string[] \| undefined | No | | | | | | -| deferTimeout | number \| undefined | No | | | | Integer to determine a timeout for the deferred callback | | -| dir | string \| undefined | No | | | | | | -| disabled | boolean \| undefined | No | | | | If true, the component will be disabled | | -| draggable | Booleanish \| undefined | No | | | | | | -| enterKeyHint | "go" \| "send" \| "search" \| "enter" \| "done" \| "next" \| "previous" \| undefined | No | | | | | | -| error | string \| boolean \| undefined | No | | | | Indicate that error has occurred. | | -| exportparts | string \| undefined | No | | | | | | -| form | string \| undefined | No | | | | | | -| formAction | string \| undefined | No | | | | | | -| formattedValue | string \| undefined | No | | | | An optional alternative for props.value, this is useful if the real value is an ID but you want to show a human-readable version. | | -| formEncType | string \| undefined | No | | | | | | -| formMethod | string \| undefined | No | | | | | | -| formNoValidate | boolean \| undefined | No | | | | | | -| formTarget | string \| undefined | No | | | | | | -| height | string \| number \| undefined | No | | | | | | -| hidden | boolean \| undefined | No | | | | | | -| iconOnClick | ((ev: React.MouseEvent \| React.KeyboardEvent) => void) \| undefined | No | | | | Optional handler for click event on Textbox icon | | -| iconOnMouseDown | ((ev: React.MouseEvent) => void) \| undefined | No | | | | Optional handler for mouse down event on Textbox icon | | -| iconTabIndex | number \| undefined | No | | | | Overrides the default tabindex of the component | | -| id | string \| undefined | No | | | | The input id | | -| inlist | any | No | | | | | | -| inputHint | string \| undefined | No | | | | A hint string rendered before the input but after the label. Intended to describe the purpose or content of the input. | | -| inputIcon | string \| number \| boolean \| React.ReactElement> \| Iterable \| React.ReactPortal \| null \| undefined | No | | | | Type of the icon that will be rendered next to the input | | -| inputMode | "email" \| "none" \| "search" \| "text" \| "tel" \| "url" \| "numeric" \| "decimal" \| undefined | No | | | | Hints at the type of data that might be entered by the user while editing the element or its contents | | -| inputWidth | number \| undefined | No | | | | The width of the input as a percentage | | -| is | string \| undefined | No | | | | Specify that a standard HTML element should behave like a defined custom built-in element | | -| itemID | string \| undefined | No | | | | | | -| itemProp | string \| undefined | No | | | | | | -| itemRef | string \| undefined | No | | | | | | -| itemScope | boolean \| undefined | No | | | | | | -| itemType | string \| undefined | No | | | | | | -| label | string \| undefined | No | | | | Label content | | -| labelInline | boolean \| undefined | No | | | | When true label is inline. | | -| lang | string \| undefined | No | | | | | | -| leftChildren | React.ReactNode | No | | | | Additional child elements to display before the input | | -| list | string \| undefined | No | | | | | | -| locale | string \| undefined | No | | | | The locale string - default en | | -| m | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| max | string \| number \| undefined | No | | | | | | -| maxLength | number \| undefined | No | | | | | | -| maxWidth | string \| undefined | No | | | | Prop for specifying the max width of the input. Leaving the `maxWidth` prop with no value will default the width to '100%' | | -| mb | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| min | string \| number \| undefined | No | | | | | | -| minLength | number \| undefined | No | | | | | | -| ml | ResponsiveValue \| undefined | No | | | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | | | Margin on top | | -| multiple | boolean \| undefined | No | | | | | | -| mx | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| name | string \| undefined | No | | | | The input name | | -| nonce | string \| undefined | No | | | | | | -| onAbort | ReactEventHandler \| undefined | No | | | | | | -| onAbortCapture | ReactEventHandler \| undefined | No | | | | | | -| onAnimationEnd | AnimationEventHandler \| undefined | No | | | | | | -| onAnimationEndCapture | AnimationEventHandler \| undefined | No | | | | | | -| onAnimationIteration | AnimationEventHandler \| undefined | No | | | | | | -| onAnimationIterationCapture | AnimationEventHandler \| undefined | No | | | | | | -| onAnimationStart | AnimationEventHandler \| undefined | No | | | | | | -| onAnimationStartCapture | AnimationEventHandler \| undefined | No | | | | | | -| onAuxClick | MouseEventHandler \| undefined | No | | | | | | -| onAuxClickCapture | MouseEventHandler \| undefined | No | | | | | | -| onBeforeInput | InputEventHandler \| undefined | No | | | | | | -| onBeforeInputCapture | FormEventHandler \| undefined | No | | | | | | -| onBlur | ((ev: CustomEvent) => void) \| undefined | No | | | | Handler for blur event | | -| onBlurCapture | FocusEventHandler \| undefined | No | | | | | | -| onCanPlay | ReactEventHandler \| undefined | No | | | | | | -| onCanPlayCapture | ReactEventHandler \| undefined | No | | | | | | -| onCanPlayThrough | ReactEventHandler \| undefined | No | | | | | | -| onCanPlayThroughCapture | ReactEventHandler \| undefined | No | | | | | | -| onChangeCapture | FormEventHandler \| undefined | No | | | | | | -| onChangeDeferred | ((ev: React.ChangeEvent) => void) \| undefined | No | | | | Deferred callback to be called after the onChange event | | -| onClick | ((ev: React.MouseEvent \| React.KeyboardEvent) => void) \| undefined | No | | | | Specify a callback triggered on click | | -| onClickCapture | MouseEventHandler \| undefined | No | | | | | | -| onCompositionEnd | CompositionEventHandler \| undefined | No | | | | | | -| onCompositionEndCapture | CompositionEventHandler \| undefined | No | | | | | | -| onCompositionStart | CompositionEventHandler \| undefined | No | | | | | | -| onCompositionStartCapture | CompositionEventHandler \| undefined | No | | | | | | -| onCompositionUpdate | CompositionEventHandler \| undefined | No | | | | | | -| onCompositionUpdateCapture | CompositionEventHandler \| undefined | No | | | | | | -| onContextMenu | MouseEventHandler \| undefined | No | | | | | | -| onContextMenuCapture | MouseEventHandler \| undefined | No | | | | | | -| onCopy | ClipboardEventHandler \| undefined | No | | | | | | -| onCopyCapture | ClipboardEventHandler \| undefined | No | | | | | | -| onCut | ClipboardEventHandler \| undefined | No | | | | | | -| onCutCapture | ClipboardEventHandler \| undefined | No | | | | | | -| onDoubleClick | MouseEventHandler \| undefined | No | | | | | | -| onDoubleClickCapture | MouseEventHandler \| undefined | No | | | | | | -| onDrag | DragEventHandler \| undefined | No | | | | | | -| onDragCapture | DragEventHandler \| undefined | No | | | | | | -| onDragEnd | DragEventHandler \| undefined | No | | | | | | -| onDragEndCapture | DragEventHandler \| undefined | No | | | | | | -| onDragEnter | DragEventHandler \| undefined | No | | | | | | -| onDragEnterCapture | DragEventHandler \| undefined | No | | | | | | -| onDragExit | DragEventHandler \| undefined | No | | | | | | -| onDragExitCapture | DragEventHandler \| undefined | No | | | | | | -| onDragLeave | DragEventHandler \| undefined | No | | | | | | -| onDragLeaveCapture | DragEventHandler \| undefined | No | | | | | | -| onDragOver | DragEventHandler \| undefined | No | | | | | | -| onDragOverCapture | DragEventHandler \| undefined | No | | | | | | -| onDragStart | DragEventHandler \| undefined | No | | | | | | -| onDragStartCapture | DragEventHandler \| undefined | No | | | | | | -| onDrop | DragEventHandler \| undefined | No | | | | | | -| onDropCapture | DragEventHandler \| undefined | No | | | | | | -| onDurationChange | ReactEventHandler \| undefined | No | | | | | | -| onDurationChangeCapture | ReactEventHandler \| undefined | No | | | | | | -| onEmptied | ReactEventHandler \| undefined | No | | | | | | -| onEmptiedCapture | ReactEventHandler \| undefined | No | | | | | | -| onEncrypted | ReactEventHandler \| undefined | No | | | | | | -| onEncryptedCapture | ReactEventHandler \| undefined | No | | | | | | -| onEnded | ReactEventHandler \| undefined | No | | | | | | -| onEndedCapture | ReactEventHandler \| undefined | No | | | | | | -| onError | ReactEventHandler \| undefined | No | | | | | | -| onErrorCapture | ReactEventHandler \| undefined | No | | | | | | -| onFocus | ((ev: React.FocusEvent) => void) \| undefined | No | | | | Event handler for the focus event | | -| onFocusCapture | FocusEventHandler \| undefined | No | | | | | | -| onGotPointerCapture | PointerEventHandler \| undefined | No | | | | | | -| onGotPointerCaptureCapture | PointerEventHandler \| undefined | No | | | | | | -| onInput | FormEventHandler \| undefined | No | | | | | | -| onInputCapture | FormEventHandler \| undefined | No | | | | | | -| onInvalid | FormEventHandler \| undefined | No | | | | | | -| onInvalidCapture | FormEventHandler \| undefined | No | | | | | | -| onKeyDown | ((ev: React.KeyboardEvent) => void) \| undefined | No | | | | Specify a callback triggered on keyDown | | -| onKeyDownCapture | KeyboardEventHandler \| undefined | No | | | | | | -| onKeyUp | KeyboardEventHandler \| undefined | No | | | | | | -| onKeyUpCapture | KeyboardEventHandler \| undefined | No | | | | | | -| onLoad | ReactEventHandler \| undefined | No | | | | | | -| onLoadCapture | ReactEventHandler \| undefined | No | | | | | | -| onLoadedData | ReactEventHandler \| undefined | No | | | | | | -| onLoadedDataCapture | ReactEventHandler \| undefined | No | | | | | | -| onLoadedMetadata | ReactEventHandler \| undefined | No | | | | | | -| onLoadedMetadataCapture | ReactEventHandler \| undefined | No | | | | | | -| onLoadStart | ReactEventHandler \| undefined | No | | | | | | -| onLoadStartCapture | ReactEventHandler \| undefined | No | | | | | | -| onLostPointerCapture | PointerEventHandler \| undefined | No | | | | | | -| onLostPointerCaptureCapture | PointerEventHandler \| undefined | No | | | | | | -| onMouseDown | ((ev: React.MouseEvent) => void) \| undefined | No | | | | Event handler for the mouse down event | | -| onMouseDownCapture | MouseEventHandler \| undefined | No | | | | | | -| onMouseEnter | MouseEventHandler \| undefined | No | | | | | | -| onMouseLeave | MouseEventHandler \| undefined | No | | | | | | -| onMouseMove | MouseEventHandler \| undefined | No | | | | | | -| onMouseMoveCapture | MouseEventHandler \| undefined | No | | | | | | -| onMouseOut | MouseEventHandler \| undefined | No | | | | | | -| onMouseOutCapture | MouseEventHandler \| undefined | No | | | | | | -| onMouseOver | MouseEventHandler \| undefined | No | | | | | | -| onMouseOverCapture | MouseEventHandler \| undefined | No | | | | | | -| onMouseUp | MouseEventHandler \| undefined | No | | | | | | -| onMouseUpCapture | MouseEventHandler \| undefined | No | | | | | | -| onPaste | ClipboardEventHandler \| undefined | No | | | | | | -| onPasteCapture | ClipboardEventHandler \| undefined | No | | | | | | -| onPause | ReactEventHandler \| undefined | No | | | | | | -| onPauseCapture | ReactEventHandler \| undefined | No | | | | | | -| onPlay | ReactEventHandler \| undefined | No | | | | | | -| onPlayCapture | ReactEventHandler \| undefined | No | | | | | | -| onPlaying | ReactEventHandler \| undefined | No | | | | | | -| onPlayingCapture | ReactEventHandler \| undefined | No | | | | | | -| onPointerCancel | PointerEventHandler \| undefined | No | | | | | | -| onPointerCancelCapture | PointerEventHandler \| undefined | No | | | | | | -| onPointerDown | PointerEventHandler \| undefined | No | | | | | | -| onPointerDownCapture | PointerEventHandler \| undefined | No | | | | | | -| onPointerEnter | PointerEventHandler \| undefined | No | | | | | | -| onPointerLeave | PointerEventHandler \| undefined | No | | | | | | -| onPointerMove | PointerEventHandler \| undefined | No | | | | | | -| onPointerMoveCapture | PointerEventHandler \| undefined | No | | | | | | -| onPointerOut | PointerEventHandler \| undefined | No | | | | | | -| onPointerOutCapture | PointerEventHandler \| undefined | No | | | | | | -| onPointerOver | PointerEventHandler \| undefined | No | | | | | | -| onPointerOverCapture | PointerEventHandler \| undefined | No | | | | | | -| onPointerUp | PointerEventHandler \| undefined | No | | | | | | -| onPointerUpCapture | PointerEventHandler \| undefined | No | | | | | | -| onProgress | ReactEventHandler \| undefined | No | | | | | | -| onProgressCapture | ReactEventHandler \| undefined | No | | | | | | -| onRateChange | ReactEventHandler \| undefined | No | | | | | | -| onRateChangeCapture | ReactEventHandler \| undefined | No | | | | | | -| onReset | FormEventHandler \| undefined | No | | | | | | -| onResetCapture | FormEventHandler \| undefined | No | | | | | | -| onScroll | UIEventHandler \| undefined | No | | | | | | -| onScrollCapture | UIEventHandler \| undefined | No | | | | | | -| onSeeked | ReactEventHandler \| undefined | No | | | | | | -| onSeekedCapture | ReactEventHandler \| undefined | No | | | | | | -| onSeeking | ReactEventHandler \| undefined | No | | | | | | -| onSeekingCapture | ReactEventHandler \| undefined | No | | | | | | -| onSelect | ReactEventHandler \| undefined | No | | | | | | -| onSelectCapture | ReactEventHandler \| undefined | No | | | | | | -| onStalled | ReactEventHandler \| undefined | No | | | | | | -| onStalledCapture | ReactEventHandler \| undefined | No | | | | | | -| onSubmit | FormEventHandler \| undefined | No | | | | | | -| onSubmitCapture | FormEventHandler \| undefined | No | | | | | | -| onSuspend | ReactEventHandler \| undefined | No | | | | | | -| onSuspendCapture | ReactEventHandler \| undefined | No | | | | | | -| onTimeUpdate | ReactEventHandler \| undefined | No | | | | | | -| onTimeUpdateCapture | ReactEventHandler \| undefined | No | | | | | | -| onTouchCancel | TouchEventHandler \| undefined | No | | | | | | -| onTouchCancelCapture | TouchEventHandler \| undefined | No | | | | | | -| onTouchEnd | TouchEventHandler \| undefined | No | | | | | | -| onTouchEndCapture | TouchEventHandler \| undefined | No | | | | | | -| onTouchMove | TouchEventHandler \| undefined | No | | | | | | -| onTouchMoveCapture | TouchEventHandler \| undefined | No | | | | | | -| onTouchStart | TouchEventHandler \| undefined | No | | | | | | -| onTouchStartCapture | TouchEventHandler \| undefined | No | | | | | | -| onTransitionEnd | TransitionEventHandler \| undefined | No | | | | | | -| onTransitionEndCapture | TransitionEventHandler \| undefined | No | | | | | | -| onVolumeChange | ReactEventHandler \| undefined | No | | | | | | -| onVolumeChangeCapture | ReactEventHandler \| undefined | No | | | | | | -| onWaiting | ReactEventHandler \| undefined | No | | | | | | -| onWaitingCapture | ReactEventHandler \| undefined | No | | | | | | -| onWheel | WheelEventHandler \| undefined | No | | | | | | -| onWheelCapture | WheelEventHandler \| undefined | No | | | | | | -| part | string \| undefined | No | | | | | | -| pattern | string \| undefined | No | | | | | | -| placeholder | string \| undefined | No | | | | Placeholder string to be displayed in input | | -| popoverContainerAriaLabel | string \| undefined | No | | | | Sets the accessible name (aria-label) on the PopoverContainer dialog | | -| popoverContainerContent | React.ReactNode | No | | | | Content to render inside a PopoverContainer, displayed via a button at the right of the input | | -| popoverPosition | ("left" \| "right" \| "center") \| undefined | No | | | | Sets the position of the PopoverContainer dialog relative to its trigger button | | -| popoverTriggerAriaLabel | string \| undefined | No | | | | Sets the aria-label on the popover trigger button | | -| precision | 0 \| 9 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 10 \| 11 \| 12 \| 13 \| 14 \| 15 \| undefined | No | | | | The decimal precision of the value in the input | | -| prefix | string \| undefined | No | | | | Emphasized part of the displayed text | | -| property | string \| undefined | No | | | | | | -| radioGroup | string \| undefined | No | | | | | | -| readOnly | boolean \| undefined | No | | | | If true, the component will be read-only | | -| rel | string \| undefined | No | | | | | | -| required | boolean \| undefined | No | | | | Flag to configure component as mandatory | | -| resource | string \| undefined | No | | | | | | -| results | number \| undefined | No | | | | | | -| rev | string \| undefined | No | | | | | | -| role | AriaRole \| undefined | No | | | | | | -| security | string \| undefined | No | | | | | | -| size | "small" \| "medium" \| "large" \| undefined | No | | | | Size of an input | | -| slot | string \| undefined | No | | | | | | -| spellCheck | Booleanish \| undefined | No | | | | | | -| src | string \| undefined | No | | | | | | -| step | string \| number \| undefined | No | | | | | | -| style | CSSProperties \| undefined | No | | | | | | -| suffix | string \| undefined | No | | | | A suffix to display alongside the input. Please note that if a prefix is also provided, only the prefix will be rendered. | | -| suppressContentEditableWarning | boolean \| undefined | No | | | | | | -| suppressHydrationWarning | boolean \| undefined | No | | | | | | -| tabIndex | number \| undefined | No | | | | | | -| title | string \| undefined | No | | | | | | -| translate | "yes" \| "no" \| undefined | No | | | | | | -| type | HTMLInputTypeAttribute \| undefined | No | | | | | | -| typeof | string \| undefined | No | | | | | | -| unselectable | "off" \| "on" \| undefined | No | | | | | | -| validationIconId | string \| undefined | No | | | | Id of the validation icon | | -| validationMessagePositionTop | boolean \| undefined | No | | | | Render the ValidationMessage above the Textbox input when validationRedesignOptIn flag is set | | -| vocab | string \| undefined | No | | | | | | -| warning | string \| boolean \| undefined | No | | | | Indicate that warning has occurred. | | -| width | string \| number \| undefined | No | | | | | | -| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| aria-activedescendant | string \| undefined | No | | | | Identifies the currently active element when DOM focus is on a composite widget, textbox, group, or application. | | -| aria-atomic | Booleanish \| undefined | No | | | | Indicates whether assistive technologies will present all, or only parts of, the changed region based on the change notifications defined by the aria-relevant attribute. | | -| aria-autocomplete | "none" \| "inline" \| "list" \| "both" \| undefined | No | | | | Indicates whether inputting text could trigger display of one or more predictions of the user's intended value for an input and specifies how predictions would be presented if they are made. | | -| aria-braillelabel | string \| undefined | No | | | | Indicates an element is being modified and that assistive technologies MAY want to wait until the modifications are complete before exposing them to the user. Defines a string value that labels the current element, which is intended to be converted into Braille. | | -| aria-brailleroledescription | string \| undefined | No | | | | Defines a human-readable, author-localized abbreviated description for the role of an element, which is intended to be converted into Braille. | | -| aria-busy | Booleanish \| undefined | No | | | | | | -| aria-checked | boolean \| "true" \| "false" \| "mixed" \| undefined | No | | | | Indicates the current "checked" state of checkboxes, radio buttons, and other widgets. | | -| aria-colcount | number \| undefined | No | | | | Defines the total number of columns in a table, grid, or treegrid. | | -| aria-colindex | number \| undefined | No | | | | Defines an element's column index or position with respect to the total number of columns within a table, grid, or treegrid. | | -| aria-colindextext | string \| undefined | No | | | | Defines a human readable text alternative of aria-colindex. | | -| aria-colspan | number \| undefined | No | | | | Defines the number of columns spanned by a cell or gridcell within a table, grid, or treegrid. | | -| aria-controls | string \| undefined | No | | | | Identifies the element (or elements) whose contents or presence are controlled by the current element. | | -| aria-current | boolean \| "location" \| "page" \| "time" \| "true" \| "false" \| "step" \| "date" \| undefined | No | | | | Indicates the element that represents the current item within a container or set of related elements. | | -| aria-describedby | string \| undefined | No | | | | The ID of the input's description, is set along with hint text and error message. | | -| aria-description | string \| undefined | No | | | | Defines a string value that describes or annotates the current element. | | -| aria-details | string \| undefined | No | | | | Identifies the element that provides a detailed, extended description for the object. | | -| aria-disabled | Booleanish \| undefined | No | | | | Indicates that the element is perceivable but disabled, so it is not editable or otherwise operable. | | -| aria-errormessage | string \| undefined | No | | | | Identifies the element that provides an error message for the object. | | -| aria-expanded | Booleanish \| undefined | No | | | | Indicates whether the element, or another grouping element it controls, is currently expanded or collapsed. | | -| aria-flowto | string \| undefined | No | | | | Identifies the next element (or elements) in an alternate reading order of content which, at the user's discretion, allows assistive technology to override the general default of reading in document source order. | | -| aria-haspopup | boolean \| "grid" \| "dialog" \| "menu" \| "true" \| "false" \| "listbox" \| "tree" \| undefined | No | | | | Indicates the availability and type of interactive popup element, such as menu or dialog, that can be triggered by an element. | | -| aria-hidden | Booleanish \| undefined | No | | | | Indicates whether the element is exposed to an accessibility API. | | -| aria-invalid | boolean \| "true" \| "false" \| "grammar" \| "spelling" \| undefined | No | | | | Indicates the entered value does not conform to the format expected by the application. | | -| aria-keyshortcuts | string \| undefined | No | | | | Indicates keyboard shortcuts that an author has implemented to activate or give focus to an element. | | -| aria-label | string \| undefined | No | | | | Defines a string value that labels the current element. | | -| aria-labelledby | string \| undefined | No | | | | Prop to specify the aria-labelledby property of the component | | -| aria-level | number \| undefined | No | | | | Defines the hierarchical level of an element within a structure. | | -| aria-live | "off" \| "assertive" \| "polite" \| undefined | No | | | | Indicates that an element will be updated, and describes the types of updates the user agents, assistive technologies, and user can expect from the live region. | | -| aria-modal | Booleanish \| undefined | No | | | | Indicates whether an element is modal when displayed. | | -| aria-multiline | Booleanish \| undefined | No | | | | Indicates whether a text box accepts multiple lines of input or only a single line. | | -| aria-multiselectable | Booleanish \| undefined | No | | | | Indicates that the user may select more than one item from the current selectable descendants. | | -| aria-orientation | "horizontal" \| "vertical" \| undefined | No | | | | Indicates whether the element's orientation is horizontal, vertical, or unknown/ambiguous. | | -| aria-owns | string \| undefined | No | | | | Identifies an element (or elements) in order to define a visual, functional, or contextual parent/child relationship between DOM elements where the DOM hierarchy cannot be used to represent the relationship. | | -| aria-placeholder | string \| undefined | No | | | | Defines a short hint (a word or short phrase) intended to aid the user with data entry when the control has no value. A hint could be a sample value or a brief description of the expected format. | | -| aria-posinset | number \| undefined | No | | | | Defines an element's number or position in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM. | | -| aria-pressed | boolean \| "true" \| "false" \| "mixed" \| undefined | No | | | | Indicates the current "pressed" state of toggle buttons. | | -| aria-readonly | Booleanish \| undefined | No | | | | Indicates that the element is not editable, but is otherwise operable. | | -| aria-relevant | "text" \| "additions" \| "additions removals" \| "additions text" \| "all" \| "removals" \| "removals additions" \| "removals text" \| "text additions" \| "text removals" \| undefined | No | | | | Indicates what notifications the user agent will trigger when the accessibility tree within a live region is modified. | | -| aria-required | Booleanish \| undefined | No | | | | Indicates that user input is required on the element before a form may be submitted. | | -| aria-roledescription | string \| undefined | No | | | | Defines a human-readable, author-localized description for the role of an element. | | -| aria-rowcount | number \| undefined | No | | | | Defines the total number of rows in a table, grid, or treegrid. | | -| aria-rowindex | number \| undefined | No | | | | Defines an element's row index or position with respect to the total number of rows within a table, grid, or treegrid. | | -| aria-rowindextext | string \| undefined | No | | | | Defines a human readable text alternative of aria-rowindex. | | -| aria-rowspan | number \| undefined | No | | | | Defines the number of rows spanned by a cell or gridcell within a table, grid, or treegrid. | | -| aria-selected | Booleanish \| undefined | No | | | | Indicates the current "selected" state of various widgets. | | -| aria-setsize | number \| undefined | No | | | | Defines the number of items in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM. | | -| aria-sort | "none" \| "ascending" \| "descending" \| "other" \| undefined | No | | | | Indicates if items in a table or grid are sorted in ascending or descending order. | | -| aria-valuemax | number \| undefined | No | | | | Defines the maximum allowed value for a range widget. | | -| aria-valuemin | number \| undefined | No | | | | Defines the minimum allowed value for a range widget. | | -| aria-valuenow | number \| undefined | No | | | | Defines the current value for a range widget. | | -| aria-valuetext | string \| undefined | No | | | | Defines the human readable text alternative of aria-valuenow for a range widget. | | -| adaptiveLabelBreakpoint | number \| undefined | No | | Yes | `adaptiveLabelBreakpoint` has been deprecated, the functionality will no longer work. | | | -| fieldHelp | React.ReactNode | No | | Yes | `fieldHelp` has been deprecated, `inputHint` should be used instead. [Legacy] Help content to be displayed under an input. | | | -| helpAriaLabel | string \| undefined | No | | Yes | `helpAriaLabel` has been deprecated, the functionality will no longer work. | | | -| info | string \| boolean \| undefined | No | | Yes | `info` has been deprecated, the functionality will no longer work. | | | -| labelAlign | "left" \| "right" \| undefined | No | | Yes | `labelAlign` has been deprecated, the functionality will no longer work. | | | -| labelHelp | React.ReactNode | No | | Yes | `labelHelp` has been deprecated, `inputHint` should be used instead. [Legacy] Text applied to label help tooltip. When opted into new design validations string values will render as a hint above the input, unless an `inputHint` prop is also passed. | | | -| labelSpacing | 1 \| 2 \| undefined | No | | Yes | `labelSpacing` has been deprecated, the functionality will no longer work. | | | -| labelWidth | number \| undefined | No | | Yes | `labelWidth` has been deprecated, the functionality will no longer work. | | | -| onKeyPress | KeyboardEventHandler \| undefined | No | | Yes | Use `onKeyUp` or `onKeyDown` instead | | | -| onKeyPressCapture | KeyboardEventHandler \| undefined | No | | Yes | Use `onKeyUpCapture` or `onKeyDownCapture` instead | | | -| reverse | boolean \| undefined | No | | Yes | `reverse` has been deprecated, the functionality will no longer work. | | | -| tooltipId | string \| undefined | No | | Yes | `tooltipId` has been deprecated, the functionality will no longer work. | | | -| tooltipPosition | "left" \| "right" \| "bottom" \| "top" \| undefined | No | | Yes | `tooltipPosition` has been deprecated, the functionality will no longer work. | | | -| validationOnLabel | boolean \| undefined | No | | Yes | `validationOnLabel` has been deprecated, the functionality will no longer work. | | | -| aria-dropeffect | "copy" \| "link" \| "none" \| "execute" \| "move" \| "popup" \| undefined | No | | Yes | in ARIA 1.1 | Indicates what functions can be performed when a dragged object is released on the drop target. | | -| aria-grabbed | Booleanish \| undefined | No | | Yes | in ARIA 1.1 | Indicates an element's "grabbed" state in a drag-and-drop operation. | | - -## Examples -No Storybook examples found. \ No newline at end of file diff --git a/skills/carbon-react/components/detail.md b/skills/carbon-react/components/detail.md deleted file mode 100644 index db3aa6da8a..0000000000 --- a/skills/carbon-react/components/detail.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -name: carbon-component-detail -description: Carbon Detail component props and usage examples. ---- - -# Detail - -## Import -`import Detail from "carbon-react/lib/components/detail";` - -## Source -- Export: `./components/detail` -- Props interface: `DetailProps` -- Deprecated: Yes -- Deprecation reason: `Detail` has been deprecated. See the Carbon documentation for migration details. - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | No | | The rendered children of the component. | | -| footnote | string \| undefined | No | | A small detail to display under the main content. | | -| icon | IconType \| undefined | No | | The type of icon to use. | | -| m | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | - -## Examples -### Default - -**Render** - -```tsx -() => ( - This is where the children will live. -) -``` - - -### Detail with footnote - -**Render** - -```tsx -() => ( - - This is where the children will live. - -) -``` - - -### Detail with icon - -**Render** - -```tsx -() => ( - - This is where the children will live. - -) -``` - - -### Detail inside Card - -**Render** - -```tsx -() => ( - - - This example of Detail just has children. - - - - - This example of Detail has children and also a footnote. - - - - - - Where as this example of Detail has a footnote and icon. - - - -) -``` - - -### Detail inside Tile - -**Render** - -```tsx -() => ( - - - This example of Detail just has children. - - - - This example of Detail has children and also a footnote. - - - - - Where as this example of Detail has a footnote and icon. - - - -) -``` - diff --git a/skills/carbon-react/components/dialog.md b/skills/carbon-react/components/dialog.md deleted file mode 100644 index 7ea6e43ce8..0000000000 --- a/skills/carbon-react/components/dialog.md +++ /dev/null @@ -1,1152 +0,0 @@ ---- -name: carbon-component-dialog -description: Carbon Dialog component props and usage examples. ---- - -# Dialog - -## Import -`import Dialog from "carbon-react/lib/components/dialog";` - -## Source -- Export: `./components/dialog` -- Props interface: `DialogProps` - -## Props -| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | -| --- | --- | --- | --- | --- | --- | --- | --- | -| open | boolean | Yes | | | | Sets the open state of the modal | | -| ariaRole | string \| undefined | No | | | | The ARIA role to be applied to the modal | | -| children | React.ReactNode | No | | | | Child elements | | -| closeButtonDataProps | Pick \| undefined | No | | | | Data tag prop bag for close Button | | -| contentPadding | ContentPaddingInterface \| undefined | No | | | | Padding to be set on the Dialog content | | -| contentRef | React.ForwardedRef \| undefined | No | | | | Reference to the scrollable content element | | -| disableAutoFocus | boolean \| undefined | No | | | | | | -| disableEscKey | boolean \| undefined | No | | | | Determines if the Esc Key closes the modal | | -| disableFocusTrap | boolean \| undefined | No | | | | | | -| disableStickyOnSmallScreen | boolean \| undefined | No | | | | When true, header and sticky footer become unstickied for accessibility on small screen devices. On small screen devices, the dialog becomes full width and has no dimmer. | | -| enableBackgroundUI | boolean \| undefined | No | | | | Determines if the background is disabled when the modal is open | | -| focusableContainers | React.RefObject[] \| undefined | No | | | | an optional array of refs to containers whose content should also be reachable by tabbing from the dialog | | -| focusableSelectors | string \| undefined | No | | | | Optional selector to identify the focusable elements, if not provided a default selector is used | | -| focusFirstElement | HTMLElement \| React.RefObject \| null \| undefined | No | | | | Optional reference to an element meant to be focused on open | | -| footer | React.ReactNode | No | | | | Footer content to be rendered at the bottom of the dialog | | -| gradientKeyLine | boolean \| undefined | No | | | | Adds a gradient keyline to the dialog header | | -| greyBackground | boolean \| undefined | No | | | | Change the background color of the content to grey | | -| headerChildren | React.ReactNode | No | | | | Container for components to be displayed in the header | | -| height | string \| undefined | No | | | | Allows developers to specify a specific height for the dialog. | | -| help | string \| undefined | No | | | | Adds Help tooltip to Header | | -| onCancel | ((ev: React.KeyboardEvent \| KeyboardEvent \| React.MouseEvent) => void) \| undefined | No | | | | A custom close event handler | | -| restoreFocusOnClose | boolean \| undefined | No | | | | Enables the automatic restoration of focus to the element that invoked the modal when the modal is closed. | | -| role | string \| undefined | No | | | | The ARIA role to be applied to the Dialog container | | -| showCloseIcon | boolean \| undefined | No | | | | Determines if the close icon is shown | | -| size | "auto" \| "extra-small" \| "medium-small" \| "medium-large" \| "extra-large" \| "maximise" \| Size \| undefined | No | | | | Size — accepts both legacy values (extra-small, medium-small, etc.) and new values (small, medium, large, fullscreen). | | -| stickyFooter | boolean \| undefined | No | | | | Makes the footer stick to the bottom of the dialog when content scrolls | | -| subtitle | React.ReactNode | No | | | | Subtitle displayed at top of dialog. Its consumers' responsibility to set a suitable accessible name/description for the Dialog if they pass a node to subtitle prop. | | -| title | React.ReactNode | No | | | | Title displayed at top of dialog. Its consumers' responsibility to set a suitable accessible name/description for the Dialog if they pass a node to title prop. | | -| topModalOverride | boolean \| undefined | No | | | | Manually override the internal modal stacking order to set this as top | | -| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| aria-describedby | string \| undefined | No | | | | Prop to specify the aria-describedby property of the Dialog component | | -| aria-label | string \| undefined | No | | | | Prop to specify the aria-label of the Dialog component. To be used only when the title prop is not defined, and the component is not labelled by any internal element. | | -| aria-labelledby | string \| undefined | No | | | | Prop to specify the aria-labelledby property of the Dialog component To be used when the title prop is a custom React Node, or the component is labelled by an internal element other than the title. | | -| disableClose | boolean \| undefined | No | | Yes | Use `showCloseIcon={false}` instead. | | | -| disableContentPadding | boolean \| undefined | No | | Yes | Use `contentPadding` instead. | | | -| fullscreen | boolean \| undefined | No | | Yes | Use `size="fullscreen"` instead. | | | -| highlightVariant | string \| undefined | No | | Yes | Use `gradientKeyLine` instead. | | | -| pagesStyling | boolean \| undefined | No | | Yes | PagesStyling is now deprecated and will be removed in a future release | | | - -## Examples -### Loading Content - -**Render** - -```tsx -() => { - const [isLoading, setIsLoading] = useState(false); - const [isOpen, setIsOpen] = useState(defaultOpenState); - - const handleOpen = () => { - setIsLoading(true); - setIsOpen(true); - setTimeout(() => { - setIsLoading(false); - }, 3000); - }; - - return ( - <> - - setIsOpen(false)} - > - {isLoading ? ( - - ) : ( - <> - {}} - /> - {}} - /> - {}} - /> - {}} - /> - {}} - /> - {}} - /> - {}} - /> - - )} - - - ); -} -``` - - -### Focusing a Different First Element - -**Render** - -```tsx -() => { - const [isOpenOne, setIsOpenOne] = useState(false); - const [isOpenTwo, setIsOpenTwo] = useState(false); - const ref = useRef(null); - return ( - <> - - setIsOpenOne(false)} - aria-label="Demo using focusFirstElement" - > - - Focus an element that does not support autofocus - - - - - - {}} /> - - - setIsOpenTwo(false)} - aria-label="Demo using autoFocus" - > - Focus an element that supports autoFocus - - - - - {}} - /> - - - ); -} -``` - - -### Other Focusable Containers - -**Render** - -```tsx -() => { - const [isDialogOpen, setIsDialogOpen] = useState(false); - const [isToast1Open, setIsToast1Open] = useState(false); - const [isToast2Open, setIsToast2Open] = useState(false); - const toast1Ref = useRef(null); - const toast2Ref = useRef(null); - - return ( - <> - - setIsDialogOpen(false)} - title="Title" - subtitle="Subtitle" - focusableContainers={[toast1Ref, toast2Ref]} - > -
setIsDialogOpen(false)}>Cancel - } - saveButton={ - - } - > - - This is an example of a dialog with a Form as content - - {}} /> - {}} /> - {}} /> - - - -
- setIsToast1Open(false)} - ref={toast1Ref} - targetPortalId="stacked" - > - Toast message 1 - - setIsToast2Open(false)} - ref={toast2Ref} - targetPortalId="stacked" - > - Toast message 2 - - - ); -} -``` - - -### WithScrollableContent - -**Args** - -```tsx -{ - children: childrenText.repeat(2), - title: "Dialog with scrollable content", - subtitle: "amet non ornare suspendisse tempor.", - height: "200px", - } -``` - -**Render** - -```tsx -function WithScrollableContentExample(args) { - const { children, open, ...rest } = args; - const [isOpen, setIsOpen] = useState(false); - - return ( - <> - - setIsOpen(false)} {...rest}> - {/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */} -
- {children} -
-
- - ); - } -``` - - -### DefaultStory - -**Args** - -```tsx -{ - open: isChromatic(), - title: "Title", - subtitle: "Subtitle", - size: "medium", - } -``` - -**Render** - -```tsx -function DefaultRender({ onCancel, ...args }: DialogProps) { - const buttonRef = useRef(null); - const [open, setOpen] = useState(args.open || false); - return ( - <> - - { - onCancel?.(ev); - setOpen(false); - setTimeout(() => buttonRef.current?.focus(), 0); - }} - footer={} - > - {dialogContent} - - - ); - } -``` - - -### DefaultWithForm - -**Args** - -```tsx -{ - open: isChromatic(), - title: "Title", - subtitle: "Subtitle", - size: "medium", - } -``` - -**Render** - -```tsx -function DefaultWithFormRender({ onCancel, ...args }: DialogProps) { - const buttonRef = useRef(null); - const [open, setOpen] = useState(args.open || false); - return ( - <> - - { - onCancel?.(ev); - setOpen(false); - setTimeout(() => buttonRef.current?.focus(), 0); - }} - > -
setOpen(false)}>Cancel - } - saveButton={ - - } - > - - This is an example of a dialog with a Form as content - - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - -
- - ); - } -``` - - -### With Restore Focus On Close - -**Render** - -```tsx -() => { - const [isOpen, setIsOpen] = useState(false); - const [showMessage, setShowMessage] = useState(false); - const messageRef = useRef(null); - - return ( - <> - - {showMessage && ( - setShowMessage(false)} - > - Some custom message - - )} - { - setIsOpen(false); - setShowMessage(true); - setTimeout(() => messageRef.current?.focus(), 1); - }} - title="Title" - subtitle="Subtitle" - restoreFocusOnClose={false} - > -
setIsOpen(false)}>Cancel - } - saveButton={ - - } - > - - This is an example of a dialog with a Form as content - - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - -
- - ); -} -``` - - -### SmallSize - -**Args** - -```tsx -{ - ...DefaultStory.args, - size: "small", - } -``` - - -### GradientKeyLine - -**Args** - -```tsx -{ - ...DefaultStory.args, - gradientKeyLine: true, - } -``` - - -### MediumSize - -**Args** - -```tsx -{ - ...DefaultStory.args, - size: "medium", - } -``` - - -### LargeSize - -**Args** - -```tsx -{ - ...DefaultStory.args, - size: "large", - } -``` - - -### Size: Full Screen - -**Render** - -```tsx -() => { - const [isOpen, setIsOpen] = useState(defaultOpenState); - const buttonRef = useRef(null); - - return ( - <> - - { - setIsOpen(false); - setTimeout(() => buttonRef.current?.focus(), 0); - }} - title="Title" - subtitle="Subtitle" - footer={} - > - {dialogContent} - - - ); -} -``` - - -### ResponsiveBehavior - -**Args** - -```tsx -{ - open: isChromatic(), - title: "Responsive Dialog", - subtitle: "Dialog shrinks to fit viewport", - size: "large", - } -``` - -**Render** - -```tsx -function ResponsiveBehaviorRender({ - onCancel, - ...args - }: Partial) { - const buttonRef = useRef(null); - const [open, setOpen] = useState(args.open || false); - return ( - <> - - - Resize your browser window to see the dialog responsively shrink while - staying centered. The dialog has a minimum width of 288px. - - { - onCancel?.(ev); - setOpen(false); - setTimeout(() => buttonRef.current?.focus(), 0); - }} - > -
setOpen(false)}>Cancel - } - saveButton={ - - } - > - - This dialog will shrink responsively when the viewport is smaller - than the dialog's max-width. - - {}} /> - {}} /> - {}} /> - -
- - ); - } -``` - - -### SmallScreenBehavior - -**Args** - -```tsx -{ - open: isChromatic(), - title: "Small Screen Dialog", - subtitle: "Header and footer are not sticky on small screens", - size: "medium", - disableStickyOnSmallScreen: true, - } -``` - -**Render** - -```tsx -function SmallScreenBehaviorRender({ - onCancel, - ...args - }: Partial) { - const buttonRef = useRef(null); - const [open, setOpen] = useState(args.open || false); - return ( - <> - - - On small screen devices (below 600px), the dialog becomes full width, - the dimmer is removed, and the header/footer are no longer sticky. - This improves accessibility on mobile devices. Form also has a - `disableStickyOnSmallScreen` prop, which allows it to be used within a - Dialog without a sticky footer on small screen devices. - - { - onCancel?.(ev); - setOpen(false); - setTimeout(() => buttonRef.current?.focus(), 0); - }} - > -
setOpen(false)}>Cancel - } - saveButton={ - - } - > - - This dialog demonstrates small screen accessibility behavior. On - small screens, both the dialog header and the Form's sticky - footer are disabled. - - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - -
- - ); - } -``` - - -### StickyFooter - -**Args** - -```tsx -{ - open: isChromatic(), - title: "Title", - subtitle: "Subtitle", - size: "medium", - stickyFooter: true, - } -``` - -**Render** - -```tsx -function StickyFooterRender({ - onCancel, - ...args - }: Partial) { - const buttonRef = useRef(null); - const [open, setOpen] = useState(args.open || false); - return ( - <> - - { - onCancel?.(ev); - setOpen(false); - setTimeout(() => buttonRef.current?.focus(), 0); - }} - footer={} - > - - This is an example of a dialog with a sticky footer using the - Dialog's own stickyFooter and footer{" "} - props. - - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - - - ); - } -``` - - -### StickyFooterWithForm - -**Args** - -```tsx -{ - open: isChromatic(), - title: "Title", - subtitle: "Subtitle", - size: "medium", - } -``` - -**Render** - -```tsx -function StickyFooterWithFormRender({ - onCancel, - ...args - }: Partial) { - const buttonRef = useRef(null); - const [open, setOpen] = useState(args.open || false); - return ( - <> - - { - onCancel?.(ev); - setOpen(false); - setTimeout(() => buttonRef.current?.focus(), 0); - }} - > -
setOpen(false)}>Cancel - } - saveButton={ - - } - > - - This is an example of a dialog using a Form component with its own - sticky footer. The Form manages the footer internally. - - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - -
- - ); - } -``` - - -### FormLinkedToFooterButtons - -**Args** - -```tsx -{ - open: isChromatic(), - title: "Personal Details", - subtitle: "Enter your details below", - size: "medium", - stickyFooter: true, - } -``` - -**Render** - -```tsx -function FormLinkedToFooterButtonsRender({ - onCancel, - ...args - }: Partial) { - const buttonRef = useRef(null); - const [open, setOpen] = useState(args.open || false); - const [submitted, setSubmitted] = useState(false); - - const handleSubmit = (ev: React.FormEvent) => { - ev.preventDefault(); - setSubmitted(true); - setOpen(false); - setTimeout(() => buttonRef.current?.focus(), 0); - }; - - return ( - <> - - {submitted && ( - Form submitted successfully! - )} - { - onCancel?.(ev); - setOpen(false); - setTimeout(() => buttonRef.current?.focus(), 0); - }} - footer={ - - - - - } - > -
- {}} /> - {}} /> - {}} /> - {}} /> - {}} /> - -
- - ); - } -``` - - -### WithHeight - -**Args** - -```tsx -{ - ...DefaultStory.args, - height: "500", - } -``` - - -### WithHeaderChildren - -**Args** - -```tsx -{ - open: isChromatic(), - title: "Title", - subtitle: "Subtitle", - size: "medium", - } -``` - -**Render** - -```tsx -function WithHeaderChildrenRender({ - onCancel, - ...args - }: Partial) { - const buttonRef = useRef(null); - const [open, setOpen] = useState(args.open || false); - return ( - <> - - { - onCancel?.(ev); - setOpen(false); - setTimeout(() => buttonRef.current?.focus(), 0); - }} - headerChildren={ - - - - - } - footer={} - > - {dialogContent} - - - ); - } -``` - - -### WithContentPadding - -**Args** - -```tsx -{ - ...DefaultStory.args, - contentPadding: { p: 0 }, - } -``` - - -### WithContentPaddingCustom - -**Args** - -```tsx -{ - ...DefaultStory.args, - contentPadding: { py: 5, px: 8 }, - } -``` - - -### MDX Example 1 - -**Args** - -```tsx -## Related Components - -- Need to refer back to the underlying page? [Try Sidebar](../?path=/docs/sidebar--docs). - -## Examples - -### Default - -A `Dialog` requires an `open` prop and an `onCancel` handler. Use the `footer` prop to render action buttons at the bottom of the dialog. The call-to-action element should always be focused when the `Dialog` is closed — the example below shows how to programmatically restore focus to the trigger element for consistent behaviour across all browsers. - - - -### With a Form - -When including a `Form` inside a `Dialog`, the `Form` can manage its own sticky footer independently. - - - -### Sizes - -The `size` prop controls the maximum width of the dialog. The default is `"medium"`. - -#### Small (540px) - - - -#### Medium (850px) — Default - - - -#### Large (1080px) - - - -#### Full Screen - - - -### Responsive behavior - -The dialog shrinks to fit the viewport when the viewport is narrower than the dialog's maximum width. The minimum width is 288px. - - - -### Small screen behavior - -When `disableStickyOnSmallScreen` is set, the header and footer are no longer sticky on small screen devices (below 600px). On these devices the dialog also becomes full width and the dimmer is removed, improving accessibility on mobile. - - - -### Sticky footer - -Use the `stickyFooter` prop together with `footer` to keep the footer visible when dialog content scrolls. - - - -### Sticky footer with Form - - - -### Form linked to footer buttons - -When using the Dialog's `footer` prop, the action buttons live outside the `
` element in the DOM. Use the `id` prop on `Form` and the `form` prop on `Button` to associate them. - - - -### With a custom height - -Use the `height` prop to set a fixed height on the dialog. - - - -### With header children - -Use the `headerChildren` prop to render additional content — such as action buttons — in the dialog header. - - - -### Gradient keyline - -Setting `gradientKeyLine` adds a decorative gradient keyline below the dialog header. - - - -### Overriding content padding - -Use the `contentPadding` prop to override the default padding applied to the dialog content area. - - - -### Preventing focus from being restored when Dialog closes - -When `restoreFocusOnClose` is `false`, focus will not be returned to the element that was focused before the `Dialog` was opened. You can instead programmatically apply focus to another element — for example, a message that has just appeared. - - - -### Loading content - -For content that cannot be rendered immediately — such as data from an external API — use conditional rendering with the `Loader` component: - - - -The first interactive element in the loaded content has `autoFocus` set, which is recommended so that assistive technology users are informed of the updated content. - -### Overriding the first focused element - -By default, when a dialog opens it focuses the first focusable element in its children. There are two ways to override this: - -- Pass a ref to `focusFirstElement` to focus a specific element on open. -- Use `disableAutoFocus` and set `autoFocus` directly on the element you want focused. - -To achieve this, forward a custom ref handle to the `Dialog` component using the `DialogHandle` type: -``` - - -### MDX Example 2 - -**Args** - -```tsx -The handle exposes the `focus()` method of the Dialog's root DOM node: -``` - diff --git a/skills/carbon-react/components/dismissible-box.md b/skills/carbon-react/components/dismissible-box.md deleted file mode 100644 index a3a926b2d3..0000000000 --- a/skills/carbon-react/components/dismissible-box.md +++ /dev/null @@ -1,145 +0,0 @@ ---- -name: carbon-component-dismissible-box -description: Carbon DismissibleBox component props and usage examples. ---- - -# DismissibleBox - -## Import -`import DismissibleBox from "carbon-react/lib/components/dismissible-box";` - -## Source -- Export: `./components/dismissible-box` -- Props interface: `DismissibleBoxProps` -- Deprecated: Yes -- Deprecation reason: `DismissibleBox` has been deprecated. See the Carbon documentation for migration details. - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| onClose | (e: React.KeyboardEvent \| React.MouseEvent) => void | Yes | | Callback to be called when the close icon button is clicked | | -| alignContent | ResponsiveValue \| undefined | No | | The CSS align-content property sets how the browser distributes space between and around content items along the cross-axis of a flexbox container, and the main-axis of a grid container. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/align-content) | | -| alignItems | ResponsiveValue \| undefined | No | | The CSS align-items property sets the align-self value on all direct children as a group. The align-self property sets the alignment of an item within its containing block. In Flexbox it controls the alignment of items on the Cross Axis, in Grid Layout it controls the alignment of items on the Block Axis within their grid area. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/align-items) | | -| alignSelf | ResponsiveValue \| undefined | No | | The align-self CSS property aligns flex items of the current flex line overriding the align-items value. If any of the item's cross-axis margin is set to auto, then align-self is ignored. In Grid layout align-self aligns the item inside the grid area. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/align-self) | | -| as | keyof JSX.IntrinsicElements \| React.ComponentType \| undefined | No | | | | -| borderRadius | BorderRadiusType \| undefined | No | | Design Token for Border Radius. Note: please check that the border radius design token you are using is compatible with the Box component. | "borderRadius100" | -| bottom | ResponsiveValue \| undefined | No | | The bottom CSS property participates in specifying the vertical position of a positioned element. It has no effect on non-positioned elements. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/top) | | -| boxShadow | BoxShadowsType \| undefined | No | | Design Token for Box Shadow. Note: please check that the box shadow design token you are using is compatible with the Box component. | | -| boxSizing | BoxSizing \| undefined | No | | Set the box-sizing attribute of the Box component | | -| children | React.ReactNode | No | | The content to render in the component | | -| closeButtonDataProps | TagProps \| undefined | No | | Data tag prop bag for close Button | | -| color | string \| undefined | No | | Set the color attribute of the Box component | | -| columnGap | Gap \| undefined | No | | Column gap, an integer multiplier of the base spacing constant (8px) or any valid CSS string." | | -| flex | ResponsiveValue \| undefined | No | | The flex CSS property specifies how a flex item will grow or shrink so as to fit the space available in its flex container. This is a shorthand property that sets flex-grow, flex-shrink, and flex-basis. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/flex) | | -| flexBasis | ResponsiveValue \| undefined | No | | | | -| flexDirection | ResponsiveValue \| undefined | No | | The flex-direction CSS property specifies how flex items are placed in the flex container defining the main axis and the direction (normal or reversed). [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction) | | -| flexGrow | ResponsiveValue \| undefined | No | | The flex-grow CSS property sets the flex grow factor of a flex item main size. It specifies how much of the remaining space in the flex container should be assigned to the item (the flex grow factor). [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/flex-grow) | | -| flexShrink | ResponsiveValue \| undefined | No | | The flex-shrink CSS property sets the flex shrink factor of a flex item. If the size of all flex items is larger than the flex container, items shrink to fit according to flex-shrink. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/flex-shrink) | | -| flexWrap | ResponsiveValue \| undefined | No | | The flex-wrap CSS property sets whether flex items are forced onto one line or can wrap onto multiple lines. If wrapping is allowed, it sets the direction that lines are stacked. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/flex-wrap) | | -| gap | Gap \| undefined | No | | Gap, an integer multiplier of the base spacing constant (8px) or any valid CSS string." | | -| gridArea | ResponsiveValue \| undefined | No | | The grid-area CSS property is a shorthand property for grid-row-start, grid-column-start, grid-row-end and grid-column-end, specifying a grid item’s size and location within the grid row by contributing a line, a span, or nothing (automatic) to its grid placement, thereby specifying the edges of its grid area. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-area) | | -| gridAutoColumns | ResponsiveValue \| undefined | No | | The grid-auto-columns CSS property specifies the size of an implicitly-created grid column track. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-columns) | | -| gridAutoFlow | ResponsiveValue \| undefined | No | | The grid-auto-flow CSS property controls how the auto-placement algorithm works, specifying exactly how auto-placed items get flowed into the grid. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow) | | -| gridAutoRows | ResponsiveValue \| undefined | No | | The grid-auto-rows CSS property specifies the size of an implicitly-created grid row track. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-rows) | | -| gridColumn | ResponsiveValue \| undefined | No | | The grid-column CSS property is a shorthand property for grid-column-start and grid-column-end specifying a grid item's size and location within the grid column by contributing a line, a span, or nothing (automatic) to its grid placement, thereby specifying the inline-start and inline-end edge of its grid area. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column) | | -| gridRow | ResponsiveValue \| undefined | No | | The grid-row CSS property is a shorthand property for grid-row-start and grid-row-end specifying a grid item’s size and location within the grid row by contributing a line, a span, or nothing (automatic) to its grid placement, thereby specifying the inline-start and inline-end edge of its grid area. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row) | | -| gridTemplateAreas | ResponsiveValue \| undefined | No | | The grid-template-areas CSS property specifies named grid areas. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-areas) | | -| gridTemplateColumns | ResponsiveValue \| undefined | No | | The grid-template-columns CSS property defines the line names and track sizing functions of the grid columns. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns) | | -| gridTemplateRows | ResponsiveValue \| undefined | No | | The grid-template-rows CSS property defines the line names and track sizing functions of the grid rows. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/row-template-rows) | | -| hasBorderLeftHighlight | boolean \| undefined | No | | Flag to control whether the thicker left border highlight should be rendered | | -| height | ResponsiveValue \| undefined | No | | The height CSS property specifies the height of an element. By default, the property defines the height of the content area. If box-sizing is set to border-box, however, it instead determines the height of the border area. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/height) | | -| hidden | boolean \| undefined | No | | Whether the component is hidden from view. In this state, the component will not be visible to users but will remain in the HTML document | | -| id | string \| undefined | No | | Set the ID attribute of the Box component | | -| justifyItems | ResponsiveValue \| undefined | No | | The CSS justify-items property defines the default justify-self for all items of the box, giving them all a default way of justifying each box along the appropriate axis. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/justify-items) | | -| justifySelf | ResponsiveValue \| undefined | No | | The CSS justify-self property set the way a box is justified inside its alignment container along the appropriate axis. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/justify-self) | | -| left | ResponsiveValue \| undefined | No | | The left CSS property participates in specifying the horizontal position of a positioned element. It has no effect on non-positioned elements. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/left) | | -| m | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| maxHeight | ResponsiveValue \| undefined | No | | The max-height CSS property sets the maximum height of an element. It prevents the used value of the height property from becoming larger than the value specified for max-height. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/max-height) | | -| maxWidth | ResponsiveValue \| undefined | No | | The max-width CSS property sets the maximum width of an element. It prevents the used value of the width property from becoming larger than the value specified by max-width. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/max-width) | | -| mb | ResponsiveValue \| undefined | No | | Margin on bottom | | -| minHeight | ResponsiveValue \| undefined | No | | The min-height CSS property sets the minimum height of an element. It prevents the used value of the height property from becoming smaller than the value specified for min-height. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/display) | | -| minWidth | ResponsiveValue \| undefined | No | | The min-width CSS property sets the minimum width of an element. It prevents the used value of the width property from becoming smaller than the value specified for min-width. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/min-width) | | -| ml | ResponsiveValue \| undefined | No | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| opacity | string \| number \| undefined | No | | Set the opacity attribute of the Box component | | -| order | ResponsiveValue \| undefined | No | | The order CSS property sets the order to lay out an item in a flex or grid container. Items in a container are sorted by ascending order value and then by their source code order. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/order) | | -| overflow | ResponsiveValue \| undefined | No | | The overflow CSS property sets what to do when an element's content is too big to fit in its block formatting context. It is a shorthand for overflow-x and overflow-y. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/overflow) | | -| overflowWrap | OverflowWrap \| undefined | No | | String to set Box content break strategy. Note "anywhere" is not supported in Safari | | -| overflowX | ResponsiveValue \| undefined | No | | The overflow-x CSS property sets what shows when content overflows a block-level element's left and right edges. This may be nothing, a scroll bar, or the overflow content. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-x) | | -| overflowY | ResponsiveValue \| undefined | No | | The overflow-y CSS property sets what shows when content overflows a block-level element's top and bottom edges. This may be nothing, a scroll bar, or the overflow content. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-y) | | -| p | ResponsiveValue \| undefined | No | | Padding on top, left, bottom and right | | -| padding | ResponsiveValue \| undefined | No | | Padding on top, left, bottom and right | | -| paddingBottom | ResponsiveValue \| undefined | No | | Padding on bottom | | -| paddingLeft | ResponsiveValue \| undefined | No | | Padding on left | | -| paddingRight | ResponsiveValue \| undefined | No | | Padding on right | | -| paddingTop | ResponsiveValue \| undefined | No | | Padding on top | | -| paddingX | ResponsiveValue \| undefined | No | | Padding on left and right | | -| paddingY | ResponsiveValue \| undefined | No | | Padding on top and bottom | | -| pb | ResponsiveValue \| undefined | No | | Padding on bottom | | -| pl | ResponsiveValue \| undefined | No | | Padding on left | | -| position | ResponsiveValue \| undefined | No | | The position CSS property specifies how an element is positioned in a document. The top, right, bottom, and left properties determine the final location of positioned elements. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/position) | | -| pr | ResponsiveValue \| undefined | No | | Padding on right | | -| pt | ResponsiveValue \| undefined | No | | Padding on top | | -| px | ResponsiveValue \| undefined | No | | Padding on left and right | | -| py | ResponsiveValue \| undefined | No | | Padding on top and bottom | | -| right | ResponsiveValue \| undefined | No | | The right CSS property participates in specifying the horizontal position of a positioned element. It has no effect on non-positioned elements. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/right) | | -| role | string \| undefined | No | | Set the Role attribute of the Box component | | -| rowGap | Gap \| undefined | No | | Row gap an integer multiplier of the base spacing constant (8px) or any valid CSS string." | | -| scrollVariant | ScrollVariant \| undefined | No | | Scroll styling attribute | | -| size | ResponsiveValue \| undefined | No | | | | -| top | ResponsiveValue \| undefined | No | | The top CSS property participates in specifying the vertical position of a positioned element. It has no effect on non-positioned elements. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/top) | | -| variant | "dark" \| "light" \| undefined | No | | Set the base color variant | | -| verticalAlign | ResponsiveValue \| undefined | No | | The vertical-align CSS property specifies sets vertical alignment of an inline or table-cell box. [MDN reference](https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align) | | -| width | string \| number \| undefined | No | | Use this prop to override the default width. Numbers from 0-1 are converted to percentage widths. Numbers greater than 1 are converted to pixel values. String values are passed as raw CSS values. And arrays are converted to responsive width styles. If theme.sizes is defined, the width prop will attempt to pick up values from the theme. Please note this component has a minWidth of 600px | | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| aria-atomic | "true" \| "false" \| undefined | No | | Indicates whether AT will announce all, or only parts of, the changed region | | -| aria-hidden | "true" \| "false" \| undefined | No | | Set the container to be hidden from screen readers | | -| aria-live | "off" \| "assertive" \| "polite" \| undefined | No | | Make the container an aria-live region | | - -## Examples -### LightVariant - -**Args** - -```tsx -{ onClose: () => {} } -``` - - -### DarkVariant - -**Args** - -```tsx -{ variant: "dark", onClose: () => {} } -``` - - -### WithNoLeftBorderHighlight - -**Args** - -```tsx -{ mb: 2, hasBorderLeftHighlight: false, onClose: () => {} } -``` - - -### WidthOverridden - -**Args** - -```tsx -{ width: "650px", onClose: () => {} } -``` - diff --git a/skills/carbon-react/components/dl.md b/skills/carbon-react/components/dl.md deleted file mode 100644 index 1caca00b3f..0000000000 --- a/skills/carbon-react/components/dl.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -name: carbon-component-dl -description: Carbon Dl component props and usage examples. ---- - -# Dl - -## Import -`import { Dl } from "carbon-react/lib/components/definition-list";` - -## Source -- Export: `./components/definition-list` -- Props interface: `DlProps` - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | Yes | | prop to render children. | | -| asSingleColumn | boolean \| undefined | No | | Render the DefinitionList as a single column | false | -| ddTextAlign | ElementAlignment \| undefined | No | | This string will specify the text align styling of the `
`. | "left" | -| dtTextAlign | ElementAlignment \| undefined | No | | This string will specify the text align styling of the `
`. | "right" | -| id | string \| undefined | No | | HTML id attribute of the input | | -| m | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| p | ResponsiveValue \| undefined | No | | Padding on top, left, bottom and right | | -| padding | ResponsiveValue \| undefined | No | | Padding on top, left, bottom and right | | -| paddingBottom | ResponsiveValue \| undefined | No | | Padding on bottom | | -| paddingLeft | ResponsiveValue \| undefined | No | | Padding on left | | -| paddingRight | ResponsiveValue \| undefined | No | | Padding on right | | -| paddingTop | ResponsiveValue \| undefined | No | | Padding on top | | -| paddingX | ResponsiveValue \| undefined | No | | Padding on left and right | | -| paddingY | ResponsiveValue \| undefined | No | | Padding on top and bottom | | -| pb | ResponsiveValue \| undefined | No | | Padding on bottom | | -| pl | ResponsiveValue \| undefined | No | | Padding on left | | -| pr | ResponsiveValue \| undefined | No | | Padding on right | | -| pt | ResponsiveValue \| undefined | No | | Padding on top | | -| px | ResponsiveValue \| undefined | No | | Padding on left and right | | -| py | ResponsiveValue \| undefined | No | | Padding on top and bottom | | -| w | number \| undefined | No | | This value will specify the width of the `StyledDtDiv` as a percentage. The remaining space will be taken up by the `StyledDdDiv`. This prop has no effect when `asSingleColumn` is set. | 50 | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | - -## Examples -No Storybook examples found. \ No newline at end of file diff --git a/skills/carbon-react/components/draggable-container.md b/skills/carbon-react/components/draggable-container.md deleted file mode 100644 index b99a129040..0000000000 --- a/skills/carbon-react/components/draggable-container.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -name: carbon-component-draggable-container -description: Carbon DraggableContainer component props and usage examples. ---- - -# DraggableContainer - -## Import -`import { DraggableContainer } from "carbon-react/lib/components/draggable";` - -## Source -- Export: `./components/draggable` -- Props interface: `DraggableContainerProps` - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | No | | The content of the component `` is required to make `Draggable` works | | -| flexDirection | "row" \| "row-reverse" \| undefined | No | | Defines the direction in which the draggable items contents are placed. Can be either "row" or "row-reverse". | "row" | -| getOrder | ((draggableItemIds?: (string \| number \| undefined)[], movedItemId?: string \| number \| undefined) => void) \| undefined | No | | Callback fired when an item is successfully dropped. | | -| m | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | - -## Examples -No Storybook examples found. \ No newline at end of file diff --git a/skills/carbon-react/components/draggable-item.md b/skills/carbon-react/components/draggable-item.md deleted file mode 100644 index 701791acac..0000000000 --- a/skills/carbon-react/components/draggable-item.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -name: carbon-component-draggable-item -description: Carbon DraggableItem component props and usage examples. ---- - -# DraggableItem - -## Import -`import { DraggableItem } from "carbon-react/lib/components/draggable";` - -## Source -- Export: `./components/draggable` -- Props interface: `DraggableItemProps` - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | Yes | | The content of the component. | | -| id | string \| number | Yes | | The id of the `DraggableItem`. Use this prop to make `Draggable` work | | -| p | ResponsiveValue \| undefined | No | | Padding on top, left, bottom and right | | -| padding | ResponsiveValue \| undefined | No | | Padding on top, left, bottom and right | | -| paddingBottom | ResponsiveValue \| undefined | No | | Padding on bottom | | -| paddingLeft | ResponsiveValue \| undefined | No | | Padding on left | | -| paddingRight | ResponsiveValue \| undefined | No | | Padding on right | | -| paddingTop | ResponsiveValue \| undefined | No | | Padding on top | | -| paddingX | ResponsiveValue \| undefined | No | | Padding on left and right | | -| paddingY | ResponsiveValue \| undefined | No | | Padding on top and bottom | | -| pb | ResponsiveValue \| undefined | No | | Padding on bottom | | -| pl | ResponsiveValue \| undefined | No | | Padding on left | | -| pr | ResponsiveValue \| undefined | No | | Padding on right | | -| pt | ResponsiveValue \| undefined | No | | Padding on top | | -| px | ResponsiveValue \| undefined | No | | Padding on left and right | | -| py | ResponsiveValue \| undefined | No | | Padding on top and bottom | 1 | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | - -## Examples -### Default - -**Args** - -```tsx -{ - children: [], - } -``` - diff --git a/skills/carbon-react/components/drawer.md b/skills/carbon-react/components/drawer.md deleted file mode 100644 index d6bf807323..0000000000 --- a/skills/carbon-react/components/drawer.md +++ /dev/null @@ -1,209 +0,0 @@ ---- -name: carbon-component-drawer -description: Carbon Drawer component props and usage examples. ---- - -# Drawer - -## Import -`import Drawer from "carbon-react/lib/components/drawer";` - -## Source -- Export: `./components/drawer` -- Props interface: `DrawerProps` - -## Props -| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | -| --- | --- | --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | Yes | | | | Main content to display | | -| backgroundColor | string \| undefined | No | | | | Sets color of sidebar's background | | -| expanded | boolean \| undefined | No | | | | Sets the expansion state of the Drawer if component is meant to be used as controlled | | -| expandedWidth | string \| undefined | No | | | | The width of the expanded sidebar | "30vw" | -| footer | React.ReactNode | No | | | | Content to display inside of a footer | | -| height | string \| undefined | No | | | | Sets the height of the component | "100%" | -| onChange | ((e: React.MouseEvent \| React.KeyboardEvent, isExpanded: boolean) => void) \| undefined | No | | | | Callback fired when expansion state changes, onChange(event: object, isExpanded: boolean) | | -| sidebar | React.ReactNode | No | | | | Drawer sidebar content | | -| sidebarAriaLabel | string \| undefined | No | | | | Specify an aria-label for the Drawer sidebar | | -| stickyFooter | boolean \| undefined | No | | | | Makes the footer of the drawer sticky. Footer prop must also be set. | | -| stickyHeader | boolean \| undefined | No | | | | Makes the header of the drawer sticky. Title prop must also be set. | | -| title | React.ReactNode | No | | | | Sets the heading of the drawer | | -| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| aria-label | string \| undefined | No | | | | Specify an aria-label for the Drawer component | | -| animationDuration | string \| undefined | No | | Yes | This prop will soon be removed. | Duration of a animation | "400ms" | -| defaultExpanded | boolean \| undefined | No | | Yes | This prop will soon be removed, please use the `expanded` prop instead. | Set the default state of expansion of the Drawer if component is meant to be used as uncontrolled | | -| showControls | boolean \| undefined | No | | Yes | This prop will soon be removed, this component is now intended to be non-dismissible. | Enables expand/collapse button that controls drawer | | - -## Examples -### Default - -**Args** - -```tsx -{ - sidebar: Drawer content, - } -``` - -**Render** - -```tsx -(args) => ( - - Main body content - - ) -``` - - -### Height - -**Args** - -```tsx -{ - ...Default.args, - height: "100px", - } -``` - - -### SidebarWidth - -**Args** - -```tsx -{ - ...Default.args, - expandedWidth: "400px", - } -``` - - -### WithTitle - -**Args** - -```tsx -{ - ...Default.args, - title: Drawer Title, - } -``` - - -### WithFooter - -**Args** - -```tsx -{ - ...WithTitle.args, - footer: ( - - - - ), - } -``` - - -### StickyHeaderAndFooter - -**Args** - -```tsx -{ - ...WithFooter.args, - stickyHeader: true, - stickyFooter: true, - height: "300px", - sidebar: ( - - Drawer Content - Drawer Content - Drawer Content - Drawer Content - Drawer Content - - ), - } -``` - - -### SidebarAriaLabel - -**Args** - -```tsx -{ - ...Default.args, - sidebarAriaLabel: "This is a Drawer", - } -``` - - -### WithBackgroundColor - -**Args** - -```tsx -{ - ...Default.args, - backgroundColor: "var(--colorsUtilityMajor050)", - } -``` - - -### Controlled - -**Render** - -```tsx -() => { - const [isExpanded, setIsExpanded] = useState(true); - - return ( - <> - Drawer content} - > - Main body content - - - - - ); -} -``` - - -### FocusedToggle - -**Args** - -```tsx -{ - sidebar: Drawer content, - showControls: true, - } -``` - -**Render** - -```tsx -(args) => ( - - Main body - - ) -``` - diff --git a/skills/carbon-react/components/dt.md b/skills/carbon-react/components/dt.md deleted file mode 100644 index c80d32dbc8..0000000000 --- a/skills/carbon-react/components/dt.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -name: carbon-component-dt -description: Carbon Dt component props and usage examples. ---- - -# Dt - -## Import -`import { Dt } from "carbon-react/lib/components/definition-list";` - -## Source -- Export: `./components/definition-list` -- Props interface: `DtProps` - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | Yes | | Prop for what will render in the `
` tags | | -| m | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| p | ResponsiveValue \| undefined | No | | Padding on top, left, bottom and right | | -| padding | ResponsiveValue \| undefined | No | | Padding on top, left, bottom and right | | -| paddingBottom | ResponsiveValue \| undefined | No | | Padding on bottom | | -| paddingLeft | ResponsiveValue \| undefined | No | | Padding on left | | -| paddingRight | ResponsiveValue \| undefined | No | | Padding on right | | -| paddingTop | ResponsiveValue \| undefined | No | | Padding on top | | -| paddingX | ResponsiveValue \| undefined | No | | Padding on left and right | | -| paddingY | ResponsiveValue \| undefined | No | | Padding on top and bottom | | -| pb | ResponsiveValue \| undefined | No | | Padding on bottom | | -| pl | ResponsiveValue \| undefined | No | | Padding on left | | -| pr | ResponsiveValue \| undefined | No | | Padding on right | | -| pt | ResponsiveValue \| undefined | No | | Padding on top | | -| px | ResponsiveValue \| undefined | No | | Padding on left and right | | -| py | ResponsiveValue \| undefined | No | | Padding on top and bottom | | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | - -## Examples -### Default - -**Args** - -```tsx -{ - children: [], - } -``` - diff --git a/skills/carbon-react/components/duelling-picklist.md b/skills/carbon-react/components/duelling-picklist.md deleted file mode 100644 index a264119988..0000000000 --- a/skills/carbon-react/components/duelling-picklist.md +++ /dev/null @@ -1,626 +0,0 @@ ---- -name: carbon-component-duelling-picklist -description: Carbon DuellingPicklist component props and usage examples. ---- - -# DuellingPicklist - -## Import -`import { DuellingPicklist } from "carbon-react/lib/components/duelling-picklist";` - -## Source -- Export: `./components/duelling-picklist` -- Props interface: `DuellingPicklistProps` -- Deprecated: Yes -- Deprecation reason: `DuellingPicklist` has been deprecated. See the Carbon documentation for migration details. - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | No | | Content of the component, should contain two Picklist children and a PicklistDivider | | -| disabled | boolean \| undefined | No | | Indicate if component is disabled | | -| leftControls | React.ReactNode | No | | Place for components like Search or Filter placed above the left list | | -| leftLabel | string \| undefined | No | | Left list label | | -| m | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| rightControls | React.ReactNode | No | | Place for components like Search or Filter placed above the right list | | -| rightLabel | string \| undefined | No | | Right list label | | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | - -## Examples -### Default - -**Render** - -```tsx -() => { - const mockData: Item[] = useMemo(() => { - const arr = []; - for (let i = 0; i < 20; i++) { - const data = { - key: i.toString(), - title: `Content ${i + 1}`, - description: `Description ${i + 1}`, - }; - arr.push(data); - } - return arr; - }, []); - - const allItems = useMemo(() => { - return mockData.reduce( - (obj, item) => { - obj[item.key] = item; - return obj; - }, - {} as { [key: string]: Item }, - ); - }, [mockData]); - - const [isEachItemSelected, setIsEachItemSelected] = useState(false); - const [order] = useState(mockData.map(({ key }) => key)); - const [notSelectedItems, setNotSelectedItems] = useState(allItems); - const [notSelectedSearch, setNotSelectedSearch] = useState({}); - const [selectedItems, setSelectedItems] = useState({}); - const [searchQuery, setSearchQuery] = useState(""); - const isSearchMode = Boolean(searchQuery.length); - - const onAdd = useCallback( - (item: Item) => { - const { [item.key]: removed, ...rest } = notSelectedItems; - setNotSelectedItems(rest); - setSelectedItems({ ...selectedItems, [item.key]: item }); - const { [item.key]: removed2, ...rest2 } = notSelectedSearch; - setNotSelectedSearch(rest2); - }, - [notSelectedItems, notSelectedSearch, selectedItems], - ); - - const onRemove = useCallback( - (item: Item) => { - const { [item.key]: removed, ...rest } = selectedItems; - setSelectedItems(rest); - setNotSelectedItems({ ...notSelectedItems, [item.key]: item }); - if (isSearchMode && item.title.includes(searchQuery)) { - setNotSelectedSearch({ ...notSelectedSearch, [item.key]: item }); - } - }, - [ - isSearchMode, - notSelectedItems, - notSelectedSearch, - searchQuery, - selectedItems, - ], - ); - - const handleSearch = useCallback( - (ev: SearchEvent) => { - setSearchQuery(ev.target.value); - const tempNotSelectedItems = Object.keys(notSelectedItems).reduce( - (items, key) => { - const item = notSelectedItems[key]; - if (item.title.includes(ev.target.value)) { - items[item.key] = item; - } - return items; - }, - {} as AllItems, - ); - setNotSelectedSearch(tempNotSelectedItems); - }, - [notSelectedItems], - ); - - const renderItems = ( - list: AllItems, - type: PicklistItemProps["type"], - handler: PicklistItemProps["onChange"], - ) => - order.reduce((items, key) => { - const item = list[key]; - if (item) { - items.push( - -
-
-

- {item.title} -

-
-
-

{item.description}

-
-
-
, - ); - } - return items; - }, [] as JSX.Element[]); - - return ( - <> - setIsEachItemSelected(!isEachItemSelected)} - checked={isEachItemSelected} - label="Example checkbox" - /> - - } - disabled={isEachItemSelected} - > - Your own placeholder} - > - {renderItems( - isSearchMode ? notSelectedSearch : notSelectedItems, - "add", - onAdd as PicklistItemProps["onChange"], - )} - - - } - > - {renderItems( - selectedItems, - "remove", - onRemove as PicklistItemProps["onChange"], - )} - - - - ); -} -``` - - -### Alternative Search Placement - -**Render** - -```tsx -() => { - const mockData = useMemo(() => { - const arr = []; - for (let i = 0; i < 20; i++) { - const data = { - key: i.toString(), - title: `Content ${i + 1}`, - description: `Description ${i + 1}`, - }; - arr.push(data); - } - return arr; - }, []); - - const allItems = useMemo(() => { - return mockData.reduce((obj, item) => { - obj[item.key] = item; - return obj; - }, {} as AllItems); - }, [mockData]); - - const [isEachItemSelected, setIsEachItemSelected] = useState(false); - const [order] = useState(mockData.map(({ key }) => key)); - const [notSelectedItems, setNotSelectedItems] = useState(allItems); - const [notSelectedSearch, setNotSelectedSearch] = useState({}); - const [selectedItems, setSelectedItems] = useState({}); - const [searchQuery, setSearchQuery] = useState(""); - const isSearchMode = Boolean(searchQuery.length); - - const onAdd = useCallback( - (item: Item) => { - const { [item.key]: removed, ...rest } = notSelectedItems; - setNotSelectedItems(rest); - setSelectedItems({ ...selectedItems, [item.key]: item }); - const { [item.key]: removed2, ...rest2 } = notSelectedSearch; - setNotSelectedSearch(rest2); - }, - [notSelectedItems, notSelectedSearch, selectedItems], - ); - - const onRemove = useCallback( - (item: Item) => { - const { [item.key]: removed, ...rest } = selectedItems; - setSelectedItems(rest); - setNotSelectedItems({ ...notSelectedItems, [item.key]: item }); - if (isSearchMode && item.title.includes(searchQuery)) { - setNotSelectedSearch({ ...notSelectedSearch, [item.key]: item }); - } - }, - [ - isSearchMode, - notSelectedItems, - notSelectedSearch, - searchQuery, - selectedItems, - ], - ); - - const handleSearch = useCallback( - (ev: SearchEvent) => { - setSearchQuery(ev.target.value); - const tempNotSelectedItems = Object.keys(notSelectedItems).reduce( - (items, key) => { - const item = notSelectedItems[key]; - if (item.title.includes(ev.target.value)) { - items[item.key] = item; - } - return items; - }, - {} as AllItems, - ); - setNotSelectedSearch(tempNotSelectedItems); - }, - [notSelectedItems], - ); - - const renderItems = ( - list: AllItems, - type: PicklistItemProps["type"], - handler: PicklistItemProps["onChange"], - ) => - order.reduce((items, key) => { - const item = list[key]; - if (item) { - items.push( - -
-
-

- {item.title} -

-
-
-

{item.description}

-
-
-
, - ); - } - return items; - }, [] as JSX.Element[]); - - return ( - <> - - setIsEachItemSelected(!isEachItemSelected)} - checked={isEachItemSelected} - label="Example checkbox" - /> - - - - - - Your own placeholder} - > - {renderItems( - isSearchMode ? notSelectedSearch : notSelectedItems, - "add", - onAdd as PicklistItemProps["onChange"], - )} - - } - > - {renderItems( - selectedItems, - "remove", - onRemove as PicklistItemProps["onChange"], - )} - - - - ); -} -``` - - -### Grouped - -**Render** - -```tsx -() => { - const allGroups = { - groupA: "Group A", - groupB: "Group B", - groupC: "Group C", - }; - - const mockData = [ - { key: 1, title: "Content 1", group: "groupA" }, - { key: 2, title: "Content 2", group: "groupA" }, - { key: 3, title: "Content 3", group: "groupA" }, - { key: 4, title: "Content 4", group: "groupB" }, - { key: 5, title: "Content 5", group: "groupC" }, - { key: 6, title: "Content 6", group: "groupC" }, - ]; - - type MockData = typeof mockData; - type GroupKey = keyof typeof allGroups; - - const [notSelectedItems, setNotSelectedItems] = useState([ - ...mockData, - ]); - const [selectedItems, setSelectedItems] = useState([]); - - const onAdd = useCallback( - (item: ItemGroup) => { - setSelectedItems([...selectedItems, item]); - setNotSelectedItems([ - ...notSelectedItems.filter((i) => i.key !== item.key), - ]); - }, - [notSelectedItems, selectedItems], - ); - - const onRemove = useCallback( - (item: ItemGroup) => { - setNotSelectedItems([...notSelectedItems, item]); - setSelectedItems([...selectedItems.filter((i) => i.key !== item.key)]); - }, - [notSelectedItems, selectedItems], - ); - - const addGroup = useCallback( - (group: GroupKey) => { - const groupItems = notSelectedItems.filter( - (item) => item.group === group, - ); - setNotSelectedItems([ - ...notSelectedItems.filter((item) => item.group !== group), - ]); - setSelectedItems([...selectedItems, ...groupItems]); - }, - [notSelectedItems, selectedItems], - ); - - const removeGroup = useCallback( - (group: GroupKey) => { - const groupItems = selectedItems.filter((item) => item.group === group); - - setSelectedItems([ - ...selectedItems.filter((item) => item.group !== group), - ]); - setNotSelectedItems([...notSelectedItems, ...groupItems]); - }, - [notSelectedItems, selectedItems], - ); - - const renderItems = ( - list: MockData, - type: PicklistItemProps["type"], - handler: PicklistItemProps["onChange"], - ) => { - if (!list) return null; - - list.sort((a, b) => a.key - b.key); - - return list.map((item) => { - return ( - -
-

- {item.title} -

-
-
- ); - }); - }; - - return ( - - } - > - {Object.entries(allGroups).map(([key, value]) => { - const groupItems = notSelectedItems.filter( - (item) => item.group === key, - ); - return groupItems.length ? ( - {value}} - type="add" - onChange={() => addGroup(key as GroupKey)} - > - {renderItems( - groupItems, - "add", - onAdd as PicklistItemProps["onChange"], - )} - - ) : null; - })} - - - } - > - {Object.entries(allGroups).map(([key, value]) => { - const groupItems = selectedItems.filter((item) => item.group === key); - return groupItems.length ? ( - {value}} - type="remove" - onChange={() => removeGroup(key as GroupKey)} - > - {renderItems( - groupItems, - "remove", - onRemove as PicklistItemProps["onChange"], - )} - - ) : null; - })} - - - ); -} -``` - - -### In Dialog - -**Render** - -```tsx -() => { - const [isDialogOpen, setIsDialogOpen] = useState(defaultOpenState); - return ( - - - setIsDialogOpen(false)} - title="Duelling Picklist" - size="large" - > - - - - ); -} -``` - - -### Add Item - -**Render** - -```tsx -() => ( -
    - null}> -
    -
    -

    - Title for Item -

    -
    -
    -
    -
-) -``` - - -### Remove Item - -**Render** - -```tsx -() => ( -
    - null}> -
    -
    -

    - Title for Item -

    -
    -
    -
    -
-) -``` - - -### Locked - -**Render** - -```tsx -() => ( -
    - null} locked> -
    -
    -

    - Title for Item -

    -
    -
    -
    -
-) -``` - - -### Custom Tooltip Message - -**Render** - -```tsx -() => ( -
    - null} - locked - tooltipMessage="This is a custom locked tooltip message" - > -
    -
    -

    - Title for Item -

    -
    -
    -
    -
-) -``` - diff --git a/skills/carbon-react/components/fieldset.md b/skills/carbon-react/components/fieldset.md deleted file mode 100644 index dbe1eb4b44..0000000000 --- a/skills/carbon-react/components/fieldset.md +++ /dev/null @@ -1,163 +0,0 @@ ---- -name: carbon-component-fieldset -description: Carbon Fieldset component props and usage examples. ---- - -# Fieldset - -## Import -`import Fieldset from "carbon-react/lib/components/fieldset";` - -## Source -- Export: `./components/fieldset` -- Props interface: `FieldsetProps` - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | No | | Inputs rendered within the fieldset. | | -| error | string \| undefined | No | | Error message to be displayed when validation fails. | | -| id | string \| undefined | No | | Set an id value on the fieldset. | | -| labelWeight | "bold" \| "regular" \| undefined | No | | Set the label weight of the children input's label. | "regular" | -| legend | string \| undefined | No | | The content for the fieldset legend. | | -| legendHint | string \| undefined | No | | Content for an additional hint text below the legend. | | -| m | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| mb | ResponsiveValue \| undefined | No | | Margin on bottom | | -| ml | ResponsiveValue \| undefined | No | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| orientation | "horizontal" \| "vertical" \| undefined | No | | Set the orientation of the fieldset's children. | "vertical" | -| required | boolean \| undefined | No | | If true, an asterisk will be added to the legend and all inputs within the fieldset will be required. | | -| size | "small" \| "medium" \| "large" \| undefined | No | | Set the size of the component. | "medium" | -| validationMessagePositionTop | boolean \| undefined | No | | Specifies whether the validation message should be displayed above the input. | true | -| warning | string \| undefined | No | | Warning message to be displayed when validation warning occurs. | | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | - -## Examples -### Default - -**Args** - -```tsx -{ - legend: "Fieldset Legend", - } -``` - -**Render** - -```tsx -(args) => ( -
- {}} /> - {}} /> - {}} /> -
- ) -``` - - -### WithLegendHint - -**Args** - -```tsx -{ - ...Default.args, - legendHint: "Fieldset LegendHint", - } -``` - - -### HorizontalOrientation - -**Args** - -```tsx -{ - ...Default.args, - orientation: "horizontal", - } -``` - - -### Sizes - -**Args** - -```tsx -{ - mb: 4, - } -``` - -**Render** - -```tsx -(args) => ( - <> -
- {}} /> - {}} /> - {}} /> -
-
- {}} /> - {}} /> - {}} /> -
-
- {}} /> - {}} /> - {}} /> -
- - ) -``` - - -### HorizontalSizes - -**Args** - -```tsx -{ - ...Sizes.args, - orientation: "horizontal", - } -``` - - -### LabelFontWeight - -**Args** - -```tsx -{ - ...Default.args, - labelWeight: "bold", - } -``` - - -### Required - -**Args** - -```tsx -{ - ...Default.args, - required: true, - } -``` - diff --git a/skills/carbon-react/components/file-input.md b/skills/carbon-react/components/file-input.md deleted file mode 100644 index e2a571a2a6..0000000000 --- a/skills/carbon-react/components/file-input.md +++ /dev/null @@ -1,440 +0,0 @@ ---- -name: carbon-component-file-input -description: Carbon FileInput component props and usage examples. ---- - -# FileInput - -## Import -`import FileInput from "carbon-react/lib/components/file-input";` - -## Source -- Export: `./components/file-input` -- Props interface: `FileInputProps` - -## Props -| Name | Type | Required | Literals | Description | Default | -| --- | --- | --- | --- | --- | --- | -| onChange | (files: FileList) => void | Yes | | onChange event handler. Accepts a list of all files currently entered to the input. | | -| accept | string \| undefined | No | | Which file format(s) to accept. Will be passed to the underlying HTML input. See https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept | | -| buttonText | string \| undefined | No | | Text to appear on the main button. Defaults to "Select file" | | -| dragAndDropText | string \| undefined | No | | Explanatory text to appear inside the input area. Defaults to "or drag and drop your file" | | -| error | string \| boolean \| undefined | No | | Indicate that error has occurred. | | -| id | string \| undefined | No | | HTML id attribute of the input | | -| inputHint | React.ReactNode | No | | A hint string rendered before the input but after the label. Intended to describe the purpose or content of the input. | | -| isVertical | boolean \| undefined | No | | Sets the default layout to vertical - with the button below the explanatory text rather than next to it. This is the equivalent of removing the maxHeight prop - it will be over-ridden if this prop is set explicitly. | | -| label | string \| undefined | No | | Label content | | -| m | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| maxHeight | string \| undefined | No | | A valid CSS string for the max-height CSS property. | | -| maxWidth | string \| undefined | No | | A valid CSS string for the max-width CSS property. Defaults to the same as the minWidth. | | -| mb | ResponsiveValue \| undefined | No | | Margin on bottom | | -| minHeight | string \| undefined | No | | A valid CSS string for the min-height CSS property. | | -| minWidth | string \| undefined | No | | A valid CSS string for the min-width CSS property. | | -| ml | ResponsiveValue \| undefined | No | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | Margin on top | | -| mx | ResponsiveValue \| undefined | No | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | Margin on top and bottom | | -| name | string \| undefined | No | | Name of the input | | -| required | boolean \| undefined | No | | Flag to configure component as mandatory. | | -| uploadStatus | FileUploadStatusProps \| FileUploadStatusProps[] \| undefined | No | | used to control how to display the progress of uploaded file(s) within the component | | -| validationMessagePositionTop | boolean \| undefined | No | | Render the ValidationMessage above the FileInput | | -| data-element | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | Identifier used for testing purposes, applied to the root element of the component. | | - -## Examples -### Default - -**Render** - -```tsx -() => { - return {}} />; -} -``` - - -### With Input Hint - -**Render** - -```tsx -() => { - return ( - {}} /> - ); -} -``` - - -### Required - -**Render** - -```tsx -() => { - return {}} />; -} -``` - - -### Increased Height - -**Render** - -```tsx -() => { - return ( - {}} - /> - ); -} -``` - - -### Responsive Width - -**Render** - -```tsx -() => { - return ( - {}} - /> - ); -} -``` - - -### Increased Width and Height - -**Render** - -```tsx -() => { - return ( - {}} - /> - ); -} -``` - - -### Full Width - -**Render** - -```tsx -() => { - return {}} />; -} -``` - - -### Vertical - -**Render** - -```tsx -() => { - return {}} />; -} -``` - - -### Accept - -**Render** - -```tsx -() => { - return ( - {}} - /> - ); -} -``` - - -### File Type Validation - -**Render** - -```tsx -() => { - const [error, setError] = useState(); - const onChange = (files: FileList) => { - let errorMessage; - if (files.length > 0) { - const fileType = files[0].type; - if (!fileType.startsWith("image/")) { - errorMessage = "Please choose an image file to upload"; - } - } - setError(errorMessage); - }; - return ( - - ); -} -``` - - -### Upload Status (Client) - -**Render** - -```tsx -() => { - const [error, setError] = useState(); - const [uploadStatus, setUploadStatus] = useState< - FileUploadStatusProps | undefined - >(); - const reader = useRef(); - - const getReader = () => { - if (!reader.current) { - reader.current = new FileReader(); - } - return reader.current; - }; - - const removeFile = () => setUploadStatus(undefined); - - const onChange = (files: FileList) => { - if (!files.length) { - setError(undefined); - removeFile(); - return; - } - // as this is a single file input there will only ever be (at most) 1 file - const fileUploaded = files[0]; - - // abandon with error if the file is too big - if (fileUploaded.size > 5 * 1024 * 1024) { - setError("This file is too big to be uploaded - maximum size 5MB"); - return; - } - - setError(undefined); - - const fileReader = getReader(); - - const handleLoad = () => { - const uploadProps: FileUploadStatusProps = { - status: "uploading", - filename: fileUploaded.name, - onAction: () => fileReader.abort(), - progress: 0, - }; - setUploadStatus(uploadProps); - }; - - const handleProgress = (e: ProgressEvent) => { - const progress = (100 * e.loaded) / e.total; - const isComplete = e.type === "loadend" || progress >= 100; - if (isComplete) { - removeListeners(); - } - const uploadProps: FileUploadStatusProps = isComplete - ? { - status: "completed", - filename: fileUploaded.name, - onAction: () => removeFile(), - href: fileReader.result as string, - message: "File uploaded", - } - : { - status: "uploading", - filename: fileUploaded.name, - onAction: () => fileReader.abort(), - progress, - message: `${progress} percent uploaded`, - }; - setUploadStatus(uploadProps); - }; - - const handleError = () => { - const uploadProps: FileUploadStatusProps = { - status: "error", - filename: fileUploaded.name, - onAction: () => removeFile(), - message: "failed to upload", - }; - setUploadStatus(uploadProps); - removeListeners(); - }; - - const handleAbort = () => { - removeFile(); - removeListeners(); - }; - - const removeListeners = () => { - fileReader.removeEventListener("loadstart", handleLoad); - fileReader.removeEventListener("load", handleLoad); - fileReader.removeEventListener("loadend", handleProgress); - fileReader.removeEventListener("progress", handleProgress); - fileReader.removeEventListener("error", handleError); - fileReader.removeEventListener("abort", handleAbort); - }; - - fileReader.addEventListener("loadstart", handleLoad); - fileReader.addEventListener("load", handleProgress); - fileReader.addEventListener("loadend", handleProgress); - fileReader.addEventListener("progress", handleProgress); - fileReader.addEventListener("error", handleError); - fileReader.addEventListener("abort", handleAbort); - - fileReader.readAsDataURL(fileUploaded); - }; - - return ( - - ); -} -``` - - -### Upload Status (Alternative) - -**Render** - -```tsx -() => { - const [uploadStatus, setUploadStatus] = useState< - FileUploadStatusProps | undefined - >(); - - const removeFile = () => setUploadStatus(undefined); - - const onChange = (files: FileList) => { - if (!files.length) { - removeFile(); - return; - } - // as this is a single file input there will only ever be (at most) 1 file - const fileUploaded = files[0]; - - setUploadStatus({ - status: "uploading", - filename: fileUploaded.name, - onAction: () => { - // in practice you might need to send a new request to the server here to ensure nothing of the file gets stored - removeFile(); - }, - progress: 0, - }); - - // mock progress, and possibility of error, at regular intervals. In practice you could poll an endpoint to monitor progress, - // or use a WebSocket connection for the server to give regular updates. - const interval = setInterval(() => { - const randomNumber = Math.floor(Math.random() * 20); - // mock possibility of server error - if (randomNumber === 0) { - setUploadStatus({ - status: "error", - filename: fileUploaded.name, - onAction: () => { - // in practice you might need to send a new request to the server here to ensure nothing of the file gets stored - removeFile(); - }, - message: - "something went wrong with uploading the file - please try again", - }); - clearInterval(interval); - } else { - setUploadStatus((currentStatus) => { - if (currentStatus?.status !== "uploading") { - return currentStatus; - } - const currentProgress = currentStatus.progress as number; - const newProgress = currentProgress + randomNumber; - if (newProgress >= 100) { - clearInterval(interval); - return { - status: "completed", - filename: fileUploaded.name, - onAction: () => { - // in practice you might need to send a new request to the server here to ensure nothing of the file gets stored - removeFile(); - }, - href: "https://carbon.sage.com/", // real href will be whatever URL the file is stored at - message: "File uploaded", - }; - } - return { - ...currentStatus, - progress: newProgress, - message: `${newProgress} percent uploaded`, - }; - }); - } - }, 100); - }; - - return ( - - ); -} -``` - - -### Upload Status (No Progress) - -**Render** - -```tsx -() => { - return ( - {}, - }} - onChange={() => {}} - /> - ); -} -``` - diff --git a/skills/carbon-react/components/filterable-select.md b/skills/carbon-react/components/filterable-select.md deleted file mode 100644 index ca443e51b8..0000000000 --- a/skills/carbon-react/components/filterable-select.md +++ /dev/null @@ -1,514 +0,0 @@ ---- -name: carbon-component-filterable-select -description: Carbon FilterableSelect component props and usage examples. ---- - -# FilterableSelect - -## Import -`import { FilterableSelect } from "carbon-react/lib/components/select";` - -## Source -- Export: `./components/select` -- Props interface: `FilterableSelectProps` - -## Props -| Name | Type | Required | Literals | Deprecated | Deprecation reason | Description | Default | -| --- | --- | --- | --- | --- | --- | --- | --- | -| children | React.ReactNode | Yes | | | | Child components (such as Option or OptionRow) for the SelectList | | -| onChange | (ev: CustomSelectChangeEvent \| React.ChangeEvent) => void | Yes | | | | Specify a callback triggered on change | | -| value | string \| Record | Yes | | | | The selected value(s) | | -| about | string \| undefined | No | | | | | | -| accept | string \| undefined | No | | | | | | -| accessKey | string \| undefined | No | | | | | | -| align | "left" \| "right" \| undefined | No | | | | | | -| alt | string \| undefined | No | | | | | | -| ariaLabel | string \| undefined | No | | | | Prop to specify the aria-label attribute of the component input | | -| ariaLabelledby | string \| undefined | No | | | | Prop to specify the aria-labelledby property of the component input | | -| as | React.ElementType \| undefined | No | | | | Override the variant component | | -| autoCapitalize | (string & {}) \| "none" \| "off" \| "on" \| "sentences" \| "words" \| "characters" \| undefined | No | | | | | | -| autoComplete | HTMLInputAutoCompleteAttribute \| undefined | No | | | | | | -| autoCorrect | string \| undefined | No | | | | | | -| autoFocus | boolean \| undefined | No | | | | If true the Component will be focused when rendered | | -| autoSave | string \| undefined | No | | | | | | -| capture | boolean \| "user" \| "environment" \| undefined | No | | | | | | -| checked | boolean \| undefined | No | | | | | | -| className | string \| undefined | No | | | | | | -| color | string \| undefined | No | | | | | | -| content | string \| undefined | No | | | | | | -| contentEditable | "inherit" \| Booleanish \| "plaintext-only" \| undefined | No | | | | | | -| contextMenu | string \| undefined | No | | | | | | -| dangerouslySetInnerHTML | { __html: string \| TrustedHTML; } \| undefined | No | | | | | | -| datatype | string \| undefined | No | | | | | | -| defaultChecked | boolean \| undefined | No | | | | | | -| deferTimeout | number \| undefined | No | | | | Integer to determine a timeout for the deferred callback | | -| dir | string \| undefined | No | | | | | | -| disabled | boolean \| undefined | No | | | | If true, the component will be disabled | | -| disableDefaultFiltering | boolean \| undefined | No | | | | Boolean to disable automatic filtering and highlighting of options. This allows custom filtering and option styling to be performed outside of the component when the filter text changes. | | -| draggable | Booleanish \| undefined | No | | | | | | -| enableVirtualScroll | boolean \| undefined | No | | | | Set this prop to enable a virtualised list of options. If it is not used then all options will be in the DOM at all times, which may cause performance problems on very large lists | | -| enterKeyHint | "go" \| "send" \| "search" \| "enter" \| "done" \| "next" \| "previous" \| undefined | No | | | | | | -| error | string \| boolean \| undefined | No | | | | Indicate that error has occurred. | | -| exportparts | string \| undefined | No | | | | | | -| flipEnabled | boolean \| undefined | No | | | | Use the opposite list placement if the set placement does not fit | | -| form | string \| undefined | No | | | | | | -| formAction | string \| undefined | No | | | | | | -| formattedValue | string \| undefined | No | | | | An optional alternative for props.value, this is useful if the real value is an ID but you want to show a human-readable version. | | -| formEncType | string \| undefined | No | | | | | | -| formMethod | string \| undefined | No | | | | | | -| formNoValidate | boolean \| undefined | No | | | | | | -| formTarget | string \| undefined | No | | | | | | -| height | string \| number \| undefined | No | | | | | | -| hidden | boolean \| undefined | No | | | | | | -| iconOnClick | ((ev: React.MouseEvent \| React.KeyboardEvent) => void) \| undefined | No | | | | Optional handler for click event on Textbox icon | | -| iconOnMouseDown | ((ev: React.MouseEvent) => void) \| undefined | No | | | | Optional handler for mouse down event on Textbox icon | | -| iconTabIndex | number \| undefined | No | | | | Overrides the default tabindex of the component | | -| id | string \| undefined | No | | | | Id attribute of the input element | | -| info | string \| boolean \| undefined | No | | | | [Legacy] Indicate additional information. | | -| inlist | any | No | | | | | | -| inputHint | string \| undefined | No | | | | A hint string rendered before the input but after the label. Intended to describe the purpose or content of the input. | | -| inputIcon | string \| number \| boolean \| React.ReactElement> \| Iterable \| React.ReactPortal \| null \| undefined | No | | | | Type of the icon that will be rendered next to the input | | -| inputMode | "email" \| "none" \| "search" \| "text" \| "tel" \| "url" \| "numeric" \| "decimal" \| undefined | No | | | | Hints at the type of data that might be entered by the user while editing the element or its contents | | -| inputWidth | number \| undefined | No | | | | The width of the input as a percentage | | -| is | string \| undefined | No | | | | Specify that a standard HTML element should behave like a defined custom built-in element | | -| isLoading | boolean \| undefined | No | | | | If true the loader animation is displayed in the option list | | -| itemID | string \| undefined | No | | | | | | -| itemProp | string \| undefined | No | | | | | | -| itemRef | string \| undefined | No | | | | | | -| itemScope | boolean \| undefined | No | | | | | | -| itemType | string \| undefined | No | | | | | | -| label | string \| undefined | No | | | | Label content | | -| labelHelp | React.ReactNode | No | | | | [Legacy] A message that the Help component will display | | -| labelInline | boolean \| undefined | No | | | | [Legacy] When true label is inline | | -| labelWidth | number \| undefined | No | | | | [Legacy] Label width | | -| lang | string \| undefined | No | | | | | | -| leftChildren | React.ReactNode | No | | | | Additional child elements to display before the input | | -| list | string \| undefined | No | | | | | | -| listActionButton | boolean \| React.ReactElement> \| undefined | No | | | | True for default text button or a Button Component to be rendered | | -| listMaxHeight | number \| undefined | No | | | | Maximum list height - defaults to 180 | | -| listPlacement | ListPlacement \| undefined | No | | | | Placement of the select list in relation to the input element | | -| listWidth | number \| undefined | No | | | | Override the default width of the list element. Number passed is converted into pixel value | | -| m | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| margin | ResponsiveValue \| undefined | No | | | | Margin on top, left, bottom and right | | -| marginBottom | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| marginLeft | ResponsiveValue \| undefined | No | | | | Margin on left | | -| marginRight | ResponsiveValue \| undefined | No | | | | Margin on right | | -| marginTop | ResponsiveValue \| undefined | No | | | | Margin on top | | -| marginX | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| marginY | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| max | string \| number \| undefined | No | | | | | | -| maxLength | number \| undefined | No | | | | | | -| maxWidth | string \| undefined | No | | | | Prop for specifying the max width of the input. Leaving the `maxWidth` prop with no value will default the width to '100%' | | -| mb | ResponsiveValue \| undefined | No | | | | Margin on bottom | | -| min | string \| number \| undefined | No | | | | | | -| minLength | number \| undefined | No | | | | | | -| ml | ResponsiveValue \| undefined | No | | | | Margin on left | | -| mr | ResponsiveValue \| undefined | No | | | | Margin on right | | -| mt | ResponsiveValue \| undefined | No | | | | Margin on top | | -| multiColumn | boolean \| undefined | No | | | | When true component will work in multi column mode. Children should consist of OptionRow components in this mode | | -| multiple | boolean \| undefined | No | | | | | | -| mx | ResponsiveValue \| undefined | No | | | | Margin on left and right | | -| my | ResponsiveValue \| undefined | No | | | | Margin on top and bottom | | -| name | string \| undefined | No | | | | Name attribute of the input element | | -| nonce | string \| undefined | No | | | | | | -| noResultsMessage | string \| undefined | No | | | | A custom message to be displayed when any option does not match the filter text | | -| onAbort | ReactEventHandler \| undefined | No | | | | | | -| onAbortCapture | ReactEventHandler \| undefined | No | | | | | | -| onAnimationEnd | AnimationEventHandler \| undefined | No | | | | | | -| onAnimationEndCapture | AnimationEventHandler \| undefined | No | | | | | | -| onAnimationIteration | AnimationEventHandler \| undefined | No | | | | | | -| onAnimationIterationCapture | AnimationEventHandler \| undefined | No | | | | | | -| onAnimationStart | AnimationEventHandler \| undefined | No | | | | | | -| onAnimationStartCapture | AnimationEventHandler \| undefined | No | | | | | | -| onAuxClick | MouseEventHandler \| undefined | No | | | | | | -| onAuxClickCapture | MouseEventHandler \| undefined | No | | | | | | -| onBeforeInput | InputEventHandler \| undefined | No | | | | | | -| onBeforeInputCapture | FormEventHandler \| undefined | No | | | | | | -| onBlur | ((ev: React.FocusEvent) => void) \| undefined | No | | | | Specify a callback triggered on blur | | -| onBlurCapture | FocusEventHandler \| undefined | No | | | | | | -| onCanPlay | ReactEventHandler \| undefined | No | | | | | | -| onCanPlayCapture | ReactEventHandler \| undefined | No | | | | | | -| onCanPlayThrough | ReactEventHandler \| undefined | No | | | | | | -| onCanPlayThroughCapture | ReactEventHandler \| undefined | No | | | | | | -| onChangeCapture | FormEventHandler \| undefined | No | | | | | | -| onChangeDeferred | ((ev: React.ChangeEvent) => void) \| undefined | No | | | | Deferred callback to be called after the onChange event | | -| onClick | ((ev: React.MouseEvent) => void) \| undefined | No | | | | Specify a callback triggered on click | | -| onClickCapture | MouseEventHandler \| undefined | No | | | | | | -| onCompositionEnd | CompositionEventHandler \| undefined | No | | | | | | -| onCompositionEndCapture | CompositionEventHandler \| undefined | No | | | | | | -| onCompositionStart | CompositionEventHandler \| undefined | No | | | | | | -| onCompositionStartCapture | CompositionEventHandler \| undefined | No | | | | | | -| onCompositionUpdate | CompositionEventHandler \| undefined | No | | | | | | -| onCompositionUpdateCapture | CompositionEventHandler \| undefined | No | | | | | | -| onContextMenu | MouseEventHandler \| undefined | No | | | | | | -| onContextMenuCapture | MouseEventHandler \| undefined | No | | | | | | -| onCopy | ClipboardEventHandler \| undefined | No | | | | | | -| onCopyCapture | ClipboardEventHandler \| undefined | No | | | | | | -| onCut | ClipboardEventHandler \| undefined | No | | | | | | -| onCutCapture | ClipboardEventHandler \| undefined | No | | | | | | -| onDoubleClick | MouseEventHandler \| undefined | No | | | | | | -| onDoubleClickCapture | MouseEventHandler \| undefined | No | | | | | | -| onDrag | DragEventHandler \| undefined | No | | | | | | -| onDragCapture | DragEventHandler \| undefined | No | | | | | | -| onDragEnd | DragEventHandler \| undefined | No | | | | | | -| onDragEndCapture | DragEventHandler \| undefined | No | | | | | | -| onDragEnter | DragEventHandler \| undefined | No | | | | | | -| onDragEnterCapture | DragEventHandler \| undefined | No | | | | | | -| onDragExit | DragEventHandler \| undefined | No | | | | | | -| onDragExitCapture | DragEventHandler \| undefined | No | | | | | | -| onDragLeave | DragEventHandler \| undefined | No | | | | | | -| onDragLeaveCapture | DragEventHandler \| undefined | No | | | | | | -| onDragOver | DragEventHandler \| undefined | No | | | | | | -| onDragOverCapture | DragEventHandler \| undefined | No | | | | | | -| onDragStart | DragEventHandler \| undefined | No | | | | | | -| onDragStartCapture | DragEventHandler \| undefined | No | | | | | | -| onDrop | DragEventHandler \| undefined | No | | | | | | -| onDropCapture | DragEventHandler \| undefined | No | | | | | | -| onDurationChange | ReactEventHandler \| undefined | No | | | | | | -| onDurationChangeCapture | ReactEventHandler \| undefined | No | | | | | | -| onEmptied | ReactEventHandler \| undefined | No | | | | | | -| onEmptiedCapture | ReactEventHandler \| undefined | No | | | | | | -| onEncrypted | ReactEventHandler \| undefined | No | | | | | | -| onEncryptedCapture | ReactEventHandler \| undefined | No | | | | | | -| onEnded | ReactEventHandler \| undefined | No | | | | | | -| onEndedCapture | ReactEventHandler \| undefined | No | | | | | | -| onError | ReactEventHandler \| undefined | No | | | | | | -| onErrorCapture | ReactEventHandler \| undefined | No | | | | | | -| onFilterChange | ((filterText: string) => void) \| undefined | No | | | | A custom callback for when the input text changes | | -| onFocus | ((ev: React.FocusEvent) => void) \| undefined | No | | | | Specify a callback triggered on focus | | -| onFocusCapture | FocusEventHandler \| undefined | No | | | | | | -| onGotPointerCapture | PointerEventHandler \| undefined | No | | | | | | -| onGotPointerCaptureCapture | PointerEventHandler \| undefined | No | | | | | | -| onInput | FormEventHandler \| undefined | No | | | | | | -| onInputCapture | FormEventHandler \| undefined | No | | | | | | -| onInvalid | FormEventHandler \| undefined | No | | | | | | -| onInvalidCapture | FormEventHandler \| undefined | No | | | | | | -| onKeyDown | ((ev: React.KeyboardEvent) => void) \| undefined | No | | | | Specify a callback triggered onKeyDown | | -| onKeyDownCapture | KeyboardEventHandler \| undefined | No | | | | | | -| onKeyUp | KeyboardEventHandler \| undefined | No | | | | | | -| onKeyUpCapture | KeyboardEventHandler \| undefined | No | | | | | | -| onListAction | (() => void) \| undefined | No | | | | A callback for when the Action Button is triggered | | -| onListScrollBottom | (() => void) \| undefined | No | | | | A callback that is triggered when a user scrolls to the bottom of the list | | -| onLoad | ReactEventHandler \| undefined | No | | | | | | -| onLoadCapture | ReactEventHandler \| undefined | No | | | | | | -| onLoadedData | ReactEventHandler \| undefined | No | | | | | | -| onLoadedDataCapture | ReactEventHandler \| undefined | No | | | | | | -| onLoadedMetadata | ReactEventHandler \| undefined | No | | | | | | -| onLoadedMetadataCapture | ReactEventHandler \| undefined | No | | | | | | -| onLoadStart | ReactEventHandler \| undefined | No | | | | | | -| onLoadStartCapture | ReactEventHandler \| undefined | No | | | | | | -| onLostPointerCapture | PointerEventHandler \| undefined | No | | | | | | -| onLostPointerCaptureCapture | PointerEventHandler \| undefined | No | | | | | | -| onMouseDown | ((ev: React.MouseEvent) => void) \| undefined | No | | | | Event handler for the mouse down event | | -| onMouseDownCapture | MouseEventHandler \| undefined | No | | | | | | -| onMouseEnter | MouseEventHandler \| undefined | No | | | | | | -| onMouseLeave | MouseEventHandler \| undefined | No | | | | | | -| onMouseMove | MouseEventHandler \| undefined | No | | | | | | -| onMouseMoveCapture | MouseEventHandler \| undefined | No | | | | | | -| onMouseOut | MouseEventHandler \| undefined | No | | | | | | -| onMouseOutCapture | MouseEventHandler \| undefined | No | | | | | | -| onMouseOver | MouseEventHandler \| undefined | No | | | | | | -| onMouseOverCapture | MouseEventHandler \| undefined | No | | | | | | -| onMouseUp | MouseEventHandler \| undefined | No | | | | | | -| onMouseUpCapture | MouseEventHandler \| undefined | No | | | | | | -| onOpen | (() => void) \| undefined | No | | | | A custom callback for when the dropdown menu opens | | -| onPaste | ClipboardEventHandler \| undefined | No | | | | | | -| onPasteCapture | ClipboardEventHandler \| undefined | No | | | | | | -| onPause | ReactEventHandler \| undefined | No | | | | | | -| onPauseCapture | ReactEventHandler \| undefined | No | | | | | | -| onPlay | ReactEventHandler \| undefined | No | | | | | | -| onPlayCapture | ReactEventHandler \| undefined | No | | | | | | -| onPlaying | ReactEventHandler \| undefined | No | | | | | | -| onPlayingCapture | ReactEventHandler \| undefined | No | | | | | | -| onPointerCancel | PointerEventHandler \| undefined | No | | | | | | -| onPointerCancelCapture | PointerEventHandler \| undefined | No | | | | | | -| onPointerDown | PointerEventHandler \| undefined | No | | | | | | -| onPointerDownCapture | PointerEventHandler \| undefined | No | | | | | | -| onPointerEnter | PointerEventHandler \| undefined | No | | | | | | -| onPointerLeave | PointerEventHandler \| undefined | No | | | | | | -| onPointerMove | PointerEventHandler \| undefined | No | | | | | | -| onPointerMoveCapture | PointerEventHandler \| undefined | No | | | | | | -| onPointerOut | PointerEventHandler \| undefined | No | | | | | | -| onPointerOutCapture | PointerEventHandler \| undefined | No | | | | | | -| onPointerOver | PointerEventHandler \| undefined | No | | | | | | -| onPointerOverCapture | PointerEventHandler \| undefined | No | | | | | | -| onPointerUp | PointerEventHandler \| undefined | No | | | | | | -| onPointerUpCapture | PointerEventHandler \| undefined | No | | | | | | -| onProgress | ReactEventHandler \| undefined | No | | | | | | -| onProgressCapture | ReactEventHandler \| undefined | No | | | | | | -| onRateChange | ReactEventHandler \| undefined | No | | | | | | -| onRateChangeCapture | ReactEventHandler \| undefined | No | | | | | | -| onReset | FormEventHandler \| undefined | No | | | | | | -| onResetCapture | FormEventHandler \| undefined | No | | | | | | -| onScroll | UIEventHandler \| undefined | No | | | | | | -| onScrollCapture | UIEventHandler \| undefined | No | | | | | | -| onSeeked | ReactEventHandler \| undefined | No | | | | | | -| onSeekedCapture | ReactEventHandler \| undefined | No | | | | | | -| onSeeking | ReactEventHandler \| undefined | No | | | | | | -| onSeekingCapture | ReactEventHandler \| undefined | No | | | | | | -| onSelect | ReactEventHandler \| undefined | No | | | | | | -| onSelectCapture | ReactEventHandler \| undefined | No | | | | | | -| onStalled | ReactEventHandler \| undefined | No | | | | | | -| onStalledCapture | ReactEventHandler \| undefined | No | | | | | | -| onSubmit | FormEventHandler \| undefined | No | | | | | | -| onSubmitCapture | FormEventHandler \| undefined | No | | | | | | -| onSuspend | ReactEventHandler \| undefined | No | | | | | | -| onSuspendCapture | ReactEventHandler \| undefined | No | | | | | | -| onTimeUpdate | ReactEventHandler \| undefined | No | | | | | | -| onTimeUpdateCapture | ReactEventHandler \| undefined | No | | | | | | -| onTouchCancel | TouchEventHandler \| undefined | No | | | | | | -| onTouchCancelCapture | TouchEventHandler \| undefined | No | | | | | | -| onTouchEnd | TouchEventHandler \| undefined | No | | | | | | -| onTouchEndCapture | TouchEventHandler \| undefined | No | | | | | | -| onTouchMove | TouchEventHandler \| undefined | No | | | | | | -| onTouchMoveCapture | TouchEventHandler \| undefined | No | | | | | | -| onTouchStart | TouchEventHandler \| undefined | No | | | | | | -| onTouchStartCapture | TouchEventHandler \| undefined | No | | | | | | -| onTransitionEnd | TransitionEventHandler \| undefined | No | | | | | | -| onTransitionEndCapture | TransitionEventHandler \| undefined | No | | | | | | -| onVolumeChange | ReactEventHandler \| undefined | No | | | | | | -| onVolumeChangeCapture | ReactEventHandler \| undefined | No | | | | | | -| onWaiting | ReactEventHandler \| undefined | No | | | | | | -| onWaitingCapture | ReactEventHandler \| undefined | No | | | | | | -| onWheel | WheelEventHandler \| undefined | No | | | | | | -| onWheelCapture | WheelEventHandler \| undefined | No | | | | | | -| openOnFocus | boolean \| undefined | No | | | | If true the Component opens on focus | | -| part | string \| undefined | No | | | | | | -| pattern | string \| undefined | No | | | | | | -| placeholder | string \| undefined | No | | | | Placeholder string to be displayed in input | | -| prefix | string \| undefined | No | | | | Emphasized part of the displayed text | | -| property | string \| undefined | No | | | | | | -| radioGroup | string \| undefined | No | | | | | | -| readOnly | boolean \| undefined | No | | | | If true, the component will be read-only | | -| rel | string \| undefined | No | | | | | | -| required | boolean \| undefined | No | | | | Flag to configure component as mandatory | | -| resource | string \| undefined | No | | | | | | -| results | number \| undefined | No | | | | | | -| rev | string \| undefined | No | | | | | | -| role | AriaRole \| undefined | No | | | | | | -| security | string \| undefined | No | | | | | | -| size | "small" \| "medium" \| "large" \| undefined | No | | | | Size of an input | | -| slot | string \| undefined | No | | | | | | -| spellCheck | Booleanish \| undefined | No | | | | | | -| src | string \| undefined | No | | | | | | -| step | string \| number \| undefined | No | | | | | | -| style | CSSProperties \| undefined | No | | | | | | -| suppressContentEditableWarning | boolean \| undefined | No | | | | | | -| suppressHydrationWarning | boolean \| undefined | No | | | | | | -| tabIndex | number \| undefined | No | | | | | | -| tableHeader | React.ReactNode | No | | | | SelectList table header, should consist of multiple th elements. Works only in multiColumn mode | | -| title | string \| undefined | No | | | | | | -| tooltipPosition | "left" \| "right" \| "bottom" \| "top" \| undefined | No | | | | [Legacy] Overrides the default tooltip position | | -| translate | "yes" \| "no" \| undefined | No | | | | | | -| type | HTMLInputTypeAttribute \| undefined | No | | | | | | -| typeof | string \| undefined | No | | | | | | -| unselectable | "off" \| "on" \| undefined | No | | | | | | -| validationIconId | string \| undefined | No | | | | Id of the validation icon | | -| validationMessagePositionTop | boolean \| undefined | No | | | | Render the ValidationMessage above the Textbox input when validationRedesignOptIn flag is set | | -| virtualScrollOverscan | number \| undefined | No | | | | The number of options to render into the DOM at once, either side of the currently-visible ones. Higher values make for smoother scrolling but may impact performance. Only used if the `enableVirtualScroll` prop is set. | | -| vocab | string \| undefined | No | | | | | | -| warning | string \| boolean \| undefined | No | | | | Indicate that warning has occurred. | | -| width | string \| number \| undefined | No | | | | | | -| data-element | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| data-role | string \| undefined | No | | | | Identifier used for testing purposes, applied to the root element of the component. | | -| aria-activedescendant | string \| undefined | No | | | | Identifies the currently active element when DOM focus is on a composite widget, textbox, group, or application. | | -| aria-atomic | Booleanish \| undefined | No | | | | Indicates whether assistive technologies will present all, or only parts of, the changed region based on the change notifications defined by the aria-relevant attribute. | | -| aria-autocomplete | "none" \| "inline" \| "list" \| "both" \| undefined | No | | | | Indicates whether inputting text could trigger display of one or more predictions of the user's intended value for an input and specifies how predictions would be presented if they are made. | | -| aria-braillelabel | string \| undefined | No | | | | Indicates an element is being modified and that assistive technologies MAY want to wait until the modifications are complete before exposing them to the user. Defines a string value that labels the current element, which is intended to be converted into Braille. | | -| aria-brailleroledescription | string \| undefined | No | | | | Defines a human-readable, author-localized abbreviated description for the role of an element, which is intended to be converted into Braille. | | -| aria-busy | Booleanish \| undefined | No | | | | | | -| aria-checked | boolean \| "true" \| "false" \| "mixed" \| undefined | No | | | | Indicates the current "checked" state of checkboxes, radio buttons, and other widgets. | | -| aria-colcount | number \| undefined | No | | | | Defines the total number of columns in a table, grid, or treegrid. | | -| aria-colindex | number \| undefined | No | | | | Defines an element's column index or position with respect to the total number of columns within a table, grid, or treegrid. | | -| aria-colindextext | string \| undefined | No | | | | Defines a human readable text alternative of aria-colindex. | | -| aria-colspan | number \| undefined | No | | | | Defines the number of columns spanned by a cell or gridcell within a table, grid, or treegrid. | | -| aria-controls | string \| undefined | No | | | | Identifies the element (or elements) whose contents or presence are controlled by the current element. | | -| aria-current | boolean \| "location" \| "page" \| "time" \| "true" \| "false" \| "step" \| "date" \| undefined | No | | | | Indicates the element that represents the current item within a container or set of related elements. | | -| aria-describedby | string \| undefined | No | | | | The ID of the input's description, is set along with hint text and error message. | | -| aria-description | string \| undefined | No | | | | Defines a string value that describes or annotates the current element. | | -| aria-details | string \| undefined | No | | | | Identifies the element that provides a detailed, extended description for the object. | | -| aria-disabled | Booleanish \| undefined | No | | | | Indicates that the element is perceivable but disabled, so it is not editable or otherwise operable. | | -| aria-errormessage | string \| undefined | No | | | | Identifies the element that provides an error message for the object. | | -| aria-expanded | Booleanish \| undefined | No | | | | Indicates whether the element, or another grouping element it controls, is currently expanded or collapsed. | | -| aria-flowto | string \| undefined | No | | | | Identifies the next element (or elements) in an alternate reading order of content which, at the user's discretion, allows assistive technology to override the general default of reading in document source order. | | -| aria-haspopup | boolean \| "grid" \| "dialog" \| "menu" \| "true" \| "false" \| "listbox" \| "tree" \| undefined | No | | | | Indicates the availability and type of interactive popup element, such as menu or dialog, that can be triggered by an element. | | -| aria-hidden | Booleanish \| undefined | No | | | | Indicates whether the element is exposed to an accessibility API. | | -| aria-invalid | boolean \| "true" \| "false" \| "grammar" \| "spelling" \| undefined | No | | | | Indicates the entered value does not conform to the format expected by the application. | | -| aria-keyshortcuts | string \| undefined | No | | | | Indicates keyboard shortcuts that an author has implemented to activate or give focus to an element. | | -| aria-label | string \| undefined | No | | | | Prop to specify the aria-label attribute of the component input | | -| aria-labelledby | string \| undefined | No | | | | Prop to specify the aria-labelledby property of the component input | | -| aria-level | number \| undefined | No | | | | Defines the hierarchical level of an element within a structure. | | -| aria-live | "off" \| "assertive" \| "polite" \| undefined | No | | | | Indicates that an element will be updated, and describes the types of updates the user agents, assistive technologies, and user can expect from the live region. | | -| aria-modal | Booleanish \| undefined | No | | | | Indicates whether an element is modal when displayed. | | -| aria-multiline | Booleanish \| undefined | No | | | | Indicates whether a text box accepts multiple lines of input or only a single line. | | -| aria-multiselectable | Booleanish \| undefined | No | | | | Indicates that the user may select more than one item from the current selectable descendants. | | -| aria-orientation | "horizontal" \| "vertical" \| undefined | No | | | | Indicates whether the element's orientation is horizontal, vertical, or unknown/ambiguous. | | -| aria-owns | string \| undefined | No | | | | Identifies an element (or elements) in order to define a visual, functional, or contextual parent/child relationship between DOM elements where the DOM hierarchy cannot be used to represent the relationship. | | -| aria-placeholder | string \| undefined | No | | | | Defines a short hint (a word or short phrase) intended to aid the user with data entry when the control has no value. A hint could be a sample value or a brief description of the expected format. | | -| aria-posinset | number \| undefined | No | | | | Defines an element's number or position in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM. | | -| aria-pressed | boolean \| "true" \| "false" \| "mixed" \| undefined | No | | | | Indicates the current "pressed" state of toggle buttons. | | -| aria-readonly | Booleanish \| undefined | No | | | | Indicates that the element is not editable, but is otherwise operable. | | -| aria-relevant | "text" \| "additions" \| "additions removals" \| "additions text" \| "all" \| "removals" \| "removals additions" \| "removals text" \| "text additions" \| "text removals" \| undefined | No | | | | Indicates what notifications the user agent will trigger when the accessibility tree within a live region is modified. | | -| aria-required | Booleanish \| undefined | No | | | | Indicates that user input is required on the element before a form may be submitted. | | -| aria-roledescription | string \| undefined | No | | | | Defines a human-readable, author-localized description for the role of an element. | | -| aria-rowcount | number \| undefined | No | | | | Defines the total number of rows in a table, grid, or treegrid. | | -| aria-rowindex | number \| undefined | No | | | | Defines an element's row index or position with respect to the total number of rows within a table, grid, or treegrid. | | -| aria-rowindextext | string \| undefined | No | | | | Defines a human readable text alternative of aria-rowindex. | | -| aria-rowspan | number \| undefined | No | | | | Defines the number of rows spanned by a cell or gridcell within a table, grid, or treegrid. | | -| aria-selected | Booleanish \| undefined | No | | | | Indicates the current "selected" state of various widgets. | | -| aria-setsize | number \| undefined | No | | | | Defines the number of items in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM. | | -| aria-sort | "none" \| "ascending" \| "descending" \| "other" \| undefined | No | | | | Indicates if items in a table or grid are sorted in ascending or descending order. | | -| aria-valuemax | number \| undefined | No | | | | Defines the maximum allowed value for a range widget. | | -| aria-valuemin | number \| undefined | No | | | | Defines the minimum allowed value for a range widget. | | -| aria-valuenow | number \| undefined | No | | | | Defines the current value for a range widget. | | -| aria-valuetext | string \| undefined | No | | | | Defines the human readable text alternative of aria-valuenow for a range widget. | | -| adaptiveLabelBreakpoint | number \| undefined | No | | Yes | `adaptiveLabelBreakpoint` has been deprecated. It is recommended to use `useMediaQuery` hook to implement adaptive behaviour. Breakpoint for adaptive label (inline labels change to top aligned). Enables the adaptive behaviour when set | | | -| fieldHelp | React.ReactNode | No | | Yes | `fieldHelp` has been deprecated, `inputHint` should be used instead. [Legacy] Help content to be displayed under an input. | | | -| helpAriaLabel | string \| undefined | No | | Yes | `helpAriaLabel` has been deprecated, the functionality will no longer work. | | | -| labelAlign | "left" \| "right" \| undefined | No | | Yes | `labelAlign` has been deprecated, the functionality will no longer work. | | | -| labelSpacing | 1 \| 2 \| undefined | No | | Yes | `labelSpacing` has been deprecated, the functionality will no longer work. | | | -| onKeyPress | KeyboardEventHandler \| undefined | No | | Yes | Use `onKeyUp` or `onKeyDown` instead | | | -| onKeyPressCapture | KeyboardEventHandler \| undefined | No | | Yes | Use `onKeyUpCapture` or `onKeyDownCapture` instead | | | -| reverse | boolean \| undefined | No | | Yes | `reverse` has been deprecated, the functionality will no longer work. | | | -| tooltipId | string \| undefined | No | | Yes | `tooltipId` has been deprecated, the functionality will no longer work. | | | -| validationOnLabel | boolean \| undefined | No | | Yes | `validationOnLabel` has been deprecated, the functionality will no longer work. | | | -| aria-dropeffect | "copy" \| "link" \| "none" \| "execute" \| "move" \| "popup" \| undefined | No | | Yes | in ARIA 1.1 | Indicates what functions can be performed when a dragged object is released on the drop target. | | -| aria-grabbed | Booleanish \| undefined | No | | Yes | in ARIA 1.1 | Indicates an element's "grabbed" state in a drag-and-drop operation. | | - -## Examples -### MDX Example 1 - -**Args** - -```tsx -Always insert `Option` Components inside the `FilterableSelect`, analogous to the `