@solidrt/components 0.0.51 → 0.0.52

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 (50) hide show
  1. package/AGENTS.md +34 -7
  2. package/README.md +47 -10
  3. package/demos/README.md +24 -0
  4. package/demos/assets/icon.png +0 -0
  5. package/demos/assets/icon.svg +23 -0
  6. package/demos/package.json +9 -0
  7. package/demos/src/gallery.tsx +866 -0
  8. package/demos/tsconfig.json +15 -0
  9. package/docs/button.md +1 -1
  10. package/docs/focus-nav.md +1 -1
  11. package/docs/icon.md +1 -1
  12. package/docs/item.md +1 -1
  13. package/docs/policy.md +1 -1
  14. package/docs/scroll-view.md +22 -1
  15. package/docs/split-view.md +1 -1
  16. package/docs/theme.md +14 -2
  17. package/docs/types.md +4 -0
  18. package/package.json +4 -3
  19. package/src/badge.tsx +21 -14
  20. package/src/button.tsx +13 -7
  21. package/src/card.tsx +10 -3
  22. package/src/checkbox.tsx +8 -2
  23. package/src/context-menu.tsx +9 -6
  24. package/src/divider.tsx +8 -3
  25. package/src/editor-field.tsx +18 -11
  26. package/src/field.tsx +4 -2
  27. package/src/icon.tsx +8 -4
  28. package/src/image.tsx +10 -3
  29. package/src/index.ts +10 -1
  30. package/src/item.tsx +12 -7
  31. package/src/nav-shell.tsx +6 -16
  32. package/src/policy.ts +9 -4
  33. package/src/pressable.tsx +11 -2
  34. package/src/progress-bar.tsx +4 -3
  35. package/src/qrcode.tsx +7 -5
  36. package/src/radio.tsx +12 -4
  37. package/src/rich-text-editor.tsx +5 -3
  38. package/src/scroll-view.tsx +76 -7
  39. package/src/segmented-control.tsx +14 -5
  40. package/src/select.tsx +23 -12
  41. package/src/slider.tsx +31 -5
  42. package/src/spinner.tsx +5 -2
  43. package/src/split-view.tsx +3 -4
  44. package/src/switch.tsx +8 -2
  45. package/src/text-input.tsx +4 -2
  46. package/src/text.tsx +22 -2
  47. package/src/theme.ts +72 -20
  48. package/src/tooltip.tsx +16 -5
  49. package/src/types.ts +119 -1
  50. package/src/view.tsx +11 -2
