@phreshos/react-ui 0.1.30 → 0.1.31

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 (80) hide show
  1. package/README.md +162 -18
  2. package/dist/accordion.d.ts +45 -0
  3. package/dist/accordion.js +62 -0
  4. package/dist/alert-dialog.d.ts +0 -1
  5. package/dist/alert-dialog.js +0 -1
  6. package/dist/aria-direction.d.ts +9 -0
  7. package/dist/aria-direction.js +49 -0
  8. package/dist/calendar-layout.d.ts +8 -0
  9. package/dist/calendar-layout.js +103 -0
  10. package/dist/calendar-trigger.d.ts +5 -0
  11. package/dist/calendar-trigger.js +30 -0
  12. package/dist/calendar.d.ts +18 -0
  13. package/dist/calendar.js +13 -0
  14. package/dist/color.d.ts +16 -1
  15. package/dist/color.js +60 -11
  16. package/dist/combo-box.d.ts +20 -0
  17. package/dist/combo-box.js +68 -0
  18. package/dist/context-menu.d.ts +2 -4
  19. package/dist/context-menu.js +0 -1
  20. package/dist/control-surface.d.ts +2 -1
  21. package/dist/control-surface.js +2 -2
  22. package/dist/control.d.ts +1 -1
  23. package/dist/control.js +7 -8
  24. package/dist/date-control.d.ts +24 -0
  25. package/dist/date-control.js +69 -0
  26. package/dist/date-field.d.ts +19 -0
  27. package/dist/date-field.js +13 -0
  28. package/dist/date-picker.d.ts +19 -0
  29. package/dist/date-picker.js +16 -0
  30. package/dist/date-range-picker.d.ts +20 -0
  31. package/dist/date-range-picker.js +25 -0
  32. package/dist/date-range.d.ts +6 -0
  33. package/dist/date-range.js +0 -0
  34. package/dist/dialog.d.ts +4 -2
  35. package/dist/dialog.js +24 -7
  36. package/dist/disclosure.d.ts +42 -0
  37. package/dist/disclosure.js +97 -0
  38. package/dist/dropdown-menu.d.ts +0 -2
  39. package/dist/dropdown-menu.js +0 -1
  40. package/dist/list-box.d.ts +49 -0
  41. package/dist/list-box.js +129 -0
  42. package/dist/main.d.ts +25 -9
  43. package/dist/main.js +25 -9
  44. package/dist/material-paint.js +19 -1
  45. package/dist/menu.d.ts +22 -4
  46. package/dist/menu.js +25 -6
  47. package/dist/panel.d.ts +0 -1
  48. package/dist/panel.js +0 -1
  49. package/dist/popover.d.ts +0 -1
  50. package/dist/popover.js +13 -3
  51. package/dist/progress-bar.d.ts +22 -0
  52. package/dist/progress-bar.js +46 -0
  53. package/dist/radio.d.ts +5 -5
  54. package/dist/radio.js +8 -4
  55. package/dist/radius.js +1 -1
  56. package/dist/range-calendar.d.ts +19 -0
  57. package/dist/range-calendar.js +15 -0
  58. package/dist/scroll-area.d.ts +4 -1
  59. package/dist/scroll-area.js +3 -3
  60. package/dist/select.js +4 -14
  61. package/dist/selection.d.ts +18 -0
  62. package/dist/selection.js +28 -0
  63. package/dist/slider.js +1 -1
  64. package/dist/spacing.js +1 -1
  65. package/dist/table.d.ts +78 -0
  66. package/dist/table.js +148 -0
  67. package/dist/tabs.d.ts +45 -0
  68. package/dist/tabs.js +103 -0
  69. package/dist/time-field.d.ts +22 -0
  70. package/dist/time-field.js +13 -0
  71. package/dist/toggle-indicator.js +1 -1
  72. package/dist/toolbar.d.ts +46 -0
  73. package/dist/toolbar.js +121 -0
  74. package/dist/tooltip.d.ts +0 -1
  75. package/dist/tooltip.js +0 -1
  76. package/dist/tree.d.ts +56 -0
  77. package/dist/tree.js +134 -0
  78. package/dist/window.d.ts +6 -3
  79. package/dist/window.js +10 -7
  80. package/package.json +3 -1
