@phreshos/react-ui 0.1.36 → 0.1.38

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 (202) hide show
  1. package/README.md +147 -167
  2. package/dist/accordion.d.ts +7 -6
  3. package/dist/accordion.js +5 -5
  4. package/dist/alert-dialog.d.ts +2 -2
  5. package/dist/alert-dialog.js +3 -1
  6. package/dist/alert.d.ts +17 -0
  7. package/dist/alert.js +30 -0
  8. package/dist/app-layout.d.ts +13 -0
  9. package/dist/app-layout.js +84 -0
  10. package/dist/button.d.ts +31 -27
  11. package/dist/button.js +48 -40
  12. package/dist/calendar-layout.d.ts +9 -5
  13. package/dist/calendar-layout.js +67 -78
  14. package/dist/calendar-trigger.d.ts +4 -4
  15. package/dist/calendar-trigger.js +7 -29
  16. package/dist/calendar.d.ts +2 -2
  17. package/dist/calendar.js +6 -5
  18. package/dist/checkbox.d.ts +4 -4
  19. package/dist/checkbox.js +16 -6
  20. package/dist/color-area.d.ts +20 -0
  21. package/dist/color-area.js +30 -0
  22. package/dist/color-field.d.ts +17 -0
  23. package/dist/color-field.js +17 -0
  24. package/dist/color-picker.d.ts +24 -0
  25. package/dist/color-picker.js +30 -0
  26. package/dist/color-slider.d.ts +19 -0
  27. package/dist/color-slider.js +29 -0
  28. package/dist/color-swatch-picker.d.ts +23 -0
  29. package/dist/color-swatch-picker.js +36 -0
  30. package/dist/color-swatch.d.ts +18 -0
  31. package/dist/color-swatch.js +20 -0
  32. package/dist/combo-box.d.ts +18 -10
  33. package/dist/combo-box.js +43 -58
  34. package/dist/context-menu.d.ts +14 -10
  35. package/dist/context-menu.js +7 -6
  36. package/dist/control/color-thumb.d.ts +13 -0
  37. package/dist/control/color-thumb.js +33 -0
  38. package/dist/control/color-value.d.ts +6 -0
  39. package/dist/control/color-value.js +7 -0
  40. package/dist/control/control.d.ts +60 -0
  41. package/dist/control/control.js +71 -0
  42. package/dist/control/field-button.d.ts +13 -0
  43. package/dist/control/field-button.js +28 -0
  44. package/dist/control/field.d.ts +20 -0
  45. package/dist/control/field.js +34 -0
  46. package/dist/control/icon.d.ts +11 -0
  47. package/dist/control/icon.js +8 -0
  48. package/dist/control/item.d.ts +37 -0
  49. package/dist/control/item.js +57 -0
  50. package/dist/control/open-state.d.ts +25 -0
  51. package/dist/control/open-state.js +8 -0
  52. package/dist/control/selection-track.d.ts +39 -0
  53. package/dist/control/selection-track.js +122 -0
  54. package/dist/control/selection.d.ts +44 -0
  55. package/dist/{selection.js → control/selection.js} +16 -0
  56. package/dist/control/surface-render.d.ts +10 -0
  57. package/dist/control/surface-render.js +12 -0
  58. package/dist/control/text-control.d.ts +32 -0
  59. package/dist/control/text-control.js +31 -0
  60. package/dist/control/toggle.d.ts +32 -0
  61. package/dist/control/toggle.js +80 -0
  62. package/dist/date-control.d.ts +9 -9
  63. package/dist/date-control.js +31 -34
  64. package/dist/date-field.d.ts +7 -6
  65. package/dist/date-field.js +8 -6
  66. package/dist/date-picker.d.ts +13 -6
  67. package/dist/date-picker.js +9 -6
  68. package/dist/date-range-picker.d.ts +15 -6
  69. package/dist/date-range-picker.js +12 -9
  70. package/dist/dialog.d.ts +29 -15
  71. package/dist/dialog.js +37 -28
  72. package/dist/disclosure.d.ts +8 -7
  73. package/dist/disclosure.js +31 -52
  74. package/dist/drop-zone.d.ts +18 -0
  75. package/dist/drop-zone.js +32 -0
  76. package/dist/dropdown-menu.d.ts +11 -8
  77. package/dist/dropdown-menu.js +5 -4
  78. package/dist/fieldset.d.ts +13 -0
  79. package/dist/fieldset.js +26 -0
  80. package/dist/file-trigger.d.ts +13 -0
  81. package/dist/file-trigger.js +6 -0
  82. package/dist/flex.d.ts +1 -1
  83. package/dist/flex.js +5 -4
  84. package/dist/foundation/appearance.d.ts +83 -0
  85. package/dist/foundation/appearance.js +38 -0
  86. package/dist/{aria-direction.js → foundation/aria-direction.js} +3 -1
  87. package/dist/foundation/color.d.ts +61 -0
  88. package/dist/foundation/color.js +247 -0
  89. package/dist/{layout.d.ts → foundation/layout.d.ts} +6 -4
  90. package/dist/{layout.js → foundation/layout.js} +7 -5
  91. package/dist/foundation/motion-style.d.ts +9 -0
  92. package/dist/foundation/motion-style.js +50 -0
  93. package/dist/foundation/preferences.d.ts +15 -0
  94. package/dist/{ui-provider.d.ts → foundation/provider.d.ts} +9 -5
  95. package/dist/{ui-provider.js → foundation/provider.js} +18 -27
  96. package/dist/{radius.d.ts → foundation/radius.d.ts} +6 -3
  97. package/dist/foundation/radius.js +11 -0
  98. package/dist/foundation/spacing.d.ts +11 -0
  99. package/dist/foundation/spacing.js +4 -0
  100. package/dist/foundation/visual.d.ts +42 -0
  101. package/dist/{appearance-context.js → foundation/visual.js} +41 -27
  102. package/dist/grid.d.ts +1 -1
  103. package/dist/grid.js +5 -4
  104. package/dist/icons/main.d.ts +5 -3
  105. package/dist/icons/main.js +5 -3
  106. package/dist/input.d.ts +2 -2
  107. package/dist/input.js +9 -7
  108. package/dist/list-box.d.ts +24 -19
  109. package/dist/list-box.js +52 -109
  110. package/dist/main.d.ts +28 -17
  111. package/dist/main.js +22 -9
  112. package/dist/menu.d.ts +28 -32
  113. package/dist/menu.js +47 -93
  114. package/dist/number-field.d.ts +17 -0
  115. package/dist/number-field.js +28 -0
  116. package/dist/panel.d.ts +10 -5
  117. package/dist/panel.js +33 -12
  118. package/dist/popover.d.ts +26 -12
  119. package/dist/popover.js +22 -15
  120. package/dist/progress-bar.d.ts +8 -10
  121. package/dist/progress-bar.js +18 -34
  122. package/dist/radio.d.ts +15 -12
  123. package/dist/radio.js +27 -37
  124. package/dist/range-calendar.d.ts +5 -3
  125. package/dist/range-calendar.js +8 -7
  126. package/dist/scroll-area.d.ts +2 -2
  127. package/dist/scroll-area.js +10 -9
  128. package/dist/segmented-control.d.ts +23 -0
  129. package/dist/segmented-control.js +38 -0
  130. package/dist/select.d.ts +40 -13
  131. package/dist/select.js +63 -18
  132. package/dist/slider.d.ts +7 -3
  133. package/dist/slider.js +51 -50
  134. package/dist/spinner.d.ts +5 -8
  135. package/dist/spinner.js +12 -27
  136. package/dist/surface/grain.d.ts +12 -0
  137. package/dist/surface/grain.js +65 -0
  138. package/dist/{material-options.d.ts → surface/material-options.d.ts} +1 -2
  139. package/dist/{material-options.js → surface/material-options.js} +2 -2
  140. package/dist/surface/paint-class.d.ts +13 -0
  141. package/dist/surface/paint-class.js +47 -0
  142. package/dist/{shadow-options.d.ts → surface/shadow-options.d.ts} +13 -1
  143. package/dist/{shadow-options.js → surface/shadow-options.js} +17 -2
  144. package/dist/surface/surface.d.ts +80 -0
  145. package/dist/surface/surface.js +239 -0
  146. package/dist/switch.d.ts +4 -5
  147. package/dist/switch.js +17 -8
  148. package/dist/table.d.ts +29 -32
  149. package/dist/table.js +68 -106
  150. package/dist/tabs.d.ts +16 -15
  151. package/dist/tabs.js +44 -86
  152. package/dist/textarea.d.ts +2 -2
  153. package/dist/textarea.js +10 -14
  154. package/dist/time-field.d.ts +6 -6
  155. package/dist/time-field.js +8 -6
  156. package/dist/toolbar.d.ts +6 -4
  157. package/dist/toolbar.js +16 -15
  158. package/dist/tooltip.d.ts +17 -8
  159. package/dist/tooltip.js +17 -15
  160. package/dist/tree.d.ts +22 -27
  161. package/dist/tree.js +54 -99
  162. package/dist/window.d.ts +4 -4
  163. package/dist/window.js +18 -20
  164. package/package.json +3 -3
  165. package/dist/appearance-context.d.ts +0 -54
  166. package/dist/appearance.d.ts +0 -11
  167. package/dist/appearance.js +0 -11
  168. package/dist/color.d.ts +0 -69
  169. package/dist/color.js +0 -192
  170. package/dist/control-surface.d.ts +0 -20
  171. package/dist/control-surface.js +0 -11
  172. package/dist/control.d.ts +0 -70
  173. package/dist/control.js +0 -105
  174. package/dist/field-style.d.ts +0 -3
  175. package/dist/field-style.js +0 -12
  176. package/dist/material-paint.d.ts +0 -13
  177. package/dist/material-paint.js +0 -119
  178. package/dist/motion-style.d.ts +0 -13
  179. package/dist/motion-style.js +0 -75
  180. package/dist/preferences.d.ts +0 -12
  181. package/dist/radius.js +0 -11
  182. package/dist/readiness.d.ts +0 -37
  183. package/dist/readiness.js +0 -134
  184. package/dist/selection.d.ts +0 -18
  185. package/dist/spacing.d.ts +0 -8
  186. package/dist/spacing.js +0 -8
  187. package/dist/surface-edge.d.ts +0 -11
  188. package/dist/surface-edge.js +0 -55
  189. package/dist/surface.d.ts +0 -27
  190. package/dist/surface.js +0 -92
  191. package/dist/text-control.d.ts +0 -10
  192. package/dist/text-control.js +0 -0
  193. package/dist/toggle-indicator.d.ts +0 -18
  194. package/dist/toggle-indicator.js +0 -49
  195. /package/dist/{aria-direction.d.ts → foundation/aria-direction.d.ts} +0 -0
  196. /package/dist/{direction.d.ts → foundation/direction.d.ts} +0 -0
  197. /package/dist/{direction.js → foundation/direction.js} +0 -0
  198. /package/dist/{overlay-placement.d.ts → foundation/overlay-placement.d.ts} +0 -0
  199. /package/dist/{overlay-placement.js → foundation/overlay-placement.js} +0 -0
  200. /package/dist/{preferences.js → foundation/preferences.js} +0 -0
  201. /package/dist/{scale.d.ts → foundation/scale.d.ts} +0 -0
  202. /package/dist/{scale.js → foundation/scale.js} +0 -0
