@solo-io-public/ui-components 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +167 -0
  3. package/dist/Button.style-CCplEN2o.js +474 -0
  4. package/dist/Button.style-CCplEN2o.js.map +1 -0
  5. package/dist/Button.style-CI6Xbod7.cjs +10 -0
  6. package/dist/Button.style-CI6Xbod7.cjs.map +1 -0
  7. package/dist/_internal/Svg.d.ts +15 -0
  8. package/dist/_internal/colors.d.ts +17 -0
  9. package/dist/_internal/gradients.d.ts +11 -0
  10. package/dist/_internal/hexAddAlpha.d.ts +3 -0
  11. package/dist/_internal/palette.d.ts +30 -0
  12. package/dist/_internal/sizing.d.ts +14 -0
  13. package/dist/_internal/unstyledButton.d.ts +8 -0
  14. package/dist/_internal/utils.d.ts +7 -0
  15. package/dist/components/Alert/Alert.d.ts +17 -0
  16. package/dist/components/Alert/index.d.ts +1 -0
  17. package/dist/components/Button/Button.d.ts +32 -0
  18. package/dist/components/Button/Button.style.d.ts +48 -0
  19. package/dist/components/Button/index.d.ts +1 -0
  20. package/dist/components/CloseButton/CloseButton.d.ts +14 -0
  21. package/dist/components/CloseButton/index.d.ts +1 -0
  22. package/dist/components/Layout/FlexLayout.d.ts +83 -0
  23. package/dist/components/Layout/Spacer.d.ts +80 -0
  24. package/dist/components/Layout/index.d.ts +2 -0
  25. package/dist/components/MonacoEditor/EditorSettingsContext.d.ts +15 -0
  26. package/dist/components/MonacoEditor/MonacoEditorWithSettings.d.ts +20 -0
  27. package/dist/components/MonacoEditor/index.d.ts +2 -0
  28. package/dist/components/Text/Text.d.ts +71 -0
  29. package/dist/components/Text/index.d.ts +1 -0
  30. package/dist/index.d.ts +7 -0
  31. package/dist/providers/SoloContextProvider.d.ts +62 -0
  32. package/dist/providers/SoloModeContext.d.ts +5 -0
  33. package/dist/providers/index.d.ts +2 -0
  34. package/dist/solo-components.cjs +56 -0
  35. package/dist/solo-components.cjs.map +1 -0
  36. package/dist/solo-components.js +664 -0
  37. package/dist/solo-components.js.map +1 -0
  38. package/dist/styles.cjs +2 -0
  39. package/dist/styles.cjs.map +1 -0
  40. package/dist/styles.d.ts +1 -0
  41. package/dist/styles.js +5 -0
  42. package/dist/styles.js.map +1 -0
  43. package/package.json +109 -0
  44. package/src/_internal/Svg.tsx +58 -0
  45. package/src/_internal/colors.ts +26 -0
  46. package/src/_internal/gradients.ts +36 -0
  47. package/src/_internal/hexAddAlpha.ts +9 -0
  48. package/src/_internal/palette.ts +46 -0
  49. package/src/_internal/sizing.ts +15 -0
  50. package/src/_internal/unstyledButton.ts +17 -0
  51. package/src/_internal/utils.ts +11 -0
  52. package/src/components/Alert/Alert.stories.tsx +44 -0
  53. package/src/components/Alert/Alert.tsx +168 -0
  54. package/src/components/Alert/index.ts +1 -0
  55. package/src/components/Button/Button.stories.tsx +62 -0
  56. package/src/components/Button/Button.style.ts +158 -0
  57. package/src/components/Button/Button.test.tsx +47 -0
  58. package/src/components/Button/Button.tsx +84 -0
  59. package/src/components/Button/index.ts +11 -0
  60. package/src/components/CloseButton/CloseButton.tsx +76 -0
  61. package/src/components/CloseButton/index.ts +1 -0
  62. package/src/components/Layout/FlexLayout.tsx +101 -0
  63. package/src/components/Layout/Spacer.tsx +131 -0
  64. package/src/components/Layout/index.ts +2 -0
  65. package/src/components/MonacoEditor/EditorSettingsContext.test.tsx +55 -0
  66. package/src/components/MonacoEditor/EditorSettingsContext.tsx +63 -0
  67. package/src/components/MonacoEditor/MonacoEditor.stories.tsx +197 -0
  68. package/src/components/MonacoEditor/MonacoEditorWithSettings.tsx +376 -0
  69. package/src/components/MonacoEditor/index.ts +9 -0
  70. package/src/components/Text/Text.stories.tsx +63 -0
  71. package/src/components/Text/Text.tsx +65 -0
  72. package/src/components/Text/index.ts +1 -0
  73. package/src/index.ts +7 -0
  74. package/src/providers/SoloContextProvider.tsx +213 -0
  75. package/src/providers/SoloModeContext.tsx +13 -0
  76. package/src/providers/index.ts +10 -0
  77. package/src/styles.ts +5 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solo-components.js","sources":["../src/providers/SoloModeContext.tsx","../src/components/CloseButton/CloseButton.tsx","../src/components/Layout/Spacer.tsx","../src/components/Text/Text.tsx","../src/components/Alert/Alert.tsx","../src/_internal/Svg.tsx","../src/components/Button/Button.tsx","../src/components/Layout/FlexLayout.tsx","../src/components/MonacoEditor/EditorSettingsContext.tsx","../src/components/MonacoEditor/MonacoEditorWithSettings.tsx","../src/providers/SoloContextProvider.tsx"],"sourcesContent":["import { createContext, useContext } from 'react';\n\nexport type SoloMode = 'light' | 'dark';\n\nconst SoloModeContext = createContext<SoloMode>('dark');\n\n/** Provides the active light/dark mode to descendants (e.g. the editor). */\nexport const SoloModeProvider = SoloModeContext.Provider;\n\n/** Read the active Solo color mode. Defaults to `'dark'` outside a provider. */\nexport function useSoloMode(): SoloMode {\n return useContext(SoloModeContext);\n}\n","import type { SerializedStyles } from '@emotion/react';\nimport styled from '@emotion/styled';\nimport { X } from 'lucide-react';\nimport type { ButtonHTMLAttributes } from 'react';\nimport { dontForwardProps } from '../../_internal/utils';\n\n// region Styles\n\nconst StyledCloseButton = styled('button', dontForwardProps('styleOverrides'))<{ styleOverrides?: SerializedStyles }>`\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 6px;\n background: transparent;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n color: inherit;\n opacity: 0.8;\n transition:\n background-color 0.08s ease,\n opacity 0.08s ease;\n\n &:hover {\n opacity: 1;\n /* Subtle wash derived from the button's own color, so it works on any background. */\n background-color: color-mix(in srgb, currentColor 14%, transparent);\n }\n\n &:active {\n background-color: color-mix(in srgb, currentColor 24%, transparent);\n }\n\n &:focus-visible {\n outline: 2px solid var(--color-primary, #6844ff);\n outline-offset: 2px;\n }\n\n @media (prefers-reduced-motion: reduce) {\n transition: none;\n }\n\n svg {\n display: block;\n }\n\n ${props => props.styleOverrides}\n`;\n\n// region Component\n\nexport interface CloseButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** X icon size in px. */\n size?: number;\n /** Emotion styles appended to the button. */\n styleOverrides?: SerializedStyles;\n}\n\n/**\n * A minimal \"×\" icon button (Lucide `X`). Inherits its color from context\n * (override via `style`/`styleOverrides`); hover/active washes derive from that\n * color, so it sits cleanly on any surface — alerts, drawers, modals, etc.\n */\nexport function CloseButton({\n size = 18,\n styleOverrides,\n type = 'button',\n 'aria-label': ariaLabel = 'Close',\n ...props\n}: CloseButtonProps) {\n return (\n <StyledCloseButton type={type} aria-label={ariaLabel} styleOverrides={styleOverrides} {...props}>\n <X size={size} />\n </StyledCloseButton>\n );\n}\n","import type { SerializedStyles } from '@emotion/react';\nimport styled from '@emotion/styled';\nimport type { ComponentProps, CSSProperties } from 'react';\nimport { cssProp, dontForwardProps } from '../../_internal/utils';\n\n// region Helpers\n\ntype SizeType = number | string;\n\n// region Component\n\n/**\n * Margin/padding/sizing primitive. Use a string for exact values\n * (e.g. `mx='5px'`). Directional props (`mr`, `mb`, …) override the axis\n * shorthands (`mx`, `my`).\n */\nexport type SpacerProps = {\n mx?: string;\n my?: string;\n mr?: string;\n ml?: string;\n mt?: string;\n mb?: string;\n margin?: string;\n px?: string;\n py?: string;\n pr?: string;\n pl?: string;\n pt?: string;\n pb?: string;\n padding?: string;\n display?: CSSProperties['display'];\n position?: CSSProperties['position'];\n minHeight?: SizeType;\n minWidth?: CSSProperties['minWidth'];\n height?: SizeType;\n width?: SizeType;\n maxHeight?: CSSProperties['maxHeight'];\n maxWidth?: CSSProperties['maxWidth'];\n flexGrow?: CSSProperties['flexGrow'];\n flexBasis?: CSSProperties['flexBasis'];\n flexShrink?: CSSProperties['flexShrink'];\n overflowY?: CSSProperties['overflowY'];\n overflowX?: CSSProperties['overflowX'];\n textOverflow?: CSSProperties['textOverflow'];\n overflow?: CSSProperties['overflow'];\n zIndex?: CSSProperties['zIndex'];\n stylingOverrides?: SerializedStyles;\n fadeIn?: boolean;\n} & ComponentProps<'div'>;\n\nexport const Spacer = styled(\n 'div',\n dontForwardProps(\n 'mx',\n 'my',\n 'mr',\n 'ml',\n 'mt',\n 'mb',\n 'margin',\n 'px',\n 'py',\n 'pr',\n 'pl',\n 'pt',\n 'pb',\n 'padding',\n 'display',\n 'position',\n 'minHeight',\n 'minWidth',\n 'height',\n 'width',\n 'maxHeight',\n 'maxWidth',\n 'flexGrow',\n 'flexBasis',\n 'flexShrink',\n 'overflowY',\n 'overflowX',\n 'textOverflow',\n 'overflow',\n 'zIndex',\n 'stylingOverrides',\n 'fadeIn'\n )\n)<SpacerProps>(props => {\n const { mx, my, mr, ml, mt, mb, margin, px, py, pl, pr, pt, pb, padding } = props;\n const marginRight = mr ?? mx;\n const marginLeft = ml ?? mx;\n const marginTop = mt ?? my;\n const marginBottom = mb ?? my;\n const paddingRight = pr ?? px;\n const paddingLeft = pl ?? px;\n const paddingTop = pt ?? py;\n const paddingBottom = pb ?? py;\n return `\n ${cssProp('display', props.display)}\n ${cssProp('position', props.position)}\n ${cssProp('margin', margin)}\n ${cssProp('margin-right', marginRight)}\n ${cssProp('margin-left', marginLeft)}\n ${cssProp('margin-top', marginTop)}\n ${cssProp('margin-bottom', marginBottom)}\n ${cssProp('padding', padding)}\n ${cssProp('padding-right', paddingRight)}\n ${cssProp('padding-left', paddingLeft)}\n ${cssProp('padding-top', paddingTop)}\n ${cssProp('padding-bottom', paddingBottom)}\n ${cssProp('min-height', props.minHeight)}\n ${cssProp('min-width', props.minWidth)}\n ${cssProp('height', props.height)}\n ${cssProp('width', props.width)}\n ${cssProp('max-height', props.maxHeight)}\n ${cssProp('max-width', props.maxWidth)}\n ${cssProp('flex-grow', props.flexGrow)}\n ${cssProp('flex-shrink', props.flexShrink)}\n ${cssProp('flex-basis', props.flexBasis)}\n ${cssProp('overflow-y', props.overflowY)}\n ${cssProp('overflow-x', props.overflowX)}\n ${cssProp('overflow', props.overflow)}\n ${cssProp('text-overflow', props.textOverflow)}\n ${cssProp('z-index', props.zIndex)}\n\n animation: ${props.fadeIn ? `fadeIn 200ms cubic-bezier(0.22, 1, 0.36, 1) forwards` : 'none'};\n ${props.fadeIn ? `@media (prefers-reduced-motion: reduce) { animation: none; opacity: 1; }` : ''}\n\n ${props.stylingOverrides?.styles ? props.stylingOverrides.styles : ''}\n`;\n});\n","import styled from '@emotion/styled';\nimport type { CSSProperties } from 'react';\nimport { cssProp, dontForwardProps } from '../../_internal/utils';\nimport { Spacer, type SpacerProps } from '../Layout/Spacer';\n\n// region Helpers\n\nconst truncated = `\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n`;\n\n// region Component\n\n/**\n * Typography primitive built on `Spacer` (so margin/padding/sizing props work\n * too). Defaults to the theme's `--color-text-primary`, so text color follows\n * the active light/dark mode unless `color` is set explicitly.\n */\nexport type TextProps = SpacerProps & {\n size?: CSSProperties['fontSize'];\n weight?: CSSProperties['fontWeight'];\n lineHeight?: CSSProperties['lineHeight'];\n color?: CSSProperties['color'];\n textAlign?: CSSProperties['textAlign'];\n whiteSpace?: CSSProperties['whiteSpace'];\n truncate?: boolean;\n wordBreak?: CSSProperties['wordBreak'];\n textTransform?: CSSProperties['textTransform'];\n fontStyle?: CSSProperties['fontStyle'];\n inline?: boolean;\n};\n\nexport const Text = styled(\n Spacer,\n dontForwardProps(\n 'size',\n 'weight',\n 'lineHeight',\n 'color',\n 'textAlign',\n 'whiteSpace',\n 'truncate',\n 'wordBreak',\n 'textTransform',\n 'fontStyle',\n 'inline'\n )\n)<TextProps>(\n ({ size, weight, lineHeight, color, textAlign, whiteSpace, truncate, wordBreak, textTransform, fontStyle, inline, display }) => `\n font-family: var(--solo-font-family, inherit);\n color: ${color ?? 'var(--color-text-primary, #fafafa)'};\n ${cssProp('font-size', size)}\n ${cssProp('font-weight', weight)}\n ${cssProp('line-height', lineHeight)}\n ${cssProp('text-align', textAlign)}\n ${cssProp('white-space', whiteSpace)}\n ${cssProp('word-break', wordBreak)}\n ${cssProp('text-transform', textTransform)}\n ${cssProp('font-style', fontStyle)}\n ${cssProp('display', display ?? (inline ? 'inline' : 'block'))}\n ${truncate ? truncated : ''}\n `\n);\n","import styled from '@emotion/styled';\nimport { CircleCheck, Info, OctagonAlert, TriangleAlert, type LucideIcon } from 'lucide-react';\nimport { useState, type ReactNode } from 'react';\nimport { soloColorTokens, type SoloColorName } from '../../_internal/palette';\nimport { dontForwardProps } from '../../_internal/utils';\nimport { useSoloMode } from '../../providers/SoloModeContext';\nimport { CloseButton } from '../CloseButton';\nimport { Text } from '../Text';\n\n// region Styles\n\nconst Container = styled('div', dontForwardProps('background', 'frame', 'shadow'))<{\n background: string;\n frame: string;\n shadow: string;\n}>`\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 14px 16px;\n border-radius: 6px;\n border: 1px solid ${props => props.frame};\n background: ${props => props.background};\n box-shadow: ${props => props.shadow};\n`;\n\nconst IconSlot = styled('div', dontForwardProps('accent'))<{ accent: string }>`\n flex-shrink: 0;\n display: flex;\n margin-top: 1px;\n color: ${props => props.accent};\n\n svg {\n width: 18px;\n height: 18px;\n }\n`;\n\nconst Body = styled.div`\n display: flex;\n flex: 1;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n`;\n\n// region Component\n\nexport type AlertType = 'info' | 'success' | 'warning' | 'danger';\n\n// `darkAccent` is a neon-bright icon/outline for dark mode. `lightAccent` lets a\n// type swap its muted palette solid for a punchier hue in light mode (e.g. a\n// truer red / yellow); it falls back to the solid when omitted.\nconst typeConfig: Record<AlertType, { color: SoloColorName; Icon: LucideIcon; darkAccent: string; lightAccent?: string }> = {\n // Brand purple, matching the Button's `dark-purple`.\n info: { color: 'dark-purple', Icon: Info, darkAccent: '#b57bff', lightAccent: '#8134e2' },\n success: { color: 'success', Icon: CircleCheck, darkAccent: '#2fe07f', lightAccent: '#16a34a' },\n warning: { color: 'warning', Icon: TriangleAlert, darkAccent: '#ffb238', lightAccent: '#f7c52e' },\n danger: { color: 'red', Icon: OctagonAlert, darkAccent: '#ff6a6a', lightAccent: '#ef3030' }\n};\n\nexport interface AlertProps {\n type?: AlertType;\n title?: ReactNode;\n children?: ReactNode;\n /** Shows an X button in the upper-right that hides the alert. */\n isDismissable?: boolean;\n /** Called when the alert is dismissed (after it hides itself). */\n onDismiss?: () => void;\n}\n\n/**\n * Inline alert with a Lucide icon. Dark uses a neon accent — a bright outline +\n * icon with a glow — over a translucent fill; light uses a soft accent wash on\n * near-white. Pass `isDismissable` for an X button that closes it.\n */\nexport function Alert({ type = 'info', title, children, isDismissable = false, onDismiss }: AlertProps) {\n const { color, Icon, darkAccent, lightAccent } = typeConfig[type];\n const tokens = soloColorTokens[color];\n const mode = useSoloMode();\n const [dismissed, setDismissed] = useState(false);\n\n // Light mode can swap the muted solid for a punchier hue; dark keeps its neon.\n const lightBase = lightAccent ?? tokens.bg;\n const accent = mode === 'dark' ? darkAccent : lightBase;\n // Base color the fill + text tints are composed from.\n const tintBase = mode === 'dark' ? tokens.bg : lightBase;\n // Colored icon in light (keeps the hue, grounded for contrast); dark keeps the\n // neon accent. Warning's bright yellow is deepened more so it stays legible.\n const iconColor =\n mode === 'dark'\n ? accent\n : type === 'warning'\n ? `color-mix(in srgb, ${lightBase} 42%, #15151a)`\n : `color-mix(in srgb, ${lightBase} 60%, #1c1c22)`;\n // Light uses an accent-on-white border; dark keeps the neon edge. Warning's\n // pale-yellow border needs full strength to stay visible.\n const borderColor =\n mode === 'dark'\n ? accent\n : type === 'warning'\n ? lightBase\n : `color-mix(in srgb, ${lightBase} 60%, #ffffff)`;\n\n // Dark: a translucent accent-tinted fill so the page shows through. Light: a\n // medium accent tint on near-white.\n const opacity = mode === 'dark' ? 72 : 100;\n const fillPct = mode === 'dark' ? 28 : 20;\n const background = `color-mix(in srgb, color-mix(in srgb, ${tintBase} ${fillPct}%, var(--color-bg-elevated, #1e1e22)) ${opacity}%, transparent)`;\n\n // Dark: a neon glow from the accent plus a small drop shadow. Light: a soft,\n // slightly accent-tinted card shadow so the alert reads as an elevated surface\n // instead of a flat tinted rectangle.\n const shadow =\n mode === 'dark'\n ? `0 0 16px color-mix(in srgb, ${accent} 34%, transparent), 0 2px 4px rgba(0, 0, 0, 0.32)`\n : `0 1px 2px rgba(16, 24, 40, 0.05), 0 2px 5px rgba(16, 24, 40, 0.04)`;\n\n // Text is tinted with the accent — light on dark, and a soft accent-tinted dark\n // on light (tinted rather than near-black, to suit the airy wash).\n const titleColor =\n mode === 'dark'\n ? `color-mix(in srgb, ${tintBase} 22%, #ffffff)`\n : `color-mix(in srgb, ${tintBase} 30%, #17171b)`;\n const messageColor =\n mode === 'dark'\n ? `color-mix(in srgb, ${tintBase} 20%, #c8ccd4)`\n : `color-mix(in srgb, ${tintBase} 22%, #3c3c44)`;\n\n if (dismissed) return null;\n\n const handleDismiss = () => {\n setDismissed(true);\n onDismiss?.();\n };\n\n // info/success are polite (status); warning/danger interrupt (alert).\n const role = type === 'warning' || type === 'danger' ? 'alert' : 'status';\n\n return (\n <Container role={role} background={background} frame={borderColor} shadow={shadow}>\n {/* Icon is decorative — the title/message already carry the meaning. */}\n <IconSlot accent={iconColor} aria-hidden='true'>\n <Icon />\n </IconSlot>\n <Body>\n {title ? (\n <Text size='14px' weight={600} color={titleColor}>\n {title}\n </Text>\n ) : null}\n {children ? (\n <Text size='14px' color={messageColor}>\n {children}\n </Text>\n ) : null}\n </Body>\n {isDismissable ? (\n <CloseButton\n aria-label='Dismiss'\n size={16}\n onClick={handleDismiss}\n style={{ color: messageColor, flexShrink: 0, marginTop: 1 }}\n />\n ) : null}\n </Container>\n );\n}\n","import { css } from '@emotion/react';\nimport styled from '@emotion/styled';\nimport type { FunctionComponent, SVGProps } from 'react';\nimport { dontForwardProps } from './utils';\n\nexport type SvgAsset = FunctionComponent<SVGProps<SVGSVGElement> & { title?: string }>;\n\nexport type SvgSize = number | string;\n\ntype SvgContainerProps = {\n svgColor?: string;\n inline?: boolean;\n width?: SvgSize;\n height?: SvgSize;\n};\n\nconst px = (v: SvgSize | undefined) =>\n v === undefined ? undefined : typeof v === 'number' ? `${v}px` : v;\n\nconst SvgContainer = styled(\n 'span',\n dontForwardProps('svgColor', 'inline', 'width', 'height')\n)<SvgContainerProps>(\n ({ svgColor, inline, width, height }) => css`\n display: ${inline ? 'inline-flex' : 'flex'};\n align-items: center;\n justify-items: center;\n ${svgColor ? `color: ${svgColor};` : ''}\n\n svg {\n ${width !== undefined ? `width: ${px(width)};` : ''}\n ${height !== undefined ? `height: ${px(height)};` : ''}\n ${svgColor\n ? `&:not([fill]), &[fill]:not([fill='none'], [fill='transparent']) { fill: ${svgColor}; }\n *[fill]:not([fill='none'], [fill='transparent']) { fill: ${svgColor}; }\n *[stroke]:not([stroke='none'], [stroke='transparent']) { stroke: ${svgColor}; }`\n : ''}\n }\n `\n);\n\nexport type SvgProps = {\n asset: SvgAsset;\n color?: string;\n width?: SvgSize;\n height?: SvgSize;\n /** Sets both width and height. */\n size?: SvgSize;\n inline?: boolean;\n};\n\nexport const Svg = ({ asset: Asset, color, size, width = size, height = size, inline }: SvgProps) => {\n return (\n <SvgContainer svgColor={color} width={width} height={height} inline={inline}>\n <Asset />\n </SvgContainer>\n );\n};\n","import { css, type SerializedStyles } from '@emotion/react';\nimport type { CSSProperties, PropsWithChildren, ReactNode, ButtonHTMLAttributes } from 'react';\nimport { Svg, type SvgAsset } from '../../_internal/Svg';\nimport type { ElementOf } from '../../_internal/utils';\nimport { StyledButton } from './Button.style';\n\n/** Helper to render an SvgAsset at the standard 16px size with `currentColor`. */\nexport const buttonSvg = (asset: SvgAsset) => <Svg asset={asset} color='currentColor' size={16} />;\n\nexport const buttonVariants = {\n /** `variant='bare'` is an outlined secondary button (dim fill + accent outline & text). */\n variants: ['solid', 'bare'],\n colors: ['dark-purple', 'red', 'warning', 'success', 'gray', 'black', 'blue'],\n sizes: ['sm', 'md']\n} as const;\n\nexport type ButtonPropsBase = {\n variant?: ElementOf<(typeof buttonVariants)['variants']>;\n color?: ElementOf<(typeof buttonVariants)['colors']>;\n size?: ElementOf<(typeof buttonVariants)['sizes']>;\n\n disabled?: boolean;\n isSquareIconButton?: boolean;\n isCircleIconButton?: boolean;\n minWidth?: CSSProperties['minWidth'];\n\n leftIcon?: ReactNode;\n rightIcon?: ReactNode;\n uiTestId?: string;\n styleOverrides?: SerializedStyles;\n} & PropsWithChildren<unknown>;\n\nexport type ButtonProps = ButtonPropsBase & ButtonHTMLAttributes<HTMLButtonElement>;\n\nexport const Button = ({ children, leftIcon, rightIcon, uiTestId, disabled, ...props }: ButtonProps) => {\n return (\n <StyledButton\n type='button'\n // `aria-disabled` (not the native attribute) keeps the button focusable and\n // lets `cursor: not-allowed` show — browsers suppress custom cursors on a\n // natively-disabled control. Activation is guarded in the onClick below.\n aria-disabled={disabled || undefined}\n {...props}\n {...(uiTestId ? { 'data-testid': uiTestId } : {})}\n onClick={\n props.onClick && !disabled\n ? e => {\n // Stops propagation so the button is safe inside clickable rows/cards.\n e.stopPropagation();\n e.preventDefault();\n props.onClick?.(e);\n return false;\n }\n : undefined\n }>\n {leftIcon}\n {children}\n {rightIcon}\n </StyledButton>\n );\n};\n\nexport type IconButtonProps = Omit<ButtonProps, 'children' | 'leftIcon' | 'rightIcon' | 'size'> & {\n icon: SvgAsset;\n size?: number | ButtonPropsBase['size'];\n};\n\nexport const IconButton = ({ icon, size: sizeIn = 'md', ...props }: IconButtonProps) => {\n const size = typeof sizeIn === 'number' ? sizeIn : sizeIn === 'sm' ? 32 : 36;\n return (\n <Button\n {...props}\n size='sm'\n minWidth='auto'\n styleOverrides={css`\n padding: ${size / 4}px;\n width: ${size + 1}px;\n height: ${size + 1}px;\n ${props.styleOverrides}\n `}>\n <Svg asset={icon} size={size / 2} color='currentColor' />\n </Button>\n );\n};\n","import { css } from '@emotion/react';\nimport styled from '@emotion/styled';\nimport type { CSSProperties } from 'react';\nimport { cssProp, dontForwardProps } from '../../_internal/utils';\nimport { Spacer, type SpacerProps } from './Spacer';\n\n// region Component\n\nexport type FlexLayoutProps = SpacerProps & {\n horizontal?: boolean;\n vertical?: boolean;\n gap?: CSSProperties['gap'] | number;\n display?: CSSProperties['display'];\n flexWrap?: CSSProperties['flexWrap'];\n justifyContent?: CSSProperties['justifyContent'];\n alignItems?: CSSProperties['alignItems'];\n alignContent?: CSSProperties['alignContent'];\n flexDirection?: CSSProperties['flexDirection'];\n overflow?: CSSProperties['overflow'];\n column?: boolean;\n row?: boolean;\n nowrap?: boolean;\n expandChildren?: boolean;\n};\n\n/**\n * Quick horizontal, vertical, or centered (horizontal & vertical) flex layout.\n * A numeric `gap` is treated as a 0.25em scale step (e.g. `gap={3}` → `0.75em`).\n */\nexport const FlexLayout = styled(\n Spacer,\n dontForwardProps(\n 'horizontal',\n 'vertical',\n 'gap',\n 'display',\n 'flexWrap',\n 'justifyContent',\n 'alignItems',\n 'alignContent',\n 'flexDirection',\n 'overflow',\n 'column',\n 'row',\n 'nowrap',\n 'expandChildren'\n )\n)<FlexLayoutProps>(({\n horizontal,\n vertical,\n gap,\n display,\n flexWrap,\n nowrap,\n justifyContent,\n alignItems,\n alignContent,\n flexDirection,\n column,\n row,\n maxWidth,\n minWidth,\n maxHeight,\n expandChildren,\n overflow\n}) => {\n if (typeof gap === 'number') gap = gap * 0.25 + 'em';\n return css`\n display: flex;\n ${cssProp('justify-content', justifyContent ? justifyContent : horizontal ? 'center' : undefined)}\n ${cssProp('align-items', alignItems ? alignItems : vertical ? 'center' : undefined)}\n ${cssProp('align-content', alignContent ? alignContent : vertical ? 'center' : undefined)}\n ${cssProp('flex-direction', flexDirection ? flexDirection : column ? 'column' : row ? 'row' : undefined)}\n ${cssProp('gap', gap)}\n ${cssProp('display', display)}\n ${cssProp('flex-wrap', flexWrap ? flexWrap : nowrap ? 'nowrap' : 'wrap')}\n ${cssProp('overflow', overflow)}\n max-width: ${maxWidth ?? '100%'};\n ${minWidth\n ? css`\n min-width: ${minWidth};\n `\n : ''}\n max-height: ${maxHeight ?? '100%'};\n ${expandChildren &&\n css`\n > * {\n flex-grow: 1;\n width: auto;\n }\n `}\n `;\n});\n\n/** Adds a `flex-grow: 1` filler into a flex layout. */\nexport const FlexLayoutSpacer = styled.div<{ flexBasis?: CSSProperties['flexBasis'] }>(\n ({ flexBasis }) => css`\n flex-grow: 1;\n ${cssProp('flex-basis', flexBasis)}\n `\n);\n","import { createContext, useContext, useState, type ReactNode } from 'react';\n\n// region Helpers\n\nconst VIM_MODE_STORAGE_KEY = 'monaco-editor-vim-mode';\nconst WORD_WRAP_STORAGE_KEY = 'monaco-editor-word-wrap';\n\nexport interface EditorSettings {\n vimEnabled: boolean;\n toggleVimMode: () => void;\n wordWrapEnabled: boolean;\n toggleWordWrap: () => void;\n}\n\nconst EditorSettingsContext = createContext<EditorSettings | undefined>(undefined);\n\n// region Component\n\n/**\n * Provides per-user editor preferences (vim mode, word wrap), persisted to\n * `localStorage`. Wrap any tree that renders `<MonacoEditorWithSettings />`.\n */\nexport function EditorSettingsProvider({ children }: { children: ReactNode }) {\n const [vimEnabled, setVimEnabled] = useState(() => {\n const saved = localStorage.getItem(VIM_MODE_STORAGE_KEY);\n return saved === 'true';\n });\n\n const [wordWrapEnabled, setWordWrapEnabled] = useState(() => {\n const saved = localStorage.getItem(WORD_WRAP_STORAGE_KEY);\n return saved === 'true';\n });\n\n const toggleVimMode = () => {\n setVimEnabled(prev => {\n const newValue = !prev;\n localStorage.setItem(VIM_MODE_STORAGE_KEY, String(newValue));\n return newValue;\n });\n };\n\n const toggleWordWrap = () => {\n setWordWrapEnabled(prev => {\n const newValue = !prev;\n localStorage.setItem(WORD_WRAP_STORAGE_KEY, String(newValue));\n return newValue;\n });\n };\n\n return (\n <EditorSettingsContext.Provider value={{ vimEnabled, toggleVimMode, wordWrapEnabled, toggleWordWrap }}>\n {children}\n </EditorSettingsContext.Provider>\n );\n}\n\nexport function useEditorSettings() {\n const context = useContext(EditorSettingsContext);\n if (context === undefined) {\n throw new Error('useEditorSettings must be used within EditorSettingsProvider');\n }\n return context;\n}\n","import type { SerializedStyles } from '@emotion/react';\nimport styled from '@emotion/styled';\nimport { Editor, type OnMount } from '@monaco-editor/react';\nimport { Dropdown, Tooltip, type MenuProps } from 'antd';\nimport { Copy, Settings } from 'lucide-react';\nimport type * as monacoEditor from 'monaco-editor';\nimport { initVimMode, type VimMode, VimMode as VimModeClass } from 'monaco-vim';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport toast from 'react-hot-toast';\nimport { useEditorSettings } from './EditorSettingsContext';\nimport { useSoloMode, type SoloMode } from '../../providers/SoloModeContext';\n\n// region Styles\n\n// The component reads its palette from CSS custom properties so consumers can\n// theme it, but ships dark-theme fallbacks so it looks right with no theming.\nconst EditorContainer = styled.div<{ height: string; mode: SoloMode; styleOverrides?: SerializedStyles }>`\n /* Include the 1px border in the 100% width/height so the container never spills\n past a tight parent (e.g. an antd Drawer body), which would show scrollbars. */\n box-sizing: border-box;\n position: relative;\n width: 100%;\n height: ${props => props.height};\n display: flex;\n flex-direction: column;\n background: transparent;\n border-radius: 6px;\n overflow: hidden;\n /* Light gets a clearer border + a soft card shadow so the editor reads as an\n elevated surface on a white page; dark keeps a subtle themed frame. */\n ${props =>\n props.mode === 'light'\n ? `\n border: 1px solid #cdd1d8;\n box-shadow: 0 1px 2px rgba(16, 24, 40, 0.06), 0 6px 16px rgba(16, 24, 40, 0.06);\n `\n : `border: 1px solid var(--color-border-base, #3f3f46);`}\n ${props => props.styleOverrides}\n`;\n\nconst EditorWrapper = styled.div`\n flex: 1;\n position: relative;\n min-height: 0;\n background: transparent;\n`;\n\n// Top-right control bar holding the (read-only) copy button and the settings gear.\n// Shifts left by `offsetRight` so it clears the editor's vertical scrollbar.\nconst ControlsBar = styled.div<{ offsetRight: number }>`\n position: absolute;\n top: 8px;\n right: ${props => props.offsetRight}px;\n z-index: 10;\n display: flex;\n gap: 6px;\n transition: right 0.15s ease;\n`;\n\nconst IconActionButton = styled.button`\n background: var(--color-bg-elevated, #1e1e22);\n border: 1px solid var(--color-border-base, #3f3f46);\n border-radius: 3px;\n padding: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.08s ease;\n\n &:hover {\n background: var(--color-bg-hover, #282035);\n border-color: var(--color-primary, #8134e2);\n }\n\n /* Active is a clearly distinct step from hover (deeper fill + press shift). */\n &:active {\n background: var(--color-bg-active, #352b48);\n border-color: var(--color-primary, #8134e2);\n transform: translateY(1px);\n }\n\n &:focus-visible {\n outline: 2px solid var(--color-primary, #8134e2);\n outline-offset: 2px;\n }\n\n svg {\n width: 16px;\n height: 16px;\n color: var(--color-text-primary, #fafafa);\n }\n`;\n\nconst VimStatusBar = styled.div`\n padding: 4px 8px;\n background: var(--color-bg-elevated, #1e1e22);\n border-top: 1px solid var(--color-border-base, #3f3f46);\n font-family: monospace;\n font-size: 12px;\n min-height: 24px;\n`;\n\n// region Component\n\nexport interface MonacoEditorWithSettingsProps {\n value: string;\n onChange?: (value: string | undefined) => void;\n language: string;\n height?: string;\n /** Defaults to the active `SoloContextProvider` mode when omitted. */\n theme?: 'light' | 'dark';\n options?: monacoEditor.editor.IStandaloneEditorConstructionOptions;\n onMount?: OnMount;\n readOnly?: boolean;\n downloadFileName?: string;\n onSave?: () => void;\n onQuit?: () => void;\n /** Emotion styles appended to the outer container. */\n styleOverrides?: SerializedStyles;\n}\n\nexport function MonacoEditorWithSettings({\n value,\n onChange,\n language,\n height = '100%',\n theme,\n options = {},\n onMount,\n readOnly = false,\n downloadFileName,\n onSave,\n onQuit,\n styleOverrides,\n}: MonacoEditorWithSettingsProps) {\n const { vimEnabled, toggleVimMode, wordWrapEnabled, toggleWordWrap } = useEditorSettings();\n // Vim is suppressed in read-only mode, regardless of the user's saved setting.\n const vimActive = vimEnabled && !readOnly;\n // Fall back to the provider's light/dark mode when no explicit theme is given.\n const soloMode = useSoloMode();\n const resolvedTheme = theme ?? soloMode;\n const editorRef = useRef<monacoEditor.editor.IStandaloneCodeEditor | null>(null);\n const vimModeRef = useRef<VimMode | null>(null);\n const statusNodeRef = useRef<HTMLDivElement | null>(null);\n const onSaveRef = useRef(onSave);\n const onQuitRef = useRef(onQuit);\n const disposablesRef = useRef<monacoEditor.IDisposable[]>([]);\n // Width of the vertical scrollbar when it's visible; the controls shift left by this.\n const [scrollbarWidth, setScrollbarWidth] = useState(0);\n\n // Keep onSave and onQuit refs up to date\n useEffect(() => {\n onSaveRef.current = onSave;\n }, [onSave]);\n\n useEffect(() => {\n onQuitRef.current = onQuit;\n }, [onQuit]);\n\n // Enable/disable vim mode for this editor instance\n useEffect(() => {\n if (!editorRef.current) return;\n\n if (vimActive) {\n // Enable vim mode\n if (!vimModeRef.current && statusNodeRef.current) {\n vimModeRef.current = initVimMode(editorRef.current, statusNodeRef.current);\n\n // Set up vim save and quit commands using VimMode.Vim\n setTimeout(() => {\n try {\n const Vim = (VimModeClass as any).Vim;\n if (Vim && Vim.defineEx) {\n if (onSaveRef.current) {\n Vim.defineEx('write', 'w', () => {\n onSaveRef.current?.();\n });\n }\n if (onQuitRef.current) {\n Vim.defineEx('quit', 'q', () => {\n onQuitRef.current?.();\n });\n }\n if (onSaveRef.current && onQuitRef.current) {\n Vim.defineEx('wq', 'wq', () => {\n onSaveRef.current?.();\n onQuitRef.current?.();\n });\n }\n }\n } catch (e) {\n console.error('Failed to setup vim commands:', e);\n }\n }, 100);\n }\n } else {\n // Disable vim mode\n if (vimModeRef.current) {\n vimModeRef.current.dispose();\n vimModeRef.current = null;\n }\n }\n }, [vimActive]);\n\n const handleEditorMount: OnMount = useCallback(\n (editor, monaco) => {\n editorRef.current = editor;\n\n // Track the vertical scrollbar so the top-right controls can clear it.\n const syncScrollbar = () => {\n const layout = editor.getLayoutInfo();\n const hasVerticalScrollbar = editor.getScrollHeight() > layout.height;\n setScrollbarWidth(hasVerticalScrollbar ? layout.verticalScrollbarWidth : 0);\n };\n syncScrollbar();\n disposablesRef.current.push(\n editor.onDidContentSizeChange(syncScrollbar),\n editor.onDidLayoutChange(syncScrollbar)\n );\n\n // Add keyboard shortcut for save (Cmd+S / Ctrl+S)\n if (onSaveRef.current) {\n editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => {\n onSaveRef.current?.();\n });\n }\n\n // Initialize vim mode if enabled (never in read-only mode)\n if (vimActive && statusNodeRef.current && !vimModeRef.current) {\n vimModeRef.current = initVimMode(editor, statusNodeRef.current);\n\n // Set up vim save and quit commands using VimMode.Vim\n setTimeout(() => {\n try {\n const Vim = (VimModeClass as any).Vim;\n if (Vim && Vim.defineEx) {\n if (onSaveRef.current) {\n Vim.defineEx('write', 'w', () => {\n onSaveRef.current?.();\n });\n }\n if (onQuitRef.current) {\n Vim.defineEx('quit', 'q', () => {\n onQuitRef.current?.();\n });\n }\n if (onSaveRef.current && onQuitRef.current) {\n Vim.defineEx('wq', 'wq', () => {\n onSaveRef.current?.();\n onQuitRef.current?.();\n });\n }\n }\n } catch (e) {\n console.error('Failed to setup vim commands:', e);\n }\n }, 100);\n }\n\n // Call custom onMount if provided\n if (onMount) {\n onMount(editor, monaco);\n }\n },\n [onMount, vimActive]\n );\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n vimModeRef.current?.dispose();\n disposablesRef.current.forEach(d => d.dispose());\n };\n }, []);\n\n const handleCopy = useCallback(async () => {\n // Read the live editor content, not the (possibly stale) `value` prop.\n const text = editorRef.current?.getValue() ?? value;\n try {\n await navigator.clipboard.writeText(text);\n toast.success('Copied to clipboard');\n } catch {\n toast.error('Failed to copy to clipboard');\n }\n }, [value]);\n\n const handleDownload = useCallback(() => {\n const text = editorRef.current?.getValue() ?? value;\n try {\n const blob = new Blob([text], { type: 'text/plain' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n\n // Determine file extension from language\n let extension = 'txt';\n if (language === 'json') extension = 'json';\n else if (language === 'yaml' || language === 'yml') extension = 'yaml';\n else if (language === 'javascript' || language === 'typescript')\n extension = language === 'typescript' ? 'ts' : 'js';\n else if (language === 'html') extension = 'html';\n else if (language === 'css') extension = 'css';\n\n a.download = downloadFileName || `content.${extension}`;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n URL.revokeObjectURL(url);\n toast.success('Downloaded successfully');\n } catch {\n toast.error('Failed to download file');\n }\n }, [value, language, downloadFileName]);\n\n const menuItems: MenuProps['items'] = [\n // Copy lives in its own always-visible button (left of the gear), not the menu.\n {\n key: 'download',\n label: 'Download',\n onClick: handleDownload,\n },\n {\n type: 'divider',\n },\n // Vim mode is meaningless when read-only, so omit the toggle there.\n !readOnly && {\n key: 'vim',\n label: vimEnabled ? 'Disable Vim Mode' : 'Enable Vim Mode',\n onClick: toggleVimMode,\n },\n {\n key: 'wordwrap',\n label: wordWrapEnabled ? 'Disable Word Wrap' : 'Enable Word Wrap',\n onClick: toggleWordWrap,\n },\n ].filter(Boolean) as MenuProps['items'];\n\n return (\n <EditorContainer height={height} mode={resolvedTheme} styleOverrides={styleOverrides}>\n <EditorWrapper>\n <ControlsBar offsetRight={8 + scrollbarWidth}>\n <Tooltip title='Copy to clipboard'>\n <IconActionButton type='button' aria-label='Copy to clipboard' onClick={handleCopy}>\n <Copy />\n </IconActionButton>\n </Tooltip>\n <Dropdown menu={{ items: menuItems }} placement='bottomRight' trigger={['click']}>\n <Tooltip title='More options'>\n <IconActionButton type='button' aria-label='Editor settings'>\n <Settings />\n </IconActionButton>\n </Tooltip>\n </Dropdown>\n </ControlsBar>\n <Editor\n height='100%'\n language={language}\n value={value}\n onChange={onChange}\n theme={resolvedTheme === 'dark' ? 'vs-dark' : 'vs'}\n onMount={handleEditorMount}\n options={{\n // Keep Monaco fitted to its container as it resizes (e.g. a drawer\n // opening) so it never ends up shorter than its box.\n automaticLayout: true,\n ...options,\n readOnly,\n wordWrap: wordWrapEnabled ? 'on' : 'off',\n }}\n />\n </EditorWrapper>\n {vimActive && <VimStatusBar ref={statusNodeRef as any} className='monaco-vim-status' />}\n </EditorContainer>\n );\n}\n","import { css, Global, ThemeProvider, type Theme } from '@emotion/react';\nimport type { ReactNode } from 'react';\nimport { Toaster, type ToasterProps } from 'react-hot-toast';\n// Import the context directly (not the MonacoEditor barrel) so this provider\n// never pulls the editor's heavy optional deps (antd / monaco) into apps that\n// only use it for theming + toasts.\nimport { EditorSettingsProvider } from '../components/MonacoEditor/EditorSettingsContext';\nimport { SoloModeProvider, type SoloMode } from './SoloModeContext';\n\n// region Helpers\n\n/** Theme tokens the library — and the Monaco editor chrome — read from. */\nexport interface SoloTheme {\n mode: SoloMode;\n fontFamily: string;\n colors: {\n background: string;\n bgElevated: string;\n bgHover: string;\n /** Pressed/active surface — a clearly distinct step from `bgHover`. */\n bgActive: string;\n borderBase: string;\n primary: string;\n textPrimary: string;\n textSecondary: string;\n };\n}\n\nconst FONT_FAMILY = \"'Figtree', ui-sans-serif, system-ui, sans-serif\";\n\n// Light and dark palettes. The editor chrome and components read these via the\n// `--color-*` CSS variables the provider injects.\n// Purple-core: neutrals are tinted toward the brand violet (#8134e2, hue ~267) so\n// purple reads as the system. `bgHover` → `bgActive` is a clear, deliberate step.\nconst palettes: Record<SoloMode, SoloTheme['colors']> = {\n dark: {\n background: '#0f0b18',\n bgElevated: '#1b1624',\n bgHover: '#282035',\n bgActive: '#352b48',\n borderBase: '#3d344d',\n primary: '#8134e2',\n textPrimary: '#f6f4fb',\n textSecondary: '#a6a0b8'\n },\n light: {\n background: '#ffffff',\n bgElevated: '#f6f3fb',\n bgHover: '#ece7f5',\n bgActive: '#ddd3ee',\n borderBase: '#ded7ec',\n primary: '#8134e2',\n textPrimary: '#1a1623',\n textSecondary: '#585465'\n }\n};\n\n/** Default Solo theme (dark). */\nexport const defaultSoloTheme: SoloTheme = { mode: 'dark', fontFamily: FONT_FAMILY, colors: palettes.dark };\n\n/** Theme overrides — non-recursive (one level of `colors`) to keep types cheap. */\nexport interface SoloThemeOverride {\n fontFamily?: string;\n colors?: Partial<SoloTheme['colors']>;\n}\n\n/** Toggle which providers `SoloContextProvider` sets up. Each defaults to `true`. */\nexport interface SoloFeatures {\n /** emotion `ThemeProvider`, the `--color-*` CSS variables, and the web fonts. */\n theme?: boolean;\n /** react-hot-toast `<Toaster />`. */\n toaster?: boolean;\n}\n\n/** Fully typed customization for the enabled features. */\nexport interface SoloConfig {\n /** Theme overrides, merged over the mode palette and any outer `ThemeProvider`. */\n theme?: SoloThemeOverride;\n /** Props for the bundled react-hot-toast `<Toaster />`. */\n toaster?: ToasterProps;\n}\n\n// Loads Figtree (UI), DM Sans, and DM Mono. Kept first in the injected sheet so\n// the @import stays valid.\nconst FONT_IMPORT =\n \"@import url('https://fonts.googleapis.com/css2?family=Figtree:wght@300;400;500;600;700;800&family=DM+Sans:wght@300;400;500;600;700&family=DM+Mono:wght@300;400;500&display=swap');\";\n\n// Non-destructive merge: start from the mode palette, keep outer emotion theme\n// keys, then apply the caller's overrides.\nconst mergeTheme = (mode: SoloMode, outer: Theme | undefined, overrides?: SoloThemeOverride): SoloTheme => {\n const outerOverride = (outer ?? {}) as SoloThemeOverride;\n return {\n ...(outer as object),\n mode,\n fontFamily: overrides?.fontFamily ?? outerOverride.fontFamily ?? FONT_FAMILY,\n colors: {\n ...palettes[mode],\n ...(outerOverride.colors ?? {}),\n ...(overrides?.colors ?? {})\n }\n };\n};\n\nconst globalStyles = (theme: SoloTheme) => css`\n ${FONT_IMPORT}\n\n :root {\n --solo-font-family: ${theme.fontFamily};\n --color-background: ${theme.colors.background};\n --color-bg-elevated: ${theme.colors.bgElevated};\n --color-bg-hover: ${theme.colors.bgHover};\n --color-bg-active: ${theme.colors.bgActive};\n --color-border-base: ${theme.colors.borderBase};\n --color-primary: ${theme.colors.primary};\n --color-text-primary: ${theme.colors.textPrimary};\n --color-text-secondary: ${theme.colors.textSecondary};\n }\n\n body {\n font-family: ${theme.fontFamily};\n }\n\n @keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n }\n`;\n\n// region Component\n\n/**\n * Wraps children in the emotion theme + CSS variables + web fonts, or passes\n * them through untouched when theming is off. Isolating this keeps\n * `SoloContextProvider` a flat, declarative tree instead of branching inline.\n */\nfunction ThemeLayer({\n enabled,\n mode,\n overrides,\n children\n}: {\n enabled: boolean;\n mode: SoloMode;\n overrides?: SoloThemeOverride;\n children: ReactNode;\n}) {\n if (!enabled) return <>{children}</>;\n\n const theme = mergeTheme(mode, undefined, overrides);\n return (\n <ThemeProvider theme={outer => mergeTheme(mode, outer, overrides)}>\n <Global styles={globalStyles(theme)} />\n {children}\n </ThemeProvider>\n );\n}\n\nexport interface SoloContextProviderProps {\n children: ReactNode;\n /** Light or dark color mode. Drives the palette and the editor's default theme. Defaults to `'dark'`. */\n mode?: SoloMode;\n /** Toggle which providers are set up. Each feature defaults to on. */\n features?: SoloFeatures;\n /** Fully typed customization for the enabled features. */\n config?: SoloConfig;\n}\n\n/**\n * Single top-level provider for apps consuming this library. Composes the\n * color mode + emotion theme (web fonts + the `--color-*` CSS variables the\n * editor chrome reads), editor settings, and a react-hot-toast `<Toaster />` —\n * so the library's components work as drop-ins.\n *\n * Opinionated by default (closed to modification), open to extension: pick\n * `mode`, toggle pieces with `features`, and customize them with `config`.\n *\n * The body reads top-down as the provider tree it renders:\n * mode → theme → editor settings → toaster → your app.\n */\nexport function SoloContextProvider({ children, mode = 'dark', features, config }: SoloContextProviderProps) {\n const themeEnabled = features?.theme !== false;\n const toasterEnabled = features?.toaster !== false;\n\n return (\n <SoloModeProvider value={mode}>\n <ThemeLayer enabled={themeEnabled} mode={mode} overrides={config?.theme}>\n <EditorSettingsProvider>\n {toasterEnabled && (\n <Toaster\n {...config?.toaster}\n position={config?.toaster?.position ?? 'bottom-right'}\n toastOptions={{\n ...config?.toaster?.toastOptions,\n // Themed via CSS variables so toasts match light/dark automatically.\n style: {\n background: 'var(--color-bg-elevated, #1e1e22)',\n color: 'var(--color-text-primary, #fafafa)',\n border: '1px solid var(--color-border-base, #3f3f46)',\n ...config?.toaster?.toastOptions?.style\n }\n }}\n />\n )}\n {children}\n </EditorSettingsProvider>\n </ThemeLayer>\n </SoloModeProvider>\n );\n}\n"],"names":["SoloModeContext","createContext","SoloModeProvider","Provider","useSoloMode","useContext","StyledCloseButton","process","env","NODE_ENV","_extends","target","dontForwardProps","label","props","styleOverrides","CloseButton","size","type","ariaLabel","jsx","X","Spacer","mx","my","mr","ml","mt","mb","margin","px","py","pl","pr","pt","pb","padding","marginRight","marginLeft","marginTop","marginBottom","paddingRight","paddingLeft","paddingTop","paddingBottom","cssProp","display","position","minHeight","minWidth","height","width","maxHeight","maxWidth","flexGrow","flexShrink","flexBasis","overflowY","overflowX","overflow","textOverflow","zIndex","fadeIn","stylingOverrides","styles","truncated","Text","weight","lineHeight","color","textAlign","whiteSpace","truncate","wordBreak","textTransform","fontStyle","inline","Container","frame","background","shadow","IconSlot","accent","Body","_styled","name","toString","_EMOTION_STRINGIFIED_CSS_ERROR__","typeConfig","info","Icon","Info","darkAccent","lightAccent","success","CircleCheck","warning","TriangleAlert","danger","OctagonAlert","Alert","title","children","isDismissable","onDismiss","tokens","soloColorTokens","mode","dismissed","setDismissed","useState","lightBase","bg","tintBase","iconColor","borderColor","titleColor","messageColor","handleDismiss","v","undefined","SvgContainer","svgColor","css","Svg","asset","Asset","buttonSvg","buttonVariants","variants","colors","sizes","Button","leftIcon","rightIcon","uiTestId","disabled","jsxs","StyledButton","onClick","e","stopPropagation","preventDefault","IconButton","icon","sizeIn","_ref","FlexLayout","horizontal","vertical","gap","flexWrap","nowrap","justifyContent","alignItems","alignContent","flexDirection","column","row","expandChildren","FlexLayoutSpacer","VIM_MODE_STORAGE_KEY","WORD_WRAP_STORAGE_KEY","EditorSettingsContext","EditorSettingsProvider","vimEnabled","setVimEnabled","localStorage","getItem","wordWrapEnabled","setWordWrapEnabled","toggleVimMode","prev","newValue","setItem","String","toggleWordWrap","useEditorSettings","context","Error","EditorContainer","EditorWrapper","ControlsBar","offsetRight","IconActionButton","VimStatusBar","MonacoEditorWithSettings","value","onChange","language","theme","options","onMount","readOnly","downloadFileName","onSave","onQuit","vimActive","soloMode","resolvedTheme","editorRef","useRef","vimModeRef","statusNodeRef","onSaveRef","onQuitRef","disposablesRef","scrollbarWidth","setScrollbarWidth","useEffect","current","initVimMode","setTimeout","Vim","VimModeClass","defineEx","console","error","dispose","handleEditorMount","useCallback","editor","monaco","syncScrollbar","layout","getLayoutInfo","hasVerticalScrollbar","getScrollHeight","verticalScrollbarWidth","push","onDidContentSizeChange","onDidLayoutChange","addCommand","KeyMod","CtrlCmd","KeyCode","KeyS","forEach","d","handleCopy","text","getValue","navigator","clipboard","writeText","toast","menuItems","key","blob","Blob","url","URL","createObjectURL","a","document","createElement","href","extension","download","body","appendChild","click","removeChild","revokeObjectURL","handleDownload","filter","Boolean","Tooltip","Copy","Dropdown","items","Settings","Editor","automaticLayout","wordWrap","FONT_FAMILY","palettes","dark","bgElevated","bgHover","bgActive","borderBase","primary","textPrimary","textSecondary","light","defaultSoloTheme","fontFamily","FONT_IMPORT","mergeTheme","outer","overrides","outerOverride","globalStyles","ThemeLayer","enabled","Fragment","ThemeProvider","Global","SoloContextProvider","features","config","themeEnabled","toasterEnabled","toaster","Toaster","toastOptions","style","border"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./Button.style-CI6Xbod7.cjs");Object.defineProperty(exports,"SoloButtonStyles",{enumerable:!0,get:()=>e.SoloButtonStyles});