package/dist/tree.js ADDED
@@ -0,0 +1,134 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { createContext, forwardRef, useContext, useMemo } from "react";
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 });
12
+ 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: {
15
+ display: "grid",
16
+ alignContent: "start",
17
+ gap: theme.gap,
18
+ minWidth: 0,
19
+ padding: theme.gap,
20
+ boxSizing: "border-box",
21
+ outline: "none",
22
+ fontFamily: "inherit",
23
+ fontSize: theme.fontSize,
24
+ ...style
25
+ } }) }) });
26
+ });
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 => {
59
+ const responds = interactive || onAction != null || state.hasChildItems;
60
+ 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",
73
+ 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" }),
86
+ ...style
87
+ };
88
+ } });
89
+ });
90
+ export const TreeItem = TreeItemImplementation;
91
+ export const TreeContent = forwardRef(function TreeContent({ children }, ref) {
92
+ const { direction, theme } = useTreeTheme();
93
+ return _jsx(AriaTreeItemContent, { ref: ref, children: state => _jsxs(_Fragment, { children: [state.hasChildItems
94
+ ? _jsx(AriaButton, { slot: "chevron", style: ({ isFocusVisible }) => ({
95
+ ...theme.transition,
96
+ appearance: "none",
97
+ display: "inline-grid",
98
+ flex: "0 0 auto",
99
+ placeItems: "center",
100
+ width: theme.indicatorSize,
101
+ height: theme.indicatorSize,
102
+ padding: 0,
103
+ border: 0,
104
+ borderRadius: theme.radius,
105
+ outline: isFocusVisible ? `1px solid ${theme.focusColor}` : "none",
106
+ outlineOffset: 1,
107
+ background: "transparent",
108
+ color: "inherit",
109
+ cursor: state.isDisabled ? "not-allowed" : "pointer",
110
+ 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 })] }) });
113
+ });
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" }) });
121
+ }
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,
126
+ Content: TreeContent,
127
+ Collection: TreeCollection
128
+ });
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,13 +1,16 @@
1
1
  import type { HTMLAttributes, ReactNode } from "react";
2
2
  import { type ButtonProps } from "./button.js";
3
+ import { type Color } from "./color.js";
3
4
  import { type SurfaceProps } from "./surface.js";
4
5
  /** The material shell that establishes the complete header-and-content layout. */
5
6
  export type WindowProps = SurfaceProps;
6
7
  /** The remaining window area. Its consumer owns content behavior, including overflow. */
7
8
  export type WindowContentProps = HTMLAttributes<HTMLDivElement>;
8
- export interface WindowHeaderProps extends HTMLAttributes<HTMLDivElement> {
9
+ export interface WindowHeaderProps extends Omit<HTMLAttributes<HTMLDivElement>, "color"> {
9
10
  /** Attenuates the identity when this header is not active. */
10
11
  readonly active?: boolean;
12
+ /** Base color inherited by header-owned text and icons. */
13
+ readonly color?: Color;
11
14
  }
12
15
  export interface WindowIdentityProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
13
16
  readonly icon?: string;
@@ -20,7 +23,7 @@ export type WindowControlProps = Omit<WindowActionProps, "children">;
20
23
  export interface WindowMaximizeProps extends WindowControlProps {
21
24
  readonly maximized?: boolean;
22
25
  }
23
- export type WindowCloseProps = Omit<WindowControlProps, "color">;
26
+ export type WindowCloseProps = WindowControlProps;
24
27
  /** One Surface with a ready-to-use header-and-content composition. */
25
28
  export declare const Window: import("react").ForwardRefExoticComponent<Omit<WindowProps, "ref"> & import("react").RefAttributes<HTMLDivElement>> & {
26
29
  Header: import("react").ForwardRefExoticComponent<WindowHeaderProps & import("react").RefAttributes<HTMLDivElement>> & {
@@ -30,7 +33,7 @@ export declare const Window: import("react").ForwardRefExoticComponent<Omit<Wind
30
33
  Action: import("react").ForwardRefExoticComponent<WindowActionProps & import("react").RefAttributes<HTMLButtonElement>>;
31
34
  Minimize: import("react").ForwardRefExoticComponent<WindowControlProps & import("react").RefAttributes<HTMLButtonElement>>;
32
35
  Maximize: import("react").ForwardRefExoticComponent<WindowMaximizeProps & import("react").RefAttributes<HTMLButtonElement>>;
33
- Close: import("react").ForwardRefExoticComponent<WindowCloseProps & import("react").RefAttributes<HTMLButtonElement>>;
36
+ Close: import("react").ForwardRefExoticComponent<WindowControlProps & import("react").RefAttributes<HTMLButtonElement>>;
34
37
  };
35
38
  Content: import("react").ForwardRefExoticComponent<WindowContentProps & import("react").RefAttributes<HTMLDivElement>>;
36
39
  };
package/dist/window.js CHANGED
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { createContext, forwardRef, useContext } from "react";
3
3
  import { useResolvedAppearance } from "./appearance-context.js";
4
4
  import { Button } from "./button.js";
5
+ import { resolveColor } from "./color.js";
5
6
  import { transitionTiming } from "./motion-style.js";
6
7
  import { scale } from "./scale.js";
7
8
  import { Surface } from "./surface.js";
@@ -31,12 +32,13 @@ const WindowContent = forwardRef(function WindowContent({ style, ...properties }
31
32
  } });