package/dist/tree.js CHANGED
@@ -1,134 +1,89 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { createContext, forwardRef, useContext, useMemo } from "react";
3
3
  import { Button as AriaButton, Collection as AriaCollection, Tree as AriaTree, TreeItem as AriaTreeItem, TreeItemContent as AriaTreeItemContent } from "react-aria-components";
4
- import { controlOpacity, useControlTheme } from "./control.js";
5
- import { resolveDirection, useDirection } from "./direction.js";
6
- import { multipleSelection, singleSelection, stringKey, stringKeys, toAriaSelection } from "./selection.js";
7
- import { AriaDirectionBoundary } from "./aria-direction.js";
8
- const TreeThemeContext = createContext(null);
9
- const TreeRootImplementation = forwardRef(function TreeRoot(properties, ref) {
10
- const { className, color, defaultExpanded, defaultValue, disabledValues, expanded, onChange, onExpandedChange, onItemAction, radius = "medium", selectionMode = "none", size = "medium", style, value, ...native } = properties;
11
- const theme = useControlTheme({ color, radius, size });
4
+ import { proportionalRadius, transition, useControlMetrics } from "./control/control.js";
5
+ import { itemPaint, itemStyle } from "./control/item.js";
6
+ import { ariaSelection, stringKey, stringKeys } from "./control/selection.js";
7
+ import { AriaDirectionBoundary } from "./foundation/aria-direction.js";
8
+ import { colorOpacity } from "./foundation/color.js";
9
+ import { resolveDirection, useDirection } from "./foundation/direction.js";
10
+ import { dimmedClass } from "./surface/surface.js";
11
+ import { ChevronRight } from "lucide-react";
12
+ import { iconProps } from "./control/icon.js";
13
+ const TreeStyleContext = createContext(null);
14
+ const TreeRootImplementation = forwardRef(function Tree(properties, ref) {
15
+ const { className, color = "primary", defaultExpanded, defaultValue: _defaultValue, expanded, onAction, onChange: _onChange, onExpandedChange, radius, selectOnPressUp, selectionMode = "none", size, style, value: _value, ...native } = properties;
16
+ const metrics = useControlMetrics(size, radius);
17
+ // Items are controls: they take the control radius at their size.
18
+ const itemRadius = metrics.radius;
12
19
  const direction = resolveDirection(native.dir, useDirection());
13
- const context = useMemo(() => ({ direction, interactive: selectionMode !== "none" || onItemAction != null, theme }), [direction, onItemAction, selectionMode, theme]);
14
- return _jsx(TreeThemeContext.Provider, { value: context, children: _jsx(AriaDirectionBoundary, { direction: direction, children: _jsx(AriaTree, { ...native, ...selectionProperties(properties), ...expansionProperties({ defaultExpanded, expanded, onExpandedChange }), ref: ref, dir: direction, className: className, disabledKeys: disabledValues, selectionMode: selectionMode, onAction: onItemAction == null ? undefined : key => onItemAction(stringKey(key)), style: {
20
+ const context = useMemo(() => ({ color, direction, interactive: selectionMode !== "none" || onAction != null, metrics, itemRadius }), [color, direction, metrics, itemRadius, onAction, selectionMode]);
21
+ return _jsx(TreeStyleContext.Provider, { value: context, children: _jsx(AriaDirectionBoundary, { direction: direction, children: _jsx(AriaTree, { ...native, shouldSelectOnPressUp: selectOnPressUp, ...ariaSelection(properties, "none"), ...(expanded !== undefined ? { expandedKeys: new Set(expanded) } : {}), ...(defaultExpanded !== undefined ? { defaultExpandedKeys: new Set(defaultExpanded) } : {}), ...(onExpandedChange !== undefined ? { onExpandedChange: (keys) => onExpandedChange(stringKeys(keys)) } : {}), ref: ref, dir: direction, className: className, onAction: onAction == null ? undefined : key => onAction(stringKey(key)), style: {
15
22
  display: "grid",
16
23
  alignContent: "start",
17
- gap: theme.gap,
24
+ gap: 2,
18
25
  minWidth: 0,
19
- padding: theme.gap,
26
+ padding: metrics.listInset,
20
27
  boxSizing: "border-box",
21
28
  outline: "none",
22
29
  fontFamily: "inherit",
23
- fontSize: theme.fontSize,
30
+ fontSize: metrics.fontSize,
24
31
  ...style
25
32
  } }) }) });
26
33
  });
27
- export const TreeRoot = TreeRootImplementation;
28
- function selectionProperties(properties) {
29
- const selectedKeys = toAriaSelection(properties.value);
30
- const defaultSelectedKeys = toAriaSelection(properties.defaultValue);
31
- const onSelectionChange = properties.onChange == null
32
- ? undefined
33
- : (selection) => {
34
- if (properties.selectionMode === "multiple") {
35
- properties.onChange?.(multipleSelection(selection));
36
- return;
37
- }
38
- if (properties.selectionMode === "single")
39
- properties.onChange?.(singleSelection(selection));
40
- };
41
- return {
42
- ...(selectedKeys !== undefined ? { selectedKeys } : {}),
43
- ...(defaultSelectedKeys !== undefined ? { defaultSelectedKeys } : {}),
44
- ...(onSelectionChange !== undefined ? { onSelectionChange } : {})
45
- };
46
- }
47
- function expansionProperties({ defaultExpanded, expanded, onExpandedChange }) {
48
- return {
49
- ...(expanded !== undefined ? { expandedKeys: new Set(expanded) } : {}),
50
- ...(defaultExpanded !== undefined ? { defaultExpandedKeys: new Set(defaultExpanded) } : {}),
51
- ...(onExpandedChange !== undefined
52
- ? { onExpandedChange: (keys) => onExpandedChange(stringKeys(keys)) }
53
- : {})
54
- };
55
- }
56
- const TreeItemImplementation = forwardRef(function TreeItem({ className, disabled = false, onAction, style, ...properties }, ref) {
57
- const { interactive, theme } = useTreeTheme();
58
- return _jsx(AriaTreeItem, { ...properties, ref: ref, className: className, isDisabled: disabled, onAction: onAction, style: state => {
34
+ /** Tree entries use the collection Item treatment as their own paint. */
35
+ const TreeItemImplementation = forwardRef(function TreeItem({ arrowNavigation, className, disabled = false, expandable, onAction, style, ...properties }, ref) {
36
+ const { color, interactive, itemRadius, metrics } = useTreeStyle();
37
+ return _jsx(AriaTreeItem, { ...properties, allowsArrowNavigation: arrowNavigation, hasChildItems: expandable, ref: ref, className: state => dimmedClass(state.isDisabled, className ?? state.defaultClassName) ?? "", isDisabled: disabled, onAction: onAction, style: state => {
59
38
  const responds = interactive || onAction != null || state.hasChildItems;
60
39
  return {
61
- ...theme.transition,
62
- display: "flex",
63
- alignItems: "center",
64
- gap: theme.gap,
65
- minWidth: 0,
66
- minHeight: theme.height,
67
- paddingBlock: 0,
68
- paddingInlineEnd: Math.max(8, theme.spacing),
69
- paddingInlineStart: Math.max(8, theme.spacing) + Math.max(0, state.level - 1) * theme.spacing,
70
- boxSizing: "border-box",
71
- borderRadius: theme.radius,
72
- outline: state.isFocusVisible ? `1px solid ${theme.focusColor}` : "none",
40
+ ...itemStyle(metrics, state.isDisabled),
41
+ ...itemPaint(metrics.visual, color, {
42
+ selected: state.isSelected,
43
+ hovered: responds && state.isHovered,
44
+ pressed: responds && state.isPressed,
45
+ focusVisible: false,
46
+ disabled: state.isDisabled
47
+ }),
48
+ paddingInlineStart: metrics.inset / 2 + Math.max(0, state.level - 1) * metrics.spacing,
49
+ borderRadius: itemRadius,
50
+ outline: `3px solid ${state.isFocusVisible ? colorOpacity(metrics.visual.colors.primary, 0.34) : "transparent"}`,
73
51
  outlineOffset: 1,
74
- cursor: disabled ? "not-allowed" : responds ? "pointer" : "default",
75
- opacity: disabled ? controlOpacity.disabled : 1,
76
- userSelect: "none",
77
- ...(state.isSelected
78
- ? state.isPressed
79
- ? theme.paints.palette.pressed
80
- : state.isHovered
81
- ? theme.paints.palette.hover
82
- : theme.paints.palette.rest
83
- : state.isHovered && responds
84
- ? theme.paints.subtle.hover
85
- : { background: "transparent", color: "inherit" }),
52
+ cursor: state.isDisabled ? "not-allowed" : responds ? "pointer" : "default",
86
53
  ...style
87
54
  };
88
55
  } });
89
56
  });
90
- export const TreeItem = TreeItemImplementation;
91
- export const TreeContent = forwardRef(function TreeContent({ children }, ref) {
92
- const { direction, theme } = useTreeTheme();
57
+ const TreeContent = forwardRef(function TreeContent({ children }, ref) {
58
+ const { direction, metrics } = useTreeStyle();
59
+ const box = Math.round(metrics.indicator);
93
60
  return _jsx(AriaTreeItemContent, { ref: ref, children: state => _jsxs(_Fragment, { children: [state.hasChildItems
94
61
  ? _jsx(AriaButton, { slot: "chevron", style: ({ isFocusVisible }) => ({
95
- ...theme.transition,
96
- appearance: "none",
97
62
  display: "inline-grid",
98
63
  flex: "0 0 auto",
99
64
  placeItems: "center",
100
- width: theme.indicatorSize,
101
- height: theme.indicatorSize,
65
+ width: box,
66
+ height: box,
102
67
  padding: 0,
103
68
  border: 0,
104
- borderRadius: theme.radius,
105
- outline: isFocusVisible ? `1px solid ${theme.focusColor}` : "none",
106
- outlineOffset: 1,
69
+ borderRadius: proportionalRadius(metrics.visual, box),
70
+ outline: `3px solid ${isFocusVisible ? colorOpacity(metrics.visual.colors.primary, 0.34) : "transparent"}`,
107
71
  background: "transparent",
108
72
  color: "inherit",
109
73
  cursor: state.isDisabled ? "not-allowed" : "pointer",
110
74
  font: "inherit"
111
- }), children: _jsx(Chevron, { direction: direction, expanded: state.isExpanded, theme: theme }) })
112
- : _jsx("span", { "aria-hidden": "true", style: { flex: `0 0 ${theme.indicatorSize}px`, width: theme.indicatorSize } }), _jsx("span", { style: { flex: "1 1 auto", minWidth: 0 }, children: typeof children === "function" ? children(state) : children })] }) });
75
+ }), children: _jsx(ChevronRight, { ...iconProps(14), style: { ...transition(metrics.visual, "rotate"), rotate: state.isExpanded ? "90deg" : direction === "rtl" ? "180deg" : "0deg" } }) })
76
+ : _jsx("span", { "aria-hidden": "true", style: { flex: `0 0 ${box}px` } }), _jsx("span", { style: { flex: "1 1 auto", minWidth: 0, display: "flex", alignItems: "center", gap: metrics.gap }, children: typeof children === "function" ? children(state) : children })] }) });
113
77
  });
114
- function Chevron({ direction, expanded, theme }) {
115
- const collapsedRotation = direction === "rtl" ? 180 : 0;
116
- return _jsx("svg", { "aria-hidden": "true", width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", style: {
117
- ...theme.transition,
118
- transitionProperty: "transform",
119
- transform: `rotate(${expanded ? 90 : collapsedRotation}deg)`
120
- }, children: _jsx("path", { d: "m4 2 4 4-4 4" }) });
78
+ function useTreeStyle() {
79
+ const context = useContext(TreeStyleContext);
80
+ if (context == null)
81
+ throw new Error("Tree parts must be used inside Tree");
82
+ return context;
121
83
  }
122
- export const TreeCollection = AriaCollection;
123
- /** Hierarchical navigation with independently controlled expansion, selection, and item actions. */
124
- export const Tree = Object.assign(TreeRoot, {
125
- Item: TreeItem,
84
+ /** Hierarchical navigation with independently controlled expansion, selection, and actions. */
85
+ export const Tree = Object.assign(TreeRootImplementation, {
86
+ Item: TreeItemImplementation,
126
87
  Content: TreeContent,
127
- Collection: TreeCollection
88
+ Collection: AriaCollection
128
89
  });
129
- function useTreeTheme() {
130
- const value = useContext(TreeThemeContext);
131
- if (value == null)
132
- throw new Error("Tree parts must be used inside Tree");
133
- return value;
134
- }
package/dist/window.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import type { HTMLAttributes, ReactNode } from "react";
2
2
  import type { BeginWindowMoveGesture } from "@phreshos/core";
3
- import { type ButtonProps } from "./button.js";
4
- import { type Color } from "./color.js";
5
- import { type SurfaceProps } from "./surface.js";
3
+ import { type ButtonActionProps } from "./button.js";
4
+ import { type Color } from "./foundation/color.js";
5
+ import { type SurfaceProps } from "./surface/surface.js";
6
6
  /** The material shell that establishes the complete header-and-content layout. */
7
7
  export type WindowProps = SurfaceProps;
8
8
  /** The remaining window area. Its consumer owns content behavior, including overflow. */
@@ -27,7 +27,7 @@ export interface WindowIdentityProps extends Omit<HTMLAttributes<HTMLDivElement>
27
27
  }
28
28
  export type WindowCenterProps = HTMLAttributes<HTMLDivElement>;
29
29
  export type WindowActionsProps = HTMLAttributes<HTMLDivElement>;
30
- export type WindowActionProps = Omit<ButtonProps, "size">;
30
+ export type WindowActionProps = Omit<ButtonActionProps, "size">;
31
31
  export type WindowControlProps = Omit<WindowActionProps, "children">;
32
32
  export interface WindowMaximizeProps extends WindowControlProps {
33
33
  readonly maximized?: boolean;
package/dist/window.js CHANGED
@@ -1,12 +1,15 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { createContext, forwardRef, useContext } from "react";
3
- import { useResolvedAppearance } from "./appearance-context.js";
4
3
  import { Button } from "./button.js";
5
- import { resolveColor } from "./color.js";
6
- import { transitionTiming } from "./motion-style.js";
7
- import { scale } from "./scale.js";
8
- import { Surface } from "./surface.js";
4
+ import { transition } from "./control/control.js";
5
+ import { resolveColor } from "./foundation/color.js";
6
+ import { headerHeight } from "./foundation/layout.js";
7
+ import { scale } from "./foundation/scale.js";
8
+ import { useVisual } from "./foundation/visual.js";
9
+ import { Surface } from "./surface/surface.js";
9
10
  import useWindowMoveHandle from "./use-window-move-handle.js";
11
+ import { ArrowDownLeft, Maximize2, Minimize2, X } from "lucide-react";
12
+ import { iconProps } from "./control/icon.js";
10
13
  const HeaderContext = createContext(null);
11
14
  function useHeader() {
12
15
  const value = useContext(HeaderContext);
@@ -34,17 +37,17 @@ const WindowContent = forwardRef(function WindowContent({ style, ...properties }
34
37
  });
35
38
  /** The composable top region of a window; its enclosing Surface owns the material. */
36
39
  const HeaderRoot = forwardRef(function HeaderRoot({ active = true, beginMoveGesture, children, color, maximized = false, onDoubleClick, onLostPointerCapture, onMaximize, onMoveError, onPointerCancel, onPointerDown, onPointerMove, onPointerUp, style, ...properties }, ref) {
37
- const resolved = useResolvedAppearance();
38
- const spacing = resolved.appearance.spacing;
39
- const foreground = style?.color ?? resolveColor(color ?? "foreground:base", resolved.colors);
40
+ const visual = useVisual();
41
+ const spacing = visual.spacing;
42
+ const foreground = style?.color ?? resolveColor(color ?? "foreground", visual.colors);
40
43
  const state = {
41
44
  active,
42
45
  foreground,
43
- iconRadius: scale(resolved.appearance.radius, "xsmall"),
46
+ iconRadius: scale(visual.radius, "xsmall"),
44
47
  maximized,
45
48
  onMaximize,
46
49
  spacing,
47
- transition: transitionTiming(resolved.transaction, resolved.preferences.animations)
50
+ transition: transition(visual, "opacity")
48
51
  };
49
52
  const move = useWindowMoveHandle(beginMoveGesture, onMoveError);
50
53
  return _jsx(HeaderContext.Provider, { value: state, children: _jsx("div", { ...properties, ref: ref, onPointerDown: event => {
@@ -61,7 +64,7 @@ const HeaderRoot = forwardRef(function HeaderRoot({ active = true, beginMoveGest
61
64
  alignItems: "center",
62
65
  gap: spacing,
63
66
  minWidth: 0,
64
- height: 16 + spacing * 2,
67
+ height: headerHeight(spacing),
65
68
  paddingInline: spacing,
66
69
  flexShrink: 0,
67
70
  userSelect: "none",
@@ -122,21 +125,16 @@ const WindowAction = forwardRef(function WindowAction({ ...properties }, ref) {
122
125
  return _jsx(Button, { ...properties, ref: ref, size: "xsmall" });
123
126
  });
124
127
  const WindowMinimize = forwardRef(function WindowMinimize({ "aria-label": label = "Minimize", preventFocusOnPress = true, ...properties }, ref) {
125
- return _jsx(WindowAction, { ...properties, ref: ref, "aria-label": label, preventFocusOnPress: preventFocusOnPress, children: _jsx(ControlIcon, { children: _jsx("path", { d: "M1.5 7.5h7" }) }) });
128
+ return _jsx(WindowAction, { ...properties, ref: ref, "aria-label": label, preventFocusOnPress: preventFocusOnPress, children: _jsx(ArrowDownLeft, { ...iconProps(14) }) });
126
129
  });
127
130
  const WindowMaximize = forwardRef(function WindowMaximize({ "aria-label": label, maximized, onPress, ...properties }, ref) {
128
131
  const header = useHeader();
129
132
  const selected = maximized ?? header.maximized;
130
- return _jsx(WindowAction, { ...properties, ref: ref, onPress: onPress ?? header.onMaximize, "aria-label": label ?? (selected ? "Restore" : "Maximize"), children: _jsx(ControlIcon, { children: selected
131
- ? _jsx("path", { d: "M1 4h5v5H1zM4 1h5v5H6.5", strokeWidth: "1.3", strokeLinejoin: "round" })
132
- : _jsx("path", { d: "M1.5 1.5h7v7h-7z", strokeWidth: "1.3", strokeLinejoin: "round" }) }) });
133
+ return _jsx(WindowAction, { ...properties, ref: ref, onPress: onPress ?? header.onMaximize, "aria-label": label ?? (selected ? "Restore" : "Maximize"), children: selected ? _jsx(Minimize2, { ...iconProps(14) }) : _jsx(Maximize2, { ...iconProps(14) }) });
133
134
  });
134
- const WindowClose = forwardRef(function WindowClose({ "aria-label": label = "Close", color = "danger:base", preventFocusOnPress = true, ...properties }, ref) {
135
- return _jsx(WindowAction, { ...properties, ref: ref, "aria-label": label, color: color, preventFocusOnPress: preventFocusOnPress, children: _jsx(ControlIcon, { children: _jsx("path", { d: "M1.5 1.5 8.5 8.5M8.5 1.5 1.5 8.5" }) }) });
135
+ const WindowClose = forwardRef(function WindowClose({ "aria-label": label = "Close", color = "danger", preventFocusOnPress = true, ...properties }, ref) {
136
+ return _jsx(WindowAction, { ...properties, ref: ref, "aria-label": label, color: color, preventFocusOnPress: preventFocusOnPress, children: _jsx(X, { ...iconProps(14) }) });
136
137
  });
137
- function ControlIcon({ children }) {
138
- return _jsx("svg", { "aria-hidden": "true", width: "10", height: "10", viewBox: "0 0 10 10", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", children: children });
139
- }
140
138
  const Header = Object.assign(HeaderRoot, {
141
139
  Identity: WindowIdentity,
142
140
  Center: WindowCenter,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phreshos/react-ui",
3
- "version": "0.1.36",
3
+ "version": "0.1.38",
4
4
  "description": "React components for coherent PhreshOS Program interfaces.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -57,9 +57,9 @@
57
57
  "dependencies": {
58
58
  "@base-ui/react": "^1.7.0",
59
59
  "@internationalized/date": "^3.12.3",
60
- "@phreshos/core": "^0.1.60",
60
+ "@phreshos/core": "^0.1.62",
61
61
  "colorjs.io": "^0.7.1",
62
- "motion": "^13.2.0",
62
+ "lucide-react": "^1.48.0",
63
63
  "react-aria": "^3.51.0",
64
64
  "react-aria-components": "^1.20.0"
65
65
  },
@@ -1,54 +0,0 @@
1
- import { type Appearance, type ThemedValue } from "./appearance.js";
2
- import type { Preferences } from "./preferences.js";
3
- export declare const AppearanceContext: import("react").Context<Appearance>;
4
- export interface PreferencesSource {
5
- readonly getSnapshot: () => Preferences;
6
- readonly getServerSnapshot: () => Preferences;
7
- readonly subscribe: (change: () => void) => () => void;
8
- }
9
- /** Returns the nearest unresolved appearance, or React UI's default. */
10
- export declare function useAppearance(): Appearance;
11
- /** Returns the nearest complete Preferences, or reactively follows the browser. */
12
- export declare function usePreferences(): Preferences;
13
- /** Reactively reads the browser's complete visual preferences. */
14
- export declare function useBrowserPreferences(): Preferences;
15
- /** Selects the active branch of one complete ThemedValue. */
16
- export declare function useThemedValue<Value>(value: ThemedValue<Value>): Value;
17
- /** Resolves one coherent Appearance snapshot for internal component derivation. */
18
- export declare function useResolvedAppearance(): {
19
- appearance: Appearance;
20
- preferences: Preferences;
21
- colors: Readonly<{
22
- background: string;
23
- foreground: string;
24
- default: string;
25
- primary: string;
26
- secondary: string;
27
- success: string;
28
- warning: string;
29
- danger: string;
30
- info: string;
31
- }>;
32
- material: Readonly<{
33
- grain: number;
34
- grainAmount: number;
35
- backdrop: number;
36
- opacity: number;
37
- distortion: number;
38
- saturation: number;
39
- }>;
40
- shadow: Readonly<{
41
- x: number;
42
- y: number;
43
- blur: number;
44
- spread: number;
45
- opacity: number;
46
- }>;
47
- transaction: Readonly<{
48
- duration: number;
49
- easing: import("@phreshos/core").Easing;
50
- }>;
51
- };
52
- /** Creates a stable source for a complete explicitly supplied Preferences value. */
53
- export declare function fixedPreferencesSource(preferences: Preferences): PreferencesSource;
54
- export declare const PreferencesContext: import("react").Context<PreferencesSource>;
@@ -1,11 +0,0 @@
1
- import { appearanceLimits, type Appearance as SystemAppearance, type AppearanceUpdate as SystemAppearanceUpdate, type AppearanceColor, type AppearanceColors, type AppearanceMaterial, type AppearanceRange, type AppearanceShadow, type AppearanceTransaction, type Easing, type ThemedValue } from "@phreshos/core";
2
- /** Complete visual input consumed by React UI. */
3
- export type Appearance = Pick<SystemAppearance, "colors" | "spacing" | "radius" | "shadow" | "material" | "transaction">;
4
- type AppearanceUpdateFields = Pick<SystemAppearanceUpdate, "colors" | "spacing" | "radius" | "shadow" | "material" | "transaction">;
5
- /** At least one partial visual field recursively merged with the nearest UIProvider. */
6
- export type AppearanceUpdate = {
7
- [Field in keyof AppearanceUpdateFields]-?: Readonly<Required<Pick<AppearanceUpdateFields, Field>> & Omit<AppearanceUpdateFields, Field>>;
8
- }[keyof AppearanceUpdateFields];
9
- export { appearanceLimits, type AppearanceColor, type AppearanceColors, type AppearanceMaterial, type AppearanceRange, type AppearanceShadow, type AppearanceTransaction, type Easing, type ThemedValue };
10
- /** React UI's default visual input, derived from the System default. */
11
- export declare const defaultAppearance: Appearance;
@@ -1,11 +0,0 @@
1
- import { appearanceLimits, defaultAppearance as systemDefaultAppearance } from "@phreshos/core";
2
- export { appearanceLimits };
3
- /** React UI's default visual input, derived from the System default. */
4
- export const defaultAppearance = Object.freeze({
5
- colors: systemDefaultAppearance.colors,
6
- spacing: systemDefaultAppearance.spacing,
7
- radius: systemDefaultAppearance.radius,
8
- shadow: systemDefaultAppearance.shadow,
9
- material: systemDefaultAppearance.material,
10
- transaction: systemDefaultAppearance.transaction
11
- });
package/dist/color.d.ts DELETED
@@ -1,69 +0,0 @@
1
- import type { AppearanceColor, AppearanceColors } from "./appearance.js";
2
- /** A visual treatment derived from one concrete CSS color. */
3
- export type ColorLevel = "subtle" | "soft" | "base" | "strong" | "intense";
4
- /** Every visual treatment derived from one concrete CSS color. */
5
- export type ColorScale = Readonly<Record<ColorLevel, string>>;
6
- /** One Appearance color and resting level, or a direct CSS color. */
7
- export type Color = `${AppearanceColor}:${ColorLevel}` | (string & {});
8
- export declare const defaultColor = "background:base";
9
- /** Distinguishes derived color levels from direct CSS colors. */
10
- export declare function isColorLevel(value: string | undefined): value is ColorLevel;
11
- /** Derives visual treatments while preserving the concrete value at `base`. */
12
- export declare function color(value: string): ColorScale;
13
- /** Resolves the same named treatment for solid paint and contrast calculations. */
14
- export declare function resolveColorLevel(value: string, level: ColorLevel): string;
15
- /** Returns the complete visual treatments derived from one concrete color. */
16
- export declare function useColor(value: string): ColorScale;
17
- /** Returns the readable Appearance content color for one semantic or CSS fill. */
18
- export declare function useContrastingColor(value: Color): string;
19
- /** Resolves a semantic color from an already selected Appearance branch. */
20
- export declare function resolveColor(value: Color | undefined, colors: AppearanceColors): string;
21
- /** Resolves opaque control paint from an already selected Appearance branch. */
22
- export declare function resolveSolidColor(value: Color, colors: AppearanceColors): string;
23
- /** Applies material opacity without restricting the source CSS color syntax. */
24
- export declare function colorOpacity(value: string, opacity: number): string;
25
- /** Reads perceptual lightness from a resolved CSS color. */
26
- export declare function colorLightness(value: string): number;
27
- /** Orders resolved CSS colors by perceptual lightness, never by their role. */
28
- export declare function orderColors(first: string, second: string): {
29
- lighter: string;
30
- darker: string;
31
- };
32
- /** Solid controls use opaque, gamut-mapped colors for both paint and contrast. */
33
- export declare function opaqueColor(value: string): string;
34
- /** Changes only perceptual lightness; theme names never determine direction. */
35
- export declare function colorShade(value: string, amount: number): string;
36
- /** Chooses the perceptually opposite Appearance color for the actual painted fill. */
37
- export declare function onColor(fill: string, background: string, foreground: string): string;
38
- /** Chooses readable content when the fill can be evaluated, otherwise preserves Appearance foreground. */
39
- export declare function contrastingColor(value: Color, colors: AppearanceColors): string;
40
- /** Solid controls start at base; interaction shades preserve its text choice. */
41
- export declare function solidColors(base: string, background: string, foreground: string): {
42
- rest: {
43
- background: string;
44
- color: string;
45
- };
46
- hover: {
47
- background: string;
48
- color: string;
49
- };
50
- pressed: {
51
- background: string;
52
- color: string;
53
- };
54
- };
55
- /** Low-emphasis interaction paints derived from the same component-owned base. */
56
- export declare function subtleColors(base: string, background: string, foreground: string): {
57
- rest: {
58
- background: string;
59
- color: string;
60
- };
61
- hover: {
62
- background: string;
63
- color: string;
64
- };
65
- pressed: {
66
- background: string;
67
- color: string;
68
- };
69
- };