@liiift-studio/mac-os9-ui 0.2.21 → 0.2.23
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/fonts/65e59833.woff +0 -0
- package/dist/fonts/6fb9ec6b.woff +0 -0
- package/dist/fonts/9f492b6d.woff2 +0 -0
- package/dist/fonts/e45380e5.woff2 +0 -0
- package/dist/index.cjs +100 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +50 -9
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +42 -2
- package/dist/index.js +100 -27
- package/dist/index.js.map +1 -1
- package/dist/types/components/MenuBar/MenuDropdown.d.ts +36 -0
- package/dist/types/components/MenuBar/MenuItem.d.ts +4 -0
- package/dist/types/components/MenuBar/index.d.ts +1 -0
- package/dist/types/index.d.ts +1 -1
- package/package.json +1 -1
- package/dist/fonts/2bc2468e.woff +0 -0
- package/dist/fonts/3306dfd5.woff +0 -0
- package/dist/fonts/b9e24cd1.woff2 +0 -0
- package/dist/fonts/cf596b2d.woff2 +0 -0
- package/dist/fonts/pixelOperator/PixelOperator-Bold.ttf +0 -0
- package/dist/fonts/pixelOperator/PixelOperator.ttf +0 -0
package/dist/index.js
CHANGED
|
@@ -913,7 +913,7 @@ const Dialog = forwardRef(({ open = false, onClose, closeOnBackdropClick = true,
|
|
|
913
913
|
});
|
|
914
914
|
Dialog.displayName = 'Dialog';
|
|
915
915
|
|
|
916
|
-
var styles$4 = {"menuBar":"MenuBar-module_menuBar","leftContent":"MenuBar-module_leftContent","menusContainer":"MenuBar-module_menusContainer","menuContainer":"MenuBar-module_menuContainer","rightContent":"MenuBar-module_rightContent","menuButton":"MenuBar-module_menuButton","menuButton--disabled":"MenuBar-module_menuButton--disabled","menuButton--open":"MenuBar-module_menuButton--open","dropdown":"MenuBar-module_dropdown"};
|
|
916
|
+
var styles$4 = {"menuBar":"MenuBar-module_menuBar","leftContent":"MenuBar-module_leftContent","menusContainer":"MenuBar-module_menusContainer","menuContainer":"MenuBar-module_menuContainer","rightContent":"MenuBar-module_rightContent","menuButton":"MenuBar-module_menuButton","menuButton--disabled":"MenuBar-module_menuButton--disabled","menuButton--open":"MenuBar-module_menuButton--open","dropdown":"MenuBar-module_dropdown","dropdown--right":"MenuBar-module_dropdown--right"};
|
|
917
917
|
|
|
918
918
|
/**
|
|
919
919
|
* Mac OS 9 style MenuBar component
|
|
@@ -970,41 +970,56 @@ var styles$4 = {"menuBar":"MenuBar-module_menuBar","leftContent":"MenuBar-module
|
|
|
970
970
|
const MenuBar = forwardRef(({ menus, openMenuIndex, onMenuOpen, onMenuClose, className = '', dropdownClassName = '', leftContent, rightContent, }, ref) => {
|
|
971
971
|
const [menuBarElement, setMenuBarElement] = useState(null);
|
|
972
972
|
const [focusedIndex, setFocusedIndex] = useState(-1);
|
|
973
|
+
const [internalOpenIndex, setInternalOpenIndex] = useState(undefined);
|
|
974
|
+
const isControlled = openMenuIndex !== undefined;
|
|
975
|
+
const activeOpenIndex = isControlled ? openMenuIndex : internalOpenIndex;
|
|
976
|
+
const handleMenuOpenInternal = (index) => {
|
|
977
|
+
if (!isControlled) {
|
|
978
|
+
setInternalOpenIndex(index);
|
|
979
|
+
}
|
|
980
|
+
onMenuOpen?.(index);
|
|
981
|
+
};
|
|
982
|
+
const handleMenuCloseInternal = () => {
|
|
983
|
+
if (!isControlled) {
|
|
984
|
+
setInternalOpenIndex(undefined);
|
|
985
|
+
}
|
|
986
|
+
onMenuClose?.();
|
|
987
|
+
};
|
|
973
988
|
// Handle click outside to close menu
|
|
974
989
|
useEffect(() => {
|
|
975
|
-
if (
|
|
990
|
+
if (activeOpenIndex === undefined || !menuBarElement)
|
|
976
991
|
return;
|
|
977
992
|
const handleClickOutside = (event) => {
|
|
978
993
|
if (menuBarElement && !menuBarElement.contains(event.target)) {
|
|
979
|
-
|
|
994
|
+
handleMenuCloseInternal();
|
|
980
995
|
}
|
|
981
996
|
};
|
|
982
997
|
document.addEventListener('mousedown', handleClickOutside);
|
|
983
998
|
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
984
|
-
}, [
|
|
999
|
+
}, [activeOpenIndex, onMenuClose, menuBarElement, isControlled]);
|
|
985
1000
|
// Handle Escape key to close menu
|
|
986
1001
|
useEffect(() => {
|
|
987
|
-
if (
|
|
1002
|
+
if (activeOpenIndex === undefined)
|
|
988
1003
|
return;
|
|
989
1004
|
const handleEscape = (event) => {
|
|
990
1005
|
if (event.key === 'Escape') {
|
|
991
1006
|
event.preventDefault();
|
|
992
|
-
|
|
1007
|
+
handleMenuCloseInternal();
|
|
993
1008
|
}
|
|
994
1009
|
};
|
|
995
1010
|
document.addEventListener('keydown', handleEscape);
|
|
996
1011
|
return () => document.removeEventListener('keydown', handleEscape);
|
|
997
|
-
}, [
|
|
1012
|
+
}, [activeOpenIndex, onMenuClose, isControlled]);
|
|
998
1013
|
// Handle keyboard navigation
|
|
999
1014
|
const handleKeyDown = useCallback((event) => {
|
|
1000
1015
|
switch (event.key) {
|
|
1001
1016
|
case 'ArrowLeft':
|
|
1002
1017
|
event.preventDefault();
|
|
1003
|
-
if (
|
|
1018
|
+
if (activeOpenIndex !== undefined) {
|
|
1004
1019
|
// Move to previous menu
|
|
1005
|
-
const prevIndex =
|
|
1020
|
+
const prevIndex = activeOpenIndex > 0 ? activeOpenIndex - 1 : menus.length - 1;
|
|
1006
1021
|
if (!menus[prevIndex]?.disabled) {
|
|
1007
|
-
|
|
1022
|
+
handleMenuOpenInternal(prevIndex);
|
|
1008
1023
|
}
|
|
1009
1024
|
}
|
|
1010
1025
|
else if (focusedIndex > 0) {
|
|
@@ -1013,11 +1028,11 @@ const MenuBar = forwardRef(({ menus, openMenuIndex, onMenuOpen, onMenuClose, cla
|
|
|
1013
1028
|
break;
|
|
1014
1029
|
case 'ArrowRight':
|
|
1015
1030
|
event.preventDefault();
|
|
1016
|
-
if (
|
|
1031
|
+
if (activeOpenIndex !== undefined) {
|
|
1017
1032
|
// Move to next menu
|
|
1018
|
-
const nextIndex =
|
|
1033
|
+
const nextIndex = activeOpenIndex < menus.length - 1 ? activeOpenIndex + 1 : 0;
|
|
1019
1034
|
if (!menus[nextIndex]?.disabled) {
|
|
1020
|
-
|
|
1035
|
+
handleMenuOpenInternal(nextIndex);
|
|
1021
1036
|
}
|
|
1022
1037
|
}
|
|
1023
1038
|
else if (focusedIndex < menus.length - 1) {
|
|
@@ -1026,18 +1041,18 @@ const MenuBar = forwardRef(({ menus, openMenuIndex, onMenuOpen, onMenuClose, cla
|
|
|
1026
1041
|
break;
|
|
1027
1042
|
case 'ArrowDown':
|
|
1028
1043
|
event.preventDefault();
|
|
1029
|
-
if (
|
|
1044
|
+
if (activeOpenIndex === undefined && focusedIndex >= 0) {
|
|
1030
1045
|
// Open the focused menu (only if it's a dropdown)
|
|
1031
1046
|
const menu = menus[focusedIndex];
|
|
1032
1047
|
if (!menu?.disabled && menu?.type !== 'link') {
|
|
1033
|
-
|
|
1048
|
+
handleMenuOpenInternal(focusedIndex);
|
|
1034
1049
|
}
|
|
1035
1050
|
}
|
|
1036
1051
|
break;
|
|
1037
1052
|
case 'Enter':
|
|
1038
1053
|
case ' ':
|
|
1039
1054
|
event.preventDefault();
|
|
1040
|
-
if (
|
|
1055
|
+
if (activeOpenIndex === undefined && focusedIndex >= 0) {
|
|
1041
1056
|
const menu = menus[focusedIndex];
|
|
1042
1057
|
if (!menu?.disabled) {
|
|
1043
1058
|
if (menu.type === 'link') {
|
|
@@ -1046,13 +1061,13 @@ const MenuBar = forwardRef(({ menus, openMenuIndex, onMenuOpen, onMenuClose, cla
|
|
|
1046
1061
|
}
|
|
1047
1062
|
else {
|
|
1048
1063
|
// Open the focused dropdown menu
|
|
1049
|
-
|
|
1064
|
+
handleMenuOpenInternal(focusedIndex);
|
|
1050
1065
|
}
|
|
1051
1066
|
}
|
|
1052
1067
|
}
|
|
1053
1068
|
break;
|
|
1054
1069
|
}
|
|
1055
|
-
}, [
|
|
1070
|
+
}, [activeOpenIndex, focusedIndex, menus, onMenuOpen, onMenuClose, isControlled]);
|
|
1056
1071
|
// Handle menu button click
|
|
1057
1072
|
const handleMenuClick = (index) => {
|
|
1058
1073
|
const menu = menus[index];
|
|
@@ -1063,13 +1078,13 @@ const MenuBar = forwardRef(({ menus, openMenuIndex, onMenuOpen, onMenuClose, cla
|
|
|
1063
1078
|
menu.onClick?.();
|
|
1064
1079
|
return;
|
|
1065
1080
|
}
|
|
1066
|
-
if (
|
|
1081
|
+
if (activeOpenIndex === index) {
|
|
1067
1082
|
// Clicking the same menu closes it
|
|
1068
|
-
|
|
1083
|
+
handleMenuCloseInternal();
|
|
1069
1084
|
}
|
|
1070
1085
|
else {
|
|
1071
1086
|
// Open the clicked menu
|
|
1072
|
-
|
|
1087
|
+
handleMenuOpenInternal(index);
|
|
1073
1088
|
}
|
|
1074
1089
|
};
|
|
1075
1090
|
// Class names
|
|
@@ -1086,7 +1101,7 @@ const MenuBar = forwardRef(({ menus, openMenuIndex, onMenuOpen, onMenuClose, cla
|
|
|
1086
1101
|
}
|
|
1087
1102
|
}, [ref]);
|
|
1088
1103
|
return (jsxs("div", { ref: handleRef, className: menuBarClassNames, role: "menubar", onKeyDown: handleKeyDown, children: [leftContent && (jsx("div", { className: styles$4.leftContent, children: leftContent })), jsx("div", { className: styles$4.menusContainer, children: menus.map((menu, index) => {
|
|
1089
|
-
const isOpen =
|
|
1104
|
+
const isOpen = activeOpenIndex === index;
|
|
1090
1105
|
const isDropdown = menu.type !== 'link';
|
|
1091
1106
|
const menuButtonClassNames = [
|
|
1092
1107
|
styles$4.menuButton,
|
|
@@ -1105,14 +1120,14 @@ const MenuBar = forwardRef(({ menus, openMenuIndex, onMenuOpen, onMenuClose, cla
|
|
|
1105
1120
|
}, onFocus: () => setFocusedIndex(index), onBlur: () => setFocusedIndex(-1), "aria-disabled": menu.disabled, children: jsx("h3", { children: menu.label }) }) }, index));
|
|
1106
1121
|
}
|
|
1107
1122
|
// Standard dropdown menu or link without href
|
|
1108
|
-
return (jsxs("div", { className: styles$4.menuContainer, children: [jsx("button", { type: "button", className: menuButtonClassNames, onClick: () => handleMenuClick(index), onFocus: () => setFocusedIndex(index), onBlur: () => setFocusedIndex(-1), disabled: menu.disabled, "aria-haspopup": isDropdown ? 'true' : undefined, "aria-expanded": isOpen, "aria-disabled": menu.disabled, children: menu.label }), isOpen && isDropdown && menu.items && (jsx("div", { className: dropdownClassNames, role: "menu", children: menu.items }))] }, index));
|
|
1123
|
+
return (jsxs("div", { className: styles$4.menuContainer, children: [jsx("button", { type: "button", className: menuButtonClassNames, onClick: () => handleMenuClick(index), onFocus: () => setFocusedIndex(index), onBlur: () => setFocusedIndex(-1), disabled: menu.disabled, "aria-haspopup": isDropdown ? 'true' : undefined, "aria-expanded": isOpen, "aria-disabled": menu.disabled, children: jsx("h3", { children: menu.label }) }), isOpen && isDropdown && menu.items && (jsx("div", { className: dropdownClassNames, role: "menu", children: menu.items }))] }, index));
|
|
1109
1124
|
}) }), rightContent && (jsx("div", { className: styles$4.rightContent, children: Array.isArray(rightContent)
|
|
1110
1125
|
? rightContent.map((item, index) => (jsx(React.Fragment, { children: item }, index)))
|
|
1111
1126
|
: rightContent }))] }));
|
|
1112
1127
|
});
|
|
1113
1128
|
MenuBar.displayName = 'MenuBar';
|
|
1114
1129
|
|
|
1115
|
-
var styles$3 = {"menuItem":"MenuItem-module_menuItem","menuItem--disabled":"MenuItem-module_menuItem--disabled","menuItem--selected":"MenuItem-module_menuItem--selected","menuItem--separator":"MenuItem-module_menuItem--separator","checkmark":"MenuItem-module_checkmark","icon":"MenuItem-module_icon","label":"MenuItem-module_label","shortcut":"MenuItem-module_shortcut","submenuArrow":"MenuItem-module_submenuArrow","separatorLine":"MenuItem-module_separatorLine"};
|
|
1130
|
+
var styles$3 = {"menuItem":"MenuItem-module_menuItem","menuItem--disabled":"MenuItem-module_menuItem--disabled","menuItem--selected":"MenuItem-module_menuItem--selected","menuItem--separator":"MenuItem-module_menuItem--separator","checkmark":"MenuItem-module_checkmark","icon":"MenuItem-module_icon","label":"MenuItem-module_label","shortcut":"MenuItem-module_shortcut","submenuArrow":"MenuItem-module_submenuArrow","submenu":"MenuItem-module_submenu","separatorLine":"MenuItem-module_separatorLine"};
|
|
1116
1131
|
|
|
1117
1132
|
/**
|
|
1118
1133
|
* Mac OS 9 style MenuItem component
|
|
@@ -1151,7 +1166,9 @@ var styles$3 = {"menuItem":"MenuItem-module_menuItem","menuItem--disabled":"Menu
|
|
|
1151
1166
|
* <MenuItem label="Recent Files" hasSubmenu />
|
|
1152
1167
|
* ```
|
|
1153
1168
|
*/
|
|
1154
|
-
const MenuItem = forwardRef(({ label, shortcut, disabled = false, selected = false, separator = false, checked = false, icon, onClick, onFocus, onBlur, className = '', hasSubmenu = false, }, ref) => {
|
|
1169
|
+
const MenuItem = forwardRef(({ label, shortcut, disabled = false, selected = false, separator = false, checked = false, icon, onClick, onFocus, onBlur, className = '', hasSubmenu = false, items, }, ref) => {
|
|
1170
|
+
const [isSubmenuOpen, setIsSubmenuOpen] = useState(false);
|
|
1171
|
+
const effectiveHasSubmenu = hasSubmenu || !!items;
|
|
1155
1172
|
// Class names
|
|
1156
1173
|
const menuItemClassNames = [
|
|
1157
1174
|
styles$3.menuItem,
|
|
@@ -1170,10 +1187,66 @@ const MenuItem = forwardRef(({ label, shortcut, disabled = false, selected = fal
|
|
|
1170
1187
|
}
|
|
1171
1188
|
onClick?.(event);
|
|
1172
1189
|
};
|
|
1173
|
-
return (jsxs(
|
|
1190
|
+
return (jsxs("div", { className: styles$3.menuItemContainer, onMouseEnter: () => setIsSubmenuOpen(true), onMouseLeave: () => setIsSubmenuOpen(false), style: { position: 'relative', width: '100%' }, children: [jsxs("button", { ref: ref, type: "button", className: menuItemClassNames, onClick: handleClick, onFocus: onFocus, onBlur: onBlur, disabled: disabled, role: "menuitem", "aria-disabled": disabled, "aria-checked": checked ? 'true' : undefined, children: [jsx("span", { className: styles$3.checkmark, children: checked && '✓' }), icon && jsx("span", { className: styles$3.icon, children: icon }), jsx("span", { className: styles$3.label, children: label }), shortcut && jsx("span", { className: styles$3.shortcut, children: shortcut }), effectiveHasSubmenu && jsx("span", { className: styles$3.submenuArrow, children: "\u25B6" })] }), items && isSubmenuOpen && (jsx("div", { className: styles$3.submenu, role: "menu", children: items })), separator && jsx("div", { className: styles$3.separatorLine, role: "separator" })] }));
|
|
1174
1191
|
});
|
|
1175
1192
|
MenuItem.displayName = 'MenuItem';
|
|
1176
1193
|
|
|
1194
|
+
/**
|
|
1195
|
+
* Mac OS 9 style MenuDropdown component
|
|
1196
|
+
*
|
|
1197
|
+
* A standalone dropdown menu that shares the styling of the MenuBar.
|
|
1198
|
+
* Useful for placing menus in the status area (rightContent) or other parts of the app.
|
|
1199
|
+
*/
|
|
1200
|
+
const MenuDropdown = ({ label, items, disabled = false, className = '', dropdownClassName = '', align = 'left', }) => {
|
|
1201
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
1202
|
+
const containerRef = useRef(null);
|
|
1203
|
+
// Handle click outside to close menu
|
|
1204
|
+
useEffect(() => {
|
|
1205
|
+
if (!isOpen)
|
|
1206
|
+
return;
|
|
1207
|
+
const handleClickOutside = (event) => {
|
|
1208
|
+
if (containerRef.current && !containerRef.current.contains(event.target)) {
|
|
1209
|
+
setIsOpen(false);
|
|
1210
|
+
}
|
|
1211
|
+
};
|
|
1212
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
1213
|
+
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
1214
|
+
}, [isOpen]);
|
|
1215
|
+
// Handle Escape key to close menu
|
|
1216
|
+
useEffect(() => {
|
|
1217
|
+
if (!isOpen)
|
|
1218
|
+
return;
|
|
1219
|
+
const handleEscape = (event) => {
|
|
1220
|
+
if (event.key === 'Escape') {
|
|
1221
|
+
event.preventDefault();
|
|
1222
|
+
setIsOpen(false);
|
|
1223
|
+
}
|
|
1224
|
+
};
|
|
1225
|
+
document.addEventListener('keydown', handleEscape);
|
|
1226
|
+
return () => document.removeEventListener('keydown', handleEscape);
|
|
1227
|
+
}, [isOpen]);
|
|
1228
|
+
const handleToggle = () => {
|
|
1229
|
+
if (!disabled) {
|
|
1230
|
+
setIsOpen(!isOpen);
|
|
1231
|
+
}
|
|
1232
|
+
};
|
|
1233
|
+
const menuContainerClassNames = [
|
|
1234
|
+
styles$4.menuContainer,
|
|
1235
|
+
className
|
|
1236
|
+
].filter(Boolean).join(' ');
|
|
1237
|
+
const menuButtonClassNames = [
|
|
1238
|
+
styles$4.menuButton,
|
|
1239
|
+
isOpen ? styles$4['menuButton--open'] : '',
|
|
1240
|
+
disabled ? styles$4['menuButton--disabled'] : '',
|
|
1241
|
+
].filter(Boolean).join(' ');
|
|
1242
|
+
const dropdownClassNames = [
|
|
1243
|
+
styles$4.dropdown,
|
|
1244
|
+
align === 'right' ? styles$4['dropdown--right'] : '',
|
|
1245
|
+
dropdownClassName
|
|
1246
|
+
].filter(Boolean).join(' ');
|
|
1247
|
+
return (jsxs("div", { ref: containerRef, className: menuContainerClassNames, children: [jsx("button", { type: "button", className: menuButtonClassNames, onClick: handleToggle, disabled: disabled, "aria-haspopup": "true", "aria-expanded": isOpen, "aria-disabled": disabled, children: typeof label === 'string' ? jsx("h3", { children: label }) : label }), isOpen && (jsx("div", { className: dropdownClassNames, role: "menu", onClick: () => setIsOpen(false), children: items }))] }));
|
|
1248
|
+
};
|
|
1249
|
+
|
|
1177
1250
|
var styles$2 = {"scrollbar":"Scrollbar-module_scrollbar","scrollbar--vertical":"Scrollbar-module_scrollbar--vertical","scrollbar--horizontal":"Scrollbar-module_scrollbar--horizontal","scrollbar--disabled":"Scrollbar-module_scrollbar--disabled","arrow":"Scrollbar-module_arrow","arrowIcon":"Scrollbar-module_arrowIcon","arrow--start":"Scrollbar-module_arrow--start","arrow--end":"Scrollbar-module_arrow--end","track":"Scrollbar-module_track","thumb":"Scrollbar-module_thumb"};
|
|
1178
1251
|
|
|
1179
1252
|
// Scrollbar component - Mac OS 9 style
|
|
@@ -1637,5 +1710,5 @@ const tokens = {
|
|
|
1637
1710
|
transitions,
|
|
1638
1711
|
};
|
|
1639
1712
|
|
|
1640
|
-
export { Button, Checkbox, Dialog, DividerIcon, FolderList, Icon, IconButton, IconLibrary, ListView, MenuBar, MenuItem, Radio, Scrollbar, Select, TabPanel, Tabs, TextField, Window, borders, colors, shadows, spacing, tokens, transitions, typography, zIndex };
|
|
1713
|
+
export { Button, Checkbox, Dialog, DividerIcon, FolderList, Icon, IconButton, IconLibrary, ListView, MenuBar, MenuDropdown, MenuItem, Radio, Scrollbar, Select, TabPanel, Tabs, TextField, Window, borders, colors, shadows, spacing, tokens, transitions, typography, zIndex };
|
|
1641
1714
|
//# sourceMappingURL=index.js.map
|