32
33
  });
33
34
  /** The composable top region of a window; its enclosing Surface owns the material. */
34
- const HeaderRoot = forwardRef(function HeaderRoot({ active = true, children, onPointerDown, style, ...properties }, ref) {
35
+ const HeaderRoot = forwardRef(function HeaderRoot({ active = true, children, color, onPointerDown, style, ...properties }, ref) {
35
36
  const resolved = useResolvedAppearance();
36
37
  const spacing = resolved.appearance.spacing;
38
+ const foreground = style?.color ?? resolveColor(color ?? "foreground:base", resolved.colors);
37
39
  const state = {
38
40
  active,
39
- foreground: resolved.colors.foreground,
41
+ foreground,
40
42
  iconRadius: scale(resolved.appearance.radius, "xsmall"),
41
43
  spacing,
42
44
  transition: transitionTiming(resolved.transaction, resolved.preferences.animations)
@@ -53,6 +55,7 @@ const HeaderRoot = forwardRef(function HeaderRoot({ active = true, children, onP
53
55
  userSelect: "none",
54
56
  touchAction: onPointerDown ? "none" : undefined,
55
57
  cursor: onPointerDown ? "grab" : undefined,
58
+ color: foreground,
56
59
  ...style
57
60
  }, children: children }) });
58
61
  });
@@ -102,9 +105,9 @@ const WindowActions = forwardRef(function WindowActions({ onDoubleClick, onPoint
102
105
  } });
103
106
  });
104
107
  /** A compact header action; extra actions use the same treatment as the standard controls. */
105
- const WindowAction = forwardRef(function WindowAction({ style, ...properties }, ref) {
106
- const { foreground } = useHeader();
107
- return _jsx(Button, { ...properties, ref: ref, size: "xsmall", style: { color: foreground, ...style } });
108
+ const WindowAction = forwardRef(function WindowAction({ ...properties }, ref) {
109
+ useHeader();
110
+ return _jsx(Button, { ...properties, ref: ref, size: "xsmall" });
108
111
  });
109
112
  const WindowMinimize = forwardRef(function WindowMinimize({ "aria-label": label = "Minimize", preventFocusOnPress = true, ...properties }, ref) {
110
113
  return _jsx(WindowAction, { ...properties, ref: ref, "aria-label": label, preventFocusOnPress: preventFocusOnPress, children: _jsx(ControlIcon, { children: _jsx("path", { d: "M1.5 7.5h7" }) }) });
@@ -114,8 +117,8 @@ const WindowMaximize = forwardRef(function WindowMaximize({ "aria-label": label,
114
117
  ? _jsx("path", { d: "M1 4h5v5H1zM4 1h5v5H6.5", strokeWidth: "1.3", strokeLinejoin: "round" })
115
118
  : _jsx("path", { d: "M1.5 1.5h7v7h-7z", strokeWidth: "1.3", strokeLinejoin: "round" }) }) });
116
119
  });
117
- const WindowClose = forwardRef(function WindowClose({ "aria-label": label = "Close", preventFocusOnPress = true, ...properties }, ref) {
118
- return _jsx(WindowAction, { ...properties, ref: ref, "aria-label": label, color: "danger:base", preventFocusOnPress: preventFocusOnPress, children: _jsx(ControlIcon, { children: _jsx("path", { d: "M1.5 1.5 8.5 8.5M8.5 1.5 1.5 8.5" }) }) });
120
+ const WindowClose = forwardRef(function WindowClose({ "aria-label": label = "Close", color = "danger:base", preventFocusOnPress = true, ...properties }, ref) {
121
+ 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" }) }) });
119
122
  });
120
123
  function ControlIcon({ children }) {
121
124
  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 });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phreshos/react-ui",
3
- "version": "0.1.30",
3
+ "version": "0.1.31",
4
4
  "description": "React components for coherent PhreshOS Program interfaces.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -56,9 +56,11 @@
56
56
  },
57
57
  "dependencies": {
58
58
  "@base-ui/react": "^1.7.0",
59
+ "@internationalized/date": "^3.12.3",
59
60
  "@phreshos/core": "^0.1.55",
60
61
  "colorjs.io": "^0.7.1",
61
62
  "motion": "^13.2.0",
63
+ "react-aria": "^3.51.0",
62
64
  "react-aria-components": "^1.20.0"
63
65
  },
64
66
  "devDependencies": {