@deadragdoll/reactnu 0.1.52 → 0.1.73

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/dist/styles.css CHANGED
@@ -20,6 +20,8 @@
20
20
  --nu-color-button-face-alt: #c7c7c7;
21
21
  --nu-color-button-danger: #c84d4d;
22
22
  --nu-color-button-success: #188f3b;
23
+ --nu-text-danger: #c84d4d;
24
+ --nu-text-success: #188f3b;
23
25
  --nu-color-button-text: #000000;
24
26
  --nu-color-field-bg: #000000;
25
27
  --nu-color-field-text: #ffffff;
@@ -47,10 +49,22 @@
47
49
  --nu-button-press-depth-y: 0.1em;
48
50
  --nu-frame-thickness: 2px;
49
51
  --nu-rule-thickness: 1px;
52
+ --nu-toolbar-background: var(--nu-color-panel);
53
+ --nu-toolbar-inset: 0.2ch;
54
+ --nu-toolbar-border-color: var(--nu-border-dark);
55
+ --nu-toolbar-border-style: solid;
56
+ --nu-toolbar-border-width: var(--nu-rule-thickness);
57
+ --nu-toolbar-separator-color: var(--nu-border-dark);
58
+ --nu-toolbar-separator-style: solid;
59
+ --nu-toolbar-separator-width: var(--nu-rule-thickness);
60
+ --nu-menu-divider-color: var(--nu-border-dark);
61
+ --nu-menu-divider-style: solid;
62
+ --nu-menu-divider-width: var(--nu-rule-thickness);
50
63
  --nu-window-shadow-bg: rgba(0, 0, 0, 0.38);
51
64
  --nu-window-shadow-offset-x: 1ch;
52
65
  --nu-window-shadow-offset-y: 1em;
53
66
  --nu-window-title-controls-width: 7.8ch;
67
+ --nu-window-title-icon-width: 1em;
54
68
  --nu-window-title-height: calc(1em + 3px);
55
69
  --nu-window-status-height: 1.35rem;
56
70
  --nu-window-inactive-overlay: rgba(0, 0, 0, 0.22);
@@ -1085,20 +1099,23 @@
1085
1099
  .nu-main-menu__item-button:disabled {
1086
1100
  cursor: default;
1087
1101
  }
