@deadragdoll/reactnu 0.1.17 → 0.1.24
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/components/IconGrid/IconGrid.types.d.ts +35 -0
- package/dist/components/IconGrid/NuIconGrid.d.ts +7 -0
- package/dist/components/IconGrid/NuIconProvider.d.ts +6 -0
- package/dist/components/IconGrid/iconContext.d.ts +10 -0
- package/dist/components/IconGrid/index.d.ts +4 -0
- package/dist/index.cjs +1091 -677
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1109 -688
- package/dist/styles.css +68 -1
- package/docs/API_REFERENCE.md +4 -0
- package/docs/COMPONENT_INDEX.md +1 -0
- package/docs/Desktop.md +13 -0
- package/docs/IconGrid.md +93 -0
- package/package.json +1 -1
package/dist/styles.css
CHANGED
|
@@ -542,6 +542,73 @@
|
|
|
542
542
|
.nu-info__accent[data-upper] {
|
|
543
543
|
text-transform: uppercase;
|
|
544
544
|
}
|
|
545
|
+
.nu-icon-grid {
|
|
546
|
+
position: relative;
|
|
547
|
+
min-width: 0;
|
|
548
|
+
min-height: 0;
|
|
549
|
+
width: 100%;
|
|
550
|
+
height: 100%;
|
|
551
|
+
overflow: hidden;
|
|
552
|
+
user-select: none;
|
|
553
|
+
}
|
|
554
|
+
.nu-icon-grid__icon {
|
|
555
|
+
position: absolute;
|
|
556
|
+
display: grid;
|
|
557
|
+
grid-template-rows: 3.25rem minmax(0, 2.2em);
|
|
558
|
+
justify-items: center;
|
|
559
|
+
width: 6rem;
|
|
560
|
+
height: 6rem;
|
|
561
|
+
padding: 0.25rem;
|
|
562
|
+
border: 1px solid transparent;
|
|
563
|
+
background: transparent;
|
|
564
|
+
color: var(--nu-text-primary);
|
|
565
|
+
font: inherit;
|
|
566
|
+
line-height: 1.1;
|
|
567
|
+
text-align: center;
|
|
568
|
+
cursor: default;
|
|
569
|
+
touch-action: none;
|
|
570
|
+
}
|
|
571
|
+
.nu-icon-grid__icon:focus-visible,
|
|
572
|
+
.nu-icon-grid__icon[data-selected] {
|
|
573
|
+
border-color: var(--nu-border-light);
|
|
574
|
+
outline: 1px solid var(--nu-border-dark);
|
|
575
|
+
outline-offset: -3px;
|
|
576
|
+
background: var(--nu-color-title-bg);
|
|
577
|
+
color: var(--nu-text-inverse);
|
|
578
|
+
}
|
|
579
|
+
.nu-icon-grid__icon[data-dragging] {
|
|
580
|
+
z-index: 1;
|
|
581
|
+
}
|
|
582
|
+
.nu-icon-grid__icon:disabled {
|
|
583
|
+
opacity: 0.6;
|
|
584
|
+
}
|
|
585
|
+
.nu-icon-grid__glyph {
|
|
586
|
+
display: inline-flex;
|
|
587
|
+
align-items: center;
|
|
588
|
+
justify-content: center;
|
|
589
|
+
width: 3rem;
|
|
590
|
+
height: 3rem;
|
|
591
|
+
color: var(--nu-text-hotkey);
|
|
592
|
+
}
|
|
593
|
+
.nu-icon-grid__glyph > img,
|
|
594
|
+
.nu-icon-grid__glyph > svg {
|
|
595
|
+
display: block;
|
|
596
|
+
max-width: 100%;
|
|
597
|
+
max-height: 100%;
|
|
598
|
+
width: 100%;
|
|
599
|
+
height: 100%;
|
|
600
|
+
object-fit: contain;
|
|
601
|
+
}
|
|
602
|
+
.nu-icon-grid__label {
|
|
603
|
+
display: -webkit-box;
|
|
604
|
+
max-width: 100%;
|
|
605
|
+
overflow: hidden;
|
|
606
|
+
overflow-wrap: anywhere;
|
|
607
|
+
text-overflow: ellipsis;
|
|
608
|
+
-webkit-box-orient: vertical;
|
|
609
|
+
-webkit-line-clamp: 2;
|
|
610
|
+
line-clamp: 2;
|
|
611
|
+
}
|
|
545
612
|
.nu-listbox {
|
|
546
613
|
flex: 1 1 auto;
|
|
547
614
|
align-self: stretch;
|
|
@@ -3318,7 +3385,7 @@
|
|
|
3318
3385
|
}
|
|
3319
3386
|
.nu-window {
|
|
3320
3387
|
--nu-window-title-controls-width: 7.8ch;
|
|
3321
|
-
--nu-window-title-height: 1em;
|
|
3388
|
+
--nu-window-title-height: calc(1em + 3px);
|
|
3322
3389
|
position: relative;
|
|
3323
3390
|
display: flex;
|
|
3324
3391
|
flex-direction: column;
|
package/docs/API_REFERENCE.md
CHANGED
|
@@ -39,6 +39,8 @@ See: [Slot Customization](./SLOT_CUSTOMIZATION.md)
|
|
|
39
39
|
- `useNuWindowManager()`
|
|
40
40
|
opens, updates, activates, and closes managed windows
|
|
41
41
|
also exposes `showMessageBox(...)` and `showInputBox(...)`
|
|
42
|
+
- `useNuIconManager()`
|
|
43
|
+
manages icons inside a `NuIconProvider`
|
|
42
44
|
- `usePopupMenu()`
|
|
43
45
|
anchor/open helper for `PopupMenu`
|
|
44
46
|
- `useWindowMenu()`
|
|
@@ -113,6 +115,8 @@ See: [Slot Customization](./SLOT_CUSTOMIZATION.md)
|
|
|
113
115
|
docs: [MainMenu](./MainMenu.md)
|
|
114
116
|
- `PopupMenu`
|
|
115
117
|
docs: [PopupMenu](./PopupMenu.md)
|
|
118
|
+
- `NuIconProvider`, `NuIconGrid`
|
|
119
|
+
docs: [Icon Grid](./IconGrid.md)
|
|
116
120
|
|
|
117
121
|
## Windowing And Desktop Chrome
|
|
118
122
|
|
package/docs/COMPONENT_INDEX.md
CHANGED
package/docs/Desktop.md
CHANGED
|
@@ -21,6 +21,19 @@
|
|
|
21
21
|
- `appBarContent?: ReactNode`
|
|
22
22
|
- standard `div` props
|
|
23
23
|
|
|
24
|
+
## Application icons
|
|
25
|
+
|
|
26
|
+
`NuDesktop` does not own a separate icon implementation. Compose a reusable
|
|
27
|
+
`NuIconProvider` and `NuIconGrid` inside the desktop workspace instead. The
|
|
28
|
+
same pair can also live inside a `Window`.
|
|
29
|
+
|
|
30
|
+
Use `NuIconGrid`'s `contextMenuItems` callback for a desktop background menu.
|
|
31
|
+
It receives `useNuIconManager()`'s methods, so an `Arrange icons` submenu can
|
|
32
|
+
call `arrangeIcons("columns")`, `arrangeIcons("rows")`, or
|
|
33
|
+
`arrangeIcons("name")`.
|
|
34
|
+
|
|
35
|
+
See [Icon Grid](./IconGrid.md) for the full API and interaction contract.
|
|
36
|
+
|
|
24
37
|
## Notes
|
|
25
38
|
|
|
26
39
|
- The desktop owns the browser viewport and is intended to behave like a bounded screen.
|
package/docs/IconGrid.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Icon Grid
|
|
2
|
+
|
|
3
|
+
`NuIconProvider` owns a mutable collection of application icons. Place a
|
|
4
|
+
`NuIconGrid` anywhere inside it: on the desktop, in a `Window`, or in another
|
|
5
|
+
bounded surface.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import {
|
|
9
|
+
NuIconGrid,
|
|
10
|
+
NuIconProvider,
|
|
11
|
+
useNuIconManager
|
|
12
|
+
} from "@deadragdoll/reactnu";
|
|
13
|
+
|
|
14
|
+
function Applications() {
|
|
15
|
+
return (
|
|
16
|
+
<NuIconProvider
|
|
17
|
+
defaultIcons={[
|
|
18
|
+
{
|
|
19
|
+
id: "diagnostics",
|
|
20
|
+
icon: "/icons/diagnostics.svg",
|
|
21
|
+
label: "&Diagnostics",
|
|
22
|
+
onDoubleClick: () => openDiagnostics()
|
|
23
|
+
}
|
|
24
|
+
]}
|
|
25
|
+
>
|
|
26
|
+
<NuIconGrid
|
|
27
|
+
defaultArrangeMode="columns"
|
|
28
|
+
contextMenuItems={(icons) => [
|
|
29
|
+
{
|
|
30
|
+
id: "arrange-icons",
|
|
31
|
+
items: [
|
|
32
|
+
{
|
|
33
|
+
id: "arrange-by-name",
|
|
34
|
+
text: "&By name",
|
|
35
|
+
onSelect: () => icons.arrangeIcons("name")
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
text: "&Arrange icons"
|
|
39
|
+
}
|
|
40
|
+
]}
|
|
41
|
+
/>
|
|
42
|
+
</NuIconProvider>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## API
|
|
48
|
+
|
|
49
|
+
`NuIconProvider`
|
|
50
|
+
|
|
51
|
+
- `defaultIcons?: NuIconDefinition[]` seeds its internal collection. IDs should
|
|
52
|
+
be unique; omitted IDs are generated.
|
|
53
|
+
- Icon `icon` accepts a URL string for SVG, PNG, or JPEG assets, or inline
|
|
54
|
+
React content such as an `<svg>`.
|
|
55
|
+
|
|
56
|
+
`NuIconGrid`
|
|
57
|
+
|
|
58
|
+
- `contextMenuItems` accepts ordinary `MainMenuNode[]` or a callback receiving
|
|
59
|
+
the icon manager. Use the callback for a background menu such as Arrange
|
|
60
|
+
icons.
|
|
61
|
+
- `defaultArrangeMode="columns" | "rows" | "name"` arranges seeded icons
|
|
62
|
+
once, after the grid measures a non-zero available area. This prevents icons
|
|
63
|
+
from initially landing outside a bounded `Window`.
|
|
64
|
+
|
|
65
|
+
`useNuIconManager()`
|
|
66
|
+
|
|
67
|
+
- `addIcon(definition)` returns the new icon ID.
|
|
68
|
+
- `updateIcon(id, patch)`, `removeIcon(id)`, `moveIcon(id, position)`, and
|
|
69
|
+
`selectIcon(id | null)` update the provider collection.
|
|
70
|
+
- `arrangeIcons("columns" | "rows" | "name")` lays out the current icons.
|
|
71
|
+
|
|
72
|
+
Each icon can have `onClick`, `onDoubleClick`, `onContextMenu`,
|
|
73
|
+
`onPositionChange`, and its own `contextMenuItems`.
|
|
74
|
+
|
|
75
|
+
## Interaction and accessibility
|
|
76
|
+
|
|
77
|
+
- Drag icons to move them inside the grid; their resulting positions remain in
|
|
78
|
+
the provider for the lifetime of that provider.
|
|
79
|
+
- A click selects an icon. Enter and Space activate its normal button action.
|
|
80
|
+
- Right-click opens the icon menu; `Shift+F10` and the Context Menu key open it
|
|
81
|
+
from the keyboard.
|
|
82
|
+
- Right-click the grid background for the grid context menu, such as Arrange
|
|
83
|
+
icons. An `onContextMenu` handler may call `preventDefault()` to replace it.
|
|
84
|
+
- Labels wrap to two lines. Longer labels receive an ellipsis; long unbroken
|
|
85
|
+
words are wrapped instead of overflowing their icon cell.
|
|
86
|
+
|
|
87
|
+
## Persistence
|
|
88
|
+
|
|
89
|
+
The provider keeps icon positions for its mounted lifetime. To restore a layout
|
|
90
|
+
after a reload, save a position from `onPositionChange` and pass it back as the
|
|
91
|
+
icon's `position` in `defaultIcons` on the next mount. Call `arrangeIcons(...)`
|
|
92
|
+
only for an explicit user action, rather than on every render, so a saved layout
|
|
93
|
+
is not overwritten.
|