- ButtonClass() now emits "ui-button ui-button-solid ui-button-default ui-button-md" - Ghost variant special case: "ui-button ui-button-ghost ui-button-md" (tone omitted) - button.templ: added Icon string field to ButtonProps, replaced inline btnType with buttonType() helper - ui_test.go: updated TestButton_DefaultSolidMD to multi-class slice assertions - ui_test.go: updated TestButtonClass_String and TestButtonClass_GhostVariant expectations - All 18 ui package tests pass
201 lines
6.3 KiB
Go
201 lines
6.3 KiB
Go
package ui
|
|
|
|
// Size is the canonical component size enum. Phase 1 only renders SizeMD via
|
|
// CSS, but every component normalizes Size so future phases can drop in
|
|
// `.ui-button-...-sm` / `.ui-button-...-lg` rules without changing call sites.
|
|
type Size string
|
|
|
|
const (
|
|
SizeSM Size = "sm"
|
|
SizeMD Size = "md"
|
|
SizeLG Size = "lg"
|
|
)
|
|
|
|
// ButtonVariant is the semantic-color enum for Button.
|
|
type ButtonVariant string
|
|
|
|
const (
|
|
ButtonVariantDefault ButtonVariant = "default"
|
|
ButtonVariantNeutral ButtonVariant = "neutral"
|
|
ButtonVariantWarning ButtonVariant = "warning"
|
|
ButtonVariantSuccess ButtonVariant = "success"
|
|
ButtonVariantDanger ButtonVariant = "danger"
|
|
ButtonVariantGhost ButtonVariant = "ghost"
|
|
)
|
|
|
|
// ButtonTone is the visual-weight enum for Button (solid vs. soft).
|
|
type ButtonTone string
|
|
|
|
const (
|
|
ButtonToneSolid ButtonTone = "solid"
|
|
ButtonToneSoft ButtonTone = "soft"
|
|
)
|
|
|
|
// BadgeVariant is the semantic-color enum for Badge.
|
|
type BadgeVariant string
|
|
|
|
const (
|
|
BadgeVariantInfo BadgeVariant = "info"
|
|
BadgeVariantWarning BadgeVariant = "warning"
|
|
BadgeVariantSuccess BadgeVariant = "success"
|
|
BadgeVariantDanger BadgeVariant = "danger"
|
|
BadgeVariantPrimary BadgeVariant = "primary"
|
|
)
|
|
|
|
// IconButtonVariant is the semantic-color enum for IconButton.
|
|
type IconButtonVariant string
|
|
|
|
const (
|
|
IconButtonVariantNeutral IconButtonVariant = "neutral"
|
|
IconButtonVariantWarning IconButtonVariant = "warning"
|
|
IconButtonVariantSuccess IconButtonVariant = "success"
|
|
IconButtonVariantDanger IconButtonVariant = "danger"
|
|
)
|
|
|
|
// IconButtonTone is the visual-weight enum for IconButton (solid vs. ghost).
|
|
type IconButtonTone string
|
|
|
|
const (
|
|
IconButtonToneSolid IconButtonTone = "solid"
|
|
IconButtonToneGhost IconButtonTone = "ghost"
|
|
)
|
|
|
|
// SpacingStep is the spacing size enum for space components.
|
|
type SpacingStep string
|
|
|
|
const (
|
|
SpacingStepXS SpacingStep = "xs"
|
|
SpacingStepSM SpacingStep = "sm"
|
|
SpacingStepMD SpacingStep = "md"
|
|
SpacingStepLG SpacingStep = "lg"
|
|
SpacingStepXL SpacingStep = "xl"
|
|
)
|
|
|
|
// NormalizedSize returns the safe default (SizeMD) for the zero value and any
|
|
// value not in the declared set.
|
|
func NormalizedSize(size Size) Size {
|
|
switch size {
|
|
case SizeSM, SizeLG:
|
|
return size
|
|
default:
|
|
return SizeMD
|
|
}
|
|
}
|
|
|
|
// NormalizedButtonVariant returns the safe default (ButtonVariantDefault) for
|
|
// the zero value and any value not in the declared set.
|
|
func NormalizedButtonVariant(variant ButtonVariant) ButtonVariant {
|
|
switch variant {
|
|
case ButtonVariantNeutral, ButtonVariantWarning, ButtonVariantSuccess, ButtonVariantDanger, ButtonVariantGhost:
|
|
return variant
|
|
default:
|
|
return ButtonVariantDefault
|
|
}
|
|
}
|
|
|
|
// NormalizedButtonTone returns the safe default (ButtonToneSolid) for the zero
|
|
// value and any value not in the declared set.
|
|
func NormalizedButtonTone(tone ButtonTone) ButtonTone {
|
|
switch tone {
|
|
case ButtonToneSoft:
|
|
return tone
|
|
default:
|
|
return ButtonToneSolid
|
|
}
|
|
}
|
|
|
|
// NormalizedBadgeVariant returns the safe default (BadgeVariantInfo) for the
|
|
// zero value and any value not in the declared set.
|
|
func NormalizedBadgeVariant(variant BadgeVariant) BadgeVariant {
|
|
switch variant {
|
|
case BadgeVariantWarning, BadgeVariantSuccess, BadgeVariantDanger, BadgeVariantPrimary:
|
|
return variant
|
|
default:
|
|
return BadgeVariantInfo
|
|
}
|
|
}
|
|
|
|
// NormalizedIconButtonVariant returns the safe default (IconButtonVariantNeutral)
|
|
// for the zero value and any value not in the declared set.
|
|
func NormalizedIconButtonVariant(variant IconButtonVariant) IconButtonVariant {
|
|
switch variant {
|
|
case IconButtonVariantWarning, IconButtonVariantSuccess, IconButtonVariantDanger:
|
|
return variant
|
|
default:
|
|
return IconButtonVariantNeutral
|
|
}
|
|
}
|
|
|
|
// NormalizedIconButtonTone returns the safe default (IconButtonToneSolid) for
|
|
// the zero value and any value not in the declared set.
|
|
func NormalizedIconButtonTone(tone IconButtonTone) IconButtonTone {
|
|
switch tone {
|
|
case IconButtonToneGhost:
|
|
return tone
|
|
default:
|
|
return IconButtonToneSolid
|
|
}
|
|
}
|
|
|
|
// NormalizedSpacingStep returns the safe default (SpacingStepMD) for the zero
|
|
// value and any value not in the declared set.
|
|
func NormalizedSpacingStep(step SpacingStep) SpacingStep {
|
|
switch step {
|
|
case SpacingStepXS, SpacingStepSM, SpacingStepLG, SpacingStepXL:
|
|
return step
|
|
default:
|
|
return SpacingStepMD
|
|
}
|
|
}
|
|
|
|
// ButtonClass assembles the deterministic class string for a Button. Inputs
|
|
// are normalized before assembly so callers can pass zero values safely.
|
|
//
|
|
// Example: ButtonClass(ButtonVariantDefault, ButtonToneSolid, SizeMD) ==
|
|
// "ui-button ui-button-solid ui-button-default ui-button-md".
|
|
//
|
|
// Ghost variant is a special case: the tone class is omitted and "ui-button-ghost"
|
|
// is emitted as a standalone modifier.
|
|
func ButtonClass(variant ButtonVariant, tone ButtonTone, size Size) string {
|
|
v := NormalizedButtonVariant(variant)
|
|
s := NormalizedSize(size)
|
|
if v == ButtonVariantGhost {
|
|
return "ui-button ui-button-ghost ui-button-" + string(s)
|
|
}
|
|
t := NormalizedButtonTone(tone)
|
|
return "ui-button ui-button-" + string(t) + " ui-button-" + string(v) + " ui-button-" + string(s)
|
|
}
|
|
|
|
// BadgeClass assembles the deterministic class string for a Badge.
|
|
//
|
|
// Example: BadgeClass(BadgeVariantInfo) == "ui-badge ui-badge-info".
|
|
func BadgeClass(variant BadgeVariant) string {
|
|
v := NormalizedBadgeVariant(variant)
|
|
return "ui-badge ui-badge-" + string(v)
|
|
}
|
|
|
|
// IconButtonClass assembles the deterministic class string for an IconButton.
|
|
// Ghost tone uses the borderless pattern; solid tone uses the filled pattern.
|
|
func IconButtonClass(variant IconButtonVariant, tone IconButtonTone) string {
|
|
normalizedVariant := NormalizedIconButtonVariant(variant)
|
|
switch NormalizedIconButtonTone(tone) {
|
|
case IconButtonToneGhost:
|
|
return "borderless-icon-button ui-icon-button-ghost ui-icon-button-" + string(normalizedVariant)
|
|
default:
|
|
return "ui-icon-button ui-icon-button-solid ui-icon-button-" + string(normalizedVariant)
|
|
}
|
|
}
|
|
|
|
// SpaceXClass assembles the deterministic class string for a horizontal spacer.
|
|
//
|
|
// Example: SpaceXClass(SpacingStepMD) == "ui-space-x ui-space-x-md".
|
|
func SpaceXClass(step SpacingStep) string {
|
|
return "ui-space-x ui-space-x-" + string(NormalizedSpacingStep(step))
|
|
}
|
|
|
|
// SpaceYClass assembles the deterministic class string for a vertical spacer.
|
|
//
|
|
// Example: SpaceYClass(SpacingStepLG) == "ui-space-y ui-space-y-lg".
|
|
func SpaceYClass(step SpacingStep) string {
|
|
return "ui-space-y ui-space-y-" + string(NormalizedSpacingStep(step))
|
|
}
|