+
{(children != null)
?
: }
diff --git a/src/controls/menu-item/index.jsx b/src/controls/menu-item/index.jsx
index e5c68dc..0fa0869 100644
--- a/src/controls/menu-item/index.jsx
+++ b/src/controls/menu-item/index.jsx
@@ -3,11 +3,10 @@
const React = require("react");
const useMeasure = require("react-use-measure");
const matchValue = require("match-value");
-const insecureNanoid = require("nanoid/non-secure").nanoid;
const defaultStyle = require("./style.css");
const useTheme = require("../../util/themeable");
-const useGuaranteedMemo = require("../../util/use-guaranteed-memo");
+const useID = require("../../util/use-id");
const isEventInsideRef = require("../../util/is-event-inside-ref");
const comparePath = require("../../util/compare-path");
const MenuItemContext = require("../../contexts/menu-item");
@@ -20,7 +19,7 @@ module.exports = function MenuItem({ label, title, menu, onClick }) {
let submenuRef = React.useRef();
let itemContext = React.useContext(MenuItemContext);
let path = React.useContext(MenuPathContext);
- let id = useGuaranteedMemo(() => insecureNanoid()); // insecure is fine here, these IDs are not interesting to an attacker
+ let id = useID(); // insecure is fine here, these IDs are not interesting to an attacker
let ownPath = path.concat([ id ]); // FIXME: memoize?
let isSelected = itemContext.isActive && comparePath(itemContext.selectedPath, ownPath);
@@ -65,11 +64,11 @@ module.exports = function MenuItem({ label, title, menu, onClick }) {
},
};
- let buttonClasses = withTheme([
+ let buttonClasses = withTheme(
"item",
{ item_selected: isSelected },
{ item_directPress: (menu == null) }
- ]);
+ );
return (
diff --git a/src/controls/ribbon/style.css b/src/controls/ribbon/style.css
index 0db15c9..a6ec59f 100644
--- a/src/controls/ribbon/style.css
+++ b/src/controls/ribbon/style.css
@@ -1,4 +1,18 @@
+:import("../button/style.css") { button: button; }
+:import("../shared.css") { combinedButton: combinedButton; }
+
.ribbon {
composes: notSelectable from "../shared.css";
display: flex;
+
+ .button {
+ width: 100%;
+ height: 100%;
+ min-width: 16px;
+ }
+
+ .combinedButton {
+ display: grid; /* block, not inline */
+ height: 100%;
+ }
}
diff --git a/src/controls/shared.css b/src/controls/shared.css
index c7d8fde..d7bf008 100644
--- a/src/controls/shared.css
+++ b/src/controls/shared.css
@@ -15,3 +15,14 @@
justify-content: center;
text-align: center;
}
+
+.combinedButton {
+ display: inline-grid;
+ box-sizing: border-box;
+ border-radius: 2px;
+ overflow: hidden;
+
+ & > * {
+ border-radius: 0px !important;
+ }
+}
diff --git a/src/index.js b/src/index.js
index aad939e..74474fb 100644
--- a/src/index.js
+++ b/src/index.js
@@ -3,6 +3,8 @@
module.exports = {
/* Multi-purpose controls */
Icon: require("./controls/icon/index.jsx"),
+ Button: require("./controls/button/index.jsx"),
+ ButtonSet: require("./controls/button-set/index.jsx"),
// Text: require("./controls/text.jsx"),
// /* Pane layout */
diff --git a/src/themes/dark.css b/src/themes/dark.css
index 0842a7c..810372c 100644
--- a/src/themes/dark.css
+++ b/src/themes/dark.css
@@ -2,6 +2,14 @@ $darkGray: rgb(34, 34, 34);
$hoverColor: rgba(113, 113, 113, 0.26);
$activeColor: $darkGray;
+/* :export {
+ darkGray: $darkGray;
+ hoverColor: $hoverColor;
+ activeColor: $activeColor;
+} */
+
+/* FIXME: Casemap control names */
+
.edgeRaise {
box-shadow: inset -1px -1px rgba(30, 27, 27, 0.7),
inset 1px 1px rgba(135, 131, 131, 0.3);
@@ -41,7 +49,7 @@ $activeColor: $darkGray;
}
}
-.menu_menuBar {
+.menu_menuBar, .ribbon_ribbon {
composes: bar;
}
@@ -70,6 +78,21 @@ $activeColor: $darkGray;
}
}
-.ribbon_ribbon {
- composes: bar;
+.button_button {
+ // background-color: #38383c;
+ background-color: magenta;
+ border: none;
+
+ &:hover {
+ background-color: $hoverColor;
+ }
+
+ &:active {
+ @include edge-lower;
+ background-color: $activeColor;
+ }
+
+ &.button_selected {
+ background-color: $darkGray;
+ }
}
diff --git a/src/util/compose-handlers.js b/src/util/compose-handlers.js
new file mode 100644
index 0000000..872b8ad
--- /dev/null
+++ b/src/util/compose-handlers.js
@@ -0,0 +1,11 @@
+"use strict";
+
+module.exports = function composeHandlers(handlers) {
+ let nonNullHandlers = handlers.filter((handler) => handler != null);
+
+ return function callOnEvent(... args) {
+ for (let handler of nonNullHandlers) {
+ handler(... args);
+ }
+ };
+};
diff --git a/src/util/themeable/index.jsx b/src/util/themeable/index.jsx
index d6cb2a7..0d4a990 100644
--- a/src/util/themeable/index.jsx
+++ b/src/util/themeable/index.jsx
@@ -23,10 +23,10 @@ module.exports = function useTheme({ control, defaultStyle }) {
? `${control}_`
: "";
- function withTheme(classes) {
- if (arguments.length > 1) {
- console.warn(`WARNING: More than one argument specified to 'withTheme' call (second argument is ${JSON.stringify(arguments[1])})`);
- }
+ function withTheme(... classes) {
+ // if (arguments.length > 1) {
+ // console.warn(`WARNING: More than one argument specified to 'withTheme' call (second argument is ${JSON.stringify(arguments[1])})`);
+ // }
let mappedClasses = extendClassnames(classes, (className) => {
return [
diff --git a/src/util/use-id.js b/src/util/use-id.js
new file mode 100644
index 0000000..e772207
--- /dev/null
+++ b/src/util/use-id.js
@@ -0,0 +1,8 @@
+"use strict";
+
+const insecureNanoid = require("nanoid/non-secure").nanoid;
+const useGuaranteedMemo = require("./use-guaranteed-memo");
+
+module.exports = function useID() {
+ return useGuaranteedMemo(() => insecureNanoid());
+};