/** * The shared style vocabulary (milestone 23, ruling 3; replaces the Tailwind * class constants of milestone 18, ruling 10). * * Every interactive element must carry `focusRing` or `insetFocusRing`; that * is the milestone-9 accessibility floor. Compose at the call site with * `stylex.props(styles.button, extra)` instead of re-spelling a variant. */ import * as stylex from "@stylexjs/stylex"; import { colors } from "./tokens.stylex"; const FOCUS = ":focus-visible"; const DISABLED = ":disabled"; /** The half-fade loop a placeholder runs while its data is in flight. */ const pulseFrames = stylex.keyframes({ "50%": { opacity: 0.5 }, }); export const styles = stylex.create({ /** The ring drawn outside the element. */ focusRing: { outlineWidth: { default: null, [FOCUS]: 2 }, outlineStyle: { default: null, [FOCUS]: "solid" }, outlineColor: { default: null, [FOCUS]: colors.focus }, outlineOffset: { default: null, [FOCUS]: 2 }, }, /** The ring drawn inside the element, for controls flush against a panel edge. */ insetFocusRing: { outlineWidth: { default: null, [FOCUS]: 2 }, outlineStyle: { default: null, [FOCUS]: "solid" }, outlineColor: { default: null, [FOCUS]: colors.focus }, outlineOffset: { default: null, [FOCUS]: -2 }, }, input: { marginTop: "0.25rem", width: "100%", borderRadius: "0.25rem", borderWidth: 1, borderStyle: "solid", borderColor: colors.borderStrong, backgroundColor: colors.surfaceRaised, color: colors.text, paddingInline: "0.75rem", paddingBlock: "0.5rem", }, smallInput: { borderRadius: "0.25rem", borderWidth: 1, borderStyle: "solid", borderColor: colors.borderStrong, backgroundColor: colors.surfaceRaised, color: colors.text, paddingInline: "0.5rem", paddingBlock: "0.375rem", fontSize: "0.875rem", lineHeight: "1.25rem", }, button: { borderRadius: "0.25rem", borderWidth: 1, borderStyle: "solid", borderColor: colors.borderStrong, paddingInline: "0.75rem", paddingBlock: "0.375rem", fontSize: "0.875rem", lineHeight: "1.25rem", }, smallButton: { borderRadius: "0.25rem", borderWidth: 1, borderStyle: "solid", borderColor: colors.borderStrong, paddingInline: "0.5rem", paddingBlock: "0.25rem", fontSize: "0.875rem", lineHeight: "1.25rem", }, largeButton: { borderRadius: "0.25rem", borderWidth: 1, borderStyle: "solid", borderColor: colors.borderStrong, paddingInline: "0.75rem", paddingBlock: "0.5rem", fontWeight: 500, }, primaryButton: { borderRadius: "0.25rem", borderStyle: "none", backgroundColor: colors.primary, color: colors.primaryText, paddingInline: "0.75rem", paddingBlock: "0.375rem", fontSize: "0.875rem", lineHeight: "1.25rem", fontWeight: 500, opacity: { default: 1, [DISABLED]: 0.5 }, }, largePrimaryButton: { borderRadius: "0.25rem", borderStyle: "none", backgroundColor: colors.primary, color: colors.primaryText, paddingInline: "0.75rem", paddingBlock: "0.5rem", fontWeight: 500, opacity: { default: 1, [DISABLED]: 0.5 }, }, rowButton: { borderRadius: "0.25rem", borderStyle: "none", backgroundColor: "transparent", paddingInline: "0.5rem", paddingBlock: "0.25rem", fontSize: "0.875rem", lineHeight: "1.25rem", color: colors.primaryOnSurface, }, linkButton: { borderStyle: "none", backgroundColor: "transparent", padding: 0, fontSize: "0.875rem", lineHeight: "1.25rem", fontWeight: 500, color: colors.primaryOnSurface, }, dangerLinkButton: { borderStyle: "none", backgroundColor: "transparent", padding: 0, fontSize: "0.875rem", lineHeight: "1.25rem", fontWeight: 500, color: colors.danger, opacity: { default: 1, [DISABLED]: 0.5 }, }, retryButton: { marginTop: "0.75rem", borderRadius: "0.25rem", borderWidth: 1, borderStyle: "solid", borderColor: colors.dangerBorder, backgroundColor: "transparent", paddingInline: "0.75rem", paddingBlock: "0.375rem", fontSize: "0.875rem", lineHeight: "1.25rem", fontWeight: 500, color: colors.dangerText, }, /** Marks an element as waiting on data. Carries no colour of its own. */ pulse: { animationName: pulseFrames, animationDuration: "2s", animationTimingFunction: "cubic-bezier(0.4, 0, 0.6, 1)", animationIterationCount: "infinite", }, /** Digits of equal width, so a column of counts does not jitter as it updates. */ tabularNums: { fontVariantNumeric: "tabular-nums", }, /** * A learned name is runtime state, not something the operator typed, so it * reads muted and carries an outlined "learned" tag. The tag is real text — * a screen reader announces it — because colour alone is not an affordance. */ learnedName: { color: colors.textMuted, }, learnedTag: { marginLeft: "0.5rem", borderWidth: 1, borderStyle: "solid", borderColor: colors.border, borderRadius: "0.25rem", paddingInline: "0.375rem", paddingBlock: "0.125rem", fontSize: "0.75rem", lineHeight: "1rem", color: colors.textMuted, }, /** For a value the operator reads character by character: a domain, an IP, a URL. */ mono: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace", }, /** Visible to a screen reader only; the element keeps its place in the a11y tree. */ srOnly: { position: "absolute", width: 1, height: 1, padding: 0, margin: -1, overflow: "hidden", clipPath: "inset(50%)", whiteSpace: "nowrap", borderWidth: 0, }, th: { borderBottomWidth: 1, borderBottomStyle: "solid", borderBottomColor: colors.borderStrong, paddingInline: "0.75rem", paddingBlock: "0.5rem", textAlign: "left", fontWeight: 500, }, td: { borderBottomWidth: 1, borderBottomStyle: "solid", borderBottomColor: colors.border, paddingInline: "0.75rem", paddingBlock: "0.5rem", }, tableWrap: { marginTop: "1rem", overflowX: "auto", }, /** * Not a faithful port: `space-y-3` set sibling margins on a block container, * this is a flex formatting context. StyleX has no way to write the `> * + *` * selector that `space-y` compiles to, so the rhythm can only come from * `gap`. Child sizing and margin behaviour differ from the Tailwind original; * both call sites are plain vertical form stacks, where they do not. */ formCard: { display: "flex", flexDirection: "column", gap: "0.75rem", marginTop: "1rem", maxWidth: "32rem", borderRadius: "0.25rem", borderWidth: 1, borderStyle: "solid", borderColor: colors.border, padding: "1rem", }, });