package/src/types.ts CHANGED
@@ -1,4 +1,122 @@
1
- import type { Color, Gradient, LayoutProps } from "@solidrt/core"
1
+ import type {
2
+ Color,
3
+ Gradient,
4
+ LayoutProps,
5
+ Transition,
6
+ TransitionEndEvent,
7
+ TransitionPropName,
8
+ TransitionProps as CoreTransitionProps,
9
+ } from "@solidrt/core"
10
+
11
+ // Native transitions through a component. A component is a root view plus
12
+ // the nodes it draws for `style` (a background d-rect, a stroke d-rect for
13
+ // the border), so a declaration names the STYLE properties - backgroundColor,
14
+ // borderColor, borderWidth, borderRadius - next to the view-level ones, and
15
+ // splitTransition hands each entry to the node that owns it. Core's paint
16
+ // names (color, radius, strokeWidth) are deliberately not accepted: on a
17
+ // component they would land on the root view, which has no paint, and be
18
+ // silently ignored.
19
+ //
20
+ // Controls whose paint is their own (Switch knob, Slider thumb, Checkbox
21
+ // mark, ...) take the view-level entries only for now; see
22
+ // okf/backlog/component-transitions-internal-paint.md.
23
+ export type TransitionViewProp =
24
+ | "opacity"
25
+ | "x"
26
+ | "y"
27
+ | "scale"
28
+ | "scaleX"
29
+ | "scaleY"
30
+ | "rotate"
31
+ | "rotateX"
32
+ | "rotateY"
33
+ | "originX"
34
+ | "originY"
35
+ | "perspective"
36
+ | "clipRadius"
37
+ export type TransitionStyleProp = "backgroundColor" | "borderColor" | "borderWidth" | "borderRadius"
38
+ export type TransitionScrollProp = "scrollX" | "scrollY"
39
+
40
+ type TransitionEntries<P extends string> = {
41
+ /** One spec for every property the component animates (no `from`/`exit` here, as in core). */
42
+ all?: Transition
43
+ /** Group stagger (ms) for descendant enter/exit animations; see core. */
44
+ stagger?: number
45
+ } & { [K in P]?: Transition }
46
+
47
+ /** A component's transition declaration: view-level and style names, `all`, or a shorthand string. */
48
+ export type ComponentTransition<P extends string = TransitionViewProp | TransitionStyleProp> =
49
+ | TransitionEntries<P>
50
+ | string
51
+ | null
52
+
53
+ export interface TransitionProps<P extends string = TransitionViewProp | TransitionStyleProp> {
54
+ /**
55
+ * Animate later writes of the listed properties instead of snapping, like
56
+ * the core `transition` prop but in the component's own vocabulary:
57
+ * `transition={{ opacity: "200ms ease-out", backgroundColor: { duration: 300 } }}`.
58
+ * `all` or a bare string covers every property the component animates.
59
+ */
60
+ transition?: ComponentTransition<P>
61
+ /** A transition settled; `property` is in the component's vocabulary (`backgroundColor`, not `color`). */
62
+ onTransitionEnd?: (event: { property: P }) => void
63
+ }
64
+
65
+ /** The core transition declarations for a component's root view and its background/border rects. */
66
+ export type SplitTransition = {
67
+ root: CoreTransitionProps["transition"]
68
+ background: CoreTransitionProps["transition"]
69
+ border: CoreTransitionProps["transition"]
70
+ }
71
+
72
+ const STYLE_TO_BACKGROUND: Record<string, TransitionPropName> = { backgroundColor: "color", borderRadius: "radius" }
73
+ const STYLE_TO_BORDER: Record<string, TransitionPropName> = {
74
+ borderColor: "color",
75
+ borderWidth: "strokeWidth",
76
+ borderRadius: "radius",
77
+ }
78
+
79
+ /**
80
+ * Map a component declaration onto the three nodes a styled component
81
+ * draws. `all`, a shorthand string and `stagger` apply to every node; named
82
+ * entries go to the node owning the property. An entry for a node that is
83
+ * not mounted (no background set) simply never animates.
84
+ */
85
+ export function splitTransition<P extends string>(t: ComponentTransition<P> | undefined): SplitTransition {
86
+ if (t == null || typeof t === "string") return { root: t, background: t, border: t }
87
+ let root: Record<string, unknown> = {}
88
+ let background: Record<string, unknown> = {}
89
+ let border: Record<string, unknown> = {}
90
+ for (let [key, value] of Object.entries(t)) {
91
+ if (key === "all" || key === "stagger") {
92
+ root[key] = value
93
+ background[key] = value
94
+ border[key] = value
95
+ } else if (key in STYLE_TO_BACKGROUND || key in STYLE_TO_BORDER) {
96
+ if (key in STYLE_TO_BACKGROUND) background[STYLE_TO_BACKGROUND[key]!] = value
97
+ if (key in STYLE_TO_BORDER) border[STYLE_TO_BORDER[key]!] = value
98
+ } else {
99
+ root[key] = value
100
+ }
101
+ }
102
+ let pick = (o: Record<string, unknown>) => (Object.keys(o).length ? (o as CoreTransitionProps["transition"]) : undefined)
103
+ return { root: pick(root), background: pick(background), border: pick(border) }
104
+ }
105
+
106
+ /** Report a settled core property in the component vocabulary for the node it settled on. */
107
+ export function transitionEndFor<P extends string>(
108
+ node: "root" | "background" | "border",
109
+ handler: ((event: { property: P }) => void) | undefined,
110
+ ): ((event: TransitionEndEvent) => void) | undefined {
111
+ if (!handler) return undefined
112
+ return (e) => {
113
+ let name: string = e.property
114
+ if (node === "background") name = e.property === "color" ? "backgroundColor" : "borderRadius"
115
+ if (node === "border")
116
+ name = e.property === "color" ? "borderColor" : e.property === "strokeWidth" ? "borderWidth" : "borderRadius"
117
+ handler({ property: name as P })
118
+ }
119
+ }
2
120
 
3
121
  // The split between layout and style follows one rule: layout properties feed
4
122
  // into Taffy and changing them triggers a relayout; style properties are
package/src/view.tsx CHANGED
@@ -1,7 +1,8 @@
1
1
  import type { LayoutProps, PointerProps } from "@solidrt/core"
2
- import type { StyleProps } from "./types"
2
+ import type { StyleProps, TransitionProps } from "./types"
3
+ import { splitTransition, transitionEndFor } from "./types"
3
4
 
4
- export interface ViewProps extends PointerProps {
5
+ export interface ViewProps extends PointerProps, TransitionProps {
5
6
  children?: any
6
7
  ref?: (node: { id: number }) => void
7
8
  layout?: LayoutProps
@@ -13,8 +14,12 @@ export function View(props: ViewProps) {
13
14
  props.style?.backgroundColor != null || props.style?.borderRadius != null
14
15
  let hasBorder = () => (props.style?.borderWidth ?? 0) > 0
15
16
 
17
+ let split = () => splitTransition(props.transition)
18
+
16
19
  return (
17
20
  <view
21
+ transition={split().root}
22
+ onTransitionEnd={transitionEndFor("root", props.onTransitionEnd)}
18
23
  ref={props.ref}
19
24
  {...props.layout}
20
25
  x={props.style?.x}
@@ -45,6 +50,8 @@ export function View(props: ViewProps) {
45
50
  >
46
51
  {hasBackground() ? (
47
52
  <d-rect
53
+ transition={split().background}
54
+ onTransitionEnd={transitionEndFor("background", props.onTransitionEnd)}
48
55
  color={props.style?.backgroundColor ?? "transparent"}
49
56
  radius={props.style?.borderRadius}
50
57
  />
@@ -53,6 +60,8 @@ export function View(props: ViewProps) {
53
60
  {hasBorder() ? (
54
61
  <d-rect
55
62
  drawStyle="stroke"
63
+ transition={split().border}
64
+ onTransitionEnd={transitionEndFor("border", props.onTransitionEnd)}
56
65
  color={props.style?.borderColor ?? "transparent"}
57
66
  strokeWidth={props.style?.borderWidth}
58
67
  radius={props.style?.borderRadius}