2
+ //# sourceMappingURL=styles.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ export { SoloButtonStyles } from './components/Button/Button.style';
package/dist/styles.js ADDED
@@ -0,0 +1,5 @@
1
+ import { S } from "./Button.style-CCplEN2o.js";
2
+ export {
3
+ S as SoloButtonStyles
4
+ };
5
+ //# sourceMappingURL=styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
package/package.json ADDED
@@ -0,0 +1,109 @@
1
+ {
2
+ "name": "@solo-io-public/ui-components",
3
+ "version": "0.0.0",
4
+ "description": "Open-source React component library for Solo.io projects",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "packageManager": "yarn@4.9.0",
8
+ "engines": {
9
+ "node": ">= 24.8.0"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/solo-io/ui-components-oss.git"
14
+ },
15
+ "publishConfig": {
16
+ "registry": "https://registry.npmjs.org",
17
+ "access": "public"
18
+ },
19
+ "main": "./dist/solo-components.cjs",
20
+ "module": "./dist/solo-components.js",
21
+ "types": "./dist/index.d.ts",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/solo-components.js",
26
+ "require": "./dist/solo-components.cjs"
27
+ },
28
+ "./styles": {
29
+ "types": "./dist/styles.d.ts",
30
+ "import": "./dist/styles.js",
31
+ "require": "./dist/styles.cjs"
32
+ }
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "src",
37
+ "README.md",
38
+ "LICENSE"
39
+ ],
40
+ "sideEffects": false,
41
+ "scripts": {
42
+ "build": "tsc -p tsconfig.build.json && vite build --config vite.lib.config.ts",
43
+ "dev": "vite build --watch",
44
+ "lint": "tsc -p tsconfig.json --noEmit",
45
+ "test": "vitest run",
46
+ "test:watch": "vitest",
47
+ "storybook": "storybook dev -p 6006",
48
+ "build-storybook": "storybook build -o storybook-static"
49
+ },
50
+ "dependencies": {
51
+ "react-hot-toast": "^2.4.1"
52
+ },
53
+ "peerDependencies": {
54
+ "@emotion/react": "^11.0.0",
55
+ "@emotion/styled": "^11.0.0",
56
+ "@monaco-editor/react": "^4.0.0",
57
+ "antd": "^5.0.0",
58
+ "lucide-react": ">=0.400.0",
59
+ "monaco-editor": ">=0.40.0",
60
+ "monaco-vim": "^0.4.0",
61
+ "react": ">=18.0.0",
62
+ "react-dom": ">=18.0.0"
63
+ },
64
+ "peerDependenciesMeta": {
65
+ "@monaco-editor/react": {
66
+ "optional": true
67
+ },
68
+ "antd": {
69
+ "optional": true
70
+ },
71
+ "lucide-react": {
72
+ "optional": true
73
+ },
74
+ "monaco-editor": {
75
+ "optional": true
76
+ },
77
+ "monaco-vim": {
78
+ "optional": true
79
+ }
80
+ },
81
+ "devDependencies": {
82
+ "@emotion/react": "^11.14.0",
83
+ "@emotion/styled": "^11.14.0",
84
+ "@monaco-editor/react": "^4.7.0",
85
+ "@storybook/addon-essentials": "^8.6.0",
86
+ "@storybook/react": "^8.6.0",
87
+ "@storybook/react-vite": "^8.6.0",
88
+ "@testing-library/dom": "^10.4.1",
89
+ "@testing-library/jest-dom": "^6.6.3",
90
+ "@testing-library/react": "^16.3.0",
91
+ "@testing-library/user-event": "^14.6.1",
92
+ "@types/node": "^22.10.0",
93
+ "@types/react": "^19.0.0",
94
+ "@types/react-dom": "^19.0.0",
95
+ "@vitejs/plugin-react": "^4.3.4",
96
+ "antd": "^5.23.3",
97
+ "happy-dom": "^15.11.7",
98
+ "lucide-react": "^0.562.0",
99
+ "monaco-editor": "^0.55.1",
100
+ "monaco-vim": "^0.4.4",
101
+ "react": "^19.1.0",
102
+ "react-dom": "^19.1.0",
103
+ "storybook": "^8.6.0",
104
+ "typescript": "^5.7.0",
105
+ "vite": "^6.0.0",
106
+ "vite-plugin-dts": "^4.4.0",
107
+ "vitest": "^2.1.8"
108
+ }
109
+ }
@@ -0,0 +1,58 @@
1
+ import { css } from '@emotion/react';
2
+ import styled from '@emotion/styled';
3
+ import type { FunctionComponent, SVGProps } from 'react';
4
+ import { dontForwardProps } from './utils';
5
+
6
+ export type SvgAsset = FunctionComponent<SVGProps<SVGSVGElement> & { title?: string }>;
7
+
8
+ export type SvgSize = number | string;
9
+
10
+ type SvgContainerProps = {
11
+ svgColor?: string;
12
+ inline?: boolean;
13
+ width?: SvgSize;
14
+ height?: SvgSize;
15
+ };
16
+
17
+ const px = (v: SvgSize | undefined) =>
18
+ v === undefined ? undefined : typeof v === 'number' ? `${v}px` : v;
19
+
20
+ const SvgContainer = styled(
21
+ 'span',
22
+ dontForwardProps('svgColor', 'inline', 'width', 'height')
23
+ )<SvgContainerProps>(
24
+ ({ svgColor, inline, width, height }) => css`
25
+ display: ${inline ? 'inline-flex' : 'flex'};
26
+ align-items: center;
27
+ justify-items: center;
28
+ ${svgColor ? `color: ${svgColor};` : ''}
29
+
30
+ svg {
31
+ ${width !== undefined ? `width: ${px(width)};` : ''}
32
+ ${height !== undefined ? `height: ${px(height)};` : ''}
33
+ ${svgColor
34
+ ? `&:not([fill]), &[fill]:not([fill='none'], [fill='transparent']) { fill: ${svgColor}; }
35
+ *[fill]:not([fill='none'], [fill='transparent']) { fill: ${svgColor}; }
36
+ *[stroke]:not([stroke='none'], [stroke='transparent']) { stroke: ${svgColor}; }`
37
+ : ''}
38
+ }
39
+ `
40
+ );
41
+
42
+ export type SvgProps = {
43
+ asset: SvgAsset;
44
+ color?: string;
45
+ width?: SvgSize;
46
+ height?: SvgSize;
47
+ /** Sets both width and height. */
48
+ size?: SvgSize;
49
+ inline?: boolean;
50
+ };
51
+
52
+ export const Svg = ({ asset: Asset, color, size, width = size, height = size, inline }: SvgProps) => {
53
+ return (
54
+ <SvgContainer svgColor={color} width={width} height={height} inline={inline}>
55
+ <Asset />
56
+ </SvgContainer>
57
+ );
58
+ };
@@ -0,0 +1,26 @@
1
+ import { hexAddAlpha } from './hexAddAlpha';
2
+
3
+ const blue500 = '#3B82F6';
4
+ const blue600 = '#2563EB';
5
+ const blue700 = '#1D4ED8';
6
+
7
+ const zinc50 = '#FAFAFA';
8
+ const zinc700 = '#3F3F46';
9
+
10
+ export const colors = {
11
+ textPrimary: zinc50,
12
+ inputBorder: zinc700,
13
+ red500: '#EF4444',
14
+ red900: '#7F1D1D',
15
+ NEW_background: '#0D0E15',
16
+ NEW_borderMiddleDarkArea: '#0B0C17',
17
+ NEW_grayBorderTopLeft: '#3B3C46',
18
+ NEW_darkPurpleGradient: `linear-gradient(117deg, #8023C3 -23.54%, #1D323A 223.49%)`,
19
+ NEW_darkPurpleGradientHover: `linear-gradient(117deg, #9448CAFF -23.54%, #1D323A 223.49%)`,
20
+ NEW_darkPurpleGradientActive: `linear-gradient(117deg, #A060D1FF -23.54%, #1D323A 223.49%)`,
21
+ NEW_blueGradient: `linear-gradient(117deg, ${blue500} -23.54%, #1D283A 223.49%)`,
22
+ NEW_blueGradientHover: `linear-gradient(117deg, ${blue700} -23.54%, #1D283A 223.49%)`,
23
+ NEW_blueGradientActive: `linear-gradient(117deg, ${blue600} -23.54%, #1D283A 223.49%)`
24
+ } as const;
25
+
26
+ export { hexAddAlpha };
@@ -0,0 +1,36 @@
1
+ import { css } from '@emotion/react';
2
+ import type { CSSProperties } from 'react';
3
+
4
+ export type GradientBorderCutoutProps = {
5
+ borderGradient: string;
6
+ borderWidth?: CSSProperties['borderWidth'];
7
+ borderRadius: CSSProperties['borderRadius'];
8
+ };
9
+
10
+ /**
11
+ * Renders a gradient border as a masked cutout pseudo-element so it composites
12
+ * cleanly over semi-transparent backgrounds without bleed-through.
13
+ */
14
+ export function applyGradientBorderCutout({
15
+ borderGradient,
16
+ borderWidth = '1px',
17
+ borderRadius
18
+ }: GradientBorderCutoutProps) {
19
+ return css`
20
+ position: relative;
21
+ border-radius: ${borderRadius};
22
+ &::after {
23
+ content: '';
24
+ pointer-events: none;
25
+ position: absolute;
26
+ inset: 0;
27
+ border-radius: ${borderRadius};
28
+ border: ${borderWidth} solid transparent;
29
+ background: ${borderGradient.trim().replace(/;+$/, '')} border-box;
30
+ mask:
31
+ linear-gradient(#fff 0 0) padding-box,
32
+ linear-gradient(#fff 0 0);
33
+ mask-composite: exclude;
34
+ }
35
+ `;
36
+ }
@@ -0,0 +1,9 @@
1
+ type HEX = `#${string}`;
2
+
3
+ export function hexAddAlpha(hex: HEX, alpha: number): HEX {
4
+ if (alpha < 0 || alpha > 1) throw new Error(`Alpha must be between 0 and 1, got ${alpha}`);
5
+ const a = Math.round(alpha * 255)
6
+ .toString(16)
7
+ .padStart(2, '0');
8
+ return `${hex}${a}` as HEX;
9
+ }
@@ -0,0 +1,46 @@
1
+ import type { SoloMode } from '../providers/SoloModeContext';
2
+
3
+ /** Semantic color names shared across components (buttons today, more later). */
4
+ export type SoloColorName = 'dark-purple' | 'red' | 'warning' | 'success' | 'gray' | 'black' | 'blue';
5
+
6
+ /** A value that can differ by light/dark mode, or be the same for both. */
7
+ export type PerMode<T> = T | { light: T; dark: T };
8
+
9
+ export interface SoloColorTokens {
10
+ /** Solid fill. */
11
+ bg: string;
12
+ /** Solid hover fill. */
13
+ hover: string;
14
+ /** Solid active fill. */
15
+ active: string;
16
+ /** Solid text. */
17
+ fg: string;
18
+ /** Optional solid border, where the fill needs help separating from the page. */
19
+ border?: string;
20
+ /** Outline + text for the bare variant; legible on the dim bg (>=3:1). */
21
+ bareFg: PerMode<string>;
22
+ }
23
+
24
+ /**
25
+ * Semantic palette — the basis for color theming across components. Solid fills
26
+ * use white text; `bareFg` is the outline/text for the bare variant, picked to
27
+ * stay legible (>=3:1) on the dim background in both light and dark modes.
28
+ */
29
+ export const soloColorTokens: Record<SoloColorName, SoloColorTokens> = {
30
+ // Bare dark-purple is brighter on dark, darker on light, so it reads well on both.
31
+ 'dark-purple': { bg: '#8134e2', hover: '#9450e8', active: '#6a24c0', fg: '#ffffff', bareFg: { dark: '#b083f0', light: '#7a2fd0' } },
32
+ blue: { bg: '#2563eb', hover: '#3b82f6', active: '#1d4ed8', fg: '#ffffff', bareFg: '#2563eb' },
33
+ red: { bg: '#a82f25', hover: '#c0392b', active: '#871f17', fg: '#ffffff', bareFg: '#c64f48' },
34
+ // Deep amber, near-complementary to the purple theme.
35
+ warning: { bg: '#b45309', hover: '#d97706', active: '#92400e', fg: '#ffffff', bareFg: '#cf7032' },
36
+ success: { bg: '#15803d', hover: '#16a34a', active: '#166534', fg: '#ffffff', bareFg: '#2f9e5c' },
37
+ // Gray bare is lighter on dark; black bare is darker on light — each pulls away
38
+ // from the dim background it sits on.
39
+ gray: { bg: '#636370', hover: '#71717a', active: '#52525b', fg: '#ffffff', bareFg: { dark: '#a1a1aa', light: '#82828c' } },
40
+ black: { bg: '#27272a', hover: '#37373d', active: '#1c1c1f', fg: '#ffffff', border: '#52525b', bareFg: { dark: '#808086', light: '#3f3f46' } }
41
+ };
42
+
43
+ /** Resolve a possibly per-mode bare color for the active mode. */
44
+ export function resolveBareFg(bareFg: PerMode<string>, mode: SoloMode): string {
45
+ return typeof bareFg === 'string' ? bareFg : bareFg[mode];
46
+ }
@@ -0,0 +1,15 @@
1
+ const spacing = {
2
+ zero: 0,
3
+ xs: 4,
4
+ sm: 6,
5
+ md: 8,
6
+ lg: 12,
7
+ xl: 16
8
+ } as const;
9
+
10
+ type Spacing = typeof spacing;
11
+ type SpacingPx = { [K in keyof Spacing]: `${Spacing[K]}px` };
12
+
13
+ export const spacingPx = Object.fromEntries(
14
+ Object.entries(spacing).map(([k, v]) => [k, `${v}px`])
15
+ ) as SpacingPx;
@@ -0,0 +1,17 @@
1
+ import { css, type SerializedStyles } from '@emotion/react';
2
+ import styled from '@emotion/styled';
3
+
4
+ export const resetButton = css`
5
+ background: unset;
6
+ border: unset;
7
+ padding: unset;
8
+ line-height: unset;
9
+ outline-offset: 1px;
10
+ `;
11
+
12
+ export const UnstyledButton = styled.button<{ stylingOverrides?: SerializedStyles }>(
13
+ ({ stylingOverrides }) => css`
14
+ ${resetButton}
15
+ ${stylingOverrides ? stylingOverrides : ''}
16
+ `
17
+ );
@@ -0,0 +1,11 @@
1
+ /** Helper: emotion `styled` shouldForwardProp blocking the given prop names. */
2
+ export function dontForwardProps(...props: string[]) {
3
+ return { shouldForwardProp: (propName: string) => !props.includes(propName) };
4
+ }
5
+
6
+ export type ElementOf<T> = T extends ReadonlyArray<infer E> ? E : never;
7
+
8
+ /** Emit `prop:value;` when the value is defined, else an empty string. */
9
+ export function cssProp(prop: string, value: string | number | undefined, isImportant = false) {
10
+ return value !== undefined ? `${prop}:${value}${isImportant ? ' !important' : ''};` : '';
11
+ }
@@ -0,0 +1,44 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { Alert, type AlertType } from './Alert';
3
+
4
+ const meta: Meta<typeof Alert> = {
5
+ title: 'Common / Alert',
6
+ component: Alert
7
+ };
8
+ export default meta;
9
+
10
+ type Story = StoryObj<typeof Alert>;
11
+
12
+ const samples: { type: AlertType; title: string; msg: string }[] = [
13
+ { type: 'info', title: 'Info', msg: 'Your changes have been saved as a draft.' },
14
+ { type: 'success', title: 'Success', msg: 'The deployment completed successfully.' },
15
+ { type: 'warning', title: 'Warning', msg: 'This action may take a few minutes to finish.' },
16
+ { type: 'danger', title: 'Danger', msg: 'This will permanently delete the resource.' }
17
+ ];
18
+
19
+ const Stack = () => (
20
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 20, maxWidth: 460 }}>
21
+ {samples.map(s => (
22
+ <Alert key={s.type} type={s.type} title={s.title}>
23
+ {s.msg}
24
+ </Alert>
25
+ ))}
26
+ </div>
27
+ );
28
+
29
+ export const AllTypes: Story = {
30
+ render: () => <Stack />
31
+ };
32
+
33
+ export const Dismissable: Story = {
34
+ render: () => (
35
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 20, maxWidth: 460 }}>
36
+ <Alert type='info' title='Dismissable' isDismissable>
37
+ Click the × in the corner to hide this alert.
38
+ </Alert>
39
+ <Alert type='success' title='With callback' isDismissable onDismiss={() => console.log('dismissed')}>
40
+ Hides itself and fires <code>onDismiss</code>.
41
+ </Alert>
42
+ </div>
43
+ )
44
+ };