@solidrt/components 0.0.33 → 0.0.35

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidrt/components",
3
- "version": "0.0.33",
3
+ "version": "0.0.35",
4
4
  "license": "MIT",
5
5
  "author": "Antoine van Wel",
6
6
  "type": "module",
@@ -18,6 +18,6 @@
18
18
  },
19
19
  "peerDependencies": {
20
20
  "@solidjs/signals": "2.0.0-beta.20",
21
- "@solidrt/core": "0.0.33"
21
+ "@solidrt/core": "0.0.35"
22
22
  }
23
23
  }
package/src/button.tsx CHANGED
@@ -8,20 +8,30 @@ import type { LayoutProps } from "@solidrt/core"
8
8
  import type { StyleProps } from "./types"
9
9
 
10
10
  export type ButtonVariant = "primary" | "secondary" | "ghost" | "danger"
11
+ export type ButtonSize = "sm" | "md" | "lg"
11
12
 
12
13
  export interface ButtonProps {
13
14
  // A string/number is rendered as the themed label; anything else is rendered
14
15
  // as-is, so a button can hold custom content (an icon, a row, ...).
15
16
  children?: any
16
- // Visual role: primary (accent fill), secondary (surface fill with border),
17
- // ghost (no fill until hover), danger (destructive accent fill).
17
+ // Visual role: primary (accent fill), secondary (darker-blue fill), ghost
18
+ // (no fill until hover), danger (destructive accent fill). None draw a border.
18
19
  variant?: ButtonVariant
20
+ // Fixed-width preset: pins the button to a set width (a longer label still
21
+ // expands past it), so a row of buttons lines up. Omitted, the button
22
+ // stretches to the container's width (the default). Padding is the same at
23
+ // every size.
24
+ size?: ButtonSize
19
25
  onPress?: () => void
20
26
  disabled?: boolean
21
27
  layout?: LayoutProps
22
28
  style?: StyleProps
23
29
  }
24
30
 
31
+ // Minimum width per size preset (logical px). A minimum, not a hard width, so
32
+ // labels wider than the preset never clip.
33
+ const SIZE_WIDTH: Record<ButtonSize, number> = { sm: 88, md: 120, lg: 160 }
34
+
25
35
  // Themed convenience over Pressable: a padded, centered, accent-colored box with
26
36
  // a label. Press feedback is a slight scale, hover feedback a tint (non-touch
27
37
  // interaction policies only), both driven through Pressable's reactive style so