1088
- .nu-main-menu__item--root .nu-main-menu__item-button {
1102
+ .nu-main-menu__item--root > .nu-main-menu__item-button {
1089
1103
  display: inline-flex;
1090
1104
  align-items: center;
1091
1105
  min-height: 1.4rem;
1092
1106
  padding: 0 0.65rem;
1093
1107
  }
1094
1108
  .nu-main-menu__item--submenu .nu-main-menu__item-button {
1095
- grid-template-columns: 1.1rem 1fr auto 0.8rem;
1109
+ grid-template-columns: minmax(max-content, 1fr) max-content 0.8rem;
1096
1110
  gap: 0.45rem;
1097
1111
  width: 100%;
1098
1112
  min-width: 13rem;
1099
1113
  min-height: 1.35rem;
1100
1114
  padding: 0 0.55rem;
1101
1115
  }
1116
+ .nu-main-menu__item--submenu .nu-main-menu__item-button[data-has-leading] {
1117
+ grid-template-columns: auto minmax(max-content, 1fr) max-content 0.8rem;
1118
+ }
1102
1119
  .nu-main-menu__item--open > .nu-main-menu__item-button {
1103
1120
  background: var(--nu-color-field-bg);
1104
1121
  color: var(--nu-text-primary);
@@ -1146,14 +1163,23 @@
1146
1163
  top: calc(100% - 1px);
1147
1164
  left: 0;
1148
1165
  }
1166
+ .nu-main-menu__submenu-shell--root[data-open-left] {
1167
+ right: 0;
1168
+ left: auto;
1169
+ }
1149
1170
  .nu-main-menu__submenu-shell--submenu {
1150
1171
  top: -0.2rem;
1151
1172
  left: calc(100% - 1px);
1152
1173
  }
1174
+ .nu-main-menu__submenu-shell--submenu[data-open-left] {
1175
+ right: calc(100% - 1px);
1176
+ left: auto;
1177
+ }
1153
1178
  .nu-main-menu__divider {
1154
- height: 1px;
1179
+ height: 0;
1155
1180
  margin: 0.18rem 0.55rem;
1156
- background: var(--nu-border-dark);
1181
+ border-block-start: var(--nu-menu-divider-width) var(--nu-menu-divider-style)
1182
+ var(--nu-menu-divider-color);
1157
1183
  }
1158
1184
  .nu-main-menu__check {
1159
1185
  display: inline-flex;
@@ -1163,6 +1189,13 @@
1163
1189
  block-size: var(--nu-glyph-cell-size);
1164
1190
  color: var(--nu-text-hotkey);
1165
1191
  }
1192
+ .nu-main-menu__leading {
1193
+ display: inline-flex;
1194
+ align-items: center;
1195
+ justify-content: center;
1196
+ gap: 0.25rem;
1197
+ grid-column: 1;
1198
+ }
1166
1199
  .nu-main-menu__check-box {
1167
1200
  display: inline-flex;
1168
1201
  align-items: center;
@@ -1175,24 +1208,49 @@
1175
1208
  .nu-main-menu__check-box[data-unchecked-shape="none"] {
1176
1209
  border-color: transparent;
1177
1210
  }
1211
+ .nu-main-menu__icon {
1212
+ display: inline-flex;
1213
+ align-items: center;
1214
+ justify-content: center;
1215
+ inline-size: var(--nu-glyph-cell-size);
1216
+ block-size: var(--nu-glyph-cell-size);
1217
+ color: currentColor;
1218
+ }
1219
+ .nu-main-menu__icon > svg {
1220
+ inline-size: var(--nu-glyph-cell-size);
1221
+ block-size: var(--nu-glyph-cell-size);
1222
+ }
1178
1223
  .nu-main-menu__label {
1179
1224
  min-width: 0;
1225
+ grid-column: 1;
1226
+ }
1227
+ .nu-main-menu__item-button[data-has-leading] .nu-main-menu__label {
1228
+ grid-column: 2;
1180
1229
  }
1181
1230
  .nu-main-menu__hotkey {
1182
1231
  color: var(--nu-text-hotkey);
1183
1232
  }
1184
1233
  .nu-main-menu__shortcut {
1234
+ grid-column: 2;
1235
+ justify-self: end;
1185
1236
  margin-left: 1rem;
1186
1237
  color: var(--nu-main-menu-text);
1187
1238
  }
1239
+ .nu-main-menu__item-button[data-has-leading] .nu-main-menu__shortcut {
1240
+ grid-column: 3;
1241
+ }
1188
1242
  .nu-main-menu__item--open .nu-main-menu__shortcut,
1189
1243
  .nu-main-menu__item:not(.nu-main-menu__item--disabled):hover
1190
1244
  .nu-main-menu__shortcut {
1191
1245
  color: currentColor;
1192
1246
  }
1193
1247
  .nu-main-menu__submenu-arrow {
1248
+ grid-column: 3;
1194
1249
  justify-self: end;
1195
1250
  }
1251
+ .nu-main-menu__item-button[data-has-leading] .nu-main-menu__submenu-arrow {
1252
+ grid-column: 4;
1253
+ }
1196
1254
  .nu-masked-field {
1197
1255
  display: grid;
1198
1256
  gap: var(--nu-space-xs);
@@ -1798,10 +1856,10 @@
1798
1856
  color: var(--nu-text-accent);
1799
1857
  }
1800
1858
  .nu-report-cell--danger {
1801
- color: var(--nu-text-hotkey);
1859
+ color: var(--nu-text-danger);
1802
1860
  }
1803
1861
  .nu-report-cell--success {
1804
- color: var(--nu-text-primary);
1862
+ color: var(--nu-text-success);
1805
1863
  }
1806
1864
  .nu-search-box {
1807
1865
  display: grid;
@@ -1890,6 +1948,13 @@
1890
1948
  color: var(--nu-text-muted);
1891
1949
  font-size: 0.75rem;
1892
1950
  }
1951
+ .nu-spacer {
1952
+ display: block;
1953
+ flex: 1 1 auto;
1954
+ min-width: 0;
1955
+ min-height: 0;
1956
+ pointer-events: none;
1957
+ }
1893
1958
  .nu-spin-box {
1894
1959
  display: grid;
1895
1960
  gap: var(--nu-space-xs);
@@ -2378,7 +2443,11 @@
2378
2443
  gap: 0.5ch;
2379
2444
  min-width: 0;
2380
2445
  min-height: 0;
2381
- padding: 0.2ch 0;
2446
+ overflow: clip;
2447
+ padding: var(--nu-toolbar-inset);
2448
+ border: var(--nu-toolbar-border-width) var(--nu-toolbar-border-style)
2449
+ var(--nu-toolbar-border-color);
2450
+ background: var(--nu-toolbar-background);
2382
2451
  font-family: var(--nu-font-body);
2383
2452
  }
2384
2453
  .nu-toolbar[data-fill] {
@@ -2424,6 +2493,16 @@
2424
2493
  opacity: 0.6;
2425
2494
  cursor: not-allowed;
2426
2495
  }
2496
+ .nu-toolbar__static {
2497
+ display: inline-flex;
2498
+ align-items: center;
2499
+ justify-content: center;
2500
+ flex: none;
2501
+ }
2502
+ .nu-toolbar__static > svg {
2503
+ inline-size: var(--nu-glyph-cell-size);
2504
+ block-size: var(--nu-glyph-cell-size);
2505
+ }
2427
2506
  .nu-toolbar__button-icon,
2428
2507
  .nu-toolbar__button-caret {
2429
2508
  display: inline-flex;
@@ -2439,10 +2518,11 @@
2439
2518
  padding-left: 0.55ch;
2440
2519
  }
2441
2520
  .nu-toolbar__separator {
2442
- width: 1px;
2521
+ width: 0;
2443
2522
  align-self: stretch;
2444
2523
  margin: 0 0.35ch;
2445
- background: var(--nu-border-dark);
2524
+ border-inline-start: var(--nu-toolbar-separator-width)
2525
+ var(--nu-toolbar-separator-style) var(--nu-toolbar-separator-color);
2446
2526
  }
2447
2527
  .nu-toolbar[data-wrap] .nu-toolbar__separator {
2448
2528
  min-height: 1em;
@@ -3520,7 +3600,8 @@
3520
3600
  align-items: center;
3521
3601
  justify-content: center;
3522
3602
  min-height: var(--nu-window-title-height);
3523
- padding: 0 var(--nu-window-title-controls-width) 0 0.45rem;
3603
+ padding: 0 var(--nu-window-title-controls-width) 0
3604
+ calc(0.45rem + var(--nu-window-title-icon-width));
3524
3605
  background: var(--nu-color-title-bg);
3525
3606
  color: var(--nu-color-title-text);
3526
3607
  line-height: 1;
@@ -3534,6 +3615,24 @@
3534
3615
  text-overflow: ellipsis;
3535
3616
  white-space: nowrap;
3536
3617
  }
3618
+ .nu-window__title-icon {
3619
+ position: absolute;
3620
+ top: 0;
3621
+ bottom: 0;
3622
+ left: 0.35rem;
3623
+ display: inline-flex;
3624
+ align-items: center;
3625
+ justify-content: center;
3626
+ width: var(--nu-window-title-icon-width);
3627
+ overflow: hidden;
3628
+ color: inherit;
3629
+ }
3630
+ .nu-window__title-icon > svg,
3631
+ .nu-window__title-icon > img {
3632
+ display: block;
3633
+ max-width: 100%;
3634
+ max-height: calc(var(--nu-window-title-height) - 2px);
3635
+ }
3537
3636
  .nu-window__title-controls {
3538
3637
  position: absolute;
3539
3638
  top: 0;
@@ -3726,6 +3825,16 @@ button.nu-app-bar-item:focus-visible {
3726
3825
  outline: none;
3727
3826
  box-shadow: none;
3728
3827
  }
3828
+ .nu-window-bar__icon {
3829
+ display: inline-flex;
3830
+ align-items: center;
3831
+ justify-content: center;
3832
+ flex: none;
3833
+ inline-size: var(--nu-glyph-cell-size);
3834
+ block-size: var(--nu-glyph-cell-size);
3835
+ margin-inline-end: 0.6ch;
3836
+ color: inherit;
3837
+ }
3729
3838
  .nu-app-bar-host {
3730
3839
  position: absolute;
3731
3840
  right: 0;
@@ -15,7 +15,7 @@ type AppBarItemStaticProps = AppBarItemBaseProps & Omit<HTMLAttributes<HTMLDivEl
15
15
  export type AppBarItemProps = AppBarItemButtonProps | AppBarItemStaticProps;
16
16
  export declare function AppBarItem(props: AppBarItemProps): import("react").DetailedReactHTMLElement<{
17
17
  className: string;
18
- type: "button" | "submit" | "reset";
18
+ type: "button" | "reset" | "submit";
19
19
  defaultChecked?: boolean | undefined | undefined;
20
20
  defaultValue?: string | number | readonly string[] | undefined;
21
21
  suppressContentEditableWarning?: boolean | undefined | undefined;
@@ -1,7 +1,9 @@
1
+ import { ReactNode } from "react";
1
2
  export type WindowBarItem = {
2
3
  active?: boolean;
3
4
  domain?: string;
4
5
  id: string;
6
+ icon?: ReactNode;
5
7
  minimized?: boolean;
6
8
  title: string;
7
9
  };
@@ -11,6 +11,10 @@ export type NuManagedWindowSnapshot = {
11
11
  width?: number;
12
12
  };
13
13
  export type NuManagedWindowDefinition = {
14
+ /** Windows with the same value share their active/inactive chrome state. */
15
+ activationGroup?: string;
16
+ /** Locks pointer resizing to this width / height ratio and disables maximize. */
17
+ aspectRatio?: number;
14
18
  appModal?: boolean;
15
19
  bodyClassName?: string;
16
20
  border?: WindowBorder;
@@ -18,7 +22,13 @@ export type NuManagedWindowDefinition = {
18
22
  closeable?: boolean;
19
23
  content: ReactNode | ((controls: NuManagedWindowControls) => ReactNode);
20
24
  domain?: string;
25
+ /** Decorative visual rendered in the fixed left title-bar slot. */
26
+ icon?: ReactNode;
21
27
  maximizable?: boolean;
28
+ /** Minimum rendered height and resize bound for this window. */
29
+ minHeight?: CSSProperties["minHeight"];
30
+ /** Minimum rendered width and resize bound for this window. */
31
+ minWidth?: CSSProperties["minWidth"];
22
32
  modal?: boolean | string;
23
33
  minimizable?: boolean;
24
34
  mode?: WindowMode;
@@ -115,6 +115,8 @@ See: [Slot Customization](./SLOT_CUSTOMIZATION.md)
115
115
  docs: [Splitter](./Splitter.md)
116
116
  - `Stack`
117
117
  docs: [Stack](./Stack.md)
118
+ - `Spacer`
119
+ docs: [Spacer](./Spacer.md)
118
120
  - `ToolBar`, `ToolButton`, `ToolSeparator`
119
121
  docs: [ToolBar](./ToolBar.md)
120
122
 
@@ -35,6 +35,7 @@
35
35
  - [ReportCell](./ReportCell.md)
36
36
  - [SearchBox](./SearchBox.md)
37
37
  - [SpinBox](./SpinBox.md)
38
+ - [Spacer](./Spacer.md)
38
39
  - [Stack](./Stack.md)
39
40
  - [Splitter](./Splitter.md)
40
41
  - [TextField](./TextField.md)
package/docs/MainMenu.md CHANGED
@@ -18,6 +18,7 @@
18
18
  - `MainMenuItem`
19
19
  - `id`
20
20
  - `text`
21
+ - `icon?: ReactNode` — decorative icon in a popup menu row
21
22
  - `hotkey?`
22
23
  - `shortcut?`
23
24
  - `checked?`
@@ -28,9 +29,19 @@
28
29
  - `MainMenuDivider`
29
30
  - `id`
30
31
  - `type: "divider"`
32
+ - `MainMenuSpacer`
33
+ - `id`
34
+ - `type: "spacer"`
35
+ - Valid at the root level only; pushes following menu items to the right.
31
36
 
32
37
  ## Notes
33
38
 
34
39
  - Top-level dropdowns open below their root items.
35
- - Nested submenus open to the right.
40
+ - Nested submenus open to the right by default and automatically open to the
41
+ left only when their right edge would leave the viewport.
36
42
  - Active and hovered items use the same black selection pattern used elsewhere in the library.
43
+ - Popup-menu dividers use `--nu-menu-divider-color`,
44
+ `--nu-menu-divider-style`, and `--nu-menu-divider-width`.
45
+ - Use `{ id: "main-menu-spacer", type: "spacer" }` between root menu items to
46
+ align the following menu group to the opposite edge. Their dropdowns choose
47
+ the viewport-facing side when opened.
@@ -50,6 +50,78 @@ windowManager.openWindow({
50
50
  });
51
51
  ```
52
52
 
53
+ ## Title Icons
54
+
55
+ `openWindow(...)` and `openDialog(...)` accept `icon?: ReactNode`. It renders in
56
+ the fixed left title-bar slot, so managed dialogs use the same chrome as regular
57
+ windows. The same icon is reused in the minimized AppBar item, the MDI
58
+ `Window` menu, and the `Pick...` dialog.
59
+
60
+ ```tsx
61
+ windowManager.openDialog({
62
+ content: <NetworkSettings />,
63
+ icon: <NuGlyph name="gear" />,
64
+ title: "Network settings"
65
+ });
66
+ ```
67
+
68
+ ## Fixed Aspect Ratio
69
+
70
+ Set a positive `aspectRatio` (width / height) for image, video, map, or other
71
+ fixed-ratio content. Pointer resizing keeps the ratio, combines `minWidth` and
72
+ `minHeight` into a ratio-consistent minimum, and disables maximizing the
73
+ managed window.
74
+
75
+ ```tsx
76
+ windowManager.openWindow({
77
+ aspectRatio: 178 / 704,
78
+ content: <VirtualRemote />,
79
+ minWidth: "11rem",
80
+ style: { height: "50rem", width: "13rem" },
81
+ title: "Remote"
82
+ });
83
+ ```
84
+
85
+ ## Linked Activation
86
+
87
+ Set the same `activationGroup` on managed windows that represent one logical
88
+ workspace. Activating either one gives every visible member of that group the
89
+ active window chrome. Activating a window outside the group makes all members
90
+ inactive again. This only links activation visuals; it does not dock, move, or
91
+ resize the windows together.
92
+
93
+ ```tsx
94
+ windowManager.openWindow({
95
+ activationGroup: "receiver-42",
96
+ content: <ReceiverOverview />,
97
+ title: "Receiver overview"
98
+ });
99
+
100
+ windowManager.openWindow({
101
+ activationGroup: "receiver-42",
102
+ content: <ReceiverDiagnostics />,
103
+ title: "Receiver diagnostics"
104
+ });
105
+ ```
106
+
107
+ App-modal dialogs remain the sole active surface while open, regardless of an
108
+ activation group.
109
+
110
+ ## Size Limits
111
+
112
+ Managed windows accept `minWidth` and `minHeight` directly. They override the
113
+ provider's default minimum width (`26rem` for a window and `22rem` for a
114
+ dialog) and constrain pointer resizing as well as CSS layout.
115
+
116
+ ```tsx
117
+ windowManager.openWindow({
118
+ content: <CompactLog />,
119
+ minHeight: "10rem",
120
+ minWidth: "18rem",
121
+ title: "Compact log"
122
+ });
123
+ ```
124
+
53
125
  ## Helper Dialogs
54
126
 
55
127
  The same manager also provides async helper dialogs:
package/docs/PopupMenu.md CHANGED
@@ -40,6 +40,8 @@ const popupMenu = usePopupMenu();
40
40
  ## Notes
41
41
 
42
42
  - Popup menus render through a portal and are not clipped by local overflow containers.
43
+ - Nested popup-menu levels open to the right by default and flip left only when
44
+ they would overflow the viewport.
43
45
  - `openFromContextMenu(event)` carries the event target into the portal, so
44
46
  context menus inherit tokens from the nearest `NuThemeProvider`. Pass the
45
47
  optional `themeSource` to `openAtPoint(...)` when opening one manually.
package/docs/Spacer.md ADDED
@@ -0,0 +1,41 @@
1
+ # Spacer
2
+
3
+ `Spacer` fills unused space in a flex layout, moving all following controls to
4
+ the opposite edge. It is decorative and is hidden from assistive technology.
5
+
6
+ ## Usage
7
+
8
+ ```tsx
9
+ <ToolBar>
10
+ <ToolButton>&Open</ToolButton>
11
+ <Spacer />
12
+ <ToolButton>&Help</ToolButton>
13
+ </ToolBar>
14
+ ```
15
+
16
+ It works in `ToolBar`, `Stack direction="row"`, and a window `statusBar`:
17
+
18
+ ```tsx
19
+ <Window
20
+ statusBar={
21
+ <>
22
+ <StatusBarItem>F2 Save</StatusBarItem>
23
+ <Spacer />
24
+ <StatusBarItem>Ready</StatusBarItem>
25
+ </>
26
+ }
27
+ title="Editor"
28
+ />
29
+ ```
30
+
31
+ For a root `MainMenu`, use the menu model equivalent:
32
+
33
+ ```tsx
34
+ const items: MainMenuNode[] = [
35
+ { id: "file", text: "&File" },
36
+ { id: "window", text: "&Window" },
37
+ { id: "menu-spacer", type: "spacer" },
38
+ { id: "profile", text: "&Profile" },
39
+ { id: "about", text: "&About" }
40
+ ];
41
+ ```
@@ -29,3 +29,4 @@
29
29
  - `StatusBarItem` is layout-only.
30
30
  - It does not render its own border or segmented chrome.
31
31
  - The host controls the visual content inside the item.
32
+ - Insert `Spacer` between items to pin the following status controls to the end.
@@ -61,6 +61,15 @@ If a component needs a new reusable visual value, add it there first instead of
61
61
  - `--nu-control-height`
62
62
  - `--nu-frame-thickness`
63
63
  - `--nu-rule-thickness`
64
+ - Toolbar and menu dividers:
65
+ - `--nu-toolbar-background`
66
+ - `--nu-toolbar-inset`
67
+ - `--nu-toolbar-border-color`, `--nu-toolbar-border-style`,
68
+ `--nu-toolbar-border-width`
69
+ - `--nu-toolbar-separator-color`, `--nu-toolbar-separator-style`,
70
+ `--nu-toolbar-separator-width`
71
+ - `--nu-menu-divider-color`, `--nu-menu-divider-style`,
72
+ `--nu-menu-divider-width`
64
73
  - Button mechanics:
65
74
  - `--nu-button-shadow-x`
66
75
  - `--nu-button-shadow-y`
package/docs/ToolBar.md CHANGED
@@ -7,12 +7,13 @@ For the same button behavior outside a toolbar container, use [CommandButton](./
7
7
  ## Usage
8
8
 
9
9
  ```tsx
10
- <ToolBar>
10
+ <ToolBar startContent={<NuGlyph aria-hidden name="folder" />}>
11
11
  <ToolButton icon="folder">&Scan</ToolButton>
12
12
  <ToolButton icon="star" pressed>
13
13
  &Watch
14
14
  </ToolButton>
15
15
  <ToolSeparator />
16
+ <Spacer />
16
17
  <ToolDropButton
17
18
  icon="folder"
18
19
  menuItems={[
@@ -32,20 +33,32 @@ For the same button behavior outside a toolbar container, use [CommandButton](./
32
33
  - `ToolButton`
33
34
  - `ToolDropButton`
34
35
  - `ToolSeparator`
36
+ - `Spacer`
35
37
 
36
38
  ## Key Props
37
39
 
38
40
  - `fill?: boolean`
39
41
  - `wrap?: boolean`
42
+ - `startContent?: ReactNode`
43
+ - `endContent?: ReactNode`
40
44
  - `slotStyles`
41
45
  - `slotClassNames`
42
46
 
43
47
  ## Notes
44
48
 
45
- - `ToolBar` is layout-only and defaults to `fill={true}`.
49
+ - `ToolBar` defaults to `fill={true}` and uses `--nu-toolbar-background` for
50
+ its surface.
51
+ - `startContent` and `endContent` render static React content before and after
52
+ the controls. Use them for decorative icons or compact status text, not for
53
+ actions that need toolbar keyboard semantics.
46
54
  - `wrap={true}` lets tools continue on the next row when the container is too narrow.
47
55
  - `ToolButton` supports `toggled` for toggle-style tools. `pressed` is kept as a legacy alias through the shared command-button layer.
48
56
  - `ToolButton` also supports `icon` and optional `dropdown`.
49
57
  - `ToolDropButton` is a convenience wrapper for `ToolButton dropdown`.
50
58
  - If `menuItems` are provided, `ToolDropButton` opens `PopupMenu` automatically and reports selection through `onMenuItemSelect`.
51
59
  - `ToolSeparator` is decorative and should only be used between tools.
60
+ - Toolbar chrome is themeable through `--nu-toolbar-border-color`,
61
+ `--nu-toolbar-border-style`, and `--nu-toolbar-border-width`; separators
62
+ use the corresponding `--nu-toolbar-separator-*` tokens.
63
+ - `--nu-toolbar-inset` controls Toolbar padding on all four sides.
64
+ - `Spacer` fills free space and moves following tools to the opposite edge.
package/docs/Window.md CHANGED
@@ -12,6 +12,7 @@
12
12
 
13
13
  ```tsx
14
14
  <Window
15
+ icon={<NuGlyph name="folder" />}
15
16
  title="Activity Log"
16
17
  mode="window"
17
18
  statusBar={
@@ -30,11 +31,16 @@
30
31
  - `title: string`
31
32
  - `mode?: "dialog" | "window"`
32
33
  - `border?: "single" | "double"`
34
+ - `icon?: ReactNode` — decorative visual in the fixed left title-bar slot
33
35
  - `minimized?: boolean`
34
36
  - `maximized?: boolean`
35
37
  - `closeable?: boolean`
36
38
  - `draggable?: boolean`
37
39
  - `resizable?: boolean`
40
+ - `aspectRatio?: number` — positive width / height ratio; locks pointer resize
41
+ and suppresses the maximize control
42
+ - `minWidth?: number | string` — defaults to `240px` for a standalone window
43
+ - `minHeight?: number | string` — defaults to `120px` for a standalone window
38
44
  - `scrollable?: boolean`
39
45
  - `statusBar?: ReactNode`
40
46
  - `titleButtons?: WindowTitleButtonDefinition[]`
@@ -45,9 +51,22 @@
45
51
  - `onSizeChange?(size)`
46
52
  - `onActivate?()`
47
53
 
54
+ `activationGroup?: string` is available on a managed window definition passed
55
+ to `useNuWindowManager().openWindow(...)`; it is resolved by
56
+ `NuWindowProvider`, rather than by a standalone `Window` instance. See
57
+ [NuWindowProvider](./NuWindowProvider.md#linked-activation).
58
+
48
59
  ## Notes
49
60
 
50
61
  - Drag and resize are implemented with pointer events and local DOM updates for smoother motion.
51
62
  - The public `WindowTitleButton` and `useWindowTitleButtons()` helpers support custom title-bar controls.
63
+ - The left title-bar slot is always reserved. Pass `icon` to show a `NuGlyph`,
64
+ Font Awesome icon, SVG, or another React node without shifting the title.
52
65
  - `StatusBarItem` only provides placement semantics (`grow`, `align`) and does not enforce its own border or chrome.
53
66
  - Plain string `statusBar` still works for simple status lines.
67
+ - `minWidth` and `minHeight` are applied as CSS limits and as the lower bounds
68
+ for pointer resizing. A managed window may also specify them in its
69
+ `openWindow(...)` definition.
70
+ - With `aspectRatio`, resizing follows whichever pointer axis has the greater
71
+ ratio-adjusted movement. The other dimension is derived from the ratio, and
72
+ the effective minimum remains ratio-consistent.
package/docs/WindowBar.md CHANGED
@@ -17,8 +17,11 @@
17
17
  - Marks the active window
18
18
  - Groups windows by `domain`
19
19
  - Opens a picker dialog when a grouped domain is clicked
20
+ - Shows each managed window's `icon` beside its title; grouped entries use the
21
+ active window's icon when one is available
20
22
 
21
23
  ## Notes
22
24
 
23
25
  - Grouping is driven by `NuManagedWindowDefinition.domain`.
24
26
  - Grouped pickers use the shared MDI-style window picker dialog logic.
27
+ - The MDI `Window` menu and `Pick...` dialog reuse the same managed-window icon.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deadragdoll/reactnu",
3
- "version": "0.1.52",
3
+ "version": "0.1.73",
4
4
  "private": false,
5
5
  "description": "React components with a precise DOS-era utility interface.",
6
6
  "license": "MIT",