Repository: streamlit/streamlit
File: frontend/lib/src/theme/utils.ts (TypeScript)

Code before:
export function addCssUnit(n: number, unit: "px" | "rem"): string {
  return `${n}${unit}`
}

function roundToTwoDecimals(n: number): number {
  return parseFloat(n.toFixed(2))
}

export function blend(color: string, background: string | undefined): string {
  if (background === undefined) return color
  const [r, g, b, a] = parseToRgba(color)
  if (a === 1) return color
  const [br, bg, bb, ba] = parseToRgba(background)
  const ao = a + ba * (1 - a)
  // (xaA + xaB·(1−aA))/aR
  const ro = Math.round((a * r + ba * br * (1 - a)) / ao)
  const go = Math.round((a * g + ba * bg * (1 - a)) / ao)
  const bo = Math.round((a * b + ba * bb * (1 - a)) / ao)
  return toHex(`rgba(${ro}, ${go}, ${bo}, ${ao})`)
}

/**
 * Canonical focus ring used across Streamlit components for keyboard focus
 * (usually applied via `:focus-visible`).
 */
export const getFocusRingBoxShadow = (
  color: string,
  /**
   * The alpha value to use for the focus ring.
   * Matches color2k.transparentize: 0 = unchanged, 1 = fully transparent.
   */
  alpha: number = 0.5,
  width: string = "0.2rem"
): string => {
  return `0 0 0 ${width} ${transparentize(color, alpha)}`
}

export const getPrimaryFocusRingBoxShadow = (
  theme: Pick<EmotionTheme, "colors">
): string => {
  return getFocusRingBoxShadow(theme.colors.primary)
}

/**
 * Convert a SCSS rem value to pixels.
 * @param scssValue: a string containing a value in rem units with or without the "rem" unit suffix
 * @returns pixel value of the given rem value
 */
export const convertRemToPx = (scssValue: string): number => {
  const remValue = parseFloat(scssValue.replace(/rem$/, ""))
  return (

Review comment (suggestion):
**Suggestion**: Personally prefer `getFocusBoxShadow` and `getPrimaryFocusBoxShadow` but either works!

Code after:
export function addCssUnit(n: number, unit: "px" | "rem"): string {
  return `${n}${unit}`
}

function roundToTwoDecimals(n: number): number {
  return parseFloat(n.toFixed(2))
}

export function blend(color: string, background: string | undefined): string {
  if (background === undefined) return color
  const [r, g, b, a] = parseToRgba(color)
  if (a === 1) return color
  const [br, bg, bb, ba] = parseToRgba(background)
  const ao = a + ba * (1 - a)
  // (xaA + xaB·(1−aA))/aR
  const ro = Math.round((a * r + ba * br * (1 - a)) / ao)
  const go = Math.round((a * g + ba * bg * (1 - a)) / ao)
  const bo = Math.round((a * b + ba * bb * (1 - a)) / ao)
  return toHex(`rgba(${ro}, ${go}, ${bo}, ${ao})`)
}

/**
 * Canonical focus ring used across Streamlit components for keyboard focus
 * (usually applied via `:focus-visible`).
 */
export const getFocusBoxShadow = (
  color: string,
  /**
   * The alpha value to use for the focus ring.
   * Matches color2k.transparentize: 0 = unchanged, 1 = fully transparent.
   */
  alpha: number = 0.5,
  width: string = "0.2rem"
): string => {
  return `0 0 0 ${width} ${transparentize(color, alpha)}`
}

export const getPrimaryFocusBoxShadow = (
  theme: Pick<EmotionTheme, "colors">
): string => {
  return getFocusBoxShadow(theme.colors.primary)
}

/**
 * Convert a SCSS rem value to pixels.
 * @param scssValue: a string containing a value in rem units with or without the "rem" unit suffix
 * @returns pixel value of the given rem value
 */
export const convertRemToPx = (scssValue: string): number => {
  const remValue = parseFloat(scssValue.replace(/rem$/, ""))
  return (