@@ -30,30 +40,34 @@ export interface ButtonProps {
30
40
  // its hover variant.
31
41
  export function Button(props: ButtonProps) {
32
42
  // Fill, hover fill, and label color per variant, read reactively from the
33
- // theme. Only secondary draws a border.
43
+ // theme. No variant draws a border.
34
44
  let colors = () => {
35
45
  let c = theme.color
36
46
  switch (props.variant ?? "primary") {
37
47
  case "secondary":
38
- return { fill: c.surface, hover: c.surfaceHover, label: c.text, border: c.border }
48
+ return { fill: c.secondary, hover: c.secondaryHover, label: c.onSecondary }
39
49
  case "ghost":
40
- return { fill: "transparent", hover: c.surfaceHover, label: c.text, border: undefined }
50
+ return { fill: "transparent", hover: c.surfaceHover, label: c.text }
41
51
  case "danger":
42
- return { fill: c.danger, hover: c.dangerHover, label: c.onPrimary, border: undefined }
52
+ return { fill: c.danger, hover: c.dangerHover, label: c.onPrimary }
43
53
  default:
44
- return { fill: c.primary, hover: c.primaryHover, label: c.onPrimary, border: undefined }
54
+ return { fill: c.primary, hover: c.primaryHover, label: c.onPrimary }
45
55
  }
46
56
  }
47
- let bg = (s: PressState) =>
48
- props.style?.backgroundColor ??
49
- (props.disabled
57
+ let idleFill = () =>
58
+ props.disabled
50
59
  ? props.variant === "ghost"
51
60
  ? "transparent"
52
61
  : theme.color.surface
62
+ : colors().fill
63
+ let bg = (s: PressState) =>
64
+ props.style?.backgroundColor ??
65
+ (props.disabled
66
+ ? idleFill()
53
67
  : s.hovered && policy.interaction !== "touch"
54
68
  ? colors().hover
55
69
  : colors().fill)
56
- let radius = () => props.style?.borderRadius ?? theme.radius.sm
70
+ let radius = () => props.style?.borderRadius ?? theme.radius.md
57
71
  let label = () => (props.disabled ? theme.color.textMuted : colors().label)
58
72
  // Resolved once via children(): reading the raw children getter builds a new
59
73
  // subtree per read, so the typeof probe and the two mount sites below must
@@ -63,12 +77,7 @@ export function Button(props: ButtonProps) {
63
77
  // The label's polarity against the idle fill: onPrimary on a saturated fill
64
78
  // is light-on-dark even in a light theme, so it needs the low-DPI weight
65
79
  // compensation there too.
66
- let labelOnDark = () =>
67
- lightOnDark(
68
- label(),
69
- props.style?.backgroundColor ??
70
- (props.disabled ? (props.variant === "ghost" ? "transparent" : theme.color.surface) : colors().fill),
71
- )
80
+ let labelOnDark = () => lightOnDark(label(), props.style?.backgroundColor ?? idleFill())
72
81
 
73
82
  return (
74
83
  <Pressable
@@ -78,15 +87,14 @@ export function Button(props: ButtonProps) {
78
87
  flexDirection: "row",
79
88
  alignItems: "center",
80
89
  justifyContent: "center",
81
- paddingTop: space("sm"),
82
- paddingBottom: space("sm"),
83
- paddingLeft: space("md"),
84
- paddingRight: space("md"),
90
+ paddingTop: space("md"),
91
+ paddingBottom: space("md"),
92
+ paddingLeft: space("lg"),
93
+ paddingRight: space("lg"),
94
+ ...(props.size ? { minWidth: SIZE_WIDTH[props.size] } : { width: "100%" }),
85
95
  ...props.layout,
86
96
  }}
87
97
  style={(s: PressState) => ({
88
- borderColor: colors().border,
89
- borderWidth: colors().border != null ? theme.borderWidth.sm : undefined,
90
98
  ...props.style,
91
99
  backgroundColor: bg(s),
92
100
  borderRadius: radius(),
@@ -103,4 +111,4 @@ export function Button(props: ButtonProps) {
103
111
  </Show>
104
112
  </Pressable>
105
113
  )
106
- }
114
+ }
package/src/card.tsx CHANGED
@@ -14,14 +14,14 @@ export interface CardProps {
14
14
  style?: StyleProps
15
15
  }
16
16
 
17
- // A themed surface container: a padded column box with a subtle border and
18
- // rounded corners, reading its colors from the theme so it recolors live.
19
- // Override any paint via style, spacing/sizing via layout.
17
+ // A themed surface container: a padded column box with rounded corners, reading
18
+ // its colors from the theme so it recolors live. Borderless by default; pass
19
+ // style.borderWidth or style.borderColor to draw an outline. Override any paint
20
+ // via style, spacing/sizing via layout.
20
21
  export function Card(props: CardProps) {
21
22
  let bg = () => props.style?.backgroundColor ?? theme.color.surface
22
- let border = () => props.style?.borderColor ?? theme.color.border
23
- let width = () => props.style?.borderWidth ?? theme.borderWidth.sm
24
23
  let radius = () => props.style?.borderRadius ?? theme.radius.lg
24
+ let hasBorder = () => props.style?.borderWidth != null || props.style?.borderColor != null
25
25
 
26
26
  return (
27
27
  <view
@@ -44,7 +44,14 @@ export function Card(props: CardProps) {
44
44
  </text>
45
45
  </Show>
46
46
  {props.children}
47
- <d-rect drawStyle="stroke" color={border()} strokeWidth={width()} radius={radius()} />
47
+ <Show when={hasBorder()}>
48
+ <d-rect
49
+ drawStyle="stroke"
50
+ color={props.style?.borderColor ?? theme.color.border}
51
+ strokeWidth={props.style?.borderWidth ?? theme.borderWidth.sm}
52
+ radius={radius()}
53
+ />
54
+ </Show>
48
55
  </view>
49
56
  )
50
57
  }
package/src/theme.ts CHANGED
@@ -35,6 +35,11 @@ export type Theme = {
35
35
  // Hover tint for primary-colored controls.
36
36
  primaryHover: string
37
37
  onPrimary: string
38
+ // Lower-emphasis accent: the puzzle mark's darker blue.
39
+ secondary: string
40
+ // Hover tint for secondary-colored controls.
41
+ secondaryHover: string
42
+ onSecondary: string
38
43
  // Validation / destructive.
39
44
  danger: string
40
45
  // Hover tint for danger-colored controls.
@@ -75,9 +80,15 @@ export let darkTheme: Theme = {
75
80
  // thin on low-DPI and its contrast depends on what sits behind it.
76
81
  textMuted: mixColors("#e6edf3", "#0b0f17", 0.4),
77
82
  border: "rgba(255,255,255,0.14)",
78
- primary: "#1f6feb",
79
- primaryHover: "#388bfd",
83
+ // Accent tuned to the puzzle mark's mid blue; hover lifts toward its
84
+ // lightest segment tone.
85
+ primary: "#547ebf",
86
+ primaryHover: "#7ea9ea",
80
87
  onPrimary: "#ffffff",
88
+ // The darker shade of the same puzzle segment; hover lifts toward primary.
89
+ secondary: "#2b5696",
90
+ secondaryHover: "#3a68ab",
91
+ onSecondary: "#ffffff",
81
92
  danger: "#f85149",
82
93
  dangerHover: "#ff7b72",
83
94
  scrim: "rgba(0,0,0,0.6)",
@@ -97,9 +108,15 @@ export let lightTheme: Theme = {
97
108
  text: "#1f2328",
98
109
  textMuted: mixColors("#1f2328", "#ffffff", 0.4),
99
110
  border: "rgba(0,0,0,0.15)",
100
- primary: "#1f6feb",
101
- primaryHover: "#1a5fd0",
111
+ // Accent tuned to the puzzle mark's mid blue; hover deepens toward its
112
+ // darker segment tone.
113
+ primary: "#547ebf",
114
+ primaryHover: "#3f5494",
102
115
  onPrimary: "#ffffff",
116
+ // The darker shade of the same puzzle segment; hover deepens it further.
117
+ secondary: "#2b5696",
118
+ secondaryHover: "#1f4176",
119
+ onSecondary: "#ffffff",
103
120
  danger: "#cf222e",
104
121
  dangerHover: "#a40e26",
105
122
  scrim: "rgba(0,0,0,0.4)",
package/src/types.ts CHANGED
@@ -17,6 +17,22 @@ export interface StyleProps {
17
17
  y?: number
18
18
  rotate?: number
19
19
  scale?: number
20
+ // Per-axis scale; overrides `scale` on that axis (e.g. scaleX for a flip).
21
+ scaleX?: number
22
+ scaleY?: number
23
+ // 3D rotation in radians about the horizontal (rotateX) / vertical (rotateY)
24
+ // axis; reads as real depth only with `perspective` set.
25
+ rotateX?: number
26
+ rotateY?: number
27
+ // Perspective viewing distance in pixels, enabling 3D depth for rotateX/Y.
28
+ perspective?: number
29
+ // Transform origin (the pivot for scale/rotate), in pixels from the box's
30
+ // top-left. Defaults to the box center on each axis.
31
+ originX?: number
32
+ originY?: number
33
+ // Corner radii for the clip applied when overflow is non-visible (hidden,
34
+ // clip, scroll); a single number or [tl, tr, br, bl].
35
+ clipRadius?: number | [number, number, number, number]
20
36
  opacity?: number
21
37
  }
22
38
 
package/src/view.tsx CHANGED
@@ -20,7 +20,15 @@ export function View(props: ViewProps) {
20
20
  x={props.style?.x}
21
21
  y={props.style?.y}
22
22
  scale={props.style?.scale}
23
+ scaleX={props.style?.scaleX}
24
+ scaleY={props.style?.scaleY}
23
25
  rotate={props.style?.rotate}
26
+ rotateX={props.style?.rotateX}
27
+ rotateY={props.style?.rotateY}
28
+ perspective={props.style?.perspective}
29
+ originX={props.style?.originX}
30
+ originY={props.style?.originY}
31
+ clipRadius={props.style?.clipRadius}
24
32
  opacity={props.style?.opacity}
25
33
  onPointerEnter={props.onPointerEnter}
26
34
  onPointerLeave={props.onPointerLeave}